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