]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/lock.c
merge
[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;
45         Dir *dir;
46
47         if (lockwait)
48                 while ((lckfd = open(lock, ORDWR)) < 0)
49                         sleep(1000);
50         else
51                 lckfd = open(lock, ORDWR);
52         if (lckfd < 0)
53                 sysfatal("can't open %s read/write: %r", lock);
54         dir = dirfstat(lckfd);
55         if (dir == nil)
56                 sysfatal("can't fstat %s: %r", lock);
57         if (!(dir->mode & DMEXCL)) {
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         }
63         free(dir);
64         return lckfd;
65 }
66
67 void
68 main(int argc, char *argv[])
69 {
70         int fd, lckfd, lckpid, cmdpid;
71         char *cmd, *p, *lock;
72         char **args;
73         char *argarr[2];
74         Waitmsg *w;
75
76         ARGBEGIN {
77         case 'd':
78                 ++debug;
79                 break;
80         case 'w':
81                 ++lockwait;
82                 break;
83         default:
84                 usage();
85                 break;
86         } ARGEND
87
88         if (argc < 1)
89                 usage();
90         if (argc == 1) {
91                 args = argarr;
92                 args[0] = cmd = "rc";
93                 args[1] = nil;
94         } else {
95                 cmd = argv[1];
96                 args = &argv[1];
97         }
98
99         /* set up lock and process to keep it alive */
100         lock = argv[0];
101         lckfd = openlock(lock);
102         lckpid = fork();
103         switch(lckpid){
104         case -1:
105                 error("fork");
106         case 0:
107                 /* keep lock alive until killed */
108                 for (;;) {
109                         sleep(60*1000);
110                         seek(lckfd, 0, 0);
111                         fprint(lckfd, "\n");
112                 }
113         }
114
115         /* spawn argument command */
116         cmdpid = rfork(RFFDG|RFREND|RFPROC|RFENVG);
117         switch(cmdpid){
118         case -1:
119                 error("fork");
120         case 0:
121                 fd = create("/env/prompt", OWRITE, 0666);
122                 if (fd >= 0) {
123                         fprint(fd, "%s%% ", lock);
124                         close(fd);
125                 }
126                 exec(cmd, args);
127                 if(cmd[0] != '/' && strncmp(cmd, "./", 2) != 0 &&
128                    strncmp(cmd, "../", 3) != 0)
129                         exec(smprint("/bin/%s", cmd), args);
130                 error(cmd);
131         }
132
133         notify(notifyf);
134
135         w = waitfor(cmdpid);
136         if (w == nil)
137                 error("wait");
138
139         postnote(PNPROC, lckpid, "die");
140         waitfor(lckpid);
141         if(w->msg[0]){
142                 p = utfrune(w->msg, ':');
143                 if(p && p[1])
144                         p++;
145                 else
146                         p = w->msg;
147                 while (isspace(*p))
148                         p++;
149                 fprint(2, "%s: %s  # status=%s\n", argv0, cmd, p);
150         }
151         exits(w->msg);
152 }
153
154 void
155 error(char *s)
156 {
157         fprint(2, "%s: %s: %r\n", argv0, s);
158         exits(s);
159 }
160
161 void
162 notifyf(void *a, char *s)
163 {
164         USED(a);
165         if(strcmp(s, "interrupt") == 0)
166                 noted(NCONT);
167         noted(NDFLT);
168 }