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