print.c revision 157098
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 157098 2006-03-24 16:38:02Z jhb $");
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;
1711556Srgrimes		(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}
24096892Stjr
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)
3811556Srgrimes	if (f_sectime)
38261920Sjoe		/* mmm dd hh:mm:ss yyyy || dd mmm hh:mm:ss yyyy */
38374566Sache		format = d_first ? "%e %b %T %Y " : "%b %e %T %Y ";
38421545Smpp	else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS)
38561920Sjoe		/* mmm dd hh:mm || dd mmm hh:mm */
38674566Sache		format = d_first ? "%e %b %R " : "%b %e %R ";
38761814Sjoe	else
38861920Sjoe		/* mmm dd  yyyy || dd mmm  yyyy */
38974566Sache		format = d_first ? "%e %b  %Y " : "%b %e  %Y ";
39061814Sjoe	strftime(longstring, sizeof(longstring), format, localtime(&ftime));
39161814Sjoe	fputs(longstring, stdout);
3921556Srgrimes}
3931556Srgrimes
3941556Srgrimesstatic int
39590110Simpprinttype(u_int mode)
3961556Srgrimes{
39796892Stjr
39896892Stjr	if (f_slash) {
39996892Stjr		if ((mode & S_IFMT) == S_IFDIR) {
40096892Stjr			(void)putchar('/');
40196892Stjr			return (1);
40296892Stjr		}
40396892Stjr		return (0);
40496892Stjr	}
40596892Stjr
4061556Srgrimes	switch (mode & S_IFMT) {
4071556Srgrimes	case S_IFDIR:
4081556Srgrimes		(void)putchar('/');
4091556Srgrimes		return (1);
4101556Srgrimes	case S_IFIFO:
4111556Srgrimes		(void)putchar('|');
4121556Srgrimes		return (1);
4131556Srgrimes	case S_IFLNK:
4141556Srgrimes		(void)putchar('@');
4151556Srgrimes		return (1);
4161556Srgrimes	case S_IFSOCK:
4171556Srgrimes		(void)putchar('=');
4181556Srgrimes		return (1);
41920417Ssteve	case S_IFWHT:
42020417Ssteve		(void)putchar('%');
42120417Ssteve		return (1);
42290150Smarkm	default:
42396681Sbillf		break;
4241556Srgrimes	}
4251556Srgrimes	if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
4261556Srgrimes		(void)putchar('*');
4271556Srgrimes		return (1);
4281556Srgrimes	}
4291556Srgrimes	return (0);
4301556Srgrimes}
4311556Srgrimes
43261268Sjoe#ifdef COLORLS
43361323Sachestatic int
43490110Simpputch(int c)
43561291Sache{
43688602Sjoe	(void)putchar(c);
43761321Sache	return 0;
43861291Sache}
43961291Sache
44061323Sachestatic int
44190110Simpwritech(int c)
44261321Sache{
443114583Smarkm	char tmp = (char)c;
44461291Sache
44588602Sjoe	(void)write(STDOUT_FILENO, &tmp, 1);
44661321Sache	return 0;
44761321Sache}
44861321Sache
44961323Sachestatic void
45090110Simpprintcolor(Colors c)
45161178Sjoe{
45288594Sjoe	char *ansiseq;
45361268Sjoe
45488583Sjoe	if (colors[c].bold)
45588583Sjoe		tputs(enter_bold, 1, putch);
45688583Sjoe
45788583Sjoe	if (colors[c].num[0] != -1) {
45888583Sjoe		ansiseq = tgoto(ansi_fgcol, 0, colors[c].num[0]);
45961321Sache		if (ansiseq)
46061291Sache			tputs(ansiseq, 1, putch);
46161178Sjoe	}
46288583Sjoe	if (colors[c].num[1] != -1) {
46388583Sjoe		ansiseq = tgoto(ansi_bgcol, 0, colors[c].num[1]);
46461321Sache		if (ansiseq)
46561291Sache			tputs(ansiseq, 1, putch);
46661268Sjoe	}
46761178Sjoe}
46861178Sjoe
46961321Sachestatic void
47090110Simpendcolor(int sig)
47161268Sjoe{
47261321Sache	tputs(ansi_coloff, 1, sig ? writech : putch);
47388583Sjoe	tputs(attrs_off, 1, sig ? writech : putch);
47461268Sjoe}
47561268Sjoe
47661321Sachestatic int
47790110Simpcolortype(mode_t mode)
47861178Sjoe{
47988602Sjoe	switch (mode & S_IFMT) {
48088595Sjoe	case S_IFDIR:
48161178Sjoe		if (mode & S_IWOTH)
48288595Sjoe			if (mode & S_ISTXT)
48388595Sjoe				printcolor(C_WSDIR);
48488595Sjoe			else
48588595Sjoe				printcolor(C_WDIR);
48661178Sjoe		else
48788595Sjoe			printcolor(C_DIR);
48888602Sjoe		return (1);
48988595Sjoe	case S_IFLNK:
49061178Sjoe		printcolor(C_LNK);
49188602Sjoe		return (1);
49288595Sjoe	case S_IFSOCK:
49361178Sjoe		printcolor(C_SOCK);
49488602Sjoe		return (1);
49588595Sjoe	case S_IFIFO:
49661178Sjoe		printcolor(C_FIFO);
49788602Sjoe		return (1);
49888595Sjoe	case S_IFBLK:
49961178Sjoe		printcolor(C_BLK);
50088602Sjoe		return (1);
50188595Sjoe	case S_IFCHR:
50261178Sjoe		printcolor(C_CHR);
50388602Sjoe		return (1);
504114583Smarkm	default:;
50561178Sjoe	}
50661178Sjoe	if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
50761178Sjoe		if (mode & S_ISUID)
50888595Sjoe			printcolor(C_SUID);
50961178Sjoe		else if (mode & S_ISGID)
51088595Sjoe			printcolor(C_SGID);
51161178Sjoe		else
51288595Sjoe			printcolor(C_EXEC);
51388602Sjoe		return (1);
51461178Sjoe	}
51588602Sjoe	return (0);
51661178Sjoe}
51761178Sjoe
51861178Sjoevoid
51990110Simpparsecolors(const char *cs)
52061178Sjoe{
52188594Sjoe	int i;
52288594Sjoe	int j;
523105780Smarkm	size_t len;
52488594Sjoe	char c[2];
52588594Sjoe	short legacy_warn = 0;
52661321Sache
52788586Sjoe	if (cs == NULL)
52888602Sjoe		cs = "";	/* LSCOLORS not set */
52961178Sjoe	len = strlen(cs);
530114583Smarkm	for (i = 0; i < (int)C_NUMCOLORS; i++) {
53188583Sjoe		colors[i].bold = 0;
53288583Sjoe
533114583Smarkm		if (len <= 2 * (size_t)i) {
53488586Sjoe			c[0] = defcolors[2 * i];
53588586Sjoe			c[1] = defcolors[2 * i + 1];
53688602Sjoe		} else {
53788586Sjoe			c[0] = cs[2 * i];
53888586Sjoe			c[1] = cs[2 * i + 1];
53961178Sjoe		}
54088602Sjoe		for (j = 0; j < 2; j++) {
54188583Sjoe			/* Legacy colours used 0-7 */
54288583Sjoe			if (c[j] >= '0' && c[j] <= '7') {
54388583Sjoe				colors[i].num[j] = c[j] - '0';
54488583Sjoe				if (!legacy_warn) {
545106479Stjr					warnx("LSCOLORS should use "
54688588Sjoe					    "characters a-h instead of 0-9 ("
547106479Stjr					    "see the manual page)");
54888583Sjoe				}
54988583Sjoe				legacy_warn = 1;
55088583Sjoe			} else if (c[j] >= 'a' && c[j] <= 'h')
55188583Sjoe				colors[i].num[j] = c[j] - 'a';
55288583Sjoe			else if (c[j] >= 'A' && c[j] <= 'H') {
55388583Sjoe				colors[i].num[j] = c[j] - 'A';
55488583Sjoe				colors[i].bold = 1;
555114583Smarkm			} else if (tolower((unsigned char)c[j]) == 'x')
55688583Sjoe				colors[i].num[j] = -1;
55788583Sjoe			else {
558106479Stjr				warnx("invalid character '%c' in LSCOLORS"
559106479Stjr				    " env var", c[j]);
56088584Sjoe				colors[i].num[j] = -1;
56161178Sjoe			}
56261178Sjoe		}
56361178Sjoe	}
56461178Sjoe}
56561291Sache
56661323Sachevoid
56790110Simpcolorquit(int sig)
56861291Sache{
56961321Sache	endcolor(sig);
57061294Sache
57188602Sjoe	(void)signal(sig, SIG_DFL);
57288602Sjoe	(void)kill(getpid(), sig);
57361291Sache}
57488602Sjoe
57588602Sjoe#endif /* COLORLS */
57688602Sjoe
5771556Srgrimesstatic void
578105780Smarkmprintlink(const FTSENT *p)
5791556Srgrimes{
58088594Sjoe	int lnklen;
58188594Sjoe	char name[MAXPATHLEN + 1];
58288594Sjoe	char path[MAXPATHLEN + 1];
5831556Srgrimes
5841556Srgrimes	if (p->fts_level == FTS_ROOTLEVEL)
5851556Srgrimes		(void)snprintf(name, sizeof(name), "%s", p->fts_name);
5868855Srgrimes	else
5871556Srgrimes		(void)snprintf(name, sizeof(name),
5881556Srgrimes		    "%s/%s", p->fts_parent->fts_accpath, p->fts_name);
5891556Srgrimes	if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) {
5901556Srgrimes		(void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno));
5911556Srgrimes		return;
5921556Srgrimes	}
5931556Srgrimes	path[lnklen] = '\0';
59462597Sassar	(void)printf(" -> ");
59590150Smarkm	(void)printname(path);
5961556Srgrimes}
59788591Sjoe
59888591Sjoestatic void
59990110Simpprintsize(size_t width, off_t bytes)
60088591Sjoe{
60188602Sjoe
60288591Sjoe	if (f_humanval) {
603129719Spjd		char buf[5];
60488591Sjoe
605129719Spjd		humanize_number(buf, sizeof(buf), (int64_t)bytes, "",
606129719Spjd		    HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
607129719Spjd		(void)printf("%5s ", buf);
60888602Sjoe	} else
609114583Smarkm		(void)printf("%*jd ", (u_int)width, bytes);
61088591Sjoe}
61188591Sjoe
612106371Stjrstatic void
613114583Smarkmaclmode(char *buf, const FTSENT *p, int *haveacls)
614106371Stjr{
615106371Stjr	char name[MAXPATHLEN + 1];
616106371Stjr	int entries, ret;
617106371Stjr	acl_t facl;
618106371Stjr	acl_entry_t ae;
619106371Stjr
620106371Stjr	/*
621106371Stjr	 * Add a + after the standard rwxrwxrwx mode if the file has an
622106371Stjr	 * extended ACL. strmode() reserves space at the end of the string.
623106371Stjr	 */
624106371Stjr	if (p->fts_level == FTS_ROOTLEVEL)
625106371Stjr		snprintf(name, sizeof(name), "%s", p->fts_name);
626106371Stjr	else
627106371Stjr		snprintf(name, sizeof(name), "%s/%s",
628106371Stjr		    p->fts_parent->fts_accpath, p->fts_name);
629108066Stjr	/*
630108066Stjr	 * We have no way to tell whether a symbolic link has an ACL since
631108066Stjr	 * pathconf() and acl_get_file() both follow them.
632108066Stjr	 */
633108066Stjr	if (S_ISLNK(p->fts_statp->st_mode)) {
634108066Stjr		*haveacls = 1;
635108066Stjr		return;
636108066Stjr	}
637106371Stjr	if ((ret = pathconf(name, _PC_ACL_EXTENDED)) <= 0) {
638106371Stjr		if (ret < 0 && errno != EINVAL)
639106371Stjr			warn("%s", name);
640106371Stjr		else
641106371Stjr			*haveacls = 0;
642106371Stjr		return;
643106371Stjr	}
644106371Stjr	*haveacls = 1;
645106371Stjr	if ((facl = acl_get_file(name, ACL_TYPE_ACCESS)) != NULL) {
646106371Stjr		if (acl_get_entry(facl, ACL_FIRST_ENTRY, &ae) == 1) {
647127795Sbmilekic			entries = 1;
648127795Sbmilekic			while (acl_get_entry(facl, ACL_NEXT_ENTRY, &ae) == 1)
649127795Sbmilekic				if (++entries > 3)
650127795Sbmilekic					break;
651127795Sbmilekic			/*
652127795Sbmilekic			 * POSIX.1e requires that ACLs of type ACL_TYPE_ACCESS
653127795Sbmilekic			 * must have at least three entries (owner, group,
654127795Sbmilekic			 * and other). So anything with more than 3 ACLs looks
655127795Sbmilekic			 * interesting to us.
656127795Sbmilekic			 */
657127795Sbmilekic			if (entries > 3)
658106371Stjr				buf[10] = '+';
659106371Stjr		}
660106371Stjr		acl_free(facl);
661106371Stjr	} else
662106371Stjr		warn("%s", name);
663106371Stjr}
664