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