Commit | Line | Data |
---|---|---|
7fe2f639 DB |
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> | |
498ca793 | 14 | #include <errno.h> |
8a19cb58 TR |
15 | #include <sys/types.h> |
16 | #include <sys/stat.h> | |
17 | #include <sys/utsname.h> | |
7fe2f639 DB |
18 | |
19 | #include "builtin.h" | |
20 | #include "helpers/helpers.h" | |
21 | #include "helpers/bitmask.h" | |
22 | ||
7fe2f639 DB |
23 | #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) |
24 | ||
498ca793 | 25 | static int cmd_help(int argc, const char **argv); |
7fe2f639 DB |
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 | ||
c4f3610e TR |
43 | struct cmd_struct { |
44 | const char *cmd; | |
45 | int (*main)(int, const char **); | |
46 | int needs_root; | |
47 | }; | |
48 | ||
7fe2f639 | 49 | static struct cmd_struct commands[] = { |
498ca793 DB |
50 | { "frequency-info", cmd_freq_info, 0 }, |
51 | { "frequency-set", cmd_freq_set, 1 }, | |
52 | { "idle-info", cmd_idle_info, 0 }, | |
c4f3610e | 53 | { "idle-set", cmd_idle_set, 1 }, |
498ca793 DB |
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 }, */ | |
7fe2f639 DB |
59 | }; |
60 | ||
7fe2f639 DB |
61 | static void print_help(void) |
62 | { | |
63 | unsigned int i; | |
64 | ||
65 | #ifdef DEBUG | |
498ca793 | 66 | printf(_("Usage:\tcpupower [-d|--debug] [-c|--cpu cpulist ] <command> [<args>]\n")); |
7fe2f639 | 67 | #else |
498ca793 | 68 | printf(_("Usage:\tcpupower [-c|--cpu cpulist ] <command> [<args>]\n")); |
7fe2f639 | 69 | #endif |
498ca793 | 70 | printf(_("Supported commands are:\n")); |
7fe2f639 DB |
71 | for (i = 0; i < ARRAY_SIZE(commands); i++) |
72 | printf("\t%s\n", commands[i].cmd); | |
498ca793 DB |
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; | |
7fe2f639 DB |
111 | } |
112 | ||
a1ce5ba2 DB |
113 | static void print_version(void) |
114 | { | |
115 | printf(PACKAGE " " VERSION "\n"); | |
7fe2f639 DB |
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]; | |
a1ce5ba2 | 128 | if (!strcmp(param, "-h") || !strcmp(param, "--help")) { |
7fe2f639 DB |
129 | print_help(); |
130 | exit(EXIT_SUCCESS); | |
a1ce5ba2 | 131 | } else if (!strcmp(param, "-c") || !strcmp(param, "--cpu")) { |
7fe2f639 DB |
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; | |
a1ce5ba2 DB |
151 | } else if (!strcmp(param, "-v") || |
152 | !strcmp(param, "--version")) { | |
7fe2f639 DB |
153 | print_version(); |
154 | exit(EXIT_SUCCESS); | |
155 | #ifdef DEBUG | |
a1ce5ba2 | 156 | } else if (!strcmp(param, "-d") || !strcmp(param, "--debug")) { |
7fe2f639 | 157 | be_verbose = 1; |
a1ce5ba2 | 158 | new_argc++; |
7fe2f639 DB |
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; | |
8a19cb58 TR |
175 | struct stat statbuf; |
176 | struct utsname uts; | |
7fe2f639 DB |
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, ""); | |
a1ce5ba2 | 193 | textdomain(PACKAGE); |
7fe2f639 DB |
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); | |
ad1d8313 | 202 | run_as_root = !geteuid(); |
8a19cb58 TR |
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 | ||
7fe2f639 DB |
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 | } |