* Copyright (c) 1989 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
"@(#) Copyright (c) 1989 The Regents of the University of California.\n\
static char sccsid
[] = "@(#)ls.c 5.26 (Berkeley) %G%";
int qflg
, Aflg
, Cflg
, Fflg
, Lflg
, Rflg
, Sflg
;
int termwidth
= 80; /* default terminal width */
int f_accesstime
; /* use time of last access */
int f_group
; /* show group ownership of a file */
int f_ignorelink
; /* indirect through symbolic link operands */
int f_inode
; /* print inode */
int f_listalldot
; /* list . and .. as well */
int f_listdir
; /* list actual directory, not contents */
int f_listdot
; /* list files beginning with . */
int f_longform
; /* long listing format */
int f_nonprint
; /* show unprintables as ? */
int f_recursive
; /* ls subdirectories also */
int f_reversesort
; /* reverse whatever sort is used */
int f_singlecol
; /* use single column output */
int f_size
; /* list size in short listing */
int f_specialdir
; /* force params to be directories */
int f_statustime
; /* use time of last mode change */
int f_timesort
; /* sort by time vice name */
int f_type
; /* add type character for non-regular files */
extern int optind
, stat();
int namecmp(), revnamecmp(), acccmp(), revacccmp();
int modcmp(), revmodcmp(), statcmp(), revstatcmp();
int printcol(), printlong(), printscol();
* terminal defaults to -C -q
* non-terminal defaults to -1
if (ioctl(1, TIOCGWINSZ
, &win
) == -1 || !win
.ws_col
) {
if (p
= getenv("COLUMNS"))
/* root is -A automatically */
while ((ch
= getopt(argc
, argv
, "1ACFLRacdfgilqrstu")) != EOF
) {
* -1, -C and -l all override each other
* so shell aliasing works right
f_longform
= f_singlecol
= 0;
/* -c and -u override each other */
Sflg
++; /* fall into... */
/* -f turns off -F, -R, -l, -t, -s, -r, turns on -a */
f_longform
= f_recursive
= f_reversesort
= f_size
=
f_listdot
= f_listalldot
= 1;
/* if need to stat files */
needstat
= f_longform
|| f_recursive
|| f_timesort
|| f_size
|| f_type
;
/* select a sort function */
else /* use modification time */
else /* use modification time */
/* select a print function */
if (lstat(local
.name
= ".", &local
.lstat
)) {
(void)fprintf(stderr
, "ls: .: %s\n", strerror(errno
));
if (num
= tabdir(&local
, &stats
, &names
))
static char path
[MAXPATHLEN
+ 1];
static char *endofpath
= path
;
register LS
*dstatp
, *rstatp
;
register int cnt
, dircnt
, regcnt
;
int num
, (*statfcn
)(), stat(), lstat();
char *names
, top
[MAXPATHLEN
+ 1];
* walk through the operands, building separate arrays of LS
* structures for directory and non-directory files.
statfcn
= f_ignorelink
? stat
: lstat
;
for (dircnt
= regcnt
= 0; *argv
; ++argv
) {
if (statfcn(*argv
, &sb
)) {
(void)fprintf(stderr
, "ls: %s: %s\n",
if (!f_specialdir
&& !f_listdir
&& S_ISDIR(sb
.st_mode
)) {
dstatp
= dstats
= (LS
*)emalloc((u_int
)argc
*
rstatp
= rstats
= (LS
*)emalloc((u_int
)argc
*
/* display regular files */
* for -f flag -- switch above treats all -f operands as
* regular files; this code uses tabdir() to read
for (cnt
= regcnt
; cnt
--;) {
if (num
= tabdir(rstats
++, &stats
, &names
))
(void)free((char *)stats
);
(void)free((char *)names
);
displaydir(rstats
, regcnt
);
/* display directories */
qsort((char *)dstats
, dircnt
, sizeof(LS
), sortfcn
);
for (cnt
= 0; cnt
< dircnt
; ++dstats
) {
for (endofpath
= path
, p
= dstats
->name
;
*endofpath
= *p
++; ++endofpath
);
subdir(dstats
, regcnt
|| cnt
, regcnt
|| dircnt
> 1);
if (++cnt
< dircnt
&& chdir(top
)) {
(void)fprintf(stderr
, "ls: %s: %s\n",
register char *p
, *savedpath
;
if (num
> 1 && !f_specialdir
) {
save1
= stats
[0].lstat
.st_btotal
;
save2
= stats
[0].lstat
.st_maxlen
;
qsort((char *)stats
, num
, sizeof(LS
), sortfcn
);
stats
[0].lstat
.st_btotal
= save1
;
stats
[0].lstat
.st_maxlen
= save2
;
for (lp
= stats
; num
--; ++lp
) {
if (!S_ISDIR(lp
->lstat
.st_mode
))
if (p
[0] == '.' && (!p
[1] || p
[1] == '.' && !p
[2]))
if (endofpath
!= path
&& endofpath
[-1] != '/')
for (; *endofpath
= *p
++; ++endofpath
);
*(endofpath
= savedpath
) = '\0';
* this doesn't really belong here, but it's the only place that
* everybody goes through; the `tag' variable is so that we don't
* print the header for directories unless we're going to display
* more directories, or we've already displayed files or directories.
* The `newline' variable keeps us from inserting a newline before
* we've displayed anything at all.
(void)printf("%s:\n", path
);
(void)fprintf(stderr
, "ls: %s: %s\n",
lp
->name
, strerror(errno
));
if (num
= tabdir(lp
, &stats
, &names
))
(void)free((char *)stats
);
(void)free((char *)names
);
(void)fprintf(stderr
, "ls: ..: %s\n", strerror(errno
));
tabdir(lp
, s_stats
, s_names
)
register int cnt
, maxentry
, maxlen
;
register char *p
, *names
;
* allocate space for array of LS structures and the file names
* the name field will point to. Make it big so we don't have
*s_stats
= stats
= (LS
*)emalloc((u_int
)DEFNUM
* sizeof(LS
));
*s_names
= names
= emalloc((u_int
)lp
->lstat
.st_size
);
if (!(dirp
= opendir(f_specialdir
? lp
->name
: "."))) {
(void)fprintf(stderr
, "ls: %s: %s\n", lp
->name
,
for (cnt
= 0; dp
= readdir(dirp
);) {
/* this does -A and -a */
if (!f_listalldot
&& (!p
[1] || p
[1] == '.' && !p
[2]))
if (!(stats
= (LS
*)realloc((char *)stats
,
(u_int
)maxentry
* sizeof(LS
))))
if (needstat
&& lstat(dp
->d_name
, &stats
[cnt
].lstat
)) {
(void)fprintf(stderr
, "ls: %s: %s\n",
dp
->d_name
, strerror(errno
));
/* strip out unprintables */
prcopy(dp
->d_name
, names
, (int)dp
->d_namlen
);
bcopy(dp
->d_name
, names
, (int)dp
->d_namlen
);
* get the inode from the directory, so the -f flag
stats
[cnt
].lstat
.st_ino
= dp
->d_ino
;
/* save name length for -C format */
stats
[cnt
].len
= dp
->d_namlen
;
/* calculate number of blocks if -l format */
if (f_longform
|| f_size
)
blocks
+= stats
[cnt
].lstat
.st_blocks
;
/* save max length if -C format */
if (!f_longform
&& !f_singlecol
&& maxlen
< (int)dp
->d_namlen
)
stats
[0].lstat
.st_btotal
= blocks
;
stats
[0].lstat
.st_maxlen
= maxlen
;