diff options
Diffstat (limited to 'e2fsck/logfile.c')
-rw-r--r-- | e2fsck/logfile.c | 411 |
1 files changed, 411 insertions, 0 deletions
diff --git a/e2fsck/logfile.c b/e2fsck/logfile.c new file mode 100644 index 0000000..9d79eed --- /dev/null +++ b/e2fsck/logfile.c @@ -0,0 +1,411 @@ +/* + * logfile.c --- set up e2fsck log files + * + * Copyright 1996, 1997 by Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include "config.h" +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include "e2fsck.h" +#include <pwd.h> + +extern e2fsck_t e2fsck_global_ctx; /* Try your very best not to use this! */ + +struct string { + char *s; + int len; + int end; +}; + +static void alloc_string(struct string *s, int len) +{ + s->s = malloc(len); +/* e2fsck_allocate_memory(ctx, len, "logfile name"); */ + s->len = s->s ? len : 0; + s->end = 0; +} + +static void append_string(struct string *s, const char *a, int len) +{ + int needlen; + + if (!len) + len = strlen(a); + + needlen = s->end + len + 1; + if (needlen > s->len) { + char *n; + + if (s->len * 2 > needlen) + needlen = s->len * 2; + n = realloc(s->s, needlen); + + if (n) { + s->s = n; + s->len = needlen; + } else { + /* Don't append if we ran out of memory */ + return; + } + } + memcpy(s->s + s->end, a, len); + s->end += len; + s->s[s->end] = 0; +} + +#define FLAG_UTC 0x0001 + +static void expand_percent_expression(e2fsck_t ctx, char ch, + struct string *s, int *flags) +{ + struct tm *tm = NULL, tm_struct; + struct passwd *pw = NULL, pw_struct; + char *cp; + char buf[256]; + + if ((ch == 'D') || (ch == 'd') || (ch == 'm') || (ch == 'y') || + (ch == 'Y') || + (ch == 'T') || (ch == 'H') || (ch == 'M') || (ch == 'S')) { + tzset(); + tm = (*flags & FLAG_UTC) ? gmtime_r(&ctx->now, &tm_struct) : + localtime_r(&ctx->now, &tm_struct); + } + + switch (ch) { + case '%': + append_string(s, "%", 1); + return; + case 'd': + sprintf(buf, "%02d", tm->tm_mday); + break; + case 'D': + sprintf(buf, "%d%02d%02d", tm->tm_year + 1900, tm->tm_mon + 1, + tm->tm_mday); + break; + case 'h': +#ifdef TEST_PROGRAM + strcpy(buf, "server"); +#else + buf[0] = 0; + gethostname(buf, sizeof(buf)); + buf[sizeof(buf)-1] = 0; +#endif + break; + case 'H': + sprintf(buf, "%02d", tm->tm_hour); + break; + case 'm': + sprintf(buf, "%02d", tm->tm_mon + 1); + break; + case 'M': + sprintf(buf, "%02d", tm->tm_min); + break; + case 'N': /* block device name */ + cp = strrchr(ctx->filesystem_name, '/'); + if (cp) + cp++; + else + cp = ctx->filesystem_name; + append_string(s, cp, 0); + return; + case 'p': + sprintf(buf, "%lu", (unsigned long) getpid()); + break; + case 's': + sprintf(buf, "%lu", (unsigned long) ctx->now); + break; + case 'S': + sprintf(buf, "%02d", tm->tm_sec); + break; + case 'T': + sprintf(buf, "%02d%02d%02d", tm->tm_hour, tm->tm_min, + tm->tm_sec); + break; + case 'u': +#ifdef TEST_PROGRAM + strcpy(buf, "tytso"); + break; +#else +#ifdef HAVE_GETPWUID_R + getpwuid_r(getuid(), &pw_struct, buf, sizeof(buf), &pw); +#else + pw = getpwuid(getuid()); +#endif + if (pw) + append_string(s, pw->pw_name, 0); + return; +#endif + case 'U': + *flags |= FLAG_UTC; + return; + case 'y': + sprintf(buf, "%02d", tm->tm_year % 100); + break; + case 'Y': + sprintf(buf, "%d", tm->tm_year + 1900); + break; + default: + sprintf(buf, "%%%c", ch); + break; + } + append_string(s, buf, 0); +} + +static void expand_logfn(e2fsck_t ctx, const char *log_fn, struct string *s) +{ + const char *cp; + int i; + int flags = 0; + + alloc_string(s, 100); + for (cp = log_fn; *cp; cp++) { + if (cp[0] == '%') { + cp++; + expand_percent_expression(ctx, *cp, s, &flags); + continue; + } + for (i = 0; cp[i]; i++) + if (cp[i] == '%') + break; + append_string(s, cp, i); + cp += i-1; + } +} + +static int outbufsize; +static void *outbuf; + +static int do_read(int fd) +{ + int c; + char *n; + char buffer[4096]; + + c = read(fd, buffer, sizeof(buffer)-1); + if (c <= 0) + return c; + + n = realloc(outbuf, outbufsize + c); + if (n) { + outbuf = n; + memcpy(((char *)outbuf)+outbufsize, buffer, c); + outbufsize += c; + } + return c; +} + +/* + * Fork a child process to save the output of the logfile until the + * appropriate file system is mounted read/write. + */ +static FILE *save_output(const char *s0, const char *s1, const char *s2) +{ + int c, fd, fds[2]; + char *cp; + pid_t pid; + FILE *ret; + + if (s0 && *s0 == 0) + s0 = 0; + if (s1 && *s1 == 0) + s1 = 0; + if (s2 && *s2 == 0) + s2 = 0; + + /* At least one potential output file name is valid */ + if (!s0 && !s1 && !s2) + return NULL; + if (pipe(fds) < 0) { + perror("pipe"); + exit(1); + } + + pid = fork(); + if (pid < 0) { + perror("fork"); + exit(1); + } + + if (pid == 0) { + if (e2fsck_global_ctx && e2fsck_global_ctx->progress_fd) + close(e2fsck_global_ctx->progress_fd); + if (daemon(0, 0) < 0) { + perror("daemon"); + exit(1); + } + /* + * Grab the output from our parent + */ + close(fds[1]); + while (do_read(fds[0]) > 0) + ; + close(fds[0]); + + /* OK, now let's try to open the output file */ + fd = -1; + while (1) { + if (fd < 0 && s0) + fd = open(s0, O_WRONLY|O_CREAT|O_TRUNC, 0644); + if (fd < 0 && s1) + fd = open(s1, O_WRONLY|O_CREAT|O_TRUNC, 0644); + if (fd < 0 && s2) + fd = open(s2, O_WRONLY|O_CREAT|O_TRUNC, 0644); + if (fd >= 0) + break; + sleep(1); + } + + cp = outbuf; + while (outbufsize > 0) { + c = write(fd, cp, outbufsize); + if (c < 0) { + if ((errno == EAGAIN) || (errno == EINTR)) + continue; + break; + } + outbufsize -= c; + cp += c; + } + exit(0); + } + + close(fds[0]); + ret = fdopen(fds[1], "w"); + if (!ret) + close(fds[1]); + return ret; +} + +#ifndef TEST_PROGRAM +static FILE *set_up_log_file(e2fsck_t ctx, const char *key, const char *fn) +{ + FILE *f = NULL; + struct string s, s1, s2; + char *s0 = 0, *log_dir = 0, *log_fn = 0; + int log_dir_wait = 0; + + s.s = s1.s = s2.s = 0; + + profile_get_boolean(ctx->profile, "options", "log_dir_wait", 0, 0, + &log_dir_wait); + if (fn) + log_fn = string_copy(ctx, fn, 0); + else + profile_get_string(ctx->profile, "options", key, + 0, 0, &log_fn); + profile_get_string(ctx->profile, "options", "log_dir", 0, 0, &log_dir); + + if (!log_fn || !log_fn[0]) + goto out; + + expand_logfn(ctx, log_fn, &s); + if ((log_fn[0] == '/') || !log_dir || !log_dir[0]) + s0 = s.s; + + if (log_dir && log_dir[0]) { + alloc_string(&s1, strlen(log_dir) + strlen(s.s) + 2); + append_string(&s1, log_dir, 0); + append_string(&s1, "/", 1); + append_string(&s1, s.s, 0); + } + + free(log_dir); + profile_get_string(ctx->profile, "options", "log_dir_fallback", 0, 0, + &log_dir); + if (log_dir && log_dir[0]) { + alloc_string(&s2, strlen(log_dir) + strlen(s.s) + 2); + append_string(&s2, log_dir, 0); + append_string(&s2, "/", 1); + append_string(&s2, s.s, 0); + printf("%s\n", s2.s); + } + + if (s0) + f = fopen(s0, "w"); + if (!f && s1.s) + f = fopen(s1.s, "w"); + if (!f && s2.s) + f = fopen(s2.s, "w"); + if (!f && log_dir_wait) + f = save_output(s0, s1.s, s2.s); + +out: + free(s.s); + free(s1.s); + free(s2.s); + free(log_fn); + free(log_dir); + return f; +} + +void set_up_logging(e2fsck_t ctx) +{ + ctx->logf = set_up_log_file(ctx, "log_filename", ctx->log_fn); + ctx->problem_logf = set_up_log_file(ctx, "problem_log_filename", + ctx->problem_log_fn); +} +#else +void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned long size, + const char *description) +{ + void *ret; + char buf[256]; + + ret = malloc(size); + if (!ret) { + sprintf(buf, "Can't allocate %s\n", description); + exit(1); + } + memset(ret, 0, size); + return ret; +} + +errcode_t e2fsck_allocate_context(e2fsck_t *ret) +{ + e2fsck_t context; + errcode_t retval; + char *time_env; + + context = malloc(sizeof(struct e2fsck_struct)); + if (!context) + return ENOMEM; + + memset(context, 0, sizeof(struct e2fsck_struct)); + + context->now = 1332006474; + + context->filesystem_name = "/dev/sda3"; + context->device_name = "fslabel"; + + *ret = context; + return 0; +} + +int main(int argc, char **argv) +{ + e2fsck_t ctx; + struct string s; + + putenv("TZ=EST+5:00"); + e2fsck_allocate_context(&ctx); + expand_logfn(ctx, "e2fsck-%N.%h.%u.%D-%T", &s); + printf("%s\n", s.s); + free(s.s); + expand_logfn(ctx, "e2fsck-%N.%h.%u.%Y%m%d-%H%M%S", &s); + printf("%s\n", s.s); + free(s.s); + + return 0; +} +#endif |