]> Dogcows Code - chaz/tar/blob - src/checkpoint.c
Revamp initial name collection functions to ensure proper argument ordering.
[chaz/tar] / src / checkpoint.c
1 /* Checkpoint management for tar.
2
3 Copyright 2007, 2013 Free Software Foundation, Inc.
4
5 This file is part of GNU tar.
6
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.
11
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.
16
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/>. */
19
20 #include <system.h>
21 #include "common.h"
22
23 enum checkpoint_opcode
24 {
25 cop_dot,
26 cop_bell,
27 cop_echo,
28 cop_ttyout,
29 cop_sleep,
30 cop_exec
31 };
32
33 struct checkpoint_action
34 {
35 struct checkpoint_action *next;
36 enum checkpoint_opcode opcode;
37 union
38 {
39 time_t time;
40 char *command;
41 } v;
42 };
43
44 /* Checkpointing counter */
45 static unsigned checkpoint;
46
47 /* List of checkpoint actions */
48 static struct checkpoint_action *checkpoint_action, *checkpoint_action_tail;
49
50 static struct checkpoint_action *
51 alloc_action (enum checkpoint_opcode opcode)
52 {
53 struct checkpoint_action *p = xzalloc (sizeof *p);
54 if (checkpoint_action_tail)
55 checkpoint_action_tail->next = p;
56 else
57 checkpoint_action = p;
58 checkpoint_action_tail = p;
59 p->opcode = opcode;
60 return p;
61 }
62
63 static char *
64 copy_string_unquote (const char *str)
65 {
66 char *output = xstrdup (str);
67 size_t len = strlen (output);
68 if ((*output == '"' || *output == '\'')
69 && output[len-1] == *output)
70 {
71 memmove (output, output+1, len-2);
72 output[len-2] = 0;
73 }
74 unquote_string (output);
75 return output;
76 }
77
78 void
79 checkpoint_compile_action (const char *str)
80 {
81 struct checkpoint_action *act;
82
83 if (strcmp (str, ".") == 0 || strcmp (str, "dot") == 0)
84 alloc_action (cop_dot);
85 else if (strcmp (str, "bell") == 0)
86 alloc_action (cop_bell);
87 else if (strcmp (str, "echo") == 0)
88 alloc_action (cop_echo);
89 else if (strncmp (str, "echo=", 5) == 0)
90 {
91 act = alloc_action (cop_echo);
92 act->v.command = copy_string_unquote (str + 5);
93 }
94 else if (strncmp (str, "exec=", 5) == 0)
95 {
96 act = alloc_action (cop_exec);
97 act->v.command = copy_string_unquote (str + 5);
98 }
99 else if (strncmp (str, "ttyout=", 7) == 0)
100 {
101 act = alloc_action (cop_ttyout);
102 act->v.command = copy_string_unquote (str + 7);
103 }
104 else if (strncmp (str, "sleep=", 6) == 0)
105 {
106 char *p;
107 time_t n = strtoul (str+6, &p, 10);
108 if (*p)
109 FATAL_ERROR ((0, 0, _("%s: not a valid timeout"), str));
110 act = alloc_action (cop_sleep);
111 act->v.time = n;
112 }
113 else
114 FATAL_ERROR ((0, 0, _("%s: unknown checkpoint action"), str));
115 }
116
117 void
118 checkpoint_finish_compile (void)
119 {
120 if (checkpoint_option)
121 {
122 if (!checkpoint_action)
123 /* Provide a historical default */
124 checkpoint_compile_action ("echo");
125 }
126 else if (checkpoint_action)
127 /* Otherwise, set default checkpoint rate */
128 checkpoint_option = DEFAULT_CHECKPOINT;
129 }
130
131 static char *
132 expand_checkpoint_string (const char *input, bool do_write, unsigned cpn)
133 {
134 const char *opstr = do_write ? gettext ("write") : gettext ("read");
135 size_t opstrlen = strlen (opstr);
136 char uintbuf[UINTMAX_STRSIZE_BOUND];
137 char *cps = STRINGIFY_BIGINT (cpn, uintbuf);
138 size_t cpslen = strlen (cps);
139 const char *ip;
140 char *op;
141 char *output;
142 size_t outlen = strlen (input); /* Initial guess */
143
144 /* Fix the initial length guess */
145 for (ip = input; (ip = strchr (ip, '%')) != NULL; )
146 {
147 switch (ip[1])
148 {
149 case 'u':
150 outlen += cpslen - 2;
151 break;
152
153 case 's':
154 outlen += opstrlen - 2;
155 }
156 ip++;
157 }
158
159 output = xmalloc (outlen + 1);
160 for (ip = input, op = output; *ip; )
161 {
162 if (*ip == '%')
163 {
164 switch (*++ip)
165 {
166 case 'u':
167 op = stpcpy (op, cps);
168 break;
169
170 case 's':
171 op = stpcpy (op, opstr);
172 break;
173
174 default:
175 *op++ = '%';
176 *op++ = *ip;
177 break;
178 }
179 ip++;
180 }
181 else
182 *op++ = *ip++;
183 }
184 *op = 0;
185 return output;
186 }
187
188 static void
189 run_checkpoint_actions (bool do_write)
190 {
191 struct checkpoint_action *p;
192 FILE *tty = NULL;
193
194 for (p = checkpoint_action; p; p = p->next)
195 {
196 switch (p->opcode)
197 {
198 case cop_dot:
199 fputc ('.', stdlis);
200 fflush (stdlis);
201 break;
202
203 case cop_bell:
204 if (!tty)
205 tty = fopen ("/dev/tty", "w");
206 if (tty)
207 {
208 fputc ('\a', tty);
209 fflush (tty);
210 }
211 break;
212
213 case cop_echo:
214 {
215 char *tmp;
216 const char *str = p->v.command;
217 if (!str)
218 {
219 if (do_write)
220 /* TRANSLATORS: This is a "checkpoint of write operation",
221 *not* "Writing a checkpoint".
222 E.g. in Spanish "Punto de comprobaci@'on de escritura",
223 *not* "Escribiendo un punto de comprobaci@'on" */
224 str = gettext ("Write checkpoint %u");
225 else
226 /* TRANSLATORS: This is a "checkpoint of read operation",
227 *not* "Reading a checkpoint".
228 E.g. in Spanish "Punto de comprobaci@'on de lectura",
229 *not* "Leyendo un punto de comprobaci@'on" */
230 str = gettext ("Read checkpoint %u");
231 }
232 tmp = expand_checkpoint_string (str, do_write, checkpoint);
233 WARN ((0, 0, "%s", tmp));
234 free (tmp);
235 }
236 break;
237
238 case cop_ttyout:
239 if (!tty)
240 tty = fopen ("/dev/tty", "w");
241 if (tty)
242 {
243 char *tmp = expand_checkpoint_string (p->v.command, do_write,
244 checkpoint);
245 fprintf (tty, "%s", tmp);
246 fflush (tty);
247 free (tmp);
248 }
249 break;
250
251 case cop_sleep:
252 sleep (p->v.time);
253 break;
254
255 case cop_exec:
256 sys_exec_checkpoint_script (p->v.command,
257 archive_name_cursor[0],
258 checkpoint);
259 break;
260 }
261 }
262 if (tty)
263 fclose (tty);
264 }
265
266 void
267 checkpoint_run (bool do_write)
268 {
269 if (checkpoint_option && !(++checkpoint % checkpoint_option))
270 run_checkpoint_actions (do_write);
271 }
This page took 0.043674 seconds and 4 git commands to generate.