Next: , Previous: , Up: Top   [Contents][Index]


9 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: , Previous: , Up: Top   [Contents][Index]