gptsync.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  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 (int lba, grub_uint8_t *cl, grub_uint8_t *ch,
  38. grub_uint8_t *dh)
  39. {
  40. int cylinder, head, sector;
  41. int 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. if (argc < 1)
  64. return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
  65. if (argc > 4)
  66. return grub_error (GRUB_ERR_BAD_ARGUMENT, "only 3 partitions can be "
  67. "in hybrid MBR");
  68. if (args[0][0] == '(' && args[0][grub_strlen (args[0]) - 1] == ')')
  69. {
  70. args[0][grub_strlen (args[0]) - 1] = 0;
  71. dev = grub_device_open (args[0] + 1);
  72. args[0][grub_strlen (args[0])] = ')';
  73. }
  74. else
  75. dev = grub_device_open (args[0]);
  76. if (! dev)
  77. return grub_errno;
  78. if (! dev->disk)
  79. {
  80. grub_device_close (dev);
  81. return grub_error (GRUB_ERR_BAD_ARGUMENT, "not a disk");
  82. }
  83. /* Read the protective MBR. */
  84. if (grub_disk_read (dev->disk, 0, 0, sizeof (mbr), &mbr))
  85. {
  86. grub_device_close (dev);
  87. return grub_errno;
  88. }
  89. /* Check if it is valid. */
  90. if (mbr.signature != grub_cpu_to_le16 (GRUB_PC_PARTITION_SIGNATURE))
  91. {
  92. grub_device_close (dev);
  93. return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");
  94. }
  95. /* Make sure the MBR is a protective MBR and not a normal MBR. */
  96. if (mbr.entries[0].type != GRUB_PC_PARTITION_TYPE_GPT_DISK)
  97. {
  98. grub_device_close (dev);
  99. return grub_error (GRUB_ERR_BAD_PART_TABLE, "no GPT partition map found");
  100. }
  101. int i;
  102. first_sector = dev->disk->total_sectors;
  103. for (i = 1; i < argc; i++)
  104. {
  105. char *separator, csep = 0;
  106. grub_uint8_t type;
  107. separator = grub_strchr (args[i], '+');
  108. if (! separator)
  109. separator = grub_strchr (args[i], '-');
  110. if (separator)
  111. {
  112. csep = *separator;
  113. *separator = 0;
  114. }
  115. partition = grub_partition_probe (dev->disk, args[i]);
  116. if (separator)
  117. *separator = csep;
  118. if (! partition)
  119. {
  120. grub_device_close (dev);
  121. return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such partition");
  122. }
  123. if (partition->start + partition->len > 0xffffffff)
  124. {
  125. grub_device_close (dev);
  126. return grub_error (GRUB_ERR_OUT_OF_RANGE,
  127. "only partitions residing in the first 2TB "
  128. "can be present in hybrid MBR");
  129. }
  130. if (first_sector > partition->start)
  131. first_sector = partition->start;
  132. if (separator && *(separator + 1))
  133. type = grub_strtoul (separator + 1, 0, 0);
  134. else
  135. {
  136. grub_fs_t fs = 0;
  137. dev->disk->partition = partition;
  138. fs = grub_fs_probe (dev);
  139. /* Unknown filesystem isn't fatal. */
  140. if (grub_errno == GRUB_ERR_UNKNOWN_FS)
  141. {
  142. fs = 0;
  143. grub_errno = GRUB_ERR_NONE;
  144. }
  145. if (fs && grub_strcmp (fs->name, "ntfs") == 0)
  146. type = GRUB_PC_PARTITION_TYPE_NTFS;
  147. else if (fs && grub_strcmp (fs->name, "fat") == 0)
  148. /* FIXME: detect FAT16. */
  149. type = GRUB_PC_PARTITION_TYPE_FAT32_LBA;
  150. else if (fs && (grub_strcmp (fs->name, "hfsplus") == 0
  151. || grub_strcmp (fs->name, "hfs") == 0))
  152. type = GRUB_PC_PARTITION_TYPE_HFS;
  153. else
  154. /* FIXME: detect more types. */
  155. type = GRUB_PC_PARTITION_TYPE_EXT2FS;
  156. dev->disk->partition = 0;
  157. }
  158. mbr.entries[i].flag = (csep == '+') ? 0x80 : 0;
  159. if (csep == '+')
  160. {
  161. numactive++;
  162. if (numactive == 2)
  163. {
  164. grub_device_close (dev);
  165. return grub_error (GRUB_ERR_BAD_ARGUMENT,
  166. "only one partition can be active");
  167. }
  168. }
  169. mbr.entries[i].type = type;
  170. mbr.entries[i].start = grub_cpu_to_le32 (partition->start);
  171. lba_to_chs (partition->start,
  172. &(mbr.entries[i].start_sector),
  173. &(mbr.entries[i].start_cylinder),
  174. &(mbr.entries[i].start_head));
  175. lba_to_chs (partition->start + partition->len - 1,
  176. &(mbr.entries[i].end_sector),
  177. &(mbr.entries[i].end_cylinder),
  178. &(mbr.entries[i].end_head));
  179. mbr.entries[i].length = grub_cpu_to_le32 (partition->len);
  180. grub_free (partition);
  181. }
  182. for (; i < 4; i++)
  183. grub_memset (&(mbr.entries[i]), 0, sizeof (mbr.entries[i]));
  184. /* The protective partition. */
  185. if (first_sector > 0xffffffff)
  186. first_sector = 0xffffffff;
  187. else
  188. first_sector--;
  189. mbr.entries[0].flag = 0;
  190. mbr.entries[0].type = GRUB_PC_PARTITION_TYPE_GPT_DISK;
  191. mbr.entries[0].start = grub_cpu_to_le32 (1);
  192. lba_to_chs (1,
  193. &(mbr.entries[0].start_sector),
  194. &(mbr.entries[0].start_cylinder),
  195. &(mbr.entries[0].start_head));
  196. lba_to_chs (first_sector,
  197. &(mbr.entries[0].end_sector),
  198. &(mbr.entries[0].end_cylinder),
  199. &(mbr.entries[0].end_head));
  200. mbr.entries[0].length = grub_cpu_to_le32 (first_sector);
  201. mbr.signature = grub_cpu_to_le16 (GRUB_PC_PARTITION_SIGNATURE);
  202. if (grub_disk_write (dev->disk, 0, 0, sizeof (mbr), &mbr))
  203. {
  204. grub_device_close (dev);
  205. return grub_errno;
  206. }
  207. grub_printf ("New MBR is written to '%s'\n", args[0]);
  208. return GRUB_ERR_NONE;
  209. }
  210. static grub_command_t cmd;
  211. GRUB_MOD_INIT(gptsync)
  212. {
  213. (void) mod; /* To stop warning. */
  214. cmd = grub_register_command ("gptsync", grub_cmd_gptsync,
  215. N_("DEVICE [PARTITION[+/-[TYPE]]] ..."),
  216. N_("Fill hybrid MBR of GPT drive DEVICE. "
  217. "Specified partitions will be a part "
  218. "of hybrid MBR. Up to 3 partitions are "
  219. "allowed. TYPE is an MBR type. "
  220. "+ means that partition is active. "
  221. "Only one partition can be active."));
  222. }
  223. GRUB_MOD_FINI(gptsync)
  224. {
  225. grub_unregister_command (cmd);
  226. }