| #include <sys/types.h> |
| #include <sys/wait.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <argp.h> |
| |
| #include <parlib/parlib.h> |
| #include <parlib/vcore.h> |
| |
| static char doc[] = "prov -- control for provisioning resources"; |
| static char args_doc[] = "-p PID\n-c PROGRAM [ARGS]\nPROGRAM [ARGS]\n" |
| "-- PROGRAM [ARGS]\n-s"; |
| |
| static struct argp_option options[] = { |
| {"type", 't', "TYPE",0, "Type of resource to provision"}, |
| {"Possible types:", 0, 0, OPTION_DOC | OPTION_NO_USAGE, "c = cores\n" |
| "m = ram"}, |
| {0, 0, 0, 0, "Call with exactly one of these, or with a program and args:"}, |
| {"pid", 'p', "PID", OPTION_NO_USAGE, "Pid of process to provision " |
| "resources to"}, |
| {0, 0, 0, 0, ""}, |
| {"command", 'c', "PROG",OPTION_NO_USAGE, "Launch a program and " |
| "provision (alternate)"}, |
| {0, 0, 0, 0, ""}, |
| {"show", 's', 0, OPTION_NO_USAGE, "Show current resource " |
| "provisioning"}, |
| {0, 0, 0, OPTION_DOC, "If your command has arguments that conflict with " |
| "prov, then put them after -- to keep prov from " |
| "interpretting them."}, |
| {0, 0, 0, 0, "Call with exactly one of these when changing a provision:"}, |
| {"value", 'v', "VAL", 0, "Type-specific value, passed to the kernel"}, |
| {"max", 'm', 0, 0, "Provision all resources of the given type"}, |
| {0, 0, 0, OPTION_DOC, "VAL for cores is a list, e.g. -v 1,3-5,9"}, |
| {0, 0, 0, OPTION_DOC, "To undo a core's provisioning, pass in pid=0."}, |
| { 0 } |
| }; |
| |
| #define PROV_MODE_PID 1 |
| #define PROV_MODE_CMD 2 |
| #define PROV_MODE_SHOW 3 |
| |
| struct prog_args { |
| char **cmd_argv; |
| int cmd_argc; |
| int mode; /* PROV_MODE_ETC */ |
| pid_t pid; |
| char res_type; /* cores (c), ram (m), etc */ |
| char *res_val; /* type-specific value, unparsed */ |
| struct core_set cores; |
| bool max; |
| int dummy_val_flag; |
| }; |
| |
| static error_t parse_opt (int key, char *arg, struct argp_state *state) |
| { |
| struct prog_args *pargs = state->input; |
| switch (key) { |
| case 't': |
| pargs->res_type = arg[0]; |
| if (arg[1] != '\0') |
| printf("Warning, extra letters detected for -t's argument\n"); |
| break; |
| case 'p': |
| if (pargs->mode) { |
| printf("Too many modes given (-p, -s, CMD, etc)\n\n"); |
| argp_usage(state); |
| } |
| pargs->mode = PROV_MODE_PID; |
| pargs->pid = atoi(arg); |
| break; |
| case 's': |
| if (pargs->mode) { |
| printf("Too many modes given (-p, -s, CMD, etc)\n\n"); |
| argp_usage(state); |
| } |
| pargs->mode = PROV_MODE_SHOW; |
| break; |
| case 'c': |
| case ARGP_KEY_ARG: |
| if (pargs->mode) { |
| printf("Too many modes given (-p, -s, CMD, etc)\n\n"); |
| argp_usage(state); |
| } |
| pargs->mode = PROV_MODE_CMD; |
| |
| pargs->cmd_argc = state->argc - state->next + 1; |
| pargs->cmd_argv = malloc(sizeof(char*) * (pargs->cmd_argc + 1)); |
| assert(pargs->cmd_argv); |
| pargs->cmd_argv[0] = arg; |
| memcpy(&pargs->cmd_argv[1], &state->argv[state->next], |
| sizeof(char*) * (pargs->cmd_argc - 1)); |
| pargs->cmd_argv[pargs->cmd_argc] = NULL; |
| state->next = state->argc; |
| break; |
| case 'v': |
| /* could also check to make sure we're not -s (and vice versa) |
| */ |
| if (pargs->dummy_val_flag) { |
| printf("Provide only -v or -m, not both\n\n"); |
| argp_usage(state); |
| } |
| pargs->dummy_val_flag = 1; |
| pargs->res_val = arg; |
| break; |
| case 'm': |
| if (pargs->dummy_val_flag) { |
| printf("Provide only -v or -m, not both\n\n"); |
| argp_usage(state); |
| } |
| pargs->dummy_val_flag = 1; |
| pargs->max = true; |
| break; |
| case ARGP_KEY_END: |
| /* Make sure we selected a mode */ |
| if (!pargs->mode) { |
| printf("No mode selected (-p, -s, etc).\n\n"); |
| argp_usage(state); |
| } |
| break; |
| default: |
| return ARGP_ERR_UNKNOWN; |
| } |
| return 0; |
| } |
| |
| static struct argp argp = {options, parse_opt, args_doc, doc}; |
| |
| /* Used by both -p and -c modes (-c will use it after creating pid) */ |
| static int prov_pid(pid_t pid, struct prog_args *pargs) |
| { |
| switch (pargs->res_type) { |
| case ('c'): |
| if (pargs->max) { |
| parlib_get_all_core_set(&pargs->cores); |
| } else { |
| if (!pargs->res_val) { |
| printf("Need a list of cores to provision\n"); |
| return -1; |
| } |
| parlib_parse_cores(pargs->res_val, &pargs->cores); |
| } |
| provision_core_set(pid, &pargs->cores); |
| break; |
| case ('m'): |
| printf("Provisioning memory is not supported yet\n"); |
| return -1; |
| break; |
| default: |
| if (!pargs->res_type) |
| printf("No resource type selected. Use -t\n"); |
| else |
| printf("Unsupported resource type %c\n", |
| pargs->res_type); |
| return -1; |
| } |
| return 0; |
| } |
| |
| int main(int argc, char **argv, char **envp) |
| { |
| struct prog_args pargs = {0}; |
| pid_t pid; |
| |
| argp_parse(&argp, argc, argv, 0, 0, &pargs); |
| |
| switch (pargs.mode) { |
| case (PROV_MODE_PID): |
| return prov_pid(pargs.pid, &pargs); |
| break; |
| case (PROV_MODE_CMD): |
| pid = create_child_with_stdfds(pargs.cmd_argv[0], |
| pargs.cmd_argc, pargs.cmd_argv, |
| envp); |
| if (pid < 0) { |
| perror("Unable to spawn child"); |
| exit(-1); |
| } |
| if (prov_pid(pid, &pargs)) { |
| perror("Unable to provision to child"); |
| sys_proc_destroy(pid, -1); |
| exit(-1); |
| } |
| sys_proc_run(pid); |
| waitpid(pid, NULL, 0); |
| return 0; |
| case (PROV_MODE_SHOW): |
| printf("Show mode not supported, using ghetto interface\n\n"); |
| printf("Check 'dmesg' if you aren't on the console\n\n"); |
| sys_provision(-1, 0, 0); |
| return 0; |
| break; |
| default: |
| return -1; |
| } |
| } |