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