Exemple #1
0
static int munmap_file(void *base, const char *path, int fd,
                const struct stat *st) {
  int status = 0;
#ifdef HAVE_SYS_MMAP_H
  if (munmap(base, st->st_size) != 0) {
    rs_log_error("munmap of file '%s' failed: %s", path, strerror(errno));
    status = 1;
  }
#else
  errno = 0;
  if (lseek(fd, 0, SEEK_SET) == -1) {
    rs_log_error("can't seek to start of %s: %s", path, strerror(errno));
    status = 1;
  } else if (write(fd, base, st->st_size) != st->st_size) {
    rs_log_error("can't write %ld bytes to %s: %s", (long) st->st_size, path,
                 strerror(errno));
    status = 1;
  }
#endif
  if (close(fd) != 0) {
    rs_log_error("close of file '%s' failed: %s", path, strerror(errno));
    status = 1;
  }
  return status;
}
Exemple #2
0
static int dcc_set_file_extension(const char *sfile,
                                  const char *new_ext,
                                  char **ofile)
{
    char *dot, *o;

    o = strdup(sfile);
    if (!o) {
        rs_log_error("strdup failed (out of memory?)");
        return EXIT_DISTCC_FAILED;
    }
    dot = dcc_find_extension(o);
    if (!dot) {
        rs_log_error("couldn't find extension in \"%s\"", o);
        return EXIT_DISTCC_FAILED;
    }
    if (strlen(dot) < strlen(new_ext)) {
        rs_log_error("not enough space for new extension");
        return EXIT_DISTCC_FAILED;
    }
    strcpy(dot, new_ext);
    *ofile = o;

    return 0;
}
Exemple #3
0
void rs_sig_handle(int signum) {

    int err = errno;

    switch(signum) {

    case SIGPIPE:
        /* ignore */
        break;
    case SIGINT:
        rs_quit = 1;
        rs_log_error(RS_LOG_INFO, 0, "get a SIGINT signal");
        break;
    case SIGTERM:
        rs_quit = 1;
        rs_log_error(RS_LOG_INFO, 0, "get a SIGTERM signal");
        break;
    case SIGQUIT:
        rs_quit = 1;
        rs_log_error(RS_LOG_INFO, 0, "get a SIGQUIT signal");
        break;
    case SIGHUP:
        rs_reload = 1;
        rs_log_error(RS_LOG_INFO, 0, "get a SIGHUP signal");
    }

    errno = err;

    return;
}
Exemple #4
0
/**
 * Read the "DONE" token from the network that introduces a response.
 **/
int dcc_r_result_header(int ifd,
                        enum dcc_protover expect_ver)
{
    unsigned vers;
    int ret;

    if ((ret = dcc_r_token_int(ifd, "DONE", &vers)))
        rs_log_error("server provided no answer. "
                     "Is the server configured to allow access from your IP"
                     " address? Is the server performing authentication and"
                     " your client isn't? Does the server have the compiler"
                     " installed? Is the server configured to access the"
                     " compiler?");
        return ret;

    if (vers != expect_ver) {
        rs_log_error("got version %d not %d in response from server",
                     vers, expect_ver);
        return EXIT_PROTOCOL_ERROR;
    }

    rs_trace("got response header");

    return 0;
}
Exemple #5
0
Fichier : io.c Projet : aosm/distcc
/**
 * Write bytes to an fd.  Keep writing until we're all done or something goes
 * wrong.
 *
 * @returns 0 or exit code.
 **/
