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

📄 builtins.c

📁 早期freebsd实现
💻 C
字号:
/* builtins.c: the collection of rc's builtin commands *//*	NOTE: rc's builtins do not call "rc_error" because they are	commands, and rc errors usually arise from syntax errors. e.g.,	you probably don't want interpretation of a shell script to stop	because of a bad umask.*/#include <sys/ioctl.h>#include <setjmp.h>#include <errno.h>#include "rc.h"#include "jbwrap.h"#include <sys/time.h>#include <sys/resource.h>extern int umask(int);static void b_break(char **), b_cd(char **), b_eval(char **), b_exit(char **),	b_newpgrp(char **), b_return(char **), b_shift(char **), b_umask(char **),	b_wait(char **), b_whatis(char **);static void b_limit(char **);static void b_echo(char **);static struct {	builtin_t *p;	char *name;} builtins[] = {	{ b_break,	"break" },	{ b_builtin,	"builtin" },	{ b_cd,		"cd" },	{ b_echo,	"echo" },	{ b_eval,	"eval" },	{ b_exec,	"exec" },	{ b_exit,	"exit" },	{ b_limit,	"limit" },	{ b_newpgrp,	"newpgrp" },	{ b_return,	"return" },	{ b_shift,	"shift" },	{ b_umask,	"umask" },	{ b_wait,	"wait" },	{ b_whatis,	"whatis" },	{ b_dot,	"." },};extern builtin_t *isbuiltin(char *s) {	int i;	for (i = 0; i < arraysize(builtins); i++)		if (streq(builtins[i].name, s))			return builtins[i].p;	return NULL;}/* funcall() is the wrapper used to invoke shell functions. pushes $*, and "return" returns here. */extern void funcall(char **av) {	Jbwrap j;	Estack e1, e2;	Edata jreturn, star;	if (setjmp(j.j))		return;	starassign(*av, av+1, TRUE);	jreturn.jb = &j;	star.name = "*";	except(eReturn, jreturn, &e1);	except(eVarstack, star, &e2);	walk(treecpy(fnlookup(*av), nalloc), TRUE);	varrm("*", TRUE);	unexcept(); /* eVarstack */	unexcept(); /* eReturn */}static void arg_count(char *name) {	fprint(2, "too many arguments to %s\n", name);	set(FALSE);}static void badnum(char *num) {	fprint(2, "%s is a bad number\n", num);	set(FALSE);}/* a dummy command. (exec() performs "exec" simply by not forking) */extern void b_exec(char **av) {}/* echo -n omits a newline. echo -- -n echos '-n' */static void b_echo(char **av) {	char *format = "%A\n";	if (*++av != NULL) {		if (streq(*av, "-n"))                	format = "%A", av++;		else if (streq(*av, "--"))			av++;	}	fprint(1, format, av);	set(TRUE);}/* cd. traverse $cdpath if the directory given is not an absolute pathname */static void b_cd(char **av) {	List *s, nil;	char *path = NULL;	size_t t, pathlen = 0;	if (*++av == NULL) {		s = varlookup("home");		*av = (s == NULL) ? "/" : s->w;	} else if (av[1] != NULL) {		arg_count("cd");		return;	}	if (isabsolute(*av) || streq(*av, ".") || streq(*av, "..")) { /* absolute pathname? */		if (chdir(*av) < 0) {			set(FALSE);			uerror(*av);		} else			set(TRUE);	} else {		s = varlookup("cdpath");		if (s == NULL) {			s = &nil;			nil.w = "";			nil.n = NULL;		}		do {			if (s != &nil && *s->w != '\0') {				t = strlen(*av) + strlen(s->w) + 2;				if (t > pathlen)					path = nalloc(pathlen = t);				strcpy(path, s->w);				if (!streq(s->w, "/")) /* "//" is special to POSIX */					strcat(path, "/");				strcat(path, *av);			} else {				pathlen = 0;				path = *av;			}			if (chdir(path) >= 0) {				set(TRUE);				if (interactive && *s->w != '\0' && !streq(s->w, "."))					fprint(1, "%s\n", path);				return;			}			s = s->n;		} while (s != NULL);		fprint(2, "couldn't cd to %s\n", *av);		set(FALSE);	}}static void b_umask(char **av) {	int i;	if (*++av == NULL) {		set(TRUE);		i = umask(0);		umask(i);		fprint(1, "0%o\n", i);	} else if (av[1] == NULL) {		i = o2u(*av);		if ((unsigned int) i > 0777) {			fprint(2, "bad umask\n");			set(FALSE);		} else {			umask(i);			set(TRUE);		}	} else {		arg_count("umask");		return;	}}static void b_exit(char **av) {	if (*++av != NULL)		ssetstatus(av);	rc_exit(getstatus());}/* raise a "return" exception, i.e., return from a function. if an integer argument is present, set $status to it */static void b_return(char **av) {	if (*++av != NULL)		ssetstatus(av);	rc_raise(eReturn);}/* raise a "break" exception for breaking out of for and while loops */static void b_break(char **av) {	if (av[1] != NULL) {		arg_count("break");		return;	}	rc_raise(eBreak);}/* shift $* n places (default 1) */static void b_shift(char **av) {	int shift = (av[1] == NULL ? 1 : a2u(av[1]));	List *s, *dollarzero;	if (av[1] != NULL && av[2] != NULL) {		arg_count("shift");		return;	}	if (shift < 0) {		badnum(av[1]);		return;	}	s = varlookup("*")->n;	dollarzero = varlookup("0");	while (s != NULL && shift != 0) {		s = s->n;		--shift;	}	if (s == NULL && shift != 0) {		fprint(2, "cannot shift\n");		set(FALSE);	} else {		varassign("*", append(dollarzero, s), FALSE);		set(TRUE);	}}/* dud function */extern void b_builtin(char **av) {}/* wait for a given process, or all outstanding processes */static void b_wait(char **av) {	int stat, pid;	if (av[1] == NULL) {		waitforall();		return;	}	if (av[2] != NULL) {		arg_count("wait");		return;	}	if ((pid = a2u(av[1])) < 0) {		badnum(av[1]);		return;	}	if (rc_wait4(pid, &stat, FALSE) > 0)		setstatus(pid, stat);	else		set(FALSE);	SIGCHK;}/*   whatis without arguments prints all variables and functions. Otherwise, check to see if a name   is defined as a variable, function or pathname.*/static void b_whatis(char **av) {	bool f, found;	bool ess = FALSE;	int i, ac, c;	List *s;	Node *n;	char *e;	for (rc_optind = ac = 0; av[ac] != NULL; ac++)		; /* count the arguments for getopt */	while ((c = rc_getopt(ac, av, "s")) == 's')		ess = TRUE;	if (c != -1) {		set(FALSE);		return;	}	av += rc_optind;	if (*av == NULL && !ess) {		whatare_all_vars();		set(TRUE);		return;	}	if (ess)		whatare_all_signals();	found = TRUE;	for (i = 0; av[i] != NULL; i++) {		f = FALSE;		errno = ENOENT;		if ((s = varlookup(av[i])) != NULL) {			f = TRUE;			prettyprint_var(1, av[i], s);		}		if ((n = fnlookup(av[i])) != NULL) {			f = TRUE;			prettyprint_fn(1, av[i], n);		} else if (isbuiltin(av[i]) != NULL) {			f = TRUE;			fprint(1, "builtin %s\n", av[i]);		} else if ((e = which(av[i], FALSE)) != NULL) {			f = TRUE;			fprint(1, "%s\n", e);		}		if (!f) {			found = FALSE;			if (errno != ENOENT)				uerror(av[i]);			else				fprint(2, "%s not found\n", av[i]);		}	}	set(found);}/* push a string to be eval'ed onto the input stack. evaluate it */static void b_eval(char **av) {	bool i = interactive;	if (av[1] == NULL)		return;	interactive = FALSE;	pushstring(av + 1, i); /* don't reset line numbers on noninteractive eval */	doit(TRUE);	interactive = i;}/*   push a file to be interpreted onto the input stack. with "-i" treat this as an interactive   input source.*/extern void b_dot(char **av) {	int fd;	bool old_i = interactive, i = FALSE;	Estack e;	Edata star;	av++;	if (*av == NULL)		return;	if (streq(*av, "-i")) {		av++;		i = TRUE;	}	if (dasheye) { /* rc -i file has to do the right thing. reset the dasheye state to FALSE, though. */		dasheye = FALSE;		i = TRUE;	}	if (*av == NULL)		return;	fd = rc_open(*av, rFrom);	if (fd < 0) {		if (rcrc) /* on rc -l, don't flag nonexistence of .rcrc */			rcrc = FALSE;		else {			uerror(*av);			set(FALSE);		}		return;	}	rcrc = FALSE;	starassign(*av, av+1, TRUE);	pushfd(fd);	interactive = i;	star.name = "*";	except(eVarstack, star, &e);	doit(TRUE);	varrm("*", TRUE);	unexcept(); /* eVarstack */	interactive = old_i;}/* put rc into a new pgrp. Used on the NeXT where the Terminal program is broken (sigh) */static void b_newpgrp(char **av) {	if (av[1] != NULL) {		arg_count("newpgrp");		return;	}	setpgrp(rc_pid, rc_pid);	ioctl(2, TIOCSPGRP, &rc_pid);}/* Berkeley limit support was cleaned up by Paul Haahr. */typedef struct Suffix Suffix;struct Suffix {	const Suffix *next;	long amount;	char *name;};static const Suffix	kbsuf = { NULL, 1024, "k" },	mbsuf = { &kbsuf, 1024*1024, "m" },	gbsuf = { &mbsuf, 1024*1024*1024, "g" },	stsuf = { NULL, 1, "s" },	mtsuf = { &stsuf, 60, "m" },	htsuf = { &mtsuf, 60*60, "h" };#define	SIZESUF &gbsuf#define	TIMESUF &htsuf#define	NOSUF ((Suffix *) NULL)  /* for RLIMIT_NOFILE on SunOS 4.1 */typedef struct {	char *name;	int flag;	const Suffix *suffix;} Limit;static const Limit limits[] = {	{ "cputime",		RLIMIT_CPU,	TIMESUF },	{ "filesize",		RLIMIT_FSIZE,	SIZESUF },	{ "datasize",		RLIMIT_DATA,	SIZESUF },	{ "stacksize",		RLIMIT_STACK,	SIZESUF },	{ "coredumpsize",	RLIMIT_CORE,	SIZESUF },	{ "memoryuse",		RLIMIT_RSS,	SIZESUF },	{ "descriptors",	RLIMIT_NOFILE,	NOSUF },	{ NULL, 0, NULL }};static void printlimit(const Limit *limit, bool hard) {	struct rlimit rlim;	long lim;	getrlimit(limit->flag, &rlim);	if (hard)		lim = rlim.rlim_max;	else		lim = rlim.rlim_cur;	if ((unsigned) lim == (unsigned) RLIM_INFINITY)		fprint(1, "%s \tunlimited\n", limit->name);	else {		const Suffix *suf;		for (suf = limit->suffix; suf != NULL; suf = suf->next)			if (lim % suf->amount == 0 && (lim != 0 || suf->amount > 1)) {				lim /= suf->amount;				break;			}		fprint(1, "%s \t%d%s\n", limit->name, lim, (suf == NULL || lim == 0) ? "" : suf->name);	}}static long parselimit(const Limit *limit, char *s) {	char *t;	int len = strlen(s);	long lim = 1;	const Suffix *suf = limit->suffix;	if (streq(s, "unlimited"))		return RLIM_INFINITY;	if (suf == TIMESUF && (t = strchr(s, ':')) != NULL) {		*t++ = '\0';		lim = 60 * a2u(s) + a2u(t);	} else {		for (; suf != NULL; suf = suf->next)			if (streq(suf->name, s + len - strlen(suf->name))) {				s[len - strlen(suf->name)] = '\0';				lim *= suf->amount;				break;			}		lim *= a2u(s);	}	return lim;}static void b_limit(char **av) {	const Limit *lp = limits;	bool hard = FALSE;	if (*++av != NULL && streq(*av, "-h")) {		av++;		hard = TRUE;	}	if (*av == NULL) {		for (; lp->name != NULL; lp++)			printlimit(lp, hard);		return;	}	for (;; lp++) {		if (lp->name == NULL) {			fprint(2, "no such limit\n");			set(FALSE);			return;		}		if (streq(*av, lp->name))			break;	}	if (*++av == NULL)		printlimit(lp, hard);	else {		struct rlimit rlim;		long pl;		getrlimit(lp->flag, &rlim);		if ((pl = parselimit(lp, *av)) < 0) {			fprint(2, "bad limit\n");			set(FALSE);			return;		}		if (hard)			rlim.rlim_max = pl;		else			rlim.rlim_cur = pl;		if (setrlimit(lp->flag, &rlim) == -1) {			uerror("setrlimit");			set(FALSE);		} else			set(TRUE);	}}

⌨️ 快捷键说明

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