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

📄 ls.c

📁 minix软件源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*	ls 4.1 - List files.				Author: Kees J. Bot *								25 Apr 1989 * * About the amount of bytes for heap + stack under Minix: * Ls needs a average amount of 42 bytes per unserviced directory entry, so * scanning 10 directory levels deep in an ls -R with 100 entries per directory * takes 42000 bytes of heap.  So giving ls 10000 bytes is tight, 20000 is * usually enough, 40000 is pessimistic. *//* The array _ifmt[] is used in an 'ls -l' to map the type of a file to a * letter.  This is done so that ls can list any future file or device type * other than symlinks, without recompilation.  (Yes it's dirty.) */char _ifmt[] = "0pcCd?bB-?l?s???";#define ifmt(mode)	_ifmt[((mode) >> 12) & 0xF]#define nil 0#include <stdio.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <stddef.h>#include <stdlib.h>#include <unistd.h>#include <dirent.h>#include <time.h>#include <pwd.h>#include <grp.h>#include <errno.h>#include <fcntl.h>#include <termios.h>#include <sys/ioctl.h>#ifndef major#define major(dev)	((int) (((dev) >> 8) & 0xFF))#define minor(dev)	((int) (((dev) >> 0) & 0xFF))#endif#if !__minix#define SUPER_ID	uid	/* Let -A flag be default for SUPER_ID == 0. */#else#define SUPER_ID	gid#endif#ifdef S_IFLNKint (*status)(const char *file, struct stat *stp);#else#define status	stat#endif/* Basic disk block size is 512 except for one niche O.S. */#if __minix#define BLOCK	1024#else#define BLOCK	 512#endif/* Assume other systems have st_blocks. */#if !__minix#define ST_BLOCKS 1#endif/* Some terminals ignore more than 80 characters on a line.  Dumb ones wrap * when the cursor hits the side.  Nice terminals don't wrap until they have * to print the 81st character.  Wether we like it or not, no column 80. */int ncols= 79;#define NSEP	2	/* # spaces between columns. */#define MAXCOLS	150	/* Max # of files per line. */char *arg0;	/* Last component of argv[0]. */int uid, gid;	/* callers id. */int ex= 0;	/* Exit status to be. */int istty;	/* Output is on a terminal. *//* Safer versions of malloc and realloc: */void heaperr(void){	fprintf(stderr, "%s: Out of memory\n", arg0);	exit(-1);}void *allocate(size_t n)/* Deliver or die. */{	void *a;	if ((a= malloc(n)) == nil) heaperr();	return a;}#define reallocate	rllct	/* Same as realloc under some compilers. */void *reallocate(void *a, size_t n){	if ((a= realloc(a, n)) == nil) heaperr();	return a;}char allowed[] = "acdfgilnqrstu1ACFLMRTX";char flags[sizeof(allowed)];char arg0flag[] = "cfmrtx";	/* These in argv[0] go to upper case. */void setflags(char *flgs){	int c;	while ((c= *flgs++) != 0) {		if (strchr(allowed, c) == nil) {			fprintf(stderr, "Usage: %s -[%s] [file ...]\n",				arg0, allowed);			exit(1);		} else		if (strchr(flags, c) == nil) {			flags[strlen(flags)] = c;		}	}}int present(int f){	return f == 0 || strchr(flags, f) != nil;}void report(char *f)/* Like perror(3), but in the style: "ls: junk: No such file or directory. */{	fprintf(stderr, "%s: %s: %s\n", arg0, f, strerror(errno));	ex= 1;}/* Two functions, uidname and gidname, translate id's to readable names. * All names are remembered to avoid searching the password file. */#define NNAMES	(1 << (sizeof(int) + sizeof(char *)))enum whatmap { PASSWD, GROUP };struct idname {		/* Hash list of names. */	struct idname	*next;	char		*name;	uid_t		id;} *uids[NNAMES], *gids[NNAMES];char *idname(unsigned id, enum whatmap map)/* Return name for a given user/group id. */{	struct idname *i;	struct idname **ids= &(map == PASSWD ? uids : gids)[id % NNAMES];	while ((i= *ids) != nil && id < i->id) ids= &i->next;	if (i == nil || id != i->id) {		/* Not found, go look in the password or group map. */		char *name= nil;		char noname[3 * sizeof(uid_t)];		if (!present('n')) {			if (map == PASSWD) {				struct passwd *pw= getpwuid(id);				if (pw != nil) name= pw->pw_name;			} else {				struct group *gr= getgrgid(id);				if (gr != nil) name= gr->gr_name;			}		}		if (name == nil) {			/* Can't find it, weird.  Use numerical "name." */			sprintf(noname, "%u", id);			name= noname;		}		/* Add a new id-to-name cell. */		i= allocate(sizeof(*i));		i->id= id;		i->name= allocate(strlen(name) + 1);		strcpy(i->name, name);		i->next= *ids;		*ids= i;	}	return i->name;}#define uidname(uid)	idname((uid), PASSWD)#define gidname(gid)	idname((gid), GROUP)/* Path name construction, addpath adds a component, delpath removes it. * The string path is used throughout the program as the file under examination. */char *path;	/* Path name constructed in path[]. */int plen= 0, pidx= 0;	/* Lenght/index for path[]. */void addpath(int *didx, char *name)/* Add a component to path. (name may also be a full path at the first call) * The index where the current path ends is stored in *pdi. */{	if (plen == 0) path= (char *) allocate((plen= 32) * sizeof(path[0]));	if (pidx == 1 && path[0] == '.') pidx= 0;	/* Remove "." */	*didx= pidx;	/* Record point to go back to for delpath. */	if (pidx > 0 && path[pidx-1] != '/') path[pidx++]= '/';	do {		if (*name != '/' || pidx == 0 || path[pidx-1] != '/') {			if (pidx == plen) {				path= (char *) reallocate((void *) path,						(plen*= 2) * sizeof(path[0]));			}			path[pidx++]= *name;		}	} while (*name++ != 0);	--pidx;		/* Put pidx back at the null.  The path[pidx++]= '/'			 * statement will overwrite it at the next call.			 */}#define delpath(didx)	(path[pidx= didx]= 0)	/* Remove component. */int field = 0;	/* (used to be) Fields that must be printed. */		/* (now) Effects triggered by certain flags. */#define F_INODE		0x001	/* -i */#define F_BLOCKS	0x002	/* -s */#define F_EXTRA		0x004	/* -X */#define F_MODE		0x008	/* -lMX */#define F_LONG		0x010	/* -l */#define F_GROUP		0x020	/* -g */#define F_BYTIME	0x040	/* -tuc */#define F_ATIME		0x080	/* -u */#define F_CTIME		0x100	/* -c */#define F_MARK		0x200	/* -F */#define F_TYPE		0x400	/* -T */#define F_DIR		0x800	/* -d */struct file {		/* A file plus stat(2) information. */	struct file	*next;	/* Lists are made of them. */	char		*name;	/* Null terminated name. */	ino_t		ino;	mode_t		mode;	uid_t		uid;	gid_t		gid;	nlink_t		nlink;	dev_t		rdev;	off_t		size;	time_t		mtime;	time_t		atime;	time_t		ctime;#if ST_BLOCKS	long		blocks;#endif};void setstat(struct file *f, struct stat *stp){	f->ino=		stp->st_ino;	f->mode=	stp->st_mode;	f->nlink=	stp->st_nlink;	f->uid=		stp->st_uid;	f->gid=		stp->st_gid;	f->rdev=	stp->st_rdev;	f->size=	stp->st_size;	f->mtime=	stp->st_mtime;	f->atime=	stp->st_atime;	f->ctime=	stp->st_ctime;#if ST_BLOCKS	f->blocks=	stp->st_blocks;#endif}#define	PAST	(26*7*24*3600L)	/* Half a year ago. *//* Between PAST and FUTURE from now a time is printed, otherwise a year. */#define FUTURE	(15*60L)	/* Fifteen minutes. */static char *timestamp(struct file *f)/* Transform the right time field into something readable. */{	struct tm *tm;	time_t t;	static time_t now;	static int drift= 0;	static char date[] = "Jan 19  2038";	static char month[] = "JanFebMarAprMayJunJulAugSepOctNovDec";	t= f->mtime;	if (field & F_ATIME) t= f->atime;	if (field & F_CTIME) t= f->ctime;	tm= localtime(&t);	if (--drift < 0) { time(&now); drift= 50; }	/* limit time() calls */	if (t < now - PAST || t > now + FUTURE) {		sprintf(date, "%.3s %2d  %4d",			month + 3*tm->tm_mon,			tm->tm_mday,			1900 + tm->tm_year);	} else {		sprintf(date, "%.3s %2d %02d:%02d",			month + 3*tm->tm_mon,			tm->tm_mday,			tm->tm_hour, tm->tm_min);	}	return date;}char *permissions(struct file *f)/* Compute long or short rwx bits. */{	static char rwx[] = "drwxr-x--x";	rwx[0] = ifmt(f->mode);	/* Note that rwx[0] is a guess for the more alien file types.  It is	 * correct for BSD4.3 and derived systems.  I just don't know how	 * "standardized" these numbers are.	 */	if (field & F_EXTRA) {		/* Short style */		int mode = f->mode, ucase= 0;		if (uid == f->uid) {	/* What group of bits to use. */			/* mode<<= 0, */			ucase= (mode<<3) | (mode<<6);			/* Remember if group or others have permissions. */		} else		if (gid == f->gid) {			mode<<= 3;		} else {			mode<<= 6;		}		rwx[1]= mode&S_IRUSR ? (ucase&S_IRUSR ? 'R' : 'r') : '-';		rwx[2]= mode&S_IWUSR ? (ucase&S_IWUSR ? 'W' : 'w') : '-';		if (mode&S_IXUSR) {			static char sbit[]= { 'x', 'g', 'u', 's' };			rwx[3]= sbit[(f->mode&(S_ISUID|S_ISGID))>>10];			if (ucase&S_IXUSR) rwx[3] += 'A'-'a';		} else {			rwx[3]= f->mode&(S_ISUID|S_ISGID) ? '=' : '-';		}		rwx[4]= 0;	} else {		/* Long form. */		char *p= rwx+1;		int mode= f->mode;		do {			p[0] = (mode & S_IRUSR) ? 'r' : '-';			p[1] = (mode & S_IWUSR) ? 'w' : '-';			p[2] = (mode & S_IXUSR) ? 'x' : '-';			mode<<= 3;		} while ((p+=3) <= rwx+7);		if (f->mode&S_ISUID) rwx[3]= f->mode&(S_IXUSR>>0) ? 's' : '=';		if (f->mode&S_ISGID) rwx[6]= f->mode&(S_IXUSR>>3) ? 's' : '=';		if (f->mode&S_ISVTX) rwx[9]= f->mode&(S_IXUSR>>6) ? 't' : '=';	}	return rwx;}void numeral(int i, char **pp){	char itoa[3*sizeof(int)], *a=itoa;	do *a++ = i%10 + '0'; while ((i/=10) > 0);	do *(*pp)++ = *--a; while (a>itoa);}#define K	1024L		/* A kilobyte counts in multiples of K */#define T	1000L		/* A megabyte in T*K, a gigabyte in T*T*K */char *cxsize(struct file *f)/* Try and fail to turn a 32 bit size into 4 readable characters. */{	static char siz[] = "1.2m";	char *p= siz;	off_t z;	siz[1]= siz[2]= siz[3]= 0;	if (f->size <= 5*K) {	/* <= 5K prints as is. */		numeral((int) f->size, &p);		return siz;	}	z= (f->size + K-1) / K;	if (z <= 999) {		/* Print as 123k. */		numeral((int) z, &p);		*p = 'k';	/* Can't use 'K', looks bad */	} else	if (z*10 <= 99*T) {	/* 1.2m (Try ls -X /dev/at0) */		z= (z*10 + T-1) / T;	/* Force roundup */		numeral((int) z / 10, &p);		*p++ = '.';		numeral((int) z % 10, &p);		*p = 'm';	} else	if (z <= 999*T) {	/* 123m */		numeral((int) ((z + T-1) / T), &p);		*p = 'm';	} else {		/* 1.2g */		z= (z*10 + T*T-1) / (T*T);		numeral((int) z / 10, &p);		*p++ = '.';		numeral((int) z % 10, &p);		*p = 'g';	}	return siz;}/* Transform size of file to number of blocks.  This was once a function that * guessed the number of indirect blocks, but that nonsense has been removed. */#if ST_BLOCKS#define nblocks(f)	((f)->blocks)#else#define nblocks(f)	(((f)->size + BLOCK-1) / BLOCK)#endif/* From number of blocks to kilobytes. */#if BLOCK < 1024#define nblk2k(nb)	(((nb) + (1024 / BLOCK - 1)) / (1024 / BLOCK))#else#define nblk2k(nb)	((nb) * (BLOCK / 1024))#endifstatic int (*CMP)(struct file *f1, struct file *f2);static int (*rCMP)(struct file *f1, struct file *f2);static void mergesort(struct file **al)/* This is either a stable mergesort, or thermal noise, I'm no longer sure. * It must be called like this: if (L != nil && L->next != nil) mergesort(&L); */{	/* static */ struct file *l1, **mid;  /* Need not be local */	struct file *l2;	l1= *(mid= &(*al)->next);	do {		if ((l1= l1->next) == nil) break;		mid= &(*mid)->next;	} while ((l1= l1->next) != nil);	l2= *mid;	*mid= nil;	if ((*al)->next != nil) mergesort(al);	if (l2->next != nil) mergesort(&l2);	l1= *al;	for (;;) {		if ((*CMP)(l1, l2) <= 0) {			if ((l1= *(al= &l1->next)) == nil) {				*al= l2;				break;			}		} else {			*al= l2;			l2= *(al= &l2->next);			*al= l1;			if (l2 == nil) break;		}	}}int namecmp(struct file *f1, struct file *f2){	return strcmp(f1->name, f2->name);}int mtimecmp(struct file *f1, struct file *f2){	return f1->mtime == f2->mtime ? 0 : f1->mtime > f2->mtime ? -1 : 1;}int atimecmp(struct file *f1, struct file *f2){	return f1->atime == f2->atime ? 0 : f1->atime > f2->atime ? -1 : 1;}int ctimecmp(struct file *f1, struct file *f2){	return f1->ctime == f2->ctime ? 0 : f1->ctime > f2->ctime ? -1 : 1;}int typecmp(struct file *f1, struct file *f2){	return ifmt(f1->mode) - ifmt(f2->mode);}int revcmp(struct file *f1, struct file *f2) { return (*rCMP)(f2, f1); }static void sort(struct file **al)/* Sort the files according to the flags. */{	if (!present('f') && *al != nil && (*al)->next != nil) {		CMP= namecmp;		if (!(field & F_BYTIME)) {			/* Sort on name */			if (present('r')) { rCMP= CMP; CMP= revcmp; }			mergesort(al);		} else {			/* Sort on name first, then sort on time. */			mergesort(al);			if (field & F_CTIME) {				CMP= ctimecmp;			} else

⌨️ 快捷键说明

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