blob: 8e9cb8e857be2988666ad8ab6274e41153b48173 [file] [log] [blame]
#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;
}
}