/* Distributed Checksum Clearinghouse * * --C-LICENSE-- * $Revision: 1.67 $ */ #include "dcc_defs.h" #include "dcc_paths.h" #ifdef DCC_UNIX #include #endif u_char dcc_clnt_debug; u_char dcc_no_syslog; int dcc_error_priority = LOG_ERR | LOG_MAIL; int dcc_trace_priority = LOG_NOTICE | LOG_MAIL; DCC_PATH dcc_progname; int dcc_progname_len; #ifdef HAVE___PROGNAME extern const char *__progname; #endif const char LICENSE[] = ""; void dcc_syslog_init(u_char use_syslog, const char *argv0 DCC_UNUSED, const char *suffix) { const char *p; /* Solaris defaults to "syslog" with a null identification string, * but does not seem to have __progname set by crt0. */ #undef GOT_PROGNAME #ifdef HAVE_GETPROGNAME p = getprogname(); # define GOT_PROGNAME #endif #if defined(HAVE___PROGNAME) && !defined(GOT_PROGNAME) p = __progname; # define GOT_PROGNAME #endif #ifndef GOT_PROGNAME p = strrchr(argv0, '/'); #ifdef DCC_WIN32 if (!p) p = strrchr(argv0, '\\'); #endif if (!p) p = argv0; else ++p; #ifdef DCC_WIN32 /* strip ".exe" from Windows progam name */ dcc_progname_len = strlen(p); if (dcc_progname_len > LITZ(".exe") && !CLITCMP(&p[dcc_progname_len-LITZ(".exe")], ".exe")) { char *p1 = strdup(p); p1[dcc_progname_len-LITZ(".exe")] = '\0'; p = p1; } #endif /* DCC_WIN32 */ #endif /* !GOT_PROGNAME */ snprintf(dcc_progname.c, sizeof(dcc_progname), "%s%s", p, suffix ? suffix : ""); dcc_progname_len = strlen(dcc_progname.c); /* ensure that stdout and stderr exist so that when we open * database or other files, we don't get file descriptor 1 or 2 * and then later write error messages to them. */ dcc_clean_stdio(); #ifdef DCC_WIN32 dcc_no_syslog = 1; #else /* Don't wait for the console if somehow we must use it, * because that messes up dccm. */ #ifndef LOG_NOWAIT #define LOG_NOWAIT 0 #endif openlog(dcc_progname.c, LOG_PID | LOG_NOWAIT, LOG_MAIL); if (!use_syslog) dcc_no_syslog = 1; #endif /* DCC_WIN32 */ } static void clean_stdfd(int stdfd) { struct stat sb; int fd; if (0 > fstat(stdfd, &sb) && errno == EBADF) { fd = open(_PATH_DEVNULL, 0, O_RDWR); if (fd < 0) /* ignore errors we can't help */ return; if (fd != stdfd) { dup2(fd, stdfd); close(fd); } } } /* prevent surprises from uses of stdio FDs by ensuring that the FDs are open */ void dcc_clean_stdio(void) { clean_stdfd(STDIN_FILENO); clean_stdfd(STDOUT_FILENO); clean_stdfd(STDERR_FILENO); } /* Fetch the exit code stashed after the end of an error message. */ int emsg_ex_code(const DCC_EMSG *emsg) { int len; len = strlen(emsg->c); if (len >= ISZ(DCC_EMSG)-2 || emsg->c[len+1] == 0) return EX_UNAVAILABLE; return emsg->c[len+1]; } /* Generate an eorr message string in a buffer, if we have a buffer. * Stash an exit code after the end of the test in the buffer. * Log or print the message if there is no buffer. */ void dcc_vpemsg(u_char ex_code, DCC_EMSG *emsg, const char *msg, va_list args) { int len; if (!emsg) { dcc_verror_msg(msg, args); } else { len = vsnprintf(emsg->c, sizeof(emsg->c), msg, args); if (len < ISZ(DCC_EMSG)-2) emsg->c[len+1] = ex_code; } } void DCC_PF(3,4) dcc_pemsg(u_char ex_code, DCC_EMSG *emsg, const char *msg, ...) { va_list args; va_start(args, msg); dcc_vpemsg(ex_code, emsg, msg, args); va_end(args); } int dcc_verror_msg(const char *p, va_list args) { char logbuf[LOGBUF_SIZE]; int i; i = vsnprintf(logbuf, sizeof(logbuf), p, args); if (i >= ISZ(logbuf)) { strcpy(&logbuf[ISZ(logbuf)-sizeof("...")], "..."); i = ISZ(logbuf)-1; } else if (i == 0) { i = snprintf(logbuf, sizeof(logbuf), "(empty error message)"); } fflush(stdout); /* keep stderr and stdout straight */ (void)fwrite(logbuf, i, 1, stderr); if (logbuf[i-1] != '\n') { fputc('\n', stderr); ++i; } if (!dcc_no_syslog) { dcc_syslog_lock(); syslog(dcc_error_priority, "%s", logbuf); dcc_syslog_unlock(); } fflush(stderr); /* keep stderr and stdout straight */ return i; } void DCC_PF(1,2) dcc_error_msg(const char *p, ...) { va_list args; va_start(args, p); dcc_verror_msg(p, args); va_end(args); } /* talk to stdout * and to the system log unless the system log is off */ void dcc_vtrace_msg(const char *p, va_list args) { char logbuf[LOGBUF_SIZE]; int i; /* Some systems including Linux with gcc 3.4.2 on AMD 64 processors * do not allow two uses of a va_list but requires va_copy() * Other systems do not have any notion of va_copy(). */ i = vsnprintf(logbuf, sizeof(logbuf), p, args); if (i >= ISZ(logbuf)) strcpy(&logbuf[ISZ(logbuf)-sizeof("...")], "..."); fflush(stdout); /* keep stderr and stdout straight */ fprintf(stderr, "%s\n", logbuf); if (!dcc_no_syslog) { dcc_syslog_lock(); syslog(dcc_trace_priority, "%s", logbuf); dcc_syslog_unlock(); } fflush(stderr); /* keep stderr and stdout straight */ } void DCC_PF(1,2) dcc_trace_msg(const char *p, ...) { va_list args; va_start(args, p); dcc_vtrace_msg(p, args); va_end(args); } void dcc_vfatal_msg(const char *p, va_list args) { char logbuf[LOGBUF_SIZE]; int i; /* write the message with the "fatal error" addition as * a single message to syslog */ i = vsnprintf(logbuf, sizeof(logbuf), p, args); if (i >= ISZ(logbuf)) strcpy(&logbuf[ISZ(logbuf)-sizeof("...")], "..."); fflush(stdout); /* keep stderr and stdout straight */ fprintf(stderr, "%s; fatal error\n", logbuf); fflush(stderr); if (dcc_no_syslog) return; dcc_syslog_lock(); syslog(dcc_error_priority, "%s; fatal error", logbuf); closelog(); dcc_syslog_unlock(); } void dcc_version_print(void) { static u_char seen_V = 0; if (!seen_V) { fputs(DCC_VERSION"\n", stderr); seen_V = 1; } else { #ifndef DCC_CONFIGURE fputs("`configure` not used\n", stderr); #else fputs("built with `configure "DCC_CONFIGURE"`\n", stderr); #endif } }