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