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$"); 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> 42176732Sjeff#include <limits.h> 43176732Sjeff#include <stdio.h> 44176732Sjeff#include <stdlib.h> 45176732Sjeff#include <stdint.h> 46176732Sjeff#include <unistd.h> 47200462Sdelphij#include <string.h> 48176732Sjeff 49227160Sedstatic int Cflag; 50227160Sedstatic int cflag; 51227160Sedstatic int gflag; 52227160Sedstatic int iflag; 53227160Sedstatic int jflag; 54227160Sedstatic int lflag; 55227160Sedstatic int pflag; 56227160Sedstatic int rflag; 57227160Sedstatic int sflag; 58227160Sedstatic int tflag; 59227160Sedstatic int xflag; 60227160Sedstatic id_t id; 61227160Sedstatic cpulevel_t level; 62227160Sedstatic cpuwhich_t which; 63176732Sjeff 64227160Sedstatic void usage(void); 65176732Sjeff 66176732Sjeffstatic void printset(cpuset_t *mask); 67176732Sjeff 68176732Sjeffstatic void 69176732Sjeffparselist(char *list, cpuset_t *mask) 70176732Sjeff{ 71176732Sjeff enum { NONE, NUM, DASH } state; 72176732Sjeff int lastnum; 73176732Sjeff int curnum; 74176732Sjeff char *l; 75176732Sjeff 76217416Sjhb if (strcasecmp(list, "all") == 0) { 77217416Sjhb if (cpuset_getaffinity(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1, 78217416Sjhb sizeof(*mask), mask) != 0) 79217416Sjhb err(EXIT_FAILURE, "getaffinity"); 80217416Sjhb return; 81217416Sjhb } 82176732Sjeff state = NONE; 83176732Sjeff curnum = lastnum = 0; 84176732Sjeff for (l = list; *l != '\0';) { 85176732Sjeff if (isdigit(*l)) { 86176732Sjeff curnum = atoi(l); 87176732Sjeff if (curnum > CPU_SETSIZE) 88176732Sjeff errx(EXIT_FAILURE, 89176732Sjeff "Only %d cpus supported", CPU_SETSIZE); 90176732Sjeff while (isdigit(*l)) 91176732Sjeff l++; 92176732Sjeff switch (state) { 93176732Sjeff case NONE: 94176732Sjeff lastnum = curnum; 95176732Sjeff state = NUM; 96176732Sjeff break; 97176732Sjeff case DASH: 98176732Sjeff for (; lastnum <= curnum; lastnum++) 99176732Sjeff CPU_SET(lastnum, mask); 100176732Sjeff state = NONE; 101176732Sjeff break; 102176732Sjeff case NUM: 103176732Sjeff default: 104176732Sjeff goto parserr; 105176732Sjeff } 106176732Sjeff continue; 107176732Sjeff } 108176732Sjeff switch (*l) { 109176732Sjeff case ',': 110176732Sjeff switch (state) { 111176732Sjeff case NONE: 112176732Sjeff break; 113176732Sjeff case NUM: 114176732Sjeff CPU_SET(curnum, mask); 115176732Sjeff state = NONE; 116176732Sjeff break; 117176732Sjeff case DASH: 118176732Sjeff goto parserr; 119176732Sjeff break; 120176732Sjeff } 121176732Sjeff break; 122176732Sjeff case '-': 123176732Sjeff if (state != NUM) 124176732Sjeff goto parserr; 125176732Sjeff state = DASH; 126176732Sjeff break; 127176732Sjeff default: 128176732Sjeff goto parserr; 129176732Sjeff } 130176732Sjeff l++; 131176732Sjeff } 132176732Sjeff switch (state) { 133176732Sjeff case NONE: 134176732Sjeff break; 135176732Sjeff case NUM: 136176732Sjeff CPU_SET(curnum, mask); 137176732Sjeff break; 138176732Sjeff case DASH: 139176732Sjeff goto parserr; 140176732Sjeff } 141176732Sjeff return; 142176732Sjeffparserr: 143176811Sjeff errx(EXIT_FAILURE, "Malformed cpu-list %s", list); 144176732Sjeff} 145176732Sjeff 146176732Sjeffstatic void 147176732Sjeffprintset(cpuset_t *mask) 148176732Sjeff{ 149176732Sjeff int once; 150176732Sjeff int cpu; 151176732Sjeff 152176732Sjeff for (once = 0, cpu = 0; cpu < CPU_SETSIZE; cpu++) { 153176732Sjeff if (CPU_ISSET(cpu, mask)) { 154176732Sjeff if (once == 0) { 155176732Sjeff printf("%d", cpu); 156176732Sjeff once = 1; 157176732Sjeff } else 158176732Sjeff printf(", %d", cpu); 159176732Sjeff } 160176732Sjeff } 161176732Sjeff printf("\n"); 162176732Sjeff} 163176732Sjeff 164227160Sedstatic const char *whichnames[] = { NULL, "tid", "pid", "cpuset", "irq", "jail" }; 165227160Sedstatic const char *levelnames[] = { NULL, " root", " cpuset", "" }; 166176732Sjeff 167176732Sjeffstatic void 168176732Sjeffprintaffinity(void) 169176732Sjeff{ 170176732Sjeff cpuset_t mask; 171176732Sjeff 172176811Sjeff if (cpuset_getaffinity(level, which, id, sizeof(mask), &mask) != 0) 173176732Sjeff err(EXIT_FAILURE, "getaffinity"); 174176732Sjeff printf("%s %jd%s mask: ", whichnames[which], (intmax_t)id, 175176732Sjeff levelnames[level]); 176176732Sjeff printset(&mask); 177176732Sjeff exit(EXIT_SUCCESS); 178176732Sjeff} 179176732Sjeff 180176732Sjeffstatic void 181176732Sjeffprintsetid(void) 182176732Sjeff{ 183176732Sjeff cpusetid_t setid; 184176732Sjeff 185176732Sjeff /* 186176732Sjeff * Only LEVEL_WHICH && WHICH_CPUSET has a numbered id. 187176732Sjeff */ 188176732Sjeff if (level == CPU_LEVEL_WHICH && !sflag) 189176732Sjeff level = CPU_LEVEL_CPUSET; 190176732Sjeff if (cpuset_getid(level, which, id, &setid)) 191176732Sjeff err(errno, "getid"); 192176732Sjeff printf("%s %jd%s id: %d\n", whichnames[which], (intmax_t)id, 193176732Sjeff levelnames[level], setid); 194176732Sjeff} 195176732Sjeff 196176732Sjeffint 197176732Sjeffmain(int argc, char *argv[]) 198176732Sjeff{ 199176732Sjeff cpusetid_t setid; 200176732Sjeff cpuset_t mask; 201176732Sjeff lwpid_t tid; 202176732Sjeff pid_t pid; 203176732Sjeff int ch; 204176732Sjeff 205176732Sjeff CPU_ZERO(&mask); 206176732Sjeff level = CPU_LEVEL_WHICH; 207176732Sjeff which = CPU_WHICH_PID; 208176732Sjeff id = pid = tid = setid = -1; 209217416Sjhb while ((ch = getopt(argc, argv, "Ccgij:l:p:rs:t:x:")) != -1) { 210176732Sjeff switch (ch) { 211217416Sjhb case 'C': 212217416Sjhb Cflag = 1; 213217416Sjhb break; 214176732Sjeff case 'c': 215176732Sjeff if (rflag) 216176732Sjeff usage(); 217176732Sjeff cflag = 1; 218176732Sjeff level = CPU_LEVEL_CPUSET; 219176732Sjeff break; 220176732Sjeff case 'g': 221176732Sjeff gflag = 1; 222176732Sjeff break; 223176732Sjeff case 'i': 224176732Sjeff iflag = 1; 225176732Sjeff break; 226185435Sbz case 'j': 227185435Sbz jflag = 1; 228185435Sbz which = CPU_WHICH_JAIL; 229185435Sbz id = atoi(optarg); 230185435Sbz break; 231176732Sjeff case 'l': 232176732Sjeff lflag = 1; 233176732Sjeff parselist(optarg, &mask); 234176732Sjeff break; 235176732Sjeff case 'p': 236176732Sjeff pflag = 1; 237176732Sjeff which = CPU_WHICH_PID; 238176732Sjeff id = pid = atoi(optarg); 239176732Sjeff break; 240176732Sjeff case 'r': 241176732Sjeff if (cflag) 242176732Sjeff usage(); 243176732Sjeff level = CPU_LEVEL_ROOT; 244176732Sjeff rflag = 1; 245176732Sjeff break; 246176732Sjeff case 's': 247176732Sjeff sflag = 1; 248176732Sjeff which = CPU_WHICH_CPUSET; 249176732Sjeff id = setid = atoi(optarg); 250176732Sjeff break; 251176732Sjeff case 't': 252176732Sjeff tflag = 1; 253176732Sjeff which = CPU_WHICH_TID; 254176732Sjeff id = tid = atoi(optarg); 255176732Sjeff break; 256178093Sjeff case 'x': 257178093Sjeff xflag = 1; 258178093Sjeff which = CPU_WHICH_IRQ; 259178093Sjeff id = atoi(optarg); 260178093Sjeff break; 261176732Sjeff default: 262176732Sjeff usage(); 263176732Sjeff } 264176732Sjeff } 265176732Sjeff argc -= optind; 266176732Sjeff argv += optind; 267176732Sjeff if (gflag) { 268217416Sjhb if (argc || Cflag || lflag) 269176732Sjeff usage(); 270176732Sjeff /* Only one identity specifier. */ 271185435Sbz if (jflag + xflag + sflag + pflag + tflag > 1) 272176732Sjeff usage(); 273176732Sjeff if (iflag) 274176732Sjeff printsetid(); 275176732Sjeff else 276176732Sjeff printaffinity(); 277176732Sjeff exit(EXIT_SUCCESS); 278176732Sjeff } 279176812Sjeff if (iflag) 280176812Sjeff usage(); 281176732Sjeff /* 282176732Sjeff * The user wants to run a command with a set and possibly cpumask. 283176732Sjeff */ 284176732Sjeff if (argc) { 285217416Sjhb if (Cflag | pflag | rflag | tflag | xflag | jflag) 286176732Sjeff usage(); 287176732Sjeff if (sflag) { 288176732Sjeff if (cpuset_setid(CPU_WHICH_PID, -1, setid)) 289176732Sjeff err(argc, "setid"); 290176812Sjeff } else { 291176732Sjeff if (cpuset(&setid)) 292176732Sjeff err(argc, "newid"); 293176732Sjeff } 294176732Sjeff if (lflag) { 295177131Sjeff if (cpuset_setaffinity(level, CPU_WHICH_PID, 296176812Sjeff -1, sizeof(mask), &mask) != 0) 297176732Sjeff err(EXIT_FAILURE, "setaffinity"); 298176732Sjeff } 299176732Sjeff errno = 0; 300176732Sjeff execvp(*argv, argv); 301176732Sjeff err(errno == ENOENT ? 127 : 126, "%s", *argv); 302176732Sjeff } 303176732Sjeff /* 304176732Sjeff * We're modifying something that presently exists. 305176732Sjeff */ 306217416Sjhb if (Cflag && (sflag || rflag || !pflag || tflag || xflag || jflag)) 307217416Sjhb usage(); 308176732Sjeff if (!lflag && (cflag || rflag)) 309176732Sjeff usage(); 310217416Sjhb if (!lflag && !(Cflag || sflag)) 311176732Sjeff usage(); 312176732Sjeff /* You can only set a mask on a thread. */ 313185435Sbz if (tflag && (sflag | pflag | xflag | jflag)) 314176732Sjeff usage(); 315178093Sjeff /* You can only set a mask on an irq. */ 316185435Sbz if (xflag && (jflag | pflag | sflag | tflag)) 317178093Sjeff usage(); 318217416Sjhb if (Cflag) { 319217416Sjhb /* 320217416Sjhb * Create a new cpuset and move the specified process 321217416Sjhb * into the set. 322217416Sjhb */ 323217416Sjhb if (cpuset(&setid) < 0) 324217416Sjhb err(EXIT_FAILURE, "newid"); 325217416Sjhb sflag = 1; 326217416Sjhb } 327176732Sjeff if (pflag && sflag) { 328176732Sjeff if (cpuset_setid(CPU_WHICH_PID, pid, setid)) 329176732Sjeff err(EXIT_FAILURE, "setid"); 330176732Sjeff /* 331176732Sjeff * If the user specifies a set and a list we want the mask 332176732Sjeff * to effect the pid and not the set. 333176732Sjeff */ 334176732Sjeff which = CPU_WHICH_PID; 335176732Sjeff id = pid; 336176732Sjeff } 337176732Sjeff if (lflag) { 338176811Sjeff if (cpuset_setaffinity(level, which, id, sizeof(mask), 339176732Sjeff &mask) != 0) 340176732Sjeff err(EXIT_FAILURE, "setaffinity"); 341176732Sjeff } 342176732Sjeff 343176732Sjeff exit(EXIT_SUCCESS); 344176732Sjeff} 345176732Sjeff 346227160Sedstatic void 347176732Sjeffusage(void) 348176732Sjeff{ 349176732Sjeff 350176732Sjeff fprintf(stderr, 351176812Sjeff "usage: cpuset [-l cpu-list] [-s setid] cmd ...\n"); 352176732Sjeff fprintf(stderr, 353176811Sjeff " cpuset [-l cpu-list] [-s setid] -p pid\n"); 354176732Sjeff fprintf(stderr, 355217416Sjhb " cpuset [-c] [-l cpu-list] -C -p pid\n"); 356217416Sjhb fprintf(stderr, 357185435Sbz " cpuset [-cr] [-l cpu-list] [-j jailid | -p pid | -t tid | -s setid | -x irq]\n"); 358176732Sjeff fprintf(stderr, 359185435Sbz " cpuset [-cgir] [-j jailid | -p pid | -t tid | -s setid | -x irq]\n"); 360176732Sjeff exit(1); 361176732Sjeff} 362