#define UCB /* Controls output format for -F */
/* #define UCB_PWHASH /* If have hashed password file */
* ls - list file or directory
* Modified by Bill Joy UCB May/August 1977
* Modified by Dave Presotto BTL Feb/80
* Modified by Bill Joy and Mark Horton Summer 1980
* this version of ls is designed for graphic terminals and to
* list directories with lots of files in them compactly.
* It supports three variants for listings:
* 3) Old one per line format.
* Columnar output is the default.
* If, however, the standard output is not a teletype, the default
* With columnar output, the items are sorted down the columns.
* We use columns only for a directory we are interpreting.
* Thus, in particular, we do not use columns for
* This version of ls also prints non-printing characters as '?' if
* the standard output is a teletype.
* Flags relating to these and other new features are:
* -m force stream output.
* -1 force one entry per line, e.g. to a teletype
* -q force non-printings to be '?'s, e.g. to a file
* -C force columnar output, e.g. into a file
* -n like -l, but user/group id's in decimal rather than
* looking in /etc/passwd to save time
* -F turns on the "flagging" of executables and directories
* -R causes ls to recurse through the branches of the subtree
#define NMAX (sizeof utmp.ut_name)
char *dc_name
; /* the path name */
struct dchain
*dc_next
; /* the next directory on the chain */
struct dchain
*dfirst
; /* the start of the directory chain */
struct dchain
*cdfirst
; /* the start of the current directory chain */
struct dchain
*dtemp
; /* temporary used when linking */
char *curdir
; /* the current directory */
int aflg
, bflg
, dflg
, lflg
, sflg
, tflg
, uflg
, iflg
, fflg
, gflg
, cflg
;
int Aflg
, nflg
, qflg
, Fflg
, Rflg
, across
, Cflg
;
int xtraent
; /* for those switches which print out a total */
struct lbuf
*flist
[NFILES
];
struct lbuf
**lastp
= flist
;
struct lbuf
**firstp
= flist
;
register struct lbuf
*ep
;
register struct lbuf
**slastp
;
lb
.lmtime
= time((long *) 0);
year
= lb
.lmtime
- 6L*30L*24L*60L*60L; /* 6 months ago */
qflg
= gtty(1, &sgbuf
) == 0;
/* guarantee at least on column width */
* If the standard output is not a teletype,
* then we default to one-per-line format
* otherwise decide between stream and
* columnar based on our name.
if ((sgbuf
.sg_flags
& XTABS
) == 0)
for (cp
= argv
[0]; cp
[0] && cp
[1]; cp
++)
* Certain kinds of links (l, ll, lr, lf, lx) cause some
* various options to be turned on.
while (--argc
> 0 && *argv
[1] == '-') {
while (*++*argv
) switch (**argv
) {
* C - force columnar output
* m - force stream output
* q - force ?'s in output
* b - force octal value in output
* 1 - force 1/line in output
* n - don't look in password file
fprintf (stderr
, "usage: ls [-1ACFRabcdfgilmnqrstux] [files]\n");
for (i
=0; i
< argc
; i
++) {
if ((ep
= gstat(*argv
, 1))==NULL
)
filewidth
= MAXFILEWIDTH
;
colwidth
= fixedwidth
+ filewidth
;
qsort(firstp
, lastp
- firstp
, sizeof *lastp
, compar
);
/* For each argument user typed */
for (epp
=firstp
; epp
<slastp
; epp
++) {
if (ep
->ltype
=='d' && dflg
==0 || fflg
)
pdirectory(ep
->ln
.namep
, (argc
>1), slastp
);
/* -R: print subdirectories found */
while (dfirst
|| cdfirst
) {
/* Place direct subdirs on front in right order */
/* reverse cdfirst onto front of dfirst */
cdfirst
= cdfirst
-> dc_next
;
dtemp
-> dc_next
= dfirst
;
/* take off first dir on dfirst & print it */
dfirst
= dfirst
->dc_next
;
pdirectory (dtemp
->dc_name
, 1, firstp
);
* pdirectory: print the directory name, labelling it if title is
* nonzero, using lp as the place to start reading in the dir.
pdirectory (name
, title
, lp
)
register struct dchain
*dp
;
register struct lbuf
*ap
;
filewidth
= MAXFILEWIDTH
;
colwidth
= fixedwidth
+ filewidth
;
/* Taken out because it appears this is done below in pem. */
qsort(lp
,lastp
- lp
,sizeof *lastp
,compar
);
if (Rflg
) for (app
=lastp
-1; app
>=lp
; app
--) {
if (ap
->ltype
== 'd' && strcmp(ap
->ln
.lname
, ".") &&
strcmp(ap
->ln
.lname
, "..")) {
dp
= (struct dchain
*) calloc(1, sizeof(struct dchain
));
pname
= makename (curdir
, ap
->ln
.lname
);
dp
->dc_name
= (char *) calloc(1, strlen(pname
)+1);
strcpy(dp
->dc_name
, pname
);
printf("total %D", tblocks
);
* pem: print 'em. Print a list of files (e.g. a directory) bounded
register struct lbuf
**slp
, **lp
;
int ncols
, nrows
, row
, col
;
register struct lbuf
**ep
;
if (ncols
== 1 || Cflg
== 0) {
for (ep
= slp
; ep
< lp
; ep
++)
for (ep
= slp
; ep
< lp
; ep
++)
nrows
= (lp
- slp
- 1) / ncols
+ 1;
for (row
= 0; row
< nrows
; row
++) {
col
= row
== 0 && xtraent
;
for (; col
< ncols
; col
++) {
ep
= slp
+ (nrows
* col
) + row
;
* pputchar: like putchar but knows how to handle control chars.
* CAUTION: if you make ctrl chars print in ^x notation, or any
* other notation which is wider than one character, the column
* nature of things (such as files with 14 letter names) will be
* messed up. Weigh this carefully!
outcol
= (outcol
+ 8) &~ 7;
if (c
< ' ' || c
>= 0177) {
* column: get to the beginning of the next column.
if (outcol
+ colwidth
+ 2 > 80) {
if ((outcol
/ colwidth
+ 2) * colwidth
> 80) {
if (tabflg
&& (colwidth
<= 16)) {
outcol
+= 8 - (outcol
% 8);
outcol
+= 8 - (outcol
% 8);
} while (outcol
% colwidth
);
* nblock: the number of 512 byte blocks a size byte file takes up.
* (Note: the number stays 512 no matter what BUFSIZ or the filesystem uses.)
* This code handles the rwx- business.
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])];)
while (--n
>=0 && (flags
&*pairp
++)==0)
* returns cat(dir, "/", file), unless dir ends in /, when it doesn't //
* readdir: read in the directory whose name is dir,
static struct direct dentry
;
register struct lbuf
*ep
;
if ((dirf
= fopen(dir
, "r")) == NULL
) {
printf("%s unreadable\n", dir
);
if (fread(&dentry
, sizeof(dentry
), 1, dirf
) != 1)
aflg
==0 && dentry
.d_name
[0]=='.' && (
|| dentry
.d_name
[1]=='.' && dentry
.d_name
[2]=='\0'))
width
= strlen (dentry
.d_name
);
ep
= gstat(makename(dir
, dentry
.d_name
), Fflg
|| Rflg
);
ep
->ln
.lname
[j
] = dentry
.d_name
[j
];
* stat the given file and return an lbuf containing it.
* argfl is nonzero if a stat is required because the file is
* an argument, rather than having been found in a directory.
register struct lbuf
*rep
;
rep
= (struct lbuf
*)malloc(sizeof(struct lbuf
));
fprintf(stderr
, "ls: out of memory\n");
if (lastp
>= &flist
[NFILES
]) {
fprintf(stderr
, "ls: too many files\n");
if (stat(file
, &statb
)<0) {
printf("%s not found\n", file
);
rep
->lnum
= statb
.st_ino
;
rep
->lsize
= statb
.st_size
;
switch(statb
.st_mode
&S_IFMT
) {
rep
->lsize
= statb
.st_rdev
;
rep
->lsize
= statb
.st_rdev
;
rep
->lsize
= statb
.st_rdev
;
rep
->lsize
= statb
.st_rdev
;
rep
->lflags
= statb
.st_mode
& ~S_IFMT
;
rep
->luid
= statb
.st_uid
;
rep
->lgid
= statb
.st_gid
;
rep
->lnl
= statb
.st_nlink
;
rep
->lmtime
= statb
.st_atime
;
rep
->lmtime
= statb
.st_ctime
;
rep
->lmtime
= statb
.st_mtime
;
tblocks
+= nblock(statb
.st_size
);
* decide whether to print pp1 before or after pp2, based on their
* names, various times, and the r flag.
struct lbuf
**pp1
, **pp2
;
register struct lbuf
*p1
, *p2
;
if (p1
->lflags
&ISARG
&& p1
->ltype
=='d') {
if (!(p2
->lflags
&ISARG
&& p2
->ltype
=='d'))
if (p2
->lflags
&ISARG
&& p2
->ltype
=='d')
if(p2
->lmtime
== p1
->lmtime
)
if(p2
->lmtime
> p1
->lmtime
)
return(rflg
* strcmp(p1
->lflags
&ISARG
? p1
->ln
.namep
: p1
->ln
.lname
,
p2
->lflags
&ISARG
? p2
->ln
.namep
: p2
->ln
.lname
));
* print the entry pointed at by ap
struct { char dminor
, dmajor
;};
struct passwd
*getpwuid();
struct group
*getgrgid();
printf("%D ", nblock(p
->lsize
));
printf("%4D ", nblock(p
->lsize
));
grptr
= getgrgid(p
->lgid
);
if (nflg
== 0 && grptr
!= 0)
printf("%-8.8s", grptr
->gr_name
);
if (nflg
== 0 && (name
= getname(p
->luid
))) {
pwptr
= getpwuid(p
->luid
);
if (nflg
== 0 && pwptr
!= 0)
printf("%-8.8s", pwptr
->pw_name
);
major((int)p
->lsize
), minor((int)p
->lsize
));
printf("%7ld", p
->lsize
);
printf(" %-7.7s %-4.4s ", cp
+4, cp
+20); else
printf(" %-12.12s ", cp
+4);
else if (p
->lflags
& 0111)
strncat (fname
, p
->ln
.namep
, 98);
strncat (fname
, p
->ln
.lname
, 14);
else if (p
->lflags
& 0111)
/* char printf_id[] = "@(#) printf.c:2.2 6/5/79";*/
* This version of printf is compatible with the Version 7 C
* printf. The differences are only minor except that this
* printf assumes it is to print through pputchar. Version 7
* printf is more general (and is much larger) and includes
* provisions for floating point.
#define MAXOCT 11 /* Maximum octal digits in a long */
#define MAXINT 32767 /* largest normal length positive integer */
#define BIG 1000000000 /* largest power of 10 less than an unsigned long */
#define MAXDIGS 10 /* number of digits in BIG */
static int width
, sign
, fill
;
int length
,mask1
,nbits
,n
;
/* process format string first */
while ((fcode
= *fmt
++)!='%') {
/* ordinary (non-%) character */
/* length modifier: -1 for h, 1 for l, 0 for none */
/* check for a leading - sign */
/* a '0' may follow the - sign */
/* this is the requested fill character */
/* Now comes a digit string which may be a '*' */
while (*fmt
>='0' && *fmt
<='9')
width
= width
* 10 + (*fmt
++ - '0');
/* maybe a decimal point followed by more digits (or '*') */
while (*fmt
>='0' && *fmt
<='9')
prec
= prec
* 10 + (*fmt
++ - '0');
* At this point, "sign" is nonzero if there was
* a sign, "fill" is 0 if there was a leading
* zero and 1 otherwise, "width" and "prec"
* contain numbers corresponding to the digit
* strings before and after the decimal point,
* respectively, and "fmt" addresses the next
* character after the whole mess. If there was
* no decimal point, "prec" will be -1.
* At exit from the following switch, we will
* emit the characters starting at "bptr" and
* ending at "ptr"-1, unless fcode is '\0'.
switch (fcode
= *fmt
++) {
/* process characters and strings first */
buf
[0] = va_arg(ap
, int);
bptr
= va_arg(ap
,char *);
for (n
=0; *bptr
++ && n
< prec
; n
++) ;
num
= (unsigned)va_arg(ap
,int);
/* shift and mask for speed */
if (((int) num
& mask1
) < 10)
*--bptr
= ((int) num
& mask1
) + 060;
*--bptr
= ((int) num
& mask1
) + 0127;
while (num
= (num
>> nbits
) & mask2
);
if (!sign
&& fill
<= 0) {
fcode
= fcode
+ 'a' - 'A';
if (n
= (fcode
!= 'u' && num
< 0))
/* now convert to digits */
bptr
= b_dconv(num
, buf
);
/* not a control character,
/* b_dconv converts the unsigned long integer "value" to
* printable decimal and places it in "buffer", right-justified.
* The value returned is the address of the first non-zero character,
* or the address of the last character if all are zero.
* The result is NOT null terminated, and is MAXDIGS characters long,
* starting at buffer[1] (to allow for insertion of a sign).
* This program assumes it is running on 2's complement machine
* with reasonable overflow treatment.
/* zero is a special case */
/* develop the leading digit of the value in "n" */
value
-= BIG
; /* will eventually underflow */
while ((lval
= value
- BIG
) >= 0) {
/* stash it in buffer[1] to allow for a sign */
* Now develop the rest of the digits. Since speed counts here,
* we do it in two loops. The first gets "value" down until it
* is no larger than MAXINT. The second one uses integer divides
* rather than long divides to speed it up.
*--bp
= (int)(value
% 10) + '0';
/* cannot lose precision */
*--bp
= (svalue
% 10) + '0';
/* fill in intermediate zeroes if needed */
* This program sends string "s" to pputchar. The character after
* the end of "s" is given by "send". This allows the size of the
* field to be computed; it is stored in "alen". "width" contains the
* user specified length. If width<alen, the width will be taken to
* be alen. "sign" is zero if the string is to be right-justified
* in the field, nonzero if it is to be left-justified. "fill" is
* 0 if the string is to be padded with '0', positive if it is to be
* padded with ' ', and negative if an initial '-' should appear before
* any padding in right-justification (to avoid printing "-3" as
* "000-3" where "-0003" was intended).
cfill
= fill
>0? ' ': '0';
/* we may want to print a leading '-' before anything */
if (*s
== '-' && fill
< 0) {
/* emit any leading pad characters */
/* emit the string itself */
/* emit trailing pad characters */
char names
[NUID
][NMAX
+1];
register struct passwd
*pw
;
struct passwd
*getpwent();
if (uid
>= 0 && uid
< NUID
&& names
[uid
][0])
while (pw
= getpwent()) {
if (pw
->pw_uid
< 0 || pw
->pw_uid
>= NUID
)
if (names
[pw
->pw_uid
][0])
strncpy(names
[pw
->pw_uid
], pw
->pw_name
, NMAX
);