diff options
Diffstat (limited to 'init/msvc.c')
-rw-r--r-- | init/msvc.c | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/init/msvc.c b/init/msvc.c new file mode 100644 index 0000000..d72ddce --- /dev/null +++ b/init/msvc.c @@ -0,0 +1,300 @@ +/* + * minit version 0.9.1 by Felix von Leitner + * ported to busybox by Glenn McGrath <bug1@optushome.com.au> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <sys/fcntl.h> +#include <sys/file.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "busybox.h" + +static int infd, outfd; + +static char buf[1500]; + +static unsigned int fmt_ulong(char *dest, unsigned long i) +{ + register unsigned long len, tmp, len2; + + /* first count the number of bytes needed */ + for (len = 1, tmp = i; tmp > 9; ++len) + tmp /= 10; + if (dest) + for (tmp = i, dest += len, len2 = len + 1; --len2; tmp /= 10) + *--dest = (tmp % 10) + '0'; + return len; +} + +static void addservice(char *service) +{ + char *service_ptr; + + if (strncmp(service, "/etc/minit/", 11) == 0) { + service += 11; + } + + while ((service_ptr = last_char_is(service, '/')) != NULL) { + *service_ptr = 0; + } + strncpy(buf + 1, service, 1400); + buf[1400] = 0; +} + +static int addreadwrite(char *service) +{ + addservice(service); + write(infd, buf, strlen(buf)); + return read(outfd, buf, 1500); +} + +/* return PID, 0 if error */ +static pid_t __readpid(char *service) +{ + int len; + + buf[0] = 'p'; + len = addreadwrite(service); + if (len < 0) + return 0; + buf[len] = 0; + return atoi(buf); +} + +/* return nonzero if error */ +static int respawn(char *service, int yesno) +{ + int len; + + buf[0] = yesno ? 'R' : 'r'; + len = addreadwrite(service); + return (len != 1 || buf[0] == '0'); +} + +/* return nonzero if error */ +static int startservice(char *service) +{ + int len; + + buf[0] = 's'; + len = addreadwrite(service); + return (len != 1 || buf[0] == '0'); +} + +extern int msvc_main(int argc, char **argv) +{ + if (argc < 2) { + bb_show_usage(); + } + infd = bb_xopen("/etc/minit/in", O_WRONLY); + outfd = bb_xopen("/etc/minit/out", O_RDONLY); + + while (lockf(infd, F_LOCK, 1)) { + bb_perror_msg("could not aquire lock!\n"); + sleep(1); + } + + if (argc == 2) { + pid_t pid = __readpid(argv[1]); + + if (buf[0] != '0') { + int len; + int up_time; + + printf("%s: ", argv[1]); + if (pid == 0) + printf("down "); + else if (pid == 1) + printf("finished "); + else { + printf("up (pid %d) ", pid); + } + + buf[0] = 'u'; + len = addreadwrite(argv[1]); + if (len < 0) { + up_time = 0; + } else { + buf[len] = 0; + up_time = atoi(buf); + } + printf("%d seconds\n", up_time); + + if (pid == 0) + return 2; + else if (pid == 1) + return 3; + else + return 0; + } else { + bb_error_msg_and_die("no such service"); + } + } else { + int i; + int ret = 0; + int sig = 0; + pid_t pid; + + if (argv[1][0] == '-') { + switch (argv[1][1]) { + case 'g': + for (i = 2; i < argc; ++i) { + pid = __readpid(argv[i]); + if (pid < 2) { + if (pid == 1) { + bb_error_msg("%s, service termination", argv[i]); + } else { + bb_error_msg("%s, no such service", argv[i]); + } + ret = 1; + } + printf("%d\n", pid); + } + break; + case 'p': + sig = SIGSTOP; + goto dokill; + break; + case 'c': + sig = SIGCONT; + goto dokill; + break; + case 'h': + sig = SIGHUP; + goto dokill; + break; + case 'a': + sig = SIGALRM; + goto dokill; + break; + case 'i': + sig = SIGINT; + goto dokill; + break; + case 't': + sig = SIGTERM; + goto dokill; + break; + case 'k': + sig = SIGKILL; + goto dokill; + break; + case 'o': + for (i = 2; i < argc; ++i) + if (startservice(argv[i]) || respawn(argv[i], 0)) { + bb_error_msg("Couldnt not start %s\n", argv[i]); + ret = 1; + } + break; + case 'd': + for (i = 2; i < argc; ++i) { + pid = __readpid(argv[i]); + if (pid == 0) { + bb_error_msg("%s, no such service\n", argv[i]); + ret = 1; + } else if (pid == 1) + continue; + if (respawn(argv[i], 0) || kill(pid, SIGTERM) + || kill(pid, SIGCONT)); + } + break; + case 'u': + for (i = 2; i < argc; ++i) { + if (startservice(argv[i]) || respawn(argv[i], 1)) { + bb_error_msg("Couldnt not start %s\n", argv[i]); + ret = 1; + } + break; + } + case 'C': + for (i = 2; i < argc; ++i) { + int len; + + buf[0] = 'C'; + len = addreadwrite(argv[i]); + if (len != 1 || buf[0] == '0') { + bb_error_msg("%s has terminated or was killed\n", + argv[i]); + ret = 1; + } + } + break; + case 'P': + pid = atoi(argv[1] + 2); + if (pid > 1) { + char *tmp; + int len; + + buf[0] = 'P'; + addservice(argv[2]); + tmp = buf + strlen(buf) + 1; + tmp[fmt_ulong(tmp, pid)] = 0; + write(infd, buf, strlen(buf) + strlen(tmp) + 2); + len = read(outfd, buf, 1500); + if (len != 1 || buf[0] == '0') { + bb_error_msg_and_die("Couldnt not set pid of service %s\n", argv[2]); + } + } + break; + default: + bb_show_usage(); + } + } else { + bb_show_usage(); + } + return ret; +dokill: + for (i = 2; i < argc; i++) { + pid = __readpid(argv[i]); + if (!pid) { + bb_error_msg("%s no such service\n", argv[i]); + ret = 1; + } + if (kill(pid, sig)) { + bb_error_msg("%s, could not send signal %d to PID %d\n", + argv[i], sig, pid); + ret = 1; + } + } + return ret; + } +} + +/* + -u Up. If the service is not running, start it. If the service stops, + restart it. + -d Down. If the service is running, send it a TERM signal and then a CONT + signal. After it stops, do not restart it. + -o Once. If the service is not running, start it. Do not restart it if it + stops. + -r Tell supervise that the service is normally running; this affects status + messages. + -s Tell supervise that the service is normally stopped; this affects status + messages. + -p Pause. Send the service a STOP signal. + -c Continue. Send the service a CONT signal. + -h Hangup. Send the service a HUP signal. + -a Alarm. Send the service an ALRM signal. + -i Interrupt. Send the service an INT signal. + -t Terminate. Send the service a TERM signal. + -k Kill. Send the service a KILL signal. + -x Exit. supervise will quit as soon as the service is down. +*/ |