Coverage Report

Created: 2025-10-23 06:55

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/lib/defaults.c
Line
Count
Source
1
// SPDX-License-Identifier: ISC
2
/*
3
 * FRR switchable defaults.
4
 * Copyright (c) 2017-2019  David Lamparter, for NetDEF, Inc.
5
 */
6
7
#include <zebra.h>
8
9
#include "defaults.h"
10
#include "lib/version.h"
11
12
static char df_version[128] = FRR_VER_SHORT, df_profile[128] = DFLT_NAME;
13
static struct frr_default *dflt_first = NULL, **dflt_next = &dflt_first;
14
15
/* these are global for all FRR daemons.  they have to be, since we write an
16
 * integrated config with the same value for all daemons.
17
 */
18
const char *frr_defaults_profiles[] = {
19
  "traditional",
20
  "datacenter",
21
  NULL,
22
};
23
24
static int version_value(int ch)
25
0
{
26
  /* non-ASCII shouldn't happen */
27
0
  if (ch < 0 || ch >= 128)
28
0
    return 2;
29
30
  /* ~foo sorts older than nothing */
31
0
  if (ch == '~')
32
0
    return 0;
33
0
  if (ch == '\0')
34
0
    return 1;
35
0
  if (isalpha(ch))
36
0
    return 0x100 + tolower(ch);
37
38
  /* punctuation and digits (and everything else) */
39
0
  return 0x200 + ch;
40
0
}
41
42
int frr_version_cmp(const char *aa, const char *bb)
43
20
{
44
20
  const char *apos = aa, *bpos = bb;
45
46
  /* || is correct, we won't scan past the end of a string since that
47
   * doesn't compare equal to anything else */
48
20
  while (apos[0] || bpos[0]) {
49
20
    if (isdigit((unsigned char)apos[0]) &&
50
20
        isdigit((unsigned char)bpos[0])) {
51
20
      unsigned long av, bv;
52
20
      char *aend = NULL, *bend = NULL;
53
54
20
      av = strtoul(apos, &aend, 10);
55
20
      bv = strtoul(bpos, &bend, 10);
56
20
      if (av < bv)
57
0
        return -1;
58
20
      if (av > bv)
59
20
        return 1;
60
61
0
      apos = aend;
62
0
      bpos = bend;
63
0
      continue;
64
20
    }
65
66
0
    int a = version_value(*apos++);
67
0
    int b = version_value(*bpos++);
68
69
0
    if (a < b)
70
0
      return -1;
71
0
    if (a > b)
72
0
      return 1;
73
0
  }
74
0
  return 0;
75
20
}
76
77
static void frr_default_apply_one(struct frr_default *dflt, bool check);
78
79
void frr_default_add(struct frr_default *dflt)
80
26
{
81
26
  dflt->next = NULL;
82
26
  *dflt_next = dflt;
83
26
  dflt_next = &dflt->next;
84
85
26
  frr_default_apply_one(dflt, true);
86
26
}
87
88
static bool frr_match_version(const char *name, const char *vspec,
89
            const char *version, bool check)
