file_cmds-321.100.10.0.1.tar.gz
[apple/file_cmds.git] / ls / print.c
1 /*
2 * Copyright (c) 1989, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Michael Fischbein.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37 #if 0
38 #ifndef lint
39 static char sccsid[] = "@(#)print.c 8.4 (Berkeley) 4/17/94";
40 #endif /* not lint */
41 #endif
42 #include <sys/cdefs.h>
43 __RCSID("$FreeBSD: src/bin/ls/print.c,v 1.57 2002/08/29 14:29:09 keramida Exp $");
44
45 #include <sys/param.h>
46 #include <sys/stat.h>
47 #ifdef __APPLE__
48 #include <sys/acl.h>
49 #include <sys/xattr.h>
50 #include <sys/types.h>
51 #include <grp.h>
52 #include <pwd.h>
53 #include <TargetConditionals.h>
54 #include <membership.h>
55 #include <membershipPriv.h>
56 #include <uuid/uuid.h>
57 #endif
58
59 #include <err.h>
60 #include <errno.h>
61 #include <fts.h>
62 #include <math.h>
63 #include <langinfo.h>
64 #include <libutil.h>
65 #include <stdio.h>
66 #include <stdlib.h>
67 #include <string.h>
68 #include <time.h>
69 #include <unistd.h>
70 #ifdef COLORLS
71 #include <ctype.h>
72 #include <termcap.h>
73 #include <signal.h>
74 #endif
75 #include <stdint.h> /* intmax_t */
76 #include <assert.h>
77 #ifdef __APPLE__
78 #include <get_compat.h>
79 #else
80 #define COMPAT_MODE(a,b) (1)
81 #endif /* __APPLE__ */
82
83 #include "ls.h"
84 #include "extern.h"
85
86 static int printaname(FTSENT *, u_long, u_long);
87 static void printlink(FTSENT *);
88 static void printtime(time_t);
89 static int printtype(u_int);
90 static void printsize(size_t, off_t);
91 #ifdef COLORLS
92 static void endcolor(int);
93 static int colortype(mode_t);
94 #endif
95
96 #define IS_NOPRINT(p) ((p)->fts_number == NO_PRINT)
97
98 #ifdef COLORLS
99 /* Most of these are taken from <sys/stat.h> */
100 typedef enum Colors {
101 C_DIR, /* directory */
102 C_LNK, /* symbolic link */
103 C_SOCK, /* socket */
104 C_FIFO, /* pipe */
105 C_EXEC, /* executable */
106 C_BLK, /* block special */
107 C_CHR, /* character special */
108 C_SUID, /* setuid executable */
109 C_SGID, /* setgid executable */
110 C_WSDIR, /* directory writeble to others, with sticky
111 * bit */
112 C_WDIR, /* directory writeble to others, without
113 * sticky bit */
114 C_NUMCOLORS /* just a place-holder */
115 } Colors;
116
117 static const char *defcolors = "exfxcxdxbxegedabagacad";
118
119 /* colors for file types */
120 static struct {
121 int num[2];
122 int bold;
123 } colors[C_NUMCOLORS];
124 #endif
125
126 void
127 printscol(DISPLAY *dp)
128 {
129 FTSENT *p;
130
131 assert(dp);
132 if (COMPAT_MODE("bin/ls", "Unix2003") && (dp->list != NULL)) {
133 if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
134 (void)printf("total %qu\n", (u_int64_t)howmany(dp->btotal, blocksize));
135 }
136
137 for (p = dp->list; p; p = p->fts_link) {
138 if (IS_NOPRINT(p))
139 continue;
140 (void)printaname(p, dp->s_inode, dp->s_block);
141 (void)putchar('\n');
142 }
143 }
144
145 /*
146 * print name in current style
147 */
148 static int
149 printname(const char *name)
150 {
151 if (f_octal || f_octal_escape)
152 return prn_octal(name);
153 else if (f_nonprint)
154 return prn_printable(name);
155 else
156 return prn_normal(name);
157 }
158
159 /*
160 * print access control list
161 */
162 static struct {
163 acl_perm_t perm;
164 char *name;
165 int flags;
166 #define ACL_PERM_DIR (1<<0)
167 #define ACL_PERM_FILE (1<<1)
168 } acl_perms[] = {
169 {ACL_READ_DATA, "read", ACL_PERM_FILE},
170 {ACL_LIST_DIRECTORY, "list", ACL_PERM_DIR},
171 {ACL_WRITE_DATA, "write", ACL_PERM_FILE},
172 {ACL_ADD_FILE, "add_file", ACL_PERM_DIR},
173 {ACL_EXECUTE, "execute", ACL_PERM_FILE},
174 {ACL_SEARCH, "search", ACL_PERM_DIR},
175 {ACL_DELETE, "delete", ACL_PERM_FILE | ACL_PERM_DIR},
176 {ACL_APPEND_DATA, "append", ACL_PERM_FILE},
177 {ACL_ADD_SUBDIRECTORY, "add_subdirectory", ACL_PERM_DIR},
178 {ACL_DELETE_CHILD, "delete_child", ACL_PERM_DIR},
179 {ACL_READ_ATTRIBUTES, "readattr", ACL_PERM_FILE | ACL_PERM_DIR},
180 {ACL_WRITE_ATTRIBUTES, "writeattr", ACL_PERM_FILE | ACL_PERM_DIR},
181 {ACL_READ_EXTATTRIBUTES, "readextattr", ACL_PERM_FILE | ACL_PERM_DIR},
182 {ACL_WRITE_EXTATTRIBUTES, "writeextattr", ACL_PERM_FILE | ACL_PERM_DIR},
183 {ACL_READ_SECURITY, "readsecurity", ACL_PERM_FILE | ACL_PERM_DIR},
184 {ACL_WRITE_SECURITY, "writesecurity", ACL_PERM_FILE | ACL_PERM_DIR},
185 {ACL_CHANGE_OWNER, "chown", ACL_PERM_FILE | ACL_PERM_DIR},
186 {0, NULL, 0}
187 };
188
189 static struct {
190 acl_flag_t flag;
191 char *name;
192 int flags;
193 } acl_flags[] = {
194 {ACL_ENTRY_FILE_INHERIT, "file_inherit", ACL_PERM_DIR},
195 {ACL_ENTRY_DIRECTORY_INHERIT, "directory_inherit", ACL_PERM_DIR},
196 {ACL_ENTRY_LIMIT_INHERIT, "limit_inherit", ACL_PERM_FILE | ACL_PERM_DIR},
197 {ACL_ENTRY_ONLY_INHERIT, "only_inherit", ACL_PERM_DIR},
198 {0, NULL, 0}
199 };
200
201 static char *
202 uuid_to_name(uuid_t *uu)
203 {
204 int type;
205 char *name = NULL;
206 char *recname = NULL;
207
208 #define MAXNAMETAG (MAXLOGNAME + 6) /* + strlen("group:") */
209 name = (char *) malloc(MAXNAMETAG);
210
211 if (NULL == name) {
212 err(1, "malloc");
213 }
214
215 if (f_numericonly) {
216 goto errout;
217 }
218
219 if (mbr_identifier_translate(ID_TYPE_UUID, *uu, sizeof(*uu), ID_TYPE_NAME, (void **) &recname, &type)) {
220 goto errout;
221 }
222
223 snprintf(name, MAXNAMETAG, "%s:%s", (type == MBR_REC_TYPE_USER ? "user" : "group"), recname);
224 free(recname);
225
226 return name;
227 errout:
228 uuid_unparse_upper(*uu, name);
229
230 return name;
231 }
232
233 static void
234 printxattr(DISPLAY *dp, int count, char *buf, int sizes[])
235 {
236 for (int i = 0; i < count; i++) {
237 putchar('\t');
238 printname(buf);
239 putchar('\t');
240 printsize(dp->s_size, sizes[i]);
241 putchar('\n');
242 buf += strlen(buf) + 1;
243 }
244 }
245
246 static void
247 printacl(acl_t acl, int isdir)
248 {
249 acl_entry_t entry = NULL;
250 int index;
251 uuid_t *applicable;
252 char *name = NULL;
253 acl_tag_t tag;
254 acl_flagset_t flags;
255 acl_permset_t perms;
256 char *type;
257 int i, first;
258
259
260 for (index = 0;
261 acl_get_entry(acl, entry == NULL ? ACL_FIRST_ENTRY : ACL_NEXT_ENTRY, &entry) == 0;
262 index++) {
263 if (acl_get_tag_type(entry, &tag) != 0)
264 continue;
265 if (acl_get_flagset_np(entry, &flags) != 0)
266 continue;
267 if (acl_get_permset(entry, &perms) != 0)
268 continue;
269 if ((applicable = (uuid_t *) acl_get_qualifier(entry)) == NULL)
270 continue;
271 name = uuid_to_name(applicable);
272 acl_free(applicable);
273 switch(tag) {
274 case ACL_EXTENDED_ALLOW:
275 type = "allow";
276 break;
277 case ACL_EXTENDED_DENY:
278 type = "deny";
279 break;
280 default:
281 type = "unknown";
282 }
283
284 (void)printf(" %d: %s%s %s ",
285 index,
286 name,
287 acl_get_flag_np(flags, ACL_ENTRY_INHERITED) ? " inherited" : "",
288 type);
289
290 if (name)
291 free(name);
292
293 for (i = 0, first = 0; acl_perms[i].name != NULL; i++) {
294 if (acl_get_perm_np(perms, acl_perms[i].perm) == 0)
295 continue;
296 if (!(acl_perms[i].flags & (isdir ? ACL_PERM_DIR : ACL_PERM_FILE)))
297 continue;
298 (void)printf("%s%s", first++ ? "," : "", acl_perms[i].name);
299 }
300 for (i = 0; acl_flags[i].name != NULL; i++) {
301 if (acl_get_flag_np(flags, acl_flags[i].flag) == 0)
302 continue;
303 if (!(acl_flags[i].flags & (isdir ? ACL_PERM_DIR : ACL_PERM_FILE)))
304 continue;
305 (void)printf("%s%s", first++ ? "," : "", acl_flags[i].name);
306 }
307
308 (void)putchar('\n');
309 }
310
311 }
312
313 void
314 printlong(DISPLAY *dp)
315 {
316 struct stat *sp;
317 FTSENT *p;
318 NAMES *np;
319 char buf[20];
320 #ifdef COLORLS
321 int color_printed = 0;
322 #endif
323
324 if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
325 (void)printf("total %qu\n", (u_int64_t)howmany(dp->btotal, blocksize));
326
327 for (p = dp->list; p; p = p->fts_link) {
328 if (IS_NOPRINT(p))
329 continue;
330 sp = p->fts_statp;
331 if (f_inode)
332 #if _DARWIN_FEATURE_64_BIT_INODE
333 (void)printf("%*llu ", dp->s_inode, (u_quad_t)sp->st_ino);
334 #else
335 (void)printf("%*lu ", dp->s_inode, (u_long)sp->st_ino);
336 #endif
337 if (f_size)
338 (void)printf("%*qu ",
339 dp->s_block, (u_int64_t)howmany(sp->st_blocks, blocksize));
340 strmode(sp->st_mode, buf);
341 np = p->fts_pointer;
342 #ifdef __APPLE__
343 buf[10] = '\0'; /* make +/@ abut the mode */
344 char str[2] = { np->mode_suffix, '\0' };
345 #endif /* __APPLE__ */
346 if (f_group && f_owner) { /* means print neither */
347 #ifdef __APPLE__
348 (void)printf("%s%s %*u ", buf, str, dp->s_nlink,
349 sp->st_nlink);
350 #else /* ! __APPLE__ */
351 (void)printf("%s %*u ", buf, dp->s_nlink,
352 sp->st_nlink);
353 #endif /* __APPLE__ */
354 }
355 else if (f_group) {
356 #ifdef __APPLE__
357 (void)printf("%s%s %*u %-*s ", buf, str, dp->s_nlink,
358 sp->st_nlink, dp->s_group, np->group);
359 #else /* ! __APPLE__ */
360 (void)printf("%s %*u %-*s ", buf, dp->s_nlink,
361 sp->st_nlink, dp->s_group, np->group);
362 #endif /* __APPLE__ */
363 }
364 else if (f_owner) {
365 #ifdef __APPLE__
366 (void)printf("%s%s %*u %-*s ", buf, str, dp->s_nlink,
367 sp->st_nlink, dp->s_user, np->user);
368 #else /* ! __APPLE__ */
369 (void)printf("%s %*u %-*s ", buf, dp->s_nlink,
370 sp->st_nlink, dp->s_user, np->user);
371 #endif /* __APPLE__ */
372 }
373 else {
374 #ifdef __APPLE__
375 (void)printf("%s%s %*u %-*s %-*s ", buf, str, dp->s_nlink,
376 sp->st_nlink, dp->s_user, np->user, dp->s_group,
377 np->group);
378 #else /* ! __APPLE__ */
379 (void)printf("%s %*u %-*s %-*s ", buf, dp->s_nlink,
380 sp->st_nlink, dp->s_user, np->user, dp->s_group,
381 np->group);
382 #endif /* ! __APPLE__ */
383 }
384 if (f_flags)
385 (void)printf("%-*s ", dp->s_flags, np->flags);
386 if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode))
387 if (minor(sp->st_rdev) > 255 || minor(sp->st_rdev) < 0)
388 (void)printf("%3d, 0x%08x ",
389 major(sp->st_rdev),
390 (u_int)minor(sp->st_rdev));
391 else
392 (void)printf("%3d, %3d ",
393 major(sp->st_rdev), minor(sp->st_rdev));
394 else if (dp->bcfile)
395 (void)printf("%*s%*qu ",
396 8 - dp->s_size, "", dp->s_size, (u_int64_t)sp->st_size);
397 else
398 printsize(dp->s_size, sp->st_size);
399 if (f_accesstime)
400 printtime(sp->st_atime);
401 else if (f_statustime)
402 printtime(sp->st_ctime);
403 else if (f_birthtime)
404 printtime(sp->st_birthtime);
405 else
406 printtime(sp->st_mtime);
407 #ifdef COLORLS
408 if (f_color)
409 color_printed = colortype(sp->st_mode);
410 #endif
411 (void)printname(p->fts_name);
412 #ifdef COLORLS
413 if (f_color && color_printed)
414 endcolor(0);
415 #endif
416 if (f_type)
417 (void)printtype(sp->st_mode);
418 if (S_ISLNK(sp->st_mode))
419 printlink(p);
420 (void)putchar('\n');
421 #ifdef __APPLE__
422 if (np->xattr_count && f_xattr) {
423 printxattr(dp, np->xattr_count, np->xattr_names, np->xattr_sizes);
424 }
425 if (np->acl != NULL && f_acl) {
426 printacl(np->acl, S_ISDIR(sp->st_mode));
427 }
428 #endif /* __APPLE__ */
429 }
430 }
431
432 void
433 printstream(DISPLAY *dp)
434 {
435 FTSENT *p;
436 extern int termwidth;
437 int chcnt;
438
439 for (p = dp->list, chcnt = 0; p; p = p->fts_link) {
440 if (p->fts_number == NO_PRINT)
441 continue;
442 if (strlen(p->fts_name) + chcnt +
443 (p->fts_link ? 2 : 0) >= (unsigned)termwidth) {
444 putchar('\n');
445 chcnt = 0;
446 }
447 chcnt += printaname(p, dp->s_inode, dp->s_block);
448 if (p->fts_link) {
449 printf(", ");
450 chcnt += 2;
451 }
452 }
453 if (chcnt)
454 putchar('\n');
455 }
456
457 void
458 printcol(DISPLAY *dp)
459 {
460 extern int termwidth;
461 static FTSENT **array;
462 static int lastentries = -1;
463 FTSENT *p;
464 int base;
465 int chcnt;
466 int cnt;
467 int col;
468 int colwidth;
469 int endcol;
470 int num;
471 int numcols;
472 int numrows;
473 int row;
474 int tabwidth;
475
476 if (f_notabs)
477 tabwidth = 1;
478 else
479 tabwidth = 8;
480
481 /*
482 * Have to do random access in the linked list -- build a table
483 * of pointers.
484 */
485 if ((lastentries == -1) || (dp->entries > lastentries)) {
486 lastentries = dp->entries;
487 if ((array = realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) {
488 warn(NULL);
489 printscol(dp);
490 return;
491 }
492 }
493 memset(array, 0, dp->entries * sizeof(FTSENT *));
494 for (p = dp->list, num = 0; p; p = p->fts_link)
495 if (p->fts_number != NO_PRINT)
496 array[num++] = p;
497
498 colwidth = dp->maxlen;
499 if (f_inode)
500 colwidth += dp->s_inode + 1;
501 if (f_size)
502 colwidth += dp->s_block + 1;
503 if (f_type)
504 colwidth += 1;
505
506 colwidth = (colwidth + tabwidth) & ~(tabwidth - 1);
507 if (termwidth < 2 * colwidth) {
508 printscol(dp);
509 return;
510 }
511 numcols = termwidth / colwidth;
512 numrows = num / numcols;
513 if (num % numcols)
514 ++numrows;
515
516 assert(dp->list);
517 if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
518 (void)printf("total %qu\n", (u_int64_t)howmany(dp->btotal, blocksize));
519
520 base = 0;
521 for (row = 0; row < numrows; ++row) {
522 endcol = colwidth;
523 if (!f_sortacross)
524 base = row;
525 for (col = 0, chcnt = 0; col < numcols; ++col) {
526 assert(base < dp->entries);
527 chcnt += printaname(array[base], dp->s_inode, dp->s_block);
528 if (f_sortacross)
529 base++;
530 else
531 base += numrows;
532 if (base >= num)
533 break;
534 while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1)))
535 <= endcol) {
536 if (f_sortacross && col + 1 >= numcols)
537 break;
538 (void)putchar(f_notabs ? ' ' : '\t');
539 chcnt = cnt;
540 }
541 endcol += colwidth;
542 }
543 (void)putchar('\n');
544 }
545 }
546
547 /*
548 * print [inode] [size] name
549 * return # of characters printed, no trailing characters.
550 */
551 static int
552 printaname(FTSENT *p, u_long inodefield, u_long sizefield)
553 {
554 struct stat *sp;
555 int chcnt;
556 #ifdef COLORLS
557 int color_printed = 0;
558 #endif
559
560 sp = p->fts_statp;
561 chcnt = 0;
562 if (f_inode)
563 #if _DARWIN_FEATURE_64_BIT_INODE
564 chcnt += printf("%*llu ", (int)inodefield, (u_quad_t)sp->st_ino);
565 #else
566 chcnt += printf("%*lu ", (int)inodefield, (u_long)sp->st_ino);
567 #endif
568 if (f_size)
569 chcnt += printf("%*qu ",
570 (int)sizefield, (u_int64_t)howmany(sp->st_blocks, blocksize));
571 #ifdef COLORLS
572 if (f_color)
573 color_printed = colortype(sp->st_mode);
574 #endif
575 chcnt += printname(p->fts_name);
576 #ifdef COLORLS
577 if (f_color && color_printed)
578 endcolor(0);
579 #endif
580 if (f_type)
581 chcnt += printtype(sp->st_mode);
582 return (chcnt);
583 }
584
585 static void
586 printtime(time_t ftime)
587 {
588 char longstring[80];
589 static time_t now;
590 const char *format;
591 static int d_first = -1;
592
593 if (d_first < 0)
594 d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
595 if (now == 0)
596 now = time(NULL);
597
598 #define SIXMONTHS ((365 / 2) * 86400)
599 if (f_sectime)
600 /* mmm dd hh:mm:ss yyyy || dd mmm hh:mm:ss yyyy */
601 format = d_first ? "%e %b %T %Y " : "%b %e %T %Y ";
602 else if (COMPAT_MODE("bin/ls", "Unix2003")) {
603 if (ftime + SIXMONTHS > now && ftime <= now)
604 /* mmm dd hh:mm || dd mmm hh:mm */
605 format = d_first ? "%e %b %R " : "%b %e %R ";
606 else
607 /* mmm dd yyyy || dd mmm yyyy */
608 format = d_first ? "%e %b %Y " : "%b %e %Y ";
609 }
610 else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS)
611 /* mmm dd hh:mm || dd mmm hh:mm */
612 format = d_first ? "%e %b %R " : "%b %e %R ";
613 else
614 /* mmm dd yyyy || dd mmm yyyy */
615 format = d_first ? "%e %b %Y " : "%b %e %Y ";
616 strftime(longstring, sizeof(longstring), format, localtime(&ftime));
617 fputs(longstring, stdout);
618 }
619
620 static int
621 printtype(u_int mode)
622 {
623
624 if (f_slash) {
625 if ((mode & S_IFMT) == S_IFDIR) {
626 (void)putchar('/');
627 return (1);
628 }
629 return (0);
630 }
631
632 switch (mode & S_IFMT) {
633 case S_IFDIR:
634 (void)putchar('/');
635 return (1);
636 case S_IFIFO:
637 (void)putchar('|');
638 return (1);
639 case S_IFLNK:
640 (void)putchar('@');
641 return (1);
642 case S_IFSOCK:
643 (void)putchar('=');
644 return (1);
645 case S_IFWHT:
646 (void)putchar('%');
647 return (1);
648 default:
649 break;
650 }
651 if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
652 (void)putchar('*');
653 return (1);
654 }
655 return (0);
656 }
657
658 #ifdef COLORLS
659 static int
660 putch(int c)
661 {
662 (void)putchar(c);
663 return 0;
664 }
665
666 static int
667 writech(int c)
668 {
669 char tmp = c;
670
671 (void)write(STDOUT_FILENO, &tmp, 1);
672 return 0;
673 }
674
675 static void
676 printcolor(Colors c)
677 {
678 char *ansiseq;
679
680 if (colors[c].bold)
681 tputs(enter_bold, 1, putch);
682
683 if (colors[c].num[0] != -1) {
684 ansiseq = tgoto(ansi_fgcol, 0, colors[c].num[0]);
685 if (ansiseq)
686 tputs(ansiseq, 1, putch);
687 }
688 if (colors[c].num[1] != -1) {
689 ansiseq = tgoto(ansi_bgcol, 0, colors[c].num[1]);
690 if (ansiseq)
691 tputs(ansiseq, 1, putch);
692 }
693 }
694
695 static void
696 endcolor(int sig)
697 {
698 tputs(ansi_coloff, 1, sig ? writech : putch);
699 tputs(attrs_off, 1, sig ? writech : putch);
700 }
701
702 static int
703 colortype(mode_t mode)
704 {
705 switch (mode & S_IFMT) {
706 case S_IFDIR:
707 if (mode & S_IWOTH)
708 if (mode & S_ISTXT)
709 printcolor(C_WSDIR);
710 else
711 printcolor(C_WDIR);
712 else
713 printcolor(C_DIR);
714 return (1);
715 case S_IFLNK:
716 printcolor(C_LNK);
717 return (1);
718 case S_IFSOCK:
719 printcolor(C_SOCK);
720 return (1);
721 case S_IFIFO:
722 printcolor(C_FIFO);
723 return (1);
724 case S_IFBLK:
725 printcolor(C_BLK);
726 return (1);
727 case S_IFCHR:
728 printcolor(C_CHR);
729 return (1);
730 }
731 if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
732 if (mode & S_ISUID)
733 printcolor(C_SUID);
734 else if (mode & S_ISGID)
735 printcolor(C_SGID);
736 else
737 printcolor(C_EXEC);
738 return (1);
739 }
740 return (0);
741 }
742
743 void
744 parsecolors(const char *cs)
745 {
746 int i;
747 int j;
748 int len;
749 char c[2];
750 short legacy_warn = 0;
751
752 if (cs == NULL)
753 cs = ""; /* LSCOLORS not set */
754 len = strlen(cs);
755 for (i = 0; i < C_NUMCOLORS; i++) {
756 colors[i].bold = 0;
757
758 if (len <= 2 * i) {
759 c[0] = defcolors[2 * i];
760 c[1] = defcolors[2 * i + 1];
761 } else {
762 c[0] = cs[2 * i];
763 c[1] = cs[2 * i + 1];
764 }
765 for (j = 0; j < 2; j++) {
766 /* Legacy colours used 0-7 */
767 if (c[j] >= '0' && c[j] <= '7') {
768 colors[i].num[j] = c[j] - '0';
769 if (!legacy_warn) {
770 fprintf(stderr,
771 "warn: LSCOLORS should use "
772 "characters a-h instead of 0-9 ("
773 "see the manual page)\n");
774 }
775 legacy_warn = 1;
776 } else if (c[j] >= 'a' && c[j] <= 'h')
777 colors[i].num[j] = c[j] - 'a';
778 else if (c[j] >= 'A' && c[j] <= 'H') {
779 colors[i].num[j] = c[j] - 'A';
780 colors[i].bold = 1;
781 } else if (tolower((unsigned char)c[j] == 'x'))
782 colors[i].num[j] = -1;
783 else {
784 fprintf(stderr,
785 "error: invalid character '%c' in LSCOLORS"
786 " env var\n", c[j]);
787 colors[i].num[j] = -1;
788 }
789 }
790 }
791 }
792
793 void
794 colorquit(int sig)
795 {
796 endcolor(sig);
797
798 (void)signal(sig, SIG_DFL);
799 (void)kill(getpid(), sig);
800 }
801
802 #endif /* COLORLS */
803
804 static void
805 printlink(FTSENT *p)
806 {
807 int lnklen;
808 char name[MAXPATHLEN + 1];
809 char path[MAXPATHLEN + 1];
810
811 if (p->fts_level == FTS_ROOTLEVEL)
812 (void)snprintf(name, sizeof(name), "%s", p->fts_name);
813 else
814 (void)snprintf(name, sizeof(name),
815 "%s/%s", p->fts_parent->fts_accpath, p->fts_name);
816 if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) {
817 (void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno));
818 return;
819 }
820 path[lnklen] = '\0';
821 (void)printf(" -> ");
822 (void)printname(path);
823 }
824
825 static void
826 printsize(size_t width, off_t bytes)
827 {
828
829 if (f_humanval) {
830 char buf[5];
831
832 humanize_number(buf, sizeof(buf), (int64_t)bytes, "",
833 HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
834 (void)printf("%5s ", buf);
835 } else
836 (void)printf("%*jd ", (u_int)width, (intmax_t)bytes);
837 }