re-mark 1.29b-2 as not yet uploaded (merge madness!)
[debian/tar] / tests / genfile.c
index 1b338bce2f95a77635abe7f7f6926b53802d4395..219fb5e9ed90d702674c74cac6956dc4a0d11d0d 100644 (file)
@@ -2,7 +2,7 @@
    Print statistics for existing files.
 
    Copyright (C) 1995, 1996, 1997, 2001, 2003, 2004, 2005, 2006, 2007,
    Print statistics for existing files.
 
    Copyright (C) 1995, 1996, 1997, 2001, 2003, 2004, 2005, 2006, 2007,
-   2008 Free Software Foundation, Inc.
+   2008, 2009, 2016 Free Software Foundation, Inc.
 
    François Pinard <pinard@iro.umontreal.ca>, 1995.
    Sergey Poznyakoff <gray@mirddin.farlep.net>, 2004, 2005, 2006, 2007, 2008.
 
    François Pinard <pinard@iro.umontreal.ca>, 1995.
    Sergey Poznyakoff <gray@mirddin.farlep.net>, 2004, 2005, 2006, 2007, 2008.
 #include <argmatch.h>
 #include <argp.h>
 #include <argcv.h>
 #include <argmatch.h>
 #include <argp.h>
 #include <argcv.h>
-#include <getdate.h>
-#include <utimens.h>
+#include <parse-datetime.h>
 #include <inttostr.h>
 #include <fcntl.h>
 #include <sys/stat.h>
 #include <inttostr.h>
 #include <fcntl.h>
 #include <sys/stat.h>
+#include <c-ctype.h>
 #define obstack_chunk_alloc malloc
 #define obstack_chunk_free free
 #include <obstack.h>
 #define obstack_chunk_alloc malloc
 #define obstack_chunk_free free
 #include <obstack.h>
@@ -99,6 +99,7 @@ char *buffer;
 /* Number of arguments and argument vector for mode == mode_exec */
 int exec_argc;
 char **exec_argv;
 /* Number of arguments and argument vector for mode == mode_exec */
 int exec_argc;
 char **exec_argv;
+char *checkpoint_option;
 
 /* Time for --touch option */
 struct timespec touch_time;
 
 /* Time for --touch option */
 struct timespec touch_time;
@@ -106,6 +107,9 @@ struct timespec touch_time;
 /* Verbose mode */
 int verbose;
 
 /* Verbose mode */
 int verbose;
 
