/** * 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; }
/* * 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; }
/* * 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); }
/* * 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); }
void dcc_job_summary(void) { rs_log_notice("%s", job_summary); }