checkpoint.c 6.0 KB

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