int dcc_writex(int fd, const void *buf, size_t len)
{
    ssize_t r;
    int ret;
	
    while (len > 0) {
        r = write(fd, buf, len);

        if (r == -1 && errno == EAGAIN) {
            if ((ret = dcc_select_for_write(fd, dcc_io_timeout)))
                return ret;
            else
                continue;
        } else if (r == -1 && errno == EINTR) {
            continue;
        } else if (r == -1) {
            rs_log_error("failed to write: %s", strerror(errno));
            return EXIT_IO_ERROR;
        } else if (r == 0) {
            rs_log_error("unexpected eof on fd%d", fd);
            return EXIT_TRUNCATED;
        } else {
            buf = &((char *) buf)[r];
            len -= r;
        }
    }

    return 0;
}
Exemple #6
0
int rs_redis_append_command(rs_slave_info_t *si, const char *fmt, ...) 
{
    va_list         args;
    redisContext    *c;
    int             i, err;

    i = 0;
    err = 0;
    c = si->c;

    for( ;; ) {

        if(c == NULL) {

            /* retry connect*/
            c = redisConnect(si->redis_addr, si->redis_port);

            if(c->err) {
                if(i % 60 == 0) {
                    i = 0;
                    rs_log_error(RS_LOG_ERR, rs_errno, "redisConnect(\"%s\", "
                            "%d) failed, %s" , si->redis_addr, si->redis_port, 
                            c->errstr);
                }

                redisFree(c);
                c = NULL;

                i += RS_REDIS_CONNECT_RETRY_SLEEP_SEC;
                sleep(RS_REDIS_CONNECT_RETRY_SLEEP_SEC); 

                continue;
            }
        }

        va_start(args, fmt);
        err = redisvAppendCommand(c, fmt, args);
        va_end(args);

        break;
    }

    si->c = c;

    if(err != REDIS_OK) {
        rs_log_error(RS_LOG_ERR, rs_errno, "redisvAppendCommand() failed");
        return RS_ERR;
    }

    si->cmdn++;

    return RS_OK;
}
Exemple #7
0
/**
 * Obtain the CPU speed in Hz.
 **/
int dcc_cpuspeed(unsigned long long *speed)
{

#if defined(__APPLE__)

    size_t len = sizeof(*speed);
    if (sysctlbyname("hw.cpufrequency", speed, &len, NULL, 0) == 0)
        return 0;

    rs_log_error("sysctlbyname(\"hw.cpufrequency\") failed: %s",
                 strerror(errno));
    *speed = 1;
    return EXIT_DISTCC_FAILED;

#elif defined(linux)

    /* This fetches the maximum speed for cpu0, on the assumption that all
     * CPUs in the system are the same speed, and the maximum speed is the
     * speed that the CPU will run at if needed.  The maximum speed may be
     * greater than the current speed due to scaling. */
    FILE *f;
    long long khz;
    int rv;

    f = fopen("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", "r");
    if (!f) {
        rs_log_error("open cpuinfo_max_freq failed: %s", strerror(errno));
        *speed = 1;
        return EXIT_DISTCC_FAILED;
    }

    rv = fscanf(f, "%lld", &khz);
    fclose(f);

    if (rv != 1 || khz <= 0) {
        rs_log_error("cpuinfo_max_freq makes no sense");
        *speed = 1;
        return EXIT_DISTCC_FAILED;
    }

    *speed = khz * 1000;
    return 0;

#else /* linux */

#warning "Please port this function"
    *speed = 1;
    return EXIT_DISTCC_FAILED;

#endif /* linux */

}
Exemple #8
0
int main(int argc, char *argv[])
{
    rs_trace_set_level(RS_LOG_DEBUG);
    rs_add_logger(rs_logger_file, RS_LOG_DEBUG, NULL, STDERR_FILENO);
    if (argc < 2) {
        rs_log_error(USAGE);
        return 1;
    }

    if (strcmp(argv[1], "dcc_fresh_dependency_exists") == 0) {
        if (argc != 5) {
            rs_log_error("dcc_fresh_dependency_exists expects DOTD_FNAME "
                         "EXCL_PAT REF_TIME");
            return 1;
        }
        errno = 0;
        char *ptr;
        time_t ref_time = (time_t)strtol(argv[4], &ptr, 0);
        if (errno || (*ptr != '\0')) {
            rs_log_error("strtol failed");
            return 1;
        } else {
            char *result;
            int ret;
            ret = dcc_fresh_dependency_exists((const char *)argv[2],
                                              (const char *)argv[3],
                                              ref_time,
                                              &result);
            if (ret)
                printf("h_compile.c: UNEXPECTED RETURN VALUE\n");
            else
                printf("result %s\n", result ? result : "(NULL)");
            if (result) free(result);
        }
    } else if (strcmp(argv[1], "dcc_discrepancy_filename") == 0) {
        if (argc != 2) {
            rs_log_error("dcc_discrepancy_filename expects no arguments");
            return 1;
        }
        char *result;
        int ret = dcc_discrepancy_filename(&result);
        if (ret)
            printf("h_compile.c: UNEXPECTED RETURN VALUE\n");
        else
            printf("%s", result ? result : "(NULL)");
    } else {
        rs_log_error(USAGE);
        return 1;
    }
    return 0;
}
Exemple #9
0
/*
 * Transmit the body of a file using sendfile().
 *
 * Linux at the moment requires the input be page-based -- ie a disk file, and
 * only on particular filesystems.  If the sendfile() call fails in a way that
 * makes us think that regular IO might work, then we try that instead.  For
 * example, the /tmp filesystem may not support sendfile().
 */
