b36e264974bad601cc900e1433ddec71dc1b9e71
[debian/amanda] / tape-src / output-rait.c
1 /* NOTE: this driver is *deprecated* and should not be used.  See the Device API
2  * in device-src/ for the new implementation.
3  */
4
5 #ifdef NO_AMANDA
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <unistd.h>
9 #include <string.h>
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <sys/stat.h>
13 #include <sys/wait.h>
14 #include <sys/ioctl.h>
15 #else
16 #include "amanda.h"
17 #include "tapeio.h"
18 #endif
19
20 #include "output-rait.h"
21 #include "output-tape.h"
22
23 #ifdef NO_AMANDA
24 #define amfree(x)       do {                                            \
25         if (x) {                                                        \
26             int save_errno = errno;                                     \
27             free(x);                                                    \
28             (x) = NULL;                                                 \
29             errno = save_errno;                                         \
30         }
31 } while(0)
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
43
44 int tapeio_init_devname (char * dev,
45                          char **dev_left,
46                          char **dev_right,
47                          char **dev_next);
48 char *tapeio_next_devname (char * dev_left,
49                            char * dev_right,
50                            char **dev_next);
51 #endif
52
53 /*
54 ** RAIT -- redundant array of (inexpensive?) tapes
55 **
56 ** Author: Marc Mengel <mengel@fnal.gov>
57 **
58 ** This package provides for striping input/output across
59 ** multiple tape drives.
60 **
61                  Table of Contents
62
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
75         ifndef NO_AMANDA
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
82
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
91 */
92
93 /*\f*/
94
95 /*
96 ** rait_open takes a string like:
97 ** "/dev/rmt/tps0d{3,5,7,19}nrnsv"
98 ** and opens
99 ** "/dev/rmt/tps0d3nrnsv"
100 ** "/dev/rmt/tps0d5nrnsv"
101 ** "/dev/rmt/tps0d7nrnsv"
102 ** "/dev/rmt/tps0d19nrnsv"
103 ** as a RAIT.
104 **
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.
107 */
108
109 #ifdef RAIT_DEBUG
110 #define rait_debug(...) do {                                            \
111   int save_errno = errno;                                               \
112                                                                         \
113   if (0 != getenv("RAIT_DEBUG")) {                                      \
114     dbprintf(__VA_ARGS__);                                              \
115   }                                                                     \
116   errno = save_errno;                                                   \
117 } while (0)
118 #else
119 #define rait_debug(...)
120 #endif
121
122 static RAIT *rait_table = 0;            /* table to keep track of RAITS */
123 static size_t rait_table_count;
124
125 #ifdef NO_AMANDA
126 /*
127  * amtable_alloc -- (re)allocate enough space for some number of elements.
128  *
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
136  */
137
138 static int
139 amtable_alloc(
140     void **     table,
141     int *       current,
142     size_t      elsize,
143     int         count,
144     int         bump,
145     void *      dummy)
146 {
147     void *table_new;
148     int table_count_new;
149
150     if (count >= *current) {
151         table_count_new = ((count + bump) / bump) * bump;
152         table_new = alloc(table_count_new * elsize);
153         if (0 != *table) {
154             memcpy(table_new, *table, *current * elsize);
155             amfree(*table);
156         }
157         *table = table_new;
158         memset(((char *)*table) + *current * elsize,
159                0,
160                (table_count_new - *current) * elsize);
161         *current = table_count_new;
162     }
163     return 0;
164 }
165
166 /*
167  * amtable_free -- release a table.
168  *
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
173  */
174
175 void
176 amtable_free(
177     void **     table,
178     int *       current)
179 {
180     amfree(*table);
181     *current = 0;
182 }
183 #endif
184
185 #define rait_table_alloc(fd)    amtable_alloc((void **)rait_table_p,         \
186                                               &rait_table_count,             \
187                                               SIZEOF(*rait_table),   \
188                                               (size_t)(fd),                  \
189                                               10,                            \
190                                               NULL)
191
192 int
193 rait_open(
194     char *      dev,
195     int         flags,
196     mode_t      mask)
197 {
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 */
205     int save_errno;
206     int r;
207     RAIT **rait_table_p = &rait_table;
208     int **fds_p;
209
210     rait_debug(stderr,_("rait_open( %s, %d, %d )\n"), dev, flags, mask);
211
212     rait_flag = (0 != strchr(dev, '{'));
213
214     if (rait_flag) {
215
216         /*
217         ** we have to return a valid file descriptor, so use
218         ** a dummy one to /dev/null
219         */
220         fd = open("/dev/null",flags,mask);
221     } else {
222
223         /*
224         ** call the normal tape_open function if we are not
225         ** going to do RAIT
226         */
227         fd = tape_open(dev,flags,mask);
228     }
229     if(-1 == fd) {
230         rait_debug(stderr, _("rait_open:returning %d: %s\n"),
231                             fd,
232                             strerror(errno));
233         return fd;
234     }
235
236     if(0 != rait_table_alloc(fd + 1)) {
237         save_errno = errno;
238         (void)tapefd_close(fd);
239         errno = save_errno;
240         rait_debug(stderr, _("rait_open:returning %d: %s\n"),
241                             -1,
242                             strerror(errno));
243         return -1;
244     }
245
246     res = &rait_table[fd];
247
248     memset(res, 0, SIZEOF(*res));
249     res->nopen = 1;
250
251     res->fd_count = 0;
252     if (rait_flag) {
253
254         /* copy and parse the dev string so we can scribble on it */
255         dev = stralloc(dev);
256         if (0 == dev) {
257             rait_debug(stderr, _("rait_open:returning %d: %s\n"),
258                                 -1,
259                                 _("out of stralloc memory"));
260             return -1;
261         }
262         if (0 != tapeio_init_devname(dev, &dev_left, &dev_right, &dev_next)) {
263             rait_debug(stderr, _("rait_open:returning %d: %s\n"),
264                                 -1,
265                                 strerror(errno));
266             return -1;
267         }
268
269         while (0 != (dev_real = tapeio_next_devname(dev_left, dev_right, &dev_next))) {
270             fds_p = &(res->fds);
271             r = amtable_alloc((void **)fds_p,
272                             &res->fd_count,
273                             SIZEOF(*res->fds),
274                             (size_t)res->nfds + 1,
275                             10,
276                             NULL);
277             if (0 != r) {
278                 (void)rait_close(fd);
279                 fd = -1;
280                 amfree(dev_real);
281                 break;
282             }
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 ) {
287                 save_errno = errno;
288                 (void)rait_close(fd);
289                 amfree(dev_real);
290                 errno = save_errno;
291                 fd = -1;
292                 break;
293             }
294             tapefd_set_master_fd(res->fds[res->nfds], fd);
295             amfree(dev_real);
296             res->nfds++;
297         }
298
299         /* clean up our copied string */
300         amfree(dev);
301
302     } else {
303
304         /*
305         ** set things up to treat this as a normal tape if we ever
306         ** come in here again
307         */
308
309         res->nfds = 0;
310         fds_p = &(res->fds);
311         r = amtable_alloc((void **)fds_p,
312                           &res->fd_count,
313                           SIZEOF(*res->fds),
314                           (size_t)res->nfds + 1,
315                           1,
316                           NULL);
317         if (0 != r) {
318             (void)tapefd_close(fd);
319             memset(res, 0, SIZEOF(*res));
320             errno = ENOMEM;
321             fd = -1;
322         } else {
323             res->fds[res->nfds] = fd;
324             res->nfds++;
325         }
326     }
327
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));
331     }
332
333     rait_debug(stderr, _("rait_open:returning %d%s%s\n"),
334                         fd,
335                         (fd < 0) ? ": " : "",
336                         (fd < 0) ? strerror(errno) : "");
337
338     return fd;
339 }
340
341 #ifdef NO_AMANDA
342 int
343 tapeio_init_devname(
344     char *      dev,
345     char **     dev_left,
346     char **     dev_right,
347     char **     dev_next)
348 {
349     /*
350     ** find the first { and then the first } that follows it
351     */
352     if ( 0 == (*dev_next = strchr(dev, '{'))
353          || 0 == (*dev_right = strchr(*dev_next + 1, '}')) ) {
354         /* we dont have a {} pair */
355         amfree(dev);
356         errno = EINVAL;
357         return -1;
358     }
359
360     *dev_left = dev;                            /* before the { */
361     **dev_next = 0;                             /* zap the { */
362     (*dev_next)++;
363     (*dev_right)++;                             /* after the } */
364     return 0;
365 }
366
367 char *
368 tapeio_next_devname(
369     char *      dev_left,
370     char *      dev_right,
371     char **     dev_next)
372 {
373     char *dev_real = 0;
374     char *next;
375     int len;
376
377     next = *dev_next;
378     if (0 != (*dev_next = strchr(next, ','))
379         || 0 != (*dev_next = strchr(next, '}'))){
380
381         **dev_next = 0;                         /* zap the terminator */
382         (*dev_next)++;
383
384         /*
385         ** we have one string picked out, build it into the buffer
386         */
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 */
392     }
393     return dev_real;
394 }
395 #endif
396
397 /*
398 ** close everything we opened and free our memory.
399 */
400 int
401 rait_close(
402     int fd)
403 {
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;
409     pid_t kid;
410     int **fds_p;
411
412     rait_debug(stderr,_("rait_close( %d )\n"), fd);
413
414     if ((fd < 0) || ((size_t)fd >= rait_table_count)) {
415         errno = EBADF;
416         rait_debug(stderr, _("rait_close:returning %d: %s\n"),
417                             -1,
418                             strerror(errno));
419         return -1;
420     }
421
422     pr = &rait_table[fd];
423     if (0 == pr->nopen) {
424         errno = EBADF;
425         rait_debug(stderr, _("rait_close:returning %d: %s\n"),
426                             -1,
427                             strerror(errno));
428         return -1;
429     }
430
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));
434     }
435
436     res = 0;
437     /*
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.)
442     */
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 */
447                 sleep(0);
448                 j = tapefd_close(pr->fds[i]);
449                 exit(j);
450             } else {
451                 /* remember who the child is or that an error happened */
452                 pr->readres[i] = (ssize_t)kid;
453             }
454         }
455         else {
456             j = tapefd_close(pr->fds[i]);
457             if ( j != 0 )
458                 res = j;
459             pr->readres[i] = -1;
460         }
461     }
462
463     for( i = 0; i < pr->nfds; i++ ) {
464         j = tapefd_close(pr->fds[i]);
465         if ( j != 0 )
466            res = j;
467     }
468
469     for( i = 0; i < pr->nfds; i++ ) {
470         int stat;
471         if(pr->readres[i] != -1) {
472             waitpid((pid_t)pr->readres[i], &stat, 0);
473             if( WEXITSTATUS(stat) != 0 ) {
474                 res = WEXITSTATUS(stat);
475                 if( res == 255 )
476                     res = -1;
477             }
478         }
479     }
480     if (pr->nfds > 1) {
481         (void)close(fd);        /* close the dummy /dev/null descriptor */
482     }
483     if (0 != pr->fds) {
484         fds_p = &pr->fds;
485         amtable_free((void **)fds_p, &pr->fd_count);
486     }
487     if (0 != pr->readres) {
488         amfree(pr->readres);
489     }
490     if (0 != pr->xorbuf) {
491         amfree(pr->xorbuf);
492     }
493     pr->nopen = 0;
494     errno = save_errno;
495     rait_debug(stderr, _("rait_close:returning %d%s%s\n"),
496                         res,
497                         (res < 0) ? ": " : "",
498                         (res < 0) ? strerror(errno) : "");
499     return res;
500 }
501
502 /*\f*/
503
504 /*
505 ** seek out to the nth byte on the RAIT set.
506 ** this is assumed to be evenly divided across all the stripes
507 */
508 off_t
509 rait_lseek(
510     int         fd,
511     off_t       pos,
512     int         whence)
513 {
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 */
518
519     rait_debug(stderr, _("rait_lseek(%d, %lld, %d)\n"),
520                 fd, (long long)pos, whence);
521
522     if ((fd < 0) || ((size_t)fd >= rait_table_count)) {
523         errno = EBADF;
524         rait_debug(stderr, _("rait_lseek:returning %d: %s\n"),
525                             -1,
526                             strerror(errno));
527         return (off_t)-1;
528     }
529
530     pr = &rait_table[fd];
531     if (0 == pr->nopen) {
532         errno = EBADF;
533         rait_debug(stderr, _("rait_lseek:returning %d: %s\n"),
534                             -1,
535                             strerror(errno));
536         return (off_t)-1;
537     }
538
539     if ((pr->nfds > 1) && ((pos % (off_t)(pr->nfds-1)) != (off_t)0)) {
540         errno = EDOM;
541         total = (off_t)-1;
542     } else {
543         total = (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))) {
547                 total = res;
548                 break;
549             }
550             total += res;
551         }
552     }
553     rait_debug(stderr, _("rait_lseek:returning %ld%s%s\n"),
554                         total,
555                         (total < 0) ? ": " : "",
556                         (total < 0) ? strerror(errno) : "");
557     return total;
558 }
559
560 /*\f*/
561
562 /*
563 ** if we only have one stream, just do a write,
564 ** otherwise compute an xor sum, and do several
565 ** writes...
566 */
567 ssize_t
568 rait_write(
569     int         fd,
570     const void *bufptr,
571     size_t      len)
572 {
573     const char *buf = bufptr;
574     int i;      /* drive number */
575     size_t j;   /* byte offset */
576     RAIT *pr;   /* RAIT structure for this RAIT */
577     ssize_t res;
578     ssize_t total = 0;
579     int data_fds;       /* number of data stream file descriptors */
580
581     rait_debug(stderr, _("rait_write(%d,%lx,%d)\n"),fd,(unsigned long)buf,len);
582
583     if ((fd < 0) || ((size_t)fd >= rait_table_count)) {
584         errno = EBADF;
585         rait_debug(stderr, _("rait_write:returning %d: %s\n"),
586                             -1,
587                             strerror(errno));
588         return -1;
589     }
590
591     pr = &rait_table[fd];
592     if (0 == pr->nopen) {
593         errno = EBADF;
594         rait_debug(stderr, _("rait_write:returning %d: %s\n"),
595                             -1,
596                             strerror(errno));
597         return -1;
598     }
599
600     /* need to be able to slice it up evenly... */
601     if (pr->nfds > 1) {
602         data_fds = pr->nfds - 1;
603         if (0 != len % data_fds) {
604             errno = EDOM;
605             rait_debug(stderr, _("rait_write:returning %d: %s\n"),
606                                 -1,
607                                 strerror(errno));
608             return -1;
609         }
610         /* each slice gets an even portion */
611         len = len / data_fds;
612
613         /* make sure we have enough buffer space */
614         if (len > (size_t)pr->xorbuflen) {
615             if (0 != pr->xorbuf) {
616                 amfree(pr->xorbuf);
617             }
618             pr->xorbuf = alloc(len);
619             pr->xorbuflen = len;
620         }
621
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];
627             }
628         }
629     } else {
630         data_fds = pr->nfds;
631     }
632
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"),
637                         pr->fds[i],
638                         (unsigned long)(buf + len*i),
639                         len,
640                         res,
641                         (res < 0) ? ": " : "",
642                         (res < 0) ? strerror(errno) : "");
643         if (res < 0) {
644             total = res;
645             break;
646         }
647         total += res;
648     }
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"),
653                     pr->fds[i],
654                     (unsigned long)pr->xorbuf,
655                     len,
656                     res,
657                     (res < 0) ? ": " : "",
658                     (res < 0) ? strerror(errno) : "");
659         if (res < 0) {
660             total = res;
661         }
662     }
663
664     rait_debug(stderr, _("rait_write:returning %d%s%s\n"),
665                         total,
666                         (total < 0) ? ": " : "",
667                         (total < 0) ? strerror(errno) : "");
668
669     return total;
670 }
671
672 /*\f*/
673
674 /*
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...
682 */
683 ssize_t
684 rait_read(
685     int         fd,
686     void *      bufptr,
687     size_t      len)
688 {
689     char *buf = bufptr;
690     int nerrors, neofs, errorblock;
691     ssize_t    total;
692     int i;
693     size_t j;
694     RAIT *pr;
695     int data_fds;
696     int save_errno = errno;
697     ssize_t maxreadres = 0;
698     int sum_mismatch = 0;
699
700     rait_debug(stderr, _("rait_read(%d,%lx,%d)\n"),fd,(unsigned long)buf,len);
701
702     if ((fd < 0) || ((size_t)fd >= rait_table_count)) {
703         errno = EBADF;
704         rait_debug(stderr, _("rait_read:returning %d: %s\n"),
705                             -1,
706                             strerror(errno));
707         return -1;
708     }
709
710     pr = &rait_table[fd];
711     if (0 == pr->nopen) {
712         errno = EBADF;
713         rait_debug(stderr, _("rait_read:returning %d: %s\n"),
714                             -1,
715                             strerror(errno));
716         return -1;
717     }
718
719     nerrors = 0;
720     neofs = 0;
721     errorblock = -1;
722     /* once again , we slice it evenly... */
723     if (pr->nfds > 1) {
724         data_fds = pr->nfds - 1;
725         if (0 != len % data_fds) {
726             errno = EDOM;
727             rait_debug(stderr, _("rait_read:returning %d: %s\n"),
728                                 -1,
729                                 strerror(errno));
730             return -1;
731         }
732         len = len / data_fds;
733     } else {
734         data_fds = 1;
735     }
736
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"),
742                     pr->fds[i],
743                     pr->readres[i],
744                     (pr->readres[i] < 0) ? ": " : "",
745                     (pr->readres[i] < 0) ? strerror(errno) : "");
746         if ( pr->readres[i] <= 0 ) {
747             if ( pr->readres[i] == 0 ) {
748                 neofs++;
749             } else {
750                 if (0 == nerrors) {
751                     save_errno = errno;
752                 }
753                 nerrors++;
754             }
755             errorblock = i;
756         } else if (pr->readres[i] > maxreadres) {
757             maxreadres = pr->readres[i];
758         }
759     }
760     if (pr->nfds > 1) {
761         /* make sure we have enough buffer space */
762         if (len > (size_t)pr->xorbuflen) {
763             if (0 != pr->xorbuf) {
764                 amfree(pr->xorbuf);
765             }
766             pr->xorbuf = alloc(len);
767             pr->xorbuflen = len;
768         }
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"),
771                     pr->fds[i],
772                     pr->readres[i],
773                     (pr->readres[i] < 0) ? ": " : "",
774                     (pr->readres[i] < 0) ? strerror(errno) : "");
775     }
776
777     /*
778      * Make sure all the reads were the same length
779      */
780     for (j = 0; j < (size_t)pr->nfds; j++) {
781         if (pr->readres[j] != maxreadres) {
782             nerrors++;
783             errorblock = (int)j;
784         }
785     }
786
787     /*
788      * If no errors, check that the xor sum matches
789      */
790     if ( nerrors == 0 && pr->nfds > 1  ) {
791        for(i = 0; i < (int)maxreadres; i++ ) {
792            int sum = 0;
793            for(j = 0; (j + 1) < (size_t)pr->nfds; j++) {
794                sum ^= (buf + len * j)[i];
795            }
796            if (sum != pr->xorbuf[i]) {
797               sum_mismatch = 1;
798            }
799        }
800     }
801
802     /*
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
807     */
808
809     if (neofs == pr->nfds) {
810         rait_debug(stderr, _("rait_read:returning 0\n"));
811         return 0;
812     }
813
814     if (sum_mismatch) {
815         errno = EDOM;
816         rait_debug(stderr, _("rait_read:returning %d: %s\n"),
817                             -1,
818                             _("XOR block mismatch"));
819         return -1;
820     }
821
822     if (nerrors > 1 || (pr->nfds <= 1 && nerrors > 0)) {
823         errno = save_errno;
824         rait_debug(stderr, _("rait_read:returning %d: %s\n"),
825                             -1,
826                             strerror(errno));
827         return -1;
828     }
829
830     /*
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?
833     */
834     if (nerrors == 1 && pr->nfds > 1 && errorblock != pr->nfds-1) {
835
836         rait_debug(stderr, _("rait_read: fixing data from fd %d\n"),
837                             pr->fds[errorblock]);
838
839         /* the reads were all *supposed* to be the same size, so... */
840         pr->readres[errorblock] = maxreadres;
841
842         /* fill it in first with the xor sum */
843         memcpy(buf + len * errorblock, pr->xorbuf, len);
844
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];
850                 }
851             }
852         }
853         /* there, now the block is back as if it never failed... */
854     }
855
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]);
861         }
862         total += pr->readres[i];
863     }
864
865     rait_debug(stderr, _("rait_read:returning %d%s%s\n"),
866                         total,
867                         (total < 0) ? ": " : "",
868                         (total < 0) ? strerror(errno) : "");
869
870     return total;
871 }
872
873 /*\f*/
874
875 int
876 rait_ioctl(
877     int         fd,
878     int         op,
879     void *      p)
880 {
881     int i, res = 0;
882     RAIT *pr;
883     int errors = 0;
884
885     rait_debug(stderr, _("rait_ioctl(%d,%d)\n"),fd,op);
886
887     if ((fd < 0) || ((size_t)fd >= rait_table_count)) {
888         errno = EBADF;
889         rait_debug(stderr, _("rait_ioctl:returning %d: %s\n"),
890                             -1,
891                             strerror(errno));
892         return -1;
893     }
894
895     pr = &rait_table[fd];
896     if (0 == pr->nopen) {
897         errno = EBADF;
898         rait_debug(stderr, _("rait_ioctl:returning %d: %s\n"),
899                             -1,
900                             strerror(errno));
901         return -1;
902     }
903
904     for( i = 0; i < pr->nfds ; i++ ) {
905         /*@ignore@*/
906         res = ioctl(pr->fds[i], op, p);
907         /*@end@*/
908         if ( res != 0 ) {
909             errors++;
910             if (errors > 1) {
911                 break;
912             }
913             res = 0;
914         }
915     }
916
917     rait_debug(stderr, _("rait_ioctl: returning %d%s%s\n"),
918                         res,
919                         (res < 0) ? ": " : "",
920                         (res < 0) ? strerror(errno) : "");
921
922     return res;
923 }
924
925 /*
926 ** access() all the devices, returning if any fail
927 */
928 int
929 rait_access(
930     char *      devname,
931     int         flags)
932 {
933     int res = 0;
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 */
938
939     /* copy and parse the dev string so we can scribble on it */
940     devname = stralloc(devname);
941     if (0 == devname) {
942         rait_debug(stderr, _("rait_access:returning %d: %s\n"),
943                             -1,
944                             _("out of stralloc memory"));
945         return -1;
946     }
947     if ( 0 != tapeio_init_devname(devname, &dev_left, &dev_right, &dev_next)) {
948         rait_debug(stderr, _("rait_access:returning %d: %s\n"),
949                             -1,
950                             strerror(errno));
951         return -1;
952     }
953
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 );
958         amfree(dev_real);
959         if (res < 0) {
960             break;
961         }
962     }
963     amfree(devname);
964
965     rait_debug(stderr, _("rait_access: returning %d%s%s\n"),
966                         res,
967                         (res < 0) ? ": " : "",
968                         (res < 0) ? strerror(errno) : "");
969
970     return res;
971 }
972
973 /*
974 ** stat all the devices, returning the last one unless one fails
975 */
976 int
977 rait_stat(
978     char *       devname,
979     struct stat *buf)
980 {
981     int res = 0;
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 */
986
987     /* copy and parse the dev string so we can scribble on it */
988     devname = stralloc(devname);
989     if (0 == devname) {
990         rait_debug(stderr, _("rait_access:returning %d: %s\n"),
991                             -1,
992                             _("out of stralloc memory"));
993         return -1;
994     }
995     if ( 0 != tapeio_init_devname(devname, &dev_left, &dev_right, &dev_next)) {
996         rait_debug(stderr, _("rait_access:returning %d: %s\n"),
997                             -1,
998                             strerror(errno));
999         return -1;
1000     }
1001
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") );
1006         amfree(dev_real);
1007         if (res != 0) {
1008             break;
1009         }
1010     }
1011     amfree(devname);
1012
1013     rait_debug(stderr, _("rait_access: returning %d%s%s\n"),
1014                         res,
1015                         (res < 0) ? ": " : "",
1016                         (res < 0) ? strerror(errno) : "");
1017
1018     return res;
1019 }
1020
1021 /*\f*/
1022
1023 int
1024 rait_copy(
1025     char *      f1,
1026     char *      f2,
1027     size_t      buflen)
1028 {
1029     int t1, t2;
1030     ssize_t len;
1031     ssize_t wres;
1032     char *buf;
1033     int save_errno;
1034
1035     t1 = rait_open(f1,O_RDONLY,0644);
1036     if (t1 < 0) {
1037         return t1;
1038     }
1039     t2 = rait_open(f2,O_CREAT|O_RDWR,0644);
1040     if (t2 < 0) {
1041         save_errno = errno;
1042         (void)rait_close(t1);
1043         errno = save_errno;
1044         return -1;
1045     }
1046     buf = alloc(buflen);
1047     do {
1048         len = rait_read(t1,buf,buflen);
1049         if (len > 0 ) {
1050             wres = rait_write(t2, buf, (size_t)len);
1051             if (wres < 0) {
1052                 len = -1;
1053                 break;
1054             }
1055         }
1056     } while( len > 0 );
1057     save_errno = errno;
1058     amfree(buf);
1059     (void)rait_close(t1);
1060     (void)rait_close(t2);
1061     errno = save_errno;
1062     return (len < 0) ? -1 : 0;
1063 }
1064
1065 /*\f*/
1066
1067 /*
1068 ** Amanda Tape API routines:
1069 */
1070
1071 static int
1072 rait_tapefd_ioctl(
1073     int         (*func0)(int),
1074     int         (*func1)(int, off_t),
1075     int         fd,
1076     off_t       count)
1077 {
1078     int i, j, res = 0;
1079     RAIT *pr;
1080     int errors = 0;
1081     pid_t kid;
1082     int status = 0;
1083
1084     rait_debug(stderr, _("rait_tapefd_ioctl(%d,%d)\n"),fd,count);
1085
1086     if ((fd < 0) || ((size_t)fd >= rait_table_count)) {
1087         errno = EBADF;
1088         rait_debug(stderr, _("rait_tapefd_ioctl:returning %d: %s\n"),
1089                             -1,
1090                             strerror(errno));
1091         return -1;
1092     }
1093
1094     pr = &rait_table[fd];
1095     if (0 == pr->nopen) {
1096         errno = EBADF;
1097         rait_debug(stderr, _("rait_tapefd_ioctl:returning %d: %s\n"),
1098                             -1,
1099                             strerror(errno));
1100         return -1;
1101     }
1102
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));
1106     }
1107
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]);
1115                 } else {
1116                     res = (*func1)(pr->fds[i], count);
1117                 }
1118                 rait_debug(stderr, _("in kid, func (%d) returned %d errno %s\n"),
1119                                 pr->fds[i], res, strerror(errno));
1120                 if (kid == 0)
1121                     exit(res);
1122             } else {
1123                 rait_debug(stderr, _("in parent, fork returned %d\n"), kid);
1124                 pr->readres[i] = (ssize_t)kid;
1125             }
1126         }
1127         else {
1128             if(func0 != NULL) {
1129                 j = (*func0)(pr->fds[i]);
1130             } else {
1131                 j = (*func1)(pr->fds[i], count);
1132             }
1133             if( j != 0) {
1134                 errors++;
1135             }
1136             pr->readres[i] = -1;
1137         }
1138     }
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);
1145                 if( res == 255 )
1146                     res = -1;
1147             }
1148             rait_debug(stderr, _("in parent, return code was %d\n"), res);
1149             if ( res != 0 ) {
1150                 errors++;
1151                 res = 0;
1152             }
1153         }
1154     }
1155     if (errors > 0) {
1156         res = -1;
1157     }
1158
1159     rait_debug(stderr, _("rait_tapefd_ioctl: returning %d%s%s\n"),
1160                         res,
1161                         (res < 0) ? ": " : "",
1162                         (res < 0) ? strerror(errno) : "");
1163
1164     return res;
1165 }
1166
1167 int
1168 rait_tapefd_fsf(
1169     int         fd,
1170     off_t       count)
1171 {
1172     return rait_tapefd_ioctl(NULL, tapefd_fsf, fd, count);
1173 }
1174
1175 int
1176 rait_tapefd_rewind(
1177     int         fd)
1178 {
1179     return rait_tapefd_ioctl(tapefd_rewind, NULL, fd, (off_t)-1);
1180 }
1181
1182 int
1183 rait_tapefd_unload(
1184     int         fd)
1185 {
1186     return rait_tapefd_ioctl(tapefd_unload, NULL, fd, (off_t)-1);
1187 }
1188
1189 int
1190 rait_tapefd_weof(
1191     int         fd,
1192     off_t       count)
1193 {
1194     return rait_tapefd_ioctl(NULL, tapefd_weof, fd, count);
1195 }
1196
1197 int
1198 rait_tape_open(
1199     char *      name,
1200     int         flags,
1201     mode_t      mask)
1202 {
1203     return rait_open(name, flags, mask);
1204 }
1205
1206 int
1207 rait_tapefd_status(
1208     int                  fd,
1209     struct am_mt_status *stat)
1210 {
1211     int i;
1212     RAIT *pr;
1213     int res = 0;
1214     int errors = 0;
1215
1216     rait_debug(stderr, _("rait_tapefd_status(%d)\n"),fd);
1217
1218     if ((fd < 0) || ((size_t)fd >= rait_table_count)) {
1219         errno = EBADF;
1220         rait_debug(stderr, _("rait_tapefd_status:returning %d: %s\n"),
1221                             -1,
1222                             strerror(errno));
1223         return -1;
1224     }
1225
1226     pr = &rait_table[fd];
1227     if (0 == pr->nopen) {
1228         errno = EBADF;
1229         rait_debug(stderr, _("rait_tapefd_status:returning %d: %s\n"),
1230                             -1,
1231                             strerror(errno));
1232         return -1;
1233     }
1234
1235     for( i = 0; i < pr->nfds ; i++ ) {
1236         res = tapefd_status(pr->fds[i], stat);
1237         if(res != 0) {
1238             errors++;
1239         }
1240     }
1241     if (errors > 0) {
1242         res = -1;
1243     }
1244     return res;
1245 }
1246
1247 void
1248 rait_tapefd_resetofs(
1249     int         fd)
1250 {
1251     (void)rait_lseek(fd, (off_t)0, SEEK_SET);
1252 }
1253
1254 int
1255 rait_tapefd_can_fork(
1256     int         fd)
1257 {
1258     (void)fd;   /* Quiet unused parameter warning */
1259
1260     return 0;
1261 }
1262