1 /* Generate a file containing some preset patterns.
2 Print statistics for existing files.
4 Copyright (C) 1995, 1996, 1997, 2001, 2003, 2004, 2005, 2006, 2007,
5 2008, 2009, 2016 Free Software Foundation, Inc.
7 François Pinard <pinard@iro.umontreal.ca>, 1995.
8 Sergey Poznyakoff <gray@mirddin.farlep.net>, 2004, 2005, 2006, 2007, 2008.
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)
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.
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.
31 #include <parse-datetime.h>
36 #define obstack_chunk_alloc malloc
37 #define obstack_chunk_free free
41 # define EXIT_SUCCESS 0
44 # define EXIT_FAILURE 1
47 #if ! defined SIGCHLD && defined SIGCLD
48 # define SIGCHLD SIGCLD
57 /* The name this program was run with. */
58 const char *program_name;
60 /* Name of file to generate */
61 static char *file_name;
63 /* Name of the file-list file: */
64 static char *files_from;
65 static char filename_terminator = '\n';
67 /* Length of file to generate. */
68 static off_t file_length = 0;
69 static off_t seek_offset = 0;
71 /* Pattern to generate. */
72 static enum pattern pattern = DEFAULT_PATTERN;
74 /* Next checkpoint number */
85 enum genfile_mode mode = mode_generate;
87 #define DEFAULT_STAT_FORMAT \
88 "name,dev,ino,mode,nlink,uid,gid,size,blksize,blocks,atime,mtime,ctime"
90 /* Format for --stat option */
91 static char *stat_format = DEFAULT_STAT_FORMAT;
93 /* Size of a block for sparse file */
94 size_t block_size = 512;
96 /* Block buffer for sparse file */
99 /* Number of arguments and argument vector for mode == mode_exec */
102 char *checkpoint_option;
104 /* Time for --touch option */
105 struct timespec touch_time;
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"
118 #define OPT_CHECKPOINT 256
119 #define OPT_TOUCH 257
120 #define OPT_APPEND 258
121 #define OPT_TRUNCATE 259
124 #define OPT_VERBOSE 262
126 #define OPT_UNLINK 264
128 static struct argp_option options[] = {
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'"),
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."),
148 {"seek", OPT_SEEK, N_("OFFSET"), 0,
149 N_("Seek to the given offset before writing data"),
151 {"quiet", 'q', NULL, 0,
152 N_("Suppress non-fatal diagnostic messages") },
156 N_("File statistics options:"), GRP},
158 {"stat", 'S', N_("FORMAT"), OPTION_ARG_OPTIONAL,
159 N_("Print contents of struct stat for each given file. Default FORMAT is: ")
166 N_("Synchronous execution options:"), GRP},
168 {"run", 'r', N_("OPTION"), OPTION_ARG_OPTIONAL,
169 N_("Execute ARGS. Useful with --checkpoint and one of --cut, --append, --touch, --unlink"),
171 {"checkpoint", OPT_CHECKPOINT, N_("NUMBER"), 0,
172 N_("Perform given action (see below) upon reaching checkpoint NUMBER"),
174 {"date", OPT_DATE, N_("STRING"), 0,
175 N_("Set date for next --touch option"),
177 {"verbose", OPT_VERBOSE, NULL, 0,
178 N_("Display executed checkpoints and exit status of COMMAND"),
183 N_("Synchronous execution actions. These are executed when checkpoint number given by --checkpoint option is reached."), GRP},
185 {"cut", OPT_TRUNCATE, N_("FILE"), 0,
186 N_("Truncate FILE to the size specified by previous --length option (or 0, if it is not given)"),
188 {"truncate", 0, NULL, OPTION_ALIAS, NULL, GRP+1 },
189 {"append", OPT_APPEND, N_("FILE"), 0,
190 N_("Append SIZE bytes to FILE. SIZE is given by previous --length option."),
192 {"touch", OPT_TOUCH, N_("FILE"), 0,
193 N_("Update the access and modification times of FILE"),
195 {"exec", OPT_EXEC, N_("COMMAND"), 0,
196 N_("Execute COMMAND"),
198 {"unlink", OPT_UNLINK, N_("FILE"), 0,
205 static char const * const pattern_args[] = { "default", "zeros", 0 };
206 static enum pattern const pattern_types[] = {DEFAULT_PATTERN, ZEROS_PATTERN};
209 xlat_suffix (off_t *vp, const char *p)
237 get_size (const char *str, int allow_zero)
242 for (p = str; *p; p++)
244 int digit = *p - '0';
246 if (9 < (unsigned) digit)
248 if (xlat_suffix (&v, p))
249 error (EXIT_FAILURE, 0, _("Invalid size: %s"), str);
253 else if (x / 10 != v)
254 error (EXIT_FAILURE, 0, _("Number out of allowed range: %s"), str);
257 error (EXIT_FAILURE, 0, _("Negative size: %s"), str);
263 verify_file (char *file_name)
269 if (stat (file_name, &st))
270 error (0, errno, _("stat(%s) failed"), file_name);
272 if (st.st_size != file_length + seek_offset)
273 error (EXIT_FAILURE, 0, _("requested file length %lu, actual %lu"),
274 (unsigned long)st.st_size, (unsigned long)file_length);
276 if (!quiet && mode == mode_sparse && !ST_IS_SPARSE (st))
277 error (EXIT_FAILURE, 0, _("created file is not sparse"));
288 enum pattern pattern;
292 static struct action *action_list;
295 reg_action (int action, char *arg)
297 struct action *act = xmalloc (sizeof (*act));
298 act->checkpoint = checkpoint;
299 act->action = action;
300 act->pattern = pattern;
301 act->ts = touch_time;
302 act->size = file_length;
304 act->next = action_list;
309 parse_opt (int key, char *arg, struct argp_state *state)
314 filename_terminator = 0;
322 file_length = get_size (arg, 1);
326 pattern = XARGMATCH ("--pattern", arg, pattern_args, pattern_types);
330 block_size = get_size (arg, 0);
351 argcv_get (arg, "", NULL, &exec_argc, &exec_argv);
352 checkpoint_option = "--checkpoint";
361 seek_offset = get_size (arg, 0);
368 checkpoint = strtoul (arg, &p, 0);
370 argp_error (state, _("Error parsing number near `%s'"), p);
375 if (! parse_datetime (&touch_time, arg, NULL))
376 argp_error (state, _("Unknown date format"));
384 reg_action (key, arg);
392 return ARGP_ERR_UNKNOWN;
397 static struct argp argp = {
409 fill (FILE *fp, off_t length, enum pattern pattern)
415 case DEFAULT_PATTERN:
416 for (i = 0; i < length; i++)
421 for (i = 0; i < length; i++)
427 /* Generate Mode: usual files */
429 generate_simple_file (char *filename)
435 fp = fopen (filename, seek_offset ? "rb+" : "wb");
437 error (EXIT_FAILURE, errno, _("cannot open `%s'"), filename);
442 if (fseeko (fp, seek_offset, 0))
443 error (EXIT_FAILURE, errno, "%s", _("cannot seek"));
445 fill (fp, file_length, pattern);
450 /* A simplified version of the same function from tar */
452 read_name_from_file (FILE *fp, struct obstack *stk)
457 for (c = getc (fp); c != EOF && c != filename_terminator; c = getc (fp))
460 error (EXIT_FAILURE, 0, _("file name contains null character"));
461 obstack_1grow (stk, c);
465 obstack_1grow (stk, 0);
467 return (counter == 0 && c == EOF);
471 generate_files_from_list ()
473 FILE *fp = strcmp (files_from, "-") ? fopen (files_from, "rb") : stdin;
477 error (EXIT_FAILURE, errno, _("cannot open `%s'"), files_from);
480 while (!read_name_from_file (fp, &stk))
482 char *name = obstack_finish (&stk);
483 generate_simple_file (name);
485 obstack_free (&stk, name);
488 obstack_free (&stk, NULL);
492 /* Generate Mode: sparse files */
495 mkhole (int fd, off_t displ)
497 off_t offset = lseek (fd, displ, SEEK_CUR);
499 error (EXIT_FAILURE, errno, "lseek");
500 if (ftruncate (fd, offset) != 0)
501 error (EXIT_FAILURE, errno, "ftruncate");
505 mksparse (int fd, off_t displ, char *marks)
507 if (lseek (fd, displ, SEEK_CUR) == -1)
508 error (EXIT_FAILURE, errno, "lseek");
510 for (; *marks; marks++)
512 memset (buffer, *marks, block_size);
513 if (write (fd, buffer, block_size) != block_size)
514 error (EXIT_FAILURE, errno, "write");
519 make_fragment (int fd, char *offstr, char *mapstr)
522 off_t displ = get_size (offstr, 1);
524 file_length += displ;
526 if (!mapstr || !*mapstr)
531 else if (*mapstr == '=')
533 off_t n = get_size (mapstr + 1, 1);
537 case DEFAULT_PATTERN:
538 for (i = 0; i < block_size; i++)
543 memset (buffer, 0, block_size);
547 if (lseek (fd, displ, SEEK_CUR) == -1)
548 error (EXIT_FAILURE, errno, "lseek");
552 if (write (fd, buffer, block_size) != block_size)
553 error (EXIT_FAILURE, errno, "write");
554 file_length += block_size;
559 file_length += block_size * strlen (mapstr);
560 mksparse (fd, displ, mapstr);
566 generate_sparse_file (int argc, char **argv)
569 int flags = O_CREAT | O_RDWR | O_BINARY;
572 error (EXIT_FAILURE, 0,
573 _("cannot generate sparse files on standard output, use --file option"));
576 fd = open (file_name, flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
578 error (EXIT_FAILURE, errno, _("cannot open `%s'"), file_name);
580 buffer = xmalloc (block_size);
586 if (argv[0][0] == '-' && argv[0][1] == 0)
589 while (fgets (buf, sizeof (buf), stdin))
591 size_t n = strlen (buf);
593 while (n > 0 && c_isspace (buf[n-1]))
596 n = strcspn (buf, " \t");
598 while (buf[n] && c_isblank (buf[n]))
600 make_fragment (fd, buf, buf + n);
607 if (make_fragment (fd, argv[0], argv[1]))
621 print_time (time_t t)
623 char buf[20]; /* ccyy-mm-dd HH:MM:SS\0 */
624 strftime (buf, sizeof buf, "%Y-%m-%d %H:%M:%S", gmtime (&t));
629 print_stat (const char *name)
633 char buf[UINTMAX_STRSIZE_BOUND];
635 if (stat (name, &st))
637 error (0, errno, _("stat(%s) failed"), name);
641 fmt = strdup (stat_format);
642 for (p = strtok (fmt, ","); p; )
644 if (memcmp (p, "st_", 3) == 0)
646 if (strcmp (p, "name") == 0)
648 else if (strcmp (p, "dev") == 0)
649 printf ("%lu", (unsigned long) st.st_dev);
650 else if (strcmp (p, "ino") == 0)
651 printf ("%lu", (unsigned long) st.st_ino);
652 else if (strncmp (p, "mode", 4) == 0)
654 unsigned val = st.st_mode;
656 if (ispunct ((unsigned char) p[4]))
660 val &= strtoul (p + 5, &q, 8);
664 error (EXIT_FAILURE, 0, _("incorrect mask (near `%s')"), q);
670 error (EXIT_FAILURE, 0, _("Unknown field `%s'"), p);
674 else if (strcmp (p, "nlink") == 0)
675 printf ("%lu", (unsigned long) st.st_nlink);
676 else if (strcmp (p, "uid") == 0)
677 printf ("%ld", (long unsigned) st.st_uid);
678 else if (strcmp (p, "gid") == 0)
679 printf ("%lu", (unsigned long) st.st_gid);
680 else if (strcmp (p, "size") == 0)
681 printf ("%s", umaxtostr (st.st_size, buf));
682 else if (strcmp (p, "blksize") == 0)
683 printf ("%s", umaxtostr (st.st_blksize, buf));
684 else if (strcmp (p, "blocks") == 0)
685 printf ("%s", umaxtostr (st.st_blocks, buf));
686 else if (strcmp (p, "atime") == 0)
687 printf ("%lu", (unsigned long) st.st_atime);
688 else if (strcmp (p, "atimeH") == 0)
689 print_time (st.st_atime);
690 else if (strcmp (p, "mtime") == 0)
691 printf ("%lu", (unsigned long) st.st_mtime);
692 else if (strcmp (p, "mtimeH") == 0)
693 print_time (st.st_mtime);
694 else if (strcmp (p, "ctime") == 0)
695 printf ("%lu", (unsigned long) st.st_ctime);
696 else if (strcmp (p, "ctimeH") == 0)
697 print_time (st.st_ctime);
698 else if (strcmp (p, "sparse") == 0)
699 printf ("%d", ST_IS_SPARSE (st));
703 error (EXIT_FAILURE, 0, _("Unknown field `%s'"), p);
705 p = strtok (NULL, ",");
717 exec_checkpoint (struct action *p)
720 printf ("processing checkpoint %lu\n", (unsigned long) p->checkpoint);
725 struct timespec ts[2];
727 ts[0] = ts[1] = p->ts;
728 if (utimensat (AT_FDCWD, p->name, ts, 0) != 0)
730 error (0, errno, _("cannot set time on `%s'"), p->name);
738 FILE *fp = fopen (p->name, "ab");
741 error (0, errno, _("cannot open `%s'"), p->name);
745 fill (fp, p->size, p->pattern);
752 int fd = open (p->name, O_RDWR | O_BINARY);
755 error (0, errno, _("cannot open `%s'"), p->name);
758 if (ftruncate (fd, p->size) != 0)
760 error (0, errno, _("cannot truncate `%s'"), p->name);
768 if (system (p->name) != 0)
769 error (0, 0, _("command failed: %s"), p->name);
773 if (unlink (p->name))
774 error (0, errno, _("cannot unlink `%s'"), p->name);
783 process_checkpoint (size_t n)
785 struct action *p, *prev = NULL;
787 for (p = action_list; p; )
789 struct action *next = p->next;
791 if (p->checkpoint <= n)
794 /* Remove the item from the list */
808 #define CHECKPOINT_TEXT "Write checkpoint"
820 /* Insert --checkpoint option.
821 FIXME: This assumes that exec_argv does not use traditional tar options
823 FIXME: There is no way to set checkpoint argument (granularity).
825 if (checkpoint_option)
828 exec_argv = xrealloc (exec_argv, (exec_argc + 1) * sizeof (*exec_argv));
829 memmove (exec_argv+2, exec_argv+1,
830 (exec_argc - 1) * sizeof (*exec_argv));
831 exec_argv[1] = checkpoint_option;
835 /* System V fork+wait does not work if SIGCHLD is ignored. */
836 signal (SIGCHLD, SIG_DFL);
840 error (EXIT_FAILURE, errno, "pipe");
844 error (EXIT_FAILURE, errno, "fork");
855 /* Make sure POSIX locale is used */
856 setenv ("LC_ALL", "POSIX", 1);
858 execvp (exec_argv[0], exec_argv);
859 error (EXIT_FAILURE, errno, "execvp %s", exec_argv[0]);
864 fp = fdopen (fd[0], "rb");
866 error (EXIT_FAILURE, errno, "fdopen");
868 while ((p = fgets (buf, sizeof buf, fp)))
870 while (*p && !isspace ((unsigned char) *p) && *p != ':')
875 for (p++; *p && isspace ((unsigned char) *p); p++)
879 && memcmp (p, CHECKPOINT_TEXT, sizeof CHECKPOINT_TEXT - 1) == 0)
882 size_t n = strtoul (p + sizeof CHECKPOINT_TEXT - 1, &end, 10);
883 if (!(*end && !isspace ((unsigned char) *end)))
885 process_checkpoint (n);
890 fprintf (stderr, "%s", buf);
893 /* Collect exit status */
894 waitpid (pid, &status, 0);
898 if (WIFEXITED (status))
900 if (WEXITSTATUS (status) == 0)
901 printf (_("Command exited successfully\n"));
903 printf (_("Command failed with status %d\n"),
904 WEXITSTATUS (status));
906 else if (WIFSIGNALED (status))
907 printf (_("Command terminated on signal %d\n"), WTERMSIG (status));
908 else if (WIFSTOPPED (status))
909 printf (_("Command stopped on signal %d\n"), WSTOPSIG (status));
911 else if (WCOREDUMP (status))
912 printf (_("Command dumped core\n"));
915 printf(_("Command terminated\n"));
918 if (WIFEXITED (status))
919 exit (WEXITSTATUS (status));
924 main (int argc, char **argv)
928 program_name = argv[0];
929 setlocale (LC_ALL, "");
930 bindtextdomain (PACKAGE, LOCALEDIR);
931 textdomain (PACKAGE);
933 parse_datetime (&touch_time, "now", NULL);
935 /* Decode command options. */
937 if (argp_parse (&argp, argc, argv, 0, &index, NULL))
947 error (EXIT_FAILURE, 0, _("--stat requires file names"));
950 print_stat (*argv++);
954 generate_sparse_file (argc, argv);
955 verify_file (file_name);
960 error (EXIT_FAILURE, 0, _("too many arguments"));
962 generate_files_from_list ();
965 generate_simple_file (file_name);
966 verify_file (file_name);
971 if (!checkpoint_option)
977 error (EXIT_FAILURE, 0, _("too many arguments"));