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