| /* | |
| * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc. | |
| * | |
| * Licensed under the terms of the GNU GPL License version 2. | |
| * | |
| * Ideas taken over from the perf userspace tool (included in the Linus | |
| * kernel git repo): subcommand builtins and param parsing. | |
| */ | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include <errno.h> | |
| #include <sys/types.h> | |
| #include <sys/stat.h> | |
| #include <sys/utsname.h> | |
| #include "builtin.h" | |
| #include "helpers/helpers.h" | |
| #include "helpers/bitmask.h" | |
| #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) | |
| static int cmd_help(int argc, const char **argv); | |
| /* Global cpu_info object available for all binaries | |
| * Info only retrieved from CPU 0 | |
| * | |
| * Values will be zero/unknown on non X86 archs | |
| */ | |
| struct cpupower_cpu_info cpupower_cpu_info; | |
| int run_as_root; | |
| /* Affected cpus chosen by -c/--cpu param */ | |
| struct bitmask *cpus_chosen; | |
| #ifdef DEBUG | |
| int be_verbose; | |
| #endif | |
| static void print_help(void); | |
| struct cmd_struct { | |
| const char *cmd; | |
| int (*main)(int, const char **); | |
| int needs_root; | |
| }; | |
| static struct cmd_struct commands[] = { | |
| { "frequency-info", cmd_freq_info, 0 }, | |
| { "frequency-set", cmd_freq_set, 1 }, | |
| { "idle-info", cmd_idle_info, 0 }, | |
| { "idle-set", cmd_idle_set, 1 }, | |
| { "set", cmd_set, 1 }, | |
| { "info", cmd_info, 0 }, | |
| { "monitor", cmd_monitor, 0 }, | |
| { "help", cmd_help, 0 }, | |
| /* { "bench", cmd_bench, 1 }, */ | |
| }; | |
| static void print_help(void) | |
| { | |
| unsigned int i; | |
| #ifdef DEBUG | |
| printf(_("Usage:\tcpupower [-d|--debug] [-c|--cpu cpulist ] <command> [<args>]\n")); | |
| #else | |
| printf(_("Usage:\tcpupower [-c|--cpu cpulist ] <command> [<args>]\n")); | |
| #endif | |
| printf(_("Supported commands are:\n")); | |
| for (i = 0; i < ARRAY_SIZE(commands); i++) | |
| printf("\t%s\n", commands[i].cmd); | |
| printf(_("\nNot all commands can make use of the -c cpulist option.\n")); | |
| printf(_("\nUse 'cpupower help <command>' for getting help for above commands.\n")); | |
| } | |
| static int print_man_page(const char *subpage) | |
| { | |
| int len; | |
| char *page; | |
| len = 10; /* enough for "cpupower-" */ | |
| if (subpage != NULL) | |
| len += strlen(subpage); | |
| page = malloc(len); | |
| if (!page) | |
| return -ENOMEM; | |
| sprintf(page, "cpupower"); | |
| if ((subpage != NULL) && strcmp(subpage, "help")) { | |
| strcat(page, "-"); | |
| strcat(page, subpage); | |
| } | |
| execlp("man", "man", page, NULL); | |
| /* should not be reached */ | |
| return -EINVAL; | |
| } | |
| static int cmd_help(int argc, const char **argv) | |
| { | |
| if (argc > 1) { | |
| print_man_page(argv[1]); /* exits within execlp() */ | |
| return EXIT_FAILURE; | |
| } | |
| print_help(); | |
| return EXIT_SUCCESS; | |
| } | |
| static void print_version(void) | |
| { | |
| printf(PACKAGE " " VERSION "\n"); | |
| printf(_("Report errors and bugs to %s, please.\n"), PACKAGE_BUGREPORT); | |
| } | |
| static void handle_options(int *argc, const char ***argv) | |
| { | |
| int ret, x, new_argc = 0; | |
| if (*argc < 1) | |
| return; | |
| for (x = 0; x < *argc && ((*argv)[x])[0] == '-'; x++) { | |
| const char *param = (*argv)[x]; | |
| if (!strcmp(param, "-h") || !strcmp(param, "--help")) { | |
| print_help(); | |
| exit(EXIT_SUCCESS); | |
| } else if (!strcmp(param, "-c") || !strcmp(param, "--cpu")) { | |
| if (*argc < 2) { | |
| print_help(); | |
| exit(EXIT_FAILURE); | |
| } | |
| if (!strcmp((*argv)[x+1], "all")) | |
| bitmask_setall(cpus_chosen); | |
| else { | |
| ret = bitmask_parselist( | |
| (*argv)[x+1], cpus_chosen); | |
| if (ret < 0) { | |
| fprintf(stderr, _("Error parsing cpu " | |
| "list\n")); | |
| exit(EXIT_FAILURE); | |
| } | |
| } | |
| x += 1; | |
| /* Cut out param: cpupower -c 1 info -> cpupower info */ | |
| new_argc += 2; | |
| continue; | |
| } else if (!strcmp(param, "-v") || | |
| !strcmp(param, "--version")) { | |
| print_version(); | |
| exit(EXIT_SUCCESS); | |
| #ifdef DEBUG | |
| } else if (!strcmp(param, "-d") || !strcmp(param, "--debug")) { | |
| be_verbose = 1; | |
| new_argc++; | |
| continue; | |
| #endif | |
| } else { | |
| fprintf(stderr, "Unknown option: %s\n", param); | |
| print_help(); | |
| exit(EXIT_FAILURE); | |
| } | |
| } | |
| *argc -= new_argc; | |
| *argv += new_argc; | |
| } | |
| int main(int argc, const char *argv[]) | |
| { | |
| const char *cmd; | |
| unsigned int i, ret; | |
| struct stat statbuf; | |
| struct utsname uts; | |
| cpus_chosen = bitmask_alloc(sysconf(_SC_NPROCESSORS_CONF)); | |
| argc--; | |
| argv += 1; | |
| handle_options(&argc, &argv); | |
| cmd = argv[0]; | |
| if (argc < 1) { | |
| print_help(); | |
| return EXIT_FAILURE; | |
| } | |
| setlocale(LC_ALL, ""); | |
| textdomain(PACKAGE); | |
| /* Turn "perf cmd --help" into "perf help cmd" */ | |
| if (argc > 1 && !strcmp(argv[1], "--help")) { | |
| argv[1] = argv[0]; | |
| argv[0] = cmd = "help"; | |
| } | |
| get_cpu_info(0, &cpupower_cpu_info); | |
| run_as_root = !getuid(); | |
| if (run_as_root) { | |
| ret = uname(&uts); | |
| if (!ret && !strcmp(uts.machine, "x86_64") && | |
| stat("/dev/cpu/0/msr", &statbuf) != 0) { | |
| if (system("modprobe msr") == -1) | |
| fprintf(stderr, _("MSR access not available.\n")); | |
| } | |
| } | |
| for (i = 0; i < ARRAY_SIZE(commands); i++) { | |
| struct cmd_struct *p = commands + i; | |
| if (strcmp(p->cmd, cmd)) | |
| continue; | |
| if (!run_as_root && p->needs_root) { | |
| fprintf(stderr, _("Subcommand %s needs root " | |
| "privileges\n"), cmd); | |
| return EXIT_FAILURE; | |
| } | |
| ret = p->main(argc, argv); | |
| if (cpus_chosen) | |
| bitmask_free(cpus_chosen); | |
| return ret; | |
| } | |
| print_help(); | |
| return EXIT_FAILURE; | |
| } |