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