service.c

Go to the documentation of this file.
00001 /* Utility to start or stop system services.  Requests are sent to the 
00002  * reincarnation server that does the actual work. 
00003  *
00004  * Changes:
00005  *   Jul 22, 2005:      Created  (Jorrit N. Herder)
00006  */
00007 
00008 #include <stdlib.h>
00009 #include <stdio.h>
00010 #include <string.h>
00011 #include <errno.h>
00012 #include <minix/config.h>
00013 #include <minix/com.h>
00014 #include <minix/const.h>
00015 #include <minix/type.h>
00016 #include <minix/ipc.h>
00017 #include <minix/syslib.h>
00018 #include <sys/types.h>
00019 #include <sys/stat.h>
00020 
00021 
00022 /* This array defines all known requests. */
00023 PRIVATE char *known_requests[] = {
00024   "up", 
00025   "down",
00026   "refresh", 
00027   "rescue", 
00028   "shutdown", 
00029   "catch for illegal requests"
00030 };
00031 #define ILLEGAL_REQUEST  sizeof(known_requests)/sizeof(char *)
00032 
00033 /* Global error number set for failed system calls. */
00034 #define OK 0
00035 extern int errno;
00036 
00037 /* Define names for arguments provided to this utility. The first few 
00038  * arguments are required and have a known index. Thereafter, some optional
00039  * argument pairs like "-args arglist" follow.
00040  */
00041 #define ARG_NAME        0               /* own application name */
00042 #define ARG_REQUEST     1               /* request to perform */
00043 #define ARG_PATH        2               /* rescue dir or system service */
00044 #define ARG_PID         2               /* pid of system service */
00045 
00046 #define MIN_ARG_COUNT   2               /* require an action */
00047 
00048 #define ARG_ARGS        "-args"         /* list of arguments to be passed */
00049 #define ARG_DEV         "-dev"          /* major device number for drivers */
00050 #define ARG_PRIV        "-priv"         /* required privileges */
00051 #define ARG_PERIOD      "-period"       /* heartbeat period in ticks */
00052 
00053 /* The function parse_arguments() verifies and parses the command line 
00054  * parameters passed to this utility. Request parameters that are needed
00055  * are stored globally in the following variables:
00056  */
00057 PRIVATE int req_type;
00058 PRIVATE int req_pid;
00059 PRIVATE char *req_path;
00060 PRIVATE char *req_args;
00061 PRIVATE int req_major;
00062 PRIVATE long req_period;
00063 PRIVATE char *req_priv;
00064 
00065 /* Buffer to build "/command arg1 arg2 ..." string to pass to RS server. */
00066 PRIVATE char command[4096];     
00067 
00068 /* An error occurred. Report the problem, print the usage, and exit. 
00069  */
00070 PRIVATE void print_usage(char *app_name, char *problem) 
00071 {
00072   printf("Warning, %s\n", problem);
00073   printf("Usage:\n");
00074   printf("    %s up <binary> [%s <args>] [%s <special>] [%s <ticks>]\n", 
00075         app_name, ARG_ARGS, ARG_DEV, ARG_PERIOD);
00076   printf("    %s down <pid>\n", app_name);
00077   printf("    %s refresh <pid>\n", app_name);
00078   printf("    %s rescue <dir>\n", app_name);
00079   printf("    %s shutdown\n", app_name);
00080   printf("\n");
00081 }
00082 
00083 /* A request to the RS server failed. Report and exit. 
00084  */
00085 PRIVATE void failure(int num) 
00086 {
00087   printf("Request to RS failed: %s (%d)\n", strerror(num), num);
00088   exit(num);
00089 }
00090 
00091 
00092 /* Parse and verify correctness of arguments. Report problem and exit if an 
00093  * error is found. Store needed parameters in global variables.
00094  */
00095 PRIVATE int parse_arguments(int argc, char **argv)
00096 {
00097   struct stat stat_buf;
00098   char *hz;
00099   int req_nr;
00100   int i;
00101 
00102   /* Verify argument count. */ 
00103   if (argc < MIN_ARG_COUNT) {
00104       print_usage(argv[ARG_NAME], "wrong number of arguments");
00105       exit(EINVAL);
00106   }
00107 
00108   /* Verify request type. */
00109   for (req_type=0; req_type< ILLEGAL_REQUEST; req_type++) {
00110       if (strcmp(known_requests[req_type],argv[ARG_REQUEST])==0) break;
00111   }
00112   if (req_type == ILLEGAL_REQUEST) {
00113       print_usage(argv[ARG_NAME], "illegal request type");
00114       exit(ENOSYS);
00115   }
00116   req_nr = RS_RQ_BASE + req_type;
00117 
00118   if (req_nr == RS_UP) {
00119 
00120       /* Verify argument count. */ 
00121       if (argc - 1 < ARG_PATH) {
00122           print_usage(argv[ARG_NAME], "action requires a binary to start");
00123           exit(EINVAL);
00124       }
00125 
00126       /* Verify the name of the binary of the system service. */
00127       req_path = argv[ARG_PATH];
00128       if (req_path[0] != '/') {
00129           print_usage(argv[ARG_NAME], "binary should be absolute path");
00130           exit(EINVAL);
00131       }
00132       if (stat(req_path, &stat_buf) == -1) {
00133           perror(req_path);
00134           fprintf(stderr, "couldn't get stat binary\n");
00135           exit(errno);
00136       }
00137       if (! (stat_buf.st_mode & S_IFREG)) {
00138           print_usage(argv[ARG_NAME], "binary is not a regular file");
00139           exit(EINVAL);
00140       }
00141 
00142       /* Check optional arguments that come in pairs like "-args arglist". */
00143       for (i=MIN_ARG_COUNT+1; i<argc; i=i+2) {
00144           if (! (i+1 < argc)) {
00145               print_usage(argv[ARG_NAME], "optional argument not complete");
00146               exit(EINVAL);
00147           }
00148           if (strcmp(argv[i], ARG_ARGS)==0) {
00149               req_args = argv[i+1];
00150           }
00151           else if (strcmp(argv[i], ARG_PERIOD)==0) {
00152               req_period = strtol(argv[i+1], &hz, 10);
00153               if (strcmp(hz,"HZ")==0) req_period *= HZ;
00154               if (req_period < 1) {
00155                   print_usage(argv[ARG_NAME], "period is at least be one tick");
00156                   exit(EINVAL);
00157               }
00158           }
00159           else if (strcmp(argv[i], ARG_DEV)==0) {
00160               if (stat(argv[i+1], &stat_buf) == -1) {
00161                   print_usage(argv[ARG_NAME], "couldn't get status of device");
00162                   exit(errno);
00163               }
00164               if ( ! (stat_buf.st_mode & (S_IFBLK | S_IFCHR))) {
00165                   print_usage(argv[ARG_NAME], "special file is not a device");
00166                   exit(EINVAL);
00167               } 
00168               req_major = (stat_buf.st_rdev >> MAJOR) & BYTE;
00169           }
00170           else if (strcmp(argv[i], ARG_ARGS)==0) {
00171               req_priv = argv[i+1];
00172           }
00173           else {
00174               print_usage(argv[ARG_NAME], "unknown optional argument given");
00175               exit(EINVAL);
00176           }
00177       }
00178   }
00179   else if (req_nr == RS_DOWN || req_nr == RS_REFRESH) {
00180 
00181       /* Verify argument count. */ 
00182       if (argc - 1 < ARG_PID) {
00183           print_usage(argv[ARG_NAME], "action requires a pid to stop");
00184           exit(EINVAL);
00185       }
00186       if (! (req_pid = atoi(argv[ARG_PID])) > 0) {
00187           print_usage(argv[ARG_NAME], "pid must be greater than zero");
00188           exit(EINVAL);
00189       }
00190   } 
00191   else if (req_nr == RS_RESCUE) {
00192 
00193       /* Verify argument count. */ 
00194       if (argc - 1 < ARG_PATH) {
00195           print_usage(argv[ARG_NAME], "action requires rescue directory");
00196           exit(EINVAL);
00197       }
00198       req_path = argv[ARG_PATH];
00199       if (req_path[0] != '/') {
00200           print_usage(argv[ARG_NAME], "rescue dir should be absolute path");
00201           exit(EINVAL);
00202       }
00203       if (stat(argv[ARG_PATH], &stat_buf) == -1) {
00204           print_usage(argv[ARG_NAME], "couldn't get status of directory");
00205           exit(errno);
00206       }
00207       if ( ! (stat_buf.st_mode & S_IFDIR)) {
00208           print_usage(argv[ARG_NAME], "file is not a directory");
00209           exit(EINVAL);
00210       } 
00211   } 
00212   else if (req_nr == RS_SHUTDOWN) {
00213         /* no extra arguments required */
00214   }
00215 
00216   /* Return the request number if no error were found. */
00217   return(req_nr);
00218 }
00219 
00220 
00221 /* Main program. 
00222  */
00223 PUBLIC int main(int argc, char **argv)
00224 {
00225   message m;
00226   int result;
00227   int request;
00228   int s;
00229 
00230   /* Verify and parse the command line arguments. All arguments are checked
00231    * here. If an error occurs, the problem is reported and exit(2) is called. 
00232    * all needed parameters to perform the request are extracted and stored
00233    * global variables. 
00234    */
00235   request = parse_arguments(argc, argv);
00236 
00237   /* Arguments seem fine. Try to perform the request. Only valid requests 
00238    * should end up here. The default is used for not yet supported requests. 
00239    */
00240   switch(request) {
00241   case RS_UP:
00242       /* Build space-separated command string to be passed to RS server. */
00243       strcpy(command, req_path);
00244       command[strlen(req_path)] = ' ';
00245       strcpy(command+strlen(req_path)+1, req_args);
00246 
00247       /* Build request message and send the request. */
00248       m.RS_CMD_ADDR = command;
00249       m.RS_CMD_LEN = strlen(command);
00250       m.RS_DEV_MAJOR = req_major;
00251       m.RS_PERIOD = req_period;
00252       if (OK != (s=_taskcall(RS_PROC_NR, request, &m))) 
00253           failure(s);
00254       result = m.m_type;
00255       break;
00256   case RS_DOWN:
00257   case RS_REFRESH:
00258       m.RS_PID = req_pid;
00259       if (OK != (s=_taskcall(RS_PROC_NR, request, &m))) 
00260           failure(s);
00261       break;
00262   case RS_RESCUE:
00263       m.RS_CMD_ADDR = req_path;
00264       m.RS_CMD_LEN = strlen(req_path);
00265       if (OK != (s=_taskcall(RS_PROC_NR, request, &m))) 
00266           failure(s);
00267       break;
00268   case RS_SHUTDOWN:
00269       if (OK != (s=_taskcall(RS_PROC_NR, request, &m))) 
00270           failure(s);
00271       break;
00272   default:
00273       print_usage(argv[ARG_NAME], "request is not yet supported");
00274       result = EGENERIC;
00275   }
00276   return(result);
00277 }
00278 

Generated on Fri Apr 14 22:57:32 2006 for minix by  doxygen 1.4.6