From nobody Tue Jul 7 14:16:10 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4gvjvM52TVz6jQ3Q for ; Tue, 07 Jul 2026 14:16:15 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR1" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4gvjvM4FrDz3lYZ for ; Tue, 07 Jul 2026 14:16:15 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1783433775; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=gcNXsjpmRCn+bcsGY7MkAs8ZzQWuPPqIBv/ZmbaW4dI=; b=yBjNjCKmiAtB2J8nYY0eLZaoyuBCWIMXybSviiRc56TpeFRmMvHNvF+LDx2A4lCa6fCuAt WXpBgY7cn0sOq9AUpj524vVTCCdxPT2kKxBdn//hCQuiToel43Q/ZQi5CI1hQjFvW7CJOR orE2hu8CxRLPQ0H3TZ+1wjOsfC2mJI2uTbISemhYF+X53C3qKXfcWZeON7cmH45KlC7BK/ KWYlGW6BalWKEmTGwSKEJZx8DLDsSaJU521rIPqgncnh2TrTY3qBpfAZwrcEC+g1jb/219 NZXKOjFwpAqGZAzxl2L3p8TtKOfLJfxPMB0saN7GBCvRaFmu7ZZ1jWUnirmHpA== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1783433775; a=rsa-sha256; cv=none; b=WwzaFjSjLhX2076FYIcq0AvUKyj43SPolG4uFyzs5sHtoKj674DrA5OhO71BQ+9MZcYM9N rP7RMQmFe/9wZkj9x6mUqfwb01xmBkWYHxbwY9t+SGlbm5kB5sjEwPwLqphpLddNiiwclt pLOS3tc5wiL6oV6FPdz58rz0jjTjk5ItL/i1Xfq5MbV/hGcoCE3Fze+SZr505vrW6IWSFO j0PPMk+EvUgMFv0wuNJ7zmYWjI70sQtKetAAu99OVAOs9HnQjZdZ2HtYfTOU/oibkWyS7e 7XnRk0hmgYRuFWDWhCWqpZoi7OAcezvS5XLMGGHyl20CWlodqhwtjJZdAbZLOA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1783433775; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=gcNXsjpmRCn+bcsGY7MkAs8ZzQWuPPqIBv/ZmbaW4dI=; b=idsNB1gqvPVaUz1ABumrcS+S0rlJZSszTatPTTtNvveFmTYvToWVDq7qdZiJdyhimPL7Hn fz51jZbFAg/pWn94qFqiQ2FmtCRzFF8VyocfMksSY+XiRip3WLRLcs3adUo0PnH0Td3DD8 imjw+yWkehSJN9jU3RDNunJ/I9kfHbt05zNQ/tIv62mmPsZWNL128TeMAj0GnFRi9k5OA7 woGL1sRLzerX1lIU8DWgo1oBJLKW0k+gYOrabqRYj2JU34k1AbcZAsOq6oWIM7yPL13Jm/ o5tFcbRSS/Bi4HxesYtfpdM0qhGk1kN6Aed79f8Ba/whUdjeVubgVK9M+JqDxw== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4gvjvM38JbzfGT for ; Tue, 07 Jul 2026 14:16:15 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 4607d by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Tue, 07 Jul 2026 14:16:10 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Mark Johnston Subject: git: 0083a4d6224f - main - tests/procdesc: Add some test cases for pdopenpid() List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: markj X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 0083a4d6224f1290af31528b55ba27c51e27ba46 Auto-Submitted: auto-generated Date: Tue, 07 Jul 2026 14:16:10 +0000 Message-Id: <6a4d0a2a.4607d.435cde32@gitrepo.freebsd.org> The branch main has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=0083a4d6224f1290af31528b55ba27c51e27ba46 commit 0083a4d6224f1290af31528b55ba27c51e27ba46 Author: Mark Johnston AuthorDate: 2026-07-07 14:14:39 +0000 Commit: Mark Johnston CommitDate: 2026-07-07 14:14:39 +0000 tests/procdesc: Add some test cases for pdopenpid() Reviewed by: kib MFC with: 5c32aa785184 ("kern: add pdopenpid(2)") Differential Revision: https://reviews.freebsd.org/D58023 --- tests/sys/kern/procdesc.c | 467 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 467 insertions(+) diff --git a/tests/sys/kern/procdesc.c b/tests/sys/kern/procdesc.c index 2fe50be45bf7..388104054b82 100644 --- a/tests/sys/kern/procdesc.c +++ b/tests/sys/kern/procdesc.c @@ -27,16 +27,21 @@ */ #include +#include +#include #include #include #include #include #include +#include #include #include #include +#include #include +#include #include #include @@ -205,11 +210,473 @@ ATF_TC_BODY(poll_exit_wakeup, tc) ATF_REQUIRE_MSG(close(pd) == 0, "close: %s", strerror(errno)); } +/* Tests for pdopenpid(2) */ + +/* + * Basic: open a process descriptor for a child, verify pdgetpid() returns the + * right pid. + */ +ATF_TC_WITHOUT_HEAD(pdopenpid_basic); +ATF_TC_BODY(pdopenpid_basic, tc) +{ + pid_t child, queried; + int fd; + + child = fork(); + ATF_REQUIRE_MSG(child >= 0, "fork: %s", strerror(errno)); + if (child == 0) { + for (;;) + pause(); + _exit(0); + } + + fd = pdopenpid(child, 0); + ATF_REQUIRE_MSG(fd >= 0, "pdopenpid: %s", strerror(errno)); + + ATF_REQUIRE_MSG(pdgetpid(fd, &queried) == 0, + "pdgetpid: %s", strerror(errno)); + ATF_REQUIRE_EQ(child, queried); + + ATF_REQUIRE_MSG(pdkill(fd, SIGKILL) == 0, + "pdkill: %s", strerror(errno)); + ATF_REQUIRE_EQ(child, waitpid(child, NULL, 0)); + ATF_REQUIRE(close(fd) == 0); +} + +/* + * pdopenpid with PD_CLOEXEC should set the close-on-exec flag. + */ +ATF_TC_WITHOUT_HEAD(pdopenpid_cloexec); +ATF_TC_BODY(pdopenpid_cloexec, tc) +{ + pid_t child; + int fd, flags; + + child = fork(); + ATF_REQUIRE_MSG(child >= 0, "fork: %s", strerror(errno)); + if (child == 0) { + for (;;) + pause(); + _exit(0); + } + + fd = pdopenpid(child, PD_CLOEXEC); + ATF_REQUIRE_MSG(fd >= 0, "pdopenpid: %s", strerror(errno)); + + flags = fcntl(fd, F_GETFD); + ATF_REQUIRE(flags >= 0); + ATF_REQUIRE(flags & FD_CLOEXEC); + + ATF_REQUIRE_MSG(pdkill(fd, SIGKILL) == 0, + "pdkill: %s", strerror(errno)); + ATF_REQUIRE_EQ(child, waitpid(child, NULL, 0)); + ATF_REQUIRE(close(fd) == 0); +} + +/* + * Invalid flags should return EINVAL. + */ +ATF_TC_WITHOUT_HEAD(pdopenpid_einval); +ATF_TC_BODY(pdopenpid_einval, tc) +{ + ATF_REQUIRE_ERRNO(EINVAL, pdopenpid(getpid(), 0xdeadbeef) < 0); + ATF_REQUIRE_ERRNO(EINVAL, pdopenpid(getpid(), ~PD_ALLOWED_AT_FORK) < 0); +} + +/* + * Validate handling of EMFILE. + */ +ATF_TC_WITHOUT_HEAD(pdopenpid_emfile); +ATF_TC_BODY(pdopenpid_emfile, tc) +{ + pid_t child; + struct rlimit rl; + int fd; + + child = fork(); + ATF_REQUIRE_MSG(child >= 0, "fork: %s", strerror(errno)); + if (child == 0) { + for (;;) + pause(); + _exit(0); + } + + /* + * Determine the lowest unused fd, then set the fd limit to that + * value so that no new fds can be allocated. + */ + fd = dup(STDIN_FILENO); + ATF_REQUIRE(fd >= 0); + ATF_REQUIRE(close(fd) == 0); + + ATF_REQUIRE_EQ(getrlimit(RLIMIT_NOFILE, &rl), 0); + rl.rlim_cur = fd; + ATF_REQUIRE_EQ(setrlimit(RLIMIT_NOFILE, &rl), 0); + + ATF_REQUIRE_ERRNO(EMFILE, pdopenpid(child, 0) < 0); + + /* + * The child should not have been killed or reparented as a side + * effect of the failed syscall. + */ + ATF_REQUIRE_MSG(kill(child, 0) == 0, + "child was killed: %s", strerror(errno)); + ATF_REQUIRE_MSG(waitpid(child, NULL, WNOHANG) == 0, + "child was reparented"); + + ATF_REQUIRE_MSG(kill(child, SIGKILL) == 0, + "kill: %s", strerror(errno)); + ATF_REQUIRE_EQ(child, waitpid(child, NULL, 0)); +} + +/* + * Opening a nonexistent pid should return ESRCH. + */ +ATF_TC_WITHOUT_HEAD(pdopenpid_esrch); +ATF_TC_BODY(pdopenpid_esrch, tc) +{ + ATF_REQUIRE_ERRNO(ESRCH, pdopenpid(123456789, 0) < 0); +} + +/* + * pdopenpid should fail in capability mode. + */ +ATF_TC_WITHOUT_HEAD(pdopenpid_capmode); +ATF_TC_BODY(pdopenpid_capmode, tc) +{ + pid_t child, parent; + + parent = getpid(); + child = fork(); + ATF_REQUIRE_MSG(child >= 0, "fork: %s", strerror(errno)); + if (child == 0) { + while (getppid() == parent) + sleep(1); + _exit(0); + } + + ATF_REQUIRE_MSG(cap_enter() == 0, "cap_enter: %s", strerror(errno)); + ATF_REQUIRE_ERRNO(ECAPMODE, pdopenpid(child, 0) < 0); +} + +/* + * Open a process descriptor for a child that already has one from pdfork(). + * Both fds should refer to the same process. + */ +ATF_TC_WITHOUT_HEAD(pdopenpid_pdfork_then_open); +ATF_TC_BODY(pdopenpid_pdfork_then_open, tc) +{ + pid_t child, pid1, pid2; + int fd1, fd2; + + child = pdfork(&fd1, PD_DAEMON); + ATF_REQUIRE_MSG(child >= 0, "pdfork: %s", strerror(errno)); + if (child == 0) { + for (;;) + pause(); + _exit(0); + } + + fd2 = pdopenpid(child, 0); + ATF_REQUIRE_MSG(fd2 >= 0, "pdopenpid: %s", strerror(errno)); + + ATF_REQUIRE(pdgetpid(fd1, &pid1) == 0); + ATF_REQUIRE(pdgetpid(fd2, &pid2) == 0); + ATF_REQUIRE_EQ(pid1, pid2); + ATF_REQUIRE_EQ(child, pid1); + + /* Kill via the second fd, wait via the first. */ + ATF_REQUIRE_MSG(pdkill(fd2, SIGKILL) == 0, + "pdkill: %s", strerror(errno)); + ATF_REQUIRE_MSG(pdwait(fd1, NULL, WEXITED, NULL, NULL) == 0, + "pdwait: %s", strerror(errno)); + + ATF_REQUIRE(close(fd1) == 0); + ATF_REQUIRE(close(fd2) == 0); +} + +/* + * Open a process descriptor for a child created with fork(), which has no + * pre-existing procdesc. Then use pdkill() and pdwait() on it. + */ +ATF_TC_WITHOUT_HEAD(pdopenpid_fork_then_open); +ATF_TC_BODY(pdopenpid_fork_then_open, tc) +{ + pid_t child; + int fd, status; + + child = fork(); + ATF_REQUIRE_MSG(child >= 0, "fork: %s", strerror(errno)); + if (child == 0) { + for (;;) + pause(); + _exit(0); + } + + fd = pdopenpid(child, 0); + ATF_REQUIRE_MSG(fd >= 0, "pdopenpid: %s", strerror(errno)); + + ATF_REQUIRE_MSG(pdkill(fd, SIGKILL) == 0, + "pdkill: %s", strerror(errno)); + ATF_REQUIRE_MSG(pdwait(fd, &status, WEXITED, NULL, NULL) == 0, + "pdwait: %s", strerror(errno)); + ATF_REQUIRE(WIFSIGNALED(status)); + ATF_REQUIRE_EQ(WTERMSIG(status), SIGKILL); + + ATF_REQUIRE(close(fd) == 0); +} + +/* + * Closing one fd should not kill the process when another fd still references + * the same procdesc. + */ +ATF_TC_WITHOUT_HEAD(pdopenpid_close_one_of_two); +ATF_TC_BODY(pdopenpid_close_one_of_two, tc) +{ + pid_t child, queried; + int fd1, fd2, status; + + child = pdfork(&fd1, PD_DAEMON); + ATF_REQUIRE_MSG(child >= 0, "pdfork: %s", strerror(errno)); + if (child == 0) { + for (;;) + pause(); + _exit(0); + } + + fd2 = pdopenpid(child, 0); + ATF_REQUIRE_MSG(fd2 >= 0, "pdopenpid: %s", strerror(errno)); + + /* Close the first fd; the process should remain alive. */ + ATF_REQUIRE(close(fd1) == 0); + + /* + * Verify the process is still reachable via the second fd and still + * alive. + */ + ATF_REQUIRE_EQ(0, pdgetpid(fd2, &queried)); + ATF_REQUIRE_EQ(child, queried); + ATF_REQUIRE_MSG(pdkill(fd2, 0) == 0, + "pdkill(0) after closing first fd: %s", strerror(errno)); + + /* Now kill and reap via the second fd. */ + ATF_REQUIRE_MSG(pdkill(fd2, SIGKILL) == 0, + "pdkill: %s", strerror(errno)); + ATF_REQUIRE_MSG(pdwait(fd2, &status, WEXITED, NULL, NULL) == 0, + "pdwait: %s", strerror(errno)); + ATF_REQUIRE(WIFSIGNALED(status)); + ATF_REQUIRE_EQ(WTERMSIG(status), SIGKILL); + + ATF_REQUIRE(close(fd2) == 0); +} + +/* + * Two calls to pdopenpid for the same process (no pdfork) should both work. + */ +ATF_TC_WITHOUT_HEAD(pdopenpid_open_twice); +ATF_TC_BODY(pdopenpid_open_twice, tc) +{ + pid_t child, pid1, pid2; + int fd1, fd2; + + child = fork(); + ATF_REQUIRE_MSG(child >= 0, "fork: %s", strerror(errno)); + if (child == 0) { + for (;;) + pause(); + _exit(0); + } + + fd1 = pdopenpid(child, 0); + ATF_REQUIRE_MSG(fd1 >= 0, "pdopenpid(1): %s", strerror(errno)); + + fd2 = pdopenpid(child, 0); + ATF_REQUIRE_MSG(fd2 >= 0, "pdopenpid(2): %s", strerror(errno)); + + ATF_REQUIRE_EQ(0, pdgetpid(fd1, &pid1)); + ATF_REQUIRE_EQ(0, pdgetpid(fd2, &pid2)); + ATF_REQUIRE_EQ(pid1, pid2); + + /* Close the first, process should survive. */ + ATF_REQUIRE(close(fd1) == 0); + ATF_REQUIRE_MSG(pdkill(fd2, 0) == 0, + "pdkill(0) after closing first fd: %s", strerror(errno)); + + ATF_REQUIRE_MSG(pdkill(fd2, SIGKILL) == 0, + "pdkill: %s", strerror(errno)); + ATF_REQUIRE_MSG(pdwait(fd2, NULL, WEXITED, NULL, NULL) == 0, + "pdwait: %s", strerror(errno)); + ATF_REQUIRE(close(fd2) == 0); +} + +/* + * When a process with two procdesc fds exits, only one pdwait should succeed + * in collecting the exit status. The other should get ESRCH. + */ +ATF_TC_WITHOUT_HEAD(pdopenpid_pdwait_only_one); +ATF_TC_BODY(pdopenpid_pdwait_only_one, tc) +{ + pid_t child; + int fd1, fd2, status; + + child = pdfork(&fd1, PD_DAEMON); + ATF_REQUIRE_MSG(child >= 0, "pdfork: %s", strerror(errno)); + if (child == 0) + _exit(42); + + fd2 = pdopenpid(child, 0); + ATF_REQUIRE_MSG(fd2 >= 0, "pdopenpid: %s", strerror(errno)); + + /* Collect via the first fd. */ + ATF_REQUIRE_MSG(pdwait(fd1, &status, WEXITED, NULL, NULL) == 0, + "pdwait(fd1): %s", strerror(errno)); + ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == 42); + + /* The second fd should no longer be able to collect. */ + ATF_REQUIRE_ERRNO(ESRCH, pdwait(fd2, &status, WEXITED, NULL, NULL) < 0); + + ATF_REQUIRE(close(fd1) == 0); + ATF_REQUIRE(close(fd2) == 0); +} + +/* + * Opening a process descriptor for ourselves should work. + */ +ATF_TC_WITHOUT_HEAD(pdopenpid_self); +ATF_TC_BODY(pdopenpid_self, tc) +{ + pid_t child, queried; + int childfd, fd, status; + + /* + * Closing self-referencing procdesc would steal the exit + * status from the parent. Keep one more procdesc for the + * child in the parent so that we can query the state. + * + * For the same reason we must use fork() and test in the + * child, otherwise kyua does not get the SIGCHILD nor the + * exit status. + */ + child = pdfork(&childfd, 0); + if (child == 0) { + fd = pdopenpid(getpid(), PD_DAEMON); + if (fd < 0) + _exit(21); + if (pdgetpid(fd, &queried) == -1) + _exit(22); + if (getpid() != queried) + _exit(23); + if (close(fd) != 0) + _exit(24); + _exit(0); + } + + ATF_REQUIRE(pdgetpid(childfd, &queried) == 0); + ATF_REQUIRE_EQ(queried, child); + ATF_REQUIRE(pdwait(childfd, &status, WEXITED, NULL, NULL) == 0); + + ATF_REQUIRE(WIFEXITED(status)); + ATF_REQUIRE_EQ(WEXITSTATUS(status), 0); + ATF_REQUIRE(close(childfd) == 0); +} + +/* + * pdopenpid for a process that is exiting (P_WEXIT set) should fail with EBUSY. + */ +ATF_TC_WITHOUT_HEAD(pdopenpid_exiting); +ATF_TC_BODY(pdopenpid_exiting, tc) +{ + pid_t child; + int fd, pip[2], status; + + ATF_REQUIRE_EQ(pipe(pip), 0); + + child = fork(); + ATF_REQUIRE_MSG(child >= 0, "fork: %s", strerror(errno)); + if (child == 0) { + char c; + + close(pip[1]); + (void)read(pip[0], &c, 1); + _exit(0); + } + ATF_REQUIRE(close(pip[0]) == 0); + + /* Tell the child to exit. */ + ATF_REQUIRE(close(pip[1]) == 0); + + /* Might still race. */ + usleep(1000); + fd = pdopenpid(child, 0); + if (fd >= 0) { + ATF_REQUIRE(close(fd) == 0); + } else { + ATF_REQUIRE_MSG(errno == EBUSY, + "unexpected errno %d (%s)", errno, strerror(errno)); + } + + ATF_REQUIRE(waitpid(child, &status, 0) == child); + ATF_REQUIRE(WIFEXITED(status)); + ATF_REQUIRE_EQ(WEXITSTATUS(status), 0); +} + +/* + * Make sure that opening a process descriptor doesn't cause a wakeup in the + * target process. + */ +ATF_TC_WITHOUT_HEAD(pdopenpid_no_wakeup); +ATF_TC_BODY(pdopenpid_no_wakeup, tc) +{ + pid_t child; + int fd, pip[2]; + + ATF_REQUIRE(pipe(pip) == 0); + + child = fork(); + ATF_REQUIRE_MSG(child >= 0, "fork: %s", strerror(errno)); + if (child == 0) { + char buf[1]; + + close(pip[1]); + (void)read(pip[0], buf, 1); + _exit(0); + } + close(pip[0]); + + wait_for_naptime(child, "piperd"); + + fd = pdopenpid(child, 0); + ATF_REQUIRE_MSG(fd >= 0, "pdopenpid: %s", strerror(errno)); + + /* + * If pdopenpid() caused a wakeup, read() returned and the child exited. + */ + wait_for_naptime(child, "piperd"); + + ATF_REQUIRE(close(pip[1]) == 0); + ATF_REQUIRE(close(fd) == 0); +} + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, pid_recycle); ATF_TP_ADD_TC(tp, poll_close_race); ATF_TP_ADD_TC(tp, poll_exit_wakeup); + ATF_TP_ADD_TC(tp, pdopenpid_basic); + ATF_TP_ADD_TC(tp, pdopenpid_cloexec); + ATF_TP_ADD_TC(tp, pdopenpid_einval); + ATF_TP_ADD_TC(tp, pdopenpid_emfile); + ATF_TP_ADD_TC(tp, pdopenpid_esrch); + ATF_TP_ADD_TC(tp, pdopenpid_capmode); + ATF_TP_ADD_TC(tp, pdopenpid_pdfork_then_open); + ATF_TP_ADD_TC(tp, pdopenpid_fork_then_open); + ATF_TP_ADD_TC(tp, pdopenpid_close_one_of_two); + ATF_TP_ADD_TC(tp, pdopenpid_open_twice); + ATF_TP_ADD_TC(tp, pdopenpid_pdwait_only_one); + ATF_TP_ADD_TC(tp, pdopenpid_self); + ATF_TP_ADD_TC(tp, pdopenpid_exiting); + ATF_TP_ADD_TC(tp, pdopenpid_no_wakeup); + return (atf_no_error()); }