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