1 /* Multi-purpose tool for tar and cpio testsuite.
2
3 Copyright (C) 1995-1997, 2001-2018, 2023 Free Software Foundation, Inc.
4
5 François Pinard <pinard@iro.umontreal.ca>, 1995.
6 Sergey Poznyakoff <gray@gnu.org>, 2004-2018.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
11 any later version.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include <system.h>
23 #include <signal.h>
24 #include <stdarg.h>
25 #include <argmatch.h>
26 #include <argp.h>
27 #include <argcv.h>
28 #include <parse-datetime.h>
29 #include <fcntl.h>
30 #include <sys/stat.h>
31 #include <c-ctype.h>
32 #define obstack_chunk_alloc malloc
33 #define obstack_chunk_free free
34 #include <obstack.h>
35
36 #ifndef EXIT_SUCCESS
37 # define EXIT_SUCCESS 0
38 #endif
39 #ifndef EXIT_FAILURE
40 # define EXIT_FAILURE 1
41 #endif
42 #define EXIT_USAGE 2
43 #define EXIT_UNAVAILABLE 3
44
45 #if ! defined SIGCHLD && defined SIGCLD
46 # define SIGCHLD SIGCLD
47 #endif
48
49 enum pattern
50 {
51 DEFAULT_PATTERN,
52 ZEROS_PATTERN
53 };
54
55 /* The name this program was run with. */
56 const char *program_name;
57
58 /* Name of file to generate */
59 static char *file_name;
60
61 /* Name of the file-list file: */
62 static char *files_from;
63 static char filename_terminator = '\n';
64
65 /* Length of file to generate. */
66 static off_t file_length = 0;
67 static off_t seek_offset = 0;
68
69 /* Pattern to generate. */
70 static enum pattern pattern = DEFAULT_PATTERN;
71
72 /* Next checkpoint number */
73 uintmax_t checkpoint;
74
75 enum genfile_mode
76 {
77 mode_generate,
78 mode_sparse,
79 mode_stat,
80 mode_exec,
81 mode_set_times
82 };
83
84 enum genfile_mode mode = mode_generate;
85
86 #define DEFAULT_STAT_FORMAT \
87 "name,dev,ino,mode,nlink,uid,gid,size,blksize,blocks,atime,mtime,ctime"
88
89 /* Format for --stat option */
90 static char *stat_format = DEFAULT_STAT_FORMAT;
91
92 /* Size of a block for sparse file */
93 size_t block_size = 512;
94
95 /* Block buffer for sparse file */
96 char *buffer;
97
98 /* Checkpoint granularity for mode == mode_exec */
99 char *checkpoint_granularity;
100
101 /* Time for --touch option */
102 struct timespec touch_time;
103
104 /* Verbose mode */
105 int verbose;
106
107 /* Quiet mode */
108 int quiet;
109
110 /* Don't dereference symlinks (for --stat) */
111 int no_dereference_option;
112
113 const char *argp_program_version = "genfile (" PACKAGE ") " VERSION;
114 const char *argp_program_bug_address = "<" PACKAGE_BUGREPORT ">";
115 static char doc[] = N_("genfile manipulates data files for GNU paxutils test suite.\n"
116 "OPTIONS are:\n");
117
118 #define OPT_CHECKPOINT 256
119 #define OPT_TOUCH 257
120 #define OPT_APPEND 258
121 #define OPT_TRUNCATE 259
122 #define OPT_EXEC 260
123 #define OPT_DATE 261
124 #define OPT_VERBOSE 262
125 #define OPT_SEEK 263
126 #define OPT_DELETE 264
127
128 static struct argp_option options[] = {
129 #define GRP 0
130 {NULL, 0, NULL, 0,
131 N_("File creation options:"), GRP},
132 {"length", 'l', N_("SIZE"), 0,
133 N_("Create file of the given SIZE"), GRP+1 },
134 {"file", 'f', N_("NAME"), 0,
135 N_("Write to file NAME, instead of standard output"), GRP+1},
136 {"files-from", 'T', N_("FILE"), 0,
137 N_("Read file names from FILE"), GRP+1},
138 {"null", '0', NULL, 0,
139 N_("-T reads null-terminated names"), GRP+1},
140 {"pattern", 'p', N_("PATTERN"), 0,
141 N_("Fill the file with the given PATTERN. PATTERN is 'default' or 'zeros'"),
142 GRP+1 },
143 {"block-size", 'b', N_("SIZE"), 0,
144 N_("Size of a block for sparse file"), GRP+1},
145 {"sparse", 's', NULL, 0,
146 N_("Generate sparse file. Rest of the command line gives the file map."),
147 GRP+1 },
148 {"seek", OPT_SEEK, N_("OFFSET"), 0,
149 N_("Seek to the given offset before writing data"),
150 GRP+1 },
151 {"quiet", 'q', NULL, 0,
152 N_("Suppress non-fatal diagnostic messages") },
153 #undef GRP
154 #define GRP 10
155 {NULL, 0, NULL, 0,
156 N_("File statistics options:"), GRP},
157
158 {"stat", 'S', N_("FORMAT"), OPTION_ARG_OPTIONAL,
159 N_("Print contents of struct stat for each given file. Default FORMAT is: ")
160 DEFAULT_STAT_FORMAT,
161 GRP+1 },
162 {"no-dereference", 'h', NULL, 0,
163 N_("stat symbolic links instead of referenced files"),
164 GRP+1 },
165
166 {"set-times", 't', NULL, 0,
167 N_("Set access and modification times of the files to the time supplied"
168 " by --date option"),
169 GRP+1 },
170
171 #undef GRP
172 #define GRP 20
173 {NULL, 0, NULL, 0,
174 N_("Synchronous execution options:"), GRP},
175
176 {"run", 'r', N_("N"), OPTION_ARG_OPTIONAL,
177 N_("Execute ARGS. Trigger checkpoints every Nth record (default 1). Useful with --checkpoint and one of --cut, --append, --touch, --unlink"),
178 GRP+1 },
179 {"checkpoint", OPT_CHECKPOINT, N_("NUMBER"), 0,
180 N_("Perform given action (see below) upon reaching checkpoint NUMBER"),
181 GRP+1 },
182 {"date", OPT_DATE, N_("STRING"), 0,
183 N_("Set date for next --touch option"),
184 GRP+1 },
185 {"verbose", OPT_VERBOSE, NULL, 0,
186 N_("Display executed checkpoints and exit status of COMMAND"),
187 GRP+1 },
188 #undef GRP
189 #define GRP 30
190 {NULL, 0, NULL, 0,
191 N_("Synchronous execution actions. These are executed when checkpoint number given by --checkpoint option is reached."), GRP},
192
193 {"cut", OPT_TRUNCATE, N_("FILE"), 0,
194 N_("Truncate FILE to the size specified by previous --length option (or 0, if it is not given)"),
195 GRP+1 },
196 {"truncate", 0, NULL, OPTION_ALIAS, NULL, GRP+1 },
197 {"append", OPT_APPEND, N_("FILE"), 0,
198 N_("Append SIZE bytes to FILE. SIZE is given by previous --length option."),
199 GRP+1 },
200 {"touch", OPT_TOUCH, N_("FILE"), 0,
201 N_("Update the access and modification times of FILE"),
202 GRP+1 },
203 {"exec", OPT_EXEC, N_("COMMAND"), 0,
204 N_("Execute COMMAND"),
205 GRP+1 },
206 {"delete", OPT_DELETE, N_("FILE"), 0,
207 N_("Delete FILE"),
208 GRP+1 },
209 {"unlink", 0, 0, OPTION_ALIAS, NULL, GRP+1},
210 #undef GRP
211 { NULL, }
212 };
213
214 static char const * const pattern_args[] = { "default", "zeros", 0 };
215 static enum pattern const pattern_types[] = {DEFAULT_PATTERN, ZEROS_PATTERN};
216
217 static int
218 xlat_suffix (off_t *vp, const char *p)
219 {
220 off_t val = *vp;
221
222 if (p[1])
223 return 1;
224 switch (p[0])
225 {
226 case 'g':
227 case 'G':
228 *vp *= 1024;
229
230 case 'm':
231 case 'M':
232 *vp *= 1024;
233
234 case 'k':
235 case 'K':
236 *vp *= 1024;
237 break;
238
239 default:
240 return 1;
241 }
242 return *vp <= val;
243 }
244
245 static off_t
246 get_size (const char *str, int allow_zero)
247 {
248 const char *p;
249 off_t v = 0;
250
251 for (p = str; *p; p++)
252 {
253 int digit = *p - '0';
254 off_t x = v * 10;
255 if (9 < (unsigned) digit)
256 {
257 if (xlat_suffix (&v, p))
258 error (EXIT_USAGE, 0, _("Invalid size: %s"), str);
259 else
260 break;
261 }
262 else if (x / 10 != v)
263 error (EXIT_USAGE, 0, _("Number out of allowed range: %s"), str);
264 v = x + digit;
265 if (v < 0)
266 error (EXIT_USAGE, 0, _("Negative size: %s"), str);
267 }
268 return v;
269 }
270
271 void
272 verify_file (char *file_name)
273 {
274 if (file_name)
275 {
276 struct stat st;
277
278 if (stat (file_name, &st))
279 error (0, errno, _("stat(%s) failed"), file_name);
280
281 if (st.st_size != file_length + seek_offset)
282 {
283 intmax_t requested = st.st_size, actual = file_length;
284 error (EXIT_FAILURE, 0, _("requested file length %jd, actual %jd"),
285 requested, actual);
286 }
287
288 if (!quiet && mode == mode_sparse && !ST_IS_SPARSE (st))
289 error (EXIT_UNAVAILABLE, 0, _("created file is not sparse"));
290 }
291 }
292
293 struct action
294 {
295 struct action *next;
296 uintmax_t checkpoint;
297 int action;
298 char *name;
299 off_t size;
300 enum pattern pattern;
301 struct timespec ts;
302 };
303
304 static struct action *action_head, *action_tail;
305
306 void
307 reg_action (int action, char *arg)
308 {
309 struct action *act = xmalloc (sizeof (*act));
310 act->checkpoint = checkpoint;
311 act->action = action;
312 act->pattern = pattern;
313 act->ts = touch_time;
314 act->size = file_length;
315 act->name = arg;
316 act->next = NULL;
317 if (action_tail)
318 action_tail->next = act;
319 else
320 action_head = act;
321 action_tail = act;
322 }
323
324 static error_t
325 parse_opt (int key, char *arg, struct argp_state *state)
326 {
327 switch (key)
328 {
329 case '0':
330 filename_terminator = 0;
331 break;
332
333 case 'f':
334 file_name = arg;
335 break;
336
337 case 'l':
338 file_length = get_size (arg, 1);
339 break;
340
341 case 'p':
342 pattern = XARGMATCH ("--pattern", arg, pattern_args, pattern_types);
343 break;
344
345 case 'b':
346 block_size = get_size (arg, 0);
347 break;
348
349 case 'q':
350 quiet = 1;
351 break;
352
353 case 's':
354 mode = mode_sparse;
355 break;
356
357 case 'S':
358 mode = mode_stat;
359 if (arg)
360 stat_format = arg;
361 break;
362
363 case 't':
364 mode = mode_set_times;
365 break;
366
367 case 'h':
368 no_dereference_option = 1;
369 break;
370
371 case 'r':
372 mode = mode_exec;
373 checkpoint_granularity = arg ? arg : "1";
374 break;
375
376 case 'T':
377 files_from = arg;
378 break;
379
380 case OPT_SEEK:
381 seek_offset = get_size (arg, 0);
382 break;
383
384 case OPT_CHECKPOINT:
385 {
386 char *p;
387
388 checkpoint = strtoumax (arg, &p, 0);
389 if (*p)
390 argp_error (state, _("Error parsing number near `%s'"), p);
391 }
392 break;
393
394 case OPT_DATE:
395 if (! parse_datetime (&touch_time, arg, NULL))
396 argp_error (state, _("Unknown date format"));
397 break;
398
399 case OPT_APPEND:
400 case OPT_TRUNCATE:
401 case OPT_TOUCH:
402 case OPT_EXEC:
403 case OPT_DELETE:
404 reg_action (key, arg);
405 break;
406
407 case OPT_VERBOSE:
408 verbose++;
409 break;
410
411 default:
412 return ARGP_ERR_UNKNOWN;
413 }
414 return 0;
415 }
416
417 static struct argp argp = {
418 options,
419 parse_opt,
420 N_("[ARGS...]"),
421 doc,
422 NULL,
423 NULL,
424 NULL
425 };
426
427
428 void
429 fill (FILE *fp, off_t length, enum pattern pattern)
430 {
431 off_t i;
432
433 switch (pattern)
434 {
435 case DEFAULT_PATTERN:
436 for (i = 0; i < length; i++)
437 fputc (i & 255, fp);
438 break;
439
440 case ZEROS_PATTERN:
441 for (i = 0; i < length; i++)
442 fputc (0, fp);
443 break;
444 }
445 }
446
447 /* Generate Mode: usual files */
448 static void
449 generate_simple_file (char *filename)
450 {
451 FILE *fp;
452
453 if (filename)
454 {
455 fp = fopen (filename, seek_offset ? "rb+" : "wb");
456 if (!fp)
457 error (EXIT_FAILURE, errno, _("cannot open `%s'"), filename);
458 }
459 else
460 fp = stdout;
461
462 if (fseeko (fp, seek_offset, 0))
463 error (EXIT_FAILURE, errno, "%s", _("cannot seek"));
464
465 fill (fp, file_length, pattern);
466
467 fclose (fp);
468 }
469
470 /* A simplified version of the same function from tar */
471 int
472 read_name_from_file (FILE *fp, struct obstack *stk)
473 {
474 int c;
475 size_t counter = 0;
476
477 for (c = getc (fp); c != EOF && c != filename_terminator; c = getc (fp))
478 {
479 if (c == 0)
480 error (EXIT_FAILURE, 0, _("file name contains null character"));
481 obstack_1grow (stk, c);
482 counter++;
483 }
484
485 obstack_1grow (stk, 0);
486
487 return (counter == 0 && c == EOF);
488 }
489
490 void
491 generate_files_from_list ()
492 {
493 FILE *fp = strcmp (files_from, "-") ? fopen (files_from, "rb") : stdin;
494 struct obstack stk;
495
496 if (!fp)
497 error (EXIT_FAILURE, errno, _("cannot open `%s'"), files_from);
498
499 obstack_init (&stk);
500 while (!read_name_from_file (fp, &stk))
501 {
502 char *name = obstack_finish (&stk);
503 generate_simple_file (name);
504 verify_file (name);
505 obstack_free (&stk, name);
506 }
507 fclose (fp);
508 obstack_free (&stk, NULL);
509 }
510
511
512 /* Generate Mode: sparse files */
513
514 static void
515 mkhole (int fd, off_t displ)
516 {
517 off_t offset = lseek (fd, displ, SEEK_CUR);
518 if (offset < 0)
519 error (EXIT_FAILURE, errno, "lseek");
520 if (ftruncate (fd, offset) != 0)
521 error (EXIT_FAILURE, errno, "ftruncate");
522 }
523
524 static void
525 mksparse (int fd, off_t displ, char *marks)
526 {
527 if (lseek (fd, displ, SEEK_CUR) == -1)
528 error (EXIT_FAILURE, errno, "lseek");
529
530 for (; *marks; marks++)
531 {
532 memset (buffer, *marks, block_size);
533 if (write (fd, buffer, block_size) != block_size)
534 error (EXIT_FAILURE, errno, "write");
535 }
536 }
537
538 static int
539 make_fragment (int fd, char *offstr, char *mapstr)
540 {
541 int i;
542 off_t displ = get_size (offstr, 1);
543
544 file_length += displ;
545
546 if (!mapstr || !*mapstr)
547 {
548 mkhole (fd, displ);
549 return 1;
550 }
551 else if (*mapstr == '=')
552 {
553 off_t n = get_size (mapstr + 1, 1);
554
555 switch (pattern)
556 {
557 case DEFAULT_PATTERN:
558 for (i = 0; i < block_size; i++)
559 buffer[i] = i & 255;
560 break;
561
562 case ZEROS_PATTERN:
563 memset (buffer, 0, block_size);
564 break;
565 }
566
567 if (lseek (fd, displ, SEEK_CUR) == -1)
568 error (EXIT_FAILURE, errno, "lseek");
569
570 for (; n; n--)
571 {
572 if (write (fd, buffer, block_size) != block_size)
573 error (EXIT_FAILURE, errno, "write");
574 file_length += block_size;
575 }
576 }
577 else
578 {
579 file_length += block_size * strlen (mapstr);
580 mksparse (fd, displ, mapstr);
581 }
582 return 0;
583 }
584
585 static void
586 generate_sparse_file (int argc, char **argv)
587 {
588 int fd;
589 int flags = O_CREAT | O_RDWR | O_BINARY;
590
591 if (!file_name)
592 error (EXIT_USAGE, 0,
593 _("cannot generate sparse files on standard output, use --file option"));
594 if (!seek_offset)
595 flags |= O_TRUNC;
596 fd = open (file_name, flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
597 if (fd < 0)
598 error (EXIT_FAILURE, errno, _("cannot open `%s'"), file_name);
599
600 buffer = xmalloc (block_size);
601
602 file_length = 0;
603
604 while (argc)
605 {
606 if (argv[0][0] == '-' && argv[0][1] == 0)
607 {
608 char buf[256];
609 while (fgets (buf, sizeof (buf), stdin))
610 {
611 size_t n = strlen (buf);
612
613 while (n > 0 && c_isspace (buf[n-1]))
614 buf[--n] = 0;
615
616 n = strcspn (buf, " \t");
617 buf[n++] = 0;
618 while (buf[n] && c_isblank (buf[n]))
619 ++n;
620 make_fragment (fd, buf, buf + n);
621 }
622 ++argv;
623 --argc;
624 }
625 else
626 {
627 if (make_fragment (fd, argv[0], argv[1]))
628 break;
629 argc -= 2;
630 argv += 2;
631 }
632 }
633
634 close (fd);
635 }
636
637
638 /* Status Mode */
639
640 #define PRINT_INT(expr) \
641 do \
642 { \
643 if (EXPR_SIGNED (expr)) \
644 { \
645 intmax_t printval = expr; \
646 printf ("%jd", printval); \
647 } \
648 else \
649 { \
650 uintmax_t printval = expr; \
651 printf ("%ju", printval); \
652 } \
653 } \
654 while (false)
655
656 void
657 print_time (time_t t)
658 {
659 char buf[20]; /* ccyy-mm-dd HH:MM:SS\0 */
660 strftime (buf, sizeof buf, "%Y-%m-%d %H:%M:%S", gmtime (&t));
661 printf ("%s ", buf);
662 }
663
664 void
665 print_stat (const char *name)
666 {
667 char *fmt, *p;
668 struct stat st;
669
670 if ((no_dereference_option ? lstat : stat) (name, &st))
671 {
672 error (0, errno, _("stat(%s) failed"), name);
673 return;
674 }
675
676 fmt = strdup (stat_format);
677 for (p = strtok (fmt, ","); p; )
678 {
679 if (memcmp (p, "st_", 3) == 0)
680 p += 3;
681 if (strcmp (p, "name") == 0)
682 printf ("%s", name);
683 else if (strcmp (p, "dev") == 0)
684 PRINT_INT (st.st_dev);
685 else if (strcmp (p, "ino") == 0)
686 PRINT_INT (st.st_ino);
687 else if (strncmp (p, "mode", 4) == 0)
688 {
689 uintmax_t val = st.st_mode;
690
691 if (ispunct ((unsigned char) p[4]))
692 {
693 char *q;
694
695 val &= strtoumax (p + 5, &q, 8);
696 if (*q)
697 {
698 printf ("\n");
699 error (EXIT_USAGE, 0, _("incorrect mask (near `%s')"), q);
700 }
701 }
702 else if (p[4])
703 {
704 printf ("\n");
705 error (EXIT_USAGE, 0, _("Unknown field `%s'"), p);
706 }
707 printf ("%0jo", val);
708 }
709 else if (strcmp (p, "nlink") == 0)
710 PRINT_INT (st.st_nlink);
711 else if (strcmp (p, "uid") == 0)
712 PRINT_INT (st.st_uid);
713 else if (strcmp (p, "gid") == 0)
714 PRINT_INT (st.st_gid);
715 else if (strcmp (p, "size") == 0)
716 PRINT_INT (st.st_size);
717 else if (strcmp (p, "blksize") == 0)
718 PRINT_INT (st.st_blksize);
719 else if (strcmp (p, "blocks") == 0)
720 PRINT_INT (st.st_blocks);
721 else if (strcmp (p, "atime") == 0)
722 PRINT_INT (st.st_atime);
723 else if (strcmp (p, "atimeH") == 0)
724 print_time (st.st_atime);
725 else if (strcmp (p, "mtime") == 0)
726 PRINT_INT (st.st_mtime);
727 else if (strcmp (p, "mtimeH") == 0)
728 print_time (st.st_mtime);
729 else if (strcmp (p, "ctime") == 0)
730 PRINT_INT (st.st_ctime);
731 else if (strcmp (p, "ctimeH") == 0)
732 print_time (st.st_ctime);
733 else if (strcmp (p, "sparse") == 0)
734 printf ("%d", ST_IS_SPARSE (st));
735 else
736 {
737 printf ("\n");
738 error (EXIT_USAGE, 0, _("Unknown field `%s'"), p);
739 }
740 p = strtok (NULL, ",");
741 if (p)
742 printf (" ");
743 }
744 printf ("\n");
745 free (fmt);
746 }
747
748 void
749 set_times (char const *name)
750 {
751 struct timespec ts[2];
752
753 ts[0] = ts[1] = touch_time;
754 if (utimensat (AT_FDCWD, name, ts, no_dereference_option ? AT_SYMLINK_NOFOLLOW : 0) != 0)
755 {
756 error (EXIT_FAILURE, errno, _("cannot set time on `%s'"), name);
757 }
758 }
759
760 /* Exec Mode */
761
762 void
763 exec_checkpoint (struct action *p)
764 {
765 if (verbose)
766 printf ("processing checkpoint %ju\n", p->checkpoint);
767 switch (p->action)
768 {
769 case OPT_TOUCH:
770 {
771 struct timespec ts[2];
772
773 ts[0] = ts[1] = p->ts;
774 if (utimensat (AT_FDCWD, p->name, ts, no_dereference_option ? AT_SYMLINK_NOFOLLOW : 0) != 0)
775 {
776 error (0, errno, _("cannot set time on `%s'"), p->name);
777 break;
778 }
779 }
780 break;
781
782 case OPT_APPEND:
783 {
784 FILE *fp = fopen (p->name, "ab");
785 if (!fp)
786 {
787 error (0, errno, _("cannot open `%s'"), p->name);
788 break;
789 }
790
791 fill (fp, p->size, p->pattern);
792 fclose (fp);
793 }
794 break;
795
796 case OPT_TRUNCATE:
797 {
798 int fd = open (p->name, O_RDWR | O_BINARY);
799 if (fd == -1)
800 {
801 error (0, errno, _("cannot open `%s'"), p->name);
802 break;
803 }
804 if (ftruncate (fd, p->size) != 0)
805 {
806 error (0, errno, _("cannot truncate `%s'"), p->name);
807 break;
808 }
809 close (fd);
810 }
811 break;
812
813 case OPT_EXEC:
814 if (system (p->name) != 0)
815 error (0, 0, _("command failed: %s"), p->name);
816 break;
817
818 case OPT_DELETE:
819 {
820 struct stat st;
821 if (stat (p->name, &st))
822 error (0, errno, _("cannot stat `%s'"), p->name);
823 else if (S_ISDIR (st.st_mode))
824 {
825 if (rmdir (p->name))
826 error (0, errno, _("cannot remove directory `%s'"), p->name);
827 }
828 else if (unlink (p->name))
829 error (0, errno, _("cannot unlink `%s'"), p->name);
830 }
831 break;
832
833 default:
834 abort ();
835 }
836 }
837
838 void
839 process_checkpoint (uintmax_t n)
840 {
841 struct action *p, *prev = NULL;
842
843 for (p = action_head; p; )
844 {
845 struct action *next = p->next;
846
847 if (p->checkpoint <= n)
848 {
849 exec_checkpoint (p);
850 /* Remove the item from the list */
851 if (prev)
852 prev->next = next;
853 else
854 action_head = next;
855 if (next == NULL)
856 action_tail = prev;
857 free (p);
858 }
859 else
860 prev = p;
861
862 p = next;
863 }
864 }
865
866 #define CHECKPOINT_TEXT "genfile checkpoint"
867
868 void
869 exec_command (int argc, char **argv)
870 {
871 int status;
872 pid_t pid;
873 int fd[2];
874 char *p;
875 FILE *fp;
876 char buf[128];
877 int xargc;
878 char **xargv;
879 int i;
880 char checkpoint_option[80];
881
882 /* Insert --checkpoint option.
883 FIXME: This assumes that argv does not use traditional tar options
884 (without dash).
885 */
886 xargc = argc + 5;
887 xargv = xcalloc (xargc + 1, sizeof (xargv[0]));
888 xargv[0] = argv[0];
889 snprintf (checkpoint_option, sizeof (checkpoint_option),
890 "--checkpoint=%s", checkpoint_granularity);
891 xargv[1] = checkpoint_option;
892 xargv[2] = "--checkpoint-action";
893 xargv[3] = "echo=" CHECKPOINT_TEXT " %u";
894 xargv[4] = "--checkpoint-action";
895 xargv[5] = "wait=SIGUSR1";
896
897 for (i = 1; i <= argc; i++)
898 xargv[i + 5] = argv[i];
899
900 #ifdef SIGCHLD
901 /* System V fork+wait does not work if SIGCHLD is ignored. */
902 signal (SIGCHLD, SIG_DFL);
903 #endif
904
905 if (pipe (fd) != 0)
906 error (EXIT_FAILURE, errno, "pipe");
907
908 pid = fork ();
909 if (pid == -1)
910 error (EXIT_FAILURE, errno, "fork");
911
912 if (pid == 0)
913 {
914 /* Child */
915
916 /* Pipe stderr */
917 if (fd[1] != 2)
918 dup2 (fd[1], 2);
919 close (fd[0]);
920
921 /* Make sure POSIX locale is used */
922 setenv ("LC_ALL", "POSIX", 1);
923
924 execvp (xargv[0], xargv);
925 error (EXIT_FAILURE, errno, "execvp %s", xargv[0]);
926 }
927
928 /* Master */
929 close (fd[1]);
930 fp = fdopen (fd[0], "rb");
931 if (fp == NULL)
932 error (EXIT_FAILURE, errno, "fdopen");
933
934 while ((p = fgets (buf, sizeof buf, fp)))
935 {
936 while (*p && !isspace ((unsigned char) *p) && *p != ':')
937 p++;
938
939 if (*p == ':')
940 {
941 for (p++; *p && isspace ((unsigned char) *p); p++)
942 ;
943
944 if (*p
945 && memcmp (p, CHECKPOINT_TEXT, sizeof CHECKPOINT_TEXT - 1) == 0)
946 {
947 char *end;
948 uintmax_t n = strtoumax (p + sizeof CHECKPOINT_TEXT - 1,
949 &end, 10);
950 if (!(*end && !isspace ((unsigned char) *end)))
951 {
952 process_checkpoint (n);
953 kill (pid, SIGUSR1);
954 continue;
955 }
956 }
957 }
958 fprintf (stderr, "%s", buf);
959 }
960
961 /* Collect exit status */
962 waitpid (pid, &status, 0);
963
964 if (verbose)
965 {
966 if (WIFEXITED (status))
967 {
968 if (WEXITSTATUS (status) == 0)
969 printf (_("Command exited successfully\n"));
970 else
971 printf (_("Command failed with status %d\n"),
972 WEXITSTATUS (status));
973 }
974 else if (WIFSIGNALED (status))
975 printf (_("Command terminated on signal %d\n"), WTERMSIG (status));
976 else if (WIFSTOPPED (status))
977 printf (_("Command stopped on signal %d\n"), WSTOPSIG (status));
978 #ifdef WCOREDUMP
979 else if (WCOREDUMP (status))
980 printf (_("Command dumped core\n"));
981 #endif
982 else
983 printf(_("Command terminated\n"));
984 }
985
986 if (WIFEXITED (status))
987 exit (WEXITSTATUS (status));
988 exit (EXIT_FAILURE);
989 }
990
991 int
992 main (int argc, char **argv)
993 {
994 int index;
995
996 program_name = argv[0];
997 setlocale (LC_ALL, "");
998 bindtextdomain (PACKAGE, LOCALEDIR);
999 textdomain (PACKAGE);
1000
1001 parse_datetime (&touch_time, "now", NULL);
1002
1003 /* Decode command options. */
1004
1005 if (argp_parse (&argp, argc, argv, 0, &index, NULL))
1006 exit (EXIT_USAGE);
1007
1008 argc -= index;
1009 argv += index;
1010
1011 switch (mode)
1012 {
1013 case mode_stat:
1014 if (argc == 0)
1015 error (EXIT_USAGE, 0, _("--stat requires file names"));
1016
1017 while (argc--)
1018 print_stat (*argv++);
1019 break;
1020
1021 case mode_set_times:
1022 if (argc == 0)
1023 error (EXIT_USAGE, 0, _("--set-times requires file names"));
1024
1025 while (argc--)
1026 set_times (*argv++);
1027 break;
1028
1029 case mode_sparse:
1030 generate_sparse_file (argc, argv);
1031 verify_file (file_name);
1032 break;
1033
1034 case mode_generate:
1035 if (argc)
1036 error (EXIT_USAGE, 0, _("too many arguments"));
1037 if (files_from)
1038 generate_files_from_list ();
1039 else
1040 {
1041 generate_simple_file (file_name);
1042 verify_file (file_name);
1043 }
1044 break;
1045
1046 case mode_exec:
1047 exec_command (argc, argv);
1048 break;
1049
1050 default:
1051 /* Just in case */
1052 abort ();
1053 }
1054 exit (EXIT_SUCCESS);
1055 }