Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
	/* 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
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
157
error(char *s)
158
{
159
	fprint(2, "%s: %s: %r\n", argv0, s);
160
	exits(s);
161
}
162
 
163
void
164
notifyf(void *a, char *s)
165
{
166
	USED(a);
167
	if(strcmp(s, "interrupt") == 0)
168
		noted(NCONT);
169
	noted(NDFLT);
170
}