blob: 8a70ddf1c4efe2b009de4cc0cc0f09a2035b42e2 [file] [log] [blame]
alaffincc2e5552000-07-27 17:13:18 +00001/*
2 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
subrata_modak3311a252009-10-13 13:59:29 +00003 * Copyright (c) 2009 Cyril Hrubis chrubis@suse.cz
subrata_modak88c166c2009-06-09 16:01:20 +00004 *
alaffincc2e5552000-07-27 17:13:18 +00005 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
vapier45a8ba02009-07-20 10:59:32 +00008 *
alaffincc2e5552000-07-27 17:13:18 +00009 * This program is distributed in the hope that it would be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
vapier45a8ba02009-07-20 10:59:32 +000012 *
alaffincc2e5552000-07-27 17:13:18 +000013 * Further, this software is distributed without any warranty that it is
14 * free of the rightful claim of any third person regarding infringement
15 * or the like. Any license provided herein, whether implied or
16 * otherwise, applies only to this software file. Patent licenses, if
17 * any, provided herein do not apply to combinations of this program with
18 * other software, or any other product whatsoever.
vapier45a8ba02009-07-20 10:59:32 +000019 *
alaffincc2e5552000-07-27 17:13:18 +000020 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write the Free Software Foundation, Inc., 59
22 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
vapier45a8ba02009-07-20 10:59:32 +000023 *
alaffincc2e5552000-07-27 17:13:18 +000024 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
25 * Mountain View, CA 94043, or:
vapier45a8ba02009-07-20 10:59:32 +000026 *
27 * http://www.sgi.com
28 *
29 * For further information regarding this notice, see:
30 *
alaffincc2e5552000-07-27 17:13:18 +000031 * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
32 */
33
34
yaberauneya7113a0c2009-12-01 08:57:20 +000035/* $Id: tst_res.c,v 1.14 2009/12/01 08:57:20 yaberauneya Exp $ */
alaffincc2e5552000-07-27 17:13:18 +000036
37/**********************************************************
38 *
39 * OS Testing - Silicon Graphics, Inc.
40 *
41 * FUNCTION NAME :
42 * tst_res() - Print result message (include file contents)
43 * tst_resm() - Print result message
44 * tst_brk() - Print result message (include file contents)
45 * and break remaining test cases
46 * tst_brkm() - Print result message and break remaining test
47 * cases
Garrett Cooper5b875442010-12-13 20:49:15 -080048 * tst_flush() - Print any messages pending in the output stream
alaffincc2e5552000-07-27 17:13:18 +000049 * tst_exit() - Exit test with a meaningful exit value.
50 * tst_environ() - Keep results coming to original stdout
51 *
52 * FUNCTION TITLE : Standard automated test result reporting mechanism
53 *
54 * SYNOPSIS:
55 * #include "test.h"
56 *
57 * void tst_res(ttype, fname, tmesg [,arg]...)
58 * int ttype;
59 * char *fname;
60 * char *tmesg;
61 *
62 * void tst_resm(ttype, tmesg [,arg]...)
63 * int ttype;
64 * char *tmesg;
65 *
66 * void tst_brk(ttype, fname, cleanup, tmesg, [,argv]...)
67 * int ttype;
68 * char *fname;
69 * void (*cleanup)();
70 * char *tmesg;
71 *
72 * void tst_brkm(ttype, cleanup, tmesg [,arg]...)
73 * int ttype;
74 * void (*cleanup)();
75 * char *tmesg;
76 *
alaffincc2e5552000-07-27 17:13:18 +000077 * void tst_flush()
78 *
79 * void tst_exit()
80 *
81 * int tst_environ()
82 *
83 * AUTHOR : Kent Rogers (from Dave Fenner's original)
84 *
85 * CO-PILOT : Rich Logan
86 *
87 * DATE STARTED : 05/01/90 (rewritten 1/96)
88 *
subrata_modak88c166c2009-06-09 16:01:20 +000089 * MAJOR CLEANUPS BY : Cyril Hrubis
90 *
alaffincc2e5552000-07-27 17:13:18 +000091 * DESCRIPTION
92 * See the man page(s).
93 *
94 *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/
Garrett Cooperd3e6e8f2010-12-13 02:55:35 -080095
96#ifdef GARRETT_IS_A_PEDANTIC_BASTARD
97#include <assert.h>
98#endif
alaffincc2e5552000-07-27 17:13:18 +000099#include <errno.h>
subrata_modak88c166c2009-06-09 16:01:20 +0000100#include <stdio.h>
101#include <stdlib.h>
102#include <stdarg.h>
Garrett Cooperd3e6e8f2010-12-13 02:55:35 -0800103#include <string.h>
subrata_modak88c166c2009-06-09 16:01:20 +0000104#include <unistd.h>
105#include "test.h"
vapier9799ea12009-07-20 02:42:32 +0000106#include "usctest.h"
alaffincc2e5552000-07-27 17:13:18 +0000107
Garrett Cooperd3e6e8f2010-12-13 02:55:35 -0800108/* Break bad habits. */
109#ifdef GARRETT_IS_A_PEDANTIC_BASTARD
110pid_t spawned_program_pid;
111#endif
112
alaffincc2e5552000-07-27 17:13:18 +0000113#define VERBOSE 1 /* flag values for the T_mode variable */
alaffincc2e5552000-07-27 17:13:18 +0000114#define NOPASS 3
115#define DISCARD 4
116
117#define MAXMESG 80 /* max length of internal messages */
118#define USERMESG 2048 /* max length of user message */
119#define TRUE 1
120#define FALSE 0
121
122/*
123 * EXPAND_VAR_ARGS - Expand the variable portion (arg_fmt) of a result
124 * message into the specified string.
125 */
subrata_modak3311a252009-10-13 13:59:29 +0000126#define EXPAND_VAR_ARGS(buf, arg_fmt, buf_len) { \
127 va_list ap; \
128 \
129 if (arg_fmt != NULL) { \
130 if (Expand_varargs) { \
131 va_start(ap, arg_fmt); \
132 vsnprintf(buf, buf_len, arg_fmt, ap); \
133 va_end(ap); \
134 } else \
135 strncpy(buf, arg_fmt, buf_len); \
136 } else \
137 buf[0] = '\0'; \
subrata_modak88c166c2009-06-09 16:01:20 +0000138}
alaffincc2e5552000-07-27 17:13:18 +0000139
140/*
141 * Define local function prototypes.
142 */
subrata_modak88c166c2009-06-09 16:01:20 +0000143static void check_env(void);
alaffincc2e5552000-07-27 17:13:18 +0000144static void tst_condense(int tnum, int ttype, char *tmesg);
Garrett Cooper5b875442010-12-13 20:49:15 -0800145static void tst_print(char *tcid, int tnum, int ttype, char *tmesg);
alaffincc2e5552000-07-27 17:13:18 +0000146static void cat_file(char *filename);
147
alaffincc2e5552000-07-27 17:13:18 +0000148/*
149 * Define some static/global variables.
150 */
151static FILE *T_out = NULL; /* tst_res() output file descriptor */
152static char *File; /* file whose contents is part of result */
153static int T_exitval = 0; /* exit value used by tst_exit() */
154static int T_mode = VERBOSE; /* flag indicating print mode: VERBOSE, */
Garrett Cooper5b875442010-12-13 20:49:15 -0800155 /* NOPASS, DISCARD */
alaffincc2e5552000-07-27 17:13:18 +0000156
157static int Expand_varargs = TRUE; /* if TRUE, expand varargs stuff */
158static char Warn_mesg[MAXMESG]; /* holds warning messages */
159
160/*
161 * These are used for condensing output when NOT in verbose mode.
162 */
163static int Buffered = FALSE; /* TRUE if condensed output is currently */
164 /* buffered (i.e. not yet printed) */
165static char *Last_tcid; /* previous test case id */
166static int Last_num; /* previous test case number */
167static int Last_type; /* previous test result type */
168static char *Last_mesg; /* previous test result message */
169
170
171/*
172 * These globals may be externed by the test.
173 */
174int Tst_count = 0; /* current count of test cases executed; NOTE: */
175 /* Tst_count may be externed by other programs */
alaffincc2e5552000-07-27 17:13:18 +0000176
177/*
178 * These globals must be defined in the test.
179 */
180extern char *TCID; /* Test case identifier from the test source */
181extern int TST_TOTAL; /* Total number of test cases from the test */
182 /* source */
183
vapier9799ea12009-07-20 02:42:32 +0000184struct pair {
185 const char *name;
186 int val;
187};
188#define PAIR(def) [def] = { .name = #def, .val = def, },
189const char *pair_lookup(struct pair *pair, int pair_size, int idx)
190{
191 if (idx < 0 || idx >= pair_size || pair[idx].name == NULL)
192 return "???";
193 return pair[idx].name;
194}
195#define pair_lookup(pair, idx) pair_lookup(pair, ARRAY_SIZE(pair), idx)
196
197/*
198 * strttype() - convert a type result to the human readable string
199 */
200const char *strttype(int ttype)
201{
202 struct pair ttype_pairs[] = {
203 PAIR(TPASS)
204 PAIR(TFAIL)
205 PAIR(TBROK)
206 PAIR(TRETR)
207 PAIR(TCONF)
208 PAIR(TWARN)
209 PAIR(TINFO)
210 };
211 return pair_lookup(ttype_pairs, TTYPE_RESULT(ttype));
212}
213
214/*
215 * strerrnodef() - convert an errno value to its C define
216 */
217static const char *strerrnodef(int err)
218{
219 struct pair errno_pairs[] = {
220 PAIR(EPERM)
221 PAIR(ENOENT)
222 PAIR(ESRCH)
223 PAIR(EINTR)
224 PAIR(EIO)
225 PAIR(ENXIO)
226 PAIR(E2BIG)
227 PAIR(ENOEXEC)
228 PAIR(EBADF)
229 PAIR(ECHILD)
230 PAIR(EAGAIN)
231 PAIR(ENOMEM)
232 PAIR(EACCES)
233 PAIR(EFAULT)
234 PAIR(ENOTBLK)
235 PAIR(EBUSY)
236 PAIR(EEXIST)
237 PAIR(EXDEV)
238 PAIR(ENODEV)
239 PAIR(ENOTDIR)
240 PAIR(EISDIR)
241 PAIR(EINVAL)
242 PAIR(ENFILE)
243 PAIR(EMFILE)
244 PAIR(ENOTTY)
245 PAIR(ETXTBSY)
246 PAIR(EFBIG)
247 PAIR(ENOSPC)
248 PAIR(ESPIPE)
249 PAIR(EROFS)
250 PAIR(EMLINK)
251 PAIR(EPIPE)
252 PAIR(EDOM)
253 PAIR(ERANGE)
vapier995d5a32009-08-28 11:05:36 +0000254 PAIR(ENAMETOOLONG)
vapier9799ea12009-07-20 02:42:32 +0000255 };
256 return pair_lookup(errno_pairs, err);
257}
258
alaffincc2e5552000-07-27 17:13:18 +0000259/*
260 * tst_res() - Main result reporting function. Handle test information
261 * appropriately depending on output display mode. Call
262 * tst_condense() or tst_print() to actually print results.
263 * All result functions (tst_resm(), tst_brk(), etc.)
264 * eventually get here to print the results.
265 */
subrata_modak88c166c2009-06-09 16:01:20 +0000266void tst_res(int ttype, char *fname, char *arg_fmt, ...)
alaffincc2e5552000-07-27 17:13:18 +0000267{
subrata_modak88c166c2009-06-09 16:01:20 +0000268 char tmesg[USERMESG];
vapier9799ea12009-07-20 02:42:32 +0000269 int ttype_result = TTYPE_RESULT(ttype);
alaffincc2e5552000-07-27 17:13:18 +0000270
271#if DEBUG
Garrett Cooper8798ebf2010-12-13 20:27:37 -0800272 printf("IN tst_res; Tst_count = %d\n", Tst_count);
273 fflush(stdout);
alaffincc2e5552000-07-27 17:13:18 +0000274#endif
275
subrata_modak3311a252009-10-13 13:59:29 +0000276 EXPAND_VAR_ARGS(tmesg, arg_fmt, USERMESG);
alaffincc2e5552000-07-27 17:13:18 +0000277
subrata_modak88c166c2009-06-09 16:01:20 +0000278 /*
279 * Save the test result type by ORing ttype into the current exit
280 * value (used by tst_exit()).
281 */
vapier9799ea12009-07-20 02:42:32 +0000282 T_exitval |= ttype_result;
alaffincc2e5552000-07-27 17:13:18 +0000283
subrata_modak88c166c2009-06-09 16:01:20 +0000284 /*
285 * Unless T_out has already been set by tst_environ(), make tst_res()
286 * output go to standard output.
287 */
288 if (T_out == NULL)
289 T_out = stdout;
alaffincc2e5552000-07-27 17:13:18 +0000290
subrata_modak88c166c2009-06-09 16:01:20 +0000291 /*
292 * Check TOUTPUT environment variable (if first time) and set T_mode
293 * flag.
294 */
295 check_env();
alaffincc2e5552000-07-27 17:13:18 +0000296
subrata_modak88c166c2009-06-09 16:01:20 +0000297 if (fname != NULL && access(fname, F_OK) == 0)
298 File = fname;
alaffincc2e5552000-07-27 17:13:18 +0000299
subrata_modak88c166c2009-06-09 16:01:20 +0000300 /*
301 * Set the test case number and print the results, depending on the
302 * display type.
303 */
vapier9799ea12009-07-20 02:42:32 +0000304 if (ttype_result == TWARN || ttype_result == TINFO) {
Garrett Cooper5b875442010-12-13 20:49:15 -0800305 tst_print(TCID, 0, ttype, tmesg);
subrata_modak88c166c2009-06-09 16:01:20 +0000306 } else {
307 if (Tst_count < 0)
Garrett Cooper5b875442010-12-13 20:49:15 -0800308 tst_print(TCID, 0, TWARN,
309 "tst_res(): Tst_count < 0 is not valid");
alaffincc2e5552000-07-27 17:13:18 +0000310
subrata_modak88c166c2009-06-09 16:01:20 +0000311 /*
312 * Process each display type.
313 */
314 switch (T_mode) {
Garrett Cooper8798ebf2010-12-13 20:27:37 -0800315 case DISCARD:
subrata_modak88c166c2009-06-09 16:01:20 +0000316 break;
Garrett Cooper8798ebf2010-12-13 20:27:37 -0800317 case NOPASS: /* filtered by tst_print() */
Garrett Cooper5b875442010-12-13 20:49:15 -0800318 tst_condense(Tst_count+1, ttype, tmesg);
subrata_modak88c166c2009-06-09 16:01:20 +0000319 break;
Garrett Cooper8798ebf2010-12-13 20:27:37 -0800320 default: /* VERBOSE */
Garrett Cooper5b875442010-12-13 20:49:15 -0800321 tst_print(TCID, Tst_count+1, ttype, tmesg);
subrata_modak88c166c2009-06-09 16:01:20 +0000322 break;
323 }
alaffincc2e5552000-07-27 17:13:18 +0000324
Garrett Cooper8798ebf2010-12-13 20:27:37 -0800325 Tst_count++;
subrata_modak88c166c2009-06-09 16:01:20 +0000326 }
alaffincc2e5552000-07-27 17:13:18 +0000327
subrata_modak88c166c2009-06-09 16:01:20 +0000328 Expand_varargs = TRUE;
329}
alaffincc2e5552000-07-27 17:13:18 +0000330
331
332/*
Garrett Cooper5b875442010-12-13 20:49:15 -0800333 * tst_condense() - Handle test cases in NOPASS mode (i.e.
alaffincc2e5552000-07-27 17:13:18 +0000334 * buffer the current result and print the last result
335 * if different than the current). If a file was
336 * specified, print the current result and do not
337 * buffer it.
338 */
subrata_modak88c166c2009-06-09 16:01:20 +0000339static void tst_condense(int tnum, int ttype, char *tmesg)
alaffincc2e5552000-07-27 17:13:18 +0000340{
subrata_modak88c166c2009-06-09 16:01:20 +0000341 char *file;
vapier9799ea12009-07-20 02:42:32 +0000342 int ttype_result = TTYPE_RESULT(ttype);
alaffincc2e5552000-07-27 17:13:18 +0000343
344#if DEBUG
Garrett Cooper6bfb01e2010-11-22 10:16:28 -0800345 printf( "IN tst_condense: tcid = %s, tnum = %d, ttype = %d, "
346 "tmesg = %s\n",
347 TCID, tnum, ttype, tmesg);
subrata_modak88c166c2009-06-09 16:01:20 +0000348 fflush(stdout);
alaffincc2e5552000-07-27 17:13:18 +0000349#endif
350
subrata_modak88c166c2009-06-09 16:01:20 +0000351 /*
352 * If this result is the same as the previous result, return.
353 */
354 if (Buffered == TRUE) {
vapier9799ea12009-07-20 02:42:32 +0000355 if (strcmp(Last_tcid, TCID) == 0 && Last_type == ttype_result &&
Garrett Cooper5b875442010-12-13 20:49:15 -0800356 strcmp(Last_mesg, tmesg) == 0 && File == NULL)
subrata_modak88c166c2009-06-09 16:01:20 +0000357 return;
alaffincc2e5552000-07-27 17:13:18 +0000358
subrata_modak88c166c2009-06-09 16:01:20 +0000359 /*
360 * This result is different from the previous result. First,
361 * print the previous result.
362 */
363 file = File;
364 File = NULL;
Garrett Cooper5b875442010-12-13 20:49:15 -0800365 tst_print(Last_tcid, Last_num, Last_type, Last_mesg);
subrata_modak88c166c2009-06-09 16:01:20 +0000366 free(Last_tcid);
367 free(Last_mesg);
368 File = file;
369 }
alaffincc2e5552000-07-27 17:13:18 +0000370
subrata_modak88c166c2009-06-09 16:01:20 +0000371 /*
372 * If a file was specified, print the current result since we have no
373 * way of retaining the file contents for comparing with future
374 * results. Otherwise, buffer the current result info for next time.
375 */
376 if (File != NULL) {
Garrett Cooper5b875442010-12-13 20:49:15 -0800377 tst_print(TCID, tnum, ttype, tmesg);
subrata_modak88c166c2009-06-09 16:01:20 +0000378 Buffered = FALSE;
379 } else {
380 Last_tcid = (char *)malloc(strlen(TCID) + 1);
381 strcpy(Last_tcid, TCID);
382 Last_num = tnum;
vapier9799ea12009-07-20 02:42:32 +0000383 Last_type = ttype_result;
subrata_modak88c166c2009-06-09 16:01:20 +0000384 Last_mesg = (char *)malloc(strlen(tmesg) + 1);
385 strcpy(Last_mesg, tmesg);
386 Buffered = TRUE;
387 }
388}
alaffincc2e5552000-07-27 17:13:18 +0000389
390
391/*
Garrett Cooper5b875442010-12-13 20:49:15 -0800392 * tst_flush() - Print any messages pending because due to tst_condense,
alaffincc2e5552000-07-27 17:13:18 +0000393 * and flush T_out.
394 */
subrata_modak88c166c2009-06-09 16:01:20 +0000395void tst_flush(void)
alaffincc2e5552000-07-27 17:13:18 +0000396{
397#if DEBUG
subrata_modak88c166c2009-06-09 16:01:20 +0000398 printf("IN tst_flush\n");
399 fflush(stdout);
alaffincc2e5552000-07-27 17:13:18 +0000400#endif
401
subrata_modak88c166c2009-06-09 16:01:20 +0000402 /*
Garrett Cooper5b875442010-12-13 20:49:15 -0800403 * Print out last line if in NOPASS mode.
subrata_modak88c166c2009-06-09 16:01:20 +0000404 */
Garrett Cooper5b875442010-12-13 20:49:15 -0800405 if (Buffered == TRUE && T_mode == NOPASS) {
406 tst_print(Last_tcid, Last_num, Last_type, Last_mesg);
subrata_modak88c166c2009-06-09 16:01:20 +0000407 Buffered = FALSE;
408 }
409
410 fflush(T_out);
411}
alaffincc2e5552000-07-27 17:13:18 +0000412
413
414/*
Garrett Cooper5b875442010-12-13 20:49:15 -0800415 * tst_print() - Print a line to the output stream.
alaffincc2e5552000-07-27 17:13:18 +0000416 */
Garrett Cooper5b875442010-12-13 20:49:15 -0800417static void tst_print(char *tcid, int tnum, int ttype, char *tmesg)
alaffincc2e5552000-07-27 17:13:18 +0000418{
yaberauneya7113a0c2009-12-01 08:57:20 +0000419 /*
420 * avoid unintended side effects from failures with fprintf when
421 * calling write(2), et all.
422 */
Garrett Cooper1e6f5a62010-12-19 09:58:10 -0800423 int err = errno;
vapier9799ea12009-07-20 02:42:32 +0000424 const char *type;
425 int ttype_result = TTYPE_RESULT(ttype);
alaffincc2e5552000-07-27 17:13:18 +0000426
Garrett Cooperd3e6e8f2010-12-13 02:55:35 -0800427#ifdef GARRETT_IS_A_PEDANTIC_BASTARD
428 /* Don't execute these APIs unless you have the same pid as main! */
Garrett Cooper60cd1672010-11-23 21:06:05 -0800429 if (spawned_program_pid != 0) {
Garrett Cooper1e6f5a62010-12-19 09:58:10 -0800430 /*
Garrett Cooperd3e6e8f2010-12-13 02:55:35 -0800431 * Die quickly and noisily so people get the cluebat that the
432 * test needs to be fixed. These APIs should _not_ be called
433 * from forked processes because of the fact that it can confuse
434 * end-users with printouts, cleanup will potentially blow away
435 * directories and/or files still in use introducing
436 * non-determinism, etc.
437 *
438 * assert will not return (by design in accordance with POSIX
439 * 1003.1) if the assertion fails. Read abort(3) for more
440 * details. So don't worry about saving / restoring the signal
441 * handler, unless you have a buggy OS that you've hacked 15
442 * different ways to Sunday.
443 */
Garrett Cooper60cd1672010-11-23 21:06:05 -0800444 assert(spawned_program_pid == getpid());
Garrett Cooperd3e6e8f2010-12-13 02:55:35 -0800445 }
446#endif
447
alaffincc2e5552000-07-27 17:13:18 +0000448#if DEBUG
Garrett Cooper5b875442010-12-13 20:49:15 -0800449 printf("IN tst_print: tnum = %d, ttype = %d, tmesg = %s\n",
450 tnum, ttype, tmesg);
subrata_modak88c166c2009-06-09 16:01:20 +0000451 fflush(stdout);
alaffincc2e5552000-07-27 17:13:18 +0000452#endif
453
subrata_modak88c166c2009-06-09 16:01:20 +0000454 /*
455 * Save the test result type by ORing ttype into the current exit value
456 * (used by tst_exit()). This is already done in tst_res(), but is
457 * also done here to catch internal warnings. For internal warnings,
458 * tst_print() is called directly with a case of TWARN.
459 */
vapier9799ea12009-07-20 02:42:32 +0000460 T_exitval |= ttype_result;
alaffincc2e5552000-07-27 17:13:18 +0000461
subrata_modak88c166c2009-06-09 16:01:20 +0000462 /*
463 * If output mode is DISCARD, or if the output mode is NOPASS and this
464 * result is not one of FAIL, BROK, or WARN, just return. This check
465 * is necessary even though we check for DISCARD mode inside of
466 * tst_res(), since occasionally we get to this point without going
467 * through tst_res() (e.g. internal TWARN messages).
468 */
vapier9799ea12009-07-20 02:42:32 +0000469 if (T_mode == DISCARD || (T_mode == NOPASS && ttype_result != TFAIL &&
470 ttype_result != TBROK && ttype_result != TWARN))
subrata_modak88c166c2009-06-09 16:01:20 +0000471 return;
alaffincc2e5552000-07-27 17:13:18 +0000472
subrata_modak88c166c2009-06-09 16:01:20 +0000473 /*
subrata_modak88c166c2009-06-09 16:01:20 +0000474 * Build the result line and print it.
475 */
vapier9799ea12009-07-20 02:42:32 +0000476 type = strttype(ttype);
subrata_modak88c166c2009-06-09 16:01:20 +0000477 if (T_mode == VERBOSE) {
vapier9799ea12009-07-20 02:42:32 +0000478 fprintf(T_out, "%-8s %4d %s : %s", tcid, tnum, type, tmesg);
subrata_modak88c166c2009-06-09 16:01:20 +0000479 } else {
Garrett Cooper5b875442010-12-13 20:49:15 -0800480 fprintf(T_out, "%-8s %4d %s : %s",
481 tcid, tnum, type, tmesg);
subrata_modak88c166c2009-06-09 16:01:20 +0000482 }
vapier9799ea12009-07-20 02:42:32 +0000483 if (ttype & TERRNO) {
vapier9799ea12009-07-20 02:42:32 +0000484 fprintf(T_out, ": errno=%s(%i): %s", strerrnodef(err),
485 err, strerror(err));
486 }
yaberauneya7113a0c2009-12-01 08:57:20 +0000487 if (ttype & TTERRNO) {
488 fprintf(T_out, ": TEST_ERRNO=%s(%i): %s",
489 strerrnodef(TEST_ERRNO), (int)TEST_ERRNO,
490 strerror(TEST_ERRNO));
491 }
vapier9799ea12009-07-20 02:42:32 +0000492 fprintf(T_out, "\n");
alaffincc2e5552000-07-27 17:13:18 +0000493
subrata_modak88c166c2009-06-09 16:01:20 +0000494 /*
495 * If tst_res() was called with a file, append file contents to the
496 * end of last printed result.
497 */
498 if (File != NULL)
499 cat_file(File);
500
501 File = NULL;
502}
alaffincc2e5552000-07-27 17:13:18 +0000503
504
505/*
506 * check_env() - Check the value of the environment variable TOUTPUT and
507 * set the global variable T_mode. The TOUTPUT environment
Garrett Cooper5b875442010-12-13 20:49:15 -0800508 * variable should be set to "VERBOSE", "NOPASS", or "DISCARD".
509 * If TOUTPUT does not exist or is not set to a valid value, the
510 * default is "VERBOSE".
alaffincc2e5552000-07-27 17:13:18 +0000511 */
subrata_modak88c166c2009-06-09 16:01:20 +0000512static void check_env(void)
alaffincc2e5552000-07-27 17:13:18 +0000513{
subrata_modak88c166c2009-06-09 16:01:20 +0000514 static int first_time = 1;
515 char *value;
alaffincc2e5552000-07-27 17:13:18 +0000516
517#if DEBUG
subrata_modak88c166c2009-06-09 16:01:20 +0000518 printf("IN check_env\n");
519 fflush(stdout);
alaffincc2e5552000-07-27 17:13:18 +0000520#endif
521
subrata_modak88c166c2009-06-09 16:01:20 +0000522 if (!first_time)
523 return;
alaffincc2e5552000-07-27 17:13:18 +0000524
subrata_modak88c166c2009-06-09 16:01:20 +0000525 first_time = 0;
alaffincc2e5552000-07-27 17:13:18 +0000526
Garrett Cooper60cd1672010-11-23 21:06:05 -0800527 /* BTOUTPUT not defined, use default */
subrata_modak88c166c2009-06-09 16:01:20 +0000528 if ((value = getenv(TOUTPUT)) == NULL) {
529 T_mode = VERBOSE;
530 return;
531 }
alaffincc2e5552000-07-27 17:13:18 +0000532
subrata_modak88c166c2009-06-09 16:01:20 +0000533 if (strcmp(value, TOUT_NOPASS_S) == 0) {
534 T_mode = NOPASS;
535 return;
536 }
537
538 if (strcmp(value, TOUT_DISCARD_S) == 0) {
539 T_mode = DISCARD;
540 return;
541 }
542
543 /* default */
544 T_mode = VERBOSE;
545 return;
546}
alaffincc2e5552000-07-27 17:13:18 +0000547
548
549/*
550 * tst_exit() - Call exit() with the value T_exitval, set up by
551 * tst_res(). T_exitval has a bit set for most of the
552 * result types that were seen (including TPASS, TFAIL,
553 * TBROK, TWARN, TCONF). Also, print the last result (if
554 * necessary) before exiting.
555 */
subrata_modak88c166c2009-06-09 16:01:20 +0000556void tst_exit(void)
alaffincc2e5552000-07-27 17:13:18 +0000557{
558#if DEBUG
subrata_modak88c166c2009-06-09 16:01:20 +0000559 printf("IN tst_exit\n"); fflush(stdout);
560 fflush(stdout);
alaffincc2e5552000-07-27 17:13:18 +0000561#endif
562
Garrett Cooper5b875442010-12-13 20:49:15 -0800563 /* Call tst_flush() flush any output in the buffer. */
subrata_modak88c166c2009-06-09 16:01:20 +0000564 tst_flush();
alaffincc2e5552000-07-27 17:13:18 +0000565
Garrett Cooper5b875442010-12-13 20:49:15 -0800566 /* Mask out TRETR, TINFO, and TCONF results from the exit status. */
subrata_modak88c166c2009-06-09 16:01:20 +0000567 exit(T_exitval & ~(TRETR | TINFO | TCONF));
568}
alaffincc2e5552000-07-27 17:13:18 +0000569
570
571/*
572 * tst_environ() - Preserve the tst_res() output location, despite any
573 * changes to stdout.
574 */
subrata_modak88c166c2009-06-09 16:01:20 +0000575int tst_environ(void)
alaffincc2e5552000-07-27 17:13:18 +0000576{
subrata_modak88c166c2009-06-09 16:01:20 +0000577 if ((T_out = fdopen(dup(fileno(stdout)), "w")) == NULL)
578 return -1;
579 else
580 return 0;
581}
alaffincc2e5552000-07-27 17:13:18 +0000582
583
584/*
585 * tst_brk() - Fail or break current test case, and break the remaining
586 * tests cases.
587 */
subrata_modak88c166c2009-06-09 16:01:20 +0000588void tst_brk(int ttype, char *fname, void (*func)(void), char *arg_fmt, ...)
alaffincc2e5552000-07-27 17:13:18 +0000589{
subrata_modak88c166c2009-06-09 16:01:20 +0000590 char tmesg[USERMESG];
vapier9799ea12009-07-20 02:42:32 +0000591 int ttype_result = TTYPE_RESULT(ttype);
alaffincc2e5552000-07-27 17:13:18 +0000592
593#if DEBUG
subrata_modak88c166c2009-06-09 16:01:20 +0000594 printf("IN tst_brk\n"); fflush(stdout);
595 fflush(stdout);
alaffincc2e5552000-07-27 17:13:18 +0000596#endif
597
subrata_modak3311a252009-10-13 13:59:29 +0000598 EXPAND_VAR_ARGS(tmesg, arg_fmt, USERMESG);
alaffincc2e5552000-07-27 17:13:18 +0000599
subrata_modak88c166c2009-06-09 16:01:20 +0000600 /*
601 * Only FAIL, BROK, CONF, and RETR are supported by tst_brk().
602 */
vapier9799ea12009-07-20 02:42:32 +0000603 if (ttype_result != TFAIL && ttype_result != TBROK &&
604 ttype_result != TCONF && ttype_result != TRETR) {
Garrett Coopereacf2a32010-12-16 16:04:04 -0800605 sprintf(Warn_mesg, "%s: Invalid Type: %d. Using TBROK",
606 __func__, ttype_result);
Garrett Cooper5b875442010-12-13 20:49:15 -0800607 tst_print(TCID, 0, TWARN, Warn_mesg);
Garrett Coopereacf2a32010-12-16 16:04:04 -0800608 /* Keep TERRNO, TTERRNO, etc. */
609 ttype = (ttype & ~ttype_result) | TBROK;
subrata_modak88c166c2009-06-09 16:01:20 +0000610 }
alaffincc2e5552000-07-27 17:13:18 +0000611
subrata_modak88c166c2009-06-09 16:01:20 +0000612 /* Print the first result, if necessary. */
613 if (Tst_count < TST_TOTAL)
614 tst_res(ttype, fname, "%s", tmesg);
alaffincc2e5552000-07-27 17:13:18 +0000615
Garrett Coopereacf2a32010-12-16 16:04:04 -0800616 if (ttype_result == TCONF)
Garrett Cooper5b875442010-12-13 20:49:15 -0800617 tst_res(ttype, NULL,
618 "Remaining cases not appropriate for configuration");
Garrett Coopereacf2a32010-12-16 16:04:04 -0800619 else if (ttype_result == TRETR)
620 tst_res(ttype, NULL, "Remaining cases retired");
621 else if (ttype_result == TBROK)
622 tst_res(TBROK, NULL, "Remaining cases broken");
Garrett Cooper5b875442010-12-13 20:49:15 -0800623 Expand_varargs = TRUE;
alaffincc2e5552000-07-27 17:13:18 +0000624
alaffincc2e5552000-07-27 17:13:18 +0000625 /*
626 * If no cleanup function was specified, just return to the caller.
Garrett Cooper9f2555e2010-12-13 23:55:22 -0800627 * Otherwise call the specified function.
alaffincc2e5552000-07-27 17:13:18 +0000628 */
Garrett Cooper6bfb01e2010-11-22 10:16:28 -0800629 if (func != NULL) {
subrata_modak88c166c2009-06-09 16:01:20 +0000630 (*func)();
Garrett Cooper6bfb01e2010-11-22 10:16:28 -0800631 }
632 tst_exit();
subrata_modak88c166c2009-06-09 16:01:20 +0000633}
alaffincc2e5552000-07-27 17:13:18 +0000634
alaffincc2e5552000-07-27 17:13:18 +0000635/*
636 * tst_resm() - Interface to tst_res(), with no filename.
637 */
subrata_modak88c166c2009-06-09 16:01:20 +0000638void tst_resm(int ttype, char *arg_fmt, ...)
alaffincc2e5552000-07-27 17:13:18 +0000639{
subrata_modak88c166c2009-06-09 16:01:20 +0000640 char tmesg[USERMESG];
alaffincc2e5552000-07-27 17:13:18 +0000641
642#if DEBUG
subrata_modak88c166c2009-06-09 16:01:20 +0000643 printf("IN tst_resm\n"); fflush(stdout);
644 fflush(stdout);
alaffincc2e5552000-07-27 17:13:18 +0000645#endif
646
subrata_modak3311a252009-10-13 13:59:29 +0000647 EXPAND_VAR_ARGS(tmesg, arg_fmt, USERMESG);
alaffincc2e5552000-07-27 17:13:18 +0000648
subrata_modak88c166c2009-06-09 16:01:20 +0000649 tst_res(ttype, NULL, "%s", tmesg);
650}
alaffincc2e5552000-07-27 17:13:18 +0000651
652
653/*
654 * tst_brkm() - Interface to tst_brk(), with no filename.
655 */
subrata_modak88c166c2009-06-09 16:01:20 +0000656void tst_brkm(int ttype, void (*func)(void), char *arg_fmt, ...)
alaffincc2e5552000-07-27 17:13:18 +0000657{
subrata_modak88c166c2009-06-09 16:01:20 +0000658 char tmesg[USERMESG];
alaffincc2e5552000-07-27 17:13:18 +0000659
660#if DEBUG
subrata_modak88c166c2009-06-09 16:01:20 +0000661 printf("IN tst_brkm\n"); fflush(stdout);
662 fflush(stdout);
alaffincc2e5552000-07-27 17:13:18 +0000663#endif
664
subrata_modak3311a252009-10-13 13:59:29 +0000665 EXPAND_VAR_ARGS(tmesg, arg_fmt, USERMESG);
alaffincc2e5552000-07-27 17:13:18 +0000666
vapierf88c09e2009-08-28 10:00:39 +0000667 tst_brk(ttype, NULL, func, "%s", tmesg);
subrata_modak88c166c2009-06-09 16:01:20 +0000668}
alaffincc2e5552000-07-27 17:13:18 +0000669
670
671/*
vapier640adf42008-05-06 15:47:54 +0000672 * tst_require_root() - Test for root permissions and abort if not.
673 */
subrata_modak88c166c2009-06-09 16:01:20 +0000674void tst_require_root(void (*func)(void))
vapier640adf42008-05-06 15:47:54 +0000675{
subrata_modak88c166c2009-06-09 16:01:20 +0000676 if (geteuid() != 0)
677 tst_brkm(TCONF, func, "Test needs to be run as root");
vapier640adf42008-05-06 15:47:54 +0000678}
679
680
681/*
alaffincc2e5552000-07-27 17:13:18 +0000682 * cat_file() - Print the contents of a file to standard out.
683 */
subrata_modak88c166c2009-06-09 16:01:20 +0000684static void cat_file(char *filename)
alaffincc2e5552000-07-27 17:13:18 +0000685{
subrata_modak88c166c2009-06-09 16:01:20 +0000686 FILE *fp;
687 int b_read, b_written;
688 char buffer[BUFSIZ];
alaffincc2e5552000-07-27 17:13:18 +0000689
690#if DEBUG
subrata_modak88c166c2009-06-09 16:01:20 +0000691 printf("IN cat_file\n"); fflush(stdout);
alaffincc2e5552000-07-27 17:13:18 +0000692#endif
693
subrata_modak88c166c2009-06-09 16:01:20 +0000694 if ((fp = fopen(filename, "r")) == NULL) {
695 sprintf(Warn_mesg,
696 "tst_res(): fopen(%s, \"r\") failed; errno = %d: %s",
697 filename, errno, strerror(errno));
Garrett Cooper5b875442010-12-13 20:49:15 -0800698 tst_print(TCID, 0, TWARN, Warn_mesg);
subrata_modak88c166c2009-06-09 16:01:20 +0000699 return;
700 }
alaffincc2e5552000-07-27 17:13:18 +0000701
subrata_modak88c166c2009-06-09 16:01:20 +0000702 errno = 0;
alaffincc2e5552000-07-27 17:13:18 +0000703
subrata_modak88c166c2009-06-09 16:01:20 +0000704 while ((b_read = fread(buffer, 1, BUFSIZ, fp)) != 0) {
705 if ((b_written = fwrite(buffer, 1, b_read, T_out)) != b_read) {
706 sprintf(Warn_mesg,
Garrett Cooper6bfb01e2010-11-22 10:16:28 -0800707 "tst_res(): While trying to cat \"%s\", "
708 "fwrite() wrote only %d of %d bytes",
subrata_modak88c166c2009-06-09 16:01:20 +0000709 filename, b_written, b_read);
Garrett Cooper5b875442010-12-13 20:49:15 -0800710 tst_print(TCID, 0, TWARN, Warn_mesg);
subrata_modak88c166c2009-06-09 16:01:20 +0000711 break;
712 }
713 }
alaffincc2e5552000-07-27 17:13:18 +0000714
subrata_modak88c166c2009-06-09 16:01:20 +0000715 if (!feof(fp)) {
716 sprintf(Warn_mesg,
Garrett Cooper6bfb01e2010-11-22 10:16:28 -0800717 "tst_res(): While trying to cat \"%s\", fread() "
718 "failed, errno = %d: %s",
subrata_modak88c166c2009-06-09 16:01:20 +0000719 filename, errno, strerror(errno));
Garrett Cooper5b875442010-12-13 20:49:15 -0800720 tst_print(TCID, 0, TWARN, Warn_mesg);
subrata_modak88c166c2009-06-09 16:01:20 +0000721 }
alaffincc2e5552000-07-27 17:13:18 +0000722
subrata_modak88c166c2009-06-09 16:01:20 +0000723 if (fclose(fp) != 0) {
724 sprintf(Warn_mesg,
Garrett Cooper6bfb01e2010-11-22 10:16:28 -0800725 "tst_res(): While trying to cat \"%s\", fclose() "
726 "failed, errno = %d: %s",
subrata_modak88c166c2009-06-09 16:01:20 +0000727 filename, errno, strerror(errno));
Garrett Cooper5b875442010-12-13 20:49:15 -0800728 tst_print(TCID, 0, TWARN, Warn_mesg);
subrata_modak88c166c2009-06-09 16:01:20 +0000729 }
730}
alaffincc2e5552000-07-27 17:13:18 +0000731
732
733#ifdef UNIT_TEST
734/****************************************************************************
735 * Unit test code: Takes input from stdin and can make the following
736 * calls: tst_res(), tst_resm(), tst_brk(), tst_brkm(),
737 * tst_flush_buf(), tst_exit().
738 ****************************************************************************/
739int TST_TOTAL = 10;
740char *TCID = "TESTTCID";
741
742#define RES "tst_res.c UNIT TEST message; ttype = %d; contents of \"%s\":"
743#define RESM "tst_res.c UNIT TEST message; ttype = %d"
744
subrata_modak88c166c2009-06-09 16:01:20 +0000745int main(void)
alaffincc2e5552000-07-27 17:13:18 +0000746{
subrata_modak88c166c2009-06-09 16:01:20 +0000747 int ttype;
subrata_modak88c166c2009-06-09 16:01:20 +0000748 char chr;
749 char fname[MAXMESG];
alaffincc2e5552000-07-27 17:13:18 +0000750
subrata_modak88c166c2009-06-09 16:01:20 +0000751 printf("UNIT TEST of tst_res.c. Options for ttype:\n\
752 -1 : call tst_exit()\n\
753 -2 : call tst_flush()\n\
754 -3 : call tst_brk()\n\
Garrett Cooper5b875442010-12-13 20:49:15 -0800755 -4 : call tst_res()\n\
vapier9799ea12009-07-20 02:42:32 +0000756 %2i : call tst_res(TPASS, ...)\n\
757 %2i : call tst_res(TFAIL, ...)\n\
758 %2i : call tst_res(TBROK, ...)\n\
759 %2i : call tst_res(TWARN, ...)\n\
760 %2i : call tst_res(TRETR, ...)\n\
761 %2i : call tst_res(TINFO, ...)\n\
762 %2i : call tst_res(TCONF, ...)\n\n",
763 TPASS, TFAIL, TBROK, TWARN, TRETR, TINFO, TCONF);
alaffincc2e5552000-07-27 17:13:18 +0000764
subrata_modak88c166c2009-06-09 16:01:20 +0000765 while (1) {
vapier9799ea12009-07-20 02:42:32 +0000766 printf("Enter ttype (-5,-4,-3,-2,-1,%i,%i,%i,%i,%i,%i,%i): ",
767 TPASS, TFAIL, TBROK, TWARN, TRETR, TINFO, TCONF);
subrata_modak88c166c2009-06-09 16:01:20 +0000768 scanf("%d%c", &ttype, &chr);
alaffincc2e5552000-07-27 17:13:18 +0000769
subrata_modak88c166c2009-06-09 16:01:20 +0000770 switch (ttype) {
Garrett Cooper6bfb01e2010-11-22 10:16:28 -0800771 case -1:
772 tst_exit();
subrata_modak88c166c2009-06-09 16:01:20 +0000773 break;
alaffincc2e5552000-07-27 17:13:18 +0000774
Garrett Cooper6bfb01e2010-11-22 10:16:28 -0800775 case -2:
776 tst_flush();
subrata_modak88c166c2009-06-09 16:01:20 +0000777 break;
alaffincc2e5552000-07-27 17:13:18 +0000778
Garrett Cooper6bfb01e2010-11-22 10:16:28 -0800779 case -3:
Garrett Cooper53740502010-12-16 00:04:01 -0800780 printf("Enter the current type (%i=FAIL, %i=BROK, %i=RETR, %i=CONF): ",
Garrett Cooper6bfb01e2010-11-22 10:16:28 -0800781 TFAIL, TBROK, TRETR, TCONF);
782 scanf("%d%c", &ttype, &chr);
783 printf("Enter file name (<cr> for none): ");
784 gets(fname);
785 if (strcmp(fname, "") == 0)
786 tst_brkm(ttype, tst_exit, RESM, ttype);
787 else
Garrett Cooper53740502010-12-16 00:04:01 -0800788 tst_brk(ttype, fname, tst_exit, RES, ttype, fname);
789 break;
alaffincc2e5552000-07-27 17:13:18 +0000790
Garrett Cooper53740502010-12-16 00:04:01 -0800791 case -4:
792 printf("Enter the current type (%i,%i,%i,%i,%i,%i,%i): ",
793 TPASS, TFAIL, TBROK, TWARN, TRETR, TINFO, TCONF);
Garrett Cooper6bfb01e2010-11-22 10:16:28 -0800794 scanf("%d%c", &ttype, &chr);
795 default:
796 printf("Enter file name (<cr> for none): ");
797 gets(fname);
alaffincc2e5552000-07-27 17:13:18 +0000798
Garrett Cooper6bfb01e2010-11-22 10:16:28 -0800799 if (strcmp(fname, "") == 0)
800 tst_resm(ttype, RESM, ttype);
801 else
802 tst_res(ttype, fname, RES, ttype, fname);
subrata_modak88c166c2009-06-09 16:01:20 +0000803 break;
804 }
805
806 }
alaffincc2e5552000-07-27 17:13:18 +0000807}
subrata_modak88c166c2009-06-09 16:01:20 +0000808
Garrett Cooper1e6f5a62010-12-19 09:58:10 -0800809#endif /* UNIT_TEST */