148bfd359SMateusz Guzik /*- 248bfd359SMateusz Guzik * Copyright (c) 2023 Mateusz Guzik 348bfd359SMateusz Guzik * 448bfd359SMateusz Guzik * SPDX-License-Identifier: BSD-2-Clause 548bfd359SMateusz Guzik */ 648bfd359SMateusz Guzik 748bfd359SMateusz Guzik /* 848bfd359SMateusz Guzik * This program is intended to be compatible with nproc as found in GNU 948bfd359SMateusz Guzik * coreutils. 1048bfd359SMateusz Guzik * 1148bfd359SMateusz Guzik * In order to maintain that, do not add any features here if they are not 1248bfd359SMateusz Guzik * present in said program. If you are looking for anything more advanced you 1348bfd359SMateusz Guzik * probably should patch cpuset(1) instead. 1448bfd359SMateusz Guzik */ 1548bfd359SMateusz Guzik 1648bfd359SMateusz Guzik #include <sys/param.h> 1748bfd359SMateusz Guzik #include <sys/cpuset.h> 1848bfd359SMateusz Guzik 1948bfd359SMateusz Guzik #include <err.h> 2048bfd359SMateusz Guzik #include <errno.h> 2148bfd359SMateusz Guzik #include <getopt.h> 2248bfd359SMateusz Guzik #include <limits.h> 2348bfd359SMateusz Guzik #include <stdbool.h> 2448bfd359SMateusz Guzik #include <stdio.h> 2548bfd359SMateusz Guzik #include <stdlib.h> 2648bfd359SMateusz Guzik #include <sysexits.h> 2748bfd359SMateusz Guzik #include <unistd.h> 2848bfd359SMateusz Guzik 2948bfd359SMateusz Guzik #define OPT_ALL (CHAR_MAX + 1) 3048bfd359SMateusz Guzik #define OPT_IGNORE (CHAR_MAX + 2) 3148bfd359SMateusz Guzik #define OPT_VERSION (CHAR_MAX + 3) 3248bfd359SMateusz Guzik #define OPT_HELP (CHAR_MAX + 4) 3348bfd359SMateusz Guzik 3448bfd359SMateusz Guzik static struct option long_opts[] = { 3548bfd359SMateusz Guzik { "all", no_argument, NULL, OPT_ALL }, 3648bfd359SMateusz Guzik { "ignore", required_argument, NULL, OPT_IGNORE }, 3748bfd359SMateusz Guzik { "version", no_argument, NULL, OPT_VERSION }, 3848bfd359SMateusz Guzik { "help", no_argument, NULL, OPT_HELP }, 3948bfd359SMateusz Guzik { NULL, 0, NULL, 0 } 4048bfd359SMateusz Guzik }; 4148bfd359SMateusz Guzik 4248bfd359SMateusz Guzik static void 4348bfd359SMateusz Guzik help(void) 4448bfd359SMateusz Guzik { 4548bfd359SMateusz Guzik fprintf(stderr, 4648bfd359SMateusz Guzik "usage: nproc [--all] [--ignore=count]\n"); 4748bfd359SMateusz Guzik fprintf(stderr, 4848bfd359SMateusz Guzik " nproc --help\n"); 4948bfd359SMateusz Guzik fprintf(stderr, 5048bfd359SMateusz Guzik " nproc --version\n"); 5148bfd359SMateusz Guzik } 5248bfd359SMateusz Guzik 5348bfd359SMateusz Guzik static void 5448bfd359SMateusz Guzik usage(void) 5548bfd359SMateusz Guzik { 5648bfd359SMateusz Guzik help(); 5748bfd359SMateusz Guzik exit(EX_USAGE); 5848bfd359SMateusz Guzik } 5948bfd359SMateusz Guzik 6048bfd359SMateusz Guzik /* 6148bfd359SMateusz Guzik * GNU variant ships with the --version switch. 6248bfd359SMateusz Guzik * 6348bfd359SMateusz Guzik * While we don't have anything to put there, print something which is 6448bfd359SMateusz Guzik * whitespace-compatible with the original. Version number was taken 6548bfd359SMateusz Guzik * from coreutils this code is in sync with. 6648bfd359SMateusz Guzik */ 6748bfd359SMateusz Guzik static void 6848bfd359SMateusz Guzik version(void) 6948bfd359SMateusz Guzik { 7048bfd359SMateusz Guzik printf("nproc (neither_GNU nor_coreutils) 8.32\n"); 7148bfd359SMateusz Guzik exit(EXIT_SUCCESS); 7248bfd359SMateusz Guzik } 7348bfd359SMateusz Guzik 7448bfd359SMateusz Guzik int 7548bfd359SMateusz Guzik main(int argc, char *argv[]) 7648bfd359SMateusz Guzik { 7748bfd359SMateusz Guzik const char *errstr; 7848bfd359SMateusz Guzik cpuset_t mask; 7948bfd359SMateusz Guzik int ch, cpus, ignore; 8048bfd359SMateusz Guzik bool all_flag; 8148bfd359SMateusz Guzik 8248bfd359SMateusz Guzik ignore = 0; 8348bfd359SMateusz Guzik all_flag = false; 8448bfd359SMateusz Guzik 8548bfd359SMateusz Guzik while ((ch = getopt_long(argc, argv, "", long_opts, NULL)) != -1) { 8648bfd359SMateusz Guzik switch (ch) { 8748bfd359SMateusz Guzik case OPT_ALL: 8848bfd359SMateusz Guzik all_flag = true; 8948bfd359SMateusz Guzik break; 9048bfd359SMateusz Guzik case OPT_IGNORE: 9148bfd359SMateusz Guzik ignore = strtonum(optarg, 0, INT_MAX, &errstr); 9248bfd359SMateusz Guzik if (errstr) 9348bfd359SMateusz Guzik errx(1, "bad ignore count: %s", errstr); 9448bfd359SMateusz Guzik break; 9548bfd359SMateusz Guzik case OPT_VERSION: 9648bfd359SMateusz Guzik version(); 97*606c37c5SCollin Funk __unreachable(); 9848bfd359SMateusz Guzik case OPT_HELP: 9948bfd359SMateusz Guzik help(); 10048bfd359SMateusz Guzik exit(EXIT_SUCCESS); 10148bfd359SMateusz Guzik default: 10248bfd359SMateusz Guzik usage(); 10348bfd359SMateusz Guzik } 10448bfd359SMateusz Guzik } 10548bfd359SMateusz Guzik 10648bfd359SMateusz Guzik argc -= optind; 10748bfd359SMateusz Guzik argv += optind; 10848bfd359SMateusz Guzik 10948bfd359SMateusz Guzik if (argc != 0) 11048bfd359SMateusz Guzik usage(); 11148bfd359SMateusz Guzik 11248bfd359SMateusz Guzik if (all_flag) { 113059320b8SMateusz Guzik cpus = sysconf(_SC_NPROCESSORS_CONF); 11448bfd359SMateusz Guzik if (cpus == -1) 11548bfd359SMateusz Guzik err(1, "sysconf"); 11648bfd359SMateusz Guzik } else { 11748bfd359SMateusz Guzik CPU_ZERO(&mask); 11848bfd359SMateusz Guzik if (cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, 11948bfd359SMateusz Guzik sizeof(mask), &mask) != 0) 12048bfd359SMateusz Guzik err(1, "cpuset_getaffinity"); 12148bfd359SMateusz Guzik cpus = CPU_COUNT(&mask); 12248bfd359SMateusz Guzik } 12348bfd359SMateusz Guzik 12448bfd359SMateusz Guzik if (ignore >= cpus) 12548bfd359SMateusz Guzik cpus = 1; 12648bfd359SMateusz Guzik else 12748bfd359SMateusz Guzik cpus -= ignore; 12848bfd359SMateusz Guzik 12948bfd359SMateusz Guzik printf("%u\n", cpus); 13048bfd359SMateusz Guzik 13148bfd359SMateusz Guzik exit(EXIT_SUCCESS); 13248bfd359SMateusz Guzik } 133