]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
tests: (helpers) simple tool to create a child process
authorChristian Goeschel Ndjomouo <cgoesc2@wgu.edu>
Thu, 23 Apr 2026 01:01:43 +0000 (21:01 -0400)
committerChristian Goeschel Ndjomouo <cgoesc2@wgu.edu>
Mon, 4 May 2026 15:50:45 +0000 (11:50 -0400)
This basic helper program can be used to create a child process
to test process attribute inheritances between parent and
child processes, e.g. real-time scheduling attributes with chrt(1)
or utilization clamp settings with uclampset(1), where options
like --reset-on-fork need to be tested.

Signed-off-by: Christian Goeschel Ndjomouo <cgoesc2@wgu.edu>
meson.build
tests/commands.sh
tests/helpers/Makemodule.am
tests/helpers/test_child_create.c [new file with mode: 0644]

index 48070b741bd0a79f6d2e2c85f126b2ae5ce426cd..0e5248da2cce776576237c4eda753bbf26cd52be 100644 (file)
@@ -4006,6 +4006,16 @@ if not is_disabler(exe)
   exes += exe
 endif
 
+exe = executable(
+  'test_child_create',
+  'tests/helpers/test_child_create.c',
+  include_directories : includes,
+  link_with : lib_common,
+  build_by_default: program_tests)
+if not is_disabler(exe)
+  exes += exe
+endif
+
 ############################################################
 
 if conf.get('HAVE_OPENAT').to_string() == '1'
index e68d0b3e363d2d1bdc46fc621537509f5e7ff7a6..07a147382f018fd1e42a354cdd8e422178e86aeb 100644 (file)
@@ -5,6 +5,7 @@ TS_TESTUSER=${TS_TESTUSER:-"nobody"}
 TS_HELPER_BOILERPLATE="${ts_helpersdir}test_boilerplate"
 TS_HELPER_BYTESWAP="${ts_helpersdir}test_byteswap"
 TS_HELPER_CANONICALIZE="${ts_helpersdir}test_canonicalize"
+TS_HELPER_CHILD_CREATE="${ts_helpersdir}test_child_create"
 TS_HELPER_COLORS="${ts_helpersdir}test_colors"
 TS_HELPER_CONFIGS="${ts_helpersdir}test_configs"
 TS_HELPER_CPUSET="${ts_helpersdir}test_cpuset"
index 1e02e68a7818f916bd8597ee7ef90bb4def00691..d374c0db185466911ce318800f91a4f2644831ba 100644 (file)
@@ -63,3 +63,7 @@ endif
 
 check_PROGRAMS += test_open_twice
 test_open_twice_SOURCES = tests/helpers/test_open_twice.c
+
+check_PROGRAMS += test_child_create
+test_child_create_SOURCES = tests/helpers/test_child_create.c
+test_child_create_LDADD = $(LDADD) libcommon.la
diff --git a/tests/helpers/test_child_create.c b/tests/helpers/test_child_create.c
new file mode 100644 (file)
index 0000000..1e06659
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2026 Christian Goeschel Ndjomouo <cgoesc2@wgu.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://gnu.org/licenses/>.
+ */
+
+#include <sys/prctl.h>
+#include <stdint.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <err.h>
+#include <getopt.h>
+#include <errno.h>
+#include "strutils.h"
+
+#define DEFAULT_CHILD_SLEEP_SEC 2
+#define DEFAULT_FORK_DELAY_SEC 1
+
+static void __attribute__((__noreturn__)) usage(void)
+{
+       printf("%s [options] <sleep time>\n\n", program_invocation_short_name);
+       fputs("Options:\n", stdout);
+       fputs(" -d, --delay <sec>  delay (in seconds) before forking\n", stdout);
+       fputs(" -h, --help         show this usage information\n", stdout);
+
+       exit(EXIT_SUCCESS);
+}
+
+int main(int argc, char **argv)
+{
+       int c, status, rc = 0;
+       uint16_t sleep_time = DEFAULT_CHILD_SLEEP_SEC;
+       uint16_t fork_delay = DEFAULT_FORK_DELAY_SEC;
+       pid_t pid = 0;
+
+       static const struct option longopts[] = {
+               { "delay",       1, NULL, 'd' },
+               { "help",       0, NULL, 'h' },
+               { NULL, 0, NULL, 0 },
+       };
+
+       while((c = getopt_long(argc, argv, "hd:", longopts, NULL)) != -1) {
+               switch(c) {
+               case 'd':
+                       fork_delay = strtou16_or_err(optarg, "invalid --delay argument");
+                       break;
+               case 'h':
+                       usage();
+                       break;
+               default:
+                       err(EXIT_FAILURE, "try --help");
+               }
+       }
+
+       if (argc - optind > 1)
+               errx(EXIT_FAILURE, "too many arguments");
+
+       if (optind < argc)
+               sleep_time = strtou16_or_err(argv[optind], "invalid <sleep time> argument");
+
+
+       printf("Parent PID: %d\n", getpid());
+       fflush(stdout);
+
+       sleep(fork_delay);
+
+       errno = 0;
+       pid = fork();
+       switch (pid) {
+       case -1:
+               err(EXIT_FAILURE, "failed to create child process");
+       case 0:
+               errno = 0;
+               rc = prctl(PR_SET_PDEATHSIG, SIGTERM);
+               if (rc < 0)
+                       err(EXIT_FAILURE, "prctl() failed");
+
+               sleep(sleep_time);
+               return EXIT_SUCCESS;
+       default:
+               printf("Child PID: %d\n", pid);
+               fflush(stdout);
+
+               errno = 0;
+               rc = waitpid(pid, &status, 0);
+               if (rc < 0 && errno != ECHILD) {
+                       err(EXIT_FAILURE, "waitpid() failed for child process %d", pid);
+               }
+       }
+       return EXIT_SUCCESS;
+}