print.c revision 61321
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 61321 2000-06-06 06:52:03Z 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)); 7261321Sache#ifdef COLORLS 7361321Sachestatic void endcolor __P((int)); 7461321Sachestatic int colortype __P((mode_t)); 7561321Sache#endif 761556Srgrimes 771556Srgrimes#define IS_NOPRINT(p) ((p)->fts_number == NO_PRINT) 781556Srgrimes 7961268Sjoe#ifdef COLORLS 8061178Sjoe/* Most of these are taken from <sys/stat.h> */ 8161178Sjoetypedef enum Colors { 8261178Sjoe C_DIR, /* directory */ 8361178Sjoe C_LNK, /* symbolic link */ 8461178Sjoe C_SOCK, /* socket */ 8561178Sjoe C_FIFO, /* pipe */ 8661178Sjoe C_EXEC, /* executable */ 8761178Sjoe C_BLK, /* block special */ 8861178Sjoe C_CHR, /* character special */ 8961178Sjoe C_SUID, /* setuid executable */ 9061178Sjoe C_SGID, /* setgid executable */ 9161178Sjoe C_WSDIR, /* directory writeble to others, with sticky bit */ 9261178Sjoe C_WDIR, /* directory writeble to others, without sticky bit */ 9361178Sjoe C_NUMCOLORS /* just a place-holder */ 9461178Sjoe} Colors ; 9561178Sjoe 9661178Sjoechar *defcolors = "4x5x2x3x1x464301060203"; 9761178Sjoe 9861178Sjoestatic int colors[C_NUMCOLORS][2]; 9961268Sjoe#endif 10061178Sjoe 1011556Srgrimesvoid 1021556Srgrimesprintscol(dp) 1031556Srgrimes DISPLAY *dp; 1041556Srgrimes{ 1051556Srgrimes FTSENT *p; 1061556Srgrimes 1071556Srgrimes for (p = dp->list; p; p = p->fts_link) { 1081556Srgrimes if (IS_NOPRINT(p)) 1091556Srgrimes continue; 1101556Srgrimes (void)printaname(p, dp->s_inode, dp->s_block); 1111556Srgrimes (void)putchar('\n'); 1121556Srgrimes } 1131556Srgrimes} 1141556Srgrimes 1151556Srgrimesvoid 1161556Srgrimesprintlong(dp) 1171556Srgrimes DISPLAY *dp; 1181556Srgrimes{ 1191556Srgrimes struct stat *sp; 1201556Srgrimes FTSENT *p; 1211556Srgrimes NAMES *np; 1221556Srgrimes char buf[20]; 12361292Sache#ifdef COLORLS 12461292Sache int color_printed = 0; 12561292Sache#endif 1261556Srgrimes 1271556Srgrimes if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) 1281556Srgrimes (void)printf("total %lu\n", howmany(dp->btotal, blocksize)); 1291556Srgrimes 1301556Srgrimes for (p = dp->list; p; p = p->fts_link) { 1311556Srgrimes if (IS_NOPRINT(p)) 1321556Srgrimes continue; 1331556Srgrimes sp = p->fts_statp; 1341556Srgrimes if (f_inode) 13520417Ssteve (void)printf("%*lu ", dp->s_inode, (u_long)sp->st_ino); 1361556Srgrimes if (f_size) 1371556Srgrimes (void)printf("%*qd ", 1381556Srgrimes dp->s_block, howmany(sp->st_blocks, blocksize)); 1391556Srgrimes (void)strmode(sp->st_mode, buf); 1401556Srgrimes np = p->fts_pointer; 1411556Srgrimes (void)printf("%s %*u %-*s %-*s ", buf, dp->s_nlink, 1421556Srgrimes sp->st_nlink, dp->s_user, np->user, dp->s_group, 1431556Srgrimes np->group); 1441556Srgrimes if (f_flags) 1451556Srgrimes (void)printf("%-*s ", dp->s_flags, np->flags); 1461556Srgrimes if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode)) 14755514Sbde if (minor(sp->st_rdev) > 255 || minor(sp->st_rdev) < 0) 14813120Sjoerg (void)printf("%3d, 0x%08x ", 14955514Sbde major(sp->st_rdev), 15055514Sbde (u_int)minor(sp->st_rdev)); 15113120Sjoerg else 15213120Sjoerg (void)printf("%3d, %3d ", 15313120Sjoerg major(sp->st_rdev), minor(sp->st_rdev)); 1541556Srgrimes else if (dp->bcfile) 1551556Srgrimes (void)printf("%*s%*qd ", 1561556Srgrimes 8 - dp->s_size, "", dp->s_size, sp->st_size); 1571556Srgrimes else 1581556Srgrimes (void)printf("%*qd ", dp->s_size, sp->st_size); 1591556Srgrimes if (f_accesstime) 1601556Srgrimes printtime(sp->st_atime); 1611556Srgrimes else if (f_statustime) 1621556Srgrimes printtime(sp->st_ctime); 1631556Srgrimes else 1641556Srgrimes printtime(sp->st_mtime); 16561268Sjoe#ifdef COLORLS 16661178Sjoe if (f_color) 16761291Sache color_printed = colortype(sp->st_mode); 16861268Sjoe#endif 16935417Sdes if (f_octal || f_octal_escape) (void)prn_octal(p->fts_name); 17035373Sdes else (void)printf("%s", p->fts_name); 17161268Sjoe#ifdef COLORLS 17261291Sache if (f_color && color_printed) 17361321Sache endcolor(0); 17461268Sjoe#endif 1751556Srgrimes if (f_type) 1761556Srgrimes (void)printtype(sp->st_mode); 1771556Srgrimes if (S_ISLNK(sp->st_mode)) 1781556Srgrimes printlink(p); 1791556Srgrimes (void)putchar('\n'); 1801556Srgrimes } 1811556Srgrimes} 1821556Srgrimes 1831556Srgrimesvoid 1841556Srgrimesprintcol(dp) 1851556Srgrimes DISPLAY *dp; 1861556Srgrimes{ 1871556Srgrimes extern int termwidth; 1881556Srgrimes static FTSENT **array; 1891556Srgrimes static int lastentries = -1; 1901556Srgrimes FTSENT *p; 1911556Srgrimes int base, chcnt, cnt, col, colwidth, num; 1921556Srgrimes int endcol, numcols, numrows, row; 19337932Shoek int tabwidth; 1941556Srgrimes 19537932Shoek if (f_notabs) 19637932Shoek tabwidth = 1; 19737932Shoek else 19837932Shoek tabwidth = 8; 19937932Shoek 2001556Srgrimes /* 2011556Srgrimes * Have to do random access in the linked list -- build a table 2021556Srgrimes * of pointers. 2031556Srgrimes */ 2041556Srgrimes if (dp->entries > lastentries) { 2051556Srgrimes lastentries = dp->entries; 2061556Srgrimes if ((array = 2071556Srgrimes realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) { 2081556Srgrimes warn(NULL); 2091556Srgrimes printscol(dp); 2101556Srgrimes } 2111556Srgrimes } 2121556Srgrimes for (p = dp->list, num = 0; p; p = p->fts_link) 2131556Srgrimes if (p->fts_number != NO_PRINT) 2141556Srgrimes array[num++] = p; 2151556Srgrimes 2161556Srgrimes colwidth = dp->maxlen; 2171556Srgrimes if (f_inode) 2181556Srgrimes colwidth += dp->s_inode + 1; 2191556Srgrimes if (f_size) 2201556Srgrimes colwidth += dp->s_block + 1; 2211556Srgrimes if (f_type) 2221556Srgrimes colwidth += 1; 2231556Srgrimes 22437932Shoek colwidth = (colwidth + tabwidth) & ~(tabwidth - 1); 2251556Srgrimes if (termwidth < 2 * colwidth) { 2261556Srgrimes printscol(dp); 2271556Srgrimes return; 2281556Srgrimes } 2291556Srgrimes 2301556Srgrimes numcols = termwidth / colwidth; 2311556Srgrimes numrows = num / numcols; 2321556Srgrimes if (num % numcols) 2331556Srgrimes ++numrows; 2341556Srgrimes 2351556Srgrimes if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) 2361556Srgrimes (void)printf("total %lu\n", howmany(dp->btotal, blocksize)); 2371556Srgrimes for (row = 0; row < numrows; ++row) { 2381556Srgrimes endcol = colwidth; 2391556Srgrimes for (base = row, chcnt = col = 0; col < numcols; ++col) { 2401556Srgrimes chcnt += printaname(array[base], dp->s_inode, 2411556Srgrimes dp->s_block); 2421556Srgrimes if ((base += numrows) >= num) 2431556Srgrimes break; 24461268Sjoe#ifdef COLORLS 24561178Sjoe /* 24661178Sjoe * some terminals get confused if we mix tabs 24761178Sjoe * with color sequences 24861178Sjoe */ 24961178Sjoe if (f_color) 25061178Sjoe while ((cnt = (chcnt + 1)) <= endcol) { 25161178Sjoe (void)putchar(' '); 25261178Sjoe chcnt = cnt; 25361178Sjoe } 25461178Sjoe else 25561268Sjoe#endif 25637932Shoek while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1))) 25737932Shoek <= endcol){ 25837932Shoek (void)putchar(f_notabs ? ' ' : '\t'); 2591556Srgrimes chcnt = cnt; 2601556Srgrimes } 2611556Srgrimes endcol += colwidth; 2621556Srgrimes } 2631556Srgrimes (void)putchar('\n'); 2641556Srgrimes } 2651556Srgrimes} 2661556Srgrimes 2671556Srgrimes/* 2681556Srgrimes * print [inode] [size] name 2691556Srgrimes * return # of characters printed, no trailing characters. 2701556Srgrimes */ 2711556Srgrimesstatic int 2721556Srgrimesprintaname(p, inodefield, sizefield) 2731556Srgrimes FTSENT *p; 2741556Srgrimes u_long sizefield, inodefield; 2751556Srgrimes{ 2761556Srgrimes struct stat *sp; 2771556Srgrimes int chcnt; 27861292Sache#ifdef COLORLS 27961292Sache int color_printed = 0; 28061292Sache#endif 2811556Srgrimes 2821556Srgrimes sp = p->fts_statp; 2831556Srgrimes chcnt = 0; 2841556Srgrimes if (f_inode) 28520417Ssteve chcnt += printf("%*lu ", (int)inodefield, (u_long)sp->st_ino); 2861556Srgrimes if (f_size) 2871556Srgrimes chcnt += printf("%*qd ", 2881556Srgrimes (int)sizefield, howmany(sp->st_blocks, blocksize)); 28961268Sjoe#ifdef COLORLS 29061178Sjoe if (f_color) 29161291Sache color_printed = colortype(sp->st_mode); 29261268Sjoe#endif 29335417Sdes chcnt += (f_octal || f_octal_escape) ? prn_octal(p->fts_name) 29435417Sdes : printf("%s", p->fts_name); 29561268Sjoe#ifdef COLORLS 29661291Sache if (f_color && color_printed) 29761321Sache endcolor(0); 29861268Sjoe#endif 2991556Srgrimes if (f_type) 3001556Srgrimes chcnt += printtype(sp->st_mode); 3011556Srgrimes return (chcnt); 3021556Srgrimes} 3031556Srgrimes 3041556Srgrimesstatic void 3051556Srgrimesprinttime(ftime) 3061556Srgrimes time_t ftime; 3071556Srgrimes{ 3081556Srgrimes int i; 3099991Sache char longstring[80]; 31021545Smpp static time_t now; 3111556Srgrimes 31221545Smpp if (now == 0) 31321545Smpp now = time(NULL); 31421545Smpp 3159991Sache strftime(longstring, sizeof(longstring), "%c", localtime(&ftime)); 3161556Srgrimes for (i = 4; i < 11; ++i) 3171556Srgrimes (void)putchar(longstring[i]); 3181556Srgrimes 3199987Swollman#define SIXMONTHS ((365 / 2) * 86400) 3201556Srgrimes if (f_sectime) 3211556Srgrimes for (i = 11; i < 24; i++) 3221556Srgrimes (void)putchar(longstring[i]); 32321545Smpp else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS) 3241556Srgrimes for (i = 11; i < 16; ++i) 3251556Srgrimes (void)putchar(longstring[i]); 3261556Srgrimes else { 3271556Srgrimes (void)putchar(' '); 3281556Srgrimes for (i = 20; i < 24; ++i) 3291556Srgrimes (void)putchar(longstring[i]); 3301556Srgrimes } 3311556Srgrimes (void)putchar(' '); 3321556Srgrimes} 3331556Srgrimes 3341556Srgrimesstatic int 3351556Srgrimesprinttype(mode) 3361556Srgrimes u_int mode; 3371556Srgrimes{ 3381556Srgrimes switch (mode & S_IFMT) { 3391556Srgrimes case S_IFDIR: 3401556Srgrimes (void)putchar('/'); 3411556Srgrimes return (1); 3421556Srgrimes case S_IFIFO: 3431556Srgrimes (void)putchar('|'); 3441556Srgrimes return (1); 3451556Srgrimes case S_IFLNK: 3461556Srgrimes (void)putchar('@'); 3471556Srgrimes return (1); 3481556Srgrimes case S_IFSOCK: 3491556Srgrimes (void)putchar('='); 3501556Srgrimes return (1); 35120417Ssteve case S_IFWHT: 35220417Ssteve (void)putchar('%'); 35320417Ssteve return (1); 3541556Srgrimes } 3551556Srgrimes if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 3561556Srgrimes (void)putchar('*'); 3571556Srgrimes return (1); 3581556Srgrimes } 3591556Srgrimes return (0); 3601556Srgrimes} 3611556Srgrimes 36261268Sjoe#ifdef COLORLS 36361291Sacheint putch(c) 36461291Sache int c; 36561291Sache{ 36661321Sache (void) putchar(c); 36761321Sache return 0; 36861291Sache} 36961291Sache 37061321Sacheint writech(c) 37161321Sache int c; 37261321Sache{ 37361321Sache char tmp = c; 37461291Sache 37561321Sache (void) write(STDOUT_FILENO, &tmp, 1); 37661321Sache return 0; 37761321Sache} 37861321Sache 37961178Sjoevoid 38061178Sjoeprintcolor(c) 38161178Sjoe Colors c; 38261178Sjoe{ 38361268Sjoe char *ansiseq; 38461268Sjoe 38561178Sjoe if (colors[c][0] != -1) { 38661296Sache ansiseq = tgoto(ansi_fgcol, 0, colors[c][0]); 38761321Sache if (ansiseq) 38861291Sache tputs(ansiseq, 1, putch); 38961178Sjoe } 39061268Sjoe 39161268Sjoe if (colors[c][1] != -1) { 39261296Sache ansiseq = tgoto(ansi_bgcol, 0, colors[c][1]); 39361321Sache if (ansiseq) 39461291Sache tputs(ansiseq, 1, putch); 39561268Sjoe } 39661178Sjoe} 39761178Sjoe 39861321Sachestatic void 39961321Sacheendcolor(sig) 40061321Sache int sig; 40161268Sjoe{ 40261321Sache tputs(ansi_coloff, 1, sig ? writech : putch); 40361268Sjoe} 40461268Sjoe 40561321Sachestatic int 40661178Sjoecolortype(mode) 40761178Sjoe mode_t mode; 40861178Sjoe{ 40961178Sjoe switch(mode & S_IFMT) { 41061178Sjoe case S_IFDIR: 41161178Sjoe if (mode & S_IWOTH) 41261178Sjoe if (mode & S_ISTXT) 41361178Sjoe printcolor(C_WSDIR); 41461178Sjoe else 41561178Sjoe printcolor(C_WDIR); 41661178Sjoe else 41761178Sjoe printcolor(C_DIR); 41861178Sjoe return(1); 41961178Sjoe case S_IFLNK: 42061178Sjoe printcolor(C_LNK); 42161178Sjoe return(1); 42261178Sjoe case S_IFSOCK: 42361178Sjoe printcolor(C_SOCK); 42461178Sjoe return(1); 42561178Sjoe case S_IFIFO: 42661178Sjoe printcolor(C_FIFO); 42761178Sjoe return(1); 42861178Sjoe case S_IFBLK: 42961178Sjoe printcolor(C_BLK); 43061178Sjoe return(1); 43161178Sjoe case S_IFCHR: 43261178Sjoe printcolor(C_CHR); 43361178Sjoe return(1); 43461178Sjoe } 43561178Sjoe if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 43661178Sjoe if (mode & S_ISUID) 43761178Sjoe printcolor(C_SUID); 43861178Sjoe else if (mode & S_ISGID) 43961178Sjoe printcolor(C_SGID); 44061178Sjoe else 44161178Sjoe printcolor(C_EXEC); 44261178Sjoe return(1); 44361178Sjoe } 44461178Sjoe return(0); 44561178Sjoe} 44661178Sjoe 44761178Sjoevoid 44861178Sjoeparsecolors(cs) 44961178Sjoechar *cs; 45061178Sjoe{ 45161178Sjoe int i, j, len; 45261178Sjoe char c[2]; 45361321Sache 45461178Sjoe if (cs == NULL) cs = ""; /* LSCOLORS not set */ 45561178Sjoe len = strlen(cs); 45661178Sjoe for (i = 0 ; i < C_NUMCOLORS ; i++) { 45761178Sjoe if (len <= 2*i) { 45861178Sjoe c[0] = defcolors[2*i]; 45961178Sjoe c[1] = defcolors[2*i+1]; 46061178Sjoe } 46161178Sjoe else { 46261178Sjoe c[0] = cs[2*i]; 46361178Sjoe c[1] = cs[2*i+1]; 46461178Sjoe } 46561178Sjoe for (j = 0 ; j < 2 ; j++) { 46661178Sjoe if ((c[j] < '0' || c[j] > '7') && 46761291Sache tolower((unsigned char)c[j]) != 'x') { 46861178Sjoe fprintf(stderr, 46961178Sjoe "error: invalid character '%c' in LSCOLORS env var\n", 47061178Sjoe c[j]); 47161178Sjoe c[j] = defcolors[2*i+j]; 47261178Sjoe } 47361321Sache if (tolower((unsigned char)c[j]) == 'x') 47461178Sjoe colors[i][j] = -1; 47561178Sjoe else 47661178Sjoe colors[i][j] = c[j]-'0'; 47761178Sjoe } 47861178Sjoe } 47961178Sjoe} 48061291Sache 48161291Sachevoid colorquit(sig) 48261291Sache int sig; 48361291Sache{ 48461321Sache endcolor(sig); 48561294Sache 48661294Sache (void) signal(sig, SIG_DFL); 48761294Sache (void) kill(getpid(), sig); 48861291Sache} 48961268Sjoe#endif /*COLORLS*/ 49061178Sjoe 4911556Srgrimesstatic void 4921556Srgrimesprintlink(p) 4931556Srgrimes FTSENT *p; 4941556Srgrimes{ 4951556Srgrimes int lnklen; 4961556Srgrimes char name[MAXPATHLEN + 1], path[MAXPATHLEN + 1]; 4971556Srgrimes 4981556Srgrimes if (p->fts_level == FTS_ROOTLEVEL) 4991556Srgrimes (void)snprintf(name, sizeof(name), "%s", p->fts_name); 5008855Srgrimes else 5011556Srgrimes (void)snprintf(name, sizeof(name), 5021556Srgrimes "%s/%s", p->fts_parent->fts_accpath, p->fts_name); 5031556Srgrimes if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) { 5041556Srgrimes (void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno)); 5051556Srgrimes return; 5061556Srgrimes } 5071556Srgrimes path[lnklen] = '\0'; 50835417Sdes if (f_octal || f_octal_escape) { 50935417Sdes (void)printf(" -> "); 51035417Sdes (void)prn_octal(path); 51135373Sdes } 51235373Sdes else (void)printf(" -> %s", path); 5131556Srgrimes} 514