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 }