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