bsdlabel.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. /* bsdlabel.c - Read BSD style partition tables. */
  2. /*
  3. * GRUB -- GRand Unified Bootloader
  4. * Copyright (C) 2002,2004,2005,2006,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. #include <grub/partition.h>
  20. #include <grub/bsdlabel.h>
  21. #include <grub/disk.h>
  22. #include <grub/mm.h>
  23. #include <grub/misc.h>
  24. #include <grub/dl.h>
  25. #include <grub/msdos_partition.h>
  26. #include <grub/i18n.h>
  27. GRUB_MOD_LICENSE ("GPLv3+");
  28. #ifdef GRUB_UTIL
  29. #include <grub/emu/misc.h>
  30. #endif
  31. static struct grub_partition_map grub_bsdlabel_partition_map;
  32. static struct grub_partition_map grub_netbsdlabel_partition_map;
  33. static struct grub_partition_map grub_openbsdlabel_partition_map;
  34. static grub_err_t
  35. iterate_real (grub_disk_t disk, grub_disk_addr_t sector, int freebsd,
  36. struct grub_partition_map *pmap,
  37. grub_partition_iterate_hook_t hook, void *hook_data)
  38. {
  39. struct grub_partition_bsd_disk_label label;
  40. struct grub_partition p;
  41. grub_disk_addr_t delta = 0;
  42. grub_disk_addr_t pos;
  43. /* Read the BSD label. */
  44. if (grub_disk_read (disk, sector, 0, sizeof (label), &label))
  45. return grub_errno;
  46. /* Check if it is valid. */
  47. if (label.magic != grub_cpu_to_le32_compile_time (GRUB_PC_PARTITION_BSD_LABEL_MAGIC))
  48. return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");
  49. /* A kludge to determine a base of be.offset. */
  50. if (GRUB_PC_PARTITION_BSD_LABEL_WHOLE_DISK_PARTITION
  51. < grub_cpu_to_le16 (label.num_partitions) && freebsd)
  52. {
  53. struct grub_partition_bsd_entry whole_disk_be;
  54. pos = sizeof (label) + sector * GRUB_DISK_SECTOR_SIZE
  55. + sizeof (struct grub_partition_bsd_entry)
  56. * GRUB_PC_PARTITION_BSD_LABEL_WHOLE_DISK_PARTITION;
  57. if (grub_disk_read (disk, pos / GRUB_DISK_SECTOR_SIZE,
  58. pos % GRUB_DISK_SECTOR_SIZE, sizeof (whole_disk_be),
  59. &whole_disk_be))
  60. return grub_errno;
  61. delta = grub_le_to_cpu32 (whole_disk_be.offset);
  62. }
  63. pos = sizeof (label) + sector * GRUB_DISK_SECTOR_SIZE;
  64. for (p.number = 0;
  65. p.number < grub_cpu_to_le16 (label.num_partitions);
  66. p.number++, pos += sizeof (struct grub_partition_bsd_entry))
  67. {
  68. struct grub_partition_bsd_entry be;
  69. if (p.number == GRUB_PC_PARTITION_BSD_LABEL_WHOLE_DISK_PARTITION)
  70. continue;
  71. p.offset = pos / GRUB_DISK_SECTOR_SIZE;
  72. p.index = pos % GRUB_DISK_SECTOR_SIZE;
  73. if (grub_disk_read (disk, p.offset, p.index, sizeof (be), &be))
  74. return grub_errno;
  75. p.start = grub_le_to_cpu32 (be.offset);
  76. p.len = grub_le_to_cpu32 (be.size);
  77. p.partmap = pmap;
  78. if (p.len == 0)
  79. continue;
  80. if (p.start < delta)
  81. {
  82. #ifdef GRUB_UTIL
  83. char *partname;
  84. /* disk->partition != NULL as 0 < delta */
  85. partname = disk->partition ? grub_partition_get_name (disk->partition)
  86. : 0;
  87. grub_util_warn (_("Discarding improperly nested partition (%s,%s,%s%d)"),
  88. disk->name, partname ? : "", p.partmap->name,
  89. p.number + 1);
  90. grub_free (partname);
  91. #endif
  92. continue;
  93. }
  94. p.start -= delta;
  95. if (hook (disk, &p, hook_data))
  96. return grub_errno;
  97. }
  98. return GRUB_ERR_NONE;
  99. }
  100. static grub_err_t
  101. bsdlabel_partition_map_iterate (grub_disk_t disk,
  102. grub_partition_iterate_hook_t hook,
  103. void *hook_data)
  104. {
  105. if (disk->partition && grub_strcmp (disk->partition->partmap->name, "msdos")
  106. == 0 && disk->partition->msdostype == GRUB_PC_PARTITION_TYPE_FREEBSD)
  107. return iterate_real (disk, GRUB_PC_PARTITION_BSD_LABEL_SECTOR, 1,
  108. &grub_bsdlabel_partition_map, hook, hook_data);
  109. if (disk->partition
  110. && (grub_strcmp (disk->partition->partmap->name, "msdos") == 0
  111. || disk->partition->partmap == &grub_bsdlabel_partition_map
  112. || disk->partition->partmap == &grub_netbsdlabel_partition_map
  113. || disk->partition->partmap == &grub_openbsdlabel_partition_map))
  114. return grub_error (GRUB_ERR_BAD_PART_TABLE, "no embedding supported");
  115. return iterate_real (disk, GRUB_PC_PARTITION_BSD_LABEL_SECTOR, 0,
  116. &grub_bsdlabel_partition_map, hook, hook_data);
  117. }
  118. /* Context for netopenbsdlabel_partition_map_iterate. */
  119. struct netopenbsdlabel_ctx
  120. {
  121. grub_uint8_t type;
  122. struct grub_partition_map *pmap;
  123. grub_partition_iterate_hook_t hook;
  124. void *hook_data;
  125. int count;
  126. };
  127. /* Helper for netopenbsdlabel_partition_map_iterate. */
  128. static int
  129. check_msdos (grub_disk_t dsk, const grub_partition_t partition, void *data)
  130. {
  131. struct netopenbsdlabel_ctx *ctx = data;
  132. grub_err_t err;
  133. if (partition->msdostype != ctx->type)
  134. return 0;
  135. err = iterate_real (dsk, partition->start
  136. + GRUB_PC_PARTITION_BSD_LABEL_SECTOR, 0, ctx->pmap,
  137. ctx->hook, ctx->hook_data);
  138. if (err == GRUB_ERR_NONE)
  139. {
  140. ctx->count++;
  141. return 1;
  142. }
  143. if (err == GRUB_ERR_BAD_PART_TABLE)
  144. {
  145. grub_errno = GRUB_ERR_NONE;
  146. return 0;
  147. }
  148. grub_print_error ();
  149. return 0;
  150. }
  151. /* This is a total breakage. Even when net-/openbsd label is inside partition
  152. it actually describes the whole disk.
  153. */
  154. static grub_err_t
  155. netopenbsdlabel_partition_map_iterate (grub_disk_t disk, grub_uint8_t type,
  156. struct grub_partition_map *pmap,
  157. grub_partition_iterate_hook_t hook,
  158. void *hook_data)
  159. {
  160. if (disk->partition && grub_strcmp (disk->partition->partmap->name, "msdos")
  161. == 0)
  162. return grub_error (GRUB_ERR_BAD_PART_TABLE, "no embedding supported");
  163. {
  164. struct netopenbsdlabel_ctx ctx = {
  165. .type = type,
  166. .pmap = pmap,
  167. .hook = hook,
  168. .hook_data = hook_data,
  169. .count = 0
  170. };
  171. grub_err_t err;
  172. err = grub_partition_msdos_iterate (disk, check_msdos, &ctx);
  173. if (err)
  174. return err;
  175. if (!ctx.count)
  176. return grub_error (GRUB_ERR_BAD_PART_TABLE, "no bsdlabel found");
  177. }
  178. return GRUB_ERR_NONE;
  179. }
  180. static grub_err_t
  181. netbsdlabel_partition_map_iterate (grub_disk_t disk,
  182. grub_partition_iterate_hook_t hook,
  183. void *hook_data)
  184. {
  185. return netopenbsdlabel_partition_map_iterate (disk,
  186. GRUB_PC_PARTITION_TYPE_NETBSD,
  187. &grub_netbsdlabel_partition_map,
  188. hook, hook_data);
  189. }
  190. static grub_err_t
  191. openbsdlabel_partition_map_iterate (grub_disk_t disk,
  192. grub_partition_iterate_hook_t hook,
  193. void *hook_data)
  194. {
  195. return netopenbsdlabel_partition_map_iterate (disk,
  196. GRUB_PC_PARTITION_TYPE_OPENBSD,
  197. &grub_openbsdlabel_partition_map,
  198. hook, hook_data);
  199. }
  200. static struct grub_partition_map grub_bsdlabel_partition_map =
  201. {
  202. .name = "bsd",
  203. .iterate = bsdlabel_partition_map_iterate,
  204. };
  205. static struct grub_partition_map grub_openbsdlabel_partition_map =
  206. {
  207. .name = "openbsd",
  208. .iterate = openbsdlabel_partition_map_iterate,
  209. };
  210. static struct grub_partition_map grub_netbsdlabel_partition_map =
  211. {
  212. .name = "netbsd",
  213. .iterate = netbsdlabel_partition_map_iterate,
  214. };
  215. GRUB_MOD_INIT(part_bsd)
  216. {
  217. grub_partition_map_register (&grub_bsdlabel_partition_map);
  218. grub_partition_map_register (&grub_netbsdlabel_partition_map);
  219. grub_partition_map_register (&grub_openbsdlabel_partition_map);
  220. }
  221. GRUB_MOD_FINI(part_bsd)
  222. {
  223. grub_partition_map_unregister (&grub_bsdlabel_partition_map);
  224. grub_partition_map_unregister (&grub_netbsdlabel_partition_map);
  225. grub_partition_map_unregister (&grub_openbsdlabel_partition_map);
  226. }