]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/btape.c
Watchdog updates
[bacula/bacula] / bacula / src / stored / btape.c
1 /*
2  *
3  *   Bacula Tape manipulation program
4  *
5  *    Has various tape manipulation commands -- mostly for
6  *    use in determining how tapes really work.
7  *
8  *     Kern Sibbald, April MM
9  *
10  *   Note, this program reads stored.conf, and will only
11  *     talk to devices that are configured.
12  *
13  *   Version $Id$
14  *
15  */
16 /*
17    Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
18
19    This program is free software; you can redistribute it and/or
20    modify it under the terms of the GNU General Public License as
21    published by the Free Software Foundation; either version 2 of
22    the License, or (at your option) any later version.
23
24    This program is distributed in the hope that it will be useful,
25    but WITHOUT ANY WARRANTY; without even the implied warranty of
26    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27    General Public License for more details.
28
29    You should have received a copy of the GNU General Public
30    License along with this program; if not, write to the Free
31    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
32    MA 02111-1307, USA.
33
34  */
35
36 #include "bacula.h"
37 #include "stored.h"
38
39
40 /* External subroutines */
41 extern void free_config_resources();
42
43 /* Exported variables */
44 int quit = 0;
45 char buf[100000];
46 int bsize = TAPE_BSIZE;
47 char VolName[100];
48
49 DEVICE *dev = NULL;
50 DEVRES *device = NULL;
51
52             
53 /* Forward referenced subroutines */
54 static void do_tape_cmds();
55 static void helpcmd();
56 static void scancmd();
57 static void rewindcmd();
58 static void clearcmd();
59 static void wrcmd();
60 static void eodcmd();
61 static void fillcmd();
62 static void unfillcmd();
63 static int flush_block(DEV_BLOCK *block, int dump);
64 static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec);
65 static int my_mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
66
67
68 /* Static variables */
69 #define CONFIG_FILE "bacula-sd.conf"
70 char *configfile;
71
72 static BSR *bsr = NULL;
73 static char cmd[1000];
74 static int signals = TRUE;
75 static int ok;
76 static int stop;
77 static uint64_t vol_size;
78 static uint64_t VolBytes;
79 static time_t now;
80 static double kbs;
81 static long file_index;
82 static int verbose = 0;
83 static int end_of_tape = 0;
84 static uint32_t LastBlock = 0;
85 static uint32_t eot_block;
86 static uint32_t eot_block_len;
87 static uint32_t eot_FileIndex;
88 static int dumped = 0;
89
90 static char *VolumeName = NULL;
91
92 static JCR *jcr = NULL;
93
94
95 static void usage();
96 static void terminate_btape(int sig);
97 int get_cmd(char *prompt);
98
99
100 int write_dev(DEVICE *dev, char *buf, size_t len) 
101 {
102    Emsg0(M_ABORT, 0, "write_dev not implemented.\n");
103    return 0;
104 }
105
106 int read_dev(DEVICE *dev, char *buf, size_t len)
107 {
108    Emsg0(M_ABORT, 0, "read_dev not implemented.\n");
109    return 0;
110 }
111
112
113 /*********************************************************************
114  *
115  *         Main Bacula Pool Creation Program
116  *
117  */
118 int main(int argc, char *argv[])
119 {
120    int ch;
121    DEV_BLOCK *block;
122
123    /* Sanity checks */
124    if (TAPE_BSIZE % DEV_BSIZE != 0 || TAPE_BSIZE / DEV_BSIZE == 0) {
125       Emsg2(M_ABORT, 0, "Tape block size (%d) not multiple of system size (%d)\n",
126          TAPE_BSIZE, DEV_BSIZE);
127    }
128    if (TAPE_BSIZE != (1 << (ffs(TAPE_BSIZE)-1))) {
129       Emsg1(M_ABORT, 0, "Tape block size (%d) is not a power of 2\n", TAPE_BSIZE);
130    }
131
132    printf("Tape block granularity is %d bytes.\n", TAPE_BSIZE);
133
134    working_directory = "/tmp";
135    my_name_is(argc, argv, "btape");
136    init_msg(NULL, NULL);
137
138    while ((ch = getopt(argc, argv, "b:c:d:sv?")) != -1) {
139       switch (ch) {
140          case 'b':                    /* bootstrap file */
141             bsr = parse_bsr(NULL, optarg);
142 //          dump_bsr(bsr);
143             break;
144
145          case 'c':                    /* specify config file */
146             if (configfile != NULL) {
147                free(configfile);
148             }
149             configfile = bstrdup(optarg);
150             break;
151
152          case 'd':                    /* set debug level */
153             debug_level = atoi(optarg);
154             if (debug_level <= 0) {
155                debug_level = 1; 
156             }
157             break;
158
159          case 's':
160             signals = FALSE;
161             break;
162
163          case 'v':
164             verbose++;
165             break;
166
167          case '?':
168          default:
169             helpcmd();
170             exit(0);
171
172       }  
173    }
174    argc -= optind;
175    argv += optind;
176
177
178    
179    if (signals) {
180       init_signals(terminate_btape);
181    }
182
183    if (configfile == NULL) {
184       configfile = bstrdup(CONFIG_FILE);
185    }
186
187    daemon_start_time = time(NULL);
188
189    parse_config(configfile);
190
191
192    /* See if we can open a device */
193    if (argc == 0) {
194       Pmsg0(000, "No archive name specified.\n");
195       usage();
196       exit(1);
197    } else if (argc != 1) {
198       Pmsg0(000, "Improper number of arguments specified.\n");
199       usage();
200       exit(1);
201    }
202
203    jcr = setup_jcr("btape", argv[0], bsr);
204    dev = setup_to_access_device(jcr, 0);     /* acquire for write */
205    if (!dev) {
206       exit(1);
207    }
208    block = new_block(dev);
209    lock_device(dev);
210    if (!(dev->state & ST_OPENED)) {
211       Dmsg0(129, "Opening device.\n");
212       if (open_dev(dev, jcr->VolumeName, READ_WRITE) < 0) {
213          Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), dev->errmsg);
214          unlock_device(dev);
215          free_block(block);
216          goto terminate;
217       }
218    }
219    Dmsg1(129, "open_dev %s OK\n", dev_name(dev));
220    unlock_device(dev);
221    free_block(block);
222
223    Dmsg0(200, "Do tape commands\n");
224    do_tape_cmds();
225   
226 terminate:
227    terminate_btape(0);
228    return 0;
229 }
230
231 static void terminate_btape(int stat)
232 {
233
234    sm_check(__FILE__, __LINE__, False);
235    if (configfile) {
236       free(configfile);
237    }
238    free_config_resources();
239
240    if (dev) {
241       term_dev(dev);
242    }
243
244    if (debug_level > 10)
245       print_memory_pool_stats(); 
246
247    free_jcr(jcr);
248    jcr = NULL;
249
250    if (bsr) {
251       free_bsr(bsr);
252    }
253
254    term_msg();
255    close_memory_pool();               /* free memory in pool */
256
257    sm_dump(False);
258    exit(stat);
259 }
260
261 void quitcmd()
262 {
263    quit = 1;
264 }
265
266 /*
267  * Write a label to the tape   
268  */
269 static void labelcmd()
270 {
271    DEVRES *device;
272    int found = 0;
273
274    LockRes();
275    for (device=NULL; (device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device)); ) {
276       if (strcmp(device->device_name, dev->dev_name) == 0) {
277          jcr->device = device;        /* Arggg a bit of duplication here */
278          device->dev = dev;
279          dev->device = device;
280          found = 1;
281          break;
282       }
283    } 
284    UnlockRes();
285    if (!found) {
286       Pmsg2(0, "Could not find device %s in %s\n", dev->dev_name, configfile);
287       return;
288    }
289
290    if (VolumeName) {
291       strcpy(cmd, VolumeName);
292    } else {
293       if (!get_cmd("Enter Volume Name: ")) {
294          return;
295       }
296    }
297          
298    if (!(dev->state & ST_OPENED)) {
299       if (!open_device(dev)) {
300          Pmsg1(0, "Device open failed. ERR=%s\n", strerror_dev(dev));
301       }
302    }
303    write_volume_label_to_dev(jcr, device, cmd, "Default");
304 }
305
306 /*
307  * Read the tape label   
308  */
309 static void readlabelcmd()
310 {
311    int save_debug_level = debug_level;
312    int stat;
313    DEV_BLOCK *block;
314
315    block = new_block(dev);
316    stat = read_dev_volume_label(jcr, dev, block);
317    switch (stat) {
318       case VOL_NO_LABEL:
319          Pmsg0(0, "Volume has no label.\n");
320          break;
321       case VOL_OK:
322          Pmsg0(0, "Volume label read correctly.\n");
323          break;
324       case VOL_IO_ERROR:
325          Pmsg1(0, "I/O error on device: ERR=%s", strerror_dev(dev));
326          break;
327       case VOL_NAME_ERROR:
328          Pmsg0(0, "Volume name error\n");
329          break;
330       case VOL_CREATE_ERROR:
331          Pmsg1(0, "Error creating label. ERR=%s", strerror_dev(dev));
332          break;
333       case VOL_VERSION_ERROR:
334          Pmsg0(0, "Volume version error.\n");
335          break;
336       case VOL_LABEL_ERROR:
337          Pmsg0(0, "Bad Volume label type.\n");
338          break;
339       default:
340          Pmsg0(0, "Unknown error.\n");
341          break;
342    }
343
344    debug_level = 20;
345    dump_volume_label(dev); 
346    debug_level = save_debug_level;
347    free_block(block);
348 }
349
350
351 /*
352  * Load the tape should have prevously been taken
353  * off line, otherwise this command is not necessary.
354  */
355 static void loadcmd()
356 {
357
358    if (!load_dev(dev)) {
359       Pmsg1(0, "Bad status from load. ERR=%s\n", strerror_dev(dev));
360    } else
361       Pmsg1(0, "Loaded %s\n", dev_name(dev));
362 }
363
364 /*
365  * Rewind the tape.   
366  */
367 static void rewindcmd()
368 {
369    if (!rewind_dev(dev)) {
370       Pmsg1(0, "Bad status from rewind. ERR=%s\n", strerror_dev(dev));
371       clrerror_dev(dev, -1);
372    } else {
373       Pmsg1(0, "Rewound %s\n", dev_name(dev));
374    }
375 }
376
377 /*
378  * Clear any tape error   
379  */
380 static void clearcmd()
381 {
382    clrerror_dev(dev, -1);
383 }
384
385 /*
386  * Write and end of file on the tape   
387  */
388 static void weofcmd()
389 {
390    int stat;
391
392    if ((stat = weof_dev(dev, 1)) < 0) {
393       Pmsg2(0, "Bad status from weof %d. ERR=%s\n", stat, strerror_dev(dev));
394       return;
395    } else {
396       Pmsg1(0, "Wrote EOF to %s\n", dev_name(dev));
397    }
398 }
399
400
401 /* Go to the end of the medium -- raw command   
402  * The idea was orginally that the end of the Bacula
403  * medium would be flagged differently. This is not
404  * currently the case. So, this is identical to the
405  * eodcmd().
406  */
407 static void eomcmd()
408 {
409    if (!eod_dev(dev)) {
410       Pmsg1(0, _("Bad status from eod. ERR=%s\n"), strerror_dev(dev));
411       return;
412    } else {
413       Pmsg0(0, _("Moved to end of media\n"));
414    }
415 }
416
417 /*
418  * Go to the end of the media (either hardware determined
419  *  or defined by two eofs.
420  */
421 static void eodcmd()
422 {
423    eomcmd();
424 }
425
426 /*
427  * Backspace file   
428  */
429 static void bsfcmd()
430 {
431    int stat;
432
433    if ((stat=bsf_dev(dev, 1)) < 0) {
434       Pmsg1(0, _("Bad status from bsf. ERR=%s\n"), strerror(errno));
435    } else {
436       Pmsg0(0, _("Back spaced one file.\n"));
437    }
438 }
439
440 /*
441  * Backspace record   
442  */
443 static void bsrcmd()
444 {
445    int stat;
446
447    if ((stat=bsr_dev(dev, 1)) < 0) {
448       Pmsg1(0, _("Bad status from bsr. ERR=%s\n"), strerror(errno));
449    } else {
450       Pmsg0(0, _("Back spaced one record.\n"));
451    }
452 }
453
454 /*
455  * List device capabilities as defined in the 
456  *  stored.conf file.
457  */
458 static void capcmd()
459 {
460    printf(_("Device capabilities:\n"));
461    printf("%sEOF ", dev->capabilities & CAP_EOF ? "" : "!");
462    printf("%sBSR ", dev->capabilities & CAP_BSR ? "" : "!");
463    printf("%sBSF ", dev->capabilities & CAP_BSF ? "" : "!");
464    printf("%sFSR ", dev->capabilities & CAP_FSR ? "" : "!");
465    printf("%sFSF ", dev->capabilities & CAP_FSF ? "" : "!");
466    printf("%sEOM ", dev->capabilities & CAP_EOM ? "" : "!");
467    printf("%sREM ", dev->capabilities & CAP_REM ? "" : "!");
468    printf("%sRACCESS ", dev->capabilities & CAP_RACCESS ? "" : "!");
469    printf("%sAUTOMOUNT ", dev->capabilities & CAP_AUTOMOUNT ? "" : "!");
470    printf("%sLABEL ", dev->capabilities & CAP_LABEL ? "" : "!");
471    printf("%sANONVOLS ", dev->capabilities & CAP_ANONVOLS ? "" : "!");
472    printf("%sALWAYSOPEN ", dev->capabilities & CAP_ALWAYSOPEN ? "" : "!");
473    printf("\n");
474
475    printf(_("Device status:\n"));
476    printf("%sOPENED ", dev->state & ST_OPENED ? "" : "!");
477    printf("%sTAPE ", dev->state & ST_TAPE ? "" : "!");
478    printf("%sLABEL ", dev->state & ST_LABEL ? "" : "!");
479    printf("%sMALLOC ", dev->state & ST_MALLOC ? "" : "!");
480    printf("%sAPPEND ", dev->state & ST_APPEND ? "" : "!");
481    printf("%sREAD ", dev->state & ST_READ ? "" : "!");
482    printf("%sEOT ", dev->state & ST_EOT ? "" : "!");
483    printf("%sWEOT ", dev->state & ST_WEOT ? "" : "!");
484    printf("%sEOF ", dev->state & ST_EOF ? "" : "!");
485    printf("%sNEXTVOL ", dev->state & ST_NEXTVOL ? "" : "!");
486    printf("%sSHORT ", dev->state & ST_SHORT ? "" : "!");
487    printf("\n");
488
489 }
490
491 /*
492  * Test writting larger and larger records.  
493  * This is a torture test for records.
494  */
495 static void rectestcmd()
496 {
497    DEV_BLOCK *block;
498    DEV_RECORD *rec;
499    int i, blkno = 0;
500
501    Pmsg0(0, "Test writting larger and larger records.\n\
502 This is a torture test for records.\nI am going to write\n\
503 larger and larger records. It will stop when the record size\n\
504 plus the header exceeds the block size (by default about 64K\n");
505
506
507    get_cmd("Do you want to continue? (y/n): ");
508    if (cmd[0] != 'y') {
509       Pmsg0(000, "Command aborted.\n");
510       return;
511    }
512
513    sm_check(__FILE__, __LINE__, False);
514    block = new_block(dev);
515    rec = new_record();
516
517    for (i=1; i<500000; i++) {
518       rec->data = check_pool_memory_size(rec->data, i);
519       memset(rec->data, i & 0xFF, i);
520       rec->data_len = i;
521       sm_check(__FILE__, __LINE__, False);
522       if (write_record_to_block(block, rec)) {
523          empty_block(block);
524          blkno++;
525          Pmsg2(0, "Block %d i=%d\n", blkno, i);
526       } else {
527          break;
528       }
529       sm_check(__FILE__, __LINE__, False);
530    }
531    free_record(rec);
532    free_block(block);
533    sm_check(__FILE__, __LINE__, False);
534 }
535
536 /* 
537  * This is a general test of Bacula's functions
538  *   needed to read and write the tape.
539  */
540 static void testcmd()
541 {
542    DEV_BLOCK *block;
543    DEV_RECORD *rec;
544    int len;
545
546    Pmsg0(0, "\nWrite, backup, and re-read test.\n\n"
547 "I'm going to write three records and two eof's\n"
548 "then backup over the eof's and re-read the last record.\n\n");
549    rewindcmd();
550    block = new_block(dev);
551    rec = new_record();
552    rec->data = check_pool_memory_size(rec->data, block->buf_len);
553    len = rec->data_len = block->buf_len-100;
554    memset(rec->data, 1, rec->data_len);
555    if (!write_record_to_block(block, rec)) {
556       Pmsg0(0, "Error writing record to block.\n"); 
557       goto bail_out;
558    }
559    if (!write_block_to_dev(jcr, dev, block)) {
560       Pmsg0(0, "Error writing block to device.\n"); 
561       goto bail_out;
562    } else {
563       Pmsg1(0, "Wrote one record of %d bytes.\n", rec->data_len);
564    }
565    memset(rec->data, 2, rec->data_len);
566    if (!write_record_to_block(block, rec)) {
567       Pmsg0(0, "Error writing record to block.\n"); 
568       goto bail_out;
569    }
570    if (!write_block_to_dev(jcr, dev, block)) {
571       Pmsg0(0, "Error writing block to device.\n"); 
572       goto bail_out;
573    } else {
574       Pmsg1(0, "Wrote one record of %d bytes.\n", rec->data_len);
575    }
576    memset(rec->data, 3, rec->data_len);
577    if (!write_record_to_block(block, rec)) {
578       Pmsg0(0, "Error writing record to block.\n"); 
579       goto bail_out;
580    }
581    if (!write_block_to_dev(jcr, dev, block)) {
582       Pmsg0(0, "Error writing block to device.\n"); 
583       goto bail_out;
584    } else {
585       Pmsg1(0, "Wrote one record of %d bytes.\n", rec->data_len);
586    }
587    weofcmd();
588    weofcmd();
589    if (bsf_dev(dev, 1) != 0) {
590       Pmsg1(0, "Back space file failed! ERR=%s\n", strerror(dev->dev_errno));
591       goto bail_out;
592    }
593    if (bsf_dev(dev, 1) != 0) {
594       Pmsg1(0, "Back space file failed! ERR=%s\n", strerror(dev->dev_errno));
595       goto bail_out;
596    }
597    Pmsg0(0, "Backspaced over two EOFs OK.\n");
598    if (bsr_dev(dev, 1) != 0) {
599       Pmsg1(0, "Back space record failed! ERR=%s\n", strerror(dev->dev_errno));
600       goto bail_out;
601    }
602    Pmsg0(0, "Backspace record OK.\n");
603    if (!read_block_from_dev(dev, block)) {
604       Pmsg1(0, "Read block failed! ERR=%s\n", strerror(dev->dev_errno));
605       goto bail_out;
606    }
607    memset(rec->data, 0, rec->data_len);
608    if (!read_record_from_block(block, rec)) {
609       Pmsg1(0, "Read block failed! ERR=%s\n", strerror(dev->dev_errno));
610       goto bail_out;
611    }
612    for (int i=0; i<len; i++) {
613       if (rec->data[i] != 3) {
614          Pmsg0(0, "Bad data in record. Test failed!\n");
615          goto bail_out;
616       }
617    }
618    Pmsg0(0, "Test succeeded!\n\n");
619
620
621    Pmsg0(0, "\nAppend files test.\n\n"
622 "I'm going to write one record  in file 0,\n"
623 "                   two records in file 1,\n"
624 "             and three records in file 2\n\n");
625    rewindcmd();
626    wrcmd();
627    weofcmd();      /* end file 0 */
628    wrcmd();
629    wrcmd();
630    weofcmd();      /* end file 1 */
631    wrcmd();
632    wrcmd();
633    wrcmd();
634    weofcmd();     /* end file 2 */
635 //   weofcmd();
636    rewindcmd();
637    Pmsg0(0, "Now moving to end of media.\n");
638    eodcmd();
639    Pmsg2(0, "End Append files test.\n\
640 We should be in file 3. I am at file %d. This is %s\n\n", 
641       dev->file, dev->file == 3 ? "correct!" : "NOT correct!!!!");
642
643    Pmsg0(0, "\nNow I am going to attempt to append to the tape.\n");
644    wrcmd(); 
645    weofcmd();
646 //   weofcmd();
647    rewindcmd();
648    Pmsg0(0, "Done writing, scanning results ...\n\n");
649    scancmd();
650    Pmsg0(0, "End Append to the tape test.\n\
651 The above scan should have four files of:\n\
652 One record, two records, three records, and one record \n\
653 respectively each with 64,512 bytes.\n\n");
654
655
656    Pmsg0(0, "Append block test.\n\
657 I'm going to write a block, an EOF, rewind, go to EOM,\n\
658 then backspace over the EOF and attempt to append a second\n\
659 block in the first file.\n\n");
660    rewindcmd();
661    wrcmd();
662    weofcmd();
663 //   weofcmd();
664    rewindcmd();
665    eodcmd();
666    Pmsg2(0, "We should be at file 1. I am at EOM File=%d. This is %s\n",
667       dev->file, dev->file == 1 ? "correct!" : "NOT correct!!!!");
668    Pmsg0(0, "Doing backspace file.\n");
669    bsfcmd();
670    Pmsg0(0, "Write second block, hoping to append to first file.\n");
671    wrcmd();
672    weofcmd();
673    rewindcmd();
674    Pmsg0(0, "Done writing, scanning results ...\n\n");
675    scancmd();
676    Pmsg0(0, "The above should have one file of two blocks 64,512 bytes each.\n");
677 bail_out:
678    free_record(rec);
679    free_block(block);
680 }
681
682
683 static void fsfcmd()
684 {
685    int stat;
686
687    if ((stat=fsf_dev(dev, 1)) < 0) {
688       Pmsg2(0, "Bad status from fsf %d. ERR=%s\n", stat, strerror_dev(dev));
689       return;
690    }
691    Pmsg0(0, "Forward spaced one file.\n");
692 }
693
694 static void fsrcmd()
695 {
696    int stat;
697
698    if ((stat=fsr_dev(dev, 1)) < 0) {
699       Pmsg2(0, "Bad status from fsr %d. ERR=%s\n", stat, strerror_dev(dev));
700       return;
701    }
702    Pmsg0(0, "Forward spaced one record.\n");
703 }
704
705 static void rdcmd()
706 {
707 #ifdef xxxxx
708    int stat;
709
710    if (!read_dev(dev, buf, 512*126)) {
711       Pmsg1(0, "Bad status from read. ERR=%s\n", strerror_dev(dev));
712       return;
713    }
714    Pmsg1(10, "Read %d bytes\n", stat);
715 #else
716    printf("Rdcmd no longer implemented.\n");
717 #endif
718 }
719
720
721 static void wrcmd()
722 {
723    DEV_BLOCK *block;
724    DEV_RECORD *rec;
725    int i;
726
727    sm_check(__FILE__, __LINE__, False);
728    block = new_block(dev);
729    rec = new_record();
730    dump_block(block, "test");
731
732    i = block->buf_len - 100;
733    ASSERT (i > 0);
734    rec->data = check_pool_memory_size(rec->data, i);
735    memset(rec->data, i & 0xFF, i);
736    rec->data_len = i;
737    sm_check(__FILE__, __LINE__, False);
738    if (!write_record_to_block(block, rec)) {
739       Pmsg0(0, "Error writing record to block.\n"); 
740       goto bail_out;
741    }
742    if (!write_block_to_dev(jcr, dev, block)) {
743       Pmsg0(0, "Error writing block to device.\n"); 
744       goto bail_out;
745    } else {
746       Pmsg1(0, "Wrote one record of %d bytes.\n",
747          ((i+TAPE_BSIZE-1)/TAPE_BSIZE) * TAPE_BSIZE);
748    }
749    Pmsg0(0, "Wrote block to device.\n");
750
751 bail_out:
752    sm_check(__FILE__, __LINE__, False);
753    free_record(rec);
754    free_block(block);
755    sm_check(__FILE__, __LINE__, False);
756 }
757
758
759 /*
760  * Scan tape by reading block by block. Report what is
761  * on the tape.
762  */
763 static void scancmd()
764 {
765    int stat;
766    int blocks, tot_blocks, tot_files;
767    int block_size;
768    uint64_t bytes;
769
770
771    blocks = block_size = tot_blocks = 0;
772    bytes = 0;
773    if (dev->state & ST_EOT) {
774       Pmsg0(0, "End of tape\n");
775       return; 
776    }
777    update_pos_dev(dev);
778    tot_files = dev->file;
779    for (;;) {
780       if ((stat = read(dev->fd, buf, sizeof(buf))) < 0) {
781          clrerror_dev(dev, -1);
782          Mmsg2(&dev->errmsg, "read error on %s. ERR=%s.\n",
783             dev->dev_name, strerror(dev->dev_errno));
784          Pmsg2(0, "Bad status from read %d. ERR=%s\n", stat, strerror_dev(dev));
785          if (blocks > 0)
786             printf("%d block%s of %d bytes in file %d\n",        
787                     blocks, blocks>1?"s":"", block_size, dev->file);
788          return;
789       }
790       Dmsg1(200, "read status = %d\n", stat);
791 /*    sleep(1); */
792       if (stat != block_size) {
793          update_pos_dev(dev);
794          if (blocks > 0) {
795             printf("%d block%s of %d bytes in file %d\n", 
796                  blocks, blocks>1?"s":"", block_size, dev->file);
797             blocks = 0;
798          }
799          block_size = stat;
800       }
801       if (stat == 0) {                /* EOF */
802          update_pos_dev(dev);
803          printf("End of File mark.\n");
804          /* Two reads of zero means end of tape */
805          if (dev->state & ST_EOF)
806             dev->state |= ST_EOT;
807          else {
808             dev->state |= ST_EOF;
809             dev->file++;
810          }
811          if (dev->state & ST_EOT) {
812             printf("End of tape\n");
813             break;
814          }
815       } else {                        /* Got data */
816          dev->state &= ~ST_EOF;
817          blocks++;
818          tot_blocks++;
819          bytes += stat;
820       }
821    }
822    update_pos_dev(dev);
823    tot_files = dev->file - tot_files;
824    printf("Total files=%d, blocks=%d, bytes = %" lld "\n", tot_files, tot_blocks, bytes);
825 }
826
827 static void statcmd()
828 {
829    int stat = 0;
830    int debug;
831    uint32_t status;
832
833    debug = debug_level;
834    debug_level = 30;
835    if (!status_dev(dev, &status)) {
836       Pmsg2(0, "Bad status from status %d. ERR=%s\n", stat, strerror_dev(dev));
837    }
838 #ifdef xxxx
839    dump_volume_label(dev);
840 #endif
841    debug_level = debug;
842 }
843
844
845 /* 
846  * First we label the tape, then we fill
847  *  it with data get a new tape and write a few blocks.
848  */                            
849 static void fillcmd()
850 {
851    DEV_RECORD rec;
852    DEV_BLOCK  *block;
853    char ec1[50];
854    char *p;
855
856    ok = TRUE;
857    stop = FALSE;
858
859    Pmsg0(000, "\n\
860 This command simulates Bacula writing to a tape.\n\
861 It command requires two blank tapes, which it\n\
862 will label and write. It will print a status approximately\n\
863 every 322 MB, and write an EOF every 3.2 GB.  When the first tape\n\
864 fills, it will ask for a second, and after writing a few \n\
865 blocks, it will stop.  Then it will begin re-reading the\n\
866 This may take a long time. I.e. hours! ...\n\n");
867
868    get_cmd("Insert a blank tape then answer. Do you wish to continue? (y/n): ");
869    if (cmd[0] != 'y') {
870       Pmsg0(000, "Command aborted.\n");
871       return;
872    }
873
874    VolumeName = "TestVolume1";
875    labelcmd();
876    VolumeName = NULL;
877
878    
879    Dmsg1(20, "Begin append device=%s\n", dev_name(dev));
880
881    block = new_block(dev);
882
883    /* 
884     * Acquire output device for writing.  Note, after acquiring a
885     *   device, we MUST release it, which is done at the end of this
886     *   subroutine.
887     */
888    Dmsg0(100, "just before acquire_device\n");
889    if (!acquire_device_for_append(jcr, dev, block)) {
890       jcr->JobStatus = JS_Cancelled;
891       free_block(block);
892       return;
893    }
894
895    Dmsg0(100, "Just after acquire_device_for_append\n");
896    /*
897     * Write Begin Session Record
898     */
899    if (!write_session_label(jcr, block, SOS_LABEL)) {
900       jcr->JobStatus = JS_Cancelled;
901       Jmsg1(jcr, M_FATAL, 0, _("Write session label failed. ERR=%s\n"),
902          strerror_dev(dev));
903       ok = FALSE;
904    }
905
906    memset(&rec, 0, sizeof(rec));
907    rec.data = get_memory(100000);     /* max record size */
908    /* 
909     * Fill write buffer with random data
910     */
911 #define REC_SIZE 32768
912    p = rec.data;
913    for (int i=0; i < REC_SIZE; ) {
914       makeSessionKey(p, NULL, 0);
915       p += 16;
916       i += 16;
917    }
918    rec.data_len = REC_SIZE;
919
920    /* 
921     * Get Data from File daemon, write to device   
922     */
923    jcr->VolFirstFile = 0;
924    time(&jcr->run_time);              /* start counting time for rates */
925    for (file_index = 0; ok && !job_cancelled(jcr); ) {
926       uint64_t *lp;
927       rec.VolSessionId = jcr->VolSessionId;
928       rec.VolSessionTime = jcr->VolSessionTime;
929       rec.FileIndex = ++file_index;
930       rec.Stream = STREAM_FILE_DATA;
931       /* Write file_index at beginning of buffer */
932       lp = (uint64_t *)rec.data;
933       *lp = (uint64_t)file_index;
934
935       Dmsg4(250, "before writ_rec FI=%d SessId=%d Strm=%s len=%d\n",
936          rec.FileIndex, rec.VolSessionId, stream_to_ascii(rec.Stream, rec.FileIndex), 
937          rec.data_len);
938        
939       if (!write_record_to_block(block, &rec)) {
940          Dmsg2(150, "!write_record_to_block data_len=%d rem=%d\n", rec.data_len,
941                     rec.remainder);
942
943          /* Write block to tape */
944          if (!flush_block(block, 1)) {
945             return;
946          }
947
948          /* Every 5000 blocks (approx 322MB) report where we are.
949           */
950          if ((block->BlockNumber % 5000) == 0) {
951             now = time(NULL);
952             now -= jcr->run_time;
953             if (now <= 0) {
954                now = 1;
955             }
956             kbs = (double)dev->VolCatInfo.VolCatBytes / (1000 * now);
957             Pmsg3(000, "Wrote block=%u, VolBytes=%s rate=%.1f KB/s\n", block->BlockNumber,
958                edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, ec1), (float)kbs);
959          }
960          /* Every 50000 blocks (approx 3.2MB) write an eof.
961           */
962          if ((block->BlockNumber % 50000) == 0) {
963             Pmsg0(000, "Flush block, write EOF\n");
964             flush_block(block, 0);
965             weof_dev(dev, 1);
966             /* The weof resets the block number */
967          }
968
969          if (block->BlockNumber > 10 && stop) {      /* get out */
970             break;
971          }
972       }
973       if (!ok) {
974          Pmsg0(000, "Not OK\n");
975          break;
976       }
977       jcr->JobBytes += rec.data_len;   /* increment bytes this job */
978       Dmsg4(190, "write_record FI=%s SessId=%d Strm=%s len=%d\n",
979          FI_to_ascii(rec.FileIndex), rec.VolSessionId, 
980          stream_to_ascii(rec.Stream, rec.FileIndex), rec.data_len);
981    }
982    Dmsg0(000, "Write_end_session_label()\n");
983    /* Create Job status for end of session label */
984    if (!job_cancelled(jcr) && ok) {
985       jcr->JobStatus = JS_Terminated;
986    } else if (!ok) {
987       jcr->JobStatus = JS_ErrorTerminated;
988    }
989    if (!write_session_label(jcr, block, EOS_LABEL)) {
990       Pmsg1(000, _("Error writting end session label. ERR=%s\n"), strerror_dev(dev));
991       ok = FALSE;
992    }
993    /* Write out final block of this session */
994    if (!write_block_to_device(jcr, dev, block)) {
995       Pmsg0(000, "Set ok=FALSE after write_block_to_device.\n");
996       ok = FALSE;
997    }
998
999    /* Release the device */
1000    if (!release_device(jcr, dev)) {
1001       Pmsg0(000, "Error in release_device\n");
1002       ok = FALSE;
1003    }
1004
1005    free_block(block);
1006    free_memory(rec.data);
1007    Pmsg0(000, "Done with fill command. Now beginning re-read of tapes...\n");
1008
1009    unfillcmd();
1010 }
1011
1012 /*
1013  * Read two tapes written by the "fill" command and ensure
1014  *  that the data is valid.
1015  */
1016 static void unfillcmd()
1017 {
1018    DEV_BLOCK *block;
1019
1020    dumped = 0;
1021    VolBytes = 0;
1022    LastBlock = 0;
1023    block = new_block(dev);
1024
1025    dev->capabilities |= CAP_ANONVOLS; /* allow reading any volume */
1026    dev->capabilities &= ~CAP_LABEL;   /* don't label anything here */
1027
1028    end_of_tape = 0;
1029    get_cmd("Mount first of two tapes. Press enter when ready: "); 
1030    
1031    free_vol_list(jcr);
1032    pm_strcpy(&jcr->VolumeName, "TestVolume1");
1033    jcr->bsr = NULL;
1034    create_vol_list(jcr);
1035    close_dev(dev);
1036    dev->state &= ~ST_READ;
1037    if (!acquire_device_for_read(jcr, dev, block)) {
1038       Pmsg0(000, dev->errmsg);
1039       return;
1040    }
1041
1042    time(&jcr->run_time);              /* start counting time for rates */
1043    stop = 0;
1044    file_index = 0;
1045    read_records(jcr, dev, record_cb, my_mount_next_read_volume);
1046    free_block(block);
1047
1048    Pmsg0(000, "Done with unfillcmd.\n");
1049 }
1050
1051
1052 /* 
1053  * We are called here from "unfill" for each record on the
1054  *   tape.
1055  */
1056 static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
1057 {
1058
1059    SESSION_LABEL label;
1060    if (stop > 1) {                    /* on second tape */
1061       Pmsg4(000, "Blk: FileIndex=%d: block=%u size=%d vol=%s\n", 
1062            rec->FileIndex, block->BlockNumber, block->block_len, dev->VolHdr.VolName);
1063       Pmsg6(000, "   Rec: VId=%d VT=%d FI=%s Strm=%s len=%d state=%x\n",
1064            rec->VolSessionId, rec->VolSessionTime, 
1065            FI_to_ascii(rec->FileIndex), stream_to_ascii(rec->Stream, rec->FileIndex),
1066            rec->data_len, rec->state);
1067
1068       if (!dumped) {
1069          dumped = 1;
1070          dump_block(block, "Block not written to previous tape");
1071       }
1072    }
1073    if (rec->FileIndex < 0) {
1074       if (verbose > 1) {
1075          dump_label_record(dev, rec, 1);
1076       }
1077       switch (rec->FileIndex) {
1078          case PRE_LABEL:
1079             Pmsg0(000, "Volume is prelabeled. This tape cannot be scanned.\n");
1080             return;
1081          case VOL_LABEL:
1082             unser_volume_label(dev, rec);
1083             Pmsg3(000, "VOL_LABEL: block=%u size=%d vol=%s\n", block->BlockNumber, 
1084                block->block_len, dev->VolHdr.VolName);
1085             stop++;
1086             break;
1087          case SOS_LABEL:
1088             unser_session_label(&label, rec);
1089             Pmsg1(000, "SOS_LABEL: JobId=%u\n", label.JobId);
1090             break;
1091          case EOS_LABEL:
1092             unser_session_label(&label, rec);
1093             Pmsg2(000, "EOS_LABEL: block=%u JobId=%u\n", block->BlockNumber, 
1094                label.JobId);
1095             break;
1096          case EOM_LABEL:
1097             Pmsg0(000, "EOM_LABEL:\n");
1098             break;
1099          case EOT_LABEL:              /* end of all tapes */
1100             char ec1[50];
1101
1102             if (LastBlock != block->BlockNumber) {
1103                VolBytes += block->block_len;
1104             }
1105             LastBlock = block->BlockNumber;
1106             now = time(NULL);
1107             now -= jcr->run_time;
1108             if (now <= 0) {
1109                now = 1;
1110             }
1111             kbs = (double)VolBytes / (1000 * now);
1112             Pmsg3(000, "Read block=%u, VolBytes=%s rate=%.1f KB/s\n", block->BlockNumber,
1113                      edit_uint64_with_commas(VolBytes, ec1), (float)kbs);
1114
1115             Pmsg0(000, "End of all tapes.\n");
1116
1117             break;
1118          default:
1119             break;
1120       }
1121       return;
1122    }
1123    if (LastBlock != block->BlockNumber) {
1124       VolBytes += block->block_len;
1125    }
1126    if ((block->BlockNumber != LastBlock) && (block->BlockNumber % 50000) == 0) {
1127       char ec1[50];
1128       now = time(NULL);
1129       now -= jcr->run_time;
1130       if (now <= 0) {
1131          now = 1;
1132       }
1133       kbs = (double)VolBytes / (1000 * now);
1134       Pmsg3(000, "Read block=%u, VolBytes=%s rate=%.1f KB/s\n", block->BlockNumber,
1135                edit_uint64_with_commas(VolBytes, ec1), (float)kbs);
1136    }
1137    LastBlock = block->BlockNumber;
1138    if (end_of_tape) {
1139       Pmsg1(000, "End of all blocks. Block=%u\n", block->BlockNumber);
1140    }
1141 }
1142
1143
1144
1145 /*
1146  * Write current block to tape regardless of whether or
1147  *   not it is full. If the tape fills, attempt to
1148  *   acquire another tape.
1149  */
1150 static int flush_block(DEV_BLOCK *block, int dump)
1151 {
1152    char ec1[50];
1153    lock_device(dev);
1154    if (!write_block_to_dev(jcr, dev, block)) {
1155       Pmsg0(000, strerror_dev(dev));            
1156       Pmsg3(000, "Block not written: FileIndex=%u Block=%u Size=%u\n", 
1157          (unsigned)file_index, block->BlockNumber, block->block_len);
1158       if (dump) {
1159          dump_block(block, "Block not written");
1160       }
1161       if (!stop) {
1162          eot_block = block->BlockNumber;
1163          eot_block_len = block->block_len;
1164          eot_FileIndex = file_index;
1165       }
1166       now = time(NULL);
1167       now -= jcr->run_time;
1168       if (now <= 0) {
1169          now = 1;
1170       }
1171       kbs = (double)dev->VolCatInfo.VolCatBytes / (1000 * now);
1172       vol_size = dev->VolCatInfo.VolCatBytes;
1173       Pmsg2(000, "End of tape. VolumeCapacity=%s. Write rate = %.1f KB/s\n", 
1174          edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, ec1), kbs);
1175       if (!fixup_device_block_write_error(jcr, dev, block)) {
1176          Pmsg1(000, _("Cannot fixup device error. %s\n"), strerror_dev(dev));
1177          ok = FALSE;
1178          unlock_device(dev);
1179          return 0;
1180       }
1181       stop = 1;                                                     
1182       unlock_device(dev);
1183       return 1;     /* write one more block to next tape then stop */
1184    }
1185    unlock_device(dev);
1186    return 1;
1187 }
1188
1189
1190 struct cmdstruct { char *key; void (*func)(); char *help; }; 
1191 static struct cmdstruct commands[] = {
1192  {"bsf",        bsfcmd,       "backspace file"},
1193  {"bsr",        bsrcmd,       "backspace record"},
1194  {"cap",        capcmd,       "list device capabilities"},
1195  {"clear",      clearcmd,     "clear tape errors"},
1196  {"eod",        eodcmd,       "go to end of Bacula data for append"},
1197  {"test",       testcmd,      "General test Bacula tape functions"},
1198  {"eom",        eomcmd,       "go to the physical end of medium"},
1199  {"fill",       fillcmd,      "fill tape, write onto second volume"},
1200  {"unfill",     unfillcmd,    "read filled tape"},
1201  {"fsf",        fsfcmd,       "forward space a file"},
1202  {"fsr",        fsrcmd,       "forward space a record"},
1203  {"help",       helpcmd,      "print this command"},
1204  {"label",      labelcmd,     "write a Bacula label to the tape"},
1205  {"load",       loadcmd,      "load a tape"},
1206  {"quit",       quitcmd,      "quit btape"},   
1207  {"rd",         rdcmd,        "read tape"},
1208  {"readlabel",  readlabelcmd, "read and print the Bacula tape label"},
1209  {"rectest",    rectestcmd,   "test record handling functions"},
1210  {"rewind",     rewindcmd,    "rewind the tape"},
1211  {"scan",       scancmd,      "read tape block by block to EOT and report"}, 
1212  {"status",     statcmd,      "print tape status"},
1213  {"weof",       weofcmd,      "write an EOF on the tape"},
1214  {"wr",         wrcmd,        "write a single record of 2048 bytes"}, 
1215              };
1216 #define comsize (sizeof(commands)/sizeof(struct cmdstruct))
1217
1218 static void
1219 do_tape_cmds()
1220 {
1221    unsigned int i;
1222    int found;
1223
1224    while (get_cmd("*")) {
1225       sm_check(__FILE__, __LINE__, False);
1226       found = 0;
1227       for (i=0; i<comsize; i++)       /* search for command */
1228          if (fstrsch(cmd,  commands[i].key)) {
1229             (*commands[i].func)();    /* go execute command */
1230             found = 1;
1231             break;
1232          }
1233       if (!found)
1234          Pmsg1(0, _("%s is an illegal command\n"), cmd);
1235       if (quit)
1236          break;
1237    }
1238 }
1239
1240 static void helpcmd()
1241 {
1242    unsigned int i;
1243    usage();
1244    printf(_("  Command    Description\n  =======    ===========\n"));
1245    for (i=0; i<comsize; i++)
1246       printf("  %-10s %s\n", commands[i].key, commands[i].help);
1247    printf("\n");
1248 }
1249
1250 static void usage()
1251 {
1252    fprintf(stderr, _(
1253 "\nVersion: " VERSION " (" DATE ")\n\n"
1254 "Usage: btape [-c config_file] [-d debug_level] [device_name]\n"
1255 "       -c <file>   set configuration file to file\n"
1256 "       -dnn        set debug level to nn\n"
1257 "       -s          turn off signals\n"
1258 "       -t          open the default tape device\n"
1259 "       -?          print this message.\n"  
1260 "\n"));
1261
1262 }
1263
1264 /*      
1265  * Get next input command from terminal.  This
1266  * routine is REALLY primitive, and should be enhanced
1267  * to have correct backspacing, etc.
1268  */
1269 int 
1270 get_cmd(char *prompt)
1271 {
1272    int i = 0;
1273    int ch;
1274    fprintf(stdout, prompt);
1275
1276    /* We really should turn off echoing and pretty this
1277     * up a bit.
1278     */
1279    cmd[i] = 0;
1280    while ((ch = fgetc(stdin)) != EOF) { 
1281       if (ch == '\n') {
1282          strip_trailing_junk(cmd);
1283          return 1;
1284       } else if (ch == 4 || ch == 0xd3 || ch == 0x8) {
1285          if (i > 0)
1286             cmd[--i] = 0;
1287          continue;
1288       } 
1289          
1290       cmd[i++] = ch;
1291       cmd[i] = 0;
1292    }
1293    quit = 1;
1294    return 0;
1295 }
1296
1297 /* Dummies to replace askdir.c */
1298 int     dir_get_volume_info(JCR *jcr, int writing) { return 1;}
1299 int     dir_find_next_appendable_volume(JCR *jcr) { return 1;}
1300 int     dir_update_volume_info(JCR *jcr, VOLUME_CAT_INFO *vol, int relabel) { return 1; }
1301 int     dir_create_jobmedia_record(JCR *jcr) { return 1; }
1302 int     dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec) { return 1;}
1303 int     dir_send_job_status(JCR *jcr) {return 1;}
1304
1305
1306 int dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev)
1307 {
1308    Pmsg0(000, dev->errmsg);           /* print reason */
1309    fprintf(stderr, "Mount Volume \"%s\" on device %s and press return when ready: ",
1310       jcr->VolumeName, dev_name(dev));
1311    getchar();   
1312    return 1;
1313 }
1314
1315 int dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev)
1316 {
1317    fprintf(stderr, "Mount next Volume on device %s and press return when ready: ",
1318       dev_name(dev));
1319    getchar();   
1320    VolumeName = "TestVolume2";
1321    labelcmd();
1322    VolumeName = NULL;
1323    return 1;
1324 }
1325
1326 static int my_mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
1327 {
1328    char ec1[50];
1329
1330    Pmsg1(000, "End of Volume \"%s\"\n", jcr->VolumeName);
1331
1332    if (LastBlock != block->BlockNumber) {
1333       VolBytes += block->block_len;
1334    }
1335    LastBlock = block->BlockNumber;
1336    now = time(NULL);
1337    now -= jcr->run_time;
1338    if (now <= 0) {
1339       now = 1;
1340    }
1341    kbs = (double)VolBytes / (1000 * now);
1342    Pmsg3(000, "Read block=%u, VolBytes=%s rate=%.1f KB/s\n", block->BlockNumber,
1343             edit_uint64_with_commas(VolBytes, ec1), (float)kbs);
1344
1345    if (strcmp(jcr->VolumeName, "TestVolume2") == 0) {
1346       end_of_tape = 1;
1347       return 0;
1348    }
1349
1350    free_vol_list(jcr);
1351    pm_strcpy(&jcr->VolumeName, "TestVolume2");
1352    jcr->bsr = NULL;
1353    create_vol_list(jcr);
1354    close_dev(dev);
1355    dev->state &= ~ST_READ; 
1356    if (!acquire_device_for_read(jcr, dev, block)) {
1357       Pmsg2(0, "Cannot open Dev=%s, Vol=%s\n", dev_name(dev), jcr->VolumeName);
1358       return 0;
1359    }
1360    return 1;                       /* next volume mounted */
1361 }