1 /* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Michael Fischbein. 7 * 8 * %sccs.include.redist.c% 9 */ 10 11 #ifndef lint 12 static char sccsid[] = "@(#)print.c 8.1 (Berkeley) 06/02/93"; 13 #endif /* not lint */ 14 15 #include <sys/param.h> 16 #include <sys/stat.h> 17 18 #include <err.h> 19 #include <errno.h> 20 #include <fts.h> 21 #include <grp.h> 22 #include <pwd.h> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <time.h> 27 #include <tzfile.h> 28 #include <unistd.h> 29 #include <utmp.h> 30 31 #include "ls.h" 32 #include "extern.h" 33 34 static int printaname __P((FTSENT *, u_long, u_long)); 35 static void printlink __P((FTSENT *)); 36 static void printtime __P((time_t)); 37 static int printtype __P((u_int)); 38 39 #define IS_NOPRINT(p) ((p)->fts_number == NO_PRINT) 40 41 void 42 printscol(dp) 43 DISPLAY *dp; 44 { 45 register FTSENT *p; 46 47 for (p = dp->list; p; p = p->fts_link) { 48 if (IS_NOPRINT(p)) 49 continue; 50 (void)printaname(p, dp->s_inode, dp->s_block); 51 (void)putchar('\n'); 52 } 53 } 54 55 void 56 printlong(dp) 57 DISPLAY *dp; 58 { 59 register FTSENT *p; 60 register struct stat *sp; 61 NAMES *np; 62 char buf[20]; 63 64 if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) 65 (void)printf("total %lu\n", howmany(dp->btotal, blocksize)); 66 67 for (p = dp->list; p; p = p->fts_link) { 68 if (IS_NOPRINT(p)) 69 continue; 70 sp = p->fts_statp; 71 if (f_inode) 72 (void)printf("%*lu ", dp->s_inode, sp->st_ino); 73 if (f_size) 74 (void)printf("%*qd ", 75 dp->s_block, howmany(sp->st_blocks, blocksize)); 76 (void)strmode(sp->st_mode, buf); 77 np = p->fts_pointer; 78 (void)printf("%s %*u %-*s %-*s ", buf, dp->s_nlink, 79 sp->st_nlink, dp->s_user, np->user, dp->s_group, 80 np->group); 81 if (f_flags) 82 (void)printf("%-*s ", dp->s_flags, np->flags); 83 if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode)) 84 (void)printf("%3d, %3d ", 85 major(sp->st_rdev), minor(sp->st_rdev)); 86 else if (dp->bcfile) 87 (void)printf("%*s%*qd ", 88 8 - dp->s_size, "", dp->s_size, sp->st_size); 89 else 90 (void)printf("%*qd ", dp->s_size, sp->st_size); 91 if (f_accesstime) 92 printtime(sp->st_atime); 93 else if (f_statustime) 94 printtime(sp->st_ctime); 95 else 96 printtime(sp->st_mtime); 97 (void)printf("%s", p->fts_name); 98 if (f_type) 99 (void)printtype(sp->st_mode); 100 if (S_ISLNK(sp->st_mode)) 101 printlink(p); 102 (void)putchar('\n'); 103 } 104 } 105 106 #define TAB 8 107 108 void 109 printcol(dp) 110 DISPLAY *dp; 111 { 112 extern int termwidth; 113 static FTSENT **array; 114 static int lastentries = -1; 115 register FTSENT *p; 116 register int base, chcnt, cnt, col, colwidth, num; 117 int endcol, numcols, numrows, row; 118 119 /* 120 * Have to do random access in the linked list -- build a table 121 * of pointers. 122 */ 123 if (dp->entries > lastentries) { 124 lastentries = dp->entries; 125 if ((array = 126 realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) { 127 warn(NULL); 128 printscol(dp); 129 } 130 } 131 for (p = dp->list, num = 0; p; p = p->fts_link) 132 if (p->fts_number != NO_PRINT) 133 array[num++] = p; 134 135 colwidth = dp->maxlen; 136 if (f_inode) 137 colwidth += dp->s_inode + 1; 138 if (f_size) 139 colwidth += dp->s_block + 1; 140 if (f_type) 141 colwidth += 1; 142 143 colwidth = (colwidth + TAB) & ~(TAB - 1); 144 if (termwidth < 2 * colwidth) { 145 printscol(dp); 146 return; 147 } 148 149 numcols = termwidth / colwidth; 150 numrows = num / numcols; 151 if (num % numcols) 152 ++numrows; 153 154 if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) 155 (void)printf("total %lu\n", howmany(dp->btotal, blocksize)); 156 for (row = 0; row < numrows; ++row) { 157 endcol = colwidth; 158 for (base = row, chcnt = col = 0; col < numcols; ++col) { 159 chcnt += printaname(array[base], dp->s_inode, 160 dp->s_block); 161 if ((base += numrows) >= num) 162 break; 163 while ((cnt = (chcnt + TAB & ~(TAB - 1))) <= endcol) { 164 (void)putchar('\t'); 165 chcnt = cnt; 166 } 167 endcol += colwidth; 168 } 169 (void)putchar('\n'); 170 } 171 } 172 173 /* 174 * print [inode] [size] name 175 * return # of characters printed, no trailing characters. 176 */ 177 static int 178 printaname(p, inodefield, sizefield) 179 register FTSENT *p; 180 u_long sizefield, inodefield; 181 { 182 struct stat *sp; 183 int chcnt; 184 185 sp = p->fts_statp; 186 chcnt = 0; 187 if (f_inode) 188 chcnt += printf("%*lu ", (int)inodefield, sp->st_ino); 189 if (f_size) 190 chcnt += printf("%*qd ", 191 (int)sizefield, howmany(sp->st_blocks, blocksize)); 192 chcnt += printf("%s", p->fts_name); 193 if (f_type) 194 chcnt += printtype(sp->st_mode); 195 return (chcnt); 196 } 197 198 static void 199 printtime(ftime) 200 time_t ftime; 201 { 202 int i; 203 char *longstring; 204 205 longstring = ctime(&ftime); 206 for (i = 4; i < 11; ++i) 207 (void)putchar(longstring[i]); 208 209 #define SIXMONTHS ((DAYSPERNYEAR / 2) * SECSPERDAY) 210 if (f_sectime) 211 for (i = 11; i < 24; i++) 212 (void)putchar(longstring[i]); 213 else if (ftime + SIXMONTHS > time(NULL)) 214 for (i = 11; i < 16; ++i) 215 (void)putchar(longstring[i]); 216 else { 217 (void)putchar(' '); 218 for (i = 20; i < 24; ++i) 219 (void)putchar(longstring[i]); 220 } 221 (void)putchar(' '); 222 } 223 224 static int 225 printtype(mode) 226 u_int mode; 227 { 228 switch(mode & S_IFMT) { 229 case S_IFDIR: 230 (void)putchar('/'); 231 return (1); 232 case S_IFLNK: 233 (void)putchar('@'); 234 return (1); 235 case S_IFSOCK: 236 (void)putchar('='); 237 return (1); 238 } 239 if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 240 (void)putchar('*'); 241 return (1); 242 } 243 return (0); 244 } 245 246 static void 247 printlink(p) 248 FTSENT *p; 249 { 250 int lnklen; 251 char name[MAXPATHLEN + 1], path[MAXPATHLEN + 1]; 252 253 if (p->fts_level == FTS_ROOTLEVEL) 254 (void)snprintf(name, sizeof(name), "%s", p->fts_name); 255 else 256 (void)snprintf(name, sizeof(name), 257 "%s/%s", p->fts_parent->fts_accpath, p->fts_name); 258 if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) { 259 (void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno)); 260 return; 261 } 262 path[lnklen] = '\0'; 263 (void)printf(" -> %s", path); 264 } 265