1 /* search.c - search devices based on a file or a filesystem label */
   2 /*
   3  *  GRUB  --  GRand Unified Bootloader
   4  *  Copyright (C) 2005,2007,2008,2009  Free Software Foundation, Inc.
   5  *
   6  *  GRUB is free software: you can redistribute it and/or modify
   7  *  it under the terms of the GNU General Public License as published by
   8  *  the Free Software Foundation, either version 3 of the License, or
   9  *  (at your option) any later version.
  10  *
  11  *  GRUB is distributed in the hope that it will be useful,
  12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14  *  GNU General Public License for more details.
  15  *
  16  *  You should have received a copy of the GNU General Public License
  17  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
  18  */
  19 
  20 #include <grub/types.h>
  21 #include <grub/misc.h>
  22 #include <grub/mm.h>
  23 #include <grub/err.h>
  24 #include <grub/dl.h>
  25 #include <grub/env.h>
  26 #include <grub/extcmd.h>
  27 #include <grub/search.h>
  28 #include <grub/i18n.h>
  29 
  30 GRUB_MOD_LICENSE ("GPLv3+");
  31 
  32 static const struct grub_arg_option options[] =
  33   {
  34     {"file",            'f', 0, N_("Search devices by a file."), 0, 0},
  35     {"label",           'l', 0, N_("Search devices by a filesystem label."),
  36      0, 0},
  37     {"fs-uuid",         'u', 0, N_("Search devices by a filesystem UUID."),
  38      0, 0},
  39     {"set",             's', GRUB_ARG_OPTION_OPTIONAL,
  40      N_("Set a variable to the first device found."), N_("VARNAME"),
  41      ARG_TYPE_STRING},
  42     {"no-floppy",       'n', 0, N_("Do not probe any floppy drive."), 0, 0},
  43     {"hint",            'h', GRUB_ARG_OPTION_REPEATABLE,
  44      N_("First try the device HINT. If HINT ends in comma, "
  45         "also try subpartitions"), N_("HINT"), ARG_TYPE_STRING},
  46     {"hint-ieee1275",   0, GRUB_ARG_OPTION_REPEATABLE,
  47      N_("First try the device HINT if currently running on IEEE1275. "
  48         "If HINT ends in comma, also try subpartitions"),
  49      N_("HINT"), ARG_TYPE_STRING},
  50     {"hint-bios",   0, GRUB_ARG_OPTION_REPEATABLE,
  51      N_("First try the device HINT if currently running on BIOS. "
  52         "If HINT ends in comma, also try subpartitions"),
  53      N_("HINT"), ARG_TYPE_STRING},
  54     {"hint-baremetal",   0, GRUB_ARG_OPTION_REPEATABLE,
  55      N_("First try the device HINT if direct hardware access is supported. "
  56         "If HINT ends in comma, also try subpartitions"),
  57      N_("HINT"), ARG_TYPE_STRING},
  58     {"hint-efi",   0, GRUB_ARG_OPTION_REPEATABLE,
  59      N_("First try the device HINT if currently running on EFI. "
  60         "If HINT ends in comma, also try subpartitions"),
  61      N_("HINT"), ARG_TYPE_STRING},
  62     {"hint-arc",   0, GRUB_ARG_OPTION_REPEATABLE,
  63      N_("First try the device HINT if currently running on ARC."
  64         " If HINT ends in comma, also try subpartitions"),
  65      N_("HINT"), ARG_TYPE_STRING},
  66     {"zfs-mirror", 'z', 0, N_("Handle zfs-mirror disk"), 0, 0},
  67     {0, 0, 0, 0, 0, 0}
  68   };
  69 
  70 enum options
  71   {
  72     SEARCH_FILE,
  73     SEARCH_LABEL,
  74     SEARCH_FS_UUID,
  75     SEARCH_SET,
  76     SEARCH_NO_FLOPPY,
  77     SEARCH_HINT,
  78     SEARCH_HINT_IEEE1275,
  79     SEARCH_HINT_BIOS,
  80     SEARCH_HINT_BAREMETAL,
  81     SEARCH_HINT_EFI,
  82     SEARCH_HINT_ARC,
  83     SEARCH_ZFS_MIRROR,
  84  };
  85 
  86 static grub_err_t
  87 grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args)
  88 {
  89   struct grub_arg_list *state = ctxt->state;
  90   const char *var = 0;
  91   const char *id = 0;
  92   int i = 0, j = 0, nhints = 0;
  93   char **hints = NULL;
  94   int mirror_mode = 0;
  95 
  96   if (state[SEARCH_HINT].set)
  97     for (i = 0; state[SEARCH_HINT].args[i]; i++)
  98       nhints++;
  99 
 100 #ifdef GRUB_MACHINE_IEEE1275
 101   if (state[SEARCH_HINT_IEEE1275].set)
 102     for (i = 0; state[SEARCH_HINT_IEEE1275].args[i]; i++)
 103       nhints++;
 104 #endif
 105 
 106 #ifdef GRUB_MACHINE_EFI
 107   if (state[SEARCH_HINT_EFI].set)
 108     for (i = 0; state[SEARCH_HINT_EFI].args[i]; i++)
 109       nhints++;
 110 #endif
 111 
 112 #ifdef GRUB_MACHINE_PCBIOS
 113   if (state[SEARCH_HINT_BIOS].set)
 114     for (i = 0; state[SEARCH_HINT_BIOS].args[i]; i++)
 115       nhints++;
 116 #endif
 117 
 118 #ifdef GRUB_MACHINE_ARC
 119   if (state[SEARCH_HINT_ARC].set)
 120     for (i = 0; state[SEARCH_HINT_ARC].args[i]; i++)
 121       nhints++;
 122 #endif
 123 
 124   if (state[SEARCH_HINT_BAREMETAL].set)
 125     for (i = 0; state[SEARCH_HINT_BAREMETAL].args[i]; i++)
 126       nhints++;
 127 
 128   hints = grub_malloc (sizeof (hints[0]) * nhints);
 129   if (!hints)
 130     return grub_errno;
 131   j = 0;
 132 
 133   if (state[SEARCH_HINT].set)
 134     for (i = 0; state[SEARCH_HINT].args[i]; i++)
 135       hints[j++] = state[SEARCH_HINT].args[i];
 136 
 137 #ifdef GRUB_MACHINE_IEEE1275
 138   if (state[SEARCH_HINT_IEEE1275].set)
 139     for (i = 0; state[SEARCH_HINT_IEEE1275].args[i]; i++)
 140       hints[j++] = state[SEARCH_HINT_IEEE1275].args[i];
 141 #endif
 142 
 143 #ifdef GRUB_MACHINE_EFI
 144   if (state[SEARCH_HINT_EFI].set)
 145     for (i = 0; state[SEARCH_HINT_EFI].args[i]; i++)
 146       hints[j++] = state[SEARCH_HINT_EFI].args[i];
 147 #endif
 148 
 149 #ifdef GRUB_MACHINE_ARC
 150   if (state[SEARCH_HINT_ARC].set)
 151     for (i = 0; state[SEARCH_HINT_ARC].args[i]; i++)
 152       hints[j++] = state[SEARCH_HINT_ARC].args[i];
 153 #endif
 154 
 155 #ifdef GRUB_MACHINE_PCBIOS
 156   if (state[SEARCH_HINT_BIOS].set)
 157     for (i = 0; state[SEARCH_HINT_BIOS].args[i]; i++)
 158       hints[j++] = state[SEARCH_HINT_BIOS].args[i];
 159 #endif
 160 
 161   if (state[SEARCH_HINT_BAREMETAL].set)
 162     for (i = 0; state[SEARCH_HINT_BAREMETAL].args[i]; i++)
 163       hints[j++] = state[SEARCH_HINT_BAREMETAL].args[i];
 164 
 165   /* Skip hints for future platforms.  */
 166   for (j = 0; j < argc; j++)
 167     if (grub_memcmp (args[j], "--hint-", sizeof ("--hint-") - 1) != 0)
 168       break;
 169 
 170   if (state[SEARCH_SET].set)
 171     var = state[SEARCH_SET].arg ? state[SEARCH_SET].arg : "root";
 172 
 173   if (argc != j)
 174     id = args[j];
 175   else if (state[SEARCH_SET].set && state[SEARCH_SET].arg)
 176     {
 177       id = state[SEARCH_SET].arg;
 178       var = "root";
 179     }
 180   else
 181     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
 182 
 183   if (state[SEARCH_ZFS_MIRROR].set)
 184     mirror_mode = 1;
 185 
 186   if (state[SEARCH_LABEL].set)
 187     grub_search_label (id, var, state[SEARCH_NO_FLOPPY].set, 
 188                        hints, nhints, mirror_mode);
 189   else if (state[SEARCH_FS_UUID].set)
 190     grub_search_fs_uuid (id, var, state[SEARCH_NO_FLOPPY].set,
 191                          hints, nhints, mirror_mode);
 192   else if (state[SEARCH_FILE].set)
 193     grub_search_fs_file (id, var, state[SEARCH_NO_FLOPPY].set, 
 194                          hints, nhints, mirror_mode);
 195   else
 196     return grub_error (GRUB_ERR_INVALID_COMMAND, "unspecified search type");
 197 
 198   return grub_errno;
 199 }
 200 
 201 static grub_extcmd_t cmd;
 202 
 203 GRUB_MOD_INIT(search)
 204 {
 205   cmd =
 206     grub_register_extcmd ("search", grub_cmd_search,
 207                           GRUB_COMMAND_FLAG_EXTRACTOR | GRUB_COMMAND_ACCEPT_DASH,
 208                           N_("[-f|-l|-u|-s|-n] [--hint HINT [--hint HINT] ...]"
 209                              " NAME"),
 210                           N_("Search devices by file, filesystem label"
 211                              " or filesystem UUID."
 212                              " If --set is specified, the first device found is"
 213                              " set to a variable. If no variable name is"
 214                              " specified, `root' is used."),
 215                           options);
 216 }
 217 
 218 GRUB_MOD_FINI(search)
 219 {
 220   grub_unregister_extcmd (cmd);
 221 }