]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/lock.c
vmx: reset virtio queue state on device reset
[plan9front.git] / sys / src / cmd / lock.c
1 /*
2  * lock - keep a lock alive while a command runs
3  */
4
5 #include <u.h>
6 #include <libc.h>
7 #include <ctype.h>
8
9 static int debug;
10 static int lockwait;
11
12 void    error(char*);
13 void    notifyf(void*, char*);
14
15 static void
16 usage(void)
17 {
18         fprint(2, "usage: %s [-dw] lock [command [file]...]\n", argv0);
19         exits("usage");
20 }
21
22 static Waitmsg *
23 waitfor(int pid)
24 {
25         char err[ERRMAX];
26         Waitmsg *w;
27
28         for (;;) {
29                 w = wait();
30                 if (w == nil){
31                         errstr(err, sizeof err);
32                         if(strcmp(err, "interrupted") == 0)
33                                 continue;
34                         return nil;
35                 }
36                 if (w->pid == pid)
37                         return w;
38         }
39 }
40
41 static int
42 openlock(char *lock)
43 {
44         int lckfd, didwstat = 0;
45         Dir *dir;
46
47 Reopen:
48         while ((lckfd = open(lock, ORDWR)) < 0 && lockwait)
49                 sleep(1000);
50         if (lckfd < 0)
51                 sysfatal("can't open %s read/write: %r", lock);
52         dir = dirfstat(lckfd);
53         if (dir == nil)
54                 sysfatal("can't fstat %s: %r", lock);
55         if (!(dir->mode & DMEXCL)) {
56                 if(didwstat++)
57                         sysfatal("exclusive bit does not stick for %s", lock);
58                 dir->mode |= DMEXCL;
59                 dir->qid.type |= QTEXCL;
60                 if (dirfwstat(lckfd, dir) < 0)
61                         sysfatal("can't make %s exclusive access: %r", lock);
62                 /* reopen for lock to be effective */
63                 free(dir);
64                 close(lckfd);
65                 goto Reopen;
66         }
67         free(dir);
68         return lckfd;
69 }
70
71 void
72 main(int argc, char *argv[])
73 {
74         int fd, lckfd, lckpid, cmdpid;
75         char *cmd, *p, *lock;
76         char **args;
77         char *argarr[2];
78         Waitmsg *w;
79
80         ARGBEGIN {
81         case 'd':
82                 ++debug;
83                 break;
84         case 'w':
85                 ++lockwait;
86                 break;
87         default:
88                 usage();
89                 break;
90         } ARGEND
91
92         if (argc < 1)
93                 usage();
94         if (argc == 1) {
95                 args = argarr;
96                 args[0] = cmd = "rc";
97                 args[1] = nil;
98         } else {
99                 cmd = argv[1];
100                 args = &argv[1];
101         }
102
103         /* set up lock and process to keep it alive */
104         lock = argv[0];
105         lckfd = openlock(lock);
106         lckpid = fork();
107         switch(lckpid){
108         case -1:
109                 error("fork");
110         case 0:
111                 /* keep lock alive until killed */
112                 for (;;) {
113                         sleep(60*1000);
114                         seek(lckfd, 0, 0);
115                         fprint(lckfd, "\n");
116                 }
117         }
118
119         /* spawn argument command */
120         cmdpid = rfork(RFFDG|RFREND|RFPROC|RFENVG);
121         switch(cmdpid){
122         case -1:
123                 error("fork");
124         case 0:
125                 fd = create("/env/prompt", OWRITE, 0666);
126                 if (fd >= 0) {
127                         fprint(fd, "%s%% ", lock);
128                         close(fd);
129                 }
130                 exec(cmd, args);
131                 if(cmd[0] != '/' && strncmp(cmd, "./", 2) != 0 &&
132                    strncmp(cmd, "../", 3) != 0)
133                         exec(smprint("/bin/%s", cmd), args);
134                 error(cmd);
135         }
136
137         notify(notifyf);
138
139         w = waitfor(cmdpid);
140         if (w == nil)
141                 error("wait");
142
143         postnote(PNPROC, lckpid, "die");
144         waitfor(lckpid);
145         if(w->msg[0]){
146                 p = utfrune(w->msg, ':');
147                 if(p && p[1])
148                         p++;
149                 else
150                         p = w->msg;
151                 while (isspace(*p))
152                         p++;
153                 fprint(2, "%s: %s  # status=%s\n", argv0, cmd, p);
154         }
155         exits(w->msg);
156 }
157
158 void
159 error(char *s)
160 {
161         fprint(2, "%s: %s: %r\n", argv0, s);
162         exits(s);
163 }
164
165 void
166 notifyf(void *a, char *s)
167 {
168         USED(a);
169         if(strcmp(s, "interrupt") == 0)
170                 noted(NCONT);
171         noted(NDFLT);
172 }