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