add ls; simpler pwd
This commit is contained in:
parent
273f150c84
commit
6ef3d9174b
6
Makefile
6
Makefile
|
@ -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
4
echo.c
|
@ -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
27
ls.1
Normal 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
212
ls.c
Normal 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
12
pwd.c
|
@ -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
1
util.h
|
@ -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
20
util/agetcwd.c
Normal 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;
|
||||||
|
}
|
|
@ -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)))
|
||||||
|
|
Loading…
Reference in New Issue
Block a user