/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
* Copyright 2015 Gary Mills
*/
/*
* Copyright 2009 Jason King. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/* Copyright (c) 1987, 1988 Microsoft Corporation */
/* All Rights Reserved */
/*
* List files or directories
*/
#include <wchar.h>
#include <stdio.h>
#include <ctype.h>
#include <dirent.h>
#include <string.h>
#include <locale.h>
#include <curses.h>
#include <term.h>
#include <termios.h>
#include <stdlib.h>
#include <widec.h>
#include <locale.h>
#include <wctype.h>
#include <pwd.h>
#include <grp.h>
#include <limits.h>
#include <fcntl.h>
#include <unistd.h>
#include <libgen.h>
#include <errno.h>
#include <aclutils.h>
#include <libnvpair.h>
#include <libcmdutils.h>
#include <attr.h>
#include <getopt.h>
#include <inttypes.h>
#ifndef STANDALONE
#define TERMINFO
#endif
/*
* -DNOTERMINFO can be defined on the cc command line to prevent
* the use of terminfo. This should be done on systems not having
* the terminfo feature(pre 6.0 systems ?).
* As a result, columnar listings assume 80 columns for output,
* unless told otherwise via the COLUMNS environment variable.
*/
#ifdef NOTERMINFO
#endif
#include <term.h>
/* this bit equals 1 in lflags of structure lbuf if *namep is to be used */
/*
* this flag has been added to manipulate the display of S instead of 'l' when
* the file is not a regular file and when group execution bit is off
*/
/*
* Date and time formats
*
* b --- abbreviated month name
* e --- day number
* Y --- year in the form ccyy
* H --- hour(24-hour version)
* M --- minute
* F --- yyyy-mm-dd
* T --- hh:mm:ss
* z --- time zone as hours displacement from UTC
* note that %F and %z are from the ISO C99 standard and are
* not present in older C libraries
*/
struct ditem {
};
/* Holds boolean extended system attributes */
struct attrb {
char *name;
};
/* Holds timestamp extended system attributes */
struct attrtm {
char *name;
};
#define LSA_NONE (0)
/* these should be ordered most general to most specific */
typedef enum LS_CFTYPE {
} ls_cftype_t;
typedef struct {
char *sfx;
int attr;
int fg;
int bg;
} ls_color_t;
struct lbuf {
union {
} ln;
};
struct dchain {
};
/*
* A numbuf_t is used when converting a number to a string representation
*/
static char *makename(char *, char *);
static void column(void);
static void selection(int *);
static void new_line(void);
static int strcol(unsigned char *);
static void pdirectory(char *, int, int, int, struct ditem *);
static void csi_pprintf(unsigned char *);
static void pprintf(char *, char *);
unsigned long long number,
long scale);
int, struct ditem *);
static void ls_color_init(void);
static void ls_start_color(ls_color_t *);
static void ls_end_color(void);
static int aflg;
static int atflg;
static int bflg;
static int cflg;
static int dflg;
static int eflg;
static int fflg;
static int gflg;
static int hflg;
static int iflg;
static int lflg;
static int mflg;
static int nflg;
static int oflg;
static int pflg;
static int qflg;
static int sflg;
static int tflg;
static int uflg;
static int Uflg;
static int wflg;
static int xflg;
static int Aflg;
static int Bflg;
static int Cflg;
static int Eflg;
static int Fflg;
static int Hflg;
static int Lflg;
static int Rflg;
static int Sflg;
static int vflg;
static int Vflg;
static int copt;
static int vopt;
static int ctm;
static int atm;
static int mtm;
static int crtm;
static int alltm;
static long hscale;
static int colorflg;
static int file_typeflg;
static int noflist = 0;
/* statreq > 0 if any of sflg, (n)lflg, tflg, Sflg, colorflg are on */
static int statreq;
static int colwidth;
static int filewidth;
static int fixedwidth;
static int nomocore;
static int curcol;
/* if time_fmt_new is left NULL, time_fmt_old is used for all times */
static int lsc_debug;
static char *lsc_bold;
static char *lsc_underline;
static char *lsc_blink;
static char *lsc_reverse;
static char *lsc_concealed;
static char *lsc_none;
static char *lsc_setfg;
static char *lsc_setbg;
/* Extended system attributes support */
static int get_sysxattr(char *, struct lbuf *);
static void set_sysattrtm_display(char *, struct lbuf *);
static void print_time(struct lbuf *);
static void format_attrtime(struct lbuf *);
static void free_sysattr(struct lbuf *);
static int acl_err;
/* no short options for these */
{0, 0, 0, 0}
};
int
{
int c;
int i;
int width;
int amino = 0;
int opterr = 0;
int option_index = 0;
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
#endif
(void) textdomain(TEXT_DOMAIN);
#ifdef STANDALONE
if (argv[0][0] == '\0')
#endif
if (isatty(1)) {
Cflg = 1;
mflg = 0;
}
"+aAbBcCdeEfFghHiklLmnopqrRsStuUw:x1@vV/:%:", long_options,
&option_index)) != -1)
switch (c) {
case 0:
/* non-short options */
"color") == 0 ||
"colour") == 0) {
colorflg++;
statreq++;
continue;
}
colorflg++;
statreq++;
}
continue;
}
colorflg = 0;
continue;
}
gettext("Invalid argument '%s' for "
"--color\n"), optarg);
++opterr;
continue;
}
"si") == 0) {
hflg++;
hscale = 1000;
continue;
}
"block-size") == 0) {
char scale_c;
if (scale_len == 0) {
"Invalid block size \'%s\'\n"),
optarg);
exit(1);
}
if (scale_c == 'B') {
/* need at least digit, scale, B */
if (scale_len < 3) {
"Invalid block size "
"\'%s\'\n"), optarg);
exit(1);
}
kilo = 1000;
gettext("Invalid block size"
" \'%s\'\n"), optarg);
exit(1);
}
/*
* make optarg[scale_len - 1] point to
* the scale factor
*/
--scale_len;
}
switch (scale_c) {
case 'y':
case 'Y':
/*FALLTHROUGH*/
case 'Z':
case 'z':
/*FALLTHROUGH*/
case 'E':
case 'e':
/*FALLTHROUGH*/
case 'P':
case 'p':
/*FALLTHROUGH*/
case 'T':
case 't':
/*FALLTHROUGH*/
case 'G':
case 'g':
/*FALLTHROUGH*/
case 'M':
case 'm':
/*FALLTHROUGH*/
case 'K':
case 'k':
break;
default:
gettext("Invalid character "
"following block size in "
"\'%s\'\n"), optarg);
exit(1);
}
}
/* NULL out scale constant if present */
/* Based on testing, this is what GNU ls does */
if (block_size < 1) {
gettext("Invalid block size "
"\'%s\'\n"), optarg);
exit(1);
}
continue;
}
"file-type") == 0) {
file_typeflg++;
Fflg++;
statreq++;
continue;
}
"full-time") == 0) {
Eflg++;
statreq++;
eflg = 0;
continue;
}
"time-style") == 0) {
/* like -E, but doesn't imply -l */
Eflg++;
statreq++;
eflg = 0;
continue;
}
statreq++;
Eflg = 0;
eflg = 0;
continue;
}
statreq++;
Eflg = 0;
eflg = 0;
continue;
}
/* should be the default */
continue;
}
if (optarg[0] == '+') {
char *p;
if (p != NULL)
*p++ = '\0';
/*
* Time format requires a leading and
* trailing space
* Add room for 3 spaces + 2 nulls
* The + in optarg is replaced with
* a space.
*/
perror("ls");
exit(2);
}
told[0] = ' ';
timelen);
if (p != NULL) {
tnew[0] = ' ';
tnew_len);
tnew_len);
(const char *)tnew;
} else {
(const char *)told;
}
time_fmt_old = (const char *)told;
time_custom = 1;
continue;
}
continue;
}
continue;
case 'a':
aflg++;
continue;
case 'A':
Aflg++;
continue;
case 'b':
bflg = 1;
qflg = 0;
continue;
case 'B':
Bflg = 1;
continue;
case 'c':
uflg = 0;
atm = 0;
ctm = 0;
mtm = 0;
crtm = 0;
cflg++;
continue;
case 'C':
Cflg = 1;
mflg = 0;
#ifdef XPG4
lflg = 0;
#endif
continue;
case 'd':
dflg++;
continue;
case 'e':
eflg++;
lflg++;
statreq++;
Eflg = 0;
continue;
case 'E':
Eflg++;
lflg++;
statreq++;
eflg = 0;
continue;
case 'f':
fflg++;
continue;
case 'F':
Fflg++;
statreq++;
continue;
case 'g':
gflg++;
lflg++;
statreq++;
continue;
case 'h':
hflg++;
hscale = 1024;
continue;
case 'H':
Hflg++;
/* -H and -L are mutually exclusive */
Lflg = 0;
continue;
case 'i':
iflg++;
continue;
case 'k':
block_size = 1024;
continue;
case 'l':
lflg++;
statreq++;
Cflg = 0;
xflg = 0;
mflg = 0;
atflg = 0;
continue;
case 'L':
Lflg++;
/* -H and -L are mutually exclusive */
Hflg = 0;
continue;
case 'm':
Cflg = 0;
mflg = 1;
#ifdef XPG4
lflg = 0;
#endif
continue;
case 'n':
nflg++;
lflg++;
statreq++;
Cflg = 0;
xflg = 0;
mflg = 0;
atflg = 0;
continue;
case 'o':
oflg++;
lflg++;
statreq++;
continue;
case 'p':
pflg++;
statreq++;
continue;
case 'q':
qflg = 1;
bflg = 0;
continue;
case 'r':
rflg = -1;
continue;
case 'R':
Rflg++;
statreq++;
continue;
case 's':
sflg++;
statreq++;
continue;
case 'S':
tflg = 0;
Uflg = 0;
Sflg++;
statreq++;
continue;
case 't':
Sflg = 0;
Uflg = 0;
tflg++;
statreq++;
continue;
case 'U':
Sflg = 0;
tflg = 0;
Uflg++;
continue;
case 'u':
cflg = 0;
atm = 0;
ctm = 0;
mtm = 0;
crtm = 0;
uflg++;
continue;
case 'V':
Vflg++;
/*FALLTHROUGH*/
case 'v':
vflg++;
#if !defined(XPG4)
if (lflg)
continue;
#endif
lflg++;
statreq++;
Cflg = 0;
xflg = 0;
mflg = 0;
continue;
case 'w':
wflg++;
continue;
case 'x':
xflg = 1;
Cflg = 1;
mflg = 0;
#ifdef XPG4
lflg = 0;
#endif
continue;
case '1':
Cflg = 0;
continue;
case '@':
#if !defined(XPG4)
/*
* -l has precedence over -@
*/
if (lflg)
continue;
#endif
atflg++;
lflg++;
statreq++;
Cflg = 0;
xflg = 0;
mflg = 0;
continue;
case '/':
saflg++;
copt++;
vopt = 0;
vopt++;
copt = 0;
} else
opterr++;
} else
opterr++;
lflg++;
statreq++;
Cflg = 0;
xflg = 0;
mflg = 0;
continue;
case '%':
tmflg++;
ctm++;
atm = 0;
mtm = 0;
crtm = 0;
atm++;
ctm = 0;
mtm = 0;
crtm = 0;
uflg = 0;
cflg = 0;
mtm++;
atm = 0;
ctm = 0;
crtm = 0;
uflg = 0;
cflg = 0;
crtm++;
atm = 0;
ctm = 0;
mtm = 0;
uflg = 0;
cflg = 0;
alltm++;
atm = 0;
ctm = 0;
mtm = 0;
crtm = 0;
} else
opterr++;
} else
opterr++;
Sflg = 0;
statreq++;
mflg = 0;
continue;
case '?':
opterr++;
continue;
}
if (opterr) {
"usage: ls -aAbBcCdeEfFghHiklLmnopqrRsStuUwxvV1@/%[c | v]"
"%%[atime | crtime | ctime | mtime | all]"
" [files]\n"));
exit(2);
}
if (fflg) {
aflg++;
lflg = 0;
sflg = 0;
tflg = 0;
Sflg = 0;
statreq = 0;
}
fixedwidth = 2;
fixedwidth++;
if (iflg)
fixedwidth += 11;
if (sflg)
fixedwidth += 5;
if (lflg) {
else
}
char *clptr;
#ifdef TERMINFO
else {
}
#endif
}
/*
* When certain options (-f, or -U and -1, and not -l, etc.) are
* specified, don't cache each dirent as it's read. This 'noflist'
* option is set when there's no need to cache those dirents; instead,
* print them out as they're read.
*/
noflist = 1;
/* assume it is an error */
num_cols = 80;
/* allocate space for flist and the associated */
/* data structures (lbufs) */
perror("ls");
exit(2);
}
/*
* case when no names are given
* in ls-command and current
* directory is to be used
*/
}
if (colorflg)
/*
* If we are recursing, we need to make sure we don't
* get into an endless loop. To keep track of the inodes
* (actually, just the directories) visited, we
* maintain a directory ancestry list for a file
* hierarchy. As we go deeper into the hierarchy,
* a parent directory passes its directory list
* info (device id, inode number, and a pointer to
* its parent) to each of its children. As we
* process a child that is a directory, we save
* its own personal directory list info. We then
* check to see if the child has already been
* processed by comparing its device id and inode
* number from its own personal directory list info
* to that of each of its ancestors. If there is a
* match, then we know we've detected a cycle.
*/
if (Rflg) {
/*
* This is the first parent in this lineage
* (first in a directory hierarchy), so
* this parent's parent doesn't exist. We
* only initialize myinfo when we are
* recursing, otherwise it's not used.
*/
perror("ls");
exit(2);
} else {
}
}
}
if (nomocore)
exit(2);
err = 2;
optind++;
continue;
}
optind++;
nargs++; /* count good arguments stored in flist */
if (acl_err)
err = 2;
}
if (!Uflg)
(int (*)(const void *, const void *))compar);
for (i = 0; i < nargs; i++) {
break;
}
for (; i < nargs; i++) {
if (nomocore)
exit(2);
/* -R: print subdirectories found */
/* Place direct subdirs on front in right order */
while (cdfirst) {
/* reverse cdfirst onto front of dfirst */
}
/* take off first dir on dfirst & print it */
if (nomocore)
exit(2);
}
}
return (err);
}
/*
* pdirectory: print the directory name, labelling it if title is
* nonzero, using lp as the place to start reading in the dir.
*/
static void
{
char *pname;
int j;
filewidth = 0;
if (title) {
if (!first)
new_line();
}
/*
* If there was a cycle detected, then notify and don't report
* further.
*/
if (cdetect) {
new_line();
}
"ls: cycle detected for %s\n"), name);
return;
}
return;
sizeof (struct lbuf *),
(int (*)(const void *, const void *))compar);
if (Rflg) {
perror("ls");
exit(2);
}
perror("ls");
exit(2);
}
}
}
}
new_line();
}
}
/*
* pem: print 'em. Print a list of files (e.g. a directory) bounded
* by slp and lp.
*/
static void
{
}
}
new_line();
return;
}
/* otherwise print -C columns */
if (tot_flag) {
slp--;
row = 1;
}
else
row = 0;
}
new_line();
}
}
/*
* print one output entry;
*/
static void
{
struct lbuf *p;
char *cp;
char *str;
if (noflist) {
return;
}
p = ap;
column();
if (iflg) {
else
}
if (sflg) {
}
if (lflg) {
curcol++;
/* ACL: additional access mode flag */
curcol++;
if (oflg) {
if (!nflg) {
} else
}
if (gflg) {
if (!nflg) {
} else
}
} else {
/*
* Round up only when using blocks > 1 byte, otherwise
* 'normal' sizes display 1 byte too large.
*/
if (p->lsize % block_size != 0)
bsize++;
}
/* format extended system attribute time */
format_attrtime(p);
}
/*
* prevent both "->" and trailing marks
* from appearing
*/
dmark = "/";
if (p->ltype == 'd')
dmark = "/";
else if (p->ltype == 'D')
dmark = ">";
else if (p->ltype == 'p')
dmark = "|";
else if (p->ltype == 'l')
dmark = "@";
else if (p->ltype == 's')
dmark = "=";
else if (!file_typeflg &&
dmark = "*";
else
dmark = "";
}
if (colorflg)
ls_start_color(p->color);
else
csi_pprintf((unsigned char *)str);
if (colorflg)
ls_end_color();
csi_pprintf((unsigned char *)" -> ");
if (colorflg)
ls_start_color(p->link_color);
csi_pprintf((unsigned char *)p->flinkto);
} else {
csi_pprintf((unsigned char *)dmark);
}
} else {
if (colorflg)
ls_end_color();
str = " -> ";
if (colorflg)
ls_start_color(p->link_color);
} else {
}
}
if (colorflg)
ls_end_color();
/* Display extended system attributes */
if (saflg) {
int i;
new_line();
(void) printf(" \t{");
int k = 0;
for (i = 0; i < sacnt; i++) {
k++;
}
for (i = 0; i < sacnt; i++) {
k--;
if (vopt && (k != 0))
(void) printf(",");
}
}
}
(void) printf("}\n");
}
/* Display file timestamps and extended system attribute timestamps */
new_line();
print_time(p);
new_line();
}
if (vflg) {
new_line();
if (p->aclp) {
}
}
/* Free extended system attribute lists */
free_sysattr(p);
}
/* print various r,w,x permissions */
static void
{
/* these arrays are declared static to allow initializations */
#ifdef XPG4
#else
#endif
int **mp;
}
static void
{
int n;
n = *pairp++;
while (n-->0) {
pairp++;
break;
} else {
pairp += 2;
}
}
curcol++;
}
/*
* column: get to the beginning of the next column.
*/
static void
column(void)
{
if (curcol == 0)
return;
if (mflg) {
curcol++;
curcol = 0;
return;
}
curcol++;
return;
}
if (Cflg == 0) {
curcol = 0;
return;
}
curcol = 0;
return;
}
do {
curcol++;
}
static void
new_line(void)
{
if (curcol) {
first = 0;
curcol = 0;
}
}
/*
* read each filename in directory dir and store its
* status in flist[nfiles]
*/
static void
{
int j;
int width;
err = 2;
return;
} else {
tblocks = 0;
for (;;) {
errno = 0;
break;
(Aflg == 0 ||
/*
* check for directory items '.', '..',
* and items without valid inode-number;
*/
continue;
/* skip entries ending in ~ if -B was given */
if (Bflg &&
continue;
}
if (nomocore)
exit(2);
continue;
} else {
/*
* Since this entry doesn't need to be sorted
* or further processed, print it right away.
*/
if (noflist) {
nfiles--;
}
}
}
if (errno) {
gettext("ls: error reading directory %s: %s\n"),
}
}
}
/*
* Attaching a link to an inode's ancestors. Search
* through the ancestors to check for cycles (an inode which
* we have already tracked in this inodes ancestry). If a cycle
* is detected, set the exit code and record the fact so that
* it is reported at the right time when printing the directory.
* In addition, set the exit code. Note: If the -a flag was
* specified, we don't want to check for cycles for directories
* ending in '/.' or '/..' unless they were specified on the
* command line.
*/
static void
{
/*
* Add this inode's ancestry
* info and insert it into the
* ancestry list by pointing
* back to its parent. We save
* it (in rep) with the other info
* we're gathering for this inode.
*/
perror("ls");
exit(2);
}
/*
* If this node has the same device id and
* inode number of one of its ancestors,
* then we've detected a cycle.
*/
/*
* Cycle detected for this
* directory. Record the fact
* it is a cycle so we don't
* try to process this
* directory as we are
* walking through the
* list of directories.
*/
err = 2;
break;
}
}
}
}
}
/*
* Do re-calculate the mode for group for ACE_T type of acls.
* This is because, if the server's FS happens to be UFS, supporting
* POSIX ACL's, then it does a special calculation of group mode
* to be the bitwise OR of CLASS_OBJ and GROUP_OBJ (see PSARC/2001/717.)
*
* This algorithm is from the NFSv4 ACL Draft. Here a part of that
* algorithm is used for the group mode calculation only.
* What is modified here from the algorithm is that only the
* entries with flags ACE_GROUP are considered. For each entry
* with ACE_GROUP flag, the first occurance of a specific access
* is checked if it is allowed.
* We are not interested in perms for user and other, as they
* were taken from st_mode value.
* We are not interested in a_who field of ACE, as we need just
* unix mode bits for the group.
*/
int
{
int acecnt;
int flags;
continue;
continue;
/*
* if it is first group@ or first everyone@
* for each of read, write and execute, then
* that will be the group mode bit.
*/
}
}
}
}
}
}
}
}
return (mode);
}
/*
* get status of file and recomputes tblocks;
* argfl = 1 if file is a name in ls-command and = 0
* for filename in a directory whose name is an
* argument in the command;
* stores a pointer in flist[nfiles] and
* returns that pointer;
* returns NULL if failed;
*/
static struct lbuf *
{
int aclcnt;
int error;
if (nomocore)
return (NULL);
/*
* more space
*/
perror("ls");
nomocore = 1;
return (NULL);
}
}
/*
* nfiles is reset to nargs for each directory
* that is given as an argument maxn is checked
* to prevent the assignment of an lbuf to a flist entry
* that already has one assigned.
*/
} else {
}
/* Clear the lbuf */
/*
* When noflist is set, none of the extra information about the dirent
* will be printed, so omit remaining initialization of this lbuf
* as well as the stat(2) call.
*/
return (rep);
/* Initialize non-zero members */
int doacl;
if (lflg)
doacl = 1;
else
doacl = 0;
/*
* Avoid race between readdir and lstat.
* Print error message in case of dangling link.
*/
err = 2;
}
nfiles--;
return (NULL);
}
/*
* If -H was specified, and the file linked to was
* not a directory, then we need to get the info
* for the symlink itself.
*/
err = 2;
}
}
if (colorflg)
case S_IFDIR:
if (Rflg) {
}
break;
case S_IFBLK:
break;
case S_IFCHR:
break;
case S_IFIFO:
break;
case S_IFSOCK:
break;
case S_IFLNK:
/* symbolic links may not have ACLs, so elide acl() */
doacl = 0;
}
if (cc < 0)
break;
/*
* follow the symbolic link
* to generate the appropriate
* Fflg marker for the object
*/
error = 0;
if (colorflg) {
if (error >= 0)
rep->link_color =
else
rep->link_color =
}
case S_IFDIR:
break;
case S_IFSOCK:
break;
case S_IFDOOR:
break;
case S_IFIFO:
break;
default:
break;
}
}
perror("ls");
nomocore = 1;
return (NULL);
}
break;
}
/*
* ls /sym behaves differently from ls /sym/
* when /sym is a symbolic link. This is fixed
* when explicit arguments are specified.
*/
#ifdef XPG6
/* Do not follow a symlink when -F is specified */
#else
/* Follow a symlink when -F is specified */
#endif /* XPG6 */
break;
if (Rflg) {
}
}
break;
case S_IFDOOR:
break;
case S_IFREG:
break;
case S_IFPORT:
break;
default:
break;
}
else
/* ACL: check acl entries count */
if (doacl) {
if (error) {
gettext("ls: can't read ACL on %s: %s\n"),
acl_err++;
return (rep);
}
/*
* Special handling for ufs aka aclent_t ACL's
*/
/*
* For files with non-trivial acls, the
* effective group permissions are the
* intersection of the GROUP_OBJ value
* and the CLASS_OBJ (acl mask) value.
* Determine both the GROUP_OBJ and
* CLASS_OBJ for this file and insert
* the logical AND of those two values
* in the group permissions field
* of the lflags value for this file.
*/
/*
* Until found in acl list, assume
* maximum permissions for both group
* a nd mask. (Just in case the acl
* lacks either value for some reason.)
*/
groupperm = 07;
mask = 07;
grouppermfound = 0;
maskfound = 0;
for (tp =
grouppermfound = 1;
continue;
}
maskfound = 1;
}
if (grouppermfound && maskfound)
break;
}
/* reset all the group bits */
/*
* Now set them to the logical AND of
* the GROUP_OBJ permissions and the
* acl mask.
*/
int mode;
}
}
}
} else
/* mask ISARG and other file-type bits */
/* Get extended system attributes */
int i;
sacnt = attr_count();
/*
* Allocate 'sacnt' size array to hold extended
* system attribute name (verbose) or respective
* symbol represenation (compact).
*/
rep);
/* initialize boolean attribute list */
for (i = 0; i < sacnt; i++)
gettext("ls:Failed to retrieve "
"extended system attribute from "
"%s\n"), file);
}
}
}
return (rep);
}
/*
* dir and file are null-terminated strings.
*/
static char *
{
/*
* PATH_MAX is the maximum length of a path name.
* MAXNAMLEN is the maximum length of any path name component.
* Allocate space for both, plus the '/' in the middle
* and the null character at the end.
* dfile is static as this is returned by makename().
*/
while (*fp)
*dp++ = '/';
while (*fp)
*dp = '\0';
return (dfile);
}
#include <pwd.h>
#include <grp.h>
#include <utmpx.h>
};
static struct cachenode *
{
while (c != NULL) {
/* found it */
return (c);
c = c->lesschild;
} else {
c = c->grtrchild;
}
}
/* not in the cache, make a new entry for it */
if (c == NULL) {
perror("ls");
exit(2);
}
*parent = c;
return (c);
}
/*
* get name from cache, or passwd file for a given uid;
* lastuid is set to uid.
*/
static char *
{
struct cachenode *c;
return (lastuname);
if (c->initted == 0) {
} else {
}
c->initted = 1;
}
return (lastuname);
}
/*
* get name from cache, or group file for a given gid;
* lastgid is set to gid.
*/
static char *
{
struct cachenode *c;
return (lastgname);
if (c->initted == 0) {
} else {
}
c->initted = 1;
}
return (lastgname);
}
/* return >0 if item pointed by pp2 should appear first */
static int
{
if (dflg == 0) {
/*
* compare two names in ls-command one of which is file
* and the other is a directory;
* this portion is not used for comparing files within
* a directory name of ls-command;
*/
return (1);
} else {
return (-1);
}
}
if (tflg) {
return (rflg);
return (-rflg);
/* times are equal to the sec, check nsec */
return (rflg);
return (-rflg);
/* if times are equal, fall through and sort by name */
} else if (Sflg) {
/*
* The size stored in lsize can be either the
* size or the major minor number (in the case of
* block and character special devices). If it's
* a major minor number, then the size is considered
* to be zero and we want to fall through and sort
* by name. In addition, if the size of p2 is equal
* to the size of p1 we want to fall through and
* sort by name.
*/
return (rflg);
return (-rflg);
}
/* Sizes are equal, fall through and sort by name. */
}
}
static void
{
csi_pprintf((unsigned char *)s1);
csi_pprintf((unsigned char *)s2);
}
static void
csi_pprintf(unsigned char *s)
{
unsigned char *cp;
char c;
int i;
int c_len;
int p_col;
curcol++;
}
return;
}
if (!isprint(c)) {
if (qflg) {
c = '?';
} else {
curcol += 3;
}
}
curcol++;
cp++;
continue;
}
c_len = 1;
goto not_print;
}
continue;
}
for (i = 0; i < c_len; i++) {
if (qflg) {
c = '?';
} else {
curcol += 3;
}
curcol++;
cp++;
}
}
}
static int
{
int w;
int w_col;
int len;
w = 0;
while (*s1) {
w++;
s1++;
continue;
}
w++;
s1++;
continue;
}
w += w_col;
}
return (w);
}
/*
* Convert an unsigned long long to a string representation and place the
* result in the caller-supplied buffer.
*
* The number provided is a size in bytes. The number is first
* converted to an integral multiple of 'scale' bytes. This new
* number is then scaled down until it is small enough to be in a good
* human readable format, i.e. in the range 0 thru scale-1. If the
* number used to derive the final number is not a multiple of scale, and
* the final number has only a single significant digit, we compute
* tenths of units to provide a second significant digit.
*
* The value "(unsigned long long)-1" is a special case and is always
* converted to "-1".
*
* A pointer to the caller-supplied buffer is returned.
*/
static char *
unsigned long long number, /* convert this number */
long scale)
{
unsigned long long save;
/* Measurement: kilo, mega, giga, tera, peta, exa */
if ((long long)number == (long long)-1) {
return (buf);
}
/*
* Now we have number as a count of scale units.
* If no further scaling is necessary, we round up as appropriate.
*
* The largest value number could have had entering the routine is
* 16 Exabytes, so running off the end of the uom array should
* never happen. We check for that, though, as a guard against
* a breakdown elsewhere in the algorithm.
*/
uom++;
number = 1;
}
}
} else {
uom++; /* next unit of measurement */
/*
* If we're over half way to the next unit of
* 'scale' bytes (which means we should round
* up), then adding half of 'scale' prior to
* the division will push us into that next
* unit of scale when we perform the division
*/
}
}
/* check if we should output a decimal place after the point */
/* snprintf() will round for us */
} else {
}
return (buf);
}
/* Get extended system attributes and set the display */
int
{
int error;
char *name;
int i;
&response)) != 0) {
perror("ls:getattrat");
return (error);
}
/*
* Allocate 'sacnt' size array to hold extended timestamp
* system attributes and initialize the array.
*/
for (i = 0; i < sacnt; i++) {
}
if (type == DATA_TYPE_BOOLEAN_VALUE) {
if (error) {
gettext("nvpair_value_boolean_value "
"failed: error = %d\n"), error);
continue;
}
continue;
} else if (type == DATA_TYPE_UINT64_ARRAY) {
continue;
}
}
return (0);
}
/* Set extended system attribute boolean display */
void
{
const char *opt;
if (vopt) {
if (val) {
len + 1);
} else {
"no%s", name);
}
} else {
if (val)
else
}
}
}
}
/* Set extended system attribute timestamp display */
void
{
int i;
i = 0;
i++;
}
}
}
void
{
if (Eflg) {
return;
}
fstr = time_fmt_old;
/* if a custom time was specified, shouldn't be localized */
}
void
{
int tmattr = 0;
int i;
for (i = 0; i < sacnt; i++) {
tmattr = 1;
break;
}
}
}
if (tmattr) {
/* Eflg always sets format to FORMAT_ISO_FULL */
if (!Eflg && !time_custom) {
}
}
}
void
{
int i = 0;
if (!Eflg) {
}
new_line();
(void) printf(" timestamp:"
" %s %s\n",
}
i++;
}
}
}
/*
* Check if color definition applies to entry, returns 1 if yes, 0 if no
*/
static int
{
case LS_PAT:
{
return (0);
return (1);
else
return (0);
}
case LS_NORMAL:
return (1);
case LS_FILE:
case LS_DIR:
case LS_LINK:
case LS_FIFO:
case LS_SOCK:
case LS_DOOR:
case LS_BLK:
case LS_CHR:
case LS_PORT:
case LS_ORPHAN:
/* this is tested for by gstat */
return (0);
case LS_SETUID:
case LS_SETGID:
case LS_STICKY_OTHER_WRITABLE:
case LS_OTHER_WRITABLE:
case LS_STICKY:
case LS_EXEC:
}
return (0);
}
static void
{
if (c == NULL)
return;
(void) printf("\n\ttype: ");
switch (c->ftype) {
case LS_NORMAL:
(void) printf("LS_NORMAL");
break;
case LS_FILE:
(void) printf("LS_FILE");
break;
case LS_EXEC:
(void) printf("LS_EXEC");
break;
case LS_DIR:
(void) printf("LS_DIR");
break;
case LS_LINK:
(void) printf("LS_LINK");
break;
case LS_FIFO:
(void) printf("LS_FIFO");
break;
case LS_SOCK:
(void) printf("LS_SOCK");
break;
case LS_DOOR:
(void) printf("LS_DOOR");
break;
case LS_BLK:
(void) printf("LS_BLK");
break;
case LS_CHR:
(void) printf("LS_CHR");
break;
case LS_PORT:
(void) printf("LS_PORT");
break;
case LS_STICKY:
(void) printf("LS_STICKY");
break;
case LS_ORPHAN:
(void) printf("LS_ORPHAN");
break;
case LS_SETGID:
(void) printf("LS_SETGID");
break;
case LS_SETUID:
(void) printf("LS_SETUID");
break;
case LS_OTHER_WRITABLE:
(void) printf("LS_OTHER_WRITABLE");
break;
case LS_STICKY_OTHER_WRITABLE:
(void) printf("LS_STICKY_OTHER_WRITABLE");
break;
case LS_PAT:
(void) printf("LS_PAT\n");
break;
}
(void) printf("\n");
(void) printf("\t");
}
static ls_color_t *
{
int i;
/*
* Colors are sorted from most general lsc_colors[0] to most specific
* lsc_colors[lsc_ncolors - 1] by ls_color_init(). Start search with
* most specific color rule and work towards most general.
*/
for (i = lsc_ncolors - 1; i >= 0; --i)
return (&lsc_colors[i]);
return (NULL);
}
static void
{
char *s;
return;
if (s != NULL)
(void) putp(s);
}
static void
{
if (c == NULL)
return;
if (lsc_debug)
lsc_match = c;
if (c->attr & LSA_UNDERSCORE)
ls_tprint(lsc_underline, 0, 0, 0, 0, 0, 0, 0, 0, 0);
if (c->attr & LSA_REVERSE)
ls_tprint(lsc_reverse, 0, 0, 0, 0, 0, 0, 0, 0, 0);
if (c->attr & LSA_CONCEALED)
ls_tprint(lsc_concealed, 0, 0, 0, 0, 0, 0, 0, 0, 0);
if (c->fg != -1)
if (c->bg != -1)
}
static void
{
if (lsc_debug)
}
static void
{
static const struct {
const char *s;
} type_map[] = {
{ "no", LS_NORMAL },
{ "fi", LS_FILE },
{ "di", LS_DIR },
{ "ln", LS_LINK },
{ "pi", LS_FIFO },
{ "so", LS_SOCK },
{ "do", LS_DOOR },
{ "bd", LS_BLK },
{ "cd", LS_CHR },
{ "or", LS_ORPHAN },
{ "su", LS_SETUID },
{ "sg", LS_SETGID },
{ "tw", LS_STICKY_OTHER_WRITABLE },
{ "ow", LS_OTHER_WRITABLE },
{ "st", LS_STICKY },
{ "ex", LS_EXEC },
{ "po", LS_PORT },
};
char *p, *lasts;
int i;
if (p == NULL) {
colorflg = 0;
return;
}
if (p[0] == '*') {
/* don't include the * in the suffix */
colorflg = 0;
return;
}
} else {
break;
}
/* ignore unknown file types */
return;
}
if (color < 10) {
switch (color) {
case 0:
continue;
case 1:
continue;
case 4:
attr |= LSA_UNDERSCORE;
continue;
case 5:
continue;
case 7:
attr |= LSA_REVERSE;
continue;
case 8:
attr |= LSA_CONCEALED;
continue;
default:
continue;
}
}
if (color < 40)
else
}
++lsc_ncolors;
}
static int
{
if (ret != 0)
return (ret);
return (ret);
}
static void
{
":pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01"
":su=37;41:sg=30;43:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31"
":*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31"
":*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.deb=01;31"
":*.rpm=01;31:*.jar=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35"
":*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35"
":*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35"
":*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.avi=01;35:*.fli=01;35"
":*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.flac=01;35"
":*.mp3=01;35:*.mpc=01;35:*.ogg=01;35:*.wav=01;35";
char *colorstr;
char *p, *lasts;
int termret;
int i;
if (termret != 1)
return;
p = default_colorstr;
return;
/*
* Determine the size of lsc_colors. color_sz can be > lsc_ncolors
* if there are invalid entries passed in the string (they are ignored)
*/
color_sz = 1;
p = strchr(++p, ':'))
++color_sz;
if (lsc_colors == NULL) {
return;
}
new_color_entry(p);
for (i = 0; i < lsc_ncolors; ++i)
lsc_orphan = &lsc_colors[i];
break;
}
lsc_reverse = NULL;
int i;
lsc_debug = 1;
for (i = 0; i < lsc_ncolors; ++i)
dump_color(&lsc_colors[i]);
}
}
/* Free extended system attribute lists */
void
{
int i;
for (i = 0; i < sacnt; i++) {
}
}
for (i = 0; i < sacnt; i++) {
}
}
}
/* Allocate extended system attribute list */
void *
{
perror("ls");
free_sysattr(p);
exit(2);
}
return (p);
}