0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2025-03-21 22:07:03 +00:00

Merge commit 'e7c2380260f20a4a3587b47df97879ef91c69774' into integrated

This commit is contained in:
Ondrej Zajicek 2014-04-29 15:16:32 +02:00
commit 455539ba1b
12 changed files with 241 additions and 151 deletions

View File

@ -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 no literals of this type. There are three special operators on
clists: clists:
<cf><m/C/.len</cf> returns the length of clist <m/C/.
<cf>add(<m/C/,<m/P/)</cf> adds pair (or quad) <m/P/ to clist <cf>add(<m/C/,<m/P/)</cf> adds pair (or quad) <m/P/ to clist
<m/C/ and returns the result. If item <m/P/ is already in <m/C/ and returns the result. If item <m/P/ is already in
clist <m/C/, it does nothing. <m/P/ may also be a clist, clist <m/C/, it does nothing. <m/P/ may also be a clist,

View File

@ -58,22 +58,6 @@ adata_empty(struct linpool *pool, int l)
return res; 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 static void
pm_format(struct f_path_mask *p, byte *buf, unsigned int size) pm_format(struct f_path_mask *p, byte *buf, unsigned int size)
{ {
@ -112,25 +96,22 @@ pm_format(struct f_path_mask *p, byte *buf, unsigned int size)
*buf = 0; *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; return (i1 > i2) - (i1 < i2);
if (i1 < i2) return -1;
else return 1;
} }
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; return (int)(i1 > i2) - (int)(i1 < i2);
if (i1 < i2) return -1;
else return 1;
} }
static inline int u64_cmp(u64 i1, u64 i2) static inline int
u64_cmp(u64 i1, u64 i2)
{ {
if (i1 == i2) return 0; return (int)(i1 > i2) - (int)(i1 < i2);
if (i1 < i2) return -1;
else return 1;
} }
/** /**
@ -138,23 +119,21 @@ static inline int u64_cmp(u64 i1, u64 i2)
* @v1: first value * @v1: first value
* @v2: second value * @v2: second value
* *
* Compares two values and returns -1, 0, 1 on <, =, > or 999 on error. * Compares two values and returns -1, 0, 1 on <, =, > or CMP_ERROR on
* Tree module relies on this giving consistent results so that it can * error. Tree module relies on this giving consistent results so
* build balanced trees. * that it can be used for building balanced trees.
*/ */
int int
val_compare(struct f_val v1, struct f_val v2) val_compare(struct f_val v1, struct f_val v2)
{ {
int rc; 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 != v2.type) {
if (v1.type == T_VOID) /* Hack for else */
return -1;
if (v2.type == T_VOID)
return 1;
#ifndef IPV6 #ifndef IPV6
/* IP->Quad implicit conversion */ /* IP->Quad implicit conversion */
if ((v1.type == T_QUAD) && (v2.type == T_IP)) if ((v1.type == T_QUAD) && (v2.type == T_IP))
@ -166,7 +145,10 @@ val_compare(struct f_val v1, struct f_val v2)
debug( "Types do not match in val_compare\n" ); debug( "Types do not match in val_compare\n" );
return CMP_ERROR; return CMP_ERROR;
} }
switch (v1.type) { switch (v1.type) {
case T_VOID:
return 0;
case T_ENUM: case T_ENUM:
case T_INT: case T_INT:
case T_BOOL: case T_BOOL:
@ -181,25 +163,63 @@ val_compare(struct f_val v1, struct f_val v2)
case T_PREFIX: case T_PREFIX:
if (rc = ipa_compare(v1.val.px.ip, v2.val.px.ip)) if (rc = ipa_compare(v1.val.px.ip, v2.val.px.ip))
return rc; return rc;
if (v1.val.px.len < v2.val.px.len) return int_cmp(v1.val.px.len, v2.val.px.len);
return -1;
if (v1.val.px.len > v2.val.px.len)
return 1;
return 0;
case T_PATH_MASK:
return pm_path_compare(v1.val.path_mask, v2.val.path_mask);
case T_STRING: case T_STRING:
return strcmp(v1.val.s, v2.val.s); return strcmp(v1.val.s, v2.val.s);
default: default:
debug( "Compare of unknown entities: %x\n", v1.type );
return CMP_ERROR; return CMP_ERROR;
} }
} }
int static int
tree_compare(const void *p1, const void *p2) 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 void
@ -220,39 +240,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 static int
clist_set_type(struct f_tree *set, struct f_val *v) clist_set_type(struct f_tree *set, struct f_val *v)
{ {
@ -396,47 +383,57 @@ eclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int po
* @v1: element * @v1: element
* @v2: set * @v2: set
* *
* Checks if @v1 is element (|~| operator) of @v2. Sets are internally represented as balanced trees, see * Checks if @v1 is element (|~| operator) of @v2.
* |tree.c| module (this is not limited to sets, but for non-set cases, val_simple_in_range() is called early).
*/ */
static int static int
val_in_range(struct f_val v1, struct f_val v2) 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)) if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX_SET))
return trie_match_fprefix(v2.val.ti, &v1.val.px); 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); 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); 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); 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; return CMP_ERROR;
} }
@ -717,8 +714,15 @@ interpret(struct f_inst *what)
res.val.i = (x); \ res.val.i = (x); \
break; break;
case P('!','='): COMPARE(i!=0); #define SAME(x) \
case P('=','='): COMPARE(i==0); 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 '<': COMPARE(i==-1);
case P('<','='): COMPARE(i!=1); case P('<','='): COMPARE(i!=1);
@ -1063,7 +1067,9 @@ interpret(struct f_inst *what)
switch(v1.type) { switch(v1.type) {
case T_PREFIX: res.val.i = v1.val.px.len; break; case T_PREFIX: res.val.i = v1.val.px.len; break;
case T_PATH: res.val.i = as_path_getlen(v1.val.ad); break; case T_PATH: res.val.i = as_path_getlen(v1.val.ad); break;
default: runtime( "Prefix or path expected" ); case T_CLIST: res.val.i = int_set_get_size(v1.val.ad); break;
case T_ECLIST: res.val.i = ec_set_get_size(v1.val.ad); break;
default: runtime( "Prefix, path, clist or eclist expected" );
} }
break; break;
case P('c','p'): /* Convert prefix to ... */ case P('c','p'): /* Convert prefix to ... */
@ -1409,33 +1415,12 @@ i_same(struct f_inst *f1, struct f_inst *f2)
A2_SAME; A2_SAME;
} }
break; 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() case 'C':
also T_PATH, T_CLIST and T_ECLIST does not work, if (!val_same(* (struct f_val *) f1->a1.p, * (struct f_val *) f2->a1.p))
but you cannot easily create such constants */ return 0;
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;
}
break; break;
case 'V': case 'V':
if (strcmp((char *) f1->a2.p, (char *) f2->a2.p)) if (strcmp((char *) f1->a2.p, (char *) f2->a2.p))
return 0; return 0;

