Fix the creation of the dumpdir directory in stress_floppy Makefile
[ltp-debian.git] / lib / tst_res.c
blob5eaab6c30a642c2687c29570f9b174e6427df487
1 /*
2 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
3 * Copyright (c) 2009 Cyril Hrubis chrubis@suse.cz
5 * 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.
9 * 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.
13 * 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.
20 * 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.
24 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
25 * Mountain View, CA 94043, or:
27 * http://www.sgi.com
29 * For further information regarding this notice, see:
31 * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
35 /* $Id: tst_res.c,v 1.14 2009/12/01 08:57:20 yaberauneya Exp $ */
37 /**********************************************************
39 * OS Testing - Silicon Graphics, Inc.
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
57 * FUNCTION TITLE : Standard automated test result reporting mechanism
59 * SYNOPSIS:
60 * #include "test.h"
62 * void tst_res(ttype, fname, tmesg [,arg]...)
63 * int ttype;
64 * char *fname;
65 * char *tmesg;
67 * void tst_resm(ttype, tmesg [,arg]...)
68 * int ttype;
69 * char *tmesg;
71 * void tst_brk(ttype, fname, cleanup, tmesg, [,argv]...)
72 * int ttype;
73 * char *fname;
74 * void (*cleanup)();
75 * char *tmesg;
77 * void tst_brkm(ttype, cleanup, tmesg [,arg]...)
78 * int ttype;
79 * void (*cleanup)();
80 * char *tmesg;
82 * void tst_brkloop(ttype, fname, cleanup, char *tmesg, [,argv]...)
83 * int ttype;
84 * char *fname;
85 * void (*cleanup)();
86 * char *tmesg;
88 * void tst_brkloopm(ttype, cleanup, tmesg [,arg]...)
89 * int ttype;
90 * void (*cleanup)();
91 * char *tmesg;
93 * void tst_flush()
95 * void tst_exit()
97 * int tst_environ()
99 * AUTHOR : Kent Rogers (from Dave Fenner's original)
101 * CO-PILOT : Rich Logan
103 * DATE STARTED : 05/01/90 (rewritten 1/96)
105 * MAJOR CLEANUPS BY : Cyril Hrubis
107 * DESCRIPTION
108 * See the man page(s).
110 *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/
111 #include <errno.h>
112 #include <string.h>
113 #include <stdio.h>
114 #include <stdlib.h>
115 #include <stdarg.h>
116 #include <unistd.h>
117 #include "test.h"
118 #include "usctest.h"
120 #define VERBOSE 1 /* flag values for the T_mode variable */
121 #define CONDENSE 2
122 #define NOPASS 3
123 #define DISCARD 4
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
130 #undef tst_brk
131 #undef tst_brkm
134 * EXPAND_VAR_ARGS - Expand the variable portion (arg_fmt) of a result
135 * message into the specified string.
137 #define EXPAND_VAR_ARGS(buf, arg_fmt, buf_len) { \
138 va_list ap; \
140 if (arg_fmt != NULL) { \
141 if (Expand_varargs) { \
142 va_start(ap, arg_fmt); \
143 vsnprintf(buf, buf_len, arg_fmt, ap); \
144 va_end(ap); \
145 } else \
146 strncpy(buf, arg_fmt, buf_len); \
147 } else \
148 buf[0] = '\0'; \
152 * Define local function prototypes.
154 static void check_env(void);
155 static void tst_condense(int tnum, int ttype, char *tmesg);
156 static void tst_print(char *tcid, int tnum, int trange, int ttype, char *tmesg);
157 static void cat_file(char *filename);
161 * Define some static/global variables.
163 static FILE *T_out = NULL; /* tst_res() output file descriptor */
164 static char *File; /* file whose contents is part of result */
165 static int T_exitval = 0; /* exit value used by tst_exit() */
166 static int T_mode = VERBOSE; /* flag indicating print mode: VERBOSE, */
167 /* CONDENSE, NOPASS, DISCARD */
169 static int Expand_varargs = TRUE; /* if TRUE, expand varargs stuff */
170 static char Warn_mesg[MAXMESG]; /* holds warning messages */
173 * These are used for condensing output when NOT in verbose mode.
175 static int Buffered = FALSE; /* TRUE if condensed output is currently */
176 /* buffered (i.e. not yet printed) */
177 static char *Last_tcid; /* previous test case id */
178 static int Last_num; /* previous test case number */
179 static int Last_type; /* previous test result type */
180 static char *Last_mesg; /* previous test result message */
184 * These globals may be externed by the test.
186 int Tst_count = 0; /* current count of test cases executed; NOTE: */
187 /* Tst_count may be externed by other programs */
188 int Tst_lptotal = 0; /* tst_brkloop() external */
189 int Tst_lpstart = 0; /* tst_brkloop() external */
190 int Tst_range = 1; /* for specifying multiple results */
191 int Tst_nobuf = 1; /* this is a no-op; buffering is never done, but */
192 /* this will stay for compatibility reasons */
195 * These globals must be defined in the test.
197 extern char *TCID; /* Test case identifier from the test source */
198 extern int TST_TOTAL; /* Total number of test cases from the test */
199 /* source */
202 * This global is used by the temp. dir. maintenance functions,
203 * tst_tmpdir()/tst_rmdir(), tst_wildcard()/tst_tr_rmdir(). It is the
204 * name of the directory created (if any). It is defined here, so that
205 * it only has to be declared once and can then be referenced from more
206 * than one module. Also, since the temp. dir. maintenance functions
207 * rely on the tst_res.c package this seemed like a reasonable place.
209 char *TESTDIR = NULL;
211 struct pair {
212 const char *name;
213 int val;
215 #define PAIR(def) [def] = { .name = #def, .val = def, },
216 const char *pair_lookup(struct pair *pair, int pair_size, int idx)
218 if (idx < 0 || idx >= pair_size || pair[idx].name == NULL)
219 return "???";
220 return pair[idx].name;
222 #define pair_lookup(pair, idx) pair_lookup(pair, ARRAY_SIZE(pair), idx)
225 * strttype() - convert a type result to the human readable string
227 const char *strttype(int ttype)
229 struct pair ttype_pairs[] = {
230 PAIR(TPASS)
231 PAIR(TFAIL)
232 PAIR(TBROK)
233 PAIR(TRETR)
234 PAIR(TCONF)
235 PAIR(TWARN)
236 PAIR(TINFO)
238 return pair_lookup(ttype_pairs, TTYPE_RESULT(ttype));
242 * strerrnodef() - convert an errno value to its C define
244 static const char *strerrnodef(int err)
246 struct pair errno_pairs[] = {
247 PAIR(EPERM)
248 PAIR(ENOENT)
249 PAIR(ESRCH)
250 PAIR(EINTR)
251 PAIR(EIO)
252 PAIR(ENXIO)
253 PAIR(E2BIG)
254 PAIR(ENOEXEC)
255 PAIR(EBADF)
256 PAIR(ECHILD)
257 PAIR(EAGAIN)
258 PAIR(ENOMEM)
259 PAIR(EACCES)
260 PAIR(EFAULT)
261 PAIR(ENOTBLK)
262 PAIR(EBUSY)
263 PAIR(EEXIST)
264 PAIR(EXDEV)
265 PAIR(ENODEV)
266 PAIR(ENOTDIR)
267 PAIR(EISDIR)
268 PAIR(EINVAL)
269 PAIR(ENFILE)
270 PAIR(EMFILE)
271 PAIR(ENOTTY)
272 PAIR(ETXTBSY)
273 PAIR(EFBIG)
274 PAIR(ENOSPC)
275 PAIR(ESPIPE)
276 PAIR(EROFS)
277 PAIR(EMLINK)
278 PAIR(EPIPE)
279 PAIR(EDOM)
280 PAIR(ERANGE)
281 PAIR(ENAMETOOLONG)
283 return pair_lookup(errno_pairs, err);
287 * tst_res() - Main result reporting function. Handle test information
288 * appropriately depending on output display mode. Call
289 * tst_condense() or tst_print() to actually print results.
290 * All result functions (tst_resm(), tst_brk(), etc.)
291 * eventually get here to print the results.
293 void tst_res(int ttype, char *fname, char *arg_fmt, ...)
295 int i;
296 char tmesg[USERMESG];
297 int ttype_result = TTYPE_RESULT(ttype);
299 #if DEBUG
300 printf("IN tst_res; Tst_count = %d; Tst_range = %d\n",
301 Tst_count, Tst_range); fflush(stdout);
302 #endif
304 EXPAND_VAR_ARGS(tmesg, arg_fmt, USERMESG);
307 * Save the test result type by ORing ttype into the current exit
308 * value (used by tst_exit()).
310 T_exitval |= ttype_result;
313 * Unless T_out has already been set by tst_environ(), make tst_res()
314 * output go to standard output.
316 if (T_out == NULL)
317 T_out = stdout;
320 * Check TOUTPUT environment variable (if first time) and set T_mode
321 * flag.
323 check_env();
325 if (Tst_range <= 0) {
326 Tst_range = 1;
327 tst_print(TCID, 0, 1, TWARN,
328 "tst_res(): Tst_range must be positive");
331 if (fname != NULL && access(fname, F_OK) == 0)
332 File = fname;
335 * Set the test case number and print the results, depending on the
336 * display type.
338 if (ttype_result == TWARN || ttype_result == TINFO) {
339 if (Tst_range > 1)
340 tst_print(TCID, 0, 1, TWARN,
341 "tst_res(): Range not valid for TINFO or TWARN types");
342 tst_print(TCID, 0, 1, ttype, tmesg);
343 } else {
344 if (Tst_count < 0)
345 tst_print(TCID, 0, 1, TWARN,
346 "tst_res(): Tst_count < 0 is not valid");
349 * Process each display type.
351 switch (T_mode) {
352 case DISCARD: /* do not print any results */
353 break;
355 case NOPASS: /* passing result types are filtered by tst_print() */
356 case CONDENSE:
357 tst_condense(Tst_count + 1, ttype, tmesg);
358 break;
360 default: /* VERBOSE */
361 for (i = 1 ; i <= Tst_range ; i++)
362 tst_print(TCID, Tst_count + i, Tst_range, ttype, tmesg);
363 break;
366 Tst_count += Tst_range;
369 Tst_range = 1;
370 Expand_varargs = TRUE;
375 * tst_condense() - Handle test cases in CONDENSE or NOPASS mode (i.e.
376 * buffer the current result and print the last result
377 * if different than the current). If a file was
378 * specified, print the current result and do not
379 * buffer it.
381 static void tst_condense(int tnum, int ttype, char *tmesg)
383 char *file;
384 int ttype_result = TTYPE_RESULT(ttype);
386 #if DEBUG
387 printf("IN tst_condense: tcid = %s, tnum = %d, ttype = %d, tmesg = %s\n",
388 TCID, tnum, ttype, tmesg);
389 fflush(stdout);
390 #endif
393 * If this result is the same as the previous result, return.
395 if (Buffered == TRUE) {
396 if (strcmp(Last_tcid, TCID) == 0 && Last_type == ttype_result &&
397 strcmp(Last_mesg, tmesg) == 0 && File == NULL )
398 return;
401 * This result is different from the previous result. First,
402 * print the previous result.
404 file = File;
405 File = NULL;
406 tst_print(Last_tcid, Last_num, tnum - Last_num, Last_type,
407 Last_mesg);
408 free(Last_tcid);
409 free(Last_mesg);
410 File = file;
414 * If a file was specified, print the current result since we have no
415 * way of retaining the file contents for comparing with future
416 * results. Otherwise, buffer the current result info for next time.
418 if (File != NULL) {
419 tst_print(TCID, tnum, Tst_range, ttype, tmesg);
420 Buffered = FALSE;
421 } else {
422 Last_tcid = (char *)malloc(strlen(TCID) + 1);
423 strcpy(Last_tcid, TCID);
424 Last_num = tnum;
425 Last_type = ttype_result;
426 Last_mesg = (char *)malloc(strlen(tmesg) + 1);
427 strcpy(Last_mesg, tmesg);
428 Buffered = TRUE;
434 * tst_flush() - Print any messages pending because of CONDENSE mode,
435 * and flush T_out.
437 void tst_flush(void)
439 #if DEBUG
440 printf("IN tst_flush\n");
441 fflush(stdout);
442 #endif
445 * Print out last line if in CONDENSE or NOPASS mode.
447 if (Buffered == TRUE && (T_mode == CONDENSE || T_mode == NOPASS)) {
448 tst_print(Last_tcid, Last_num, Tst_count - Last_num + 1,
449 Last_type, Last_mesg);
450 Buffered = FALSE;
453 fflush(T_out);
458 * tst_print() - Actually print a line or range of lines to the output
459 * stream.
461 static void tst_print(char *tcid, int tnum, int trange, int ttype, char *tmesg)
464 * avoid unintended side effects from failures with fprintf when
465 * calling write(2), et all.
467 int err = errno;
468 const char *type;
469 int ttype_result = TTYPE_RESULT(ttype);
471 #if DEBUG
472 printf("IN tst_print: tnum = %d, trange = %d, ttype = %d, tmesg = %s\n",
473 tnum, trange, ttype, tmesg);
474 fflush(stdout);
475 #endif
478 * Save the test result type by ORing ttype into the current exit value
479 * (used by tst_exit()). This is already done in tst_res(), but is
480 * also done here to catch internal warnings. For internal warnings,
481 * tst_print() is called directly with a case of TWARN.
483 T_exitval |= ttype_result;
486 * If output mode is DISCARD, or if the output mode is NOPASS and this
487 * result is not one of FAIL, BROK, or WARN, just return. This check
488 * is necessary even though we check for DISCARD mode inside of
489 * tst_res(), since occasionally we get to this point without going
490 * through tst_res() (e.g. internal TWARN messages).
492 if (T_mode == DISCARD || (T_mode == NOPASS && ttype_result != TFAIL &&
493 ttype_result != TBROK && ttype_result != TWARN))
494 return;
497 * Build the result line and print it.
499 type = strttype(ttype);
500 if (T_mode == VERBOSE) {
501 fprintf(T_out, "%-8s %4d %s : %s", tcid, tnum, type, tmesg);
502 } else {
503 if (trange > 1)
504 fprintf(T_out, "%-8s %4d-%-4d %s : %s",
505 tcid, tnum, tnum + trange - 1, type, tmesg);
506 else
507 fprintf(T_out, "%-8s %4d %s : %s",
508 tcid, tnum, type, tmesg);
510 if (ttype & TERRNO) {
511 fprintf(T_out, ": errno=%s(%i): %s", strerrnodef(err),
512 err, strerror(err));
514 if (ttype & TTERRNO) {
515 fprintf(T_out, ": TEST_ERRNO=%s(%i): %s",
516 strerrnodef(TEST_ERRNO), (int)TEST_ERRNO,
517 strerror(TEST_ERRNO));
519 fprintf(T_out, "\n");
522 * If tst_res() was called with a file, append file contents to the
523 * end of last printed result.
525 if (File != NULL)
526 cat_file(File);
528 File = NULL;
533 * check_env() - Check the value of the environment variable TOUTPUT and
534 * set the global variable T_mode. The TOUTPUT environment
535 * variable should be set to "VERBOSE", "CONDENSE",
536 * "NOPASS", or "DISCARD". If TOUTPUT does not exist or
537 * is not set to a valid value, the default is "VERBOSE".
539 static void check_env(void)
541 static int first_time = 1;
542 char *value;
544 #if DEBUG
545 printf("IN check_env\n");
546 fflush(stdout);
547 #endif
549 if (!first_time)
550 return;
552 first_time = 0;
554 /* TOUTPUT not defined, use default */
555 if ((value = getenv(TOUTPUT)) == NULL) {
556 T_mode = VERBOSE;
557 return;
560 if (strcmp(value, TOUT_CONDENSE_S) == 0) {
561 T_mode = CONDENSE;
562 return;
565 if (strcmp(value, TOUT_NOPASS_S) == 0) {
566 T_mode = NOPASS;
567 return;
570 if (strcmp(value, TOUT_DISCARD_S) == 0) {
571 T_mode = DISCARD;
572 return;
575 /* default */
576 T_mode = VERBOSE;
577 return;
582 * tst_exit() - Call exit() with the value T_exitval, set up by
583 * tst_res(). T_exitval has a bit set for most of the
584 * result types that were seen (including TPASS, TFAIL,
585 * TBROK, TWARN, TCONF). Also, print the last result (if
586 * necessary) before exiting.
588 void tst_exit(void)
590 #if DEBUG
591 printf("IN tst_exit\n"); fflush(stdout);
592 fflush(stdout);
593 #endif
596 * Call tst_flush() flush any ouput in the buffer or the last
597 * result not printed because of CONDENSE mode.
599 tst_flush();
602 * Mask out TRETR, TINFO, and TCONF results from the exit status.
604 exit(T_exitval & ~(TRETR | TINFO | TCONF));
609 * tst_environ() - Preserve the tst_res() output location, despite any
610 * changes to stdout.
612 int tst_environ(void)
614 if ((T_out = fdopen(dup(fileno(stdout)), "w")) == NULL)
615 return -1;
616 else
617 return 0;
622 * tst_brk() - Fail or break current test case, and break the remaining
623 * tests cases.
625 void tst_brk(int ttype, char *fname, void (*func)(void), char *arg_fmt, ...)
627 char tmesg[USERMESG];
628 int ttype_result = TTYPE_RESULT(ttype);
630 #if DEBUG
631 printf("IN tst_brk\n"); fflush(stdout);
632 fflush(stdout);
633 #endif
635 EXPAND_VAR_ARGS(tmesg, arg_fmt, USERMESG);
638 * Only FAIL, BROK, CONF, and RETR are supported by tst_brk().
640 if (ttype_result != TFAIL && ttype_result != TBROK &&
641 ttype_result != TCONF && ttype_result != TRETR) {
642 sprintf(Warn_mesg, "tst_brk(): Invalid Type: %d. Using TBROK",
643 ttype_result);
644 tst_print(TCID, 0, 1, TWARN, Warn_mesg);
645 ttype = TBROK;
648 /* Print the first result, if necessary. */
649 if (Tst_count < TST_TOTAL)
650 tst_res(ttype, fname, "%s", tmesg);
652 /* Determine the number of results left to report. */
653 Tst_range = TST_TOTAL - Tst_count;
655 /* Print the rest of the results, if necessary. */
656 if (Tst_range > 0) {
657 if (ttype == TCONF) {
658 tst_res(ttype, NULL,
659 "Remaining cases not appropriate for configuration");
660 } else {
661 if ( ttype == TRETR )
662 tst_res(ttype, NULL, "Remaining cases retired");
663 else
664 tst_res(TBROK, NULL, "Remaining cases broken");
666 } else {
667 Tst_range = 1;
668 Expand_varargs = TRUE;
672 * If no cleanup function was specified, just return to the caller.
673 * Otherwise call the specified function. If specified function
674 * returns, call tst_exit().
676 if (func != NULL) {
677 (*func)();
678 tst_exit();
684 * tst_brkloop() - Fail or break current test case, and break the
685 * remaining test cases within test case loop.
687 void tst_brkloop(int ttype, char *fname, void (*func)(void), char *arg_fmt, ...)
689 char tmesg[USERMESG];
691 #if DEBUG
692 printf("IN tst_brkloop\n"); fflush(stdout);
693 fflush(stdout);
694 #endif
696 EXPAND_VAR_ARGS(tmesg, arg_fmt, USERMESG);
698 if (Tst_lpstart < 0 || Tst_lptotal < 0) {
699 tst_print(TCID, 0, 1, TWARN,
700 "tst_brkloop(): Tst_lpstart & Tst_lptotal must both be assigned non-negative values");
701 Expand_varargs = TRUE;
702 return;
706 * Only FAIL, BROK, CONF, and RETR are supported by tst_brkloop().
708 if (ttype != TFAIL && ttype != TBROK && ttype != TCONF &&
709 ttype != TRETR) {
710 sprintf(Warn_mesg,
711 "tst_brkloop(): Invalid Type: %d(%s). Using TBROK",
712 ttype, strttype(ttype));
713 tst_print(TCID, 0, 1, TWARN, Warn_mesg);
714 ttype = TBROK;
717 /* Print the first result. */
718 tst_res(ttype, fname, "%s", tmesg);
720 /* Determine the number of results left to report. */
721 Tst_range = Tst_lptotal + Tst_lpstart - Tst_count;
723 /* Print the rest of the results, if necessary. */
724 if (Tst_range > 0) {
725 if (ttype == TCONF) {
726 tst_res(ttype, NULL,
727 "Remaining cases in loop not appropriate for configuration");
728 } else {
729 if (ttype == TRETR)
730 tst_res(ttype, NULL, "Remaining cases in loop retired");
731 else
732 tst_res(TBROK, NULL, "Remaining cases in loop broken");
734 } else {
735 Tst_range = 1;
736 Expand_varargs = TRUE;
739 /* If a cleanup function was specified, call it. */
740 if (func != NULL)
741 (*func)();
746 * tst_resm() - Interface to tst_res(), with no filename.
748 void tst_resm(int ttype, char *arg_fmt, ...)
750 char tmesg[USERMESG];
752 #if DEBUG
753 printf("IN tst_resm\n"); fflush(stdout);
754 fflush(stdout);
755 #endif
757 EXPAND_VAR_ARGS(tmesg, arg_fmt, USERMESG);
759 tst_res(ttype, NULL, "%s", tmesg);
764 * tst_brkm() - Interface to tst_brk(), with no filename.
766 void tst_brkm(int ttype, void (*func)(void), char *arg_fmt, ...)
768 char tmesg[USERMESG];
770 #if DEBUG
771 printf("IN tst_brkm\n"); fflush(stdout);
772 fflush(stdout);
773 #endif
775 EXPAND_VAR_ARGS(tmesg, arg_fmt, USERMESG);
777 tst_brk(ttype, NULL, func, "%s", tmesg);
782 * tst_brkloopm() - Interface to tst_brkloop(), with no filename.
784 void tst_brkloopm(int ttype, void (*func)(void), char *arg_fmt, ...)
786 char tmesg[USERMESG];
788 #if DEBUG
789 printf("IN tst_brkloopm\n");
790 fflush(stdout);
791 #endif
793 EXPAND_VAR_ARGS(tmesg, arg_fmt, USERMESG);
795 tst_brkloop(ttype, NULL, func, "%s", tmesg);
800 * tst_require_root() - Test for root permissions and abort if not.
802 void tst_require_root(void (*func)(void))
804 if (geteuid() != 0)
805 tst_brkm(TCONF, func, "Test needs to be run as root");
810 * cat_file() - Print the contents of a file to standard out.
812 static void cat_file(char *filename)
814 FILE *fp;
815 int b_read, b_written;
816 char buffer[BUFSIZ];
818 #if DEBUG
819 printf("IN cat_file\n"); fflush(stdout);
820 #endif
822 if ((fp = fopen(filename, "r")) == NULL) {
823 sprintf(Warn_mesg,
824 "tst_res(): fopen(%s, \"r\") failed; errno = %d: %s",
825 filename, errno, strerror(errno));
826 tst_print(TCID, 0, 1, TWARN, Warn_mesg);
827 return;
830 errno = 0;
832 while ((b_read = fread(buffer, 1, BUFSIZ, fp)) != 0) {
833 if ((b_written = fwrite(buffer, 1, b_read, T_out)) != b_read) {
834 sprintf(Warn_mesg,
835 "tst_res(): While trying to cat \"%s\", fwrite() wrote only %d of %d bytes",
836 filename, b_written, b_read);
837 tst_print(TCID, 0, 1, TWARN, Warn_mesg);
838 break;
842 if (!feof(fp)) {
843 sprintf(Warn_mesg,
844 "tst_res(): While trying to cat \"%s\", fread() failed, errno = %d: %s",
845 filename, errno, strerror(errno));
846 tst_print(TCID, 0, 1, TWARN, Warn_mesg);
849 if (fclose(fp) != 0) {
850 sprintf(Warn_mesg,
851 "tst_res(): While trying to cat \"%s\", fclose() failed, errno = %d: %s",
852 filename, errno, strerror(errno));
853 tst_print(TCID, 0, 1, TWARN, Warn_mesg);
858 #ifdef UNIT_TEST
859 /****************************************************************************
860 * Unit test code: Takes input from stdin and can make the following
861 * calls: tst_res(), tst_resm(), tst_brk(), tst_brkm(),
862 * tst_flush_buf(), tst_exit().
863 ****************************************************************************/
864 int TST_TOTAL = 10;
865 char *TCID = "TESTTCID";
867 #define RES "tst_res.c UNIT TEST message; ttype = %d; contents of \"%s\":"
868 #define RESM "tst_res.c UNIT TEST message; ttype = %d"
870 int main(void)
872 int ttype;
873 int range;
874 char chr;
875 char fname[MAXMESG];
877 printf("UNIT TEST of tst_res.c. Options for ttype:\n\
878 -1 : call tst_exit()\n\
879 -2 : call tst_flush()\n\
880 -3 : call tst_brk()\n\
881 -4 : call tst_brkloop()\n\
882 -5 : call tst_res() with a range\n\
883 %2i : call tst_res(TPASS, ...)\n\
884 %2i : call tst_res(TFAIL, ...)\n\
885 %2i : call tst_res(TBROK, ...)\n\
886 %2i : call tst_res(TWARN, ...)\n\
887 %2i : call tst_res(TRETR, ...)\n\
888 %2i : call tst_res(TINFO, ...)\n\
889 %2i : call tst_res(TCONF, ...)\n\n",
890 TPASS, TFAIL, TBROK, TWARN, TRETR, TINFO, TCONF);
892 while (1) {
893 printf("Enter ttype (-5,-4,-3,-2,-1,%i,%i,%i,%i,%i,%i,%i): ",
894 TPASS, TFAIL, TBROK, TWARN, TRETR, TINFO, TCONF);
895 scanf("%d%c", &ttype, &chr);
897 switch (ttype) {
898 case -1:
899 tst_exit();
900 break;
902 case -2:
903 tst_flush();
904 break;
906 case -3:
907 printf("Enter the current type (%i=FAIL, %i=BROK, %i=RETR, %i=CONF): ",
908 TFAIL, TBROK, TRETR, TCONF);
909 scanf("%d%c", &ttype, &chr);
910 printf("Enter file name (<cr> for none): ");
911 gets(fname);
912 if (strcmp(fname, "") == 0)
913 tst_brkm(ttype, tst_exit, RESM, ttype);
914 else
915 tst_brk(ttype, fname, tst_exit, RES, ttype, fname);
916 break;
918 case -4:
919 printf("Enter the size of the loop: ");
920 scanf("%d%c", &range, &chr);
921 Tst_lpstart = Tst_count;
922 Tst_lptotal = range;
923 printf("Enter the current type (%i=FAIL, %i=BROK, %i=RETR, %i=CONF): ",
924 TFAIL, TBROK, TRETR, TCONF);
925 scanf("%d%c", &ttype, &chr);
926 printf("Enter file name (<cr> for none): ");
927 gets(fname);
929 if (strcmp(fname, "") == 0)
930 tst_brkloopm(ttype, NULL, RESM, ttype);
931 else
932 tst_brkloop(ttype, fname, NULL, RES, ttype, fname);
933 break;
935 case -5:
936 printf("Enter the size of the range: ");
937 scanf("%d%c", &Tst_range, &chr);
938 printf("Enter the current type (%i,%i,%i,%i,%i,%i,%i): ",
939 TPASS, TFAIL, TBROK, TWARN, TRETR, TINFO, TCONF);
940 scanf("%d%c", &ttype, &chr);
941 default:
942 printf("Enter file name (<cr> for none): ");
943 gets(fname);
945 if (strcmp(fname, "") == 0)
946 tst_resm(ttype, RESM, ttype);
947 else
948 tst_res(ttype, fname, RES, ttype, fname);
949 break;
955 #endif /* UNIT_TEST */