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