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