Error reporting
***************

Many functions, especially those involving system calls, detect and report exceptional conditions, including error conditions and interruptions. Exception conditions must often be checked and handled, often by retrying, doing something else, or reporting the error to the user and exit.

Unless otherwise specified, exceptional conditions are reporting using the facilities described in this chapter.

Error checking
==============

Most functions return a sentinel value when an exceptional condition occurs, typically a negative value (actually -1), a constant such as EOF, or NULL. This return value only tells you that an exeception condition has occurred.

By including the header file <errno.h>, the modifiable lvalue errno is made available. ISO C specifies that errno is not necessarily a variable, but rather just an modifiable lvalue. In fact, must libc:s, including slibc defines it as a macro that calls a function and uses the unary *-operator on the return.

errno is often thought of as a variable declared as int errno, or volatile int errno. But the value is thread-local, and is thus more like _Thread_local volatile int errno. Because of this, the errno is defined as a macro that calls a function. Otherwise, it would not be implementable without ISO C11.

The value of errno is describes the error, if and only if the function returned a value indicating an error. Some, function can return the sentinel value both on success and error. Therefore, the value 0 on errno means that the function returned after successful completion rather than on failure. Exceptional conditions are describe by non-zero values listed in Error codes.

The state of errno is undefined unless otherwise specified after a succesful completion of a function call. This means that you, generally, cannot check whether an error has occurred by checking the value of errno rather than the return value.

Etymology for errno: (Err)or (number).

Error codes
===========

TODO: The list of error codes have not be added to slibc yet.

Error messages
==============

The C standard library provides a several mechanisms for reporting errors to the user, spread out over a few header files.

void perror(const char* prefix)
     The POSIX.1-2001 standard (_POSIX_C_SOURCE >= 200112L), the ISO C89 standard, and 4.3 BSD (_BSD_SOURCE) added this function to the header file <stdio.h>.

     This function prints an error message for the current value on errno, to stderr. If prefix is neither NULL or an empty string, prefix followed by a colon and a blank space, is prepended to the ouput. The function will also (always) add a line feed to the end of the message.

     This function does not detect or report errors. Thus, you should not use this function if you want to be able to tell whether the messages was actually printed. Of course, if it was not, your only option is to print it to another file descriptor which you normally do not want to do.

     This function is subject to race condition over stderr.

     Because successful function calls may change the value on errno, its value must be saved if there are function calls between the failure and the call to perror.

     It is customary to set prefix to a value equivalent to program_invocation_name, or alternatively program_invocation_short_name. Sometiems, the name of the called function is used, this is to simplify debugging. But the standard is that programs shall print there them when reporting an error so that the user knows that program failed.

     TODO: Not implemented.

char* strerror(int errnum)
     The POSIX.1-2001 standard (_POSIX_C_SOURCE >= 200112L) and ISO C89 standard, defines this function in the header file <string.h>.

     This function returns a description of the error code whose number is errnum. Description may or may not (it is in slibc) be localised using the LC_MESSAGES part of the current locale.

     The returned value must not be modified the the program, by it may be modified by subsequent calls to strerror-functions. If the error code is not recognised some implementations will return NULL, other implementations, such as slibc's, will return a message that states to number of the error code.

     According to POSIX, errno must not be modified if the call is successful. It may however set errno on failure. However, the slibc implementation cannot fail.

     slibc's implementation of this function is threadsafe, this is however not true for all implementions.

int strerror_r(int errnum, char* buffer, size_t size)
     The POSIX.1-2001 standard added this function to the header file <string.h>. It is a reenterant variant fo strerror. Instead of returning the error message, it saves it to buffer. The allocation size of buffer is pass to the function via the argument size. If it is too small, ERANGE is returned.

     The function returns a positive value, that is appropriate for errno, on error, rather than setting the value of errno. Upon successful completion, 0 is returned.

     This function is not available if _PORTABLE_SOURCE or _LIBRARY_HEADER is defined, because it is conflicting with the GNU-version. Without knowning which version that is used, it is impossible to check for errors.

     This function is also non-portable even if the GNU-version is not used, that is, if _GNU_SOURCE is not defined and (_POSIX_C_SOURCE >= 200112L) || (_XOPEN_SOURCE >= 600). Old versions of GNU C Library, returned -1 on failure and set errno, instead of returned a value for errno.

     Whilst strerror_r is not portable, the most portable use of strerror_r is

          int r;
          r = strerror_r(errnum, buffer, size);
          if (r > 0 ? (errno = r) : r)
            goto fail;

     Note that, unlike strerror, there is no restriction against strerror_r to set errno on success.

