xref: /netbsd-src/bin/ls/print.c (revision c98285893d1176364826ef6654c2348bab485a19)
1*c9828589Ssimonb /*	$NetBSD: print.c,v 1.59 2024/12/11 12:56:31 simonb Exp $	*/
249f0ad86Scgd 
361f28255Scgd /*
483ede345Smycroft  * Copyright (c) 1989, 1993, 1994
583ede345Smycroft  *	The Regents of the University of California.  All rights reserved.
661f28255Scgd  *
761f28255Scgd  * This code is derived from software contributed to Berkeley by
861f28255Scgd  * Michael Fischbein.
961f28255Scgd  *
1061f28255Scgd  * Redistribution and use in source and binary forms, with or without
1161f28255Scgd  * modification, are permitted provided that the following conditions
1261f28255Scgd  * are met:
1361f28255Scgd  * 1. Redistributions of source code must retain the above copyright
1461f28255Scgd  *    notice, this list of conditions and the following disclaimer.
1561f28255Scgd  * 2. Redistributions in binary form must reproduce the above copyright
1661f28255Scgd  *    notice, this list of conditions and the following disclaimer in the
1761f28255Scgd  *    documentation and/or other materials provided with the distribution.
18b5b29542Sagc  * 3. Neither the name of the University nor the names of its contributors
1961f28255Scgd  *    may be used to endorse or promote products derived from this software
2061f28255Scgd  *    without specific prior written permission.
2161f28255Scgd  *
2261f28255Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2361f28255Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2461f28255Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2561f28255Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2661f28255Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2761f28255Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2861f28255Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2961f28255Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3061f28255Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3161f28255Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3261f28255Scgd  * SUCH DAMAGE.
3361f28255Scgd  */
3461f28255Scgd 
35b22592e8Schristos #include <sys/cdefs.h>
3661f28255Scgd #ifndef lint
3749f0ad86Scgd #if 0
38d943cdadSjtc static char sccsid[] = "@(#)print.c	8.5 (Berkeley) 7/28/94";
3949f0ad86Scgd #else
40*c9828589Ssimonb __RCSID("$NetBSD: print.c,v 1.59 2024/12/11 12:56:31 simonb Exp $");
4149f0ad86Scgd #endif
4261f28255Scgd #endif /* not lint */
4361f28255Scgd 
4461f28255Scgd #include <sys/param.h>
4561f28255Scgd #include <sys/stat.h>
46f6a91933Schristos #ifndef SMALL
479aa2a9c3Schristos #include <sys/acl.h>
48f6a91933Schristos #endif
4983ede345Smycroft 
5083ede345Smycroft #include <err.h>
51203e4227Smycroft #include <errno.h>
52062900c4Smartin #include <inttypes.h>
5383ede345Smycroft #include <fts.h>
5461f28255Scgd #include <grp.h>
5561f28255Scgd #include <pwd.h>
56203e4227Smycroft #include <stdio.h>
5783ede345Smycroft #include <stdlib.h>
58203e4227Smycroft #include <string.h>
5983ede345Smycroft #include <time.h>
6083ede345Smycroft #include <tzfile.h>
6183ede345Smycroft #include <unistd.h>
62f4c47802Sgrant #include <util.h>
6383ede345Smycroft 
6461f28255Scgd #include "ls.h"
65203e4227Smycroft #include "extern.h"
6661f28255Scgd 
6718d76c32Schristos extern int termwidth;
6818d76c32Schristos 
69ba2e04dcSlukem static int	printaname(FTSENT *, int, int);
70ba2e04dcSlukem static void	printlink(FTSENT *);
71ba2e04dcSlukem static void	printtime(time_t);
72c111d829Sahoka static void	printtotal(DISPLAY *dp);
73ba2e04dcSlukem static int	printtype(u_int);
74f6a91933Schristos #ifndef SMALL
759aa2a9c3Schristos static void	aclmode(char *, const FTSENT *);
76f6a91933Schristos #endif
77203e4227Smycroft 
78d4e67eb2Smycroft static time_t	now;
79d4e67eb2Smycroft 
80203e4227Smycroft #define	IS_NOPRINT(p)	((p)->fts_number == NO_PRINT)
81203e4227Smycroft 
820c47a5c3Schristos static int
830c47a5c3Schristos safe_printpath(const FTSENT *p) {
840c47a5c3Schristos 	int chcnt;
850c47a5c3Schristos 
860c47a5c3Schristos 	if (f_fullpath) {
870c47a5c3Schristos 		chcnt = safe_print(p->fts_path);
880c47a5c3Schristos 		chcnt += safe_print("/");
890c47a5c3Schristos 	} else
900c47a5c3Schristos 		chcnt = 0;
910c47a5c3Schristos 	return chcnt + safe_print(p->fts_name);
920c47a5c3Schristos }
930c47a5c3Schristos 
940c47a5c3Schristos static int
950c47a5c3Schristos printescapedpath(const FTSENT *p) {
960c47a5c3Schristos 	int chcnt;
970c47a5c3Schristos 
980c47a5c3Schristos 	if (f_fullpath) {
990c47a5c3Schristos 		chcnt = printescaped(p->fts_path);
1000c47a5c3Schristos 		chcnt += printescaped("/");
1010c47a5c3Schristos 	} else
1020c47a5c3Schristos 		chcnt = 0;
1030c47a5c3Schristos 
1040c47a5c3Schristos 	return chcnt + printescaped(p->fts_name);
1050c47a5c3Schristos }
1060c47a5c3Schristos 
1070c47a5c3Schristos static int
1080c47a5c3Schristos printpath(const FTSENT *p) {
1090c47a5c3Schristos 	if (f_fullpath)
1100c47a5c3Schristos 		return printf("%s/%s", p->fts_path, p->fts_name);
1110c47a5c3Schristos 	else
112fa4d72b1Smlelstv 		return printf("%s", p->fts_name);
1130c47a5c3Schristos }
1140c47a5c3Schristos 
115203e4227Smycroft void
116ba2e04dcSlukem printscol(DISPLAY *dp)
11761f28255Scgd {
11883ede345Smycroft 	FTSENT *p;
119203e4227Smycroft 
120203e4227Smycroft 	for (p = dp->list; p; p = p->fts_link) {
121203e4227Smycroft 		if (IS_NOPRINT(p))
122203e4227Smycroft 			continue;
123203e4227Smycroft 		(void)printaname(p, dp->s_inode, dp->s_block);
12461f28255Scgd 		(void)putchar('\n');
12561f28255Scgd 	}
12661f28255Scgd }
12761f28255Scgd 
128203e4227Smycroft void
129ba2e04dcSlukem printlong(DISPLAY *dp)
13061f28255Scgd {
13183ede345Smycroft 	struct stat *sp;
13283ede345Smycroft 	FTSENT *p;
133203e4227Smycroft 	NAMES *np;
134f4c47802Sgrant 	char buf[20], szbuf[5];
13561f28255Scgd 
1361381f684Smycroft 	now = time(NULL);
137d4e67eb2Smycroft 
1380c47a5c3Schristos 	if (!f_leafonly)
139c111d829Sahoka 		printtotal(dp);		/* "total: %u\n" */
140203e4227Smycroft 
141203e4227Smycroft 	for (p = dp->list; p; p = p->fts_link) {
142203e4227Smycroft 		if (IS_NOPRINT(p))
143203e4227Smycroft 			continue;
144203e4227Smycroft 		sp = p->fts_statp;
14561f28255Scgd 		if (f_inode)
146062900c4Smartin 			(void)printf("%*"PRIu64" ", dp->s_inode, sp->st_ino);
1470386433dSjschauma 		if (f_size) {
1480386433dSjschauma 			if (f_humanize) {
1490386433dSjschauma 				if ((humanize_number(szbuf, sizeof(szbuf),
1500386433dSjschauma 				    sp->st_blocks * S_BLKSIZE,
1510386433dSjschauma 				    "", HN_AUTOSCALE,
1520386433dSjschauma 				    (HN_DECIMAL | HN_B | HN_NOSPACE))) == -1)
1530386433dSjschauma 					err(1, "humanize_number");
1540386433dSjschauma 				(void)printf("%*s ", dp->s_block, szbuf);
1550386433dSjschauma 			} else {
156cde105a4Schristos 				(void)printf(f_commas ? "%'*llu " : "%*llu ",
157cde105a4Schristos 				    dp->s_block,
158cde105a4Schristos 				    (unsigned long long)howmany(sp->st_blocks,
1590386433dSjschauma 				    blocksize));
1600386433dSjschauma 			}
161f4c47802Sgrant 		}
162203e4227Smycroft 		(void)strmode(sp->st_mode, buf);
163f6a91933Schristos #ifndef SMALL
1649aa2a9c3Schristos 		aclmode(buf, p);
165f6a91933Schristos #endif
166203e4227Smycroft 		np = p->fts_pointer;
16775d0e9d0Sgrant 		(void)printf("%s %*lu ", buf, dp->s_nlink,
16875d0e9d0Sgrant 		    (unsigned long)sp->st_nlink);
16975d0e9d0Sgrant 		if (!f_grouponly)
17075d0e9d0Sgrant 			(void)printf("%-*s  ", dp->s_user, np->user);
17175d0e9d0Sgrant 		(void)printf("%-*s  ", dp->s_group, np->group);
172203e4227Smycroft 		if (f_flags)
173203e4227Smycroft 			(void)printf("%-*s ", dp->s_flags, np->flags);
174203e4227Smycroft 		if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode))
175909ffa32Schristos 			(void)printf("%*lld, %*lld ",
176909ffa32Schristos 			    dp->s_major, (long long)major(sp->st_rdev),
177909ffa32Schristos 			    dp->s_minor, (long long)minor(sp->st_rdev));
17861f28255Scgd 		else
179f4c47802Sgrant 			if (f_humanize) {
180f4c47802Sgrant 				if ((humanize_number(szbuf, sizeof(szbuf),
181f4c47802Sgrant 				    sp->st_size, "", HN_AUTOSCALE,
182f4c47802Sgrant 				    (HN_DECIMAL | HN_B | HN_NOSPACE))) == -1)
183f4c47802Sgrant 					err(1, "humanize_number");
184f4c47802Sgrant 				(void)printf("%*s ", dp->s_size, szbuf);
185f4c47802Sgrant 			} else {
186cde105a4Schristos 				(void)printf(f_commas ? "%'*llu " : "%*llu ",
187cde105a4Schristos 				    dp->s_size, (unsigned long long)
188cde105a4Schristos 				    sp->st_size);
189f4c47802Sgrant 			}
19061f28255Scgd 		if (f_accesstime)
191203e4227Smycroft 			printtime(sp->st_atime);
19261f28255Scgd 		else if (f_statustime)
193203e4227Smycroft 			printtime(sp->st_ctime);
19461f28255Scgd 		else
195203e4227Smycroft 			printtime(sp->st_mtime);
19621ab6335Sjschauma 		if (f_octal || f_octal_escape)
1970c47a5c3Schristos 			(void)safe_printpath(p);
1982ccef82cSjschauma 		else if (f_nonprint)
1990c47a5c3Schristos 			(void)printescapedpath(p);
200c5a80669Sassar 		else
2010c47a5c3Schristos 			(void)printpath(p);
202c5a80669Sassar 
203b424b8feSkleink 		if (f_type || (f_typedir && S_ISDIR(sp->st_mode)))
204203e4227Smycroft 			(void)printtype(sp->st_mode);
205203e4227Smycroft 		if (S_ISLNK(sp->st_mode))
206203e4227Smycroft 			printlink(p);
20761f28255Scgd 		(void)putchar('\n');
20861f28255Scgd 	}
20961f28255Scgd }
21061f28255Scgd 
211203e4227Smycroft void
212ba2e04dcSlukem printcol(DISPLAY *dp)
21361f28255Scgd {
214203e4227Smycroft 	static FTSENT **array;
215203e4227Smycroft 	static int lastentries = -1;
21683ede345Smycroft 	FTSENT *p;
217b22592e8Schristos 	int base, chcnt, col, colwidth, num;
21851175461Sthorpej 	int numcols, numrows, row;
21961f28255Scgd 
220ac591fc0Slukem 	colwidth = dp->maxlen;
221ac591fc0Slukem 	if (f_inode)
222ac591fc0Slukem 		colwidth += dp->s_inode + 1;
223f4c47802Sgrant 	if (f_size) {
224f4c47802Sgrant 		if (f_humanize)
225f4c47802Sgrant 			colwidth += dp->s_size + 1;
226f4c47802Sgrant 		else
227ac591fc0Slukem 			colwidth += dp->s_block + 1;
228f4c47802Sgrant 	}
229b424b8feSkleink 	if (f_type || f_typedir)
230ac591fc0Slukem 		colwidth += 1;
231ac591fc0Slukem 
232ac591fc0Slukem 	colwidth += 1;
233ac591fc0Slukem 
234df291acdSjschauma 	printtotal(dp);				/* "total: %u\n" */
235df291acdSjschauma 
236ac591fc0Slukem 	if (termwidth < 2 * colwidth) {
237ac591fc0Slukem 		printscol(dp);
238ac591fc0Slukem 		return;
239ac591fc0Slukem 	}
240ac591fc0Slukem 
241203e4227Smycroft 	/*
242203e4227Smycroft 	 * Have to do random access in the linked list -- build a table
243203e4227Smycroft 	 * of pointers.
244203e4227Smycroft 	 */
245203e4227Smycroft 	if (dp->entries > lastentries) {
24646583bd0Syamt 		FTSENT **newarray;
24746583bd0Syamt 
24846583bd0Syamt 		newarray = realloc(array, dp->entries * sizeof(FTSENT *));
24946583bd0Syamt 		if (newarray == NULL) {
25085cbf55dSdrochner 			warn(NULL);
251203e4227Smycroft 			printscol(dp);
25246583bd0Syamt 			return;
253203e4227Smycroft 		}
25446583bd0Syamt 		lastentries = dp->entries;
25546583bd0Syamt 		array = newarray;
256203e4227Smycroft 	}
257203e4227Smycroft 	for (p = dp->list, num = 0; p; p = p->fts_link)
258203e4227Smycroft 		if (p->fts_number != NO_PRINT)
259203e4227Smycroft 			array[num++] = p;
260203e4227Smycroft 
261ac591fc0Slukem 	numcols = termwidth / colwidth;
262ac591fc0Slukem 	colwidth = termwidth / numcols;		/* spread out if possible */
263ac591fc0Slukem 	numrows = num / numcols;
264ac591fc0Slukem 	if (num % numcols)
265ac591fc0Slukem 		++numrows;
266ac591fc0Slukem 
267ac591fc0Slukem 	for (row = 0; row < numrows; ++row) {
268ac591fc0Slukem 		for (base = row, chcnt = col = 0; col < numcols; ++col) {
269ac591fc0Slukem 			chcnt = printaname(array[base], dp->s_inode,
270f4c47802Sgrant 			    f_humanize ? dp->s_size : dp->s_block);
271ac591fc0Slukem 			if ((base += numrows) >= num)
272ac591fc0Slukem 				break;
273ac591fc0Slukem 			while (chcnt++ < colwidth)
2741381f684Smycroft 				(void)putchar(' ');
275ac591fc0Slukem 		}
276ac591fc0Slukem 		(void)putchar('\n');
277ac591fc0Slukem 	}
278ac591fc0Slukem }
279ac591fc0Slukem 
280ac591fc0Slukem void
281ba2e04dcSlukem printacol(DISPLAY *dp)
282ac591fc0Slukem {
283ac591fc0Slukem 	FTSENT *p;
284ac591fc0Slukem 	int chcnt, col, colwidth;
285ac591fc0Slukem 	int numcols;
286ac591fc0Slukem 
287203e4227Smycroft 	colwidth = dp->maxlen;
28861f28255Scgd 	if (f_inode)
289203e4227Smycroft 		colwidth += dp->s_inode + 1;
290f4c47802Sgrant 	if (f_size) {
291f4c47802Sgrant 		if (f_humanize)
292f4c47802Sgrant 			colwidth += dp->s_size + 1;
293f4c47802Sgrant 		else
294203e4227Smycroft 			colwidth += dp->s_block + 1;
295f4c47802Sgrant 	}
296b424b8feSkleink 	if (f_type || f_typedir)
29761f28255Scgd 		colwidth += 1;
29861f28255Scgd 
29951175461Sthorpej 	colwidth += 1;
30051175461Sthorpej 
301df291acdSjschauma 	printtotal(dp);				/* "total: %u\n" */
302df291acdSjschauma 
30361f28255Scgd 	if (termwidth < 2 * colwidth) {
304203e4227Smycroft 		printscol(dp);
30561f28255Scgd 		return;
30661f28255Scgd 	}
30761f28255Scgd 
30861f28255Scgd 	numcols = termwidth / colwidth;
30951175461Sthorpej 	colwidth = termwidth / numcols;		/* spread out if possible */
31061f28255Scgd 
311ac591fc0Slukem 	chcnt = col = 0;
312ac591fc0Slukem 	for (p = dp->list; p; p = p->fts_link) {
313ac591fc0Slukem 		if (IS_NOPRINT(p))
314ac591fc0Slukem 			continue;
315ac591fc0Slukem 		if (col >= numcols) {
316ac591fc0Slukem 			chcnt = col = 0;
3171381f684Smycroft 			(void)putchar('\n');
318ac591fc0Slukem 		}
319f4c47802Sgrant 		chcnt = printaname(p, dp->s_inode,
320f4c47802Sgrant 		    f_humanize ? dp->s_size : dp->s_block);
32151175461Sthorpej 		while (chcnt++ < colwidth)
3221381f684Smycroft 			(void)putchar(' ');
323ac591fc0Slukem 		col++;
32461f28255Scgd 	}
3251381f684Smycroft 	(void)putchar('\n');
32661f28255Scgd }
32761f28255Scgd 
328b7443b0fSkleink void
329ba2e04dcSlukem printstream(DISPLAY *dp)
330b7443b0fSkleink {
331b7443b0fSkleink 	FTSENT *p;
332b7443b0fSkleink 	int col;
333b7443b0fSkleink 	int extwidth;
334b7443b0fSkleink 
335b7443b0fSkleink 	extwidth = 0;
336b7443b0fSkleink 	if (f_inode)
337b7443b0fSkleink 		extwidth += dp->s_inode + 1;
338f4c47802Sgrant 	if (f_size) {
339f4c47802Sgrant 		if (f_humanize)
340f4c47802Sgrant 			extwidth += dp->s_size + 1;
341f4c47802Sgrant 		else
342b7443b0fSkleink 			extwidth += dp->s_block + 1;
343f4c47802Sgrant 	}
344b7443b0fSkleink 	if (f_type)
345b7443b0fSkleink 		extwidth += 1;
346b7443b0fSkleink 
347b7443b0fSkleink 	for (col = 0, p = dp->list; p != NULL; p = p->fts_link) {
348b7443b0fSkleink 		if (IS_NOPRINT(p))
349b7443b0fSkleink 			continue;
350b7443b0fSkleink 		if (col > 0) {
351b7443b0fSkleink 			(void)putchar(','), col++;
352990d25a9Slukem 			if (col + 1 + extwidth + (int)p->fts_namelen >= termwidth)
353b7443b0fSkleink 				(void)putchar('\n'), col = 0;
354b7443b0fSkleink 			else
355b7443b0fSkleink 				(void)putchar(' '), col++;
356b7443b0fSkleink 		}
357f4c47802Sgrant 		col += printaname(p, dp->s_inode,
358f4c47802Sgrant 		    f_humanize ? dp->s_size : dp->s_block);
359b7443b0fSkleink 	}
360b7443b0fSkleink 	(void)putchar('\n');
361b7443b0fSkleink }
362b7443b0fSkleink 
36361f28255Scgd /*
36461f28255Scgd  * print [inode] [size] name
365203e4227Smycroft  * return # of characters printed, no trailing characters.
36661f28255Scgd  */
367203e4227Smycroft static int
368ba2e04dcSlukem printaname(FTSENT *p, int inodefield, int sizefield)
36961f28255Scgd {
370203e4227Smycroft 	struct stat *sp;
37161f28255Scgd 	int chcnt;
372f4c47802Sgrant 	char szbuf[5];
37361f28255Scgd 
374203e4227Smycroft 	sp = p->fts_statp;
37561f28255Scgd 	chcnt = 0;
37661f28255Scgd 	if (f_inode)
377062900c4Smartin 		chcnt += printf("%*"PRIu64" ", inodefield, sp->st_ino);
378f4c47802Sgrant 	if (f_size) {
379f4c47802Sgrant 		if (f_humanize) {
380f4c47802Sgrant 			if ((humanize_number(szbuf, sizeof(szbuf), sp->st_size,
381f4c47802Sgrant 			    "", HN_AUTOSCALE,
382f4c47802Sgrant 			    (HN_DECIMAL | HN_B | HN_NOSPACE))) == -1)
383f4c47802Sgrant 				err(1, "humanize_number");
384f4c47802Sgrant 			chcnt += printf("%*s ", sizefield, szbuf);
385f4c47802Sgrant 		} else {
386cde105a4Schristos 			chcnt += printf(f_commas ? "%'*llu " : "%*llu ",
387cde105a4Schristos 			    sizefield, (unsigned long long)
388cde105a4Schristos 			    howmany(sp->st_blocks, blocksize));
389f4c47802Sgrant 		}
390f4c47802Sgrant 	}
39121ab6335Sjschauma 	if (f_octal || f_octal_escape)
3920c47a5c3Schristos 		chcnt += safe_printpath(p);
3932ccef82cSjschauma 	else if (f_nonprint)
3940c47a5c3Schristos 		chcnt += printescapedpath(p);
395b23df5beSassar 	else
3960c47a5c3Schristos 		chcnt += printpath(p);
397b424b8feSkleink 	if (f_type || (f_typedir && S_ISDIR(sp->st_mode)))
398203e4227Smycroft 		chcnt += printtype(sp->st_mode);
39961f28255Scgd 	return (chcnt);
40061f28255Scgd }
40161f28255Scgd 
402203e4227Smycroft static void
403ba2e04dcSlukem printtime(time_t ftime)
40461f28255Scgd {
40561f28255Scgd 	int i;
406221f2e33Schristos 	const char *longstring;
40761f28255Scgd 
408b22f1047Schristos 	if ((longstring = ctime(&ftime)) == NULL) {
409221f2e33Schristos 			   /* 012345678901234567890123 */
410221f2e33Schristos 		longstring = "????????????????????????";
411221f2e33Schristos 	}
41261f28255Scgd 	for (i = 4; i < 11; ++i)
41361f28255Scgd 		(void)putchar(longstring[i]);
41461f28255Scgd 
41561f28255Scgd #define	SIXMONTHS	((DAYSPERNYEAR / 2) * SECSPERDAY)
41661f28255Scgd 	if (f_sectime)
41761f28255Scgd 		for (i = 11; i < 24; i++)
41861f28255Scgd 			(void)putchar(longstring[i]);
41975a40767Smycroft 	else if (ftime + SIXMONTHS > now && ftime - SIXMONTHS < now)
42061f28255Scgd 		for (i = 11; i < 16; ++i)
42161f28255Scgd 			(void)putchar(longstring[i]);
42261f28255Scgd 	else {
42361f28255Scgd 		(void)putchar(' ');
42461f28255Scgd 		for (i = 20; i < 24; ++i)
42561f28255Scgd 			(void)putchar(longstring[i]);
42661f28255Scgd 	}
42761f28255Scgd 	(void)putchar(' ');
42861f28255Scgd }
42961f28255Scgd 
430c111d829Sahoka /*
431c111d829Sahoka  * Display total used disk space in the form "total: %u\n".
432c111d829Sahoka  * Note: POSIX (IEEE Std 1003.1-2001) says this should be always in 512 blocks,
4334aaf499cSerh  * but we humanise it with -h, or separate it with commas with -M, and use 1024
4344aaf499cSerh  * with -k.
435c111d829Sahoka  */
436c111d829Sahoka static void
437c111d829Sahoka printtotal(DISPLAY *dp)
438c111d829Sahoka {
439c111d829Sahoka 	char szbuf[5];
440c111d829Sahoka 
441c111d829Sahoka 	if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) {
442c111d829Sahoka 		if (f_humanize) {
443*c9828589Ssimonb 			if ((humanize_number(szbuf, sizeof(szbuf),
444*c9828589Ssimonb 			    dp->btotal * POSIX_BLOCK_SIZE,
445c111d829Sahoka 			    "", HN_AUTOSCALE,
446c111d829Sahoka 			    (HN_DECIMAL | HN_B | HN_NOSPACE))) == -1)
447c111d829Sahoka 				err(1, "humanize_number");
448c111d829Sahoka 			(void)printf("total %s\n", szbuf);
449c111d829Sahoka 		} else {
450cde105a4Schristos 			(void)printf(f_commas ? "total %'llu\n" :
451cde105a4Schristos 			    "total %llu\n", (unsigned long long)
452cde105a4Schristos 			    howmany(dp->btotal, blocksize));
453c111d829Sahoka 		}
454c111d829Sahoka 	}
455c111d829Sahoka }
456c111d829Sahoka 
457203e4227Smycroft static int
458ba2e04dcSlukem printtype(u_int mode)
45961f28255Scgd {
46061f28255Scgd 	switch (mode & S_IFMT) {
46161f28255Scgd 	case S_IFDIR:
46261f28255Scgd 		(void)putchar('/');
46361f28255Scgd 		return (1);
46483ede345Smycroft 	case S_IFIFO:
46583ede345Smycroft 		(void)putchar('|');
46683ede345Smycroft 		return (1);
46761f28255Scgd 	case S_IFLNK:
46861f28255Scgd 		(void)putchar('@');
46961f28255Scgd 		return (1);
47061f28255Scgd 	case S_IFSOCK:
47161f28255Scgd 		(void)putchar('=');
47261f28255Scgd 		return (1);
473d966913fSmycroft 	case S_IFWHT:
474d966913fSmycroft 		(void)putchar('%');
475d966913fSmycroft 		return (1);
47661f28255Scgd 	}
47761f28255Scgd 	if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
47861f28255Scgd 		(void)putchar('*');
47961f28255Scgd 		return (1);
48061f28255Scgd 	}
48161f28255Scgd 	return (0);
48261f28255Scgd }
48361f28255Scgd 
484203e4227Smycroft static void
485ba2e04dcSlukem printlink(FTSENT *p)
48661f28255Scgd {
48761f28255Scgd 	int lnklen;
488203e4227Smycroft 	char name[MAXPATHLEN + 1], path[MAXPATHLEN + 1];
48961f28255Scgd 
490203e4227Smycroft 	if (p->fts_level == FTS_ROOTLEVEL)
491203e4227Smycroft 		(void)snprintf(name, sizeof(name), "%s", p->fts_name);
492203e4227Smycroft 	else
49383ede345Smycroft 		(void)snprintf(name, sizeof(name),
49483ede345Smycroft 		    "%s/%s", p->fts_parent->fts_accpath, p->fts_name);
49583ede345Smycroft 	if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) {
49661f28255Scgd 		(void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno));
49761f28255Scgd 		return;
49861f28255Scgd 	}
49961f28255Scgd 	path[lnklen] = '\0';
500c5a80669Sassar 	(void)printf(" -> ");
50121ab6335Sjschauma 	if (f_octal || f_octal_escape)
5022ccef82cSjschauma 		(void)safe_print(path);
5032ccef82cSjschauma 	else if (f_nonprint)
5042ccef82cSjschauma 		(void)printescaped(path);
505c5a80669Sassar 	else
506c5a80669Sassar 		(void)printf("%s", path);
50761f28255Scgd }
5089aa2a9c3Schristos 
509f6a91933Schristos #ifndef SMALL
5109aa2a9c3Schristos /*
5119aa2a9c3Schristos  * Add a + after the standard rwxrwxrwx mode if the file has an
5129aa2a9c3Schristos  * ACL. strmode() reserves space at the end of the string.
5139aa2a9c3Schristos  */
5149aa2a9c3Schristos static void
5159aa2a9c3Schristos aclmode(char *buf, const FTSENT *p)
5169aa2a9c3Schristos {
5179aa2a9c3Schristos 	char name[MAXPATHLEN + 1];
5189aa2a9c3Schristos 	int ret, trivial;
5199aa2a9c3Schristos 	static dev_t previous_dev = NODEV;
5209aa2a9c3Schristos 	static int supports_acls = -1;
5219aa2a9c3Schristos 	static int type = ACL_TYPE_ACCESS;
5229aa2a9c3Schristos 	acl_t facl;
5239aa2a9c3Schristos 
5249aa2a9c3Schristos 	/*
5259aa2a9c3Schristos 	 * XXX: ACLs are not supported on whiteouts and device files
5269aa2a9c3Schristos 	 * residing on UFS.
5279aa2a9c3Schristos 	 */
5289aa2a9c3Schristos 	if (S_ISCHR(p->fts_statp->st_mode) || S_ISBLK(p->fts_statp->st_mode) ||
5299aa2a9c3Schristos 	    S_ISWHT(p->fts_statp->st_mode))
5309aa2a9c3Schristos 		return;
5319aa2a9c3Schristos 
5329aa2a9c3Schristos 	if (previous_dev == p->fts_statp->st_dev && supports_acls == 0)
5339aa2a9c3Schristos 		return;
5349aa2a9c3Schristos 
5359aa2a9c3Schristos 	if (p->fts_level == FTS_ROOTLEVEL)
5369aa2a9c3Schristos 		snprintf(name, sizeof(name), "%s", p->fts_name);
5379aa2a9c3Schristos 	else
5389aa2a9c3Schristos 		snprintf(name, sizeof(name), "%s/%s",
5399aa2a9c3Schristos 		    p->fts_parent->fts_accpath, p->fts_name);
5409aa2a9c3Schristos 
5419aa2a9c3Schristos 	if (supports_acls == -1 || previous_dev != p->fts_statp->st_dev) {
5429aa2a9c3Schristos 		previous_dev = p->fts_statp->st_dev;
5439aa2a9c3Schristos 		supports_acls = 0;
5449aa2a9c3Schristos 
5459aa2a9c3Schristos 		ret = lpathconf(name, _PC_ACL_NFS4);
5469aa2a9c3Schristos 		if (ret > 0) {
5479aa2a9c3Schristos 			type = ACL_TYPE_NFS4;
5489aa2a9c3Schristos 			supports_acls = 1;
5499aa2a9c3Schristos 		} else if (ret < 0 && errno != EINVAL) {
5509aa2a9c3Schristos 			warn("%s", name);
5519aa2a9c3Schristos 			return;
5529aa2a9c3Schristos 		}
5539aa2a9c3Schristos 		if (supports_acls == 0) {
5549aa2a9c3Schristos 			ret = lpathconf(name, _PC_ACL_EXTENDED);
5559aa2a9c3Schristos 			if (ret > 0) {
5569aa2a9c3Schristos 				type = ACL_TYPE_ACCESS;
5579aa2a9c3Schristos 				supports_acls = 1;
5589aa2a9c3Schristos 			} else if (ret < 0 && errno != EINVAL) {
5599aa2a9c3Schristos 				warn("%s", name);
5609aa2a9c3Schristos 				return;
5619aa2a9c3Schristos 			}
5629aa2a9c3Schristos 		}
5639aa2a9c3Schristos 	}
5649aa2a9c3Schristos 	if (supports_acls == 0)
5659aa2a9c3Schristos 		return;
5669aa2a9c3Schristos 	facl = acl_get_link_np(name, type);
5679aa2a9c3Schristos 	if (facl == NULL) {
5689aa2a9c3Schristos 		warn("%s", name);
5699aa2a9c3Schristos 		return;
5709aa2a9c3Schristos 	}
5719aa2a9c3Schristos 	if (acl_is_trivial_np(facl, &trivial)) {
5729aa2a9c3Schristos 		acl_free(facl);
5739aa2a9c3Schristos 		warn("%s", name);
5749aa2a9c3Schristos 		return;
5759aa2a9c3Schristos 	}
5769aa2a9c3Schristos 	if (!trivial)
5779aa2a9c3Schristos 		buf[10] = '+';
5789aa2a9c3Schristos 	acl_free(facl);
5799aa2a9c3Schristos }
580f6a91933Schristos #endif
581