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