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