90
20
{
91
20
  int cmp;
92
20
  static const struct spec {
93
20
    const char *str;
94
20
    int dir, eq;
95
20
  } specs[] = {
96
20
    {"<=", -1, 1},
97
20
    {">=", 1, 1},
98
20
    {"==", 0, 1},
99
20
    {"<", -1, 0},
100
20
    {">", 1, 0},
101
20
    {"=", 0, 1},
102
20
    {NULL, 0, 0},
103
20
  };
104
20
  const struct spec *s;
105
106
20
  if (!vspec)
107
    /* NULL = all versions */
108
0
    return true;
109
110
80
  for (s = specs; s->str; s++)
111
80
    if (!strncmp(s->str, vspec, strlen(s->str)))
112
20
      break;
113
20
  if (!s->str) {
114
0
    if (check)
115
0
      fprintf(stderr, "invalid version specifier for %s: %s",
116
0
        name, vspec);
117
    /* invalid version spec, never matches */
118
0
    return false;
119
0
  }
120
121
20
  vspec += strlen(s->str);
122
20
  while (isspace((unsigned char)*vspec))
123
20
    vspec++;
124
125
20
  cmp = frr_version_cmp(version, vspec);
126
20
  if (cmp == s->dir || (s->eq && cmp == 0))
127
0
    return true;
128
129
20
  return false;
130
20
}
131
132
static void frr_default_apply_one(struct frr_default *dflt, bool check)
133
26
{
134
26
  struct frr_default_entry *entry = dflt->entries;
135
26
  struct frr_default_entry *dfltentry = NULL, *saveentry = NULL;
136
137
54
  for (; entry->match_version || entry->match_profile; entry++) {
138
28
    if (entry->match_profile
139
20
      && strcmp(entry->match_profile, df_profile))
140
18
      continue;
141
142
10
    if (!dfltentry && frr_match_version(dflt->name,
143
10
        entry->match_version, df_version, check))
144
0
      dfltentry = entry;
145
10
    if (!saveentry && frr_match_version(dflt->name,
146
10
        entry->match_version, FRR_VER_SHORT, check))
147
0
      saveentry = entry;
148
149
10
    if (dfltentry && saveentry && !check)
150
0
      break;
151
10
  }
152
  /* found default or arrived at last entry that has NULL,NULL spec */
153
154
26
  if (!dfltentry)
155
26
    dfltentry = entry;
156
26
  if (!saveentry)
157
26
    saveentry = entry;
158
159
26
  if (dflt->dflt_bool)
160
20
    *dflt->dflt_bool = dfltentry->val_bool;
161
26
  if (dflt->dflt_str)
162
0
    *dflt->dflt_str = dfltentry->val_str;
163
26
  if (dflt->dflt_long)
164
0
    *dflt->dflt_long = dfltentry->val_long;
165
26
  if (dflt->dflt_ulong)
166
6
    *dflt->dflt_ulong = dfltentry->val_ulong;
167
26
  if (dflt->dflt_float)
168
0
    *dflt->dflt_float = dfltentry->val_float;
169
26
  if (dflt->save_bool)
170
20
    *dflt->save_bool = saveentry->val_bool;
171
26
  if (dflt->save_str)
172
0
    *dflt->save_str = saveentry->val_str;
173
26
  if (dflt->save_long)
174
0
    *dflt->save_long = saveentry->val_long;
175
26
  if (dflt->save_ulong)
176
6
    *dflt->save_ulong = saveentry->val_ulong;
177
26
  if (dflt->save_float)
178
0
    *dflt->save_float = saveentry->val_float;
179
26
}
180
181
void frr_defaults_apply(void)
182
0
{
183
0
  struct frr_default *dflt;
184
185
0
  for (dflt = dflt_first; dflt; dflt = dflt->next)
186
0
    frr_default_apply_one(dflt, false);
187
0
}
188
189
bool frr_defaults_profile_valid(const char *profile)
190
0
{
191
0
  const char **p;
192
193
0
  for (p = frr_defaults_profiles; *p; p++)
194
0
    if (!strcmp(profile, *p))
195
0
      return true;
196
0
  return false;
197
0
}
198
199
const char *frr_defaults_version(void)
200
0
{
201
0
  return df_version;
202
0
}
203
204
const char *frr_defaults_profile(void)
205
0
{
206
0
  return df_profile;
207
0
}
208
209
void frr_defaults_version_set(const char *version)
210
0
{
211
0
  strlcpy(df_version, version, sizeof(df_version));
212
0
  frr_defaults_apply();
213
0
}
214
215
void frr_defaults_profile_set(const char *profile)
216
0
{
217
0
  strlcpy(df_profile, profile, sizeof(df_profile));
218
0
  frr_defaults_apply();
219
0
}