print.c revision 196712
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 196712 2009-08-31 20:53:01Z trasz $"); 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> 511556Srgrimes#include <stdlib.h> 521556Srgrimes#include <string.h> 5391212Sbde#include <time.h> 541556Srgrimes#include <unistd.h> 5561294Sache#ifdef COLORLS 5661294Sache#include <ctype.h> 5761294Sache#include <termcap.h> 5861294Sache#include <signal.h> 5961294Sache#endif 601556Srgrimes 611556Srgrimes#include "ls.h" 621556Srgrimes#include "extern.h" 631556Srgrimes 64114583Smarkmstatic int printaname(const FTSENT *, u_long, u_long); 65105780Smarkmstatic void printlink(const FTSENT *); 6690110Simpstatic void printtime(time_t); 6790110Simpstatic int printtype(u_int); 6890110Simpstatic void printsize(size_t, off_t); 6961321Sache#ifdef COLORLS 7090110Simpstatic void endcolor(int); 7190110Simpstatic int colortype(mode_t); 7261321Sache#endif 73196712Straszstatic void aclmode(char *, const FTSENT *); 741556Srgrimes 751556Srgrimes#define IS_NOPRINT(p) ((p)->fts_number == NO_PRINT) 761556Srgrimes 7761268Sjoe#ifdef COLORLS 7861178Sjoe/* Most of these are taken from <sys/stat.h> */ 7961178Sjoetypedef enum Colors { 8088602Sjoe C_DIR, /* directory */ 8188602Sjoe C_LNK, /* symbolic link */ 8288602Sjoe C_SOCK, /* socket */ 8388602Sjoe C_FIFO, /* pipe */ 8488602Sjoe C_EXEC, /* executable */ 8588602Sjoe C_BLK, /* block special */ 8688602Sjoe C_CHR, /* character special */ 8788602Sjoe C_SUID, /* setuid executable */ 8888602Sjoe C_SGID, /* setgid executable */ 8988602Sjoe C_WSDIR, /* directory writeble to others, with sticky 9088602Sjoe * bit */ 9188602Sjoe C_WDIR, /* directory writeble to others, without 9288602Sjoe * sticky bit */ 9388602Sjoe C_NUMCOLORS /* just a place-holder */ 9488586Sjoe} Colors; 9561178Sjoe 9690150Smarkmstatic const char *defcolors = "exfxcxdxbxegedabagacad"; 9761178Sjoe 9888583Sjoe/* colors for file types */ 9988583Sjoestatic struct { 10088586Sjoe int num[2]; 10188586Sjoe int bold; 10288583Sjoe} colors[C_NUMCOLORS]; 10361268Sjoe#endif 10461178Sjoe 1051556Srgrimesvoid 106114583Smarkmprintscol(const DISPLAY *dp) 1071556Srgrimes{ 10888594Sjoe FTSENT *p; 1091556Srgrimes 1101556Srgrimes for (p = dp->list; p; p = p->fts_link) { 1111556Srgrimes if (IS_NOPRINT(p)) 1121556Srgrimes continue; 1131556Srgrimes (void)printaname(p, dp->s_inode, dp->s_block); 1141556Srgrimes (void)putchar('\n'); 1151556Srgrimes } 1161556Srgrimes} 1171556Srgrimes 11862597Sassar/* 11962597Sassar * print name in current style 12062597Sassar */ 121105390Stjrint 12290110Simpprintname(const char *name) 12362597Sassar{ 12462597Sassar if (f_octal || f_octal_escape) 12562597Sassar return prn_octal(name); 12662597Sassar else if (f_nonprint) 12762597Sassar return prn_printable(name); 12862597Sassar else 129128823Stjr return prn_normal(name); 13062597Sassar} 13162597Sassar 1321556Srgrimesvoid 133114583Smarkmprintlong(const DISPLAY *dp) 1341556Srgrimes{ 1351556Srgrimes struct stat *sp; 13688594Sjoe FTSENT *p; 13788594Sjoe NAMES *np; 13888594Sjoe char buf[20]; 13961292Sache#ifdef COLORLS 14088594Sjoe int color_printed = 0; 14161292Sache#endif 1421556Srgrimes 143130236Sdas if ((dp->list == NULL || dp->list->fts_level != FTS_ROOTLEVEL) && 144130236Sdas (f_longform || f_size)) { 1451556Srgrimes (void)printf("total %lu\n", howmany(dp->btotal, blocksize)); 146130236Sdas } 1471556Srgrimes 1481556Srgrimes for (p = dp->list; p; p = p->fts_link) { 1491556Srgrimes if (IS_NOPRINT(p)) 1501556Srgrimes continue; 1511556Srgrimes sp = p->fts_statp; 1521556Srgrimes if (f_inode) 15320417Ssteve (void)printf("%*lu ", dp->s_inode, (u_long)sp->st_ino); 1541556Srgrimes if (f_size) 155114583Smarkm (void)printf("%*jd ", 1561556Srgrimes dp->s_block, howmany(sp->st_blocks, blocksize)); 15790150Smarkm strmode(sp->st_mode, buf); 158196712Strasz aclmode(buf, p); 1591556Srgrimes np = p->fts_pointer; 160177942Simp (void)printf("%s %*u %-*s %-*s ", buf, dp->s_nlink, 1611556Srgrimes sp->st_nlink, dp->s_user, np->user, dp->s_group, 1621556Srgrimes np->group); 1631556Srgrimes if (f_flags) 1641556Srgrimes (void)printf("%-*s ", dp->s_flags, np->flags); 165105832Srwatson if (f_label) 166105832Srwatson (void)printf("%-*s ", dp->s_label, np->label); 1671556Srgrimes if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode)) 16855514Sbde if (minor(sp->st_rdev) > 255 || minor(sp->st_rdev) < 0) 16913120Sjoerg (void)printf("%3d, 0x%08x ", 17055514Sbde major(sp->st_rdev), 17155514Sbde (u_int)minor(sp->st_rdev)); 17213120Sjoerg else 17313120Sjoerg (void)printf("%3d, %3d ", 17413120Sjoerg major(sp->st_rdev), minor(sp->st_rdev)); 1751556Srgrimes else if (dp->bcfile) 176114583Smarkm (void)printf("%*s%*jd ", 1771556Srgrimes 8 - dp->s_size, "", dp->s_size, sp->st_size); 1781556Srgrimes else 17988591Sjoe printsize(dp->s_size, sp->st_size); 1801556Srgrimes if (f_accesstime) 1811556Srgrimes printtime(sp->st_atime); 182157098Sjhb else if (f_birthtime) 183157098Sjhb printtime(sp->st_birthtime); 1841556Srgrimes else if (f_statustime) 1851556Srgrimes printtime(sp->st_ctime); 1861556Srgrimes else 1871556Srgrimes printtime(sp->st_mtime); 18861268Sjoe#ifdef COLORLS 18961178Sjoe if (f_color) 19061291Sache color_printed = colortype(sp->st_mode); 19161268Sjoe#endif 19262597Sassar (void)printname(p->fts_name); 19361268Sjoe#ifdef COLORLS 19461291Sache if (f_color && color_printed) 19561321Sache endcolor(0); 19661268Sjoe#endif 1971556Srgrimes if (f_type) 1981556Srgrimes (void)printtype(sp->st_mode); 1991556Srgrimes if (S_ISLNK(sp->st_mode)) 2001556Srgrimes printlink(p); 2011556Srgrimes (void)putchar('\n'); 2021556Srgrimes } 2031556Srgrimes} 2041556Srgrimes 2051556Srgrimesvoid 206114583Smarkmprintstream(const DISPLAY *dp) 20796892Stjr{ 20896892Stjr FTSENT *p; 20996892Stjr int chcnt; 21096892Stjr 21196892Stjr for (p = dp->list, chcnt = 0; p; p = p->fts_link) { 21296892Stjr if (p->fts_number == NO_PRINT) 21396892Stjr continue; 214128823Stjr /* XXX strlen does not take octal escapes into account. */ 21596892Stjr if (strlen(p->fts_name) + chcnt + 21696892Stjr (p->fts_link ? 2 : 0) >= (unsigned)termwidth) { 21796892Stjr putchar('\n'); 21896892Stjr chcnt = 0; 21996892Stjr } 22096892Stjr chcnt += printaname(p, dp->s_inode, dp->s_block); 22196892Stjr if (p->fts_link) { 22296892Stjr printf(", "); 22396892Stjr chcnt += 2; 22496892Stjr } 22596892Stjr } 22696892Stjr if (chcnt) 22796892Stjr putchar('\n'); 22896892Stjr} 229177907Sgrog 23096892Stjrvoid 231114583Smarkmprintcol(const DISPLAY *dp) 2321556Srgrimes{ 2331556Srgrimes static FTSENT **array; 2341556Srgrimes static int lastentries = -1; 23588594Sjoe FTSENT *p; 236121124Stjr FTSENT **narray; 23788594Sjoe int base; 23888594Sjoe int chcnt; 23988594Sjoe int cnt; 24088594Sjoe int col; 24188594Sjoe int colwidth; 24288594Sjoe int endcol; 24388594Sjoe int num; 24488594Sjoe int numcols; 24588594Sjoe int numrows; 24688594Sjoe int row; 24788594Sjoe int tabwidth; 2481556Srgrimes 24937932Shoek if (f_notabs) 25037932Shoek tabwidth = 1; 25137932Shoek else 25237932Shoek tabwidth = 8; 25337932Shoek 2541556Srgrimes /* 2551556Srgrimes * Have to do random access in the linked list -- build a table 2561556Srgrimes * of pointers. 2571556Srgrimes */ 2581556Srgrimes if (dp->entries > lastentries) { 259121124Stjr if ((narray = 2601556Srgrimes realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) { 2611556Srgrimes warn(NULL); 2621556Srgrimes printscol(dp); 263121124Stjr return; 2641556Srgrimes } 265121124Stjr lastentries = dp->entries; 266121124Stjr array = narray; 2671556Srgrimes } 2681556Srgrimes for (p = dp->list, num = 0; p; p = p->fts_link) 2691556Srgrimes if (p->fts_number != NO_PRINT) 2701556Srgrimes array[num++] = p; 2711556Srgrimes 2721556Srgrimes colwidth = dp->maxlen; 2731556Srgrimes if (f_inode) 2741556Srgrimes colwidth += dp->s_inode + 1; 2751556Srgrimes if (f_size) 2761556Srgrimes colwidth += dp->s_block + 1; 2771556Srgrimes if (f_type) 2781556Srgrimes colwidth += 1; 2791556Srgrimes 28037932Shoek colwidth = (colwidth + tabwidth) & ~(tabwidth - 1); 2811556Srgrimes if (termwidth < 2 * colwidth) { 2821556Srgrimes printscol(dp); 2831556Srgrimes return; 2841556Srgrimes } 2851556Srgrimes numcols = termwidth / colwidth; 2861556Srgrimes numrows = num / numcols; 2871556Srgrimes if (num % numcols) 2881556Srgrimes ++numrows; 2891556Srgrimes 290130236Sdas if ((dp->list == NULL || dp->list->fts_level != FTS_ROOTLEVEL) && 291130236Sdas (f_longform || f_size)) { 2921556Srgrimes (void)printf("total %lu\n", howmany(dp->btotal, blocksize)); 293130236Sdas } 29496892Stjr 295102577Skeramida base = 0; 2961556Srgrimes for (row = 0; row < numrows; ++row) { 2971556Srgrimes endcol = colwidth; 29896892Stjr if (!f_sortacross) 29996892Stjr base = row; 30096892Stjr for (col = 0, chcnt = 0; col < numcols; ++col) { 3011556Srgrimes chcnt += printaname(array[base], dp->s_inode, 3021556Srgrimes dp->s_block); 30396892Stjr if (f_sortacross) 30496892Stjr base++; 30596892Stjr else 30696892Stjr base += numrows; 30796892Stjr if (base >= num) 3081556Srgrimes break; 30937932Shoek while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1))) 31088595Sjoe <= endcol) { 31196892Stjr if (f_sortacross && col + 1 >= numcols) 31296892Stjr break; 31337932Shoek (void)putchar(f_notabs ? ' ' : '\t'); 3141556Srgrimes chcnt = cnt; 3151556Srgrimes } 3161556Srgrimes endcol += colwidth; 3171556Srgrimes } 3181556Srgrimes (void)putchar('\n'); 3191556Srgrimes } 3201556Srgrimes} 3211556Srgrimes 3221556Srgrimes/* 3231556Srgrimes * print [inode] [size] name 3241556Srgrimes * return # of characters printed, no trailing characters. 3251556Srgrimes */ 3261556Srgrimesstatic int 327114583Smarkmprintaname(const FTSENT *p, u_long inodefield, u_long sizefield) 3281556Srgrimes{ 3291556Srgrimes struct stat *sp; 33088594Sjoe int chcnt; 33161292Sache#ifdef COLORLS 33288594Sjoe int color_printed = 0; 33361292Sache#endif 3341556Srgrimes 3351556Srgrimes sp = p->fts_statp; 3361556Srgrimes chcnt = 0; 3371556Srgrimes if (f_inode) 33820417Ssteve chcnt += printf("%*lu ", (int)inodefield, (u_long)sp->st_ino); 3391556Srgrimes if (f_size) 340114583Smarkm chcnt += printf("%*jd ", 3411556Srgrimes (int)sizefield, howmany(sp->st_blocks, blocksize)); 34261268Sjoe#ifdef COLORLS 34361178Sjoe if (f_color) 34461291Sache color_printed = colortype(sp->st_mode); 34561268Sjoe#endif 34662597Sassar chcnt += printname(p->fts_name); 34761268Sjoe#ifdef COLORLS 34861291Sache if (f_color && color_printed) 34961321Sache endcolor(0); 35061268Sjoe#endif 3511556Srgrimes if (f_type) 3521556Srgrimes chcnt += printtype(sp->st_mode); 3531556Srgrimes return (chcnt); 3541556Srgrimes} 3551556Srgrimes 3561556Srgrimesstatic void 35790110Simpprinttime(time_t ftime) 3581556Srgrimes{ 35988594Sjoe char longstring[80]; 360114583Smarkm static time_t now = 0; 36188594Sjoe const char *format; 36288594Sjoe static int d_first = -1; 3631556Srgrimes 36474566Sache if (d_first < 0) 36574566Sache d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 36621545Smpp if (now == 0) 36721545Smpp now = time(NULL); 36821545Smpp 3699987Swollman#define SIXMONTHS ((365 / 2) * 86400) 370177907Sgrog if (f_timeformat) /* user specified format */ 371177907Sgrog format = f_timeformat; 372177907Sgrog else if (f_sectime) 37361920Sjoe /* mmm dd hh:mm:ss yyyy || dd mmm hh:mm:ss yyyy */ 374177907Sgrog format = d_first ? "%e %b %T %Y" : "%b %e %T %Y"; 37521545Smpp else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS) 37661920Sjoe /* mmm dd hh:mm || dd mmm hh:mm */ 377177907Sgrog format = d_first ? "%e %b %R" : "%b %e %R"; 37861814Sjoe else 37961920Sjoe /* mmm dd yyyy || dd mmm yyyy */ 380177942Simp format = d_first ? "%e %b %Y" : "%b %e %Y"; 38161814Sjoe strftime(longstring, sizeof(longstring), format, localtime(&ftime)); 38261814Sjoe fputs(longstring, stdout); 383177907Sgrog fputc(' ', stdout); 3841556Srgrimes} 3851556Srgrimes 3861556Srgrimesstatic int 38790110Simpprinttype(u_int mode) 3881556Srgrimes{ 38996892Stjr 39096892Stjr if (f_slash) { 39196892Stjr if ((mode & S_IFMT) == S_IFDIR) { 39296892Stjr (void)putchar('/'); 39396892Stjr return (1); 39496892Stjr } 39596892Stjr return (0); 39696892Stjr } 39796892Stjr 3981556Srgrimes switch (mode & S_IFMT) { 3991556Srgrimes case S_IFDIR: 4001556Srgrimes (void)putchar('/'); 4011556Srgrimes return (1); 4021556Srgrimes case S_IFIFO: 4031556Srgrimes (void)putchar('|'); 4041556Srgrimes return (1); 4051556Srgrimes case S_IFLNK: 4061556Srgrimes (void)putchar('@'); 4071556Srgrimes return (1); 4081556Srgrimes case S_IFSOCK: 4091556Srgrimes (void)putchar('='); 4101556Srgrimes return (1); 41120417Ssteve case S_IFWHT: 41220417Ssteve (void)putchar('%'); 41320417Ssteve return (1); 41490150Smarkm default: 41596681Sbillf break; 4161556Srgrimes } 4171556Srgrimes if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 4181556Srgrimes (void)putchar('*'); 4191556Srgrimes return (1); 4201556Srgrimes } 4211556Srgrimes return (0); 4221556Srgrimes} 4231556Srgrimes 42461268Sjoe#ifdef COLORLS 42561323Sachestatic int 42690110Simpputch(int c) 42761291Sache{ 42888602Sjoe (void)putchar(c); 42961321Sache return 0; 43061291Sache} 43161291Sache 43261323Sachestatic int 43390110Simpwritech(int c) 43461321Sache{ 435114583Smarkm char tmp = (char)c; 43661291Sache 43788602Sjoe (void)write(STDOUT_FILENO, &tmp, 1); 43861321Sache return 0; 43961321Sache} 44061321Sache 44161323Sachestatic void 44290110Simpprintcolor(Colors c) 44361178Sjoe{ 44488594Sjoe char *ansiseq; 44561268Sjoe 44688583Sjoe if (colors[c].bold) 44788583Sjoe tputs(enter_bold, 1, putch); 44888583Sjoe 44988583Sjoe if (colors[c].num[0] != -1) { 45088583Sjoe ansiseq = tgoto(ansi_fgcol, 0, colors[c].num[0]); 45161321Sache if (ansiseq) 45261291Sache tputs(ansiseq, 1, putch); 45361178Sjoe } 45488583Sjoe if (colors[c].num[1] != -1) { 45588583Sjoe ansiseq = tgoto(ansi_bgcol, 0, colors[c].num[1]); 45661321Sache if (ansiseq) 45761291Sache tputs(ansiseq, 1, putch); 45861268Sjoe } 45961178Sjoe} 46061178Sjoe 46161321Sachestatic void 46290110Simpendcolor(int sig) 46361268Sjoe{ 46461321Sache tputs(ansi_coloff, 1, sig ? writech : putch); 46588583Sjoe tputs(attrs_off, 1, sig ? writech : putch); 46661268Sjoe} 46761268Sjoe 46861321Sachestatic int 46990110Simpcolortype(mode_t mode) 47061178Sjoe{ 47188602Sjoe switch (mode & S_IFMT) { 47288595Sjoe case S_IFDIR: 47361178Sjoe if (mode & S_IWOTH) 47488595Sjoe if (mode & S_ISTXT) 47588595Sjoe printcolor(C_WSDIR); 47688595Sjoe else 47788595Sjoe printcolor(C_WDIR); 47861178Sjoe else 47988595Sjoe printcolor(C_DIR); 48088602Sjoe return (1); 48188595Sjoe case S_IFLNK: 48261178Sjoe printcolor(C_LNK); 48388602Sjoe return (1); 48488595Sjoe case S_IFSOCK: 48561178Sjoe printcolor(C_SOCK); 48688602Sjoe return (1); 48788595Sjoe case S_IFIFO: 48861178Sjoe printcolor(C_FIFO); 48988602Sjoe return (1); 49088595Sjoe case S_IFBLK: 49161178Sjoe printcolor(C_BLK); 49288602Sjoe return (1); 49388595Sjoe case S_IFCHR: 49461178Sjoe printcolor(C_CHR); 49588602Sjoe return (1); 496114583Smarkm default:; 49761178Sjoe } 49861178Sjoe if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 49961178Sjoe if (mode & S_ISUID) 50088595Sjoe printcolor(C_SUID); 50161178Sjoe else if (mode & S_ISGID) 50288595Sjoe printcolor(C_SGID); 50361178Sjoe else 50488595Sjoe printcolor(C_EXEC); 50588602Sjoe return (1); 50661178Sjoe } 50788602Sjoe return (0); 50861178Sjoe} 50961178Sjoe 51061178Sjoevoid 51190110Simpparsecolors(const char *cs) 51261178Sjoe{ 51388594Sjoe int i; 51488594Sjoe int j; 515105780Smarkm size_t len; 51688594Sjoe char c[2]; 51788594Sjoe short legacy_warn = 0; 51861321Sache 51988586Sjoe if (cs == NULL) 52088602Sjoe cs = ""; /* LSCOLORS not set */ 52161178Sjoe len = strlen(cs); 522114583Smarkm for (i = 0; i < (int)C_NUMCOLORS; i++) { 52388583Sjoe colors[i].bold = 0; 52488583Sjoe 525114583Smarkm if (len <= 2 * (size_t)i) { 52688586Sjoe c[0] = defcolors[2 * i]; 52788586Sjoe c[1] = defcolors[2 * i + 1]; 52888602Sjoe } else { 52988586Sjoe c[0] = cs[2 * i]; 53088586Sjoe c[1] = cs[2 * i + 1]; 53161178Sjoe } 53288602Sjoe for (j = 0; j < 2; j++) { 53388583Sjoe /* Legacy colours used 0-7 */ 53488583Sjoe if (c[j] >= '0' && c[j] <= '7') { 53588583Sjoe colors[i].num[j] = c[j] - '0'; 53688583Sjoe if (!legacy_warn) { 537106479Stjr warnx("LSCOLORS should use " 53888588Sjoe "characters a-h instead of 0-9 (" 539106479Stjr "see the manual page)"); 54088583Sjoe } 54188583Sjoe legacy_warn = 1; 54288583Sjoe } else if (c[j] >= 'a' && c[j] <= 'h') 54388583Sjoe colors[i].num[j] = c[j] - 'a'; 54488583Sjoe else if (c[j] >= 'A' && c[j] <= 'H') { 54588583Sjoe colors[i].num[j] = c[j] - 'A'; 54688583Sjoe colors[i].bold = 1; 547114583Smarkm } else if (tolower((unsigned char)c[j]) == 'x') 54888583Sjoe colors[i].num[j] = -1; 54988583Sjoe else { 550106479Stjr warnx("invalid character '%c' in LSCOLORS" 551106479Stjr " env var", c[j]); 55288584Sjoe colors[i].num[j] = -1; 55361178Sjoe } 55461178Sjoe } 55561178Sjoe } 55661178Sjoe} 55761291Sache 55861323Sachevoid 55990110Simpcolorquit(int sig) 56061291Sache{ 56161321Sache endcolor(sig); 56261294Sache 56388602Sjoe (void)signal(sig, SIG_DFL); 56488602Sjoe (void)kill(getpid(), sig); 56561291Sache} 56688602Sjoe 56788602Sjoe#endif /* COLORLS */ 56888602Sjoe 5691556Srgrimesstatic void 570105780Smarkmprintlink(const FTSENT *p) 5711556Srgrimes{ 57288594Sjoe int lnklen; 57388594Sjoe char name[MAXPATHLEN + 1]; 57488594Sjoe char path[MAXPATHLEN + 1]; 5751556Srgrimes 5761556Srgrimes if (p->fts_level == FTS_ROOTLEVEL) 5771556Srgrimes (void)snprintf(name, sizeof(name), "%s", p->fts_name); 5788855Srgrimes else 5791556Srgrimes (void)snprintf(name, sizeof(name), 5801556Srgrimes "%s/%s", p->fts_parent->fts_accpath, p->fts_name); 5811556Srgrimes if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) { 5821556Srgrimes (void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno)); 5831556Srgrimes return; 5841556Srgrimes } 5851556Srgrimes path[lnklen] = '\0'; 58662597Sassar (void)printf(" -> "); 58790150Smarkm (void)printname(path); 5881556Srgrimes} 58988591Sjoe 59088591Sjoestatic void 59190110Simpprintsize(size_t width, off_t bytes) 59288591Sjoe{ 59388602Sjoe 59488591Sjoe if (f_humanval) { 595129719Spjd char buf[5]; 59688591Sjoe 597129719Spjd humanize_number(buf, sizeof(buf), (int64_t)bytes, "", 598129719Spjd HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 599129719Spjd (void)printf("%5s ", buf); 60088602Sjoe } else 601114583Smarkm (void)printf("%*jd ", (u_int)width, bytes); 60288591Sjoe} 60388591Sjoe 604196712Strasz/* 605196712Strasz * Add a + after the standard rwxrwxrwx mode if the file has an 606196712Strasz * ACL. strmode() reserves space at the end of the string. 607196712Strasz */ 608106371Stjrstatic void 609196712Straszaclmode(char *buf, const FTSENT *p) 610106371Stjr{ 611106371Stjr char name[MAXPATHLEN + 1]; 612196712Strasz int ret, trivial; 613196712Strasz static dev_t previous_dev = NODEV; 614196712Strasz static int supports_acls = -1; 615196712Strasz static int type = ACL_TYPE_ACCESS; 616106371Stjr acl_t facl; 617106371Stjr 618106371Stjr /* 619196712Strasz * XXX: ACLs are not supported on whiteouts and device files 620196712Strasz * residing on UFS. 621106371Stjr */ 622196712Strasz if (S_ISCHR(p->fts_statp->st_mode) || S_ISBLK(p->fts_statp->st_mode) || 623196712Strasz S_ISWHT(p->fts_statp->st_mode)) 624108066Stjr return; 625196712Strasz 626196712Strasz if (previous_dev != p->fts_statp->st_dev) { 627196712Strasz previous_dev = p->fts_statp->st_dev; 628196712Strasz supports_acls = 0; 629196712Strasz 630196712Strasz if (p->fts_level == FTS_ROOTLEVEL) 631196712Strasz snprintf(name, sizeof(name), "%s", p->fts_name); 632196712Strasz else 633196712Strasz snprintf(name, sizeof(name), "%s/%s", 634196712Strasz p->fts_parent->fts_accpath, p->fts_name); 635196712Strasz ret = lpathconf(name, _PC_ACL_NFS4); 636196712Strasz if (ret > 0) { 637196712Strasz type = ACL_TYPE_NFS4; 638196712Strasz supports_acls = 1; 639196712Strasz } else if (ret < 0 && errno != EINVAL) { 640196712Strasz warn("%s", name); 641196712Strasz return; 642196712Strasz } 643196712Strasz if (supports_acls == 0) { 644196712Strasz ret = lpathconf(name, _PC_ACL_EXTENDED); 645196712Strasz if (ret > 0) { 646196712Strasz type = ACL_TYPE_ACCESS; 647196712Strasz supports_acls = 1; 648196712Strasz } else if (ret < 0 && errno != EINVAL) { 649196712Strasz warn("%s", name); 650196712Strasz return; 651196712Strasz } 652196712Strasz } 653108066Stjr } 654196712Strasz if (supports_acls == 0) 655106371Stjr return; 656196712Strasz facl = acl_get_link_np(name, type); 657196712Strasz if (facl == NULL) { 658196712Strasz warn("%s", name); 659196712Strasz return; 660106371Stjr } 661196712Strasz if (acl_is_trivial_np(facl, &trivial)) { 662106371Stjr acl_free(facl); 663106371Stjr warn("%s", name); 664196712Strasz return; 665196712Strasz } 666196712Strasz if (!trivial) 667196712Strasz buf[10] = '+'; 668196712Strasz acl_free(facl); 669106371Stjr} 670