1 /*
2    lib - common code for testing lib/utilinux:my_system() function
3 
4    Copyright (C) 2013-2021
5    Free Software Foundation, Inc.
6 
7    Written by:
8    Slava Zanko <slavazanko@gmail.com>, 2013
9 
10    This file is part of the Midnight Commander.
11 
12    The Midnight Commander is free software: you can redistribute it
13    and/or modify it under the terms of the GNU General Public License as
14    published by the Free Software Foundation, either version 3 of the License,
15    or (at your option) any later version.
16 
17    The Midnight Commander is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21 
22    You should have received a copy of the GNU General Public License
23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24  */
25 
26 #include <signal.h>
27 #include <unistd.h>
28 
29 #include "lib/vfs/vfs.h"
30 
31 /* sighandler_t is GNU extension */
32 #ifndef HAVE_SIGHANDLER_T
33 typedef void (*sighandler_t) (int);
34 #endif
35 
36 /* --------------------------------------------------------------------------------------------- */
37 
38 /* @CapturedValue */
39 static sigset_t *sigemptyset_set__captured;
40 /* @ThenReturnValue */
41 static int sigemptyset__return_value = 0;
42 
43 /* @Mock */
44 int
sigemptyset(sigset_t * set)45 sigemptyset (sigset_t * set)
46 {
47     sigemptyset_set__captured = set;
48     return sigemptyset__return_value;
49 }
50 
51 /* --------------------------------------------------------------------------------------------- */
52 
53 /* @CapturedValue */
54 static GPtrArray *sigaction_signum__captured = NULL;
55 /* @CapturedValue */
56 static GPtrArray *sigaction_act__captured = NULL;
57 /* @CapturedValue */
58 static GPtrArray *sigaction_oldact__captured = NULL;
59 /* @ThenReturnValue */
60 static int sigaction__return_value = 0;
61 
62 /* @Mock */
63 int
sigaction(int signum,const struct sigaction * act,struct sigaction * oldact)64 sigaction (int signum, const struct sigaction *act, struct sigaction *oldact)
65 {
66     int *tmp_signum;
67     struct sigaction *tmp_act;
68 
69     /* store signum */
70     tmp_signum = g_new (int, 1);
71     memcpy (tmp_signum, &signum, sizeof (*tmp_signum));
72     if (sigaction_signum__captured != NULL)
73         g_ptr_array_add (sigaction_signum__captured, tmp_signum);
74 
75     /* store act */
76     if (act != NULL)
77     {
78         tmp_act = g_new (struct sigaction, 1);
79         memcpy (tmp_act, act, sizeof (*tmp_act));
80     }
81     else
82         tmp_act = NULL;
83     if (sigaction_act__captured != NULL)
84         g_ptr_array_add (sigaction_act__captured, tmp_act);
85 
86     /* store oldact */
87     if (oldact != NULL)
88     {
89         tmp_act = g_new (struct sigaction, 1);
90         memcpy (tmp_act, oldact, sizeof (*tmp_act));
91     }
92     else
93         tmp_act = NULL;
94     if (sigaction_oldact__captured != NULL)
95         g_ptr_array_add (sigaction_oldact__captured, tmp_act);
96 
97     return sigaction__return_value;
98 }
99 
100 static void
sigaction__init(void)101 sigaction__init (void)
102 {
103     sigaction_signum__captured = g_ptr_array_new ();
104     sigaction_act__captured = g_ptr_array_new ();
105     sigaction_oldact__captured = g_ptr_array_new ();
106 }
107 
108 static void
sigaction__deinit(void)109 sigaction__deinit (void)
110 {
111     g_ptr_array_foreach (sigaction_signum__captured, (GFunc) g_free, NULL);
112     g_ptr_array_free (sigaction_signum__captured, TRUE);
113     sigaction_signum__captured = NULL;
114 
115     g_ptr_array_foreach (sigaction_act__captured, (GFunc) g_free, NULL);
116     g_ptr_array_free (sigaction_act__captured, TRUE);
117     sigaction_act__captured = NULL;
118 
119     g_ptr_array_foreach (sigaction_oldact__captured, (GFunc) g_free, NULL);
120     g_ptr_array_free (sigaction_oldact__captured, TRUE);
121     sigaction_oldact__captured = NULL;
122 }
123 
124 /* --------------------------------------------------------------------------------------------- */
125 
126 /* @CapturedValue */
127 static GPtrArray *signal_signum__captured;
128 /* @CapturedValue */
129 static GPtrArray *signal_handler__captured;
130 /* @ThenReturnValue */
131 static sighandler_t signal__return_value = NULL;
132 
133 /* @Mock */
134 sighandler_t
signal(int signum,sighandler_t handler)135 signal (int signum, sighandler_t handler)
136 {
137     int *tmp_signum;
138     sighandler_t *tmp_handler;
139 
140     /* store signum */
141     tmp_signum = g_new (int, 1);
142     memcpy (tmp_signum, &signum, sizeof (*tmp_signum));
143     g_ptr_array_add (signal_signum__captured, tmp_signum);
144 
145     /* store handler */
146     if (handler != SIG_DFL)
147     {
148         tmp_handler = g_new (sighandler_t, 1);
149         memcpy (tmp_handler, handler, sizeof (*tmp_handler));
150     }
151     else
152         tmp_handler = (void *) SIG_DFL;
153     g_ptr_array_add (signal_handler__captured, tmp_handler);
154 
155     return signal__return_value;
156 }
157 
158 static void
signal__init(void)159 signal__init (void)
160 {
161     signal_signum__captured = g_ptr_array_new ();
162     signal_handler__captured = g_ptr_array_new ();
163 }
164 
165 static void
signal__deinit(void)166 signal__deinit (void)
167 {
168     g_ptr_array_foreach (signal_signum__captured, (GFunc) g_free, NULL);
169     g_ptr_array_free (signal_signum__captured, TRUE);
170     signal_signum__captured = NULL;
171 
172     g_ptr_array_foreach (signal_handler__captured, (GFunc) g_free, NULL);
173     g_ptr_array_free (signal_handler__captured, TRUE);
174     signal_handler__captured = NULL;
175 }
176 
177 /* --------------------------------------------------------------------------------------------- */
178 
179 /* @ThenReturnValue */
180 static pid_t fork__return_value;
181 
182 /* @Mock */
183 pid_t
fork(void)184 fork (void)
185 {
186     return fork__return_value;
187 }
188 
189 /* --------------------------------------------------------------------------------------------- */
190 /* @CapturedValue */
191 static int my_exit__status__captured;
192 
193 /* @Mock */
194 void
my_exit(int status)195 my_exit (int status)
196 {
197     my_exit__status__captured = status;
198 }
199 
200 /* --------------------------------------------------------------------------------------------- */
201 
202 /* @CapturedValue */
203 static char *execvp__file__captured = NULL;
204 /* @CapturedValue */
205 static GPtrArray *execvp__args__captured;
206 /* @ThenReturnValue */
207 static int execvp__return_value = 0;
208 
209 /* @Mock */
210 int
execvp(const char * file,char * const argv[])211 execvp (const char *file, char *const argv[])
212 {
213     char **one_arg;
214     execvp__file__captured = g_strdup (file);
215 
216     for (one_arg = (char **) argv; *one_arg != NULL; one_arg++)
217         g_ptr_array_add (execvp__args__captured, g_strdup (*one_arg));
218 
219     return execvp__return_value;
220 }
221 
222 static void
execvp__init(void)223 execvp__init (void)
224 {
225     execvp__args__captured = g_ptr_array_new ();
226 }
227 
228 static void
execvp__deinit(void)229 execvp__deinit (void)
230 {
231     g_ptr_array_foreach (execvp__args__captured, (GFunc) g_free, NULL);
232     g_ptr_array_free (execvp__args__captured, TRUE);
233     execvp__args__captured = NULL;
234     MC_PTR_FREE (execvp__file__captured);
235 }
236 
237 /* --------------------------------------------------------------------------------------------- */
238 
239 #define VERIFY_SIGACTION__ACT_IGNORED(_pntr) { \
240     struct sigaction *_act = (struct sigaction *) _pntr; \
241     mctest_assert_ptr_eq (_act->sa_handler, SIG_IGN); \
242     mctest_assert_int_eq (_act->sa_flags, 0); \
243 }
244 
245 #define VERIFY_SIGACTION__IS_RESTORED(oldact_idx, act_idx) { \
246     struct sigaction *_oldact = (struct sigaction *) g_ptr_array_index(sigaction_oldact__captured, oldact_idx); \
247     struct sigaction *_act = (struct sigaction *) g_ptr_array_index(sigaction_act__captured, act_idx); \
248     ck_assert_msg (memcmp(_oldact, _act, sizeof(struct sigaction)) == 0, \
249         "sigaction(): oldact[%d] should be equals to act[%d]", oldact_idx, act_idx); \
250 }
251 
252 /* @Verify */
253 #define VERIFY_SIGACTION_CALLS() { \
254     mctest_assert_int_eq (sigaction_signum__captured->len, 6); \
255 \
256     mctest_assert_int_eq (*((int *) g_ptr_array_index(sigaction_signum__captured, 0)), SIGINT); \
257     mctest_assert_int_eq (*((int *) g_ptr_array_index(sigaction_signum__captured, 1)), SIGQUIT); \
258     mctest_assert_int_eq (*((int *) g_ptr_array_index(sigaction_signum__captured, 2)), SIGTSTP); \
259     mctest_assert_int_eq (*((int *) g_ptr_array_index(sigaction_signum__captured, 3)), SIGINT); \
260     mctest_assert_int_eq (*((int *) g_ptr_array_index(sigaction_signum__captured, 4)), SIGQUIT); \
261     mctest_assert_int_eq (*((int *) g_ptr_array_index(sigaction_signum__captured, 5)), SIGTSTP); \
262 \
263     VERIFY_SIGACTION__ACT_IGNORED(g_ptr_array_index(sigaction_act__captured, 0)); \
264     VERIFY_SIGACTION__ACT_IGNORED(g_ptr_array_index(sigaction_act__captured, 1)); \
265     { \
266         struct sigaction *_act  = g_ptr_array_index(sigaction_act__captured, 2); \
267         ck_assert_msg (memcmp (_act, &startup_handler, sizeof(struct sigaction)) == 0, \
268             "The 'act' in third call to sigaction() should be equals to startup_handler"); \
269     } \
270 \
271     VERIFY_SIGACTION__IS_RESTORED (0, 3); \
272     VERIFY_SIGACTION__IS_RESTORED (1, 4); \
273     VERIFY_SIGACTION__IS_RESTORED (2, 5); \
274 \
275     ck_assert_msg (g_ptr_array_index(sigaction_oldact__captured, 3) == NULL, \
276         "oldact in fourth call to sigaction() should be NULL"); \
277     ck_assert_msg (g_ptr_array_index(sigaction_oldact__captured, 4) == NULL, \
278         "oldact in fifth call to sigaction() should be NULL"); \
279     ck_assert_msg (g_ptr_array_index(sigaction_oldact__captured, 5) == NULL, \
280         "oldact in sixth call to sigaction() should be NULL"); \
281 }
282 
283 /* --------------------------------------------------------------------------------------------- */
284 
285 #define VERIFY_SIGNAL_HANDLER_IS_SIG_DFL(_idx) { \
286     sighandler_t *tmp_handler = (sighandler_t *) g_ptr_array_index(signal_handler__captured, _idx);\
287     mctest_assert_ptr_eq (tmp_handler, (sighandler_t *) SIG_DFL); \
288 }
289 
290 /* @Verify */
291 #define VERIFY_SIGNAL_CALLS() { \
292     mctest_assert_int_eq (signal_signum__captured->len, 4); \
293     mctest_assert_int_eq (*((int *) g_ptr_array_index(signal_signum__captured, 0)), SIGINT); \
294     mctest_assert_int_eq (*((int *) g_ptr_array_index(signal_signum__captured, 1)), SIGQUIT); \
295     mctest_assert_int_eq (*((int *) g_ptr_array_index(signal_signum__captured, 2)), SIGTSTP); \
296     mctest_assert_int_eq (*((int *) g_ptr_array_index(signal_signum__captured, 3)), SIGCHLD); \
297     \
298     VERIFY_SIGNAL_HANDLER_IS_SIG_DFL (0); \
299     VERIFY_SIGNAL_HANDLER_IS_SIG_DFL (1); \
300     VERIFY_SIGNAL_HANDLER_IS_SIG_DFL (2); \
301     VERIFY_SIGNAL_HANDLER_IS_SIG_DFL (3); \
302 }
303 
304 /* --------------------------------------------------------------------------------------------- */
305 
306 /* @Before */
307 static void
setup(void)308 setup (void)
309 {
310     signal__return_value = NULL;
311 
312     sigaction__init ();
313     signal__init ();
314     execvp__init ();
315 }
316 
317 /* --------------------------------------------------------------------------------------------- */
318 
319 /* @After */
320 static void
teardown(void)321 teardown (void)
322 {
323     execvp__deinit ();
324     signal__deinit ();
325     sigaction__deinit ();
326 }
327 
328 /* --------------------------------------------------------------------------------------------- */
329