print.c revision 61296
11556Srgrimes/* 21556Srgrimes * Copyright (c) 1989, 1993, 1994 31556Srgrimes * The Regents of the University of California. All rights reserved. 41556Srgrimes * 51556Srgrimes * This code is derived from software contributed to Berkeley by 61556Srgrimes * Michael Fischbein. 71556Srgrimes * 81556Srgrimes * Redistribution and use in source and binary forms, with or without 91556Srgrimes * modification, are permitted provided that the following conditions 101556Srgrimes * are met: 111556Srgrimes * 1. Redistributions of source code must retain the above copyright 121556Srgrimes * notice, this list of conditions and the following disclaimer. 131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141556Srgrimes * notice, this list of conditions and the following disclaimer in the 151556Srgrimes * documentation and/or other materials provided with the distribution. 161556Srgrimes * 3. All advertising materials mentioning features or use of this software 171556Srgrimes * must display the following acknowledgement: 181556Srgrimes * This product includes software developed by the University of 191556Srgrimes * California, Berkeley and its contributors. 201556Srgrimes * 4. Neither the name of the University nor the names of its contributors 211556Srgrimes * may be used to endorse or promote products derived from this software 221556Srgrimes * without specific prior written permission. 231556Srgrimes * 241556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341556Srgrimes * SUCH DAMAGE. 351556Srgrimes */ 361556Srgrimes 371556Srgrimes#ifndef lint 3827967Ssteve#if 0 3927967Sstevestatic char sccsid[] = "@(#)print.c 8.4 (Berkeley) 4/17/94"; 4027967Ssteve#else 4127958Sstevestatic const char rcsid[] = 4250471Speter "$FreeBSD: head/bin/ls/print.c 61296 2000-06-05 20:54:46Z ache $"; 4327967Ssteve#endif 441556Srgrimes#endif /* not lint */ 451556Srgrimes 461556Srgrimes#include <sys/param.h> 471556Srgrimes#include <sys/stat.h> 481556Srgrimes 491556Srgrimes#include <err.h> 501556Srgrimes#include <errno.h> 511556Srgrimes#include <fts.h> 521556Srgrimes#include <grp.h> 531556Srgrimes#include <pwd.h> 541556Srgrimes#include <stdio.h> 551556Srgrimes#include <stdlib.h> 561556Srgrimes#include <string.h> 571556Srgrimes#include <time.h> 581556Srgrimes#include <unistd.h> 5961294Sache#ifdef COLORLS 6061294Sache#include <ctype.h> 6161294Sache#include <termcap.h> 6261294Sache#include <signal.h> 6361294Sache#endif 641556Srgrimes 651556Srgrimes#include "ls.h" 661556Srgrimes#include "extern.h" 671556Srgrimes 681556Srgrimesstatic int printaname __P((FTSENT *, u_long, u_long)); 691556Srgrimesstatic void printlink __P((FTSENT *)); 701556Srgrimesstatic void printtime __P((time_t)); 711556Srgrimesstatic int printtype __P((u_int)); 721556Srgrimes 731556Srgrimes#define IS_NOPRINT(p) ((p)->fts_number == NO_PRINT) 741556Srgrimes 7561268Sjoe#ifdef COLORLS 7661178Sjoe/* Most of these are taken from <sys/stat.h> */ 7761178Sjoetypedef enum Colors { 7861178Sjoe C_DIR, /* directory */ 7961178Sjoe C_LNK, /* symbolic link */ 8061178Sjoe C_SOCK, /* socket */ 8161178Sjoe C_FIFO, /* pipe */ 8261178Sjoe C_EXEC, /* executable */ 8361178Sjoe C_BLK, /* block special */ 8461178Sjoe C_CHR, /* character special */ 8561178Sjoe C_SUID, /* setuid executable */ 8661178Sjoe C_SGID, /* setgid executable */ 8761178Sjoe C_WSDIR, /* directory writeble to others, with sticky bit */ 8861178Sjoe C_WDIR, /* directory writeble to others, without sticky bit */ 8961178Sjoe C_NUMCOLORS /* just a place-holder */ 9061178Sjoe} Colors ; 9161178Sjoe 9261178Sjoechar *defcolors = "4x5x2x3x1x464301060203"; 9361178Sjoe 9461178Sjoestatic int colors[C_NUMCOLORS][2]; 9561268Sjoe#endif 9661178Sjoe 971556Srgrimesvoid 981556Srgrimesprintscol(dp) 991556Srgrimes DISPLAY *dp; 1001556Srgrimes{ 1011556Srgrimes FTSENT *p; 1021556Srgrimes 1031556Srgrimes for (p = dp->list; p; p = p->fts_link) { 1041556Srgrimes if (IS_NOPRINT(p)) 1051556Srgrimes continue; 1061556Srgrimes (void)printaname(p, dp->s_inode, dp->s_block); 1071556Srgrimes (void)putchar('\n'); 1081556Srgrimes } 1091556Srgrimes} 1101556Srgrimes 1111556Srgrimesvoid 1121556Srgrimesprintlong(dp) 1131556Srgrimes DISPLAY *dp; 1141556Srgrimes{ 1151556Srgrimes struct stat *sp; 1161556Srgrimes FTSENT *p; 1171556Srgrimes NAMES *np; 1181556Srgrimes char buf[20]; 11961292Sache#ifdef COLORLS 12061292Sache int color_printed = 0; 12161292Sache#endif 1221556Srgrimes 1231556Srgrimes if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) 1241556Srgrimes (void)printf("total %lu\n", howmany(dp->btotal, blocksize)); 1251556Srgrimes 1261556Srgrimes for (p = dp->list; p; p = p->fts_link) { 1271556Srgrimes if (IS_NOPRINT(p)) 1281556Srgrimes continue; 1291556Srgrimes sp = p->fts_statp; 1301556Srgrimes if (f_inode) 13120417Ssteve (void)printf("%*lu ", dp->s_inode, (u_long)sp->st_ino); 1321556Srgrimes if (f_size) 1331556Srgrimes (void)printf("%*qd ", 1341556Srgrimes dp->s_block, howmany(sp->st_blocks, blocksize)); 1351556Srgrimes (void)strmode(sp->st_mode, buf); 1361556Srgrimes np = p->fts_pointer; 1371556Srgrimes (void)printf("%s %*u %-*s %-*s ", buf, dp->s_nlink, 1381556Srgrimes sp->st_nlink, dp->s_user, np->user, dp->s_group, 1391556Srgrimes np->group); 1401556Srgrimes if (f_flags) 1411556Srgrimes (void)printf("%-*s ", dp->s_flags, np->flags); 1421556Srgrimes if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode)) 14355514Sbde if (minor(sp->st_rdev) > 255 || minor(sp->st_rdev) < 0) 14413120Sjoerg (void)printf("%3d, 0x%08x ", 14555514Sbde major(sp->st_rdev), 14655514Sbde (u_int)minor(sp->st_rdev)); 14713120Sjoerg else 14813120Sjoerg (void)printf("%3d, %3d ", 14913120Sjoerg major(sp->st_rdev), minor(sp->st_rdev)); 1501556Srgrimes else if (dp->bcfile) 1511556Srgrimes (void)printf("%*s%*qd ", 1521556Srgrimes 8 - dp->s_size, "", dp->s_size, sp->st_size); 1531556Srgrimes else 1541556Srgrimes (void)printf("%*qd ", dp->s_size, sp->st_size); 1551556Srgrimes if (f_accesstime) 1561556Srgrimes printtime(sp->st_atime); 1571556Srgrimes else if (f_statustime) 1581556Srgrimes printtime(sp->st_ctime); 1591556Srgrimes else 1601556Srgrimes printtime(sp->st_mtime); 16161268Sjoe#ifdef COLORLS 16261178Sjoe if (f_color) 16361291Sache color_printed = colortype(sp->st_mode); 16461268Sjoe#endif 16535417Sdes if (f_octal || f_octal_escape) (void)prn_octal(p->fts_name); 16635373Sdes else (void)printf("%s", p->fts_name); 16761268Sjoe#ifdef COLORLS 16861291Sache if (f_color && color_printed) 16961268Sjoe endcolor(); 17061268Sjoe#endif 1711556Srgrimes if (f_type) 1721556Srgrimes (void)printtype(sp->st_mode); 1731556Srgrimes if (S_ISLNK(sp->st_mode)) 1741556Srgrimes printlink(p); 1751556Srgrimes (void)putchar('\n'); 1761556Srgrimes } 1771556Srgrimes} 1781556Srgrimes 1791556Srgrimesvoid 1801556Srgrimesprintcol(dp) 1811556Srgrimes DISPLAY *dp; 1821556Srgrimes{ 1831556Srgrimes extern int termwidth; 1841556Srgrimes static FTSENT **array; 1851556Srgrimes static int lastentries = -1; 1861556Srgrimes FTSENT *p; 1871556Srgrimes int base, chcnt, cnt, col, colwidth, num; 1881556Srgrimes int endcol, numcols, numrows, row; 18937932Shoek int tabwidth; 1901556Srgrimes 19137932Shoek if (f_notabs) 19237932Shoek tabwidth = 1; 19337932Shoek else 19437932Shoek tabwidth = 8; 19537932Shoek 1961556Srgrimes /* 1971556Srgrimes * Have to do random access in the linked list -- build a table 1981556Srgrimes * of pointers. 1991556Srgrimes */ 2001556Srgrimes if (dp->entries > lastentries) { 2011556Srgrimes lastentries = dp->entries; 2021556Srgrimes if ((array = 2031556Srgrimes realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) { 2041556Srgrimes warn(NULL); 2051556Srgrimes printscol(dp); 2061556Srgrimes } 2071556Srgrimes } 2081556Srgrimes for (p = dp->list, num = 0; p; p = p->fts_link) 2091556Srgrimes if (p->fts_number != NO_PRINT) 2101556Srgrimes array[num++] = p; 2111556Srgrimes 2121556Srgrimes colwidth = dp->maxlen; 2131556Srgrimes if (f_inode) 2141556Srgrimes colwidth += dp->s_inode + 1; 2151556Srgrimes if (f_size) 2161556Srgrimes colwidth += dp->s_block + 1; 2171556Srgrimes if (f_type) 2181556Srgrimes colwidth += 1; 2191556Srgrimes 22037932Shoek colwidth = (colwidth + tabwidth) & ~(tabwidth - 1); 2211556Srgrimes if (termwidth < 2 * colwidth) { 2221556Srgrimes printscol(dp); 2231556Srgrimes return; 2241556Srgrimes } 2251556Srgrimes 2261556Srgrimes numcols = termwidth / colwidth; 2271556Srgrimes numrows = num / numcols; 2281556Srgrimes if (num % numcols) 2291556Srgrimes ++numrows; 2301556Srgrimes 2311556Srgrimes if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) 2321556Srgrimes (void)printf("total %lu\n", howmany(dp->btotal, blocksize)); 2331556Srgrimes for (row = 0; row < numrows; ++row) { 2341556Srgrimes endcol = colwidth; 2351556Srgrimes for (base = row, chcnt = col = 0; col < numcols; ++col) { 2361556Srgrimes chcnt += printaname(array[base], dp->s_inode, 2371556Srgrimes dp->s_block); 2381556Srgrimes if ((base += numrows) >= num) 2391556Srgrimes break; 24061268Sjoe#ifdef COLORLS 24161178Sjoe /* 24261178Sjoe * some terminals get confused if we mix tabs 24361178Sjoe * with color sequences 24461178Sjoe */ 24561178Sjoe if (f_color) 24661178Sjoe while ((cnt = (chcnt + 1)) <= endcol) { 24761178Sjoe (void)putchar(' '); 24861178Sjoe chcnt = cnt; 24961178Sjoe } 25061178Sjoe else 25161268Sjoe#endif 25237932Shoek while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1))) 25337932Shoek <= endcol){ 25437932Shoek (void)putchar(f_notabs ? ' ' : '\t'); 2551556Srgrimes chcnt = cnt; 2561556Srgrimes } 2571556Srgrimes endcol += colwidth; 2581556Srgrimes } 2591556Srgrimes (void)putchar('\n'); 2601556Srgrimes } 2611556Srgrimes} 2621556Srgrimes 2631556Srgrimes/* 2641556Srgrimes * print [inode] [size] name 2651556Srgrimes * return # of characters printed, no trailing characters. 2661556Srgrimes */ 2671556Srgrimesstatic int 2681556Srgrimesprintaname(p, inodefield, sizefield) 2691556Srgrimes FTSENT *p; 2701556Srgrimes u_long sizefield, inodefield; 2711556Srgrimes{ 2721556Srgrimes struct stat *sp; 2731556Srgrimes int chcnt; 27461292Sache#ifdef COLORLS 27561292Sache int color_printed = 0; 27661292Sache#endif 2771556Srgrimes 2781556Srgrimes sp = p->fts_statp; 2791556Srgrimes chcnt = 0; 2801556Srgrimes if (f_inode) 28120417Ssteve chcnt += printf("%*lu ", (int)inodefield, (u_long)sp->st_ino); 2821556Srgrimes if (f_size) 2831556Srgrimes chcnt += printf("%*qd ", 2841556Srgrimes (int)sizefield, howmany(sp->st_blocks, blocksize)); 28561268Sjoe#ifdef COLORLS 28661178Sjoe if (f_color) 28761291Sache color_printed = colortype(sp->st_mode); 28861268Sjoe#endif 28935417Sdes chcnt += (f_octal || f_octal_escape) ? prn_octal(p->fts_name) 29035417Sdes : printf("%s", p->fts_name); 29161268Sjoe#ifdef COLORLS 29261291Sache if (f_color && color_printed) 29361268Sjoe endcolor(); 29461268Sjoe#endif 2951556Srgrimes if (f_type) 2961556Srgrimes chcnt += printtype(sp->st_mode); 2971556Srgrimes return (chcnt); 2981556Srgrimes} 2991556Srgrimes 3001556Srgrimesstatic void 3011556Srgrimesprinttime(ftime) 3021556Srgrimes time_t ftime; 3031556Srgrimes{ 3041556Srgrimes int i; 3059991Sache char longstring[80]; 30621545Smpp static time_t now; 3071556Srgrimes 30821545Smpp if (now == 0) 30921545Smpp now = time(NULL); 31021545Smpp 3119991Sache strftime(longstring, sizeof(longstring), "%c", localtime(&ftime)); 3121556Srgrimes for (i = 4; i < 11; ++i) 3131556Srgrimes (void)putchar(longstring[i]); 3141556Srgrimes 3159987Swollman#define SIXMONTHS ((365 / 2) * 86400) 3161556Srgrimes if (f_sectime) 3171556Srgrimes for (i = 11; i < 24; i++) 3181556Srgrimes (void)putchar(longstring[i]); 31921545Smpp else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS) 3201556Srgrimes for (i = 11; i < 16; ++i) 3211556Srgrimes (void)putchar(longstring[i]); 3221556Srgrimes else { 3231556Srgrimes (void)putchar(' '); 3241556Srgrimes for (i = 20; i < 24; ++i) 3251556Srgrimes (void)putchar(longstring[i]); 3261556Srgrimes } 3271556Srgrimes (void)putchar(' '); 3281556Srgrimes} 3291556Srgrimes 3301556Srgrimesstatic int 3311556Srgrimesprinttype(mode) 3321556Srgrimes u_int mode; 3331556Srgrimes{ 3341556Srgrimes switch (mode & S_IFMT) { 3351556Srgrimes case S_IFDIR: 3361556Srgrimes (void)putchar('/'); 3371556Srgrimes return (1); 3381556Srgrimes case S_IFIFO: 3391556Srgrimes (void)putchar('|'); 3401556Srgrimes return (1); 3411556Srgrimes case S_IFLNK: 3421556Srgrimes (void)putchar('@'); 3431556Srgrimes return (1); 3441556Srgrimes case S_IFSOCK: 3451556Srgrimes (void)putchar('='); 3461556Srgrimes return (1); 34720417Ssteve case S_IFWHT: 34820417Ssteve (void)putchar('%'); 34920417Ssteve return (1); 3501556Srgrimes } 3511556Srgrimes if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 3521556Srgrimes (void)putchar('*'); 3531556Srgrimes return (1); 3541556Srgrimes } 3551556Srgrimes return (0); 3561556Srgrimes} 3571556Srgrimes 35861268Sjoe#ifdef COLORLS 35961291Sacheint putch(c) 36061291Sache int c; 36161291Sache{ 36261291Sache return putc(c, stdout); 36361291Sache} 36461291Sache 36561291Sache 36661178Sjoevoid 36761178Sjoeprintcolor(c) 36861178Sjoe Colors c; 36961178Sjoe{ 37061268Sjoe char *ansiseq; 37161268Sjoe 37261178Sjoe if (colors[c][0] != -1) { 37361296Sache ansiseq = tgoto(ansi_fgcol, 0, colors[c][0]); 37461296Sache if (ansiseq && *ansiseq != 'O') /* "OOPS" */ 37561291Sache tputs(ansiseq, 1, putch); 37661178Sjoe } 37761268Sjoe 37861268Sjoe if (colors[c][1] != -1) { 37961296Sache ansiseq = tgoto(ansi_bgcol, 0, colors[c][1]); 38061296Sache if (ansiseq && *ansiseq != 'O') /* "OOPS" */ 38161291Sache tputs(ansiseq, 1, putch); 38261268Sjoe } 38361178Sjoe} 38461178Sjoe 38561268Sjoevoid 38661268Sjoeendcolor() 38761268Sjoe{ 38861291Sache tputs(ansi_coloff, 1, putch); 38961268Sjoe} 39061268Sjoe 39161178Sjoeint 39261178Sjoecolortype(mode) 39361178Sjoe mode_t mode; 39461178Sjoe{ 39561178Sjoe switch(mode & S_IFMT) { 39661178Sjoe case S_IFDIR: 39761178Sjoe if (mode & S_IWOTH) 39861178Sjoe if (mode & S_ISTXT) 39961178Sjoe printcolor(C_WSDIR); 40061178Sjoe else 40161178Sjoe printcolor(C_WDIR); 40261178Sjoe else 40361178Sjoe printcolor(C_DIR); 40461178Sjoe return(1); 40561178Sjoe case S_IFLNK: 40661178Sjoe printcolor(C_LNK); 40761178Sjoe return(1); 40861178Sjoe case S_IFSOCK: 40961178Sjoe printcolor(C_SOCK); 41061178Sjoe return(1); 41161178Sjoe case S_IFIFO: 41261178Sjoe printcolor(C_FIFO); 41361178Sjoe return(1); 41461178Sjoe case S_IFBLK: 41561178Sjoe printcolor(C_BLK); 41661178Sjoe return(1); 41761178Sjoe case S_IFCHR: 41861178Sjoe printcolor(C_CHR); 41961178Sjoe return(1); 42061178Sjoe } 42161178Sjoe if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 42261178Sjoe if (mode & S_ISUID) 42361178Sjoe printcolor(C_SUID); 42461178Sjoe else if (mode & S_ISGID) 42561178Sjoe printcolor(C_SGID); 42661178Sjoe else 42761178Sjoe printcolor(C_EXEC); 42861178Sjoe return(1); 42961178Sjoe } 43061178Sjoe return(0); 43161178Sjoe} 43261178Sjoe 43361178Sjoevoid 43461178Sjoeparsecolors(cs) 43561178Sjoechar *cs; 43661178Sjoe{ 43761178Sjoe int i, j, len; 43861178Sjoe char c[2]; 43961178Sjoe if (cs == NULL) cs = ""; /* LSCOLORS not set */ 44061178Sjoe len = strlen(cs); 44161178Sjoe for (i = 0 ; i < C_NUMCOLORS ; i++) { 44261178Sjoe if (len <= 2*i) { 44361178Sjoe c[0] = defcolors[2*i]; 44461178Sjoe c[1] = defcolors[2*i+1]; 44561178Sjoe } 44661178Sjoe else { 44761178Sjoe c[0] = cs[2*i]; 44861178Sjoe c[1] = cs[2*i+1]; 44961178Sjoe } 45061178Sjoe for (j = 0 ; j < 2 ; j++) { 45161178Sjoe if ((c[j] < '0' || c[j] > '7') && 45261291Sache tolower((unsigned char)c[j]) != 'x') { 45361178Sjoe fprintf(stderr, 45461178Sjoe "error: invalid character '%c' in LSCOLORS env var\n", 45561178Sjoe c[j]); 45661178Sjoe c[j] = defcolors[2*i+j]; 45761178Sjoe } 45861178Sjoe if (c[j] == 'x') 45961178Sjoe colors[i][j] = -1; 46061178Sjoe else 46161178Sjoe colors[i][j] = c[j]-'0'; 46261178Sjoe } 46361178Sjoe } 46461178Sjoe} 46561291Sache 46661291Sachevoid colorquit(sig) 46761291Sache int sig; 46861291Sache{ 46961291Sache endcolor(); 47061294Sache fflush(stdout); 47161294Sache 47261294Sache (void) signal(sig, SIG_DFL); 47361294Sache (void) kill(getpid(), sig); 47461291Sache} 47561268Sjoe#endif /*COLORLS*/ 47661178Sjoe 4771556Srgrimesstatic void 4781556Srgrimesprintlink(p) 4791556Srgrimes FTSENT *p; 4801556Srgrimes{ 4811556Srgrimes int lnklen; 4821556Srgrimes char name[MAXPATHLEN + 1], path[MAXPATHLEN + 1]; 4831556Srgrimes 4841556Srgrimes if (p->fts_level == FTS_ROOTLEVEL) 4851556Srgrimes (void)snprintf(name, sizeof(name), "%s", p->fts_name); 4868855Srgrimes else 4871556Srgrimes (void)snprintf(name, sizeof(name), 4881556Srgrimes "%s/%s", p->fts_parent->fts_accpath, p->fts_name); 4891556Srgrimes if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) { 4901556Srgrimes (void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno)); 4911556Srgrimes return; 4921556Srgrimes } 4931556Srgrimes path[lnklen] = '\0'; 49435417Sdes if (f_octal || f_octal_escape) { 49535417Sdes (void)printf(" -> "); 49635417Sdes (void)prn_octal(path); 49735373Sdes } 49835373Sdes else (void)printf(" -> %s", path); 4991556Srgrimes} 500