print.c revision 242840
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 242840 2012-11-09 20:19:56Z peter $");
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)
155241014Smdf			(void)printf("%*ju ",
156241014Smdf			    dp->s_inode, (uintmax_t)sp->st_ino);
1571556Srgrimes		if (f_size)
158114583Smarkm			(void)printf("%*jd ",
1591556Srgrimes			    dp->s_block, howmany(sp->st_blocks, blocksize));
16090150Smarkm		strmode(sp->st_mode, buf);
161196712Strasz		aclmode(buf, p);
1621556Srgrimes		np = p->fts_pointer;
163242840Speter		(void)printf("%s %*u %-*s  %-*s  ", buf, dp->s_nlink,
1641556Srgrimes		    sp->st_nlink, dp->s_user, np->user, dp->s_group,
1651556Srgrimes		    np->group);
1661556Srgrimes		if (f_flags)
1671556Srgrimes			(void)printf("%-*s ", dp->s_flags, np->flags);
168105832Srwatson		if (f_label)
169105832Srwatson			(void)printf("%-*s ", dp->s_label, np->label);
1701556Srgrimes		if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode))
171202945Sjh			printdev(dp->s_size, sp->st_rdev);
1721556Srgrimes		else
17388591Sjoe			printsize(dp->s_size, sp->st_size);
1741556Srgrimes		if (f_accesstime)
1751556Srgrimes			printtime(sp->st_atime);
176157098Sjhb		else if (f_birthtime)
177157098Sjhb			printtime(sp->st_birthtime);
1781556Srgrimes		else if (f_statustime)
1791556Srgrimes			printtime(sp->st_ctime);
1801556Srgrimes		else
1811556Srgrimes			printtime(sp->st_mtime);
18261268Sjoe#ifdef COLORLS
18361178Sjoe		if (f_color)
18461291Sache			color_printed = colortype(sp->st_mode);
18561268Sjoe#endif
18662597Sassar		(void)printname(p->fts_name);
18761268Sjoe#ifdef COLORLS
18861291Sache		if (f_color && color_printed)
18961321Sache			endcolor(0);
19061268Sjoe#endif
1911556Srgrimes		if (f_type)
1921556Srgrimes			(void)printtype(sp->st_mode);
1931556Srgrimes		if (S_ISLNK(sp->st_mode))
1941556Srgrimes			printlink(p);
1951556Srgrimes		(void)putchar('\n');
1961556Srgrimes	}
1971556Srgrimes}
1981556Srgrimes
1991556Srgrimesvoid
200114583Smarkmprintstream(const DISPLAY *dp)
20196892Stjr{
20296892Stjr	FTSENT *p;
20396892Stjr	int chcnt;
20496892Stjr
20596892Stjr	for (p = dp->list, chcnt = 0; p; p = p->fts_link) {
20696892Stjr		if (p->fts_number == NO_PRINT)
20796892Stjr			continue;
208128823Stjr		/* XXX strlen does not take octal escapes into account. */
20996892Stjr		if (strlen(p->fts_name) + chcnt +
21096892Stjr		    (p->fts_link ? 2 : 0) >= (unsigned)termwidth) {
21196892Stjr			putchar('\n');
21296892Stjr			chcnt = 0;
21396892Stjr		}
21496892Stjr		chcnt += printaname(p, dp->s_inode, dp->s_block);
21596892Stjr		if (p->fts_link) {
21696892Stjr			printf(", ");
21796892Stjr			chcnt += 2;
21896892Stjr		}
21996892Stjr	}
22096892Stjr	if (chcnt)
22196892Stjr		putchar('\n');
22296892Stjr}
223177907Sgrog
22496892Stjrvoid
225114583Smarkmprintcol(const DISPLAY *dp)
2261556Srgrimes{
2271556Srgrimes	static FTSENT **array;
2281556Srgrimes	static int lastentries = -1;
22988594Sjoe	FTSENT *p;
230121124Stjr	FTSENT **narray;
23188594Sjoe	int base;
23288594Sjoe	int chcnt;
23388594Sjoe	int cnt;
23488594Sjoe	int col;
23588594Sjoe	int colwidth;
23688594Sjoe	int endcol;
23788594Sjoe	int num;
23888594Sjoe	int numcols;
23988594Sjoe	int numrows;
24088594Sjoe	int row;
24188594Sjoe	int tabwidth;
2421556Srgrimes
24337932Shoek	if (f_notabs)
24437932Shoek		tabwidth = 1;
24537932Shoek	else
24637932Shoek		tabwidth = 8;
24737932Shoek
2481556Srgrimes	/*
2491556Srgrimes	 * Have to do random access in the linked list -- build a table
2501556Srgrimes	 * of pointers.
2511556Srgrimes	 */
2521556Srgrimes	if (dp->entries > lastentries) {
253121124Stjr		if ((narray =
2541556Srgrimes		    realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) {
2551556Srgrimes			warn(NULL);
2561556Srgrimes			printscol(dp);
257121124Stjr			return;
2581556Srgrimes		}
259121124Stjr		lastentries = dp->entries;
260121124Stjr		array = narray;
2611556Srgrimes	}
2621556Srgrimes	for (p = dp->list, num = 0; p; p = p->fts_link)
2631556Srgrimes		if (p->fts_number != NO_PRINT)
2641556Srgrimes			array[num++] = p;
2651556Srgrimes
2661556Srgrimes	colwidth = dp->maxlen;
2671556Srgrimes	if (f_inode)
2681556Srgrimes		colwidth += dp->s_inode + 1;
2691556Srgrimes	if (f_size)
2701556Srgrimes		colwidth += dp->s_block + 1;
2711556Srgrimes	if (f_type)
2721556Srgrimes		colwidth += 1;
2731556Srgrimes
27437932Shoek	colwidth = (colwidth + tabwidth) & ~(tabwidth - 1);
2751556Srgrimes	if (termwidth < 2 * colwidth) {
2761556Srgrimes		printscol(dp);
2771556Srgrimes		return;
2781556Srgrimes	}
2791556Srgrimes	numcols = termwidth / colwidth;
2801556Srgrimes	numrows = num / numcols;
2811556Srgrimes	if (num % numcols)
2821556Srgrimes		++numrows;
2831556Srgrimes
284130236Sdas	if ((dp->list == NULL || dp->list->fts_level != FTS_ROOTLEVEL) &&
285130236Sdas	    (f_longform || f_size)) {
2861556Srgrimes		(void)printf("total %lu\n", howmany(dp->btotal, blocksize));
287130236Sdas	}
28896892Stjr
289102577Skeramida	base = 0;
2901556Srgrimes	for (row = 0; row < numrows; ++row) {
2911556Srgrimes		endcol = colwidth;
29296892Stjr		if (!f_sortacross)
29396892Stjr			base = row;
29496892Stjr		for (col = 0, chcnt = 0; col < numcols; ++col) {
2951556Srgrimes			chcnt += printaname(array[base], dp->s_inode,
2961556Srgrimes			    dp->s_block);
29796892Stjr			if (f_sortacross)
29896892Stjr				base++;
29996892Stjr			else
30096892Stjr				base += numrows;
30196892Stjr			if (base >= num)
3021556Srgrimes				break;
30337932Shoek			while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1)))
30488595Sjoe			    <= endcol) {
30596892Stjr				if (f_sortacross && col + 1 >= numcols)
30696892Stjr					break;
30737932Shoek				(void)putchar(f_notabs ? ' ' : '\t');
3081556Srgrimes				chcnt = cnt;
3091556Srgrimes			}
3101556Srgrimes			endcol += colwidth;
3111556Srgrimes		}
3121556Srgrimes		(void)putchar('\n');
3131556Srgrimes	}
3141556Srgrimes}
3151556Srgrimes
3161556Srgrimes/*
3171556Srgrimes * print [inode] [size] name
3181556Srgrimes * return # of characters printed, no trailing characters.
3191556Srgrimes */
3201556Srgrimesstatic int
321114583Smarkmprintaname(const FTSENT *p, u_long inodefield, u_long sizefield)
3221556Srgrimes{
3231556Srgrimes	struct stat *sp;
32488594Sjoe	int chcnt;
32561292Sache#ifdef COLORLS
32688594Sjoe	int color_printed = 0;
32761292Sache#endif
3281556Srgrimes
3291556Srgrimes	sp = p->fts_statp;
3301556Srgrimes	chcnt = 0;
3311556Srgrimes	if (f_inode)
332241014Smdf		chcnt += printf("%*ju ",
333241014Smdf		    (int)inodefield, (uintmax_t)sp->st_ino);
3341556Srgrimes	if (f_size)
335114583Smarkm		chcnt += printf("%*jd ",
3361556Srgrimes		    (int)sizefield, howmany(sp->st_blocks, blocksize));
33761268Sjoe#ifdef COLORLS
33861178Sjoe	if (f_color)
33961291Sache		color_printed = colortype(sp->st_mode);
34061268Sjoe#endif
34162597Sassar	chcnt += printname(p->fts_name);
34261268Sjoe#ifdef COLORLS
34361291Sache	if (f_color && color_printed)
34461321Sache		endcolor(0);
34561268Sjoe#endif
3461556Srgrimes	if (f_type)
3471556Srgrimes		chcnt += printtype(sp->st_mode);
3481556Srgrimes	return (chcnt);
3491556Srgrimes}
3501556Srgrimes
351202945Sjh/*
352202945Sjh * Print device special file major and minor numbers.
353202945Sjh */
3541556Srgrimesstatic void
355202945Sjhprintdev(size_t width, dev_t dev)
356202945Sjh{
357202945Sjh
358225847Sed	(void)printf("%#*jx ", (u_int)width, (uintmax_t)dev);
359202945Sjh}
360202945Sjh
361202945Sjhstatic void
36290110Simpprinttime(time_t ftime)
3631556Srgrimes{
36488594Sjoe	char longstring[80];
365114583Smarkm	static time_t now = 0;
36688594Sjoe	const char *format;
36788594Sjoe	static int d_first = -1;
3681556Srgrimes
36974566Sache	if (d_first < 0)
37074566Sache		d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
37121545Smpp	if (now == 0)
37221545Smpp		now = time(NULL);
37321545Smpp
3749987Swollman#define	SIXMONTHS	((365 / 2) * 86400)
375177907Sgrog	if (f_timeformat)  /* user specified format */
376177907Sgrog		format = f_timeformat;
377177907Sgrog	else if (f_sectime)
37861920Sjoe		/* mmm dd hh:mm:ss yyyy || dd mmm hh:mm:ss yyyy */
379177907Sgrog		format = d_first ? "%e %b %T %Y" : "%b %e %T %Y";
38021545Smpp	else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS)
38161920Sjoe		/* mmm dd hh:mm || dd mmm hh:mm */
382177907Sgrog		format = d_first ? "%e %b %R" : "%b %e %R";
38361814Sjoe	else
38461920Sjoe		/* mmm dd  yyyy || dd mmm  yyyy */
385242840Speter		format = d_first ? "%e %b  %Y" : "%b %e  %Y";
38661814Sjoe	strftime(longstring, sizeof(longstring), format, localtime(&ftime));
38761814Sjoe	fputs(longstring, stdout);
388177907Sgrog	fputc(' ', stdout);
3891556Srgrimes}
3901556Srgrimes
3911556Srgrimesstatic int
39290110Simpprinttype(u_int mode)
3931556Srgrimes{
39496892Stjr
39596892Stjr	if (f_slash) {
39696892Stjr		if ((mode & S_IFMT) == S_IFDIR) {
39796892Stjr			(void)putchar('/');
39896892Stjr			return (1);
39996892Stjr		}
40096892Stjr		return (0);
40196892Stjr	}
40296892Stjr
4031556Srgrimes	switch (mode & S_IFMT) {
4041556Srgrimes	case S_IFDIR:
4051556Srgrimes		(void)putchar('/');
4061556Srgrimes		return (1);
4071556Srgrimes	case S_IFIFO:
4081556Srgrimes		(void)putchar('|');
4091556Srgrimes		return (1);
4101556Srgrimes	case S_IFLNK:
4111556Srgrimes		(void)putchar('@');
4121556Srgrimes		return (1);
4131556Srgrimes	case S_IFSOCK:
4141556Srgrimes		(void)putchar('=');
4151556Srgrimes		return (1);
41620417Ssteve	case S_IFWHT:
41720417Ssteve		(void)putchar('%');
41820417Ssteve		return (1);
41990150Smarkm	default:
42096681Sbillf		break;
4211556Srgrimes	}
4221556Srgrimes	if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
4231556Srgrimes		(void)putchar('*');
4241556Srgrimes		return (1);
4251556Srgrimes	}
4261556Srgrimes	return (0);
4271556Srgrimes}
4281556Srgrimes
42961268Sjoe#ifdef COLORLS
43061323Sachestatic int
43190110Simpputch(int c)
43261291Sache{
43388602Sjoe	(void)putchar(c);
43461321Sache	return 0;
43561291Sache}
43661291Sache
43761323Sachestatic int
43890110Simpwritech(int c)
43961321Sache{
440114583Smarkm	char tmp = (char)c;
44161291Sache
44288602Sjoe	(void)write(STDOUT_FILENO, &tmp, 1);
44361321Sache	return 0;
44461321Sache}
44561321Sache
44661323Sachestatic void
44790110Simpprintcolor(Colors c)
44861178Sjoe{
44988594Sjoe	char *ansiseq;
45061268Sjoe
45188583Sjoe	if (colors[c].bold)
45288583Sjoe		tputs(enter_bold, 1, putch);
45388583Sjoe
45488583Sjoe	if (colors[c].num[0] != -1) {
45588583Sjoe		ansiseq = tgoto(ansi_fgcol, 0, colors[c].num[0]);
45661321Sache		if (ansiseq)
45761291Sache			tputs(ansiseq, 1, putch);
45861178Sjoe	}
45988583Sjoe	if (colors[c].num[1] != -1) {
46088583Sjoe		ansiseq = tgoto(ansi_bgcol, 0, colors[c].num[1]);
46161321Sache		if (ansiseq)
46261291Sache			tputs(ansiseq, 1, putch);
46361268Sjoe	}
46461178Sjoe}
46561178Sjoe
46661321Sachestatic void
46790110Simpendcolor(int sig)
46861268Sjoe{
46961321Sache	tputs(ansi_coloff, 1, sig ? writech : putch);
47088583Sjoe	tputs(attrs_off, 1, sig ? writech : putch);
47161268Sjoe}
47261268Sjoe
47361321Sachestatic int
47490110Simpcolortype(mode_t mode)
47561178Sjoe{
47688602Sjoe	switch (mode & S_IFMT) {
47788595Sjoe	case S_IFDIR:
47861178Sjoe		if (mode & S_IWOTH)
47988595Sjoe			if (mode & S_ISTXT)
48088595Sjoe				printcolor(C_WSDIR);
48188595Sjoe			else
48288595Sjoe				printcolor(C_WDIR);
48361178Sjoe		else
48488595Sjoe			printcolor(C_DIR);
48588602Sjoe		return (1);
48688595Sjoe	case S_IFLNK:
48761178Sjoe		printcolor(C_LNK);
48888602Sjoe		return (1);
48988595Sjoe	case S_IFSOCK:
49061178Sjoe		printcolor(C_SOCK);
49188602Sjoe		return (1);
49288595Sjoe	case S_IFIFO:
49361178Sjoe		printcolor(C_FIFO);
49488602Sjoe		return (1);
49588595Sjoe	case S_IFBLK:
49661178Sjoe		printcolor(C_BLK);
49788602Sjoe		return (1);
49888595Sjoe	case S_IFCHR:
49961178Sjoe		printcolor(C_CHR);
50088602Sjoe		return (1);
501114583Smarkm	default:;
50261178Sjoe	}
50361178Sjoe	if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
50461178Sjoe		if (mode & S_ISUID)
50588595Sjoe			printcolor(C_SUID);
50661178Sjoe		else if (mode & S_ISGID)
50788595Sjoe			printcolor(C_SGID);
50861178Sjoe		else
50988595Sjoe			printcolor(C_EXEC);
51088602Sjoe		return (1);
51161178Sjoe	}
51288602Sjoe	return (0);
51361178Sjoe}
51461178Sjoe
51561178Sjoevoid
51690110Simpparsecolors(const char *cs)
51761178Sjoe{
51888594Sjoe	int i;
51988594Sjoe	int j;
520105780Smarkm	size_t len;
52188594Sjoe	char c[2];
52288594Sjoe	short legacy_warn = 0;
52361321Sache
52488586Sjoe	if (cs == NULL)
52588602Sjoe		cs = "";	/* LSCOLORS not set */
52661178Sjoe	len = strlen(cs);
527114583Smarkm	for (i = 0; i < (int)C_NUMCOLORS; i++) {
52888583Sjoe		colors[i].bold = 0;
52988583Sjoe
530114583Smarkm		if (len <= 2 * (size_t)i) {
53188586Sjoe			c[0] = defcolors[2 * i];
53288586Sjoe			c[1] = defcolors[2 * i + 1];
53388602Sjoe		} else {
53488586Sjoe			c[0] = cs[2 * i];
53588586Sjoe			c[1] = cs[2 * i + 1];
53661178Sjoe		}
53788602Sjoe		for (j = 0; j < 2; j++) {
53888583Sjoe			/* Legacy colours used 0-7 */
53988583Sjoe			if (c[j] >= '0' && c[j] <= '7') {
54088583Sjoe				colors[i].num[j] = c[j] - '0';
54188583Sjoe				if (!legacy_warn) {
542106479Stjr					warnx("LSCOLORS should use "
54388588Sjoe					    "characters a-h instead of 0-9 ("
544106479Stjr					    "see the manual page)");
54588583Sjoe				}
54688583Sjoe				legacy_warn = 1;
54788583Sjoe			} else if (c[j] >= 'a' && c[j] <= 'h')
54888583Sjoe				colors[i].num[j] = c[j] - 'a';
54988583Sjoe			else if (c[j] >= 'A' && c[j] <= 'H') {
55088583Sjoe				colors[i].num[j] = c[j] - 'A';
55188583Sjoe				colors[i].bold = 1;
552114583Smarkm			} else if (tolower((unsigned char)c[j]) == 'x')
55388583Sjoe				colors[i].num[j] = -1;
55488583Sjoe			else {
555106479Stjr				warnx("invalid character '%c' in LSCOLORS"
556106479Stjr				    " env var", c[j]);
55788584Sjoe				colors[i].num[j] = -1;
55861178Sjoe			}
55961178Sjoe		}
56061178Sjoe	}
56161178Sjoe}
56261291Sache
56361323Sachevoid
56490110Simpcolorquit(int sig)
56561291Sache{
56661321Sache	endcolor(sig);
56761294Sache
56888602Sjoe	(void)signal(sig, SIG_DFL);
56988602Sjoe	(void)kill(getpid(), sig);
57061291Sache}
57188602Sjoe
57288602Sjoe#endif /* COLORLS */
57388602Sjoe
5741556Srgrimesstatic void
575105780Smarkmprintlink(const FTSENT *p)
5761556Srgrimes{
57788594Sjoe	int lnklen;
57888594Sjoe	char name[MAXPATHLEN + 1];
57988594Sjoe	char path[MAXPATHLEN + 1];
5801556Srgrimes
5811556Srgrimes	if (p->fts_level == FTS_ROOTLEVEL)
5821556Srgrimes		(void)snprintf(name, sizeof(name), "%s", p->fts_name);
5838855Srgrimes	else
5841556Srgrimes		(void)snprintf(name, sizeof(name),
5851556Srgrimes		    "%s/%s", p->fts_parent->fts_accpath, p->fts_name);
5861556Srgrimes	if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) {
5871556Srgrimes		(void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno));
5881556Srgrimes		return;
5891556Srgrimes	}
5901556Srgrimes	path[lnklen] = '\0';
59162597Sassar	(void)printf(" -> ");
59290150Smarkm	(void)printname(path);
5931556Srgrimes}
59488591Sjoe
59588591Sjoestatic void
59690110Simpprintsize(size_t width, off_t bytes)
59788591Sjoe{
59888602Sjoe
59988591Sjoe	if (f_humanval) {
600202945Sjh		/*
601202945Sjh		 * Reserve one space before the size and allocate room for
602202945Sjh		 * the trailing '\0'.
603202945Sjh		 */
604202945Sjh		char buf[HUMANVALSTR_LEN - 1 + 1];
60588591Sjoe
606129719Spjd		humanize_number(buf, sizeof(buf), (int64_t)bytes, "",
607129719Spjd		    HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
608202945Sjh		(void)printf("%*s ", (u_int)width, buf);
609242807Sgrog	} else if (f_thousands) {		/* with commas */
610242725Sgrog		/* This format assignment needed to work round gcc bug. */
611242807Sgrog		const char *format = "%*j'd ";
612242725Sgrog		(void)printf(format, (u_int)width, bytes);
613242807Sgrog	} else
614114583Smarkm		(void)printf("%*jd ", (u_int)width, bytes);
61588591Sjoe}
61688591Sjoe
617196712Strasz/*
618196712Strasz * Add a + after the standard rwxrwxrwx mode if the file has an
619196712Strasz * ACL. strmode() reserves space at the end of the string.
620196712Strasz */
621106371Stjrstatic void
622196712Straszaclmode(char *buf, const FTSENT *p)
623106371Stjr{
624106371Stjr	char name[MAXPATHLEN + 1];
625196712Strasz	int ret, trivial;
626196712Strasz	static dev_t previous_dev = NODEV;
627196712Strasz	static int supports_acls = -1;
628196712Strasz	static int type = ACL_TYPE_ACCESS;
629106371Stjr	acl_t facl;
630106371Stjr
631106371Stjr	/*
632196712Strasz	 * XXX: ACLs are not supported on whiteouts and device files
633196712Strasz	 * residing on UFS.
634106371Stjr	 */
635196712Strasz	if (S_ISCHR(p->fts_statp->st_mode) || S_ISBLK(p->fts_statp->st_mode) ||
636196712Strasz	    S_ISWHT(p->fts_statp->st_mode))
637108066Stjr		return;
638196712Strasz
639196773Strasz	if (previous_dev == p->fts_statp->st_dev && supports_acls == 0)
640196773Strasz		return;
641196773Strasz
642196773Strasz	if (p->fts_level == FTS_ROOTLEVEL)
643196773Strasz		snprintf(name, sizeof(name), "%s", p->fts_name);
644196773Strasz	else
645196773Strasz		snprintf(name, sizeof(name), "%s/%s",
646196773Strasz		    p->fts_parent->fts_accpath, p->fts_name);
647196773Strasz
648196712Strasz	if (previous_dev != p->fts_statp->st_dev) {
649196712Strasz		previous_dev = p->fts_statp->st_dev;
650196712Strasz		supports_acls = 0;
651196712Strasz
652196712Strasz		ret = lpathconf(name, _PC_ACL_NFS4);
653196712Strasz		if (ret > 0) {
654196712Strasz			type = ACL_TYPE_NFS4;
655196712Strasz			supports_acls = 1;
656196712Strasz		} else if (ret < 0 && errno != EINVAL) {
657196712Strasz			warn("%s", name);
658196712Strasz			return;
659196712Strasz		}
660196712Strasz		if (supports_acls == 0) {
661196712Strasz			ret = lpathconf(name, _PC_ACL_EXTENDED);
662196712Strasz			if (ret > 0) {
663196712Strasz				type = ACL_TYPE_ACCESS;
664196712Strasz				supports_acls = 1;
665196712Strasz			} else if (ret < 0 && errno != EINVAL) {
666196712Strasz				warn("%s", name);
667196712Strasz				return;
668196712Strasz			}
669196712Strasz		}
670108066Stjr	}
671196712Strasz	if (supports_acls == 0)
672106371Stjr		return;
673196712Strasz	facl = acl_get_link_np(name, type);
674196712Strasz	if (facl == NULL) {
675196712Strasz		warn("%s", name);
676196712Strasz		return;
677106371Stjr	}
678196712Strasz	if (acl_is_trivial_np(facl, &trivial)) {
679106371Stjr		acl_free(facl);
680106371Stjr		warn("%s", name);
681196712Strasz		return;
682196712Strasz	}
683196712Strasz	if (!trivial)
684196712Strasz		buf[10] = '+';
685196712Strasz	acl_free(facl);
686106371Stjr}
687