/* Checkpoint management for tar.
- Copyright 2007, 2013 Free Software Foundation, Inc.
+ Copyright 2007, 2013-2014 Free Software Foundation, Inc.
This file is part of GNU tar.
#include "common.h"
#include "wordsplit.h"
#include <sys/ioctl.h>
+#include <termios.h>
#include "fprintftime.h"
enum checkpoint_opcode
checkpoint_option = DEFAULT_CHECKPOINT;
}
-static char *checkpoint_total_format[] = {
+static const char *checkpoint_total_format[] = {
"R",
"W",
"D"
};
-static int
-getwidth(FILE *fp)
+static long
+getwidth (FILE *fp)
{
+ char const *columns;
+
+#ifdef TIOCGWINSZ
struct winsize ws;
+ if (ioctl (fileno (fp), TIOCGWINSZ, &ws) == 0 && 0 < ws.ws_col)
+ return ws.ws_col;
+#endif
- ws.ws_col = ws.ws_row = 0;
- if ((ioctl (fileno (fp), TIOCGWINSZ, (char *) &ws) < 0) || ws.ws_col == 0)
+ columns = getenv ("COLUMNS");
+ if (columns)
{
- const char *col = getenv ("COLUMNS");
- if (col)
- return strtol (col, NULL, 10);
- else
- return 80;
+ long int col = strtol (columns, NULL, 10);
+ if (0 < col)
+ return col;
}
- return ws.ws_col;
+
+ return 80;
}
static char *
return NULL;
}
+static int tty_cleanup;
-static void
-format_checkpoint_string (FILE *fp, const char *input, bool do_write,
+static const char *def_format =
+ "%{%Y-%m-%d %H:%M:%S}t: %ds, %{read,wrote}T%*\r";
+
+static int
+format_checkpoint_string (FILE *fp, size_t len,
+ const char *input, bool do_write,
unsigned cpn)
{
const char *opstr = do_write ? gettext ("write") : gettext ("read");
char uintbuf[UINTMAX_STRSIZE_BOUND];
char *cps = STRINGIFY_BIGINT (cpn, uintbuf);
const char *ip;
- size_t len = 0;
static char *argbuf = NULL;
static size_t arglen = 0;
char *arg = NULL;
-
+
if (!input)
{
if (do_write)
*not* "Leyendo un punto de comprobaci@'on" */
input = gettext ("Read checkpoint %u");
}
-
+
for (ip = input; *ip; ip++)
{
if (*ip == '%')
}
switch (*ip)
{
+ case 'c':
+ len += format_checkpoint_string (fp, len, def_format, do_write,
+ cpn);
+ break;
+
case 'u':
fputs (cps, fp);
len += strlen (cps);
case 'd':
len += fprintf (fp, "%.0f", compute_duration ());
break;
-
+
case 'T':
- compute_duration ();
- len += format_total_stats (fp, checkpoint_total_format, ',', 0);
+ {
+ const char **fmt = checkpoint_total_format, *fmtbuf[3];
+ struct wordsplit ws;
+ compute_duration ();
+
+ if (arg)
+ {
+ ws.ws_delim = ",";
+ if (wordsplit (arg, &ws, WRDSF_NOVAR | WRDSF_NOCMD |
+ WRDSF_QUOTE | WRDSF_DELIM))
+ ERROR ((0, 0, _("cannot split string '%s': %s"),
+ arg, wordsplit_strerror (&ws)));
+ else
+ {
+ int i;
+
+ for (i = 0; i < ws.ws_wordc; i++)
+ fmtbuf[i] = ws.ws_wordv[i];
+ for (; i < 3; i++)
+ fmtbuf[i] = NULL;
+ fmt = fmtbuf;
+ }
+ }
+ len += format_total_stats (fp, fmt, ',', 0);
+ if (arg)
+ wordsplit_free (&ws);
+ }
break;
case 't':
{
struct timeval tv;
struct tm *tm;
- char *fmt = arg ? arg : "%c";
+ const char *fmt = arg ? arg : "%c";
gettimeofday (&tv, NULL);
tm = localtime (&tv.tv_sec);
len += fprintftime (fp, fmt, tm, 0, tv.tv_usec * 1000);
}
break;
-
+
case '*':
{
- int w = arg ? strtoul (arg, NULL, 10) : getwidth (fp);
+ long w = arg ? strtol (arg, NULL, 10) : getwidth (fp);
for (; w > len; len++)
fputc (' ', fp);
}
break;
-
+
default:
fputc ('%', fp);
fputc (*ip, fp);
{
fputc (*ip, fp);
if (*ip == '\r')
- len = 0;
+ {
+ len = 0;
+ tty_cleanup = 1;
+ }
else
len++;
}
}
fflush (fp);
+ return len;
}
+static FILE *tty = NULL;
+
static void
run_checkpoint_actions (bool do_write)
{
struct checkpoint_action *p;
- FILE *tty = NULL;
for (p = checkpoint_action; p; p = p->next)
{
break;
case cop_echo:
- fprintf (stderr, "%s: ", program_name);
- format_checkpoint_string (stderr, p->v.command, do_write, checkpoint);
- fputc ('\n', stderr);
+ {
+ int n = fprintf (stderr, "%s: ", program_name);
+ format_checkpoint_string (stderr, n, p->v.command, do_write,
+ checkpoint);
+ fputc ('\n', stderr);
+ }
break;
case cop_ttyout:
if (!tty)
tty = fopen ("/dev/tty", "w");
if (tty)
- {
- format_checkpoint_string (tty, p->v.command, do_write,
- checkpoint);
- fflush (tty);
- }
+ format_checkpoint_string (tty, 0, p->v.command, do_write,
+ checkpoint);
break;
case cop_sleep:
print_total_stats ();
}
}
- if (tty)
- fclose (tty);
+}
+
+void
+checkpoint_flush_actions (void)
+{
+ struct checkpoint_action *p;
+
+ for (p = checkpoint_action; p; p = p->next)
+ {
+ switch (p->opcode)
+ {
+ case cop_ttyout:
+ if (tty && tty_cleanup)
+ {
+ long w = getwidth (tty);
+ while (w--)
+ fputc (' ', tty);
+ fputc ('\r', tty);
+ fflush (tty);
+ }
+ break;
+ default:
+ /* nothing */;
+ }
+ }
}
void
if (checkpoint_option && !(++checkpoint % checkpoint_option))
run_checkpoint_actions (do_write);
}
+
+void
+checkpoint_finish (void)
+{
+ if (checkpoint_option)
+ {
+ checkpoint_flush_actions ();
+ if (tty)
+ fclose (tty);
+ }
+}