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 55long TEST_RETURN; 56int 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 87static pthread_mutex_t tmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; 88 89static void check_env(void); 90static void tst_condense(int tnum, int ttype, const char *tmesg); 91static void tst_print(const char *tcid, int tnum, int ttype, const char *tmesg); 92 93static int T_exitval = 0; /* exit value used by tst_exit() */ 94static int T_mode = VERBOSE; /* flag indicating print mode: VERBOSE, */ 95 /* NOPASS, DISCARD */ 96 97static char Warn_mesg[MAXMESG]; /* holds warning messages */ 98 99/* 100 * These are used for condensing output when NOT in verbose mode. 101 */ 102static int Buffered = FALSE; /* TRUE if condensed output is currently */ 103 /* buffered (i.e. not yet printed) */ 104static char *Last_tcid; /* previous test case id */ 105static int Last_num; /* previous test case number */ 106static int Last_type; /* previous test result type */ 107static char *Last_mesg; /* previous test result message */ 108 109int tst_count = 0; 110 111/* 112 * These globals must be defined in the test. 113 */ 114extern char *TCID; /* Test case identifier from the test source */ 115extern int TST_TOTAL; /* Total number of test cases from the test */ 116 117 118struct 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 133const 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 150static 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 202static 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 237void 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 256static 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 355static 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 385void 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 396pid_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 411void 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 444pid_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 */ 456static int tst_brk_entered = 0; 457 458static 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 507void 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 520typedef void (*tst_res_func_t)(const char *file, const int lineno, 521 int ttype, const char *fmt, ...); 522 523void 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 562void 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 584void 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