unix/minit

msvc.c in master
Repositories | Summary | Log | Files | README | COPYING

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}