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;
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 for(i=0; (i < count) && (where != -1) ; i++) {
579 Dmsg3(dbglevel," fsr ok count=%i i=%i where=%i\n", count, i, where);
580 nb = ::read(cur_fd, &size, sizeof(size));
581 if (nb == sizeof(size)) {
582 where = lseek(cur_fd, size, SEEK_CUR);
593 Dmsg2(dbglevel," fsr ok i=%i where=%i\n", i, where);
597 int faketape::bsf(int count)
600 atEOT = atEOD = false;
602 if (current_file - count < 0) {
609 current_file = current_file - count;
619 * Put faketape in offline mode
621 int faketape::offline()
639 int faketape::close_file()
641 Dmsg0(dbglevel, "close_file\n");
649 int faketape::close()
659 * EOF Bacula status: file=2 block=0
660 * Device status: EOF ONLINE IM_REP_EN file=2 block=0
663 * EOD EOF Bacula status: file=2 block=0
664 * Device status: EOD ONLINE IM_REP_EN file=2 block=-1
668 int faketape::read(void *buffer, unsigned int count)
670 unsigned int nb, size;
673 if (atEOT || atEOD) {
680 nb = ::read(cur_fd, &size, sizeof(size));
682 lseek(cur_fd, size, SEEK_CUR);
686 nb = ::read(cur_fd, buffer, size);
689 if (current_file == last_file) {
693 Dmsg0(dbglevel, "EOF during reading\n");
698 int faketape::read_volinfo()
701 memset(&tape_info, 0, sizeof(FTAPE_FORMAT));
703 Dmsg2(dbglevel, "read_volinfo %p %p\n", cur_info, volume);
704 Mmsg(cur_info, "%s/info", volume);
705 fd = ::open(cur_info, O_CREAT | O_RDWR | O_BINARY, 0640);
713 /* read volume info */
714 int nb = ::read(fd, &tape_info, sizeof(FTAPE_FORMAT));
715 if (nb != sizeof(FTAPE_FORMAT)) { /* new tape ? */
716 Dmsg1(dbglevel, "Initialize %s\n", volume);
717 tape_info.version = 1;
718 tape_info.block_max = 2000000;
719 tape_info.block_size = statp.st_blksize;
720 tape_info.max_size = 10000000;
722 lseek(fd, SEEK_SET, 0);
723 nb = ::write(fd, &tape_info, sizeof(FTAPE_FORMAT));
725 if (nb != sizeof(FTAPE_FORMAT)) {
731 Dmsg0(dbglevel, "read_volinfo OK\n");
737 int faketape::open(const char *pathname, int uflags, int umode)
739 Dmsg3(dbglevel, "faketape::open(%s, %i, %i)\n", pathname, uflags, umode);
740 pm_strcpy(volume, pathname);
743 if (stat(volume, &statp) != 0) {
744 Dmsg1(dbglevel, "Can't stat on %s\n", volume);
748 if (!S_ISDIR(statp.st_mode)) {
749 Dmsg1(dbglevel, "%s is not a directory\n", volume);
754 /* open volume descriptor and get this->fd */
755 if (read_volinfo() < 0) {
765 * read volume directory to get the last file number
767 int faketape::find_maxfile()
777 fp_dir = opendir(this->volume);
785 /* search for all digit file */
786 while ((dir = readdir (fp_dir)) != NULL)
788 Mmsg(tmp, "%s/%s", this->volume, dir->d_name);
789 if (lstat(tmp.c_str(), &statp) == 0) {
790 this->size += statp.st_size;
792 Dmsg1(dbglevel, "Can't stat %s\n", tmp.c_str());
795 /* TODO: compute size */
796 for(p = dir->d_name; *p && isdigit(*p); p++)
802 max = (max > cur)?max:cur;
807 this->last_file = max;
811 int faketape::open_file()
813 ASSERT(current_file >= 0);
816 Mmsg(cur_file, "%s/%i", volume, current_file);
817 cur_fd = ::open(cur_file, O_CREAT | O_RDWR | O_BINARY, 0640);
822 last_file = (last_file > current_file)?last_file:current_file;
824 Dmsg1(dbglevel, "open_file %s\n", cur_file);
829 void faketape::dump()
831 Dmsg0(dbglevel+1, "===================\n");
832 Dmsg2(dbglevel, "file:block = %i:%i\n", current_file, current_block);
833 Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
834 Dmsg1(dbglevel+1, "volume=%s\n", volume);
835 Dmsg1(dbglevel+1, "cur_file=%s\n", cur_file);
836 Dmsg1(dbglevel+1, "size=%i\n", size);
837 Dmsg1(dbglevel+1, "EOF=%i\n", atEOF);
838 Dmsg1(dbglevel+1, "EOT=%i\n", atEOT);
839 Dmsg1(dbglevel+1, "EOD=%i\n", atEOD);
842 /****************************************************************
844 #define GMT_EOF(x) ((x) & 0x80000000)
845 #define GMT_BOT(x) ((x) & 0x40000000)
846 #define GMT_EOT(x) ((x) & 0x20000000)
847 #define GMT_SM(x) ((x) & 0x10000000)
848 #define GMT_EOD(x) ((x) & 0x08000000)
851 GMT_EOF(x) : La bande est positionnée juste après une filemark (toujours faux
852 après une opération MTSEEK).
854 GMT_BOT(x) : La bande est positionnée juste au début du premier fichier
855 (toujours faux après une opération MTSEEK).
857 GMT_EOT(x) : Une opération a atteint la fin physique de la bande (End Of
860 GMT_SM(x) : La bande est positionnée sur une setmark (toujours faux après une
863 GMT_EOD(x) : La bande est positionnée à la fin des données enregistrées.
866 blkno = -1 (after MTBSF MTBSS or MTSEEK)
867 fileno = -1 (after MTBSS or MTSEEK)
870 drive type = Generic SCSI-2 tape
876 Tape block size 0 bytes. Density code 0x0 (default).
877 Soft error count since last status=0
878 General status bits on (41010000):
882 dd if=/dev/lto2 of=/tmp/toto count=1
883 dd: lecture de `/dev/lto2': Ne peut allouer de la mémoire
884 0+0 enregistrements lus
885 0+0 enregistrements écrits
886 1 octet (1B) copié, 4,82219 seconde, 0,0 kB/s
892 dd if=/dev/lto2 of=/tmp/toto count=1
893 0+0 enregistrements lus
894 0+0 enregistrements écrits
895 1 octet (1B) copié, 0,167274 seconde, 0,0 kB/s
900 *** write 2 blocks after rewind
901 dd if=/dev/zero of=/dev/lto2 count=2
902 2+0 enregistrements lus
903 2+0 enregistrements écrits
904 1024 octets (1,0 kB) copiés, 6,57402 seconde, 0,2 kB/s
917 *** rewind and 2x fsr (we have just 2 blocks)
922 mt: /dev/lto2: Erreur
927 ****************************************************************/
936 printf("Starting FakeTape\n");
938 mkdir("/tmp/fake", 0700);