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