source: trunk/essentials/app-arch/tar/tests/genfile.c

Last change on this file was 3348, checked in by bird, 18 years ago

create binary files.

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