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