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