add ls; simpler pwd
This commit is contained in:
		
							
								
								
									
										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))) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user