Next: Stack and heap size, Previous: Porting, Up: Top [Contents][Index]
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: Top [Contents][Index]