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