int
dcc_pump_sendfile(int ofd, int ifd, size_t size)
{
    ssize_t sent;
    off_t offset = 0;
    int ret;

    while (size) {
        /* Handle possibility of partial transmission, e.g. if
         * sendfile() is interrupted by a signal.  size is decremented
         * as we go. */

        sent = sys_sendfile(ofd, ifd, &offset, size);
        if (sent == -1) {
            if ((errno == ENOSYS || errno == EINVAL) && offset == 0) {
                /* The offset==0 tests is because we may be part way through
                 * the file.  We can't just naively go back to read/write
                 * because sendfile() does not update the file pointer: we
                 * would need to lseek() first.  That case is not handled at
                 * the moment because it's unlikely that sendfile() would
                 * suddenly be unsupported while we're using it.  A failure
                 * halfway through probably indicates a genuine error.*/

                rs_log_info("decided to use read/write rather than sendfile");
                return dcc_pump_readwrite(ofd, ifd, size);
            } else if (errno == EAGAIN) {
                /* Sleep until we're able to write out more data. */
                if ((ret = dcc_select_for_write(ofd, dcc_io_timeout)) != 0)
                    return ret;
                rs_trace("select() returned, continuing to write");
            } else if (errno == EINTR) {
                rs_trace("sendfile() interrupted, continuing");
            } else {
                rs_log_error("sendfile failed: %s", strerror(errno));
                return EXIT_IO_ERROR;
            }
        } else if (sent == 0) {
            rs_log_error("sendfile returned 0? can't cope");
            return EXIT_IO_ERROR;
        } else if (sent != (ssize_t) size) {
            /* offset is automatically updated by sendfile. */
            size -= sent;
            rs_log_notice("sendfile: partial transmission of %ld bytes; retrying %ld @%ld",
                          (long) sent, (long) size, (long) offset);
        } else {
            /* normal case, everything was sent. */
            break;
        }
    }
    return 0;
}
Exemple #10
0
/**
 * Become a daemon, discarding the controlling terminal.
 *
 * Borrowed from rsync.
 *
 * This function returns in the child, but not in the parent.
 **/
static void dcc_detach(void)
{
    int i;
    pid_t pid;
    pid_t sid;

    dcc_ignore_sighup();

    if ((pid = fork()) == -1) {
        rs_log_error("fork failed: %s", strerror(errno));
        exit(EXIT_DISTCC_FAILED);
    } else if (pid != 0) {
        /* In the parent.  This guy is about to go away so as to
         * detach from the controlling process, but first save the
         * child's pid. */
        dcc_save_pid(pid);
        _exit(0);
    }

    /* This is called in the detached child */

    /* detach from the terminal */
#ifdef HAVE_SETSID
    if ((sid = setsid()) == -1) {
        rs_log_error("setsid failed: %s", strerror(errno));
    } else {
        rs_trace("setsid to session %d", (int) sid);
    }
#else /* no HAVE_SETSID */
#ifdef TIOCNOTTY
    i = open("/dev/tty", O_RDWR);
    if (i >= 0) {
        ioctl(i, (int) TIOCNOTTY, (char *)0);
        close(i);
    }
#endif /* TIOCNOTTY */
#endif /* not HAVE_SETSID */

    /* make sure that stdin, stdout an stderr don't stuff things
       up (library functions, for example) */
    for (i=0;i<3;i++) {
        close(i);
        open("/dev/null", O_RDWR);
    }

    /* If there's a lifetime limit on this server (for testing) then it needs
     * to apply after detaching as well. */
    dcc_set_lifetime();
}
Exemple #11
0
/**
 * Fork a child to repeatedly accept and handle incoming connections.
 *
 * To protect against leaks, we quit after 50 requests and let the parent
 * recreate us.
 **/
