diff options
author | rsc <devnull@localhost> | 2005-10-29 16:26:44 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2005-10-29 16:26:44 +0000 |
commit | 5cdb17983ae6e6367ad7a940cb219eab247a9304 (patch) | |
tree | 8ca1ef49af2a96e7daebe624d91fdf679814a057 /src/cmd/upas/common/libsys.c | |
parent | cd3745196389579fb78b9b01ef1daefb5a57aa71 (diff) | |
download | plan9port-5cdb17983ae6e6367ad7a940cb219eab247a9304.tar.gz plan9port-5cdb17983ae6e6367ad7a940cb219eab247a9304.tar.bz2 plan9port-5cdb17983ae6e6367ad7a940cb219eab247a9304.zip |
Thanks to John Cummings.
Diffstat (limited to 'src/cmd/upas/common/libsys.c')
-rw-r--r-- | src/cmd/upas/common/libsys.c | 1001 |
1 files changed, 1001 insertions, 0 deletions
diff --git a/src/cmd/upas/common/libsys.c b/src/cmd/upas/common/libsys.c new file mode 100644 index 00000000..67f36798 --- /dev/null +++ b/src/cmd/upas/common/libsys.c @@ -0,0 +1,1001 @@ +#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) +{ + return getuser(); +} +#if 0 /* jpc */ +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; +} +#endif /* jpc */ +/* + * 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; + Ndb* db; + Ndbs s; + int n; + char *cp; + + if(namev) + return namev; + + /* free(csgetvalue(0, "sys", alt_sysname_read(), "dom", &t)); jpc */ + db = ndbopen(unsharp("#9/ndb/local")); + free(ndbgetvalue(db, &s, "sys", sysname(),"dom", &t)); + /* t = nil; /* jpc */ + /* fprint(2,"csgetvalue called: fixme"); /* jpc */ + + 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 +exit9(int i) +{ + char buf[32]; + + if(i == 0) + exits(0); + snprint(buf, sizeof(buf), "%d", i); + exits(buf); +} + +static int +islikeatty(int fd) +{ + Dir *d; + int rv; + + d = dirfstat(fd); + if(d == nil) + return 0; + rv = strcmp(d->name, "cons") == 0; + free(d); + return rv; +} + +#if 0 +/* jpc */ +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; +} +#endif + +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, unsharp(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){ + fprint(2,"remoteaddr: called fd2path: fixme\n"); /* jpc + 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; +} |