print.c revision 86922
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 86922 2001-11-26 22:21:15Z green $"; 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> 5374566Sache#include <langinfo.h> 541556Srgrimes#include <pwd.h> 551556Srgrimes#include <stdio.h> 561556Srgrimes#include <stdlib.h> 571556Srgrimes#include <string.h> 581556Srgrimes#include <time.h> 591556Srgrimes#include <unistd.h> 6061294Sache#ifdef COLORLS 6161294Sache#include <ctype.h> 6261294Sache#include <termcap.h> 6361294Sache#include <signal.h> 6461294Sache#endif 651556Srgrimes 661556Srgrimes#include "ls.h" 671556Srgrimes#include "extern.h" 681556Srgrimes 691556Srgrimesstatic int printaname __P((FTSENT *, u_long, u_long)); 701556Srgrimesstatic void printlink __P((FTSENT *)); 711556Srgrimesstatic void printtime __P((time_t)); 721556Srgrimesstatic int printtype __P((u_int)); 7361321Sache#ifdef COLORLS 7461321Sachestatic void endcolor __P((int)); 7561321Sachestatic int colortype __P((mode_t)); 7661321Sache#endif 771556Srgrimes 781556Srgrimes#define IS_NOPRINT(p) ((p)->fts_number == NO_PRINT) 791556Srgrimes 8061268Sjoe#ifdef COLORLS 8161178Sjoe/* Most of these are taken from <sys/stat.h> */ 8261178Sjoetypedef enum Colors { 8361178Sjoe C_DIR, /* directory */ 8461178Sjoe C_LNK, /* symbolic link */ 8561178Sjoe C_SOCK, /* socket */ 8661178Sjoe C_FIFO, /* pipe */ 8761178Sjoe C_EXEC, /* executable */ 8861178Sjoe C_BLK, /* block special */ 8961178Sjoe C_CHR, /* character special */ 9061178Sjoe C_SUID, /* setuid executable */ 9161178Sjoe C_SGID, /* setgid executable */ 9261178Sjoe C_WSDIR, /* directory writeble to others, with sticky bit */ 9361178Sjoe C_WDIR, /* directory writeble to others, without sticky bit */ 9461178Sjoe C_NUMCOLORS /* just a place-holder */ 9561178Sjoe} Colors ; 9661178Sjoe 9761178Sjoechar *defcolors = "4x5x2x3x1x464301060203"; 9861178Sjoe 9961178Sjoestatic int colors[C_NUMCOLORS][2]; 10061268Sjoe#endif 10161178Sjoe 1021556Srgrimesvoid 1031556Srgrimesprintscol(dp) 1041556Srgrimes DISPLAY *dp; 1051556Srgrimes{ 1061556Srgrimes FTSENT *p; 1071556Srgrimes 1081556Srgrimes for (p = dp->list; p; p = p->fts_link) { 1091556Srgrimes if (IS_NOPRINT(p)) 1101556Srgrimes continue; 1111556Srgrimes (void)printaname(p, dp->s_inode, dp->s_block); 1121556Srgrimes (void)putchar('\n'); 1131556Srgrimes } 1141556Srgrimes} 1151556Srgrimes 11662597Sassar/* 11762597Sassar * print name in current style 11862597Sassar */ 11962597Sassarstatic int 12062597Sassarprintname(name) 12162597Sassar const char *name; 12262597Sassar{ 12362597Sassar if (f_octal || f_octal_escape) 12462597Sassar return prn_octal(name); 12562597Sassar else if (f_nonprint) 12662597Sassar return prn_printable(name); 12762597Sassar else 12862597Sassar return printf("%s", name); 12962597Sassar} 13062597Sassar 1311556Srgrimesvoid 1321556Srgrimesprintlong(dp) 1331556Srgrimes DISPLAY *dp; 1341556Srgrimes{ 1351556Srgrimes struct stat *sp; 1361556Srgrimes FTSENT *p; 1371556Srgrimes NAMES *np; 1381556Srgrimes char buf[20]; 13961292Sache#ifdef COLORLS 14061292Sache int color_printed = 0; 14161292Sache#endif 1421556Srgrimes 1431556Srgrimes if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) 1441556Srgrimes (void)printf("total %lu\n", howmany(dp->btotal, blocksize)); 1451556Srgrimes 1461556Srgrimes for (p = dp->list; p; p = p->fts_link) { 1471556Srgrimes if (IS_NOPRINT(p)) 1481556Srgrimes continue; 1491556Srgrimes sp = p->fts_statp; 1501556Srgrimes if (f_inode) 15120417Ssteve (void)printf("%*lu ", dp->s_inode, (u_long)sp->st_ino); 1521556Srgrimes if (f_size) 1531556Srgrimes (void)printf("%*qd ", 1541556Srgrimes dp->s_block, howmany(sp->st_blocks, blocksize)); 1551556Srgrimes (void)strmode(sp->st_mode, buf); 1561556Srgrimes np = p->fts_pointer; 1571556Srgrimes (void)printf("%s %*u %-*s %-*s ", buf, dp->s_nlink, 1581556Srgrimes sp->st_nlink, dp->s_user, np->user, dp->s_group, 1591556Srgrimes np->group); 1601556Srgrimes if (f_flags) 1611556Srgrimes (void)printf("%-*s ", dp->s_flags, np->flags); 16286922Sgreen if (f_lomac) 16386922Sgreen (void)printf("%-*s ", dp->s_lattr, np->lattr); 1641556Srgrimes if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode)) 16555514Sbde if (minor(sp->st_rdev) > 255 || minor(sp->st_rdev) < 0) 16613120Sjoerg (void)printf("%3d, 0x%08x ", 16755514Sbde major(sp->st_rdev), 16855514Sbde (u_int)minor(sp->st_rdev)); 16913120Sjoerg else 17013120Sjoerg (void)printf("%3d, %3d ", 17113120Sjoerg major(sp->st_rdev), minor(sp->st_rdev)); 1721556Srgrimes else if (dp->bcfile) 1731556Srgrimes (void)printf("%*s%*qd ", 1741556Srgrimes 8 - dp->s_size, "", dp->s_size, sp->st_size); 1751556Srgrimes else 1761556Srgrimes (void)printf("%*qd ", dp->s_size, sp->st_size); 1771556Srgrimes if (f_accesstime) 1781556Srgrimes printtime(sp->st_atime); 1791556Srgrimes else if (f_statustime) 1801556Srgrimes printtime(sp->st_ctime); 1811556Srgrimes else 1821556Srgrimes printtime(sp->st_mtime); 18361268Sjoe#ifdef COLORLS 18461178Sjoe if (f_color) 18561291Sache color_printed = colortype(sp->st_mode); 18661268Sjoe#endif 18762597Sassar (void)printname(p->fts_name); 18861268Sjoe#ifdef COLORLS 18961291Sache if (f_color && color_printed) 19061321Sache endcolor(0); 19161268Sjoe#endif 1921556Srgrimes if (f_type) 1931556Srgrimes (void)printtype(sp->st_mode); 1941556Srgrimes if (S_ISLNK(sp->st_mode)) 1951556Srgrimes printlink(p); 1961556Srgrimes (void)putchar('\n'); 1971556Srgrimes } 1981556Srgrimes} 1991556Srgrimes 2001556Srgrimesvoid 2011556Srgrimesprintcol(dp) 2021556Srgrimes DISPLAY *dp; 2031556Srgrimes{ 2041556Srgrimes extern int termwidth; 2051556Srgrimes static FTSENT **array; 2061556Srgrimes static int lastentries = -1; 2071556Srgrimes FTSENT *p; 2081556Srgrimes int base, chcnt, cnt, col, colwidth, num; 2091556Srgrimes int endcol, numcols, numrows, row; 21037932Shoek int tabwidth; 2111556Srgrimes 21237932Shoek if (f_notabs) 21337932Shoek tabwidth = 1; 21437932Shoek else 21537932Shoek tabwidth = 8; 21637932Shoek 2171556Srgrimes /* 2181556Srgrimes * Have to do random access in the linked list -- build a table 2191556Srgrimes * of pointers. 2201556Srgrimes */ 2211556Srgrimes if (dp->entries > lastentries) { 2221556Srgrimes lastentries = dp->entries; 2231556Srgrimes if ((array = 2241556Srgrimes realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) { 2251556Srgrimes warn(NULL); 2261556Srgrimes printscol(dp); 2271556Srgrimes } 2281556Srgrimes } 2291556Srgrimes for (p = dp->list, num = 0; p; p = p->fts_link) 2301556Srgrimes if (p->fts_number != NO_PRINT) 2311556Srgrimes array[num++] = p; 2321556Srgrimes 2331556Srgrimes colwidth = dp->maxlen; 2341556Srgrimes if (f_inode) 2351556Srgrimes colwidth += dp->s_inode + 1; 2361556Srgrimes if (f_size) 2371556Srgrimes colwidth += dp->s_block + 1; 2381556Srgrimes if (f_type) 2391556Srgrimes colwidth += 1; 2401556Srgrimes 24137932Shoek colwidth = (colwidth + tabwidth) & ~(tabwidth - 1); 2421556Srgrimes if (termwidth < 2 * colwidth) { 2431556Srgrimes printscol(dp); 2441556Srgrimes return; 2451556Srgrimes } 2461556Srgrimes 2471556Srgrimes numcols = termwidth / colwidth; 2481556Srgrimes numrows = num / numcols; 2491556Srgrimes if (num % numcols) 2501556Srgrimes ++numrows; 2511556Srgrimes 2521556Srgrimes if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) 2531556Srgrimes (void)printf("total %lu\n", howmany(dp->btotal, blocksize)); 2541556Srgrimes for (row = 0; row < numrows; ++row) { 2551556Srgrimes endcol = colwidth; 2561556Srgrimes for (base = row, chcnt = col = 0; col < numcols; ++col) { 2571556Srgrimes chcnt += printaname(array[base], dp->s_inode, 2581556Srgrimes dp->s_block); 2591556Srgrimes if ((base += numrows) >= num) 2601556Srgrimes break; 26137932Shoek while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1))) 26237932Shoek <= endcol){ 26337932Shoek (void)putchar(f_notabs ? ' ' : '\t'); 2641556Srgrimes chcnt = cnt; 2651556Srgrimes } 2661556Srgrimes endcol += colwidth; 2671556Srgrimes } 2681556Srgrimes (void)putchar('\n'); 2691556Srgrimes } 2701556Srgrimes} 2711556Srgrimes 2721556Srgrimes/* 2731556Srgrimes * print [inode] [size] name 2741556Srgrimes * return # of characters printed, no trailing characters. 2751556Srgrimes */ 2761556Srgrimesstatic int 2771556Srgrimesprintaname(p, inodefield, sizefield) 2781556Srgrimes FTSENT *p; 2791556Srgrimes u_long sizefield, inodefield; 2801556Srgrimes{ 2811556Srgrimes struct stat *sp; 2821556Srgrimes int chcnt; 28361292Sache#ifdef COLORLS 28461292Sache int color_printed = 0; 28561292Sache#endif 2861556Srgrimes 2871556Srgrimes sp = p->fts_statp; 2881556Srgrimes chcnt = 0; 2891556Srgrimes if (f_inode) 29020417Ssteve chcnt += printf("%*lu ", (int)inodefield, (u_long)sp->st_ino); 2911556Srgrimes if (f_size) 2921556Srgrimes chcnt += printf("%*qd ", 2931556Srgrimes (int)sizefield, howmany(sp->st_blocks, blocksize)); 29461268Sjoe#ifdef COLORLS 29561178Sjoe if (f_color) 29661291Sache color_printed = colortype(sp->st_mode); 29761268Sjoe#endif 29862597Sassar chcnt += printname(p->fts_name); 29961268Sjoe#ifdef COLORLS 30061291Sache if (f_color && color_printed) 30161321Sache endcolor(0); 30261268Sjoe#endif 3031556Srgrimes if (f_type) 3041556Srgrimes chcnt += printtype(sp->st_mode); 3051556Srgrimes return (chcnt); 3061556Srgrimes} 3071556Srgrimes 3081556Srgrimesstatic void 3091556Srgrimesprinttime(ftime) 3101556Srgrimes time_t ftime; 3111556Srgrimes{ 3129991Sache char longstring[80]; 31321545Smpp static time_t now; 31461814Sjoe const char *format; 31574581Sache static int d_first = -1; 3161556Srgrimes 31774566Sache if (d_first < 0) 31874566Sache d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 31921545Smpp if (now == 0) 32021545Smpp now = time(NULL); 32121545Smpp 3229987Swollman#define SIXMONTHS ((365 / 2) * 86400) 3231556Srgrimes if (f_sectime) 32461920Sjoe /* mmm dd hh:mm:ss yyyy || dd mmm hh:mm:ss yyyy */ 32574566Sache format = d_first ? "%e %b %T %Y " : "%b %e %T %Y "; 32621545Smpp else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS) 32761920Sjoe /* mmm dd hh:mm || dd mmm hh:mm */ 32874566Sache format = d_first ? "%e %b %R " : "%b %e %R "; 32961814Sjoe else 33061920Sjoe /* mmm dd yyyy || dd mmm yyyy */ 33174566Sache format = d_first ? "%e %b %Y " : "%b %e %Y "; 33261814Sjoe strftime(longstring, sizeof(longstring), format, localtime(&ftime)); 33361814Sjoe fputs(longstring, stdout); 3341556Srgrimes} 3351556Srgrimes 3361556Srgrimesstatic int 3371556Srgrimesprinttype(mode) 3381556Srgrimes u_int mode; 3391556Srgrimes{ 3401556Srgrimes switch (mode & S_IFMT) { 3411556Srgrimes case S_IFDIR: 3421556Srgrimes (void)putchar('/'); 3431556Srgrimes return (1); 3441556Srgrimes case S_IFIFO: 3451556Srgrimes (void)putchar('|'); 3461556Srgrimes return (1); 3471556Srgrimes case S_IFLNK: 3481556Srgrimes (void)putchar('@'); 3491556Srgrimes return (1); 3501556Srgrimes case S_IFSOCK: 3511556Srgrimes (void)putchar('='); 3521556Srgrimes return (1); 35320417Ssteve case S_IFWHT: 35420417Ssteve (void)putchar('%'); 35520417Ssteve return (1); 3561556Srgrimes } 3571556Srgrimes if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 3581556Srgrimes (void)putchar('*'); 3591556Srgrimes return (1); 3601556Srgrimes } 3611556Srgrimes return (0); 3621556Srgrimes} 3631556Srgrimes 36461268Sjoe#ifdef COLORLS 36561323Sachestatic int 36661323Sacheputch(c) 36761291Sache int c; 36861291Sache{ 36961321Sache (void) putchar(c); 37061321Sache return 0; 37161291Sache} 37261291Sache 37361323Sachestatic int 37461323Sachewritech(c) 37561321Sache int c; 37661321Sache{ 37761321Sache char tmp = c; 37861291Sache 37961321Sache (void) write(STDOUT_FILENO, &tmp, 1); 38061321Sache return 0; 38161321Sache} 38261321Sache 38361323Sachestatic void 38461178Sjoeprintcolor(c) 38561178Sjoe Colors c; 38661178Sjoe{ 38761268Sjoe char *ansiseq; 38861268Sjoe 38961178Sjoe if (colors[c][0] != -1) { 39061296Sache ansiseq = tgoto(ansi_fgcol, 0, colors[c][0]); 39161321Sache if (ansiseq) 39261291Sache tputs(ansiseq, 1, putch); 39361178Sjoe } 39461268Sjoe 39561268Sjoe if (colors[c][1] != -1) { 39661296Sache ansiseq = tgoto(ansi_bgcol, 0, colors[c][1]); 39761321Sache if (ansiseq) 39861291Sache tputs(ansiseq, 1, putch); 39961268Sjoe } 40061178Sjoe} 40161178Sjoe 40261321Sachestatic void 40361321Sacheendcolor(sig) 40461321Sache int sig; 40561268Sjoe{ 40661321Sache tputs(ansi_coloff, 1, sig ? writech : putch); 40761268Sjoe} 40861268Sjoe 40961321Sachestatic int 41061178Sjoecolortype(mode) 41161178Sjoe mode_t mode; 41261178Sjoe{ 41361178Sjoe switch(mode & S_IFMT) { 41461178Sjoe case S_IFDIR: 41561178Sjoe if (mode & S_IWOTH) 41661178Sjoe if (mode & S_ISTXT) 41761178Sjoe printcolor(C_WSDIR); 41861178Sjoe else 41961178Sjoe printcolor(C_WDIR); 42061178Sjoe else 42161178Sjoe printcolor(C_DIR); 42261178Sjoe return(1); 42361178Sjoe case S_IFLNK: 42461178Sjoe printcolor(C_LNK); 42561178Sjoe return(1); 42661178Sjoe case S_IFSOCK: 42761178Sjoe printcolor(C_SOCK); 42861178Sjoe return(1); 42961178Sjoe case S_IFIFO: 43061178Sjoe printcolor(C_FIFO); 43161178Sjoe return(1); 43261178Sjoe case S_IFBLK: 43361178Sjoe printcolor(C_BLK); 43461178Sjoe return(1); 43561178Sjoe case S_IFCHR: 43661178Sjoe printcolor(C_CHR); 43761178Sjoe return(1); 43861178Sjoe } 43961178Sjoe if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 44061178Sjoe if (mode & S_ISUID) 44161178Sjoe printcolor(C_SUID); 44261178Sjoe else if (mode & S_ISGID) 44361178Sjoe printcolor(C_SGID); 44461178Sjoe else 44561178Sjoe printcolor(C_EXEC); 44661178Sjoe return(1); 44761178Sjoe } 44861178Sjoe return(0); 44961178Sjoe} 45061178Sjoe 45161178Sjoevoid 45261178Sjoeparsecolors(cs) 45361178Sjoechar *cs; 45461178Sjoe{ 45561178Sjoe int i, j, len; 45661178Sjoe char c[2]; 45761321Sache 45861178Sjoe if (cs == NULL) cs = ""; /* LSCOLORS not set */ 45961178Sjoe len = strlen(cs); 46061178Sjoe for (i = 0 ; i < C_NUMCOLORS ; i++) { 46161178Sjoe if (len <= 2*i) { 46261178Sjoe c[0] = defcolors[2*i]; 46361178Sjoe c[1] = defcolors[2*i+1]; 46461178Sjoe } 46561178Sjoe else { 46661178Sjoe c[0] = cs[2*i]; 46761178Sjoe c[1] = cs[2*i+1]; 46861178Sjoe } 46961178Sjoe for (j = 0 ; j < 2 ; j++) { 47061178Sjoe if ((c[j] < '0' || c[j] > '7') && 47161291Sache tolower((unsigned char)c[j]) != 'x') { 47261178Sjoe fprintf(stderr, 47361178Sjoe "error: invalid character '%c' in LSCOLORS env var\n", 47461178Sjoe c[j]); 47561178Sjoe c[j] = defcolors[2*i+j]; 47661178Sjoe } 47761321Sache if (tolower((unsigned char)c[j]) == 'x') 47861178Sjoe colors[i][j] = -1; 47961178Sjoe else 48061178Sjoe colors[i][j] = c[j]-'0'; 48161178Sjoe } 48261178Sjoe } 48361178Sjoe} 48461291Sache 48561323Sachevoid 48661323Sachecolorquit(sig) 48761291Sache int sig; 48861291Sache{ 48961321Sache endcolor(sig); 49061294Sache 49161294Sache (void) signal(sig, SIG_DFL); 49261294Sache (void) kill(getpid(), sig); 49361291Sache} 49461268Sjoe#endif /*COLORLS*/ 49561178Sjoe 4961556Srgrimesstatic void 4971556Srgrimesprintlink(p) 4981556Srgrimes FTSENT *p; 4991556Srgrimes{ 5001556Srgrimes int lnklen; 5011556Srgrimes char name[MAXPATHLEN + 1], path[MAXPATHLEN + 1]; 5021556Srgrimes 5031556Srgrimes if (p->fts_level == FTS_ROOTLEVEL) 5041556Srgrimes (void)snprintf(name, sizeof(name), "%s", p->fts_name); 5058855Srgrimes else 5061556Srgrimes (void)snprintf(name, sizeof(name), 5071556Srgrimes "%s/%s", p->fts_parent->fts_accpath, p->fts_name); 5081556Srgrimes if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) { 5091556Srgrimes (void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno)); 5101556Srgrimes return; 5111556Srgrimes } 5121556Srgrimes path[lnklen] = '\0'; 51362597Sassar (void)printf(" -> "); 51462597Sassar printname(path); 5151556Srgrimes} 516