OSDN Git Service

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