|
|
1.1 root 1: # This is a shell archive. Remove anything before this line, then unpack
2: # it by saving it into a file and typing "sh file". To overwrite existing
3: # files, type "sh file -c". You can also feed this as standard input via
4: # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
5: # will see the following message at the end:
6: # "End of archive 3 (of 6)."
7: # Contents: fileio.c namelist.c pax.c pax.h tar.c
8: # Wrapped by mark@jhereg on Tue Dec 27 19:37:45 1988
9: PATH=/bin:/usr/bin:/usr/ucb ; export PATH
10: if test -f fileio.c -a "${1}" != "-c" ; then
11: echo shar: Will not over-write existing file \"fileio.c\"
12: else
13: echo shar: Extracting \"fileio.c\" \(10596 characters\)
14: sed "s/^X//" >fileio.c <<'END_OF_fileio.c'
15: X/* $Source: /u/mark/src/pax/RCS/fileio.c,v $
16: X *
17: X * $Revision: 1.1 $
18: X *
19: X * fileio.c - file I/O functions for all archive interfaces
20: X *
21: X * DESCRIPTION
22: X *
23: X * These function all do I/O of some form or another. They are
24: X * grouped here mainly for convienence.
25: X *
26: X * AUTHOR
27: X *
28: X * Mark H. Colburn, NAPS International ([email protected])
29: X *
30: X * Sponsored by The USENIX Association for public distribution.
31: X *
32: X * Copyright (c) 1989 Mark H. Colburn.
33: X * All rights reserved.
34: X *
35: X * Redistribution and use in source and binary forms are permitted
36: X * provided that the above copyright notice is duplicated in all such
37: X * forms and that any documentation, advertising materials, and other
38: X * materials related to such distribution and use acknowledge that the
39: X * software was developed * by Mark H. Colburn and sponsored by The
40: X * USENIX Association.
41: X *
42: X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
43: X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
44: X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
45: X *
46: X * $Log: fileio.c,v $
47: X * Revision 1.1 88/12/23 18:02:09 mark
48: X * Initial revision
49: X *
50: X */
51: X
52: X#ifndef lint
53: Xstatic char *ident = "$Id: fileio.c,v 1.1 88/12/23 18:02:09 mark Rel $";
54: Xstatic char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n";
55: X#endif /* ! lint */
56: X
57: X
58: X/* Headers */
59: X
60: X#include "pax.h"
61: X
62: X
63: X/* open_archive - open an archive file.
64: X *
65: X * DESCRIPTION
66: X *
67: X * Open_archive will open an archive file for reading or writing,
68: X * setting the proper file mode, depending on the "mode" passed to
69: X * it. All buffer pointers are reset according to the mode
70: X * specified.
71: X *
72: X * PARAMETERS
73: X *
74: X * int mode - specifies whether we are reading or writing.
75: X *
76: X * RETURNS
77: X *
78: X * Returns a zero if successfull, or -1 if an error occured during
79: X * the open.
80: X */
81: X
82: X#ifdef __STDC__
83: X
84: Xint open_archive(int mode)
85: X
86: X#else
87: X
88: Xint open_archive(mode)
89: Xint mode;
90: X
91: X#endif
92: X{
93: X if (ar_file[0] == '-' && ar_file[1] == '\0') {
94: X if (mode == AR_READ) {
95: X archivefd = STDIN;
96: X bufend = bufidx = bufstart;
97: X } else {
98: X archivefd = STDOUT;
99: X }
100: X } else if (mode == AR_READ) {
101: X archivefd = open(ar_file, O_RDONLY | O_BINARY);
102: X bufend = bufidx = bufstart; /* set up for initial read */
103: X } else if (mode == AR_WRITE) {
104: X archivefd = open(ar_file, O_WRONLY|O_TRUNC|O_CREAT|O_BINARY, 0666);
105: X } else if (mode == AR_APPEND) {
106: X archivefd = open(ar_file, O_RDWR | O_BINARY, 0666);
107: X bufend = bufidx = bufstart; /* set up for initial read */
108: X }
109: X
110: X if (archivefd < 0) {
111: X warnarch(syserr(), (OFFSET) 0);
112: X return (-1);
113: X }
114: X ++arvolume;
115: X return (0);
116: X}
117: X
118: X
119: X/* close_archive - close the archive file
120: X *
121: X * DESCRIPTION
122: X *
123: X * Closes the current archive and resets the archive end of file
124: X * marker.
125: X */
126: X
127: X#ifdef __STDC__
128: X
129: Xvoid close_archive(void)
130: X
131: X#else
132: X
133: Xvoid close_archive()
134: X
135: X#endif
136: X{
137: X if (archivefd != STDIN && archivefd != STDOUT) {
138: X close(archivefd);
139: X }
140: X areof = 0;
141: X}
142: X
143: X
144: X/* openo - open an output file
145: X *
146: X * DESCRIPTION
147: X *
148: X * Openo opens the named file for output. The file mode and type are
149: X * set based on the values stored in the stat structure for the file.
150: X * If the file is a special file, then no data will be written, the
151: X * file/directory/Fifo, etc., will just be created. Appropriate
152: X * permission may be required to create special files.
153: X *
154: X * PARAMETERS
155: X *
156: X * char *name - The name of the file to create
157: X * Stat *asb - Stat structure for the file
158: X * Link *linkp; - pointer to link chain for this file
159: X * int ispass - true if we are operating in "pass" mode
160: X *
161: X * RETURNS
162: X *
163: X * Returns the output file descriptor, 0 if no data is required or -1
164: X * if unsuccessful. Note that UNIX open() will never return 0 because
165: X * the standard input is in use.
166: X */
167: X
168: X#ifdef __STDC__
169: X
170: Xint openo(char *name, Stat *asb, Link *linkp, int ispass)
171: X
172: X#else
173: X
174: Xint openo(name, asb, linkp, ispass)
175: Xchar *name;
176: XStat *asb;
177: XLink *linkp;
178: Xint ispass;
179: X
180: X#endif
181: X{
182: X int exists;
183: X int fd;
184: X ushort perm;
185: X ushort operm = 0;
186: X Stat osb;
187: X#ifdef S_IFLNK
188: X int ssize;
189: X char sname[PATH_MAX + 1];
190: X#endif /* S_IFLNK */
191: X
192: X if (exists = (LSTAT(name, &osb) == 0)) {
193: X if (ispass && osb.sb_ino == asb->sb_ino && osb.sb_dev == asb->sb_dev) {
194: X warn(name, "Same file");
195: X return (-1);
196: X } else if ((osb.sb_mode & S_IFMT) == (asb->sb_mode & S_IFMT)) {
197: X operm = osb.sb_mode & S_IPERM;
198: X } else if (REMOVE(name, &osb) < 0) {
199: X warn(name, syserr());
200: X return (-1);
201: X } else {
202: X exists = 0;
203: X }
204: X }
205: X if (linkp) {
206: X if (exists) {
207: X if (asb->sb_ino == osb.sb_ino && asb->sb_dev == osb.sb_dev) {
208: X return (0);
209: X } else if (unlink(name) < 0) {
210: X warn(name, syserr());
211: X return (-1);
212: X } else {
213: X exists = 0;
214: X }
215: X }
216: X if (link(linkp->l_name, name) != 0) {
217: X if (errno == ENOENT) {
218: X if (f_create_dirs) {
219: X if (dirneed(name) != 0 ||
220: X link(linkp->l_name, name) != 0) {
221: X warn(name, syserr());
222: X return (-1);
223: X }
224: X } else {
225: X warn(name,
226: X "Directories are not being created (-d option)");
227: X }
228: X return(0);
229: X } else if (errno != EXDEV) {
230: X warn(name, syserr());
231: X return (-1);
232: X }
233: X } else {
234: X return(0);
235: X }
236: X }
237: X perm = asb->sb_mode & S_IPERM;
238: X switch (asb->sb_mode & S_IFMT) {
239: X case S_IFBLK:
240: X case S_IFCHR:
241: X fd = 0;
242: X if (exists) {
243: X if (asb->sb_rdev == osb.sb_rdev) {
244: X if (perm != operm && chmod(name, (int) perm) < 0) {
245: X warn(name, syserr());
246: X return (-1);
247: X } else {
248: X break;
249: X }
250: X } else if (REMOVE(name, &osb) < 0) {
251: X warn(name, syserr());
252: X return (-1);
253: X } else {
254: X exists = 0;
255: X }
256: X }
257: X if (mknod(name, (int) asb->sb_mode, (int) asb->sb_rdev) < 0) {
258: X if (errno == ENOENT) {
259: X if (f_create_dirs) {
260: X if (dirneed(name) < 0 || mknod(name, (int) asb->sb_mode,
261: X (int) asb->sb_rdev) < 0) {
262: X warn(name, syserr());
263: X return (-1);
264: X }
265: X } else {
266: X warn(name, "Directories are not being created (-d option)");
267: X }
268: X } else {
269: X warn(name, syserr());
270: X return (-1);
271: X }
272: X }
273: X return(0);
274: X break;
275: X case S_IFDIR:
276: X if (exists) {
277: X if (perm != operm && chmod(name, (int) perm) < 0) {
278: X warn(name, syserr());
279: X return (-1);
280: X }
281: X } else if (f_create_dirs) {
282: X if (dirmake(name, asb) < 0 || dirneed(name) < 0) {
283: X warn(name, syserr());
284: X return (-1);
285: X }
286: X } else {
287: X warn(name, "Directories are not being created (-d option)");
288: X }
289: X return (0);
290: X#ifdef S_IFIFO
291: X case S_IFIFO:
292: X fd = 0;
293: X if (exists) {
294: X if (perm != operm && chmod(name, (int) perm) < 0) {
295: X warn(name, syserr());
296: X return (-1);
297: X }
298: X } else if (mknod(name, (int) asb->sb_mode, 0) < 0) {
299: X if (errno == ENOENT) {
300: X if (f_create_dirs) {
301: X if (dirneed(name) < 0
302: X || mknod(name, (int) asb->sb_mode, 0) < 0) {
303: X warn(name, syserr());
304: X return (-1);
305: X }
306: X } else {
307: X warn(name, "Directories are not being created (-d option)");
308: X }
309: X } else {
310: X warn(name, syserr());
311: X return (-1);
312: X }
313: X }
314: X return(0);
315: X break;
316: X#endif /* S_IFIFO */
317: X#ifdef S_IFLNK
318: X case S_IFLNK:
319: X if (exists) {
320: X if ((ssize = readlink(name, sname, sizeof(sname))) < 0) {
321: X warn(name, syserr());
322: X return (-1);
323: X } else if (strncmp(sname, asb->sb_link, ssize) == 0) {
324: X return (0);
325: X } else if (REMOVE(name, &osb) < 0) {
326: X warn(name, syserr());
327: X return (-1);
328: X } else {
329: X exists = 0;
330: X }
331: X }
332: X if (symlink(asb->sb_link, name) < 0) {
333: X if (errno == ENOENT) {
334: X if (f_create_dirs) {
335: X if (dirneed(name) < 0 || symlink(asb->sb_link, name) < 0) {
336: X warn(name, syserr());
337: X return (-1);
338: X }
339: X } else {
340: X warn(name, "Directories are not being created (-d option)");
341: X }
342: X } else {
343: X warn(name, syserr());
344: X return (-1);
345: X }
346: X }
347: X return (0); /* Can't chown()/chmod() a symbolic link */
348: X#endif /* S_IFLNK */
349: X case S_IFREG:
350: X if (exists) {
351: X if (!f_unconditional && osb.sb_mtime > asb->sb_mtime) {
352: X warn(name, "Newer file exists");
353: X return (-1);
354: X } else if (unlink(name) < 0) {
355: X warn(name, syserr());
356: X return (-1);
357: X } else {
358: X exists = 0;
359: X }
360: X }
361: X if ((fd = creat(name, (int) perm)) < 0) {
362: X if (errno == ENOENT) {
363: X if (f_create_dirs) {
364: X if (dirneed(name) < 0 ||
365: X (fd = creat(name, (int) perm)) < 0) {
366: X warn(name, syserr());
367: X return (-1);
368: X }
369: X } else {
370: X /*
371: X * the file requires a directory which does not exist
372: X * and which the user does not want created, so skip
373: X * the file...
374: X */
375: X warn(name, "Directories are not being created (-d option)");
376: X return(0);
377: X }
378: X } else {
379: X warn(name, syserr());
380: X return (-1);
381: X }
382: X }
383: X break;
384: X default:
385: X warn(name, "Unknown filetype");
386: X return (-1);
387: X }
388: X if (f_owner) {
389: X if (!exists || asb->sb_uid != osb.sb_uid || asb->sb_gid != osb.sb_gid) {
390: X chown(name, (int) asb->sb_uid, (int) asb->sb_gid);
391: X }
392: X }
393: X return (fd);
394: X}
395: X
396: X
397: X/* openi - open the next input file
398: X *
399: X * DESCRIPTION
400: X *
401: X * Openi will attempt to open the next file for input. If the file is
402: X * a special file, such as a directory, FIFO, link, character- or
403: X * block-special file, then the file size field of the stat structure
404: X * is zeroed to make sure that no data is written out for the file.
405: X * If the file is a special file, then a file descriptor of 0 is
406: X * returned to the caller, which is handled specially. If the file
407: X * is a regular file, then the file is opened and a file descriptor
408: X * to the open file is returned to the caller.
409: X *
410: X * PARAMETERS
411: X *
412: X * char *name - pointer to the name of the file to open
413: X * Stat *asb - pointer to the stat block for the file to open
414: X *
415: X * RETURNS
416: X *
417: X * Returns a file descriptor, 0 if no data exists, or -1 at EOF. This
418: X * kludge works because standard input is in use, preventing open() from
419: X * returning zero.
420: X */
421: X
422: X#ifdef __STDC__
423: X
424: Xint openi(char *name, Stat *asb)
425: X
426: X#else
427: X
428: Xint openi(name, asb)
429: Xchar *name; /* name of file to open */
430: XStat *asb; /* pointer to stat structure for file */
431: X
432: X#endif
433: X{
434: X int fd;
435: X
436: X switch (asb->sb_mode & S_IFMT) {
437: X case S_IFDIR:
438: X asb->sb_nlink = 1;
439: X asb->sb_size = 0;
440: X return (0);
441: X#ifdef S_IFLNK
442: X case S_IFLNK:
443: X if ((asb->sb_size = readlink(name,
444: X asb->sb_link, sizeof(asb->sb_link) - 1)) < 0) {
445: X warn(name, syserr());
446: X return(0);
447: X }
448: X asb->sb_link[asb->sb_size] = '\0';
449: X return (0);
450: X#endif /* S_IFLNK */
451: X case S_IFREG:
452: X if (asb->sb_size == 0) {
453: X return (0);
454: X }
455: X if ((fd = open(name, O_RDONLY | O_BINARY)) < 0) {
456: X warn(name, syserr());
457: X }
458: X return (fd);
459: X default:
460: X asb->sb_size = 0;
461: X return (0);
462: X }
463: X}
464: END_OF_fileio.c
465: if test 10596 -ne `wc -c <fileio.c`; then
466: echo shar: \"fileio.c\" unpacked with wrong size!
467: fi
468: # end of overwriting check
469: fi
470: if test -f namelist.c -a "${1}" != "-c" ; then
471: echo shar: Will not over-write existing file \"namelist.c\"
472: else
473: echo shar: Extracting \"namelist.c\" \(11056 characters\)
474: sed "s/^X//" >namelist.c <<'END_OF_namelist.c'
475: X/* $Source: /u/mark/src/pax/RCS/namelist.c,v $
476: X *
477: X * $Revision: 1.1 $
478: X *
479: X * namelist.c - track filenames given as arguments to tar/cpio/pax
480: X *
481: X * DESCRIPTION
482: X *
483: X * Arguments may be regular expressions, therefore all agurments will
484: X * be treated as if they were regular expressions, even if they are
485: X * not.
486: X *
487: X * AUTHOR
488: X *
489: X * Mark H. Colburn, NAPS International ([email protected])
490: X *
491: X * Sponsored by The USENIX Association for public distribution.
492: X *
493: X * Copyright (c) 1989 Mark H. Colburn.
494: X * All rights reserved.
495: X *
496: X * Redistribution and use in source and binary forms are permitted
497: X * provided that the above copyright notice is duplicated in all such
498: X * forms and that any documentation, advertising materials, and other
499: X * materials related to such distribution and use acknowledge that the
500: X * software was developed * by Mark H. Colburn and sponsored by The
501: X * USENIX Association.
502: X *
503: X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
504: X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
505: X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
506: X *
507: X * $Log: namelist.c,v $
508: X * Revision 1.1 88/12/23 18:02:17 mark
509: X * Initial revision
510: X *
511: X */
512: X
513: X#ifndef lint
514: Xstatic char *ident = "$Id: namelist.c,v 1.1 88/12/23 18:02:17 mark Rel $";
515: Xstatic char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n";
516: X#endif /* ! lint */
517: X
518: X
519: X/* Headers */
520: X
521: X#include "pax.h"
522: X
523: X
524: X/* Type Definitions */
525: X
526: X/*
527: X * Structure for keeping track of filenames and lists thereof.
528: X */
529: Xstruct nm_list {
530: X struct nm_list *next;
531: X short length; /* cached strlen(name) */
532: X char found; /* A matching file has been found */
533: X char firstch; /* First char is literally matched */
534: X char regexp; /* regexp pattern for item */
535: X char name[1]; /* name of file or rexexp */
536: X};
537: X
538: Xstruct dirinfo {
539: X char dirname[PATH_MAX + 1]; /* name of directory */
540: X OFFSET where; /* current location in directory */
541: X struct dirinfo *next;
542: X};
543: X
544: X
545: X/* Function Prototypes */
546: X
547: X#ifndef __STDC__
548: X
549: Xstatic void pushdir();
550: Xstatic struct dirinfo *popdir();
551: X
552: X#else
553: X
554: Xstatic void pushdir(struct dirinfo *info);
555: Xstatic struct dirinfo *popdir(void);
556: X
557: X#endif
558: X
559: X
560: X/* Internal Identifiers */
561: X
562: Xstatic struct nm_list *namelast; /* Points to last name in list */
563: Xstatic struct nm_list *namelist; /* Points to first name in list */
564: X
565: X
566: X/* addname - add a name to the namelist.
567: X *
568: X * DESCRIPTION
569: X *
570: X * Addname adds the name given to the name list. Memory for the
571: X * namelist structure is dynamically allocated. If the space for
572: X * the structure cannot be allocated, then the program will exit
573: X * the an out of memory error message and a non-zero return code
574: X * will be returned to the caller.
575: X *
576: X * PARAMETERS
577: X *
578: X * char *name - A pointer to the name to add to the list
579: X */
580: X
581: X#ifdef __STDC__
582: X
583: Xvoid add_name(char *name)
584: X
585: X#else
586: X
587: Xvoid add_name(name)
588: Xchar *name; /* pointer to name */
589: X
590: X#endif
591: X{
592: X int i; /* Length of string */
593: X struct nm_list *p; /* Current struct pointer */
594: X
595: X i = strlen(name);
596: X p = (struct nm_list *) malloc((unsigned) (i + sizeof(struct nm_list)));
597: X if (!p) {
598: X fatal("cannot allocate memory for namelist entry\n");
599: X }
600: X p->next = (struct nm_list *) NULL;
601: X p->length = i;
602: X strncpy(p->name, name, i);
603: X p->name[i] = '\0'; /* Null term */
604: X p->found = 0;
605: X p->firstch = isalpha(name[0]);
606: X if (strchr(name, '*') || strchr(name, '[') || strchr(name, '?')) {
607: X p->regexp = 1;
608: X }
609: X if (namelast) {
610: X namelast->next = p;
611: X }
612: X namelast = p;
613: X if (!namelist) {
614: X namelist = p;
615: X }
616: X}
617: X
618: X
619: X/* name_match - match a name from an archive with a name from the namelist
620: X *
621: X * DESCRIPTION
622: X *
623: X * Name_match attempts to find a name pointed at by p in the namelist.
624: X * If no namelist is available, then all filenames passed in are
625: X * assumed to match the filename criteria. Name_match knows how to
626: X * match names with regular expressions, etc.
627: X *
628: X * PARAMETERS
629: X *
630: X * char *p - the name to match
631: X *
632: X * RETURNS
633: X *
634: X * Returns 1 if the name is in the namelist, or no name list is
635: X * available, otherwise returns 0
636: X *
637: X */
638: X
639: X#ifdef __STDC__
640: X
641: Xint name_match(char *p)
642: X
643: X#else
644: X
645: Xint name_match(p)
646: Xchar *p;
647: X
648: X#endif
649: X{
650: X struct nm_list *nlp;
651: X int len;
652: X
653: X if ((nlp = namelist) == 0) {/* Empty namelist is easy */
654: X return (1);
655: X }
656: X len = strlen(p);
657: X for (; nlp != 0; nlp = nlp->next) {
658: X /* If first chars don't match, quick skip */
659: X if (nlp->firstch && nlp->name[0] != p[0]) {
660: X continue;
661: X }
662: X /* Regular expressions */
663: X if (nlp->regexp) {
664: X if (wildmat(nlp->name, p)) {
665: X nlp->found = 1; /* Remember it matched */
666: X return (1); /* We got a match */
667: X }
668: X continue;
669: X }
670: X /* Plain Old Strings */
671: X if (nlp->length <= len /* Archive len >= specified */
672: X && (p[nlp->length] == '\0' || p[nlp->length] == '/')
673: X && strncmp(p, nlp->name, nlp->length) == 0) {
674: X /* Name compare */
675: X nlp->found = 1; /* Remember it matched */
676: X return (1); /* We got a match */
677: X }
678: X }
679: X return (0);
680: X}
681: X
682: X
683: X/* names_notfound - print names of files in namelist that were not found
684: X *
685: X * DESCRIPTION
686: X *
687: X * Names_notfound scans through the namelist for any files which were
688: X * named, but for which a matching file was not processed by the
689: X * archive. Each of the files is listed on the standard error.
690: X *
691: X */
692: X
693: X#ifdef __STDC__
694: X
695: Xvoid names_notfound(void)
696: X
697: X#else
698: X
699: Xvoid names_notfound()
700: X
701: X#endif
702: X{
703: X struct nm_list *nlp;
704: X
705: X for (nlp = namelist; nlp != 0; nlp = nlp->next) {
706: X if (!nlp->found) {
707: X fprintf(stderr, "%s: %s not found in archive\n",
708: X myname, nlp->name);
709: X }
710: X free(nlp);
711: X }
712: X namelist = (struct nm_list *) NULL;
713: X namelast = (struct nm_list *) NULL;
714: X}
715: X
716: X
717: X/* name_init - set up to gather file names
718: X *
719: X * DESCRIPTION
720: X *
721: X * Name_init sets up the namelist pointers so that we may access the
722: X * command line arguments. At least the first item of the command
723: X * line (argv[0]) is assumed to be stripped off, prior to the
724: X * name_init call.
725: X *
726: X * PARAMETERS
727: X *
728: X * int argc - number of items in argc
729: X * char **argv - pointer to the command line arguments
730: X */
731: X
732: X#ifdef __STDC__
733: X
734: Xvoid name_init(int argc, char **argv)
735: X
736: X#else
737: X
738: Xvoid name_init(argc, argv)
739: Xint argc;
740: Xchar **argv;
741: X
742: X#endif
743: X{
744: X /* Get file names from argv, after options. */
745: X n_argc = argc;
746: X n_argv = argv;
747: X}
748: X
749: X
750: X/* name_next - get the next name from argv or the name file.
751: X *
752: X * DESCRIPTION
753: X *
754: X * Name next finds the next name which is to be processed in the
755: X * archive. If the named file is a directory, then the directory
756: X * is recursively traversed for additional file names. Directory
757: X * names and locations within the directory are kept track of by
758: X * using a directory stack. See the pushdir/popdir function for
759: X * more details.
760: X *
761: X * The names come from argv, after options or from the standard input.
762: X *
763: X * PARAMETERS
764: X *
765: X * name - a pointer to a buffer of at least MAX_PATH + 1 bytes long;
766: X * statbuf - a pointer to a stat structure
767: X *
768: X * RETURNS
769: X *
770: X * Returns -1 if there are no names left, (e.g. EOF), otherwise returns
771: X * 0
772: X */
773: X
774: X#ifdef __STDC__
775: X
776: Xint name_next(char *name, Stat *statbuf)
777: X
778: X#else
779: X
780: Xint name_next(name, statbuf)
781: Xchar *name;
782: XStat *statbuf;
783: X
784: X#endif
785: X{
786: X int err = -1;
787: X static int in_subdir = 0;
788: X static DIR *dirp;
789: X struct dirent *d;
790: X static struct dirinfo *curr_dir;
791: X int len;
792: X
793: X do {
794: X if (names_from_stdin) {
795: X if (lineget(stdin, name) < 0) {
796: X return (-1);
797: X }
798: X if (nameopt(name) < 0) {
799: X continue;
800: X }
801: X } else {
802: X if (in_subdir) {
803: X if ((d = readdir(dirp)) != NULL) {
804: X /* Skip . and .. */
805: X if (strcmp(d->d_name, ".") == 0 ||
806: X strcmp(d->d_name, "..") == 0) {
807: X continue;
808: X }
809: X if (strlen(d->d_name) +
810: X strlen(curr_dir->dirname) >= PATH_MAX) {
811: X warn("name too long", d->d_name);
812: X continue;
813: X }
814: X strcpy(name, curr_dir->dirname);
815: X strcat(name, d->d_name);
816: X } else {
817: X closedir(dirp);
818: X in_subdir--;
819: X curr_dir = popdir();
820: X if (in_subdir) {
821: X errno = 0;
822: X if ((dirp = opendir(curr_dir->dirname)) == NULL) {
823: X warn(curr_dir->dirname, "error opening directory (1)");
824: X in_subdir--;
825: X }
826: X seekdir(dirp, curr_dir->where);
827: X }
828: X continue;
829: X }
830: X } else if (optind >= n_argc) {
831: X return (-1);
832: X } else {
833: X strcpy(name, n_argv[optind++]);
834: X }
835: X }
836: X if ((err = LSTAT(name, statbuf)) < 0) {
837: X warn(name, syserr());
838: X continue;
839: X }
840: X if (!names_from_stdin && (statbuf->sb_mode & S_IFMT) == S_IFDIR) {
841: X if (in_subdir) {
842: X curr_dir->where = telldir(dirp);
843: X pushdir(curr_dir);
844: X close(dirp);
845: X }
846: X in_subdir++;
847: X
848: X /* Build new prototype name */
849: X if ((curr_dir = (struct dirinfo *)
850: X mem_get(sizeof(struct dirinfo))) == NULL) {
851: X exit(2);
852: X }
853: X strcpy(curr_dir->dirname, name);
854: X len = strlen(curr_dir->dirname);
855: X while (len >= 1 && curr_dir->dirname[len - 1] == '/') {
856: X len--; /* Delete trailing slashes */
857: X }
858: X curr_dir->dirname[len++] = '/'; /* Now add exactly one back */
859: X curr_dir->dirname[len] = '\0';/* Make sure null-terminated */
860: X
861: X errno = 0;
862: X if ((dirp = opendir(curr_dir->dirname)) == NULL) {
863: X warn(curr_dir->dirname, "error opening directory (2)");
864: X }
865: X }
866: X } while (err < 0);
867: X return (0);
868: X}
869: X
870: X
871: X/* name_gather - gather names in a list for scanning.
872: X *
873: X * DESCRIPTION
874: X *
875: X * Name_gather takes names from the command line and adds them to
876: X * the name list.
877: X *
878: X * FIXME
879: X *
880: X * We could hash the names if we really care about speed here.
881: X */
882: X
883: X#ifdef __STDC__
884: X
885: Xvoid name_gather(void)
886: X
887: X#else
888: X
889: Xvoid name_gather()
890: X
891: X#endif
892: X{
893: X while (optind < n_argc) {
894: X add_name(n_argv[optind++]);
895: X }
896: X}
897: X
898: X
899: Xstatic struct dirinfo *stack_head = NULL;
900: X
901: X
902: X/* pushdir - pushes a directory name on the directory stack
903: X *
904: X * DESCRIPTION
905: X *
906: X * The pushdir function puses the directory structure which is pointed
907: X * to by "info" onto a stack for later processing. The information
908: X * may be retrieved later with a call to popdir().
909: X *
910: X * PARAMETERS
911: X *
912: X * dirinfo *info - pointer to directory structure to save
913: X */
914: X
915: X#ifdef __STDC__
916: X
917: Xstatic void pushdir(struct dirinfo *info)
918: X
919: X#else
920: X
921: Xstatic void pushdir(info)
922: Xstruct dirinfo *info;
923: X
924: X#endif
925: X{
926: X if (stack_head == NULL) {
927: X stack_head = info;
928: X stack_head->next = NULL;
929: X } else {
930: X info->next = stack_head;
931: X stack_head = info;
932: X }
933: X}
934: X
935: X
936: X/* popdir - pop a directory structure off the directory stack.
937: X *
938: X * DESCRIPTION
939: X *
940: X * The popdir function pops the most recently pushed directory
941: X * structure off of the directory stack and returns it to the calling
942: X * function.
943: X *
944: X * RETURNS
945: X *
946: X * Returns a pointer to the most recently pushed directory structure
947: X * or NULL if the stack is empty.
948: X */
949: X
950: X#ifdef __STDC__
951: X
952: Xstatic struct dirinfo *popdir(void)
953: X
954: X#else
955: X
956: Xstatic struct dirinfo *popdir()
957: X
958: X#endif
959: X{
960: X struct dirinfo *tmp;
961: X
962: X if (stack_head == NULL) {
963: X return(NULL);
964: X } else {
965: X tmp = stack_head;
966: X stack_head = stack_head->next;
967: X }
968: X return(tmp);
969: X}
970: END_OF_namelist.c
971: if test 11056 -ne `wc -c <namelist.c`; then
972: echo shar: \"namelist.c\" unpacked with wrong size!
973: fi
974: # end of overwriting check
975: fi
976: if test -f pax.c -a "${1}" != "-c" ; then
977: echo shar: Will not over-write existing file \"pax.c\"
978: else
979: echo shar: Extracting \"pax.c\" \(13026 characters\)
980: sed "s/^X//" >pax.c <<'END_OF_pax.c'
981: X/* $Source: /u/mark/src/pax/RCS/pax.c,v $
982: X *
983: X * $Revision: 1.1 $
984: X *
985: X * DESCRIPTION
986: X *
987: X * Pax is the archiver described in IEEE P1003.2. It is an archiver
988: X * which understands both tar and cpio archives and has a new interface.
989: X *
990: X * SYNOPSIS
991: X *
992: X * pax -[cimopuvy] [-f archive] [-s replstr] [-t device] [pattern...]
993: X * pax -r [-cimopuvy] [-f archive] [-s replstr] [-t device] [pattern...]
994: X * pax -w [-adimuvy] [-b blocking] [-f archive] [-s replstr]...]
995: X * [-t device][-x format][pathname...]
996: X * pax -r -w [-ilmopuvy][-s replstr][pathname...] directory
997: X *
998: X * DESCRIPTION
999: X *
1000: X * PAX - POSIX conforming tar and cpio archive handler. This
1001: X * program implements POSIX conformant versions of tar, cpio and pax
1002: X * archive handlers for UNIX. These handlers have defined befined
1003: X * by the IEEE P1003.2 commitee.
1004: X *
1005: X * COMPILATION
1006: X *
1007: X * A number of different compile time configuration options are
1008: X * available, please see the Makefile and config.h for more details.
1009: X *
1010: X * AUTHOR
1011: X *
1012: X * Mark H. Colburn, NAPS International ([email protected])
1013: X *
1014: X *
1015: X * Sponsored by The USENIX Association for public distribution.
1016: X *
1017: X * Copyright (c) 1989 Mark H. Colburn.
1018: X * All rights reserved.
1019: X *
1020: X * Redistribution and use in source and binary forms are permitted
1021: X * provided that the above copyright notice is duplicated in all such
1022: X * forms and that any documentation, advertising materials, and other
1023: X * materials related to such distribution and use acknowledge that the
1024: X * software was developed * by Mark H. Colburn and sponsored by The
1025: X * USENIX Association.
1026: X *
1027: X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1028: X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1029: X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1030: X *
1031: X * $Log: pax.c,v $
1032: X * Revision 1.1 88/12/23 18:02:23 mark
1033: X * Initial revision
1034: X *
1035: X */
1036: X
1037: X#ifndef lint
1038: Xstatic char *ident = "$Id: pax.c,v 1.1 88/12/23 18:02:23 mark Rel $";
1039: Xstatic char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n";
1040: X#endif /* ! lint */
1041: X
1042: X
1043: X/* Headers */
1044: X
1045: X#define NO_EXTERN
1046: X#include "pax.h"
1047: X
1048: X
1049: X/* Globally Available Identifiers */
1050: X
1051: Xchar *ar_file; /* File containing name of archive */
1052: Xchar *bufend; /* End of data within archive buffer */
1053: Xchar *bufstart; /* Archive buffer */
1054: Xchar *bufidx; /* Archive buffer index */
1055: Xchar *myname; /* name of executable (argv[0]) */
1056: Xchar **n_argv; /* Argv used by name routines */
1057: Xint n_argc; /* Argc used by name routines */
1058: Xint archivefd; /* Archive file descriptor */
1059: Xint blocking; /* Size of each block, in records */
1060: Xint gid; /* Group ID */
1061: Xint head_standard; /* true if archive is POSIX format */
1062: Xint ar_interface; /* defines interface we are using */
1063: Xint ar_format; /* defines current archve format */
1064: Xint mask; /* File creation mask */
1065: Xint ttyf; /* For interactive queries */
1066: Xint uid; /* User ID */
1067: Xint names_from_stdin; /* names for files are from stdin */
1068: XOFFSET total; /* Total number of bytes transferred */
1069: Xshort f_access_time; /* Reset access times of input files */
1070: Xshort areof; /* End of input volume reached */
1071: Xshort f_create_dirs; /* Create missing directories */
1072: Xshort f_append; /* Add named files to end of archive */
1073: Xshort f_create; /* create a new archive */
1074: Xshort f_extract; /* Extract named files from archive */
1075: Xshort f_follow_links; /* follow symbolic links */
1076: Xshort f_interactive; /* Interactivly extract files */
1077: Xshort f_linksleft; /* Report on unresolved links */
1078: Xshort f_list; /* List files on the archive */
1079: Xshort f_modified; /* Don't restore modification times */
1080: Xshort f_verbose; /* Turn on verbose mode */
1081: Xshort f_link; /* link files where possible */
1082: Xshort f_owner; /* extract files as the user */
1083: Xshort f_pass; /* pass files between directories */
1084: Xshort f_newer; /* append files to archive if newer */
1085: Xshort f_disposition; /* ask for file disposition */
1086: Xshort f_reverse_match; /* Reverse sense of pattern match */
1087: Xshort f_modification_time; /* Retain file modification time */
1088: Xshort f_unconditional; /* Copy unconditionally */
1089: Xtime_t now = 0; /* Current time */
1090: Xuint arvolume; /* Volume number */
1091: Xuint blocksize = BLOCKSIZE; /* Archive block size */
1092: XFILE *msgfile; /* message outpu file stdout/stderr */
1093: XReplstr *rplhead = NULL; /* pointer to head of replstr list */
1094: XReplstr *rpltail; /* pointer to tail of replstr list */
1095: X
1096: X
1097: X/* Function Prototypes */
1098: X
1099: X#ifdef __STDC__
1100: X
1101: Xstatic void usage(void);
1102: Xstatic OFFSET pax_optsize(char *);
1103: X
1104: X#else /* !__STDC__ */
1105: X
1106: Xstatic void usage();
1107: Xstatic OFFSET pax_optsize();
1108: X
1109: X#endif /* __STDC__ */
1110: X
1111: X
1112: X/* main - main routine for handling all archive formats.
1113: X *
1114: X * DESCRIPTION
1115: X *
1116: X * Set up globals and call the proper interface as specified by the user.
1117: X *
1118: X * PARAMETERS
1119: X *
1120: X * int argc - count of user supplied arguments
1121: X * char **argv - user supplied arguments
1122: X *
1123: X * RETURNS
1124: X *
1125: X * Returns an exit code of 0 to the parent process.
1126: X */
1127: X
1128: X#ifdef __STDC__
1129: X
1130: Xint main(int argc, char **argv)
1131: X
1132: X#else
1133: X
1134: Xint main(argc, argv)
1135: Xint argc;
1136: Xchar **argv;
1137: X
1138: X#endif
1139: X{
1140: X /* strip the pathname off of the name of the executable */
1141: X if ((myname = strrchr(argv[0], '/')) != (char *)NULL) {
1142: X myname++;
1143: X } else {
1144: X myname = argv[0];
1145: X }
1146: X
1147: X /* set upt for collecting other command line arguments */
1148: X name_init(argc, argv);
1149: X
1150: X /* get all our necessary information */
1151: X mask = umask(0);
1152: X uid = getuid();
1153: X gid = getgid();
1154: X now = time((time_t *) 0);
1155: X
1156: X /* open terminal for interactive queries */
1157: X ttyf = open_tty();
1158: X
1159: X if (strcmp(myname, "tar")==0) {
1160: X do_tar(argc, argv);
1161: X } else if (strcmp(myname, "cpio")==0) {
1162: X do_cpio(argc, argv);
1163: X } else {
1164: X do_pax(argc, argv);
1165: X }
1166: X exit(0);
1167: X /* NOTREACHED */
1168: X}
1169: X
1170: X
1171: X/* do_pax - provide a PAX conformant user interface for archive handling
1172: X *
1173: X * DESCRIPTION
1174: X *
1175: X * Process the command line parameters given, doing some minimal sanity
1176: X * checking, and then launch the specified archiving functions.
1177: X *
1178: X * PARAMETERS
1179: X *
1180: X * int ac - A count of arguments in av. Should be passed argc
1181: X * from main
1182: X * char **av - A pointer to an argument list. Should be passed
1183: X * argv from main
1184: X *
1185: X * RETURNS
1186: X *
1187: X * Normally returns 0. If an error occurs, -1 is returned
1188: X * and state is set to reflect the error.
1189: X *
1190: X */
1191: X
1192: X#ifdef __STDC__
1193: X
1194: Xint do_pax(int ac, char **av)
1195: X
1196: X#else
1197: X
1198: Xint do_pax(ac, av)
1199: Xint ac; /* argument counter */
1200: Xchar **av; /* arguments */
1201: X
1202: X#endif
1203: X{
1204: X int c;
1205: X char *dirname;
1206: X Stat st;
1207: X
1208: X /* default input/output file for PAX is STDIN/STDOUT */
1209: X ar_file = "-";
1210: X
1211: X /*
1212: X * set up the flags to reflect the default pax inteface. Unfortunately
1213: X * the pax interface has several options which are completely opposite
1214: X * of the tar and/or cpio interfaces...
1215: X */
1216: X f_unconditional = 1;
1217: X f_modification_time = 1;
1218: X f_create_dirs = 1;
1219: X f_list = 1;
1220: X blocksize = 0;
1221: X blocking = 0;
1222: X ar_interface = PAX;
1223: X ar_format = TAR; /* default interface if none given for -w */
1224: X msgfile=stdout;
1225: X
1226: X while ((c = getopt(ac, av, "ab:cdf:ilmoprs:t:uvwx:y")) != EOF) {
1227: X switch (c) {
1228: X case 'a':
1229: X f_append = 1;
1230: X f_list = 0;
1231: X break;
1232: X case 'b':
1233: X if ((blocksize = pax_optsize(optarg)) == 0) {
1234: X fatal("Bad block size");
1235: X }
1236: X break;
1237: X case 'c':
1238: X f_reverse_match = 1;
1239: X break;
1240: X case 'd':
1241: X f_create_dirs = 0;
1242: X break;
1243: X case 'f':
1244: X if (blocksize == 0) {
1245: X blocking = 1;
1246: X blocksize = 1 * BLOCKSIZE;
1247: X }
1248: X ar_file = optarg;
1249: X break;
1250: X case 'i':
1251: X f_interactive = 1;
1252: X break;
1253: X case 'l':
1254: X f_link = 1;
1255: X break;
1256: X case 'm':
1257: X f_modification_time = 0;
1258: X break;
1259: X case 'o':
1260: X f_owner = 1;
1261: X break;
1262: X case 'p':
1263: X f_access_time = 1;
1264: X break;
1265: X case 'r':
1266: X if (f_create) {
1267: X f_create = 0;
1268: X f_pass = 1;
1269: X } else {
1270: X f_list = 0;
1271: X f_extract = 1;
1272: X }
1273: X msgfile=stderr;
1274: X break;
1275: X case 's':
1276: X add_replstr(optarg);
1277: X break;
1278: X case 't':
1279: X if (blocksize == 0) {
1280: X blocking = 1;
1281: X blocksize = 10 * BLOCKSIZE;
1282: X }
1283: X ar_file = optarg;
1284: X break;
1285: X case 'u':
1286: X f_unconditional = 1;
1287: X break;
1288: X case 'v':
1289: X f_verbose = 1;
1290: X break;
1291: X case 'w':
1292: X if (f_extract) {
1293: X f_extract = 0;
1294: X f_pass = 1;
1295: X } else {
1296: X f_list = 0;
1297: X f_create = 1;
1298: X }
1299: X msgfile=stderr;
1300: X break;
1301: X case 'x':
1302: X if (strcmp(optarg, "ustar") == 0) {
1303: X ar_format = TAR;
1304: X } else if (strcmp(optarg, "cpio") == 0) {
1305: X ar_format = CPIO;
1306: X } else {
1307: X usage();
1308: X }
1309: X break;
1310: X case 'y':
1311: X f_disposition = 1;
1312: X break;
1313: X default:
1314: X usage();
1315: X }
1316: X }
1317: X
1318: X if (blocksize == 0) {
1319: X blocking = 1;
1320: X blocksize = blocking * BLOCKSIZE;
1321: X }
1322: X buf_allocate((OFFSET) blocksize);
1323: X
1324: X if (f_extract || f_list) {
1325: X open_archive(AR_READ);
1326: X get_archive_type();
1327: X read_archive();
1328: X } else if (f_create) {
1329: X if (optind >= n_argc) {
1330: X names_from_stdin++; /* args from stdin */
1331: X }
1332: X open_archive(AR_WRITE);
1333: X create_archive();
1334: X } else if (f_append) {
1335: X open_archive(AR_APPEND);
1336: X get_archive_type();
1337: X append_archive();
1338: X } else if (f_pass && optind < n_argc) {
1339: X dirname = n_argv[--n_argc];
1340: X if (LSTAT(dirname, &st) < 0) {
1341: X fatal(syserr());
1342: X }
1343: X if ((st.sb_mode & S_IFMT) != S_IFDIR) {
1344: X fatal("Not a directory");
1345: X }
1346: X if (optind >= n_argc) {
1347: X names_from_stdin++; /* args from stdin */
1348: X }
1349: X pass(dirname);
1350: X } else {
1351: X usage();
1352: X }
1353: X
1354: X return (0);
1355: X}
1356: X
1357: X
1358: X/* get_archive_type - determine input archive type from archive header
1359: X *
1360: X * DESCRIPTION
1361: X *
1362: X * reads the first block of the archive and determines the archive
1363: X * type from the data. If the archive type cannot be determined,
1364: X * processing stops, and a 1 is returned to the caller. If verbose
1365: X * mode is on, then the archive type will be printed on the standard
1366: X * error device as it is determined.
1367: X *
1368: X * FIXME
1369: X *
1370: X * be able to understand TAR and CPIO magic numbers
1371: X */
1372: X
1373: X#ifdef __STDC__
1374: X
1375: Xvoid get_archive_type(void)
1376: X
1377: X#else
1378: X
1379: Xvoid get_archive_type()
1380: X
1381: X#endif
1382: X{
1383: X if (ar_read() != 0) {
1384: X fatal("Unable to determine archive type.");
1385: X }
1386: X if (strncmp(bufstart, "070707", 6) == 0) {
1387: X ar_format = CPIO;
1388: X if (f_verbose) {
1389: X fputs("CPIO format archive\n", stderr);
1390: X }
1391: X } else if (strncmp(&bufstart[257], "ustar", 5) == 0) {
1392: X ar_format = TAR;
1393: X if (f_verbose) {
1394: X fputs("USTAR format archive\n", stderr);
1395: X }
1396: X } else {
1397: X ar_format = TAR;
1398: X }
1399: X}
1400: X
1401: X
1402: X/* pax_optsize - interpret a size argument
1403: X *
1404: X * DESCRIPTION
1405: X *
1406: X * Recognizes suffixes for blocks (512-bytes), k-bytes and megabytes.
1407: X * Also handles simple expressions containing '+' for addition.
1408: X *
1409: X * PARAMETERS
1410: X *
1411: X * char *str - A pointer to the string to interpret
1412: X *
1413: X * RETURNS
1414: X *
1415: X * Normally returns the value represented by the expression in the
1416: X * the string.
1417: X *
1418: X * ERRORS
1419: X *
1420: X * If the string cannot be interpretted, the program will fail, since
1421: X * the buffering will be incorrect.
1422: X *
1423: X */
1424: X
1425: X#ifdef __STDC__
1426: X
1427: Xstatic OFFSET pax_optsize(char *str)
1428: X
1429: X#else
1430: X
1431: Xstatic OFFSET pax_optsize(str)
1432: Xchar *str; /* pointer to string to interpret */
1433: X
1434: X#endif
1435: X{
1436: X char *idx;
1437: X OFFSET number; /* temporary storage for current number */
1438: X OFFSET result; /* cumulative total to be returned to caller */
1439: X
1440: X result = 0;
1441: X idx = str;
1442: X for (;;) {
1443: X number = 0;
1444: X while (*idx >= '0' && *idx <= '9')
1445: X number = number * 10 + *idx++ - '0';
1446: X switch (*idx++) {
1447: X case 'b':
1448: X result += number * 512;
1449: X continue;
1450: X case 'k':
1451: X result += number * 1024;
1452: X continue;
1453: X case 'm':
1454: X result += number * 1024 * 1024;
1455: X continue;
1456: X case '+':
1457: X result += number;
1458: X continue;
1459: X case '\0':
1460: X result += number;
1461: X break;
1462: X default:
1463: X break;
1464: X }
1465: X break;
1466: X }
1467: X if (*--idx) {
1468: X fatal("Unrecognizable value");
1469: X }
1470: X return (result);
1471: X}
1472: X
1473: X
1474: X/* usage - print a helpful message and exit
1475: X *
1476: X * DESCRIPTION
1477: X *
1478: X * Usage prints out the usage message for the PAX interface and then
1479: X * exits with a non-zero termination status. This is used when a user
1480: X * has provided non-existant or incompatible command line arguments.
1481: X *
1482: X * RETURNS
1483: X *
1484: X * Returns an exit status of 1 to the parent process.
1485: X *
1486: X */
1487: X
1488: X#ifdef __STDC__
1489: X
1490: Xstatic void usage(void)
1491: X
1492: X#else
1493: X
1494: Xstatic void usage()
1495: X
1496: X#endif
1497: X{
1498: X fprintf(stderr, "\
1499: XUsage: %s -[cimopuvy] [-f archive] [-s replstr] [-t device] [pattern...]\n",
1500: X myname);
1501: X fprintf(stderr, "\
1502: X %s -r [-cimopuvy] [-f archive] [-s replstr] [-t device] [pattern...]\n",
1503: X myname);
1504: X fprintf(stderr, "\
1505: X %s -w [-adimuvy] [-b blocking] [-f archive] [-s replstr]\n\
1506: X [-t device] [-x format] [pathname...]\n",
1507: X myname);
1508: X fprintf(stderr, "\
1509: X %s -r -w [-ilmopuvy] [-s replstr] [pathname...] directory\n",
1510: X myname);
1511: X exit(1);
1512: X}
1513: END_OF_pax.c
1514: if test 13026 -ne `wc -c <pax.c`; then
1515: echo shar: \"pax.c\" unpacked with wrong size!
1516: fi
1517: # end of overwriting check
1518: fi
1519: if test -f pax.h -a "${1}" != "-c" ; then
1520: echo shar: Will not over-write existing file \"pax.h\"
1521: else
1522: echo shar: Extracting \"pax.h\" \(9317 characters\)
1523: sed "s/^X//" >pax.h <<'END_OF_pax.h'
1524: X/* $Source: /u/mark/src/pax/RCS/pax.h,v $
1525: X *
1526: X * $Revision: 1.1 $
1527: X *
1528: X * pax.h - defnitions for entire program
1529: X *
1530: X * DESCRIPTION
1531: X *
1532: X * This file contains most all of the definitions required by the PAX
1533: X * software. This header is included in every source file.
1534: X *
1535: X * AUTHOR
1536: X *
1537: X * Mark H. Colburn, NAPS International ([email protected])
1538: X *
1539: X * Sponsored by The USENIX Association for public distribution.
1540: X *
1541: X * Copyright (c) 1989 Mark H. Colburn.
1542: X * All rights reserved.
1543: X *
1544: X * Redistribution and use in source and binary forms are permitted
1545: X * provided that the above copyright notice and this paragraph are
1546: X * duplicated in all such forms and that any documentation,
1547: X * advertising materials, and other materials related to such
1548: X * distribution and use acknowledge that the software was developed
1549: X * by Mark H. Colburn and sponsored by The USENIX Association.
1550: X *
1551: X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1552: X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1553: X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1554: X */
1555: X
1556: X#ifndef _PAX_H
1557: X#define _PAX_H
1558: X
1559: X/* Headers */
1560: X
1561: X#include "config.h"
1562: X#include "limits.h"
1563: X#include <stdio.h>
1564: X#include <errno.h>
1565: X#include <signal.h>
1566: X#include <ctype.h>
1567: X#include <sys/types.h>
1568: X#include <sys/ioctl.h>
1569: X#include <sys/stat.h>
1570: X#include "regexp.h"
1571: X
1572: X#if defined(DIRENT) || defined(_POSIX_SOURCE)
1573: X# ifdef PAXDIR
1574: X# include "paxdir.h"
1575: X# else
1576: X# include <dirent.h>
1577: X# endif
1578: X#else
1579: X# include <sys/dir.h>
1580: X# define dirent direct
1581: X#endif
1582: X
1583: X#ifndef major
1584: X# include <sys/sysmacros.h>
1585: X#endif /* major */
1586: X
1587: X#ifdef SYSTIME
1588: X# include <sys/time.h>
1589: X#else /* SYSTIME */
1590: X# include <time.h>
1591: X#endif /* SYSTIME */
1592: X
1593: X#ifndef V7
1594: X# include <fcntl.h>
1595: X#endif
1596: X
1597: X#ifdef XENIX
1598: X# include <sys/inode.h>
1599: X#endif
1600: X
1601: X#include <pwd.h>
1602: X#include <grp.h>
1603: X#include <sys/file.h>
1604: X
1605: X/* Defines */
1606: X
1607: X#define STDIN 0 /* Standard input file descriptor */
1608: X#define STDOUT 1 /* Standard output file descriptor */
1609: X
1610: X/*
1611: X * Open modes; there is no <fcntl.h> with v7 UNIX and other versions of
1612: X * UNIX may not have all of these defined...
1613: X */
1614: X
1615: X#ifndef O_RDONLY
1616: X# define O_RDONLY 0
1617: X#endif
1618: X
1619: X#ifndef O_WRONLY
1620: X# define O_WRONLY 1
1621: X#endif
1622: X
1623: X#ifndef O_RDWR
1624: X# define O_WRONLY 2
1625: X#endif
1626: X
1627: X#ifndef O_BINARY
1628: X# define O_BINARY 0
1629: X#endif
1630: X
1631: X#ifndef NULL
1632: X# define NULL 0
1633: X#endif
1634: X
1635: X#define TMAGIC "ustar" /* ustar and a null */
1636: X#define TMAGLEN 6
1637: X#define TVERSION "00" /* 00 and no null */
1638: X#define TVERSLEN 2
1639: X
1640: X/* Values used in typeflag field */
1641: X#define REGTYPE '0' /* Regular File */
1642: X#define AREGTYPE '\0' /* Regular File */
1643: X#define LNKTYPE '1' /* Link */
1644: X#define SYMTYPE '2' /* Reserved */
1645: X#define CHRTYPE '3' /* Character Special File */
1646: X#define BLKTYPE '4' /* Block Special File */
1647: X#define DIRTYPE '5' /* Directory */
1648: X#define FIFOTYPE '6' /* FIFO */
1649: X#define CONTTYPE '7' /* Reserved */
1650: X
1651: X#define BLOCKSIZE 512 /* all output is padded to 512 bytes */
1652: X#define uint unsigned int /* Not always in types.h */
1653: X#define ushort unsigned short /* Not always in types.h */
1654: X#define BLOCK 5120 /* Default archive block size */
1655: X#define H_COUNT 10 /* Number of items in ASCII header */
1656: X#define H_PRINT "%06o%06o%06o%06o%06o%06o%06o%011lo%06o%011lo"
1657: X#define H_SCAN "%6ho%6ho%6ho%6ho%6ho%6ho%6ho%11lo%6o%11lo"
1658: X#define H_STRLEN 70 /* ASCII header string length */
1659: X#define M_ASCII "070707" /* ASCII magic number */
1660: X#define M_BINARY 070707 /* Binary magic number */
1661: X#define M_STRLEN 6 /* ASCII magic number length */
1662: X#define PATHELEM 256 /* Pathname element count limit */
1663: X#define S_IFSHF 12 /* File type shift (shb in stat.h) */
1664: X#define S_IPERM 07777 /* File permission bits (shb in stat.h) */
1665: X#define S_IPEXE 07000 /* Special execution bits (shb in stat.h) */
1666: X#define S_IPOPN 0777 /* Open access bits (shb in stat.h) */
1667: X
1668: X/*
1669: X * Trailer pathnames. All must be of the same length.
1670: X */
1671: X#define TRAILER "TRAILER!!!" /* Archive trailer (cpio compatible) */
1672: X#define TRAILZ 11 /* Trailer pathname length (including null) */
1673: X
1674: X#include "port.h"
1675: X
1676: X
1677: X#define TAR 1
1678: X#define CPIO 2
1679: X#define PAX 3
1680: X
1681: X#define AR_READ 0
1682: X#define AR_WRITE 1
1683: X#define AR_EXTRACT 2
1684: X#define AR_APPEND 4
1685: X
1686: X/*
1687: X * Header block on tape.
1688: X */
1689: X#define NAMSIZ 100
1690: X#define PFIXSIZ 155
1691: X#define TUNMLEN 32
1692: X#define TGNMLEN 32
1693: X
1694: X/* The checksum field is filled with this while the checksum is computed. */
1695: X#define CHKBLANKS " " /* 8 blanks, no null */
1696: X
1697: X/*
1698: X * Exit codes from the "tar" program
1699: X */
1700: X#define EX_SUCCESS 0 /* success! */
1701: X#define EX_ARGSBAD 1 /* invalid args */
1702: X#define EX_BADFILE 2 /* invalid filename */
1703: X#define EX_BADARCH 3 /* bad archive */
1704: X#define EX_SYSTEM 4 /* system gave unexpected error */
1705: X
1706: X#define ROUNDUP(a,b) (((a) % (b)) == 0 ? (a) : ((a) + ((b) - ((a) % (b)))))
1707: X
1708: X/*
1709: X * Mininum value.
1710: X */
1711: X#define MIN(a, b) (((a) < (b)) ? (a) : (b))
1712: X
1713: X/*
1714: X * Remove a file or directory.
1715: X */
1716: X#define REMOVE(name, asb) \
1717: X (((asb)->sb_mode & S_IFMT) == S_IFDIR ? rmdir(name) : unlink(name))
1718: X
1719: X/*
1720: X * Cast and reduce to unsigned short.
1721: X */
1722: X#define USH(n) (((ushort) (n)) & 0177777)
1723: X
1724: X
1725: X/* Type Definitions */
1726: X
1727: X/*
1728: X * Binary archive header (obsolete).
1729: X */
1730: Xtypedef struct {
1731: X short b_dev; /* Device code */
1732: X ushort b_ino; /* Inode number */
1733: X ushort b_mode; /* Type and permissions */
1734: X ushort b_uid; /* Owner */
1735: X ushort b_gid; /* Group */
1736: X short b_nlink; /* Number of links */
1737: X short b_rdev; /* Real device */
1738: X ushort b_mtime[2]; /* Modification time (hi/lo) */
1739: X ushort b_name; /* Length of pathname (with null) */
1740: X ushort b_size[2]; /* Length of data */
1741: X} Binary;
1742: X
1743: X/*
1744: X * File status with symbolic links. Kludged to hold symbolic link pathname
1745: X * within structure.
1746: X */
1747: Xtypedef struct {
1748: X struct stat sb_stat;
1749: X char sb_link[PATH_MAX + 1];
1750: X} Stat;
1751: X
1752: X#define STAT(name, asb) stat(name, &(asb)->sb_stat)
1753: X#define FSTAT(fd, asb) fstat(fd, &(asb)->sb_stat)
1754: X
1755: X#define sb_dev sb_stat.st_dev
1756: X#define sb_ino sb_stat.st_ino
1757: X#define sb_mode sb_stat.st_mode
1758: X#define sb_nlink sb_stat.st_nlink
1759: X#define sb_uid sb_stat.st_uid
1760: X#define sb_gid sb_stat.st_gid
1761: X#define sb_rdev sb_stat.st_rdev
1762: X#define sb_size sb_stat.st_size
1763: X#define sb_atime sb_stat.st_atime
1764: X#define sb_mtime sb_stat.st_mtime
1765: X#define sb_ctime sb_stat.st_ctime
1766: X
1767: X#ifdef S_IFLNK
1768: X# define LSTAT(name, asb) lstat(name, &(asb)->sb_stat)
1769: X# define sb_blksize sb_stat.st_blksize
1770: X# define sb_blocks sb_stat.st_blocks
1771: X#else /* S_IFLNK */
1772: X/*
1773: X * File status without symbolic links.
1774: X */
1775: X# define LSTAT(name, asb) stat(name, &(asb)->sb_stat)
1776: X#endif /* S_IFLNK */
1777: X
1778: X/*
1779: X * Hard link sources. One or more are chained from each link structure.
1780: X */
1781: Xtypedef struct name {
1782: X struct name *p_forw; /* Forward chain (terminated) */
1783: X struct name *p_back; /* Backward chain (circular) */
1784: X char *p_name; /* Pathname to link from */
1785: X} Path;
1786: X
1787: X/*
1788: X * File linking information. One entry exists for each unique file with with
1789: X * outstanding hard links.
1790: X */
1791: Xtypedef struct link {
1792: X struct link *l_forw; /* Forward chain (terminated) */
1793: X struct link *l_back; /* Backward chain (terminated) */
1794: X dev_t l_dev; /* Device */
1795: X ino_t l_ino; /* Inode */
1796: X ushort l_nlink; /* Unresolved link count */
1797: X OFFSET l_size; /* Length */
1798: X char *l_name; /* pathname to link from */
1799: X Path *l_path; /* Pathname which link to l_name */
1800: X} Link;
1801: X
1802: X/*
1803: X * Structure for ed-style replacement strings (-s option).
1804: X*/
1805: Xtypedef struct replstr {
1806: X regexp *comp; /* compiled regular expression */
1807: X char *replace; /* replacement string */
1808: X char print; /* >0 if we are to print replacement */
1809: X char global; /* >0 if we are to replace globally */
1810: X struct replstr *next; /* pointer to next record */
1811: X} Replstr;
1812: X
1813: X
1814: X/*
1815: X * This has to be included here to insure that all of the type
1816: X * delcarations are declared for the prototypes.
1817: X */
1818: X#include "func.h"
1819: X
1820: X
1821: X#ifndef NO_EXTERN
1822: X/* Globally Available Identifiers */
1823: X
1824: Xextern char *ar_file;
1825: Xextern char *bufend;
1826: Xextern char *bufstart;
1827: Xextern char *bufidx;
1828: Xextern char *myname;
1829: Xextern int archivefd;
1830: Xextern int blocking;
1831: Xextern uint blocksize;
1832: Xextern int gid;
1833: Xextern int head_standard;
1834: Xextern int ar_interface;
1835: Xextern int ar_format;
1836: Xextern int mask;
1837: Xextern int ttyf;
1838: Xextern int uid;
1839: Xextern OFFSET total;
1840: Xextern short areof;
1841: Xextern short f_append;
1842: Xextern short f_create;
1843: Xextern short f_extract;
1844: Xextern short f_follow_links;
1845: Xextern short f_interactive;
1846: Xextern short f_linksleft;
1847: Xextern short f_list;
1848: Xextern short f_modified;
1849: Xextern short f_verbose;
1850: Xextern short f_link;
1851: Xextern short f_owner;
1852: Xextern short f_access_time;
1853: Xextern short f_pass;
1854: Xextern short f_pass;
1855: Xextern short f_disposition;
1856: Xextern short f_reverse_match;
1857: Xextern short f_modification_time;
1858: Xextern short f_create_dirs;
1859: Xextern short f_unconditional;
1860: Xextern short f_newer;
1861: Xextern time_t now;
1862: Xextern uint arvolume;
1863: Xextern int names_from_stdin;
1864: Xextern Replstr *rplhead;
1865: Xextern Replstr *rpltail;
1866: Xextern char **n_argv;
1867: Xextern int n_argc;
1868: Xextern FILE *msgfile;
1869: X#endif /* NO_EXTERN */
1870: X
1871: Xextern char *optarg;
1872: Xextern int optind;
1873: Xextern int sys_nerr;
1874: Xextern char *sys_errlist[];
1875: Xextern int errno;
1876: X
1877: X#endif /* _PAX_H */
1878: END_OF_pax.h
1879: if test 9317 -ne `wc -c <pax.h`; then
1880: echo shar: \"pax.h\" unpacked with wrong size!
1881: fi
1882: # end of overwriting check
1883: fi
1884: if test -f tar.c -a "${1}" != "-c" ; then
1885: echo shar: Will not over-write existing file \"tar.c\"
1886: else
1887: echo shar: Extracting \"tar.c\" \(7881 characters\)
1888: sed "s/^X//" >tar.c <<'END_OF_tar.c'
1889: X/* $Source: /u/mark/src/pax/RCS/tar.c,v $
1890: X *
1891: X * $Revision: 1.1 $
1892: X *
1893: X * tar.c - tar specific functions for archive handling
1894: X *
1895: X * DESCRIPTION
1896: X *
1897: X * These routines provide a tar conforming interface to the pax
1898: X * program.
1899: X *
1900: X * AUTHOR
1901: X *
1902: X * Mark H. Colburn, NAPS International ([email protected])
1903: X *
1904: X * Sponsored by The USENIX Association for public distribution.
1905: X *
1906: X * Copyright (c) 1989 Mark H. Colburn.
1907: X * All rights reserved.
1908: X *
1909: X * Redistribution and use in source and binary forms are permitted
1910: X * provided that the above copyright notice is duplicated in all such
1911: X * forms and that any documentation, advertising materials, and other
1912: X * materials related to such distribution and use acknowledge that the
1913: X * software was developed by Mark H. Colburn and sponsored by The
1914: X * USENIX Association.
1915: X *
1916: X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1917: X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1918: X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1919: X *
1920: X * $Log: tar.c,v $
1921: X * Revision 1.1 88/12/23 18:02:38 mark
1922: X * Initial revision
1923: X *
1924: X */
1925: X
1926: X#ifndef lint
1927: Xstatic char *ident = "$Id: tar.c,v 1.1 88/12/23 18:02:38 mark Rel $";
1928: Xstatic char *copyright ="Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.";
1929: X#endif /* not lint */
1930: X
1931: X/* Headers */
1932: X
1933: X#include "pax.h"
1934: X
1935: X
1936: X/* Defines */
1937: X
1938: X#define DEF_BLOCKING 20 /* default blocking factor for extract */
1939: X
1940: X
1941: X/* Function Prototypes */
1942: X
1943: X#ifdef __STDC__
1944: X
1945: Xstatic int taropt(int , char **, char *);
1946: Xstatic void usage(void);
1947: X
1948: X#else /* !__STDC__ */
1949: X
1950: Xstatic int taropt();
1951: Xstatic void usage();
1952: X
1953: X#endif /* __STDC__ */
1954: X
1955: X
1956: X/* do_tar - main routine for tar.
1957: X *
1958: X * DESCRIPTION
1959: X *
1960: X * Provides a tar interface to the PAX program. All tar standard
1961: X * command line options are supported.
1962: X *
1963: X * PARAMETERS
1964: X *
1965: X * int argc - argument count (argc from main)
1966: X * char **argv - argument list (argv from main)
1967: X *
1968: X * RETURNS
1969: X *
1970: X * zero
1971: X */
1972: X
1973: X#ifdef __STDC__
1974: X
1975: Xint do_tar(int argc, char **argv)
1976: X
1977: X#else
1978: X
1979: Xint do_tar(argc, argv)
1980: Xint argc; /* argument count (argc from main) */
1981: Xchar **argv; /* argument list (argv from main) */
1982: X
1983: X#endif
1984: X{
1985: X int c; /* Option letter */
1986: X
1987: X /* Set default option values */
1988: X names_from_stdin = 0;
1989: X ar_file = getenv("TAPE"); /* From environment, or */
1990: X if (ar_file == 0) {
1991: X ar_file = DEF_AR_FILE; /* From Makefile */
1992: X }
1993: X
1994: X /*
1995: X * set up the flags to reflect the default pax inteface. Unfortunately
1996: X * the pax interface has several options which are completely opposite
1997: X * of the tar and/or cpio interfaces...
1998: X */
1999: X f_unconditional = 1;
2000: X f_modification_time = 1;
2001: X f_create_dirs = 1;
2002: X blocking = 0;
2003: X ar_interface = TAR;
2004: X ar_format = TAR;
2005: X msgfile=stdout;
2006: X
2007: X /* Parse options */
2008: X while ((c = taropt(argc, argv, "b:cf:hlmortuvwx")) != EOF) {
2009: X switch (c) {
2010: X case 'b': /* specify blocking factor */
2011: X /*
2012: X * FIXME - we should use a conversion routine that does
2013: X * some kind of reasonable error checking, but...
2014: X */
2015: X blocking = atoi(optarg);
2016: X break;
2017: X case 'c': /* create a new archive */
2018: X f_create = 1;
2019: X break;
2020: X case 'f': /* specify input/output file */
2021: X ar_file = optarg;
2022: X break;
2023: X case 'h':
2024: X f_follow_links = 1; /* follow symbolic links */
2025: X break;
2026: X case 'l': /* report unresolved links */
2027: X f_linksleft = 1;
2028: X break;
2029: X case 'm': /* don't restore modification times */
2030: X f_modified = 1;
2031: X break;
2032: X case 'o': /* take on user's group rather than
2033: X * archives */
2034: X break;
2035: X case 'r': /* named files are appended to archive */
2036: X f_append = 1;
2037: X break;
2038: X case 't':
2039: X f_list = 1; /* list files in archive */
2040: X break;
2041: X case 'u': /* named files are added to archive */
2042: X f_newer = 1;
2043: X break;
2044: X case 'v': /* verbose mode */
2045: X f_verbose = 1;
2046: X break;
2047: X case 'w': /* user interactive mode */
2048: X f_disposition = 1;
2049: X break;
2050: X case 'x': /* named files are extracted from archive */
2051: X f_extract = 1;
2052: X break;
2053: X case '?':
2054: X usage();
2055: X exit(EX_ARGSBAD);
2056: X }
2057: X }
2058: X
2059: X /* check command line argument sanity */
2060: X if (f_create + f_extract + f_list + f_append + f_newer != 1) {
2061: X (void) fprintf(stderr,
2062: X "%s: you must specify exactly one of the c, t, r, u or x options\n",
2063: X myname);
2064: X usage();
2065: X exit(EX_ARGSBAD);
2066: X }
2067: X
2068: X /* set the blocking factor, if not set by the user */
2069: X if (blocking == 0) {
2070: X#ifdef USG
2071: X if (f_extract || f_list) {
2072: X blocking = DEF_BLOCKING;
2073: X fprintf(stderr, "Tar: blocksize = %d\n", blocking);
2074: X } else {
2075: X blocking = 1;
2076: X }
2077: X#else /* !USG */
2078: X blocking = 20;
2079: X#endif /* USG */
2080: X }
2081: X blocksize = blocking * BLOCKSIZE;
2082: X buf_allocate((OFFSET) blocksize);
2083: X
2084: X if (f_create) {
2085: X open_archive(AR_WRITE);
2086: X create_archive(); /* create the archive */
2087: X } else if (f_extract) {
2088: X open_archive(AR_READ);
2089: X read_archive(); /* extract files from archive */
2090: X } else if (f_list) {
2091: X open_archive(AR_READ);
2092: X read_archive(); /* read and list contents of archive */
2093: X } else if (f_append) {
2094: X open_archive(AR_APPEND);
2095: X append_archive(); /* append files to archive */
2096: X }
2097: X
2098: X if (f_linksleft) {
2099: X linkleft(); /* report any unresolved links */
2100: X }
2101: X
2102: X return (0);
2103: X}
2104: X
2105: X
2106: X/* taropt - tar specific getopt
2107: X *
2108: X * DESCRIPTION
2109: X *
2110: X * Plug-compatible replacement for getopt() for parsing tar-like
2111: X * arguments. If the first argument begins with "-", it uses getopt;
2112: X * otherwise, it uses the old rules used by tar, dump, and ps.
2113: X *
2114: X * PARAMETERS
2115: X *
2116: X * int argc - argument count (argc from main)
2117: X * char **argv - argument list (argv from main)
2118: X * char *optstring - sring which describes allowable options
2119: X *
2120: X * RETURNS
2121: X *
2122: X * Returns the next option character in the option string(s). If the
2123: X * option requires an argument and an argument was given, the argument
2124: X * is pointed to by "optarg". If no option character was found,
2125: X * returns an EOF.
2126: X *
2127: X */
2128: X
2129: X#ifdef __STDC__
2130: X
2131: Xstatic int taropt(int argc, char **argv, char *optstring)
2132: X
2133: X#else
2134: X
2135: Xstatic int taropt(argc, argv, optstring)
2136: Xint argc;
2137: Xchar **argv;
2138: Xchar *optstring;
2139: X
2140: X#endif
2141: X{
2142: X extern char *optarg; /* Points to next arg */
2143: X extern int optind; /* Global argv index */
2144: X static char *key; /* Points to next keyletter */
2145: X static char use_getopt; /* !=0 if argv[1][0] was '-' */
2146: X char c;
2147: X char *place;
2148: X
2149: X optarg = NULL;
2150: X
2151: X if (key == NULL) { /* First time */
2152: X if (argc < 2)
2153: X return EOF;
2154: X key = argv[1];
2155: X if (*key == '-')
2156: X use_getopt++;
2157: X else
2158: X optind = 2;
2159: X }
2160: X if (use_getopt) {
2161: X return getopt(argc, argv, optstring);
2162: X }
2163: X
2164: X c = *key++;
2165: X if (c == '\0') {
2166: X key--;
2167: X return EOF;
2168: X }
2169: X place = strchr(optstring, c);
2170: X
2171: X if (place == NULL || c == ':') {
2172: X fprintf(stderr, "%s: unknown option %c\n", argv[0], c);
2173: X return ('?');
2174: X }
2175: X place++;
2176: X if (*place == ':') {
2177: X if (optind < argc) {
2178: X optarg = argv[optind];
2179: X optind++;
2180: X } else {
2181: X fprintf(stderr, "%s: %c argument missing\n",
2182: X argv[0], c);
2183: X return ('?');
2184: X }
2185: X }
2186: X return (c);
2187: X}
2188: X
2189: X
2190: X/* usage - print a helpful message and exit
2191: X *
2192: X * DESCRIPTION
2193: X *
2194: X * Usage prints out the usage message for the TAR interface and then
2195: X * exits with a non-zero termination status. This is used when a user
2196: X * has provided non-existant or incompatible command line arguments.
2197: X *
2198: X * RETURNS
2199: X *
2200: X * Returns an exit status of 1 to the parent process.
2201: X *
2202: X */
2203: X
2204: X#ifdef __STDC__
2205: X
2206: Xstatic void usage(void)
2207: X
2208: X#else
2209: X
2210: Xstatic void usage()
2211: X
2212: X#endif
2213: X{
2214: X fprintf(stderr, "\
2215: XUsage: %s -c[bfvw] device block filename..\n", myname);
2216: X fprintf(stderr, "\
2217: X %s -r[bvw] device block [filename...]\n", myname);
2218: X fprintf(stderr, "\
2219: X %s -t[vf] device\n", myname);
2220: X fprintf(stderr, "\
2221: X %s -u[bvw] device block [filename...]\n", myname);
2222: X fprintf(stderr, "\
2223: X %s -x[flmovw] device [filename...]\n", myname);
2224: X exit(1);
2225: X}
2226: END_OF_tar.c
2227: if test 7881 -ne `wc -c <tar.c`; then
2228: echo shar: \"tar.c\" unpacked with wrong size!
2229: fi
2230: # end of overwriting check
2231: fi
2232: echo shar: End of archive 3 \(of 6\).
2233: cp /dev/null ark3isdone
2234: MISSING=""
2235: for I in 1 2 3 4 5 6 ; do
2236: if test ! -f ark${I}isdone ; then
2237: MISSING="${MISSING} ${I}"
2238: fi
2239: done
2240: if test "${MISSING}" = "" ; then
2241: echo You have unpacked all 6 archives.
2242: rm -f ark[1-9]isdone
2243: else
2244: echo You still need to unpack the following archives:
2245: echo " " ${MISSING}
2246: fi
2247: ## End of shell archive.
2248: exit 0
2249:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.