char* strerror_r(int errnum, char* buffer, size_t size)
     This is a GNU extension, defined in the header file <string.h> and is available, instead of the XSI-compliant version, if _GNU_SOURCE is defined or if (_POSIX_C_SOURCE < 200112L) && (_XOPEN_SOURCE < 600). It is identical to the XSI-compliant version, except, rather than returning an error code, it will set errno and return NULL on failure. On successful completion, buffer is returned.

     This function is not available if _PORTABLE_SOURCE or _LIBRARY_HEADER is defined, because it is conflicting with the XSI-compliant version. Without knowning which version that is used, it is impossible to check for errors.

char* strerror_l(int errnum, locale_t locale)
     The POSIX.1-2008 standard (_POSIX_C_SOURCE >= 200809L), defines this function in the header file <string.h>. It is identical to strerror_l with two exceptions: it is thread save, and it uses a specified locale.

     The behaviour of this function is undefined if locale is LC_GLOBAL_LOCALE.

const char* const sys_errlist[]
     This variable is defined in the header files <errno.h> (derived from BSD libc) and <stdio.h> (derived from GNU libc) if _BSD_SOURCE is defined.

     This is a list, index by error codes, of error messages.

     This list is deprecated, and all error codes may not have been added in all libc implementations.

     TODO: Not implemented.

int sys_nerr
     This variable is defined in the header files <errno.h> (derived from BSD libc) and <stdio.h> (derived from GNU libc) if _BSD_SOURCE is defined.

     This is the number of error codes that are defined, including 0 (successful completion.) That is, the value of the error code with highest value, plus 1.

     TODO: Not implemented.

char* program_invocation_name
     This variable is defined in the header file <errno.h>, if _GNU_SOURCE or _SLIBC_SOURCE is defined.

     This is the name that was used to invoke the program running in the current process. This is the value argv[0] from the main function (where argv is the second parameter.) If argc (the first parameter) is zero, this variable will have the value NULL. This is not necessarily a proper command name. For example, login shells are usually prefixes with a dash, for example -bash, despite that there is no such command. Often, but not always, this will not contain directory.

     It is recommended for portable programs to saved the value of argv[0] from main to a global variable (often named argv0) instead of using this variable.

char* program_invocation_short_name
     This variable is defined in the header file <errno.h>, if _GNU_SOURCE is defined. It is similar to program_invocation_name, but it only contains the basename, that is, the part after the last slash.

     If program_invocation_name is edited, program_invocation_short_name may be modified too. However, if error_print_progname from <error.h> is not NULL, it will be used to pritn the process name.

void warn(const char* format, ...)
     This function is a non-standard BSD extension, and requires that _BSD_SOURCE is defined. It is made available by including the header file <err.h>. It is similar to printf except it prints the message to stderr, and a description of the error specified by the current value on errno is also printed.

     It is specified that the last component of the process name shall be printed, however, the slibc's implementation will print the full process name, or more precisely, it prints program_invocation_name.

     Etymology: Print (warn)ing!

void vwarn(const char* format, va_list args)
     This function is a non-standard BSD extension, and requires that _BSD_SOURCE is defined. It is made available by including the header file <err.h>. It is identical to warn except it uses va_list instead of being a variadic function.

     Etymology: (V)ariadic version of (`warn`).

void warnx(const char* format, ...)
     This function is a non-standard BSD extension, and requires that _BSD_SOURCE is defined. It is made available by including the header file <err.h>. It is identical to warn except it does not print a description of the value of errno.

     Etymology: (`warn`), [x=](lesser variant).

void vwarnx(const char* format, va_list args)
     This function is a non-standard BSD extension, and requires that _BSD_SOURCE is defined. It is made available by including the header file <err.h>. It is identical to warnx except it uses va_list instead of being a variadic function.

     Etymology: (V)ariadic version of (`warnx`).

noreturn void err(int status, const char* format, ...)
     This function is a non-standard BSD extension, and requires that _BSD_SOURCE is defined. It is made available by including the header file <err.h>. It is identical to warn except will return with the exit value status & 255.

     Etymology: Report (err)or!

noreturn void verr(int status, const char* format, va_list args)
     This function is a non-standard BSD extension, and requires that _BSD_SOURCE is defined. It is made available by including the header file <err.h>. It is identical to err except it uses va_list instead of being a variadic function.

     Etymology: (V)ariadic version of (`err`).

noreturn void errx(int status, const char* format, ...)
     This function is a non-standard BSD extension, and requires that _BSD_SOURCE is defined. It is made available by including the header file <err.h>. It is identical to err except it does not print a description of the value of errno.

     Etymology: (`err`), [x=](lesser variant).

noreturn void verrx(int status, const char* format, va_list args)
     This function is a non-standard BSD extension, and requires that _BSD_SOURCE is defined. It is made available by including the header file <err.h>. It is identical to errx except it uses va_list instead of being a variadic function.

     Etymology: (V)ariadic version of (`errx`).

void error(int status, int errnum, const char* format, ...)
     This function is a GNU-extension (_GNU_SOURCE) that is made available by including the header file <error.h>.

     This function flushes stdout and prints an error message to stderr. The message begins with the process name (more precisely: program_invocation_name), a colon, and a blank space. The message, continues with a desciption of the errno-value pass via the argument errnum. However, if errnum is 0, the string described by format and the following arguments are printed --- using fprintf --- instead of the description of errnum.

     Unless status is 0, the process will exit with the exit value status & 255.

     Etymology: Report (error)!

void verror(int status, int errnum, const char* format, va_list args)
     This function is made available, if both _GNU_SOURCE and _SLIBC_SOURCE are defined, by including the header file <error.h>. It is identical to error except it uses va_list instead of being a variadic function.

     Etymology: (V)ariadic version of (error).

void error_at_line(int status, int errnum, const char* filename, unsigned int linenum, const char* format, ...)
     This function is a GNU-extension (_GNU_SOURCE) that is made available by including the header file <error.h>. It is a variant of error. It will also print the filename and the line where there error occured.

     A way to use this function is to utilise the C preprocessor.

          #include <error.h>
          #include <errno.h>
          #define if(...)  if (error_line = __LINE__, __VA_ARGS__)

          int main(void)
          {
            int error_line;

            if (something_that_may_fail())
              goto fail;

            return 0;
           fail:
            error_at_line(1, errno, __FILE__, error_line, NULL);
          }

     Etymology: Report (error at line) in source code!

void verror_at_line(int status, int errnum, const char* filename, unsigned int linenum, const char* format, va_list args)
     This function is made available, if both _GNU_SOURCE and _SLIBC_SOURCE are defined, by including the header file <error.h>. It is identical to error_at_line except it uses va_list instead of being a variadic function.

     Etymology: (V)ariadic version of (error_at_line).

volatile unsigned int error_message_count
     This variable is a GNU-extension (_GNU_SOURCE) that is made available by including the header file <error.h>. Counts the number of times error (or verror) and error_at_line (verror_at_line) has returned. This variable is global and shared by all threads.

     Etymology: (error)-subsystem: (message count).

volatile int error_one_per_line
     This variable is a GNU-extension (_GNU_SOURCE) that is made available by including the header file <error.h>.

     If set to non-zero (the default), error_at_line and verror_at_line restrict themself to only print an error the first time it appears. This is determined by the uniqueness of the combination of the values on filename and linenum. However it will forget the line the next time the function is called from a different line. This variable is global and shared by all threads. As a slibc modification, errnum is also remembered, meaning if the error code is different (zero is considered an error code), the error is printed even if it occurred on the same line as the last time.

     Etymology: (error)-subsystem: print (one) time (per line).

void (*volatile error_print_progname)(void)
     This variable is a GNU-extension (_GNU_SOURCE) that is made available by including the header file <error.h>.

     If not NULL, this function is used instead of flushing stdout and printing the process name to stderr, by error (verror) and verror_at_line (verror_at_line). This variable is global and shared by all threads.

     Etymology: (error)-subsystem function: (print) the (prog)ram's (name).

In slibc, functions defined in <err.h> use functions defined in <error.h>.

slibc adds the header file <slibc-error.h>. It includes <errno.h>. It does not require the _SLIBC_SOURCE is defined, but it does require that neither _PORTABLE_SOURCE nor _LIBRARY_HEADER. <slibc-error.h> also uses C preprocessors directives added by the ISO C99 standard. Additionally, the C language extensions ({ }) and typeof. These extensions are available in GCC.

