grub2-dev: Error Handling

1 
1 6 Error Handling
1 ****************
1 
1 Error handling in GRUB 2 is based on exception handling model.  As C
1 language doesn't directly support exceptions, exception handling
1 behavior is emulated in software.
1 
1    When exception is raised, function must return to calling function.
1 If calling function does not provide handling of the exception it must
1 return back to its calling function and so on, until exception is
1 handled.  If exception is not handled before prompt is displayed, error
1 message will be shown to user.
1 
1    Exception information is stored on 'grub_errno' global variable.  If
1 'grub_errno' variable contains value 'GRUB_ERR_NONE', there is no active
1 exception and application can continue normal processing.  When
1 'grub_errno' has other value, it is required that application code
1 either handles this error or returns instantly to caller.  If function
1 is with return type 'grub_err_t' is about to return 'GRUB_ERR_NONE', it
1 should not set 'grub_errno' to that value.  Only set 'grub_errno' in
1 cases where there is error situation.
1 
1    Simple exception forwarder.
1      grub_err_t
1      forwarding_example (void)
1      {
1        /* Call function that might cause exception.  */
1        foobar ();
1 
1        /* No special exception handler, just forward possible exceptions.  */
1        if (grub_errno != GRUB_ERR_NONE)
1          {
1            return grub_errno;
1          }
1 
1        /* All is OK, do more processing.  */
1 
1        /* Return OK signal, to caller.  */
1        return GRUB_ERR_NONE;
1      }
1 
1    Error reporting has two components, the actual error code (of type
1 'grub_err_t') and textual message that will be displayed to user.  List
1 of valid error codes is listed in header file 'include/grub/err.h'.
1 Textual error message can contain any textual data.  At time of writing,
1 error message can contain up to 256 characters (including terminating
1 NUL). To ease error reporting there is a helper function 'grub_error'
1 that allows easier formatting of error messages and should be used
1 instead of writing directly to global variables.
1 
1    Example of error reporting.
1      grub_err_t
1      failing_example ()
1      {
1        return grub_error (GRUB_ERR_FILE_NOT_FOUND,
1                           "Failed to read %s, tried %d times.",
1                           "test.txt",
1                           10);
1      }
1 
1    If there is a special reason that error code does not need to be
1 taken account, 'grub_errno' can be zeroed back to 'GRUB_ERR_NONE'.  In
1 cases like this all previous error codes should have been handled
1 correctly.  This makes sure that there are no unhandled exceptions.
1 
1    Example of zeroing 'grub_errno'.
1      grub_err_t
1      probe_example ()
1      {
1        /* Try to probe device type 1.  */
1        probe_for_device ();
1        if (grub_errno == GRUB_ERR_NONE)
1          {
1            /* Device type 1 was found on system.  */
1            register_device ();
1            return GRUB_ERR_NONE;
1          }
1        /* Zero out error code.  */
1        grub_errno = GRUB_ERR_NONE;
1 
1        /* No device type 1 found, try to probe device type 2.  */
1        probe_for_device2 ();
1        if (grub_errno == GRUB_ERR_NONE)
1          {
1            /* Device type 2 was found on system.  */
1            register_device2 ();
1            return GRUB_ERR_NONE;
1          }
1        /* Zero out error code.  */
1        grub_errno = GRUB_ERR_NONE;
1 
1        /* Return custom error message.  */
1        return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "No device type 1 or 2 found.");
1      }
1 
1    Some times there is a need to continue processing even if there is a
1 error state in application.  In situations like this, there is a needed
1 to save old error state and then call other functions that might fail.
1 To aid in this, there is a error stack implemented.  Error state can be
1 pushed to error stack by calling function 'grub_error_push ()'.  When
1 processing has been completed, 'grub_error_pop ()' can be used to pop
1 error state from stack.  Error stack contains predefined amount of error
1 stack items.  Error stack is protected for overflow and marks these
1 situations so overflow error does not get unseen.  If there is no space
1 available to store error message, it is simply discarded and overflow
1 will be marked as happened.  When overflow happens, it most likely will
1 corrupt error stack consistency as for pushed error there is no matching
1 pop, but overflow message will be shown to inform user about the
1 situation.  Overflow message will be shown at time when prompt is about
1 to be drawn.
1 
1    Example usage of error stack.
1      /* Save possible old error message.  */
1      grub_error_push ();
1 
1      /* Do your stuff here.  */
1      call_possibly_failing_function ();
1 
1      if (grub_errno != GRUB_ERR_NONE)
1        {
1          /* Inform rest of the code that there is error (grub_errno
1             is set). There is no pop here as we want both error states
1             to be displayed.  */
1          return;
1        }
1 
1      /* Restore old error state by popping previous item from stack. */
1      grub_error_pop ();
1