msvc.c (7535B) download
1#include <fcntl.h>
2#include <sys/file.h>
3#include <signal.h>
4#include <stdio.h>
5#include <string.h>
6#include <stdlib.h>
7#include <unistd.h>
8#include <errno.h>
9
10#include <libowfat/str.h>
11#include <libowfat/fmt.h>
12#include <libowfat/buffer.h>
13#include <libowfat/errmsg.h>
14#define NOVARS
15#include "minit.h"
16
17static int infd,outfd;
18
19static char buf[1500];
20
21void addservice(char* service) {
22 char* x;
23 if (str_start(service,MINITROOT "/"))
24 service+=sizeof(MINITROOT "/") -1;
25 x=service+str_len(service)-1;
26 while (x>service && *x=='/') { *x=0; --x; }
27 strncpy(buf+1,service,1400);
28 buf[1400]=0;
29}
30
31int addreadwrite(char* service) {
32 addservice(service);
33 write(infd,buf,str_len(buf));
34 return read(outfd,buf,1500);
35}
36
37/* return PID, 0 if error */
38pid_t __readpid(char *service) {
39 int len;
40 buf[0]='p';
41 len=addreadwrite(service);
42 if (len<0) return 0;
43 buf[len]=0;
44 return atoi(buf);
45}
46
47/* return nonzero if error */
48int respawn(char *service,int yesno) {
49 int len;
50 buf[0]=yesno?'R':'r';
51 len=addreadwrite(service);
52 return (len!=1 || buf[0]=='0');
53}
54
55/* return nonzero if error */
56int setpid(char *service, pid_t pid) {
57 char *tmp;
58 int len;
59 buf[0]='P';
60 addservice(service);
61 tmp=buf+str_len(buf)+1;
62 tmp[fmt_ulong(tmp,pid)]=0;
63 write(infd,buf,str_len(buf)+str_len(tmp)+2);
64 len=read(outfd,buf,1500);
65 return (len!=1 || buf[0]=='0');
66}
67
68/* return nonzero if error */
69int check_remove(char *service) {
70 int len;
71 buf[0]='C';
72 len=addreadwrite(service);
73 return (len!=1 || buf[0]=='0');
74}
75
76/* return nonzero if error */
77int startservice(char *service) {
78 int len;
79 buf[0]='s';
80 len=addreadwrite(service);
81 return (len!=1 || buf[0]=='0');
82}
83
84/* return uptime, 0 if error */
85unsigned long uptime(char *service) {
86 int len;
87 buf[0]='u';
88 len=addreadwrite(service);
89 if (len<0) return 0;
90 buf[len]=0;
91 return atoi(buf);
92}
93
94void dumphistory() {
95 char tmp[16384];
96 int i,j;
97 char first,last;
98 first=1; last='x';
99 write(infd,"h",1);
100 for (;;) {
101 int done;
102 j=read(outfd,tmp,sizeof(tmp));
103 if (j<1) break;
104 done=i=0;
105 if (first) {
106 if (tmp[0]=='0') {
107 carp("minit compiled without history support.");
108 return;
109 }
110 i+=2;
111 } else {
112 if (!tmp[0] && last=='\n') break;
113 }
114 for (; i<j; ++i)
115 if (!tmp[i]) {
116 tmp[i]=done?0:'\n';
117 if (i<j && !tmp[i+1]) { done=1; --j; }
118 }
119 if (first)
120 write(1,tmp+2,j-2);
121 else
122 write(1,tmp,j);
123 if (done) break;
124 last=tmp[j-1];
125 first=0;
126 }
127}
128
129void dumpdependencies(char* service) {
130 char tmp[16384];
131 int i,j;
132 char first,last;
133 buf[0]='d';
134 addservice(service);
135 write(infd,buf,str_len(buf));
136 first=1; last='x';
137 for (;;) {
138 int done;
139 j=read(outfd,tmp,sizeof(tmp));
140 if (j<1) break;
141 done=i=0;
142 if (first) {
143 if (tmp[0]=='0') {
144 carp(service,": no such service.");
145 return;
146 }
147 i+=2;
148 } else {
149 if (!tmp[0] && last=='\n') break;
150 }
151 for (; i<j; ++i)
152 if (!tmp[i]) {
153 tmp[i]=done?0:'\n';
154 if (i<j && !tmp[i+1]) { done=1; --j; }
155 }
156 if (first)
157 write(1,tmp+2,j-2);
158 else
159 write(1,tmp,j);
160 if (done) break;
161 last=tmp[j-1];
162 first=0;
163 }
164}
165
166int main(int argc,char *argv[]) {
167 if (argc<2) {
168 msg(
169 "usage: msvc -[uodpchaitkogC] service\n"
170 " msvc -Ppid service\n"
171 " -u\tup; start service with respawn\n"
172 " -o\tonce; start service without respawn\n"
173 " -d\tdown; disable respawn, stop service\n"
174 " -p\tpause; send SIGSTOP\n"
175 " -c\tcontinue; send SIGCONT\n"
176 " -h\thangup; send SIGHUP\n"
177 " -a\talarm; send SIGALRM\n"
178 " -i\tintr; send SIGINT\n"
179 " -t\tterminate; send SIGTERM\n"
180 " -k\tkill; send SIGKILL\n"
181 " -g\tget; output just the PID\n"
182 " -Ppid\tset PID of service (for pidfilehack)\n"
183 " -D service\tprint services started as dependency\n"
184 " -H\tprint last n respawned services\n"
185 " -C\tClear; remove service form active list\n");
186 return 0;
187 }
188 errmsg_iam("msvc");
189 infd=open(MINITROOT "/in",O_WRONLY);
190 outfd=open(MINITROOT "/out",O_RDONLY);
191 if (infd>=0) {
192 while (lockf(infd,F_LOCK,1)) {
193 carp("could not acquire lock!");
194 sleep(1);
195 }
196 if (argc==2 && argv[1][1]!='H') {
197 pid_t pid=__readpid(argv[1]);
198 if (buf[0]!='0') {
199 unsigned long len;
200 unsigned long ut=uptime(argv[1]);
201
202 if (isatty(1)) {
203 char tmp[FMT_ULONG+20];
204 char tmp2[FMT_ULONG];
205 char* what;
206
207 if (pid==0) what="down "; else
208 if (pid==1) what="finished "; else {
209 len=fmt_str(tmp,"up (pid ");
210 len+=fmt_ulong(tmp+len,pid);
211 tmp[len+fmt_str(tmp+len,") ")]=0;
212 what=tmp;
213 }
214 tmp2[fmt_ulong(tmp2,ut)]=0;
215 msg(argv[1],": ",what,tmp2," seconds");
216 } else {
217 char tmp[FMT_ULONG*2+5];
218 len=fmt_ulong(tmp,pid);
219 tmp[len]=' '; ++len;
220 len+=fmt_ulong(tmp+len,ut);
221 tmp[len]='\n';
222 write(1,tmp,len+1);
223 }
224
225 if (pid==0) return 2; else if (pid==1) return 3; else return 0;
226 } else
227 carp(argv[1],": no such service.");
228 return 1;
229 } else {
230 int i;
231 int ret=0;
232 int sig=0;
233 pid_t pid;
234 if (argv[1][0]=='-') {
235 switch (argv[1][1]) {
236 case 'g':
237 for (i=2; i<argc; ++i) {
238 pid=__readpid(argv[i]);
239 if (pid<2) {
240 carp(argv[i],pid==1?": service terminated":": no such service");
241 ret=1;
242 } else {
243 char tmp[FMT_ULONG];
244 int i;
245 tmp[i=fmt_ulong(tmp,pid)]='\n';
246 write(1,tmp,i+1);
247 }
248 }
249 break;
250 case 'p': sig=SIGSTOP; goto dokill; break;
251 case 'c': sig=SIGCONT; goto dokill; break;
252 case 'h': sig=SIGHUP; goto dokill; break;
253 case 'a': sig=SIGALRM; goto dokill; break;
254 case 'i': sig=SIGINT; goto dokill; break;
255 case 't': sig=SIGTERM; goto dokill; break;
256 case 'k': sig=SIGKILL; goto dokill; break;
257 case 'o':
258 for (i=2; i<argc; ++i)
259 if (startservice(argv[i]) || respawn(argv[i],0)) {
260 carp("Could not start ",argv[i]);
261 ret=1;
262 }
263 break;
264 case 'd':
265 for (i=2; i<argc; ++i) {
266 pid=__readpid(argv[i]);
267 if (pid==0) {
268 carp(argv[i],": no such service");
269 ret=1;
270 } else if (pid==1)
271 continue;
272 else
273 if (respawn(argv[i],0) || kill(pid,SIGTERM) || kill(pid,SIGCONT))
274 carp(argv[i],": failed to send signal");
275 }
276 break;
277 case 'u':
278 for (i=2; i<argc; ++i)
279 if (startservice(argv[i]) || respawn(argv[i],1)) {
280 carp("Could not start ",argv[i]);
281 ret=1;
282 }
283 break;
284 case 'C':
285 for (i=2; i<argc; ++i)
286 if (check_remove(argv[i])) {
287 carp(argv[i]," could not be cleared");
288 ret=1;
289 }
290 break;
291 case 'P':
292 pid=atoi(argv[1]+2);
293 if (pid>1)
294 if (setpid(argv[2],pid)) {
295 carp("Could not set PID of service ",argv[2]);
296 ret=1;
297 }
298 break;
299 case 'H':
300 dumphistory();
301 break;
302 case 'D':
303 dumpdependencies(argv[2]);
304 break;
305 }
306 }
307 return ret;
308dokill:
309 for (i=2; i<argc; i++) {
310 pid=__readpid(argv[i]);
311 if (!pid) {
312 carp(argv[i],": no such service");
313 ret=1;
314 } else if (pid==1) {
315 carp(argv[i],": service not running");
316 ret=1;
317 } else if (kill(pid,sig)) {
318 char tmp[FMT_ULONG];
319 char tmp2[FMT_ULONG];
320 char* s;
321 switch (errno) {
322 case EINVAL: s="invalid signal"; break;
323 case EPERM: s="permission denied"; break;
324 case ESRCH: s="no such pid"; break;
325 default: s="unknown error";
326 }
327 tmp[fmt_ulong(tmp,sig)]=0;
328 tmp2[fmt_ulong(tmp2,pid)]=0;
329 carp(argv[i],": could not send signal ",tmp," to PID ",tmp2,": ",s);
330 ret=1;
331 }
332 }
333 return ret;
334 }
335 } else {
336 carp("minit: could not open " MINITROOT "/in or " MINITROOT "/out");
337 return 1;
338 }
339}