1 /* Utility to start or stop system services. Requests are sent to the 2 * reincarnation server that does the actual work. 3 * 4 * Changes: 5 * Nov 22, 2009: added basic live update support (Cristiano Giuffrida) 6 * Jul 22, 2005: Created (Jorrit N. Herder) 7 */ 8 9 #include <stdarg.h> 10 #include <assert.h> 11 #include <stdlib.h> 12 #include <stdio.h> 13 #include <string.h> 14 #include <errno.h> 15 #include <pwd.h> 16 #include <unistd.h> 17 #include <limits.h> 18 #include <lib.h> 19 #include <minix/config.h> 20 #include <minix/com.h> 21 #include <minix/const.h> 22 #include <minix/type.h> 23 #include <minix/ipc.h> 24 #include <minix/rs.h> 25 #include <minix/syslib.h> 26 #include <minix/sysinfo.h> 27 #include <minix/bitmap.h> 28 #include <minix/paths.h> 29 #include <minix/sef.h> 30 #include <minix/dmap.h> 31 #include <sys/types.h> 32 #include <sys/stat.h> 33 #include <configfile.h> 34 35 #include <machine/archtypes.h> 36 #include <minix/timers.h> 37 #include <err.h> 38 39 #include "config.h" 40 #include "proto.h" 41 42 /* This array defines all known requests. */ 43 static char *known_requests[] = { 44 "up", 45 "down", 46 "refresh", 47 "restart", 48 "shutdown", 49 "update", 50 "clone", 51 "unclone", 52 "edit", 53 "sysctl", 54 "fi", 55 "catch for illegal requests" 56 }; 57 static int known_request_types[] = { 58 RS_UP, 59 RS_DOWN, 60 RS_REFRESH, 61 RS_RESTART, 62 RS_SHUTDOWN, 63 RS_UPDATE, 64 RS_CLONE, 65 RS_UNCLONE, 66 RS_EDIT, 67 RS_SYSCTL, 68 RS_FI, 69 0 70 }; 71 #define ILLEGAL_REQUEST sizeof(known_requests)/sizeof(char *) 72 73 /* Global error number set for failed system calls. */ 74 #define OK 0 75 76 #define RUN_CMD "run" 77 #define RUN_SCRIPT "/etc/rs.single" /* Default script for 'run' */ 78 #define SELF_BINARY "self" 79 #define SELF_REQ_PATH "/dev/null" 80 #define PATH_CONFIG _PATH_SYSTEM_CONF /* Default config file */ 81 #define DEFAULT_LU_STATE SEF_LU_STATE_WORK_FREE /* Default lu state */ 82 #define DEFAULT_LU_MAXTIME 0 /* Default lu max time */ 83 84 /* Define names for options provided to this utility. */ 85 #define OPT_COPY "-c" /* copy executable image */ 86 #define OPT_REUSE "-r" /* reuse executable image */ 87 #define OPT_NOBLOCK "-n" /* unblock caller immediately */ 88 #define OPT_REPLICA "-p" /* create replica for the service */ 89 #define OPT_NO_BIN_EXP "-b" /* no binary exponential backoff */ 90 #define OPT_BATCH "-q" /* batch mode */ 91 #define OPT_ASR_LU "-a" /* asr update */ 92 #define OPT_PREPARE_ONLY_LU "-o" /* prepare-only update */ 93 #define OPT_FORCE_SELF_LU "-s" /* force self update */ 94 #define OPT_FORCE_INIT_CRASH "-x" /* force init crash (for debugging) */ 95 #define OPT_FORCE_INIT_FAIL "-y" /* force init failure (for debugging) */ 96 #define OPT_FORCE_INIT_TIMEOUT "-z" /* force init timeout (for debugging) */ 97 #define OPT_FORCE_INIT_DEFCB "-d" /* force init default callback */ 98 #define OPT_NOMMAP_LU "-m" /* don't inherit mmaped regions */ 99 #define OPT_DETACH "-e" /* detach on update/restart */ 100 #define OPT_NORESTART "-f" /* don't restart */ 101 #define OPT_FORCE_INIT_ST "-t" /* force init state transfer */ 102 103 /* Define names for arguments provided to this utility. The first few 104 * arguments are required and have a known index. Thereafter, some optional 105 * argument pairs like "-args arglist" follow. 106 */ 107 #define ARG_NAME 0 /* own application name */ 108 109 /* The following are relative to optind */ 110 #define ARG_REQUEST 0 /* request to perform */ 111 #define ARG_PATH 1 /* system service */ 112 #define ARG_LABEL 1 /* name of system service */ 113 #define ARG_SYSCTL_TYPE 1 /* sysctl action type */ 114 115 116 #define MIN_ARG_COUNT 1 /* require an action */ 117 118 #define ARG_ARGS "-args" /* list of arguments to be passed */ 119 #define ARG_DEV "-dev" /* major device number for drivers */ 120 #define ARG_MAJOR "-major" /* major number */ 121 #define ARG_PERIOD "-period" /* heartbeat period in ticks */ 122 #define ARG_SCRIPT "-script" /* name of the script to restart a 123 * system service 124 */ 125 #define ARG_LABELNAME "-label" /* custom label name */ 126 #define ARG_PROGNAME "-progname" /* custom program name */ 127 #define ARG_CONFIG "-config" /* name of the file with the resource 128 * configuration 129 */ 130 131 #define ARG_LU_STATE "-state" /* the live update state required */ 132 #define ARG_LU_MAXTIME "-maxtime" /* max time to prepare for the update */ 133 #define ARG_DEVMANID "-devid" /* the id of the devman device this 134 driver should be able to access */ 135 #define ARG_HEAP_PREALLOC "-heap-prealloc" /* preallocate heap regions */ 136 #define ARG_MAP_PREALLOC "-map-prealloc" /* preallocate mmapped regions */ 137 #define ARG_TRG_LABELNAME "-trg-label" /* target label name */ 138 #define ARG_LU_IPC_BL "-ipc_bl" /* IPC blacklist filter */ 139 #define ARG_LU_IPC_WL "-ipc_wl" /* IPC whitelist filter */ 140 #define ARG_ASR_COUNT "-asr-count" /* number of ASR live updates */ 141 #define ARG_RESTARTS "-restarts" /* number of restarts */ 142 143 /* The function parse_arguments() verifies and parses the command line 144 * parameters passed to this utility. Request parameters that are needed 145 * are stored globally in the following variables: 146 */ 147 static int req_type; 148 static int do_run= 0; /* 'run' command instead of 'up' */ 149 static char *req_label = NULL; 150 static char *req_trg_label = NULL; 151 static char *req_path = NULL; 152 static char *req_path_self = SELF_REQ_PATH; 153 static char *req_progname = NULL; 154 static char *req_args = ""; 155 static int req_major = 0; 156 static int devman_id = 0; 157 static long req_period = 0; 158 static char *req_script = NULL; 159 static char *req_config = PATH_CONFIG; 160 static int custom_config_file = 0; 161 static int req_lu_state = DEFAULT_LU_STATE; 162 static int req_lu_maxtime = DEFAULT_LU_MAXTIME; 163 static int req_restarts = 0; 164 static int req_asr_count = -1; 165 static long req_heap_prealloc = 0; 166 static long req_map_prealloc = 0; 167 static int req_sysctl_type = 0; 168 static struct rs_ipc_filter_el rs_ipc_filter_els[RS_MAX_IPC_FILTERS][IPCF_MAX_ELEMENTS]; 169 static int num_ipc_filters = 0; 170 static char *req_state_eval = NULL; 171 172 /* Buffer to build "/command arg1 arg2 ..." string to pass to RS server. */ 173 static char command[4096]; 174 175 /* An error occurred. Report the problem, print the usage, and exit. 176 */ 177 static void print_usage(char *app_name, char *problem) 178 { 179 fprintf(stderr, "Warning, %s\n", problem); 180 fprintf(stderr, "Usage:\n"); 181 fprintf(stderr, 182 " %s [%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s] (up|run|edit|update) <binary|%s> [%s <args>] [%s <special>] [%s <major_nr>] [%s <dev_id>] [%s <ticks>] [%s <path>] [%s <name>] [%s <name>] [%s <path>] [%s <state value|eval_expression>] [%s <time>] [%s <bytes>] [%s <bytes>] [%s <name>] [(%s|%s <src_label1,src_type1:src_label2,:,src_type3:...>)*] [%s <count>] [%s <restarts>]\n", 183 app_name, OPT_COPY, OPT_REUSE, OPT_NOBLOCK, OPT_REPLICA, OPT_NO_BIN_EXP, 184 OPT_BATCH, OPT_ASR_LU, OPT_PREPARE_ONLY_LU, OPT_FORCE_SELF_LU, 185 OPT_FORCE_INIT_CRASH, OPT_FORCE_INIT_FAIL, OPT_FORCE_INIT_TIMEOUT, 186 OPT_FORCE_INIT_DEFCB, OPT_NOMMAP_LU, OPT_DETACH, 187 OPT_NORESTART, OPT_FORCE_INIT_ST, SELF_BINARY, 188 ARG_ARGS, ARG_DEV, ARG_MAJOR, ARG_DEVMANID, ARG_PERIOD, 189 ARG_SCRIPT, ARG_LABELNAME, ARG_PROGNAME, ARG_CONFIG, ARG_LU_STATE, ARG_LU_MAXTIME, 190 ARG_HEAP_PREALLOC, ARG_MAP_PREALLOC, ARG_TRG_LABELNAME, ARG_LU_IPC_BL, ARG_LU_IPC_WL, 191 ARG_ASR_COUNT, ARG_RESTARTS); 192 fprintf(stderr, " %s down <label>\n", app_name); 193 fprintf(stderr, " %s refresh <label>\n", app_name); 194 fprintf(stderr, " %s restart <label>\n", app_name); 195 fprintf(stderr, " %s clone <label>\n", app_name); 196 fprintf(stderr, " %s unclone <label>\n", app_name); 197 fprintf(stderr, " %s fi <label>\n", app_name); 198 fprintf(stderr, " %s sysctl <srv_status|upd_start|upd_run|upd_stop|upd_status>\n", app_name); 199 fprintf(stderr, " %s shutdown\n", app_name); 200 fprintf(stderr, " Options:\n"); 201 fprintf(stderr, " %s: copy executable image \n", OPT_COPY); 202 fprintf(stderr, " %s: reuse executable image \n", OPT_REUSE); 203 fprintf(stderr, " %s: unblock caller immediately \n", OPT_NOBLOCK); 204 fprintf(stderr, " %s: create replica for the service \n", OPT_REPLICA); 205 fprintf(stderr, " %s: batch mode \n", OPT_BATCH); 206 fprintf(stderr, " %s: asr update \n", OPT_ASR_LU); 207 fprintf(stderr, " %s: prepare-only update \n", OPT_PREPARE_ONLY_LU); 208 fprintf(stderr, " %s: force self update \n", OPT_FORCE_SELF_LU); 209 fprintf(stderr, " %s: force init crash (for debugging) \n", OPT_FORCE_INIT_CRASH); 210 fprintf(stderr, " %s: force init failure (for debugging)\n", OPT_FORCE_INIT_FAIL); 211 fprintf(stderr, " %s: force init timeout (for debugging)\n", OPT_FORCE_INIT_TIMEOUT); 212 fprintf(stderr, " %s: force init default callback \n", OPT_FORCE_INIT_DEFCB); 213 fprintf(stderr, " %s: don't inherit mmaped regions \n", OPT_NOMMAP_LU); 214 fprintf(stderr, " %s: detach on update/restart \n", OPT_DETACH); 215 fprintf(stderr, " %s: don't restart \n", OPT_NORESTART); 216 fprintf(stderr, " %s: force init state transfer \n", OPT_FORCE_INIT_ST); 217 218 fprintf(stderr, "\n"); 219 } 220 221 /* A request to the RS server failed. Report and exit. 222 */ 223 static void failure(int request) 224 { 225 fprintf(stderr, "Request 0x%x to RS failed: %s (error %d)\n", request, strerror(errno), errno); 226 exit(errno); 227 } 228 229 static int parse_ipc_filter(char* str, int type_flag) 230 { 231 char *el_str, *label_str, *type_str; 232 char el_strings[IPCF_MAX_ELEMENTS][RS_MAX_IPCF_STR_LEN]; 233 int i, num_els, label_len, type_len; 234 struct rs_ipc_filter_el *ipcf_el; 235 if(num_ipc_filters+1 > RS_MAX_IPC_FILTERS) { 236 return E2BIG; 237 } 238 el_str = (char*) strsep(&str,":"); 239 num_els = 0; 240 while (el_str != NULL) 241 { 242 if(num_els >= IPCF_MAX_ELEMENTS) { 243 return E2BIG; 244 } 245 if(strlen(el_str)>=RS_MAX_IPCF_STR_LEN) { 246 return ENOMEM; 247 } 248 strcpy(el_strings[num_els], el_str); 249 el_str = (char*) strsep(&str, ":"); 250 num_els++; 251 } 252 memset(rs_ipc_filter_els[num_ipc_filters],0,IPCF_MAX_ELEMENTS); 253 for(i=0;i<num_els;i++) { 254 el_str = el_strings[i]; 255 ipcf_el = &rs_ipc_filter_els[num_ipc_filters][i]; 256 label_str = (char*) strsep(&el_str,","); 257 type_str = (char*) strsep(&el_str,","); 258 if(!label_str || !type_str || strsep(&el_str,",")) { 259 return EINVAL; 260 } 261 label_len = strlen(label_str); 262 type_len = strlen(type_str); 263 ipcf_el->flags = 0; 264 if(label_len>0) { 265 if(label_len >= RS_MAX_LABEL_LEN) { 266 return ENOMEM; 267 } 268 strcpy(ipcf_el->m_label, label_str); 269 ipcf_el->flags |= IPCF_MATCH_M_SOURCE; 270 } 271 if(type_len>0) { 272 char *buff; 273 errno=0; 274 ipcf_el->m_type = strtol(type_str, &buff, 10); 275 if(errno || strcmp(buff, "")) { 276 return EINVAL; 277 } 278 ipcf_el->flags |= IPCF_MATCH_M_TYPE; 279 } 280 if(ipcf_el->flags == 0) { 281 return EINVAL; 282 } 283 ipcf_el->flags |= type_flag; 284 } 285 num_ipc_filters++; 286 return OK; 287 } 288 289 /* Parse and verify correctness of arguments. Report problem and exit if an 290 * error is found. Store needed parameters in global variables. 291 */ 292 static int parse_arguments(int argc, char **argv, u32_t *rss_flags) 293 { 294 struct stat stat_buf; 295 char *hz, *buff; 296 int req_nr; 297 int c, i, j, r; 298 int b_flag, c_flag, r_flag, n_flag, p_flag, q_flag, 299 a_flag, o_flag, s_flag, x_flag, y_flag, 300 z_flag, d_flag, u_flag, m_flag, e_flag, 301 f_flag, t_flag; 302 int label_required; 303 304 b_flag = 0; 305 c_flag = 0; 306 r_flag = 0; 307 n_flag = 0; 308 p_flag = 0; 309 q_flag = 0; 310 a_flag = 0; 311 o_flag = 0; 312 s_flag = 0; 313 x_flag = 0; 314 y_flag = 0; 315 z_flag = 0; 316 d_flag = 0; 317 u_flag = 0; 318 m_flag = 0; 319 e_flag = 0; 320 f_flag = 0; 321 t_flag = 0; 322 while (c= getopt(argc, argv, "rbcnpqaosxyzdumeft?"), c != -1) 323 { 324 switch(c) 325 { 326 case '?': 327 print_usage(argv[ARG_NAME], "wrong number of arguments"); 328 exit(EINVAL); 329 case 'b': 330 b_flag = 1; 331 break; 332 case 'c': 333 c_flag = 1; 334 break; 335 case 'r': 336 c_flag = 1; /* -r implies -c */ 337 r_flag = 1; 338 break; 339 case 'n': 340 n_flag = 1; 341 break; 342 case 'p': 343 p_flag = 1; 344 break; 345 case 'q': 346 q_flag = 1; 347 break; 348 case 'a': 349 a_flag = 1; 350 break; 351 case 'o': 352 o_flag = 1; 353 break; 354 case 's': 355 s_flag = 1; 356 break; 357 case 'x': 358 x_flag = 1; 359 break; 360 case 'y': 361 y_flag = 1; 362 break; 363 case 'z': 364 z_flag = 1; 365 break; 366 case 'd': 367 d_flag = 1; 368 break; 369 case 'u': 370 u_flag = 1; 371 break; 372 case 'm': 373 m_flag = 1; 374 break; 375 case 'e': 376 e_flag = 1; 377 break; 378 case 'f': 379 f_flag = 1; 380 break; 381 case 't': 382 t_flag = 1; 383 break; 384 default: 385 fprintf(stderr, "%s: getopt failed: %c\n", 386 argv[ARG_NAME], c); 387 exit(1); 388 } 389 } 390 391 /* Verify argument count. */ 392 if (argc < optind+MIN_ARG_COUNT) { 393 print_usage(argv[ARG_NAME], "wrong number of arguments"); 394 exit(EINVAL); 395 } 396 397 if (strcmp(argv[optind+ARG_REQUEST], RUN_CMD) == 0) 398 { 399 req_nr= RS_UP; 400 do_run= TRUE; 401 } 402 else 403 { 404 /* Verify request type. */ 405 for (req_type=0; req_type< ILLEGAL_REQUEST; req_type++) { 406 if (strcmp(known_requests[req_type],argv[optind+ARG_REQUEST])==0) 407 break; 408 } 409 if (req_type == ILLEGAL_REQUEST) { 410 print_usage(argv[ARG_NAME], "illegal request type"); 411 exit(ENOSYS); 412 } 413 req_nr = known_request_types[req_type]; 414 } 415 416 *rss_flags = 0; 417 if (req_nr == RS_UP || req_nr == RS_UPDATE || req_nr == RS_EDIT) { 418 u32_t system_hz; 419 420 if (c_flag) 421 *rss_flags |= RSS_COPY; 422 423 if(r_flag) 424 *rss_flags |= RSS_REUSE; 425 426 if(n_flag) 427 *rss_flags |= RSS_NOBLOCK; 428 429 if(p_flag) 430 *rss_flags |= RSS_REPLICA; 431 432 if(b_flag) 433 *rss_flags |= RSS_NO_BIN_EXP; 434 435 if(q_flag) 436 *rss_flags |= RSS_BATCH; 437 438 if(a_flag) 439 *rss_flags |= RSS_ASR_LU; 440 441 if(s_flag) 442 *rss_flags |= RSS_FORCE_SELF_LU; 443 444 if(o_flag) 445 *rss_flags |= RSS_PREPARE_ONLY_LU; 446 447 if(x_flag) 448 *rss_flags |= RSS_FORCE_INIT_CRASH; 449 450 if(y_flag) 451 *rss_flags |= RSS_FORCE_INIT_FAIL; 452 453 if(z_flag) 454 *rss_flags |= RSS_FORCE_INIT_TIMEOUT; 455 456 if(d_flag) 457 *rss_flags |= RSS_FORCE_INIT_DEFCB; 458 459 if(m_flag) 460 *rss_flags |= RSS_NOMMAP_LU; 461 462 if(e_flag) 463 *rss_flags |= RSS_DETACH; 464 465 if(f_flag) 466 *rss_flags |= RSS_NORESTART; 467 468 if(t_flag) 469 *rss_flags |= RSS_FORCE_INIT_ST; 470 471 /* Verify argument count. */ 472 if (argc - 1 < optind+ARG_PATH) { 473 print_usage(argv[ARG_NAME], "action requires a binary to start"); 474 exit(EINVAL); 475 } 476 477 if(req_nr != RS_UPDATE && q_flag) { 478 print_usage(argv[ARG_NAME], "action does not support batch mode"); 479 exit(EINVAL); 480 } 481 482 req_path = argv[optind+ARG_PATH]; 483 if(req_nr == RS_UPDATE && !strcmp(req_path, SELF_BINARY)) { 484 /* Self update needs no real path or configuration file. */ 485 req_config = NULL; 486 req_path = req_path_self; 487 *rss_flags |= RSS_SELF_LU; 488 } 489 490 if (do_run) 491 { 492 /* Set default recovery script for RUN */ 493 req_script = RUN_SCRIPT; 494 } 495 496 /* Verify the name of the binary of the system service. */ 497 if(!(*rss_flags & RSS_SELF_LU)) { 498 if (req_path[0] != '/') { 499 print_usage(argv[ARG_NAME], "binary should be absolute path"); 500 exit(EINVAL); 501 } 502 if (stat(req_path, &stat_buf) == -1) { 503 perror(req_path); 504 fprintf(stderr, "%s: couldn't get stat binary\n", argv[ARG_NAME]); 505 exit(errno); 506 } 507 if (! (stat_buf.st_mode & S_IFREG)) { 508 print_usage(argv[ARG_NAME], "binary is not a regular file"); 509 exit(EINVAL); 510 } 511 } 512 513 /* Get HZ. */ 514 system_hz = (u32_t) sysconf(_SC_CLK_TCK); 515 516 /* Check optional arguments that come in pairs like "-args arglist". */ 517 for (i=optind+MIN_ARG_COUNT+1; i<argc; i=i+2) { 518 if (! (i+1 < argc)) { 519 print_usage(argv[ARG_NAME], "optional argument not complete"); 520 exit(EINVAL); 521 } 522 if (strcmp(argv[i], ARG_ARGS)==0) { 523 req_args = argv[i+1]; 524 } 525 else if (strcmp(argv[i], ARG_PERIOD)==0) { 526 req_period = strtol(argv[i+1], &hz, 10); 527 if (strcmp(hz,"HZ")==0) req_period *= system_hz; 528 if (req_period < 0) { 529 print_usage(argv[ARG_NAME], "bad period argument"); 530 exit(EINVAL); 531 } 532 } 533 else if (strcmp(argv[i], ARG_DEV)==0) { 534 if (stat(argv[i+1], &stat_buf) == -1) { 535 perror(argv[i+1]); 536 print_usage(argv[ARG_NAME], "couldn't get status of device"); 537 exit(errno); 538 } 539 if ( ! (stat_buf.st_mode & (S_IFBLK | S_IFCHR))) { 540 print_usage(argv[ARG_NAME], "special file is not a device"); 541 exit(EINVAL); 542 } 543 if (req_major != 0) { 544 print_usage(argv[ARG_NAME], "major already set"); 545 exit(EINVAL); 546 } 547 req_major = major(stat_buf.st_rdev); 548 } 549 else if (strcmp(argv[i], ARG_MAJOR)==0) { 550 if (req_major != 0) { 551 print_usage(argv[ARG_NAME], "major already set"); 552 exit(EINVAL); 553 } 554 if (i+1 < argc) { 555 req_major = atoi(argv[i+1]); 556 } else { 557 exit(EINVAL); 558 } 559 } 560 else if (strcmp(argv[i], ARG_SCRIPT)==0) { 561 req_script = argv[i+1]; 562 } 563 else if (strcmp(argv[i], ARG_LABELNAME)==0) { 564 req_label = argv[i+1]; 565 } 566 else if (strcmp(argv[i], ARG_TRG_LABELNAME)==0) { 567 req_trg_label = argv[i+1]; 568 } 569 else if (strcmp(argv[i], ARG_PROGNAME)==0) { 570 req_progname = argv[i+1]; 571 } 572 else if (strcmp(argv[i], ARG_CONFIG)==0) { 573 req_config = argv[i+1]; 574 custom_config_file = 1; 575 } 576 else if (strcmp(argv[i], ARG_LU_STATE)==0) { 577 errno=0; 578 req_lu_state = strtol(argv[i+1], &buff, 10); 579 if(errno || strcmp(buff, "")) { 580 /* State is not a number, assume it's an eval expression. */ 581 req_lu_state = SEF_LU_STATE_EVAL; 582 req_state_eval = argv[i+1]; 583 } 584 else if(req_lu_state == SEF_LU_STATE_NULL) { 585 print_usage(argv[ARG_NAME], "null live update state"); 586 exit(EINVAL); 587 } 588 } 589 else if (strcmp(argv[i], ARG_LU_MAXTIME)==0) { 590 errno=0; 591 req_lu_maxtime = strtol(argv[i+1], &hz, 10); 592 if(errno || (strcmp(hz, "") && strcmp(hz, "HZ")) 593 || req_lu_maxtime<0) { 594 print_usage(argv[ARG_NAME], 595 "bad live update max time"); 596 exit(EINVAL); 597 } 598 if(req_lu_maxtime == 0) { 599 /* no timeout requested. */ 600 req_lu_maxtime = -1; 601 } 602 else if (strcmp(hz,"HZ")==0) req_lu_maxtime *= system_hz; 603 } 604 else if (strcmp(argv[i], ARG_DEVMANID) == 0) { 605 if (i+1 < argc) { 606 devman_id = atoi(argv[i+1]); 607 } else { 608 exit(EINVAL); 609 } 610 } 611 else if (strcmp(argv[i], ARG_HEAP_PREALLOC)==0) { 612 errno=0; 613 req_heap_prealloc = strtol(argv[i+1], &buff, 10); 614 if(errno || strcmp(buff, "") || req_heap_prealloc <= 0) { 615 print_usage(argv[ARG_NAME], "bad heap prealloc bytes"); 616 exit(EINVAL); 617 } 618 } 619 else if (strcmp(argv[i], ARG_MAP_PREALLOC)==0) { 620 errno=0; 621 req_map_prealloc = strtol(argv[i+1], &buff, 10); 622 if(errno || strcmp(buff, "") || req_map_prealloc <= 0) { 623 print_usage(argv[ARG_NAME], "bad heap prealloc bytes"); 624 exit(EINVAL); 625 } 626 } 627 else if (strcmp(argv[i], ARG_LU_IPC_BL)==0) { 628 if((r=parse_ipc_filter(argv[i+1], IPCF_EL_BLACKLIST)) != OK) { 629 print_usage(argv[ARG_NAME], "bad IPC blacklist filter"); 630 exit(r); 631 } 632 } 633 else if (strcmp(argv[i], ARG_LU_IPC_WL)==0) { 634 if((r=parse_ipc_filter(argv[i+1], IPCF_EL_WHITELIST)) != OK) { 635 print_usage(argv[ARG_NAME], "bad IPC whitelist filter"); 636 exit(r); 637 } 638 } 639 else if (strcmp(argv[i], ARG_ASR_COUNT)==0) { 640 errno=0; 641 req_asr_count = strtol(argv[i+1], &buff, 10); 642 if(errno || strcmp(buff, "") || req_asr_count<0) { 643 print_usage(argv[ARG_NAME], "bad ASR count"); 644 exit(EINVAL); 645 } 646 } 647 else if (strcmp(argv[i], ARG_RESTARTS)==0) { 648 errno=0; 649 req_restarts = strtol(argv[i+1], &buff, 10); 650 if(errno || strcmp(buff, "") || req_restarts<0) { 651 print_usage(argv[ARG_NAME], "bad number of restarts"); 652 exit(EINVAL); 653 } 654 } 655 else { 656 print_usage(argv[ARG_NAME], "unknown optional argument given"); 657 exit(EINVAL); 658 } 659 } 660 } 661 else if (req_nr == RS_DOWN || req_nr == RS_REFRESH || req_nr == RS_RESTART 662 || req_nr == RS_CLONE || req_nr == RS_UNCLONE || req_nr == RS_FI) { 663 664 /* Verify argument count. */ 665 if (argc - 1 < optind+ARG_LABEL) { 666 print_usage(argv[ARG_NAME], "action requires a target label"); 667 exit(EINVAL); 668 } 669 req_label= argv[optind+ARG_LABEL]; 670 } 671 else if (req_nr == RS_SYSCTL) { 672 char* sysctl_types[] = { "srv_status", "upd_start", "upd_run", "upd_stop", 673 "upd_status", NULL }; 674 char* sysctl_type; 675 int sysctl_type_values[] = { RS_SYSCTL_SRV_STATUS, RS_SYSCTL_UPD_START, 676 RS_SYSCTL_UPD_RUN, RS_SYSCTL_UPD_STOP, RS_SYSCTL_UPD_STATUS }; 677 678 /* Verify argument count. */ 679 if (argc - 1 < optind+ARG_SYSCTL_TYPE) { 680 print_usage(argv[ARG_NAME], "sysctl requires an action type"); 681 exit(EINVAL); 682 } 683 684 sysctl_type = argv[optind+ARG_SYSCTL_TYPE]; 685 for(i=0;sysctl_types[i]!=NULL;i++) { 686 if(!strcmp(sysctl_types[i], sysctl_type)) { 687 break; 688 } 689 } 690 if(sysctl_types[i] == NULL) { 691 print_usage(argv[ARG_NAME], "bad sysctl type"); 692 exit(EINVAL); 693 } 694 req_sysctl_type = sysctl_type_values[i]; 695 } 696 else if (req_nr == RS_SHUTDOWN) { 697 /* no extra arguments required */ 698 } 699 700 label_required = (*rss_flags & RSS_SELF_LU) || (req_nr == RS_EDIT); 701 if(label_required && !req_label) { 702 print_usage(argv[ARG_NAME], "label option mandatory for target action"); 703 exit(EINVAL); 704 } 705 706 /* Return the request number if no error were found. */ 707 return(req_nr); 708 } 709 710 /* Main program. 711 */ 712 int main(int argc, char **argv) 713 { 714 message m; 715 int result = EXIT_SUCCESS; 716 int request; 717 char *progname = NULL; 718 /* Arguments for RS to start a new service */ 719 struct rs_config config; 720 u32_t rss_flags = 0; 721 722 /* Verify and parse the command line arguments. All arguments are checked 723 * here. If an error occurs, the problem is reported and exit(2) is called. 724 * all needed parameters to perform the request are extracted and stored 725 * global variables. 726 */ 727 request = parse_arguments(argc, argv, &rss_flags); 728 729 /* Arguments seem fine. Try to perform the request. Only valid requests 730 * should end up here. The default is used for not yet supported requests. 731 */ 732 result = OK; 733 memset(&m, 0, sizeof(m)); 734 switch(request) { 735 case RS_UPDATE: 736 m.m_rs_update.state = req_lu_state; 737 m.m_rs_update.prepare_maxtime = req_lu_maxtime; 738 /* fall through */ 739 case RS_UP: 740 case RS_EDIT: 741 /* Build space-separated command string to be passed to RS server. */ 742 if (req_progname != NULL) { 743 progname = req_progname; 744 } else { 745 progname = strrchr(req_path, '/'); 746 assert(progname); /* an absolute path was required */ 747 progname++; /* skip last slash */ 748 } 749 strcpy(command, req_path); 750 command[strlen(req_path)] = ' '; 751 strcpy(command+strlen(req_path)+1, req_args); 752 753 if (req_config) { 754 assert(progname); 755 memset(&config, 0, sizeof(config)); 756 if(!parse_config(progname, custom_config_file, req_config, &config)) 757 errx(1, "couldn't parse config"); 758 assert(config.rs_start.rss_priority < NR_SCHED_QUEUES); 759 assert(config.rs_start.rss_quantum > 0); 760 } 761 762 /* Set specifics */ 763 config.rs_start.rss_cmd= command; 764 config.rs_start.rss_cmdlen= strlen(command); 765 config.rs_start.rss_progname= progname; 766 config.rs_start.rss_prognamelen= strlen(progname); 767 config.rs_start.rss_major= req_major; 768 config.rs_start.rss_period= req_period; 769 config.rs_start.rss_script= req_script; 770 config.rs_start.rss_asr_count= req_asr_count; 771 config.rs_start.rss_restarts= req_restarts; 772 config.rs_start.devman_id= devman_id; 773 config.rs_start.rss_heap_prealloc_bytes= req_heap_prealloc; 774 config.rs_start.rss_map_prealloc_bytes= req_map_prealloc; 775 config.rs_start.rss_flags |= rss_flags; 776 if(req_label) { 777 config.rs_start.rss_label.l_addr = req_label; 778 config.rs_start.rss_label.l_len = strlen(req_label); 779 } else { 780 config.rs_start.rss_label.l_addr = progname; 781 config.rs_start.rss_label.l_len = strlen(progname); 782 } 783 if(req_trg_label) { 784 config.rs_start.rss_trg_label.l_addr = req_trg_label; 785 config.rs_start.rss_trg_label.l_len = strlen(req_trg_label); 786 } else { 787 config.rs_start.rss_trg_label.l_addr = 0; 788 config.rs_start.rss_trg_label.l_len = 0; 789 } 790 if (req_script) 791 config.rs_start.rss_scriptlen= strlen(req_script); 792 else 793 config.rs_start.rss_scriptlen= 0; 794 795 /* State-related data. */ 796 config.rs_start.rss_state_data.size = 797 sizeof(config.rs_start.rss_state_data); 798 if(num_ipc_filters > 0) { 799 config.rs_start.rss_state_data.ipcf_els = rs_ipc_filter_els; 800 config.rs_start.rss_state_data.ipcf_els_size = 801 num_ipc_filters*sizeof(rs_ipc_filter_els[0]); 802 } 803 else { 804 config.rs_start.rss_state_data.ipcf_els = NULL; 805 config.rs_start.rss_state_data.ipcf_els_size = 0; 806 } 807 if(req_state_eval) { 808 config.rs_start.rss_state_data.eval_addr = req_state_eval; 809 config.rs_start.rss_state_data.eval_len = strlen(req_state_eval); 810 } 811 else { 812 config.rs_start.rss_state_data.eval_addr = NULL; 813 config.rs_start.rss_state_data.eval_len = 0; 814 } 815 816 m.m_rs_req.addr = (char *) &config.rs_start; 817 break; 818 case RS_DOWN: 819 case RS_REFRESH: 820 case RS_RESTART: 821 case RS_CLONE: 822 case RS_UNCLONE: 823 case RS_FI: 824 m.m_rs_req.addr = req_label; 825 m.m_rs_req.len = strlen(req_label); 826 break; 827 case RS_SYSCTL: 828 m.m_rs_req.subtype = req_sysctl_type; 829 break; 830 case RS_SHUTDOWN: 831 break; 832 default: 833 print_usage(argv[ARG_NAME], "request is not yet supported"); 834 result = EGENERIC; 835 } 836 837 /* Build request message and send the request. */ 838 if(result == OK) { 839 if (_syscall(RS_PROC_NR, request, &m) == -1) 840 failure(request); 841 result = m.m_type; 842 } 843 844 return(result); 845 } 846 847