tape.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. #include "platform.h"
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6. #include "archive.h"
  7. #include "ccache.h"
  8. #include "hexify.h"
  9. #include "multitape.h"
  10. #include "bsdtar.h"
  11. /*
  12. * Delete a tape.
  13. */
  14. void
  15. tarsnap_mode_d(struct bsdtar *bsdtar)
  16. {
  17. TAPE_D * d;
  18. size_t i;
  19. /* Prepare for deletes. */
  20. if ((d = deletetape_init(bsdtar->machinenum)) == NULL)
  21. goto err1;
  22. /* Delete archives. */
  23. for (i = 0; i < bsdtar->ntapes; i++) {
  24. if (bsdtar->verbose)
  25. fprintf(stderr, "Deleting archive \"%s\"\n",
  26. bsdtar->tapenames[i]);
  27. switch (deletetape(d, bsdtar->machinenum, bsdtar->cachedir,
  28. bsdtar->tapenames[i], bsdtar->option_print_stats,
  29. bsdtar->ntapes > 1 ? 1 : 0, bsdtar->option_csv_filename,
  30. &bsdtar->storage_modified)) {
  31. case 0:
  32. break;
  33. case 1:
  34. if (bsdtar->option_keep_going)
  35. break;
  36. /* FALLTHROUGH */
  37. default:
  38. goto err2;
  39. }
  40. }
  41. /* We've finished deleting archives. */
  42. deletetape_free(d);
  43. /* Success! */
  44. return;
  45. err2:
  46. deletetape_free(d);
  47. err1:
  48. /* Failure! */
  49. bsdtar_warnc(bsdtar, 0, "Error deleting archive");
  50. bsdtar->return_value = 1;
  51. return;
  52. }
  53. /*
  54. * Read the tape and write to stdout.
  55. */
  56. void
  57. tarsnap_mode_r(struct bsdtar *bsdtar)
  58. {
  59. TAPE_R * d;
  60. const void * buf;
  61. ssize_t lenread;
  62. size_t writelen;
  63. /* Open the tape. */
  64. if ((d = readtape_open(bsdtar->machinenum,
  65. bsdtar->tapenames[0])) == NULL)
  66. goto err1;
  67. /* Loop until we have an error or EOF. */
  68. do {
  69. lenread = readtape_read(d, &buf);
  70. /* Error? */
  71. if (lenread < 0)
  72. goto err2;
  73. /* EOF? */
  74. if (lenread == 0)
  75. break;
  76. /* Output data to stdout. */
  77. writelen = (size_t)(lenread);
  78. if (fwrite(buf, 1, writelen, stdout) != writelen)
  79. goto err2;
  80. } while (1);
  81. /* We're done! Close the tape. */
  82. if (readtape_close(d))
  83. goto err1;
  84. /* Success! */
  85. return;
  86. err2:
  87. readtape_close(d);
  88. err1:
  89. /* Failure! */
  90. bsdtar_warnc(bsdtar, 0, "Error reading archive");
  91. bsdtar->return_value = 1;
  92. return;
  93. }
  94. /*
  95. * Print statistics relating to an archive or set of archives.
  96. */
  97. void
  98. tarsnap_mode_print_stats(struct bsdtar *bsdtar)
  99. {
  100. TAPE_S * d;
  101. size_t i;
  102. /* Open the archive set for statistics purposes. */
  103. if ((d = statstape_open(bsdtar->machinenum,
  104. bsdtar->cachedir)) == NULL)
  105. goto err1;
  106. /* Print statistics about the archive set. */
  107. if (statstape_printglobal(d, bsdtar->option_csv_filename))
  108. goto err2;
  109. if (bsdtar->ntapes == 0) {
  110. /* User only wanted global statistics. */
  111. } else if ((bsdtar->tapenames[0][0] == '*') &&
  112. (bsdtar->tapenames[0][1] == '\0')) {
  113. /* User wants statistics on all archives. */
  114. if (statstape_printall(d, bsdtar->option_csv_filename))
  115. goto err2;
  116. } else {
  117. /* User wants statistics about specific archive(s). */
  118. for (i = 0; i < bsdtar->ntapes; i++) {
  119. switch (statstape_print(d, bsdtar->tapenames[i],
  120. bsdtar->option_csv_filename)) {
  121. case 0:
  122. break;
  123. case 1:
  124. if (bsdtar->option_keep_going)
  125. break;
  126. /* FALLTHROUGH */
  127. default:
  128. goto err2;
  129. }
  130. }
  131. }
  132. /* We're done. Close the archive set. */
  133. if (statstape_close(d))
  134. goto err1;
  135. /* Success! */
  136. return;
  137. err2:
  138. statstape_close(d);
  139. err1:
  140. /* Failure! */
  141. bsdtar_warnc(bsdtar, 0, "Error generating archive statistics");
  142. bsdtar->return_value = 1;
  143. return;
  144. }
  145. /*
  146. * Print the names of all the archives.
  147. */
  148. void
  149. tarsnap_mode_list_archives(struct bsdtar *bsdtar, int print_hashes)
  150. {
  151. TAPE_S * d;
  152. uint8_t hash[32];
  153. size_t i;
  154. /* Sanity check. */
  155. if ((print_hashes == 0) && (bsdtar->ntapes > 0)) {
  156. bsdtar_warnc(bsdtar, 0, "--list-archives: can only use -f"
  157. " with --hashes");
  158. goto err1;
  159. }
  160. /* Open the archive set for statistics purposes. */
  161. if ((d = statstape_open(bsdtar->machinenum, NULL)) == NULL)
  162. goto err1;
  163. /* Ask for the list of archives to be printed. */
  164. if (bsdtar->ntapes == 0) {
  165. if (statstape_printlist(d, bsdtar->verbose, bsdtar->option_null,
  166. print_hashes))
  167. goto err2;
  168. } else {
  169. /* User wants metadata about specific archive(s). */
  170. for (i = 0; i < bsdtar->ntapes; i++) {
  171. /* Convert ascii hex to a hash. */
  172. if (unhexify(bsdtar->tapenames[i], hash, 32)) {
  173. bsdtar_warnc(bsdtar, 0,
  174. "Invalid archive hash: %s",
  175. bsdtar->tapenames[i]);
  176. goto err1;
  177. }
  178. /* Print desired metadata about the archive. */
  179. if (statstape_printlist_item(d, hash,
  180. bsdtar->verbose, bsdtar->option_null, 1))
  181. goto err2;
  182. }
  183. }
  184. /* We're done. Close the archive set. */
  185. if (statstape_close(d))
  186. goto err1;
  187. /* Success! */
  188. return;
  189. err2:
  190. statstape_close(d);
  191. err1:
  192. /* Failure! */
  193. bsdtar_warnc(bsdtar, 0, "Error listing archives");
  194. bsdtar->return_value = 1;
  195. return;
  196. }
  197. /*
  198. * Archive set consistency check and repair.
  199. */
  200. void
  201. tarsnap_mode_fsck(struct bsdtar *bsdtar, int prune, int whichkey)
  202. {
  203. if (fscktape(bsdtar->machinenum, bsdtar->cachedir, prune, whichkey,
  204. &bsdtar->storage_modified)) {
  205. bsdtar_warnc(bsdtar, 0, "Error fscking archives");
  206. goto err0;
  207. }
  208. /*
  209. * Remove the chunkification cache in case whatever caused the fsck to
  210. * be necessary (e.g., disk corruption) also damaged that cache. The
  211. * chunkification cache is purely a performance optimization; since
  212. * we're dealing with backups here it makes sense to sacrifice some
  213. * performance to prevent possible data loss.
  214. */
  215. if (ccache_remove(bsdtar->cachedir)) {
  216. bsdtar_warnc(bsdtar, 0, "Error removing chunkification cache");
  217. goto err0;
  218. }
  219. /* Success! */
  220. return;
  221. err0:
  222. /* Failure! */
  223. bsdtar->return_value = 1;
  224. return;
  225. }
  226. /*
  227. * Initialize cache directory.
  228. */
  229. void
  230. tarsnap_mode_initialize_cachedir(struct bsdtar *bsdtar)
  231. {
  232. switch (statstape_initialize(bsdtar->machinenum, bsdtar->cachedir)) {
  233. case 0:
  234. break;
  235. case 1:
  236. bsdtar_warnc(bsdtar, 0, "Cache directory already initialized");
  237. /* FALLTHROUGH */
  238. default:
  239. goto err0;
  240. }
  241. /* Success! */
  242. return;
  243. err0:
  244. /* Failure! */
  245. bsdtar->return_value = 1;
  246. return;
  247. }
  248. /*
  249. * Nuke all the files belonging to an archive set.
  250. */
  251. void
  252. tarsnap_mode_nuke(struct bsdtar *bsdtar)
  253. {
  254. char s[100];
  255. /* Safeguard against being called accidentally. */
  256. fprintf(stderr, "Please type 'No Tomorrow' to continue\n");
  257. if (fgets(s, 100, stdin) == NULL) {
  258. bsdtar_warnc(bsdtar, 0,
  259. "Error reading string from standard input");
  260. goto err0;
  261. }
  262. if (strcmp(s, "No Tomorrow\n")) {
  263. bsdtar_warnc(bsdtar, 0, "You didn't type 'No Tomorrow'");
  264. goto err0;
  265. }
  266. if (nuketape(bsdtar->machinenum, &bsdtar->storage_modified)) {
  267. bsdtar_warnc(bsdtar, 0, "Error nuking archives");
  268. goto err0;
  269. }
  270. /* Success! */
  271. return;
  272. err0:
  273. /* Failure! */
  274. bsdtar->return_value = 1;
  275. return;
  276. }
  277. /*
  278. * Recover an interrupted archive if one exists.
  279. */
  280. void
  281. tarsnap_mode_recover(struct bsdtar *bsdtar, int whichkey)
  282. {
  283. if (recovertape(bsdtar->machinenum, bsdtar->cachedir, whichkey,
  284. &bsdtar->storage_modified))
  285. goto err1;
  286. /* Success! */
  287. return;
  288. err1:
  289. /* Failure! */
  290. bsdtar_warnc(bsdtar, 0, "Error recovering archive");
  291. bsdtar->return_value = 1;
  292. return;
  293. }