static int dcc_preforked_child(int listen_fd)
{
    int ireq;
    const int child_lifetime = 50;

    for (ireq = 0; ireq < child_lifetime; ireq++) {
        int acc_fd;
        struct dcc_sockaddr_storage cli_addr;
        socklen_t cli_len;

        cli_len = sizeof cli_addr;

        do {
            acc_fd = accept(listen_fd, (struct sockaddr *) &cli_addr,
                            &cli_len);
        } while (acc_fd == -1 && errno == EINTR);

        if (acc_fd == -1) {
            rs_log_error("accept failed: %s", strerror(errno));
            dcc_exit(EXIT_CONNECT_FAILED);
        }

        dcc_service_job(acc_fd, acc_fd,
                        (struct sockaddr *) &cli_addr, cli_len);

        dcc_close(acc_fd);
    }

    rs_log_info("worn out");

    return 0;
}
Exemple #12
0
/**
 * Change object file or suffix of -o to @p ofname
 * Frees the old value, if it exists.
 *
 * It's crucially important that in every case where an output file is
 * detected by dcc_scan_args(), it's also correctly identified here.
 * It might be better to make the code shared.
 **/
int dcc_set_output(char **a, char *ofname)
{
    int i;

    for (i = 0; a[i]; i++)
        if (0 == strcmp(a[i], "-o") && a[i+1] != NULL) {
            rs_trace("changed output from \"%s\" to \"%s\"", a[i+1], ofname);
            free(a[i+1]);
            a[i+1] = strdup(ofname);
            if (a[i+1] == NULL) {
                rs_log_crit("failed to allocate space for output parameter");
                return EXIT_OUT_OF_MEMORY;
            }
            dcc_trace_argv("command after", a);
            return 0;
        } else if (0 == strncmp(a[i], "-o", 2)) {
            char *newptr;
            rs_trace("changed output from \"%s\" to \"%s\"", a[i]+2, ofname);
            free(a[i]);
            if (asprintf(&newptr, "-o%s", ofname) == -1) {
                rs_log_crit("failed to allocate space for output parameter");
                return EXIT_OUT_OF_MEMORY;
            }
            a[i] = newptr;
            dcc_trace_argv("command after", a);
            return 0;
        }

    rs_log_error("failed to find \"-o\"");
    return EXIT_DISTCC_FAILED;
}
Exemple #13
0
static ssize_t sys_sendfile(int ofd, int ifd, off_t *offset, size_t size)
{
    off_t sent_bytes;
    int ret;
    
    /* According to the manual, this can never partially complete on a
     * socket open for blocking IO. */
    ret = sendfile(ifd, ofd, *offset, size, 0, &sent_bytes, 0);
    if (ret == -1) {
        /* http://cvs.apache.org/viewcvs.cgi/apr/network_io/unix/sendrecv.c?rev=1.95&content-type=text/vnd.viewcvs-markup */
        if (errno == EAGAIN) {
            if (sent_bytes == 0) {
                /* Didn't send anything. Return error with errno == EAGAIN. */
                return -1;
            } else {
                /* We sent some bytes, but they we would block.  Treat this as
                 * success for now. */
                *offset += sent_bytes;
                return sent_bytes;
            }
        } else {
            /* some other error */
            return -1;
        }
    } else if (ret == 0) {
        *offset += size;
        return size;
    } else {
        rs_log_error("don't know how to handle return %d from BSD sendfile",
                     ret);
        return -1;
    }
}
Exemple #14
0
Fichier : io.c Projet : aosm/distcc
int dcc_select_for_write(int fd, int timeout)
{
    fd_set fds;
    int rs;

    struct timeval tv;

    tv.tv_sec = timeout;
    tv.tv_usec = 0;

    while (1) {
        FD_ZERO(&fds);
        FD_SET(fd, &fds);
        rs_trace("select for write on fd%d", fd);
        
        rs = select(fd + 1, NULL, &fds, &fds, &tv);

        if (rs == -1 && errno == EINTR) {
            rs_trace("select was interrupted");
            continue;
        } else if (rs == -1) {
            rs_log_error("select failed: %s", strerror(errno));
            return EXIT_IO_ERROR;
        } else {
            return 0;
        }
    }
}
Exemple #15
0
/*
 * DESCRIPTION
 *   send slave dump cmd
 *   format : slave.info\n,filter.tables,\0ringbuf_sleep_usec(binary)
 *   eaxmplae : /data/mysql-bin.00001,0\n,test.test,\01000(binary)
 *
 *
 */
