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#if 0 38#ifndef lint 39static char sccsid[] = "@(#)print.c 8.4 (Berkeley) 4/17/94"; 40#endif /* not lint */ 41#endif 42#include <sys/cdefs.h> 43__RCSID("$FreeBSD: src/bin/ls/print.c,v 1.57 2002/08/29 14:29:09 keramida Exp $"); 44 45#include <sys/param.h> 46#include <sys/stat.h> 47#ifdef __APPLE__ 48#include <sys/acl.h> 49#include <sys/xattr.h> 50#include <sys/types.h> 51#include <grp.h> 52#include <pwd.h> 53#include <TargetConditionals.h> 54#if !TARGET_OS_EMBEDDED 55#include <membership.h> 56#include <membershipPriv.h> 57#endif 58#include <uuid/uuid.h> 59#endif 60 61#include <err.h> 62#include <errno.h> 63#include <fts.h> 64#include <math.h> 65#include <langinfo.h> 66#include <libutil.h> 67#include <stdio.h> 68#include <stdlib.h> 69#include <string.h> 70#include <time.h> 71#include <unistd.h> 72#ifdef COLORLS 73#include <ctype.h> 74#include <termcap.h> 75#include <signal.h> 76#endif 77#include <stdint.h> /* intmax_t */ 78#include <assert.h> 79#ifdef __APPLE__ 80#include <get_compat.h> 81#else 82#define COMPAT_MODE(a,b) (1) 83#endif /* __APPLE__ */ 84 85#include "ls.h" 86#include "extern.h" 87 88static int printaname(FTSENT *, u_long, u_long); 89static void printlink(FTSENT *); 90static void printtime(time_t); 91static int printtype(u_int); 92static void printsize(size_t, off_t); 93#ifdef COLORLS 94static void endcolor(int); 95static int colortype(mode_t); 96#endif 97 98#define IS_NOPRINT(p) ((p)->fts_number == NO_PRINT) 99 100#ifdef COLORLS 101/* Most of these are taken from <sys/stat.h> */ 102typedef enum Colors { 103 C_DIR, /* directory */ 104 C_LNK, /* symbolic link */ 105 C_SOCK, /* socket */ 106 C_FIFO, /* pipe */ 107 C_EXEC, /* executable */ 108 C_BLK, /* block special */ 109 C_CHR, /* character special */ 110 C_SUID, /* setuid executable */ 111 C_SGID, /* setgid executable */ 112 C_WSDIR, /* directory writeble to others, with sticky 113 * bit */ 114 C_WDIR, /* directory writeble to others, without 115 * sticky bit */ 116 C_NUMCOLORS /* just a place-holder */ 117} Colors; 118 119static const char *defcolors = "exfxcxdxbxegedabagacad"; 120 121/* colors for file types */ 122static struct { 123 int num[2]; 124 int bold; 125} colors[C_NUMCOLORS]; 126#endif 127 128void 129printscol(DISPLAY *dp) 130{ 131 FTSENT *p; 132 133 if (COMPAT_MODE("bin/ls", "Unix2003")) { 134 if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) 135 (void)printf("total %qu\n", (u_int64_t)howmany(dp->btotal, blocksize)); 136 } 137 138 for (p = dp->list; p; p = p->fts_link) { 139 if (IS_NOPRINT(p)) 140 continue; 141 (void)printaname(p, dp->s_inode, dp->s_block); 142 (void)putchar('\n'); 143 } 144} 145 146/* 147 * print name in current style 148 */ 149static int 150printname(const char *name) 151{ 152 if (f_octal || f_octal_escape) 153 return prn_octal(name); 154 else if (f_nonprint) 155 return prn_printable(name); 156 else 157 return prn_normal(name); 158} 159 160/* 161 * print access control list 162 */ 163static struct { 164 acl_perm_t perm; 165 char *name; 166 int flags; 167#define ACL_PERM_DIR (1<<0) 168#define ACL_PERM_FILE (1<<1) 169} acl_perms[] = { 170 {ACL_READ_DATA, "read", ACL_PERM_FILE}, 171 {ACL_LIST_DIRECTORY, "list", ACL_PERM_DIR}, 172 {ACL_WRITE_DATA, "write", ACL_PERM_FILE}, 173 {ACL_ADD_FILE, "add_file", ACL_PERM_DIR}, 174 {ACL_EXECUTE, "execute", ACL_PERM_FILE}, 175 {ACL_SEARCH, "search", ACL_PERM_DIR}, 176 {ACL_DELETE, "delete", ACL_PERM_FILE | ACL_PERM_DIR}, 177 {ACL_APPEND_DATA, "append", ACL_PERM_FILE}, 178 {ACL_ADD_SUBDIRECTORY, "add_subdirectory", ACL_PERM_DIR}, 179 {ACL_DELETE_CHILD, "delete_child", ACL_PERM_DIR}, 180 {ACL_READ_ATTRIBUTES, "readattr", ACL_PERM_FILE | ACL_PERM_DIR}, 181 {ACL_WRITE_ATTRIBUTES, "writeattr", ACL_PERM_FILE | ACL_PERM_DIR}, 182 {ACL_READ_EXTATTRIBUTES, "readextattr", ACL_PERM_FILE | ACL_PERM_DIR}, 183 {ACL_WRITE_EXTATTRIBUTES, "writeextattr", ACL_PERM_FILE | ACL_PERM_DIR}, 184 {ACL_READ_SECURITY, "readsecurity", ACL_PERM_FILE | ACL_PERM_DIR}, 185 {ACL_WRITE_SECURITY, "writesecurity", ACL_PERM_FILE | ACL_PERM_DIR}, 186 {ACL_CHANGE_OWNER, "chown", ACL_PERM_FILE | ACL_PERM_DIR}, 187 {0, NULL, 0} 188}; 189 190static struct { 191 acl_flag_t flag; 192 char *name; 193 int flags; 194} acl_flags[] = { 195 {ACL_ENTRY_FILE_INHERIT, "file_inherit", ACL_PERM_DIR}, 196 {ACL_ENTRY_DIRECTORY_INHERIT, "directory_inherit", ACL_PERM_DIR}, 197 {ACL_ENTRY_LIMIT_INHERIT, "limit_inherit", ACL_PERM_FILE | ACL_PERM_DIR}, 198 {ACL_ENTRY_ONLY_INHERIT, "only_inherit", ACL_PERM_DIR}, 199 {0, NULL, 0} 200}; 201 202static char * 203uuid_to_name(uuid_t *uu) 204{ 205#if TARGET_OS_EMBEDDED 206 return strdup("<UNKNOWN>"); 207#else /* !TARGET_OS_EMBEDDED */ 208 int is_gid = -1; 209 struct group *tgrp = NULL; 210 struct passwd *tpass = NULL; 211 char *name = NULL; 212 uid_t id; 213 214 215#define MAXNAMETAG (MAXLOGNAME + 6) /* + strlen("group:") */ 216 name = (char *) malloc(MAXNAMETAG); 217 218 if (NULL == name) 219 err(1, "malloc"); 220 221 if (!f_numericonly) { 222 if (0 != mbr_uuid_to_id(*uu, &id, &is_gid)) 223 goto errout; 224 } 225 226 switch (is_gid) { 227 case ID_TYPE_UID: 228 tpass = getpwuid(id); 229 if (!tpass) { 230 goto errout; 231 } 232 snprintf(name, MAXNAMETAG, "%s:%s", "user", tpass->pw_name); 233 break; 234 case ID_TYPE_GID: 235 tgrp = getgrgid((gid_t) id); 236 if (!tgrp) { 237 goto errout; 238 } 239 snprintf(name, MAXNAMETAG, "%s:%s", "group", tgrp->gr_name); 240 break; 241 default: 242 goto errout; 243 } 244 return name; 245 errout: 246 uuid_unparse_upper(*uu, name); 247 return name; 248#endif /* !TARGET_OS_EMBEDDED */ 249} 250 251static void 252printxattr(DISPLAY *dp, char *filename, ssize_t xattr) 253{ 254 int flags = XATTR_NOFOLLOW; 255 char *buf = malloc(xattr); 256 257 if (NULL == buf) 258 err(1, "malloc"); 259 if (listxattr(filename, buf, xattr, flags) > 0) { 260 char *name; 261 for (name = buf; name < buf+xattr; name += strlen(name) + 1) { 262 ssize_t size = getxattr(filename, name, 0, 0, 0, flags); 263 putchar('\t'); 264 printname(name); 265 putchar('\t'); 266 printsize(dp->s_size, size); 267 putchar('\n'); 268 } 269 } 270 free(buf); 271} 272 273static void 274printacl(acl_t acl, int isdir) 275{ 276 acl_entry_t entry = NULL; 277 int index; 278 uuid_t *applicable; 279 char *name = NULL; 280 acl_tag_t tag; 281 acl_flagset_t flags; 282 acl_permset_t perms; 283 char *type; 284 int i, first; 285 286 287 for (index = 0; 288 acl_get_entry(acl, entry == NULL ? ACL_FIRST_ENTRY : ACL_NEXT_ENTRY, &entry) == 0; 289 index++) { 290 if (acl_get_tag_type(entry, &tag) != 0) 291 continue; 292 if (acl_get_flagset_np(entry, &flags) != 0) 293 continue; 294 if (acl_get_permset(entry, &perms) != 0) 295 continue; 296 if ((applicable = (uuid_t *) acl_get_qualifier(entry)) == NULL) 297 continue; 298 name = uuid_to_name(applicable); 299 acl_free(applicable); 300 switch(tag) { 301 case ACL_EXTENDED_ALLOW: 302 type = "allow"; 303 break; 304 case ACL_EXTENDED_DENY: 305 type = "deny"; 306 break; 307 default: 308 type = "unknown"; 309 } 310 311 (void)printf(" %d: %s%s %s ", 312 index, 313 name, 314 acl_get_flag_np(flags, ACL_ENTRY_INHERITED) ? " inherited" : "", 315 type); 316 317 if (name) 318 free(name); 319 320 for (i = 0, first = 0; acl_perms[i].name != NULL; i++) { 321 if (acl_get_perm_np(perms, acl_perms[i].perm) == 0) 322 continue; 323 if (!(acl_perms[i].flags & (isdir ? ACL_PERM_DIR : ACL_PERM_FILE))) 324 continue; 325 (void)printf("%s%s", first++ ? "," : "", acl_perms[i].name); 326 } 327 for (i = 0; acl_flags[i].name != NULL; i++) { 328 if (acl_get_flag_np(flags, acl_flags[i].flag) == 0) 329 continue; 330 if (!(acl_flags[i].flags & (isdir ? ACL_PERM_DIR : ACL_PERM_FILE))) 331 continue; 332 (void)printf("%s%s", first++ ? "," : "", acl_flags[i].name); 333 } 334 335 (void)putchar('\n'); 336 } 337 338} 339 340void 341printlong(DISPLAY *dp) 342{ 343 struct stat *sp; 344 FTSENT *p; 345 NAMES *np; 346 char buf[20]; 347#ifdef __APPLE__ 348 acl_t acl = NULL; 349 acl_entry_t dummy; 350 char full_path[MAXPATHLEN]; 351 char *filename; 352 ssize_t xattr = 0; 353 char str[2]; 354#endif 355#ifdef COLORLS 356 int color_printed = 0; 357#endif 358 359 if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) 360 (void)printf("total %qu\n", (u_int64_t)howmany(dp->btotal, blocksize)); 361 362 for (p = dp->list; p; p = p->fts_link) { 363 if (IS_NOPRINT(p)) 364 continue; 365 sp = p->fts_statp; 366 if (f_inode) 367#if _DARWIN_FEATURE_64_BIT_INODE 368 (void)printf("%*llu ", dp->s_inode, (u_quad_t)sp->st_ino); 369#else 370 (void)printf("%*lu ", dp->s_inode, (u_long)sp->st_ino); 371#endif 372 if (f_size) 373 (void)printf("%*qu ", 374 dp->s_block, (u_int64_t)howmany(sp->st_blocks, blocksize)); 375 strmode(sp->st_mode, buf); 376 np = p->fts_pointer; 377#ifdef __APPLE__ 378 buf[10] = '\0'; /* make +/@ abut the mode */ 379 filename = p->fts_name; 380 if (p->fts_level != FTS_ROOTLEVEL) 381 { 382 snprintf(full_path, sizeof full_path, "%s/%s", 383 p->fts_parent->fts_accpath, p->fts_name); 384 filename = full_path; 385 } 386 /* symlinks can not have ACLs */ 387 acl = acl_get_link_np(filename, ACL_TYPE_EXTENDED); 388 if (acl && acl_get_entry(acl, ACL_FIRST_ENTRY, &dummy) == -1) { 389 acl_free(acl); 390 acl = NULL; 391 } 392 xattr = listxattr(filename, NULL, 0, XATTR_NOFOLLOW); 393 if (xattr < 0) 394 xattr = 0; 395 str[1] = '\0'; 396 if (xattr > 0) 397 str[0] = '@'; 398 else if (acl != NULL) 399 str[0] = '+'; 400 else 401 str[0] = ' '; 402#endif /* __APPLE__ */ 403 if (f_group && f_owner) { /* means print neither */ 404#ifdef __APPLE__ 405 (void)printf("%s%s %*u ", buf, str, dp->s_nlink, 406 sp->st_nlink); 407#else /* ! __APPLE__ */ 408 (void)printf("%s %*u ", buf, dp->s_nlink, 409 sp->st_nlink); 410#endif /* __APPLE__ */ 411 } 412 else if (f_group) { 413#ifdef __APPLE__ 414 (void)printf("%s%s %*u %-*s ", buf, str, dp->s_nlink, 415 sp->st_nlink, dp->s_group, np->group); 416#else /* ! __APPLE__ */ 417 (void)printf("%s %*u %-*s ", buf, dp->s_nlink, 418 sp->st_nlink, dp->s_group, np->group); 419#endif /* __APPLE__ */ 420 } 421 else if (f_owner) { 422#ifdef __APPLE__ 423 (void)printf("%s%s %*u %-*s ", buf, str, dp->s_nlink, 424 sp->st_nlink, dp->s_user, np->user); 425#else /* ! __APPLE__ */ 426 (void)printf("%s %*u %-*s ", buf, dp->s_nlink, 427 sp->st_nlink, dp->s_user, np->user); 428#endif /* __APPLE__ */ 429 } 430 else { 431#ifdef __APPLE__ 432 (void)printf("%s%s %*u %-*s %-*s ", buf, str, dp->s_nlink, 433 sp->st_nlink, dp->s_user, np->user, dp->s_group, 434 np->group); 435#else /* ! __APPLE__ */ 436 (void)printf("%s %*u %-*s %-*s ", buf, dp->s_nlink, 437 sp->st_nlink, dp->s_user, np->user, dp->s_group, 438 np->group); 439#endif /* ! __APPLE__ */ 440 } 441 if (f_flags) 442 (void)printf("%-*s ", dp->s_flags, np->flags); 443 if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode)) 444 if (minor(sp->st_rdev) > 255 || minor(sp->st_rdev) < 0) 445 (void)printf("%3d, 0x%08x ", 446 major(sp->st_rdev), 447 (u_int)minor(sp->st_rdev)); 448 else 449 (void)printf("%3d, %3d ", 450 major(sp->st_rdev), minor(sp->st_rdev)); 451 else if (dp->bcfile) 452 (void)printf("%*s%*qu ", 453 8 - dp->s_size, "", dp->s_size, (u_int64_t)sp->st_size); 454 else 455 printsize(dp->s_size, sp->st_size); 456 if (f_accesstime) 457 printtime(sp->st_atime); 458 else if (f_statustime) 459 printtime(sp->st_ctime); 460 else if (f_birthtime) 461 printtime(sp->st_birthtime); 462 else 463 printtime(sp->st_mtime); 464#ifdef COLORLS 465 if (f_color) 466 color_printed = colortype(sp->st_mode); 467#endif 468 (void)printname(p->fts_name); 469#ifdef COLORLS 470 if (f_color && color_printed) 471 endcolor(0); 472#endif 473 if (f_type) 474 (void)printtype(sp->st_mode); 475 if (S_ISLNK(sp->st_mode)) 476 printlink(p); 477 (void)putchar('\n'); 478#ifdef __APPLE__ 479 if (f_xattr && xattr) { 480 printxattr(dp, filename, xattr); 481 } 482 if (acl != NULL) { 483 if (f_acl) 484 printacl(acl, S_ISDIR(sp->st_mode)); 485 acl_free(acl); 486 acl = NULL; 487 } 488#endif /* __APPLE__ */ 489 } 490} 491 492void 493printstream(DISPLAY *dp) 494{ 495 FTSENT *p; 496 extern int termwidth; 497 int chcnt; 498 499 for (p = dp->list, chcnt = 0; p; p = p->fts_link) { 500 if (p->fts_number == NO_PRINT) 501 continue; 502 if (strlen(p->fts_name) + chcnt + 503 (p->fts_link ? 2 : 0) >= (unsigned)termwidth) { 504 putchar('\n'); 505 chcnt = 0; 506 } 507 chcnt += printaname(p, dp->s_inode, dp->s_block); 508 if (p->fts_link) { 509 printf(", "); 510 chcnt += 2; 511 } 512 } 513 if (chcnt) 514 putchar('\n'); 515} 516 517void 518printcol(DISPLAY *dp) 519{ 520 extern int termwidth; 521 static FTSENT **array; 522 static int lastentries = -1; 523 FTSENT *p; 524 int base; 525 int chcnt; 526 int cnt; 527 int col; 528 int colwidth; 529 int endcol; 530 int num; 531 int numcols; 532 int numrows; 533 int row; 534 int tabwidth; 535 536 if (f_notabs) 537 tabwidth = 1; 538 else 539 tabwidth = 8; 540 541 /* 542 * Have to do random access in the linked list -- build a table 543 * of pointers. 544 */ 545 if ((lastentries == -1) || (dp->entries > lastentries)) { 546 lastentries = dp->entries; 547 if ((array = 548 realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) { 549 warn(NULL); 550 printscol(dp); 551 } 552 } 553 for (p = dp->list, num = 0; p; p = p->fts_link) 554 if (p->fts_number != NO_PRINT) 555 array[num++] = p; 556 557 colwidth = dp->maxlen; 558 if (f_inode) 559 colwidth += dp->s_inode + 1; 560 if (f_size) 561 colwidth += dp->s_block + 1; 562 if (f_type) 563 colwidth += 1; 564 565 colwidth = (colwidth + tabwidth) & ~(tabwidth - 1); 566 if (termwidth < 2 * colwidth) { 567 printscol(dp); 568 return; 569 } 570 numcols = termwidth / colwidth; 571 numrows = num / numcols; 572 if (num % numcols) 573 ++numrows; 574 575 assert(dp->list); 576 if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) 577 (void)printf("total %qu\n", (u_int64_t)howmany(dp->btotal, blocksize)); 578 579 base = 0; 580 for (row = 0; row < numrows; ++row) { 581 endcol = colwidth; 582 if (!f_sortacross) 583 base = row; 584 for (col = 0, chcnt = 0; col < numcols; ++col) { 585 chcnt += printaname(array[base], dp->s_inode, 586 dp->s_block); 587 if (f_sortacross) 588 base++; 589 else 590 base += numrows; 591 if (base >= num) 592 break; 593 while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1))) 594 <= endcol) { 595 if (f_sortacross && col + 1 >= numcols) 596 break; 597 (void)putchar(f_notabs ? ' ' : '\t'); 598 chcnt = cnt; 599 } 600 endcol += colwidth; 601 } 602 (void)putchar('\n'); 603 } 604} 605 606/* 607 * print [inode] [size] name 608 * return # of characters printed, no trailing characters. 609 */ 610static int 611printaname(FTSENT *p, u_long inodefield, u_long sizefield) 612{ 613 struct stat *sp; 614 int chcnt; 615#ifdef COLORLS 616 int color_printed = 0; 617#endif 618 619 sp = p->fts_statp; 620 chcnt = 0; 621 if (f_inode) 622#if _DARWIN_FEATURE_64_BIT_INODE 623 chcnt += printf("%*llu ", (int)inodefield, (u_quad_t)sp->st_ino); 624#else 625 chcnt += printf("%*lu ", (int)inodefield, (u_long)sp->st_ino); 626#endif 627 if (f_size) 628 chcnt += printf("%*qu ", 629 (int)sizefield, (u_int64_t)howmany(sp->st_blocks, blocksize)); 630#ifdef COLORLS 631 if (f_color) 632 color_printed = colortype(sp->st_mode); 633#endif 634 chcnt += printname(p->fts_name); 635#ifdef COLORLS 636 if (f_color && color_printed) 637 endcolor(0); 638#endif 639 if (f_type) 640 chcnt += printtype(sp->st_mode); 641 return (chcnt); 642} 643 644static void 645printtime(time_t ftime) 646{ 647 char longstring[80]; 648 static time_t now; 649 const char *format; 650 static int d_first = -1; 651 652 if (d_first < 0) 653 d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 654 if (now == 0) 655 now = time(NULL); 656 657#define SIXMONTHS ((365 / 2) * 86400) 658 if (f_sectime) 659 /* mmm dd hh:mm:ss yyyy || dd mmm hh:mm:ss yyyy */ 660 format = d_first ? "%e %b %T %Y " : "%b %e %T %Y "; 661 else if (COMPAT_MODE("bin/ls", "Unix2003")) { 662 if (ftime + SIXMONTHS > now && ftime <= now) 663 /* mmm dd hh:mm || dd mmm hh:mm */ 664 format = d_first ? "%e %b %R " : "%b %e %R "; 665 else 666 /* mmm dd yyyy || dd mmm yyyy */ 667 format = d_first ? "%e %b %Y " : "%b %e %Y "; 668 } 669 else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS) 670 /* mmm dd hh:mm || dd mmm hh:mm */ 671 format = d_first ? "%e %b %R " : "%b %e %R "; 672 else 673 /* mmm dd yyyy || dd mmm yyyy */ 674 format = d_first ? "%e %b %Y " : "%b %e %Y "; 675 strftime(longstring, sizeof(longstring), format, localtime(&ftime)); 676 fputs(longstring, stdout); 677} 678 679static int 680printtype(u_int mode) 681{ 682 683 if (f_slash) { 684 if ((mode & S_IFMT) == S_IFDIR) { 685 (void)putchar('/'); 686 return (1); 687 } 688 return (0); 689 } 690 691 switch (mode & S_IFMT) { 692 case S_IFDIR: 693 (void)putchar('/'); 694 return (1); 695 case S_IFIFO: 696 (void)putchar('|'); 697 return (1); 698 case S_IFLNK: 699 (void)putchar('@'); 700 return (1); 701 case S_IFSOCK: 702 (void)putchar('='); 703 return (1); 704 case S_IFWHT: 705 (void)putchar('%'); 706 return (1); 707 default: 708 break; 709 } 710 if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 711 (void)putchar('*'); 712 return (1); 713 } 714 return (0); 715} 716 717#ifdef COLORLS 718static int 719putch(int c) 720{ 721 (void)putchar(c); 722 return 0; 723} 724 725static int 726writech(int c) 727{ 728 char tmp = c; 729 730 (void)write(STDOUT_FILENO, &tmp, 1); 731 return 0; 732} 733 734static void 735printcolor(Colors c) 736{ 737 char *ansiseq; 738 739 if (colors[c].bold) 740 tputs(enter_bold, 1, putch); 741 742 if (colors[c].num[0] != -1) { 743 ansiseq = tgoto(ansi_fgcol, 0, colors[c].num[0]); 744 if (ansiseq) 745 tputs(ansiseq, 1, putch); 746 } 747 if (colors[c].num[1] != -1) { 748 ansiseq = tgoto(ansi_bgcol, 0, colors[c].num[1]); 749 if (ansiseq) 750 tputs(ansiseq, 1, putch); 751 } 752} 753 754static void 755endcolor(int sig) 756{ 757 tputs(ansi_coloff, 1, sig ? writech : putch); 758 tputs(attrs_off, 1, sig ? writech : putch); 759} 760 761static int 762colortype(mode_t mode) 763{ 764 switch (mode & S_IFMT) { 765 case S_IFDIR: 766 if (mode & S_IWOTH) 767 if (mode & S_ISTXT) 768 printcolor(C_WSDIR); 769 else 770 printcolor(C_WDIR); 771 else 772 printcolor(C_DIR); 773 return (1); 774 case S_IFLNK: 775 printcolor(C_LNK); 776 return (1); 777 case S_IFSOCK: 778 printcolor(C_SOCK); 779 return (1); 780 case S_IFIFO: 781 printcolor(C_FIFO); 782 return (1); 783 case S_IFBLK: 784 printcolor(C_BLK); 785 return (1); 786 case S_IFCHR: 787 printcolor(C_CHR); 788 return (1); 789 } 790 if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 791 if (mode & S_ISUID) 792 printcolor(C_SUID); 793 else if (mode & S_ISGID) 794 printcolor(C_SGID); 795 else 796 printcolor(C_EXEC); 797 return (1); 798 } 799 return (0); 800} 801 802void 803parsecolors(const char *cs) 804{ 805 int i; 806 int j; 807 int len; 808 char c[2]; 809 short legacy_warn = 0; 810 811 if (cs == NULL) 812 cs = ""; /* LSCOLORS not set */ 813 len = strlen(cs); 814 for (i = 0; i < C_NUMCOLORS; i++) { 815 colors[i].bold = 0; 816 817 if (len <= 2 * i) { 818 c[0] = defcolors[2 * i]; 819 c[1] = defcolors[2 * i + 1]; 820 } else { 821 c[0] = cs[2 * i]; 822 c[1] = cs[2 * i + 1]; 823 } 824 for (j = 0; j < 2; j++) { 825 /* Legacy colours used 0-7 */ 826 if (c[j] >= '0' && c[j] <= '7') { 827 colors[i].num[j] = c[j] - '0'; 828 if (!legacy_warn) { 829 fprintf(stderr, 830 "warn: LSCOLORS should use " 831 "characters a-h instead of 0-9 (" 832 "see the manual page)\n"); 833 } 834 legacy_warn = 1; 835 } else if (c[j] >= 'a' && c[j] <= 'h') 836 colors[i].num[j] = c[j] - 'a'; 837 else if (c[j] >= 'A' && c[j] <= 'H') { 838 colors[i].num[j] = c[j] - 'A'; 839 colors[i].bold = 1; 840 } else if (tolower((unsigned char)c[j] == 'x')) 841 colors[i].num[j] = -1; 842 else { 843 fprintf(stderr, 844 "error: invalid character '%c' in LSCOLORS" 845 " env var\n", c[j]); 846 colors[i].num[j] = -1; 847 } 848 } 849 } 850} 851 852void 853colorquit(int sig) 854{ 855 endcolor(sig); 856 857 (void)signal(sig, SIG_DFL); 858 (void)kill(getpid(), sig); 859} 860 861#endif /* COLORLS */ 862 863static void 864printlink(FTSENT *p) 865{ 866 int lnklen; 867 char name[MAXPATHLEN + 1]; 868 char path[MAXPATHLEN + 1]; 869 870 if (p->fts_level == FTS_ROOTLEVEL) 871 (void)snprintf(name, sizeof(name), "%s", p->fts_name); 872 else 873 (void)snprintf(name, sizeof(name), 874 "%s/%s", p->fts_parent->fts_accpath, p->fts_name); 875 if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) { 876 (void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno)); 877 return; 878 } 879 path[lnklen] = '\0'; 880 (void)printf(" -> "); 881 (void)printname(path); 882} 883 884static void 885printsize(size_t width, off_t bytes) 886{ 887 888 if (f_humanval) { 889 char buf[5]; 890 891 humanize_number(buf, sizeof(buf), (int64_t)bytes, "", 892 HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 893 (void)printf("%5s ", buf); 894 } else 895 (void)printf("%*jd ", (u_int)width, (intmax_t)bytes); 896} 897