minit

A small yet feature-complete init (http://fefe.de/minit/)
Log | Files | Refs | README | LICENSE

msvc.c (7535B)


      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 
     17 static int infd,outfd;
     18 
     19 static char buf[1500];
     20 
     21 void 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 
     31 int 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 */
     38 pid_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 */
     48 int 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 */
     56 int 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 */
     69 int 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 */
     77 int 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 */
     85 unsigned 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 
     94 void 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 
    129 void 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 
    166 int 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;
    308 dokill:
    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 }