Update primary code license to Apache 2.0.
[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     error = cfg_set_file(config_file);
64     if (error) {
65         ovs_fatal(error, "failed to add configuration file \"%s\"",
66                 config_file);
67     }
68
69     error = cfg_lock(NULL, timeout);
70     if (error) {
71         ovs_fatal(error, "could not lock configuration file\n");
72     }
73
74     cfg_get_all(&orig_cfg);
75 }
76
77 static void
78 print_vals(char *key)
79 {
80     struct svec vals;
81     int i;
82
83     svec_init(&vals);
84     cfg_get_all_strings(&vals, "%s", key);
85
86     for (i=0; i<vals.n; i++) {
87         printf("%s\n", vals.names[i]);
88     }
89 }
90
91 static void
92 log_diffs(void)
93 {
94     struct svec new_cfg, removed, added;
95     size_t i;
96
97     svec_init(&new_cfg);
98     cfg_get_all(&new_cfg);
99     svec_diff(&orig_cfg, &new_cfg, &removed, NULL, &added);
100     if (removed.n || added.n) {
101         VLOG_INFO("configuration changes:");
102         for (i = 0; i < removed.n; i++) {
103             VLOG_INFO("-%s", removed.names[i]);
104         }
105         for (i = 0; i < added.n; i++) {
106             VLOG_INFO("+%s", added.names[i]);
107         }
108     } else {
109         VLOG_INFO("configuration unchanged");
110     }
111     svec_destroy(&added);
112     svec_destroy(&removed);
113     svec_swap(&new_cfg, &orig_cfg);
114     svec_destroy(&new_cfg);
115 }
116
117 int main(int argc, char *argv[])
118 {
119     enum {
120         OPT_DEL_MATCH = UCHAR_MAX + 1,
121     };
122     static const struct option long_options[] = {
123         {"config-file",  required_argument, 0, 'F'},
124         {"timeout",      required_argument, 0, 'T'},
125         {"add",          required_argument, 0, 'a'},
126         {"del-entry",    required_argument, 0, 'd'},
127         {"del-section",  required_argument, 0, 'D'},
128         {"del-match",    required_argument, 0, OPT_DEL_MATCH},
129         {"query",        required_argument, 0, 'q'},
130         {"changes",      no_argument, 0, 'c'},
131         {"verbose",      optional_argument, 0, 'v'},
132         {"help",         no_argument, 0, 'h'},
133         {"version",      no_argument, 0, 'V'},
134         {0, 0, 0, 0},
135     };
136     char *short_options;
137     bool config_set = false;
138     int timeout = INT_MAX;
139
140     set_program_name(argv[0]);
141     time_init();
142     vlog_init();
143
144     short_options = long_options_to_short_options(long_options);
145     for (;;) {
146         int option;
147
148         option = getopt_long(argc, argv, short_options, long_options, NULL);
149         if (option == -1) {
150             break;
151         }
152
153         if ((option > UCHAR_MAX || !strchr("FhVv?", option))
154             && config_set == false) {
155             ovs_fatal(0, "no config file specified (use --help for help)");
156         }
157
158         switch (option) {
159         case 'T':
160             if (config_set) {
161                 ovs_fatal(0, "--timeout or -T must be specified "
162                           "before --file or -F");
163             }
164             timeout = atoi(optarg);
165             break;
166
167         case 'F': 
168             open_config(optarg, timeout);
169             config_set = true;
170             break;
171
172        case 'a':
173             cfg_add_entry("%s", optarg);
174             break;
175
176         case 'd':
177             cfg_del_entry("%s", optarg);
178             break;
179
180         case 'D':
181             cfg_del_section("%s", optarg);
182             break;
183
184         case OPT_DEL_MATCH:
185             cfg_del_match("%s", optarg);
186             break;
187
188         case 'q':
189             print_vals(optarg);
190             break;
191
192         case 'c':
193             log_diffs();
194             break;
195
196         case 'h':
197             usage(argv[0], EXIT_SUCCESS);
198             break;
199
200         case 'V':
201             OVS_PRINT_VERSION(0, 0);
202             exit(EXIT_SUCCESS);
203
204         case 'v':
205             vlog_set_verbosity(optarg);
206             break;
207
208         case '?':
209             exit(EXIT_FAILURE);
210
211         default:
212             NOT_REACHED();
213         }
214     }
215     free(short_options);
216
217     if (optind != argc) {
218         ovs_fatal(0, "non-option arguments not accepted "
219                   "(use --help for help)");
220     }
221
222     if (cfg_is_dirty()) {
223         cfg_write();
224     }
225     cfg_unlock();
226
227     exit(0);
228 }