sbase

suckless unix tools
git clone git://git.2f30.org/sbase.git
Log | Files | Refs | README | LICENSE

commit 6ef3d9174bbfaeb955e32c59b40b4451e1b0b396
parent 273f150c842e3daeb95f398ec29ed36c264e4ccf
Author: Connor Lane Smith <cls@lubutu.com>
Date:   Thu May 26 04:01:20 +0100

add ls; simpler pwd
Diffstat:
Makefile | 6+++---
echo.c | 4++--
ls.1 | 27+++++++++++++++++++++++++++
ls.c | 212+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
pwd.c | 12+-----------
util.h | 1+
util/agetcwd.c | 20++++++++++++++++++++
util/recurse.c | 8+-------
wc.c | 2+-
9 files changed, 268 insertions(+), 24 deletions(-)
diff --git a/Makefile b/Makefile @@ -1,8 +1,8 @@ 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 \ - 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) BIN = $(SRC:.c=) MAN = $(SRC:.c=.1) @@ -11,7 +11,7 @@ all: $(BIN) $(OBJ): util.h $(BIN): util.a -grep: text.h +grep.o: text.h .o: @echo CC -o $@ diff --git a/echo.c b/echo.c @@ -21,9 +21,9 @@ main(int argc, char *argv[]) for(; optind < argc; optind++) { fputs(argv[optind], stdout); if(optind+1 < argc) - fputc(' ', stdout); + putchar(' '); } if(!nflag) - fputc('\n', stdout); + putchar('\n'); return EXIT_SUCCESS; } diff --git a/ls.1 b/ls.1 @@ -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) diff --git a/ls.c b/ls.c @@ -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); +} diff --git a/pwd.c b/pwd.c @@ -7,16 +7,6 @@ int main(void) { - char *buf; - 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); + puts(agetcwd()); return EXIT_SUCCESS; } diff --git a/util.h b/util.h @@ -1,5 +1,6 @@ /* See LICENSE file for copyright and license details. */ +char *agetcwd(void); void enmasse(int, char **, int (*)(const char *, const char *)); void eprintf(const char *, ...); void recurse(const char *, void (*)(const char *)); diff --git a/util/agetcwd.c b/util/agetcwd.c @@ -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; +} diff --git a/util/recurse.c b/util/recurse.c @@ -11,7 +11,6 @@ void recurse(const char *path, void (*fn)(const char *)) { char *buf; - long size; struct dirent *d; DIR *dp; @@ -21,12 +20,7 @@ recurse(const char *path, void (*fn)(const char *)) else eprintf("opendir %s:", path); } - if((size = pathconf(".", _PC_PATH_MAX)) < 0) - size = BUFSIZ; - if(!(buf = malloc(size))) - eprintf("malloc:"); - if(!getcwd(buf, size)) - eprintf("getcwd:"); + buf = agetcwd(); if(chdir(path) != 0) eprintf("chdir %s:", path); while((d = readdir(dp))) diff --git a/wc.c b/wc.c @@ -64,7 +64,7 @@ output(const char *str, long nc, long nl, long nw) printf(" %5ld", nc); if(str) printf(" %s", str); - fputc('\n', stdout); + putchar('\n'); } void