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: stable/11/bin/ls/print.c 314129 2017-02-23 07:42:49Z kib $"); 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> 50291959Sbapt#include <limits.h> 511556Srgrimes#include <stdio.h> 52225847Sed#include <stdint.h> 531556Srgrimes#include <stdlib.h> 541556Srgrimes#include <string.h> 5591212Sbde#include <time.h> 561556Srgrimes#include <unistd.h> 57291959Sbapt#include <wchar.h> 5861294Sache#ifdef COLORLS 5961294Sache#include <ctype.h> 6061294Sache#include <termcap.h> 6161294Sache#include <signal.h> 6261294Sache#endif 63284198Smarcel#include <libxo/xo.h> 641556Srgrimes 651556Srgrimes#include "ls.h" 661556Srgrimes#include "extern.h" 671556Srgrimes 68114583Smarkmstatic int printaname(const FTSENT *, u_long, u_long); 69202945Sjhstatic void printdev(size_t, dev_t); 70105780Smarkmstatic void printlink(const FTSENT *); 71284198Smarcelstatic void printtime(const char *, time_t); 7290110Simpstatic int printtype(u_int); 73284198Smarcelstatic void printsize(const char *, size_t, off_t); 7461321Sache#ifdef COLORLS 7590110Simpstatic void endcolor(int); 7690110Simpstatic int colortype(mode_t); 7761321Sache#endif 78196712Straszstatic void aclmode(char *, const FTSENT *); 791556Srgrimes 801556Srgrimes#define IS_NOPRINT(p) ((p)->fts_number == NO_PRINT) 811556Srgrimes 8261268Sjoe#ifdef COLORLS 8361178Sjoe/* Most of these are taken from <sys/stat.h> */ 8461178Sjoetypedef enum Colors { 8588602Sjoe C_DIR, /* directory */ 8688602Sjoe C_LNK, /* symbolic link */ 8788602Sjoe C_SOCK, /* socket */ 8888602Sjoe C_FIFO, /* pipe */ 8988602Sjoe C_EXEC, /* executable */ 9088602Sjoe C_BLK, /* block special */ 9188602Sjoe C_CHR, /* character special */ 9288602Sjoe C_SUID, /* setuid executable */ 9388602Sjoe C_SGID, /* setgid executable */ 9488602Sjoe C_WSDIR, /* directory writeble to others, with sticky 9588602Sjoe * bit */ 9688602Sjoe C_WDIR, /* directory writeble to others, without 9788602Sjoe * sticky bit */ 9888602Sjoe C_NUMCOLORS /* just a place-holder */ 9988586Sjoe} Colors; 10061178Sjoe 10190150Smarkmstatic const char *defcolors = "exfxcxdxbxegedabagacad"; 10261178Sjoe 10388583Sjoe/* colors for file types */ 10488583Sjoestatic struct { 10588586Sjoe int num[2]; 10688586Sjoe int bold; 10788583Sjoe} colors[C_NUMCOLORS]; 10861268Sjoe#endif 10961178Sjoe 110291959Sbaptstatic size_t padding_for_month[12]; 111291959Sbaptstatic size_t month_max_size = 0; 112291959Sbapt 1131556Srgrimesvoid 114114583Smarkmprintscol(const DISPLAY *dp) 1151556Srgrimes{ 11688594Sjoe FTSENT *p; 1171556Srgrimes 118284198Smarcel xo_open_list("entry"); 1191556Srgrimes for (p = dp->list; p; p = p->fts_link) { 1201556Srgrimes if (IS_NOPRINT(p)) 1211556Srgrimes continue; 122284198Smarcel xo_open_instance("entry"); 1231556Srgrimes (void)printaname(p, dp->s_inode, dp->s_block); 124284198Smarcel xo_close_instance("entry"); 125284198Smarcel xo_emit("\n"); 1261556Srgrimes } 127284198Smarcel xo_close_list("entry"); 1281556Srgrimes} 1291556Srgrimes 13062597Sassar/* 13162597Sassar * print name in current style 13262597Sassar */ 133105390Stjrint 134284198Smarcelprintname(const char *field, const char *name) 13562597Sassar{ 136284198Smarcel char fmt[BUFSIZ]; 137284198Smarcel char *s = getname(name); 138284198Smarcel int rc; 139284198Smarcel 140284198Smarcel snprintf(fmt, sizeof(fmt), "{:%s/%%hs}", field); 141284198Smarcel rc = xo_emit(fmt, s); 142284198Smarcel free(s); 143284198Smarcel return rc; 144284198Smarcel} 145284198Smarcel 146291959Sbaptstatic const char * 147291959Sbaptget_abmon(int mon) 148291959Sbapt{ 149291959Sbapt 150291959Sbapt switch (mon) { 151291959Sbapt case 0: return (nl_langinfo(ABMON_1)); 152291959Sbapt case 1: return (nl_langinfo(ABMON_2)); 153291959Sbapt case 2: return (nl_langinfo(ABMON_3)); 154291959Sbapt case 3: return (nl_langinfo(ABMON_4)); 155291959Sbapt case 4: return (nl_langinfo(ABMON_5)); 156291959Sbapt case 5: return (nl_langinfo(ABMON_6)); 157291959Sbapt case 6: return (nl_langinfo(ABMON_7)); 158291959Sbapt case 7: return (nl_langinfo(ABMON_8)); 159291959Sbapt case 8: return (nl_langinfo(ABMON_9)); 160291959Sbapt case 9: return (nl_langinfo(ABMON_10)); 161291959Sbapt case 10: return (nl_langinfo(ABMON_11)); 162291959Sbapt case 11: return (nl_langinfo(ABMON_12)); 163291959Sbapt } 164291959Sbapt 165291959Sbapt /* should never happen */ 166291959Sbapt abort(); 167291959Sbapt} 168291959Sbapt 169291959Sbaptstatic size_t 170291959Sbaptmbswidth(const char *month) 171291959Sbapt{ 172291959Sbapt wchar_t wc; 173291959Sbapt size_t width, donelen, clen, w; 174291959Sbapt 175291959Sbapt width = donelen = 0; 176291959Sbapt while ((clen = mbrtowc(&wc, month + donelen, MB_LEN_MAX, NULL)) != 0) { 177291959Sbapt if (clen == (size_t)-1 || clen == (size_t)-2) 178291959Sbapt return (-1); 179291959Sbapt donelen += clen; 180291959Sbapt if ((w = wcwidth(wc)) == (size_t)-1) 181291959Sbapt return (-1); 182291959Sbapt width += w; 183291959Sbapt } 184291959Sbapt 185291959Sbapt return (width); 186291959Sbapt} 187291959Sbapt 188291959Sbaptstatic void 189291959Sbaptcompute_abbreviated_month_size(void) 190291959Sbapt{ 191291959Sbapt int i; 192291959Sbapt size_t width; 193291959Sbapt size_t months_width[12]; 194291959Sbapt 195291959Sbapt for (i = 0; i < 12; i++) { 196291959Sbapt width = mbswidth(get_abmon(i)); 197291959Sbapt if (width == (size_t)-1) { 198291959Sbapt month_max_size = -1; 199291959Sbapt return; 200291959Sbapt } 201291959Sbapt months_width[i] = width; 202291959Sbapt if (width > month_max_size) 203291959Sbapt month_max_size = width; 204291959Sbapt } 205291959Sbapt 206291959Sbapt for (i = 0; i < 12; i++) 207291959Sbapt padding_for_month[i] = month_max_size - months_width[i]; 208291959Sbapt} 209291959Sbapt 210284198Smarcel/* 211284198Smarcel * print name in current style 212284198Smarcel */ 213284198Smarcelchar * 214284198Smarcelgetname(const char *name) 215284198Smarcel{ 21662597Sassar if (f_octal || f_octal_escape) 217284198Smarcel return get_octal(name); 21862597Sassar else if (f_nonprint) 219284198Smarcel return get_printable(name); 22062597Sassar else 221284198Smarcel return strdup(name); 22262597Sassar} 22362597Sassar 2241556Srgrimesvoid 225114583Smarkmprintlong(const DISPLAY *dp) 2261556Srgrimes{ 2271556Srgrimes struct stat *sp; 22888594Sjoe FTSENT *p; 22988594Sjoe NAMES *np; 23088594Sjoe char buf[20]; 23161292Sache#ifdef COLORLS 23288594Sjoe int color_printed = 0; 23361292Sache#endif 2341556Srgrimes 235130236Sdas if ((dp->list == NULL || dp->list->fts_level != FTS_ROOTLEVEL) && 236130236Sdas (f_longform || f_size)) { 237284198Smarcel xo_emit("{L:total} {:total-blocks/%lu}\n", 238284198Smarcel howmany(dp->btotal, blocksize)); 239130236Sdas } 2401556Srgrimes 241284198Smarcel xo_open_list("entry"); 2421556Srgrimes for (p = dp->list; p; p = p->fts_link) { 243285734Sallanjude char *name, *type; 2441556Srgrimes if (IS_NOPRINT(p)) 2451556Srgrimes continue; 246284198Smarcel xo_open_instance("entry"); 2471556Srgrimes sp = p->fts_statp; 248284198Smarcel name = getname(p->fts_name); 249284198Smarcel if (name) 250284494Skan xo_emit("{ke:name/%hs}", name); 2511556Srgrimes if (f_inode) 252285734Sallanjude xo_emit("{t:inode/%*ju} ", 253241014Smdf dp->s_inode, (uintmax_t)sp->st_ino); 2541556Srgrimes if (f_size) 255285734Sallanjude xo_emit("{t:blocks/%*jd} ", 2561556Srgrimes dp->s_block, howmany(sp->st_blocks, blocksize)); 25790150Smarkm strmode(sp->st_mode, buf); 258196712Strasz aclmode(buf, p); 2591556Srgrimes np = p->fts_pointer; 260284198Smarcel xo_attr("value", "%03o", (int) sp->st_mode & ALLPERMS); 261285734Sallanjude if (f_numericonly) { 262314129Skib xo_emit("{t:mode/%s}{e:mode_octal/%03o} {t:links/%*ju} {td:user/%-*s}{e:user/%ju} {td:group/%-*s}{e:group/%ju} ", 263314129Skib buf, (int) sp->st_mode & ALLPERMS, dp->s_nlink, (uintmax_t)sp->st_nlink, 264285857Sallanjude dp->s_user, np->user, (uintmax_t)sp->st_uid, dp->s_group, np->group, (uintmax_t)sp->st_gid); 265285734Sallanjude } else { 266314129Skib xo_emit("{t:mode/%s}{e:mode_octal/%03o} {t:links/%*ju} {t:user/%-*s} {t:group/%-*s} ", 267314129Skib buf, (int) sp->st_mode & ALLPERMS, dp->s_nlink, (uintmax_t)sp->st_nlink, 268285734Sallanjude dp->s_user, np->user, dp->s_group, np->group); 269285734Sallanjude } 270285734Sallanjude if (S_ISBLK(sp->st_mode)) 271285734Sallanjude asprintf(&type, "block"); 272285734Sallanjude if (S_ISCHR(sp->st_mode)) 273285734Sallanjude asprintf(&type, "character"); 274285734Sallanjude if (S_ISDIR(sp->st_mode)) 275285734Sallanjude asprintf(&type, "directory"); 276285734Sallanjude if (S_ISFIFO(sp->st_mode)) 277285734Sallanjude asprintf(&type, "fifo"); 278285734Sallanjude if (S_ISLNK(sp->st_mode)) 279285734Sallanjude asprintf(&type, "symlink"); 280285734Sallanjude if (S_ISREG(sp->st_mode)) 281285734Sallanjude asprintf(&type, "regular"); 282285734Sallanjude if (S_ISSOCK(sp->st_mode)) 283285734Sallanjude asprintf(&type, "socket"); 284285734Sallanjude if (S_ISWHT(sp->st_mode)) 285285734Sallanjude asprintf(&type, "whiteout"); 286285734Sallanjude xo_emit("{e:type/%s}", type); 287285734Sallanjude free(type); 2881556Srgrimes if (f_flags) 289284198Smarcel xo_emit("{:flags/%-*s} ", dp->s_flags, np->flags); 290105832Srwatson if (f_label) 291285734Sallanjude xo_emit("{t:label/%-*s} ", dp->s_label, np->label); 2921556Srgrimes if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode)) 293202945Sjh printdev(dp->s_size, sp->st_rdev); 2941556Srgrimes else 295284198Smarcel printsize("size", dp->s_size, sp->st_size); 2961556Srgrimes if (f_accesstime) 297284198Smarcel printtime("access-time", sp->st_atime); 298157098Sjhb else if (f_birthtime) 299284198Smarcel printtime("birth-time", sp->st_birthtime); 3001556Srgrimes else if (f_statustime) 301284198Smarcel printtime("change-time", sp->st_ctime); 3021556Srgrimes else 303284198Smarcel printtime("modify-time", sp->st_mtime); 30461268Sjoe#ifdef COLORLS 30561178Sjoe if (f_color) 30661291Sache color_printed = colortype(sp->st_mode); 30761268Sjoe#endif 308284198Smarcel 309284198Smarcel if (name) { 310284494Skan xo_emit("{dk:name/%hs}", name); 311284198Smarcel free(name); 312284198Smarcel } 313284198Smarcel 31461268Sjoe#ifdef COLORLS 31561291Sache if (f_color && color_printed) 31661321Sache endcolor(0); 31761268Sjoe#endif 3181556Srgrimes if (f_type) 3191556Srgrimes (void)printtype(sp->st_mode); 3201556Srgrimes if (S_ISLNK(sp->st_mode)) 3211556Srgrimes printlink(p); 322284198Smarcel xo_close_instance("entry"); 323284198Smarcel xo_emit("\n"); 3241556Srgrimes } 325284198Smarcel xo_close_list("entry"); 3261556Srgrimes} 3271556Srgrimes 3281556Srgrimesvoid 329114583Smarkmprintstream(const DISPLAY *dp) 33096892Stjr{ 33196892Stjr FTSENT *p; 33296892Stjr int chcnt; 33396892Stjr 334285734Sallanjude xo_open_list("entry"); 33596892Stjr for (p = dp->list, chcnt = 0; p; p = p->fts_link) { 33696892Stjr if (p->fts_number == NO_PRINT) 33796892Stjr continue; 338128823Stjr /* XXX strlen does not take octal escapes into account. */ 33996892Stjr if (strlen(p->fts_name) + chcnt + 34096892Stjr (p->fts_link ? 2 : 0) >= (unsigned)termwidth) { 341284198Smarcel xo_emit("\n"); 34296892Stjr chcnt = 0; 34396892Stjr } 344285734Sallanjude xo_open_instance("file"); 34596892Stjr chcnt += printaname(p, dp->s_inode, dp->s_block); 346285734Sallanjude xo_close_instance("file"); 34796892Stjr if (p->fts_link) { 348284198Smarcel xo_emit(", "); 34996892Stjr chcnt += 2; 35096892Stjr } 35196892Stjr } 352285734Sallanjude xo_close_list("entry"); 35396892Stjr if (chcnt) 354284198Smarcel xo_emit("\n"); 35596892Stjr} 356177907Sgrog 35796892Stjrvoid 358114583Smarkmprintcol(const DISPLAY *dp) 3591556Srgrimes{ 3601556Srgrimes static FTSENT **array; 3611556Srgrimes static int lastentries = -1; 36288594Sjoe FTSENT *p; 363121124Stjr FTSENT **narray; 36488594Sjoe int base; 36588594Sjoe int chcnt; 36688594Sjoe int cnt; 36788594Sjoe int col; 36888594Sjoe int colwidth; 36988594Sjoe int endcol; 37088594Sjoe int num; 37188594Sjoe int numcols; 37288594Sjoe int numrows; 37388594Sjoe int row; 37488594Sjoe int tabwidth; 3751556Srgrimes 37637932Shoek if (f_notabs) 37737932Shoek tabwidth = 1; 37837932Shoek else 37937932Shoek tabwidth = 8; 38037932Shoek 3811556Srgrimes /* 3821556Srgrimes * Have to do random access in the linked list -- build a table 3831556Srgrimes * of pointers. 3841556Srgrimes */ 3851556Srgrimes if (dp->entries > lastentries) { 386121124Stjr if ((narray = 3871556Srgrimes realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) { 3881556Srgrimes printscol(dp); 389121124Stjr return; 3901556Srgrimes } 391121124Stjr lastentries = dp->entries; 392121124Stjr array = narray; 3931556Srgrimes } 3941556Srgrimes for (p = dp->list, num = 0; p; p = p->fts_link) 3951556Srgrimes if (p->fts_number != NO_PRINT) 3961556Srgrimes array[num++] = p; 3971556Srgrimes 3981556Srgrimes colwidth = dp->maxlen; 3991556Srgrimes if (f_inode) 4001556Srgrimes colwidth += dp->s_inode + 1; 4011556Srgrimes if (f_size) 4021556Srgrimes colwidth += dp->s_block + 1; 4031556Srgrimes if (f_type) 4041556Srgrimes colwidth += 1; 4051556Srgrimes 40637932Shoek colwidth = (colwidth + tabwidth) & ~(tabwidth - 1); 4071556Srgrimes if (termwidth < 2 * colwidth) { 4081556Srgrimes printscol(dp); 4091556Srgrimes return; 4101556Srgrimes } 4111556Srgrimes numcols = termwidth / colwidth; 4121556Srgrimes numrows = num / numcols; 4131556Srgrimes if (num % numcols) 4141556Srgrimes ++numrows; 4151556Srgrimes 416130236Sdas if ((dp->list == NULL || dp->list->fts_level != FTS_ROOTLEVEL) && 417130236Sdas (f_longform || f_size)) { 418284198Smarcel xo_emit("{L:total} {:total-blocks/%lu}\n", 419284198Smarcel howmany(dp->btotal, blocksize)); 420130236Sdas } 42196892Stjr 422284198Smarcel xo_open_list("entry"); 423102577Skeramida base = 0; 4241556Srgrimes for (row = 0; row < numrows; ++row) { 4251556Srgrimes endcol = colwidth; 42696892Stjr if (!f_sortacross) 42796892Stjr base = row; 42896892Stjr for (col = 0, chcnt = 0; col < numcols; ++col) { 429284198Smarcel xo_open_instance("entry"); 4301556Srgrimes chcnt += printaname(array[base], dp->s_inode, 4311556Srgrimes dp->s_block); 432284198Smarcel xo_close_instance("entry"); 43396892Stjr if (f_sortacross) 43496892Stjr base++; 43596892Stjr else 43696892Stjr base += numrows; 43796892Stjr if (base >= num) 4381556Srgrimes break; 43937932Shoek while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1))) 44088595Sjoe <= endcol) { 44196892Stjr if (f_sortacross && col + 1 >= numcols) 44296892Stjr break; 443284198Smarcel xo_emit(f_notabs ? " " : "\t"); 4441556Srgrimes chcnt = cnt; 4451556Srgrimes } 4461556Srgrimes endcol += colwidth; 4471556Srgrimes } 448284198Smarcel xo_emit("\n"); 4491556Srgrimes } 450284198Smarcel xo_close_list("entry"); 4511556Srgrimes} 4521556Srgrimes 4531556Srgrimes/* 4541556Srgrimes * print [inode] [size] name 4551556Srgrimes * return # of characters printed, no trailing characters. 4561556Srgrimes */ 4571556Srgrimesstatic int 458114583Smarkmprintaname(const FTSENT *p, u_long inodefield, u_long sizefield) 4591556Srgrimes{ 4601556Srgrimes struct stat *sp; 46188594Sjoe int chcnt; 46261292Sache#ifdef COLORLS 46388594Sjoe int color_printed = 0; 46461292Sache#endif 4651556Srgrimes 4661556Srgrimes sp = p->fts_statp; 4671556Srgrimes chcnt = 0; 4681556Srgrimes if (f_inode) 469285734Sallanjude chcnt += xo_emit("{t:inode/%*ju} ", 470241014Smdf (int)inodefield, (uintmax_t)sp->st_ino); 4711556Srgrimes if (f_size) 472285734Sallanjude chcnt += xo_emit("{t:size/%*jd} ", 4731556Srgrimes (int)sizefield, howmany(sp->st_blocks, blocksize)); 47461268Sjoe#ifdef COLORLS 47561178Sjoe if (f_color) 47661291Sache color_printed = colortype(sp->st_mode); 47761268Sjoe#endif 478284198Smarcel chcnt += printname("name", p->fts_name); 47961268Sjoe#ifdef COLORLS 48061291Sache if (f_color && color_printed) 48161321Sache endcolor(0); 48261268Sjoe#endif 4831556Srgrimes if (f_type) 4841556Srgrimes chcnt += printtype(sp->st_mode); 4851556Srgrimes return (chcnt); 4861556Srgrimes} 4871556Srgrimes 488202945Sjh/* 489202945Sjh * Print device special file major and minor numbers. 490202945Sjh */ 4911556Srgrimesstatic void 492202945Sjhprintdev(size_t width, dev_t dev) 493202945Sjh{ 494284198Smarcel xo_emit("{:device/%#*jx} ", (u_int)width, (uintmax_t)dev); 495202945Sjh} 496202945Sjh 497291959Sbaptstatic size_t 498291959Sbaptls_strftime(char *str, size_t len, const char *fmt, const struct tm *tm) 499291959Sbapt{ 500291959Sbapt char *posb, nfmt[BUFSIZ]; 501291959Sbapt const char *format = fmt; 502291959Sbapt size_t ret; 503291959Sbapt 504291959Sbapt if ((posb = strstr(fmt, "%b")) != NULL) { 505291959Sbapt if (month_max_size == 0) { 506291959Sbapt compute_abbreviated_month_size(); 507291959Sbapt } 508291959Sbapt if (month_max_size > 0) { 509291959Sbapt snprintf(nfmt, sizeof(nfmt), "%.*s%s%*s%s", 510291959Sbapt (int)(posb - fmt), fmt, 511291959Sbapt get_abmon(tm->tm_mon), 512291959Sbapt (int)padding_for_month[tm->tm_mon], 513291959Sbapt "", 514291959Sbapt posb + 2); 515291959Sbapt format = nfmt; 516291959Sbapt } 517291959Sbapt } 518291959Sbapt ret = strftime(str, len, format, tm); 519291959Sbapt return (ret); 520291959Sbapt} 521291959Sbapt 522202945Sjhstatic void 523284198Smarcelprinttime(const char *field, time_t ftime) 5241556Srgrimes{ 52588594Sjoe char longstring[80]; 526284198Smarcel char fmt[BUFSIZ]; 527114583Smarkm static time_t now = 0; 52888594Sjoe const char *format; 52988594Sjoe static int d_first = -1; 5301556Srgrimes 53174566Sache if (d_first < 0) 53274566Sache d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 53321545Smpp if (now == 0) 53421545Smpp now = time(NULL); 53521545Smpp 5369987Swollman#define SIXMONTHS ((365 / 2) * 86400) 537177907Sgrog if (f_timeformat) /* user specified format */ 538177907Sgrog format = f_timeformat; 539177907Sgrog else if (f_sectime) 54061920Sjoe /* mmm dd hh:mm:ss yyyy || dd mmm hh:mm:ss yyyy */ 541177907Sgrog format = d_first ? "%e %b %T %Y" : "%b %e %T %Y"; 54221545Smpp else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS) 54361920Sjoe /* mmm dd hh:mm || dd mmm hh:mm */ 544177907Sgrog format = d_first ? "%e %b %R" : "%b %e %R"; 54561814Sjoe else 54661920Sjoe /* mmm dd yyyy || dd mmm yyyy */ 547242840Speter format = d_first ? "%e %b %Y" : "%b %e %Y"; 548291959Sbapt ls_strftime(longstring, sizeof(longstring), format, localtime(&ftime)); 549284198Smarcel 550285734Sallanjude snprintf(fmt, sizeof(fmt), "{d:%s/%%hs} ", field); 551284198Smarcel xo_attr("value", "%ld", (long) ftime); 552284198Smarcel xo_emit(fmt, longstring); 553285803Sallanjude snprintf(fmt, sizeof(fmt), "{en:%s/%%ld}", field); 554285734Sallanjude xo_emit(fmt, (long) ftime); 5551556Srgrimes} 5561556Srgrimes 5571556Srgrimesstatic int 55890110Simpprinttype(u_int mode) 5591556Srgrimes{ 56096892Stjr 56196892Stjr if (f_slash) { 56296892Stjr if ((mode & S_IFMT) == S_IFDIR) { 563284198Smarcel xo_emit("{D:\\/}{e:type/directory}"); 56496892Stjr return (1); 56596892Stjr } 56696892Stjr return (0); 56796892Stjr } 56896892Stjr 5691556Srgrimes switch (mode & S_IFMT) { 5701556Srgrimes case S_IFDIR: 571284198Smarcel xo_emit("{D:/\\/}{e:type/directory}"); 5721556Srgrimes return (1); 5731556Srgrimes case S_IFIFO: 574284198Smarcel xo_emit("{D:|}{e:type/fifo}"); 5751556Srgrimes return (1); 5761556Srgrimes case S_IFLNK: 577284198Smarcel xo_emit("{D:@}{e:type/link}"); 5781556Srgrimes return (1); 5791556Srgrimes case S_IFSOCK: 580284198Smarcel xo_emit("{D:=}{e:type/socket}"); 5811556Srgrimes return (1); 58220417Ssteve case S_IFWHT: 583285857Sallanjude xo_emit("{D:%%}{e:type/whiteout}"); 58420417Ssteve return (1); 58590150Smarkm default: 58696681Sbillf break; 5871556Srgrimes } 5881556Srgrimes if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 589284198Smarcel xo_emit("{D:*}{e:executable/}"); 5901556Srgrimes return (1); 5911556Srgrimes } 5921556Srgrimes return (0); 5931556Srgrimes} 5941556Srgrimes 59561268Sjoe#ifdef COLORLS 59661323Sachestatic int 59790110Simpputch(int c) 59861291Sache{ 599284198Smarcel xo_emit("{D:/%c}", c); 60061321Sache return 0; 60161291Sache} 60261291Sache 60361323Sachestatic int 60490110Simpwritech(int c) 60561321Sache{ 606114583Smarkm char tmp = (char)c; 60761291Sache 60888602Sjoe (void)write(STDOUT_FILENO, &tmp, 1); 60961321Sache return 0; 61061321Sache} 61161321Sache 61261323Sachestatic void 61390110Simpprintcolor(Colors c) 61461178Sjoe{ 61588594Sjoe char *ansiseq; 61661268Sjoe 61788583Sjoe if (colors[c].bold) 61888583Sjoe tputs(enter_bold, 1, putch); 61988583Sjoe 62088583Sjoe if (colors[c].num[0] != -1) { 62188583Sjoe ansiseq = tgoto(ansi_fgcol, 0, colors[c].num[0]); 62261321Sache if (ansiseq) 62361291Sache tputs(ansiseq, 1, putch); 62461178Sjoe } 62588583Sjoe if (colors[c].num[1] != -1) { 62688583Sjoe ansiseq = tgoto(ansi_bgcol, 0, colors[c].num[1]); 62761321Sache if (ansiseq) 62861291Sache tputs(ansiseq, 1, putch); 62961268Sjoe } 63061178Sjoe} 63161178Sjoe 63261321Sachestatic void 63390110Simpendcolor(int sig) 63461268Sjoe{ 63561321Sache tputs(ansi_coloff, 1, sig ? writech : putch); 63688583Sjoe tputs(attrs_off, 1, sig ? writech : putch); 63761268Sjoe} 63861268Sjoe 63961321Sachestatic int 64090110Simpcolortype(mode_t mode) 64161178Sjoe{ 64288602Sjoe switch (mode & S_IFMT) { 64388595Sjoe case S_IFDIR: 64461178Sjoe if (mode & S_IWOTH) 64588595Sjoe if (mode & S_ISTXT) 64688595Sjoe printcolor(C_WSDIR); 64788595Sjoe else 64888595Sjoe printcolor(C_WDIR); 64961178Sjoe else 65088595Sjoe printcolor(C_DIR); 65188602Sjoe return (1); 65288595Sjoe case S_IFLNK: 65361178Sjoe printcolor(C_LNK); 65488602Sjoe return (1); 65588595Sjoe case S_IFSOCK: 65661178Sjoe printcolor(C_SOCK); 65788602Sjoe return (1); 65888595Sjoe case S_IFIFO: 65961178Sjoe printcolor(C_FIFO); 66088602Sjoe return (1); 66188595Sjoe case S_IFBLK: 66261178Sjoe printcolor(C_BLK); 66388602Sjoe return (1); 66488595Sjoe case S_IFCHR: 66561178Sjoe printcolor(C_CHR); 66688602Sjoe return (1); 667114583Smarkm default:; 66861178Sjoe } 66961178Sjoe if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 67061178Sjoe if (mode & S_ISUID) 67188595Sjoe printcolor(C_SUID); 67261178Sjoe else if (mode & S_ISGID) 67388595Sjoe printcolor(C_SGID); 67461178Sjoe else 67588595Sjoe printcolor(C_EXEC); 67688602Sjoe return (1); 67761178Sjoe } 67888602Sjoe return (0); 67961178Sjoe} 68061178Sjoe 68161178Sjoevoid 68290110Simpparsecolors(const char *cs) 68361178Sjoe{ 68488594Sjoe int i; 68588594Sjoe int j; 686105780Smarkm size_t len; 68788594Sjoe char c[2]; 68888594Sjoe short legacy_warn = 0; 68961321Sache 69088586Sjoe if (cs == NULL) 69188602Sjoe cs = ""; /* LSCOLORS not set */ 69261178Sjoe len = strlen(cs); 693114583Smarkm for (i = 0; i < (int)C_NUMCOLORS; i++) { 69488583Sjoe colors[i].bold = 0; 69588583Sjoe 696114583Smarkm if (len <= 2 * (size_t)i) { 69788586Sjoe c[0] = defcolors[2 * i]; 69888586Sjoe c[1] = defcolors[2 * i + 1]; 69988602Sjoe } else { 70088586Sjoe c[0] = cs[2 * i]; 70188586Sjoe c[1] = cs[2 * i + 1]; 70261178Sjoe } 70388602Sjoe for (j = 0; j < 2; j++) { 70488583Sjoe /* Legacy colours used 0-7 */ 70588583Sjoe if (c[j] >= '0' && c[j] <= '7') { 70688583Sjoe colors[i].num[j] = c[j] - '0'; 70788583Sjoe if (!legacy_warn) { 708284198Smarcel xo_warnx("LSCOLORS should use " 70988588Sjoe "characters a-h instead of 0-9 (" 710106479Stjr "see the manual page)"); 71188583Sjoe } 71288583Sjoe legacy_warn = 1; 71388583Sjoe } else if (c[j] >= 'a' && c[j] <= 'h') 71488583Sjoe colors[i].num[j] = c[j] - 'a'; 71588583Sjoe else if (c[j] >= 'A' && c[j] <= 'H') { 71688583Sjoe colors[i].num[j] = c[j] - 'A'; 71788583Sjoe colors[i].bold = 1; 718114583Smarkm } else if (tolower((unsigned char)c[j]) == 'x') 71988583Sjoe colors[i].num[j] = -1; 72088583Sjoe else { 721284198Smarcel xo_warnx("invalid character '%c' in LSCOLORS" 722106479Stjr " env var", c[j]); 72388584Sjoe colors[i].num[j] = -1; 72461178Sjoe } 72561178Sjoe } 72661178Sjoe } 72761178Sjoe} 72861291Sache 72961323Sachevoid 73090110Simpcolorquit(int sig) 73161291Sache{ 73261321Sache endcolor(sig); 73361294Sache 73488602Sjoe (void)signal(sig, SIG_DFL); 73588602Sjoe (void)kill(getpid(), sig); 73661291Sache} 73788602Sjoe 73888602Sjoe#endif /* COLORLS */ 73988602Sjoe 7401556Srgrimesstatic void 741105780Smarkmprintlink(const FTSENT *p) 7421556Srgrimes{ 74388594Sjoe int lnklen; 74488594Sjoe char name[MAXPATHLEN + 1]; 74588594Sjoe char path[MAXPATHLEN + 1]; 7461556Srgrimes 7471556Srgrimes if (p->fts_level == FTS_ROOTLEVEL) 7481556Srgrimes (void)snprintf(name, sizeof(name), "%s", p->fts_name); 7498855Srgrimes else 7501556Srgrimes (void)snprintf(name, sizeof(name), 7511556Srgrimes "%s/%s", p->fts_parent->fts_accpath, p->fts_name); 7521556Srgrimes if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) { 753284198Smarcel xo_error("\nls: %s: %s\n", name, strerror(errno)); 7541556Srgrimes return; 7551556Srgrimes } 7561556Srgrimes path[lnklen] = '\0'; 757284198Smarcel xo_emit(" -> "); 758284198Smarcel (void)printname("target", path); 7591556Srgrimes} 76088591Sjoe 76188591Sjoestatic void 762284198Smarcelprintsize(const char *field, size_t width, off_t bytes) 76388591Sjoe{ 764284198Smarcel char fmt[BUFSIZ]; 765284198Smarcel 76688591Sjoe if (f_humanval) { 767202945Sjh /* 768202945Sjh * Reserve one space before the size and allocate room for 769202945Sjh * the trailing '\0'. 770202945Sjh */ 771202945Sjh char buf[HUMANVALSTR_LEN - 1 + 1]; 77288591Sjoe 773129719Spjd humanize_number(buf, sizeof(buf), (int64_t)bytes, "", 774129719Spjd HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 775284198Smarcel snprintf(fmt, sizeof(fmt), "{:%s/%%%ds} ", field, (int) width); 776284198Smarcel xo_attr("value", "%jd", (intmax_t) bytes); 777284198Smarcel xo_emit(fmt, buf); 778284198Smarcel } else { /* with commas */ 779242725Sgrog /* This format assignment needed to work round gcc bug. */ 780284198Smarcel snprintf(fmt, sizeof(fmt), "{:%s/%%%dj%sd} ", 781284198Smarcel field, (int) width, f_thousands ? "'" : ""); 782284198Smarcel xo_emit(fmt, (intmax_t) bytes); 783284198Smarcel } 78488591Sjoe} 78588591Sjoe 786196712Strasz/* 787196712Strasz * Add a + after the standard rwxrwxrwx mode if the file has an 788196712Strasz * ACL. strmode() reserves space at the end of the string. 789196712Strasz */ 790106371Stjrstatic void 791196712Straszaclmode(char *buf, const FTSENT *p) 792106371Stjr{ 793106371Stjr char name[MAXPATHLEN + 1]; 794196712Strasz int ret, trivial; 795196712Strasz static dev_t previous_dev = NODEV; 796196712Strasz static int supports_acls = -1; 797196712Strasz static int type = ACL_TYPE_ACCESS; 798106371Stjr acl_t facl; 799106371Stjr 800106371Stjr /* 801196712Strasz * XXX: ACLs are not supported on whiteouts and device files 802196712Strasz * residing on UFS. 803106371Stjr */ 804196712Strasz if (S_ISCHR(p->fts_statp->st_mode) || S_ISBLK(p->fts_statp->st_mode) || 805196712Strasz S_ISWHT(p->fts_statp->st_mode)) 806108066Stjr return; 807196712Strasz 808196773Strasz if (previous_dev == p->fts_statp->st_dev && supports_acls == 0) 809196773Strasz return; 810196773Strasz 811196773Strasz if (p->fts_level == FTS_ROOTLEVEL) 812196773Strasz snprintf(name, sizeof(name), "%s", p->fts_name); 813196773Strasz else 814196773Strasz snprintf(name, sizeof(name), "%s/%s", 815196773Strasz p->fts_parent->fts_accpath, p->fts_name); 816196773Strasz 817196712Strasz if (previous_dev != p->fts_statp->st_dev) { 818196712Strasz previous_dev = p->fts_statp->st_dev; 819196712Strasz supports_acls = 0; 820196712Strasz 821196712Strasz ret = lpathconf(name, _PC_ACL_NFS4); 822196712Strasz if (ret > 0) { 823196712Strasz type = ACL_TYPE_NFS4; 824196712Strasz supports_acls = 1; 825196712Strasz } else if (ret < 0 && errno != EINVAL) { 826284198Smarcel xo_warn("%s", name); 827196712Strasz return; 828196712Strasz } 829196712Strasz if (supports_acls == 0) { 830196712Strasz ret = lpathconf(name, _PC_ACL_EXTENDED); 831196712Strasz if (ret > 0) { 832196712Strasz type = ACL_TYPE_ACCESS; 833196712Strasz supports_acls = 1; 834196712Strasz } else if (ret < 0 && errno != EINVAL) { 835284198Smarcel xo_warn("%s", name); 836196712Strasz return; 837196712Strasz } 838196712Strasz } 839108066Stjr } 840196712Strasz if (supports_acls == 0) 841106371Stjr return; 842196712Strasz facl = acl_get_link_np(name, type); 843196712Strasz if (facl == NULL) { 844284198Smarcel xo_warn("%s", name); 845196712Strasz return; 846106371Stjr } 847196712Strasz if (acl_is_trivial_np(facl, &trivial)) { 848106371Stjr acl_free(facl); 849284198Smarcel xo_warn("%s", name); 850196712Strasz return; 851196712Strasz } 852196712Strasz if (!trivial) 853196712Strasz buf[10] = '+'; 854196712Strasz acl_free(facl); 855106371Stjr} 856