Index: lib/libc/gen/sysctl.3 =================================================================== --- lib/libc/gen/sysctl.3 +++ lib/libc/gen/sysctl.3 @@ -865,6 +865,9 @@ The .Fa name array specifies a value that is unknown. +.It Bq Er ENXIO +The associated kernel variable has gotten a bad value and +no sensible result is available. .It Bq Er EPERM An attempt is made to set a read-only value. .It Bq Er EPERM Index: sys/kern/subr_param.c =================================================================== --- sys/kern/subr_param.c +++ sys/kern/subr_param.c @@ -80,7 +80,15 @@ #define MAXFILES (40 + 32 * maxusers) #endif -static int sysctl_kern_vm_guest(SYSCTL_HANDLER_ARGS); +struct sysctl_enum_params { + int *const value; + int first; + u_int count; + char *const names[]; +}; + +static int sysctl_enum_proc(struct sysctl_oid *oidp, void *const _params, + intmax_t arg2, struct sysctl_req *req); int hz; /* system clock's frequency */ int tick; /* usec per tick (1000000 / hz) */ @@ -136,28 +144,32 @@ "Maximum stack size"); SYSCTL_ULONG(_kern, OID_AUTO, sgrowsiz, CTLFLAG_RWTUN | CTLFLAG_NOFETCH, &sgrowsiz, 0, "Amount to grow stack on a stack fault"); -SYSCTL_PROC(_kern, OID_AUTO, vm_guest, - CTLFLAG_RD | CTLTYPE_STRING | CTLFLAG_MPSAFE, NULL, 0, - sysctl_kern_vm_guest, "A", - "Virtual machine guest detected?"); /* - * The elements of this array are ordered based upon the values of the - * corresponding enum VM_GUEST members. + * Parameters for the vm_guest enum */ -static const char *const vm_guest_sysctl_names[] = { - [VM_GUEST_NO] = "none", - [VM_GUEST_VM] = "generic", - [VM_GUEST_XEN] = "xen", - [VM_GUEST_HV] = "hv", - [VM_GUEST_VMWARE] = "vmware", - [VM_GUEST_KVM] = "kvm", - [VM_GUEST_BHYVE] = "bhyve", - [VM_GUEST_VBOX] = "vbox", - [VM_GUEST_PARALLELS] = "parallels", - [VM_LAST] = NULL +static const struct sysctl_enum_params vm_guest_sysctl_params = { + &vm_guest, + VM_GUEST_NO, + VM_LAST - VM_GUEST_NO, /* VM_LAST is an invalid value */ + { + [VM_GUEST_BHYVE - VM_GUEST_NO] = "bhyve", + [VM_GUEST_HV - VM_GUEST_NO] = "hv", + [VM_GUEST_KVM - VM_GUEST_NO] = "kvm", + [VM_GUEST_NO - VM_GUEST_NO] = "none", + [VM_GUEST_PARALLELS - VM_GUEST_NO] = "parallels", + [VM_GUEST_VBOX - VM_GUEST_NO] = "vbox", + [VM_GUEST_VM - VM_GUEST_NO] = "generic", + [VM_GUEST_VMWARE - VM_GUEST_NO] = "vmware", + [VM_GUEST_XEN - VM_GUEST_NO] = "xen", + [VM_LAST - VM_GUEST_NO] = NULL + } }; -CTASSERT(nitems(vm_guest_sysctl_names) - 1 == VM_LAST); + +SYSCTL_PROC(_kern, OID_AUTO, vm_guest, + CTLFLAG_RD | CTLTYPE_STRING | CTLFLAG_MPSAFE, + __DECONST(void *, &vm_guest_sysctl_params), 0, sysctl_enum_proc, "A", + "Virtual machine guest detected?"); /* * Boot time overrides that are not scaled against main memory @@ -325,10 +337,18 @@ } /* - * Sysctl stringifying handler for kern.vm_guest. + * Generalized sysctl stringifying handler for enums */ static int -sysctl_kern_vm_guest(SYSCTL_HANDLER_ARGS) +sysctl_enum_proc(struct sysctl_oid *oidp, void *const _params, + intmax_t arg2, struct sysctl_req *req) { - return (SYSCTL_OUT_STR(req, vm_guest_sysctl_names[vm_guest])); + const struct sysctl_enum_params *const params = _params; + u_int index = *params->value - params->first; + + if (index >= params->count) + return (ENXIO); + if (params->names[index] == NULL) + return (0); + return (SYSCTL_OUT_STR(req, params->names[index])); }