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