add ls; simpler pwd

This commit is contained in:
Connor Lane Smith 2011-05-26 04:01:20 +01:00
parent 273f150c84
commit 6ef3d9174b
9 changed files with 268 additions and 24 deletions

View File

@ -1,8 +1,8 @@
include config.mk include config.mk
LIB = util/afgets.o util/enmasse.o util/eprintf.o util/recurse.o LIB = util/afgets.o util/agetcwd.o util/enmasse.o util/eprintf.o util/recurse.o
SRC = basename.c cat.c chown.c date.c dirname.c echo.c false.c grep.c head.c \ SRC = basename.c cat.c chown.c date.c dirname.c echo.c false.c grep.c head.c \
ln.c mkfifo.c pwd.c rm.c sleep.c tee.c touch.c true.c wc.c ln.c ls.c mkfifo.c pwd.c rm.c sleep.c tee.c touch.c true.c wc.c
OBJ = $(SRC:.c=.o) $(LIB) OBJ = $(SRC:.c=.o) $(LIB)
BIN = $(SRC:.c=) BIN = $(SRC:.c=)
MAN = $(SRC:.c=.1) MAN = $(SRC:.c=.1)
@ -11,7 +11,7 @@ all: $(BIN)
$(OBJ): util.h $(OBJ): util.h
$(BIN): util.a $(BIN): util.a
grep: text.h grep.o: text.h
.o: .o:
@echo CC -o $@ @echo CC -o $@

4
echo.c
View File

@ -21,9 +21,9 @@ main(int argc, char *argv[])
for(; optind < argc; optind++) { for(; optind < argc; optind++) {
fputs(argv[optind], stdout); fputs(argv[optind], stdout);
if(optind+1 < argc) if(optind+1 < argc)
fputc(' ', stdout); putchar(' ');
} }
if(!nflag) if(!nflag)
fputc('\n', stdout); putchar('\n');
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

27
ls.1 Normal file
View File

@ -0,0 +1,27 @@
.TH LS 1 sbase\-VERSION
.SH NAME
ls \- list directory contents
.SH SYNOPSIS
.B ls
.RB [ \-adlt ]
.RI [ file ...]
.SH DESCRIPTION
.B ls
lists each given file, and the contents of each given directory. If no files
are given the current directory is listed.
.SH OPTIONS
.TP
.B \-a
shows hidden files (those beginning with '.').
.TP
.B \-d
lists directories themselves, not their contents.
.TP
.B \-l
lists detailed information about each file, including their permissions, links,
owner, group, size, and modification time.
.TP
.B \-t
sorts files by modification time instead of by name.
.SH SEE ALSO
.IR stat (2)

212
ls.c Normal file
View File

