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