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#include <sys/cdefs.h> 38#ifndef lint 39__used static const char copyright[] = 40"@(#) Copyright (c) 1989, 1993, 1994\n\ 41 The Regents of the University of California. All rights reserved.\n"; 42#endif /* not lint */ 43 44#if 0 45#ifndef lint 46static char sccsid[] = "@(#)ls.c 8.5 (Berkeley) 4/2/94"; 47#endif /* not lint */ 48#endif 49#include <sys/cdefs.h> 50__RCSID("$FreeBSD: src/bin/ls/ls.c,v 1.66 2002/09/21 01:28:36 wollman Exp $"); 51 52#include <sys/types.h> 53#include <sys/stat.h> 54#include <sys/ioctl.h> 55 56#include <dirent.h> 57#include <err.h> 58#include <errno.h> 59#include <fts.h> 60#include <grp.h> 61#include <limits.h> 62#include <locale.h> 63#include <pwd.h> 64#include <stdio.h> 65#include <stdlib.h> 66#include <string.h> 67#include <unistd.h> 68#ifdef COLORLS 69#include <termcap.h> 70#include <signal.h> 71#endif 72#ifdef __APPLE__ 73#include <sys/acl.h> 74#include <sys/xattr.h> 75#include <sys/param.h> 76#include <get_compat.h> 77#else 78#define COMPAT_MODE(a,b) (1) 79#endif /* __APPLE__ */ 80#include "ls.h" 81#include "extern.h" 82 83/* 84 * Upward approximation of the maximum number of characters needed to 85 * represent a value of integral type t as a string, excluding the 86 * NUL terminator, with provision for a sign. 87 */ 88#define STRBUF_SIZEOF(t) (1 + CHAR_BIT * sizeof(t) / 3 + 1) 89 90static void display(FTSENT *, FTSENT *); 91static u_quad_t makenines(u_quad_t); 92static int mastercmp(const FTSENT **, const FTSENT **); 93static void traverse(int, char **, int); 94 95static void (*printfcn)(DISPLAY *); 96static int (*sortfcn)(const FTSENT *, const FTSENT *); 97 98long blocksize; /* block size units */ 99int termwidth = 80; /* default terminal width */ 100 101/* flags */ 102 int f_accesstime; /* use time of last access */ 103 int f_birthtime; /* use time of file birth */ 104 int f_flags; /* show flags associated with a file */ 105 int f_humanval; /* show human-readable file sizes */ 106 int f_inode; /* print inode */ 107static int f_kblocks; /* print size in kilobytes */ 108static int f_listdir; /* list actual directory, not contents */ 109static int f_listdot; /* list files beginning with . */ 110 int f_longform; /* long listing format */ 111 int f_nonprint; /* show unprintables as ? */ 112static int f_nosort; /* don't sort output */ 113 int f_notabs; /* don't use tab-separated multi-col output */ 114 int f_numericonly; /* don't convert uid/gid to name */ 115 int f_octal; /* show unprintables as \xxx */ 116 int f_octal_escape; /* like f_octal but use C escapes if possible */ 117static int f_recursive; /* ls subdirectories also */ 118static int f_reversesort; /* reverse whatever sort is used */ 119 int f_sectime; /* print the real time for all files */ 120static int f_singlecol; /* use single column output */ 121 int f_size; /* list size in short listing */ 122 int f_slash; /* similar to f_type, but only for dirs */ 123 int f_sortacross; /* sort across rows, not down columns */ 124 int f_statustime; /* use time of last mode change */ 125 int f_stream; /* stream the output, separate with commas */ 126static int f_timesort; /* sort by time vice name */ 127static int f_sizesort; /* sort by size */ 128 int f_type; /* add type character for non-regular files */ 129static int f_whiteout; /* show whiteout entries */ 130 int f_acl; /* show ACLs in long listing */ 131 int f_xattr; /* show extended attributes in long listing */ 132 int f_group; /* show group */ 133 int f_owner; /* show owner */ 134#ifdef COLORLS 135 int f_color; /* add type in color for non-regular files */ 136 137char *ansi_bgcol; /* ANSI sequence to set background colour */ 138char *ansi_fgcol; /* ANSI sequence to set foreground colour */ 139char *ansi_coloff; /* ANSI sequence to reset colours */ 140char *attrs_off; /* ANSI sequence to turn off attributes */ 141char *enter_bold; /* ANSI sequence to set color to bold mode */ 142#endif 143 144static int rval; 145 146int 147main(int argc, char *argv[]) 148{ 149 static char dot[] = ".", *dotav[] = {dot, NULL}; 150 struct winsize win; 151 int ch, fts_options, notused; 152 char *p; 153#ifdef COLORLS 154 char termcapbuf[1024]; /* termcap definition buffer */ 155 char tcapbuf[512]; /* capability buffer */ 156 char *bp = tcapbuf; 157#endif 158 159 if (argc < 1) 160 usage(); 161 (void)setlocale(LC_ALL, ""); 162 163 /* Terminal defaults to -Cq, non-terminal defaults to -1. */ 164 if (isatty(STDOUT_FILENO)) { 165 termwidth = 80; 166 if ((p = getenv("COLUMNS")) != NULL && *p != '\0') 167 termwidth = atoi(p); 168 else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) != -1 && 169 win.ws_col > 0) 170 termwidth = win.ws_col; 171 f_nonprint = 1; 172 } else { 173 f_singlecol = 1; 174 /* retrieve environment variable, in case of explicit -C */ 175 p = getenv("COLUMNS"); 176 if (p) 177 termwidth = atoi(p); 178 } 179 180 /* Root is -A automatically. */ 181 if (!getuid()) 182 f_listdot = 1; 183 184 fts_options = FTS_PHYSICAL; 185 while ((ch = getopt(argc, argv, "1@ABCFGHLOPRSTUWabcdefghiklmnopqrstuvwx")) 186 != -1) { 187 switch (ch) { 188 /* 189 * The -1, -C, -x and -l options all override each other so 190 * shell aliasing works right. 191 */ 192 case '1': 193 f_singlecol = 1; 194 f_longform = 0; 195 f_stream = 0; 196 break; 197 case 'B': 198 f_nonprint = 0; 199 f_octal = 1; 200 f_octal_escape = 0; 201 break; 202 case 'C': 203 f_sortacross = f_longform = f_singlecol = 0; 204 break; 205 case 'l': 206 f_longform = 1; 207 f_singlecol = 0; 208 f_stream = 0; 209 break; 210 case 'x': 211 f_sortacross = 1; 212 f_longform = 0; 213 f_singlecol = 0; 214 break; 215 /* The -c and -u options override each other. */ 216 case 'c': 217 f_statustime = 1; 218 f_accesstime = f_birthtime = 0; 219 break; 220 case 'u': 221 f_accesstime = 1; 222 f_statustime = f_birthtime = 0; 223 break; 224 case 'U': 225 f_birthtime = 1; 226 f_statustime = f_accesstime = 0; 227 break; 228 case 'F': 229 f_type = 1; 230 f_slash = 0; 231 break; 232 case 'H': 233 if (COMPAT_MODE("bin/ls", "Unix2003")) { 234 fts_options &= ~FTS_LOGICAL; 235 fts_options |= FTS_PHYSICAL; 236 fts_options |= FTS_COMFOLLOWDIR; 237 } else 238 fts_options |= FTS_COMFOLLOW; 239 break; 240 case 'G': 241 setenv("CLICOLOR", "", 1); 242 break; 243 case 'L': 244 fts_options &= ~FTS_PHYSICAL; 245 fts_options |= FTS_LOGICAL; 246 if (COMPAT_MODE("bin/ls", "Unix2003")) { 247 fts_options &= ~(FTS_COMFOLLOW|FTS_COMFOLLOWDIR); 248 } 249 break; 250 case 'P': 251 fts_options &= ~(FTS_COMFOLLOW|FTS_COMFOLLOWDIR); 252 fts_options &= ~FTS_LOGICAL; 253 fts_options |= FTS_PHYSICAL; 254 break; 255 case 'R': 256 f_recursive = 1; 257 break; 258 case 'a': 259 fts_options |= FTS_SEEDOT; 260 /* FALLTHROUGH */ 261 case 'A': 262 f_listdot = 1; 263 break; 264 /* The -d option turns off the -R option. */ 265 case 'd': 266 f_listdir = 1; 267 f_recursive = 0; 268 break; 269 case 'f': 270 f_nosort = 1; 271 if (COMPAT_MODE("bin/ls", "Unix2003")) { 272 fts_options |= FTS_SEEDOT; 273 f_listdot = 1; 274 } 275 break; 276 case 'g': /* Compatibility with Unix03 */ 277 if (COMPAT_MODE("bin/ls", "Unix2003")) { 278 f_group = 1; 279 f_longform = 1; 280 f_singlecol = 0; 281 f_stream = 0; 282 } 283 break; 284 case 'h': 285 f_humanval = 1; 286 break; 287 case 'i': 288 f_inode = 1; 289 break; 290 case 'k': 291 f_kblocks = 1; 292 break; 293 case 'm': 294 f_stream = 1; 295 f_singlecol = 0; 296 f_longform = 0; 297 break; 298 case 'n': 299 f_numericonly = 1; 300 if (COMPAT_MODE("bin/ls", "Unix2003")) { 301 f_longform = 1; 302 f_singlecol = 0; 303 f_stream = 0; 304 } 305 break; 306 case 'o': 307 if (COMPAT_MODE("bin/ls", "Unix2003")) { 308 f_owner = 1; 309 f_longform = 1; 310 f_singlecol = 0; 311 f_stream = 0; 312 } else { 313 f_flags = 1; 314 } 315 break; 316 case 'p': 317 f_slash = 1; 318 f_type = 1; 319 break; 320 case 'q': 321 f_nonprint = 1; 322 f_octal = 0; 323 f_octal_escape = 0; 324 break; 325 case 'r': 326 f_reversesort = 1; 327 break; 328 case 'S': 329 /* Darwin 1.4.1 compatibility */ 330 f_sizesort = 1; 331 break; 332 case 's': 333 f_size = 1; 334 break; 335 case 'T': 336 f_sectime = 1; 337 break; 338 case 't': 339 f_timesort = 1; 340 break; 341 case 'W': 342 f_whiteout = 1; 343 break; 344 case 'v': 345 /* Darwin 1.4.1 compatibility */ 346 f_nonprint = 0; 347 break; 348 case 'b': 349 f_nonprint = 0; 350 f_octal = 0; 351 f_octal_escape = 1; 352 break; 353 case 'w': 354 f_nonprint = 0; 355 f_octal = 0; 356 f_octal_escape = 0; 357 break; 358 case 'e': 359 f_acl = 1; 360 break; 361 case '@': 362 f_xattr = 1; 363 break; 364 case 'O': 365 f_flags = 1; 366 break; 367 default: 368 case '?': 369 usage(); 370 } 371 } 372 argc -= optind; 373 argv += optind; 374 375 /* Enabling of colours is conditional on the environment. */ 376 if (getenv("CLICOLOR") && 377 (isatty(STDOUT_FILENO) || getenv("CLICOLOR_FORCE"))) 378#ifdef COLORLS 379 if (tgetent(termcapbuf, getenv("TERM")) == 1) { 380 ansi_fgcol = tgetstr("AF", &bp); 381 ansi_bgcol = tgetstr("AB", &bp); 382 attrs_off = tgetstr("me", &bp); 383 enter_bold = tgetstr("md", &bp); 384 385 /* To switch colours off use 'op' if 386 * available, otherwise use 'oc', or 387 * don't do colours at all. */ 388 ansi_coloff = tgetstr("op", &bp); 389 if (!ansi_coloff) 390 ansi_coloff = tgetstr("oc", &bp); 391 if (ansi_fgcol && ansi_bgcol && ansi_coloff) 392 f_color = 1; 393 } 394#else 395 (void)fprintf(stderr, "Color support not compiled in.\n"); 396#endif /*COLORLS*/ 397 398#ifdef COLORLS 399 if (f_color) { 400 /* 401 * We can't put tabs and color sequences together: 402 * column number will be incremented incorrectly 403 * for "stty oxtabs" mode. 404 */ 405 f_notabs = 1; 406 (void)signal(SIGINT, colorquit); 407 (void)signal(SIGQUIT, colorquit); 408 parsecolors(getenv("LSCOLORS")); 409 } 410#endif 411 412 /* 413 * If not -F, -i, -l, -s or -t options, don't require stat 414 * information, unless in color mode in which case we do 415 * need this to determine which colors to display. 416 */ 417 if (!f_inode && !f_longform && !f_size && !f_timesort && !f_type && !f_sizesort 418#ifdef COLORLS 419 && !f_color 420#endif 421 ) 422 fts_options |= FTS_NOSTAT; 423 424 /* 425 * If not -F, -d or -l options, follow any symbolic links listed on 426 * the command line. 427 */ 428 if (!f_longform && !f_listdir && !f_type && !f_inode) 429 fts_options |= FTS_COMFOLLOW; 430 431 /* 432 * If -W, show whiteout entries 433 */ 434#ifdef FTS_WHITEOUT 435 if (f_whiteout) 436 fts_options |= FTS_WHITEOUT; 437#endif 438 439 /* If -l or -s, figure out block size. */ 440 if (f_longform || f_size) { 441 if (f_kblocks) 442 blocksize = 2; 443 else { 444 (void)getbsize(¬used, &blocksize); 445 blocksize /= 512; 446 } 447 } 448 /* Select a sort function. */ 449 if (f_reversesort) { 450 if (f_sizesort) 451 sortfcn = revsizecmp; 452 else if (!f_timesort) 453 sortfcn = revnamecmp; 454 else if (f_accesstime) 455 sortfcn = revacccmp; 456 else if (f_statustime) 457 sortfcn = revstatcmp; 458 else if (f_birthtime) 459 sortfcn = revbirthcmp; 460 else /* Use modification time. */ 461 sortfcn = revmodcmp; 462 } else { 463 if (f_sizesort) 464 sortfcn = sizecmp; 465 else if (!f_timesort) 466 sortfcn = namecmp; 467 else if (f_accesstime) 468 sortfcn = acccmp; 469 else if (f_statustime) 470 sortfcn = statcmp; 471 else if (f_birthtime) 472 sortfcn = birthcmp; 473 else /* Use modification time. */ 474 sortfcn = modcmp; 475 } 476 477 /* Select a print function. */ 478 if (f_singlecol) 479 printfcn = printscol; 480 else if (f_longform) 481 printfcn = printlong; 482 else if (f_stream) 483 printfcn = printstream; 484 else 485 printfcn = printcol; 486 487 if (argc) 488 traverse(argc, argv, fts_options); 489 else 490 traverse(1, dotav, fts_options); 491 exit(rval); 492} 493 494static int output; /* If anything output. */ 495 496/* 497 * Traverse() walks the logical directory structure specified by the argv list 498 * in the order specified by the mastercmp() comparison function. During the 499 * traversal it passes linked lists of structures to display() which represent 500 * a superset (may be exact set) of the files to be displayed. 501 */ 502static void 503traverse(int argc, char *argv[], int options) 504{ 505 FTS *ftsp; 506 FTSENT *p, *chp; 507 int ch_options, error; 508 509 if ((ftsp = 510 fts_open(argv, options, f_nosort ? NULL : mastercmp)) == NULL) 511 err(1, "fts_open"); 512 513 display(NULL, fts_children(ftsp, 0)); 514 if (f_listdir) { 515 fts_close(ftsp); 516 return; 517 } 518 519 /* 520 * If not recursing down this tree and don't need stat info, just get 521 * the names. 522 */ 523 ch_options = !f_recursive && options & FTS_NOSTAT ? FTS_NAMEONLY : 0; 524 525 while ((p = fts_read(ftsp)) != NULL) 526 switch (p->fts_info) { 527 case FTS_DC: 528 warnx("%s: directory causes a cycle", p->fts_name); 529 if (COMPAT_MODE("bin/ls", "Unix2003")) { 530 rval = 1; 531 } 532 break; 533 case FTS_DNR: 534 case FTS_ERR: 535 warnx("%s: %s", p->fts_name, strerror(p->fts_errno)); 536 rval = 1; 537 break; 538 case FTS_D: 539 if (p->fts_level != FTS_ROOTLEVEL && 540 p->fts_name[0] == '.' && !f_listdot) { 541 fts_set(ftsp, p, FTS_SKIP); 542 break; 543 } 544 545 /* 546 * If already output something, put out a newline as 547 * a separator. If multiple arguments, precede each 548 * directory with its name. 549 */ 550 if (output) 551 (void)printf("\n%s:\n", p->fts_path); 552 else if (argc > 1) { 553 (void)printf("%s:\n", p->fts_path); 554 output = 1; 555 } 556 chp = fts_children(ftsp, ch_options); 557 if (COMPAT_MODE("bin/ls", "Unix2003") && ((options & FTS_LOGICAL)!=0)) { 558 FTSENT *curr; 559 for (curr = chp; curr; curr = curr->fts_link) { 560 if (curr->fts_info == FTS_SLNONE) 561 curr->fts_number = NO_PRINT; 562 } 563 } 564 display(p, chp); 565 566 if (!f_recursive && chp != NULL) 567 (void)fts_set(ftsp, p, FTS_SKIP); 568 break; 569 case FTS_SLNONE: /* Same as default unless Unix conformance */ 570 if (COMPAT_MODE("bin/ls", "Unix2003")) { 571 if ((options & FTS_LOGICAL)!=0) { /* -L was specified */ 572 warnx("%s: %s", p->fts_name, strerror(p->fts_errno ?: ENOENT)); 573 rval = 1; 574 } 575 } 576 break; 577 default: 578 break; 579 } 580 error = errno; 581 fts_close(ftsp); 582 errno = error; 583 584 if (errno) 585 err(1, "fts_read"); 586} 587 588/* 589 * Display() takes a linked list of FTSENT structures and passes the list 590 * along with any other necessary information to the print function. P 591 * points to the parent directory of the display list. 592 */ 593static void 594display(FTSENT *p, FTSENT *list) 595{ 596 struct stat *sp; 597 DISPLAY d; 598 FTSENT *cur; 599 NAMES *np; 600 off_t maxsize; 601 u_int64_t btotal, maxblock; 602 u_long lattrlen, maxlen, maxnlink, maxlattr; 603 ino_t maxinode; 604 int bcfile, maxflags; 605 gid_t maxgroup; 606 uid_t maxuser; 607 size_t flen, ulen, glen; 608 char *initmax; 609 int entries, needstats; 610 const char *user, *group; 611 char *flags, *lattr = NULL; 612 char buf[STRBUF_SIZEOF(u_quad_t) + 1]; 613 char ngroup[STRBUF_SIZEOF(uid_t) + 1]; 614 char nuser[STRBUF_SIZEOF(gid_t) + 1]; 615#ifdef __APPLE__ 616 acl_entry_t dummy; 617 ssize_t xattr_size; 618 char *filename; 619 char path[MAXPATHLEN+1]; 620#endif // __APPLE__ 621 /* 622 * If list is NULL there are two possibilities: that the parent 623 * directory p has no children, or that fts_children() returned an 624 * error. We ignore the error case since it will be replicated 625 * on the next call to fts_read() on the post-order visit to the 626 * directory p, and will be signaled in traverse(). 627 */ 628 if (list == NULL) 629 return; 630 631 needstats = f_inode || f_longform || f_size; 632 btotal = 0; 633 initmax = getenv("LS_COLWIDTHS"); 634 /* Fields match -lios order. New ones should be added at the end. */ 635 maxlattr = maxblock = maxinode = maxlen = maxnlink = 636 maxuser = maxgroup = maxflags = maxsize = 0; 637 if (initmax != NULL && *initmax != '\0') { 638 char *initmax2, *jinitmax; 639 int ninitmax; 640 641 /* Fill-in "::" as "0:0:0" for the sake of scanf. */ 642 jinitmax = initmax2 = malloc(strlen(initmax) * 2 + 2); 643 if (jinitmax == NULL) 644 err(1, "malloc"); 645 if (*initmax == ':') 646 strcpy(initmax2, "0:"), initmax2 += 2; 647 else 648 *initmax2++ = *initmax, *initmax2 = '\0'; 649 for (initmax++; *initmax != '\0'; initmax++) { 650 if (initmax[-1] == ':' && initmax[0] == ':') { 651 *initmax2++ = '0'; 652 *initmax2++ = initmax[0]; 653 initmax2[1] = '\0'; 654 } else { 655 *initmax2++ = initmax[0]; 656 initmax2[1] = '\0'; 657 } 658 } 659 if (initmax2[-1] == ':') 660 strcpy(initmax2, "0"); 661 662 ninitmax = sscanf(jinitmax, 663#if _DARWIN_FEATURE_64_BIT_INODE 664 " %llu : %qu : %lu : %i : %i : %i : %qu : %lu : %lu ", 665#else 666 " %lu : %qu : %lu : %i : %i : %i : %qu : %lu : %lu ", 667#endif 668 &maxinode, &maxblock, &maxnlink, &maxuser, 669 &maxgroup, &maxflags, &maxsize, &maxlen, &maxlattr); 670 f_notabs = 1; 671 switch (ninitmax) { 672 case 0: 673 maxinode = 0; 674 /* FALLTHROUGH */ 675 case 1: 676 maxblock = 0; 677 /* FALLTHROUGH */ 678 case 2: 679 maxnlink = 0; 680 /* FALLTHROUGH */ 681 case 3: 682 maxuser = 0; 683 /* FALLTHROUGH */ 684 case 4: 685 maxgroup = 0; 686 /* FALLTHROUGH */ 687 case 5: 688 maxflags = 0; 689 /* FALLTHROUGH */ 690 case 6: 691 maxsize = 0; 692 /* FALLTHROUGH */ 693 case 7: 694 maxlen = 0; 695 /* FALLTHROUGH */ 696 case 8: 697 maxlattr = 0; 698 /* FALLTHROUGH */ 699#ifdef COLORLS 700 if (!f_color) 701#endif 702 f_notabs = 0; 703 /* FALLTHROUGH */ 704 default: 705 break; 706 } 707 maxinode = makenines(maxinode); 708 maxblock = makenines(maxblock); 709 maxnlink = makenines(maxnlink); 710 maxsize = makenines(maxsize); 711 } 712 bcfile = 0; 713 flags = NULL; 714 for (cur = list, entries = 0; cur; cur = cur->fts_link) { 715 if (cur->fts_info == FTS_ERR || cur->fts_info == FTS_NS) { 716 warnx("%s: %s", 717 cur->fts_name, strerror(cur->fts_errno)); 718 cur->fts_number = NO_PRINT; 719 rval = 1; 720 continue; 721 } 722 /* 723 * P is NULL if list is the argv list, to which different rules 724 * apply. 725 */ 726 if (p == NULL) { 727 /* Directories will be displayed later. */ 728 if (cur->fts_info == FTS_D && !f_listdir) { 729 cur->fts_number = NO_PRINT; 730 continue; 731 } 732 } else { 733 /* Only display dot file if -a/-A set. */ 734 if (cur->fts_name[0] == '.' && !f_listdot) { 735 cur->fts_number = NO_PRINT; 736 continue; 737 } 738 } 739 if (cur->fts_namelen > maxlen) 740 maxlen = cur->fts_namelen; 741 if (f_octal || f_octal_escape) { 742 u_long t = len_octal(cur->fts_name, cur->fts_namelen); 743 744 if (t > maxlen) 745 maxlen = t; 746 } 747 if (needstats) { 748 sp = cur->fts_statp; 749 if (sp->st_blocks > maxblock) 750 maxblock = sp->st_blocks; 751 if (sp->st_ino > maxinode) 752 maxinode = sp->st_ino; 753 if (sp->st_nlink > maxnlink) 754 maxnlink = sp->st_nlink; 755 if (sp->st_size > maxsize) 756 maxsize = sp->st_size; 757 758 btotal += sp->st_blocks; 759 if (f_longform) { 760 if (f_numericonly) { 761 (void)snprintf(nuser, sizeof(nuser), 762 "%u", sp->st_uid); 763 (void)snprintf(ngroup, sizeof(ngroup), 764 "%u", sp->st_gid); 765 user = nuser; 766 group = ngroup; 767 } else { 768 user = user_from_uid(sp->st_uid, 0); 769 group = group_from_gid(sp->st_gid, 0); 770 } 771 if ((ulen = strlen(user)) > maxuser) 772 maxuser = ulen; 773 if ((glen = strlen(group)) > maxgroup) 774 maxgroup = glen; 775 if (f_flags) { 776 flags = fflagstostr(sp->st_flags); 777 if (flags != NULL && *flags == '\0') { 778 free(flags); 779 flags = strdup("-"); 780 } 781 if (flags == NULL) 782 err(1, "fflagstostr"); 783 flen = strlen(flags); 784 if (flen > (size_t)maxflags) 785 maxflags = flen; 786 } else 787 flen = 0; 788 lattr = NULL; 789 lattrlen = 0; 790 791 if ((np = calloc(1, sizeof(NAMES) + lattrlen + 792 ulen + glen + flen + 4)) == NULL) 793 err(1, "malloc"); 794 795 np->user = &np->data[0]; 796 (void)strcpy(np->user, user); 797 np->group = &np->data[ulen + 1]; 798 (void)strcpy(np->group, group); 799#ifdef __APPLE__ 800 if (cur->fts_level == FTS_ROOTLEVEL) { 801 filename = cur->fts_name; 802 } else { 803 snprintf(path, sizeof(path), "%s/%s", cur->fts_parent->fts_accpath, cur->fts_name); 804 filename = path; 805 } 806 xattr_size = listxattr(filename, NULL, 0, XATTR_NOFOLLOW); 807 if (xattr_size < 0) { 808 xattr_size = 0; 809 } 810 if ((xattr_size > 0) && f_xattr) { 811 /* collect sizes */ 812 np->xattr_names = malloc(xattr_size); 813 listxattr(filename, np->xattr_names, xattr_size, XATTR_NOFOLLOW); 814 for (char *name = np->xattr_names; name < np->xattr_names + xattr_size; 815 name += strlen(name)+1) { 816 np->xattr_sizes = reallocf(np->xattr_sizes, (np->xattr_count+1) * sizeof(np->xattr_sizes[0])); 817 np->xattr_sizes[np->xattr_count] = getxattr(filename, name, 0, 0, 0, XATTR_NOFOLLOW); 818 np->xattr_count++; 819 } 820 } 821 /* symlinks can not have ACLs */ 822 np->acl = acl_get_link_np(filename, ACL_TYPE_EXTENDED); 823 if (np->acl) { 824 if (acl_get_entry(np->acl, ACL_FIRST_ENTRY, &dummy) == -1) { 825 acl_free(np->acl); 826 np->acl = NULL; 827 } 828 } 829 if (xattr_size > 0) { 830 np->mode_suffix = '@'; 831 } else if (np->acl) { 832 np->mode_suffix = '+'; 833 } else { 834 np->mode_suffix = ' '; 835 } 836 if (!f_acl) { 837 acl_free(np->acl); 838 np->acl = NULL; 839 } 840#endif // __APPLE__ 841 if (S_ISCHR(sp->st_mode) || 842 S_ISBLK(sp->st_mode)) 843 bcfile = 1; 844 845 if (f_flags) { 846 np->flags = &np->data[ulen + glen + 2]; 847 (void)strcpy(np->flags, flags); 848 free(flags); 849 } 850 cur->fts_pointer = np; 851 } 852 } 853 ++entries; 854 } 855 856 if (!entries) 857 return; 858 859 d.list = list; 860 d.entries = entries; 861 d.maxlen = maxlen; 862 if (needstats) { 863 d.bcfile = bcfile; 864 d.btotal = btotal; 865 (void)snprintf(buf, sizeof(buf), "%qu", (u_int64_t)maxblock); 866 d.s_block = strlen(buf); 867 d.s_flags = maxflags; 868 d.s_lattr = maxlattr; 869 d.s_group = maxgroup; 870#if _DARWIN_FEATURE_64_BIT_INODE 871 (void)snprintf(buf, sizeof(buf), "%llu", maxinode); 872#else 873 (void)snprintf(buf, sizeof(buf), "%lu", maxinode); 874#endif 875 d.s_inode = strlen(buf); 876 (void)snprintf(buf, sizeof(buf), "%lu", maxnlink); 877 d.s_nlink = strlen(buf); 878 (void)snprintf(buf, sizeof(buf), "%qu", (u_int64_t)maxsize); 879 d.s_size = strlen(buf); 880 d.s_user = maxuser; 881 } 882 printfcn(&d); 883 output = 1; 884 885 if (f_longform) { 886 for (cur = list; cur; cur = cur->fts_link) { 887 np = cur->fts_pointer; 888 if (np) { 889 if (np->acl) { 890 acl_free(np->acl); 891 } 892 free(np->xattr_names); 893 free(np->xattr_sizes); 894 free(np); 895 cur->fts_pointer = NULL; 896 } 897 } 898 } 899} 900 901/* 902 * Ordering for mastercmp: 903 * If ordering the argv (fts_level = FTS_ROOTLEVEL) return non-directories 904 * as larger than directories. Within either group, use the sort function. 905 * All other levels use the sort function. Error entries remain unsorted. 906 */ 907static int 908mastercmp(const FTSENT **a, const FTSENT **b) 909{ 910 int a_info, b_info; 911 912 a_info = (*a)->fts_info; 913 if (a_info == FTS_ERR) 914 return (0); 915 b_info = (*b)->fts_info; 916 if (b_info == FTS_ERR) 917 return (0); 918 919 if (a_info == FTS_NS || b_info == FTS_NS) 920 return (namecmp(*a, *b)); 921 922 if (a_info != b_info && 923 (*a)->fts_level == FTS_ROOTLEVEL && !f_listdir) { 924 if (a_info == FTS_D) 925 return (1); 926 if (b_info == FTS_D) 927 return (-1); 928 } 929 return (sortfcn(*a, *b)); 930} 931 932/* 933 * Makenines() returns (10**n)-1. This is useful for converting a width 934 * into a number that wide in decimal. 935 */ 936static u_quad_t 937makenines(u_quad_t n) 938{ 939 u_long i; 940 u_quad_t reg; 941 942 reg = 1; 943 /* Use a loop instead of pow(), since all values of n are small. */ 944 for (i = 0; i < n; i++) 945 reg *= 10; 946 reg--; 947 948 return reg; 949} 950