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