getroot.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777
  1. /*
  2. * GRUB -- GRand Unified Bootloader
  3. * Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc.
  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. #include <config-util.h>
  19. #include <config.h>
  20. #include <sys/stat.h>
  21. #include <sys/types.h>
  22. #include <assert.h>
  23. #include <fcntl.h>
  24. #include <unistd.h>
  25. #include <string.h>
  26. #include <dirent.h>
  27. #include <errno.h>
  28. #include <error.h>
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <stdint.h>
  32. #ifdef HAVE_LIMITS_H
  33. #include <limits.h>
  34. #endif
  35. #include <grub/util/misc.h>
  36. #include <grub/emu/exec.h>
  37. #include <grub/cryptodisk.h>
  38. #include <grub/i18n.h>
  39. #if !defined (__MINGW32__) && !defined (__CYGWIN__) && !defined (__AROS__) && !defined (__HAIKU__)
  40. #ifdef __linux__
  41. #include <sys/ioctl.h> /* ioctl */
  42. #include <sys/mount.h>
  43. #ifndef FLOPPY_MAJOR
  44. # define FLOPPY_MAJOR 2
  45. #endif /* ! FLOPPY_MAJOR */
  46. #endif
  47. #include <sys/types.h>
  48. #if defined(MAJOR_IN_MKDEV)
  49. #include <sys/mkdev.h>
  50. #elif defined(MAJOR_IN_SYSMACROS)
  51. #include <sys/sysmacros.h>
  52. #endif
  53. #if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
  54. # include <grub/util/libzfs.h>
  55. # include <grub/util/libnvpair.h>
  56. #endif
  57. #include <grub/mm.h>
  58. #include <grub/misc.h>
  59. #include <grub/emu/misc.h>
  60. #include <grub/emu/hostdisk.h>
  61. #include <grub/emu/getroot.h>
  62. #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
  63. # define FLOPPY_MAJOR 2
  64. #endif
  65. #if defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
  66. #include <sys/mount.h>
  67. #endif
  68. #if defined(__NetBSD__) || defined(__OpenBSD__)
  69. # include <sys/ioctl.h>
  70. # include <sys/disklabel.h> /* struct disklabel */
  71. # include <sys/disk.h> /* struct dkwedge_info */
  72. #include <sys/param.h>
  73. #include <sys/mount.h>
  74. #endif /* defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) */
  75. #if defined(__NetBSD__) || defined(__OpenBSD__)
  76. # ifdef HAVE_GETRAWPARTITION
  77. # include <util.h> /* getrawpartition */
  78. # endif /* HAVE_GETRAWPARTITION */
  79. #if defined(__NetBSD__)
  80. # include <sys/fdio.h>
  81. #endif
  82. # ifndef FLOPPY_MAJOR
  83. # define FLOPPY_MAJOR 2
  84. # endif /* ! FLOPPY_MAJOR */
  85. # ifndef RAW_FLOPPY_MAJOR
  86. # define RAW_FLOPPY_MAJOR 9
  87. # endif /* ! RAW_FLOPPY_MAJOR */
  88. #endif /* defined(__NetBSD__) */
  89. #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
  90. #define LVM_DEV_MAPPER_STRING "/dev/linux_lvm/"
  91. #else
  92. #define LVM_DEV_MAPPER_STRING "/dev/mapper/"
  93. #endif
  94. #include <sys/types.h>
  95. #include <sys/wait.h>
  96. #if defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) && defined(HAVE_STRUCT_STATFS_F_MNTFROMNAME)
  97. #include <sys/param.h>
  98. #include <sys/mount.h>
  99. #endif
  100. #if !defined (__GNU__)
  101. static void
  102. strip_extra_slashes (char *dir)
  103. {
  104. char *p = dir;
  105. while ((p = strchr (p, '/')) != 0)
  106. {
  107. if (p[1] == '/')
  108. {
  109. memmove (p, p + 1, strlen (p));
  110. continue;
  111. }
  112. else if (p[1] == '\0')
  113. {
  114. if (p > dir)
  115. p[0] = '\0';
  116. break;
  117. }
  118. p++;
  119. }
  120. }
  121. static char *
  122. xgetcwd (void)
  123. {
  124. size_t size = 10;
  125. char *path;
  126. path = xmalloc (size);
  127. while (! getcwd (path, size))
  128. {
  129. size <<= 1;
  130. path = xrealloc (path, size);
  131. }
  132. return path;
  133. }
  134. char **
  135. grub_util_find_root_devices_from_poolname (char *poolname)
  136. {
  137. char **devices = 0;
  138. size_t ndevices = 0;
  139. size_t devices_allocated = 0;
  140. #if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
  141. zpool_handle_t *zpool;
  142. libzfs_handle_t *libzfs;
  143. nvlist_t *config, *vdev_tree;
  144. nvlist_t **children;
  145. unsigned int nvlist_count;
  146. unsigned int i;
  147. char *device = 0;
  148. libzfs = grub_get_libzfs_handle ();
  149. if (! libzfs)
  150. return NULL;
  151. zpool = zpool_open (libzfs, poolname);
  152. config = zpool_get_config (zpool, NULL);
  153. if (nvlist_lookup_nvlist (config, "vdev_tree", &vdev_tree) != 0)
  154. error (1, errno, "nvlist_lookup_nvlist (\"vdev_tree\")");
  155. if (nvlist_lookup_nvlist_array (vdev_tree, "children", &children, &nvlist_count) != 0)
  156. error (1, errno, "nvlist_lookup_nvlist_array (\"children\")");
  157. assert (nvlist_count > 0);
  158. while (nvlist_lookup_nvlist_array (children[0], "children",
  159. &children, &nvlist_count) == 0)
  160. assert (nvlist_count > 0);
  161. for (i = 0; i < nvlist_count; i++)
  162. {
  163. if (nvlist_lookup_string (children[i], "path", &device) != 0)
  164. error (1, errno, "nvlist_lookup_string (\"path\")");
  165. struct stat st;
  166. if (stat (device, &st) == 0)
  167. {
  168. #ifdef __sun__
  169. if (grub_memcmp (device, "/dev/dsk/", sizeof ("/dev/dsk/") - 1)
  170. == 0)
  171. device = xasprintf ("/dev/rdsk/%s",
  172. device + sizeof ("/dev/dsk/") - 1);
  173. else if (grub_memcmp (device, "/devices", sizeof ("/devices") - 1)
  174. == 0
  175. && grub_memcmp (device + strlen (device) - 4,
  176. ",raw", 4) != 0)
  177. device = xasprintf ("%s,raw", device);
  178. else
  179. #endif
  180. device = xstrdup (device);
  181. if (ndevices >= devices_allocated)
  182. {
  183. devices_allocated = 2 * (devices_allocated + 8);
  184. devices = xrealloc (devices, sizeof (devices[0])
  185. * devices_allocated);
  186. }
  187. devices[ndevices++] = device;
  188. }
  189. device = NULL;
  190. }
  191. zpool_close (zpool);
  192. #else
  193. FILE *fp;
  194. int ret;
  195. char *line;
  196. size_t len;
  197. int st;
  198. char name[PATH_MAX + 1], state[257], readlen[257], writelen[257];
  199. char cksum[257], notes[257];
  200. unsigned int dummy;
  201. const char *argv[4];
  202. pid_t pid;
  203. int fd;
  204. argv[0] = "zpool";
  205. argv[1] = "status";
  206. argv[2] = poolname;
  207. argv[3] = NULL;
  208. pid = grub_util_exec_pipe (argv, &fd);
  209. if (!pid)
  210. return NULL;
  211. fp = fdopen (fd, "r");
  212. if (!fp)
  213. {
  214. grub_util_warn (_("Unable to open stream from %s: %s"),
  215. "zpool", strerror (errno));
  216. goto out;
  217. }
  218. st = 0;
  219. while (1)
  220. {
  221. line = NULL;
  222. ret = getline (&line, &len, fp);
  223. if (ret == -1)
  224. break;
  225. if (sscanf (line, " %s %256s %256s %256s %256s %256s",
  226. name, state, readlen, writelen, cksum, notes) >= 5)
  227. switch (st)
  228. {
  229. case 0:
  230. if (!strcmp (name, "NAME")
  231. && !strcmp (state, "STATE")
  232. && !strcmp (readlen, "READ")
  233. && !strcmp (writelen, "WRITE")
  234. && !strcmp (cksum, "CKSUM"))
  235. st++;
  236. break;
  237. case 1:
  238. {
  239. char *ptr = line;
  240. while (1)
  241. {
  242. if (strncmp (ptr, poolname, strlen (poolname)) == 0
  243. && grub_isspace(ptr[strlen (poolname)]))
  244. st++;
  245. if (!grub_isspace (*ptr))
  246. break;
  247. ptr++;
  248. }
  249. }
  250. break;
  251. case 2:
  252. if (strcmp (name, "mirror") && !sscanf (name, "mirror-%u", &dummy)
  253. && !sscanf (name, "raidz%u", &dummy)
  254. && !sscanf (name, "raidz1%u", &dummy)
  255. && !sscanf (name, "raidz2%u", &dummy)
  256. && !sscanf (name, "raidz3%u", &dummy)
  257. && !strcmp (state, "ONLINE"))
  258. {
  259. if (ndevices >= devices_allocated)
  260. {
  261. devices_allocated = 2 * (devices_allocated + 8);
  262. devices = xrealloc (devices, sizeof (devices[0])
  263. * devices_allocated);
  264. }
  265. if (name[0] == '/')
  266. devices[ndevices++] = xstrdup (name);
  267. else
  268. devices[ndevices++] = xasprintf ("/dev/%s", name);
  269. }
  270. break;
  271. }
  272. free (line);
  273. }
  274. out:
  275. close (fd);
  276. waitpid (pid, NULL, 0);
  277. #endif
  278. if (devices)
  279. {
  280. if (ndevices >= devices_allocated)
  281. {
  282. devices_allocated = 2 * (devices_allocated + 8);
  283. devices = xrealloc (devices, sizeof (devices[0])
  284. * devices_allocated);
  285. }
  286. devices[ndevices++] = 0;
  287. }
  288. return devices;
  289. }
  290. static char **
  291. find_root_devices_from_libzfs (const char *dir)
  292. {
  293. char **devices = NULL;
  294. char *poolname;
  295. char *poolfs;
  296. grub_find_zpool_from_dir (dir, &poolname, &poolfs);
  297. if (! poolname)
  298. return NULL;
  299. devices = grub_util_find_root_devices_from_poolname (poolname);
  300. free (poolname);
  301. if (poolfs)
  302. free (poolfs);
  303. return devices;
  304. }
  305. char *
  306. grub_find_device (const char *dir, dev_t dev)
  307. {
  308. DIR *dp;
  309. char *saved_cwd;
  310. struct dirent *ent;
  311. if (! dir)
  312. dir = "/dev";
  313. dp = opendir (dir);
  314. if (! dp)
  315. return 0;
  316. saved_cwd = xgetcwd ();
  317. grub_util_info ("changing current directory to %s", dir);
  318. if (chdir (dir) < 0)
  319. {
  320. free (saved_cwd);
  321. closedir (dp);
  322. return 0;
  323. }
  324. while ((ent = readdir (dp)) != 0)
  325. {
  326. struct stat st;
  327. /* Avoid:
  328. - dotfiles (like "/dev/.tmp.md0") since they could be duplicates.
  329. - dotdirs (like "/dev/.static") since they could contain duplicates. */
  330. if (ent->d_name[0] == '.')
  331. continue;
  332. if (lstat (ent->d_name, &st) < 0)
  333. /* Ignore any error. */
  334. continue;
  335. if (S_ISLNK (st.st_mode)) {
  336. #ifdef __linux__
  337. if (strcmp (dir, "mapper") == 0 || strcmp (dir, "/dev/mapper") == 0) {
  338. /* Follow symbolic links under /dev/mapper/; the canonical name
  339. may be something like /dev/dm-0, but the names under
  340. /dev/mapper/ are more human-readable and so we prefer them if
  341. we can get them. */
  342. if (stat (ent->d_name, &st) < 0)
  343. continue;
  344. } else
  345. #endif /* __linux__ */
  346. /* Don't follow other symbolic links. */
  347. continue;
  348. }
  349. if (S_ISDIR (st.st_mode))
  350. {
  351. /* Find it recursively. */
  352. char *res;
  353. res = grub_find_device (ent->d_name, dev);
  354. if (res)
  355. {
  356. if (chdir (saved_cwd) < 0)
  357. grub_util_error ("%s",
  358. _("cannot restore the original directory"));
  359. free (saved_cwd);
  360. closedir (dp);
  361. return res;
  362. }
  363. }
  364. #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
  365. if (S_ISCHR (st.st_mode) && st.st_rdev == dev)
  366. #else
  367. if (S_ISBLK (st.st_mode) && st.st_rdev == dev)
  368. #endif
  369. {
  370. #ifdef __linux__
  371. /* Skip device names like /dev/dm-0, which are short-hand aliases
  372. to more descriptive device names, e.g. those under /dev/mapper */
  373. if (ent->d_name[0] == 'd' &&
  374. ent->d_name[1] == 'm' &&
  375. ent->d_name[2] == '-' &&
  376. ent->d_name[3] >= '0' &&
  377. ent->d_name[3] <= '9')
  378. continue;
  379. #endif
  380. /* Found! */
  381. char *res;
  382. char *cwd;
  383. cwd = xgetcwd ();
  384. res = xmalloc (strlen (cwd) + strlen (ent->d_name) + 3);
  385. sprintf (res,
  386. #if defined(__NetBSD__) || defined(__OpenBSD__)
  387. /* Convert this block device to its character (raw) device. */
  388. "%s/r%s",
  389. #else
  390. /* Keep the device name as it is. */
  391. "%s/%s",
  392. #endif
  393. cwd, ent->d_name);
  394. strip_extra_slashes (res);
  395. free (cwd);
  396. /* /dev/root is not a real block device keep looking, takes care
  397. of situation where root filesystem is on the same partition as
  398. grub files */
  399. if (strcmp(res, "/dev/root") == 0)
  400. {
  401. free (res);
  402. continue;
  403. }
  404. if (chdir (saved_cwd) < 0)
  405. grub_util_error ("%s", _("cannot restore the original directory"));
  406. free (saved_cwd);
  407. closedir (dp);
  408. return res;
  409. }
  410. }
  411. if (chdir (saved_cwd) < 0)
  412. grub_util_error ("%s", _("cannot restore the original directory"));
  413. free (saved_cwd);
  414. closedir (dp);
  415. return 0;
  416. }
  417. char **
  418. grub_guess_root_devices (const char *dir_in)
  419. {
  420. char **os_dev = NULL;
  421. struct stat st;
  422. dev_t dev;
  423. char *dir = grub_canonicalize_file_name (dir_in);
  424. if (!dir)
  425. grub_util_error (_("failed to get canonical path of `%s'"), dir_in);
  426. #ifdef __linux__
  427. if (!os_dev)
  428. os_dev = grub_find_root_devices_from_mountinfo (dir, NULL);
  429. #endif /* __linux__ */
  430. if (!os_dev)
  431. os_dev = find_root_devices_from_libzfs (dir);
  432. if (os_dev)
  433. {
  434. char **cur;
  435. for (cur = os_dev; *cur; cur++)
  436. {
  437. char *tmp = *cur;
  438. int root, dm;
  439. if (strcmp (*cur, "/dev/root") == 0
  440. || strncmp (*cur, "/dev/dm-", sizeof ("/dev/dm-") - 1) == 0)
  441. *cur = tmp;
  442. else
  443. {
  444. *cur = grub_canonicalize_file_name (tmp);
  445. if (*cur == NULL)
  446. grub_util_error (_("failed to get canonical path of `%s'"), tmp);
  447. free (tmp);
  448. }
  449. root = (strcmp (*cur, "/dev/root") == 0);
  450. dm = (strncmp (*cur, "/dev/dm-", sizeof ("/dev/dm-") - 1) == 0);
  451. if (!dm && !root)
  452. continue;
  453. if (stat (*cur, &st) < 0)
  454. break;
  455. free (*cur);
  456. dev = st.st_rdev;
  457. *cur = grub_find_device (dm ? "/dev/mapper" : "/dev", dev);
  458. }
  459. if (!*cur)
  460. return os_dev;
  461. for (cur = os_dev; *cur; cur++)
  462. free (*cur);
  463. free (os_dev);
  464. os_dev = 0;
  465. }
  466. if (stat (dir, &st) < 0)
  467. grub_util_error (_("cannot stat `%s': %s"), dir, strerror (errno));
  468. free (dir);
  469. dev = st.st_dev;
  470. os_dev = xmalloc (2 * sizeof (os_dev[0]));
  471. /* This might be truly slow, but is there any better way? */
  472. os_dev[0] = grub_find_device ("/dev", dev);
  473. if (!os_dev[0])
  474. {
  475. free (os_dev);
  476. return 0;
  477. }
  478. os_dev[1] = 0;
  479. return os_dev;
  480. }
  481. #endif
  482. void
  483. grub_util_pull_lvm_by_command (const char *os_dev)
  484. {
  485. const char *argv[8];
  486. int fd;
  487. pid_t pid;
  488. FILE *vgs;
  489. char *buf = NULL;
  490. size_t len = 0;
  491. char *vgname = NULL;
  492. const char *iptr;
  493. char *optr;
  494. char *vgid = NULL;
  495. grub_size_t vgidlen = 0;
  496. vgid = grub_util_get_vg_uuid (os_dev);
  497. if (vgid)
  498. vgidlen = grub_strlen (vgid);
  499. if (!vgid)
  500. {
  501. if (strncmp (os_dev, LVM_DEV_MAPPER_STRING,
  502. sizeof (LVM_DEV_MAPPER_STRING) - 1)
  503. != 0)
  504. return;
  505. vgname = xmalloc (strlen (os_dev + sizeof (LVM_DEV_MAPPER_STRING) - 1) + 1);
  506. for (iptr = os_dev + sizeof (LVM_DEV_MAPPER_STRING) - 1, optr = vgname; *iptr; )
  507. if (*iptr != '-')
  508. *optr++ = *iptr++;
  509. else if (iptr[0] == '-' && iptr[1] == '-')
  510. {
  511. iptr += 2;
  512. *optr++ = '-';
  513. }
  514. else
  515. break;
  516. *optr = '\0';
  517. }
  518. /* by default PV name is left aligned in 10 character field, meaning that
  519. we do not know where name ends. Using dummy --separator disables
  520. alignment. We have a single field, so separator itself is not output */
  521. argv[0] = "vgs";
  522. argv[1] = "--options";
  523. if (vgid)
  524. argv[2] = "vg_uuid,pv_name";
  525. else
  526. argv[2] = "pv_name";
  527. argv[3] = "--noheadings";
  528. argv[4] = "--separator";
  529. argv[5] = ":";
  530. argv[6] = vgname;
  531. argv[7] = NULL;
  532. pid = grub_util_exec_pipe (argv, &fd);
  533. free (vgname);
  534. if (!pid)
  535. {
  536. free (vgid);
  537. return;
  538. }
  539. /* Parent. Read vgs' output. */
  540. vgs = fdopen (fd, "r");
  541. if (! vgs)
  542. {
  543. grub_util_warn (_("Unable to open stream from %s: %s"),
  544. "vgs", strerror (errno));
  545. goto out;
  546. }
  547. while (getline (&buf, &len, vgs) > 0)
  548. {
  549. char *ptr;
  550. /* LVM adds two spaces as standard prefix */
  551. for (ptr = buf; ptr < buf + 2 && *ptr == ' '; ptr++);
  552. if (vgid && (grub_strncmp (vgid, ptr, vgidlen) != 0
  553. || ptr[vgidlen] != ':'))
  554. continue;
  555. if (vgid)
  556. ptr += vgidlen + 1;
  557. if (*ptr == '\0')
  558. continue;
  559. *(ptr + strlen (ptr) - 1) = '\0';
  560. grub_util_pull_device (ptr);
  561. }
  562. out:
  563. close (fd);
  564. waitpid (pid, NULL, 0);
  565. free (buf);
  566. free (vgid);
  567. }
  568. /* ZFS has similar problems to those of btrfs (see above). */
  569. void
  570. grub_find_zpool_from_dir (const char *dir, char **poolname, char **poolfs)
  571. {
  572. char *slash;
  573. *poolname = *poolfs = NULL;
  574. #if defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) && defined(HAVE_STRUCT_STATFS_F_MNTFROMNAME)
  575. /* FreeBSD and GNU/kFreeBSD. */
  576. {
  577. struct statfs mnt;
  578. if (statfs (dir, &mnt) != 0)
  579. return;
  580. if (strcmp (mnt.f_fstypename, "zfs") != 0)
  581. return;
  582. *poolname = xstrdup (mnt.f_mntfromname);
  583. }
  584. #elif defined(HAVE_GETEXTMNTENT)
  585. /* Solaris. */
  586. {
  587. struct stat st;
  588. struct extmnttab mnt;
  589. if (stat (dir, &st) != 0)
  590. return;
  591. FILE *mnttab = grub_util_fopen ("/etc/mnttab", "r");
  592. if (! mnttab)
  593. return;
  594. while (getextmntent (mnttab, &mnt, sizeof (mnt)) == 0)
  595. {
  596. if (makedev (mnt.mnt_major, mnt.mnt_minor) == st.st_dev
  597. && !strcmp (mnt.mnt_fstype, "zfs"))
  598. {
  599. *poolname = xstrdup (mnt.mnt_special);
  600. break;
  601. }
  602. }
  603. fclose (mnttab);
  604. }
  605. #endif
  606. if (! *poolname)
  607. return;
  608. slash = strchr (*poolname, '/');
  609. if (slash)
  610. {
  611. *slash = '\0';
  612. *poolfs = xstrdup (slash + 1);
  613. }
  614. else
  615. *poolfs = xstrdup ("");
  616. }
  617. int
  618. grub_util_biosdisk_is_floppy (grub_disk_t disk)
  619. {
  620. struct stat st;
  621. int fd;
  622. const char *dname;
  623. dname = grub_util_biosdisk_get_osdev (disk);
  624. if (!dname)
  625. return 0;
  626. fd = open (dname, O_RDONLY);
  627. /* Shouldn't happen. */
  628. if (fd == -1)
  629. return 0;
  630. /* Shouldn't happen either. */
  631. if (fstat (fd, &st) < 0)
  632. {
  633. close (fd);
  634. return 0;
  635. }
  636. close (fd);
  637. #if defined(__NetBSD__)
  638. if (major(st.st_rdev) == RAW_FLOPPY_MAJOR)
  639. return 1;
  640. #endif
  641. #if defined(FLOPPY_MAJOR)
  642. if (major(st.st_rdev) == FLOPPY_MAJOR)
  643. #else
  644. /* Some kernels (e.g. kFreeBSD) don't have a static major number
  645. for floppies, but they still use a "fd[0-9]" pathname. */
  646. if (dname[5] == 'f'
  647. && dname[6] == 'd'
  648. && dname[7] >= '0'
  649. && dname[7] <= '9')
  650. #endif
  651. return 1;
  652. return 0;
  653. }
  654. #else
  655. #include <grub/emu/getroot.h>
  656. void
  657. grub_util_pull_lvm_by_command (const char *os_dev __attribute__ ((unused)))
  658. {
  659. }
  660. #endif