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