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