Index: lib/libutil/Makefile =================================================================== --- lib/libutil/Makefile +++ lib/libutil/Makefile @@ -9,8 +9,8 @@ LIB= util SHLIB_MAJOR= 9 -SRCS= _secure_path.c auth.c expand_number.c flopen.c fparseln.c gr_util.c \ - hexdump.c humanize_number.c kinfo_getfile.c \ +SRCS= _secure_path.c auth.c cpuset.c expand_number.c flopen.c fparseln.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 \ @@ -27,7 +27,7 @@ CFLAGS+= -I${.CURDIR} -I${SRCTOP}/lib/libc/gen/ -MAN+= expand_number.3 flopen.3 fparseln.3 hexdump.3 \ +MAN+= cpuset.3 expand_number.3 flopen.3 fparseln.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 \ @@ -84,6 +84,7 @@ 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 Index: lib/libutil/cpuset.3 =================================================================== --- /dev/null +++ lib/libutil/cpuset.3 @@ -0,0 +1,80 @@ +.\" 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. +.\" +.\" $FreeBSD$ +.\" +.Dd October 31, 2017 +.Dt CPUSET 3 +.Os +.Sh NAME +.Nm cpuset_parselist +.Nd utility functions for +.Xr 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" +.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. +.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 +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 maximum number being +.Va CPU_SETSIZE . +.El +.Sh SEE ALSO +.Xr cpuset 1 , +.Xr cpuset 2 , +.Xr cpuset 9 +.Sh AUTHORS +.An Jeffrey Roberson Aq Mt jeff@FreeBSD.org Index: lib/libutil/cpuset.c =================================================================== --- /dev/null +++ lib/libutil/cpuset.c @@ -0,0 +1,113 @@ +/* + * 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 +#include + +#include +#include +#include +#include + +int +cpuset_parselist(const char *list, cpuset_t *mask) +{ + 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) + 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); + state = NONE; + break; + case NUM: + default: + goto parserr; + } + continue; + } + switch (*l) { + case ',': + switch (state) { + case NONE: + break; + case NUM: + CPU_SET(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); + break; + case DASH: + goto parserr; + } + return (CPUSET_PARSE_OK); +parserr: + return (CPUSET_PARSE_ERROR); +} Index: lib/libutil/libutil.h =================================================================== --- lib/libutil/libutil.h +++ lib/libutil/libutil.h @@ -202,6 +202,14 @@ 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 +#endif + __END_DECLS /* fparseln(3) */ Index: lib/libutil/tests/Makefile =================================================================== --- lib/libutil/tests/Makefile +++ lib/libutil/tests/Makefile @@ -1,4 +1,4 @@ -# $FreeBSD$ +r# $FreeBSD: head/lib/libutil/tests/Makefile 321201 2017-07-19 14:07:38Z emaste 2 TAP_TESTS_C+= flopen_test TAP_TESTS_C+= grp_test Index: usr.bin/cpuset/Makefile =================================================================== --- usr.bin/cpuset/Makefile +++ usr.bin/cpuset/Makefile @@ -1,5 +1,6 @@ # $FreeBSD$ PROG= cpuset +LIBADD= util .include Index: usr.bin/cpuset/cpuset.c =================================================================== --- usr.bin/cpuset/cpuset.c +++ usr.bin/cpuset/cpuset.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -67,84 +68,6 @@ static void printset(cpuset_t *mask); static void -parselist(char *list, cpuset_t *mask) -{ - enum { NONE, NUM, DASH } state; - int lastnum; - int curnum; - char *l; - - if (strcasecmp(list, "all") == 0) { - if (cpuset_getaffinity(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1, - sizeof(*mask), mask) != 0) - err(EXIT_FAILURE, "getaffinity"); - return; - } - state = NONE; - curnum = lastnum = 0; - for (l = list; *l != '\0';) { - if (isdigit(*l)) { - curnum = atoi(l); - if (curnum > CPU_SETSIZE) - errx(EXIT_FAILURE, - "Only %d cpus supported", CPU_SETSIZE); - while (isdigit(*l)) - l++; - switch (state) { - case NONE: - lastnum = curnum; - state = NUM; - break; - case DASH: - for (; lastnum <= curnum; lastnum++) - CPU_SET(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); - 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); - break; - case DASH: - goto parserr; - } - return; -parserr: - errx(EXIT_FAILURE, "Malformed cpu-list %s", list); -} - -static void printset(cpuset_t *mask) { int once; @@ -235,7 +158,19 @@ break; case 'l': lflag = 1; - parselist(optarg, &mask); + switch (cpuset_parselist(optarg, &mask)) { + case CPUSET_PARSE_ERROR: + errx(EXIT_FAILURE, "Malformed cpu-list %s", + optarg); + break; + case CPUSET_PARSE_GETAFFINITY: + errx(EXIT_FAILURE, "getaffinity"); + break; + case CPUSET_PARSE_INVALID_CPU: + errx(EXIT_FAILURE, + "Only %d cpus supported", CPU_SETSIZE); + break; + } break; case 'p': pflag = 1;