1 /* The tunable framework. See the README.tunables to know how to use the
2 tunable in a glibc module.
4 Copyright (C) 2016-2023 Free Software Foundation, Inc.
5 This file is part of the GNU C Library.
7 The GNU C Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
12 The GNU C Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with the GNU C Library; if not, see
19 <https://www.gnu.org/licenses/>. */
21 /* Mark symbols hidden in static PIE for early self relocation to work. */
23 # pragma GCC visibility push(hidden)
33 #include <array_length.h>
34 #include <dl-minimal-malloc.h>
36 #define TUNABLES_INTERNAL 1
37 #include "dl-tunables.h"
39 #include <not-errno.h>
42 tunables_strdup (const char *in
)
46 while (in
[i
++] != '\0');
47 char *out
= __minimal_malloc (i
+ 1);
49 /* For most of the tunables code, we ignore user errors. However,
50 this is a system error - and running out of memory at program
51 startup should be reported, so we do. */
53 _dl_fatal_printf ("failed to allocate memory to process tunables\n");
62 get_next_env (char **envp
, char **name
, size_t *namelen
, char **val
,
65 while (envp
!= NULL
&& *envp
!= NULL
)
68 char *envline
= *envp
++;
71 while (envline
[len
] != '\0' && envline
[len
] != '=')
74 /* Just the name and no value, go to the next one. */
75 if (envline
[len
] == '\0')
80 *val
= &envline
[len
+ 1];
90 do_tunable_update_val (tunable_t
*cur
, const tunable_val_t
*valp
,
91 const tunable_num_t
*minp
,
92 const tunable_num_t
*maxp
)
94 tunable_num_t val
, min
, max
;
96 if (cur
->type
.type_code
== TUNABLE_TYPE_STRING
)
98 cur
->val
.strval
= valp
->strval
;
99 cur
->initialized
= true;
103 bool unsigned_cmp
= unsigned_tunable_type (cur
->type
.type_code
);
106 min
= minp
!= NULL
? *minp
: cur
->type
.min
;
107 max
= maxp
!= NULL
? *maxp
: cur
->type
.max
;
109 /* We allow only increasingly restrictive bounds. */
110 if (tunable_val_lt (min
, cur
->type
.min
, unsigned_cmp
))
113 if (tunable_val_gt (max
, cur
->type
.max
, unsigned_cmp
))
116 /* Skip both bounds if they're inconsistent. */
117 if (tunable_val_gt (min
, max
, unsigned_cmp
))
123 /* Bail out if the bounds are not valid. */
124 if (tunable_val_lt (val
, min
, unsigned_cmp
)
125 || tunable_val_lt (max
, val
, unsigned_cmp
))
128 cur
->val
.numval
= val
;
131 cur
->initialized
= true;
134 /* Validate range of the input value and initialize the tunable CUR if it looks
137 tunable_initialize (tunable_t
*cur
, const char *strval
)
141 if (cur
->type
.type_code
!= TUNABLE_TYPE_STRING
)
142 val
.numval
= (tunable_num_t
) _dl_strtoul (strval
, NULL
);
145 do_tunable_update_val (cur
, &val
, NULL
, NULL
);
149 __tunable_set_val (tunable_id_t id
, tunable_val_t
*valp
, tunable_num_t
*minp
,
152 tunable_t
*cur
= &tunable_list
[id
];
154 do_tunable_update_val (cur
, valp
, minp
, maxp
);
157 /* Parse the tunable string VALSTRING. VALSTRING is a duplicated value,
158 where delimiters ':' are replaced with '\0', so string tunables are null
161 parse_tunables (char *valstring
)
163 if (valstring
== NULL
|| *valstring
== '\0')
173 /* First, find where the name ends. */
174 while (*p
!= '=' && *p
!= ':' && *p
!= '\0')
177 /* If we reach the end of the string before getting a valid name-value
182 /* We did not find a valid name-value pair before encountering the
193 const char *value
= p
;
195 while (*p
!= ':' && *p
!= '\0')
203 /* Add the tunable if it exists. */
204 for (size_t i
= 0; i
< sizeof (tunable_list
) / sizeof (tunable_t
); i
++)
206 tunable_t
*cur
= &tunable_list
[i
];
208 if (tunable_is_name (cur
->name
, name
))
210 tunable_initialize (cur
, value
);
217 /* Initialize the tunables list from the environment. For now we only use the
218 ENV_ALIAS to find values. Later we will also use the tunable names to find
221 __tunables_init (char **envp
)
223 char *envname
= NULL
;
226 char **prev_envp
= envp
;
228 /* Ignore tunables for AT_SECURE programs. */
229 if (__libc_enable_secure
)
232 while ((envp
= get_next_env (envp
, &envname
, &len
, &envval
,
233 &prev_envp
)) != NULL
)
235 if (tunable_is_name ("GLIBC_TUNABLES", envname
))
237 parse_tunables (tunables_strdup (envval
));
241 for (int i
= 0; i
< sizeof (tunable_list
) / sizeof (tunable_t
); i
++)
243 tunable_t
*cur
= &tunable_list
[i
];
245 /* Skip over tunables that have either been set already or should be
247 if (cur
->initialized
|| cur
->env_alias
[0] == '\0')
250 const char *name
= cur
->env_alias
;
252 /* We have a match. Initialize and move on to the next line. */
253 if (tunable_is_name (name
, envname
))
255 tunable_initialize (cur
, envval
);
263 __tunables_print (void)
265 for (int i
= 0; i
< array_length (tunable_list
); i
++)
267 const tunable_t
*cur
= &tunable_list
[i
];
268 if (cur
->type
.type_code
== TUNABLE_TYPE_STRING
269 && cur
->val
.strval
== NULL
)
270 _dl_printf ("%s:\n", cur
->name
);
273 _dl_printf ("%s: ", cur
->name
);
274 switch (cur
->type
.type_code
)
276 case TUNABLE_TYPE_INT_32
:
277 _dl_printf ("%d (min: %d, max: %d)\n",
278 (int) cur
->val
.numval
,
280 (int) cur
->type
.max
);
282 case TUNABLE_TYPE_UINT_64
:
283 _dl_printf ("0x%lx (min: 0x%lx, max: 0x%lx)\n",
284 (long int) cur
->val
.numval
,
285 (long int) cur
->type
.min
,
286 (long int) cur
->type
.max
);
288 case TUNABLE_TYPE_SIZE_T
:
289 _dl_printf ("0x%zx (min: 0x%zx, max: 0x%zx)\n",
290 (size_t) cur
->val
.numval
,
291 (size_t) cur
->type
.min
,
292 (size_t) cur
->type
.max
);
294 case TUNABLE_TYPE_STRING
:
295 _dl_printf ("%s\n", cur
->val
.strval
);
298 __builtin_unreachable ();
304 /* Set the tunable value. This is called by the module that the tunable exists
307 __tunable_get_val (tunable_id_t id
, void *valp
, tunable_callback_t callback
)
309 tunable_t
*cur
= &tunable_list
[id
];
311 switch (cur
->type
.type_code
)
313 case TUNABLE_TYPE_UINT_64
:
315 *((uint64_t *) valp
) = (uint64_t) cur
->val
.numval
;
318 case TUNABLE_TYPE_INT_32
:
320 *((int32_t *) valp
) = (int32_t) cur
->val
.numval
;
323 case TUNABLE_TYPE_SIZE_T
:
325 *((size_t *) valp
) = (size_t) cur
->val
.numval
;
328 case TUNABLE_TYPE_STRING
:
330 *((const char **)valp
) = cur
->val
.strval
;
334 __builtin_unreachable ();
337 if (cur
->initialized
&& callback
!= NULL
)
338 callback (&cur
->val
);
341 rtld_hidden_def (__tunable_get_val
)