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