From e072a2dd866b7cb9f14319b80326a4e7fd16fcdf Mon Sep 17 00:00:00 2001 From: Arno Töll Date: Sun, 8 Jan 2012 22:53:17 +0100 Subject: Imported Upstream version 2.3.16-beta --- support/rotatelogs.c | 779 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 584 insertions(+), 195 deletions(-) (limited to 'support/rotatelogs.c') diff --git a/support/rotatelogs.c b/support/rotatelogs.c index 1e7218f1..81bd950f 100644 --- a/support/rotatelogs.c +++ b/support/rotatelogs.c @@ -34,6 +34,8 @@ * -f option added Feb, 2008. This causes rotatelog to open/create * the logfile as soon as it's started, not as soon as it sees * data. + * + * -v option added Feb, 2008. Verbose output of command line parsing. */ @@ -46,16 +48,16 @@ #include "apr_general.h" #include "apr_time.h" #include "apr_getopt.h" +#include "apr_thread_proc.h" +#if APR_FILES_AS_SOCKETS +#include "apr_poll.h" +#endif #if APR_HAVE_STDLIB_H #include #endif -#if APR_HAVE_STRING_H -#include -#endif -#if APR_HAVE_STRINGS_H -#include -#endif +#define APR_WANT_STRFUNC +#include "apr_want.h" #define BUFSIZE 65536 #define ERRMSGSZ 256 @@ -64,14 +66,75 @@ #define MAX_PATH 1024 #endif +#define ROTATE_NONE 0 +#define ROTATE_NEW 1 +#define ROTATE_TIME 2 +#define ROTATE_SIZE 3 +#define ROTATE_FORCE 4 + +static const char *ROTATE_REASONS[] = { + "None", + "Open a new file", + "Time interval expired", + "Maximum size reached", + "Forced rotation", + NULL +}; + +typedef struct rotate_config rotate_config_t; + +struct rotate_config { + unsigned int sRotation; + int tRotation; + int utc_offset; + int use_localtime; + int use_strftime; + int force_open; + int verbose; + int echo; + const char *szLogRoot; + int truncate; + const char *linkfile; + const char *postrotate_prog; +#if APR_FILES_AS_SOCKETS + int create_empty; +#endif +}; + +typedef struct rotate_status rotate_status_t; + +/* Structure to contain relevant logfile state: fd, pool and + * filename. */ +struct logfile { + apr_pool_t *pool; + apr_file_t *fd; + char name[MAX_PATH]; +}; + +struct rotate_status { + struct logfile current; /* current logfile. */ + apr_pool_t *pool; /* top-level pool */ + char errbuf[ERRMSGSZ]; + int rotateReason; + int tLogEnd; + int nMessCount; +}; + +static rotate_config_t config; +static rotate_status_t status; + static void usage(const char *argv0, const char *reason) { if (reason) { fprintf(stderr, "%s\n", reason); } fprintf(stderr, - "Usage: %s [-l] [-f] " - "{|} " +#if APR_FILES_AS_SOCKETS + "Usage: %s [-v] [-l] [-L linkname] [-p prog] [-f] [-t] [-e] [-c] " +#else + "Usage: %s [-v] [-l] [-L linkname] [-p prog] [-f] [-t] [-e] " +#endif + "{|(B|K|M|G)} " "[offset minutes from UTC]\n\n", argv0); #ifdef OS2 @@ -86,19 +149,43 @@ static void usage(const char *argv0, const char *reason) "or \n\nTransferLog \"|%s /some/where 5M\"\n\n", argv0); #endif fprintf(stderr, - "to httpd.conf. The generated name will be /some/where.nnnn " - "where nnnn is the\nsystem time at which the log nominally " - "starts (N.B. if using a rotation time,\nthe time will always " - "be a multiple of the rotation time, so you can synchronize\n" - "cron scripts with it). At the end of each rotation time or " - "when the file size\nis reached a new log is started.\n"); + "to httpd.conf. By default, the generated name will be\n" + ".nnnn where nnnn is the system time at which the log\n" + "nominally starts (N.B. if using a rotation time, the time will\n" + "always be a multiple of the rotation time, so you can synchronize\n" + "cron scripts with it). If contains strftime conversion\n" + "specifications, those will be used instead. At the end of each\n" + "rotation time or when the file size is reached a new log is\n" + "started.\n" + "\n" + "Options:\n" + " -v Verbose operation. Messages are written to stderr.\n" + " -l Base rotation on local time instead of UTC.\n" + " -L path Create hard link from current log to specified path.\n" + " -p prog Run specified program after opening a new log file. See below.\n" + " -f Force opening of log on program start.\n" + " -t Truncate logfile instead of rotating, tail friendly.\n" + " -e Echo log to stdout for further processing.\n" +#if APR_FILES_AS_SOCKETS + " -c Create log even if it is empty.\n" +#endif + "\n" + "The program is invoked as \"[prog] []\"\n" + "where is the filename of the newly opened logfile, and\n" + ", if given, is the filename of the previously used logfile.\n" + "\n"); exit(1); } -static int get_now(int use_localtime, int utc_offset) +/* + * Get the unix time with timezone corrections + * given in the config struct. + */ +static int get_now(rotate_config_t *config) { apr_time_t tNow = apr_time_now(); - if (use_localtime) { + int utc_offset = config->utc_offset; + if (config->use_localtime) { /* Check for our UTC offset before using it, since it might * change if there's a switch between standard and daylight * savings time. @@ -110,41 +197,390 @@ static int get_now(int use_localtime, int utc_offset) return (int)apr_time_sec(tNow) + utc_offset; } +/* + * Close a file and destroy the associated pool. + */ +static void close_logfile(rotate_config_t *config, struct logfile *logfile) +{ + if (config->verbose) { + fprintf(stderr, "Closing file %s\n", logfile->name); + } + apr_file_close(logfile->fd); + apr_pool_destroy(logfile->pool); +} + +/* + * Dump the configuration parsing result to STDERR. + */ +static void dumpConfig (rotate_config_t *config) +{ + fprintf(stderr, "Rotation time interval: %12d\n", config->tRotation); + fprintf(stderr, "Rotation size interval: %12d\n", config->sRotation); + fprintf(stderr, "Rotation time UTC offset: %12d\n", config->utc_offset); + fprintf(stderr, "Rotation based on localtime: %12s\n", config->use_localtime ? "yes" : "no"); + fprintf(stderr, "Rotation file date pattern: %12s\n", config->use_strftime ? "yes" : "no"); + fprintf(stderr, "Rotation file forced open: %12s\n", config->force_open ? "yes" : "no"); + fprintf(stderr, "Rotation verbose: %12s\n", config->verbose ? "yes" : "no"); +#if APR_FILES_AS_SOCKETS + fprintf(stderr, "Rotation create empty logs: %12s\n", config->create_empty ? "yes" : "no"); +#endif + fprintf(stderr, "Rotation file name: %21s\n", config->szLogRoot); + fprintf(stderr, "Post-rotation prog: %21s\n", config->postrotate_prog); +} + +/* + * Check whether we need to rotate. + * Possible reasons are: + * - No log file open (ROTATE_NEW) + * - User forces us to rotate (ROTATE_FORCE) + * - Our log file size is already bigger than the + * allowed maximum (ROTATE_SIZE) + * - The next log time interval expired (ROTATE_TIME) + * + * When size and time constraints are both given, + * it suffices that one of them is fulfilled. + */ +static void checkRotate(rotate_config_t *config, rotate_status_t *status) +{ + if (status->current.fd == NULL) { + status->rotateReason = ROTATE_NEW; + } + else if (config->sRotation) { + apr_finfo_t finfo; + apr_off_t current_size = -1; + + if (apr_file_info_get(&finfo, APR_FINFO_SIZE, status->current.fd) == APR_SUCCESS) { + current_size = finfo.size; + } + + if (current_size > config->sRotation) { + status->rotateReason = ROTATE_SIZE; + } + else if (config->tRotation) { + if (get_now(config) >= status->tLogEnd) { + status->rotateReason = ROTATE_TIME; + } + } + } + else if (config->tRotation) { + if (get_now(config) >= status->tLogEnd) { + status->rotateReason = ROTATE_TIME; + } + } + else { + fprintf(stderr, "No rotation time or size specified\n"); + exit(2); + } + + if (status->rotateReason != ROTATE_NONE && config->verbose) { + fprintf(stderr, "File rotation needed, reason: %s\n", ROTATE_REASONS[status->rotateReason]); + } +} + +/* + * Handle post-rotate processing. + */ +static void post_rotate(apr_pool_t *pool, struct logfile *newlog, + rotate_config_t *config, rotate_status_t *status) +{ + apr_status_t rv; + char error[120]; + apr_procattr_t *pattr; + const char *argv[4]; + apr_proc_t proc; + + /* Handle link file, if configured. */ + if (config->linkfile) { + apr_file_remove(config->linkfile, newlog->pool); + if (config->verbose) { + fprintf(stderr,"Linking %s to %s\n", newlog->name, config->linkfile); + } + rv = apr_file_link(newlog->name, config->linkfile); + if (rv != APR_SUCCESS) { + char error[120]; + apr_strerror(rv, error, sizeof error); + fprintf(stderr, "Error linking file %s to %s (%s)\n", + newlog->name, config->linkfile, error); + exit(2); + } + } + + if (!config->postrotate_prog) { + /* Nothing more to do. */ + return; + } + + /* Collect any zombies from a previous run, but don't wait. */ + while (apr_proc_wait_all_procs(&proc, NULL, NULL, APR_NOWAIT, pool) == APR_CHILD_DONE) + /* noop */; + + if ((rv = apr_procattr_create(&pattr, pool)) != APR_SUCCESS) { + fprintf(stderr, + "post_rotate: apr_procattr_create failed for '%s': %s\n", + config->postrotate_prog, + apr_strerror(rv, error, sizeof(error))); + return; + } + + rv = apr_procattr_error_check_set(pattr, 1); + if (rv == APR_SUCCESS) + rv = apr_procattr_cmdtype_set(pattr, APR_PROGRAM_ENV); + + if (rv != APR_SUCCESS) { + fprintf(stderr, + "post_rotate: could not set up process attributes for '%s': %s\n", + config->postrotate_prog, + apr_strerror(rv, error, sizeof(error))); + return; + } + + argv[0] = config->postrotate_prog; + argv[1] = newlog->name; + if (status->current.name) { + argv[2] = status->current.name; + argv[3] = NULL; + } + else { + argv[2] = NULL; + } + + if (config->verbose) + fprintf(stderr, "Calling post-rotate program: %s\n", argv[0]); + + rv = apr_proc_create(&proc, argv[0], argv, NULL, pattr, pool); + if (rv != APR_SUCCESS) { + fprintf(stderr, "Could not spawn post-rotate process '%s': %s\n", + config->postrotate_prog, + apr_strerror(rv, error, sizeof(error))); + return; + } +} + +/* + * Open a new log file, and if successful + * also close the old one. + * + * The timestamp for the calculation of the file + * name of the new log file will be the actual millisecond + * timestamp, except when a regular rotation based on a time + * interval is configured and the previous interval + * is over. Then the timestamp is the starting time + * of the actual interval. + */ +static void doRotate(rotate_config_t *config, rotate_status_t *status) +{ + + int now = get_now(config); + int tLogStart; + apr_status_t rv; + struct logfile newlog; + + status->rotateReason = ROTATE_NONE; + + if (config->tRotation) { + int tLogEnd; + tLogStart = (now / config->tRotation) * config->tRotation; + tLogEnd = tLogStart + config->tRotation; + /* + * Check if rotation was forced and the last rotation + * interval is not yet over. Use the value of now instead + * of the time interval boundary for the file name then. + */ + if (tLogStart < status->tLogEnd) { + tLogStart = now; + } + status->tLogEnd = tLogEnd; + } + else { + tLogStart = now; + } + + if (config->use_strftime) { + apr_time_t tNow = apr_time_from_sec(tLogStart); + apr_time_exp_t e; + apr_size_t rs; + + apr_time_exp_gmt(&e, tNow); + apr_strftime(newlog.name, &rs, sizeof(newlog.name), config->szLogRoot, &e); + } + else { + if (config->truncate) { + apr_snprintf(newlog.name, sizeof(newlog.name), "%s", config->szLogRoot); + } + else { + apr_snprintf(newlog.name, sizeof(newlog.name), "%s.%010d", config->szLogRoot, + tLogStart); + } + } + apr_pool_create(&newlog.pool, status->pool); + if (config->verbose) { + fprintf(stderr, "Opening file %s\n", newlog.name); + } + rv = apr_file_open(&newlog.fd, newlog.name, APR_WRITE | APR_CREATE | APR_APPEND + | (config->truncate ? APR_TRUNCATE : 0), APR_OS_DEFAULT, newlog.pool); + if (rv == APR_SUCCESS) { + /* Handle post-rotate processing. */ + post_rotate(newlog.pool, &newlog, config, status); + + /* Close out old (previously 'current') logfile, if any. */ + if (status->current.fd) { + close_logfile(config, &status->current); + } + + /* New log file is now 'current'. */ + status->current = newlog; + } + else { + char error[120]; + apr_size_t nWrite; + + apr_strerror(rv, error, sizeof error); + + /* Uh-oh. Failed to open the new log file. Try to clear + * the previous log file, note the lost log entries, + * and keep on truckin'. */ + if (status->current.fd == NULL) { + fprintf(stderr, "Could not open log file '%s' (%s)\n", newlog.name, error); + exit(2); + } + + /* Throw away new state; it isn't going to be used. */ + apr_pool_destroy(newlog.pool); + + /* Try to keep this error message constant length + * in case it occurs several times. */ + apr_snprintf(status->errbuf, sizeof status->errbuf, + "Resetting log file due to error opening " + "new log file, %10d messages lost: %-25.25s\n", + status->nMessCount, error); + nWrite = strlen(status->errbuf); + + if (apr_file_trunc(status->current.fd, 0) != APR_SUCCESS) { + fprintf(stderr, "Error truncating the file %s\n", status->current.name); + exit(2); + } + if (apr_file_write(status->current.fd, status->errbuf, &nWrite) != APR_SUCCESS) { + fprintf(stderr, "Error writing to the file %s\n", status->current.name); + exit(2); + } + } + + status->nMessCount = 0; +} + +/* + * Get a size or time param from a string. + * Parameter 'last' indicates, whether the + * argument is the last commadnline argument. + * UTC offset is only allowed as a last argument + * in order to make is distinguishable from the + * rotation interval time. + */ +static const char *get_time_or_size(rotate_config_t *config, + const char *arg, int last) { + char *ptr = NULL; + /* Byte multiplier */ + unsigned int mult = 1; + if ((ptr = strchr(arg, 'B')) != NULL) { /* Found KB size */ + mult = 1; + } + else if ((ptr = strchr(arg, 'K')) != NULL) { /* Found KB size */ + mult = 1024; + } + else if ((ptr = strchr(arg, 'M')) != NULL) { /* Found MB size */ + mult = 1024 * 1024; + } + else if ((ptr = strchr(arg, 'G')) != NULL) { /* Found GB size */ + mult = 1024 * 1024 * 1024; + } + if (ptr) { /* rotation based on file size */ + if (config->sRotation > 0) { + return "Rotation size parameter allowed only once"; + } + if (*(ptr+1) == '\0') { + config->sRotation = atoi(arg) * mult; + } + if (config->sRotation == 0) { + return "Invalid rotation size parameter"; + } + } + else if ((config->sRotation > 0 || config->tRotation > 0) && last) { + /* rotation based on elapsed time */ + if (config->use_localtime) { + return "UTC offset parameter is not valid with -l"; + } + config->utc_offset = atoi(arg) * 60; + } + else { /* rotation based on elapsed time */ + if (config->tRotation > 0) { + return "Rotation time parameter allowed only once"; + } + config->tRotation = atoi(arg); + if (config->tRotation <= 0) { + return "Invalid rotation time parameter"; + } + } + return NULL; +} + int main (int argc, const char * const argv[]) { - char buf[BUFSIZE], buf2[MAX_PATH], errbuf[ERRMSGSZ]; - int tLogEnd = 0, tRotation = 0, utc_offset = 0; - unsigned int sRotation = 0; - int nMessCount = 0; + char buf[BUFSIZE]; apr_size_t nRead, nWrite; - int use_strftime = 0; - int use_localtime = 0; - int bypass_io = 0; - int now = 0; - const char *szLogRoot; - apr_file_t *f_stdin, *nLogFD = NULL, *nLogFDprev = NULL; - apr_pool_t *pool; - apr_pool_t *pfile = NULL; - apr_pool_t *pfile_prev = NULL; + apr_file_t *f_stdin; + apr_file_t *f_stdout; apr_getopt_t *opt; apr_status_t rv; char c; - const char *optarg; - char *ptr = NULL; + const char *opt_arg; + const char *err = NULL; +#if APR_FILES_AS_SOCKETS + apr_pollfd_t pollfd = { 0 }; + apr_status_t pollret = APR_SUCCESS; + int polltimeout; +#endif apr_app_initialize(&argc, &argv, NULL); atexit(apr_terminate); - apr_pool_create(&pool, NULL); - apr_getopt_init(&opt, pool, argc, argv); - while ((rv = apr_getopt(opt, "lf", &c, &optarg)) == APR_SUCCESS) { + memset(&config, 0, sizeof config); + memset(&status, 0, sizeof status); + status.rotateReason = ROTATE_NONE; + + apr_pool_create(&status.pool, NULL); + apr_getopt_init(&opt, status.pool, argc, argv); +#if APR_FILES_AS_SOCKETS + while ((rv = apr_getopt(opt, "lL:p:ftvec", &c, &opt_arg)) == APR_SUCCESS) { +#else + while ((rv = apr_getopt(opt, "lL:p:ftve", &c, &opt_arg)) == APR_SUCCESS) { +#endif switch (c) { case 'l': - use_localtime = 1; + config.use_localtime = 1; + break; + case 'L': + config.linkfile = opt_arg; + break; + case 'p': + config.postrotate_prog = opt_arg; break; case 'f': - bypass_io = 1; + config.force_open = 1; + break; + case 't': + config.truncate = 1; break; + case 'v': + config.verbose = 1; + break; + case 'e': + config.echo = 1; + break; +#if APR_FILES_AS_SOCKETS + case 'c': + config.create_empty = 1; + break; +#endif } } @@ -152,195 +588,148 @@ int main (int argc, const char * const argv[]) usage(argv[0], NULL /* specific error message already issued */ ); } - if (opt->ind + 2 != argc && opt->ind + 3 != argc) { + /* + * After the initial flags we need 2 to 4 arguments, + * the file name, either the rotation interval time or size + * or both of them, and optionally the UTC offset. + */ + if ((argc - opt->ind < 2) || (argc - opt->ind > 4) ) { usage(argv[0], "Incorrect number of arguments"); } - szLogRoot = argv[opt->ind++]; + config.szLogRoot = argv[opt->ind++]; - ptr = strchr(argv[opt->ind], 'M'); - if (ptr) { /* rotation based on file size */ - if (*(ptr+1) == '\0') { - sRotation = atoi(argv[opt->ind]) * 1048576; - } - if (sRotation == 0) { - usage(argv[0], "Invalid rotation size parameter"); - } - } - else { /* rotation based on elapsed time */ - tRotation = atoi(argv[opt->ind]); - if (tRotation <= 0) { - usage(argv[0], "Invalid rotation time parameter"); + /* Read in the remaining flags, namely time, size and UTC offset. */ + for(; opt->ind < argc; opt->ind++) { + if ((err = get_time_or_size(&config, argv[opt->ind], + opt->ind < argc - 1 ? 0 : 1)) != NULL) { + usage(argv[0], err); } } - opt->ind++; - if (opt->ind < argc) { /* have UTC offset */ - if (use_localtime) { - usage(argv[0], "UTC offset parameter is not valid with -l"); - } - utc_offset = atoi(argv[opt->ind]) * 60; - } + config.use_strftime = (strchr(config.szLogRoot, '%') != NULL); - use_strftime = (strchr(szLogRoot, '%') != NULL); - if (apr_file_open_stdin(&f_stdin, pool) != APR_SUCCESS) { + if (apr_file_open_stdin(&f_stdin, status.pool) != APR_SUCCESS) { fprintf(stderr, "Unable to open stdin\n"); exit(1); } + if (apr_file_open_stdout(&f_stdout, status.pool) != APR_SUCCESS) { + fprintf(stderr, "Unable to open stdout\n"); + exit(1); + } + + /* + * Write out result of config parsing if verbose is set. + */ + if (config.verbose) { + dumpConfig(&config); + } + +#if APR_FILES_AS_SOCKETS + if (config.create_empty && config.tRotation) { + pollfd.p = status.pool; + pollfd.desc_type = APR_POLL_FILE; + pollfd.reqevents = APR_POLLIN; + pollfd.desc.f = f_stdin; + } +#endif + + /* + * Immediately open the logfile as we start, if we were forced + * to do so via '-f'. + */ + if (config.force_open) { + doRotate(&config, &status); + } + for (;;) { nRead = sizeof(buf); - /* - * Bypass reading stdin if we are forcing the logfile - * to be opened as soon as we start. Since we won't be - * writing anything, we just want to open the file. - * First time through is the only time we do this - * since we reset bypass_io after the 1st loop - */ - if (!bypass_io) { - if (apr_file_read(f_stdin, buf, &nRead) != APR_SUCCESS) { - exit(3); +#if APR_FILES_AS_SOCKETS + if (config.create_empty && config.tRotation) { + polltimeout = status.tLogEnd ? status.tLogEnd - get_now(&config) : config.tRotation; + if (polltimeout <= 0) { + pollret = APR_TIMEUP; } - } - if (tRotation) { - now = get_now(use_localtime, utc_offset); - if (nLogFD != NULL && now >= tLogEnd) { - nLogFDprev = nLogFD; - nLogFD = NULL; + else { + pollret = apr_poll(&pollfd, 1, &pollret, apr_time_from_sec(polltimeout)); } } - else if (sRotation) { - apr_finfo_t finfo; - apr_off_t current_size = -1; - - if ((nLogFD != NULL) && - (apr_file_info_get(&finfo, APR_FINFO_SIZE, nLogFD) == APR_SUCCESS)) { - current_size = finfo.size; + if (pollret == APR_SUCCESS) { + rv = apr_file_read(f_stdin, buf, &nRead); + if (APR_STATUS_IS_EOF(rv)) { + break; } - - if (current_size > sRotation) { - nLogFDprev = nLogFD; - nLogFD = NULL; + else if (rv != APR_SUCCESS) { + exit(3); } } + else if (pollret == APR_TIMEUP) { + *buf = 0; + nRead = 0; + } else { - fprintf(stderr, "No rotation time or size specified\n"); - exit(2); + fprintf(stderr, "Unable to poll stdin\n"); + exit(5); + } +#else /* APR_FILES_AS_SOCKETS */ + rv = apr_file_read(f_stdin, buf, &nRead); + if (APR_STATUS_IS_EOF(rv)) { + break; + } + else if (rv != APR_SUCCESS) { + exit(3); + } +#endif /* APR_FILES_AS_SOCKETS */ + checkRotate(&config, &status); + if (status.rotateReason != ROTATE_NONE) { + doRotate(&config, &status); } - if (nLogFD == NULL) { - int tLogStart; - apr_status_t rv; - - if (tRotation) { - tLogStart = (now / tRotation) * tRotation; - } - else { - tLogStart = get_now(use_localtime, utc_offset); - } - - if (use_strftime) { - apr_time_t tNow = apr_time_from_sec(tLogStart); - apr_time_exp_t e; - apr_size_t rs; + nWrite = nRead; + rv = apr_file_write(status.current.fd, buf, &nWrite); + if (rv == APR_SUCCESS && nWrite != nRead) { + /* buffer partially written, which for rotatelogs means we encountered + * an error such as out of space or quota or some other limit reached; + * try to write the rest so we get the real error code + */ + apr_size_t nWritten = nWrite; - apr_time_exp_gmt(&e, tNow); - apr_strftime(buf2, &rs, sizeof(buf2), szLogRoot, &e); - } - else { - apr_snprintf(buf2, sizeof(buf2), "%s.%010d", szLogRoot, tLogStart); - } - tLogEnd = tLogStart + tRotation; - pfile_prev = pfile; - apr_pool_create(&pfile, pool); - rv = apr_file_open(&nLogFD, buf2, APR_WRITE | APR_CREATE | APR_APPEND, - APR_OS_DEFAULT, pfile); - if (rv != APR_SUCCESS) { - char error[120]; - - apr_strerror(rv, error, sizeof error); - - /* Uh-oh. Failed to open the new log file. Try to clear - * the previous log file, note the lost log entries, - * and keep on truckin'. */ - if (nLogFDprev == NULL) { - fprintf(stderr, "Could not open log file '%s' (%s)\n", buf2, error); - exit(2); - } - else { - nLogFD = nLogFDprev; - apr_pool_destroy(pfile); - pfile = pfile_prev; - /* Try to keep this error message constant length - * in case it occurs several times. */ - apr_snprintf(errbuf, sizeof errbuf, - "Resetting log file due to error opening " - "new log file, %10d messages lost: %-25.25s\n", - nMessCount, error); - nWrite = strlen(errbuf); - apr_file_trunc(nLogFD, 0); - if (apr_file_write(nLogFD, errbuf, &nWrite) != APR_SUCCESS) { - fprintf(stderr, "Error writing to the file %s\n", buf2); - exit(2); - } - } - } - else if (nLogFDprev) { - apr_file_close(nLogFDprev); - if (pfile_prev) { - apr_pool_destroy(pfile_prev); - } - } - nMessCount = 0; - } - /* - * If we just bypassed reading stdin, due to bypass_io, - * then we have nothing to write, so skip this. - */ - if (!bypass_io) { + nRead = nRead - nWritten; nWrite = nRead; - rv = apr_file_write(nLogFD, buf, &nWrite); - if (rv == APR_SUCCESS && nWrite != nRead) { - /* buffer partially written, which for rotatelogs means we encountered - * an error such as out of space or quota or some other limit reached; - * try to write the rest so we get the real error code - */ - apr_size_t nWritten = nWrite; - - nRead = nRead - nWritten; - nWrite = nRead; - rv = apr_file_write(nLogFD, buf + nWritten, &nWrite); + rv = apr_file_write(status.current.fd, buf + nWritten, &nWrite); + } + if (nWrite != nRead) { + char strerrbuf[120]; + apr_off_t cur_offset; + + cur_offset = 0; + if (apr_file_seek(status.current.fd, APR_CUR, &cur_offset) != APR_SUCCESS) { + cur_offset = -1; } - if (nWrite != nRead) { - char strerrbuf[120]; - apr_off_t cur_offset; - - cur_offset = 0; - if (apr_file_seek(nLogFD, APR_CUR, &cur_offset) != APR_SUCCESS) { - cur_offset = -1; - } - apr_strerror(rv, strerrbuf, sizeof strerrbuf); - nMessCount++; - apr_snprintf(errbuf, sizeof errbuf, - "Error %d writing to log file at offset %" APR_OFF_T_FMT ". " - "%10d messages lost (%s)\n", - rv, cur_offset, nMessCount, strerrbuf); - nWrite = strlen(errbuf); - apr_file_trunc(nLogFD, 0); - if (apr_file_write(nLogFD, errbuf, &nWrite) != APR_SUCCESS) { - fprintf(stderr, "Error writing to the file %s\n", buf2); + apr_strerror(rv, strerrbuf, sizeof strerrbuf); + status.nMessCount++; + apr_snprintf(status.errbuf, sizeof status.errbuf, + "Error %d writing to log file at offset %" APR_OFF_T_FMT ". " + "%10d messages lost (%s)\n", + rv, cur_offset, status.nMessCount, strerrbuf); + nWrite = strlen(status.errbuf); + apr_file_trunc(status.current.fd, 0); + if (apr_file_write(status.current.fd, status.errbuf, &nWrite) != APR_SUCCESS) { + fprintf(stderr, "Error writing to the file %s\n", status.current.name); exit(2); - } - } - else { - nMessCount++; } } else { - /* now worry about reading 'n writing all the time */ - bypass_io = 0; + status.nMessCount++; + } + if (config.echo) { + if (apr_file_write_full(f_stdout, buf, nRead, &nWrite)) { + fprintf(stderr, "Unable to write to stdout\n"); + exit(4); + } } } - /* Of course we never, but prevent compiler warnings */ - return 0; + + return 0; /* reached only at stdin EOF. */ } -- cgit v1.2.3