17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 23*5a5eeccaSmarks * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 287c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate /* Copyright (c) 1987, 1988 Microsoft Corporation */ 317c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 327c478bd9Sstevel@tonic-gate 337c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate /* 367c478bd9Sstevel@tonic-gate * List files or directories 377c478bd9Sstevel@tonic-gate */ 387c478bd9Sstevel@tonic-gate 397c478bd9Sstevel@tonic-gate #include <sys/param.h> 407c478bd9Sstevel@tonic-gate #include <sys/types.h> 417c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 427c478bd9Sstevel@tonic-gate #include <sys/stat.h> 437c478bd9Sstevel@tonic-gate #include <sys/acl.h> 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate #include <wchar.h> 467c478bd9Sstevel@tonic-gate #include <stdio.h> 477c478bd9Sstevel@tonic-gate #include <ctype.h> 487c478bd9Sstevel@tonic-gate #include <dirent.h> 497c478bd9Sstevel@tonic-gate #include <string.h> 507c478bd9Sstevel@tonic-gate #include <locale.h> 517c478bd9Sstevel@tonic-gate #include <curses.h> 527c478bd9Sstevel@tonic-gate #include <termios.h> 537c478bd9Sstevel@tonic-gate #include <stdlib.h> 547c478bd9Sstevel@tonic-gate #include <widec.h> 557c478bd9Sstevel@tonic-gate #include <locale.h> 567c478bd9Sstevel@tonic-gate #include <wctype.h> 577c478bd9Sstevel@tonic-gate #include <pwd.h> 587c478bd9Sstevel@tonic-gate #include <grp.h> 597c478bd9Sstevel@tonic-gate #include <limits.h> 607c478bd9Sstevel@tonic-gate #include <fcntl.h> 617c478bd9Sstevel@tonic-gate #include <unistd.h> 627c478bd9Sstevel@tonic-gate #include <libgen.h> 637c478bd9Sstevel@tonic-gate #include <errno.h> 64fa9e4066Sahrens #include <aclutils.h> 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate #ifndef STANDALONE 677c478bd9Sstevel@tonic-gate #define TERMINFO 687c478bd9Sstevel@tonic-gate #endif 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate /* 717c478bd9Sstevel@tonic-gate * -DNOTERMINFO can be defined on the cc command line to prevent 727c478bd9Sstevel@tonic-gate * the use of terminfo. This should be done on systems not having 737c478bd9Sstevel@tonic-gate * the terminfo feature(pre 6.0 sytems ?). 747c478bd9Sstevel@tonic-gate * As a result, columnar listings assume 80 columns for output, 757c478bd9Sstevel@tonic-gate * unless told otherwise via the COLUMNS environment variable. 767c478bd9Sstevel@tonic-gate */ 777c478bd9Sstevel@tonic-gate #ifdef NOTERMINFO 787c478bd9Sstevel@tonic-gate #undef TERMINFO 797c478bd9Sstevel@tonic-gate #endif 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate #include <term.h> 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate #define BFSIZE 16 847c478bd9Sstevel@tonic-gate /* this bit equals 1 in lflags of structure lbuf if *namep is to be used */ 857c478bd9Sstevel@tonic-gate #define ISARG 0100000 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate /* 887c478bd9Sstevel@tonic-gate * this flag has been added to manipulate the display of S instead of 'l' when 897c478bd9Sstevel@tonic-gate * the file is not a regular file and when group execution bit is off 907c478bd9Sstevel@tonic-gate */ 917c478bd9Sstevel@tonic-gate #define LS_NOTREG 010000 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate /* 957c478bd9Sstevel@tonic-gate * Date and time formats 967c478bd9Sstevel@tonic-gate * 977c478bd9Sstevel@tonic-gate * b --- abbreviated month name 987c478bd9Sstevel@tonic-gate * e --- day number 997c478bd9Sstevel@tonic-gate * Y --- year in the form ccyy 1007c478bd9Sstevel@tonic-gate * H --- hour(24-hour version) 1017c478bd9Sstevel@tonic-gate * M --- minute 1027c478bd9Sstevel@tonic-gate * F --- yyyy-mm-dd 1037c478bd9Sstevel@tonic-gate * T --- hh:mm:ss 1047c478bd9Sstevel@tonic-gate * z --- time zone as hours displacement from UTC 1057c478bd9Sstevel@tonic-gate * note that %F and %z are from the ISO C99 standard and are 1067c478bd9Sstevel@tonic-gate * not present in older C libraries 1077c478bd9Sstevel@tonic-gate */ 1087c478bd9Sstevel@tonic-gate #define FORMAT1 " %b %e %Y " 1097c478bd9Sstevel@tonic-gate #define FORMAT2 " %b %e %H:%M " 1107c478bd9Sstevel@tonic-gate #define FORMAT3 " %b %e %T %Y " 1117c478bd9Sstevel@tonic-gate #define FORMAT4 " %%F %%T.%.09ld %%z " 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate #undef BUFSIZ 1147c478bd9Sstevel@tonic-gate #define BUFSIZ 4096 1157c478bd9Sstevel@tonic-gate #define NUMBER_WIDTH 40 1167c478bd9Sstevel@tonic-gate #define FMTSIZE 50 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate struct ditem { 1197c478bd9Sstevel@tonic-gate dev_t dev; /* directory items device number */ 1207c478bd9Sstevel@tonic-gate ino_t ino; /* directory items inode number */ 1217c478bd9Sstevel@tonic-gate struct ditem *parent; /* dir items ptr to its parent's info */ 1227c478bd9Sstevel@tonic-gate }; 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate struct lbuf { 1257c478bd9Sstevel@tonic-gate union { 1267c478bd9Sstevel@tonic-gate char lname[MAXNAMLEN]; /* used for filename in a directory */ 1277c478bd9Sstevel@tonic-gate char *namep; /* for name in ls-command; */ 1287c478bd9Sstevel@tonic-gate } ln; 1297c478bd9Sstevel@tonic-gate char ltype; /* filetype */ 1307c478bd9Sstevel@tonic-gate ino_t lnum; /* inode number of file */ 1317c478bd9Sstevel@tonic-gate mode_t lflags; /* 0777 bits used as r,w,x permissions */ 1327c478bd9Sstevel@tonic-gate nlink_t lnl; /* number of links to file */ 1337c478bd9Sstevel@tonic-gate uid_t luid; 1347c478bd9Sstevel@tonic-gate gid_t lgid; 1357c478bd9Sstevel@tonic-gate off_t lsize; /* filesize or major/minor dev numbers */ 1367c478bd9Sstevel@tonic-gate blkcnt_t lblocks; /* number of file blocks */ 1377c478bd9Sstevel@tonic-gate timestruc_t lmtime; 1387c478bd9Sstevel@tonic-gate char *flinkto; /* symbolic link contents */ 1397c478bd9Sstevel@tonic-gate char acl; /* indicate there are additional acl entries */ 1407c478bd9Sstevel@tonic-gate int cycle; /* cycle detected flag */ 1417c478bd9Sstevel@tonic-gate struct ditem *ancinfo; /* maintains ancestor info */ 142fa9e4066Sahrens acl_t *aclp; /* ACL if present */ 1437c478bd9Sstevel@tonic-gate }; 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate struct dchain { 1467c478bd9Sstevel@tonic-gate char *dc_name; /* path name */ 1477c478bd9Sstevel@tonic-gate int cycle_detected; /* cycle detected visiting this directory */ 1487c478bd9Sstevel@tonic-gate struct ditem *myancinfo; /* this directory's ancestry info */ 1497c478bd9Sstevel@tonic-gate struct dchain *dc_next; /* next directory in the chain */ 1507c478bd9Sstevel@tonic-gate }; 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate /* 1537c478bd9Sstevel@tonic-gate * A numbuf_t is used when converting a number to a string representation 1547c478bd9Sstevel@tonic-gate */ 1557c478bd9Sstevel@tonic-gate typedef char numbuf_t[NUMBER_WIDTH]; 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate static struct dchain *dfirst; /* start of the dir chain */ 1587c478bd9Sstevel@tonic-gate static struct dchain *cdfirst; /* start of the current dir chain */ 1597c478bd9Sstevel@tonic-gate static struct dchain *dtemp; /* temporary - used for linking */ 1607c478bd9Sstevel@tonic-gate static char *curdir; /* the current directory */ 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate static int first = 1; /* true if first line is not yet printed */ 1637c478bd9Sstevel@tonic-gate static int nfiles = 0; /* number of flist entries in current use */ 1647c478bd9Sstevel@tonic-gate static int nargs = 0; /* number of flist entries used for arguments */ 1657c478bd9Sstevel@tonic-gate static int maxfils = 0; /* number of flist/lbuf entries allocated */ 1667c478bd9Sstevel@tonic-gate static int maxn = 0; /* number of flist entries with lbufs asigned */ 1677c478bd9Sstevel@tonic-gate static int quantn = 64; /* allocation growth quantum */ 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate static struct lbuf *nxtlbf; /* ptr to next lbuf to be assigned */ 1707c478bd9Sstevel@tonic-gate static struct lbuf **flist; /* ptr to list of lbuf pointers */ 1717c478bd9Sstevel@tonic-gate static struct lbuf *gstat(char *, int, struct ditem *); 1727c478bd9Sstevel@tonic-gate static char *getname(uid_t); 1737c478bd9Sstevel@tonic-gate static char *getgroup(gid_t); 1747c478bd9Sstevel@tonic-gate static char *makename(char *, char *); 1757c478bd9Sstevel@tonic-gate static void pentry(struct lbuf *); 1767c478bd9Sstevel@tonic-gate static void column(void); 1777c478bd9Sstevel@tonic-gate static void pmode(mode_t aflag); 1787c478bd9Sstevel@tonic-gate static void selection(int *); 1797c478bd9Sstevel@tonic-gate static void new_line(void); 1807c478bd9Sstevel@tonic-gate static void rddir(char *, struct ditem *); 1817c478bd9Sstevel@tonic-gate static int strcol(unsigned char *); 1827c478bd9Sstevel@tonic-gate static void pem(struct lbuf **, struct lbuf **, int); 1837c478bd9Sstevel@tonic-gate static void pdirectory(char *, int, int, int, struct ditem *); 1847c478bd9Sstevel@tonic-gate static struct cachenode *findincache(struct cachenode **, long); 1857c478bd9Sstevel@tonic-gate static void csi_pprintf(unsigned char *); 1867c478bd9Sstevel@tonic-gate static void pprintf(char *, char *); 1877c478bd9Sstevel@tonic-gate static int compar(struct lbuf **pp1, struct lbuf **pp2); 1887c478bd9Sstevel@tonic-gate static char *number_to_scaled_string(numbuf_t buf, 1897c478bd9Sstevel@tonic-gate unsigned long long number, 1907c478bd9Sstevel@tonic-gate long scale); 1917c478bd9Sstevel@tonic-gate static void record_ancestry(char *, struct stat *, struct lbuf *, 1927c478bd9Sstevel@tonic-gate int, struct ditem *); 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate static int aflg; 1957c478bd9Sstevel@tonic-gate static int atflg; 1967c478bd9Sstevel@tonic-gate static int bflg; 1977c478bd9Sstevel@tonic-gate static int cflg; 1987c478bd9Sstevel@tonic-gate static int dflg; 1997c478bd9Sstevel@tonic-gate static int eflg; 2007c478bd9Sstevel@tonic-gate static int fflg; 2017c478bd9Sstevel@tonic-gate static int gflg; 2027c478bd9Sstevel@tonic-gate static int hflg; 2037c478bd9Sstevel@tonic-gate static int iflg; 2047c478bd9Sstevel@tonic-gate static int lflg; 2057c478bd9Sstevel@tonic-gate static int mflg; 2067c478bd9Sstevel@tonic-gate static int nflg; 2077c478bd9Sstevel@tonic-gate static int oflg; 2087c478bd9Sstevel@tonic-gate static int pflg; 2097c478bd9Sstevel@tonic-gate static int qflg; 2107c478bd9Sstevel@tonic-gate static int rflg = 1; /* init to 1 for special use in compar */ 2117c478bd9Sstevel@tonic-gate static int sflg; 2127c478bd9Sstevel@tonic-gate static int tflg; 2137c478bd9Sstevel@tonic-gate static int uflg; 2147c478bd9Sstevel@tonic-gate static int xflg; 2157c478bd9Sstevel@tonic-gate static int Aflg; 2167c478bd9Sstevel@tonic-gate static int Cflg; 2177c478bd9Sstevel@tonic-gate static int Eflg; 2187c478bd9Sstevel@tonic-gate static int Fflg; 2197c478bd9Sstevel@tonic-gate static int Hflg; 2207c478bd9Sstevel@tonic-gate static int Lflg; 2217c478bd9Sstevel@tonic-gate static int Rflg; 2227c478bd9Sstevel@tonic-gate static int Sflg; 223fa9e4066Sahrens static int vflg; 224*5a5eeccaSmarks static int Vflg; 2257c478bd9Sstevel@tonic-gate static long hscale; 2267c478bd9Sstevel@tonic-gate static mode_t flags; 2277c478bd9Sstevel@tonic-gate static int err = 0; /* Contains return code */ 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate static uid_t lastuid = (uid_t)-1; 2307c478bd9Sstevel@tonic-gate static gid_t lastgid = (gid_t)-1; 2317c478bd9Sstevel@tonic-gate static char *lastuname = NULL; 2327c478bd9Sstevel@tonic-gate static char *lastgname = NULL; 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate /* statreq > 0 if any of sflg, (n)lflg, tflg, Sflg are on */ 2357c478bd9Sstevel@tonic-gate static int statreq; 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate static char *dotp = "."; 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate static u_longlong_t tblocks; /* number of blocks of files in a directory */ 2407c478bd9Sstevel@tonic-gate static time_t year, now; 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate static int num_cols = 80; 2437c478bd9Sstevel@tonic-gate static int colwidth; 2447c478bd9Sstevel@tonic-gate static int filewidth; 2457c478bd9Sstevel@tonic-gate static int fixedwidth; 2467c478bd9Sstevel@tonic-gate static int nomocore; 2477c478bd9Sstevel@tonic-gate static int curcol; 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate static struct winsize win; 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate static char time_buf[50]; /* array to hold day and time */ 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate #define NOTWORKINGDIR(d, l) (((l) < 2) || \ 2547c478bd9Sstevel@tonic-gate (strcmp((d) + (l) - 2, "/.") != 0)) 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate #define NOTPARENTDIR(d, l) (((l) < 3) || \ 2577c478bd9Sstevel@tonic-gate (strcmp((d) + (l) - 3, "/..") != 0)) 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate int 2607c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 2617c478bd9Sstevel@tonic-gate { 2627c478bd9Sstevel@tonic-gate int c; 2637c478bd9Sstevel@tonic-gate int i; 2647c478bd9Sstevel@tonic-gate int width; 2657c478bd9Sstevel@tonic-gate int amino = 0; 2667c478bd9Sstevel@tonic-gate int opterr = 0; 2677c478bd9Sstevel@tonic-gate struct lbuf *ep; 2687c478bd9Sstevel@tonic-gate struct lbuf lb; 2697c478bd9Sstevel@tonic-gate struct ditem *myinfo; 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 2727c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 2737c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 2747c478bd9Sstevel@tonic-gate #endif 2757c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 2767c478bd9Sstevel@tonic-gate #ifdef STANDALONE 2777c478bd9Sstevel@tonic-gate if (argv[0][0] == '\0') 2787c478bd9Sstevel@tonic-gate argc = getargv("ls", &argv, 0); 2797c478bd9Sstevel@tonic-gate #endif 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate lb.lmtime.tv_sec = time(NULL); 2827c478bd9Sstevel@tonic-gate lb.lmtime.tv_nsec = 0; 2837c478bd9Sstevel@tonic-gate year = lb.lmtime.tv_sec - 6L*30L*24L*60L*60L; /* 6 months ago */ 2847c478bd9Sstevel@tonic-gate now = lb.lmtime.tv_sec + 60; 2857c478bd9Sstevel@tonic-gate if (isatty(1)) { 2867c478bd9Sstevel@tonic-gate Cflg = 1; 2877c478bd9Sstevel@tonic-gate mflg = 0; 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, 291*5a5eeccaSmarks "aAbcCdeEfFghHilLmnopqrRsStux1@vV")) != EOF) 2927c478bd9Sstevel@tonic-gate switch (c) { 2937c478bd9Sstevel@tonic-gate case 'a': 2947c478bd9Sstevel@tonic-gate aflg++; 2957c478bd9Sstevel@tonic-gate continue; 2967c478bd9Sstevel@tonic-gate case 'A': 2977c478bd9Sstevel@tonic-gate Aflg++; 2987c478bd9Sstevel@tonic-gate continue; 2997c478bd9Sstevel@tonic-gate case 'b': 3007c478bd9Sstevel@tonic-gate bflg = 1; 3017c478bd9Sstevel@tonic-gate qflg = 0; 3027c478bd9Sstevel@tonic-gate continue; 3037c478bd9Sstevel@tonic-gate case 'c': 3047c478bd9Sstevel@tonic-gate uflg = 0; 3057c478bd9Sstevel@tonic-gate cflg++; 3067c478bd9Sstevel@tonic-gate continue; 3077c478bd9Sstevel@tonic-gate case 'C': 3087c478bd9Sstevel@tonic-gate Cflg = 1; 3097c478bd9Sstevel@tonic-gate mflg = 0; 3107c478bd9Sstevel@tonic-gate #ifdef XPG4 3117c478bd9Sstevel@tonic-gate lflg = 0; 3127c478bd9Sstevel@tonic-gate #endif 3137c478bd9Sstevel@tonic-gate continue; 3147c478bd9Sstevel@tonic-gate case 'd': 3157c478bd9Sstevel@tonic-gate dflg++; 3167c478bd9Sstevel@tonic-gate continue; 3177c478bd9Sstevel@tonic-gate case 'e': 3187c478bd9Sstevel@tonic-gate eflg++; 3197c478bd9Sstevel@tonic-gate lflg++; 3207c478bd9Sstevel@tonic-gate statreq++; 3217c478bd9Sstevel@tonic-gate Eflg = 0; 3227c478bd9Sstevel@tonic-gate continue; 3237c478bd9Sstevel@tonic-gate case 'E': 3247c478bd9Sstevel@tonic-gate Eflg++; 3257c478bd9Sstevel@tonic-gate lflg++; 3267c478bd9Sstevel@tonic-gate statreq++; 3277c478bd9Sstevel@tonic-gate eflg = 0; 3287c478bd9Sstevel@tonic-gate continue; 3297c478bd9Sstevel@tonic-gate case 'f': 3307c478bd9Sstevel@tonic-gate fflg++; 3317c478bd9Sstevel@tonic-gate continue; 3327c478bd9Sstevel@tonic-gate case 'F': 3337c478bd9Sstevel@tonic-gate Fflg++; 3347c478bd9Sstevel@tonic-gate statreq++; 3357c478bd9Sstevel@tonic-gate continue; 3367c478bd9Sstevel@tonic-gate case 'g': 3377c478bd9Sstevel@tonic-gate gflg++; 3387c478bd9Sstevel@tonic-gate lflg++; 3397c478bd9Sstevel@tonic-gate statreq++; 3407c478bd9Sstevel@tonic-gate continue; 3417c478bd9Sstevel@tonic-gate case 'h': 3427c478bd9Sstevel@tonic-gate hflg++; 3437c478bd9Sstevel@tonic-gate hscale = 1024; 3447c478bd9Sstevel@tonic-gate continue; 3457c478bd9Sstevel@tonic-gate case 'H': 3467c478bd9Sstevel@tonic-gate Hflg++; 3477c478bd9Sstevel@tonic-gate /* -H and -L are mutually exclusive */ 3487c478bd9Sstevel@tonic-gate Lflg = 0; 3497c478bd9Sstevel@tonic-gate continue; 3507c478bd9Sstevel@tonic-gate case 'i': 3517c478bd9Sstevel@tonic-gate iflg++; 3527c478bd9Sstevel@tonic-gate continue; 3537c478bd9Sstevel@tonic-gate case 'l': 3547c478bd9Sstevel@tonic-gate lflg++; 3557c478bd9Sstevel@tonic-gate statreq++; 3567c478bd9Sstevel@tonic-gate Cflg = 0; 3577c478bd9Sstevel@tonic-gate xflg = 0; 3587c478bd9Sstevel@tonic-gate mflg = 0; 3597c478bd9Sstevel@tonic-gate atflg = 0; 3607c478bd9Sstevel@tonic-gate continue; 3617c478bd9Sstevel@tonic-gate case 'L': 3627c478bd9Sstevel@tonic-gate Lflg++; 3637c478bd9Sstevel@tonic-gate /* -H and -L are mutually exclusive */ 3647c478bd9Sstevel@tonic-gate Hflg = 0; 3657c478bd9Sstevel@tonic-gate continue; 3667c478bd9Sstevel@tonic-gate case 'm': 3677c478bd9Sstevel@tonic-gate Cflg = 0; 3687c478bd9Sstevel@tonic-gate mflg = 1; 3697c478bd9Sstevel@tonic-gate #ifdef XPG4 3707c478bd9Sstevel@tonic-gate lflg = 0; 3717c478bd9Sstevel@tonic-gate #endif 3727c478bd9Sstevel@tonic-gate continue; 3737c478bd9Sstevel@tonic-gate case 'n': 3747c478bd9Sstevel@tonic-gate nflg++; 3757c478bd9Sstevel@tonic-gate lflg++; 3767c478bd9Sstevel@tonic-gate statreq++; 3777c478bd9Sstevel@tonic-gate Cflg = 0; 3787c478bd9Sstevel@tonic-gate xflg = 0; 3797c478bd9Sstevel@tonic-gate mflg = 0; 3807c478bd9Sstevel@tonic-gate atflg = 0; 3817c478bd9Sstevel@tonic-gate continue; 3827c478bd9Sstevel@tonic-gate case 'o': 3837c478bd9Sstevel@tonic-gate oflg++; 3847c478bd9Sstevel@tonic-gate lflg++; 3857c478bd9Sstevel@tonic-gate statreq++; 3867c478bd9Sstevel@tonic-gate continue; 3877c478bd9Sstevel@tonic-gate case 'p': 3887c478bd9Sstevel@tonic-gate pflg++; 3897c478bd9Sstevel@tonic-gate statreq++; 3907c478bd9Sstevel@tonic-gate continue; 3917c478bd9Sstevel@tonic-gate case 'q': 3927c478bd9Sstevel@tonic-gate qflg = 1; 3937c478bd9Sstevel@tonic-gate bflg = 0; 3947c478bd9Sstevel@tonic-gate continue; 3957c478bd9Sstevel@tonic-gate case 'r': 3967c478bd9Sstevel@tonic-gate rflg = -1; 3977c478bd9Sstevel@tonic-gate continue; 3987c478bd9Sstevel@tonic-gate case 'R': 3997c478bd9Sstevel@tonic-gate Rflg++; 4007c478bd9Sstevel@tonic-gate statreq++; 4017c478bd9Sstevel@tonic-gate continue; 4027c478bd9Sstevel@tonic-gate case 's': 4037c478bd9Sstevel@tonic-gate sflg++; 4047c478bd9Sstevel@tonic-gate statreq++; 4057c478bd9Sstevel@tonic-gate continue; 4067c478bd9Sstevel@tonic-gate case 'S': 4077c478bd9Sstevel@tonic-gate tflg = 0; 4087c478bd9Sstevel@tonic-gate Sflg++; 4097c478bd9Sstevel@tonic-gate statreq++; 4107c478bd9Sstevel@tonic-gate continue; 4117c478bd9Sstevel@tonic-gate case 't': 4127c478bd9Sstevel@tonic-gate Sflg = 0; 4137c478bd9Sstevel@tonic-gate tflg++; 4147c478bd9Sstevel@tonic-gate statreq++; 4157c478bd9Sstevel@tonic-gate continue; 4167c478bd9Sstevel@tonic-gate case 'u': 4177c478bd9Sstevel@tonic-gate cflg = 0; 4187c478bd9Sstevel@tonic-gate uflg++; 4197c478bd9Sstevel@tonic-gate continue; 420*5a5eeccaSmarks case 'V': 421*5a5eeccaSmarks Vflg++; 422*5a5eeccaSmarks /*FALLTHROUGH*/ 423fa9e4066Sahrens case 'v': 424fa9e4066Sahrens vflg++; 425fa9e4066Sahrens #if !defined(XPG4) 426fa9e4066Sahrens if (lflg) 427fa9e4066Sahrens continue; 428fa9e4066Sahrens #endif 429fa9e4066Sahrens lflg++; 430fa9e4066Sahrens statreq++; 431fa9e4066Sahrens Cflg = 0; 432fa9e4066Sahrens xflg = 0; 433fa9e4066Sahrens mflg = 0; 434fa9e4066Sahrens continue; 4357c478bd9Sstevel@tonic-gate case 'x': 4367c478bd9Sstevel@tonic-gate xflg = 1; 4377c478bd9Sstevel@tonic-gate Cflg = 1; 4387c478bd9Sstevel@tonic-gate mflg = 0; 4397c478bd9Sstevel@tonic-gate #ifdef XPG4 4407c478bd9Sstevel@tonic-gate lflg = 0; 4417c478bd9Sstevel@tonic-gate #endif 4427c478bd9Sstevel@tonic-gate continue; 4437c478bd9Sstevel@tonic-gate case '1': 4447c478bd9Sstevel@tonic-gate Cflg = 0; 4457c478bd9Sstevel@tonic-gate continue; 4467c478bd9Sstevel@tonic-gate case '@': 4477c478bd9Sstevel@tonic-gate #if !defined(XPG4) 4487c478bd9Sstevel@tonic-gate /* 4497c478bd9Sstevel@tonic-gate * -l has precedence over -@ 4507c478bd9Sstevel@tonic-gate */ 4517c478bd9Sstevel@tonic-gate if (lflg) 4527c478bd9Sstevel@tonic-gate continue; 4537c478bd9Sstevel@tonic-gate #endif 4547c478bd9Sstevel@tonic-gate atflg++; 4557c478bd9Sstevel@tonic-gate lflg++; 4567c478bd9Sstevel@tonic-gate statreq++; 4577c478bd9Sstevel@tonic-gate Cflg = 0; 4587c478bd9Sstevel@tonic-gate xflg = 0; 4597c478bd9Sstevel@tonic-gate mflg = 0; 4607c478bd9Sstevel@tonic-gate continue; 4617c478bd9Sstevel@tonic-gate case '?': 4627c478bd9Sstevel@tonic-gate opterr++; 4637c478bd9Sstevel@tonic-gate continue; 4647c478bd9Sstevel@tonic-gate } 4657c478bd9Sstevel@tonic-gate if (opterr) { 4667c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 467*5a5eeccaSmarks "usage: ls -aAbcCdeEfFghHilLmnopqrRsStuxvV1@ [files]\n")); 4687c478bd9Sstevel@tonic-gate exit(2); 4697c478bd9Sstevel@tonic-gate } 4707c478bd9Sstevel@tonic-gate 4717c478bd9Sstevel@tonic-gate if (fflg) { 4727c478bd9Sstevel@tonic-gate aflg++; 4737c478bd9Sstevel@tonic-gate lflg = 0; 4747c478bd9Sstevel@tonic-gate sflg = 0; 4757c478bd9Sstevel@tonic-gate tflg = 0; 4767c478bd9Sstevel@tonic-gate Sflg = 0; 4777c478bd9Sstevel@tonic-gate statreq = 0; 4787c478bd9Sstevel@tonic-gate } 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate fixedwidth = 2; 4817c478bd9Sstevel@tonic-gate if (pflg || Fflg) 4827c478bd9Sstevel@tonic-gate fixedwidth++; 4837c478bd9Sstevel@tonic-gate if (iflg) 4847c478bd9Sstevel@tonic-gate fixedwidth += 11; 4857c478bd9Sstevel@tonic-gate if (sflg) 4867c478bd9Sstevel@tonic-gate fixedwidth += 5; 4877c478bd9Sstevel@tonic-gate 4887c478bd9Sstevel@tonic-gate if (lflg) { 4897c478bd9Sstevel@tonic-gate if (!gflg && !oflg) 4907c478bd9Sstevel@tonic-gate gflg = oflg = 1; 4917c478bd9Sstevel@tonic-gate else 4927c478bd9Sstevel@tonic-gate if (gflg && oflg) 4937c478bd9Sstevel@tonic-gate gflg = oflg = 0; 4947c478bd9Sstevel@tonic-gate Cflg = mflg = 0; 4957c478bd9Sstevel@tonic-gate } 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate if (Cflg || mflg) { 4987c478bd9Sstevel@tonic-gate char *clptr; 4997c478bd9Sstevel@tonic-gate if ((clptr = getenv("COLUMNS")) != NULL) 5007c478bd9Sstevel@tonic-gate num_cols = atoi(clptr); 5017c478bd9Sstevel@tonic-gate #ifdef TERMINFO 5027c478bd9Sstevel@tonic-gate else { 5037c478bd9Sstevel@tonic-gate if (ioctl(1, TIOCGWINSZ, &win) != -1) 5047c478bd9Sstevel@tonic-gate num_cols = (win.ws_col == 0 ? 80 : win.ws_col); 5057c478bd9Sstevel@tonic-gate } 5067c478bd9Sstevel@tonic-gate #endif 5077c478bd9Sstevel@tonic-gate if (num_cols < 20 || num_cols > 1000) 5087c478bd9Sstevel@tonic-gate /* assume it is an error */ 5097c478bd9Sstevel@tonic-gate num_cols = 80; 5107c478bd9Sstevel@tonic-gate } 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate /* allocate space for flist and the associated */ 5137c478bd9Sstevel@tonic-gate /* data structures (lbufs) */ 5147c478bd9Sstevel@tonic-gate maxfils = quantn; 5157c478bd9Sstevel@tonic-gate if (((flist = malloc(maxfils * sizeof (struct lbuf *))) == NULL) || 5167c478bd9Sstevel@tonic-gate ((nxtlbf = malloc(quantn * sizeof (struct lbuf))) == NULL)) { 5177c478bd9Sstevel@tonic-gate perror("ls"); 5187c478bd9Sstevel@tonic-gate exit(2); 5197c478bd9Sstevel@tonic-gate } 5207c478bd9Sstevel@tonic-gate if ((amino = (argc-optind)) == 0) { 5217c478bd9Sstevel@tonic-gate /* 5227c478bd9Sstevel@tonic-gate * case when no names are given 5237c478bd9Sstevel@tonic-gate * in ls-command and current 5247c478bd9Sstevel@tonic-gate * directory is to be used 5257c478bd9Sstevel@tonic-gate */ 5267c478bd9Sstevel@tonic-gate argv[optind] = dotp; 5277c478bd9Sstevel@tonic-gate } 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate for (i = 0; i < (amino ? amino : 1); i++) { 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate /* 5327c478bd9Sstevel@tonic-gate * If we are recursing, we need to make sure we don't 5337c478bd9Sstevel@tonic-gate * get into an endless loop. To keep track of the inodes 5347c478bd9Sstevel@tonic-gate * (actually, just the directories) visited, we 5357c478bd9Sstevel@tonic-gate * maintain a directory ancestry list for a file 5367c478bd9Sstevel@tonic-gate * hierarchy. As we go deeper into the hierarchy, 5377c478bd9Sstevel@tonic-gate * a parent directory passes its directory list 5387c478bd9Sstevel@tonic-gate * info (device id, inode number, and a pointer to 5397c478bd9Sstevel@tonic-gate * its parent) to each of its children. As we 5407c478bd9Sstevel@tonic-gate * process a child that is a directory, we save 5417c478bd9Sstevel@tonic-gate * its own personal directory list info. We then 5427c478bd9Sstevel@tonic-gate * check to see if the child has already been 5437c478bd9Sstevel@tonic-gate * processed by comparing its device id and inode 5447c478bd9Sstevel@tonic-gate * number from its own personal directory list info 5457c478bd9Sstevel@tonic-gate * to that of each of its ancestors. If there is a 5467c478bd9Sstevel@tonic-gate * match, then we know we've detected a cycle. 5477c478bd9Sstevel@tonic-gate */ 5487c478bd9Sstevel@tonic-gate if (Rflg) { 5497c478bd9Sstevel@tonic-gate /* 5507c478bd9Sstevel@tonic-gate * This is the first parent in this lineage 5517c478bd9Sstevel@tonic-gate * (first in a directory hierarchy), so 5527c478bd9Sstevel@tonic-gate * this parent's parent doesn't exist. We 5537c478bd9Sstevel@tonic-gate * only initialize myinfo when we are 5547c478bd9Sstevel@tonic-gate * recursing, otherwise it's not used. 5557c478bd9Sstevel@tonic-gate */ 5567c478bd9Sstevel@tonic-gate if ((myinfo = (struct ditem *)malloc( 5577c478bd9Sstevel@tonic-gate sizeof (struct ditem))) == NULL) { 5587c478bd9Sstevel@tonic-gate perror("ls"); 5597c478bd9Sstevel@tonic-gate exit(2); 5607c478bd9Sstevel@tonic-gate } else { 5617c478bd9Sstevel@tonic-gate myinfo->dev = 0; 5627c478bd9Sstevel@tonic-gate myinfo->ino = 0; 5637c478bd9Sstevel@tonic-gate myinfo->parent = NULL; 5647c478bd9Sstevel@tonic-gate } 5657c478bd9Sstevel@tonic-gate } 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate if (Cflg || mflg) { 5687c478bd9Sstevel@tonic-gate width = strcol((unsigned char *)argv[optind]); 5697c478bd9Sstevel@tonic-gate if (width > filewidth) 5707c478bd9Sstevel@tonic-gate filewidth = width; 5717c478bd9Sstevel@tonic-gate } 5727c478bd9Sstevel@tonic-gate if ((ep = gstat((*argv[optind] ? argv[optind] : dotp), 5737c478bd9Sstevel@tonic-gate 1, myinfo)) == NULL) { 5747c478bd9Sstevel@tonic-gate if (nomocore) 5757c478bd9Sstevel@tonic-gate exit(2); 5767c478bd9Sstevel@tonic-gate err = 2; 5777c478bd9Sstevel@tonic-gate optind++; 5787c478bd9Sstevel@tonic-gate continue; 5797c478bd9Sstevel@tonic-gate } 5807c478bd9Sstevel@tonic-gate ep->ln.namep = (*argv[optind] ? argv[optind] : dotp); 5817c478bd9Sstevel@tonic-gate ep->lflags |= ISARG; 5827c478bd9Sstevel@tonic-gate optind++; 5837c478bd9Sstevel@tonic-gate nargs++; /* count good arguments stored in flist */ 5847c478bd9Sstevel@tonic-gate } 5857c478bd9Sstevel@tonic-gate colwidth = fixedwidth + filewidth; 5867c478bd9Sstevel@tonic-gate qsort(flist, (unsigned)nargs, sizeof (struct lbuf *), 5877c478bd9Sstevel@tonic-gate (int (*)(const void *, const void *))compar); 5887c478bd9Sstevel@tonic-gate for (i = 0; i < nargs; i++) { 5897c478bd9Sstevel@tonic-gate if (flist[i]->ltype == 'd' && dflg == 0 || fflg) 5907c478bd9Sstevel@tonic-gate break; 5917c478bd9Sstevel@tonic-gate } 5927c478bd9Sstevel@tonic-gate pem(&flist[0], &flist[i], 0); 5937c478bd9Sstevel@tonic-gate for (; i < nargs; i++) { 5947c478bd9Sstevel@tonic-gate pdirectory(flist[i]->ln.namep, Rflg || 5957c478bd9Sstevel@tonic-gate (amino > 1), nargs, 0, flist[i]->ancinfo); 5967c478bd9Sstevel@tonic-gate if (nomocore) 5977c478bd9Sstevel@tonic-gate exit(2); 5987c478bd9Sstevel@tonic-gate /* -R: print subdirectories found */ 5997c478bd9Sstevel@tonic-gate while (dfirst || cdfirst) { 6007c478bd9Sstevel@tonic-gate /* Place direct subdirs on front in right order */ 6017c478bd9Sstevel@tonic-gate while (cdfirst) { 6027c478bd9Sstevel@tonic-gate /* reverse cdfirst onto front of dfirst */ 6037c478bd9Sstevel@tonic-gate dtemp = cdfirst; 6047c478bd9Sstevel@tonic-gate cdfirst = cdfirst -> dc_next; 6057c478bd9Sstevel@tonic-gate dtemp -> dc_next = dfirst; 6067c478bd9Sstevel@tonic-gate dfirst = dtemp; 6077c478bd9Sstevel@tonic-gate } 6087c478bd9Sstevel@tonic-gate /* take off first dir on dfirst & print it */ 6097c478bd9Sstevel@tonic-gate dtemp = dfirst; 6107c478bd9Sstevel@tonic-gate dfirst = dfirst->dc_next; 6117c478bd9Sstevel@tonic-gate pdirectory(dtemp->dc_name, 1, nargs, 6127c478bd9Sstevel@tonic-gate dtemp->cycle_detected, dtemp->myancinfo); 6137c478bd9Sstevel@tonic-gate if (nomocore) 6147c478bd9Sstevel@tonic-gate exit(2); 6157c478bd9Sstevel@tonic-gate free(dtemp->dc_name); 6167c478bd9Sstevel@tonic-gate free(dtemp); 6177c478bd9Sstevel@tonic-gate } 6187c478bd9Sstevel@tonic-gate } 6197c478bd9Sstevel@tonic-gate return (err); 6207c478bd9Sstevel@tonic-gate } 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate /* 6237c478bd9Sstevel@tonic-gate * pdirectory: print the directory name, labelling it if title is 6247c478bd9Sstevel@tonic-gate * nonzero, using lp as the place to start reading in the dir. 6257c478bd9Sstevel@tonic-gate */ 6267c478bd9Sstevel@tonic-gate static void 6277c478bd9Sstevel@tonic-gate pdirectory(char *name, int title, int lp, int cdetect, struct ditem *myinfo) 6287c478bd9Sstevel@tonic-gate { 6297c478bd9Sstevel@tonic-gate struct dchain *dp; 6307c478bd9Sstevel@tonic-gate struct lbuf *ap; 6317c478bd9Sstevel@tonic-gate char *pname; 6327c478bd9Sstevel@tonic-gate int j; 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate filewidth = 0; 6357c478bd9Sstevel@tonic-gate curdir = name; 6367c478bd9Sstevel@tonic-gate if (title) { 6377c478bd9Sstevel@tonic-gate if (!first) 6387c478bd9Sstevel@tonic-gate (void) putc('\n', stdout); 6397c478bd9Sstevel@tonic-gate pprintf(name, ":"); 6407c478bd9Sstevel@tonic-gate new_line(); 6417c478bd9Sstevel@tonic-gate } 6427c478bd9Sstevel@tonic-gate /* 6437c478bd9Sstevel@tonic-gate * If there was a cycle detected, then notify and don't report 6447c478bd9Sstevel@tonic-gate * further. 6457c478bd9Sstevel@tonic-gate */ 6467c478bd9Sstevel@tonic-gate if (cdetect) { 6477c478bd9Sstevel@tonic-gate if (lflg || sflg) { 6487c478bd9Sstevel@tonic-gate curcol += printf(gettext("total %d"), 0); 6497c478bd9Sstevel@tonic-gate new_line(); 6507c478bd9Sstevel@tonic-gate } 6517c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6527c478bd9Sstevel@tonic-gate "ls: cycle detected for %s\n"), name); 6537c478bd9Sstevel@tonic-gate return; 6547c478bd9Sstevel@tonic-gate } 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate nfiles = lp; 6577c478bd9Sstevel@tonic-gate rddir(name, myinfo); 6587c478bd9Sstevel@tonic-gate if (nomocore) 6597c478bd9Sstevel@tonic-gate return; 6607c478bd9Sstevel@tonic-gate if (fflg == 0) 6617c478bd9Sstevel@tonic-gate qsort(&flist[lp], (unsigned)(nfiles - lp), 6627c478bd9Sstevel@tonic-gate sizeof (struct lbuf *), 6637c478bd9Sstevel@tonic-gate (int (*)(const void *, const void *))compar); 6647c478bd9Sstevel@tonic-gate if (Rflg) { 6657c478bd9Sstevel@tonic-gate for (j = nfiles - 1; j >= lp; j--) { 6667c478bd9Sstevel@tonic-gate ap = flist[j]; 6677c478bd9Sstevel@tonic-gate if (ap->ltype == 'd' && strcmp(ap->ln.lname, ".") && 6687c478bd9Sstevel@tonic-gate strcmp(ap->ln.lname, "..")) { 6697c478bd9Sstevel@tonic-gate dp = malloc(sizeof (struct dchain)); 6707c478bd9Sstevel@tonic-gate if (dp == NULL) { 6717c478bd9Sstevel@tonic-gate perror("ls"); 6727c478bd9Sstevel@tonic-gate exit(2); 6737c478bd9Sstevel@tonic-gate } 6747c478bd9Sstevel@tonic-gate pname = makename(curdir, ap->ln.lname); 6757c478bd9Sstevel@tonic-gate if ((dp->dc_name = strdup(pname)) == NULL) { 6767c478bd9Sstevel@tonic-gate perror("ls"); 6777c478bd9Sstevel@tonic-gate exit(2); 6787c478bd9Sstevel@tonic-gate } 6797c478bd9Sstevel@tonic-gate dp->cycle_detected = ap->cycle; 6807c478bd9Sstevel@tonic-gate dp->myancinfo = ap->ancinfo; 6817c478bd9Sstevel@tonic-gate dp->dc_next = dfirst; 6827c478bd9Sstevel@tonic-gate dfirst = dp; 6837c478bd9Sstevel@tonic-gate } 6847c478bd9Sstevel@tonic-gate } 6857c478bd9Sstevel@tonic-gate } 6867c478bd9Sstevel@tonic-gate if (lflg || sflg) { 6877c478bd9Sstevel@tonic-gate curcol += printf(gettext("total %llu"), tblocks); 6887c478bd9Sstevel@tonic-gate new_line(); 6897c478bd9Sstevel@tonic-gate } 6907c478bd9Sstevel@tonic-gate pem(&flist[lp], &flist[nfiles], lflg||sflg); 6917c478bd9Sstevel@tonic-gate } 6927c478bd9Sstevel@tonic-gate 6937c478bd9Sstevel@tonic-gate /* 6947c478bd9Sstevel@tonic-gate * pem: print 'em. Print a list of files (e.g. a directory) bounded 6957c478bd9Sstevel@tonic-gate * by slp and lp. 6967c478bd9Sstevel@tonic-gate */ 6977c478bd9Sstevel@tonic-gate static void 6987c478bd9Sstevel@tonic-gate pem(struct lbuf **slp, struct lbuf **lp, int tot_flag) 6997c478bd9Sstevel@tonic-gate { 7007c478bd9Sstevel@tonic-gate long row, nrows, i; 7017c478bd9Sstevel@tonic-gate int col, ncols; 7027c478bd9Sstevel@tonic-gate struct lbuf **ep; 7037c478bd9Sstevel@tonic-gate 7047c478bd9Sstevel@tonic-gate if (Cflg || mflg) { 7057c478bd9Sstevel@tonic-gate if (colwidth > num_cols) { 7067c478bd9Sstevel@tonic-gate ncols = 1; 7077c478bd9Sstevel@tonic-gate } else { 7087c478bd9Sstevel@tonic-gate ncols = num_cols / colwidth; 7097c478bd9Sstevel@tonic-gate } 7107c478bd9Sstevel@tonic-gate } 7117c478bd9Sstevel@tonic-gate 7127c478bd9Sstevel@tonic-gate if (ncols == 1 || mflg || xflg || !Cflg) { 7137c478bd9Sstevel@tonic-gate for (ep = slp; ep < lp; ep++) 7147c478bd9Sstevel@tonic-gate pentry(*ep); 7157c478bd9Sstevel@tonic-gate new_line(); 7167c478bd9Sstevel@tonic-gate return; 7177c478bd9Sstevel@tonic-gate } 7187c478bd9Sstevel@tonic-gate /* otherwise print -C columns */ 7197c478bd9Sstevel@tonic-gate if (tot_flag) { 7207c478bd9Sstevel@tonic-gate slp--; 7217c478bd9Sstevel@tonic-gate row = 1; 7227c478bd9Sstevel@tonic-gate } 7237c478bd9Sstevel@tonic-gate else 7247c478bd9Sstevel@tonic-gate row = 0; 7257c478bd9Sstevel@tonic-gate 7267c478bd9Sstevel@tonic-gate nrows = (lp - slp - 1) / ncols + 1; 7277c478bd9Sstevel@tonic-gate for (i = 0; i < nrows; i++, row++) { 7287c478bd9Sstevel@tonic-gate for (col = 0; col < ncols; col++) { 7297c478bd9Sstevel@tonic-gate ep = slp + (nrows * col) + row; 7307c478bd9Sstevel@tonic-gate if (ep < lp) 7317c478bd9Sstevel@tonic-gate pentry(*ep); 7327c478bd9Sstevel@tonic-gate } 7337c478bd9Sstevel@tonic-gate new_line(); 7347c478bd9Sstevel@tonic-gate } 7357c478bd9Sstevel@tonic-gate } 7367c478bd9Sstevel@tonic-gate 7377c478bd9Sstevel@tonic-gate /* 7387c478bd9Sstevel@tonic-gate * print one output entry; 7397c478bd9Sstevel@tonic-gate * if uid/gid is not found in the appropriate 7407c478bd9Sstevel@tonic-gate * file(passwd/group), then print uid/gid instead of 7417c478bd9Sstevel@tonic-gate * user/group name; 7427c478bd9Sstevel@tonic-gate */ 7437c478bd9Sstevel@tonic-gate static void 7447c478bd9Sstevel@tonic-gate pentry(struct lbuf *ap) 7457c478bd9Sstevel@tonic-gate { 7467c478bd9Sstevel@tonic-gate struct lbuf *p; 7477c478bd9Sstevel@tonic-gate numbuf_t hbuf; 7487c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; 7497c478bd9Sstevel@tonic-gate char fmt_buf[FMTSIZE]; 7507c478bd9Sstevel@tonic-gate char *dmark = ""; /* Used if -p or -F option active */ 7517c478bd9Sstevel@tonic-gate char *cp; 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate p = ap; 7547c478bd9Sstevel@tonic-gate column(); 7557c478bd9Sstevel@tonic-gate if (iflg) 7567c478bd9Sstevel@tonic-gate if (mflg && !lflg) 7577c478bd9Sstevel@tonic-gate curcol += printf("%llu ", (long long)p->lnum); 7587c478bd9Sstevel@tonic-gate else 7597c478bd9Sstevel@tonic-gate curcol += printf("%10llu ", (long long)p->lnum); 7607c478bd9Sstevel@tonic-gate if (sflg) 7617c478bd9Sstevel@tonic-gate curcol += printf((mflg && !lflg) ? "%lld " : 7627c478bd9Sstevel@tonic-gate (p->lblocks < 10000) ? "%4lld " : "%lld ", 7637c478bd9Sstevel@tonic-gate (p->ltype != 'b' && p->ltype != 'c') ? 7647c478bd9Sstevel@tonic-gate p->lblocks : 0LL); 7657c478bd9Sstevel@tonic-gate if (lflg) { 7667c478bd9Sstevel@tonic-gate (void) putchar(p->ltype); 7677c478bd9Sstevel@tonic-gate curcol++; 7687c478bd9Sstevel@tonic-gate pmode(p->lflags); 7697c478bd9Sstevel@tonic-gate 7707c478bd9Sstevel@tonic-gate /* ACL: additional access mode flag */ 7717c478bd9Sstevel@tonic-gate (void) putchar(p->acl); 7727c478bd9Sstevel@tonic-gate curcol++; 7737c478bd9Sstevel@tonic-gate 7747c478bd9Sstevel@tonic-gate curcol += printf("%3lu ", (ulong_t)p->lnl); 7757c478bd9Sstevel@tonic-gate if (oflg) 7767c478bd9Sstevel@tonic-gate if (!nflg) { 7777c478bd9Sstevel@tonic-gate cp = getname(p->luid); 7787c478bd9Sstevel@tonic-gate curcol += printf("%-8s ", cp); 7797c478bd9Sstevel@tonic-gate } else 7807c478bd9Sstevel@tonic-gate curcol += printf("%-8lu ", (ulong_t)p->luid); 7817c478bd9Sstevel@tonic-gate if (gflg) 7827c478bd9Sstevel@tonic-gate if (!nflg) { 7837c478bd9Sstevel@tonic-gate cp = getgroup(p->lgid); 7847c478bd9Sstevel@tonic-gate curcol += printf("%-8s ", cp); 7857c478bd9Sstevel@tonic-gate } else 7867c478bd9Sstevel@tonic-gate curcol += printf("%-8lu ", (ulong_t)p->lgid); 7877c478bd9Sstevel@tonic-gate if (p->ltype == 'b' || p->ltype == 'c') { 7887c478bd9Sstevel@tonic-gate curcol += printf("%3u, %2u", 7897c478bd9Sstevel@tonic-gate (uint_t)major((dev_t)p->lsize), 7907c478bd9Sstevel@tonic-gate (uint_t)minor((dev_t)p->lsize)); 7917c478bd9Sstevel@tonic-gate } else if (hflg && (p->lsize >= hscale)) { 7927c478bd9Sstevel@tonic-gate curcol += printf("%7s", 7937c478bd9Sstevel@tonic-gate number_to_scaled_string(hbuf, p->lsize, hscale)); 7947c478bd9Sstevel@tonic-gate } else { 7957c478bd9Sstevel@tonic-gate curcol += printf((p->lsize < (off_t)10000000) ? 7967c478bd9Sstevel@tonic-gate "%7lld" : "%lld", p->lsize); 7977c478bd9Sstevel@tonic-gate } 7987c478bd9Sstevel@tonic-gate if (eflg) { 7997c478bd9Sstevel@tonic-gate (void) strftime(time_buf, sizeof (time_buf), 8007c478bd9Sstevel@tonic-gate dcgettext(NULL, FORMAT3, LC_TIME), 8017c478bd9Sstevel@tonic-gate localtime(&p->lmtime.tv_sec)); 8027c478bd9Sstevel@tonic-gate } else if (Eflg) { 8037c478bd9Sstevel@tonic-gate /* fill in nanoseconds first */ 8047c478bd9Sstevel@tonic-gate (void) snprintf(fmt_buf, sizeof (fmt_buf), 8057c478bd9Sstevel@tonic-gate FORMAT4, p->lmtime.tv_nsec); 8067c478bd9Sstevel@tonic-gate (void) strftime(time_buf, sizeof (time_buf), 8077c478bd9Sstevel@tonic-gate fmt_buf, localtime(&p->lmtime.tv_sec)); 8087c478bd9Sstevel@tonic-gate } else { 8097c478bd9Sstevel@tonic-gate if ((p->lmtime.tv_sec < year) || 8107c478bd9Sstevel@tonic-gate (p->lmtime.tv_sec > now)) { 8117c478bd9Sstevel@tonic-gate (void) strftime(time_buf, sizeof (time_buf), 8127c478bd9Sstevel@tonic-gate dcgettext(NULL, FORMAT1, LC_TIME), 8137c478bd9Sstevel@tonic-gate localtime(&p->lmtime.tv_sec)); 8147c478bd9Sstevel@tonic-gate } else { 8157c478bd9Sstevel@tonic-gate (void) strftime(time_buf, sizeof (time_buf), 8167c478bd9Sstevel@tonic-gate dcgettext(NULL, FORMAT2, LC_TIME), 8177c478bd9Sstevel@tonic-gate localtime(&p->lmtime.tv_sec)); 8187c478bd9Sstevel@tonic-gate } 8197c478bd9Sstevel@tonic-gate } 8207c478bd9Sstevel@tonic-gate curcol += printf("%s", time_buf); 8217c478bd9Sstevel@tonic-gate } 8227c478bd9Sstevel@tonic-gate 8237c478bd9Sstevel@tonic-gate /* 8247c478bd9Sstevel@tonic-gate * prevent both "->" and trailing marks 8257c478bd9Sstevel@tonic-gate * from appearing 8267c478bd9Sstevel@tonic-gate */ 8277c478bd9Sstevel@tonic-gate 8287c478bd9Sstevel@tonic-gate if (pflg && p->ltype == 'd') 8297c478bd9Sstevel@tonic-gate dmark = "/"; 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate if (Fflg && !(lflg && p->flinkto)) { 8327c478bd9Sstevel@tonic-gate if (p->ltype == 'd') 8337c478bd9Sstevel@tonic-gate dmark = "/"; 8347c478bd9Sstevel@tonic-gate else if (p->ltype == 'D') 8357c478bd9Sstevel@tonic-gate dmark = ">"; 8367c478bd9Sstevel@tonic-gate else if (p->ltype == 'p') 8377c478bd9Sstevel@tonic-gate dmark = "|"; 8387c478bd9Sstevel@tonic-gate else if (p->ltype == 'l') 8397c478bd9Sstevel@tonic-gate dmark = "@"; 8407c478bd9Sstevel@tonic-gate else if (p->ltype == 's') 8417c478bd9Sstevel@tonic-gate dmark = "="; 8427c478bd9Sstevel@tonic-gate else if (p->lflags & (S_IXUSR|S_IXGRP|S_IXOTH)) 8437c478bd9Sstevel@tonic-gate dmark = "*"; 8447c478bd9Sstevel@tonic-gate else 8457c478bd9Sstevel@tonic-gate dmark = ""; 8467c478bd9Sstevel@tonic-gate } 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate if (lflg && p->flinkto) { 8497c478bd9Sstevel@tonic-gate (void) strncpy(buf, " -> ", 4); 8507c478bd9Sstevel@tonic-gate (void) strcpy(buf + 4, p->flinkto); 8517c478bd9Sstevel@tonic-gate dmark = buf; 8527c478bd9Sstevel@tonic-gate } 8537c478bd9Sstevel@tonic-gate 8547c478bd9Sstevel@tonic-gate if (p->lflags & ISARG) { 8557c478bd9Sstevel@tonic-gate if (qflg || bflg) 8567c478bd9Sstevel@tonic-gate pprintf(p->ln.namep, dmark); 8577c478bd9Sstevel@tonic-gate else { 8587c478bd9Sstevel@tonic-gate (void) printf("%s%s", p->ln.namep, dmark); 8597c478bd9Sstevel@tonic-gate curcol += strcol((unsigned char *)p->ln.namep); 8607c478bd9Sstevel@tonic-gate curcol += strcol((unsigned char *)dmark); 8617c478bd9Sstevel@tonic-gate } 8627c478bd9Sstevel@tonic-gate } else { 8637c478bd9Sstevel@tonic-gate if (qflg || bflg) 8647c478bd9Sstevel@tonic-gate pprintf(p->ln.lname, dmark); 8657c478bd9Sstevel@tonic-gate else { 8667c478bd9Sstevel@tonic-gate (void) printf("%s%s", p->ln.lname, dmark); 8677c478bd9Sstevel@tonic-gate curcol += strcol((unsigned char *)p->ln.lname); 8687c478bd9Sstevel@tonic-gate curcol += strcol((unsigned char *)dmark); 8697c478bd9Sstevel@tonic-gate } 8707c478bd9Sstevel@tonic-gate } 871fa9e4066Sahrens 872fa9e4066Sahrens if (vflg) { 873fa9e4066Sahrens new_line(); 874fa9e4066Sahrens if (p->aclp) { 875*5a5eeccaSmarks acl_printacl(p->aclp, num_cols, Vflg); 876fa9e4066Sahrens } 877fa9e4066Sahrens } 8787c478bd9Sstevel@tonic-gate } 8797c478bd9Sstevel@tonic-gate 8807c478bd9Sstevel@tonic-gate /* print various r,w,x permissions */ 8817c478bd9Sstevel@tonic-gate static void 8827c478bd9Sstevel@tonic-gate pmode(mode_t aflag) 8837c478bd9Sstevel@tonic-gate { 8847c478bd9Sstevel@tonic-gate /* these arrays are declared static to allow initializations */ 8857c478bd9Sstevel@tonic-gate static int m0[] = { 1, S_IRUSR, 'r', '-' }; 8867c478bd9Sstevel@tonic-gate static int m1[] = { 1, S_IWUSR, 'w', '-' }; 8877c478bd9Sstevel@tonic-gate static int m2[] = { 3, S_ISUID|S_IXUSR, 's', S_IXUSR, 8887c478bd9Sstevel@tonic-gate 'x', S_ISUID, 'S', '-' }; 8897c478bd9Sstevel@tonic-gate static int m3[] = { 1, S_IRGRP, 'r', '-' }; 8907c478bd9Sstevel@tonic-gate static int m4[] = { 1, S_IWGRP, 'w', '-' }; 8917c478bd9Sstevel@tonic-gate static int m5[] = { 4, S_ISGID|S_IXGRP, 's', S_IXGRP, 8927c478bd9Sstevel@tonic-gate 'x', S_ISGID|LS_NOTREG, 'S', 8937c478bd9Sstevel@tonic-gate #ifdef XPG4 8947c478bd9Sstevel@tonic-gate S_ISGID, 'L', '-'}; 8957c478bd9Sstevel@tonic-gate #else 8967c478bd9Sstevel@tonic-gate S_ISGID, 'l', '-'}; 8977c478bd9Sstevel@tonic-gate #endif 8987c478bd9Sstevel@tonic-gate static int m6[] = { 1, S_IROTH, 'r', '-' }; 8997c478bd9Sstevel@tonic-gate static int m7[] = { 1, S_IWOTH, 'w', '-' }; 9007c478bd9Sstevel@tonic-gate static int m8[] = { 3, S_ISVTX|S_IXOTH, 't', S_IXOTH, 9017c478bd9Sstevel@tonic-gate 'x', S_ISVTX, 'T', '-'}; 9027c478bd9Sstevel@tonic-gate 9037c478bd9Sstevel@tonic-gate static int *m[] = { m0, m1, m2, m3, m4, m5, m6, m7, m8}; 9047c478bd9Sstevel@tonic-gate 9057c478bd9Sstevel@tonic-gate int **mp; 9067c478bd9Sstevel@tonic-gate 9077c478bd9Sstevel@tonic-gate flags = aflag; 9087c478bd9Sstevel@tonic-gate for (mp = &m[0]; mp < &m[sizeof (m) / sizeof (m[0])]; mp++) 9097c478bd9Sstevel@tonic-gate selection(*mp); 9107c478bd9Sstevel@tonic-gate } 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate static void 9137c478bd9Sstevel@tonic-gate selection(int *pairp) 9147c478bd9Sstevel@tonic-gate { 9157c478bd9Sstevel@tonic-gate int n; 9167c478bd9Sstevel@tonic-gate 9177c478bd9Sstevel@tonic-gate n = *pairp++; 9187c478bd9Sstevel@tonic-gate while (n-->0) { 9197c478bd9Sstevel@tonic-gate if ((flags & *pairp) == *pairp) { 9207c478bd9Sstevel@tonic-gate pairp++; 9217c478bd9Sstevel@tonic-gate break; 9227c478bd9Sstevel@tonic-gate } else { 9237c478bd9Sstevel@tonic-gate pairp += 2; 9247c478bd9Sstevel@tonic-gate } 9257c478bd9Sstevel@tonic-gate } 9267c478bd9Sstevel@tonic-gate (void) putchar(*pairp); 9277c478bd9Sstevel@tonic-gate curcol++; 9287c478bd9Sstevel@tonic-gate } 9297c478bd9Sstevel@tonic-gate 9307c478bd9Sstevel@tonic-gate /* 9317c478bd9Sstevel@tonic-gate * column: get to the beginning of the next column. 9327c478bd9Sstevel@tonic-gate */ 9337c478bd9Sstevel@tonic-gate static void 9347c478bd9Sstevel@tonic-gate column(void) 9357c478bd9Sstevel@tonic-gate { 9367c478bd9Sstevel@tonic-gate if (curcol == 0) 9377c478bd9Sstevel@tonic-gate return; 9387c478bd9Sstevel@tonic-gate if (mflg) { 9397c478bd9Sstevel@tonic-gate (void) putc(',', stdout); 9407c478bd9Sstevel@tonic-gate curcol++; 9417c478bd9Sstevel@tonic-gate if (curcol + colwidth + 2 > num_cols) { 9427c478bd9Sstevel@tonic-gate (void) putc('\n', stdout); 9437c478bd9Sstevel@tonic-gate curcol = 0; 9447c478bd9Sstevel@tonic-gate return; 9457c478bd9Sstevel@tonic-gate } 9467c478bd9Sstevel@tonic-gate (void) putc(' ', stdout); 9477c478bd9Sstevel@tonic-gate curcol++; 9487c478bd9Sstevel@tonic-gate return; 9497c478bd9Sstevel@tonic-gate } 9507c478bd9Sstevel@tonic-gate if (Cflg == 0) { 9517c478bd9Sstevel@tonic-gate (void) putc('\n', stdout); 9527c478bd9Sstevel@tonic-gate curcol = 0; 9537c478bd9Sstevel@tonic-gate return; 9547c478bd9Sstevel@tonic-gate } 9557c478bd9Sstevel@tonic-gate if ((curcol / colwidth + 2) * colwidth > num_cols) { 9567c478bd9Sstevel@tonic-gate (void) putc('\n', stdout); 9577c478bd9Sstevel@tonic-gate curcol = 0; 9587c478bd9Sstevel@tonic-gate return; 9597c478bd9Sstevel@tonic-gate } 9607c478bd9Sstevel@tonic-gate do { 9617c478bd9Sstevel@tonic-gate (void) putc(' ', stdout); 9627c478bd9Sstevel@tonic-gate curcol++; 9637c478bd9Sstevel@tonic-gate } while (curcol % colwidth); 9647c478bd9Sstevel@tonic-gate } 9657c478bd9Sstevel@tonic-gate 9667c478bd9Sstevel@tonic-gate static void 9677c478bd9Sstevel@tonic-gate new_line(void) 9687c478bd9Sstevel@tonic-gate { 9697c478bd9Sstevel@tonic-gate if (curcol) { 9707c478bd9Sstevel@tonic-gate first = 0; 9717c478bd9Sstevel@tonic-gate (void) putc('\n', stdout); 9727c478bd9Sstevel@tonic-gate curcol = 0; 9737c478bd9Sstevel@tonic-gate } 9747c478bd9Sstevel@tonic-gate } 9757c478bd9Sstevel@tonic-gate 9767c478bd9Sstevel@tonic-gate /* 9777c478bd9Sstevel@tonic-gate * read each filename in directory dir and store its 9787c478bd9Sstevel@tonic-gate * status in flist[nfiles] 9797c478bd9Sstevel@tonic-gate * use makename() to form pathname dir/filename; 9807c478bd9Sstevel@tonic-gate */ 9817c478bd9Sstevel@tonic-gate static void 9827c478bd9Sstevel@tonic-gate rddir(char *dir, struct ditem *myinfo) 9837c478bd9Sstevel@tonic-gate { 9847c478bd9Sstevel@tonic-gate struct dirent *dentry; 9857c478bd9Sstevel@tonic-gate DIR *dirf; 9867c478bd9Sstevel@tonic-gate int j; 9877c478bd9Sstevel@tonic-gate struct lbuf *ep; 9887c478bd9Sstevel@tonic-gate int width; 9897c478bd9Sstevel@tonic-gate 9907c478bd9Sstevel@tonic-gate if ((dirf = opendir(dir)) == NULL) { 9917c478bd9Sstevel@tonic-gate (void) fflush(stdout); 9927c478bd9Sstevel@tonic-gate perror(dir); 9937c478bd9Sstevel@tonic-gate err = 2; 9947c478bd9Sstevel@tonic-gate return; 9957c478bd9Sstevel@tonic-gate } else { 9967c478bd9Sstevel@tonic-gate tblocks = 0; 9977c478bd9Sstevel@tonic-gate for (;;) { 9987c478bd9Sstevel@tonic-gate errno = 0; 9997c478bd9Sstevel@tonic-gate if ((dentry = readdir(dirf)) == NULL) 10007c478bd9Sstevel@tonic-gate break; 10017c478bd9Sstevel@tonic-gate if (aflg == 0 && dentry->d_name[0] == '.' && 10027c478bd9Sstevel@tonic-gate (Aflg == 0 || 10037c478bd9Sstevel@tonic-gate dentry->d_name[1] == '\0' || 10047c478bd9Sstevel@tonic-gate dentry->d_name[1] == '.' && 10057c478bd9Sstevel@tonic-gate dentry->d_name[2] == '\0')) 10067c478bd9Sstevel@tonic-gate /* 10077c478bd9Sstevel@tonic-gate * check for directory items '.', '..', 10087c478bd9Sstevel@tonic-gate * and items without valid inode-number; 10097c478bd9Sstevel@tonic-gate */ 10107c478bd9Sstevel@tonic-gate continue; 10117c478bd9Sstevel@tonic-gate 10127c478bd9Sstevel@tonic-gate if (Cflg || mflg) { 10137c478bd9Sstevel@tonic-gate width = strcol((unsigned char *)dentry->d_name); 10147c478bd9Sstevel@tonic-gate if (width > filewidth) 10157c478bd9Sstevel@tonic-gate filewidth = width; 10167c478bd9Sstevel@tonic-gate } 10177c478bd9Sstevel@tonic-gate ep = gstat(makename(dir, dentry->d_name), 0, myinfo); 10187c478bd9Sstevel@tonic-gate if (ep == NULL) { 10197c478bd9Sstevel@tonic-gate if (nomocore) 10207c478bd9Sstevel@tonic-gate return; 10217c478bd9Sstevel@tonic-gate continue; 10227c478bd9Sstevel@tonic-gate } else { 10237c478bd9Sstevel@tonic-gate ep->lnum = dentry->d_ino; 10247c478bd9Sstevel@tonic-gate for (j = 0; dentry->d_name[j] != '\0'; j++) 10257c478bd9Sstevel@tonic-gate ep->ln.lname[j] = dentry->d_name[j]; 10267c478bd9Sstevel@tonic-gate ep->ln.lname[j] = '\0'; 10277c478bd9Sstevel@tonic-gate } 10287c478bd9Sstevel@tonic-gate } 10297c478bd9Sstevel@tonic-gate if (errno) { 10307c478bd9Sstevel@tonic-gate int sav_errno = errno; 10317c478bd9Sstevel@tonic-gate 10327c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 10337c478bd9Sstevel@tonic-gate gettext("ls: error reading directory %s: %s\n"), 10347c478bd9Sstevel@tonic-gate dir, strerror(sav_errno)); 10357c478bd9Sstevel@tonic-gate } 10367c478bd9Sstevel@tonic-gate (void) closedir(dirf); 10377c478bd9Sstevel@tonic-gate colwidth = fixedwidth + filewidth; 10387c478bd9Sstevel@tonic-gate } 10397c478bd9Sstevel@tonic-gate } 10407c478bd9Sstevel@tonic-gate 10417c478bd9Sstevel@tonic-gate /* 10427c478bd9Sstevel@tonic-gate * Attaching a link to an inode's ancestors. Search 10437c478bd9Sstevel@tonic-gate * through the ancestors to check for cycles (an inode which 10447c478bd9Sstevel@tonic-gate * we have already tracked in this inodes ancestry). If a cycle 10457c478bd9Sstevel@tonic-gate * is detected, set the exit code and record the fact so that 10467c478bd9Sstevel@tonic-gate * it is reported at the right time when printing the directory. 10477c478bd9Sstevel@tonic-gate * In addition, set the exit code. Note: If the -a flag was 10487c478bd9Sstevel@tonic-gate * specified, we don't want to check for cycles for directories 10497c478bd9Sstevel@tonic-gate * ending in '/.' or '/..' unless they were specified on the 10507c478bd9Sstevel@tonic-gate * command line. 10517c478bd9Sstevel@tonic-gate */ 10527c478bd9Sstevel@tonic-gate static void 10537c478bd9Sstevel@tonic-gate record_ancestry(char *file, struct stat *pstatb, struct lbuf *rep, 10547c478bd9Sstevel@tonic-gate int argfl, struct ditem *myparent) 10557c478bd9Sstevel@tonic-gate { 10567c478bd9Sstevel@tonic-gate size_t file_len; 10577c478bd9Sstevel@tonic-gate struct ditem *myinfo; 10587c478bd9Sstevel@tonic-gate struct ditem *tptr; 10597c478bd9Sstevel@tonic-gate 10607c478bd9Sstevel@tonic-gate file_len = strlen(file); 10617c478bd9Sstevel@tonic-gate if (!aflg || argfl || (NOTWORKINGDIR(file, file_len) && 10627c478bd9Sstevel@tonic-gate NOTPARENTDIR(file, file_len))) { 10637c478bd9Sstevel@tonic-gate /* 10647c478bd9Sstevel@tonic-gate * Add this inode's ancestry 10657c478bd9Sstevel@tonic-gate * info and insert it into the 10667c478bd9Sstevel@tonic-gate * ancestry list by pointing 10677c478bd9Sstevel@tonic-gate * back to its parent. We save 10687c478bd9Sstevel@tonic-gate * it (in rep) with the other info 10697c478bd9Sstevel@tonic-gate * we're gathering for this inode. 10707c478bd9Sstevel@tonic-gate */ 10717c478bd9Sstevel@tonic-gate if ((myinfo = malloc( 10727c478bd9Sstevel@tonic-gate sizeof (struct ditem))) == NULL) { 10737c478bd9Sstevel@tonic-gate perror("ls"); 10747c478bd9Sstevel@tonic-gate exit(2); 10757c478bd9Sstevel@tonic-gate } 10767c478bd9Sstevel@tonic-gate myinfo->dev = pstatb->st_dev; 10777c478bd9Sstevel@tonic-gate myinfo->ino = pstatb->st_ino; 10787c478bd9Sstevel@tonic-gate myinfo->parent = myparent; 10797c478bd9Sstevel@tonic-gate rep->ancinfo = myinfo; 10807c478bd9Sstevel@tonic-gate 10817c478bd9Sstevel@tonic-gate /* 10827c478bd9Sstevel@tonic-gate * If this node has the same device id and 10837c478bd9Sstevel@tonic-gate * inode number of one of its ancestors, 10847c478bd9Sstevel@tonic-gate * then we've detected a cycle. 10857c478bd9Sstevel@tonic-gate */ 10867c478bd9Sstevel@tonic-gate if (myparent != NULL) { 10877c478bd9Sstevel@tonic-gate for (tptr = myparent; tptr->parent != NULL; 10887c478bd9Sstevel@tonic-gate tptr = tptr->parent) { 10897c478bd9Sstevel@tonic-gate if ((tptr->dev == pstatb->st_dev) && 10907c478bd9Sstevel@tonic-gate (tptr->ino == pstatb->st_ino)) { 10917c478bd9Sstevel@tonic-gate /* 10927c478bd9Sstevel@tonic-gate * Cycle detected for this 10937c478bd9Sstevel@tonic-gate * directory. Record the fact 10947c478bd9Sstevel@tonic-gate * it is a cycle so we don't 10957c478bd9Sstevel@tonic-gate * try to process this 10967c478bd9Sstevel@tonic-gate * directory as we are 10977c478bd9Sstevel@tonic-gate * walking through the 10987c478bd9Sstevel@tonic-gate * list of directories. 10997c478bd9Sstevel@tonic-gate */ 11007c478bd9Sstevel@tonic-gate rep->cycle = 1; 11017c478bd9Sstevel@tonic-gate err = 2; 11027c478bd9Sstevel@tonic-gate break; 11037c478bd9Sstevel@tonic-gate } 11047c478bd9Sstevel@tonic-gate } 11057c478bd9Sstevel@tonic-gate } 11067c478bd9Sstevel@tonic-gate } 11077c478bd9Sstevel@tonic-gate } 11087c478bd9Sstevel@tonic-gate 11097c478bd9Sstevel@tonic-gate /* 11107c478bd9Sstevel@tonic-gate * get status of file and recomputes tblocks; 11117c478bd9Sstevel@tonic-gate * argfl = 1 if file is a name in ls-command and = 0 11127c478bd9Sstevel@tonic-gate * for filename in a directory whose name is an 11137c478bd9Sstevel@tonic-gate * argument in the command; 11147c478bd9Sstevel@tonic-gate * stores a pointer in flist[nfiles] and 11157c478bd9Sstevel@tonic-gate * returns that pointer; 11167c478bd9Sstevel@tonic-gate * returns NULL if failed; 11177c478bd9Sstevel@tonic-gate */ 11187c478bd9Sstevel@tonic-gate static struct lbuf * 11197c478bd9Sstevel@tonic-gate gstat(char *file, int argfl, struct ditem *myparent) 11207c478bd9Sstevel@tonic-gate { 11217c478bd9Sstevel@tonic-gate struct stat statb, statb1; 11227c478bd9Sstevel@tonic-gate struct lbuf *rep; 11237c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; 11247c478bd9Sstevel@tonic-gate ssize_t cc; 11257c478bd9Sstevel@tonic-gate int (*statf)() = ((Lflg) || (Hflg && argfl)) ? stat : lstat; 11267c478bd9Sstevel@tonic-gate int aclcnt; 1127fa9e4066Sahrens int error; 11287c478bd9Sstevel@tonic-gate aclent_t *tp; 11297c478bd9Sstevel@tonic-gate o_mode_t groupperm, mask; 11307c478bd9Sstevel@tonic-gate int grouppermfound, maskfound; 11317c478bd9Sstevel@tonic-gate 11327c478bd9Sstevel@tonic-gate if (nomocore) 11337c478bd9Sstevel@tonic-gate return (NULL); 11347c478bd9Sstevel@tonic-gate 11357c478bd9Sstevel@tonic-gate if (nfiles >= maxfils) { 11367c478bd9Sstevel@tonic-gate /* 11377c478bd9Sstevel@tonic-gate * all flist/lbuf pair assigned files, time to get some 11387c478bd9Sstevel@tonic-gate * more space 11397c478bd9Sstevel@tonic-gate */ 11407c478bd9Sstevel@tonic-gate maxfils += quantn; 11417c478bd9Sstevel@tonic-gate if (((flist = realloc(flist, 11427c478bd9Sstevel@tonic-gate maxfils * sizeof (struct lbuf *))) == NULL) || 11437c478bd9Sstevel@tonic-gate ((nxtlbf = malloc(quantn * 11447c478bd9Sstevel@tonic-gate sizeof (struct lbuf))) == NULL)) { 11457c478bd9Sstevel@tonic-gate perror("ls"); 11467c478bd9Sstevel@tonic-gate nomocore = 1; 11477c478bd9Sstevel@tonic-gate return (NULL); 11487c478bd9Sstevel@tonic-gate } 11497c478bd9Sstevel@tonic-gate } 11507c478bd9Sstevel@tonic-gate 11517c478bd9Sstevel@tonic-gate /* 11527c478bd9Sstevel@tonic-gate * nfiles is reset to nargs for each directory 11537c478bd9Sstevel@tonic-gate * that is given as an argument maxn is checked 11547c478bd9Sstevel@tonic-gate * to prevent the assignment of an lbuf to a flist entry 11557c478bd9Sstevel@tonic-gate * that already has one assigned. 11567c478bd9Sstevel@tonic-gate */ 11577c478bd9Sstevel@tonic-gate if (nfiles >= maxn) { 11587c478bd9Sstevel@tonic-gate rep = nxtlbf++; 11597c478bd9Sstevel@tonic-gate flist[nfiles++] = rep; 11607c478bd9Sstevel@tonic-gate maxn = nfiles; 11617c478bd9Sstevel@tonic-gate } else { 11627c478bd9Sstevel@tonic-gate rep = flist[nfiles++]; 11637c478bd9Sstevel@tonic-gate } 11647c478bd9Sstevel@tonic-gate rep->lflags = (mode_t)0; 11657c478bd9Sstevel@tonic-gate rep->flinkto = NULL; 11667c478bd9Sstevel@tonic-gate rep->cycle = 0; 11677c478bd9Sstevel@tonic-gate if (argfl || statreq) { 11687c478bd9Sstevel@tonic-gate int doacl; 11697c478bd9Sstevel@tonic-gate 11707c478bd9Sstevel@tonic-gate if (lflg) 11717c478bd9Sstevel@tonic-gate doacl = 1; 11727c478bd9Sstevel@tonic-gate else 11737c478bd9Sstevel@tonic-gate doacl = 0; 11747c478bd9Sstevel@tonic-gate if ((*statf)(file, &statb) < 0) { 11757c478bd9Sstevel@tonic-gate if (argfl || errno != ENOENT || 11767c478bd9Sstevel@tonic-gate (Lflg && lstat(file, &statb) == 0)) { 11777c478bd9Sstevel@tonic-gate /* 11787c478bd9Sstevel@tonic-gate * Avoid race between readdir and lstat. 11797c478bd9Sstevel@tonic-gate * Print error message in case of dangling link. 11807c478bd9Sstevel@tonic-gate */ 11817c478bd9Sstevel@tonic-gate perror(file); 11827c478bd9Sstevel@tonic-gate } 11837c478bd9Sstevel@tonic-gate nfiles--; 11847c478bd9Sstevel@tonic-gate return (NULL); 11857c478bd9Sstevel@tonic-gate } 11867c478bd9Sstevel@tonic-gate 11877c478bd9Sstevel@tonic-gate /* 11887c478bd9Sstevel@tonic-gate * If -H was specified, and the file linked to was 11897c478bd9Sstevel@tonic-gate * not a directory, then we need to get the info 11907c478bd9Sstevel@tonic-gate * for the symlink itself. 11917c478bd9Sstevel@tonic-gate */ 11927c478bd9Sstevel@tonic-gate if ((Hflg) && (argfl) && 11937c478bd9Sstevel@tonic-gate ((statb.st_mode & S_IFMT) != S_IFDIR)) { 11947c478bd9Sstevel@tonic-gate if (lstat(file, &statb) < 0) { 11957c478bd9Sstevel@tonic-gate perror(file); 11967c478bd9Sstevel@tonic-gate } 11977c478bd9Sstevel@tonic-gate } 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate rep->lnum = statb.st_ino; 12007c478bd9Sstevel@tonic-gate rep->lsize = statb.st_size; 12017c478bd9Sstevel@tonic-gate rep->lblocks = statb.st_blocks; 12027c478bd9Sstevel@tonic-gate switch (statb.st_mode & S_IFMT) { 12037c478bd9Sstevel@tonic-gate case S_IFDIR: 12047c478bd9Sstevel@tonic-gate rep->ltype = 'd'; 12057c478bd9Sstevel@tonic-gate if (Rflg) { 12067c478bd9Sstevel@tonic-gate record_ancestry(file, &statb, rep, 12077c478bd9Sstevel@tonic-gate argfl, myparent); 12087c478bd9Sstevel@tonic-gate } 12097c478bd9Sstevel@tonic-gate break; 12107c478bd9Sstevel@tonic-gate case S_IFBLK: 12117c478bd9Sstevel@tonic-gate rep->ltype = 'b'; 12127c478bd9Sstevel@tonic-gate rep->lsize = (off_t)statb.st_rdev; 12137c478bd9Sstevel@tonic-gate break; 12147c478bd9Sstevel@tonic-gate case S_IFCHR: 12157c478bd9Sstevel@tonic-gate rep->ltype = 'c'; 12167c478bd9Sstevel@tonic-gate rep->lsize = (off_t)statb.st_rdev; 12177c478bd9Sstevel@tonic-gate break; 12187c478bd9Sstevel@tonic-gate case S_IFIFO: 12197c478bd9Sstevel@tonic-gate rep->ltype = 'p'; 12207c478bd9Sstevel@tonic-gate break; 12217c478bd9Sstevel@tonic-gate case S_IFSOCK: 12227c478bd9Sstevel@tonic-gate rep->ltype = 's'; 12237c478bd9Sstevel@tonic-gate rep->lsize = 0; 12247c478bd9Sstevel@tonic-gate break; 12257c478bd9Sstevel@tonic-gate case S_IFLNK: 12267c478bd9Sstevel@tonic-gate /* symbolic links may not have ACLs, so elide acl() */ 12277c478bd9Sstevel@tonic-gate if ((Lflg == 0) || (Hflg == 0) || 12287c478bd9Sstevel@tonic-gate ((Hflg) && (!argfl))) { 12297c478bd9Sstevel@tonic-gate doacl = 0; 12307c478bd9Sstevel@tonic-gate } 12317c478bd9Sstevel@tonic-gate rep->ltype = 'l'; 12327c478bd9Sstevel@tonic-gate if (lflg) { 12337c478bd9Sstevel@tonic-gate cc = readlink(file, buf, BUFSIZ); 12347c478bd9Sstevel@tonic-gate if (cc >= 0) { 12357c478bd9Sstevel@tonic-gate 12367c478bd9Sstevel@tonic-gate /* 12377c478bd9Sstevel@tonic-gate * follow the symbolic link 12387c478bd9Sstevel@tonic-gate * to generate the appropriate 12397c478bd9Sstevel@tonic-gate * Fflg marker for the object 12407c478bd9Sstevel@tonic-gate * eg, /bin -> /sym/bin/ 12417c478bd9Sstevel@tonic-gate */ 12427c478bd9Sstevel@tonic-gate if ((Fflg || pflg) && 12437c478bd9Sstevel@tonic-gate (stat(file, &statb1) >= 0)) { 12447c478bd9Sstevel@tonic-gate switch (statb1.st_mode & 12457c478bd9Sstevel@tonic-gate S_IFMT) { 12467c478bd9Sstevel@tonic-gate case S_IFDIR: 12477c478bd9Sstevel@tonic-gate buf[cc++] = '/'; 12487c478bd9Sstevel@tonic-gate break; 12497c478bd9Sstevel@tonic-gate case S_IFSOCK: 12507c478bd9Sstevel@tonic-gate buf[cc++] = '='; 12517c478bd9Sstevel@tonic-gate break; 12527c478bd9Sstevel@tonic-gate default: 12537c478bd9Sstevel@tonic-gate if ((statb1.st_mode & 12547c478bd9Sstevel@tonic-gate ~S_IFMT) & 12557c478bd9Sstevel@tonic-gate (S_IXUSR|S_IXGRP| 12567c478bd9Sstevel@tonic-gate S_IXOTH)) 12577c478bd9Sstevel@tonic-gate buf[cc++] = '*'; 12587c478bd9Sstevel@tonic-gate break; 12597c478bd9Sstevel@tonic-gate } 12607c478bd9Sstevel@tonic-gate } 12617c478bd9Sstevel@tonic-gate buf[cc] = '\0'; 12627c478bd9Sstevel@tonic-gate rep->flinkto = strdup(buf); 12637c478bd9Sstevel@tonic-gate } 12647c478bd9Sstevel@tonic-gate break; 12657c478bd9Sstevel@tonic-gate } 12667c478bd9Sstevel@tonic-gate 12677c478bd9Sstevel@tonic-gate /* 12687c478bd9Sstevel@tonic-gate * ls /sym behaves differently from ls /sym/ 12697c478bd9Sstevel@tonic-gate * when /sym is a symbolic link. This is fixed 12707c478bd9Sstevel@tonic-gate * when explicit arguments are specified. 12717c478bd9Sstevel@tonic-gate */ 12727c478bd9Sstevel@tonic-gate 12737c478bd9Sstevel@tonic-gate #ifdef XPG6 12747c478bd9Sstevel@tonic-gate /* Do not follow a symlink when -F is specified */ 12757c478bd9Sstevel@tonic-gate if ((!argfl) || (argfl && Fflg) || 12767c478bd9Sstevel@tonic-gate (stat(file, &statb1) < 0)) 12777c478bd9Sstevel@tonic-gate #else 12787c478bd9Sstevel@tonic-gate /* Follow a symlink when -F is specified */ 12797c478bd9Sstevel@tonic-gate if (!argfl || stat(file, &statb1) < 0) 12807c478bd9Sstevel@tonic-gate #endif /* XPG6 */ 12817c478bd9Sstevel@tonic-gate break; 12827c478bd9Sstevel@tonic-gate if ((statb1.st_mode & S_IFMT) == S_IFDIR) { 12837c478bd9Sstevel@tonic-gate statb = statb1; 12847c478bd9Sstevel@tonic-gate rep->ltype = 'd'; 12857c478bd9Sstevel@tonic-gate rep->lsize = statb1.st_size; 12867c478bd9Sstevel@tonic-gate if (Rflg) { 12877c478bd9Sstevel@tonic-gate record_ancestry(file, &statb, rep, 12887c478bd9Sstevel@tonic-gate argfl, myparent); 12897c478bd9Sstevel@tonic-gate } 12907c478bd9Sstevel@tonic-gate } 12917c478bd9Sstevel@tonic-gate break; 12927c478bd9Sstevel@tonic-gate case S_IFDOOR: 12937c478bd9Sstevel@tonic-gate rep->ltype = 'D'; 12947c478bd9Sstevel@tonic-gate break; 12957c478bd9Sstevel@tonic-gate case S_IFREG: 12967c478bd9Sstevel@tonic-gate rep->ltype = '-'; 12977c478bd9Sstevel@tonic-gate break; 12987c478bd9Sstevel@tonic-gate case S_IFPORT: 12997c478bd9Sstevel@tonic-gate rep->ltype = 'P'; 13007c478bd9Sstevel@tonic-gate break; 13017c478bd9Sstevel@tonic-gate default: 13027c478bd9Sstevel@tonic-gate rep->ltype = '?'; 13037c478bd9Sstevel@tonic-gate break; 13047c478bd9Sstevel@tonic-gate } 13057c478bd9Sstevel@tonic-gate rep->lflags = statb.st_mode & ~S_IFMT; 13067c478bd9Sstevel@tonic-gate 13077c478bd9Sstevel@tonic-gate if (!S_ISREG(statb.st_mode)) 13087c478bd9Sstevel@tonic-gate rep->lflags |= LS_NOTREG; 13097c478bd9Sstevel@tonic-gate 13107c478bd9Sstevel@tonic-gate /* ACL: check acl entries count */ 13117c478bd9Sstevel@tonic-gate if (doacl) { 13127c478bd9Sstevel@tonic-gate 1313fa9e4066Sahrens error = acl_get(file, 0, &rep->aclp); 1314fa9e4066Sahrens if (error) { 1315fa9e4066Sahrens (void) fprintf(stderr, 1316fa9e4066Sahrens gettext("ls: can't read ACL on %s: %s\n"), 1317fa9e4066Sahrens file, acl_strerror(error)); 13187c478bd9Sstevel@tonic-gate return (NULL); 13197c478bd9Sstevel@tonic-gate } 13207c478bd9Sstevel@tonic-gate 1321fa9e4066Sahrens rep->acl = ' '; 1322fa9e4066Sahrens 1323fa9e4066Sahrens if (rep->aclp && 1324fa9e4066Sahrens ((acl_flags(rep->aclp) & ACL_IS_TRIVIAL) == 0)) { 1325fa9e4066Sahrens rep->acl = '+'; 13267c478bd9Sstevel@tonic-gate /* 1327fa9e4066Sahrens * Special handling for ufs aka aclent_t ACL's 1328fa9e4066Sahrens */ 1329fa9e4066Sahrens if (rep->aclp && 1330fa9e4066Sahrens acl_type(rep->aclp) == ACLENT_T) { 1331fa9e4066Sahrens /* 1332fa9e4066Sahrens * For files with non-trivial acls, the 1333fa9e4066Sahrens * effective group permissions are the 1334fa9e4066Sahrens * intersection of the GROUP_OBJ value 1335fa9e4066Sahrens * and the CLASS_OBJ (acl mask) value. 1336fa9e4066Sahrens * Determine both the GROUP_OBJ and 1337fa9e4066Sahrens * CLASS_OBJ for this file and insert 1338fa9e4066Sahrens * the logical AND of those two values 1339fa9e4066Sahrens * in the group permissions field 1340fa9e4066Sahrens * of the lflags value for this file. 1341fa9e4066Sahrens */ 1342fa9e4066Sahrens 1343fa9e4066Sahrens /* 1344fa9e4066Sahrens * Until found in acl list, assume 1345fa9e4066Sahrens * maximum permissions for both group 1346fa9e4066Sahrens * a nd mask. (Just in case the acl 1347fa9e4066Sahrens * lacks either value for some reason.) 13487c478bd9Sstevel@tonic-gate */ 13497c478bd9Sstevel@tonic-gate groupperm = 07; 13507c478bd9Sstevel@tonic-gate mask = 07; 13517c478bd9Sstevel@tonic-gate grouppermfound = 0; 13527c478bd9Sstevel@tonic-gate maskfound = 0; 1353fa9e4066Sahrens aclcnt = acl_cnt(rep->aclp); 1354fa9e4066Sahrens for (tp = 1355fa9e4066Sahrens (aclent_t *)acl_data(rep->aclp); 1356fa9e4066Sahrens aclcnt--; tp++) { 13577c478bd9Sstevel@tonic-gate if (tp->a_type == GROUP_OBJ) { 13587c478bd9Sstevel@tonic-gate groupperm = tp->a_perm; 13597c478bd9Sstevel@tonic-gate grouppermfound = 1; 13607c478bd9Sstevel@tonic-gate continue; 13617c478bd9Sstevel@tonic-gate } 13627c478bd9Sstevel@tonic-gate if (tp->a_type == CLASS_OBJ) { 13637c478bd9Sstevel@tonic-gate mask = tp->a_perm; 13647c478bd9Sstevel@tonic-gate maskfound = 1; 13657c478bd9Sstevel@tonic-gate } 13667c478bd9Sstevel@tonic-gate if (grouppermfound && maskfound) 13677c478bd9Sstevel@tonic-gate break; 13687c478bd9Sstevel@tonic-gate } 13697c478bd9Sstevel@tonic-gate 13707c478bd9Sstevel@tonic-gate 13717c478bd9Sstevel@tonic-gate /* reset all the group bits */ 13727c478bd9Sstevel@tonic-gate rep->lflags &= ~S_IRWXG; 13737c478bd9Sstevel@tonic-gate 13747c478bd9Sstevel@tonic-gate /* 1375fa9e4066Sahrens * Now set them to the logical AND of 1376fa9e4066Sahrens * the GROUP_OBJ permissions and the 1377fa9e4066Sahrens * acl mask. 13787c478bd9Sstevel@tonic-gate */ 13797c478bd9Sstevel@tonic-gate 13807c478bd9Sstevel@tonic-gate rep->lflags |= (groupperm & mask) << 3; 1381fa9e4066Sahrens 1382fa9e4066Sahrens } 13837c478bd9Sstevel@tonic-gate } 13847c478bd9Sstevel@tonic-gate 1385*5a5eeccaSmarks if (!vflg && !Vflg && rep->aclp) { 1386*5a5eeccaSmarks acl_free(rep->aclp); 1387*5a5eeccaSmarks rep->aclp = NULL; 1388*5a5eeccaSmarks } 1389*5a5eeccaSmarks 13907c478bd9Sstevel@tonic-gate if (atflg && pathconf(file, _PC_XATTR_EXISTS) == 1) 13917c478bd9Sstevel@tonic-gate rep->acl = '@'; 13927c478bd9Sstevel@tonic-gate } else 13937c478bd9Sstevel@tonic-gate rep->acl = ' '; 13947c478bd9Sstevel@tonic-gate 13957c478bd9Sstevel@tonic-gate /* mask ISARG and other file-type bits */ 13967c478bd9Sstevel@tonic-gate 13977c478bd9Sstevel@tonic-gate rep->luid = statb.st_uid; 13987c478bd9Sstevel@tonic-gate rep->lgid = statb.st_gid; 13997c478bd9Sstevel@tonic-gate rep->lnl = statb.st_nlink; 14007c478bd9Sstevel@tonic-gate if (uflg) 14017c478bd9Sstevel@tonic-gate rep->lmtime = statb.st_atim; 14027c478bd9Sstevel@tonic-gate else if (cflg) 14037c478bd9Sstevel@tonic-gate rep->lmtime = statb.st_ctim; 14047c478bd9Sstevel@tonic-gate else 14057c478bd9Sstevel@tonic-gate rep->lmtime = statb.st_mtim; 14067c478bd9Sstevel@tonic-gate 14077c478bd9Sstevel@tonic-gate if (rep->ltype != 'b' && rep->ltype != 'c') 14087c478bd9Sstevel@tonic-gate tblocks += rep->lblocks; 14097c478bd9Sstevel@tonic-gate } 14107c478bd9Sstevel@tonic-gate return (rep); 14117c478bd9Sstevel@tonic-gate } 14127c478bd9Sstevel@tonic-gate 14137c478bd9Sstevel@tonic-gate /* 14147c478bd9Sstevel@tonic-gate * returns pathname of the form dir/file; 14157c478bd9Sstevel@tonic-gate * dir and file are null-terminated strings. 14167c478bd9Sstevel@tonic-gate */ 14177c478bd9Sstevel@tonic-gate static char * 14187c478bd9Sstevel@tonic-gate makename(char *dir, char *file) 14197c478bd9Sstevel@tonic-gate { 14207c478bd9Sstevel@tonic-gate /* 14217c478bd9Sstevel@tonic-gate * PATH_MAX is the maximum length of a path name. 14227c478bd9Sstevel@tonic-gate * MAXNAMLEN is the maximum length of any path name component. 14237c478bd9Sstevel@tonic-gate * Allocate space for both, plus the '/' in the middle 14247c478bd9Sstevel@tonic-gate * and the null character at the end. 14257c478bd9Sstevel@tonic-gate * dfile is static as this is returned by makename(). 14267c478bd9Sstevel@tonic-gate */ 14277c478bd9Sstevel@tonic-gate static char dfile[PATH_MAX + 1 + MAXNAMLEN + 1]; 14287c478bd9Sstevel@tonic-gate char *dp, *fp; 14297c478bd9Sstevel@tonic-gate 14307c478bd9Sstevel@tonic-gate dp = dfile; 14317c478bd9Sstevel@tonic-gate fp = dir; 14327c478bd9Sstevel@tonic-gate while (*fp) 14337c478bd9Sstevel@tonic-gate *dp++ = *fp++; 14347c478bd9Sstevel@tonic-gate if (dp > dfile && *(dp - 1) != '/') 14357c478bd9Sstevel@tonic-gate *dp++ = '/'; 14367c478bd9Sstevel@tonic-gate fp = file; 14377c478bd9Sstevel@tonic-gate while (*fp) 14387c478bd9Sstevel@tonic-gate *dp++ = *fp++; 14397c478bd9Sstevel@tonic-gate *dp = '\0'; 14407c478bd9Sstevel@tonic-gate return (dfile); 14417c478bd9Sstevel@tonic-gate } 14427c478bd9Sstevel@tonic-gate 14437c478bd9Sstevel@tonic-gate 14447c478bd9Sstevel@tonic-gate #include <pwd.h> 14457c478bd9Sstevel@tonic-gate #include <grp.h> 14467c478bd9Sstevel@tonic-gate #include <utmpx.h> 14477c478bd9Sstevel@tonic-gate 14487c478bd9Sstevel@tonic-gate struct utmpx utmp; 14497c478bd9Sstevel@tonic-gate 14507c478bd9Sstevel@tonic-gate #define NMAX (sizeof (utmp.ut_name)) 14517c478bd9Sstevel@tonic-gate #define SCPYN(a, b) (void) strncpy(a, b, NMAX) 14527c478bd9Sstevel@tonic-gate 14537c478bd9Sstevel@tonic-gate 14547c478bd9Sstevel@tonic-gate struct cachenode { /* this struct must be zeroed before using */ 14557c478bd9Sstevel@tonic-gate struct cachenode *lesschild; /* subtree whose entries < val */ 14567c478bd9Sstevel@tonic-gate struct cachenode *grtrchild; /* subtree whose entries > val */ 14577c478bd9Sstevel@tonic-gate long val; /* the uid or gid of this entry */ 14587c478bd9Sstevel@tonic-gate int initted; /* name has been filled in */ 14597c478bd9Sstevel@tonic-gate char name[NMAX+1]; /* the string that val maps to */ 14607c478bd9Sstevel@tonic-gate }; 14617c478bd9Sstevel@tonic-gate static struct cachenode *names, *groups; 14627c478bd9Sstevel@tonic-gate 14637c478bd9Sstevel@tonic-gate static struct cachenode * 14647c478bd9Sstevel@tonic-gate findincache(struct cachenode **head, long val) 14657c478bd9Sstevel@tonic-gate { 14667c478bd9Sstevel@tonic-gate struct cachenode **parent = head; 14677c478bd9Sstevel@tonic-gate struct cachenode *c = *parent; 14687c478bd9Sstevel@tonic-gate 14697c478bd9Sstevel@tonic-gate while (c != NULL) { 14707c478bd9Sstevel@tonic-gate if (val == c->val) { 14717c478bd9Sstevel@tonic-gate /* found it */ 14727c478bd9Sstevel@tonic-gate return (c); 14737c478bd9Sstevel@tonic-gate } else if (val < c->val) { 14747c478bd9Sstevel@tonic-gate parent = &c->lesschild; 14757c478bd9Sstevel@tonic-gate c = c->lesschild; 14767c478bd9Sstevel@tonic-gate } else { 14777c478bd9Sstevel@tonic-gate parent = &c->grtrchild; 14787c478bd9Sstevel@tonic-gate c = c->grtrchild; 14797c478bd9Sstevel@tonic-gate } 14807c478bd9Sstevel@tonic-gate } 14817c478bd9Sstevel@tonic-gate 14827c478bd9Sstevel@tonic-gate /* not in the cache, make a new entry for it */ 14837c478bd9Sstevel@tonic-gate c = calloc(1, sizeof (struct cachenode)); 14847c478bd9Sstevel@tonic-gate if (c == NULL) { 14857c478bd9Sstevel@tonic-gate perror("ls"); 14867c478bd9Sstevel@tonic-gate exit(2); 14877c478bd9Sstevel@tonic-gate } 14887c478bd9Sstevel@tonic-gate *parent = c; 14897c478bd9Sstevel@tonic-gate c->val = val; 14907c478bd9Sstevel@tonic-gate return (c); 14917c478bd9Sstevel@tonic-gate } 14927c478bd9Sstevel@tonic-gate 14937c478bd9Sstevel@tonic-gate /* 14947c478bd9Sstevel@tonic-gate * get name from cache, or passwd file for a given uid; 14957c478bd9Sstevel@tonic-gate * lastuid is set to uid. 14967c478bd9Sstevel@tonic-gate */ 14977c478bd9Sstevel@tonic-gate static char * 14987c478bd9Sstevel@tonic-gate getname(uid_t uid) 14997c478bd9Sstevel@tonic-gate { 15007c478bd9Sstevel@tonic-gate struct passwd *pwent; 15017c478bd9Sstevel@tonic-gate struct cachenode *c; 15027c478bd9Sstevel@tonic-gate 15037c478bd9Sstevel@tonic-gate if ((uid == lastuid) && lastuname) 15047c478bd9Sstevel@tonic-gate return (lastuname); 15057c478bd9Sstevel@tonic-gate 15067c478bd9Sstevel@tonic-gate c = findincache(&names, uid); 15077c478bd9Sstevel@tonic-gate if (c->initted == 0) { 15087c478bd9Sstevel@tonic-gate if ((pwent = getpwuid(uid)) != NULL) { 15097c478bd9Sstevel@tonic-gate SCPYN(&c->name[0], pwent->pw_name); 15107c478bd9Sstevel@tonic-gate } else { 15117c478bd9Sstevel@tonic-gate (void) sprintf(&c->name[0], "%-8u", (int)uid); 15127c478bd9Sstevel@tonic-gate } 15137c478bd9Sstevel@tonic-gate c->initted = 1; 15147c478bd9Sstevel@tonic-gate } 15157c478bd9Sstevel@tonic-gate lastuid = uid; 15167c478bd9Sstevel@tonic-gate lastuname = &c->name[0]; 15177c478bd9Sstevel@tonic-gate return (lastuname); 15187c478bd9Sstevel@tonic-gate } 15197c478bd9Sstevel@tonic-gate 15207c478bd9Sstevel@tonic-gate /* 15217c478bd9Sstevel@tonic-gate * get name from cache, or group file for a given gid; 15227c478bd9Sstevel@tonic-gate * lastgid is set to gid. 15237c478bd9Sstevel@tonic-gate */ 15247c478bd9Sstevel@tonic-gate static char * 15257c478bd9Sstevel@tonic-gate getgroup(gid_t gid) 15267c478bd9Sstevel@tonic-gate { 15277c478bd9Sstevel@tonic-gate struct group *grent; 15287c478bd9Sstevel@tonic-gate struct cachenode *c; 15297c478bd9Sstevel@tonic-gate 15307c478bd9Sstevel@tonic-gate if ((gid == lastgid) && lastgname) 15317c478bd9Sstevel@tonic-gate return (lastgname); 15327c478bd9Sstevel@tonic-gate 15337c478bd9Sstevel@tonic-gate c = findincache(&groups, gid); 15347c478bd9Sstevel@tonic-gate if (c->initted == 0) { 15357c478bd9Sstevel@tonic-gate if ((grent = getgrgid(gid)) != NULL) { 15367c478bd9Sstevel@tonic-gate SCPYN(&c->name[0], grent->gr_name); 15377c478bd9Sstevel@tonic-gate } else { 15387c478bd9Sstevel@tonic-gate (void) sprintf(&c->name[0], "%-8u", (int)gid); 15397c478bd9Sstevel@tonic-gate } 15407c478bd9Sstevel@tonic-gate c->initted = 1; 15417c478bd9Sstevel@tonic-gate } 15427c478bd9Sstevel@tonic-gate lastgid = gid; 15437c478bd9Sstevel@tonic-gate lastgname = &c->name[0]; 15447c478bd9Sstevel@tonic-gate return (lastgname); 15457c478bd9Sstevel@tonic-gate } 15467c478bd9Sstevel@tonic-gate 15477c478bd9Sstevel@tonic-gate /* return >0 if item pointed by pp2 should appear first */ 15487c478bd9Sstevel@tonic-gate static int 15497c478bd9Sstevel@tonic-gate compar(struct lbuf **pp1, struct lbuf **pp2) 15507c478bd9Sstevel@tonic-gate { 15517c478bd9Sstevel@tonic-gate struct lbuf *p1, *p2; 15527c478bd9Sstevel@tonic-gate 15537c478bd9Sstevel@tonic-gate p1 = *pp1; 15547c478bd9Sstevel@tonic-gate p2 = *pp2; 15557c478bd9Sstevel@tonic-gate if (dflg == 0) { 15567c478bd9Sstevel@tonic-gate /* 15577c478bd9Sstevel@tonic-gate * compare two names in ls-command one of which is file 15587c478bd9Sstevel@tonic-gate * and the other is a directory; 15597c478bd9Sstevel@tonic-gate * this portion is not used for comparing files within 15607c478bd9Sstevel@tonic-gate * a directory name of ls-command; 15617c478bd9Sstevel@tonic-gate */ 15627c478bd9Sstevel@tonic-gate if (p1->lflags&ISARG && p1->ltype == 'd') { 15637c478bd9Sstevel@tonic-gate if (!(p2->lflags&ISARG && p2->ltype == 'd')) 15647c478bd9Sstevel@tonic-gate return (1); 15657c478bd9Sstevel@tonic-gate } else { 15667c478bd9Sstevel@tonic-gate if (p2->lflags&ISARG && p2->ltype == 'd') 15677c478bd9Sstevel@tonic-gate return (-1); 15687c478bd9Sstevel@tonic-gate } 15697c478bd9Sstevel@tonic-gate } 15707c478bd9Sstevel@tonic-gate if (tflg) { 15717c478bd9Sstevel@tonic-gate if (p2->lmtime.tv_sec > p1->lmtime.tv_sec) 15727c478bd9Sstevel@tonic-gate return (rflg); 15737c478bd9Sstevel@tonic-gate else if (p2->lmtime.tv_sec < p1->lmtime.tv_sec) 15747c478bd9Sstevel@tonic-gate return (-rflg); 15757c478bd9Sstevel@tonic-gate /* times are equal to the sec, check nsec */ 15767c478bd9Sstevel@tonic-gate if (p2->lmtime.tv_nsec > p1->lmtime.tv_nsec) 15777c478bd9Sstevel@tonic-gate return (rflg); 15787c478bd9Sstevel@tonic-gate else if (p2->lmtime.tv_nsec < p1->lmtime.tv_nsec) 15797c478bd9Sstevel@tonic-gate return (-rflg); 15807c478bd9Sstevel@tonic-gate /* if times are equal, fall through and sort by name */ 15817c478bd9Sstevel@tonic-gate } else if (Sflg) { 15827c478bd9Sstevel@tonic-gate /* 15837c478bd9Sstevel@tonic-gate * The size stored in lsize can be either the 15847c478bd9Sstevel@tonic-gate * size or the major minor number (in the case of 15857c478bd9Sstevel@tonic-gate * block and character special devices). If it's 15867c478bd9Sstevel@tonic-gate * a major minor number, then the size is considered 15877c478bd9Sstevel@tonic-gate * to be zero and we want to fall through and sort 15887c478bd9Sstevel@tonic-gate * by name. In addition, if the size of p2 is equal 15897c478bd9Sstevel@tonic-gate * to the size of p1 we want to fall through and 15907c478bd9Sstevel@tonic-gate * sort by name. 15917c478bd9Sstevel@tonic-gate */ 15927c478bd9Sstevel@tonic-gate off_t p1size = (p1->ltype == 'b') || 15937c478bd9Sstevel@tonic-gate (p1->ltype == 'c') ? 0 : p1->lsize; 15947c478bd9Sstevel@tonic-gate off_t p2size = (p2->ltype == 'b') || 15957c478bd9Sstevel@tonic-gate (p2->ltype == 'c') ? 0 : p2->lsize; 15967c478bd9Sstevel@tonic-gate if (p2size > p1size) { 15977c478bd9Sstevel@tonic-gate return (rflg); 15987c478bd9Sstevel@tonic-gate } else if (p2size < p1size) { 15997c478bd9Sstevel@tonic-gate return (-rflg); 16007c478bd9Sstevel@tonic-gate } 16017c478bd9Sstevel@tonic-gate /* Sizes are equal, fall through and sort by name. */ 16027c478bd9Sstevel@tonic-gate } 16037c478bd9Sstevel@tonic-gate return (rflg * strcoll( 16047c478bd9Sstevel@tonic-gate p1->lflags & ISARG ? p1->ln.namep : p1->ln.lname, 16057c478bd9Sstevel@tonic-gate p2->lflags&ISARG ? p2->ln.namep : p2->ln.lname)); 16067c478bd9Sstevel@tonic-gate } 16077c478bd9Sstevel@tonic-gate 16087c478bd9Sstevel@tonic-gate static void 16097c478bd9Sstevel@tonic-gate pprintf(char *s1, char *s2) 16107c478bd9Sstevel@tonic-gate { 16117c478bd9Sstevel@tonic-gate csi_pprintf((unsigned char *)s1); 16127c478bd9Sstevel@tonic-gate csi_pprintf((unsigned char *)s2); 16137c478bd9Sstevel@tonic-gate } 16147c478bd9Sstevel@tonic-gate 16157c478bd9Sstevel@tonic-gate static void 16167c478bd9Sstevel@tonic-gate csi_pprintf(unsigned char *s) 16177c478bd9Sstevel@tonic-gate { 16187c478bd9Sstevel@tonic-gate unsigned char *cp; 16197c478bd9Sstevel@tonic-gate char c; 16207c478bd9Sstevel@tonic-gate int i; 16217c478bd9Sstevel@tonic-gate int c_len; 16227c478bd9Sstevel@tonic-gate int p_col; 16237c478bd9Sstevel@tonic-gate wchar_t pcode; 16247c478bd9Sstevel@tonic-gate 16257c478bd9Sstevel@tonic-gate if (!qflg && !bflg) { 16267c478bd9Sstevel@tonic-gate for (cp = s; *cp != '\0'; cp++) { 16277c478bd9Sstevel@tonic-gate (void) putchar(*cp); 16287c478bd9Sstevel@tonic-gate curcol++; 16297c478bd9Sstevel@tonic-gate } 16307c478bd9Sstevel@tonic-gate return; 16317c478bd9Sstevel@tonic-gate } 16327c478bd9Sstevel@tonic-gate 16337c478bd9Sstevel@tonic-gate for (cp = s; *cp; ) { 16347c478bd9Sstevel@tonic-gate if (isascii(c = *cp)) { 16357c478bd9Sstevel@tonic-gate if (!isprint(c)) { 16367c478bd9Sstevel@tonic-gate if (qflg) { 16377c478bd9Sstevel@tonic-gate c = '?'; 16387c478bd9Sstevel@tonic-gate } else { 16397c478bd9Sstevel@tonic-gate curcol += 3; 16407c478bd9Sstevel@tonic-gate (void) putc('\\', stdout); 16417c478bd9Sstevel@tonic-gate c = '0' + ((*cp >> 6) & 07); 16427c478bd9Sstevel@tonic-gate (void) putc(c, stdout); 16437c478bd9Sstevel@tonic-gate c = '0' + ((*cp >> 3) & 07); 16447c478bd9Sstevel@tonic-gate (void) putc(c, stdout); 16457c478bd9Sstevel@tonic-gate c = '0' + (*cp & 07); 16467c478bd9Sstevel@tonic-gate } 16477c478bd9Sstevel@tonic-gate } 16487c478bd9Sstevel@tonic-gate curcol++; 16497c478bd9Sstevel@tonic-gate cp++; 16507c478bd9Sstevel@tonic-gate (void) putc(c, stdout); 16517c478bd9Sstevel@tonic-gate continue; 16527c478bd9Sstevel@tonic-gate } 16537c478bd9Sstevel@tonic-gate 16547c478bd9Sstevel@tonic-gate if ((c_len = mbtowc(&pcode, (char *)cp, MB_LEN_MAX)) <= 0) { 16557c478bd9Sstevel@tonic-gate c_len = 1; 16567c478bd9Sstevel@tonic-gate goto not_print; 16577c478bd9Sstevel@tonic-gate } 16587c478bd9Sstevel@tonic-gate 16597c478bd9Sstevel@tonic-gate if ((p_col = wcwidth(pcode)) > 0) { 16607c478bd9Sstevel@tonic-gate (void) putwchar(pcode); 16617c478bd9Sstevel@tonic-gate cp += c_len; 16627c478bd9Sstevel@tonic-gate curcol += p_col; 16637c478bd9Sstevel@tonic-gate continue; 16647c478bd9Sstevel@tonic-gate } 16657c478bd9Sstevel@tonic-gate 16667c478bd9Sstevel@tonic-gate not_print: 16677c478bd9Sstevel@tonic-gate for (i = 0; i < c_len; i++) { 16687c478bd9Sstevel@tonic-gate if (qflg) { 16697c478bd9Sstevel@tonic-gate c = '?'; 16707c478bd9Sstevel@tonic-gate } else { 16717c478bd9Sstevel@tonic-gate curcol += 3; 16727c478bd9Sstevel@tonic-gate (void) putc('\\', stdout); 16737c478bd9Sstevel@tonic-gate c = '0' + ((*cp >> 6) & 07); 16747c478bd9Sstevel@tonic-gate (void) putc(c, stdout); 16757c478bd9Sstevel@tonic-gate c = '0' + ((*cp >> 3) & 07); 16767c478bd9Sstevel@tonic-gate (void) putc(c, stdout); 16777c478bd9Sstevel@tonic-gate c = '0' + (*cp & 07); 16787c478bd9Sstevel@tonic-gate } 16797c478bd9Sstevel@tonic-gate curcol++; 16807c478bd9Sstevel@tonic-gate (void) putc(c, stdout); 16817c478bd9Sstevel@tonic-gate cp++; 16827c478bd9Sstevel@tonic-gate } 16837c478bd9Sstevel@tonic-gate } 16847c478bd9Sstevel@tonic-gate } 16857c478bd9Sstevel@tonic-gate 16867c478bd9Sstevel@tonic-gate static int 16877c478bd9Sstevel@tonic-gate strcol(unsigned char *s1) 16887c478bd9Sstevel@tonic-gate { 16897c478bd9Sstevel@tonic-gate int w; 16907c478bd9Sstevel@tonic-gate int w_col; 16917c478bd9Sstevel@tonic-gate int len; 16927c478bd9Sstevel@tonic-gate wchar_t wc; 16937c478bd9Sstevel@tonic-gate 16947c478bd9Sstevel@tonic-gate w = 0; 16957c478bd9Sstevel@tonic-gate while (*s1) { 16967c478bd9Sstevel@tonic-gate if (isascii(*s1)) { 16977c478bd9Sstevel@tonic-gate w++; 16987c478bd9Sstevel@tonic-gate s1++; 16997c478bd9Sstevel@tonic-gate continue; 17007c478bd9Sstevel@tonic-gate } 17017c478bd9Sstevel@tonic-gate 17027c478bd9Sstevel@tonic-gate if ((len = mbtowc(&wc, (char *)s1, MB_LEN_MAX)) <= 0) { 17037c478bd9Sstevel@tonic-gate w++; 17047c478bd9Sstevel@tonic-gate s1++; 17057c478bd9Sstevel@tonic-gate continue; 17067c478bd9Sstevel@tonic-gate } 17077c478bd9Sstevel@tonic-gate 17087c478bd9Sstevel@tonic-gate if ((w_col = wcwidth(wc)) < 0) 17097c478bd9Sstevel@tonic-gate w_col = len; 17107c478bd9Sstevel@tonic-gate s1 += len; 17117c478bd9Sstevel@tonic-gate w += w_col; 17127c478bd9Sstevel@tonic-gate } 17137c478bd9Sstevel@tonic-gate return (w); 17147c478bd9Sstevel@tonic-gate } 17157c478bd9Sstevel@tonic-gate 17167c478bd9Sstevel@tonic-gate /* 17177c478bd9Sstevel@tonic-gate * Convert an unsigned long long to a string representation and place the 17187c478bd9Sstevel@tonic-gate * result in the caller-supplied buffer. 17197c478bd9Sstevel@tonic-gate * 17207c478bd9Sstevel@tonic-gate * The number provided is a size in bytes. The number is first 17217c478bd9Sstevel@tonic-gate * converted to an integral multiple of 'scale' bytes. This new 17227c478bd9Sstevel@tonic-gate * number is then scaled down until it is small enough to be in a good 17237c478bd9Sstevel@tonic-gate * human readable format, i.e. in the range 0 thru scale-1. If the 17247c478bd9Sstevel@tonic-gate * number used to derive the final number is not a multiple of scale, and 17257c478bd9Sstevel@tonic-gate * the final number has only a single significant digit, we compute 17267c478bd9Sstevel@tonic-gate * tenths of units to provide a second significant digit. 17277c478bd9Sstevel@tonic-gate * 17287c478bd9Sstevel@tonic-gate * The value "(unsigned long long)-1" is a special case and is always 17297c478bd9Sstevel@tonic-gate * converted to "-1". 17307c478bd9Sstevel@tonic-gate * 17317c478bd9Sstevel@tonic-gate * A pointer to the caller-supplied buffer is returned. 17327c478bd9Sstevel@tonic-gate */ 17337c478bd9Sstevel@tonic-gate static char * 17347c478bd9Sstevel@tonic-gate number_to_scaled_string( 17357c478bd9Sstevel@tonic-gate numbuf_t buf, /* put the result here */ 17367c478bd9Sstevel@tonic-gate unsigned long long number, /* convert this number */ 17377c478bd9Sstevel@tonic-gate long scale) 17387c478bd9Sstevel@tonic-gate { 17397c478bd9Sstevel@tonic-gate unsigned long long save; 17407c478bd9Sstevel@tonic-gate /* Measurement: kilo, mega, giga, tera, peta, exa */ 17417c478bd9Sstevel@tonic-gate char *uom = "KMGTPE"; 17427c478bd9Sstevel@tonic-gate 17437c478bd9Sstevel@tonic-gate if ((long long)number == (long long)-1) { 17447c478bd9Sstevel@tonic-gate (void) strlcpy(buf, "-1", sizeof (numbuf_t)); 17457c478bd9Sstevel@tonic-gate return (buf); 17467c478bd9Sstevel@tonic-gate } 17477c478bd9Sstevel@tonic-gate 17487c478bd9Sstevel@tonic-gate save = number; 17497c478bd9Sstevel@tonic-gate number = number / scale; 17507c478bd9Sstevel@tonic-gate 17517c478bd9Sstevel@tonic-gate /* 17527c478bd9Sstevel@tonic-gate * Now we have number as a count of scale units. 17537c478bd9Sstevel@tonic-gate * If no further scaling is necessary, we round up as appropriate. 17547c478bd9Sstevel@tonic-gate * 17557c478bd9Sstevel@tonic-gate * The largest value number could have had entering the routine is 17567c478bd9Sstevel@tonic-gate * 16 Exabytes, so running off the end of the uom array should 17577c478bd9Sstevel@tonic-gate * never happen. We check for that, though, as a guard against 17587c478bd9Sstevel@tonic-gate * a breakdown elsewhere in the algorithm. 17597c478bd9Sstevel@tonic-gate */ 17607c478bd9Sstevel@tonic-gate if (number < (unsigned long long)scale) { 17617c478bd9Sstevel@tonic-gate if ((save % scale) >= (unsigned long long)(scale / 2)) { 17627c478bd9Sstevel@tonic-gate if (++number == (unsigned long long)scale) { 17637c478bd9Sstevel@tonic-gate uom++; 17647c478bd9Sstevel@tonic-gate number = 1; 17657c478bd9Sstevel@tonic-gate } 17667c478bd9Sstevel@tonic-gate } 17677c478bd9Sstevel@tonic-gate } else { 17687c478bd9Sstevel@tonic-gate while ((number >= (unsigned long long)scale) && (*uom != 'E')) { 17697c478bd9Sstevel@tonic-gate uom++; /* next unit of measurement */ 17707c478bd9Sstevel@tonic-gate save = number; 17717c478bd9Sstevel@tonic-gate /* 17727c478bd9Sstevel@tonic-gate * If we're over half way to the next unit of 17737c478bd9Sstevel@tonic-gate * 'scale' bytes (which means we should round 17747c478bd9Sstevel@tonic-gate * up), then adding half of 'scale' prior to 17757c478bd9Sstevel@tonic-gate * the division will push us into that next 17767c478bd9Sstevel@tonic-gate * unit of scale when we perform the division 17777c478bd9Sstevel@tonic-gate */ 17787c478bd9Sstevel@tonic-gate number = (number + (scale / 2)) / scale; 17797c478bd9Sstevel@tonic-gate } 17807c478bd9Sstevel@tonic-gate } 17817c478bd9Sstevel@tonic-gate 17827c478bd9Sstevel@tonic-gate /* check if we should output a decimal place after the point */ 17837c478bd9Sstevel@tonic-gate if ((save / scale) < 10) { 17847c478bd9Sstevel@tonic-gate /* snprintf() will round for us */ 17857c478bd9Sstevel@tonic-gate float fnum = (float)save / scale; 17867c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (numbuf_t), "%2.1f%c", 17877c478bd9Sstevel@tonic-gate fnum, *uom); 17887c478bd9Sstevel@tonic-gate } else { 17897c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (numbuf_t), "%4llu%c", 17907c478bd9Sstevel@tonic-gate number, *uom); 17917c478bd9Sstevel@tonic-gate } 17927c478bd9Sstevel@tonic-gate return (buf); 17937c478bd9Sstevel@tonic-gate } 1794