/*
* 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;
}
|