Example #1
0
/**
 * Serve a single file on stdin, and then exit.
 **/
static int dcc_inetd_server(void)
{
    int ret, close_ret;
    struct dcc_sockaddr_storage ss;
    struct sockaddr *psa = (struct sockaddr *) &ss;
    socklen_t len = sizeof ss;

    dcc_log_daemon_started("inetd server");

    if ((getpeername(STDIN_FILENO, psa, &len) == -1)) {
        /* This can fail with ENOTSOCK if e.g. sshd has started us on a pipe,
         * not on a socket.  I think it's harmless. */
        rs_log_notice("failed to get peer name: %s", strerror(errno));
        psa = NULL;             /* make sure we don't refer to uninitialized mem */
        len = 0;
    }

    ret = dcc_service_job(STDIN_FILENO, STDOUT_FILENO, psa, len);

    close_ret = dcc_close(STDIN_FILENO);

    if (ret)
        return ret;
    else
        return close_ret;
}
Example #2
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;
}
Example #3
0
/*
 * You can call this at any time, or hook it into atexit().  It is
 * safe to call repeatedly.
 *
 * If from_signal_handler (a boolean) is non-zero, it means that
 * we're being called from a signal handler, so we need to be
 * careful not to call malloc() or free() or any other functions
 * that might not be async-signal-safe.
 * (We do call the tracing functions, which is perhaps unsafe
 * because they call sprintf() if DISCC_VERBOSE=1 is enabled.
 * But in that case it is probably worth the very small risk
 * of a crash to get the full tracing output.)
 *
 * If $DISTCC_SAVE_TEMPS is set to "1", then files are not actually
 * deleted, which can be good for debugging.  However, we still need
 * to remove them from the list, otherwise it will eventually overflow
 * in prefork mode.
 */
static void dcc_cleanup_tempfiles_inner(int from_signal_handler)
{
    int i;
    int done = 0;
    int save = dcc_getenv_bool("DISTCC_SAVE_TEMPS", 0);

    /* do the unlinks from the last to the first file.
     * This way, directories get deleted after their files. */

     /* tempus fugit */
    for (i = n_cleanups - 1; i >= 0; i--) {
        if (save) {
            rs_trace("skip cleanup of %s", cleanups[i]);
        } else {
            /* Try removing it as a directory first, and
             * if that fails, try removing is as a file.
             * Report the error from removing-as-a-file
             * if both fail. */
            if ((rmdir(cleanups[i]) == -1) &&
                (unlink(cleanups[i]) == -1) &&
                (errno != ENOENT)) {
                rs_log_notice("cleanup %s failed: %s", cleanups[i],
                              strerror(errno));
            }
            done++;
        }
        n_cleanups = i;
        if (from_signal_handler) {
            /* It's not safe to call free() in this case.
             * Don't worry about the memory leak - we're about
             * to exit the process anyway. */
        } else {
            free(cleanups[i]);
        }
        cleanups[i] = NULL;
    }

    rs_trace("deleted %d temporary files", done);
}
Example #4
0
/*
 * You can call this at any time, or hook it into atexit().  It is
 * safe to call repeatedly.
 *
 * If $DISTCC_SAVE_TEMPS is set to "1", then files are not actually
 * deleted, which can be good for debugging.  However, we still need
 * to remove them from the list, otherwise it will eventually overflow
 * in prefork mode.
 */
void dcc_cleanup_tempfiles(void)
{
    int i;
    int done = 0;
    int save = dcc_getenv_bool("DISTCC_SAVE_TEMPS", 0);

     /* tempus fugit */
    for (i = 0; i < N_CLEANUPS && cleanups[i]; i++) {
        if (save) {
            rs_trace("skip cleanup of %s", cleanups[i]);
        } else { 
            if (unlink((char *) cleanups[i]) == -1 && (errno != ENOENT)) {
                rs_log_notice("cleanup %s failed: %s", cleanups[i],
                              strerror(errno));
            }
            done++;
        }
        free((char *) cleanups[i]);
        cleanups[i] = NULL;
    }

    rs_trace("deleted %d temporary files", done);
}
Example #5
0
void dcc_job_summary(void) {
    rs_log_notice("%s", job_summary);
}