Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 04 Jan 2008 08:04:59 -0800
From:      Julian Elischer <julian@elischer.org>
To:        John Baldwin <jhb@freebsd.org>
Cc:        freebsd-arch@freebsd.org
Subject:   Re: RFC: sysctl additional functions/macros
Message-ID:  <477E592B.9040106@elischer.org>
In-Reply-To: <200801041042.09573.jhb@freebsd.org>
References:  <477D931D.4000303@elischer.org> <200801041042.09573.jhb@freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help
John Baldwin wrote:
> On Thursday 03 January 2008 08:59:57 pm Julian Elischer wrote:
>> I would like to extend the current SYSCTL_INT() with 
>> SYSCTL_INT_CLAMPED() or similar, where you also supply a
>> maximum acceptable value. (and maybe a clue as to what to say if it is 
>> a bad value).
>>
>> so many users of SYSCTL_INT don't check for bad values because it's so
>> much harder (you need to supply your own handler), and so many
>> simple handlers exist fo rthe people that DO check that it seems to
>> me that we should provide a pre-canned way to do this....
>>
>> we are limited to using the existing structure,
>> but as we have no existing callers we can redefine
>> one element....
> 
> In HEAD you can change the ABI of struct sysctl_oid.  Or even better, you
> could do something like this:
> 
> <sys/sysctl.h>:
> 
> struct sysctl_int_validator {
> 	int (*siv_validator)(void *arg, int newvalue);
> 	void *siv_arg;
> 	int *siv_data;
> }
> 
> #define	SYSCTL_INT_VALIDATED(parent, nbr, name, access, ptr, validator, arg, descr) \
> 	struct sysctl_int_validator siv__##parent##_##name = {		\
> 		(validator), (arg), (ptr) };				\
> 	SYSCTL_OID(parent, nbr, name, CTLTYPE_INT|(access),		\
> 	    &siv__##parent##_##name, 0, sysctl_handle_validated_int,	\
> 	    "I", descr)
> 
> int	sysctl_handle_validated_int(SYSCTL_HANDLER_ARGS);
> 
> kern/kern_sysctl.c:
> 
> int
> sysctl_handle_validated_int(SYSCTL_HANDLER_ARGS)
> {
> 	struct sysctl_int_validator *siv;
> 	int error, tmp;
> 
> 	siv = arg1;
> 	if (!siv)
> 		return (EINVAL);
> 	tmp = *siv->siv_data;
> 	error = sysctl_handle_int(oidp, &tmp, 0, req);
> 	if (error || !req->newptr)
> 		return (error);
> 	error = siv->siv_validator(siv->siv_arg, tmp);
> 	if (error == 0)
> 		*siv->siv_data = tmp;
> 	return (error);
> }
> 
> You can repeat this for the various sysctl types adding a validator handler
> for each type.  This gives you a framework to add simple validation.  You
> could then add wrappers to that for specific cases if they are common.  For
> example, you could implement the _CLAMPED variant like so:
> 
> <sys/sysctl.h>:
> 
> SYSCTL_INT_CLAMPED(parent, nbr, name, access, ptr, max, descr)		\
> 	SYSCTL_INT_VALIDATED(parent, nbr, name, access, ptr,		\
> 	    sysctl_validate_clamped_int, (void *)max, descr)
> 
> int	sysctl_validate_clamped_int(void *arg, int newvalue);
> 
> kern/kern_sysctl.c:
> 
> int
> sysctl_validate_clamped_int(void *arg, int newvalue)
> {
> 	int max = (intptr_t)arg;
> 
> 	if (newvalue > max)
> 		return (ERANGE);
> 	return (0);
> }
> 
> 
> You could even add min/max boundaries if desired:
> 
> <sys/sysctl.h>:
> 
> struct sysctl_int_bounds = {
> 	int	sib_min;
> 	int	sib_max;
> };
> 
> SYSCTL_INT_BOUNDED(parent, nbr, name, access, ptr, min, max, descr)	\
> 	struct sysctl_int_bounds sib__##parent##_##name = {		\
> 	    (min), (max) };						\
> 	SYSCTL_INT_VALIDATED(parent, nbr, name, access, ptr,		\
> 	    sysctl_validate_bounded_int, &sib__##parent##_##name,	\
> 	    descr)
> 
> int	sysctl_validate_bounded_int(void *arg, int newvalue);
> 
> kern/kern_sysctl.c:
> 
> int
> sysctl_validate_bounded_int(void *arg, int newwvalue)
> {
> 	struct sysctl_bounded_int *sib;
> 
> 	sib = arg;
> 	if (newvalue < sib->sib_min || newvalue > sib->sib_max)
> 		return (ERANGE);
> 	return (0);
> }
> 
> It would be nice to allow the validator function to be an anonymous routine
> like phk suggests.  Perhaps something like:
> 
> #define	SYSCTL_INT_VALIDATOR(parent, nbr, name, access, ptr, descr, validator) \
> 	int								\
> 	validate__##parent##_##name(int newvalue)			\
> 	validator							\
> 	SYSCTL_INT_VALIDATED(parent, nbr, name, access, ptr,		\
> 	    &validate__##parent##_##name, 0, descr)
> 
> would work, though I'm not sure how cpp(1) would really handle that.
> 
> You could also inline sysctl_handle_int() into sysctl_handle_validated_int()
> if you wanted.
> 


right, so you've solved that one..  now for global warming..

You might as well go ahead and commit it I think..  :-)



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?477E592B.9040106>