]> git.ipfire.org Git - thirdparty/bird.git/blob - sysdep/unix/main.c
Adds support for soft reconfiguration.
[thirdparty/bird.git] / sysdep / unix / main.c
1 /*
2 * BIRD Internet Routing Daemon -- Unix Entry Point
3 *
4 * (c) 1998--2000 Martin Mares <mj@ucw.cz>
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
9 #undef LOCAL_DEBUG
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <fcntl.h>
14 #include <unistd.h>
15 #include <signal.h>
16
17 #include "nest/bird.h"
18 #include "lib/lists.h"
19 #include "lib/resource.h"
20 #include "lib/socket.h"
21 #include "lib/event.h"
22 #include "lib/string.h"
23 #include "nest/route.h"
24 #include "nest/protocol.h"
25 #include "nest/iface.h"
26 #include "nest/cli.h"
27 #include "nest/locks.h"
28 #include "conf/conf.h"
29 #include "filter/filter.h"
30
31 #include "unix.h"
32 #include "krt.h"
33
34 /*
35 * Debugging
36 */
37
38 #ifdef DEBUGGING
39 static int debug_flag = 1;
40 #else
41 static int debug_flag = 0;
42 #endif
43
44 void
45 async_dump(void)
46 {
47 debug("INTERNAL STATE DUMP\n\n");
48
49 rdump(&root_pool);
50 sk_dump_all();
51 tm_dump_all();
52 if_dump_all();
53 neigh_dump_all();
54 rta_dump_all();
55 rt_dump_all();
56 protos_dump_all();
57
58 debug("\n");
59 }
60
61 /*
62 * Reading the Configuration
63 */
64
65 static int conf_fd;
66 static char *config_name = PATH_CONFIG;
67
68 static int
69 cf_read(byte *dest, unsigned int len)
70 {
71 int l = read(conf_fd, dest, len);
72 if (l < 0)
73 cf_error("Read error");
74 return l;
75 }
76
77 void
78 sysdep_preconfig(struct config *c)
79 {
80 init_list(&c->logfiles);
81 }
82
83 int
84 sysdep_commit(struct config *new, struct config *old UNUSED)
85 {
86 log_switch(debug_flag, &new->logfiles);
87 return 0;
88 }
89
90 static int
91 unix_read_config(struct config **cp, char *name)
92 {
93 struct config *conf = config_alloc(name);
94 int ret;
95
96 *cp = conf;
97 conf_fd = open(name, O_RDONLY);
98 if (conf_fd < 0)
99 return 0;
100 cf_read_hook = cf_read;
101 ret = config_parse(conf);
102 close(conf_fd);
103 return ret;
104 }
105
106 static void
107 read_config(void)
108 {
109 struct config *conf;
110
111 if (!unix_read_config(&conf, config_name))
112 {
113 if (conf->err_msg)
114 die("%s, line %d: %s", config_name, conf->err_lino, conf->err_msg);
115 else
116 die("Unable to open configuration file %s: %m", config_name);
117 }
118 config_commit(conf, RECONFIG_HARD);
119 }
120
121 void
122 async_config(void)
123 {
124 struct config *conf;
125
126 log(L_INFO "Reconfiguration requested by SIGHUP");
127 if (!unix_read_config(&conf, config_name))
128 {
129 if (conf->err_msg)
130 log(L_ERR "%s, line %d: %s", config_name, conf->err_lino, conf->err_msg);
131 else
132 log(L_ERR "Unable to open configuration file %s: %m", config_name);
133 config_free(conf);
134 }
135 else
136 config_commit(conf, RECONFIG_HARD);
137 }
138
139 void
140 cmd_reconfig(char *name, int type)
141 {
142 struct config *conf;
143
144 if (!name)
145 name = config_name;
146 cli_msg(-2, "Reading configuration from %s", name);
147 if (!unix_read_config(&conf, name))
148 {
149 if (conf->err_msg)
150 cli_msg(8002, "%s, line %d: %s", name, conf->err_lino, conf->err_msg);
151 else
152 cli_msg(8002, "%s: %m", name);
153 config_free(conf);
154 }
155 else
156 {
157 switch (config_commit(conf, type))
158 {
159 case CONF_DONE:
160 cli_msg(3, "Reconfigured.");
161 break;
162 case CONF_PROGRESS:
163 cli_msg(4, "Reconfiguration in progress.");
164 break;
165 case CONF_SHUTDOWN:
166 cli_msg(6, "Reconfiguration ignored, shutting down.");
167 break;
168 default:
169 cli_msg(5, "Reconfiguration already in progress, queueing new config");
170 }
171 }
172 }
173
174 /*
175 * Command-Line Interface
176 */
177
178 static sock *cli_sk;
179 static char *path_control_socket = PATH_CONTROL_SOCKET;
180
181 int
182 cli_write(cli *c)
183 {
184 sock *s = c->priv;
185
186 if (c->tx_pos)
187 {
188 struct cli_out *o = c->tx_pos;
189 s->tbuf = o->outpos;
190 if (sk_send(s, o->wpos - o->outpos) > 0)
191 {
192 c->tx_pos = o->next;
193 ev_schedule(c->event);
194 }
195 }
196 return !c->tx_pos;
197 }
198
199 int
200 cli_get_command(cli *c)
201 {
202 sock *s = c->priv;
203 byte *t = c->rx_aux ? : s->rbuf;
204 byte *tend = s->rpos;
205 byte *d = c->rx_pos;
206 byte *dend = c->rx_buf + CLI_RX_BUF_SIZE - 2;
207
208 while (t < tend)
209 {
210 if (*t == '\r')
211 t++;
212 else if (*t == '\n')
213 {
214 t++;
215 c->rx_pos = c->rx_buf;
216 c->rx_aux = t;
217 *d = 0;
218 return (d < dend) ? 1 : -1;
219 }
220 else if (d < dend)
221 *d++ = *t++;
222 }
223 c->rx_aux = s->rpos = s->rbuf;
224 c->rx_pos = d;
225 return 0;
226 }
227
228 static int
229 cli_rx(sock *s, int size UNUSED)
230 {
231 cli_kick(s->data);
232 return 0;
233 }
234
235 static void
236 cli_tx(sock *s)
237 {
238 cli *c = s->data;
239
240 if (cli_write(c))
241 cli_written(c);
242 }
243
244 static void
245 cli_err(sock *s, int err)
246 {
247 if (config->cli_debug)
248 {
249 if (err)
250 log(L_INFO "CLI connection dropped: %s", strerror(err));
251 else
252 log(L_INFO "CLI connection closed");
253 }
254 cli_free(s->data);
255 }
256
257 static int
258 cli_connect(sock *s, int size UNUSED)
259 {
260 cli *c;
261
262 if (config->cli_debug)
263 log(L_INFO "CLI connect");
264 s->rx_hook = cli_rx;
265 s->tx_hook = cli_tx;
266 s->err_hook = cli_err;
267 s->data = c = cli_new(s);
268 s->pool = c->pool; /* We need to have all the socket buffers allocated in the cli pool */
269 c->rx_pos = c->rx_buf;
270 c->rx_aux = NULL;
271 rmove(s, c->pool);
272 return 1;
273 }
274
275 static void
276 cli_init_unix(void)
277 {
278 sock *s;
279
280 cli_init();
281 s = cli_sk = sk_new(cli_pool);
282 s->type = SK_UNIX_PASSIVE;
283 s->rx_hook = cli_connect;
284 s->rbsize = 1024;
285 if (sk_open_unix(s, path_control_socket) < 0)
286 die("Unable to create control socket %s", path_control_socket);
287 }
288
289 /*
290 * Shutdown
291 */
292
293 void
294 async_shutdown(void)
295 {
296 DBG("Shutting down...\n");
297 order_shutdown();
298 }
299
300 void
301 sysdep_shutdown_done(void)
302 {
303 unlink(PATH_CONTROL_SOCKET);
304 die("System shutdown completed");
305 }
306
307 /*
308 * Signals
309 */
310
311 static void
312 handle_sighup(int sig UNUSED)
313 {
314 DBG("Caught SIGHUP...\n");
315 async_config_flag = 1;
316 }
317
318 static void
319 handle_sigusr(int sig UNUSED)
320 {
321 DBG("Caught SIGUSR...\n");
322 async_dump_flag = 1;
323 }
324
325 static void
326 handle_sigterm(int sig UNUSED)
327 {
328 DBG("Caught SIGTERM...\n");
329 async_shutdown_flag = 1;
330 }
331
332 static void
333 signal_init(void)
334 {
335 struct sigaction sa;
336
337 bzero(&sa, sizeof(sa));
338 sa.sa_handler = handle_sigusr;
339 sa.sa_flags = SA_RESTART;
340 sigaction(SIGUSR1, &sa, NULL);
341 sa.sa_handler = handle_sighup;
342 sa.sa_flags = SA_RESTART;
343 sigaction(SIGHUP, &sa, NULL);
344 sa.sa_handler = handle_sigterm;
345 sa.sa_flags = SA_RESTART;
346 sigaction(SIGTERM, &sa, NULL);
347 signal(SIGPIPE, SIG_IGN);
348 }
349
350 /*
351 * Parsing of command-line arguments
352 */
353
354 static char *opt_list = "c:dD:s:";
355
356 static void
357 usage(void)
358 {
359 fprintf(stderr, "Usage: bird [-c <config-file>] [-d] [-D <debug-file>] [-s <control-socket>]\n");
360 exit(1);
361 }
362
363 static void
364 parse_args(int argc, char **argv)
365 {
366 int c;
367
368 if (argc == 2)
369 {
370 if (!strcmp(argv[1], "--version"))
371 {
372 fprintf(stderr, "BIRD version " BIRD_VERSION "\n");
373 exit(0);
374 }
375 if (!strcmp(argv[1], "--help"))
376 usage();
377 }
378 while ((c = getopt(argc, argv, opt_list)) >= 0)
379 switch (c)
380 {
381 case 'c':
382 config_name = optarg;
383 break;
384 case 'd':
385 debug_flag |= 1;
386 break;
387 case 'D':
388 log_init_debug(optarg);
389 debug_flag |= 2;
390 break;
391 case 's':
392 path_control_socket = optarg;
393 break;
394 default:
395 usage();
396 }
397 if (optind < argc)
398 usage();
399 }
400
401 /*
402 * Hic Est main()
403 */
404
405 int
406 main(int argc, char **argv)
407 {
408 #ifdef HAVE_LIBDMALLOC
409 if (!getenv("DMALLOC_OPTIONS"))
410 dmalloc_debug(0x2f03d00);
411 #endif
412
413 parse_args(argc, argv);
414 if (debug_flag == 1)
415 log_init_debug("");
416 log_init(debug_flag, 1);
417
418 test_old_bird(path_control_socket);
419
420 DBG("Initializing.\n");
421 resource_init();
422 olock_init();
423 io_init();
424 rt_init();
425 if_init();
426
427 protos_build();
428 proto_build(&proto_unix_kernel);
429 proto_build(&proto_unix_iface);
430
431 read_config();
432
433 if (!debug_flag)
434 {
435 pid_t pid = fork();
436 if (pid < 0)
437 die("fork: %m");
438 if (pid)
439 return 0;
440 setsid();
441 close(0);
442 if (open("/dev/null", O_RDWR) < 0)
443 die("Cannot open /dev/null: %m");
444 dup2(0, 1);
445 dup2(0, 2);
446 }
447
448 signal_init();
449
450 cli_init_unix();
451
452 #ifdef LOCAL_DEBUG
453 async_dump_flag = 1;
454 #endif
455
456 DBG("Entering I/O loop.\n");
457
458 io_loop();
459 bug("I/O loop died");
460 }