Next: Stack and heap size, Previous: Porting, Up: GNU GRUB developer manual [Contents][Index]

## 7 Error Handling

Error handling in GRUB 2 is based on exception handling model. As C language doesn’t directly support exceptions, exception handling behavior is emulated in software.

When exception is raised, function must return to calling function. If calling function does not provide handling of the exception it must return back to its calling function and so on, until exception is handled. If exception is not handled before prompt is displayed, error message will be shown to user.

Exception information is stored on `grub_errno` global variable. If `grub_errno` variable contains value `GRUB_ERR_NONE`, there is no active exception and application can continue normal processing. When `grub_errno` has other value, it is required that application code either handles this error or returns instantly to caller. If function is with return type `grub_err_t` is about to return `GRUB_ERR_NONE`, it should not set `grub_errno` to that value. Only set `grub_errno` in cases where there is error situation.

Simple exception forwarder.

    grub_err_t
    forwarding_example (void)
    {
      /* Call function that might cause exception.  */
      foobar ();

      /* No special exception handler, just forward possible exceptions.  */
      if (grub_errno != GRUB_ERR_NONE)
        {
          return grub_errno;
        }

      /* All is OK, do more processing.  */

      /* Return OK signal, to caller.  */
      return GRUB_ERR_NONE;
    }

Error reporting has two components, the actual error code (of type `grub_err_t`) and textual message that will be displayed to user. List of valid error codes is listed in header file `include/grub/err.h`. Textual error message can contain any textual data. At time of writing, error message can contain up to 256 characters (including terminating NUL). To ease error reporting there is a helper function `grub_error` that allows easier formatting of error messages and should be used instead of writing directly to global variables.

Example of error reporting.

    grub_err_t
    failing_example ()
    {
      return grub_error (GRUB_ERR_FILE_NOT_FOUND,
                         "Failed to read %s, tried %d times.",
                         "test.txt",
                         10);
    }

If there is a special reason that error code does not need to be taken account, `grub_errno` can be zeroed back to `GRUB_ERR_NONE`. In cases like this all previous error codes should have been handled correctly. This makes sure that there are no unhandled exceptions.

Example of zeroing `grub_errno`.

    grub_err_t
    probe_example ()
    {
      /* Try to probe device type 1.  */
      probe_for_device ();
      if (grub_errno == GRUB_ERR_NONE)
        {
          /* Device type 1 was found on system.  */
          register_device ();
          return GRUB_ERR_NONE;
        }
      /* Zero out error code.  */
      grub_errno = GRUB_ERR_NONE;

      /* No device type 1 found, try to probe device type 2.  */
      probe_for_device2 ();
      if (grub_errno == GRUB_ERR_NONE)
        {
          /* Device type 2 was found on system.  */
          register_device2 ();
          return GRUB_ERR_NONE;
        }
      /* Zero out error code.  */
      grub_errno = GRUB_ERR_NONE;

      /* Return custom error message.  */
      return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "No device type 1 or 2 found.");
    }

Some times there is a need to continue processing even if there is a error state in application. In situations like this, there is a needed to save old error state and then call other functions that might fail. To aid in this, there is a error stack implemented. Error state can be pushed to error stack by calling function `grub_error_push ()`. When processing has been completed, `grub_error_pop ()` can be used to pop error state from stack. Error stack contains predefined amount of error stack items. Error stack is protected for overflow and marks these situations so overflow error does not get unseen. If there is no space available to store error message, it is simply discarded and overflow will be marked as happened. When overflow happens, it most likely will corrupt error stack consistency as for pushed error there is no matching pop, but overflow message will be shown to inform user about the situation. Overflow message will be shown at time when prompt is about to be drawn.

Example usage of error stack.

    /* Save possible old error message.  */
    grub_error_push ();

    /* Do your stuff here.  */
    call_possibly_failing_function ();

    if (grub_errno != GRUB_ERR_NONE)
      {
        /* Inform rest of the code that there is error (grub_errno
           is set). There is no pop here as we want both error states
           to be displayed.  */
        return;
      }

    /* Restore old error state by popping previous item from stack. */
    grub_error_pop ();

Next: Stack and heap size, Previous: Porting, Up: GNU GRUB developer manual [Contents][Index]