initscript: pass complete path to pidfile to status command
[sliver-openvswitch.git] / utilities / ovs-cfg-mod.c
1 /* Copyright (c) 2008, 2009  Nicira Networks
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <config.h>
16
17 #include <dirent.h>
18 #include <errno.h>
19 #include <getopt.h>
20 #include <stdarg.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24
25 #include "cfg.h"
26 #include "command-line.h"
27 #include "svec.h"
28 #include "timeval.h"
29 #include "util.h"
30
31 #define THIS_MODULE VLM_cfg_mod
32 #include "vlog.h"
33
34 /* Configuration when we first read the configuration file. */
35 static struct svec orig_cfg = SVEC_EMPTY_INITIALIZER;
36
37 static void
38 usage(char *prog_name, int exit_code)
39 {
40     printf("Usage: %s --config-file=FILE ACTIONS\n"
41            "\nConfig:\n"
42            "  -T, --timeout=MS        wait at most MS milliseconds for lock\n"
43            "  -F, --config-file=FILE  use configuration FILE\n"
44            "\nActions:\n"
45            "  -a, --add=ENTRY         add ENTRY\n"
46            "  -d, --del-entry=ENTRY   delete ENTRY\n"
47            "  -D, --del-section=KEY   delete section matching KEY\n"
48            "  --del-match=PATTERN     delete entries matching shell PATTERN\n"
49            "  -q, --query=KEY         return all entries matching KEY\n"
50            "  -c, --log-changes       log changes up to this point\n"
51            "\nOther options:\n"
52            "  -h, --help              display this help message\n"
53            "  -V, --version           display version information\n",
54            prog_name);
55     exit(exit_code);
56 }
57
58 static void 
59 open_config(char *config_file, int timeout) 
60 {
61     int error;
62
63     cfg_init();
64     error = cfg_set_file(config_file);
65     if (error) {
66         ovs_fatal(error, "failed to add configuration file \"%s\"",
67                 config_file);
68     }
69
70     error = cfg_lock(NULL, timeout);
71     if (error) {
72         ovs_fatal(error, "could not lock configuration file\n");
73     }
74
75     cfg_get_all(&orig_cfg);
76 }
77
78 static void
79 print_vals(char *key)
80 {
81     struct svec vals;
82     int i;
83
84     svec_init(&vals);
85     cfg_get_all_strings(&vals, "%s", key);
86
87     for (i=0; i<vals.n; i++) {
88         printf("%s\n", vals.names[i]);
89     }
90 }
91
92 static void
93 log_diffs(void)
94 {
95     struct svec new_cfg, removed, added;
96     size_t i;
97
98     svec_init(&new_cfg);
99     cfg_get_all(&new_cfg);
100     svec_diff(&orig_cfg, &new_cfg, &removed, NULL, &added);
101     if (removed.n || added.n) {
102         VLOG_INFO("configuration changes:");
103         for (i = 0; i < removed.n; i++) {
104             VLOG_INFO("-%s", removed.names[i]);
105         }
106         for (i = 0; i < added.n; i++) {
107             VLOG_INFO("+%s", added.names[i]);
108         }
109     } else {
110         VLOG_INFO("configuration unchanged");
111     }
112     svec_destroy(&added);
113     svec_destroy(&removed);
114     svec_swap(&new_cfg, &orig_cfg);
115     svec_destroy(&new_cfg);
116 }
117
118 int main(int argc, char *argv[])
119 {
120     enum {
121         OPT_DEL_MATCH = UCHAR_MAX + 1,
122     };
123     static const struct option long_options[] = {
124         {"config-file",  required_argument, 0, 'F'},
125         {"timeout",      required_argument, 0, 'T'},
126         {"add",          required_argument, 0, 'a'},
127         {"del-entry",    required_argument, 0, 'd'},
128         {"del-section",  required_argument, 0, 'D'},
129         {"del-match",    required_argument, 0, OPT_DEL_MATCH},
130         {"query",        required_argument, 0, 'q'},
131         {"changes",      no_argument, 0, 'c'},
132         {"verbose",      optional_argument, 0, 'v'},
133         {"help",         no_argument, 0, 'h'},
134         {"version",      no_argument, 0, 'V'},
135         {0, 0, 0, 0},
136     };
137     char *short_options;
138     bool config_set = false;
139     int timeout = INT_MAX;
140
141     set_program_name(argv[0]);
142     time_init();
143     vlog_init();
144
145     short_options = long_options_to_short_options(long_options);
146     for (;;) {
147         int option;
148
149         option = getopt_long(argc, argv, short_options, long_options, NULL);
150         if (option == -1) {
151             break;
152         }
153
154         if ((option > UCHAR_MAX || !strchr("FhVv?", option))
155             && config_set == false) {
156             ovs_fatal(0, "no config file specified (use --help for help)");
157         }
158
159         switch (option) {
160         case 'T':
161             if (config_set) {
162                 ovs_fatal(0, "--timeout or -T must be specified "
163                           "before --file or -F");
164             }
165             timeout = atoi(optarg);
166             break;
167
168         case 'F': 
169             open_config(optarg, timeout);
170             config_set = true;
171             break;
172
173        case 'a':
174             cfg_add_entry("%s", optarg);
175             break;
176
177         case 'd':
178             cfg_del_entry("%s", optarg);
179             break;
180
181         case 'D':
182             cfg_del_section("%s", optarg);
183             break;
184
185         case OPT_DEL_MATCH:
186             cfg_del_match("%s", optarg);
187             break;
188
189         case 'q':
190             print_vals(optarg);
191             break;
192
193         case 'c':
194             log_diffs();
195             break;
196
197         case 'h':
198             usage(argv[0], EXIT_SUCCESS);
199             break;
200
201         case 'V':
202             OVS_PRINT_VERSION(0, 0);
203             exit(EXIT_SUCCESS);
204
205         case 'v':
206             vlog_set_verbosity(optarg);
207             break;
208
209         case '?':
210             exit(EXIT_FAILURE);
211
212         default:
213             NOT_REACHED();
214         }
215     }
216     free(short_options);
217
218     if (optind != argc) {
219         ovs_fatal(0, "non-option arguments not accepted "
220                   "(use --help for help)");
221     }
222
223     if (cfg_is_dirty()) {
224         cfg_write();
225     }
226     cfg_unlock();
227
228     exit(0);
229 }