]> git.proxmox.com Git - mirror_frr.git/blob - lib/libfrr.c
release: FRR 3.0-rc1
[mirror_frr.git] / lib / libfrr.c
1 /*
2 * libfrr overall management functions
3 *
4 * Copyright (C) 2016 David Lamparter for NetDEF, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
18 * Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include <zebra.h>
22
23 #include "libfrr.h"
24 #include "getopt.h"
25 #include "vty.h"
26 #include "command.h"
27 #include "version.h"
28 #include "memory_vty.h"
29 #include "zclient.h"
30 #include "log_int.h"
31 #include "module.h"
32
33 DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm))
34
35 const char frr_sysconfdir[] = SYSCONFDIR;
36 const char frr_vtydir[] = DAEMON_VTY_DIR;
37 const char frr_moduledir[] = MODULE_PATH;
38
39 char config_default[256];
40 static char pidfile_default[256];
41 static char vtypath_default[256];
42
43 static char comb_optstr[256];
44 static struct option comb_lo[64];
45 static struct option *comb_next_lo = &comb_lo[0];
46 static char comb_helpstr[4096];
47
48 struct optspec {
49 const char *optstr;
50 const char *helpstr;
51 const struct option *longopts;
52 };
53
54 static void opt_extend(const struct optspec *os)
55 {
56 const struct option *lo;
57
58 strcat(comb_optstr, os->optstr);
59 strcat(comb_helpstr, os->helpstr);
60 for (lo = os->longopts; lo->name; lo++)
61 memcpy(comb_next_lo++, lo, sizeof(*lo));
62 }
63
64
65 #define OPTION_VTYSOCK 1000
66 #define OPTION_MODULEDIR 1002
67
68 static const struct option lo_always[] = {
69 {"help", no_argument, NULL, 'h'},
70 {"version", no_argument, NULL, 'v'},
71 {"daemon", no_argument, NULL, 'd'},
72 {"module", no_argument, NULL, 'M'},
73 {"vty_socket", required_argument, NULL, OPTION_VTYSOCK},
74 {"moduledir", required_argument, NULL, OPTION_MODULEDIR},
75 {NULL}};
76 static const struct optspec os_always = {
77 "hvdM:",
78 " -h, --help Display this help and exit\n"
79 " -v, --version Print program version\n"
80 " -d, --daemon Runs in daemon mode\n"
81 " -M, --module Load specified module\n"
82 " --vty_socket Override vty socket path\n"
83 " --moduledir Override modules directory\n",
84 lo_always};
85
86
87 static const struct option lo_cfg_pid_dry[] = {
88 {"pid_file", required_argument, NULL, 'i'},
89 {"config_file", required_argument, NULL, 'f'},
90 {"dryrun", no_argument, NULL, 'C'},
91 {NULL}};
92 static const struct optspec os_cfg_pid_dry = {
93 "f:i:C",
94 " -f, --config_file Set configuration file name\n"
95 " -i, --pid_file Set process identifier file name\n"
96 " -C, --dryrun Check configuration for validity and exit\n",
97 lo_cfg_pid_dry};
98
99
100 static const struct option lo_zclient[] = {
101 {"socket", required_argument, NULL, 'z'},
102 {NULL}};
103 static const struct optspec os_zclient = {
104 "z:", " -z, --socket Set path of zebra socket\n", lo_zclient};
105
106
107 static const struct option lo_vty[] = {
108 {"vty_addr", required_argument, NULL, 'A'},
109 {"vty_port", required_argument, NULL, 'P'},
110 {NULL}};
111 static const struct optspec os_vty = {
112 "A:P:",
113 " -A, --vty_addr Set vty's bind address\n"
114 " -P, --vty_port Set vty's port number\n",
115 lo_vty};
116
117
118 static const struct option lo_user[] = {{"user", required_argument, NULL, 'u'},
119 {"group", required_argument, NULL, 'g'},
120 {NULL}};
121 static const struct optspec os_user = {"u:g:",
122 " -u, --user User to run as\n"
123 " -g, --group Group to run as\n",
124 lo_user};
125
126
127 static struct frr_daemon_info *di = NULL;
128
129 void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv)
130 {
131 di = daemon;
132
133 /* basename(), opencoded. */
134 char *p = strrchr(argv[0], '/');
135 di->progname = p ? p + 1 : argv[0];
136
137 umask(0027);
138
139 opt_extend(&os_always);
140 if (!(di->flags & FRR_NO_CFG_PID_DRY))
141 opt_extend(&os_cfg_pid_dry);
142 if (!(di->flags & FRR_NO_PRIVSEP))
143 opt_extend(&os_user);
144 if (!(di->flags & FRR_NO_ZCLIENT))
145 opt_extend(&os_zclient);
146 if (!(di->flags & FRR_NO_TCPVTY))
147 opt_extend(&os_vty);
148
149 snprintf(config_default, sizeof(config_default), "%s/%s.conf",
150 frr_sysconfdir, di->name);
151 snprintf(pidfile_default, sizeof(pidfile_default), "%s/%s.pid",
152 frr_vtydir, di->name);
153 }
154
155 void frr_opt_add(const char *optstr, const struct option *longopts,
156 const char *helpstr)
157 {
158 const struct optspec main_opts = {optstr, helpstr, longopts};
159 opt_extend(&main_opts);
160 }
161
162 void frr_help_exit(int status)
163 {
164 FILE *target = status ? stderr : stdout;
165
166 if (status != 0)
167 fprintf(stderr, "Invalid options.\n\n");
168
169 if (di->printhelp)
170 di->printhelp(target);
171 else
172 fprintf(target, "Usage: %s [OPTION...]\n\n%s%s%s\n\n%s",
173 di->progname, di->proghelp, di->copyright ? "\n\n" : "",
174 di->copyright ? di->copyright : "", comb_helpstr);
175 fprintf(target, "\nReport bugs to %s\n", FRR_BUG_ADDRESS);
176 exit(status);
177 }
178
179 struct option_chain {
180 struct option_chain *next;
181 const char *arg;
182 };
183
184 static struct option_chain *modules = NULL, **modnext = &modules;
185 static int errors = 0;
186
187 static int frr_opt(int opt)
188 {
189 static int vty_port_set = 0;
190 static int vty_addr_set = 0;
191 struct option_chain *oc;
192 char *err;
193
194 switch (opt) {
195 case 'h':
196 frr_help_exit(0);
197 break;
198 case 'v':
199 print_version(di->progname);
200 exit(0);
201 break;
202 case 'd':
203 di->daemon_mode = 1;
204 break;
205 case 'M':
206 oc = XMALLOC(MTYPE_TMP, sizeof(*oc));
207 oc->arg = optarg;
208 oc->next = NULL;
209 *modnext = oc;
210 modnext = &oc->next;
211 break;
212 case 'i':
213 if (di->flags & FRR_NO_CFG_PID_DRY)
214 return 1;
215 di->pid_file = optarg;
216 break;
217 case 'f':
218 if (di->flags & FRR_NO_CFG_PID_DRY)
219 return 1;
220 di->config_file = optarg;
221 break;
222 case 'C':
223 if (di->flags & FRR_NO_CFG_PID_DRY)
224 return 1;
225 di->dryrun = 1;
226 break;
227 case 'z':
228 if (di->flags & FRR_NO_ZCLIENT)
229 return 1;
230 zclient_serv_path_set(optarg);
231 break;
232 case 'A':
233 if (di->flags & FRR_NO_TCPVTY)
234 return 1;
235 if (vty_addr_set) {
236 fprintf(stderr,
237 "-A option specified more than once!\n");
238 errors++;
239 break;
240 }
241 vty_addr_set = 1;
242 di->vty_addr = optarg;
243 break;
244 case 'P':
245 if (di->flags & FRR_NO_TCPVTY)
246 return 1;
247 if (vty_port_set) {
248 fprintf(stderr,
249 "-P option specified more than once!\n");
250 errors++;
251 break;
252 }
253 vty_port_set = 1;
254 di->vty_port = strtoul(optarg, &err, 0);
255 if (*err || !*optarg) {
256 fprintf(stderr,
257 "invalid port number \"%s\" for -P option\n",
258 optarg);
259 errors++;
260 break;
261 }
262 break;
263 case OPTION_VTYSOCK:
264 if (di->vty_sock_path) {
265 fprintf(stderr,
266 "--vty_socket option specified more than once!\n");
267 errors++;
268 break;
269 }
270 di->vty_sock_path = optarg;
271 break;
272 case OPTION_MODULEDIR:
273 if (di->module_path) {
274 fprintf(stderr,
275 "----moduledir option specified more than once!\n");
276 errors++;
277 break;
278 }
279 di->module_path = optarg;
280 break;
281 case 'u':
282 if (di->flags & FRR_NO_PRIVSEP)
283 return 1;
284 di->privs->user = optarg;
285 break;
286 case 'g':
287 if (di->flags & FRR_NO_PRIVSEP)
288 return 1;
289 di->privs->group = optarg;
290 break;
291 default:
292 return 1;
293 }
294 return 0;
295 }
296
297 int frr_getopt(int argc, char *const argv[], int *longindex)
298 {
299 int opt;
300 int lidx;
301
302 comb_next_lo->name = NULL;
303
304 do {
305 opt = getopt_long(argc, argv, comb_optstr, comb_lo, &lidx);
306 if (frr_opt(opt))
307 break;
308 } while (opt != -1);
309
310 if (opt == -1 && errors)
311 frr_help_exit(1);
312 if (longindex)
313 *longindex = lidx;
314 return opt;
315 }
316
317 static struct thread_master *master;
318 struct thread_master *frr_init(void)
319 {
320 struct option_chain *oc;
321 struct frrmod_runtime *module;
322 char moderr[256];
323 const char *dir;
324 dir = di->module_path ? di->module_path : frr_moduledir;
325
326 srandom(time(NULL));
327
328 openzlog(di->progname, di->logname, di->instance,
329 LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON);
330 #if defined(HAVE_CUMULUS)
331 zlog_set_level(ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
332 #endif
333
334 frrmod_init(di->module);
335 while (modules) {
336 modules = (oc = modules)->next;
337 module = frrmod_load(oc->arg, dir, moderr, sizeof(moderr));
338 if (!module) {
339 fprintf(stderr, "%s\n", moderr);
340 exit(1);
341 }
342 XFREE(MTYPE_TMP, oc);
343 }
344
345 zprivs_init(di->privs);
346
347 master = thread_master_create();
348 signal_init(master, di->n_signals, di->signals);
349
350 if (di->flags & FRR_LIMITED_CLI)
351 cmd_init(-1);
352 else
353 cmd_init(1);
354 vty_init(master);
355 memory_init();
356
357 return master;
358 }
359
360 void frr_config_fork(void)
361 {
362 hook_call(frr_late_init, master);
363
364 if (di->instance) {
365 snprintf(config_default, sizeof(config_default),
366 "%s/%s-%d.conf", frr_sysconfdir, di->name,
367 di->instance);
368 snprintf(pidfile_default, sizeof(pidfile_default),
369 "%s/%s-%d.pid", frr_vtydir, di->name, di->instance);
370 }
371
372 vty_read_config(di->config_file, config_default);
373
374 /* Don't start execution if we are in dry-run mode */
375 if (di->dryrun)
376 exit(0);
377
378 /* Daemonize. */
379 if (di->daemon_mode && daemon(0, 0) < 0) {
380 zlog_err("Zebra daemon failed: %s", strerror(errno));
381 exit(1);
382 }
383
384 if (!di->pid_file)
385 di->pid_file = pidfile_default;
386 pid_output(di->pid_file);
387 }
388
389 void frr_vty_serv(void)
390 {
391 /* allow explicit override of vty_path in the future
392 * (not currently set anywhere) */
393 if (!di->vty_path) {
394 const char *dir;
395 dir = di->vty_sock_path ? di->vty_sock_path : frr_vtydir;
396
397 if (di->instance)
398 snprintf(vtypath_default, sizeof(vtypath_default),
399 "%s/%s-%d.vty", dir, di->name, di->instance);
400 else
401 snprintf(vtypath_default, sizeof(vtypath_default),
402 "%s/%s.vty", dir, di->name);
403
404 di->vty_path = vtypath_default;
405 }
406
407 vty_serv_sock(di->vty_addr, di->vty_port, di->vty_path);
408 }
409
410 void frr_run(struct thread_master *master)
411 {
412 char instanceinfo[64] = "";
413
414 frr_vty_serv();
415
416 if (di->instance)
417 snprintf(instanceinfo, sizeof(instanceinfo), "instance %u ",
418 di->instance);
419
420 zlog_notice("%s %s starting: %svty@%d%s", di->name, FRR_VERSION,
421 instanceinfo, di->vty_port, di->startinfo);
422
423 struct thread thread;
424 while (thread_fetch(master, &thread))
425 thread_call(&thread);
426 }