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