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