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