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