static int rs_send_dumpcmd(rs_slave_info_t *si)
{
    int32_t l;
    ssize_t n;
    l = rs_strlen(si->dump_info) + 2 + rs_strlen(si->filter_tables) + 2 + 4;
    char buf[4 + l], *p;

    p = buf;

    p = rs_cpymem(buf, &l, 4);
    if(snprintf(p, l + 1, "%s\n,%s,%c", si->dump_info, si->filter_tables, 0)
            < 0)
    {
        rs_log_error(RS_LOG_ERR, rs_errno, "snprintf() failed");
        return RS_ERR;
    }

    rs_memcpy(p + l - 4, &(si->rb_esusec), 4);

    n = rs_write(si->svr_fd, buf, 4 + l);

    if(n != 4 + l) {
        return RS_ERR;
    }

    return RS_OK;
}
Exemple #16
0
/**
 * Main loop for no-fork mode.
 *
 * Much slower and may leak.  Should only be used when you want to run gdb on
 * distccd.
 **/
static void dcc_nofork_parent(int listen_fd)
{
    while (1) {
        int acc_fd;
        struct dcc_sockaddr_storage cli_addr;
        socklen_t cli_len;

        rs_log_info("waiting to accept connection");

        cli_len = sizeof cli_addr;
        acc_fd = accept(listen_fd,
                        (struct sockaddr *) &cli_addr, &cli_len);
        if (acc_fd == -1 && errno == EINTR) {
            ;
        }  else if (acc_fd == -1) {
            rs_log_error("accept failed: %s", strerror(errno));

#ifdef HAVE_GSSAPI
            if (dcc_auth_enabled) {
                dcc_gssapi_release_credentials();

                if (opt_blacklist_enabled || opt_whitelist_enabled) {
                    dcc_gssapi_free_list();
	            }
            }
#endif
            dcc_exit(EXIT_CONNECT_FAILED);
        } else {
            dcc_service_job(acc_fd, acc_fd, (struct sockaddr *) &cli_addr, cli_len);
            dcc_close(acc_fd);
        }
    }
}
Exemple #17
0
/**
 * Set log to the final destination after options have been read.
 **/
static void dcc_setup_real_log(void)
{
    int fd;

    /* Even in inetd mode, we might want to log to stderr, because that will
     * work OK for ssh connections. */

    if (opt_log_stderr) {
        rs_remove_all_loggers();
        rs_add_logger(rs_logger_file, opt_log_level_num, 0, STDERR_FILENO);
        return;
    }

    if (arg_log_file) {
        /* Don't remove loggers yet, in case this fails and needs to go to the
         * default. */
        if ((fd = open(arg_log_file, O_CREAT|O_APPEND|O_WRONLY, 0666)) == -1) {
            rs_log_error("failed to open %s: %s", arg_log_file,
                         strerror(errno));
            /* continue and use syslog */
        } else {
            rs_remove_all_loggers();
            rs_add_logger(rs_logger_file, opt_log_level_num, NULL, fd);
            return;
        }
    }

    rs_remove_all_loggers();
    openlog("distccd", LOG_PID, LOG_DAEMON);
    rs_add_logger(rs_logger_syslog, opt_log_level_num, NULL, 0);
}
Exemple #18
0
/**
 * Main loop for the parent process with the new preforked implementation.
 * The parent is just responsible for keeping a pool of children and they
 * accept connections themselves.
 **/
