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 {
const char *filename;
char *filename;
const char *mode;
struct timeval tv;
FILE *fd;
int disp;
#define FILEDISP_KEEPOPEN 0x1
#define FILEDISP_REOPEN 0x2
#define FILEDISP_IFEXISTS 0x3
int freefilename;
#define FILEDISP_IFEXISTS 0x4
};
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)
{
struct timeval tv;
struct file_data *f = data;
FILE *logf = f->fd;
char *msgclean;
size_t i;
size_t i = 0;
size_t j;
if (f->disp != FILEDISP_KEEPOPEN) {
char *filename;
int flags = -1;
if (logf == NULL || (f->disp & FILEDISP_REOPEN)) {
int flags = O_WRONLY|O_APPEND;
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->mode[0] == 'e') {
flags |= O_CLOEXEC;
i = 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 */
gettimeofday(&tv, NULL);
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;
}
if (heim_expand_path_tokens(context, f->filename, 1, &filename, NULL))
return;
fd = open(filename, flags, 0666);
free(filename);
fd = open(f->filename, flags, 0666); /* umask best be set */
if (fd == -1) {
if (f->disp == FILEDISP_IFEXISTS)
if (f->disp & FILEDISP_IFEXISTS)
gettimeofday(&f->tv, NULL);
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;
/*
* 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.
* So, we change here to eat the special characters, instead.
*/
msgclean = strdup(msg);
if (msgclean == NULL)
goto out;
for (i=0, j=0; msg[i]; i++)
if (msg[i] >= 32 || msg[i] == '\t')
msgclean[j++] = msg[i];
fprintf(f->fd, "%s %s\n", timestr, msgclean);
free(msgclean);
out:
if (f->disp != FILEDISP_KEEPOPEN) {
fclose(f->fd);
f->fd = NULL;
if (msg && (msgclean = strdup(msg))) {
for (i = 0, j = 0; msg[i]; i++)
if (msg[i] >= 32 || msg[i] == '\t')
msgclean[j++] = msg[i];
fprintf(logf, "%s %s\n", timestr ? timestr : "", msgclean);
free(msgclean);
}
if (logf != f->fd)
fclose(logf);
}
static void HEIM_CALLCONV
close_file(void *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);
if (f->filename && f->freefilename)
free((char *)f->filename);
free(f->filename);
free(data);
}
static heim_error_code
open_file(heim_context context, heim_log_facility *fac, int min, int max,
const char *filename, const char *mode, FILE *f, int disp,
int freefilename)
int exp_tokens)
{
struct file_data *fd = malloc(sizeof(*fd));
if (fd == NULL) {
if (freefilename && filename)
free((char *)filename);
heim_error_code ret = 0;
struct file_data *fd;
if ((fd = calloc(1, sizeof(*fd))) == NULL)
return heim_enomem(context);
}
fd->filename = filename;
fd->filename = NULL;
fd->mode = mode;
fd->fd = f;
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
@@ -346,48 +360,30 @@ heim_addlog_dest(heim_context context, heim_log_facility *f, const char *orig)
p++;
}
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) {
/* XXX WIN32 */
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 disp = FILEDISP_REOPEN;
fn = strdup(p + 5);
if (fn == NULL)
return heim_enomem(context);
if (p[4] == '=') {
int i = open(fn, O_WRONLY | O_CREAT |
O_TRUNC | O_APPEND, 0666);
if (i < 0) {
ret = errno;
heim_set_error_message(context, ret,
N_("open(%s) logfile: %s", ""), fn,
strerror(ret));
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);
FILEDISP_KEEPOPEN, 0);
} else if (strncmp(p, "EFILE:", 5) == 0) {
ret = open_file(context, f, min, max, p + sizeof("EFILE:") - 1, "a",
NULL, FILEDISP_IFEXISTS | FILEDISP_REOPEN, 1);
} else if (strncmp(p, "EFILE=", 5) == 0) {
ret = open_file(context, f, min, max, p + sizeof("EFILE=") - 1, "a",
NULL, FILEDISP_IFEXISTS | FILEDISP_KEEPOPEN, 1);
} else if (strncmp(p, "FILE:", sizeof("FILE:") - 1) == 0) {
ret = open_file(context, f, min, max, p + sizeof("FILE:") - 1, "a",
NULL, FILEDISP_REOPEN, 1);
} else if (strncmp(p, "FILE=", sizeof("FILE=") - 1) == 0) {
ret = open_file(context, f, min, max, p + sizeof("FILE=") - 1, "a",
NULL, FILEDISP_KEEPOPEN, 1);
} else if (strncmp(p, "DEVICE:", sizeof("DEVICE:") - 1) == 0) {
ret = open_file(context, f, min, max, p + sizeof("DEVICE:") - 1, "a",
NULL, FILEDISP_REOPEN, 0);
} else if (strncmp(p, "DEVICE=", sizeof("DEVICE=") - 1) == 0) {
ret = open_file(context, f, min, max, p + sizeof("DEVICE=") - 1, "a",
NULL, FILEDISP_KEEPOPEN, 0);
} else if (strncmp(p, "SYSLOG", 6) == 0 && (p[6] == '\0' || p[6] == ':')) {
char severity[128] = "";
char facility[128] = "";