(root)/
tar-1.35/
tests/
genfile.c
       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  }