1 /* @(#)list.c	1.84 20/02/05 Copyright 1985, 1995, 2000-2020 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)list.c	1.84 20/02/05 Copyright 1985, 1995, 2000-2020 J. Schilling";
6 #endif
7 /*
8  *	List the content of an archive
9  *
10  *	Copyright (c) 1985, 1995, 2000-2020 J. Schilling
11  */
12 /*
13  * The contents of this file are subject to the terms of the
14  * Common Development and Distribution License, Version 1.0 only
15  * (the "License").  You may not use this file except in compliance
16  * with the License.
17  *
18  * See the file CDDL.Schily.txt in this distribution for details.
19  * A copy of the CDDL is also available via the Internet at
20  * http://www.opensource.org/licenses/cddl1.txt
21  *
22  * When distributing Covered Code, include this CDDL HEADER in each
23  * file and include the License file CDDL.Schily.txt from this distribution.
24  */
25 
26 #include <schily/stdio.h>
27 #include "star.h"
28 #include "props.h"
29 #include "table.h"
30 #include <schily/dirent.h>
31 #include <schily/standard.h>
32 #include <schily/stdlib.h>
33 #include <schily/string.h>
34 #define	GT_COMERR		/* #define comerr gtcomerr */
35 #define	GT_ERROR		/* #define error gterror   */
36 #include <schily/schily.h>
37 #include "starsubs.h"
38 #ifdef	USE_FIND
39 #include <schily/walk.h>
40 #endif
41 
42 extern	FILE	*tarf;
43 extern	FILE	*vpr;
44 extern	char	*listfile;
45 extern	Llong	curblockno;
46 
47 extern	time_t	sixmonth;		/* 6 months before limit (ls)	*/
48 extern	time_t	now;			/* now limit (ls)		*/
49 
50 extern	BOOL	havepat;
51 extern	int	iftype;
52 extern	BOOL	paxls;
53 extern	int	xdebug;
54 extern	BOOL	numeric;
55 extern	int	verbose;
56 extern	BOOL	prblockno;
57 extern	BOOL	tpath;
58 extern	BOOL	cflag;
59 extern	BOOL	xflag;
60 extern	BOOL	interactive;
61 
62 extern	BOOL	acctime;
63 extern	BOOL	no_dirslash;
64 extern	BOOL	Ctime;
65 extern	BOOL	prinodes;
66 
67 extern	BOOL	listnew;
68 extern	BOOL	listnewf;
69 
70 extern	BOOL	do_subst;
71 
72 #ifdef	USE_FIND
73 extern	BOOL	dofind;
74 #endif
75 
76 EXPORT	void	list		__PR((void));
77 LOCAL	void	modstr		__PR((FINFO *info, char *s, mode_t  mode));
78 EXPORT	void	list_file	__PR((FINFO *info));
79 EXPORT	void	vprint		__PR((FINFO *info));
80 
81 EXPORT void
list()82 list()
83 {
84 #ifdef	USE_FIND
85 extern	struct WALK walkstate;
86 #endif
87 		FINFO	finfo;
88 		FINFO	newinfo;
89 		TCB	tb;
90 		TCB	newtb;
91 	register TCB 	*ptb = &tb;
92 
93 	fillbytes((char *)&finfo, sizeof (finfo), '\0');
94 	fillbytes((char *)&newinfo, sizeof (newinfo), '\0');
95 
96 	if (init_pspace(PS_STDERR, &finfo.f_pname) < 0)
97 		return;
98 	if (init_pspace(PS_STDERR, &finfo.f_plname) < 0)
99 		return;
100 	if (listnew || listnewf) {
101 		if (init_pspace(PS_STDERR, &newinfo.f_pname) < 0)
102 			return;
103 		if (init_pspace(PS_STDERR, &newinfo.f_plname) < 0)
104 			return;
105 	}
106 
107 #ifdef	USE_FIND
108 	if (dofind) {
109 		walkopen(&walkstate);
110 		walkgethome(&walkstate);	/* Needed in case we chdir */
111 	}
112 #endif
113 	finfo.f_tcb = ptb;
114 	for (;;) {
115 		if (get_tcb(ptb) == EOF)
116 			break;
117 		if (prblockno)
118 			(void) tblocks();		/* set curblockno */
119 
120 		finfo.f_name = finfo.f_pname.ps_path;
121 		finfo.f_lname = finfo.f_plname.ps_path;
122 		if (tcb_to_info(ptb, &finfo) == EOF)
123 			break;
124 		if (xdebug > 0)
125 			dump_info(&finfo);
126 
127 #ifdef	USE_FIND
128 		if (dofind && !findinfo(&finfo)) {
129 			void_file(&finfo);
130 			continue;
131 		}
132 #endif
133 
134 		if (do_subst) {
135 			subst(&finfo);
136 		}
137 
138 		if (listnew || listnewf) {
139 			/*
140 			 * Honor nsecs if part of the archive.
141 			 */
142 			if (((finfo.f_mtime > newinfo.f_mtime) ||
143 			    ((finfo.f_xflags & XF_MTIME) &&
144 			    (newinfo.f_xflags & XF_MTIME) &&
145 			    (finfo.f_mtime == newinfo.f_mtime) &&
146 			    (finfo.f_mnsec > newinfo.f_mnsec))) &&
147 					(!listnewf || is_file(&finfo))) {
148 				movebytes(&finfo, &newinfo,
149 						offsetof(FINFO, f_pname));
150 				movetcb(&tb, &newtb);
151 				if (strcpy_pspace(PS_STDERR,
152 						&newinfo.f_pname,
153 						finfo.f_name) < 0) {
154 					newinfo.f_name = "";
155 				} else {
156 					newinfo.f_name =
157 						newinfo.f_pname.ps_path;
158 				}
159 				if (newinfo.f_lname[0] != '\0') {
160 					if (strcpy_pspace(PS_STDERR,
161 							&newinfo.f_plname,
162 							finfo.f_lname) < 0) {
163 						newinfo.f_lname = "";
164 					} else {
165 						newinfo.f_lname =
166 						    newinfo.f_plname.ps_path;
167 					}
168 				}
169 				newinfo.f_flags |= F_HAS_NAME;
170 			}
171 			void_file(&finfo);
172 			continue;
173 		}
174 		if (listfile && !hash_lookup(finfo.f_name)) {
175 			void_file(&finfo);
176 			continue;
177 		}
178 		if (hash_xlookup(finfo.f_name)) {
179 			void_file(&finfo);
180 			continue;
181 		}
182 		if (havepat && !match(finfo.f_name)) {
183 			void_file(&finfo);
184 			continue;
185 		}
186 		list_file(&finfo);
187 		void_file(&finfo);
188 	}
189 #ifdef	USE_FIND
190 	if (dofind) {
191 		walkhome(&walkstate);
192 		walkclose(&walkstate);
193 		free(walkstate.twprivate);
194 	}
195 #endif
196 	if ((listnew || listnewf) && newinfo.f_mtime != 0L) {
197 		/*
198 		 * XXX
199 		 * XXX Achtung!!! tcb_to_info zerst�rt t_name[NAMSIZ]
200 		 * XXX und t_linkname[NAMSIZ].
201 		 * XXX Ist dies noch richtig?
202 		 * XXX Es sieht so aus as ob nur noch t_name[NAMSIZ] auf ' '
203 		 * XXX gesetzt wird wenn dort ein null Byte steht.
204 		 */
205 		if ((props.pr_flags & PR_CPIO) == 0) {
206 			/*
207 			 * Needed to set up the uname/gname fields for the
208 			 * various TAR headers.
209 			 */
210 			tcb_to_info(&newtb, &newinfo);
211 		}
212 		list_file(&newinfo);
213 	}
214 }
215 
216 /*
217  * Convert POSIX.1 TAR mode/permission flags into string.
218  */
219 LOCAL void
220 #ifdef	PROTOTYPES
modstr(FINFO * info,char * s,register mode_t mode)221 modstr(FINFO *info, char *s, register mode_t  mode)
222 #else
223 modstr(info, s, mode)
224 		FINFO	*info;
225 		char	*s;
226 	register mode_t	mode;
227 #endif
228 {
229 	register char	*mstr = "xwrxwrxwr";
230 	register char	*str = s;
231 	register int	i;
232 
233 	*str++ = '?';				/* Unknown file type */
234 	for (i = 9; --i >= 0; ) {
235 		if (mode & (1 << i))
236 			*str++ = mstr[i];
237 		else
238 			*str++ = '-';
239 	}
240 #ifdef	USE_ACL
241 	*str++ = ' ';
242 #endif
243 #ifdef	USE_XATTR
244 	*str++ = '\0';				/* Don't claim space for '@' */
245 #endif
246 	*str = '\0';
247 	str = s;
248 	if (mode & TSVTX) {
249 		if (mode & TOEXEC) {
250 			str[9] = 't';		/* Sticky & exec. by others  */
251 		} else {
252 			str[9] = 'T';		/* Sticky but !exec. by oth  */
253 		}
254 	}
255 	if (mode & TSGID) {
256 		if (mode & TGEXEC) {
257 			str[6] = 's';		/* Sgid & executable by grp  */
258 		} else {
259 			if (!is_file(info))
260 				str[6] = 'S';	/* Sgid directory, or other  */
261 			else
262 				str[6] = 'l';	/* Mandatory lock file	    */
263 		}
264 	}
265 	if (mode & TSUID) {
266 		if (mode & TUEXEC)
267 			str[3] = 's';		/* Suid & executable by own. */
268 		else
269 			str[3] = 'S';		/* Suid but not executable   */
270 	}
271 	i = 10;
272 #ifdef	USE_ACL
273 	if ((info->f_xflags & (XF_ACL_ACCESS|XF_ACL_DEFAULT|XF_ACL_ACE)) != 0)
274 		str[i++] = '+';
275 #endif
276 #ifdef	USE_XATTR
277 	if ((info->f_xflags & XF_XATTR) != 0)
278 		str[i++] = '@';
279 #endif
280 	i++;	/* Make lint believe that we always use i. */
281 }
282 
283 EXPORT void
list_file(info)284 list_file(info)
285 	register FINFO	*info;
286 {
287 		FILE	*f;
288 		time_t	*tp;
289 		char	*tstr;
290 		char	mstr[13]; /* 10 UNIX chars + ACL '+' XATTR '@' + nul */
291 		char	lstr[22]; /* ' ' + link count as string - 64 bits */
292 	static	char	nuid[21]; /* uid as 64 bit long */
293 	static	char	ngid[21]; /* gid as 64 bit long */
294 		char	*add = "";
295 
296 	f = vpr;
297 	if (prblockno)
298 		fgtprintf(f, "block %9lld: ", curblockno);
299 	if (cflag)
300 		fprintf(f, "a ");
301 	else if (xflag)
302 		fprintf(f, "x ");
303 
304 	if (prinodes && info->f_ino > 0)
305 		fprintf(f, "%7llu ", (Llong)info->f_ino);
306 	if (cflag && is_dir(info) && !no_dirslash) {
307 		int	len = info->f_namelen;
308 
309 		if (len == 0)
310 			len = strlen(info->f_name);
311 		if (info->f_name[len-1] != '/')
312 			add = "/";
313 	}
314 	if (verbose) {
315 		register Uint	xft = info->f_xftype;
316 
317 		tp = acctime ? &info->f_atime :
318 				(Ctime ? &info->f_ctime : &info->f_mtime);
319 		tstr = ctime(tp);
320 		if (numeric || info->f_uname == NULL) {
321 			sprintf(nuid, "%lld", (Llong)info->f_uid);
322 			info->f_uname = nuid;
323 			info->f_umaxlen = sizeof (nuid)-1;
324 		}
325 		if (numeric || info->f_gname == NULL) {
326 			sprintf(ngid, "%lld", (Llong)info->f_gid);
327 			info->f_gname = ngid;
328 			info->f_gmaxlen = sizeof (ngid)-1;
329 		}
330 
331 		if (!paxls) {
332 			if (is_special(info))
333 				fprintf(f, "%3lu %3lu",
334 					info->f_rdevmaj, info->f_rdevmin);
335 			else
336 				fprintf(f, "%7llu", (Llong)info->f_size);
337 		}
338 		modstr(info, mstr, info->f_mode);
339 
340 		if (paxls && info->f_nlink == 0 && is_link(info)) {
341 			info->f_nlink = 2;
342 		}
343 		if (paxls || info->f_nlink > 0) {
344 			/*
345 			 * UNIX ls uses %3d for the link count
346 			 * and does not claim space for ACL '+'
347 			 */
348 			js_sprintf(lstr, " %2llu", (Ullong)info->f_nlink);
349 		} else {
350 			lstr[0] = 0;
351 		}
352 /*
353  * XXX �bergangsweise, bis die neue Filetypenomenklatur sauber eingebaut ist.
354  */
355 if (xft == 0 || xft == XT_BAD) {
356 	xft = info->f_xftype = IFTOXT(info->f_type);
357 	errmsgno(EX_BAD, "XXXXX xftype == 0 (typeflag = '%c' 0x%02X)\n",
358 				info->f_typeflag, info->f_typeflag);
359 }
360 		if (xft == XT_LINK)
361 			xft = info->f_rxftype;
362 		{
363 			char	*p = XTTOSTR(xft);
364 
365 			if (p)
366 				mstr[0] = *p;
367 		}
368 		if (!paxls) {
369 			fprintf(f,
370 				" %s%s %3.*s/%-3.*s %.12s %4.4s ",
371 				mstr,
372 				lstr,
373 				(int)info->f_umaxlen, info->f_uname,
374 				(int)info->f_gmaxlen, info->f_gname,
375 				&tstr[4], &tstr[20]);
376 		} else {
377 			fprintf(f,
378 				"%s%s %-8.*s %-8.*s ",
379 				mstr,
380 				lstr,
381 				(int)info->f_umaxlen, info->f_uname,
382 				(int)info->f_gmaxlen, info->f_gname);
383 			if (is_special(info))
384 				fprintf(f, "%3lu %3lu",
385 					info->f_rdevmaj, info->f_rdevmin);
386 			else
387 				fprintf(f, "%7llu", (Llong)info->f_size);
388 			if ((*tp < sixmonth) || (*tp > now)) {
389 				fprintf(f, " %.6s  %4.4s ",
390 					&tstr[4], &tstr[20]);
391 			} else {
392 				fprintf(f, " %.12s ",
393 					&tstr[4]);
394 			}
395 		}
396 	}
397 	fprintf(f, "%s%s", info->f_name, add);
398 	if (tpath) {
399 		fprintf(f, "\n");
400 		return;
401 	}
402 	/*
403 	 * In case of a hardlinked symlink, we currently do not have the symlink
404 	 * target path and thus cannot check the synlink target. So first check
405 	 * whether it is a hardlink.
406 	 */
407 	if (is_link(info)) {
408 		if (is_dir(info))
409 			fgtprintf(f, " directory");
410 		fprintf(f, " %s %s",
411 			paxls ? "==" : "link to",
412 			info->f_lname);
413 	} else if (is_symlink(info))
414 		fprintf(f, " -> %s", info->f_lname);
415 	if (is_volhdr(info))
416 		fgtprintf(f, " --Volume Header--");
417 	if (is_multivol(info)) {
418 		fgtprintf(f, " --Continued at byte %lld--",
419 						(Llong)info->f_contoffset);
420 	}
421 	fprintf(f, "\n");
422 }
423 
424 EXPORT void
vprint(info)425 vprint(info)
426 	FINFO	*info;
427 {
428 		FILE	*f;
429 	char	*mode;
430 	char	*add = "";
431 
432 	if (verbose || interactive) {
433 		if (verbose > 1) {
434 			list_file(info);
435 			return;
436 		}
437 
438 		f = vpr;
439 
440 		if (prblockno)
441 			fgtprintf(f, "block %9lld: ", curblockno);
442 		if (cflag)
443 			mode = "a ";
444 		else if (xflag)
445 			mode = "x ";
446 		else
447 			mode = "";
448 
449 		if (cflag && is_dir(info) && !no_dirslash) {
450 			int	len = info->f_namelen;
451 
452 			if (len == 0)
453 				len = strlen(info->f_name);
454 			if (info->f_name[len-1] != '/')
455 				add = "/";
456 		}
457 		if (tpath) {
458 			fprintf(f, "%s%s\n", info->f_name, add);
459 			return;
460 		}
461 		if (is_dir(info)) {
462 			if (is_link(info)) {
463 				fgtprintf(f, "%s%s%s directory %s %s\n",
464 					mode, info->f_name, add,
465 					paxls ? "==" : "link to",
466 					info->f_lname);
467 			} else {
468 				fgtprintf(f, "%s%s%s directory\n", mode,
469 							info->f_name, add);
470 			}
471 		} else if (is_link(info)) {
472 			fprintf(f, "%s%s %s %s\n",
473 				mode, info->f_name,
474 				paxls ? "==" : "link to",
475 				info->f_lname);
476 		} else if (is_symlink(info)) {
477 			fprintf(f, "%s%s %s %s\n",
478 				mode, info->f_name,
479 				paxls ? "->" : "symbolic link to",
480 				info->f_lname);
481 		} else if (is_special(info)) {
482 			fgtprintf(f, "%s%s special\n", mode, info->f_name);
483 		} else {
484 			fgtprintf(f, "%s%s %lld bytes, %lld tape blocks\n",
485 				mode, info->f_name, (Llong)info->f_size,
486 				(Llong)tarblocks(info->f_rsize));
487 		}
488 	}
489 }
490