]> git.cworth.org Git - tar/blob - src/checkpoint.c
Imported Upstream version 1.21
[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 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 }  
270