xref: /plan9/sys/src/cmd/lock.c (revision a382d53bcdd3e333e35c31b623dd084adce596e0)
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