print.c revision 61268
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 61268 2000-06-05 02:14:01Z joe $"; 4327967Ssteve#endif 441556Srgrimes#endif /* not lint */ 451556Srgrimes 461556Srgrimes#include <sys/param.h> 471556Srgrimes#include <sys/stat.h> 481556Srgrimes 4961268Sjoe#ifdef COLORLS 5061268Sjoe#include <ctype.h> 5161268Sjoe#include <curses.h> 5261268Sjoe#endif 531556Srgrimes#include <err.h> 541556Srgrimes#include <errno.h> 551556Srgrimes#include <fts.h> 561556Srgrimes#include <grp.h> 571556Srgrimes#include <pwd.h> 581556Srgrimes#include <stdio.h> 591556Srgrimes#include <stdlib.h> 601556Srgrimes#include <string.h> 6161268Sjoe#ifdef COLORLS 6261268Sjoe#include <term.h> 6361268Sjoe#endif 641556Srgrimes#include <time.h> 651556Srgrimes#include <unistd.h> 661556Srgrimes 671556Srgrimes#include "ls.h" 681556Srgrimes#include "extern.h" 691556Srgrimes 701556Srgrimesstatic int printaname __P((FTSENT *, u_long, u_long)); 711556Srgrimesstatic void printlink __P((FTSENT *)); 721556Srgrimesstatic void printtime __P((time_t)); 731556Srgrimesstatic int printtype __P((u_int)); 741556Srgrimes 751556Srgrimes#define IS_NOPRINT(p) ((p)->fts_number == NO_PRINT) 761556Srgrimes 7761268Sjoe#ifdef COLORLS 7861178Sjoe/* Most of these are taken from <sys/stat.h> */ 7961178Sjoetypedef enum Colors { 8061178Sjoe C_DIR, /* directory */ 8161178Sjoe C_LNK, /* symbolic link */ 8261178Sjoe C_SOCK, /* socket */ 8361178Sjoe C_FIFO, /* pipe */ 8461178Sjoe C_EXEC, /* executable */ 8561178Sjoe C_BLK, /* block special */ 8661178Sjoe C_CHR, /* character special */ 8761178Sjoe C_SUID, /* setuid executable */ 8861178Sjoe C_SGID, /* setgid executable */ 8961178Sjoe C_WSDIR, /* directory writeble to others, with sticky bit */ 9061178Sjoe C_WDIR, /* directory writeble to others, without sticky bit */ 9161178Sjoe C_NUMCOLORS /* just a place-holder */ 9261178Sjoe} Colors ; 9361178Sjoe 9461178Sjoechar *defcolors = "4x5x2x3x1x464301060203"; 9561178Sjoe 9661178Sjoestatic int colors[C_NUMCOLORS][2]; 9761268Sjoe#endif 9861178Sjoe 991556Srgrimesvoid 1001556Srgrimesprintscol(dp) 1011556Srgrimes DISPLAY *dp; 1021556Srgrimes{ 1031556Srgrimes FTSENT *p; 1041556Srgrimes 1051556Srgrimes for (p = dp->list; p; p = p->fts_link) { 1061556Srgrimes if (IS_NOPRINT(p)) 1071556Srgrimes continue; 1081556Srgrimes (void)printaname(p, dp->s_inode, dp->s_block); 1091556Srgrimes (void)putchar('\n'); 1101556Srgrimes } 1111556Srgrimes} 1121556Srgrimes 1131556Srgrimesvoid 1141556Srgrimesprintlong(dp) 1151556Srgrimes DISPLAY *dp; 1161556Srgrimes{ 1171556Srgrimes struct stat *sp; 1181556Srgrimes FTSENT *p; 1191556Srgrimes NAMES *np; 1201556Srgrimes char buf[20]; 1211556Srgrimes 1221556Srgrimes if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) 1231556Srgrimes (void)printf("total %lu\n", howmany(dp->btotal, blocksize)); 1241556Srgrimes 1251556Srgrimes for (p = dp->list; p; p = p->fts_link) { 1261556Srgrimes if (IS_NOPRINT(p)) 1271556Srgrimes continue; 1281556Srgrimes sp = p->fts_statp; 1291556Srgrimes if (f_inode) 13020417Ssteve (void)printf("%*lu ", dp->s_inode, (u_long)sp->st_ino); 1311556Srgrimes if (f_size) 1321556Srgrimes (void)printf("%*qd ", 1331556Srgrimes dp->s_block, howmany(sp->st_blocks, blocksize)); 1341556Srgrimes (void)strmode(sp->st_mode, buf); 1351556Srgrimes np = p->fts_pointer; 1361556Srgrimes (void)printf("%s %*u %-*s %-*s ", buf, dp->s_nlink, 1371556Srgrimes sp->st_nlink, dp->s_user, np->user, dp->s_group, 1381556Srgrimes np->group); 1391556Srgrimes if (f_flags) 1401556Srgrimes (void)printf("%-*s ", dp->s_flags, np->flags); 1411556Srgrimes if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode)) 14255514Sbde if (minor(sp->st_rdev) > 255 || minor(sp->st_rdev) < 0) 14313120Sjoerg (void)printf("%3d, 0x%08x ", 14455514Sbde major(sp->st_rdev), 14555514Sbde (u_int)minor(sp->st_rdev)); 14613120Sjoerg else 14713120Sjoerg (void)printf("%3d, %3d ", 14813120Sjoerg major(sp->st_rdev), minor(sp->st_rdev)); 1491556Srgrimes else if (dp->bcfile) 1501556Srgrimes (void)printf("%*s%*qd ", 1511556Srgrimes 8 - dp->s_size, "", dp->s_size, sp->st_size); 1521556Srgrimes else 1531556Srgrimes (void)printf("%*qd ", dp->s_size, sp->st_size); 1541556Srgrimes if (f_accesstime) 1551556Srgrimes printtime(sp->st_atime); 1561556Srgrimes else if (f_statustime) 1571556Srgrimes printtime(sp->st_ctime); 1581556Srgrimes else 1591556Srgrimes printtime(sp->st_mtime); 16061268Sjoe#ifdef COLORLS 16161178Sjoe if (f_color) 16261178Sjoe (void)colortype(sp->st_mode); 16361268Sjoe#endif 16435417Sdes if (f_octal || f_octal_escape) (void)prn_octal(p->fts_name); 16535373Sdes else (void)printf("%s", p->fts_name); 16661268Sjoe#ifdef COLORLS 16761178Sjoe if (f_color) 16861268Sjoe endcolor(); 16961268Sjoe#endif 1701556Srgrimes if (f_type) 1711556Srgrimes (void)printtype(sp->st_mode); 1721556Srgrimes if (S_ISLNK(sp->st_mode)) 1731556Srgrimes printlink(p); 1741556Srgrimes (void)putchar('\n'); 1751556Srgrimes } 1761556Srgrimes} 1771556Srgrimes 1781556Srgrimesvoid 1791556Srgrimesprintcol(dp) 1801556Srgrimes DISPLAY *dp; 1811556Srgrimes{ 1821556Srgrimes extern int termwidth; 1831556Srgrimes static FTSENT **array; 1841556Srgrimes static int lastentries = -1; 1851556Srgrimes FTSENT *p; 1861556Srgrimes int base, chcnt, cnt, col, colwidth, num; 1871556Srgrimes int endcol, numcols, numrows, row; 18837932Shoek int tabwidth; 1891556Srgrimes 19037932Shoek if (f_notabs) 19137932Shoek tabwidth = 1; 19237932Shoek else 19337932Shoek tabwidth = 8; 19437932Shoek 1951556Srgrimes /* 1961556Srgrimes * Have to do random access in the linked list -- build a table 1971556Srgrimes * of pointers. 1981556Srgrimes */ 1991556Srgrimes if (dp->entries > lastentries) { 2001556Srgrimes lastentries = dp->entries; 2011556Srgrimes if ((array = 2021556Srgrimes realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) { 2031556Srgrimes warn(NULL); 2041556Srgrimes printscol(dp); 2051556Srgrimes } 2061556Srgrimes } 2071556Srgrimes for (p = dp->list, num = 0; p; p = p->fts_link) 2081556Srgrimes if (p->fts_number != NO_PRINT) 2091556Srgrimes array[num++] = p; 2101556Srgrimes 2111556Srgrimes colwidth = dp->maxlen; 2121556Srgrimes if (f_inode) 2131556Srgrimes colwidth += dp->s_inode + 1; 2141556Srgrimes if (f_size) 2151556Srgrimes colwidth += dp->s_block + 1; 2161556Srgrimes if (f_type) 2171556Srgrimes colwidth += 1; 2181556Srgrimes 21937932Shoek colwidth = (colwidth + tabwidth) & ~(tabwidth - 1); 2201556Srgrimes if (termwidth < 2 * colwidth) { 2211556Srgrimes printscol(dp); 2221556Srgrimes return; 2231556Srgrimes } 2241556Srgrimes 2251556Srgrimes numcols = termwidth / colwidth; 2261556Srgrimes numrows = num / numcols; 2271556Srgrimes if (num % numcols) 2281556Srgrimes ++numrows; 2291556Srgrimes 2301556Srgrimes if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) 2311556Srgrimes (void)printf("total %lu\n", howmany(dp->btotal, blocksize)); 2321556Srgrimes for (row = 0; row < numrows; ++row) { 2331556Srgrimes endcol = colwidth; 2341556Srgrimes for (base = row, chcnt = col = 0; col < numcols; ++col) { 2351556Srgrimes chcnt += printaname(array[base], dp->s_inode, 2361556Srgrimes dp->s_block); 2371556Srgrimes if ((base += numrows) >= num) 2381556Srgrimes break; 23961268Sjoe#ifdef COLORLS 24061178Sjoe /* 24161178Sjoe * some terminals get confused if we mix tabs 24261178Sjoe * with color sequences 24361178Sjoe */ 24461178Sjoe if (f_color) 24561178Sjoe while ((cnt = (chcnt + 1)) <= endcol) { 24661178Sjoe (void)putchar(' '); 24761178Sjoe chcnt = cnt; 24861178Sjoe } 24961178Sjoe else 25061268Sjoe#endif 25137932Shoek while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1))) 25237932Shoek <= endcol){ 25337932Shoek (void)putchar(f_notabs ? ' ' : '\t'); 2541556Srgrimes chcnt = cnt; 2551556Srgrimes } 2561556Srgrimes endcol += colwidth; 2571556Srgrimes } 2581556Srgrimes (void)putchar('\n'); 2591556Srgrimes } 2601556Srgrimes} 2611556Srgrimes 2621556Srgrimes/* 2631556Srgrimes * print [inode] [size] name 2641556Srgrimes * return # of characters printed, no trailing characters. 2651556Srgrimes */ 2661556Srgrimesstatic int 2671556Srgrimesprintaname(p, inodefield, sizefield) 2681556Srgrimes FTSENT *p; 2691556Srgrimes u_long sizefield, inodefield; 2701556Srgrimes{ 2711556Srgrimes struct stat *sp; 2721556Srgrimes int chcnt; 2731556Srgrimes 2741556Srgrimes sp = p->fts_statp; 2751556Srgrimes chcnt = 0; 2761556Srgrimes if (f_inode) 27720417Ssteve chcnt += printf("%*lu ", (int)inodefield, (u_long)sp->st_ino); 2781556Srgrimes if (f_size) 2791556Srgrimes chcnt += printf("%*qd ", 2801556Srgrimes (int)sizefield, howmany(sp->st_blocks, blocksize)); 28161268Sjoe#ifdef COLORLS 28261178Sjoe if (f_color) 28361178Sjoe (void)colortype(sp->st_mode); 28461268Sjoe#endif 28535417Sdes chcnt += (f_octal || f_octal_escape) ? prn_octal(p->fts_name) 28635417Sdes : printf("%s", p->fts_name); 28761268Sjoe#ifdef COLORLS 28861178Sjoe if (f_color) 28961268Sjoe endcolor(); 29061268Sjoe#endif 2911556Srgrimes if (f_type) 2921556Srgrimes chcnt += printtype(sp->st_mode); 2931556Srgrimes return (chcnt); 2941556Srgrimes} 2951556Srgrimes 2961556Srgrimesstatic void 2971556Srgrimesprinttime(ftime) 2981556Srgrimes time_t ftime; 2991556Srgrimes{ 3001556Srgrimes int i; 3019991Sache char longstring[80]; 30221545Smpp static time_t now; 3031556Srgrimes 30421545Smpp if (now == 0) 30521545Smpp now = time(NULL); 30621545Smpp 3079991Sache strftime(longstring, sizeof(longstring), "%c", localtime(&ftime)); 3081556Srgrimes for (i = 4; i < 11; ++i) 3091556Srgrimes (void)putchar(longstring[i]); 3101556Srgrimes 3119987Swollman#define SIXMONTHS ((365 / 2) * 86400) 3121556Srgrimes if (f_sectime) 3131556Srgrimes for (i = 11; i < 24; i++) 3141556Srgrimes (void)putchar(longstring[i]); 31521545Smpp else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS) 3161556Srgrimes for (i = 11; i < 16; ++i) 3171556Srgrimes (void)putchar(longstring[i]); 3181556Srgrimes else { 3191556Srgrimes (void)putchar(' '); 3201556Srgrimes for (i = 20; i < 24; ++i) 3211556Srgrimes (void)putchar(longstring[i]); 3221556Srgrimes } 3231556Srgrimes (void)putchar(' '); 3241556Srgrimes} 3251556Srgrimes 3261556Srgrimesstatic int 3271556Srgrimesprinttype(mode) 3281556Srgrimes u_int mode; 3291556Srgrimes{ 3301556Srgrimes switch (mode & S_IFMT) { 3311556Srgrimes case S_IFDIR: 3321556Srgrimes (void)putchar('/'); 3331556Srgrimes return (1); 3341556Srgrimes case S_IFIFO: 3351556Srgrimes (void)putchar('|'); 3361556Srgrimes return (1); 3371556Srgrimes case S_IFLNK: 3381556Srgrimes (void)putchar('@'); 3391556Srgrimes return (1); 3401556Srgrimes case S_IFSOCK: 3411556Srgrimes (void)putchar('='); 3421556Srgrimes return (1); 34320417Ssteve case S_IFWHT: 34420417Ssteve (void)putchar('%'); 34520417Ssteve return (1); 3461556Srgrimes } 3471556Srgrimes if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 3481556Srgrimes (void)putchar('*'); 3491556Srgrimes return (1); 3501556Srgrimes } 3511556Srgrimes return (0); 3521556Srgrimes} 3531556Srgrimes 35461268Sjoe#ifdef COLORLS 35561268Sjoestatic char tcapbuf[512]; 35661178Sjoevoid 35761178Sjoeprintcolor(c) 35861178Sjoe Colors c; 35961178Sjoe{ 36061268Sjoe char *bp = tcapbuf; 36161268Sjoe char *ansiseq; 36261268Sjoe 36361178Sjoe if (colors[c][0] != -1) { 36461268Sjoe ansiseq = tparm(tgetstr("AF", &bp), colors[c][0]); 36561268Sjoe if (ansiseq) 36661268Sjoe putp(ansiseq); 36761178Sjoe } 36861268Sjoe 36961268Sjoe if (colors[c][1] != -1) { 37061268Sjoe ansiseq = tparm(tgetstr("AB", &bp), colors[c][1]); 37161268Sjoe if (ansiseq) 37261268Sjoe putp(ansiseq); 37361268Sjoe } 37461178Sjoe} 37561178Sjoe 37661268Sjoevoid 37761268Sjoeendcolor() 37861268Sjoe{ 37961268Sjoe char *bp = tcapbuf; 38061268Sjoe char *ansiseq; 38161268Sjoe ansiseq = tgetstr("se", &bp); 38261268Sjoe if (ansiseq) 38361268Sjoe putp(ansiseq); 38461268Sjoe} 38561268Sjoe 38661178Sjoeint 38761178Sjoecolortype(mode) 38861178Sjoe mode_t mode; 38961178Sjoe{ 39061178Sjoe switch(mode & S_IFMT) { 39161178Sjoe case S_IFDIR: 39261178Sjoe if (mode & S_IWOTH) 39361178Sjoe if (mode & S_ISTXT) 39461178Sjoe printcolor(C_WSDIR); 39561178Sjoe else 39661178Sjoe printcolor(C_WDIR); 39761178Sjoe else 39861178Sjoe printcolor(C_DIR); 39961178Sjoe return(1); 40061178Sjoe case S_IFLNK: 40161178Sjoe printcolor(C_LNK); 40261178Sjoe return(1); 40361178Sjoe case S_IFSOCK: 40461178Sjoe printcolor(C_SOCK); 40561178Sjoe return(1); 40661178Sjoe case S_IFIFO: 40761178Sjoe printcolor(C_FIFO); 40861178Sjoe return(1); 40961178Sjoe case S_IFBLK: 41061178Sjoe printcolor(C_BLK); 41161178Sjoe return(1); 41261178Sjoe case S_IFCHR: 41361178Sjoe printcolor(C_CHR); 41461178Sjoe return(1); 41561178Sjoe } 41661178Sjoe if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 41761178Sjoe if (mode & S_ISUID) 41861178Sjoe printcolor(C_SUID); 41961178Sjoe else if (mode & S_ISGID) 42061178Sjoe printcolor(C_SGID); 42161178Sjoe else 42261178Sjoe printcolor(C_EXEC); 42361178Sjoe return(1); 42461178Sjoe } 42561178Sjoe return(0); 42661178Sjoe} 42761178Sjoe 42861178Sjoevoid 42961178Sjoeparsecolors(cs) 43061178Sjoechar *cs; 43161178Sjoe{ 43261178Sjoe int i, j, len; 43361178Sjoe char c[2]; 43461178Sjoe if (cs == NULL) cs = ""; /* LSCOLORS not set */ 43561178Sjoe len = strlen(cs); 43661178Sjoe for (i = 0 ; i < C_NUMCOLORS ; i++) { 43761178Sjoe if (len <= 2*i) { 43861178Sjoe c[0] = defcolors[2*i]; 43961178Sjoe c[1] = defcolors[2*i+1]; 44061178Sjoe } 44161178Sjoe else { 44261178Sjoe c[0] = cs[2*i]; 44361178Sjoe c[1] = cs[2*i+1]; 44461178Sjoe } 44561178Sjoe for (j = 0 ; j < 2 ; j++) { 44661178Sjoe if ((c[j] < '0' || c[j] > '7') && 44761178Sjoe tolower(c[j]) != 'x') { 44861178Sjoe fprintf(stderr, 44961178Sjoe "error: invalid character '%c' in LSCOLORS env var\n", 45061178Sjoe c[j]); 45161178Sjoe c[j] = defcolors[2*i+j]; 45261178Sjoe } 45361178Sjoe if (c[j] == 'x') 45461178Sjoe colors[i][j] = -1; 45561178Sjoe else 45661178Sjoe colors[i][j] = c[j]-'0'; 45761178Sjoe } 45861178Sjoe } 45961178Sjoe} 46061268Sjoe#endif /*COLORLS*/ 46161178Sjoe 4621556Srgrimesstatic void 4631556Srgrimesprintlink(p) 4641556Srgrimes FTSENT *p; 4651556Srgrimes{ 4661556Srgrimes int lnklen; 4671556Srgrimes char name[MAXPATHLEN + 1], path[MAXPATHLEN + 1]; 4681556Srgrimes 4691556Srgrimes if (p->fts_level == FTS_ROOTLEVEL) 4701556Srgrimes (void)snprintf(name, sizeof(name), "%s", p->fts_name); 4718855Srgrimes else 4721556Srgrimes (void)snprintf(name, sizeof(name), 4731556Srgrimes "%s/%s", p->fts_parent->fts_accpath, p->fts_name); 4741556Srgrimes if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) { 4751556Srgrimes (void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno)); 4761556Srgrimes return; 4771556Srgrimes } 4781556Srgrimes path[lnklen] = '\0'; 47935417Sdes if (f_octal || f_octal_escape) { 48035417Sdes (void)printf(" -> "); 48135417Sdes (void)prn_octal(path); 48235373Sdes } 48335373Sdes else (void)printf(" -> %s", path); 4841556Srgrimes} 485