@ -0,0 +1,212 @@
/* See LICENSE file for copyright and license details. */
#include <dirent.h>
#include <errno.h>
#include <grp.h>
#include <pwd.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/stat.h>
#include "util.h"
typedef struct {
char *name;
mode_t mode;
nlink_t nlink;
uid_t uid;
gid_t gid;
off_t size;
time_t mtime;
} Entry;
static int entcmp(Entry *, Entry *);
static void ls(char *, bool);
static void lsdir(const char *);
static void mkent(Entry *, char *);
static void output(Entry *);
static bool aflag = false;
static bool lflag = false;
static bool tflag = false;
static bool many;
int
main(int argc, char *argv[])
{
bool dflag = false;
char c;
while((c = getopt(argc, argv, "adlt")) != -1)
switch(c) {
case 'a':
aflag = true;
break;
case 'd':
dflag = true;
break;
case 'l':
lflag = true;
break;
case 't':
tflag = true;
break;
default:
exit(EXIT_FAILURE);
}
many = (argc > optind+1);
if(optind == argc)
ls(".", !dflag);
else for(; optind < argc; optind++)
ls(argv[optind], !dflag);
return EXIT_SUCCESS;
}
int
entcmp(Entry *a, Entry *b)
{
if(tflag)
return b->mtime - a->mtime;
else
return strcmp(a->name, b->name);
}
void
ls(char *path, bool expand)
{
Entry ent;
mkent(&ent, path);
if(expand && S_ISDIR(ent.mode))
lsdir(path);
else
output(&ent);
}
void
lsdir(const char *path)
{
char *buf, *p;
long i, n = 0;
struct dirent *d;
DIR *dp;
Entry *ents = NULL;
buf = agetcwd();
if(!(dp = opendir(path)))
eprintf("opendir %s:", path);
if(chdir(path) != 0)
eprintf("chdir %s:", path);
while((d = readdir(dp))) {
if(d->d_name[0] == '.' && !aflag)
continue;
if(!(ents = realloc(ents, ++n * sizeof *ents)))
eprintf("realloc:");
if(!(p = strdup(d->d_name)))
eprintf("strdup:");
mkent(&ents[n-1], p);
}
closedir(dp);
qsort(ents, n, sizeof *ents, (int (*)(const void *, const void *))entcmp);
if(many)
printf("%s:\n", path);
for(i = 0; i < n; i++) {
output(&ents[i]);
free(ents[i].name);
}
if(chdir(buf) != 0)
eprintf("chdir %s:", buf);
free(ents);
free(buf);
}
void
mkent(Entry *ent, char *path)
{
struct stat st;
if(lstat(path, &st) != 0)
eprintf("lstat %s:", path);
ent->name = path;
ent->mode = st.st_mode;
ent->nlink = st.st_nlink;
ent->uid = st.st_uid;
ent->gid = st.st_gid;
ent->size = st.st_size;
ent->mtime = st.st_mtime;
}
void
output(Entry *ent)
{
char buf[BUFSIZ], mode[11], *fmt;
struct group *gr;
struct passwd *pw;
if(!lflag) {
puts(ent->name);
return;
}
if(S_ISREG(ent->mode))
mode[0] = '-';
else if(S_ISBLK(ent->mode))
mode[0] = 'b';
else if(S_ISCHR(ent->mode))
mode[0] = 'c';
else if(S_ISDIR(ent->mode))
mode[0] = 'd';
else if(S_ISFIFO(ent->mode))
mode[0] = 'p';
else if(S_ISLNK(ent->mode))
mode[0] = 'l';
else if(S_ISSOCK(ent->mode))
mode[0] = 's';
else
mode[0] = '?';
mode[1] = (ent->mode & S_IRUSR) ? 'r' : '-';
mode[2] = (ent->mode & S_IWUSR) ? 'w' : '-';
if(ent->mode & S_ISUID)
mode[3] = (ent->mode & S_IXUSR) ? 's' : 'S';
else
mode[3] = (ent->mode & S_IXUSR) ? 'x' : '-';
mode[4] = (ent->mode & S_IRGRP) ? 'r' : '-';
mode[5] = (ent->mode & S_IWGRP) ? 'w' : '-';
if(ent->mode & S_ISGID)
mode[6] = (ent->mode & S_IXGRP) ? 's' : 'S';
else
mode[6] = (ent->mode & S_IXGRP) ? 'x' : '-';
mode[7] = (ent->mode & S_IROTH) ? 'r' : '-';
mode[8] = (ent->mode & S_IWOTH) ? 'w' : '-';
mode[9] = (ent->mode & S_IXOTH) ? 'x' : '-';
mode[10] = '\0';
errno = 0;
pw = getpwuid(ent->uid);
if(errno)
eprintf("getpwuid %d:", ent->uid);
else if(!pw)
eprintf("getpwuid %d: no such user\n", ent->uid);
errno = 0;
gr = getgrgid(ent->gid);
if(errno)
eprintf("getgrgid %d:", ent->gid);
else if(!gr)
eprintf("getgrgid %d: no such group\n", ent->gid);
if(time(NULL) > ent->mtime + (180*24*60*60)) /* 6 months ago? */
fmt = "%b %d %Y";
else
fmt = "%b %d %H:%M";
strftime(buf, sizeof buf, fmt, localtime(&ent->mtime));
printf("%s %2d %s %s %6lu %s %s\n", mode, ent->nlink, pw->pw_name, gr->gr_name, (unsigned long)ent->size, buf, ent->name);
}

12
pwd.c
View File

@ -7,16 +7,6 @@
int int
main(void) main(void)
{ {
char *buf; puts(agetcwd());
long size;
if((size = pathconf(".", _PC_PATH_MAX)) < 0)
size = BUFSIZ;
if(!(buf = malloc(size)))
eprintf("malloc:");
if(!getcwd(buf, size))
eprintf("getcwd:");
puts(buf);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

1
util.h
View File

@ -1,5 +1,6 @@
/* See LICENSE file for copyright and license details. */ /* See LICENSE file for copyright and license details. */
char *agetcwd(void);
void enmasse(int, char **, int (*)(const char *, const char *)); void enmasse(int, char **, int (*)(const char *, const char *));
void eprintf(const char *, ...); void eprintf(const char *, ...);
void recurse(const char *, void (*)(const char *)); void recurse(const char *, void (*)(const char *));

20
util/agetcwd.c Normal file
View File

@ -0,0 +1,20 @@
/* See LICENSE file for copyright and license details. */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "../util.h"
char *
agetcwd(void)
{
char *buf;
size_t size;
if((size = pathconf(".", _PC_PATH_MAX)) < 0)
size = BUFSIZ;
if(!(buf = malloc(size)))
eprintf("malloc:");
if(!getcwd(buf, size))
eprintf("getcwd:");
return buf;
}

View File

@ -11,7 +11,6 @@ void
recurse(const char *path, void (*fn)(const char *)) recurse(const char *path, void (*fn)(const char *))
{ {
char *buf; char *buf;
long size;
struct dirent *d; struct dirent *d;
DIR *dp; DIR *dp;
@ -21,12 +20,7 @@ recurse(const char *path, void (*fn)(const char *))
else else
eprintf("opendir %s:", path); eprintf("opendir %s:", path);
} }
if((size = pathconf(".", _PC_PATH_MAX)) < 0) buf = agetcwd();
size = BUFSIZ;
if(!(buf = malloc(size)))
eprintf("malloc:");
if(!getcwd(buf, size))
eprintf("getcwd:");
if(chdir(path) != 0) if(chdir(path) != 0)
eprintf("chdir %s:", path); eprintf("chdir %s:", path);
while((d = readdir(dp))) while((d = readdir(dp)))

2
wc.c
View File

@ -64,7 +64,7 @@ output(const char *str, long nc, long nl, long nw)
printf(" %5ld", nc); printf(" %5ld", nc);
if(str) if(str)
printf(" %s", str); printf(" %s", str);
fputc('\n', stdout); putchar('\n');
} }
void void