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 391void 392fill (FILE *fp, off_t length, enum pattern pattern) 393{ 394 off_t i; 395 396 switch (pattern) 397 { 398 case DEFAULT_PATTERN: 399 for (i = 0; i < length; i++) 400 fputc (i & 255, fp); 401 break; 402 403 case ZEROS_PATTERN: 404 for (i = 0; i < length; i++) 405 fputc (0, fp); 406 break; 407 } 408} 409 410/* Generate Mode: usual files */ 411static void 412generate_simple_file (char *filename) 413{ 414 FILE *fp; 415 416 if (filename) 417 { 418 fp = fopen (filename, seek_offset ? "r+" : "w"); 419 if (!fp) 420 error (EXIT_FAILURE, 0, _("cannot open `%s'"), filename); 421 } 422 else 423 fp = stdout; 424 425 if (fseeko (fp, seek_offset, 0)) 426 error (EXIT_FAILURE, 0, _("cannot seek: %s"), strerror (errno)); 427 428 fill (fp, file_length, pattern); 429 430 fclose (fp); 431} 432 433/* A simplified version of the same function from tar */ 434int 435read_name_from_file (FILE *fp, struct obstack *stk) 436{ 437 int c; 438 size_t counter = 0; 439 440 for (c = getc (fp); c != EOF && c != filename_terminator; c = getc (fp)) 441 { 442 if (c == 0) 443 error (EXIT_FAILURE, 0, _("file name contains null character")); 444 obstack_1grow (stk, c); 445 counter++; 446 } 447 448 obstack_1grow (stk, 0); 449 450 return (counter == 0 && c == EOF); 451} 452 453void 454generate_files_from_list () 455{ 456 FILE *fp = strcmp (files_from, "-") ? fopen (files_from, "r") : stdin; 457 struct obstack stk; 458 459 if (!fp) 460 error (EXIT_FAILURE, errno, _("cannot open `%s'"), files_from); 461 462 obstack_init (&stk); 463 while (!read_name_from_file (fp, &stk)) 464 { 465 char *name = obstack_finish (&stk); 466 generate_simple_file (name); 467 verify_file (name); 468 obstack_free (&stk, name); 469 } 470 fclose (fp); 471 obstack_free (&stk, NULL); 472} 473 474 475/* Generate Mode: sparse files */ 476 477static void 478mkhole (int fd, off_t displ) 479{ 480 if (lseek (fd, displ, SEEK_CUR) == -1) 481 error (EXIT_FAILURE, errno, "lseek"); 482 ftruncate (fd, lseek (fd, 0, SEEK_CUR)); 483} 484 485static void 486mksparse (int fd, off_t displ, char *marks) 487{ 488 if (lseek (fd, displ, SEEK_CUR) == -1) 489 error (EXIT_FAILURE, errno, "lseek"); 490 491 for (; *marks; marks++) 492 { 493 memset (buffer, *marks, block_size); 494 if (write (fd, buffer, block_size) != block_size) 495 error (EXIT_FAILURE, errno, "write"); 496 } 497} 498 499static void 500generate_sparse_file (int argc, char **argv) 501{ 502 int i; 503 int fd; 504 int flags = O_CREAT|O_RDWR; 505 506 if (!file_name) 507 error (EXIT_FAILURE, 0, 508 _("cannot generate sparse files on standard output, use --file option")); 509 if (!seek_offset) 510 flags |= O_TRUNC; 511 fd = open (file_name, flags, 0644); 512 if (fd < 0) 513 error (EXIT_FAILURE, 0, _("cannot open `%s'"), file_name); 514 515 buffer = xmalloc (block_size); 516 517 file_length = 0; 518 519 for (i = 0; i < argc; i += 2) 520 { 521 off_t displ = get_size (argv[i], 1); 522 file_length += displ; 523 524 if (i == argc-1) 525 { 526 mkhole (fd, displ); 527 break; 528 } 529 else 530 { 531 file_length += block_size * strlen (argv[i+1]); 532 mksparse (fd, displ, argv[i+1]); 533 } 534 } 535 536 close (fd); 537} 538 539 540/* Status Mode */ 541 542void 543print_time (time_t t) 544{ 545 char buf[20]; /* ccyy-mm-dd HH:MM:SS\0 */ 546 strftime (buf, sizeof buf, "%Y-%m-%d %H:%M:%S", gmtime (&t)); 547 printf ("%s ", buf); 548} 549 550void 551print_stat (const char *name) 552{ 553 char *fmt, *p; 554 struct stat st; 555 char buf[UINTMAX_STRSIZE_BOUND]; 556 557 if (stat (name, &st)) 558 { 559 error (0, errno, _("stat(%s) failed"), name); 560 return; 561 } 562 563 fmt = strdup (stat_format); 564 for (p = strtok (fmt, ","); p; ) 565 { 566 if (memcmp (p, "st_", 3) == 0) 567 p += 3; 568 if (strcmp (p, "name") == 0) 569 printf ("%s", name); 570 else if (strcmp (p, "dev") == 0) 571 printf ("%lu", (unsigned long) st.st_dev); 572 else if (strcmp (p, "ino") == 0) 573 printf ("%lu", (unsigned long) st.st_ino); 574 else if (strncmp (p, "mode", 4) == 0) 575 { 576 mode_t mask = ~0; 577 578 if (ispunct (p[4])) 579 { 580 char *q; 581 582 mask = strtoul (p + 5, &q, 8); 583 if (*q) 584 { 585 printf ("\n"); 586 error (EXIT_FAILURE, 0, _("incorrect mask (near `%s')"), q); 587 } 588 } 589 else if (p[4]) 590 { 591 printf ("\n"); 592 error (EXIT_FAILURE, 0, _("Unknown field `%s'"), p); 593 } 594 printf ("%0o", st.st_mode & mask); 595 } 596 else if (strcmp (p, "nlink") == 0) 597 printf ("%lu", (unsigned long) st.st_nlink); 598 else if (strcmp (p, "uid") == 0) 599 printf ("%ld", (long unsigned) st.st_uid); 600 else if (strcmp (p, "gid") == 0) 601 printf ("%lu", (unsigned long) st.st_gid); 602 else if (strcmp (p, "size") == 0) 603 printf ("%s", umaxtostr (st.st_size, buf)); 604 else if (strcmp (p, "blksize") == 0) 605 printf ("%s", umaxtostr (st.st_blksize, buf)); 606 else if (strcmp (p, "blocks") == 0) 607 printf ("%s", umaxtostr (st.st_blocks, buf)); 608 else if (strcmp (p, "atime") == 0) 609 printf ("%lu", (unsigned long) st.st_atime); 610 else if (strcmp (p, "atimeH") == 0) 611 print_time (st.st_atime); 612 else if (strcmp (p, "mtime") == 0) 613 printf ("%lu", (unsigned long) st.st_mtime); 614 else if (strcmp (p, "mtimeH") == 0) 615 print_time (st.st_mtime); 616 else if (strcmp (p, "ctime") == 0) 617 printf ("%lu", (unsigned long) st.st_ctime); 618 else if (strcmp (p, "ctimeH") == 0) 619 print_time (st.st_ctime); 620 else if (strcmp (p, "sparse") == 0) 621 printf ("%d", ST_IS_SPARSE (st)); 622 else 623 { 624 printf ("\n"); 625 error (EXIT_FAILURE, 0, _("Unknown field `%s'"), p); 626 } 627 p = strtok (NULL, ","); 628 if (p) 629 printf (" "); 630 } 631 printf ("\n"); 632 free (fmt); 633} 634 635 636/* Exec Mode */ 637 638void 639exec_checkpoint (struct action *p) 640{ 641 if (verbose) 642 printf ("processing checkpoint %lu\n", (unsigned long) p->checkpoint); 643 switch (p->action) 644 { 645 case OPT_TOUCH: 646 { 647 struct timespec ts[2]; 648 649 ts[0] = ts[1] = p->ts; 650 if (utimens (p->name, ts) != 0) 651 { 652 error (0, errno, _("cannot set time on `%s'"), p->name); 653 break; 654 } 655 } 656 break; 657 658 case OPT_APPEND: 659 { 660 FILE *fp = fopen (p->name, "a"); 661 if (!fp) 662 { 663 error (0, errno, _("cannot open `%s'"), p->name); 664 break; 665 } 666 667 fill (fp, p->size, p->pattern); 668 fclose (fp); 669 } 670 break; 671 672 case OPT_TRUNCATE: 673 { 674 int fd = open (p->name, O_RDWR); 675 if (fd == -1) 676 { 677 error (0, errno, _("cannot open `%s'"), p->name); 678 break; 679 } 680 ftruncate (fd, p->size); 681 close (fd); 682 } 683 break; 684 685 case OPT_EXEC: 686 system (p->name); 687 break; 688 689 default: 690 abort (); 691 } 692} 693 694void 695process_checkpoint (size_t n) 696{ 697 struct action *p, *prev = NULL; 698 699 for (p = action_list; p; ) 700 { 701 struct action *next = p->next; 702 703 if (p->checkpoint <= n) 704 { 705 exec_checkpoint (p); 706 /* Remove the item from the list */ 707 if (prev) 708 prev->next = next; 709 else 710 action_list = next; 711 free (p); 712 } 713 else 714 prev = p; 715 716 p = next; 717 } 718} 719 720#define CHECKPOINT_TEXT "Write checkpoint" 721 722void 723exec_command (void) 724{ 725 int status; 726 pid_t pid; 727 int fd[2]; 728 char *p; 729 FILE *fp; 730 char buf[128]; 731 732 /* Insert --checkpoint option. 733 FIXME: This assumes that exec_argv does not use traditional tar options 734 (without dash) */ 735 exec_argc++; 736 exec_argv = xrealloc (exec_argv, (exec_argc + 1) * sizeof (*exec_argv)); 737 memmove (exec_argv+2, exec_argv+1, (exec_argc - 1) * sizeof (*exec_argv)); 738 exec_argv[1] = "--checkpoint"; 739 740#ifdef SIGCHLD 741 /* System V fork+wait does not work if SIGCHLD is ignored. */ 742 signal (SIGCHLD, SIG_DFL); 743#endif 744 745 pipe (fd); 746 747 pid = fork (); 748 if (pid == -1) 749 error (EXIT_FAILURE, errno, "fork"); 750 751 if (pid == 0) 752 { 753 /* Child */ 754 755 /* Pipe stderr */ 756 if (fd[1] != 2) 757 dup2 (fd[1], 2); 758 close (fd[0]); 759 760 /* Make sure POSIX locale is used */ 761 setenv ("LC_ALL", "POSIX", 1); 762 763 execvp (exec_argv[0], exec_argv); 764 error (EXIT_FAILURE, errno, "execvp"); 765 } 766 767 /* Master */ 768 close (fd[1]); 769 fp = fdopen (fd[0], "r"); 770 if (fp == NULL) 771 error (EXIT_FAILURE, errno, "fdopen"); 772 773 while ((p = fgets (buf, sizeof buf, fp))) 774 { 775 while (*p && !isspace (*p) && *p != ':') 776 p++; 777 778 if (*p == ':') 779 { 780 for (p++; *p && isspace (*p); p++) 781 ; 782 783 if (*p 784 && memcmp (p, CHECKPOINT_TEXT, sizeof CHECKPOINT_TEXT - 1) == 0) 785 { 786 char *end; 787 size_t n = strtoul (p + sizeof CHECKPOINT_TEXT - 1, &end, 10); 788 if (!(*end && !isspace (*end))) 789 { 790 process_checkpoint (n); 791 continue; 792 } 793 } 794 } 795 fprintf (stderr, "%s", buf); 796 } 797 798 /* Collect exit status */ 799 waitpid (pid, &status, 0); 800 801 if (verbose) 802 { 803 if (WIFEXITED (status)) 804 { 805 if (WEXITSTATUS (status) == 0) 806 printf (_("Command exited successfully\n")); 807 else 808 printf (_("Command failed with status %d\n"), 809 WEXITSTATUS (status)); 810 } 811 else if (WIFSIGNALED (status)) 812 printf (_("Command terminated on signal %d\n"), WTERMSIG (status)); 813 else if (WIFSTOPPED (status)) 814 printf (_("Command stopped on signal %d\n"), WSTOPSIG (status)); 815#ifdef WCOREDUMP 816 else if (WCOREDUMP (status)) 817 printf (_("Command dumped core\n")); 818#endif 819 else 820 printf(_("Command terminated\n")); 821 } 822 823 if (WIFEXITED (status)) 824 exit (WEXITSTATUS (status)); 825 exit (EXIT_FAILURE); 826} 827 828int 829main (int argc, char **argv) 830{ 831 int index; 832 833 program_name = argv[0]; 834 setlocale (LC_ALL, ""); 835 bindtextdomain (PACKAGE, LOCALEDIR); 836 textdomain (PACKAGE); 837 838 get_date (&touch_time, "now", NULL); 839 840 /* Decode command options. */ 841 842 if (argp_parse (&argp, argc, argv, 0, &index, NULL)) 843 exit (EXIT_FAILURE); 844 845 argc -= index; 846 argv += index; 847 848 switch (mode) 849 { 850 case mode_stat: 851 if (argc == 0) 852 error (EXIT_FAILURE, 0, _("--stat requires file names")); 853 854 while (argc--) 855 print_stat (*argv++); 856 break; 857 858 case mode_sparse: 859 generate_sparse_file (argc, argv); 860 verify_file (file_name); 861 break; 862 863 case mode_generate: 864 if (argc) 865 error (EXIT_FAILURE, 0, _("too many arguments")); 866 if (files_from) 867 generate_files_from_list (); 868 else 869 { 870 generate_simple_file (file_name); 871 verify_file (file_name); 872 } 873 break; 874 875 case mode_exec: 876 exec_command (); 877 break; 878 879 default: 880 /* Just in case */ 881 abort (); 882 } 883 exit (EXIT_SUCCESS); 884} 885