base: Make log reopen option thread-safe
This commit is contained in:
166
lib/base/log.c
166
lib/base/log.c
@@ -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)
|
for (i = 0, j = 0; msg[i]; i++)
|
||||||
goto out;
|
if (msg[i] >= 32 || msg[i] == '\t')
|
||||||
for (i=0, j=0; msg[i]; i++)
|
msgclean[j++] = msg[i];
|
||||||
if (msg[i] >= 32 || msg[i] == '\t')
|
fprintf(logf, "%s %s\n", timestr ? timestr : "", msgclean);
|
||||||
msgclean[j++] = msg[i];
|
free(msgclean);
|
||||||
fprintf(f->fd, "%s %s\n", timestr, 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] = "";
|
||||||
|
Reference in New Issue
Block a user