summaryrefslogtreecommitdiffstats
path: root/e2fsck/logfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'e2fsck/logfile.c')
-rw-r--r--e2fsck/logfile.c411
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