1 /*- 2 * Copyright (c) 2023 Mateusz Guzik 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7 /* 8 * This program is intended to be compatible with nproc as found in GNU 9 * coreutils. 10 * 11 * In order to maintain that, do not add any features here if they are not 12 * present in said program. If you are looking for anything more advanced you 13 * probably should patch cpuset(1) instead. 14 */ 15 16 #include <sys/param.h> 17 #include <sys/cpuset.h> 18 19 #include <err.h> 20 #include <errno.h> 21 #include <getopt.h> 22 #include <limits.h> 23 #include <stdbool.h> 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <sysexits.h> 27 #include <unistd.h> 28 29 #define OPT_ALL (CHAR_MAX + 1) 30 #define OPT_IGNORE (CHAR_MAX + 2) 31 #define OPT_VERSION (CHAR_MAX + 3) 32 #define OPT_HELP (CHAR_MAX + 4) 33 34 static struct option long_opts[] = { 35 { "all", no_argument, NULL, OPT_ALL }, 36 { "ignore", required_argument, NULL, OPT_IGNORE }, 37 { "version", no_argument, NULL, OPT_VERSION }, 38 { "help", no_argument, NULL, OPT_HELP }, 39 { NULL, 0, NULL, 0 } 40 }; 41 42 static void 43 help(void) 44 { 45 fprintf(stderr, 46 "usage: nproc [--all] [--ignore=count]\n"); 47 fprintf(stderr, 48 " nproc --help\n"); 49 fprintf(stderr, 50 " nproc --version\n"); 51 } 52 53 static void 54 usage(void) 55 { 56 help(); 57 exit(EX_USAGE); 58 } 59 60 /* 61 * GNU variant ships with the --version switch. 62 * 63 * While we don't have anything to put there, print something which is 64 * whitespace-compatible with the original. Version number was taken 65 * from coreutils this code is in sync with. 66 */ 67 static void 68 version(void) 69 { 70 printf("nproc (neither_GNU nor_coreutils) 8.32\n"); 71 exit(EXIT_SUCCESS); 72 } 73 74 int 75 main(int argc, char *argv[]) 76 { 77 const char *errstr; 78 cpuset_t mask; 79 int ch, cpus, ignore; 80 bool all_flag; 81 82 ignore = 0; 83 all_flag = false; 84 85 while ((ch = getopt_long(argc, argv, "", long_opts, NULL)) != -1) { 86 switch (ch) { 87 case OPT_ALL: 88 all_flag = true; 89 break; 90 case OPT_IGNORE: 91 ignore = strtonum(optarg, 0, INT_MAX, &errstr); 92 if (errstr) 93 errx(1, "bad ignore count: %s", errstr); 94 break; 95 case OPT_VERSION: 96 version(); 97 __builtin_unreachable(); 98 case OPT_HELP: 99 help(); 100 exit(EXIT_SUCCESS); 101 default: 102 usage(); 103 } 104 } 105 106 argc -= optind; 107 argv += optind; 108 109 if (argc != 0) 110 usage(); 111 112 if (all_flag) { 113 cpus = sysconf(_SC_NPROCESSORS_CONF); 114 if (cpus == -1) 115 err(1, "sysconf"); 116 } else { 117 CPU_ZERO(&mask); 118 if (cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, 119 sizeof(mask), &mask) != 0) 120 err(1, "cpuset_getaffinity"); 121 cpus = CPU_COUNT(&mask); 122 } 123 124 if (ignore >= cpus) 125 cpus = 1; 126 else 127 cpus -= ignore; 128 129 printf("%u\n", cpus); 130 131 exit(EXIT_SUCCESS); 132 } 133