print.c revision 62597
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 62597 2000-07-04 23:09:23Z assar $"; 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 11562597Sassar/* 11662597Sassar * print name in current style 11762597Sassar */ 11862597Sassarstatic int 11962597Sassarprintname(name) 12062597Sassar const char *name; 12162597Sassar{ 12262597Sassar if (f_octal || f_octal_escape) 12362597Sassar return prn_octal(name); 12462597Sassar else if (f_nonprint) 12562597Sassar return prn_printable(name); 12662597Sassar else 12762597Sassar return printf("%s", name); 12862597Sassar} 12962597Sassar 1301556Srgrimesvoid 1311556Srgrimesprintlong(dp) 1321556Srgrimes DISPLAY *dp; 1331556Srgrimes{ 1341556Srgrimes struct stat *sp; 1351556Srgrimes FTSENT *p; 1361556Srgrimes NAMES *np; 1371556Srgrimes char buf[20]; 13861292Sache#ifdef COLORLS 13961292Sache int color_printed = 0; 14061292Sache#endif 1411556Srgrimes 1421556Srgrimes if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) 1431556Srgrimes (void)printf("total %lu\n", howmany(dp->btotal, blocksize)); 1441556Srgrimes 1451556Srgrimes for (p = dp->list; p; p = p->fts_link) { 1461556Srgrimes if (IS_NOPRINT(p)) 1471556Srgrimes continue; 1481556Srgrimes sp = p->fts_statp; 1491556Srgrimes if (f_inode) 15020417Ssteve (void)printf("%*lu ", dp->s_inode, (u_long)sp->st_ino); 1511556Srgrimes if (f_size) 1521556Srgrimes (void)printf("%*qd ", 1531556Srgrimes dp->s_block, howmany(sp->st_blocks, blocksize)); 1541556Srgrimes (void)strmode(sp->st_mode, buf); 1551556Srgrimes np = p->fts_pointer; 1561556Srgrimes (void)printf("%s %*u %-*s %-*s ", buf, dp->s_nlink, 1571556Srgrimes sp->st_nlink, dp->s_user, np->user, dp->s_group, 1581556Srgrimes np->group); 1591556Srgrimes if (f_flags) 1601556Srgrimes (void)printf("%-*s ", dp->s_flags, np->flags); 1611556Srgrimes if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode)) 16255514Sbde if (minor(sp->st_rdev) > 255 || minor(sp->st_rdev) < 0) 16313120Sjoerg (void)printf("%3d, 0x%08x ", 16455514Sbde major(sp->st_rdev), 16555514Sbde (u_int)minor(sp->st_rdev)); 16613120Sjoerg else 16713120Sjoerg (void)printf("%3d, %3d ", 16813120Sjoerg major(sp->st_rdev), minor(sp->st_rdev)); 1691556Srgrimes else if (dp->bcfile) 1701556Srgrimes (void)printf("%*s%*qd ", 1711556Srgrimes 8 - dp->s_size, "", dp->s_size, sp->st_size); 1721556Srgrimes else 1731556Srgrimes (void)printf("%*qd ", dp->s_size, sp->st_size); 1741556Srgrimes if (f_accesstime) 1751556Srgrimes printtime(sp->st_atime); 1761556Srgrimes else if (f_statustime) 1771556Srgrimes printtime(sp->st_ctime); 1781556Srgrimes else 1791556Srgrimes printtime(sp->st_mtime); 18061268Sjoe#ifdef COLORLS 18161178Sjoe if (f_color) 18261291Sache color_printed = colortype(sp->st_mode); 18361268Sjoe#endif 18462597Sassar (void)printname(p->fts_name); 18561268Sjoe#ifdef COLORLS 18661291Sache if (f_color && color_printed) 18761321Sache endcolor(0); 18861268Sjoe#endif 1891556Srgrimes if (f_type) 1901556Srgrimes (void)printtype(sp->st_mode); 1911556Srgrimes if (S_ISLNK(sp->st_mode)) 1921556Srgrimes printlink(p); 1931556Srgrimes (void)putchar('\n'); 1941556Srgrimes } 1951556Srgrimes} 1961556Srgrimes 1971556Srgrimesvoid 1981556Srgrimesprintcol(dp) 1991556Srgrimes DISPLAY *dp; 2001556Srgrimes{ 2011556Srgrimes extern int termwidth; 2021556Srgrimes static FTSENT **array; 2031556Srgrimes static int lastentries = -1; 2041556Srgrimes FTSENT *p; 2051556Srgrimes int base, chcnt, cnt, col, colwidth, num; 2061556Srgrimes int endcol, numcols, numrows, row; 20737932Shoek int tabwidth; 2081556Srgrimes 20937932Shoek if (f_notabs) 21037932Shoek tabwidth = 1; 21137932Shoek else 21237932Shoek tabwidth = 8; 21337932Shoek 2141556Srgrimes /* 2151556Srgrimes * Have to do random access in the linked list -- build a table 2161556Srgrimes * of pointers. 2171556Srgrimes */ 2181556Srgrimes if (dp->entries > lastentries) { 2191556Srgrimes lastentries = dp->entries; 2201556Srgrimes if ((array = 2211556Srgrimes realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) { 2221556Srgrimes warn(NULL); 2231556Srgrimes printscol(dp); 2241556Srgrimes } 2251556Srgrimes } 2261556Srgrimes for (p = dp->list, num = 0; p; p = p->fts_link) 2271556Srgrimes if (p->fts_number != NO_PRINT) 2281556Srgrimes array[num++] = p; 2291556Srgrimes 2301556Srgrimes colwidth = dp->maxlen; 2311556Srgrimes if (f_inode) 2321556Srgrimes colwidth += dp->s_inode + 1; 2331556Srgrimes if (f_size) 2341556Srgrimes colwidth += dp->s_block + 1; 2351556Srgrimes if (f_type) 2361556Srgrimes colwidth += 1; 2371556Srgrimes 23837932Shoek colwidth = (colwidth + tabwidth) & ~(tabwidth - 1); 2391556Srgrimes if (termwidth < 2 * colwidth) { 2401556Srgrimes printscol(dp); 2411556Srgrimes return; 2421556Srgrimes } 2431556Srgrimes 2441556Srgrimes numcols = termwidth / colwidth; 2451556Srgrimes numrows = num / numcols; 2461556Srgrimes if (num % numcols) 2471556Srgrimes ++numrows; 2481556Srgrimes 2491556Srgrimes if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) 2501556Srgrimes (void)printf("total %lu\n", howmany(dp->btotal, blocksize)); 2511556Srgrimes for (row = 0; row < numrows; ++row) { 2521556Srgrimes endcol = colwidth; 2531556Srgrimes for (base = row, chcnt = col = 0; col < numcols; ++col) { 2541556Srgrimes chcnt += printaname(array[base], dp->s_inode, 2551556Srgrimes dp->s_block); 2561556Srgrimes if ((base += numrows) >= num) 2571556Srgrimes break; 25837932Shoek while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1))) 25937932Shoek <= endcol){ 26037932Shoek (void)putchar(f_notabs ? ' ' : '\t'); 2611556Srgrimes chcnt = cnt; 2621556Srgrimes } 2631556Srgrimes endcol += colwidth; 2641556Srgrimes } 2651556Srgrimes (void)putchar('\n'); 2661556Srgrimes } 2671556Srgrimes} 2681556Srgrimes 2691556Srgrimes/* 2701556Srgrimes * print [inode] [size] name 2711556Srgrimes * return # of characters printed, no trailing characters. 2721556Srgrimes */ 2731556Srgrimesstatic int 2741556Srgrimesprintaname(p, inodefield, sizefield) 2751556Srgrimes FTSENT *p; 2761556Srgrimes u_long sizefield, inodefield; 2771556Srgrimes{ 2781556Srgrimes struct stat *sp; 2791556Srgrimes int chcnt; 28061292Sache#ifdef COLORLS 28161292Sache int color_printed = 0; 28261292Sache#endif 2831556Srgrimes 2841556Srgrimes sp = p->fts_statp; 2851556Srgrimes chcnt = 0; 2861556Srgrimes if (f_inode) 28720417Ssteve chcnt += printf("%*lu ", (int)inodefield, (u_long)sp->st_ino); 2881556Srgrimes if (f_size) 2891556Srgrimes chcnt += printf("%*qd ", 2901556Srgrimes (int)sizefield, howmany(sp->st_blocks, blocksize)); 29161268Sjoe#ifdef COLORLS 29261178Sjoe if (f_color) 29361291Sache color_printed = colortype(sp->st_mode); 29461268Sjoe#endif 29562597Sassar chcnt += printname(p->fts_name); 29661268Sjoe#ifdef COLORLS 29761291Sache if (f_color && color_printed) 29861321Sache endcolor(0); 29961268Sjoe#endif 3001556Srgrimes if (f_type) 3011556Srgrimes chcnt += printtype(sp->st_mode); 3021556Srgrimes return (chcnt); 3031556Srgrimes} 3041556Srgrimes 3051556Srgrimesstatic void 3061556Srgrimesprinttime(ftime) 3071556Srgrimes time_t ftime; 3081556Srgrimes{ 3099991Sache char longstring[80]; 31021545Smpp static time_t now; 31161814Sjoe const char *format; 3121556Srgrimes 31321545Smpp if (now == 0) 31421545Smpp now = time(NULL); 31521545Smpp 3169987Swollman#define SIXMONTHS ((365 / 2) * 86400) 31761920Sjoe /* "%Ef" is a FreeBSD strftime definition for "%e %b" or "%b %e". 31861920Sjoe * Actually format is locale sensitive. 31961920Sjoe */ 3201556Srgrimes if (f_sectime) 32161920Sjoe /* mmm dd hh:mm:ss yyyy || dd mmm hh:mm:ss yyyy */ 32261920Sjoe format = "%Ef %T %Y "; 32321545Smpp else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS) 32461920Sjoe /* mmm dd hh:mm || dd mmm hh:mm */ 32561920Sjoe format = "%Ef %R "; 32661814Sjoe else 32761920Sjoe /* mmm dd yyyy || dd mmm yyyy */ 32861920Sjoe format = "%Ef %Y "; 32961814Sjoe strftime(longstring, sizeof(longstring), format, localtime(&ftime)); 33061814Sjoe fputs(longstring, stdout); 3311556Srgrimes} 3321556Srgrimes 3331556Srgrimesstatic int 3341556Srgrimesprinttype(mode) 3351556Srgrimes u_int mode; 3361556Srgrimes{ 3371556Srgrimes switch (mode & S_IFMT) { 3381556Srgrimes case S_IFDIR: 3391556Srgrimes (void)putchar('/'); 3401556Srgrimes return (1); 3411556Srgrimes case S_IFIFO: 3421556Srgrimes (void)putchar('|'); 3431556Srgrimes return (1); 3441556Srgrimes case S_IFLNK: 3451556Srgrimes (void)putchar('@'); 3461556Srgrimes return (1); 3471556Srgrimes case S_IFSOCK: 3481556Srgrimes (void)putchar('='); 3491556Srgrimes return (1); 35020417Ssteve case S_IFWHT: 35120417Ssteve (void)putchar('%'); 35220417Ssteve return (1); 3531556Srgrimes } 3541556Srgrimes if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 3551556Srgrimes (void)putchar('*'); 3561556Srgrimes return (1); 3571556Srgrimes } 3581556Srgrimes return (0); 3591556Srgrimes} 3601556Srgrimes 36161268Sjoe#ifdef COLORLS 36261323Sachestatic int 36361323Sacheputch(c) 36461291Sache int c; 36561291Sache{ 36661321Sache (void) putchar(c); 36761321Sache return 0; 36861291Sache} 36961291Sache 37061323Sachestatic int 37161323Sachewritech(c) 37261321Sache int c; 37361321Sache{ 37461321Sache char tmp = c; 37561291Sache 37661321Sache (void) write(STDOUT_FILENO, &tmp, 1); 37761321Sache return 0; 37861321Sache} 37961321Sache 38061323Sachestatic void 38161178Sjoeprintcolor(c) 38261178Sjoe Colors c; 38361178Sjoe{ 38461268Sjoe char *ansiseq; 38561268Sjoe 38661178Sjoe if (colors[c][0] != -1) { 38761296Sache ansiseq = tgoto(ansi_fgcol, 0, colors[c][0]); 38861321Sache if (ansiseq) 38961291Sache tputs(ansiseq, 1, putch); 39061178Sjoe } 39161268Sjoe 39261268Sjoe if (colors[c][1] != -1) { 39361296Sache ansiseq = tgoto(ansi_bgcol, 0, colors[c][1]); 39461321Sache if (ansiseq) 39561291Sache tputs(ansiseq, 1, putch); 39661268Sjoe } 39761178Sjoe} 39861178Sjoe 39961321Sachestatic void 40061321Sacheendcolor(sig) 40161321Sache int sig; 40261268Sjoe{ 40361321Sache tputs(ansi_coloff, 1, sig ? writech : putch); 40461268Sjoe} 40561268Sjoe 40661321Sachestatic int 40761178Sjoecolortype(mode) 40861178Sjoe mode_t mode; 40961178Sjoe{ 41061178Sjoe switch(mode & S_IFMT) { 41161178Sjoe case S_IFDIR: 41261178Sjoe if (mode & S_IWOTH) 41361178Sjoe if (mode & S_ISTXT) 41461178Sjoe printcolor(C_WSDIR); 41561178Sjoe else 41661178Sjoe printcolor(C_WDIR); 41761178Sjoe else 41861178Sjoe printcolor(C_DIR); 41961178Sjoe return(1); 42061178Sjoe case S_IFLNK: 42161178Sjoe printcolor(C_LNK); 42261178Sjoe return(1); 42361178Sjoe case S_IFSOCK: 42461178Sjoe printcolor(C_SOCK); 42561178Sjoe return(1); 42661178Sjoe case S_IFIFO: 42761178Sjoe printcolor(C_FIFO); 42861178Sjoe return(1); 42961178Sjoe case S_IFBLK: 43061178Sjoe printcolor(C_BLK); 43161178Sjoe return(1); 43261178Sjoe case S_IFCHR: 43361178Sjoe printcolor(C_CHR); 43461178Sjoe return(1); 43561178Sjoe } 43661178Sjoe if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 43761178Sjoe if (mode & S_ISUID) 43861178Sjoe printcolor(C_SUID); 43961178Sjoe else if (mode & S_ISGID) 44061178Sjoe printcolor(C_SGID); 44161178Sjoe else 44261178Sjoe printcolor(C_EXEC); 44361178Sjoe return(1); 44461178Sjoe } 44561178Sjoe return(0); 44661178Sjoe} 44761178Sjoe 44861178Sjoevoid 44961178Sjoeparsecolors(cs) 45061178Sjoechar *cs; 45161178Sjoe{ 45261178Sjoe int i, j, len; 45361178Sjoe char c[2]; 45461321Sache 45561178Sjoe if (cs == NULL) cs = ""; /* LSCOLORS not set */ 45661178Sjoe len = strlen(cs); 45761178Sjoe for (i = 0 ; i < C_NUMCOLORS ; i++) { 45861178Sjoe if (len <= 2*i) { 45961178Sjoe c[0] = defcolors[2*i]; 46061178Sjoe c[1] = defcolors[2*i+1]; 46161178Sjoe } 46261178Sjoe else { 46361178Sjoe c[0] = cs[2*i]; 46461178Sjoe c[1] = cs[2*i+1]; 46561178Sjoe } 46661178Sjoe for (j = 0 ; j < 2 ; j++) { 46761178Sjoe if ((c[j] < '0' || c[j] > '7') && 46861291Sache tolower((unsigned char)c[j]) != 'x') { 46961178Sjoe fprintf(stderr, 47061178Sjoe "error: invalid character '%c' in LSCOLORS env var\n", 47161178Sjoe c[j]); 47261178Sjoe c[j] = defcolors[2*i+j]; 47361178Sjoe } 47461321Sache if (tolower((unsigned char)c[j]) == 'x') 47561178Sjoe colors[i][j] = -1; 47661178Sjoe else 47761178Sjoe colors[i][j] = c[j]-'0'; 47861178Sjoe } 47961178Sjoe } 48061178Sjoe} 48161291Sache 48261323Sachevoid 48361323Sachecolorquit(sig) 48461291Sache int sig; 48561291Sache{ 48661321Sache endcolor(sig); 48761294Sache 48861294Sache (void) signal(sig, SIG_DFL); 48961294Sache (void) kill(getpid(), sig); 49061291Sache} 49161268Sjoe#endif /*COLORLS*/ 49261178Sjoe 4931556Srgrimesstatic void 4941556Srgrimesprintlink(p) 4951556Srgrimes FTSENT *p; 4961556Srgrimes{ 4971556Srgrimes int lnklen; 4981556Srgrimes char name[MAXPATHLEN + 1], path[MAXPATHLEN + 1]; 4991556Srgrimes 5001556Srgrimes if (p->fts_level == FTS_ROOTLEVEL) 5011556Srgrimes (void)snprintf(name, sizeof(name), "%s", p->fts_name); 5028855Srgrimes else 5031556Srgrimes (void)snprintf(name, sizeof(name), 5041556Srgrimes "%s/%s", p->fts_parent->fts_accpath, p->fts_name); 5051556Srgrimes if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) { 5061556Srgrimes (void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno)); 5071556Srgrimes return; 5081556Srgrimes } 5091556Srgrimes path[lnklen] = '\0'; 51062597Sassar (void)printf(" -> "); 51162597Sassar printname(path); 5121556Srgrimes} 513