Plan 9 from Bell Labs’s /usr/web/sources/patch/maybe/rc-unix-limit/unix.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


/*
 * Unix versions of system-specific functions
 *	By convention, exported routines herein have names beginning with an
 *	upper case letter.
 */
#include "rc.h"
#include "io.h"
#include "exec.h"
#include "getflags.h"
#include <errno.h>

#ifndef ETXTBSY
#define ETXTBSY	9999
#endif

char *Rcmain = "/usr/lib/rcmain";
char *Fdprefix = "/dev/fd/";

void execfinit(void);
void execlimit(void);

struct builtin Builtin[] = {
	"cd",		execcd,
	"whatis",	execwhatis,
	"eval",		execeval,
	"exec",		execexec,	/* but with popword first */
	"exit",		execexit,
	"shift",	execshift,
	"wait",		execwait,
	"umask",	execumask,
	".",		execdot,
	"finit",	execfinit,
	"flag",		execflag,
	"limit",	execlimit,
	0
};
#define	SEP	'\1'
char **environp;

struct word*
enval(char *s)
{
	char *t, c;
	struct word *v;
	for(t = s;*t && *t!=SEP;t++);
	c=*t;
	*t='\0';
	v = newword(s, c=='\0'?(struct word *)0:enval(t+1));
	*t = c;
	return v;
}

void
Vinit(void)
{
	extern char **environ;
	char *s;
	char **env = environ;
	environp = env;
	for(;*env;env++){
		for(s=*env;*s && *s!='(' && *s!='=';s++);
		switch(*s){
		case '\0':
			pfmt(err, "environment %q?\n", *env);
			break;
		case '=':
			*s='\0';
			setvar(*env, enval(s+1));
			*s='=';
			break;
		case '(':	/* ignore functions for now */
			break;
		}
	}
}

char **envp;

void
Xrdfn(void)
{
	char *s;
	int len;
	for(;*envp;envp++){
		for(s=*envp;*s && *s!='(' && *s!='=';s++);
		switch(*s){
		case '\0':
			pfmt(err, "environment %q?\n", *envp);
			break;
		case '=':	/* ignore variables */
			break;
		case '(':		/* Bourne again */
			s=*envp+3;
			envp++;
			len = strlen(s);
			s[len]='\n';
			execcmds(opencore(s, len+1));
			s[len]='\0';
			return;
		}
	}
	Xreturn();
}

union code rdfns[4];

void
execfinit(void)
{
	static int first = 1;
	if(first){
		rdfns[0].i = 1;
		rdfns[1].f = Xrdfn;
		rdfns[2].f = Xjump;
		rdfns[3].i = 1;
		first = 0;
	}
	Xpopm();
	envp = environp;
	start(rdfns, 1, runq->local);
}

static struct {
	char *name;
	int id;
} limits[] = {
	{ "cputime",		RLIMIT_CPU },
	{ "filesize",		RLIMIT_FSIZE },
	{ "datasize",		RLIMIT_DATA },
	{ "stacksize",		RLIMIT_STACK },
	{ "coredumpsize",	RLIMIT_CORE },
	{ "descriptors",	RLIMIT_NOFILE },
	{ "memoryuse",		RLIMIT_AS },
	{ "memoryrss",		RLIMIT_RSS },
	{ "maxproc",		RLIMIT_NPROC },
	{ "memorylocked",	RLIMIT_MEMLOCK },
	{ "filelocks",		RLIMIT_LOCKS },
};

static void 
prlim(char *name, int id)
{
	char pad[32];
	struct rlimit rlim;

	memset(pad, ' ', sizeof(pad));
	pad[sizeof(pad)-strlen(name)] = 0;

	pfmt(err, "%s%s ", name, pad);
	if(getrlimit(id, &rlim) < 0){
		pfmt(err, "%s			%s\n", "?", "?");
		return;
	}
	if(rlim.rlim_max == RLIM_INFINITY)
		pfmt(err, "%s			", "∞");
	else
		pfmt(err, "%d		", rlim.rlim_max);
	if(rlim.rlim_cur == RLIM_INFINITY)
		pfmt(err, "%s\n", "∞");
	else
		pfmt(err, "%d\n", rlim.rlim_cur);
}

