checkpoint.c 5.9 KB

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