print.c revision 242840
10SN/A/*-
214627Snaoto * Copyright (c) 1989, 1993, 1994
30SN/A *	The Regents of the University of California.  All rights reserved.
40SN/A *
50SN/A * This code is derived from software contributed to Berkeley by
60SN/A * Michael Fischbein.
72362SN/A *
80SN/A * Redistribution and use in source and binary forms, with or without
92362SN/A * modification, are permitted provided that the following conditions
100SN/A * are met:
110SN/A * 1. Redistributions of source code must retain the above copyright
120SN/A *    notice, this list of conditions and the following disclaimer.
130SN/A * 2. Redistributions in binary form must reproduce the above copyright
140SN/A *    notice, this list of conditions and the following disclaimer in the
150SN/A *    documentation and/or other materials provided with the distribution.
160SN/A * 4. Neither the name of the University nor the names of its contributors
170SN/A *    may be used to endorse or promote products derived from this software
180SN/A *    without specific prior written permission.
190SN/A *
200SN/A * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
212362SN/A * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
222362SN/A * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
232362SN/A * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
240SN/A * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
250SN/A * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
260SN/A * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
270SN/A * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
280SN/A * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
290SN/A * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
300SN/A * SUCH DAMAGE.
310SN/A */
320SN/A
330SN/A#if 0
340SN/A#ifndef lint
350SN/Astatic char sccsid[] = "@(#)print.c	8.4 (Berkeley) 4/17/94";
360SN/A#endif /* not lint */
370SN/A#endif
380SN/A#include <sys/cdefs.h>
390SN/A__FBSDID("$FreeBSD: head/bin/ls/print.c 242840 2012-11-09 20:19:56Z peter $");
400SN/A
410SN/A#include <sys/param.h>
420SN/A#include <sys/stat.h>
430SN/A#include <sys/acl.h>
440SN/A
450SN/A#include <err.h>
460SN/A#include <errno.h>
475731SN/A#include <fts.h>
480SN/A#include <langinfo.h>
495116SN/A#include <libutil.h>
505116SN/A#include <stdio.h>
515116SN/A#include <stdint.h>
525116SN/A#include <stdlib.h>
535116SN/A#include <string.h>
540SN/A#include <time.h>
550SN/A#include <unistd.h>
560SN/A#ifdef COLORLS
570SN/A#include <ctype.h>
580SN/A#include <termcap.h>
590SN/A#include <signal.h>
600SN/A#endif
610SN/A
620SN/A#include "ls.h"
630SN/A#include "extern.h"
640SN/A
650SN/Astatic int	printaname(const FTSENT *, u_long, u_long);
660SN/Astatic void	printdev(size_t, dev_t);
670SN/Astatic void	printlink(const FTSENT *);
680SN/Astatic void	printtime(time_t);
690SN/Astatic int	printtype(u_int);
700SN/Astatic void	printsize(size_t, off_t);
710SN/A#ifdef COLORLS
720SN/Astatic void	endcolor(int);
730SN/Astatic int	colortype(mode_t);
740SN/A#endif
750SN/Astatic void	aclmode(char *, const FTSENT *);
760SN/A
770SN/A#define	IS_NOPRINT(p)	((p)->fts_number == NO_PRINT)
780SN/A
790SN/A#ifdef COLORLS
8014627Snaoto/* Most of these are taken from <sys/stat.h> */
8114627Snaototypedef enum Colors {
8214627Snaoto	C_DIR,			/* directory */
8314627Snaoto	C_LNK,			/* symbolic link */
8414627Snaoto	C_SOCK,			/* socket */
8514627Snaoto	C_FIFO,			/* pipe */
8614627Snaoto	C_EXEC,			/* executable */
870SN/A	C_BLK,			/* block special */
880SN/A	C_CHR,			/* character special */
890SN/A	C_SUID,			/* setuid executable */
900SN/A	C_SGID,			/* setgid executable */
910SN/A	C_WSDIR,		/* directory writeble to others, with sticky
920SN/A				 * bit */
930SN/A	C_WDIR,			/* directory writeble to others, without
940SN/A				 * sticky bit */
950SN/A	C_NUMCOLORS		/* just a place-holder */
960SN/A} Colors;
970SN/A
980SN/Astatic const char *defcolors = "exfxcxdxbxegedabagacad";
990SN/A
1000SN/A/* colors for file types */
1010SN/Astatic struct {
1020SN/A	int	num[2];
1030SN/A	int	bold;
1040SN/A} colors[C_NUMCOLORS];
1050SN/A#endif
1060SN/A
1070SN/Avoid
1080SN/Aprintscol(const DISPLAY *dp)
1090SN/A{
1100SN/A	FTSENT *p;
1110SN/A
1120SN/A	for (p = dp->list; p; p = p->fts_link) {
1130SN/A		if (IS_NOPRINT(p))
1140SN/A			continue;
1150SN/A		(void)printaname(p, dp->s_inode, dp->s_block);
1160SN/A		(void)putchar('\n');
1170SN/A	}
1180SN/A}
1190SN/A
1200SN/A/*
1210SN/A * print name in current style
1220SN/A */
1230SN/Aint
1240SN/Aprintname(const char *name)
1250SN/A{
1260SN/A	if (f_octal || f_octal_escape)
1270SN/A		return prn_octal(name);
1280SN/A	else if (f_nonprint)
1290SN/A		return prn_printable(name);
1300SN/A	else
1310SN/A		return prn_normal(name);
1320SN/A}
13310856Sfparain
1340SN/Avoid
1350SN/Aprintlong(const DISPLAY *dp)
1360SN/A{
1370SN/A	struct stat *sp;
1380SN/A	FTSENT *p;
1390SN/A	NAMES *np;
1400SN/A	char buf[20];
1410SN/A#ifdef COLORLS
1420SN/A	int color_printed = 0;
1430SN/A#endif
1440SN/A
1450SN/A	if ((dp->list == NULL || dp->list->fts_level != FTS_ROOTLEVEL) &&
14610856Sfparain	    (f_longform || f_size)) {
1470SN/A		(void)printf("total %lu\n", howmany(dp->btotal, blocksize));
1480SN/A	}
1490SN/A
1500SN/A	for (p = dp->list; p; p = p->fts_link) {
1510SN/A		if (IS_NOPRINT(p))
1520SN/A			continue;
1530SN/A		sp = p->fts_statp;
1540SN/A		if (f_inode)
1550SN/A			(void)printf("%*ju ",
1560SN/A			    dp->s_inode, (uintmax_t)sp->st_ino);
1570SN/A		if (f_size)
1580SN/A			(void)printf("%*jd ",
1590SN/A			    dp->s_block, howmany(sp->st_blocks, blocksize));
1600SN/A		strmode(sp->st_mode, buf);
1610SN/A		aclmode(buf, p);
1620SN/A		np = p->fts_pointer;
1630SN/A		(void)printf("%s %*u %-*s  %-*s  ", buf, dp->s_nlink,
1640SN/A		    sp->st_nlink, dp->s_user, np->user, dp->s_group,
1650SN/A		    np->group);
1660SN/A		if (f_flags)
1670SN/A			(void)printf("%-*s ", dp->s_flags, np->flags);
1680SN/A		if (f_label)
1690SN/A			(void)printf("%-*s ", dp->s_label, np->label);
1700SN/A		if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode))
1710SN/A			printdev(dp->s_size, sp->st_rdev);
1720SN/A		else
1730SN/A			printsize(dp->s_size, sp->st_size);
1740SN/A		if (f_accesstime)
1750SN/A			printtime(sp->st_atime);
1760SN/A		else if (f_birthtime)
1770SN/A			printtime(sp->st_birthtime);
1780SN/A		else if (f_statustime)
1790SN/A			printtime(sp->st_ctime);
1800SN/A		else
1810SN/A			printtime(sp->st_mtime);
1820SN/A#ifdef COLORLS
1830SN/A		if (f_color)
1840SN/A			color_printed = colortype(sp->st_mode);
1850SN/A#endif
1860SN/A		(void)printname(p->fts_name);
1870SN/A#ifdef COLORLS
1880SN/A		if (f_color && color_printed)
1890SN/A			endcolor(0);
1900SN/A#endif
1910SN/A		if (f_type)
1920SN/A			(void)printtype(sp->st_mode);
1930SN/A		if (S_ISLNK(sp->st_mode))
1940SN/A			printlink(p);
1950SN/A		(void)putchar('\n');
1960SN/A	}
1970SN/A}
1980SN/A
1990SN/Avoid
20010856Sfparainprintstream(const DISPLAY *dp)
20110856Sfparain{
2020SN/A	FTSENT *p;
2030SN/A	int chcnt;
2040SN/A
2050SN/A	for (p = dp->list, chcnt = 0; p; p = p->fts_link) {
2060SN/A		if (p->fts_number == NO_PRINT)
2070SN/A			continue;
2080SN/A		/* XXX strlen does not take octal escapes into account. */
2090SN/A		if (strlen(p->fts_name) + chcnt +
2100SN/A		    (p->fts_link ? 2 : 0) >= (unsigned)termwidth) {
2110SN/A			putchar('\n');
2120SN/A			chcnt = 0;
2130SN/A		}
2140SN/A		chcnt += printaname(p, dp->s_inode, dp->s_block);
2150SN/A		if (p->fts_link) {
2160SN/A			printf(", ");
217910SN/A			chcnt += 2;
2180SN/A		}
2190SN/A	}
2200SN/A	if (chcnt)
2210SN/A		putchar('\n');
2220SN/A}
2230SN/A
2240SN/Avoid
2250SN/Aprintcol(const DISPLAY *dp)
2260SN/A{
2270SN/A	static FTSENT **array;
2280SN/A	static int lastentries = -1;
2290SN/A	FTSENT *p;
2300SN/A	FTSENT **narray;
2310SN/A	int base;
2320SN/A	int chcnt;
2330SN/A	int cnt;
2340SN/A	int col;
2350SN/A	int colwidth;
2360SN/A	int endcol;
2370SN/A	int num;
2380SN/A	int numcols;
2390SN/A	int numrows;
2400SN/A	int row;
2410SN/A	int tabwidth;
2420SN/A
2430SN/A	if (f_notabs)
2440SN/A		tabwidth = 1;
2450SN/A	else
2460SN/A		tabwidth = 8;
2470SN/A
2480SN/A	/*
2490SN/A	 * Have to do random access in the linked list -- build a table
2500SN/A	 * of pointers.
2510SN/A	 */
2520SN/A	if (dp->entries > lastentries) {
2530SN/A		if ((narray =
2540SN/A		    realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) {
2550SN/A			warn(NULL);
2560SN/A			printscol(dp);
2572227SN/A			return;
2580SN/A		}
2592227SN/A		lastentries = dp->entries;
2602227SN/A		array = narray;
2612227SN/A	}
2622227SN/A	for (p = dp->list, num = 0; p; p = p->fts_link)
2630SN/A		if (p->fts_number != NO_PRINT)
2642227SN/A			array[num++] = p;
2652227SN/A
2662227SN/A	colwidth = dp->maxlen;
2671332SN/A	if (f_inode)
2681332SN/A		colwidth += dp->s_inode + 1;
2690SN/A	if (f_size)
2700SN/A		colwidth += dp->s_block + 1;
2710SN/A	if (f_type)
2720SN/A		colwidth += 1;
2730SN/A
2740SN/A	colwidth = (colwidth + tabwidth) & ~(tabwidth - 1);
2750SN/A	if (termwidth < 2 * colwidth) {
2760SN/A		printscol(dp);
2770SN/A		return;
2781332SN/A	}
2791332SN/A	numcols = termwidth / colwidth;
2801332SN/A	numrows = num / numcols;
2811332SN/A	if (num % numcols)
2821332SN/A		++numrows;
2831332SN/A
2841332SN/A	if ((dp->list == NULL || dp->list->fts_level != FTS_ROOTLEVEL) &&
2851332SN/A	    (f_longform || f_size)) {
2861332SN/A		(void)printf("total %lu\n", howmany(dp->btotal, blocksize));
2871332SN/A	}
2881332SN/A
2891332SN/A	base = 0;
2901332SN/A	for (row = 0; row < numrows; ++row) {
29111593Smartin		endcol = colwidth;
2921332SN/A		if (!f_sortacross)
29311593Smartin			base = row;
2941332SN/A		for (col = 0, chcnt = 0; col < numcols; ++col) {
2951332SN/A			chcnt += printaname(array[base], dp->s_inode,
2960SN/A			    dp->s_block);
2970SN/A			if (f_sortacross)
2980SN/A				base++;
299701SN/A			else
300701SN/A				base += numrows;
3010SN/A			if (base >= num)
3020SN/A				break;
3030SN/A			while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1)))
3040SN/A			    <= endcol) {
3050SN/A				if (f_sortacross && col + 1 >= numcols)
3060SN/A					break;
3070SN/A				(void)putchar(f_notabs ? ' ' : '\t');
3080SN/A				chcnt = cnt;
3090SN/A			}
3100SN/A			endcol += colwidth;
3111332SN/A		}
3120SN/A		(void)putchar('\n');
3130SN/A	}
3140SN/A}
3150SN/A
3160SN/A/*
3170SN/A * print [inode] [size] name
3180SN/A * return # of characters printed, no trailing characters.
3190SN/A */
3203115SN/Astatic int
3210SN/Aprintaname(const FTSENT *p, u_long inodefield, u_long sizefield)
3220SN/A{
3230SN/A	struct stat *sp;
3240SN/A	int chcnt;
3250SN/A#ifdef COLORLS
3260SN/A	int color_printed = 0;
3270SN/A#endif
3280SN/A
3290SN/A	sp = p->fts_statp;
3300SN/A	chcnt = 0;
3310SN/A	if (f_inode)
3320SN/A		chcnt += printf("%*ju ",
3330SN/A		    (int)inodefield, (uintmax_t)sp->st_ino);
3341332SN/A	if (f_size)
3351332SN/A		chcnt += printf("%*jd ",
3361332SN/A		    (int)sizefield, howmany(sp->st_blocks, blocksize));
3371332SN/A#ifdef COLORLS
3381332SN/A	if (f_color)
3391332SN/A		color_printed = colortype(sp->st_mode);
3401332SN/A#endif
3411332SN/A	chcnt += printname(p->fts_name);
3421332SN/A#ifdef COLORLS
3431332SN/A	if (f_color && color_printed)
3441332SN/A		endcolor(0);
3451332SN/A#endif
3461332SN/A	if (f_type)
3471332SN/A		chcnt += printtype(sp->st_mode);
3481332SN/A	return (chcnt);
3491332SN/A}
3501332SN/A
3511332SN/A/*
3521332SN/A * Print device special file major and minor numbers.
3531332SN/A */
3541332SN/Astatic void
3550SN/Aprintdev(size_t width, dev_t dev)
3560SN/A{
3570SN/A
3581332SN/A	(void)printf("%#*jx ", (u_int)width, (uintmax_t)dev);
359701SN/A}
3600SN/A
3610SN/Astatic void
3620SN/Aprinttime(time_t ftime)
3631032SN/A{
3641032SN/A	char longstring[80];
3651032SN/A	static time_t now = 0;
3661032SN/A	const char *format;
3671032SN/A	static int d_first = -1;
3681032SN/A
3691032SN/A	if (d_first < 0)
3701032SN/A		d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
3711032SN/A	if (now == 0)
3721032SN/A		now = time(NULL);
3731032SN/A
3741032SN/A#define	SIXMONTHS	((365 / 2) * 86400)
3751032SN/A	if (f_timeformat)  /* user specified format */
3761032SN/A		format = f_timeformat;
3771032SN/A	else if (f_sectime)
3781032SN/A		/* mmm dd hh:mm:ss yyyy || dd mmm hh:mm:ss yyyy */
3791032SN/A		format = d_first ? "%e %b %T %Y" : "%b %e %T %Y";
3801032SN/A	else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS)
3811032SN/A		/* mmm dd hh:mm || dd mmm hh:mm */
3821032SN/A		format = d_first ? "%e %b %R" : "%b %e %R";
3831032SN/A	else
3841032SN/A		/* mmm dd  yyyy || dd mmm  yyyy */
3851032SN/A		format = d_first ? "%e %b  %Y" : "%b %e  %Y";
3861032SN/A	strftime(longstring, sizeof(longstring), format, localtime(&ftime));
3871032SN/A	fputs(longstring, stdout);
3881032SN/A	fputc(' ', stdout);
3891032SN/A}
3901032SN/A
3911032SN/Astatic int
3921032SN/Aprinttype(u_int mode)
3931032SN/A{
3941032SN/A
3950SN/A	if (f_slash) {
3960SN/A		if ((mode & S_IFMT) == S_IFDIR) {
3970SN/A			(void)putchar('/');
3980SN/A			return (1);
3990SN/A		}
4000SN/A		return (0);
4010SN/A	}
4020SN/A
4030SN/A	switch (mode & S_IFMT) {
4040SN/A	case S_IFDIR:
4050SN/A		(void)putchar('/');
4060SN/A		return (1);
4070SN/A	case S_IFIFO:
4080SN/A		(void)putchar('|');
4090SN/A		return (1);
4100SN/A	case S_IFLNK:
4110SN/A		(void)putchar('@');
4120SN/A		return (1);
4130SN/A	case S_IFSOCK:
4140SN/A		(void)putchar('=');
4150SN/A		return (1);
4160SN/A	case S_IFWHT:
4170SN/A		(void)putchar('%');
4180SN/A		return (1);
4190SN/A	default:
4200SN/A		break;
4210SN/A	}
4220SN/A	if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
4230SN/A		(void)putchar('*');
4240SN/A		return (1);
4250SN/A	}
4260SN/A	return (0);
4270SN/A}
4280SN/A
4290SN/A#ifdef COLORLS
4300SN/Astatic int
4310SN/Aputch(int c)
4323115SN/A{
4330SN/A	(void)putchar(c);
4340SN/A	return 0;
4350SN/A}
4360SN/A
4370SN/Astatic int
4380SN/Awritech(int c)
4390SN/A{
4400SN/A	char tmp = (char)c;
4410SN/A
4420SN/A	(void)write(STDOUT_FILENO, &tmp, 1);
4430SN/A	return 0;
4440SN/A}
4450SN/A
4460SN/Astatic void
4470SN/Aprintcolor(Colors c)
4480SN/A{
4490SN/A	char *ansiseq;
4500SN/A
4510SN/A	if (colors[c].bold)
4520SN/A		tputs(enter_bold, 1, putch);
4530SN/A
4540SN/A	if (colors[c].num[0] != -1) {
4550SN/A		ansiseq = tgoto(ansi_fgcol, 0, colors[c].num[0]);
4560SN/A		if (ansiseq)
4570SN/A			tputs(ansiseq, 1, putch);
4580SN/A	}
4590SN/A	if (colors[c].num[1] != -1) {
4600SN/A		ansiseq = tgoto(ansi_bgcol, 0, colors[c].num[1]);
4610SN/A		if (ansiseq)
4620SN/A			tputs(ansiseq, 1, putch);
4630SN/A	}
4640SN/A}
4650SN/A
4660SN/Astatic void
4670SN/Aendcolor(int sig)
4680SN/A{
4690SN/A	tputs(ansi_coloff, 1, sig ? writech : putch);
4700SN/A	tputs(attrs_off, 1, sig ? writech : putch);
4710SN/A}
4720SN/A
4730SN/Astatic int
4740SN/Acolortype(mode_t mode)
4750SN/A{
4760SN/A	switch (mode & S_IFMT) {
4770SN/A	case S_IFDIR:
4780SN/A		if (mode & S_IWOTH)
4790SN/A			if (mode & S_ISTXT)
4800SN/A				printcolor(C_WSDIR);
4810SN/A			else
4820SN/A				printcolor(C_WDIR);
4830SN/A		else
4840SN/A			printcolor(C_DIR);
4850SN/A		return (1);
4860SN/A	case S_IFLNK:
4870SN/A		printcolor(C_LNK);
4880SN/A		return (1);
4890SN/A	case S_IFSOCK:
4900SN/A		printcolor(C_SOCK);
4910SN/A		return (1);
4920SN/A	case S_IFIFO:
4930SN/A		printcolor(C_FIFO);
4940SN/A		return (1);
4950SN/A	case S_IFBLK:
4960SN/A		printcolor(C_BLK);
4970SN/A		return (1);
4980SN/A	case S_IFCHR:
4990SN/A		printcolor(C_CHR);
5000SN/A		return (1);
5010SN/A	default:;
5020SN/A	}
5030SN/A	if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
5040SN/A		if (mode & S_ISUID)
5050SN/A			printcolor(C_SUID);
5060SN/A		else if (mode & S_ISGID)
5070SN/A			printcolor(C_SGID);
5080SN/A		else
5090SN/A			printcolor(C_EXEC);
5100SN/A		return (1);
5110SN/A	}
5120SN/A	return (0);
5130SN/A}
5140SN/A
5150SN/Avoid
5160SN/Aparsecolors(const char *cs)
5170SN/A{
5180SN/A	int i;
5190SN/A	int j;
5200SN/A	size_t len;
5210SN/A	char c[2];
5220SN/A	short legacy_warn = 0;
5230SN/A
5240SN/A	if (cs == NULL)
5250SN/A		cs = "";	/* LSCOLORS not set */
5260SN/A	len = strlen(cs);
5275048SN/A	for (i = 0; i < (int)C_NUMCOLORS; i++) {
5280SN/A		colors[i].bold = 0;
5290SN/A
5300SN/A		if (len <= 2 * (size_t)i) {
5310SN/A			c[0] = defcolors[2 * i];
5320SN/A			c[1] = defcolors[2 * i + 1];
5330SN/A		} else {
5340SN/A			c[0] = cs[2 * i];
5350SN/A			c[1] = cs[2 * i + 1];
5360SN/A		}
5378565SN/A		for (j = 0; j < 2; j++) {
538701SN/A			/* Legacy colours used 0-7 */
5390SN/A			if (c[j] >= '0' && c[j] <= '7') {
5400SN/A				colors[i].num[j] = c[j] - '0';
5410SN/A				if (!legacy_warn) {
5420SN/A					warnx("LSCOLORS should use "
5430SN/A					    "characters a-h instead of 0-9 ("
5440SN/A					    "see the manual page)");
5451032SN/A				}
5460SN/A				legacy_warn = 1;
5470SN/A			} else if (c[j] >= 'a' && c[j] <= 'h')
5480SN/A				colors[i].num[j] = c[j] - 'a';
5490SN/A			else if (c[j] >= 'A' && c[j] <= 'H') {
5500SN/A				colors[i].num[j] = c[j] - 'A';
5510SN/A				colors[i].bold = 1;
5520SN/A			} else if (tolower((unsigned char)c[j]) == 'x')
553910SN/A				colors[i].num[j] = -1;
5540SN/A			else {
5550SN/A				warnx("invalid character '%c' in LSCOLORS"
5561032SN/A				    " env var", c[j]);
5570SN/A				colors[i].num[j] = -1;
5580SN/A			}
5590SN/A		}
5600SN/A	}
5610SN/A}
5620SN/A
5630SN/Avoid
564701SN/Acolorquit(int sig)
5650SN/A{
566701SN/A	endcolor(sig);
5670SN/A
5680SN/A	(void)signal(sig, SIG_DFL);
5690SN/A	(void)kill(getpid(), sig);
5700SN/A}
5711032SN/A
5721032SN/A#endif /* COLORLS */
5731032SN/A
5741032SN/Astatic void
5751032SN/Aprintlink(const FTSENT *p)
5761032SN/A{
5771032SN/A	int lnklen;
5781032SN/A	char name[MAXPATHLEN + 1];
5791032SN/A	char path[MAXPATHLEN + 1];
5801032SN/A
5811032SN/A	if (p->fts_level == FTS_ROOTLEVEL)
5821032SN/A		(void)snprintf(name, sizeof(name), "%s", p->fts_name);
5831032SN/A	else
5841032SN/A		(void)snprintf(name, sizeof(name),
58514684Ssherman		    "%s/%s", p->fts_parent->fts_accpath, p->fts_name);
5860SN/A	if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) {
58714684Ssherman		(void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno));
5880SN/A		return;
5890SN/A	}
5900SN/A	path[lnklen] = '\0';
5910SN/A	(void)printf(" -> ");
5921032SN/A	(void)printname(path);
59314684Ssherman}
5940SN/A
59514684Sshermanstatic void
5960SN/Aprintsize(size_t width, off_t bytes)
5972227SN/A{
5982227SN/A
5992227SN/A	if (f_humanval) {
6002227SN/A		/*
6012227SN/A		 * Reserve one space before the size and allocate room for
6022227SN/A		 * the trailing '\0'.
6032227SN/A		 */
6042227SN/A		char buf[HUMANVALSTR_LEN - 1 + 1];
6052227SN/A
6062227SN/A		humanize_number(buf, sizeof(buf), (int64_t)bytes, "",
6072227SN/A		    HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
6082227SN/A		(void)printf("%*s ", (u_int)width, buf);
6092227SN/A	} else if (f_thousands) {		/* with commas */
6102227SN/A		/* This format assignment needed to work round gcc bug. */
6112227SN/A		const char *format = "%*j'd ";
6122227SN/A		(void)printf(format, (u_int)width, bytes);
6132227SN/A	} else
6142227SN/A		(void)printf("%*jd ", (u_int)width, bytes);
6152227SN/A}
6162227SN/A
6172227SN/A/*
6182227SN/A * Add a + after the standard rwxrwxrwx mode if the file has an
6192227SN/A * ACL. strmode() reserves space at the end of the string.
6202227SN/A */
6212227SN/Astatic void
6222227SN/Aaclmode(char *buf, const FTSENT *p)
6232227SN/A{
6242227SN/A	char name[MAXPATHLEN + 1];
6252227SN/A	int ret, trivial;
6262227SN/A	static dev_t previous_dev = NODEV;
6272227SN/A	static int supports_acls = -1;
6282227SN/A	static int type = ACL_TYPE_ACCESS;
6292227SN/A	acl_t facl;
6302227SN/A
6312227SN/A	/*
6322227SN/A	 * XXX: ACLs are not supported on whiteouts and device files
6332227SN/A	 * residing on UFS.
6342227SN/A	 */
6352227SN/A	if (S_ISCHR(p->fts_statp->st_mode) || S_ISBLK(p->fts_statp->st_mode) ||
6362227SN/A	    S_ISWHT(p->fts_statp->st_mode))
6372227SN/A		return;
6382227SN/A
6392227SN/A	if (previous_dev == p->fts_statp->st_dev && supports_acls == 0)
6402227SN/A		return;
6412227SN/A
6420SN/A	if (p->fts_level == FTS_ROOTLEVEL)
6430SN/A		snprintf(name, sizeof(name), "%s", p->fts_name);
6440SN/A	else
6450SN/A		snprintf(name, sizeof(name), "%s/%s",
6460SN/A		    p->fts_parent->fts_accpath, p->fts_name);
6470SN/A
6480SN/A	if (previous_dev != p->fts_statp->st_dev) {
6490SN/A		previous_dev = p->fts_statp->st_dev;
6500SN/A		supports_acls = 0;
6511032SN/A
6521032SN/A		ret = lpathconf(name, _PC_ACL_NFS4);
6531032SN/A		if (ret > 0) {
6541032SN/A			type = ACL_TYPE_NFS4;
6551032SN/A			supports_acls = 1;
6561032SN/A		} else if (ret < 0 && errno != EINVAL) {
6571032SN/A			warn("%s", name);
6580SN/A			return;
6590SN/A		}
6600SN/A		if (supports_acls == 0) {
6619198SN/A			ret = lpathconf(name, _PC_ACL_EXTENDED);
6629198SN/A			if (ret > 0) {
6639198SN/A				type = ACL_TYPE_ACCESS;
6649198SN/A				supports_acls = 1;
6650SN/A			} else if (ret < 0 && errno != EINVAL) {
6660SN/A				warn("%s", name);
6670SN/A				return;
6680SN/A			}
6690SN/A		}
6700SN/A	}
6710SN/A	if (supports_acls == 0)
6720SN/A		return;
6730SN/A	facl = acl_get_link_np(name, type);
6740SN/A	if (facl == NULL) {
6750SN/A		warn("%s", name);
6760SN/A		return;
6770SN/A	}
6780SN/A	if (acl_is_trivial_np(facl, &trivial)) {
6790SN/A		acl_free(facl);
6800SN/A		warn("%s", name);
6810SN/A		return;
6820SN/A	}
6830SN/A	if (!trivial)
6840SN/A		buf[10] = '+';
68514684Ssherman	acl_free(facl);
6860SN/A}
68714684Ssherman