ref: 7a503757b1251c2746df7bdcd891814c1518cc28
dir: /sys/src/cmd/lock.c/
/* * lock - keep a lock alive while a command runs */ #include <u.h> #include <libc.h> #include <ctype.h> static int debug; static int lockwait; void error(char*); void notifyf(void*, char*); static void usage(void) { fprint(2, "usage: %s [-dw] lock [command [file]...]\n", argv0); exits("usage"); } static Waitmsg * waitfor(int pid) { char err[ERRMAX]; Waitmsg *w; for (;;) { w = wait(); if (w == nil){ errstr(err, sizeof err); if(strcmp(err, "interrupted") == 0) continue; return nil; } if (w->pid == pid) return w; free(w); } } static int openlock(char *lock) { int lckfd, didwstat = 0; Dir *dir; Reopen: while ((lckfd = open(lock, ORDWR)) < 0 && lockwait) sleep(1000); if (lckfd < 0) sysfatal("can't open %s read/write: %r", lock); dir = dirfstat(lckfd); if (dir == nil) sysfatal("can't fstat %s: %r", lock); if (!(dir->mode & DMEXCL)) { if(didwstat++) sysfatal("exclusive bit does not stick for %s", lock); dir->mode |= DMEXCL; dir->qid.type |= QTEXCL; if (dirfwstat(lckfd, dir) < 0) sysfatal("can't make %s exclusive access: %r", lock); /* reopen for lock to be effective */ free(dir); close(lckfd); goto Reopen; } free(dir); return lckfd; } void main(int argc, char *argv[]) { int fd, lckfd, lckpid, cmdpid; char *cmd, *p, *lock; char **args; char *argarr[2]; Waitmsg *w; ARGBEGIN { case 'd': ++debug; break; case 'w': ++lockwait; break; default: usage(); break; } ARGEND if (argc < 1) usage(); if (argc == 1) { args = argarr; args[0] = cmd = "rc"; args[1] = nil; } else { cmd = argv[1]; args = &argv[1]; } /* set up lock and process to keep it alive */ lock = argv[0]; lckfd = openlock(lock); lckpid = fork(); switch(lckpid){ case -1: error("fork"); case 0: /* keep lock alive until killed */ for (;;) { sleep(60*1000); seek(lckfd, 0, 0); fprint(lckfd, "\n"); } } /* spawn argument command */ cmdpid = rfork(RFFDG|RFREND|RFPROC|RFENVG); switch(cmdpid){ case -1: error("fork"); case 0: fd = create("/env/prompt", OWRITE, 0666); if (fd >= 0) { fprint(fd, "%s%% ", lock); close(fd); } exec(cmd, args); if(cmd[0] != '/' && strncmp(cmd, "./", 2) != 0 && strncmp(cmd, "../", 3) != 0) exec(smprint("/bin/%s", cmd), args); error(cmd); } notify(notifyf); w = waitfor(cmdpid); if (w == nil) error("wait"); postnote(PNPROC, lckpid, "die"); free(waitfor(lckpid)); if(w->msg[0]){ p = utfrune(w->msg, ':'); if(p && p[1]) p++; else p = w->msg; while (isspace(*p)) p++; fprint(2, "%s: %s # status=%s\n", argv0, cmd, p); } exits(w->msg); } void error(char *s) { fprint(2, "%s: %s: %r\n", argv0, s); exits(s); } void notifyf(void *a, char *s) { USED(a); if(strcmp(s, "interrupt") == 0) noted(NCONT); noted(NDFLT); }