Super User's BSD Cross Reference: /FreeBSD/bin/ls/print.c

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

AltStyle によって変換されたページ (->オリジナル) /