* 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, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
"@(#) Copyright (c) 1989 The Regents of the University of California.\n\
static char sccsid
[] = "@(#)ls.c 5.48 (Berkeley) 4/3/91";
static char rcsid
[] = "$Header: /b/source/CVS/src/bin/ls/ls.c,v 1.5 1993/05/26 10:23:24 deraadt Exp $";
int (*sortfcn
)(), (*printfcn
)();
int termwidth
= 80; /* default terminal width */
int f_accesstime
; /* use time of last access */
int f_column
; /* columnated format */
int f_group
; /* show group ownership of a file */
int f_ignorelink
; /* indirect through symbolic link operands */
int f_inode
; /* print inode */
int f_kblocks
; /* print size in kilobytes */
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_needstat
; /* if need to stat files */
int f_newline
; /* if precede with newline */
int f_nonprint
; /* show unprintables as ? */
int f_nosort
; /* don't sort output */
int f_recursive
; /* ls subdirectories also */
int f_reversesort
; /* reverse whatever sort is used */
int f_sectime
; /* print the real time for all files */
int f_singlecol
; /* use single column output */
int f_size
; /* list size in short listing */
int f_statustime
; /* use time of last mode change */
int f_dirname
; /* if precede with directory name */
int f_timesort
; /* sort by time vice name */
int f_total
; /* if precede with "total" line */
int f_type
; /* add type character for non-regular files */
int (*statfcn
)(), stat(), lstat();
extern int optind
, stat();
int acccmp(), modcmp(), namecmp(), prcopy(), printcol();
int printlong(), printscol(), revacccmp(), revmodcmp(), revnamecmp();
int revstatcmp(), statcmp();
/* terminal defaults to -Cq, 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
, "1ACFLRTacdfgiklqrstu")) != EOF
) {
* -1, -C and -l all override each other
* so shell aliasing works right
f_column
= f_longform
= 0;
f_longform
= f_singlecol
= 0;
f_column
= f_singlecol
= 0;
/* -c and -u override each other */
/* if need to stat files */
f_needstat
= f_longform
|| f_recursive
|| f_timesort
||
/* select a sort function */
else /* use modification time */
else /* use modification time */
/* select a print function */
/* if -l, -d, -R, or -F, and not ignoring the link, use lstat() */
(f_longform
|| f_listdir
|| f_type
|| f_recursive
) && !f_ignorelink
? lstat
: stat
;
static char path
[MAXPATHLEN
+ 1];
static char *endofpath
= path
;
register LS
*dstatp
, *rstatp
;
register int cnt
, dircnt
, maxlen
, regcnt
;
char top
[MAXPATHLEN
+ 1];
* walk through the operands, building separate arrays of LS
* structures for directory and non-directory files.
for (dircnt
= regcnt
= 0; *argv
; ++argv
) {
if (statfcn(*argv
, &sb
) &&
(statfcn
== lstat
|| lstat(*argv
, &sb
))) {
"ls: %s: %s\n", *argv
, strerror(errno
));
if (S_ISDIR(sb
.st_mode
) && !f_listdir
) {
dstatp
= dstats
= (LS
*)emalloc((u_int
)argc
*
rstatp
= rstats
= (LS
*)emalloc((u_int
)argc
*
/* save name length for -C format */
rstatp
->len
= strlen(*argv
);
prcopy(*argv
, *argv
, rstatp
->len
);
/* calculate number of blocks if -l/-s formats */
if (f_longform
|| f_size
)
/* save max length if -C format */
if (f_column
&& maxlen
< rstatp
->len
)
/* display regular files */
rstats
[0].lstat
.st_btotal
= blocks
;
rstats
[0].lstat
.st_maxlen
= maxlen
;
displaydir(rstats
, regcnt
);
f_newline
= f_dirname
= 1;
/* display directories */
qsort((char *)dstats
, dircnt
, sizeof(LS
), sortfcn
);
for (cnt
= 0; cnt
< dircnt
; ++dstats
) {
for (endofpath
= path
, p
= dstats
->name
;
*endofpath
= *p
++; ++endofpath
);
if (++cnt
< dircnt
&& chdir(top
)) {
(void)fprintf(stderr
, "ls: %s: %s\n",
register char *p
, *savedpath
;
if (num
> 1 && !f_nosort
) {
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
);
f_newline
= f_dirname
= f_total
= 1;
*(endofpath
= savedpath
) = '\0';
(void)printf("%s:\n", path
);
(void)fprintf(stderr
, "ls: %s: %s\n", lp
->name
,
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
;
if (!(dirp
= opendir("."))) {
(void)fprintf(stderr
, "ls: %s: %s\n", lp
->name
,
blocks
= maxentry
= maxlen
= 0;
for (cnt
= 0; dp
= readdir(dirp
);) {
/* this does -A and -a */
if (!f_listalldot
&& (!p
[1] || p
[1] == '.' && !p
[2]))
emalloc((u_int
)lp
->lstat
.st_size
);
if (!(*s_stats
= stats
= (LS
*)realloc((char *)stats
,
(u_int
)maxentry
* sizeof(LS
))))
if (f_needstat
&& statfcn(dp
->d_name
, &stats
[cnt
].lstat
) &&
statfcn
== stat
&& lstat(dp
->d_name
, &stats
[cnt
].lstat
)) {
* don't exit -- this could be an NFS mount that has
* gone away. Flush stdout so the messages line up.
"ls: %s: %s\n", dp
->d_name
, strerror(errno
));
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/-s formats */
if (f_longform
|| f_size
)
blocks
+= stats
[cnt
].lstat
.st_blocks
;
/* save max length if -C format */
if (f_column
&& maxlen
< (int)dp
->d_namlen
)
stats
[0].lstat
.st_btotal
= blocks
;
stats
[0].lstat
.st_maxlen
= maxlen
;
(void)free((char *)stats
);
(void)free((char *)names
);