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