View File

@ -119,7 +119,7 @@ int filter_same(struct filter *new, struct filter *old);
int i_same(struct f_inst *f1, struct f_inst *f2); int i_same(struct f_inst *f1, struct f_inst *f2);
int val_compare(struct f_val v1, struct f_val v2); 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); void val_print(struct f_val v);

View File

@ -142,10 +142,10 @@ eclist el2;
l = add( l, (3,5) ); l = add( l, (3,5) );
l2 = filter( l, [(3,*)] ); l2 = filter( l, [(3,*)] );
l = delete( l, [(3,2..4)] ); l = delete( l, [(3,2..4)] );
print "Community list (1,2) (3,1) (3,5) ", l; print "Community list (1,2) (3,1) (3,5) ", l, " len: ", l.len;
l = add( l, (3,2) ); l = add( l, (3,2) );
l = add( l, (4,5) ); l = add( l, (4,5) );
print "Community list (1,2) (3,1) (3,2) (3,5) (4,5) ", l; print "Community list (1,2) (3,1) (3,2) (3,5) (4,5) ", l, " len: ", l.len;
print "Should be true: ", l ~ [(*,2)], " ", l ~ [(*,5)], " ", l ~ [(*, one)]; print "Should be true: ", l ~ [(*,2)], " ", l ~ [(*,5)], " ", l ~ [(*, one)];
print "Should be false: ", l ~ [(*,3)], " ", l ~ [(*,(one+6))], " ", l ~ [(*, (one+one+one))]; print "Should be false: ", l ~ [(*,3)], " ", l ~ [(*,(one+6))], " ", l ~ [(*, (one+one+one))];
l = delete( l, [(*,(one+onef(3)))] ); l = delete( l, [(*,(one+onef(3)))] );
@ -168,6 +168,7 @@ eclist el2;
el = add(el, (ro, 11.21.31.41.mask(16), 200)); el = add(el, (ro, 11.21.31.41.mask(16), 200));
print "EC list (rt, 10, 20) (ro, 10.20.30.40, 100) (ro, 11.21.0.0, 200):"; print "EC list (rt, 10, 20) (ro, 10.20.30.40, 100) (ro, 11.21.0.0, 200):";
print el; print el;
print "EC len: ", el.len;
el = delete(el, (rt, 10, 20)); el = delete(el, (rt, 10, 20));
el = delete(el, (rt, 10, 30)); el = delete(el, (rt, 10, 30));
el = add(el, (unknown 2, ten, 1)); el = add(el, (unknown 2, ten, 1));
@ -282,6 +283,12 @@ string s;
# if 1 <= 1 then printn "."; else { print "*** FAIL: test 3"; } # if 1 <= 1 then printn "."; else { print "*** FAIL: test 3"; }
if 1234 < 1234 then { print "*** FAIL: test 4"; quitbird; } else print "ok"; if 1234 < 1234 then { print "*** FAIL: test 4"; quitbird; } else print "ok";
is = [ 2, 3, 4, 7..11 ]; 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 " 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 " 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"); print " must be true: ", true && true, ",", true || false, ",", ! false && ! false && true, ",", 1 < 2 && 1 != 3, ",", true && true && ! false, ",", true || 1+"a", ",", !(false && 1+"a");

