88ecfe324ac4934dd8602825ae3c621d1571453b
[sliver-openvswitch.git] / utilities / ovs-appctl.c
1 /*
2  * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
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
19 #include <errno.h>
20 #include <getopt.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24
25 #include "command-line.h"
26 #include "daemon.h"
27 #include "dirs.h"
28 #include "dynamic-string.h"
29 #include "timeval.h"
30 #include "unixctl.h"
31 #include "util.h"
32
33 static void usage(void);
34 static const char *parse_command_line(int argc, char *argv[]);
35 static struct unixctl_client *connect_to_target(const char *target);
36
37 int
38 main(int argc, char *argv[])
39 {
40     struct unixctl_client *client;
41     const char *target;
42     struct ds request;
43     int code, error;
44     char *reply;
45     int i;
46
47     set_program_name(argv[0]);
48
49     /* Parse command line and connect to target. */
50     target = parse_command_line(argc, argv);
51     client = connect_to_target(target);
52
53     /* Compose request. */
54     ds_init(&request);
55     for (i = optind; i < argc; i++) {
56         if (i != optind) {
57             ds_put_char(&request, ' ');
58         }
59         ds_put_cstr(&request, argv[i]);
60     }
61
62     /* Transact request and process reply. */
63     error = unixctl_client_transact(client, ds_cstr(&request), &code, &reply);
64     if (error) {
65         ovs_fatal(error, "%s: transaction error", target);
66     }
67     if (code / 100 != 2) {
68         fputs(reply, stderr);
69         ovs_error(0, "%s: server returned reply code %03d", target, code);
70         exit(2);
71     }
72     fputs(reply, stdout);
73
74     unixctl_client_destroy(client);
75     free(reply);
76     ds_destroy(&request);
77
78     return 0;
79 }
80
81 static void
82 usage(void)
83 {
84     printf("%s, for querying and controlling Open vSwitch daemon\n"
85            "usage: %s [TARGET] COMMAND [ARG...]\n"
86            "Targets:\n"
87            "  -t, --target=TARGET  pidfile or socket to contact\n"
88            "Common commands:\n"
89            "  help               List commands supported by the target\n"
90            "  vlog/list          List current logging levels\n"
91            "  vlog/set MODULE[:FACILITY[:LEVEL]]\n"
92            "        Set MODULE and FACILITY log level to LEVEL\n"
93            "        MODULE may be any valid module name or 'ANY'\n"
94            "        FACILITY may be 'syslog', 'console', 'file', or 'ANY' (default)\n"
95            "        LEVEL may be 'emer', 'err', 'warn', 'info', or 'dbg' (default)\n"
96            "  vlog/reopen        Make the program reopen its log file\n"
97            "Other options:\n"
98            "  -h, --help         Print this helpful information\n"
99            "  -V, --version      Display version information\n",
100            program_name, program_name);
101     exit(EXIT_SUCCESS);
102 }
103
104 static const char *
105 parse_command_line(int argc, char *argv[])
106 {
107     static const struct option long_options[] = {
108         {"target", required_argument, NULL, 't'},
109         {"execute", no_argument, NULL, 'e'},
110         {"help", no_argument, NULL, 'h'},
111         {"version", no_argument, NULL, 'V'},
112         {NULL, 0, NULL, 0},
113     };
114     const char *target;
115     int e_options;
116
117     target = NULL;
118     e_options = 0;
119     for (;;) {
120         int option;
121
122         option = getopt_long(argc, argv, "+t:hVe", long_options, NULL);
123         if (option == -1) {
124             break;
125         }
126         switch (option) {
127         case 't':
128             if (target) {
129                 ovs_fatal(0, "-t or --target may be specified only once");
130             }
131             target = optarg;
132             break;
133
134         case 'e':
135             /* We ignore -e for compatibility.  Older versions specified the
136              * command as the argument to -e.  Since the current version takes
137              * the command as non-option arguments and we say that -e has no
138              * arguments, this just works in the common case. */
139             if (e_options++) {
140                 ovs_fatal(0, "-e or --execute may be speciifed only once");
141             }
142             break;
143
144         case 'h':
145             usage();
146             break;
147
148         case 'V':
149             OVS_PRINT_VERSION(0, 0);
150             exit(EXIT_SUCCESS);
151
152         case '?':
153             exit(EXIT_FAILURE);
154
155         default:
156             NOT_REACHED();
157         }
158     }
159
160     if (optind >= argc) {
161         ovs_fatal(0, "at least one non-option argument is required "
162                   "(use --help for help)");
163     }
164
165     return target ? target : "ovs-vswitchd";
166 }
167
168 static struct unixctl_client *
169 connect_to_target(const char *target)
170 {
171     struct unixctl_client *client;
172     char *socket_name;
173     int error;
174
175     if (target[0] != '/') {
176         char *pidfile_name;
177         pid_t pid;
178
179         pidfile_name = xasprintf("%s/%s.pid", ovs_rundir(), target);
180         pid = read_pidfile(pidfile_name);
181         if (pid < 0) {
182             ovs_fatal(-pid, "cannot read pidfile \"%s\"", pidfile_name);
183         }
184         free(pidfile_name);
185         socket_name = xasprintf("%s/%s.%ld.ctl",
186                                 ovs_rundir(), target, (long int) pid);
187     } else {
188         socket_name = xstrdup(target);
189     }
190
191     error = unixctl_client_create(socket_name, &client);
192     if (error) {
193         ovs_fatal(error, "cannot connect to \"%s\"", socket_name);
194     }
195     free(socket_name);
196
197     return client;
198 }
199