1 /*
2 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
3 * AUTHOR : Kent Rogers (from Dave Fenner's original)
4 * CO-PILOT : Rich Logan
5 * DATE STARTED : 05/01/90 (rewritten 1/96)
6 * Copyright (c) 2009-2016 Cyril Hrubis <chrubis@suse.cz>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of version 2 of the GNU General Public License as
10 * published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it would be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 *
16 * Further, this software is distributed without any warranty that it is
17 * free of the rightful claim of any third person regarding infringement
18 * or the like. Any license provided herein, whether implied or
19 * otherwise, applies only to this software file. Patent licenses, if
20 * any, provided herein do not apply to combinations of this program with
21 * other software, or any other product whatsoever.
22 *
23 * You should have received a copy of the GNU General Public License along
24 * with this program; if not, write the Free Software Foundation, Inc.,
25 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 *
27 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
28 * Mountain View, CA 94043, or:
29 *
30 * http://www.sgi.com
31 *
32 * For further information regarding this notice, see:
33 *
34 * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
35 */
36
37 #define _GNU_SOURCE
38
39 #include <pthread.h>
40 #include <assert.h>
41 #include <errno.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <stdarg.h>
45 #include <string.h>
46 #include <unistd.h>
47 #include <sys/types.h>
48 #include <sys/wait.h>
49
50 #include "test.h"
51 #include "usctest.h"
52 #include "ltp_priv.h"
53 #include "tst_ansi_color.h"
54
55 long TEST_RETURN;
56 int TEST_ERRNO;
57
58 #define VERBOSE 1
59 #define NOPASS 3
60 #define DISCARD 4
61
62 #define MAXMESG 80 /* max length of internal messages */
63 #define USERMESG 2048 /* max length of user message */
64 #define TRUE 1
65 #define FALSE 0
66
67 /*
68 * EXPAND_VAR_ARGS - Expand the variable portion (arg_fmt) of a result
69 * message into the specified string.
70 *
71 * NOTE (garrcoop): arg_fmt _must_ be the last element in each function
72 * argument list that employs this.
73 */
74 #define EXPAND_VAR_ARGS(buf, arg_fmt, buf_len) do {\
75 va_list ap; \
76 assert(arg_fmt != NULL); \
77 va_start(ap, arg_fmt); \
78 vsnprintf(buf, buf_len, arg_fmt, ap); \
79 va_end(ap); \
80 assert(strlen(buf) > 0); \
81 } while (0)
82
83 #if defined(__ANDROID__) && !defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
84 #define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
85 #endif
86
87 static pthread_mutex_t tmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
88
89 static void check_env(void);
90 static void tst_condense(int tnum, int ttype, const char *tmesg);
91 static void tst_print(const char *tcid, int tnum, int ttype, const char *tmesg);
92
93 static int T_exitval = 0; /* exit value used by tst_exit() */
94 static int T_mode = VERBOSE; /* flag indicating print mode: VERBOSE, */
95 /* NOPASS, DISCARD */
96
97 static char Warn_mesg[MAXMESG]; /* holds warning messages */
98
99 /*
100 * These are used for condensing output when NOT in verbose mode.
101 */
102 static int Buffered = FALSE; /* TRUE if condensed output is currently */
103 /* buffered (i.e. not yet printed) */
104 static char *Last_tcid; /* previous test case id */
105 static int Last_num; /* previous test case number */
106 static int Last_type; /* previous test result type */
107 static char *Last_mesg; /* previous test result message */
108
109 int tst_count = 0;
110
111 /*
112 * These globals must be defined in the test.
113 */
114 extern char *TCID; /* Test case identifier from the test source */
115 extern int TST_TOTAL; /* Total number of test cases from the test */
116
117
118 struct pair {
119 const char *name;
120 int val;
121 };
122
123 #define PAIR(def) [def] = {.name = #def, .val = def},
124 #define STRPAIR(key, value) [key] = {.name = value, .val = key},
125
126 #define PAIR_LOOKUP(pair_arr, idx) do { \
127 if (idx < 0 || (size_t)idx >= ARRAY_SIZE(pair_arr) || \
128 pair_arr[idx].name == NULL) \
129 return "???"; \
130 return pair_arr[idx].name; \
131 } while (0)
132
strttype(int ttype)133 const char *strttype(int ttype)
134 {
135 static const struct pair ttype_pairs[] = {
136 PAIR(TPASS)
137 PAIR(TFAIL)
138 PAIR(TBROK)
139 PAIR(TCONF)
140 PAIR(TWARN)
141 PAIR(TINFO)
142 };
143
144 PAIR_LOOKUP(ttype_pairs, TTYPE_RESULT(ttype));
145 }
146
147 #include "errnos.h"
148 #include "signame.h"
149
tst_res__(const char * file,const int lineno,int ttype,const char * arg_fmt,...)150 static void tst_res__(const char *file, const int lineno, int ttype,
151 const char *arg_fmt, ...)
152 {
153 pthread_mutex_lock(&tmutex);
154
155 char tmesg[USERMESG];
156 int len = 0;
157 int ttype_result = TTYPE_RESULT(ttype);
158
159 if (file && (ttype_result != TPASS && ttype_result != TINFO))
160 len = sprintf(tmesg, "%s:%d: ", file, lineno);
161 EXPAND_VAR_ARGS(tmesg + len, arg_fmt, USERMESG - len);
162
163 /*
164 * Save the test result type by ORing ttype into the current exit
165 * value (used by tst_exit()).
166 */
167 T_exitval |= ttype_result;
168
169 check_env();
170
171 /*
172 * Set the test case number and print the results, depending on the
173 * display type.
174 */
175 if (ttype_result == TWARN || ttype_result == TINFO) {
176 tst_print(TCID, 0, ttype, tmesg);
177 } else {
178 if (tst_count < 0)
179 tst_print(TCID, 0, TWARN,
180 "tst_res(): tst_count < 0 is not valid");
181
182 /*
183 * Process each display type.
184 */
185 switch (T_mode) {
186 case DISCARD:
187 break;
188 case NOPASS: /* filtered by tst_print() */
189 tst_condense(tst_count + 1, ttype, tmesg);
190 break;
191 default: /* VERBOSE */
192 tst_print(TCID, tst_count + 1, ttype, tmesg);
193 break;
194 }
195
196 tst_count++;
197 }
198
199 pthread_mutex_unlock(&tmutex);
200 }
201
tst_condense(int tnum,int ttype,const char * tmesg)202 static void tst_condense(int tnum, int ttype, const char *tmesg)
203 {
204 int ttype_result = TTYPE_RESULT(ttype);
205
206 /*
207 * If this result is the same as the previous result, return.
208 */
209 if (Buffered == TRUE) {
210 if (strcmp(Last_tcid, TCID) == 0 && Last_type == ttype_result &&
211 strcmp(Last_mesg, tmesg) == 0)
212 return;
213
214 /*
215 * This result is different from the previous result. First,
216 * print the previous result.
217 */
218 tst_print(Last_tcid, Last_num, Last_type, Last_mesg);
219 free(Last_tcid);
220 free(Last_mesg);
221 }
222
223 /*
224 * If a file was specified, print the current result since we have no
225 * way of retaining the file contents for comparing with future
226 * results. Otherwise, buffer the current result info for next time.
227 */
228 Last_tcid = malloc(strlen(TCID) + 1);
229 strcpy(Last_tcid, TCID);
230 Last_num = tnum;
231 Last_type = ttype_result;
232 Last_mesg = malloc(strlen(tmesg) + 1);
233 strcpy(Last_mesg, tmesg);
234 Buffered = TRUE;
235 }
236
tst_flush(void)237 void tst_flush(void)
238 {
239 NO_NEWLIB_ASSERT("Unknown", 0);
240
241 pthread_mutex_lock(&tmutex);
242
243 /*
244 * Print out last line if in NOPASS mode.
245 */
246 if (Buffered == TRUE && T_mode == NOPASS) {
247 tst_print(Last_tcid, Last_num, Last_type, Last_mesg);
248 Buffered = FALSE;
249 }
250
251 fflush(stdout);
252
253 pthread_mutex_unlock(&tmutex);
254 }
255
tst_print(const char * tcid,int tnum,int ttype,const char * tmesg)256 static void tst_print(const char *tcid, int tnum, int ttype, const char *tmesg)
257 {
258 int err = errno;
259 const char *type;
260 int ttype_result = TTYPE_RESULT(ttype);
261 char message[USERMESG];
262 size_t size = 0;
263
264 /*
265 * Save the test result type by ORing ttype into the current exit value
266 * (used by tst_exit()). This is already done in tst_res(), but is
267 * also done here to catch internal warnings. For internal warnings,
268 * tst_print() is called directly with a case of TWARN.
269 */
270 T_exitval |= ttype_result;
271
272 /*
273 * If output mode is DISCARD, or if the output mode is NOPASS and this
274 * result is not one of FAIL, BROK, or WARN, just return. This check
275 * is necessary even though we check for DISCARD mode inside of
276 * tst_res(), since occasionally we get to this point without going
277 * through tst_res() (e.g. internal TWARN messages).
278 */
279 if (T_mode == DISCARD || (T_mode == NOPASS && ttype_result != TFAIL &&
280 ttype_result != TBROK
281 && ttype_result != TWARN))
282 return;
283
284 /*
285 * Build the result line and print it.
286 */
287 type = strttype(ttype);
288
289 if (T_mode == VERBOSE) {
290 size += snprintf(message + size, sizeof(message) - size,
291 "%-8s %4d ", tcid, tnum);
292 } else {
293 size += snprintf(message + size, sizeof(message) - size,
294 "%-8s %4d ", tcid, tnum);
295 }
296
297 if (size >= sizeof(message)) {
298 printf("%s: %i: line too long\n", __func__, __LINE__);
299 abort();
300 }
301
302 if (tst_color_enabled(STDOUT_FILENO))
303 size += snprintf(message + size, sizeof(message) - size,
304 "%s%s%s : %s", tst_ttype2color(ttype), type, ANSI_COLOR_RESET, tmesg);
305 else
306 size += snprintf(message + size, sizeof(message) - size,
307 "%s : %s", type, tmesg);
308
309 if (size >= sizeof(message)) {
310 printf("%s: %i: line too long\n", __func__, __LINE__);
311 abort();
312 }
313
314 if (ttype & TERRNO) {
315 size += snprintf(message + size, sizeof(message) - size,
316 ": errno=%s(%i): %s", tst_strerrno(err),
317 err, strerror(err));
318 }
319
320 if (size >= sizeof(message)) {
321 printf("%s: %i: line too long\n", __func__, __LINE__);
322 abort();
323 }
324
325 if (ttype & TTERRNO) {
326 size += snprintf(message + size, sizeof(message) - size,
327 ": TEST_ERRNO=%s(%i): %s",
328 tst_strerrno(TEST_ERRNO), (int)TEST_ERRNO,
329 strerror(TEST_ERRNO));
330 }
331
332 if (size >= sizeof(message)) {
333 printf("%s: %i: line too long\n", __func__, __LINE__);
334 abort();
335 }
336
337 if (ttype & TRERRNO) {
338 size += snprintf(message + size, sizeof(message) - size,
339 ": TEST_RETURN=%s(%i): %s",
340 tst_strerrno(TEST_RETURN), (int)TEST_RETURN,
341 strerror(TEST_RETURN));
342 }
343
344 if (size + 1 >= sizeof(message)) {
345 printf("%s: %i: line too long\n", __func__, __LINE__);
346 abort();
347 }
348
349 message[size] = '\n';
350 message[size + 1] = '\0';
351
352 fputs(message, stdout);
353 }
354
check_env(void)355 static void check_env(void)
356 {
357 static int first_time = 1;
358 char *value;
359
360 if (!first_time)
361 return;
362
363 first_time = 0;
364
365 /* BTOUTPUT not defined, use default */
366 if ((value = getenv(TOUTPUT)) == NULL) {
367 T_mode = VERBOSE;
368 return;
369 }
370
371 if (strcmp(value, TOUT_NOPASS_S) == 0) {
372 T_mode = NOPASS;
373 return;
374 }
375
376 if (strcmp(value, TOUT_DISCARD_S) == 0) {
377 T_mode = DISCARD;
378 return;
379 }
380
381 T_mode = VERBOSE;
382 return;
383 }
384
tst_exit(void)385 void tst_exit(void)
386 {
387 NO_NEWLIB_ASSERT("Unknown", 0);
388
389 pthread_mutex_lock(&tmutex);
390
391 tst_flush();
392
393 exit(T_exitval & ~TINFO);
394 }
395
tst_fork(void)396 pid_t tst_fork(void)
397 {
398 pid_t child;
399
400 NO_NEWLIB_ASSERT("Unknown", 0);
401
402 tst_flush();
403
404 child = fork();
405 if (child == 0)
406 T_exitval = 0;
407
408 return child;
409 }
410
tst_record_childstatus(void (* cleanup)(void),pid_t child)411 void tst_record_childstatus(void (*cleanup)(void), pid_t child)
412 {
413 int status, ttype_result;
414
415 NO_NEWLIB_ASSERT("Unknown", 0);
416
417 if (waitpid(child, &status, 0) < 0)
418 tst_brkm(TBROK | TERRNO, cleanup, "waitpid(%d) failed", child);
419
420 if (WIFEXITED(status)) {
421 ttype_result = WEXITSTATUS(status);
422 ttype_result = TTYPE_RESULT(ttype_result);
423 T_exitval |= ttype_result;
424
425 if (ttype_result == TPASS)
426 tst_resm(TINFO, "Child process returned TPASS");
427
428 if (ttype_result & TFAIL)
429 tst_resm(TINFO, "Child process returned TFAIL");
430
431 if (ttype_result & TBROK)
432 tst_resm(TINFO, "Child process returned TBROK");
433
434 if (ttype_result & TCONF)
435 tst_resm(TINFO, "Child process returned TCONF");
436
437 } else {
438 tst_brkm(TBROK, cleanup, "child process(%d) killed by "
439 "unexpected signal %s(%d)", child,
440 tst_strsig(WTERMSIG(status)), WTERMSIG(status));
441 }
442 }
443
tst_vfork(void)444 pid_t tst_vfork(void)
445 {
446 NO_NEWLIB_ASSERT("Unknown", 0);
447
448 tst_flush();
449 return vfork();
450 }
451
452 /*
453 * Make tst_brk reentrant so that one can call the SAFE_* macros from within
454 * user-defined cleanup functions.
455 */
456 static int tst_brk_entered = 0;
457
tst_brk__(const char * file,const int lineno,int ttype,void (* func)(void),const char * arg_fmt,...)458 static void tst_brk__(const char *file, const int lineno, int ttype,
459 void (*func)(void), const char *arg_fmt, ...)
460 {
461 pthread_mutex_lock(&tmutex);
462
463 char tmesg[USERMESG];
464 int ttype_result = TTYPE_RESULT(ttype);
465
466 EXPAND_VAR_ARGS(tmesg, arg_fmt, USERMESG);
467
468 /*
469 * Only FAIL, BROK, CONF, and RETR are supported by tst_brk().
470 */
471 if (ttype_result != TFAIL && ttype_result != TBROK &&
472 ttype_result != TCONF) {
473 sprintf(Warn_mesg, "%s: Invalid Type: %d. Using TBROK",
474 __func__, ttype_result);
475 tst_print(TCID, 0, TWARN, Warn_mesg);
476 /* Keep TERRNO, TTERRNO, etc. */
477 ttype = (ttype & ~ttype_result) | TBROK;
478 }
479
480 tst_res__(file, lineno, ttype, "%s", tmesg);
481 if (tst_brk_entered == 0) {
482 if (ttype_result == TCONF) {
483 tst_res__(file, lineno, ttype,
484 "Remaining cases not appropriate for "
485 "configuration");
486 } else if (ttype_result == TBROK) {
487 tst_res__(file, lineno, TBROK,
488 "Remaining cases broken");
489 }
490 }
491
492 /*
493 * If no cleanup function was specified, just return to the caller.
494 * Otherwise call the specified function.
495 */
496 if (func != NULL) {
497 tst_brk_entered++;
498 (*func) ();
499 tst_brk_entered--;
500 }
501 if (tst_brk_entered == 0)
502 tst_exit();
503
504 pthread_mutex_unlock(&tmutex);
505 }
506
tst_resm_(const char * file,const int lineno,int ttype,const char * arg_fmt,...)507 void tst_resm_(const char *file, const int lineno, int ttype,
508 const char *arg_fmt, ...)
509 {
510 char tmesg[USERMESG];
511
512 EXPAND_VAR_ARGS(tmesg, arg_fmt, USERMESG);
513
514 if (tst_test)
515 tst_res_(file, lineno, ttype, "%s", tmesg);
516 else
517 tst_res__(file, lineno, ttype, "%s", tmesg);
518 }
519
520 typedef void (*tst_res_func_t)(const char *file, const int lineno,
521 int ttype, const char *fmt, ...);
522
tst_resm_hexd_(const char * file,const int lineno,int ttype,const void * buf,size_t size,const char * arg_fmt,...)523 void tst_resm_hexd_(const char *file, const int lineno, int ttype,
524 const void *buf, size_t size, const char *arg_fmt, ...)
525 {
526 char tmesg[USERMESG];
527 static const size_t symb_num = 2; /* xx */
528 static const size_t size_max = 16;
529 size_t offset;
530 size_t i;
531 char *pmesg = tmesg;
532 tst_res_func_t res_func;
533
534 if (tst_test)
535 res_func = tst_res_;
536 else
537 res_func = tst_res__;
538
539 EXPAND_VAR_ARGS(tmesg, arg_fmt, USERMESG);
540 offset = strlen(tmesg);
541
542 if (size > size_max || size == 0 ||
543 (offset + size * (symb_num + 1)) >= USERMESG)
544 res_func(file, lineno, ttype, "%s", tmesg);
545 else
546 pmesg += offset;
547
548 for (i = 0; i < size; ++i) {
549 /* add space before byte except first one */
550 if (pmesg != tmesg)
551 *(pmesg++) = ' ';
552
553 sprintf(pmesg, "%02x", ((unsigned char *)buf)[i]);
554 pmesg += symb_num;
555 if ((i + 1) % size_max == 0 || i + 1 == size) {
556 res_func(file, lineno, ttype, "%s", tmesg);
557 pmesg = tmesg;
558 }
559 }
560 }
561
tst_brkm_(const char * file,const int lineno,int ttype,void (* func)(void),const char * arg_fmt,...)562 void tst_brkm_(const char *file, const int lineno, int ttype,
563 void (*func)(void), const char *arg_fmt, ...)
564 {
565 char tmesg[USERMESG];
566
567 EXPAND_VAR_ARGS(tmesg, arg_fmt, USERMESG);
568
569 if (tst_test) {
570 if (func) {
571 tst_brk_(file, lineno, TBROK,
572 "Non-NULL cleanup in newlib!");
573 }
574
575 tst_brk_(file, lineno, ttype, "%s", tmesg);
576 } else {
577 tst_brk__(file, lineno, ttype, func, "%s", tmesg);
578 }
579
580 /* Shouldn't be reached, but fixes build time warnings about noreturn. */
581 abort();
582 }
583
tst_require_root(void)584 void tst_require_root(void)
585 {
586 NO_NEWLIB_ASSERT("Unknown", 0);
587
588 if (geteuid() != 0)
589 tst_brkm(TCONF, NULL, "Test needs to be run as root");
590 }
591