mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-26 03:17:48 +00:00
ad1d8313cd
Some operations, like frequency-set, need root privileges. However, the way that this is detected is not correct. The getuid() is called, while in fact geteuid() should be. This way we can allow distributions or users to set SETUID flags on the cpupower binary if they want to and let regular users change the cpu frequency governor. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> Acked-by: Thomas Renninger <trenn@suse.de> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
230 lines
5.0 KiB
C
230 lines
5.0 KiB
C
/*
|
|
* (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
|
|
*
|
|
* Licensed under the terms of the GNU GPL License version 2.
|
|
*
|
|
* Ideas taken over from the perf userspace tool (included in the Linus
|
|
* kernel git repo): subcommand builtins and param parsing.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/utsname.h>
|
|
|
|
#include "builtin.h"
|
|
#include "helpers/helpers.h"
|
|
#include "helpers/bitmask.h"
|
|
|
|
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
|
|
|
|
static int cmd_help(int argc, const char **argv);
|
|
|
|
/* Global cpu_info object available for all binaries
|
|
* Info only retrieved from CPU 0
|
|
*
|
|
* Values will be zero/unknown on non X86 archs
|
|
*/
|
|
struct cpupower_cpu_info cpupower_cpu_info;
|
|
int run_as_root;
|
|
/* Affected cpus chosen by -c/--cpu param */
|
|
struct bitmask *cpus_chosen;
|
|
|
|
#ifdef DEBUG
|
|
int be_verbose;
|
|
#endif
|
|
|
|
static void print_help(void);
|
|
|
|
struct cmd_struct {
|
|
const char *cmd;
|
|
int (*main)(int, const char **);
|
|
int needs_root;
|
|
};
|
|
|
|
static struct cmd_struct commands[] = {
|
|
{ "frequency-info", cmd_freq_info, 0 },
|
|
{ "frequency-set", cmd_freq_set, 1 },
|
|
{ "idle-info", cmd_idle_info, 0 },
|
|
{ "idle-set", cmd_idle_set, 1 },
|
|
{ "set", cmd_set, 1 },
|
|
{ "info", cmd_info, 0 },
|
|
{ "monitor", cmd_monitor, 0 },
|
|
{ "help", cmd_help, 0 },
|
|
/* { "bench", cmd_bench, 1 }, */
|
|
};
|
|
|
|
static void print_help(void)
|
|
{
|
|
unsigned int i;
|
|
|
|
#ifdef DEBUG
|
|
printf(_("Usage:\tcpupower [-d|--debug] [-c|--cpu cpulist ] <command> [<args>]\n"));
|
|
#else
|
|
printf(_("Usage:\tcpupower [-c|--cpu cpulist ] <command> [<args>]\n"));
|
|
#endif
|
|
printf(_("Supported commands are:\n"));
|
|
for (i = 0; i < ARRAY_SIZE(commands); i++)
|
|
printf("\t%s\n", commands[i].cmd);
|
|
printf(_("\nNot all commands can make use of the -c cpulist option.\n"));
|
|
printf(_("\nUse 'cpupower help <command>' for getting help for above commands.\n"));
|
|
}
|
|
|
|
static int print_man_page(const char *subpage)
|
|
{
|
|
int len;
|
|
char *page;
|
|
|
|
len = 10; /* enough for "cpupower-" */
|
|
if (subpage != NULL)
|
|
len += strlen(subpage);
|
|
|
|
page = malloc(len);
|
|
if (!page)
|
|
return -ENOMEM;
|
|
|
|
sprintf(page, "cpupower");
|
|
if ((subpage != NULL) && strcmp(subpage, "help")) {
|
|
strcat(page, "-");
|
|
strcat(page, subpage);
|
|
}
|
|
|
|
execlp("man", "man", page, NULL);
|
|
|
|
/* should not be reached */
|
|
return -EINVAL;
|
|
}
|
|
|
|
static int cmd_help(int argc, const char **argv)
|
|
{
|
|
if (argc > 1) {
|
|
print_man_page(argv[1]); /* exits within execlp() */
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
print_help();
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
static void print_version(void)
|
|
{
|
|
printf(PACKAGE " " VERSION "\n");
|
|
printf(_("Report errors and bugs to %s, please.\n"), PACKAGE_BUGREPORT);
|
|
}
|
|
|
|
static void handle_options(int *argc, const char ***argv)
|
|
{
|
|
int ret, x, new_argc = 0;
|
|
|
|
if (*argc < 1)
|
|
return;
|
|
|
|
for (x = 0; x < *argc && ((*argv)[x])[0] == '-'; x++) {
|
|
const char *param = (*argv)[x];
|
|
if (!strcmp(param, "-h") || !strcmp(param, "--help")) {
|
|
print_help();
|
|
exit(EXIT_SUCCESS);
|
|
} else if (!strcmp(param, "-c") || !strcmp(param, "--cpu")) {
|
|
if (*argc < 2) {
|
|
print_help();
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
if (!strcmp((*argv)[x+1], "all"))
|
|
bitmask_setall(cpus_chosen);
|
|
else {
|
|
ret = bitmask_parselist(
|
|
(*argv)[x+1], cpus_chosen);
|
|
if (ret < 0) {
|
|
fprintf(stderr, _("Error parsing cpu "
|
|
"list\n"));
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
x += 1;
|
|
/* Cut out param: cpupower -c 1 info -> cpupower info */
|
|
new_argc += 2;
|
|
continue;
|
|
} else if (!strcmp(param, "-v") ||
|
|
!strcmp(param, "--version")) {
|
|
print_version();
|
|
exit(EXIT_SUCCESS);
|
|
#ifdef DEBUG
|
|
} else if (!strcmp(param, "-d") || !strcmp(param, "--debug")) {
|
|
be_verbose = 1;
|
|
new_argc++;
|
|
continue;
|
|
#endif
|
|
} else {
|
|
fprintf(stderr, "Unknown option: %s\n", param);
|
|
print_help();
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
*argc -= new_argc;
|
|
*argv += new_argc;
|
|
}
|
|
|
|
int main(int argc, const char *argv[])
|
|
{
|
|
const char *cmd;
|
|
unsigned int i, ret;
|
|
struct stat statbuf;
|
|
struct utsname uts;
|
|
|
|
cpus_chosen = bitmask_alloc(sysconf(_SC_NPROCESSORS_CONF));
|
|
|
|
argc--;
|
|
argv += 1;
|
|
|
|
handle_options(&argc, &argv);
|
|
|
|
cmd = argv[0];
|
|
|
|
if (argc < 1) {
|
|
print_help();
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
setlocale(LC_ALL, "");
|
|
textdomain(PACKAGE);
|
|
|
|
/* Turn "perf cmd --help" into "perf help cmd" */
|
|
if (argc > 1 && !strcmp(argv[1], "--help")) {
|
|
argv[1] = argv[0];
|
|
argv[0] = cmd = "help";
|
|
}
|
|
|
|
get_cpu_info(0, &cpupower_cpu_info);
|
|
run_as_root = !geteuid();
|
|
if (run_as_root) {
|
|
ret = uname(&uts);
|
|
if (!ret && !strcmp(uts.machine, "x86_64") &&
|
|
stat("/dev/cpu/0/msr", &statbuf) != 0) {
|
|
if (system("modprobe msr") == -1)
|
|
fprintf(stderr, _("MSR access not available.\n"));
|
|
}
|
|
}
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(commands); i++) {
|
|
struct cmd_struct *p = commands + i;
|
|
if (strcmp(p->cmd, cmd))
|
|
continue;
|
|
if (!run_as_root && p->needs_root) {
|
|
fprintf(stderr, _("Subcommand %s needs root "
|
|
"privileges\n"), cmd);
|
|
return EXIT_FAILURE;
|
|
}
|
|
ret = p->main(argc, argv);
|
|
if (cpus_chosen)
|
|
bitmask_free(cpus_chosen);
|
|
return ret;
|
|
}
|
|
print_help();
|
|
return EXIT_FAILURE;
|
|
}
|