1*c9828589Ssimonb /* $NetBSD: print.c,v 1.59 2024/12/11 12:56:31 simonb Exp $ */ 249f0ad86Scgd 361f28255Scgd /* 483ede345Smycroft * Copyright (c) 1989, 1993, 1994 583ede345Smycroft * The Regents of the University of California. All rights reserved. 661f28255Scgd * 761f28255Scgd * This code is derived from software contributed to Berkeley by 861f28255Scgd * Michael Fischbein. 961f28255Scgd * 1061f28255Scgd * Redistribution and use in source and binary forms, with or without 1161f28255Scgd * modification, are permitted provided that the following conditions 1261f28255Scgd * are met: 1361f28255Scgd * 1. Redistributions of source code must retain the above copyright 1461f28255Scgd * notice, this list of conditions and the following disclaimer. 1561f28255Scgd * 2. Redistributions in binary form must reproduce the above copyright 1661f28255Scgd * notice, this list of conditions and the following disclaimer in the 1761f28255Scgd * documentation and/or other materials provided with the distribution. 18b5b29542Sagc * 3. Neither the name of the University nor the names of its contributors 1961f28255Scgd * may be used to endorse or promote products derived from this software 2061f28255Scgd * without specific prior written permission. 2161f28255Scgd * 2261f28255Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2361f28255Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2461f28255Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2561f28255Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2661f28255Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2761f28255Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2861f28255Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2961f28255Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3061f28255Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3161f28255Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3261f28255Scgd * SUCH DAMAGE. 3361f28255Scgd */ 3461f28255Scgd 35b22592e8Schristos #include <sys/cdefs.h> 3661f28255Scgd #ifndef lint 3749f0ad86Scgd #if 0 38d943cdadSjtc static char sccsid[] = "@(#)print.c 8.5 (Berkeley) 7/28/94"; 3949f0ad86Scgd #else 40*c9828589Ssimonb __RCSID("$NetBSD: print.c,v 1.59 2024/12/11 12:56:31 simonb Exp $"); 4149f0ad86Scgd #endif 4261f28255Scgd #endif /* not lint */ 4361f28255Scgd 4461f28255Scgd #include <sys/param.h> 4561f28255Scgd #include <sys/stat.h> 46f6a91933Schristos #ifndef SMALL 479aa2a9c3Schristos #include <sys/acl.h> 48f6a91933Schristos #endif 4983ede345Smycroft 5083ede345Smycroft #include <err.h> 51203e4227Smycroft #include <errno.h> 52062900c4Smartin #include <inttypes.h> 5383ede345Smycroft #include <fts.h> 5461f28255Scgd #include <grp.h> 5561f28255Scgd #include <pwd.h> 56203e4227Smycroft #include <stdio.h> 5783ede345Smycroft #include <stdlib.h> 58203e4227Smycroft #include <string.h> 5983ede345Smycroft #include <time.h> 6083ede345Smycroft #include <tzfile.h> 6183ede345Smycroft #include <unistd.h> 62f4c47802Sgrant #include <util.h> 6383ede345Smycroft 6461f28255Scgd #include "ls.h" 65203e4227Smycroft #include "extern.h" 6661f28255Scgd 6718d76c32Schristos extern int termwidth; 6818d76c32Schristos 69ba2e04dcSlukem static int printaname(FTSENT *, int, int); 70ba2e04dcSlukem static void printlink(FTSENT *); 71ba2e04dcSlukem static void printtime(time_t); 72c111d829Sahoka static void printtotal(DISPLAY *dp); 73ba2e04dcSlukem static int printtype(u_int); 74f6a91933Schristos #ifndef SMALL 759aa2a9c3Schristos static void aclmode(char *, const FTSENT *); 76f6a91933Schristos #endif 77203e4227Smycroft 78d4e67eb2Smycroft static time_t now; 79d4e67eb2Smycroft 80203e4227Smycroft #define IS_NOPRINT(p) ((p)->fts_number == NO_PRINT) 81203e4227Smycroft 820c47a5c3Schristos static int 830c47a5c3Schristos safe_printpath(const FTSENT *p) { 840c47a5c3Schristos int chcnt; 850c47a5c3Schristos 860c47a5c3Schristos if (f_fullpath) { 870c47a5c3Schristos chcnt = safe_print(p->fts_path); 880c47a5c3Schristos chcnt += safe_print("/"); 890c47a5c3Schristos } else 900c47a5c3Schristos chcnt = 0; 910c47a5c3Schristos return chcnt + safe_print(p->fts_name); 920c47a5c3Schristos } 930c47a5c3Schristos 940c47a5c3Schristos static int 950c47a5c3Schristos printescapedpath(const FTSENT *p) { 960c47a5c3Schristos int chcnt; 970c47a5c3Schristos 980c47a5c3Schristos if (f_fullpath) { 990c47a5c3Schristos chcnt = printescaped(p->fts_path); 1000c47a5c3Schristos chcnt += printescaped("/"); 1010c47a5c3Schristos } else 1020c47a5c3Schristos chcnt = 0; 1030c47a5c3Schristos 1040c47a5c3Schristos return chcnt + printescaped(p->fts_name); 1050c47a5c3Schristos } 1060c47a5c3Schristos 1070c47a5c3Schristos static int 1080c47a5c3Schristos printpath(const FTSENT *p) { 1090c47a5c3Schristos if (f_fullpath) 1100c47a5c3Schristos return printf("%s/%s", p->fts_path, p->fts_name); 1110c47a5c3Schristos else 112fa4d72b1Smlelstv return printf("%s", p->fts_name); 1130c47a5c3Schristos } 1140c47a5c3Schristos 115203e4227Smycroft void 116ba2e04dcSlukem printscol(DISPLAY *dp) 11761f28255Scgd { 11883ede345Smycroft FTSENT *p; 119203e4227Smycroft 120203e4227Smycroft for (p = dp->list; p; p = p->fts_link) { 121203e4227Smycroft if (IS_NOPRINT(p)) 122203e4227Smycroft continue; 123203e4227Smycroft (void)printaname(p, dp->s_inode, dp->s_block); 12461f28255Scgd (void)putchar('\n'); 12561f28255Scgd } 12661f28255Scgd } 12761f28255Scgd 128203e4227Smycroft void 129ba2e04dcSlukem printlong(DISPLAY *dp) 13061f28255Scgd { 13183ede345Smycroft struct stat *sp; 13283ede345Smycroft FTSENT *p; 133203e4227Smycroft NAMES *np; 134f4c47802Sgrant char buf[20], szbuf[5]; 13561f28255Scgd 1361381f684Smycroft now = time(NULL); 137d4e67eb2Smycroft 1380c47a5c3Schristos if (!f_leafonly) 139c111d829Sahoka printtotal(dp); /* "total: %u\n" */ 140203e4227Smycroft 141203e4227Smycroft for (p = dp->list; p; p = p->fts_link) { 142203e4227Smycroft if (IS_NOPRINT(p)) 143203e4227Smycroft continue; 144203e4227Smycroft sp = p->fts_statp; 14561f28255Scgd if (f_inode) 146062900c4Smartin (void)printf("%*"PRIu64" ", dp->s_inode, sp->st_ino); 1470386433dSjschauma if (f_size) { 1480386433dSjschauma if (f_humanize) { 1490386433dSjschauma if ((humanize_number(szbuf, sizeof(szbuf), 1500386433dSjschauma sp->st_blocks * S_BLKSIZE, 1510386433dSjschauma "", HN_AUTOSCALE, 1520386433dSjschauma (HN_DECIMAL | HN_B | HN_NOSPACE))) == -1) 1530386433dSjschauma err(1, "humanize_number"); 1540386433dSjschauma (void)printf("%*s ", dp->s_block, szbuf); 1550386433dSjschauma } else { 156cde105a4Schristos (void)printf(f_commas ? "%'*llu " : "%*llu ", 157cde105a4Schristos dp->s_block, 158cde105a4Schristos (unsigned long long)howmany(sp->st_blocks, 1590386433dSjschauma blocksize)); 1600386433dSjschauma } 161f4c47802Sgrant } 162203e4227Smycroft (void)strmode(sp->st_mode, buf); 163f6a91933Schristos #ifndef SMALL 1649aa2a9c3Schristos aclmode(buf, p); 165f6a91933Schristos #endif 166203e4227Smycroft np = p->fts_pointer; 16775d0e9d0Sgrant (void)printf("%s %*lu ", buf, dp->s_nlink, 16875d0e9d0Sgrant (unsigned long)sp->st_nlink); 16975d0e9d0Sgrant if (!f_grouponly) 17075d0e9d0Sgrant (void)printf("%-*s ", dp->s_user, np->user); 17175d0e9d0Sgrant (void)printf("%-*s ", dp->s_group, np->group); 172203e4227Smycroft if (f_flags) 173203e4227Smycroft (void)printf("%-*s ", dp->s_flags, np->flags); 174203e4227Smycroft if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode)) 175909ffa32Schristos (void)printf("%*lld, %*lld ", 176909ffa32Schristos dp->s_major, (long long)major(sp->st_rdev), 177909ffa32Schristos dp->s_minor, (long long)minor(sp->st_rdev)); 17861f28255Scgd else 179f4c47802Sgrant if (f_humanize) { 180f4c47802Sgrant if ((humanize_number(szbuf, sizeof(szbuf), 181f4c47802Sgrant sp->st_size, "", HN_AUTOSCALE, 182f4c47802Sgrant (HN_DECIMAL | HN_B | HN_NOSPACE))) == -1) 183f4c47802Sgrant err(1, "humanize_number"); 184f4c47802Sgrant (void)printf("%*s ", dp->s_size, szbuf); 185f4c47802Sgrant } else { 186cde105a4Schristos (void)printf(f_commas ? "%'*llu " : "%*llu ", 187cde105a4Schristos dp->s_size, (unsigned long long) 188cde105a4Schristos sp->st_size); 189f4c47802Sgrant } 19061f28255Scgd if (f_accesstime) 191203e4227Smycroft printtime(sp->st_atime); 19261f28255Scgd else if (f_statustime) 193203e4227Smycroft printtime(sp->st_ctime); 19461f28255Scgd else 195203e4227Smycroft printtime(sp->st_mtime); 19621ab6335Sjschauma if (f_octal || f_octal_escape) 1970c47a5c3Schristos (void)safe_printpath(p); 1982ccef82cSjschauma else if (f_nonprint) 1990c47a5c3Schristos (void)printescapedpath(p); 200c5a80669Sassar else 2010c47a5c3Schristos (void)printpath(p); 202c5a80669Sassar 203b424b8feSkleink if (f_type || (f_typedir && S_ISDIR(sp->st_mode))) 204203e4227Smycroft (void)printtype(sp->st_mode); 205203e4227Smycroft if (S_ISLNK(sp->st_mode)) 206203e4227Smycroft printlink(p); 20761f28255Scgd (void)putchar('\n'); 20861f28255Scgd } 20961f28255Scgd } 21061f28255Scgd 211203e4227Smycroft void 212ba2e04dcSlukem printcol(DISPLAY *dp) 21361f28255Scgd { 214203e4227Smycroft static FTSENT **array; 215203e4227Smycroft static int lastentries = -1; 21683ede345Smycroft FTSENT *p; 217b22592e8Schristos int base, chcnt, col, colwidth, num; 21851175461Sthorpej int numcols, numrows, row; 21961f28255Scgd 220ac591fc0Slukem colwidth = dp->maxlen; 221ac591fc0Slukem if (f_inode) 222ac591fc0Slukem colwidth += dp->s_inode + 1; 223f4c47802Sgrant if (f_size) { 224f4c47802Sgrant if (f_humanize) 225f4c47802Sgrant colwidth += dp->s_size + 1; 226f4c47802Sgrant else 227ac591fc0Slukem colwidth += dp->s_block + 1; 228f4c47802Sgrant } 229b424b8feSkleink if (f_type || f_typedir) 230ac591fc0Slukem colwidth += 1; 231ac591fc0Slukem 232ac591fc0Slukem colwidth += 1; 233ac591fc0Slukem 234df291acdSjschauma printtotal(dp); /* "total: %u\n" */ 235df291acdSjschauma 236ac591fc0Slukem if (termwidth < 2 * colwidth) { 237ac591fc0Slukem printscol(dp); 238ac591fc0Slukem return; 239ac591fc0Slukem } 240ac591fc0Slukem 241203e4227Smycroft /* 242203e4227Smycroft * Have to do random access in the linked list -- build a table 243203e4227Smycroft * of pointers. 244203e4227Smycroft */ 245203e4227Smycroft if (dp->entries > lastentries) { 24646583bd0Syamt FTSENT **newarray; 24746583bd0Syamt 24846583bd0Syamt newarray = realloc(array, dp->entries * sizeof(FTSENT *)); 24946583bd0Syamt if (newarray == NULL) { 25085cbf55dSdrochner warn(NULL); 251203e4227Smycroft printscol(dp); 25246583bd0Syamt return; 253203e4227Smycroft } 25446583bd0Syamt lastentries = dp->entries; 25546583bd0Syamt array = newarray; 256203e4227Smycroft } 257203e4227Smycroft for (p = dp->list, num = 0; p; p = p->fts_link) 258203e4227Smycroft if (p->fts_number != NO_PRINT) 259203e4227Smycroft array[num++] = p; 260203e4227Smycroft 261ac591fc0Slukem numcols = termwidth / colwidth; 262ac591fc0Slukem colwidth = termwidth / numcols; /* spread out if possible */ 263ac591fc0Slukem numrows = num / numcols; 264ac591fc0Slukem if (num % numcols) 265ac591fc0Slukem ++numrows; 266ac591fc0Slukem 267ac591fc0Slukem for (row = 0; row < numrows; ++row) { 268ac591fc0Slukem for (base = row, chcnt = col = 0; col < numcols; ++col) { 269ac591fc0Slukem chcnt = printaname(array[base], dp->s_inode, 270f4c47802Sgrant f_humanize ? dp->s_size : dp->s_block); 271ac591fc0Slukem if ((base += numrows) >= num) 272ac591fc0Slukem break; 273ac591fc0Slukem while (chcnt++ < colwidth) 2741381f684Smycroft (void)putchar(' '); 275ac591fc0Slukem } 276ac591fc0Slukem (void)putchar('\n'); 277ac591fc0Slukem } 278ac591fc0Slukem } 279ac591fc0Slukem 280ac591fc0Slukem void 281ba2e04dcSlukem printacol(DISPLAY *dp) 282ac591fc0Slukem { 283ac591fc0Slukem FTSENT *p; 284ac591fc0Slukem int chcnt, col, colwidth; 285ac591fc0Slukem int numcols; 286ac591fc0Slukem 287203e4227Smycroft colwidth = dp->maxlen; 28861f28255Scgd if (f_inode) 289203e4227Smycroft colwidth += dp->s_inode + 1; 290f4c47802Sgrant if (f_size) { 291f4c47802Sgrant if (f_humanize) 292f4c47802Sgrant colwidth += dp->s_size + 1; 293f4c47802Sgrant else 294203e4227Smycroft colwidth += dp->s_block + 1; 295f4c47802Sgrant } 296b424b8feSkleink if (f_type || f_typedir) 29761f28255Scgd colwidth += 1; 29861f28255Scgd 29951175461Sthorpej colwidth += 1; 30051175461Sthorpej 301df291acdSjschauma printtotal(dp); /* "total: %u\n" */ 302df291acdSjschauma 30361f28255Scgd if (termwidth < 2 * colwidth) { 304203e4227Smycroft printscol(dp); 30561f28255Scgd return; 30661f28255Scgd } 30761f28255Scgd 30861f28255Scgd numcols = termwidth / colwidth; 30951175461Sthorpej colwidth = termwidth / numcols; /* spread out if possible */ 31061f28255Scgd 311ac591fc0Slukem chcnt = col = 0; 312ac591fc0Slukem for (p = dp->list; p; p = p->fts_link) { 313ac591fc0Slukem if (IS_NOPRINT(p)) 314ac591fc0Slukem continue; 315ac591fc0Slukem if (col >= numcols) { 316ac591fc0Slukem chcnt = col = 0; 3171381f684Smycroft (void)putchar('\n'); 318ac591fc0Slukem } 319f4c47802Sgrant chcnt = printaname(p, dp->s_inode, 320f4c47802Sgrant f_humanize ? dp->s_size : dp->s_block); 32151175461Sthorpej while (chcnt++ < colwidth) 3221381f684Smycroft (void)putchar(' '); 323ac591fc0Slukem col++; 32461f28255Scgd } 3251381f684Smycroft (void)putchar('\n'); 32661f28255Scgd } 32761f28255Scgd 328b7443b0fSkleink void 329ba2e04dcSlukem printstream(DISPLAY *dp) 330b7443b0fSkleink { 331b7443b0fSkleink FTSENT *p; 332b7443b0fSkleink int col; 333b7443b0fSkleink int extwidth; 334b7443b0fSkleink 335b7443b0fSkleink extwidth = 0; 336b7443b0fSkleink if (f_inode) 337b7443b0fSkleink extwidth += dp->s_inode + 1; 338f4c47802Sgrant if (f_size) { 339f4c47802Sgrant if (f_humanize) 340f4c47802Sgrant extwidth += dp->s_size + 1; 341f4c47802Sgrant else 342b7443b0fSkleink extwidth += dp->s_block + 1; 343f4c47802Sgrant } 344b7443b0fSkleink if (f_type) 345b7443b0fSkleink extwidth += 1; 346b7443b0fSkleink 347b7443b0fSkleink for (col = 0, p = dp->list; p != NULL; p = p->fts_link) { 348b7443b0fSkleink if (IS_NOPRINT(p)) 349b7443b0fSkleink continue; 350b7443b0fSkleink if (col > 0) { 351b7443b0fSkleink (void)putchar(','), col++; 352990d25a9Slukem if (col + 1 + extwidth + (int)p->fts_namelen >= termwidth) 353b7443b0fSkleink (void)putchar('\n'), col = 0; 354b7443b0fSkleink else 355b7443b0fSkleink (void)putchar(' '), col++; 356b7443b0fSkleink } 357f4c47802Sgrant col += printaname(p, dp->s_inode, 358f4c47802Sgrant f_humanize ? dp->s_size : dp->s_block); 359b7443b0fSkleink } 360b7443b0fSkleink (void)putchar('\n'); 361b7443b0fSkleink } 362b7443b0fSkleink 36361f28255Scgd /* 36461f28255Scgd * print [inode] [size] name 365203e4227Smycroft * return # of characters printed, no trailing characters. 36661f28255Scgd */ 367203e4227Smycroft static int 368ba2e04dcSlukem printaname(FTSENT *p, int inodefield, int sizefield) 36961f28255Scgd { 370203e4227Smycroft struct stat *sp; 37161f28255Scgd int chcnt; 372f4c47802Sgrant char szbuf[5]; 37361f28255Scgd 374203e4227Smycroft sp = p->fts_statp; 37561f28255Scgd chcnt = 0; 37661f28255Scgd if (f_inode) 377062900c4Smartin chcnt += printf("%*"PRIu64" ", inodefield, sp->st_ino); 378f4c47802Sgrant if (f_size) { 379f4c47802Sgrant if (f_humanize) { 380f4c47802Sgrant if ((humanize_number(szbuf, sizeof(szbuf), sp->st_size, 381f4c47802Sgrant "", HN_AUTOSCALE, 382f4c47802Sgrant (HN_DECIMAL | HN_B | HN_NOSPACE))) == -1) 383f4c47802Sgrant err(1, "humanize_number"); 384f4c47802Sgrant chcnt += printf("%*s ", sizefield, szbuf); 385f4c47802Sgrant } else { 386cde105a4Schristos chcnt += printf(f_commas ? "%'*llu " : "%*llu ", 387cde105a4Schristos sizefield, (unsigned long long) 388cde105a4Schristos howmany(sp->st_blocks, blocksize)); 389f4c47802Sgrant } 390f4c47802Sgrant } 39121ab6335Sjschauma if (f_octal || f_octal_escape) 3920c47a5c3Schristos chcnt += safe_printpath(p); 3932ccef82cSjschauma else if (f_nonprint) 3940c47a5c3Schristos chcnt += printescapedpath(p); 395b23df5beSassar else 3960c47a5c3Schristos chcnt += printpath(p); 397b424b8feSkleink if (f_type || (f_typedir && S_ISDIR(sp->st_mode))) 398203e4227Smycroft chcnt += printtype(sp->st_mode); 39961f28255Scgd return (chcnt); 40061f28255Scgd } 40161f28255Scgd 402203e4227Smycroft static void 403ba2e04dcSlukem printtime(time_t ftime) 40461f28255Scgd { 40561f28255Scgd int i; 406221f2e33Schristos const char *longstring; 40761f28255Scgd 408b22f1047Schristos if ((longstring = ctime(&ftime)) == NULL) { 409221f2e33Schristos /* 012345678901234567890123 */ 410221f2e33Schristos longstring = "????????????????????????"; 411221f2e33Schristos } 41261f28255Scgd for (i = 4; i < 11; ++i) 41361f28255Scgd (void)putchar(longstring[i]); 41461f28255Scgd 41561f28255Scgd #define SIXMONTHS ((DAYSPERNYEAR / 2) * SECSPERDAY) 41661f28255Scgd if (f_sectime) 41761f28255Scgd for (i = 11; i < 24; i++) 41861f28255Scgd (void)putchar(longstring[i]); 41975a40767Smycroft else if (ftime + SIXMONTHS > now && ftime - SIXMONTHS < now) 42061f28255Scgd for (i = 11; i < 16; ++i) 42161f28255Scgd (void)putchar(longstring[i]); 42261f28255Scgd else { 42361f28255Scgd (void)putchar(' '); 42461f28255Scgd for (i = 20; i < 24; ++i) 42561f28255Scgd (void)putchar(longstring[i]); 42661f28255Scgd } 42761f28255Scgd (void)putchar(' '); 42861f28255Scgd } 42961f28255Scgd 430c111d829Sahoka /* 431c111d829Sahoka * Display total used disk space in the form "total: %u\n". 432c111d829Sahoka * Note: POSIX (IEEE Std 1003.1-2001) says this should be always in 512 blocks, 4334aaf499cSerh * but we humanise it with -h, or separate it with commas with -M, and use 1024 4344aaf499cSerh * with -k. 435c111d829Sahoka */ 436c111d829Sahoka static void 437c111d829Sahoka printtotal(DISPLAY *dp) 438c111d829Sahoka { 439c111d829Sahoka char szbuf[5]; 440c111d829Sahoka 441c111d829Sahoka if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) { 442c111d829Sahoka if (f_humanize) { 443*c9828589Ssimonb if ((humanize_number(szbuf, sizeof(szbuf), 444*c9828589Ssimonb dp->btotal * POSIX_BLOCK_SIZE, 445c111d829Sahoka "", HN_AUTOSCALE, 446c111d829Sahoka (HN_DECIMAL | HN_B | HN_NOSPACE))) == -1) 447c111d829Sahoka err(1, "humanize_number"); 448c111d829Sahoka (void)printf("total %s\n", szbuf); 449c111d829Sahoka } else { 450cde105a4Schristos (void)printf(f_commas ? "total %'llu\n" : 451cde105a4Schristos "total %llu\n", (unsigned long long) 452cde105a4Schristos howmany(dp->btotal, blocksize)); 453c111d829Sahoka } 454c111d829Sahoka } 455c111d829Sahoka } 456c111d829Sahoka 457203e4227Smycroft static int 458ba2e04dcSlukem printtype(u_int mode) 45961f28255Scgd { 46061f28255Scgd switch (mode & S_IFMT) { 46161f28255Scgd case S_IFDIR: 46261f28255Scgd (void)putchar('/'); 46361f28255Scgd return (1); 46483ede345Smycroft case S_IFIFO: 46583ede345Smycroft (void)putchar('|'); 46683ede345Smycroft return (1); 46761f28255Scgd case S_IFLNK: 46861f28255Scgd (void)putchar('@'); 46961f28255Scgd return (1); 47061f28255Scgd case S_IFSOCK: 47161f28255Scgd (void)putchar('='); 47261f28255Scgd return (1); 473d966913fSmycroft case S_IFWHT: 474d966913fSmycroft (void)putchar('%'); 475d966913fSmycroft return (1); 47661f28255Scgd } 47761f28255Scgd if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 47861f28255Scgd (void)putchar('*'); 47961f28255Scgd return (1); 48061f28255Scgd } 48161f28255Scgd return (0); 48261f28255Scgd } 48361f28255Scgd 484203e4227Smycroft static void 485ba2e04dcSlukem printlink(FTSENT *p) 48661f28255Scgd { 48761f28255Scgd int lnklen; 488203e4227Smycroft char name[MAXPATHLEN + 1], path[MAXPATHLEN + 1]; 48961f28255Scgd 490203e4227Smycroft if (p->fts_level == FTS_ROOTLEVEL) 491203e4227Smycroft (void)snprintf(name, sizeof(name), "%s", p->fts_name); 492203e4227Smycroft else 49383ede345Smycroft (void)snprintf(name, sizeof(name), 49483ede345Smycroft "%s/%s", p->fts_parent->fts_accpath, p->fts_name); 49583ede345Smycroft if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) { 49661f28255Scgd (void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno)); 49761f28255Scgd return; 49861f28255Scgd } 49961f28255Scgd path[lnklen] = '\0'; 500c5a80669Sassar (void)printf(" -> "); 50121ab6335Sjschauma if (f_octal || f_octal_escape) 5022ccef82cSjschauma (void)safe_print(path); 5032ccef82cSjschauma else if (f_nonprint) 5042ccef82cSjschauma (void)printescaped(path); 505c5a80669Sassar else 506c5a80669Sassar (void)printf("%s", path); 50761f28255Scgd } 5089aa2a9c3Schristos 509f6a91933Schristos #ifndef SMALL 5109aa2a9c3Schristos /* 5119aa2a9c3Schristos * Add a + after the standard rwxrwxrwx mode if the file has an 5129aa2a9c3Schristos * ACL. strmode() reserves space at the end of the string. 5139aa2a9c3Schristos */ 5149aa2a9c3Schristos static void 5159aa2a9c3Schristos aclmode(char *buf, const FTSENT *p) 5169aa2a9c3Schristos { 5179aa2a9c3Schristos char name[MAXPATHLEN + 1]; 5189aa2a9c3Schristos int ret, trivial; 5199aa2a9c3Schristos static dev_t previous_dev = NODEV; 5209aa2a9c3Schristos static int supports_acls = -1; 5219aa2a9c3Schristos static int type = ACL_TYPE_ACCESS; 5229aa2a9c3Schristos acl_t facl; 5239aa2a9c3Schristos 5249aa2a9c3Schristos /* 5259aa2a9c3Schristos * XXX: ACLs are not supported on whiteouts and device files 5269aa2a9c3Schristos * residing on UFS. 5279aa2a9c3Schristos */ 5289aa2a9c3Schristos if (S_ISCHR(p->fts_statp->st_mode) || S_ISBLK(p->fts_statp->st_mode) || 5299aa2a9c3Schristos S_ISWHT(p->fts_statp->st_mode)) 5309aa2a9c3Schristos return; 5319aa2a9c3Schristos 5329aa2a9c3Schristos if (previous_dev == p->fts_statp->st_dev && supports_acls == 0) 5339aa2a9c3Schristos return; 5349aa2a9c3Schristos 5359aa2a9c3Schristos if (p->fts_level == FTS_ROOTLEVEL) 5369aa2a9c3Schristos snprintf(name, sizeof(name), "%s", p->fts_name); 5379aa2a9c3Schristos else 5389aa2a9c3Schristos snprintf(name, sizeof(name), "%s/%s", 5399aa2a9c3Schristos p->fts_parent->fts_accpath, p->fts_name); 5409aa2a9c3Schristos 5419aa2a9c3Schristos if (supports_acls == -1 || previous_dev != p->fts_statp->st_dev) { 5429aa2a9c3Schristos previous_dev = p->fts_statp->st_dev; 5439aa2a9c3Schristos supports_acls = 0; 5449aa2a9c3Schristos 5459aa2a9c3Schristos ret = lpathconf(name, _PC_ACL_NFS4); 5469aa2a9c3Schristos if (ret > 0) { 5479aa2a9c3Schristos type = ACL_TYPE_NFS4; 5489aa2a9c3Schristos supports_acls = 1; 5499aa2a9c3Schristos } else if (ret < 0 && errno != EINVAL) { 5509aa2a9c3Schristos warn("%s", name); 5519aa2a9c3Schristos return; 5529aa2a9c3Schristos } 5539aa2a9c3Schristos if (supports_acls == 0) { 5549aa2a9c3Schristos ret = lpathconf(name, _PC_ACL_EXTENDED); 5559aa2a9c3Schristos if (ret > 0) { 5569aa2a9c3Schristos type = ACL_TYPE_ACCESS; 5579aa2a9c3Schristos supports_acls = 1; 5589aa2a9c3Schristos } else if (ret < 0 && errno != EINVAL) { 5599aa2a9c3Schristos warn("%s", name); 5609aa2a9c3Schristos return; 5619aa2a9c3Schristos } 5629aa2a9c3Schristos } 5639aa2a9c3Schristos } 5649aa2a9c3Schristos if (supports_acls == 0) 5659aa2a9c3Schristos return; 5669aa2a9c3Schristos facl = acl_get_link_np(name, type); 5679aa2a9c3Schristos if (facl == NULL) { 5689aa2a9c3Schristos warn("%s", name); 5699aa2a9c3Schristos return; 5709aa2a9c3Schristos } 5719aa2a9c3Schristos if (acl_is_trivial_np(facl, &trivial)) { 5729aa2a9c3Schristos acl_free(facl); 5739aa2a9c3Schristos warn("%s", name); 5749aa2a9c3Schristos return; 5759aa2a9c3Schristos } 5769aa2a9c3Schristos if (!trivial) 5779aa2a9c3Schristos buf[10] = '+'; 5789aa2a9c3Schristos acl_free(facl); 5799aa2a9c3Schristos } 580f6a91933Schristos #endif 581