#include "internal.h"
#pragma mark Utilities
static int
_sysctl_12809455(int mib[4], size_t mib_cnt, void *old, size_t *old_len,
void *new, size_t new_len)
{
int error = -1;
int ret = -1;
size_t mylen = 0;
size_t *mylenp = NULL;
#if RDAR_12809455
bool workaround_12809455 = false;
#endif
if (old_len) {
mylen = *old_len;
mylenp = &mylen;
}
#if RDAR_12809455
if (old_len && *old_len > 0) {
workaround_12809455 = true;
}
#endif
ret = sysctl(mib, (u_int)mib_cnt, old, mylenp, new, new_len);
#if RDAR_12809455
if (workaround_12809455 && old && ret == 0 && mylen == 0) {
ret = -1;
errno = ENOMEM;
}
#endif // RDAR_12809455
if (ret == 0) {
error = 0;
} else {
error = errno;
}
if (old_len) {
*old_len = mylen;
}
return error;
}
static char *
_strblk(const char *str)
{
const char *cur = str;
while (*cur && !isblank(*cur)) {
cur++;
}
return (char *)cur;
}
static bool
_get_boot_arg_value(const char *which, char *where, size_t max)
{
bool found = false;
errno_t error = -1;
char *buff = NULL;
size_t buff_len = 0;
char *theone = NULL;
char *equals = NULL;
error = sysctlbyname_get_data_np("kern.bootargs", (void **)&buff,
&buff_len);
if (error) {
goto __out;
}
theone = strstr(buff, which);
if (!theone) {
goto __out;
}
found = true;
if (!where) {
goto __out;
}
equals = strchr(theone, '=');
if (!equals || isblank(equals[1])) {
strlcpy(where, "", max);
} else {
char *nextsep = NULL;
char nextsep_old = 0;
nextsep = _strblk(theone);
nextsep_old = *nextsep;
*nextsep = 0;
strlcpy(where, &equals[1], max);
*nextsep = nextsep_old;
}
__out:
free(buff);
return found;
}
#pragma mark API
errno_t
sysctl_get_data_np(int mib[4], size_t mib_cnt, void **buff, size_t *buff_len)
{
errno_t error = -1;
size_t needed = 0;
void *mybuff = NULL;
error = _sysctl_12809455(mib, mib_cnt, NULL, &needed, NULL, 0);
if (error) {
goto __out;
}
mybuff = malloc(needed);
if (!mybuff) {
error = errno;
goto __out;
}
error = _sysctl_12809455(mib, mib_cnt, mybuff, &needed, NULL, 0);
if (error) {
goto __out;
}
*buff = mybuff;
*buff_len = needed;
__out:
if (error) {
free(mybuff);
}
return error;
}
errno_t
sysctlbyname_get_data_np(const char *mibdesc, void **buff, size_t *buff_len)
{
int ret = -1;
int error = -1;
int mib[4];
size_t mib_cnt = countof(mib);
ret = sysctlnametomib(mibdesc, mib, &mib_cnt);
if (ret) {
error = errno;
goto __out;
}
error = sysctl_get_data_np(mib, mib_cnt, buff, buff_len);
__out:
return error;
}
bool
os_parse_boot_arg_int(const char *which, int64_t *where)
{
bool found = false;
char buff[24] = {0};
char *endptr = NULL;
int64_t val = 0;
found = _get_boot_arg_value(which, buff, sizeof(buff));
if (!found || !where) {
goto __out;
}
val = strtoll(buff, &endptr, 0);
if (*endptr == 0) {
*where = val;
} else {
found = false;
}
__out:
return found;
}
bool
os_parse_boot_arg_string(const char *which, char *where, size_t maxlen)
{
return _get_boot_arg_value(which, where, maxlen);
}