diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/upas/common |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/upas/common')
-rwxr-xr-x | sys/src/cmd/upas/common/appendfiletombox.c | 164 | ||||
-rwxr-xr-x | sys/src/cmd/upas/common/aux.c | 149 | ||||
-rwxr-xr-x | sys/src/cmd/upas/common/become.c | 28 | ||||
-rwxr-xr-x | sys/src/cmd/upas/common/common.h | 80 | ||||
-rwxr-xr-x | sys/src/cmd/upas/common/config.c | 11 | ||||
-rwxr-xr-x | sys/src/cmd/upas/common/libsys.c | 971 | ||||
-rwxr-xr-x | sys/src/cmd/upas/common/mail.c | 57 | ||||
-rwxr-xr-x | sys/src/cmd/upas/common/makefile | 18 | ||||
-rwxr-xr-x | sys/src/cmd/upas/common/mkfile | 24 | ||||
-rwxr-xr-x | sys/src/cmd/upas/common/process.c | 173 | ||||
-rwxr-xr-x | sys/src/cmd/upas/common/sys.h | 85 |
11 files changed, 1760 insertions, 0 deletions
diff --git a/sys/src/cmd/upas/common/appendfiletombox.c b/sys/src/cmd/upas/common/appendfiletombox.c new file mode 100755 index 000000000..16bdd48aa --- /dev/null +++ b/sys/src/cmd/upas/common/appendfiletombox.c @@ -0,0 +1,164 @@ +#include "common.h" + +enum { + Buffersize = 64*1024, +}; + +typedef struct Inbuf Inbuf; +struct Inbuf +{ + char buf[Buffersize]; + char *wp; + char *rp; + int eof; + int in; + int out; + int last; + ulong bytes; +}; + +static Inbuf* +allocinbuf(int in, int out) +{ + Inbuf *b; + + b = mallocz(sizeof(Inbuf), 1); + if(b == nil) + sysfatal("reading mailbox: %r"); + b->rp = b->wp = b->buf; + b->in = in; + b->out = out; + return b; +} + +/* should only be called at start of file or when b->rp[-1] == '\n' */ +static int +fill(Inbuf *b, int addspace) +{ + int i, n; + + if(b->eof && b->wp - b->rp == 0) + return 0; + + n = b->rp - b->buf; + if(n > 0){ + i = write(b->out, b->buf, n); + if(i != n) + return -1; + b->last = b->buf[n-1]; + b->bytes += n; + } + if(addspace){ + if(write(b->out, " ", 1) != 1) + return -1; + b->last = ' '; + b->bytes++; + } + + n = b->wp - b->rp; + memmove(b->buf, b->rp, n); + b->rp = b->buf; + b->wp = b->rp + n; + + i = read(b->in, b->buf+n, sizeof(b->buf)-n); + if(i < 0) + return -1; + b->wp += i; + + return b->wp - b->rp; +} + +enum { Fromlen = sizeof "From " - 1, }; + +/* code to escape ' '*From' ' at the beginning of a line */ +int +appendfiletombox(int in, int out) +{ + int addspace, n, sol; + char *p; + Inbuf *b; + + seek(out, 0, 2); + + b = allocinbuf(in, out); + addspace = 0; + sol = 1; + + for(;;){ + if(b->wp - b->rp < Fromlen){ + /* + * not enough unread bytes in buffer to match "From ", + * so get some more. We must only inject a space at + * the start of a line (one that begins with "From "). + */ + if (b->rp == b->buf || b->rp[-1] == '\n') { + n = fill(b, addspace); + addspace = 0; + } else + n = fill(b, 0); + if(n < 0) + goto error; + if(n == 0) + break; + if(n < Fromlen){ /* still can't match? */ + b->rp = b->wp; + continue; + } + } + + /* state machine looking for ' '*From' ' */ + if(!sol){ + p = memchr(b->rp, '\n', b->wp - b->rp); + if(p == nil) + b->rp = b->wp; + else{ + b->rp = p+1; + sol = 1; + } + continue; + } else { + if(*b->rp == ' ' || strncmp(b->rp, "From ", Fromlen) != 0){ + b->rp++; + continue; + } + addspace = 1; + sol = 0; + } + } + + /* mailbox entries always terminate with two newlines */ + n = b->last == '\n' ? 1 : 2; + if(write(out, "\n\n", n) != n) + goto error; + n += b->bytes; + free(b); + return n; +error: + free(b); + return -1; +} + +int +appendfiletofile(int in, int out) +{ + int n; + Inbuf *b; + + seek(out, 0, 2); + + b = allocinbuf(in, out); + for(;;){ + n = fill(b, 0); + if(n < 0) + goto error; + if(n == 0) + break; + b->rp = b->wp; + } + n = b->bytes; + free(b); + return n; +error: + free(b); + return -1; +} diff --git a/sys/src/cmd/upas/common/aux.c b/sys/src/cmd/upas/common/aux.c new file mode 100755 index 000000000..8786acb50 --- /dev/null +++ b/sys/src/cmd/upas/common/aux.c @@ -0,0 +1,149 @@ +#include "common.h" + +/* expand a path relative to some `.' */ +extern String * +abspath(char *path, char *dot, String *to) +{ + if (*path == '/') { + to = s_append(to, path); + } else { + to = s_append(to, dot); + to = s_append(to, "/"); + to = s_append(to, path); + } + return to; +} + +/* return a pointer to the base component of a pathname */ +extern char * +basename(char *path) +{ + char *cp; + + cp = strrchr(path, '/'); + return cp==0 ? path : cp+1; +} + +/* append a sub-expression match onto a String */ +extern void +append_match(Resub *subexp, String *sp, int se) +{ + char *cp, *ep; + + cp = subexp[se].sp; + ep = subexp[se].ep; + for (; cp < ep; cp++) + s_putc(sp, *cp); + s_terminate(sp); +} + +/* + * check for shell characters in a String + */ +static char *illegalchars = "\r\n"; + +extern int +shellchars(char *cp) +{ + char *sp; + + for(sp=illegalchars; *sp; sp++) + if(strchr(cp, *sp)) + return 1; + return 0; +} + +static char *specialchars = " ()<>{};=\\'\`^&|"; +static char *escape = "%%"; + +int +hexchar(int x) +{ + x &= 0xf; + if(x < 10) + return '0' + x; + else + return 'A' + x - 10; +} + +/* + * rewrite a string to escape shell characters + */ +extern String* +escapespecial(String *s) +{ + String *ns; + char *sp; + + for(sp = specialchars; *sp; sp++) + if(strchr(s_to_c(s), *sp)) + break; + if(*sp == 0) + return s; + + ns = s_new(); + for(sp = s_to_c(s); *sp; sp++){ + if(strchr(specialchars, *sp)){ + s_append(ns, escape); + s_putc(ns, hexchar(*sp>>4)); + s_putc(ns, hexchar(*sp)); + } else + s_putc(ns, *sp); + } + s_terminate(ns); + s_free(s); + return ns; +} + +int +hex2uint(char x) +{ + if(x >= '0' && x <= '9') + return x - '0'; + if(x >= 'A' && x <= 'F') + return (x - 'A') + 10; + if(x >= 'a' && x <= 'f') + return (x - 'a') + 10; + return -512; +} + +/* + * rewrite a string to remove shell characters escapes + */ +extern String* +unescapespecial(String *s) +{ + int c; + String *ns; + char *sp; + uint n; + + if(strstr(s_to_c(s), escape) == 0) + return s; + n = strlen(escape); + + ns = s_new(); + for(sp = s_to_c(s); *sp; sp++){ + if(strncmp(sp, escape, n) == 0){ + c = (hex2uint(sp[n])<<4) | hex2uint(sp[n+1]); + if(c < 0) + s_putc(ns, *sp); + else { + s_putc(ns, c); + sp += n+2-1; + } + } else + s_putc(ns, *sp); + } + s_terminate(ns); + s_free(s); + return ns; + +} + +int +returnable(char *path) +{ + + return strcmp(path, "/dev/null") != 0; +} diff --git a/sys/src/cmd/upas/common/become.c b/sys/src/cmd/upas/common/become.c new file mode 100755 index 000000000..8c012d212 --- /dev/null +++ b/sys/src/cmd/upas/common/become.c @@ -0,0 +1,28 @@ +#include "common.h" +#include <auth.h> +#include <ndb.h> + +/* + * become powerless user + */ +int +become(char **cmd, char *who) +{ + int fd; + + USED(cmd); + if(strcmp(who, "none") == 0) { + fd = open("#c/user", OWRITE); + if(fd < 0 || write(fd, "none", strlen("none")) < 0) { + werrstr("can't become none"); + return -1; + } + close(fd); + if(newns("none", 0)) { + werrstr("can't set new namespace"); + return -1; + } + } + return 0; +} + diff --git a/sys/src/cmd/upas/common/common.h b/sys/src/cmd/upas/common/common.h new file mode 100755 index 000000000..3f9acbd18 --- /dev/null +++ b/sys/src/cmd/upas/common/common.h @@ -0,0 +1,80 @@ +#include "sys.h" + +/* format of REMOTE FROM lines */ +extern char *REMFROMRE; +extern int REMSENDERMATCH; +extern int REMDATEMATCH; +extern int REMSYSMATCH; + +/* format of mailbox FROM lines */ +#define IS_HEADER(p) ((p)[0]=='F'&&(p)[1]=='r'&&(p)[2]=='o'&&(p)[3]=='m'&&(p)[4]==' ') +#define IS_TRAILER(p) ((p)[0]=='m'&&(p)[1]=='o'&&(p)[2]=='r'&&(p)[3]=='F'&&(p)[4]=='\n') +extern char *FROMRE; +extern int SENDERMATCH; +extern int DATEMATCH; + +enum +{ + Elemlen= 28, + Errlen= ERRMAX, + Pathlen= 256, +}; +enum { Atnoteunknown, Atnoterecog }; + +/* + * routines in mail.c + */ +extern int print_header(Biobuf*, char*, char*); +extern int print_remote_header(Biobuf*, char*, char*, char*); +extern int parse_header(char*, String*, String*); + +/* + * routines in aux.c + */ +extern String *abspath(char*, char*, String*); +extern String *mboxpath(char*, char*, String*, int); +extern char *basename(char*); +extern int delivery_status(String*); +extern void append_match(Resub*, String*, int); +extern int shellchars(char*); +extern String* escapespecial(String*); +extern String* unescapespecial(String*); +extern int returnable(char*); + +/* in copymessage */ +extern int appendfiletombox(int, int); +extern int appendfiletofile(int, int); + +/* mailbox types */ +#define MF_NORMAL 0 +#define MF_PIPE 1 +#define MF_FORWARD 2 +#define MF_NOMBOX 3 +#define MF_NOTMBOX 4 + +/* a pipe between parent and child*/ +typedef struct { + Biobuf bb; + Biobuf *fp; /* parent process end*/ + int fd; /* child process end*/ +} stream; + +/* a child process*/ +typedef struct process{ + stream *std[3]; /* standard fd's*/ + int pid; /* process identifier*/ + int status; /* exit status*/ + Waitmsg *waitmsg; +} process; + +extern stream *instream(void); +extern stream *outstream(void); +extern void stream_free(stream*); +extern process *noshell_proc_start(char**, stream*, stream*, stream*, int, char*); +extern process *proc_start(char*, stream*, stream*, stream*, int, char*); +extern int proc_wait(process*); +extern int proc_free(process*); +extern int proc_kill(process*); + +/* tell compiler we're using a value so it won't complain */ +#define USE(x) if(x) diff --git a/sys/src/cmd/upas/common/config.c b/sys/src/cmd/upas/common/config.c new file mode 100755 index 000000000..f322783ef --- /dev/null +++ b/sys/src/cmd/upas/common/config.c @@ -0,0 +1,11 @@ +#include "common.h" + +char *MAILROOT = "/mail"; +char *UPASLOG = "/sys/log"; +char *UPASLIB = "/mail/lib"; +char *UPASBIN= "/bin/upas"; +char *UPASTMP = "/mail/tmp"; +char *SHELL = "/bin/rc"; +char *POST = "/sys/lib/post/dispatch"; + +int MBOXMODE = 0662; diff --git a/sys/src/cmd/upas/common/libsys.c b/sys/src/cmd/upas/common/libsys.c new file mode 100755 index 000000000..f0b8f35a4 --- /dev/null +++ b/sys/src/cmd/upas/common/libsys.c @@ -0,0 +1,971 @@ +#include "common.h" +#include <auth.h> +#include <ndb.h> + +/* + * number of predefined fd's + */ +int nsysfile=3; + +static char err[Errlen]; + +/* + * return the date + */ +extern char * +thedate(void) +{ + static char now[64]; + char *cp; + + strcpy(now, ctime(time(0))); + cp = strchr(now, '\n'); + if(cp) + *cp = 0; + return now; +} + +/* + * return the user id of the current user + */ +extern char * +getlog(void) +{ + static char user[64]; + int fd; + int n; + + fd = open("/dev/user", 0); + if(fd < 0) + return nil; + if((n=read(fd, user, sizeof(user)-1)) <= 0) + return nil; + close(fd); + user[n] = 0; + return user; +} + +/* + * return the lock name (we use one lock per directory) + */ +static String * +lockname(char *path) +{ + String *lp; + char *cp; + + /* + * get the name of the lock file + */ + lp = s_new(); + cp = strrchr(path, '/'); + if(cp) + s_nappend(lp, path, cp - path + 1); + s_append(lp, "L.mbox"); + + return lp; +} + +int +syscreatelocked(char *path, int mode, int perm) +{ + return create(path, mode, DMEXCL|perm); +} + +int +sysopenlocked(char *path, int mode) +{ +/* return open(path, OEXCL|mode);/**/ + return open(path, mode); /* until system call is fixed */ +} + +int +sysunlockfile(int fd) +{ + return close(fd); +} + +/* + * try opening a lock file. If it doesn't exist try creating it. + */ +static int +openlockfile(Mlock *l) +{ + int fd; + Dir *d; + Dir nd; + char *p; + + fd = open(s_to_c(l->name), OREAD); + if(fd >= 0){ + l->fd = fd; + return 0; + } + + d = dirstat(s_to_c(l->name)); + if(d == nil){ + /* file doesn't exist */ + /* try creating it */ + fd = create(s_to_c(l->name), OREAD, DMEXCL|0666); + if(fd >= 0){ + nulldir(&nd); + nd.mode = DMEXCL|0666; + if(dirfwstat(fd, &nd) < 0){ + /* if we can't chmod, don't bother */ + /* live without the lock but log it */ + syslog(0, "mail", "lock error: %s: %r", s_to_c(l->name)); + remove(s_to_c(l->name)); + } + l->fd = fd; + return 0; + } + + /* couldn't create */ + /* do we have write access to the directory? */ + p = strrchr(s_to_c(l->name), '/'); + if(p != 0){ + *p = 0; + fd = access(s_to_c(l->name), 2); + *p = '/'; + if(fd < 0){ + /* live without the lock but log it */ + syslog(0, "mail", "lock error: %s: %r", s_to_c(l->name)); + return 0; + } + } else { + fd = access(".", 2); + if(fd < 0){ + /* live without the lock but log it */ + syslog(0, "mail", "lock error: %s: %r", s_to_c(l->name)); + return 0; + } + } + } else + free(d); + + return 1; /* try again later */ +} + +#define LSECS 5*60 + +/* + * Set a lock for a particular file. The lock is a file in the same directory + * and has L. prepended to the name of the last element of the file name. + */ +extern Mlock * +syslock(char *path) +{ + Mlock *l; + int tries; + + l = mallocz(sizeof(Mlock), 1); + if(l == 0) + return nil; + + l->name = lockname(path); + + /* + * wait LSECS seconds for it to unlock + */ + for(tries = 0; tries < LSECS*2; tries++){ + switch(openlockfile(l)){ + case 0: + return l; + case 1: + sleep(500); + break; + default: + goto noway; + } + } + +noway: + s_free(l->name); + free(l); + return nil; +} + +/* + * like lock except don't wait + */ +extern Mlock * +trylock(char *path) +{ + Mlock *l; + char buf[1]; + int fd; + + l = malloc(sizeof(Mlock)); + if(l == 0) + return 0; + + l->name = lockname(path); + if(openlockfile(l) != 0){ + s_free(l->name); + free(l); + return 0; + } + + /* fork process to keep lock alive */ + switch(l->pid = rfork(RFPROC)){ + default: + break; + case 0: + fd = l->fd; + for(;;){ + sleep(1000*60); + if(pread(fd, buf, 1, 0) < 0) + break; + } + _exits(0); + } + return l; +} + +extern void +syslockrefresh(Mlock *l) +{ + char buf[1]; + + pread(l->fd, buf, 1, 0); +} + +extern void +sysunlock(Mlock *l) +{ + if(l == 0) + return; + if(l->name){ + s_free(l->name); + } + if(l->fd >= 0) + close(l->fd); + if(l->pid > 0) + postnote(PNPROC, l->pid, "time to die"); + free(l); +} + +/* + * Open a file. The modes are: + * + * l - locked + * a - set append permissions + * r - readable + * w - writable + * A - append only (doesn't exist in Bio) + */ +extern Biobuf * +sysopen(char *path, char *mode, ulong perm) +{ + int sysperm; + int sysmode; + int fd; + int docreate; + int append; + int truncate; + Dir *d, nd; + Biobuf *bp; + + /* + * decode the request + */ + sysperm = 0; + sysmode = -1; + docreate = 0; + append = 0; + truncate = 0; + for(; mode && *mode; mode++) + switch(*mode){ + case 'A': + sysmode = OWRITE; + append = 1; + break; + case 'c': + docreate = 1; + break; + case 'l': + sysperm |= DMEXCL; + break; + case 'a': + sysperm |= DMAPPEND; + break; + case 'w': + if(sysmode == -1) + sysmode = OWRITE; + else + sysmode = ORDWR; + break; + case 'r': + if(sysmode == -1) + sysmode = OREAD; + else + sysmode = ORDWR; + break; + case 't': + truncate = 1; + break; + default: + break; + } + switch(sysmode){ + case OREAD: + case OWRITE: + case ORDWR: + break; + default: + if(sysperm&DMAPPEND) + sysmode = OWRITE; + else + sysmode = OREAD; + break; + } + + /* + * create file if we need to + */ + if(truncate) + sysmode |= OTRUNC; + fd = open(path, sysmode); + if(fd < 0){ + d = dirstat(path); + if(d == nil){ + if(docreate == 0) + return 0; + + fd = create(path, sysmode, sysperm|perm); + if(fd < 0) + return 0; + nulldir(&nd); + nd.mode = sysperm|perm; + dirfwstat(fd, &nd); + } else { + free(d); + return 0; + } + } + + bp = (Biobuf*)malloc(sizeof(Biobuf)); + if(bp == 0){ + close(fd); + return 0; + } + memset(bp, 0, sizeof(Biobuf)); + Binit(bp, fd, sysmode&~OTRUNC); + + if(append) + Bseek(bp, 0, 2); + return bp; +} + +/* + * close the file, etc. + */ +int +sysclose(Biobuf *bp) +{ + int rv; + + rv = Bterm(bp); + close(Bfildes(bp)); + free(bp); + return rv; +} + +/* + * create a file + */ +int +syscreate(char *file, int mode, ulong perm) +{ + return create(file, mode, perm); +} + +/* + * make a directory + */ +int +sysmkdir(char *file, ulong perm) +{ + int fd; + + if((fd = create(file, OREAD, DMDIR|perm)) < 0) + return -1; + close(fd); + return 0; +} + +/* + * change the group of a file + */ +int +syschgrp(char *file, char *group) +{ + Dir nd; + + if(group == 0) + return -1; + nulldir(&nd); + nd.gid = group; + return dirwstat(file, &nd); +} + +extern int +sysdirreadall(int fd, Dir **d) +{ + return dirreadall(fd, d); +} + +/* + * read in the system name + */ +extern char * +sysname_read(void) +{ + static char name[128]; + char *cp; + + cp = getenv("site"); + if(cp == 0 || *cp == 0) + cp = alt_sysname_read(); + if(cp == 0 || *cp == 0) + cp = "kremvax"; + strecpy(name, name+sizeof name, cp); + return name; +} +extern char * +alt_sysname_read(void) +{ + static char name[128]; + int n, fd; + + fd = open("/dev/sysname", OREAD); + if(fd < 0) + return 0; + n = read(fd, name, sizeof(name)-1); + close(fd); + if(n <= 0) + return 0; + name[n] = 0; + return name; +} + +/* + * get all names + */ +extern char** +sysnames_read(void) +{ + static char **namev; + Ndbtuple *t, *nt; + int n; + char *cp; + + if(namev) + return namev; + + free(csgetvalue(0, "sys", alt_sysname_read(), "dom", &t)); + + n = 0; + for(nt = t; nt; nt = nt->entry) + if(strcmp(nt->attr, "dom") == 0) + n++; + + namev = (char**)malloc(sizeof(char *)*(n+3)); + + if(namev){ + n = 0; + namev[n++] = strdup(sysname_read()); + cp = alt_sysname_read(); + if(cp) + namev[n++] = strdup(cp); + for(nt = t; nt; nt = nt->entry) + if(strcmp(nt->attr, "dom") == 0) + namev[n++] = strdup(nt->val); + namev[n] = 0; + } + if(t) + ndbfree(t); + + return namev; +} + +/* + * read in the domain name + */ +extern char * +domainname_read(void) +{ + char **namev; + + for(namev = sysnames_read(); *namev; namev++) + if(strchr(*namev, '.')) + return *namev; + return 0; +} + +/* + * return true if the last error message meant file + * did not exist. + */ +extern int +e_nonexistent(void) +{ + rerrstr(err, sizeof(err)); + return strcmp(err, "file does not exist") == 0; +} + +/* + * return true if the last error message meant file + * was locked. + */ +extern int +e_locked(void) +{ + rerrstr(err, sizeof(err)); + return strcmp(err, "open/create -- file is locked") == 0; +} + +/* + * return the length of a file + */ +extern long +sysfilelen(Biobuf *fp) +{ + Dir *d; + long rv; + + d = dirfstat(Bfildes(fp)); + if(d == nil) + return -1; + rv = d->length; + free(d); + return rv; +} + +/* + * remove a file + */ +extern int +sysremove(char *path) +{ + return remove(path); +} + +/* + * rename a file, fails unless both are in the same directory + */ +extern int +sysrename(char *old, char *new) +{ + Dir d; + char *obase; + char *nbase; + + obase = strrchr(old, '/'); + nbase = strrchr(new, '/'); + if(obase){ + if(nbase == 0) + return -1; + if(strncmp(old, new, obase-old) != 0) + return -1; + nbase++; + } else { + if(nbase) + return -1; + nbase = new; + } + nulldir(&d); + d.name = nbase; + return dirwstat(old, &d); +} + +/* + * see if a file exists + */ +extern int +sysexist(char *file) +{ + Dir *d; + + d = dirstat(file); + if(d == nil) + return 0; + free(d); + return 1; +} + +/* + * return nonzero if file is a directory + */ +extern int +sysisdir(char *file) +{ + Dir *d; + int rv; + + d = dirstat(file); + if(d == nil) + return 0; + rv = d->mode & DMDIR; + free(d); + return rv; +} + +/* + * kill a process or process group + */ + +static int +stomp(int pid, char *file) +{ + char name[64]; + int fd; + + snprint(name, sizeof(name), "/proc/%d/%s", pid, file); + fd = open(name, 1); + if(fd < 0) + return -1; + if(write(fd, "die: yankee pig dog\n", sizeof("die: yankee pig dog\n") - 1) <= 0){ + close(fd); + return -1; + } + close(fd); + return 0; + +} + +/* + * kill a process + */ +extern int +syskill(int pid) +{ + return stomp(pid, "note"); + +} + +/* + * kill a process group + */ +extern int +syskillpg(int pid) +{ + return stomp(pid, "notepg"); +} + +extern int +sysdetach(void) +{ + if(rfork(RFENVG|RFNAMEG|RFNOTEG) < 0) { + werrstr("rfork failed"); + return -1; + } + return 0; +} + +/* + * catch a write on a closed pipe + */ +static int *closedflag; +static int +catchpipe(void *a, char *msg) +{ + static char *foo = "sys: write on closed pipe"; + + USED(a); + if(strncmp(msg, foo, strlen(foo)) == 0){ + if(closedflag) + *closedflag = 1; + return 1; + } + return 0; +} +void +pipesig(int *flagp) +{ + closedflag = flagp; + atnotify(catchpipe, 1); +} +void +pipesigoff(void) +{ + atnotify(catchpipe, 0); +} + +void +exit(int i) +{ + char buf[32]; + + if(i == 0) + exits(0); + snprint(buf, sizeof(buf), "%d", i); + exits(buf); +} + +static int +islikeatty(int fd) +{ + char buf[64]; + + if(fd2path(fd, buf, sizeof buf) != 0) + return 0; + + /* might be /mnt/term/dev/cons */ + return strlen(buf) >= 9 && strcmp(buf+strlen(buf)-9, "/dev/cons") == 0; +} + +extern int +holdon(void) +{ + int fd; + + if(!islikeatty(0)) + return -1; + + fd = open("/dev/consctl", OWRITE); + write(fd, "holdon", 6); + + return fd; +} + +extern int +sysopentty(void) +{ + return open("/dev/cons", ORDWR); +} + +extern void +holdoff(int fd) +{ + write(fd, "holdoff", 7); + close(fd); +} + +extern int +sysfiles(void) +{ + return 128; +} + +/* + * expand a path relative to the user's mailbox directory + * + * if the path starts with / or ./, don't change it + * + */ +extern String * +mboxpath(char *path, char *user, String *to, int dot) +{ + if (dot || *path=='/' || strncmp(path, "./", 2) == 0 + || strncmp(path, "../", 3) == 0) { + to = s_append(to, path); + } else { + to = s_append(to, MAILROOT); + to = s_append(to, "/box/"); + to = s_append(to, user); + to = s_append(to, "/"); + to = s_append(to, path); + } + return to; +} + +extern String * +mboxname(char *user, String *to) +{ + return mboxpath("mbox", user, to, 0); +} + +extern String * +deadletter(String *to) /* pass in sender??? */ +{ + char *cp; + + cp = getlog(); + if(cp == 0) + return 0; + return mboxpath("dead.letter", cp, to, 0); +} + +char * +homedir(char *user) +{ + USED(user); + return getenv("home"); +} + +String * +readlock(String *file) +{ + char *cp; + + cp = getlog(); + if(cp == 0) + return 0; + return mboxpath("reading", cp, file, 0); +} + +String * +username(String *from) +{ + int n; + Biobuf *bp; + char *p, *q; + String *s; + + bp = Bopen("/adm/keys.who", OREAD); + if(bp == 0) + bp = Bopen("/adm/netkeys.who", OREAD); + if(bp == 0) + return 0; + + s = 0; + n = strlen(s_to_c(from)); + for(;;) { + p = Brdline(bp, '\n'); + if(p == 0) + break; + p[Blinelen(bp)-1] = 0; + if(strncmp(p, s_to_c(from), n)) + continue; + p += n; + if(*p != ' ' && *p != '\t') /* must be full match */ + continue; + while(*p && (*p == ' ' || *p == '\t')) + p++; + if(*p == 0) + continue; + for(q = p; *q; q++) + if(('0' <= *q && *q <= '9') || *q == '<') + break; + while(q > p && q[-1] != ' ' && q[-1] != '\t') + q--; + while(q > p && (q[-1] == ' ' || q[-1] == '\t')) + q--; + *q = 0; + s = s_new(); + s_append(s, "\""); + s_append(s, p); + s_append(s, "\""); + break; + } + Bterm(bp); + return s; +} + +char * +remoteaddr(int fd, char *dir) +{ + char buf[128], *p; + int n; + + if(dir == 0){ + if(fd2path(fd, buf, sizeof(buf)) != 0) + return ""; + + /* parse something of the form /net/tcp/nnnn/data */ + p = strrchr(buf, '/'); + if(p == 0) + return ""; + strncpy(p+1, "remote", sizeof(buf)-(p-buf)-2); + } else + snprint(buf, sizeof buf, "%s/remote", dir); + buf[sizeof(buf)-1] = 0; + + fd = open(buf, OREAD); + if(fd < 0) + return ""; + n = read(fd, buf, sizeof(buf)-1); + close(fd); + if(n > 0){ + buf[n] = 0; + p = strchr(buf, '!'); + if(p) + *p = 0; + return strdup(buf); + } + return ""; +} + +// create a file and +// 1) ensure the modes we asked for +// 2) make gid == uid +static int +docreate(char *file, int perm) +{ + int fd; + Dir ndir; + Dir *d; + + // create the mbox + fd = create(file, OREAD, perm); + if(fd < 0){ + fprint(2, "couldn't create %s\n", file); + return -1; + } + d = dirfstat(fd); + if(d == nil){ + fprint(2, "couldn't stat %s\n", file); + return -1; + } + nulldir(&ndir); + ndir.mode = perm; + ndir.gid = d->uid; + if(dirfwstat(fd, &ndir) < 0) + fprint(2, "couldn't chmod %s: %r\n", file); + close(fd); + return 0; +} + +// create a mailbox +int +creatembox(char *user, char *folder) +{ + char *p; + String *mailfile; + char buf[512]; + Mlock *ml; + + mailfile = s_new(); + if(folder == 0) + mboxname(user, mailfile); + else { + snprint(buf, sizeof(buf), "%s/mbox", folder); + mboxpath(buf, user, mailfile, 0); + } + + // don't destroy existing mailbox + if(access(s_to_c(mailfile), 0) == 0){ + fprint(2, "mailbox already exists\n"); + return -1; + } + fprint(2, "creating new mbox: %s\n", s_to_c(mailfile)); + + // make sure preceding levels exist + for(p = s_to_c(mailfile); p; p++) { + if(*p == '/') /* skip leading or consecutive slashes */ + continue; + p = strchr(p, '/'); + if(p == 0) + break; + *p = 0; + if(access(s_to_c(mailfile), 0) != 0){ + if(docreate(s_to_c(mailfile), DMDIR|0711) < 0) + return -1; + } + *p = '/'; + } + + // create the mbox + if(docreate(s_to_c(mailfile), 0622|DMAPPEND|DMEXCL) < 0) + return -1; + + /* + * create the lock file if it doesn't exist + */ + ml = trylock(s_to_c(mailfile)); + if(ml != nil) + sysunlock(ml); + + return 0; +} diff --git a/sys/src/cmd/upas/common/mail.c b/sys/src/cmd/upas/common/mail.c new file mode 100755 index 000000000..5347c6550 --- /dev/null +++ b/sys/src/cmd/upas/common/mail.c @@ -0,0 +1,57 @@ +#include "common.h" + +/* format of REMOTE FROM lines */ +char *REMFROMRE = + "^>?From[ \t]+((\".*\")?[^\" \t]+?(\".*\")?[^\" \t]+?)[ \t]+(.+)[ \t]+remote[ \t]+from[ \t]+(.*)\n$"; +int REMSENDERMATCH = 1; +int REMDATEMATCH = 4; +int REMSYSMATCH = 5; + +/* format of LOCAL FROM lines */ +char *FROMRE = + "^>?From[ \t]+((\".*\")?[^\" \t]+?(\".*\")?[^\" \t]+?)[ \t]+(.+)\n$"; +int SENDERMATCH = 1; +int DATEMATCH = 4; + +/* output a unix style local header */ +int +print_header(Biobuf *fp, char *sender, char *date) +{ + return Bprint(fp, "From %s %s\n", sender, date); +} + +/* output a unix style remote header */ +int +print_remote_header(Biobuf *fp, char *sender, char *date, char *system) +{ + return Bprint(fp, "From %s %s remote from %s\n", sender, date, system); +} + +/* parse a mailbox style header */ +int +parse_header(char *line, String *sender, String *date) +{ + if (!IS_HEADER(line)) + return -1; + line += sizeof("From ") - 1; + s_restart(sender); + while(*line==' '||*line=='\t') + line++; + if(*line == '"'){ + s_putc(sender, *line++); + while(*line && *line != '"') + s_putc(sender, *line++); + s_putc(sender, *line++); + } else { + while(*line && *line != ' ' && *line != '\t') + s_putc(sender, *line++); + } + s_terminate(sender); + s_restart(date); + while(*line==' '||*line=='\t') + line++; + while(*line) + s_putc(date, *line++); + s_terminate(date); + return 0; +} diff --git a/sys/src/cmd/upas/common/makefile b/sys/src/cmd/upas/common/makefile new file mode 100755 index 000000000..c7beae817 --- /dev/null +++ b/sys/src/cmd/upas/common/makefile @@ -0,0 +1,18 @@ +CFLAGS=${UNIX} -g -I. -I../libc -I../common -I/usr/include ${SCFLAGS} +OBJS=mail.o aux.o string.o ${SYSOBJ} +AR=ar +.c.o: ; ${CC} -c ${CFLAGS} $*.c + +common.a: ${OBJS} + ${AR} cr common.a ${OBJS} + -ranlib common.a + +aux.o: aux.h string.h mail.h +string.o: string.h mail.h +mail.o: mail.h +syslog.o: sys.h +mail.h: sys.h + +clean: + -rm -f *.[oO] core a.out *.a *.sL common.a + diff --git a/sys/src/cmd/upas/common/mkfile b/sys/src/cmd/upas/common/mkfile new file mode 100755 index 000000000..5d817b72b --- /dev/null +++ b/sys/src/cmd/upas/common/mkfile @@ -0,0 +1,24 @@ +</$objtype/mkfile + +LIB=libcommon.a$O +OFILES=aux.$O\ + become.$O\ + mail.$O\ + process.$O\ + libsys.$O\ + config.$O\ + appendfiletombox.$O\ + +HFILES=common.h\ + sys.h\ + +UPDATE=\ + mkfile\ + ${OFILES:%.$O=%.c}\ + $HFILES\ + +</sys/src/cmd/mklib + +nuke:V: + mk clean + rm -f libcommon.a[$OS] diff --git a/sys/src/cmd/upas/common/process.c b/sys/src/cmd/upas/common/process.c new file mode 100755 index 000000000..f698c9600 --- /dev/null +++ b/sys/src/cmd/upas/common/process.c @@ -0,0 +1,173 @@ +#include "common.h" + +/* make a stream to a child process */ +extern stream * +instream(void) +{ + stream *rv; + int pfd[2]; + + if ((rv = (stream *)malloc(sizeof(stream))) == 0) + return 0; + memset(rv, 0, sizeof(stream)); + if (pipe(pfd) < 0) + return 0; + if(Binit(&rv->bb, pfd[1], OWRITE) < 0){ + close(pfd[0]); + close(pfd[1]); + return 0; + } + rv->fp = &rv->bb; + rv->fd = pfd[0]; + return rv; +} + +/* make a stream from a child process */ +extern stream * +outstream(void) +{ + stream *rv; + int pfd[2]; + + if ((rv = (stream *)malloc(sizeof(stream))) == 0) + return 0; + memset(rv, 0, sizeof(stream)); + if (pipe(pfd) < 0) + return 0; + if (Binit(&rv->bb, pfd[0], OREAD) < 0){ + close(pfd[0]); + close(pfd[1]); + return 0; + } + rv->fp = &rv->bb; + rv->fd = pfd[1]; + return rv; +} + +extern void +stream_free(stream *sp) +{ + int fd; + + close(sp->fd); + fd = Bfildes(sp->fp); + Bterm(sp->fp); + close(fd); + free((char *)sp); +} + +/* start a new process */ +extern process * +noshell_proc_start(char **av, stream *inp, stream *outp, stream *errp, int newpg, char *who) +{ + process *pp; + int i, n; + + if ((pp = (process *)malloc(sizeof(process))) == 0) { + if (inp != 0) + stream_free(inp); + if (outp != 0) + stream_free(outp); + if (errp != 0) + stream_free(errp); + return 0; + } + pp->std[0] = inp; + pp->std[1] = outp; + pp->std[2] = errp; + switch (pp->pid = fork()) { + case -1: + proc_free(pp); + return 0; + case 0: + if(newpg) + sysdetach(); + for (i=0; i<3; i++) + if (pp->std[i] != 0){ + close(Bfildes(pp->std[i]->fp)); + while(pp->std[i]->fd < 3) + pp->std[i]->fd = dup(pp->std[i]->fd, -1); + } + for (i=0; i<3; i++) + if (pp->std[i] != 0) + dup(pp->std[i]->fd, i); + for (n = sysfiles(); i < n; i++) + close(i); + if(who) + become(av, who); + exec(av[0], av); + perror("proc_start"); + exits("proc_start"); + default: + for (i=0; i<3; i++) + if (pp->std[i] != 0) { + close(pp->std[i]->fd); + pp->std[i]->fd = -1; + } + return pp; + } +} + +/* start a new process under a shell */ +extern process * +proc_start(char *cmd, stream *inp, stream *outp, stream *errp, int newpg, char *who) +{ + char *av[4]; + + av[0] = SHELL; + av[1] = "-c"; + av[2] = cmd; + av[3] = 0; + return noshell_proc_start(av, inp, outp, errp, newpg, who); +} + +/* wait for a process to stop */ +extern int +proc_wait(process *pp) +{ + Waitmsg *status; + char err[Errlen]; + + for(;;){ + status = wait(); + if(status == nil){ + rerrstr(err, sizeof(err)); + if(strstr(err, "interrupt") == 0) + break; + } + if (status->pid==pp->pid) + break; + } + pp->pid = -1; + if(status == nil) + pp->status = -1; + else + pp->status = status->msg[0]; + pp->waitmsg = status; + return pp->status; +} + +/* free a process */ +extern int +proc_free(process *pp) +{ + int i; + + if(pp->std[1] == pp->std[2]) + pp->std[2] = 0; /* avoid freeing it twice */ + for (i = 0; i < 3; i++) + if (pp->std[i]) + stream_free(pp->std[i]); + if (pp->pid >= 0) + proc_wait(pp); + free(pp->waitmsg); + free((char *)pp); + return 0; +} + +/* kill a process */ +extern int +proc_kill(process *pp) +{ + return syskill(pp->pid); +} diff --git a/sys/src/cmd/upas/common/sys.h b/sys/src/cmd/upas/common/sys.h new file mode 100755 index 000000000..a50f27284 --- /dev/null +++ b/sys/src/cmd/upas/common/sys.h @@ -0,0 +1,85 @@ +/* + * System dependent header files for research + */ + +#include <u.h> +#include <libc.h> +#include <regexp.h> +#include <bio.h> +#include "String.h" + +/* + * for the lock routines in libsys.c + */ +typedef struct Mlock Mlock; +struct Mlock { + int fd; + int pid; + String *name; +}; + +/* + * from config.c + */ +extern char *MAILROOT; /* root of mail system */ +extern char *UPASLOG; /* log directory */ +extern char *UPASLIB; /* upas library directory */ +extern char *UPASBIN; /* upas binary directory */ +extern char *UPASTMP; /* temporary directory */ +extern char *SHELL; /* path name of shell */ +extern char *POST; /* path name of post server addresses */ +extern int MBOXMODE; /* default mailbox protection mode */ + +/* + * files in libsys.c + */ +extern char *sysname_read(void); +extern char *alt_sysname_read(void); +extern char *domainname_read(void); +extern char **sysnames_read(void); +extern char *getlog(void); +extern char *thedate(void); +extern Biobuf *sysopen(char*, char*, ulong); +extern int sysopentty(void); +extern int sysclose(Biobuf*); +extern int sysmkdir(char*, ulong); +extern int syschgrp(char*, char*); +extern Mlock *syslock(char *); +extern void sysunlock(Mlock *); +extern void syslockrefresh(Mlock *); +extern int e_nonexistent(void); +extern int e_locked(void); +extern long sysfilelen(Biobuf*); +extern int sysremove(char*); +extern int sysrename(char*, char*); +extern int sysexist(char*); +extern int sysisdir(char*); +extern int syskill(int); +extern int syskillpg(int); +extern int syscreate(char*, int, ulong); +extern Mlock *trylock(char *); +extern void exit(int); +extern void pipesig(int*); +extern void pipesigoff(void); +extern int holdon(void); +extern void holdoff(int); +extern int syscreatelocked(char*, int, int); +extern int sysopenlocked(char*, int); +extern int sysunlockfile(int); +extern int sysfiles(void); +extern int become(char**, char*); +extern int sysdetach(void); +extern int sysdirreadall(int, Dir**); +extern String *username(String*); +extern char* remoteaddr(int, char*); +extern int creatembox(char*, char*); + +extern String *readlock(String*); +extern char *homedir(char*); +extern String *mboxname(char*, String*); +extern String *deadletter(String*); + +/* + * maximum size for a file path + */ +#define MAXPATHLEN 128 |