* Copyright (c) 1980 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
"@(#) Copyright (c) 1980 Regents of the University of California.\n\
static char sccsid
[] = "@(#)ls.c 5.3 (Berkeley) %G%";
* 4.2bsd version for symbolic links, variable length
* directory entries, block size in the inode, etc.
#define kbytes(size) (((size) + 1023) / 1024)
char ftype
; /* file type, e.g. 'd', 'c', 'f' */
ino_t fnum
; /* inode number of file */
short fflags
; /* mode&~S_IFMT, perhaps ISARG */
short fnl
; /* number of links */
short fuid
; /* owner id */
short fgid
; /* group id */
long fsize
; /* file size */
long fblks
; /* number of blocks used */
time_t fmtime
; /* time (modify or access or create) */
char *fname
; /* file name */
char *flinkto
; /* symbolic link value */
#define ISARG 0x8000 /* extra ``mode'' */
int aflg
, dflg
, gflg
, lflg
, sflg
, tflg
, uflg
, iflg
, fflg
, cflg
, rflg
= 1;
int qflg
, Aflg
, Cflg
, Fflg
, Lflg
, Rflg
, Sflg
;
time_t now
, sixmonthsago
;
char *getname(), *getgroup();
char *malloc(), *calloc(), *realloc();
char *sprintf(), *strcpy(), *strcat();
struct afile
*fp0
, *fplast
;
register struct afile
*fp
;
(void) time(&now
); sixmonthsago
= now
- 6L*30L*24L*60L*60L; now
+= 60;
if (ioctl(1, TIOCGWINSZ
, &win
) != -1)
twidth
= (win
.ws_col
== 0 ? 80 : win
.ws_col
);
if ((sgbuf
.sg_flags
& XTABS
) == 0)
while (argc
> 0 && **argv
== '-') {
while (**argv
) switch (*(*argv
)++) {
Sflg
++; /* fall into... */
aflg
++; Sflg
= 0; tflg
= 0; /* -f: only turn off sort flags */
fp
= (struct afile
*)calloc(argc
, sizeof (struct afile
));
fprintf(stderr
, "ls: out of memory\n");
for (i
= 0; i
< argc
; i
++) {
if (gstat(fp
, *argv
, 1, (int *)0)) {
qsort(fp0
, fplast
- fp0
, sizeof (struct afile
), fcmp
);
for (fp
= fp0
; fp
< fplast
&& fp
->ftype
!= 'd'; fp
++)
formatd(fp
->fname
, argc
> 1);
t
= subdirs
; subdirs
= t
->sd_next
;
register struct afile
*fp
;
register struct subdirs
*dp
;
struct afile
*dfp0
, *dfplast
;
nkb
= getdir(name
, &dfp0
, &dfplast
);
qsort(dfp0
, dfplast
- dfp0
, sizeof (struct afile
), fcmp
);
printf("total %ld\n", nkb
);
for (fp
= dfplast
- 1; fp
>= dfp0
; fp
--) {
!strcmp(fp
->fname
, ".") ||
!strcmp(fp
->fname
, ".."))
dp
= (struct subdirs
*)malloc(sizeof (struct subdirs
));
dp
->sd_name
= savestr(cat(name
, fp
->fname
));
dp
->sd_next
= subdirs
; subdirs
= dp
;
for (fp
= dfp0
; fp
< dfplast
; fp
++) {
if ((fp
->fflags
&ISARG
) == 0 && fp
->fname
)
getdir(dir
, pfp0
, pfplast
)
struct afile
**pfp0
, **pfplast
;
register struct afile
*fp
;
register struct direct
*dp
;
printf("%s unreadable\n", dir
); /* not stderr! */
fp
= *pfp0
= (struct afile
*)calloc(nent
, sizeof (struct afile
));
while (dp
= readdir(dirp
)) {
if (aflg
== 0 && dp
->d_name
[0]=='.' &&
(Aflg
== 0 || dp
->d_name
[1]==0 ||
dp
->d_name
[1]=='.' && dp
->d_name
[2]==0))
if (gstat(fp
, cat(dir
, dp
->d_name
), Fflg
+Rflg
, &nb
) == 0)
fp
->fname
= savestr(dp
->d_name
);
*pfp0
= (struct afile
*)realloc((char *)*pfp0
,
2 * nent
* sizeof (struct afile
));
fprintf(stderr
, "ls: out of memory\n");
return (kbytes(dbtob(nb
)));
gstat(fp
, file
, statarg
, pnb
)
register struct afile
*fp
;
int (*statf
)() = Lflg
? stat
: lstat
;
char buf
[BUFSIZ
]; int cc
;
static struct afile azerofile
;
if (statarg
|| sflg
|| lflg
|| tflg
) {
if ((*statf
)(file
, &stb
) < 0) {
if (statf
== lstat
|| lstat(file
, &stb
) < 0) {
fprintf(stderr
, "%s not found\n", file
);
fp
->fblks
= stb
.st_blocks
;
switch (stb
.st_mode
& S_IFMT
) {
fp
->ftype
= 'b'; fp
->fsize
= stb
.st_rdev
; break;
fp
->ftype
= 'c'; fp
->fsize
= stb
.st_rdev
; break;
fp
->ftype
= 's'; fp
->fsize
= 0; break;
cc
= readlink(file
, buf
, BUFSIZ
);
fp
->flinkto
= savestr(buf
);
if (stat(file
, &stb1
) < 0)
if ((stb1
.st_mode
& S_IFMT
) == S_IFDIR
) {
fp
->fblks
= stb
.st_blocks
;
fp
->fflags
= stb
.st_mode
& ~S_IFMT
;
fp
->fmtime
= stb
.st_atime
;
fp
->fmtime
= stb
.st_ctime
;
fp
->fmtime
= stb
.st_mtime
;
struct afile
*fp0
, *fplast
;
register struct afile
*fp
;
int width
= 0, w
, nentry
= fplast
- fp0
;
int i
, j
, columns
, lines
;
for (fp
= fp0
; fp
< fplast
; fp
++) {
int len
= strlen(fmtentry(fp
));
width
= (width
+ 8) &~ 7;
columns
= twidth
/ width
;
lines
= (nentry
+ columns
- 1) / columns
;
for (i
= 0; i
< lines
; i
++) {
for (j
= 0; j
< columns
; j
++) {
fp
= fp0
+ j
* lines
+ i
;
if (fp
+ lines
>= fplast
) {
register struct afile
*f1
, *f2
;
if (dflg
== 0 && fflg
== 0) {
if ((f1
->fflags
&ISARG
) && f1
->ftype
== 'd') {
if ((f2
->fflags
&ISARG
) == 0 || f2
->ftype
!= 'd')
if ((f2
->fflags
&ISARG
) && f2
->ftype
== 'd')
if (f2
->fmtime
== f1
->fmtime
)
if (f2
->fmtime
> f1
->fmtime
)
if (f2
->fsize
== f1
->fsize
)
if (f2
->fsize
> f1
->fsize
)
return (rflg
* strcmp(f1
->fname
, f2
->fname
));
static char dfile
[BUFSIZ
];
if (strlen(dir
)+1+strlen(file
)+1 > BUFSIZ
) {
fprintf(stderr
, "ls: filename too long\n");
if (!strcmp(dir
, "") || !strcmp(dir
, ".")) {
(void) strcpy(dfile
, file
);
(void) strcpy(dfile
, dir
);
if (dir
[strlen(dir
) - 1] != '/' && *file
!= '/')
(void) strcat(dfile
, "/");
(void) strcat(dfile
, file
);
char *cp
= malloc(strlen(str
) + 1);
fprintf(stderr
, "ls: out of memory\n");
char *fmtinum(), *fmtsize(), *fmtlstuff(), *fmtmode();
register struct afile
*fp
;
static char fmtres
[BUFSIZ
];
(void) sprintf(fmtres
, "%s%s%s",
lflg
? fmtlstuff(fp
) : "");
dp
= &fmtres
[strlen(fmtres
)];
for (cp
= fp
->fname
; *cp
; cp
++)
if (qflg
&& (*cp
< ' ' || *cp
>= 0177))
else if (fp
->ftype
== 'l')
else if (fp
->ftype
== 's')
else if (fp
->fflags
& 0111)
if (lflg
&& fp
->flinkto
) {
(void) strcpy(dp
, " -> "); dp
+= 4;
for (cp
= fp
->flinkto
; *cp
; cp
++)
if (qflg
&& (*cp
< ' ' || *cp
>= 0177))
register struct afile
*p
;
(void) sprintf(inumbuf
, "%5d ", p
->fnum
);
register struct afile
*p
;
(void) sprintf(sizebuf
, "%4ld ", kbytes(dbtob(p
->fblks
)));
register struct afile
*p
;
static char lstuffbuf
[256];
char gname
[32], uname
[32], fsize
[32], ftime
[32];
register char *lp
= lstuffbuf
;
/* type mode uname gname fsize ftime */
{ char *cp
= getname(p
->fuid
);
(void) sprintf(uname
, "%-9.9s", cp
);
(void) sprintf(uname
, "%-9d", p
->fuid
);
char *cp
= getgroup(p
->fgid
);
(void) sprintf(gname
, "%-9.9s", cp
);
(void) sprintf(gname
, "%-9d", p
->fgid
);
if (p
->ftype
== 'b' || p
->ftype
== 'c')
(void) sprintf(fsize
, "%3d,%4d",
major(p
->fsize
), minor(p
->fsize
));
else if (p
->ftype
== 's')
(void) sprintf(fsize
, "%8ld", 0);
(void) sprintf(fsize
, "%8ld", p
->fsize
);
{ char *cp
= ctime(&p
->fmtime
);
if ((p
->fmtime
< sixmonthsago
) || (p
->fmtime
> now
))
(void) sprintf(ftime
, " %-7.7s %-4.4s ", cp
+4, cp
+20);
(void) sprintf(ftime
, " %-12.12s ", cp
+4);
lp
= fmtmode(lp
, p
->fflags
);
(void) sprintf(lp
, "%3d %s%s%s%s",
p
->fnl
, uname
, gflg
? gname
: "", fsize
, ftime
);
int m1
[] = { 1, S_IREAD
>>0, 'r', '-' };
int m2
[] = { 1, S_IWRITE
>>0, 'w', '-' };
int m3
[] = { 2, S_ISUID
, 's', S_IEXEC
>>0, 'x', '-' };
int m4
[] = { 1, S_IREAD
>>3, 'r', '-' };
int m5
[] = { 1, S_IWRITE
>>3, 'w', '-' };
int m6
[] = { 2, S_ISGID
, 's', S_IEXEC
>>3, 'x', '-' };
int m7
[] = { 1, S_IREAD
>>6, 'r', '-' };
int m8
[] = { 1, S_IWRITE
>>6, 'w', '-' };
int m9
[] = { 2, S_ISVTX
, 't', S_IEXEC
>>6, 'x', '-' };
int *m
[] = { m1
, m2
, m3
, m4
, m5
, m6
, m7
, m8
, m9
};
for (mp
= &m
[0]; mp
< &m
[sizeof(m
)/sizeof(m
[0])]; ) {
register int *pairp
= *mp
++;
register int n
= *pairp
++;
while (--n
>= 0 && (flags
&*pairp
++) == 0)
/* rest should be done with nameserver or database */
#define NMAX (sizeof (utmp.ut_name))
#define SCPYN(a, b) strncpy(a, b, NMAX)
#define NUID 64 /* power of 2 */
char outrangename
[NMAX
+1];
char groups
[NGID
][NMAX
+1];
char outrangegroup
[NMAX
+1];
register struct passwd
*pw
;
struct passwd
*getpwent();
if (uid
>= 0 && nc
[cp
].uid
== uid
&& nc
[cp
].name
[0])
SCPYN(nc
[cp
].name
, pw
->pw_name
);
register struct group
*gr
;
struct group
*getgrent();
if (gid
>= 0 && gid
< NGID
&& groups
[gid
][0])
return (&groups
[gid
][0]);
if (gid
>= 0 && gid
== outrangegid
)
while (gr
= getgrent()) {
outrangegid
= gr
->gr_gid
;
SCPYN(outrangegroup
, gr
->gr_name
);
while (gr
= getgrent()) {
if (gr
->gr_gid
< 0 || gr
->gr_gid
>= NGID
) {
outrangegid
= gr
->gr_gid
;
SCPYN(outrangegroup
, gr
->gr_name
);
if (groups
[gr
->gr_gid
][0])
SCPYN(groups
[gr
->gr_gid
], gr
->gr_name
);
return (&groups
[gid
][0]);