]>
git.proxmox.com Git - mirror_frr.git/blob - lib/libfrr.c
2 * libfrr overall management functions
4 * Copyright (C) 2016 David Lamparter for NetDEF, Inc.
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)
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
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
23 #include <sys/types.h>
31 #include "memory_vty.h"
37 DEFINE_HOOK(frr_late_init
, (struct thread_master
* tm
), (tm
))
39 const char frr_sysconfdir
[] = SYSCONFDIR
;
40 const char frr_vtydir
[] = DAEMON_VTY_DIR
;
41 const char frr_moduledir
[] = MODULE_PATH
;
43 char frr_protoname
[256] = "NONE";
44 char frr_protonameinst
[256] = "NONE";
46 char config_default
[256];
47 static char pidfile_default
[256];
48 static char vtypath_default
[256];
50 static char comb_optstr
[256];
51 static struct option comb_lo
[64];
52 static struct option
*comb_next_lo
= &comb_lo
[0];
53 static char comb_helpstr
[4096];
58 const struct option
*longopts
;
61 static void opt_extend(const struct optspec
*os
)
63 const struct option
*lo
;
65 strcat(comb_optstr
, os
->optstr
);
66 strcat(comb_helpstr
, os
->helpstr
);
67 for (lo
= os
->longopts
; lo
->name
; lo
++)
68 memcpy(comb_next_lo
++, lo
, sizeof(*lo
));
72 #define OPTION_VTYSOCK 1000
73 #define OPTION_MODULEDIR 1002
75 static const struct option lo_always
[] = {
76 {"help", no_argument
, NULL
, 'h'},
77 {"version", no_argument
, NULL
, 'v'},
78 {"daemon", no_argument
, NULL
, 'd'},
79 {"module", no_argument
, NULL
, 'M'},
80 {"vty_socket", required_argument
, NULL
, OPTION_VTYSOCK
},
81 {"moduledir", required_argument
, NULL
, OPTION_MODULEDIR
},
83 static const struct optspec os_always
= {
85 " -h, --help Display this help and exit\n"
86 " -v, --version Print program version\n"
87 " -d, --daemon Runs in daemon mode\n"
88 " -M, --module Load specified module\n"
89 " --vty_socket Override vty socket path\n"
90 " --moduledir Override modules directory\n",
94 static const struct option lo_cfg_pid_dry
[] = {
95 {"pid_file", required_argument
, NULL
, 'i'},
96 {"config_file", required_argument
, NULL
, 'f'},
97 {"dryrun", no_argument
, NULL
, 'C'},
99 static const struct optspec os_cfg_pid_dry
= {
101 " -f, --config_file Set configuration file name\n"
102 " -i, --pid_file Set process identifier file name\n"
103 " -C, --dryrun Check configuration for validity and exit\n",
107 static const struct option lo_zclient
[] = {
108 {"socket", required_argument
, NULL
, 'z'},
110 static const struct optspec os_zclient
= {
111 "z:", " -z, --socket Set path of zebra socket\n", lo_zclient
};
114 static const struct option lo_vty
[] = {
115 {"vty_addr", required_argument
, NULL
, 'A'},
116 {"vty_port", required_argument
, NULL
, 'P'},
118 static const struct optspec os_vty
= {
120 " -A, --vty_addr Set vty's bind address\n"
121 " -P, --vty_port Set vty's port number\n",
125 static const struct option lo_user
[] = {{"user", required_argument
, NULL
, 'u'},
126 {"group", required_argument
, NULL
, 'g'},
128 static const struct optspec os_user
= {"u:g:",
129 " -u, --user User to run as\n"
130 " -g, --group Group to run as\n",
134 static struct frr_daemon_info
*di
= NULL
;
136 void frr_preinit(struct frr_daemon_info
*daemon
, int argc
, char **argv
)
140 /* basename(), opencoded. */
141 char *p
= strrchr(argv
[0], '/');
142 di
->progname
= p
? p
+ 1 : argv
[0];
146 opt_extend(&os_always
);
147 if (!(di
->flags
& FRR_NO_CFG_PID_DRY
))
148 opt_extend(&os_cfg_pid_dry
);
149 if (!(di
->flags
& FRR_NO_PRIVSEP
))
150 opt_extend(&os_user
);
151 if (!(di
->flags
& FRR_NO_ZCLIENT
))
152 opt_extend(&os_zclient
);
153 if (!(di
->flags
& FRR_NO_TCPVTY
))
156 snprintf(config_default
, sizeof(config_default
), "%s/%s.conf",
157 frr_sysconfdir
, di
->name
);
158 snprintf(pidfile_default
, sizeof(pidfile_default
), "%s/%s.pid",
159 frr_vtydir
, di
->name
);
161 strlcpy(frr_protoname
, di
->logname
, sizeof(frr_protoname
));
162 strlcpy(frr_protonameinst
, di
->logname
, sizeof(frr_protonameinst
));
165 void frr_opt_add(const char *optstr
, const struct option
*longopts
,
168 const struct optspec main_opts
= {optstr
, helpstr
, longopts
};
169 opt_extend(&main_opts
);
172 void frr_help_exit(int status
)
174 FILE *target
= status
? stderr
: stdout
;
177 fprintf(stderr
, "Invalid options.\n\n");
180 di
->printhelp(target
);
182 fprintf(target
, "Usage: %s [OPTION...]\n\n%s%s%s\n\n%s",
183 di
->progname
, di
->proghelp
, di
->copyright
? "\n\n" : "",
184 di
->copyright
? di
->copyright
: "", comb_helpstr
);
185 fprintf(target
, "\nReport bugs to %s\n", FRR_BUG_ADDRESS
);
189 struct option_chain
{
190 struct option_chain
*next
;
194 static struct option_chain
*modules
= NULL
, **modnext
= &modules
;
195 static int errors
= 0;
197 static int frr_opt(int opt
)
199 static int vty_port_set
= 0;
200 static int vty_addr_set
= 0;
201 struct option_chain
*oc
;
209 print_version(di
->progname
);
216 oc
= XMALLOC(MTYPE_TMP
, sizeof(*oc
));
223 if (di
->flags
& FRR_NO_CFG_PID_DRY
)
225 di
->pid_file
= optarg
;
228 if (di
->flags
& FRR_NO_CFG_PID_DRY
)
230 di
->config_file
= optarg
;
233 if (di
->flags
& FRR_NO_CFG_PID_DRY
)
238 if (di
->flags
& FRR_NO_ZCLIENT
)
240 zclient_serv_path_set(optarg
);
243 if (di
->flags
& FRR_NO_TCPVTY
)
247 "-A option specified more than once!\n");
252 di
->vty_addr
= optarg
;
255 if (di
->flags
& FRR_NO_TCPVTY
)
259 "-P option specified more than once!\n");
264 di
->vty_port
= strtoul(optarg
, &err
, 0);
265 if (*err
|| !*optarg
) {
267 "invalid port number \"%s\" for -P option\n",
274 if (di
->vty_sock_path
) {
276 "--vty_socket option specified more than once!\n");
280 di
->vty_sock_path
= optarg
;
282 case OPTION_MODULEDIR
:
283 if (di
->module_path
) {
285 "----moduledir option specified more than once!\n");
289 di
->module_path
= optarg
;
292 if (di
->flags
& FRR_NO_PRIVSEP
)
294 di
->privs
->user
= optarg
;
297 if (di
->flags
& FRR_NO_PRIVSEP
)
299 di
->privs
->group
= optarg
;
307 int frr_getopt(int argc
, char *const argv
[], int *longindex
)
312 comb_next_lo
->name
= NULL
;
315 opt
= getopt_long(argc
, argv
, comb_optstr
, comb_lo
, &lidx
);
320 if (opt
== -1 && errors
)
327 static struct thread_master
*master
;
328 struct thread_master
*frr_init(void)
330 struct option_chain
*oc
;
331 struct frrmod_runtime
*module
;
334 dir
= di
->module_path
? di
->module_path
: frr_moduledir
;
339 snprintf(frr_protonameinst
, sizeof(frr_protonameinst
), "%s[%u]",
340 di
->logname
, di
->instance
);
342 openzlog(di
->progname
, di
->logname
, di
->instance
,
343 LOG_CONS
| LOG_NDELAY
| LOG_PID
, LOG_DAEMON
);
344 #if defined(HAVE_CUMULUS)
345 zlog_set_level(ZLOG_DEST_SYSLOG
, zlog_default
->default_lvl
);
348 frrmod_init(di
->module
);
350 modules
= (oc
= modules
)->next
;
351 module
= frrmod_load(oc
->arg
, dir
, moderr
, sizeof(moderr
));
353 fprintf(stderr
, "%s\n", moderr
);
356 XFREE(MTYPE_TMP
, oc
);
359 zprivs_init(di
->privs
);
361 master
= thread_master_create(NULL
);
362 signal_init(master
, di
->n_signals
, di
->signals
);
364 if (di
->flags
& FRR_LIMITED_CLI
)
374 static void frr_daemon_wait(int fd
)
376 struct pollfd pfd
[1];
383 pfd
[0].events
= POLLIN
;
385 ret
= poll(pfd
, 1, -1);
386 if (ret
< 0 && errno
!= EINTR
&& errno
!= EAGAIN
) {
392 exitpid
= waitpid(-1, &exitstat
, WNOHANG
);
394 /* child successfully went to main loop & closed socket */
397 /* child failed one way or another ... */
398 if (WIFEXITED(exitstat
))
399 fprintf(stderr
, "%s failed to start, exited %d\n", di
->name
,
400 WEXITSTATUS(exitstat
));
401 else if (WIFSIGNALED(exitstat
))
402 fprintf(stderr
, "%s crashed in startup, signal %d\n", di
->name
,
405 fprintf(stderr
, "%s failed to start, unknown problem\n",
410 static int daemon_ctl_sock
= -1;
412 static void frr_daemonize(void)
417 if (socketpair(AF_UNIX
, SOCK_STREAM
, 0, fds
)) {
418 perror("socketpair() for daemon control");
437 daemon_ctl_sock
= fds
[1];
442 frr_daemon_wait(fds
[0]);
445 void frr_config_fork(void)
447 hook_call(frr_late_init
, master
);
450 snprintf(config_default
, sizeof(config_default
),
451 "%s/%s-%d.conf", frr_sysconfdir
, di
->name
,
453 snprintf(pidfile_default
, sizeof(pidfile_default
),
454 "%s/%s-%d.pid", frr_vtydir
, di
->name
, di
->instance
);
457 vty_read_config(di
->config_file
, config_default
);
459 /* Don't start execution if we are in dry-run mode */
467 di
->pid_file
= pidfile_default
;
468 pid_output(di
->pid_file
);
471 void frr_vty_serv(void)
473 /* allow explicit override of vty_path in the future
474 * (not currently set anywhere) */
477 dir
= di
->vty_sock_path
? di
->vty_sock_path
: frr_vtydir
;
480 snprintf(vtypath_default
, sizeof(vtypath_default
),
481 "%s/%s-%d.vty", dir
, di
->name
, di
->instance
);
483 snprintf(vtypath_default
, sizeof(vtypath_default
),
484 "%s/%s.vty", dir
, di
->name
);
486 di
->vty_path
= vtypath_default
;
489 vty_serv_sock(di
->vty_addr
, di
->vty_port
, di
->vty_path
);
492 void frr_run(struct thread_master
*master
)
494 char instanceinfo
[64] = "";
499 snprintf(instanceinfo
, sizeof(instanceinfo
), "instance %u ",
502 zlog_notice("%s %s starting: %svty@%d%s", di
->name
, FRR_VERSION
,
503 instanceinfo
, di
->vty_port
, di
->startinfo
);
505 if (daemon_ctl_sock
!= -1) {
506 close(daemon_ctl_sock
);
507 daemon_ctl_sock
= -1;
510 struct thread thread
;
511 while (thread_fetch(master
, &thread
))
512 thread_call(&thread
);