diff --git a/bin/cpuset/Makefile b/bin/cpuset/Makefile index d6f58db62901..639dd9812171 100644 --- a/bin/cpuset/Makefile +++ b/bin/cpuset/Makefile @@ -1,7 +1,7 @@ PROG= cpuset -LIBADD= jail +LIBADD= jail util SYMLINKS+= ../..${BINDIR}/cpuset /usr/bin/cpuset .include diff --git a/bin/cpuset/cpuset.c b/bin/cpuset/cpuset.c index 82ffcaeec252..7416e100a3c6 100644 --- a/bin/cpuset/cpuset.c +++ b/bin/cpuset/cpuset.c @@ -1,473 +1,326 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2007, 2008 Jeffrey Roberson * All rights reserved. * * Copyright (c) 2008 Nokia Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #define _WANT_FREEBSD_BITSET #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include static int Cflag; static int cflag; static int dflag; static int gflag; static int iflag; static int jflag; static int lflag; static int nflag; static int pflag; static int rflag; static int sflag; static int tflag; static int xflag; static id_t id; static cpulevel_t level; static cpuwhich_t which; static void usage(void) __dead2; -struct numa_policy { - const char *name; - int policy; -}; - -static struct numa_policy policies[] = { - { "round-robin", DOMAINSET_POLICY_ROUNDROBIN }, - { "rr", DOMAINSET_POLICY_ROUNDROBIN }, - { "first-touch", DOMAINSET_POLICY_FIRSTTOUCH }, - { "ft", DOMAINSET_POLICY_FIRSTTOUCH }, - { "prefer", DOMAINSET_POLICY_PREFER }, - { "interleave", DOMAINSET_POLICY_INTERLEAVE}, - { "il", DOMAINSET_POLICY_INTERLEAVE}, - { NULL, DOMAINSET_POLICY_INVALID } -}; - -static void printset(struct bitset *mask, int size); - -static void -parselist(char *list, struct bitset *mask, int size) -{ - enum { NONE, NUM, DASH } state; - int lastnum; - int curnum; - char *l; - - state = NONE; - curnum = lastnum = 0; - for (l = list; *l != '\0';) { - if (isdigit(*l)) { - curnum = atoi(l); - if (curnum >= size) - errx(EXIT_FAILURE, - "List entry %d exceeds maximum of %d", - curnum, size - 1); - while (isdigit(*l)) - l++; - switch (state) { - case NONE: - lastnum = curnum; - state = NUM; - break; - case DASH: - for (; lastnum <= curnum; lastnum++) - BIT_SET(size, lastnum, mask); - state = NONE; - break; - case NUM: - default: - goto parserr; - } - continue; - } - switch (*l) { - case ',': - switch (state) { - case NONE: - break; - case NUM: - BIT_SET(size, curnum, mask); - state = NONE; - break; - case DASH: - goto parserr; - break; - } - break; - case '-': - if (state != NUM) - goto parserr; - state = DASH; - break; - default: - goto parserr; - } - l++; - } - switch (state) { - case NONE: - break; - case NUM: - BIT_SET(size, curnum, mask); - break; - case DASH: - goto parserr; - } - return; -parserr: - errx(EXIT_FAILURE, "Malformed list %s", list); -} - -static void -parsecpulist(char *list, cpuset_t *mask) -{ - - if (strcasecmp(list, "all") == 0) { - if (cpuset_getaffinity(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1, - sizeof(*mask), mask) != 0) - err(EXIT_FAILURE, "getaffinity"); - return; - } - parselist(list, (struct bitset *)mask, CPU_SETSIZE); -} - -/* - * permissively parse policy:domain list - * allow: - * round-robin:0-4 explicit - * round-robin:all explicit root domains - * 0-4 implicit root policy - * round-robin implicit root domains - * all explicit root domains and implicit policy - */ -static void -parsedomainlist(char *list, domainset_t *mask, int *policyp) -{ - domainset_t rootmask; - struct numa_policy *policy; - char *l; - int p; - - /* - * Use the rootset's policy as the default for unspecified policies. - */ - if (cpuset_getdomain(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1, - sizeof(rootmask), &rootmask, &p) != 0) - err(EXIT_FAILURE, "getdomain"); - - l = list; - for (policy = &policies[0]; policy->name != NULL; policy++) { - if (strncasecmp(l, policy->name, strlen(policy->name)) == 0) { - p = policy->policy; - l += strlen(policy->name); - if (*l != ':' && *l != '\0') - errx(EXIT_FAILURE, "Malformed list %s", list); - if (*l == ':') - l++; - break; - } - } - *policyp = p; - if (strcasecmp(l, "all") == 0 || *l == '\0') { - DOMAINSET_COPY(&rootmask, mask); - return; - } - parselist(l, (struct bitset *)mask, DOMAINSET_SETSIZE); -} - static void printset(struct bitset *mask, int size) { int once; int bit; for (once = 0, bit = 0; bit < size; bit++) { if (BIT_ISSET(size, bit, mask)) { if (once == 0) { printf("%d", bit); once = 1; } else printf(", %d", bit); } } printf("\n"); } static const char *whichnames[] = { NULL, "tid", "pid", "cpuset", "irq", "jail", "domain" }; static const char *levelnames[] = { NULL, " root", " cpuset", "" }; static const char *policynames[] = { "invalid", "round-robin", "first-touch", "prefer", "interleave" }; static void printaffinity(void) { domainset_t domain; cpuset_t mask; int policy; if (cpuset_getaffinity(level, which, id, sizeof(mask), &mask) != 0) err(EXIT_FAILURE, "getaffinity"); printf("%s %jd%s mask: ", whichnames[which], (intmax_t)id, levelnames[level]); printset((struct bitset *)&mask, CPU_SETSIZE); if (dflag || xflag) goto out; if (cpuset_getdomain(level, which, id, sizeof(domain), &domain, &policy) != 0) err(EXIT_FAILURE, "getdomain"); printf("%s %jd%s domain policy: %s mask: ", whichnames[which], (intmax_t)id, levelnames[level], policynames[policy]); printset((struct bitset *)&domain, DOMAINSET_SETSIZE); out: exit(EXIT_SUCCESS); } static void printsetid(void) { cpusetid_t setid; /* * Only LEVEL_WHICH && WHICH_CPUSET has a numbered id. */ if (level == CPU_LEVEL_WHICH && !sflag) level = CPU_LEVEL_CPUSET; if (cpuset_getid(level, which, id, &setid)) err(errno, "getid"); printf("%s %jd%s id: %d\n", whichnames[which], (intmax_t)id, levelnames[level], setid); } int main(int argc, char *argv[]) { domainset_t domains; cpusetid_t setid; cpuset_t mask; int policy; lwpid_t tid; pid_t pid; int ch; CPU_ZERO(&mask); DOMAINSET_ZERO(&domains); policy = DOMAINSET_POLICY_INVALID; level = CPU_LEVEL_WHICH; which = CPU_WHICH_PID; id = pid = tid = setid = -1; while ((ch = getopt(argc, argv, "Ccd:gij:l:n:p:rs:t:x:")) != -1) { switch (ch) { case 'C': Cflag = 1; break; case 'c': cflag = 1; level = CPU_LEVEL_CPUSET; break; case 'd': dflag = 1; which = CPU_WHICH_DOMAIN; id = atoi(optarg); break; case 'g': gflag = 1; break; case 'i': iflag = 1; break; case 'j': jflag = 1; which = CPU_WHICH_JAIL; id = jail_getid(optarg); if (id < 0) errx(EXIT_FAILURE, "%s", jail_errmsg); break; case 'l': lflag = 1; - parsecpulist(optarg, &mask); + cpuset_parselist(optarg, &mask); break; case 'n': nflag = 1; - parsedomainlist(optarg, &domains, &policy); + domainset_parselist(optarg, &domains, &policy); break; case 'p': pflag = 1; which = CPU_WHICH_PID; id = pid = atoi(optarg); break; case 'r': level = CPU_LEVEL_ROOT; rflag = 1; break; case 's': sflag = 1; which = CPU_WHICH_CPUSET; id = setid = atoi(optarg); break; case 't': tflag = 1; which = CPU_WHICH_TID; id = tid = atoi(optarg); break; case 'x': xflag = 1; which = CPU_WHICH_IRQ; id = atoi(optarg); break; default: usage(); } } argc -= optind; argv += optind; if (gflag) { if (argc || Cflag || lflag || nflag) usage(); /* Only one identity specifier. */ if (dflag + jflag + xflag + sflag + pflag + tflag > 1) usage(); if (iflag) printsetid(); else printaffinity(); exit(EXIT_SUCCESS); } if (dflag || iflag || rflag) usage(); /* * The user wants to run a command with a set and possibly cpumask. */ if (argc) { if (Cflag || pflag || tflag || xflag || jflag) usage(); if (sflag) { if (cpuset_setid(CPU_WHICH_PID, -1, setid)) err(argc, "setid"); } else { if (cpuset(&setid)) err(argc, "newid"); } if (lflag) { if (cpuset_setaffinity(level, CPU_WHICH_PID, -1, sizeof(mask), &mask) != 0) err(EXIT_FAILURE, "setaffinity"); } if (nflag) { if (cpuset_setdomain(level, CPU_WHICH_PID, -1, sizeof(domains), &domains, policy) != 0) err(EXIT_FAILURE, "setdomain"); } errno = 0; execvp(*argv, argv); err(errno == ENOENT ? 127 : 126, "%s", *argv); } /* * We're modifying something that presently exists. */ if (Cflag && (jflag || !pflag || sflag || tflag || xflag)) usage(); if ((!lflag && !nflag) && cflag) usage(); if ((!lflag && !nflag) && !(Cflag || sflag)) usage(); /* You can only set a mask on a thread. */ if (tflag && (sflag | pflag | xflag | jflag)) usage(); /* You can only set a mask on an irq. */ if (xflag && (jflag | pflag | sflag | tflag)) usage(); if (Cflag) { /* * Create a new cpuset and move the specified process * into the set. */ if (cpuset(&setid) < 0) err(EXIT_FAILURE, "newid"); sflag = 1; } if (pflag && sflag) { if (cpuset_setid(CPU_WHICH_PID, pid, setid)) err(EXIT_FAILURE, "setid"); /* * If the user specifies a set and a list we want the mask * to effect the pid and not the set. */ which = CPU_WHICH_PID; id = pid; } if (lflag) { if (cpuset_setaffinity(level, which, id, sizeof(mask), &mask) != 0) err(EXIT_FAILURE, "setaffinity"); } if (nflag) { if (cpuset_setdomain(level, which, id, sizeof(domains), &domains, policy) != 0) err(EXIT_FAILURE, "setdomain"); } exit(EXIT_SUCCESS); } static void usage(void) { fprintf(stderr, "usage: cpuset [-l cpu-list] [-n policy:domain-list] [-s setid] cmd ...\n"); fprintf(stderr, " cpuset [-l cpu-list] [-n policy:domain-list] [-s setid] -p pid\n"); fprintf(stderr, " cpuset [-c] [-l cpu-list] [-n policy:domain-list] -C -p pid\n"); fprintf(stderr, " cpuset [-c] [-l cpu-list] [-n policy:domain-list]\n" " [-j jailid | -p pid | -t tid | -s setid | -x irq]\n"); fprintf(stderr, " cpuset -g [-cir]\n" " [-d domain | -j jailid | -p pid | -t tid | -s setid | -x irq]\n"); exit(1); } diff --git a/lib/libutil/Makefile b/lib/libutil/Makefile index 0639745d08fc..2d92c5ba1916 100644 --- a/lib/libutil/Makefile +++ b/lib/libutil/Makefile @@ -1,103 +1,104 @@ SHLIBDIR?= /lib .include PACKAGE= runtime .PATH: ${SRCTOP}/lib/libc/gen # for pw_scan.c LIB= util SHLIB_MAJOR= 9 SRCS= _secure_path.c auth.c cpuset.c expand_number.c flopen.c fparseln.c \ ftime.c getlocalbase.c gr_util.c \ hexdump.c humanize_number.c kinfo_getfile.c \ kinfo_getallproc.c kinfo_getproc.c kinfo_getvmmap.c \ kinfo_getvmobject.c kld.c \ login_auth.c login_cap.c \ login_class.c login_crypt.c login_ok.c login_times.c login_tty.c \ mntopts.c \ pidfile.c property.c pty.c pw_scan.c pw_util.c quotafile.c \ realhostname.c stub.c trimdomain.c uucplock.c INCS= libutil.h login_cap.h mntopts.h CFLAGS+= -DNO__SCCSID .if ${MK_INET6_SUPPORT} != "no" CFLAGS+= -DINET6 .endif CFLAGS+= -I${.CURDIR} -I${SRCTOP}/lib/libc/gen/ MAN+= cpuset.3 expand_number.3 flopen.3 fparseln.3 ftime.3 getlocalbase.3 \ hexdump.3 humanize_number.3 kinfo_getallproc.3 kinfo_getfile.3 \ kinfo_getproc.3 kinfo_getvmmap.3 kinfo_getvmobject.3 kld.3 \ login_auth.3 login_cap.3 \ login_class.3 login_ok.3 login_times.3 login_tty.3 mntopts.3 \ pidfile.3 \ property.3 pty.3 quotafile.3 realhostname.3 realhostname_sa.3 \ _secure_path.3 trimdomain.3 uucplock.3 pw_util.3 MAN+= login.conf.5 +MLINKS+=cpuset.3 domainset_parselist.3 MLINKS+=flopen.3 flopenat.3 MLINKS+=kld.3 kld_isloaded.3 kld.3 kld_load.3 MLINKS+=login_auth.3 auth_cat.3 login_auth.3 auth_checknologin.3 MLINKS+=login_cap.3 login_close.3 login_cap.3 login_getcapbool.3 \ login_cap.3 login_getcaplist.3 login_cap.3 login_getcapnum.3 \ login_cap.3 login_getcapsize.3 login_cap.3 login_getcapstr.3 \ login_cap.3 login_getcaptime.3 login_cap.3 login_getclass.3 \ login_cap.3 login_getclassbyname.3 login_cap.3 login_getpath.3 \ login_cap.3 login_getpwclass.3 login_cap.3 login_getstyle.3 \ login_cap.3 login_getuserclass.3 login_cap.3 login_setcryptfmt.3 MLINKS+=login_class.3 setclasscontext.3 login_class.3 setclassenvironment.3 \ login_class.3 setclassresources.3 login_class.3 setusercontext.3 MLINKS+=login_ok.3 auth_hostok.3 login_ok.3 auth_timeok.3 \ login_ok.3 auth_ttyok.3 MLINKS+=login_times.3 in_lt.3 login_times.3 in_ltm.3 \ login_times.3 in_ltms.3 \ login_times.3 in_lts.3 \ login_times.3 parse_lt.3 MLINKS+=mntopts.3 getmntopts.3 \ mntopts.3 getmntpoint.3 \ mntopts.3 chkdoreload.3 \ mntopts.3 build_iovec.3 \ mntopts.3 build_iovec_argf.3 \ mntopts.3 free_iovec.3 \ mntopts.3 checkpath.3 \ mntopts.3 rmslashes.3 MLINKS+=pidfile.3 pidfile_close.3 \ pidfile.3 pidfile_fileno.3 \ pidfile.3 pidfile_open.3 \ pidfile.3 pidfile_remove.3 \ pidfile.3 pidfile_write.3 MLINKS+=property.3 property_find.3 property.3 properties_free.3 MLINKS+=property.3 properties_read.3 MLINKS+=pty.3 forkpty.3 pty.3 openpty.3 MLINKS+=quotafile.3 quota_close.3 \ quotafile.3 quota_fsname.3 \ quotafile.3 quota_open.3 \ quotafile.3 quota_qfname.3 \ quotafile.3 quota_read.3 \ quotafile.3 quota_statfs.3 \ quotafile.3 quota_write_limits.3 \ quotafile.3 quota_write_usage.3 MLINKS+=uucplock.3 uu_lock.3 uucplock.3 uu_lock_txfr.3 \ uucplock.3 uu_lockerr.3 uucplock.3 uu_unlock.3 MLINKS+=pw_util.3 pw_copy.3 \ pw_util.3 pw_dup.3 \ pw_util.3 pw_edit.3 \ pw_util.3 pw_equal.3 \ pw_util.3 pw_fini.3 \ pw_util.3 pw_init.3 \ pw_util.3 pw_make.3 \ pw_util.3 pw_make_v7.3 \ pw_util.3 pw_mkdb.3 \ pw_util.3 pw_lock.3 \ pw_util.3 pw_scan.3 \ pw_util.3 pw_tempname.3 \ pw_util.3 pw_tmp.3 MLINKS+=cpuset.3 cpuset_parselist.3 HAS_TESTS= SUBDIR.${MK_TESTS}+= tests .include diff --git a/lib/libutil/cpuset.3 b/lib/libutil/cpuset.3 index be29d5309ef0..47dffd209ee6 100644 --- a/lib/libutil/cpuset.3 +++ b/lib/libutil/cpuset.3 @@ -1,78 +1,111 @@ .\" Copyright (c) 2017 Baptiste Daroussin .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd October 31, 2017 +.Dd June 24, 2025 .Dt CPUSET 3 .Os .Sh NAME -.Nm cpuset_parselist -.Nd utility functions for -.Xr cpuset 2 -handling +.Nm cpuset_parselist , +.Nm domainset_parselist +.Nd utility functions for cpuset(2) handling .Sh LIBRARY .Lb libutil .Sh SYNOPSIS .In sys/cpuset.h .In libutil.h .Ft int -.Fn cpuset_parselist "const char *cpu-list" "cpuset_t *mask" +.Fn cpuset_parselist "const char *cpu_list" "cpuset_t *mask" +.Ft int +.Fn domainset_parselist "const char *domain_policy" "domainset_t *domain_mask" "int *policyp" .Sh DESCRIPTION The .Fn cpuset_parselist function parses a .Va cpu-list filling the .Va mask . .Pp The .Va cpu-list may include numbers separated by '-' for ranges and commas separating individual numbers. A special list of .Dq all may be specified in which case the list includes all CPUs from the root set. +.Pp +The +.Fn domainset_parselist +function parses a +.Xr domainset 9 +memory domain allocation policy +specified by +.Va domain_policy +filling the +.Va domain_mask +and the +.Va policyp . +A valid +.Va domain_policy +is formatted as +.Ar policy:domain-list . +See the +.Ar -n +flag in +.Xr cpuset 1 +for a list of valid domain policies. .Sh RETURN VALUES Return values can be the following .Bl -tag -width Er .It Dv CPUSET_PARSE_OK The parsing was successful .It Dv CPUSET_PARSE_ERROR The .Va cpu-list +or +.Va domain-policy format is invalid .It Dv CPUSET_PARSE_GETAFFINITY The .Xr cpuset_getaffinity 2 call has failed .It Dv CPUSET_PARSE_INVALID_CPU -The number of supported CPUs has been exceeded. +The number of supported CPUs or NUMA domains has been exceeded. The maximum number being -.Va CPU_SETSIZE . +.Va CPU_SETSIZE +and +.Va DOMAINSET_SETSIZE +respectively. +.It Dv CPUSET_PARSE_GETDOMAIN +The +.Xr cpuset_getdomain 2 +call has failed .El .Sh SEE ALSO .Xr cpuset 1 , .Xr cpuset 2 , -.Xr cpuset 9 +.Xr numa 4 , +.Xr cpuset 9 , +.Xr domainset 9 .Sh AUTHORS .An Jeffrey Roberson Aq Mt jeff@FreeBSD.org diff --git a/lib/libutil/cpuset.c b/lib/libutil/cpuset.c index 3c374bfa6cac..d4840af7e175 100644 --- a/lib/libutil/cpuset.c +++ b/lib/libutil/cpuset.c @@ -1,113 +1,187 @@ /* * Copyright (c) 2007, 2008 Jeffrey Roberson * All rights reserved. * * Copyright (c) 2008 Nokia Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ +#include +#define _WANT_FREEBSD_BITSET + #include #include +#include #include #include #include #include -int -cpuset_parselist(const char *list, cpuset_t *mask) +struct numa_policy { + const char *name; + int policy; +}; + +static const struct numa_policy policies[] = { + { "round-robin", DOMAINSET_POLICY_ROUNDROBIN }, + { "rr", DOMAINSET_POLICY_ROUNDROBIN }, + { "first-touch", DOMAINSET_POLICY_FIRSTTOUCH }, + { "ft", DOMAINSET_POLICY_FIRSTTOUCH }, + { "prefer", DOMAINSET_POLICY_PREFER }, + { "interleave", DOMAINSET_POLICY_INTERLEAVE}, + { "il", DOMAINSET_POLICY_INTERLEAVE}, + { NULL, DOMAINSET_POLICY_INVALID } +}; + +static int +parselist(const char *list, struct bitset *mask, int size) { enum { NONE, NUM, DASH } state; int lastnum; int curnum; const char *l; - if (strcasecmp(list, "all") == 0) { - if (cpuset_getaffinity(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1, - sizeof(*mask), mask) != 0) - return (CPUSET_PARSE_GETAFFINITY); - return (CPUSET_PARSE_OK); - } state = NONE; curnum = lastnum = 0; for (l = list; *l != '\0';) { if (isdigit(*l)) { curnum = atoi(l); - if (curnum > CPU_SETSIZE) + if (curnum >= size) return (CPUSET_PARSE_INVALID_CPU); while (isdigit(*l)) l++; switch (state) { case NONE: lastnum = curnum; state = NUM; break; case DASH: for (; lastnum <= curnum; lastnum++) - CPU_SET(lastnum, mask); + BIT_SET(size, lastnum, mask); state = NONE; break; case NUM: default: goto parserr; } continue; } switch (*l) { case ',': switch (state) { case NONE: break; case NUM: - CPU_SET(curnum, mask); + BIT_SET(size, curnum, mask); state = NONE; break; case DASH: goto parserr; break; } break; case '-': if (state != NUM) goto parserr; state = DASH; break; default: goto parserr; } l++; } switch (state) { case NONE: break; case NUM: - CPU_SET(curnum, mask); + BIT_SET(size, curnum, mask); break; case DASH: goto parserr; } return (CPUSET_PARSE_OK); parserr: return (CPUSET_PARSE_ERROR); } + +/* + * permissively parse policy:domain list + * allow: + * round-robin:0-4 explicit + * round-robin:all explicit root domains + * 0-4 implicit root policy + * round-robin implicit root domains + * all explicit root domains and implicit policy + */ +int +domainset_parselist(const char *list, domainset_t *mask, int *policyp) +{ + domainset_t rootmask; + const struct numa_policy *policy; + const char *l; + int p; + + /* + * Use the rootset's policy as the default for unspecified policies. + */ + if (cpuset_getdomain(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1, + sizeof(rootmask), &rootmask, &p) != 0) + return (CPUSET_PARSE_GETDOMAIN); + + if (list == NULL || strcasecmp(list, "all") == 0 || *list == '\0') { + *policyp = p; + DOMAINSET_COPY(&rootmask, mask); + return (CPUSET_PARSE_OK); + } + + l = list; + for (policy = &policies[0]; policy->name != NULL; policy++) { + if (strncasecmp(l, policy->name, strlen(policy->name)) == 0) { + p = policy->policy; + l += strlen(policy->name); + if (*l != ':' && *l != '\0') + return (CPUSET_PARSE_ERROR); + if (*l == ':') + l++; + break; + } + } + *policyp = p; + + return (parselist(l, (struct bitset *)mask, DOMAINSET_SETSIZE)); +} + +int +cpuset_parselist(const char *list, cpuset_t *mask) +{ + if (strcasecmp(list, "all") == 0) { + if (cpuset_getaffinity(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1, + sizeof(*mask), mask) != 0) + return (CPUSET_PARSE_GETAFFINITY); + return (CPUSET_PARSE_OK); + } + + return (parselist(list, (struct bitset *)mask, CPU_SETSIZE)); +} diff --git a/lib/libutil/libutil.h b/lib/libutil/libutil.h index 919855184caf..7d8bfdf67fac 100644 --- a/lib/libutil/libutil.h +++ b/lib/libutil/libutil.h @@ -1,267 +1,273 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1996 Peter Wemm . * All rights reserved. * Copyright (c) 2002 Networks Associates Technology, Inc. * All rights reserved. * * Portions of this software were developed for the FreeBSD Project by * ThinkSec AS and NAI Labs, the Security Research Division of Network * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 * ("CBOSS"), as part of the DARPA CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, is permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef _LIBUTIL_H_ #define _LIBUTIL_H_ #include #include #include #ifndef _GID_T_DECLARED typedef __gid_t gid_t; #define _GID_T_DECLARED #endif #ifndef _MODE_T_DECLARED typedef __mode_t mode_t; #define _MODE_T_DECLARED #endif #ifndef _PID_T_DECLARED typedef __pid_t pid_t; #define _PID_T_DECLARED #endif #ifndef _SIZE_T_DECLARED typedef __size_t size_t; #define _SIZE_T_DECLARED #endif #ifndef _UID_T_DECLARED typedef __uid_t uid_t; #define _UID_T_DECLARED #endif #define PROPERTY_MAX_NAME 64 #define PROPERTY_MAX_VALUE 512 /* For properties.c. */ typedef struct _property { struct _property *next; char *name; char *value; } *properties; /* Avoid pulling in all the include files for no need. */ struct in_addr; struct pidfh; struct sockaddr; struct termios; struct winsize; __BEGIN_DECLS char *auth_getval(const char *_name); void clean_environment(const char * const *_white, const char * const *_more_white); int expand_number(const char *_buf, uint64_t *_num); int extattr_namespace_to_string(int _attrnamespace, char **_string); int extattr_string_to_namespace(const char *_string, int *_attrnamespace); int flopen(const char *_path, int _flags, ...); int flopenat(int _dirfd, const char *_path, int _flags, ...); int forkpty(int *_amaster, char *_name, struct termios *_termp, struct winsize *_winp); const char * getlocalbase(void); void hexdump(const void *_ptr, int _length, const char *_hdr, int _flags); int humanize_number(char *_buf, size_t _len, int64_t _number, const char *_suffix, int _scale, int _flags); struct kinfo_file * kinfo_getfile(pid_t _pid, int *_cntp); struct kinfo_vmentry * kinfo_getvmmap(pid_t _pid, int *_cntp); struct kinfo_vmobject * kinfo_getvmobject(int *_cntp); struct kinfo_vmobject * kinfo_getswapvmobject(int *_cntp); struct kinfo_proc * kinfo_getallproc(int *_cntp); struct kinfo_proc * kinfo_getproc(pid_t _pid); int kld_isloaded(const char *_name); int kld_load(const char *_name); int login_tty(int _fd); int openpty(int *_amaster, int *_aslave, char *_name, struct termios *_termp, struct winsize *_winp); int pidfile_close(struct pidfh *_pfh); int pidfile_fileno(const struct pidfh *_pfh); int pidfile_signal(const char *pathp, int sig, pid_t *pidptr); struct pidfh * pidfile_open(const char *_path, mode_t _mode, pid_t *_pidptr); int pidfile_remove(struct pidfh *_pfh); int pidfile_write(struct pidfh *_pfh); void properties_free(properties _list); char *property_find(properties _list, const char *_name); properties properties_read(int _fd); int realhostname(char *_host, size_t _hsize, const struct in_addr *_ip); int realhostname_sa(char *_host, size_t _hsize, struct sockaddr *_addr, int _addrlen); int _secure_path(const char *_path, uid_t _uid, gid_t _gid); void trimdomain(char *_fullhost, int _hostsize); const char * uu_lockerr(int _uu_lockresult); int uu_lock(const char *_ttyname); int uu_unlock(const char *_ttyname); int uu_lock_txfr(const char *_ttyname, pid_t _pid); /* * Conditionally prototype the following functions if the include * files upon which they depend have been included. */ #ifdef _STDIO_H_ char *fparseln(FILE *_fp, size_t *_len, size_t *_lineno, const char _delim[3], int _flags); #endif #ifdef _PWD_H_ int pw_copy(int _ffd, int _tfd, const struct passwd *_pw, struct passwd *_old_pw); struct passwd *pw_dup(const struct passwd *_pw); int pw_edit(int _notsetuid); int pw_equal(const struct passwd *_pw1, const struct passwd *_pw2); void pw_fini(void); int pw_init(const char *_dir, const char *_master); void pw_initpwd(struct passwd *_pw); char *pw_make(const struct passwd *_pw); char *pw_make_v7(const struct passwd *_pw); int pw_mkdb(const char *_user); int pw_lock(void); struct passwd * pw_scan(const char *_line, int _flags); const char * pw_tempname(void); int pw_tmp(int _mfd); #endif #ifdef _GRP_H_ int gr_copy(int __ffd, int _tfd, const struct group *_gr, struct group *_old_gr); struct group * gr_dup(const struct group *_gr); struct group * gr_add(const struct group *_gr, const char *_newmember); int gr_equal(const struct group *_gr1, const struct group *_gr2); void gr_fini(void); int gr_init(const char *_dir, const char *_master); int gr_lock(void); char *gr_make(const struct group *_gr); int gr_mkdb(void); struct group * gr_scan(const char *_line); int gr_tmp(int _mdf); #endif #ifdef _UFS_UFS_QUOTA_H_ struct fstab; struct quotafile; int quota_check_path(const struct quotafile *_qf, const char *_path); void quota_close(struct quotafile *_qf); int quota_convert(struct quotafile *_qf, int _wordsize); const char * quota_fsname(const struct quotafile *_qf); int quota_maxid(struct quotafile *_qf); int quota_off(struct quotafile *_qf); int quota_on(struct quotafile *_qf); struct quotafile * quota_open(struct fstab *_fs, int _quotatype, int _openflags); const char * quota_qfname(const struct quotafile *_qf); int quota_read(struct quotafile *_qf, struct dqblk *_dqb, int _id); int quota_write_limits(struct quotafile *_qf, struct dqblk *_dqb, int _id); int quota_write_usage(struct quotafile *_qf, struct dqblk *_dqb, int _id); #endif #ifdef _SYS_CPUSET_H_ int cpuset_parselist(const char *list, cpuset_t *mask); #define CPUSET_PARSE_OK 0 #define CPUSET_PARSE_GETAFFINITY -1 #define CPUSET_PARSE_ERROR -2 -#define CPUSET_PARSE_INVALID_CPU -3 +#define CPUSET_PARSE_OUT_OF_RANGE -3 +#define CPUSET_PARSE_GETDOMAIN -4 +#define CPUSET_PARSE_INVALID_CPU CPUSET_PARSE_OUT_OF_RANGE /* backwards compat */ +#endif + +#ifdef _SYS_DOMAINSET_H_ +int domainset_parselist(const char *list, domainset_t *mask, int *policyp); #endif __END_DECLS /* fparseln(3) */ #define FPARSELN_UNESCESC 0x01 #define FPARSELN_UNESCCONT 0x02 #define FPARSELN_UNESCCOMM 0x04 #define FPARSELN_UNESCREST 0x08 #define FPARSELN_UNESCALL 0x0f /* Flags for hexdump(3). */ #define HD_COLUMN_MASK 0xff #define HD_DELIM_MASK 0xff00 #define HD_OMIT_COUNT (1 << 16) #define HD_OMIT_HEX (1 << 17) #define HD_OMIT_CHARS (1 << 18) /* Values for humanize_number(3)'s flags parameter. */ #define HN_DECIMAL 0x01 #define HN_NOSPACE 0x02 #define HN_B 0x04 #define HN_DIVISOR_1000 0x08 #define HN_IEC_PREFIXES 0x10 /* Values for humanize_number(3)'s scale parameter. */ #define HN_GETSCALE 0x10 #define HN_AUTOSCALE 0x20 /* Return values from realhostname(). */ #define HOSTNAME_FOUND 0 #define HOSTNAME_INCORRECTNAME 1 #define HOSTNAME_INVALIDADDR 2 #define HOSTNAME_INVALIDNAME 3 /* Flags for pw_scan(). */ #define PWSCAN_MASTER 0x01 #define PWSCAN_WARN 0x02 /* Return values from uu_lock(). */ #define UU_LOCK_INUSE 1 #define UU_LOCK_OK 0 #define UU_LOCK_OPEN_ERR (-1) #define UU_LOCK_READ_ERR (-2) #define UU_LOCK_CREAT_ERR (-3) #define UU_LOCK_WRITE_ERR (-4) #define UU_LOCK_LINK_ERR (-5) #define UU_LOCK_TRY_ERR (-6) #define UU_LOCK_OWNER_ERR (-7) #endif /* !_LIBUTIL_H_ */