base: Make log reopen option thread-safe

This commit is contained in:
Nicolas Williams
2020-08-14 20:35:57 -05:00
parent faee4626fb
commit 7208217410

View File

@@ -199,38 +199,44 @@ open_syslog(heim_context context,
} }
struct file_data { struct file_data {
const char *filename; char *filename;
const char *mode; const char *mode;
struct timeval tv; struct timeval tv;
FILE *fd; FILE *fd;
int disp; int disp;
#define FILEDISP_KEEPOPEN 0x1 #define FILEDISP_KEEPOPEN 0x1
#define FILEDISP_REOPEN 0x2 #define FILEDISP_REOPEN 0x2
#define FILEDISP_IFEXISTS 0x3 #define FILEDISP_IFEXISTS 0x4
int freefilename;
}; };
static void HEIM_CALLCONV #ifndef O_CLOEXEC
#define O_CLOEXEC 0
#endif
static void
log_file(heim_context context, const char *timestr, const char *msg, void *data) log_file(heim_context context, const char *timestr, const char *msg, void *data)
{ {
struct timeval tv; struct timeval tv;
struct file_data *f = data; struct file_data *f = data;
FILE *logf = f->fd;
char *msgclean; char *msgclean;
size_t i; size_t i = 0;
size_t j; size_t j;
if (f->disp != FILEDISP_KEEPOPEN) { if (logf == NULL || (f->disp & FILEDISP_REOPEN)) {
char *filename; int flags = O_WRONLY|O_APPEND;
int flags = -1;
int fd; int fd;
if (f->mode[0] == 'w' && f->mode[1] == 0) if (f->mode[0] == 'e') {
flags = O_WRONLY|O_TRUNC; flags |= O_CLOEXEC;
if (f->mode[0] == 'a' && f->mode[1] == 0) i = 1;
flags = O_WRONLY|O_APPEND; }
assert(flags != -1); if (f->mode[i] == 'w')
flags |= O_TRUNC;
if (f->mode[i + 1] == '+')
flags |= O_RDWR;
if (f->disp == FILEDISP_IFEXISTS) { if (f->disp & FILEDISP_IFEXISTS) {
/* Cache failure for 1s */ /* Cache failure for 1s */
gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
if (tv.tv_sec == f->tv.tv_sec) if (tv.tv_sec == f->tv.tv_sec)
@@ -239,18 +245,18 @@ log_file(heim_context context, const char *timestr, const char *msg, void *data)
flags |= O_CREAT; flags |= O_CREAT;
} }
if (heim_expand_path_tokens(context, f->filename, 1, &filename, NULL)) fd = open(f->filename, flags, 0666); /* umask best be set */
return;
fd = open(filename, flags, 0666);
free(filename);
if (fd == -1) { if (fd == -1) {
if (f->disp == FILEDISP_IFEXISTS) if (f->disp & FILEDISP_IFEXISTS)
gettimeofday(&f->tv, NULL); gettimeofday(&f->tv, NULL);
return; return;
} }
f->fd = fdopen(fd, f->mode); rk_cloexec(fd);
logf = fdopen(fd, f->mode);
} }
if (f->fd == NULL) if (f->fd == NULL && (f->disp & FILEDISP_KEEPOPEN))
f->fd = logf;
if (logf == NULL)
return; return;
/* /*
* make sure the log doesn't contain special chars: * make sure the log doesn't contain special chars:
@@ -260,50 +266,58 @@ log_file(heim_context context, const char *timestr, const char *msg, void *data)
* been quoted such as what krb5_unparse_principal() gives us. * been quoted such as what krb5_unparse_principal() gives us.
* So, we change here to eat the special characters, instead. * So, we change here to eat the special characters, instead.
*/ */
msgclean = strdup(msg); if (msg && (msgclean = strdup(msg))) {
if (msgclean == NULL)
goto out;
for (i = 0, j = 0; msg[i]; i++) for (i = 0, j = 0; msg[i]; i++)
if (msg[i] >= 32 || msg[i] == '\t') if (msg[i] >= 32 || msg[i] == '\t')
msgclean[j++] = msg[i]; msgclean[j++] = msg[i];
fprintf(f->fd, "%s %s\n", timestr, msgclean); fprintf(logf, "%s %s\n", timestr ? timestr : "", msgclean);
free(msgclean); free(msgclean);
out:
if (f->disp != FILEDISP_KEEPOPEN) {
fclose(f->fd);
f->fd = NULL;
} }
if (logf != f->fd)
fclose(logf);
} }
static void HEIM_CALLCONV static void HEIM_CALLCONV
close_file(void *data) close_file(void *data)
{ {
struct file_data *f = data; struct file_data *f = data;
if (f->disp == FILEDISP_KEEPOPEN && f->filename) if (f->fd && f->fd != stdout && f->fd != stderr)
fclose(f->fd); fclose(f->fd);
if (f->filename && f->freefilename) free(f->filename);
free((char *)f->filename);
free(data); free(data);
} }
static heim_error_code static heim_error_code
open_file(heim_context context, heim_log_facility *fac, int min, int max, open_file(heim_context context, heim_log_facility *fac, int min, int max,
const char *filename, const char *mode, FILE *f, int disp, const char *filename, const char *mode, FILE *f, int disp,
int freefilename) int exp_tokens)
{ {
struct file_data *fd = malloc(sizeof(*fd)); heim_error_code ret = 0;
if (fd == NULL) { struct file_data *fd;
if (freefilename && filename)
free((char *)filename); if ((fd = calloc(1, sizeof(*fd))) == NULL)
return heim_enomem(context); return heim_enomem(context);
}
fd->filename = filename; fd->filename = NULL;
fd->mode = mode; fd->mode = mode;
fd->fd = f; fd->fd = f;
fd->disp = disp; fd->disp = disp;
fd->freefilename = freefilename;
return heim_addlog_func(context, fac, min, max, log_file, close_file, fd); if (filename) {
if (exp_tokens)
ret = heim_expand_path_tokens(context, filename, 1, &fd->filename, NULL);
else if ((fd->filename = strdup(filename)) == NULL)
ret = heim_enomem(context);
}
if (ret == 0)
ret = heim_addlog_func(context, fac, min, max, log_file, close_file, fd);
if (ret) {
free(fd->filename);
free(fd);
}
if (disp & FILEDISP_KEEPOPEN)
log_file(context, NULL, NULL, fd);
return ret;
} }
heim_error_code heim_error_code
@@ -346,48 +360,30 @@ heim_addlog_dest(heim_context context, heim_log_facility *f, const char *orig)
p++; p++;
} }
if (strcmp(p, "STDERR") == 0) { if (strcmp(p, "STDERR") == 0) {
ret = open_file(context, f, min, max, NULL, NULL, stderr, 1, 0); ret = open_file(context, f, min, max, NULL, NULL, stderr,
FILEDISP_KEEPOPEN, 0);
} else if (strcmp(p, "CONSOLE") == 0) { } else if (strcmp(p, "CONSOLE") == 0) {
/* XXX WIN32 */
ret = open_file(context, f, min, max, "/dev/console", "w", NULL, ret = open_file(context, f, min, max, "/dev/console", "w", NULL,
FILEDISP_REOPEN, 0); FILEDISP_KEEPOPEN, 0);
} else if (strncmp(p, "EFILE", 5) == 0 && p[5] == ':') { } else if (strncmp(p, "EFILE:", 5) == 0) {
ret = open_file(context, f, min, max, strdup(p+6), "a", NULL, ret = open_file(context, f, min, max, p + sizeof("EFILE:") - 1, "a",
FILEDISP_IFEXISTS, 1); NULL, FILEDISP_IFEXISTS | FILEDISP_REOPEN, 1);
} else if (strncmp(p, "FILE", 4) == 0 && (p[4] == ':' || p[4] == '=')) { } else if (strncmp(p, "EFILE=", 5) == 0) {
char *fn; ret = open_file(context, f, min, max, p + sizeof("EFILE=") - 1, "a",
FILE *file = NULL; NULL, FILEDISP_IFEXISTS | FILEDISP_KEEPOPEN, 1);
int disp = FILEDISP_REOPEN; } else if (strncmp(p, "FILE:", sizeof("FILE:") - 1) == 0) {
fn = strdup(p + 5); ret = open_file(context, f, min, max, p + sizeof("FILE:") - 1, "a",
if (fn == NULL) NULL, FILEDISP_REOPEN, 1);
return heim_enomem(context); } else if (strncmp(p, "FILE=", sizeof("FILE=") - 1) == 0) {
if (p[4] == '=') { ret = open_file(context, f, min, max, p + sizeof("FILE=") - 1, "a",
int i = open(fn, O_WRONLY | O_CREAT | NULL, FILEDISP_KEEPOPEN, 1);
O_TRUNC | O_APPEND, 0666); } else if (strncmp(p, "DEVICE:", sizeof("DEVICE:") - 1) == 0) {
if (i < 0) { ret = open_file(context, f, min, max, p + sizeof("DEVICE:") - 1, "a",
ret = errno; NULL, FILEDISP_REOPEN, 0);
heim_set_error_message(context, ret, } else if (strncmp(p, "DEVICE=", sizeof("DEVICE=") - 1) == 0) {
N_("open(%s) logfile: %s", ""), fn, ret = open_file(context, f, min, max, p + sizeof("DEVICE=") - 1, "a",
strerror(ret)); NULL, FILEDISP_KEEPOPEN, 0);
free(fn);
return ret;
}
rk_cloexec(i);
file = fdopen(i, "a");
if (file == NULL) {
ret = errno;
close(i);
heim_set_error_message(context, ret,
N_("fdopen(%s) logfile: %s", ""),
fn, strerror(ret));
free(fn);
return ret;
}
disp = FILEDISP_KEEPOPEN;
}
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,
FILEDISP_REOPEN, 1);
} else if (strncmp(p, "SYSLOG", 6) == 0 && (p[6] == '\0' || p[6] == ':')) { } else if (strncmp(p, "SYSLOG", 6) == 0 && (p[6] == '\0' || p[6] == ':')) {
char severity[128] = ""; char severity[128] = "";
char facility[128] = ""; char facility[128] = "";