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
help(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
usage(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
version(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
main(int argc,char * argv[])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