View File

@ -53,6 +53,11 @@ build_tree_rec(struct f_tree **buf, int l, int h)
return n; 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 * build_tree

View File

@ -293,7 +293,7 @@ trie_print(struct f_trie *t)
logn("["); logn("[");
if (t->zero) if (t->zero)
{ {
logn("0.0.0.0/0"); logn("%I/%d", IPA_NONE, 0);
sep = ", "; sep = ", ";
} }
trie_node_print(&t->root, &sep); trie_node_print(&t->root, &sep);

View File

@ -34,6 +34,12 @@
#define NULL ((void *) 0) #define NULL ((void *) 0)
#endif #endif
#ifndef IPV6
#define IP_VERSION 4
#else
#define IP_VERSION 6
#endif
/* Macros for gcc attributes */ /* Macros for gcc attributes */
#define NORET __attribute__((noreturn)) #define NORET __attribute__((noreturn))

View File

@ -69,6 +69,9 @@ int as_path_match(struct adata *path, struct f_path_mask *mask);
static inline int int_set_get_size(struct adata *list) static inline int int_set_get_size(struct adata *list)
{ return list->length / 4; } { return list->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) static inline u32 *int_set_get_data(struct adata *list)
{ return (u32 *) list->data; } { return (u32 *) list->data; }

View File

