Re: *oldlenp comes back with wrong value in helper sysctl_createv() function
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
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
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
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 ?