]> git.proxmox.com Git - mirror_frr.git/blame - lib/libfrr.c
build: check for sendmmsg() and struct mmsghdr
[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>
689f5a8c 22#include <sys/un.h>
4f04a76b 23
f43fbf83
DL
24#include <sys/types.h>
25#include <sys/wait.h>
26
4f04a76b
DL
27#include "libfrr.h"
28#include "getopt.h"
beaa5470 29#include "privs.h"
4f04a76b
DL
30#include "vty.h"
31#include "command.h"
09781197 32#include "lib/version.h"
1c0d8808 33#include "lib_vty.h"
f73126c3 34#include "log_vty.h"
eb05883f 35#include "zclient.h"
30771d65 36#include "module.h"
f43fbf83 37#include "network.h"
b66d022e 38#include "lib_errors.h"
1c2facd1
RW
39#include "db.h"
40#include "northbound_cli.h"
1ae9686c 41#include "northbound_db.h"
ae0994f6 42#include "debug.h"
3e41733f 43#include "frrcu.h"
b9b4c061 44#include "frr_pthread.h"
ac4adef4 45#include "defaults.h"
e613a6f7 46#include "frrscript.h"
247898d5 47#include "systemd.h"
eb05883f 48
8451921b 49DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm));
bf645e31 50DEFINE_HOOK(frr_config_pre, (struct thread_master * tm), (tm));
2bafda27 51DEFINE_HOOK(frr_config_post, (struct thread_master * tm), (tm));
8451921b
DL
52DEFINE_KOOH(frr_early_fini, (), ());
53DEFINE_KOOH(frr_fini, (), ());
a5b38c5b 54
eb05883f 55const char frr_sysconfdir[] = SYSCONFDIR;
43e587c1 56char frr_vtydir[256];
1c2facd1
RW
57#ifdef HAVE_SQLITE3
58const char frr_dbdir[] = DAEMON_DB_DIR;
59#endif
80b4df3b 60const char frr_moduledir[] = MODULE_PATH;
e4e0229a 61const char frr_scriptdir[] = SCRIPT_PATH;
eb05883f 62
4f138a3e
DL
63char frr_protoname[256] = "NONE";
64char frr_protonameinst[256] = "NONE";
b85120bc 65
ff44f570 66char config_default[512];
689f5a8c 67char frr_zclientpath[256];
43e587c1 68static char pidfile_default[1024];
1c2facd1
RW
69#ifdef HAVE_SQLITE3
70static char dbfile_default[512];
71#endif
918537e2 72static char vtypath_default[512];
4f04a76b 73
38554d3a
DL
74/* cleared in frr_preinit(), then re-set after daemonizing */
75bool frr_is_after_fork = true;
d8729f8c 76bool debug_memstats_at_exit = false;
0a7c7856 77static bool nodetach_term, nodetach_daemon;
6e3253b9 78static uint64_t startup_fds;
9eed278b 79
4f04a76b
DL
80static char comb_optstr[256];
81static struct option comb_lo[64];
82static struct option *comb_next_lo = &comb_lo[0];
83static char comb_helpstr[4096];
84
85struct optspec {
86 const char *optstr;
87 const char *helpstr;
88 const struct option *longopts;
89};
90
91static void opt_extend(const struct optspec *os)
92{
93 const struct option *lo;
94
9f73d2c9 95 strlcat(comb_optstr, os->optstr, sizeof(comb_optstr));
67c726a1 96 strlcat(comb_helpstr, os->helpstr, sizeof(comb_helpstr));
4f04a76b
DL
97 for (lo = os->longopts; lo->name; lo++)
98 memcpy(comb_next_lo++, lo, sizeof(*lo));
99}
100
101
80b4df3b
MW
102#define OPTION_VTYSOCK 1000
103#define OPTION_MODULEDIR 1002
e9b4e74a
DS
104#define OPTION_LOG 1003
105#define OPTION_LOGLEVEL 1004
1c2facd1
RW
106#define OPTION_TCLI 1005
107#define OPTION_DB_FILE 1006
2950f5da 108#define OPTION_LOGGING 1007
1a9f340b 109#define OPTION_LIMIT_FDS 1008
e4e0229a 110#define OPTION_SCRIPTDIR 1009
4f04a76b
DL
111
112static const struct option lo_always[] = {
d62a17ae 113 {"help", no_argument, NULL, 'h'},
114 {"version", no_argument, NULL, 'v'},
115 {"daemon", no_argument, NULL, 'd'},
116 {"module", no_argument, NULL, 'M'},
ac4adef4 117 {"profile", required_argument, NULL, 'F'},
33606a15 118 {"pathspace", required_argument, NULL, 'N'},
d62a17ae 119 {"vty_socket", required_argument, NULL, OPTION_VTYSOCK},
120 {"moduledir", required_argument, NULL, OPTION_MODULEDIR},
e4e0229a 121 {"scriptdir", required_argument, NULL, OPTION_SCRIPTDIR},
f8507817 122 {"log", required_argument, NULL, OPTION_LOG},
e9b4e74a 123 {"log-level", required_argument, NULL, OPTION_LOGLEVEL},
2950f5da 124 {"command-log-always", no_argument, NULL, OPTION_LOGGING},
1a9f340b 125 {"limit-fds", required_argument, NULL, OPTION_LIMIT_FDS},
d62a17ae 126 {NULL}};
4f04a76b 127static const struct optspec os_always = {
33606a15 128 "hvdM:F:N:",
4f04a76b
DL
129 " -h, --help Display this help and exit\n"
130 " -v, --version Print program version\n"
eb05883f 131 " -d, --daemon Runs in daemon mode\n"
30771d65 132 " -M, --module Load specified module\n"
ac4adef4 133 " -F, --profile Use specified configuration profile\n"
33606a15 134 " -N, --pathspace Insert prefix into config & socket paths\n"
80b4df3b 135 " --vty_socket Override vty socket path\n"
f8507817 136 " --moduledir Override modules directory\n"
e4e0229a 137 " --scriptdir Override scripts directory\n"
e9b4e74a 138 " --log Set Logging to stdout, syslog, or file:<name>\n"
1c2facd1 139 " --log-level Set Logging Level to use, debug, info, warn, etc\n"
1a9f340b 140 " --limit-fds Limit number of fds supported\n",
d62a17ae 141 lo_always};
4f04a76b
DL
142
143
b1dc60f4 144static const struct option lo_cfg[] = {
d62a17ae 145 {"config_file", required_argument, NULL, 'f'},
146 {"dryrun", no_argument, NULL, 'C'},
147 {NULL}};
b1dc60f4
DL
148static const struct optspec os_cfg = {
149 "f:C",
eb05883f 150 " -f, --config_file Set configuration file name\n"
b1dc60f4
DL
151 " -C, --dryrun Check configuration for validity and exit\n",
152 lo_cfg};
153
154
155static const struct option lo_fullcli[] = {
156 {"terminal", no_argument, NULL, 't'},
157 {"tcli", no_argument, NULL, OPTION_TCLI},
1c2facd1 158#ifdef HAVE_SQLITE3
b1dc60f4 159 {"db_file", required_argument, NULL, OPTION_DB_FILE},
1c2facd1 160#endif
b1dc60f4
DL
161 {NULL}};
162static const struct optspec os_fullcli = {
163 "t",
164 " --tcli Use transaction-based CLI\n"
cff2b211
DL
165 " -t, --terminal Open terminal session on stdio\n"
166 " -d -t Daemonize after terminal session ends\n",
b1dc60f4
DL
167 lo_fullcli};
168
169
170static const struct option lo_pid[] = {
171 {"pid_file", required_argument, NULL, 'i'},
172 {NULL}};
173static const struct optspec os_pid = {
174 "i:",
175 " -i, --pid_file Set process identifier file name\n",
176 lo_pid};
eb05883f
DL
177
178
179static const struct option lo_zclient[] = {
d62a17ae 180 {"socket", required_argument, NULL, 'z'},
181 {NULL}};
eb05883f 182static const struct optspec os_zclient = {
d62a17ae 183 "z:", " -z, --socket Set path of zebra socket\n", lo_zclient};
eb05883f
DL
184
185
4f04a76b 186static const struct option lo_vty[] = {
d62a17ae 187 {"vty_addr", required_argument, NULL, 'A'},
188 {"vty_port", required_argument, NULL, 'P'},
189 {NULL}};
4f04a76b
DL
190static const struct optspec os_vty = {
191 "A:P:",
192 " -A, --vty_addr Set vty's bind address\n"
193 " -P, --vty_port Set vty's port number\n",
d62a17ae 194 lo_vty};
4f04a76b
DL
195
196
d62a17ae 197static const struct option lo_user[] = {{"user", required_argument, NULL, 'u'},
198 {"group", required_argument, NULL, 'g'},
199 {NULL}};
200static const struct optspec os_user = {"u:g:",
201 " -u, --user User to run as\n"
202 " -g, --group Group to run as\n",
203 lo_user};
4f04a76b 204
689f5a8c
DL
205bool frr_zclient_addr(struct sockaddr_storage *sa, socklen_t *sa_len,
206 const char *path)
207{
208 memset(sa, 0, sizeof(*sa));
209
210 if (!path)
4e99f309 211 path = frr_zclientpath;
689f5a8c
DL
212
213 if (!strncmp(path, ZAPI_TCP_PATHNAME, strlen(ZAPI_TCP_PATHNAME))) {
5d13cd09 214 /* note: this functionality is disabled at bottom */
689f5a8c
DL
215 int af;
216 int port = ZEBRA_PORT;
217 char *err = NULL;
218 struct sockaddr_in *sin = NULL;
219 struct sockaddr_in6 *sin6 = NULL;
220
221 path += strlen(ZAPI_TCP_PATHNAME);
222
223 switch (path[0]) {
224 case '4':
225 path++;
226 af = AF_INET;
227 break;
228 case '6':
229 path++;
996c9314 230 /* fallthrough */
689f5a8c
DL
231 default:
232 af = AF_INET6;
233 break;
234 }
235
236 switch (path[0]) {
237 case '\0':
238 break;
239 case ':':
240 path++;
241 port = strtoul(path, &err, 10);
242 if (*err || !*path)
243 return false;
244 break;
245 default:
246 return false;
247 }
248
249 sa->ss_family = af;
250 switch (af) {
251 case AF_INET:
252 sin = (struct sockaddr_in *)sa;
253 sin->sin_port = htons(port);
254 sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
255 *sa_len = sizeof(struct sockaddr_in);
256#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
257 sin->sin_len = *sa_len;
258#endif
259 break;
260 case AF_INET6:
261 sin6 = (struct sockaddr_in6 *)sa;
262 sin6->sin6_port = htons(port);
263 inet_pton(AF_INET6, "::1", &sin6->sin6_addr);
264 *sa_len = sizeof(struct sockaddr_in6);
265#ifdef SIN6_LEN
266 sin6->sin6_len = *sa_len;
267#endif
268 break;
269 }
5d13cd09
DL
270
271#if 1
272 /* force-disable this path, because tcp-zebra is a
273 * SECURITY ISSUE. there are no checks at all against
274 * untrusted users on the local system connecting on TCP
275 * and injecting bogus routing data into the entire routing
276 * domain.
277 *
278 * The functionality is only left here because it may be
279 * useful during development, in order to be able to get
280 * tcpdump or wireshark watching ZAPI as TCP. If you want
281 * to do that, flip the #if 1 above to #if 0. */
282 memset(sa, 0, sizeof(*sa));
283 return false;
284#endif
689f5a8c
DL
285 } else {
286 /* "sun" is a #define on solaris */
287 struct sockaddr_un *suna = (struct sockaddr_un *)sa;
288
289 suna->sun_family = AF_UNIX;
290 strlcpy(suna->sun_path, path, sizeof(suna->sun_path));
291#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
292 *sa_len = suna->sun_len = SUN_LEN(suna);
293#else
294 *sa_len = sizeof(suna->sun_family) + strlen(suna->sun_path);
295#endif /* HAVE_STRUCT_SOCKADDR_UN_SUN_LEN */
296#if 0
297 /* this is left here for future reference; Linux abstract
298 * socket namespace support can be enabled by replacing
299 * above #if 0 with #ifdef GNU_LINUX.
300 *
301 * THIS IS A SECURITY ISSUE, the abstract socket namespace
302 * does not have user/group permission control on sockets.
303 * we'd need to implement SCM_CREDENTIALS support first to
304 * check that only proper users can connect to abstract
305 * sockets. (same problem as tcp-zebra, except there is a
306 * fix with SCM_CREDENTIALS. tcp-zebra has no such fix.)
307 */
308 if (suna->sun_path[0] == '@')
309 suna->sun_path[0] = '\0';
310#endif
311 }
312 return true;
313}
314
4f04a76b
DL
315static struct frr_daemon_info *di = NULL;
316
43e587c1
DS
317void frr_init_vtydir(void)
318{
319 snprintf(frr_vtydir, sizeof(frr_vtydir), DAEMON_VTY_DIR, "", "");
320}
321
4f04a76b
DL
322void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv)
323{
324 di = daemon;
38554d3a 325 frr_is_after_fork = false;
4f04a76b
DL
326
327 /* basename(), opencoded. */
328 char *p = strrchr(argv[0], '/');
329 di->progname = p ? p + 1 : argv[0];
330
331 umask(0027);
332
333 opt_extend(&os_always);
b1dc60f4
DL
334 if (!(di->flags & FRR_NO_SPLIT_CONFIG))
335 opt_extend(&os_cfg);
336 if (!(di->flags & FRR_LIMITED_CLI))
337 opt_extend(&os_fullcli);
338 if (!(di->flags & FRR_NO_PID))
339 opt_extend(&os_pid);
4f04a76b
DL
340 if (!(di->flags & FRR_NO_PRIVSEP))
341 opt_extend(&os_user);
eb05883f
DL
342 if (!(di->flags & FRR_NO_ZCLIENT))
343 opt_extend(&os_zclient);
4f04a76b
DL
344 if (!(di->flags & FRR_NO_TCPVTY))
345 opt_extend(&os_vty);
0a7c7856
DL
346 if (di->flags & FRR_DETACH_LATER)
347 nodetach_daemon = true;
eb05883f 348
43e587c1 349 frr_init_vtydir();
eb05883f 350 snprintf(config_default, sizeof(config_default), "%s/%s.conf",
d62a17ae 351 frr_sysconfdir, di->name);
eb05883f 352 snprintf(pidfile_default, sizeof(pidfile_default), "%s/%s.pid",
d62a17ae 353 frr_vtydir, di->name);
43e587c1
DS
354 snprintf(frr_zclientpath, sizeof(frr_zclientpath),
355 ZEBRA_SERV_PATH, "", "");
1c2facd1
RW
356#ifdef HAVE_SQLITE3
357 snprintf(dbfile_default, sizeof(dbfile_default), "%s/%s.db",
358 frr_dbdir, di->name);
359#endif
b85120bc
DL
360
361 strlcpy(frr_protoname, di->logname, sizeof(frr_protoname));
362 strlcpy(frr_protonameinst, di->logname, sizeof(frr_protonameinst));
689f5a8c 363
1c2facd1 364 di->cli_mode = FRR_CLI_CLASSIC;
6e3253b9
DL
365
366 /* we may be starting with extra FDs open for whatever purpose,
367 * e.g. logging, some module, etc. Recording them here allows later
368 * checking whether an fd is valid for such extension purposes,
369 * without this we could end up e.g. logging to a BGP session fd.
370 */
371 startup_fds = 0;
372 for (int i = 0; i < 64; i++) {
373 struct stat st;
374
375 if (fstat(i, &st))
376 continue;
377 if (S_ISDIR(st.st_mode) || S_ISBLK(st.st_mode))
378 continue;
379
380 startup_fds |= UINT64_C(0x1) << (uint64_t)i;
381 }
247898d5
DL
382
383 /* note this doesn't do anything, it just grabs state, so doing it
384 * early in _preinit is perfect.
385 */
386 systemd_init_env();
6e3253b9
DL
387}
388
389bool frr_is_startup_fd(int fd)
390{
391 return !!(startup_fds & (UINT64_C(0x1) << (uint64_t)fd));
4f04a76b
DL
392}
393
394void frr_opt_add(const char *optstr, const struct option *longopts,
d62a17ae 395 const char *helpstr)
4f04a76b 396{
d62a17ae 397 const struct optspec main_opts = {optstr, helpstr, longopts};
4f04a76b
DL
398 opt_extend(&main_opts);
399}
400
401void frr_help_exit(int status)
402{
403 FILE *target = status ? stderr : stdout;
404
405 if (status != 0)
406 fprintf(stderr, "Invalid options.\n\n");
407
408 if (di->printhelp)
409 di->printhelp(target);
410 else
411 fprintf(target, "Usage: %s [OPTION...]\n\n%s%s%s\n\n%s",
d62a17ae 412 di->progname, di->proghelp, di->copyright ? "\n\n" : "",
413 di->copyright ? di->copyright : "", comb_helpstr);
4f04a76b
DL
414 fprintf(target, "\nReport bugs to %s\n", FRR_BUG_ADDRESS);
415 exit(status);
416}
417
30771d65
DL
418struct option_chain {
419 struct option_chain *next;
420 const char *arg;
421};
80b4df3b 422
30771d65 423static struct option_chain *modules = NULL, **modnext = &modules;
4f04a76b
DL
424static int errors = 0;
425
426static int frr_opt(int opt)
427{
428 static int vty_port_set = 0;
429 static int vty_addr_set = 0;
30771d65 430 struct option_chain *oc;
4f04a76b
DL
431 char *err;
432
433 switch (opt) {
434 case 'h':
435 frr_help_exit(0);
4f04a76b
DL
436 case 'v':
437 print_version(di->progname);
438 exit(0);
439 break;
eb05883f 440 case 'd':
08c2d52a 441 di->daemon_mode = true;
eb05883f 442 break;
30771d65
DL
443 case 'M':
444 oc = XMALLOC(MTYPE_TMP, sizeof(*oc));
445 oc->arg = optarg;
446 oc->next = NULL;
447 *modnext = oc;
448 modnext = &oc->next;
449 break;
ac4adef4
DL
450 case 'F':
451 if (!frr_defaults_profile_valid(optarg)) {
452 const char **p;
453 FILE *ofd = stderr;
454
455 if (!strcmp(optarg, "help"))
456 ofd = stdout;
457 else
458 fprintf(stderr,
459 "The \"%s\" configuration profile is not valid for this FRR version.\n",
460 optarg);
461
462 fprintf(ofd, "Available profiles are:\n");
463 for (p = frr_defaults_profiles; *p; p++)
464 fprintf(ofd, "%s%s\n",
465 strcmp(*p, DFLT_NAME) ? " " : " * ",
466 *p);
467
468 if (ofd == stdout)
469 exit(0);
470 fprintf(ofd, "\n");
471 errors++;
472 break;
473 }
474 frr_defaults_profile_set(optarg);
475 break;
eb05883f 476 case 'i':
b1dc60f4 477 if (di->flags & FRR_NO_PID)
eb05883f
DL
478 return 1;
479 di->pid_file = optarg;
480 break;
481 case 'f':
b1dc60f4 482 if (di->flags & FRR_NO_SPLIT_CONFIG)
eb05883f
DL
483 return 1;
484 di->config_file = optarg;
485 break;
d1b4fc1f 486 case 'N':
d1b4fc1f
DL
487 if (di->pathspace) {
488 fprintf(stderr,
489 "-N/--pathspace option specified more than once!\n");
490 errors++;
491 break;
492 }
43e587c1
DS
493 if (di->zpathspace)
494 fprintf(stderr,
f79f7a7b 495 "-N option overridden by -z for zebra named socket path\n");
43e587c1 496
d1b4fc1f
DL
497 if (strchr(optarg, '/') || strchr(optarg, '.')) {
498 fprintf(stderr,
499 "slashes or dots are not permitted in the --pathspace option.\n");
500 errors++;
501 break;
502 }
503 di->pathspace = optarg;
4e99f309 504
43e587c1
DS
505 if (!di->zpathspace)
506 snprintf(frr_zclientpath, sizeof(frr_zclientpath),
507 ZEBRA_SERV_PATH, "/", di->pathspace);
508 snprintf(frr_vtydir, sizeof(frr_vtydir), DAEMON_VTY_DIR, "/",
509 di->pathspace);
510 snprintf(pidfile_default, sizeof(pidfile_default), "%s/%s.pid",
511 frr_vtydir, di->name);
d1b4fc1f 512 break;
1c2facd1
RW
513#ifdef HAVE_SQLITE3
514 case OPTION_DB_FILE:
b1dc60f4 515 if (di->flags & FRR_NO_PID)
1c2facd1
RW
516 return 1;
517 di->db_file = optarg;
518 break;
519#endif
eb05883f 520 case 'C':
b1dc60f4 521 if (di->flags & FRR_NO_SPLIT_CONFIG)
eb05883f 522 return 1;
08c2d52a 523 di->dryrun = true;
eb05883f 524 break;
cff2b211 525 case 't':
b1dc60f4 526 if (di->flags & FRR_LIMITED_CLI)
cff2b211 527 return 1;
08c2d52a 528 di->terminal = true;
cff2b211 529 break;
eb05883f 530 case 'z':
43e587c1
DS
531 di->zpathspace = true;
532 if (di->pathspace)
533 fprintf(stderr,
534 "-z option overrides -N option for zebra named socket path\n");
eb05883f
DL
535 if (di->flags & FRR_NO_ZCLIENT)
536 return 1;
689f5a8c 537 strlcpy(frr_zclientpath, optarg, sizeof(frr_zclientpath));
eb05883f 538 break;
4f04a76b
DL
539 case 'A':
540 if (di->flags & FRR_NO_TCPVTY)
541 return 1;
542 if (vty_addr_set) {
d62a17ae 543 fprintf(stderr,
544 "-A option specified more than once!\n");
4f04a76b
DL
545 errors++;
546 break;
547 }
548 vty_addr_set = 1;
549 di->vty_addr = optarg;
550 break;
551 case 'P':
552 if (di->flags & FRR_NO_TCPVTY)
553 return 1;
554 if (vty_port_set) {
d62a17ae 555 fprintf(stderr,
556 "-P option specified more than once!\n");
4f04a76b
DL
557 errors++;
558 break;
559 }
560 vty_port_set = 1;
561 di->vty_port = strtoul(optarg, &err, 0);
562 if (*err || !*optarg) {
d62a17ae 563 fprintf(stderr,
564 "invalid port number \"%s\" for -P option\n",
565 optarg);
4f04a76b
DL
566 errors++;
567 break;
568 }
569 break;
570 case OPTION_VTYSOCK:
571 if (di->vty_sock_path) {
d62a17ae 572 fprintf(stderr,
573 "--vty_socket option specified more than once!\n");
4f04a76b
DL
574 errors++;
575 break;
576 }
577 di->vty_sock_path = optarg;
578 break;
80b4df3b
MW
579 case OPTION_MODULEDIR:
580 if (di->module_path) {
d62a17ae 581 fprintf(stderr,
582 "----moduledir option specified more than once!\n");
80b4df3b
MW
583 errors++;
584 break;
585 }
586 di->module_path = optarg;
587 break;
e4e0229a
QY
588 case OPTION_SCRIPTDIR:
589 if (di->script_path) {
590 fprintf(stderr, "--scriptdir option specified more than once!\n");
591 errors++;
592 break;
593 }
594 di->script_path = optarg;
595 break;
1c2facd1
RW
596 case OPTION_TCLI:
597 di->cli_mode = FRR_CLI_TRANSACTIONAL;
598 break;
4f04a76b
DL
599 case 'u':
600 if (di->flags & FRR_NO_PRIVSEP)
601 return 1;
602 di->privs->user = optarg;
603 break;
604 case 'g':
605 if (di->flags & FRR_NO_PRIVSEP)
606 return 1;
607 di->privs->group = optarg;
608 break;
f8507817
DS
609 case OPTION_LOG:
610 di->early_logging = optarg;
611 break;
e9b4e74a
DS
612 case OPTION_LOGLEVEL:
613 di->early_loglevel = optarg;
614 break;
2950f5da
DS
615 case OPTION_LOGGING:
616 di->log_always = true;
617 break;
1a9f340b
MS
618 case OPTION_LIMIT_FDS:
619 di->limit_fds = strtoul(optarg, &err, 0);
620 break;
4f04a76b
DL
621 default:
622 return 1;
623 }
624 return 0;
625}
626
d62a17ae 627int frr_getopt(int argc, char *const argv[], int *longindex)
4f04a76b
DL
628{
629 int opt;
630 int lidx;
631
632 comb_next_lo->name = NULL;
633
634 do {
635 opt = getopt_long(argc, argv, comb_optstr, comb_lo, &lidx);
636 if (frr_opt(opt))
637 break;
638 } while (opt != -1);
639
640 if (opt == -1 && errors)
641 frr_help_exit(1);
642 if (longindex)
643 *longindex = lidx;
644 return opt;
645}
646
beaa5470
DL
647static void frr_mkdir(const char *path, bool strip)
648{
649 char buf[256];
650 mode_t prev;
651 int ret;
652 struct zprivs_ids_t ids;
653
654 if (strip) {
655 char *slash = strrchr(path, '/');
656 size_t plen;
657 if (!slash)
658 return;
659 plen = slash - path;
660 if (plen > sizeof(buf) - 1)
661 return;
662 memcpy(buf, path, plen);
663 buf[plen] = '\0';
664 path = buf;
665 }
666
667 /* o+rx (..5) is needed for the frrvty group to work properly;
668 * without it, users in the frrvty group can't access the vty sockets.
669 */
670 prev = umask(0022);
671 ret = mkdir(path, 0755);
672 umask(prev);
673
674 if (ret != 0) {
675 /* if EEXIST, return without touching the permissions,
676 * so user-set custom permissions are left in place
677 */
678 if (errno == EEXIST)
679 return;
680
1c50c1c0
QY
681 flog_err(EC_LIB_SYSTEM_CALL, "failed to mkdir \"%s\": %s", path,
682 strerror(errno));
beaa5470
DL
683 return;
684 }
685
686 zprivs_get_ids(&ids);
687 if (chown(path, ids.uid_normal, ids.gid_normal))
1c50c1c0
QY
688 flog_err(EC_LIB_SYSTEM_CALL, "failed to chown \"%s\": %s", path,
689 strerror(errno));
beaa5470
DL
690}
691
52fad8f6
PZ
692static void _err_print(const void *cookie, const char *errstr)
693{
694 const char *prefix = (const char *)cookie;
695
696 fprintf(stderr, "%s: %s\n", prefix, errstr);
697}
698
a5b38c5b 699static struct thread_master *master;
4f04a76b
DL
700struct thread_master *frr_init(void)
701{
30771d65
DL
702 struct option_chain *oc;
703 struct frrmod_runtime *module;
0bdeb5e5 704 struct zprivs_ids_t ids;
d1b4fc1f 705 char p_instance[16] = "", p_pathspace[256] = "";
80b4df3b
MW
706 const char *dir;
707 dir = di->module_path ? di->module_path : frr_moduledir;
4f04a76b
DL
708
709 srandom(time(NULL));
ac4adef4 710 frr_defaults_apply();
4f04a76b 711
d1b4fc1f 712 if (di->instance) {
d62a17ae 713 snprintf(frr_protonameinst, sizeof(frr_protonameinst), "%s[%u]",
714 di->logname, di->instance);
d1b4fc1f
DL
715 snprintf(p_instance, sizeof(p_instance), "-%d", di->instance);
716 }
717 if (di->pathspace)
b39404c1 718 snprintf(p_pathspace, sizeof(p_pathspace), "%s/",
d1b4fc1f
DL
719 di->pathspace);
720
36077833 721 snprintf(config_default, sizeof(config_default), "%s%s%s%s.conf",
d1b4fc1f 722 frr_sysconfdir, p_pathspace, di->name, p_instance);
43e587c1
DS
723 snprintf(pidfile_default, sizeof(pidfile_default), "%s/%s%s.pid",
724 frr_vtydir, di->name, p_instance);
1c2facd1
RW
725#ifdef HAVE_SQLITE3
726 snprintf(dbfile_default, sizeof(dbfile_default), "%s/%s%s%s.db",
727 frr_dbdir, p_pathspace, di->name, p_instance);
728#endif
b85120bc 729
37a1f2fb 730 zprivs_preinit(di->privs);
0bdeb5e5 731 zprivs_get_ids(&ids);
37a1f2fb 732
0bdeb5e5
DL
733 zlog_init(di->progname, di->logname, di->instance,
734 ids.uid_normal, ids.gid_normal);
f8507817 735
e9b4e74a 736 command_setup_early_logging(di->early_logging, di->early_loglevel);
4f04a76b 737
689f5a8c
DL
738 if (!frr_zclient_addr(&zclient_addr, &zclient_addr_len,
739 frr_zclientpath)) {
740 fprintf(stderr, "Invalid zserv socket path: %s\n",
741 frr_zclientpath);
742 exit(1);
743 }
744
b8c1fde3
DL
745 /* don't mkdir these as root... */
746 if (!(di->flags & FRR_NO_PRIVSEP)) {
747 if (!di->pid_file || !di->vty_path)
748 frr_mkdir(frr_vtydir, false);
749 if (di->pid_file)
750 frr_mkdir(di->pid_file, true);
751 if (di->vty_path)
752 frr_mkdir(di->vty_path, true);
753 }
beaa5470 754
30771d65
DL
755 frrmod_init(di->module);
756 while (modules) {
757 modules = (oc = modules)->next;
52fad8f6
PZ
758 module = frrmod_load(oc->arg, dir, _err_print, __func__);
759 if (!module)
30771d65 760 exit(1);
30771d65
DL
761 XFREE(MTYPE_TMP, oc);
762 }
763
4f04a76b
DL
764 zprivs_init(di->privs);
765
972a411c 766 master = thread_master_create(NULL);
4f04a76b
DL
767 signal_init(master, di->n_signals, di->signals);
768
1c2facd1
RW
769#ifdef HAVE_SQLITE3
770 if (!di->db_file)
771 di->db_file = dbfile_default;
772 db_init(di->db_file);
773#endif
774
857b5446
DL
775 if (di->flags & FRR_LIMITED_CLI)
776 cmd_init(-1);
777 else
778 cmd_init(1);
1c2facd1 779
2950f5da 780 vty_init(master, di->log_always);
1c0d8808 781 lib_cmd_init();
857b5446 782
b9b4c061 783 frr_pthread_init();
fa22080d 784#ifdef HAVE_SCRIPTING
e4e0229a 785 frrscript_init(di->script_path ? di->script_path : frr_scriptdir);
fa22080d 786#endif
b9b4c061 787
85cd2f9f 788 log_ref_init();
1f9128d6 789 log_ref_vty_init();
b66d022e
DS
790 lib_error_init();
791
390a8862 792 nb_init(master, di->yang_modules, di->n_yang_modules, true);
1ae9686c
RW
793 if (nb_db_init() != NB_OK)
794 flog_warn(EC_LIB_NB_DATABASE,
795 "%s: failed to initialize northbound database",
796 __func__);
1c2facd1 797
3bb513c3
CH
798 debug_init_cli();
799
4f04a76b
DL
800 return master;
801}
802
1c2facd1
RW
803const char *frr_get_progname(void)
804{
805 return di ? di->progname : NULL;
806}
807
808enum frr_cli_mode frr_get_cli_mode(void)
809{
810 return di ? di->cli_mode : FRR_CLI_CLASSIC;
811}
812
1a9f340b
MS
813uint32_t frr_get_fd_limit(void)
814{
815 return di ? di->limit_fds : 0;
816}
817
154b9e8f
DL
818static int rcvd_signal = 0;
819
820static void rcv_signal(int signum)
821{
822 rcvd_signal = signum;
823 /* poll() is interrupted by the signal; handled below */
824}
825
f43fbf83
DL
826static void frr_daemon_wait(int fd)
827{
828 struct pollfd pfd[1];
829 int ret;
830 pid_t exitpid;
831 int exitstat;
154b9e8f
DL
832 sigset_t sigs, prevsigs;
833
834 sigemptyset(&sigs);
835 sigaddset(&sigs, SIGTSTP);
836 sigaddset(&sigs, SIGQUIT);
837 sigaddset(&sigs, SIGINT);
838 sigprocmask(SIG_BLOCK, &sigs, &prevsigs);
839
840 struct sigaction sa = {
841 .sa_handler = rcv_signal, .sa_flags = SA_RESETHAND,
842 };
843 sigemptyset(&sa.sa_mask);
844 sigaction(SIGTSTP, &sa, NULL);
845 sigaction(SIGQUIT, &sa, NULL);
846 sigaction(SIGINT, &sa, NULL);
f43fbf83
DL
847
848 do {
154b9e8f
DL
849 char buf[1];
850 ssize_t nrecv;
851
f43fbf83
DL
852 pfd[0].fd = fd;
853 pfd[0].events = POLLIN;
854
154b9e8f
DL
855 rcvd_signal = 0;
856
996c9314 857#if defined(HAVE_PPOLL)
154b9e8f
DL
858 ret = ppoll(pfd, 1, NULL, &prevsigs);
859#elif defined(HAVE_POLLTS)
860 ret = pollts(pfd, 1, NULL, &prevsigs);
861#else
862 /* racy -- only used on FreeBSD 9 */
863 sigset_t tmpsigs;
864 sigprocmask(SIG_SETMASK, &prevsigs, &tmpsigs);
f43fbf83 865 ret = poll(pfd, 1, -1);
154b9e8f
DL
866 sigprocmask(SIG_SETMASK, &tmpsigs, NULL);
867#endif
f43fbf83
DL
868 if (ret < 0 && errno != EINTR && errno != EAGAIN) {
869 perror("poll()");
870 exit(1);
871 }
154b9e8f
DL
872 switch (rcvd_signal) {
873 case SIGTSTP:
874 send(fd, "S", 1, 0);
875 do {
876 nrecv = recv(fd, buf, sizeof(buf), 0);
877 } while (nrecv == -1
878 && (errno == EINTR || errno == EAGAIN));
879
880 raise(SIGTSTP);
881 sigaction(SIGTSTP, &sa, NULL);
882 send(fd, "R", 1, 0);
883 break;
884 case SIGINT:
885 send(fd, "I", 1, 0);
886 break;
887 case SIGQUIT:
888 send(fd, "Q", 1, 0);
889 break;
890 }
f43fbf83
DL
891 } while (ret <= 0);
892
893 exitpid = waitpid(-1, &exitstat, WNOHANG);
894 if (exitpid == 0)
895 /* child successfully went to main loop & closed socket */
896 exit(0);
897
898 /* child failed one way or another ... */
6bd2b360
DL
899 if (WIFEXITED(exitstat) && WEXITSTATUS(exitstat) == 0)
900 /* can happen in --terminal case if exit is fast enough */
901 (void)0;
902 else if (WIFEXITED(exitstat))
f43fbf83
DL
903 fprintf(stderr, "%s failed to start, exited %d\n", di->name,
904 WEXITSTATUS(exitstat));
905 else if (WIFSIGNALED(exitstat))
906 fprintf(stderr, "%s crashed in startup, signal %d\n", di->name,
907 WTERMSIG(exitstat));
908 else
909 fprintf(stderr, "%s failed to start, unknown problem\n",
910 di->name);
911 exit(1);
912}
913
914static int daemon_ctl_sock = -1;
915
916static void frr_daemonize(void)
917{
918 int fds[2];
919 pid_t pid;
920
921 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) {
922 perror("socketpair() for daemon control");
923 exit(1);
924 }
925 set_cloexec(fds[0]);
926 set_cloexec(fds[1]);
927
928 pid = fork();
929 if (pid < 0) {
930 perror("fork()");
931 exit(1);
932 }
933 if (pid == 0) {
934 /* child */
935 close(fds[0]);
936 if (setsid() < 0) {
937 perror("setsid()");
938 exit(1);
939 }
940
941 daemon_ctl_sock = fds[1];
942 return;
943 }
944
945 close(fds[1]);
946 frr_daemon_wait(fds[0]);
947}
948
9e224e60
DS
949/*
950 * Why is this a thread?
951 *
952 * The read in of config for integrated config happens *after*
953 * thread execution starts( because it is passed in via a vtysh -b -n )
954 * While if you are not using integrated config we want the ability
955 * to read the config in after thread execution starts, so that
956 * we can match this behavior.
957 */
958static int frr_config_read_in(struct thread *t)
4f04a76b 959{
bf645e31
DL
960 hook_call(frr_config_pre, master);
961
91f9fd78
RW
962 if (!vty_read_config(vty_shared_candidate_config, di->config_file,
963 config_default)
964 && di->backup_config_file) {
fe64533a
DS
965 char *orig = XSTRDUP(MTYPE_TMP, host_config_get());
966
573de11f
DS
967 zlog_info("Attempting to read backup config file: %s specified",
968 di->backup_config_file);
91f9fd78
RW
969 vty_read_config(vty_shared_candidate_config,
970 di->backup_config_file, config_default);
fe64533a
DS
971
972 host_config_set(orig);
973 XFREE(MTYPE_TMP, orig);
573de11f 974 }
1c2facd1
RW
975
976 /*
91f9fd78
RW
977 * Automatically commit the candidate configuration after
978 * reading the configuration file.
1c2facd1 979 */
91f9fd78 980 if (frr_get_cli_mode() == FRR_CLI_TRANSACTIONAL) {
13d6b9c1 981 struct nb_context context = {};
df5eda3d 982 char errmsg[BUFSIZ] = {0};
91f9fd78
RW
983 int ret;
984
13d6b9c1
RW
985 context.client = NB_CLIENT_CLI;
986 ret = nb_candidate_commit(&context, vty_shared_candidate_config,
df5eda3d
RW
987 true, "Read configuration file", NULL,
988 errmsg, sizeof(errmsg));
91f9fd78 989 if (ret != NB_OK && ret != NB_ERR_NO_CHANGES)
df5eda3d
RW
990 zlog_err(
991 "%s: failed to read configuration file: %s (%s)",
992 __func__, nb_err_name(ret), errmsg);
91f9fd78 993 }
1c2facd1 994
2bafda27 995 hook_call(frr_config_post, master);
88e635ee 996
9e224e60
DS
997 return 0;
998}
999
1000void frr_config_fork(void)
1001{
1002 hook_call(frr_late_init, master);
eb05883f 1003
b1dc60f4 1004 if (!(di->flags & FRR_NO_SPLIT_CONFIG)) {
0a7c7856
DL
1005 /* Don't start execution if we are in dry-run mode */
1006 if (di->dryrun) {
1007 frr_config_read_in(NULL);
1008 exit(0);
1009 }
9e224e60 1010
0a7c7856
DL
1011 thread_add_event(master, frr_config_read_in, NULL, 0,
1012 &di->read_in);
1013 }
eb05883f 1014
154b9e8f 1015 if (di->daemon_mode || di->terminal)
f43fbf83 1016 frr_daemonize();
eb05883f 1017
38554d3a
DL
1018 frr_is_after_fork = true;
1019
eb05883f
DL
1020 if (!di->pid_file)
1021 di->pid_file = pidfile_default;
d62a17ae 1022 pid_output(di->pid_file);
e2be2643 1023 zlog_tls_buffer_init();
eb05883f
DL
1024}
1025
0a7c7856 1026static void frr_vty_serv(void)
eb05883f 1027{
d62a17ae 1028 /* allow explicit override of vty_path in the future
eb05883f
DL
1029 * (not currently set anywhere) */
1030 if (!di->vty_path) {
1031 const char *dir;
d1b4fc1f
DL
1032 char defvtydir[256];
1033
43e587c1 1034 snprintf(defvtydir, sizeof(defvtydir), "%s", frr_vtydir);
d1b4fc1f
DL
1035
1036 dir = di->vty_sock_path ? di->vty_sock_path : defvtydir;
eb05883f
DL
1037
1038 if (di->instance)
1039 snprintf(vtypath_default, sizeof(vtypath_default),
d62a17ae 1040 "%s/%s-%d.vty", dir, di->name, di->instance);
eb05883f
DL
1041 else
1042 snprintf(vtypath_default, sizeof(vtypath_default),
d62a17ae 1043 "%s/%s.vty", dir, di->name);
eb05883f
DL
1044
1045 di->vty_path = vtypath_default;
1046 }
1047
1048 vty_serv_sock(di->vty_addr, di->vty_port, di->vty_path);
4f04a76b
DL
1049}
1050
0a7c7856
DL
1051static void frr_check_detach(void)
1052{
1053 if (nodetach_term || nodetach_daemon)
1054 return;
1055
1056 if (daemon_ctl_sock != -1)
1057 close(daemon_ctl_sock);
1058 daemon_ctl_sock = -1;
1059}
1060
154b9e8f 1061static void frr_terminal_close(int isexit)
cff2b211 1062{
993bab89
RW
1063 int nullfd;
1064
0a7c7856
DL
1065 nodetach_term = false;
1066 frr_check_detach();
154b9e8f
DL
1067
1068 if (!di->daemon_mode || isexit) {
cff2b211 1069 printf("\n%s exiting\n", di->name);
154b9e8f
DL
1070 if (!isexit)
1071 raise(SIGINT);
1072 return;
cff2b211
DL
1073 } else {
1074 printf("\n%s daemonizing\n", di->name);
1075 fflush(stdout);
1076 }
1077
993bab89
RW
1078 nullfd = open("/dev/null", O_RDONLY | O_NOCTTY);
1079 if (nullfd == -1) {
450971aa 1080 flog_err_sys(EC_LIB_SYSTEM_CALL,
09c866e3
QY
1081 "%s: failed to open /dev/null: %s", __func__,
1082 safe_strerror(errno));
993bab89
RW
1083 } else {
1084 dup2(nullfd, 0);
1085 dup2(nullfd, 1);
1086 dup2(nullfd, 2);
1087 close(nullfd);
1088 }
154b9e8f 1089}
cff2b211 1090
154b9e8f
DL
1091static struct thread *daemon_ctl_thread = NULL;
1092
1093static int frr_daemon_ctl(struct thread *t)
1094{
1095 char buf[1];
1096 ssize_t nr;
1097
1098 nr = recv(daemon_ctl_sock, buf, sizeof(buf), 0);
1099 if (nr < 0 && (errno == EINTR || errno == EAGAIN))
1100 goto out;
1101 if (nr <= 0)
1102 return 0;
1103
1104 switch (buf[0]) {
996c9314 1105 case 'S': /* SIGTSTP */
154b9e8f 1106 vty_stdio_suspend();
e339d7c0 1107 if (send(daemon_ctl_sock, "s", 1, 0) < 0)
1108 zlog_err("%s send(\"s\") error (SIGTSTP propagation)",
1109 (di && di->name ? di->name : ""));
154b9e8f 1110 break;
996c9314 1111 case 'R': /* SIGTCNT [implicit] */
154b9e8f
DL
1112 vty_stdio_resume();
1113 break;
996c9314 1114 case 'I': /* SIGINT */
154b9e8f
DL
1115 di->daemon_mode = false;
1116 raise(SIGINT);
1117 break;
996c9314 1118 case 'Q': /* SIGQUIT */
154b9e8f
DL
1119 di->daemon_mode = true;
1120 vty_stdio_close();
1121 break;
cff2b211 1122 }
154b9e8f
DL
1123
1124out:
1125 thread_add_read(master, frr_daemon_ctl, NULL, daemon_ctl_sock,
1126 &daemon_ctl_thread);
1127 return 0;
cff2b211
DL
1128}
1129
0a7c7856
DL
1130void frr_detach(void)
1131{
1132 nodetach_daemon = false;
1133 frr_check_detach();
1134}
1135
16077f2f
DL
1136void frr_run(struct thread_master *master)
1137{
1138 char instanceinfo[64] = "";
1139
1140 frr_vty_serv();
1141
1142 if (di->instance)
1143 snprintf(instanceinfo, sizeof(instanceinfo), "instance %u ",
d62a17ae 1144 di->instance);
1145
1146 zlog_notice("%s %s starting: %svty@%d%s", di->name, FRR_VERSION,
1147 instanceinfo, di->vty_port, di->startinfo);
16077f2f 1148
cff2b211 1149 if (di->terminal) {
0a7c7856
DL
1150 nodetach_term = true;
1151
cff2b211 1152 vty_stdio(frr_terminal_close);
154b9e8f
DL
1153 if (daemon_ctl_sock != -1) {
1154 set_nonblocking(daemon_ctl_sock);
1155 thread_add_read(master, frr_daemon_ctl, NULL,
1156 daemon_ctl_sock, &daemon_ctl_thread);
1157 }
eef3d030 1158 } else if (di->daemon_mode) {
c9c8d0d1 1159 int nullfd = open("/dev/null", O_RDONLY | O_NOCTTY);
993bab89 1160 if (nullfd == -1) {
450971aa 1161 flog_err_sys(EC_LIB_SYSTEM_CALL,
09c866e3
QY
1162 "%s: failed to open /dev/null: %s",
1163 __func__, safe_strerror(errno));
993bab89
RW
1164 } else {
1165 dup2(nullfd, 0);
1166 dup2(nullfd, 1);
1167 dup2(nullfd, 2);
1168 close(nullfd);
1169 }
c9c8d0d1 1170
0a7c7856 1171 frr_check_detach();
f43fbf83
DL
1172 }
1173
d34cb7f0 1174 /* end fixed stderr startup logging */
0bdeb5e5 1175 zlog_startup_end();
d34cb7f0 1176
16077f2f
DL
1177 struct thread thread;
1178 while (thread_fetch(master, &thread))
1179 thread_call(&thread);
1180}
03951374
DL
1181
1182void frr_early_fini(void)
1183{
1184 hook_call(frr_early_fini);
1185}
1186
1187void frr_fini(void)
1188{
9eed278b
DL
1189 FILE *fp;
1190 char filename[128];
1191 int have_leftovers;
1192
03951374
DL
1193 hook_call(frr_fini);
1194
03951374
DL
1195 vty_terminate();
1196 cmd_terminate();
1c2facd1
RW
1197 nb_terminate();
1198 yang_terminate();
1199#ifdef HAVE_SQLITE3
1200 db_close();
1201#endif
85cd2f9f 1202 log_ref_fini();
b9b4c061 1203 frr_pthread_finish();
03951374
DL
1204 zprivs_terminate(di->privs);
1205 /* signal_init -> nothing needed */
1206 thread_master_free(master);
e5716b16 1207 master = NULL;
0bdeb5e5
DL
1208 zlog_tls_buffer_fini();
1209 zlog_fini();
03951374 1210 /* frrmod_init -> nothing needed / hooks */
3e41733f 1211 rcu_shutdown();
9eed278b
DL
1212
1213 if (!debug_memstats_at_exit)
1214 return;
1215
1216 have_leftovers = log_memstats(stderr, di->name);
1217
1218 /* in case we decide at runtime that we want exit-memstats for
1219 * a daemon, but it has no stderr because it's daemonized
1220 * (only do this if we actually have something to print though)
1221 */
1222 if (!have_leftovers)
1223 return;
1224
996c9314
LB
1225 snprintf(filename, sizeof(filename), "/tmp/frr-memstats-%s-%llu-%llu",
1226 di->name, (unsigned long long)getpid(),
9eed278b
DL
1227 (unsigned long long)time(NULL));
1228
1229 fp = fopen(filename, "w");
1230 if (fp) {
1231 log_memstats(fp, di->name);
1232 fclose(fp);
1233 }
03951374 1234}
42efb0d4
DL
1235
1236#ifdef INTERP
1237static const char interp[]
1238 __attribute__((section(".interp"), used)) = INTERP;
1239#endif
1240/*
1241 * executable entry point for libfrr.so
1242 *
1243 * note that libc initialization is skipped for this so the set of functions
1244 * that can be called is rather limited
1245 */
1246extern void _libfrr_version(void)
1247 __attribute__((visibility("hidden"), noreturn));
1248void _libfrr_version(void)
1249{
1250 const char banner[] =
1251 FRR_FULL_NAME " " FRR_VERSION ".\n"
1252 FRR_COPYRIGHT GIT_INFO "\n"
1253 "configured with:\n " FRR_CONFIG_ARGS "\n";
1254 write(1, banner, sizeof(banner) - 1);
1255 _exit(0);
1256}