print.c revision 177942
1139969Simp/*-
21556Srgrimes * Copyright (c) 1989, 1993, 1994
31556Srgrimes *	The Regents of the University of California.  All rights reserved.
41556Srgrimes *
51556Srgrimes * This code is derived from software contributed to Berkeley by
61556Srgrimes * Michael Fischbein.
71556Srgrimes *
81556Srgrimes * Redistribution and use in source and binary forms, with or without
91556Srgrimes * modification, are permitted provided that the following conditions
101556Srgrimes * are met:
111556Srgrimes * 1. Redistributions of source code must retain the above copyright
121556Srgrimes *    notice, this list of conditions and the following disclaimer.
131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141556Srgrimes *    notice, this list of conditions and the following disclaimer in the
151556Srgrimes *    documentation and/or other materials provided with the distribution.
161556Srgrimes * 4. Neither the name of the University nor the names of its contributors
171556Srgrimes *    may be used to endorse or promote products derived from this software
181556Srgrimes *    without specific prior written permission.
191556Srgrimes *
201556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301556Srgrimes * SUCH DAMAGE.
311556Srgrimes */
321556Srgrimes
3390153Smarkm#if 0
341556Srgrimes#ifndef lint
3527967Sstevestatic char sccsid[] = "@(#)print.c	8.4 (Berkeley) 4/17/94";
3690153Smarkm#endif /* not lint */
3727967Ssteve#endif
3899109Sobrien#include <sys/cdefs.h>
3999109Sobrien__FBSDID("$FreeBSD: head/bin/ls/print.c 177942 2008-04-05 21:26:25Z imp $");
401556Srgrimes
411556Srgrimes#include <sys/param.h>
421556Srgrimes#include <sys/stat.h>
43106371Stjr#include <sys/acl.h>
441556Srgrimes
451556Srgrimes#include <err.h>
461556Srgrimes#include <errno.h>
471556Srgrimes#include <fts.h>
4874566Sache#include <langinfo.h>
49129719Spjd#include <libutil.h>
501556Srgrimes#include <stdio.h>
511556Srgrimes#include <stdlib.h>
521556Srgrimes#include <string.h>
5391212Sbde#include <time.h>
541556Srgrimes#include <unistd.h>
5561294Sache#ifdef COLORLS
5661294Sache#include <ctype.h>
5761294Sache#include <termcap.h>
5861294Sache#include <signal.h>
5961294Sache#endif
601556Srgrimes
611556Srgrimes#include "ls.h"
621556Srgrimes#include "extern.h"
631556Srgrimes
64114583Smarkmstatic int	printaname(const FTSENT *, u_long, u_long);
65105780Smarkmstatic void	printlink(const FTSENT *);
6690110Simpstatic void	printtime(time_t);
6790110Simpstatic int	printtype(u_int);
6890110Simpstatic void	printsize(size_t, off_t);
6961321Sache#ifdef COLORLS
7090110Simpstatic void	endcolor(int);
7190110Simpstatic int	colortype(mode_t);
7261321Sache#endif
73114583Smarkmstatic void	aclmode(char *, const FTSENT *, int *);
741556Srgrimes
751556Srgrimes#define	IS_NOPRINT(p)	((p)->fts_number == NO_PRINT)
761556Srgrimes
7761268Sjoe#ifdef COLORLS
7861178Sjoe/* Most of these are taken from <sys/stat.h> */
7961178Sjoetypedef enum Colors {
8088602Sjoe	C_DIR,			/* directory */
8188602Sjoe	C_LNK,			/* symbolic link */
8288602Sjoe	C_SOCK,			/* socket */
8388602Sjoe	C_FIFO,			/* pipe */
8488602Sjoe	C_EXEC,			/* executable */
8588602Sjoe	C_BLK,			/* block special */
8688602Sjoe	C_CHR,			/* character special */
8788602Sjoe	C_SUID,			/* setuid executable */
8888602Sjoe	C_SGID,			/* setgid executable */
8988602Sjoe	C_WSDIR,		/* directory writeble to others, with sticky
9088602Sjoe				 * bit */
9188602Sjoe	C_WDIR,			/* directory writeble to others, without
9288602Sjoe				 * sticky bit */
9388602Sjoe	C_NUMCOLORS		/* just a place-holder */
9488586Sjoe} Colors;
9561178Sjoe
9690150Smarkmstatic const char *defcolors = "exfxcxdxbxegedabagacad";
9761178Sjoe
9888583Sjoe/* colors for file types */
9988583Sjoestatic struct {
10088586Sjoe	int	num[2];
10188586Sjoe	int	bold;
10288583Sjoe} colors[C_NUMCOLORS];
10361268Sjoe#endif
10461178Sjoe
1051556Srgrimesvoid
106114583Smarkmprintscol(const DISPLAY *dp)
1071556Srgrimes{
10888594Sjoe	FTSENT *p;
1091556Srgrimes
1101556Srgrimes	for (p = dp->list; p; p = p->fts_link) {
1111556Srgrimes		if (IS_NOPRINT(p))
1121556Srgrimes			continue;
1131556Srgrimes		(void)printaname(p, dp->s_inode, dp->s_block);
1141556Srgrimes		(void)putchar('\n');
1151556Srgrimes	}
1161556Srgrimes}
1171556Srgrimes
11862597Sassar/*
11962597Sassar * print name in current style
12062597Sassar */
121105390Stjrint
12290110Simpprintname(const char *name)
12362597Sassar{
12462597Sassar	if (f_octal || f_octal_escape)
12562597Sassar		return prn_octal(name);
12662597Sassar	else if (f_nonprint)
12762597Sassar		return prn_printable(name);
12862597Sassar	else
129128823Stjr		return prn_normal(name);
13062597Sassar}
13162597Sassar
1321556Srgrimesvoid
133114583Smarkmprintlong(const DISPLAY *dp)
1341556Srgrimes{
1351556Srgrimes	struct stat *sp;
13688594Sjoe	FTSENT *p;
13788594Sjoe	NAMES *np;
13888594Sjoe	char buf[20];
13961292Sache#ifdef COLORLS
14088594Sjoe	int color_printed = 0;
14161292Sache#endif
142106371Stjr	int haveacls;
143106371Stjr	dev_t prevdev;
1441556Srgrimes
145130236Sdas	if ((dp->list == NULL || dp->list->fts_level != FTS_ROOTLEVEL) &&
146130236Sdas	    (f_longform || f_size)) {
1471556Srgrimes		(void)printf("total %lu\n", howmany(dp->btotal, blocksize));
148130236Sdas	}
1491556Srgrimes
150106371Stjr	haveacls = 1;
151106371Stjr	prevdev = (dev_t)-1;
1521556Srgrimes	for (p = dp->list; p; p = p->fts_link) {
1531556Srgrimes		if (IS_NOPRINT(p))
1541556Srgrimes			continue;
1551556Srgrimes		sp = p->fts_statp;
1561556Srgrimes		if (f_inode)
15720417Ssteve			(void)printf("%*lu ", dp->s_inode, (u_long)sp->st_ino);
1581556Srgrimes		if (f_size)
159114583Smarkm			(void)printf("%*jd ",
1601556Srgrimes			    dp->s_block, howmany(sp->st_blocks, blocksize));
16190150Smarkm		strmode(sp->st_mode, buf);
162106371Stjr		/*
163106371Stjr		 * Cache whether or not the filesystem supports ACL's to
164106371Stjr		 * avoid expensive syscalls. Try again when we change devices.
165106371Stjr		 */
166106371Stjr		if (haveacls || sp->st_dev != prevdev) {
167106371Stjr			aclmode(buf, p, &haveacls);
168106371Stjr			prevdev = sp->st_dev;
169106371Stjr		}
1701556Srgrimes		np = p->fts_pointer;
171177942Simp		(void)printf("%s %*u %-*s  %-*s  ", buf, dp->s_nlink,
1721556Srgrimes		    sp->st_nlink, dp->s_user, np->user, dp->s_group,
1731556Srgrimes		    np->group);
1741556Srgrimes		if (f_flags)
1751556Srgrimes			(void)printf("%-*s ", dp->s_flags, np->flags);
176105832Srwatson		if (f_label)
177105832Srwatson			(void)printf("%-*s ", dp->s_label, np->label);
1781556Srgrimes		if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode))
17955514Sbde			if (minor(sp->st_rdev) > 255 || minor(sp->st_rdev) < 0)
18013120Sjoerg				(void)printf("%3d, 0x%08x ",
18155514Sbde				    major(sp->st_rdev),
18255514Sbde				    (u_int)minor(sp->st_rdev));
18313120Sjoerg			else
18413120Sjoerg				(void)printf("%3d, %3d ",
18513120Sjoerg				    major(sp->st_rdev), minor(sp->st_rdev));
1861556Srgrimes		else if (dp->bcfile)
187114583Smarkm			(void)printf("%*s%*jd ",
1881556Srgrimes			    8 - dp->s_size, "", dp->s_size, sp->st_size);
1891556Srgrimes		else
19088591Sjoe			printsize(dp->s_size, sp->st_size);
1911556Srgrimes		if (f_accesstime)
1921556Srgrimes			printtime(sp->st_atime);
193157098Sjhb		else if (f_birthtime)
194157098Sjhb			printtime(sp->st_birthtime);
1951556Srgrimes		else if (f_statustime)
1961556Srgrimes			printtime(sp->st_ctime);
1971556Srgrimes		else
1981556Srgrimes			printtime(sp->st_mtime);
19961268Sjoe#ifdef COLORLS
20061178Sjoe		if (f_color)
20161291Sache			color_printed = colortype(sp->st_mode);
20261268Sjoe#endif
20362597Sassar		(void)printname(p->fts_name);
20461268Sjoe#ifdef COLORLS
20561291Sache		if (f_color && color_printed)
20661321Sache			endcolor(0);
20761268Sjoe#endif
2081556Srgrimes		if (f_type)
2091556Srgrimes			(void)printtype(sp->st_mode);
2101556Srgrimes		if (S_ISLNK(sp->st_mode))
2111556Srgrimes			printlink(p);
2121556Srgrimes		(void)putchar('\n');
2131556Srgrimes	}
2141556Srgrimes}
2151556Srgrimes
2161556Srgrimesvoid
217114583Smarkmprintstream(const DISPLAY *dp)
21896892Stjr{
21996892Stjr	FTSENT *p;
22096892Stjr	int chcnt;
22196892Stjr
22296892Stjr	for (p = dp->list, chcnt = 0; p; p = p->fts_link) {
22396892Stjr		if (p->fts_number == NO_PRINT)
22496892Stjr			continue;
225128823Stjr		/* XXX strlen does not take octal escapes into account. */
22696892Stjr		if (strlen(p->fts_name) + chcnt +
22796892Stjr		    (p->fts_link ? 2 : 0) >= (unsigned)termwidth) {
22896892Stjr			putchar('\n');
22996892Stjr			chcnt = 0;
23096892Stjr		}
23196892Stjr		chcnt += printaname(p, dp->s_inode, dp->s_block);
23296892Stjr		if (p->fts_link) {
23396892Stjr			printf(", ");
23496892Stjr			chcnt += 2;
23596892Stjr		}
23696892Stjr	}
23796892Stjr	if (chcnt)
23896892Stjr		putchar('\n');
23996892Stjr}
240177907Sgrog
24196892Stjrvoid
242114583Smarkmprintcol(const DISPLAY *dp)
2431556Srgrimes{
2441556Srgrimes	static FTSENT **array;
2451556Srgrimes	static int lastentries = -1;
24688594Sjoe	FTSENT *p;
247121124Stjr	FTSENT **narray;
24888594Sjoe	int base;
24988594Sjoe	int chcnt;
25088594Sjoe	int cnt;
25188594Sjoe	int col;
25288594Sjoe	int colwidth;
25388594Sjoe	int endcol;
25488594Sjoe	int num;
25588594Sjoe	int numcols;
25688594Sjoe	int numrows;
25788594Sjoe	int row;
25888594Sjoe	int tabwidth;
2591556Srgrimes
26037932Shoek	if (f_notabs)
26137932Shoek		tabwidth = 1;
26237932Shoek	else
26337932Shoek		tabwidth = 8;
26437932Shoek
2651556Srgrimes	/*
2661556Srgrimes	 * Have to do random access in the linked list -- build a table
2671556Srgrimes	 * of pointers.
2681556Srgrimes	 */
2691556Srgrimes	if (dp->entries > lastentries) {
270121124Stjr		if ((narray =
2711556Srgrimes		    realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) {
2721556Srgrimes			warn(NULL);
2731556Srgrimes			printscol(dp);
274121124Stjr			return;
2751556Srgrimes		}
276121124Stjr		lastentries = dp->entries;
277121124Stjr		array = narray;
2781556Srgrimes	}
2791556Srgrimes	for (p = dp->list, num = 0; p; p = p->fts_link)
2801556Srgrimes		if (p->fts_number != NO_PRINT)
2811556Srgrimes			array[num++] = p;
2821556Srgrimes
2831556Srgrimes	colwidth = dp->maxlen;
2841556Srgrimes	if (f_inode)
2851556Srgrimes		colwidth += dp->s_inode + 1;
2861556Srgrimes	if (f_size)
2871556Srgrimes		colwidth += dp->s_block + 1;
2881556Srgrimes	if (f_type)
2891556Srgrimes		colwidth += 1;
2901556Srgrimes
29137932Shoek	colwidth = (colwidth + tabwidth) & ~(tabwidth - 1);
2921556Srgrimes	if (termwidth < 2 * colwidth) {
2931556Srgrimes		printscol(dp);
2941556Srgrimes		return;
2951556Srgrimes	}
2961556Srgrimes	numcols = termwidth / colwidth;
2971556Srgrimes	numrows = num / numcols;
2981556Srgrimes	if (num % numcols)
2991556Srgrimes		++numrows;
3001556Srgrimes
301130236Sdas	if ((dp->list == NULL || dp->list->fts_level != FTS_ROOTLEVEL) &&
302130236Sdas	    (f_longform || f_size)) {
3031556Srgrimes		(void)printf("total %lu\n", howmany(dp->btotal, blocksize));
304130236Sdas	}
30596892Stjr
306102577Skeramida	base = 0;
3071556Srgrimes	for (row = 0; row < numrows; ++row) {
3081556Srgrimes		endcol = colwidth;
30996892Stjr		if (!f_sortacross)
31096892Stjr			base = row;
31196892Stjr		for (col = 0, chcnt = 0; col < numcols; ++col) {
3121556Srgrimes			chcnt += printaname(array[base], dp->s_inode,
3131556Srgrimes			    dp->s_block);
31496892Stjr			if (f_sortacross)
31596892Stjr				base++;
31696892Stjr			else
31796892Stjr				base += numrows;
31896892Stjr			if (base >= num)
3191556Srgrimes				break;
32037932Shoek			while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1)))
32188595Sjoe			    <= endcol) {
32296892Stjr				if (f_sortacross && col + 1 >= numcols)
32396892Stjr					break;
32437932Shoek				(void)putchar(f_notabs ? ' ' : '\t');
3251556Srgrimes				chcnt = cnt;
3261556Srgrimes			}
3271556Srgrimes			endcol += colwidth;
3281556Srgrimes		}
3291556Srgrimes		(void)putchar('\n');
3301556Srgrimes	}
3311556Srgrimes}
3321556Srgrimes
3331556Srgrimes/*
3341556Srgrimes * print [inode] [size] name
3351556Srgrimes * return # of characters printed, no trailing characters.
3361556Srgrimes */
3371556Srgrimesstatic int
338114583Smarkmprintaname(const FTSENT *p, u_long inodefield, u_long sizefield)
3391556Srgrimes{
3401556Srgrimes	struct stat *sp;
34188594Sjoe	int chcnt;
34261292Sache#ifdef COLORLS
34388594Sjoe	int color_printed = 0;
34461292Sache#endif
3451556Srgrimes
3461556Srgrimes	sp = p->fts_statp;
3471556Srgrimes	chcnt = 0;
3481556Srgrimes	if (f_inode)
34920417Ssteve		chcnt += printf("%*lu ", (int)inodefield, (u_long)sp->st_ino);
3501556Srgrimes	if (f_size)
351114583Smarkm		chcnt += printf("%*jd ",
3521556Srgrimes		    (int)sizefield, howmany(sp->st_blocks, blocksize));
35361268Sjoe#ifdef COLORLS
35461178Sjoe	if (f_color)
35561291Sache		color_printed = colortype(sp->st_mode);
35661268Sjoe#endif
35762597Sassar	chcnt += printname(p->fts_name);
35861268Sjoe#ifdef COLORLS
35961291Sache	if (f_color && color_printed)
36061321Sache		endcolor(0);
36161268Sjoe#endif
3621556Srgrimes	if (f_type)
3631556Srgrimes		chcnt += printtype(sp->st_mode);
3641556Srgrimes	return (chcnt);
3651556Srgrimes}
3661556Srgrimes
3671556Srgrimesstatic void
36890110Simpprinttime(time_t ftime)
3691556Srgrimes{
37088594Sjoe	char longstring[80];
371114583Smarkm	static time_t now = 0;
37288594Sjoe	const char *format;
37388594Sjoe	static int d_first = -1;
3741556Srgrimes
37574566Sache	if (d_first < 0)
37674566Sache		d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
37721545Smpp	if (now == 0)
37821545Smpp		now = time(NULL);
37921545Smpp
3809987Swollman#define	SIXMONTHS	((365 / 2) * 86400)
381177907Sgrog	if (f_timeformat)  /* user specified format */
382177907Sgrog		format = f_timeformat;
383177907Sgrog	else if (f_sectime)
38461920Sjoe		/* mmm dd hh:mm:ss yyyy || dd mmm hh:mm:ss yyyy */
385177907Sgrog		format = d_first ? "%e %b %T %Y" : "%b %e %T %Y";
38621545Smpp	else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS)
38761920Sjoe		/* mmm dd hh:mm || dd mmm hh:mm */
388177907Sgrog		format = d_first ? "%e %b %R" : "%b %e %R";
38961814Sjoe	else
39061920Sjoe		/* mmm dd  yyyy || dd mmm  yyyy */
391177942Simp		format = d_first ? "%e %b  %Y" : "%b %e  %Y";
39261814Sjoe	strftime(longstring, sizeof(longstring), format, localtime(&ftime));
39361814Sjoe	fputs(longstring, stdout);
394177907Sgrog	fputc(' ', stdout);
3951556Srgrimes}
3961556Srgrimes
3971556Srgrimesstatic int
39890110Simpprinttype(u_int mode)
3991556Srgrimes{
40096892Stjr
40196892Stjr	if (f_slash) {
40296892Stjr		if ((mode & S_IFMT) == S_IFDIR) {
40396892Stjr			(void)putchar('/');
40496892Stjr			return (1);
40596892Stjr		}
40696892Stjr		return (0);
40796892Stjr	}
40896892Stjr
4091556Srgrimes	switch (mode & S_IFMT) {
4101556Srgrimes	case S_IFDIR:
4111556Srgrimes		(void)putchar('/');
4121556Srgrimes		return (1);
4131556Srgrimes	case S_IFIFO:
4141556Srgrimes		(void)putchar('|');
4151556Srgrimes		return (1);
4161556Srgrimes	case S_IFLNK:
4171556Srgrimes		(void)putchar('@');
4181556Srgrimes		return (1);
4191556Srgrimes	case S_IFSOCK:
4201556Srgrimes		(void)putchar('=');
4211556Srgrimes		return (1);
42220417Ssteve	case S_IFWHT:
42320417Ssteve		(void)putchar('%');
42420417Ssteve		return (1);
42590150Smarkm	default:
42696681Sbillf		break;
4271556Srgrimes	}
4281556Srgrimes	if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
4291556Srgrimes		(void)putchar('*');
4301556Srgrimes		return (1);
4311556Srgrimes	}
4321556Srgrimes	return (0);
4331556Srgrimes}
4341556Srgrimes
43561268Sjoe#ifdef COLORLS
43661323Sachestatic int
43790110Simpputch(int c)
43861291Sache{
43988602Sjoe	(void)putchar(c);
44061321Sache	return 0;
44161291Sache}
44261291Sache
44361323Sachestatic int
44490110Simpwritech(int c)
44561321Sache{
446114583Smarkm	char tmp = (char)c;
44761291Sache
44888602Sjoe	(void)write(STDOUT_FILENO, &tmp, 1);
44961321Sache	return 0;
45061321Sache}
45161321Sache
45261323Sachestatic void
45390110Simpprintcolor(Colors c)
45461178Sjoe{
45588594Sjoe	char *ansiseq;
45661268Sjoe
45788583Sjoe	if (colors[c].bold)
45888583Sjoe		tputs(enter_bold, 1, putch);
45988583Sjoe
46088583Sjoe	if (colors[c].num[0] != -1) {
46188583Sjoe		ansiseq = tgoto(ansi_fgcol, 0, colors[c].num[0]);
46261321Sache		if (ansiseq)
46361291Sache			tputs(ansiseq, 1, putch);
46461178Sjoe	}
46588583Sjoe	if (colors[c].num[1] != -1) {
46688583Sjoe		ansiseq = tgoto(ansi_bgcol, 0, colors[c].num[1]);
46761321Sache		if (ansiseq)
46861291Sache			tputs(ansiseq, 1, putch);
46961268Sjoe	}
47061178Sjoe}
47161178Sjoe
47261321Sachestatic void
47390110Simpendcolor(int sig)
47461268Sjoe{
47561321Sache	tputs(ansi_coloff, 1, sig ? writech : putch);
47688583Sjoe	tputs(attrs_off, 1, sig ? writech : putch);
47761268Sjoe}
47861268Sjoe
47961321Sachestatic int
48090110Simpcolortype(mode_t mode)
48161178Sjoe{
48288602Sjoe	switch (mode & S_IFMT) {
48388595Sjoe	case S_IFDIR:
48461178Sjoe		if (mode & S_IWOTH)
48588595Sjoe			if (mode & S_ISTXT)
48688595Sjoe				printcolor(C_WSDIR);
48788595Sjoe			else
48888595Sjoe				printcolor(C_WDIR);
48961178Sjoe		else
49088595Sjoe			printcolor(C_DIR);
49188602Sjoe		return (1);
49288595Sjoe	case S_IFLNK:
49361178Sjoe		printcolor(C_LNK);
49488602Sjoe		return (1);
49588595Sjoe	case S_IFSOCK:
49661178Sjoe		printcolor(C_SOCK);
49788602Sjoe		return (1);
49888595Sjoe	case S_IFIFO:
49961178Sjoe		printcolor(C_FIFO);
50088602Sjoe		return (1);
50188595Sjoe	case S_IFBLK:
50261178Sjoe		printcolor(C_BLK);
50388602Sjoe		return (1);
50488595Sjoe	case S_IFCHR:
50561178Sjoe		printcolor(C_CHR);
50688602Sjoe		return (1);
507114583Smarkm	default:;
50861178Sjoe	}
50961178Sjoe	if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
51061178Sjoe		if (mode & S_ISUID)
51188595Sjoe			printcolor(C_SUID);
51261178Sjoe		else if (mode & S_ISGID)
51388595Sjoe			printcolor(C_SGID);
51461178Sjoe		else
51588595Sjoe			printcolor(C_EXEC);
51688602Sjoe		return (1);
51761178Sjoe	}
51888602Sjoe	return (0);
51961178Sjoe}
52061178Sjoe
52161178Sjoevoid
52290110Simpparsecolors(const char *cs)
52361178Sjoe{
52488594Sjoe	int i;
52588594Sjoe	int j;
526105780Smarkm	size_t len;
52788594Sjoe	char c[2];
52888594Sjoe	short legacy_warn = 0;
52961321Sache
53088586Sjoe	if (cs == NULL)
53188602Sjoe		cs = "";	/* LSCOLORS not set */
53261178Sjoe	len = strlen(cs);
533114583Smarkm	for (i = 0; i < (int)C_NUMCOLORS; i++) {
53488583Sjoe		colors[i].bold = 0;
53588583Sjoe
536114583Smarkm		if (len <= 2 * (size_t)i) {
53788586Sjoe			c[0] = defcolors[2 * i];
53888586Sjoe			c[1] = defcolors[2 * i + 1];
53988602Sjoe		} else {
54088586Sjoe			c[0] = cs[2 * i];
54188586Sjoe			c[1] = cs[2 * i + 1];
54261178Sjoe		}
54388602Sjoe		for (j = 0; j < 2; j++) {
54488583Sjoe			/* Legacy colours used 0-7 */
54588583Sjoe			if (c[j] >= '0' && c[j] <= '7') {
54688583Sjoe				colors[i].num[j] = c[j] - '0';
54788583Sjoe				if (!legacy_warn) {
548106479Stjr					warnx("LSCOLORS should use "
54988588Sjoe					    "characters a-h instead of 0-9 ("
550106479Stjr					    "see the manual page)");
55188583Sjoe				}
55288583Sjoe				legacy_warn = 1;
55388583Sjoe			} else if (c[j] >= 'a' && c[j] <= 'h')
55488583Sjoe				colors[i].num[j] = c[j] - 'a';
55588583Sjoe			else if (c[j] >= 'A' && c[j] <= 'H') {
55688583Sjoe				colors[i].num[j] = c[j] - 'A';
55788583Sjoe				colors[i].bold = 1;
558114583Smarkm			} else if (tolower((unsigned char)c[j]) == 'x')
55988583Sjoe				colors[i].num[j] = -1;
56088583Sjoe			else {
561106479Stjr				warnx("invalid character '%c' in LSCOLORS"
562106479Stjr				    " env var", c[j]);
56388584Sjoe				colors[i].num[j] = -1;
56461178Sjoe			}
56561178Sjoe		}
56661178Sjoe	}
56761178Sjoe}
56861291Sache
56961323Sachevoid
57090110Simpcolorquit(int sig)
57161291Sache{
57261321Sache	endcolor(sig);
57361294Sache
57488602Sjoe	(void)signal(sig, SIG_DFL);
57588602Sjoe	(void)kill(getpid(), sig);
57661291Sache}
57788602Sjoe
57888602Sjoe#endif /* COLORLS */
57988602Sjoe
5801556Srgrimesstatic void
581105780Smarkmprintlink(const FTSENT *p)
5821556Srgrimes{
58388594Sjoe	int lnklen;
58488594Sjoe	char name[MAXPATHLEN + 1];
58588594Sjoe	char path[MAXPATHLEN + 1];
5861556Srgrimes
5871556Srgrimes	if (p->fts_level == FTS_ROOTLEVEL)
5881556Srgrimes		(void)snprintf(name, sizeof(name), "%s", p->fts_name);
5898855Srgrimes	else
5901556Srgrimes		(void)snprintf(name, sizeof(name),
5911556Srgrimes		    "%s/%s", p->fts_parent->fts_accpath, p->fts_name);
5921556Srgrimes	if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) {
5931556Srgrimes		(void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno));
5941556Srgrimes		return;
5951556Srgrimes	}
5961556Srgrimes	path[lnklen] = '\0';
59762597Sassar	(void)printf(" -> ");
59890150Smarkm	(void)printname(path);
5991556Srgrimes}
60088591Sjoe
60188591Sjoestatic void
60290110Simpprintsize(size_t width, off_t bytes)
60388591Sjoe{
60488602Sjoe
60588591Sjoe	if (f_humanval) {
606129719Spjd		char buf[5];
60788591Sjoe
608129719Spjd		humanize_number(buf, sizeof(buf), (int64_t)bytes, "",
609129719Spjd		    HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
610129719Spjd		(void)printf("%5s ", buf);
61188602Sjoe	} else
612114583Smarkm		(void)printf("%*jd ", (u_int)width, bytes);
61388591Sjoe}
61488591Sjoe
615106371Stjrstatic void
616114583Smarkmaclmode(char *buf, const FTSENT *p, int *haveacls)
617106371Stjr{
618106371Stjr	char name[MAXPATHLEN + 1];
619106371Stjr	int entries, ret;
620106371Stjr	acl_t facl;
621106371Stjr	acl_entry_t ae;
622106371Stjr
623106371Stjr	/*
624106371Stjr	 * Add a + after the standard rwxrwxrwx mode if the file has an
625106371Stjr	 * extended ACL. strmode() reserves space at the end of the string.
626106371Stjr	 */
627106371Stjr	if (p->fts_level == FTS_ROOTLEVEL)
628106371Stjr		snprintf(name, sizeof(name), "%s", p->fts_name);
629106371Stjr	else
630106371Stjr		snprintf(name, sizeof(name), "%s/%s",
631177907Sgrog		    p->fts_parent->fts_accpath, p->fts_name);
632108066Stjr	/*
633108066Stjr	 * We have no way to tell whether a symbolic link has an ACL since
634163480Sru	 * pathconf() and acl_get_file() both follow them.  They also don't
635163480Sru	 * support whiteouts.
636108066Stjr	 */
637163480Sru	if (S_ISLNK(p->fts_statp->st_mode) || S_ISWHT(p->fts_statp->st_mode)) {
638108066Stjr		*haveacls = 1;
639108066Stjr		return;
640108066Stjr	}
641106371Stjr	if ((ret = pathconf(name, _PC_ACL_EXTENDED)) <= 0) {
642106371Stjr		if (ret < 0 && errno != EINVAL)
643106371Stjr			warn("%s", name);
644106371Stjr		else
645106371Stjr			*haveacls = 0;
646106371Stjr		return;
647106371Stjr	}
648106371Stjr	*haveacls = 1;
649106371Stjr	if ((facl = acl_get_file(name, ACL_TYPE_ACCESS)) != NULL) {
650106371Stjr		if (acl_get_entry(facl, ACL_FIRST_ENTRY, &ae) == 1) {
651127795Sbmilekic			entries = 1;
652127795Sbmilekic			while (acl_get_entry(facl, ACL_NEXT_ENTRY, &ae) == 1)
653127795Sbmilekic				if (++entries > 3)
654127795Sbmilekic					break;
655127795Sbmilekic			/*
656127795Sbmilekic			 * POSIX.1e requires that ACLs of type ACL_TYPE_ACCESS
657127795Sbmilekic			 * must have at least three entries (owner, group,
658127795Sbmilekic			 * and other). So anything with more than 3 ACLs looks
659127795Sbmilekic			 * interesting to us.
660127795Sbmilekic			 */
661127795Sbmilekic			if (entries > 3)
662106371Stjr				buf[10] = '+';
663106371Stjr		}
664106371Stjr		acl_free(facl);
665106371Stjr	} else
666106371Stjr		warn("%s", name);
667106371Stjr}
668