]> git.proxmox.com Git - mirror_frr.git/blob - lib/libfrr.c
16681fe578535c2420bb7eb90ad3c3ed101ca857
[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
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 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 };
77 static const struct optspec os_always = {
78 "hvdM:",
79 " -h, --help Display this help and exit\n"
80 " -v, --version Print program version\n"
81 " -d, --daemon Runs in daemon mode\n"
82 " -M, --module Load specified module\n"
83 " --vty_socket Override vty socket path\n"
84 " --moduledir Override modules directory\n",
85 lo_always
86 };
87
88
89 static const struct option lo_cfg_pid_dry[] = {
90 { "pid_file", required_argument, NULL, 'i' },
91 { "config_file", required_argument, NULL, 'f' },
92 { "dryrun", no_argument, NULL, 'C' },
93 { NULL }
94 };
95 static const struct optspec os_cfg_pid_dry = {
96 "f:i:C",
97 " -f, --config_file Set configuration file name\n"
98 " -i, --pid_file Set process identifier file name\n"
99 " -C, --dryrun Check configuration for validity and exit\n",
100 lo_cfg_pid_dry
101 };
102
103
104 static const struct option lo_zclient[] = {
105 { "socket", required_argument, NULL, 'z' },
106 { NULL }
107 };
108 static const struct optspec os_zclient = {
109 "z:",
110 " -z, --socket Set path of zebra socket\n",
111 lo_zclient
112 };
113
114
115 static const struct option lo_vty[] = {
116 { "vty_addr", required_argument, NULL, 'A'},
117 { "vty_port", required_argument, NULL, 'P'},
118 { NULL }
119 };
120 static const struct optspec os_vty = {
121 "A:P:",
122 " -A, --vty_addr Set vty's bind address\n"
123 " -P, --vty_port Set vty's port number\n",
124 lo_vty
125 };
126
127
128 static const struct option lo_user[] = {
129 { "user", required_argument, NULL, 'u'},
130 { "group", required_argument, NULL, 'g'},
131 { NULL }
132 };
133 static const struct optspec os_user = {
134 "u:g:",
135 " -u, --user User to run as\n"
136 " -g, --group Group to run as\n",
137 lo_user
138 };
139
140
141 static struct frr_daemon_info *di = NULL;
142
143 void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv)
144 {
145 di = daemon;
146
147 /* basename(), opencoded. */
148 char *p = strrchr(argv[0], '/');
149 di->progname = p ? p + 1 : argv[0];
150
151 umask(0027);
152
153 opt_extend(&os_always);
154 if (!(di->flags & FRR_NO_CFG_PID_DRY))
155 opt_extend(&os_cfg_pid_dry);
156 if (!(di->flags & FRR_NO_PRIVSEP))
157 opt_extend(&os_user);
158 if (!(di->flags & FRR_NO_ZCLIENT))
159 opt_extend(&os_zclient);
160 if (!(di->flags & FRR_NO_TCPVTY))
161 opt_extend(&os_vty);
162
163 snprintf(config_default, sizeof(config_default), "%s/%s.conf",
164 frr_sysconfdir, di->name);
165 snprintf(pidfile_default, sizeof(pidfile_default), "%s/%s.pid",
166 frr_vtydir, di->name);
167 }
168
169 void frr_opt_add(const char *optstr, const struct option *longopts,
170 const char *helpstr)
171 {
172 const struct optspec main_opts = { optstr, helpstr, longopts };
173 opt_extend(&main_opts);
174 }
175
176 void frr_help_exit(int status)
177 {
178 FILE *target = status ? stderr : stdout;
179
180 if (status != 0)
181 fprintf(stderr, "Invalid options.\n\n");
182
183 if (di->printhelp)
184 di->printhelp(target);
185 else
186 fprintf(target, "Usage: %s [OPTION...]\n\n%s%s%s\n\n%s",
187 di->progname,
188 di->proghelp,
189 di->copyright ? "\n\n" : "",
190 di->copyright ? di->copyright : "",
191 comb_helpstr);
192 fprintf(target, "\nReport bugs to %s\n", FRR_BUG_ADDRESS);
193 exit(status);
194 }
195
196 struct option_chain {
197 struct option_chain *next;
198 const char *arg;
199 };
200
201 static struct option_chain *modules = NULL, **modnext = &modules;
202 static int errors = 0;
203
204 static int frr_opt(int opt)
205 {
206 static int vty_port_set = 0;
207 static int vty_addr_set = 0;
208 struct option_chain *oc;
209 char *err;
210
211 switch (opt) {
212 case 'h':
213 frr_help_exit(0);
214 break;
215 case 'v':
216 print_version(di->progname);
217 exit(0);
218 break;
219 case 'd':
220 di->daemon_mode = 1;
221 break;
222 case 'M':
223 oc = XMALLOC(MTYPE_TMP, sizeof(*oc));
224 oc->arg = optarg;
225 oc->next = NULL;
226 *modnext = oc;
227 modnext = &oc->next;
228 break;
229 case 'i':
230 if (di->flags & FRR_NO_CFG_PID_DRY)
231 return 1;
232 di->pid_file = optarg;
233 break;
234 case 'f':
235 if (di->flags & FRR_NO_CFG_PID_DRY)
236 return 1;
237 di->config_file = optarg;
238 break;
239 case 'C':
240 if (di->flags & FRR_NO_CFG_PID_DRY)
241 return 1;
242 di->dryrun = 1;
243 break;
244 case 'z':
245 if (di->flags & FRR_NO_ZCLIENT)
246 return 1;
247 zclient_serv_path_set(optarg);
248 break;
249 case 'A':
250 if (di->flags & FRR_NO_TCPVTY)
251 return 1;
252 if (vty_addr_set) {
253 fprintf(stderr, "-A option specified more than once!\n");
254 errors++;
255 break;
256 }
257 vty_addr_set = 1;
258 di->vty_addr = optarg;
259 break;
260 case 'P':
261 if (di->flags & FRR_NO_TCPVTY)
262 return 1;
263 if (vty_port_set) {
264 fprintf(stderr, "-P option specified more than once!\n");
265 errors++;
266 break;
267 }
268 vty_port_set = 1;
269 di->vty_port = strtoul(optarg, &err, 0);
270 if (*err || !*optarg) {
271 fprintf(stderr, "invalid port number \"%s\" for -P option\n",
272 optarg);
273 errors++;
274 break;
275 }
276 break;
277 case OPTION_VTYSOCK:
278 if (di->vty_sock_path) {
279 fprintf(stderr, "--vty_socket option specified more than once!\n");
280 errors++;
281 break;
282 }
283 di->vty_sock_path = optarg;
284 break;
285 case OPTION_MODULEDIR:
286 if (di->module_path) {
287 fprintf(stderr, "----moduledir option specified more than once!\n");
288 errors++;
289 break;
290 }
291 di->module_path = optarg;
292 break;
293 case 'u':
294 if (di->flags & FRR_NO_PRIVSEP)
295 return 1;
296 di->privs->user = optarg;
297 break;
298 case 'g':
299 if (di->flags & FRR_NO_PRIVSEP)
300 return 1;
301 di->privs->group = optarg;
302 break;
303 default:
304 return 1;
305 }
306 return 0;
307 }
308
309 int frr_getopt(int argc, char * const argv[], int *longindex)
310 {
311 int opt;
312 int lidx;
313
314 comb_next_lo->name = NULL;
315
316 do {
317 opt = getopt_long(argc, argv, comb_optstr, comb_lo, &lidx);
318 if (frr_opt(opt))
319 break;
320 } while (opt != -1);
321
322 if (opt == -1 && errors)
323 frr_help_exit(1);
324 if (longindex)
325 *longindex = lidx;
326 return opt;
327 }
328
329 static struct thread_master *master;
330 struct thread_master *frr_init(void)
331 {
332 struct option_chain *oc;
333 struct frrmod_runtime *module;
334 char moderr[256];
335 const char *dir;
336 dir = di->module_path ? di->module_path : frr_moduledir;
337
338 srandom(time(NULL));
339
340 openzlog (di->progname, di->logname, di->instance,
341 LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON);
342 #if defined(HAVE_CUMULUS)
343 zlog_set_level (ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
344 #endif
345
346 frrmod_init(di->module);
347 while (modules) {
348 modules = (oc = modules)->next;
349 module = frrmod_load(oc->arg, dir, moderr, sizeof(moderr));
350 if (!module) {
351 fprintf(stderr, "%s\n", moderr);
352 exit(1);
353 }
354 XFREE(MTYPE_TMP, oc);
355 }
356
357 zprivs_init(di->privs);
358
359 master = thread_master_create();
360 signal_init(master, di->n_signals, di->signals);
361
362 if (di->flags & FRR_LIMITED_CLI)
363 cmd_init(-1);
364 else
365 cmd_init(1);
366 vty_init(master);
367 memory_init();
368
369 return master;
370 }
371
372 void frr_config_fork(void)
373 {
374 hook_call(frr_late_init, master);
375
376 if (di->instance) {
377 snprintf(config_default, sizeof(config_default), "%s/%s-%d.conf",
378 frr_sysconfdir, di->name, di->instance);
379 snprintf(pidfile_default, sizeof(pidfile_default), "%s/%s-%d.pid",
380 frr_vtydir, di->name, di->instance);
381 }
382
383 vty_read_config(di->config_file, config_default);
384
385 /* Don't start execution if we are in dry-run mode */
386 if (di->dryrun)
387 exit(0);
388
389 /* Daemonize. */
390 if (di->daemon_mode && daemon (0, 0) < 0) {
391 zlog_err("Zebra daemon failed: %s", strerror(errno));
392 exit(1);
393 }
394
395 if (!di->pid_file)
396 di->pid_file = pidfile_default;
397 pid_output (di->pid_file);
398 }
399
400 void frr_vty_serv(void)
401 {
402 /* allow explicit override of vty_path in the future
403 * (not currently set anywhere) */
404 if (!di->vty_path) {
405 const char *dir;
406 dir = di->vty_sock_path ? di->vty_sock_path : frr_vtydir;
407
408 if (di->instance)
409 snprintf(vtypath_default, sizeof(vtypath_default),
410 "%s/%s-%d.vty",
411 dir, di->name, di->instance);
412 else
413 snprintf(vtypath_default, sizeof(vtypath_default),
414 "%s/%s.vty", dir, di->name);
415
416 di->vty_path = vtypath_default;
417 }
418
419 vty_serv_sock(di->vty_addr, di->vty_port, di->vty_path);
420 }
421
422 void frr_run(struct thread_master *master)
423 {
424 char instanceinfo[64] = "";
425
426 frr_vty_serv();
427
428 if (di->instance)
429 snprintf(instanceinfo, sizeof(instanceinfo), "instance %u ",
430 di->instance);
431
432 zlog_notice("%s %s starting: %svty@%d%s",
433 di->name,
434 FRR_VERSION,
435 instanceinfo,
436 di->vty_port,
437 di->startinfo);
438
439 struct thread thread;
440 while (thread_fetch(master, &thread))
441 thread_call(&thread);
442 }