source: MondoRescue/branches/3.3/mondo/src/common/libmondo-stream.c@ 3876

Last change on this file since 3876 was 3872, checked in by Bruno Cornec, 4 months ago

Rewrite find_dvd_device

  • Property svn:keywords set to Id
File size: 48.5 KB
RevLine 
[1]1/* libmondo-stream.c
[128]2 $Id: libmondo-stream.c 3872 2024-03-07 18:00:38Z bruno $
[1]3
4...tools for talking to tapes, Monitas streams, etc.
5
6*/
7
8
9/**
10 * @file
11 * Functions for writing data to/reading data from streams (tape, CD stream, etc.)
12 */
13
14#include "my-stuff.h"
[2211]15#include "mr_mem.h"
[3613]16#include "mr_file.h"
[1]17#include "mondostructures.h"
[3870]18
[1]19#include "libmondo-string-EXT.h"
20#include "libmondo-files-EXT.h"
[541]21#include "libmondo-gui-EXT.h"
[1]22#include "libmondo-fork-EXT.h"
23#include "libmondo-tools-EXT.h"
24#include "libmondo-fifo-EXT.h"
25
26#define EXTRA_TAPE_CHECKSUMS
[1934]27#define STR_HEADER "Mondolicious, baby"
[1]28
29/*@unused@*/
[128]30//static char cvsid[] = "$Id: libmondo-stream.c 3872 2024-03-07 18:00:38Z bruno $";
[1]31extern bool g_sigpipe;
32extern int g_tape_buffer_size_MB;
33
[948]34extern char *g_getfacl;
35extern char *g_getfattr;
[1316]36extern char *MONDO_LOGFILE;
[948]37
[1645]38/* Reference to global bkpinfo */
39extern struct s_bkpinfo *bkpinfo;
40
[1]41/**
42 * @addtogroup globalGroup
43 * @{
44 */
45/**
46 * The file pointer for the opened tape/CD stream.
47 * Opened and closed by openin_tape(), openin_cdstream(),
48 * openout_tape(), openout_cdstream(), closein_tape(), closein_cdstream(),
49 * closeout_tape(), and closeout_cdstream().
50 */
51FILE *g_tape_stream = NULL;
52
53
54/**
55 * The position (in kilobytes) where we are on the tape.
56 */
57long long g_tape_posK = 0;
58
59/**
60 * The current media number we're using. This value is 1-based.
61 */
[128]62int g_current_media_number = -1;
[1]63
64/**
65 * The tape catalog that keeps track of files written to tape.
66 */
67struct s_tapecatalog *g_tapecatalog;
68
69/* @} - end of globalGroup */
70
[1645]71int write_backcatalog_to_tape();
[1]72
73
74
75
76
77/**
78 * @addtogroup streamGroup
79 * @{
80 */
81/**
82 * Close the global output file descriptor which Mondo has used to read
83 * from the CD stream.
84 * @param bkpinfo The backup information structure. Passed directly to closein_tape().
85 * @return 0 for success, nonzero for failure.
86 * @note This should be called by restore processes only.
87 */
[1645]88int closein_cdstream()
[1]89{
[1645]90 return (closein_tape());
[1]91}
92
[3860]93/**
94 * Write a header block to the opened stream (CD or tape).
95 * @param length_of_incoming_file The length to store in the header block.
96 * Usually matters only if this is a file-related header, in which case it should
97 * be the length of the file that will follow.
98 * @param filename The filename to store in the header block. Usually matters
99 * only if this is a file-related header, in which case this should be the name
100 * if the file that will follow.
101 * @param control_char The type of header block this is (start-file, end-file, start-tape, ...)
102 * @return 0 for success, nonzero for failure.
103 */
104int write_header_block_to_stream(off_t length_of_incoming_file, const char *filename, int control_char)
105{
106 /*@ buffers **************************************************** */
107 char tempblock[TAPE_BLOCK_SIZE];
108 char *p;
109 char *tmp = NULL;
[1]110
[3860]111 /*@ int ******************************************************** */
112 int i;
113
114 off_t olen;
115
116 /*@ end vars *************************************************** */
117
118 olen = length_of_incoming_file;
119 p = strrchr(filename, '/'); /* Make 'em go, "Unnnh!" Oh wait, that was _Master_ P... */
120 if (!p) {
121 p = filename;
122 } else {
123 p++;
124 }
125 if (!g_tape_stream) {
126 log_to_screen("You're not backing up to tape. Why write a tape header?");
127 return (1);
128 }
129 for (i = 0; i < (int) TAPE_BLOCK_SIZE; i++) {
130 tempblock[i] = 0;
131 }
132 sprintf(tempblock + 6000 + control_char, STR_HEADER);
133 tempblock[7000] = control_char;
134 if (length_of_incoming_file > 0) {
135 memcpy(tempblock + 7001, (char *) &olen, sizeof(off_t));
136 }
137 strcpy(tempblock + 1000, filename);
138 g_tape_posK += fwrite(tempblock, 1, (size_t) TAPE_BLOCK_SIZE, g_tape_stream) / 1024;
139 tmp = marker_to_string(control_char);
140 log_msg(6, "%s (fname=%s, size=%ld K)", tmp, p, (long) length_of_incoming_file >> 10);
141 mr_free(tmp);
142 return (0);
143}
144
145
[1]146/**
147 * Close the global output file descriptor which Mondo has used to read
148 * from buffer or dd, which read from the tape.
149 * @param bkpinfo The backup information structure. Unused.
150 * @return 0 for success, nonzero for failure.
151 * @note This should be called by restore processes only.
152 * @note This function also works for cdstreams for now, but don't count on this behavior.
153 * @bug @p bkpinfo parameter is unused.
154 */
[1645]155int closein_tape()
[1]156{
[128]157 /*@ int's ******************************************************* */
158 int retval = 0;
159 int res = 0;
160 int ctrl_chr = '\0';
[1]161
[128]162 /*@ buffers ***************************************************** */
163 char fname[MAX_STR_LEN];
[1]164
[128]165 /*@ long long's ************************************************* */
166 long long size;
167 char *blk;
168 int i;
[3060]169 int j;
[1]170
[128]171 blk = (char *) malloc(256 * 1024);
[1]172
[128]173 log_it("closein_tape() -- entering");
174 res = read_header_block_from_stream(&size, fname, &ctrl_chr);
175 retval += res;
176 if (ctrl_chr != BLK_END_OF_BACKUP) {
177 wrong_marker(BLK_END_OF_BACKUP, ctrl_chr);
178 }
179 res = read_header_block_from_stream(&size, fname, &ctrl_chr);
180 retval += res;
181 if (ctrl_chr != BLK_END_OF_TAPE) {
182 wrong_marker(BLK_END_OF_TAPE, ctrl_chr);
183 }
184 for (i = 0; i < 8 && !feof(g_tape_stream); i++) {
[3060]185 j = fread(blk, 1, 256 * 1024, g_tape_stream);
186 if (j) {
187 // FIXME
188 }
[128]189 }
190 sleep(1);
[3191]191 sync();
[128]192 sleep(1);
193 paranoid_pclose(g_tape_stream);
194 log_it("closein_tape() -- leaving");
195 if (!bkpinfo->please_dont_eject) {
196 eject_device(bkpinfo->media_device);
197 }
198 paranoid_free(blk);
199 paranoid_free(g_tapecatalog);
200 return (retval);
[1]201}
202
203
204
205/**
206 * Close the global output file descriptor which Mondo has been using to write
207 * to the tape device (via buffer or dd).
208 * @param bkpinfo The backup information structure. @c bkpinfo->media_size is the only field used.
209 * @return 0 for success, nonzero for failure.
210 * @note This should be called by backup processes only.
211 */
[1645]212int closeout_tape()
[1]213{
[128]214 /*@ int's ******************************************************* */
215 int retval = 0;
[1]216// int res = 0;
217// int ctrl_chr = '\0';
218
[128]219 /*@ buffers ***************************************************** */
[1]220// char fname[MAX_STR_LEN];
221
[128]222 /*@ long long's ************************************************* */
[1]223// long long size;
[128]224 int i;
225 char *blk;
[1]226
[128]227 blk = (char *) malloc(256 * 1024);
[1]228
[128]229 sleep(1);
[3191]230 sync();
[128]231 sleep(1);
232 log_it("closeout_tape() -- entering");
233 retval +=
[684]234 write_header_block_to_stream((off_t)0, "end-of-backup",
[128]235 BLK_END_OF_BACKUP);
[684]236 retval += write_header_block_to_stream((off_t)0, "end-of-tape", BLK_END_OF_TAPE); /* just in case */
[1]237/* write 1MB of crap */
[128]238 for (i = 0; i < 256 * 1024; i++) {
239 blk[i] = (int) (random() & 0xFF);
240 }
241 for (i = 0; i < 4 * 8; i++) {
[3060]242 if (fwrite(blk, 1, 256 * 1024, g_tape_stream)) {
243 //FIXME
244 }
[128]245 if (should_we_write_to_next_tape
[3150]246 (bkpinfo->media_size, (off_t)256 * 1024)) {
[1645]247 start_to_write_to_next_tape();
[128]248 }
249 }
[1]250/* write 1MB of zeroes */
251/*
252 for (i = 0; i < 256*1024; i++)
253 {
254 blk[i] = 0;
255 }
256 for (i = 0; i < 4; i++)
257 {
258 fwrite (blk, 1, 256*1024, g_tape_stream);
[3150]259 if (should_we_write_to_next_tape (bkpinfo->media_size, 256*1024))
[1]260 {
[1645]261 start_to_write_to_next_tape ();
[1]262 }
263 }
264*/
[128]265 sleep(2);
266 paranoid_pclose(g_tape_stream);
267 log_it("closeout_tape() -- leaving");
268 for (i = 0; i < g_tapecatalog->entries; i++) {
269 log_it("i=%d type=%s num=%d aux=%ld posK=%lld", i,
270 (g_tapecatalog->el[i].type ==
271 fileset) ? "fileset" : "bigslice",
272 g_tapecatalog->el[i].number, g_tapecatalog->el[i].aux,
273 g_tapecatalog->el[i].tape_posK);
274 }
275 paranoid_free(blk);
276 paranoid_free(g_tapecatalog);
277 return (retval);
[1]278}
279
280
281
[128]282bool mt_says_tape_exists(char *dev)
[1]283{
[2520]284 char *command = NULL;
[128]285 int res;
[1]286
[3185]287 mr_asprintf(command, "mt -f %s status", dev);
[128]288 res = run_program_and_log_output(command, 1);
[2520]289 mr_free(command);
290
[128]291 if (res) {
292 return (FALSE);
293 } else {
294 return (TRUE);
295 }
[1]296}
297
298
299
300/**
[3870]301 * Determine the name of the tape device. Tries the SCSI tape for
302 * this platform, then "/dev/st0", then "/dev/ht0" and "/dev/osst0".
303 * @return the value of the tape device or NULL if not found. Allocated dynamically must be freed by caller.
[1]304 */
[3870]305char *find_tape_device(void) {
[3610]306 char *tmp = NULL;
[3870]307 char *dev = NULL;
[2520]308 char *command = NULL;
[1]309
[128]310 log_to_screen("I am looking for your tape streamer. Please wait.");
[2520]311
[3872]312 if (bkpinfo->media_device != NULL) {
313 log_msg(3, "Been there, done that. Returning %s", bkpinfo->media_device);
314 return (bkpinfo->media_device);
315 }
316
[3870]317 tmp = find_home_of_exe("lsscsi");
318 if (tmp != NULL) {
319 mr_asprintf(command, "%s | grep ' tape' | awk '{print $NF}' | head -1", tmp);
320 dev = call_program_and_get_last_line_of_output(command);
321 mr_free(command);
[128]322 }
[3191]323 mr_free(tmp);
324
[3872]325 if ((dev != NULL) && does_file_exist(dev)) {
[3870]326 if (mt_says_tape_exists(dev)) {
327 log_it("find_tape_device found %s automatically", dev);
328 }
329 } else {
330 /* trying something else then */
331 mr_asprintf(dev, "%s", VANILLA_SCSI_TAPE);
[128]332 if (!mt_says_tape_exists(dev)) {
[3870]333 mr_asprintf(dev, "%s", ALT_TAPE);
[128]334 if (!mt_says_tape_exists(dev)) {
[3857]335 mr_asprintf(dev, "%s", "/dev/osst0");
[128]336 if (!mt_says_tape_exists(dev)) {
[3870]337 log_it("Unable to find a tape device on this system");
[128]338 }
339 }
340 }
[3872]341 if (dev != NULL) {
342 log_it("find_tape_device found %s manually", dev);
343 }
[128]344 }
[1]345
[3872]346 if ((dev != NULL) && does_file_exist(dev)) {
[3870]347 log_it("find_tape_device returns %s", dev);
[3191]348 } else {
[3872]349 mr_free(dev);
[3870]350 log_it("find_tape_device found no tape on your system returning NULL");
[3191]351 }
[3870]352 return (dev);
[1]353}
354
355
[1645]356int read_EXAT_files_from_tape(long long *ptmp_size, char *tmp_fname,
[128]357 int *pctrl_chr, char *xattr_fname,
358 char *acl_fname)
[1]359{
[128]360 int res = 0;
[3080]361 char fname_buf[PATH_MAX];
[3116]362 char *fname = (char *)fname_buf; /* Should NOT be NULL */
[1940]363 char *tmp = NULL;
[128]364
[1933]365 // xattr
[948]366 if (g_getfattr) {
[955]367 res = read_header_block_from_stream(ptmp_size, fname, pctrl_chr);
[948]368 if (*pctrl_chr != BLK_START_EXAT_FILE) {
369 wrong_marker(BLK_START_EXAT_FILE, *pctrl_chr);
370 }
[1940]371 if (strstr(fname, "xattr") == NULL) {
[3185]372 mr_asprintf(tmp,"Wrong order expected xattr, got %s, sunshine.", fname);
[1940]373 fatal_error(tmp);
[948]374 }
[1645]375 read_file_from_stream_to_file(xattr_fname, *ptmp_size);
[1940]376 res = read_header_block_from_stream(ptmp_size, fname, pctrl_chr);
[948]377 if (*pctrl_chr != BLK_STOP_EXAT_FILE) {
378 wrong_marker(BLK_STOP_EXAT_FILE, *pctrl_chr);
379 }
380 log_msg(1, "Got xattr");
[1940]381 res = read_header_block_from_stream(ptmp_size, fname, pctrl_chr);
[1933]382 if (*pctrl_chr != BLK_STOP_EXTENDED_ATTRIBUTES) {
383 wrong_marker(BLK_STOP_EXTENDED_ATTRIBUTES, *pctrl_chr);
384 }
[1940]385 res = read_header_block_from_stream(ptmp_size, fname, pctrl_chr);
[1943]386 if (*pctrl_chr == BLK_START_AN_AFIO_OR_SLICE) {
[1933]387 log_msg(1, "No acl attributes found, skipping to afio files");
388 return(0);
389 } else {
[1943]390 if (*pctrl_chr != BLK_START_EXTENDED_ATTRIBUTES) {
[1933]391 wrong_marker(BLK_START_EXTENDED_ATTRIBUTES, *pctrl_chr);
392 }
393 }
[128]394 }
[1933]395 // acl
[948]396 if (g_getfacl) {
[955]397 res = read_header_block_from_stream(ptmp_size, fname, pctrl_chr);
[948]398 if (*pctrl_chr != BLK_START_EXAT_FILE) {
399 wrong_marker(BLK_START_EXAT_FILE, *pctrl_chr);
400 }
[1940]401 if (strstr(fname, "acl") == NULL) {
[3185]402 mr_asprintf(tmp,"Wrong order expected acl, got %s, sunshine.", fname);
[1940]403 fatal_error(tmp);
404 }
[1645]405 read_file_from_stream_to_file(acl_fname, *ptmp_size);
[1940]406 res = read_header_block_from_stream(ptmp_size, fname, pctrl_chr);
[948]407 if (*pctrl_chr != BLK_STOP_EXAT_FILE) {
408 wrong_marker(BLK_STOP_EXAT_FILE, *pctrl_chr);
409 }
[1940]410 res = read_header_block_from_stream(ptmp_size, fname, pctrl_chr);
[948]411 if (*pctrl_chr != BLK_STOP_EXTENDED_ATTRIBUTES) {
412 wrong_marker(BLK_STOP_EXTENDED_ATTRIBUTES, *pctrl_chr);
413 }
414 log_msg(1, "Got acl");
[128]415 }
[1933]416 // tarball itself
[128]417 res = read_header_block_from_stream(ptmp_size, tmp_fname, pctrl_chr);
[1933]418 log_msg(1, "End of extended attributes, now looking for afioball");
[3116]419 return (res);
[1]420}
421
422
[1645]423int write_EXAT_files_to_tape(char *xattr_fname,
[128]424 char *acl_fname)
[1]425{
[128]426 int res = 0;
[948]427 if (g_getfattr) {
[955]428 // xattr
[3860]429 write_header_block_to_stream(length_of_file(xattr_fname), xattr_fname, BLK_START_EXTENDED_ATTRIBUTES);
430 write_header_block_to_stream(length_of_file(xattr_fname), xattr_fname, BLK_START_EXAT_FILE);
[1645]431 write_file_to_stream_from_file(xattr_fname);
[948]432 write_header_block_to_stream((off_t)-1, xattr_fname, BLK_STOP_EXAT_FILE);
[3860]433 write_header_block_to_stream(length_of_file(xattr_fname), xattr_fname, BLK_STOP_EXTENDED_ATTRIBUTES);
[948]434 }
435 if (g_getfacl) {
[955]436 // acl
[3860]437 write_header_block_to_stream(length_of_file(acl_fname), acl_fname, BLK_START_EXTENDED_ATTRIBUTES);
438 write_header_block_to_stream(length_of_file(acl_fname), acl_fname, BLK_START_EXAT_FILE);
[1645]439 write_file_to_stream_from_file(acl_fname);
[948]440 write_header_block_to_stream((off_t)-1, acl_fname, BLK_STOP_EXAT_FILE);
[3860]441 write_header_block_to_stream(length_of_file(acl_fname), acl_fname, BLK_STOP_EXTENDED_ATTRIBUTES);
[948]442 }
[128]443 return (res);
[1]444}
445
446
447
448
449/**
450 * Tell the user to insert tape @p tapeno and wait for it to settle (5 seconds).
451 * @param tapeno The tape number to insist on.
452 * @bug There is currently no way to actually verify that the user has actually
453 * inserted the right tape.
454 */
455void insist_on_this_tape_number(int tapeno)
456{
[128]457 int i;
[2520]458 char *tmp = NULL;
[1]459
[128]460 log_it("Insisting on tape #%d", tapeno);
461 if (g_current_media_number != tapeno) {
[3191]462 mr_asprintf(tmp, "When the tape drive goes quiet, please insert volume %d in this series.", tapeno);
[128]463 popup_and_OK(tmp);
[2520]464 mr_free(tmp);
[541]465 open_evalcall_form("Waiting while the tape drive settles");
[128]466 } else {
[541]467 open_evalcall_form("Waiting while the tape drive rewinds");
[128]468 }
[1]469
[128]470 for (i = 0; i <= 100; i += 2) {
471 usleep(100000);
472 update_evalcall_form(i);
473 }
474 close_evalcall_form();
475 log_it("I assume user has inserted it. They _say_ they have...");
476 g_current_media_number = tapeno;
[1]477
[128]478 // log_it("g_current_media_number = %d", g_current_media_number);
479 log_it("OK, I've finished insisting. On with the revelry.");
[1]480}
481
482
483
484
485/**
486 * Debugging aid - log the offset we're at on the tape (reading or writing).
487 */
[128]488void log_tape_pos(void)
[1]489{
[128]490 /*@ buffers ***************************************************** */
[1]491
492
[128]493 /*@ end vars *************************************************** */
[1]494
[128]495 log_it("Tape position -- %ld KB (%ld MB)", (long) g_tape_posK,
496 (long) g_tape_posK >> 10);
[1]497}
498
499
500
501
502/**
503 * Add a file to a collection of recently archived filesets/slices.
504 * The type is determined by the filename: if it contains ".afio." it is
505 * assumed to be a fileset, otherwise if it contains "slice" it's a slice,
506 * otherwise we generate a fatal_error().
507 * @param td The current @c bkpinfo->tempdir (file will be placed in <tt>td</tt>/tmpfs/backcatalog/).
508 * @param latest_fname The file to place in the collection.
509 * @return 0, always.
510 * @bug Return value is redundant.
511 * @bug The detection won't work for uncompressed afioballs (they end in ".afio", no dot afterwards). // Not true. They end in '.' -Hugo
512 */
513int maintain_collection_of_recent_archives(char *td, char *latest_fname)
514{
[128]515 long long final_alleged_writeK, final_projected_certain_writeK,
[3060]516 cposK, bufsize_K;
[128]517 int last, curr, i;
[2520]518 char *command = NULL;
519 char *tmpdir = NULL;
520 char *old_fname = NULL;
[128]521 char *p;
522 char suffix[16];
[1]523
[128]524 bufsize_K = (long long) (1024LL * (1 + g_tape_buffer_size_MB));
525 if ((p = strrchr(latest_fname, '.'))) {
526 strcpy(suffix, ++p);
527 } else {
528 suffix[0] = '\0';
[1]529 }
[3185]530 mr_asprintf(tmpdir, "%s/tmpfs/backcatalog", td);
[128]531 mkdir(tmpdir, 0x700);
[3185]532 mr_asprintf(command, "cp -f %s %s", latest_fname, tmpdir);
[128]533 if (run_program_and_log_output(command, 6)) {
534 log_it("Warning - failed to copy %s to backcatalog at %s",
535 latest_fname, tmpdir);
536 }
[2520]537 mr_free(command);
538
[128]539 last = g_tapecatalog->entries - 1;
540 if (last <= 0) {
[2230]541 log_it("Too early to start deleting from collection.");
[2520]542 mr_free(tmpdir);
[128]543 return (0);
544 }
545 final_alleged_writeK = g_tapecatalog->el[last].tape_posK;
546 final_projected_certain_writeK = final_alleged_writeK - bufsize_K;
547 for (curr = last; curr >= 0; curr--) {
548 cposK = g_tapecatalog->el[curr].tape_posK;
549 if (cposK < final_projected_certain_writeK) {
550 break;
551 }
552 }
553 if (curr < 0) {
[2230]554 log_it("Not far enough into tape to start deleting old archives from collection.");
[2520]555 mr_free(tmpdir);
[128]556 return (0);
557 }
[1]558
[128]559 for (i = curr - 1; i >= 0 && curr - i < 10; i--) {
[3185]560 mr_asprintf(old_fname, "%s/%s", tmpdir, g_tapecatalog->el[i].fname);
[128]561 unlink(old_fname);
[2520]562 mr_free(old_fname);
[128]563 }
[2520]564 mr_free(tmpdir);
[128]565 return (0);
[1]566}
567
568
569
570
571/**
572 * Open the CD stream for input.
573 * @param bkpinfo The backup information structure. Passed to openin_tape().
574 * @return 0 for success, nonzero for failure.
575 * @note Equivalent to openin_tape() for now, but don't count on this behavior.
576 */
[1645]577int openin_cdstream()
[1]578{
[1645]579 return (openin_tape());
[1]580}
581
582/**
583 * FIFO used to read/write to the tape device.
584 * @bug This seems obsolete now that we call an external @c buffer program. Please look onto this.
585 */
586char g_tape_fifo[MAX_STR_LEN];
587
588
589
[1954]590int set_tape_block_size_with_mt(long internal_tape_block_size)
[1]591{
[2520]592 char *tmp = NULL;
[128]593 int res;
[1]594
[3191]595 if (bkpinfo->media_device == NULL) {
596 return(1);
597 }
598
[1954]599 if (strncmp(bkpinfo->media_device, "/dev/", 5)) {
[3191]600 log_msg(1, "Not using 'mt setblk'. This isn't an actual /dev entry.");
[128]601 return (0);
602 }
[3185]603 mr_asprintf(tmp, "mt -f %s setblk %ld", bkpinfo->media_device, internal_tape_block_size);
[128]604 res = run_program_and_log_output(tmp, 3);
[2520]605 mr_free(tmp);
[128]606 return (res);
[1]607}
608
[1951]609/**
610 * Return the non-rewinding device when passed the normal one
611 * @param tapedev The tape device to open for writing.
612 * @note the caller needs to free the string returned
613 */
614char *get_non_rewind_dev(char *tapedev)
615{
[1]616
[1951]617 char *ntapedev = NULL;
618 char *p = NULL;
619 char *q = NULL;
620 char *r = NULL;
621
[3620]622 ntapedev = (char *)mr_malloc(strlen(tapedev)+2*sizeof(char));
[1951]623 p = strrchr(tapedev,'/');
624 if (p == NULL) {
625 log_it("Didn't find a '/' in %s",tapedev);
626 return(NULL);
627 }
628
629 /* Copy tapedev content up to the last / */
630 q = tapedev;
631 r = ntapedev;
632 while (q != p) {
633 *r = *q;
634 r++;
635 q++;
636 }
637 /* Copy the '/' */
638 *r = *q;
639 r++;
640 q++;
641 /* Adds a 'n' - non-rewinding */
642 *r = 'n';
643 r++;
644 /* Copy the rest of tapedev */
645 while (*q != '\0') {
646 *r = *q;
647 r++;
648 q++;
649 }
650 *r = '\0';
651 if (mt_says_tape_exists(ntapedev)) {
652 log_it("Non-rewinding tape device is %s",ntapedev);
653 } else {
654 log_it("Unable to find non-rewinding tape device.");
655 ntapedev = NULL;
656 }
657 return(ntapedev);
658}
659
660
661
[1949]662/**
663 * Handle OBDR if we were asked to do so
[1954]664 * @param tapedev The tape device to open for reading.
[1949]665 */
[1968]666int skip_obdr(void)
[1949]667{
668 char *command = NULL;
[1955]669 int res = 0;
[1]670
[3191]671 if (bkpinfo->media_device == NULL) {
672 return(1);
673 }
674
[1955]675 log_it("Skipping OBDR headers");
[3185]676 mr_asprintf(command, "mt -f %s rewind",bkpinfo->media_device);
[1962]677 res = run_program_and_log_output(command, 1);
678 paranoid_free(command);
679
[3185]680 mr_asprintf(command, "mt -f %s fsf 2",bkpinfo->media_device);
[1955]681 res = run_program_and_log_output(command, 1);
[1949]682 paranoid_free(command);
683
[1954]684 set_tape_block_size_with_mt(bkpinfo->internal_tape_block_size);
[1955]685 return(res);
[1949]686}
687
[1954]688/**
689 * Handle OBDR if we were asked to do so
690 * @param tapedev The tape device to open for writing.
691 * @return 0 for success, nonzero for failure.
692 * @note This should be called ONLY from backup processes. It will OVERWRITE ANY
693 * EXISTING DATA on the tape!
694 */
[1968]695int create_obdr(void)
[1949]696{
697
698 char *command = NULL;
699 int res = 0;
700
[3191]701 if (bkpinfo->media_device == NULL) {
702 return(1);
703 }
704
[1955]705 log_it("Creating OBDR headers");
[1949]706 /* OBDR: First block 10 kB of zero bs = 512 */
[3185]707 mr_asprintf(command, "mt -f %s compression off",bkpinfo->media_device);
[1949]708 res = run_program_and_log_output(command, 1);
709 paranoid_free(command);
710
[3185]711 mr_asprintf(command, "mt -f %s rewind",bkpinfo->media_device);
[1955]712 res += run_program_and_log_output(command, 1);
[1949]713 paranoid_free(command);
714
[1954]715 set_tape_block_size_with_mt(512);
[1949]716
[3185]717 mr_asprintf(command, "dd if=/dev/zero of=%s bs=512 count=20",bkpinfo->media_device);
[1955]718 res += run_program_and_log_output(command, 1);
[1949]719 paranoid_free(command);
720
721 /* OBDR: then ISO boot image bs = 2048 */
[1954]722 set_tape_block_size_with_mt(2048);
[1949]723
[3527]724 mr_asprintf(command, "dd if=%s of=%s bs=2048",MINDI_CACHE"/mindi.iso",bkpinfo->media_device);
[1955]725 res += run_program_and_log_output(command, 1);
[1949]726 paranoid_free(command);
727
[1954]728 set_tape_block_size_with_mt(bkpinfo->internal_tape_block_size);
[2900]729
730 /* restore compression mode on */
[3185]731 mr_asprintf(command, "mt -f %s compression on",bkpinfo->media_device);
[2900]732 res = run_program_and_log_output(command, 1);
733 paranoid_free(command);
734
[1955]735 return(res);
[1949]736}
737
738
[1]739/**
740 * Open the tape device for input.
741 * @param bkpinfo The backup information structure. Fields used:
742 * - @c bkpinfo->media_device
743 * - @c bkpinfo->tmpdir
744 * @return 0 for success, nonzero for failure.
745 * @note This will also work with a cdstream for now, but don't count on this behavior.
746 */
[1645]747int openin_tape()
[1]748{
[128]749 /*@ buffer ***************************************************** */
750 char fname[MAX_STR_LEN];
751 char *datablock;
[2520]752 char *tmp = NULL;
[3613]753 char *old_pwd = NULL;
[2520]754 char *outfname = NULL;
[128]755 /*@ int ******************************************************* */
756 int i;
757 int j;
[1955]758 int res = 0;
[128]759 long length, templong;
760 size_t k;
761 int retval = 0;
762 int ctrl_chr;
[1]763
[128]764 /*@ long long ************************************************* */
765 long long size;
[1]766
[128]767 /*@ pointers ************************************************** */
768 FILE *fout;
[1]769
[128]770 /*@ end vars *************************************************** */
[1]771
[3191]772 g_tapecatalog = mr_malloc(sizeof(struct s_tapecatalog));
[128]773 g_tapecatalog->entries = 0;
774 g_tape_posK = 0;
775 if (g_tape_stream) {
776 log_it("FYI - I won't 'openin' the tape. It's already open.");
777 return (0);
778 }
[1969]779
780 // mondoarchive should have configured everything to give the right non-rew device
781 if ((bkpinfo->use_obdr) && (bkpinfo->media_device != NULL)) {
[1955]782 res = skip_obdr();
783 if (res != 0) {
784 log_it("Not able to skip OBDR - Restore will have to be done manually");
785 }
[1952]786 } else {
[1969]787 if (bkpinfo->media_device == NULL) {
[1954]788 log_it("Not able to skip OBDR - Restore will have to be done manually");
[3191]789 return (1);
[1954]790 }
791 set_tape_block_size_with_mt(bkpinfo->internal_tape_block_size);
[1948]792 }
793
[128]794 insist_on_this_tape_number(1);
[3185]795 mr_asprintf(outfname, "%s/tmp/all.tar.gz", bkpinfo->tmpdir);
[128]796 make_hole_for_file(outfname);
[1]797
[128]798 log_it("Opening IN tape");
[3191]799 if (!(g_tape_stream = open_device_via_buffer(bkpinfo->media_device, 'r', bkpinfo->internal_tape_block_size))) {
[128]800 log_OS_error(g_tape_fifo);
[541]801 log_to_screen("Cannot openin stream device");
[2520]802 mr_free(outfname);
[128]803 return (1);
804 }
[541]805 log_to_screen("Reading stream");
[128]806 log_it("stream device = '%s'", bkpinfo->media_device);
[3191]807 /* skip data disks */
[128]808 open_evalcall_form("Skipping data disks on stream");
[541]809 log_to_screen("Skipping data disks on stream");
[128]810 if (!(fout = fopen(outfname, "w"))) {
811 log_OS_error(outfname);
[541]812 log_to_screen("Cannot openout datadisk all.tar.gz file");
[2520]813 mr_free(outfname);
[128]814 return (-1);
[1]815 }
[128]816 if (!(datablock = (char *) malloc(256 * 1024))) {
[541]817 log_to_screen("Unable to malloc 256*1024");
[2520]818 mr_free(outfname);
[2240]819 finish(1);
[128]820 }
821 for (i = 0; i < 32; i++) {
822 for (j = 0; j < 4; j++) {
823 for (length = 0, k = 0; length < 256 * 1024; length += k) {
824 k = fread(datablock + length, 1, 256 * 1024 - length,
825 g_tape_stream);
826 }
[3060]827 if (fwrite(datablock, 1, (size_t) length, fout)) {
828 // FIXME
829 }
[128]830 g_tape_posK += length / 1024;
831 }
832 if (i > 8) // otherwise, 'buffer' distorts calculations
833 {
834 templong = ((i - 8) * 4 + j) * 100 / (128 - 8 * 4);
835 update_evalcall_form((int) (templong));
836 }
837 }
838 paranoid_fclose(fout);
839 paranoid_free(datablock);
[2520]840
[1]841/* find initial blocks */
[128]842 res = read_header_block_from_stream(&size, fname, &ctrl_chr);
843 retval += res;
844 if (ctrl_chr != BLK_START_OF_TAPE) {
845 wrong_marker(BLK_START_OF_TAPE, ctrl_chr);
846 }
847 res = read_header_block_from_stream(&size, fname, &ctrl_chr);
848 retval += res;
849 if (ctrl_chr != BLK_START_OF_BACKUP) {
850 wrong_marker(BLK_START_OF_BACKUP, ctrl_chr);
851 }
852 close_evalcall_form();
853 log_it("Saved all.tar.gz to '%s'", outfname);
[3613]854 old_pwd = mr_getcwd();
[3060]855 if (chdir(bkpinfo->tmpdir)) {
856 // FIXME
857 }
[3271]858 mr_asprintf(tmp, "tar -zxf %s ./tmp/mondorestore.cfg 2> /dev/null", outfname);
[128]859 paranoid_system(tmp);
[2520]860 mr_free(tmp);
861
[3271]862 paranoid_system("cp -f tmp/mondorestore.cfg . 2> /dev/null");
[3613]863 if (chdir(old_pwd)) {
[3060]864 // FIXME
865 }
[3613]866 mr_free(old_pwd);
[128]867 unlink(outfname);
[2520]868 mr_free(outfname);
[128]869 return (retval);
[1]870}
871
872
873/**
874 * Start writing to a CD stream.
875 * @param cddev The CD device to openout via cdrecord.
876 * @param speed The speed to write at.
877 * @return 0 for success, nonzero for failure.
878 * @note This should be called only from backup processes.
879 */
[128]880int openout_cdstream(char *cddev, int speed)
[1]881{
[128]882 /*@ buffers ***************************************************** */
[2520]883 char *command = NULL;
[1]884
[128]885 /*@ end vars *************************************************** */
[1]886
[3191]887 if (cddev == NULL) {
888 log_to_screen("Failed to openout NULL cddev");
889 return (1);
890 }
[2520]891 /* add 'dummy' if testing */
[3185]892 mr_asprintf(command, "cdrecord -eject dev=%s speed=%d fs=24m -waiti - >> %s 2>> %s", cddev, speed, MONDO_LOGFILE, MONDO_LOGFILE);
[2520]893 /* initialise the catalog */
[128]894 g_current_media_number = 1;
895 if (!(g_tapecatalog = malloc(sizeof(struct s_tapecatalog)))) {
896 fatal_error("Cannot alloc mem for tape catalog");
897 }
898 g_tapecatalog->entries = 0;
[2520]899 /* log stuff */
[128]900 log_it("Opening OUT cdstream with the command");
901 log_it(command);
[2520]902 /* log_it("Let's see what happens, shall we?"); */
[128]903 g_tape_stream = popen(command, "w");
[2520]904 mr_free(command);
905
[128]906 if (g_tape_stream) {
907 return (0);
908 } else {
[541]909 log_to_screen("Failed to openout to cdstream (fifo)");
[128]910 return (1);
911 }
[1]912}
913
[2520]914
[1]915/**
916 * Start writing to a tape device for the backup.
[1948]917 * Handle OBDR if we were asked to do so
[1]918 * @param tapedev The tape device to open for writing.
919 * @return 0 for success, nonzero for failure.
920 * @note This should be called ONLY from backup processes. It will OVERWRITE ANY
921 * EXISTING DATA on the tape!
922 */
[1954]923int openout_tape() {
[1]924
[1954]925g_current_media_number = 1;
926if (g_tape_stream) {
927 log_it("FYI - I won't 'openout' the tape. It's already open.");
[128]928 return (0);
[1]929}
[3191]930if (bkpinfo->media_device == NULL) {
931 log_it("Unable to openout NULL device");
932 return(1);
[1954]933}
[3191]934g_tapecatalog = mr_malloc(sizeof(struct s_tapecatalog));
[1954]935g_tapecatalog->entries = 0;
936g_tape_posK = 0;
[1]937
[1956]938if (bkpinfo->use_obdr) {
[1954]939 create_obdr();
940} else {
941 set_tape_block_size_with_mt(bkpinfo->internal_tape_block_size);
942}
943log_it("Opening OUT tape");
[3191]944if (!(g_tape_stream = open_device_via_buffer(bkpinfo->media_device, 'w', bkpinfo->internal_tape_block_size))) {
[1954]945 log_OS_error(g_tape_fifo);
946 log_to_screen("Cannot openin stream device");
947 return (1);
948}
949return (0);
950}
[1]951
952
953
[1954]954
[1]955/**
956 * Copy a file from the opened stream (CD or tape) to @p outfile.
957 * @param outfile The file to write to.
958 * @param size The size of the file in the input stream.
959 * @return 0 for success, nonzero for failure.
960 */
961int
[1645]962read_file_from_stream_to_file(char *outfile, long long size)
[1]963{
964
[128]965 /*@ int ******************************************************** */
966 int res;
[1]967
[128]968 /*@ end vars *************************************************** */
[1]969
[1645]970 res = read_file_from_stream_FULL(outfile, NULL, size);
[1]971
[128]972 return (res);
[1]973}
974
975
976
977/**
978 * Copy a file from the currently opened stream (CD or tape) to the stream indicated
979 * by @p fout.
980 * @param bkpinfo The backup information structure. @c bkpinfo->media_size is the only field used.
981 * @param fout The stream to write the file to.
982 * @param size The size of the file in bytes.
983 * @return 0 for success, nonzero for failure.
984 */
985int
[1645]986read_file_from_stream_to_stream(FILE * fout, long long size)
[1]987{
988
[128]989 /*@ int ******************************************************** */
990 int res;
[1]991
[128]992 /*@ end vars *************************************************** */
[1]993
[1645]994 res = read_file_from_stream_FULL(NULL, fout, size);
[1]995/* fflush(g_tape_stream);
996 fflush(fout);*/
[128]997 return (res);
[1]998}
999
1000
1001
1002/**
1003 * Copy a file from the currently opened stream (CD or tape) to either a
1004 * @c FILE pointer indicating a currently-opened file, or a filename indicating
1005 * a new file to create. This is the backbone function that read_file_from_stream_to_file()
1006 * and read_file_from_stream_to_stream() are wrappers for.
1007 * @param bkpinfo The backup information structure. @c bkpinfo->media_size is the only field used.
1008 * @param outfname If non-NULL, write to this file.
1009 * @param foutstream If non-NULL, write to this stream.
1010 * @param orig_size The original length of the file in bytes.
1011 * @return 0 for success, nonzero for failure.
1012 * @note Only @b one of @p outfname or @p foutstream may be non-NULL.
1013 */
1014int
[1645]1015read_file_from_stream_FULL(char *outfname, FILE * foutstream, long long orig_size)
[1]1016{
[128]1017 /*@ buffers ***************************************************** */
1018 char *datablock;
1019 char *temp_fname;
1020 char *temp_cksum;
[2520]1021 char *actual_cksum = NULL;
[1]1022
[128]1023 /*@ int ********************************************************* */
1024 int retval = 0;
[1]1025#ifdef EXTRA_TAPE_CHECKSUMS
[128]1026 int i, ch;
[1]1027#endif
[128]1028 int noof_blocks;
1029 int ctrl_chr;
1030 int res;
1031 /*@ pointers **************************************************** */
1032 FILE *fout;
[1]1033
[128]1034 /*@ long ***************************************************** */
[1899]1035 long bytes_to_write = 0L /*,i */ ;
[1]1036// long bytes_successfully_read_in_this_time = 0;
1037
[128]1038 /*@ long long *************************************************** */
1039 long long temp_size, size;
1040 long bytes_read, bytes_to_read;
1041 long long total_read_from_tape_for_this_file = 0;
1042 long long where_I_was_before_tape_change = 0;
1043 /*@ unsigned int ************************************************ */
1044 /* unsigned int ch; */
1045 unsigned int crc16;
1046 unsigned int crctt;
[1]1047
[128]1048 /*@ init ******************************************************* */
1049 malloc_string(temp_fname);
1050 malloc_string(temp_cksum);
1051 datablock = malloc(TAPE_BLOCK_SIZE);
1052 crc16 = 0;
1053 crctt = 0;
1054 size = orig_size;
[1]1055
[128]1056 /*@ end vars *************************************************** */
[1]1057
[128]1058 res = read_header_block_from_stream(&temp_size, temp_fname, &ctrl_chr);
[3060]1059 if (res) {
1060 // FIXME
1061 }
[128]1062 if (orig_size != temp_size && orig_size != -1) {
[3191]1063 log_to_screen("output file's size should be %ld K but is apparently %ld K", (long) size >> 10, (long) temp_size >> 10);
[128]1064 }
1065 if (ctrl_chr != BLK_START_FILE) {
1066 wrong_marker(BLK_START_FILE, ctrl_chr);
1067 return (1);
1068 }
[1]1069
[128]1070 if (foutstream) {
1071 fout = foutstream;
1072 } else {
1073 fout = fopen(outfname, "w");
[1]1074 }
[128]1075 if (!fout) {
1076 log_OS_error(outfname);
[541]1077 log_to_screen("Cannot openout file");
[128]1078 return (1);
1079 }
1080 total_read_from_tape_for_this_file = 0;
1081 for (noof_blocks = 0; size > 0;
1082 noof_blocks++, size -=
1083 bytes_to_write, total_read_from_tape_for_this_file +=
1084 bytes_read) {
1085 bytes_to_write =
1086 (size < TAPE_BLOCK_SIZE) ? (long) size : TAPE_BLOCK_SIZE;
1087 bytes_to_read = TAPE_BLOCK_SIZE;
1088 bytes_read = fread(datablock, 1, bytes_to_read, g_tape_stream);
1089 while (bytes_read < bytes_to_read) { // next tape!
1090// crctt=crc16=0;
1091 where_I_was_before_tape_change = size;
1092 log_msg(4, "where_I_was_... = %lld",
1093 where_I_was_before_tape_change);
[1645]1094 start_to_read_from_next_tape();
[128]1095 log_msg(4, "Started reading from next tape.");
1096 skip_incoming_files_until_we_find_this_one(temp_fname);
1097 log_msg(4, "Skipped irrelevant files OK.");
1098 for (size = orig_size; size > where_I_was_before_tape_change;
1099 size -= bytes_to_write) {
[3060]1100 bytes_read = fread(datablock, 1, bytes_to_read, g_tape_stream);
[128]1101 }
1102 log_msg(4, "'size' is now %lld (should be %lld)", size,
1103 where_I_was_before_tape_change);
1104 log_to_screen("Successfully re-sync'd tape");
1105 bytes_read = fread(datablock, 1, bytes_to_read, g_tape_stream);
1106 }
[1]1107
[3060]1108 if (fwrite(datablock, 1, (size_t) bytes_to_write, fout)) { // for blocking reasons, bytes_successfully_read_in isn't necessarily the same as bytes_to_write
1109 // FIXME
1110 }
[1]1111
1112#ifdef EXTRA_TAPE_CHECKSUMS
[128]1113 for (i = 0; i < (int) bytes_to_write; i++) {
1114 ch = datablock[i];
1115 crc16 = updcrcr(crc16, (unsigned) ch);
1116 crctt = updcrc(crctt, (unsigned) ch);
1117 }
[1]1118#endif
[128]1119 }
1120 log_msg(6, "Total read from tape for this file = %lld",
1121 total_read_from_tape_for_this_file);
1122 log_msg(6, ".......................... Should be %lld", orig_size);
1123 g_tape_posK += total_read_from_tape_for_this_file / 1024;
[3185]1124 mr_asprintf(actual_cksum, "%04x%04x", crc16, crctt);
[128]1125 if (foutstream) { /*log_it("Finished writing to foutstream"); */
1126 } else {
1127 paranoid_fclose(fout);
1128 }
1129 res = read_header_block_from_stream(&temp_size, temp_cksum, &ctrl_chr);
1130 if (ctrl_chr != BLK_STOP_FILE) {
1131 wrong_marker(BLK_STOP_FILE, ctrl_chr);
1132 }
1133 if (strcmp(temp_cksum, actual_cksum)) {
[3191]1134 log_to_screen("actual cksum=%s; recorded cksum=%s", actual_cksum, temp_cksum);
1135 log_to_screen("%s (%ld K) is corrupt on tape", temp_fname, (long) orig_size >> 10);
[128]1136 retval++;
1137 }
[2520]1138 mr_free(actual_cksum);
1139
[128]1140 paranoid_free(datablock);
1141 paranoid_free(temp_fname);
1142 paranoid_free(temp_cksum);
1143 return (retval);
[1]1144}
1145
1146
1147
1148/**
1149 * Read a header block from the currently opened stream (CD or tape).
1150 * This block indicates the length of the following file (if it's file-related)
1151 * the filename (if it's file-related), and the block type.
1152 * @param plen Where to put the length of the file. Valid only for file-related header blocks.
1153 * @param filename Where to put the name of the file. Valid only for file-related header blocks.
1154 * @param pcontrol_char Where to put the type of block (e.g. start-file, end-file, start-tape, ...)
1155 * @return 0 for success, nonzero for failure.
1156 * @note If you read a marker (@p pcontrol_char) you're not expecting, you can call wrong_marker().
1157 */
1158int
[128]1159read_header_block_from_stream(long long *plen, char *filename,
1160 int *pcontrol_char)
[1]1161{
1162
[128]1163 /*@ buffers ***************************************************** */
1164 char *tempblock;
[3611]1165 char *tmp = NULL;
[1]1166
[128]1167 /*@ int ********************************************************* */
1168 int i, retval;
[1]1169
[128]1170 /*@ end vars *************************************************** */
[1]1171
[128]1172 tempblock = (char *) malloc((size_t) TAPE_BLOCK_SIZE);
[1]1173
[128]1174 for (i = 0; i < (int) TAPE_BLOCK_SIZE; i++) {
1175 tempblock[i] = 0;
1176 }
1177 while (!(*pcontrol_char = tempblock[7000])) {
[3060]1178 g_tape_posK += fread(tempblock, 1, (size_t) TAPE_BLOCK_SIZE, g_tape_stream) / 1024;
[128]1179 }
1180 memcpy((char *) plen, tempblock + 7001, sizeof(long long));
[1934]1181 if (strcmp(tempblock + 6000 + *pcontrol_char, STR_HEADER)) {
[128]1182 log_it("Bad header block at %ld K", (long) g_tape_posK);
1183 }
1184 strcpy(filename, tempblock + 1000);
1185 if (*pcontrol_char == BLK_ABORTED_BACKUP) {
1186 log_to_screen("I can't verify an aborted backup.");
1187 retval = 1;
1188 } else {
1189 retval = 0;
1190 }
1191 for (i = 1000; i < 1020; i++) {
1192 if (tempblock[i] < 32 || tempblock[i] > 126) {
1193 tempblock[i] = ' ';
1194 }
1195 }
1196 tempblock[i] = '\0';
[3611]1197 tmp = marker_to_string(*pcontrol_char);
1198 log_msg(6, "%s (fname=%s, size=%ld K)", tmp, tempblock + 1000, (long) (*plen) >> 10);
1199 mr_free(tmp);
[128]1200 paranoid_free(tempblock);
1201 return (retval);
[1]1202}
1203
1204
1205
1206/**
1207 * Add specified file/slice to the internal catalog of all archives written.
1208 * This lets us restart on a new CD/tape/whatever if it runs out of room. We just
1209 * write the last [buffer size] MB from the catalog to the new tape, so we know
1210 * we have @e all archives on some CD/tape/whatever.
1211 * @param type The type of file we're cataloging (afioball, slice, something else)
1212 * @param number The fileset number or biggiefile number.
1213 * @param aux The slice number if it's a biggiefile, or any other additional info.
1214 * @param fn The original full pathname of the file we're recording.
1215 * @return The index of the record we just added.
1216 */
[128]1217int register_in_tape_catalog(t_archtype type, int number, long aux,
1218 char *fn)
[1]1219{
[128]1220 int last;
[2176]1221 char fname[MAX_TAPECAT_FNAME_LEN+1];
[128]1222 char *p;
[1]1223
[128]1224 p = strrchr(fn, '/');
1225 if (p) {
1226 p++;
1227 } else {
1228 p = fn;
1229 }
1230 strncpy(fname, p, MAX_TAPECAT_FNAME_LEN);
1231 fname[MAX_TAPECAT_FNAME_LEN] = '\0';
1232 last = g_tapecatalog->entries;
1233 if (last >= MAX_TAPECATALOG_ENTRIES) {
1234 log_it
1235 ("Warning - can't log #%d in tape catalog - too many entries already",
1236 number);
1237 return (-1);
1238 }
1239 g_tapecatalog->el[last].type = type;
1240 g_tapecatalog->el[last].number = number;
1241 g_tapecatalog->el[last].aux = aux;
1242 g_tapecatalog->el[last].tape_posK = g_tape_posK;
1243 strcpy(g_tapecatalog->el[last].fname, fname);
1244 g_tapecatalog->entries++;
1245 return (last); // returns the index of the record we've jsut added
[1]1246}
1247
1248
1249
1250
1251/**
1252 * Decide whether we should start a new tape. This is TRUE if we've run out of tape
1253 * (got SIGPIPE) or look like we will.
1254 * @param mediasize The size of the tape in megabytes.
1255 * @param length_of_incoming_file The length of the file we're about to write, in bytes.
1256 * @bug This seems like it'll only work for media_size != autodetect, but Mondo only allows
1257 * autodetecting the size. Huh?
1258 */
[684]1259
[3430]1260/* TODO: Should be reviewed for mediasize being a off_t ??? */
[1]1261bool
[128]1262should_we_write_to_next_tape(long mediasize,
[684]1263 off_t length_of_incoming_file)
[1]1264{
[128]1265 /*@ bool's ***************************************************** */
1266 bool we_need_a_new_tape = FALSE;
[1]1267
[128]1268 /*@ end vars *************************************************** */
[1]1269
[128]1270 if (mediasize == 0) {
1271 return (FALSE);
1272 }
1273 if (mediasize > 0 && (g_tape_posK >> 10 >= mediasize)) {
1274 log_it("mediasize = %ld", mediasize);
1275 we_need_a_new_tape = TRUE;
[541]1276 log_to_screen("Should have started a new tape/CD already");
[128]1277 }
1278 if ((g_tape_posK + length_of_incoming_file / 1024) >> 10 >=
1279 mediasize - (SLICE_SIZE * 4 / 1024)) {
1280 log_it("g_tape_posK = %ld\nmediasize = %ld\n", g_tape_posK,
1281 mediasize);
1282 we_need_a_new_tape = TRUE;
1283 }
1284 return (we_need_a_new_tape);
[1]1285}
1286
1287
1288/**
1289 * Seek through the stream until we find a header block where the NAME field matches
1290 * @p the_file_I_was_reading. This is useful if you've just started reading from
1291 * a new tape and want to find the file you were reading when the tape ended.
1292 * @param the_file_I_was_reading File name to look for.
1293 * @return 0 for success, nonzero for failure.
1294 */
[128]1295int skip_incoming_files_until_we_find_this_one(char
1296 *the_file_I_was_reading)
[1]1297{
[128]1298 char *pA;
1299 char *pB;
1300 int res;
1301 int ctrl_chr;
1302 char *temp_fname;
1303 char *datablock;
1304 long long temp_size, size;
1305 long bytes_to_write;
[1]1306
[128]1307 datablock = malloc(TAPE_BLOCK_SIZE);
1308 malloc_string(temp_fname);
1309 pB = strrchr(the_file_I_was_reading, '/');
1310 if (pB) {
1311 pB++;
1312 } else {
1313 pB = the_file_I_was_reading;
[1]1314 }
[128]1315 log_msg(1, "skip_incoming_..(%s)", pB);
1316 log_msg(2, "Looking for initial START_AN_AFIO_OR_SLICE");
1317 ctrl_chr = -1;
1318 while (ctrl_chr != BLK_START_AN_AFIO_OR_SLICE) {
[3060]1319 res = read_header_block_from_stream(&temp_size, temp_fname, &ctrl_chr);
1320 if (res) {
1321 // FIXME
1322 }
[128]1323 if (ctrl_chr == BLK_START_AN_AFIO_OR_SLICE) {
1324 break;
1325 }
1326 log_msg(1, "%lld %s %c", temp_size, temp_fname, ctrl_chr);
1327 wrong_marker(BLK_START_AN_AFIO_OR_SLICE, ctrl_chr);
1328 log_msg(3, "Still trying to re-sync w/ tape");
1329 }
1330 while (ctrl_chr != BLK_START_FILE) {
[3060]1331 res = read_header_block_from_stream(&temp_size, temp_fname, &ctrl_chr);
[3191]1332 if (res) {
1333 //FIXME
1334 }
[128]1335 if (ctrl_chr == BLK_START_FILE) {
1336 break;
1337 }
1338 log_msg(1, "%lld %s %c", temp_size, temp_fname, ctrl_chr);
1339 wrong_marker(BLK_START_FILE, ctrl_chr);
1340 log_msg(3, "Still trying to re-sync w/ tape");
1341 }
1342 pA = strrchr(temp_fname, '/');
1343 if (pA) {
1344 pA++;
1345 } else {
1346 pA = temp_fname;
1347 }
1348 pB = strrchr(the_file_I_was_reading, '/');
1349 if (pB) {
1350 pB++;
1351 } else {
1352 pB = the_file_I_was_reading;
1353 }
1354 while (strcmp(pA, pB)) {
[3191]1355 log_msg(6, "Skipping %s (it's not %s)", temp_fname, the_file_I_was_reading);
[128]1356 for (size = temp_size; size > 0; size -= bytes_to_write) {
1357 bytes_to_write =
1358 (size < TAPE_BLOCK_SIZE) ? (long) size : TAPE_BLOCK_SIZE;
[3060]1359 if (fread(datablock, 1, (size_t) TAPE_BLOCK_SIZE, g_tape_stream)) {
1360 // FIXME - needs error-checking and -catching
1361 }
[128]1362 }
[3060]1363 res = read_header_block_from_stream(&temp_size, temp_fname, &ctrl_chr);
[128]1364 if (ctrl_chr != BLK_STOP_FILE) {
1365 wrong_marker(BLK_STOP_FILE, ctrl_chr);
1366 }
[3060]1367 res = read_header_block_from_stream(&temp_size, temp_fname, &ctrl_chr);
[128]1368 if (ctrl_chr != BLK_STOP_AN_AFIO_OR_SLICE) {
1369 wrong_marker(BLK_STOP_AN_AFIO_OR_SLICE, ctrl_chr);
1370 }
[3060]1371 res = read_header_block_from_stream(&temp_size, temp_fname, &ctrl_chr);
[128]1372 if (ctrl_chr != BLK_START_AN_AFIO_OR_SLICE) {
1373 wrong_marker(BLK_START_AN_AFIO_OR_SLICE, ctrl_chr);
1374 }
[3060]1375 res = read_header_block_from_stream(&temp_size, temp_fname, &ctrl_chr);
[128]1376 if (ctrl_chr != BLK_START_FILE) {
1377 wrong_marker(BLK_START_FILE, ctrl_chr);
1378 }
1379 pA = strrchr(temp_fname, '/');
1380 if (pA) {
1381 pA++;
1382 } else {
1383 pA = temp_fname;
1384 }
1385 pB = strrchr(the_file_I_was_reading, '/');
1386 if (pB) {
1387 pB++;
1388 } else {
1389 pB = the_file_I_was_reading;
1390 }
1391 }
[3191]1392 log_msg(2, "Reading %s (it matches %s)", temp_fname, the_file_I_was_reading);
[128]1393 paranoid_free(temp_fname);
1394 paranoid_free(datablock);
1395 return (0);
[1]1396}
1397
1398
1399/**
1400 * Start to read from the next tape. Assumes the user has already inserted it.
1401 * @param bkpinfo The backup information structure. @c bkpinfo->media_device is the only field used.
1402 * @return 0 for success, nonzero for failure.
1403 */
[1645]1404int start_to_read_from_next_tape()
[1]1405{
[128]1406 /*@ int ********************************************************* */
1407 int res = 0;
1408 char *sz_msg;
1409 int ctrlchr;
1410 long long temp_size;
1411 malloc_string(sz_msg);
1412 /*@ end vars *************************************************** */
[1]1413
[3191]1414 if (bkpinfo->media_device == NULL) {
1415 log_it("Unable to open in from NULL device");
1416 return (1);
1417 }
1418
[128]1419 paranoid_pclose(g_tape_stream);
[1934]1420 sync();
1421 sync();
1422 sync();
[128]1423 log_it("Next tape requested.");
1424 insist_on_this_tape_number(g_current_media_number + 1); // will increment it, too
1425 log_it("Opening IN the next tape");
[3191]1426 if (!(g_tape_stream = open_device_via_buffer(bkpinfo->media_device, 'r', bkpinfo->internal_tape_block_size))) {
[128]1427 log_OS_error(g_tape_fifo);
[541]1428 log_to_screen("Cannot openin stream device");
[128]1429 return (1);
1430 }
1431 g_tape_posK = 0;
1432 g_sigpipe = FALSE;
1433 res += read_header_block_from_stream(&temp_size, sz_msg, &ctrlchr); /* just in case */
1434 if (ctrlchr != BLK_START_OF_TAPE) {
1435 wrong_marker(BLK_START_OF_TAPE, ctrlchr);
1436 }
1437 res += read_header_block_from_stream(&temp_size, sz_msg, &ctrlchr); /* just in case */
1438 if (ctrlchr != BLK_START_OF_BACKUP) {
1439 wrong_marker(BLK_START_OF_BACKUP, ctrlchr);
1440 } else {
1441 log_msg(3, "Next tape opened OK. Whoopee!");
1442 }
1443 paranoid_free(sz_msg);
1444 return (res);
[1]1445}
1446
1447
1448
1449/**
1450 * Start to write to the next tape. Assume the user has already inserted it.
1451 * @param bkpinfo The backup information structure. @c bkpinfo->media_device is the only field used.
1452 * @return 0 for success, nonzero for failure.
1453 */
[1645]1454int start_to_write_to_next_tape()
[1]1455{
[128]1456 int res = 0;
[2520]1457 char *command = NULL;
1458
[3191]1459 if (bkpinfo->media_device == NULL) {
1460 log_it("Unable to open out from NULL device");
1461 return (1);
1462 }
1463
[128]1464 paranoid_pclose(g_tape_stream);
[3191]1465 sync();
1466 sync();
1467 sync();
[128]1468 log_it("New tape requested.");
1469 insist_on_this_tape_number(g_current_media_number + 1); // will increment g_current_media, too
1470 if (bkpinfo->backup_media_type == cdstream) {
[3191]1471 mr_asprintf(command, "cdrecord -eject dev=%s speed=%d fs=24m -waiti - >> %s 2>> %s", bkpinfo->media_device, bkpinfo->cdrw_speed, MONDO_LOGFILE, MONDO_LOGFILE);
[128]1472 log_it("Opening OUT to next CD with the command");
1473 log_it(command);
1474 log_it("Let's see what happens, shall we?");
1475 g_tape_stream = popen(command, "w");
[2520]1476 mr_free(command);
1477
[128]1478 if (!g_tape_stream) {
[541]1479 log_to_screen("Failed to openout to cdstream (fifo)");
[128]1480 return (1);
1481 }
1482 } else {
1483 log_it("Opening OUT to next tape");
[3191]1484 if (!(g_tape_stream = open_device_via_buffer(bkpinfo->media_device, 'w', bkpinfo->internal_tape_block_size))) {
[128]1485 log_OS_error(g_tape_fifo);
[541]1486 log_to_screen("Cannot openin stream device");
[128]1487 return (1);
1488 }
[1]1489 }
[128]1490 g_tape_posK = 0;
1491 g_sigpipe = FALSE;
[684]1492 res += write_header_block_to_stream((off_t)0, "start-of-tape", BLK_START_OF_TAPE); /* just in case */
1493 res += write_header_block_to_stream((off_t)0, "start-of-backup", BLK_START_OF_BACKUP); /* just in case */
[128]1494 return (res);
[1]1495}
1496
1497
1498
1499
1500/**
1501 * Write a bufferfull of the most recent archives to the tape. The
1502 * rationale behind this is a bit complex. If the previous tape ended
1503 * suddenly (EOF or otherwise) some archives were probably left in the
1504 * buffer. That means that Mondo thinks they have been written, but
1505 * the external binary @c buffer has not actually written them. So to
1506 * be safe, we start the new tape by writing the last bufferfull from
1507 * the old one. This insures that all archives will be on at least
1508 * one tape. Sounds inelegant, but it works.
1509 * @param bkpinfo The backup information structure. @c bkpinfo->tmpdir is the only field used.
1510 * @return 0 for success, nonzero for failure.
1511 */
[1645]1512int write_backcatalog_to_tape()
[1]1513{
[128]1514 int i, last, res = 0;
[2520]1515 char *fname = NULL;
[1]1516
[128]1517 log_msg(2, "I am now writing back catalog to tape");
1518 last = g_tapecatalog->entries - 1;
1519 for (i = 0; i <= last; i++) {
[3185]1520 mr_asprintf(fname, "%s/tmpfs/backcatalog/%s", bkpinfo->tmpdir, g_tapecatalog->el[i].fname);
[128]1521 if (!does_file_exist(fname)) {
1522 log_msg(6, "Can't write %s - it doesn't exist.", fname);
1523 } else {
[3860]1524 write_header_block_to_stream(length_of_file(fname), "start-backcatalog-afio-or-slice", BLK_START_AN_AFIO_OR_SLICE);
[128]1525 log_msg(2, "Writing %s", fname);
[1645]1526 if (write_file_to_stream_from_file(fname)) {
[128]1527 res++;
1528 log_msg(2, "%s failed", fname);
1529 }
1530 if (i != last) {
[3860]1531 write_header_block_to_stream((off_t)0, "stop-backcatalog-afio-or-slice", BLK_STOP_AN_AFIO_OR_SLICE);
[128]1532 }
1533 }
[2520]1534 mr_free(fname);
[128]1535 }
1536 log_msg(2, "Finished writing back catalog to tape");
1537 return (res);
[1]1538}
1539
1540
1541
1542/**
1543 * Write all.tar.gz (produced by Mindi) to the first 32M of the first tape.
1544 * @param fname The path to all.tar.gz.
1545 * @return 0 for success, nonzero for failure.
1546 */
[128]1547int write_data_disks_to_stream(char *fname)
[1]1548{
[128]1549 /*@ pointers *************************************************** */
1550 FILE *fin;
[1]1551
[128]1552 /*@ long ******************************************************* */
1553 long m = -1;
1554 long templong;
[1]1555
[128]1556 /*@ int ******************************************************** */
1557 int i, j;
[1]1558
[128]1559 /*@ buffers **************************************************** */
1560 char tempblock[256 * 1024];
[1]1561
[128]1562 /*@ end vars *************************************************** */
[1]1563
[541]1564 open_evalcall_form("Writing data disks to tape");
1565 log_to_screen("Writing data disks to tape");
[128]1566 log_it("Data disks = %s", fname);
1567 if (!does_file_exist(fname)) {
[3191]1568 log_to_screen("Cannot find %s", fname);
[128]1569 return (1);
[1]1570 }
[128]1571 if (!(fin = fopen(fname, "r"))) {
1572 log_OS_error(fname);
1573 fatal_error("Cannot openin the data disk");
1574 }
1575 for (i = 0; i < 32; i++) { /* 32MB */
1576 for (j = 0; j < 4; j++) { /* 256K x 4 = 1MB (1024K) */
1577 if (!feof(fin)) {
1578 m = (long) fread(tempblock, 1, 256 * 1024, fin);
1579 } else {
1580 m = 0;
1581 }
1582 for (; m < 256 * 1024; m++) {
1583 tempblock[m] = '\0';
1584 }
1585 g_tape_posK +=
1586 fwrite(tempblock, 1, 256 * 1024, g_tape_stream) / 1024;
1587 }
1588 if (i > g_tape_buffer_size_MB) // otherwise, 'buffer' distorts calculations
1589 {
1590 templong = ((i - 8) * 4 + j) * 100 / (128 - 8 * 4);
1591 update_evalcall_form((int) (templong));
1592 }
1593 }
1594 paranoid_fclose(fin);
1595 close_evalcall_form();
1596 return (0);
[1]1597}
1598
1599
1600
1601
1602/**
1603 * Copy @p infile to the opened stream (CD or tape).
1604 * @param bkpinfo The backup information structure. @c bkpinfo->media_size is the only field used.
1605 * @param infile The file to write to the stream.
1606 * @return 0 for success, nonzero for failure.
1607 */
[1645]1608int write_file_to_stream_from_file(char *infile)
[1]1609{
[128]1610 /*@ buffers **************************************************** */
1611 char datablock[TAPE_BLOCK_SIZE];
[2520]1612 char *checksum = NULL;
[128]1613 char *infile_basename;
[1]1614
[128]1615 /*@ int ******************************************************** */
1616 int retval = 0;
1617 int noof_blocks;
[1]1618
[128]1619 /* unsigned int ch; */
1620 unsigned int crc16;
1621 unsigned int crctt;
[1]1622
[128]1623 /*@ pointers *************************************************** */
1624 FILE *fin;
1625 char *p;
[1]1626
[128]1627 /*@ long ******************************************************* */
1628 long bytes_to_read = 0;
1629 long i;
[1]1630
[684]1631 off_t filesize;
[1]1632
1633#ifdef EXTRA_TAPE_CHECKSUMS
[128]1634 int ch;
[1]1635#endif
1636
[128]1637 /*@ initialize ************************************************ */
1638 crc16 = 0;
1639 crctt = 0;
[1]1640
1641
1642
[128]1643 /*@ end vars *************************************************** */
[1]1644
[128]1645 infile_basename = strrchr(infile, '/');
1646 if (infile_basename) {
1647 infile_basename++;
1648 } else {
1649 infile_basename = infile;
1650 }
1651 filesize = length_of_file(infile);
[3860]1652 if (should_we_write_to_next_tape(bkpinfo->media_size, filesize)) {
[1645]1653 start_to_write_to_next_tape();
1654 write_backcatalog_to_tape();
[128]1655 }
1656 p = strrchr(infile, '/');
1657 if (!p) {
1658 p = infile;
1659 } else {
1660 p++;
1661 }
[3191]1662 log_it("Writing file '%s' to tape (%ld KB)", p, (long) filesize >> 10);
[3860]1663 write_header_block_to_stream(filesize, infile_basename, BLK_START_FILE);
[1]1664//go_here_to_restart_saving_of_file:
[128]1665 if (!(fin = fopen(infile, "r"))) {
1666 log_OS_error(infile);
1667 return (1);
[1]1668 }
[128]1669 for (noof_blocks = 0; filesize > 0;
1670 noof_blocks++, filesize -= bytes_to_read) {
1671 if (filesize < TAPE_BLOCK_SIZE) {
1672 bytes_to_read = (long) filesize;
1673 for (i = 0; i < TAPE_BLOCK_SIZE; i++) {
1674 datablock[i] = '\0';
1675 }
1676 } else {
1677 bytes_to_read = TAPE_BLOCK_SIZE;
1678 }
[3060]1679 if (fread(datablock, 1, (size_t) bytes_to_read, fin)) {
1680 // FIXME
1681 }
[128]1682 g_tape_posK +=
1683 fwrite(datablock, 1, /*bytes_to_read */
1684 (size_t) TAPE_BLOCK_SIZE,
1685 g_tape_stream) / 1024;
1686 if (g_sigpipe) {
[2230]1687 log_it("Sigpipe occurred recently. I'll start a new tape.");
[128]1688 fclose(fin);
1689 g_sigpipe = FALSE;
[1645]1690 start_to_write_to_next_tape();
1691 write_backcatalog_to_tape(); // kinda-sorta recursive :)
[128]1692 return (0);
1693 }
[1]1694#ifdef EXTRA_TAPE_CHECKSUMS
[128]1695 for (i = 0; i < bytes_to_read; i++) {
1696 ch = datablock[i];
1697 crc16 = updcrcr(crc16, (unsigned) ch);
1698 crctt = updcrc(crctt, (unsigned) ch);
1699 }
[1]1700#endif
[128]1701 }
1702 paranoid_fclose(fin);
[3185]1703 mr_asprintf(checksum, "%04x%04x", crc16, crctt);
[3430]1704 /* TODO: what does it do ??? */
[2520]1705 write_header_block_to_stream((off_t)g_current_media_number, checksum, BLK_STOP_FILE);
1706 mr_free(checksum);
1707
[1]1708// log_it("File '%s' written to tape.", infile);
[128]1709 return (retval);
[1]1710}
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723/**
1724 * Log (to screen) an erroneous marker, along with what it should have been.
1725 * @param should_be What we were expecting.
1726 * @param it_is What we got.
1727 */
[128]1728void wrong_marker(int should_be, int it_is)
[1]1729{
[3611]1730 char *tmp1 = NULL;
1731 char *tmp2 = NULL;
1732 tmp1 = marker_to_string(should_be);
1733 tmp2 = marker_to_string(it_is);
1734 log_to_screen("Wrong marker! (Should be %s, is actually %s)", tmp1, tmp2);
1735 mr_free(tmp1);
1736 mr_free(tmp2);
[1]1737}
1738
1739/* @} - end of streamGroup */
Note: See TracBrowser for help on using the repository browser.