1e085f869SStanislav Sedov /*- 2f264409aSStanislav Sedov * Copyright (c) 2008-2011 Stanislav Sedov <stas@FreeBSD.org>. 3e085f869SStanislav Sedov * All rights reserved. 4e085f869SStanislav Sedov * 5e085f869SStanislav Sedov * Redistribution and use in source and binary forms, with or without 6e085f869SStanislav Sedov * modification, are permitted provided that the following conditions 7e085f869SStanislav Sedov * are met: 8e085f869SStanislav Sedov * 1. Redistributions of source code must retain the above copyright 9e085f869SStanislav Sedov * notice, this list of conditions and the following disclaimer. 10e085f869SStanislav Sedov * 2. Redistributions in binary form must reproduce the above copyright 11e085f869SStanislav Sedov * notice, this list of conditions and the following disclaimer in the 12e085f869SStanislav Sedov * documentation and/or other materials provided with the distribution. 13e085f869SStanislav Sedov * 14e085f869SStanislav Sedov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15e085f869SStanislav Sedov * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16e085f869SStanislav Sedov * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17e085f869SStanislav Sedov * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18e085f869SStanislav Sedov * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19e085f869SStanislav Sedov * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20e085f869SStanislav Sedov * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21e085f869SStanislav Sedov * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22e085f869SStanislav Sedov * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23e085f869SStanislav Sedov * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24e085f869SStanislav Sedov */ 25e085f869SStanislav Sedov 26e085f869SStanislav Sedov /* 27e085f869SStanislav Sedov * This utility provides userland access to the cpuctl(4) pseudo-device 28e085f869SStanislav Sedov * features. 29e085f869SStanislav Sedov */ 30e085f869SStanislav Sedov 31e085f869SStanislav Sedov #include <sys/cdefs.h> 32e085f869SStanislav Sedov __FBSDID("$FreeBSD$"); 33e085f869SStanislav Sedov 34e085f869SStanislav Sedov #include <assert.h> 35e085f869SStanislav Sedov #include <stdio.h> 36e085f869SStanislav Sedov #include <stdlib.h> 37e085f869SStanislav Sedov #include <string.h> 38e085f869SStanislav Sedov #include <unistd.h> 39e085f869SStanislav Sedov #include <fcntl.h> 40e085f869SStanislav Sedov #include <err.h> 41e085f869SStanislav Sedov #include <sysexits.h> 42e085f869SStanislav Sedov #include <dirent.h> 43e085f869SStanislav Sedov 44e085f869SStanislav Sedov #include <sys/queue.h> 45e085f869SStanislav Sedov #include <sys/param.h> 46e085f869SStanislav Sedov #include <sys/types.h> 47e085f869SStanislav Sedov #include <sys/stat.h> 48e085f869SStanislav Sedov #include <sys/ioctl.h> 49e085f869SStanislav Sedov #include <sys/cpuctl.h> 50e085f869SStanislav Sedov 51e085f869SStanislav Sedov #include "cpucontrol.h" 52e085f869SStanislav Sedov #include "amd.h" 53e085f869SStanislav Sedov #include "intel.h" 5496ff3b75SFabien Thomas #include "via.h" 55e085f869SStanislav Sedov 56e085f869SStanislav Sedov int verbosity_level = 0; 57e085f869SStanislav Sedov 58e085f869SStanislav Sedov #define DEFAULT_DATADIR "/usr/local/share/cpucontrol" 59e085f869SStanislav Sedov 60e085f869SStanislav Sedov #define FLAG_I 0x01 61e085f869SStanislav Sedov #define FLAG_M 0x02 62e085f869SStanislav Sedov #define FLAG_U 0x04 63e085f869SStanislav Sedov 64b2d75854SStanislav Sedov #define OP_INVAL 0x00 65b2d75854SStanislav Sedov #define OP_READ 0x01 66b2d75854SStanislav Sedov #define OP_WRITE 0x02 67b2d75854SStanislav Sedov #define OP_OR 0x04 68b2d75854SStanislav Sedov #define OP_AND 0x08 69b2d75854SStanislav Sedov 70e085f869SStanislav Sedov #define HIGH(val) (uint32_t)(((val) >> 32) & 0xffffffff) 71e085f869SStanislav Sedov #define LOW(val) (uint32_t)((val) & 0xffffffff) 72e085f869SStanislav Sedov 73e085f869SStanislav Sedov /* 74e085f869SStanislav Sedov * Macros for freeing SLISTs, probably must be in /sys/queue.h 75e085f869SStanislav Sedov */ 76e085f869SStanislav Sedov #define SLIST_FREE(head, field, freef) do { \ 77e085f869SStanislav Sedov typeof(SLIST_FIRST(head)) __elm0; \ 78e085f869SStanislav Sedov typeof(SLIST_FIRST(head)) __elm; \ 79e085f869SStanislav Sedov SLIST_FOREACH_SAFE(__elm, (head), field, __elm0) \ 80e085f869SStanislav Sedov (void)(freef)(__elm); \ 81e085f869SStanislav Sedov } while(0); 82e085f869SStanislav Sedov 83e085f869SStanislav Sedov struct datadir { 84e085f869SStanislav Sedov const char *path; 85e085f869SStanislav Sedov SLIST_ENTRY(datadir) next; 86e085f869SStanislav Sedov }; 8713e403fdSAntoine Brodin static SLIST_HEAD(, datadir) datadirs = SLIST_HEAD_INITIALIZER(datadirs); 88e085f869SStanislav Sedov 89bf70beceSEd Schouten static struct ucode_handler { 90e085f869SStanislav Sedov ucode_probe_t *probe; 91e085f869SStanislav Sedov ucode_update_t *update; 92e085f869SStanislav Sedov } handlers[] = { 93e085f869SStanislav Sedov { intel_probe, intel_update }, 94e085f869SStanislav Sedov { amd_probe, amd_update }, 9596ff3b75SFabien Thomas { via_probe, via_update }, 96e085f869SStanislav Sedov }; 97e085f869SStanislav Sedov #define NHANDLERS (sizeof(handlers) / sizeof(*handlers)) 98e085f869SStanislav Sedov 99e085f869SStanislav Sedov static void usage(void); 100e085f869SStanislav Sedov static int isdir(const char *path); 101e085f869SStanislav Sedov static int do_cpuid(const char *cmdarg, const char *dev); 102*aa1cb750SAttilio Rao static int do_cpuid_count(const char *cmdarg, const char *dev); 103e085f869SStanislav Sedov static int do_msr(const char *cmdarg, const char *dev); 104e085f869SStanislav Sedov static int do_update(const char *dev); 105e085f869SStanislav Sedov static void datadir_add(const char *path); 106e085f869SStanislav Sedov 107e085f869SStanislav Sedov static void __dead2 10810bc3a7fSEd Schouten usage(void) 109e085f869SStanislav Sedov { 110e085f869SStanislav Sedov const char *name; 111e085f869SStanislav Sedov 112e085f869SStanislav Sedov name = getprogname(); 113e085f869SStanislav Sedov if (name == NULL) 114e085f869SStanislav Sedov name = "cpuctl"; 115e085f869SStanislav Sedov fprintf(stderr, "Usage: %s [-vh] [-d datadir] [-m msr[=value] | " 116*aa1cb750SAttilio Rao "-i level | -i level,level_type | -u] device\n", name); 117e085f869SStanislav Sedov exit(EX_USAGE); 118e085f869SStanislav Sedov } 119e085f869SStanislav Sedov 120e085f869SStanislav Sedov static int 121e085f869SStanislav Sedov isdir(const char *path) 122e085f869SStanislav Sedov { 123e085f869SStanislav Sedov int error; 124e085f869SStanislav Sedov struct stat st; 125e085f869SStanislav Sedov 126e085f869SStanislav Sedov error = stat(path, &st); 127e085f869SStanislav Sedov if (error < 0) { 128e085f869SStanislav Sedov WARN(0, "stat(%s)", path); 129e085f869SStanislav Sedov return (error); 130e085f869SStanislav Sedov } 131e085f869SStanislav Sedov return (st.st_mode & S_IFDIR); 132e085f869SStanislav Sedov } 133e085f869SStanislav Sedov 134e085f869SStanislav Sedov static int 135e085f869SStanislav Sedov do_cpuid(const char *cmdarg, const char *dev) 136e085f869SStanislav Sedov { 137e085f869SStanislav Sedov unsigned int level; 138e085f869SStanislav Sedov cpuctl_cpuid_args_t args; 139e085f869SStanislav Sedov int fd, error; 140e085f869SStanislav Sedov char *endptr; 141e085f869SStanislav Sedov 142e085f869SStanislav Sedov assert(cmdarg != NULL); 143e085f869SStanislav Sedov assert(dev != NULL); 144e085f869SStanislav Sedov 145e085f869SStanislav Sedov level = strtoul(cmdarg, &endptr, 16); 146e085f869SStanislav Sedov if (*cmdarg == '\0' || *endptr != '\0') { 147e085f869SStanislav Sedov WARNX(0, "incorrect operand: %s", cmdarg); 148e085f869SStanislav Sedov usage(); 149e085f869SStanislav Sedov /* NOTREACHED */ 150e085f869SStanislav Sedov } 151e085f869SStanislav Sedov 152e085f869SStanislav Sedov /* 153e085f869SStanislav Sedov * Fill ioctl argument structure. 154e085f869SStanislav Sedov */ 155e085f869SStanislav Sedov args.level = level; 156e085f869SStanislav Sedov fd = open(dev, O_RDONLY); 157e085f869SStanislav Sedov if (fd < 0) { 158cbcc5579SStanislav Sedov WARN(0, "error opening %s for reading", dev); 159e085f869SStanislav Sedov return (1); 160e085f869SStanislav Sedov } 161e085f869SStanislav Sedov error = ioctl(fd, CPUCTL_CPUID, &args); 162e085f869SStanislav Sedov if (error < 0) { 163cbcc5579SStanislav Sedov WARN(0, "ioctl(%s, CPUCTL_CPUID)", dev); 164e085f869SStanislav Sedov close(fd); 165e085f869SStanislav Sedov return (error); 166e085f869SStanislav Sedov } 167e085f869SStanislav Sedov fprintf(stdout, "cpuid level 0x%x: 0x%.8x 0x%.8x 0x%.8x 0x%.8x\n", 168e085f869SStanislav Sedov level, args.data[0], args.data[1], args.data[2], args.data[3]); 169e085f869SStanislav Sedov close(fd); 170e085f869SStanislav Sedov return (0); 171e085f869SStanislav Sedov } 172e085f869SStanislav Sedov 173e085f869SStanislav Sedov static int 174*aa1cb750SAttilio Rao do_cpuid_count(const char *cmdarg, const char *dev) 175*aa1cb750SAttilio Rao { 176*aa1cb750SAttilio Rao char *cmdarg1, *endptr, *endptr1; 177*aa1cb750SAttilio Rao unsigned int level, level_type; 178*aa1cb750SAttilio Rao cpuctl_cpuid_args_t args; 179*aa1cb750SAttilio Rao int fd, error; 180*aa1cb750SAttilio Rao 181*aa1cb750SAttilio Rao assert(cmdarg != NULL); 182*aa1cb750SAttilio Rao assert(dev != NULL); 183*aa1cb750SAttilio Rao 184*aa1cb750SAttilio Rao level = strtoul(cmdarg, &endptr, 16); 185*aa1cb750SAttilio Rao if (*cmdarg == '\0' || *endptr == '\0') { 186*aa1cb750SAttilio Rao WARNX(0, "incorrect or missing operand: %s", cmdarg); 187*aa1cb750SAttilio Rao usage(); 188*aa1cb750SAttilio Rao /* NOTREACHED */ 189*aa1cb750SAttilio Rao } 190*aa1cb750SAttilio Rao /* Locate the comma... */ 191*aa1cb750SAttilio Rao cmdarg1 = strstr(endptr, ","); 192*aa1cb750SAttilio Rao /* ... and skip past it */ 193*aa1cb750SAttilio Rao cmdarg1 += 1; 194*aa1cb750SAttilio Rao level_type = strtoul(cmdarg1, &endptr1, 16); 195*aa1cb750SAttilio Rao if (*cmdarg1 == '\0' || *endptr1 != '\0') { 196*aa1cb750SAttilio Rao WARNX(0, "incorrect or missing operand: %s", cmdarg); 197*aa1cb750SAttilio Rao usage(); 198*aa1cb750SAttilio Rao /* NOTREACHED */ 199*aa1cb750SAttilio Rao } 200*aa1cb750SAttilio Rao 201*aa1cb750SAttilio Rao /* 202*aa1cb750SAttilio Rao * Fill ioctl argument structure. 203*aa1cb750SAttilio Rao */ 204*aa1cb750SAttilio Rao args.level = level; 205*aa1cb750SAttilio Rao args.level_type = level_type; 206*aa1cb750SAttilio Rao fd = open(dev, O_RDONLY); 207*aa1cb750SAttilio Rao if (fd < 0) { 208*aa1cb750SAttilio Rao WARN(0, "error opening %s for reading", dev); 209*aa1cb750SAttilio Rao return (1); 210*aa1cb750SAttilio Rao } 211*aa1cb750SAttilio Rao error = ioctl(fd, CPUCTL_CPUID_COUNT, &args); 212*aa1cb750SAttilio Rao if (error < 0) { 213*aa1cb750SAttilio Rao WARN(0, "ioctl(%s, CPUCTL_CPUID_COUNT)", dev); 214*aa1cb750SAttilio Rao close(fd); 215*aa1cb750SAttilio Rao return (error); 216*aa1cb750SAttilio Rao } 217*aa1cb750SAttilio Rao fprintf(stdout, "cpuid level 0x%x, level_type 0x%x: 0x%.8x 0x%.8x " 218*aa1cb750SAttilio Rao "0x%.8x 0x%.8x\n", level, level_type, args.data[0], args.data[1], 219*aa1cb750SAttilio Rao args.data[2], args.data[3]); 220*aa1cb750SAttilio Rao close(fd); 221*aa1cb750SAttilio Rao return (0); 222*aa1cb750SAttilio Rao } 223*aa1cb750SAttilio Rao 224*aa1cb750SAttilio Rao static int 225e085f869SStanislav Sedov do_msr(const char *cmdarg, const char *dev) 226e085f869SStanislav Sedov { 227e085f869SStanislav Sedov unsigned int msr; 228e085f869SStanislav Sedov cpuctl_msr_args_t args; 229b2d75854SStanislav Sedov size_t len; 230b2d75854SStanislav Sedov uint64_t data = 0; 231b2d75854SStanislav Sedov unsigned long command; 232b2d75854SStanislav Sedov int do_invert = 0, op; 233e085f869SStanislav Sedov int fd, error; 234f264409aSStanislav Sedov const char *command_name; 235e085f869SStanislav Sedov char *endptr; 236b2d75854SStanislav Sedov char *p; 237e085f869SStanislav Sedov 238e085f869SStanislav Sedov assert(cmdarg != NULL); 239e085f869SStanislav Sedov assert(dev != NULL); 240b2d75854SStanislav Sedov len = strlen(cmdarg); 241b2d75854SStanislav Sedov if (len == 0) { 242b2d75854SStanislav Sedov WARNX(0, "MSR register expected"); 243b2d75854SStanislav Sedov usage(); 244b2d75854SStanislav Sedov /* NOTREACHED */ 245b2d75854SStanislav Sedov } 246e085f869SStanislav Sedov 247b2d75854SStanislav Sedov /* 248b2d75854SStanislav Sedov * Parse command string. 249b2d75854SStanislav Sedov */ 250b2d75854SStanislav Sedov msr = strtoul(cmdarg, &endptr, 16); 251b2d75854SStanislav Sedov switch (*endptr) { 252b2d75854SStanislav Sedov case '\0': 253b2d75854SStanislav Sedov op = OP_READ; 254b2d75854SStanislav Sedov break; 255b2d75854SStanislav Sedov case '=': 256b2d75854SStanislav Sedov op = OP_WRITE; 257b2d75854SStanislav Sedov break; 258b2d75854SStanislav Sedov case '&': 259b2d75854SStanislav Sedov op = OP_AND; 260b2d75854SStanislav Sedov endptr++; 261b2d75854SStanislav Sedov break; 262b2d75854SStanislav Sedov case '|': 263b2d75854SStanislav Sedov op = OP_OR; 264b2d75854SStanislav Sedov endptr++; 265b2d75854SStanislav Sedov break; 266b2d75854SStanislav Sedov default: 267b2d75854SStanislav Sedov op = OP_INVAL; 268b2d75854SStanislav Sedov } 269b2d75854SStanislav Sedov if (op != OP_READ) { /* Complex operation. */ 270b2d75854SStanislav Sedov if (*endptr != '=') 271b2d75854SStanislav Sedov op = OP_INVAL; 272b2d75854SStanislav Sedov else { 273b2d75854SStanislav Sedov p = ++endptr; 274b2d75854SStanislav Sedov if (*p == '~') { 275b2d75854SStanislav Sedov do_invert = 1; 276b2d75854SStanislav Sedov p++; 277b2d75854SStanislav Sedov } 278b2d75854SStanislav Sedov data = strtoull(p, &endptr, 16); 279e085f869SStanislav Sedov if (*p == '\0' || *endptr != '\0') { 280b2d75854SStanislav Sedov WARNX(0, "argument required: %s", cmdarg); 281e085f869SStanislav Sedov usage(); 282e085f869SStanislav Sedov /* NOTREACHED */ 283e085f869SStanislav Sedov } 284e085f869SStanislav Sedov } 285b2d75854SStanislav Sedov } 286b2d75854SStanislav Sedov if (op == OP_INVAL) { 287b2d75854SStanislav Sedov WARNX(0, "invalid operator: %s", cmdarg); 288e085f869SStanislav Sedov usage(); 289e085f869SStanislav Sedov /* NOTREACHED */ 290e085f869SStanislav Sedov } 291e085f869SStanislav Sedov 292e085f869SStanislav Sedov /* 293e085f869SStanislav Sedov * Fill ioctl argument structure. 294e085f869SStanislav Sedov */ 295e085f869SStanislav Sedov args.msr = msr; 296b2d75854SStanislav Sedov if ((do_invert != 0) ^ (op == OP_AND)) 297b2d75854SStanislav Sedov args.data = ~data; 298b2d75854SStanislav Sedov else 299b2d75854SStanislav Sedov args.data = data; 300b2d75854SStanislav Sedov switch (op) { 301b2d75854SStanislav Sedov case OP_READ: 302b2d75854SStanislav Sedov command = CPUCTL_RDMSR; 3033b232eb6SStanislav Sedov command_name = "RDMSR"; 304b2d75854SStanislav Sedov break; 305b2d75854SStanislav Sedov case OP_WRITE: 306b2d75854SStanislav Sedov command = CPUCTL_WRMSR; 3073b232eb6SStanislav Sedov command_name = "WRMSR"; 308b2d75854SStanislav Sedov break; 309b2d75854SStanislav Sedov case OP_OR: 310b2d75854SStanislav Sedov command = CPUCTL_MSRSBIT; 3113b232eb6SStanislav Sedov command_name = "MSRSBIT"; 312b2d75854SStanislav Sedov break; 313b2d75854SStanislav Sedov case OP_AND: 314b2d75854SStanislav Sedov command = CPUCTL_MSRCBIT; 3153b232eb6SStanislav Sedov command_name = "MSRCBIT"; 316b2d75854SStanislav Sedov break; 317b2d75854SStanislav Sedov default: 318b2d75854SStanislav Sedov abort(); 319b2d75854SStanislav Sedov } 320b2d75854SStanislav Sedov fd = open(dev, op == OP_READ ? O_RDONLY : O_WRONLY); 321e085f869SStanislav Sedov if (fd < 0) { 322cbcc5579SStanislav Sedov WARN(0, "error opening %s for %s", dev, 323b2d75854SStanislav Sedov op == OP_READ ? "reading" : "writing"); 324e085f869SStanislav Sedov return (1); 325e085f869SStanislav Sedov } 326b2d75854SStanislav Sedov error = ioctl(fd, command, &args); 327e085f869SStanislav Sedov if (error < 0) { 3283b232eb6SStanislav Sedov WARN(0, "ioctl(%s, CPUCTL_%s (%lu))", dev, command_name, command); 329e085f869SStanislav Sedov close(fd); 330e085f869SStanislav Sedov return (1); 331e085f869SStanislav Sedov } 332b2d75854SStanislav Sedov if (op == OP_READ) 333e085f869SStanislav Sedov fprintf(stdout, "MSR 0x%x: 0x%.8x 0x%.8x\n", msr, 334e085f869SStanislav Sedov HIGH(args.data), LOW(args.data)); 335e085f869SStanislav Sedov close(fd); 336e085f869SStanislav Sedov return (0); 337e085f869SStanislav Sedov } 338e085f869SStanislav Sedov 339e085f869SStanislav Sedov static int 340e085f869SStanislav Sedov do_update(const char *dev) 341e085f869SStanislav Sedov { 342e085f869SStanislav Sedov int fd; 343e085f869SStanislav Sedov unsigned int i; 344e085f869SStanislav Sedov int error; 345e085f869SStanislav Sedov struct ucode_handler *handler; 346e085f869SStanislav Sedov struct datadir *dir; 3470bb2aabfSGleb Kurtsou DIR *dirp; 348e085f869SStanislav Sedov struct dirent *direntry; 349e085f869SStanislav Sedov char buf[MAXPATHLEN]; 350e085f869SStanislav Sedov 351e085f869SStanislav Sedov fd = open(dev, O_RDONLY); 352e085f869SStanislav Sedov if (fd < 0) { 353cbcc5579SStanislav Sedov WARN(0, "error opening %s for reading", dev); 354e085f869SStanislav Sedov return (1); 355e085f869SStanislav Sedov } 356e085f869SStanislav Sedov 357e085f869SStanislav Sedov /* 358e085f869SStanislav Sedov * Find the appropriate handler for device. 359e085f869SStanislav Sedov */ 360e085f869SStanislav Sedov for (i = 0; i < NHANDLERS; i++) 361e085f869SStanislav Sedov if (handlers[i].probe(fd) == 0) 362e085f869SStanislav Sedov break; 363e085f869SStanislav Sedov if (i < NHANDLERS) 364e085f869SStanislav Sedov handler = &handlers[i]; 365e085f869SStanislav Sedov else { 366e085f869SStanislav Sedov WARNX(0, "cannot find the appropriate handler for device"); 367e085f869SStanislav Sedov close(fd); 368e085f869SStanislav Sedov return (1); 369e085f869SStanislav Sedov } 370e085f869SStanislav Sedov close(fd); 371e085f869SStanislav Sedov 372e085f869SStanislav Sedov /* 373e085f869SStanislav Sedov * Process every image in specified data directories. 374e085f869SStanislav Sedov */ 375e085f869SStanislav Sedov SLIST_FOREACH(dir, &datadirs, next) { 3760bb2aabfSGleb Kurtsou dirp = opendir(dir->path); 3770bb2aabfSGleb Kurtsou if (dirp == NULL) { 378e085f869SStanislav Sedov WARNX(1, "skipping directory %s: not accessible", dir->path); 379e085f869SStanislav Sedov continue; 380e085f869SStanislav Sedov } 3810bb2aabfSGleb Kurtsou while ((direntry = readdir(dirp)) != NULL) { 382e085f869SStanislav Sedov if (direntry->d_namlen == 0) 383e085f869SStanislav Sedov continue; 384e085f869SStanislav Sedov error = snprintf(buf, sizeof(buf), "%s/%s", dir->path, 385e085f869SStanislav Sedov direntry->d_name); 386e085f869SStanislav Sedov if ((unsigned)error >= sizeof(buf)) 387e085f869SStanislav Sedov WARNX(0, "skipping %s, buffer too short", 388e085f869SStanislav Sedov direntry->d_name); 389e085f869SStanislav Sedov if (isdir(buf) != 0) { 390e085f869SStanislav Sedov WARNX(2, "skipping %s: is a directory", buf); 391e085f869SStanislav Sedov continue; 392e085f869SStanislav Sedov } 393e085f869SStanislav Sedov handler->update(dev, buf); 394e085f869SStanislav Sedov } 3950bb2aabfSGleb Kurtsou error = closedir(dirp); 396e085f869SStanislav Sedov if (error != 0) 397e085f869SStanislav Sedov WARN(0, "closedir(%s)", dir->path); 398e085f869SStanislav Sedov } 399e085f869SStanislav Sedov return (0); 400e085f869SStanislav Sedov } 401e085f869SStanislav Sedov 402e085f869SStanislav Sedov /* 403e085f869SStanislav Sedov * Add new data directory to the search list. 404e085f869SStanislav Sedov */ 405e085f869SStanislav Sedov static void 406e085f869SStanislav Sedov datadir_add(const char *path) 407e085f869SStanislav Sedov { 408e085f869SStanislav Sedov struct datadir *newdir; 409e085f869SStanislav Sedov 410e085f869SStanislav Sedov newdir = (struct datadir *)malloc(sizeof(*newdir)); 411e085f869SStanislav Sedov if (newdir == NULL) 412e085f869SStanislav Sedov err(EX_OSERR, "cannot allocate memory"); 413e085f869SStanislav Sedov newdir->path = path; 414e085f869SStanislav Sedov SLIST_INSERT_HEAD(&datadirs, newdir, next); 415e085f869SStanislav Sedov } 416e085f869SStanislav Sedov 417e085f869SStanislav Sedov int 418e085f869SStanislav Sedov main(int argc, char *argv[]) 419e085f869SStanislav Sedov { 420e085f869SStanislav Sedov int c, flags; 421e085f869SStanislav Sedov const char *cmdarg; 422e085f869SStanislav Sedov const char *dev; 423e085f869SStanislav Sedov int error; 424e085f869SStanislav Sedov 425e085f869SStanislav Sedov flags = 0; 426e085f869SStanislav Sedov error = 0; 427e085f869SStanislav Sedov cmdarg = ""; /* To keep gcc3 happy. */ 428e085f869SStanislav Sedov 429e085f869SStanislav Sedov /* 430e085f869SStanislav Sedov * Add all default data dirs to the list first. 431e085f869SStanislav Sedov */ 432e085f869SStanislav Sedov datadir_add(DEFAULT_DATADIR); 433e085f869SStanislav Sedov while ((c = getopt(argc, argv, "d:hi:m:uv")) != -1) { 434e085f869SStanislav Sedov switch (c) { 435e085f869SStanislav Sedov case 'd': 436e085f869SStanislav Sedov datadir_add(optarg); 437e085f869SStanislav Sedov break; 438e085f869SStanislav Sedov case 'i': 439e085f869SStanislav Sedov flags |= FLAG_I; 440e085f869SStanislav Sedov cmdarg = optarg; 441e085f869SStanislav Sedov break; 442e085f869SStanislav Sedov case 'm': 443e085f869SStanislav Sedov flags |= FLAG_M; 444e085f869SStanislav Sedov cmdarg = optarg; 445e085f869SStanislav Sedov break; 446e085f869SStanislav Sedov case 'u': 447e085f869SStanislav Sedov flags |= FLAG_U; 448e085f869SStanislav Sedov break; 449e085f869SStanislav Sedov case 'v': 450e085f869SStanislav Sedov verbosity_level++; 451e085f869SStanislav Sedov break; 452e085f869SStanislav Sedov case 'h': 453e085f869SStanislav Sedov /* FALLTHROUGH */ 454e085f869SStanislav Sedov default: 455e085f869SStanislav Sedov usage(); 456e085f869SStanislav Sedov /* NOTREACHED */ 457e085f869SStanislav Sedov } 458e085f869SStanislav Sedov } 459e085f869SStanislav Sedov argc -= optind; 460e085f869SStanislav Sedov argv += optind; 461e085f869SStanislav Sedov if (argc < 1) { 462e085f869SStanislav Sedov usage(); 463e085f869SStanislav Sedov /* NOTREACHED */ 464e085f869SStanislav Sedov } 465e085f869SStanislav Sedov dev = argv[0]; 466e085f869SStanislav Sedov c = flags & (FLAG_I | FLAG_M | FLAG_U); 467e085f869SStanislav Sedov switch (c) { 468e085f869SStanislav Sedov case FLAG_I: 469*aa1cb750SAttilio Rao if (strstr(cmdarg, ",") != NULL) 470*aa1cb750SAttilio Rao error = do_cpuid_count(cmdarg, dev); 471*aa1cb750SAttilio Rao else 472e085f869SStanislav Sedov error = do_cpuid(cmdarg, dev); 473e085f869SStanislav Sedov break; 474e085f869SStanislav Sedov case FLAG_M: 475e085f869SStanislav Sedov error = do_msr(cmdarg, dev); 476e085f869SStanislav Sedov break; 477e085f869SStanislav Sedov case FLAG_U: 478e085f869SStanislav Sedov error = do_update(dev); 479e085f869SStanislav Sedov break; 480e085f869SStanislav Sedov default: 481e085f869SStanislav Sedov usage(); /* Only one command can be selected. */ 482e085f869SStanislav Sedov } 483e085f869SStanislav Sedov SLIST_FREE(&datadirs, next, free); 484e085f869SStanislav Sedov return (error); 485e085f869SStanislav Sedov } 486