123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971 |
- #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;
- }
|