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