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