2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
5 Copyright (C) 2008-2014 Free Software Foundation Europe e.V.
7 The original author of Bacula is Kern Sibbald, with contributions
8 from many others, a complete list can be found in the file AUTHORS.
10 You may use this file and others of this release according to the
11 license defined in the LICENSE file, which includes the Affero General
12 Public License, v3.0 ("AGPLv3") and some additional permissions and
13 terms pursuant to its AGPLv3 Section 7.
15 This notice must be preserved when any source code is
16 conveyed and/or propagated.
18 Bacula(R) is a registered trademark of Kern Sibbald.
22 * Please note!!! The VTAPE device is for testing only.
23 * It simulates a tape drive, which is useful for testing
24 * without a real drive, but is inefficient for writing
25 * disk volumes. In addition, we do not test for every
26 * possible error condition, so please do not use this
33 Maximum File Size = 800M
34 Maximum Volume Size = 3G
36 Archive Device = /tmp/fake
38 AutomaticMount = yes; # when device opened, read it
60 #include "bacula.h" /* define 64bit file usage */
66 static int dbglevel = 100;
67 #define FILE_OFFSET 30
69 void vtape_debug(int level)
74 /* DEVICE virtual that we redefine. */
75 int vtape::d_ioctl(int fd, ioctl_req_t request, char *op)
79 if (request == MTIOCTOP) {
80 result = tape_op((mtop *)op);
81 } else if (request == MTIOCGET) {
82 result = tape_get((mtget *)op);
83 } else if (request == MTIOCPOS) {
84 result = tape_pos((mtpos *)op);
93 int vtape::tape_op(struct mtop *mt_com)
96 int count = mt_com->mt_count;
103 switch (mt_com->mt_op)
119 case MTFSF: /* Forward space over mt_count filemarks. */
122 } while (--count > 0 && result == 0);
125 case MTBSF: /* Backward space over mt_count filemarks. */
128 } while (--count > 0 && result == 0);
131 case MTFSR: /* Forward space over mt_count records (tape blocks). */
139 mt: /dev/lto2: Erreur d'entree/sortie
144 /* tester si on se trouve a la fin du fichier */
145 result = fsr(mt_com->mt_count);
148 case MTBSR: /* Backward space over mt_count records (tape blocks). */
149 result = bsr(mt_com->mt_count);
152 case MTWEOF: /* Write mt_count filemarks. */
155 } while (result == 0 && --count > 0);
158 case MTREW: /* Rewind. */
159 Dmsg0(dbglevel, "rewind vtape\n");
161 atEOF = atEOD = false;
165 lseek(fd, 0, SEEK_SET);
166 result = !read_fm(VT_READ_EOF);
169 case MTOFFL: /* put tape offline */
170 result = offline() ? 0 : -1;
173 case MTRETEN: /* Re-tension tape. */
177 case MTBSFM: /* not used by bacula */
182 case MTFSFM: /* not used by bacula */
187 case MTEOM:/* Go to the end of the recorded media (for appending files). */
189 lseek(fd, next_FM, SEEK_SET);
190 if (read_fm(VT_READ_EOF)) {
195 while (::read(fd, &l, sizeof(l)) > 0) {
197 lseek(fd, l, SEEK_CUR);
201 Dmsg0(dbglevel, "skip 1 block\n");
214 case MTERASE: /* not used by bacula */
221 lseek(fd, 0, SEEK_SET);
222 read_fm(VT_READ_EOF);
266 return result == 0 ? 0 : -1;
269 int vtape::tape_get(struct mtget *mt_get)
272 int block_size = 1024;
274 mt_get->mt_type = MT_ISSCSI2;
275 mt_get->mt_blkno = current_block;
276 mt_get->mt_fileno = current_file;
278 mt_get->mt_resid = -1;
279 // pos_info.PartitionBlockValid ? pos_info.Partition : (ULONG)-1;
283 ((density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK) |
284 ((block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK);
287 mt_get->mt_gstat = 0x00010000; /* Immediate report mode.*/
290 mt_get->mt_gstat |= 0x80000000; // GMT_EOF
294 mt_get->mt_gstat |= 0x40000000; // GMT_BOT
297 mt_get->mt_gstat |= 0x20000000; // GMT_EOT
301 mt_get->mt_gstat |= 0x08000000; // GMT_EOD
304 if (0) { //WriteProtected) {
305 mt_get->mt_gstat |= 0x04000000; // GMT_WR_PROT
309 mt_get->mt_gstat |= 0x01000000; // GMT_ONLINE
311 mt_get->mt_gstat |= 0x00040000; // GMT_DR_OPEN
313 mt_get->mt_erreg = 0;
318 int vtape::tape_pos(struct mtpos *mt_pos)
320 if (current_block >= 0) {
321 mt_pos->mt_blkno = current_block;
329 * This function try to emulate the append only behavior
330 * of a tape. When you wrote something, data after the
331 * current position are discarded.
333 int vtape::truncate_file()
335 Dmsg2(dbglevel, "truncate %i:%i\n", current_file, current_block);
336 ftruncate(fd, lseek(fd, 0, SEEK_CUR));
337 last_file = current_file;
365 max_block = VTAPE_MAX_BLOCK;
374 * DEVICE virtual that we redefine.
376 * Write a variable block of count size.
377 * block = vtape_header + data
378 * vtape_header = sizeof(data)
379 * if vtape_header == 0, this is a EOF
381 ssize_t vtape::d_write(int, const void *buffer, size_t count)
384 ASSERT(current_file >= 0);
389 Dmsg3(dbglevel*2, "write len=%i %i:%i\n",
390 count, current_file,current_block);
393 Dmsg0(dbglevel, "write nothing, EOT !\n");
398 if (!atEOD) { /* if not at the end of the data */
402 if (current_block != -1) {
408 atEOD = true; /* End of data */
410 needEOF = true; /* next operation need EOF mark */
412 uint32_t size = count;
413 ::write(fd, &size, sizeof(uint32_t));
414 nb = ::write(fd, buffer, count);
416 if (nb != (ssize_t)count) {
419 "Not enough space writing only %i of %i requested\n",
429 * +---+---------+---+------------------+---+-------------------+
430 * |00N| DATA |0LN| DATA |0LC| DATA |
431 * +---+---------+---+------------------+---+-------------------+
434 * L : Last FileMark offset
435 * N : Next FileMark offset
436 * C : Current FileMark Offset
441 ASSERT(current_file >= 0);
452 truncate_file(); /* nothing after this point */
456 cur_FM = lseek(fd, 0, SEEK_CUR); // current position
458 /* update previous next_FM */
459 lseek(fd, last_FM + sizeof(uint32_t)+sizeof(boffset_t), SEEK_SET);
460 ::write(fd, &cur_FM, sizeof(boffset_t));
461 lseek(fd, cur_FM, SEEK_SET);
466 ::write(fd, &c, sizeof(uint32_t)); // EOF
467 ::write(fd, &last_FM, sizeof(last_FM)); // F-1
468 ::write(fd, &next_FM, sizeof(next_FM)); // F (will be updated next time)
478 last_file = MAX(current_file, last_file);
480 Dmsg4(dbglevel, "Writing EOF %i:%i last=%lli cur=%lli next=0\n",
481 current_file, current_block, last_FM, cur_FM);
492 ASSERT(current_file >= 0);
495 * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
499 if (atEOT || atEOD) {
506 Dmsg2(dbglevel+1, "fsf %i <= %i\n", current_file, last_file);
508 if (next_FM > cur_FM) { /* not the last file */
509 lseek(fd, next_FM, SEEK_SET);
510 read_fm(VT_READ_EOF);
515 } else if (atEOF) { /* last file mark */
521 } else { /* last file, but no at the end */
524 Dmsg0(dbglevel, "Try to FSF after EOT\n");
526 current_file = last_file ;
534 /* /------------\ /---------------\
535 * +---+------+---+---------------+-+
537 * +---+------+---+---------------+-+
540 bool vtape::read_fm(VT_READ_FM_MODE read_all)
544 if (read_all == VT_READ_EOF) {
545 ::read(fd, &c, sizeof(c));
547 lseek(fd, cur_FM, SEEK_SET);
552 cur_FM = lseek(fd, 0, SEEK_CUR) - sizeof(c);
554 ::read(fd, &last_FM, sizeof(last_FM));
555 ret = ::read(fd, &next_FM, sizeof(next_FM));
559 Dmsg3(dbglevel, "Read FM cur=%lli last=%lli next=%lli\n",
560 cur_FM, last_FM, next_FM);
562 return (ret == sizeof(next_FM));
566 * TODO: Check fsr with EOF
568 int vtape::fsr(int count)
571 ASSERT(current_file >= 0);
575 // boffset_t where=0;
577 Dmsg4(dbglevel, "fsr %i:%i EOF=%i c=%i\n",
578 current_file,current_block,atEOF,count);
593 atBOT = atEOF = false;
595 /* check all block record */
596 for(i=0; (i < count) && !atEOF ; i++) {
597 nb = ::read(fd, &s, sizeof(uint32_t)); /* get size of next block */
598 if (nb == sizeof(uint32_t) && s) {
600 lseek(fd, s, SEEK_CUR); /* seek after this block */
602 Dmsg4(dbglevel, "read EOF %i:%i nb=%i s=%i\n",
603 current_file, current_block, nb,s);
608 read_fm(VT_SKIP_EOF);
610 atEOF = true; /* stop the loop */
618 * BSR + EOF => begin of EOF + EIO
619 * BSR + BSR + EOF => last block
622 int vtape::bsr(int count)
625 ASSERT(current_file >= 0);
639 boffset_t last=-1, last2=-1;
640 boffset_t orig = lseek(fd, 0, SEEK_CUR);
641 int orig_f = current_file;
642 int orig_b = current_block;
644 Dmsg4(dbglevel, "bsr(%i) cur_blk=%i orig=%lli cur_FM=%lli\n",
645 count, current_block, orig, cur_FM);
647 /* begin of tape, do nothing */
653 /* at EOF 0:-1 BOT=0 EOD=0 EOF=0 ERR: Input/output error */
655 lseek(fd, cur_FM, SEEK_SET);
657 if (current_file > 0) {
666 * First, go to cur/last_FM and read all blocks to find the good one
668 if (cur_FM == orig) { /* already just before EOF */
669 lseek(fd, last_FM, SEEK_SET);
672 lseek(fd, cur_FM, SEEK_SET);
675 ret = read_fm(VT_READ_EOF);
679 last2 = last; /* keep track of the 2 last blocs position */
680 last = lseek(fd, 0, SEEK_CUR);
681 last_f = current_file;
682 last_b = current_block;
683 Dmsg6(dbglevel, "EOF=%i last2=%lli last=%lli < orig=%lli %i:%i\n",
684 atEOF, last2, last, orig, current_file, current_block);
687 } while ((lseek(fd, 0, SEEK_CUR) < orig) && (ret == 0));
689 if (last2 > 0 && atEOF) { /* we take the previous position */
690 lseek(fd, last2, SEEK_SET);
691 current_file = last_f;
692 current_block = last_b - 1;
693 Dmsg3(dbglevel, "1 set offset2=%lli %i:%i\n",
694 last, current_file, current_block);
696 } else if (last > 0) {
697 lseek(fd, last, SEEK_SET);
698 current_file = last_f;
699 current_block = last_b;
700 Dmsg3(dbglevel, "2 set offset=%lli %i:%i\n",
701 last, current_file, current_block);
703 lseek(fd, orig, SEEK_SET);
704 current_file = orig_f;
705 current_block = orig_b;
709 Dmsg2(dbglevel, "bsr %i:%i\n", current_file, current_block);
711 atEOT = atEOF = atEOD = false;
712 atBOT = (lseek(fd, 0, SEEK_CUR) - (sizeof(uint32_t)+2*sizeof(boffset_t))) == 0;
715 current_block = orig_b;
721 /* BSF => just before last EOF
722 * EOF + BSF => just before EOF
723 * file 0 + BSF => BOT + errno
728 ASSERT(current_file >= 0);
729 Dmsg2(dbglevel, "bsf %i:%i count=%i\n", current_file, current_block);
734 atBOT = atEOF = atEOT = atEOD = false;
736 if (current_file == 0) {/* BOT + errno */
737 lseek(fd, 0, SEEK_SET);
738 read_fm(VT_READ_EOF);
745 Dmsg1(dbglevel, "bsf last=%lli\n", last_FM);
746 lseek(fd, cur_FM, SEEK_SET);
754 * DEVICE virtual that we redefine.
756 * Put vtape in offline mode
758 bool vtape::offline()
762 atEOF = false; /* End of file */
763 atEOT = false; /* End of tape */
764 atEOD = false; /* End of data */
765 atBOT = false; /* Begin of tape */
776 * DEVICE virtual that we redefine.
778 * A filemark is automatically written to tape if the last tape operation
779 * before close was a write.
781 int vtape::d_close(int)
788 lock.l_type = F_UNLCK;
790 lock.l_whence = SEEK_SET;
792 lock.l_pid = getpid();
794 ASSERT(fcntl(fd, F_SETLK, &lock) != -1);
805 * DEVICE virtual that we redefine.
807 * When a filemark is encountered while reading, the following happens. If
808 * there are data remaining in the buffer when the filemark is found, the
809 * buffered data is returned. The next read returns zero bytes. The following
810 * read returns data from the next file. The end of recorded data is signaled
811 * by returning zero bytes for two consecutive read calls. The third read
814 ssize_t vtape::d_read(int, void *buffer, size_t count)
817 ASSERT(current_file >= 0);
821 Dmsg2(dbglevel*2, "read %i:%i\n", current_file, current_block);
823 if (atEOT || atEOD) {
840 atEOD = atBOT = false;
842 /* reading size of data */
843 nb = ::read(fd, &s, sizeof(uint32_t));
845 atEOF = true; /* TODO: check this */
849 if (s > count) { /* not enough buffer to read block */
850 Dmsg2(dbglevel, "Need more buffer to read next block %i > %i\n",s,count);
851 lseek(fd, s, SEEK_CUR);
858 if (read_fm(VT_SKIP_EOF)) {
865 /* reading data itself */
866 nb = ::read(fd, buffer, s);
867 if (nb != (ssize_t)s) { /* read error */
871 Dmsg0(dbglevel, "EOT during reading\n");
875 if (current_block >= 0) {
882 /* Redefine DEVICE virtual function */
883 int vtape::d_open(const char *pathname, int uflags)
885 Dmsg2(dbglevel, "vtape::d_open(%s, %i)\n", pathname, uflags);
887 online = true; /* assume that drive contains a tape */
891 if (stat(pathname, &statp) != 0) {
893 Dmsg1(dbglevel, "Can't stat on %s\n", pathname);
894 if (uflags & O_NONBLOCK) {
896 fd = ::open("/dev/null", O_RDWR | O_LARGEFILE, 0600);
899 fd = ::open(pathname, O_RDWR | O_LARGEFILE, 0600);
904 Dmsg2(0, "Unable to open vtape device %s ERR=%s\n", pathname, be.bstrerror());
909 lockfile = (char *)malloc(strlen(pathname) + 3);
910 strcpy(lockfile, pathname);
911 strcat(lockfile, ".l");
913 lockfd = ::open(lockfile, O_CREAT | O_RDWR | O_LARGEFILE, 0600);
916 Dmsg2(0, "Unable to open vtape device lock %s ERR=%s\n", lockfile, be.bstrerror());
919 lock.l_type = F_WRLCK;
921 lock.l_whence = SEEK_SET;
923 lock.l_pid = getpid();
925 ASSERT(fcntl(lockfd, F_SETLK, &lock) != -1);
931 cur_FM = next_FM = last_FM = 0;
934 atEOT = atEOD = false;
936 /* If the vtape is empty, start by writing a EOF */
937 if (online && !read_fm(VT_READ_EOF)) {
938 lseek(fd, 0, SEEK_SET); /* rewind */
939 cur_FM = next_FM = last_FM = 0; /* reset */
940 weof(); /* write the first EOF */
941 last_file = current_file=0;
947 /* use this to track file usage */
948 void vtape::update_pos()
952 if (fstat(fd, &statp) == 0) {
953 file_block = statp.st_blocks;
956 Dmsg1(dbglevel*2, "update_pos=%i\n", file_block);
958 if (file_block > max_block) {
967 Dmsg0(dbglevel+1, "===================\n");
968 Dmsg2(dbglevel, "file:block = %i:%i\n", current_file, current_block);
969 Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
970 Dmsg1(dbglevel+1, "file_block=%i\n", file_block);
971 Dmsg4(dbglevel+1, "EOF=%i EOT=%i EOD=%i BOT=%i\n",
972 atEOF, atEOT, atEOD, atBOT);
975 #endif /* ! USE_VTAPE */