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@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 */
ident_ttype(char * tstype)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
tst_cat_file(const char * filename)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
apicmd_brk(int argc,char * argv[])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
apicmd_res(int argc,char * argv[])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
apicmd_brkm(int argc,char * argv[])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
apicmd_resm(int argc,char * argv[])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
apicmd_get_unused_port(int argc,char * argv[])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
apicmd_fs_has_free(int argc,char * argv[])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 */
main(int argc,char * argv[])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