From 2ade60747db41771498ab2b85ce6e3c3389f2c26 Mon Sep 17 00:00:00 2001 From: Nicholas Noll Date: Wed, 13 Oct 2021 09:08:59 -0700 Subject: feat(rc): added unix port of rc with linenoise --- sys/cmd/rc/unix.c | 627 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 627 insertions(+) create mode 100644 sys/cmd/rc/unix.c (limited to 'sys/cmd/rc/unix.c') diff --git a/sys/cmd/rc/unix.c b/sys/cmd/rc/unix.c new file mode 100644 index 0000000..32a744f --- /dev/null +++ b/sys/cmd/rc/unix.c @@ -0,0 +1,627 @@ +/* + * Unix versions of system-specific functions + * By convention, exported routines herein have names beginning with an + * upper case letter. + */ +#include "rc.h" +#include "fns.h" +#include "io.h" +#include "exec.h" +#include "getflags.h" +#include +#include +#include +#include +#include +#include +#include + +char *Rcmain = "/home/nolln/root/sys/cmd/rc/rcmain.unix"; +char *Fdprefix = "/dev/fd/"; + +void execfinit(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, + /* "history", exechistory, */ + 0 +}; +#define SEP '\1' +char **environp; + +struct word* +enval(register 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); +} + +int +cmpenv(const void *aa, const void *ab) +{ + char **a = (char**)aa, **b = (char**)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", +}; + +int +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; + } + } + } + return 0; +} + +char ** +mkargv(register 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); +} + +#define NDIR NAME_MAX + +int +Globsize(register 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; +} + +#define NDIRLIST 50 + +DIR *dirlist[NDIRLIST]; + +int +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; + + if(f<0 || f>=NDIRLIST) + return 0; + + dp = readdir(dirlist[f]); + if(dp==0) + return 0; + strcpy(p, dp->d_name); + return 1; +} + +void +Closedir(int f) +{ + if(f<0 || f>=NDIRLIST) + return; + + 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); + } + } +} + +void +Unlink(char *name) +{ + unlink(name); +} + +long +Write(int fd, char *buf, long cnt) +{ + return write(fd, buf, cnt); +} + +long +Read(int fd, char *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 +Creat(char *file) +{ + return creat(file, 0666); +} + +int +Dup(int a, int b){ + return dup2(a, b); +} + +int +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); +} + +int +Eintr(void){ + return errno==EINTR; +} + +void +Noerror(void) +{ + errno = 0; +} + +int +Isatty(int 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, long 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