void
execlimit(void)
{
	int i;
	struct rlimit rlim;
	word *a = runq->argv->words;

	switch(count(a)){
	case 1:
		for(i = 0; i < nelem(limits); i++)
			prlim(limits[i].name, limits[i].id);
		setstatus("");
		break;
	case 4:
		for(i = 0; i < nelem(limits); i++)
			if(strcmp(limits[i].name, a->next->word) == 0)
				break;
		if(i >= nelem(limits)){
			pfmt(err, "%s: %s unknown limit\n", a->word, a->next->word);
			setstatus("unknown");
			break;
		}

		if(strcmp(a->next->next->word, "∞") == 0)
			rlim.rlim_max = RLIM_INFINITY;
		else
			rlim.rlim_max = atoi(a->next->next->word);
		if(strcmp(a->next->next->next->word, "∞") == 0)
			rlim.rlim_cur = RLIM_INFINITY;
		else
			rlim.rlim_cur = atoi(a->next->next->next->word);

		if(setrlimit(limits[i].id, &rlim) < 0){
			pfmt(err, "%s: %s failed - %r\n", a->word, a->next->word);
			setstatus("failed");
			break;
		}
		setstatus("");
		break;
	default:
		pfmt(err, "usage: limit name hard soft\n");
		setstatus("usage");
		break;
	}
	poplist();
}

int
cmpenv(const void *aa, const void *ab)
{
	char * const*a = aa, * const*b = ab;

	return strcmp(*a, *b);
}

char **
mkenv(void)
{
	char **env, **ep, *p, *q;
	struct var **h, *v;
	struct word *a;
	int nvar = 0, nchr = 0, sep;

	/*
	 * Slightly kludgy loops look at locals then globals.
	 * locals no longer exist - geoff
	 */
	for(h = gvar-1; h != &gvar[NVAR]; h++)
	for(v = h >= gvar? *h: runq->local; v ;v = v->next){
		if((v==vlook(v->name)) && v->val){
			nvar++;
			nchr+=strlen(v->name)+1;
			for(a = v->val;a;a = a->next)
				nchr+=strlen(a->word)+1;
		}
		if(v->fn){
			nvar++;
			nchr+=strlen(v->name)+strlen(v->fn[v->pc-1].s)+8;
		}
	}
	env = (char **)emalloc((nvar+1)*sizeof(char *)+nchr);
	ep = env;
	p = (char *)&env[nvar+1];
	for(h = gvar-1; h != &gvar[NVAR]; h++)
	for(v = h >= gvar? *h: runq->local;v;v = v->next){
		if((v==vlook(v->name)) && v->val){
			*ep++=p;
			q = v->name;
			while(*q) *p++=*q++;
			sep='=';
			for(a = v->val;a;a = a->next){
				*p++=sep;
				sep = SEP;
				q = a->word;
				while(*q) *p++=*q++;
			}
			*p++='\0';
		}
		if(v->fn){
			*ep++=p;
			*p++='#'; *p++='('; *p++=')';	/* to fool Bourne */
			*p++='f'; *p++='n'; *p++=' ';
			q = v->name;
			while(*q) *p++=*q++;
			*p++=' ';
			q = v->fn[v->pc-1].s;
			while(*q) *p++=*q++;
			*p++='\0';
		}
	}
	*ep = 0;
	qsort((void *)env, nvar, sizeof ep[0], cmpenv);
	return env;	
}
char *sigmsg[] = {
/*  0 normal  */ 0,
/*  1 SIGHUP  */ "Hangup",
/*  2 SIGINT  */ 0,
/*  3 SIGQUIT */ "Quit",
/*  4 SIGILL  */ "Illegal instruction",
/*  5 SIGTRAP */ "Trace/BPT trap",
/*  6 SIGIOT  */ "abort",
/*  7 SIGEMT  */ "EMT trap",
/*  8 SIGFPE  */ "Floating exception",
/*  9 SIGKILL */ "Killed",
/* 10 SIGBUS  */ "Bus error",
/* 11 SIGSEGV */ "Memory fault",
/* 12 SIGSYS  */ "Bad system call",
/* 13 SIGPIPE */ 0,
/* 14 SIGALRM */ "Alarm call",
/* 15 SIGTERM */ "Terminated",
/* 16 unused  */ "signal 16",
/* 17 SIGSTOP */ "Process stopped",
/* 18 unused  */ "signal 18",
/* 19 SIGCONT */ "Process continued",
/* 20 SIGCHLD */ "Child death",
};

