blob: 0d19f691e522d3ddd2985cf6b764315ea478c1ad [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
48 * tst_brkloop() - Print result message (include file contents)
49 * and break test cases remaining in current loop
50 * tst_brkloopm() - Print result message and break test case
51 * remaining in current loop
52 * tst_flush() - Print any messages pending because of
53 * CONDENSE mode, and flush output stream
54 * tst_exit() - Exit test with a meaningful exit value.
55 * tst_environ() - Keep results coming to original stdout
56 *
57 * FUNCTION TITLE : Standard automated test result reporting mechanism
58 *
59 * SYNOPSIS:
60 * #include "test.h"
61 *
62 * void tst_res(ttype, fname, tmesg [,arg]...)
63 * int ttype;
64 * char *fname;
65 * char *tmesg;
66 *
67 * void tst_resm(ttype, tmesg [,arg]...)
68 * int ttype;
69 * char *tmesg;
70 *
71 * void tst_brk(ttype, fname, cleanup, tmesg, [,argv]...)
72 * int ttype;
73 * char *fname;
74 * void (*cleanup)();
75 * char *tmesg;
76 *
77 * void tst_brkm(ttype, cleanup, tmesg [,arg]...)
78 * int ttype;
79 * void (*cleanup)();
80 * char *tmesg;
81 *
82 * void tst_brkloop(ttype, fname, cleanup, char *tmesg, [,argv]...)
83 * int ttype;
84 * char *fname;
85 * void (*cleanup)();
86 * char *tmesg;
87 *
88 * void tst_brkloopm(ttype, cleanup, tmesg [,arg]...)
89 * int ttype;
90 * void (*cleanup)();
91 * char *tmesg;
92 *
93 * void tst_flush()
94 *
95 * void tst_exit()
96 *
97 * int tst_environ()
98 *
99 * AUTHOR : Kent Rogers (from Dave Fenner's original)
100 *
101 * CO-PILOT : Rich Logan
102 *
103 * DATE STARTED : 05/01/90 (rewritten 1/96)
104 *
subrata_modak88c166c2009-06-09 16:01:20 +0000105 * MAJOR CLEANUPS BY : Cyril Hrubis
106 *
alaffincc2e5552000-07-27 17:13:18 +0000107 * DESCRIPTION
108 * See the man page(s).
109 *
110 *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/
111#include <errno.h>
112#include <string.h>
subrata_modak88c166c2009-06-09 16:01:20 +0000113#include <stdio.h>
114#include <stdlib.h>
115#include <stdarg.h>
116#include <unistd.h>
117#include "test.h"
vapier9799ea12009-07-20 02:42:32 +0000118#include "usctest.h"
alaffincc2e5552000-07-27 17:13:18 +0000119
alaffincc2e5552000-07-27 17:13:18 +0000120#define VERBOSE 1 /* flag values for the T_mode variable */
121#define CONDENSE 2
122#define NOPASS 3
123#define DISCARD 4
124
125#define MAXMESG 80 /* max length of internal messages */
126#define USERMESG 2048 /* max length of user message */
127#define TRUE 1
128#define FALSE 0
129
130/*
131 * EXPAND_VAR_ARGS - Expand the variable portion (arg_fmt) of a result
132 * message into the specified string.
133 */
subrata_modak3311a252009-10-13 13:59:29 +0000134#define EXPAND_VAR_ARGS(buf, arg_fmt, buf_len) { \
135 va_list ap; \
136 \
137 if (arg_fmt != NULL) { \
138 if (Expand_varargs) { \
139 va_start(ap, arg_fmt); \
140 vsnprintf(buf, buf_len, arg_fmt, ap); \
141 va_end(ap); \
142 } else \
143 strncpy(buf, arg_fmt, buf_len); \
144 } else \
145 buf[0] = '\0'; \
subrata_modak88c166c2009-06-09 16:01:20 +0000146}
alaffincc2e5552000-07-27 17:13:18 +0000147
148/*
149 * Define local function prototypes.
150 */
subrata_modak88c166c2009-06-09 16:01:20 +0000151static void check_env(void);
alaffincc2e5552000-07-27 17:13:18 +0000152static void tst_condense(int tnum, int ttype, char *tmesg);
153static void tst_print(char *tcid, int tnum, int trange, int ttype, char *tmesg);
154static void cat_file(char *filename);
155
156
157/*
158 * Define some static/global variables.
159 */
160static FILE *T_out = NULL; /* tst_res() output file descriptor */
161static char *File; /* file whose contents is part of result */
162static int T_exitval = 0; /* exit value used by tst_exit() */
163static int T_mode = VERBOSE; /* flag indicating print mode: VERBOSE, */
164 /* CONDENSE, NOPASS, DISCARD */
165
166static int Expand_varargs = TRUE; /* if TRUE, expand varargs stuff */
167static char Warn_mesg[MAXMESG]; /* holds warning messages */
168
169/*
170 * These are used for condensing output when NOT in verbose mode.
171 */
172static int Buffered = FALSE; /* TRUE if condensed output is currently */
173 /* buffered (i.e. not yet printed) */
174static char *Last_tcid; /* previous test case id */
175static int Last_num; /* previous test case number */
176static int Last_type; /* previous test result type */
177static char *Last_mesg; /* previous test result message */
178
179
180/*
181 * These globals may be externed by the test.
182 */
183int Tst_count = 0; /* current count of test cases executed; NOTE: */
184 /* Tst_count may be externed by other programs */
185int Tst_lptotal = 0; /* tst_brkloop() external */
186int Tst_lpstart = 0; /* tst_brkloop() external */
187int Tst_range = 1; /* for specifying multiple results */
188int Tst_nobuf = 1; /* this is a no-op; buffering is never done, but */
189 /* this will stay for compatibility reasons */
190
191/*
192 * These globals must be defined in the test.
193 */
194extern char *TCID; /* Test case identifier from the test source */
195extern int TST_TOTAL; /* Total number of test cases from the test */
196 /* source */
197
198/*
199 * This global is used by the temp. dir. maintenance functions,
200 * tst_tmpdir()/tst_rmdir(), tst_wildcard()/tst_tr_rmdir(). It is the
201 * name of the directory created (if any). It is defined here, so that
202 * it only has to be declared once and can then be referenced from more
203 * than one module. Also, since the temp. dir. maintenance functions
204 * rely on the tst_res.c package this seemed like a reasonable place.
205 */
206char *TESTDIR = NULL;
207
vapier9799ea12009-07-20 02:42:32 +0000208struct pair {
209 const char *name;
210 int val;
211};
212#define PAIR(def) [def] = { .name = #def, .val = def, },
213const char *pair_lookup(struct pair *pair, int pair_size, int idx)
214{
215 if (idx < 0 || idx >= pair_size || pair[idx].name == NULL)
216 return "???";
217 return pair[idx].name;
218}
219#define pair_lookup(pair, idx) pair_lookup(pair, ARRAY_SIZE(pair), idx)
220
221/*
222 * strttype() - convert a type result to the human readable string
223 */
224const char *strttype(int ttype)
225{
226 struct pair ttype_pairs[] = {
227 PAIR(TPASS)
228 PAIR(TFAIL)
229 PAIR(TBROK)
230 PAIR(TRETR)
231 PAIR(TCONF)
232 PAIR(TWARN)
233 PAIR(TINFO)
234 };
235 return pair_lookup(ttype_pairs, TTYPE_RESULT(ttype));
236}
237
238/*
239 * strerrnodef() - convert an errno value to its C define
240 */
241static const char *strerrnodef(int err)
242{
243 struct pair errno_pairs[] = {
244 PAIR(EPERM)
245 PAIR(ENOENT)
246 PAIR(ESRCH)
247 PAIR(EINTR)
248 PAIR(EIO)
249 PAIR(ENXIO)
250 PAIR(E2BIG)
251 PAIR(ENOEXEC)
252 PAIR(EBADF)
253 PAIR(ECHILD)
254 PAIR(EAGAIN)
255 PAIR(ENOMEM)
256 PAIR(EACCES)
257 PAIR(EFAULT)
258 PAIR(ENOTBLK)
259 PAIR(EBUSY)
260 PAIR(EEXIST)
261 PAIR(EXDEV)
262 PAIR(ENODEV)
263 PAIR(ENOTDIR)
264 PAIR(EISDIR)
265 PAIR(EINVAL)
266 PAIR(ENFILE)
267 PAIR(EMFILE)
268 PAIR(ENOTTY)
269 PAIR(ETXTBSY)
270 PAIR(EFBIG)
271 PAIR(ENOSPC)
272 PAIR(ESPIPE)
273 PAIR(EROFS)
274 PAIR(EMLINK)
275 PAIR(EPIPE)
276 PAIR(EDOM)
277 PAIR(ERANGE)
vapier995d5a32009-08-28 11:05:36 +0000278 PAIR(ENAMETOOLONG)
vapier9799ea12009-07-20 02:42:32 +0000279 };
280 return pair_lookup(errno_pairs, err);
281}
282
alaffincc2e5552000-07-27 17:13:18 +0000283/*
284 * tst_res() - Main result reporting function. Handle test information
285 * appropriately depending on output display mode. Call
286 * tst_condense() or tst_print() to actually print results.
287 * All result functions (tst_resm(), tst_brk(), etc.)
288 * eventually get here to print the results.
289 */
subrata_modak88c166c2009-06-09 16:01:20 +0000290void tst_res(int ttype, char *fname, char *arg_fmt, ...)
alaffincc2e5552000-07-27 17:13:18 +0000291{
subrata_modak88c166c2009-06-09 16:01:20 +0000292 int i;
293 char tmesg[USERMESG];
vapier9799ea12009-07-20 02:42:32 +0000294 int ttype_result = TTYPE_RESULT(ttype);
alaffincc2e5552000-07-27 17:13:18 +0000295
296#if DEBUG
subrata_modak88c166c2009-06-09 16:01:20 +0000297 printf("IN tst_res; Tst_count = %d; Tst_range = %d\n",
298 Tst_count, Tst_range); fflush(stdout);
alaffincc2e5552000-07-27 17:13:18 +0000299#endif
300
subrata_modak3311a252009-10-13 13:59:29 +0000301 EXPAND_VAR_ARGS(tmesg, arg_fmt, USERMESG);
alaffincc2e5552000-07-27 17:13:18 +0000302
subrata_modak88c166c2009-06-09 16:01:20 +0000303 /*
304 * Save the test result type by ORing ttype into the current exit
305 * value (used by tst_exit()).
306 */
vapier9799ea12009-07-20 02:42:32 +0000307 T_exitval |= ttype_result;
alaffincc2e5552000-07-27 17:13:18 +0000308
subrata_modak88c166c2009-06-09 16:01:20 +0000309 /*
310 * Unless T_out has already been set by tst_environ(), make tst_res()
311 * output go to standard output.
312 */
313 if (T_out == NULL)
314 T_out = stdout;
alaffincc2e5552000-07-27 17:13:18 +0000315
subrata_modak88c166c2009-06-09 16:01:20 +0000316 /*
317 * Check TOUTPUT environment variable (if first time) and set T_mode
318 * flag.
319 */
320 check_env();
alaffincc2e5552000-07-27 17:13:18 +0000321
subrata_modak88c166c2009-06-09 16:01:20 +0000322 if (Tst_range <= 0) {
323 Tst_range = 1;
324 tst_print(TCID, 0, 1, TWARN,
325 "tst_res(): Tst_range must be positive");
326 }
alaffincc2e5552000-07-27 17:13:18 +0000327
subrata_modak88c166c2009-06-09 16:01:20 +0000328 if (fname != NULL && access(fname, F_OK) == 0)
329 File = fname;
alaffincc2e5552000-07-27 17:13:18 +0000330
subrata_modak88c166c2009-06-09 16:01:20 +0000331 /*
332 * Set the test case number and print the results, depending on the
333 * display type.
334 */
vapier9799ea12009-07-20 02:42:32 +0000335 if (ttype_result == TWARN || ttype_result == TINFO) {
subrata_modak88c166c2009-06-09 16:01:20 +0000336 if (Tst_range > 1)
337 tst_print(TCID, 0, 1, TWARN,
338 "tst_res(): Range not valid for TINFO or TWARN types");
339 tst_print(TCID, 0, 1, ttype, tmesg);
340 } else {
341 if (Tst_count < 0)
342 tst_print(TCID, 0, 1, TWARN,
343 "tst_res(): Tst_count < 0 is not valid");
alaffincc2e5552000-07-27 17:13:18 +0000344
subrata_modak88c166c2009-06-09 16:01:20 +0000345 /*
346 * Process each display type.
347 */
348 switch (T_mode) {
349 case DISCARD: /* do not print any results */
350 break;
alaffincc2e5552000-07-27 17:13:18 +0000351
subrata_modak88c166c2009-06-09 16:01:20 +0000352 case NOPASS: /* passing result types are filtered by tst_print() */
353 case CONDENSE:
354 tst_condense(Tst_count + 1, ttype, tmesg);
355 break;
alaffincc2e5552000-07-27 17:13:18 +0000356
subrata_modak88c166c2009-06-09 16:01:20 +0000357 default: /* VERBOSE */
358 for (i = 1 ; i <= Tst_range ; i++)
359 tst_print(TCID, Tst_count + i, Tst_range, ttype, tmesg);
360 break;
361 }
alaffincc2e5552000-07-27 17:13:18 +0000362
subrata_modak88c166c2009-06-09 16:01:20 +0000363 Tst_count += Tst_range;
364 }
alaffincc2e5552000-07-27 17:13:18 +0000365
subrata_modak88c166c2009-06-09 16:01:20 +0000366 Tst_range = 1;
367 Expand_varargs = TRUE;
368}
alaffincc2e5552000-07-27 17:13:18 +0000369
370
371/*
372 * tst_condense() - Handle test cases in CONDENSE or NOPASS mode (i.e.
373 * buffer the current result and print the last result
374 * if different than the current). If a file was
375 * specified, print the current result and do not
376 * buffer it.
377 */
subrata_modak88c166c2009-06-09 16:01:20 +0000378static void tst_condense(int tnum, int ttype, char *tmesg)
alaffincc2e5552000-07-27 17:13:18 +0000379{
subrata_modak88c166c2009-06-09 16:01:20 +0000380 char *file;
vapier9799ea12009-07-20 02:42:32 +0000381 int ttype_result = TTYPE_RESULT(ttype);
alaffincc2e5552000-07-27 17:13:18 +0000382
383#if DEBUG
subrata_modak88c166c2009-06-09 16:01:20 +0000384 printf("IN tst_condense: tcid = %s, tnum = %d, ttype = %d, tmesg = %s\n",
385 TCID, tnum, ttype, tmesg);
386 fflush(stdout);
alaffincc2e5552000-07-27 17:13:18 +0000387#endif
388
subrata_modak88c166c2009-06-09 16:01:20 +0000389 /*
390 * If this result is the same as the previous result, return.
391 */
392 if (Buffered == TRUE) {
vapier9799ea12009-07-20 02:42:32 +0000393 if (strcmp(Last_tcid, TCID) == 0 && Last_type == ttype_result &&
subrata_modak88c166c2009-06-09 16:01:20 +0000394 strcmp(Last_mesg, tmesg) == 0 && File == NULL )
395 return;
alaffincc2e5552000-07-27 17:13:18 +0000396
subrata_modak88c166c2009-06-09 16:01:20 +0000397 /*
398 * This result is different from the previous result. First,
399 * print the previous result.
400 */
401 file = File;
402 File = NULL;
403 tst_print(Last_tcid, Last_num, tnum - Last_num, Last_type,
404 Last_mesg);
405 free(Last_tcid);
406 free(Last_mesg);
407 File = file;
408 }
alaffincc2e5552000-07-27 17:13:18 +0000409
subrata_modak88c166c2009-06-09 16:01:20 +0000410 /*
411 * If a file was specified, print the current result since we have no
412 * way of retaining the file contents for comparing with future
413 * results. Otherwise, buffer the current result info for next time.
414 */
415 if (File != NULL) {
416 tst_print(TCID, tnum, Tst_range, ttype, tmesg);
417 Buffered = FALSE;
418 } else {
419 Last_tcid = (char *)malloc(strlen(TCID) + 1);
420 strcpy(Last_tcid, TCID);
421 Last_num = tnum;
vapier9799ea12009-07-20 02:42:32 +0000422 Last_type = ttype_result;
subrata_modak88c166c2009-06-09 16:01:20 +0000423 Last_mesg = (char *)malloc(strlen(tmesg) + 1);
424 strcpy(Last_mesg, tmesg);
425 Buffered = TRUE;
426 }
427}
alaffincc2e5552000-07-27 17:13:18 +0000428
429
430/*
431 * tst_flush() - Print any messages pending because of CONDENSE mode,
432 * and flush T_out.
433 */
subrata_modak88c166c2009-06-09 16:01:20 +0000434void tst_flush(void)
alaffincc2e5552000-07-27 17:13:18 +0000435{
436#if DEBUG
subrata_modak88c166c2009-06-09 16:01:20 +0000437 printf("IN tst_flush\n");
438 fflush(stdout);
alaffincc2e5552000-07-27 17:13:18 +0000439#endif
440
subrata_modak88c166c2009-06-09 16:01:20 +0000441 /*
442 * Print out last line if in CONDENSE or NOPASS mode.
443 */
444 if (Buffered == TRUE && (T_mode == CONDENSE || T_mode == NOPASS)) {
445 tst_print(Last_tcid, Last_num, Tst_count - Last_num + 1,
446 Last_type, Last_mesg);
447 Buffered = FALSE;
448 }
449
450 fflush(T_out);
451}
alaffincc2e5552000-07-27 17:13:18 +0000452
453
454/*
455 * tst_print() - Actually print a line or range of lines to the output
456 * stream.
457 */
subrata_modak88c166c2009-06-09 16:01:20 +0000458static void tst_print(char *tcid, int tnum, int trange, int ttype, char *tmesg)
alaffincc2e5552000-07-27 17:13:18 +0000459{
yaberauneya7113a0c2009-12-01 08:57:20 +0000460 /*
461 * avoid unintended side effects from failures with fprintf when
462 * calling write(2), et all.
463 */
464 int err = errno;
vapier9799ea12009-07-20 02:42:32 +0000465 const char *type;
466 int ttype_result = TTYPE_RESULT(ttype);
alaffincc2e5552000-07-27 17:13:18 +0000467
468#if DEBUG
subrata_modak88c166c2009-06-09 16:01:20 +0000469 printf("IN tst_print: tnum = %d, trange = %d, ttype = %d, tmesg = %s\n",
470 tnum, trange, ttype, tmesg);
471 fflush(stdout);
alaffincc2e5552000-07-27 17:13:18 +0000472#endif
473
subrata_modak88c166c2009-06-09 16:01:20 +0000474 /*
475 * Save the test result type by ORing ttype into the current exit value
476 * (used by tst_exit()). This is already done in tst_res(), but is
477 * also done here to catch internal warnings. For internal warnings,
478 * tst_print() is called directly with a case of TWARN.
479 */
vapier9799ea12009-07-20 02:42:32 +0000480 T_exitval |= ttype_result;
alaffincc2e5552000-07-27 17:13:18 +0000481
subrata_modak88c166c2009-06-09 16:01:20 +0000482 /*
483 * If output mode is DISCARD, or if the output mode is NOPASS and this
484 * result is not one of FAIL, BROK, or WARN, just return. This check
485 * is necessary even though we check for DISCARD mode inside of
486 * tst_res(), since occasionally we get to this point without going
487 * through tst_res() (e.g. internal TWARN messages).
488 */
vapier9799ea12009-07-20 02:42:32 +0000489 if (T_mode == DISCARD || (T_mode == NOPASS && ttype_result != TFAIL &&
490 ttype_result != TBROK && ttype_result != TWARN))
subrata_modak88c166c2009-06-09 16:01:20 +0000491 return;
alaffincc2e5552000-07-27 17:13:18 +0000492
subrata_modak88c166c2009-06-09 16:01:20 +0000493 /*
subrata_modak88c166c2009-06-09 16:01:20 +0000494 * Build the result line and print it.
495 */
vapier9799ea12009-07-20 02:42:32 +0000496 type = strttype(ttype);
subrata_modak88c166c2009-06-09 16:01:20 +0000497 if (T_mode == VERBOSE) {
vapier9799ea12009-07-20 02:42:32 +0000498 fprintf(T_out, "%-8s %4d %s : %s", tcid, tnum, type, tmesg);
subrata_modak88c166c2009-06-09 16:01:20 +0000499 } else {
500 if (trange > 1)
vapier9799ea12009-07-20 02:42:32 +0000501 fprintf(T_out, "%-8s %4d-%-4d %s : %s",
subrata_modak88c166c2009-06-09 16:01:20 +0000502 tcid, tnum, tnum + trange - 1, type, tmesg);
503 else
vapier9799ea12009-07-20 02:42:32 +0000504 fprintf(T_out, "%-8s %4d %s : %s",
subrata_modak88c166c2009-06-09 16:01:20 +0000505 tcid, tnum, type, tmesg);
506 }
vapier9799ea12009-07-20 02:42:32 +0000507 if (ttype & TERRNO) {
vapier9799ea12009-07-20 02:42:32 +0000508 fprintf(T_out, ": errno=%s(%i): %s", strerrnodef(err),
509 err, strerror(err));
510 }
yaberauneya7113a0c2009-12-01 08:57:20 +0000511 if (ttype & TTERRNO) {
512 fprintf(T_out, ": TEST_ERRNO=%s(%i): %s",
513 strerrnodef(TEST_ERRNO), (int)TEST_ERRNO,
514 strerror(TEST_ERRNO));
515 }
vapier9799ea12009-07-20 02:42:32 +0000516 fprintf(T_out, "\n");
alaffincc2e5552000-07-27 17:13:18 +0000517
subrata_modak88c166c2009-06-09 16:01:20 +0000518 /*
519 * If tst_res() was called with a file, append file contents to the
520 * end of last printed result.
521 */
522 if (File != NULL)
523 cat_file(File);
524
525 File = NULL;
526}
alaffincc2e5552000-07-27 17:13:18 +0000527
528
529/*
530 * check_env() - Check the value of the environment variable TOUTPUT and
531 * set the global variable T_mode. The TOUTPUT environment
532 * variable should be set to "VERBOSE", "CONDENSE",
533 * "NOPASS", or "DISCARD". If TOUTPUT does not exist or
534 * is not set to a valid value, the default is "VERBOSE".
535 */
subrata_modak88c166c2009-06-09 16:01:20 +0000536static void check_env(void)
alaffincc2e5552000-07-27 17:13:18 +0000537{
subrata_modak88c166c2009-06-09 16:01:20 +0000538 static int first_time = 1;
539 char *value;
alaffincc2e5552000-07-27 17:13:18 +0000540
541#if DEBUG
subrata_modak88c166c2009-06-09 16:01:20 +0000542 printf("IN check_env\n");
543 fflush(stdout);
alaffincc2e5552000-07-27 17:13:18 +0000544#endif
545
subrata_modak88c166c2009-06-09 16:01:20 +0000546 if (!first_time)
547 return;
alaffincc2e5552000-07-27 17:13:18 +0000548
subrata_modak88c166c2009-06-09 16:01:20 +0000549 first_time = 0;
alaffincc2e5552000-07-27 17:13:18 +0000550
subrata_modak88c166c2009-06-09 16:01:20 +0000551 /* TOUTPUT not defined, use default */
552 if ((value = getenv(TOUTPUT)) == NULL) {
553 T_mode = VERBOSE;
554 return;
555 }
alaffincc2e5552000-07-27 17:13:18 +0000556
subrata_modak88c166c2009-06-09 16:01:20 +0000557 if (strcmp(value, TOUT_CONDENSE_S) == 0) {
558 T_mode = CONDENSE;
559 return;
560 }
561
562 if (strcmp(value, TOUT_NOPASS_S) == 0) {
563 T_mode = NOPASS;
564 return;
565 }
566
567 if (strcmp(value, TOUT_DISCARD_S) == 0) {
568 T_mode = DISCARD;
569 return;
570 }
571
572 /* default */
573 T_mode = VERBOSE;
574 return;
575}
alaffincc2e5552000-07-27 17:13:18 +0000576
577
578/*
579 * tst_exit() - Call exit() with the value T_exitval, set up by
580 * tst_res(). T_exitval has a bit set for most of the
581 * result types that were seen (including TPASS, TFAIL,
582 * TBROK, TWARN, TCONF). Also, print the last result (if
583 * necessary) before exiting.
584 */
subrata_modak88c166c2009-06-09 16:01:20 +0000585void tst_exit(void)
alaffincc2e5552000-07-27 17:13:18 +0000586{
587#if DEBUG
subrata_modak88c166c2009-06-09 16:01:20 +0000588 printf("IN tst_exit\n"); fflush(stdout);
589 fflush(stdout);
alaffincc2e5552000-07-27 17:13:18 +0000590#endif
591
subrata_modak88c166c2009-06-09 16:01:20 +0000592 /*
593 * Call tst_flush() flush any ouput in the buffer or the last
594 * result not printed because of CONDENSE mode.
595 */
596 tst_flush();
alaffincc2e5552000-07-27 17:13:18 +0000597
subrata_modak88c166c2009-06-09 16:01:20 +0000598 /*
599 * Mask out TRETR, TINFO, and TCONF results from the exit status.
600 */
601 exit(T_exitval & ~(TRETR | TINFO | TCONF));
602}
alaffincc2e5552000-07-27 17:13:18 +0000603
604
605/*
606 * tst_environ() - Preserve the tst_res() output location, despite any
607 * changes to stdout.
608 */
subrata_modak88c166c2009-06-09 16:01:20 +0000609int tst_environ(void)
alaffincc2e5552000-07-27 17:13:18 +0000610{
subrata_modak88c166c2009-06-09 16:01:20 +0000611 if ((T_out = fdopen(dup(fileno(stdout)), "w")) == NULL)
612 return -1;
613 else
614 return 0;
615}
alaffincc2e5552000-07-27 17:13:18 +0000616
617
618/*
619 * tst_brk() - Fail or break current test case, and break the remaining
620 * tests cases.
621 */
subrata_modak88c166c2009-06-09 16:01:20 +0000622void tst_brk(int ttype, char *fname, void (*func)(void), char *arg_fmt, ...)
alaffincc2e5552000-07-27 17:13:18 +0000623{
subrata_modak88c166c2009-06-09 16:01:20 +0000624 char tmesg[USERMESG];
vapier9799ea12009-07-20 02:42:32 +0000625 int ttype_result = TTYPE_RESULT(ttype);
alaffincc2e5552000-07-27 17:13:18 +0000626
627#if DEBUG
subrata_modak88c166c2009-06-09 16:01:20 +0000628 printf("IN tst_brk\n"); fflush(stdout);
629 fflush(stdout);
alaffincc2e5552000-07-27 17:13:18 +0000630#endif
631
subrata_modak3311a252009-10-13 13:59:29 +0000632 EXPAND_VAR_ARGS(tmesg, arg_fmt, USERMESG);
alaffincc2e5552000-07-27 17:13:18 +0000633
subrata_modak88c166c2009-06-09 16:01:20 +0000634 /*
635 * Only FAIL, BROK, CONF, and RETR are supported by tst_brk().
636 */
vapier9799ea12009-07-20 02:42:32 +0000637 if (ttype_result != TFAIL && ttype_result != TBROK &&
638 ttype_result != TCONF && ttype_result != TRETR) {
subrata_modak88c166c2009-06-09 16:01:20 +0000639 sprintf(Warn_mesg, "tst_brk(): Invalid Type: %d. Using TBROK",
vapier9799ea12009-07-20 02:42:32 +0000640 ttype_result);
subrata_modak88c166c2009-06-09 16:01:20 +0000641 tst_print(TCID, 0, 1, TWARN, Warn_mesg);
642 ttype = TBROK;
643 }
alaffincc2e5552000-07-27 17:13:18 +0000644
subrata_modak88c166c2009-06-09 16:01:20 +0000645 /* Print the first result, if necessary. */
646 if (Tst_count < TST_TOTAL)
647 tst_res(ttype, fname, "%s", tmesg);
alaffincc2e5552000-07-27 17:13:18 +0000648
subrata_modak88c166c2009-06-09 16:01:20 +0000649 /* Determine the number of results left to report. */
650 Tst_range = TST_TOTAL - Tst_count;
alaffincc2e5552000-07-27 17:13:18 +0000651
subrata_modak88c166c2009-06-09 16:01:20 +0000652 /* Print the rest of the results, if necessary. */
653 if (Tst_range > 0) {
654 if (ttype == TCONF) {
655 tst_res(ttype, NULL,
656 "Remaining cases not appropriate for configuration");
657 } else {
658 if ( ttype == TRETR )
659 tst_res(ttype, NULL, "Remaining cases retired");
660 else
661 tst_res(TBROK, NULL, "Remaining cases broken");
662 }
663 } else {
664 Tst_range = 1;
665 Expand_varargs = TRUE;
666 }
alaffincc2e5552000-07-27 17:13:18 +0000667
subrata_modak88c166c2009-06-09 16:01:20 +0000668 /*
669 * If no cleanup function was specified, just return to the caller.
670 * Otherwise call the specified function. If specified function
671 * returns, call tst_exit().
672 */
673 if (func != NULL) {
674 (*func)();
675 tst_exit();
676 }
677}
alaffincc2e5552000-07-27 17:13:18 +0000678
679
680/*
681 * tst_brkloop() - Fail or break current test case, and break the
682 * remaining test cases within test case loop.
683 */
subrata_modak88c166c2009-06-09 16:01:20 +0000684void tst_brkloop(int ttype, char *fname, void (*func)(void), char *arg_fmt, ...)
alaffincc2e5552000-07-27 17:13:18 +0000685{
subrata_modak88c166c2009-06-09 16:01:20 +0000686 char tmesg[USERMESG];
alaffincc2e5552000-07-27 17:13:18 +0000687
688#if DEBUG
subrata_modak88c166c2009-06-09 16:01:20 +0000689 printf("IN tst_brkloop\n"); fflush(stdout);
690 fflush(stdout);
alaffincc2e5552000-07-27 17:13:18 +0000691#endif
692
subrata_modak3311a252009-10-13 13:59:29 +0000693 EXPAND_VAR_ARGS(tmesg, arg_fmt, USERMESG);
alaffincc2e5552000-07-27 17:13:18 +0000694
subrata_modak88c166c2009-06-09 16:01:20 +0000695 if (Tst_lpstart < 0 || Tst_lptotal < 0) {
696 tst_print(TCID, 0, 1, TWARN,
697 "tst_brkloop(): Tst_lpstart & Tst_lptotal must both be assigned non-negative values");
698 Expand_varargs = TRUE;
699 return;
700 }
alaffincc2e5552000-07-27 17:13:18 +0000701
subrata_modak88c166c2009-06-09 16:01:20 +0000702 /*
703 * Only FAIL, BROK, CONF, and RETR are supported by tst_brkloop().
704 */
705 if (ttype != TFAIL && ttype != TBROK && ttype != TCONF &&
706 ttype != TRETR) {
707 sprintf(Warn_mesg,
vapier9799ea12009-07-20 02:42:32 +0000708 "tst_brkloop(): Invalid Type: %d(%s). Using TBROK",
709 ttype, strttype(ttype));
subrata_modak88c166c2009-06-09 16:01:20 +0000710 tst_print(TCID, 0, 1, TWARN, Warn_mesg);
711 ttype = TBROK;
712 }
alaffincc2e5552000-07-27 17:13:18 +0000713
subrata_modak88c166c2009-06-09 16:01:20 +0000714 /* Print the first result, if necessary. */
715 if (Tst_count < Tst_lpstart + Tst_lptotal)
716 tst_res(ttype, fname, "%s", tmesg);
alaffincc2e5552000-07-27 17:13:18 +0000717
subrata_modak88c166c2009-06-09 16:01:20 +0000718 /* Determine the number of results left to report. */
719 Tst_range = Tst_lptotal + Tst_lpstart - Tst_count;
alaffincc2e5552000-07-27 17:13:18 +0000720
subrata_modak88c166c2009-06-09 16:01:20 +0000721 /* Print the rest of the results, if necessary. */
722 if (Tst_range > 0) {
723 if (ttype == TCONF) {
724 tst_res(ttype, NULL,
725 "Remaining cases in loop not appropriate for configuration");
726 } else {
727 if (ttype == TRETR)
728 tst_res(ttype, NULL, "Remaining cases in loop retired");
729 else
730 tst_res(TBROK, NULL, "Remaining cases in loop broken");
731 }
732 } else {
733 Tst_range = 1;
734 Expand_varargs = TRUE;
735 }
alaffincc2e5552000-07-27 17:13:18 +0000736
subrata_modak88c166c2009-06-09 16:01:20 +0000737 /* If a cleanup function was specified, call it. */
738 if (func != NULL)
739 (*func)();
740}
alaffincc2e5552000-07-27 17:13:18 +0000741
742
743/*
744 * tst_resm() - Interface to tst_res(), with no filename.
745 */
subrata_modak88c166c2009-06-09 16:01:20 +0000746void tst_resm(int ttype, char *arg_fmt, ...)
alaffincc2e5552000-07-27 17:13:18 +0000747{
subrata_modak88c166c2009-06-09 16:01:20 +0000748 char tmesg[USERMESG];
alaffincc2e5552000-07-27 17:13:18 +0000749
750#if DEBUG
subrata_modak88c166c2009-06-09 16:01:20 +0000751 printf("IN tst_resm\n"); fflush(stdout);
752 fflush(stdout);
alaffincc2e5552000-07-27 17:13:18 +0000753#endif
754
subrata_modak3311a252009-10-13 13:59:29 +0000755 EXPAND_VAR_ARGS(tmesg, arg_fmt, USERMESG);
alaffincc2e5552000-07-27 17:13:18 +0000756
subrata_modak88c166c2009-06-09 16:01:20 +0000757 tst_res(ttype, NULL, "%s", tmesg);
758}
alaffincc2e5552000-07-27 17:13:18 +0000759
760
761/*
762 * tst_brkm() - Interface to tst_brk(), with no filename.
763 */
subrata_modak88c166c2009-06-09 16:01:20 +0000764void tst_brkm(int ttype, void (*func)(void), char *arg_fmt, ...)
alaffincc2e5552000-07-27 17:13:18 +0000765{
subrata_modak88c166c2009-06-09 16:01:20 +0000766 char tmesg[USERMESG];
alaffincc2e5552000-07-27 17:13:18 +0000767
768#if DEBUG
subrata_modak88c166c2009-06-09 16:01:20 +0000769 printf("IN tst_brkm\n"); fflush(stdout);
770 fflush(stdout);
alaffincc2e5552000-07-27 17:13:18 +0000771#endif
772
subrata_modak3311a252009-10-13 13:59:29 +0000773 EXPAND_VAR_ARGS(tmesg, arg_fmt, USERMESG);
alaffincc2e5552000-07-27 17:13:18 +0000774
vapierf88c09e2009-08-28 10:00:39 +0000775 tst_brk(ttype, NULL, func, "%s", tmesg);
subrata_modak88c166c2009-06-09 16:01:20 +0000776}
alaffincc2e5552000-07-27 17:13:18 +0000777
778
779/*
780 * tst_brkloopm() - Interface to tst_brkloop(), with no filename.
781 */
subrata_modak88c166c2009-06-09 16:01:20 +0000782void tst_brkloopm(int ttype, void (*func)(void), char *arg_fmt, ...)
alaffincc2e5552000-07-27 17:13:18 +0000783{
subrata_modak88c166c2009-06-09 16:01:20 +0000784 char tmesg[USERMESG];
alaffincc2e5552000-07-27 17:13:18 +0000785
786#if DEBUG
subrata_modak88c166c2009-06-09 16:01:20 +0000787 printf("IN tst_brkloopm\n");
788 fflush(stdout);
alaffincc2e5552000-07-27 17:13:18 +0000789#endif
790
subrata_modak3311a252009-10-13 13:59:29 +0000791 EXPAND_VAR_ARGS(tmesg, arg_fmt, USERMESG);
alaffincc2e5552000-07-27 17:13:18 +0000792
vapierf88c09e2009-08-28 10:00:39 +0000793 tst_brkloop(ttype, NULL, func, "%s", tmesg);
subrata_modak88c166c2009-06-09 16:01:20 +0000794}
alaffincc2e5552000-07-27 17:13:18 +0000795
796
797/*
vapier640adf42008-05-06 15:47:54 +0000798 * tst_require_root() - Test for root permissions and abort if not.
799 */
subrata_modak88c166c2009-06-09 16:01:20 +0000800void tst_require_root(void (*func)(void))
vapier640adf42008-05-06 15:47:54 +0000801{
subrata_modak88c166c2009-06-09 16:01:20 +0000802 if (geteuid() != 0)
803 tst_brkm(TCONF, func, "Test needs to be run as root");
vapier640adf42008-05-06 15:47:54 +0000804}
805
806
807/*
alaffincc2e5552000-07-27 17:13:18 +0000808 * cat_file() - Print the contents of a file to standard out.
809 */
subrata_modak88c166c2009-06-09 16:01:20 +0000810static void cat_file(char *filename)
alaffincc2e5552000-07-27 17:13:18 +0000811{
subrata_modak88c166c2009-06-09 16:01:20 +0000812 FILE *fp;
813 int b_read, b_written;
814 char buffer[BUFSIZ];
alaffincc2e5552000-07-27 17:13:18 +0000815
816#if DEBUG
subrata_modak88c166c2009-06-09 16:01:20 +0000817 printf("IN cat_file\n"); fflush(stdout);
alaffincc2e5552000-07-27 17:13:18 +0000818#endif
819
subrata_modak88c166c2009-06-09 16:01:20 +0000820 if ((fp = fopen(filename, "r")) == NULL) {
821 sprintf(Warn_mesg,
822 "tst_res(): fopen(%s, \"r\") failed; errno = %d: %s",
823 filename, errno, strerror(errno));
824 tst_print(TCID, 0, 1, TWARN, Warn_mesg);
825 return;
826 }
alaffincc2e5552000-07-27 17:13:18 +0000827
subrata_modak88c166c2009-06-09 16:01:20 +0000828 errno = 0;
alaffincc2e5552000-07-27 17:13:18 +0000829
subrata_modak88c166c2009-06-09 16:01:20 +0000830 while ((b_read = fread(buffer, 1, BUFSIZ, fp)) != 0) {
831 if ((b_written = fwrite(buffer, 1, b_read, T_out)) != b_read) {
832 sprintf(Warn_mesg,
833 "tst_res(): While trying to cat \"%s\", fwrite() wrote only %d of %d bytes",
834 filename, b_written, b_read);
835 tst_print(TCID, 0, 1, TWARN, Warn_mesg);
836 break;
837 }
838 }
alaffincc2e5552000-07-27 17:13:18 +0000839
subrata_modak88c166c2009-06-09 16:01:20 +0000840 if (!feof(fp)) {
841 sprintf(Warn_mesg,
842 "tst_res(): While trying to cat \"%s\", fread() failed, errno = %d: %s",
843 filename, errno, strerror(errno));
844 tst_print(TCID, 0, 1, TWARN, Warn_mesg);
845 }
alaffincc2e5552000-07-27 17:13:18 +0000846
subrata_modak88c166c2009-06-09 16:01:20 +0000847 if (fclose(fp) != 0) {
848 sprintf(Warn_mesg,
849 "tst_res(): While trying to cat \"%s\", fclose() failed, errno = %d: %s",
850 filename, errno, strerror(errno));
851 tst_print(TCID, 0, 1, TWARN, Warn_mesg);
852 }
853}
alaffincc2e5552000-07-27 17:13:18 +0000854
855
856#ifdef UNIT_TEST
857/****************************************************************************
858 * Unit test code: Takes input from stdin and can make the following
859 * calls: tst_res(), tst_resm(), tst_brk(), tst_brkm(),
860 * tst_flush_buf(), tst_exit().
861 ****************************************************************************/
862int TST_TOTAL = 10;
863char *TCID = "TESTTCID";
864
865#define RES "tst_res.c UNIT TEST message; ttype = %d; contents of \"%s\":"
866#define RESM "tst_res.c UNIT TEST message; ttype = %d"
867
subrata_modak88c166c2009-06-09 16:01:20 +0000868int main(void)
alaffincc2e5552000-07-27 17:13:18 +0000869{
subrata_modak88c166c2009-06-09 16:01:20 +0000870 int ttype;
871 int range;
subrata_modak88c166c2009-06-09 16:01:20 +0000872 char chr;
873 char fname[MAXMESG];
alaffincc2e5552000-07-27 17:13:18 +0000874
subrata_modak88c166c2009-06-09 16:01:20 +0000875 printf("UNIT TEST of tst_res.c. Options for ttype:\n\
876 -1 : call tst_exit()\n\
877 -2 : call tst_flush()\n\
878 -3 : call tst_brk()\n\
879 -4 : call tst_brkloop()\n\
880 -5 : call tst_res() with a range\n\
vapier9799ea12009-07-20 02:42:32 +0000881 %2i : call tst_res(TPASS, ...)\n\
882 %2i : call tst_res(TFAIL, ...)\n\
883 %2i : call tst_res(TBROK, ...)\n\
884 %2i : call tst_res(TWARN, ...)\n\
885 %2i : call tst_res(TRETR, ...)\n\
886 %2i : call tst_res(TINFO, ...)\n\
887 %2i : call tst_res(TCONF, ...)\n\n",
888 TPASS, TFAIL, TBROK, TWARN, TRETR, TINFO, TCONF);
alaffincc2e5552000-07-27 17:13:18 +0000889
subrata_modak88c166c2009-06-09 16:01:20 +0000890 while (1) {
vapier9799ea12009-07-20 02:42:32 +0000891 printf("Enter ttype (-5,-4,-3,-2,-1,%i,%i,%i,%i,%i,%i,%i): ",
892 TPASS, TFAIL, TBROK, TWARN, TRETR, TINFO, TCONF);
subrata_modak88c166c2009-06-09 16:01:20 +0000893 scanf("%d%c", &ttype, &chr);
alaffincc2e5552000-07-27 17:13:18 +0000894
subrata_modak88c166c2009-06-09 16:01:20 +0000895 switch (ttype) {
896 case -1:
897 tst_exit();
898 break;
alaffincc2e5552000-07-27 17:13:18 +0000899
subrata_modak88c166c2009-06-09 16:01:20 +0000900 case -2:
901 tst_flush();
902 break;
alaffincc2e5552000-07-27 17:13:18 +0000903
subrata_modak88c166c2009-06-09 16:01:20 +0000904 case -3:
vapier9799ea12009-07-20 02:42:32 +0000905 printf("Enter the current type (%i=FAIL, %i=BROK, %i=RETR, %i=CONF): ",
906 TFAIL, TBROK, TRETR, TCONF);
subrata_modak88c166c2009-06-09 16:01:20 +0000907 scanf("%d%c", &ttype, &chr);
908 printf("Enter file name (<cr> for none): ");
909 gets(fname);
910 if (strcmp(fname, "") == 0)
911 tst_brkm(ttype, tst_exit, RESM, ttype);
912 else
913 tst_brk(ttype, fname, tst_exit, RES, ttype, fname);
914 break;
alaffincc2e5552000-07-27 17:13:18 +0000915
subrata_modak88c166c2009-06-09 16:01:20 +0000916 case -4:
917 printf("Enter the size of the loop: ");
918 scanf("%d%c", &range, &chr);
919 Tst_lpstart = Tst_count;
920 Tst_lptotal = range;
vapier9799ea12009-07-20 02:42:32 +0000921 printf("Enter the current type (%i=FAIL, %i=BROK, %i=RETR, %i=CONF): ",
922 TFAIL, TBROK, TRETR, TCONF);
subrata_modak88c166c2009-06-09 16:01:20 +0000923 scanf("%d%c", &ttype, &chr);
924 printf("Enter file name (<cr> for none): ");
925 gets(fname);
alaffincc2e5552000-07-27 17:13:18 +0000926
subrata_modak88c166c2009-06-09 16:01:20 +0000927 if (strcmp(fname, "") == 0)
928 tst_brkloopm(ttype, NULL, RESM, ttype);
929 else
930 tst_brkloop(ttype, fname, NULL, RES, ttype, fname);
931 break;
alaffincc2e5552000-07-27 17:13:18 +0000932
subrata_modak88c166c2009-06-09 16:01:20 +0000933 case -5:
934 printf("Enter the size of the range: ");
935 scanf("%d%c", &Tst_range, &chr);
vapier9799ea12009-07-20 02:42:32 +0000936 printf("Enter the current type (%i,%i,%i,%i,%i,%i,%i): ",
937 TPASS, TFAIL, TBROK, TWARN, TRETR, TINFO, TCONF);
subrata_modak88c166c2009-06-09 16:01:20 +0000938 scanf("%d%c", &ttype, &chr);
939 default:
940 printf("Enter file name (<cr> for none): ");
941 gets(fname);
alaffincc2e5552000-07-27 17:13:18 +0000942
subrata_modak88c166c2009-06-09 16:01:20 +0000943 if (strcmp(fname, "") == 0)
944 tst_resm(ttype, RESM, ttype);
945 else
946 tst_res(ttype, fname, RES, ttype, fname);
947 break;
948 }
949
950 }
alaffincc2e5552000-07-27 17:13:18 +0000951}
subrata_modak88c166c2009-06-09 16:01:20 +0000952
953#endif /* UNIT_TEST */