1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 1447 akaplan * Common Development and Distribution License (the "License"). 6 1447 akaplan * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 9664 jason 22 0 stevel /* 23 9664 jason * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 9664 jason * Use is subject to license terms. 25 9664 jason */ 26 9664 jason 27 9664 jason /* 28 9664 jason * Copyright 2009 Jason King. All rights reserved. 29 0 stevel * Use is subject to license terms. 30 0 stevel */ 31 0 stevel 32 0 stevel /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 33 0 stevel /* All Rights Reserved */ 34 0 stevel 35 0 stevel /* Copyright (c) 1987, 1988 Microsoft Corporation */ 36 0 stevel /* All Rights Reserved */ 37 0 stevel 38 0 stevel /* 39 0 stevel * List files or directories 40 0 stevel */ 41 0 stevel 42 0 stevel #include <sys/param.h> 43 0 stevel #include <sys/types.h> 44 0 stevel #include <sys/mkdev.h> 45 0 stevel #include <sys/stat.h> 46 0 stevel #include <sys/acl.h> 47 0 stevel 48 0 stevel #include <wchar.h> 49 0 stevel #include <stdio.h> 50 0 stevel #include <ctype.h> 51 0 stevel #include <dirent.h> 52 0 stevel #include <string.h> 53 0 stevel #include <locale.h> 54 0 stevel #include <curses.h> 55 9664 jason #include <term.h> 56 0 stevel #include <termios.h> 57 0 stevel #include <stdlib.h> 58 0 stevel #include <widec.h> 59 0 stevel #include <locale.h> 60 0 stevel #include <wctype.h> 61 0 stevel #include <pwd.h> 62 0 stevel #include <grp.h> 63 0 stevel #include <limits.h> 64 0 stevel #include <fcntl.h> 65 0 stevel #include <unistd.h> 66 0 stevel #include <libgen.h> 67 0 stevel #include <errno.h> 68 789 ahrens #include <aclutils.h> 69 5331 amw #include <libnvpair.h> 70 5331 amw #include <libcmdutils.h> 71 5331 amw #include <attr.h> 72 9664 jason #include <getopt.h> 73 9664 jason #include <inttypes.h> 74 0 stevel 75 0 stevel #ifndef STANDALONE 76 0 stevel #define TERMINFO 77 0 stevel #endif 78 0 stevel 79 0 stevel /* 80 0 stevel * -DNOTERMINFO can be defined on the cc command line to prevent 81 0 stevel * the use of terminfo. This should be done on systems not having 82 5331 amw * the terminfo feature(pre 6.0 systems ?). 83 0 stevel * As a result, columnar listings assume 80 columns for output, 84 0 stevel * unless told otherwise via the COLUMNS environment variable. 85 0 stevel */ 86 0 stevel #ifdef NOTERMINFO 87 0 stevel #undef TERMINFO 88 0 stevel #endif 89 0 stevel 90 0 stevel #include <term.h> 91 0 stevel 92 0 stevel #define BFSIZE 16 93 0 stevel /* this bit equals 1 in lflags of structure lbuf if *namep is to be used */ 94 0 stevel #define ISARG 0100000 95 0 stevel 96 0 stevel /* 97 0 stevel * this flag has been added to manipulate the display of S instead of 'l' when 98 0 stevel * the file is not a regular file and when group execution bit is off 99 0 stevel */ 100 0 stevel #define LS_NOTREG 010000 101 0 stevel 102 0 stevel 103 0 stevel /* 104 0 stevel * Date and time formats 105 0 stevel * 106 0 stevel * b --- abbreviated month name 107 0 stevel * e --- day number 108 0 stevel * Y --- year in the form ccyy 109 0 stevel * H --- hour(24-hour version) 110 0 stevel * M --- minute 111 0 stevel * F --- yyyy-mm-dd 112 0 stevel * T --- hh:mm:ss 113 0 stevel * z --- time zone as hours displacement from UTC 114 0 stevel * note that %F and %z are from the ISO C99 standard and are 115 0 stevel * not present in older C libraries 116 0 stevel */ 117 9664 jason #define FORMAT_OLD " %b %e %Y " 118 9664 jason #define FORMAT_NEW " %b %e %H:%M " 119 9664 jason #define FORMAT_LONG " %b %e %T %Y " 120 9664 jason #define FORMAT_ISO_FULL " %%F %%T.%.09ld %%z " 121 9664 jason #define FORMAT_ISO_LONG " %F %R " 122 9664 jason #define FORMAT_ISO_NEW " %m-%d %H:%M " 123 9664 jason #define FORMAT_ISO_OLD " %F " 124 0 stevel 125 0 stevel #undef BUFSIZ 126 0 stevel #define BUFSIZ 4096 127 0 stevel #define NUMBER_WIDTH 40 128 0 stevel #define FMTSIZE 50 129 0 stevel 130 0 stevel struct ditem { 131 0 stevel dev_t dev; /* directory items device number */ 132 0 stevel ino_t ino; /* directory items inode number */ 133 0 stevel struct ditem *parent; /* dir items ptr to its parent's info */ 134 0 stevel }; 135 5331 amw /* Holds boolean extended system attributes */ 136 5331 amw struct attrb { 137 5331 amw char *name; 138 5331 amw }; 139 5331 amw /* Holds timestamp extended system attributes */ 140 5331 amw struct attrtm { 141 5331 amw char *name; 142 5331 amw uint64_t stm; 143 5331 amw uint64_t nstm; 144 5331 amw }; 145 0 stevel 146 9664 jason #define LSA_NONE (0) 147 9664 jason #define LSA_BOLD (1L << 0) 148 9664 jason #define LSA_UNDERSCORE (1L << 1) 149 9664 jason #define LSA_BLINK (1L << 2) 150 9664 jason #define LSA_REVERSE (1L << 3) 151 9664 jason #define LSA_CONCEALED (1L << 4) 152 9664 jason 153 9664 jason /* these should be ordered most general to most specific */ 154 9664 jason typedef enum LS_CFTYPE { 155 9664 jason LS_NORMAL, 156 9664 jason LS_FILE, 157 9664 jason LS_EXEC, 158 9664 jason LS_DIR, 159 9664 jason LS_LINK, 160 9664 jason LS_FIFO, 161 9664 jason LS_SOCK, 162 9664 jason LS_DOOR, 163 9664 jason LS_BLK, 164 9664 jason LS_CHR, 165 9664 jason LS_PORT, 166 9664 jason LS_STICKY, 167 9664 jason LS_ORPHAN, 168 9664 jason LS_SETGID, 169 9664 jason LS_SETUID, 170 9664 jason LS_OTHER_WRITABLE, 171 9664 jason LS_STICKY_OTHER_WRITABLE, 172 9664 jason LS_PAT 173 9664 jason } ls_cftype_t; 174 9664 jason 175 10059 jason typedef struct { 176 9664 jason char *sfx; 177 9664 jason ls_cftype_t ftype; 178 9664 jason int attr; 179 9664 jason int fg; 180 9664 jason int bg; 181 9664 jason } ls_color_t; 182 10059 jason 183 10059 jason struct lbuf { 184 10059 jason union { 185 10059 jason char lname[MAXNAMLEN]; /* used for filename in a directory */ 186 10059 jason char *namep; /* for name in ls-command; */ 187 10059 jason } ln; 188 10059 jason char ltype; /* filetype */ 189 10059 jason ino_t lnum; /* inode number of file */ 190 10059 jason mode_t lflags; /* 0777 bits used as r,w,x permissions */ 191 10059 jason nlink_t lnl; /* number of links to file */ 192 10059 jason uid_t luid; 193 10059 jason gid_t lgid; 194 10059 jason off_t lsize; /* filesize or major/minor dev numbers */ 195 10059 jason blkcnt_t lblocks; /* number of file blocks */ 196 10059 jason timestruc_t lmtime; 197 10059 jason timestruc_t lat; 198 10059 jason timestruc_t lct; 199 10059 jason timestruc_t lmt; 200 10059 jason char *flinkto; /* symbolic link contents */ 201 10059 jason char acl; /* indicate there are additional acl entries */ 202 10059 jason int cycle; /* cycle detected flag */ 203 10059 jason struct ditem *ancinfo; /* maintains ancestor info */ 204 10059 jason acl_t *aclp; /* ACL if present */ 205 10059 jason struct attrb *exttr; /* boolean extended system attributes */ 206 10059 jason struct attrtm *extm; /* timestamp extended system attributes */ 207 10059 jason ls_color_t *color; /* color for entry */ 208 10059 jason ls_color_t *link_color; /* color for symlink */ 209 10059 jason }; 210 10059 jason 211 10059 jason struct dchain { 212 10059 jason char *dc_name; /* path name */ 213 10059 jason int cycle_detected; /* cycle detected visiting this directory */ 214 10059 jason struct ditem *myancinfo; /* this directory's ancestry info */ 215 10059 jason struct dchain *dc_next; /* next directory in the chain */ 216 10059 jason }; 217 9664 jason 218 0 stevel /* 219 0 stevel * A numbuf_t is used when converting a number to a string representation 220 0 stevel */ 221 0 stevel typedef char numbuf_t[NUMBER_WIDTH]; 222 0 stevel 223 0 stevel static struct dchain *dfirst; /* start of the dir chain */ 224 0 stevel static struct dchain *cdfirst; /* start of the current dir chain */ 225 0 stevel static struct dchain *dtemp; /* temporary - used for linking */ 226 0 stevel static char *curdir; /* the current directory */ 227 0 stevel 228 0 stevel static int first = 1; /* true if first line is not yet printed */ 229 0 stevel static int nfiles = 0; /* number of flist entries in current use */ 230 0 stevel static int nargs = 0; /* number of flist entries used for arguments */ 231 0 stevel static int maxfils = 0; /* number of flist/lbuf entries allocated */ 232 0 stevel static int maxn = 0; /* number of flist entries with lbufs asigned */ 233 0 stevel static int quantn = 64; /* allocation growth quantum */ 234 0 stevel 235 0 stevel static struct lbuf *nxtlbf; /* ptr to next lbuf to be assigned */ 236 0 stevel static struct lbuf **flist; /* ptr to list of lbuf pointers */ 237 0 stevel static struct lbuf *gstat(char *, int, struct ditem *); 238 0 stevel static char *getname(uid_t); 239 0 stevel static char *getgroup(gid_t); 240 0 stevel static char *makename(char *, char *); 241 0 stevel static void pentry(struct lbuf *); 242 0 stevel static void column(void); 243 0 stevel static void pmode(mode_t aflag); 244 0 stevel static void selection(int *); 245 0 stevel static void new_line(void); 246 0 stevel static void rddir(char *, struct ditem *); 247 0 stevel static int strcol(unsigned char *); 248 0 stevel static void pem(struct lbuf **, struct lbuf **, int); 249 0 stevel static void pdirectory(char *, int, int, int, struct ditem *); 250 0 stevel static struct cachenode *findincache(struct cachenode **, long); 251 0 stevel static void csi_pprintf(unsigned char *); 252 0 stevel static void pprintf(char *, char *); 253 0 stevel static int compar(struct lbuf **pp1, struct lbuf **pp2); 254 0 stevel static char *number_to_scaled_string(numbuf_t buf, 255 0 stevel unsigned long long number, 256 0 stevel long scale); 257 0 stevel static void record_ancestry(char *, struct stat *, struct lbuf *, 258 0 stevel int, struct ditem *); 259 9664 jason static void ls_color_init(void); 260 10059 jason static ls_color_t *ls_color_find(const char *, mode_t); 261 10059 jason static void ls_start_color(ls_color_t *); 262 9664 jason static void ls_end_color(void); 263 0 stevel 264 0 stevel static int aflg; 265 0 stevel static int atflg; 266 0 stevel static int bflg; 267 0 stevel static int cflg; 268 0 stevel static int dflg; 269 0 stevel static int eflg; 270 0 stevel static int fflg; 271 0 stevel static int gflg; 272 0 stevel static int hflg; 273 0 stevel static int iflg; 274 0 stevel static int lflg; 275 0 stevel static int mflg; 276 0 stevel static int nflg; 277 0 stevel static int oflg; 278 0 stevel static int pflg; 279 0 stevel static int qflg; 280 0 stevel static int rflg = 1; /* init to 1 for special use in compar */ 281 0 stevel static int sflg; 282 0 stevel static int tflg; 283 0 stevel static int uflg; 284 9664 jason static int Uflg; 285 9664 jason static int wflg; 286 0 stevel static int xflg; 287 0 stevel static int Aflg; 288 9664 jason static int Bflg; 289 0 stevel static int Cflg; 290 0 stevel static int Eflg; 291 0 stevel static int Fflg; 292 0 stevel static int Hflg; 293 0 stevel static int Lflg; 294 0 stevel static int Rflg; 295 0 stevel static int Sflg; 296 789 ahrens static int vflg; 297 1420 marks static int Vflg; 298 5331 amw static int saflg; /* boolean extended system attr. */ 299 5331 amw static int sacnt; /* number of extended system attr. */ 300 5331 amw static int copt; 301 5331 amw static int vopt; 302 5331 amw static int tmflg; /* create time ext. system attr. */ 303 5331 amw static int ctm; 304 5331 amw static int atm; 305 5331 amw static int mtm; 306 5331 amw static int crtm; 307 5331 amw static int alltm; 308 0 stevel static long hscale; 309 0 stevel static mode_t flags; 310 0 stevel static int err = 0; /* Contains return code */ 311 9664 jason static int colorflg; 312 9664 jason static int file_typeflg; 313 0 stevel 314 0 stevel static uid_t lastuid = (uid_t)-1; 315 0 stevel static gid_t lastgid = (gid_t)-1; 316 0 stevel static char *lastuname = NULL; 317 0 stevel static char *lastgname = NULL; 318 0 stevel 319 9664 jason /* statreq > 0 if any of sflg, (n)lflg, tflg, Sflg, colorflg are on */ 320 0 stevel static int statreq; 321 0 stevel 322 9664 jason static uint64_t block_size = 1; 323 0 stevel static char *dotp = "."; 324 0 stevel 325 0 stevel static u_longlong_t tblocks; /* number of blocks of files in a directory */ 326 0 stevel static time_t year, now; 327 0 stevel 328 0 stevel static int num_cols = 80; 329 0 stevel static int colwidth; 330 0 stevel static int filewidth; 331 0 stevel static int fixedwidth; 332 0 stevel static int nomocore; 333 0 stevel static int curcol; 334 0 stevel 335 0 stevel static struct winsize win; 336 0 stevel 337 9664 jason /* if time_fmt_new is left NULL, time_fmt_old is used for all times */ 338 9664 jason static const char *time_fmt_old = FORMAT_OLD; /* non-recent files */ 339 9664 jason static const char *time_fmt_new = FORMAT_NEW; /* recent files */ 340 9664 jason static int time_custom; /* != 0 if a custom format */ 341 5331 amw static char time_buf[FMTSIZE]; /* array to hold day and time */ 342 9664 jason 343 9664 jason static int lsc_debug; 344 9664 jason static ls_color_t *lsc_match; 345 9664 jason static ls_color_t *lsc_colors; 346 9664 jason static size_t lsc_ncolors; 347 9664 jason static char *lsc_bold; 348 9664 jason static char *lsc_underline; 349 9664 jason static char *lsc_blink; 350 9664 jason static char *lsc_reverse; 351 9664 jason static char *lsc_concealed; 352 9664 jason static char *lsc_none; 353 9664 jason static char *lsc_setfg; 354 9664 jason static char *lsc_setbg; 355 10059 jason static ls_color_t *lsc_orphan; 356 0 stevel 357 0 stevel #define NOTWORKINGDIR(d, l) (((l) < 2) || \ 358 0 stevel (strcmp((d) + (l) - 2, "/.") != 0)) 359 0 stevel 360 0 stevel #define NOTPARENTDIR(d, l) (((l) < 3) || \ 361 0 stevel (strcmp((d) + (l) - 3, "/..") != 0)) 362 5331 amw /* Extended system attributes support */ 363 5331 amw static int get_sysxattr(char *, struct lbuf *); 364 5331 amw static void set_sysattrb_display(char *, boolean_t, struct lbuf *); 365 5331 amw static void set_sysattrtm_display(char *, struct lbuf *); 366 9664 jason static void format_time(time_t, time_t); 367 5331 amw static void print_time(struct lbuf *); 368 5331 amw static void format_attrtime(struct lbuf *); 369 5331 amw static void *xmalloc(size_t, struct lbuf *); 370 5331 amw static void free_sysattr(struct lbuf *); 371 5331 amw static nvpair_t *pair; 372 5331 amw static nvlist_t *response; 373 6866 basabi static int acl_err; 374 9664 jason 375 9664 jason const struct option long_options[] = { 376 9664 jason { "all", no_argument, NULL, 'a' }, 377 9664 jason { "almost-all", no_argument, NULL, 'A' }, 378 9664 jason { "escape", no_argument, NULL, 'b' }, 379 9664 jason { "classify", no_argument, NULL, 'F' }, 380 9664 jason { "human-readable", no_argument, NULL, 'h' }, 381 9664 jason { "dereference", no_argument, NULL, 'L' }, 382 9664 jason { "dereference-command-line", no_argument, NULL, 'H' }, 383 9664 jason { "ignore-backups", no_argument, NULL, 'B' }, 384 9664 jason { "inode", no_argument, NULL, 'i' }, 385 9664 jason { "numeric-uid-gid", no_argument, NULL, 'n' }, 386 9664 jason { "no-group", no_argument, NULL, 'o' }, 387 9664 jason { "hide-control-chars", no_argument, NULL, 'q' }, 388 9664 jason { "reverse", no_argument, NULL, 'r' }, 389 9664 jason { "recursive", no_argument, NULL, 'R' }, 390 9664 jason { "size", no_argument, NULL, 's' }, 391 9664 jason { "width", required_argument, NULL, 'w' }, 392 9664 jason 393 9664 jason /* no short options for these */ 394 9664 jason { "block-size", required_argument, NULL, 0 }, 395 9664 jason { "full-time", no_argument, NULL, 0 }, 396 9664 jason { "si", no_argument, NULL, 0 }, 397 9664 jason { "color", optional_argument, NULL, 0 }, 398 9664 jason { "colour", optional_argument, NULL, 0}, 399 9664 jason { "file-type", no_argument, NULL, 0 }, 400 9664 jason { "time-style", required_argument, NULL, 0 }, 401 9664 jason 402 9664 jason {0, 0, 0, 0} 403 9664 jason }; 404 0 stevel 405 0 stevel int 406 0 stevel main(int argc, char *argv[]) 407 0 stevel { 408 0 stevel int c; 409 0 stevel int i; 410 0 stevel int width; 411 0 stevel int amino = 0; 412 0 stevel int opterr = 0; 413 9664 jason int option_index = 0; 414 0 stevel struct lbuf *ep; 415 0 stevel struct lbuf lb; 416 0 stevel struct ditem *myinfo; 417 0 stevel 418 0 stevel (void) setlocale(LC_ALL, ""); 419 0 stevel #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 420 0 stevel #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 421 0 stevel #endif 422 0 stevel (void) textdomain(TEXT_DOMAIN); 423 0 stevel #ifdef STANDALONE 424 0 stevel if (argv[0][0] == '\0') 425 0 stevel argc = getargv("ls", &argv, 0); 426 0 stevel #endif 427 0 stevel 428 0 stevel lb.lmtime.tv_sec = time(NULL); 429 0 stevel lb.lmtime.tv_nsec = 0; 430 0 stevel year = lb.lmtime.tv_sec - 6L*30L*24L*60L*60L; /* 6 months ago */ 431 0 stevel now = lb.lmtime.tv_sec + 60; 432 0 stevel if (isatty(1)) { 433 0 stevel Cflg = 1; 434 0 stevel mflg = 0; 435 0 stevel } 436 0 stevel 437 9664 jason while ((c = getopt_long(argc, argv, 438 9664 jason "+aAbBcCdeEfFghHiklLmnopqrRsStuUw:x1@vV/:%:", long_options, 439 9664 jason &option_index)) != -1) 440 0 stevel switch (c) { 441 9664 jason case 0: 442 9664 jason /* non-short options */ 443 9664 jason if (strcmp(long_options[option_index].name, 444 9664 jason "color") == 0 || 445 9664 jason strcmp(long_options[option_index].name, 446 9664 jason "colour") == 0) { 447 9664 jason if (optarg == NULL || 448 9664 jason strcmp(optarg, "always") == 0 || 449 9664 jason strcmp(optarg, "yes") == 0 || 450 9664 jason strcmp(optarg, "force") == 0) { 451 9664 jason colorflg++; 452 9664 jason statreq++; 453 9664 jason continue; 454 9664 jason } 455 9664 jason 456 10456 jason if (strcmp(optarg, "auto") == 0 || 457 9664 jason strcmp(optarg, "tty") == 0 || 458 10456 jason strcmp(optarg, "if-tty") == 0) { 459 10456 jason if (isatty(1) == 1) { 460 10456 jason colorflg++; 461 10456 jason statreq++; 462 10456 jason } 463 9664 jason continue; 464 9664 jason } 465 9664 jason 466 9664 jason if (strcmp(optarg, "never") == 0 || 467 9664 jason strcmp(optarg, "no") == 0 || 468 9664 jason strcmp(optarg, "none") == 0) { 469 9664 jason colorflg = 0; 470 9664 jason continue; 471 9664 jason } 472 9664 jason (void) fprintf(stderr, 473 9664 jason gettext("Invalid argument '%s' for " 474 9664 jason "--color\n"), optarg); 475 9664 jason ++opterr; 476 9664 jason continue; 477 9664 jason } 478 9664 jason 479 9664 jason if (strcmp(long_options[option_index].name, 480 9664 jason "si") == 0) { 481 9664 jason hflg++; 482 9664 jason hscale = 1000; 483 9664 jason continue; 484 9664 jason } 485 9664 jason 486 9664 jason if (strcmp(long_options[option_index].name, 487 9664 jason "block-size") == 0) { 488 9664 jason size_t scale_len = strlen(optarg); 489 9664 jason uint64_t scale = 1; 490 9664 jason uint64_t kilo = 1024; 491 9664 jason char scale_c; 492 9664 jason 493 9664 jason if (scale_len == 0) { 494 9664 jason (void) fprintf(stderr, gettext( 495 9664 jason "Invalid block size \'%s\'\n"), 496 9664 jason optarg); 497 9664 jason exit(1); 498 9664 jason } 499 9664 jason 500 9664 jason scale_c = optarg[scale_len - 1]; 501 9664 jason if (scale_c == 'B') { 502 9664 jason /* need at least digit, scale, B */ 503 9664 jason if (scale_len < 3) { 504 9664 jason (void) fprintf(stderr, gettext( 505 9664 jason "Invalid block size " 506 9664 jason "\'%s\'\n"), optarg); 507 9664 jason exit(1); 508 9664 jason } 509 9664 jason kilo = 1000; 510 9664 jason scale_c = optarg[scale_len - 2]; 511 9664 jason if (isdigit(scale_c)) { 512 9664 jason (void) fprintf(stderr, 513 9664 jason gettext("Invalid block size" 514 9664 jason " \'%s\'\n"), optarg); 515 9664 jason exit(1); 516 9664 jason } 517 9664 jason /* 518 9664 jason * make optarg[scale_len - 1] point to 519 9664 jason * the scale factor 520 9664 jason */ 521 9664 jason --scale_len; 522 9664 jason } 523 9664 jason 524 9664 jason switch (scale_c) { 525 9664 jason case 'y': 526 9664 jason case 'Y': 527 9664 jason scale *= kilo; 528 9664 jason /*FALLTHROUGH*/ 529 9664 jason case 'Z': 530 9664 jason case 'z': 531 9664 jason scale *= kilo; 532 9664 jason /*FALLTHROUGH*/ 533 9664 jason case 'E': 534 9664 jason case 'e': 535 9664 jason scale *= kilo; 536 9664 jason /*FALLTHROUGH*/ 537 9664 jason case 'P': 538 9664 jason case 'p': 539 9664 jason scale *= kilo; 540 9664 jason /*FALLTHROUGH*/ 541 9664 jason case 'T': 542 9664 jason case 't': 543 9664 jason scale *= kilo; 544 9664 jason /*FALLTHROUGH*/ 545 9664 jason case 'G': 546 9664 jason case 'g': 547 9664 jason scale *= kilo; 548 9664 jason /*FALLTHROUGH*/ 549 9664 jason case 'M': 550 9664 jason case 'm': 551 9664 jason scale *= kilo; 552 9664 jason /*FALLTHROUGH*/ 553 9664 jason case 'K': 554 9664 jason case 'k': 555 9664 jason scale *= kilo; 556 9664 jason break; 557 9664 jason default: 558 9664 jason if (!isdigit(scale_c)) { 559 9664 jason (void) fprintf(stderr, 560 9664 jason gettext("Invalid character " 561 9664 jason "following block size in " 562 9664 jason "\'%s\'\n"), optarg); 563 9664 jason exit(1); 564 9664 jason } 565 9664 jason } 566 9664 jason 567 9664 jason /* NULL out scale constant if present */ 568 9664 jason if (scale > 1 && !isdigit(scale_c)) 569 9664 jason optarg[scale_len - 1] = '\0'; 570 9664 jason 571 9664 jason /* Based on testing, this is what GNU ls does */ 572 9664 jason block_size = strtoll(optarg, NULL, 0) * scale; 573 9664 jason if (block_size < 1) { 574 9664 jason (void) fprintf(stderr, 575 9664 jason gettext("Invalid block size " 576 9664 jason "\'%s\'\n"), optarg); 577 9664 jason exit(1); 578 9664 jason } 579 9664 jason continue; 580 9664 jason } 581 9664 jason 582 9664 jason if (strcmp(long_options[option_index].name, 583 9664 jason "file-type") == 0) { 584 9664 jason file_typeflg++; 585 9664 jason Fflg++; 586 9664 jason statreq++; 587 9664 jason continue; 588 9664 jason } 589 9664 jason 590 9664 jason 591 9664 jason if (strcmp(long_options[option_index].name, 592 9664 jason "full-time") == 0) { 593 9664 jason Eflg++; 594 9664 jason statreq++; 595 9664 jason eflg = 0; 596 9664 jason time_fmt_old = FORMAT_ISO_FULL; 597 9664 jason time_fmt_new = FORMAT_ISO_FULL; 598 9664 jason continue; 599 9664 jason } 600 9664 jason 601 9664 jason if (strcmp(long_options[option_index].name, 602 9664 jason "time-style") == 0) { 603 9664 jason /* like -E, but doesn't imply -l */ 604 9664 jason if (strcmp(optarg, "full-iso") == 0) { 605 9664 jason Eflg++; 606 9664 jason statreq++; 607 9664 jason eflg = 0; 608 9664 jason time_fmt_old = FORMAT_ISO_FULL; 609 9664 jason time_fmt_new = FORMAT_ISO_FULL; 610 9664 jason continue; 611 9664 jason } 612 9664 jason if (strcmp(optarg, "long-iso") == 0) { 613 9664 jason statreq++; 614 9664 jason Eflg = 0; 615 9664 jason eflg = 0; 616 9664 jason time_fmt_old = FORMAT_ISO_LONG; 617 9664 jason time_fmt_new = FORMAT_ISO_LONG; 618 9664 jason continue; 619 9664 jason } 620 9664 jason if (strcmp(optarg, "iso") == 0) { 621 9664 jason statreq++; 622 9664 jason Eflg = 0; 623 9664 jason eflg = 0; 624 9664 jason time_fmt_old = FORMAT_ISO_OLD; 625 9664 jason time_fmt_new = FORMAT_ISO_NEW; 626 9664 jason continue; 627 9664 jason } 628 9664 jason /* should be the default */ 629 9664 jason if (strcmp(optarg, "locale") == 0) { 630 9664 jason time_fmt_old = FORMAT_OLD; 631 9664 jason time_fmt_new = FORMAT_NEW; 632 9664 jason continue; 633 9664 jason } 634 9664 jason if (optarg[0] == '+') { 635 9664 jason char *told, *tnew; 636 9664 jason char *p; 637 9664 jason size_t timelen = strlen(optarg); 638 9664 jason 639 9664 jason p = strchr(optarg, '\n'); 640 9664 jason if (p != NULL) 641 9664 jason *p++ = '\0'; 642 9664 jason 643 9664 jason /* 644 9664 jason * Time format requires a leading and 645 9664 jason * trailing space 646 9664 jason * Add room for 3 spaces + 2 nulls 647 9664 jason * The + in optarg is replaced with 648 9664 jason * a space. 649 9664 jason */ 650 9664 jason timelen += 2 + 3; 651 9664 jason told = malloc(timelen); 652 9664 jason if (told == NULL) { 653 9664 jason perror("Out of memory"); 654 9664 jason exit(1); 655 9664 jason } 656 9664 jason 657 9664 jason (void) memset(told, 0, timelen); 658 9664 jason told[0] = ' '; 659 9664 jason (void) strlcat(told, &optarg[1], 660 9664 jason timelen); 661 9664 jason (void) strlcat(told, " ", timelen); 662 9664 jason 663 9664 jason if (p != NULL) { 664 9664 jason size_t tnew_len; 665 9664 jason 666 9664 jason tnew = told + strlen(told) + 1; 667 9664 jason tnew_len = timelen - 668 9664 jason strlen(told) - 1; 669 9664 jason 670 9664 jason tnew[0] = ' '; 671 9664 jason (void) strlcat(tnew, p, 672 9664 jason tnew_len); 673 9664 jason (void) strlcat(tnew, " ", 674 9664 jason tnew_len); 675 9664 jason time_fmt_new = 676 9664 jason (const char *)tnew; 677 9664 jason } else { 678 9664 jason time_fmt_new = 679 9664 jason (const char *)told; 680 9664 jason } 681 9664 jason 682 9664 jason time_fmt_old = (const char *)told; 683 9664 jason time_custom = 1; 684 9664 jason continue; 685 9664 jason } 686 9664 jason continue; 687 9664 jason } 688 9664 jason 689 9664 jason continue; 690 9664 jason 691 0 stevel case 'a': 692 0 stevel aflg++; 693 0 stevel continue; 694 0 stevel case 'A': 695 0 stevel Aflg++; 696 0 stevel continue; 697 0 stevel case 'b': 698 0 stevel bflg = 1; 699 0 stevel qflg = 0; 700 9664 jason continue; 701 9664 jason case 'B': 702 9664 jason Bflg = 1; 703 0 stevel continue; 704 0 stevel case 'c': 705 0 stevel uflg = 0; 706 5331 amw atm = 0; 707 5331 amw ctm = 0; 708 5331 amw mtm = 0; 709 5331 amw crtm = 0; 710 0 stevel cflg++; 711 0 stevel continue; 712 0 stevel case 'C': 713 0 stevel Cflg = 1; 714 0 stevel mflg = 0; 715 0 stevel #ifdef XPG4 716 0 stevel lflg = 0; 717 0 stevel #endif 718 0 stevel continue; 719 0 stevel case 'd': 720 0 stevel dflg++; 721 0 stevel continue; 722 0 stevel case 'e': 723 0 stevel eflg++; 724 0 stevel lflg++; 725 0 stevel statreq++; 726 0 stevel Eflg = 0; 727 9664 jason time_fmt_old = FORMAT_LONG; 728 9664 jason time_fmt_new = FORMAT_LONG; 729 0 stevel continue; 730 0 stevel case 'E': 731 0 stevel Eflg++; 732 0 stevel lflg++; 733 0 stevel statreq++; 734 0 stevel eflg = 0; 735 9664 jason time_fmt_old = FORMAT_ISO_FULL; 736 9664 jason time_fmt_new = FORMAT_ISO_FULL; 737 0 stevel continue; 738 0 stevel case 'f': 739 0 stevel fflg++; 740 0 stevel continue; 741 0 stevel case 'F': 742 0 stevel Fflg++; 743 0 stevel statreq++; 744 0 stevel continue; 745 0 stevel case 'g': 746 0 stevel gflg++; 747 0 stevel lflg++; 748 0 stevel statreq++; 749 0 stevel continue; 750 0 stevel case 'h': 751 0 stevel hflg++; 752 0 stevel hscale = 1024; 753 0 stevel continue; 754 0 stevel case 'H': 755 0 stevel Hflg++; 756 0 stevel /* -H and -L are mutually exclusive */ 757 0 stevel Lflg = 0; 758 0 stevel continue; 759 0 stevel case 'i': 760 0 stevel iflg++; 761 9664 jason continue; 762 9664 jason case 'k': 763 9664 jason block_size = 1024; 764 0 stevel continue; 765 0 stevel case 'l': 766 0 stevel lflg++; 767 0 stevel statreq++; 768 0 stevel Cflg = 0; 769 0 stevel xflg = 0; 770 0 stevel mflg = 0; 771 0 stevel atflg = 0; 772 0 stevel continue; 773 0 stevel case 'L': 774 0 stevel Lflg++; 775 0 stevel /* -H and -L are mutually exclusive */ 776 0 stevel Hflg = 0; 777 0 stevel continue; 778 0 stevel case 'm': 779 0 stevel Cflg = 0; 780 0 stevel mflg = 1; 781 0 stevel #ifdef XPG4 782 0 stevel lflg = 0; 783 0 stevel #endif 784 0 stevel continue; 785 0 stevel case 'n': 786 0 stevel nflg++; 787 0 stevel lflg++; 788 0 stevel statreq++; 789 0 stevel Cflg = 0; 790 0 stevel xflg = 0; 791 0 stevel mflg = 0; 792 0 stevel atflg = 0; 793 0 stevel continue; 794 0 stevel case 'o': 795 0 stevel oflg++; 796 0 stevel lflg++; 797 0 stevel statreq++; 798 0 stevel continue; 799 0 stevel case 'p': 800 0 stevel pflg++; 801 0 stevel statreq++; 802 0 stevel continue; 803 0 stevel case 'q': 804 0 stevel qflg = 1; 805 0 stevel bflg = 0; 806 0 stevel continue; 807 0 stevel case 'r': 808 0 stevel rflg = -1; 809 0 stevel continue; 810 0 stevel case 'R': 811 0 stevel Rflg++; 812 0 stevel statreq++; 813 0 stevel continue; 814 0 stevel case 's': 815 0 stevel sflg++; 816 0 stevel statreq++; 817 0 stevel continue; 818 0 stevel case 'S': 819 0 stevel tflg = 0; 820 9664 jason Uflg = 0; 821 0 stevel Sflg++; 822 0 stevel statreq++; 823 0 stevel continue; 824 0 stevel case 't': 825 0 stevel Sflg = 0; 826 9664 jason Uflg = 0; 827 0 stevel tflg++; 828 0 stevel statreq++; 829 9664 jason continue; 830 9664 jason case 'U': 831 9664 jason Sflg = 0; 832 9664 jason tflg = 0; 833 9664 jason Uflg++; 834 0 stevel continue; 835 0 stevel case 'u': 836 0 stevel cflg = 0; 837 5331 amw atm = 0; 838 5331 amw ctm = 0; 839 5331 amw mtm = 0; 840 5331 amw crtm = 0; 841 0 stevel uflg++; 842 0 stevel continue; 843 1420 marks case 'V': 844 1420 marks Vflg++; 845 1420 marks /*FALLTHROUGH*/ 846 789 ahrens case 'v': 847 789 ahrens vflg++; 848 789 ahrens #if !defined(XPG4) 849 789 ahrens if (lflg) 850 789 ahrens continue; 851 789 ahrens #endif 852 789 ahrens lflg++; 853 789 ahrens statreq++; 854 789 ahrens Cflg = 0; 855 789 ahrens xflg = 0; 856 789 ahrens mflg = 0; 857 9664 jason continue; 858 9664 jason case 'w': 859 9664 jason wflg++; 860 9664 jason num_cols = atoi(optarg); 861 789 ahrens continue; 862 0 stevel case 'x': 863 0 stevel xflg = 1; 864 0 stevel Cflg = 1; 865 0 stevel mflg = 0; 866 0 stevel #ifdef XPG4 867 0 stevel lflg = 0; 868 0 stevel #endif 869 0 stevel continue; 870 0 stevel case '1': 871 0 stevel Cflg = 0; 872 0 stevel continue; 873 0 stevel case '@': 874 0 stevel #if !defined(XPG4) 875 0 stevel /* 876 0 stevel * -l has precedence over -@ 877 0 stevel */ 878 0 stevel if (lflg) 879 0 stevel continue; 880 0 stevel #endif 881 0 stevel atflg++; 882 0 stevel lflg++; 883 0 stevel statreq++; 884 0 stevel Cflg = 0; 885 0 stevel xflg = 0; 886 0 stevel mflg = 0; 887 0 stevel continue; 888 5331 amw case '/': 889 5331 amw saflg++; 890 5331 amw if (optarg != NULL) { 891 5331 amw if (strcmp(optarg, "c") == 0) { 892 5331 amw copt++; 893 5331 amw vopt = 0; 894 5331 amw } else if (strcmp(optarg, "v") == 0) { 895 5331 amw vopt++; 896 5331 amw copt = 0; 897 5331 amw } else 898 5331 amw opterr++; 899 5331 amw } else 900 5331 amw opterr++; 901 5331 amw lflg++; 902 5331 amw statreq++; 903 5331 amw Cflg = 0; 904 5331 amw xflg = 0; 905 5331 amw mflg = 0; 906 5331 amw continue; 907 5331 amw case '%': 908 5331 amw tmflg++; 909 5331 amw if (optarg != NULL) { 910 5331 amw if (strcmp(optarg, "ctime") == 0) { 911 5331 amw ctm++; 912 5331 amw atm = 0; 913 5331 amw mtm = 0; 914 5331 amw crtm = 0; 915 5331 amw } else if (strcmp(optarg, "atime") == 0) { 916 5331 amw atm++; 917 5331 amw ctm = 0; 918 5331 amw mtm = 0; 919 5331 amw crtm = 0; 920 5331 amw uflg = 0; 921 5331 amw cflg = 0; 922 5331 amw } else if (strcmp(optarg, "mtime") == 0) { 923 5331 amw mtm++; 924 5331 amw atm = 0; 925 5331 amw ctm = 0; 926 5331 amw crtm = 0; 927 5331 amw uflg = 0; 928 5331 amw cflg = 0; 929 5331 amw } else if (strcmp(optarg, "crtime") == 0) { 930 5331 amw crtm++; 931 5331 amw atm = 0; 932 5331 amw ctm = 0; 933 5331 amw mtm = 0; 934 5331 amw uflg = 0; 935 5331 amw cflg = 0; 936 5331 amw } else if (strcmp(optarg, "all") == 0) { 937 5331 amw alltm++; 938 5331 amw atm = 0; 939 5331 amw ctm = 0; 940 5331 amw mtm = 0; 941 5331 amw crtm = 0; 942 5331 amw } else 943 5331 amw opterr++; 944 5331 amw } else 945 5331 amw opterr++; 946 5331 amw 947 5331 amw Sflg = 0; 948 5331 amw statreq++; 949 5331 amw mflg = 0; 950 5331 amw continue; 951 0 stevel case '?': 952 0 stevel opterr++; 953 0 stevel continue; 954 0 stevel } 955 9664 jason 956 0 stevel if (opterr) { 957 0 stevel (void) fprintf(stderr, gettext( 958 9664 jason "usage: ls -aAbBcCdeEfFghHiklLmnopqrRsStuUwxvV1@/%[c | v]" 959 5331 amw "%%[atime | crtime | ctime | mtime | all]" 960 5331 amw " [files]\n")); 961 0 stevel exit(2); 962 0 stevel } 963 0 stevel 964 0 stevel if (fflg) { 965 0 stevel aflg++; 966 0 stevel lflg = 0; 967 0 stevel sflg = 0; 968 0 stevel tflg = 0; 969 0 stevel Sflg = 0; 970 0 stevel statreq = 0; 971 0 stevel } 972 0 stevel 973 0 stevel fixedwidth = 2; 974 0 stevel if (pflg || Fflg) 975 0 stevel fixedwidth++; 976 0 stevel if (iflg) 977 0 stevel fixedwidth += 11; 978 0 stevel if (sflg) 979 0 stevel fixedwidth += 5; 980 0 stevel 981 0 stevel if (lflg) { 982 0 stevel if (!gflg && !oflg) 983 0 stevel gflg = oflg = 1; 984 0 stevel else 985 0 stevel if (gflg && oflg) 986 0 stevel gflg = oflg = 0; 987 0 stevel Cflg = mflg = 0; 988 0 stevel } 989 0 stevel 990 9664 jason if (!wflg && (Cflg || mflg)) { 991 0 stevel char *clptr; 992 0 stevel if ((clptr = getenv("COLUMNS")) != NULL) 993 0 stevel num_cols = atoi(clptr); 994 0 stevel #ifdef TERMINFO 995 0 stevel else { 996 0 stevel if (ioctl(1, TIOCGWINSZ, &win) != -1) 997 0 stevel num_cols = (win.ws_col == 0 ? 80 : win.ws_col); 998 0 stevel } 999 0 stevel #endif 1000 0 stevel } 1001 9664 jason 1002 9664 jason if (num_cols < 20 || num_cols > 1000) 1003 9664 jason /* assume it is an error */ 1004 9664 jason num_cols = 80; 1005 0 stevel 1006 0 stevel /* allocate space for flist and the associated */ 1007 0 stevel /* data structures (lbufs) */ 1008 0 stevel maxfils = quantn; 1009 0 stevel if (((flist = malloc(maxfils * sizeof (struct lbuf *))) == NULL) || 1010 0 stevel ((nxtlbf = malloc(quantn * sizeof (struct lbuf))) == NULL)) { 1011 0 stevel perror("ls"); 1012 0 stevel exit(2); 1013 0 stevel } 1014 0 stevel if ((amino = (argc-optind)) == 0) { 1015 0 stevel /* 1016 0 stevel * case when no names are given 1017 0 stevel * in ls-command and current 1018 0 stevel * directory is to be used 1019 0 stevel */ 1020 0 stevel argv[optind] = dotp; 1021 0 stevel } 1022 0 stevel 1023 0 stevel for (i = 0; i < (amino ? amino : 1); i++) { 1024 0 stevel 1025 0 stevel /* 1026 0 stevel * If we are recursing, we need to make sure we don't 1027 0 stevel * get into an endless loop. To keep track of the inodes 1028 0 stevel * (actually, just the directories) visited, we 1029 0 stevel * maintain a directory ancestry list for a file 1030 0 stevel * hierarchy. As we go deeper into the hierarchy, 1031 0 stevel * a parent directory passes its directory list 1032 0 stevel * info (device id, inode number, and a pointer to 1033 0 stevel * its parent) to each of its children. As we 1034 0 stevel * process a child that is a directory, we save 1035 0 stevel * its own personal directory list info. We then 1036 0 stevel * check to see if the child has already been 1037 0 stevel * processed by comparing its device id and inode 1038 0 stevel * number from its own personal directory list info 1039 0 stevel * to that of each of its ancestors. If there is a 1040 0 stevel * match, then we know we've detected a cycle. 1041 0 stevel */ 1042 0 stevel if (Rflg) { 1043 0 stevel /* 1044 0 stevel * This is the first parent in this lineage 1045 0 stevel * (first in a directory hierarchy), so 1046 0 stevel * this parent's parent doesn't exist. We 1047 0 stevel * only initialize myinfo when we are 1048 0 stevel * recursing, otherwise it's not used. 1049 0 stevel */ 1050 0 stevel if ((myinfo = (struct ditem *)malloc( 1051 0 stevel sizeof (struct ditem))) == NULL) { 1052 0 stevel perror("ls"); 1053 0 stevel exit(2); 1054 0 stevel } else { 1055 0 stevel myinfo->dev = 0; 1056 0 stevel myinfo->ino = 0; 1057 0 stevel myinfo->parent = NULL; 1058 0 stevel } 1059 0 stevel } 1060 0 stevel 1061 0 stevel if (Cflg || mflg) { 1062 0 stevel width = strcol((unsigned char *)argv[optind]); 1063 0 stevel if (width > filewidth) 1064 0 stevel filewidth = width; 1065 0 stevel } 1066 0 stevel if ((ep = gstat((*argv[optind] ? argv[optind] : dotp), 1067 0 stevel 1, myinfo)) == NULL) { 1068 0 stevel if (nomocore) 1069 0 stevel exit(2); 1070 0 stevel err = 2; 1071 0 stevel optind++; 1072 0 stevel continue; 1073 0 stevel } 1074 0 stevel ep->ln.namep = (*argv[optind] ? argv[optind] : dotp); 1075 0 stevel ep->lflags |= ISARG; 1076 0 stevel optind++; 1077 0 stevel nargs++; /* count good arguments stored in flist */ 1078 6866 basabi if (acl_err) 1079 6866 basabi err = 2; 1080 0 stevel } 1081 0 stevel colwidth = fixedwidth + filewidth; 1082 9664 jason if (!Uflg) 1083 9664 jason qsort(flist, (unsigned)nargs, sizeof (struct lbuf *), 1084 9664 jason (int (*)(const void *, const void *))compar); 1085 0 stevel for (i = 0; i < nargs; i++) { 1086 0 stevel if (flist[i]->ltype == 'd' && dflg == 0 || fflg) 1087 0 stevel break; 1088 0 stevel } 1089 9664 jason 1090 9664 jason if (colorflg) 1091 9664 jason ls_color_init(); 1092 9664 jason 1093 0 stevel pem(&flist[0], &flist[i], 0); 1094 0 stevel for (; i < nargs; i++) { 1095 0 stevel pdirectory(flist[i]->ln.namep, Rflg || 1096 0 stevel (amino > 1), nargs, 0, flist[i]->ancinfo); 1097 0 stevel if (nomocore) 1098 0 stevel exit(2); 1099 0 stevel /* -R: print subdirectories found */ 1100 0 stevel while (dfirst || cdfirst) { 1101 0 stevel /* Place direct subdirs on front in right order */ 1102 0 stevel while (cdfirst) { 1103 0 stevel /* reverse cdfirst onto front of dfirst */ 1104 0 stevel dtemp = cdfirst; 1105 0 stevel cdfirst = cdfirst -> dc_next; 1106 0 stevel dtemp -> dc_next = dfirst; 1107 0 stevel dfirst = dtemp; 1108 0 stevel } 1109 0 stevel /* take off first dir on dfirst & print it */ 1110 0 stevel dtemp = dfirst; 1111 0 stevel dfirst = dfirst->dc_next; 1112 0 stevel pdirectory(dtemp->dc_name, 1, nargs, 1113 0 stevel dtemp->cycle_detected, dtemp->myancinfo); 1114 0 stevel if (nomocore) 1115 0 stevel exit(2); 1116 0 stevel free(dtemp->dc_name); 1117 0 stevel free(dtemp); 1118 0 stevel } 1119 0 stevel } 1120 9664 jason 1121 0 stevel return (err); 1122 0 stevel } 1123 0 stevel 1124 0 stevel /* 1125 0 stevel * pdirectory: print the directory name, labelling it if title is 1126 0 stevel * nonzero, using lp as the place to start reading in the dir. 1127 0 stevel */ 1128 0 stevel static void 1129 0 stevel pdirectory(char *name, int title, int lp, int cdetect, struct ditem *myinfo) 1130 0 stevel { 1131 0 stevel struct dchain *dp; 1132 0 stevel struct lbuf *ap; 1133 0 stevel char *pname; 1134 0 stevel int j; 1135 0 stevel 1136 0 stevel filewidth = 0; 1137 0 stevel curdir = name; 1138 0 stevel if (title) { 1139 0 stevel if (!first) 1140 0 stevel (void) putc('\n', stdout); 1141 0 stevel pprintf(name, ":"); 1142 0 stevel new_line(); 1143 0 stevel } 1144 0 stevel /* 1145 0 stevel * If there was a cycle detected, then notify and don't report 1146 0 stevel * further. 1147 0 stevel */ 1148 0 stevel if (cdetect) { 1149 0 stevel if (lflg || sflg) { 1150 0 stevel curcol += printf(gettext("total %d"), 0); 1151 0 stevel new_line(); 1152 0 stevel } 1153 0 stevel (void) fprintf(stderr, gettext( 1154 0 stevel "ls: cycle detected for %s\n"), name); 1155 0 stevel return; 1156 0 stevel } 1157 0 stevel 1158 0 stevel nfiles = lp; 1159 0 stevel rddir(name, myinfo); 1160 0 stevel if (nomocore) 1161 0 stevel return; 1162 9664 jason if (fflg == 0 && Uflg == 0) 1163 0 stevel qsort(&flist[lp], (unsigned)(nfiles - lp), 1164 0 stevel sizeof (struct lbuf *), 1165 0 stevel (int (*)(const void *, const void *))compar); 1166 0 stevel if (Rflg) { 1167 0 stevel for (j = nfiles - 1; j >= lp; j--) { 1168 0 stevel ap = flist[j]; 1169 0 stevel if (ap->ltype == 'd' && strcmp(ap->ln.lname, ".") && 1170 0 stevel strcmp(ap->ln.lname, "..")) { 1171 0 stevel dp = malloc(sizeof (struct dchain)); 1172 0 stevel if (dp == NULL) { 1173 0 stevel perror("ls"); 1174 0 stevel exit(2); 1175 0 stevel } 1176 0 stevel pname = makename(curdir, ap->ln.lname); 1177 0 stevel if ((dp->dc_name = strdup(pname)) == NULL) { 1178 0 stevel perror("ls"); 1179 0 stevel exit(2); 1180 0 stevel } 1181 0 stevel dp->cycle_detected = ap->cycle; 1182 0 stevel dp->myancinfo = ap->ancinfo; 1183 0 stevel dp->dc_next = dfirst; 1184 0 stevel dfirst = dp; 1185 0 stevel } 1186 0 stevel } 1187 0 stevel } 1188 0 stevel if (lflg || sflg) { 1189 0 stevel curcol += printf(gettext("total %llu"), tblocks); 1190 0 stevel new_line(); 1191 0 stevel } 1192 0 stevel pem(&flist[lp], &flist[nfiles], lflg||sflg); 1193 0 stevel } 1194 0 stevel 1195 0 stevel /* 1196 0 stevel * pem: print 'em. Print a list of files (e.g. a directory) bounded 1197 0 stevel * by slp and lp. 1198 0 stevel */ 1199 0 stevel static void 1200 0 stevel pem(struct lbuf **slp, struct lbuf **lp, int tot_flag) 1201 0 stevel { 1202 0 stevel long row, nrows, i; 1203 0 stevel int col, ncols; 1204 0 stevel struct lbuf **ep; 1205 0 stevel 1206 0 stevel if (Cflg || mflg) { 1207 0 stevel if (colwidth > num_cols) { 1208 0 stevel ncols = 1; 1209 0 stevel } else { 1210 0 stevel ncols = num_cols / colwidth; 1211 0 stevel } 1212 0 stevel } 1213 0 stevel 1214 0 stevel if (ncols == 1 || mflg || xflg || !Cflg) { 1215 0 stevel for (ep = slp; ep < lp; ep++) 1216 0 stevel pentry(*ep); 1217 0 stevel new_line(); 1218 0 stevel return; 1219 0 stevel } 1220 0 stevel /* otherwise print -C columns */ 1221 0 stevel if (tot_flag) { 1222 0 stevel slp--; 1223 0 stevel row = 1; 1224 0 stevel } 1225 0 stevel else 1226 0 stevel row = 0; 1227 0 stevel 1228 0 stevel nrows = (lp - slp - 1) / ncols + 1; 1229 0 stevel for (i = 0; i < nrows; i++, row++) { 1230 0 stevel for (col = 0; col < ncols; col++) { 1231 0 stevel ep = slp + (nrows * col) + row; 1232 0 stevel if (ep < lp) 1233 0 stevel pentry(*ep); 1234 0 stevel } 1235 0 stevel new_line(); 1236 0 stevel } 1237 0 stevel } 1238 0 stevel 1239 0 stevel /* 1240 0 stevel * print one output entry; 1241 0 stevel * if uid/gid is not found in the appropriate 1242 0 stevel * file(passwd/group), then print uid/gid instead of 1243 0 stevel * user/group name; 1244 0 stevel */ 1245 0 stevel static void 1246 0 stevel pentry(struct lbuf *ap) 1247 0 stevel { 1248 0 stevel struct lbuf *p; 1249 0 stevel numbuf_t hbuf; 1250 0 stevel char *dmark = ""; /* Used if -p or -F option active */ 1251 0 stevel char *cp; 1252 10059 jason char *str; 1253 0 stevel 1254 0 stevel p = ap; 1255 0 stevel column(); 1256 0 stevel if (iflg) 1257 0 stevel if (mflg && !lflg) 1258 0 stevel curcol += printf("%llu ", (long long)p->lnum); 1259 0 stevel else 1260 0 stevel curcol += printf("%10llu ", (long long)p->lnum); 1261 0 stevel if (sflg) 1262 0 stevel curcol += printf((mflg && !lflg) ? "%lld " : 1263 5331 amw (p->lblocks < 10000) ? "%4lld " : "%lld ", 1264 5331 amw (p->ltype != 'b' && p->ltype != 'c') ? 1265 5331 amw p->lblocks : 0LL); 1266 0 stevel if (lflg) { 1267 0 stevel (void) putchar(p->ltype); 1268 0 stevel curcol++; 1269 0 stevel pmode(p->lflags); 1270 0 stevel 1271 0 stevel /* ACL: additional access mode flag */ 1272 0 stevel (void) putchar(p->acl); 1273 0 stevel curcol++; 1274 0 stevel 1275 0 stevel curcol += printf("%3lu ", (ulong_t)p->lnl); 1276 0 stevel if (oflg) 1277 0 stevel if (!nflg) { 1278 0 stevel cp = getname(p->luid); 1279 0 stevel curcol += printf("%-8s ", cp); 1280 0 stevel } else 1281 0 stevel curcol += printf("%-8lu ", (ulong_t)p->luid); 1282 0 stevel if (gflg) 1283 0 stevel if (!nflg) { 1284 0 stevel cp = getgroup(p->lgid); 1285 0 stevel curcol += printf("%-8s ", cp); 1286 0 stevel } else 1287 0 stevel curcol += printf("%-8lu ", (ulong_t)p->lgid); 1288 0 stevel if (p->ltype == 'b' || p->ltype == 'c') { 1289 0 stevel curcol += printf("%3u, %2u", 1290 0 stevel (uint_t)major((dev_t)p->lsize), 1291 0 stevel (uint_t)minor((dev_t)p->lsize)); 1292 0 stevel } else if (hflg && (p->lsize >= hscale)) { 1293 0 stevel curcol += printf("%7s", 1294 0 stevel number_to_scaled_string(hbuf, p->lsize, hscale)); 1295 0 stevel } else { 1296 9664 jason uint64_t bsize = p->lsize / block_size; 1297 9664 jason 1298 9664 jason /* 1299 9664 jason * Round up only when using blocks > 1 byte, otherwise 1300 9664 jason * 'normal' sizes display 1 byte too large. 1301 9664 jason */ 1302 9664 jason if (p->lsize % block_size != 0) 1303 9664 jason bsize++; 1304 9664 jason 1305 9664 jason curcol += printf("%7" PRIu64, bsize); 1306 0 stevel } 1307 9664 jason format_time(p->lmtime.tv_sec, p->lmtime.tv_nsec); 1308 5331 amw /* format extended system attribute time */ 1309 5331 amw if (tmflg && crtm) 1310 5331 amw format_attrtime(p); 1311 5331 amw 1312 0 stevel curcol += printf("%s", time_buf); 1313 5331 amw 1314 0 stevel } 1315 0 stevel /* 1316 0 stevel * prevent both "->" and trailing marks 1317 0 stevel * from appearing 1318 0 stevel */ 1319 0 stevel 1320 0 stevel if (pflg && p->ltype == 'd') 1321 0 stevel dmark = "/"; 1322 0 stevel 1323 0 stevel if (Fflg && !(lflg && p->flinkto)) { 1324 0 stevel if (p->ltype == 'd') 1325 0 stevel dmark = "/"; 1326 0 stevel else if (p->ltype == 'D') 1327 0 stevel dmark = ">"; 1328 0 stevel else if (p->ltype == 'p') 1329 0 stevel dmark = "|"; 1330 0 stevel else if (p->ltype == 'l') 1331 0 stevel dmark = "@"; 1332 0 stevel else if (p->ltype == 's') 1333 0 stevel dmark = "="; 1334 9664 jason else if (!file_typeflg && 1335 9664 jason (p->lflags & (S_IXUSR|S_IXGRP|S_IXOTH))) 1336 0 stevel dmark = "*"; 1337 0 stevel else 1338 0 stevel dmark = ""; 1339 0 stevel } 1340 0 stevel 1341 10059 jason if (colorflg) 1342 10059 jason ls_start_color(p->color); 1343 9664 jason 1344 10059 jason if (p->lflags & ISARG) 1345 10059 jason str = p->ln.namep; 1346 10059 jason else 1347 10059 jason str = p->ln.lname; 1348 9664 jason 1349 10059 jason if (qflg || bflg) { 1350 10059 jason csi_pprintf((unsigned char *)str); 1351 10059 jason 1352 10059 jason if (lflg && p->flinkto) { 1353 10059 jason if (colorflg) 1354 10059 jason ls_end_color(); 1355 10059 jason csi_pprintf((unsigned char *)" -> "); 1356 10059 jason if (colorflg) 1357 10059 jason ls_start_color(p->link_color); 1358 10059 jason csi_pprintf((unsigned char *)p->flinkto); 1359 10059 jason } else { 1360 10059 jason csi_pprintf((unsigned char *)dmark); 1361 0 stevel } 1362 0 stevel } else { 1363 10059 jason (void) printf("%s", str); 1364 10059 jason curcol += strcol((unsigned char *)str); 1365 10059 jason 1366 10059 jason if (lflg && p->flinkto) { 1367 10059 jason if (colorflg) 1368 10059 jason ls_end_color(); 1369 10059 jason str = " -> "; 1370 10059 jason (void) printf("%s", str); 1371 10059 jason curcol += strcol((unsigned char *)str); 1372 10059 jason if (colorflg) 1373 10059 jason ls_start_color(p->link_color); 1374 10059 jason (void) printf("%s", p->flinkto); 1375 10059 jason curcol += strcol((unsigned char *)p->flinkto); 1376 10059 jason } else { 1377 10059 jason (void) printf("%s", dmark); 1378 0 stevel curcol += strcol((unsigned char *)dmark); 1379 0 stevel } 1380 0 stevel } 1381 9664 jason 1382 9664 jason if (colorflg) 1383 9664 jason ls_end_color(); 1384 789 ahrens 1385 5331 amw /* Display extended system attributes */ 1386 5331 amw if (saflg) { 1387 5331 amw int i; 1388 5331 amw 1389 5331 amw new_line(); 1390 5331 amw (void) printf(" \t{"); 1391 5331 amw if (p->exttr != NULL) { 1392 5331 amw int k = 0; 1393 5331 amw for (i = 0; i < sacnt; i++) { 1394 5331 amw if (p->exttr[i].name != NULL) 1395 5331 amw k++; 1396 5331 amw } 1397 5331 amw for (i = 0; i < sacnt; i++) { 1398 5331 amw if (p->exttr[i].name != NULL) { 1399 5331 amw (void) printf("%s", p->exttr[i].name); 1400 5331 amw k--; 1401 5331 amw if (vopt && (k != 0)) 1402 5331 amw (void) printf(","); 1403 5331 amw } 1404 5331 amw } 1405 5331 amw } 1406 5331 amw (void) printf("}\n"); 1407 5331 amw } 1408 5331 amw /* Display file timestamps and extended system attribute timestamps */ 1409 5331 amw if (tmflg && alltm) { 1410 5331 amw new_line(); 1411 5331 amw print_time(p); 1412 5331 amw new_line(); 1413 5331 amw } 1414 789 ahrens if (vflg) { 1415 789 ahrens new_line(); 1416 789 ahrens if (p->aclp) { 1417 1420 marks acl_printacl(p->aclp, num_cols, Vflg); 1418 789 ahrens } 1419 789 ahrens } 1420 5331 amw /* Free extended system attribute lists */ 1421 5331 amw if (saflg || tmflg) 1422 5331 amw free_sysattr(p); 1423 0 stevel } 1424 0 stevel 1425 0 stevel /* print various r,w,x permissions */ 1426 0 stevel static void 1427 0 stevel pmode(mode_t aflag) 1428 0 stevel { 1429 0 stevel /* these arrays are declared static to allow initializations */ 1430 0 stevel static int m0[] = { 1, S_IRUSR, 'r', '-' }; 1431 0 stevel static int m1[] = { 1, S_IWUSR, 'w', '-' }; 1432 0 stevel static int m2[] = { 3, S_ISUID|S_IXUSR, 's', S_IXUSR, 1433 0 stevel 'x', S_ISUID, 'S', '-' }; 1434 0 stevel static int m3[] = { 1, S_IRGRP, 'r', '-' }; 1435 0 stevel static int m4[] = { 1, S_IWGRP, 'w', '-' }; 1436 0 stevel static int m5[] = { 4, S_ISGID|S_IXGRP, 's', S_IXGRP, 1437 0 stevel 'x', S_ISGID|LS_NOTREG, 'S', 1438 0 stevel #ifdef XPG4 1439 0 stevel S_ISGID, 'L', '-'}; 1440 0 stevel #else 1441 0 stevel S_ISGID, 'l', '-'}; 1442 0 stevel #endif 1443 0 stevel static int m6[] = { 1, S_IROTH, 'r', '-' }; 1444 0 stevel static int m7[] = { 1, S_IWOTH, 'w', '-' }; 1445 0 stevel static int m8[] = { 3, S_ISVTX|S_IXOTH, 't', S_IXOTH, 1446 0 stevel 'x', S_ISVTX, 'T', '-'}; 1447 0 stevel 1448 0 stevel static int *m[] = { m0, m1, m2, m3, m4, m5, m6, m7, m8}; 1449 0 stevel 1450 0 stevel int **mp; 1451 0 stevel 1452 0 stevel flags = aflag; 1453 0 stevel for (mp = &m[0]; mp < &m[sizeof (m) / sizeof (m[0])]; mp++) 1454 0 stevel selection(*mp); 1455 0 stevel } 1456 0 stevel 1457 0 stevel static void 1458 0 stevel selection(int *pairp) 1459 0 stevel { 1460 0 stevel int n; 1461 0 stevel 1462 0 stevel n = *pairp++; 1463 0 stevel while (n-->0) { 1464 0 stevel if ((flags & *pairp) == *pairp) { 1465 0 stevel pairp++; 1466 0 stevel break; 1467 0 stevel } else { 1468 0 stevel pairp += 2; 1469 0 stevel } 1470 0 stevel } 1471 0 stevel (void) putchar(*pairp); 1472 0 stevel curcol++; 1473 0 stevel } 1474 0 stevel 1475 0 stevel /* 1476 0 stevel * column: get to the beginning of the next column. 1477 0 stevel */ 1478 0 stevel static void 1479 0 stevel column(void) 1480 0 stevel { 1481 0 stevel if (curcol == 0) 1482 0 stevel return; 1483 0 stevel if (mflg) { 1484 0 stevel (void) putc(',', stdout); 1485 0 stevel curcol++; 1486 0 stevel if (curcol + colwidth + 2 > num_cols) { 1487 0 stevel (void) putc('\n', stdout); 1488 0 stevel curcol = 0; 1489 0 stevel return; 1490 0 stevel } 1491 0 stevel (void) putc(' ', stdout); 1492 0 stevel curcol++; 1493 0 stevel return; 1494 0 stevel } 1495 0 stevel if (Cflg == 0) { 1496 0 stevel (void) putc('\n', stdout); 1497 0 stevel curcol = 0; 1498 0 stevel return; 1499 0 stevel } 1500 0 stevel if ((curcol / colwidth + 2) * colwidth > num_cols) { 1501 0 stevel (void) putc('\n', stdout); 1502 0 stevel curcol = 0; 1503 0 stevel return; 1504 0 stevel } 1505 0 stevel do { 1506 0 stevel (void) putc(' ', stdout); 1507 0 stevel curcol++; 1508 0 stevel } while (curcol % colwidth); 1509 0 stevel } 1510 0 stevel 1511 0 stevel static void 1512 0 stevel new_line(void) 1513 0 stevel { 1514 0 stevel if (curcol) { 1515 0 stevel first = 0; 1516 0 stevel (void) putc('\n', stdout); 1517 0 stevel curcol = 0; 1518 0 stevel } 1519 0 stevel } 1520 0 stevel 1521 0 stevel /* 1522 0 stevel * read each filename in directory dir and store its 1523 0 stevel * status in flist[nfiles] 1524 0 stevel * use makename() to form pathname dir/filename; 1525 0 stevel */ 1526 0 stevel static void 1527 0 stevel rddir(char *dir, struct ditem *myinfo) 1528 0 stevel { 1529 0 stevel struct dirent *dentry; 1530 0 stevel DIR *dirf; 1531 0 stevel int j; 1532 0 stevel struct lbuf *ep; 1533 0 stevel int width; 1534 0 stevel 1535 0 stevel if ((dirf = opendir(dir)) == NULL) { 1536 0 stevel (void) fflush(stdout); 1537 0 stevel perror(dir); 1538 0 stevel err = 2; 1539 0 stevel return; 1540 0 stevel } else { 1541 0 stevel tblocks = 0; 1542 0 stevel for (;;) { 1543 0 stevel errno = 0; 1544 0 stevel if ((dentry = readdir(dirf)) == NULL) 1545 0 stevel break; 1546 0 stevel if (aflg == 0 && dentry->d_name[0] == '.' && 1547 0 stevel (Aflg == 0 || 1548 0 stevel dentry->d_name[1] == '\0' || 1549 0 stevel dentry->d_name[1] == '.' && 1550 0 stevel dentry->d_name[2] == '\0')) 1551 0 stevel /* 1552 0 stevel * check for directory items '.', '..', 1553 0 stevel * and items without valid inode-number; 1554 0 stevel */ 1555 0 stevel continue; 1556 0 stevel 1557 9664 jason /* skip entries ending in ~ if -B was given */ 1558 9664 jason if (Bflg && 1559 9664 jason dentry->d_name[strlen(dentry->d_name) - 1] == '~') 1560 9664 jason continue; 1561 0 stevel if (Cflg || mflg) { 1562 0 stevel width = strcol((unsigned char *)dentry->d_name); 1563 0 stevel if (width > filewidth) 1564 0 stevel filewidth = width; 1565 0 stevel } 1566 0 stevel ep = gstat(makename(dir, dentry->d_name), 0, myinfo); 1567 0 stevel if (ep == NULL) { 1568 0 stevel if (nomocore) 1569 5331 amw exit(2); 1570 0 stevel continue; 1571 0 stevel } else { 1572 0 stevel ep->lnum = dentry->d_ino; 1573 0 stevel for (j = 0; dentry->d_name[j] != '\0'; j++) 1574 0 stevel ep->ln.lname[j] = dentry->d_name[j]; 1575 0 stevel ep->ln.lname[j] = '\0'; 1576 0 stevel } 1577 0 stevel } 1578 0 stevel if (errno) { 1579 0 stevel int sav_errno = errno; 1580 0 stevel 1581 0 stevel (void) fprintf(stderr, 1582 0 stevel gettext("ls: error reading directory %s: %s\n"), 1583 0 stevel dir, strerror(sav_errno)); 1584 0 stevel } 1585 0 stevel (void) closedir(dirf); 1586 0 stevel colwidth = fixedwidth + filewidth; 1587 0 stevel } 1588 0 stevel } 1589 0 stevel 1590 0 stevel /* 1591 0 stevel * Attaching a link to an inode's ancestors. Search 1592 0 stevel * through the ancestors to check for cycles (an inode which 1593 0 stevel * we have already tracked in this inodes ancestry). If a cycle 1594 0 stevel * is detected, set the exit code and record the fact so that 1595 0 stevel * it is reported at the right time when printing the directory. 1596 0 stevel * In addition, set the exit code. Note: If the -a flag was 1597 0 stevel * specified, we don't want to check for cycles for directories 1598 0 stevel * ending in '/.' or '/..' unless they were specified on the 1599 0 stevel * command line. 1600 0 stevel */ 1601 0 stevel static void 1602 0 stevel record_ancestry(char *file, struct stat *pstatb, struct lbuf *rep, 1603 0 stevel int argfl, struct ditem *myparent) 1604 0 stevel { 1605 0 stevel size_t file_len; 1606 0 stevel struct ditem *myinfo; 1607 0 stevel struct ditem *tptr; 1608 0 stevel 1609 0 stevel file_len = strlen(file); 1610 0 stevel if (!aflg || argfl || (NOTWORKINGDIR(file, file_len) && 1611 0 stevel NOTPARENTDIR(file, file_len))) { 1612 0 stevel /* 1613 0 stevel * Add this inode's ancestry 1614 0 stevel * info and insert it into the 1615 0 stevel * ancestry list by pointing 1616 0 stevel * back to its parent. We save 1617 0 stevel * it (in rep) with the other info 1618 0 stevel * we're gathering for this inode. 1619 0 stevel */ 1620 0 stevel if ((myinfo = malloc( 1621 0 stevel sizeof (struct ditem))) == NULL) { 1622 0 stevel perror("ls"); 1623 0 stevel exit(2); 1624 0 stevel } 1625 0 stevel myinfo->dev = pstatb->st_dev; 1626 0 stevel myinfo->ino = pstatb->st_ino; 1627 0 stevel myinfo->parent = myparent; 1628 0 stevel rep->ancinfo = myinfo; 1629 0 stevel 1630 0 stevel /* 1631 0 stevel * If this node has the same device id and 1632 0 stevel * inode number of one of its ancestors, 1633 0 stevel * then we've detected a cycle. 1634 0 stevel */ 1635 0 stevel if (myparent != NULL) { 1636 0 stevel for (tptr = myparent; tptr->parent != NULL; 1637 0 stevel tptr = tptr->parent) { 1638 0 stevel if ((tptr->dev == pstatb->st_dev) && 1639 0 stevel (tptr->ino == pstatb->st_ino)) { 1640 0 stevel /* 1641 0 stevel * Cycle detected for this 1642 0 stevel * directory. Record the fact 1643 0 stevel * it is a cycle so we don't 1644 0 stevel * try to process this 1645 0 stevel * directory as we are 1646 0 stevel * walking through the 1647 0 stevel * list of directories. 1648 0 stevel */ 1649 0 stevel rep->cycle = 1; 1650 0 stevel err = 2; 1651 0 stevel break; 1652 0 stevel } 1653 0 stevel } 1654 0 stevel } 1655 0 stevel } 1656 0 stevel } 1657 0 stevel 1658 0 stevel /* 1659 6178 ny155746 * Do re-calculate the mode for group for ACE_T type of acls. 1660 6178 ny155746 * This is because, if the server's FS happens to be UFS, supporting 1661 6178 ny155746 * POSIX ACL's, then it does a special calculation of group mode 1662 6178 ny155746 * to be the bitwise OR of CLASS_OBJ and GROUP_OBJ (see PSARC/2001/717.) 1663 6178 ny155746 * 1664 6178 ny155746 * This algorithm is from the NFSv4 ACL Draft. Here a part of that 1665 6178 ny155746 * algorithm is used for the group mode calculation only. 1666 6178 ny155746 * What is modified here from the algorithm is that only the 1667 6178 ny155746 * entries with flags ACE_GROUP are considered. For each entry 1668 6178 ny155746 * with ACE_GROUP flag, the first occurance of a specific access 1669 6178 ny155746 * is checked if it is allowed. 1670 6373 ny155746 * We are not interested in perms for user and other, as they 1671 6178 ny155746 * were taken from st_mode value. 1672 6178 ny155746 * We are not interested in a_who field of ACE, as we need just 1673 6178 ny155746 * unix mode bits for the group. 1674 6178 ny155746 */ 1675 6373 ny155746 1676 6373 ny155746 #define OWNED_GROUP (ACE_GROUP | ACE_IDENTIFIER_GROUP) 1677 6373 ny155746 #define IS_TYPE_ALLOWED(type) ((type) == ACE_ACCESS_ALLOWED_ACE_TYPE) 1678 6373 ny155746 1679 6178 ny155746 int 1680 6178 ny155746 grp_mask_to_mode(acl_t *acep) 1681 6178 ny155746 { 1682 6178 ny155746 int mode = 0, seen = 0; 1683 6178 ny155746 int acecnt; 1684 6373 ny155746 int flags; 1685 6178 ny155746 ace_t *ap; 1686 6178 ny155746 1687 6178 ny155746 acecnt = acl_cnt(acep); 1688 6178 ny155746 for (ap = (ace_t *)acl_data(acep); acecnt--; ap++) { 1689 6373 ny155746 1690 6373 ny155746 if (ap->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE && 1691 6373 ny155746 ap->a_type != ACE_ACCESS_DENIED_ACE_TYPE) 1692 6373 ny155746 continue; 1693 6373 ny155746 1694 6373 ny155746 if (ap->a_flags & ACE_INHERIT_ONLY_ACE) 1695 6373 ny155746 continue; 1696 6373 ny155746 1697 6373 ny155746 /* 1698 6373 ny155746 * if it is first group@ or first everyone@ 1699 6373 ny155746 * for each of read, write and execute, then 1700 6373 ny155746 * that will be the group mode bit. 1701 6373 ny155746 */ 1702 6373 ny155746 flags = ap->a_flags & ACE_TYPE_FLAGS; 1703 6373 ny155746 if (flags == OWNED_GROUP || flags == ACE_EVERYONE) { 1704 6373 ny155746 if (ap->a_access_mask & ACE_READ_DATA) { 1705 6373 ny155746 if (!(seen & S_IRGRP)) { 1706 6373 ny155746 seen |= S_IRGRP; 1707 6373 ny155746 if (IS_TYPE_ALLOWED(ap->a_type)) 1708 6373 ny155746 mode |= S_IRGRP; 1709 6178 ny155746 } 1710 6373 ny155746 } 1711 6373 ny155746 if (ap->a_access_mask & ACE_WRITE_DATA) { 1712 6373 ny155746 if (!(seen & S_IWGRP)) { 1713 6373 ny155746 seen |= S_IWGRP; 1714 6373 ny155746 if (IS_TYPE_ALLOWED(ap->a_type)) 1715 6373 ny155746 mode |= S_IWGRP; 1716 6178 ny155746 } 1717 6373 ny155746 } 1718 6373 ny155746 if (ap->a_access_mask & ACE_EXECUTE) { 1719 6373 ny155746 if (!(seen & S_IXGRP)) { 1720 6373 ny155746 seen |= S_IXGRP; 1721 6373 ny155746 if (IS_TYPE_ALLOWED(ap->a_type)) 1722 6373 ny155746 mode |= S_IXGRP; 1723 6178 ny155746 } 1724 6178 ny155746 } 1725 6178 ny155746 } 1726 6178 ny155746 } 1727 6178 ny155746 return (mode); 1728 6178 ny155746 } 1729 6178 ny155746 1730 6178 ny155746 /* 1731 0 stevel * get status of file and recomputes tblocks; 1732 0 stevel * argfl = 1 if file is a name in ls-command and = 0 1733 0 stevel * for filename in a directory whose name is an 1734 0 stevel * argument in the command; 1735 0 stevel * stores a pointer in flist[nfiles] and 1736 0 stevel * returns that pointer; 1737 0 stevel * returns NULL if failed; 1738 0 stevel */ 1739 0 stevel static struct lbuf * 1740 0 stevel gstat(char *file, int argfl, struct ditem *myparent) 1741 0 stevel { 1742 0 stevel struct stat statb, statb1; 1743 0 stevel struct lbuf *rep; 1744 0 stevel char buf[BUFSIZ]; 1745 0 stevel ssize_t cc; 1746 0 stevel int (*statf)() = ((Lflg) || (Hflg && argfl)) ? stat : lstat; 1747 0 stevel int aclcnt; 1748 789 ahrens int error; 1749 0 stevel aclent_t *tp; 1750 0 stevel o_mode_t groupperm, mask; 1751 0 stevel int grouppermfound, maskfound; 1752 0 stevel 1753 0 stevel if (nomocore) 1754 0 stevel return (NULL); 1755 0 stevel 1756 0 stevel if (nfiles >= maxfils) { 1757 0 stevel /* 1758 0 stevel * all flist/lbuf pair assigned files, time to get some 1759 0 stevel * more space 1760 0 stevel */ 1761 0 stevel maxfils += quantn; 1762 0 stevel if (((flist = realloc(flist, 1763 0 stevel maxfils * sizeof (struct lbuf *))) == NULL) || 1764 0 stevel ((nxtlbf = malloc(quantn * 1765 0 stevel sizeof (struct lbuf))) == NULL)) { 1766 0 stevel perror("ls"); 1767 0 stevel nomocore = 1; 1768 0 stevel return (NULL); 1769 0 stevel } 1770 0 stevel } 1771 0 stevel 1772 0 stevel /* 1773 0 stevel * nfiles is reset to nargs for each directory 1774 0 stevel * that is given as an argument maxn is checked 1775 0 stevel * to prevent the assignment of an lbuf to a flist entry 1776 0 stevel * that already has one assigned. 1777 0 stevel */ 1778 0 stevel if (nfiles >= maxn) { 1779 0 stevel rep = nxtlbf++; 1780 0 stevel flist[nfiles++] = rep; 1781 0 stevel maxn = nfiles; 1782 0 stevel } else { 1783 0 stevel rep = flist[nfiles++]; 1784 0 stevel } 1785 6792 basabi 1786 6792 basabi /* Initialize */ 1787 6792 basabi 1788 0 stevel rep->lflags = (mode_t)0; 1789 0 stevel rep->flinkto = NULL; 1790 0 stevel rep->cycle = 0; 1791 6792 basabi rep->lat.tv_sec = time(NULL); 1792 6792 basabi rep->lat.tv_nsec = 0; 1793 6792 basabi rep->lct.tv_sec = time(NULL); 1794 6792 basabi rep->lct.tv_nsec = 0; 1795 6792 basabi rep->lmt.tv_sec = time(NULL); 1796 6792 basabi rep->lmt.tv_nsec = 0; 1797 6792 basabi rep->exttr = NULL; 1798 6792 basabi rep->extm = NULL; 1799 10059 jason rep->color = NULL; 1800 10059 jason rep->link_color = NULL; 1801 6792 basabi 1802 0 stevel if (argfl || statreq) { 1803 0 stevel int doacl; 1804 0 stevel 1805 0 stevel if (lflg) 1806 0 stevel doacl = 1; 1807 0 stevel else 1808 0 stevel doacl = 0; 1809 6792 basabi 1810 0 stevel if ((*statf)(file, &statb) < 0) { 1811 0 stevel if (argfl || errno != ENOENT || 1812 0 stevel (Lflg && lstat(file, &statb) == 0)) { 1813 0 stevel /* 1814 0 stevel * Avoid race between readdir and lstat. 1815 0 stevel * Print error message in case of dangling link. 1816 0 stevel */ 1817 0 stevel perror(file); 1818 9664 jason err = 2; 1819 0 stevel } 1820 0 stevel nfiles--; 1821 0 stevel return (NULL); 1822 0 stevel } 1823 0 stevel 1824 0 stevel /* 1825 0 stevel * If -H was specified, and the file linked to was 1826 0 stevel * not a directory, then we need to get the info 1827 0 stevel * for the symlink itself. 1828 0 stevel */ 1829 0 stevel if ((Hflg) && (argfl) && 1830 0 stevel ((statb.st_mode & S_IFMT) != S_IFDIR)) { 1831 0 stevel if (lstat(file, &statb) < 0) { 1832 0 stevel perror(file); 1833 9664 jason err = 2; 1834 0 stevel } 1835 0 stevel } 1836 0 stevel 1837 0 stevel rep->lnum = statb.st_ino; 1838 0 stevel rep->lsize = statb.st_size; 1839 0 stevel rep->lblocks = statb.st_blocks; 1840 10059 jason if (colorflg) 1841 10059 jason rep->color = ls_color_find(file, statb.st_mode); 1842 10059 jason 1843 0 stevel switch (statb.st_mode & S_IFMT) { 1844 0 stevel case S_IFDIR: 1845 0 stevel rep->ltype = 'd'; 1846 0 stevel if (Rflg) { 1847 0 stevel record_ancestry(file, &statb, rep, 1848 0 stevel argfl, myparent); 1849 0 stevel } 1850 0 stevel break; 1851 0 stevel case S_IFBLK: 1852 0 stevel rep->ltype = 'b'; 1853 0 stevel rep->lsize = (off_t)statb.st_rdev; 1854 0 stevel break; 1855 0 stevel case S_IFCHR: 1856 0 stevel rep->ltype = 'c'; 1857 0 stevel rep->lsize = (off_t)statb.st_rdev; 1858 0 stevel break; 1859 0 stevel case S_IFIFO: 1860 0 stevel rep->ltype = 'p'; 1861 0 stevel break; 1862 0 stevel case S_IFSOCK: 1863 0 stevel rep->ltype = 's'; 1864 0 stevel rep->lsize = 0; 1865 0 stevel break; 1866 0 stevel case S_IFLNK: 1867 0 stevel /* symbolic links may not have ACLs, so elide acl() */ 1868 0 stevel if ((Lflg == 0) || (Hflg == 0) || 1869 0 stevel ((Hflg) && (!argfl))) { 1870 0 stevel doacl = 0; 1871 0 stevel } 1872 0 stevel rep->ltype = 'l'; 1873 10059 jason if (lflg || colorflg) { 1874 0 stevel cc = readlink(file, buf, BUFSIZ); 1875 10059 jason if (cc < 0) 1876 10059 jason break; 1877 0 stevel 1878 10059 jason /* 1879 10059 jason * follow the symbolic link 1880 10059 jason * to generate the appropriate 1881 10059 jason * Fflg marker for the object 1882 10059 jason * eg, /bin -> /sym/bin/ 1883 10059 jason */ 1884 10059 jason error = 0; 1885 10059 jason if (Fflg || pflg || colorflg) 1886 10059 jason error = stat(file, &statb1); 1887 10059 jason 1888 10059 jason if (colorflg) { 1889 10059 jason if (error >= 0) 1890 10059 jason rep->link_color = 1891 10059 jason ls_color_find(file, 1892 10059 jason statb1.st_mode); 1893 10059 jason else 1894 10059 jason rep->link_color = 1895 10059 jason lsc_orphan; 1896 10059 jason } 1897 10059 jason 1898 10059 jason if ((Fflg || pflg) && error >= 0) { 1899 10059 jason switch (statb1.st_mode & S_IFMT) { 1900 10059 jason case S_IFDIR: 1901 10059 jason buf[cc++] = '/'; 1902 10059 jason break; 1903 10059 jason case S_IFSOCK: 1904 10059 jason buf[cc++] = '='; 1905 10059 jason break; 1906 10059 jason case S_IFDOOR: 1907 10059 jason buf[cc++] = '>'; 1908 10059 jason break; 1909 10059 jason case S_IFIFO: 1910 10059 jason buf[cc++] = '|'; 1911 10059 jason break; 1912 10059 jason default: 1913 10059 jason if ((statb1.st_mode & ~S_IFMT) & 1914 10059 jason (S_IXUSR|S_IXGRP| S_IXOTH)) 1915 10059 jason buf[cc++] = '*'; 1916 10059 jason break; 1917 0 stevel } 1918 0 stevel } 1919 10059 jason buf[cc] = '\0'; 1920 10059 jason rep->flinkto = strdup(buf); 1921 0 stevel break; 1922 0 stevel } 1923 0 stevel 1924 0 stevel /* 1925 0 stevel * ls /sym behaves differently from ls /sym/ 1926 0 stevel * when /sym is a symbolic link. This is fixed 1927 0 stevel * when explicit arguments are specified. 1928 0 stevel */ 1929 0 stevel 1930 0 stevel #ifdef XPG6 1931 0 stevel /* Do not follow a symlink when -F is specified */ 1932 0 stevel if ((!argfl) || (argfl && Fflg) || 1933 0 stevel (stat(file, &statb1) < 0)) 1934 0 stevel #else 1935 0 stevel /* Follow a symlink when -F is specified */ 1936 0 stevel if (!argfl || stat(file, &statb1) < 0) 1937 0 stevel #endif /* XPG6 */ 1938 0 stevel break; 1939 0 stevel if ((statb1.st_mode & S_IFMT) == S_IFDIR) { 1940 0 stevel statb = statb1; 1941 0 stevel rep->ltype = 'd'; 1942 0 stevel rep->lsize = statb1.st_size; 1943 0 stevel if (Rflg) { 1944 0 stevel record_ancestry(file, &statb, rep, 1945 0 stevel argfl, myparent); 1946 0 stevel } 1947 0 stevel } 1948 0 stevel break; 1949 0 stevel case S_IFDOOR: 1950 0 stevel rep->ltype = 'D'; 1951 0 stevel break; 1952 0 stevel case S_IFREG: 1953 0 stevel rep->ltype = '-'; 1954 0 stevel break; 1955 0 stevel case S_IFPORT: 1956 0 stevel rep->ltype = 'P'; 1957 0 stevel break; 1958 0 stevel default: 1959 0 stevel rep->ltype = '?'; 1960 0 stevel break; 1961 0 stevel } 1962 0 stevel rep->lflags = statb.st_mode & ~S_IFMT; 1963 0 stevel 1964 0 stevel if (!S_ISREG(statb.st_mode)) 1965 0 stevel rep->lflags |= LS_NOTREG; 1966 0 stevel 1967 6792 basabi rep->luid = statb.st_uid; 1968 6792 basabi rep->lgid = statb.st_gid; 1969 6792 basabi rep->lnl = statb.st_nlink; 1970 6792 basabi if (uflg || (tmflg && atm)) 1971 6792 basabi rep->lmtime = statb.st_atim; 1972 6792 basabi else if (cflg || (tmflg && ctm)) 1973 6792 basabi rep->lmtime = statb.st_ctim; 1974 6792 basabi else 1975 6792 basabi rep->lmtime = statb.st_mtim; 1976 6792 basabi rep->lat = statb.st_atim; 1977 6792 basabi rep->lct = statb.st_ctim; 1978 6792 basabi rep->lmt = statb.st_mtim; 1979 6792 basabi 1980 0 stevel /* ACL: check acl entries count */ 1981 0 stevel if (doacl) { 1982 789 ahrens 1983 789 ahrens error = acl_get(file, 0, &rep->aclp); 1984 789 ahrens if (error) { 1985 789 ahrens (void) fprintf(stderr, 1986 789 ahrens gettext("ls: can't read ACL on %s: %s\n"), 1987 789 ahrens file, acl_strerror(error)); 1988 6792 basabi rep->acl = ' '; 1989 6866 basabi acl_err++; 1990 6792 basabi return (rep); 1991 789 ahrens } 1992 789 ahrens 1993 0 stevel rep->acl = ' '; 1994 0 stevel 1995 789 ahrens if (rep->aclp && 1996 789 ahrens ((acl_flags(rep->aclp) & ACL_IS_TRIVIAL) == 0)) { 1997 789 ahrens rep->acl = '+'; 1998 789 ahrens /* 1999 789 ahrens * Special handling for ufs aka aclent_t ACL's 2000 789 ahrens */ 2001 6178 ny155746 if (acl_type(rep->aclp) == ACLENT_T) { 2002 789 ahrens /* 2003 789 ahrens * For files with non-trivial acls, the 2004 789 ahrens * effective group permissions are the 2005 789 ahrens * intersection of the GROUP_OBJ value 2006 789 ahrens * and the CLASS_OBJ (acl mask) value. 2007 789 ahrens * Determine both the GROUP_OBJ and 2008 789 ahrens * CLASS_OBJ for this file and insert 2009 789 ahrens * the logical AND of those two values 2010 789 ahrens * in the group permissions field 2011 789 ahrens * of the lflags value for this file. 2012 789 ahrens */ 2013 0 stevel 2014 789 ahrens /* 2015 789 ahrens * Until found in acl list, assume 2016 789 ahrens * maximum permissions for both group 2017 789 ahrens * a nd mask. (Just in case the acl 2018 789 ahrens * lacks either value for some reason.) 2019 789 ahrens */ 2020 789 ahrens groupperm = 07; 2021 789 ahrens mask = 07; 2022 789 ahrens grouppermfound = 0; 2023 789 ahrens maskfound = 0; 2024 789 ahrens aclcnt = acl_cnt(rep->aclp); 2025 789 ahrens for (tp = 2026 789 ahrens (aclent_t *)acl_data(rep->aclp); 2027 789 ahrens aclcnt--; tp++) { 2028 789 ahrens if (tp->a_type == GROUP_OBJ) { 2029 789 ahrens groupperm = tp->a_perm; 2030 789 ahrens grouppermfound = 1; 2031 789 ahrens continue; 2032 789 ahrens } 2033 789 ahrens if (tp->a_type == CLASS_OBJ) { 2034 789 ahrens mask = tp->a_perm; 2035 789 ahrens maskfound = 1; 2036 789 ahrens } 2037 789 ahrens if (grouppermfound && maskfound) 2038 789 ahrens break; 2039 789 ahrens } 2040 0 stevel 2041 0 stevel 2042 789 ahrens /* reset all the group bits */ 2043 789 ahrens rep->lflags &= ~S_IRWXG; 2044 789 ahrens 2045 789 ahrens /* 2046 789 ahrens * Now set them to the logical AND of 2047 789 ahrens * the GROUP_OBJ permissions and the 2048 789 ahrens * acl mask. 2049 789 ahrens */ 2050 789 ahrens 2051 789 ahrens rep->lflags |= (groupperm & mask) << 3; 2052 789 ahrens 2053 6178 ny155746 } else if (acl_type(rep->aclp) == ACE_T) { 2054 6178 ny155746 int mode; 2055 6178 ny155746 mode = grp_mask_to_mode(rep->aclp); 2056 6178 ny155746 rep->lflags &= ~S_IRWXG; 2057 6178 ny155746 rep->lflags |= mode; 2058 0 stevel } 2059 0 stevel } 2060 0 stevel 2061 1420 marks if (!vflg && !Vflg && rep->aclp) { 2062 1420 marks acl_free(rep->aclp); 2063 1420 marks rep->aclp = NULL; 2064 1420 marks } 2065 1420 marks 2066 0 stevel if (atflg && pathconf(file, _PC_XATTR_EXISTS) == 1) 2067 0 stevel rep->acl = '@'; 2068 5331 amw 2069 0 stevel } else 2070 0 stevel rep->acl = ' '; 2071 0 stevel 2072 0 stevel /* mask ISARG and other file-type bits */ 2073 0 stevel 2074 0 stevel if (rep->ltype != 'b' && rep->ltype != 'c') 2075 0 stevel tblocks += rep->lblocks; 2076 5331 amw 2077 5331 amw /* Get extended system attributes */ 2078 5331 amw 2079 5331 amw if ((saflg || (tmflg && crtm) || (tmflg && alltm)) && 2080 5331 amw (sysattr_support(file, _PC_SATTR_EXISTS) == 1)) { 2081 5331 amw int i; 2082 5331 amw 2083 5331 amw sacnt = attr_count(); 2084 5331 amw /* 2085 5331 amw * Allocate 'sacnt' size array to hold extended 2086 5331 amw * system attribute name (verbose) or respective 2087 5331 amw * symbol represenation (compact). 2088 5331 amw */ 2089 5331 amw rep->exttr = xmalloc(sacnt * sizeof (struct attrb), 2090 5331 amw rep); 2091 5331 amw 2092 5331 amw /* initialize boolean attribute list */ 2093 5331 amw for (i = 0; i < sacnt; i++) 2094 5331 amw rep->exttr[i].name = NULL; 2095 5331 amw if (get_sysxattr(file, rep) != 0) { 2096 5331 amw (void) fprintf(stderr, 2097 5331 amw gettext("ls:Failed to retrieve " 2098 5331 amw "extended system attribute from " 2099 5331 amw "%s\n"), file); 2100 5331 amw rep->exttr[0].name = xmalloc(2, rep); 2101 5331 amw (void) strlcpy(rep->exttr[0].name, "?", 2); 2102 5331 amw } 2103 5331 amw } 2104 0 stevel } 2105 0 stevel return (rep); 2106 0 stevel } 2107 0 stevel 2108 0 stevel /* 2109 0 stevel * returns pathname of the form dir/file; 2110 0 stevel * dir and file are null-terminated strings. 2111 0 stevel */ 2112 0 stevel static char * 2113 0 stevel makename(char *dir, char *file) 2114 0 stevel { 2115 0 stevel /* 2116 0 stevel * PATH_MAX is the maximum length of a path name. 2117 0 stevel * MAXNAMLEN is the maximum length of any path name component. 2118 0 stevel * Allocate space for both, plus the '/' in the middle 2119 0 stevel * and the null character at the end. 2120 0 stevel * dfile is static as this is returned by makename(). 2121 0 stevel */ 2122 0 stevel static char dfile[PATH_MAX + 1 + MAXNAMLEN + 1]; 2123 0 stevel char *dp, *fp; 2124 0 stevel 2125 0 stevel dp = dfile; 2126 0 stevel fp = dir; 2127 0 stevel while (*fp) 2128 0 stevel *dp++ = *fp++; 2129 0 stevel if (dp > dfile && *(dp - 1) != '/') 2130 0 stevel *dp++ = '/'; 2131 0 stevel fp = file; 2132 0 stevel while (*fp) 2133 0 stevel *dp++ = *fp++; 2134 0 stevel *dp = '\0'; 2135 0 stevel return (dfile); 2136 0 stevel } 2137 0 stevel 2138 0 stevel 2139 0 stevel #include <pwd.h> 2140 0 stevel #include <grp.h> 2141 0 stevel #include <utmpx.h> 2142 0 stevel 2143 0 stevel struct utmpx utmp; 2144 0 stevel 2145 0 stevel #define NMAX (sizeof (utmp.ut_name)) 2146 0 stevel #define SCPYN(a, b) (void) strncpy(a, b, NMAX) 2147 0 stevel 2148 0 stevel 2149 0 stevel struct cachenode { /* this struct must be zeroed before using */ 2150 0 stevel struct cachenode *lesschild; /* subtree whose entries < val */ 2151 0 stevel struct cachenode *grtrchild; /* subtree whose entries > val */ 2152 0 stevel long val; /* the uid or gid of this entry */ 2153 0 stevel int initted; /* name has been filled in */ 2154 0 stevel char name[NMAX+1]; /* the string that val maps to */ 2155 0 stevel }; 2156 0 stevel static struct cachenode *names, *groups; 2157 0 stevel 2158 0 stevel static struct cachenode * 2159 0 stevel findincache(struct cachenode **head, long val) 2160 0 stevel { 2161 0 stevel struct cachenode **parent = head; 2162 0 stevel struct cachenode *c = *parent; 2163 0 stevel 2164 0 stevel while (c != NULL) { 2165 0 stevel if (val == c->val) { 2166 0 stevel /* found it */ 2167 0 stevel return (c); 2168 0 stevel } else if (val < c->val) { 2169 0 stevel parent = &c->lesschild; 2170 0 stevel c = c->lesschild; 2171 0 stevel } else { 2172 0 stevel parent = &c->grtrchild; 2173 0 stevel c = c->grtrchild; 2174 0 stevel } 2175 0 stevel } 2176 0 stevel 2177 0 stevel /* not in the cache, make a new entry for it */ 2178 0 stevel c = calloc(1, sizeof (struct cachenode)); 2179 0 stevel if (c == NULL) { 2180 0 stevel perror("ls"); 2181 0 stevel exit(2); 2182 0 stevel } 2183 0 stevel *parent = c; 2184 0 stevel c->val = val; 2185 0 stevel return (c); 2186 0 stevel } 2187 0 stevel 2188 0 stevel /* 2189 0 stevel * get name from cache, or passwd file for a given uid; 2190 0 stevel * lastuid is set to uid. 2191 0 stevel */ 2192 0 stevel static char * 2193 0 stevel getname(uid_t uid) 2194 0 stevel { 2195 0 stevel struct passwd *pwent; 2196 0 stevel struct cachenode *c; 2197 0 stevel 2198 0 stevel if ((uid == lastuid) && lastuname) 2199 0 stevel return (lastuname); 2200 0 stevel 2201 0 stevel c = findincache(&names, uid); 2202 0 stevel if (c->initted == 0) { 2203 0 stevel if ((pwent = getpwuid(uid)) != NULL) { 2204 0 stevel SCPYN(&c->name[0], pwent->pw_name); 2205 0 stevel } else { 2206 0 stevel (void) sprintf(&c->name[0], "%-8u", (int)uid); 2207 0 stevel } 2208 0 stevel c->initted = 1; 2209 0 stevel } 2210 0 stevel lastuid = uid; 2211 0 stevel lastuname = &c->name[0]; 2212 0 stevel return (lastuname); 2213 0 stevel } 2214 0 stevel 2215 0 stevel /* 2216 0 stevel * get name from cache, or group file for a given gid; 2217 0 stevel * lastgid is set to gid. 2218 0 stevel */ 2219 0 stevel static char * 2220 0 stevel getgroup(gid_t gid) 2221 0 stevel { 2222 0 stevel struct group *grent; 2223 0 stevel struct cachenode *c; 2224 0 stevel 2225 0 stevel if ((gid == lastgid) && lastgname) 2226 0 stevel return (lastgname); 2227 0 stevel 2228 0 stevel c = findincache(&groups, gid); 2229 0 stevel if (c->initted == 0) { 2230 0 stevel if ((grent = getgrgid(gid)) != NULL) { 2231 0 stevel SCPYN(&c->name[0], grent->gr_name); 2232 0 stevel } else { 2233 0 stevel (void) sprintf(&c->name[0], "%-8u", (int)gid); 2234 0 stevel } 2235 0 stevel c->initted = 1; 2236 0 stevel } 2237 0 stevel lastgid = gid; 2238 0 stevel lastgname = &c->name[0]; 2239 0 stevel return (lastgname); 2240 0 stevel } 2241 0 stevel 2242 0 stevel /* return >0 if item pointed by pp2 should appear first */ 2243 0 stevel static int 2244 0 stevel compar(struct lbuf **pp1, struct lbuf **pp2) 2245 0 stevel { 2246 0 stevel struct lbuf *p1, *p2; 2247 0 stevel 2248 0 stevel p1 = *pp1; 2249 0 stevel p2 = *pp2; 2250 0 stevel if (dflg == 0) { 2251 0 stevel /* 2252 0 stevel * compare two names in ls-command one of which is file 2253 0 stevel * and the other is a directory; 2254 0 stevel * this portion is not used for comparing files within 2255 0 stevel * a directory name of ls-command; 2256 0 stevel */ 2257 0 stevel if (p1->lflags&ISARG && p1->ltype == 'd') { 2258 0 stevel if (!(p2->lflags&ISARG && p2->ltype == 'd')) 2259 0 stevel return (1); 2260 0 stevel } else { 2261 0 stevel if (p2->lflags&ISARG && p2->ltype == 'd') 2262 0 stevel return (-1); 2263 0 stevel } 2264 0 stevel } 2265 0 stevel if (tflg) { 2266 0 stevel if (p2->lmtime.tv_sec > p1->lmtime.tv_sec) 2267 0 stevel return (rflg); 2268 0 stevel else if (p2->lmtime.tv_sec < p1->lmtime.tv_sec) 2269 0 stevel return (-rflg); 2270 0 stevel /* times are equal to the sec, check nsec */ 2271 0 stevel if (p2->lmtime.tv_nsec > p1->lmtime.tv_nsec) 2272 0 stevel return (rflg); 2273 0 stevel else if (p2->lmtime.tv_nsec < p1->lmtime.tv_nsec) 2274 0 stevel return (-rflg); 2275 0 stevel /* if times are equal, fall through and sort by name */ 2276 0 stevel } else if (Sflg) { 2277 0 stevel /* 2278 0 stevel * The size stored in lsize can be either the 2279 0 stevel * size or the major minor number (in the case of 2280 0 stevel * block and character special devices). If it's 2281 0 stevel * a major minor number, then the size is considered 2282 0 stevel * to be zero and we want to fall through and sort 2283 0 stevel * by name. In addition, if the size of p2 is equal 2284 0 stevel * to the size of p1 we want to fall through and 2285 0 stevel * sort by name. 2286 0 stevel */ 2287 0 stevel off_t p1size = (p1->ltype == 'b') || 2288 5331 amw (p1->ltype == 'c') ? 0 : p1->lsize; 2289 0 stevel off_t p2size = (p2->ltype == 'b') || 2290 5331 amw (p2->ltype == 'c') ? 0 : p2->lsize; 2291 0 stevel if (p2size > p1size) { 2292 0 stevel return (rflg); 2293 0 stevel } else if (p2size < p1size) { 2294 0 stevel return (-rflg); 2295 0 stevel } 2296 0 stevel /* Sizes are equal, fall through and sort by name. */ 2297 0 stevel } 2298 0 stevel return (rflg * strcoll( 2299 0 stevel p1->lflags & ISARG ? p1->ln.namep : p1->ln.lname, 2300 0 stevel p2->lflags&ISARG ? p2->ln.namep : p2->ln.lname)); 2301 0 stevel } 2302 0 stevel 2303 0 stevel static void 2304 0 stevel pprintf(char *s1, char *s2) 2305 0 stevel { 2306 0 stevel csi_pprintf((unsigned char *)s1); 2307 0 stevel csi_pprintf((unsigned char *)s2); 2308 0 stevel } 2309 0 stevel 2310 0 stevel static void 2311 0 stevel csi_pprintf(unsigned char *s) 2312 0 stevel { 2313 0 stevel unsigned char *cp; 2314 0 stevel char c; 2315 0 stevel int i; 2316 0 stevel int c_len; 2317 0 stevel int p_col; 2318 0 stevel wchar_t pcode; 2319 0 stevel 2320 0 stevel if (!qflg && !bflg) { 2321 0 stevel for (cp = s; *cp != '\0'; cp++) { 2322 0 stevel (void) putchar(*cp); 2323 0 stevel curcol++; 2324 0 stevel } 2325 0 stevel return; 2326 0 stevel } 2327 0 stevel 2328 0 stevel for (cp = s; *cp; ) { 2329 0 stevel if (isascii(c = *cp)) { 2330 0 stevel if (!isprint(c)) { 2331 0 stevel if (qflg) { 2332 0 stevel c = '?'; 2333 0 stevel } else { 2334 0 stevel curcol += 3; 2335 0 stevel (void) putc('\\', stdout); 2336 0 stevel c = '0' + ((*cp >> 6) & 07); 2337 0 stevel (void) putc(c, stdout); 2338 0 stevel c = '0' + ((*cp >> 3) & 07); 2339 0 stevel (void) putc(c, stdout); 2340 0 stevel c = '0' + (*cp & 07); 2341 0 stevel } 2342 0 stevel } 2343 0 stevel curcol++; 2344 0 stevel cp++; 2345 0 stevel (void) putc(c, stdout); 2346 0 stevel continue; 2347 0 stevel } 2348 0 stevel 2349 0 stevel if ((c_len = mbtowc(&pcode, (char *)cp, MB_LEN_MAX)) <= 0) { 2350 0 stevel c_len = 1; 2351 0 stevel goto not_print; 2352 0 stevel } 2353 0 stevel 2354 0 stevel if ((p_col = wcwidth(pcode)) > 0) { 2355 0 stevel (void) putwchar(pcode); 2356 0 stevel cp += c_len; 2357 0 stevel curcol += p_col; 2358 0 stevel continue; 2359 0 stevel } 2360 0 stevel 2361 0 stevel not_print: 2362 0 stevel for (i = 0; i < c_len; i++) { 2363 0 stevel if (qflg) { 2364 0 stevel c = '?'; 2365 0 stevel } else { 2366 0 stevel curcol += 3; 2367 0 stevel (void) putc('\\', stdout); 2368 0 stevel c = '0' + ((*cp >> 6) & 07); 2369 0 stevel (void) putc(c, stdout); 2370 0 stevel c = '0' + ((*cp >> 3) & 07); 2371 0 stevel (void) putc(c, stdout); 2372 0 stevel c = '0' + (*cp & 07); 2373 0 stevel } 2374 0 stevel curcol++; 2375 0 stevel (void) putc(c, stdout); 2376 0 stevel cp++; 2377 0 stevel } 2378 0 stevel } 2379 0 stevel } 2380 0 stevel 2381 0 stevel static int 2382 0 stevel strcol(unsigned char *s1) 2383 0 stevel { 2384 0 stevel int w; 2385 0 stevel int w_col; 2386 0 stevel int len; 2387 0 stevel wchar_t wc; 2388 0 stevel 2389 0 stevel w = 0; 2390 0 stevel while (*s1) { 2391 0 stevel if (isascii(*s1)) { 2392 0 stevel w++; 2393 0 stevel s1++; 2394 0 stevel continue; 2395 0 stevel } 2396 0 stevel 2397 0 stevel if ((len = mbtowc(&wc, (char *)s1, MB_LEN_MAX)) <= 0) { 2398 0 stevel w++; 2399 0 stevel s1++; 2400 0 stevel continue; 2401 0 stevel } 2402 0 stevel 2403 0 stevel if ((w_col = wcwidth(wc)) < 0) 2404 0 stevel w_col = len; 2405 0 stevel s1 += len; 2406 0 stevel w += w_col; 2407 0 stevel } 2408 0 stevel return (w); 2409 0 stevel } 2410 0 stevel 2411 0 stevel /* 2412 0 stevel * Convert an unsigned long long to a string representation and place the 2413 0 stevel * result in the caller-supplied buffer. 2414 0 stevel * 2415 0 stevel * The number provided is a size in bytes. The number is first 2416 0 stevel * converted to an integral multiple of 'scale' bytes. This new 2417 0 stevel * number is then scaled down until it is small enough to be in a good 2418 0 stevel * human readable format, i.e. in the range 0 thru scale-1. If the 2419 0 stevel * number used to derive the final number is not a multiple of scale, and 2420 0 stevel * the final number has only a single significant digit, we compute 2421 0 stevel * tenths of units to provide a second significant digit. 2422 0 stevel * 2423 0 stevel * The value "(unsigned long long)-1" is a special case and is always 2424 0 stevel * converted to "-1". 2425 0 stevel * 2426 0 stevel * A pointer to the caller-supplied buffer is returned. 2427 0 stevel */ 2428 0 stevel static char * 2429 0 stevel number_to_scaled_string( 2430 0 stevel numbuf_t buf, /* put the result here */ 2431 0 stevel unsigned long long number, /* convert this number */ 2432 0 stevel long scale) 2433 0 stevel { 2434 0 stevel unsigned long long save; 2435 0 stevel /* Measurement: kilo, mega, giga, tera, peta, exa */ 2436 0 stevel char *uom = "KMGTPE"; 2437 0 stevel 2438 0 stevel if ((long long)number == (long long)-1) { 2439 0 stevel (void) strlcpy(buf, "-1", sizeof (numbuf_t)); 2440 0 stevel return (buf); 2441 0 stevel } 2442 0 stevel 2443 0 stevel save = number; 2444 0 stevel number = number / scale; 2445 0 stevel 2446 0 stevel /* 2447 0 stevel * Now we have number as a count of scale units. 2448 0 stevel * If no further scaling is necessary, we round up as appropriate. 2449 0 stevel * 2450 0 stevel * The largest value number could have had entering the routine is 2451 0 stevel * 16 Exabytes, so running off the end of the uom array should 2452 0 stevel * never happen. We check for that, though, as a guard against 2453 0 stevel * a breakdown elsewhere in the algorithm. 2454 0 stevel */ 2455 0 stevel if (number < (unsigned long long)scale) { 2456 0 stevel if ((save % scale) >= (unsigned long long)(scale / 2)) { 2457 0 stevel if (++number == (unsigned long long)scale) { 2458 0 stevel uom++; 2459 0 stevel number = 1; 2460 0 stevel } 2461 0 stevel } 2462 0 stevel } else { 2463 0 stevel while ((number >= (unsigned long long)scale) && (*uom != 'E')) { 2464 0 stevel uom++; /* next unit of measurement */ 2465 0 stevel save = number; 2466 0 stevel /* 2467 0 stevel * If we're over half way to the next unit of 2468 0 stevel * 'scale' bytes (which means we should round 2469 0 stevel * up), then adding half of 'scale' prior to 2470 0 stevel * the division will push us into that next 2471 0 stevel * unit of scale when we perform the division 2472 0 stevel */ 2473 0 stevel number = (number + (scale / 2)) / scale; 2474 0 stevel } 2475 0 stevel } 2476 0 stevel 2477 0 stevel /* check if we should output a decimal place after the point */ 2478 0 stevel if ((save / scale) < 10) { 2479 0 stevel /* snprintf() will round for us */ 2480 0 stevel float fnum = (float)save / scale; 2481 0 stevel (void) snprintf(buf, sizeof (numbuf_t), "%2.1f%c", 2482 0 stevel fnum, *uom); 2483 0 stevel } else { 2484 0 stevel (void) snprintf(buf, sizeof (numbuf_t), "%4llu%c", 2485 0 stevel number, *uom); 2486 0 stevel } 2487 0 stevel return (buf); 2488 0 stevel } 2489 5331 amw 2490 5331 amw /* Get extended system attributes and set the display */ 2491 5331 amw 2492 5331 amw int 2493 5331 amw get_sysxattr(char *fname, struct lbuf *rep) 2494 5331 amw { 2495 5331 amw boolean_t value; 2496 5331 amw data_type_t type; 2497 5331 amw int error; 2498 5331 amw char *name; 2499 5331 amw int i; 2500 5331 amw 2501 5331 amw if ((error = getattrat(AT_FDCWD, XATTR_VIEW_READWRITE, fname, 2502 5331 amw &response)) != 0) { 2503 5331 amw perror("ls:getattrat"); 2504 5331 amw return (error); 2505 5331 amw } 2506 5331 amw 2507 5331 amw /* 2508 5331 amw * Allocate 'sacnt' size array to hold extended timestamp 2509 5331 amw * system attributes and initialize the array. 2510 5331 amw */ 2511 5331 amw rep->extm = xmalloc(sacnt * sizeof (struct attrtm), rep); 2512 5331 amw for (i = 0; i < sacnt; i++) { 2513 5331 amw rep->extm[i].stm = 0; 2514 5331 amw rep->extm[i].nstm = 0; 2515 5331 amw rep->extm[i].name = NULL; 2516 5331 amw } 2517 5331 amw while ((pair = nvlist_next_nvpair(response, pair)) != NULL) { 2518 5331 amw name = nvpair_name(pair); 2519 5331 amw type = nvpair_type(pair); 2520 5331 amw if (type == DATA_TYPE_BOOLEAN_VALUE) { 2521 5331 amw error = nvpair_value_boolean_value(pair, &value); 2522 5331 amw if (error) { 2523 5331 amw (void) fprintf(stderr, 2524 5331 amw gettext("nvpair_value_boolean_value " 2525 5331 amw "failed: error = %d\n"), error); 2526 5331 amw continue; 2527 5331 amw } 2528 5331 amw if (name != NULL) 2529 5331 amw set_sysattrb_display(name, value, rep); 2530 5331 amw continue; 2531 5331 amw } else if (type == DATA_TYPE_UINT64_ARRAY) { 2532 5331 amw if (name != NULL) 2533 5331 amw set_sysattrtm_display(name, rep); 2534 5331 amw continue; 2535 5331 amw } 2536 5331 amw } 2537 5331 amw nvlist_free(response); 2538 5331 amw return (0); 2539 5331 amw } 2540 5331 amw 2541 5331 amw /* Set extended system attribute boolean display */ 2542 5331 amw 2543 5331 amw void 2544 5331 amw set_sysattrb_display(char *name, boolean_t val, struct lbuf *rep) 2545 5331 amw { 2546 5331 amw f_attr_t fattr; 2547 5331 amw const char *opt; 2548 5331 amw size_t len; 2549 5331 amw 2550 5331 amw fattr = name_to_attr(name); 2551 5331 amw if (fattr != F_ATTR_INVAL && fattr < sacnt) { 2552 5331 amw if (vopt) { 2553 5331 amw len = strlen(name); 2554 5331 amw if (val) { 2555 5331 amw rep->exttr[fattr].name = xmalloc(len + 1, rep); 2556 5331 amw (void) strlcpy(rep->exttr[fattr].name, name, 2557 5331 amw len + 1); 2558 5331 amw } else { 2559 5331 amw rep->exttr[fattr].name = xmalloc(len + 3, rep); 2560 5331 amw (void) snprintf(rep->exttr[fattr].name, len + 3, 2561 5331 amw "no%s", name); 2562 5331 amw } 2563 5331 amw } else { 2564 5331 amw opt = attr_to_option(fattr); 2565 5331 amw if (opt != NULL) { 2566 5331 amw len = strlen(opt); 2567 5331 amw rep->exttr[fattr].name = xmalloc(len + 1, rep); 2568 5331 amw if (val) 2569 5331 amw (void) strlcpy(rep->exttr[fattr].name, 2570 5331 amw opt, len + 1); 2571 5331 amw else 2572 5331 amw (void) strlcpy(rep->exttr[fattr].name, 2573 5331 amw "-", len + 1); 2574 5331 amw } 2575 5331 amw } 2576 5331 amw } 2577 5331 amw } 2578 5331 amw 2579 5331 amw /* Set extended system attribute timestamp display */ 2580 5331 amw 2581 5331 amw void 2582 5331 amw set_sysattrtm_display(char *name, struct lbuf *rep) 2583 5331 amw { 2584 5331 amw uint_t nelem; 2585 5331 amw uint64_t *value; 2586 5331 amw int i; 2587 5331 amw size_t len; 2588 5331 amw 2589 5331 amw if (nvpair_value_uint64_array(pair, &value, &nelem) == 0) { 2590 5331 amw if (*value != NULL) { 2591 5331 amw len = strlen(name); 2592 5331 amw i = 0; 2593 5331 amw while (rep->extm[i].stm != 0 && i < sacnt) 2594 5331 amw i++; 2595 5331 amw rep->extm[i].stm = value[0]; 2596 5331 amw rep->extm[i].nstm = value[1]; 2597 5331 amw rep->extm[i].name = xmalloc(len + 1, rep); 2598 5331 amw (void) strlcpy(rep->extm[i].name, name, len + 1); 2599 5331 amw } 2600 5331 amw } 2601 5331 amw } 2602 5331 amw 2603 5331 amw void 2604 9664 jason format_time(time_t sec, time_t nsec) 2605 5331 amw { 2606 9664 jason const char *fstr = time_fmt_new; 2607 9664 jason char fmt_buf[FMTSIZE]; 2608 5331 amw 2609 9664 jason if (Eflg) { 2610 9664 jason (void) snprintf(fmt_buf, FMTSIZE, fstr, nsec); 2611 9664 jason (void) strftime(time_buf, sizeof (time_buf), fmt_buf, 2612 9664 jason localtime(&sec)); 2613 9664 jason return; 2614 9664 jason } 2615 9664 jason 2616 9664 jason if (sec < year || sec > now) 2617 9664 jason fstr = time_fmt_old; 2618 9664 jason 2619 9664 jason /* if a custom time was specified, shouldn't be localized */ 2620 5331 amw (void) strftime(time_buf, sizeof (time_buf), 2621 9664 jason (time_custom == 0) ? dcgettext(NULL, fstr, LC_TIME) : fstr, 2622 5331 amw localtime(&sec)); 2623 5331 amw } 2624 5331 amw 2625 5331 amw void 2626 5331 amw format_attrtime(struct lbuf *p) 2627 5331 amw { 2628 9664 jason int tmattr = 0; 2629 5331 amw int i; 2630 5331 amw 2631 5331 amw if (p->extm != NULL) { 2632 5331 amw for (i = 0; i < sacnt; i++) { 2633 5331 amw if (p->extm[i].name != NULL) { 2634 5331 amw tmattr = 1; 2635 5331 amw break; 2636 5331 amw } 2637 5331 amw } 2638 5331 amw } 2639 9664 jason 2640 5331 amw if (tmattr) { 2641 9664 jason const char *old_save = time_fmt_old; 2642 9664 jason const char *new_save = time_fmt_new; 2643 9664 jason 2644 9664 jason /* Eflg always sets format to FORMAT_ISO_FULL */ 2645 9664 jason if (!Eflg && !time_custom) { 2646 9664 jason time_fmt_old = FORMAT_OLD; 2647 9664 jason time_fmt_new = FORMAT_NEW; 2648 5331 amw } 2649 9664 jason 2650 9664 jason format_time((time_t)p->extm[i].stm, (time_t)p->extm[i].nstm); 2651 9664 jason 2652 9664 jason time_fmt_old = old_save; 2653 9664 jason time_fmt_new = new_save; 2654 5331 amw } 2655 5331 amw } 2656 5331 amw 2657 5331 amw void 2658 5331 amw print_time(struct lbuf *p) 2659 5331 amw { 2660 9664 jason const char *old_save = time_fmt_old; 2661 9664 jason const char *new_save = time_fmt_new; 2662 9664 jason 2663 5331 amw int i = 0; 2664 5331 amw 2665 9664 jason if (!Eflg) { 2666 9664 jason time_fmt_old = FORMAT_LONG; 2667 9664 jason time_fmt_new = FORMAT_LONG; 2668 9664 jason } 2669 9664 jason 2670 5331 amw new_line(); 2671 9664 jason format_time(p->lat.tv_sec, p->lat.tv_nsec); 2672 9664 jason (void) printf(" timestamp: atime %s\n", time_buf); 2673 9664 jason format_time(p->lct.tv_sec, p->lct.tv_nsec); 2674 9664 jason (void) printf(" timestamp: ctime %s\n", time_buf); 2675 9664 jason format_time(p->lmt.tv_sec, p->lmt.tv_nsec); 2676 9664 jason (void) printf(" timestamp: mtime %s\n", time_buf); 2677 9664 jason if (p->extm != NULL) { 2678 9664 jason while (p->extm[i].nstm != 0 && i < sacnt) { 2679 9664 jason format_time(p->extm[i].stm, p->extm[i].nstm); 2680 9664 jason if (p->extm[i].name != NULL) { 2681 9664 jason (void) printf(" timestamp:" 2682 9664 jason " %s %s\n", 2683 9664 jason p->extm[i].name, time_buf); 2684 9664 jason } 2685 9664 jason i++; 2686 9664 jason } 2687 9664 jason } 2688 9664 jason 2689 9664 jason time_fmt_old = old_save; 2690 9664 jason time_fmt_new = new_save; 2691 9664 jason } 2692 9664 jason 2693 9664 jason /* 2694 9664 jason * Check if color definition applies to entry, returns 1 if yes, 0 if no 2695 9664 jason */ 2696 9664 jason static int 2697 10059 jason color_match(const char *fname, mode_t mode, ls_color_t *color) 2698 9664 jason { 2699 9664 jason switch (color->ftype) { 2700 9664 jason case LS_PAT: 2701 9664 jason { 2702 9664 jason size_t fname_len, sfx_len; 2703 9664 jason 2704 9664 jason fname_len = strlen(fname); 2705 9664 jason sfx_len = strlen(color->sfx); 2706 9664 jason if (sfx_len > fname_len) 2707 9664 jason return (0); 2708 9664 jason 2709 9664 jason if (strcmp(color->sfx, fname + fname_len - sfx_len) == 0) 2710 9664 jason return (1); 2711 9664 jason else 2712 9664 jason return (0); 2713 9664 jason } 2714 9664 jason 2715 9664 jason case LS_NORMAL: 2716 9664 jason return (1); 2717 9664 jason 2718 9664 jason case LS_FILE: 2719 10059 jason return (S_ISREG(mode)); 2720 9664 jason 2721 9664 jason case LS_DIR: 2722 10059 jason return (S_ISDIR(mode)); 2723 9664 jason 2724 9664 jason case LS_LINK: 2725 10059 jason return (S_ISLNK(mode)); 2726 9664 jason 2727 9664 jason case LS_FIFO: 2728 10059 jason return (S_ISFIFO(mode)); 2729 9664 jason 2730 9664 jason case LS_SOCK: 2731 10059 jason return (S_ISSOCK(mode)); 2732 9664 jason 2733 9664 jason case LS_DOOR: 2734 10059 jason return (S_ISDOOR(mode)); 2735 9664 jason 2736 9664 jason case LS_BLK: 2737 10059 jason return (S_ISBLK(mode)); 2738 9664 jason 2739 9664 jason case LS_CHR: 2740 10059 jason return (S_ISCHR(mode)); 2741 9664 jason 2742 9664 jason case LS_PORT: 2743 10059 jason return (S_ISPORT(mode)); 2744 9664 jason 2745 9664 jason case LS_ORPHAN: 2746 10059 jason /* this is tested for by gstat */ 2747 9664 jason return (0); 2748 9664 jason 2749 9664 jason case LS_SETUID: 2750 10059 jason return (!S_ISLNK(mode) && (mode & S_ISUID)); 2751 9664 jason 2752 9664 jason case LS_SETGID: 2753 10059 jason return (!S_ISLNK(mode) && (mode & S_ISGID)); 2754 9664 jason 2755 9664 jason case LS_STICKY_OTHER_WRITABLE: 2756 10059 jason return (!S_ISLNK(mode) && (mode & (S_IWOTH|S_ISVTX))); 2757 9664 jason 2758 9664 jason case LS_OTHER_WRITABLE: 2759 10059 jason return (!S_ISLNK(mode) && (mode & S_IWOTH)); 2760 9664 jason 2761 9664 jason case LS_STICKY: 2762 10059 jason return (!S_ISLNK(mode) && (mode & S_ISVTX)); 2763 9664 jason 2764 9664 jason case LS_EXEC: 2765 10059 jason return (!S_ISLNK(mode) && (mode & (S_IXUSR|S_IXGRP|S_IXOTH))); 2766 9664 jason } 2767 9664 jason 2768 9664 jason return (0); 2769 9664 jason } 2770 9664 jason 2771 9664 jason static void 2772 9664 jason dump_color(ls_color_t *c) 2773 9664 jason { 2774 9664 jason if (c == NULL) 2775 9664 jason return; 2776 9664 jason 2777 9664 jason (void) printf("\n\ttype: "); 2778 9664 jason switch (c->ftype) { 2779 9664 jason case LS_NORMAL: 2780 9664 jason (void) printf("LS_NORMAL"); 2781 9664 jason break; 2782 9664 jason case LS_FILE: 2783 9664 jason (void) printf("LS_FILE"); 2784 9664 jason break; 2785 9664 jason case LS_EXEC: 2786 9664 jason (void) printf("LS_EXEC"); 2787 9664 jason break; 2788 9664 jason case LS_DIR: 2789 9664 jason (void) printf("LS_DIR"); 2790 9664 jason break; 2791 9664 jason case LS_LINK: 2792 9664 jason (void) printf("LS_LINK"); 2793 9664 jason break; 2794 9664 jason 2795 9664 jason case LS_FIFO: 2796 9664 jason (void) printf("LS_FIFO"); 2797 9664 jason break; 2798 9664 jason 2799 9664 jason case LS_SOCK: 2800 9664 jason (void) printf("LS_SOCK"); 2801 9664 jason break; 2802 9664 jason 2803 9664 jason case LS_DOOR: 2804 9664 jason (void) printf("LS_DOOR"); 2805 9664 jason break; 2806 9664 jason 2807 9664 jason case LS_BLK: 2808 9664 jason (void) printf("LS_BLK"); 2809 9664 jason break; 2810 9664 jason 2811 9664 jason case LS_CHR: 2812 9664 jason (void) printf("LS_CHR"); 2813 9664 jason break; 2814 9664 jason 2815 9664 jason case LS_PORT: 2816 9664 jason (void) printf("LS_PORT"); 2817 9664 jason break; 2818 9664 jason 2819 9664 jason case LS_STICKY: 2820 9664 jason (void) printf("LS_STICKY"); 2821 9664 jason break; 2822 9664 jason 2823 9664 jason case LS_ORPHAN: 2824 9664 jason (void) printf("LS_ORPHAN"); 2825 9664 jason break; 2826 9664 jason 2827 9664 jason case LS_SETGID: 2828 9664 jason (void) printf("LS_SETGID"); 2829 9664 jason break; 2830 9664 jason 2831 9664 jason case LS_SETUID: 2832 9664 jason (void) printf("LS_SETUID"); 2833 9664 jason break; 2834 9664 jason 2835 9664 jason case LS_OTHER_WRITABLE: 2836 9664 jason (void) printf("LS_OTHER_WRITABLE"); 2837 9664 jason break; 2838 9664 jason 2839 9664 jason case LS_STICKY_OTHER_WRITABLE: 2840 9664 jason (void) printf("LS_STICKY_OTHER_WRITABLE"); 2841 9664 jason break; 2842 9664 jason 2843 9664 jason case LS_PAT: 2844 9664 jason (void) printf("LS_PAT\n"); 2845 9664 jason (void) printf("\tpattern: %s", c->sfx); 2846 9664 jason break; 2847 9664 jason } 2848 9664 jason (void) printf("\n"); 2849 9664 jason (void) printf("\tattr: %d\n", c->attr); 2850 9664 jason (void) printf("\tfg: %d\n", c->fg); 2851 9664 jason (void) printf("\tbg: %d\n", c->bg); 2852 9664 jason (void) printf("\t"); 2853 9664 jason } 2854 9664 jason 2855 9664 jason static ls_color_t * 2856 10059 jason ls_color_find(const char *fname, mode_t mode) 2857 9664 jason { 2858 9664 jason int i; 2859 9664 jason 2860 9664 jason /* 2861 9664 jason * Colors are sorted from most general lsc_colors[0] to most specific 2862 9664 jason * lsc_colors[lsc_ncolors - 1] by ls_color_init(). Start search with 2863 9664 jason * most specific color rule and work towards most general. 2864 9664 jason */ 2865 9664 jason for (i = lsc_ncolors - 1; i >= 0; --i) 2866 10059 jason if (color_match(fname, mode, &lsc_colors[i])) 2867 9664 jason return (&lsc_colors[i]); 2868 9664 jason 2869 9664 jason return (NULL); 2870 9664 jason } 2871 9664 jason 2872 9664 jason static void 2873 9664 jason ls_tprint(char *str, long int p1, long int p2, long int p3, long int p4, 2874 9664 jason long int p5, long int p6, long int p7, long int p8, long int p9) 2875 9664 jason { 2876 9664 jason char *s; 2877 9664 jason 2878 9664 jason if (str == NULL) 2879 9664 jason return; 2880 9664 jason 2881 9664 jason s = tparm(str, p1, p2, p3, p4, p5, p6, p7, p8, p9); 2882 9664 jason 2883 9664 jason if (s != NULL) 2884 9664 jason (void) putp(s); 2885 9664 jason } 2886 9664 jason 2887 9664 jason static void 2888 10059 jason ls_start_color(ls_color_t *c) 2889 9664 jason { 2890 9664 jason if (c == NULL) 2891 9664 jason return; 2892 9664 jason 2893 9664 jason if (lsc_debug) 2894 9664 jason lsc_match = c; 2895 9664 jason 2896 9664 jason if (c->attr & LSA_BOLD) 2897 9664 jason ls_tprint(lsc_bold, 0, 0, 0, 0, 0, 0, 0, 0, 0); 2898 9664 jason if (c->attr & LSA_UNDERSCORE) 2899 9664 jason ls_tprint(lsc_underline, 0, 0, 0, 0, 0, 0, 0, 0, 0); 2900 9664 jason if (c->attr & LSA_BLINK) 2901 9664 jason ls_tprint(lsc_blink, 0, 0, 0, 0, 0, 0, 0, 0, 0); 2902 9664 jason if (c->attr & LSA_REVERSE) 2903 9664 jason ls_tprint(lsc_reverse, 0, 0, 0, 0, 0, 0, 0, 0, 0); 2904 9664 jason if (c->attr & LSA_CONCEALED) 2905 9664 jason ls_tprint(lsc_concealed, 0, 0, 0, 0, 0, 0, 0, 0, 0); 2906 9664 jason if (c->attr == LSA_NONE) 2907 9664 jason ls_tprint(lsc_none, 0, 0, 0, 0, 0, 0, 0, 0, 0); 2908 9664 jason 2909 9664 jason if (c->fg != -1) 2910 9664 jason ls_tprint(lsc_setfg, c->fg, 0, 0, 0, 0, 0, 0, 0, 0); 2911 9664 jason if (c->bg != -1) 2912 9664 jason ls_tprint(lsc_setbg, c->bg, 0, 0, 0, 0, 0, 0, 0, 0); 2913 9664 jason } 2914 9664 jason 2915 9664 jason static void 2916 9664 jason ls_end_color() 2917 9664 jason { 2918 9664 jason ls_tprint(lsc_none, 0, 0, 0, 0, 0, 0, 0, 0, 0); 2919 9664 jason if (lsc_debug) 2920 9664 jason dump_color(lsc_match); 2921 9664 jason } 2922 9664 jason 2923 9664 jason static void 2924 9664 jason new_color_entry(char *colorstr) 2925 9664 jason { 2926 9664 jason static const struct { 2927 9664 jason const char *s; 2928 9664 jason ls_cftype_t stype; 2929 9664 jason } type_map[] = { 2930 9664 jason { "no", LS_NORMAL }, 2931 9664 jason { "fi", LS_FILE }, 2932 9664 jason { "di", LS_DIR }, 2933 9664 jason { "ln", LS_LINK }, 2934 9664 jason { "pi", LS_FIFO }, 2935 9664 jason { "so", LS_SOCK }, 2936 9664 jason { "do", LS_DOOR }, 2937 9664 jason { "bd", LS_BLK }, 2938 9664 jason { "cd", LS_CHR }, 2939 9664 jason { "or", LS_ORPHAN }, 2940 9664 jason { "su", LS_SETUID }, 2941 9664 jason { "sg", LS_SETGID }, 2942 9664 jason { "tw", LS_STICKY_OTHER_WRITABLE }, 2943 9664 jason { "ow", LS_OTHER_WRITABLE }, 2944 9664 jason { "st", LS_STICKY }, 2945 9664 jason { "ex", LS_EXEC }, 2946 9664 jason { "po", LS_PORT }, 2947 9664 jason { NULL, LS_NORMAL } 2948 9664 jason }; 2949 9664 jason 2950 9664 jason char *p, *lasts; 2951 9664 jason int i; 2952 9664 jason int color, attr; 2953 9664 jason 2954 9664 jason p = strtok_r(colorstr, "=", &lasts); 2955 9664 jason if (p == NULL) { 2956 9664 jason colorflg = 0; 2957 9664 jason return; 2958 9664 jason } 2959 9664 jason 2960 9664 jason if (p[0] == '*') { 2961 9664 jason lsc_colors[lsc_ncolors].ftype = LS_PAT; 2962 9664 jason /* don't include the * in the suffix */ 2963 9664 jason if ((lsc_colors[lsc_ncolors].sfx = strdup(p + 1)) == NULL) { 2964 9664 jason colorflg = 0; 2965 9664 jason return; 2966 9664 jason } 2967 9664 jason } else { 2968 9664 jason lsc_colors[lsc_ncolors].sfx = NULL; 2969 9664 jason 2970 9664 jason for (i = 0; type_map[i].s != NULL; ++i) { 2971 9664 jason if (strncmp(type_map[i].s, p, 2) == 0) 2972 9664 jason break; 2973 9664 jason } 2974 9664 jason 2975 9664 jason /* ignore unknown file types */ 2976 9664 jason if (type_map[i].s == NULL) 2977 9664 jason return; 2978 9664 jason 2979 9664 jason lsc_colors[lsc_ncolors].ftype = type_map[i].stype; 2980 9664 jason } 2981 9664 jason 2982 9664 jason attr = LSA_NONE; 2983 9664 jason lsc_colors[lsc_ncolors].fg = -1; 2984 9664 jason lsc_colors[lsc_ncolors].bg = -1; 2985 9664 jason for (p = strtok_r(NULL, ";", &lasts); p != NULL; 2986 9664 jason p = strtok_r(NULL, ";", &lasts)) { 2987 9664 jason color = strtol(p, NULL, 10); 2988 9664 jason 2989 9664 jason if (color < 10) { 2990 9664 jason switch (color) { 2991 9664 jason case 0: 2992 9664 jason attr = LSA_NONE; 2993 9664 jason continue; 2994 9664 jason case 1: 2995 9664 jason attr |= LSA_BOLD; 2996 9664 jason continue; 2997 9664 jason case 4: 2998 9664 jason attr |= LSA_UNDERSCORE; 2999 9664 jason continue; 3000 9664 jason case 5: 3001 9664 jason attr |= LSA_BLINK; 3002 9664 jason continue; 3003 9664 jason case 7: 3004 9664 jason attr |= LSA_REVERSE; 3005 9664 jason continue; 3006 9664 jason case 8: 3007 9664 jason attr |= LSA_CONCEALED; 3008 9664 jason continue; 3009 9664 jason default: 3010 9664 jason continue; 3011 5331 amw } 3012 5331 amw } 3013 9664 jason 3014 9664 jason if (color < 40) 3015 9664 jason lsc_colors[lsc_ncolors].fg = color - 30; 3016 9664 jason else 3017 9664 jason lsc_colors[lsc_ncolors].bg = color - 40; 3018 9664 jason } 3019 9664 jason 3020 9664 jason lsc_colors[lsc_ncolors].attr = attr; 3021 9664 jason ++lsc_ncolors; 3022 9664 jason } 3023 9664 jason 3024 9664 jason static int 3025 9664 jason ls_color_compare(const void *p1, const void *p2) 3026 9664 jason { 3027 9664 jason const ls_color_t *c1 = (const ls_color_t *)p1; 3028 9664 jason const ls_color_t *c2 = (const ls_color_t *)p2; 3029 9664 jason 3030 9664 jason int ret = c1->ftype - c2->ftype; 3031 9664 jason 3032 9664 jason if (ret != 0) 3033 9664 jason return (ret); 3034 9664 jason 3035 9664 jason if (c1->ftype != LS_PAT) 3036 9664 jason return (ret); 3037 9664 jason 3038 9664 jason return (strcmp(c1->sfx, c2->sfx)); 3039 9664 jason } 3040 9664 jason 3041 9664 jason static void 3042 9664 jason ls_color_init() 3043 9664 jason { 3044 9664 jason static char *default_colorstr = "no=00:fi=00:di=01;34:ln=01;36:po=01;35" 3045 9664 jason ":pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01" 3046 9664 jason ":su=37;41:sg=30;43:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31" 3047 9664 jason ":*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31" 3048 9664 jason ":*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.deb=01;31" 3049 9664 jason ":*.rpm=01;31:*.jar=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35" 3050 9664 jason ":*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35" 3051 9664 jason ":*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35" 3052 9664 jason ":*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.avi=01;35:*.fli=01;35" 3053 9664 jason ":*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.flac=01;35" 3054 9664 jason ":*.mp3=01;35:*.mpc=01;35:*.ogg=01;35:*.wav=01;35"; 3055 9664 jason 3056 9664 jason char *colorstr; 3057 9664 jason char *p, *lasts; 3058 9664 jason size_t color_sz; 3059 9664 jason int termret; 3060 10059 jason int i; 3061 9664 jason 3062 9664 jason (void) setupterm(NULL, 1, &termret); 3063 9664 jason if (termret != 1) 3064 9664 jason return; 3065 9664 jason 3066 9664 jason if ((colorstr = getenv("LS_COLORS")) == NULL) 3067 9664 jason colorstr = default_colorstr; 3068 9664 jason 3069 9689 jason /* 3070 9689 jason * Determine the size of lsc_colors. color_sz can be > lsc_ncolors 3071 9689 jason * if there are invalid entries passed in the string (they are ignored) 3072 9689 jason */ 3073 9689 jason color_sz = 1; 3074 9664 jason for (p = strchr(colorstr, ':'); p != NULL && *p != '\0'; 3075 9664 jason p = strchr(++p, ':')) 3076 9664 jason ++color_sz; 3077 9664 jason 3078 9664 jason lsc_colors = calloc(color_sz, sizeof (ls_color_t)); 3079 9664 jason if (lsc_colors == NULL) { 3080 9664 jason free(colorstr); 3081 9664 jason return; 3082 9664 jason } 3083 9664 jason 3084 9664 jason for (p = strtok_r(colorstr, ":", &lasts); 3085 9664 jason p != NULL && lsc_ncolors < color_sz; 3086 9664 jason p = strtok_r(NULL, ":", &lasts)) 3087 9664 jason new_color_entry(p); 3088 9664 jason 3089 9664 jason qsort((void *)lsc_colors, lsc_ncolors, sizeof (ls_color_t), 3090 9664 jason ls_color_compare); 3091 10059 jason 3092 10059 jason for (i = 0; i < lsc_ncolors; ++i) 3093 10059 jason if (lsc_colors[i].ftype == LS_ORPHAN) { 3094 10059 jason lsc_orphan = &lsc_colors[i]; 3095 10059 jason break; 3096 10059 jason } 3097 9664 jason 3098 9664 jason if ((lsc_bold = tigetstr("bold")) == (char *)-1) 3099 9664 jason lsc_bold = NULL; 3100 9664 jason 3101 9664 jason if ((lsc_underline = tigetstr("smul")) == (char *)-1) 3102 9664 jason lsc_underline = NULL; 3103 9664 jason 3104 9664 jason if ((lsc_blink = tigetstr("blink")) == (char *)-1) 3105 9664 jason lsc_blink = NULL; 3106 9664 jason 3107 9664 jason if ((lsc_reverse = tigetstr("rev")) == (char *)-1) 3108 9664 jason lsc_reverse = NULL; 3109 9664 jason 3110 9664 jason if ((lsc_concealed = tigetstr("prot")) == (char *)-1) 3111 9664 jason lsc_concealed = NULL; 3112 9664 jason 3113 9664 jason if ((lsc_none = tigetstr("sgr0")) == (char *)-1) 3114 9664 jason lsc_none = NULL; 3115 9664 jason 3116 9664 jason if ((lsc_setfg = tigetstr("setaf")) == (char *)-1) 3117 9664 jason lsc_setfg = NULL; 3118 9664 jason 3119 9664 jason if ((lsc_setbg = tigetstr("setab")) == (char *)-1) 3120 9664 jason lsc_setbg = NULL; 3121 9664 jason 3122 9664 jason if (getenv("_LS_COLOR_DEBUG") != NULL) { 3123 9664 jason int i; 3124 9664 jason 3125 9664 jason lsc_debug = 1; 3126 9664 jason for (i = 0; i < lsc_ncolors; ++i) 3127 9664 jason dump_color(&lsc_colors[i]); 3128 5331 amw } 3129 5331 amw } 3130 5331 amw 3131 5331 amw /* Free extended system attribute lists */ 3132 5331 amw 3133 5331 amw void 3134 5331 amw free_sysattr(struct lbuf *p) 3135 5331 amw { 3136 5331 amw int i; 3137 5331 amw 3138 5331 amw if (p->exttr != NULL) { 3139 5331 amw for (i = 0; i < sacnt; i++) { 3140 5331 amw if (p->exttr[i].name != NULL) 3141 5331 amw free(p->exttr[i].name); 3142 5331 amw } 3143 5331 amw free(p->exttr); 3144 5331 amw } 3145 5331 amw if (p->extm != NULL) { 3146 5331 amw for (i = 0; i < sacnt; i++) { 3147 5331 amw if (p->extm[i].name != NULL) 3148 5331 amw free(p->extm[i].name); 3149 5331 amw } 3150 5331 amw free(p->extm); 3151 5331 amw } 3152 5331 amw } 3153 5331 amw 3154 5331 amw /* Allocate extended system attribute list */ 3155 5331 amw 3156 5331 amw void * 3157 5331 amw xmalloc(size_t size, struct lbuf *p) 3158 5331 amw { 3159 5331 amw if ((p = malloc(size)) == NULL) { 3160 5331 amw perror("ls"); 3161 5331 amw free_sysattr(p); 3162 5331 amw nvlist_free(response); 3163 5331 amw exit(2); 3164 5331 amw } 3165 5331 amw return (p); 3166 5331 amw } 3167