aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/upas/common/libsys.c
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2005-10-29 16:26:44 +0000
committerrsc <devnull@localhost>2005-10-29 16:26:44 +0000
commit5cdb17983ae6e6367ad7a940cb219eab247a9304 (patch)
tree8ca1ef49af2a96e7daebe624d91fdf679814a057 /src/cmd/upas/common/libsys.c
parentcd3745196389579fb78b9b01ef1daefb5a57aa71 (diff)
downloadplan9port-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.c1001
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;
+}