2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation, which is
11 listed in the file LICENSE.
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of John Walker.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
34 static int dbglevel = 10;
36 faketape *ftape_list[FTAPE_MAX_DRIVE];
38 static faketape *get_tape(int fd)
42 if (fd >= FTAPE_MAX_DRIVE) {
47 return ftape_list[fd];
50 static bool put_tape(faketape *ftape)
52 ASSERT(ftape != NULL);
54 int fd = ftape->get_fd();
55 if (fd >= FTAPE_MAX_DRIVE) {
59 ftape_list[fd] = ftape;
63 /****************************************************************/
64 /* theses function will replace open/read/write/close/ioctl
67 int faketape_open(const char *pathname, int flags, int mode)
69 ASSERT(pathname != NULL);
72 faketape *tape = new faketape();
73 fd = tape->open(pathname, flags, mode);
80 int faketape_read(int fd, void *buffer, unsigned int count)
82 faketape *tape = get_tape(fd);
84 return tape->read(buffer, count);
87 int faketape_write(int fd, const void *buffer, unsigned int count)
89 faketape *tape = get_tape(fd);
91 return tape->write(buffer, count);
94 int faketape_close(int fd)
96 faketape *tape = get_tape(fd);
103 int faketape_ioctl(int fd, unsigned long int request, ...)
108 faketape *t = get_tape(fd);
114 va_start(argp, request);
116 if (request == MTIOCTOP) {
117 result = t->tape_op(va_arg(argp, mtop *));
118 } else if (request == MTIOCGET) {
119 result = t->tape_get(va_arg(argp, mtget *));
123 // result = tape_pos(fd, va_arg(argp, mtpos *));
135 /****************************************************************/
137 int faketape::tape_op(struct mtop *mt_com)
141 switch (mt_com->mt_op)
157 case MTFSF: /* Forward space over mt_count filemarks. */
158 result = fsf(mt_com->mt_count);
161 case MTBSF: /* Backward space over mt_count filemarks. */
162 current_file = current_file - mt_com->mt_count;
163 if (current_file < 0) {
174 case MTFSR: /* Forward space over mt_count records (tape blocks). */
182 mt: /dev/lto2: Erreur d'entrée/sortie
187 /* tester si on se trouve a la fin du fichier */
188 result = fsr(mt_com->mt_count);
191 case MTBSR: /* Backward space over mt_count records (tape blocks). */
195 case MTWEOF: /* Write mt_count filemarks. */
196 weof(mt_com->mt_count);
199 case MTREW: /* Rewind. */
201 atEOF = atEOD = false;
207 case MTOFFL: /* put tape offline */
211 case MTRETEN: /* Re-tension tape. */
215 case MTBSFM: /* not used by bacula */
220 case MTFSFM: /* not used by bacula */
225 case MTEOM:/* Go to the end of the recorded media (for appending files). */
235 current_file = last_file+1;
237 /* Ne pas creer le fichier si on est a la fin */
241 case MTERASE: /* not used by bacula */
247 delete_files(current_file);
292 // case -1: /* Error has already been translated into errno */
296 // case ERROR_FILEMARK_DETECTED:
300 // case ERROR_END_OF_MEDIA:
304 // case ERROR_NO_DATA_DETECTED:
308 // case ERROR_NO_MEDIA_IN_DRIVE:
309 // errno = ENOMEDIUM;
312 // case ERROR_INVALID_HANDLE:
313 // case ERROR_ACCESS_DENIED:
314 // case ERROR_LOCK_VIOLATION:
319 return result == 0 ? 0 : -1;
322 int faketape::tape_get(struct mtget *mt_get)
326 mt_get->mt_type = MT_ISSCSI2;
327 mt_get->mt_blkno = current_block;
328 mt_get->mt_fileno = current_file;
330 mt_get->mt_resid = -1;
331 // pos_info.PartitionBlockValid ? pos_info.Partition : (ULONG)-1;
335 ((density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK) |
336 ((tape_info.block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK);
339 mt_get->mt_gstat = 0x00010000; /* Immediate report mode.*/
342 mt_get->mt_gstat |= 0x80000000; // GMT_EOF
346 mt_get->mt_gstat |= 0x40000000; // GMT_BOT
349 mt_get->mt_gstat |= 0x20000000; // GMT_EOT
353 mt_get->mt_gstat |= 0x08000000; // GMT_EOD
356 if (0) { //WriteProtected) {
357 mt_get->mt_gstat |= 0x04000000; // GMT_WR_PROT
361 mt_get->mt_gstat |= 0x01000000; // GMT_ONLINE
363 mt_get->mt_gstat |= 0x00040000; // GMT_DR_OPEN
365 mt_get->mt_erreg = 0;
370 int faketape::tape_pos(struct mtpos *mt_pos)
376 * This function try to emulate the append only behavior
377 * of a tape. When you wrote something, data after the
378 * current position are discarded.
380 int faketape::delete_files(int startfile)
389 Dmsg1(dbglevel, "delete_files %i\n", startfile);
391 fp_dir = opendir(this->volume);
400 /* search for all digit files
401 * and we remove all ones that are greater than
404 while ((dir = readdir (fp_dir)) != NULL)
406 Mmsg(tmp, "%s/%s", this->volume, dir->d_name);
408 /* check if d_name contains only digits */
409 for(p = dir->d_name; *p && isdigit(*p); p++)
414 if (!*p && cur > 0) {
415 if (cur >= startfile) { /* remove it */
418 if (lstat(tmp.c_str(), &statp) == 0) {
419 this->size += statp.st_size;
421 max = (max > cur)?max:cur;
427 this->last_file = max;
447 volume = get_pool_memory(PM_NAME);
448 cur_file = get_pool_memory(PM_NAME);
449 cur_info = get_pool_memory(PM_NAME);
452 faketape::~faketape()
454 free_pool_memory(volume);
455 free_pool_memory(cur_file);
456 free_pool_memory(cur_info);
459 int faketape::get_fd()
464 int faketape::write(const void *buffer, unsigned int count)
467 Dmsg2(dbglevel, "write len=%i blocks=%i\n", count, current_block);
471 Dmsg0(dbglevel, "write nothing, EOT !\n");
475 if (current_block != -1) {
482 /* TODO: remove all files > current_file and
483 * remove blocks > current_block
485 if (count + size > tape_info.max_size) {
487 "EOT writing only %i of %i requested\n",
488 tape_info.max_size - size, count);
489 count = tape_info.max_size - size;
493 ::write(cur_fd, &count, sizeof(count));
494 nb = ::write(cur_fd, buffer, count);
499 "Not enough space writing only %i of %i requested\n",
506 int faketape::weof(int count)
508 Dmsg2(dbglevel, "Writing EOF %i:%i\n", current_file, current_block);
514 count--; /* end this file */
515 ftruncate(cur_fd, lseek(cur_fd, 0, SEEK_CUR));
519 /* we erase all previous information */
520 if (last_file > current_file) {
521 delete_files(current_file);
536 int faketape::fsf(int count)
540 * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
550 Dmsg3(dbglevel+1, "fsf %i+%i <= %i\n", current_file, count, last_file);
552 if ((current_file + count) <= last_file) {
553 current_file += count;
557 Dmsg0(dbglevel, "Try to FSF after EOT\n");
558 current_file = last_file ;
565 int faketape::fsr(int count)
569 Dmsg2(dbglevel, "fsr current_block=%i count=%i\n", current_block, count);
578 /* check all block record */
579 for(i=0; (i < count) && (where != -1) ; i++) {
580 nb = ::read(cur_fd, &size, sizeof(size)); /* get size of block */
581 if (nb == sizeof(size)) {
583 where = lseek(cur_fd, size, SEEK_CUR); /* seek after this block */
596 int faketape::bsf(int count)
599 atEOT = atEOD = false;
601 if (current_file - count < 0) {
608 current_file = current_file - count;
618 * Put faketape in offline mode
620 int faketape::offline()
638 int faketape::close_file()
640 Dmsg0(dbglevel, "close_file\n");
648 int faketape::close()
658 * EOF Bacula status: file=2 block=0
659 * Device status: EOF ONLINE IM_REP_EN file=2 block=0
662 * EOD EOF Bacula status: file=2 block=0
663 * Device status: EOD ONLINE IM_REP_EN file=2 block=-1
667 int faketape::read(void *buffer, unsigned int count)
669 unsigned int nb, size;
672 if (atEOT || atEOD) {
679 nb = ::read(cur_fd, &size, sizeof(size));
681 lseek(cur_fd, size, SEEK_CUR);
685 nb = ::read(cur_fd, buffer, size);
688 if (current_file == last_file) {
692 Dmsg0(dbglevel, "EOF during reading\n");
697 int faketape::read_volinfo()
700 memset(&tape_info, 0, sizeof(FTAPE_FORMAT));
702 Dmsg2(dbglevel, "read_volinfo %p %p\n", cur_info, volume);
703 Mmsg(cur_info, "%s/info", volume);
704 fd = ::open(cur_info, O_CREAT | O_RDWR | O_BINARY, 0640);
712 /* read volume info */
713 int nb = ::read(fd, &tape_info, sizeof(FTAPE_FORMAT));
714 if (nb != sizeof(FTAPE_FORMAT)) { /* new tape ? */
715 Dmsg1(dbglevel, "Initialize %s\n", volume);
716 tape_info.version = 1;
717 tape_info.block_max = 2000000;
718 tape_info.block_size = statp.st_blksize;
719 tape_info.max_size = 10000000;
721 lseek(fd, SEEK_SET, 0);
722 nb = ::write(fd, &tape_info, sizeof(FTAPE_FORMAT));
724 if (nb != sizeof(FTAPE_FORMAT)) {
730 Dmsg0(dbglevel, "read_volinfo OK\n");
736 int faketape::open(const char *pathname, int uflags, int umode)
738 Dmsg3(dbglevel, "faketape::open(%s, %i, %i)\n", pathname, uflags, umode);
739 pm_strcpy(volume, pathname);
742 if (stat(volume, &statp) != 0) {
743 Dmsg1(dbglevel, "Can't stat on %s\n", volume);
747 if (!S_ISDIR(statp.st_mode)) {
748 Dmsg1(dbglevel, "%s is not a directory\n", volume);
753 /* open volume descriptor and get this->fd */
754 if (read_volinfo() < 0) {
764 * read volume directory to get the last file number
766 int faketape::find_maxfile()
776 fp_dir = opendir(this->volume);
784 /* search for all digit file */
785 while ((dir = readdir (fp_dir)) != NULL)
787 Mmsg(tmp, "%s/%s", this->volume, dir->d_name);
788 if (lstat(tmp.c_str(), &statp) == 0) {
789 this->size += statp.st_size;
791 Dmsg1(dbglevel, "Can't stat %s\n", tmp.c_str());
794 /* TODO: compute size */
795 for(p = dir->d_name; *p && isdigit(*p); p++)
801 max = (max > cur)?max:cur;
806 this->last_file = max;
810 int faketape::open_file()
812 ASSERT(current_file >= 0);
815 Mmsg(cur_file, "%s/%i", volume, current_file);
816 cur_fd = ::open(cur_file, O_CREAT | O_RDWR | O_BINARY, 0640);
821 last_file = (last_file > current_file)?last_file:current_file;
823 Dmsg1(dbglevel, "open_file %s\n", cur_file);
828 void faketape::dump()
830 Dmsg0(dbglevel+1, "===================\n");
831 Dmsg2(dbglevel, "file:block = %i:%i\n", current_file, current_block);
832 Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
833 Dmsg1(dbglevel+1, "volume=%s\n", volume);
834 Dmsg1(dbglevel+1, "cur_file=%s\n", cur_file);
835 Dmsg1(dbglevel+1, "size=%i\n", size);
836 Dmsg1(dbglevel+1, "EOF=%i\n", atEOF);
837 Dmsg1(dbglevel+1, "EOT=%i\n", atEOT);
838 Dmsg1(dbglevel+1, "EOD=%i\n", atEOD);
841 /****************************************************************
843 #define GMT_EOF(x) ((x) & 0x80000000)
844 #define GMT_BOT(x) ((x) & 0x40000000)
845 #define GMT_EOT(x) ((x) & 0x20000000)
846 #define GMT_SM(x) ((x) & 0x10000000)
847 #define GMT_EOD(x) ((x) & 0x08000000)
850 GMT_EOF(x) : La bande est positionnée juste après une filemark (toujours faux
851 après une opération MTSEEK).
853 GMT_BOT(x) : La bande est positionnée juste au début du premier fichier
854 (toujours faux après une opération MTSEEK).
856 GMT_EOT(x) : Une opération a atteint la fin physique de la bande (End Of
859 GMT_SM(x) : La bande est positionnée sur une setmark (toujours faux après une
862 GMT_EOD(x) : La bande est positionnée à la fin des données enregistrées.
865 blkno = -1 (after MTBSF MTBSS or MTSEEK)
866 fileno = -1 (after MTBSS or MTSEEK)
869 drive type = Generic SCSI-2 tape
875 Tape block size 0 bytes. Density code 0x0 (default).
876 Soft error count since last status=0
877 General status bits on (41010000):
881 dd if=/dev/lto2 of=/tmp/toto count=1
882 dd: lecture de `/dev/lto2': Ne peut allouer de la mémoire
883 0+0 enregistrements lus
884 0+0 enregistrements écrits
885 1 octet (1B) copié, 4,82219 seconde, 0,0 kB/s
891 dd if=/dev/lto2 of=/tmp/toto count=1
892 0+0 enregistrements lus
893 0+0 enregistrements écrits
894 1 octet (1B) copié, 0,167274 seconde, 0,0 kB/s
899 *** write 2 blocks after rewind
900 dd if=/dev/zero of=/dev/lto2 count=2
901 2+0 enregistrements lus
902 2+0 enregistrements écrits
903 1024 octets (1,0 kB) copiés, 6,57402 seconde, 0,2 kB/s
916 *** rewind and 2x fsr (we have just 2 blocks)
921 mt: /dev/lto2: Erreur
926 ****************************************************************/
935 printf("Starting FakeTape\n");
937 mkdir("/tmp/fake", 0700);