ref: 46b0c36526f6004ba57adf9fe675313bae870836
parent: 271a7db1cd9afb4cf841101188199c3a0d0f4c62
author: halfwit <michaelmisch1985@gmail.com>
date: Mon Feb 26 18:31:45 PST 2024
rc now builds fairly unchanged from upstream
--- a/Makefile
+++ b/Makefile
@@ -26,7 +26,7 @@
libip/libip.a\
# stupid gcc
-LIBS=$(LIBS1) $(LIBS1) $(LIBS1) libmachdep.a
+LIBS=$(LIBS1) libmachdep.a
default: $(TARG)
$(TARG): $(OFILES) $(LIBS)
--- a/TODO
+++ b/TODO
@@ -1,40 +1,44 @@
NOTES:
-Some builtins will be required **TEST**
+Some commands we will need to add as builtins to rc
- 'mount'
- - 'bind'
- - 'auth/factotum'
- - 'auth/secstore'
+ - 'bind', might need a device driver or header-exposed syscall See how bind (2) is coded
+ - 'unmount'
- 'ns'
- - Can run a command or interactive shell
- - The profile is ran (!!!)
TODO:
- - [ ] have it export a var $service=unix or $service=windows
+ - [ ] Install rcmain properly on system, refer to it as needed
+ - [ ] have it export a var service=unix
- [ ] Some people probably want aan?
- - [ ] Move rc code to use our libc.h, u.h everywhere so our defs of open + such are correct
+ - [x] Move rc code to use our libc.h, u.h everywhere so our defs of open + such are correct
- [ ] gui-cocoa try to capture the windows we create so we can send mouse/keyboard to it, plist for launchd
- [ ] gui-wl cannibalize the wayland shims
- - [ ] handle notes and signals
- - [x] Remove listen1 outright, it's messing everything up.
- - [x] tlssrv, but use internal factotum bits
- [ ] create namespaces with our bind/mount and allow report via ns(1)
- [ ] define the gui interface
- - [ ] Makefile librc --> librc.a
- - [ ] move much of io.c and exec.c into our cpu space
- - It looks like it's mostly broken out into unix.c/plan9.c to where the defs we'd want are and builtins
- - Could pull in exec.c into the cpu scope instead of where it is, provide pieces into the library or abstracted out? Unsure.
+ - [x] Makefile librc --> librc.a
+ - [x] libc.h getwd plan9port/src/lib9/getwd.c
+ - [x] libc.h dirread /sys/src/libc/9sys/dirread.c
+ - [x] libc.h notify plan9port/src/lib9/notify.c
+ - [x] libc.h postnote plan9port/src/lib9/postnote.c
+ - [x] libc.h await plan9port/src/lib9/await.c
+ - [x] libc.h rfork plan9port/src/lib9/rfork.c
+ - [x] libc.h wait plan9port/src/lib9/wait.c
+ - [x] libc.h time plan9port/src/lib9/time.c
+ - [ ] RFREND + RFNOMEM could probably be handled
Kernel space needs:
- - devdraw, devkbd, devmouse, devaudio - wrong side
- - devcmd - we'll need more insight as to what this really does
- - devcons - needed, console
- - devenv - needed, env vars
- - devfs - needed, local files
- - devip - needed, networking
- - devlfd - I am unsure
- - devmnt - needed, client shares
- - devpipe - probably needed for any pipe
- - devroot - needed, base of stack
- - devssl - needed, ssl
- - devtab - meta, needed
- - devtls - needed! probably before connection even happens, though it may be odd scoping there, we may just need to bind it up just after the accept
+ - devdraw - #i: !needed, We use the client exported /dev/draw instead
+ - devkbd - #b: !needed, We use the client exported /dev/kbd instead
+ - devmouse - #m: !needed, We use the client exported /dev/mouse instead
+ - devaudio - #A: !needed, We use the client exported /dev/audio instead
+ - devcmd - #C: needed OS(1) commands *outside* namespace
+ - devcons - #c: needed, /dev/cons
+ - devenv - #e: needed, /dev/env
+ - devfs - #U: needed, local files
+ - devip - #I: !needed, networking
+ - devlfd - #L: !needed
+ - devmnt - #M: needed, client shares
+ - devpipe - #|: !needed for pipe in rc
+ - devroot - #/: needed, base of stack
+ - devssl - #D: !needed, ssl
+ - devtls - #a: !needed, tls
+ - devtab - meta, needed - add/remove any devices that we add/remove, from here as well
binary files /dev/null b/drawcpu differ
--- a/include/lib.h
+++ b/include/lib.h
@@ -66,6 +66,31 @@
};
/*
+ * one-of-a-kind
+ */
+enum
+{
+ PNPROC = 1,
+ PNGROUP = 2,
+};
+
+enum
+{
+ RFNAMEG = (1<<0),
+ RFENVG = (1<<1),
+ RFFDG = (1<<2),
+ RFNOTEG = (1<<3),
+ RFPROC = (1<<4),
+ RFMEM = (1<<5),
+ RFNOWAIT = (1<<6),
+ RFCNAMEG = (1<<10),
+ RFCENVG = (1<<11),
+ RFCFDG = (1<<12),
+ /*RFREND - (1<<13),*/
+ /*RFNOMNT = (1<<14),*/
+};
+
+/*
* new rune routines
*/
extern int runetochar(char*, Rune*);
@@ -155,6 +180,9 @@
uchar type;
} Qid;
+#define STATMAX 65535U /* max length of machine-independent stat structure */
+#define DIRMAX (sizeof(Dir)+STATMAX) /* max length of Dir structure */
+
typedef
struct Dir {
/* system-modified data */
@@ -176,7 +204,7 @@
struct Waitmsg
{
int pid; /* of loved one */
- ulong time[3]; /* of loved one & descendants */
+ ulong dur[3]; /* of loved one & descendants */
char *msg;
} Waitmsg;
--- a/include/user.h
+++ b/include/user.h
@@ -3,8 +3,10 @@
#define chdir syschdir
#define close sysclose
#define create syscreate
-#define dup sysdup
+#define dup sysdup
#define export sysexport
+#define getwd sysgetwd
+#define fd2path sysfd2path
#define fstat sysfstat
#define fwstat sysfwstat
#define mount sysmount
@@ -11,8 +13,10 @@
#define open sysopen
#define read sysread
#define remove sysremove
+#define rfork sysrfork
#define seek sysseek
#define stat sysstat
+#define wait syswait
#define write syswrite
#define wstat syswstat
#define unmount sysunmount
@@ -34,8 +38,10 @@
extern int create(char*, int, ulong);
extern int dup(int, int);
extern int export(int);
+extern int fd2path(int, char*, int);
extern int fstat(int, uchar*, int);
extern int fwstat(int, uchar*, int);
+extern char* getwd(char *, int);
extern int mount(int, int, char*, int, char*);
extern int unmount(char*, char*);
extern int open(char*, int);
@@ -43,17 +49,19 @@
extern long read(int, void*, long);
extern long readn(int, void*, long);
extern int remove(char*);
+extern int rfork(int);
extern vlong seek(int, vlong, int);
extern int stat(char*, uchar*, int);
+extern long time(long*);
extern long write(int, void*, long);
extern int wstat(char*, uchar*, int);
extern void werrstr(char* ,...);
-
+extern Waitmsg* wait(void);
extern Dir *dirstat(char*);
extern Dir *dirfstat(int);
extern int dirwstat(char*, Dir*);
extern int dirfwstat(int, Dir*);
-extern long dirread(int, Dir*, long);
+extern long dirread(int, Dir**);
extern ulong iounit(int);
extern int lfdfd(int);
@@ -87,6 +95,8 @@
extern int errstr(char*, uint);
extern char *estrdup(char*);
extern int rerrstr(char*, uint);
+extern int notify(void (*)(void*, char*));
+extern int noted(int);
extern int encrypt(void*, void*, int);
extern int decrypt(void*, void*, int);
extern void qlock(QLock*);
@@ -100,5 +110,8 @@
extern void exits(char*);
extern char* getenv(char*);
+extern int await(char*, int);
+extern int awaitnohang(char*, int);
+extern int awaitfor(int, char*, int);
#define IOUNIT 32768 /* default buffer size for 9p io */
--- a/kern/Makefile
+++ b/kern/Makefile
@@ -5,6 +5,7 @@
OFILES=\
alloc.$O\
allocb.$O\
+ await.$O\
chan.$O\
data.$O\
dev.$O\
@@ -26,17 +27,24 @@
devssl.$O\
devtls.$O\
devtab.$O\
+ dirread.$O\
error.$O\
+ getwd.$O\
parse.$O\
pgrp.$O\
+ postnote.$O\
procinit.$O\
+ notify.$O\
+ rfork.$O\
rwlock.$O\
sleep.$O\
stub.$O\
sysfile.$O\
+ time.$O\
qio.$O\
qlock.$O\
term.$O\
+ wait.$O\
waserror.$O\
$(OS).$O
--- /dev/null
+++ b/kern/await.c
@@ -1,0 +1,136 @@
+
+#include <u.h>
+#include <libc.h>
+
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#ifndef WCOREDUMP /* not on Mac OS X Tiger */
+#define WCOREDUMP(status) 0
+#endif
+
+static struct {
+ int sig;
+ char *str;
+} tab[] = {
+ SIGHUP, "hangup",
+ SIGINT, "interrupt",
+ SIGQUIT, "quit",
+ SIGILL, "sys: illegal instruction",
+ SIGTRAP, "sys: breakpoint",
+ SIGABRT, "sys: abort",
+#ifdef SIGEMT
+ SIGEMT, "sys: emulate instruction executed",
+#endif
+ SIGFPE, "sys: fp: trap",
+ SIGKILL, "sys: kill",
+ SIGBUS, "sys: bus error",
+ SIGSEGV, "sys: segmentation violation",
+ SIGALRM, "alarm",
+ SIGTERM, "kill",
+ SIGURG, "sys: urgent condition on socket",
+ SIGSTOP, "sys: stop",
+ SIGTSTP, "sys: tstp",
+ SIGCONT, "sys: cont",
+ SIGCHLD, "sys: child",
+ SIGTTIN, "sys: ttin",
+ SIGTTOU, "sys: ttou",
+#ifdef SIGIO /* not on Mac OS X Tiger */
+ SIGIO, "sys: i/o possible on fd",
+#endif
+ SIGXCPU, "sys: cpu time limit exceeded",
+ SIGXFSZ, "sys: file size limit exceeded",
+ SIGVTALRM, "sys: virtual time alarm",
+ SIGPROF, "sys: profiling timer alarm",
+#ifdef SIGWINCH /* not on Mac OS X Tiger */
+ SIGWINCH, "sys: window size change",
+#endif
+#ifdef SIGINFO
+ SIGINFO, "sys: status request",
+#endif
+ SIGUSR1, "sys: usr1",
+ SIGUSR2, "sys: usr2",
+ SIGPIPE, "sys: write on closed pipe",
+};
+
+char*
+_p9sigstr(int sig, char *tmp)
+{
+ int i;
+
+ for(i=0; i<nelem(tab); i++)
+ if(tab[i].sig == sig)
+ return tab[i].str;
+ if(tmp == nil)
+ return nil;
+ sprint(tmp, "sys: signal %d", sig);
+ return tmp;
+}
+
+int
+_p9strsig(char *s)
+{
+ int i;
+
+ for(i=0; i<nelem(tab); i++)
+ if(strcmp(s, tab[i].str) == 0)
+ return tab[i].sig;
+ return 0;
+}
+
+static int
+_await(int pid4, char *str, int n, int opt)
+{
+ int pid, status, cd;
+ struct rusage ru;
+ char buf[128], tmp[64];
+ ulong u, s;
+
+ for(;;){
+ /* On Linux, pid==-1 means anyone; on SunOS, it's pid==0. */
+ if(pid4 == -1)
+ pid = wait3(&status, opt, &ru);
+ else
+ pid = wait4(pid4, &status, opt, &ru);
+ if(pid <= 0)
+ return -1;
+ u = ru.ru_utime.tv_sec*1000+((ru.ru_utime.tv_usec+500)/1000);
+ s = ru.ru_stime.tv_sec*1000+((ru.ru_stime.tv_usec+500)/1000);
+ if(WIFEXITED(status)){
+ status = WEXITSTATUS(status);
+ if(status)
+ snprint(buf, sizeof buf, "%d %lud %lud %lud %d", pid, u, s, u+s, status);
+ else
+ snprint(buf, sizeof buf, "%d %lud %lud %lud ''", pid, u, s, u+s, status);
+ strecpy(str, str+n, buf);
+ return strlen(str);
+ }
+ if(WIFSIGNALED(status)){
+ cd = WCOREDUMP(status);
+ snprint(buf, sizeof buf, "%d %lud %lud %lud 'signal: %s%s'", pid, u, s, u+s, _p9sigstr(WTERMSIG(status), tmp), cd ? " (core dumped)" : "");
+ strecpy(str, str+n, buf);
+ return strlen(str);
+ }
+ }
+}
+
+int
+await(char *str, int n)
+{
+ return _await(-1, str, n, 0);
+}
+
+int
+awaitnohang(char *str, int n)
+{
+ return _await(-1, str, n, WNOHANG);
+}
+
+int
+awaitfor(int pid, char *str, int n)
+{
+ return _await(pid, str, n, 0);
+}
--- /dev/null
+++ b/kern/dirread.c
@@ -1,0 +1,92 @@
+#include <u.h>
+#include <libc.h>
+#include <fcall.h>
+
+static
+long
+dirpackage(uchar *buf, long ts, Dir **d)
+{
+ char *s;
+ long i, n, nn, m;
+
+ /*
+ * first find number of all stats, check they look like stats, & size all associated strings
+ */
+ n = 0;
+ for(i = 0; i < ts; i += m){
+ if(i+BIT16SZ >= ts)
+ return -1;
+ m = BIT16SZ + GBIT16(&buf[i]);
+ if(i+m > ts || statcheck(&buf[i], m) < 0)
+ return -1;
+ n++;
+ }
+
+ *d = malloc(n * sizeof(Dir) + ts);
+ if(*d == nil)
+ return -1;
+
+ /*
+ * then convert all buffers
+ */
+ s = (char*)*d + n * sizeof(Dir);
+ nn = 0;
+ for(i = 0; i < ts; i += m){
+ m = BIT16SZ + GBIT16(&buf[i]);
+ if(i+m > ts || nn >= n || convM2D(&buf[i], m, *d + nn, s) != m){
+ free(*d);
+ *d = nil;
+ return -1;
+ }
+ nn++;
+ s += m;
+ }
+
+ return nn;
+}
+
+long
+dirread(int fd, Dir **d)
+{
+ uchar *buf;
+ long ts;
+
+ *d = nil;
+ buf = malloc(DIRMAX);
+ if(buf == nil)
+ return -1;
+ ts = read(fd, buf, DIRMAX);
+ if(ts > 0)
+ ts = dirpackage(buf, ts, d);
+ free(buf);
+ return ts;
+}
+
+long
+dirreadall(int fd, Dir **d)
+{
+ uchar *buf, *nbuf;
+ long n, ts;
+
+ *d = nil;
+ buf = nil;
+ ts = 0;
+ for(;;){
+ nbuf = realloc(buf, ts+DIRMAX);
+ if(nbuf == nil){
+ free(buf);
+ return -1;
+ }
+ buf = nbuf;
+ n = read(fd, buf+ts, DIRMAX);
+ if(n <= 0)
+ break;
+ ts += n;
+ }
+ if(ts > 0)
+ ts = dirpackage(buf, ts, d);
+ free(buf);
+ if(ts == 0 && n < 0)
+ return -1;
+ return ts;
+}
\ No newline at end of file
--- /dev/null
+++ b/kern/getwd.c
@@ -1,0 +1,10 @@
+#include <u.h>
+#include <libc.h>
+
+#undef getwd
+
+char*
+sysgetwd(char *s, int ns)
+{
+ return getcwd(s, ns);
+}
--- /dev/null
+++ b/kern/notify.c
@@ -1,0 +1,268 @@
+/*
+ * Signal handling for Plan 9 programs.
+ * We stubbornly use the strings from Plan 9 instead
+ * of the enumerated Unix constants.
+ * There are some weird translations. In particular,
+ * a "kill" note is the same as SIGTERM in Unix.
+ * There is no equivalent note to Unix's SIGKILL, since
+ * it's not a deliverable signal anyway.
+ *
+ * We do not handle SIGABRT or SIGSEGV, mainly because
+ * the thread library queues its notes for later, and we want
+ * to dump core with the state at time of delivery.
+ *
+ * We have to add some extra entry points to provide the
+ * ability to tweak which signals are deliverable and which
+ * are acted upon. Notifydisable and notifyenable play with
+ * the process signal mask. Notifyignore enables the signal
+ * but will not call notifyf when it comes in. This is occasionally
+ * useful.
+ */
+
+#include <u.h>
+#include <signal.h>
+#include <libc.h>
+
+extern char *_p9sigstr(int, char*);
+extern int _p9strsig(char*);
+
+typedef struct Sig Sig;
+struct Sig
+{
+ int sig; /* signal number */
+ int flags;
+};
+
+enum
+{
+ Restart = 1<<0,
+ Ignore = 1<<1,
+ NoNotify = 1<<2,
+};
+
+static Sig sigs[] = {
+ SIGHUP, 0,
+ SIGINT, 0,
+ SIGQUIT, 0,
+ SIGILL, 0,
+ SIGTRAP, 0,
+/* SIGABRT, 0, */
+#ifdef SIGEMT
+ SIGEMT, 0,
+#endif
+ SIGFPE, 0,
+ SIGBUS, 0,
+/* SIGSEGV, 0, */
+ SIGCHLD, Restart|Ignore,
+ SIGSYS, 0,
+ SIGPIPE, Ignore,
+ SIGALRM, 0,
+ SIGTERM, 0,
+ SIGTSTP, Restart|Ignore|NoNotify,
+/* SIGTTIN, Restart|Ignore, */
+/* SIGTTOU, Restart|Ignore, */
+ SIGXCPU, 0,
+ SIGXFSZ, 0,
+ SIGVTALRM, 0,
+ SIGUSR1, 0,
+ SIGUSR2, 0,
+#ifdef SIGWINCH
+ SIGWINCH, Restart|Ignore|NoNotify,
+#endif
+#ifdef SIGINFO
+ SIGINFO, Restart|Ignore|NoNotify,
+#endif
+};
+
+static Sig*
+findsig(int s)
+{
+ int i;
+
+ for(i=0; i<nelem(sigs); i++)
+ if(sigs[i].sig == s)
+ return &sigs[i];
+ return nil;
+}
+
+// for now
+typedef long p9jmp_buf[sizeof(sigjmp_buf)/(sizeof(long))];
+typedef struct Jmp Jmp;
+struct Jmp
+{
+ p9jmp_buf b;
+};
+
+static Jmp onejmp;
+
+static Jmp*
+getonejmp(void)
+{
+ return &onejmp;
+}
+
+Jmp *(*_notejmpbuf)(void) = getonejmp;
+static void noteinit(void);
+
+/*
+ * Actual signal handler.
+ */
+
+static void (*notifyf)(void*, char*); /* Plan 9 handler */
+
+static void
+signotify(int sig)
+{
+ char tmp[64];
+ Jmp *j;
+ Sig *s;
+
+ j = (*_notejmpbuf)();
+ switch(sigsetjmp((void*)j->b, 1)){
+ case 0:
+ if(notifyf)
+ // probaby not p9sigstr
+ (*notifyf)(nil, _p9sigstr(sig, tmp));
+ /* fall through */
+ case 1: /* noted(NDFLT) */
+ if(0)print("DEFAULT %d\n", sig);
+ s = findsig(sig);
+ if(s && (s->flags&Ignore))
+ return;
+ signal(sig, SIG_DFL);
+ raise(sig);
+ _exit(1);
+ case 2: /* noted(NCONT) */
+ if(0)print("HANDLED %d\n", sig);
+ return;
+ }
+}
+
+static void
+signonotify(int sig)
+{
+ USED(sig);
+}
+
+int
+noted(int v)
+{
+ siglongjmp((*_notejmpbuf)()->b, v==NCONT ? 2 : 1);
+ abort();
+ return 0;
+}
+
+int
+notify(void (*f)(void*, char*))
+{
+ static int init;
+
+ notifyf = f;
+ if(!init){
+ init = 1;
+ noteinit();
+ }
+ return 0;
+}
+
+/*
+ * Nonsense about enabling and disabling signals.
+ */
+typedef void Sighandler(int);
+static Sighandler*
+handler(int s)
+{
+ struct sigaction sa;
+
+ sigaction(s, nil, &sa);
+ return sa.sa_handler;
+}
+
+static int
+notesetenable(int sig, int enabled)
+{
+ sigset_t mask, omask;
+
+ if(sig == 0)
+ return -1;
+
+ sigemptyset(&mask);
+ sigaddset(&mask, sig);
+ sigprocmask(enabled ? SIG_UNBLOCK : SIG_BLOCK, &mask, &omask);
+ return !sigismember(&omask, sig);
+}
+
+int
+noteenable(char *msg)
+{
+ return notesetenable(_p9strsig(msg), 1);
+}
+
+int
+notedisable(char *msg)
+{
+ return notesetenable(_p9strsig(msg), 0);
+}
+
+static int
+notifyseton(int s, int on)
+{
+ Sig *sig;
+ struct sigaction sa, osa;
+
+ sig = findsig(s);
+ if(sig == nil)
+ return -1;
+ memset(&sa, 0, sizeof sa);
+ sa.sa_handler = on ? signotify : signonotify;
+ if(sig->flags&Restart)
+ sa.sa_flags |= SA_RESTART;
+
+ /*
+ * We can't allow signals within signals because there's
+ * only one jump buffer.
+ */
+ sigfillset(&sa.sa_mask);
+
+ /*
+ * Install handler.
+ */
+ sigaction(sig->sig, &sa, &osa);
+ return osa.sa_handler == signotify;
+}
+
+int
+notifyon(char *msg)
+{
+ return notifyseton(_p9strsig(msg), 1);
+}
+
+int
+notifyoff(char *msg)
+{
+ return notifyseton(_p9strsig(msg), 0);
+}
+
+/*
+ * Initialization follows sigs table.
+ */
+static void
+noteinit(void)
+{
+ int i;
+ Sig *sig;
+
+ for(i=0; i<nelem(sigs); i++){
+ sig = &sigs[i];
+ /*
+ * If someone has already installed a handler,
+ * It's probably some ld preload nonsense,
+ * like pct (a SIGVTALRM-based profiler).
+ * Or maybe someone has already called notifyon/notifyoff.
+ * Leave it alone.
+ */
+ if(handler(sig->sig) != SIG_DFL)
+ continue;
+ notifyseton(sig->sig, !(sig->flags&NoNotify));
+ }
+}
--- /dev/null
+++ b/kern/postnote.c
@@ -1,0 +1,35 @@
+#include <u.h>
+#include <libc.h>
+
+#include <signal.h>
+
+extern int _p9strsig(char*);
+
+int
+postnote(int who, int pid, char *msg)
+{
+ int sig;
+
+ sig = _p9strsig(msg);
+ if(sig == 0){
+ werrstr("unknown note");
+ return -1;
+ }
+
+ if(pid <= 0){
+ werrstr("bad pid in postnote");
+ return -1;
+ }
+
+ switch(who){
+ default:
+ werrstr("bad who in postnote");
+ return -1;
+ case PNPROC:
+ return kill(pid, sig);
+ case PNGROUP:
+ if((pid = getpgid(pid)) < 0)
+ return -1;
+ return killpg(pid, sig);
+ }
+}
--- /dev/null
+++ b/kern/rfork.c
@@ -1,0 +1,127 @@
+#include <u.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <libc.h>
+#undef rfork
+
+static void
+nop(int x)
+{
+ USED(x);
+}
+
+int
+sysrfork(int flags)
+{
+ int pid, status;
+ int p[2];
+ int n;
+ char buf[128], *q;
+ extern char **environ;
+ struct sigaction oldchld;
+
+ memset(&oldchld, 0, sizeof oldchld);
+
+ if((flags&(RFPROC|RFFDG|RFMEM)) == (RFPROC|RFFDG)){
+ /* check other flags before we commit */
+ flags &= ~(RFPROC|RFFDG|RFENVG);
+ n = (flags & ~(RFNOTEG|RFNAMEG|RFNOWAIT|RFCENVG));
+ if(n){
+ werrstr("unknown flags %08ux in rfork", n);
+ return -1;
+ }
+ if(flags&RFNOWAIT){
+ sigaction(SIGCHLD, nil, &oldchld);
+ signal(SIGCHLD, nop);
+ if(pipe(p) < 0)
+ return -1;
+ }
+ pid = fork();
+ if(pid == -1)
+ return -1;
+ if(flags&RFNOWAIT){
+ flags &= ~RFNOWAIT;
+ if(pid){
+ /*
+ * Parent - wait for child to fork wait-free child.
+ * Then read pid from pipe. Assume pipe buffer can absorb the write.
+ */
+ close(p[1]);
+ status = 0;
+ if(wait4(pid, &status, 0, 0) < 0){
+ werrstr("pipe dance - wait4 - %r");
+ close(p[0]);
+ return -1;
+ }
+ n = readn(p[0], buf, sizeof buf-1);
+ close(p[0]);
+ if(!WIFEXITED(status) || WEXITSTATUS(status)!=0 || n <= 0){
+ if(!WIFEXITED(status))
+ werrstr("pipe dance - !exited 0x%ux", status);
+ else if(WEXITSTATUS(status) != 0)
+ werrstr("pipe dance - non-zero status 0x%ux", status);
+ else if(n < 0)
+ werrstr("pipe dance - pipe read error - %r");
+ else if(n == 0)
+ werrstr("pipe dance - pipe read eof");
+ else
+ werrstr("pipe dance - unknown failure");
+ return -1;
+ }
+ buf[n] = 0;
+ if(buf[0] == 'x'){
+ werrstr("%s", buf+2);
+ return -1;
+ }
+ pid = strtol(buf, &q, 0);
+ }else{
+ /*
+ * Child - fork a new child whose wait message can't
+ * get back to the parent because we're going to exit!
+ */
+ signal(SIGCHLD, SIG_IGN);
+ close(p[0]);
+ pid = fork();
+ if(pid){
+ /* Child parent - send status over pipe and exit. */
+ if(pid > 0)
+ fprint(p[1], "%d", pid);
+ else
+ fprint(p[1], "x %r");
+ close(p[1]);
+ _exit(0);
+ }else{
+ /* Child child - close pipe. */
+ close(p[1]);
+ }
+ }
+ sigaction(SIGCHLD, &oldchld, nil);
+ }
+ if(pid != 0)
+ return pid;
+ if(flags&RFCENVG)
+ if(environ)
+ *environ = nil;
+ }
+ if(flags&RFPROC){
+ werrstr("cannot use rfork for shared memory -- use libthread");
+ return -1;
+ }
+ if(flags&RFNAMEG){
+ /* XXX set $NAMESPACE to a new directory */
+ flags &= ~RFNAMEG;
+ }
+ if(flags&RFNOTEG){
+ setpgid(0, getpid());
+ flags &= ~RFNOTEG;
+ }
+ if(flags&RFNOWAIT){
+ werrstr("cannot use RFNOWAIT without RFPROC");
+ return -1;
+ }
+ if(flags){
+ werrstr("unknown flags %08ux in rfork", flags);
+ return -1;
+ }
+ return 0;
+}
--- a/kern/sysfile.c
+++ b/kern/sysfile.c
@@ -8,6 +8,7 @@
#undef open
#undef mount
#undef read
+#undef fd2path
#undef write
#undef seek
#undef stat
@@ -183,8 +184,8 @@
return o;
}
-long
-_sysfd2path(int fd, char *buf, uint nbuf)
+int
+sysfd2path(int fd, char *buf, int nbuf)
{
Chan *c;
--- /dev/null
+++ b/kern/time.c
@@ -1,0 +1,49 @@
+#include <u.h>
+#include <sys/time.h>
+#include <time.h>
+#include <sys/resource.h>
+#include <libc.h>
+
+#undef times
+#undef cputimes
+#undef time
+
+long
+systimes(long *t)
+{
+ struct rusage ru, cru;
+
+ if(getrusage(0, &ru) < 0 || getrusage(-1, &cru) < 0)
+ return -1;
+
+ t[0] = ru.ru_utime.tv_sec*1000 + ru.ru_utime.tv_usec/1000;
+ t[1] = ru.ru_stime.tv_sec*1000 + ru.ru_stime.tv_usec/1000;
+ t[2] = cru.ru_utime.tv_sec*1000 + cru.ru_utime.tv_usec/1000;
+ t[3] = cru.ru_stime.tv_sec*1000 + cru.ru_stime.tv_usec/1000;
+
+ /* BUG */
+ return t[0]+t[1]+t[2]+t[3];
+}
+
+double
+syscputime(void)
+{
+ long t[4];
+ double d;
+
+ if(systimes(t) < 0)
+ return -1.0;
+
+ d = (double)t[0]+(double)t[1]+(double)t[2]+(double)t[3];
+ return d/1000.0;
+}
+
+long
+systime(long *tt)
+{
+ long t;
+ t = time(0);
+ if(tt)
+ *tt = t;
+ return t;
+}
--- /dev/null
+++ b/kern/wait.c
@@ -1,0 +1,53 @@
+#include <u.h>
+#include <libc.h>
+
+static Waitmsg*
+_wait(int n, char *buf)
+{
+ int l;
+ char *fld[5];
+ Waitmsg *w;
+
+ if(n <= 0)
+ return nil;
+ buf[n] = '\0';
+ if(tokenize(buf, fld, nelem(fld)) != nelem(fld)){
+ werrstr("couldn't parse wait message");
+ return nil;
+ }
+ l = strlen(fld[4])+1;
+ w = malloc(sizeof(Waitmsg)+l);
+ if(w == nil)
+ return nil;
+ w->pid = atoi(fld[0]);
+ w->dur[0] = atoi(fld[1]);
+ w->dur[1] = atoi(fld[2]);
+ w->dur[2] = atoi(fld[3]);
+ w->msg = (char*)&w[1];
+ memmove(w->msg, fld[4], l);
+ return w;
+}
+
+Waitmsg*
+syswait(void)
+{
+ char buf[256];
+
+ return _wait(await(buf, sizeof buf-1), buf);
+}
+
+Waitmsg*
+waitnohang(void)
+{
+ char buf[256];
+
+ return _wait(awaitnohang(buf, sizeof buf-1), buf);
+}
+
+Waitmsg*
+waitfor(int pid)
+{
+ char buf[256];
+
+ return _wait(awaitfor(pid, buf, sizeof buf-1), buf);
+}
--- a/main.c
+++ b/main.c
@@ -44,8 +44,6 @@
int
main(int argc, char **argv)
{
- int fd;
- char s[1024];
extern ulong kerndate;
kerndate = seconds();
eve = getuser();
@@ -65,30 +63,18 @@
panic("bind #c: %r");
if(bind("#e", "/env", MREPL|MCREATE) < 0)
panic("bind #e: %r");
- if(bind("#I", "/net", MBEFORE) < 0)
- panic("bind #I: %r");
if(bind("#U", "/root", MREPL) < 0)
panic("bind #U: %r");
- bind("#A", "/dev", MAFTER);
- bind("#N", "/dev", MAFTER);
- bind("#C", "/", MAFTER);
-
if(bind("/root", "/", MAFTER) < 0)
panic("bind /root: %r");
- if((fd = open("/dev/cons", OREAD)) < 0)
- panic("open stdin: %r");
- if(read(fd, s, sizeof s) <= 0)
- panic("read: %r");
- close(fd);
-
+ // We get service=cpu, change to =unix
char *cmd[] = {
- "/bin/rc",
- "-c",
- s
+ "drawcpu",
+ "-c"
+ ". <{n=`{read} && ! ~ $#n 0 && read -c $n} >[2=1]"
};
- printf("%s %s %s\n", cmd[0], cmd[1], cmd[2]);
runcommand(3, cmd);
_exit(0);
}
--- a/rc/drawcpu.c
+++ b/rc/drawcpu.c
@@ -3,7 +3,6 @@
* By convention, exported routines herein have names beginning with an
* upper case letter.
*/
-
#include "rc.h"
#include "exec.h"
#include "io.h"
@@ -10,17 +9,12 @@
#include "fns.h"
#include "getflags.h"
-#include <signal.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <sys/wait.h>
-
+static void execrfork(void);
static void execfinit(void);
builtin Builtin[] = {
"cd", execcd,
- "whatis", execwhatis,
+ "whatis", execwhatis,
"eval", execeval,
"exec", execexec, /* but with popword first */
"exit", execexit,
@@ -29,15 +23,31 @@
".", execdot,
"flag", execflag,
"finit", execfinit,
+ "rfork", execrfork,
0
};
-// TODO: PREFIX "/lib/rcmain"
-char Rcmain[]="./rc/rcmain.unix";
+char Rcmain[]="/usr/local/lib/rcmain";
char Fdprefix[]="/dev/fd/";
-char *Signame[NSIG];
+char *Signame[] = {
+ "sigexit", "sighup", "sigint", "sigquit",
+ "sigalrm", "sigkill", "sigfpe", "sigterm",
+ 0
+};
+static char *syssigname[] = {
+ "exit", /* can't happen */
+ "hangup",
+ "interrupt",
+ "quit", /* can't happen */
+ "alarm",
+ "kill",
+ "sys: fp: ",
+ "term",
+ 0
+};
+
/*
* finit could be removed but is kept for
* backwards compatibility, see: rcmain.plan9
@@ -53,6 +63,61 @@
runq->lex->qflag = 1;
}
+static void
+execrfork(void)
+{
+ int arg;
+ char *s;
+
+ switch(count(runq->argv->words)){
+ case 1:
+ arg = RFENVG|RFNAMEG|RFNOTEG;
+ break;
+ case 2:
+ arg = 0;
+ for(s = runq->argv->words->next->word;*s;s++) switch(*s){
+ default:
+ goto Usage;
+ case 'n':
+ arg|=RFNAMEG; break;
+ case 'N':
+ arg|=RFCNAMEG;
+ break;
+ case 'm':
+ /*arg|=RFNOMNT;*/ break;
+ case 'e':
+ arg|=RFENVG; break;
+ case 'E':
+ arg|=RFCENVG; break;
+ case 's':
+ arg|=RFNOTEG; break;
+ case 'f':
+ arg|=RFFDG; break;
+ case 'F':
+ arg|=RFCFDG; break;
+ }
+ break;
+ default:
+ Usage:
+ pfmt(err, "Usage: %s [fnesFNEm]\n", runq->argv->words->word);
+ setstatus("rfork usage");
+ poplist();
+ return;
+ }
+ if(rfork(arg)==-1){
+ pfmt(err, "%s: %s failed\n", argv0, runq->argv->words->word);
+ setstatus("rfork failed");
+ } else {
+ if(arg & RFCFDG){
+ redir *rp;
+ for(rp = runq->redir; rp; rp = rp->next)
+ rp->type = 0;
+ }
+ setstatus("");
+ }
+ poplist();
+}
+
char*
Env(char *name, int fn)
{
@@ -66,69 +131,74 @@
void
Vinit(void)
{
- int fd;
- DIR *dir;
- struct dirent *ent;
+ int dir, fd, i, n;
+ Dir *ent;
- dir = opendir("/env");
- if(dir == nil){
+ dir = Open(Env("", 0), 0);
+ if(dir<0){
pfmt(err, "%s: can't open: %s\n", argv0, Errstr());
return;
}
for(;;){
- ent = readdir(dir);
- if (ent == nil)
+ ent = 0;
+ n = dirread(dir, &ent);
+ if(n <= 0)
break;
- if(ent->d_namlen<=0 || strncmp(ent->d_name, "fn#", 3)==0)
- continue;
- if((fd = Open(Env(ent->d_name, 0), 0))>=0){
- io *f = openiofd(fd);
- word *w = 0, **wp = &w;
- char *s;
- while((s = rstr(f, "")) != 0){
- *wp = Newword(s, (word*)0);
- wp = &(*wp)->next;
+ for(i = 0; i<n; i++){
+ if(ent[i].length<=0 || strncmp(ent[i].name, "fn#", 3)==0)
+ continue;
+ if((fd = Open(Env(ent[i].name, 0), 0))>=0){
+ io *f = openiofd(fd);
+ word *w = 0, **wp = &w;
+ char *s;
+ while((s = rstr(f, "")) != 0){
+ *wp = Newword(s, (word*)0);
+ wp = &(*wp)->next;
+ }
+ closeio(f);
+ setvar(ent[i].name, w);
+ vlook(ent[i].name)->changed = 0;
}
- closeio(f);
- setvar(ent->d_name, w);
- vlook(ent->d_name)->changed = 0;
}
free(ent);
}
- closedir(dir);
+ Close(dir);
}
char*
Errstr(void)
{
- return strerror(errno);
+ static char err[ERRMAX];
+ rerrstr(err, sizeof err);
+ return err;
}
-/* Can we do this inside the kernel? */
int
Waitfor(int pid)
{
thread *p;
- char num[12];
- int wpid, status;
+ Waitmsg *w;
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);
+
+ while((w = wait()) != nil){
+ delwaitpid(w->pid);
+ if(w->pid==pid){
+ setstatus(w->msg);
+ free(w);
return 0;
}
for(p = runq->ret;p;p = p->ret)
- if(p->pid==wpid){
+ if(p->pid==w->pid){
p->pid=-1;
- p->status = estrdup(num);
+ p->status = estrdup(w->msg);
break;
}
+ free(w);
}
- if(errno==EINTR) return -1;
+
+ if(strcmp(Errstr(), "interrupted")==0) return -1;
return 0;
}
@@ -192,8 +262,7 @@
void
Exec(char **argv)
{
- // TODO: execve after loading env to string
- execv(argv[0], argv+1);
+ execvp(argv[0], argv+1);
}
int
@@ -200,87 +269,105 @@
Fork(void)
{
Updenv();
- return fork();
+ // TODO: Tie into the rendezvous so we can block 'em in rfork
+ return rfork(RFPROC|RFFDG/*|RFREND*/);
}
+
+typedef struct readdir readdir;
+struct readdir {
+ Dir *dbuf;
+ int i, n;
+ int fd;
+};
+
void*
Opendir(char *name)
{
- return opendir(name);
+ readdir *rd;
+ int fd;
+ if((fd = Open(name, 0))<0)
+ return 0;
+ rd = new(readdir);
+ rd->dbuf = 0;
+ rd->i = 0;
+ rd->n = 0;
+ rd->fd = fd;
+ return rd;
}
+static int
+trimdirs(Dir *d, int nd)
+{
+ int r, w;
+
+ for(r=w=0; r<nd; r++)
+ if(d[r].mode&DMDIR)
+ d[w++] = d[r];
+ return w;
+}
+
char*
Readdir(void *arg, int onlydirs)
{
- DIR *rd = arg;
- struct dirent *ent = readdir(rd);
- if(ent == NULL)
+ readdir *rd = arg;
+ int n;
+Again:
+ if(rd->i>=rd->n){ /* read */
+ free(rd->dbuf);
+ rd->dbuf = 0;
+ n = dirread(rd->fd, &rd->dbuf);
+ if(n>0){
+ if(onlydirs){
+ n = trimdirs(rd->dbuf, n);
+ if(n == 0)
+ goto Again;
+ }
+ rd->n = n;
+ }else
+ rd->n = 0;
+ rd->i = 0;
+ }
+ if(rd->i>=rd->n)
return 0;
- return ent->d_name;
+ return rd->dbuf[rd->i++].name;
}
void
Closedir(void *arg)
{
- DIR *rd = arg;
- closedir(rd);
+ readdir *rd = arg;
+ Close(rd->fd);
+ free(rd->dbuf);
+ free(rd);
}
+static int interrupted = 0;
+
static void
-sighandler(int sig)
+notifyf(void* u, char *s)
{
- trap[sig]++;
- ntrap++;
+ int i;
+
+ USED(u);
+ for(i = 0;syssigname[i];i++) if(strncmp(s, syssigname[i], strlen(syssigname[i]))==0){
+ if(strncmp(s, "sys: ", 5)!=0) interrupted = 1;
+ goto Out;
+ }
+ noted(NDFLT);
+ return;
+Out:
+ if(strcmp(s, "interrupt")!=0 || trap[i]==0){
+ trap[i]++;
+ ntrap++;
+ }
+ noted(NCONT);
}
-// TODO: Use kernel sighandling
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
- }
+ notify(notifyf);
}
long
@@ -356,7 +443,7 @@
void
Noerror(void)
{
- errno = 0;
+ interrupted = 0;
}
int
@@ -363,6 +450,12 @@
Isatty(int fd)
{
return isatty(fd);
+ /*
+ char buf[64];
+ if(fd2path(fd, buf, sizeof buf) != 0)
+ return 0;
+ return strlen(buf) >= 9 && strcmp(buf+strlen(buf)-9, "/dev/cons") == 0;
+ */
}
void
@@ -371,9 +464,12 @@
abort();
}
+static int newwdir;
+
int
Chdir(char *dir)
{
+ newwdir = 1;
return chdir(dir);
}
@@ -382,4 +478,15 @@
{
pstr(err, s);
flushio(err);
+
+ if(newwdir){
+ char dir[4096];
+ int fd;
+ if((fd=Creat("/dev/wdir"))>=0){
+ getwd(dir, sizeof(dir));
+ Write(fd, dir, strlen(dir));
+ Close(fd);
+ }
+ newwdir = 0;
+ }
}
--- a/rc/exec.c
+++ b/rc/exec.c
@@ -243,9 +243,11 @@
else if(flag['i']==0 && argc==1 && Isatty(0)) flag['i'] = flagset;
if(flag['m']) rcmain = flag['m'][0];
+ /* Open stdout so next desc is stderr */
fd = open("/dev/cons", ORDWR);
- err = open("/dev/cons", OWRITE);
+ err = openiofd(open("/dev/cons", OWRITE));
close(fd);
+
kinit();
Trapinit();
Vinit();
@@ -275,7 +277,6 @@
bootstrap[18].f = Xexit;
bootstrap[19].f = 0;
start(bootstrap, 2, (var*)0, (redir*)0);
-
/* prime bootstrap argv */
pushlist();
for(i = argc-1;i!=0;--i) pushword(argv[i]);
@@ -287,6 +288,7 @@
dotrap();
}
}
+
/*
* Opcode routines
* Arguments on stack (...)
--- a/rc/io.c
+++ b/rc/io.c
@@ -148,10 +148,10 @@
pptr(io *f, void *p)
{
static char hex[] = "0123456789ABCDEF";
- unsigned long v;
+ uvlong v;
int n;
- v = (unsigned long)p;
+ v = (uvlong)p;
if(sizeof(v) == sizeof(p) && v>>32)
for(n = 60;n>=32;n-=4) pchr(f, hex[(v>>n)&0xF]);
for(n = 28;n>=0;n-=4) pchr(f, hex[(v>>n)&0xF]);
--- a/rc/rc.h
+++ b/rc/rc.h
@@ -1,9 +1,3 @@
-/*
- * Plan9 is defined for plan 9
- * otherwise its UNIX.
- * Please don't litter the code with ifdefs. The three below (and one in
- * getflags) should be enough.
- */
#include <u.h>
#include <libc.h>