From ec57bbf67f9e4221fb98f6769f592cedf2eb2d24 Mon Sep 17 00:00:00 2001 From: Ondrej Filip Date: Mon, 30 Sep 2013 14:07:34 +0200 Subject: [PATCH 1/6] Recheck export/import/receive limits during reconfiguration. --- nest/proto.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/nest/proto.c b/nest/proto.c index 60495aa0..140ec943 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -376,6 +376,7 @@ int proto_reconfig_type; /* Hack to propagate type info to pipe reconfigure hoo static int proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config *nc, int type) { + struct announce_hook *ah = p->main_ahook; /* If the protocol is DOWN, we just restart it */ if (p->proto_state == PS_DOWN) return 0; @@ -407,14 +408,31 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config /* Update filters and limits in the main announce hook Note that this also resets limit state */ - if (p->main_ahook) + if (ah) { - p->main_ahook->in_filter = nc->in_filter; - p->main_ahook->out_filter = nc->out_filter; - p->main_ahook->rx_limit = nc->rx_limit; - p->main_ahook->in_limit = nc->in_limit; - p->main_ahook->out_limit = nc->out_limit; - p->main_ahook->in_keep_filtered = nc->in_keep_filtered; + ah->in_filter = nc->in_filter; + ah->out_filter = nc->out_filter; + ah->rx_limit = nc->rx_limit; + ah->in_limit = nc->in_limit; + ah->out_limit = nc->out_limit; + ah->in_keep_filtered = nc->in_keep_filtered; + + if (p->proto_state == PS_UP) /* Recheck export/import/receive limit */ + { + struct proto_stats *stats = ah->stats; + struct proto_limit *l = ah->in_limit; + u32 all_routes = stats->imp_routes + stats->filt_routes; + + if (l && (stats->imp_routes >= l->limit)) proto_notify_limit(ah, l, PLD_IN, stats->imp_routes); + + l = ah->rx_limit; + + if (l && ( all_routes >= l->limit)) proto_notify_limit(ah, l, PLD_RX, all_routes ); + + l = ah->out_limit; + + if (l && ( stats->exp_routes >= l->limit)) proto_notify_limit(ah, l, PLD_OUT, stats->exp_routes); + } } /* Update routes when filters changed. If the protocol in not UP, From b655596d1d9ad7664d12249c946ba3483b2de3f0 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Wed, 2 Oct 2013 11:42:46 +0200 Subject: [PATCH 2/6] Simplifies val_in_range(). Also fixes missing type check for element ~ set. --- filter/filter.c | 95 +++++++++++++++++++------------------------------ lib/birdlib.h | 6 ++++ 2 files changed, 42 insertions(+), 59 deletions(-) diff --git a/filter/filter.c b/filter/filter.c index 0fc10f1f..acdd8dc7 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -220,39 +220,6 @@ fprefix_get_bounds(struct f_prefix *px, int *l, int *h) } } -/* - * val_simple_in_range - check if @v1 ~ @v2 for everything except sets - */ -static int -val_simple_in_range(struct f_val v1, struct f_val v2) -{ - if ((v1.type == T_PATH) && (v2.type == T_PATH_MASK)) - return as_path_match(v1.val.ad, v2.val.path_mask); - if ((v1.type == T_INT) && (v2.type == T_PATH)) - return as_path_is_member(v2.val.ad, v1.val.i); - - if (((v1.type == T_PAIR) || (v1.type == T_QUAD)) && (v2.type == T_CLIST)) - return int_set_contains(v2.val.ad, v1.val.i); -#ifndef IPV6 - /* IP->Quad implicit conversion */ - if ((v1.type == T_IP) && (v2.type == T_CLIST)) - return int_set_contains(v2.val.ad, ipa_to_u32(v1.val.px.ip)); -#endif - if ((v1.type == T_EC) && (v2.type == T_ECLIST)) - return ec_set_contains(v2.val.ad, v1.val.ec); - - if ((v1.type == T_STRING) && (v2.type == T_STRING)) - return patmatch(v2.val.s, v1.val.s); - - if ((v1.type == T_IP) && (v2.type == T_PREFIX)) - return ipa_in_net(v1.val.px.ip, v2.val.px.ip, v2.val.px.len); - - if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX)) - return net_in_net(v1.val.px.ip, v1.val.px.len, v2.val.px.ip, v2.val.px.len); - - return CMP_ERROR; -} - static int clist_set_type(struct f_tree *set, struct f_val *v) { @@ -396,47 +363,57 @@ eclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int po * @v1: element * @v2: set * - * Checks if @v1 is element (|~| operator) of @v2. Sets are internally represented as balanced trees, see - * |tree.c| module (this is not limited to sets, but for non-set cases, val_simple_in_range() is called early). + * Checks if @v1 is element (|~| operator) of @v2. */ static int val_in_range(struct f_val v1, struct f_val v2) { - int res; + if ((v1.type == T_PATH) && (v2.type == T_PATH_MASK)) + return as_path_match(v1.val.ad, v2.val.path_mask); - res = val_simple_in_range(v1, v2); + if ((v1.type == T_INT) && (v2.type == T_PATH)) + return as_path_is_member(v2.val.ad, v1.val.i); + + if (((v1.type == T_PAIR) || (v1.type == T_QUAD)) && (v2.type == T_CLIST)) + return int_set_contains(v2.val.ad, v1.val.i); +#ifndef IPV6 + /* IP->Quad implicit conversion */ + if ((v1.type == T_IP) && (v2.type == T_CLIST)) + return int_set_contains(v2.val.ad, ipa_to_u32(v1.val.px.ip)); +#endif + + if ((v1.type == T_EC) && (v2.type == T_ECLIST)) + return ec_set_contains(v2.val.ad, v1.val.ec); + + if ((v1.type == T_STRING) && (v2.type == T_STRING)) + return patmatch(v2.val.s, v1.val.s); + + if ((v1.type == T_IP) && (v2.type == T_PREFIX)) + return ipa_in_net(v1.val.px.ip, v2.val.px.ip, v2.val.px.len); + + if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX)) + return net_in_net(v1.val.px.ip, v1.val.px.len, v2.val.px.ip, v2.val.px.len); - if (res != CMP_ERROR) - return res; - if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX_SET)) return trie_match_fprefix(v2.val.ti, &v1.val.px); - if ((v1.type == T_CLIST) && (v2.type == T_SET)) + if (v2.type != T_SET) + return CMP_ERROR; + + /* With integrated Quad<->IP implicit conversion */ + if ((v1.type == v2.val.t->from.type) || + ((IP_VERSION == 4) && (v1.type == T_QUAD) && (v2.val.t->from.type == T_IP))) + return !!find_tree(v2.val.t, v1); + + if (v1.type == T_CLIST) return clist_match_set(v1.val.ad, v2.val.t); - if ((v1.type == T_ECLIST) && (v2.type == T_SET)) + if (v1.type == T_ECLIST) return eclist_match_set(v1.val.ad, v2.val.t); - if ((v1.type == T_PATH) && (v2.type == T_SET)) + if (v1.type == T_PATH) return as_path_match_set(v1.val.ad, v2.val.t); - if (v2.type == T_SET) - switch (v1.type) { - case T_ENUM: - case T_INT: - case T_PAIR: - case T_QUAD: - case T_IP: - case T_EC: - { - struct f_tree *n; - n = find_tree(v2.val.t, v1); - if (!n) - return 0; - return !! (val_simple_in_range(v1, n->from)); /* We turn CMP_ERROR into compared ok, and that's fine */ - } - } return CMP_ERROR; } diff --git a/lib/birdlib.h b/lib/birdlib.h index 479f3d5c..7e6e8526 100644 --- a/lib/birdlib.h +++ b/lib/birdlib.h @@ -34,6 +34,12 @@ #define NULL ((void *) 0) #endif +#ifndef IPV6 +#define IP_VERSION 4 +#else +#define IP_VERSION 6 +#endif + /* Macros for gcc attributes */ #define NORET __attribute__((noreturn)) From 70c5780535fa3bd2360e8208f9273ac6d1741107 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Wed, 2 Oct 2013 12:10:09 +0200 Subject: [PATCH 3/6] Minor code cleanups. Thanks to Sergey Popovich for the patch. --- filter/filter.c | 41 +++++++++++++++++------------------------ 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/filter/filter.c b/filter/filter.c index acdd8dc7..4198a408 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -112,25 +112,22 @@ pm_format(struct f_path_mask *p, byte *buf, unsigned int size) *buf = 0; } -static inline int int_cmp(int i1, int i2) +static inline int +int_cmp(int i1, int i2) { - if (i1 == i2) return 0; - if (i1 < i2) return -1; - else return 1; + return (i1 > i2) - (i1 < i2); } -static inline int uint_cmp(unsigned int i1, unsigned int i2) +static inline int +uint_cmp(unsigned int i1, unsigned int i2) { - if (i1 == i2) return 0; - if (i1 < i2) return -1; - else return 1; + return (int)(i1 > i2) - (int)(i1 < i2); } -static inline int u64_cmp(u64 i1, u64 i2) +static inline int +u64_cmp(u64 i1, u64 i2) { - if (i1 == i2) return 0; - if (i1 < i2) return -1; - else return 1; + return (int)(i1 > i2) - (int)(i1 < i2); } /** @@ -147,14 +144,12 @@ val_compare(struct f_val v1, struct f_val v2) { int rc; - if ((v1.type == T_VOID) && (v2.type == T_VOID)) - return 0; - if (v1.type == T_VOID) /* Hack for else */ - return -1; - if (v2.type == T_VOID) - return 1; - if (v1.type != v2.type) { + if (v1.type == T_VOID) /* Hack for else */ + return -1; + if (v2.type == T_VOID) + return 1; + #ifndef IPV6 /* IP->Quad implicit conversion */ if ((v1.type == T_QUAD) && (v2.type == T_IP)) @@ -181,15 +176,13 @@ val_compare(struct f_val v1, struct f_val v2) case T_PREFIX: if (rc = ipa_compare(v1.val.px.ip, v2.val.px.ip)) return rc; - if (v1.val.px.len < v2.val.px.len) - return -1; - if (v1.val.px.len > v2.val.px.len) - return 1; - return 0; + return int_cmp(v1.val.px.len, v2.val.px.len); case T_PATH_MASK: return pm_path_compare(v1.val.path_mask, v2.val.path_mask); case T_STRING: return strcmp(v1.val.s, v2.val.s); + case T_VOID: + return 0; default: debug( "Compare of unknown entities: %x\n", v1.type ); return CMP_ERROR; From 28a10f84cbc3635e59bff348cb1715859dfacade Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Wed, 2 Oct 2013 14:41:37 +0200 Subject: [PATCH 4/6] Some fixes in filter code. Thanks to Sergey Popovich for original patches. --- filter/filter.c | 121 ++++++++++++++++++++++++++--------------------- filter/filter.h | 2 +- filter/test.conf | 6 +++ filter/tree.c | 5 ++ filter/trie.c | 2 +- nest/route.h | 4 ++ nest/rt-attr.c | 3 +- 7 files changed, 85 insertions(+), 58 deletions(-) diff --git a/filter/filter.c b/filter/filter.c index 4198a408..50e3f403 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -58,22 +58,6 @@ adata_empty(struct linpool *pool, int l) return res; } -static int -pm_path_compare(struct f_path_mask *m1, struct f_path_mask *m2) -{ - while (1) { - if ((!m1) || (!m2)) - return !((!m1) && (!m2)); - - /* FIXME: buggy, should return -1, 0, 1; but it doesn't matter */ - if ((m1->kind != m2->kind) || (m1->val != m2->val)) return 1; - m1 = m1->next; - m2 = m2->next; - } -} - -u32 f_eval_asn(struct f_inst *expr); - static void pm_format(struct f_path_mask *p, byte *buf, unsigned int size) { @@ -135,9 +119,9 @@ u64_cmp(u64 i1, u64 i2) * @v1: first value * @v2: second value * - * Compares two values and returns -1, 0, 1 on <, =, > or 999 on error. - * Tree module relies on this giving consistent results so that it can - * build balanced trees. + * Compares two values and returns -1, 0, 1 on <, =, > or CMP_ERROR on + * error. Tree module relies on this giving consistent results so + * that it can be used for building balanced trees. */ int val_compare(struct f_val v1, struct f_val v2) @@ -161,7 +145,10 @@ val_compare(struct f_val v1, struct f_val v2) debug( "Types do not match in val_compare\n" ); return CMP_ERROR; } + switch (v1.type) { + case T_VOID: + return 0; case T_ENUM: case T_INT: case T_BOOL: @@ -177,22 +164,62 @@ val_compare(struct f_val v1, struct f_val v2) if (rc = ipa_compare(v1.val.px.ip, v2.val.px.ip)) return rc; return int_cmp(v1.val.px.len, v2.val.px.len); - case T_PATH_MASK: - return pm_path_compare(v1.val.path_mask, v2.val.path_mask); case T_STRING: return strcmp(v1.val.s, v2.val.s); - case T_VOID: - return 0; default: - debug( "Compare of unknown entities: %x\n", v1.type ); return CMP_ERROR; } } -int -tree_compare(const void *p1, const void *p2) +static int +pm_path_same(struct f_path_mask *m1, struct f_path_mask *m2) { - return val_compare((* (struct f_tree **) p1)->from, (* (struct f_tree **) p2)->from); + while (m1 && m2) + { + if ((m1->kind != m2->kind) || (m1->val != m2->val)) + return 0; + + m1 = m1->next; + m2 = m2->next; + } + + return !m1 && !m2; +} + +/** + * val_same - compare two values + * @v1: first value + * @v2: second value + * + * Compares two values and returns 1 if they are same and 0 if not. + * Comparison of values of different types is valid and returns 0. + */ +int +val_same(struct f_val v1, struct f_val v2) +{ + int rc; + + rc = val_compare(v1, v2); + if (rc != CMP_ERROR) + return !rc; + + if (v1.type != v2.type) + return 0; + + switch (v1.type) { + case T_PATH_MASK: + return pm_path_same(v1.val.path_mask, v2.val.path_mask); + case T_PATH: + case T_CLIST: + case T_ECLIST: + return adata_same(v1.val.ad, v2.val.ad); + case T_SET: + return same_tree(v1.val.t, v2.val.t); + case T_PREFIX_SET: + return trie_same(v1.val.ti, v2.val.ti); + default: + bug("Invalid type in val_same(): %x", v1.type); + } } void @@ -687,8 +714,15 @@ interpret(struct f_inst *what) res.val.i = (x); \ break; - case P('!','='): COMPARE(i!=0); - case P('=','='): COMPARE(i==0); +#define SAME(x) \ + TWOARGS; \ + i = val_same(v1, v2); \ + res.type = T_BOOL; \ + res.val.i = (x); \ + break; + + case P('!','='): SAME(!i); + case P('=','='): SAME(i); case '<': COMPARE(i==-1); case P('<','='): COMPARE(i!=1); @@ -1379,33 +1413,12 @@ i_same(struct f_inst *f1, struct f_inst *f2) A2_SAME; } break; - case 'C': - { - struct f_val *v1 = (struct f_val *) f1->a1.p; - struct f_val *v2 = (struct f_val *) f2->a1.p; - /* Handle some cases that are not handled by val_compare() - also T_PATH, T_CLIST and T_ECLIST does not work, - but you cannot easily create such constants */ - - if ((v1->type == T_SET) && (v2->type == T_SET)) - { - if (!same_tree(v1->val.t, v2->val.t)) - return 0; - break; - } - - if ((v1->type == T_PREFIX_SET) && (v2->type == T_PREFIX_SET)) - { - if (!trie_same(v1->val.ti, v2->val.ti)) - return 0; - break; - } - - if (val_compare(*v1 , *v2)) - return 0; - } + case 'C': + if (!val_same(* (struct f_val *) f1->a1.p, * (struct f_val *) f2->a1.p)) + return 0; break; + case 'V': if (strcmp((char *) f1->a2.p, (char *) f2->a2.p)) return 0; diff --git a/filter/filter.h b/filter/filter.h index dcac8253..5570a8a3 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -116,7 +116,7 @@ int filter_same(struct filter *new, struct filter *old); int i_same(struct f_inst *f1, struct f_inst *f2); int val_compare(struct f_val v1, struct f_val v2); -int tree_compare(const void *p1, const void *p2); +int val_same(struct f_val v1, struct f_val v2); void val_print(struct f_val v); diff --git a/filter/test.conf b/filter/test.conf index 048983b5..b8f706cb 100644 --- a/filter/test.conf +++ b/filter/test.conf @@ -282,6 +282,12 @@ string s; # if 1 <= 1 then printn "."; else { print "*** FAIL: test 3"; } if 1234 < 1234 then { print "*** FAIL: test 4"; quitbird; } else print "ok"; is = [ 2, 3, 4, 7..11 ]; + + print "must be true: ", 1 = 1, " ", 1 != (0,1), " ", 1 != "a", " ", +empty+ = +empty+, " ", -empty- = -empty-, " ", --empty-- = --empty-- , + " ", [1,4..10,20] = [1,4..10,20] , " ", [ 10.0.0.0/8{ 15 , 17 } ] = [ 10.0.0.0/8{ 15 , 17 } ]; + print "must be false: ", 1 != 1, " ", 1 = (0,1), " ", 1 = "a", " ", +empty+ = -empty-, " ", -empty- = --empty--, " ", --empty-- = +empty+ , + " ", [1,2] = [1,3], " ", [ 10.0.0.0/8{ 15 , 17 } ] = [ 11.0.0.0/8{ 15 , 17 } ]; + print " must be true: ", 1.2.0.0/16 ~ [ 1.0.0.0/8{ 15 , 17 } ]; print " data types; must be true: ", 1.2.3.4 = 1.2.3.4, ",", 1 ~ [1,2,3], ",", 5 ~ [1..20], ",", 10 ~ is, ",", 2 ~ [ 1, 2, 3 ], ",", 5 ~ [ 4 .. 7 ], ",", 1.2.3.4 ~ [ 1.2.3.3..1.2.3.5 ], ",", 1.2.3.4 ~ 1.0.0.0/8, ",", 1.0.0.0/8 ~ 1.0.0.0/8, ",", 1.0.0.0/8 ~ [ 1.0.0.0/8+ ]; print " must be true: ", true && true, ",", true || false, ",", ! false && ! false && true, ",", 1 < 2 && 1 != 3, ",", true && true && ! false, ",", true || 1+"a", ",", !(false && 1+"a"); diff --git a/filter/tree.c b/filter/tree.c index f6ab75b4..d27db18b 100644 --- a/filter/tree.c +++ b/filter/tree.c @@ -53,6 +53,11 @@ build_tree_rec(struct f_tree **buf, int l, int h) return n; } +static int +tree_compare(const void *p1, const void *p2) +{ + return val_compare((* (struct f_tree **) p1)->from, (* (struct f_tree **) p2)->from); +} /** * build_tree diff --git a/filter/trie.c b/filter/trie.c index 581332c6..f42afb84 100644 --- a/filter/trie.c +++ b/filter/trie.c @@ -293,7 +293,7 @@ trie_print(struct f_trie *t) logn("["); if (t->zero) { - logn("0.0.0.0/0"); + logn("%I/%d", IPA_NONE, 0); sep = ", "; } trie_node_print(&t->root, &sep); diff --git a/nest/route.h b/nest/route.h index 35b5fa19..e0b88551 100644 --- a/nest/route.h +++ b/nest/route.h @@ -405,6 +405,10 @@ struct adata { byte data[0]; }; +static inline int adata_same(struct adata *a, struct adata *b) +{ return (a->length == b->length && !memcmp(a->data, b->data, a->length)); } + + typedef struct ea_list { struct ea_list *next; /* In case we have an override list */ byte flags; /* Flags: EALF_... */ diff --git a/nest/rt-attr.c b/nest/rt-attr.c index 6aed318b..3f79ee59 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -366,8 +366,7 @@ ea_same(ea_list *x, ea_list *y) if (a->id != b->id || a->flags != b->flags || a->type != b->type || - ((a->type & EAF_EMBEDDED) ? a->u.data != b->u.data : - (a->u.ptr->length != b->u.ptr->length || memcmp(a->u.ptr->data, b->u.ptr->data, a->u.ptr->length)))) + ((a->type & EAF_EMBEDDED) ? a->u.data != b->u.data : !adata_same(a->u.ptr, b->u.ptr))) return 0; } return 1; From 7ccb36d3308ef57d340e663f0cabd24663f4f62a Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Wed, 2 Oct 2013 14:57:29 +0200 Subject: [PATCH 5/6] Implements C.len operator for clist and eclist types. Thanks to Sergey Popovich for the original patch. --- doc/bird.sgml | 2 ++ filter/filter.c | 4 +++- filter/test.conf | 5 +++-- nest/attrs.h | 3 +++ 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/doc/bird.sgml b/doc/bird.sgml index f43eb4bf..050acf33 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -1077,6 +1077,8 @@ incompatible with each other (that is to prevent you from shooting in the foot). no literals of this type. There are three special operators on clists: + returns the length of clist add( adds pair (or quad) length / 4; } +static inline int ec_set_get_size(struct adata *list) +{ return list->length / 8; } + static inline u32 *int_set_get_data(struct adata *list) { return (u32 *) list->data; } From e7c2380260f20a4a3587b47df97879ef91c69774 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sat, 5 Oct 2013 19:30:12 +0200 Subject: [PATCH 6/6] Implements PID file support. Thanks to Thierry Fournier for the original patch. --- sysdep/unix/main.c | 65 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c index bd80ba2c..c7db7c81 100644 --- a/sysdep/unix/main.c +++ b/sysdep/unix/main.c @@ -472,6 +472,58 @@ cli_init_unix(uid_t use_uid, gid_t use_gid) die("chmod: %m"); } +/* + * PID file + */ + +static char *pid_file; +static int pid_fd; + +static inline void +open_pid_file(void) +{ + if (!pid_file) + return; + + pid_fd = open(pid_file, O_WRONLY|O_CREAT, 0664); + if (pid_fd < 0) + die("Cannot create PID file %s: %m", pid_file); +} + +static inline void +write_pid_file(void) +{ + int pl, rv; + char ps[24]; + + if (!pid_file) + return; + + /* We don't use PID file for uniqueness, so no need for locking */ + + pl = bsnprintf(ps, sizeof(ps), "%ld\n", (long) getpid()); + if (pl < 0) + bug("PID buffer too small"); + + rv = ftruncate(pid_fd, 0); + if (rv < 0) + die("fruncate: %m"); + + rv = write(pid_fd, ps, pl); + if(rv < 0) + die("write: %m"); + + close(pid_fd); +} + +static inline void +unlink_pid_file(void) +{ + if (pid_file) + unlink(pid_file); +} + + /* * Shutdown */ @@ -496,6 +548,7 @@ async_shutdown(void) void sysdep_shutdown_done(void) { + unlink_pid_file(); unlink(path_control_socket); log_msg(L_FATAL "Shutdown completed"); exit(0); @@ -548,7 +601,7 @@ signal_init(void) * Parsing of command-line arguments */ -static char *opt_list = "c:dD:ps:u:g:"; +static char *opt_list = "c:dD:ps:P:u:g:"; static int parse_and_exit; char *bird_name; static char *use_user; @@ -557,7 +610,7 @@ static char *use_group; static void usage(void) { - fprintf(stderr, "Usage: %s [-c ] [-d] [-D ] [-p] [-s ] [-u ] [-g ]\n", bird_name); + fprintf(stderr, "Usage: %s [-c ] [-d] [-D ] [-p] [-s ] [-P ] [-u ] [-g ]\n", bird_name); exit(1); } @@ -656,6 +709,9 @@ parse_args(int argc, char **argv) case 's': path_control_socket = optarg; break; + case 'P': + pid_file = optarg; + break; case 'u': use_user = optarg; break; @@ -709,6 +765,9 @@ main(int argc, char **argv) if (use_uid) drop_uid(use_uid); + if (!parse_and_exit) + open_pid_file(); + protos_build(); proto_build(&proto_unix_kernel); proto_build(&proto_unix_iface); @@ -733,6 +792,8 @@ main(int argc, char **argv) dup2(0, 2); } + write_pid_file(); + signal_init(); #ifdef LOCAL_DEBUG