Coverage Report

Created: 2025-08-03 06:36

/src/frr/lib/defaults.c
Line
Count
Source (jump to first uncovered line)
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
10
{
44
10
  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
10
  while (apos[0] || bpos[0]) {
49
10
    if (isdigit((unsigned char)apos[0]) &&
50
10
        isdigit((unsigned char)bpos[0])) {
51
10
      unsigned long av, bv;
52
10
      char *aend = NULL, *bend = NULL;
53
54
10
      av = strtoul(apos, &aend, 10);
55
10
      bv = strtoul(bpos, &bend, 10);
56
10
      if (av < bv)
57
0
        return -1;
58
10
      if (av > bv)
59
10
        return 1;
60
61
0
      apos = aend;
62
0
      bpos = bend;
63
0
      continue;
64
10
    }
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
10
}
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
14
{
81
14
  dflt->next = NULL;
82
14
  *dflt_next = dflt;
83
14
  dflt_next = &dflt->next;
84
85
14
  frr_default_apply_one(dflt, true);
86
14
}
87
88
static bool frr_match_version(const char *name, const char *vspec,
89
            const char *version, bool check)
90
10
{
91
10
  int cmp;
92
10
  static const struct spec {
93
10
    const char *str;
94
10
    int dir, eq;
95
10
  } specs[] = {
96
10
    {"<=", -1, 1},
97
10
    {">=", 1, 1},
98
10
    {"==", 0, 1},
99
10
    {"<", -1, 0},
100
10
    {">", 1, 0},
101
10
    {"=", 0, 1},
102
10
    {NULL, 0, 0},
103
10
  };
104
10
  const struct spec *s;
105
106
10
  if (!vspec)
107
    /* NULL = all versions */
108
0
    return true;
109
110
40
  for (s = specs; s->str; s++)
111
40
    if (!strncmp(s->str, vspec, strlen(s->str)))
112
10
      break;
113
10
  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
10
  vspec += strlen(s->str);
122
10
  while (isspace((unsigned char)*vspec))
123
10
    vspec++;
124
125
10
  cmp = frr_version_cmp(version, vspec);
126
10
  if (cmp == s->dir || (s->eq && cmp == 0))
127
0
    return true;
128
129
10
  return false;
130
10
}
131
132
static void frr_default_apply_one(struct frr_default *dflt, bool check)
133
14
{
134
14
  struct frr_default_entry *entry = dflt->entries;
135
14
  struct frr_default_entry *dfltentry = NULL, *saveentry = NULL;
136
137
29
  for (; entry->match_version || entry->match_profile; entry++) {
138
15
    if (entry->match_profile
139
15
      && strcmp(entry->match_profile, df_profile))
140
10
      continue;
141
142
5
    if (!dfltentry && frr_match_version(dflt->name,
143
5
        entry->match_version, df_version, check))
144
0
      dfltentry = entry;
145
5
    if (!saveentry && frr_match_version(dflt->name,
146
5
        entry->match_version, FRR_VER_SHORT, check))
147
0
      saveentry = entry;
148
149
5
    if (dfltentry && saveentry && !check)
150
0
      break;
151
5
  }
152
  /* found default or arrived at last entry that has NULL,NULL spec */
153
154
14
  if (!dfltentry)
155
14
    dfltentry = entry;
156
14
  if (!saveentry)
157
14
    saveentry = entry;
158
159
14
  if (dflt->dflt_bool)
160
11
    *dflt->dflt_bool = dfltentry->val_bool;
161
14
  if (dflt->dflt_str)
162
0
    *dflt->dflt_str = dfltentry->val_str;
163
14
  if (dflt->dflt_long)
164
0
    *dflt->dflt_long = dfltentry->val_long;
165
14
  if (dflt->dflt_ulong)
166
3
    *dflt->dflt_ulong = dfltentry->val_ulong;
167
14
  if (dflt->dflt_float)
168
0
    *dflt->dflt_float = dfltentry->val_float;
169
14
  if (dflt->save_bool)
170
11
    *dflt->save_bool = saveentry->val_bool;
171
14
  if (dflt->save_str)
172
0
    *dflt->save_str = saveentry->val_str;
173
14
  if (dflt->save_long)
174
0
    *dflt->save_long = saveentry->val_long;
175
14
  if (dflt->save_ulong)
176
3
    *dflt->save_ulong = saveentry->val_ulong;
177
14
  if (dflt->save_float)
178
0
    *dflt->save_float = saveentry->val_float;
179
14
}
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
}