tools/power turbostat: relax dependency on root permission
authorLen Brown <len.brown@intel.com>
Fri, 15 Aug 2014 04:36:50 +0000 (00:36 -0400)
committerLen Brown <len.brown@intel.com>
Mon, 9 Feb 2015 21:41:16 +0000 (16:41 -0500)
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>
tools/power/x86/turbostat/turbostat.c

index 5b1b807265a15e826e174a197c06b6c0788ff9b7..6f29fc11fde6593fc968d31e010d6df1c2808037 100644 (file)
@@ -38,6 +38,8 @@
 #include <ctype.h>
 #include <sched.h>
 #include <cpuid.h>
+#include <linux/capability.h>
+#include <errno.h>
 
 char *proc_stat = "/proc/stat";
 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)
        sprintf(pathname, "/dev/cpu/%d/msr", cpu);
        fd = open(pathname, O_RDONLY);
        if (fd < 0)
-               return -1;
+               err(-1, "%s open failed, try chown or chmod +r /dev/cpu/*/msr, or run as root", pathname);
 
        retval = pread(fd, msr, sizeof *msr, offset);
        close(fd);
 
-       if (retval != sizeof *msr) {
-               fprintf(stderr, "%s offset 0x%llx read failed\n", pathname, (unsigned long long)offset);
-               return -1;
-       }
+       if (retval != sizeof *msr)
+               err(-1, "%s offset 0x%llx read failed", pathname, (unsigned long long)offset);
 
        return 0;
 }
@@ -1462,10 +1462,40 @@ void check_dev_msr()
                    "Try \"# modprobe msr\"");
 }
 
-void check_super_user()
+void check_permissions()
 {
-       if (getuid() != 0)
-               errx(-6, "must be root");
+       struct __user_cap_header_struct cap_header_data;
+       cap_user_header_t cap_header = &cap_header_data;
+       struct __user_cap_data_struct cap_data_data;
+       cap_user_data_t cap_data = &cap_data_data;
+       extern int capget(cap_user_header_t hdrp, cap_user_data_t datap);
+       int do_exit = 0;
+
+       /* check for CAP_SYS_RAWIO */
+       cap_header->pid = getpid();
+       cap_header->version = _LINUX_CAPABILITY_VERSION;
+       if (capget(cap_header, cap_data) < 0)
+               err(-6, "capget(2) failed");
+
+       if ((cap_data->effective & (1 << CAP_SYS_RAWIO)) == 0) {
+               do_exit++;
+               warnx("capget(CAP_SYS_RAWIO) failed,"
+                       " try \"# setcap cap_sys_rawio=ep %s\"", progname);
+       }
+
+       /* test file permissions */
+       if (euidaccess("/dev/cpu/0/msr", R_OK)) {
+               do_exit++;
+               warn("/dev/cpu/0/msr open failed, try chown or chmod +r /dev/cpu/*/msr");
+       }
+
+       /* if all else fails, thell them to be root */
+       if (do_exit)
+               if (getuid() != 0)
+                       warnx("Or simply run as root");
+
+       if (do_exit)
+               exit(-6);
 }
 
 int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model)
@@ -2299,10 +2329,9 @@ void setup_all_buffers(void)
 
 void turbostat_init()
 {
-       check_cpuid();
-
        check_dev_msr();
-       check_super_user();
+       check_permissions();
+       check_cpuid();
 
        setup_all_buffers();
 
@@ -2441,7 +2470,7 @@ int main(int argc, char **argv)
        cmdline(argc, argv);
 
        if (verbose)
-               fprintf(stderr, "turbostat v3.7 Feb 6, 2014"
+               fprintf(stderr, "turbostat v3.8 14-Aug 2014"
                        " - Len Brown <lenb@kernel.org>\n");
 
        turbostat_init();