| /* 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 */ |