xref: /trafficserver/src/tscore/ink_args.cc (revision 4cfd5a73)
1 /** @file
2 
3   A brief file description
4 
5   @section license License
6 
7   Licensed to the Apache Software Foundation (ASF) under one
8   or more contributor license agreements.  See the NOTICE file
9   distributed with this work for additional information
10   regarding copyright ownership.  The ASF licenses this file
11   to you under the Apache License, Version 2.0 (the
12   "License"); you may not use this file except in compliance
13   with the License.  You may obtain a copy of the License at
14 
15       http://www.apache.org/licenses/LICENSE-2.0
16 
17   Unless required by applicable law or agreed to in writing, software
18   distributed under the License is distributed on an "AS IS" BASIS,
19   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   See the License for the specific language governing permissions and
21   limitations under the License.
22  */
23 
24 /****************************************************************************
25 Process arguments
26 
27 ****************************************************************************/
28 
29 #include "tscore/ink_platform.h"
30 #include "tscore/ink_args.h"
31 #include "tscore/Diags.h"
32 #include "tscore/I_Version.h"
33 #include "tscore/ink_file.h"
34 #include "tscore/ink_memory.h"
35 #include "tscore/ink_string.h"
36 
37 //
38 //  Global variables
39 //
40 
41 const char *file_arguments[MAX_FILE_ARGUMENTS] = {nullptr};
42 const char *program_name                       = (char *)"Traffic Server";
43 unsigned n_file_arguments                      = 0;
44 int cmd_disable_pfreelist                      = 0;
45 
46 //
47 //  Local variables
48 //
49 
50 static const char *argument_types_keys           = (char *)"ISDfFTL";
51 static const char *argument_types_descriptions[] = {(char *)"int  ", (char *)"str  ", (char *)"dbl  ", (char *)"off  ",
52                                                     (char *)"on   ", (char *)"tog  ", (char *)"i64  ", (char *)"     "};
53 
54 //
55 // Functions
56 //
57 
58 static bool
arg_is_version_flag(const ArgumentDescription * arg)59 arg_is_version_flag(const ArgumentDescription *arg)
60 {
61   return strcmp(arg->name, "version") == 0 && arg->key == 'V';
62 }
63 
64 static void
append_file_argument(const char * arg)65 append_file_argument(const char *arg)
66 {
67   if (n_file_arguments >= countof(file_arguments)) {
68     ink_fatal("too many files");
69   }
70 
71   file_arguments[n_file_arguments++] = arg;
72 }
73 
74 static bool
process_arg(const AppVersionInfo * appinfo,const ArgumentDescription * argument_descriptions,unsigned n_argument_descriptions,int i,const char *** argv)75 process_arg(const AppVersionInfo *appinfo, const ArgumentDescription *argument_descriptions, unsigned n_argument_descriptions,
76             int i, const char ***argv)
77 {
78   const char *arg = nullptr;
79 
80   if (arg_is_version_flag(&argument_descriptions[i])) {
81     ink_fputln(stdout, appinfo->FullVersionInfoStr);
82     exit(0);
83   }
84 
85   if (argument_descriptions[i].type) {
86     char type = argument_descriptions[i].type[0];
87     if (type == 'F' || type == 'f') {
88       *static_cast<int *>(argument_descriptions[i].location) = type == 'F' ? 1 : 0;
89     } else if (type == 'T') {
90       *static_cast<int *>(argument_descriptions[i].location) = !*static_cast<int *>(argument_descriptions[i].location);
91     } else {
92       arg = *++(**argv) ? **argv : *++(*argv);
93       if (!arg) {
94         return false;
95       }
96       switch (type) {
97       case 'I':
98         *static_cast<int *>(argument_descriptions[i].location) = atoi(arg);
99         break;
100       case 'D':
101         *static_cast<double *>(argument_descriptions[i].location) = atof(arg);
102         break;
103       case 'L':
104         *static_cast<int64_t *>(argument_descriptions[i].location) = ink_atoi64(arg);
105         break;
106       case 'S':
107         if (argument_descriptions[i].type[1] == '*') {
108           char **out = static_cast<char **>(argument_descriptions[i].location);
109           *out       = ats_strdup(arg);
110         } else {
111           ink_strlcpy(static_cast<char *>(argument_descriptions[i].location), arg, atoi(argument_descriptions[i].type + 1));
112         }
113         break;
114       default:
115         ink_fatal("bad argument description");
116         break;
117       }
118       **argv += strlen(**argv) - 1;
119     }
120   }
121 
122   if (argument_descriptions[i].pfn) {
123     argument_descriptions[i].pfn(argument_descriptions, n_argument_descriptions, arg);
124   }
125 
126   return true;
127 }
128 
129 void
show_argument_configuration(const ArgumentDescription * argument_descriptions,unsigned n_argument_descriptions)130 show_argument_configuration(const ArgumentDescription *argument_descriptions, unsigned n_argument_descriptions)
131 {
132   printf("Argument Configuration\n");
133   for (unsigned i = 0; i < n_argument_descriptions; i++) {
134     if (argument_descriptions[i].type) {
135       printf("  %-34s ", argument_descriptions[i].description);
136       switch (argument_descriptions[i].type[0]) {
137       case 'F':
138       case 'f':
139       case 'T':
140         printf(*static_cast<int *>(argument_descriptions[i].location) ? "TRUE" : "FALSE");
141         break;
142       case 'I':
143         printf("%d", *static_cast<int *>(argument_descriptions[i].location));
144         break;
145       case 'D':
146         printf("%f", *static_cast<double *>(argument_descriptions[i].location));
147         break;
148       case 'L':
149         printf("%" PRId64 "", *static_cast<int64_t *>(argument_descriptions[i].location));
150         break;
151       case 'S':
152         printf("%s", static_cast<char *>(argument_descriptions[i].location));
153         break;
154       default:
155         ink_fatal("bad argument description");
156         break;
157       }
158       printf("\n");
159     }
160   }
161 }
162 
163 void
process_args(const AppVersionInfo * appinfo,const ArgumentDescription * argument_descriptions,unsigned n_argument_descriptions,const char ** argv,const char * usage_string)164 process_args(const AppVersionInfo *appinfo, const ArgumentDescription *argument_descriptions, unsigned n_argument_descriptions,
165              const char **argv, const char *usage_string)
166 {
167   if (!process_args_ex(appinfo, argument_descriptions, n_argument_descriptions, argv)) {
168     usage(argument_descriptions, n_argument_descriptions, usage_string);
169   }
170 }
171 
172 bool
process_args_ex(const AppVersionInfo * appinfo,const ArgumentDescription * argument_descriptions,unsigned n_argument_descriptions,const char ** argv)173 process_args_ex(const AppVersionInfo *appinfo, const ArgumentDescription *argument_descriptions, unsigned n_argument_descriptions,
174                 const char **argv)
175 {
176   unsigned i = 0;
177   //
178   // Grab Environment Variables
179   //
180   for (i = 0; i < n_argument_descriptions; i++) {
181     if (argument_descriptions[i].env) {
182       char type = argument_descriptions[i].type[0];
183       char *env = getenv(argument_descriptions[i].env);
184       if (!env) {
185         continue;
186       }
187       switch (type) {
188       case 'f':
189       case 'F':
190       case 'I':
191         *static_cast<int *>(argument_descriptions[i].location) = atoi(env);
192         break;
193       case 'D':
194         *static_cast<double *>(argument_descriptions[i].location) = atof(env);
195         break;
196       case 'L':
197         *static_cast<int64_t *>(argument_descriptions[i].location) = atoll(env);
198         break;
199       case 'S':
200         ink_strlcpy(static_cast<char *>(argument_descriptions[i].location), env, atoi(argument_descriptions[i].type + 1));
201         break;
202       }
203     }
204   }
205   //
206   // Grab Command Line Arguments
207   //
208   program_name = appinfo->AppStr;
209   while (*++argv) {
210     // Hack for supporting '-' as a file argument.
211     if (strcmp(*argv, "-") == 0) {
212       append_file_argument(*argv);
213       break;
214     }
215 
216     // No leading '-', this is the start of the file arguments.
217     if ((*argv)[0] != '-') {
218       append_file_argument(*argv);
219       break;
220     }
221 
222     if ((*argv)[1] == '-') {
223       // Deal with long options ...
224       for (i = 0; i < n_argument_descriptions; i++) {
225         // handle the runroot arg
226         std::string_view cur_argv = *argv + 2;
227         if (cur_argv.size() >= 8 && cur_argv.substr(0, 8) == "run-root") {
228           break;
229         }
230         // handle the args
231         if (!strcmp(argument_descriptions[i].name, (*argv) + 2)) {
232           *argv += strlen(*argv) - 1;
233           if (!process_arg(appinfo, argument_descriptions, n_argument_descriptions, i, &argv)) {
234             return false;
235           }
236           break;
237         }
238       }
239       if (i >= n_argument_descriptions) {
240         return false;
241       }
242     } else {
243       // Deal with (possibly combined) short options ...
244       while (*++(*argv)) {
245         for (i = 0; i < n_argument_descriptions; i++) {
246           if (argument_descriptions[i].key == **argv) {
247             if (!process_arg(appinfo, argument_descriptions, n_argument_descriptions, i, &argv)) {
248               return false;
249             }
250             break;
251           }
252         }
253 
254         if (i >= n_argument_descriptions) {
255           return false;
256         }
257       }
258     }
259   }
260 
261   // If we have any arguments left, slurp them up into file_arguments.
262   if (*argv) {
263     while (*++argv) {
264       append_file_argument(*argv);
265     }
266   }
267 
268   return true;
269 }
270 
271 void
usage(const ArgumentDescription * argument_descriptions,unsigned n_argument_descriptions,const char * usage_string)272 usage(const ArgumentDescription *argument_descriptions, unsigned n_argument_descriptions, const char *usage_string)
273 {
274   (void)argument_descriptions;
275   (void)n_argument_descriptions;
276   (void)usage_string;
277   if (usage_string) {
278     fprintf(stderr, "%s\n", usage_string);
279   } else {
280     fprintf(stderr, "Usage: %s [--SWITCH [ARG]]\n", program_name);
281   }
282   fprintf(stderr, "  switch__________________type__default___description\n");
283   for (unsigned i = 0; i < n_argument_descriptions; i++) {
284     if (!argument_descriptions[i].description) {
285       continue;
286     }
287 
288     fprintf(stderr, "  ");
289 
290     if ('-' == argument_descriptions[i].key) {
291       fprintf(stderr, "   ");
292     } else {
293       fprintf(stderr, "-%c,", argument_descriptions[i].key);
294     }
295 
296     fprintf(stderr, " --%-17s %s", argument_descriptions[i].name,
297             argument_types_descriptions[argument_descriptions[i].type ?
298                                           strchr(argument_types_keys, argument_descriptions[i].type[0]) - argument_types_keys :
299                                           strlen(argument_types_keys)]);
300     switch (argument_descriptions[i].type ? argument_descriptions[i].type[0] : 0) {
301     case 0:
302       fprintf(stderr, "          ");
303       break;
304     case 'L':
305       fprintf(stderr, " %-9" PRId64 "", *static_cast<int64_t *>(argument_descriptions[i].location));
306       break;
307     case 'S': {
308       char *location;
309       if (argument_descriptions[i].type[1] == '*') {
310         location = *static_cast<char **>(argument_descriptions[i].location);
311       } else {
312         location = static_cast<char *>(argument_descriptions[i].location);
313       }
314 
315       if (location) {
316         if (strlen(location) < 10) {
317           fprintf(stderr, " %-9s", location);
318         } else {
319           fprintf(stderr, " %-7.7s..", location);
320         }
321       } else {
322         fprintf(stderr, " (null)   ");
323       }
324       break;
325     }
326     case 'D':
327       fprintf(stderr, " %-9.3f", *static_cast<double *>(argument_descriptions[i].location));
328       break;
329     case 'I':
330       fprintf(stderr, " %-9d", *static_cast<int *>(argument_descriptions[i].location));
331       break;
332     case 'T':
333     case 'f':
334     case 'F':
335       if (argument_descriptions[i].location) {
336         fprintf(stderr, " %-9s", *static_cast<int *>(argument_descriptions[i].location) ? "true " : "false");
337       } else {
338         fprintf(stderr, " %-9s", "false");
339       }
340       break;
341     }
342     fprintf(stderr, " %s\n", argument_descriptions[i].description);
343   }
344   ::exit(EX_USAGE);
345 }
346