siginfo.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /*-
  2. * Copyright 2008 Colin Percival
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
  15. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  16. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  17. * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
  18. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  19. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  20. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  21. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  23. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. #include "bsdtar_platform.h"
  26. __FBSDID("$FreeBSD: src/usr.bin/tar/siginfo.c,v 1.2 2008/05/22 21:08:36 cperciva Exp $");
  27. #include <assert.h>
  28. #include <errno.h>
  29. #include <inttypes.h>
  30. #include <signal.h>
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34. #include "bsdtar.h"
  35. #include "humansize.h"
  36. #include "tarsnap_opt.h"
  37. /* Is there a pending SIGINFO or SIGUSR1? */
  38. static volatile sig_atomic_t siginfo_received = 0;
  39. struct siginfo_data {
  40. /* What sort of operation are we doing? */
  41. char * oper;
  42. /* What path are we handling? */
  43. char * path;
  44. /* How large is the archive entry? */
  45. int64_t size;
  46. /* How many filesystem entries have we handled in total? */
  47. int file_count;
  48. /* How many bytes have we handled in total? */
  49. uint64_t total_uncompressed;
  50. /* When did we last print a progress message? */
  51. uint64_t lastprogress;
  52. /* Old signal handlers. */
  53. #ifdef SIGINFO
  54. struct sigaction siginfo_old;
  55. #endif
  56. #ifdef SIGUSR1
  57. struct sigaction sigusr1_old;
  58. #endif
  59. };
  60. static void siginfo_handler(int sig);
  61. /* Handler for SIGINFO / SIGUSR1. */
  62. static void
  63. siginfo_handler(int sig)
  64. {
  65. (void)sig; /* UNUSED */
  66. /* Record that SIGINFO or SIGUSR1 has been received. */
  67. siginfo_received = 1;
  68. }
  69. void
  70. siginfo_init(struct bsdtar *bsdtar)
  71. {
  72. struct siginfo_data * siginfo;
  73. struct sigaction sa;
  74. /* Allocate space for internal structure. */
  75. if ((siginfo = malloc(sizeof(struct siginfo_data))) == NULL)
  76. bsdtar_errc(bsdtar, 1, errno, "malloc failed");
  77. bsdtar->siginfo = siginfo;
  78. /* Initialize numeric variables of siginfo. */
  79. memset(siginfo, 0, sizeof(struct siginfo_data));
  80. /* Set the strings to NULL so that free() is safe. */
  81. siginfo->path = siginfo->oper = NULL;
  82. /* We want to catch SIGINFO, if it exists. */
  83. sa.sa_handler = siginfo_handler;
  84. sigemptyset(&sa.sa_mask);
  85. sa.sa_flags = 0;
  86. #ifdef SIGINFO
  87. if (sigaction(SIGINFO, &sa, &siginfo->siginfo_old))
  88. bsdtar_errc(bsdtar, 1, errno, "sigaction(SIGINFO) failed");
  89. #endif
  90. #ifdef SIGUSR1
  91. /* ... and treat SIGUSR1 the same way as SIGINFO. */
  92. if (sigaction(SIGUSR1, &sa, &siginfo->sigusr1_old))
  93. bsdtar_errc(bsdtar, 1, errno, "sigaction(SIGUSR1) failed");
  94. #endif
  95. }
  96. void
  97. siginfo_setinfo(struct bsdtar *bsdtar, const char * oper, const char * path,
  98. int64_t size, int file_count, int64_t archive_uncompressed)
  99. {
  100. struct siginfo_data * siginfo = bsdtar->siginfo;
  101. /* Sanity check. */
  102. assert(archive_uncompressed >= 0);
  103. /* Free old operation and path strings. */
  104. free(siginfo->oper);
  105. free(siginfo->path);
  106. /* Duplicate strings and store entry size. */
  107. if (oper != NULL) {
  108. if ((siginfo->oper = strdup(oper)) == NULL)
  109. bsdtar_errc(bsdtar, 1, errno, "Cannot strdup");
  110. } else
  111. siginfo->oper = NULL;
  112. if (path != NULL) {
  113. if ((siginfo->path = strdup(path)) == NULL)
  114. bsdtar_errc(bsdtar, 1, errno, "Cannot strdup");
  115. } else
  116. siginfo->path = NULL;
  117. siginfo->size = size;
  118. siginfo->file_count = file_count;
  119. siginfo->total_uncompressed = (uint64_t)archive_uncompressed;
  120. /*
  121. * Look at how many bytes on disk have been processed since the last
  122. * update, and trigger a siginfo_printinfo() if desired.
  123. */
  124. if (bsdtar->option_progress_bytes != 0) {
  125. if (siginfo->total_uncompressed >
  126. siginfo->lastprogress + bsdtar->option_progress_bytes) {
  127. siginfo->lastprogress = siginfo->total_uncompressed;
  128. /* Fake a SIGINFO (no need for an actual signal). */
  129. siginfo_received = 1;
  130. }
  131. }
  132. }
  133. void
  134. siginfo_printinfo(struct bsdtar *bsdtar, off_t progress, int finalmsg)
  135. {
  136. struct siginfo_data * siginfo = bsdtar->siginfo;
  137. char * s_progress;
  138. char * s_size;
  139. char * s_total_uncompressed;
  140. /* Sanity check. */
  141. assert(progress >= 0);
  142. /* Quit if there's no signal to handle. */
  143. if (!siginfo_received)
  144. return;
  145. /* Print overall progress (if applicable). */
  146. if (siginfo->total_uncompressed > 0) {
  147. /* --verbose mode doesn't print newlines at the end of lines. */
  148. if (bsdtar->verbose && !finalmsg)
  149. fprintf(stderr, "\n");
  150. /* Print overall progress with or without --humanize-numbers. */
  151. if (tarsnap_opt_humanize_numbers) {
  152. if ((s_total_uncompressed = humansize(
  153. siginfo->total_uncompressed)) == NULL)
  154. goto err0;
  155. safe_fprintf(stderr, "Processed %d entries, %s",
  156. siginfo->file_count, s_total_uncompressed);
  157. /* Clean up. */
  158. free(s_total_uncompressed);
  159. } else {
  160. safe_fprintf(stderr,
  161. "Processed %d entries, %" PRId64 " bytes",
  162. siginfo->file_count, siginfo->total_uncompressed);
  163. }
  164. /* --verbose mode doesn't want newlines at the end of lines. */
  165. if (!bsdtar->verbose || finalmsg)
  166. fprintf(stderr, "\n");
  167. /* We've handled the signal. */
  168. siginfo_received = 0;
  169. }
  170. /* Print info about current file (if applicable). */
  171. if ((siginfo->path != NULL) && (siginfo->oper != NULL)) {
  172. /* --verbose mode doesn't print newlines at the end of lines. */
  173. if (bsdtar->verbose)
  174. fprintf(stderr, "\n");
  175. /* Print current operation and filename. */
  176. safe_fprintf(stderr, "%s %s", siginfo->oper, siginfo->path);
  177. /* Print progress on current file (if applicable). */
  178. if (siginfo->size > 0) {
  179. if (tarsnap_opt_humanize_numbers) {
  180. if ((s_progress = humansize((uint64_t)progress))
  181. == NULL)
  182. goto err0;
  183. if ((s_size = humansize(
  184. (uint64_t)siginfo->size)) == NULL)
  185. goto err1;
  186. safe_fprintf(stderr, " (%s / %s bytes)",
  187. s_progress, s_size);
  188. /* Clean up. */
  189. free(s_progress);
  190. free(s_size);
  191. } else {
  192. safe_fprintf(stderr, " (%ju / %" PRId64
  193. " bytes)", (uintmax_t)progress,
  194. siginfo->size);
  195. }
  196. }
  197. /* --verbose mode doesn't want newlines at the end of lines. */
  198. if (!bsdtar->verbose)
  199. fprintf(stderr, "\n");
  200. /* We've handled the signal. */
  201. siginfo_received = 0;
  202. }
  203. /* Success! */
  204. return;
  205. err1:
  206. free(s_progress);
  207. err0:
  208. /* Failure! */
  209. bsdtar_errc(bsdtar, 1, ENOMEM, "Cannot allocate memory");
  210. }
  211. void
  212. siginfo_done(struct bsdtar *bsdtar)
  213. {
  214. struct siginfo_data * siginfo = bsdtar->siginfo;
  215. #ifdef SIGINFO
  216. /* Restore old SIGINFO handler. */
  217. sigaction(SIGINFO, &siginfo->siginfo_old, NULL);
  218. #endif
  219. #ifdef SIGUSR1
  220. /* And the old SIGUSR1 handler, too. */
  221. sigaction(SIGUSR1, &siginfo->sigusr1_old, NULL);
  222. #endif
  223. /* Free strings. */
  224. free(siginfo->path);
  225. free(siginfo->oper);
  226. /* Free internal data structure. */
  227. free(siginfo);
  228. }