diff --git a/lib/krb5/krb5_openlog.3 b/lib/krb5/krb5_openlog.3 index f233d3c29..85599eed0 100644 --- a/lib/krb5/krb5_openlog.3 +++ b/lib/krb5/krb5_openlog.3 @@ -161,13 +161,24 @@ follows: .Bl -tag -width "xxx" -offset indent .It Li STDERR This logs to the program's stderr. +.It Li EFILE: Ns Pa /file +Log to the specified file if it exists, otherwise do nothing. +All writes will be appended to the end of the file and the file +will be re-opened for each new write. +Non-existence of the file is cached for 1 second which reduces +the potential performance impact significantly. +This is useful for defining a trace file which can be enabled +without restarting a server. .It Li FILE: Ns Pa /file +Log to the specified file. +All writes will be appended to the end of the file and the file +will be re-opened for each new write. .It Li FILE= Ns Pa /file -Log to the specified file. The form using a colon appends to the file, the -form with an equal truncates the file. The truncating form keeps the file -open, while the appending form closes it after each log message (which -makes it possible to rotate logs). The truncating form is mainly for -compatibility with the MIT libkrb5. +On the first write, this form will +.Xr truncate 2 +the file and then append all subsequent messages whilst keeping the +file descriptor open. +This form is mainly for compatibility with MIT libkrb5. .It Li DEVICE= Ns Pa /device This logs to the specified device, at present this is the same as .Li FILE:/device . @@ -255,6 +266,7 @@ and facility .Bd -literal -offset indent [logging] kdc = FILE:/var/log/kdc-%{strftime:%Y%m%d%H} + kdc = 4-/EFILE:/tmp/kdc-trace .Ed .Pp This will log all messages from the @@ -266,6 +278,9 @@ As the file is .Xr open 2 ed each time a log message is written, this can be used to write automatically rotating log files. +All of the KDC debugging messages will be written into +.Pa /tmp/kdc-trace +but only if it exists. .Sh SEE ALSO .Xr syslog 3 , .Xr krb5.conf 5 diff --git a/lib/krb5/log.c b/lib/krb5/log.c index 2b8dedf79..fc233c897 100644 --- a/lib/krb5/log.c +++ b/lib/krb5/log.c @@ -34,6 +34,7 @@ */ #include "krb5_locl.h" +#include #include struct facility { @@ -195,27 +196,55 @@ open_syslog(krb5_context context, log_syslog, close_syslog, sd); } -struct file_data{ +struct file_data { const char *filename; const char *mode; + struct timeval tv; FILE *fd; - int keep_open; + int disp; +#define FILEDISP_KEEPOPEN 0x1 +#define FILEDISP_REOPEN 0x2 +#define FILEDISP_IFEXISTS 0x3 int freefilename; }; static void KRB5_CALLCONV log_file(krb5_context context, const char *timestr, const char *msg, void *data) { + struct timeval tv; struct file_data *f = data; char *msgclean; size_t len = strlen(msg); - if (f->keep_open == 0) { + if (f->disp != FILEDISP_KEEPOPEN) { char *filename; + int flags = -1; + int fd; + + if (f->mode[0] == 'w' && f->mode[1] == 0) + flags = O_WRONLY|O_TRUNC; + if (f->mode[0] == 'a' && f->mode[1] == 0) + flags = O_WRONLY|O_APPEND; + assert(flags != -1); + + if (f->disp == FILEDISP_IFEXISTS) { + /* Cache failure for 1s */ + gettimeofday(&tv, NULL); + if (tv.tv_sec == f->tv.tv_sec) + return; + } else { + flags |= O_CREAT; + } if (_krb5_expand_path_tokens(context, f->filename, 1, &filename)) return; - f->fd = fopen(filename, f->mode); + fd = open(filename, flags, 0666); + if (fd == -1) { + if (f->disp == FILEDISP_IFEXISTS) + gettimeofday(&f->tv, NULL); + return; + } + f->fd = fdopen(fd, f->mode); free(filename); } if(f->fd == NULL) @@ -228,7 +257,7 @@ log_file(krb5_context context, const char *timestr, const char *msg, void *data) fprintf(f->fd, "%s %s\n", timestr, msgclean); free(msgclean); out: - if(f->keep_open == 0) { + if(f->disp != FILEDISP_KEEPOPEN) { fclose(f->fd); f->fd = NULL; } @@ -238,7 +267,7 @@ static void KRB5_CALLCONV close_file(void *data) { struct file_data *f = data; - if(f->keep_open && f->filename) + if(f->disp == FILEDISP_KEEPOPEN && f->filename) fclose(f->fd); if (f->filename && f->freefilename) free((char *)f->filename); @@ -247,7 +276,7 @@ close_file(void *data) static krb5_error_code open_file(krb5_context context, krb5_log_facility *fac, int min, int max, - const char *filename, const char *mode, FILE *f, int keep_open, + const char *filename, const char *mode, FILE *f, int disp, int freefilename) { struct file_data *fd = malloc(sizeof(*fd)); @@ -259,7 +288,7 @@ open_file(krb5_context context, krb5_log_facility *fac, int min, int max, fd->filename = filename; fd->mode = mode; fd->fd = f; - fd->keep_open = keep_open; + fd->disp = disp; fd->freefilename = freefilename; return krb5_addlog_func(context, fac, min, max, log_file, close_file, fd); @@ -309,11 +338,15 @@ krb5_addlog_dest(krb5_context context, krb5_log_facility *f, const char *orig) if(strcmp(p, "STDERR") == 0){ ret = open_file(context, f, min, max, NULL, NULL, stderr, 1, 0); }else if(strcmp(p, "CONSOLE") == 0){ - ret = open_file(context, f, min, max, "/dev/console", "w", NULL, 0, 0); + ret = open_file(context, f, min, max, "/dev/console", "w", NULL, + FILEDISP_REOPEN, 0); + }else if (strncmp(p, "EFILE", 5) == 0 && p[5] == ':') { + ret = open_file(context, f, min, max, strdup(p+6), "a", NULL, + FILEDISP_IFEXISTS, 1); }else if(strncmp(p, "FILE", 4) == 0 && (p[4] == ':' || p[4] == '=')){ char *fn; FILE *file = NULL; - int keep_open = 0; + int disp = FILEDISP_REOPEN; fn = strdup(p + 5); if (fn == NULL) return krb5_enomem(context); @@ -339,11 +372,12 @@ krb5_addlog_dest(krb5_context context, krb5_log_facility *f, const char *orig) free(fn); return ret; } - keep_open = 1; + disp = FILEDISP_KEEPOPEN; } - ret = open_file(context, f, min, max, fn, "a", file, keep_open, 1); + ret = open_file(context, f, min, max, fn, "a", file, disp, 1); }else if(strncmp(p, "DEVICE", 6) == 0 && (p[6] == ':' || p[6] == '=')){ - ret = open_file(context, f, min, max, strdup(p + 7), "w", NULL, 0, 1); + ret = open_file(context, f, min, max, strdup(p + 7), "w", NULL, + FILEDISP_REOPEN, 1); }else if(strncmp(p, "SYSLOG", 6) == 0 && (p[6] == '\0' || p[6] == ':')){ char severity[128] = ""; char facility[128] = "";