print.c revision 177907
1254721Semaste/*- 2254721Semaste * Copyright (c) 1989, 1993, 1994 3254721Semaste * The Regents of the University of California. All rights reserved. 4254721Semaste * 5254721Semaste * This code is derived from software contributed to Berkeley by 6254721Semaste * Michael Fischbein. 7254721Semaste * 8254721Semaste * Redistribution and use in source and binary forms, with or without 9254721Semaste * modification, are permitted provided that the following conditions 10254721Semaste * are met: 11254721Semaste * 1. Redistributions of source code must retain the above copyright 12254721Semaste * notice, this list of conditions and the following disclaimer. 13254721Semaste * 2. Redistributions in binary form must reproduce the above copyright 14254721Semaste * notice, this list of conditions and the following disclaimer in the 15254721Semaste * documentation and/or other materials provided with the distribution. 16254721Semaste * 4. Neither the name of the University nor the names of its contributors 17254721Semaste * may be used to endorse or promote products derived from this software 18254721Semaste * without specific prior written permission. 19254721Semaste * 20254721Semaste * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21254721Semaste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22254721Semaste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23254721Semaste * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24254721Semaste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25254721Semaste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26254721Semaste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27254721Semaste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28254721Semaste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29254721Semaste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30254721Semaste * SUCH DAMAGE. 31254721Semaste */ 32254721Semaste 33254721Semaste#if 0 34254721Semaste#ifndef lint 35254721Semastestatic char sccsid[] = "@(#)print.c 8.4 (Berkeley) 4/17/94"; 36254721Semaste#endif /* not lint */ 37254721Semaste#endif 38254721Semaste#include <sys/cdefs.h> 39254721Semaste__FBSDID("$FreeBSD: head/bin/ls/print.c 177907 2008-04-04 03:57:46Z grog $"); 40254721Semaste 41254721Semaste#include <sys/param.h> 42254721Semaste#include <sys/stat.h> 43254721Semaste#include <sys/acl.h> 44254721Semaste 45254721Semaste#include <err.h> 46254721Semaste#include <errno.h> 47254721Semaste#include <fts.h> 48254721Semaste#include <langinfo.h> 49254721Semaste#include <libutil.h> 50254721Semaste#include <stdio.h> 51254721Semaste#include <stdlib.h> 52254721Semaste#include <string.h> 53254721Semaste#include <time.h> 54254721Semaste#include <unistd.h> 55254721Semaste#ifdef COLORLS 56254721Semaste#include <ctype.h> 57254721Semaste#include <termcap.h> 58254721Semaste#include <signal.h> 59254721Semaste#endif 60254721Semaste 61254721Semaste#include "ls.h" 62254721Semaste#include "extern.h" 63254721Semaste 64254721Semastestatic int printaname(const FTSENT *, u_long, u_long); 65254721Semastestatic void printlink(const FTSENT *); 66254721Semastestatic void printtime(time_t); 67254721Semastestatic int printtype(u_int); 68254721Semastestatic void printsize(size_t, off_t); 69254721Semaste#ifdef COLORLS 70254721Semastestatic void endcolor(int); 71254721Semastestatic int colortype(mode_t); 72254721Semaste#endif 73254721Semastestatic void aclmode(char *, const FTSENT *, int *); 74254721Semaste 75254721Semaste#define IS_NOPRINT(p) ((p)->fts_number == NO_PRINT) 76254721Semaste 77254721Semaste#ifdef COLORLS 78254721Semaste/* Most of these are taken from <sys/stat.h> */ 79254721Semastetypedef enum Colors { 80254721Semaste C_DIR, /* directory */ 81254721Semaste C_LNK, /* symbolic link */ 82254721Semaste C_SOCK, /* socket */ 83254721Semaste C_FIFO, /* pipe */ 84254721Semaste C_EXEC, /* executable */ 85254721Semaste C_BLK, /* block special */ 86254721Semaste C_CHR, /* character special */ 87254721Semaste C_SUID, /* setuid executable */ 88254721Semaste C_SGID, /* setgid executable */ 89254721Semaste C_WSDIR, /* directory writeble to others, with sticky 90254721Semaste * bit */ 91254721Semaste C_WDIR, /* directory writeble to others, without 92254721Semaste * sticky bit */ 93254721Semaste C_NUMCOLORS /* just a place-holder */ 94254721Semaste} Colors; 95254721Semaste 96254721Semastestatic const char *defcolors = "exfxcxdxbxegedabagacad"; 97254721Semaste 98254721Semaste/* colors for file types */ 99254721Semastestatic struct { 100254721Semaste int num[2]; 101254721Semaste int bold; 102254721Semaste} colors[C_NUMCOLORS]; 103254721Semaste#endif 104254721Semaste 105254721Semastevoid 106254721Semasteprintscol(const DISPLAY *dp) 107254721Semaste{ 108254721Semaste FTSENT *p; 109254721Semaste 110254721Semaste for (p = dp->list; p; p = p->fts_link) { 111254721Semaste if (IS_NOPRINT(p)) 112254721Semaste continue; 113254721Semaste (void)printaname(p, dp->s_inode, dp->s_block); 114254721Semaste (void)putchar('\n'); 115254721Semaste } 116254721Semaste} 117254721Semaste 118254721Semaste/* 119254721Semaste * print name in current style 120254721Semaste */ 121254721Semasteint 122254721Semasteprintname(const char *name) 123254721Semaste{ 124254721Semaste if (f_octal || f_octal_escape) 125254721Semaste return prn_octal(name); 126254721Semaste else if (f_nonprint) 127254721Semaste return prn_printable(name); 128254721Semaste else 129254721Semaste return prn_normal(name); 130254721Semaste} 131254721Semaste 132254721Semastevoid 133254721Semasteprintlong(const DISPLAY *dp) 134254721Semaste{ 135254721Semaste struct stat *sp; 136254721Semaste FTSENT *p; 137254721Semaste NAMES *np; 138254721Semaste char buf[20]; 139254721Semaste#ifdef COLORLS 140254721Semaste int color_printed = 0; 141254721Semaste#endif 142254721Semaste int haveacls; 143254721Semaste dev_t prevdev; 144254721Semaste 145254721Semaste if ((dp->list == NULL || dp->list->fts_level != FTS_ROOTLEVEL) && 146254721Semaste (f_longform || f_size)) { 147254721Semaste (void)printf("total %lu\n", howmany(dp->btotal, blocksize)); 148254721Semaste } 149254721Semaste 150254721Semaste haveacls = 1; 151254721Semaste prevdev = (dev_t)-1; 152254721Semaste for (p = dp->list; p; p = p->fts_link) { 153254721Semaste if (IS_NOPRINT(p)) 154254721Semaste continue; 155254721Semaste sp = p->fts_statp; 156254721Semaste if (f_inode) 157254721Semaste (void)printf("%*lu ", dp->s_inode, (u_long)sp->st_ino); 158254721Semaste if (f_size) 159254721Semaste (void)printf("%*jd ", 160254721Semaste dp->s_block, howmany(sp->st_blocks, blocksize)); 161254721Semaste strmode(sp->st_mode, buf); 162254721Semaste /* 163254721Semaste * Cache whether or not the filesystem supports ACL's to 164254721Semaste * avoid expensive syscalls. Try again when we change devices. 165254721Semaste */ 166254721Semaste if (haveacls || sp->st_dev != prevdev) { 167254721Semaste aclmode(buf, p, &haveacls); 168254721Semaste prevdev = sp->st_dev; 169254721Semaste } 170254721Semaste np = p->fts_pointer; 171254721Semaste (void)printf("%s %*u %-*s %-*s ", buf, dp->s_nlink, 172254721Semaste sp->st_nlink, dp->s_user, np->user, dp->s_group, 173254721Semaste np->group); 174254721Semaste if (f_flags) 175254721Semaste (void)printf("%-*s ", dp->s_flags, np->flags); 176254721Semaste if (f_label) 177254721Semaste (void)printf("%-*s ", dp->s_label, np->label); 178254721Semaste if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode)) 179254721Semaste if (minor(sp->st_rdev) > 255 || minor(sp->st_rdev) < 0) 180254721Semaste (void)printf("%3d, 0x%08x ", 181254721Semaste major(sp->st_rdev), 182254721Semaste (u_int)minor(sp->st_rdev)); 183254721Semaste else 184254721Semaste (void)printf("%3d, %3d ", 185254721Semaste major(sp->st_rdev), minor(sp->st_rdev)); 186254721Semaste else if (dp->bcfile) 187254721Semaste (void)printf("%*s%*jd ", 188254721Semaste 8 - dp->s_size, "", dp->s_size, sp->st_size); 189254721Semaste else 190254721Semaste printsize(dp->s_size, sp->st_size); 191254721Semaste if (f_accesstime) 192254721Semaste printtime(sp->st_atime); 193254721Semaste else if (f_birthtime) 194254721Semaste printtime(sp->st_birthtime); 195254721Semaste else if (f_statustime) 196254721Semaste printtime(sp->st_ctime); 197254721Semaste else 198254721Semaste printtime(sp->st_mtime); 199254721Semaste#ifdef COLORLS 200254721Semaste if (f_color) 201254721Semaste color_printed = colortype(sp->st_mode); 202254721Semaste#endif 203254721Semaste (void)printname(p->fts_name); 204254721Semaste#ifdef COLORLS 205254721Semaste if (f_color && color_printed) 206254721Semaste endcolor(0); 207254721Semaste#endif 208254721Semaste if (f_type) 209254721Semaste (void)printtype(sp->st_mode); 210254721Semaste if (S_ISLNK(sp->st_mode)) 211254721Semaste printlink(p); 212254721Semaste (void)putchar('\n'); 213254721Semaste } 214254721Semaste} 215254721Semaste 216254721Semastevoid 217254721Semasteprintstream(const DISPLAY *dp) 218254721Semaste{ 219254721Semaste FTSENT *p; 220254721Semaste int chcnt; 221254721Semaste 222254721Semaste for (p = dp->list, chcnt = 0; p; p = p->fts_link) { 223254721Semaste if (p->fts_number == NO_PRINT) 224254721Semaste continue; 225254721Semaste /* XXX strlen does not take octal escapes into account. */ 226254721Semaste if (strlen(p->fts_name) + chcnt + 227254721Semaste (p->fts_link ? 2 : 0) >= (unsigned)termwidth) { 228254721Semaste putchar('\n'); 229254721Semaste chcnt = 0; 230254721Semaste } 231254721Semaste chcnt += printaname(p, dp->s_inode, dp->s_block); 232254721Semaste if (p->fts_link) { 233254721Semaste printf(", "); 234254721Semaste chcnt += 2; 235254721Semaste } 236254721Semaste } 237254721Semaste if (chcnt) 238254721Semaste putchar('\n'); 239254721Semaste} 240254721Semaste 241254721Semastevoid 242254721Semasteprintcol(const DISPLAY *dp) 243254721Semaste{ 244254721Semaste static FTSENT **array; 245254721Semaste static int lastentries = -1; 246254721Semaste FTSENT *p; 247254721Semaste FTSENT **narray; 248254721Semaste int base; 249254721Semaste int chcnt; 250254721Semaste int cnt; 251254721Semaste int col; 252254721Semaste int colwidth; 253254721Semaste int endcol; 254254721Semaste int num; 255254721Semaste int numcols; 256254721Semaste int numrows; 257254721Semaste int row; 258254721Semaste int tabwidth; 259254721Semaste 260254721Semaste if (f_notabs) 261254721Semaste tabwidth = 1; 262254721Semaste else 263254721Semaste tabwidth = 8; 264254721Semaste 265254721Semaste /* 266254721Semaste * Have to do random access in the linked list -- build a table 267254721Semaste * of pointers. 268254721Semaste */ 269254721Semaste if (dp->entries > lastentries) { 270254721Semaste if ((narray = 271254721Semaste realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) { 272254721Semaste warn(NULL); 273254721Semaste printscol(dp); 274254721Semaste return; 275254721Semaste } 276254721Semaste lastentries = dp->entries; 277254721Semaste array = narray; 278254721Semaste } 279254721Semaste for (p = dp->list, num = 0; p; p = p->fts_link) 280254721Semaste if (p->fts_number != NO_PRINT) 281254721Semaste array[num++] = p; 282254721Semaste 283254721Semaste colwidth = dp->maxlen; 284254721Semaste if (f_inode) 285254721Semaste colwidth += dp->s_inode + 1; 286254721Semaste if (f_size) 287254721Semaste colwidth += dp->s_block + 1; 288254721Semaste if (f_type) 289254721Semaste colwidth += 1; 290254721Semaste 291254721Semaste colwidth = (colwidth + tabwidth) & ~(tabwidth - 1); 292254721Semaste if (termwidth < 2 * colwidth) { 293254721Semaste printscol(dp); 294254721Semaste return; 295254721Semaste } 296254721Semaste numcols = termwidth / colwidth; 297254721Semaste numrows = num / numcols; 298254721Semaste if (num % numcols) 299254721Semaste ++numrows; 300254721Semaste 301254721Semaste if ((dp->list == NULL || dp->list->fts_level != FTS_ROOTLEVEL) && 302254721Semaste (f_longform || f_size)) { 303254721Semaste (void)printf("total %lu\n", howmany(dp->btotal, blocksize)); 304254721Semaste } 305254721Semaste 306254721Semaste base = 0; 307254721Semaste for (row = 0; row < numrows; ++row) { 308254721Semaste endcol = colwidth; 309254721Semaste if (!f_sortacross) 310254721Semaste base = row; 311254721Semaste for (col = 0, chcnt = 0; col < numcols; ++col) { 312254721Semaste chcnt += printaname(array[base], dp->s_inode, 313254721Semaste dp->s_block); 314254721Semaste if (f_sortacross) 315254721Semaste base++; 316254721Semaste else 317254721Semaste base += numrows; 318254721Semaste if (base >= num) 319254721Semaste break; 320254721Semaste while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1))) 321254721Semaste <= endcol) { 322254721Semaste if (f_sortacross && col + 1 >= numcols) 323254721Semaste break; 324254721Semaste (void)putchar(f_notabs ? ' ' : '\t'); 325254721Semaste chcnt = cnt; 326254721Semaste } 327254721Semaste endcol += colwidth; 328254721Semaste } 329254721Semaste (void)putchar('\n'); 330254721Semaste } 331254721Semaste} 332254721Semaste 333254721Semaste/* 334254721Semaste * print [inode] [size] name 335254721Semaste * return # of characters printed, no trailing characters. 336254721Semaste */ 337254721Semastestatic int 338254721Semasteprintaname(const FTSENT *p, u_long inodefield, u_long sizefield) 339254721Semaste{ 340254721Semaste struct stat *sp; 341254721Semaste int chcnt; 342254721Semaste#ifdef COLORLS 343254721Semaste int color_printed = 0; 344254721Semaste#endif 345254721Semaste 346254721Semaste sp = p->fts_statp; 347254721Semaste chcnt = 0; 348254721Semaste if (f_inode) 349254721Semaste chcnt += printf("%*lu ", (int)inodefield, (u_long)sp->st_ino); 350254721Semaste if (f_size) 351254721Semaste chcnt += printf("%*jd ", 352254721Semaste (int)sizefield, howmany(sp->st_blocks, blocksize)); 353254721Semaste#ifdef COLORLS 354254721Semaste if (f_color) 355254721Semaste color_printed = colortype(sp->st_mode); 356254721Semaste#endif 357254721Semaste chcnt += printname(p->fts_name); 358254721Semaste#ifdef COLORLS 359254721Semaste if (f_color && color_printed) 360254721Semaste endcolor(0); 361254721Semaste#endif 362254721Semaste if (f_type) 363254721Semaste chcnt += printtype(sp->st_mode); 364254721Semaste return (chcnt); 365254721Semaste} 366254721Semaste 367254721Semastestatic void 368254721Semasteprinttime(time_t ftime) 369254721Semaste{ 370254721Semaste char longstring[80]; 371254721Semaste static time_t now = 0; 372254721Semaste const char *format; 373254721Semaste static int d_first = -1; 374254721Semaste 375254721Semaste if (d_first < 0) 376254721Semaste d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 377254721Semaste if (now == 0) 378254721Semaste now = time(NULL); 379254721Semaste 380254721Semaste#define SIXMONTHS ((365 / 2) * 86400) 381254721Semaste if (f_timeformat) /* user specified format */ 382254721Semaste format = f_timeformat; 383254721Semaste else if (f_sectime) 384254721Semaste /* mmm dd hh:mm:ss yyyy || dd mmm hh:mm:ss yyyy */ 385254721Semaste format = d_first ? "%e %b %T %Y" : "%b %e %T %Y"; 386254721Semaste else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS) 387254721Semaste /* mmm dd hh:mm || dd mmm hh:mm */ 388254721Semaste format = d_first ? "%e %b %R" : "%b %e %R"; 389254721Semaste else 390254721Semaste /* mmm dd yyyy || dd mmm yyyy */ 391254721Semaste format = d_first ? "%e %b %Y" : "%b %e %Y"; 392254721Semaste strftime(longstring, sizeof(longstring), format, localtime(&ftime)); 393254721Semaste fputs(longstring, stdout); 394254721Semaste fputc(' ', stdout); 395254721Semaste} 396254721Semaste 397254721Semastestatic int 398254721Semasteprinttype(u_int mode) 399254721Semaste{ 400254721Semaste 401254721Semaste if (f_slash) { 402254721Semaste if ((mode & S_IFMT) == S_IFDIR) { 403254721Semaste (void)putchar('/'); 404254721Semaste return (1); 405254721Semaste } 406254721Semaste return (0); 407254721Semaste } 408254721Semaste 409254721Semaste switch (mode & S_IFMT) { 410254721Semaste case S_IFDIR: 411254721Semaste (void)putchar('/'); 412254721Semaste return (1); 413254721Semaste case S_IFIFO: 414254721Semaste (void)putchar('|'); 415254721Semaste return (1); 416254721Semaste case S_IFLNK: 417254721Semaste (void)putchar('@'); 418254721Semaste return (1); 419254721Semaste case S_IFSOCK: 420254721Semaste (void)putchar('='); 421254721Semaste return (1); 422254721Semaste case S_IFWHT: 423254721Semaste (void)putchar('%'); 424254721Semaste return (1); 425254721Semaste default: 426254721Semaste break; 427254721Semaste } 428254721Semaste if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 429254721Semaste (void)putchar('*'); 430254721Semaste return (1); 431254721Semaste } 432254721Semaste return (0); 433254721Semaste} 434254721Semaste 435254721Semaste#ifdef COLORLS 436254721Semastestatic int 437254721Semasteputch(int c) 438254721Semaste{ 439254721Semaste (void)putchar(c); 440254721Semaste return 0; 441254721Semaste} 442254721Semaste 443254721Semastestatic int 444254721Semastewritech(int c) 445254721Semaste{ 446254721Semaste char tmp = (char)c; 447254721Semaste 448254721Semaste (void)write(STDOUT_FILENO, &tmp, 1); 449254721Semaste return 0; 450254721Semaste} 451254721Semaste 452254721Semastestatic void 453254721Semasteprintcolor(Colors c) 454254721Semaste{ 455254721Semaste char *ansiseq; 456254721Semaste 457254721Semaste if (colors[c].bold) 458254721Semaste tputs(enter_bold, 1, putch); 459254721Semaste 460254721Semaste if (colors[c].num[0] != -1) { 461254721Semaste ansiseq = tgoto(ansi_fgcol, 0, colors[c].num[0]); 462254721Semaste if (ansiseq) 463254721Semaste tputs(ansiseq, 1, putch); 464254721Semaste } 465254721Semaste if (colors[c].num[1] != -1) { 466254721Semaste ansiseq = tgoto(ansi_bgcol, 0, colors[c].num[1]); 467254721Semaste if (ansiseq) 468254721Semaste tputs(ansiseq, 1, putch); 469254721Semaste } 470254721Semaste} 471254721Semaste 472254721Semastestatic void 473254721Semasteendcolor(int sig) 474254721Semaste{ 475254721Semaste tputs(ansi_coloff, 1, sig ? writech : putch); 476254721Semaste tputs(attrs_off, 1, sig ? writech : putch); 477254721Semaste} 478254721Semaste 479254721Semastestatic int 480254721Semastecolortype(mode_t mode) 481254721Semaste{ 482254721Semaste switch (mode & S_IFMT) { 483254721Semaste case S_IFDIR: 484254721Semaste if (mode & S_IWOTH) 485254721Semaste if (mode & S_ISTXT) 486254721Semaste printcolor(C_WSDIR); 487254721Semaste else 488254721Semaste printcolor(C_WDIR); 489254721Semaste else 490254721Semaste printcolor(C_DIR); 491254721Semaste return (1); 492254721Semaste case S_IFLNK: 493254721Semaste printcolor(C_LNK); 494254721Semaste return (1); 495254721Semaste case S_IFSOCK: 496254721Semaste printcolor(C_SOCK); 497254721Semaste return (1); 498254721Semaste case S_IFIFO: 499254721Semaste printcolor(C_FIFO); 500254721Semaste return (1); 501254721Semaste case S_IFBLK: 502254721Semaste printcolor(C_BLK); 503254721Semaste return (1); 504254721Semaste case S_IFCHR: 505254721Semaste printcolor(C_CHR); 506254721Semaste return (1); 507254721Semaste default:; 508254721Semaste } 509254721Semaste if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 510254721Semaste if (mode & S_ISUID) 511254721Semaste printcolor(C_SUID); 512254721Semaste else if (mode & S_ISGID) 513254721Semaste printcolor(C_SGID); 514254721Semaste else 515254721Semaste printcolor(C_EXEC); 516254721Semaste return (1); 517254721Semaste } 518254721Semaste return (0); 519254721Semaste} 520254721Semaste 521254721Semastevoid 522254721Semasteparsecolors(const char *cs) 523254721Semaste{ 524254721Semaste int i; 525254721Semaste int j; 526254721Semaste size_t len; 527254721Semaste char c[2]; 528254721Semaste short legacy_warn = 0; 529254721Semaste 530254721Semaste if (cs == NULL) 531254721Semaste cs = ""; /* LSCOLORS not set */ 532254721Semaste len = strlen(cs); 533254721Semaste for (i = 0; i < (int)C_NUMCOLORS; i++) { 534254721Semaste colors[i].bold = 0; 535254721Semaste 536254721Semaste if (len <= 2 * (size_t)i) { 537254721Semaste c[0] = defcolors[2 * i]; 538254721Semaste c[1] = defcolors[2 * i + 1]; 539254721Semaste } else { 540254721Semaste c[0] = cs[2 * i]; 541254721Semaste c[1] = cs[2 * i + 1]; 542254721Semaste } 543254721Semaste for (j = 0; j < 2; j++) { 544254721Semaste /* Legacy colours used 0-7 */ 545254721Semaste if (c[j] >= '0' && c[j] <= '7') { 546254721Semaste colors[i].num[j] = c[j] - '0'; 547254721Semaste if (!legacy_warn) { 548254721Semaste warnx("LSCOLORS should use " 549254721Semaste "characters a-h instead of 0-9 (" 550254721Semaste "see the manual page)"); 551254721Semaste } 552254721Semaste legacy_warn = 1; 553254721Semaste } else if (c[j] >= 'a' && c[j] <= 'h') 554254721Semaste colors[i].num[j] = c[j] - 'a'; 555254721Semaste else if (c[j] >= 'A' && c[j] <= 'H') { 556254721Semaste colors[i].num[j] = c[j] - 'A'; 557254721Semaste colors[i].bold = 1; 558254721Semaste } else if (tolower((unsigned char)c[j]) == 'x') 559254721Semaste colors[i].num[j] = -1; 560254721Semaste else { 561254721Semaste warnx("invalid character '%c' in LSCOLORS" 562254721Semaste " env var", c[j]); 563254721Semaste colors[i].num[j] = -1; 564254721Semaste } 565254721Semaste } 566254721Semaste } 567254721Semaste} 568254721Semaste 569254721Semastevoid 570254721Semastecolorquit(int sig) 571254721Semaste{ 572254721Semaste endcolor(sig); 573254721Semaste 574254721Semaste (void)signal(sig, SIG_DFL); 575254721Semaste (void)kill(getpid(), sig); 576254721Semaste} 577254721Semaste 578254721Semaste#endif /* COLORLS */ 579254721Semaste 580254721Semastestatic void 581254721Semasteprintlink(const FTSENT *p) 582254721Semaste{ 583254721Semaste int lnklen; 584254721Semaste char name[MAXPATHLEN + 1]; 585254721Semaste char path[MAXPATHLEN + 1]; 586254721Semaste 587254721Semaste if (p->fts_level == FTS_ROOTLEVEL) 588254721Semaste (void)snprintf(name, sizeof(name), "%s", p->fts_name); 589254721Semaste else 590254721Semaste (void)snprintf(name, sizeof(name), 591254721Semaste "%s/%s", p->fts_parent->fts_accpath, p->fts_name); 592254721Semaste if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) { 593254721Semaste (void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno)); 594254721Semaste return; 595254721Semaste } 596254721Semaste path[lnklen] = '\0'; 597254721Semaste (void)printf(" -> "); 598254721Semaste (void)printname(path); 599254721Semaste} 600254721Semaste 601254721Semastestatic void 602254721Semasteprintsize(size_t width, off_t bytes) 603254721Semaste{ 604254721Semaste 605254721Semaste if (f_humanval) { 606254721Semaste char buf[5]; 607254721Semaste 608254721Semaste humanize_number(buf, sizeof(buf), (int64_t)bytes, "", 609254721Semaste HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 610254721Semaste (void)printf("%5s ", buf); 611254721Semaste } else 612254721Semaste (void)printf("%*jd ", (u_int)width, bytes); 613254721Semaste} 614254721Semaste 615254721Semastestatic void 616254721Semasteaclmode(char *buf, const FTSENT *p, int *haveacls) 617254721Semaste{ 618254721Semaste char name[MAXPATHLEN + 1]; 619254721Semaste int entries, ret; 620254721Semaste acl_t facl; 621254721Semaste acl_entry_t ae; 622254721Semaste 623254721Semaste /* 624254721Semaste * Add a + after the standard rwxrwxrwx mode if the file has an 625254721Semaste * extended ACL. strmode() reserves space at the end of the string. 626254721Semaste */ 627254721Semaste if (p->fts_level == FTS_ROOTLEVEL) 628254721Semaste snprintf(name, sizeof(name), "%s", p->fts_name); 629254721Semaste else 630254721Semaste snprintf(name, sizeof(name), "%s/%s", 631254721Semaste p->fts_parent->fts_accpath, p->fts_name); 632254721Semaste /* 633254721Semaste * We have no way to tell whether a symbolic link has an ACL since 634254721Semaste * pathconf() and acl_get_file() both follow them. They also don't 635254721Semaste * support whiteouts. 636254721Semaste */ 637254721Semaste if (S_ISLNK(p->fts_statp->st_mode) || S_ISWHT(p->fts_statp->st_mode)) { 638254721Semaste *haveacls = 1; 639254721Semaste return; 640254721Semaste } 641254721Semaste if ((ret = pathconf(name, _PC_ACL_EXTENDED)) <= 0) { 642254721Semaste if (ret < 0 && errno != EINVAL) 643254721Semaste warn("%s", name); 644254721Semaste else 645254721Semaste *haveacls = 0; 646254721Semaste return; 647254721Semaste } 648254721Semaste *haveacls = 1; 649254721Semaste if ((facl = acl_get_file(name, ACL_TYPE_ACCESS)) != NULL) { 650254721Semaste if (acl_get_entry(facl, ACL_FIRST_ENTRY, &ae) == 1) { 651254721Semaste entries = 1; 652254721Semaste while (acl_get_entry(facl, ACL_NEXT_ENTRY, &ae) == 1) 653254721Semaste if (++entries > 3) 654263363Semaste break; 655254721Semaste /* 656254721Semaste * POSIX.1e requires that ACLs of type ACL_TYPE_ACCESS 657254721Semaste * must have at least three entries (owner, group, 658254721Semaste * and other). So anything with more than 3 ACLs looks 659254721Semaste * interesting to us. 660254721Semaste */ 661254721Semaste if (entries > 3) 662254721Semaste buf[10] = '+'; 663254721Semaste } 664254721Semaste acl_free(facl); 665254721Semaste } else 666254721Semaste warn("%s", name); 667254721Semaste} 668254721Semaste