1 1.59 simonb /* $NetBSD: print.c,v 1.59 2024/12/11 12:56:31 simonb Exp $ */ 2 1.13 cgd 3 1.1 cgd /* 4 1.11 mycroft * Copyright (c) 1989, 1993, 1994 5 1.11 mycroft * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * This code is derived from software contributed to Berkeley by 8 1.1 cgd * Michael Fischbein. 9 1.1 cgd * 10 1.1 cgd * Redistribution and use in source and binary forms, with or without 11 1.1 cgd * modification, are permitted provided that the following conditions 12 1.1 cgd * are met: 13 1.1 cgd * 1. Redistributions of source code must retain the above copyright 14 1.1 cgd * notice, this list of conditions and the following disclaimer. 15 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 cgd * notice, this list of conditions and the following disclaimer in the 17 1.1 cgd * documentation and/or other materials provided with the distribution. 18 1.35 agc * 3. Neither the name of the University nor the names of its contributors 19 1.1 cgd * may be used to endorse or promote products derived from this software 20 1.1 cgd * without specific prior written permission. 21 1.1 cgd * 22 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 1.1 cgd * SUCH DAMAGE. 33 1.1 cgd */ 34 1.1 cgd 35 1.16 christos #include <sys/cdefs.h> 36 1.1 cgd #ifndef lint 37 1.13 cgd #if 0 38 1.14 jtc static char sccsid[] = "@(#)print.c 8.5 (Berkeley) 7/28/94"; 39 1.13 cgd #else 40 1.59 simonb __RCSID("$NetBSD: print.c,v 1.59 2024/12/11 12:56:31 simonb Exp $"); 41 1.13 cgd #endif 42 1.1 cgd #endif /* not lint */ 43 1.1 cgd 44 1.1 cgd #include <sys/param.h> 45 1.1 cgd #include <sys/stat.h> 46 1.57 christos #ifndef SMALL 47 1.56 christos #include <sys/acl.h> 48 1.57 christos #endif 49 1.11 mycroft 50 1.11 mycroft #include <err.h> 51 1.11 mycroft #include <errno.h> 52 1.55 martin #include <inttypes.h> 53 1.5 mycroft #include <fts.h> 54 1.1 cgd #include <grp.h> 55 1.1 cgd #include <pwd.h> 56 1.11 mycroft #include <stdio.h> 57 1.5 mycroft #include <stdlib.h> 58 1.5 mycroft #include <string.h> 59 1.11 mycroft #include <time.h> 60 1.11 mycroft #include <tzfile.h> 61 1.11 mycroft #include <unistd.h> 62 1.38 grant #include <util.h> 63 1.11 mycroft 64 1.1 cgd #include "ls.h" 65 1.5 mycroft #include "extern.h" 66 1.1 cgd 67 1.31 christos extern int termwidth; 68 1.31 christos 69 1.30 lukem static int printaname(FTSENT *, int, int); 70 1.30 lukem static void printlink(FTSENT *); 71 1.30 lukem static void printtime(time_t); 72 1.43 ahoka static void printtotal(DISPLAY *dp); 73 1.30 lukem static int printtype(u_int); 74 1.57 christos #ifndef SMALL 75 1.56 christos static void aclmode(char *, const FTSENT *); 76 1.57 christos #endif 77 1.5 mycroft 78 1.20 mycroft static time_t now; 79 1.20 mycroft 80 1.5 mycroft #define IS_NOPRINT(p) ((p)->fts_number == NO_PRINT) 81 1.5 mycroft 82 1.53 christos static int 83 1.53 christos safe_printpath(const FTSENT *p) { 84 1.53 christos int chcnt; 85 1.53 christos 86 1.53 christos if (f_fullpath) { 87 1.53 christos chcnt = safe_print(p->fts_path); 88 1.53 christos chcnt += safe_print("/"); 89 1.53 christos } else 90 1.53 christos chcnt = 0; 91 1.53 christos return chcnt + safe_print(p->fts_name); 92 1.53 christos } 93 1.53 christos 94 1.53 christos static int 95 1.53 christos printescapedpath(const FTSENT *p) { 96 1.53 christos int chcnt; 97 1.53 christos 98 1.53 christos if (f_fullpath) { 99 1.53 christos chcnt = printescaped(p->fts_path); 100 1.53 christos chcnt += printescaped("/"); 101 1.53 christos } else 102 1.53 christos chcnt = 0; 103 1.53 christos 104 1.53 christos return chcnt + printescaped(p->fts_name); 105 1.53 christos } 106 1.53 christos 107 1.53 christos static int 108 1.53 christos printpath(const FTSENT *p) { 109 1.53 christos if (f_fullpath) 110 1.53 christos return printf("%s/%s", p->fts_path, p->fts_name); 111 1.53 christos else 112 1.54 mlelstv return printf("%s", p->fts_name); 113 1.53 christos } 114 1.53 christos 115 1.5 mycroft void 116 1.30 lukem printscol(DISPLAY *dp) 117 1.1 cgd { 118 1.11 mycroft FTSENT *p; 119 1.5 mycroft 120 1.5 mycroft for (p = dp->list; p; p = p->fts_link) { 121 1.5 mycroft if (IS_NOPRINT(p)) 122 1.5 mycroft continue; 123 1.5 mycroft (void)printaname(p, dp->s_inode, dp->s_block); 124 1.1 cgd (void)putchar('\n'); 125 1.1 cgd } 126 1.1 cgd } 127 1.1 cgd 128 1.5 mycroft void 129 1.30 lukem printlong(DISPLAY *dp) 130 1.5 mycroft { 131 1.11 mycroft struct stat *sp; 132 1.11 mycroft FTSENT *p; 133 1.5 mycroft NAMES *np; 134 1.38 grant char buf[20], szbuf[5]; 135 1.5 mycroft 136 1.22 mycroft now = time(NULL); 137 1.20 mycroft 138 1.53 christos if (!f_leafonly) 139 1.53 christos printtotal(dp); /* "total: %u\n" */ 140 1.43 ahoka 141 1.5 mycroft for (p = dp->list; p; p = p->fts_link) { 142 1.5 mycroft if (IS_NOPRINT(p)) 143 1.5 mycroft continue; 144 1.5 mycroft sp = p->fts_statp; 145 1.1 cgd if (f_inode) 146 1.55 martin (void)printf("%*"PRIu64" ", dp->s_inode, sp->st_ino); 147 1.41 jschauma if (f_size) { 148 1.41 jschauma if (f_humanize) { 149 1.41 jschauma if ((humanize_number(szbuf, sizeof(szbuf), 150 1.48 enami sp->st_blocks * S_BLKSIZE, 151 1.48 enami "", HN_AUTOSCALE, 152 1.48 enami (HN_DECIMAL | HN_B | HN_NOSPACE))) == -1) 153 1.48 enami err(1, "humanize_number"); 154 1.48 enami (void)printf("%*s ", dp->s_block, szbuf); 155 1.41 jschauma } else { 156 1.50 christos (void)printf(f_commas ? "%'*llu " : "%*llu ", 157 1.50 christos dp->s_block, 158 1.50 christos (unsigned long long)howmany(sp->st_blocks, 159 1.48 enami blocksize)); 160 1.41 jschauma } 161 1.38 grant } 162 1.5 mycroft (void)strmode(sp->st_mode, buf); 163 1.57 christos #ifndef SMALL 164 1.56 christos aclmode(buf, p); 165 1.57 christos #endif 166 1.5 mycroft np = p->fts_pointer; 167 1.34 grant (void)printf("%s %*lu ", buf, dp->s_nlink, 168 1.34 grant (unsigned long)sp->st_nlink); 169 1.34 grant if (!f_grouponly) 170 1.34 grant (void)printf("%-*s ", dp->s_user, np->user); 171 1.34 grant (void)printf("%-*s ", dp->s_group, np->group); 172 1.5 mycroft if (f_flags) 173 1.5 mycroft (void)printf("%-*s ", dp->s_flags, np->flags); 174 1.5 mycroft if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode)) 175 1.44 christos (void)printf("%*lld, %*lld ", 176 1.44 christos dp->s_major, (long long)major(sp->st_rdev), 177 1.44 christos dp->s_minor, (long long)minor(sp->st_rdev)); 178 1.1 cgd else 179 1.38 grant if (f_humanize) { 180 1.38 grant if ((humanize_number(szbuf, sizeof(szbuf), 181 1.38 grant sp->st_size, "", HN_AUTOSCALE, 182 1.38 grant (HN_DECIMAL | HN_B | HN_NOSPACE))) == -1) 183 1.38 grant err(1, "humanize_number"); 184 1.38 grant (void)printf("%*s ", dp->s_size, szbuf); 185 1.38 grant } else { 186 1.50 christos (void)printf(f_commas ? "%'*llu " : "%*llu ", 187 1.50 christos dp->s_size, (unsigned long long) 188 1.50 christos sp->st_size); 189 1.38 grant } 190 1.1 cgd if (f_accesstime) 191 1.5 mycroft printtime(sp->st_atime); 192 1.1 cgd else if (f_statustime) 193 1.5 mycroft printtime(sp->st_ctime); 194 1.1 cgd else 195 1.5 mycroft printtime(sp->st_mtime); 196 1.37 jschauma if (f_octal || f_octal_escape) 197 1.53 christos (void)safe_printpath(p); 198 1.36 jschauma else if (f_nonprint) 199 1.53 christos (void)printescapedpath(p); 200 1.28 assar else 201 1.53 christos (void)printpath(p); 202 1.28 assar 203 1.26 kleink if (f_type || (f_typedir && S_ISDIR(sp->st_mode))) 204 1.5 mycroft (void)printtype(sp->st_mode); 205 1.5 mycroft if (S_ISLNK(sp->st_mode)) 206 1.5 mycroft printlink(p); 207 1.1 cgd (void)putchar('\n'); 208 1.1 cgd } 209 1.1 cgd } 210 1.1 cgd 211 1.5 mycroft void 212 1.30 lukem printcol(DISPLAY *dp) 213 1.1 cgd { 214 1.5 mycroft static FTSENT **array; 215 1.5 mycroft static int lastentries = -1; 216 1.11 mycroft FTSENT *p; 217 1.16 christos int base, chcnt, col, colwidth, num; 218 1.15 thorpej int numcols, numrows, row; 219 1.1 cgd 220 1.19 lukem colwidth = dp->maxlen; 221 1.19 lukem if (f_inode) 222 1.19 lukem colwidth += dp->s_inode + 1; 223 1.38 grant if (f_size) { 224 1.38 grant if (f_humanize) 225 1.38 grant colwidth += dp->s_size + 1; 226 1.38 grant else 227 1.38 grant colwidth += dp->s_block + 1; 228 1.38 grant } 229 1.26 kleink if (f_type || f_typedir) 230 1.19 lukem colwidth += 1; 231 1.19 lukem 232 1.19 lukem colwidth += 1; 233 1.19 lukem 234 1.58 jschauma printtotal(dp); /* "total: %u\n" */ 235 1.58 jschauma 236 1.19 lukem if (termwidth < 2 * colwidth) { 237 1.19 lukem printscol(dp); 238 1.19 lukem return; 239 1.19 lukem } 240 1.19 lukem 241 1.5 mycroft /* 242 1.5 mycroft * Have to do random access in the linked list -- build a table 243 1.5 mycroft * of pointers. 244 1.5 mycroft */ 245 1.5 mycroft if (dp->entries > lastentries) { 246 1.51 yamt FTSENT **newarray; 247 1.51 yamt 248 1.51 yamt newarray = realloc(array, dp->entries * sizeof(FTSENT *)); 249 1.51 yamt if (newarray == NULL) { 250 1.27 drochner warn(NULL); 251 1.5 mycroft printscol(dp); 252 1.51 yamt return; 253 1.5 mycroft } 254 1.51 yamt lastentries = dp->entries; 255 1.51 yamt array = newarray; 256 1.5 mycroft } 257 1.5 mycroft for (p = dp->list, num = 0; p; p = p->fts_link) 258 1.5 mycroft if (p->fts_number != NO_PRINT) 259 1.5 mycroft array[num++] = p; 260 1.5 mycroft 261 1.19 lukem numcols = termwidth / colwidth; 262 1.19 lukem colwidth = termwidth / numcols; /* spread out if possible */ 263 1.19 lukem numrows = num / numcols; 264 1.19 lukem if (num % numcols) 265 1.19 lukem ++numrows; 266 1.19 lukem 267 1.19 lukem for (row = 0; row < numrows; ++row) { 268 1.19 lukem for (base = row, chcnt = col = 0; col < numcols; ++col) { 269 1.19 lukem chcnt = printaname(array[base], dp->s_inode, 270 1.38 grant f_humanize ? dp->s_size : dp->s_block); 271 1.19 lukem if ((base += numrows) >= num) 272 1.19 lukem break; 273 1.19 lukem while (chcnt++ < colwidth) 274 1.22 mycroft (void)putchar(' '); 275 1.19 lukem } 276 1.19 lukem (void)putchar('\n'); 277 1.19 lukem } 278 1.19 lukem } 279 1.19 lukem 280 1.19 lukem void 281 1.30 lukem printacol(DISPLAY *dp) 282 1.19 lukem { 283 1.19 lukem FTSENT *p; 284 1.19 lukem int chcnt, col, colwidth; 285 1.19 lukem int numcols; 286 1.19 lukem 287 1.5 mycroft colwidth = dp->maxlen; 288 1.1 cgd if (f_inode) 289 1.5 mycroft colwidth += dp->s_inode + 1; 290 1.38 grant if (f_size) { 291 1.38 grant if (f_humanize) 292 1.38 grant colwidth += dp->s_size + 1; 293 1.38 grant else 294 1.38 grant colwidth += dp->s_block + 1; 295 1.38 grant } 296 1.26 kleink if (f_type || f_typedir) 297 1.1 cgd colwidth += 1; 298 1.1 cgd 299 1.15 thorpej colwidth += 1; 300 1.15 thorpej 301 1.58 jschauma printtotal(dp); /* "total: %u\n" */ 302 1.58 jschauma 303 1.1 cgd if (termwidth < 2 * colwidth) { 304 1.5 mycroft printscol(dp); 305 1.1 cgd return; 306 1.1 cgd } 307 1.1 cgd 308 1.1 cgd numcols = termwidth / colwidth; 309 1.15 thorpej colwidth = termwidth / numcols; /* spread out if possible */ 310 1.1 cgd 311 1.19 lukem chcnt = col = 0; 312 1.19 lukem for (p = dp->list; p; p = p->fts_link) { 313 1.19 lukem if (IS_NOPRINT(p)) 314 1.19 lukem continue; 315 1.19 lukem if (col >= numcols) { 316 1.19 lukem chcnt = col = 0; 317 1.22 mycroft (void)putchar('\n'); 318 1.1 cgd } 319 1.38 grant chcnt = printaname(p, dp->s_inode, 320 1.38 grant f_humanize ? dp->s_size : dp->s_block); 321 1.19 lukem while (chcnt++ < colwidth) 322 1.22 mycroft (void)putchar(' '); 323 1.19 lukem col++; 324 1.25 kleink } 325 1.25 kleink (void)putchar('\n'); 326 1.25 kleink } 327 1.25 kleink 328 1.25 kleink void 329 1.30 lukem printstream(DISPLAY *dp) 330 1.25 kleink { 331 1.25 kleink FTSENT *p; 332 1.25 kleink int col; 333 1.25 kleink int extwidth; 334 1.25 kleink 335 1.25 kleink extwidth = 0; 336 1.25 kleink if (f_inode) 337 1.25 kleink extwidth += dp->s_inode + 1; 338 1.38 grant if (f_size) { 339 1.38 grant if (f_humanize) 340 1.38 grant extwidth += dp->s_size + 1; 341 1.38 grant else 342 1.38 grant extwidth += dp->s_block + 1; 343 1.38 grant } 344 1.25 kleink if (f_type) 345 1.25 kleink extwidth += 1; 346 1.25 kleink 347 1.25 kleink for (col = 0, p = dp->list; p != NULL; p = p->fts_link) { 348 1.25 kleink if (IS_NOPRINT(p)) 349 1.25 kleink continue; 350 1.25 kleink if (col > 0) { 351 1.25 kleink (void)putchar(','), col++; 352 1.45 lukem if (col + 1 + extwidth + (int)p->fts_namelen >= termwidth) 353 1.25 kleink (void)putchar('\n'), col = 0; 354 1.25 kleink else 355 1.25 kleink (void)putchar(' '), col++; 356 1.25 kleink } 357 1.38 grant col += printaname(p, dp->s_inode, 358 1.38 grant f_humanize ? dp->s_size : dp->s_block); 359 1.1 cgd } 360 1.22 mycroft (void)putchar('\n'); 361 1.1 cgd } 362 1.1 cgd 363 1.1 cgd /* 364 1.1 cgd * print [inode] [size] name 365 1.5 mycroft * return # of characters printed, no trailing characters. 366 1.1 cgd */ 367 1.5 mycroft static int 368 1.30 lukem printaname(FTSENT *p, int inodefield, int sizefield) 369 1.1 cgd { 370 1.5 mycroft struct stat *sp; 371 1.1 cgd int chcnt; 372 1.38 grant char szbuf[5]; 373 1.1 cgd 374 1.5 mycroft sp = p->fts_statp; 375 1.1 cgd chcnt = 0; 376 1.1 cgd if (f_inode) 377 1.55 martin chcnt += printf("%*"PRIu64" ", inodefield, sp->st_ino); 378 1.38 grant if (f_size) { 379 1.38 grant if (f_humanize) { 380 1.38 grant if ((humanize_number(szbuf, sizeof(szbuf), sp->st_size, 381 1.38 grant "", HN_AUTOSCALE, 382 1.38 grant (HN_DECIMAL | HN_B | HN_NOSPACE))) == -1) 383 1.38 grant err(1, "humanize_number"); 384 1.38 grant chcnt += printf("%*s ", sizefield, szbuf); 385 1.38 grant } else { 386 1.50 christos chcnt += printf(f_commas ? "%'*llu " : "%*llu ", 387 1.50 christos sizefield, (unsigned long long) 388 1.50 christos howmany(sp->st_blocks, blocksize)); 389 1.38 grant } 390 1.38 grant } 391 1.37 jschauma if (f_octal || f_octal_escape) 392 1.53 christos chcnt += safe_printpath(p); 393 1.36 jschauma else if (f_nonprint) 394 1.53 christos chcnt += printescapedpath(p); 395 1.29 assar else 396 1.53 christos chcnt += printpath(p); 397 1.26 kleink if (f_type || (f_typedir && S_ISDIR(sp->st_mode))) 398 1.5 mycroft chcnt += printtype(sp->st_mode); 399 1.5 mycroft return (chcnt); 400 1.1 cgd } 401 1.1 cgd 402 1.5 mycroft static void 403 1.30 lukem printtime(time_t ftime) 404 1.1 cgd { 405 1.1 cgd int i; 406 1.46 christos const char *longstring; 407 1.1 cgd 408 1.47 christos if ((longstring = ctime(&ftime)) == NULL) { 409 1.46 christos /* 012345678901234567890123 */ 410 1.46 christos longstring = "????????????????????????"; 411 1.46 christos } 412 1.1 cgd for (i = 4; i < 11; ++i) 413 1.1 cgd (void)putchar(longstring[i]); 414 1.1 cgd 415 1.1 cgd #define SIXMONTHS ((DAYSPERNYEAR / 2) * SECSPERDAY) 416 1.1 cgd if (f_sectime) 417 1.1 cgd for (i = 11; i < 24; i++) 418 1.1 cgd (void)putchar(longstring[i]); 419 1.40 mycroft else if (ftime + SIXMONTHS > now && ftime - SIXMONTHS < now) 420 1.1 cgd for (i = 11; i < 16; ++i) 421 1.1 cgd (void)putchar(longstring[i]); 422 1.1 cgd else { 423 1.1 cgd (void)putchar(' '); 424 1.1 cgd for (i = 20; i < 24; ++i) 425 1.1 cgd (void)putchar(longstring[i]); 426 1.1 cgd } 427 1.1 cgd (void)putchar(' '); 428 1.1 cgd } 429 1.1 cgd 430 1.43 ahoka /* 431 1.43 ahoka * Display total used disk space in the form "total: %u\n". 432 1.43 ahoka * Note: POSIX (IEEE Std 1003.1-2001) says this should be always in 512 blocks, 433 1.49 erh * but we humanise it with -h, or separate it with commas with -M, and use 1024 434 1.49 erh * with -k. 435 1.43 ahoka */ 436 1.43 ahoka static void 437 1.43 ahoka printtotal(DISPLAY *dp) 438 1.43 ahoka { 439 1.43 ahoka char szbuf[5]; 440 1.43 ahoka 441 1.43 ahoka if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) { 442 1.43 ahoka if (f_humanize) { 443 1.59 simonb if ((humanize_number(szbuf, sizeof(szbuf), 444 1.59 simonb dp->btotal * POSIX_BLOCK_SIZE, 445 1.43 ahoka "", HN_AUTOSCALE, 446 1.43 ahoka (HN_DECIMAL | HN_B | HN_NOSPACE))) == -1) 447 1.43 ahoka err(1, "humanize_number"); 448 1.43 ahoka (void)printf("total %s\n", szbuf); 449 1.43 ahoka } else { 450 1.50 christos (void)printf(f_commas ? "total %'llu\n" : 451 1.50 christos "total %llu\n", (unsigned long long) 452 1.50 christos howmany(dp->btotal, blocksize)); 453 1.43 ahoka } 454 1.43 ahoka } 455 1.43 ahoka } 456 1.43 ahoka 457 1.5 mycroft static int 458 1.30 lukem printtype(u_int mode) 459 1.1 cgd { 460 1.11 mycroft switch (mode & S_IFMT) { 461 1.1 cgd case S_IFDIR: 462 1.1 cgd (void)putchar('/'); 463 1.5 mycroft return (1); 464 1.11 mycroft case S_IFIFO: 465 1.11 mycroft (void)putchar('|'); 466 1.11 mycroft return (1); 467 1.1 cgd case S_IFLNK: 468 1.1 cgd (void)putchar('@'); 469 1.5 mycroft return (1); 470 1.1 cgd case S_IFSOCK: 471 1.1 cgd (void)putchar('='); 472 1.12 mycroft return (1); 473 1.12 mycroft case S_IFWHT: 474 1.12 mycroft (void)putchar('%'); 475 1.6 jtc return (1); 476 1.1 cgd } 477 1.1 cgd if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { 478 1.1 cgd (void)putchar('*'); 479 1.5 mycroft return (1); 480 1.1 cgd } 481 1.5 mycroft return (0); 482 1.1 cgd } 483 1.1 cgd 484 1.5 mycroft static void 485 1.30 lukem printlink(FTSENT *p) 486 1.1 cgd { 487 1.1 cgd int lnklen; 488 1.5 mycroft char name[MAXPATHLEN + 1], path[MAXPATHLEN + 1]; 489 1.5 mycroft 490 1.5 mycroft if (p->fts_level == FTS_ROOTLEVEL) 491 1.5 mycroft (void)snprintf(name, sizeof(name), "%s", p->fts_name); 492 1.33 enami else 493 1.11 mycroft (void)snprintf(name, sizeof(name), 494 1.11 mycroft "%s/%s", p->fts_parent->fts_accpath, p->fts_name); 495 1.11 mycroft if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) { 496 1.1 cgd (void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno)); 497 1.1 cgd return; 498 1.1 cgd } 499 1.1 cgd path[lnklen] = '\0'; 500 1.28 assar (void)printf(" -> "); 501 1.37 jschauma if (f_octal || f_octal_escape) 502 1.36 jschauma (void)safe_print(path); 503 1.36 jschauma else if (f_nonprint) 504 1.36 jschauma (void)printescaped(path); 505 1.28 assar else 506 1.28 assar (void)printf("%s", path); 507 1.1 cgd } 508 1.56 christos 509 1.57 christos #ifndef SMALL 510 1.56 christos /* 511 1.56 christos * Add a + after the standard rwxrwxrwx mode if the file has an 512 1.56 christos * ACL. strmode() reserves space at the end of the string. 513 1.56 christos */ 514 1.56 christos static void 515 1.56 christos aclmode(char *buf, const FTSENT *p) 516 1.56 christos { 517 1.56 christos char name[MAXPATHLEN + 1]; 518 1.56 christos int ret, trivial; 519 1.56 christos static dev_t previous_dev = NODEV; 520 1.56 christos static int supports_acls = -1; 521 1.56 christos static int type = ACL_TYPE_ACCESS; 522 1.56 christos acl_t facl; 523 1.56 christos 524 1.56 christos /* 525 1.56 christos * XXX: ACLs are not supported on whiteouts and device files 526 1.56 christos * residing on UFS. 527 1.56 christos */ 528 1.56 christos if (S_ISCHR(p->fts_statp->st_mode) || S_ISBLK(p->fts_statp->st_mode) || 529 1.56 christos S_ISWHT(p->fts_statp->st_mode)) 530 1.56 christos return; 531 1.56 christos 532 1.56 christos if (previous_dev == p->fts_statp->st_dev && supports_acls == 0) 533 1.56 christos return; 534 1.56 christos 535 1.56 christos if (p->fts_level == FTS_ROOTLEVEL) 536 1.56 christos snprintf(name, sizeof(name), "%s", p->fts_name); 537 1.56 christos else 538 1.56 christos snprintf(name, sizeof(name), "%s/%s", 539 1.56 christos p->fts_parent->fts_accpath, p->fts_name); 540 1.56 christos 541 1.56 christos if (supports_acls == -1 || previous_dev != p->fts_statp->st_dev) { 542 1.56 christos previous_dev = p->fts_statp->st_dev; 543 1.56 christos supports_acls = 0; 544 1.56 christos 545 1.56 christos ret = lpathconf(name, _PC_ACL_NFS4); 546 1.56 christos if (ret > 0) { 547 1.56 christos type = ACL_TYPE_NFS4; 548 1.56 christos supports_acls = 1; 549 1.56 christos } else if (ret < 0 && errno != EINVAL) { 550 1.56 christos warn("%s", name); 551 1.56 christos return; 552 1.56 christos } 553 1.56 christos if (supports_acls == 0) { 554 1.56 christos ret = lpathconf(name, _PC_ACL_EXTENDED); 555 1.56 christos if (ret > 0) { 556 1.56 christos type = ACL_TYPE_ACCESS; 557 1.56 christos supports_acls = 1; 558 1.56 christos } else if (ret < 0 && errno != EINVAL) { 559 1.56 christos warn("%s", name); 560 1.56 christos return; 561 1.56 christos } 562 1.56 christos } 563 1.56 christos } 564 1.56 christos if (supports_acls == 0) 565 1.56 christos return; 566 1.56 christos facl = acl_get_link_np(name, type); 567 1.56 christos if (facl == NULL) { 568 1.56 christos warn("%s", name); 569 1.56 christos return; 570 1.56 christos } 571 1.56 christos if (acl_is_trivial_np(facl, &trivial)) { 572 1.56 christos acl_free(facl); 573 1.56 christos warn("%s", name); 574 1.56 christos return; 575 1.56 christos } 576 1.56 christos if (!trivial) 577 1.56 christos buf[10] = '+'; 578 1.56 christos acl_free(facl); 579 1.56 christos } 580 1.57 christos #endif 581