1*60425338Scf46844 /* Portions Copyright 2006 Stephen P. Potter */ 2*60425338Scf46844 37c478bd9Sstevel@tonic-gate /* 4524e558aScf46844 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 57c478bd9Sstevel@tonic-gate * Use is subject to license terms. 67c478bd9Sstevel@tonic-gate */ 77c478bd9Sstevel@tonic-gate 87c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 97c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 107c478bd9Sstevel@tonic-gate 117c478bd9Sstevel@tonic-gate /* 127c478bd9Sstevel@tonic-gate * Copyright (c) 1980 Regents of the University of California. 137c478bd9Sstevel@tonic-gate * All rights reserved. The Berkeley software License Agreement 147c478bd9Sstevel@tonic-gate * specifies the terms and conditions for redistribution. 157c478bd9Sstevel@tonic-gate */ 167c478bd9Sstevel@tonic-gate 177c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 187c478bd9Sstevel@tonic-gate 197c478bd9Sstevel@tonic-gate /* 207c478bd9Sstevel@tonic-gate * ls 217c478bd9Sstevel@tonic-gate * 227c478bd9Sstevel@tonic-gate * 4.2bsd version for symbolic links, variable length 237c478bd9Sstevel@tonic-gate * directory entries, block size in the inode, etc. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <stdio.h> 277c478bd9Sstevel@tonic-gate #include <stdlib.h> 287c478bd9Sstevel@tonic-gate #include <unistd.h> 297c478bd9Sstevel@tonic-gate #include <string.h> 307c478bd9Sstevel@tonic-gate #include <stddef.h> 317c478bd9Sstevel@tonic-gate #include <dirent.h> 327c478bd9Sstevel@tonic-gate #include <ctype.h> 337c478bd9Sstevel@tonic-gate #include <time.h> 347c478bd9Sstevel@tonic-gate #include <limits.h> 357c478bd9Sstevel@tonic-gate #include <locale.h> 367c478bd9Sstevel@tonic-gate #include <errno.h> 377c478bd9Sstevel@tonic-gate #include <sys/types.h> 387c478bd9Sstevel@tonic-gate #include <sys/param.h> 397c478bd9Sstevel@tonic-gate #include <sys/stat.h> 407c478bd9Sstevel@tonic-gate #include <sys/termios.h> 417c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 427c478bd9Sstevel@tonic-gate #include <sys/acl.h> 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate #define dbtokb(nb) ((nb) / (1024 / DEV_BSIZE)) 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate struct afile { 477c478bd9Sstevel@tonic-gate char ftype; /* file type, e.g. 'd', 'c', 'f' */ 487c478bd9Sstevel@tonic-gate ino_t fnum; /* inode number of file */ 497c478bd9Sstevel@tonic-gate short fflags; /* mode&~S_IFMT, perhaps ISARG */ 507c478bd9Sstevel@tonic-gate nlink_t fnl; /* number of links */ 517c478bd9Sstevel@tonic-gate uid_t fuid; /* owner id */ 527c478bd9Sstevel@tonic-gate gid_t fgid; /* group id */ 537c478bd9Sstevel@tonic-gate off_t fsize; /* file size */ 547c478bd9Sstevel@tonic-gate blkcnt_t fblks; /* number of blocks used */ 557c478bd9Sstevel@tonic-gate time_t fmtime; /* time (modify or access or create) */ 567c478bd9Sstevel@tonic-gate char *fname; /* file name */ 577c478bd9Sstevel@tonic-gate char *flinkto; /* symbolic link value */ 587c478bd9Sstevel@tonic-gate char acl; /* acl access flag */ 597c478bd9Sstevel@tonic-gate }; 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate #define ISARG 0x8000 /* extra ``mode'' */ 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate static struct subdirs { 647c478bd9Sstevel@tonic-gate char *sd_name; 657c478bd9Sstevel@tonic-gate struct subdirs *sd_next; 667c478bd9Sstevel@tonic-gate } *subdirs; 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate static int aflg, dflg, gflg, lflg, sflg, tflg, uflg, iflg, fflg, cflg; 697c478bd9Sstevel@tonic-gate static int rflg = 1; 707c478bd9Sstevel@tonic-gate static int qflg, Aflg, Cflg, Fflg, Lflg, Rflg; 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate static int usetabs; 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate static time_t now, sixmonthsago, onehourfromnow; 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate static char *dotp = "."; 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate static struct winsize win; 797c478bd9Sstevel@tonic-gate static int twidth; 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate static struct afile *gstat(struct afile *, char *, int, off_t *); 827c478bd9Sstevel@tonic-gate static int fcmp(const void *, const void *); 837c478bd9Sstevel@tonic-gate static char *cat(char *, char *); 847c478bd9Sstevel@tonic-gate static char *savestr(char *); 857c478bd9Sstevel@tonic-gate static char *fmtentry(struct afile *); 867c478bd9Sstevel@tonic-gate static char *getname(), *getgroup(); 877c478bd9Sstevel@tonic-gate static void formatd(char *, int); 887c478bd9Sstevel@tonic-gate static void formatf(struct afile *, struct afile *); 897c478bd9Sstevel@tonic-gate static off_t getdir(char *, struct afile **, struct afile **); 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate int 927c478bd9Sstevel@tonic-gate main(int argc, char **argv) 937c478bd9Sstevel@tonic-gate { 947c478bd9Sstevel@tonic-gate int i; 957c478bd9Sstevel@tonic-gate struct afile *fp0, *fplast; 967c478bd9Sstevel@tonic-gate register struct afile *fp; 977c478bd9Sstevel@tonic-gate struct termios trbuf; 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate argc--, argv++; 1007c478bd9Sstevel@tonic-gate if (getuid() == 0) 1017c478bd9Sstevel@tonic-gate Aflg++; 1027c478bd9Sstevel@tonic-gate (void) time(&now); 1037c478bd9Sstevel@tonic-gate sixmonthsago = now - 6L*30L*24L*60L*60L; 1047c478bd9Sstevel@tonic-gate onehourfromnow = now + 60L*60L; 1057c478bd9Sstevel@tonic-gate now += 60; 1067c478bd9Sstevel@tonic-gate twidth = 80; 1077c478bd9Sstevel@tonic-gate if (isatty(1)) { 1087c478bd9Sstevel@tonic-gate qflg = Cflg = 1; 1097c478bd9Sstevel@tonic-gate (void) ioctl(1, TCGETS, &trbuf); 1107c478bd9Sstevel@tonic-gate if (ioctl(1, TIOCGWINSZ, &win) != -1) 1117c478bd9Sstevel@tonic-gate twidth = (win.ws_col == 0 ? 80 : win.ws_col); 1127c478bd9Sstevel@tonic-gate if ((trbuf.c_oflag & TABDLY) != TAB3) 1137c478bd9Sstevel@tonic-gate usetabs = 1; 1147c478bd9Sstevel@tonic-gate } else 1157c478bd9Sstevel@tonic-gate usetabs = 1; 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); /* set local environment */ 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate while (argc > 0 && **argv == '-') { 1207c478bd9Sstevel@tonic-gate (*argv)++; 1217c478bd9Sstevel@tonic-gate while (**argv) { 1227c478bd9Sstevel@tonic-gate switch (*(*argv)++) { 1237c478bd9Sstevel@tonic-gate case 'C': 1247c478bd9Sstevel@tonic-gate Cflg = 1; break; 1257c478bd9Sstevel@tonic-gate case 'q': 1267c478bd9Sstevel@tonic-gate qflg = 1; break; 1277c478bd9Sstevel@tonic-gate case '1': 1287c478bd9Sstevel@tonic-gate Cflg = 0; break; 1297c478bd9Sstevel@tonic-gate case 'a': 1307c478bd9Sstevel@tonic-gate aflg++; break; 1317c478bd9Sstevel@tonic-gate case 'A': 1327c478bd9Sstevel@tonic-gate Aflg++; break; 1337c478bd9Sstevel@tonic-gate case 'c': 1347c478bd9Sstevel@tonic-gate cflg++; break; 1357c478bd9Sstevel@tonic-gate case 's': 1367c478bd9Sstevel@tonic-gate sflg++; break; 1377c478bd9Sstevel@tonic-gate case 'd': 1387c478bd9Sstevel@tonic-gate dflg++; break; 1397c478bd9Sstevel@tonic-gate case 'g': 1407c478bd9Sstevel@tonic-gate gflg++; break; 1417c478bd9Sstevel@tonic-gate case 'l': 1427c478bd9Sstevel@tonic-gate lflg++; break; 1437c478bd9Sstevel@tonic-gate case 'r': 1447c478bd9Sstevel@tonic-gate rflg = -1; break; 1457c478bd9Sstevel@tonic-gate case 't': 1467c478bd9Sstevel@tonic-gate tflg++; break; 1477c478bd9Sstevel@tonic-gate case 'u': 1487c478bd9Sstevel@tonic-gate uflg++; break; 1497c478bd9Sstevel@tonic-gate case 'i': 1507c478bd9Sstevel@tonic-gate iflg++; break; 1517c478bd9Sstevel@tonic-gate case 'f': 1527c478bd9Sstevel@tonic-gate fflg++; break; 1537c478bd9Sstevel@tonic-gate case 'L': 1547c478bd9Sstevel@tonic-gate Lflg++; break; 1557c478bd9Sstevel@tonic-gate case 'F': 1567c478bd9Sstevel@tonic-gate Fflg++; break; 1577c478bd9Sstevel@tonic-gate case 'R': 1587c478bd9Sstevel@tonic-gate Rflg++; break; 1597c478bd9Sstevel@tonic-gate } 1607c478bd9Sstevel@tonic-gate } 1617c478bd9Sstevel@tonic-gate argc--, argv++; 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate if (fflg) { 1647c478bd9Sstevel@tonic-gate aflg++; lflg = 0; sflg = 0; tflg = 0; 1657c478bd9Sstevel@tonic-gate } 1667c478bd9Sstevel@tonic-gate if (lflg) 1677c478bd9Sstevel@tonic-gate Cflg = 0; 1687c478bd9Sstevel@tonic-gate if (argc == 0) { 1697c478bd9Sstevel@tonic-gate argc++; 1707c478bd9Sstevel@tonic-gate argv = &dotp; 1717c478bd9Sstevel@tonic-gate } 1727c478bd9Sstevel@tonic-gate fp = (struct afile *)calloc(argc, sizeof (struct afile)); 1737c478bd9Sstevel@tonic-gate if (fp == 0) { 1747c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "ls: out of memory\n"); 1757c478bd9Sstevel@tonic-gate exit(1); 1767c478bd9Sstevel@tonic-gate } 1777c478bd9Sstevel@tonic-gate fp0 = fp; 1787c478bd9Sstevel@tonic-gate for (i = 0; i < argc; i++) { 1797c478bd9Sstevel@tonic-gate if (gstat(fp, *argv, 1, (off_t *)0)) { 1807c478bd9Sstevel@tonic-gate fp->fname = *argv; 1817c478bd9Sstevel@tonic-gate fp->fflags |= ISARG; 1827c478bd9Sstevel@tonic-gate fp++; 1837c478bd9Sstevel@tonic-gate } 1847c478bd9Sstevel@tonic-gate argv++; 1857c478bd9Sstevel@tonic-gate } 1867c478bd9Sstevel@tonic-gate fplast = fp; 1877c478bd9Sstevel@tonic-gate qsort(fp0, fplast - fp0, sizeof (struct afile), fcmp); 1887c478bd9Sstevel@tonic-gate if (dflg) { 1897c478bd9Sstevel@tonic-gate formatf(fp0, fplast); 1907c478bd9Sstevel@tonic-gate exit(0); 1917c478bd9Sstevel@tonic-gate } 1927c478bd9Sstevel@tonic-gate if (fflg) 1937c478bd9Sstevel@tonic-gate fp = fp0; 1947c478bd9Sstevel@tonic-gate else { 1957c478bd9Sstevel@tonic-gate for (fp = fp0; fp < fplast && fp->ftype != 'd'; fp++) 1967c478bd9Sstevel@tonic-gate continue; 1977c478bd9Sstevel@tonic-gate formatf(fp0, fp); 1987c478bd9Sstevel@tonic-gate } 1997c478bd9Sstevel@tonic-gate if (fp < fplast) { 2007c478bd9Sstevel@tonic-gate if (fp > fp0) 2017c478bd9Sstevel@tonic-gate (void) printf("\n"); 2027c478bd9Sstevel@tonic-gate for (;;) { 2037c478bd9Sstevel@tonic-gate formatd(fp->fname, argc > 1); 2047c478bd9Sstevel@tonic-gate while (subdirs) { 2057c478bd9Sstevel@tonic-gate struct subdirs *t; 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate t = subdirs; subdirs = t->sd_next; 2087c478bd9Sstevel@tonic-gate (void) printf("\n"); 2097c478bd9Sstevel@tonic-gate formatd(t->sd_name, 1); 2107c478bd9Sstevel@tonic-gate free(t->sd_name); 2117c478bd9Sstevel@tonic-gate free(t); 2127c478bd9Sstevel@tonic-gate } 2137c478bd9Sstevel@tonic-gate if (++fp == fplast) 2147c478bd9Sstevel@tonic-gate break; 2157c478bd9Sstevel@tonic-gate (void) printf("\n"); 2167c478bd9Sstevel@tonic-gate } 2177c478bd9Sstevel@tonic-gate } 2187c478bd9Sstevel@tonic-gate return (0); 2197c478bd9Sstevel@tonic-gate } 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate static void 2227c478bd9Sstevel@tonic-gate formatd(char *name, int title) 2237c478bd9Sstevel@tonic-gate { 2247c478bd9Sstevel@tonic-gate register struct afile *fp; 2257c478bd9Sstevel@tonic-gate register struct subdirs *dp; 2267c478bd9Sstevel@tonic-gate struct afile *dfp0, *dfplast; 2277c478bd9Sstevel@tonic-gate off_t nkb; 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate nkb = getdir(name, &dfp0, &dfplast); 2307c478bd9Sstevel@tonic-gate if (dfp0 == 0) 2317c478bd9Sstevel@tonic-gate return; 2327c478bd9Sstevel@tonic-gate if (fflg == 0) 2337c478bd9Sstevel@tonic-gate qsort(dfp0, dfplast - dfp0, sizeof (struct afile), fcmp); 2347c478bd9Sstevel@tonic-gate if (title) 2357c478bd9Sstevel@tonic-gate (void) printf("%s:\n", name); 2367c478bd9Sstevel@tonic-gate if (lflg || sflg) 2377c478bd9Sstevel@tonic-gate (void) printf("total %lld\n", nkb); 2387c478bd9Sstevel@tonic-gate formatf(dfp0, dfplast); 2397c478bd9Sstevel@tonic-gate if (Rflg) 2407c478bd9Sstevel@tonic-gate for (fp = dfplast - 1; fp >= dfp0; fp--) { 2417c478bd9Sstevel@tonic-gate if (fp->ftype != 'd' || 2427c478bd9Sstevel@tonic-gate strcmp(fp->fname, ".") == 0 || 2437c478bd9Sstevel@tonic-gate strcmp(fp->fname, "..") == 0) 2447c478bd9Sstevel@tonic-gate continue; 2457c478bd9Sstevel@tonic-gate dp = (struct subdirs *)malloc(sizeof (struct subdirs)); 2467c478bd9Sstevel@tonic-gate dp->sd_name = savestr(cat(name, fp->fname)); 2477c478bd9Sstevel@tonic-gate dp->sd_next = subdirs; subdirs = dp; 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate for (fp = dfp0; fp < dfplast; fp++) { 2507c478bd9Sstevel@tonic-gate if ((fp->fflags&ISARG) == 0 && fp->fname) 2517c478bd9Sstevel@tonic-gate free(fp->fname); 2527c478bd9Sstevel@tonic-gate if (fp->flinkto) 2537c478bd9Sstevel@tonic-gate free(fp->flinkto); 2547c478bd9Sstevel@tonic-gate } 2557c478bd9Sstevel@tonic-gate free(dfp0); 2567c478bd9Sstevel@tonic-gate } 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate static off_t 2597c478bd9Sstevel@tonic-gate getdir(char *dir, struct afile **pfp0, struct afile **pfplast) 2607c478bd9Sstevel@tonic-gate { 2617c478bd9Sstevel@tonic-gate register struct afile *fp; 2627c478bd9Sstevel@tonic-gate DIR *dirp; 2637c478bd9Sstevel@tonic-gate register struct dirent *dp; 2647c478bd9Sstevel@tonic-gate off_t nb; 2657c478bd9Sstevel@tonic-gate size_t nent = 20; 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate /* 2687c478bd9Sstevel@tonic-gate * This code (opendir, readdir, and the "for" loop) is arranged in 2697c478bd9Sstevel@tonic-gate * this strange manner to handle the case where UNIX lets root open 2707c478bd9Sstevel@tonic-gate * any directory for reading, but NFS does not let root read the 2717c478bd9Sstevel@tonic-gate * openned directory. 2727c478bd9Sstevel@tonic-gate */ 2737c478bd9Sstevel@tonic-gate *pfp0 = *pfplast = NULL; 2747c478bd9Sstevel@tonic-gate if ((dirp = opendir(dir)) == NULL) { 2757c478bd9Sstevel@tonic-gate (void) printf("%s unreadable\n", dir); /* not stderr! */ 2767c478bd9Sstevel@tonic-gate return (0); 2777c478bd9Sstevel@tonic-gate } 2787c478bd9Sstevel@tonic-gate errno = 0; 2797c478bd9Sstevel@tonic-gate if (((dp = readdir(dirp)) == NULL) && (errno != 0)) { 2807c478bd9Sstevel@tonic-gate /* root reading across NFS can get to this error case */ 2817c478bd9Sstevel@tonic-gate (void) printf("%s unreadable\n", dir); /* not stderr! */ 2827c478bd9Sstevel@tonic-gate (void) closedir(dirp); 2837c478bd9Sstevel@tonic-gate return (0); 2847c478bd9Sstevel@tonic-gate } 2857c478bd9Sstevel@tonic-gate fp = *pfp0 = (struct afile *)calloc(nent, sizeof (struct afile)); 2867c478bd9Sstevel@tonic-gate *pfplast = *pfp0 + nent; 2877c478bd9Sstevel@tonic-gate for (nb = 0; dp != NULL; dp = readdir(dirp)) { 2887c478bd9Sstevel@tonic-gate if (dp->d_ino == 0) 2897c478bd9Sstevel@tonic-gate continue; 2907c478bd9Sstevel@tonic-gate if (aflg == 0 && dp->d_name[0] == '.' && 2917c478bd9Sstevel@tonic-gate (Aflg == 0 || dp->d_name[1] == 0 || 2927c478bd9Sstevel@tonic-gate dp->d_name[1] == '.' && dp->d_name[2] == 0)) 2937c478bd9Sstevel@tonic-gate continue; 2947c478bd9Sstevel@tonic-gate if (gstat(fp, cat(dir, dp->d_name), Fflg+Rflg, &nb) == 0) 2957c478bd9Sstevel@tonic-gate continue; 2967c478bd9Sstevel@tonic-gate fp->fnum = dp->d_ino; 2977c478bd9Sstevel@tonic-gate fp->fname = savestr(dp->d_name); 2987c478bd9Sstevel@tonic-gate fp++; 2997c478bd9Sstevel@tonic-gate if (fp == *pfplast) { 3007c478bd9Sstevel@tonic-gate *pfp0 = (struct afile *)realloc((char *)*pfp0, 3017c478bd9Sstevel@tonic-gate 2 * nent * sizeof (struct afile)); 3027c478bd9Sstevel@tonic-gate if (*pfp0 == 0) { 3037c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "ls: out of memory\n"); 3047c478bd9Sstevel@tonic-gate exit(1); 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate fp = *pfp0 + nent; 3077c478bd9Sstevel@tonic-gate *pfplast = fp + nent; 3087c478bd9Sstevel@tonic-gate nent *= 2; 3097c478bd9Sstevel@tonic-gate } 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate (void) closedir(dirp); 3127c478bd9Sstevel@tonic-gate *pfplast = fp; 3137c478bd9Sstevel@tonic-gate return (dbtokb(nb)); 3147c478bd9Sstevel@tonic-gate } 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate static struct afile * 3187c478bd9Sstevel@tonic-gate gstat(struct afile *fp, char *file, int statarg, off_t *pnb) 3197c478bd9Sstevel@tonic-gate { 3207c478bd9Sstevel@tonic-gate static struct afile azerofile; 3217c478bd9Sstevel@tonic-gate int (*statf)() = Lflg ? stat : lstat; 3227c478bd9Sstevel@tonic-gate int cc; 3237c478bd9Sstevel@tonic-gate char buf[PATH_MAX]; 3247c478bd9Sstevel@tonic-gate int aclcnt; 3257c478bd9Sstevel@tonic-gate aclent_t *aclp; 3267c478bd9Sstevel@tonic-gate aclent_t *tp; 3277c478bd9Sstevel@tonic-gate o_mode_t groupperm, mask; 3287c478bd9Sstevel@tonic-gate int grouppermfound, maskfound; 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate *fp = azerofile; 3317c478bd9Sstevel@tonic-gate fp->fflags = 0; 3327c478bd9Sstevel@tonic-gate fp->fnum = 0; 3337c478bd9Sstevel@tonic-gate fp->ftype = '-'; 3347c478bd9Sstevel@tonic-gate if (statarg || sflg || lflg || tflg) { 3357c478bd9Sstevel@tonic-gate struct stat stb, stb1; 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate if ((*statf)(file, &stb) < 0) { 3387c478bd9Sstevel@tonic-gate if (statf == lstat || lstat(file, &stb) < 0) { 3397c478bd9Sstevel@tonic-gate if (errno == ENOENT) 3407c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 3417c478bd9Sstevel@tonic-gate "%s not found\n", file); 3427c478bd9Sstevel@tonic-gate else { 3437c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "ls: "); 3447c478bd9Sstevel@tonic-gate perror(file); 3457c478bd9Sstevel@tonic-gate } 3467c478bd9Sstevel@tonic-gate return (0); 3477c478bd9Sstevel@tonic-gate } 3487c478bd9Sstevel@tonic-gate } 3497c478bd9Sstevel@tonic-gate fp->fblks = stb.st_blocks; 3507c478bd9Sstevel@tonic-gate fp->fsize = stb.st_size; 3517c478bd9Sstevel@tonic-gate switch (stb.st_mode & S_IFMT) { 3527c478bd9Sstevel@tonic-gate case S_IFDIR: 3537c478bd9Sstevel@tonic-gate fp->ftype = 'd'; break; 3547c478bd9Sstevel@tonic-gate case S_IFDOOR: 3557c478bd9Sstevel@tonic-gate fp->ftype = 'D'; break; 3567c478bd9Sstevel@tonic-gate case S_IFBLK: 3577c478bd9Sstevel@tonic-gate fp->ftype = 'b'; fp->fsize = (off_t)stb.st_rdev; break; 3587c478bd9Sstevel@tonic-gate case S_IFCHR: 3597c478bd9Sstevel@tonic-gate fp->ftype = 'c'; fp->fsize = (off_t)stb.st_rdev; break; 3607c478bd9Sstevel@tonic-gate case S_IFSOCK: 3617c478bd9Sstevel@tonic-gate fp->ftype = 's'; fp->fsize = 0LL; break; 3627c478bd9Sstevel@tonic-gate case S_IFIFO: 3637c478bd9Sstevel@tonic-gate fp->ftype = 'p'; fp->fsize = 0LL; break; 3647c478bd9Sstevel@tonic-gate case S_IFLNK: 3657c478bd9Sstevel@tonic-gate fp->ftype = 'l'; 3667c478bd9Sstevel@tonic-gate if (lflg) { 3677c478bd9Sstevel@tonic-gate cc = readlink(file, buf, BUFSIZ); 3687c478bd9Sstevel@tonic-gate if (cc >= 0) { 3697c478bd9Sstevel@tonic-gate /* 3707c478bd9Sstevel@tonic-gate * here we follow the symbolic 3717c478bd9Sstevel@tonic-gate * link to generate the proper 3727c478bd9Sstevel@tonic-gate * Fflg marker for the object, 3737c478bd9Sstevel@tonic-gate * eg, /bin -> /pub/bin/ 3747c478bd9Sstevel@tonic-gate */ 3757c478bd9Sstevel@tonic-gate buf[cc] = 0; 3767c478bd9Sstevel@tonic-gate if (Fflg && !stat(file, &stb1)) 3777c478bd9Sstevel@tonic-gate switch (stb1.st_mode & S_IFMT) { 3787c478bd9Sstevel@tonic-gate case S_IFDIR: 3797c478bd9Sstevel@tonic-gate buf[cc++] = '/'; 3807c478bd9Sstevel@tonic-gate break; 3817c478bd9Sstevel@tonic-gate case S_IFDOOR: 3827c478bd9Sstevel@tonic-gate buf[cc++] = '>'; 3837c478bd9Sstevel@tonic-gate break; 3847c478bd9Sstevel@tonic-gate case S_IFIFO: 3857c478bd9Sstevel@tonic-gate buf[cc++] = '|'; 3867c478bd9Sstevel@tonic-gate break; 3877c478bd9Sstevel@tonic-gate case S_IFSOCK: 3887c478bd9Sstevel@tonic-gate buf[cc++] = '='; 3897c478bd9Sstevel@tonic-gate break; 3907c478bd9Sstevel@tonic-gate default: 3917c478bd9Sstevel@tonic-gate if ((stb1.st_mode & ~S_IFMT) 3927c478bd9Sstevel@tonic-gate & 0111) 3937c478bd9Sstevel@tonic-gate buf[cc++] = '*'; 3947c478bd9Sstevel@tonic-gate break; 3957c478bd9Sstevel@tonic-gate } 3967c478bd9Sstevel@tonic-gate buf[cc] = 0; 3977c478bd9Sstevel@tonic-gate fp->flinkto = savestr(buf); 3987c478bd9Sstevel@tonic-gate } 3997c478bd9Sstevel@tonic-gate break; 4007c478bd9Sstevel@tonic-gate } 4017c478bd9Sstevel@tonic-gate /* 4027c478bd9Sstevel@tonic-gate * this is a hack from UCB to avoid having 4037c478bd9Sstevel@tonic-gate * ls /bin behave differently from ls /bin/ 4047c478bd9Sstevel@tonic-gate * when /bin is a symbolic link. We hack the 4057c478bd9Sstevel@tonic-gate * hack to have that happen, but only for 4067c478bd9Sstevel@tonic-gate * explicit arguments, by inspecting pnb. 4077c478bd9Sstevel@tonic-gate */ 4087c478bd9Sstevel@tonic-gate if (pnb != (off_t *)0 || stat(file, &stb1) < 0) 4097c478bd9Sstevel@tonic-gate break; 4107c478bd9Sstevel@tonic-gate if ((stb1.st_mode & S_IFMT) == S_IFDIR) { 4117c478bd9Sstevel@tonic-gate stb = stb1; 4127c478bd9Sstevel@tonic-gate fp->ftype = 'd'; 4137c478bd9Sstevel@tonic-gate fp->fsize = stb.st_size; 4147c478bd9Sstevel@tonic-gate fp->fblks = stb.st_blocks; 4157c478bd9Sstevel@tonic-gate } 4167c478bd9Sstevel@tonic-gate break; 4177c478bd9Sstevel@tonic-gate } 4187c478bd9Sstevel@tonic-gate fp->fnum = stb.st_ino; 4197c478bd9Sstevel@tonic-gate fp->fflags = stb.st_mode & ~S_IFMT; 4207c478bd9Sstevel@tonic-gate fp->fnl = stb.st_nlink; 4217c478bd9Sstevel@tonic-gate fp->fuid = stb.st_uid; 4227c478bd9Sstevel@tonic-gate fp->fgid = stb.st_gid; 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate /* ACL: check acl entries count */ 4257c478bd9Sstevel@tonic-gate if ((aclcnt = acl(file, GETACLCNT, 0, NULL)) > 4267c478bd9Sstevel@tonic-gate MIN_ACL_ENTRIES) { 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate /* this file has a non-trivial acl */ 4297c478bd9Sstevel@tonic-gate 4307c478bd9Sstevel@tonic-gate fp->acl = '+'; 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate /* 4337c478bd9Sstevel@tonic-gate * For files with non-trivial acls, the 4347c478bd9Sstevel@tonic-gate * effective group permissions are the 4357c478bd9Sstevel@tonic-gate * intersection of the GROUP_OBJ value and 4367c478bd9Sstevel@tonic-gate * the CLASS_OBJ (acl mask) value. Determine 4377c478bd9Sstevel@tonic-gate * both the GROUP_OBJ and CLASS_OBJ for this 4387c478bd9Sstevel@tonic-gate * file and insert the logical AND of those 4397c478bd9Sstevel@tonic-gate * two values in the group permissions field 4407c478bd9Sstevel@tonic-gate * of the lflags value for this file. 4417c478bd9Sstevel@tonic-gate */ 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate if ((aclp = (aclent_t *)malloc( 4447c478bd9Sstevel@tonic-gate (sizeof (aclent_t)) * aclcnt)) == NULL) { 4457c478bd9Sstevel@tonic-gate perror("ls"); 4467c478bd9Sstevel@tonic-gate exit(2); 4477c478bd9Sstevel@tonic-gate } 4487c478bd9Sstevel@tonic-gate 4497c478bd9Sstevel@tonic-gate if (acl(file, GETACL, aclcnt, aclp) < 0) { 4507c478bd9Sstevel@tonic-gate free(aclp); 4517c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "ls: "); 4527c478bd9Sstevel@tonic-gate perror(file); 4537c478bd9Sstevel@tonic-gate return (0); 4547c478bd9Sstevel@tonic-gate } 4557c478bd9Sstevel@tonic-gate 4567c478bd9Sstevel@tonic-gate /* 4577c478bd9Sstevel@tonic-gate * Until found in acl list, assume maximum 4587c478bd9Sstevel@tonic-gate * permissions for both group and mask. (Just 4597c478bd9Sstevel@tonic-gate * in case the acl lacks either value for 4607c478bd9Sstevel@tonic-gate * some reason.) 4617c478bd9Sstevel@tonic-gate */ 4627c478bd9Sstevel@tonic-gate groupperm = 07; 4637c478bd9Sstevel@tonic-gate mask = 07; 4647c478bd9Sstevel@tonic-gate grouppermfound = 0; 4657c478bd9Sstevel@tonic-gate maskfound = 0; 4667c478bd9Sstevel@tonic-gate for (tp = aclp; aclcnt--; tp++) { 4677c478bd9Sstevel@tonic-gate if (tp->a_type == GROUP_OBJ) { 4687c478bd9Sstevel@tonic-gate groupperm = tp->a_perm; 4697c478bd9Sstevel@tonic-gate grouppermfound = 1; 4707c478bd9Sstevel@tonic-gate continue; 4717c478bd9Sstevel@tonic-gate } 4727c478bd9Sstevel@tonic-gate if (tp->a_type == CLASS_OBJ) { 4737c478bd9Sstevel@tonic-gate mask = tp->a_perm; 4747c478bd9Sstevel@tonic-gate maskfound = 1; 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate if (grouppermfound && maskfound) 4777c478bd9Sstevel@tonic-gate break; 4787c478bd9Sstevel@tonic-gate } 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate free(aclp); 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate /* reset all the group bits */ 4837c478bd9Sstevel@tonic-gate fp->fflags &= ~S_IRWXG; 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate /* 4867c478bd9Sstevel@tonic-gate * Now set them to the logical AND of the 4877c478bd9Sstevel@tonic-gate * GROUP_OBJ permissions and the acl mask. 4887c478bd9Sstevel@tonic-gate */ 4897c478bd9Sstevel@tonic-gate 4907c478bd9Sstevel@tonic-gate fp->fflags |= (groupperm & mask) << 3; 4917c478bd9Sstevel@tonic-gate } else 4927c478bd9Sstevel@tonic-gate fp->acl = ' '; 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate if (uflg) 4957c478bd9Sstevel@tonic-gate fp->fmtime = stb.st_atime; 4967c478bd9Sstevel@tonic-gate else if (cflg) 4977c478bd9Sstevel@tonic-gate fp->fmtime = stb.st_ctime; 4987c478bd9Sstevel@tonic-gate else 4997c478bd9Sstevel@tonic-gate fp->fmtime = stb.st_mtime; 5007c478bd9Sstevel@tonic-gate if (pnb) 5017c478bd9Sstevel@tonic-gate *pnb += stb.st_blocks; 5027c478bd9Sstevel@tonic-gate } 5037c478bd9Sstevel@tonic-gate return (fp); 5047c478bd9Sstevel@tonic-gate } 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate static void 5077c478bd9Sstevel@tonic-gate formatf(struct afile *fp0, struct afile *fplast) 5087c478bd9Sstevel@tonic-gate { 5097c478bd9Sstevel@tonic-gate register struct afile *fp; 5107c478bd9Sstevel@tonic-gate int width = 0, w, nentry = fplast - fp0; 5117c478bd9Sstevel@tonic-gate int i, j, columns, lines; 5127c478bd9Sstevel@tonic-gate char *cp; 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate if (fp0 == fplast) 5157c478bd9Sstevel@tonic-gate return; 5167c478bd9Sstevel@tonic-gate if (lflg || Cflg == 0) 5177c478bd9Sstevel@tonic-gate columns = 1; 5187c478bd9Sstevel@tonic-gate else { 5197c478bd9Sstevel@tonic-gate for (fp = fp0; fp < fplast; fp++) { 5207c478bd9Sstevel@tonic-gate int len = strlen(fmtentry(fp)); 5217c478bd9Sstevel@tonic-gate 5227c478bd9Sstevel@tonic-gate if (len > width) 5237c478bd9Sstevel@tonic-gate width = len; 5247c478bd9Sstevel@tonic-gate } 5257c478bd9Sstevel@tonic-gate if (usetabs) 5267c478bd9Sstevel@tonic-gate width = (width + 8) &~ 7; 5277c478bd9Sstevel@tonic-gate else 5287c478bd9Sstevel@tonic-gate width += 2; 5297c478bd9Sstevel@tonic-gate columns = twidth / width; 5307c478bd9Sstevel@tonic-gate if (columns == 0) 5317c478bd9Sstevel@tonic-gate columns = 1; 5327c478bd9Sstevel@tonic-gate } 5337c478bd9Sstevel@tonic-gate lines = (nentry + columns - 1) / columns; 5347c478bd9Sstevel@tonic-gate for (i = 0; i < lines; i++) { 5357c478bd9Sstevel@tonic-gate for (j = 0; j < columns; j++) { 5367c478bd9Sstevel@tonic-gate fp = fp0 + j * lines + i; 5377c478bd9Sstevel@tonic-gate cp = fmtentry(fp); 5387c478bd9Sstevel@tonic-gate (void) printf("%s", cp); 5397c478bd9Sstevel@tonic-gate if (fp + lines >= fplast) { 5407c478bd9Sstevel@tonic-gate (void) printf("\n"); 5417c478bd9Sstevel@tonic-gate break; 5427c478bd9Sstevel@tonic-gate } 5437c478bd9Sstevel@tonic-gate w = strlen(cp); 5447c478bd9Sstevel@tonic-gate while (w < width) 5457c478bd9Sstevel@tonic-gate if (usetabs) { 5467c478bd9Sstevel@tonic-gate w = (w + 8) &~ 7; 5477c478bd9Sstevel@tonic-gate (void) putchar('\t'); 5487c478bd9Sstevel@tonic-gate } else { 5497c478bd9Sstevel@tonic-gate w++; 5507c478bd9Sstevel@tonic-gate (void) putchar(' '); 5517c478bd9Sstevel@tonic-gate } 5527c478bd9Sstevel@tonic-gate } 5537c478bd9Sstevel@tonic-gate } 5547c478bd9Sstevel@tonic-gate } 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate static int 5577c478bd9Sstevel@tonic-gate fcmp(const void *arg1, const void *arg2) 5587c478bd9Sstevel@tonic-gate { 5597c478bd9Sstevel@tonic-gate const struct afile *f1 = arg1; 5607c478bd9Sstevel@tonic-gate const struct afile *f2 = arg2; 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate if (dflg == 0 && fflg == 0) { 5637c478bd9Sstevel@tonic-gate if ((f1->fflags&ISARG) && f1->ftype == 'd') { 5647c478bd9Sstevel@tonic-gate if ((f2->fflags&ISARG) == 0 || f2->ftype != 'd') 5657c478bd9Sstevel@tonic-gate return (1); 5667c478bd9Sstevel@tonic-gate } else { 5677c478bd9Sstevel@tonic-gate if ((f2->fflags&ISARG) && f2->ftype == 'd') 5687c478bd9Sstevel@tonic-gate return (-1); 5697c478bd9Sstevel@tonic-gate } 5707c478bd9Sstevel@tonic-gate } 5717c478bd9Sstevel@tonic-gate if (tflg) { 5727c478bd9Sstevel@tonic-gate if (f2->fmtime == f1->fmtime) 5737c478bd9Sstevel@tonic-gate return (0); 5747c478bd9Sstevel@tonic-gate if (f2->fmtime > f1->fmtime) 5757c478bd9Sstevel@tonic-gate return (rflg); 5767c478bd9Sstevel@tonic-gate return (-rflg); 5777c478bd9Sstevel@tonic-gate } 5787c478bd9Sstevel@tonic-gate return (rflg * strcmp(f1->fname, f2->fname)); 5797c478bd9Sstevel@tonic-gate } 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate static char * 5827c478bd9Sstevel@tonic-gate cat(char *dir, char *file) 5837c478bd9Sstevel@tonic-gate { 5847c478bd9Sstevel@tonic-gate static char dfile[BUFSIZ]; 5857c478bd9Sstevel@tonic-gate 5867c478bd9Sstevel@tonic-gate if (strlen(dir)+1+strlen(file)+1 > BUFSIZ) { 5877c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "ls: filename too long\n"); 5887c478bd9Sstevel@tonic-gate exit(1); 5897c478bd9Sstevel@tonic-gate } 5907c478bd9Sstevel@tonic-gate if (strcmp(dir, "") == 0 || strcmp(dir, ".") == 0) { 5917c478bd9Sstevel@tonic-gate (void) strcpy(dfile, file); 5927c478bd9Sstevel@tonic-gate return (dfile); 5937c478bd9Sstevel@tonic-gate } 5947c478bd9Sstevel@tonic-gate (void) strcpy(dfile, dir); 5957c478bd9Sstevel@tonic-gate if (dir[strlen(dir) - 1] != '/' && *file != '/') 5967c478bd9Sstevel@tonic-gate (void) strcat(dfile, "/"); 5977c478bd9Sstevel@tonic-gate (void) strcat(dfile, file); 5987c478bd9Sstevel@tonic-gate return (dfile); 5997c478bd9Sstevel@tonic-gate } 6007c478bd9Sstevel@tonic-gate 6017c478bd9Sstevel@tonic-gate static char * 6027c478bd9Sstevel@tonic-gate savestr(char *str) 6037c478bd9Sstevel@tonic-gate { 6047c478bd9Sstevel@tonic-gate char *cp = malloc(strlen(str) + 1); 6057c478bd9Sstevel@tonic-gate 6067c478bd9Sstevel@tonic-gate if (cp == NULL) { 6077c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "ls: out of memory\n"); 6087c478bd9Sstevel@tonic-gate exit(1); 6097c478bd9Sstevel@tonic-gate } 6107c478bd9Sstevel@tonic-gate (void) strcpy(cp, str); 6117c478bd9Sstevel@tonic-gate return (cp); 6127c478bd9Sstevel@tonic-gate } 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate static char *fmtinum(struct afile *); 6157c478bd9Sstevel@tonic-gate static char *fmtsize(struct afile *); 6167c478bd9Sstevel@tonic-gate static char *fmtlstuff(struct afile *); 6177c478bd9Sstevel@tonic-gate static char *fmtmode(char *, int); 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate static char * 6207c478bd9Sstevel@tonic-gate fmtentry(struct afile *fp) 6217c478bd9Sstevel@tonic-gate { 6227c478bd9Sstevel@tonic-gate static char fmtres[BUFSIZ]; 6237c478bd9Sstevel@tonic-gate register char *cp, *dp; 6247c478bd9Sstevel@tonic-gate 6257c478bd9Sstevel@tonic-gate (void) sprintf(fmtres, "%s%s%s", 6267c478bd9Sstevel@tonic-gate iflg ? fmtinum(fp) : "", 6277c478bd9Sstevel@tonic-gate sflg ? fmtsize(fp) : "", 6287c478bd9Sstevel@tonic-gate lflg ? fmtlstuff(fp) : ""); 6297c478bd9Sstevel@tonic-gate dp = &fmtres[strlen(fmtres)]; 6307c478bd9Sstevel@tonic-gate for (cp = fp->fname; *cp; cp++) 6317c478bd9Sstevel@tonic-gate if (qflg && !isprint((unsigned char)*cp)) 6327c478bd9Sstevel@tonic-gate *dp++ = '?'; 6337c478bd9Sstevel@tonic-gate else 6347c478bd9Sstevel@tonic-gate *dp++ = *cp; 6357c478bd9Sstevel@tonic-gate /* avoid both "->" and trailing marks */ 6367c478bd9Sstevel@tonic-gate if (Fflg && ! (lflg && fp->flinkto)) { 6377c478bd9Sstevel@tonic-gate if (fp->ftype == 'd') 6387c478bd9Sstevel@tonic-gate *dp++ = '/'; 6397c478bd9Sstevel@tonic-gate else if (fp->ftype == 'D') 6407c478bd9Sstevel@tonic-gate *dp++ = '>'; 6417c478bd9Sstevel@tonic-gate else if (fp->ftype == 'p') 6427c478bd9Sstevel@tonic-gate *dp++ = '|'; 6437c478bd9Sstevel@tonic-gate else if (fp->ftype == 'l') 6447c478bd9Sstevel@tonic-gate *dp++ = '@'; 6457c478bd9Sstevel@tonic-gate else if (fp->ftype == 's') 6467c478bd9Sstevel@tonic-gate *dp++ = '='; 6477c478bd9Sstevel@tonic-gate else if (fp->fflags & 0111) 6487c478bd9Sstevel@tonic-gate *dp++ = '*'; 6497c478bd9Sstevel@tonic-gate } 6507c478bd9Sstevel@tonic-gate if (lflg && fp->flinkto) { 6517c478bd9Sstevel@tonic-gate (void) strcpy(dp, " -> "); dp += 4; 6527c478bd9Sstevel@tonic-gate for (cp = fp->flinkto; *cp; cp++) 6537c478bd9Sstevel@tonic-gate if (qflg && !isprint((unsigned char) *cp)) 6547c478bd9Sstevel@tonic-gate *dp++ = '?'; 6557c478bd9Sstevel@tonic-gate else 6567c478bd9Sstevel@tonic-gate *dp++ = *cp; 6577c478bd9Sstevel@tonic-gate } 6587c478bd9Sstevel@tonic-gate *dp++ = 0; 6597c478bd9Sstevel@tonic-gate return (fmtres); 6607c478bd9Sstevel@tonic-gate } 6617c478bd9Sstevel@tonic-gate 6627c478bd9Sstevel@tonic-gate static char * 6637c478bd9Sstevel@tonic-gate fmtinum(struct afile *p) 6647c478bd9Sstevel@tonic-gate { 6657c478bd9Sstevel@tonic-gate static char inumbuf[12]; 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate (void) sprintf(inumbuf, "%10llu ", p->fnum); 6687c478bd9Sstevel@tonic-gate return (inumbuf); 6697c478bd9Sstevel@tonic-gate } 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate static char * 6727c478bd9Sstevel@tonic-gate fmtsize(struct afile *p) 6737c478bd9Sstevel@tonic-gate { 6747c478bd9Sstevel@tonic-gate static char sizebuf[32]; 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate (void) sprintf(sizebuf, (off_t)dbtokb(p->fblks) < 10000 ? "%4lld " : \ 6777c478bd9Sstevel@tonic-gate "%lld ", (off_t)dbtokb(p->fblks)); 6787c478bd9Sstevel@tonic-gate return (sizebuf); 6797c478bd9Sstevel@tonic-gate } 6807c478bd9Sstevel@tonic-gate 6817c478bd9Sstevel@tonic-gate static char * 6827c478bd9Sstevel@tonic-gate fmtlstuff(struct afile *p) 6837c478bd9Sstevel@tonic-gate { 6847c478bd9Sstevel@tonic-gate static char lstuffbuf[256]; 6857c478bd9Sstevel@tonic-gate char gname[32], uname[32], fsize[32], ftime[32]; 6867c478bd9Sstevel@tonic-gate register char *lp = lstuffbuf; 6877c478bd9Sstevel@tonic-gate 6887c478bd9Sstevel@tonic-gate /* type mode uname gname fsize ftime */ 6897c478bd9Sstevel@tonic-gate /* get uname */ 6907c478bd9Sstevel@tonic-gate { 6917c478bd9Sstevel@tonic-gate char *cp = getname(p->fuid); 692524e558aScf46844 (void) sprintf(uname, "%-8s ", cp); 6937c478bd9Sstevel@tonic-gate } 6947c478bd9Sstevel@tonic-gate /* get gname */ 6957c478bd9Sstevel@tonic-gate if (gflg) { 6967c478bd9Sstevel@tonic-gate char *cp = getgroup(p->fgid); 697524e558aScf46844 (void) sprintf(gname, "%-8s ", cp); 6987c478bd9Sstevel@tonic-gate } 6997c478bd9Sstevel@tonic-gate /* get fsize */ 7007c478bd9Sstevel@tonic-gate if (p->ftype == 'b' || p->ftype == 'c') 7017c478bd9Sstevel@tonic-gate (void) sprintf(fsize, "%3ld,%4ld", 7027c478bd9Sstevel@tonic-gate major(p->fsize), minor(p->fsize)); 7037c478bd9Sstevel@tonic-gate else if (p->ftype == 's') 7047c478bd9Sstevel@tonic-gate (void) sprintf(fsize, "%8d", 0); 7057c478bd9Sstevel@tonic-gate else 7067c478bd9Sstevel@tonic-gate (void) sprintf(fsize, p->fsize < 100000000 ? "%8lld" : \ 7077c478bd9Sstevel@tonic-gate "%lld", p->fsize); 7087c478bd9Sstevel@tonic-gate /* get ftime */ 7097c478bd9Sstevel@tonic-gate { 7107c478bd9Sstevel@tonic-gate char *cp = ctime(&p->fmtime); 7117c478bd9Sstevel@tonic-gate if ((p->fmtime < sixmonthsago) || (p->fmtime > onehourfromnow)) 7127c478bd9Sstevel@tonic-gate (void) sprintf(ftime, " %-7.7s %-4.4s ", cp+4, cp+20); 7137c478bd9Sstevel@tonic-gate else 7147c478bd9Sstevel@tonic-gate (void) sprintf(ftime, " %-12.12s ", cp+4); 7157c478bd9Sstevel@tonic-gate } 7167c478bd9Sstevel@tonic-gate /* splat */ 7177c478bd9Sstevel@tonic-gate *lp++ = p->ftype; 7187c478bd9Sstevel@tonic-gate lp = fmtmode(lp, p->fflags); 7197c478bd9Sstevel@tonic-gate (void) sprintf(lp, "%c%3ld %s%s%s%s", 7207c478bd9Sstevel@tonic-gate p->acl, p->fnl, uname, gflg ? gname : "", fsize, ftime); 7217c478bd9Sstevel@tonic-gate return (lstuffbuf); 7227c478bd9Sstevel@tonic-gate } 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate static int m1[] = 7257c478bd9Sstevel@tonic-gate { 1, S_IREAD>>0, 'r', '-' }; 7267c478bd9Sstevel@tonic-gate static int m2[] = 7277c478bd9Sstevel@tonic-gate { 1, S_IWRITE>>0, 'w', '-' }; 7287c478bd9Sstevel@tonic-gate static int m3[] = 7297c478bd9Sstevel@tonic-gate { 3, S_ISUID|(S_IEXEC>>0), 's', S_IEXEC>>0, 'x', S_ISUID, 'S', '-' }; 7307c478bd9Sstevel@tonic-gate static int m4[] = 7317c478bd9Sstevel@tonic-gate { 1, S_IREAD>>3, 'r', '-' }; 7327c478bd9Sstevel@tonic-gate static int m5[] = 7337c478bd9Sstevel@tonic-gate { 1, S_IWRITE>>3, 'w', '-' }; 7347c478bd9Sstevel@tonic-gate static int m6[] = 7357c478bd9Sstevel@tonic-gate { 3, S_ISGID|(S_IEXEC>>3), 's', S_IEXEC>>3, 'x', S_ISGID, 'S', '-' }; 7367c478bd9Sstevel@tonic-gate static int m7[] = 7377c478bd9Sstevel@tonic-gate { 1, S_IREAD>>6, 'r', '-' }; 7387c478bd9Sstevel@tonic-gate static int m8[] = 7397c478bd9Sstevel@tonic-gate { 1, S_IWRITE>>6, 'w', '-' }; 7407c478bd9Sstevel@tonic-gate static int m9[] = 7417c478bd9Sstevel@tonic-gate { 3, S_ISVTX|(S_IEXEC>>6), 't', S_ISVTX, 'T', S_IEXEC>>6, 'x', '-' }; 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate static int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate static char * 7467c478bd9Sstevel@tonic-gate fmtmode(char *lp, int flags) 7477c478bd9Sstevel@tonic-gate { 7487c478bd9Sstevel@tonic-gate int **mp; 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate for (mp = &m[0]; mp < &m[sizeof (m)/sizeof (m[0])]; ) { 7517c478bd9Sstevel@tonic-gate register int *pairp = *mp++; 7527c478bd9Sstevel@tonic-gate register int n = *pairp++; 7537c478bd9Sstevel@tonic-gate 7547c478bd9Sstevel@tonic-gate while (n-- > 0) { 7557c478bd9Sstevel@tonic-gate if ((flags&*pairp) == *pairp) { 7567c478bd9Sstevel@tonic-gate pairp++; 7577c478bd9Sstevel@tonic-gate break; 7587c478bd9Sstevel@tonic-gate } else 7597c478bd9Sstevel@tonic-gate pairp += 2; 7607c478bd9Sstevel@tonic-gate } 7617c478bd9Sstevel@tonic-gate *lp++ = *pairp; 7627c478bd9Sstevel@tonic-gate } 7637c478bd9Sstevel@tonic-gate return (lp); 7647c478bd9Sstevel@tonic-gate } 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate /* rest should be done with nameserver or database */ 7677c478bd9Sstevel@tonic-gate 7687c478bd9Sstevel@tonic-gate #include <pwd.h> 7697c478bd9Sstevel@tonic-gate #include <grp.h> 7707c478bd9Sstevel@tonic-gate #include <utmpx.h> 7717c478bd9Sstevel@tonic-gate 7727c478bd9Sstevel@tonic-gate #define NMAX (sizeof (((struct utmpx *)0)->ut_name)) 7737c478bd9Sstevel@tonic-gate #define SCPYN(a, b) strncpy(a, b, NMAX) 7747c478bd9Sstevel@tonic-gate 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate static struct cachenode { /* this struct must be zeroed before using */ 7777c478bd9Sstevel@tonic-gate struct cachenode *lesschild; /* subtree whose entries < val */ 7787c478bd9Sstevel@tonic-gate struct cachenode *grtrchild; /* subtree whose entries > val */ 7797c478bd9Sstevel@tonic-gate int val; /* the uid or gid of this entry */ 7807c478bd9Sstevel@tonic-gate int initted; /* name has been filled in */ 7817c478bd9Sstevel@tonic-gate char name[NMAX+1]; /* the string that val maps to */ 7827c478bd9Sstevel@tonic-gate } *names, *groups; 7837c478bd9Sstevel@tonic-gate 7847c478bd9Sstevel@tonic-gate static struct cachenode * 7857c478bd9Sstevel@tonic-gate findincache(struct cachenode **head, id_t val) 7867c478bd9Sstevel@tonic-gate { 7877c478bd9Sstevel@tonic-gate register struct cachenode **parent = head; 7887c478bd9Sstevel@tonic-gate register struct cachenode *c = *parent; 7897c478bd9Sstevel@tonic-gate 7907c478bd9Sstevel@tonic-gate while (c != NULL) { 7917c478bd9Sstevel@tonic-gate if (val == c->val) { 7927c478bd9Sstevel@tonic-gate /* found it */ 7937c478bd9Sstevel@tonic-gate return (c); 7947c478bd9Sstevel@tonic-gate } else if (val < c->val) { 7957c478bd9Sstevel@tonic-gate parent = &c->lesschild; 7967c478bd9Sstevel@tonic-gate c = c->lesschild; 7977c478bd9Sstevel@tonic-gate } else { 7987c478bd9Sstevel@tonic-gate parent = &c->grtrchild; 7997c478bd9Sstevel@tonic-gate c = c->grtrchild; 8007c478bd9Sstevel@tonic-gate } 8017c478bd9Sstevel@tonic-gate } 8027c478bd9Sstevel@tonic-gate 8037c478bd9Sstevel@tonic-gate /* not in the cache, make a new entry for it */ 8047c478bd9Sstevel@tonic-gate *parent = c = (struct cachenode *)calloc(1, sizeof (struct cachenode)); 8057c478bd9Sstevel@tonic-gate c->val = val; 8067c478bd9Sstevel@tonic-gate return (c); 8077c478bd9Sstevel@tonic-gate } 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate static char * 8107c478bd9Sstevel@tonic-gate getname(uid_t uid) 8117c478bd9Sstevel@tonic-gate { 8127c478bd9Sstevel@tonic-gate struct cachenode *c; 8137c478bd9Sstevel@tonic-gate struct passwd *pw; 8147c478bd9Sstevel@tonic-gate 8157c478bd9Sstevel@tonic-gate c = findincache(&names, uid); 8167c478bd9Sstevel@tonic-gate if (c->initted == 0) { 8177c478bd9Sstevel@tonic-gate if ((pw = getpwuid(uid)) != NULL) { 8187c478bd9Sstevel@tonic-gate (void) SCPYN(&c->name[0], pw->pw_name); 8197c478bd9Sstevel@tonic-gate } else { 8207c478bd9Sstevel@tonic-gate (void) sprintf(&c->name[0], "%-8lu ", uid); 8217c478bd9Sstevel@tonic-gate } 8227c478bd9Sstevel@tonic-gate c->initted = 1; 8237c478bd9Sstevel@tonic-gate } 8247c478bd9Sstevel@tonic-gate return (&c->name[0]); 8257c478bd9Sstevel@tonic-gate } 8267c478bd9Sstevel@tonic-gate 8277c478bd9Sstevel@tonic-gate static char * 8287c478bd9Sstevel@tonic-gate getgroup(gid_t gid) 8297c478bd9Sstevel@tonic-gate { 8307c478bd9Sstevel@tonic-gate struct cachenode *c; 8317c478bd9Sstevel@tonic-gate struct group *gr; 8327c478bd9Sstevel@tonic-gate 8337c478bd9Sstevel@tonic-gate c = findincache(&groups, gid); 8347c478bd9Sstevel@tonic-gate if (c->initted == 0) { 8357c478bd9Sstevel@tonic-gate if ((gr = getgrgid(gid)) != NULL) { 8367c478bd9Sstevel@tonic-gate (void) SCPYN(&c->name[0], gr->gr_name); 8377c478bd9Sstevel@tonic-gate } else { 8387c478bd9Sstevel@tonic-gate (void) sprintf(&c->name[0], "%-8lu ", gid); 8397c478bd9Sstevel@tonic-gate } 8407c478bd9Sstevel@tonic-gate c->initted = 1; 8417c478bd9Sstevel@tonic-gate } 8427c478bd9Sstevel@tonic-gate return (&c->name[0]); 8437c478bd9Sstevel@tonic-gate } 844