+/* Quiet mode */
+int quiet;
+
 const char *argp_program_version = "genfile (" PACKAGE ") " VERSION;
 const char *argp_program_bug_address = "<" PACKAGE_BUGREPORT ">";
 static char doc[] = N_("genfile manipulates data files for GNU paxutils test suite.\n"
 const char *argp_program_version = "genfile (" PACKAGE ") " VERSION;
 const char *argp_program_bug_address = "<" PACKAGE_BUGREPORT ">";
 static char doc[] = N_("genfile manipulates data files for GNU paxutils test suite.\n"
@@ -119,6 +123,7 @@ static char doc[] = N_("genfile manipulates data files for GNU paxutils test sui
 #define OPT_DATE       261
 #define OPT_VERBOSE    262
 #define OPT_SEEK       263
 #define OPT_DATE       261
 #define OPT_VERBOSE    262
 #define OPT_SEEK       263
+#define OPT_UNLINK     264
 
 static struct argp_option options[] = {
 #define GRP 0
 
 static struct argp_option options[] = {
 #define GRP 0
@@ -143,7 +148,8 @@ static struct argp_option options[] = {
   {"seek", OPT_SEEK, N_("OFFSET"), 0,
    N_("Seek to the given offset before writing data"),
    GRP+1 },
   {"seek", OPT_SEEK, N_("OFFSET"), 0,
    N_("Seek to the given offset before writing data"),
    GRP+1 },
-
+  {"quiet", 'q', NULL, 0,
+   N_("Suppress non-fatal diagnostic messages") },
 #undef GRP
 #define GRP 10
   {NULL, 0, NULL, 0,
 #undef GRP
 #define GRP 10
   {NULL, 0, NULL, 0,
@@ -159,8 +165,8 @@ static struct argp_option options[] = {
   {NULL, 0, NULL, 0,
    N_("Synchronous execution options:"), GRP},
 
   {NULL, 0, NULL, 0,
    N_("Synchronous execution options:"), GRP},
 
-  {"run", 'r', N_("COMMAND"), 0,
-   N_("Execute given COMMAND. Useful with --checkpoint and one of --cut, --append, --touch"),
+  {"run", 'r', N_("OPTION"), OPTION_ARG_OPTIONAL,
+   N_("Execute ARGS. Useful with --checkpoint and one of --cut, --append, --touch, --unlink"),
    GRP+1 },
   {"checkpoint", OPT_CHECKPOINT, N_("NUMBER"), 0,
    N_("Perform given action (see below) upon reaching checkpoint NUMBER"),
    GRP+1 },
   {"checkpoint", OPT_CHECKPOINT, N_("NUMBER"), 0,
    N_("Perform given action (see below) upon reaching checkpoint NUMBER"),
@@ -189,6 +195,9 @@ static struct argp_option options[] = {
   {"exec", OPT_EXEC, N_("COMMAND"), 0,
    N_("Execute COMMAND"),
    GRP+1 },
   {"exec", OPT_EXEC, N_("COMMAND"), 0,
    N_("Execute COMMAND"),
    GRP+1 },
+  {"unlink", OPT_UNLINK, N_("FILE"), 0,
+   N_("Unlink FILE"),
+   GRP+1 },
 #undef GRP
   { NULL, }
 };
 #undef GRP
   { NULL, }
 };
@@ -261,11 +270,11 @@ verify_file (char *file_name)
        error (0, errno, _("stat(%s) failed"), file_name);
 
       if (st.st_size != file_length + seek_offset)
        error (0, errno, _("stat(%s) failed"), file_name);
 
       if (st.st_size != file_length + seek_offset)
-       error (1, 0, _("requested file length %lu, actual %lu"),
+       error (EXIT_FAILURE, 0, _("requested file length %lu, actual %lu"),
               (unsigned long)st.st_size, (unsigned long)file_length);
 
               (unsigned long)st.st_size, (unsigned long)file_length);
 
-      if (mode == mode_sparse && !ST_IS_SPARSE (st))
-       error (1, 0, _("created file is not sparse"));
+      if (!quiet && mode == mode_sparse && !ST_IS_SPARSE (st))
+       error (EXIT_FAILURE, 0, _("created file is not sparse"));
     }
 }
 
     }
 }
 
@@ -321,6 +330,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
       block_size = get_size (arg, 0);
       break;
 
       block_size = get_size (arg, 0);
       break;
 
+    case 'q':
+      quiet = 1;
+      break;
+      
     case 's':
       mode = mode_sparse;
       break;
     case 's':
       mode = mode_sparse;
       break;
@@ -333,7 +346,11 @@ parse_opt (int key, char *arg, struct argp_state *state)
 
     case 'r':
       mode = mode_exec;
 
     case 'r':
       mode = mode_exec;
-      argcv_get (arg, "", NULL, &exec_argc, &exec_argv);
+      if (arg)
+       {
+         argcv_get (arg, "", NULL, &exec_argc, &exec_argv);
+         checkpoint_option = "--checkpoint";
+       }
       break;
 
     case 'T':
       break;
 
     case 'T':
@@ -355,7 +372,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
       break;
 
     case OPT_DATE:
       break;
 
     case OPT_DATE:
-      if (!get_date (&touch_time, arg, NULL))
+      if (! parse_datetime (&touch_time, arg, NULL))
        argp_error (state, _("Unknown date format"));
       break;
 
        argp_error (state, _("Unknown date format"));
       break;
 
@@ -363,6 +380,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
     case OPT_TRUNCATE:
     case OPT_TOUCH:
     case OPT_EXEC:
     case OPT_TRUNCATE:
     case OPT_TOUCH:
     case OPT_EXEC:
+    case OPT_UNLINK:
       reg_action (key, arg);
       break;
 
       reg_action (key, arg);
       break;
 
@@ -476,9 +494,11 @@ generate_files_from_list ()
 static void
 mkhole (int fd, off_t displ)
 {
 static void
 mkhole (int fd, off_t displ)
 {
-  if (lseek (fd, displ, SEEK_CUR) == -1)
+  off_t offset = lseek (fd, displ, SEEK_CUR);
+  if (offset < 0)
     error (EXIT_FAILURE, errno, "lseek");
     error (EXIT_FAILURE, errno, "lseek");
-  ftruncate (fd, lseek (fd, 0, SEEK_CUR));
+  if (ftruncate (fd, offset) != 0)
+    error (EXIT_FAILURE, errno, "ftruncate");
 }
 
 static void
 }
 
 static void
@@ -495,10 +515,56 @@ mksparse (int fd, off_t displ, char *marks)
     }
 }
 
     }
 }
 
+static int
+make_fragment (int fd, char *offstr, char *mapstr)
+{
+  int i;
+  off_t displ = get_size (offstr, 1);
+
+  file_length += displ;
+
+  if (!mapstr || !*mapstr)
+    {
+      mkhole (fd, displ);
+      return 1;
+    }
+  else if (*mapstr == '=')
+    {
+      off_t n = get_size (mapstr + 1, 1);
+
+      switch (pattern)
+       {
+       case DEFAULT_PATTERN:
+         for (i = 0; i < block_size; i++)
+           buffer[i] = i & 255;
+         break;
+         
+       case ZEROS_PATTERN:
+         memset (buffer, 0, block_size);
+         break;
+       }
+
+      if (lseek (fd, displ, SEEK_CUR) == -1)
+       error (EXIT_FAILURE, errno, "lseek");
+      
+      for (; n; n--)
+       {
+         if (write (fd, buffer, block_size) != block_size)
+           error (EXIT_FAILURE, errno, "write");
+         file_length += block_size;
+       }
+    }
+  else
+    {
+      file_length += block_size * strlen (mapstr);
+      mksparse (fd, displ, mapstr);
+    }
+  return 0;
+}
+
 static void
 generate_sparse_file (int argc, char **argv)
 {
 static void
 generate_sparse_file (int argc, char **argv)
 {
-  int i;
   int fd;
   int flags = O_CREAT | O_RDWR | O_BINARY;
 
   int fd;
   int flags = O_CREAT | O_RDWR | O_BINARY;
 
@@ -515,20 +581,33 @@ generate_sparse_file (int argc, char **argv)
 
   file_length = 0;
 
 
   file_length = 0;
 
-  for (i = 0; i < argc; i += 2)
+  while (argc)
     {
     {
-      off_t displ = get_size (argv[i], 1);
-      file_length += displ;
-
-      if (i == argc-1)
+      if (argv[0][0] == '-' && argv[0][1] == 0)
        {
        {
-         mkhole (fd, displ);
-         break;
+         char buf[256];
+         while (fgets (buf, sizeof (buf), stdin))
+           {
+             size_t n = strlen (buf);
+
+             while (n > 0 && c_isspace (buf[n-1]))
+               buf[--n] = 0;
+             
+             n = strcspn (buf, " \t");
+             buf[n++] = 0;
+             while (buf[n] && c_isblank (buf[n]))
+               ++n;
+             make_fragment (fd, buf, buf + n);
+           }
+         ++argv;
+         --argc;
        }
       else
        {
        }
       else
        {
-         file_length += block_size * strlen (argv[i+1]);
-         mksparse (fd, displ, argv[i+1]);
+         if (make_fragment (fd, argv[0], argv[1]))
+           break;
+         argc -= 2;
+         argv += 2;
        }
     }
 
        }
     }
 
@@ -572,13 +651,13 @@ print_stat (const char *name)
        printf ("%lu", (unsigned long) st.st_ino);
       else if (strncmp (p, "mode", 4) == 0)
        {
        printf ("%lu", (unsigned long) st.st_ino);
       else if (strncmp (p, "mode", 4) == 0)
        {
-         mode_t mask = ~0;
+         unsigned val = st.st_mode;
 
 
-         if (ispunct (p[4]))
+         if (ispunct ((unsigned char) p[4]))
            {
              char *q;
 
            {
              char *q;
 
-             mask = strtoul (p + 5, &q, 8);
+             val &= strtoul (p + 5, &q, 8);
              if (*q)
                {
                  printf ("\n");
              if (*q)
                {
                  printf ("\n");
@@ -590,7 +669,7 @@ print_stat (const char *name)
              printf ("\n");
              error (EXIT_FAILURE, 0, _("Unknown field `%s'"), p);
            }
              printf ("\n");
              error (EXIT_FAILURE, 0, _("Unknown field `%s'"), p);
            }
-         printf ("%0o", st.st_mode & mask);
+         printf ("%0o", val);
        }
       else if (strcmp (p, "nlink") == 0)
        printf ("%lu", (unsigned long) st.st_nlink);
        }
       else if (strcmp (p, "nlink") == 0)
        printf ("%lu", (unsigned long) st.st_nlink);
@@ -646,7 +725,7 @@ exec_checkpoint (struct action *p)
        struct timespec ts[2];
 
        ts[0] = ts[1] = p->ts;
        struct timespec ts[2];
 
        ts[0] = ts[1] = p->ts;
-       if (utimens (p->name, ts) != 0)
+       if (utimensat (AT_FDCWD, p->name, ts, 0) != 0)
          {
            error (0, errno, _("cannot set time on `%s'"), p->name);
            break;
          {
            error (0, errno, _("cannot set time on `%s'"), p->name);
            break;
@@ -676,13 +755,23 @@ exec_checkpoint (struct action *p)
            error (0, errno, _("cannot open `%s'"), p->name);
            break;
          }
            error (0, errno, _("cannot open `%s'"), p->name);
            break;
          }
-       ftruncate (fd, p->size);
+       if (ftruncate (fd, p->size) != 0)
+         {
+           error (0, errno, _("cannot truncate `%s'"), p->name);
+           break;
+         }
        close (fd);
       }
       break;
 
     case OPT_EXEC:
        close (fd);
       }
       break;
 
     case OPT_EXEC:
-      system (p->name);
+      if (system (p->name) != 0)
+       error (0, 0, _("command failed: %s"), p->name);
+      break;
+
+    case OPT_UNLINK:
+      if (unlink (p->name))
+       error (0, errno, _("cannot unlink `%s'"), p->name);
       break;
 
     default:
       break;
 
     default:
@@ -730,18 +819,25 @@ exec_command (void)
 
   /* Insert --checkpoint option.
      FIXME: This assumes that exec_argv does not use traditional tar options
 
   /* Insert --checkpoint option.
      FIXME: This assumes that exec_argv does not use traditional tar options
-     (without dash) */
-  exec_argc++;
-  exec_argv = xrealloc (exec_argv, (exec_argc + 1) * sizeof (*exec_argv));
-  memmove (exec_argv+2, exec_argv+1, (exec_argc - 1) * sizeof (*exec_argv));
-  exec_argv[1] = "--checkpoint";
+     (without dash).
+     FIXME: There is no way to set checkpoint argument (granularity).
+  */
+  if (checkpoint_option)
+    {
+      exec_argc++;
+      exec_argv = xrealloc (exec_argv, (exec_argc + 1) * sizeof (*exec_argv));
+      memmove (exec_argv+2, exec_argv+1,
+              (exec_argc - 1) * sizeof (*exec_argv));
+      exec_argv[1] = checkpoint_option;
+    }
 
 #ifdef SIGCHLD
   /* System V fork+wait does not work if SIGCHLD is ignored.  */
   signal (SIGCHLD, SIG_DFL);
 #endif
 
 
 #ifdef SIGCHLD
   /* System V fork+wait does not work if SIGCHLD is ignored.  */
   signal (SIGCHLD, SIG_DFL);
 #endif
 
-  pipe (fd);
+  if (pipe (fd) != 0)
+    error (EXIT_FAILURE, errno, "pipe");
 
   pid = fork ();
   if (pid == -1)
 
   pid = fork ();
   if (pid == -1)
@@ -760,7 +856,7 @@ exec_command (void)
       setenv ("LC_ALL", "POSIX", 1);
 
       execvp (exec_argv[0], exec_argv);
       setenv ("LC_ALL", "POSIX", 1);
 
       execvp (exec_argv[0], exec_argv);
-      error (EXIT_FAILURE, errno, "execvp");
+      error (EXIT_FAILURE, errno, "execvp %s", exec_argv[0]);
     }
 
   /* Master */
     }
 
   /* Master */
@@ -771,12 +867,12 @@ exec_command (void)
 
   while ((p = fgets (buf, sizeof buf, fp)))
     {
 
   while ((p = fgets (buf, sizeof buf, fp)))
     {
-      while (*p && !isspace (*p) && *p != ':')
+      while (*p && !isspace ((unsigned char) *p) && *p != ':')
        p++;
 
       if (*p == ':')
        {
        p++;
 
       if (*p == ':')
        {
-         for (p++; *p && isspace (*p); p++)
+         for (p++; *p && isspace ((unsigned char) *p); p++)
            ;
 
          if (*p
            ;
 
          if (*p
@@ -784,7 +880,7 @@ exec_command (void)
            {
              char *end;
              size_t n = strtoul (p + sizeof CHECKPOINT_TEXT - 1, &end, 10);
            {
              char *end;
              size_t n = strtoul (p + sizeof CHECKPOINT_TEXT - 1, &end, 10);
-             if (!(*end && !isspace (*end)))
+             if (!(*end && !isspace ((unsigned char) *end)))
                {
                  process_checkpoint (n);
                  continue;
                {
                  process_checkpoint (n);
                  continue;
@@ -834,7 +930,7 @@ main (int argc, char **argv)
   bindtextdomain (PACKAGE, LOCALEDIR);
   textdomain (PACKAGE);
 
   bindtextdomain (PACKAGE, LOCALEDIR);
   textdomain (PACKAGE);
 
-  get_date (&touch_time, "now", NULL);
+  parse_datetime (&touch_time, "now", NULL);
 
   /* Decode command options.  */
 
 
   /* Decode command options.  */
 
@@ -872,6 +968,13 @@ main (int argc, char **argv)
       break;
 
     case mode_exec:
       break;
 
     case mode_exec:
+      if (!checkpoint_option)
+       {
+         exec_argc = argc;
+         exec_argv = argv;
+       }
+      else if (argc)
+       error (EXIT_FAILURE, 0, _("too many arguments"));
       exec_command ();
       break;
 
       exec_command ();
       break;