]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
chcpu: add --sysroot option
authorChristian Goeschel Ndjomouo <cgoesc2@wgu.edu>
Fri, 29 May 2026 23:46:40 +0000 (19:46 -0400)
committerChristian Goeschel Ndjomouo <cgoesc2@wgu.edu>
Tue, 2 Jun 2026 11:45:37 +0000 (07:45 -0400)
This patch makes it possible to configure the CPUs on a Linux
system other than the one on which the chcpu command is called.
To achieve this users can simply define the root directory of
the sys/ directory with the --sysroot command line option. It
is also beneficial for regression tests, as these make use of
sysfs tar archive dumps.

To properly implement this new feature, the syspath initialization
had to be deferred until after all option arguments, especially
--sysroot, have been parsed, which simplified the path access check.

Along the way a small refactoring of the enable,disable,configure &
deconfigure option parsing had been done, more precisely the CPU list
option argument is now saved in a variable 'cpu_list_arg' to defer
the CPU list validity check until after all option arguments have
been parsed to simplify the logic. Lastly, getopt(3)'s 'optarg' variable
is used instead of argv[optind-1] to store the options argument, which
is more idiomatic and readable.

Signed-off-by: Christian Goeschel Ndjomouo <cgoesc2@wgu.edu>
bash-completion/chcpu
sys-utils/chcpu.8.adoc
sys-utils/chcpu.c

index 50b1da4a344cce88d2828af9af0d15d52a30ed80..fb21051d56b567a29c440b74d14d492c873e611c 100644 (file)
@@ -41,6 +41,10 @@ _chcpu_module()
                        COMPREPLY=( $(compgen -W "horizontal vertical" -- $cur) )
                        return 0
                        ;;
+               '-s'|'--sysroot')
+                       COMPREPLY=( $(compgen -d -- $cur) )
+                       return 0
+                       ;;
                '-h'|'--help'|'-V'|'--version')
                        return 0
                        ;;
@@ -52,6 +56,7 @@ _chcpu_module()
                --deconfigure
                --dispatch
                --rescan
+               --sysroot
                --version"
        COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) )
        return 0
index f8aec0f3511936734eceb44e96795217aab1fc30..5b49ab203ee4ba4a2e158d738da6669c92192fdf 100644 (file)
@@ -54,6 +54,9 @@ The workload is concentrated on few CPUs.
 *-r*, *--rescan*::
 Trigger a rescan of CPUs. After a rescan, the Linux kernel recognizes the new CPUs. Use this option on systems that do not automatically detect newly attached CPUs.
 
+*-s*, *--sysroot* _directory_::
+Configure CPUs for a Linux instance other than the instance from which the *chcpu* command is issued. The specified _directory_ is the system root of the Linux instance to be configured.
+
 include::man-common/help-version.adoc[]
 
 == EXIT STATUS
index 1e8f8cb3cf1d981d9686d0fb5796fb774b512b82..cb0b9f5229cf0f15578e90922a873cc4f59e5ce9 100644 (file)
@@ -251,6 +251,7 @@ static void __attribute__((__noreturn__)) usage(void)
                " -g, --deconfigure <cpu-list>  deconfigure cpus\n"
                " -p, --dispatch <mode>         set dispatching mode\n"
                " -r, --rescan                  trigger rescan of cpus\n"
+               " -s, --sysroot <dir>           use the specified directory as system root\n"
                ), stdout);
        fprintf(stdout, USAGE_HELP_OPTIONS(31));
 
@@ -265,6 +266,7 @@ int main(int argc, char *argv[])
        size_t setsize;
        int cmd = -1;
        int c, rc;
+       char *sysroot = NULL, *cpu_list_arg = NULL;
 
        static const struct option longopts[] = {
                { "configure",  required_argument, NULL, 'c' },
@@ -274,6 +276,7 @@ int main(int argc, char *argv[])
                { "enable",     required_argument, NULL, 'e' },
                { "help",       no_argument,       NULL, 'h' },
                { "rescan",     no_argument,       NULL, 'r' },
+               { "sysroot",    required_argument, NULL, 's'},
                { "version",    no_argument,       NULL, 'V' },
                { NULL,         0, NULL, 0 }
        };
@@ -289,58 +292,42 @@ int main(int argc, char *argv[])
        textdomain(PACKAGE);
        close_stdout_atexit();
 
