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