print.c revision 196712
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 196712 2009-08-31 20:53:01Z trasz $");
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
73196712Straszstatic void	aclmode(char *, const FTSENT *);
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
1421556Srgrimes
143130236Sdas	if ((dp->list == NULL || dp->list->fts_level != FTS_ROOTLEVEL) &&
144130236Sdas	    (f_longform || f_size)) {
1451556Srgrimes		(void)printf("total %lu\n", howmany(dp->btotal, blocksize));
146130236Sdas	}
1471556Srgrimes
1481556Srgrimes	for (p = dp->list; p; p = p->fts_link) {
1491556Srgrimes		if (IS_NOPRINT(p))
1501556Srgrimes			continue;
1511556Srgrimes		sp = p->fts_statp;
1521556Srgrimes		if (f_inode)
15320417Ssteve			(void)printf("%*lu ", dp->s_inode, (u_long)sp->st_ino);
1541556Srgrimes		if (f_size)
155114583Smarkm			(void)printf("%*jd ",
1561556Srgrimes			    dp->s_block, howmany(sp->st_blocks, blocksize));
15790150Smarkm		strmode(sp->st_mode, buf);
158196712Strasz		aclmode(buf, p);
1591556Srgrimes		np = p->fts_pointer;
160177942Simp		(void)printf("%s %*u %-*s  %-*s  ", buf, dp->s_nlink,
1611556Srgrimes		    sp->st_nlink, dp->s_user, np->user, dp->s_group,
1621556Srgrimes		    np->group);
1631556Srgrimes		if (f_flags)
1641556Srgrimes			(void)printf("%-*s ", dp->s_flags, np->flags);
165105832Srwatson		if (f_label)
166105832Srwatson			(void)printf("%-*s ", dp->s_label, np->label);
1671556Srgrimes		if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode))
16855514Sbde			if (minor(sp->st_rdev) > 255 || minor(sp->st_rdev) < 0)
16913120Sjoerg				(void)printf("%3d, 0x%08x ",
17055514Sbde				    major(sp->st_rdev),
17155514Sbde				    (u_int)minor(sp->st_rdev));
17213120Sjoerg			else
17313120Sjoerg				(void)printf("%3d, %3d ",
17413120Sjoerg				    major(sp->st_rdev), minor(sp->st_rdev));
1751556Srgrimes		else if (dp->bcfile)
176114583Smarkm			(void)printf("%*s%*jd ",
1771556Srgrimes			    8 - dp->s_size, "", dp->s_size, sp->st_size);
1781556Srgrimes		else
17988591Sjoe			printsize(dp->s_size, sp->st_size);
1801556Srgrimes		if (f_accesstime)
1811556Srgrimes			printtime(sp->st_atime);
182157098Sjhb		else if (f_birthtime)
183157098Sjhb			printtime(sp->st_birthtime);
1841556Srgrimes		else if (f_statustime)
1851556Srgrimes			printtime(sp->st_ctime);
1861556Srgrimes		else
1871556Srgrimes			printtime(sp->st_mtime);
18861268Sjoe#ifdef COLORLS
18961178Sjoe		if (f_color)
19061291Sache			color_printed = colortype(sp->st_mode);
19161268Sjoe#endif
19262597Sassar		(void)printname(p->fts_name);
19361268Sjoe#ifdef COLORLS
19461291Sache		if (f_color && color_printed)
19561321Sache			endcolor(0);
19661268Sjoe#endif
1971556Srgrimes		if (f_type)
1981556Srgrimes			(void)printtype(sp->st_mode);
1991556Srgrimes		if (S_ISLNK(sp->st_mode))
2001556Srgrimes			printlink(p);
2011556Srgrimes		(void)putchar('\n');
2021556Srgrimes	}
2031556Srgrimes}
2041556Srgrimes
2051556Srgrimesvoid
206114583Smarkmprintstream(const DISPLAY *dp)
20796892Stjr{
20896892Stjr	FTSENT *p;
20996892Stjr	int chcnt;
21096892Stjr
21196892Stjr	for (p = dp->list, chcnt = 0; p; p = p->fts_link) {
21296892Stjr		if (p->fts_number == NO_PRINT)
21396892Stjr			continue;
214128823Stjr		/* XXX strlen does not take octal escapes into account. */
21596892Stjr		if (strlen(p->fts_name) + chcnt +
21696892Stjr		    (p->fts_link ? 2 : 0) >= (unsigned)termwidth) {
21796892Stjr			putchar('\n');
21896892Stjr			chcnt = 0;
21996892Stjr		}
22096892Stjr		chcnt += printaname(p, dp->s_inode, dp->s_block);
22196892Stjr		if (p->fts_link) {
22296892Stjr			printf(", ");
22396892Stjr			chcnt += 2;
22496892Stjr		}
22596892Stjr	}
22696892Stjr	if (chcnt)
22796892Stjr		putchar('\n');
22896892Stjr}
229177907Sgrog
23096892Stjrvoid
231114583Smarkmprintcol(const DISPLAY *dp)
2321556Srgrimes{
2331556Srgrimes	static FTSENT **array;
2341556Srgrimes	static int lastentries = -1;
23588594Sjoe	FTSENT *p;
236121124Stjr	FTSENT **narray;
23788594Sjoe	int base;
23888594Sjoe	int chcnt;
23988594Sjoe	int cnt;
24088594Sjoe	int col;
24188594Sjoe	int colwidth;
24288594Sjoe	int endcol;
24388594Sjoe	int num;
24488594Sjoe	int numcols;
24588594Sjoe	int numrows;
24688594Sjoe	int row;
24788594Sjoe	int tabwidth;
2481556Srgrimes
24937932Shoek	if (f_notabs)
25037932Shoek		tabwidth = 1;
25137932Shoek	else
25237932Shoek		tabwidth = 8;
25337932Shoek
2541556Srgrimes	/*
2551556Srgrimes	 * Have to do random access in the linked list -- build a table
2561556Srgrimes	 * of pointers.
2571556Srgrimes	 */
2581556Srgrimes	if (dp->entries > lastentries) {
259121124Stjr		if ((narray =
2601556Srgrimes		    realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) {
2611556Srgrimes			warn(NULL);
2621556Srgrimes			printscol(dp);
263121124Stjr			return;
2641556Srgrimes		}
265121124Stjr		lastentries = dp->entries;
266121124Stjr		array = narray;
2671556Srgrimes	}
2681556Srgrimes	for (p = dp->list, num = 0; p; p = p->fts_link)
2691556Srgrimes		if (p->fts_number != NO_PRINT)
2701556Srgrimes			array[num++] = p;
2711556Srgrimes
2721556Srgrimes	colwidth = dp->maxlen;
2731556Srgrimes	if (f_inode)
2741556Srgrimes		colwidth += dp->s_inode + 1;
2751556Srgrimes	if (f_size)
2761556Srgrimes		colwidth += dp->s_block + 1;
2771556Srgrimes	if (f_type)
2781556Srgrimes		colwidth += 1;
2791556Srgrimes
28037932Shoek	colwidth = (colwidth + tabwidth) & ~(tabwidth - 1);
2811556Srgrimes	if (termwidth < 2 * colwidth) {
2821556Srgrimes		printscol(dp);
2831556Srgrimes		return;
2841556Srgrimes	}
2851556Srgrimes	numcols = termwidth / colwidth;
2861556Srgrimes	numrows = num / numcols;
2871556Srgrimes	if (num % numcols)
2881556Srgrimes		++numrows;
2891556Srgrimes
290130236Sdas	if ((dp->list == NULL || dp->list->fts_level != FTS_ROOTLEVEL) &&
291130236Sdas	    (f_longform || f_size)) {
2921556Srgrimes		(void)printf("total %lu\n", howmany(dp->btotal, blocksize));
293130236Sdas	}
29496892Stjr
295102577Skeramida	base = 0;
2961556Srgrimes	for (row = 0; row < numrows; ++row) {
2971556Srgrimes		endcol = colwidth;
29896892Stjr		if (!f_sortacross)
29996892Stjr			base = row;
30096892Stjr		for (col = 0, chcnt = 0; col < numcols; ++col) {
3011556Srgrimes			chcnt += printaname(array[base], dp->s_inode,
3021556Srgrimes			    dp->s_block);
30396892Stjr			if (f_sortacross)
30496892Stjr				base++;
30596892Stjr			else
30696892Stjr				base += numrows;
30796892Stjr			if (base >= num)
3081556Srgrimes				break;
30937932Shoek			while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1)))
31088595Sjoe			    <= endcol) {
31196892Stjr				if (f_sortacross && col + 1 >= numcols)
31296892Stjr					break;
31337932Shoek				(void)putchar(f_notabs ? ' ' : '\t');
3141556Srgrimes				chcnt = cnt;
3151556Srgrimes			}
3161556Srgrimes			endcol += colwidth;
3171556Srgrimes		}
3181556Srgrimes		(void)putchar('\n');
3191556Srgrimes	}
3201556Srgrimes}
3211556Srgrimes
3221556Srgrimes/*
3231556Srgrimes * print [inode] [size] name
3241556Srgrimes * return # of characters printed, no trailing characters.
3251556Srgrimes */
3261556Srgrimesstatic int
327114583Smarkmprintaname(const FTSENT *p, u_long inodefield, u_long sizefield)
3281556Srgrimes{
3291556Srgrimes	struct stat *sp;
33088594Sjoe	int chcnt;
33161292Sache#ifdef COLORLS
33288594Sjoe	int color_printed = 0;
33361292Sache#endif
3341556Srgrimes
3351556Srgrimes	sp = p->fts_statp;
3361556Srgrimes	chcnt = 0;
3371556Srgrimes	if (f_inode)
33820417Ssteve		chcnt += printf("%*lu ", (int)inodefield, (u_long)sp->st_ino);
3391556Srgrimes	if (f_size)
340114583Smarkm		chcnt += printf("%*jd ",
3411556Srgrimes		    (int)sizefield, howmany(sp->st_blocks, blocksize));
34261268Sjoe#ifdef COLORLS
34361178Sjoe	if (f_color)
34461291Sache		color_printed = colortype(sp->st_mode);
34561268Sjoe#endif
34662597Sassar	chcnt += printname(p->fts_name);
34761268Sjoe#ifdef COLORLS
34861291Sache	if (f_color && color_printed)
34961321Sache		endcolor(0);
35061268Sjoe#endif
3511556Srgrimes	if (f_type)
3521556Srgrimes		chcnt += printtype(sp->st_mode);
3531556Srgrimes	return (chcnt);
3541556Srgrimes}
3551556Srgrimes
3561556Srgrimesstatic void
35790110Simpprinttime(time_t ftime)
3581556Srgrimes{
35988594Sjoe	char longstring[80];
360114583Smarkm	static time_t now = 0;
36188594Sjoe	const char *format;
36288594Sjoe	static int d_first = -1;
3631556Srgrimes
36474566Sache	if (d_first < 0)
36574566Sache		d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
36621545Smpp	if (now == 0)
36721545Smpp		now = time(NULL);
36821545Smpp
3699987Swollman#define	SIXMONTHS	((365 / 2) * 86400)
370177907Sgrog	if (f_timeformat)  /* user specified format */
371177907Sgrog		format = f_timeformat;
372177907Sgrog	else if (f_sectime)
37361920Sjoe		/* mmm dd hh:mm:ss yyyy || dd mmm hh:mm:ss yyyy */
374177907Sgrog		format = d_first ? "%e %b %T %Y" : "%b %e %T %Y";
37521545Smpp	else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS)
37661920Sjoe		/* mmm dd hh:mm || dd mmm hh:mm */
377177907Sgrog		format = d_first ? "%e %b %R" : "%b %e %R";
37861814Sjoe	else
37961920Sjoe		/* mmm dd  yyyy || dd mmm  yyyy */
380177942Simp		format = d_first ? "%e %b  %Y" : "%b %e  %Y";
38161814Sjoe	strftime(longstring, sizeof(longstring), format, localtime(&ftime));
38261814Sjoe	fputs(longstring, stdout);
383177907Sgrog	fputc(' ', stdout);
3841556Srgrimes}
3851556Srgrimes
3861556Srgrimesstatic int
38790110Simpprinttype(u_int mode)
3881556Srgrimes{
38996892Stjr
39096892Stjr	if (f_slash) {
39196892Stjr		if ((mode & S_IFMT) == S_IFDIR) {
39296892Stjr			(void)putchar('/');
39396892Stjr			return (1);
39496892Stjr		}
39596892Stjr		return (0);
39696892Stjr	}
39796892Stjr
3981556Srgrimes	switch (mode & S_IFMT) {
3991556Srgrimes	case S_IFDIR:
4001556Srgrimes		(void)putchar('/');
4011556Srgrimes		return (1);
4021556Srgrimes	case S_IFIFO:
4031556Srgrimes		(void)putchar('|');
4041556Srgrimes		return (1);
4051556Srgrimes	case S_IFLNK:
4061556Srgrimes		(void)putchar('@');
4071556Srgrimes		return (1);
4081556Srgrimes	case S_IFSOCK:
4091556Srgrimes		(void)putchar('=');
4101556Srgrimes		return (1);
41120417Ssteve	case S_IFWHT:
41220417Ssteve		(void)putchar('%');
41320417Ssteve		return (1);
41490150Smarkm	default:
41596681Sbillf		break;
4161556Srgrimes	}
4171556Srgrimes	if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
4181556Srgrimes		(void)putchar('*');
4191556Srgrimes		return (1);
4201556Srgrimes	}
4211556Srgrimes	return (0);
4221556Srgrimes}
4231556Srgrimes
42461268Sjoe#ifdef COLORLS
42561323Sachestatic int
42690110Simpputch(int c)
42761291Sache{
42888602Sjoe	(void)putchar(c);
42961321Sache	return 0;
43061291Sache}
43161291Sache
43261323Sachestatic int
43390110Simpwritech(int c)
43461321Sache{
435114583Smarkm	char tmp = (char)c;
43661291Sache
43788602Sjoe	(void)write(STDOUT_FILENO, &tmp, 1);
43861321Sache	return 0;
43961321Sache}
44061321Sache
44161323Sachestatic void
44290110Simpprintcolor(Colors c)
44361178Sjoe{
44488594Sjoe	char *ansiseq;
44561268Sjoe
44688583Sjoe	if (colors[c].bold)
44788583Sjoe		tputs(enter_bold, 1, putch);
44888583Sjoe
44988583Sjoe	if (colors[c].num[0] != -1) {
45088583Sjoe		ansiseq = tgoto(ansi_fgcol, 0, colors[c].num[0]);
45161321Sache		if (ansiseq)
45261291Sache			tputs(ansiseq, 1, putch);
45361178Sjoe	}
45488583Sjoe	if (colors[c].num[1] != -1) {
45588583Sjoe		ansiseq = tgoto(ansi_bgcol, 0, colors[c].num[1]);
45661321Sache		if (ansiseq)
45761291Sache			tputs(ansiseq, 1, putch);
45861268Sjoe	}
45961178Sjoe}
46061178Sjoe
46161321Sachestatic void
46290110Simpendcolor(int sig)
46361268Sjoe{
46461321Sache	tputs(ansi_coloff, 1, sig ? writech : putch);
46588583Sjoe	tputs(attrs_off, 1, sig ? writech : putch);
46661268Sjoe}
46761268Sjoe
46861321Sachestatic int
46990110Simpcolortype(mode_t mode)
47061178Sjoe{
47188602Sjoe	switch (mode & S_IFMT) {
47288595Sjoe	case S_IFDIR:
47361178Sjoe		if (mode & S_IWOTH)
47488595Sjoe			if (mode & S_ISTXT)
47588595Sjoe				printcolor(C_WSDIR);
47688595Sjoe			else
47788595Sjoe				printcolor(C_WDIR);
47861178Sjoe		else
47988595Sjoe			printcolor(C_DIR);
48088602Sjoe		return (1);
48188595Sjoe	case S_IFLNK:
48261178Sjoe		printcolor(C_LNK);
48388602Sjoe		return (1);
48488595Sjoe	case S_IFSOCK:
48561178Sjoe		printcolor(C_SOCK);
48688602Sjoe		return (1);
48788595Sjoe	case S_IFIFO:
48861178Sjoe		printcolor(C_FIFO);
48988602Sjoe		return (1);
49088595Sjoe	case S_IFBLK:
49161178Sjoe		printcolor(C_BLK);
49288602Sjoe		return (1);
49388595Sjoe	case S_IFCHR:
49461178Sjoe		printcolor(C_CHR);
49588602Sjoe		return (1);
496114583Smarkm	default:;
49761178Sjoe	}
49861178Sjoe	if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
49961178Sjoe		if (mode & S_ISUID)
50088595Sjoe			printcolor(C_SUID);
50161178Sjoe		else if (mode & S_ISGID)
50288595Sjoe			printcolor(C_SGID);
50361178Sjoe		else
50488595Sjoe			printcolor(C_EXEC);
50588602Sjoe		return (1);
50661178Sjoe	}
50788602Sjoe	return (0);
50861178Sjoe}
50961178Sjoe
51061178Sjoevoid
51190110Simpparsecolors(const char *cs)
51261178Sjoe{
51388594Sjoe	int i;
51488594Sjoe	int j;
515105780Smarkm	size_t len;
51688594Sjoe	char c[2];
51788594Sjoe	short legacy_warn = 0;
51861321Sache
51988586Sjoe	if (cs == NULL)
52088602Sjoe		cs = "";	/* LSCOLORS not set */
52161178Sjoe	len = strlen(cs);
522114583Smarkm	for (i = 0; i < (int)C_NUMCOLORS; i++) {
52388583Sjoe		colors[i].bold = 0;
52488583Sjoe
525114583Smarkm		if (len <= 2 * (size_t)i) {
52688586Sjoe			c[0] = defcolors[2 * i];
52788586Sjoe			c[1] = defcolors[2 * i + 1];
52888602Sjoe		} else {
52988586Sjoe			c[0] = cs[2 * i];
53088586Sjoe			c[1] = cs[2 * i + 1];
53161178Sjoe		}
53288602Sjoe		for (j = 0; j < 2; j++) {
53388583Sjoe			/* Legacy colours used 0-7 */
53488583Sjoe			if (c[j] >= '0' && c[j] <= '7') {
53588583Sjoe				colors[i].num[j] = c[j] - '0';
53688583Sjoe				if (!legacy_warn) {
537106479Stjr					warnx("LSCOLORS should use "
53888588Sjoe					    "characters a-h instead of 0-9 ("
539106479Stjr					    "see the manual page)");
54088583Sjoe				}
54188583Sjoe				legacy_warn = 1;
54288583Sjoe			} else if (c[j] >= 'a' && c[j] <= 'h')
54388583Sjoe				colors[i].num[j] = c[j] - 'a';
54488583Sjoe			else if (c[j] >= 'A' && c[j] <= 'H') {
54588583Sjoe				colors[i].num[j] = c[j] - 'A';
54688583Sjoe				colors[i].bold = 1;
547114583Smarkm			} else if (tolower((unsigned char)c[j]) == 'x')
54888583Sjoe				colors[i].num[j] = -1;
54988583Sjoe			else {
550106479Stjr				warnx("invalid character '%c' in LSCOLORS"
551106479Stjr				    " env var", c[j]);
55288584Sjoe				colors[i].num[j] = -1;
55361178Sjoe			}
55461178Sjoe		}
55561178Sjoe	}
55661178Sjoe}
55761291Sache
55861323Sachevoid
55990110Simpcolorquit(int sig)
56061291Sache{
56161321Sache	endcolor(sig);
56261294Sache
56388602Sjoe	(void)signal(sig, SIG_DFL);
56488602Sjoe	(void)kill(getpid(), sig);
56561291Sache}
56688602Sjoe
56788602Sjoe#endif /* COLORLS */
56888602Sjoe
5691556Srgrimesstatic void
570105780Smarkmprintlink(const FTSENT *p)
5711556Srgrimes{
57288594Sjoe	int lnklen;
57388594Sjoe	char name[MAXPATHLEN + 1];
57488594Sjoe	char path[MAXPATHLEN + 1];
5751556Srgrimes
5761556Srgrimes	if (p->fts_level == FTS_ROOTLEVEL)
5771556Srgrimes		(void)snprintf(name, sizeof(name), "%s", p->fts_name);
5788855Srgrimes	else
5791556Srgrimes		(void)snprintf(name, sizeof(name),
5801556Srgrimes		    "%s/%s", p->fts_parent->fts_accpath, p->fts_name);
5811556Srgrimes	if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) {
5821556Srgrimes		(void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno));
5831556Srgrimes		return;
5841556Srgrimes	}
5851556Srgrimes	path[lnklen] = '\0';
58662597Sassar	(void)printf(" -> ");
58790150Smarkm	(void)printname(path);
5881556Srgrimes}
58988591Sjoe
59088591Sjoestatic void
59190110Simpprintsize(size_t width, off_t bytes)
59288591Sjoe{
59388602Sjoe
59488591Sjoe	if (f_humanval) {
595129719Spjd		char buf[5];
59688591Sjoe
597129719Spjd		humanize_number(buf, sizeof(buf), (int64_t)bytes, "",
598129719Spjd		    HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
599129719Spjd		(void)printf("%5s ", buf);
60088602Sjoe	} else
601114583Smarkm		(void)printf("%*jd ", (u_int)width, bytes);
60288591Sjoe}
60388591Sjoe
604196712Strasz/*
605196712Strasz * Add a + after the standard rwxrwxrwx mode if the file has an
606196712Strasz * ACL. strmode() reserves space at the end of the string.
607196712Strasz */
608106371Stjrstatic void
609196712Straszaclmode(char *buf, const FTSENT *p)
610106371Stjr{
611106371Stjr	char name[MAXPATHLEN + 1];
612196712Strasz	int ret, trivial;
613196712Strasz	static dev_t previous_dev = NODEV;
614196712Strasz	static int supports_acls = -1;
615196712Strasz	static int type = ACL_TYPE_ACCESS;
616106371Stjr	acl_t facl;
617106371Stjr
618106371Stjr	/*
619196712Strasz	 * XXX: ACLs are not supported on whiteouts and device files
620196712Strasz	 * residing on UFS.
621106371Stjr	 */
622196712Strasz	if (S_ISCHR(p->fts_statp->st_mode) || S_ISBLK(p->fts_statp->st_mode) ||
623196712Strasz	    S_ISWHT(p->fts_statp->st_mode))
624108066Stjr		return;
625196712Strasz
626196712Strasz	if (previous_dev != p->fts_statp->st_dev) {
627196712Strasz		previous_dev = p->fts_statp->st_dev;
628196712Strasz		supports_acls = 0;
629196712Strasz
630196712Strasz		if (p->fts_level == FTS_ROOTLEVEL)
631196712Strasz			snprintf(name, sizeof(name), "%s", p->fts_name);
632196712Strasz		else
633196712Strasz			snprintf(name, sizeof(name), "%s/%s",
634196712Strasz			    p->fts_parent->fts_accpath, p->fts_name);
635196712Strasz		ret = lpathconf(name, _PC_ACL_NFS4);
636196712Strasz		if (ret > 0) {
637196712Strasz			type = ACL_TYPE_NFS4;
638196712Strasz			supports_acls = 1;
639196712Strasz		} else if (ret < 0 && errno != EINVAL) {
640196712Strasz			warn("%s", name);
641196712Strasz			return;
642196712Strasz		}
643196712Strasz		if (supports_acls == 0) {
644196712Strasz			ret = lpathconf(name, _PC_ACL_EXTENDED);
645196712Strasz			if (ret > 0) {
646196712Strasz				type = ACL_TYPE_ACCESS;
647196712Strasz				supports_acls = 1;
648196712Strasz			} else if (ret < 0 && errno != EINVAL) {
649196712Strasz				warn("%s", name);
650196712Strasz				return;
651196712Strasz			}
652196712Strasz		}
653108066Stjr	}
654196712Strasz	if (supports_acls == 0)
655106371Stjr		return;
656196712Strasz	facl = acl_get_link_np(name, type);
657196712Strasz	if (facl == NULL) {
658196712Strasz		warn("%s", name);
659196712Strasz		return;
660106371Stjr	}
661196712Strasz	if (acl_is_trivial_np(facl, &trivial)) {
662106371Stjr		acl_free(facl);
663106371Stjr		warn("%s", name);
664196712Strasz		return;
665196712Strasz	}
666196712Strasz	if (!trivial)
667196712Strasz		buf[10] = '+';
668196712Strasz	acl_free(facl);
669106371Stjr}
670