Whamcloud - gitweb
3bb15cd3f2c0b71abc8c3c12da9848b274df8b40
[tools/e2fsprogs.git] / e2fsck / logfile.c
1 /*
2  * logfile.c --- set up e2fsck log files
3  *
4  * Copyright 1996, 1997 by Theodore Ts'o
5  *
6  * %Begin-Header%
7  * This file may be redistributed under the terms of the GNU Public
8  * License.
9  * %End-Header%
10  */
11
12 #include "config.h"
13 #ifdef HAVE_ERRNO_H
14 #include <errno.h>
15 #endif
16
17 #include "e2fsck.h"
18 #include <pwd.h>
19
20 struct string {
21         char    *s;
22         int     len;
23         int     end;
24 };
25
26 static void alloc_string(struct string *s, int len)
27 {
28         s->s = malloc(len);
29 /* e2fsck_allocate_memory(ctx, len, "logfile name"); */
30         s->len = len;
31         s->end = 0;
32 }
33
34 static void append_string(struct string *s, const char *a, int len)
35 {
36         if (!len)
37                 len = strlen(a);
38
39         if (s->end + len >= s->len) {
40                 char *n = realloc(s, s->len * 2);
41
42                 if (n) {
43                         s->s = n;
44                         s->len = s->len * 2;
45                 } else {
46                         len = s->len - s->end - 1;
47                         if (len <= 0)
48                                 return;
49                 }
50         }
51         memcpy(s->s + s->end, a, len);
52         s->end += len;
53         s->s[s->end] = 0;
54 }
55
56 #define FLAG_UTC        0x0001
57
58 static void expand_percent_expression(e2fsck_t ctx, char ch,
59                                       struct string *s, int *flags)
60 {
61         struct tm       *tm = NULL, tm_struct;
62         struct passwd   *pw = NULL, pw_struct;
63         char            *cp;
64         char            buf[256];
65
66         if ((ch == 'D') || (ch == 'd') || (ch == 'm') || (ch == 'y') ||
67             (ch == 'Y') ||
68             (ch == 'T') || (ch == 'H') || (ch == 'M') || (ch == 'S')) {
69                 tzset();
70                 tm = (*flags & FLAG_UTC) ? gmtime_r(&ctx->now, &tm_struct) :
71                         localtime_r(&ctx->now, &tm_struct);
72         }
73
74         switch (ch) {
75         case '%':
76                 append_string(s, "%", 1);
77                 return;
78         case 'd':
79                 sprintf(buf, "%02d", tm->tm_mday);
80                 break;
81         case 'D':
82                 sprintf(buf, "%d%02d%02d", tm->tm_year + 1900, tm->tm_mon + 1,
83                         tm->tm_mday);
84                 break;
85         case 'h':
86 #ifdef TEST_PROGRAM
87                 strcpy(buf, "server");
88 #else
89                 buf[0] = 0;
90                 gethostname(buf, sizeof(buf));
91                 buf[sizeof(buf)-1] = 0;
92 #endif
93                 break;
94         case 'H':
95                 sprintf(buf, "%02d", tm->tm_hour);
96                 break;
97         case 'm':
98                 sprintf(buf, "%02d", tm->tm_mon + 1);
99                 break;
100         case 'M':
101                 sprintf(buf, "%02d", tm->tm_min);
102                 break;
103         case 'N':               /* block device name */
104                 cp = strrchr(ctx->filesystem_name, '/');
105                 if (cp)
106                         cp++;
107                 else
108                         cp = ctx->filesystem_name;
109                 append_string(s, cp, 0);
110                 return;
111         case 'p':
112                 sprintf(buf, "%lu", (unsigned long) getpid());
113                 break;
114         case 's':
115                 sprintf(buf, "%lu", (unsigned long) ctx->now);
116                 break;
117         case 'S':
118                 sprintf(buf, "%02d", tm->tm_sec);
119                 break;
120         case 'T':
121                 sprintf(buf, "%02d%02d%02d", tm->tm_hour, tm->tm_min,
122                         tm->tm_sec);
123                 break;
124         case 'u':
125 #ifdef TEST_PROGRAM
126                 strcpy(buf, "tytso");
127                 break;
128 #else
129 #ifdef HAVE_GETPWUID_R
130                 getpwuid_r(getuid(), &pw_struct, buf, sizeof(buf), &pw);
131 #else
132                 pw = getpwuid(getuid());
133 #endif
134                 if (pw)
135                         append_string(s, pw->pw_name, 0);
136                 return;
137 #endif
138         case 'U':
139                 *flags |= FLAG_UTC;
140                 return;
141         case 'y':
142                 sprintf(buf, "%02d", tm->tm_year % 100);
143                 break;
144         case 'Y':
145                 sprintf(buf, "%d", tm->tm_year + 1900);
146                 break;
147         }
148         append_string(s, buf, 0);
149 }
150
151 static void expand_logfn(e2fsck_t ctx, const char *log_fn, struct string *s)
152 {
153         const char      *cp;
154         int             i;
155         int             flags = 0;
156
157         alloc_string(s, 100);
158         for (cp = log_fn; *cp; cp++) {
159                 if (cp[0] == '%') {
160                         cp++;
161                         expand_percent_expression(ctx, *cp, s, &flags);
162                         continue;
163                 }
164                 for (i = 0; cp[i]; i++)
165                         if (cp[i] == '%')
166                                 break;
167                 append_string(s, cp, i);
168                 cp += i-1;
169         }
170 }
171
172 static int      outbufsize;
173 static void     *outbuf;
174
175 static int do_read(int fd)
176 {
177         int     c;
178         char            *n;
179         char    buffer[4096];
180
181         c = read(fd, buffer, sizeof(buffer)-1);
182         if (c <= 0)
183                 return c;
184
185         n = realloc(outbuf, outbufsize + c);
186         if (n) {
187                 outbuf = n;
188                 memcpy(((char *)outbuf)+outbufsize, buffer, c);
189                 outbufsize += c;
190         }
191         return c;
192 }
193
194 /*
195  * Fork a child process to save the output of the logfile until the
196  * appropriate file system is mounted read/write.
197  */
198 static FILE *save_output(const char *s0, const char *s1, const char *s2)
199 {
200         int c, fd, fds[2];
201         char *cp;
202         pid_t pid;
203         FILE *ret;
204
205         if (s0 && *s0 == 0)
206                 s0 = 0;
207         if (s1 && *s1 == 0)
208                 s1 = 0;
209         if (s2 && *s2 == 0)
210                 s2 = 0;
211
212         /* At least one potential output file name is valid */
213         if (!s0 && !s1 && !s2)
214                 return NULL;
215         if (pipe(fds) < 0) {
216                 perror("pipe");
217                 exit(1);
218         }
219
220         pid = fork();
221         if (pid < 0) {
222                 perror("fork");
223                 exit(1);
224         }
225
226         if (pid == 0) {
227                 if (daemon(0, 0) < 0) {
228                         perror("daemon");
229                         exit(1);
230                 }
231                 /*
232                  * Grab the output from our parent
233                  */
234                 close(fds[1]);
235                 while (do_read(fds[0]) > 0)
236                         ;
237                 close(fds[0]);
238
239                 /* OK, now let's try to open the output file */
240                 fd = -1;
241                 while (1) {
242                         if (fd < 0 && s0)
243                                 fd = open(s0, O_WRONLY|O_CREAT|O_TRUNC, 0644);
244                         if (fd < 0 && s1)
245                                 fd = open(s1, O_WRONLY|O_CREAT|O_TRUNC, 0644);
246                         if (fd < 0 && s2)
247                                 fd = open(s2, O_WRONLY|O_CREAT|O_TRUNC, 0644);
248                         if (fd >= 0)
249                                 break;
250                         sleep(1);
251                 }
252
253                 cp = outbuf;
254                 while (outbufsize > 0) {
255                         c = write(fd, cp, outbufsize);
256                         if (c < 0) {
257                                 if ((errno == EAGAIN) || (errno == EINTR))
258                                         continue;
259                                 break;
260                         }
261                         outbufsize -= c;
262                         cp += c;
263                 }
264                 exit(0);
265         }
266
267         close(fds[0]);
268         ret = fdopen(fds[1], "w");
269         if (!ret)
270                 close(fds[1]);
271         return ret;
272 }
273
274 #ifndef TEST_PROGRAM
275 void set_up_logging(e2fsck_t ctx)
276 {
277         struct string s, s1, s2;
278         char *s0 = 0, *log_dir = 0, *log_fn = 0;
279         int log_dir_wait = 0;
280
281         s.s = s1.s = s2.s = 0;
282
283         profile_get_boolean(ctx->profile, "options", "log_dir_wait", 0, 0,
284                             &log_dir_wait);
285         if (ctx->log_fn)
286                 log_fn = string_copy(ctx, ctx->log_fn, 0);
287         else
288                 profile_get_string(ctx->profile, "options", "log_filename",
289                                    0, 0, &log_fn);
290         profile_get_string(ctx->profile, "options", "log_dir", 0, 0, &log_dir);
291
292         if (!log_fn || !log_fn[0])
293                 goto out;
294
295         expand_logfn(ctx, log_fn, &s);
296         if ((log_fn[0] == '/') || !log_dir || !log_dir[0])
297                 s0 = s.s;
298
299         if (log_dir && log_dir[0]) {
300                 alloc_string(&s1, strlen(log_dir) + strlen(s.s) + 2);
301                 append_string(&s1, log_dir, 0);
302                 append_string(&s1, "/", 1);
303                 append_string(&s1, s.s, 0);
304         }
305
306         free(log_dir);
307         profile_get_string(ctx->profile, "options", "log_dir_fallback", 0, 0,
308                            &log_dir);
309         if (log_dir && log_dir[0]) {
310                 alloc_string(&s2, strlen(log_dir) + strlen(s.s) + 2);
311                 append_string(&s2, log_dir, 0);
312                 append_string(&s2, "/", 1);
313                 append_string(&s2, s.s, 0);
314                 printf("%s\n", s2.s);
315         }
316
317         if (s0)
318                 ctx->logf = fopen(s0, "w");
319         if (!ctx->logf && s1.s)
320                 ctx->logf = fopen(s1.s, "w");
321         if (!ctx->logf && s2.s)
322                 ctx->logf = fopen(s2.s, "w");
323         if (!ctx->logf && log_dir_wait)
324                 ctx->logf = save_output(s0, s1.s, s2.s);
325
326 out:
327         free(s.s);
328         free(s1.s);
329         free(s2.s);
330         free(log_fn);
331         free(log_dir);
332         return;
333 }
334 #else
335 void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
336                              const char *description)
337 {
338         void *ret;
339         char buf[256];
340
341         ret = malloc(size);
342         if (!ret) {
343                 sprintf(buf, "Can't allocate %s\n", description);
344                 exit(1);
345         }
346         memset(ret, 0, size);
347         return ret;
348 }
349
350 errcode_t e2fsck_allocate_context(e2fsck_t *ret)
351 {
352         e2fsck_t        context;
353         errcode_t       retval;
354         char            *time_env;
355
356         context = malloc(sizeof(struct e2fsck_struct));
357         if (!context)
358                 return ENOMEM;
359
360         memset(context, 0, sizeof(struct e2fsck_struct));
361
362         context->now = 1332006474;
363
364         context->filesystem_name = "/dev/sda3";
365         context->device_name = "fslabel";
366
367         *ret = context;
368         return 0;
369 }
370
371 int main(int argc, char **argv)
372 {
373         e2fsck_t        ctx;
374         struct string   s;
375
376         putenv("TZ=EST+5:00");
377         e2fsck_allocate_context(&ctx);
378         expand_logfn(ctx, "e2fsck-%N.%h.%u.%D-%T", &s);
379         printf("%s\n", s.s);
380         free(s.s);
381         expand_logfn(ctx, "e2fsck-%N.%h.%u.%Y%m%d-%H%M%S", &s);
382         printf("%s\n", s.s);
383         free(s.s);
384
385         return 0;
386 }
387 #endif