print.c revision 61920
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 61920 2000-06-21 21:49:57Z joe $"; 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; 24437932Shoek while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1))) 24537932Shoek <= endcol){ 24637932Shoek (void)putchar(f_notabs ? ' ' : '\t'); 2471556Srgrimes chcnt = cnt; 2481556Srgrimes } 2491556Srgrimes endcol += colwidth; 2501556Srgrimes } 2511556Srgrimes (void)putchar('\n'); 2521556Srgrimes } 2531556Srgrimes} 2541556Srgrimes 2551556Srgrimes/* 2561556Srgrimes * print [inode] [size] name 2571556Srgrimes * return # of characters printed, no trailing characters. 2581556Srgrimes */ 2591556Srgrimesstatic int 2601556Srgrimesprintaname(p, inodefield, sizefield) 2611556Srgrimes FTSENT *p; 2621556Srgrimes u_long sizefield, inodefield; 2631556Srgrimes{ 2641556Srgrimes struct stat *sp; 2651556Srgrimes int chcnt; 26661292Sache#ifdef COLORLS 26761292Sache int color_printed = 0; 26861292Sache#endif 2691556Srgrimes 2701556Srgrimes sp = p->fts_statp; 2711556Srgrimes chcnt = 0; 2721556Srgrimes if (f_inode) 27320417Ssteve chcnt += printf("%*lu ", (int)inodefield, (u_long)sp->st_ino); 2741556Srgrimes if (f_size) 2751556Srgrimes chcnt += printf("%*qd ", 2761556Srgrimes (int)sizefield, howmany(sp->st_blocks, blocksize)); 27761268Sjoe#ifdef COLORLS 27861178Sjoe if (f_color) 27961291Sache color_printed = colortype(sp->st_mode); 28061268Sjoe#endif 28135417Sdes chcnt += (f_octal || f_octal_escape) ? prn_octal(p->fts_name) 28235417Sdes : printf("%s", p->fts_name); 28361268Sjoe#ifdef COLORLS 28461291Sache if (f_color && color_printed) 28561321Sache endcolor(0); 28661268Sjoe#endif 2871556Srgrimes if (f_type) 2881556Srgrimes chcnt += printtype(sp->st_mode); 2891556Srgrimes return (chcnt); 2901556Srgrimes} 2911556Srgrimes 2921556Srgrimesstatic void 2931556Srgrimesprinttime(ftime) 2941556Srgrimes time_t ftime; 2951556Srgrimes{ 2969991Sache char longstring[80]; 29721545Smpp static time_t now; 29861814Sjoe const char *format; 2991556Srgrimes 30021545Smpp if (now == 0) 30121545Smpp now = time(NULL); 30221545Smpp 3039987Swollman#define SIXMONTHS ((365 / 2) * 86400) 30461920Sjoe /* "%Ef" is a FreeBSD strftime definition for "%e %b" or "%b %e". 30561920Sjoe * Actually format is locale sensitive. 30661920Sjoe */ 3071556Srgrimes if (f_sectime) 30861920Sjoe /* mmm dd hh:mm:ss yyyy || dd mmm hh:mm:ss yyyy */ 30961920Sjoe format = "%Ef %T %Y "; 31021545Smpp else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS) 31161920Sjoe /* mmm dd hh:mm || dd mmm hh:mm */ 31261920Sjoe format = "%Ef %R "; 31361814Sjoe else 31461920Sjoe /* mmm dd yyyy || dd mmm yyyy */ 31561920Sjoe format = "%Ef %Y "; 31661814Sjoe strftime(longstring, sizeof(longstring), format, localtime(&ftime)); 31761814Sjoe fputs(longstring, stdout); 3181556Srgrimes} 3191556Srgrimes 3201556Srgrimesstatic int 3211556Srgrimesprinttype(mode) 3221556Srgrimes u_int mode; 3231556Srgrimes{ 3241556Srgrimes switch (mode & S_IFMT) { 3251556Srgrimes case S_IFDIR: 3261556Srgrimes (void)putchar('/'); 3271556Srgrimes return (1); 3281556Srgrimes case S_IFIFO: 3291556Srgrimes (void)putchar('|'); 3301556Srgrimes return (1); 3311556Srgrimes case S_IFLNK: 3321556Srgrimes (void)putchar('@'); 3331556Srgrimes return (1); 3341556Srgrimes case S_IFSOCK: 3351556Srgrimes (void)putchar('='); 3361556Srgrimes return (1); 33720417Ssteve case S_IFWHT: 33820417Ssteve (void)putchar('%'); 33920417Ssteve return (1); 3401556Srgrimes } 3411556Srgrimes if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 3421556Srgrimes (void)putchar('*'); 3431556Srgrimes return (1); 3441556Srgrimes } 3451556Srgrimes return (0); 3461556Srgrimes} 3471556Srgrimes 34861268Sjoe#ifdef COLORLS 34961323Sachestatic int 35061323Sacheputch(c) 35161291Sache int c; 35261291Sache{ 35361321Sache (void) putchar(c); 35461321Sache return 0; 35561291Sache} 35661291Sache 35761323Sachestatic int 35861323Sachewritech(c) 35961321Sache int c; 36061321Sache{ 36161321Sache char tmp = c; 36261291Sache 36361321Sache (void) write(STDOUT_FILENO, &tmp, 1); 36461321Sache return 0; 36561321Sache} 36661321Sache 36761323Sachestatic void 36861178Sjoeprintcolor(c) 36961178Sjoe Colors c; 37061178Sjoe{ 37161268Sjoe char *ansiseq; 37261268Sjoe 37361178Sjoe if (colors[c][0] != -1) { 37461296Sache ansiseq = tgoto(ansi_fgcol, 0, colors[c][0]); 37561321Sache if (ansiseq) 37661291Sache tputs(ansiseq, 1, putch); 37761178Sjoe } 37861268Sjoe 37961268Sjoe if (colors[c][1] != -1) { 38061296Sache ansiseq = tgoto(ansi_bgcol, 0, colors[c][1]); 38161321Sache if (ansiseq) 38261291Sache tputs(ansiseq, 1, putch); 38361268Sjoe } 38461178Sjoe} 38561178Sjoe 38661321Sachestatic void 38761321Sacheendcolor(sig) 38861321Sache int sig; 38961268Sjoe{ 39061321Sache tputs(ansi_coloff, 1, sig ? writech : putch); 39161268Sjoe} 39261268Sjoe 39361321Sachestatic int 39461178Sjoecolortype(mode) 39561178Sjoe mode_t mode; 39661178Sjoe{ 39761178Sjoe switch(mode & S_IFMT) { 39861178Sjoe case S_IFDIR: 39961178Sjoe if (mode & S_IWOTH) 40061178Sjoe if (mode & S_ISTXT) 40161178Sjoe printcolor(C_WSDIR); 40261178Sjoe else 40361178Sjoe printcolor(C_WDIR); 40461178Sjoe else 40561178Sjoe printcolor(C_DIR); 40661178Sjoe return(1); 40761178Sjoe case S_IFLNK: 40861178Sjoe printcolor(C_LNK); 40961178Sjoe return(1); 41061178Sjoe case S_IFSOCK: 41161178Sjoe printcolor(C_SOCK); 41261178Sjoe return(1); 41361178Sjoe case S_IFIFO: 41461178Sjoe printcolor(C_FIFO); 41561178Sjoe return(1); 41661178Sjoe case S_IFBLK: 41761178Sjoe printcolor(C_BLK); 41861178Sjoe return(1); 41961178Sjoe case S_IFCHR: 42061178Sjoe printcolor(C_CHR); 42161178Sjoe return(1); 42261178Sjoe } 42361178Sjoe if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 42461178Sjoe if (mode & S_ISUID) 42561178Sjoe printcolor(C_SUID); 42661178Sjoe else if (mode & S_ISGID) 42761178Sjoe printcolor(C_SGID); 42861178Sjoe else 42961178Sjoe printcolor(C_EXEC); 43061178Sjoe return(1); 43161178Sjoe } 43261178Sjoe return(0); 43361178Sjoe} 43461178Sjoe 43561178Sjoevoid 43661178Sjoeparsecolors(cs) 43761178Sjoechar *cs; 43861178Sjoe{ 43961178Sjoe int i, j, len; 44061178Sjoe char c[2]; 44161321Sache 44261178Sjoe if (cs == NULL) cs = ""; /* LSCOLORS not set */ 44361178Sjoe len = strlen(cs); 44461178Sjoe for (i = 0 ; i < C_NUMCOLORS ; i++) { 44561178Sjoe if (len <= 2*i) { 44661178Sjoe c[0] = defcolors[2*i]; 44761178Sjoe c[1] = defcolors[2*i+1]; 44861178Sjoe } 44961178Sjoe else { 45061178Sjoe c[0] = cs[2*i]; 45161178Sjoe c[1] = cs[2*i+1]; 45261178Sjoe } 45361178Sjoe for (j = 0 ; j < 2 ; j++) { 45461178Sjoe if ((c[j] < '0' || c[j] > '7') && 45561291Sache tolower((unsigned char)c[j]) != 'x') { 45661178Sjoe fprintf(stderr, 45761178Sjoe "error: invalid character '%c' in LSCOLORS env var\n", 45861178Sjoe c[j]); 45961178Sjoe c[j] = defcolors[2*i+j]; 46061178Sjoe } 46161321Sache if (tolower((unsigned char)c[j]) == 'x') 46261178Sjoe colors[i][j] = -1; 46361178Sjoe else 46461178Sjoe colors[i][j] = c[j]-'0'; 46561178Sjoe } 46661178Sjoe } 46761178Sjoe} 46861291Sache 46961323Sachevoid 47061323Sachecolorquit(sig) 47161291Sache int sig; 47261291Sache{ 47361321Sache endcolor(sig); 47461294Sache 47561294Sache (void) signal(sig, SIG_DFL); 47661294Sache (void) kill(getpid(), sig); 47761291Sache} 47861268Sjoe#endif /*COLORLS*/ 47961178Sjoe 4801556Srgrimesstatic void 4811556Srgrimesprintlink(p) 4821556Srgrimes FTSENT *p; 4831556Srgrimes{ 4841556Srgrimes int lnklen; 4851556Srgrimes char name[MAXPATHLEN + 1], path[MAXPATHLEN + 1]; 4861556Srgrimes 4871556Srgrimes if (p->fts_level == FTS_ROOTLEVEL) 4881556Srgrimes (void)snprintf(name, sizeof(name), "%s", p->fts_name); 4898855Srgrimes else 4901556Srgrimes (void)snprintf(name, sizeof(name), 4911556Srgrimes "%s/%s", p->fts_parent->fts_accpath, p->fts_name); 4921556Srgrimes if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) { 4931556Srgrimes (void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno)); 4941556Srgrimes return; 4951556Srgrimes } 4961556Srgrimes path[lnklen] = '\0'; 49735417Sdes if (f_octal || f_octal_escape) { 49835417Sdes (void)printf(" -> "); 49935417Sdes (void)prn_octal(path); 50035373Sdes } 50135373Sdes else (void)printf(" -> %s", path); 5021556Srgrimes} 503