home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sbin / restore / tape.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-11-11  |  29.2 KB  |  1,344 lines

  1. /*
  2.  * Copyright (c) 1983 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char sccsid[] = "@(#)tape.c    5.35 (Berkeley) 11/11/92";
  36. #endif /* not lint */
  37.  
  38. #include <sys/param.h>
  39. #include <sys/file.h>
  40. #include <sys/ioctl.h>
  41. #include <sys/mtio.h>
  42. #include <sys/stat.h>
  43.  
  44. #include <ufs/ufs/dinode.h>
  45. #include <protocols/dumprestore.h>
  46.  
  47. #include <errno.h>
  48. #include <setjmp.h>
  49. #include <stdio.h>
  50. #include <stdlib.h>
  51. #include <string.h>
  52. #include <unistd.h>
  53.  
  54. #include "restore.h"
  55. #include "extern.h"
  56. #include "pathnames.h"
  57.  
  58. static long    fssize = MAXBSIZE;
  59. static int    mt = -1;
  60. static int    pipein = 0;
  61. static char    magtape[BUFSIZ];
  62. static int    blkcnt;
  63. static int    numtrec;
  64. static char    *tapebuf;
  65. static union    u_spcl endoftapemark;
  66. static long    blksread;        /* blocks read since last header */
  67. static long    tpblksread = 0;        /* TP_BSIZE blocks read */
  68. static long    tapesread;
  69. static jmp_buf    restart;
  70. static int    gettingfile = 0;    /* restart has a valid frame */
  71. static char    *host = NULL;
  72.  
  73. static int    ofile;
  74. static char    *map;
  75. static char    lnkbuf[MAXPATHLEN + 1];
  76. static int    pathlen;
  77.  
  78. int        oldinofmt;    /* old inode format conversion required */
  79. int        Bcvt;        /* Swap Bytes (for CCI or sun) */
  80. static int    Qcvt;        /* Swap quads (for sun) */
  81.  
  82. #define    FLUSHTAPEBUF()    blkcnt = ntrec + 1
  83.  
  84. static void     accthdr __P((struct s_spcl *));
  85. static int     checksum __P((int *));
  86. static void     findinode __P((struct s_spcl *));
  87. static void     findtapeblksize __P((void));
  88. static int     gethead __P((struct s_spcl *));
  89. static void     readtape __P((char *));
  90. static void     setdumpnum __P((void));
  91. static u_long     swabl __P((u_long));
  92. static u_char    *swablong __P((u_char *, int));
  93. static u_char    *swabshort __P((u_char *, int));
  94. static void     terminateinput __P((void));
  95. static void     xtrfile __P((char *, long));
  96. static void     xtrlnkfile __P((char *, long));
  97. static void     xtrlnkskip __P((char *, long));
  98. static void     xtrmap __P((char *, long));
  99. static void     xtrmapskip __P((char *, long));
  100. static void     xtrskip __P((char *, long));
  101.  
  102. /*
  103.  * Set up an input source
  104.  */
  105. void
  106. setinput(source)
  107.     char *source;
  108. {
  109.     FLUSHTAPEBUF();
  110.     if (bflag)
  111.         newtapebuf(ntrec);
  112.     else
  113.         newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC);
  114.     terminal = stdin;
  115.  
  116. #ifdef RRESTORE
  117.     if (index(source, ':')) {
  118.         host = source;
  119.         source = index(host, ':');
  120.         *source++ = '\0';
  121.         if (rmthost(host) == 0)
  122.             done(1);
  123.     } else
  124. #endif
  125.     if (strcmp(source, "-") == 0) {
  126.         /*
  127.          * Since input is coming from a pipe we must establish
  128.          * our own connection to the terminal.
  129.          */
  130.         terminal = fopen(_PATH_TTY, "r");
  131.         if (terminal == NULL) {
  132.             (void)fprintf(stderr, "cannot open %s: %s\n",
  133.                 _PATH_TTY, strerror(errno));
  134.             terminal = fopen(_PATH_DEVNULL, "r");
  135.             if (terminal == NULL) {
  136.                 (void)fprintf(stderr, "cannot open %s: %s\n",
  137.                     _PATH_DEVNULL, strerror(errno));
  138.                 done(1);
  139.             }
  140.         }
  141.         pipein++;
  142.     }
  143.     setuid(getuid());    /* no longer need or want root privileges */
  144.     (void) strcpy(magtape, source);
  145. }
  146.  
  147. void
  148. newtapebuf(size)
  149.     long size;
  150. {
  151.     static tapebufsize = -1;
  152.  
  153.     ntrec = size;
  154.     if (size <= tapebufsize)
  155.         return;
  156.     if (tapebuf != NULL)
  157.         free(tapebuf);
  158.     tapebuf = malloc(size * TP_BSIZE);
  159.     if (tapebuf == NULL) {
  160.         fprintf(stderr, "Cannot allocate space for tape buffer\n");
  161.         done(1);
  162.     }
  163.     tapebufsize = size;
  164. }
  165.  
  166. /*
  167.  * Verify that the tape drive can be accessed and
  168.  * that it actually is a dump tape.
  169.  */
  170. void
  171. setup()
  172. {
  173.     int i, j, *ip;
  174.     struct stat stbuf;
  175.  
  176.     vprintf(stdout, "Verify tape and initialize maps\n");
  177. #ifdef RRESTORE
  178.     if (host)
  179.         mt = rmtopen(magtape, O_RDONLY, 0);
  180.     else
  181. #endif
  182.     if (pipein)
  183.         mt = 0;
  184.     else
  185.         mt = open(magtape, O_RDONLY, 0);
  186.     if (mt < 0) {
  187.         fprintf(stderr, "%s: %s\n", magtape, strerror(errno));
  188.         done(1);
  189.     }
  190.     volno = 1;
  191.     setdumpnum();
  192.     FLUSHTAPEBUF();
  193.     if (!pipein && !bflag)
  194.         findtapeblksize();
  195.     if (gethead(&spcl) == FAIL) {
  196.         blkcnt--; /* push back this block */
  197.         blksread--;
  198.         tpblksread--;
  199.         cvtflag++;
  200.         if (gethead(&spcl) == FAIL) {
  201.             fprintf(stderr, "Tape is not a dump tape\n");
  202.             done(1);
  203.         }
  204.         fprintf(stderr, "Converting to new file system format.\n");
  205.     }
  206.     if (pipein) {
  207.         endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC;
  208.         endoftapemark.s_spcl.c_type = TS_END;
  209.         ip = (int *)&endoftapemark;
  210.         j = sizeof(union u_spcl) / sizeof(int);
  211.         i = 0;
  212.         do
  213.             i += *ip++;
  214.         while (--j);
  215.         endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
  216.     }
  217.     if (vflag || command == 't')
  218.         printdumpinfo();
  219.     dumptime = spcl.c_ddate;
  220.     dumpdate = spcl.c_date;
  221.     if (stat(".", &stbuf) < 0) {
  222.         fprintf(stderr, "cannot stat .: %s\n", strerror(errno));
  223.         done(1);
  224.     }
  225.     if (stbuf.st_blksize > 0 && stbuf.st_blksize <= MAXBSIZE)
  226.         fssize = stbuf.st_blksize;
  227.     if (((fssize - 1) & fssize) != 0) {
  228.         fprintf(stderr, "bad block size %d\n", fssize);
  229.         done(1);
  230.     }
  231.     if (spcl.c_volume != 1) {
  232.         fprintf(stderr, "Tape is not volume 1 of the dump\n");
  233.         done(1);
  234.     }
  235.     if (gethead(&spcl) == FAIL) {
  236.         dprintf(stdout, "header read failed at %d blocks\n", blksread);
  237.         panic("no header after volume mark!\n");
  238.     }
  239.     findinode(&spcl);
  240.     if (spcl.c_type != TS_CLRI) {
  241.         fprintf(stderr, "Cannot find file removal list\n");
  242.         done(1);
  243.     }
  244.     maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
  245.     dprintf(stdout, "maxino = %d\n", maxino);
  246.     map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
  247.     if (map == NULL)
  248.         panic("no memory for file removal list\n");
  249.     clrimap = map;
  250.     curfile.action = USING;
  251.     getfile(xtrmap, xtrmapskip);
  252.     if (spcl.c_type != TS_BITS) {
  253.         fprintf(stderr, "Cannot find file dump list\n");
  254.         done(1);
  255.     }
  256.     map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
  257.     if (map == (char *)NULL)
  258.         panic("no memory for file dump list\n");
  259.     dumpmap = map;
  260.     curfile.action = USING;
  261.     getfile(xtrmap, xtrmapskip);
  262. }
  263.  
  264. /*
  265.  * Prompt user to load a new dump volume.
  266.  * "Nextvol" is the next suggested volume to use.
  267.  * This suggested volume is enforced when doing full
  268.  * or incremental restores, but can be overrridden by
  269.  * the user when only extracting a subset of the files.
  270.  */
  271. void
  272. getvol(nextvol)
  273.     long nextvol;
  274. {
  275.     long newvol, savecnt, wantnext, i;
  276.     union u_spcl tmpspcl;
  277. #    define tmpbuf tmpspcl.s_spcl
  278.     char buf[TP_BSIZE];
  279.  
  280.     if (nextvol == 1) {
  281.         tapesread = 0;
  282.         gettingfile = 0;
  283.     }
  284.     if (pipein) {
  285.         if (nextvol != 1)
  286.             panic("Changing volumes on pipe input?\n");
  287.         if (volno == 1)
  288.             return;
  289.         goto gethdr;
  290.     }
  291.     savecnt = blksread;
  292. again:
  293.     if (pipein)
  294.         done(1); /* pipes do not get a second chance */
  295.     if (command == 'R' || command == 'r' || curfile.action != SKIP) {
  296.         newvol = nextvol;
  297.         wantnext = 1;
  298.     } else { 
  299.         newvol = 0;
  300.         wantnext = 0;
  301.     }
  302.     while (newvol <= 0) {
  303.         if (tapesread == 0) {
  304.             fprintf(stderr, "%s%s%s%s%s",
  305.                 "You have not read any tapes yet.\n",
  306.                 "Unless you know which volume your",
  307.                 " file(s) are on you should start\n",
  308.                 "with the last volume and work",
  309.                 " towards towards the first.\n");
  310.         } else {
  311.             fprintf(stderr, "You have read volumes");
  312.             strcpy(buf, ": ");
  313.             for (i = 1; i < 32; i++)
  314.                 if (tapesread & (1 << i)) {
  315.                     fprintf(stderr, "%s%d", buf, i);
  316.                     strcpy(buf, ", ");
  317.                 }
  318.             fprintf(stderr, "\n");
  319.         }
  320.         do    {
  321.             fprintf(stderr, "Specify next volume #: ");
  322.             (void) fflush(stderr);
  323.             (void) fgets(buf, BUFSIZ, terminal);
  324.         } while (!feof(terminal) && buf[0] == '\n');
  325.         if (feof(terminal))
  326.             done(1);
  327.         newvol = atoi(buf);
  328.         if (newvol <= 0) {
  329.             fprintf(stderr,
  330.                 "Volume numbers are positive numerics\n");
  331.         }
  332.     }
  333.     if (newvol == volno) {
  334.         tapesread |= 1 << volno;
  335.         return;
  336.     }
  337.     closemt();
  338.     fprintf(stderr, "Mount tape volume %d\n", newvol);
  339.     fprintf(stderr, "Enter ``none'' if there are no more tapes\n");
  340.     fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape);
  341.     (void) fflush(stderr);
  342.     (void) fgets(buf, BUFSIZ, terminal);
  343.     if (feof(terminal))
  344.         done(1);
  345.     if (!strcmp(buf, "none\n")) {
  346.         terminateinput();
  347.         return;
  348.     }
  349.     if (buf[0] != '\n') {
  350.         (void) strcpy(magtape, buf);
  351.         magtape[strlen(magtape) - 1] = '\0';
  352.     }
  353. #ifdef RRESTORE
  354.     if (host)
  355.         mt = rmtopen(magtape, 0);
  356.     else
  357. #endif
  358.         mt = open(magtape, O_RDONLY, 0);
  359.  
  360.     if (mt == -1) {
  361.         fprintf(stderr, "Cannot open %s\n", magtape);
  362.         volno = -1;
  363.         goto again;
  364.     }
  365. gethdr:
  366.     volno = newvol;
  367.     setdumpnum();
  368.     FLUSHTAPEBUF();
  369.     if (gethead(&tmpbuf) == FAIL) {
  370.         dprintf(stdout, "header read failed at %d blocks\n", blksread);
  371.         fprintf(stderr, "tape is not dump tape\n");
  372.         volno = 0;
  373.         goto again;
  374.     }
  375.     if (spcl.c_volume != volno) {
  376.         fprintf(stderr, "Wrong volume (%d)\n", tmpbuf.c_volume);
  377.         volno = 0;
  378.         goto again;
  379.     }
  380.     if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) {
  381.         fprintf(stderr, "Wrong dump date\n\tgot: %s",
  382.             ctime(&tmpbuf.c_date));
  383.         fprintf(stderr, "\twanted: %s", ctime(&dumpdate));
  384.         volno = 0;
  385.         goto again;
  386.     }
  387.     tapesread |= 1 << volno;
  388.     blksread = savecnt;
  389.      /*
  390.       * If continuing from the previous volume, skip over any
  391.       * blocks read already at the end of the previous volume.
  392.       *
  393.       * If coming to this volume at random, skip to the beginning
  394.       * of the next record.
  395.       */
  396.     dprintf(stdout, "read %ld recs, tape starts with %ld\n", 
  397.         tpblksread, tmpbuf.c_firstrec);
  398.      if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) {
  399.          if (!wantnext) {
  400.              tpblksread = tmpbuf.c_firstrec;
  401.              for (i = tmpbuf.c_count; i > 0; i--)
  402.                  readtape(buf);
  403.          } else if (tmpbuf.c_firstrec > 0 &&
  404.                tmpbuf.c_firstrec < tpblksread - 1) {
  405.             /*
  406.              * -1 since we've read the volume header
  407.              */
  408.              i = tpblksread - tmpbuf.c_firstrec - 1;
  409.             dprintf(stderr, "Skipping %d duplicate record%s.\n",
  410.                 i, i > 1 ? "s" : "");
  411.              while (--i >= 0)
  412.                  readtape(buf);
  413.          }
  414.      }
  415.     if (curfile.action == USING) {
  416.         if (volno == 1)
  417.             panic("active file into volume 1\n");
  418.         return;
  419.     }
  420.     /*
  421.      * Skip up to the beginning of the next record
  422.      */
  423.     if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER))
  424.         for (i = tmpbuf.c_count; i > 0; i--)
  425.             readtape(buf);
  426.     (void) gethead(&spcl);
  427.     findinode(&spcl);
  428.     if (gettingfile) {
  429.         gettingfile = 0;
  430.         longjmp(restart, 1);
  431.     }
  432. }
  433.  
  434. /*
  435.  * Handle unexpected EOF.
  436.  */
  437. static void
  438. terminateinput()
  439. {
  440.  
  441.     if (gettingfile && curfile.action == USING) {
  442.         printf("Warning: %s %s\n",
  443.             "End-of-input encountered while extracting", curfile.name);
  444.     }
  445.     curfile.name = "<name unknown>";
  446.     curfile.action = UNKNOWN;
  447.     curfile.dip = NULL;
  448.     curfile.ino = maxino;
  449.     if (gettingfile) {
  450.         gettingfile = 0;
  451.         longjmp(restart, 1);
  452.     }
  453. }
  454.  
  455. /*
  456.  * handle multiple dumps per tape by skipping forward to the
  457.  * appropriate one.
  458.  */
  459. static void
  460. setdumpnum()
  461. {
  462.     struct mtop tcom;
  463.  
  464.     if (dumpnum == 1 || volno != 1)
  465.         return;
  466.     if (pipein) {
  467.         fprintf(stderr, "Cannot have multiple dumps on pipe input\n");
  468.         done(1);
  469.     }
  470.     tcom.mt_op = MTFSF;
  471.     tcom.mt_count = dumpnum - 1;
  472. #ifdef RRESTORE
  473.     if (host)
  474.         rmtioctl(MTFSF, dumpnum - 1);
  475.     else 
  476. #endif
  477.         if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0)
  478.             fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno));
  479. }
  480.  
  481. void
  482. printdumpinfo()
  483. {
  484.     fprintf(stdout, "Dump   date: %s", ctime(&spcl.c_date));
  485.     fprintf(stdout, "Dumped from: %s",
  486.         (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&spcl.c_ddate));
  487.     if (spcl.c_host[0] == '\0')
  488.         return;
  489.     fprintf(stderr, "Level %d dump of %s on %s:%s\n",
  490.         spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev);
  491.     fprintf(stderr, "Label: %s\n", spcl.c_label);
  492. }
  493.  
  494. int
  495. extractfile(name)
  496.     char *name;
  497. {
  498.     int mode;
  499.     struct timeval timep[2];
  500.     struct entry *ep;
  501.  
  502.     curfile.name = name;
  503.     curfile.action = USING;
  504.     timep[0].tv_sec = curfile.dip->di_atime.ts_sec;
  505.     timep[0].tv_usec = curfile.dip->di_atime.ts_nsec / 1000;
  506.     timep[1].tv_sec = curfile.dip->di_mtime.ts_sec;
  507.     timep[1].tv_usec = curfile.dip->di_mtime.ts_nsec / 1000;
  508.     mode = curfile.dip->di_mode;
  509.     switch (mode & IFMT) {
  510.  
  511.     default:
  512.         fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode);
  513.         skipfile();
  514.         return (FAIL);
  515.  
  516.     case IFSOCK:
  517.         vprintf(stdout, "skipped socket %s\n", name);
  518.         skipfile();
  519.         return (GOOD);
  520.  
  521.     case IFDIR:
  522.         if (mflag) {
  523.             ep = lookupname(name);
  524.             if (ep == NULL || ep->e_flags & EXTRACT)
  525.                 panic("unextracted directory %s\n", name);
  526.             skipfile();
  527.             return (GOOD);
  528.         }
  529.         vprintf(stdout, "extract file %s\n", name);
  530.         return (genliteraldir(name, curfile.ino));
  531.  
  532.     case IFLNK:
  533.         lnkbuf[0] = '\0';
  534.         pathlen = 0;
  535.         getfile(xtrlnkfile, xtrlnkskip);
  536.         if (pathlen == 0) {
  537.             vprintf(stdout,
  538.                 "%s: zero length symbolic link (ignored)\n", name);
  539.             return (GOOD);
  540.         }
  541.         return (linkit(lnkbuf, name, SYMLINK));
  542.  
  543.     case IFCHR:
  544.     case IFBLK:
  545.         vprintf(stdout, "extract special file %s\n", name);
  546.         if (Nflag) {
  547.             skipfile();
  548.             return (GOOD);
  549.         }
  550.         if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) {
  551.             fprintf(stderr, "%s: cannot create special file: %s\n",
  552.                 name, strerror(errno));
  553.             skipfile();
  554.             return (FAIL);
  555.         }
  556.         (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
  557.         (void) chmod(name, mode);
  558.         skipfile();
  559.         utimes(name, timep);
  560.         return (GOOD);
  561.  
  562.     case IFREG:
  563.         vprintf(stdout, "extract file %s\n", name);
  564.         if (Nflag) {
  565.             skipfile();
  566.             return (GOOD);
  567.         }
  568.         if ((ofile = creat(name, 0666)) < 0) {
  569.             fprintf(stderr, "%s: cannot create file: %s\n",
  570.                 name, strerror(errno));
  571.             skipfile();
  572.             return (FAIL);
  573.         }
  574.         (void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid);
  575.         (void) fchmod(ofile, mode);
  576.         getfile(xtrfile, xtrskip);
  577.         (void) close(ofile);
  578.         utimes(name, timep);
  579.         return (GOOD);
  580.     }
  581.     /* NOTREACHED */
  582. }
  583.  
  584. /*
  585.  * skip over bit maps on the tape
  586.  */
  587. void
  588. skipmaps()
  589. {
  590.  
  591.     while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI)
  592.         skipfile();
  593. }
  594.  
  595. /*
  596.  * skip over a file on the tape
  597.  */
  598. void
  599. skipfile()
  600. {
  601.  
  602.     curfile.action = SKIP;
  603.     getfile(xtrnull, xtrnull);
  604. }
  605.  
  606. /*
  607.  * Extract a file from the tape.
  608.  * When an allocated block is found it is passed to the fill function;
  609.  * when an unallocated block (hole) is found, a zeroed buffer is passed
  610.  * to the skip function.
  611.  */
  612. void
  613. getfile(fill, skip)
  614.     void    (*fill) __P((char *, long));
  615.     void    (*skip) __P((char *, long));
  616. {
  617.     register int i;
  618.     int curblk = 0;
  619.     long size = spcl.c_dinode.di_size;
  620.     static char clearedbuf[MAXBSIZE];
  621.     char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
  622.     char junk[TP_BSIZE];
  623.  
  624.     if (spcl.c_type == TS_END)
  625.         panic("ran off end of tape\n");
  626.     if (spcl.c_magic != NFS_MAGIC)
  627.         panic("not at beginning of a file\n");
  628.     if (!gettingfile && setjmp(restart) != 0)
  629.         return;
  630.     gettingfile++;
  631. loop:
  632.     for (i = 0; i < spcl.c_count; i++) {
  633.         if (spcl.c_addr[i]) {
  634.             readtape(&buf[curblk++][0]);
  635.             if (curblk == fssize / TP_BSIZE) {
  636.                 (*fill)((char *)buf, size > TP_BSIZE ?
  637.                      (long) (fssize) :
  638.                      (curblk - 1) * TP_BSIZE + size);
  639.                 curblk = 0;
  640.             }
  641.         } else {
  642.             if (curblk > 0) {
  643.                 (*fill)((char *)buf, size > TP_BSIZE ?
  644.                      (long) (curblk * TP_BSIZE) :
  645.                      (curblk - 1) * TP_BSIZE + size);
  646.                 curblk = 0;
  647.             }
  648.             (*skip)(clearedbuf, size > TP_BSIZE ?
  649.                 (long) TP_BSIZE : size);
  650.         }
  651.         if ((size -= TP_BSIZE) <= 0) {
  652.             for (i++; i < spcl.c_count; i++)
  653.                 if (spcl.c_addr[i])
  654.                     readtape(junk);
  655.             break;
  656.         }
  657.     }
  658.     if (gethead(&spcl) == GOOD && size > 0) {
  659.         if (spcl.c_type == TS_ADDR)
  660.             goto loop;
  661.         dprintf(stdout,
  662.             "Missing address (header) block for %s at %d blocks\n",
  663.             curfile.name, blksread);
  664.     }
  665.     if (curblk > 0)
  666.         (*fill)((char *)buf, (curblk * TP_BSIZE) + size);
  667.     findinode(&spcl);
  668.     gettingfile = 0;
  669. }
  670.  
  671. /*
  672.  * Write out the next block of a file.
  673.  */
  674. static void
  675. xtrfile(buf, size)
  676.     char    *buf;
  677.     long    size;
  678. {
  679.  
  680.     if (Nflag)
  681.         return;
  682.     if (write(ofile, buf, (int) size) == -1) {
  683.         fprintf(stderr,
  684.             "write error extracting inode %d, name %s\nwrite: %s\n",
  685.             curfile.ino, curfile.name, strerror(errno));
  686.         done(1);
  687.     }
  688. }
  689.  
  690. /*
  691.  * Skip over a hole in a file.
  692.  */
  693. /* ARGSUSED */
  694. static void
  695. xtrskip(buf, size)
  696.     char *buf;
  697.     long size;
  698. {
  699.  
  700.     if (lseek(ofile, size, SEEK_CUR) == (long)-1) {
  701.         fprintf(stderr,
  702.             "seek error extracting inode %d, name %s\nlseek: %s\n",
  703.             curfile.ino, curfile.name, strerror(errno));
  704.         done(1);
  705.     }
  706. }
  707.  
  708. /*
  709.  * Collect the next block of a symbolic link.
  710.  */
  711. static void
  712. xtrlnkfile(buf, size)
  713.     char    *buf;
  714.     long    size;
  715. {
  716.  
  717.     pathlen += size;
  718.     if (pathlen > MAXPATHLEN) {
  719.         fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n",
  720.             curfile.name, lnkbuf, buf, pathlen);
  721.         done(1);
  722.     }
  723.     (void) strcat(lnkbuf, buf);
  724. }
  725.  
  726. /*
  727.  * Skip over a hole in a symbolic link (should never happen).
  728.  */
  729. /* ARGSUSED */
  730. static void
  731. xtrlnkskip(buf, size)
  732.     char *buf;
  733.     long size;
  734. {
  735.  
  736.     fprintf(stderr, "unallocated block in symbolic link %s\n",
  737.         curfile.name);
  738.     done(1);
  739. }
  740.  
  741. /*
  742.  * Collect the next block of a bit map.
  743.  */
  744. static void
  745. xtrmap(buf, size)
  746.     char    *buf;
  747.     long    size;
  748. {
  749.  
  750.     bcopy(buf, map, size);
  751.     map += size;
  752. }
  753.  
  754. /*
  755.  * Skip over a hole in a bit map (should never happen).
  756.  */
  757. /* ARGSUSED */
  758. static void
  759. xtrmapskip(buf, size)
  760.     char *buf;
  761.     long size;
  762. {
  763.  
  764.     panic("hole in map\n");
  765.     map += size;
  766. }
  767.  
  768. /*
  769.  * Noop, when an extraction function is not needed.
  770.  */
  771. /* ARGSUSED */
  772. void
  773. xtrnull(buf, size)
  774.     char *buf;
  775.     long size;
  776. {
  777.  
  778.     return;
  779. }
  780.  
  781. /*
  782.  * Read TP_BSIZE blocks from the input.
  783.  * Handle read errors, and end of media.
  784.  */
  785. static void
  786. readtape(buf)
  787.     char *buf;
  788. {
  789.     long rd, newvol, i;
  790.     int cnt, seek_failed;
  791.  
  792.     if (blkcnt < numtrec) {
  793.         bcopy(&tapebuf[(blkcnt++ * TP_BSIZE)], buf, (long)TP_BSIZE);
  794.         blksread++;
  795.         tpblksread++;
  796.         return;
  797.     }
  798.     for (i = 0; i < ntrec; i++)
  799.         ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
  800.     if (numtrec == 0)
  801.         numtrec = ntrec;
  802.     cnt = ntrec * TP_BSIZE;
  803.     rd = 0;
  804. getmore:
  805. #ifdef RRESTORE
  806.     if (host)
  807.         i = rmtread(&tapebuf[rd], cnt);
  808.     else
  809. #endif
  810.         i = read(mt, &tapebuf[rd], cnt);
  811.     /*
  812.      * Check for mid-tape short read error.
  813.      * If found, skip rest of buffer and start with the next.
  814.      */
  815.     if (!pipein && numtrec < ntrec && i > 0) {
  816.         dprintf(stdout, "mid-media short read error.\n");
  817.         numtrec = ntrec;
  818.     }
  819.     /*
  820.      * Handle partial block read.
  821.      */
  822.     if (pipein && i == 0 && rd > 0)
  823.         i = rd;
  824.     else if (i > 0 && i != ntrec * TP_BSIZE) {
  825.         if (pipein) {
  826.             rd += i;
  827.             cnt -= i;
  828.             if (cnt > 0)
  829.                 goto getmore;
  830.             i = rd;
  831.         } else {
  832.             /*
  833.              * Short read. Process the blocks read.
  834.              */
  835.             if (i % TP_BSIZE != 0)
  836.                 vprintf(stdout,
  837.                     "partial block read: %d should be %d\n",
  838.                     i, ntrec * TP_BSIZE);
  839.             numtrec = i / TP_BSIZE;
  840.         }
  841.     }
  842.     /*
  843.      * Handle read error.
  844.      */
  845.     if (i < 0) {
  846.         fprintf(stderr, "Tape read error while ");
  847.         switch (curfile.action) {
  848.         default:
  849.             fprintf(stderr, "trying to set up tape\n");
  850.             break;
  851.         case UNKNOWN:
  852.             fprintf(stderr, "trying to resynchronize\n");
  853.             break;
  854.         case USING:
  855.             fprintf(stderr, "restoring %s\n", curfile.name);
  856.             break;
  857.         case SKIP:
  858.             fprintf(stderr, "skipping over inode %d\n",
  859.                 curfile.ino);
  860.             break;
  861.         }
  862.         if (!yflag && !reply("continue"))
  863.             done(1);
  864.         i = ntrec * TP_BSIZE;
  865.         bzero(tapebuf, i);
  866. #ifdef RRESTORE
  867.         if (host)
  868.             seek_failed = (rmtseek(i, 1) < 0);
  869.         else
  870. #endif
  871.             seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1);
  872.  
  873.         if (seek_failed) {
  874.             fprintf(stderr,
  875.                 "continuation failed: %s\n", strerror(errno));
  876.             done(1);
  877.         }
  878.     }
  879.     /*
  880.      * Handle end of tape.
  881.      */
  882.     if (i == 0) {
  883.         vprintf(stdout, "End-of-tape encountered\n");
  884.         if (!pipein) {
  885.             newvol = volno + 1;
  886.             volno = 0;
  887.             numtrec = 0;
  888.             getvol(newvol);
  889.             readtape(buf);
  890.             return;
  891.         }
  892.         if (rd % TP_BSIZE != 0)
  893.             panic("partial block read: %d should be %d\n",
  894.                 rd, ntrec * TP_BSIZE);
  895.         terminateinput();
  896.         bcopy((char *)&endoftapemark, &tapebuf[rd], (long)TP_BSIZE);
  897.     }
  898.     blkcnt = 0;
  899.     bcopy(&tapebuf[(blkcnt++ * TP_BSIZE)], buf, (long)TP_BSIZE);
  900.     blksread++;
  901.     tpblksread++;
  902. }
  903.  
  904. static void
  905. findtapeblksize()
  906. {
  907.     register long i;
  908.  
  909.     for (i = 0; i < ntrec; i++)
  910.         ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
  911.     blkcnt = 0;
  912. #ifdef RRESTORE
  913.     if (host)
  914.         i = rmtread(tapebuf, ntrec * TP_BSIZE);
  915.     else
  916. #endif
  917.         i = read(mt, tapebuf, ntrec * TP_BSIZE);
  918.  
  919.     if (i <= 0) {
  920.         fprintf(stderr, "tape read error: %s\n", strerror(errno));
  921.         done(1);
  922.     }
  923.     if (i % TP_BSIZE != 0) {
  924.         fprintf(stderr, "Tape block size (%d) %s (%d)\n",
  925.             i, "is not a multiple of dump block size", TP_BSIZE);
  926.         done(1);
  927.     }
  928.     ntrec = i / TP_BSIZE;
  929.     numtrec = ntrec;
  930.     vprintf(stdout, "Tape block size is %d\n", ntrec);
  931. }
  932.  
  933. void
  934. closemt()
  935. {
  936.  
  937.     if (mt < 0)
  938.         return;
  939. #ifdef RRESTORE
  940.     if (host)
  941.         rmtclose();
  942.     else
  943. #endif
  944.         (void) close(mt);
  945. }
  946.  
  947. /*
  948.  * Read the next block from the tape.
  949.  * Check to see if it is one of several vintage headers.
  950.  * If it is an old style header, convert it to a new style header.
  951.  * If it is not any valid header, return an error.
  952.  */
  953. static int
  954. gethead(buf)
  955.     struct s_spcl *buf;
  956. {
  957.     long i;
  958.     union {
  959.         quad_t    qval;
  960.         long    val[2];
  961.     } qcvt;
  962.     union u_ospcl {
  963.         char dummy[TP_BSIZE];
  964.         struct    s_ospcl {
  965.             long    c_type;
  966.             long    c_date;
  967.             long    c_ddate;
  968.             long    c_volume;
  969.             long    c_tapea;
  970.             u_short    c_inumber;
  971.             long    c_magic;
  972.             long    c_checksum;
  973.             struct odinode {
  974.                 unsigned short odi_mode;
  975.                 u_short    odi_nlink;
  976.                 u_short    odi_uid;
  977.                 u_short    odi_gid;
  978.                 long    odi_size;
  979.                 long    odi_rdev;
  980.                 char    odi_addr[36];
  981.                 long    odi_atime;
  982.                 long    odi_mtime;
  983.                 long    odi_ctime;
  984.             } c_dinode;
  985.             long    c_count;
  986.             char    c_addr[256];
  987.         } s_ospcl;
  988.     } u_ospcl;
  989.  
  990.     if (!cvtflag) {
  991.         readtape((char *)buf);
  992.         if (buf->c_magic != NFS_MAGIC) {
  993.             if (swabl(buf->c_magic) != NFS_MAGIC)
  994.                 return (FAIL);
  995.             if (!Bcvt) {
  996.                 vprintf(stdout, "Note: Doing Byte swapping\n");
  997.                 Bcvt = 1;
  998.             }
  999.         }
  1000.         if (checksum((int *)buf) == FAIL)
  1001.             return (FAIL);
  1002.         if (Bcvt)
  1003.             swabst((u_char *)"8l4s31l", (u_char *)buf);
  1004.         goto good;
  1005.     }
  1006.     readtape((char *)(&u_ospcl.s_ospcl));
  1007.     bzero((char *)buf, (long)TP_BSIZE);
  1008.     buf->c_type = u_ospcl.s_ospcl.c_type;
  1009.     buf->c_date = u_ospcl.s_ospcl.c_date;
  1010.     buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
  1011.     buf->c_volume = u_ospcl.s_ospcl.c_volume;
  1012.     buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
  1013.     buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
  1014.     buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
  1015.     buf->c_magic = u_ospcl.s_ospcl.c_magic;
  1016.     buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
  1017.     buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
  1018.     buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
  1019.     buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
  1020.     buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
  1021.     buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
  1022.     buf->c_dinode.di_atime.ts_sec = u_ospcl.s_ospcl.c_dinode.odi_atime;
  1023.     buf->c_dinode.di_mtime.ts_sec = u_ospcl.s_ospcl.c_dinode.odi_mtime;
  1024.     buf->c_dinode.di_ctime.ts_sec = u_ospcl.s_ospcl.c_dinode.odi_ctime;
  1025.     buf->c_count = u_ospcl.s_ospcl.c_count;
  1026.     bcopy(u_ospcl.s_ospcl.c_addr, buf->c_addr, (long)256);
  1027.     if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
  1028.         checksum((int *)(&u_ospcl.s_ospcl)) == FAIL)
  1029.         return(FAIL);
  1030.     buf->c_magic = NFS_MAGIC;
  1031.  
  1032. good:
  1033.     if ((buf->c_dinode.di_size == 0 || buf->c_dinode.di_size > 0xfffffff) &&
  1034.         (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt == 0) {
  1035.         qcvt.qval = buf->c_dinode.di_size;
  1036.         if (qcvt.val[0] || qcvt.val[1]) {
  1037.             printf("Note: Doing Quad swapping\n");
  1038.             Qcvt = 1;
  1039.         }
  1040.     }
  1041.     if (Qcvt) {
  1042.         qcvt.qval = buf->c_dinode.di_size;
  1043.         i = qcvt.val[1];
  1044.         qcvt.val[1] = qcvt.val[0];
  1045.         qcvt.val[0] = i;
  1046.         buf->c_dinode.di_size = qcvt.qval;
  1047.     }
  1048.  
  1049.     switch (buf->c_type) {
  1050.  
  1051.     case TS_CLRI:
  1052.     case TS_BITS:
  1053.         /*
  1054.          * Have to patch up missing information in bit map headers
  1055.          */
  1056.         buf->c_inumber = 0;
  1057.         buf->c_dinode.di_size = buf->c_count * TP_BSIZE;
  1058.         for (i = 0; i < buf->c_count; i++)
  1059.             buf->c_addr[i]++;
  1060.         break;
  1061.  
  1062.     case TS_TAPE:
  1063.         if ((buf->c_flags & DR_NEWINODEFMT) == 0)
  1064.             oldinofmt = 1;
  1065.         /* fall through */
  1066.     case TS_END:
  1067.         buf->c_inumber = 0;
  1068.         break;
  1069.  
  1070.     case TS_INODE:
  1071.     case TS_ADDR:
  1072.         break;
  1073.  
  1074.     default:
  1075.         panic("gethead: unknown inode type %d\n", buf->c_type);
  1076.         break;
  1077.     }
  1078.     /*
  1079.      * If we are restoring a filesystem with old format inodes, 
  1080.      * copy the uid/gid to the new location.
  1081.      */
  1082.     if (oldinofmt) {
  1083.         buf->c_dinode.di_uid = buf->c_dinode.di_ouid;
  1084.         buf->c_dinode.di_gid = buf->c_dinode.di_ogid;
  1085.     }
  1086.     if (dflag)
  1087.         accthdr(buf);
  1088.     return(GOOD);
  1089. }
  1090.  
  1091. /*
  1092.  * Check that a header is where it belongs and predict the next header
  1093.  */
  1094. static void
  1095. accthdr(header)
  1096.     struct s_spcl *header;
  1097. {
  1098.     static ino_t previno = 0x7fffffff;
  1099.     static int prevtype;
  1100.     static long predict;
  1101.     long blks, i;
  1102.  
  1103.     if (header->c_type == TS_TAPE) {
  1104.         fprintf(stderr, "Volume header (%s inode format) ",
  1105.             oldinofmt ? "old" : "new");
  1106.          if (header->c_firstrec)
  1107.              fprintf(stderr, "begins with record %d",
  1108.                  header->c_firstrec);
  1109.          fprintf(stderr, "\n");
  1110.         previno = 0x7fffffff;
  1111.         return;
  1112.     }
  1113.     if (previno == 0x7fffffff)
  1114.         goto newcalc;
  1115.     switch (prevtype) {
  1116.     case TS_BITS:
  1117.         fprintf(stderr, "Dump mask header");
  1118.         break;
  1119.     case TS_CLRI:
  1120.         fprintf(stderr, "Remove mask header");
  1121.         break;
  1122.     case TS_INODE:
  1123.         fprintf(stderr, "File header, ino %d", previno);
  1124.         break;
  1125.     case TS_ADDR:
  1126.         fprintf(stderr, "File continuation header, ino %d", previno);
  1127.         break;
  1128.     case TS_END:
  1129.         fprintf(stderr, "End of tape header");
  1130.         break;
  1131.     }
  1132.     if (predict != blksread - 1)
  1133.         fprintf(stderr, "; predicted %d blocks, got %d blocks",
  1134.             predict, blksread - 1);
  1135.     fprintf(stderr, "\n");
  1136. newcalc:
  1137.     blks = 0;
  1138.     if (header->c_type != TS_END)
  1139.         for (i = 0; i < header->c_count; i++)
  1140.             if (header->c_addr[i] != 0)
  1141.                 blks++;
  1142.     predict = blks;
  1143.     blksread = 0;
  1144.     prevtype = header->c_type;
  1145.     previno = header->c_inumber;
  1146. }
  1147.  
  1148. /*
  1149.  * Find an inode header.
  1150.  * Complain if had to skip, and complain is set.
  1151.  */
  1152. static void
  1153. findinode(header)
  1154.     struct s_spcl *header;
  1155. {
  1156.     static long skipcnt = 0;
  1157.     long i;
  1158.     char buf[TP_BSIZE];
  1159.  
  1160.     curfile.name = "<name unknown>";
  1161.     curfile.action = UNKNOWN;
  1162.     curfile.dip = NULL;
  1163.     curfile.ino = 0;
  1164.     do {
  1165.         if (header->c_magic != NFS_MAGIC) {
  1166.             skipcnt++;
  1167.             while (gethead(header) == FAIL ||
  1168.                 header->c_date != dumpdate)
  1169.                 skipcnt++;
  1170.         }
  1171.         switch (header->c_type) {
  1172.  
  1173.         case TS_ADDR:
  1174.             /*
  1175.              * Skip up to the beginning of the next record
  1176.              */
  1177.             for (i = 0; i < header->c_count; i++)
  1178.                 if (header->c_addr[i])
  1179.                     readtape(buf);
  1180.             while (gethead(header) == FAIL ||
  1181.                 header->c_date != dumpdate)
  1182.                 skipcnt++;
  1183.             break;
  1184.  
  1185.         case TS_INODE:
  1186.             curfile.dip = &header->c_dinode;
  1187.             curfile.ino = header->c_inumber;
  1188.             break;
  1189.  
  1190.         case TS_END:
  1191.             curfile.ino = maxino;
  1192.             break;
  1193.  
  1194.         case TS_CLRI:
  1195.             curfile.name = "<file removal list>";
  1196.             break;
  1197.  
  1198.         case TS_BITS:
  1199.             curfile.name = "<file dump list>";
  1200.             break;
  1201.  
  1202.         case TS_TAPE:
  1203.             panic("unexpected tape header\n");
  1204.             /* NOTREACHED */
  1205.  
  1206.         default:
  1207.             panic("unknown tape header type %d\n", spcl.c_type);
  1208.             /* NOTREACHED */
  1209.  
  1210.         }
  1211.     } while (header->c_type == TS_ADDR);
  1212.     if (skipcnt > 0)
  1213.         fprintf(stderr, "resync restore, skipped %d blocks\n", skipcnt);
  1214.     skipcnt = 0;
  1215. }
  1216.  
  1217. static int
  1218. checksum(buf)
  1219.     register int *buf;
  1220. {
  1221.     register int i, j;
  1222.  
  1223.     j = sizeof(union u_spcl) / sizeof(int);
  1224.     i = 0;
  1225.     if(!Bcvt) {
  1226.         do
  1227.             i += *buf++;
  1228.         while (--j);
  1229.     } else {
  1230.         /* What happens if we want to read restore tapes
  1231.             for a 16bit int machine??? */
  1232.         do 
  1233.             i += swabl(*buf++);
  1234.         while (--j);
  1235.     }
  1236.             
  1237.     if (i != CHECKSUM) {
  1238.         fprintf(stderr, "Checksum error %o, inode %d file %s\n", i,
  1239.             curfile.ino, curfile.name);
  1240.         return(FAIL);
  1241.     }
  1242.     return(GOOD);
  1243. }
  1244.  
  1245. #ifdef RRESTORE
  1246. #if __STDC__
  1247. #include <stdarg.h>
  1248. #else
  1249. #include <varargs.h>
  1250. #endif
  1251.  
  1252. void
  1253. #if __STDC__
  1254. msg(const char *fmt, ...)
  1255. #else
  1256. msg(fmt, va_alist)
  1257.     char *fmt;
  1258.     va_dcl
  1259. #endif
  1260. {
  1261.     va_list ap;
  1262. #if __STDC__
  1263.     va_start(ap, fmt);
  1264. #else
  1265.     va_start(ap);
  1266. #endif
  1267.     (void)vfprintf(stderr, fmt, ap);
  1268.     va_end(ap);
  1269. }
  1270. #endif /* RRESTORE */
  1271.  
  1272. static u_char *
  1273. swabshort(sp, n)
  1274.     register u_char *sp;
  1275.     register int n;
  1276. {
  1277.     char c;
  1278.  
  1279.     while (--n >= 0) {
  1280.         c = sp[0]; sp[0] = sp[1]; sp[1] = c;
  1281.         sp += 2;
  1282.     }
  1283.     return (sp);
  1284. }
  1285.  
  1286. static u_char *
  1287. swablong(sp, n)
  1288.     register u_char *sp;
  1289.     register int n;
  1290. {
  1291.     char c;
  1292.  
  1293.     while (--n >= 0) {
  1294.         c = sp[0]; sp[0] = sp[3]; sp[3] = c;
  1295.         c = sp[2]; sp[2] = sp[1]; sp[1] = c;
  1296.         sp += 4;
  1297.     }
  1298.     return (sp);
  1299. }
  1300.  
  1301. void
  1302. swabst(cp, sp)
  1303.     register u_char *cp, *sp;
  1304. {
  1305.     int n = 0;
  1306.  
  1307.     while (*cp) {
  1308.         switch (*cp) {
  1309.         case '0': case '1': case '2': case '3': case '4':
  1310.         case '5': case '6': case '7': case '8': case '9':
  1311.             n = (n * 10) + (*cp++ - '0');
  1312.             continue;
  1313.         
  1314.         case 's': case 'w': case 'h':
  1315.             if (n == 0)
  1316.                 n = 1;
  1317.             sp = swabshort(sp, n);
  1318.             break;
  1319.  
  1320.         case 'l':
  1321.             if (n == 0)
  1322.                 n = 1;
  1323.             sp = swablong(sp, n);
  1324.             break;
  1325.  
  1326.         default: /* Any other character, like 'b' counts as byte. */
  1327.             if (n == 0)
  1328.                 n = 1;
  1329.             sp += n;
  1330.             break;
  1331.         }
  1332.         cp++;
  1333.         n = 0;
  1334.     }
  1335. }
  1336.  
  1337. static u_long
  1338. swabl(x)
  1339.     u_long x;
  1340. {
  1341.     swabst((u_char *)"l", (u_char *)&x);
  1342.     return (x);
  1343. }
  1344.