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