3 * Program to test loss of data at EOM on
6 * Kern Sibbald, August 2003
8 * If you build this program with:
10 * c++ -g -O2 -Wall -c tapetest.c
11 * c++ -g -O2 -Wall tapetest.o -o tapetest
13 * Procedure for testing tape
14 * ./tapetest /dev/your-tape-device
25 * *Begin writing blocks of 64512 bytes.
26 * ++++++++++++++++++++ ...
27 * Write failed. Last block written=17294. stat=0 ERR=Unknown error: 0
29 * Wrote EOF to /dev/nsa0
31 * *Starting scan at file 0
32 * 17294 blocks of 64512 bytes in file 0
36 * Total files=1, blocks=17294, bytes = 1115670528
39 * which is correct. Notice that the return status is
40 * 0, while in the example below, which fails, the return
44 * If you build this program with:
46 * c++ -g -O2 -Wall -pthread -c tapetest.c
47 * c++ -g -O2 -Wall -pthread tapetest.o -o tapetest
48 * Note, we simply added -pthread compared to the
51 * Procedure for testing tape
52 * ./tapetest /dev/your-tape-device
63 * *Begin writing blocks of 64512 bytes.
64 * +++++++++++++++++++++++++++++ ...
65 * Write failed. Last block written=17926. stat=-1 ERR=No space left on device
67 * Wrote EOF to /dev/nsa0
69 * *Starting scan at file 0
70 * 17913 blocks of 64512 bytes in file 0
74 * Total files=1, blocks=17913, bytes = 1155603456
77 * which is incroorect because it wrote 17,926 blocks but read
78 * back only 17,913 blocks, AND because the return status on
79 * the last block written was -1 when it should have been
80 * 0 (ie. stat=0 above).
90 #include <sys/ioctl.h>
94 #include <sys/types.h>
102 #define dev_state(dev, state) ((dev)->state & (state))
104 /* Device state bits */
105 #define ST_OPENED (1<<0) /* set when device opened */
106 #define ST_TAPE (1<<1) /* is a tape device */
107 #define ST_FILE (1<<2) /* is a file device */
108 #define ST_FIFO (1<<3) /* is a fifo device */
109 #define ST_PROG (1<<4) /* is a program device */
110 #define ST_LABEL (1<<5) /* label found */
111 #define ST_MALLOC (1<<6) /* dev packet malloc'ed in init_dev() */
112 #define ST_APPEND (1<<7) /* ready for Bacula append */
113 #define ST_READ (1<<8) /* ready for Bacula read */
114 #define ST_EOT (1<<9) /* at end of tape */
115 #define ST_WEOT (1<<10) /* Got EOT on write */
116 #define ST_EOF (1<<11) /* Read EOF i.e. zero bytes */
117 #define ST_NEXTVOL (1<<12) /* Start writing on next volume */
118 #define ST_SHORT (1<<13) /* Short block read */
120 #define BLOCK_SIZE (512 * 126)
123 /* Exported variables */
144 #define uint32_t unsigned long
145 #define uint64_t unsigned long long
147 /* Forward referenced subroutines */
148 static void do_tape_cmds();
149 static void helpcmd();
150 static void scancmd();
151 static void rewindcmd();
152 static void rawfill_cmd();
155 /* Static variables */
157 static char cmd[1000];
160 int get_cmd(char *prompt);
163 /*********************************************************************
165 * Main Bacula Pool Creation Program
168 int main(int argc, char *argv[])
172 while ((ch = getopt(argc, argv, "d:v?")) != -1) {
174 case 'd': /* set debug level */
175 debug_level = atoi(optarg);
176 if (debug_level <= 0) {
196 /* See if we can open a device */
198 printf("No archive name specified.\n");
201 } else if (argc != 1) {
202 printf("Improper number of arguments specified.\n");
207 fd = open(argv[0], O_RDWR);
209 printf("Error opening %s ERR=%s\n", argv[0], strerror(errno));
212 dev = (DEVICE *)malloc(sizeof(DEVICE));
213 memset(dev, 0, sizeof(DEVICE));
215 dev->dev_name = strdup(argv[0]);
216 dev->buf_len = BLOCK_SIZE;
217 dev->buf = (char *)malloc(BLOCK_SIZE);
224 int rewind_dev(DEVICE *dev)
229 dev->dev_errno = EBADF;
230 printf("Bad call to rewind_dev. Device %s not open\n",
234 dev->state &= ~(ST_APPEND|ST_READ|ST_EOT|ST_EOF|ST_WEOT); /* remove EOF/EOT flags */
235 dev->block_num = dev->file = 0;
236 mt_com.mt_op = MTREW;
238 if (ioctl(dev->fd, MTIOCTOP, (char *)&mt_com) < 0) {
239 dev->dev_errno = errno;
240 printf("Rewind error on %s. ERR=%s.\n",
241 dev->dev_name, strerror(dev->dev_errno));
248 * Write an end of file on the device
249 * Returns: 0 on success
250 * non-zero on failure
253 weof_dev(DEVICE *dev, int num)
259 dev->dev_errno = EBADF;
260 printf("Bad call to fsf_dev. Archive not open\n");
264 dev->state &= ~(ST_EOT | ST_EOF); /* remove EOF/EOT flags */
266 printf("weof_dev\n");
267 mt_com.mt_op = MTWEOF;
268 mt_com.mt_count = num;
269 stat = ioctl(dev->fd, MTIOCTOP, (char *)&mt_com);
274 dev->dev_errno = errno;
275 printf("ioctl MTWEOF error on %s. ERR=%s.\n",
276 dev->dev_name, strerror(dev->dev_errno));
294 static void rewindcmd()
296 if (!rewind_dev(dev)) {
297 printf("Bad status from rewind. ERR=%s\n", strerror(dev->dev_errno));
299 printf("Rewound %s\n", dev->dev_name);
304 * Write and end of file on the tape
306 static void weofcmd()
310 if ((stat = weof_dev(dev, 1)) < 0) {
311 printf("Bad status from weof %d. ERR=%s\n", stat, strerror(dev->dev_errno));
314 printf("Wrote EOF to %s\n", dev->dev_name);
320 * Read a record from the tape
327 if (!get_cmd("Enter length to read: ")) {
331 if (len < 0 || len > 1000000) {
332 printf("Bad length entered, using default of 1024 bytes.\n");
335 buf = (char *)malloc(len);
336 stat = read(fd, buf, len);
337 if (stat > 0 && stat <= len) {
340 printf("Read of %d bytes gives stat=%d. ERR=%s\n",
341 len, stat, strerror(errno));
346 * Write a record to the tape
353 rfd = open("/dev/urandom", O_RDONLY);
355 read(rfd, dev->buf, dev->buf_len);
357 printf("Cannot open /dev/urandom.\n");
360 printf("Write one block of %u bytes.\n", dev->buf_len);
361 stat = write(dev->fd, dev->buf, dev->buf_len);
362 if (stat != (int)dev->buf_len) {
364 printf("Bad status from write. ERR=%s\n", strerror(errno));
366 printf("Expected to write %d bytes but wrote only %d.\n",
375 * Scan tape by reading block by block. Report what is
376 * on the tape. Note, this command does raw reads, and as such
377 * will not work with fixed block size devices.
379 static void scancmd()
382 int blocks, tot_blocks, tot_files;
387 blocks = block_size = tot_blocks = 0;
389 if (dev->state & ST_EOT) {
390 printf("End of tape\n");
393 tot_files = dev->file;
394 printf("Starting scan at file %u\n", dev->file);
396 if ((stat = read(dev->fd, buf, sizeof(buf))) < 0) {
397 dev->dev_errno = errno;
398 printf("Bad status from read %d. ERR=%s\n", stat, strerror(dev->dev_errno));
400 printf("%d block%s of %d bytes in file %d\n",
401 blocks, blocks>1?"s":"", block_size, dev->file);
404 if (stat != block_size) {
406 printf("%d block%s of %d bytes in file %d\n",
407 blocks, blocks>1?"s":"", block_size, dev->file);
412 if (stat == 0) { /* EOF */
413 printf("End of File mark.\n");
414 /* Two reads of zero means end of tape */
415 if (dev->state & ST_EOF)
416 dev->state |= ST_EOT;
418 dev->state |= ST_EOF;
421 if (dev->state & ST_EOT) {
422 printf("End of tape\n");
425 } else { /* Got data */
426 dev->state &= ~ST_EOF;
432 tot_files = dev->file - tot_files;
433 printf("Total files=%d, blocks=%d, bytes = %d\n", tot_files, tot_blocks,
438 static void rawfill_cmd()
442 uint32_t block_num = 0;
446 rfd = open("/dev/urandom", O_RDONLY);
448 read(rfd, dev->buf, dev->buf_len);
450 printf("Cannot open /dev/urandom.\n");
453 p = (uint32_t *)dev->buf;
454 printf("Begin writing blocks of %u bytes.\n", dev->buf_len);
457 stat = write(dev->fd, dev->buf, dev->buf_len);
458 if (stat == (int)dev->buf_len) {
459 if ((block_num++ % 100) == 0) {
470 printf("Write failed. Last block written=%d. stat=%d ERR=%s\n", (int)block_num, stat,
475 /* Strip any trailing junk from the command */
476 void strip_trailing_junk(char *cmd)
479 p = cmd + strlen(cmd) - 1;
481 /* strip trailing junk from command */
482 while ((p >= cmd) && (*p == '\n' || *p == '\r' || *p == ' '))
486 /* folded search for string - case insensitive */
488 fstrsch(char *a, char *b) /* folded case search */
490 register char *s1,*s2;
491 register char c1=0, c2=0;
495 while (*s1) { /* do it the fast way */
496 if ((*s1++ | 0x20) != (*s2++ | 0x20))
497 return 0; /* failed */
499 while (*a) { /* do it over the correct slow way */
500 if (isupper(c1 = *a)) {
501 c1 = tolower((int)c1);
503 if (isupper(c2 = *b)) {
504 c2 = tolower((int)c2);
516 struct cmdstruct { char *key; void (*func)(); char *help; };
517 static struct cmdstruct commands[] = {
518 {"help", helpcmd, "print this command"},
519 {"quit", quitcmd, "quit tapetest"},
520 {"rawfill", rawfill_cmd, "use write() to fill tape"},
521 {"rewind", rewindcmd, "rewind the tape"},
522 {"rr", rrcmd, "raw read the tape"},
523 {"wr", wrcmd, "raw write one block to the tape"},
524 {"scan", scancmd, "read() tape block by block to EOT and report"},
525 {"weof", weofcmd, "write an EOF on the tape"},
527 #define comsize (sizeof(commands)/sizeof(struct cmdstruct))
535 while (get_cmd("*")) {
537 for (i=0; i<comsize; i++) /* search for command */
538 if (fstrsch(cmd, commands[i].key)) {
539 (*commands[i].func)(); /* go execute command */
544 printf("%s is an illegal command\n", cmd);
552 static void helpcmd()
556 printf(" Command Description\n ======= ===========\n");
557 for (i=0; i<comsize; i++)
558 printf(" %-10s %s\n", commands[i].key, commands[i].help);
565 "Usage: tapetest [-d debug_level] [device_name]\n"
566 " -dnn set debug level to nn\n"
567 " -? print this message.\n"
575 * Get next input command from terminal. This
576 * routine is REALLY primitive, and should be enhanced
577 * to have correct backspacing, etc.
580 get_cmd(char *prompt)
584 fprintf(stdout, prompt);
586 /* We really should turn off echoing and pretty this
590 while ((ch = fgetc(stdin)) != EOF) {
592 strip_trailing_junk(cmd);
594 } else if (ch == 4 || ch == 0xd3 || ch == 0x8) {