]>
Commit | Line | Data |
---|---|---|
064af421 | 1 | /* |
9664732f | 2 | * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2014 Nicira, Inc. |
064af421 | 3 | * |
a14bc59f BP |
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: | |
064af421 | 7 | * |
a14bc59f BP |
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. | |
064af421 | 15 | */ |
3fbe1d30 | 16 | |
064af421 | 17 | #include <config.h> |
064af421 | 18 | |
064af421 BP |
19 | #include <errno.h> |
20 | #include <getopt.h> | |
064af421 BP |
21 | #include <stdio.h> |
22 | #include <string.h> | |
23 | #include <stdlib.h> | |
24 | ||
25 | #include "command-line.h" | |
3fbe1d30 BP |
26 | #include "daemon.h" |
27 | #include "dirs.h" | |
3e8a2ad1 | 28 | #include "openvswitch/dynamic-string.h" |
bde9f75d | 29 | #include "jsonrpc.h" |
0e15264f | 30 | #include "process.h" |
064af421 BP |
31 | #include "timeval.h" |
32 | #include "unixctl.h" | |
33 | #include "util.h" | |
e6211adc | 34 | #include "openvswitch/vlog.h" |
064af421 | 35 | |
3fbe1d30 BP |
36 | static void usage(void); |
37 | static const char *parse_command_line(int argc, char *argv[]); | |
bde9f75d | 38 | static struct jsonrpc *connect_to_target(const char *target); |
064af421 | 39 | |
3fbe1d30 BP |
40 | int |
41 | main(int argc, char *argv[]) | |
064af421 | 42 | { |
bde9f75d EJ |
43 | char *cmd_result, *cmd_error; |
44 | struct jsonrpc *client; | |
45 | char *cmd, **cmd_argv; | |
3fbe1d30 | 46 | const char *target; |
bde9f75d EJ |
47 | int cmd_argc; |
48 | int error; | |
3fbe1d30 BP |
49 | |
50 | set_program_name(argv[0]); | |
3fbe1d30 BP |
51 | |
52 | /* Parse command line and connect to target. */ | |
53 | target = parse_command_line(argc, argv); | |
54 | client = connect_to_target(target); | |
55 | ||
3fbe1d30 | 56 | /* Transact request and process reply. */ |
bde9f75d EJ |
57 | cmd = argv[optind++]; |
58 | cmd_argc = argc - optind; | |
59 | cmd_argv = cmd_argc ? argv + optind : NULL; | |
60 | error = unixctl_client_transact(client, cmd, cmd_argc, cmd_argv, | |
61 | &cmd_result, &cmd_error); | |
064af421 | 62 | if (error) { |
3fbe1d30 BP |
63 | ovs_fatal(error, "%s: transaction error", target); |
64 | } | |
bde9f75d EJ |
65 | |
66 | if (cmd_error) { | |
156f7a40 | 67 | jsonrpc_close(client); |
bde9f75d EJ |
68 | fputs(cmd_error, stderr); |
69 | ovs_error(0, "%s: server returned an error", target); | |
3fbe1d30 | 70 | exit(2); |
bde9f75d EJ |
71 | } else if (cmd_result) { |
72 | fputs(cmd_result, stdout); | |
73 | } else { | |
428b2edd | 74 | OVS_NOT_REACHED(); |
064af421 | 75 | } |
65f92a50 | 76 | |
bde9f75d EJ |
77 | jsonrpc_close(client); |
78 | free(cmd_result); | |
79 | free(cmd_error); | |
3fbe1d30 | 80 | return 0; |
064af421 BP |
81 | } |
82 | ||
83 | static void | |
3fbe1d30 | 84 | usage(void) |
064af421 | 85 | { |
c1a543a8 BP |
86 | printf("\ |
87 | %s, for querying and controlling Open vSwitch daemon\n\ | |
88 | usage: %s [TARGET] COMMAND [ARG...]\n\ | |
89 | Targets:\n\ | |
90 | -t, --target=TARGET pidfile or socket to contact\n\ | |
91 | Common commands:\n\ | |
91a11f5b | 92 | list-commands List commands supported by the target\n\ |
d5e1e5ed | 93 | version Print version of the target\n\ |
c1a543a8 | 94 | vlog/list List current logging levels\n\ |
532e1463 | 95 | vlog/list-pattern List logging patterns for each destination.\n\ |
2a3e30b2 BP |
96 | vlog/set [SPEC]\n\ |
97 | Set log levels as detailed in SPEC, which may include:\n\ | |
98 | A valid module name (all modules, by default)\n\ | |
d5460484 | 99 | 'syslog', 'console', 'file' (all destinations, by default))\n\ |
2a3e30b2 | 100 | 'off', 'emer', 'err', 'warn', 'info', or 'dbg' ('dbg', bydefault)\n\ |
c1a543a8 BP |
101 | vlog/reopen Make the program reopen its log file\n\ |
102 | Other options:\n\ | |
f4ec6ff4 | 103 | --timeout=SECS wait at most SECS seconds for a response\n\ |
c1a543a8 | 104 | -h, --help Print this helpful information\n\ |
d5e1e5ed | 105 | -V, --version Display ovs-appctl version information\n", |
3fbe1d30 BP |
106 | program_name, program_name); |
107 | exit(EXIT_SUCCESS); | |
064af421 BP |
108 | } |
109 | ||
3fbe1d30 BP |
110 | static const char * |
111 | parse_command_line(int argc, char *argv[]) | |
064af421 | 112 | { |
9664732f | 113 | enum { |
66fa2c88 | 114 | OPT_START = UCHAR_MAX + 1, |
9664732f BP |
115 | VLOG_OPTION_ENUMS |
116 | }; | |
064af421 | 117 | static const struct option long_options[] = { |
064af421 | 118 | {"target", required_argument, NULL, 't'}, |
3fbe1d30 | 119 | {"execute", no_argument, NULL, 'e'}, |
064af421 | 120 | {"help", no_argument, NULL, 'h'}, |
66fa2c88 | 121 | {"option", no_argument, NULL, 'o'}, |
064af421 | 122 | {"version", no_argument, NULL, 'V'}, |
f4ec6ff4 | 123 | {"timeout", required_argument, NULL, 'T'}, |
9664732f | 124 | VLOG_LONG_OPTIONS, |
e3c17733 | 125 | {NULL, 0, NULL, 0}, |
064af421 | 126 | }; |
5f383751 | 127 | char *short_options_ = ovs_cmdl_long_options_to_short_options(long_options); |
9664732f | 128 | char *short_options = xasprintf("+%s", short_options_); |
3fbe1d30 BP |
129 | const char *target; |
130 | int e_options; | |
9551e80b | 131 | unsigned int timeout = 0; |
064af421 | 132 | |
3fbe1d30 BP |
133 | target = NULL; |
134 | e_options = 0; | |
064af421 BP |
135 | for (;;) { |
136 | int option; | |
064af421 | 137 | |
9664732f | 138 | option = getopt_long(argc, argv, short_options, long_options, NULL); |
064af421 BP |
139 | if (option == -1) { |
140 | break; | |
141 | } | |
064af421 BP |
142 | switch (option) { |
143 | case 't': | |
3fbe1d30 BP |
144 | if (target) { |
145 | ovs_fatal(0, "-t or --target may be specified only once"); | |
064af421 | 146 | } |
3fbe1d30 | 147 | target = optarg; |
064af421 BP |
148 | break; |
149 | ||
150 | case 'e': | |
3fbe1d30 BP |
151 | /* We ignore -e for compatibility. Older versions specified the |
152 | * command as the argument to -e. Since the current version takes | |
153 | * the command as non-option arguments and we say that -e has no | |
154 | * arguments, this just works in the common case. */ | |
155 | if (e_options++) { | |
156 | ovs_fatal(0, "-e or --execute may be speciifed only once"); | |
064af421 BP |
157 | } |
158 | break; | |
159 | ||
160 | case 'h': | |
3fbe1d30 | 161 | usage(); |
064af421 BP |
162 | break; |
163 | ||
66fa2c88 | 164 | case 'o': |
5f383751 | 165 | ovs_cmdl_print_options(long_options); |
66fa2c88 AW |
166 | exit(EXIT_SUCCESS); |
167 | ||
f4ec6ff4 | 168 | case 'T': |
cbcf40a8 IM |
169 | if (!str_to_uint(optarg, 10, &timeout) || !timeout) { |
170 | ovs_fatal(0, "value %s on -T or --timeout is invalid", optarg); | |
cbcf40a8 | 171 | } |
f4ec6ff4 EJ |
172 | break; |
173 | ||
064af421 | 174 | case 'V': |
55d5bb44 | 175 | ovs_print_version(0, 0); |
064af421 BP |
176 | exit(EXIT_SUCCESS); |
177 | ||
9664732f BP |
178 | VLOG_OPTION_HANDLERS |
179 | ||
064af421 BP |
180 | case '?': |
181 | exit(EXIT_FAILURE); | |
182 | ||
183 | default: | |
428b2edd | 184 | OVS_NOT_REACHED(); |
064af421 BP |
185 | } |
186 | } | |
9664732f BP |
187 | free(short_options_); |
188 | free(short_options); | |
3fbe1d30 | 189 | |
9551e80b IM |
190 | ctl_timeout_setup(timeout); |
191 | ||
3fbe1d30 BP |
192 | if (optind >= argc) { |
193 | ovs_fatal(0, "at least one non-option argument is required " | |
194 | "(use --help for help)"); | |
195 | } | |
196 | ||
197 | return target ? target : "ovs-vswitchd"; | |
198 | } | |
199 | ||
bde9f75d | 200 | static struct jsonrpc * |
3fbe1d30 BP |
201 | connect_to_target(const char *target) |
202 | { | |
bde9f75d | 203 | struct jsonrpc *client; |
3fbe1d30 BP |
204 | char *socket_name; |
205 | int error; | |
206 | ||
a085daef | 207 | #ifndef _WIN32 |
3fbe1d30 BP |
208 | if (target[0] != '/') { |
209 | char *pidfile_name; | |
3fbe1d30 BP |
210 | pid_t pid; |
211 | ||
b43c6fe2 | 212 | pidfile_name = xasprintf("%s/%s.pid", ovs_rundir(), target); |
3fbe1d30 BP |
213 | pid = read_pidfile(pidfile_name); |
214 | if (pid < 0) { | |
215 | ovs_fatal(-pid, "cannot read pidfile \"%s\"", pidfile_name); | |
216 | } | |
217 | free(pidfile_name); | |
218 | socket_name = xasprintf("%s/%s.%ld.ctl", | |
b43c6fe2 | 219 | ovs_rundir(), target, (long int) pid); |
a085daef GS |
220 | #else |
221 | /* On windows, if the 'target' contains ':', we make an assumption that | |
222 | * it is an absolute path. */ | |
223 | if (!strchr(target, ':')) { | |
224 | socket_name = xasprintf("%s/%s.ctl", ovs_rundir(), target); | |
225 | #endif | |
3fbe1d30 BP |
226 | } else { |
227 | socket_name = xstrdup(target); | |
228 | } | |
229 | ||
230 | error = unixctl_client_create(socket_name, &client); | |
231 | if (error) { | |
232 | ovs_fatal(error, "cannot connect to \"%s\"", socket_name); | |
064af421 | 233 | } |
3fbe1d30 BP |
234 | free(socket_name); |
235 | ||
236 | return client; | |
064af421 | 237 | } |
3fbe1d30 | 238 |