diff options
| author | Len Brown <len.brown@intel.com> | 2014-08-15 00:36:50 -0400 |
|---|---|---|
| committer | Len Brown <len.brown@intel.com> | 2015-02-09 16:41:16 -0500 |
| commit | 98481e79b60a50d699b79292ff1b7e56e7fa8425 (patch) | |
| tree | 148ec049930bed66b08ccbfa1dcddc11ebd841c4 | |
| parent | bfa76d49576599a4b9f9b7a71f23d73d6dcff735 (diff) | |
tools/power turbostat: relax dependency on root permission
For turbostat to run as non-root, it needs to permissions:
1. read access to /dev/cpu/*/msr
via standard user/group/world file permissions
2. CAP_SYS_RAWIO
eg. # setcap cap_sys_rawio=ep turbostat
Yes, running as root still works.
Signed-off-by: Len Brown <len.brown@intel.com>
| -rw-r--r-- | tools/power/x86/turbostat/turbostat.c | 53 |
1 files changed, 41 insertions, 12 deletions
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 5b1b807265a1..6f29fc11fde6 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c | |||
| @@ -38,6 +38,8 @@ | |||
| 38 | #include <ctype.h> | 38 | #include <ctype.h> |
| 39 | #include <sched.h> | 39 | #include <sched.h> |
| 40 | #include <cpuid.h> | 40 | #include <cpuid.h> |
| 41 | #include <linux/capability.h> | ||
| 42 | #include <errno.h> | ||
| 41 | 43 | ||
| 42 | char *proc_stat = "/proc/stat"; | 44 | char *proc_stat = "/proc/stat"; |
| 43 | unsigned int interval_sec = 5; /* set with -i interval_sec */ | 45 | unsigned int interval_sec = 5; /* set with -i interval_sec */ |
| @@ -251,15 +253,13 @@ int get_msr(int cpu, off_t offset, unsigned long long *msr) | |||
| 251 | sprintf(pathname, "/dev/cpu/%d/msr", cpu); | 253 | sprintf(pathname, "/dev/cpu/%d/msr", cpu); |
| 252 | fd = open(pathname, O_RDONLY); | 254 | fd = open(pathname, O_RDONLY); |
| 253 | if (fd < 0) | 255 | if (fd < 0) |
| 254 | return -1; | 256 | err(-1, "%s open failed, try chown or chmod +r /dev/cpu/*/msr, or run as root", pathname); |
| 255 | 257 | ||
| 256 | retval = pread(fd, msr, sizeof *msr, offset); | 258 | retval = pread(fd, msr, sizeof *msr, offset); |
| 257 | close(fd); | 259 | close(fd); |
| 258 | 260 | ||
| 259 | if (retval != sizeof *msr) { | 261 | if (retval != sizeof *msr) |
| 260 | fprintf(stderr, "%s offset 0x%llx read failed\n", pathname, (unsigned long long)offset); | 262 | err(-1, "%s offset 0x%llx read failed", pathname, (unsigned long long)offset); |
| 261 | return -1; | ||
| 262 | } | ||
| 263 | 263 | ||
| 264 | return 0; | 264 | return 0; |
| 265 | } | 265 | } |
| @@ -1462,10 +1462,40 @@ void check_dev_msr() | |||
| 1462 | "Try \"# modprobe msr\""); | 1462 | "Try \"# modprobe msr\""); |
| 1463 | } | 1463 | } |
| 1464 | 1464 | ||
| 1465 | void check_super_user() | 1465 | void check_permissions() |
| 1466 | { | 1466 | { |
| 1467 | if (getuid() != 0) | 1467 | struct __user_cap_header_struct cap_header_data; |
| 1468 | errx(-6, "must be root"); | 1468 | cap_user_header_t cap_header = &cap_header_data; |
| 1469 | struct __user_cap_data_struct cap_data_data; | ||
| 1470 | cap_user_data_t cap_data = &cap_data_data; | ||
| 1471 | extern int capget(cap_user_header_t hdrp, cap_user_data_t datap); | ||
| 1472 | int do_exit = 0; | ||
| 1473 | |||
| 1474 | /* check for CAP_SYS_RAWIO */ | ||
| 1475 | cap_header->pid = getpid(); | ||
| 1476 | cap_header->version = _LINUX_CAPABILITY_VERSION; | ||
| 1477 | if (capget(cap_header, cap_data) < 0) | ||
| 1478 | err(-6, "capget(2) failed"); | ||
| 1479 | |||
| 1480 | if ((cap_data->effective & (1 << CAP_SYS_RAWIO)) == 0) { | ||
| 1481 | do_exit++; | ||
| 1482 | warnx("capget(CAP_SYS_RAWIO) failed," | ||
| 1483 | " try \"# setcap cap_sys_rawio=ep %s\"", progname); | ||
| 1484 | } | ||
| 1485 | |||
| 1486 | /* test file permissions */ | ||
| 1487 | if (euidaccess("/dev/cpu/0/msr", R_OK)) { | ||
| 1488 | do_exit++; | ||
| 1489 | warn("/dev/cpu/0/msr open failed, try chown or chmod +r /dev/cpu/*/msr"); | ||
| 1490 | } | ||
| 1491 | |||
| 1492 | /* if all else fails, thell them to be root */ | ||
| 1493 | if (do_exit) | ||
| 1494 | if (getuid() != 0) | ||
| 1495 | warnx("Or simply run as root"); | ||
| 1496 | |||
| 1497 | if (do_exit) | ||
| 1498 | exit(-6); | ||
| 1469 | } | 1499 | } |
| 1470 | 1500 | ||
| 1471 | int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model) | 1501 | int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model) |
| @@ -2299,10 +2329,9 @@ void setup_all_buffers(void) | |||
| 2299 | 2329 | ||
| 2300 | void turbostat_init() | 2330 | void turbostat_init() |
| 2301 | { | 2331 | { |
| 2302 | check_cpuid(); | ||
| 2303 | |||
| 2304 | check_dev_msr(); | 2332 | check_dev_msr(); |
| 2305 | check_super_user(); | 2333 | check_permissions(); |
| 2334 | check_cpuid(); | ||
| 2306 | 2335 | ||
| 2307 | setup_all_buffers(); | 2336 | setup_all_buffers(); |
| 2308 | 2337 | ||
| @@ -2441,7 +2470,7 @@ int main(int argc, char **argv) | |||
| 2441 | cmdline(argc, argv); | 2470 | cmdline(argc, argv); |
| 2442 | 2471 | ||
| 2443 | if (verbose) | 2472 | if (verbose) |
| 2444 | fprintf(stderr, "turbostat v3.7 Feb 6, 2014" | 2473 | fprintf(stderr, "turbostat v3.8 14-Aug 2014" |
| 2445 | " - Len Brown <lenb@kernel.org>\n"); | 2474 | " - Len Brown <lenb@kernel.org>\n"); |
| 2446 | 2475 | ||
| 2447 | turbostat_init(); | 2476 | turbostat_init(); |
