[LTP] [PATCH v1] Refactor pidns20 test using new LTP API
Cyril Hrubis
chrubis@suse.cz
Wed Aug 10 11:39:03 CEST 2022
Hi!
> -static void child_signal_handler(int sig, siginfo_t * si, void *unused)
> +static void child_signal_handler(LTP_ATTRIBUTE_UNUSED int sig, siginfo_t *si, LTP_ATTRIBUTE_UNUSED void *unused)
> {
> if (si->si_signo != SIGUSR1)
> - tst_resm(TBROK, "cinit: received %s unexpectedly!",
> - strsignal(si->si_signo));
> - else
> - tst_resm(TPASS, "cinit: user function is called as expected");
> + tst_brk(TBROK, "Received %s unexpectedly!", tst_strsig(si->si_signo));
It's not safe to call tst_brk() from a signal handler.
The most safe way is to store the signo here and do the check in the
child func.
So here I would do:
signals++;
last_sig = si->si_signo;
And then in the main loop:
if (singals != 1) {
tst_res(TFAIL, "Received %i signals", signals);
return 0;
}
if (last_sig != SIGUSR1) {
...
}
...
> - /* Disable broken flag */
> - broken = 0;
> + passed++;
> }
>
> -/*
> - * child_fn() - Inside container
> - */
> -int child_fn(void *arg)
> +static int child_func(LTP_ATTRIBUTE_UNUSED void *arg)
> {
> - pid_t pid, ppid;
> - sigset_t newset;
> struct sigaction sa;
> - char buf[5];
> + sigset_t newset;
> + pid_t cpid, ppid;
>
> - /* Setup pipe read and write ends */
> - pid = getpid();
> + cpid = getpid();
> ppid = getppid();
>
> - if (pid != CHILD_PID || ppid != PARENT_PID) {
> - printf("cinit: pidns was not created properly\n");
> - exit(1);
> + if (cpid != 1 || ppid != 0) {
> + tst_res(TFAIL, "Got unexpected result of cpid=%d ppid=%d", cpid, ppid);
> + return 1;
No return 1 here, we already reported TFAIL and the non-zero return
value will cause TBROK in the test library when the process is waited
for.
> }
>
> - /* Setup pipes to communicate with parent */
> - close(cinit_parent[0]);
> - close(parent_cinit[1]);
> -
> - /* Block SIGUSR1 signal */
> - sigemptyset(&newset);
> - sigaddset(&newset, SIGUSR1);
> - if (sigprocmask(SIG_BLOCK, &newset, 0) == -1) {
> - perror("cinit: sigprocmask() failed");
> - exit(1);
> - }
> - tst_resm(TINFO, "cinit: blocked SIGUSR1");
> -
> - /* Let parent to queue SIGUSR1 in pending */
> - if (write(cinit_parent[1], "c:go", 5) != 5) {
> - perror("cinit: pipe is broken to write");
> - exit(1);
> - }
> + SAFE_SIGEMPTYSET(&newset);
> + SAFE_SIGADDSET(&newset, SIGUSR1);
> + SAFE_SIGPROCMASK(SIG_BLOCK, &newset, 0);
>
> - /* Check if parent has queued up SIGUSR1 */
> - read(parent_cinit[0], buf, 5);
> - if (strcmp(buf, "p:go") != 0) {
> - printf("cinit: parent did not respond!\n");
> - exit(1);
> - }
> + TST_CHECKPOINT_WAKE_AND_WAIT(0);
>
> - /* Now redefine handler for SIGUSR1 */
> sa.sa_flags = SA_SIGINFO;
> - sigfillset(&sa.sa_mask);
> + SAFE_SIGFILLSET(&sa.sa_mask);
> sa.sa_sigaction = child_signal_handler;
> - if (sigaction(SIGUSR1, &sa, NULL) == -1) {
> - perror("cinit: sigaction failed");
> - exit(1);
> - }
>
> - /* Unblock traffic on SIGUSR1 queue */
> - tst_resm(TINFO, "cinit: unblocking SIGUSR1");
> - sigprocmask(SIG_UNBLOCK, &newset, 0);
> + SAFE_SIGACTION(SIGUSR1, &sa, NULL);
>
> - /* Check if new handler is called */
> - if (broken == 1) {
> - printf("cinit: broken flag didn't change\n");
> - exit(1);
> + SAFE_SIGPROCMASK(SIG_UNBLOCK, &newset, 0);
> +
> + if (!passed){
^
Missing space
> + tst_res(TFAIL, "User function has not been called after unblocking signal");
> + return 1;
> }
>
> - /* Cleanup and exit */
> - close(cinit_parent[1]);
> - close(parent_cinit[0]);
> - exit(0);
> -}
> + tst_res(TPASS, "User function is called as expected after unblocking signal");
>
> -static void setup(void)
> -{
> - tst_require_root();
> - check_newpid();
> + return 0;
> }
>
> -int main(void)
> +static void run(void)
> {
> - int status;
> - char buf[5];
> - pid_t cpid;
> -
> - setup();
> -
> - /* Create pipes for intercommunication */
> - if (pipe(parent_cinit) == -1 || pipe(cinit_parent) == -1) {
> - tst_brkm(TBROK | TERRNO, NULL, "pipe failed");
> - }
> + int ret;
>
> - cpid = ltp_clone_quick(CLONE_NEWPID | SIGCHLD, child_fn, NULL);
> - if (cpid == -1) {
> - tst_brkm(TBROK | TERRNO, NULL, "clone failed");
> - }
> -
> - /* Setup pipe read and write ends */
> - close(cinit_parent[1]);
> - close(parent_cinit[0]);
> -
> - /* Is container ready */
> - read(cinit_parent[0], buf, 5);
> - if (strcmp(buf, "c:go") != 0) {
> - tst_brkm(TBROK, NULL, "parent: container did not respond!");
> - }
> + ret = ltp_clone_quick(CLONE_NEWPID | SIGCHLD, child_func, NULL);
> + if (ret < 0)
> + tst_brk(TBROK | TERRNO, "clone failed");
>
> - /* Enqueue SIGUSR1 in pending signal queue of container */
> - SAFE_KILL(NULL, cpid, SIGUSR1);
> + TST_CHECKPOINT_WAIT(0);
>
> - tst_resm(TINFO, "parent: signalled SIGUSR1 to container");
> - if (write(parent_cinit[1], "p:go", 5) != 5) {
> - tst_brkm(TBROK | TERRNO, NULL, "write failed");
> - }
> -
> - /* collect exit status of child */
> - SAFE_WAIT(NULL, &status);
> -
> - if (WIFSIGNALED(status)) {
> - if (WTERMSIG(status) == SIGUSR1)
> - tst_resm(TFAIL,
> - "user function was not called inside cinit");
> - else
> - tst_resm(TBROK,
> - "cinit was terminated by %d",
> - WTERMSIG(status));
> - }
> + SAFE_KILL(ret, SIGUSR1);
>
> - /* Cleanup and exit */
> - close(parent_cinit[1]);
> - close(cinit_parent[0]);
> - tst_exit();
> + TST_CHECKPOINT_WAKE(0);
> }
> +
> +static struct tst_test test = {
> + .test_all = run,
> + .needs_root = 1,
> + .needs_checkpoints = 1,
> +};
> --
> 2.35.3
>
>
> --
> Mailing list info: https://lists.linux.it/listinfo/ltp
--
Cyril Hrubis
chrubis@suse.cz
More information about the ltp
mailing list