int dcc_preforking_parent(int listen_fd)
{
    while (1) {
        pid_t kid;

        while (dcc_nkids < dcc_max_kids) {
            if ((kid = fork()) == -1) {
                rs_log_error("fork failed: %s", strerror(errno));
                return EXIT_OUT_OF_MEMORY; /* probably */
            } else if (kid == 0) {
                dcc_exit(dcc_preforked_child(listen_fd));
            } else {
                /* in parent */
                ++dcc_nkids;
                rs_trace("up to %d children", dcc_nkids);
            }

            /* Don't start them too quickly, or we might overwhelm a machine
             * that's having trouble. */
            sleep(1);

            dcc_reap_kids(FALSE);
        }

        /* wait for any children to exit, and then start some more */
        dcc_reap_kids(TRUE);

        /* Another little safety brake here: since children should not exit
         * too quickly, pausing before starting them should be harmless. */
        sleep(1);
    }
}
Exemple #19
0
int dcc_ncpus(int *ncpus)
{
#if defined(_SC_NPROCESSORS_ONLN)
    /* Linux, Solaris, Tru64, UnixWare 7, and Open UNIX 8  */
    *ncpus = sysconf(_SC_NPROCESSORS_ONLN);
#elif defined(_SC_NPROC_ONLN)
    /* IRIX */
    *ncpus = sysconf(_SC_NPROC_ONLN);
#else
#warning "Please port this function"
    *ncpus = -1;                /* unknown */
#endif

    if (*ncpus == -1) {
        rs_log_error("sysconf(_SC_NPROCESSORS_ONLN) failed: %s",
                     strerror(errno));
        *ncpus = 1;
        return EXIT_DISTCC_FAILED;
    } else if (*ncpus == 0) {
    /* if there are no cpus, what are we running on?  But it has
         * apparently been observed to happen on ARM Linux */
    *ncpus = 1;
    }

    return 0;
}
Exemple #20
0
/**
 * We got a mismatch on a token, which indicates either a bug in distcc, or
 * that somebody (inetd?) is interfering with our network stream, or perhaps
 * some other network problem.  Whatever's happened, a bit more debugging
 * information would be handy.
 **/
static int dcc_explain_mismatch(const char *buf,
                                size_t buflen,
                                int ifd)
{
    ssize_t ret;
    char extrabuf[200];
    char *p;
    size_t l;

    memcpy(extrabuf, buf, buflen);
    
    /* Read a bit more context, and find the printable prefix. */
    ret = read(ifd, extrabuf + buflen, sizeof extrabuf - 1 - buflen);
    if (ret == -1) {
        ret = 0;                /* pah, use what we've got */
    }

    l = buflen + ret;

    extrabuf[l] = '\0';
    for (p = extrabuf; *p; p++)
        if (!(isprint(*p) || *p == ' ' || *p == '\t')) {
            *p = '\0';
            break;
        }
    
    rs_log_error("error context: \"%s\"", extrabuf);

    return 0;                   /* i just feel really sad... */
}
Exemple #21
0
/*
 * Compress from a file to a newly malloc'd block.
 */
int dcc_compress_file_lzo1x(int in_fd,
                            size_t in_len,
                            char **out_buf,
                            size_t *out_len)
{
    char *in_buf = NULL;
    int ret;

    if ((in_buf = malloc(in_len)) == NULL) {
        rs_log_error("allocation of %ld byte buffer failed",
                     (long) in_len);
        ret = EXIT_OUT_OF_MEMORY;
        goto out;
    }

    if ((ret = dcc_readx(in_fd, in_buf, in_len)))
        goto out;

    if ((ret = dcc_compress_lzo1x_alloc(in_buf, in_len, out_buf, out_len)))
        goto out;

out:
    if (in_buf != NULL) {
        free(in_buf);
    }

    return ret;
}
Exemple #22
0
/* Set the PATH environment variable to the indicated value. */
int dcc_set_path(const char *newpath)
{
    char *buf;

    if (asprintf(&buf, "PATH=%s", newpath) <= 0 || !buf) {
        rs_log_error("failed to allocate buffer for new PATH");
        return EXIT_OUT_OF_MEMORY;
    }
    rs_trace("setting %s", buf);
    if (putenv(buf) < 0) {
        rs_log_error("putenv PATH failed");
        return EXIT_FAILURE;
    }
    /* We must leave "buf" allocated. */
    return 0;
}
Exemple #23
0
static ssize_t sys_sendfile(int ofd, int ifd, off_t *offset, size_t size) 
{ 
    off_t sent_bytes = size;

    int ret = sendfile(ifd, ofd, *offset, &sent_bytes, NULL, 0);
    if (ret == -1) { 
        if (errno == EAGAIN) { 
            if (sent_bytes == 0) { 
                return -1;
            }
            else { 
                *offset += sent_bytes;
                return sent_bytes;
            }
        }
        else { 
            return -1;
        }
    }
    else if (ret == 0) { 
        *offset += size;
        return size;
    }
    else { 
        rs_log_error("don't know how to handle return %d from Darwin sendfile",
                     ret);
        return -1;
    }
}
Exemple #24
0
/**
 * Run @p argv in a child asynchronously.
 *
 * stdin, stdout and stderr are redirected as shown, unless those
 * filenames are NULL.  In that case they are left alone.
 *
 * @warning When called on the daemon, where stdin/stdout may refer to random
 * network sockets, all of the standard file descriptors must be redirected!
 **/
