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