-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;
- }
-
- // sysctl(3) doesn't behave anything like its documentation leads you to
- // believe. If the given buffer is too small to hold the requested data,
- // what's supposed to happen is:
- //
- // - as much data as possible is copied into the buffer
- // - the number of bytes copied is written to the len parameter
- // - errno is set to ENOMEM
- // - -1 is returned (to indicate that you should check errno)
- //
- // What actually happens:
- //
- // - no data is copied
- // - len is set to zero
- // - errno is undefined
- // - zero is returned
- //
- // So... swing and a miss.
- //
- // Since it returns success in this case our only indication that something
- // went wrong is if mylen is set to zero.
- //
- // So we do our best to sniff out the misbehavior and emulate sysctl(3)'s
- // API contract until it's fixed.
- //
- // <rdar://problem/12809455>
-#if RDAR_12809455
- if (old_len && *old_len > 0) {
- // We can only work around the bug if the passed-in length was non-zero.
- 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;
-}