Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2008, 2009, 2010, 2011, 2013, 2014 Nicira, Inc.
3 : : *
4 : : * Licensed under the Apache License, Version 2.0 (the "License");
5 : : * you may not use this file except in compliance with the License.
6 : : * You may obtain a copy of the License at:
7 : : *
8 : : * http://www.apache.org/licenses/LICENSE-2.0
9 : : *
10 : : * Unless required by applicable law or agreed to in writing, software
11 : : * distributed under the License is distributed on an "AS IS" BASIS,
12 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 : : * See the License for the specific language governing permissions and
14 : : * limitations under the License.
15 : : */
16 : :
17 : : #include <config.h>
18 : : #include "command-line.h"
19 : : #include <getopt.h>
20 : : #include <limits.h>
21 : : #include <stdlib.h>
22 : : #include "openvswitch/dynamic-string.h"
23 : : #include "ovs-thread.h"
24 : : #include "util.h"
25 : : #include "openvswitch/vlog.h"
26 : :
27 : 53954 : VLOG_DEFINE_THIS_MODULE(command_line);
28 : :
29 : : /* Given the GNU-style long options in 'options', returns a string that may be
30 : : * passed to getopt() with the corresponding short options. The caller is
31 : : * responsible for freeing the string. */
32 : : char *
33 : 26500 : ovs_cmdl_long_options_to_short_options(const struct option options[])
34 : : {
35 : : char short_options[UCHAR_MAX * 3 + 1];
36 : 26500 : char *p = short_options;
37 : :
38 [ + + ]: 498575 : for (; options->name; options++) {
39 : 472075 : const struct option *o = options;
40 [ + - ][ + + ]: 472075 : if (o->flag == NULL && o->val > 0 && o->val <= UCHAR_MAX) {
[ + + ]
41 : 212882 : *p++ = o->val;
42 [ + + ]: 212882 : if (o->has_arg == required_argument) {
43 : 99561 : *p++ = ':';
44 [ + + ]: 113321 : } else if (o->has_arg == optional_argument) {
45 : 26900 : *p++ = ':';
46 : 26900 : *p++ = ':';
47 : : }
48 : : }
49 : : }
50 : 26500 : *p = '\0';
51 : :
52 : 26500 : return xstrdup(short_options);
53 : : }
54 : :
55 : : /* Given the 'struct ovs_cmdl_command' array, prints the usage of all commands. */
56 : : void
57 : 5 : ovs_cmdl_print_commands(const struct ovs_cmdl_command commands[])
58 : : {
59 : 5 : struct ds ds = DS_EMPTY_INITIALIZER;
60 : :
61 : 5 : ds_put_cstr(&ds, "The available commands are:\n");
62 [ + + ]: 184 : for (; commands->name; commands++) {
63 : 179 : const struct ovs_cmdl_command *c = commands;
64 [ + + ]: 179 : ds_put_format(&ds, " %-23s %s\n", c->name, c->usage ? c->usage : "");
65 : : }
66 : 5 : printf("%s", ds.string);
67 : 5 : ds_destroy(&ds);
68 : 5 : }
69 : :
70 : : /* Given the GNU-style options in 'options', prints all options. */
71 : : void
72 : 22 : ovs_cmdl_print_options(const struct option options[])
73 : : {
74 : 22 : struct ds ds = DS_EMPTY_INITIALIZER;
75 : :
76 [ + + ]: 282 : for (; options->name; options++) {
77 : 260 : const struct option *o = options;
78 [ + + ]: 260 : const char *arg = o->has_arg == required_argument ? "ARG" : "[ARG]";
79 : :
80 [ + + ][ + + ]: 260 : ds_put_format(&ds, "--%s%s%s\n", o->name, o->has_arg ? "=" : "",
81 : 260 : o->has_arg ? arg : "");
82 [ + - ][ + - ]: 260 : if (o->flag == NULL && o->val > 0 && o->val <= UCHAR_MAX) {
[ + + ]
83 [ + + ]: 160 : ds_put_format(&ds, "-%c %s\n", o->val, o->has_arg ? arg : "");
84 : : }
85 : : }
86 : 22 : printf("%s", ds.string);
87 : 22 : ds_destroy(&ds);
88 : 22 : }
89 : :
90 : : static void
91 : 6854 : ovs_cmdl_run_command__(struct ovs_cmdl_context *ctx,
92 : : const struct ovs_cmdl_command commands[],
93 : : bool read_only)
94 : : {
95 : : const struct ovs_cmdl_command *p;
96 : :
97 [ + + ]: 6854 : if (ctx->argc < 1) {
98 : 3 : ovs_fatal(0, "missing command name; use --help for help");
99 : : }
100 : :
101 [ + - ]: 126779 : for (p = commands; p->name != NULL; p++) {
102 [ + + ]: 126779 : if (!strcmp(p->name, ctx->argv[0])) {
103 : 6851 : int n_arg = ctx->argc - 1;
104 [ + + ]: 6851 : if (n_arg < p->min_args) {
105 : 1 : VLOG_FATAL( "'%s' command requires at least %d arguments",
106 : : p->name, p->min_args);
107 [ - + ]: 6850 : } else if (n_arg > p->max_args) {
108 : 0 : VLOG_FATAL("'%s' command takes at most %d arguments",
109 : : p->name, p->max_args);
110 : : } else {
111 [ + + ][ - + ]: 6850 : if (p->mode == OVS_RW && read_only) {
112 : 0 : VLOG_FATAL("'%s' command does not work in read only mode",
113 : : p->name);
114 : : }
115 : 6850 : p->handler(ctx);
116 [ - + ]: 6489 : if (ferror(stdout)) {
117 : 0 : VLOG_FATAL("write to stdout failed");
118 : : }
119 [ - + ]: 6489 : if (ferror(stderr)) {
120 : 0 : VLOG_FATAL("write to stderr failed");
121 : : }
122 : 6489 : return;
123 : : }
124 : : }
125 : : }
126 : :
127 : 0 : VLOG_FATAL("unknown command '%s'; use --help for help", ctx->argv[0]);
128 : : }
129 : :
130 : : /* Runs the command designated by argv[0] within the command table specified by
131 : : * 'commands', which must be terminated by a command whose 'name' member is a
132 : : * null pointer.
133 : : *
134 : : * Command-line options should be stripped off, so that a typical invocation
135 : : * looks like:
136 : : * struct ovs_cmdl_context ctx = {
137 : : * .argc = argc - optind,
138 : : * .argv = argv + optind,
139 : : * };
140 : : * ovs_cmdl_run_command(&ctx, my_commands);
141 : : * */
142 : : void
143 : 6854 : ovs_cmdl_run_command(struct ovs_cmdl_context *ctx,
144 : : const struct ovs_cmdl_command commands[])
145 : : {
146 : 6854 : ovs_cmdl_run_command__(ctx, commands, false);
147 : 6489 : }
148 : :
149 : : void
150 : 0 : ovs_cmdl_run_command_read_only(struct ovs_cmdl_context *ctx,
151 : : const struct ovs_cmdl_command commands[])
152 : : {
153 : 0 : ovs_cmdl_run_command__(ctx, commands, true);
154 : 0 : }
155 : :
156 : : /* Process title. */
157 : :
158 : : #ifdef __linux__
159 : : static struct ovs_mutex proctitle_mutex = OVS_MUTEX_INITIALIZER;
160 : :
161 : : /* Start of command-line arguments in memory. */
162 : : static char *argv_start OVS_GUARDED_BY(proctitle_mutex);
163 : :
164 : : /* Number of bytes of command-line arguments. */
165 : : static size_t argv_size OVS_GUARDED_BY(proctitle_mutex);
166 : :
167 : : /* Saved command-line arguments. */
168 : : static char *saved_proctitle OVS_GUARDED_BY(proctitle_mutex);
169 : :
170 : : /* Prepares the process so that proctitle_set() can later succeed.
171 : : *
172 : : * This modifies the argv[] array so that it no longer points into the memory
173 : : * that it originally does. Later, proctitle_set() might overwrite that
174 : : * memory. That means that this function should be called before anything else
175 : : * that accesses the process's argv[] array. Ideally, it should be called
176 : : * before anything else, period, at the very beginning of program
177 : : * execution. */
178 : : void
179 : 2925 : ovs_cmdl_proctitle_init(int argc, char **argv)
180 : : {
181 : : int i;
182 : :
183 : 2925 : assert_single_threaded();
184 [ + - ][ - + ]: 2925 : if (!argc || !argv[0]) {
185 : : /* This situation should never occur, but... */
186 : 0 : return;
187 : : }
188 : :
189 : 2925 : ovs_mutex_lock(&proctitle_mutex);
190 : : /* Specialized version of first loop iteration below. */
191 : 2925 : argv_start = argv[0];
192 : 2925 : argv_size = strlen(argv[0]) + 1;
193 : 2925 : argv[0] = xstrdup(argv[0]);
194 : :
195 [ + + ]: 19588 : for (i = 1; i < argc; i++) {
196 : 16663 : size_t size = strlen(argv[i]) + 1;
197 : :
198 : : /* Add (argv[i], strlen(argv[i])+1) to (argv_start, argv_size). */
199 [ - + ]: 16663 : if (argv[i] + size == argv_start) {
200 : : /* Arguments grow downward in memory. */
201 : 0 : argv_start -= size;
202 : 0 : argv_size += size;
203 [ + - ]: 16663 : } else if (argv[i] == argv_start + argv_size) {
204 : : /* Arguments grow upward in memory. */
205 : 16663 : argv_size += size;
206 : : } else {
207 : : /* Arguments not contiguous. (Is this really Linux?) */
208 : : }
209 : :
210 : : /* Copy out the old argument so we can reuse the space. */
211 : 16663 : argv[i] = xstrdup(argv[i]);
212 : : }
213 : 2925 : ovs_mutex_unlock(&proctitle_mutex);
214 : : }
215 : :
216 : : /* Changes the name of the process, as shown by "ps", to the program name
217 : : * followed by 'format', which is formatted as if by printf(). */
218 : : void
219 : 12 : ovs_cmdl_proctitle_set(const char *format, ...)
220 : : {
221 : : va_list args;
222 : : int n;
223 : :
224 : 12 : ovs_mutex_lock(&proctitle_mutex);
225 [ + - ][ + - ]: 12 : if (!argv_start || argv_size < 8) {
226 : : goto out;
227 : : }
228 : :
229 [ + + ]: 12 : if (!saved_proctitle) {
230 : 6 : saved_proctitle = xmemdup(argv_start, argv_size);
231 : : }
232 : :
233 : 12 : va_start(args, format);
234 : 12 : n = snprintf(argv_start, argv_size, "%s: ", program_name);
235 [ + - ]: 12 : if (n < argv_size) {
236 : 12 : n += vsnprintf(argv_start + n, argv_size - n, format, args);
237 : : }
238 [ + + ]: 12 : if (n >= argv_size) {
239 : : /* The name is too long, so add an ellipsis at the end. */
240 : 4 : strcpy(&argv_start[argv_size - 4], "...");
241 : : } else {
242 : : /* Fill the extra space with null bytes, so that trailing bytes don't
243 : : * show up in the command line. */
244 : 8 : memset(&argv_start[n], '\0', argv_size - n);
245 : : }
246 : 12 : va_end(args);
247 : :
248 : : out:
249 : 12 : ovs_mutex_unlock(&proctitle_mutex);
250 : 12 : }
251 : :
252 : : /* Restores the process's original command line, as seen by "ps". */
253 : : void
254 : 4 : ovs_cmdl_proctitle_restore(void)
255 : : {
256 : 4 : ovs_mutex_lock(&proctitle_mutex);
257 [ + - ]: 4 : if (saved_proctitle) {
258 : 4 : memcpy(argv_start, saved_proctitle, argv_size);
259 : 4 : free(saved_proctitle);
260 : 4 : saved_proctitle = NULL;
261 : : }
262 : 4 : ovs_mutex_unlock(&proctitle_mutex);
263 : 4 : }
264 : : #else /* !__linux__ */
265 : : /* Stubs that don't do anything on non-Linux systems. */
266 : :
267 : : void
268 : : ovs_cmdl_proctitle_init(int argc OVS_UNUSED, char **argv OVS_UNUSED)
269 : : {
270 : : }
271 : :
272 : : #if !(defined(__FreeBSD__) || defined(__NetBSD__))
273 : : /* On these platforms we #define this to setproctitle. */
274 : : void
275 : : ovs_cmdl_proctitle_set(const char *format OVS_UNUSED, ...)
276 : : {
277 : : }
278 : : #endif
279 : :
280 : : void
281 : : ovs_cmdl_proctitle_restore(void)
282 : : {
283 : : }
284 : : #endif /* !__linux__ */
|