print.c revision 106371
11556Srgrimes/* 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 * 3. All advertising materials mentioning features or use of this software 171556Srgrimes * must display the following acknowledgement: 181556Srgrimes * This product includes software developed by the University of 191556Srgrimes * California, Berkeley and its contributors. 201556Srgrimes * 4. Neither the name of the University nor the names of its contributors 211556Srgrimes * may be used to endorse or promote products derived from this software 221556Srgrimes * without specific prior written permission. 231556Srgrimes * 241556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341556Srgrimes * SUCH DAMAGE. 351556Srgrimes */ 361556Srgrimes 3790153Smarkm#if 0 381556Srgrimes#ifndef lint 3927967Sstevestatic char sccsid[] = "@(#)print.c 8.4 (Berkeley) 4/17/94"; 4090153Smarkm#endif /* not lint */ 4127967Ssteve#endif 4299109Sobrien#include <sys/cdefs.h> 4399109Sobrien__FBSDID("$FreeBSD: head/bin/ls/print.c 106371 2002-11-03 07:29:08Z tjr $"); 441556Srgrimes 451556Srgrimes#include <sys/param.h> 461556Srgrimes#include <sys/stat.h> 47106371Stjr#include <sys/acl.h> 481556Srgrimes 491556Srgrimes#include <err.h> 501556Srgrimes#include <errno.h> 511556Srgrimes#include <fts.h> 5288591Sjoe#include <math.h> 5374566Sache#include <langinfo.h> 541556Srgrimes#include <stdio.h> 551556Srgrimes#include <stdlib.h> 561556Srgrimes#include <string.h> 5791212Sbde#include <time.h> 581556Srgrimes#include <unistd.h> 5961294Sache#ifdef COLORLS 6061294Sache#include <ctype.h> 6161294Sache#include <termcap.h> 6261294Sache#include <signal.h> 6361294Sache#endif 641556Srgrimes 651556Srgrimes#include "ls.h" 661556Srgrimes#include "extern.h" 671556Srgrimes 6890110Simpstatic int printaname(FTSENT *, u_long, u_long); 69105780Smarkmstatic void printlink(const FTSENT *); 7090110Simpstatic void printtime(time_t); 7190110Simpstatic int printtype(u_int); 7290110Simpstatic void printsize(size_t, off_t); 7361321Sache#ifdef COLORLS 7490110Simpstatic void endcolor(int); 7590110Simpstatic int colortype(mode_t); 7661321Sache#endif 77106371Stjrstatic void aclmode(char *, FTSENT *, int *); 781556Srgrimes 791556Srgrimes#define IS_NOPRINT(p) ((p)->fts_number == NO_PRINT) 801556Srgrimes 8188591Sjoe#define KILO_SZ(n) (n) 8288591Sjoe#define MEGA_SZ(n) ((n) * (n)) 8388591Sjoe#define GIGA_SZ(n) ((n) * (n) * (n)) 8488591Sjoe#define TERA_SZ(n) ((n) * (n) * (n) * (n)) 8588591Sjoe#define PETA_SZ(n) ((n) * (n) * (n) * (n) * (n)) 8688591Sjoe 8788591Sjoe#define KILO_2_SZ (KILO_SZ(1024ULL)) 8888591Sjoe#define MEGA_2_SZ (MEGA_SZ(1024ULL)) 8988591Sjoe#define GIGA_2_SZ (GIGA_SZ(1024ULL)) 9088591Sjoe#define TERA_2_SZ (TERA_SZ(1024ULL)) 9188591Sjoe#define PETA_2_SZ (PETA_SZ(1024ULL)) 9288591Sjoe 9390150Smarkmstatic unsigned long long vals_base2[] = {1, KILO_2_SZ, MEGA_2_SZ, GIGA_2_SZ, TERA_2_SZ, PETA_2_SZ}; 9488591Sjoe 9588602Sjoetypedef enum { 9688602Sjoe NONE, KILO, MEGA, GIGA, TERA, PETA, UNIT_MAX 9788602Sjoe} unit_t; 98105375Sddstatic unit_t unit_adjust(double *); 9988591Sjoe 100105780Smarkmstatic unit_t unitp[] = {NONE, KILO, MEGA, GIGA, TERA, PETA}; 10188591Sjoe 10261268Sjoe#ifdef COLORLS 10361178Sjoe/* Most of these are taken from <sys/stat.h> */ 10461178Sjoetypedef enum Colors { 10588602Sjoe C_DIR, /* directory */ 10688602Sjoe C_LNK, /* symbolic link */ 10788602Sjoe C_SOCK, /* socket */ 10888602Sjoe C_FIFO, /* pipe */ 10988602Sjoe C_EXEC, /* executable */ 11088602Sjoe C_BLK, /* block special */ 11188602Sjoe C_CHR, /* character special */ 11288602Sjoe C_SUID, /* setuid executable */ 11388602Sjoe C_SGID, /* setgid executable */ 11488602Sjoe C_WSDIR, /* directory writeble to others, with sticky 11588602Sjoe * bit */ 11688602Sjoe C_WDIR, /* directory writeble to others, without 11788602Sjoe * sticky bit */ 11888602Sjoe C_NUMCOLORS /* just a place-holder */ 11988586Sjoe} Colors; 12061178Sjoe 12190150Smarkmstatic const char *defcolors = "exfxcxdxbxegedabagacad"; 12261178Sjoe 12388583Sjoe/* colors for file types */ 12488583Sjoestatic struct { 12588586Sjoe int num[2]; 12688586Sjoe int bold; 12788583Sjoe} colors[C_NUMCOLORS]; 12861268Sjoe#endif 12961178Sjoe 1301556Srgrimesvoid 13190110Simpprintscol(DISPLAY *dp) 1321556Srgrimes{ 13388594Sjoe FTSENT *p; 1341556Srgrimes 1351556Srgrimes for (p = dp->list; p; p = p->fts_link) { 1361556Srgrimes if (IS_NOPRINT(p)) 1371556Srgrimes continue; 1381556Srgrimes (void)printaname(p, dp->s_inode, dp->s_block); 1391556Srgrimes (void)putchar('\n'); 1401556Srgrimes } 1411556Srgrimes} 1421556Srgrimes 14362597Sassar/* 14462597Sassar * print name in current style 14562597Sassar */ 146105390Stjrint 14790110Simpprintname(const char *name) 14862597Sassar{ 14962597Sassar if (f_octal || f_octal_escape) 15062597Sassar return prn_octal(name); 15162597Sassar else if (f_nonprint) 15262597Sassar return prn_printable(name); 15362597Sassar else 15462597Sassar return printf("%s", name); 15562597Sassar} 15662597Sassar 1571556Srgrimesvoid 15890110Simpprintlong(DISPLAY *dp) 1591556Srgrimes{ 1601556Srgrimes struct stat *sp; 16188594Sjoe FTSENT *p; 16288594Sjoe NAMES *np; 16388594Sjoe char buf[20]; 16461292Sache#ifdef COLORLS 16588594Sjoe int color_printed = 0; 16661292Sache#endif 167106371Stjr int haveacls; 168106371Stjr dev_t prevdev; 1691556Srgrimes 1701556Srgrimes if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) 1711556Srgrimes (void)printf("total %lu\n", howmany(dp->btotal, blocksize)); 1721556Srgrimes 173106371Stjr haveacls = 1; 174106371Stjr prevdev = (dev_t)-1; 1751556Srgrimes for (p = dp->list; p; p = p->fts_link) { 1761556Srgrimes if (IS_NOPRINT(p)) 1771556Srgrimes continue; 1781556Srgrimes sp = p->fts_statp; 1791556Srgrimes if (f_inode) 18020417Ssteve (void)printf("%*lu ", dp->s_inode, (u_long)sp->st_ino); 1811556Srgrimes if (f_size) 18290150Smarkm (void)printf("%*lld ", 1831556Srgrimes dp->s_block, howmany(sp->st_blocks, blocksize)); 18490150Smarkm strmode(sp->st_mode, buf); 185106371Stjr /* 186106371Stjr * Cache whether or not the filesystem supports ACL's to 187106371Stjr * avoid expensive syscalls. Try again when we change devices. 188106371Stjr */ 189106371Stjr if (haveacls || sp->st_dev != prevdev) { 190106371Stjr aclmode(buf, p, &haveacls); 191106371Stjr prevdev = sp->st_dev; 192106371Stjr } 1931556Srgrimes np = p->fts_pointer; 1941556Srgrimes (void)printf("%s %*u %-*s %-*s ", buf, dp->s_nlink, 1951556Srgrimes sp->st_nlink, dp->s_user, np->user, dp->s_group, 1961556Srgrimes np->group); 1971556Srgrimes if (f_flags) 1981556Srgrimes (void)printf("%-*s ", dp->s_flags, np->flags); 199105832Srwatson if (f_label) 200105832Srwatson (void)printf("%-*s ", dp->s_label, np->label); 2011556Srgrimes if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode)) 20255514Sbde if (minor(sp->st_rdev) > 255 || minor(sp->st_rdev) < 0) 20313120Sjoerg (void)printf("%3d, 0x%08x ", 20455514Sbde major(sp->st_rdev), 20555514Sbde (u_int)minor(sp->st_rdev)); 20613120Sjoerg else 20713120Sjoerg (void)printf("%3d, %3d ", 20813120Sjoerg major(sp->st_rdev), minor(sp->st_rdev)); 2091556Srgrimes else if (dp->bcfile) 21090150Smarkm (void)printf("%*s%*lld ", 2111556Srgrimes 8 - dp->s_size, "", dp->s_size, sp->st_size); 2121556Srgrimes else 21388591Sjoe printsize(dp->s_size, sp->st_size); 2141556Srgrimes if (f_accesstime) 2151556Srgrimes printtime(sp->st_atime); 2161556Srgrimes else if (f_statustime) 2171556Srgrimes printtime(sp->st_ctime); 2181556Srgrimes else 2191556Srgrimes printtime(sp->st_mtime); 22061268Sjoe#ifdef COLORLS 22161178Sjoe if (f_color) 22261291Sache color_printed = colortype(sp->st_mode); 22361268Sjoe#endif 22462597Sassar (void)printname(p->fts_name); 22561268Sjoe#ifdef COLORLS 22661291Sache if (f_color && color_printed) 22761321Sache endcolor(0); 22861268Sjoe#endif 2291556Srgrimes if (f_type) 2301556Srgrimes (void)printtype(sp->st_mode); 2311556Srgrimes if (S_ISLNK(sp->st_mode)) 2321556Srgrimes printlink(p); 2331556Srgrimes (void)putchar('\n'); 2341556Srgrimes } 2351556Srgrimes} 2361556Srgrimes 2371556Srgrimesvoid 23896892Stjrprintstream(DISPLAY *dp) 23996892Stjr{ 24096892Stjr FTSENT *p; 24196892Stjr extern int termwidth; 24296892Stjr int chcnt; 24396892Stjr 24496892Stjr for (p = dp->list, chcnt = 0; p; p = p->fts_link) { 24596892Stjr if (p->fts_number == NO_PRINT) 24696892Stjr continue; 24796892Stjr if (strlen(p->fts_name) + chcnt + 24896892Stjr (p->fts_link ? 2 : 0) >= (unsigned)termwidth) { 24996892Stjr putchar('\n'); 25096892Stjr chcnt = 0; 25196892Stjr } 25296892Stjr chcnt += printaname(p, dp->s_inode, dp->s_block); 25396892Stjr if (p->fts_link) { 25496892Stjr printf(", "); 25596892Stjr chcnt += 2; 25696892Stjr } 25796892Stjr } 25896892Stjr if (chcnt) 25996892Stjr putchar('\n'); 26096892Stjr} 26196892Stjr 26296892Stjrvoid 26390110Simpprintcol(DISPLAY *dp) 2641556Srgrimes{ 2651556Srgrimes extern int termwidth; 2661556Srgrimes static FTSENT **array; 2671556Srgrimes static int lastentries = -1; 26888594Sjoe FTSENT *p; 26988594Sjoe int base; 27088594Sjoe int chcnt; 27188594Sjoe int cnt; 27288594Sjoe int col; 27388594Sjoe int colwidth; 27488594Sjoe int endcol; 27588594Sjoe int num; 27688594Sjoe int numcols; 27788594Sjoe int numrows; 27888594Sjoe int row; 27988594Sjoe int tabwidth; 2801556Srgrimes 28137932Shoek if (f_notabs) 28237932Shoek tabwidth = 1; 28337932Shoek else 28437932Shoek tabwidth = 8; 28537932Shoek 2861556Srgrimes /* 2871556Srgrimes * Have to do random access in the linked list -- build a table 2881556Srgrimes * of pointers. 2891556Srgrimes */ 2901556Srgrimes if (dp->entries > lastentries) { 2911556Srgrimes lastentries = dp->entries; 2921556Srgrimes if ((array = 2931556Srgrimes realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) { 2941556Srgrimes warn(NULL); 2951556Srgrimes printscol(dp); 2961556Srgrimes } 2971556Srgrimes } 2981556Srgrimes for (p = dp->list, num = 0; p; p = p->fts_link) 2991556Srgrimes if (p->fts_number != NO_PRINT) 3001556Srgrimes array[num++] = p; 3011556Srgrimes 3021556Srgrimes colwidth = dp->maxlen; 3031556Srgrimes if (f_inode) 3041556Srgrimes colwidth += dp->s_inode + 1; 3051556Srgrimes if (f_size) 3061556Srgrimes colwidth += dp->s_block + 1; 3071556Srgrimes if (f_type) 3081556Srgrimes colwidth += 1; 3091556Srgrimes 31037932Shoek colwidth = (colwidth + tabwidth) & ~(tabwidth - 1); 3111556Srgrimes if (termwidth < 2 * colwidth) { 3121556Srgrimes printscol(dp); 3131556Srgrimes return; 3141556Srgrimes } 3151556Srgrimes numcols = termwidth / colwidth; 3161556Srgrimes numrows = num / numcols; 3171556Srgrimes if (num % numcols) 3181556Srgrimes ++numrows; 3191556Srgrimes 3201556Srgrimes if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) 3211556Srgrimes (void)printf("total %lu\n", howmany(dp->btotal, blocksize)); 32296892Stjr 323102577Skeramida base = 0; 3241556Srgrimes for (row = 0; row < numrows; ++row) { 3251556Srgrimes endcol = colwidth; 32696892Stjr if (!f_sortacross) 32796892Stjr base = row; 32896892Stjr for (col = 0, chcnt = 0; col < numcols; ++col) { 3291556Srgrimes chcnt += printaname(array[base], dp->s_inode, 3301556Srgrimes dp->s_block); 33196892Stjr if (f_sortacross) 33296892Stjr base++; 33396892Stjr else 33496892Stjr base += numrows; 33596892Stjr if (base >= num) 3361556Srgrimes break; 33737932Shoek while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1))) 33888595Sjoe <= endcol) { 33996892Stjr if (f_sortacross && col + 1 >= numcols) 34096892Stjr break; 34137932Shoek (void)putchar(f_notabs ? ' ' : '\t'); 3421556Srgrimes chcnt = cnt; 3431556Srgrimes } 3441556Srgrimes endcol += colwidth; 3451556Srgrimes } 3461556Srgrimes (void)putchar('\n'); 3471556Srgrimes } 3481556Srgrimes} 3491556Srgrimes 3501556Srgrimes/* 3511556Srgrimes * print [inode] [size] name 3521556Srgrimes * return # of characters printed, no trailing characters. 3531556Srgrimes */ 3541556Srgrimesstatic int 35590110Simpprintaname(FTSENT *p, u_long inodefield, u_long sizefield) 3561556Srgrimes{ 3571556Srgrimes struct stat *sp; 35888594Sjoe int chcnt; 35961292Sache#ifdef COLORLS 36088594Sjoe int color_printed = 0; 36161292Sache#endif 3621556Srgrimes 3631556Srgrimes sp = p->fts_statp; 3641556Srgrimes chcnt = 0; 3651556Srgrimes if (f_inode) 36620417Ssteve chcnt += printf("%*lu ", (int)inodefield, (u_long)sp->st_ino); 3671556Srgrimes if (f_size) 36890150Smarkm chcnt += printf("%*lld ", 3691556Srgrimes (int)sizefield, howmany(sp->st_blocks, blocksize)); 37061268Sjoe#ifdef COLORLS 37161178Sjoe if (f_color) 37261291Sache color_printed = colortype(sp->st_mode); 37361268Sjoe#endif 37462597Sassar chcnt += printname(p->fts_name); 37561268Sjoe#ifdef COLORLS 37661291Sache if (f_color && color_printed) 37761321Sache endcolor(0); 37861268Sjoe#endif 3791556Srgrimes if (f_type) 3801556Srgrimes chcnt += printtype(sp->st_mode); 3811556Srgrimes return (chcnt); 3821556Srgrimes} 3831556Srgrimes 3841556Srgrimesstatic void 38590110Simpprinttime(time_t ftime) 3861556Srgrimes{ 38788594Sjoe char longstring[80]; 38888594Sjoe static time_t now; 38988594Sjoe const char *format; 39088594Sjoe static int d_first = -1; 3911556Srgrimes 39274566Sache if (d_first < 0) 39374566Sache d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 39421545Smpp if (now == 0) 39521545Smpp now = time(NULL); 39621545Smpp 3979987Swollman#define SIXMONTHS ((365 / 2) * 86400) 3981556Srgrimes if (f_sectime) 39961920Sjoe /* mmm dd hh:mm:ss yyyy || dd mmm hh:mm:ss yyyy */ 40074566Sache format = d_first ? "%e %b %T %Y " : "%b %e %T %Y "; 40121545Smpp else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS) 40261920Sjoe /* mmm dd hh:mm || dd mmm hh:mm */ 40374566Sache format = d_first ? "%e %b %R " : "%b %e %R "; 40461814Sjoe else 40561920Sjoe /* mmm dd yyyy || dd mmm yyyy */ 40674566Sache format = d_first ? "%e %b %Y " : "%b %e %Y "; 40761814Sjoe strftime(longstring, sizeof(longstring), format, localtime(&ftime)); 40861814Sjoe fputs(longstring, stdout); 4091556Srgrimes} 4101556Srgrimes 4111556Srgrimesstatic int 41290110Simpprinttype(u_int mode) 4131556Srgrimes{ 41496892Stjr 41596892Stjr if (f_slash) { 41696892Stjr if ((mode & S_IFMT) == S_IFDIR) { 41796892Stjr (void)putchar('/'); 41896892Stjr return (1); 41996892Stjr } 42096892Stjr return (0); 42196892Stjr } 42296892Stjr 4231556Srgrimes switch (mode & S_IFMT) { 4241556Srgrimes case S_IFDIR: 4251556Srgrimes (void)putchar('/'); 4261556Srgrimes return (1); 4271556Srgrimes case S_IFIFO: 4281556Srgrimes (void)putchar('|'); 4291556Srgrimes return (1); 4301556Srgrimes case S_IFLNK: 4311556Srgrimes (void)putchar('@'); 4321556Srgrimes return (1); 4331556Srgrimes case S_IFSOCK: 4341556Srgrimes (void)putchar('='); 4351556Srgrimes return (1); 43620417Ssteve case S_IFWHT: 43720417Ssteve (void)putchar('%'); 43820417Ssteve return (1); 43990150Smarkm default: 44096681Sbillf break; 4411556Srgrimes } 4421556Srgrimes if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 4431556Srgrimes (void)putchar('*'); 4441556Srgrimes return (1); 4451556Srgrimes } 4461556Srgrimes return (0); 4471556Srgrimes} 4481556Srgrimes 44961268Sjoe#ifdef COLORLS 45061323Sachestatic int 45190110Simpputch(int c) 45261291Sache{ 45388602Sjoe (void)putchar(c); 45461321Sache return 0; 45561291Sache} 45661291Sache 45761323Sachestatic int 45890110Simpwritech(int c) 45961321Sache{ 46088594Sjoe char tmp = c; 46161291Sache 46288602Sjoe (void)write(STDOUT_FILENO, &tmp, 1); 46361321Sache return 0; 46461321Sache} 46561321Sache 46661323Sachestatic void 46790110Simpprintcolor(Colors c) 46861178Sjoe{ 46988594Sjoe char *ansiseq; 47061268Sjoe 47188583Sjoe if (colors[c].bold) 47288583Sjoe tputs(enter_bold, 1, putch); 47388583Sjoe 47488583Sjoe if (colors[c].num[0] != -1) { 47588583Sjoe ansiseq = tgoto(ansi_fgcol, 0, colors[c].num[0]); 47661321Sache if (ansiseq) 47761291Sache tputs(ansiseq, 1, putch); 47861178Sjoe } 47988583Sjoe if (colors[c].num[1] != -1) { 48088583Sjoe ansiseq = tgoto(ansi_bgcol, 0, colors[c].num[1]); 48161321Sache if (ansiseq) 48261291Sache tputs(ansiseq, 1, putch); 48361268Sjoe } 48461178Sjoe} 48561178Sjoe 48661321Sachestatic void 48790110Simpendcolor(int sig) 48861268Sjoe{ 48961321Sache tputs(ansi_coloff, 1, sig ? writech : putch); 49088583Sjoe tputs(attrs_off, 1, sig ? writech : putch); 49161268Sjoe} 49261268Sjoe 49361321Sachestatic int 49490110Simpcolortype(mode_t mode) 49561178Sjoe{ 49688602Sjoe switch (mode & S_IFMT) { 49788595Sjoe case S_IFDIR: 49861178Sjoe if (mode & S_IWOTH) 49988595Sjoe if (mode & S_ISTXT) 50088595Sjoe printcolor(C_WSDIR); 50188595Sjoe else 50288595Sjoe printcolor(C_WDIR); 50361178Sjoe else 50488595Sjoe printcolor(C_DIR); 50588602Sjoe return (1); 50688595Sjoe case S_IFLNK: 50761178Sjoe printcolor(C_LNK); 50888602Sjoe return (1); 50988595Sjoe case S_IFSOCK: 51061178Sjoe printcolor(C_SOCK); 51188602Sjoe return (1); 51288595Sjoe case S_IFIFO: 51361178Sjoe printcolor(C_FIFO); 51488602Sjoe return (1); 51588595Sjoe case S_IFBLK: 51661178Sjoe printcolor(C_BLK); 51788602Sjoe return (1); 51888595Sjoe case S_IFCHR: 51961178Sjoe printcolor(C_CHR); 52088602Sjoe return (1); 52161178Sjoe } 52261178Sjoe if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 52361178Sjoe if (mode & S_ISUID) 52488595Sjoe printcolor(C_SUID); 52561178Sjoe else if (mode & S_ISGID) 52688595Sjoe printcolor(C_SGID); 52761178Sjoe else 52888595Sjoe printcolor(C_EXEC); 52988602Sjoe return (1); 53061178Sjoe } 53188602Sjoe return (0); 53261178Sjoe} 53361178Sjoe 53461178Sjoevoid 53590110Simpparsecolors(const char *cs) 53661178Sjoe{ 53788594Sjoe int i; 53888594Sjoe int j; 539105780Smarkm size_t len; 54088594Sjoe char c[2]; 54188594Sjoe short legacy_warn = 0; 54261321Sache 54388586Sjoe if (cs == NULL) 54488602Sjoe cs = ""; /* LSCOLORS not set */ 54561178Sjoe len = strlen(cs); 54688602Sjoe for (i = 0; i < C_NUMCOLORS; i++) { 54788583Sjoe colors[i].bold = 0; 54888583Sjoe 54988586Sjoe if (len <= 2 * i) { 55088586Sjoe c[0] = defcolors[2 * i]; 55188586Sjoe c[1] = defcolors[2 * i + 1]; 55288602Sjoe } else { 55388586Sjoe c[0] = cs[2 * i]; 55488586Sjoe c[1] = cs[2 * i + 1]; 55561178Sjoe } 55688602Sjoe for (j = 0; j < 2; j++) { 55788583Sjoe /* Legacy colours used 0-7 */ 55888583Sjoe if (c[j] >= '0' && c[j] <= '7') { 55988583Sjoe colors[i].num[j] = c[j] - '0'; 56088583Sjoe if (!legacy_warn) { 56188583Sjoe fprintf(stderr, 56288668Sjoe "warn: LSCOLORS should use " 56388588Sjoe "characters a-h instead of 0-9 (" 56488588Sjoe "see the manual page)\n"); 56588583Sjoe } 56688583Sjoe legacy_warn = 1; 56788583Sjoe } else if (c[j] >= 'a' && c[j] <= 'h') 56888583Sjoe colors[i].num[j] = c[j] - 'a'; 56988583Sjoe else if (c[j] >= 'A' && c[j] <= 'H') { 57088583Sjoe colors[i].num[j] = c[j] - 'A'; 57188583Sjoe colors[i].bold = 1; 57288583Sjoe } else if (tolower((unsigned char)c[j] == 'x')) 57388583Sjoe colors[i].num[j] = -1; 57488583Sjoe else { 57561178Sjoe fprintf(stderr, 57688583Sjoe "error: invalid character '%c' in LSCOLORS" 57788583Sjoe " env var\n", c[j]); 57888584Sjoe colors[i].num[j] = -1; 57961178Sjoe } 58061178Sjoe } 58161178Sjoe } 58261178Sjoe} 58361291Sache 58461323Sachevoid 58590110Simpcolorquit(int sig) 58661291Sache{ 58761321Sache endcolor(sig); 58861294Sache 58988602Sjoe (void)signal(sig, SIG_DFL); 59088602Sjoe (void)kill(getpid(), sig); 59161291Sache} 59288602Sjoe 59388602Sjoe#endif /* COLORLS */ 59488602Sjoe 5951556Srgrimesstatic void 596105780Smarkmprintlink(const FTSENT *p) 5971556Srgrimes{ 59888594Sjoe int lnklen; 59988594Sjoe char name[MAXPATHLEN + 1]; 60088594Sjoe char path[MAXPATHLEN + 1]; 6011556Srgrimes 6021556Srgrimes if (p->fts_level == FTS_ROOTLEVEL) 6031556Srgrimes (void)snprintf(name, sizeof(name), "%s", p->fts_name); 6048855Srgrimes else 6051556Srgrimes (void)snprintf(name, sizeof(name), 6061556Srgrimes "%s/%s", p->fts_parent->fts_accpath, p->fts_name); 6071556Srgrimes if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) { 6081556Srgrimes (void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno)); 6091556Srgrimes return; 6101556Srgrimes } 6111556Srgrimes path[lnklen] = '\0'; 61262597Sassar (void)printf(" -> "); 61390150Smarkm (void)printname(path); 6141556Srgrimes} 61588591Sjoe 61688591Sjoestatic void 61790110Simpprintsize(size_t width, off_t bytes) 61888591Sjoe{ 619105375Sdd double dbytes; 62088591Sjoe unit_t unit; 62188602Sjoe 62288591Sjoe if (f_humanval) { 623105375Sdd dbytes = bytes; 624105375Sdd unit = unit_adjust(&dbytes); 62588591Sjoe 626105375Sdd if (dbytes == 0) 62788591Sjoe (void)printf("%*s ", width, "0B"); 62888591Sjoe else 629105375Sdd (void)printf("%*.*f%c ", width - 1, dbytes > 10 ? 0 : 1, 630105375Sdd dbytes, "BKMGTPE"[unit]); 63188602Sjoe } else 63290150Smarkm (void)printf("%*lld ", width, bytes); 63388591Sjoe} 63488591Sjoe 63588591Sjoe/* 63688591Sjoe * Output in "human-readable" format. Uses 3 digits max and puts 63788591Sjoe * unit suffixes at the end. Makes output compact and easy to read, 63888591Sjoe * especially on huge disks. 63988591Sjoe * 64088591Sjoe */ 641105780Smarkmstatic unit_t 642105375Sddunit_adjust(double *val) 64388591Sjoe{ 64488595Sjoe double abval; 64588595Sjoe unit_t unit; 646105780Smarkm u_int unit_sz; 64788591Sjoe 648105375Sdd abval = fabs(*val); 64988591Sjoe 650105780Smarkm unit_sz = abval ? (u_int)ilogb(abval) / 10 : 0; 65188591Sjoe 652105780Smarkm if (unit_sz >= (u_int)UNIT_MAX) { 65388595Sjoe unit = NONE; 65488595Sjoe } else { 65588595Sjoe unit = unitp[unit_sz]; 65688595Sjoe *val /= (double)vals_base2[unit_sz]; 65788595Sjoe } 65888591Sjoe 65988595Sjoe return (unit); 66088591Sjoe} 661106371Stjr 662106371Stjrstatic void 663106371Stjraclmode(char *buf, FTSENT *p, int *haveacls) 664106371Stjr{ 665106371Stjr char name[MAXPATHLEN + 1]; 666106371Stjr int entries, ret; 667106371Stjr acl_t facl; 668106371Stjr acl_entry_t ae; 669106371Stjr 670106371Stjr /* 671106371Stjr * Add a + after the standard rwxrwxrwx mode if the file has an 672106371Stjr * extended ACL. strmode() reserves space at the end of the string. 673106371Stjr */ 674106371Stjr if (p->fts_level == FTS_ROOTLEVEL) 675106371Stjr snprintf(name, sizeof(name), "%s", p->fts_name); 676106371Stjr else 677106371Stjr snprintf(name, sizeof(name), "%s/%s", 678106371Stjr p->fts_parent->fts_accpath, p->fts_name); 679106371Stjr if ((ret = pathconf(name, _PC_ACL_EXTENDED)) <= 0) { 680106371Stjr if (ret < 0 && errno != EINVAL) 681106371Stjr warn("%s", name); 682106371Stjr else 683106371Stjr *haveacls = 0; 684106371Stjr return; 685106371Stjr } 686106371Stjr *haveacls = 1; 687106371Stjr if ((facl = acl_get_file(name, ACL_TYPE_ACCESS)) != NULL) { 688106371Stjr if (acl_get_entry(facl, ACL_FIRST_ENTRY, &ae) == 1) { 689106371Stjr entries = 0; 690106371Stjr do 691106371Stjr entries++; 692106371Stjr while (acl_get_entry(facl, ACL_NEXT_ENTRY, &ae) == 1); 693106371Stjr if (entries != 3) 694106371Stjr buf[10] = '+'; 695106371Stjr } 696106371Stjr acl_free(facl); 697106371Stjr } else 698106371Stjr warn("%s", name); 699106371Stjr} 700