xref: /plan9/sys/src/ape/cmd/pax/list.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1*9a747e4fSDavid du Colombier /* $Source: /u/mark/src/pax/RCS/list.c,v $
2*9a747e4fSDavid du Colombier  *
3*9a747e4fSDavid du Colombier  * $Revision: 1.2 $
4*9a747e4fSDavid du Colombier  *
5*9a747e4fSDavid du Colombier  * list.c - List all files on an archive
6*9a747e4fSDavid du Colombier  *
7*9a747e4fSDavid du Colombier  * DESCRIPTION
8*9a747e4fSDavid du Colombier  *
9*9a747e4fSDavid du Colombier  *	These function are needed to support archive table of contents and
10*9a747e4fSDavid du Colombier  *	verbose mode during extraction and creation of achives.
11*9a747e4fSDavid du Colombier  *
12*9a747e4fSDavid du Colombier  * AUTHOR
13*9a747e4fSDavid du Colombier  *
14*9a747e4fSDavid du Colombier  *	Mark H. Colburn, NAPS International (mark@jhereg.mn.org)
15*9a747e4fSDavid du Colombier  *
16*9a747e4fSDavid du Colombier  * Sponsored by The USENIX Association for public distribution.
17*9a747e4fSDavid du Colombier  *
18*9a747e4fSDavid du Colombier  * Copyright (c) 1989 Mark H. Colburn.
19*9a747e4fSDavid du Colombier  * All rights reserved.
20*9a747e4fSDavid du Colombier  *
21*9a747e4fSDavid du Colombier  * Redistribution and use in source and binary forms are permitted
22*9a747e4fSDavid du Colombier  * provided that the above copyright notice is duplicated in all such
23*9a747e4fSDavid du Colombier  * forms and that any documentation, advertising materials, and other
24*9a747e4fSDavid du Colombier  * materials related to such distribution and use acknowledge that the
25*9a747e4fSDavid du Colombier  * software was developed * by Mark H. Colburn and sponsored by The
26*9a747e4fSDavid du Colombier  * USENIX Association.
27*9a747e4fSDavid du Colombier  *
28*9a747e4fSDavid du Colombier  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
29*9a747e4fSDavid du Colombier  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
30*9a747e4fSDavid du Colombier  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
31*9a747e4fSDavid du Colombier  *
32*9a747e4fSDavid du Colombier  * $Log:	list.c,v $
33*9a747e4fSDavid du Colombier  * Revision 1.2  89/02/12  10:04:43  mark
34*9a747e4fSDavid du Colombier  * 1.2 release fixes
35*9a747e4fSDavid du Colombier  *
36*9a747e4fSDavid du Colombier  * Revision 1.1  88/12/23  18:02:14  mark
37*9a747e4fSDavid du Colombier  * Initial revision
38*9a747e4fSDavid du Colombier  *
39*9a747e4fSDavid du Colombier  */
40*9a747e4fSDavid du Colombier 
41*9a747e4fSDavid du Colombier #ifndef lint
42*9a747e4fSDavid du Colombier static char *ident = "$Id: list.c,v 1.2 89/02/12 10:04:43 mark Exp $";
43*9a747e4fSDavid du Colombier static char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n";
44*9a747e4fSDavid du Colombier #endif /* ! lint */
45*9a747e4fSDavid du Colombier 
46*9a747e4fSDavid du Colombier 
47*9a747e4fSDavid du Colombier /* Headers */
48*9a747e4fSDavid du Colombier 
49*9a747e4fSDavid du Colombier #include "pax.h"
50*9a747e4fSDavid du Colombier 
51*9a747e4fSDavid du Colombier 
52*9a747e4fSDavid du Colombier /* Defines */
53*9a747e4fSDavid du Colombier 
54*9a747e4fSDavid du Colombier /*
55*9a747e4fSDavid du Colombier  * isodigit returns non zero iff argument is an octal digit, zero otherwise
56*9a747e4fSDavid du Colombier  */
57*9a747e4fSDavid du Colombier #define	ISODIGIT(c)	(((c) >= '0') && ((c) <= '7'))
58*9a747e4fSDavid du Colombier 
59*9a747e4fSDavid du Colombier 
60*9a747e4fSDavid du Colombier /* Function Prototypes */
61*9a747e4fSDavid du Colombier 
62*9a747e4fSDavid du Colombier #ifdef __STDC__
63*9a747e4fSDavid du Colombier 
64*9a747e4fSDavid du Colombier static void cpio_entry(char *, Stat *);
65*9a747e4fSDavid du Colombier static void tar_entry(char *, Stat *);
66*9a747e4fSDavid du Colombier static void pax_entry(char *, Stat *);
67*9a747e4fSDavid du Colombier static void print_mode(ushort);
68*9a747e4fSDavid du Colombier static long from_oct(int digs, char *where);
69*9a747e4fSDavid du Colombier 
70*9a747e4fSDavid du Colombier #else /* !__STDC__ */
71*9a747e4fSDavid du Colombier 
72*9a747e4fSDavid du Colombier static void cpio_entry();
73*9a747e4fSDavid du Colombier static void tar_entry();
74*9a747e4fSDavid du Colombier static void pax_entry();
75*9a747e4fSDavid du Colombier static void print_mode();
76*9a747e4fSDavid du Colombier static long from_oct();
77*9a747e4fSDavid du Colombier 
78*9a747e4fSDavid du Colombier #endif /* __STDC__ */
79*9a747e4fSDavid du Colombier 
80*9a747e4fSDavid du Colombier 
81*9a747e4fSDavid du Colombier /* Internal Identifiers */
82*9a747e4fSDavid du Colombier 
83*9a747e4fSDavid du Colombier static char       *monnames[] = {
84*9a747e4fSDavid du Colombier     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
85*9a747e4fSDavid du Colombier     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
86*9a747e4fSDavid du Colombier };
87*9a747e4fSDavid du Colombier 
88*9a747e4fSDavid du Colombier 
89*9a747e4fSDavid du Colombier /* read_header - read a header record
90*9a747e4fSDavid du Colombier  *
91*9a747e4fSDavid du Colombier  * DESCRIPTION
92*9a747e4fSDavid du Colombier  *
93*9a747e4fSDavid du Colombier  * 	Read a record that's supposed to be a header record. Return its
94*9a747e4fSDavid du Colombier  *	address in "head", and if it is good, the file's size in
95*9a747e4fSDavid du Colombier  *	asb->sb_size.  Decode things from a file header record into a "Stat".
96*9a747e4fSDavid du Colombier  *	Also set "head_standard" to !=0 or ==0 depending whether header record
97*9a747e4fSDavid du Colombier  *	is "Unix Standard" tar format or regular old tar format.
98*9a747e4fSDavid du Colombier  *
99*9a747e4fSDavid du Colombier  * PARAMETERS
100*9a747e4fSDavid du Colombier  *
101*9a747e4fSDavid du Colombier  *	char   *name		- pointer which will contain name of file
102*9a747e4fSDavid du Colombier  *	Stat   *asb		- pointer which will contain stat info
103*9a747e4fSDavid du Colombier  *
104*9a747e4fSDavid du Colombier  * RETURNS
105*9a747e4fSDavid du Colombier  *
106*9a747e4fSDavid du Colombier  * 	Return 1 for success, 0 if the checksum is bad, EOF on eof, 2 for a
107*9a747e4fSDavid du Colombier  * 	record full of zeros (EOF marker).
108*9a747e4fSDavid du Colombier  */
109*9a747e4fSDavid du Colombier 
110*9a747e4fSDavid du Colombier #ifdef __STDC__
111*9a747e4fSDavid du Colombier 
read_header(char * name,Stat * asb)112*9a747e4fSDavid du Colombier int read_header(char *name, Stat *asb)
113*9a747e4fSDavid du Colombier 
114*9a747e4fSDavid du Colombier #else
115*9a747e4fSDavid du Colombier 
116*9a747e4fSDavid du Colombier int read_header(name, asb)
117*9a747e4fSDavid du Colombier char           *name;
118*9a747e4fSDavid du Colombier Stat           *asb;
119*9a747e4fSDavid du Colombier 
120*9a747e4fSDavid du Colombier #endif
121*9a747e4fSDavid du Colombier {
122*9a747e4fSDavid du Colombier     int             i;
123*9a747e4fSDavid du Colombier     long            sum;
124*9a747e4fSDavid du Colombier     long	    recsum;
125*9a747e4fSDavid du Colombier     Link           *link;
126*9a747e4fSDavid du Colombier     char           *p;
127*9a747e4fSDavid du Colombier     char            hdrbuf[BLOCKSIZE];
128*9a747e4fSDavid du Colombier 
129*9a747e4fSDavid du Colombier     memset((char *)asb, 0, sizeof(Stat));
130*9a747e4fSDavid du Colombier     /* read the header from the buffer */
131*9a747e4fSDavid du Colombier     if (buf_read(hdrbuf, BLOCKSIZE) != 0) {
132*9a747e4fSDavid du Colombier 	return (EOF);
133*9a747e4fSDavid du Colombier     }
134*9a747e4fSDavid du Colombier 
135*9a747e4fSDavid du Colombier     strcpy(name, hdrbuf);
136*9a747e4fSDavid du Colombier 
137*9a747e4fSDavid du Colombier     recsum = from_oct(8, &hdrbuf[148]);
138*9a747e4fSDavid du Colombier     sum = 0;
139*9a747e4fSDavid du Colombier     p = hdrbuf;
140*9a747e4fSDavid du Colombier     for (i = 0 ; i < 500; i++) {
141*9a747e4fSDavid du Colombier 
142*9a747e4fSDavid du Colombier 	/*
143*9a747e4fSDavid du Colombier 	 * We can't use unsigned char here because of old compilers, e.g. V7.
144*9a747e4fSDavid du Colombier 	 */
145*9a747e4fSDavid du Colombier 	sum += 0xFF & *p++;
146*9a747e4fSDavid du Colombier     }
147*9a747e4fSDavid du Colombier 
148*9a747e4fSDavid du Colombier     /* Adjust checksum to count the "chksum" field as blanks. */
149*9a747e4fSDavid du Colombier     for (i = 0; i < 8; i++) {
150*9a747e4fSDavid du Colombier 	sum -= 0xFF & hdrbuf[148 + i];
151*9a747e4fSDavid du Colombier     }
152*9a747e4fSDavid du Colombier     sum += ' ' * 8;
153*9a747e4fSDavid du Colombier 
154*9a747e4fSDavid du Colombier     if (sum == 8 * ' ') {
155*9a747e4fSDavid du Colombier 
156*9a747e4fSDavid du Colombier 	/*
157*9a747e4fSDavid du Colombier 	 * This is a zeroed record...whole record is 0's except for the 8
158*9a747e4fSDavid du Colombier 	 * blanks we faked for the checksum field.
159*9a747e4fSDavid du Colombier 	 */
160*9a747e4fSDavid du Colombier 	return (2);
161*9a747e4fSDavid du Colombier     }
162*9a747e4fSDavid du Colombier     if (sum == recsum) {
163*9a747e4fSDavid du Colombier 	/*
164*9a747e4fSDavid du Colombier 	 * Good record.  Decode file size and return.
165*9a747e4fSDavid du Colombier 	 */
166*9a747e4fSDavid du Colombier 	if (hdrbuf[156] != LNKTYPE) {
167*9a747e4fSDavid du Colombier 	    asb->sb_size = from_oct(1 + 12, &hdrbuf[124]);
168*9a747e4fSDavid du Colombier 	}
169*9a747e4fSDavid du Colombier 	asb->sb_mtime = from_oct(1 + 12, &hdrbuf[136]);
170*9a747e4fSDavid du Colombier 	asb->sb_mode = from_oct(8, &hdrbuf[100]);
171*9a747e4fSDavid du Colombier 
172*9a747e4fSDavid du Colombier 	if (strcmp(&hdrbuf[257], TMAGIC) == 0) {
173*9a747e4fSDavid du Colombier 	    /* Unix Standard tar archive */
174*9a747e4fSDavid du Colombier 	    head_standard = 1;
175*9a747e4fSDavid du Colombier #ifdef NONAMES
176*9a747e4fSDavid du Colombier 	    asb->sb_uid = from_oct(8, &hdrbuf[108]);
177*9a747e4fSDavid du Colombier 	    asb->sb_gid = from_oct(8, &hdrbuf[116]);
178*9a747e4fSDavid du Colombier #else
179*9a747e4fSDavid du Colombier 	    asb->sb_uid = finduid(&hdrbuf[265]);
180*9a747e4fSDavid du Colombier 	    asb->sb_gid = findgid(&hdrbuf[297]);
181*9a747e4fSDavid du Colombier #endif
182*9a747e4fSDavid du Colombier 	    switch (hdrbuf[156]) {
183*9a747e4fSDavid du Colombier 	    case BLKTYPE:
184*9a747e4fSDavid du Colombier 	    case CHRTYPE:
185*9a747e4fSDavid du Colombier #ifndef _POSIX_SOURCE
186*9a747e4fSDavid du Colombier 		asb->sb_rdev = makedev(from_oct(8, &hdrbuf[329]),
187*9a747e4fSDavid du Colombier 				      from_oct(8, &hdrbuf[337]));
188*9a747e4fSDavid du Colombier #endif
189*9a747e4fSDavid du Colombier 		break;
190*9a747e4fSDavid du Colombier 	    default:
191*9a747e4fSDavid du Colombier 		/* do nothing... */
192*9a747e4fSDavid du Colombier 		break;
193*9a747e4fSDavid du Colombier 	    }
194*9a747e4fSDavid du Colombier 	} else {
195*9a747e4fSDavid du Colombier 	    /* Old fashioned tar archive */
196*9a747e4fSDavid du Colombier 	    head_standard = 0;
197*9a747e4fSDavid du Colombier 	    asb->sb_uid = from_oct(8, &hdrbuf[108]);
198*9a747e4fSDavid du Colombier 	    asb->sb_gid = from_oct(8, &hdrbuf[116]);
199*9a747e4fSDavid du Colombier 	}
200*9a747e4fSDavid du Colombier 
201*9a747e4fSDavid du Colombier 	switch (hdrbuf[156]) {
202*9a747e4fSDavid du Colombier 	case REGTYPE:
203*9a747e4fSDavid du Colombier 	case AREGTYPE:
204*9a747e4fSDavid du Colombier 	    /*
205*9a747e4fSDavid du Colombier 	     * Berkeley tar stores directories as regular files with a
206*9a747e4fSDavid du Colombier 	     * trailing /
207*9a747e4fSDavid du Colombier 	     */
208*9a747e4fSDavid du Colombier 	    if (name[strlen(name) - 1] == '/') {
209*9a747e4fSDavid du Colombier 		name[strlen(name) - 1] = '\0';
210*9a747e4fSDavid du Colombier 		asb->sb_mode |= S_IFDIR;
211*9a747e4fSDavid du Colombier 	    } else {
212*9a747e4fSDavid du Colombier 		asb->sb_mode |= S_IFREG;
213*9a747e4fSDavid du Colombier 	    }
214*9a747e4fSDavid du Colombier 	    break;
215*9a747e4fSDavid du Colombier 	case LNKTYPE:
216*9a747e4fSDavid du Colombier 	    asb->sb_nlink = 2;
217*9a747e4fSDavid du Colombier 	    linkto(&hdrbuf[157], asb);
218*9a747e4fSDavid du Colombier 	    linkto(name, asb);
219*9a747e4fSDavid du Colombier 	    asb->sb_mode |= S_IFREG;
220*9a747e4fSDavid du Colombier 	    break;
221*9a747e4fSDavid du Colombier 	case BLKTYPE:
222*9a747e4fSDavid du Colombier 	    asb->sb_mode |= S_IFBLK;
223*9a747e4fSDavid du Colombier 	    break;
224*9a747e4fSDavid du Colombier 	case CHRTYPE:
225*9a747e4fSDavid du Colombier 	    asb->sb_mode |= S_IFCHR;
226*9a747e4fSDavid du Colombier 	    break;
227*9a747e4fSDavid du Colombier 	case DIRTYPE:
228*9a747e4fSDavid du Colombier 	    asb->sb_mode |= S_IFDIR;
229*9a747e4fSDavid du Colombier 	    break;
230*9a747e4fSDavid du Colombier #ifdef S_IFLNK
231*9a747e4fSDavid du Colombier 	case SYMTYPE:
232*9a747e4fSDavid du Colombier 	    asb->sb_mode |= S_IFLNK;
233*9a747e4fSDavid du Colombier 	    strcpy(asb->sb_link, &hdrbuf[157]);
234*9a747e4fSDavid du Colombier 	    break;
235*9a747e4fSDavid du Colombier #endif
236*9a747e4fSDavid du Colombier #ifdef S_IFIFO
237*9a747e4fSDavid du Colombier 	case FIFOTYPE:
238*9a747e4fSDavid du Colombier 	    asb->sb_mode |= S_IFIFO;
239*9a747e4fSDavid du Colombier 	    break;
240*9a747e4fSDavid du Colombier #endif
241*9a747e4fSDavid du Colombier #ifdef S_IFCTG
242*9a747e4fSDavid du Colombier 	case CONTTYPE:
243*9a747e4fSDavid du Colombier 	    asb->sb_mode |= S_IFCTG;
244*9a747e4fSDavid du Colombier 	    break;
245*9a747e4fSDavid du Colombier #endif
246*9a747e4fSDavid du Colombier 	}
247*9a747e4fSDavid du Colombier 	return (1);
248*9a747e4fSDavid du Colombier     }
249*9a747e4fSDavid du Colombier     return (0);
250*9a747e4fSDavid du Colombier }
251*9a747e4fSDavid du Colombier 
252*9a747e4fSDavid du Colombier 
253*9a747e4fSDavid du Colombier /* print_entry - print a single table-of-contents entry
254*9a747e4fSDavid du Colombier  *
255*9a747e4fSDavid du Colombier  * DESCRIPTION
256*9a747e4fSDavid du Colombier  *
257*9a747e4fSDavid du Colombier  *	Print_entry prints a single line of file information.  The format
258*9a747e4fSDavid du Colombier  *	of the line is the same as that used by the LS command.  For some
259*9a747e4fSDavid du Colombier  *	archive formats, various fields may not make any sense, such as
260*9a747e4fSDavid du Colombier  *	the link count on tar archives.  No error checking is done for bad
261*9a747e4fSDavid du Colombier  *	or invalid data.
262*9a747e4fSDavid du Colombier  *
263*9a747e4fSDavid du Colombier  * PARAMETERS
264*9a747e4fSDavid du Colombier  *
265*9a747e4fSDavid du Colombier  *	char   *name		- pointer to name to print an entry for
266*9a747e4fSDavid du Colombier  *	Stat   *asb		- pointer to the stat structure for the file
267*9a747e4fSDavid du Colombier  */
268*9a747e4fSDavid du Colombier 
269*9a747e4fSDavid du Colombier #ifdef __STDC__
270*9a747e4fSDavid du Colombier 
print_entry(char * name,Stat * asb)271*9a747e4fSDavid du Colombier void print_entry(char *name, Stat *asb)
272*9a747e4fSDavid du Colombier 
273*9a747e4fSDavid du Colombier #else
274*9a747e4fSDavid du Colombier 
275*9a747e4fSDavid du Colombier void print_entry(name, asb)
276*9a747e4fSDavid du Colombier char		*name;
277*9a747e4fSDavid du Colombier Stat	        *asb;
278*9a747e4fSDavid du Colombier 
279*9a747e4fSDavid du Colombier #endif
280*9a747e4fSDavid du Colombier {
281*9a747e4fSDavid du Colombier     switch (ar_interface) {
282*9a747e4fSDavid du Colombier     case TAR:
283*9a747e4fSDavid du Colombier 	tar_entry(name, asb);
284*9a747e4fSDavid du Colombier 	break;
285*9a747e4fSDavid du Colombier     case CPIO:
286*9a747e4fSDavid du Colombier 	cpio_entry(name, asb);
287*9a747e4fSDavid du Colombier 	break;
288*9a747e4fSDavid du Colombier     case PAX: pax_entry(name, asb);
289*9a747e4fSDavid du Colombier 	break;
290*9a747e4fSDavid du Colombier     }
291*9a747e4fSDavid du Colombier }
292*9a747e4fSDavid du Colombier 
293*9a747e4fSDavid du Colombier 
294*9a747e4fSDavid du Colombier /* cpio_entry - print a verbose cpio-style entry
295*9a747e4fSDavid du Colombier  *
296*9a747e4fSDavid du Colombier  * DESCRIPTION
297*9a747e4fSDavid du Colombier  *
298*9a747e4fSDavid du Colombier  *	Print_entry prints a single line of file information.  The format
299*9a747e4fSDavid du Colombier  *	of the line is the same as that used by the traditional cpio
300*9a747e4fSDavid du Colombier  *	command.  No error checking is done for bad or invalid data.
301*9a747e4fSDavid du Colombier  *
302*9a747e4fSDavid du Colombier  * PARAMETERS
303*9a747e4fSDavid du Colombier  *
304*9a747e4fSDavid du Colombier  *	char   *name		- pointer to name to print an entry for
305*9a747e4fSDavid du Colombier  *	Stat   *asb		- pointer to the stat structure for the file
306*9a747e4fSDavid du Colombier  */
307*9a747e4fSDavid du Colombier 
308*9a747e4fSDavid du Colombier #ifdef __STDC__
309*9a747e4fSDavid du Colombier 
cpio_entry(char * name,Stat * asb)310*9a747e4fSDavid du Colombier static void cpio_entry(char *name, Stat *asb)
311*9a747e4fSDavid du Colombier 
312*9a747e4fSDavid du Colombier #else
313*9a747e4fSDavid du Colombier 
314*9a747e4fSDavid du Colombier static void cpio_entry(name, asb)
315*9a747e4fSDavid du Colombier char	       *name;
316*9a747e4fSDavid du Colombier Stat	       *asb;
317*9a747e4fSDavid du Colombier 
318*9a747e4fSDavid du Colombier #endif
319*9a747e4fSDavid du Colombier {
320*9a747e4fSDavid du Colombier     struct tm	       *atm;
321*9a747e4fSDavid du Colombier     Link	       *from;
322*9a747e4fSDavid du Colombier     struct passwd      *pwp;
323*9a747e4fSDavid du Colombier     struct group       *grp;
324*9a747e4fSDavid du Colombier 
325*9a747e4fSDavid du Colombier     if (f_list && f_verbose) {
326*9a747e4fSDavid du Colombier 	fprintf(msgfile, "%-7o", asb->sb_mode);
327*9a747e4fSDavid du Colombier 	atm = localtime(&asb->sb_mtime);
328*9a747e4fSDavid du Colombier 	if (pwp = getpwuid((int) USH(asb->sb_uid))) {
329*9a747e4fSDavid du Colombier 	    fprintf(msgfile, "%-6s", pwp->pw_name);
330*9a747e4fSDavid du Colombier 	} else {
331*9a747e4fSDavid du Colombier 	    fprintf(msgfile, "%-6u", USH(asb->sb_uid));
332*9a747e4fSDavid du Colombier 	}
333*9a747e4fSDavid du Colombier 	fprintf(msgfile,"%7ld  %3s %2d %02d:%02d:%02d %4d  ",
334*9a747e4fSDavid du Colombier 	               asb->sb_size, monnames[atm->tm_mon],
335*9a747e4fSDavid du Colombier 		       atm->tm_mday, atm->tm_hour, atm->tm_min,
336*9a747e4fSDavid du Colombier 		       atm->tm_sec, atm->tm_year + 1900);
337*9a747e4fSDavid du Colombier     }
338*9a747e4fSDavid du Colombier     fprintf(msgfile, "%s", name);
339*9a747e4fSDavid du Colombier     if ((asb->sb_nlink > 1) && (from = islink(name, asb))) {
340*9a747e4fSDavid du Colombier 	fprintf(msgfile, " linked to %s", from->l_name);
341*9a747e4fSDavid du Colombier     }
342*9a747e4fSDavid du Colombier #ifdef	S_IFLNK
343*9a747e4fSDavid du Colombier     if ((asb->sb_mode & S_IFMT) == S_IFLNK) {
344*9a747e4fSDavid du Colombier 	fprintf(msgfile, " symbolic link to %s", asb->sb_link);
345*9a747e4fSDavid du Colombier     }
346*9a747e4fSDavid du Colombier #endif	/* S_IFLNK */
347*9a747e4fSDavid du Colombier     putc('\n', msgfile);
348*9a747e4fSDavid du Colombier }
349*9a747e4fSDavid du Colombier 
350*9a747e4fSDavid du Colombier 
351*9a747e4fSDavid du Colombier /* tar_entry - print a tar verbose mode entry
352*9a747e4fSDavid du Colombier  *
353*9a747e4fSDavid du Colombier  * DESCRIPTION
354*9a747e4fSDavid du Colombier  *
355*9a747e4fSDavid du Colombier  *	Print_entry prints a single line of tar file information.  The format
356*9a747e4fSDavid du Colombier  *	of the line is the same as that produced by the traditional tar
357*9a747e4fSDavid du Colombier  *	command.  No error checking is done for bad or invalid data.
358*9a747e4fSDavid du Colombier  *
359*9a747e4fSDavid du Colombier  * PARAMETERS
360*9a747e4fSDavid du Colombier  *
361*9a747e4fSDavid du Colombier  *	char   *name		- pointer to name to print an entry for
362*9a747e4fSDavid du Colombier  *	Stat   *asb		- pointer to the stat structure for the file
363*9a747e4fSDavid du Colombier  */
364*9a747e4fSDavid du Colombier 
365*9a747e4fSDavid du Colombier #ifdef __STDC__
366*9a747e4fSDavid du Colombier 
tar_entry(char * name,Stat * asb)367*9a747e4fSDavid du Colombier static void tar_entry(char *name, Stat *asb)
368*9a747e4fSDavid du Colombier 
369*9a747e4fSDavid du Colombier #else
370*9a747e4fSDavid du Colombier 
371*9a747e4fSDavid du Colombier static void tar_entry(name, asb)
372*9a747e4fSDavid du Colombier char		*name;
373*9a747e4fSDavid du Colombier Stat            *asb;
374*9a747e4fSDavid du Colombier 
375*9a747e4fSDavid du Colombier #endif
376*9a747e4fSDavid du Colombier {
377*9a747e4fSDavid du Colombier     struct tm  	       *atm;
378*9a747e4fSDavid du Colombier     int			i;
379*9a747e4fSDavid du Colombier     int			mode;
380*9a747e4fSDavid du Colombier     char               *symnam = "NULL";
381*9a747e4fSDavid du Colombier     Link               *link;
382*9a747e4fSDavid du Colombier 
383*9a747e4fSDavid du Colombier     if ((mode = asb->sb_mode & S_IFMT) == S_IFDIR) {
384*9a747e4fSDavid du Colombier 	return;			/* don't print directories */
385*9a747e4fSDavid du Colombier     }
386*9a747e4fSDavid du Colombier     if (f_extract) {
387*9a747e4fSDavid du Colombier 	switch (mode) {
388*9a747e4fSDavid du Colombier #ifdef S_IFLNK
389*9a747e4fSDavid du Colombier 	case S_IFLNK: 	/* This file is a symbolic link */
390*9a747e4fSDavid du Colombier 	    i = readlink(name, symnam, PATH_MAX - 1);
391*9a747e4fSDavid du Colombier 	    if (i < 0) {		/* Could not find symbolic link */
392*9a747e4fSDavid du Colombier 		warn("can't read symbolic link", strerror());
393*9a747e4fSDavid du Colombier 	    } else { 		/* Found symbolic link filename */
394*9a747e4fSDavid du Colombier 		symnam[i] = '\0';
395*9a747e4fSDavid du Colombier 		fprintf(msgfile, "x %s symbolic link to %s\n", name, symnam);
396*9a747e4fSDavid du Colombier 	    }
397*9a747e4fSDavid du Colombier 	    break;
398*9a747e4fSDavid du Colombier #endif
399*9a747e4fSDavid du Colombier 	case S_IFREG: 	/* It is a link or a file */
400*9a747e4fSDavid du Colombier 	    if ((asb->sb_nlink > 1) && (link = islink(name, asb))) {
401*9a747e4fSDavid du Colombier 		fprintf(msgfile, "%s linked to %s\n", name, link->l_name);
402*9a747e4fSDavid du Colombier 	    } else {
403*9a747e4fSDavid du Colombier 		fprintf(msgfile, "x %s, %ld bytes, %d tape blocks\n",
404*9a747e4fSDavid du Colombier 			name, asb->sb_size, ROUNDUP(asb->sb_size,
405*9a747e4fSDavid du Colombier 			BLOCKSIZE) / BLOCKSIZE);
406*9a747e4fSDavid du Colombier 	    }
407*9a747e4fSDavid du Colombier 	}
408*9a747e4fSDavid du Colombier     } else if (f_append || f_create) {
409*9a747e4fSDavid du Colombier 	switch (mode) {
410*9a747e4fSDavid du Colombier #ifdef S_IFLNK
411*9a747e4fSDavid du Colombier 	case S_IFLNK: 	/* This file is a symbolic link */
412*9a747e4fSDavid du Colombier 	    i = readlink(name, symnam, PATH_MAX - 1);
413*9a747e4fSDavid du Colombier 	    if (i < 0) {		/* Could not find symbolic link */
414*9a747e4fSDavid du Colombier 		warn("can't read symbolic link", strerror());
415*9a747e4fSDavid du Colombier 	    } else { 		/* Found symbolic link filename */
416*9a747e4fSDavid du Colombier 		symnam[i] = '\0';
417*9a747e4fSDavid du Colombier 		fprintf(msgfile, "a %s symbolic link to %s\n", name, symnam);
418*9a747e4fSDavid du Colombier 	    }
419*9a747e4fSDavid du Colombier 	    break;
420*9a747e4fSDavid du Colombier #endif
421*9a747e4fSDavid du Colombier 	case S_IFREG: 	/* It is a link or a file */
422*9a747e4fSDavid du Colombier 	    fprintf(msgfile, "a %s ", name);
423*9a747e4fSDavid du Colombier 	    if ((asb->sb_nlink > 1) && (link = islink(name, asb))) {
424*9a747e4fSDavid du Colombier 		fprintf(msgfile, "link to %s\n", link->l_name);
425*9a747e4fSDavid du Colombier 	    } else {
426*9a747e4fSDavid du Colombier 		fprintf(msgfile, "%ld Blocks\n",
427*9a747e4fSDavid du Colombier 			ROUNDUP(asb->sb_size, BLOCKSIZE) / BLOCKSIZE);
428*9a747e4fSDavid du Colombier 	    }
429*9a747e4fSDavid du Colombier 	    break;
430*9a747e4fSDavid du Colombier 	}
431*9a747e4fSDavid du Colombier     } else if (f_list) {
432*9a747e4fSDavid du Colombier 	if (f_verbose) {
433*9a747e4fSDavid du Colombier 	    atm = localtime(&asb->sb_mtime);
434*9a747e4fSDavid du Colombier 	    print_mode(asb->sb_mode);
435*9a747e4fSDavid du Colombier 	    fprintf(msgfile," %d/%d %6d %3s %2d %02d:%02d %4d %s",
436*9a747e4fSDavid du Colombier 		    asb->sb_uid, asb->sb_gid, asb->sb_size,
437*9a747e4fSDavid du Colombier 		    monnames[atm->tm_mon], atm->tm_mday, atm->tm_hour,
438*9a747e4fSDavid du Colombier 		    atm->tm_min, atm->tm_year + 1900, name);
439*9a747e4fSDavid du Colombier 	} else {
440*9a747e4fSDavid du Colombier 	    fprintf(msgfile, "%s", name);
441*9a747e4fSDavid du Colombier 	}
442*9a747e4fSDavid du Colombier 	switch (mode) {
443*9a747e4fSDavid du Colombier #ifdef S_IFLNK
444*9a747e4fSDavid du Colombier 	case S_IFLNK: 	/* This file is a symbolic link */
445*9a747e4fSDavid du Colombier 	    i = readlink(name, symnam, PATH_MAX - 1);
446*9a747e4fSDavid du Colombier 	    if (i < 0) {		/* Could not find symbolic link */
447*9a747e4fSDavid du Colombier 		warn("can't read symbolic link", strerror());
448*9a747e4fSDavid du Colombier 	    } else { 		/* Found symbolic link filename */
449*9a747e4fSDavid du Colombier 		symnam[i] = '\0';
450*9a747e4fSDavid du Colombier 		fprintf(msgfile, " symbolic link to %s", symnam);
451*9a747e4fSDavid du Colombier 	    }
452*9a747e4fSDavid du Colombier 	    break;
453*9a747e4fSDavid du Colombier #endif
454*9a747e4fSDavid du Colombier 	case S_IFREG: 	/* It is a link or a file */
455*9a747e4fSDavid du Colombier 	    if ((asb->sb_nlink > 1) && (link = islink(name, asb))) {
456*9a747e4fSDavid du Colombier 		fprintf(msgfile, " linked to %s", link->l_name);
457*9a747e4fSDavid du Colombier 	    }
458*9a747e4fSDavid du Colombier 	    break;		/* Do not print out directories */
459*9a747e4fSDavid du Colombier 	}
460*9a747e4fSDavid du Colombier 	fputc('\n', msgfile);
461*9a747e4fSDavid du Colombier     } else {
462*9a747e4fSDavid du Colombier 	fprintf(msgfile, "? %s %ld blocks\n", name,
463*9a747e4fSDavid du Colombier 		ROUNDUP(asb->sb_size, BLOCKSIZE) / BLOCKSIZE);
464*9a747e4fSDavid du Colombier     }
465*9a747e4fSDavid du Colombier }
466*9a747e4fSDavid du Colombier 
467*9a747e4fSDavid du Colombier 
468*9a747e4fSDavid du Colombier /* pax_entry - print a verbose cpio-style entry
469*9a747e4fSDavid du Colombier  *
470*9a747e4fSDavid du Colombier  * DESCRIPTION
471*9a747e4fSDavid du Colombier  *
472*9a747e4fSDavid du Colombier  *	Print_entry prints a single line of file information.  The format
473*9a747e4fSDavid du Colombier  *	of the line is the same as that used by the LS command.
474*9a747e4fSDavid du Colombier  *	No error checking is done for bad or invalid data.
475*9a747e4fSDavid du Colombier  *
476*9a747e4fSDavid du Colombier  * PARAMETERS
477*9a747e4fSDavid du Colombier  *
478*9a747e4fSDavid du Colombier  *	char   *name		- pointer to name to print an entry for
479*9a747e4fSDavid du Colombier  *	Stat   *asb		- pointer to the stat structure for the file
480*9a747e4fSDavid du Colombier  */
481*9a747e4fSDavid du Colombier 
482*9a747e4fSDavid du Colombier #ifdef __STDC__
483*9a747e4fSDavid du Colombier 
pax_entry(char * name,Stat * asb)484*9a747e4fSDavid du Colombier static void pax_entry(char *name, Stat *asb)
485*9a747e4fSDavid du Colombier 
486*9a747e4fSDavid du Colombier #else
487*9a747e4fSDavid du Colombier 
488*9a747e4fSDavid du Colombier static void pax_entry(name, asb)
489*9a747e4fSDavid du Colombier char	       *name;
490*9a747e4fSDavid du Colombier Stat	       *asb;
491*9a747e4fSDavid du Colombier 
492*9a747e4fSDavid du Colombier #endif
493*9a747e4fSDavid du Colombier {
494*9a747e4fSDavid du Colombier     struct tm	       *atm;
495*9a747e4fSDavid du Colombier     Link	       *from;
496*9a747e4fSDavid du Colombier     struct passwd      *pwp;
497*9a747e4fSDavid du Colombier     struct group       *grp;
498*9a747e4fSDavid du Colombier 
499*9a747e4fSDavid du Colombier     if (f_list && f_verbose) {
500*9a747e4fSDavid du Colombier 	print_mode(asb->sb_mode);
501*9a747e4fSDavid du Colombier 	fprintf(msgfile, " %2d", asb->sb_nlink);
502*9a747e4fSDavid du Colombier 	atm = localtime(&asb->sb_mtime);
503*9a747e4fSDavid du Colombier 	if (pwp = getpwuid((int) USH(asb->sb_uid))) {
504*9a747e4fSDavid du Colombier 	    fprintf(msgfile, " %-8s", pwp->pw_name);
505*9a747e4fSDavid du Colombier 	} else {
506*9a747e4fSDavid du Colombier 	    fprintf(msgfile, " %-8u", USH(asb->sb_uid));
507*9a747e4fSDavid du Colombier 	}
508*9a747e4fSDavid du Colombier 	if (grp = getgrgid((int) USH(asb->sb_gid))) {
509*9a747e4fSDavid du Colombier 	    fprintf(msgfile, " %-8s", grp->gr_name);
510*9a747e4fSDavid du Colombier 	} else {
511*9a747e4fSDavid du Colombier 	    fprintf(msgfile, " %-8u", USH(asb->sb_gid));
512*9a747e4fSDavid du Colombier 	}
513*9a747e4fSDavid du Colombier 	switch (asb->sb_mode & S_IFMT) {
514*9a747e4fSDavid du Colombier 	case S_IFBLK:
515*9a747e4fSDavid du Colombier 	case S_IFCHR:
516*9a747e4fSDavid du Colombier 	    fprintf(msgfile, "\t%3d, %3d",
517*9a747e4fSDavid du Colombier 		           major(asb->sb_rdev), minor(asb->sb_rdev));
518*9a747e4fSDavid du Colombier 	    break;
519*9a747e4fSDavid du Colombier 	case S_IFREG:
520*9a747e4fSDavid du Colombier 	    fprintf(msgfile, "\t%8ld", asb->sb_size);
521*9a747e4fSDavid du Colombier 	    break;
522*9a747e4fSDavid du Colombier 	default:
523*9a747e4fSDavid du Colombier 	    fprintf(msgfile, "\t        ");
524*9a747e4fSDavid du Colombier 	}
525*9a747e4fSDavid du Colombier 	fprintf(msgfile," %3s %2d %02d:%02d ",
526*9a747e4fSDavid du Colombier 	        monnames[atm->tm_mon], atm->tm_mday,
527*9a747e4fSDavid du Colombier 		atm->tm_hour, atm->tm_min);
528*9a747e4fSDavid du Colombier     }
529*9a747e4fSDavid du Colombier     fprintf(msgfile, "%s", name);
530*9a747e4fSDavid du Colombier     if ((asb->sb_nlink > 1) && (from = islink(name, asb))) {
531*9a747e4fSDavid du Colombier 	fprintf(msgfile, " == %s", from->l_name);
532*9a747e4fSDavid du Colombier     }
533*9a747e4fSDavid du Colombier #ifdef	S_IFLNK
534*9a747e4fSDavid du Colombier     if ((asb->sb_mode & S_IFMT) == S_IFLNK) {
535*9a747e4fSDavid du Colombier 	fprintf(msgfile, " -> %s", asb->sb_link);
536*9a747e4fSDavid du Colombier     }
537*9a747e4fSDavid du Colombier #endif	/* S_IFLNK */
538*9a747e4fSDavid du Colombier     putc('\n', msgfile);
539*9a747e4fSDavid du Colombier }
540*9a747e4fSDavid du Colombier 
541*9a747e4fSDavid du Colombier 
542*9a747e4fSDavid du Colombier /* print_mode - fancy file mode display
543*9a747e4fSDavid du Colombier  *
544*9a747e4fSDavid du Colombier  * DESCRIPTION
545*9a747e4fSDavid du Colombier  *
546*9a747e4fSDavid du Colombier  *	Print_mode displays a numeric file mode in the standard unix
547*9a747e4fSDavid du Colombier  *	representation, ala ls (-rwxrwxrwx).  No error checking is done
548*9a747e4fSDavid du Colombier  *	for bad mode combinations.  FIFOS, sybmbolic links, sticky bits,
549*9a747e4fSDavid du Colombier  *	block- and character-special devices are supported if supported
550*9a747e4fSDavid du Colombier  *	by the hosting implementation.
551*9a747e4fSDavid du Colombier  *
552*9a747e4fSDavid du Colombier  * PARAMETERS
553*9a747e4fSDavid du Colombier  *
554*9a747e4fSDavid du Colombier  *	ushort	mode	- The integer representation of the mode to print.
555*9a747e4fSDavid du Colombier  */
556*9a747e4fSDavid du Colombier 
557*9a747e4fSDavid du Colombier #ifdef __STDC__
558*9a747e4fSDavid du Colombier 
print_mode(ushort mode)559*9a747e4fSDavid du Colombier static void print_mode(ushort mode)
560*9a747e4fSDavid du Colombier 
561*9a747e4fSDavid du Colombier #else
562*9a747e4fSDavid du Colombier 
563*9a747e4fSDavid du Colombier static void print_mode(mode)
564*9a747e4fSDavid du Colombier ushort	mode;
565*9a747e4fSDavid du Colombier 
566*9a747e4fSDavid du Colombier #endif
567*9a747e4fSDavid du Colombier {
568*9a747e4fSDavid du Colombier     /* Tar does not print the leading identifier... */
569*9a747e4fSDavid du Colombier     if (ar_interface != TAR) {
570*9a747e4fSDavid du Colombier 	switch (mode & S_IFMT) {
571*9a747e4fSDavid du Colombier 	case S_IFDIR:
572*9a747e4fSDavid du Colombier 	    putc('d', msgfile);
573*9a747e4fSDavid du Colombier 	    break;
574*9a747e4fSDavid du Colombier #ifdef	S_IFLNK
575*9a747e4fSDavid du Colombier 	case S_IFLNK:
576*9a747e4fSDavid du Colombier 	    putc('l', msgfile);
577*9a747e4fSDavid du Colombier 	    break;
578*9a747e4fSDavid du Colombier #endif	/* S_IFLNK */
579*9a747e4fSDavid du Colombier 	case S_IFBLK:
580*9a747e4fSDavid du Colombier 	    putc('b', msgfile);
581*9a747e4fSDavid du Colombier 	    break;
582*9a747e4fSDavid du Colombier 	case S_IFCHR:
583*9a747e4fSDavid du Colombier 	    putc('c', msgfile);
584*9a747e4fSDavid du Colombier 	    break;
585*9a747e4fSDavid du Colombier #ifdef	S_IFIFO
586*9a747e4fSDavid du Colombier 	case S_IFIFO:
587*9a747e4fSDavid du Colombier 	    putc('p', msgfile);
588*9a747e4fSDavid du Colombier 	    break;
589*9a747e4fSDavid du Colombier #endif	/* S_IFIFO */
590*9a747e4fSDavid du Colombier 	case S_IFREG:
591*9a747e4fSDavid du Colombier 	default:
592*9a747e4fSDavid du Colombier 	    putc('-', msgfile);
593*9a747e4fSDavid du Colombier 	    break;
594*9a747e4fSDavid du Colombier 	}
595*9a747e4fSDavid du Colombier     }
596*9a747e4fSDavid du Colombier     putc(mode & 0400 ? 'r' : '-', msgfile);
597*9a747e4fSDavid du Colombier     putc(mode & 0200 ? 'w' : '-', msgfile);
598*9a747e4fSDavid du Colombier     putc(mode & 0100
599*9a747e4fSDavid du Colombier 	 ? mode & 04000 ? 's' : 'x'
600*9a747e4fSDavid du Colombier 	 : mode & 04000 ? 'S' : '-', msgfile);
601*9a747e4fSDavid du Colombier     putc(mode & 0040 ? 'r' : '-', msgfile);
602*9a747e4fSDavid du Colombier     putc(mode & 0020 ? 'w' : '-', msgfile);
603*9a747e4fSDavid du Colombier     putc(mode & 0010
604*9a747e4fSDavid du Colombier 	 ? mode & 02000 ? 's' : 'x'
605*9a747e4fSDavid du Colombier 	 : mode & 02000 ? 'S' : '-', msgfile);
606*9a747e4fSDavid du Colombier     putc(mode & 0004 ? 'r' : '-', msgfile);
607*9a747e4fSDavid du Colombier     putc(mode & 0002 ? 'w' : '-', msgfile);
608*9a747e4fSDavid du Colombier     putc(mode & 0001
609*9a747e4fSDavid du Colombier 	 ? mode & 01000 ? 't' : 'x'
610*9a747e4fSDavid du Colombier 	 : mode & 01000 ? 'T' : '-', msgfile);
611*9a747e4fSDavid du Colombier }
612*9a747e4fSDavid du Colombier 
613*9a747e4fSDavid du Colombier 
614*9a747e4fSDavid du Colombier /* from_oct - quick and dirty octal conversion
615*9a747e4fSDavid du Colombier  *
616*9a747e4fSDavid du Colombier  * DESCRIPTION
617*9a747e4fSDavid du Colombier  *
618*9a747e4fSDavid du Colombier  *	From_oct will convert an ASCII representation of an octal number
619*9a747e4fSDavid du Colombier  *	to the numeric representation.  The number of characters to convert
620*9a747e4fSDavid du Colombier  *	is given by the parameter "digs".  If there are less numbers than
621*9a747e4fSDavid du Colombier  *	specified by "digs", then the routine returns -1.
622*9a747e4fSDavid du Colombier  *
623*9a747e4fSDavid du Colombier  * PARAMETERS
624*9a747e4fSDavid du Colombier  *
625*9a747e4fSDavid du Colombier  *	int digs	- Number to of digits to convert
626*9a747e4fSDavid du Colombier  *	char *where	- Character representation of octal number
627*9a747e4fSDavid du Colombier  *
628*9a747e4fSDavid du Colombier  * RETURNS
629*9a747e4fSDavid du Colombier  *
630*9a747e4fSDavid du Colombier  *	The value of the octal number represented by the first digs
631*9a747e4fSDavid du Colombier  *	characters of the string where.  Result is -1 if the field
632*9a747e4fSDavid du Colombier  *	is invalid (all blank, or nonoctal).
633*9a747e4fSDavid du Colombier  *
634*9a747e4fSDavid du Colombier  * ERRORS
635*9a747e4fSDavid du Colombier  *
636*9a747e4fSDavid du Colombier  *	If the field is all blank, then the value returned is -1.
637*9a747e4fSDavid du Colombier  *
638*9a747e4fSDavid du Colombier  */
639*9a747e4fSDavid du Colombier 
640*9a747e4fSDavid du Colombier #ifdef __STDC__
641*9a747e4fSDavid du Colombier 
from_oct(int digs,char * where)642*9a747e4fSDavid du Colombier static long from_oct(int digs, char *where)
643*9a747e4fSDavid du Colombier 
644*9a747e4fSDavid du Colombier #else
645*9a747e4fSDavid du Colombier 
646*9a747e4fSDavid du Colombier static long from_oct(digs, where)
647*9a747e4fSDavid du Colombier int             digs;		/* number of characters to convert */
648*9a747e4fSDavid du Colombier char           *where;		/* character representation of octal number */
649*9a747e4fSDavid du Colombier 
650*9a747e4fSDavid du Colombier #endif
651*9a747e4fSDavid du Colombier {
652*9a747e4fSDavid du Colombier     long            value;
653*9a747e4fSDavid du Colombier 
654*9a747e4fSDavid du Colombier     while (isspace(*where)) {	/* Skip spaces */
655*9a747e4fSDavid du Colombier 	where++;
656*9a747e4fSDavid du Colombier 	if (--digs <= 0) {
657*9a747e4fSDavid du Colombier 	    return(-1);		/* All blank field */
658*9a747e4fSDavid du Colombier 	}
659*9a747e4fSDavid du Colombier     }
660*9a747e4fSDavid du Colombier     value = 0;
661*9a747e4fSDavid du Colombier     while (digs > 0 && ISODIGIT(*where)) {	/* Scan til nonoctal */
662*9a747e4fSDavid du Colombier 	value = (value << 3) | (*where++ - '0');
663*9a747e4fSDavid du Colombier 	--digs;
664*9a747e4fSDavid du Colombier     }
665*9a747e4fSDavid du Colombier 
666*9a747e4fSDavid du Colombier     if (digs > 0 && *where && !isspace(*where)) {
667*9a747e4fSDavid du Colombier 	return(-1);		/* Ended on non-space/nul */
668*9a747e4fSDavid du Colombier     }
669*9a747e4fSDavid du Colombier     return(value);
670*9a747e4fSDavid du Colombier }
671