void
Waitfor(int pid, int persist)
{
	int wpid, sig;
	struct thread *p;
	int wstat;
	char wstatstr[12];

	for(;;){
		errno = 0;
		wpid = wait(&wstat);
		if(errno==EINTR && persist)
			continue;
		if(wpid==-1)
			break;
		sig = wstat&0177;
		if(sig==0177){
			pfmt(err, "trace: ");
			sig = (wstat>>8)&0177;
		}
		if(sig>(sizeof sigmsg/sizeof sigmsg[0]) || sigmsg[sig]){
			if(pid!=wpid)
				pfmt(err, "%d: ", wpid);
			if(sig<=(sizeof sigmsg/sizeof sigmsg[0]))
				pfmt(err, "%s", sigmsg[sig]);
			else if(sig==0177) pfmt(err, "stopped by ptrace");
			else pfmt(err, "signal %d", sig);
			if(wstat&0200)pfmt(err, " -- core dumped");
			pfmt(err, "\n");
		}
		wstat = sig?sig+1000:(wstat>>8)&0xFF;
		if(wpid==pid){
			inttoascii(wstatstr, wstat);
			setstatus(wstatstr);
			break;
		}
		else{
			for(p = runq->ret;p;p = p->ret)
				if(p->pid==wpid){
					p->pid=-1;
					inttoascii(p->status, wstat);
					break;
				}
		}
	}
}

char **
mkargv(struct word *a)
{
	char **argv = (char **)emalloc((count(a)+2)*sizeof(char *));
	char **argp = argv+1;	/* leave one at front for runcoms */

	for(;a;a = a->next)
		*argp++=a->word;
	*argp = 0;
	return argv;
}

void
Updenv(void)
{
}

void
Execute(struct word *args, struct word *path)
{
	char *msg="not found";
	int txtbusy = 0;
	char **env = mkenv();
	char **argv = mkargv(args);
	char file[512];

	for(;path;path = path->next){
		strcpy(file, path->word);
		if(file[0])
			strcat(file, "/");
		strcat(file, argv[1]);
ReExec:
		execve(file, argv+1, env);
		switch(errno){
		case ENOEXEC:
			pfmt(err, "%s: Bourne again\n", argv[1]);
			argv[0]="sh";
			argv[1] = strdup(file);
			execve("/bin/sh", argv, env);
			goto Bad;
		case ETXTBSY:
			if(++txtbusy!=5){
				sleep(txtbusy);
				goto ReExec;
			}
			msg="text busy"; goto Bad;
		case EACCES:
			msg="no access";
			break;
		case ENOMEM:
			msg="not enough memory"; goto Bad;
		case E2BIG:
			msg="too big"; goto Bad;
		}
	}
Bad:
	pfmt(err, "%s: %s\n", argv[1], msg);
	efree((char *)env);
	efree((char *)argv);
}

/* posix max path component length */
#ifndef NDIR
#ifdef MAXNAMLEN
#define NDIR MAXNAMLEN
#endif
#endif

/* BSD max path component length */
#ifndef NDIR
#ifdef NAME_MAX
#define NDIR NAME_MAX
#endif
#endif

/* last resort guess of path component length */
#ifndef NDIR	
#define	NDIR	256
#endif

int
Abspath(char *w)
{
	if(strncmp(w, "/", 1)==0)
		return 1;
	if(strncmp(w, "#", 1)==0)
		return 1;
	if(strncmp(w, "./", 2)==0)
		return 1;
	if(strncmp(w, "../", 3)==0)
		return 1;
	return 0;
}

int
Globsize(char *p)
{
	int isglob = 0, globlen = NDIR+1;
	for(;*p;p++){
		if(*p==GLOB){
			p++;
			if(*p!=GLOB)
				isglob++;
			globlen+=*p=='*'?NDIR:1;
		}
		else
			globlen++;
	}
	return isglob?globlen:0;
}

#include <sys/types.h>
#include <dirent.h>

#define	NDIRLIST	50

DIR *dirlist[NDIRLIST];

Opendir(char *name)
{
	DIR **dp;
	for(dp = dirlist;dp!=&dirlist[NDIRLIST];dp++)
		if(*dp==0){
			*dp = opendir(name);
			return *dp?dp-dirlist:-1;
		}
	return -1;
}

int
Readdir(int f, char *p, int onlydirs)
{
	struct dirent *dp = readdir(dirlist[f]);

	if(dp==0)
		return 0;
	strcpy(p, dp->d_name);
	return 1;
}

void
Closedir(int f)
{
	closedir(dirlist[f]);
	dirlist[f] = 0;
}

