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