int dcc_spawn_child(char **argv, pid_t *pidptr,
                    const char *stdin_file,
                    const char *stdout_file,
                    const char *stderr_file)
{
    pid_t pid;

    dcc_trace_argv("forking to execute", argv);

    pid = fork();
    if (pid == -1) {
        rs_log_error("failed to fork: %s", strerror(errno));
        return EXIT_OUT_OF_MEMORY; /* probably */
    } else if (pid == 0) {
        /* If this is a remote compile,
         * put the child in a new group, so we can
         * kill it and all its descendents without killing distccd
         * FIXME: if you kill distccd while it's compiling, and
         * the compiler has an infinite loop bug, the new group
         * will run forever until you kill it.
         */
        if (stdout_file != NULL) {
            if (dcc_new_pgrp() != 0)
                rs_trace("Unable to start a new group\n");
        }
        dcc_inside_child(argv, stdin_file, stdout_file, stderr_file);
        /* !! NEVER RETURN FROM HERE !! */
    } else {
        *pidptr = pid;
        rs_trace("child started as pid%d", (int) pid);
        return 0;
    }
}
Exemple #25
0
/**
 * Replace this program with another in the same process.
 *
 * Does not return, either execs the compiler in place, or exits with
 * a message.
 **/
static void dcc_execvp(char **argv)
{
    char *slash;

    execvp(argv[0], argv);

    /* If we're still running, the program was not found on the path.  One
     * thing that might have happened here is that the client sent an absolute
     * compiler path, but the compiler's located somewhere else on the server.
     * In the absence of anything better to do, we search the path for its
     * basename.
     *
     * Actually this code is called on both the client and server, which might
     * cause unintnded behaviour in contrived cases, like giving a full path
     * to a file that doesn't exist.  I don't think that's a problem. */

    slash = strrchr(argv[0], '/');
    if (slash)
        execvp(slash + 1, argv);

    /* shouldn't be reached */
    rs_log_error("failed to exec %s: %s", argv[0], strerror(errno));

    dcc_exit(EXIT_COMPILER_MISSING); /* a generalization, i know */
}
Exemple #26
0
/**
 * Open a socket to a tcp remote host with the specified port.
 **/
int dcc_connect_by_name(const char *host, int port, int *p_fd)
{
    struct addrinfo hints;
    struct addrinfo *res;
    int error;
    int ret;
    char portname[20];

    rs_trace("connecting to %s port %d", host, port);
    
    /* Unfortunately for us, getaddrinfo wants the port (service) as a string */
    snprintf(portname, sizeof portname, "%d", port);

    memset(&hints, 0, sizeof(hints));
    /* set-up hints structure */
    hints.ai_family = PF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    error = getaddrinfo(host, portname, &hints, &res);
    if (error) {
        rs_log_error("failed to resolve host %s port %d: %s", host, port,
                     gai_strerror(error));
        return EXIT_CONNECT_FAILED;
    }

    /* Try each of the hosts possible addresses. */
    do {
        ret = dcc_connect_by_addr(res->ai_addr, res->ai_addrlen, p_fd);
    } while (ret != 0 && (res = res->ai_next));

    return ret;
}
Exemple #27
0
/**
 * Create the directory @p path, and register it for deletion when this
 * compilation finished.  If it already exists as a directory
 * we succeed, but we don't register the directory for deletion.
 **/
