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