1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2000-2012 Free Software Foundation Europe e.V.
5 Copyright (C) 2014-2014 Planets Communications B.V.
6 Copyright (C) 2014-2021 Bareos GmbH & Co. KG
7
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
11 in the file LICENSE.
12
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.
17
18 You should have received a copy of the GNU Affero 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
21 02110-1301, USA.
22 */
23 /*
24 * Kern Sibbald, MM
25 *
26 * Extracted from other source files Marco van Wieringen, June 2014
27 */
28 /**
29 * @file
30 * Generic Tape API device abstraction.
31 */
32
33 #include "include/bareos.h"
34 #include "stored/device_control_record.h"
35 #include "stored/stored.h"
36 #include "generic_tape_device.h"
37 #include "stored/autochanger.h"
38 #include "lib/scsi_lli.h"
39 #include "lib/berrno.h"
40 #include "lib/util.h"
41
42 #include <string>
43
44 namespace storagedaemon {
45
46 /**
47 * Open a tape device
48 */
OpenDevice(DeviceControlRecord * dcr,DeviceMode omode)49 void generic_tape_device::OpenDevice(DeviceControlRecord* dcr, DeviceMode omode)
50 {
51 file_size = 0;
52 int timeout = max_open_wait;
53 #if !defined(HAVE_WIN32)
54 mtop mt_com{};
55 utime_t start_time = time(NULL);
56 #endif
57
58 mount(dcr, 1); /* do mount if required */
59
60 Dmsg0(100, "Open dev: device is tape\n");
61
62 GetAutochangerLoadedSlot(dcr);
63
64 open_mode = omode;
65 set_mode(omode);
66
67 if (timeout < 1) { timeout = 1; }
68 errno = 0;
69 Dmsg2(100, "Try open %s mode=%s\n", prt_name, mode_to_str(omode));
70 #if defined(HAVE_WIN32)
71 /*
72 * Windows Code
73 */
74 if ((fd = d_open(archive_device_string, oflags, 0)) < 0) {
75 dev_errno = errno;
76 }
77 #else
78 /*
79 * UNIX Code
80 *
81 * If busy retry each second for max_open_wait seconds
82 */
83 for (;;) {
84 /*
85 * Try non-blocking open
86 */
87 fd = d_open(archive_device_string, oflags | O_NONBLOCK, 0);
88 if (fd < 0) {
89 BErrNo be;
90 dev_errno = errno;
91 Dmsg5(100, "Open error on %s omode=%d oflags=%x errno=%d: ERR=%s\n",
92 prt_name, omode, oflags, errno, be.bstrerror());
93 } else {
94 /*
95 * Tape open, now rewind it
96 */
97 Dmsg0(100, "Rewind after open\n");
98 mt_com.mt_op = MTREW;
99 mt_com.mt_count = 1;
100
101 /*
102 * Rewind only if dev is a tape
103 */
104 if (d_ioctl(fd, MTIOCTOP, (char*)&mt_com) < 0) {
105 BErrNo be;
106 dev_errno = errno; /* set error status from rewind */
107 d_close(fd);
108 ClearOpened();
109 Dmsg2(100, "Rewind error on %s close: ERR=%s\n", prt_name,
110 be.bstrerror(dev_errno));
111 /*
112 * If we get busy, device is probably rewinding, try again
113 */
114 if (dev_errno != EBUSY) { break; /* error -- no medium */ }
115 } else {
116 /*
117 * Got fd and rewind worked, so we must have medium in drive
118 */
119 d_close(fd);
120 fd = d_open(archive_device_string, oflags, 0); /* open normally */
121 if (fd < 0) {
122 BErrNo be;
123 dev_errno = errno;
124 Dmsg5(100, "Open error on %s omode=%d oflags=%x errno=%d: ERR=%s\n",
125 prt_name, omode, oflags, errno, be.bstrerror());
126 break;
127 }
128 dev_errno = 0;
129 LockDoor();
130 SetOsDeviceParameters(dcr); /* do system dependent stuff */
131 break; /* Successfully opened and rewound */
132 }
133 }
134 Bmicrosleep(5, 0);
135
136 /*
137 * Exceed wait time ?
138 */
139 if (time(NULL) - start_time >= max_open_wait) { break; /* yes, get out */ }
140 }
141 #endif
142
143 if (!IsOpen()) {
144 BErrNo be;
145 Mmsg2(errmsg, _("Unable to open device %s: ERR=%s\n"), prt_name,
146 be.bstrerror(dev_errno));
147 Dmsg1(100, "%s", errmsg);
148 }
149
150 Dmsg1(100, "open dev: tape %d opened\n", fd);
151 }
152
153 /**
154 * Position device to end of medium (end of data)
155 *
156 * Returns: true on succes
157 * false on error
158 */
eod(DeviceControlRecord * dcr)159 bool generic_tape_device::eod(DeviceControlRecord* dcr)
160 {
161 mtop mt_com{};
162 bool ok = true;
163 int32_t os_file;
164
165 if (fd < 0) {
166 dev_errno = EBADF;
167 Mmsg1(errmsg, _("Bad call to eod. Device %s not open\n"), prt_name);
168 return false;
169 }
170
171 #if defined(__digital__) && defined(__unix__)
172 return fsf(VolCatInfo.VolCatFiles);
173 #endif
174
175 Dmsg0(100, "Enter eod\n");
176 if (AtEot()) { return true; }
177
178 ClearEof(); /* remove EOF flag */
179 block_num = file = 0;
180 file_size = 0;
181 file_addr = 0;
182
183 #ifdef MTEOM
184 if (HasCap(CAP_FASTFSF) && !HasCap(CAP_EOM)) {
185 Dmsg0(100, "Using FAST FSF for EOM\n");
186 /*
187 * If unknown position, rewind
188 */
189 if (GetOsTapeFile() < 0) {
190 if (!rewind(NULL)) {
191 Dmsg0(100, "Rewind error\n");
192 return false;
193 }
194 }
195 mt_com.mt_op = MTFSF;
196 /*
197 * ***FIXME*** fix code to handle case that INT16_MAX is not large enough.
198 */
199 mt_com.mt_count = INT16_MAX; /* use big positive number */
200 if (mt_com.mt_count < 0) {
201 mt_com.mt_count = INT16_MAX; /* brain damaged system */
202 }
203 }
204
205 if (HasCap(CAP_MTIOCGET) && (HasCap(CAP_FASTFSF) || HasCap(CAP_EOM))) {
206 if (HasCap(CAP_EOM)) {
207 Dmsg0(100, "Using EOM for EOM\n");
208 mt_com.mt_op = MTEOM;
209 mt_com.mt_count = 1;
210 }
211
212 if (d_ioctl(fd, MTIOCTOP, (char*)&mt_com) < 0) {
213 BErrNo be;
214 clrerror(mt_com.mt_op);
215 Dmsg1(50, "ioctl error: %s\n", be.bstrerror());
216 UpdatePos(dcr);
217 Mmsg2(errmsg, _("ioctl MTEOM error on %s. ERR=%s.\n"), prt_name,
218 be.bstrerror());
219 Dmsg0(100, errmsg);
220 return false;
221 }
222
223 os_file = GetOsTapeFile();
224 if (os_file < 0) {
225 BErrNo be;
226 clrerror(-1);
227 Mmsg2(errmsg, _("ioctl MTIOCGET error on %s. ERR=%s.\n"), prt_name,
228 be.bstrerror());
229 Dmsg0(100, errmsg);
230 return false;
231 }
232 Dmsg1(100, "EOD file=%d\n", os_file);
233 SetAteof();
234 file = os_file;
235 } else {
236 #endif
237 /*
238 * Rewind then use FSF until EOT reached
239 */
240 if (!rewind(NULL)) {
241 Dmsg0(100, "Rewind error.\n");
242 return false;
243 }
244
245 /*
246 * Move file by file to the end of the tape
247 */
248 int file_num;
249 for (file_num = file; !AtEot(); file_num++) {
250 Dmsg0(200, "eod: doing fsf 1\n");
251 if (!fsf(1)) {
252 Dmsg0(100, "fsf error.\n");
253 return false;
254 }
255 /*
256 * Avoid infinite loop by ensuring we advance.
257 */
258 if (!AtEot() && file_num == (int)file) {
259 Dmsg1(100, "fsf did not advance from file %d\n", file_num);
260 SetAteof();
261 os_file = GetOsTapeFile();
262 if (os_file >= 0) {
263 Dmsg2(100, "Adjust file from %d to %d\n", file_num, os_file);
264 file = os_file;
265 }
266 break;
267 }
268 }
269 #ifdef MTEOM
270 }
271 #endif
272
273 /*
274 * Some drivers leave us after second EOF when doing MTEOM, so we must backup
275 * so that appending overwrites the second EOF.
276 */
277 if (HasCap(CAP_BSFATEOM)) {
278 /*
279 * Backup over EOF
280 */
281 ok = bsf(1);
282
283 /*
284 * If BSF worked and fileno is known (not -1), set file
285 */
286 os_file = GetOsTapeFile();
287 if (os_file >= 0) {
288 Dmsg2(100, "BSFATEOF adjust file from %d to %d\n", file, os_file);
289 file = os_file;
290 } else {
291 file++; /* wing it -- not correct on all OSes */
292 }
293 } else {
294 UpdatePos(dcr); /* update position */
295 }
296 Dmsg1(200, "EOD dev->file=%d\n", file);
297
298 return ok;
299 }
300
301 /**
302 * Called to indicate that we have just read an EOF from the device.
303 */
SetAteof()304 void generic_tape_device::SetAteof()
305 {
306 SetEof();
307 file++;
308 file_addr = 0;
309 file_size = 0;
310 block_num = 0;
311 }
312
313 /**
314 * Called to indicate we are now at the end of the volume, and writing is not
315 * possible.
316 */
SetAteot()317 void generic_tape_device::SetAteot()
318 {
319 /*
320 * Make volume effectively read-only
321 */
322 SetBit(ST_EOF, state);
323 SetBit(ST_EOT, state);
324 SetBit(ST_WEOT, state);
325 ClearAppend();
326 }
327
328 /**
329 * Rewind device and put it offline
330 *
331 * Returns: true on success
332 * false on failure
333 */
offline()334 bool generic_tape_device::offline()
335 {
336 mtop mt_com{};
337
338 /*
339 * Remove EOF/EOT flags.
340 */
341 ClearBit(ST_APPENDREADY, state);
342 ClearBit(ST_READREADY, state);
343 ClearBit(ST_EOT, state);
344 ClearBit(ST_EOF, state);
345 ClearBit(ST_WEOT, state);
346
347 block_num = file = 0;
348 file_size = 0;
349 file_addr = 0;
350 UnlockDoor();
351 mt_com.mt_op = MTOFFL;
352 mt_com.mt_count = 1;
353
354 if (d_ioctl(fd, MTIOCTOP, (char*)&mt_com) < 0) {
355 BErrNo be;
356 dev_errno = errno;
357 Mmsg2(errmsg, _("ioctl MTOFFL error on %s. ERR=%s.\n"), prt_name,
358 be.bstrerror());
359 return false;
360 }
361 Dmsg1(100, "Offlined device %s\n", prt_name);
362
363 return true;
364 }
365
366 /**
367 * Write an end of file on the device
368 *
369 * Returns: true on success
370 * false on failure
371 */
weof(int num)372 bool generic_tape_device::weof(int num)
373 {
374 mtop mt_com{};
375 int status;
376 Dmsg1(129, "=== weof_dev=%s\n", prt_name);
377
378 if (!IsOpen()) {
379 dev_errno = EBADF;
380 Mmsg0(errmsg, _("Bad call to weof_dev. Device not open\n"));
381 Emsg0(M_FATAL, 0, errmsg);
382 return false;
383 }
384 file_size = 0;
385
386 if (!CanAppend()) {
387 Mmsg0(errmsg, _("Attempt to WEOF on non-appendable Volume\n"));
388 Emsg0(M_FATAL, 0, errmsg);
389 return false;
390 }
391
392 ClearEof();
393 ClearEot();
394 mt_com.mt_op = MTWEOF;
395 mt_com.mt_count = num;
396 status = d_ioctl(fd, MTIOCTOP, (char*)&mt_com);
397 if (status == 0) {
398 block_num = 0;
399 file += num;
400 file_addr = 0;
401 } else {
402 BErrNo be;
403
404 clrerror(mt_com.mt_op);
405 if (status == -1) {
406 Mmsg2(errmsg, _("ioctl MTWEOF error on %s. ERR=%s.\n"), prt_name,
407 be.bstrerror());
408 }
409 }
410
411 return status == 0;
412 }
413
414 /**
415 * Foward space a file
416 *
417 * Returns: true on success
418 * false on failure
419 */
fsf(int num)420 bool generic_tape_device::fsf(int num)
421 {
422 int32_t os_file = 0;
423 mtop mt_com{};
424 int status = 0;
425
426 if (!IsOpen()) {
427 dev_errno = EBADF;
428 Mmsg0(errmsg, _("Bad call to fsf. Device not open\n"));
429 Emsg0(M_FATAL, 0, errmsg);
430 return false;
431 }
432
433 if (AtEot()) {
434 dev_errno = 0;
435 Mmsg1(errmsg, _("Device %s at End of Tape.\n"), prt_name);
436 return false;
437 }
438
439 if (AtEof()) { Dmsg0(200, "ST_EOF set on entry to FSF\n"); }
440
441 Dmsg0(100, "fsf\n");
442 block_num = 0;
443
444 /*
445 * If Fast forward space file is set, then we
446 * use MTFSF to forward space and MTIOCGET
447 * to get the file position. We assume that
448 * the SCSI driver will ensure that we do not
449 * forward space past the end of the medium.
450 */
451 if (HasCap(CAP_FSF) && HasCap(CAP_MTIOCGET) && HasCap(CAP_FASTFSF)) {
452 int my_errno = 0;
453 mt_com.mt_op = MTFSF;
454 mt_com.mt_count = num;
455 status = d_ioctl(fd, MTIOCTOP, (char*)&mt_com);
456 if (status < 0) {
457 my_errno = errno; /* save errno */
458 } else if ((os_file = GetOsTapeFile()) < 0) {
459 my_errno = errno; /* save errno */
460 }
461 if (my_errno != 0) {
462 BErrNo be;
463
464 SetEot();
465 Dmsg0(200, "Set ST_EOT\n");
466 clrerror(mt_com.mt_op);
467 Mmsg2(errmsg, _("ioctl MTFSF error on %s. ERR=%s.\n"), prt_name,
468 be.bstrerror(my_errno));
469 Dmsg1(200, "%s", errmsg);
470 return false;
471 }
472
473 Dmsg1(200, "fsf file=%d\n", os_file);
474 SetAteof();
475 file = os_file;
476 return true;
477
478 /*
479 * Here if CAP_FSF is set, and virtually all drives
480 * these days support it, we read a record, then forward
481 * space one file. Using this procedure, which is slow,
482 * is the only way we can be sure that we don't read
483 * two consecutive EOF marks, which means End of Data.
484 */
485 } else if (HasCap(CAP_FSF)) {
486 POOLMEM* rbuf;
487 int rbuf_len;
488 Dmsg0(200, "FSF has cap_fsf\n");
489 if (max_block_size == 0) {
490 rbuf_len = DEFAULT_BLOCK_SIZE;
491 } else {
492 rbuf_len = max_block_size;
493 }
494 rbuf = GetMemory(rbuf_len);
495 mt_com.mt_op = MTFSF;
496 mt_com.mt_count = 1;
497 while (num-- && !AtEot()) {
498 Dmsg0(100, "Doing read before fsf\n");
499 if ((status = this->read((char*)rbuf, rbuf_len)) < 0) {
500 if (errno == ENOMEM) { /* tape record exceeds buf len */
501 status = rbuf_len; /* This is OK */
502 /*
503 * On IBM drives, they return ENOSPC at EOM instead of EOF status
504 */
505 } else if (AtEof() && errno == ENOSPC) {
506 status = 0;
507 } else if (HasCap(CAP_IOERRATEOM) && AtEof() && errno == EIO) {
508 if (HasCap(CAP_IBMLINTAPE)) {
509 Dmsg0(100, "Got EIO on read, checking lin_tape sense data\n");
510 if (CheckScsiAtEod(fd)) {
511 Dmsg0(100, "Sense data confirms it's EOD\n");
512 status = 0;
513 } else {
514 Dmsg0(100,
515 "Not at EOD, might be a real error. Check sense trace from "
516 "lin_taped logs.\n");
517 SetEot();
518 clrerror(-1);
519 Mmsg1(errmsg, _("read error on %s. ERR=Input/Output error.\n"),
520 prt_name);
521 break;
522 }
523 } else {
524 Dmsg0(100, "Got EIO on read, assuming that's due to EOD\n");
525 status = 0;
526 }
527 } else {
528 BErrNo be;
529
530 SetEot();
531 clrerror(-1);
532 Dmsg2(100, "Set ST_EOT read errno=%d. ERR=%s\n", dev_errno,
533 be.bstrerror());
534 Mmsg2(errmsg, _("read error on %s. ERR=%s.\n"), prt_name,
535 be.bstrerror());
536 Dmsg1(100, "%s", errmsg);
537 break;
538 }
539 }
540 if (status == 0) { /* EOF */
541 Dmsg1(100, "End of File mark from read. File=%d\n", file + 1);
542 /*
543 * Two reads of zero means end of tape
544 */
545 if (AtEof()) {
546 SetEot();
547 Dmsg0(100, "Set ST_EOT\n");
548 break;
549 } else {
550 SetAteof();
551 continue;
552 }
553 } else { /* Got data */
554 ClearEot();
555 ClearEof();
556 }
557
558 Dmsg0(100, "Doing MTFSF\n");
559 status = d_ioctl(fd, MTIOCTOP, (char*)&mt_com);
560 if (status < 0) { /* error => EOT */
561 BErrNo be;
562
563 SetEot();
564 Dmsg0(100, "Set ST_EOT\n");
565 clrerror(mt_com.mt_op);
566 Mmsg2(errmsg, _("ioctl MTFSF error on %s. ERR=%s.\n"), prt_name,
567 be.bstrerror());
568 Dmsg0(100, "Got < 0 for MTFSF\n");
569 Dmsg1(100, "%s", errmsg);
570 } else {
571 SetAteof();
572 }
573 }
574 FreeMemory(rbuf);
575
576 /*
577 * No FSF, so use FSR to simulate it
578 */
579 } else {
580 Dmsg0(200, "Doing FSR for FSF\n");
581 while (num-- && !AtEot()) { fsr(INT32_MAX); /* returns -1 on EOF or EOT */ }
582 if (AtEot()) {
583 dev_errno = 0;
584 Mmsg1(errmsg, _("Device %s at End of Tape.\n"), prt_name);
585 status = -1;
586 } else {
587 status = 0;
588 }
589 }
590 Dmsg1(200, "Return %d from FSF\n", status);
591 if (AtEof()) { Dmsg0(200, "ST_EOF set on exit FSF\n"); }
592 if (AtEot()) { Dmsg0(200, "ST_EOT set on exit FSF\n"); }
593 Dmsg1(200, "Return from FSF file=%d\n", file);
594
595 return status == 0;
596 }
597
598 /**
599 * Backward space a file
600 *
601 * Returns: false on failure
602 * true on success
603 */
bsf(int num)604 bool generic_tape_device::bsf(int num)
605 {
606 mtop mt_com{};
607 int status;
608
609 if (!IsOpen()) {
610 dev_errno = EBADF;
611 Mmsg0(errmsg, _("Bad call to bsf. Device not open\n"));
612 Emsg0(M_FATAL, 0, errmsg);
613 return false;
614 }
615
616 Dmsg0(100, "bsf\n");
617 ClearEot();
618 ClearEof();
619 file -= num;
620 file_addr = 0;
621 file_size = 0;
622 mt_com.mt_op = MTBSF;
623 mt_com.mt_count = num;
624
625 status = d_ioctl(fd, MTIOCTOP, (char*)&mt_com);
626 if (status < 0) {
627 BErrNo be;
628
629 clrerror(mt_com.mt_op);
630 Mmsg2(errmsg, _("ioctl MTBSF error on %s. ERR=%s.\n"), prt_name,
631 be.bstrerror());
632 }
633
634 return status == 0;
635 }
636
DevGetOsPos(Device * dev,struct mtget * mt_stat)637 static inline bool DevGetOsPos(Device* dev, struct mtget* mt_stat)
638 {
639 Dmsg0(100, "DevGetOsPos\n");
640 return dev->HasCap(CAP_MTIOCGET)
641 && dev->d_ioctl(dev->fd, MTIOCGET, (char*)mt_stat) == 0
642 && mt_stat->mt_fileno >= 0;
643 }
644
645 /**
646 * Foward space num records
647 *
648 * Returns: false on failure
649 * true on success
650 */
fsr(int num)651 bool generic_tape_device::fsr(int num)
652 {
653 mtop mt_com{};
654 int status;
655
656 if (!IsOpen()) {
657 dev_errno = EBADF;
658 Mmsg0(errmsg, _("Bad call to fsr. Device not open\n"));
659 Emsg0(M_FATAL, 0, errmsg);
660 return false;
661 }
662
663 if (!HasCap(CAP_FSR)) {
664 Mmsg1(errmsg, _("ioctl MTFSR not permitted on %s.\n"), prt_name);
665 return false;
666 }
667
668 Dmsg1(100, "fsr %d\n", num);
669 mt_com.mt_op = MTFSR;
670 mt_com.mt_count = num;
671
672 status = d_ioctl(fd, MTIOCTOP, (char*)&mt_com);
673 if (status == 0) {
674 ClearEof();
675 block_num += num;
676 } else {
677 BErrNo be;
678 struct mtget mt_stat;
679
680 clrerror(mt_com.mt_op);
681 Dmsg1(100, "FSF fail: ERR=%s\n", be.bstrerror());
682 if (DevGetOsPos(this, &mt_stat)) {
683 Dmsg4(100, "Adjust from %d:%d to %d:%d\n", file, block_num,
684 mt_stat.mt_fileno, mt_stat.mt_blkno);
685 file = mt_stat.mt_fileno;
686 block_num = mt_stat.mt_blkno;
687 } else {
688 if (AtEof()) {
689 SetEot();
690 } else {
691 SetAteof();
692 }
693 }
694 Mmsg3(errmsg, _("ioctl MTFSR %d error on %s. ERR=%s.\n"), num, prt_name,
695 be.bstrerror());
696 }
697
698 return status == 0;
699 }
700
701 /**
702 * Backward space a record
703 *
704 * Returns: false on failure
705 * true on success
706 */
bsr(int num)707 bool generic_tape_device::bsr(int num)
708 {
709 mtop mt_com{};
710 int status;
711
712 if (!IsOpen()) {
713 dev_errno = EBADF;
714 Mmsg0(errmsg, _("Bad call to bsr_dev. Device not open\n"));
715 Emsg0(M_FATAL, 0, errmsg);
716 return false;
717 }
718
719 if (!HasCap(CAP_BSR)) {
720 Mmsg1(errmsg, _("ioctl MTBSR not permitted on %s.\n"), prt_name);
721 return false;
722 }
723
724 Dmsg0(100, "bsr_dev\n");
725 block_num -= num;
726 ClearEof();
727 ClearEot();
728 mt_com.mt_op = MTBSR;
729 mt_com.mt_count = num;
730
731 status = d_ioctl(fd, MTIOCTOP, (char*)&mt_com);
732 if (status < 0) {
733 BErrNo be;
734
735 clrerror(mt_com.mt_op);
736 Mmsg2(errmsg, _("ioctl MTBSR error on %s. ERR=%s.\n"), prt_name,
737 be.bstrerror());
738 }
739
740 return status == 0;
741 }
742
743 /**
744 * Load medium in device
745 *
746 * Returns: true on success
747 * false on failure
748 */
LoadDev()749 bool generic_tape_device::LoadDev()
750 {
751 #ifdef MTLOAD
752 mtop mt_com{};
753 #endif
754
755 if (fd < 0) {
756 dev_errno = EBADF;
757 Mmsg0(errmsg, _("Bad call to LoadDev. Device not open\n"));
758 Emsg0(M_FATAL, 0, errmsg);
759 return false;
760 }
761
762 #ifndef MTLOAD
763 Dmsg0(200, "stored: MTLOAD command not available\n");
764 BErrNo be;
765 dev_errno = ENOTTY; /* function not available */
766 Mmsg2(errmsg, _("ioctl MTLOAD error on %s. ERR=%s.\n"), prt_name,
767 be.bstrerror());
768 return false;
769 #else
770 block_num = file = 0;
771 file_size = 0;
772 file_addr = 0;
773 mt_com.mt_op = MTLOAD;
774 mt_com.mt_count = 1;
775 if (d_ioctl(fd, MTIOCTOP, (char*)&mt_com) < 0) {
776 BErrNo be;
777 dev_errno = errno;
778 Mmsg2(errmsg, _("ioctl MTLOAD error on %s. ERR=%s.\n"), prt_name,
779 be.bstrerror());
780 return false;
781 }
782
783 return true;
784 #endif
785 }
786
LockDoor()787 void generic_tape_device::LockDoor()
788 {
789 #ifdef MTLOCK
790 mtop mt_com{};
791
792 mt_com.mt_op = MTLOCK;
793 mt_com.mt_count = 1;
794 if (d_ioctl(fd, MTIOCTOP, (char*)&mt_com) < 0) { clrerror(mt_com.mt_op); }
795 #endif
796 }
797
UnlockDoor()798 void generic_tape_device::UnlockDoor()
799 {
800 #ifdef MTUNLOCK
801 mtop mt_com{};
802
803 mt_com.mt_op = MTUNLOCK;
804 mt_com.mt_count = 1;
805 if (d_ioctl(fd, MTIOCTOP, (char*)&mt_com) < 0) { clrerror(mt_com.mt_op); }
806 #endif
807 }
808
OsClrError()809 void generic_tape_device::OsClrError()
810 {
811 #if defined(MTIOCLRERR)
812 // Found on Solaris
813 if (d_ioctl(fd, MTIOCLRERR) < 0) { HandleError(MTIOCLRERR); }
814 Dmsg0(200, "Did MTIOCLRERR\n");
815 #elif defined(MTIOCERRSTAT)
816 // Typically on FreeBSD
817 BErrNo be;
818 union mterrstat mt_errstat;
819
820 // Read and clear SCSI error status
821 Dmsg2(200, "Doing MTIOCERRSTAT errno=%d ERR=%s\n", dev_errno,
822 be.bstrerror(dev_errno));
823 if (d_ioctl(fd, MTIOCERRSTAT, (char*)&mt_errstat) < 0) {
824 HandleError(MTIOCERRSTAT);
825 }
826 #elif defined(MTCSE)
827 // Clear Subsystem Exception TRU64
828 mtop mt_com{};
829
830 /*
831 * Clear any error condition on the tape
832 */
833 mt_com.mt_op = MTCSE;
834 mt_com.mt_count = 1;
835 if (d_ioctl(fd, MTIOCTOP, (char*)&mt_com) < 0) { HandleError(mt_com.mt_op); }
836 Dmsg0(200, "Did MTCSE\n");
837 #endif
838 }
839
HandleError(int func)840 void generic_tape_device::HandleError(int func)
841 {
842 dev_errno = errno;
843 if (errno == EIO) {
844 VolCatInfo.VolCatErrors++;
845 } else if (errno == ENOTTY
846 || errno == ENOSYS) { /* Function not implemented */
847 std::string msg;
848 switch (func) {
849 case -1:
850 break; /* ignore message printed later */
851 case MTWEOF:
852 msg = "WTWEOF";
853 ClearCap(CAP_EOF); /* turn off feature */
854 break;
855 #ifdef MTEOM
856 case MTEOM:
857 msg = "WTEOM";
858 ClearCap(CAP_EOM); /* turn off feature */
859 break;
860 #endif
861 case MTFSF:
862 msg = "MTFSF";
863 ClearCap(CAP_FSF); /* turn off feature */
864 break;
865 case MTBSF:
866 msg = "MTBSF";
867 ClearCap(CAP_BSF); /* turn off feature */
868 break;
869 case MTFSR:
870 msg = "MTFSR";
871 ClearCap(CAP_FSR); /* turn off feature */
872 break;
873 case MTBSR:
874 msg = "MTBSR";
875 ClearCap(CAP_BSR); /* turn off feature */
876 break;
877 case MTREW:
878 msg = "MTREW";
879 break;
880 #ifdef MTSETBLK
881 case MTSETBLK:
882 msg = "MTSETBLK";
883 break;
884 #endif
885 #ifdef MTSETDRVBUFFER
886 case MTSETDRVBUFFER:
887 msg = "MTSETDRVBUFFER";
888 break;
889 #endif
890 #ifdef MTRESET
891 case MTRESET:
892 msg = "MTRESET";
893 break;
894 #endif
895 #ifdef MTSETBSIZ
896 case MTSETBSIZ:
897 msg = "MTSETBSIZ";
898 break;
899 #endif
900 #ifdef MTSRSZ
901 case MTSRSZ:
902 msg = "MTSRSZ";
903 break;
904 #endif
905 #ifdef MTLOAD
906 case MTLOAD:
907 msg = "MTLOAD";
908 break;
909 #endif
910 #ifdef MTLOCK
911 case MTLOCK:
912 msg = "MTLOCK";
913 break;
914 #endif
915 #ifdef MTUNLOCK
916 case MTUNLOCK:
917 msg = "MTUNLOCK";
918 break;
919 #endif
920 case MTOFFL:
921 msg = "MTOFFL";
922 break;
923 #ifdef MTIOCLRERR
924 case MTIOCLRERR:
925 msg = "MTIOCLRERR";
926 break;
927 #endif
928 #ifdef MTIOCERRSTAT
929 case MTIOCERRSTAT:
930 msg = "MTIOCERRSTAT";
931 break;
932 #endif
933 #ifdef MTCSE
934 case MTCSE:
935 msg = "MTCSE";
936 break;
937 #endif
938 default:
939 char buf[100];
940 Bsnprintf(buf, sizeof(buf), _("unknown func code %d"), func);
941 msg = buf;
942 break;
943 }
944 if (!msg.empty()) {
945 dev_errno = ENOSYS;
946 Mmsg1(errmsg, _("I/O function \"%s\" not supported on this device.\n"),
947 msg.c_str());
948 Emsg0(M_ERROR, 0, errmsg);
949 }
950 }
951 }
952
clrerror(int func)953 void generic_tape_device::clrerror(int func)
954 {
955 HandleError(func);
956
957 /*
958 * Now we try different methods of clearing the error status on the drive
959 * so that it is not locked for further operations.
960 */
961
962 /*
963 * On some systems such as NetBSD, this clears all errors
964 */
965 GetOsTapeFile();
966
967 // OS specific clear function.
968 OsClrError();
969 }
970
SetOsDeviceParameters(DeviceControlRecord * dcr)971 void generic_tape_device::SetOsDeviceParameters(DeviceControlRecord* dcr)
972 {
973 Device* dev = dcr->dev;
974
975 if (bstrcmp(dev->archive_device_string, "/dev/null")) {
976 return; /* no use trying to set /dev/null */
977 }
978
979 #if defined(HAVE_LINUX_OS) || defined(HAVE_WIN32)
980 mtop mt_com{};
981
982 Dmsg0(100, "In SetOsDeviceParameters\n");
983 # if defined(MTSETBLK)
984 if (dev->min_block_size == dev->max_block_size
985 && dev->min_block_size == 0) { /* variable block mode */
986 mt_com.mt_op = MTSETBLK;
987 mt_com.mt_count = 0;
988 Dmsg0(100, "Set block size to zero\n");
989 if (dev->d_ioctl(dev->fd, MTIOCTOP, (char*)&mt_com) < 0) {
990 dev->clrerror(mt_com.mt_op);
991 }
992 }
993 # endif
994 # if defined(MTSETDRVBUFFER)
995 if (getuid() == 0) { /* Only root can do this */
996 mt_com.mt_op = MTSETDRVBUFFER;
997 mt_com.mt_count = MT_ST_CLEARBOOLEANS;
998 if (!dev->HasCap(CAP_TWOEOF)) { mt_com.mt_count |= MT_ST_TWO_FM; }
999 if (dev->HasCap(CAP_EOM)) { mt_com.mt_count |= MT_ST_FAST_MTEOM; }
1000 Dmsg0(100, "MTSETDRVBUFFER\n");
1001 if (dev->d_ioctl(dev->fd, MTIOCTOP, (char*)&mt_com) < 0) {
1002 dev->clrerror(mt_com.mt_op);
1003 }
1004 }
1005 # endif
1006 return;
1007 #endif
1008
1009 #ifdef HAVE_NETBSD_OS
1010 mtop mt_com{};
1011 if (dev->min_block_size == dev->max_block_size
1012 && dev->min_block_size == 0) { /* variable block mode */
1013 mt_com.mt_op = MTSETBSIZ;
1014 mt_com.mt_count = 0;
1015 if (dev->d_ioctl(dev->fd, MTIOCTOP, (char*)&mt_com) < 0) {
1016 dev->clrerror(mt_com.mt_op);
1017 }
1018 /* Get notified at logical end of tape */
1019 mt_com.mt_op = MTEWARN;
1020 mt_com.mt_count = 1;
1021 if (dev->d_ioctl(dev->fd, MTIOCTOP, (char*)&mt_com) < 0) {
1022 dev->clrerror(mt_com.mt_op);
1023 }
1024 }
1025 return;
1026 #endif
1027
1028 #if HAVE_FREEBSD_OS || HAVE_OPENBSD_OS
1029 mtop mt_com{};
1030 if (dev->min_block_size == dev->max_block_size
1031 && dev->min_block_size == 0) { /* variable block mode */
1032 mt_com.mt_op = MTSETBSIZ;
1033 mt_com.mt_count = 0;
1034 if (dev->d_ioctl(dev->fd, MTIOCTOP, (char*)&mt_com) < 0) {
1035 dev->clrerror(mt_com.mt_op);
1036 }
1037 }
1038 # if defined(MTIOCSETEOTMODEL)
1039 uint32_t neof;
1040 if (dev->HasCap(CAP_TWOEOF)) {
1041 neof = 2;
1042 } else {
1043 neof = 1;
1044 }
1045 if (dev->d_ioctl(dev->fd, MTIOCSETEOTMODEL, (caddr_t)&neof) < 0) {
1046 BErrNo be;
1047 dev->dev_errno = errno; /* save errno */
1048 Mmsg2(dev->errmsg, _("Unable to set eotmodel on device %s: ERR=%s\n"),
1049 dev->print_name(), be.bstrerror(dev->dev_errno));
1050 Jmsg(dcr->jcr, M_FATAL, 0, dev->errmsg);
1051 }
1052 # endif
1053 return;
1054 #endif
1055
1056 #ifdef HAVE_SUN_OS
1057 mtop mt_com{};
1058 if (dev->min_block_size == dev->max_block_size
1059 && dev->min_block_size == 0) { /* variable block mode */
1060 mt_com.mt_op = MTSRSZ;
1061 mt_com.mt_count = 0;
1062 if (dev->d_ioctl(dev->fd, MTIOCTOP, (char*)&mt_com) < 0) {
1063 dev->clrerror(mt_com.mt_op);
1064 }
1065 }
1066 return;
1067 #endif
1068 }
1069
1070 /**
1071 * Returns file position on tape or -1
1072 */
GetOsTapeFile()1073 int32_t generic_tape_device::GetOsTapeFile()
1074 {
1075 struct mtget mt_stat;
1076
1077 if (HasCap(CAP_MTIOCGET) && d_ioctl(fd, MTIOCGET, (char*)&mt_stat) == 0) {
1078 return mt_stat.mt_fileno;
1079 }
1080
1081 return -1;
1082 }
1083
1084 /**
1085 * Rewind the device.
1086 *
1087 * Returns: true on success
1088 * false on failure
1089 */
rewind(DeviceControlRecord * dcr)1090 bool generic_tape_device::rewind(DeviceControlRecord* dcr)
1091 {
1092 mtop mt_com{};
1093 unsigned int i;
1094 bool first = true;
1095
1096 Dmsg3(400, "rewind res=%d fd=%d %s\n", NumReserved(), fd, prt_name);
1097
1098 /*
1099 * Remove EOF/EOT flags.
1100 */
1101 ClearBit(ST_EOT, state);
1102 ClearBit(ST_EOF, state);
1103 ClearBit(ST_WEOT, state);
1104
1105 block_num = file = 0;
1106 file_size = 0;
1107 file_addr = 0;
1108 if (fd < 0) { return false; }
1109
1110 mt_com.mt_op = MTREW;
1111 mt_com.mt_count = 1;
1112
1113 /*
1114 * If we get an I/O error on rewind, it is probably because
1115 * the drive is actually busy. We loop for (about 5 minutes)
1116 * retrying every 5 seconds.
1117 */
1118 for (i = max_rewind_wait;; i -= 5) {
1119 if (d_ioctl(fd, MTIOCTOP, (char*)&mt_com) < 0) {
1120 BErrNo be;
1121
1122 clrerror(mt_com.mt_op);
1123 if (i == max_rewind_wait) {
1124 Dmsg1(200, "Rewind error, %s. retrying ...\n", be.bstrerror());
1125 }
1126 /*
1127 * This is a gross hack, because if the user has the
1128 * device mounted (i.e. open), then uses mtx to load
1129 * a tape, the current open file descriptor is invalid.
1130 * So, we close the drive and re-open it.
1131 */
1132 if (first && dcr) {
1133 DeviceMode oo_mode = open_mode;
1134 d_close(fd);
1135 ClearOpened();
1136 open(dcr, oo_mode);
1137 if (fd < 0) { return false; }
1138 first = false;
1139 continue;
1140 }
1141 #ifdef HAVE_SUN_OS
1142 if (dev_errno == EIO) {
1143 Mmsg1(errmsg, _("No tape loaded or drive offline on %s.\n"), prt_name);
1144 return false;
1145 }
1146 #else
1147 if (dev_errno == EIO && i > 0) {
1148 Dmsg0(200, "Sleeping 5 seconds.\n");
1149 Bmicrosleep(5, 0);
1150 continue;
1151 }
1152 #endif
1153 Mmsg2(errmsg, _("Rewind error on %s. ERR=%s.\n"), prt_name,
1154 be.bstrerror());
1155 return false;
1156 }
1157 break;
1158 }
1159
1160 return true;
1161 }
1162
1163 // (Un)mount the device (for tape devices)
do_mount(DeviceControlRecord * dcr,int mount,int dotimeout)1164 bool generic_tape_device::do_mount(DeviceControlRecord* dcr, int mount, int dotimeout)
1165 {
1166 PoolMem ocmd(PM_FNAME);
1167 POOLMEM* results;
1168 char* icmd;
1169 int status, tries;
1170 BErrNo be;
1171
1172 if (mount) {
1173 icmd = device_resource->mount_command;
1174 } else {
1175 icmd = device_resource->unmount_command;
1176 }
1177
1178 EditMountCodes(ocmd, icmd);
1179 Dmsg2(100, "do_mount: cmd=%s mounted=%d\n", ocmd.c_str(),
1180 IsMounted());
1181
1182 if (dotimeout) {
1183 /* Try at most 10 times to (un)mount the device. This should perhaps be
1184 * configurable. */
1185 tries = 10;
1186 } else {
1187 tries = 1;
1188 }
1189 results = GetMemory(4000);
1190
1191 /* If busy retry each second */
1192 Dmsg1(100, "do_mount run_prog=%s\n", ocmd.c_str());
1193 while ((status = RunProgramFullOutput(ocmd.c_str(),
1194 max_open_wait / 2, results))
1195 != 0) {
1196 if (tries-- > 0) { continue; }
1197
1198 Dmsg5(100, "Device %s cannot be %smounted. stat=%d result=%s ERR=%s\n",
1199 print_name(), (mount ? "" : "un"), status, results,
1200 be.bstrerror(status));
1201 Mmsg(errmsg, _("Device %s cannot be %smounted. ERR=%s\n"),
1202 print_name(), (mount ? "" : "un"), be.bstrerror(status));
1203
1204 FreePoolMemory(results);
1205 Dmsg0(200, "============ mount=0\n");
1206 return false;
1207 }
1208
1209 FreePoolMemory(results);
1210 Dmsg1(200, "============ mount=%d\n", mount);
1211 return true;
1212 }
1213
StatusDev()1214 char* generic_tape_device::StatusDev()
1215 {
1216 struct mtget mt_stat;
1217 char* status;
1218
1219 status = (char*)malloc(BMT_BYTES);
1220 ClearAllBits(BMT_MAX, status);
1221
1222 if (BitIsSet(ST_EOT, state) || BitIsSet(ST_WEOT, state)) {
1223 SetBit(BMT_EOD, status);
1224 Pmsg0(-20, " EOD");
1225 }
1226
1227 if (BitIsSet(ST_EOF, state)) {
1228 SetBit(BMT_EOF, status);
1229 Pmsg0(-20, " EOF");
1230 }
1231
1232 SetBit(BMT_TAPE, status);
1233 Pmsg0(-20, _(" Bareos status:"));
1234 Pmsg2(-20, _(" file=%d block=%d\n"), file, block_num);
1235 if (d_ioctl(fd, MTIOCGET, (char*)&mt_stat) < 0) {
1236 BErrNo be;
1237
1238 dev_errno = errno;
1239 Mmsg2(errmsg, _("ioctl MTIOCGET error on %s. ERR=%s.\n"), print_name(),
1240 be.bstrerror());
1241 free(status);
1242 return 0;
1243 }
1244 Pmsg0(-20, _(" Device status:"));
1245
1246 #if defined(HAVE_LINUX_OS)
1247 if (GMT_EOF(mt_stat.mt_gstat)) {
1248 SetBit(BMT_EOF, status);
1249 Pmsg0(-20, " EOF");
1250 }
1251 if (GMT_BOT(mt_stat.mt_gstat)) {
1252 SetBit(BMT_BOT, status);
1253 Pmsg0(-20, " BOT");
1254 }
1255 if (GMT_EOT(mt_stat.mt_gstat)) {
1256 SetBit(BMT_EOT, status);
1257 Pmsg0(-20, " EOT");
1258 }
1259 if (GMT_SM(mt_stat.mt_gstat)) {
1260 SetBit(BMT_SM, status);
1261 Pmsg0(-20, " SM");
1262 }
1263 if (GMT_EOD(mt_stat.mt_gstat)) {
1264 SetBit(BMT_EOD, status);
1265 Pmsg0(-20, " EOD");
1266 }
1267 if (GMT_WR_PROT(mt_stat.mt_gstat)) {
1268 SetBit(BMT_WR_PROT, status);
1269 Pmsg0(-20, " WR_PROT");
1270 }
1271 if (GMT_ONLINE(mt_stat.mt_gstat)) {
1272 SetBit(BMT_ONLINE, status);
1273 Pmsg0(-20, " ONLINE");
1274 }
1275 if (GMT_DR_OPEN(mt_stat.mt_gstat)) {
1276 SetBit(BMT_DR_OPEN, status);
1277 Pmsg0(-20, " DR_OPEN");
1278 }
1279 if (GMT_IM_REP_EN(mt_stat.mt_gstat)) {
1280 SetBit(BMT_IM_REP_EN, status);
1281 Pmsg0(-20, " IM_REP_EN");
1282 }
1283 #elif defined(HAVE_WIN32)
1284 if (GMT_EOF(mt_stat.mt_gstat)) {
1285 SetBit(BMT_EOF, status);
1286 Pmsg0(-20, " EOF");
1287 }
1288 if (GMT_BOT(mt_stat.mt_gstat)) {
1289 SetBit(BMT_BOT, status);
1290 Pmsg0(-20, " BOT");
1291 }
1292 if (GMT_EOT(mt_stat.mt_gstat)) {
1293 SetBit(BMT_EOT, status);
1294 Pmsg0(-20, " EOT");
1295 }
1296 if (GMT_EOD(mt_stat.mt_gstat)) {
1297 SetBit(BMT_EOD, status);
1298 Pmsg0(-20, " EOD");
1299 }
1300 if (GMT_WR_PROT(mt_stat.mt_gstat)) {
1301 SetBit(BMT_WR_PROT, status);
1302 Pmsg0(-20, " WR_PROT");
1303 }
1304 if (GMT_ONLINE(mt_stat.mt_gstat)) {
1305 SetBit(BMT_ONLINE, status);
1306 Pmsg0(-20, " ONLINE");
1307 }
1308 if (GMT_DR_OPEN(mt_stat.mt_gstat)) {
1309 SetBit(BMT_DR_OPEN, status);
1310 Pmsg0(-20, " DR_OPEN");
1311 }
1312 if (GMT_IM_REP_EN(mt_stat.mt_gstat)) {
1313 SetBit(BMT_IM_REP_EN, status);
1314 Pmsg0(-20, " IM_REP_EN");
1315 }
1316 #endif /* HAVE_LINUX_OS || HAVE_WIN32 */
1317
1318 if (HasCap(CAP_MTIOCGET)) {
1319 Pmsg2(-20, _(" file=%d block=%d\n"), mt_stat.mt_fileno, mt_stat.mt_blkno);
1320 } else {
1321 Pmsg2(-20, _(" file=%d block=%d\n"), -1, -1);
1322 }
1323
1324 return status;
1325 }
1326
1327 /**
1328 * Set the position of the device.
1329 *
1330 * Returns: true on succes
1331 * false on error
1332 */
UpdatePos(DeviceControlRecord * dcr)1333 bool generic_tape_device::UpdatePos(DeviceControlRecord* dcr) { return true; }
1334
1335 /**
1336 * Reposition the device to file, block
1337 *
1338 * Returns: false on failure
1339 * true on success
1340 */
Reposition(DeviceControlRecord * dcr,uint32_t rfile,uint32_t rblock)1341 bool generic_tape_device::Reposition(DeviceControlRecord* dcr,
1342 uint32_t rfile,
1343 uint32_t rblock)
1344 {
1345 Dmsg4(100, "Reposition from %u:%u to %u:%u\n", file, block_num, rfile,
1346 rblock);
1347 if (rfile < file) {
1348 Dmsg0(100, "Rewind\n");
1349 if (!rewind(NULL)) { return false; }
1350 }
1351
1352 if (rfile > file) {
1353 Dmsg1(100, "fsf %d\n", rfile - file);
1354 if (!fsf(rfile - file)) {
1355 Dmsg1(100, "fsf failed! ERR=%s\n", bstrerror());
1356 return false;
1357 }
1358 Dmsg2(100, "wanted_file=%d at_file=%d\n", rfile, file);
1359 }
1360
1361 if (rblock < block_num) {
1362 Dmsg2(100, "wanted_blk=%d at_blk=%d\n", rblock, block_num);
1363 Dmsg0(100, "bsf 1\n");
1364 bsf(1);
1365 Dmsg0(100, "fsf 1\n");
1366 fsf(1);
1367 Dmsg2(100, "wanted_blk=%d at_blk=%d\n", rblock, block_num);
1368 }
1369
1370 if (HasCap(CAP_POSITIONBLOCKS) && rblock > block_num) {
1371 /*
1372 * Ignore errors as Bareos can read to the correct block.
1373 */
1374 Dmsg1(100, "fsr %d\n", rblock - block_num);
1375 return fsr(rblock - block_num);
1376 } else {
1377 while (rblock > block_num) {
1378 if (DeviceControlRecord::ReadStatus::Ok
1379 != dcr->ReadBlockFromDev(NO_BLOCK_NUMBER_CHECK)) {
1380 BErrNo be;
1381 dev_errno = errno;
1382 Dmsg2(30, "Failed to find requested block on %s: ERR=%s", prt_name,
1383 be.bstrerror());
1384 return false;
1385 }
1386 Dmsg2(300, "moving forward wanted_blk=%d at_blk=%d\n", rblock, block_num);
1387 }
1388 }
1389
1390 return true;
1391 }
1392
1393 /**
1394 * Mount the device.
1395 *
1396 * If timeout, wait until the mount command returns 0.
1397 * If !timeout, try to mount the device only once.
1398 */
MountBackend(DeviceControlRecord * dcr,int timeout)1399 bool generic_tape_device::MountBackend(DeviceControlRecord* dcr, int timeout)
1400 {
1401 bool retval = true;
1402
1403 if (RequiresMount() && device_resource->mount_command) {
1404 retval = do_mount(dcr, true, timeout);
1405 }
1406
1407 return retval;
1408 }
1409
1410 /**
1411 * Unmount the device
1412 *
1413 * If timeout, wait until the unmount command returns 0.
1414 * If !timeout, try to unmount the device only once.
1415 */
UnmountBackend(DeviceControlRecord * dcr,int timeout)1416 bool generic_tape_device::UnmountBackend(DeviceControlRecord* dcr, int timeout)
1417 {
1418 bool retval = true;
1419
1420 if (RequiresMount() && device_resource->unmount_command) {
1421 retval = do_mount(dcr, false, timeout);
1422 }
1423
1424 return retval;
1425 }
1426
d_open(const char * pathname,int flags,int mode)1427 int generic_tape_device::d_open(const char* pathname, int flags, int mode)
1428 {
1429 return ::open(pathname, flags, mode);
1430 }
1431
d_read(int fd,void * buffer,size_t count)1432 ssize_t generic_tape_device::d_read(int fd, void* buffer, size_t count)
1433 {
1434 return ::read(fd, buffer, count);
1435 }
1436
d_write(int fd,const void * buffer,size_t count)1437 ssize_t generic_tape_device::d_write(int fd, const void* buffer, size_t count)
1438 {
1439 return ::write(fd, buffer, count);
1440 }
1441
d_close(int fd)1442 int generic_tape_device::d_close(int fd) { return ::close(fd); }
1443
d_ioctl(int fd,ioctl_req_t request,char * op)1444 int generic_tape_device::d_ioctl(int fd, ioctl_req_t request, char* op)
1445 {
1446 return -1;
1447 }
1448
d_lseek(DeviceControlRecord * dcr,boffset_t offset,int whence)1449 boffset_t generic_tape_device::d_lseek(DeviceControlRecord* dcr,
1450 boffset_t offset,
1451 int whence)
1452 {
1453 return -1;
1454 }
1455
d_truncate(DeviceControlRecord * dcr)1456 bool generic_tape_device::d_truncate(DeviceControlRecord* dcr)
1457 {
1458 /*
1459 * Maybe we should rewind and write and eof ????
1460 */
1461 return true; /* We don't really truncate tapes */
1462 }
1463
1464 } /* namespace storagedaemon */
1465