Path: blob/main/lib/libc/tests/stdlib/system_test.c
178586 views
/*-1* Copyright (c) 2026 Klara, Inc.2*3* SPDX-License-Identifier: BSD-2-Clause4*/56#include <sys/wait.h>78#include <errno.h>9#include <fcntl.h>10#include <pthread.h>11#include <signal.h>12#include <stdio.h>13#include <stdlib.h>14#include <unistd.h>1516#include <atf-c.h>1718ATF_TC(system_true);19ATF_TC_HEAD(system_true, tc)20{21atf_tc_set_md_var(tc, "descr", "system(\"true\")");22}23ATF_TC_BODY(system_true, tc)24{25ATF_REQUIRE_EQ(W_EXITCODE(0, 0), system("true"));26}2728ATF_TC(system_false);29ATF_TC_HEAD(system_false, tc)30{31atf_tc_set_md_var(tc, "descr", "system(\"false\")");32}33ATF_TC_BODY(system_false, tc)34{35ATF_REQUIRE_EQ(W_EXITCODE(1, 0), system("false"));36}3738ATF_TC(system_touch);39ATF_TC_HEAD(system_touch, tc)40{41atf_tc_set_md_var(tc, "descr", "system(\"touch file\")");42}43ATF_TC_BODY(system_touch, tc)44{45/* The file does not exist */46ATF_CHECK_ERRNO(ENOENT, unlink("file"));4748/* Run a command that creates it */49ATF_REQUIRE_EQ(W_EXITCODE(0, 0), system("touch file"));5051/* Now the file exists */52ATF_CHECK_EQ(0, unlink("file"));53}5455ATF_TC(system_null);56ATF_TC_HEAD(system_null, tc)57{58atf_tc_set_md_var(tc, "descr", "system(NULL)");59atf_tc_set_md_var(tc, "require.user", "root");60}61ATF_TC_BODY(system_null, tc)62{63/* First, test in a normal environment */64ATF_REQUIRE_EQ(1, system(NULL));6566/* Now enter an empty chroot */67ATF_REQUIRE_EQ(0, chroot("."));68ATF_REQUIRE_EQ(0, chdir("/"));6970/* Test again with no shell available */71ATF_REQUIRE_EQ(0, system(NULL));72ATF_REQUIRE_EQ(W_EXITCODE(127, 0), system("true"));73}7475/*76* Define PROCMASK_IS_THREADMASK if sigprocmask() gets / sets the thread77* mask in multithreaded programs, which makes it impossible to verify78* that system(3) correctly blocks and unblocks SIGCHLD.79*/80#ifdef __FreeBSD__81#define PROCMASK_IS_THREADMASK 182#endif8384static void *85system_thread(void *arg)86{87char cmd[64];88int i = (int)(intptr_t)arg;8990snprintf(cmd, sizeof(cmd), "rm flag%d ; lockf -ns lock%d true", i, i);91return ((void *)(intptr_t)system(cmd));92}9394static inline int95sigcmpset(const sigset_t *a, const sigset_t *b)96{97return (memcmp(a, b, sizeof(sigset_t)));98}99100ATF_TC(system_concurrent);101ATF_TC_HEAD(system_concurrent, tc)102{103atf_tc_set_md_var(tc, "descr", "Concurrent calls");104}105ATF_TC_BODY(system_concurrent, tc)106{107enum { N = 3 };108struct sigaction sigint, sigquit, sigact;109sigset_t normset, sigset;110pthread_t thr[N];111char fn[8];112int fd[N];113void *arg, *ret;114115/* Create and lock the locks */116for (int i = 0; i < N; i++) {117snprintf(fn, sizeof(fn), "lock%d", i);118fd[i] = open(fn, O_CREAT|O_EXCL|O_EXLOCK|O_CLOEXEC, 0644);119ATF_REQUIRE_MSG(fd[i] >= 0, "%s: %m", fn);120}121122/* Create the flags */123for (int i = 0; i < N; i++) {124snprintf(fn, sizeof(fn), "flag%d", i);125ATF_REQUIRE_EQ(0, symlink(fn, fn));126}127128/* Save the current signal dispositions */129ATF_REQUIRE_EQ(0, sigaction(SIGINT, NULL, &sigint));130ATF_REQUIRE_EQ(0, sigaction(SIGQUIT, NULL, &sigquit));131ATF_REQUIRE_EQ(0, sigprocmask(0, NULL, &normset));132133/* Spawn threads which block on these files */134for (int i = 0; i < N; i++) {135arg = (void *)(intptr_t)i;136ATF_REQUIRE_INTEQ(0,137pthread_create(&thr[i], NULL, system_thread, arg));138}139140/* Wait until the flags are gone */141for (int i = 0; i < N; i++) {142snprintf(fn, sizeof(fn), "flag%d", i);143while (readlink(fn, fn, sizeof(fn)) > 0)144usleep(10000);145ATF_REQUIRE_EQ(ENOENT, errno);146}147148/* Release the locks */149for (int i = 0; i < N; i++) {150/* Check the signal dispositions */151ATF_REQUIRE_EQ(0, sigaction(SIGINT, NULL, &sigact));152ATF_CHECK_EQ(SIG_IGN, sigact.sa_handler);153ATF_REQUIRE_EQ(0, sigaction(SIGQUIT, NULL, &sigact));154ATF_CHECK_EQ(SIG_IGN, sigact.sa_handler);155#ifndef PROCMASK_IS_THREADMASK156ATF_REQUIRE_EQ(0, sigprocmask(0, NULL, &sigset));157ATF_CHECK(sigismember(&sigset, SIGCHLD));158#endif159160/* Close the file, releasing the lock */161ATF_REQUIRE_INTEQ(0, close(fd[i]));162163/* Join the thread and check the return value */164ATF_CHECK_INTEQ(0, pthread_join(thr[i], &ret));165ATF_CHECK_INTEQ(W_EXITCODE(0, 0), (int)(intptr_t)ret);166}167168/* Check the signal dispositions */169ATF_REQUIRE_EQ(0, sigaction(SIGINT, NULL, &sigact));170ATF_CHECK_EQ(sigint.sa_handler, sigact.sa_handler);171ATF_CHECK_EQ(sigint.sa_flags, sigact.sa_flags);172ATF_CHECK_EQ(0, sigcmpset(&sigint.sa_mask, &sigact.sa_mask));173ATF_REQUIRE_EQ(0, sigaction(SIGQUIT, NULL, &sigact));174ATF_CHECK_EQ(sigquit.sa_handler, sigact.sa_handler);175ATF_CHECK_EQ(sigquit.sa_flags, sigact.sa_flags);176ATF_CHECK_EQ(0, sigcmpset(&sigquit.sa_mask, &sigact.sa_mask));177ATF_REQUIRE_EQ(0, sigprocmask(0, NULL, &sigset));178ATF_CHECK_EQ(0, sigcmpset(&sigset, &normset));179}180181ATF_TP_ADD_TCS(tp)182{183ATF_TP_ADD_TC(tp, system_true);184ATF_TP_ADD_TC(tp, system_false);185ATF_TP_ADD_TC(tp, system_touch);186ATF_TP_ADD_TC(tp, system_null);187ATF_TP_ADD_TC(tp, system_concurrent);188return (atf_no_error());189}190191192