1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) 2022 FUJITSU LIMITED. All rights reserved.
4f08c3bdfSopenharmony_ci * Author: Yang Xu <xuyang2018.jy@fujitsu.com>
5f08c3bdfSopenharmony_ci */
6f08c3bdfSopenharmony_ci
7f08c3bdfSopenharmony_ci/*\
8f08c3bdfSopenharmony_ci * [Description]
9f08c3bdfSopenharmony_ci *
10f08c3bdfSopenharmony_ci * Verify that the PIDFD_NONBLOCK flag works with pidfd_open() and
11f08c3bdfSopenharmony_ci * that waitid() with a non-blocking pidfd returns EAGAIN.
12f08c3bdfSopenharmony_ci */
13f08c3bdfSopenharmony_ci
14f08c3bdfSopenharmony_ci#include <unistd.h>
15f08c3bdfSopenharmony_ci#include <sys/wait.h>
16f08c3bdfSopenharmony_ci#include <stdlib.h>
17f08c3bdfSopenharmony_ci#include "tst_test.h"
18f08c3bdfSopenharmony_ci#include "lapi/pidfd.h"
19f08c3bdfSopenharmony_ci
20f08c3bdfSopenharmony_ci#ifndef P_PIDFD
21f08c3bdfSopenharmony_ci#define P_PIDFD  3
22f08c3bdfSopenharmony_ci#endif
23f08c3bdfSopenharmony_ci
24f08c3bdfSopenharmony_cistatic int pidfd = -1;
25f08c3bdfSopenharmony_ci
26f08c3bdfSopenharmony_cistatic void run(void)
27f08c3bdfSopenharmony_ci{
28f08c3bdfSopenharmony_ci	int flag, pid, ret;
29f08c3bdfSopenharmony_ci	siginfo_t info;
30f08c3bdfSopenharmony_ci
31f08c3bdfSopenharmony_ci	pid = SAFE_FORK();
32f08c3bdfSopenharmony_ci	if (!pid) {
33f08c3bdfSopenharmony_ci		TST_CHECKPOINT_WAIT(0);
34f08c3bdfSopenharmony_ci		exit(EXIT_SUCCESS);
35f08c3bdfSopenharmony_ci	}
36f08c3bdfSopenharmony_ci
37f08c3bdfSopenharmony_ci	TST_EXP_FD_SILENT(pidfd_open(pid, PIDFD_NONBLOCK),
38f08c3bdfSopenharmony_ci				"pidfd_open(%d,  PIDFD_NONBLOCK)", pid);
39f08c3bdfSopenharmony_ci
40f08c3bdfSopenharmony_ci	pidfd = TST_RET;
41f08c3bdfSopenharmony_ci	flag = SAFE_FCNTL(pidfd, F_GETFL);
42f08c3bdfSopenharmony_ci
43f08c3bdfSopenharmony_ci	if (!(flag & O_NONBLOCK))
44f08c3bdfSopenharmony_ci		tst_brk(TFAIL, "pidfd_open(%d, O_NONBLOCK) didn't set O_NONBLOCK flag", pid);
45f08c3bdfSopenharmony_ci
46f08c3bdfSopenharmony_ci	tst_res(TPASS, "pidfd_open(%d, O_NONBLOCK) sets O_NONBLOCK flag", pid);
47f08c3bdfSopenharmony_ci
48f08c3bdfSopenharmony_ci	TST_EXP_FAIL(waitid(P_PIDFD, pidfd, &info, WEXITED), EAGAIN,
49f08c3bdfSopenharmony_ci			"waitid(P_PIDFD,...,WEXITED)");
50f08c3bdfSopenharmony_ci
51f08c3bdfSopenharmony_ci	TST_CHECKPOINT_WAKE(0);
52f08c3bdfSopenharmony_ci
53f08c3bdfSopenharmony_ci	ret = TST_RETRY_FUNC(waitid(P_PIDFD, pidfd, &info, WEXITED), TST_RETVAL_EQ0);
54f08c3bdfSopenharmony_ci	if (ret == 0) {
55f08c3bdfSopenharmony_ci		tst_res(TPASS, "waitid(P_PIDFD) succeeded after child process terminated");
56f08c3bdfSopenharmony_ci	} else {
57f08c3bdfSopenharmony_ci		tst_res(TFAIL, "waitid(P_PIDFD) failed after child process terminated");
58f08c3bdfSopenharmony_ci		SAFE_WAIT(NULL);
59f08c3bdfSopenharmony_ci	}
60f08c3bdfSopenharmony_ci
61f08c3bdfSopenharmony_ci	SAFE_CLOSE(pidfd);
62f08c3bdfSopenharmony_ci}
63f08c3bdfSopenharmony_ci
64f08c3bdfSopenharmony_cistatic void setup(void)
65f08c3bdfSopenharmony_ci{
66f08c3bdfSopenharmony_ci	pidfd_open_supported();
67f08c3bdfSopenharmony_ci
68f08c3bdfSopenharmony_ci	TEST(pidfd_open(getpid(), PIDFD_NONBLOCK));
69f08c3bdfSopenharmony_ci	if (TST_RET == -1) {
70f08c3bdfSopenharmony_ci		if (TST_ERR == EINVAL) {
71f08c3bdfSopenharmony_ci			tst_brk(TCONF, "PIDFD_NONBLOCK was supported since linux 5.10");
72f08c3bdfSopenharmony_ci			return;
73f08c3bdfSopenharmony_ci		}
74f08c3bdfSopenharmony_ci		tst_brk(TFAIL | TTERRNO,
75f08c3bdfSopenharmony_ci			"pidfd_open(getpid(),PIDFD_NONBLOCK) failed unexpectedly");
76f08c3bdfSopenharmony_ci	}
77f08c3bdfSopenharmony_ci	SAFE_CLOSE(TST_RET);
78f08c3bdfSopenharmony_ci}
79f08c3bdfSopenharmony_ci
80f08c3bdfSopenharmony_cistatic void cleanup(void)
81f08c3bdfSopenharmony_ci{
82f08c3bdfSopenharmony_ci	if (pidfd > -1)
83f08c3bdfSopenharmony_ci		SAFE_CLOSE(pidfd);
84f08c3bdfSopenharmony_ci}
85f08c3bdfSopenharmony_ci
86f08c3bdfSopenharmony_cistatic struct tst_test test = {
87f08c3bdfSopenharmony_ci	.needs_root = 1,
88f08c3bdfSopenharmony_ci	.forks_child = 1,
89f08c3bdfSopenharmony_ci	.needs_checkpoints = 1,
90f08c3bdfSopenharmony_ci	.setup = setup,
91f08c3bdfSopenharmony_ci	.cleanup = cleanup,
92f08c3bdfSopenharmony_ci	.test_all = run,
93f08c3bdfSopenharmony_ci};
94