-       ul_path_init_debug();
-       sys = ul_new_path(_PATH_SYS_CPU);
-       if (!sys)
-               err(EXIT_FAILURE, _("failed to initialize sysfs handler"));
-
-       maxcpus = get_max_number_of_cpus();
-       if (maxcpus < 1)
-               errx(EXIT_FAILURE, _("cannot determine NR_CPUS; aborting"));
-
-       if (ul_path_access(sys, F_OK, "online") == 0)
-               ul_path_readf_cpulist(sys, &cpu_set, maxcpus, "online");
-       else
-               cpu_set = CPU_ALLOC(maxcpus);
-       if (!cpu_set)
-               err(EXIT_FAILURE, _("cpuset_alloc failed"));
-
-       setsize = CPU_ALLOC_SIZE(maxcpus);
-
-       while ((c = getopt_long(argc, argv, "c:d:e:g:hp:rV", longopts, NULL)) != -1) {
+       while ((c = getopt_long(argc, argv, "c:d:e:g:hp:rs:V", longopts, NULL)) != -1) {
 
                err_exclusive_options(c, longopts, excl, excl_st);
 
                switch (c) {
                case 'c':
                        cmd = CMD_CPU_CONFIGURE;
-                       cpu_parse(argv[optind - 1], cpu_set, setsize);
+                       cpu_list_arg = optarg;
                        break;
                case 'd':
                        cmd = CMD_CPU_DISABLE;
-                       cpu_parse(argv[optind - 1], cpu_set, setsize);
+                       cpu_list_arg = optarg;
                        break;
                case 'e':
                        cmd = CMD_CPU_ENABLE;
-                       cpu_parse(argv[optind - 1], cpu_set, setsize);
+                       cpu_list_arg = optarg;
                        break;
                case 'g':
                        cmd = CMD_CPU_DECONFIGURE;
-                       cpu_parse(argv[optind - 1], cpu_set, setsize);
+                       cpu_list_arg = optarg;
                        break;
                case 'p':
-                       if (strcmp("horizontal", argv[optind - 1]) == 0)
+                       if (strcmp("horizontal", optarg) == 0)
                                cmd = CMD_CPU_DISPATCH_HORIZONTAL;
-                       else if (strcmp("vertical", argv[optind - 1]) == 0)
+                       else if (strcmp("vertical", optarg) == 0)
                                cmd = CMD_CPU_DISPATCH_VERTICAL;
                        else
                                errx(EXIT_FAILURE, _("unsupported argument: %s"),
-                                    argv[optind -1 ]);
+                                       optarg);
                        break;
                case 'r':
                        cmd = CMD_CPU_RESCAN;
                        break;
-
+               case 's':
+                       sysroot = optarg;
+                       break;
                case 'h':
                        usage();
                case 'V':
@@ -355,6 +342,31 @@ int main(int argc, char *argv[])
                errtryhelp(EXIT_FAILURE);
        }
 
+       ul_path_init_debug();
+       sys = ul_new_path(_PATH_SYS_CPU);
+       if (!sys)
+               err(EXIT_FAILURE, _("failed to initialize sysfs handler"));
+       if (sysroot && ul_path_set_prefix(sys, sysroot) != 0)
+               err(EXIT_FAILURE, _("failed to set up different sysroot"));
+       if (!ul_path_is_accessible(sys))
+               err(EXIT_FAILURE, _("cannot open %s"), _PATH_SYS_CPU);
+
+       maxcpus = get_max_number_of_cpus();
+       if (maxcpus < 1)
+               errx(EXIT_FAILURE, _("cannot determine NR_CPUS; aborting"));
+
+       if (ul_path_access(sys, F_OK, "online") == 0)
+               ul_path_readf_cpulist(sys, &cpu_set, maxcpus, "online");
+       else
+               cpu_set = CPU_ALLOC(maxcpus);
+       if (!cpu_set)
+               err(EXIT_FAILURE, _("cpuset_alloc failed"));
+
+       setsize = CPU_ALLOC_SIZE(maxcpus);
+
+       if (cpu_list_arg)
+               cpu_parse(cpu_list_arg, cpu_set, setsize);
+
        switch (cmd) {
        case CMD_CPU_ENABLE:
                rc = cpu_enable(sys, cpu_set, maxcpus, 1);