print.c revision 225847
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 225847 2011-09-28 18:53:36Z ed $");
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>
51225847Sed#include <stdint.h>
521556Srgrimes#include <stdlib.h>
531556Srgrimes#include <string.h>
5491212Sbde#include <time.h>
551556Srgrimes#include <unistd.h>
5661294Sache#ifdef COLORLS
5761294Sache#include <ctype.h>
5861294Sache#include <termcap.h>
5961294Sache#include <signal.h>
6061294Sache#endif
611556Srgrimes
621556Srgrimes#include "ls.h"
631556Srgrimes#include "extern.h"
641556Srgrimes
65114583Smarkmstatic int	printaname(const FTSENT *, u_long, u_long);
66202945Sjhstatic void	printdev(size_t, dev_t);
67105780Smarkmstatic void	printlink(const FTSENT *);
6890110Simpstatic void	printtime(time_t);
6990110Simpstatic int	printtype(u_int);
7090110Simpstatic void	printsize(size_t, off_t);
7161321Sache#ifdef COLORLS
7290110Simpstatic void	endcolor(int);
7390110Simpstatic int	colortype(mode_t);
7461321Sache#endif
75196712Straszstatic void	aclmode(char *, const FTSENT *);
761556Srgrimes
771556Srgrimes#define	IS_NOPRINT(p)	((p)->fts_number == NO_PRINT)
781556Srgrimes
7961268Sjoe#ifdef COLORLS
8061178Sjoe/* Most of these are taken from <sys/stat.h> */
8161178Sjoetypedef enum Colors {
8288602Sjoe	C_DIR,			/* directory */
8388602Sjoe	C_LNK,			/* symbolic link */
8488602Sjoe	C_SOCK,			/* socket */
8588602Sjoe	C_FIFO,			/* pipe */
8688602Sjoe	C_EXEC,			/* executable */
8788602Sjoe	C_BLK,			/* block special */
8888602Sjoe	C_CHR,			/* character special */
8988602Sjoe	C_SUID,			/* setuid executable */
9088602Sjoe	C_SGID,			/* setgid executable */
9188602Sjoe	C_WSDIR,		/* directory writeble to others, with sticky
9288602Sjoe				 * bit */
9388602Sjoe	C_WDIR,			/* directory writeble to others, without
9488602Sjoe				 * sticky bit */
9588602Sjoe	C_NUMCOLORS		/* just a place-holder */
9688586Sjoe} Colors;
9761178Sjoe
9890150Smarkmstatic const char *defcolors = "exfxcxdxbxegedabagacad";
9961178Sjoe
10088583Sjoe/* colors for file types */
10188583Sjoestatic struct {
10288586Sjoe	int	num[2];
10388586Sjoe	int	bold;
10488583Sjoe} colors[C_NUMCOLORS];
10561268Sjoe#endif
10661178Sjoe
1071556Srgrimesvoid
108114583Smarkmprintscol(const DISPLAY *dp)
1091556Srgrimes{
11088594Sjoe	FTSENT *p;
1111556Srgrimes
1121556Srgrimes	for (p = dp->list; p; p = p->fts_link) {
1131556Srgrimes		if (IS_NOPRINT(p))
1141556Srgrimes			continue;
1151556Srgrimes		(void)printaname(p, dp->s_inode, dp->s_block);
1161556Srgrimes		(void)putchar('\n');
1171556Srgrimes	}
1181556Srgrimes}
1191556Srgrimes
12062597Sassar/*
12162597Sassar * print name in current style
12262597Sassar */
123105390Stjrint
12490110Simpprintname(const char *name)
12562597Sassar{
12662597Sassar	if (f_octal || f_octal_escape)
12762597Sassar		return prn_octal(name);
12862597Sassar	else if (f_nonprint)
12962597Sassar		return prn_printable(name);
13062597Sassar	else
131128823Stjr		return prn_normal(name);
13262597Sassar}
13362597Sassar
1341556Srgrimesvoid
135114583Smarkmprintlong(const DISPLAY *dp)
1361556Srgrimes{
1371556Srgrimes	struct stat *sp;
13888594Sjoe	FTSENT *p;
13988594Sjoe	NAMES *np;
14088594Sjoe	char buf[20];
14161292Sache#ifdef COLORLS
14288594Sjoe	int color_printed = 0;
14361292Sache#endif
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
1501556Srgrimes	for (p = dp->list; p; p = p->fts_link) {
1511556Srgrimes		if (IS_NOPRINT(p))
1521556Srgrimes			continue;
1531556Srgrimes		sp = p->fts_statp;
1541556Srgrimes		if (f_inode)
15520417Ssteve			(void)printf("%*lu ", dp->s_inode, (u_long)sp->st_ino);
1561556Srgrimes		if (f_size)
157114583Smarkm			(void)printf("%*jd ",
1581556Srgrimes			    dp->s_block, howmany(sp->st_blocks, blocksize));
15990150Smarkm		strmode(sp->st_mode, buf);
160196712Strasz		aclmode(buf, p);
1611556Srgrimes		np = p->fts_pointer;
162177942Simp		(void)printf("%s %*u %-*s  %-*s  ", buf, dp->s_nlink,
1631556Srgrimes		    sp->st_nlink, dp->s_user, np->user, dp->s_group,
1641556Srgrimes		    np->group);
1651556Srgrimes		if (f_flags)
1661556Srgrimes			(void)printf("%-*s ", dp->s_flags, np->flags);
167105832Srwatson		if (f_label)
168105832Srwatson			(void)printf("%-*s ", dp->s_label, np->label);
1691556Srgrimes		if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode))
170202945Sjh			printdev(dp->s_size, sp->st_rdev);
1711556Srgrimes		else
17288591Sjoe			printsize(dp->s_size, sp->st_size);
1731556Srgrimes		if (f_accesstime)
1741556Srgrimes			printtime(sp->st_atime);
175157098Sjhb		else if (f_birthtime)
176157098Sjhb			printtime(sp->st_birthtime);
1771556Srgrimes		else if (f_statustime)
1781556Srgrimes			printtime(sp->st_ctime);
1791556Srgrimes		else
1801556Srgrimes			printtime(sp->st_mtime);
18161268Sjoe#ifdef COLORLS
18261178Sjoe		if (f_color)
18361291Sache			color_printed = colortype(sp->st_mode);
18461268Sjoe#endif
18562597Sassar		(void)printname(p->fts_name);
18661268Sjoe#ifdef COLORLS
18761291Sache		if (f_color && color_printed)
18861321Sache			endcolor(0);
18961268Sjoe#endif
1901556Srgrimes		if (f_type)
1911556Srgrimes			(void)printtype(sp->st_mode);
1921556Srgrimes		if (S_ISLNK(sp->st_mode))
1931556Srgrimes			printlink(p);
1941556Srgrimes		(void)putchar('\n');
1951556Srgrimes	}
1961556Srgrimes}
1971556Srgrimes
1981556Srgrimesvoid
199114583Smarkmprintstream(const DISPLAY *dp)
20096892Stjr{
20196892Stjr	FTSENT *p;
20296892Stjr	int chcnt;
20396892Stjr
20496892Stjr	for (p = dp->list, chcnt = 0; p; p = p->fts_link) {
20596892Stjr		if (p->fts_number == NO_PRINT)
20696892Stjr			continue;
207128823Stjr		/* XXX strlen does not take octal escapes into account. */
20896892Stjr		if (strlen(p->fts_name) + chcnt +
20996892Stjr		    (p->fts_link ? 2 : 0) >= (unsigned)termwidth) {
21096892Stjr			putchar('\n');
21196892Stjr			chcnt = 0;
21296892Stjr		}
21396892Stjr		chcnt += printaname(p, dp->s_inode, dp->s_block);
21496892Stjr		if (p->fts_link) {
21596892Stjr			printf(", ");
21696892Stjr			chcnt += 2;
21796892Stjr		}
21896892Stjr	}
21996892Stjr	if (chcnt)
22096892Stjr		putchar('\n');
22196892Stjr}
222177907Sgrog
22396892Stjrvoid
224114583Smarkmprintcol(const DISPLAY *dp)
2251556Srgrimes{
2261556Srgrimes	static FTSENT **array;
2271556Srgrimes	static int lastentries = -1;
22888594Sjoe	FTSENT *p;
229121124Stjr	FTSENT **narray;
23088594Sjoe	int base;
23188594Sjoe	int chcnt;
23288594Sjoe	int cnt;
23388594Sjoe	int col;
23488594Sjoe	int colwidth;
23588594Sjoe	int endcol;
23688594Sjoe	int num;
23788594Sjoe	int numcols;
23888594Sjoe	int numrows;
23988594Sjoe	int row;
24088594Sjoe	int tabwidth;
2411556Srgrimes
24237932Shoek	if (f_notabs)
24337932Shoek		tabwidth = 1;
24437932Shoek	else
24537932Shoek		tabwidth = 8;
24637932Shoek
2471556Srgrimes	/*
2481556Srgrimes	 * Have to do random access in the linked list -- build a table
2491556Srgrimes	 * of pointers.
2501556Srgrimes	 */
2511556Srgrimes	if (dp->entries > lastentries) {
252121124Stjr		if ((narray =
2531556Srgrimes		    realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) {
2541556Srgrimes			warn(NULL);
2551556Srgrimes			printscol(dp);
256121124Stjr			return;
2571556Srgrimes		}
258121124Stjr		lastentries = dp->entries;
259121124Stjr		array = narray;
2601556Srgrimes	}
2611556Srgrimes	for (p = dp->list, num = 0; p; p = p->fts_link)
2621556Srgrimes		if (p->fts_number != NO_PRINT)
2631556Srgrimes			array[num++] = p;
2641556Srgrimes
2651556Srgrimes	colwidth = dp->maxlen;
2661556Srgrimes	if (f_inode)
2671556Srgrimes		colwidth += dp->s_inode + 1;
2681556Srgrimes	if (f_size)
2691556Srgrimes		colwidth += dp->s_block + 1;
2701556Srgrimes	if (f_type)
2711556Srgrimes		colwidth += 1;
2721556Srgrimes
27337932Shoek	colwidth = (colwidth + tabwidth) & ~(tabwidth - 1);
2741556Srgrimes	if (termwidth < 2 * colwidth) {
2751556Srgrimes		printscol(dp);
2761556Srgrimes		return;
2771556Srgrimes	}
2781556Srgrimes	numcols = termwidth / colwidth;
2791556Srgrimes	numrows = num / numcols;
2801556Srgrimes	if (num % numcols)
2811556Srgrimes		++numrows;
2821556Srgrimes
283130236Sdas	if ((dp->list == NULL || dp->list->fts_level != FTS_ROOTLEVEL) &&
284130236Sdas	    (f_longform || f_size)) {
2851556Srgrimes		(void)printf("total %lu\n", howmany(dp->btotal, blocksize));
286130236Sdas	}
28796892Stjr
288102577Skeramida	base = 0;
2891556Srgrimes	for (row = 0; row < numrows; ++row) {
2901556Srgrimes		endcol = colwidth;
29196892Stjr		if (!f_sortacross)
29296892Stjr			base = row;
29396892Stjr		for (col = 0, chcnt = 0; col < numcols; ++col) {
2941556Srgrimes			chcnt += printaname(array[base], dp->s_inode,
2951556Srgrimes			    dp->s_block);
29696892Stjr			if (f_sortacross)
29796892Stjr				base++;
29896892Stjr			else
29996892Stjr				base += numrows;
30096892Stjr			if (base >= num)
3011556Srgrimes				break;
30237932Shoek			while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1)))
30388595Sjoe			    <= endcol) {
30496892Stjr				if (f_sortacross && col + 1 >= numcols)
30596892Stjr					break;
30637932Shoek				(void)putchar(f_notabs ? ' ' : '\t');
3071556Srgrimes				chcnt = cnt;
3081556Srgrimes			}
3091556Srgrimes			endcol += colwidth;
3101556Srgrimes		}
3111556Srgrimes		(void)putchar('\n');
3121556Srgrimes	}
3131556Srgrimes}
3141556Srgrimes
3151556Srgrimes/*
3161556Srgrimes * print [inode] [size] name
3171556Srgrimes * return # of characters printed, no trailing characters.
3181556Srgrimes */
3191556Srgrimesstatic int
320114583Smarkmprintaname(const FTSENT *p, u_long inodefield, u_long sizefield)
3211556Srgrimes{
3221556Srgrimes	struct stat *sp;
32388594Sjoe	int chcnt;
32461292Sache#ifdef COLORLS
32588594Sjoe	int color_printed = 0;
32661292Sache#endif
3271556Srgrimes
3281556Srgrimes	sp = p->fts_statp;
3291556Srgrimes	chcnt = 0;
3301556Srgrimes	if (f_inode)
33120417Ssteve		chcnt += printf("%*lu ", (int)inodefield, (u_long)sp->st_ino);
3321556Srgrimes	if (f_size)
333114583Smarkm		chcnt += printf("%*jd ",
3341556Srgrimes		    (int)sizefield, howmany(sp->st_blocks, blocksize));
33561268Sjoe#ifdef COLORLS
33661178Sjoe	if (f_color)
33761291Sache		color_printed = colortype(sp->st_mode);
33861268Sjoe#endif
33962597Sassar	chcnt += printname(p->fts_name);
34061268Sjoe#ifdef COLORLS
34161291Sache	if (f_color && color_printed)
34261321Sache		endcolor(0);
34361268Sjoe#endif
3441556Srgrimes	if (f_type)
3451556Srgrimes		chcnt += printtype(sp->st_mode);
3461556Srgrimes	return (chcnt);
3471556Srgrimes}
3481556Srgrimes
349202945Sjh/*
350202945Sjh * Print device special file major and minor numbers.
351202945Sjh */
3521556Srgrimesstatic void
353202945Sjhprintdev(size_t width, dev_t dev)
354202945Sjh{
355202945Sjh
356225847Sed	(void)printf("%#*jx ", (u_int)width, (uintmax_t)dev);
357202945Sjh}
358202945Sjh
359202945Sjhstatic void
36090110Simpprinttime(time_t ftime)
3611556Srgrimes{
36288594Sjoe	char longstring[80];
363114583Smarkm	static time_t now = 0;
36488594Sjoe	const char *format;
36588594Sjoe	static int d_first = -1;
3661556Srgrimes
36774566Sache	if (d_first < 0)
36874566Sache		d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
36921545Smpp	if (now == 0)
37021545Smpp		now = time(NULL);
37121545Smpp
3729987Swollman#define	SIXMONTHS	((365 / 2) * 86400)
373177907Sgrog	if (f_timeformat)  /* user specified format */
374177907Sgrog		format = f_timeformat;
375177907Sgrog	else if (f_sectime)
37661920Sjoe		/* mmm dd hh:mm:ss yyyy || dd mmm hh:mm:ss yyyy */
377177907Sgrog		format = d_first ? "%e %b %T %Y" : "%b %e %T %Y";
37821545Smpp	else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS)
37961920Sjoe		/* mmm dd hh:mm || dd mmm hh:mm */
380177907Sgrog		format = d_first ? "%e %b %R" : "%b %e %R";
38161814Sjoe	else
38261920Sjoe		/* mmm dd  yyyy || dd mmm  yyyy */
383177942Simp		format = d_first ? "%e %b  %Y" : "%b %e  %Y";
38461814Sjoe	strftime(longstring, sizeof(longstring), format, localtime(&ftime));
38561814Sjoe	fputs(longstring, stdout);
386177907Sgrog	fputc(' ', stdout);
3871556Srgrimes}
3881556Srgrimes
3891556Srgrimesstatic int
39090110Simpprinttype(u_int mode)
3911556Srgrimes{
39296892Stjr
39396892Stjr	if (f_slash) {
39496892Stjr		if ((mode & S_IFMT) == S_IFDIR) {
39596892Stjr			(void)putchar('/');
39696892Stjr			return (1);
39796892Stjr		}
39896892Stjr		return (0);
39996892Stjr	}
40096892Stjr
4011556Srgrimes	switch (mode & S_IFMT) {
4021556Srgrimes	case S_IFDIR:
4031556Srgrimes		(void)putchar('/');
4041556Srgrimes		return (1);
4051556Srgrimes	case S_IFIFO:
4061556Srgrimes		(void)putchar('|');
4071556Srgrimes		return (1);
4081556Srgrimes	case S_IFLNK:
4091556Srgrimes		(void)putchar('@');
4101556Srgrimes		return (1);
4111556Srgrimes	case S_IFSOCK:
4121556Srgrimes		(void)putchar('=');
4131556Srgrimes		return (1);
41420417Ssteve	case S_IFWHT:
41520417Ssteve		(void)putchar('%');
41620417Ssteve		return (1);
41790150Smarkm	default:
41896681Sbillf		break;
4191556Srgrimes	}
4201556Srgrimes	if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
4211556Srgrimes		(void)putchar('*');
4221556Srgrimes		return (1);
4231556Srgrimes	}
4241556Srgrimes	return (0);
4251556Srgrimes}
4261556Srgrimes
42761268Sjoe#ifdef COLORLS
42861323Sachestatic int
42990110Simpputch(int c)
43061291Sache{
43188602Sjoe	(void)putchar(c);
43261321Sache	return 0;
43361291Sache}
43461291Sache
43561323Sachestatic int
43690110Simpwritech(int c)
43761321Sache{
438114583Smarkm	char tmp = (char)c;
43961291Sache
44088602Sjoe	(void)write(STDOUT_FILENO, &tmp, 1);
44161321Sache	return 0;
44261321Sache}
44361321Sache
44461323Sachestatic void
44590110Simpprintcolor(Colors c)
44661178Sjoe{
44788594Sjoe	char *ansiseq;
44861268Sjoe
44988583Sjoe	if (colors[c].bold)
45088583Sjoe		tputs(enter_bold, 1, putch);
45188583Sjoe
45288583Sjoe	if (colors[c].num[0] != -1) {
45388583Sjoe		ansiseq = tgoto(ansi_fgcol, 0, colors[c].num[0]);
45461321Sache		if (ansiseq)
45561291Sache			tputs(ansiseq, 1, putch);
45661178Sjoe	}
45788583Sjoe	if (colors[c].num[1] != -1) {
45888583Sjoe		ansiseq = tgoto(ansi_bgcol, 0, colors[c].num[1]);
45961321Sache		if (ansiseq)
46061291Sache			tputs(ansiseq, 1, putch);
46161268Sjoe	}
46261178Sjoe}
46361178Sjoe
46461321Sachestatic void
46590110Simpendcolor(int sig)
46661268Sjoe{
46761321Sache	tputs(ansi_coloff, 1, sig ? writech : putch);
46888583Sjoe	tputs(attrs_off, 1, sig ? writech : putch);
46961268Sjoe}
47061268Sjoe
47161321Sachestatic int
47290110Simpcolortype(mode_t mode)
47361178Sjoe{
47488602Sjoe	switch (mode & S_IFMT) {
47588595Sjoe	case S_IFDIR:
47661178Sjoe		if (mode & S_IWOTH)
47788595Sjoe			if (mode & S_ISTXT)
47888595Sjoe				printcolor(C_WSDIR);
47988595Sjoe			else
48088595Sjoe				printcolor(C_WDIR);
48161178Sjoe		else
48288595Sjoe			printcolor(C_DIR);
48388602Sjoe		return (1);
48488595Sjoe	case S_IFLNK:
48561178Sjoe		printcolor(C_LNK);
48688602Sjoe		return (1);
48788595Sjoe	case S_IFSOCK:
48861178Sjoe		printcolor(C_SOCK);
48988602Sjoe		return (1);
49088595Sjoe	case S_IFIFO:
49161178Sjoe		printcolor(C_FIFO);
49288602Sjoe		return (1);
49388595Sjoe	case S_IFBLK:
49461178Sjoe		printcolor(C_BLK);
49588602Sjoe		return (1);
49688595Sjoe	case S_IFCHR:
49761178Sjoe		printcolor(C_CHR);
49888602Sjoe		return (1);
499114583Smarkm	default:;
50061178Sjoe	}
50161178Sjoe	if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
50261178Sjoe		if (mode & S_ISUID)
50388595Sjoe			printcolor(C_SUID);
50461178Sjoe		else if (mode & S_ISGID)
50588595Sjoe			printcolor(C_SGID);
50661178Sjoe		else
50788595Sjoe			printcolor(C_EXEC);
50888602Sjoe		return (1);
50961178Sjoe	}
51088602Sjoe	return (0);
51161178Sjoe}
51261178Sjoe
51361178Sjoevoid
51490110Simpparsecolors(const char *cs)
51561178Sjoe{
51688594Sjoe	int i;
51788594Sjoe	int j;
518105780Smarkm	size_t len;
51988594Sjoe	char c[2];
52088594Sjoe	short legacy_warn = 0;
52161321Sache
52288586Sjoe	if (cs == NULL)
52388602Sjoe		cs = "";	/* LSCOLORS not set */
52461178Sjoe	len = strlen(cs);
525114583Smarkm	for (i = 0; i < (int)C_NUMCOLORS; i++) {
52688583Sjoe		colors[i].bold = 0;
52788583Sjoe
528114583Smarkm		if (len <= 2 * (size_t)i) {
52988586Sjoe			c[0] = defcolors[2 * i];
53088586Sjoe			c[1] = defcolors[2 * i + 1];
53188602Sjoe		} else {
53288586Sjoe			c[0] = cs[2 * i];
53388586Sjoe			c[1] = cs[2 * i + 1];
53461178Sjoe		}
53588602Sjoe		for (j = 0; j < 2; j++) {
53688583Sjoe			/* Legacy colours used 0-7 */
53788583Sjoe			if (c[j] >= '0' && c[j] <= '7') {
53888583Sjoe				colors[i].num[j] = c[j] - '0';
53988583Sjoe				if (!legacy_warn) {
540106479Stjr					warnx("LSCOLORS should use "
54188588Sjoe					    "characters a-h instead of 0-9 ("
542106479Stjr					    "see the manual page)");
54388583Sjoe				}
54488583Sjoe				legacy_warn = 1;
54588583Sjoe			} else if (c[j] >= 'a' && c[j] <= 'h')
54688583Sjoe				colors[i].num[j] = c[j] - 'a';
54788583Sjoe			else if (c[j] >= 'A' && c[j] <= 'H') {
54888583Sjoe				colors[i].num[j] = c[j] - 'A';
54988583Sjoe				colors[i].bold = 1;
550114583Smarkm			} else if (tolower((unsigned char)c[j]) == 'x')
55188583Sjoe				colors[i].num[j] = -1;
55288583Sjoe			else {
553106479Stjr				warnx("invalid character '%c' in LSCOLORS"
554106479Stjr				    " env var", c[j]);
55588584Sjoe				colors[i].num[j] = -1;
55661178Sjoe			}
55761178Sjoe		}
55861178Sjoe	}
55961178Sjoe}
56061291Sache
56161323Sachevoid
56290110Simpcolorquit(int sig)
56361291Sache{
56461321Sache	endcolor(sig);
56561294Sache
56688602Sjoe	(void)signal(sig, SIG_DFL);
56788602Sjoe	(void)kill(getpid(), sig);
56861291Sache}
56988602Sjoe
57088602Sjoe#endif /* COLORLS */
57188602Sjoe
5721556Srgrimesstatic void
573105780Smarkmprintlink(const FTSENT *p)
5741556Srgrimes{
57588594Sjoe	int lnklen;
57688594Sjoe	char name[MAXPATHLEN + 1];
57788594Sjoe	char path[MAXPATHLEN + 1];
5781556Srgrimes
5791556Srgrimes	if (p->fts_level == FTS_ROOTLEVEL)
5801556Srgrimes		(void)snprintf(name, sizeof(name), "%s", p->fts_name);
5818855Srgrimes	else
5821556Srgrimes		(void)snprintf(name, sizeof(name),
5831556Srgrimes		    "%s/%s", p->fts_parent->fts_accpath, p->fts_name);
5841556Srgrimes	if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) {
5851556Srgrimes		(void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno));
5861556Srgrimes		return;
5871556Srgrimes	}
5881556Srgrimes	path[lnklen] = '\0';
58962597Sassar	(void)printf(" -> ");
59090150Smarkm	(void)printname(path);
5911556Srgrimes}
59288591Sjoe
59388591Sjoestatic void
59490110Simpprintsize(size_t width, off_t bytes)
59588591Sjoe{
59688602Sjoe
59788591Sjoe	if (f_humanval) {
598202945Sjh		/*
599202945Sjh		 * Reserve one space before the size and allocate room for
600202945Sjh		 * the trailing '\0'.
601202945Sjh		 */
602202945Sjh		char buf[HUMANVALSTR_LEN - 1 + 1];
60388591Sjoe
604129719Spjd		humanize_number(buf, sizeof(buf), (int64_t)bytes, "",
605129719Spjd		    HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
606202945Sjh		(void)printf("%*s ", (u_int)width, buf);
60788602Sjoe	} else
608114583Smarkm		(void)printf("%*jd ", (u_int)width, bytes);
60988591Sjoe}
61088591Sjoe
611196712Strasz/*
612196712Strasz * Add a + after the standard rwxrwxrwx mode if the file has an
613196712Strasz * ACL. strmode() reserves space at the end of the string.
614196712Strasz */
615106371Stjrstatic void
616196712Straszaclmode(char *buf, const FTSENT *p)
617106371Stjr{
618106371Stjr	char name[MAXPATHLEN + 1];
619196712Strasz	int ret, trivial;
620196712Strasz	static dev_t previous_dev = NODEV;
621196712Strasz	static int supports_acls = -1;
622196712Strasz	static int type = ACL_TYPE_ACCESS;
623106371Stjr	acl_t facl;
624106371Stjr
625106371Stjr	/*
626196712Strasz	 * XXX: ACLs are not supported on whiteouts and device files
627196712Strasz	 * residing on UFS.
628106371Stjr	 */
629196712Strasz	if (S_ISCHR(p->fts_statp->st_mode) || S_ISBLK(p->fts_statp->st_mode) ||
630196712Strasz	    S_ISWHT(p->fts_statp->st_mode))
631108066Stjr		return;
632196712Strasz
633196773Strasz	if (previous_dev == p->fts_statp->st_dev && supports_acls == 0)
634196773Strasz		return;
635196773Strasz
636196773Strasz	if (p->fts_level == FTS_ROOTLEVEL)
637196773Strasz		snprintf(name, sizeof(name), "%s", p->fts_name);
638196773Strasz	else
639196773Strasz		snprintf(name, sizeof(name), "%s/%s",
640196773Strasz		    p->fts_parent->fts_accpath, p->fts_name);
641196773Strasz
642196712Strasz	if (previous_dev != p->fts_statp->st_dev) {
643196712Strasz		previous_dev = p->fts_statp->st_dev;
644196712Strasz		supports_acls = 0;
645196712Strasz
646196712Strasz		ret = lpathconf(name, _PC_ACL_NFS4);
647196712Strasz		if (ret > 0) {
648196712Strasz			type = ACL_TYPE_NFS4;
649196712Strasz			supports_acls = 1;
650196712Strasz		} else if (ret < 0 && errno != EINVAL) {
651196712Strasz			warn("%s", name);
652196712Strasz			return;
653196712Strasz		}
654196712Strasz		if (supports_acls == 0) {
655196712Strasz			ret = lpathconf(name, _PC_ACL_EXTENDED);
656196712Strasz			if (ret > 0) {
657196712Strasz				type = ACL_TYPE_ACCESS;
658196712Strasz				supports_acls = 1;
659196712Strasz			} else if (ret < 0 && errno != EINVAL) {
660196712Strasz				warn("%s", name);
661196712Strasz				return;
662196712Strasz			}
663196712Strasz		}
664108066Stjr	}
665196712Strasz	if (supports_acls == 0)
666106371Stjr		return;
667196712Strasz	facl = acl_get_link_np(name, type);
668196712Strasz	if (facl == NULL) {
669196712Strasz		warn("%s", name);
670196712Strasz		return;
671106371Stjr	}
672196712Strasz	if (acl_is_trivial_np(facl, &trivial)) {
673106371Stjr		acl_free(facl);
674106371Stjr		warn("%s", name);
675196712Strasz		return;
676196712Strasz	}
677196712Strasz	if (!trivial)
678196712Strasz		buf[10] = '+';
679196712Strasz	acl_free(facl);
680106371Stjr}
681