⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 aupls.c

📁 高级unix编程第二版
💻 C
📖 第 1 页 / 共 2 页
字号:
/*	ls command	AUP2, Sec. 3.5, 3.6.5	Copyright 2003 by Marc J. Rochkind. All rights reserved.	May be copied only for purposes and under conditions described	on the Web page www.basepath.com/aup/copyright.htm.	The Example Files are provided "as is," without any warranty;	without even the implied warranty of merchantability or fitness	for a particular purpose. The author and his publisher are not	responsible for any damages, direct or incidental, resulting	from the use or non-use of these Example Files.	The Example Files may contain defects, and some contain deliberate	coding mistakes that were included for educational reasons.	You are responsible for determining if and how the Example Files	are to be used.*/#define WANT_LSDIR_FIXEDx#define AUPLS_FULL#include "defs.h"#include <dirent.h>#include <pwd.h>#include <grp.h>/*[aupls-top1]*/#define USAGE "Usage: aupls [-Rd] [dir]\n"static long total_entries = 0, total_dirs = 0;/*[aupls-top2]*/typedef enum {SHOW_PATH, SHOW_INFO} SHOW_OP;struct traverse_info {	bool ti_recursive;								 /* -R option? */	char *ti_name;									 /* current entry */	struct stat ti_stat;							 /* stat for ti_name */	bool (*ti_fcn)(struct traverse_info *, SHOW_OP); /* callback fcn */};/*[print_mode]*/#define TYPE(b) ((statp->st_mode & (S_IFMT)) == (b))#define MODE(b) ((statp->st_mode & (b)) == (b))static void print_mode(const struct stat *statp){	if (TYPE(S_IFBLK))		putchar('b');	else if (TYPE(S_IFCHR))		putchar('c');	else if (TYPE(S_IFDIR))		putchar('d');	else if (TYPE(S_IFIFO)) /* sic */		putchar('p');	else if (TYPE(S_IFREG))		putchar('-');	else if (TYPE(S_IFLNK))		putchar('l');	else if (TYPE(S_IFSOCK))		putchar('s');	else		putchar('?');	putchar(MODE(S_IRUSR) ? 'r' : '-');	putchar(MODE(S_IWUSR) ? 'w' : '-');	if (MODE(S_ISUID)) {		if (MODE(S_IXUSR))			putchar('s');		else			putchar('S');	}	else if (MODE(S_IXUSR))		putchar('x');	else		putchar('-');	putchar(MODE(S_IRGRP) ? 'r' : '-');	putchar(MODE(S_IWGRP) ? 'w' : '-');	if (MODE(S_ISGID)) {		if (MODE(S_IXGRP))			putchar('s');		else			putchar('S');	}	else if (MODE(S_IXGRP))		putchar('x');	else		putchar('-');	putchar(MODE(S_IROTH) ? 'r' : '-');	putchar(MODE(S_IWOTH) ? 'w' : '-');	if (MODE(S_IFDIR) && MODE(S_ISVTX)) {		if (MODE(S_IXOTH))			putchar('t');		else			putchar('T');	}	else if (MODE(S_IXOTH))		putchar('x');	else		putchar('-');}/*[]*/#undef TYPE#undef MODE/*[print_numlinks]*/static void print_numlinks(const struct stat *statp){	printf("%5ld", (long)statp->st_nlink);}/*[print_owner]*/static void print_owner(const struct stat *statp){	struct passwd *pwd = getpwuid(statp->st_uid);	if (pwd == NULL)		printf(" %-8ld", (long)statp->st_uid);	else		printf(" %-8s", pwd->pw_name);}/*[print_group]*/static void print_group(const struct stat *statp){	struct group *grp = getgrgid(statp->st_gid);	if (grp == NULL)		printf(" %-8ld", (long)statp->st_gid);	else		printf(" %-8s", grp->gr_name);}/*[print_size]*/static void print_size(const struct stat *statp){	switch (statp->st_mode & S_IFMT) {	case S_IFCHR:	case S_IFBLK:		printf("%4u,%4u", (unsigned)(statp->st_rdev >> 8),		  (unsigned)(statp->st_rdev & 0xFF));		break;	default:		printf("%9lu", (unsigned long)statp->st_size);	}}/*[print_date]*/static void print_date(const struct stat *statp){	time_t now;	double diff;	char buf[100], *fmt;	if (time(&now) == -1) {		printf(" ????????????");		return;	}	diff = difftime(now, statp->st_mtime);	if (diff < 0 || diff > 60 * 60 * 24 * 182.5) /* roughly 6 months */		fmt = "%b %e  %Y";	else		fmt = "%b %e %H:%M";	strftime(buf, sizeof(buf), fmt, localtime(&statp->st_mtime));	printf(" %s", buf);}/*	In code below, the "not supposed to happen" test modified to include EINVAL, which Darwin	returned for paths like /dev and /dev/fd.*//*[get_max_pathname]*/static long get_max_pathname(const char *path){	long max_path;	errno = 0;	max_path = pathconf(path, _PC_PATH_MAX);	if (max_path == -1) {		if (errno == 0 || errno == EINVAL) /* not supposed to happen */			max_path = 4096;		else			EC_FAIL	}	return max_path + 1;EC_CLEANUP_BGN	return -1;EC_CLEANUP_END}/*[]*//*[print_name]*/static void print_name(const struct stat *statp, const char *name){	if (S_ISLNK(statp->st_mode)) {		char *contents = malloc(statp->st_size + 1);		ssize_t n;		if (contents != NULL && (n = readlink(name, contents,		  statp->st_size)) != -1) {			contents[n] = '\0'; /* can't assume NUL-terminated */			printf(" %s -> %s", name, contents);		}		else			printf(" %s -> [can't read link]", name);		free(contents);	}	else		printf(" %s", name);}/*[ls_long-a]*/static void ls_long(const struct stat *statp, const char *name){	print_mode(statp);	print_numlinks(statp);	print_owner(statp);	print_group(statp);	print_size(statp);	print_date(statp);	print_name(statp, name);	putchar('\n');}/*[]*/#ifdef WANT_LSLONG/*[ls_long-b]*/int main(int argc, char *argv[]){	int i;	struct stat statbuf;	for (i = 1; i < argc; i++) {		ec_neg1( lstat(argv[i], &statbuf) )		ls_long(&statbuf, argv[i]);	}	exit(EXIT_SUCCESS);EC_CLEANUP_BGN	exit(EXIT_FAILURE);EC_CLEANUP_END}/*[]*/#endif/*[get_cwd]*/static char *get_cwd(bool cleanup){	static char *cwd = NULL;	static long max_path;	if (cleanup) {		free(cwd);		cwd = NULL;	}	else {		if (cwd == NULL) {			ec_neg1( max_path = get_max_pathname(".") )			ec_null( cwd = malloc((size_t)max_path) )		}		ec_null( getcwd(cwd, max_path) )		return cwd;	}	return NULL;EC_CLEANUP_BGN	return NULL;EC_CLEANUP_END}/*[aupls-print_cwd]*/static bool print_cwd(bool cleanup){	char *cwd;	if (cleanup)		(void)get_cwd(true);	else {		ec_null( cwd = get_cwd(false) )		printf("\n%s:\n", cwd);	}	return true;EC_CLEANUP_BGN	return false;EC_CLEANUP_END}/*[aupls-show_stat]*/static bool show_stat(struct traverse_info *p, SHOW_OP op){	switch (op) {	case SHOW_PATH:		ec_false( print_cwd(false) )		break;	case SHOW_INFO:		ls_long(&p->ti_stat, p->ti_name);	}	return true;EC_CLEANUP_BGN	return false;EC_CLEANUP_END}/*[aupls-check_parent]*/static bool check_parent(int dirfd, const char *name){	struct stat statbuf1, statbuf2;	if (name[0] != '/') {		ec_neg1( fstat(dirfd, &statbuf1) )		ec_neg1( lstat("..", &statbuf2) )		if (statbuf1.st_dev != statbuf2.st_dev ||		  statbuf1.st_ino != statbuf2.st_ino) {			print_cwd(false);			fprintf(stderr, "Doubly-linked directory encountered (%s).\n",			  name);			errno = 0;			EC_FAIL		}	}	return true;EC_CLEANUP_BGN	return false;EC_CLEANUP_END}/*[]*/static bool do_entry(struct traverse_info *p, bool stat_only);/*[aupls-do_dir1]*/static bool do_dir(struct traverse_info *p){	DIR *sp = NULL;	struct dirent *dp;	int dirfd = -1;	bool result = false;	/*		Entry could be changed from directory to symlink between		lstat() and here, in which case opendir would follow it,		possibly resulting in double-visiting or even a loop.	*/	ec_neg1(  dirfd = open(".", O_RDONLY) )	/*		[Not in book.]		On Darwin, fails on directory /dev/fd. Problem is that it thinks that some of		the file descriptors there are directories, and opendir fails on them with a bus		error. Skipping the entire /dev directory is a good idea. The shortcut is to skip		directories whose name is "dev", which isn't really correct, because they may not		be at the root. Fix is left to the reader...	*/	if (strcmp(p->ti_name, "dev") == 0 || strncmp(p->ti_name, "/dev", 4) == 0) {		printf("Skipping directory \"dev\" (even if it's not /dev).\n");		result = true;		EC_CLEANUP	}	/* [End of stuff not in book.] */	if ((sp = opendir(p->ti_name)) == NULL || chdir(p->ti_name) == -1) {		if (errno == EACCES) {			fprintf(stderr, "%s: Permission denied.\n", p->ti_name);			result = true;			EC_CLEANUP		}		/* Book showed just EC_FAIL here. Change so we can keep going. */		else {			syserr_print("do_dir()");			result = true; /* repeat of above, but want to keep book's logic */			EC_CLEANUP		}		/* EC_FAIL -- don't want this line anymore */	}/*[]*/	/*		Following is a good idea, but left out of book for space reasons.	*/	if (strcmp(p->ti_name, ".") != 0)		ec_false( check_parent(dirfd, p->ti_name) )/*[aupls-do_dir2]*/	if (p->ti_recursive)		ec_false( (p->ti_fcn)(p, SHOW_PATH) )

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -