Glibc wrappers for (nearly all) Linux system calls
Glibc wrappers for (nearly all) Linux system calls
Posted Aug 21, 2015 8:36 UTC (Fri) by xnox (guest, #63320)Parent article: Glibc wrappers for (nearly all) Linux system calls
Posted Aug 21, 2015 19:47 UTC (Fri)
by wahern (subscriber, #37304)
[Link]
If everything is else is returned via reference, why -errno? In my code I also usually return errno directly, but without negating it. I return negative values for application-defined errors. All C- and POSIX-defined errno values must be positive, and no unix-like system uses the negative range for implementation-specific errno values; nor does Windows AFAIK. That way my libraries can pass-through system errors, and I don't have to define ad hoc types for error reporting (which sounds like good idea in principle until you have to glue together a dozen different libraries; even using enums causes headaches because of GCC and clang warnings).
Glibc wrappers for (nearly all) Linux system calls
I partition the negative range using a simple prefix system, which makes it easy to mix-and-match components. For example, from my DNS library,
#define DNS_EBASE -(('d' << 24) | ('n' << 16) | ('s' << 8) | 64) enum dns_errno { DNS_ENOBUFS = DNS_EBASE, DNS_EILLEGAL, DNS_EORDER, DNS_ESECTION, DNS_EUNKNOWN, DNS_EADDRESS, DNS_ENOQUERY, DNS_ENOANSWER, DNS_EFETCHED, DNS_ESERVICE, /* EAI_SERVICE */ DNS_ENONAME, /* EAI_NONAME */ DNS_EFAIL, /* EAI_FAIL */ DNS_ELAST, }; /* dns_errno */ /* for documentation only; will always be type int */ #define dns_error_t int ... dns_error_t dns_res_submit(struct dns_resolver *, const char *, enum dns_type, enum dns_class); struct dns_packet *dns_res_fetch(struct dns_resolver *, dns_error_t *);
Helpfully, strerror must always return a valid string for all integer values, even for unknown values.
The strerror function maps the number in errnum to a message string. Typically, the values for errnum come from errno, but strerror shall map any value of type int to a message.C11 (N1570) 7.24.6.2p2
So if an application-specific value accidentally leaks to a component that doesn't understand the protocol it's relatively benign. In fact, most strerror implementations will include the value in the message, so you'll actually get useful output if it gets passed to strerror. But usually each component will define it's own strerror interface that forwards to strerror or a sub-component's strerror.
It's the most useful and practical error reporting method I've found, at least for C code, and especially for C libraries. Of course, sometimes a routine is better defined (easier to use, more intuitive) by returning the error value through a reference, rather than as the return value. But that's just a variation on the theme. Unless you know you'll always operate in a closed software ecosystem, every other scheme is just chasing a dragon like other classic rookie mistakes: constantly writing configuration parsers, relying too heavily on malloc/free replacements, and reinventing logging instead of using stderr or perhaps syslog. Billions of man hours have been wasted down those rabbit holes.