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