16059Samurai/* $NetBSD: sysctl.c,v 1.38 2021/03/30 15:31:51 rillig Exp $ */ 26059Samurai 36059Samurai/*- 46059Samurai * Copyright (c) 1993 56059Samurai * The Regents of the University of California. All rights reserved. 66059Samurai * 76059Samurai * Redistribution and use in source and binary forms, with or without 86059Samurai * modification, are permitted provided that the following conditions 96059Samurai * are met: 106059Samurai * 1. Redistributions of source code must retain the above copyright 116059Samurai * notice, this list of conditions and the following disclaimer. 126059Samurai * 2. Redistributions in binary form must reproduce the above copyright 136059Samurai * notice, this list of conditions and the following disclaimer in the 146059Samurai * documentation and/or other materials provided with the distribution. 156059Samurai * 3. Neither the name of the University nor the names of its contributors 166059Samurai * may be used to endorse or promote products derived from this software 176059Samurai * without specific prior written permission. 186059Samurai * 196059Samurai * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2026901Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 218857Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 226059Samurai * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 236059Samurai * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 246059Samurai * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 256059Samurai * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 266059Samurai * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 276059Samurai * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2811336Samurai * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 296059Samurai * SUCH DAMAGE. 306059Samurai */ 3123114Sbrian 326059Samurai#include <sys/cdefs.h> 336059Samurai#if defined(LIBC_SCCS) && !defined(lint) 346059Samurai#if 0 3518786Sjkhstatic char sccsid[] = "@(#)sysctl.c 8.2 (Berkeley) 1/4/94"; 366059Samurai#else 376059Samurai__RCSID("$NetBSD: sysctl.c,v 1.38 2021/03/30 15:31:51 rillig Exp $"); 3820365Sjkh#endif 3920365Sjkh#endif /* LIBC_SCCS and not lint */ 406059Samurai 416059Samurai#include "namespace.h" 426059Samurai#include <sys/param.h> 4313389Sphk#define __COMPAT_SYSCTL 446059Samurai#include <sys/sysctl.h> 456059Samurai 4626142Sbrian#include <assert.h> 476059Samurai#include <errno.h> 486735Samurai#include <paths.h> 497001Samurai#include <stdio.h> 5013389Sphk#include <string.h> 5113389Sphk#include <unistd.h> 5223840Sbrian#include "extern.h" 536059Samurai 546764Samurai#ifdef __weak_alias 5526516Sbrian__weak_alias(sysctl,_sysctl) 566764Samurai#endif 576735Samurai 586735Samurai/* 596735Samurai * handles requests off the user subtree 606735Samurai */ 616735Samuraistatic int user_sysctl(const int *, u_int, void *, size_t *, 626735Samurai const void *, size_t); 636059Samurai 6425630Sbrian/* 656059Samurai * copies out individual nodes taking target version into account 666059Samurai */ 676059Samuraistatic size_t __cvt_node_out(uint, const struct sysctlnode *, void **, 6818885Sjkh size_t *); 696059Samurai 706059Samurai#include <stdlib.h> 7110528Samurai 7225908Sbrianint 736059Samuraisysctl(const int *name, unsigned int namelen, 746059Samurai void *oldp, size_t *oldlenp, 756059Samurai const void *newp, size_t newlen) 7614418Sache{ 7713379Sphk size_t oldlen, savelen; 7820813Sjkh int error; 796059Samurai 8025634Sbrian if (name[0] != CTL_USER) 8125634Sbrian return (__sysctl(name, namelen, oldp, oldlenp, 8225445Sache newp, newlen)); 836059Samurai 846059Samurai oldlen = (oldlenp == NULL) ? 0 : *oldlenp; 8526858Sbrian savelen = oldlen; 866059Samurai error = user_sysctl(name + 1, namelen - 1, oldp, &oldlen, newp, newlen); 876059Samurai 886059Samurai if (error != 0) { 896059Samurai errno = error; 906059Samurai return (-1); 9125630Sbrian } 9225630Sbrian 9325630Sbrian if (oldlenp != NULL) { 9425630Sbrian *oldlenp = oldlen; 956059Samurai if (oldp != NULL && oldlen > savelen) { 966059Samurai errno = ENOMEM; 976059Samurai return (-1); 986059Samurai } 996059Samurai } 10026858Sbrian 10126858Sbrian return (0); 1026059Samurai} 1036059Samurai 1046059Samuraistatic int 1056735Samuraiuser_sysctl(const int *name, unsigned int namelen, 1066059Samurai void *oldp, size_t *oldlenp, 1076059Samurai const void *newp, size_t newlen) 1086059Samurai{ 1096059Samurai#define _INT(s, n, v, d) { \ 1106059Samurai .sysctl_flags = CTLFLAG_IMMEDIATE|CTLFLAG_PERMANENT| \ 1116059Samurai CTLTYPE_INT|SYSCTL_VERSION, \ 11210528Samurai .sysctl_size = sizeof(int), \ 11310528Samurai .sysctl_name = (s), \ 11410528Samurai .sysctl_num = (n), \ 1156059Samurai .sysctl_un.scu_idata = (v), \ 1166059Samurai .sysctl_desc = (d), \ 1176059Samurai } 1186059Samurai 1196059Samurai /* 1206059Samurai * the nodes under the "user" node 1216735Samurai */ 12210528Samurai static const struct sysctlnode sysctl_usermib[] = { 1236059Samurai { 1246059Samurai .sysctl_flags = SYSCTL_VERSION|CTLFLAG_PERMANENT| 1256735Samurai CTLTYPE_STRING, 1266059Samurai .sysctl_size = sizeof(_PATH_STDPATH), 12725630Sbrian .sysctl_name = "cs_path", 12825630Sbrian .sysctl_num = USER_CS_PATH, 12925630Sbrian .sysctl_data = __UNCONST(_PATH_STDPATH), 13025630Sbrian .sysctl_desc = __UNCONST( 1316059Samurai "A value for the PATH environment variable " 13225630Sbrian "that finds all the standard utilities"), 1336059Samurai }, 1346059Samurai _INT("bc_base_max", USER_BC_BASE_MAX, BC_BASE_MAX, 1356059Samurai "The maximum ibase/obase values in the bc(1) utility"), 1366059Samurai _INT("bc_dim_max", USER_BC_DIM_MAX, BC_DIM_MAX, 1376059Samurai "The maximum array size in the bc(1) utility"), 1386059Samurai _INT("bc_scale_max", USER_BC_SCALE_MAX, BC_SCALE_MAX, 1396059Samurai "The maximum scale value in the bc(1) utility"), 1406059Samurai _INT("bc_string_max", USER_BC_STRING_MAX, BC_STRING_MAX, 1416059Samurai "The maximum string length in the bc(1) utility"), 1426059Samurai _INT("coll_weights_max", USER_COLL_WEIGHTS_MAX, 1436735Samurai COLL_WEIGHTS_MAX, "The maximum number of weights that can " 1446059Samurai "be assigned to any entry of the LC_COLLATE order keyword " 14525630Sbrian "in the locale definition file"), 14625630Sbrian _INT("expr_nest_max", USER_EXPR_NEST_MAX, EXPR_NEST_MAX, 14725630Sbrian "The maximum number of expressions that can be nested " 14825630Sbrian "within parenthesis by the expr(1) utility"), 1496059Samurai _INT("line_max", USER_LINE_MAX, LINE_MAX, "The maximum length " 1506059Samurai "in bytes of a text-processing utility's input line"), 1516059Samurai _INT("re_dup_max", USER_RE_DUP_MAX, RE_DUP_MAX, "The maximum " 1526059Samurai "number of repeated occurrences of a regular expression " 15310528Samurai "permitted when using interval notation"), 1546059Samurai _INT("posix2_version", USER_POSIX2_VERSION, _POSIX2_VERSION, 1556059Samurai "The version of POSIX 1003.2 with which the system " 1566059Samurai "attempts to comply"), 1576059Samurai#ifdef _POSIX2_C_BIND 15825630Sbrian _INT("posix2_c_bind", USER_POSIX2_C_BIND, 1, 15925630Sbrian "Whether the system's C-language development facilities " 16025630Sbrian "support the C-Language Bindings Option"), 16125630Sbrian#else 1626735Samurai _INT("posix2_c_bind", USER_POSIX2_C_BIND, 0, 16310528Samurai "Whether the system's C-language development facilities " 16410528Samurai "support the C-Language Bindings Option"), 16510528Samurai#endif 16610528Samurai#ifdef POSIX2_C_DEV 16710528Samurai _INT("posix2_c_dev", USER_POSIX2_C_DEV, 1, 16810528Samurai "Whether the system supports the C-Language Development " 16910528Samurai "Utilities Option"), 17010528Samurai#else 1716059Samurai _INT("posix2_c_dev", USER_POSIX2_C_DEV, 0, 1726059Samurai "Whether the system supports the C-Language Development " 17325908Sbrian "Utilities Option"), 1746059Samurai#endif 17525707Sbrian#ifdef POSIX2_CHAR_TERM 17625707Sbrian _INT("posix2_char_term", USER_POSIX2_CHAR_TERM, 1, 1776059Samurai "Whether the system supports at least one terminal type " 17823863Sbrian "capable of all operations described in POSIX 1003.2"), 17923863Sbrian#else 18023863Sbrian _INT("posix2_char_term", USER_POSIX2_CHAR_TERM, 0, 18126516Sbrian "Whether the system supports at least one terminal type " 18223863Sbrian "capable of all operations described in POSIX 1003.2"), 18326516Sbrian#endif 18423863Sbrian#ifdef POSIX2_FORT_DEV 18523863Sbrian _INT("posix2_fort_dev", USER_POSIX2_FORT_DEV, 1, 18626516Sbrian "Whether the system supports the FORTRAN Development " 1876059Samurai "Utilities Option"), 18823598Sache#else 1896059Samurai _INT("posix2_fort_dev", USER_POSIX2_FORT_DEV, 0, 19023598Sache "Whether the system supports the FORTRAN Development " 19123598Sache "Utilities Option"), 19225707Sbrian#endif 19310528Samurai#ifdef POSIX2_FORT_RUN 1946059Samurai _INT("posix2_fort_run", USER_POSIX2_FORT_RUN, 1, 1956059Samurai "Whether the system supports the FORTRAN Runtime " 1966059Samurai "Utilities Option"), 1976059Samurai#else 1986059Samurai _INT("posix2_fort_run", USER_POSIX2_FORT_RUN, 0, 19914930Sache "Whether the system supports the FORTRAN Runtime " 20014930Sache "Utilities Option"), 2016059Samurai#endif 20226858Sbrian#ifdef POSIX2_LOCALEDEF 20326858Sbrian _INT("posix2_localedef", USER_POSIX2_LOCALEDEF, 1, 20426858Sbrian "Whether the system supports the creation of locales"), 2056059Samurai#else 2066059Samurai _INT("posix2_localedef", USER_POSIX2_LOCALEDEF, 0, 2076059Samurai "Whether the system supports the creation of locales"), 20814930Sache#endif 20914930Sache#ifdef POSIX2_SW_DEV 2106059Samurai _INT("posix2_sw_dev", USER_POSIX2_SW_DEV, 1, 21120813Sjkh "Whether the system supports the Software Development " 21220813Sjkh "Utilities Option"), 21320813Sjkh#else 21420813Sjkh _INT("posix2_sw_dev", USER_POSIX2_SW_DEV, 0, 21526516Sbrian "Whether the system supports the Software Development " 21626516Sbrian "Utilities Option"), 21726516Sbrian#endif 21826516Sbrian#ifdef POSIX2_UPE 2196059Samurai _INT("posix2_upe", USER_POSIX2_UPE, 1, 2206059Samurai "Whether the system supports the User Portability " 22110528Samurai "Utilities Option"), 22210528Samurai#else 22310528Samurai _INT("posix2_upe", USER_POSIX2_UPE, 0, 22423840Sbrian "Whether the system supports the User Portability " 22523840Sbrian "Utilities Option"), 22610528Samurai#endif 22710528Samurai _INT("stream_max", USER_STREAM_MAX, FOPEN_MAX, 22810528Samurai "The minimum maximum number of streams that a process " 22910528Samurai "may have open at any one time"), 23010528Samurai _INT("tzname_max", USER_TZNAME_MAX, NAME_MAX, 23110528Samurai "The minimum maximum number of types supported for the " 23210528Samurai "name of a timezone"), 23323840Sbrian _INT("atexit_max", USER_ATEXIT_MAX, -1, 23410528Samurai "The maximum number of functions that may be registered " 23523840Sbrian "with atexit(3)"), 23610528Samurai }; 23710528Samurai#undef _INT 23810528Samurai 23925908Sbrian static const int clen = sizeof(sysctl_usermib) / 24025908Sbrian sizeof(sysctl_usermib[0]); 24125908Sbrian 24225908Sbrian const struct sysctlnode *node; 24325908Sbrian int ni; 24425908Sbrian size_t l, sz; 24525908Sbrian 24610528Samurai /* 24725908Sbrian * none of these nodes are writable and they're all terminal (for now) 24825908Sbrian */ 24925908Sbrian if (namelen != 1) 25025908Sbrian return (EINVAL); 25125908Sbrian 25225908Sbrian l = *oldlenp; 2536059Samurai if (name[0] == CTL_QUERY) { 2546059Samurai uint v; 2556059Samurai node = newp; 25620120Snate if (node == NULL) 25720813Sjkh return (EINVAL); 2586059Samurai else if (SYSCTL_VERS(node->sysctl_flags) == SYSCTL_VERS_1 && 2596059Samurai newlen == sizeof(struct sysctlnode)) 2606059Samurai v = SYSCTL_VERS_1; 2616059Samurai else 2626059Samurai return (EINVAL); 2636059Samurai 2646059Samurai sz = 0; 2656059Samurai for (ni = 0; ni < clen; ni++) 2666059Samurai sz += __cvt_node_out(v, &sysctl_usermib[ni], &oldp, &l); 2676059Samurai *oldlenp = sz; 2686059Samurai return (0); 2696059Samurai } 2706059Samurai 2716059Samurai if (name[0] == CTL_DESCRIBE) { 27220813Sjkh /* 27325908Sbrian * XXX make sure this is larger than the largest 2746059Samurai * "user" description 2756059Samurai */ 2766059Samurai char buf[192]; 2776059Samurai struct sysctldesc *d1 = (void *)&buf[0], *d2 = oldp; 27820120Snate size_t d; 27920120Snate 28020365Sjkh node = newp; 28126142Sbrian if (node != NULL && 28226142Sbrian (SYSCTL_VERS(node->sysctl_flags) < SYSCTL_VERS_1 || 28326142Sbrian newlen != sizeof(struct sysctlnode))) 28426516Sbrian return (EINVAL); 28520365Sjkh 28620365Sjkh sz = 0; 2876059Samurai for (ni = 0; ni < clen; ni++) { 2886059Samurai memset(&buf[0], 0, sizeof(buf)); 2896059Samurai if (node != NULL && 2906059Samurai node->sysctl_num != sysctl_usermib[ni].sysctl_num) 2916059Samurai continue; 2926059Samurai d1->descr_num = sysctl_usermib[ni].sysctl_num; 2936059Samurai d1->descr_ver = sysctl_usermib[ni].sysctl_ver; 2946059Samurai if (sysctl_usermib[ni].sysctl_desc == NULL) 2956059Samurai d1->descr_len = 1; 2966059Samurai else { 2976059Samurai size_t dlen; 2986059Samurai (void)strlcpy(d1->descr_str, 2996059Samurai sysctl_usermib[ni].sysctl_desc, 3006059Samurai sizeof(buf) - sizeof(*d1)); 3016059Samurai dlen = strlen(d1->descr_str) + 1; 3026059Samurai _DIAGASSERT(__type_fit(uint32_t, dlen)); 3036059Samurai d1->descr_len = (uint32_t)dlen; 3046059Samurai } 3056059Samurai d = (size_t)__sysc_desc_len(d1->descr_len); 3066059Samurai if (d2 != NULL) 30726516Sbrian memcpy(d2, d1, d); 30826516Sbrian sz += d; 30926516Sbrian d2 = (void *)((char *)(void *)d2 + d); 31026516Sbrian if (node != NULL) 3116059Samurai break; 3126059Samurai } 3136059Samurai *oldlenp = sz; 3146059Samurai if (sz == 0 && node != NULL) 3156059Samurai return (ENOENT); 3166059Samurai return (0); 3176059Samurai 31825707Sbrian } 31926516Sbrian 32026516Sbrian /* 32126551Sbrian * none of these nodes are writable 32226516Sbrian */ 32326516Sbrian if (newp != NULL || newlen != 0) 32426516Sbrian return (EPERM); 3256059Samurai 3266059Samurai node = &sysctl_usermib[0]; 32723598Sache for (ni = 0; ni < clen; ni++) 3286059Samurai if (name[0] == node[ni].sysctl_num) 32926328Sbrian break; 33026551Sbrian if (ni == clen) 33126551Sbrian return (EOPNOTSUPP); 3326059Samurai 3336059Samurai node = &node[ni]; 3346059Samurai if (node->sysctl_flags & CTLFLAG_IMMEDIATE) { 33526516Sbrian switch (SYSCTL_TYPE(node->sysctl_flags)) { 33626516Sbrian case CTLTYPE_INT: 3376059Samurai newp = &node->sysctl_idata; 3386735Samurai break; 3396735Samurai case CTLTYPE_QUAD: 34026516Sbrian newp = &node->sysctl_qdata; 34126516Sbrian break; 34226516Sbrian default: 34326551Sbrian return (EINVAL); 34426328Sbrian } 3456764Samurai } 3466764Samurai else 3476735Samurai newp = node->sysctl_data; 3486735Samurai 3496735Samurai l = MIN(l, node->sysctl_size); 3506735Samurai if (oldp != NULL) 3516735Samurai memcpy(oldp, newp, l); 3526735Samurai *oldlenp = node->sysctl_size; 3536059Samurai 35426516Sbrian return (0); 3556059Samurai} 3566059Samurai 3576059Samuraistatic size_t 35825908Sbrian__cvt_node_out(uint v, const struct sysctlnode *n, void **o, size_t *l) 3596059Samurai{ 3606059Samurai const void *src = n; 36126516Sbrian size_t sz; 36226690Sbrian 3636059Samurai switch (v) { 36426516Sbrian#if (SYSCTL_VERSION != SYSCTL_VERS_1) 3656059Samurai#error __cvt_node_out: no support for SYSCTL_VERSION 36626516Sbrian#endif /* (SYSCTL_VERSION != SYSCTL_VERS_1) */ 36726516Sbrian 36825908Sbrian case SYSCTL_VERSION: 3696059Samurai sz = sizeof(struct sysctlnode); 3706059Samurai break; 3716059Samurai 3726059Samurai default: 3736735Samurai sz = 0; 3746059Samurai break; 37526516Sbrian } 37623840Sbrian 37723840Sbrian if (sz > 0 && *o != NULL && *l >= sz) { 37823840Sbrian memcpy(*o, src, sz); 3796735Samurai *o = sz + (caddr_t)*o; 38024753Sache *l -= sz; 3816735Samurai } 3826735Samurai 38323840Sbrian return(sz); 3846735Samurai} 38510528Samurai