print.c revision 284198
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 284198 2015-06-10 01:27:38Z marcel $"); 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 61284198Smarcel#include <libxo/xo.h> 621556Srgrimes 631556Srgrimes#include "ls.h" 641556Srgrimes#include "extern.h" 651556Srgrimes 66114583Smarkmstatic int printaname(const FTSENT *, u_long, u_long); 67202945Sjhstatic void printdev(size_t, dev_t); 68105780Smarkmstatic void printlink(const FTSENT *); 69284198Smarcelstatic void printtime(const char *, time_t); 7090110Simpstatic int printtype(u_int); 71284198Smarcelstatic void printsize(const char *, size_t, off_t); 7261321Sache#ifdef COLORLS 7390110Simpstatic void endcolor(int); 7490110Simpstatic int colortype(mode_t); 7561321Sache#endif 76196712Straszstatic void aclmode(char *, const FTSENT *); 771556Srgrimes 781556Srgrimes#define IS_NOPRINT(p) ((p)->fts_number == NO_PRINT) 791556Srgrimes 8061268Sjoe#ifdef COLORLS 8161178Sjoe/* Most of these are taken from <sys/stat.h> */ 8261178Sjoetypedef enum Colors { 8388602Sjoe C_DIR, /* directory */ 8488602Sjoe C_LNK, /* symbolic link */ 8588602Sjoe C_SOCK, /* socket */ 8688602Sjoe C_FIFO, /* pipe */ 8788602Sjoe C_EXEC, /* executable */ 8888602Sjoe C_BLK, /* block special */ 8988602Sjoe C_CHR, /* character special */ 9088602Sjoe C_SUID, /* setuid executable */ 9188602Sjoe C_SGID, /* setgid executable */ 9288602Sjoe C_WSDIR, /* directory writeble to others, with sticky 9388602Sjoe * bit */ 9488602Sjoe C_WDIR, /* directory writeble to others, without 9588602Sjoe * sticky bit */ 9688602Sjoe C_NUMCOLORS /* just a place-holder */ 9788586Sjoe} Colors; 9861178Sjoe 9990150Smarkmstatic const char *defcolors = "exfxcxdxbxegedabagacad"; 10061178Sjoe 10188583Sjoe/* colors for file types */ 10288583Sjoestatic struct { 10388586Sjoe int num[2]; 10488586Sjoe int bold; 10588583Sjoe} colors[C_NUMCOLORS]; 10661268Sjoe#endif 10761178Sjoe 1081556Srgrimesvoid 109114583Smarkmprintscol(const DISPLAY *dp) 1101556Srgrimes{ 11188594Sjoe FTSENT *p; 1121556Srgrimes 113284198Smarcel xo_open_list("entry"); 1141556Srgrimes for (p = dp->list; p; p = p->fts_link) { 1151556Srgrimes if (IS_NOPRINT(p)) 1161556Srgrimes continue; 117284198Smarcel xo_open_instance("entry"); 1181556Srgrimes (void)printaname(p, dp->s_inode, dp->s_block); 119284198Smarcel xo_close_instance("entry"); 120284198Smarcel xo_emit("\n"); 1211556Srgrimes } 122284198Smarcel xo_close_list("entry"); 1231556Srgrimes} 1241556Srgrimes 12562597Sassar/* 12662597Sassar * print name in current style 12762597Sassar */ 128105390Stjrint 129284198Smarcelprintname(const char *field, const char *name) 13062597Sassar{ 131284198Smarcel char fmt[BUFSIZ]; 132284198Smarcel char *s = getname(name); 133284198Smarcel int rc; 134284198Smarcel 135284198Smarcel snprintf(fmt, sizeof(fmt), "{:%s/%%hs}", field); 136284198Smarcel rc = xo_emit(fmt, s); 137284198Smarcel free(s); 138284198Smarcel return rc; 139284198Smarcel} 140284198Smarcel 141284198Smarcel/* 142284198Smarcel * print name in current style 143284198Smarcel */ 144284198Smarcelchar * 145284198Smarcelgetname(const char *name) 146284198Smarcel{ 14762597Sassar if (f_octal || f_octal_escape) 148284198Smarcel return get_octal(name); 14962597Sassar else if (f_nonprint) 150284198Smarcel return get_printable(name); 15162597Sassar else 152284198Smarcel return strdup(name); 15362597Sassar} 15462597Sassar 1551556Srgrimesvoid 156114583Smarkmprintlong(const DISPLAY *dp) 1571556Srgrimes{ 1581556Srgrimes struct stat *sp; 15988594Sjoe FTSENT *p; 16088594Sjoe NAMES *np; 16188594Sjoe char buf[20]; 16261292Sache#ifdef COLORLS 16388594Sjoe int color_printed = 0; 16461292Sache#endif 1651556Srgrimes 166130236Sdas if ((dp->list == NULL || dp->list->fts_level != FTS_ROOTLEVEL) && 167130236Sdas (f_longform || f_size)) { 168284198Smarcel xo_emit("{L:total} {:total-blocks/%lu}\n", 169284198Smarcel howmany(dp->btotal, blocksize)); 170130236Sdas } 1711556Srgrimes 172284198Smarcel xo_open_list("entry"); 1731556Srgrimes for (p = dp->list; p; p = p->fts_link) { 174284198Smarcel char *name; 1751556Srgrimes if (IS_NOPRINT(p)) 1761556Srgrimes continue; 177284198Smarcel xo_open_instance("entry"); 1781556Srgrimes sp = p->fts_statp; 179284198Smarcel name = getname(p->fts_name); 180284198Smarcel if (name) 181284198Smarcel xo_emit("{ke:name}", name); 1821556Srgrimes if (f_inode) 183284198Smarcel xo_emit("{:inode/%*ju} ", 184241014Smdf dp->s_inode, (uintmax_t)sp->st_ino); 1851556Srgrimes if (f_size) 186284198Smarcel xo_emit("{:blocks/%*jd} ", 1871556Srgrimes dp->s_block, howmany(sp->st_blocks, blocksize)); 18890150Smarkm strmode(sp->st_mode, buf); 189196712Strasz aclmode(buf, p); 1901556Srgrimes np = p->fts_pointer; 191284198Smarcel xo_attr("value", "%03o", (int) sp->st_mode & ALLPERMS); 192284198Smarcel xo_emit("{t:mode/%s} {:links/%*u} {:user/%-*s} {:group/%-*s} ", 193284198Smarcel buf, dp->s_nlink, sp->st_nlink, 194284198Smarcel dp->s_user, np->user, dp->s_group, np->group); 1951556Srgrimes if (f_flags) 196284198Smarcel xo_emit("{:flags/%-*s} ", dp->s_flags, np->flags); 197105832Srwatson if (f_label) 198284198Smarcel xo_emit("{:label/%-*s} ", dp->s_label, np->label); 1991556Srgrimes if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode)) 200202945Sjh printdev(dp->s_size, sp->st_rdev); 2011556Srgrimes else 202284198Smarcel printsize("size", dp->s_size, sp->st_size); 2031556Srgrimes if (f_accesstime) 204284198Smarcel printtime("access-time", sp->st_atime); 205157098Sjhb else if (f_birthtime) 206284198Smarcel printtime("birth-time", sp->st_birthtime); 2071556Srgrimes else if (f_statustime) 208284198Smarcel printtime("change-time", sp->st_ctime); 2091556Srgrimes else 210284198Smarcel printtime("modify-time", sp->st_mtime); 21161268Sjoe#ifdef COLORLS 21261178Sjoe if (f_color) 21361291Sache color_printed = colortype(sp->st_mode); 21461268Sjoe#endif 215284198Smarcel 216284198Smarcel if (name) { 217284198Smarcel xo_emit("{dk:name}", name); 218284198Smarcel free(name); 219284198Smarcel } 220284198Smarcel 22161268Sjoe#ifdef COLORLS 22261291Sache if (f_color && color_printed) 22361321Sache endcolor(0); 22461268Sjoe#endif 2251556Srgrimes if (f_type) 2261556Srgrimes (void)printtype(sp->st_mode); 2271556Srgrimes if (S_ISLNK(sp->st_mode)) 2281556Srgrimes printlink(p); 229284198Smarcel xo_close_instance("entry"); 230284198Smarcel xo_emit("\n"); 2311556Srgrimes } 232284198Smarcel xo_close_list("entry"); 2331556Srgrimes} 2341556Srgrimes 2351556Srgrimesvoid 236114583Smarkmprintstream(const DISPLAY *dp) 23796892Stjr{ 23896892Stjr FTSENT *p; 23996892Stjr int chcnt; 24096892Stjr 24196892Stjr for (p = dp->list, chcnt = 0; p; p = p->fts_link) { 24296892Stjr if (p->fts_number == NO_PRINT) 24396892Stjr continue; 244128823Stjr /* XXX strlen does not take octal escapes into account. */ 24596892Stjr if (strlen(p->fts_name) + chcnt + 24696892Stjr (p->fts_link ? 2 : 0) >= (unsigned)termwidth) { 247284198Smarcel xo_emit("\n"); 24896892Stjr chcnt = 0; 24996892Stjr } 25096892Stjr chcnt += printaname(p, dp->s_inode, dp->s_block); 25196892Stjr if (p->fts_link) { 252284198Smarcel xo_emit(", "); 25396892Stjr chcnt += 2; 25496892Stjr } 25596892Stjr } 25696892Stjr if (chcnt) 257284198Smarcel xo_emit("\n"); 25896892Stjr} 259177907Sgrog 26096892Stjrvoid 261114583Smarkmprintcol(const DISPLAY *dp) 2621556Srgrimes{ 2631556Srgrimes static FTSENT **array; 2641556Srgrimes static int lastentries = -1; 26588594Sjoe FTSENT *p; 266121124Stjr FTSENT **narray; 26788594Sjoe int base; 26888594Sjoe int chcnt; 26988594Sjoe int cnt; 27088594Sjoe int col; 27188594Sjoe int colwidth; 27288594Sjoe int endcol; 27388594Sjoe int num; 27488594Sjoe int numcols; 27588594Sjoe int numrows; 27688594Sjoe int row; 27788594Sjoe int tabwidth; 2781556Srgrimes 27937932Shoek if (f_notabs) 28037932Shoek tabwidth = 1; 28137932Shoek else 28237932Shoek tabwidth = 8; 28337932Shoek 2841556Srgrimes /* 2851556Srgrimes * Have to do random access in the linked list -- build a table 2861556Srgrimes * of pointers. 2871556Srgrimes */ 2881556Srgrimes if (dp->entries > lastentries) { 289121124Stjr if ((narray = 2901556Srgrimes realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) { 291284198Smarcel xo_warn(NULL); 2921556Srgrimes printscol(dp); 293121124Stjr return; 2941556Srgrimes } 295121124Stjr lastentries = dp->entries; 296121124Stjr array = narray; 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 320130236Sdas if ((dp->list == NULL || dp->list->fts_level != FTS_ROOTLEVEL) && 321130236Sdas (f_longform || f_size)) { 322284198Smarcel xo_emit("{L:total} {:total-blocks/%lu}\n", 323284198Smarcel howmany(dp->btotal, blocksize)); 324130236Sdas } 32596892Stjr 326284198Smarcel xo_open_list("entry"); 327102577Skeramida base = 0; 3281556Srgrimes for (row = 0; row < numrows; ++row) { 3291556Srgrimes endcol = colwidth; 33096892Stjr if (!f_sortacross) 33196892Stjr base = row; 33296892Stjr for (col = 0, chcnt = 0; col < numcols; ++col) { 333284198Smarcel xo_open_instance("entry"); 3341556Srgrimes chcnt += printaname(array[base], dp->s_inode, 3351556Srgrimes dp->s_block); 336284198Smarcel xo_close_instance("entry"); 33796892Stjr if (f_sortacross) 33896892Stjr base++; 33996892Stjr else 34096892Stjr base += numrows; 34196892Stjr if (base >= num) 3421556Srgrimes break; 34337932Shoek while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1))) 34488595Sjoe <= endcol) { 34596892Stjr if (f_sortacross && col + 1 >= numcols) 34696892Stjr break; 347284198Smarcel xo_emit(f_notabs ? " " : "\t"); 3481556Srgrimes chcnt = cnt; 3491556Srgrimes } 3501556Srgrimes endcol += colwidth; 3511556Srgrimes } 352284198Smarcel xo_emit("\n"); 3531556Srgrimes } 354284198Smarcel xo_close_list("entry"); 3551556Srgrimes} 3561556Srgrimes 3571556Srgrimes/* 3581556Srgrimes * print [inode] [size] name 3591556Srgrimes * return # of characters printed, no trailing characters. 3601556Srgrimes */ 3611556Srgrimesstatic int 362114583Smarkmprintaname(const FTSENT *p, u_long inodefield, u_long sizefield) 3631556Srgrimes{ 3641556Srgrimes struct stat *sp; 36588594Sjoe int chcnt; 36661292Sache#ifdef COLORLS 36788594Sjoe int color_printed = 0; 36861292Sache#endif 3691556Srgrimes 3701556Srgrimes sp = p->fts_statp; 3711556Srgrimes chcnt = 0; 3721556Srgrimes if (f_inode) 373284198Smarcel chcnt += xo_emit("{:inode/%*ju} ", 374241014Smdf (int)inodefield, (uintmax_t)sp->st_ino); 3751556Srgrimes if (f_size) 376284198Smarcel chcnt += xo_emit("{:size/%*jd} ", 3771556Srgrimes (int)sizefield, howmany(sp->st_blocks, blocksize)); 37861268Sjoe#ifdef COLORLS 37961178Sjoe if (f_color) 38061291Sache color_printed = colortype(sp->st_mode); 38161268Sjoe#endif 382284198Smarcel chcnt += printname("name", p->fts_name); 38361268Sjoe#ifdef COLORLS 38461291Sache if (f_color && color_printed) 38561321Sache endcolor(0); 38661268Sjoe#endif 3871556Srgrimes if (f_type) 3881556Srgrimes chcnt += printtype(sp->st_mode); 3891556Srgrimes return (chcnt); 3901556Srgrimes} 3911556Srgrimes 392202945Sjh/* 393202945Sjh * Print device special file major and minor numbers. 394202945Sjh */ 3951556Srgrimesstatic void 396202945Sjhprintdev(size_t width, dev_t dev) 397202945Sjh{ 398284198Smarcel xo_emit("{:device/%#*jx} ", (u_int)width, (uintmax_t)dev); 399202945Sjh} 400202945Sjh 401202945Sjhstatic void 402284198Smarcelprinttime(const char *field, time_t ftime) 4031556Srgrimes{ 40488594Sjoe char longstring[80]; 405284198Smarcel char fmt[BUFSIZ]; 406114583Smarkm static time_t now = 0; 40788594Sjoe const char *format; 40888594Sjoe static int d_first = -1; 4091556Srgrimes 41074566Sache if (d_first < 0) 41174566Sache d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 41221545Smpp if (now == 0) 41321545Smpp now = time(NULL); 41421545Smpp 4159987Swollman#define SIXMONTHS ((365 / 2) * 86400) 416177907Sgrog if (f_timeformat) /* user specified format */ 417177907Sgrog format = f_timeformat; 418177907Sgrog else if (f_sectime) 41961920Sjoe /* mmm dd hh:mm:ss yyyy || dd mmm hh:mm:ss yyyy */ 420177907Sgrog format = d_first ? "%e %b %T %Y" : "%b %e %T %Y"; 42121545Smpp else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS) 42261920Sjoe /* mmm dd hh:mm || dd mmm hh:mm */ 423177907Sgrog format = d_first ? "%e %b %R" : "%b %e %R"; 42461814Sjoe else 42561920Sjoe /* mmm dd yyyy || dd mmm yyyy */ 426242840Speter format = d_first ? "%e %b %Y" : "%b %e %Y"; 42761814Sjoe strftime(longstring, sizeof(longstring), format, localtime(&ftime)); 428284198Smarcel 429284198Smarcel snprintf(fmt, sizeof(fmt), "{:%s/%%s} ", field); 430284198Smarcel xo_attr("value", "%ld", (long) ftime); 431284198Smarcel xo_emit(fmt, longstring); 4321556Srgrimes} 4331556Srgrimes 4341556Srgrimesstatic int 43590110Simpprinttype(u_int mode) 4361556Srgrimes{ 43796892Stjr 43896892Stjr if (f_slash) { 43996892Stjr if ((mode & S_IFMT) == S_IFDIR) { 440284198Smarcel xo_emit("{D:\\/}{e:type/directory}"); 44196892Stjr return (1); 44296892Stjr } 44396892Stjr return (0); 44496892Stjr } 44596892Stjr 4461556Srgrimes switch (mode & S_IFMT) { 4471556Srgrimes case S_IFDIR: 448284198Smarcel xo_emit("{D:/\\/}{e:type/directory}"); 4491556Srgrimes return (1); 4501556Srgrimes case S_IFIFO: 451284198Smarcel xo_emit("{D:|}{e:type/fifo}"); 4521556Srgrimes return (1); 4531556Srgrimes case S_IFLNK: 454284198Smarcel xo_emit("{D:@}{e:type/link}"); 4551556Srgrimes return (1); 4561556Srgrimes case S_IFSOCK: 457284198Smarcel xo_emit("{D:=}{e:type/socket}"); 4581556Srgrimes return (1); 45920417Ssteve case S_IFWHT: 460284198Smarcel xo_emit("{D:%}{e:type/whiteout}"); 46120417Ssteve return (1); 46290150Smarkm default: 46396681Sbillf break; 4641556Srgrimes } 4651556Srgrimes if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 466284198Smarcel xo_emit("{D:*}{e:executable/}"); 4671556Srgrimes return (1); 4681556Srgrimes } 4691556Srgrimes return (0); 4701556Srgrimes} 4711556Srgrimes 47261268Sjoe#ifdef COLORLS 47361323Sachestatic int 47490110Simpputch(int c) 47561291Sache{ 476284198Smarcel xo_emit("{D:/%c}", c); 47761321Sache return 0; 47861291Sache} 47961291Sache 48061323Sachestatic int 48190110Simpwritech(int c) 48261321Sache{ 483114583Smarkm char tmp = (char)c; 48461291Sache 48588602Sjoe (void)write(STDOUT_FILENO, &tmp, 1); 48661321Sache return 0; 48761321Sache} 48861321Sache 48961323Sachestatic void 49090110Simpprintcolor(Colors c) 49161178Sjoe{ 49288594Sjoe char *ansiseq; 49361268Sjoe 49488583Sjoe if (colors[c].bold) 49588583Sjoe tputs(enter_bold, 1, putch); 49688583Sjoe 49788583Sjoe if (colors[c].num[0] != -1) { 49888583Sjoe ansiseq = tgoto(ansi_fgcol, 0, colors[c].num[0]); 49961321Sache if (ansiseq) 50061291Sache tputs(ansiseq, 1, putch); 50161178Sjoe } 50288583Sjoe if (colors[c].num[1] != -1) { 50388583Sjoe ansiseq = tgoto(ansi_bgcol, 0, colors[c].num[1]); 50461321Sache if (ansiseq) 50561291Sache tputs(ansiseq, 1, putch); 50661268Sjoe } 50761178Sjoe} 50861178Sjoe 50961321Sachestatic void 51090110Simpendcolor(int sig) 51161268Sjoe{ 51261321Sache tputs(ansi_coloff, 1, sig ? writech : putch); 51388583Sjoe tputs(attrs_off, 1, sig ? writech : putch); 51461268Sjoe} 51561268Sjoe 51661321Sachestatic int 51790110Simpcolortype(mode_t mode) 51861178Sjoe{ 51988602Sjoe switch (mode & S_IFMT) { 52088595Sjoe case S_IFDIR: 52161178Sjoe if (mode & S_IWOTH) 52288595Sjoe if (mode & S_ISTXT) 52388595Sjoe printcolor(C_WSDIR); 52488595Sjoe else 52588595Sjoe printcolor(C_WDIR); 52661178Sjoe else 52788595Sjoe printcolor(C_DIR); 52888602Sjoe return (1); 52988595Sjoe case S_IFLNK: 53061178Sjoe printcolor(C_LNK); 53188602Sjoe return (1); 53288595Sjoe case S_IFSOCK: 53361178Sjoe printcolor(C_SOCK); 53488602Sjoe return (1); 53588595Sjoe case S_IFIFO: 53661178Sjoe printcolor(C_FIFO); 53788602Sjoe return (1); 53888595Sjoe case S_IFBLK: 53961178Sjoe printcolor(C_BLK); 54088602Sjoe return (1); 54188595Sjoe case S_IFCHR: 54261178Sjoe printcolor(C_CHR); 54388602Sjoe return (1); 544114583Smarkm default:; 54561178Sjoe } 54661178Sjoe if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 54761178Sjoe if (mode & S_ISUID) 54888595Sjoe printcolor(C_SUID); 54961178Sjoe else if (mode & S_ISGID) 55088595Sjoe printcolor(C_SGID); 55161178Sjoe else 55288595Sjoe printcolor(C_EXEC); 55388602Sjoe return (1); 55461178Sjoe } 55588602Sjoe return (0); 55661178Sjoe} 55761178Sjoe 55861178Sjoevoid 55990110Simpparsecolors(const char *cs) 56061178Sjoe{ 56188594Sjoe int i; 56288594Sjoe int j; 563105780Smarkm size_t len; 56488594Sjoe char c[2]; 56588594Sjoe short legacy_warn = 0; 56661321Sache 56788586Sjoe if (cs == NULL) 56888602Sjoe cs = ""; /* LSCOLORS not set */ 56961178Sjoe len = strlen(cs); 570114583Smarkm for (i = 0; i < (int)C_NUMCOLORS; i++) { 57188583Sjoe colors[i].bold = 0; 57288583Sjoe 573114583Smarkm if (len <= 2 * (size_t)i) { 57488586Sjoe c[0] = defcolors[2 * i]; 57588586Sjoe c[1] = defcolors[2 * i + 1]; 57688602Sjoe } else { 57788586Sjoe c[0] = cs[2 * i]; 57888586Sjoe c[1] = cs[2 * i + 1]; 57961178Sjoe } 58088602Sjoe for (j = 0; j < 2; j++) { 58188583Sjoe /* Legacy colours used 0-7 */ 58288583Sjoe if (c[j] >= '0' && c[j] <= '7') { 58388583Sjoe colors[i].num[j] = c[j] - '0'; 58488583Sjoe if (!legacy_warn) { 585284198Smarcel xo_warnx("LSCOLORS should use " 58688588Sjoe "characters a-h instead of 0-9 (" 587106479Stjr "see the manual page)"); 58888583Sjoe } 58988583Sjoe legacy_warn = 1; 59088583Sjoe } else if (c[j] >= 'a' && c[j] <= 'h') 59188583Sjoe colors[i].num[j] = c[j] - 'a'; 59288583Sjoe else if (c[j] >= 'A' && c[j] <= 'H') { 59388583Sjoe colors[i].num[j] = c[j] - 'A'; 59488583Sjoe colors[i].bold = 1; 595114583Smarkm } else if (tolower((unsigned char)c[j]) == 'x') 59688583Sjoe colors[i].num[j] = -1; 59788583Sjoe else { 598284198Smarcel xo_warnx("invalid character '%c' in LSCOLORS" 599106479Stjr " env var", c[j]); 60088584Sjoe colors[i].num[j] = -1; 60161178Sjoe } 60261178Sjoe } 60361178Sjoe } 60461178Sjoe} 60561291Sache 60661323Sachevoid 60790110Simpcolorquit(int sig) 60861291Sache{ 60961321Sache endcolor(sig); 61061294Sache 61188602Sjoe (void)signal(sig, SIG_DFL); 61288602Sjoe (void)kill(getpid(), sig); 61361291Sache} 61488602Sjoe 61588602Sjoe#endif /* COLORLS */ 61688602Sjoe 6171556Srgrimesstatic void 618105780Smarkmprintlink(const FTSENT *p) 6191556Srgrimes{ 62088594Sjoe int lnklen; 62188594Sjoe char name[MAXPATHLEN + 1]; 62288594Sjoe char path[MAXPATHLEN + 1]; 6231556Srgrimes 6241556Srgrimes if (p->fts_level == FTS_ROOTLEVEL) 6251556Srgrimes (void)snprintf(name, sizeof(name), "%s", p->fts_name); 6268855Srgrimes else 6271556Srgrimes (void)snprintf(name, sizeof(name), 6281556Srgrimes "%s/%s", p->fts_parent->fts_accpath, p->fts_name); 6291556Srgrimes if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) { 630284198Smarcel xo_error("\nls: %s: %s\n", name, strerror(errno)); 6311556Srgrimes return; 6321556Srgrimes } 6331556Srgrimes path[lnklen] = '\0'; 634284198Smarcel xo_emit(" -> "); 635284198Smarcel (void)printname("target", path); 6361556Srgrimes} 63788591Sjoe 63888591Sjoestatic void 639284198Smarcelprintsize(const char *field, size_t width, off_t bytes) 64088591Sjoe{ 641284198Smarcel char fmt[BUFSIZ]; 642284198Smarcel 64388591Sjoe if (f_humanval) { 644202945Sjh /* 645202945Sjh * Reserve one space before the size and allocate room for 646202945Sjh * the trailing '\0'. 647202945Sjh */ 648202945Sjh char buf[HUMANVALSTR_LEN - 1 + 1]; 64988591Sjoe 650129719Spjd humanize_number(buf, sizeof(buf), (int64_t)bytes, "", 651129719Spjd HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 652284198Smarcel snprintf(fmt, sizeof(fmt), "{:%s/%%%ds} ", field, (int) width); 653284198Smarcel xo_attr("value", "%jd", (intmax_t) bytes); 654284198Smarcel xo_emit(fmt, buf); 655284198Smarcel } else { /* with commas */ 656242725Sgrog /* This format assignment needed to work round gcc bug. */ 657284198Smarcel snprintf(fmt, sizeof(fmt), "{:%s/%%%dj%sd} ", 658284198Smarcel field, (int) width, f_thousands ? "'" : ""); 659284198Smarcel xo_emit(fmt, (intmax_t) bytes); 660284198Smarcel } 66188591Sjoe} 66288591Sjoe 663196712Strasz/* 664196712Strasz * Add a + after the standard rwxrwxrwx mode if the file has an 665196712Strasz * ACL. strmode() reserves space at the end of the string. 666196712Strasz */ 667106371Stjrstatic void 668196712Straszaclmode(char *buf, const FTSENT *p) 669106371Stjr{ 670106371Stjr char name[MAXPATHLEN + 1]; 671196712Strasz int ret, trivial; 672196712Strasz static dev_t previous_dev = NODEV; 673196712Strasz static int supports_acls = -1; 674196712Strasz static int type = ACL_TYPE_ACCESS; 675106371Stjr acl_t facl; 676106371Stjr 677106371Stjr /* 678196712Strasz * XXX: ACLs are not supported on whiteouts and device files 679196712Strasz * residing on UFS. 680106371Stjr */ 681196712Strasz if (S_ISCHR(p->fts_statp->st_mode) || S_ISBLK(p->fts_statp->st_mode) || 682196712Strasz S_ISWHT(p->fts_statp->st_mode)) 683108066Stjr return; 684196712Strasz 685196773Strasz if (previous_dev == p->fts_statp->st_dev && supports_acls == 0) 686196773Strasz return; 687196773Strasz 688196773Strasz if (p->fts_level == FTS_ROOTLEVEL) 689196773Strasz snprintf(name, sizeof(name), "%s", p->fts_name); 690196773Strasz else 691196773Strasz snprintf(name, sizeof(name), "%s/%s", 692196773Strasz p->fts_parent->fts_accpath, p->fts_name); 693196773Strasz 694196712Strasz if (previous_dev != p->fts_statp->st_dev) { 695196712Strasz previous_dev = p->fts_statp->st_dev; 696196712Strasz supports_acls = 0; 697196712Strasz 698196712Strasz ret = lpathconf(name, _PC_ACL_NFS4); 699196712Strasz if (ret > 0) { 700196712Strasz type = ACL_TYPE_NFS4; 701196712Strasz supports_acls = 1; 702196712Strasz } else if (ret < 0 && errno != EINVAL) { 703284198Smarcel xo_warn("%s", name); 704196712Strasz return; 705196712Strasz } 706196712Strasz if (supports_acls == 0) { 707196712Strasz ret = lpathconf(name, _PC_ACL_EXTENDED); 708196712Strasz if (ret > 0) { 709196712Strasz type = ACL_TYPE_ACCESS; 710196712Strasz supports_acls = 1; 711196712Strasz } else if (ret < 0 && errno != EINVAL) { 712284198Smarcel xo_warn("%s", name); 713196712Strasz return; 714196712Strasz } 715196712Strasz } 716108066Stjr } 717196712Strasz if (supports_acls == 0) 718106371Stjr return; 719196712Strasz facl = acl_get_link_np(name, type); 720196712Strasz if (facl == NULL) { 721284198Smarcel xo_warn("%s", name); 722196712Strasz return; 723106371Stjr } 724196712Strasz if (acl_is_trivial_np(facl, &trivial)) { 725106371Stjr acl_free(facl); 726284198Smarcel xo_warn("%s", name); 727196712Strasz return; 728196712Strasz } 729196712Strasz if (!trivial) 730196712Strasz buf[10] = '+'; 731196712Strasz acl_free(facl); 732106371Stjr} 733