1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc. 4 * 5 * Ideas taken over from the perf userspace tool (included in the Linus 6 * kernel git repo): subcommand builtins and param parsing. 7 */ 8 9#include <stdio.h> 10#include <stdlib.h> 11#include <string.h> 12#include <unistd.h> 13#include <errno.h> 14#include <sched.h> 15#include <sys/types.h> 16#include <sys/stat.h> 17#include <sys/utsname.h> 18 19#include "builtin.h" 20#include "helpers/helpers.h" 21#include "helpers/bitmask.h" 22 23#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) 24 25static int cmd_help(int argc, const char **argv); 26 27/* Global cpu_info object available for all binaries 28 * Info only retrieved from CPU 0 29 * 30 * Values will be zero/unknown on non X86 archs 31 */ 32struct cpupower_cpu_info cpupower_cpu_info; 33int run_as_root; 34int base_cpu; 35/* Affected cpus chosen by -c/--cpu param */ 36struct bitmask *cpus_chosen; 37 38#ifdef DEBUG 39int be_verbose; 40#endif 41 42static void print_help(void); 43 44struct cmd_struct { 45 const char *cmd; 46 int (*main)(int, const char **); 47 int needs_root; 48}; 49 50static struct cmd_struct commands[] = { 51 { "frequency-info", cmd_freq_info, 0 }, 52 { "frequency-set", cmd_freq_set, 1 }, 53 { "idle-info", cmd_idle_info, 0 }, 54 { "idle-set", cmd_idle_set, 1 }, 55 { "set", cmd_set, 1 }, 56 { "info", cmd_info, 0 }, 57 { "monitor", cmd_monitor, 0 }, 58 { "help", cmd_help, 0 }, 59 /* { "bench", cmd_bench, 1 }, */ 60}; 61 62static void print_help(void) 63{ 64 unsigned int i; 65 66#ifdef DEBUG 67 printf(_("Usage:\tcpupower [-d|--debug] [-c|--cpu cpulist ] <command> [<args>]\n")); 68#else 69 printf(_("Usage:\tcpupower [-c|--cpu cpulist ] <command> [<args>]\n")); 70#endif 71 printf(_("Supported commands are:\n")); 72 for (i = 0; i < ARRAY_SIZE(commands); i++) 73 printf("\t%s\n", commands[i].cmd); 74 printf(_("\nNot all commands can make use of the -c cpulist option.\n")); 75 printf(_("\nUse 'cpupower help <command>' for getting help for above commands.\n")); 76} 77 78static int print_man_page(const char *subpage) 79{ 80 int len; 81 char *page; 82 83 len = 10; /* enough for "cpupower-" */ 84 if (subpage != NULL) 85 len += strlen(subpage); 86 87 page = malloc(len); 88 if (!page) 89 return -ENOMEM; 90 91 sprintf(page, "cpupower"); 92 if ((subpage != NULL) && strcmp(subpage, "help")) { 93 strcat(page, "-"); 94 strcat(page, subpage); 95 } 96 97 execlp("man", "man", page, NULL); 98 99 /* should not be reached */ 100 return -EINVAL; 101} 102 103static int cmd_help(int argc, const char **argv) 104{ 105 if (argc > 1) { 106 print_man_page(argv[1]); /* exits within execlp() */ 107 return EXIT_FAILURE; 108 } 109 110 print_help(); 111 return EXIT_SUCCESS; 112} 113 114static void print_version(void) 115{ 116 printf(PACKAGE " " VERSION "\n"); 117 printf(_("Report errors and bugs to %s, please.\n"), PACKAGE_BUGREPORT); 118} 119 120static void handle_options(int *argc, const char ***argv) 121{ 122 int ret, x, new_argc = 0; 123 124 if (*argc < 1) 125 return; 126 127 for (x = 0; x < *argc && ((*argv)[x])[0] == '-'; x++) { 128 const char *param = (*argv)[x]; 129 if (!strcmp(param, "-h") || !strcmp(param, "--help")) { 130 print_help(); 131 exit(EXIT_SUCCESS); 132 } else if (!strcmp(param, "-c") || !strcmp(param, "--cpu")) { 133 if (*argc < 2) { 134 print_help(); 135 exit(EXIT_FAILURE); 136 } 137 if (!strcmp((*argv)[x+1], "all")) 138 bitmask_setall(cpus_chosen); 139 else { 140 ret = bitmask_parselist( 141 (*argv)[x+1], cpus_chosen); 142 if (ret < 0) { 143 fprintf(stderr, _("Error parsing cpu " 144 "list\n")); 145 exit(EXIT_FAILURE); 146 } 147 } 148 x += 1; 149 /* Cut out param: cpupower -c 1 info -> cpupower info */ 150 new_argc += 2; 151 continue; 152 } else if (!strcmp(param, "-v") || 153 !strcmp(param, "--version")) { 154 print_version(); 155 exit(EXIT_SUCCESS); 156#ifdef DEBUG 157 } else if (!strcmp(param, "-d") || !strcmp(param, "--debug")) { 158 be_verbose = 1; 159 new_argc++; 160 continue; 161#endif 162 } else { 163 fprintf(stderr, "Unknown option: %s\n", param); 164 print_help(); 165 exit(EXIT_FAILURE); 166 } 167 } 168 *argc -= new_argc; 169 *argv += new_argc; 170} 171 172int main(int argc, const char *argv[]) 173{ 174 const char *cmd; 175 unsigned int i, ret; 176 struct stat statbuf; 177 struct utsname uts; 178 char pathname[32]; 179 180 cpus_chosen = bitmask_alloc(sysconf(_SC_NPROCESSORS_CONF)); 181 182 argc--; 183 argv += 1; 184 185 handle_options(&argc, &argv); 186 187 cmd = argv[0]; 188 189 if (argc < 1) { 190 print_help(); 191 return EXIT_FAILURE; 192 } 193 194 setlocale(LC_ALL, ""); 195 textdomain(PACKAGE); 196 197 /* Turn "perf cmd --help" into "perf help cmd" */ 198 if (argc > 1 && !strcmp(argv[1], "--help")) { 199 argv[1] = argv[0]; 200 argv[0] = cmd = "help"; 201 } 202 203 base_cpu = sched_getcpu(); 204 if (base_cpu < 0) { 205 fprintf(stderr, _("No valid cpus found.\n")); 206 return EXIT_FAILURE; 207 } 208 209 get_cpu_info(&cpupower_cpu_info); 210 run_as_root = !geteuid(); 211 if (run_as_root) { 212 ret = uname(&uts); 213 sprintf(pathname, "/dev/cpu/%d/msr", base_cpu); 214 if (!ret && !strcmp(uts.machine, "x86_64") && 215 stat(pathname, &statbuf) != 0) { 216 if (system("modprobe msr") == -1) 217 fprintf(stderr, _("MSR access not available.\n")); 218 } 219 } 220 221 for (i = 0; i < ARRAY_SIZE(commands); i++) { 222 struct cmd_struct *p = commands + i; 223 if (strcmp(p->cmd, cmd)) 224 continue; 225 if (!run_as_root && p->needs_root) { 226 fprintf(stderr, _("Subcommand %s needs root " 227 "privileges\n"), cmd); 228 return EXIT_FAILURE; 229 } 230 ret = p->main(argc, argv); 231 if (cpus_chosen) 232 bitmask_free(cpus_chosen); 233 return ret; 234 } 235 print_help(); 236 return EXIT_FAILURE; 237} 238