899 lines
20 KiB
C
899 lines
20 KiB
C
/*
|
|
* Derived from Berkeley source code. Those parts are
|
|
* Copyright (c) 1989 The Regents of the University of California.
|
|
* All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to Berkeley by
|
|
* Michael Fischbein.
|
|
*
|
|
* Redistribution and use in source and binary forms are permitted
|
|
* provided that: (1) source distributions retain this entire copyright
|
|
* notice and comment, and (2) distributions including binaries display
|
|
* the following acknowledgement: ``This product includes software
|
|
* developed by the University of California, Berkeley and its contributors''
|
|
* in the documentation or other materials provided with the distribution
|
|
* and in all advertising materials mentioning features or use of this
|
|
* software. 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
*/
|
|
|
|
#ifndef lint
|
|
char copyright[] =
|
|
"@(#) Copyright (c) 1989 The Regents of the University of California.\n\
|
|
All rights reserved.\n";
|
|
#endif /* not lint */
|
|
|
|
#ifndef lint
|
|
static char sccsid[] = "@(#)ls.c 5.42 (Berkeley) 5/17/90";
|
|
#endif /* not lint */
|
|
|
|
#define DAYSPERNYEAR (365)
|
|
#define SECSPERDAY (24*60*60)
|
|
#define UT_NAMESIZE 8
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#ifndef S_ISLNK /* On the sun, this is defined for us in
|
|
/usr/include/sys/stat.h, but it must not be
|
|
defined there on all machines, or Berkeley
|
|
wouldn't have put this into ls.c, right?
|
|
--swa@isi.edu */
|
|
#define S_ISLNK(m) ((S_IFLNK & m) == S_IFLNK)
|
|
#endif
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <sys/param.h>
|
|
#include <sys/ioctl.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <grp.h>
|
|
#include <pwd.h>
|
|
#include <utmp.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <pcompat.h>
|
|
#include <pmachine.h>
|
|
|
|
#ifdef USE_SYS_DIR_H
|
|
#include <sys/dir.h>
|
|
#else
|
|
#include <dirent.h>
|
|
#endif
|
|
|
|
/* At the moment this program doesn't work under HP-UX, because the
|
|
compatability library's version of opendir() fails under HP-UX.
|
|
*/
|
|
#ifdef HPUX
|
|
#error "The program ls.c should not be compiled under HP-UX, since it will \
|
|
not work. It relies upon the compatability library's version of opendir(), \
|
|
which has not yet been ported to HP-UX. Please proceed with compiling the \
|
|
rest of the Prospero clients."
|
|
#endif
|
|
|
|
|
|
char *user_from_uid();
|
|
char *group_from_gid();
|
|
|
|
typedef struct _lsstruct {
|
|
char *name; /* file name */
|
|
int len; /* file name length */
|
|
struct stat lstat; /* lstat(2) for file */
|
|
} LS;
|
|
|
|
int (*sortfcn)(), (*printfcn)();
|
|
int lstat();
|
|
char *emalloc();
|
|
|
|
int termwidth = 80; /* default terminal width */
|
|
|
|
/* flags */
|
|
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_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 */
|
|
|
|
char *dummyargv[2] = {"", NULL};
|
|
|
|
#ifndef TIOCGWINSZ
|
|
#include <sys/termio.h>
|
|
#endif
|
|
|
|
main(argc, argv)
|
|
int argc;
|
|
char **argv;
|
|
{
|
|
extern int optind, stat();
|
|
struct winsize win;
|
|
int ch;
|
|
char *p, *getenv();
|
|
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 (isatty(1)) {
|
|
f_nonprint = 1;
|
|
if (ioctl(1, TIOCGWINSZ, &win) == -1 || !win.ws_col) {
|
|
if (p = getenv("COLUMNS"))
|
|
termwidth = atoi(p);
|
|
}
|
|
else
|
|
termwidth = win.ws_col;
|
|
f_column = 1;
|
|
} else
|
|
f_singlecol = 1;
|
|
|
|
/* root is -A automatically */
|
|
if (!getuid())
|
|
f_listdot = 1;
|
|
|
|
/* Print sizes in kilobytes by default */
|
|
f_kblocks = 1;
|
|
|
|
while ((ch = getopt(argc, argv, "1ACFLRacdfgiklqrstu")) != EOF) {
|
|
switch (ch) {
|
|
/*
|
|
* -1, -C and -l all override each other
|
|
* so shell aliasing works right
|
|
*/
|
|
case '1':
|
|
f_singlecol = 1;
|
|
f_column = f_longform = 0;
|
|
break;
|
|
case 'C':
|
|
f_column = 1;
|
|
f_longform = f_singlecol = 0;
|
|
break;
|
|
case 'l':
|
|
f_longform = 1;
|
|
f_column = f_singlecol = 0;
|
|
break;
|
|
/* -c and -u override each other */
|
|
case 'c':
|
|
f_statustime = 1;
|
|
f_accesstime = 0;
|
|
break;
|
|
case 'u':
|
|
f_accesstime = 1;
|
|
f_statustime = 0;
|
|
break;
|
|
case 'F':
|
|
f_type = 1;
|
|
break;
|
|
case 'L':
|
|
f_ignorelink = 1;
|
|
break;
|
|
case 'R':
|
|
f_recursive = 1;
|
|
break;
|
|
case 'a':
|
|
f_listalldot = 1;
|
|
/* FALLTHROUGH */
|
|
case 'A':
|
|
f_listdot = 1;
|
|
break;
|
|
case 'd':
|
|
f_listdir = 1;
|
|
break;
|
|
case 'f':
|
|
f_nosort = 1;
|
|
break;
|
|
case 'g':
|
|
f_group = 1;
|
|
break;
|
|
case 'i':
|
|
f_inode = 1;
|
|
break;
|
|
case 'k':
|
|
f_kblocks = 1;
|
|
break;
|
|
case 'q':
|
|
f_nonprint = 1;
|
|
break;
|
|
case 'r':
|
|
f_reversesort = 1;
|
|
break;
|
|
case 's':
|
|
f_size = 1;
|
|
break;
|
|
case 't':
|
|
f_timesort = 1;
|
|
break;
|
|
default:
|
|
case '?':
|
|
usage();
|
|
}
|
|
}
|
|
argc -= optind;
|
|
argv += optind;
|
|
|
|
/* -d turns off -R */
|
|
if (f_listdir)
|
|
f_recursive = 0;
|
|
|
|
/* if need to stat files */
|
|
f_needstat = f_longform || f_recursive || f_timesort ||
|
|
f_size || f_type;
|
|
|
|
/* select a sort function */
|
|
if (f_reversesort) {
|
|
if (!f_timesort)
|
|
sortfcn = revnamecmp;
|
|
else if (f_accesstime)
|
|
sortfcn = revacccmp;
|
|
else if (f_statustime)
|
|
sortfcn = revstatcmp;
|
|
else /* use modification time */
|
|
sortfcn = revmodcmp;
|
|
} else {
|
|
if (!f_timesort)
|
|
sortfcn = namecmp;
|
|
else if (f_accesstime)
|
|
sortfcn = acccmp;
|
|
else if (f_statustime)
|
|
sortfcn = statcmp;
|
|
else /* use modification time */
|
|
sortfcn = modcmp;
|
|
}
|
|
|
|
/* select a print function */
|
|
if (f_singlecol)
|
|
printfcn = printscol;
|
|
else if (f_longform)
|
|
printfcn = printlong;
|
|
else
|
|
printfcn = printcol;
|
|
|
|
if (argc) doargs(argc, argv);
|
|
else doargs(1,dummyargv);
|
|
exit(0);
|
|
}
|
|
|
|
static char path[MAXPATHLEN + 1];
|
|
static char *endofpath = path;
|
|
|
|
doargs(argc, argv)
|
|
int argc;
|
|
char **argv;
|
|
{
|
|
register LS *dstatp, *rstatp;
|
|
register int cnt, dircnt, maxlen, regcnt;
|
|
LS *dstats, *rstats;
|
|
struct stat sb;
|
|
int (*statfcn)(), stat(), lstat();
|
|
char top[MAXPATHLEN + 1];
|
|
u_long blocks;
|
|
long r_st_btotal;
|
|
long r_st_maxlen;
|
|
|
|
/*
|
|
* walk through the operands, building separate arrays of LS
|
|
* structures for directory and non-directory files.
|
|
*/
|
|
dstats = rstats = NULL;
|
|
statfcn = (f_longform || f_listdir) && !f_ignorelink ? lstat : stat;
|
|
for (dircnt = regcnt = 0; *argv; ++argv) {
|
|
if (statfcn(*argv, &sb)) {
|
|
if (statfcn != stat || lstat(*argv, &sb)) {
|
|
(void)fflush(stdout);
|
|
(void)fprintf(stderr, "ls: %s: %s\n", *argv,
|
|
unixerrstr());
|
|
if (errno == ENOENT)
|
|
continue;
|
|
exit(1);
|
|
}
|
|
}
|
|
if (S_ISDIR(sb.st_mode) && !f_listdir) {
|
|
if (!dstats)
|
|
dstatp = dstats = (LS *)emalloc((u_int)argc *
|
|
(sizeof(LS)));
|
|
dstatp->name = *argv;
|
|
dstatp->lstat = sb;
|
|
++dstatp;
|
|
++dircnt;
|
|
}
|
|
else {
|
|
if (!rstats) {
|
|
rstatp = rstats = (LS *)emalloc((u_int)argc *
|
|
(sizeof(LS)));
|
|
blocks = 0;
|
|
maxlen = -1;
|
|
}
|
|
rstatp->name = *argv;
|
|
rstatp->lstat = sb;
|
|
|
|
/* save name length for -C format */
|
|
rstatp->len = strlen(*argv);
|
|
|
|
if (f_nonprint)
|
|
prcopy(*argv, *argv, rstatp->len);
|
|
|
|
/* calculate number of blocks if -l/-s formats */
|
|
if (f_longform || f_size)
|
|
blocks += sb.st_blocks;
|
|
|
|
/* save max length if -C format */
|
|
if (f_column && maxlen < rstatp->len)
|
|
maxlen = rstatp->len;
|
|
|
|
++rstatp;
|
|
++regcnt;
|
|
}
|
|
}
|
|
/* display regular files */
|
|
if (regcnt) {
|
|
displaydir("", rstats, regcnt, blocks, maxlen);
|
|
f_newline = f_dirname = 1;
|
|
}
|
|
/* display directories */
|
|
if (dircnt) {
|
|
register char *p;
|
|
|
|
f_total = 1;
|
|
if (dircnt > 1) {
|
|
(void)getwd(top);
|
|
qsort((char *)dstats, dircnt, sizeof(LS), sortfcn);
|
|
f_dirname = 1;
|
|
}
|
|
for (cnt = 0; cnt < dircnt; ++dstats) {
|
|
for (endofpath = path, p = dstats->name;
|
|
*endofpath = *p++; ++endofpath);
|
|
subdir("",dstats);
|
|
f_newline = 1;
|
|
if (++cnt < dircnt && chdir(top)) {
|
|
(void)fprintf(stderr, "ls: %s: %s\n",
|
|
top, unixerrstr());
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
displaydir(subdirname, stats, num, blocks, maxlen)
|
|
char *subdirname;
|
|
LS *stats;
|
|
register int num;
|
|
long blocks;
|
|
long maxlen;
|
|
{
|
|
register char *p, *savedpath;
|
|
LS *lp;
|
|
|
|
if (num > 1 && !f_nosort) {
|
|
u_long save1, save2;
|
|
qsort((char *)stats, num, sizeof(LS), sortfcn);
|
|
}
|
|
|
|
printfcn(subdirname, stats, num, blocks, maxlen);
|
|
|
|
if (f_recursive) {
|
|
savedpath = endofpath;
|
|
for (lp = stats; num--; ++lp) {
|
|
if (!S_ISDIR(lp->lstat.st_mode))
|
|
continue;
|
|
p = lp->name;
|
|
if (p[0] == '.' && (!p[1] || p[1] == '.' && !p[2]))
|
|
continue;
|
|
if (endofpath != path && endofpath[-1] != '/')
|
|
*endofpath++ = '/';
|
|
for (; *endofpath = *p++; ++endofpath);
|
|
f_newline = f_dirname = f_total = 1;
|
|
subdir(subdirname,lp);
|
|
*(endofpath = savedpath) = '\0';
|
|
}
|
|
}
|
|
}
|
|
|
|
subdir(wdir,lp)
|
|
char *wdir;
|
|
LS *lp;
|
|
{
|
|
char sbdirname[MAXPATHLEN];
|
|
LS *stats;
|
|
int num;
|
|
char *names;
|
|
long blocks;
|
|
int maxlen;
|
|
|
|
if(*wdir) sprintf(sbdirname,"%s/%s",wdir,lp->name);
|
|
else strcpy(sbdirname,lp->name);
|
|
|
|
if (f_newline)
|
|
(void)putchar('\n');
|
|
if (f_dirname)
|
|
(void)printf("%s:\n", path);
|
|
|
|
if (num = tabdir(sbdirname, lp, &stats, &names, &blocks, &maxlen)) {
|
|
displaydir(sbdirname, stats, num, blocks, maxlen);
|
|
(void)free((char *)stats);
|
|
(void)free((char *)names);
|
|
}
|
|
}
|
|
|
|
tabdir(dirname, lp, s_stats, s_names, blocksp, maxlenp)
|
|
char *dirname;
|
|
LS *lp, **s_stats;
|
|
char **s_names;
|
|
u_long *blocksp;
|
|
int *maxlenp;
|
|
{
|
|
register DIR *dirp;
|
|
register int cnt, maxentry, maxlen;
|
|
register char *p, *names;
|
|
#define NAMES_BLSIZ 2048
|
|
int names_len = 4*NAMES_BLSIZ;
|
|
int names_off;
|
|
struct dirent *dp;
|
|
u_long blocks;
|
|
LS *stats;
|
|
char newfname[MAXPATHLEN];
|
|
|
|
|
|
if (!(dirp = opendir(dirname))) {
|
|
(void)fprintf(stderr, "ls: %s: %s\n", lp->name,
|
|
unixerrstr());
|
|
return(0);
|
|
}
|
|
blocks = maxentry = maxlen = 0;
|
|
stats = NULL;
|
|
assert(P_IS_THIS_THREAD_MASTER()); /* readdir is MT-Unsafe */
|
|
for (cnt = 0; dp = readdir(dirp);) {
|
|
/* this does -A and -a */
|
|
p = dp->d_name;
|
|
if (p[0] == '.') {
|
|
if (!f_listdot)
|
|
continue;
|
|
if (!f_listalldot && (!p[1] || p[1] == '.' && !p[2]))
|
|
continue;
|
|
}
|
|
if (cnt == maxentry) {
|
|
if (!maxentry)
|
|
*s_names = names = emalloc(names_len);
|
|
|
|
if((names_len - (names_off = names - *s_names))
|
|
< (2*NAMES_BLSIZ)) {
|
|
names_len += 2*NAMES_BLSIZ;
|
|
*s_names = (char *) realloc(*s_names,names_len);
|
|
names = *s_names + names_off;
|
|
}
|
|
#define DEFNUM 256
|
|
maxentry += DEFNUM;
|
|
|
|
if (stats==NULL)
|
|
*s_stats = stats =
|
|
(LS *) emalloc((u_int)maxentry * sizeof (LS));
|
|
else if (!(*s_stats = stats =
|
|
(LS *) realloc((char *)stats,
|
|
(u_int)maxentry * sizeof(LS))))
|
|
nomem();
|
|
}
|
|
|
|
if(*dirname) sprintf(newfname,"%s/%s",dirname,dp->d_name);
|
|
else strcpy(newfname,dp->d_name);
|
|
|
|
if (f_needstat && lstat(newfname, &stats[cnt].lstat)) {
|
|
/*
|
|
* don't exit -- this could be an NFS mount that has
|
|
* gone away. Flush stdout so the messages line up.
|
|
*/
|
|
(void)fflush(stdout);
|
|
(void)fprintf(stderr, "ls: %s: %s\n",
|
|
dp->d_name, unixerrstr());
|
|
continue;
|
|
}
|
|
stats[cnt].name = names;
|
|
|
|
if (f_nonprint)
|
|
prcopy(dp->d_name, names, (int)dp->d_namlen);
|
|
else
|
|
bcopy(dp->d_name, names, (int)dp->d_namlen);
|
|
names += dp->d_namlen;
|
|
*names++ = '\0';
|
|
|
|
/*
|
|
* get the inode from the directory, so the -f flag
|
|
* works right.
|
|
*/
|
|
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)
|
|
maxlen = dp->d_namlen;
|
|
++cnt;
|
|
}
|
|
(void)closedir(dirp);
|
|
|
|
if (cnt) {
|
|
*blocksp = blocks;
|
|
*maxlenp = maxlen;
|
|
} else if (stats) {
|
|
(void)free((char *)stats);
|
|
(void)free((char *)names);
|
|
}
|
|
return(cnt);
|
|
}
|
|
|
|
printscol(dirname, stats, num, blocks, maxlen)
|
|
char *dirname;
|
|
register LS *stats;
|
|
register int num;
|
|
long blocks;
|
|
long maxlen;
|
|
{
|
|
for (; num--; ++stats) {
|
|
(void)printaname(stats);
|
|
(void)putchar('\n');
|
|
}
|
|
}
|
|
|
|
printlong(dirname, stats, num , blocks, maxlen)
|
|
char *dirname;
|
|
LS *stats;
|
|
register int num;
|
|
u_long blocks;
|
|
int maxlen ;
|
|
{
|
|
char modep[15];
|
|
|
|
if (f_total)
|
|
(void)printf("total %lu\n", f_kblocks ?
|
|
howmany(blocks, 2) :
|
|
blocks);
|
|
for (; num--; ++stats) {
|
|
if (f_inode)
|
|
(void)printf("%6lu ", stats->lstat.st_ino);
|
|
if (f_size)
|
|
(void)printf("%4ld ", f_kblocks ?
|
|
howmany(stats->lstat.st_blocks, 2) :
|
|
stats->lstat.st_blocks);
|
|
(void)strmode(stats->lstat.st_mode, modep);
|
|
(void)printf("%s %3u %-*s ", modep, stats->lstat.st_nlink,
|
|
UT_NAMESIZE, user_from_uid((uid_t) stats->lstat.st_uid));
|
|
if (f_group)
|
|
(void)printf("%-*s ", UT_NAMESIZE,
|
|
group_from_gid((gid_t) stats->lstat.st_gid));
|
|
if (S_ISCHR(stats->lstat.st_mode) ||
|
|
S_ISBLK(stats->lstat.st_mode))
|
|
(void)printf("%3d, %3d ", major(stats->lstat.st_rdev),
|
|
minor(stats->lstat.st_rdev));
|
|
else
|
|
(void)printf("%8ld ", stats->lstat.st_size);
|
|
if (f_accesstime)
|
|
printtime(stats->lstat.st_atime);
|
|
else if (f_statustime)
|
|
printtime(stats->lstat.st_ctime);
|
|
else
|
|
printtime(stats->lstat.st_mtime);
|
|
(void)printf("%s", stats->name);
|
|
if (f_type)
|
|
(void)printtype(stats->lstat.st_mode);
|
|
if (S_ISLNK(stats->lstat.st_mode))
|
|
printlink(dirname,stats->name);
|
|
(void)putchar('\n');
|
|
}
|
|
}
|
|
|
|
printcol(dirname, stats, num, blocks, maxlen)
|
|
char *dirname;
|
|
LS *stats;
|
|
int num;
|
|
u_long blocks;
|
|
int maxlen;
|
|
{
|
|
extern int termwidth;
|
|
register int base, chcnt, cnt, col, colwidth;
|
|
int endcol, numcols, numrows, row;
|
|
|
|
colwidth = maxlen + 2;
|
|
if (f_inode)
|
|
colwidth += 6;
|
|
if (f_size)
|
|
colwidth += 5;
|
|
if (f_type)
|
|
colwidth += 1;
|
|
|
|
if (termwidth < 2 * colwidth) {
|
|
printscol(dirname, stats, num, blocks, maxlen);
|
|
return;
|
|
}
|
|
|
|
numcols = termwidth / colwidth;
|
|
numrows = num / numcols;
|
|
if (num % numcols)
|
|
++numrows;
|
|
|
|
if (f_size && f_total)
|
|
(void)printf("total %lu\n", f_kblocks ?
|
|
howmany(blocks, 2) : blocks);
|
|
for (row = 0; row < numrows; ++row) {
|
|
endcol = colwidth;
|
|
for (base = row, chcnt = col = 0; col < numcols; ++col) {
|
|
chcnt += printaname(stats + base);
|
|
if ((base += numrows) >= num)
|
|
break;
|
|
while ((cnt = chcnt + 1) <= endcol) {
|
|
(void)putchar(' ');
|
|
chcnt = cnt;
|
|
}
|
|
endcol += colwidth;
|
|
}
|
|
putchar('\n');
|
|
}
|
|
}
|
|
|
|
/*
|
|
* print [inode] [size] name
|
|
* return # of characters printed, no trailing characters
|
|
*/
|
|
printaname(lp)
|
|
LS *lp;
|
|
{
|
|
int chcnt;
|
|
|
|
chcnt = 0;
|
|
if (f_inode) {
|
|
printf("%5lu ", lp->lstat.st_ino);
|
|
chcnt += 6;
|
|
}
|
|
if (f_size) {
|
|
printf("%4ld ", f_kblocks ?
|
|
howmany(lp->lstat.st_blocks, 2) : lp->lstat.st_blocks);
|
|
chcnt += 5;
|
|
}
|
|
printf("%s", lp->name);
|
|
chcnt += strlen(lp->name);
|
|
|
|
if (f_type) chcnt += printtype(lp->lstat.st_mode);
|
|
|
|
return(chcnt);
|
|
}
|
|
|
|
printtime(ftime)
|
|
time_t ftime;
|
|
{
|
|
int i;
|
|
char *longstring, *ctime();
|
|
time_t time();
|
|
|
|
if(ftime == 0) fputs("- ",stdout);
|
|
else {
|
|
|
|
DISABLE_PFS(longstring = ctime(&ftime));
|
|
for (i = 4; i < 11; ++i)
|
|
(void)putchar(longstring[i]);
|
|
|
|
#define SIXMONTHS ((DAYSPERNYEAR / 2) * SECSPERDAY)
|
|
if (ftime + SIXMONTHS > time((time_t *)NULL))
|
|
for (i = 11; i < 16; ++i)
|
|
(void)putchar(longstring[i]);
|
|
else {
|
|
(void)putchar(' ');
|
|
for (i = 20; i < 24; ++i)
|
|
(void)putchar(longstring[i]);
|
|
}
|
|
(void)putchar(' ');
|
|
}
|
|
}
|
|
|
|
printtype(mode)
|
|
mode_t mode;
|
|
{
|
|
switch(mode & S_IFMT) {
|
|
case S_IFDIR:
|
|
(void)putchar('/');
|
|
return(1);
|
|
case S_IFLNK:
|
|
(void)putchar('@');
|
|
return(1);
|
|
case S_IFSOCK:
|
|
(void)putchar('=');
|
|
return(1);
|
|
}
|
|
if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
|
|
(void)putchar('*');
|
|
return(1);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
printlink(dirname, name)
|
|
char *dirname;
|
|
char *name;
|
|
{
|
|
char linkname[MAXPATHLEN];
|
|
int lnklen;
|
|
char path[MAXPATHLEN + 1];
|
|
|
|
if(*dirname) sprintf(linkname,"%s/%s",dirname, name);
|
|
else strcpy(linkname,name);
|
|
|
|
if ((lnklen = readlink(linkname, path, MAXPATHLEN)) == -1) {
|
|
fflush(stdout);
|
|
(void)fprintf(stderr, "\nls: %s: %s", name, unixerrstr());
|
|
fflush(stderr);
|
|
return;
|
|
}
|
|
path[lnklen] = '\0';
|
|
(void)printf(" -> %s", path);
|
|
}
|
|
|
|
|
|
prcopy(src, dest, len)
|
|
register char *src, *dest;
|
|
register int len;
|
|
{
|
|
register int ch;
|
|
|
|
while(len--) {
|
|
ch = *src++;
|
|
*dest++ = isprint(ch) ? ch : '?';
|
|
}
|
|
}
|
|
|
|
char
|
|
*emalloc(size)
|
|
u_int size;
|
|
{
|
|
char *retval, *malloc();
|
|
|
|
if (!(retval = malloc(size)))
|
|
nomem();
|
|
return(retval);
|
|
}
|
|
|
|
nomem()
|
|
{
|
|
(void)fprintf(stderr, "ls: out of memory.\n");
|
|
exit(1);
|
|
}
|
|
|
|
int
|
|
usage()
|
|
{
|
|
(void)fprintf(stderr, "usage: ls [-1ACFLRacdfgiklqrstu] [file ...]\n");
|
|
exit(1);
|
|
}
|
|
|
|
|
|
|
|
namecmp(a, b)
|
|
LS *a, *b;
|
|
{
|
|
return(strcmp(a->name, b->name));
|
|
}
|
|
|
|
revnamecmp(a, b)
|
|
LS *a, *b;
|
|
{
|
|
return(strcmp(b->name, a->name));
|
|
}
|
|
|
|
modcmp(a, b)
|
|
LS *a, *b;
|
|
{
|
|
return(a->lstat.st_mtime < b->lstat.st_mtime);
|
|
}
|
|
|
|
revmodcmp(a, b)
|
|
LS *a, *b;
|
|
{
|
|
return(b->lstat.st_mtime < a->lstat.st_mtime);
|
|
}
|
|
|
|
acccmp(a, b)
|
|
LS *a, *b;
|
|
{
|
|
return(a->lstat.st_atime < b->lstat.st_atime);
|
|
}
|
|
|
|
revacccmp(a, b)
|
|
LS *a, *b;
|
|
{
|
|
return(b->lstat.st_atime < a->lstat.st_atime);
|
|
}
|
|
|
|
int
|
|
statcmp(a, b)
|
|
LS *a, *b;
|
|
{
|
|
return(a->lstat.st_ctime < b->lstat.st_ctime);
|
|
}
|
|
|
|
int
|
|
revstatcmp(a, b)
|
|
LS *a, *b;
|
|
{
|
|
return(b->lstat.st_ctime < a->lstat.st_ctime);
|
|
}
|
|
|
|
void
|
|
strmode(short mode,char *modestr)
|
|
{
|
|
strcpy(modestr,"----------");
|
|
|
|
if(mode & S_IFDIR) modestr[0] = 'd';
|
|
if((mode & S_IFLNK) == S_IFLNK) modestr[0] = 'l';
|
|
if(mode & S_IREAD) modestr[1] = 'r';
|
|
if(mode & S_IWRITE) modestr[2] = 'w';
|
|
if(mode & S_IEXEC) modestr[3] = 'x';
|
|
if(mode & S_ISUID) modestr[3] = 's';
|
|
if(mode & (S_IREAD>>3)) modestr[4] = 'r';
|
|
if(mode & (S_IWRITE>>3)) modestr[5] = 'w';
|
|
if(mode & (S_IEXEC>>3)) modestr[6] = 'x';
|
|
if(mode & S_ISGID) modestr[6] = 's';
|
|
if(mode & (S_IREAD>>6)) modestr[7] = 'r';
|
|
if(mode & (S_IWRITE>>6)) modestr[8] = 'w';
|
|
if(mode & (S_IEXEC>>6)) modestr[9] = 'x';
|
|
}
|
|
|
|
|
|
char *
|
|
user_from_uid(uid)
|
|
uid_t uid;
|
|
{
|
|
static char uidstring[10];
|
|
struct passwd *pwent;
|
|
|
|
if(uid == (uid_t) -1) return("-");
|
|
|
|
assert(P_IS_THIS_THREAD_MASTER()); /*getpwuid unsafe */
|
|
DISABLE_PFS(pwent = getpwuid(uid));
|
|
|
|
if (pwent == NULL) {
|
|
sprintf(uidstring,"%d",uid);
|
|
return(uidstring);
|
|
}
|
|
else return(pwent->pw_name);
|
|
}
|
|
|
|
|
|
char *
|
|
group_from_gid(gid)
|
|
gid_t gid;
|
|
{
|
|
static char gidstring[10];
|
|
struct group *grent;
|
|
|
|
if(gid == (gid_t) -1) return("-");
|
|
|
|
assert(P_IS_THIS_THREAD_MASTER()); /*SOLARIS getgrgid MT-Unsafe */
|
|
DISABLE_PFS(grent = getgrgid(gid));
|
|
|
|
if (grent == NULL) {
|
|
sprintf(gidstring,"%d",gid);
|
|
return(gidstring);
|
|
}
|
|
else return(grent->gr_name);
|
|
}
|
|
|