Import from old repository commit 61ef2b42a9c4ba8e1600f15bb0236765edc2ad45.
[openvswitch] / utilities / ovs-cfg-mod.c
1 /* Copyright (c) 2008, 2009  Nicira Networks
2  * 
3  * This program is free software: you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation, either version 3 of the License, or
6  * (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15  *
16  * In addition, as a special exception, Nicira Networks gives permission
17  * to link the code of its release of vswitchd with the OpenSSL project's
18  * "OpenSSL" library (or with modified versions of it that use the same
19  * license as the "OpenSSL" library), and distribute the linked
20  * executables.  You must obey the GNU General Public License in all
21  * respects for all of the code used other than "OpenSSL".  If you modify
22  * this file, you may extend this exception to your version of the file,
23  * but you are not obligated to do so.  If you do not wish to do so,
24  * delete this exception statement from your version.
25  */
26 #include <config.h>
27
28 #include <dirent.h>
29 #include <errno.h>
30 #include <getopt.h>
31 #include <stdarg.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <stdlib.h>
35
36 #include "cfg.h"
37 #include "command-line.h"
38 #include "svec.h"
39 #include "timeval.h"
40 #include "util.h"
41
42 #define THIS_MODULE VLM_cfg_mod
43 #include "vlog.h"
44
45 /* Configuration when we first read the configuration file. */
46 static struct svec orig_cfg = SVEC_EMPTY_INITIALIZER;
47
48 static void
49 usage(char *prog_name, int exit_code)
50 {
51     printf("Usage: %s --config-file=FILE ACTIONS\n"
52            "\nConfig:\n"
53            "  -T, --timeout=MS        wait at most MS milliseconds for lock\n"
54            "  -F, --config-file=FILE  use configuration FILE\n"
55            "\nActions:\n"
56            "  -a, --add=ENTRY         add ENTRY\n"
57            "  -d, --del-entry=ENTRY   delete ENTRY\n"
58            "  -D, --del-section=KEY   delete section matching KEY\n"
59            "  --del-match=PATTERN     delete entries matching shell PATTERN\n"
60            "  -q, --query=KEY         return all entries matching KEY\n"
61            "  -c, --log-changes       log changes up to this point\n"
62            "\nOther options:\n"
63            "  -h, --help              display this help message\n"
64            "  -V, --version           display version information\n",
65            prog_name);
66     exit(exit_code);
67 }
68
69 static void 
70 open_config(char *config_file, int timeout) 
71 {
72     int error;
73
74     error = cfg_set_file(config_file);
75     if (error) {
76         ovs_fatal(error, "failed to add configuration file \"%s\"",
77                 config_file);
78     }
79
80     error = cfg_lock(NULL, timeout);
81     if (error) {
82         ovs_fatal(error, "could not lock configuration file\n");
83     }
84
85     cfg_get_all(&orig_cfg);
86 }
87
88 static void
89 print_vals(char *key)
90 {
91     struct svec vals;
92     int i;
93
94     svec_init(&vals);
95     cfg_get_all_strings(&vals, "%s", key);
96
97     for (i=0; i<vals.n; i++) {
98         printf("%s\n", vals.names[i]);
99     }
100 }
101
102 static void
103 log_diffs(void)
104 {
105     struct svec new_cfg, removed, added;
106     size_t i;
107
108     svec_init(&new_cfg);
109     cfg_get_all(&new_cfg);
110     svec_diff(&orig_cfg, &new_cfg, &removed, NULL, &added);
111     if (removed.n || added.n) {
112         VLOG_INFO("configuration changes:");
113         for (i = 0; i < removed.n; i++) {
114             VLOG_INFO("-%s", removed.names[i]);
115         }
116         for (i = 0; i < added.n; i++) {
117             VLOG_INFO("+%s", added.names[i]);
118         }
119     } else {
120         VLOG_INFO("configuration unchanged");
121     }
122     svec_destroy(&added);
123     svec_destroy(&removed);
124     svec_swap(&new_cfg, &orig_cfg);
125     svec_destroy(&new_cfg);
126 }
127
128 int main(int argc, char *argv[])
129 {
130     enum {
131         OPT_DEL_MATCH = UCHAR_MAX + 1,
132     };
133     static const struct option long_options[] = {
134         {"config-file",  required_argument, 0, 'F'},
135         {"timeout",      required_argument, 0, 'T'},
136         {"add",          required_argument, 0, 'a'},
137         {"del-entry",    required_argument, 0, 'd'},
138         {"del-section",  required_argument, 0, 'D'},
139         {"del-match",    required_argument, 0, OPT_DEL_MATCH},
140         {"query",        required_argument, 0, 'q'},
141         {"changes",      no_argument, 0, 'c'},
142         {"verbose",      optional_argument, 0, 'v'},
143         {"help",         no_argument, 0, 'h'},
144         {"version",      no_argument, 0, 'V'},
145         {0, 0, 0, 0},
146     };
147     char *short_options;
148     bool config_set = false;
149     int timeout = INT_MAX;
150
151     set_program_name(argv[0]);
152     time_init();
153     vlog_init();
154
155     short_options = long_options_to_short_options(long_options);
156     for (;;) {
157         int option;
158
159         option = getopt_long(argc, argv, short_options, long_options, NULL);
160         if (option == -1) {
161             break;
162         }
163
164         if ((option > UCHAR_MAX || !strchr("FhVv?", option))
165             && config_set == false) {
166             ovs_fatal(0, "no config file specified (use --help for help)");
167         }
168
169         switch (option) {
170         case 'T':
171             if (config_set) {
172                 ovs_fatal(0, "--timeout or -T must be specified "
173                           "before --file or -F");
174             }
175             timeout = atoi(optarg);
176             break;
177
178         case 'F': 
179             open_config(optarg, timeout);
180             config_set = true;
181             break;
182
183        case 'a':
184             cfg_add_entry("%s", optarg);
185             break;
186
187         case 'd':
188             cfg_del_entry("%s", optarg);
189             break;
190
191         case 'D':
192             cfg_del_section("%s", optarg);
193             break;
194
195         case OPT_DEL_MATCH:
196             cfg_del_match("%s", optarg);
197             break;
198
199         case 'q':
200             print_vals(optarg);
201             break;
202
203         case 'c':
204             log_diffs();
205             break;
206
207         case 'h':
208             usage(argv[0], EXIT_SUCCESS);
209             break;
210
211         case 'V':
212             OVS_PRINT_VERSION(0, 0);
213             exit(EXIT_SUCCESS);
214
215         case 'v':
216             vlog_set_verbosity(optarg);
217             break;
218
219         case '?':
220             exit(EXIT_FAILURE);
221
222         default:
223             NOT_REACHED();
224         }
225     }
226     free(short_options);
227
228     if (optind != argc) {
229         ovs_fatal(0, "non-option arguments not accepted "
230                   "(use --help for help)");
231     }
232
233     if (cfg_is_dirty()) {
234         cfg_write();
235     }
236     cfg_unlock();
237
238     exit(0);
239 }