print.c revision 177942
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 177942 2008-04-05 21:26:25Z imp $"); 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 73114583Smarkmstatic void aclmode(char *, const FTSENT *, int *); 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 142106371Stjr int haveacls; 143106371Stjr dev_t prevdev; 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 150106371Stjr haveacls = 1; 151106371Stjr prevdev = (dev_t)-1; 1521556Srgrimes for (p = dp->list; p; p = p->fts_link) { 1531556Srgrimes if (IS_NOPRINT(p)) 1541556Srgrimes continue; 1551556Srgrimes sp = p->fts_statp; 1561556Srgrimes if (f_inode) 15720417Ssteve (void)printf("%*lu ", dp->s_inode, (u_long)sp->st_ino); 1581556Srgrimes if (f_size) 159114583Smarkm (void)printf("%*jd ", 1601556Srgrimes dp->s_block, howmany(sp->st_blocks, blocksize)); 16190150Smarkm strmode(sp->st_mode, buf); 162106371Stjr /* 163106371Stjr * Cache whether or not the filesystem supports ACL's to 164106371Stjr * avoid expensive syscalls. Try again when we change devices. 165106371Stjr */ 166106371Stjr if (haveacls || sp->st_dev != prevdev) { 167106371Stjr aclmode(buf, p, &haveacls); 168106371Stjr prevdev = sp->st_dev; 169106371Stjr } 1701556Srgrimes np = p->fts_pointer; 171177942Simp (void)printf("%s %*u %-*s %-*s ", buf, dp->s_nlink, 1721556Srgrimes sp->st_nlink, dp->s_user, np->user, dp->s_group, 1731556Srgrimes np->group); 1741556Srgrimes if (f_flags) 1751556Srgrimes (void)printf("%-*s ", dp->s_flags, np->flags); 176105832Srwatson if (f_label) 177105832Srwatson (void)printf("%-*s ", dp->s_label, np->label); 1781556Srgrimes if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode)) 17955514Sbde if (minor(sp->st_rdev) > 255 || minor(sp->st_rdev) < 0) 18013120Sjoerg (void)printf("%3d, 0x%08x ", 18155514Sbde major(sp->st_rdev), 18255514Sbde (u_int)minor(sp->st_rdev)); 18313120Sjoerg else 18413120Sjoerg (void)printf("%3d, %3d ", 18513120Sjoerg major(sp->st_rdev), minor(sp->st_rdev)); 1861556Srgrimes else if (dp->bcfile) 187114583Smarkm (void)printf("%*s%*jd ", 1881556Srgrimes 8 - dp->s_size, "", dp->s_size, sp->st_size); 1891556Srgrimes else 19088591Sjoe printsize(dp->s_size, sp->st_size); 1911556Srgrimes if (f_accesstime) 1921556Srgrimes printtime(sp->st_atime); 193157098Sjhb else if (f_birthtime) 194157098Sjhb printtime(sp->st_birthtime); 1951556Srgrimes else if (f_statustime) 1961556Srgrimes printtime(sp->st_ctime); 1971556Srgrimes else 1981556Srgrimes printtime(sp->st_mtime); 19961268Sjoe#ifdef COLORLS 20061178Sjoe if (f_color) 20161291Sache color_printed = colortype(sp->st_mode); 20261268Sjoe#endif 20362597Sassar (void)printname(p->fts_name); 20461268Sjoe#ifdef COLORLS 20561291Sache if (f_color && color_printed) 20661321Sache endcolor(0); 20761268Sjoe#endif 2081556Srgrimes if (f_type) 2091556Srgrimes (void)printtype(sp->st_mode); 2101556Srgrimes if (S_ISLNK(sp->st_mode)) 2111556Srgrimes printlink(p); 2121556Srgrimes (void)putchar('\n'); 2131556Srgrimes } 2141556Srgrimes} 2151556Srgrimes 2161556Srgrimesvoid 217114583Smarkmprintstream(const DISPLAY *dp) 21896892Stjr{ 21996892Stjr FTSENT *p; 22096892Stjr int chcnt; 22196892Stjr 22296892Stjr for (p = dp->list, chcnt = 0; p; p = p->fts_link) { 22396892Stjr if (p->fts_number == NO_PRINT) 22496892Stjr continue; 225128823Stjr /* XXX strlen does not take octal escapes into account. */ 22696892Stjr if (strlen(p->fts_name) + chcnt + 22796892Stjr (p->fts_link ? 2 : 0) >= (unsigned)termwidth) { 22896892Stjr putchar('\n'); 22996892Stjr chcnt = 0; 23096892Stjr } 23196892Stjr chcnt += printaname(p, dp->s_inode, dp->s_block); 23296892Stjr if (p->fts_link) { 23396892Stjr printf(", "); 23496892Stjr chcnt += 2; 23596892Stjr } 23696892Stjr } 23796892Stjr if (chcnt) 23896892Stjr putchar('\n'); 23996892Stjr} 240177907Sgrog 24196892Stjrvoid 242114583Smarkmprintcol(const DISPLAY *dp) 2431556Srgrimes{ 2441556Srgrimes static FTSENT **array; 2451556Srgrimes static int lastentries = -1; 24688594Sjoe FTSENT *p; 247121124Stjr FTSENT **narray; 24888594Sjoe int base; 24988594Sjoe int chcnt; 25088594Sjoe int cnt; 25188594Sjoe int col; 25288594Sjoe int colwidth; 25388594Sjoe int endcol; 25488594Sjoe int num; 25588594Sjoe int numcols; 25688594Sjoe int numrows; 25788594Sjoe int row; 25888594Sjoe int tabwidth; 2591556Srgrimes 26037932Shoek if (f_notabs) 26137932Shoek tabwidth = 1; 26237932Shoek else 26337932Shoek tabwidth = 8; 26437932Shoek 2651556Srgrimes /* 2661556Srgrimes * Have to do random access in the linked list -- build a table 2671556Srgrimes * of pointers. 2681556Srgrimes */ 2691556Srgrimes if (dp->entries > lastentries) { 270121124Stjr if ((narray = 2711556Srgrimes realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) { 2721556Srgrimes warn(NULL); 2731556Srgrimes printscol(dp); 274121124Stjr return; 2751556Srgrimes } 276121124Stjr lastentries = dp->entries; 277121124Stjr array = narray; 2781556Srgrimes } 2791556Srgrimes for (p = dp->list, num = 0; p; p = p->fts_link) 2801556Srgrimes if (p->fts_number != NO_PRINT) 2811556Srgrimes array[num++] = p; 2821556Srgrimes 2831556Srgrimes colwidth = dp->maxlen; 2841556Srgrimes if (f_inode) 2851556Srgrimes colwidth += dp->s_inode + 1; 2861556Srgrimes if (f_size) 2871556Srgrimes colwidth += dp->s_block + 1; 2881556Srgrimes if (f_type) 2891556Srgrimes colwidth += 1; 2901556Srgrimes 29137932Shoek colwidth = (colwidth + tabwidth) & ~(tabwidth - 1); 2921556Srgrimes if (termwidth < 2 * colwidth) { 2931556Srgrimes printscol(dp); 2941556Srgrimes return; 2951556Srgrimes } 2961556Srgrimes numcols = termwidth / colwidth; 2971556Srgrimes numrows = num / numcols; 2981556Srgrimes if (num % numcols) 2991556Srgrimes ++numrows; 3001556Srgrimes 301130236Sdas if ((dp->list == NULL || dp->list->fts_level != FTS_ROOTLEVEL) && 302130236Sdas (f_longform || f_size)) { 3031556Srgrimes (void)printf("total %lu\n", howmany(dp->btotal, blocksize)); 304130236Sdas } 30596892Stjr 306102577Skeramida base = 0; 3071556Srgrimes for (row = 0; row < numrows; ++row) { 3081556Srgrimes endcol = colwidth; 30996892Stjr if (!f_sortacross) 31096892Stjr base = row; 31196892Stjr for (col = 0, chcnt = 0; col < numcols; ++col) { 3121556Srgrimes chcnt += printaname(array[base], dp->s_inode, 3131556Srgrimes dp->s_block); 31496892Stjr if (f_sortacross) 31596892Stjr base++; 31696892Stjr else 31796892Stjr base += numrows; 31896892Stjr if (base >= num) 3191556Srgrimes break; 32037932Shoek while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1))) 32188595Sjoe <= endcol) { 32296892Stjr if (f_sortacross && col + 1 >= numcols) 32396892Stjr break; 32437932Shoek (void)putchar(f_notabs ? ' ' : '\t'); 3251556Srgrimes chcnt = cnt; 3261556Srgrimes } 3271556Srgrimes endcol += colwidth; 3281556Srgrimes } 3291556Srgrimes (void)putchar('\n'); 3301556Srgrimes } 3311556Srgrimes} 3321556Srgrimes 3331556Srgrimes/* 3341556Srgrimes * print [inode] [size] name 3351556Srgrimes * return # of characters printed, no trailing characters. 3361556Srgrimes */ 3371556Srgrimesstatic int 338114583Smarkmprintaname(const FTSENT *p, u_long inodefield, u_long sizefield) 3391556Srgrimes{ 3401556Srgrimes struct stat *sp; 34188594Sjoe int chcnt; 34261292Sache#ifdef COLORLS 34388594Sjoe int color_printed = 0; 34461292Sache#endif 3451556Srgrimes 3461556Srgrimes sp = p->fts_statp; 3471556Srgrimes chcnt = 0; 3481556Srgrimes if (f_inode) 34920417Ssteve chcnt += printf("%*lu ", (int)inodefield, (u_long)sp->st_ino); 3501556Srgrimes if (f_size) 351114583Smarkm chcnt += printf("%*jd ", 3521556Srgrimes (int)sizefield, howmany(sp->st_blocks, blocksize)); 35361268Sjoe#ifdef COLORLS 35461178Sjoe if (f_color) 35561291Sache color_printed = colortype(sp->st_mode); 35661268Sjoe#endif 35762597Sassar chcnt += printname(p->fts_name); 35861268Sjoe#ifdef COLORLS 35961291Sache if (f_color && color_printed) 36061321Sache endcolor(0); 36161268Sjoe#endif 3621556Srgrimes if (f_type) 3631556Srgrimes chcnt += printtype(sp->st_mode); 3641556Srgrimes return (chcnt); 3651556Srgrimes} 3661556Srgrimes 3671556Srgrimesstatic void 36890110Simpprinttime(time_t ftime) 3691556Srgrimes{ 37088594Sjoe char longstring[80]; 371114583Smarkm static time_t now = 0; 37288594Sjoe const char *format; 37388594Sjoe static int d_first = -1; 3741556Srgrimes 37574566Sache if (d_first < 0) 37674566Sache d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 37721545Smpp if (now == 0) 37821545Smpp now = time(NULL); 37921545Smpp 3809987Swollman#define SIXMONTHS ((365 / 2) * 86400) 381177907Sgrog if (f_timeformat) /* user specified format */ 382177907Sgrog format = f_timeformat; 383177907Sgrog else if (f_sectime) 38461920Sjoe /* mmm dd hh:mm:ss yyyy || dd mmm hh:mm:ss yyyy */ 385177907Sgrog format = d_first ? "%e %b %T %Y" : "%b %e %T %Y"; 38621545Smpp else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS) 38761920Sjoe /* mmm dd hh:mm || dd mmm hh:mm */ 388177907Sgrog format = d_first ? "%e %b %R" : "%b %e %R"; 38961814Sjoe else 39061920Sjoe /* mmm dd yyyy || dd mmm yyyy */ 391177942Simp format = d_first ? "%e %b %Y" : "%b %e %Y"; 39261814Sjoe strftime(longstring, sizeof(longstring), format, localtime(&ftime)); 39361814Sjoe fputs(longstring, stdout); 394177907Sgrog fputc(' ', stdout); 3951556Srgrimes} 3961556Srgrimes 3971556Srgrimesstatic int 39890110Simpprinttype(u_int mode) 3991556Srgrimes{ 40096892Stjr 40196892Stjr if (f_slash) { 40296892Stjr if ((mode & S_IFMT) == S_IFDIR) { 40396892Stjr (void)putchar('/'); 40496892Stjr return (1); 40596892Stjr } 40696892Stjr return (0); 40796892Stjr } 40896892Stjr 4091556Srgrimes switch (mode & S_IFMT) { 4101556Srgrimes case S_IFDIR: 4111556Srgrimes (void)putchar('/'); 4121556Srgrimes return (1); 4131556Srgrimes case S_IFIFO: 4141556Srgrimes (void)putchar('|'); 4151556Srgrimes return (1); 4161556Srgrimes case S_IFLNK: 4171556Srgrimes (void)putchar('@'); 4181556Srgrimes return (1); 4191556Srgrimes case S_IFSOCK: 4201556Srgrimes (void)putchar('='); 4211556Srgrimes return (1); 42220417Ssteve case S_IFWHT: 42320417Ssteve (void)putchar('%'); 42420417Ssteve return (1); 42590150Smarkm default: 42696681Sbillf break; 4271556Srgrimes } 4281556Srgrimes if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 4291556Srgrimes (void)putchar('*'); 4301556Srgrimes return (1); 4311556Srgrimes } 4321556Srgrimes return (0); 4331556Srgrimes} 4341556Srgrimes 43561268Sjoe#ifdef COLORLS 43661323Sachestatic int 43790110Simpputch(int c) 43861291Sache{ 43988602Sjoe (void)putchar(c); 44061321Sache return 0; 44161291Sache} 44261291Sache 44361323Sachestatic int 44490110Simpwritech(int c) 44561321Sache{ 446114583Smarkm char tmp = (char)c; 44761291Sache 44888602Sjoe (void)write(STDOUT_FILENO, &tmp, 1); 44961321Sache return 0; 45061321Sache} 45161321Sache 45261323Sachestatic void 45390110Simpprintcolor(Colors c) 45461178Sjoe{ 45588594Sjoe char *ansiseq; 45661268Sjoe 45788583Sjoe if (colors[c].bold) 45888583Sjoe tputs(enter_bold, 1, putch); 45988583Sjoe 46088583Sjoe if (colors[c].num[0] != -1) { 46188583Sjoe ansiseq = tgoto(ansi_fgcol, 0, colors[c].num[0]); 46261321Sache if (ansiseq) 46361291Sache tputs(ansiseq, 1, putch); 46461178Sjoe } 46588583Sjoe if (colors[c].num[1] != -1) { 46688583Sjoe ansiseq = tgoto(ansi_bgcol, 0, colors[c].num[1]); 46761321Sache if (ansiseq) 46861291Sache tputs(ansiseq, 1, putch); 46961268Sjoe } 47061178Sjoe} 47161178Sjoe 47261321Sachestatic void 47390110Simpendcolor(int sig) 47461268Sjoe{ 47561321Sache tputs(ansi_coloff, 1, sig ? writech : putch); 47688583Sjoe tputs(attrs_off, 1, sig ? writech : putch); 47761268Sjoe} 47861268Sjoe 47961321Sachestatic int 48090110Simpcolortype(mode_t mode) 48161178Sjoe{ 48288602Sjoe switch (mode & S_IFMT) { 48388595Sjoe case S_IFDIR: 48461178Sjoe if (mode & S_IWOTH) 48588595Sjoe if (mode & S_ISTXT) 48688595Sjoe printcolor(C_WSDIR); 48788595Sjoe else 48888595Sjoe printcolor(C_WDIR); 48961178Sjoe else 49088595Sjoe printcolor(C_DIR); 49188602Sjoe return (1); 49288595Sjoe case S_IFLNK: 49361178Sjoe printcolor(C_LNK); 49488602Sjoe return (1); 49588595Sjoe case S_IFSOCK: 49661178Sjoe printcolor(C_SOCK); 49788602Sjoe return (1); 49888595Sjoe case S_IFIFO: 49961178Sjoe printcolor(C_FIFO); 50088602Sjoe return (1); 50188595Sjoe case S_IFBLK: 50261178Sjoe printcolor(C_BLK); 50388602Sjoe return (1); 50488595Sjoe case S_IFCHR: 50561178Sjoe printcolor(C_CHR); 50688602Sjoe return (1); 507114583Smarkm default:; 50861178Sjoe } 50961178Sjoe if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 51061178Sjoe if (mode & S_ISUID) 51188595Sjoe printcolor(C_SUID); 51261178Sjoe else if (mode & S_ISGID) 51388595Sjoe printcolor(C_SGID); 51461178Sjoe else 51588595Sjoe printcolor(C_EXEC); 51688602Sjoe return (1); 51761178Sjoe } 51888602Sjoe return (0); 51961178Sjoe} 52061178Sjoe 52161178Sjoevoid 52290110Simpparsecolors(const char *cs) 52361178Sjoe{ 52488594Sjoe int i; 52588594Sjoe int j; 526105780Smarkm size_t len; 52788594Sjoe char c[2]; 52888594Sjoe short legacy_warn = 0; 52961321Sache 53088586Sjoe if (cs == NULL) 53188602Sjoe cs = ""; /* LSCOLORS not set */ 53261178Sjoe len = strlen(cs); 533114583Smarkm for (i = 0; i < (int)C_NUMCOLORS; i++) { 53488583Sjoe colors[i].bold = 0; 53588583Sjoe 536114583Smarkm if (len <= 2 * (size_t)i) { 53788586Sjoe c[0] = defcolors[2 * i]; 53888586Sjoe c[1] = defcolors[2 * i + 1]; 53988602Sjoe } else { 54088586Sjoe c[0] = cs[2 * i]; 54188586Sjoe c[1] = cs[2 * i + 1]; 54261178Sjoe } 54388602Sjoe for (j = 0; j < 2; j++) { 54488583Sjoe /* Legacy colours used 0-7 */ 54588583Sjoe if (c[j] >= '0' && c[j] <= '7') { 54688583Sjoe colors[i].num[j] = c[j] - '0'; 54788583Sjoe if (!legacy_warn) { 548106479Stjr warnx("LSCOLORS should use " 54988588Sjoe "characters a-h instead of 0-9 (" 550106479Stjr "see the manual page)"); 55188583Sjoe } 55288583Sjoe legacy_warn = 1; 55388583Sjoe } else if (c[j] >= 'a' && c[j] <= 'h') 55488583Sjoe colors[i].num[j] = c[j] - 'a'; 55588583Sjoe else if (c[j] >= 'A' && c[j] <= 'H') { 55688583Sjoe colors[i].num[j] = c[j] - 'A'; 55788583Sjoe colors[i].bold = 1; 558114583Smarkm } else if (tolower((unsigned char)c[j]) == 'x') 55988583Sjoe colors[i].num[j] = -1; 56088583Sjoe else { 561106479Stjr warnx("invalid character '%c' in LSCOLORS" 562106479Stjr " env var", c[j]); 56388584Sjoe colors[i].num[j] = -1; 56461178Sjoe } 56561178Sjoe } 56661178Sjoe } 56761178Sjoe} 56861291Sache 56961323Sachevoid 57090110Simpcolorquit(int sig) 57161291Sache{ 57261321Sache endcolor(sig); 57361294Sache 57488602Sjoe (void)signal(sig, SIG_DFL); 57588602Sjoe (void)kill(getpid(), sig); 57661291Sache} 57788602Sjoe 57888602Sjoe#endif /* COLORLS */ 57988602Sjoe 5801556Srgrimesstatic void 581105780Smarkmprintlink(const FTSENT *p) 5821556Srgrimes{ 58388594Sjoe int lnklen; 58488594Sjoe char name[MAXPATHLEN + 1]; 58588594Sjoe char path[MAXPATHLEN + 1]; 5861556Srgrimes 5871556Srgrimes if (p->fts_level == FTS_ROOTLEVEL) 5881556Srgrimes (void)snprintf(name, sizeof(name), "%s", p->fts_name); 5898855Srgrimes else 5901556Srgrimes (void)snprintf(name, sizeof(name), 5911556Srgrimes "%s/%s", p->fts_parent->fts_accpath, p->fts_name); 5921556Srgrimes if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) { 5931556Srgrimes (void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno)); 5941556Srgrimes return; 5951556Srgrimes } 5961556Srgrimes path[lnklen] = '\0'; 59762597Sassar (void)printf(" -> "); 59890150Smarkm (void)printname(path); 5991556Srgrimes} 60088591Sjoe 60188591Sjoestatic void 60290110Simpprintsize(size_t width, off_t bytes) 60388591Sjoe{ 60488602Sjoe 60588591Sjoe if (f_humanval) { 606129719Spjd char buf[5]; 60788591Sjoe 608129719Spjd humanize_number(buf, sizeof(buf), (int64_t)bytes, "", 609129719Spjd HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 610129719Spjd (void)printf("%5s ", buf); 61188602Sjoe } else 612114583Smarkm (void)printf("%*jd ", (u_int)width, bytes); 61388591Sjoe} 61488591Sjoe 615106371Stjrstatic void 616114583Smarkmaclmode(char *buf, const FTSENT *p, int *haveacls) 617106371Stjr{ 618106371Stjr char name[MAXPATHLEN + 1]; 619106371Stjr int entries, ret; 620106371Stjr acl_t facl; 621106371Stjr acl_entry_t ae; 622106371Stjr 623106371Stjr /* 624106371Stjr * Add a + after the standard rwxrwxrwx mode if the file has an 625106371Stjr * extended ACL. strmode() reserves space at the end of the string. 626106371Stjr */ 627106371Stjr if (p->fts_level == FTS_ROOTLEVEL) 628106371Stjr snprintf(name, sizeof(name), "%s", p->fts_name); 629106371Stjr else 630106371Stjr snprintf(name, sizeof(name), "%s/%s", 631177907Sgrog p->fts_parent->fts_accpath, p->fts_name); 632108066Stjr /* 633108066Stjr * We have no way to tell whether a symbolic link has an ACL since 634163480Sru * pathconf() and acl_get_file() both follow them. They also don't 635163480Sru * support whiteouts. 636108066Stjr */ 637163480Sru if (S_ISLNK(p->fts_statp->st_mode) || S_ISWHT(p->fts_statp->st_mode)) { 638108066Stjr *haveacls = 1; 639108066Stjr return; 640108066Stjr } 641106371Stjr if ((ret = pathconf(name, _PC_ACL_EXTENDED)) <= 0) { 642106371Stjr if (ret < 0 && errno != EINVAL) 643106371Stjr warn("%s", name); 644106371Stjr else 645106371Stjr *haveacls = 0; 646106371Stjr return; 647106371Stjr } 648106371Stjr *haveacls = 1; 649106371Stjr if ((facl = acl_get_file(name, ACL_TYPE_ACCESS)) != NULL) { 650106371Stjr if (acl_get_entry(facl, ACL_FIRST_ENTRY, &ae) == 1) { 651127795Sbmilekic entries = 1; 652127795Sbmilekic while (acl_get_entry(facl, ACL_NEXT_ENTRY, &ae) == 1) 653127795Sbmilekic if (++entries > 3) 654127795Sbmilekic break; 655127795Sbmilekic /* 656127795Sbmilekic * POSIX.1e requires that ACLs of type ACL_TYPE_ACCESS 657127795Sbmilekic * must have at least three entries (owner, group, 658127795Sbmilekic * and other). So anything with more than 3 ACLs looks 659127795Sbmilekic * interesting to us. 660127795Sbmilekic */ 661127795Sbmilekic if (entries > 3) 662106371Stjr buf[10] = '+'; 663106371Stjr } 664106371Stjr acl_free(facl); 665106371Stjr } else 666106371Stjr warn("%s", name); 667106371Stjr} 668