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