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