1 /*
   2  *  GRUB  --  GRand Unified Bootloader
   3  *  Copyright (C) 2012 Daniil Lunev
   4  *
   5  *  GRUB is free software: you can redistribute it and/or modify
   6  *  it under the terms of the GNU General Public License as published by
   7  *  the Free Software Foundation, either version 3 of the License, or
   8  *  (at your option) any later version.
   9  *
  10  *  GRUB is distributed in the hope that it will be useful,
  11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13  *  GNU General Public License for more details.
  14  *
  15  *  You should have received a copy of the GNU General Public License
  16  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
  17  */
  18 
  19 #define VALUE_SIZE 512
  20 
  21 typedef struct entries entries;
  22 struct entries {
  23   entries *next;
  24   char ** entry_info;
  25 };
  26 
  27 enum param_consts {
  28   ENTRY_NAME,
  29   POOL_UUID,
  30   POOL_LABEL,
  31   DATA_SET,
  32   KERNEL_PATH,
  33   KERNEL_OPTIONS,
  34   BA_PATH,
  35   DOLLAR_KERNEL_PATH,
  36   DOLLAR_BA_PATH,
  37 };
  38 
  39 static const char * params_list[] = {
  40   "entry_name",
  41   "pool_uuid",
  42   "pool_label",
  43   "data_set",
  44   "kernel_path",
  45   "kernel_options",
  46   "module",
  47   "kernel_path$",
  48   "module$",
  49   NULL
  50 };
  51 
  52 static grub_err_t
  53 init_entries(entries ** menu_entries)
  54 {
  55   (*menu_entries) = (entries*) grub_zalloc(sizeof (menu_entries));
  56   if (! *menu_entries)
  57     return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("memory can not be allocated"));
  58   return 0;
  59 }
  60 
  61 static entries * 
  62 new_entry(char * name, entries * entry_list)
  63 {
  64   unsigned int i;
  65 
  66   if (entry_list->next)
  67     do {
  68       entry_list = entry_list->next;
  69       if (!grub_strcmp(name, entry_list->entry_info[0]))
  70         return entry_list;
  71     } while (entry_list->next);
  72   entry_list->next = (entries*) grub_zalloc(sizeof(entries));
  73   if (! entry_list->next)
  74     return NULL;
  75   entry_list = entry_list->next;
  76   entry_list->entry_info = (char**) grub_zalloc(sizeof(params_list));
  77   for (i = 0; i < sizeof(params_list) / sizeof(*params_list); i++) {
  78     entry_list->entry_info[i] = (char *) grub_zalloc(VALUE_SIZE);
  79     if (! entry_list->entry_info[i]) 
  80       return NULL;
  81   }
  82   grub_strcpy(entry_list->entry_info[0], name);
  83   return entry_list;
  84 }
  85 
  86 static void
  87 clear_entries(entries * entry_list)
  88 {
  89   entries * next;
  90   unsigned int i;
  91 
  92   next = entry_list->next;
  93   grub_free(entry_list);
  94   entry_list = next;
  95 
  96   while (entry_list) {
  97     next = entry_list->next;
  98     if (entry_list->entry_info) {
  99       for (i = 0; i < sizeof(params_list) / sizeof(*params_list); i++)
 100         if (entry_list->entry_info[i])
 101           grub_free(entry_list->entry_info[i]);
 102       grub_free(entry_list->entry_info);
 103     }
 104     grub_free(entry_list);
 105     entry_list = next;
 106   }
 107 }
 108 
 109 static grub_err_t
 110 add_entries(entries * menu_entries)
 111 {
 112   grub_err_t err;
 113   char cl1[] = "os";
 114   char cl2[] = "illumos";
 115   char * class[] = {cl1, cl2, NULL};
 116   char * argv[] = { NULL, NULL };
 117   char id[512];
 118   char * entry_source = NULL;
 119   char * data_set;
 120   char entry_template[] = 
 121     "insmod part_sunpc\n"
 122     "insmod part_msdos\n"
 123     "insmod zfs\n"
 124     "insmod gzio\n"
 125     "if cpuid -l ; then\n"
 126     "  ISADIR=amd64\n"
 127     "else\n"
 128     "  ISADIR=\n"
 129     "fi\n";
 130 
 131   menu_entries = menu_entries->next;
 132   while (menu_entries) {
 133     argv[0] = grub_strdup(menu_entries->entry_info[ENTRY_NAME]);
 134     if (!argv[0])
 135       return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("memory can not be allocated"));
 136     entry_source = (char*) grub_zalloc(2048);
 137 
 138     if (!entry_source)
 139       return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("memory can not be allocated"));
 140 
 141     if (menu_entries->entry_info[DATA_SET][0] != 0)
 142       data_set = grub_strchr(menu_entries->entry_info[DATA_SET], '/');
 143     else
 144       data_set = grub_strdup("$ZFS_DATASET");
 145     grub_strcpy(entry_source, entry_template);
 146     if (menu_entries->entry_info[POOL_UUID][0]) {
 147       grub_strcat(entry_source, "search --no-floppy --zfs-mirror --fs-uuid --set=root ");
 148       grub_strcat(entry_source, menu_entries->entry_info[POOL_UUID]);
 149     } else {
 150       grub_strcat(entry_source, "search --no-floppy --zfs-mirror --label --set=root ");
 151       grub_strcat(entry_source, menu_entries->entry_info[POOL_LABEL]);
 152     }
 153     grub_strcat(entry_source, "\n");
 154     grub_strcat(entry_source, "zfs-bootfs ($root)");
 155     if (menu_entries->entry_info[DATA_SET][0] != 0) {
 156       grub_strcat(entry_source, data_set);
 157       grub_strcat(entry_source, " ZFS_BOOTFS\n");
 158     } else {
 159       grub_strcat(entry_source, "default ZFS_BOOTFS ZFS_DATASET\n");
 160     }
 161     grub_strcat(entry_source, "multiboot ($root)");
 162     if (! menu_entries->entry_info[DOLLAR_KERNEL_PATH][0]) {
 163       grub_strcat(entry_source, data_set);
 164       grub_strcat(entry_source, "/@");
 165       grub_strcat(entry_source, menu_entries->entry_info[KERNEL_PATH]);
 166       grub_strcat(entry_source, " ");
 167       grub_strcat(entry_source, menu_entries->entry_info[KERNEL_PATH]);
 168     } else {
 169       grub_strcat(entry_source, menu_entries->entry_info[DOLLAR_KERNEL_PATH]);
 170     }
 171     grub_strcat(entry_source, " ");
 172     grub_strcat(entry_source, menu_entries->entry_info[KERNEL_OPTIONS]);
 173     grub_strcat(entry_source, "\n");
 174     grub_strcat(entry_source, "module ($root)");
 175     if (! menu_entries->entry_info[DOLLAR_KERNEL_PATH][0]) {
 176       grub_strcat(entry_source, data_set);
 177       grub_strcat(entry_source, "/@");
 178       grub_strcat(entry_source, menu_entries->entry_info[BA_PATH]);
 179       grub_strcat(entry_source, " ");
 180       grub_strcat(entry_source, menu_entries->entry_info[BA_PATH]);
 181     } else {
 182       grub_strcat(entry_source, menu_entries->entry_info[DOLLAR_BA_PATH]);
 183     }
 184 
 185     grub_strcpy(id, argv[0]);
 186     grub_strcat(id, "-");
 187     grub_strcat(id, menu_entries->entry_info[POOL_UUID]);
 188 
 189     err = grub_normal_add_menu_entry (2, (const char **) argv, class, id,
 190                 NULL,  NULL,  NULL, entry_source, 0);
 191 
 192     if (err)
 193       return err;
 194     
 195     grub_free(argv[0]);
 196     menu_entries = menu_entries->next;
 197   }
 198   grub_free(entry_source);
 199   return 0;
 200 }