Re: *oldlenp comes back with wrong value in helper sysctl_createv() function

2024-01-20 Thread Emile 'iMil' Heitor





 case CTLTYPE_STRING: {
 unsigned char buf[1024], *tbuf;
 tbuf = buf;
 sz = sizeof(buf);
 rc = prog_sysctl([0], namelen, tbuf, , NULL, 0);

The sysctl command first tries with a buffer of 1024 bytes
and retries with the right size when that was too small.


Got it, makes sense. Thanks for the reply!

--

Emile `iMil' Heitor  | https://imil.net


Re: *oldlenp comes back with wrong value in helper sysctl_createv() function

2024-01-20 Thread Michael van Elst
On Sat, Jan 20, 2024 at 10:48:12AM +0100, Emile 'iMil' Heitor wrote:


Hi,

that's from sysctl.c:

case CTLTYPE_STRING: {
unsigned char buf[1024], *tbuf;
tbuf = buf;
sz = sizeof(buf); 
rc = prog_sysctl([0], namelen, tbuf, , NULL, 0);

The sysctl command first tries with a buffer of 1024 bytes
and retries with the right size when that was too small.

Compared to "probing" with a NULL buffer this saves a round trip
to the kernel for most sysctls.

A simple helper function would always return the needed size and only
copy out when oldp was set. sysctl will check the returned *oldlenp 
against the value passed by the caller and return ENOMEM as appropriate.


Greetings,
-- 
Michael van Elst
Internet: mlel...@serpens.de
"A potential Snark may lurk in every tree."


Re: *oldlenp comes back with wrong value in helper sysctl_createv() function

2024-01-20 Thread Emile 'iMil' Heitor

The helper function produces the value that is returned in *oldlenp.

If you happen to use CTL_DESCRIBE (e.g. running sysctl -d), it's
not your helper function being called but the sysctl_describe helper
that returns a value of 1024.

Maybe you can show your helper routine and how you call sysctl ?


sure, I call sysctl this way: sysctl debug.tslog

here's the helper function code:

static int
sysctl_debug_tslog(SYSCTLFN_ARGS)
{
char buf[LINE_MAX] = "";
char *where = oldp;
size_t slen, i, limit;
int error = 0;
static size_t needed = 0;

/* Come back with the right size */
/* here at second call, *oldlenp == 1024 */
if (*oldlenp < needed) {
*oldlenp = needed;
return 0; /* will be back with correct size */
}
/* Add data logged within the kernel. */
limit = MIN(nrecs, nitems(timestamps));
for (i = 0; i < limit; i++) {
snprintf(buf, LINE_MAX, "0x%x %llu",
timestamps[i].lid,
(unsigned long long)timestamps[i].tsc);
switch (timestamps[i].type) {
case TS_ENTER:
strcat(buf, " ENTER");
break;
case TS_EXIT:
strcat(buf, " EXIT");
break;
case TS_THREAD:
strcat(buf, " THREAD");
break;
case TS_EVENT:
strcat(buf, " EVENT");
break;
}
snprintf(buf, LINE_MAX, "%s %s", buf,
timestamps[i].f ? timestamps[i].f : "(null)");
if (timestamps[i].s)
snprintf(buf, LINE_MAX, "%s %s\n", buf,
timestamps[i].s);
else
strcat(buf, "\n");

slen = strlen(buf) + 1;

if (where == NULL) /* 1st pass, calculate needed */
needed += slen;
else {
if (i > 0)
where--; /* overwrite last \0 */
if ((error = copyout(buf, where, slen)))
break;
where += slen;
}
}
/* Come back with an address */
if (oldp == NULL)
*oldlenp = needed;

return error;
}

Here's the setup:

SYSCTL_SETUP(sysctl_tslog_setup, "tslog sysctl")
{
sysctl_createv(NULL, 0, NULL, NULL,
CTLFLAG_PERMANENT|CTLFLAG_READONLY,
CTLTYPE_STRING, "tslog",
SYSCTL_DESCR("Dump recorded event timestamps"),
sysctl_debug_tslog, 0, NULL, 0,
CTL_DEBUG, CTL_CREATE, CTL_EOL);
}

--

Emile `iMil' Heitor  | https://imil.net


Re: *oldlenp comes back with wrong value in helper sysctl_createv() function

2024-01-20 Thread Michael van Elst
i...@home.imil.net (Emile 'iMil' Heitor) writes:

>Except it does not, the first time it calls back the helper function,
>*oldlenp value is 1024 no matter what I set it to before.
>But if I return once again (either with ENOMEM or 0, doesn't matter),
>the helper function will now be called with the right *oldlenp value.

The helper function produces the value that is returned in *oldlenp.

If you happen to use CTL_DESCRIBE (e.g. running sysctl -d), it's
not your helper function being called but the sysctl_describe helper
that returns a value of 1024.

Maybe you can show your helper routine and how you call sysctl ?





*oldlenp comes back with wrong value in helper sysctl_createv() function

2024-01-19 Thread Emile 'iMil' Heitor



I am creating a sysctl entry for TSLOG 
https://man.freebsd.org/cgi/man.cgi?query=tslog=4=freebsd-release


In every example I see in our source tree, I read that when oldp is
NULL, *oldlenp should be set to desired size, return 0, and the
sysctl_createv() helper function will be again called with the right
*oldlenp value.
Except it does not, the first time it calls back the helper function,
*oldlenp value is 1024 no matter what I set it to before.
But if I return once again (either with ENOMEM or 0, doesn't matter),
the helper function will now be called with the right *oldlenp value.

I fail to see where this behavior comes from and I'd like to
understand the logic behind it.

--

Emile `iMil' Heitor  | https://imil.net