FAILABLE_CALL(expression)
     Store the current line, so we know which line failed, when PRINT_CUSTOM_FAILURE, PRINT_FAILURE or slibc_perror is called. expression will be evaluated exaclty once, and is returned without casting.

     Currently, the expression is not stored. However, if it is found in the future that it is preferable to have the expression printed on failure, this may change in the future. Therefore, it is advisable to only include the function call (and perhaps a variable assigment) in expression, and not the failure check.

     Example usage:

          int my_function(void)
          {
            size_t n;
            void* array;
            /* ... */
            if (FAILABLE_CALL(array = malloc(n)) == NULL)
              goto fail;
            /* ... */
            return 0;

           fail:
            PRINT_FAILURE(NULL);
            /* ... */
            return errno = 0, -1;
          }

     A more scalable example:

          #define fail_if (call_and_check)  \
            do { \
              if (FAILABLE_CALL(call_and_check)) \
                goto fail; \
            } while (0)
          /* xrm`xtt try xrm` or simply `xtt t xrm` may be even better.xtt */

          #define fail_unless (call_and_check)  \
            fail_if(!(call_and_check))
          /* xrm`xtt f xrm` may be even better.xtt */

          int my_function(void)
          {
            size_t n;
            void* array;
            /* ... */
            fail_if (!(array = malloc(n)));
            /* xrm or perhaps, `xtt fail_unless (array = malloc(n));xrm`xtt */
            /* ... */
            return 0;

           fail:
            PRINT_FAILURE(NULL);
            /* ... */
            return errno = 0, -1;
          }

FAILURE_CHECK(condition, offset)
     Check whether an error occurred. If an error occurred, stored the line, for PRINT_CUSTOM_FAILURE or PRINT_FAILURE, where the error occurred.

     condition should evaluate to non-zero on and only on error. offset is the number of lines above the current line that was the line that failed, if condition evaluates to non-zero. !!condition is returned.

     Example usage:

          int my_function(void)
          {
            char* buf;
            size_t bufsize;
            ssize_t r;
            int fd;
            /* ... */
            for (;;)
              {
                r = read(fd, buf, bufsize);
                if (FAILURE_CHECK(r < 0, 1))
                  {
                    if (errno != EINTR)
                      /* xrm Or `xtt FAILURE_CHECK(errno != EINTR, 3)xrm`.xtt */
                      goto fail;
                    continue;
                  }
                /* ... */
              }
            /* ... */
            return 0;

           fail:
            PRINT_FAILURE(NULL);
            /* ... */
            return errno = 0, -1;
          }

PRINT_FAILURE(...)
     This macro print an error message describing the error, and where the error happened. Optionally with detailed description of the action that failed.

     This function must be called in the same file and function as the the expansion of FAILABLE_CALL, FAILURE_CHECK, or slibc_perror. It is recommended that this is done all the way down the call-stack to main. This is however problematic (although it is possible) if you do not want the process to exit.

     Example of recursion:

          static int b(void)
          {
            if (FAILABLE_CALL(some_function()) < 0)
              goto fail;
            return 0;
           fail:
            return PRINT_FAILURE(NULL), -1;
          }
          static int a(void)
          {
            if (FAILABLE_CALL(b()) < 0)
              goto fail;
            return 0;
           fail:
            return PRINT_FAILURE(NULL), -1;
          }
          int main(void)
          {
            if (FAILABLE_CALL(a()) < 0)
              goto fail;
            return 0;
           fail:
            return PRINT_FAILURE(NULL), 1;
          }

     This macro will set errno to zero. If you have statements after the call to this function that may modify errno, be sure to set errno to zero before returning. A good way to do this is to have the return statement look like return errno = 0, -1.

     The arguments for this macro should be a printf-formatting-string followed by formatting-arguments used to describe what action failed. If the first argument is NULL, this is not printed and only the location of the error and errno is used to describe the error.

PRINT_CUSTOM_FAILURE(error_code, error_string, ...)
     This macro is is a generalisation of PRINT_FAILURE. It is useful if the error is not described with errno and strerror. It adds two parameters at the beginning:

     error_code
          The error code. This must be a modifiable lvalue, as it will be modified to zero to indicate that the error string has already been printed. Thus, on the original error location this value must not be zero.

     error_string
          Textual representation of the error. If errno indicates the error, this should usually be strerror(errno).

     Usage example:

          PRINT_CUSTOM_FAILURE(r, gai_strerror(r),
            _("fail to connect to server: %s"), host)

void slibc_perror(const char* progname, const char* filename, int linenum, const char* function, int* error_code, const char* error_string, const char* format, ...)
     This function print a description of an error, and where the error occurred. This function is capable of printed the full call-stack.

     It is not recommended to used this function directly. Use the macros in <slibc-error.h> instead.

     This function has a number of argument:

     progname
          The name of the program. `NULL or an empty string to use program_invocation_name.

     filename
          The source code file where the error occurred.

     linenum
          The line in the source code where the error occurred.

     function
          The function in the source code where the error occurred.

     error_code
          Pointer the variable that stores the error code, will zeroed.

     error_string
          Textual description of the error code. NULL if strerror should be used. This parameter is unused if error_code is zero.

     format
          Formatting-string for a description of the action that failed. NULL if no description other than the location and error_string should be printed. It is followed by the formatting-arguments.

     Etymology: (slibc)-enhancement of (perror).