xref: /freebsd/bin/nproc/nproc.c (revision 606c37c54160479130a7337e45efbdf01d013b13)
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