1 /* 2 * Copyright (c) 1989, 1993, 1994 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 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #ifndef lint 38 #if 0 39 static char sccsid[] = "@(#)print.c 8.4 (Berkeley) 4/17/94"; 40 #else 41 static const char rcsid[] = 42 "$FreeBSD$"; 43 #endif 44 #endif /* not lint */ 45 46 #include <sys/param.h> 47 #include <sys/stat.h> 48 49 #ifdef COLORLS 50 #include <ctype.h> 51 #include <termcap.h> 52 #include <term.h> /* for tparm */ 53 #endif 54 #include <err.h> 55 #include <errno.h> 56 #include <fts.h> 57 #include <grp.h> 58 #include <pwd.h> 59 #include <stdio.h> 60 #include <stdlib.h> 61 #include <string.h> 62 #include <time.h> 63 #include <unistd.h> 64 65 #include "ls.h" 66 #include "extern.h" 67 68 static int printaname __P((FTSENT *, u_long, u_long)); 69 static void printlink __P((FTSENT *)); 70 static void printtime __P((time_t)); 71 static int printtype __P((u_int)); 72 73 #define IS_NOPRINT(p) ((p)->fts_number == NO_PRINT) 74 75 #ifdef COLORLS 76 /* Most of these are taken from <sys/stat.h> */ 77 typedef enum Colors { 78 C_DIR, /* directory */ 79 C_LNK, /* symbolic link */ 80 C_SOCK, /* socket */ 81 C_FIFO, /* pipe */ 82 C_EXEC, /* executable */ 83 C_BLK, /* block special */ 84 C_CHR, /* character special */ 85 C_SUID, /* setuid executable */ 86 C_SGID, /* setgid executable */ 87 C_WSDIR, /* directory writeble to others, with sticky bit */ 88 C_WDIR, /* directory writeble to others, without sticky bit */ 89 C_NUMCOLORS /* just a place-holder */ 90 } Colors ; 91 92 char *defcolors = "4x5x2x3x1x464301060203"; 93 94 static int colors[C_NUMCOLORS][2]; 95 static int color_printed = 0; 96 #endif 97 98 void 99 printscol(dp) 100 DISPLAY *dp; 101 { 102 FTSENT *p; 103 104 for (p = dp->list; p; p = p->fts_link) { 105 if (IS_NOPRINT(p)) 106 continue; 107 (void)printaname(p, dp->s_inode, dp->s_block); 108 (void)putchar('\n'); 109 } 110 } 111 112 void 113 printlong(dp) 114 DISPLAY *dp; 115 { 116 struct stat *sp; 117 FTSENT *p; 118 NAMES *np; 119 char buf[20]; 120 121 if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) 122 (void)printf("total %lu\n", howmany(dp->btotal, blocksize)); 123 124 for (p = dp->list; p; p = p->fts_link) { 125 if (IS_NOPRINT(p)) 126 continue; 127 sp = p->fts_statp; 128 if (f_inode) 129 (void)printf("%*lu ", dp->s_inode, (u_long)sp->st_ino); 130 if (f_size) 131 (void)printf("%*qd ", 132 dp->s_block, howmany(sp->st_blocks, blocksize)); 133 (void)strmode(sp->st_mode, buf); 134 np = p->fts_pointer; 135 (void)printf("%s %*u %-*s %-*s ", buf, dp->s_nlink, 136 sp->st_nlink, dp->s_user, np->user, dp->s_group, 137 np->group); 138 if (f_flags) 139 (void)printf("%-*s ", dp->s_flags, np->flags); 140 if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode)) 141 if (minor(sp->st_rdev) > 255 || minor(sp->st_rdev) < 0) 142 (void)printf("%3d, 0x%08x ", 143 major(sp->st_rdev), 144 (u_int)minor(sp->st_rdev)); 145 else 146 (void)printf("%3d, %3d ", 147 major(sp->st_rdev), minor(sp->st_rdev)); 148 else if (dp->bcfile) 149 (void)printf("%*s%*qd ", 150 8 - dp->s_size, "", dp->s_size, sp->st_size); 151 else 152 (void)printf("%*qd ", dp->s_size, sp->st_size); 153 if (f_accesstime) 154 printtime(sp->st_atime); 155 else if (f_statustime) 156 printtime(sp->st_ctime); 157 else 158 printtime(sp->st_mtime); 159 #ifdef COLORLS 160 if (f_color) 161 color_printed = colortype(sp->st_mode); 162 #endif 163 if (f_octal || f_octal_escape) (void)prn_octal(p->fts_name); 164 else (void)printf("%s", p->fts_name); 165 #ifdef COLORLS 166 if (f_color && color_printed) 167 endcolor(); 168 #endif 169 if (f_type) 170 (void)printtype(sp->st_mode); 171 if (S_ISLNK(sp->st_mode)) 172 printlink(p); 173 (void)putchar('\n'); 174 } 175 } 176 177 void 178 printcol(dp) 179 DISPLAY *dp; 180 { 181 extern int termwidth; 182 static FTSENT **array; 183 static int lastentries = -1; 184 FTSENT *p; 185 int base, chcnt, cnt, col, colwidth, num; 186 int endcol, numcols, numrows, row; 187 int tabwidth; 188 189 if (f_notabs) 190 tabwidth = 1; 191 else 192 tabwidth = 8; 193 194 /* 195 * Have to do random access in the linked list -- build a table 196 * of pointers. 197 */ 198 if (dp->entries > lastentries) { 199 lastentries = dp->entries; 200 if ((array = 201 realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) { 202 warn(NULL); 203 printscol(dp); 204 } 205 } 206 for (p = dp->list, num = 0; p; p = p->fts_link) 207 if (p->fts_number != NO_PRINT) 208 array[num++] = p; 209 210 colwidth = dp->maxlen; 211 if (f_inode) 212 colwidth += dp->s_inode + 1; 213 if (f_size) 214 colwidth += dp->s_block + 1; 215 if (f_type) 216 colwidth += 1; 217 218 colwidth = (colwidth + tabwidth) & ~(tabwidth - 1); 219 if (termwidth < 2 * colwidth) { 220 printscol(dp); 221 return; 222 } 223 224 numcols = termwidth / colwidth; 225 numrows = num / numcols; 226 if (num % numcols) 227 ++numrows; 228 229 if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) 230 (void)printf("total %lu\n", howmany(dp->btotal, blocksize)); 231 for (row = 0; row < numrows; ++row) { 232 endcol = colwidth; 233 for (base = row, chcnt = col = 0; col < numcols; ++col) { 234 chcnt += printaname(array[base], dp->s_inode, 235 dp->s_block); 236 if ((base += numrows) >= num) 237 break; 238 #ifdef COLORLS 239 /* 240 * some terminals get confused if we mix tabs 241 * with color sequences 242 */ 243 if (f_color) 244 while ((cnt = (chcnt + 1)) <= endcol) { 245 (void)putchar(' '); 246 chcnt = cnt; 247 } 248 else 249 #endif 250 while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1))) 251 <= endcol){ 252 (void)putchar(f_notabs ? ' ' : '\t'); 253 chcnt = cnt; 254 } 255 endcol += colwidth; 256 } 257 (void)putchar('\n'); 258 } 259 } 260 261 /* 262 * print [inode] [size] name 263 * return # of characters printed, no trailing characters. 264 */ 265 static int 266 printaname(p, inodefield, sizefield) 267 FTSENT *p; 268 u_long sizefield, inodefield; 269 { 270 struct stat *sp; 271 int chcnt; 272 273 sp = p->fts_statp; 274 chcnt = 0; 275 if (f_inode) 276 chcnt += printf("%*lu ", (int)inodefield, (u_long)sp->st_ino); 277 if (f_size) 278 chcnt += printf("%*qd ", 279 (int)sizefield, howmany(sp->st_blocks, blocksize)); 280 #ifdef COLORLS 281 if (f_color) 282 color_printed = colortype(sp->st_mode); 283 #endif 284 chcnt += (f_octal || f_octal_escape) ? prn_octal(p->fts_name) 285 : printf("%s", p->fts_name); 286 #ifdef COLORLS 287 if (f_color && color_printed) 288 endcolor(); 289 #endif 290 if (f_type) 291 chcnt += printtype(sp->st_mode); 292 return (chcnt); 293 } 294 295 static void 296 printtime(ftime) 297 time_t ftime; 298 { 299 int i; 300 char longstring[80]; 301 static time_t now; 302 303 if (now == 0) 304 now = time(NULL); 305 306 strftime(longstring, sizeof(longstring), "%c", localtime(&ftime)); 307 for (i = 4; i < 11; ++i) 308 (void)putchar(longstring[i]); 309 310 #define SIXMONTHS ((365 / 2) * 86400) 311 if (f_sectime) 312 for (i = 11; i < 24; i++) 313 (void)putchar(longstring[i]); 314 else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS) 315 for (i = 11; i < 16; ++i) 316 (void)putchar(longstring[i]); 317 else { 318 (void)putchar(' '); 319 for (i = 20; i < 24; ++i) 320 (void)putchar(longstring[i]); 321 } 322 (void)putchar(' '); 323 } 324 325 static int 326 printtype(mode) 327 u_int mode; 328 { 329 switch (mode & S_IFMT) { 330 case S_IFDIR: 331 (void)putchar('/'); 332 return (1); 333 case S_IFIFO: 334 (void)putchar('|'); 335 return (1); 336 case S_IFLNK: 337 (void)putchar('@'); 338 return (1); 339 case S_IFSOCK: 340 (void)putchar('='); 341 return (1); 342 case S_IFWHT: 343 (void)putchar('%'); 344 return (1); 345 } 346 if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 347 (void)putchar('*'); 348 return (1); 349 } 350 return (0); 351 } 352 353 #ifdef COLORLS 354 int putch(c) 355 int c; 356 { 357 return putc(c, stdout); 358 } 359 360 361 void 362 printcolor(c) 363 Colors c; 364 { 365 char *ansiseq; 366 367 if (colors[c][0] != -1) { 368 ansiseq = tparm(ansi_fgcol, colors[c][0]); 369 if (ansiseq) 370 tputs(ansiseq, 1, putch); 371 } 372 373 if (colors[c][1] != -1) { 374 ansiseq = tparm(ansi_bgcol, colors[c][1]); 375 if (ansiseq) 376 tputs(ansiseq, 1, putch); 377 } 378 } 379 380 void 381 endcolor() 382 { 383 tputs(ansi_coloff, 1, putch); 384 } 385 386 int 387 colortype(mode) 388 mode_t mode; 389 { 390 switch(mode & S_IFMT) { 391 case S_IFDIR: 392 if (mode & S_IWOTH) 393 if (mode & S_ISTXT) 394 printcolor(C_WSDIR); 395 else 396 printcolor(C_WDIR); 397 else 398 printcolor(C_DIR); 399 return(1); 400 case S_IFLNK: 401 printcolor(C_LNK); 402 return(1); 403 case S_IFSOCK: 404 printcolor(C_SOCK); 405 return(1); 406 case S_IFIFO: 407 printcolor(C_FIFO); 408 return(1); 409 case S_IFBLK: 410 printcolor(C_BLK); 411 return(1); 412 case S_IFCHR: 413 printcolor(C_CHR); 414 return(1); 415 } 416 if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 417 if (mode & S_ISUID) 418 printcolor(C_SUID); 419 else if (mode & S_ISGID) 420 printcolor(C_SGID); 421 else 422 printcolor(C_EXEC); 423 return(1); 424 } 425 return(0); 426 } 427 428 void 429 parsecolors(cs) 430 char *cs; 431 { 432 int i, j, len; 433 char c[2]; 434 if (cs == NULL) cs = ""; /* LSCOLORS not set */ 435 len = strlen(cs); 436 for (i = 0 ; i < C_NUMCOLORS ; i++) { 437 if (len <= 2*i) { 438 c[0] = defcolors[2*i]; 439 c[1] = defcolors[2*i+1]; 440 } 441 else { 442 c[0] = cs[2*i]; 443 c[1] = cs[2*i+1]; 444 } 445 for (j = 0 ; j < 2 ; j++) { 446 if ((c[j] < '0' || c[j] > '7') && 447 tolower((unsigned char)c[j]) != 'x') { 448 fprintf(stderr, 449 "error: invalid character '%c' in LSCOLORS env var\n", 450 c[j]); 451 c[j] = defcolors[2*i+j]; 452 } 453 if (c[j] == 'x') 454 colors[i][j] = -1; 455 else 456 colors[i][j] = c[j]-'0'; 457 } 458 } 459 } 460 461 /* ARGSUSED */ 462 void colorquit(sig) 463 int sig; 464 { 465 endcolor(); 466 exit(1); 467 } 468 #endif /*COLORLS*/ 469 470 static void 471 printlink(p) 472 FTSENT *p; 473 { 474 int lnklen; 475 char name[MAXPATHLEN + 1], path[MAXPATHLEN + 1]; 476 477 if (p->fts_level == FTS_ROOTLEVEL) 478 (void)snprintf(name, sizeof(name), "%s", p->fts_name); 479 else 480 (void)snprintf(name, sizeof(name), 481 "%s/%s", p->fts_parent->fts_accpath, p->fts_name); 482 if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) { 483 (void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno)); 484 return; 485 } 486 path[lnklen] = '\0'; 487 if (f_octal || f_octal_escape) { 488 (void)printf(" -> "); 489 (void)prn_octal(path); 490 } 491 else (void)printf(" -> %s", path); 492 } 493