1 /* Checkpoint management for tar.
3 Copyright 2007, 2013-2014 Free Software Foundation, Inc.
5 This file is part of GNU tar.
7 GNU tar is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 GNU tar is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
22 #include "wordsplit.h"
23 #include <sys/ioctl.h>
25 #include "fprintftime.h"
27 enum checkpoint_opcode
38 struct checkpoint_action
40 struct checkpoint_action *next;
41 enum checkpoint_opcode opcode;
49 /* Checkpointing counter */
50 static unsigned checkpoint;
52 /* List of checkpoint actions */
53 static struct checkpoint_action *checkpoint_action, *checkpoint_action_tail;
55 static struct checkpoint_action *
56 alloc_action (enum checkpoint_opcode opcode)
58 struct checkpoint_action *p = xzalloc (sizeof *p);
59 if (checkpoint_action_tail)
60 checkpoint_action_tail->next = p;
62 checkpoint_action = p;
63 checkpoint_action_tail = p;
69 copy_string_unquote (const char *str)
71 char *output = xstrdup (str);
72 size_t len = strlen (output);
73 if ((*output == '"' || *output == '\'')
74 && output[len-1] == *output)
76 memmove (output, output+1, len-2);
79 unquote_string (output);
84 checkpoint_compile_action (const char *str)
86 struct checkpoint_action *act;
88 if (strcmp (str, ".") == 0 || strcmp (str, "dot") == 0)
89 alloc_action (cop_dot);
90 else if (strcmp (str, "bell") == 0)
91 alloc_action (cop_bell);
92 else if (strcmp (str, "echo") == 0)
93 alloc_action (cop_echo);
94 else if (strncmp (str, "echo=", 5) == 0)
96 act = alloc_action (cop_echo);
97 act->v.command = copy_string_unquote (str + 5);
99 else if (strncmp (str, "exec=", 5) == 0)
101 act = alloc_action (cop_exec);
102 act->v.command = copy_string_unquote (str + 5);
104 else if (strncmp (str, "ttyout=", 7) == 0)
106 act = alloc_action (cop_ttyout);
107 act->v.command = copy_string_unquote (str + 7);
109 else if (strncmp (str, "sleep=", 6) == 0)
112 time_t n = strtoul (str+6, &p, 10);
114 FATAL_ERROR ((0, 0, _("%s: not a valid timeout"), str));
115 act = alloc_action (cop_sleep);
118 else if (strcmp (str, "totals") == 0)
119 alloc_action (cop_totals);
121 FATAL_ERROR ((0, 0, _("%s: unknown checkpoint action"), str));
125 checkpoint_finish_compile (void)
127 if (checkpoint_option)
129 if (!checkpoint_action)
130 /* Provide a historical default */
131 checkpoint_compile_action ("echo");
133 else if (checkpoint_action)
134 /* Otherwise, set default checkpoint rate */
135 checkpoint_option = DEFAULT_CHECKPOINT;
138 static const char *checkpoint_total_format[] = {
151 if (ioctl (fileno (fp), TIOCGWINSZ, &ws) == 0 && 0 < ws.ws_col)
155 columns = getenv ("COLUMNS");
158 long int col = strtol (columns, NULL, 10);
167 getarg (const char *input, const char ** endp, char **argbuf, size_t *arglen)
171 char *p = strchr (input + 1, '}');
174 size_t n = p - input;
178 *argbuf = xrealloc (*argbuf, *arglen);
181 memcpy (*argbuf, input + 1, n);
192 static int tty_cleanup;
194 static const char *def_format =
195 "%{%Y-%m-%d %H:%M:%S}t: %ds, %{read,wrote}T%*\r";
198 format_checkpoint_string (FILE *fp, size_t len,
199 const char *input, bool do_write,
202 const char *opstr = do_write ? gettext ("write") : gettext ("read");
203 char uintbuf[UINTMAX_STRSIZE_BOUND];
204 char *cps = STRINGIFY_BIGINT (cpn, uintbuf);
207 static char *argbuf = NULL;
208 static size_t arglen = 0;
214 /* TRANSLATORS: This is a "checkpoint of write operation",
215 *not* "Writing a checkpoint".
216 E.g. in Spanish "Punto de comprobaci@'on de escritura",
217 *not* "Escribiendo un punto de comprobaci@'on" */
218 input = gettext ("Write checkpoint %u");
220 /* TRANSLATORS: This is a "checkpoint of read operation",
221 *not* "Reading a checkpoint".
222 E.g. in Spanish "Punto de comprobaci@'on de lectura",
223 *not* "Leyendo un punto de comprobaci@'on" */
224 input = gettext ("Read checkpoint %u");
227 for (ip = input; *ip; ip++)
233 arg = getarg (ip, &ip, &argbuf, &arglen);
245 len += format_checkpoint_string (fp, len, def_format, do_write,
256 len += strlen (opstr);
260 len += fprintf (fp, "%.0f", compute_duration ());
265 const char **fmt = checkpoint_total_format, *fmtbuf[3];
272 if (wordsplit (arg, &ws, WRDSF_NOVAR | WRDSF_NOCMD |
273 WRDSF_QUOTE | WRDSF_DELIM))
274 ERROR ((0, 0, _("cannot split string '%s': %s"),
275 arg, wordsplit_strerror (&ws)));
280 for (i = 0; i < ws.ws_wordc; i++)
281 fmtbuf[i] = ws.ws_wordv[i];
287 len += format_total_stats (fp, fmt, ',', 0);
289 wordsplit_free (&ws);
297 const char *fmt = arg ? arg : "%c";
299 gettimeofday (&tv, NULL);
300 tm = localtime (&tv.tv_sec);
301 len += fprintftime (fp, fmt, tm, 0, tv.tv_usec * 1000);
307 long w = arg ? strtol (arg, NULL, 10) : getwidth (fp);
308 for (; w > len; len++)
337 static FILE *tty = NULL;
340 run_checkpoint_actions (bool do_write)
342 struct checkpoint_action *p;
344 for (p = checkpoint_action; p; p = p->next)
355 tty = fopen ("/dev/tty", "w");
365 int n = fprintf (stderr, "%s: ", program_name);
366 format_checkpoint_string (stderr, n, p->v.command, do_write,
368 fputc ('\n', stderr);
374 tty = fopen ("/dev/tty", "w");
376 format_checkpoint_string (tty, 0, p->v.command, do_write,
385 sys_exec_checkpoint_script (p->v.command,
386 archive_name_cursor[0],
392 print_total_stats ();
398 checkpoint_flush_actions (void)
400 struct checkpoint_action *p;
402 for (p = checkpoint_action; p; p = p->next)
407 if (tty && tty_cleanup)
409 long w = getwidth (tty);
423 checkpoint_run (bool do_write)
425 if (checkpoint_option && !(++checkpoint % checkpoint_option))
426 run_checkpoint_actions (do_write);
430 checkpoint_finish (void)
432 if (checkpoint_option)
434 checkpoint_flush_actions ();