Home | History | Annotate | Download | only in apicmds
      1 /*
      2  * Copyright (c) International Business Machines  Corp., 2001
      3  *
      4  * This program is free software;  you can redistribute it and/or modify
      5  * it under the terms of the GNU General Public License as published by
      6  * the Free Software Foundation; either version 2 of the License, or
      7  * (at your option) any later version.
      8  *
      9  * This program is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY;  without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
     12  * the GNU General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU General Public License
     15  * along with this program;  if not, write to the Free Software
     16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     17  *
     18  */
     19 
     20 /*
     21  * File:        ltpapicmd.c
     22  *
     23  * Description: This program impliments a command line version of some of the
     24  *              LTP harness API's. This will enable tests written in shell and
     25  *              other scripts to report problems and log results in the LTP
     26  *              harness format. The intent is to have a common format in which
     27  *              the C tests and tests written in scripts report results in
     28  *              a common format.
     29  *
     30  *              The following LTP API's are available currently in command line
     31  *              form:
     32  *              tst_brk   - Print result message and break remaining test cases
     33  *              tst_brkm  - Print result message, including file contents, and
     34  *                          break remaining test cases
     35  *              tst_res   - Print result message, including file contents
     36  *              tst_resm  - Print result message
     37  *              tst_flush - Print any messages pending because of CONDENSE mode,
     38  *                          and flush output stream
     39  *              tst_exit  - Exit test with a meaningful exit value
     40  *
     41  *              These are the minimum set of functions or commands required to
     42  *              report results.
     43  *
     44  * Exit:        All commands exit with
     45  *               0   - on success
     46  *              -1  - on failure
     47  *
     48  * History
     49  * Dec 10 2002 - Created - Manoj Iyer manjo (at) mail.utexas.edu
     50  * Dec 12 2002 - Modified - Code that checked if the environment variables
     51  *               TCID and TST_TOTAL were set did not print usage message.
     52  *               Modified code to print usage message in each case.
     53  * Dec 16 2002 - Modified - Code to get the test number, gets environment
     54  *               variable TST_COUNT and initializes tst_count.
     55  * Dec 16 2002 - Documentation and comment changes.
     56  * Feb 11 2003 - tst_count was set to -1 during init or setup in the script.
     57  *               this was causing tst_resm to issue a warning message.
     58  *               This bug is now fixed.
     59  *
     60  */
     61 
     62 #include <sys/socket.h>
     63 #include <stdio.h>
     64 #include <string.h>
     65 #include <stdlib.h>
     66 #include <stdint.h>
     67 #include "test.h"
     68 #include "usctest.h"
     69 #include "safe_macros.h"
     70 
     71 char *TCID;			/* Name of the testcase */
     72 int TST_TOTAL;			/* Total number of testcases */
     73 
     74 static char cmd_name[1024];	/* name by which this program is invoked tst_brk etc */
     75 static char *tst_total;		/* total number of tests in the file. */
     76 static char *tst_cntstr;	/* sets the value of tst_count with this value */
     77 
     78 
     79 /*
     80  * Function:    ident_ttype - Return test result type.
     81  *
     82  * Description: This function will return the test result type, it actually
     83  *              the string that is entered by the user to an integer value that
     84  *              is understood by the API's.
     85  *
     86  * Return:      test type TPASS, TFAIL, TBROK, TCONF, TWARN, or TINFO
     87  *              on success
     88  *              -1 on failure
     89  */
     90 int ident_ttype(char *tstype)
     91 {
     92 	/* test result type one of TPASS, TFAIL, etc */
     93 	if (strcmp(tstype, "TBROK") == 0)
     94 		return TBROK;
     95 	else if (strcmp(tstype, "TFAIL") == 0)
     96 		return TFAIL;
     97 	else if (strcmp(tstype, "TPASS") == 0)
     98 		return TPASS;
     99 	else if (strcmp(tstype, "TCONF") == 0)
    100 		return TCONF;
    101 	else if (strcmp(tstype, "TWARN") == 0)
    102 		return TWARN;
    103 	else if (strcmp(tstype, "TINFO") == 0)
    104 		return TINFO;
    105 	else
    106 		return -1;
    107 }
    108 
    109 void tst_cat_file(const char *filename)
    110 {
    111 	const char *cmd[] = {"cat", filename, NULL};
    112 
    113 	tst_run_cmd(NULL, cmd, NULL, NULL, 0);
    114 }
    115 
    116 void apicmd_brk(int argc, char *argv[])
    117 {
    118 	int trestype;
    119 	char *file_name;
    120 
    121 	if (argc < 5) {
    122 		fprintf(stderr, "Usage: %s TTYPE FNAME FUNC STRING\n"
    123 			"\tTTYPE  - Test Result Type; one of TFAIL, TBROK "
    124 			"and TCONF.\n"
    125 			"\tFNAME  - Print contents of this file after the message\n"
    126 			"\tFUNC   - Cleanup function (ignored), but MUST be provided\n"
    127 			"\tSTRING - Message explaining the test result\n",
    128 			cmd_name);
    129 		exit(1);
    130 	}
    131 	trestype = ident_ttype((argv++)[0]);
    132 	file_name = (argv++)[0];
    133 	tst_cat_file(file_name);
    134 	argv++;
    135 	tst_brkm(trestype, NULL, "%s", *argv);
    136 
    137 }
    138 
    139 void apicmd_res(int argc, char *argv[])
    140 {
    141 	int trestype;
    142 	char *file_name;
    143 
    144 	if (argc < 4) {
    145 		fprintf(stderr, "Usage: %s TTYPE FNAME STRING\n"
    146 			"\tTTYPE  - Test Result Type; one of TFAIL, TBROK "
    147 			"and  TCONF.\n"
    148 			"\tFNAME  - Print contents of this file after the message\n"
    149 			"\tSTRING - Message explaining the test result\n",
    150 			cmd_name);
    151 		exit(1);
    152 	}
    153 	trestype = ident_ttype((argv++)[0]);
    154 	file_name = (argv++)[0];
    155 	tst_cat_file(file_name);
    156 	tst_resm(trestype, "%s", *argv);
    157 }
    158 
    159 void apicmd_brkm(int argc, char *argv[])
    160 {
    161 	int trestype;
    162 
    163 	if (argc < 4) {
    164 		fprintf(stderr, "Usage: %s TTYPE FUNC STRING\n"
    165 			"\tTTYPE  - Test Result Type; one of TFAIL, TBROK "
    166 			"and TCONF.\n"
    167 			"\tFUNC   - Cleanup function (ignored), but MUST be provided\n"
    168 			"\tSTRING - Message explaining the test result\n",
    169 			cmd_name);
    170 		exit(1);
    171 	}
    172 	trestype = ident_ttype((argv++)[0]);
    173 	argv++;
    174 	tst_brkm(trestype, NULL, "%s", *argv);
    175 }
    176 
    177 void apicmd_resm(int argc, char *argv[])
    178 {
    179 	int trestype;
    180 
    181 	if (argc < 3) {
    182 		fprintf(stderr, "Usage: %s TTYPE STRING\n"
    183 			"\tTTYPE  - Test Result Type; one of TFAIL, TBROK"
    184 			"and TCONF.\n"
    185 			"\tSTRING - Message explaining the test result\n",
    186 			cmd_name);
    187 		exit(1);
    188 	}
    189 	trestype = ident_ttype((argv++)[0]);
    190 	tst_resm(trestype, "%s", *argv);
    191 }
    192 
    193 struct param_pair {
    194 	char *cmd;
    195 	int value;
    196 };
    197 
    198 unsigned short apicmd_get_unused_port(int argc, char *argv[])
    199 {
    200 	if (argc != 3)
    201 		goto err;
    202 
    203 	const struct param_pair params[][3] = {
    204 		{{"ipv4", AF_INET}, {"ipv6", AF_INET6}, {NULL, 0}},
    205 		{{"stream", SOCK_STREAM}, {"dgram", SOCK_DGRAM}, {NULL, 0}}
    206 	};
    207 
    208 	int i;
    209 	const struct param_pair *p[2];
    210 	for (i = 0; i < 2; ++i) {
    211 		for (p[i] = params[i]; p[i]->cmd; ++p[i]) {
    212 			if (!strcmp(p[i]->cmd, argv[i]))
    213 				break;
    214 		}
    215 		if (!p[i]->cmd)
    216 			goto err;
    217 	}
    218 	return  tst_get_unused_port(NULL, p[0]->value, p[1]->value);
    219 
    220 err:
    221 	fprintf(stderr, "Usage: tst_get_unused_port FAMILY TYPE\n"
    222 		"where FAMILY := { ipv4 | ipv6 }\n"
    223 		"      TYPE := { stream | dgram }\n");
    224 	exit(1);
    225 }
    226 
    227 int apicmd_fs_has_free(int argc, char *argv[])
    228 {
    229 	if (argc != 3) {
    230 		fprintf(stderr, "Usage: tst_fs_has_free path required_bytes\n"
    231 			"path: the pathname of the mounted filesystem\n"
    232 			"required_bytes: the required free space"
    233 			" (supports kB, MB and GB suffixes)\n");
    234 		exit(2);
    235 	}
    236 
    237 	char *endptr;
    238 	unsigned int required_kib = strtoull(argv[1], &endptr, 0);
    239 	unsigned int mul = TST_BYTES;
    240 
    241 	if (*argv[1] == '\0')
    242 		goto fs_has_free_err;
    243 
    244 	if (*endptr != '\0') {
    245 		if (!strcasecmp(endptr, "kB")) {
    246 			mul = TST_KB;
    247 		} else if (!strcasecmp(endptr, "MB")) {
    248 			mul = TST_MB;
    249 		} else if (!strcasecmp(endptr, "GB")) {
    250 			mul = TST_GB;
    251 		} else {
    252 			goto fs_has_free_err;
    253 		}
    254 	}
    255 
    256 	exit(!tst_fs_has_free(NULL, argv[0], required_kib, mul));
    257 
    258 fs_has_free_err:
    259 	fprintf(stderr, "%s is not a valid size\n", argv[1]);
    260 	exit(2);
    261 }
    262 
    263 /*
    264  * Function:    main - entry point of this program
    265  *
    266  * Description: Parses the arguments to each command. Most commands have in
    267  *              common atlest 2 arguments, type of test result, which is one of
    268  *              TPASS, TFAIL, TBROK, TCONF, etc, and a message that describes
    269  *              the result. Other arguments are a file, the contents of which
    270  *              are printed after the type of test result and associated message
    271  *              is printed, also a cleanup function that will be executed.
    272  *              Currently this function name is ignored but MUST be provided
    273  *              for compatability reasons.
    274  *
    275  *              The different commands are actually a hard link to this program
    276  *              the program invokes the appropriate function based on the
    277  *              command name with which it was invoked.
    278  *
    279  *              Set the values for TCID to the name of the test case.
    280  *              set the value for TST_TOTAL for total number of tests this is
    281  *              required in case one test breaks and all following tests also
    282  *              should be reported as broken.
    283  *              Set tst_count before every individual test.
    284  *
    285  * Exit:        0 on success
    286  *              -1 on failure
    287  */
    288 int main(int argc, char *argv[])
    289 {
    290 	strcpy(cmd_name, SAFE_BASENAME(NULL, (argv++)[0]));
    291 
    292 	TCID = getenv("TCID");
    293 	tst_total = getenv("TST_TOTAL");
    294 	tst_cntstr = getenv("TST_COUNT");
    295 	if (TCID == NULL || tst_total == NULL || tst_cntstr == NULL) {
    296 		 if(!strcmp(cmd_name, "tst_fs_has_free") &&
    297 		    !strcmp(cmd_name, "tst_get_unused_port")) {
    298 			fprintf(stderr,
    299 				"\nSet variables TCID, TST_TOTAL, and TST_COUNT before each test:\n"
    300 				"export TCID=<test name>\n"
    301 				"export TST_TOTAL=<Total Number of Tests >\n"
    302 				"export TST_COUNT=<Test case number>\n\n");
    303 			/* Make sure the user knows there's an error. */
    304 			abort();
    305 		}
    306 	} else {
    307 		TST_TOTAL = atoi(tst_total);
    308 		tst_count = atoi(tst_cntstr);
    309 		if (tst_count > 0)
    310 			tst_count--;
    311 
    312 		if (strcmp(TCID, " ") == 0) {
    313 			fprintf(stderr,
    314 				"Variable TCID not set, use: TCID=<test name>\n");
    315 			exit(1);
    316 		}
    317 		if (TST_TOTAL <= 0) {
    318 			fprintf(stderr,
    319 				"Variable TST_TOTAL is set to 0, must be "
    320 				"greater than zero\n");
    321 			exit(1);
    322 		}
    323 	}
    324 
    325 	if (strcmp(cmd_name, "tst_brk") == 0) {
    326 		apicmd_brk(argc, argv);
    327 	} else if (strcmp(cmd_name, "tst_res") == 0) {
    328 		apicmd_res(argc, argv);
    329 	} else if (strcmp(cmd_name, "tst_brkm") == 0) {
    330 		apicmd_brkm(argc, argv);
    331 	} else if (strcmp(cmd_name, "tst_resm") == 0) {
    332 		apicmd_resm(argc, argv);
    333 	} else if (strcmp(cmd_name, "tst_exit") == 0) {
    334 		tst_exit();
    335 	} else if (strcmp(cmd_name, "tst_flush") == 0) {
    336 		tst_flush();
    337 	} else if (strcmp(cmd_name, "tst_ncpus") == 0) {
    338 		printf("%li\n", tst_ncpus());
    339 	} else if (strcmp(cmd_name, "tst_ncpus_conf") == 0) {
    340 		printf("%li\n", tst_ncpus_conf());
    341 	} else if (strcmp(cmd_name, "tst_ncpus_max") == 0) {
    342 		printf("%li\n", tst_ncpus_max());
    343 	} else if (strcmp(cmd_name, "tst_get_unused_port") == 0) {
    344 		printf("%u\n", apicmd_get_unused_port(argc, argv));
    345 	} else if (strcmp(cmd_name, "tst_fs_has_free") == 0) {
    346 		apicmd_fs_has_free(argc, argv);
    347 	}
    348 
    349 	exit(0);
    350 }
    351