1 /* NOTE: this driver is *deprecated* and should not be used. See the Device API
2 * in device-src/ for the new implementation.
14 #include <sys/ioctl.h>
20 #include "output-rait.h"
21 #include "output-tape.h"
24 #define amfree(x) do { \
26 int save_errno = errno; \
32 #define tape_open open
33 #define tapefd_read read
34 #define tapefd_write write
35 #define tapefd_close close
36 #define tape_access access
37 #define tape_stat stat
38 #define tapefd_fsf tape_tapefd_fsf
39 #define tapefd_rewind tape_tapefd_rewind
40 #define tapefd_status tape_tapefd_status
41 #define tapefd_unload tape_tapefd_unload
42 #define tapefd_weof tape_tapefd_weof
44 int tapeio_init_devname (char * dev,
48 char *tapeio_next_devname (char * dev_left,
54 ** RAIT -- redundant array of (inexpensive?) tapes
56 ** Author: Marc Mengel <mengel@fnal.gov>
58 ** This package provides for striping input/output across
59 ** multiple tape drives.
63 rait.c..................................................1
64 MAX_RAITS.........................................2
65 rait_table........................................2
66 rait_open(char *dev, int flags, mode_t mode)......2
67 rait_close(int fd)................................3
68 rait_lseek(int fd, long pos, int whence)..........4
69 rait_write(int fd, const char *buf, size_t len) ..5
70 rait_read(int fd, char *buf, size_t len)..........6
71 rait_ioctl(int fd, int op, void *p)...............8
72 rait_access(devname, R_OK|W_OK)...................8
73 rait_stat(devname, struct statbuf*)...............8
74 rait_copy(char *f1, char *f2).....................9
76 rait_tapefd_fsf(rait_tapefd, count)..........10
77 rait_tapefd_rewind(rait_tapefd)..............10
78 rait_tapefd_resetofs(rait_tapefd)............10
79 rait_tapefd_unload(rait_tapefd)..............10
80 rait_tapefd_status(rait_tapefd, stat)........10
81 rait_tapefd_weof(rait_tapefd, count).........10
83 rait.h.................................................1
84 typedef RAIT......................................1
85 ifdef RAIT_REDIRECT...............................1
86 open.........................................1
87 close........................................1
88 ioctl........................................1
89 read.........................................1
90 write........................................1
96 ** rait_open takes a string like:
97 ** "/dev/rmt/tps0d{3,5,7,19}nrnsv"
99 ** "/dev/rmt/tps0d3nrnsv"
100 ** "/dev/rmt/tps0d5nrnsv"
101 ** "/dev/rmt/tps0d7nrnsv"
102 ** "/dev/rmt/tps0d19nrnsv"
105 ** If it has no curly brace, we treat it as a plain device,
106 ** and do a normal open, and do normal operations on it.
110 #define rait_debug(...) do { \
111 int save_errno = errno; \
113 if (0 != getenv("RAIT_DEBUG")) { \
114 dbprintf(__VA_ARGS__); \
116 errno = save_errno; \
119 #define rait_debug(...)
122 static RAIT *rait_table = 0; /* table to keep track of RAITS */
123 static size_t rait_table_count;
127 * amtable_alloc -- (re)allocate enough space for some number of elements.
129 * input: table -- pointer to pointer to table
130 * current -- pointer to current number of elements
131 * elsize -- size of a table element
132 * count -- desired number of elements
133 * bump -- round up factor
134 * output: table -- possibly adjusted to point to new table area
135 * current -- possibly adjusted to new number of elements
150 if (count >= *current) {
151 table_count_new = ((count + bump) / bump) * bump;
152 table_new = alloc(table_count_new * elsize);
154 memcpy(table_new, *table, *current * elsize);
158 memset(((char *)*table) + *current * elsize,
160 (table_count_new - *current) * elsize);
161 *current = table_count_new;
167 * amtable_free -- release a table.
169 * input: table -- pointer to pointer to table
170 * current -- pointer to current number of elements
171 * output: table -- possibly adjusted to point to new table area
172 * current -- possibly adjusted to new number of elements
185 #define rait_table_alloc(fd) amtable_alloc((void **)rait_table_p, \
187 SIZEOF(*rait_table), \
198 int fd; /* the file descriptor number to return */
199 RAIT *res; /* resulting RAIT structure */
200 char *dev_left; /* string before { */
201 char *dev_right; /* string after } */
202 char *dev_next; /* string inside {} */
203 char *dev_real; /* parsed device name */
204 int rait_flag; /* true if RAIT syntax in dev */
207 RAIT **rait_table_p = &rait_table;
210 rait_debug(stderr,_("rait_open( %s, %d, %d )\n"), dev, flags, mask);
212 rait_flag = (0 != strchr(dev, '{'));
217 ** we have to return a valid file descriptor, so use
218 ** a dummy one to /dev/null
220 fd = open("/dev/null",flags,mask);
224 ** call the normal tape_open function if we are not
227 fd = tape_open(dev,flags,mask);
230 rait_debug(stderr, _("rait_open:returning %d: %s\n"),
236 if(0 != rait_table_alloc(fd + 1)) {
238 (void)tapefd_close(fd);
240 rait_debug(stderr, _("rait_open:returning %d: %s\n"),
246 res = &rait_table[fd];
248 memset(res, 0, SIZEOF(*res));
254 /* copy and parse the dev string so we can scribble on it */
257 rait_debug(stderr, _("rait_open:returning %d: %s\n"),
259 _("out of stralloc memory"));
262 if (0 != tapeio_init_devname(dev, &dev_left, &dev_right, &dev_next)) {
263 rait_debug(stderr, _("rait_open:returning %d: %s\n"),
269 while (0 != (dev_real = tapeio_next_devname(dev_left, dev_right, &dev_next))) {
271 r = amtable_alloc((void **)fds_p,
274 (size_t)res->nfds + 1,
278 (void)rait_close(fd);
283 res->fds[ res->nfds ] = tape_open(dev_real,flags,mask);
284 rait_debug(stderr,_("rait_open:opening %s yields %d\n"),
285 dev_real, res->fds[res->nfds] );
286 if ( res->fds[res->nfds] < 0 ) {
288 (void)rait_close(fd);
294 tapefd_set_master_fd(res->fds[res->nfds], fd);
299 /* clean up our copied string */
305 ** set things up to treat this as a normal tape if we ever
306 ** come in here again
311 r = amtable_alloc((void **)fds_p,
314 (size_t)res->nfds + 1,
318 (void)tapefd_close(fd);
319 memset(res, 0, SIZEOF(*res));
323 res->fds[res->nfds] = fd;
328 if (fd >= 0 && res->nfds > 0) {
329 res->readres = alloc(res->nfds * SIZEOF(*res->readres));
330 memset(res->readres, 0, res->nfds * SIZEOF(*res->readres));
333 rait_debug(stderr, _("rait_open:returning %d%s%s\n"),
335 (fd < 0) ? ": " : "",
336 (fd < 0) ? strerror(errno) : "");
350 ** find the first { and then the first } that follows it
352 if ( 0 == (*dev_next = strchr(dev, '{'))
353 || 0 == (*dev_right = strchr(*dev_next + 1, '}')) ) {
354 /* we dont have a {} pair */
360 *dev_left = dev; /* before the { */
361 **dev_next = 0; /* zap the { */
363 (*dev_right)++; /* after the } */
378 if (0 != (*dev_next = strchr(next, ','))
379 || 0 != (*dev_next = strchr(next, '}'))){
381 **dev_next = 0; /* zap the terminator */
385 ** we have one string picked out, build it into the buffer
387 len = strlen(dev_left) + strlen(next) + strlen(dev_right) + 1;
388 dev_real = alloc(len);
389 strcpy(dev_real, dev_left); /* safe */
390 strcat(dev_real, next); /* safe */
391 strcat(dev_real, dev_right); /* safe */
398 ** close everything we opened and free our memory.
404 int i; /* index into RAIT drives */
405 int j; /* individual tapefd_close result */
406 int res; /* result from close */
407 RAIT *pr; /* RAIT entry from table */
408 int save_errno = errno;
412 rait_debug(stderr,_("rait_close( %d )\n"), fd);
414 if ((fd < 0) || ((size_t)fd >= rait_table_count)) {
416 rait_debug(stderr, _("rait_close:returning %d: %s\n"),
422 pr = &rait_table[fd];
423 if (0 == pr->nopen) {
425 rait_debug(stderr, _("rait_close:returning %d: %s\n"),
431 if (0 == pr->readres && 0 < pr->nfds) {
432 pr->readres = alloc(pr->nfds * SIZEOF(*pr->readres));
433 memset(pr->readres, 0, pr->nfds * SIZEOF(*pr->readres));
438 ** this looks strange, but we start kids who are going to close the
439 ** drives in parallel just after the parent has closed their copy of
440 ** the descriptor. ('cause closing tape devices usually causes slow
441 ** activities like filemark writes, etc.)
443 for( i = 0; i < pr->nfds; i++ ) {
444 if(tapefd_can_fork(pr->fds[i])) {
445 if ((kid = fork()) == 0) {
446 /* we are the child process */
448 j = tapefd_close(pr->fds[i]);
451 /* remember who the child is or that an error happened */
452 pr->readres[i] = (ssize_t)kid;
456 j = tapefd_close(pr->fds[i]);
463 for( i = 0; i < pr->nfds; i++ ) {
464 j = tapefd_close(pr->fds[i]);
469 for( i = 0; i < pr->nfds; i++ ) {
471 if(pr->readres[i] != -1) {
472 waitpid((pid_t)pr->readres[i], &stat, 0);
473 if( WEXITSTATUS(stat) != 0 ) {
474 res = WEXITSTATUS(stat);
481 (void)close(fd); /* close the dummy /dev/null descriptor */
485 amtable_free((void **)fds_p, &pr->fd_count);
487 if (0 != pr->readres) {
490 if (0 != pr->xorbuf) {
495 rait_debug(stderr, _("rait_close:returning %d%s%s\n"),
497 (res < 0) ? ": " : "",
498 (res < 0) ? strerror(errno) : "");
505 ** seek out to the nth byte on the RAIT set.
506 ** this is assumed to be evenly divided across all the stripes
514 int i; /* drive number in RAIT */
515 off_t res, /* result of lseeks */
516 total; /* total of results */
517 RAIT *pr; /* RAIT slot in table */
519 rait_debug(stderr, _("rait_lseek(%d, %lld, %d)\n"),
520 fd, (long long)pos, whence);
522 if ((fd < 0) || ((size_t)fd >= rait_table_count)) {
524 rait_debug(stderr, _("rait_lseek:returning %d: %s\n"),
530 pr = &rait_table[fd];
531 if (0 == pr->nopen) {
533 rait_debug(stderr, _("rait_lseek:returning %d: %s\n"),
539 if ((pr->nfds > 1) && ((pos % (off_t)(pr->nfds-1)) != (off_t)0)) {
544 pos = pos / (off_t)pr->nfds;
545 for( i = 0; i < pr->nfds; i++ ) {
546 if ((off_t)0 >= (res = lseek(pr->fds[i], pos, whence))) {
553 rait_debug(stderr, _("rait_lseek:returning %ld%s%s\n"),
555 (total < 0) ? ": " : "",
556 (total < 0) ? strerror(errno) : "");
563 ** if we only have one stream, just do a write,
564 ** otherwise compute an xor sum, and do several
573 const char *buf = bufptr;
574 int i; /* drive number */
575 size_t j; /* byte offset */
576 RAIT *pr; /* RAIT structure for this RAIT */
579 int data_fds; /* number of data stream file descriptors */
581 rait_debug(stderr, _("rait_write(%d,%lx,%d)\n"),fd,(unsigned long)buf,len);
583 if ((fd < 0) || ((size_t)fd >= rait_table_count)) {
585 rait_debug(stderr, _("rait_write:returning %d: %s\n"),
591 pr = &rait_table[fd];
592 if (0 == pr->nopen) {
594 rait_debug(stderr, _("rait_write:returning %d: %s\n"),
600 /* need to be able to slice it up evenly... */
602 data_fds = pr->nfds - 1;
603 if (0 != len % data_fds) {
605 rait_debug(stderr, _("rait_write:returning %d: %s\n"),
610 /* each slice gets an even portion */
611 len = len / data_fds;
613 /* make sure we have enough buffer space */
614 if (len > (size_t)pr->xorbuflen) {
615 if (0 != pr->xorbuf) {
618 pr->xorbuf = alloc(len);
622 /* compute the sum */
623 memcpy(pr->xorbuf, buf, len);
624 for( i = 1; i < data_fds; i++ ) {
625 for( j = 0; j < len; j++ ) {
626 pr->xorbuf[j] ^= buf[len * i + j];
633 /* write the chunks in the main buffer */
634 for( i = 0; i < data_fds; i++ ) {
635 res = tapefd_write(pr->fds[i], buf + len*i , len);
636 rait_debug(stderr, _("rait_write: write(%d,%lx,%d) returns %d%s%s\n"),
638 (unsigned long)(buf + len*i),
641 (res < 0) ? ": " : "",
642 (res < 0) ? strerror(errno) : "");
649 if (total >= 0 && pr->nfds > 1) {
650 /* write the sum, don't include it in the total bytes written */
651 res = tapefd_write(pr->fds[i], pr->xorbuf, len);
652 rait_debug(stderr, _("rait_write: write(%d,%lx,%d) returns %d%s%s\n"),
654 (unsigned long)pr->xorbuf,
657 (res < 0) ? ": " : "",
658 (res < 0) ? strerror(errno) : "");
664 rait_debug(stderr, _("rait_write:returning %d%s%s\n"),
666 (total < 0) ? ": " : "",
667 (total < 0) ? strerror(errno) : "");
675 ** once again, if there is one data stream do a read, otherwise
676 ** do all n reads, and if any of the first n - 1 fail, compute
677 ** the missing block from the other three, then return the data.
678 ** there's some silliness here for reading tape with bigger buffers
679 ** than we wrote with, (thus the extra bcopys down below). On disk if
680 ** you read with a bigger buffer size than you wrote with, you just
681 ** garble the data...
690 int nerrors, neofs, errorblock;
696 int save_errno = errno;
697 ssize_t maxreadres = 0;
698 int sum_mismatch = 0;
700 rait_debug(stderr, _("rait_read(%d,%lx,%d)\n"),fd,(unsigned long)buf,len);
702 if ((fd < 0) || ((size_t)fd >= rait_table_count)) {
704 rait_debug(stderr, _("rait_read:returning %d: %s\n"),
710 pr = &rait_table[fd];
711 if (0 == pr->nopen) {
713 rait_debug(stderr, _("rait_read:returning %d: %s\n"),
722 /* once again , we slice it evenly... */
724 data_fds = pr->nfds - 1;
725 if (0 != len % data_fds) {
727 rait_debug(stderr, _("rait_read:returning %d: %s\n"),
732 len = len / data_fds;
737 /* try all the reads, save the result codes */
738 /* count the eof/errors */
739 for( i = 0; i < data_fds; i++ ) {
740 pr->readres[i] = tapefd_read(pr->fds[i], buf + len*i , len);
741 rait_debug(stderr, _("rait_read: read on fd %d returns %d%s%s\n"),
744 (pr->readres[i] < 0) ? ": " : "",
745 (pr->readres[i] < 0) ? strerror(errno) : "");
746 if ( pr->readres[i] <= 0 ) {
747 if ( pr->readres[i] == 0 ) {
756 } else if (pr->readres[i] > maxreadres) {
757 maxreadres = pr->readres[i];
761 /* make sure we have enough buffer space */
762 if (len > (size_t)pr->xorbuflen) {
763 if (0 != pr->xorbuf) {
766 pr->xorbuf = alloc(len);
769 pr->readres[i] = tapefd_read(pr->fds[i], pr->xorbuf , len);
770 rait_debug(stderr, _("rait_read: read on fd %d returns %d%s%s\n"),
773 (pr->readres[i] < 0) ? ": " : "",
774 (pr->readres[i] < 0) ? strerror(errno) : "");
778 * Make sure all the reads were the same length
780 for (j = 0; j < (size_t)pr->nfds; j++) {
781 if (pr->readres[j] != maxreadres) {
788 * If no errors, check that the xor sum matches
790 if ( nerrors == 0 && pr->nfds > 1 ) {
791 for(i = 0; i < (int)maxreadres; i++ ) {
793 for(j = 0; (j + 1) < (size_t)pr->nfds; j++) {
794 sum ^= (buf + len * j)[i];
796 if (sum != pr->xorbuf[i]) {
803 ** now decide what "really" happened --
804 ** all n getting eof is a "real" eof
805 ** just one getting an error/eof is recoverable if we are doing RAIT
806 ** anything else fails
809 if (neofs == pr->nfds) {
810 rait_debug(stderr, _("rait_read:returning 0\n"));
816 rait_debug(stderr, _("rait_read:returning %d: %s\n"),
818 _("XOR block mismatch"));
822 if (nerrors > 1 || (pr->nfds <= 1 && nerrors > 0)) {
824 rait_debug(stderr, _("rait_read:returning %d: %s\n"),
831 ** so now if we failed on a data block, we need to do a recovery
832 ** if we failed on the xor block -- who cares?
834 if (nerrors == 1 && pr->nfds > 1 && errorblock != pr->nfds-1) {
836 rait_debug(stderr, _("rait_read: fixing data from fd %d\n"),
837 pr->fds[errorblock]);
839 /* the reads were all *supposed* to be the same size, so... */
840 pr->readres[errorblock] = maxreadres;
842 /* fill it in first with the xor sum */
843 memcpy(buf + len * errorblock, pr->xorbuf, len);
845 /* xor back out the other blocks */
846 for( i = 0; i < data_fds; i++ ) {
847 if( i != errorblock ) {
848 for( j = 0; j < len ; j++ ) {
849 buf[j + len * errorblock] ^= buf[j + len * i];
853 /* there, now the block is back as if it never failed... */
856 /* pack together partial reads... */
857 total = pr->readres[0];
858 for( i = 1; i < data_fds; i++ ) {
859 if (total != (ssize_t)(len * i)) {
860 memmove(buf + total, buf + len*i, (size_t)pr->readres[i]);
862 total += pr->readres[i];
865 rait_debug(stderr, _("rait_read:returning %d%s%s\n"),
867 (total < 0) ? ": " : "",
868 (total < 0) ? strerror(errno) : "");
885 rait_debug(stderr, _("rait_ioctl(%d,%d)\n"),fd,op);
887 if ((fd < 0) || ((size_t)fd >= rait_table_count)) {
889 rait_debug(stderr, _("rait_ioctl:returning %d: %s\n"),
895 pr = &rait_table[fd];
896 if (0 == pr->nopen) {
898 rait_debug(stderr, _("rait_ioctl:returning %d: %s\n"),
904 for( i = 0; i < pr->nfds ; i++ ) {
906 res = ioctl(pr->fds[i], op, p);
917 rait_debug(stderr, _("rait_ioctl: returning %d%s%s\n"),
919 (res < 0) ? ": " : "",
920 (res < 0) ? strerror(errno) : "");
926 ** access() all the devices, returning if any fail
934 char *dev_left; /* string before { */
935 char *dev_right; /* string after } */
936 char *dev_next; /* string inside {} */
937 char *dev_real; /* parsed device name */
939 /* copy and parse the dev string so we can scribble on it */
940 devname = stralloc(devname);
942 rait_debug(stderr, _("rait_access:returning %d: %s\n"),
944 _("out of stralloc memory"));
947 if ( 0 != tapeio_init_devname(devname, &dev_left, &dev_right, &dev_next)) {
948 rait_debug(stderr, _("rait_access:returning %d: %s\n"),
954 while( 0 != (dev_real = tapeio_next_devname(dev_left, dev_right, &dev_next))) {
955 res = tape_access(dev_real, flags);
956 rait_debug(stderr,_("rait_access:access( %s, %d ) yields %d\n"),
957 dev_real, flags, res );
965 rait_debug(stderr, _("rait_access: returning %d%s%s\n"),
967 (res < 0) ? ": " : "",
968 (res < 0) ? strerror(errno) : "");
974 ** stat all the devices, returning the last one unless one fails
982 char *dev_left; /* string before { */
983 char *dev_right; /* string after } */
984 char *dev_next; /* string inside {} */
985 char *dev_real; /* parsed device name */
987 /* copy and parse the dev string so we can scribble on it */
988 devname = stralloc(devname);
990 rait_debug(stderr, _("rait_access:returning %d: %s\n"),
992 _("out of stralloc memory"));
995 if ( 0 != tapeio_init_devname(devname, &dev_left, &dev_right, &dev_next)) {
996 rait_debug(stderr, _("rait_access:returning %d: %s\n"),
1002 while( 0 != (dev_real = tapeio_next_devname(dev_left, dev_right, &dev_next))) {
1003 res = tape_stat(dev_real, buf);
1004 rait_debug(stderr,_("rait_stat:stat( %s ) yields %d (%s)\n"),
1005 dev_real, res, (res != 0) ? strerror(errno) : _("no error") );
1013 rait_debug(stderr, _("rait_access: returning %d%s%s\n"),
1015 (res < 0) ? ": " : "",
1016 (res < 0) ? strerror(errno) : "");
1035 t1 = rait_open(f1,O_RDONLY,0644);
1039 t2 = rait_open(f2,O_CREAT|O_RDWR,0644);
1042 (void)rait_close(t1);
1046 buf = alloc(buflen);
1048 len = rait_read(t1,buf,buflen);
1050 wres = rait_write(t2, buf, (size_t)len);
1059 (void)rait_close(t1);
1060 (void)rait_close(t2);
1062 return (len < 0) ? -1 : 0;
1068 ** Amanda Tape API routines:
1074 int (*func1)(int, off_t),
1084 rait_debug(stderr, _("rait_tapefd_ioctl(%d,%d)\n"),fd,count);
1086 if ((fd < 0) || ((size_t)fd >= rait_table_count)) {
1088 rait_debug(stderr, _("rait_tapefd_ioctl:returning %d: %s\n"),
1094 pr = &rait_table[fd];
1095 if (0 == pr->nopen) {
1097 rait_debug(stderr, _("rait_tapefd_ioctl:returning %d: %s\n"),
1103 if (0 == pr->readres && 0 < pr->nfds) {
1104 pr->readres = alloc(pr->nfds * SIZEOF(*pr->readres));
1105 memset(pr->readres, 0, pr->nfds * SIZEOF(*pr->readres));
1108 for( i = 0; i < pr->nfds ; i++ ) {
1109 if(tapefd_can_fork(pr->fds[i])) {
1110 if ((kid = fork()) < 1) {
1111 rait_debug(stderr, _("in kid, fork returned %d\n"), kid);
1112 /* if we are the kid, or fork failed do the action */
1113 if (func0 != NULL) {
1114 res = (*func0)(pr->fds[i]);
1116 res = (*func1)(pr->fds[i], count);
1118 rait_debug(stderr, _("in kid, func (%d) returned %d errno %s\n"),
1119 pr->fds[i], res, strerror(errno));
1123 rait_debug(stderr, _("in parent, fork returned %d\n"), kid);
1124 pr->readres[i] = (ssize_t)kid;
1129 j = (*func0)(pr->fds[i]);
1131 j = (*func1)(pr->fds[i], count);
1136 pr->readres[i] = -1;
1139 for( i = 0; i < pr->nfds ; i++ ) {
1140 if(tapefd_can_fork(pr->fds[i])) {
1141 rait_debug(stderr, _("in parent, waiting for %d\n"), pr->readres[i]);
1142 waitpid((pid_t)pr->readres[i], &status, 0);
1143 if( WEXITSTATUS(status) != 0 ) {
1144 res = WEXITSTATUS(status);
1148 rait_debug(stderr, _("in parent, return code was %d\n"), res);
1159 rait_debug(stderr, _("rait_tapefd_ioctl: returning %d%s%s\n"),
1161 (res < 0) ? ": " : "",
1162 (res < 0) ? strerror(errno) : "");
1172 return rait_tapefd_ioctl(NULL, tapefd_fsf, fd, count);
1179 return rait_tapefd_ioctl(tapefd_rewind, NULL, fd, (off_t)-1);
1186 return rait_tapefd_ioctl(tapefd_unload, NULL, fd, (off_t)-1);
1194 return rait_tapefd_ioctl(NULL, tapefd_weof, fd, count);
1203 return rait_open(name, flags, mask);
1209 struct am_mt_status *stat)
1216 rait_debug(stderr, _("rait_tapefd_status(%d)\n"),fd);
1218 if ((fd < 0) || ((size_t)fd >= rait_table_count)) {
1220 rait_debug(stderr, _("rait_tapefd_status:returning %d: %s\n"),
1226 pr = &rait_table[fd];
1227 if (0 == pr->nopen) {
1229 rait_debug(stderr, _("rait_tapefd_status:returning %d: %s\n"),
1235 for( i = 0; i < pr->nfds ; i++ ) {
1236 res = tapefd_status(pr->fds[i], stat);
1248 rait_tapefd_resetofs(
1251 (void)rait_lseek(fd, (off_t)0, SEEK_SET);
1255 rait_tapefd_can_fork(
1258 (void)fd; /* Quiet unused parameter warning */