char *Signame[] = {
	"sigexit",	"sighup",	"sigint",	"sigquit",
	"sigill",	"sigtrap",	"sigiot",	"sigemt",
	"sigfpe",	"sigkill",	"sigbus",	"sigsegv",
	"sigsys",	"sigpipe",	"sigalrm",	"sigterm",
	"sig16",	"sigstop",	"sigtstp",	"sigcont",
	"sigchld",	"sigttin",	"sigttou",	"sigtint",
	"sigxcpu",	"sigxfsz",	"sig26",	"sig27",
	"sig28",	"sig29",	"sig30",	"sig31",
	0,
};

void
gettrap(int sig)
{
	signal(sig, gettrap);
	trap[sig]++;
	ntrap++;
	if(ntrap>=NSIG){
		pfmt(err, "rc: Too many traps (trap %d), dumping core\n", sig);
		signal(SIGABRT, (void (*)())0);
		kill(getpid(), SIGABRT);
	}
}

void
Trapinit(void)
{
	int i;
	void (*sig)();

	if(1 || flag['d']){	/* wrong!!! */
		sig = signal(SIGINT, gettrap);
		if(sig==SIG_IGN)
			signal(SIGINT, SIG_IGN);
	}
	else{
		for(i = 1;i<=NSIG;i++) if(i!=SIGCHLD){
			sig = signal(i, gettrap);
			if(sig==SIG_IGN)
				signal(i, SIG_IGN);
		}
	}
}

Unlink(char *name)
{
	return unlink(name);
}
Write(int fd, char *buf, int cnt)
{
	return write(fd, buf, cnt);
}
Read(int fd, char *buf, int cnt)
{
	return read(fd, buf, cnt);
}
Seek(int fd, long cnt, int whence)
{
	return lseek(fd, cnt, whence);
}
Executable(char *file)
{
	return(access(file, 01)==0);
}
Creat(char *file)
{
	return creat(file, 0666);
}
Dup(int a, int b)
{
	return dup2(a, b);
}
Dup1(int a)
{
	return dup(a);
}
/*
 * Wrong:  should go through components of a|b|c and return the maximum.
 */
void
Exit(char *stat)
{
	int n = 0;

	while(*stat){
		if(*stat!='|'){
			if(*stat<'0' || '9'<*stat)
				exit(1);
			else n = n*10+*stat-'0';
		}
		stat++;
	}
	exit(n);
}
Eintr(void)
{
	return errno==EINTR;
}

void
Noerror(void)
{
	errno = 0;
}
Isatty(fd)
{
	return isatty(fd);
}

void
Abort(void)
{
	abort();
}

void
execumask(void)		/* wrong -- should fork before writing */
{
	int m;
	struct io out[1];
	switch(count(runq->argv->words)){
	default:
		pfmt(err, "Usage: umask [umask]\n");
		setstatus("umask usage");
		poplist();
		return;
	case 2:
		umask(octal(runq->argv->words->next->word));
		break;
	case 1: 
		umask(m = umask(0));
		out->fd = mapfd(1);
		out->bufp = out->buf;
		out->ebuf=&out->buf[NBUF];
		out->strp = 0;
		pfmt(out, "%o\n", m);
		break;
	}
	setstatus("");
	poplist();
}

void
Memcpy(char *a, char *b, int n)
{
	memmove(a, b, n);
}

void*
Malloc(unsigned long n)
{
	return (void *)malloc(n);
}

void
errstr(char *buf, int len)
{
	strncpy(buf, strerror(errno), len);
}

int
needsrcquote(int c)
{
	if(c <= ' ')
		return 1;
	if(strchr("`^#*[]=|\\?${}()'<>&;", c))
		return 1;
	return 0;
}

int
rfork(int bits)
{
	return fork();
}

int *waitpids;
int nwaitpids;

void
addwaitpid(int pid)
{
	waitpids = realloc(waitpids, (nwaitpids+1)*sizeof waitpids[0]);
	if(waitpids == 0)
		panic("Can't realloc %d waitpids", nwaitpids+1);
	waitpids[nwaitpids++] = pid;
}

void
delwaitpid(int pid)
{
	int r, w;
	
	for(r=w=0; r<nwaitpids; r++)
		if(waitpids[r] != pid)
			waitpids[w++] = waitpids[r];
	nwaitpids = w;
}

void
clearwaitpids(void)
{
	nwaitpids = 0;
}

int
havewaitpid(int pid)
{
	int i;

	for(i=0; i<nwaitpids; i++)
		if(waitpids[i] == pid)
			return 1;
	return 0;
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.