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     {0, 0, 0, 0, 0, 0}
  67   };
  68 
  69 enum options
  70   {
  71     SEARCH_FILE,
  72     SEARCH_LABEL,
  73     SEARCH_FS_UUID,
  74     SEARCH_SET,
  75     SEARCH_NO_FLOPPY,
  76     SEARCH_HINT,
  77     SEARCH_HINT_IEEE1275,
  78     SEARCH_HINT_BIOS,
  79     SEARCH_HINT_BAREMETAL,
  80     SEARCH_HINT_EFI,
  81     SEARCH_HINT_ARC,
  82  };
  83 
  84 static grub_err_t
  85 grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args)
  86 {
  87   struct grub_arg_list *state = ctxt->state;
  88   const char *var = 0;
  89   const char *id = 0;
  90   int i = 0, j = 0, nhints = 0;
  91   char **hints = NULL;
  92 
  93   if (state[SEARCH_HINT].set)
  94     for (i = 0; state[SEARCH_HINT].args[i]; i++)
  95       nhints++;
  96 
  97 #ifdef GRUB_MACHINE_IEEE1275
  98   if (state[SEARCH_HINT_IEEE1275].set)
  99     for (i = 0; state[SEARCH_HINT_IEEE1275].args[i]; i++)
 100       nhints++;
 101 #endif
 102 
 103 #ifdef GRUB_MACHINE_EFI
 104   if (state[SEARCH_HINT_EFI].set)
 105     for (i = 0; state[SEARCH_HINT_EFI].args[i]; i++)
 106       nhints++;
 107 #endif
 108 
 109 #ifdef GRUB_MACHINE_PCBIOS
 110   if (state[SEARCH_HINT_BIOS].set)
 111     for (i = 0; state[SEARCH_HINT_BIOS].args[i]; i++)
 112       nhints++;
 113 #endif
 114 
 115 #ifdef GRUB_MACHINE_ARC
 116   if (state[SEARCH_HINT_ARC].set)
 117     for (i = 0; state[SEARCH_HINT_ARC].args[i]; i++)
 118       nhints++;
 119 #endif
 120 
 121   if (state[SEARCH_HINT_BAREMETAL].set)
 122     for (i = 0; state[SEARCH_HINT_BAREMETAL].args[i]; i++)
 123       nhints++;
 124 
 125   hints = grub_malloc (sizeof (hints[0]) * nhints);
 126   if (!hints)
 127     return grub_errno;
 128   j = 0;
 129 
 130   if (state[SEARCH_HINT].set)
 131     for (i = 0; state[SEARCH_HINT].args[i]; i++)
 132       hints[j++] = state[SEARCH_HINT].args[i];
 133 
 134 #ifdef GRUB_MACHINE_IEEE1275
 135   if (state[SEARCH_HINT_IEEE1275].set)
 136     for (i = 0; state[SEARCH_HINT_IEEE1275].args[i]; i++)
 137       hints[j++] = state[SEARCH_HINT_IEEE1275].args[i];
 138 #endif
 139 
 140 #ifdef GRUB_MACHINE_EFI
 141   if (state[SEARCH_HINT_EFI].set)
 142     for (i = 0; state[SEARCH_HINT_EFI].args[i]; i++)
 143       hints[j++] = state[SEARCH_HINT_EFI].args[i];
 144 #endif
 145 
 146 #ifdef GRUB_MACHINE_ARC
 147   if (state[SEARCH_HINT_ARC].set)
 148     for (i = 0; state[SEARCH_HINT_ARC].args[i]; i++)
 149       hints[j++] = state[SEARCH_HINT_ARC].args[i];
 150 #endif
 151 
 152 #ifdef GRUB_MACHINE_PCBIOS
 153   if (state[SEARCH_HINT_BIOS].set)
 154     for (i = 0; state[SEARCH_HINT_BIOS].args[i]; i++)
 155       hints[j++] = state[SEARCH_HINT_BIOS].args[i];
 156 #endif
 157 
 158   if (state[SEARCH_HINT_BAREMETAL].set)
 159     for (i = 0; state[SEARCH_HINT_BAREMETAL].args[i]; i++)
 160       hints[j++] = state[SEARCH_HINT_BAREMETAL].args[i];
 161 
 162   /* Skip hints for future platforms.  */
 163   for (j = 0; j < argc; j++)
 164     if (grub_memcmp (args[j], "--hint-", sizeof ("--hint-") - 1) != 0)
 165       break;
 166 
 167   if (state[SEARCH_SET].set)
 168     var = state[SEARCH_SET].arg ? state[SEARCH_SET].arg : "root";
 169 
 170   if (argc != j)
 171     id = args[j];
 172   else if (state[SEARCH_SET].set && state[SEARCH_SET].arg)
 173     {
 174       id = state[SEARCH_SET].arg;
 175       var = "root";
 176     }
 177   else
 178     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
 179 
 180   if (state[SEARCH_LABEL].set)
 181     grub_search_label (id, var, state[SEARCH_NO_FLOPPY].set, 
 182                        hints, nhints);
 183   else if (state[SEARCH_FS_UUID].set)
 184     grub_search_fs_uuid (id, var, state[SEARCH_NO_FLOPPY].set,
 185                          hints, nhints);
 186   else if (state[SEARCH_FILE].set)
 187     grub_search_fs_file (id, var, state[SEARCH_NO_FLOPPY].set, 
 188                          hints, nhints);
 189   else
 190     return grub_error (GRUB_ERR_INVALID_COMMAND, "unspecified search type");
 191 
 192   return grub_errno;
 193 }
 194 
 195 static grub_extcmd_t cmd;
 196 
 197 GRUB_MOD_INIT(search)
 198 {
 199   cmd =
 200     grub_register_extcmd ("search", grub_cmd_search,
 201                           GRUB_COMMAND_FLAG_EXTRACTOR | GRUB_COMMAND_ACCEPT_DASH,
 202                           N_("[-f|-l|-u|-s|-n] [--hint HINT [--hint HINT] ...]"
 203                              " NAME"),
 204                           N_("Search devices by file, filesystem label"
 205                              " or filesystem UUID."
 206                              " If --set is specified, the first device found is"
 207                              " set to a variable. If no variable name is"
 208                              " specified, `root' is used."),
 209                           options);
 210 }
 211 
 212 GRUB_MOD_FINI(search)
 213 {
 214   grub_unregister_extcmd (cmd);
 215 }