/* handler.c - support handler loading */ /* * GRUB -- GRand Unified Bootloader * Copyright (C) 2009 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRUB is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GRUB. If not, see . */ #include #include #include #include #include #include #include #include struct grub_handler_list { struct grub_handler_list *next; char *name; grub_command_t cmd; }; static grub_list_t handler_list; static grub_err_t grub_handler_cmd (struct grub_command *cmd, int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) { char *p; grub_handler_class_t class; grub_handler_t handler; p = grub_strchr (cmd->name, '.'); if (! p) return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid command name"); if (cmd->data) { if (! grub_dl_get (cmd->data)) { grub_dl_t mod; mod = grub_dl_load (cmd->data); if (mod) grub_dl_ref (mod); else return grub_errno; } grub_free (cmd->data); cmd->data = 0; } *p = 0; class = grub_named_list_find (GRUB_AS_NAMED_LIST (grub_handler_class_list), cmd->name); *p = '.'; if (! class) return grub_error (GRUB_ERR_FILE_NOT_FOUND, "class not found"); handler = grub_named_list_find (GRUB_AS_NAMED_LIST (class->handler_list), p + 1); if (! handler) return grub_error (GRUB_ERR_FILE_NOT_FOUND, "handler not found"); grub_handler_set_current (class, handler); return 0; } static void insert_handler (char *name, char *module) { struct grub_handler_list *item; char *data; if (grub_command_find (name)) return; item = grub_malloc (sizeof (*item)); if (! item) return; item->name = grub_strdup (name); if (! item->name) { grub_free (item); return; } if (module) { data = grub_strdup (module); if (! data) { grub_free (item->name); grub_free (item); return; } } else data = 0; item->cmd = grub_register_command (item->name, grub_handler_cmd, 0, "Set active handler."); if (! item->cmd) { grub_free (data); grub_free (item->name); grub_free (item); return; } item->cmd->data = data; grub_list_push (&handler_list, GRUB_AS_LIST (item)); } /* Read the file handler.lst for auto-loading. */ void read_handler_list (void) { const char *prefix; static int first_time = 1; const char *class_name; auto int iterate_handler (grub_handler_t handler); int iterate_handler (grub_handler_t handler) { char name[grub_strlen (class_name) + grub_strlen (handler->name) + 2]; grub_strcpy (name, class_name); grub_strcat (name, "."); grub_strcat (name, handler->name); insert_handler (name, 0); return 0; } auto int iterate_class (grub_handler_class_t class); int iterate_class (grub_handler_class_t class) { class_name = class->name; grub_list_iterate (GRUB_AS_LIST (class->handler_list), (grub_list_hook_t) iterate_handler); return 0; } /* Make sure that this function does not get executed twice. */ if (! first_time) return; first_time = 0; prefix = grub_env_get ("prefix"); if (prefix) { char *filename; filename = grub_xasprintf ("%s/handler.lst", prefix); if (filename) { grub_file_t file; file = grub_file_open (filename); if (file) { char *buf = NULL; for (;; grub_free (buf)) { char *p; buf = grub_file_getline (file); if (! buf) break; if (! grub_isgraph (buf[0])) continue; p = grub_strchr (buf, ':'); if (! p) continue; *p = '\0'; while (*++p == ' ') ; insert_handler (buf, p); } grub_file_close (file); } grub_free (filename); } } grub_list_iterate (GRUB_AS_LIST (grub_handler_class_list), (grub_list_hook_t) iterate_class); /* Ignore errors. */ grub_errno = GRUB_ERR_NONE; } void free_handler_list (void) { struct grub_handler_list *item; while ((item = grub_list_pop (&handler_list)) != 0) { grub_free (item->cmd->data); grub_unregister_command (item->cmd); grub_free (item->name); grub_free (item); } }