189731aad0
Fixup remaining Plan9 dependencies (chartorune()). Add Makefile for UNIX-like systems (tested with Linux and APE). Make error printing consistent, use Errstr() explicitely. Get rid of NSTATUS buffer limit, just malloc it.
421 lines
5.9 KiB
C
421 lines
5.9 KiB
C
/*
|
|
* Unix versions of system-specific functions
|
|
* By convention, exported routines herein have names beginning with an
|
|
* upper case letter.
|
|
*/
|
|
#include "rc.h"
|
|
#include "exec.h"
|
|
#include "io.h"
|
|
#include "fns.h"
|
|
#include "getflags.h"
|
|
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <dirent.h>
|
|
#include <sys/wait.h>
|
|
|
|
static void execfinit(void);
|
|
|
|
builtin Builtin[] = {
|
|
"cd", execcd,
|
|
"whatis", execwhatis,
|
|
"eval", execeval,
|
|
"exec", execexec, /* but with popword first */
|
|
"exit", execexit,
|
|
"shift", execshift,
|
|
"wait", execwait,
|
|
".", execdot,
|
|
"flag", execflag,
|
|
"finit", execfinit,
|
|
0
|
|
};
|
|
|
|
char Rcmain[] = PREFIX "/lib/rcmain";
|
|
char Fdprefix[] = "/dev/fd/";
|
|
|
|
char *Signame[NSIG];
|
|
|
|
#define SEP '\1'
|
|
extern char **environ;
|
|
static char **envp;
|
|
|
|
static void
|
|
Xrdfn(void)
|
|
{
|
|
char *s;
|
|
int len;
|
|
|
|
for(;*envp;envp++){
|
|
for(s=*envp;*s && *s!='(' && *s!='=';s++);
|
|
switch(*s){
|
|
case '(': /* Bourne again */
|
|
if(strncmp(s, "()fn ", 5)!=0)
|
|
continue;
|
|
s=estrdup(s+2);
|
|
len=strlen(s);
|
|
s[len++]='\n';
|
|
envp++;
|
|
runq->pc--; /* re-execute */
|
|
execcmds(openiocore(s, len), estrdup("*environ*"), runq->local, runq->redir);
|
|
runq->lex->qflag = 1;
|
|
return;
|
|
default:
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
execfinit(void)
|
|
{
|
|
static union code rdfns[5];
|
|
if(rdfns[0].i==0){
|
|
rdfns[0].i = 1;
|
|
rdfns[1].s = "*rdfns*";
|
|
rdfns[2].f = Xrdfn;
|
|
rdfns[3].f = Xreturn;
|
|
rdfns[4].f = 0;
|
|
}
|
|
poplist();
|
|
envp=environ;
|
|
start(rdfns, 2, runq->local, runq->redir);
|
|
}
|
|
|
|
static int
|
|
cmpenv(const void *aa, const void *ab)
|
|
{
|
|
return strcmp(*(char**)aa, *(char**)ab);
|
|
}
|
|
|
|
static 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;
|
|
}
|
|
|
|
static word*
|
|
envval(char *s)
|
|
{
|
|
char *t, c;
|
|
word *v;
|
|
for(t=s;*t&&*t!=SEP;t++);
|
|
c=*t;
|
|
*t='\0';
|
|
v=newword(s, c=='\0'?(word*)0:envval(t+1));
|
|
*t=c;
|
|
return v;
|
|
}
|
|
|
|
void
|
|
Vinit(void)
|
|
{
|
|
char *s;
|
|
|
|
for(envp=environ;*envp;envp++){
|
|
for(s=*envp;*s && *s!='(' && *s!='=';s++);
|
|
switch(*s){
|
|
case '=':
|
|
*s='\0';
|
|
setvar(*envp, envval(s+1));
|
|
*s='=';
|
|
break;
|
|
default: continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
sighandler(int sig)
|
|
{
|
|
trap[sig]++;
|
|
ntrap++;
|
|
}
|
|
|
|
void
|
|
Trapinit(void)
|
|
{
|
|
int i;
|
|
|
|
Signame[0] = "sigexit";
|
|
|
|
#ifdef SIGINT
|
|
Signame[SIGINT] = "sigint";
|
|
#endif
|
|
#ifdef SIGTERM
|
|
Signame[SIGTERM] = "sigterm";
|
|
#endif
|
|
#ifdef SIGHUP
|
|
Signame[SIGHUP] = "sighup";
|
|
#endif
|
|
#ifdef SIGQUIT
|
|
Signame[SIGQUIT] = "sigquit";
|
|
#endif
|
|
#ifdef SIGPIPE
|
|
Signame[SIGPIPE] = "sigpipe";
|
|
#endif
|
|
#ifdef SIGUSR1
|
|
Signame[SIGUSR1] = "sigusr1";
|
|
#endif
|
|
#ifdef SIGUSR2
|
|
Signame[SIGUSR2] = "sigusr2";
|
|
#endif
|
|
#ifdef SIGBUS
|
|
Signame[SIGBUS] = "sigbus";
|
|
#endif
|
|
#ifdef SIGWINCH
|
|
Signame[SIGWINCH] = "sigwinch";
|
|
#endif
|
|
|
|
for(i=1; i<NSIG; i++) if(Signame[i]){
|
|
#ifdef SA_RESTART
|
|
struct sigaction a;
|
|
|
|
sigaction(i, NULL, &a);
|
|
a.sa_flags &= ~SA_RESTART;
|
|
a.sa_handler = sighandler;
|
|
sigaction(i, &a, NULL);
|
|
#else
|
|
signal(i, sighandler);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
char*
|
|
Errstr(void)
|
|
{
|
|
return strerror(errno);
|
|
}
|
|
|
|
int
|
|
Waitfor(int pid)
|
|
{
|
|
thread *p;
|
|
char num[12];
|
|
int wpid, status;
|
|
|
|
if(pid >= 0 && !havewaitpid(pid))
|
|
return 0;
|
|
while((wpid = wait(&status))!=-1){
|
|
delwaitpid(wpid);
|
|
inttoascii(num, WIFSIGNALED(status)?WTERMSIG(status)+1000:WEXITSTATUS(status));
|
|
if(wpid==pid){
|
|
setstatus(num);
|
|
return 0;
|
|
}
|
|
for(p = runq->ret;p;p = p->ret)
|
|
if(p->pid==wpid){
|
|
p->pid=-1;
|
|
p->status = estrdup(num);
|
|
break;
|
|
}
|
|
}
|
|
if(Eintr()) return -1;
|
|
return 0;
|
|
}
|
|
|
|
static char **nextenv;
|
|
|
|
void
|
|
Updenv(void)
|
|
{
|
|
if(nextenv){
|
|
free(nextenv);
|
|
nextenv = NULL;
|
|
}
|
|
if(err)
|
|
flushio(err);
|
|
}
|
|
|
|
void
|
|
Exec(char **argv)
|
|
{
|
|
if(nextenv==NULL) nextenv=mkenv();
|
|
execve(argv[0], argv+1, nextenv);
|
|
}
|
|
|
|
int
|
|
Fork(void)
|
|
{
|
|
Updenv();
|
|
return fork();
|
|
}
|
|
|
|
void*
|
|
Opendir(char *name)
|
|
{
|
|
return opendir(name);
|
|
}
|
|
|
|
char*
|
|
Readdir(void *arg, int onlydirs)
|
|
{
|
|
DIR *rd = arg;
|
|
struct dirent *ent = readdir(rd);
|
|
if(ent == NULL)
|
|
return 0;
|
|
return ent->d_name;
|
|
}
|
|
|
|
void
|
|
Closedir(void *arg)
|
|
{
|
|
DIR *rd = arg;
|
|
closedir(rd);
|
|
}
|
|
|
|
long
|
|
Write(int fd, void *buf, long cnt)
|
|
{
|
|
return write(fd, buf, cnt);
|
|
}
|
|
|
|
long
|
|
Read(int fd, void *buf, long cnt)
|
|
{
|
|
return read(fd, buf, cnt);
|
|
}
|
|
|
|
long
|
|
Seek(int fd, long cnt, long whence)
|
|
{
|
|
return lseek(fd, cnt, whence);
|
|
}
|
|
|
|
int
|
|
Executable(char *file)
|
|
{
|
|
return access(file, 01)==0;
|
|
}
|
|
|
|
int
|
|
Open(char *file, int mode)
|
|
{
|
|
static int tab[] = {O_RDONLY,O_WRONLY,O_RDWR,O_RDONLY};
|
|
int fd = open(file, tab[mode&3]);
|
|
if(fd >= 0 && mode == 3)
|
|
unlink(file);
|
|
return fd;
|
|
}
|
|
|
|
void
|
|
Close(int fd)
|
|
{
|
|
close(fd);
|
|
}
|
|
|
|
int
|
|
Creat(char *file)
|
|
{
|
|
return creat(file, 0666L);
|
|
}
|
|
|
|
int
|
|
Dup(int a, int b)
|
|
{
|
|
return dup2(a, b);
|
|
}
|
|
|
|
int
|
|
Dup1(int a)
|
|
{
|
|
return dup(a);
|
|
}
|
|
|
|
void
|
|
Exit(void)
|
|
{
|
|
Updenv();
|
|
exit(truestatus()?0:1);
|
|
}
|
|
|
|
int
|
|
Eintr(void)
|
|
{
|
|
return errno==EINTR;
|
|
}
|
|
|
|
void
|
|
Noerror(void)
|
|
{
|
|
errno=0;
|
|
}
|
|
|
|
int
|
|
Isatty(int fd)
|
|
{
|
|
return isatty(fd);
|
|
}
|
|
|
|
void
|
|
Abort(void)
|
|
{
|
|
abort();
|
|
}
|
|
|
|
int
|
|
Chdir(char *dir)
|
|
{
|
|
return chdir(dir);
|
|
}
|
|
|
|
void
|
|
Prompt(char *s)
|
|
{
|
|
pstr(err, s);
|
|
flushio(err);
|
|
}
|