print.c revision 130236
1321369Sdim/* 2303231Sdim * Copyright (c) 1989, 1993, 1994 3353358Sdim * The Regents of the University of California. All rights reserved. 4353358Sdim * 5353358Sdim * This code is derived from software contributed to Berkeley by 6303231Sdim * Michael Fischbein. 7303231Sdim * 8303231Sdim * Redistribution and use in source and binary forms, with or without 9303231Sdim * modification, are permitted provided that the following conditions 10303231Sdim * are met: 11303231Sdim * 1. Redistributions of source code must retain the above copyright 12303231Sdim * notice, this list of conditions and the following disclaimer. 13303231Sdim * 2. Redistributions in binary form must reproduce the above copyright 14303231Sdim * notice, this list of conditions and the following disclaimer in the 15303231Sdim * documentation and/or other materials provided with the distribution. 16344779Sdim * 4. Neither the name of the University nor the names of its contributors 17344779Sdim * may be used to endorse or promote products derived from this software 18314564Sdim * without specific prior written permission. 19303231Sdim * 20303231Sdim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21314564Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22314564Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23314564Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24303231Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25321369Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26303231Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27341825Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28303231Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29314564Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30314564Sdim * SUCH DAMAGE. 31314564Sdim */ 32314564Sdim 33314564Sdim#if 0 34314564Sdim#ifndef lint 35314564Sdimstatic char sccsid[] = "@(#)print.c 8.4 (Berkeley) 4/17/94"; 36314564Sdim#endif /* not lint */ 37314564Sdim#endif 38314564Sdim#include <sys/cdefs.h> 39314564Sdim__FBSDID("$FreeBSD: head/bin/ls/print.c 130236 2004-06-08 09:27:42Z das $"); 40303231Sdim 41303231Sdim#include <sys/param.h> 42303231Sdim#include <sys/stat.h> 43303231Sdim#include <sys/acl.h> 44314564Sdim 45303231Sdim#include <err.h> 46303231Sdim#include <errno.h> 47303231Sdim#include <fts.h> 48303231Sdim#include <langinfo.h> 49303231Sdim#include <libutil.h> 50314564Sdim#include <stdio.h> 51303231Sdim#include <stdlib.h> 52303231Sdim#include <string.h> 53303231Sdim#include <time.h> 54303231Sdim#include <unistd.h> 55303231Sdim#ifdef COLORLS 56303231Sdim#include <ctype.h> 57303231Sdim#include <termcap.h> 58303231Sdim#include <signal.h> 59303231Sdim#endif 60303231Sdim 61303231Sdim#include "ls.h" 62303231Sdim#include "extern.h" 63303231Sdim 64303231Sdimstatic int printaname(const FTSENT *, u_long, u_long); 65303231Sdimstatic void printlink(const FTSENT *); 66303231Sdimstatic void printtime(time_t); 67303231Sdimstatic int printtype(u_int); 68303231Sdimstatic void printsize(size_t, off_t); 69321369Sdim#ifdef COLORLS 70321369Sdimstatic void endcolor(int); 71321369Sdimstatic int colortype(mode_t); 72321369Sdim#endif 73321369Sdimstatic void aclmode(char *, const FTSENT *, int *); 74321369Sdim 75303231Sdim#define IS_NOPRINT(p) ((p)->fts_number == NO_PRINT) 76303231Sdim 77303231Sdim#ifdef COLORLS 78303231Sdim/* Most of these are taken from <sys/stat.h> */ 79303231Sdimtypedef enum Colors { 80303231Sdim C_DIR, /* directory */ 81303231Sdim C_LNK, /* symbolic link */ 82303231Sdim C_SOCK, /* socket */ 83303231Sdim C_FIFO, /* pipe */ 84303231Sdim C_EXEC, /* executable */ 85303231Sdim C_BLK, /* block special */ 86303231Sdim C_CHR, /* character special */ 87303231Sdim C_SUID, /* setuid executable */ 88314564Sdim C_SGID, /* setgid executable */ 89303231Sdim C_WSDIR, /* directory writeble to others, with sticky 90303231Sdim * bit */ 91303231Sdim C_WDIR, /* directory writeble to others, without 92303231Sdim * sticky bit */ 93303231Sdim C_NUMCOLORS /* just a place-holder */ 94303231Sdim} Colors; 95303231Sdim 96303231Sdimstatic const char *defcolors = "exfxcxdxbxegedabagacad"; 97303231Sdim 98303231Sdim/* colors for file types */ 99303231Sdimstatic struct { 100303231Sdim int num[2]; 101303231Sdim int bold; 102303231Sdim} colors[C_NUMCOLORS]; 103303231Sdim#endif 104303231Sdim 105303231Sdimvoid 106303231Sdimprintscol(const DISPLAY *dp) 107303231Sdim{ 108314564Sdim FTSENT *p; 109303231Sdim 110303231Sdim for (p = dp->list; p; p = p->fts_link) { 111303231Sdim if (IS_NOPRINT(p)) 112303231Sdim continue; 113303231Sdim (void)printaname(p, dp->s_inode, dp->s_block); 114303231Sdim (void)putchar('\n'); 115314564Sdim } 116303231Sdim} 117303231Sdim 118303231Sdim/* 119303231Sdim * print name in current style 120303231Sdim */ 121303231Sdimint 122303231Sdimprintname(const char *name) 123303231Sdim{ 124314564Sdim if (f_octal || f_octal_escape) 125303231Sdim return prn_octal(name); 126303231Sdim else if (f_nonprint) 127303231Sdim return prn_printable(name); 128303231Sdim else 129303231Sdim return prn_normal(name); 130303231Sdim} 131303231Sdim 132303231Sdimvoid 133303231Sdimprintlong(const DISPLAY *dp) 134303231Sdim{ 135303231Sdim struct stat *sp; 136303231Sdim FTSENT *p; 137303231Sdim NAMES *np; 138303231Sdim char buf[20]; 139303231Sdim#ifdef COLORLS 140303231Sdim int color_printed = 0; 141303231Sdim#endif 142303231Sdim int haveacls; 143303231Sdim dev_t prevdev; 144303231Sdim 145303231Sdim if ((dp->list == NULL || dp->list->fts_level != FTS_ROOTLEVEL) && 146303231Sdim (f_longform || f_size)) { 147314564Sdim (void)printf("total %lu\n", howmany(dp->btotal, blocksize)); 148303231Sdim } 149303231Sdim 150303231Sdim haveacls = 1; 151303231Sdim prevdev = (dev_t)-1; 152303231Sdim for (p = dp->list; p; p = p->fts_link) { 153303231Sdim if (IS_NOPRINT(p)) 154303231Sdim continue; 155303231Sdim sp = p->fts_statp; 156303231Sdim if (f_inode) 157314564Sdim (void)printf("%*lu ", dp->s_inode, (u_long)sp->st_ino); 158360784Sdim if (f_size) 159360784Sdim (void)printf("%*jd ", 160360784Sdim dp->s_block, howmany(sp->st_blocks, blocksize)); 161303231Sdim strmode(sp->st_mode, buf); 162303231Sdim /* 163303231Sdim * Cache whether or not the filesystem supports ACL's to 164303231Sdim * avoid expensive syscalls. Try again when we change devices. 165303231Sdim */ 166303231Sdim if (haveacls || sp->st_dev != prevdev) { 167303231Sdim aclmode(buf, p, &haveacls); 168303231Sdim prevdev = sp->st_dev; 169314564Sdim } 170303231Sdim np = p->fts_pointer; 171344779Sdim (void)printf("%s %*u %-*s %-*s ", buf, dp->s_nlink, 172344779Sdim sp->st_nlink, dp->s_user, np->user, dp->s_group, 173344779Sdim np->group); 174314564Sdim if (f_flags) 175303231Sdim (void)printf("%-*s ", dp->s_flags, np->flags); 176321369Sdim if (f_label) 177303231Sdim (void)printf("%-*s ", dp->s_label, np->label); 178303231Sdim if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode)) 179303231Sdim if (minor(sp->st_rdev) > 255 || minor(sp->st_rdev) < 0) 180303231Sdim (void)printf("%3d, 0x%08x ", 181314564Sdim major(sp->st_rdev), 182314564Sdim (u_int)minor(sp->st_rdev)); 183314564Sdim else 184303231Sdim (void)printf("%3d, %3d ", 185303231Sdim major(sp->st_rdev), minor(sp->st_rdev)); 186303231Sdim else if (dp->bcfile) 187303231Sdim (void)printf("%*s%*jd ", 188303231Sdim 8 - dp->s_size, "", dp->s_size, sp->st_size); 189303231Sdim else 190303231Sdim printsize(dp->s_size, sp->st_size); 191321369Sdim if (f_accesstime) 192303231Sdim printtime(sp->st_atime); 193303231Sdim else if (f_statustime) 194303231Sdim printtime(sp->st_ctime); 195303231Sdim else 196303231Sdim printtime(sp->st_mtime); 197303231Sdim#ifdef COLORLS 198303231Sdim if (f_color) 199303231Sdim color_printed = colortype(sp->st_mode); 200303231Sdim#endif 201303231Sdim (void)printname(p->fts_name); 202303231Sdim#ifdef COLORLS 203303231Sdim if (f_color && color_printed) 204303231Sdim endcolor(0); 205303231Sdim#endif 206303231Sdim if (f_type) 207303231Sdim (void)printtype(sp->st_mode); 208303231Sdim if (S_ISLNK(sp->st_mode)) 209303231Sdim printlink(p); 210303231Sdim (void)putchar('\n'); 211303231Sdim } 212303231Sdim} 213303231Sdim 214303231Sdimvoid 215303231Sdimprintstream(const DISPLAY *dp) 216303231Sdim{ 217303231Sdim FTSENT *p; 218303231Sdim int chcnt; 219303231Sdim 220303231Sdim for (p = dp->list, chcnt = 0; p; p = p->fts_link) { 221303231Sdim if (p->fts_number == NO_PRINT) 222303231Sdim continue; 223303231Sdim /* XXX strlen does not take octal escapes into account. */ 224303231Sdim if (strlen(p->fts_name) + chcnt + 225303231Sdim (p->fts_link ? 2 : 0) >= (unsigned)termwidth) { 226303231Sdim putchar('\n'); 227303231Sdim chcnt = 0; 228303231Sdim } 229303231Sdim chcnt += printaname(p, dp->s_inode, dp->s_block); 230303231Sdim if (p->fts_link) { 231303231Sdim printf(", "); 232303231Sdim chcnt += 2; 233303231Sdim } 234303231Sdim } 235303231Sdim if (chcnt) 236303231Sdim putchar('\n'); 237303231Sdim} 238303231Sdim 239303231Sdimvoid 240303231Sdimprintcol(const DISPLAY *dp) 241303231Sdim{ 242303231Sdim static FTSENT **array; 243303231Sdim static int lastentries = -1; 244303231Sdim FTSENT *p; 245321369Sdim FTSENT **narray; 246321369Sdim int base; 247321369Sdim int chcnt; 248321369Sdim int cnt; 249321369Sdim int col; 250321369Sdim int colwidth; 251321369Sdim int endcol; 252321369Sdim int num; 253303231Sdim int numcols; 254327952Sdim int numrows; 255327952Sdim int row; 256327952Sdim int tabwidth; 257327952Sdim 258327952Sdim if (f_notabs) 259327952Sdim tabwidth = 1; 260327952Sdim else 261327952Sdim tabwidth = 8; 262327952Sdim 263327952Sdim /* 264303231Sdim * Have to do random access in the linked list -- build a table 265314564Sdim * of pointers. 266327952Sdim */ 267327952Sdim if (dp->entries > lastentries) { 268303231Sdim if ((narray = 269303231Sdim realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) { 270303231Sdim warn(NULL); 271303231Sdim printscol(dp); 272314564Sdim return; 273314564Sdim } 274314564Sdim lastentries = dp->entries; 275303231Sdim array = narray; 276303231Sdim } 277303231Sdim for (p = dp->list, num = 0; p; p = p->fts_link) 278314564Sdim if (p->fts_number != NO_PRINT) 279314564Sdim array[num++] = p; 280314564Sdim 281314564Sdim colwidth = dp->maxlen; 282314564Sdim if (f_inode) 283303231Sdim colwidth += dp->s_inode + 1; 284303231Sdim if (f_size) 285303231Sdim colwidth += dp->s_block + 1; 286303231Sdim if (f_type) 287303231Sdim colwidth += 1; 288303231Sdim 289314564Sdim colwidth = (colwidth + tabwidth) & ~(tabwidth - 1); 290314564Sdim if (termwidth < 2 * colwidth) { 291303231Sdim printscol(dp); 292303231Sdim return; 293303231Sdim } 294303231Sdim numcols = termwidth / colwidth; 295303231Sdim numrows = num / numcols; 296303231Sdim if (num % numcols) 297314564Sdim ++numrows; 298314564Sdim 299314564Sdim if ((dp->list == NULL || dp->list->fts_level != FTS_ROOTLEVEL) && 300314564Sdim (f_longform || f_size)) { 301303231Sdim (void)printf("total %lu\n", howmany(dp->btotal, blocksize)); 302303231Sdim } 303303231Sdim 304303231Sdim base = 0; 305303231Sdim for (row = 0; row < numrows; ++row) { 306303231Sdim endcol = colwidth; 307303231Sdim if (!f_sortacross) 308303231Sdim base = row; 309303231Sdim for (col = 0, chcnt = 0; col < numcols; ++col) { 310341825Sdim chcnt += printaname(array[base], dp->s_inode, 311341825Sdim dp->s_block); 312341825Sdim if (f_sortacross) 313341825Sdim base++; 314341825Sdim else 315341825Sdim base += numrows; 316341825Sdim if (base >= num) 317341825Sdim break; 318321369Sdim while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1))) 319303231Sdim <= endcol) { 320303231Sdim if (f_sortacross && col + 1 >= numcols) 321314564Sdim break; 322314564Sdim (void)putchar(f_notabs ? ' ' : '\t'); 323314564Sdim chcnt = cnt; 324344779Sdim } 325314564Sdim endcol += colwidth; 326314564Sdim } 327314564Sdim (void)putchar('\n'); 328303231Sdim } 329303231Sdim} 330303231Sdim 331360784Sdim/* 332303231Sdim * print [inode] [size] name 333303231Sdim * return # of characters printed, no trailing characters. 334303231Sdim */ 335303231Sdimstatic int 336303231Sdimprintaname(const FTSENT *p, u_long inodefield, u_long sizefield) 337303231Sdim{ 338303231Sdim struct stat *sp; 339303231Sdim int chcnt; 340303231Sdim#ifdef COLORLS 341303231Sdim int color_printed = 0; 342303231Sdim#endif 343303231Sdim 344303231Sdim sp = p->fts_statp; 345303231Sdim chcnt = 0; 346344779Sdim if (f_inode) 347344779Sdim chcnt += printf("%*lu ", (int)inodefield, (u_long)sp->st_ino); 348321369Sdim if (f_size) 349321369Sdim chcnt += printf("%*jd ", 350321369Sdim (int)sizefield, howmany(sp->st_blocks, blocksize)); 351321369Sdim#ifdef COLORLS 352303231Sdim if (f_color) 353303231Sdim color_printed = colortype(sp->st_mode); 354303231Sdim#endif 355303231Sdim chcnt += printname(p->fts_name); 356303231Sdim#ifdef COLORLS 357303231Sdim if (f_color && color_printed) 358303231Sdim endcolor(0); 359303231Sdim#endif 360303231Sdim if (f_type) 361303231Sdim chcnt += printtype(sp->st_mode); 362303231Sdim return (chcnt); 363303231Sdim} 364303231Sdim 365303231Sdimstatic void 366303231Sdimprinttime(time_t ftime) 367303231Sdim{ 368303231Sdim char longstring[80]; 369303231Sdim static time_t now = 0; 370303231Sdim const char *format; 371303231Sdim static int d_first = -1; 372303231Sdim 373303231Sdim if (d_first < 0) 374303231Sdim d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 375303231Sdim if (now == 0) 376303231Sdim now = time(NULL); 377303231Sdim 378303231Sdim#define SIXMONTHS ((365 / 2) * 86400) 379303231Sdim if (f_sectime) 380303231Sdim /* mmm dd hh:mm:ss yyyy || dd mmm hh:mm:ss yyyy */ 381303231Sdim format = d_first ? "%e %b %T %Y " : "%b %e %T %Y "; 382303231Sdim else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS) 383303231Sdim /* mmm dd hh:mm || dd mmm hh:mm */ 384303231Sdim format = d_first ? "%e %b %R " : "%b %e %R "; 385303231Sdim else 386303231Sdim /* mmm dd yyyy || dd mmm yyyy */ 387303231Sdim format = d_first ? "%e %b %Y " : "%b %e %Y "; 388303231Sdim strftime(longstring, sizeof(longstring), format, localtime(&ftime)); 389303231Sdim fputs(longstring, stdout); 390303231Sdim} 391303231Sdim 392303231Sdimstatic int 393303231Sdimprinttype(u_int mode) 394303231Sdim{ 395303231Sdim 396303231Sdim if (f_slash) { 397303231Sdim if ((mode & S_IFMT) == S_IFDIR) { 398303231Sdim (void)putchar('/'); 399303231Sdim return (1); 400303231Sdim } 401303231Sdim return (0); 402303231Sdim } 403303231Sdim 404303231Sdim switch (mode & S_IFMT) { 405303231Sdim case S_IFDIR: 406303231Sdim (void)putchar('/'); 407303231Sdim return (1); 408303231Sdim case S_IFIFO: 409303231Sdim (void)putchar('|'); 410303231Sdim return (1); 411303231Sdim case S_IFLNK: 412303231Sdim (void)putchar('@'); 413303231Sdim return (1); 414303231Sdim case S_IFSOCK: 415303231Sdim (void)putchar('='); 416303231Sdim return (1); 417303231Sdim case S_IFWHT: 418303231Sdim (void)putchar('%'); 419303231Sdim return (1); 420303231Sdim default: 421303231Sdim break; 422303231Sdim } 423303231Sdim if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 424303231Sdim (void)putchar('*'); 425303231Sdim return (1); 426303231Sdim } 427303231Sdim return (0); 428303231Sdim} 429303231Sdim 430303231Sdim#ifdef COLORLS 431303231Sdimstatic int 432303231Sdimputch(int c) 433314564Sdim{ 434321369Sdim (void)putchar(c); 435303231Sdim return 0; 436321369Sdim} 437303231Sdim 438303231Sdimstatic int 439341825Sdimwritech(int c) 440303231Sdim{ 441321369Sdim char tmp = (char)c; 442321369Sdim 443303231Sdim (void)write(STDOUT_FILENO, &tmp, 1); 444321369Sdim return 0; 445321369Sdim} 446303231Sdim 447303231Sdimstatic void 448321369Sdimprintcolor(Colors c) 449321369Sdim{ 450321369Sdim char *ansiseq; 451321369Sdim 452303231Sdim if (colors[c].bold) 453303231Sdim tputs(enter_bold, 1, putch); 454303231Sdim 455303231Sdim if (colors[c].num[0] != -1) { 456303231Sdim ansiseq = tgoto(ansi_fgcol, 0, colors[c].num[0]); 457314564Sdim if (ansiseq) 458314564Sdim tputs(ansiseq, 1, putch); 459314564Sdim } 460303231Sdim if (colors[c].num[1] != -1) { 461303231Sdim ansiseq = tgoto(ansi_bgcol, 0, colors[c].num[1]); 462303231Sdim if (ansiseq) 463314564Sdim tputs(ansiseq, 1, putch); 464303231Sdim } 465303231Sdim} 466314564Sdim 467314564Sdimstatic void 468314564Sdimendcolor(int sig) 469314564Sdim{ 470314564Sdim tputs(ansi_coloff, 1, sig ? writech : putch); 471303231Sdim tputs(attrs_off, 1, sig ? writech : putch); 472303231Sdim} 473303231Sdim 474303231Sdimstatic int 475303231Sdimcolortype(mode_t mode) 476303231Sdim{ 477303231Sdim switch (mode & S_IFMT) { 478314564Sdim case S_IFDIR: 479314564Sdim if (mode & S_IWOTH) 480314564Sdim if (mode & S_ISTXT) 481303231Sdim printcolor(C_WSDIR); 482303231Sdim else 483303231Sdim printcolor(C_WDIR); 484303231Sdim else 485303231Sdim printcolor(C_DIR); 486303231Sdim return (1); 487303231Sdim case S_IFLNK: 488303231Sdim printcolor(C_LNK); 489303231Sdim return (1); 490303231Sdim case S_IFSOCK: 491303231Sdim printcolor(C_SOCK); 492303231Sdim return (1); 493303231Sdim case S_IFIFO: 494303231Sdim printcolor(C_FIFO); 495303231Sdim return (1); 496303231Sdim case S_IFBLK: 497303231Sdim printcolor(C_BLK); 498303231Sdim return (1); 499303231Sdim case S_IFCHR: 500303231Sdim printcolor(C_CHR); 501303231Sdim return (1); 502303231Sdim default:; 503303231Sdim } 504303231Sdim if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 505303231Sdim if (mode & S_ISUID) 506303231Sdim printcolor(C_SUID); 507303231Sdim else if (mode & S_ISGID) 508303231Sdim printcolor(C_SGID); 509303231Sdim else 510303231Sdim printcolor(C_EXEC); 511303231Sdim return (1); 512303231Sdim } 513303231Sdim return (0); 514303231Sdim} 515303231Sdim 516303231Sdimvoid 517303231Sdimparsecolors(const char *cs) 518303231Sdim{ 519303231Sdim int i; 520303231Sdim int j; 521303231Sdim size_t len; 522303231Sdim char c[2]; 523341825Sdim short legacy_warn = 0; 524303231Sdim 525314564Sdim if (cs == NULL) 526314564Sdim cs = ""; /* LSCOLORS not set */ 527303231Sdim len = strlen(cs); 528303231Sdim for (i = 0; i < (int)C_NUMCOLORS; i++) { 529303231Sdim colors[i].bold = 0; 530303231Sdim 531341825Sdim if (len <= 2 * (size_t)i) { 532303231Sdim c[0] = defcolors[2 * i]; 533303231Sdim c[1] = defcolors[2 * i + 1]; 534303231Sdim } else { 535303231Sdim c[0] = cs[2 * i]; 536303231Sdim c[1] = cs[2 * i + 1]; 537341825Sdim } 538303231Sdim for (j = 0; j < 2; j++) { 539303231Sdim /* Legacy colours used 0-7 */ 540303231Sdim if (c[j] >= '0' && c[j] <= '7') { 541303231Sdim colors[i].num[j] = c[j] - '0'; 542303231Sdim if (!legacy_warn) { 543341825Sdim warnx("LSCOLORS should use " 544303231Sdim "characters a-h instead of 0-9 (" 545321369Sdim "see the manual page)"); 546303231Sdim } 547303231Sdim legacy_warn = 1; 548341825Sdim } else if (c[j] >= 'a' && c[j] <= 'h') 549303231Sdim colors[i].num[j] = c[j] - 'a'; 550303231Sdim else if (c[j] >= 'A' && c[j] <= 'H') { 551360784Sdim colors[i].num[j] = c[j] - 'A'; 552303231Sdim colors[i].bold = 1; 553314564Sdim } else if (tolower((unsigned char)c[j]) == 'x') 554314564Sdim colors[i].num[j] = -1; 555303231Sdim else { 556303231Sdim warnx("invalid character '%c' in LSCOLORS" 557303231Sdim " env var", c[j]); 558303231Sdim colors[i].num[j] = -1; 559341825Sdim } 560303231Sdim } 561303231Sdim } 562303231Sdim} 563303231Sdim 564303231Sdimvoid 565341825Sdimcolorquit(int sig) 566303231Sdim{ 567303231Sdim endcolor(sig); 568303231Sdim 569303231Sdim (void)signal(sig, SIG_DFL); 570303231Sdim (void)kill(getpid(), sig); 571341825Sdim} 572303231Sdim 573303231Sdim#endif /* COLORLS */ 574303231Sdim 575303231Sdimstatic void 576303231Sdimprintlink(const FTSENT *p) 577341825Sdim{ 578303231Sdim int lnklen; 579303231Sdim char name[MAXPATHLEN + 1]; 580303231Sdim char path[MAXPATHLEN + 1]; 581303231Sdim 582303231Sdim if (p->fts_level == FTS_ROOTLEVEL) 583303231Sdim (void)snprintf(name, sizeof(name), "%s", p->fts_name); 584303231Sdim else 585303231Sdim (void)snprintf(name, sizeof(name), 586303231Sdim "%s/%s", p->fts_parent->fts_accpath, p->fts_name); 587303231Sdim if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) { 588303231Sdim (void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno)); 589303231Sdim return; 590303231Sdim } 591303231Sdim path[lnklen] = '\0'; 592303231Sdim (void)printf(" -> "); 593303231Sdim (void)printname(path); 594303231Sdim} 595303231Sdim 596314564Sdimstatic void 597314564Sdimprintsize(size_t width, off_t bytes) 598314564Sdim{ 599303231Sdim 600303231Sdim if (f_humanval) { 601303231Sdim char buf[5]; 602303231Sdim 603303231Sdim humanize_number(buf, sizeof(buf), (int64_t)bytes, "", 604303231Sdim HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 605303231Sdim (void)printf("%5s ", buf); 606303231Sdim } else 607303231Sdim (void)printf("%*jd ", (u_int)width, bytes); 608303231Sdim} 609303231Sdim 610303231Sdimstatic void 611303231Sdimaclmode(char *buf, const FTSENT *p, int *haveacls) 612303231Sdim{ 613303231Sdim char name[MAXPATHLEN + 1]; 614303231Sdim int entries, ret; 615303231Sdim acl_t facl; 616303231Sdim acl_entry_t ae; 617303231Sdim 618303231Sdim /* 619303231Sdim * Add a + after the standard rwxrwxrwx mode if the file has an 620303231Sdim * extended ACL. strmode() reserves space at the end of the string. 621303231Sdim */ 622303231Sdim if (p->fts_level == FTS_ROOTLEVEL) 623303231Sdim snprintf(name, sizeof(name), "%s", p->fts_name); 624303231Sdim else 625303231Sdim snprintf(name, sizeof(name), "%s/%s", 626303231Sdim p->fts_parent->fts_accpath, p->fts_name); 627303231Sdim /* 628303231Sdim * We have no way to tell whether a symbolic link has an ACL since 629303231Sdim * pathconf() and acl_get_file() both follow them. 630303231Sdim */ 631303231Sdim if (S_ISLNK(p->fts_statp->st_mode)) { 632303231Sdim *haveacls = 1; 633303231Sdim return; 634303231Sdim } 635303231Sdim if ((ret = pathconf(name, _PC_ACL_EXTENDED)) <= 0) { 636303231Sdim if (ret < 0 && errno != EINVAL) 637303231Sdim warn("%s", name); 638303231Sdim else 639303231Sdim *haveacls = 0; 640321369Sdim return; 641321369Sdim } 642321369Sdim *haveacls = 1; 643321369Sdim if ((facl = acl_get_file(name, ACL_TYPE_ACCESS)) != NULL) { 644321369Sdim if (acl_get_entry(facl, ACL_FIRST_ENTRY, &ae) == 1) { 645321369Sdim entries = 1; 646321369Sdim while (acl_get_entry(facl, ACL_NEXT_ENTRY, &ae) == 1) 647321369Sdim if (++entries > 3) 648321369Sdim break; 649321369Sdim /* 650321369Sdim * POSIX.1e requires that ACLs of type ACL_TYPE_ACCESS 651321369Sdim * must have at least three entries (owner, group, 652327952Sdim * and other). So anything with more than 3 ACLs looks 653327952Sdim * interesting to us. 654327952Sdim */ 655327952Sdim if (entries > 3) 656327952Sdim buf[10] = '+'; 657327952Sdim } 658327952Sdim acl_free(facl); 659327952Sdim } else 660327952Sdim warn("%s", name); 661327952Sdim} 662327952Sdim