1 /*
2  * Copyright (c) International Business Machines  Corp., 2001
3  * Copyright (c) 2012 Cyril Hrubis <chrubis@suse.cz>
4  *
5  * This program is free software;  you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY;  without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13  * the GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program;  if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 /*
21  * Verify that, pause() returns -1 and sets errno to EINTR after receipt of a
22  * signal which is caught by the calling process. Also, verify that the calling
23  * process will resume execution from the point of suspension.
24  */
25 
26 #include <unistd.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <sys/wait.h>
30 
31 #include "test.h"
32 
33 char *TCID = "pause02";
34 int TST_TOTAL = 1;
35 static pid_t cpid;
36 
37 static void do_child(void);
38 static void setup(void);
39 static void cleanup(void);
40 
41 int main(int ac, char **av)
42 {
43 	int lc;
44 	int status;
45 
46 	tst_parse_opts(ac, av, NULL, NULL);
47 
48 #ifdef UCLINUX
49 	maybe_run_child(&do_child, "");
50 #endif
51 
52 	setup();
53 
54 	for (lc = 0; TEST_LOOPING(lc); lc++) {
55 		tst_count = 0;
56 
57 		cpid = FORK_OR_VFORK();
58 		switch (cpid) {
59 		case -1:
60 			tst_brkm(TBROK, cleanup, "fork() failed");
61 		break;
62 		case 0:
63 #ifdef UCLINUX
64 			if (self_exec(av[0], "") < 0)
65 				tst_brkm(TBROK, cleanup, "self_exec failed");
66 #else
67 			do_child();
68 #endif
69 		break;
70 		default:
71 		break;
72 		}
73 
74 		/*
75 		 * Wait for child to enter pause().
76 		 */
77 		TST_PROCESS_STATE_WAIT(cleanup, cpid, 'S');
78 
79 		/*
80 		 * Send the SIGINT signal now, so that child
81 		 * returns from pause and resumes execution.
82 		 */
83 		kill(cpid, SIGINT);
84 
85 		wait(&status);
86 
87 		if (WIFEXITED(status)) {
88 			if (WEXITSTATUS(status) == 0)
89 				tst_resm(TPASS, "pause was interrupted correctly");
90 			else
91 				tst_resm(TFAIL, "pause was interrupted but the "
92 				                "retval and/or errno was wrong");
93 			continue;
94 		}
95 
96 		if (WIFSIGNALED(status)) {
97 			switch (WTERMSIG(status)) {
98 			case SIGALRM:
99 				tst_resm(TFAIL, "Timeout: SIGINT wasn't recieved by child");
100 			break;
101 			default:
102 				tst_resm(TFAIL, "Child killed by signal");
103 			}
104 
105 			continue;
106 		}
107 
108 		tst_resm(TFAIL, "Pause was not interrupted");
109 	}
110 
111 	cleanup();
112 	tst_exit();
113 }
114 
115 static void sig_handle(int sig)
116 {
117 }
118 
119 static void do_child(void)
120 {
121 	/* avoid LTP framework to do whatever it likes */
122 	signal(SIGALRM, SIG_DFL);
123 
124 	if (signal(SIGINT, sig_handle) == SIG_ERR) {
125 		fprintf(stderr, "Child: Failed to setup signal handler\n");
126 		exit(1);
127 	}
128 
129 	/* Commit suicide after 10 seconds */
130 	alarm(10);
131 
132 	TEST(pause());
133 
134 	if (TEST_RETURN == -1) {
135 		if (TEST_ERRNO == EINTR)
136 			exit(0);
137 
138 		fprintf(stderr, "Child: Pause returned -1 but errno is %d (%s)\n",
139 		        TEST_ERRNO, strerror(TEST_ERRNO));
140 		exit(1);
141 	}
142 
143 	fprintf(stderr, "Child: Pause returned %ld\n", TEST_RETURN);
144 	exit(1);
145 }
146 
147 static void setup(void)
148 {
149 	tst_sig(FORK, DEF_HANDLER, cleanup);
150 
151 	TEST_PAUSE;
152 }
153 
154 static void cleanup(void)
155 {
156 }
157