127272365SDavid du Colombier /*
227272365SDavid du Colombier * lock - keep a lock alive while a command runs
327272365SDavid du Colombier */
427272365SDavid du Colombier
527272365SDavid du Colombier #include <u.h>
627272365SDavid du Colombier #include <libc.h>
727272365SDavid du Colombier #include <ctype.h>
827272365SDavid du Colombier
927272365SDavid du Colombier static int debug;
1027272365SDavid du Colombier static int lockwait;
1127272365SDavid du Colombier
1227272365SDavid du Colombier void error(char*);
1327272365SDavid du Colombier void notifyf(void*, char*);
1427272365SDavid du Colombier
1527272365SDavid du Colombier static void
usage(void)1627272365SDavid du Colombier usage(void)
1727272365SDavid du Colombier {
1827272365SDavid du Colombier fprint(2, "usage: %s [-dw] lock [command [file]...]\n", argv0);
1927272365SDavid du Colombier exits("usage");
2027272365SDavid du Colombier }
2127272365SDavid du Colombier
2227272365SDavid du Colombier static Waitmsg *
waitfor(int pid)2327272365SDavid du Colombier waitfor(int pid)
2427272365SDavid du Colombier {
2527272365SDavid du Colombier char err[ERRMAX];
2627272365SDavid du Colombier Waitmsg *w;
2727272365SDavid du Colombier
2827272365SDavid du Colombier for (;;) {
2927272365SDavid du Colombier w = wait();
3027272365SDavid du Colombier if (w == nil){
3127272365SDavid du Colombier errstr(err, sizeof err);
3227272365SDavid du Colombier if(strcmp(err, "interrupted") == 0)
3327272365SDavid du Colombier continue;
3427272365SDavid du Colombier return nil;
3527272365SDavid du Colombier }
3627272365SDavid du Colombier if (w->pid == pid)
3727272365SDavid du Colombier return w;
3827272365SDavid du Colombier }
3927272365SDavid du Colombier }
4027272365SDavid du Colombier
4127272365SDavid du Colombier static int
openlock(char * lock)4227272365SDavid du Colombier openlock(char *lock)
4327272365SDavid du Colombier {
4427272365SDavid du Colombier int lckfd;
4527272365SDavid du Colombier Dir *dir;
4627272365SDavid du Colombier
47*a382d53bSDavid du Colombier /* first ensure that the lock file has the lock bit set */
48*a382d53bSDavid du Colombier dir = dirstat(lock);
49*a382d53bSDavid du Colombier if (dir == nil)
50*a382d53bSDavid du Colombier sysfatal("can't stat %s: %r", lock);
51*a382d53bSDavid du Colombier if (!(dir->mode & DMEXCL)) {
52*a382d53bSDavid du Colombier dir->mode |= DMEXCL;
53*a382d53bSDavid du Colombier dir->qid.type |= QTEXCL;
54*a382d53bSDavid du Colombier if (dirwstat(lock, dir) < 0)
55*a382d53bSDavid du Colombier sysfatal("can't make %s exclusive access: %r", lock);
56*a382d53bSDavid du Colombier }
57*a382d53bSDavid du Colombier free(dir);
58*a382d53bSDavid du Colombier
5927272365SDavid du Colombier if (lockwait)
6027272365SDavid du Colombier while ((lckfd = open(lock, ORDWR)) < 0)
6127272365SDavid du Colombier sleep(1000);
6227272365SDavid du Colombier else
6327272365SDavid du Colombier lckfd = open(lock, ORDWR);
6427272365SDavid du Colombier if (lckfd < 0)
6527272365SDavid du Colombier sysfatal("can't open %s read/write: %r", lock);
6627272365SDavid du Colombier return lckfd;
6727272365SDavid du Colombier }
6827272365SDavid du Colombier
6927272365SDavid du Colombier void
main(int argc,char * argv[])7027272365SDavid du Colombier main(int argc, char *argv[])
7127272365SDavid du Colombier {
7227272365SDavid du Colombier int fd, lckfd, lckpid, cmdpid;
7327272365SDavid du Colombier char *cmd, *p, *lock;
7427272365SDavid du Colombier char **args;
7527272365SDavid du Colombier char *argarr[2];
7627272365SDavid du Colombier Waitmsg *w;
7727272365SDavid du Colombier
7827272365SDavid du Colombier ARGBEGIN {
7927272365SDavid du Colombier case 'd':
8027272365SDavid du Colombier ++debug;
8127272365SDavid du Colombier break;
8227272365SDavid du Colombier case 'w':
8327272365SDavid du Colombier ++lockwait;
8427272365SDavid du Colombier break;
8527272365SDavid du Colombier default:
8627272365SDavid du Colombier usage();
8727272365SDavid du Colombier break;
8827272365SDavid du Colombier } ARGEND
8927272365SDavid du Colombier
9027272365SDavid du Colombier if (argc < 1)
9127272365SDavid du Colombier usage();
9227272365SDavid du Colombier if (argc == 1) {
9327272365SDavid du Colombier args = argarr;
9427272365SDavid du Colombier args[0] = cmd = "rc";
9527272365SDavid du Colombier args[1] = nil;
9627272365SDavid du Colombier } else {
9727272365SDavid du Colombier cmd = argv[1];
9827272365SDavid du Colombier args = &argv[1];
9927272365SDavid du Colombier }
10027272365SDavid du Colombier
10127272365SDavid du Colombier /* set up lock and process to keep it alive */
10227272365SDavid du Colombier lock = argv[0];
10327272365SDavid du Colombier lckfd = openlock(lock);
10427272365SDavid du Colombier lckpid = fork();
10527272365SDavid du Colombier switch(lckpid){
10627272365SDavid du Colombier case -1:
10727272365SDavid du Colombier error("fork");
10827272365SDavid du Colombier case 0:
10927272365SDavid du Colombier /* keep lock alive until killed */
11027272365SDavid du Colombier for (;;) {
11127272365SDavid du Colombier sleep(60*1000);
11227272365SDavid du Colombier seek(lckfd, 0, 0);
11327272365SDavid du Colombier fprint(lckfd, "\n");
11427272365SDavid du Colombier }
11527272365SDavid du Colombier }
11627272365SDavid du Colombier
11727272365SDavid du Colombier /* spawn argument command */
11827272365SDavid du Colombier cmdpid = rfork(RFFDG|RFREND|RFPROC|RFENVG);
11927272365SDavid du Colombier switch(cmdpid){
12027272365SDavid du Colombier case -1:
12127272365SDavid du Colombier error("fork");
12227272365SDavid du Colombier case 0:
12327272365SDavid du Colombier fd = create("/env/prompt", OWRITE, 0666);
12427272365SDavid du Colombier if (fd >= 0) {
12527272365SDavid du Colombier fprint(fd, "%s%% ", lock);
12627272365SDavid du Colombier close(fd);
12727272365SDavid du Colombier }
12827272365SDavid du Colombier exec(cmd, args);
12927272365SDavid du Colombier if(cmd[0] != '/' && strncmp(cmd, "./", 2) != 0 &&
13027272365SDavid du Colombier strncmp(cmd, "../", 3) != 0)
13127272365SDavid du Colombier exec(smprint("/bin/%s", cmd), args);
13227272365SDavid du Colombier error(cmd);
13327272365SDavid du Colombier }
13427272365SDavid du Colombier
13527272365SDavid du Colombier notify(notifyf);
13627272365SDavid du Colombier
13727272365SDavid du Colombier w = waitfor(cmdpid);
13827272365SDavid du Colombier if (w == nil)
13927272365SDavid du Colombier error("wait");
14027272365SDavid du Colombier
14127272365SDavid du Colombier postnote(PNPROC, lckpid, "die");
14227272365SDavid du Colombier waitfor(lckpid);
14327272365SDavid du Colombier if(w->msg[0]){
14427272365SDavid du Colombier p = utfrune(w->msg, ':');
14527272365SDavid du Colombier if(p && p[1])
14627272365SDavid du Colombier p++;
14727272365SDavid du Colombier else
14827272365SDavid du Colombier p = w->msg;
14927272365SDavid du Colombier while (isspace(*p))
15027272365SDavid du Colombier p++;
15127272365SDavid du Colombier fprint(2, "%s: %s # status=%s\n", argv0, cmd, p);
15227272365SDavid du Colombier }
15327272365SDavid du Colombier exits(w->msg);
15427272365SDavid du Colombier }
15527272365SDavid du Colombier
15627272365SDavid du Colombier void
error(char * s)15727272365SDavid du Colombier error(char *s)
15827272365SDavid du Colombier {
15927272365SDavid du Colombier fprint(2, "%s: %s: %r\n", argv0, s);
16027272365SDavid du Colombier exits(s);
16127272365SDavid du Colombier }
16227272365SDavid du Colombier
16327272365SDavid du Colombier void
notifyf(void * a,char * s)16427272365SDavid du Colombier notifyf(void *a, char *s)
16527272365SDavid du Colombier {
16627272365SDavid du Colombier USED(a);
16727272365SDavid du Colombier if(strcmp(s, "interrupt") == 0)
16827272365SDavid du Colombier noted(NCONT);
16927272365SDavid du Colombier noted(NDFLT);
17027272365SDavid du Colombier }
171