1176732Sjeff/* 2176732Sjeff * Copyright (c) 2007, 2008 Jeffrey Roberson <jeff@freebsd.org> 3176732Sjeff * All rights reserved. 4176732Sjeff * 5178093Sjeff * Copyright (c) 2008 Nokia Corporation 6178093Sjeff * All rights reserved. 7178093Sjeff * 8176732Sjeff * Redistribution and use in source and binary forms, with or without 9176732Sjeff * modification, are permitted provided that the following conditions 10176732Sjeff * are met: 11176732Sjeff * 1. Redistributions of source code must retain the above copyright 12176732Sjeff * notice, this list of conditions and the following disclaimer. 13176732Sjeff * 2. Redistributions in binary form must reproduce the above copyright 14176732Sjeff * notice, this list of conditions and the following disclaimer in the 15176732Sjeff * documentation and/or other materials provided with the distribution. 16176732Sjeff * 17176732Sjeff * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18176732Sjeff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19176732Sjeff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20176732Sjeff * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21176732Sjeff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22176732Sjeff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23176732Sjeff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24176732Sjeff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25176732Sjeff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26176732Sjeff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27176732Sjeff * SUCH DAMAGE. 28176732Sjeff */ 29176732Sjeff 30176732Sjeff#include <sys/cdefs.h> 31176732Sjeff__FBSDID("$FreeBSD: stable/10/usr.bin/cpuset/cpuset.c 336039 2018-07-06 19:10:07Z jamie $"); 32176732Sjeff 33176732Sjeff#include <sys/param.h> 34176732Sjeff#include <sys/types.h> 35176732Sjeff#include <sys/time.h> 36176732Sjeff#include <sys/resource.h> 37176732Sjeff#include <sys/cpuset.h> 38176732Sjeff 39176732Sjeff#include <ctype.h> 40176732Sjeff#include <err.h> 41176732Sjeff#include <errno.h> 42336039Sjamie#include <jail.h> 43176732Sjeff#include <limits.h> 44176732Sjeff#include <stdio.h> 45176732Sjeff#include <stdlib.h> 46176732Sjeff#include <stdint.h> 47176732Sjeff#include <unistd.h> 48200462Sdelphij#include <string.h> 49176732Sjeff 50227160Sedstatic int Cflag; 51227160Sedstatic int cflag; 52227160Sedstatic int gflag; 53227160Sedstatic int iflag; 54227160Sedstatic int jflag; 55227160Sedstatic int lflag; 56227160Sedstatic int pflag; 57227160Sedstatic int rflag; 58227160Sedstatic int sflag; 59227160Sedstatic int tflag; 60227160Sedstatic int xflag; 61227160Sedstatic id_t id; 62227160Sedstatic cpulevel_t level; 63227160Sedstatic cpuwhich_t which; 64176732Sjeff 65227160Sedstatic void usage(void); 66176732Sjeff 67176732Sjeffstatic void printset(cpuset_t *mask); 68176732Sjeff 69176732Sjeffstatic void 70176732Sjeffparselist(char *list, cpuset_t *mask) 71176732Sjeff{ 72176732Sjeff enum { NONE, NUM, DASH } state; 73176732Sjeff int lastnum; 74176732Sjeff int curnum; 75176732Sjeff char *l; 76176732Sjeff 77217416Sjhb if (strcasecmp(list, "all") == 0) { 78217416Sjhb if (cpuset_getaffinity(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1, 79217416Sjhb sizeof(*mask), mask) != 0) 80217416Sjhb err(EXIT_FAILURE, "getaffinity"); 81217416Sjhb return; 82217416Sjhb } 83176732Sjeff state = NONE; 84176732Sjeff curnum = lastnum = 0; 85176732Sjeff for (l = list; *l != '\0';) { 86176732Sjeff if (isdigit(*l)) { 87176732Sjeff curnum = atoi(l); 88176732Sjeff if (curnum > CPU_SETSIZE) 89176732Sjeff errx(EXIT_FAILURE, 90176732Sjeff "Only %d cpus supported", CPU_SETSIZE); 91176732Sjeff while (isdigit(*l)) 92176732Sjeff l++; 93176732Sjeff switch (state) { 94176732Sjeff case NONE: 95176732Sjeff lastnum = curnum; 96176732Sjeff state = NUM; 97176732Sjeff break; 98176732Sjeff case DASH: 99176732Sjeff for (; lastnum <= curnum; lastnum++) 100176732Sjeff CPU_SET(lastnum, mask); 101176732Sjeff state = NONE; 102176732Sjeff break; 103176732Sjeff case NUM: 104176732Sjeff default: 105176732Sjeff goto parserr; 106176732Sjeff } 107176732Sjeff continue; 108176732Sjeff } 109176732Sjeff switch (*l) { 110176732Sjeff case ',': 111176732Sjeff switch (state) { 112176732Sjeff case NONE: 113176732Sjeff break; 114176732Sjeff case NUM: 115176732Sjeff CPU_SET(curnum, mask); 116176732Sjeff state = NONE; 117176732Sjeff break; 118176732Sjeff case DASH: 119176732Sjeff goto parserr; 120176732Sjeff break; 121176732Sjeff } 122176732Sjeff break; 123176732Sjeff case '-': 124176732Sjeff if (state != NUM) 125176732Sjeff goto parserr; 126176732Sjeff state = DASH; 127176732Sjeff break; 128176732Sjeff default: 129176732Sjeff goto parserr; 130176732Sjeff } 131176732Sjeff l++; 132176732Sjeff } 133176732Sjeff switch (state) { 134176732Sjeff case NONE: 135176732Sjeff break; 136176732Sjeff case NUM: 137176732Sjeff CPU_SET(curnum, mask); 138176732Sjeff break; 139176732Sjeff case DASH: 140176732Sjeff goto parserr; 141176732Sjeff } 142176732Sjeff return; 143176732Sjeffparserr: 144176811Sjeff errx(EXIT_FAILURE, "Malformed cpu-list %s", list); 145176732Sjeff} 146176732Sjeff 147176732Sjeffstatic void 148176732Sjeffprintset(cpuset_t *mask) 149176732Sjeff{ 150176732Sjeff int once; 151176732Sjeff int cpu; 152176732Sjeff 153176732Sjeff for (once = 0, cpu = 0; cpu < CPU_SETSIZE; cpu++) { 154176732Sjeff if (CPU_ISSET(cpu, mask)) { 155176732Sjeff if (once == 0) { 156176732Sjeff printf("%d", cpu); 157176732Sjeff once = 1; 158176732Sjeff } else 159176732Sjeff printf(", %d", cpu); 160176732Sjeff } 161176732Sjeff } 162176732Sjeff printf("\n"); 163176732Sjeff} 164176732Sjeff 165227160Sedstatic const char *whichnames[] = { NULL, "tid", "pid", "cpuset", "irq", "jail" }; 166227160Sedstatic const char *levelnames[] = { NULL, " root", " cpuset", "" }; 167176732Sjeff 168176732Sjeffstatic void 169176732Sjeffprintaffinity(void) 170176732Sjeff{ 171176732Sjeff cpuset_t mask; 172176732Sjeff 173176811Sjeff if (cpuset_getaffinity(level, which, id, sizeof(mask), &mask) != 0) 174176732Sjeff err(EXIT_FAILURE, "getaffinity"); 175176732Sjeff printf("%s %jd%s mask: ", whichnames[which], (intmax_t)id, 176176732Sjeff levelnames[level]); 177176732Sjeff printset(&mask); 178176732Sjeff exit(EXIT_SUCCESS); 179176732Sjeff} 180176732Sjeff 181176732Sjeffstatic void 182176732Sjeffprintsetid(void) 183176732Sjeff{ 184176732Sjeff cpusetid_t setid; 185176732Sjeff 186176732Sjeff /* 187176732Sjeff * Only LEVEL_WHICH && WHICH_CPUSET has a numbered id. 188176732Sjeff */ 189176732Sjeff if (level == CPU_LEVEL_WHICH && !sflag) 190176732Sjeff level = CPU_LEVEL_CPUSET; 191176732Sjeff if (cpuset_getid(level, which, id, &setid)) 192176732Sjeff err(errno, "getid"); 193176732Sjeff printf("%s %jd%s id: %d\n", whichnames[which], (intmax_t)id, 194176732Sjeff levelnames[level], setid); 195176732Sjeff} 196176732Sjeff 197176732Sjeffint 198176732Sjeffmain(int argc, char *argv[]) 199176732Sjeff{ 200176732Sjeff cpusetid_t setid; 201176732Sjeff cpuset_t mask; 202176732Sjeff lwpid_t tid; 203176732Sjeff pid_t pid; 204176732Sjeff int ch; 205176732Sjeff 206176732Sjeff CPU_ZERO(&mask); 207176732Sjeff level = CPU_LEVEL_WHICH; 208176732Sjeff which = CPU_WHICH_PID; 209176732Sjeff id = pid = tid = setid = -1; 210217416Sjhb while ((ch = getopt(argc, argv, "Ccgij:l:p:rs:t:x:")) != -1) { 211176732Sjeff switch (ch) { 212217416Sjhb case 'C': 213217416Sjhb Cflag = 1; 214217416Sjhb break; 215176732Sjeff case 'c': 216176732Sjeff if (rflag) 217176732Sjeff usage(); 218176732Sjeff cflag = 1; 219176732Sjeff level = CPU_LEVEL_CPUSET; 220176732Sjeff break; 221176732Sjeff case 'g': 222176732Sjeff gflag = 1; 223176732Sjeff break; 224176732Sjeff case 'i': 225176732Sjeff iflag = 1; 226176732Sjeff break; 227185435Sbz case 'j': 228185435Sbz jflag = 1; 229185435Sbz which = CPU_WHICH_JAIL; 230336039Sjamie id = jail_getid(optarg); 231336039Sjamie if (id < 0) 232336039Sjamie errx(EXIT_FAILURE, "%s", jail_errmsg); 233185435Sbz break; 234176732Sjeff case 'l': 235176732Sjeff lflag = 1; 236176732Sjeff parselist(optarg, &mask); 237176732Sjeff break; 238176732Sjeff case 'p': 239176732Sjeff pflag = 1; 240176732Sjeff which = CPU_WHICH_PID; 241176732Sjeff id = pid = atoi(optarg); 242176732Sjeff break; 243176732Sjeff case 'r': 244176732Sjeff if (cflag) 245176732Sjeff usage(); 246176732Sjeff level = CPU_LEVEL_ROOT; 247176732Sjeff rflag = 1; 248176732Sjeff break; 249176732Sjeff case 's': 250176732Sjeff sflag = 1; 251176732Sjeff which = CPU_WHICH_CPUSET; 252176732Sjeff id = setid = atoi(optarg); 253176732Sjeff break; 254176732Sjeff case 't': 255176732Sjeff tflag = 1; 256176732Sjeff which = CPU_WHICH_TID; 257176732Sjeff id = tid = atoi(optarg); 258176732Sjeff break; 259178093Sjeff case 'x': 260178093Sjeff xflag = 1; 261178093Sjeff which = CPU_WHICH_IRQ; 262178093Sjeff id = atoi(optarg); 263178093Sjeff break; 264176732Sjeff default: 265176732Sjeff usage(); 266176732Sjeff } 267176732Sjeff } 268176732Sjeff argc -= optind; 269176732Sjeff argv += optind; 270176732Sjeff if (gflag) { 271217416Sjhb if (argc || Cflag || lflag) 272176732Sjeff usage(); 273176732Sjeff /* Only one identity specifier. */ 274185435Sbz if (jflag + xflag + sflag + pflag + tflag > 1) 275176732Sjeff usage(); 276176732Sjeff if (iflag) 277176732Sjeff printsetid(); 278176732Sjeff else 279176732Sjeff printaffinity(); 280176732Sjeff exit(EXIT_SUCCESS); 281176732Sjeff } 282176812Sjeff if (iflag) 283176812Sjeff usage(); 284176732Sjeff /* 285176732Sjeff * The user wants to run a command with a set and possibly cpumask. 286176732Sjeff */ 287176732Sjeff if (argc) { 288217416Sjhb if (Cflag | pflag | rflag | tflag | xflag | jflag) 289176732Sjeff usage(); 290176732Sjeff if (sflag) { 291176732Sjeff if (cpuset_setid(CPU_WHICH_PID, -1, setid)) 292176732Sjeff err(argc, "setid"); 293176812Sjeff } else { 294176732Sjeff if (cpuset(&setid)) 295176732Sjeff err(argc, "newid"); 296176732Sjeff } 297176732Sjeff if (lflag) { 298177131Sjeff if (cpuset_setaffinity(level, CPU_WHICH_PID, 299176812Sjeff -1, sizeof(mask), &mask) != 0) 300176732Sjeff err(EXIT_FAILURE, "setaffinity"); 301176732Sjeff } 302176732Sjeff errno = 0; 303176732Sjeff execvp(*argv, argv); 304176732Sjeff err(errno == ENOENT ? 127 : 126, "%s", *argv); 305176732Sjeff } 306176732Sjeff /* 307176732Sjeff * We're modifying something that presently exists. 308176732Sjeff */ 309217416Sjhb if (Cflag && (sflag || rflag || !pflag || tflag || xflag || jflag)) 310217416Sjhb usage(); 311176732Sjeff if (!lflag && (cflag || rflag)) 312176732Sjeff usage(); 313217416Sjhb if (!lflag && !(Cflag || sflag)) 314176732Sjeff usage(); 315176732Sjeff /* You can only set a mask on a thread. */ 316185435Sbz if (tflag && (sflag | pflag | xflag | jflag)) 317176732Sjeff usage(); 318178093Sjeff /* You can only set a mask on an irq. */ 319185435Sbz if (xflag && (jflag | pflag | sflag | tflag)) 320178093Sjeff usage(); 321217416Sjhb if (Cflag) { 322217416Sjhb /* 323217416Sjhb * Create a new cpuset and move the specified process 324217416Sjhb * into the set. 325217416Sjhb */ 326217416Sjhb if (cpuset(&setid) < 0) 327217416Sjhb err(EXIT_FAILURE, "newid"); 328217416Sjhb sflag = 1; 329217416Sjhb } 330176732Sjeff if (pflag && sflag) { 331176732Sjeff if (cpuset_setid(CPU_WHICH_PID, pid, setid)) 332176732Sjeff err(EXIT_FAILURE, "setid"); 333176732Sjeff /* 334176732Sjeff * If the user specifies a set and a list we want the mask 335176732Sjeff * to effect the pid and not the set. 336176732Sjeff */ 337176732Sjeff which = CPU_WHICH_PID; 338176732Sjeff id = pid; 339176732Sjeff } 340176732Sjeff if (lflag) { 341176811Sjeff if (cpuset_setaffinity(level, which, id, sizeof(mask), 342176732Sjeff &mask) != 0) 343176732Sjeff err(EXIT_FAILURE, "setaffinity"); 344176732Sjeff } 345176732Sjeff 346176732Sjeff exit(EXIT_SUCCESS); 347176732Sjeff} 348176732Sjeff 349227160Sedstatic void 350176732Sjeffusage(void) 351176732Sjeff{ 352176732Sjeff 353176732Sjeff fprintf(stderr, 354176812Sjeff "usage: cpuset [-l cpu-list] [-s setid] cmd ...\n"); 355176732Sjeff fprintf(stderr, 356176811Sjeff " cpuset [-l cpu-list] [-s setid] -p pid\n"); 357176732Sjeff fprintf(stderr, 358217416Sjhb " cpuset [-c] [-l cpu-list] -C -p pid\n"); 359217416Sjhb fprintf(stderr, 360185435Sbz " cpuset [-cr] [-l cpu-list] [-j jailid | -p pid | -t tid | -s setid | -x irq]\n"); 361176732Sjeff fprintf(stderr, 362185435Sbz " cpuset [-cgir] [-j jailid | -p pid | -t tid | -s setid | -x irq]\n"); 363176732Sjeff exit(1); 364176732Sjeff} 365