@ -376,6 +376,7 @@ int proto_reconfig_type; /* Hack to propagate type info to pipe reconfigure hoo
static int static int
proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config *nc, int type) 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 the protocol is DOWN, we just restart it */
if (p->proto_state == PS_DOWN) if (p->proto_state == PS_DOWN)
return 0; 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 /* Update filters and limits in the main announce hook
Note that this also resets limit state */ Note that this also resets limit state */
if (p->main_ahook) if (ah)
{ {
p->main_ahook->in_filter = nc->in_filter; ah->in_filter = nc->in_filter;
p->main_ahook->out_filter = nc->out_filter; ah->out_filter = nc->out_filter;
p->main_ahook->rx_limit = nc->rx_limit; ah->rx_limit = nc->rx_limit;
p->main_ahook->in_limit = nc->in_limit; ah->in_limit = nc->in_limit;
p->main_ahook->out_limit = nc->out_limit; ah->out_limit = nc->out_limit;
p->main_ahook->in_keep_filtered = nc->in_keep_filtered; 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, /* Update routes when filters changed. If the protocol in not UP,

View File

@ -450,6 +450,10 @@ struct adata {
byte data[0]; 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 { typedef struct ea_list {
struct ea_list *next; /* In case we have an override list */ struct ea_list *next; /* In case we have an override list */
byte flags; /* Flags: EALF_... */ byte flags; /* Flags: EALF_... */

View File

@ -366,8 +366,7 @@ ea_same(ea_list *x, ea_list *y)
if (a->id != b->id || if (a->id != b->id ||
a->flags != b->flags || a->flags != b->flags ||
a->type != b->type || a->type != b->type ||
((a->type & EAF_EMBEDDED) ? a->u.data != b->u.data : ((a->type & EAF_EMBEDDED) ? a->u.data != b->u.data : !adata_same(a->u.ptr, b->u.ptr)))
(a->u.ptr->length != b->u.ptr->length || memcmp(a->u.ptr->data, b->u.ptr->data, a->u.ptr->length))))
return 0; return 0;
} }
return 1; return 1;

View File

@ -472,6 +472,58 @@ cli_init_unix(uid_t use_uid, gid_t use_gid)
die("chmod: %m"); 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 * Shutdown
*/ */
@ -496,6 +548,7 @@ async_shutdown(void)
void void
sysdep_shutdown_done(void) sysdep_shutdown_done(void)
{ {
unlink_pid_file();
unlink(path_control_socket); unlink(path_control_socket);
log_msg(L_FATAL "Shutdown completed"); log_msg(L_FATAL "Shutdown completed");
exit(0); exit(0);
@ -548,7 +601,7 @@ signal_init(void)
* Parsing of command-line arguments * 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; static int parse_and_exit;
char *bird_name; char *bird_name;
static char *use_user; static char *use_user;
@ -557,7 +610,7 @@ static char *use_group;
static void static void
usage(void) usage(void)
{ {
fprintf(stderr, "Usage: %s [-c <config-file>] [-d] [-D <debug-file>] [-p] [-s <control-socket>] [-u <user>] [-g <group>]\n", bird_name); fprintf(stderr, "Usage: %s [-c <config-file>] [-d] [-D <debug-file>] [-p] [-s <control-socket>] [-P <pid-file>] [-u <user>] [-g <group>]\n", bird_name);
exit(1); exit(1);
} }
@ -656,6 +709,9 @@ parse_args(int argc, char **argv)
case 's': case 's':
path_control_socket = optarg; path_control_socket = optarg;
break; break;
case 'P':
pid_file = optarg;
break;
case 'u': case 'u':
use_user = optarg; use_user = optarg;
break; break;
@ -709,6 +765,9 @@ main(int argc, char **argv)
if (use_uid) if (use_uid)
drop_uid(use_uid); drop_uid(use_uid);
if (!parse_and_exit)
open_pid_file();
protos_build(); protos_build();
proto_build(&proto_unix_kernel); proto_build(&proto_unix_kernel);
proto_build(&proto_unix_iface); proto_build(&proto_unix_iface);
@ -733,6 +792,8 @@ main(int argc, char **argv)
dup2(0, 2); dup2(0, 2);
} }
write_pid_file();
signal_init(); signal_init();
#ifdef LOCAL_DEBUG #ifdef LOCAL_DEBUG