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/device.h> 26 #include <grub/file.h> 27 #include <grub/env.h> 28 #include <grub/command.h> 29 #include <grub/search.h> 30 #include <grub/i18n.h> 31 #include <grub/disk.h> 32 #include <grub/partition.h> 33 34 GRUB_MOD_LICENSE ("GPLv3+"); 35 36 struct cache_entry 37 { 38 struct cache_entry *next; 39 char *key; 40 char *value; 41 }; 42 43 static struct cache_entry *cache; 44 45 void 46 FUNC_NAME (const char *key, const char *var, int no_floppy, 47 char **hints, unsigned nhints) 48 { 49 int count = 0; 50 int is_cache = 0; 51 grub_fs_autoload_hook_t saved_autoload; 52 53 auto int iterate_device (const char *name); 54 int iterate_device (const char *name) 55 { 56 int found = 0; 57 58 /* Skip floppy drives when requested. */ 59 if (no_floppy && 60 name[0] == 'f' && name[1] == 'd' && name[2] >= '0' && name[2] <= '9') 61 return 0; 62 63 #ifdef DO_SEARCH_FS_UUID 64 #define compare_fn grub_strcasecmp 65 #else 66 #define compare_fn grub_strcmp 67 #endif 68 69 #ifdef DO_SEARCH_FILE 70 { 71 char *buf; 72 grub_file_t file; 73 74 buf = grub_xasprintf ("(%s)%s", name, key); 75 if (! buf) 76 return 1; 77 78 grub_file_filter_disable_compression (); 79 file = grub_file_open (buf); 80 if (file) 81 { 82 found = 1; 83 grub_file_close (file); 84 } 85 grub_free (buf); 86 } 87 #else 88 { 89 /* SEARCH_FS_UUID or SEARCH_LABEL */ 90 grub_device_t dev; 91 grub_fs_t fs; 92 char *quid; 93 94 dev = grub_device_open (name); 95 if (dev) 96 { 97 fs = grub_fs_probe (dev); 98 99 #ifdef DO_SEARCH_FS_UUID 100 #define read_fn uuid 101 #else 102 #define read_fn label 103 #endif 104 105 if (fs && fs->read_fn) 106 { 107 fs->read_fn (dev, &quid); 108 109 if (grub_errno == GRUB_ERR_NONE && quid) 110 { 111 if (compare_fn (quid, key) == 0) 112 found = 1; 113 114 grub_free (quid); 115 } 116 } 117 118 grub_device_close (dev); 119 } 120 } 121 #endif 122 123 if (!is_cache && found && count == 0) 124 { 125 struct cache_entry *cache_ent; 126 cache_ent = grub_malloc (sizeof (*cache_ent)); 127 if (cache_ent) 128 { 129 cache_ent->key = grub_strdup (key); 130 cache_ent->value = grub_strdup (name); 131 if (cache_ent->value && cache_ent->key) 132 { 133 cache_ent->next = cache; 134 cache = cache_ent; 135 } 136 else 137 { 138 grub_free (cache_ent->value); 139 grub_free (cache_ent->key); 140 grub_free (cache_ent); 141 grub_errno = GRUB_ERR_NONE; 142 } 143 } 144 else 145 grub_errno = GRUB_ERR_NONE; 146 } 147 148 if (found) 149 { 150 count++; 151 if (var) 152 grub_env_set (var, name); 153 else 154 grub_printf (" %s", name); 155 } 156 157 grub_errno = GRUB_ERR_NONE; 158 return (found && var); 159 } 160 161 auto int part_hook (grub_disk_t disk, const grub_partition_t partition); 162 int part_hook (grub_disk_t disk, const grub_partition_t partition) 163 { 164 char *partition_name, *devname; 165 int ret; 166 167 partition_name = grub_partition_get_name (partition); 168 if (! partition_name) 169 return 1; 170 171 devname = grub_xasprintf ("%s,%s", disk->name, partition_name); 172 grub_free (partition_name); 173 if (!devname) 174 return 1; 175 ret = iterate_device (devname); 176 grub_free (devname); 177 178 return ret; 179 } 180 181 auto void try (void); 182 void try (void) 183 { 184 unsigned i; 185 struct cache_entry **prev; 186 struct cache_entry *cache_ent; 187 188 for (prev = &cache, cache_ent = *prev; cache_ent; 189 prev = &cache_ent->next, cache_ent = *prev) 190 if (compare_fn (cache_ent->key, key) == 0) 191 break; 192 if (cache_ent) 193 { 194 is_cache = 1; 195 if (iterate_device (cache_ent->value)) 196 { 197 is_cache = 0; 198 return; 199 } 200 is_cache = 0; 201 /* Cache entry was outdated. Remove it. */ 202 if (!count) 203 { 204 grub_free (cache_ent->key); 205 grub_free (cache_ent->value); 206 grub_free (cache_ent); 207 *prev = cache_ent->next; 208 } 209 } 210 211 for (i = 0; i < nhints; i++) 212 { 213 char *end; 214 if (!hints[i][0]) 215 continue; 216 end = hints[i] + grub_strlen (hints[i]) - 1; 217 if (*end == ',') 218 *end = 0; 219 if (iterate_device (hints[i])) 220 { 221 if (!*end) 222 *end = ','; 223 return; 224 } 225 if (!*end) 226 { 227 grub_device_t dev; 228 int ret; 229 dev = grub_device_open (hints[i]); 230 if (!dev) 231 { 232 if (!*end) 233 *end = ','; 234 continue; 235 } 236 if (!dev->disk) 237 { 238 grub_device_close (dev); 239 if (!*end) 240 *end = ','; 241 continue; 242 } 243 ret = grub_partition_iterate (dev->disk, part_hook); 244 if (!*end) 245 *end = ','; 246 grub_device_close (dev); 247 if (ret) 248 return; 249 } 250 } 251 grub_device_iterate (iterate_device); 252 } 253 254 /* First try without autoloading if we're setting variable. */ 255 if (var) 256 { 257 saved_autoload = grub_fs_autoload_hook; 258 grub_fs_autoload_hook = 0; 259 try (); 260 261 /* Restore autoload hook. */ 262 grub_fs_autoload_hook = saved_autoload; 263 264 /* Retry with autoload if nothing found. */ 265 if (grub_errno == GRUB_ERR_NONE && count == 0) 266 try (); 267 } 268 else 269 try (); 270 271 if (grub_errno == GRUB_ERR_NONE && count == 0) 272 grub_error (GRUB_ERR_FILE_NOT_FOUND, "no such device: %s", key); 273 } 274 275 static grub_err_t 276 grub_cmd_do_search (grub_command_t cmd __attribute__ ((unused)), int argc, 277 char **args) 278 { 279 if (argc == 0) 280 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); 281 282 FUNC_NAME (args[0], argc == 1 ? 0 : args[1], 0, (args + 2), 283 argc > 2 ? argc - 2 : 0); 284 285 return grub_errno; 286 } 287 288 static grub_command_t cmd; 289 290 #ifdef DO_SEARCH_FILE 291 GRUB_MOD_INIT(search_fs_file) 292 #elif defined (DO_SEARCH_FS_UUID) 293 GRUB_MOD_INIT(search_fs_uuid) 294 #else 295 GRUB_MOD_INIT(search_label) 296 #endif 297 { 298 cmd = 299 grub_register_command (COMMAND_NAME, grub_cmd_do_search, 300 N_("NAME [VARIABLE] [HINTS]"), 301 HELP_MESSAGE); 302 } 303 304 #ifdef DO_SEARCH_FILE 305 GRUB_MOD_FINI(search_fs_file) 306 #elif defined (DO_SEARCH_FS_UUID) 307 GRUB_MOD_FINI(search_fs_uuid) 308 #else 309 GRUB_MOD_FINI(search_label) 310 #endif 311 { 312 grub_unregister_command (cmd); 313 }