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.
#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 <c-ctype.h>
#define obstack_chunk_alloc malloc
#define obstack_chunk_free free
#include <obstack.h>
/* 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;
/* 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"
#define OPT_DATE 261
#define OPT_VERBOSE 262
#define OPT_SEEK 263
+#define OPT_UNLINK 264
static struct argp_option options[] = {
#define GRP 0
{"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,
{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"),
{"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, }
};
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);
- 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"));
}
}
block_size = get_size (arg, 0);
break;
+ case 'q':
+ quiet = 1;
+ break;
+
case 's':
mode = mode_sparse;
break;
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 OPT_DATE:
- if (!get_date (&touch_time, arg, NULL))
+ if (! parse_datetime (&touch_time, arg, NULL))
argp_error (state, _("Unknown date format"));
break;
case OPT_TRUNCATE:
case OPT_TOUCH:
case OPT_EXEC:
+ case OPT_UNLINK:
reg_action (key, arg);
break;
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");
- ftruncate (fd, lseek (fd, 0, SEEK_CUR));
+ if (ftruncate (fd, offset) != 0)
+ error (EXIT_FAILURE, errno, "ftruncate");
}
static void
}
}
+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)
{
- int i;
int fd;
int flags = O_CREAT | O_RDWR | O_BINARY;
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
{
- 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;
}
}
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;
- mask = strtoul (p + 5, &q, 8);
+ val &= strtoul (p + 5, &q, 8);
if (*q)
{
printf ("\n");
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);
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 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:
- 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:
/* 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
- pipe (fd);
+ if (pipe (fd) != 0)
+ error (EXIT_FAILURE, errno, "pipe");
pid = fork ();
if (pid == -1)
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 */
while ((p = fgets (buf, sizeof buf, fp)))
{
- while (*p && !isspace (*p) && *p != ':')
+ while (*p && !isspace ((unsigned char) *p) && *p != ':')
p++;
if (*p == ':')
{
- for (p++; *p && isspace (*p); p++)
+ for (p++; *p && isspace ((unsigned char) *p); p++)
;
if (*p
{
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;
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
- get_date (&touch_time, "now", NULL);
+ parse_datetime (&touch_time, "now", NULL);
/* Decode command options. */
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;