int dcc_mk_tmpdir(const char *path)
{
    struct stat buf;
    int ret;

    if (stat(path, &buf) == -1) {
        if (mkdir(path, 0777) == -1) {
            return EXIT_IO_ERROR;
        }
        if ((ret = dcc_add_cleanup(path))) {
            /* bailing out */
            rmdir(path);
            return ret;
        }
    } else {
        /* we could stat the file successfully; if it's a directory,
         * all is well, but we should not it delete later, since we did
         * not make it.
         */
         if (S_ISDIR(buf.st_mode)) {
             return 0;
         } else {
             rs_log_error("mkdir '%s' failed: %s", path, strerror(errno));
             return EXIT_IO_ERROR;
         }
    }
    return 0;
}
Exemple #28
0
/**
 * Return a static string holding DISTCC_DIR, or ~/.distcc.
 * The directory is created if it does not exist.
 **/
int dcc_get_top_dir(char **path_ret)
{
    char *env;
    static char *cached;
    int ret;

    if (cached) {
        *path_ret = cached;
        return 0;
    }

    if ((env = getenv("DISTCC_DIR"))) {
        if ((cached = strdup(env)) == NULL) {
            return EXIT_OUT_OF_MEMORY;
        } else {
            *path_ret = cached;
            return 0;
        }
    }

    if ((env = getenv("HOME")) == NULL) {
        rs_log_warning("HOME is not set; can't find distcc directory");
        return EXIT_BAD_ARGUMENTS;
    }

    if (asprintf(path_ret, "%s/.distcc", env) == -1) {
        rs_log_error("asprintf failed");
        return EXIT_OUT_OF_MEMORY;
    }

    ret = dcc_mkdir(*path_ret);
    if (ret == 0)
        cached = *path_ret;
    return ret;
}
Exemple #29
0
/**
 * Make sure that distccd never runs as root, by discarding privileges if we
 * have them.
 *
 * This used to also check gid!=0, but on BSD that is group wheel and is
 * apparently common for daemons or users.
 *
 * This is run before dissociating from the calling terminal so any errors go
 * to stdout.
 **/
int dcc_discard_root(void)
{
    uid_t uid;
    gid_t gid;
    int ret;

    if (getuid() != 0  &&  geteuid() != 0) {
        /* Already not root.  No worries. */
        return 0;
    }

    if ((ret = dcc_preferred_user(&uid, &gid)) != 0)
        return ret;

    /* GNU C Library Manual says that when run by root, setgid() and setuid()
     * permanently discard privileges: both the real and effective uid are
     * set. */

    if (setgid(gid)) {
        rs_log_error("setgid(%d) failed: %s", (int) gid, strerror(errno));
        return EXIT_SETUID_FAILED;
    }

#ifdef HAVE_SETGROUPS
    /* Get rid of any supplementary groups this process might have
     * inherited. */
    /* XXX: OS X Jaguar broke setgroups so that setting it to 0 fails. */
    if (setgroups(1, &gid)) {
        rs_log_error("setgroups failed: %s", strerror(errno));
        return EXIT_SETUID_FAILED;
    }
#endif

    if (setuid(uid)) {
        rs_log_error("setuid(%d) failed: %s", (int) uid, strerror(errno));
        return EXIT_SETUID_FAILED;
    }

    if (getuid() == 0  ||  geteuid() == 0) {
        rs_log_crit("still have root privileges after trying to discard them!");
        return EXIT_SETUID_FAILED;
    }

    rs_trace("discarded root privileges, changed to uid=%d gid=%d", (int) uid, (int) gid);
    return 0;
}
Exemple #30
0
Fichier : io.c Projet : aosm/distcc
int dcc_close(int fd)
{
    if (close(fd) != 0) {
        rs_log_error("failed to close fd%d: %s", fd, strerror(errno));
        return EXIT_IO_ERROR;
    }
    return 0;
}