diff options
Diffstat (limited to 'simpleinit/initctl.c')
-rw-r--r-- | simpleinit/initctl.c | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/simpleinit/initctl.c b/simpleinit/initctl.c new file mode 100644 index 00000000..3b38b496 --- /dev/null +++ b/simpleinit/initctl.c @@ -0,0 +1,217 @@ +/* initctl.c + + Source file for initctl (init(8) control tool). + + Copyright (C) 2000 Richard Gooch + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + Richard Gooch may be reached by email at rgooch@atnf.csiro.au + The postal address is: + Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia. +*/ + +/* + This tool will send control messages to init(8). For example, it may + request init(8) to start a service and will wait for that service to be + available. If the service is already available, init(8) will not start it + again. + This tool may also be used to inspect the list of currently available + services. + + + Written by Richard Gooch 28-FEB-2000 + + Updated by Richard Gooch 11-OCT-2000: Added provide support. + + Last updated by Richard Gooch 6-NOV-2000: Renamed to initctl.c + + +*/ +#include <unistd.h> +#include <stdio.h> +#include <limits.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include "simpleinit.h" + + +static void signal_handler (int sig); + + +static int caught_signal = 0; + + +int main (int argc, char **argv) +{ + int fd, nbytes; + struct sigaction sa; + sigset_t ss; + char *ptr; + long *buffer; + struct command_struct *command; + + buffer = calloc(COMMAND_SIZE / sizeof (long) + 1, sizeof(long)); + if (!buffer) { + fprintf (stderr, "Unable allocate buffer for command\n"); + exit(1); + } + command = (struct command_struct *) buffer; + + sigemptyset (&ss); + sigaddset (&ss, SIG_PRESENT); + sigaddset (&ss, SIG_NOT_PRESENT); + sigaddset (&ss, SIG_FAILED); + sigprocmask (SIG_BLOCK, &ss, NULL); + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = signal_handler; + sigaction (SIG_PRESENT, &sa, NULL); + sigaction (SIG_NOT_PRESENT, &sa, NULL); + sigaction (SIG_FAILED, &sa, NULL); + command->pid = getpid (); + command->ppid = getppid (); + if ( ( ptr = strrchr (argv[0], '/') ) == NULL ) ptr = argv[0]; + else ++ptr; + /* First generate command number by looking at invocation name */ + if (strcmp (ptr, "display-services") == 0) + command->command = COMMAND_DUMP_LIST; + else if (strcmp (ptr, "need") == 0) command->command = COMMAND_NEED; + else if (strcmp (ptr, "provide") == 0) command->command = COMMAND_PROVIDE; + else command->command = COMMAND_TEST; + /* Now check for switches */ + if ( (argc > 1) && (argv[1][0] == '-') ) + { + switch (argv[1][1]) + { + case 'n': + command->command = COMMAND_NEED; + break; + case 'r': + command->command = COMMAND_ROLLBACK; + break; + case 'd': + command->command = COMMAND_DUMP_LIST; + break; + case 'p': + command->command = COMMAND_PROVIDE; + break; + default: + fprintf (stderr, "Illegal switch: \"%s\"\n", argv[1]); + exit (1); + /*break;*/ + } + --argc; + ++argv; + } + switch (command->command) + { + case COMMAND_NEED: + case COMMAND_PROVIDE: + if (argc < 2) + { + fprintf (stderr, "Usage:\tneed|provide programme\n"); + exit (1); + } + /* Fall through */ + case COMMAND_ROLLBACK: + if (argc > 1) strcpy (command->name, argv[1]); + else command->name[0] = '\0'; + break; + case COMMAND_DUMP_LIST: + if (tmpnam (command->name) == NULL) + { + fprintf (stderr, "Unable to create a unique filename\t%s\n", + ERRSTRING); + exit (1); + } + if (mkfifo (command->name, S_IRUSR) != 0) + { + fprintf (stderr, "Unable to create FIFO: \"%s\"\t%s\n", + command->name, ERRSTRING); + exit (1); + } + break; + } + if ( ( fd = open ("/dev/initctl", O_WRONLY, 0) ) < 0 ) + { + fprintf (stderr, "Error opening\t%s\n", ERRSTRING); + exit (1); + } + if (write (fd, buffer, COMMAND_SIZE) < COMMAND_SIZE) + { + fprintf (stderr, "Error writing\t%s\n", ERRSTRING); + exit (1); + } + close (fd); + if (command->command != COMMAND_DUMP_LIST) + { + sigemptyset (&ss); + while (caught_signal == 0) sigsuspend (&ss); + switch (command->command) + { + case COMMAND_PROVIDE: + switch (caught_signal) + { + case SIG_PRESENT: + return 1; + case SIG_NOT_PRESENT: + return 0; + case SIG_NOT_CHILD: + fprintf (stderr, "Error\n"); + return 2; + default: + return 3; + } + break; + default: + switch (caught_signal) + { + case SIG_PRESENT: + return 0; + case SIG_NOT_PRESENT: + return 2; + case SIG_FAILED: + return 1; + default: + return 3; + } + break; + } + return 3; + } + /* Read back the data and display it */ + if ( ( fd = open (command->name, O_RDONLY, 0) ) < 0 ) + { + fprintf (stderr, "Error opening:\"%s\"\t%s\n", + command->name, ERRSTRING); + exit (1); + } + unlink (command->name); + fflush (stdout); + while ( ( nbytes = read (fd, buffer, COMMAND_SIZE) ) > 0 ) + write (1, buffer, nbytes); + close (fd); + return (0); +} /* End Function main */ + +static void signal_handler (int sig) +{ + caught_signal = sig; +} /* End Function signal_handler */ |