gptsync.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. /* gptsync.c - fill the mbr based on gpt entries */
  2. /* XXX: I don't know what to do if sector size isn't 512 bytes */
  3. /*
  4. * GRUB -- GRand Unified Bootloader
  5. * Copyright (C) 2009 Free Software Foundation, Inc.
  6. *
  7. * GRUB is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * GRUB is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include <grub/command.h>
  21. #include <grub/dl.h>
  22. #include <grub/device.h>
  23. #include <grub/disk.h>
  24. #include <grub/msdos_partition.h>
  25. #include <grub/partition.h>
  26. #include <grub/misc.h>
  27. #include <grub/mm.h>
  28. #include <grub/fs.h>
  29. #include <grub/i18n.h>
  30. GRUB_MOD_LICENSE ("GPLv3+");
  31. /* Convert a LBA address to a CHS address in the INT 13 format. */
  32. /* Taken from grub1. */
  33. /* XXX: use hardcoded geometry of C = 1024, H = 255, S = 63.
  34. Is it a problem?
  35. */
  36. static void
  37. lba_to_chs (grub_uint32_t lba, grub_uint8_t *cl, grub_uint8_t *ch,
  38. grub_uint8_t *dh)
  39. {
  40. grub_uint32_t cylinder, head, sector;
  41. grub_uint32_t sectors = 63, heads = 255, cylinders = 1024;
  42. sector = lba % sectors + 1;
  43. head = (lba / sectors) % heads;
  44. cylinder = lba / (sectors * heads);
  45. if (cylinder >= cylinders)
  46. {
  47. *cl = *ch = *dh = 0xff;
  48. return;
  49. }
  50. *cl = sector | ((cylinder & 0x300) >> 2);
  51. *ch = cylinder & 0xFF;
  52. *dh = head;
  53. }
  54. static grub_err_t
  55. grub_cmd_gptsync (grub_command_t cmd __attribute__ ((unused)),
  56. int argc, char **args)
  57. {
  58. grub_device_t dev;
  59. struct grub_msdos_partition_mbr mbr;
  60. struct grub_partition *partition;
  61. grub_disk_addr_t first_sector;
  62. int numactive = 0;
  63. int i;
  64. if (argc < 1)
  65. return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
  66. if (argc > 4)
  67. return grub_error (GRUB_ERR_BAD_ARGUMENT, "only 3 partitions can be "
  68. "in hybrid MBR");
  69. if (args[0][0] == '(' && args[0][grub_strlen (args[0]) - 1] == ')')
  70. {
  71. args[0][grub_strlen (args[0]) - 1] = 0;
  72. dev = grub_device_open (args[0] + 1);
  73. args[0][grub_strlen (args[0])] = ')';
  74. }
  75. else
  76. dev = grub_device_open (args[0]);
  77. if (! dev)
  78. return grub_errno;
  79. if (! dev->disk)
  80. {
  81. grub_device_close (dev);
  82. return grub_error (GRUB_ERR_BAD_ARGUMENT, "not a disk");
  83. }
  84. /* Read the protective MBR. */
  85. if (grub_disk_read (dev->disk, 0, 0, sizeof (mbr), &mbr))
  86. {
  87. grub_device_close (dev);
  88. return grub_errno;
  89. }
  90. /* Check if it is valid. */
  91. if (mbr.signature != grub_cpu_to_le16_compile_time (GRUB_PC_PARTITION_SIGNATURE))
  92. {
  93. grub_device_close (dev);
  94. return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");
  95. }
  96. /* Make sure the MBR is a protective MBR and not a normal MBR. */
  97. for (i = 0; i < 4; i++)
  98. if (mbr.entries[i].type == GRUB_PC_PARTITION_TYPE_GPT_DISK)
  99. break;
  100. if (i == 4)
  101. {
  102. grub_device_close (dev);
  103. return grub_error (GRUB_ERR_BAD_PART_TABLE, "no GPT partition map found");
  104. }
  105. first_sector = dev->disk->total_sectors;
  106. for (i = 1; i < argc; i++)
  107. {
  108. char *separator, csep = 0;
  109. grub_uint8_t type;
  110. separator = grub_strchr (args[i], '+');
  111. if (! separator)
  112. separator = grub_strchr (args[i], '-');
  113. if (separator)
  114. {
  115. csep = *separator;
  116. *separator = 0;
  117. }
  118. partition = grub_partition_probe (dev->disk, args[i]);
  119. if (separator)
  120. *separator = csep;
  121. if (! partition)
  122. {
  123. grub_device_close (dev);
  124. return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
  125. N_("no such partition"));
  126. }
  127. if (partition->start + partition->len > 0xffffffff)
  128. {
  129. grub_device_close (dev);
  130. return grub_error (GRUB_ERR_OUT_OF_RANGE,
  131. "only partitions residing in the first 2TB "
  132. "can be present in hybrid MBR");
  133. }
  134. if (first_sector > partition->start)
  135. first_sector = partition->start;
  136. if (separator && *(separator + 1))
  137. type = grub_strtoul (separator + 1, 0, 0);
  138. else
  139. {
  140. grub_fs_t fs = 0;
  141. dev->disk->partition = partition;
  142. fs = grub_fs_probe (dev);
  143. /* Unknown filesystem isn't fatal. */
  144. if (grub_errno == GRUB_ERR_UNKNOWN_FS)
  145. {
  146. fs = 0;
  147. grub_errno = GRUB_ERR_NONE;
  148. }
  149. if (fs && grub_strcmp (fs->name, "ntfs") == 0)
  150. type = GRUB_PC_PARTITION_TYPE_NTFS;
  151. else if (fs && grub_strcmp (fs->name, "fat") == 0)
  152. /* FIXME: detect FAT16. */
  153. type = GRUB_PC_PARTITION_TYPE_FAT32_LBA;
  154. else if (fs && (grub_strcmp (fs->name, "hfsplus") == 0
  155. || grub_strcmp (fs->name, "hfs") == 0))
  156. type = GRUB_PC_PARTITION_TYPE_HFS;
  157. else
  158. /* FIXME: detect more types. */
  159. type = GRUB_PC_PARTITION_TYPE_EXT2FS;
  160. dev->disk->partition = 0;
  161. }
  162. mbr.entries[i].flag = (csep == '+') ? 0x80 : 0;
  163. if (csep == '+')
  164. {
  165. numactive++;
  166. if (numactive == 2)
  167. {
  168. grub_device_close (dev);
  169. return grub_error (GRUB_ERR_BAD_ARGUMENT,
  170. "only one partition can be active");
  171. }
  172. }
  173. mbr.entries[i].type = type;
  174. mbr.entries[i].start = grub_cpu_to_le32 (partition->start);
  175. lba_to_chs (partition->start,
  176. &(mbr.entries[i].start_sector),
  177. &(mbr.entries[i].start_cylinder),
  178. &(mbr.entries[i].start_head));
  179. lba_to_chs (partition->start + partition->len - 1,
  180. &(mbr.entries[i].end_sector),
  181. &(mbr.entries[i].end_cylinder),
  182. &(mbr.entries[i].end_head));
  183. mbr.entries[i].length = grub_cpu_to_le32 (partition->len);
  184. grub_free (partition);
  185. }
  186. for (; i < 4; i++)
  187. grub_memset (&(mbr.entries[i]), 0, sizeof (mbr.entries[i]));
  188. /* The protective partition. */
  189. if (first_sector > 0xffffffff)
  190. first_sector = 0xffffffff;
  191. else
  192. first_sector--;
  193. mbr.entries[0].flag = 0;
  194. mbr.entries[0].type = GRUB_PC_PARTITION_TYPE_GPT_DISK;
  195. mbr.entries[0].start = grub_cpu_to_le32_compile_time (1);
  196. lba_to_chs (1,
  197. &(mbr.entries[0].start_sector),
  198. &(mbr.entries[0].start_cylinder),
  199. &(mbr.entries[0].start_head));
  200. lba_to_chs (first_sector,
  201. &(mbr.entries[0].end_sector),
  202. &(mbr.entries[0].end_cylinder),
  203. &(mbr.entries[0].end_head));
  204. mbr.entries[0].length = grub_cpu_to_le32 (first_sector);
  205. mbr.signature = grub_cpu_to_le16_compile_time (GRUB_PC_PARTITION_SIGNATURE);
  206. if (grub_disk_write (dev->disk, 0, 0, sizeof (mbr), &mbr))
  207. {
  208. grub_device_close (dev);
  209. return grub_errno;
  210. }
  211. grub_device_close (dev);
  212. grub_printf_ (N_("New MBR is written to `%s'\n"), args[0]);
  213. return GRUB_ERR_NONE;
  214. }
  215. static grub_command_t cmd;
  216. GRUB_MOD_INIT(gptsync)
  217. {
  218. (void) mod; /* To stop warning. */
  219. cmd = grub_register_command ("gptsync", grub_cmd_gptsync,
  220. N_("DEVICE [PARTITION[+/-[TYPE]]] ..."),
  221. /* TRANSLATORS: MBR type is one-byte partition
  222. type id. */
  223. N_("Fill hybrid MBR of GPT drive DEVICE. "
  224. "Specified partitions will be a part "
  225. "of hybrid MBR. Up to 3 partitions are "
  226. "allowed. TYPE is an MBR type. "
  227. "+ means that partition is active. "
  228. "Only one partition can be active."));
  229. }
  230. GRUB_MOD_FINI(gptsync)
  231. {
  232. grub_unregister_command (cmd);
  233. }