be more social about killing attached processes (vhangup takes care of it)
[unix-history] / usr / src / old / tar / tar.c
CommitLineData
f644bb55
DF
1/*
2 * Copyright (c) 1980 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
7#ifndef lint
8char copyright[] =
9"@(#) Copyright (c) 1980 Regents of the University of California.\n\
10 All rights reserved.\n";
11#endif not lint
12
654c61ee 13#ifndef lint
8c526af6 14static char sccsid[] = "@(#)tar.c 5.3 (Berkeley) %G%";
f644bb55 15#endif not lint
555a248b 16
1e5bf3dc
KD
17/*
18 * Tape Archival Program
19 */
415c8aef 20#include <stdio.h>
d7ab2ea5 21#include <sys/param.h>
415c8aef 22#include <sys/stat.h>
654c61ee 23#include <sys/dir.h>
dfdd2236 24#include <sys/ioctl.h>
06eff236 25#include <sys/mtio.h>
828d5b76 26#include <sys/time.h>
415c8aef 27#include <signal.h>
654c61ee 28#include <errno.h>
415c8aef 29
415c8aef 30#define TBLOCK 512
9547dafa 31#define NBLOCK 20
415c8aef 32#define NAMSIZ 100
75115c46 33#define FILEBLOCK 20
555a248b 34
1e5bf3dc
KD
35#define writetape(b) writetbuf(b, 1)
36#define min(a,b) ((a) < (b) ? (a) : (b))
37#define max(a,b) ((a) > (b) ? (a) : (b))
38
415c8aef
BJ
39union hblock {
40 char dummy[TBLOCK];
41 struct header {
42 char name[NAMSIZ];
43 char mode[8];
44 char uid[8];
45 char gid[8];
46 char size[12];
47 char mtime[12];
48 char chksum[8];
49 char linkflag;
50 char linkname[NAMSIZ];
51 } dbuf;
555a248b 52};
415c8aef
BJ
53
54struct linkbuf {
55 ino_t inum;
56 dev_t devnum;
57 int count;
58 char pathname[NAMSIZ];
59 struct linkbuf *nextp;
555a248b
BJ
60};
61
62union hblock dblock;
095da6e7 63union hblock *tbuf;
555a248b
BJ
64struct linkbuf *ihead;
65struct stat stbuf;
66
67int rflag;
68int xflag;
69int vflag;
70int tflag;
71int cflag;
72int mflag;
73int fflag;
654c61ee 74int iflag;
555a248b
BJ
75int oflag;
76int pflag;
77int wflag;
78int hflag;
8678ae71 79int Bflag;
654c61ee 80int Fflag;
555a248b
BJ
81
82int mt;
75115c46 83int mtdev = 1;
555a248b
BJ
84int term;
85int chksum;
86int recno;
45a92ce3
JL
87int first;
88int prtlinkerr;
415c8aef 89int freemem = 1;
75115c46 90int nblock = 0;
555a248b
BJ
91int onintr();
92int onquit();
93int onhup();
45a92ce3 94#ifdef notdef
555a248b 95int onterm();
45a92ce3 96#endif
415c8aef
BJ
97
98daddr_t low;
99daddr_t high;
555a248b 100daddr_t bsrch();
415c8aef 101
ed4dfcb6 102FILE *vfile = stdout;
415c8aef
BJ
103FILE *tfile;
104char tname[] = "/tmp/tarXXXXXX";
415c8aef 105char *usefile;
555a248b 106char magtape[] = "/dev/rmt8";
415c8aef 107char *malloc();
555a248b
BJ
108char *sprintf();
109char *strcat();
654c61ee 110char *rindex();
5ee3622a 111char *getcwd();
13fc8845 112char *getwd();
45a92ce3 113char *getmem();
415c8aef
BJ
114
115main(argc, argv)
116int argc;
117char *argv[];
118{
119 char *cp;
415c8aef
BJ
120
121 if (argc < 2)
122 usage();
123
124 tfile = NULL;
125 usefile = magtape;
126 argv[argc] = 0;
127 argv++;
128 for (cp = *argv++; *cp; cp++)
129 switch(*cp) {
555a248b 130
415c8aef 131 case 'f':
654c61ee
SL
132 if (*argv == 0) {
133 fprintf(stderr,
134 "tar: tapefile must be specified with 'f' option\n");
135 usage();
136 }
415c8aef
BJ
137 usefile = *argv++;
138 fflag++;
415c8aef 139 break;
555a248b 140
415c8aef
BJ
141 case 'c':
142 cflag++;
143 rflag++;
144 break;
555a248b 145
415c8aef
BJ
146 case 'o':
147 oflag++;
148 break;
555a248b 149
415c8aef
BJ
150 case 'p':
151 pflag++;
152 break;
555a248b 153
415c8aef
BJ
154 case 'u':
155 mktemp(tname);
156 if ((tfile = fopen(tname, "w")) == NULL) {
555a248b 157 fprintf(stderr,
45a92ce3 158 "tar: cannot create temporary file (%s)\n",
555a248b 159 tname);
415c8aef
BJ
160 done(1);
161 }
162 fprintf(tfile, "!!!!!/!/!/!/!/!/!/! 000\n");
555a248b
BJ
163 /*FALL THRU*/
164
415c8aef
BJ
165 case 'r':
166 rflag++;
415c8aef 167 break;
555a248b 168
415c8aef
BJ
169 case 'v':
170 vflag++;
171 break;
555a248b 172
415c8aef
BJ
173 case 'w':
174 wflag++;
175 break;
555a248b 176
415c8aef
BJ
177 case 'x':
178 xflag++;
179 break;
555a248b 180
415c8aef
BJ
181 case 't':
182 tflag++;
183 break;
555a248b 184
415c8aef
BJ
185 case 'm':
186 mflag++;
187 break;
555a248b 188
415c8aef
BJ
189 case '-':
190 break;
555a248b 191
415c8aef
BJ
192 case '0':
193 case '1':
194 case '4':
195 case '5':
1e5bf3dc 196 case '7':
415c8aef
BJ
197 case '8':
198 magtape[8] = *cp;
199 usefile = magtape;
200 break;
555a248b 201
415c8aef 202 case 'b':
095da6e7
SL
203 if (*argv == 0) {
204 fprintf(stderr,
205 "tar: blocksize must be specified with 'b' option\n");
206 usage();
207 }
208 nblock = atoi(*argv);
209 if (nblock <= 0) {
210 fprintf(stderr,
211 "tar: invalid blocksize \"%s\"\n", *argv);
415c8aef
BJ
212 done(1);
213 }
095da6e7 214 argv++;
415c8aef 215 break;
555a248b 216
415c8aef 217 case 'l':
45a92ce3 218 prtlinkerr++;
415c8aef 219 break;
555a248b
BJ
220
221 case 'h':
222 hflag++;
223 break;
224
654c61ee
SL
225 case 'i':
226 iflag++;
227 break;
228
8678ae71
KM
229 case 'B':
230 Bflag++;
231 break;
232
654c61ee
SL
233 case 'F':
234 Fflag++;
235 break;
236
415c8aef
BJ
237 default:
238 fprintf(stderr, "tar: %c: unknown option\n", *cp);
239 usage();
240 }
241
555a248b
BJ
242 if (!rflag && !xflag && !tflag)
243 usage();
415c8aef 244 if (rflag) {
555a248b 245 if (cflag && tfile != NULL)
415c8aef 246 usage();
415c8aef
BJ
247 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
248 signal(SIGINT, onintr);
249 if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
250 signal(SIGHUP, onhup);
251 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
252 signal(SIGQUIT, onquit);
555a248b 253#ifdef notdef
415c8aef
BJ
254 if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
255 signal(SIGTERM, onterm);
555a248b 256#endif
415c8aef
BJ
257 if (strcmp(usefile, "-") == 0) {
258 if (cflag == 0) {
555a248b 259 fprintf(stderr,
095da6e7 260 "tar: can only create standard output archives\n");
415c8aef
BJ
261 done(1);
262 }
ed4dfcb6
KD
263 vfile = stderr;
264 setlinebuf(vfile);
415c8aef 265 mt = dup(1);
555a248b 266 } else if ((mt = open(usefile, 2)) < 0) {
415c8aef 267 if (cflag == 0 || (mt = creat(usefile, 0666)) < 0) {
555a248b
BJ
268 fprintf(stderr,
269 "tar: cannot open %s\n", usefile);
415c8aef
BJ
270 done(1);
271 }
272 }
415c8aef 273 dorep(argv);
555a248b 274 done(0);
415c8aef 275 }
555a248b
BJ
276 if (strcmp(usefile, "-") == 0) {
277 mt = dup(0);
8c526af6 278 Bflag++;
555a248b
BJ
279 } else if ((mt = open(usefile, 0)) < 0) {
280 fprintf(stderr, "tar: cannot open %s\n", usefile);
281 done(1);
415c8aef 282 }
555a248b
BJ
283 if (xflag)
284 doxtract(argv);
415c8aef 285 else
555a248b 286 dotable();
415c8aef
BJ
287 done(0);
288}
289
290usage()
291{
555a248b 292 fprintf(stderr,
1e5bf3dc 293"tar: usage: tar -{txru}[cvfblmhopwBi] [tapefile] [blocksize] file1 file2...\n");
415c8aef
BJ
294 done(1);
295}
296
297dorep(argv)
555a248b 298 char *argv[];
415c8aef
BJ
299{
300 register char *cp, *cp2;
f21b792d 301 char wdir[MAXPATHLEN], tempdir[MAXPATHLEN], *parent;
415c8aef
BJ
302
303 if (!cflag) {
304 getdir();
305 do {
306 passtape();
307 if (term)
308 done(0);
309 getdir();
310 } while (!endtape());
095da6e7 311 backtape();
415c8aef
BJ
312 if (tfile != NULL) {
313 char buf[200];
314
555a248b
BJ
315 sprintf(buf,
316"sort +0 -1 +1nr %s -o %s; awk '$1 != prev {print; prev=$1}' %s >%sX; mv %sX %s",
415c8aef
BJ
317 tname, tname, tname, tname, tname, tname);
318 fflush(tfile);
319 system(buf);
320 freopen(tname, "r", tfile);
321 fstat(fileno(tfile), &stbuf);
322 high = stbuf.st_size;
323 }
324 }
325
5ee3622a 326 (void) getcwd(wdir);
415c8aef
BJ
327 while (*argv && ! term) {
328 cp2 = *argv;
329 if (!strcmp(cp2, "-C") && argv[1]) {
330 argv++;
331 if (chdir(*argv) < 0)
332 perror(*argv);
333 else
5ee3622a 334 (void) getcwd(wdir);
415c8aef
BJ
335 argv++;
336 continue;
337 }
f21b792d 338 parent = wdir;
415c8aef
BJ
339 for (cp = *argv; *cp; cp++)
340 if (*cp == '/')
341 cp2 = cp;
342 if (cp2 != *argv) {
343 *cp2 = '\0';
f21b792d
SL
344 if (chdir(*argv) < 0) {
345 perror(*argv);
346 continue;
347 }
5ee3622a 348 parent = getcwd(tempdir);
415c8aef
BJ
349 *cp2 = '/';
350 cp2++;
351 }
f21b792d 352 putfile(*argv++, cp2, parent);
3bda777c 353 if (chdir(wdir) < 0) {
45a92ce3 354 fprintf(stderr, "tar: cannot change back?: ");
3bda777c
KM
355 perror(wdir);
356 }
415c8aef
BJ
357 }
358 putempty();
359 putempty();
360 flushtape();
45a92ce3 361 if (prtlinkerr == 0)
555a248b
BJ
362 return;
363 for (; ihead != NULL; ihead = ihead->nextp) {
364 if (ihead->count == 0)
365 continue;
095da6e7 366 fprintf(stderr, "tar: missing links to %s\n", ihead->pathname);
555a248b 367 }
415c8aef
BJ
368}
369
370endtape()
371{
1e5bf3dc 372 return (dblock.dbuf.name[0] == '\0');
415c8aef
BJ
373}
374
375getdir()
376{
377 register struct stat *sp;
378 int i;
379
654c61ee 380top:
555a248b 381 readtape((char *)&dblock);
415c8aef
BJ
382 if (dblock.dbuf.name[0] == '\0')
383 return;
384 sp = &stbuf;
385 sscanf(dblock.dbuf.mode, "%o", &i);
386 sp->st_mode = i;
387 sscanf(dblock.dbuf.uid, "%o", &i);
388 sp->st_uid = i;
389 sscanf(dblock.dbuf.gid, "%o", &i);
390 sp->st_gid = i;
391 sscanf(dblock.dbuf.size, "%lo", &sp->st_size);
392 sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime);
393 sscanf(dblock.dbuf.chksum, "%o", &chksum);
654c61ee 394 if (chksum != (i = checksum())) {
095da6e7 395 fprintf(stderr, "tar: directory checksum error (%d != %d)\n",
654c61ee
SL
396 chksum, i);
397 if (iflag)
398 goto top;
415c8aef
BJ
399 done(2);
400 }
401 if (tfile != NULL)
402 fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime);
403}
404
405passtape()
406{
407 long blocks;
1e5bf3dc 408 char *bufp;
415c8aef
BJ
409
410 if (dblock.dbuf.linkflag == '1')
411 return;
412 blocks = stbuf.st_size;
413 blocks += TBLOCK-1;
414 blocks /= TBLOCK;
415
1e5bf3dc
KD
416 while (blocks-- > 0)
417 readtbuf(&bufp, TBLOCK);
415c8aef
BJ
418}
419
f21b792d 420putfile(longname, shortname, parent)
555a248b
BJ
421 char *longname;
422 char *shortname;
f21b792d 423 char *parent;
415c8aef 424{
1e5bf3dc
KD
425 int infile = 0;
426 long blocks;
415c8aef 427 char buf[TBLOCK];
1e5bf3dc 428 char *bigbuf;
45a92ce3 429 register char *cp;
aeb5c9b4
KM
430 struct direct *dp;
431 DIR *dirp;
45a92ce3 432 int i;
f21b792d 433 char newparent[NAMSIZ+64];
654c61ee 434 extern int errno;
1e5bf3dc
KD
435 int maxread;
436 int hint; /* amount to write to get "in sync" */
415c8aef 437
f21b792d 438 if (!hflag)
654c61ee
SL
439 i = lstat(shortname, &stbuf);
440 else
441 i = stat(shortname, &stbuf);
442 if (i < 0) {
443 switch (errno) {
444 case EACCES:
445 fprintf(stderr, "tar: %s: cannot open file\n", longname);
446 break;
447 case ENOENT:
448 fprintf(stderr, "tar: %s: no such file or directory\n",
449 longname);
450 break;
451 default:
452 fprintf(stderr, "tar: %s: cannot stat file\n", longname);
453 break;
454 }
f21b792d
SL
455 return;
456 }
654c61ee 457 if (tfile != NULL && checkupdate(longname) == 0)
415c8aef 458 return;
654c61ee
SL
459 if (checkw('r', longname) == 0)
460 return;
461 if (Fflag && checkf(shortname, stbuf.st_mode, Fflag) == 0)
415c8aef 462 return;
415c8aef 463
654c61ee
SL
464 switch (stbuf.st_mode & S_IFMT) {
465 case S_IFDIR:
555a248b
BJ
466 for (i = 0, cp = buf; *cp++ = longname[i++];)
467 ;
415c8aef
BJ
468 *--cp = '/';
469 *++cp = 0 ;
415c8aef 470 if (!oflag) {
555a248b 471 if ((cp - buf) >= NAMSIZ) {
095da6e7
SL
472 fprintf(stderr, "tar: %s: file name too long\n",
473 longname);
555a248b
BJ
474 return;
475 }
476 stbuf.st_size = 0;
477 tomodes(&stbuf);
478 strcpy(dblock.dbuf.name,buf);
479 sprintf(dblock.dbuf.chksum, "%6o", checksum());
480 writetape((char *)&dblock);
415c8aef 481 }
f21b792d 482 sprintf(newparent, "%s/%s", parent, shortname);
3bda777c
KM
483 if (chdir(shortname) < 0) {
484 perror(shortname);
485 return;
486 }
aeb5c9b4 487 if ((dirp = opendir(".")) == NULL) {
095da6e7
SL
488 fprintf(stderr, "tar: %s: directory read error\n",
489 longname);
3bda777c 490 if (chdir(parent) < 0) {
45a92ce3 491 fprintf(stderr, "tar: cannot change back?: ");
3bda777c
KM
492 perror(parent);
493 }
aeb5c9b4
KM
494 return;
495 }
496 while ((dp = readdir(dirp)) != NULL && !term) {
497 if (dp->d_ino == 0)
415c8aef 498 continue;
555a248b
BJ
499 if (!strcmp(".", dp->d_name) ||
500 !strcmp("..", dp->d_name))
415c8aef 501 continue;
aeb5c9b4
KM
502 strcpy(cp, dp->d_name);
503 i = telldir(dirp);
504 closedir(dirp);
f21b792d 505 putfile(buf, cp, newparent);
aeb5c9b4
KM
506 dirp = opendir(".");
507 seekdir(dirp, i);
415c8aef 508 }
aeb5c9b4 509 closedir(dirp);
3bda777c 510 if (chdir(parent) < 0) {
45a92ce3 511 fprintf(stderr, "tar: cannot change back?: ");
3bda777c
KM
512 perror(parent);
513 }
654c61ee
SL
514 break;
515
516 case S_IFLNK:
517 tomodes(&stbuf);
518 if (strlen(longname) >= NAMSIZ) {
095da6e7
SL
519 fprintf(stderr, "tar: %s: file name too long\n",
520 longname);
654c61ee
SL
521 return;
522 }
523 strcpy(dblock.dbuf.name, longname);
555a248b 524 if (stbuf.st_size + 1 >= NAMSIZ) {
095da6e7
SL
525 fprintf(stderr, "tar: %s: symbolic link too long\n",
526 longname);
555a248b
BJ
527 return;
528 }
f21b792d 529 i = readlink(shortname, dblock.dbuf.linkname, NAMSIZ - 1);
555a248b 530 if (i < 0) {
f21b792d 531 perror(longname);
555a248b
BJ
532 return;
533 }
534 dblock.dbuf.linkname[i] = '\0';
535 dblock.dbuf.linkflag = '2';
45a92ce3
JL
536 if (vflag)
537 fprintf(vfile, "a %s symbolic link to %s\n",
538 longname, dblock.dbuf.linkname);
555a248b
BJ
539 sprintf(dblock.dbuf.size, "%11lo", 0);
540 sprintf(dblock.dbuf.chksum, "%6o", checksum());
541 writetape((char *)&dblock);
654c61ee
SL
542 break;
543
544 case S_IFREG:
545 if ((infile = open(shortname, 0)) < 0) {
546 fprintf(stderr, "tar: %s: cannot open file\n", longname);
415c8aef
BJ
547 return;
548 }
654c61ee
SL
549 tomodes(&stbuf);
550 if (strlen(longname) >= NAMSIZ) {
095da6e7
SL
551 fprintf(stderr, "tar: %s: file name too long\n",
552 longname);
1e5bf3dc 553 close(infile);
654c61ee
SL
554 return;
555 }
556 strcpy(dblock.dbuf.name, longname);
557 if (stbuf.st_nlink > 1) {
558 struct linkbuf *lp;
559 int found = 0;
560
561 for (lp = ihead; lp != NULL; lp = lp->nextp)
562 if (lp->inum == stbuf.st_ino &&
563 lp->devnum == stbuf.st_dev) {
564 found++;
565 break;
566 }
567 if (found) {
568 strcpy(dblock.dbuf.linkname, lp->pathname);
569 dblock.dbuf.linkflag = '1';
570 sprintf(dblock.dbuf.chksum, "%6o", checksum());
1e5bf3dc 571 writetape( (char *) &dblock);
45a92ce3
JL
572 if (vflag)
573 fprintf(vfile, "a %s link to %s\n",
574 longname, lp->pathname);
654c61ee
SL
575 lp->count--;
576 close(infile);
577 return;
578 }
45a92ce3
JL
579 lp = (struct linkbuf *) getmem(sizeof(*lp));
580 if (lp != NULL) {
654c61ee
SL
581 lp->nextp = ihead;
582 ihead = lp;
583 lp->inum = stbuf.st_ino;
584 lp->devnum = stbuf.st_dev;
585 lp->count = stbuf.st_nlink - 1;
586 strcpy(lp->pathname, longname);
415c8aef
BJ
587 }
588 }
1e5bf3dc 589 blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK;
45a92ce3
JL
590 if (vflag)
591 fprintf(vfile, "a %s %ld blocks\n", longname, blocks);
654c61ee 592 sprintf(dblock.dbuf.chksum, "%6o", checksum());
1e5bf3dc
KD
593 hint = writetape((char *)&dblock);
594 maxread = max(stbuf.st_blksize, (nblock * TBLOCK));
1e5bf3dc
KD
595 if ((bigbuf = malloc(maxread)) == 0) {
596 maxread = TBLOCK;
597 bigbuf = buf;
598 }
415c8aef 599
1e5bf3dc
KD
600 while ((i = read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0
601 && blocks > 0) {
602 register int nblks;
603
604 nblks = ((i-1)/TBLOCK)+1;
605 if (nblks > blocks)
606 nblks = blocks;
607 hint = writetbuf(bigbuf, nblks);
608 blocks -= nblks;
654c61ee 609 }
1e5bf3dc
KD
610 close(infile);
611 if (bigbuf != buf)
1e5bf3dc 612 free(bigbuf);
1e5bf3dc 613 if (blocks != 0 || i != 0)
095da6e7
SL
614 fprintf(stderr, "tar: %s: file changed size\n",
615 longname);
654c61ee
SL
616 while (--blocks >= 0)
617 putempty();
618 break;
619
620 default:
621 fprintf(stderr, "tar: %s is not a file. Not dumped\n",
095da6e7 622 longname);
654c61ee 623 break;
415c8aef 624 }
415c8aef
BJ
625}
626
415c8aef 627doxtract(argv)
555a248b 628 char *argv[];
415c8aef
BJ
629{
630 long blocks, bytes;
415c8aef
BJ
631 char **cp;
632 int ofile;
633
634 for (;;) {
635 getdir();
636 if (endtape())
637 break;
415c8aef
BJ
638 if (*argv == 0)
639 goto gotit;
415c8aef
BJ
640 for (cp = argv; *cp; cp++)
641 if (prefix(*cp, dblock.dbuf.name))
642 goto gotit;
643 passtape();
644 continue;
645
646gotit:
647 if (checkw('x', dblock.dbuf.name) == 0) {
648 passtape();
649 continue;
650 }
654c61ee
SL
651 if (Fflag) {
652 char *s;
653
654 if ((s = rindex(dblock.dbuf.name, '/')) == 0)
655 s = dblock.dbuf.name;
656 else
657 s++;
658 if (checkf(s, stbuf.st_mode, Fflag) == 0) {
659 passtape();
660 continue;
661 }
662 }
45a92ce3
JL
663 if (checkdir(dblock.dbuf.name)) { /* have a directory */
664 if (mflag == 0)
665 dodirtimes(&dblock);
415c8aef 666 continue;
45a92ce3
JL
667 }
668 if (dblock.dbuf.linkflag == '2') { /* symlink */
555a248b
BJ
669 unlink(dblock.dbuf.name);
670 if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) {
095da6e7
SL
671 fprintf(stderr, "tar: %s: symbolic link failed\n",
672 dblock.dbuf.name);
555a248b
BJ
673 continue;
674 }
675 if (vflag)
ed4dfcb6 676 fprintf(vfile, "x %s symbolic link to %s\n",
095da6e7 677 dblock.dbuf.name, dblock.dbuf.linkname);
75115c46
KD
678#ifdef notdef
679 /* ignore alien orders */
680 chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid);
45a92ce3
JL
681 if (mflag == 0)
682 setimes(dblock.dbuf.name, stbuf.st_mtime);
75115c46
KD
683 if (pflag)
684 chmod(dblock.dbuf.name, stbuf.st_mode & 07777);
685#endif
555a248b
BJ
686 continue;
687 }
45a92ce3 688 if (dblock.dbuf.linkflag == '1') { /* regular link */
415c8aef
BJ
689 unlink(dblock.dbuf.name);
690 if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) {
095da6e7
SL
691 fprintf(stderr, "tar: %s: cannot link\n",
692 dblock.dbuf.name);
415c8aef
BJ
693 continue;
694 }
695 if (vflag)
45a92ce3 696 fprintf(vfile, "%s linked to %s\n",
095da6e7 697 dblock.dbuf.name, dblock.dbuf.linkname);
415c8aef
BJ
698 continue;
699 }
555a248b
BJ
700 if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) {
701 fprintf(stderr, "tar: %s - cannot create\n",
095da6e7 702 dblock.dbuf.name);
415c8aef
BJ
703 passtape();
704 continue;
705 }
1e5bf3dc 706 chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid);
415c8aef
BJ
707 blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK;
708 if (vflag)
45a92ce3 709 fprintf(vfile, "x %s, %ld bytes, %ld tape blocks\n",
095da6e7 710 dblock.dbuf.name, bytes, blocks);
1e5bf3dc
KD
711 for (; blocks > 0;) {
712 register int nread;
713 char *bufp;
714 register int nwant;
715
716 nwant = NBLOCK*TBLOCK;
717 if (nwant > (blocks*TBLOCK))
718 nwant = (blocks*TBLOCK);
719 nread = readtbuf(&bufp, nwant);
45a92ce3 720 if (write(ofile, bufp, (int)min(nread, bytes)) < 0) {
555a248b 721 fprintf(stderr,
095da6e7
SL
722 "tar: %s: HELP - extract write error\n",
723 dblock.dbuf.name);
555a248b
BJ
724 done(2);
725 }
1e5bf3dc
KD
726 bytes -= nread;
727 blocks -= (((nread-1)/TBLOCK)+1);
415c8aef
BJ
728 }
729 close(ofile);
45a92ce3
JL
730 if (mflag == 0)
731 setimes(dblock.dbuf.name, stbuf.st_mtime);
cd2661db 732 if (pflag)
555a248b 733 chmod(dblock.dbuf.name, stbuf.st_mode & 07777);
415c8aef 734 }
45a92ce3
JL
735 if (mflag == 0) {
736 dblock.dbuf.name[0] = '\0'; /* process the whole stack */
737 dodirtimes(&dblock);
738 }
415c8aef
BJ
739}
740
741dotable()
742{
743 for (;;) {
744 getdir();
745 if (endtape())
746 break;
747 if (vflag)
748 longt(&stbuf);
749 printf("%s", dblock.dbuf.name);
750 if (dblock.dbuf.linkflag == '1')
751 printf(" linked to %s", dblock.dbuf.linkname);
555a248b
BJ
752 if (dblock.dbuf.linkflag == '2')
753 printf(" symbolic link to %s", dblock.dbuf.linkname);
415c8aef
BJ
754 printf("\n");
755 passtape();
756 }
757}
758
759putempty()
760{
761 char buf[TBLOCK];
415c8aef 762
095da6e7 763 bzero(buf, sizeof (buf));
415c8aef
BJ
764 writetape(buf);
765}
766
767longt(st)
555a248b 768 register struct stat *st;
415c8aef
BJ
769{
770 register char *cp;
771 char *ctime();
772
773 pmode(st);
774 printf("%3d/%1d", st->st_uid, st->st_gid);
775 printf("%7D", st->st_size);
776 cp = ctime(&st->st_mtime);
777 printf(" %-12.12s %-4.4s ", cp+4, cp+20);
778}
779
780#define SUID 04000
781#define SGID 02000
782#define ROWN 0400
783#define WOWN 0200
784#define XOWN 0100
785#define RGRP 040
786#define WGRP 020
787#define XGRP 010
788#define ROTH 04
789#define WOTH 02
790#define XOTH 01
791#define STXT 01000
792int m1[] = { 1, ROWN, 'r', '-' };
793int m2[] = { 1, WOWN, 'w', '-' };
794int m3[] = { 2, SUID, 's', XOWN, 'x', '-' };
795int m4[] = { 1, RGRP, 'r', '-' };
796int m5[] = { 1, WGRP, 'w', '-' };
797int m6[] = { 2, SGID, 's', XGRP, 'x', '-' };
798int m7[] = { 1, ROTH, 'r', '-' };
799int m8[] = { 1, WOTH, 'w', '-' };
800int m9[] = { 2, STXT, 't', XOTH, 'x', '-' };
801
802int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
803
804pmode(st)
555a248b 805 register struct stat *st;
415c8aef
BJ
806{
807 register int **mp;
808
809 for (mp = &m[0]; mp < &m[9];)
810 select(*mp++, st);
811}
812
813select(pairp, st)
555a248b
BJ
814 int *pairp;
815 struct stat *st;
415c8aef
BJ
816{
817 register int n, *ap;
818
819 ap = pairp;
820 n = *ap++;
821 while (--n>=0 && (st->st_mode&*ap++)==0)
822 ap++;
823 printf("%c", *ap);
824}
825
45a92ce3
JL
826/*
827 * Make all directories needed by `name'. If `name' is a
828 * directory itself on the tar tape (indicated by a trailing '/'),
829 * return 1; else 0.
830 */
415c8aef 831checkdir(name)
555a248b 832 register char *name;
415c8aef
BJ
833{
834 register char *cp;
555a248b 835
654c61ee 836 /*
45a92ce3 837 * Quick check for existence of directory.
654c61ee
SL
838 */
839 if ((cp = rindex(name, '/')) == 0)
840 return (0);
841 *cp = '\0';
45a92ce3 842 if (access(name, 0) == 0) { /* already exists */
654c61ee 843 *cp = '/';
45a92ce3 844 return (cp[1] == '\0'); /* return (lastchar == '/') */
654c61ee
SL
845 }
846 *cp = '/';
847
848 /*
849 * No luck, try to make all directories in path.
850 */
415c8aef 851 for (cp = name; *cp; cp++) {
555a248b
BJ
852 if (*cp != '/')
853 continue;
854 *cp = '\0';
654c61ee 855 if (access(name, 0) < 0) {
13fc8845
SL
856 if (mkdir(name, 0777) < 0) {
857 perror(name);
654c61ee
SL
858 *cp = '/';
859 return (0);
415c8aef 860 }
1e5bf3dc 861 chown(name, stbuf.st_uid, stbuf.st_gid);
07269bf2 862 if (pflag && cp[1] == '\0')
13fc8845 863 chmod(name, stbuf.st_mode & 0777);
415c8aef 864 }
555a248b 865 *cp = '/';
415c8aef 866 }
555a248b 867 return (cp[-1]=='/');
415c8aef
BJ
868}
869
870onintr()
871{
872 signal(SIGINT, SIG_IGN);
873 term++;
874}
875
876onquit()
877{
878 signal(SIGQUIT, SIG_IGN);
879 term++;
880}
881
882onhup()
883{
884 signal(SIGHUP, SIG_IGN);
885 term++;
886}
887
45a92ce3 888#ifdef notdef
415c8aef
BJ
889onterm()
890{
891 signal(SIGTERM, SIG_IGN);
892 term++;
893}
45a92ce3 894#endif
415c8aef
BJ
895
896tomodes(sp)
897register struct stat *sp;
898{
899 register char *cp;
900
901 for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
902 *cp = '\0';
903 sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777);
904 sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid);
905 sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid);
906 sprintf(dblock.dbuf.size, "%11lo ", sp->st_size);
907 sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime);
908}
909
910checksum()
911{
912 register i;
913 register char *cp;
914
555a248b
BJ
915 for (cp = dblock.dbuf.chksum;
916 cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++)
415c8aef
BJ
917 *cp = ' ';
918 i = 0;
919 for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
920 i += *cp;
555a248b 921 return (i);
415c8aef
BJ
922}
923
924checkw(c, name)
555a248b 925 char *name;
415c8aef 926{
555a248b
BJ
927 if (!wflag)
928 return (1);
929 printf("%c ", c);
930 if (vflag)
931 longt(&stbuf);
932 printf("%s: ", name);
933 return (response() == 'y');
415c8aef
BJ
934}
935
936response()
937{
938 char c;
939
940 c = getchar();
941 if (c != '\n')
555a248b
BJ
942 while (getchar() != '\n')
943 ;
944 else
945 c = 'n';
946 return (c);
415c8aef
BJ
947}
948
654c61ee
SL
949checkf(name, mode, howmuch)
950 char *name;
951 int mode, howmuch;
952{
953 int l;
954
ed4dfcb6
KD
955 if ((mode & S_IFMT) == S_IFDIR){
956 if ((strcmp(name, "SCCS")==0) || (strcmp(name, "RCS")==0))
957 return(0);
958 return(1);
959 }
654c61ee
SL
960 if ((l = strlen(name)) < 3)
961 return (1);
962 if (howmuch > 1 && name[l-2] == '.' && name[l-1] == 'o')
963 return (0);
964 if (strcmp(name, "core") == 0 ||
965 strcmp(name, "errs") == 0 ||
966 (howmuch > 1 && strcmp(name, "a.out") == 0))
967 return (0);
968 /* SHOULD CHECK IF IT IS EXECUTABLE */
969 return (1);
970}
971
45a92ce3 972/* Is the current file a new file, or the newest one of the same name? */
415c8aef 973checkupdate(arg)
555a248b 974 char *arg;
415c8aef
BJ
975{
976 char name[100];
555a248b 977 long mtime;
415c8aef
BJ
978 daddr_t seekp;
979 daddr_t lookup();
980
981 rewind(tfile);
982 for (;;) {
983 if ((seekp = lookup(arg)) < 0)
555a248b 984 return (1);
415c8aef
BJ
985 fseek(tfile, seekp, 0);
986 fscanf(tfile, "%s %lo", name, &mtime);
555a248b 987 return (stbuf.st_mtime > mtime);
415c8aef
BJ
988 }
989}
990
991done(n)
992{
1e5bf3dc 993 unlink(tname);
415c8aef
BJ
994 exit(n);
995}
996
45a92ce3
JL
997/*
998 * Does s2 begin with the string s1, on a directory boundary?
999 */
415c8aef 1000prefix(s1, s2)
555a248b 1001 register char *s1, *s2;
415c8aef
BJ
1002{
1003 while (*s1)
1004 if (*s1++ != *s2++)
555a248b 1005 return (0);
415c8aef 1006 if (*s2)
555a248b
BJ
1007 return (*s2 == '/');
1008 return (1);
415c8aef
BJ
1009}
1010
415c8aef
BJ
1011#define N 200
1012int njab;
555a248b 1013
415c8aef
BJ
1014daddr_t
1015lookup(s)
555a248b 1016 char *s;
415c8aef
BJ
1017{
1018 register i;
1019 daddr_t a;
1020
1021 for(i=0; s[i]; i++)
555a248b 1022 if (s[i] == ' ')
415c8aef
BJ
1023 break;
1024 a = bsrch(s, i, low, high);
555a248b 1025 return (a);
415c8aef
BJ
1026}
1027
1028daddr_t
1029bsrch(s, n, l, h)
555a248b
BJ
1030 daddr_t l, h;
1031 char *s;
415c8aef
BJ
1032{
1033 register i, j;
1034 char b[N];
1035 daddr_t m, m1;
1036
1037 njab = 0;
1038
1039loop:
555a248b 1040 if (l >= h)
45a92ce3 1041 return ((daddr_t) -1);
415c8aef 1042 m = l + (h-l)/2 - N/2;
555a248b 1043 if (m < l)
415c8aef
BJ
1044 m = l;
1045 fseek(tfile, m, 0);
1046 fread(b, 1, N, tfile);
1047 njab++;
1048 for(i=0; i<N; i++) {
555a248b 1049 if (b[i] == '\n')
415c8aef
BJ
1050 break;
1051 m++;
1052 }
555a248b 1053 if (m >= h)
45a92ce3 1054 return ((daddr_t) -1);
415c8aef
BJ
1055 m1 = m;
1056 j = i;
1057 for(i++; i<N; i++) {
1058 m1++;
555a248b 1059 if (b[i] == '\n')
415c8aef
BJ
1060 break;
1061 }
1062 i = cmp(b+j, s, n);
555a248b 1063 if (i < 0) {
415c8aef
BJ
1064 h = m;
1065 goto loop;
1066 }
555a248b 1067 if (i > 0) {
415c8aef
BJ
1068 l = m1;
1069 goto loop;
1070 }
555a248b 1071 return (m);
415c8aef
BJ
1072}
1073
1074cmp(b, s, n)
555a248b 1075 char *b, *s;
415c8aef
BJ
1076{
1077 register i;
1078
555a248b 1079 if (b[0] != '\n')
1e5bf3dc 1080 exit(2);
415c8aef 1081 for(i=0; i<n; i++) {
555a248b
BJ
1082 if (b[i+1] > s[i])
1083 return (-1);
1084 if (b[i+1] < s[i])
1085 return (1);
415c8aef 1086 }
555a248b 1087 return (b[i+1] == ' '? 0 : -1);
415c8aef
BJ
1088}
1089
45a92ce3 1090readtape(buffer)
555a248b 1091 char *buffer;
1e5bf3dc
KD
1092{
1093 char *bufp;
1e5bf3dc 1094
45a92ce3
JL
1095 if (first == 0)
1096 getbuf();
1097 readtbuf(&bufp, TBLOCK);
1e5bf3dc
KD
1098 bcopy(bufp, buffer, TBLOCK);
1099 return(TBLOCK);
1100}
1101
1102readtbuf(bufpp, size)
1103 char **bufpp;
1104 int size;
415c8aef 1105{
06eff236 1106 register int i;
415c8aef
BJ
1107
1108 if (recno >= nblock || first == 0) {
8678ae71 1109 if ((i = bread(mt, tbuf, TBLOCK*nblock)) < 0) {
095da6e7 1110 fprintf(stderr, "tar: tape read error\n");
415c8aef
BJ
1111 done(3);
1112 }
1113 if (first == 0) {
1114 if ((i % TBLOCK) != 0) {
095da6e7 1115 fprintf(stderr, "tar: tape blocksize error\n");
415c8aef
BJ
1116 done(3);
1117 }
1118 i /= TBLOCK;
06eff236 1119 if (i != nblock) {
095da6e7 1120 fprintf(stderr, "tar: blocksize = %d\n", i);
415c8aef
BJ
1121 nblock = i;
1122 }
75115c46 1123 first = 1;
415c8aef
BJ
1124 }
1125 recno = 0;
1126 }
1e5bf3dc
KD
1127 if (size > ((nblock-recno)*TBLOCK))
1128 size = (nblock-recno)*TBLOCK;
1129 *bufpp = (char *)&tbuf[recno];
1130 recno += (size/TBLOCK);
1131 return (size);
415c8aef
BJ
1132}
1133
1e5bf3dc
KD
1134writetbuf(buffer, n)
1135 register char *buffer;
1136 register int n;
415c8aef 1137{
45a92ce3
JL
1138
1139 if (first == 0) {
75115c46
KD
1140 getbuf();
1141 first = 1;
1142 }
415c8aef 1143 if (recno >= nblock) {
45a92ce3
JL
1144 if (write(mt, tbuf, TBLOCK*nblock) < 0) {
1145 fprintf(stderr,"tar: tape write error\n");
415c8aef
BJ
1146 done(2);
1147 }
1148 recno = 0;
1149 }
1e5bf3dc
KD
1150
1151 /*
1152 * Special case: We have an empty tape buffer, and the
1153 * users data size is >= the tape block size: Avoid
1154 * the bcopy and dma direct to tape. BIG WIN. Add the
1155 * residual to the tape buffer.
1156 */
1157 while (recno == 0 && n >= nblock) {
1158 if (write(mt, buffer, TBLOCK*nblock) < 0) {
45a92ce3 1159 fprintf(stderr,"tar: tape write error\n");
415c8aef
BJ
1160 done(2);
1161 }
1e5bf3dc
KD
1162 n -= nblock;
1163 buffer += (nblock * TBLOCK);
415c8aef 1164 }
1e5bf3dc
KD
1165
1166 while (n-- > 0) {
1167 bcopy(buffer, (char *)&tbuf[recno++], TBLOCK);
1168 buffer += TBLOCK;
1169 if (recno >= nblock) {
1170 if (write(mt, tbuf, TBLOCK*nblock) < 0) {
75115c46
KD
1171 fprintf(stderr,"tar: tape write error\n");
1172 done(2);
1e5bf3dc
KD
1173 }
1174 recno = 0;
1175 }
1176 }
1177
1178 /* Tell the user how much to write to get in sync */
1179 return (nblock - recno);
415c8aef
BJ
1180}
1181
1182backtape()
1183{
06eff236 1184 static struct mtop mtop = {MTBSR, 1};
06eff236 1185
06eff236
BJ
1186 if (mtdev == 0) {
1187 if (ioctl(mt, MTIOCTOP, &mtop) < 0) {
095da6e7 1188 fprintf(stderr, "tar: tape backspace error\n");
415c8aef
BJ
1189 done(4);
1190 }
06eff236 1191 } else
45a92ce3 1192 lseek(mt, (daddr_t) -TBLOCK*nblock, 1);
06eff236 1193 recno--;
415c8aef
BJ
1194}
1195
1196flushtape()
1197{
1e5bf3dc 1198 write(mt, tbuf, TBLOCK*nblock);
415c8aef
BJ
1199}
1200
8678ae71
KM
1201bread(fd, buf, size)
1202 int fd;
1203 char *buf;
1204 int size;
1205{
1206 int count;
1207 static int lastread = 0;
1208
45a92ce3
JL
1209 if (!Bflag)
1210 return (read(fd, buf, size));
75115c46 1211
8678ae71 1212 for (count = 0; count < size; count += lastread) {
8c526af6
KM
1213 lastread = read(fd, buf, size - count);
1214 if (lastread <= 0) {
8678ae71
KM
1215 if (count > 0)
1216 return (count);
1217 return (lastread);
1218 }
8678ae71
KM
1219 buf += lastread;
1220 }
1221 return (count);
1222}
5ee3622a
SL
1223
1224char *
1225getcwd(buf)
1226 char *buf;
1227{
5ee3622a
SL
1228 if (getwd(buf) == NULL) {
1229 fprintf(stderr, "tar: %s\n", buf);
1e5bf3dc 1230 exit(1);
5ee3622a
SL
1231 }
1232 return (buf);
1233}
ed4dfcb6
KD
1234
1235getbuf()
1236{
75115c46 1237
45a92ce3 1238 if (mtdev == 1) {
ed4dfcb6
KD
1239 fstat(mt, &stbuf);
1240 if ((stbuf.st_mode & S_IFMT) == S_IFCHR)
1241 mtdev = 0;
1242 else
1243 mtdev = -1;
1244 }
45a92ce3 1245 if (nblock == 0) {
ed4dfcb6
KD
1246 if (mtdev == 0)
1247 nblock = FILEBLOCK;
1248 else {
1249 fstat(mt, &stbuf);
1250 nblock = stbuf.st_blocks / TBLOCK;
1251 }
1252 }
45a92ce3
JL
1253 if (nblock == 0)
1254 nblock = FILEBLOCK;
ed4dfcb6
KD
1255 tbuf = (union hblock *)malloc(nblock*TBLOCK);
1256 if (tbuf == NULL) {
1257 fprintf(stderr, "tar: blocksize %d too big, can't get memory\n",
1258 nblock);
1259 done(1);
1260 }
1261}
75115c46 1262
45a92ce3
JL
1263/*
1264 * We are really keeping a directory stack, but since all the
1265 * elements of it share a common prefix, we can make do with one
1266 * string. We keep only the current directory path, with an associated
1267 * array of mtime's, one for each '/' in the path. A negative mtime
1268 * means no mtime. The mtime's are offset by one (first index 1, not
1269 * 0) because calling this with the null string causes mtime[0] to be set.
1270 *
1271 * This stack algorithm is not guaranteed to work for tapes created
1272 * with the 'r' option, but the vast majority of tapes with
1273 * directories are not. This avoids saving every directory record on
1274 * the tape and setting all the times at the end.
1275 */
1276char dirstack[NAMSIZ];
1277#define NTIM (NAMSIZ/2+1) /* a/b/c/d/... */
1278time_t mtime[NTIM];
75115c46 1279
45a92ce3
JL
1280dodirtimes(hp)
1281 union hblock *hp;
75115c46 1282{
45a92ce3
JL
1283 register char *p = dirstack;
1284 register char *q = hp->dbuf.name;
1285 register int ndir = 0;
1286 char *savp;
1287 int savndir;
1288
1289 /* Find common prefix */
1290 while (*p == *q) {
1291 if (*p++ == '/')
1292 ++ndir;
1293 q++;
1294 }
75115c46 1295
45a92ce3
JL
1296 savp = p;
1297 savndir = ndir;
1298 while (*p) {
1299 /*
1300 * Not a child: unwind the stack, setting the times.
1301 * The order we do this doesn't matter, so we go "forward."
1302 */
1303 if (*p++ == '/')
1304 if (mtime[++ndir] >= 0) {
1305 *--p = '\0'; /* zap the slash */
1306 setimes(dirstack, mtime[ndir]);
1307 *p++ = '/';
1308 }
1309 }
1310 p = savp;
1311 ndir = savndir;
1312
1313 /* Push this one on the "stack" */
1314 while (*p = *q++) /* append the rest of the new dir */
1315 if (*p++ == '/')
1316 mtime[++ndir] = -1;
1317 mtime[ndir] = stbuf.st_mtime; /* overwrite the last one */
1318}
75115c46 1319
45a92ce3
JL
1320setimes(path, mt)
1321 char *path;
1322 time_t mt;
1323{
1324 struct timeval tv[2];
1325
1326 tv[0].tv_sec = time((time_t *) 0);
1327 tv[1].tv_sec = mt;
1328 tv[0].tv_usec = tv[1].tv_usec = 0;
1329 if (utimes(path, tv) < 0)
1330 fprintf(stderr, "tar: can't set time on %s\n", path);
1331}
1332
1333char *
1334getmem(size)
1335{
1336 char *p = malloc((unsigned) size);
1337
1338 if (p == NULL && freemem) {
1339 fprintf(stderr,
1340 "tar: out of memory, link and directory modtime info lost\n");
1341 freemem = 0;
75115c46 1342 }
45a92ce3 1343 return (p);
75115c46 1344}