gptsync.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  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. /* Convert a LBA address to a CHS address in the INT 13 format. */
  31. /* Taken from grub1. */
  32. /* XXX: use hardcoded geometry of C = 1024, H = 255, S = 63.
  33. Is it a problem?
  34. */
  35. static void
  36. lba_to_chs (int lba, grub_uint8_t *cl, grub_uint8_t *ch,
  37. grub_uint8_t *dh)
  38. {
  39. int cylinder, head, sector;
  40. int sectors = 63, heads = 255, cylinders = 1024;
  41. sector = lba % sectors + 1;
  42. head = (lba / sectors) % heads;
  43. cylinder = lba / (sectors * heads);
  44. if (cylinder >= cylinders)
  45. {
  46. *cl = *ch = *dh = 0xff;
  47. return;
  48. }
  49. *cl = sector | ((cylinder & 0x300) >> 2);
  50. *ch = cylinder & 0xFF;
  51. *dh = head;
  52. }
  53. static grub_err_t
  54. grub_cmd_gptsync (grub_command_t cmd __attribute__ ((unused)),
  55. int argc, char **args)
  56. {
  57. grub_device_t dev;
  58. struct grub_msdos_partition_mbr mbr;
  59. struct grub_partition *partition;
  60. grub_disk_addr_t first_sector;
  61. int numactive = 0;
  62. int pcboot = 0;
  63. if ((argc >= 1) && (! grub_strcmp (args[0], "--pc")))
  64. {
  65. pcboot++;
  66. numactive++;
  67. argc--;
  68. args++;
  69. }
  70. if (argc < 1)
  71. return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
  72. if (argc > 4)
  73. return grub_error (GRUB_ERR_BAD_ARGUMENT, "only 3 partitions can be "
  74. "in hybrid MBR");
  75. if (args[0][0] == '(' && args[0][grub_strlen (args[0]) - 1] == ')')
  76. {
  77. args[0][grub_strlen (args[0]) - 1] = 0;
  78. dev = grub_device_open (args[0] + 1);
  79. args[0][grub_strlen (args[0])] = ')';
  80. }
  81. else
  82. dev = grub_device_open (args[0]);
  83. if (! dev)
  84. return grub_errno;
  85. if (! dev->disk)
  86. {
  87. grub_device_close (dev);
  88. return grub_error (GRUB_ERR_BAD_ARGUMENT, "not a disk");
  89. }
  90. /* Read the protective MBR. */
  91. if (grub_disk_read (dev->disk, 0, 0, sizeof (mbr), &mbr))
  92. {
  93. grub_device_close (dev);
  94. return grub_errno;
  95. }
  96. /* Check if it is valid. */
  97. if (mbr.signature != grub_cpu_to_le16 (GRUB_PC_PARTITION_SIGNATURE))
  98. {
  99. grub_device_close (dev);
  100. return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");
  101. }
  102. /* Make sure the MBR is a protective MBR and not a normal MBR. */
  103. if (mbr.entries[0].type != GRUB_PC_PARTITION_TYPE_GPT_DISK)
  104. {
  105. grub_device_close (dev);
  106. return grub_error (GRUB_ERR_BAD_PART_TABLE, "no GPT partition map found");
  107. }
  108. int i;
  109. first_sector = dev->disk->total_sectors;
  110. for (i = 1; i < argc; i++)
  111. {
  112. char *separator, csep = 0;
  113. grub_uint8_t type;
  114. separator = grub_strchr (args[i], '+');
  115. if (! separator)
  116. separator = grub_strchr (args[i], '-');
  117. if (separator)
  118. {
  119. csep = *separator;
  120. *separator = 0;
  121. }
  122. partition = grub_partition_probe (dev->disk, args[i]);
  123. if (separator)
  124. *separator = csep;
  125. if (! partition)
  126. {
  127. grub_device_close (dev);
  128. return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such partition");
  129. }
  130. if (partition->start + partition->len > 0xffffffff)
  131. {
  132. grub_device_close (dev);
  133. return grub_error (GRUB_ERR_OUT_OF_RANGE,
  134. "only partitions resding in the first 2TB "
  135. "can be presen in hybrid MBR");
  136. }
  137. if (first_sector > partition->start)
  138. first_sector = partition->start;
  139. if (separator && *(separator + 1))
  140. type = grub_strtoul (separator + 1, 0, 0);
  141. else
  142. {
  143. grub_fs_t fs = 0;
  144. dev->disk->partition = partition;
  145. fs = grub_fs_probe (dev);
  146. /* Unknown filesystem isn't fatal. */
  147. if (grub_errno == GRUB_ERR_UNKNOWN_FS)
  148. {
  149. fs = 0;
  150. grub_errno = GRUB_ERR_NONE;
  151. }
  152. if (fs && grub_strcmp (fs->name, "ntfs") == 0)
  153. type = GRUB_PC_PARTITION_TYPE_NTFS;
  154. else if (fs && grub_strcmp (fs->name, "fat") == 0)
  155. /* FIXME: detect FAT16. */
  156. type = GRUB_PC_PARTITION_TYPE_FAT32_LBA;
  157. else if (fs && (grub_strcmp (fs->name, "hfsplus") == 0
  158. || grub_strcmp (fs->name, "hfs") == 0))
  159. type = GRUB_PC_PARTITION_TYPE_HFS;
  160. else
  161. /* FIXME: detect more types. */
  162. type = GRUB_PC_PARTITION_TYPE_EXT2FS;
  163. dev->disk->partition = 0;
  164. }
  165. mbr.entries[i].flag = (csep == '+') ? 0x80 : 0;
  166. if (csep == '+')
  167. {
  168. numactive++;
  169. if (numactive == 2)
  170. {
  171. grub_device_close (dev);
  172. return grub_error (GRUB_ERR_BAD_ARGUMENT,
  173. "only one partition can be active");
  174. }
  175. }
  176. mbr.entries[i].type = type;
  177. mbr.entries[i].start = grub_cpu_to_le32 (partition->start);
  178. lba_to_chs (partition->start,
  179. &(mbr.entries[i].start_sector),
  180. &(mbr.entries[i].start_cylinder),
  181. &(mbr.entries[i].start_head));
  182. lba_to_chs (partition->start + partition->len - 1,
  183. &(mbr.entries[i].end_sector),
  184. &(mbr.entries[i].end_cylinder),
  185. &(mbr.entries[i].end_head));
  186. mbr.entries[i].length = grub_cpu_to_le32 (partition->len);
  187. grub_free (partition);
  188. }
  189. for (; i < 4; i++)
  190. grub_memset (&(mbr.entries[i]), 0, sizeof (mbr.entries[i]));
  191. /* The protective partition. */
  192. if (first_sector > 0xffffffff)
  193. first_sector = 0xffffffff;
  194. else
  195. first_sector--;
  196. mbr.entries[0].flag = (pcboot) ? 0x80 : 0;
  197. mbr.entries[0].type = GRUB_PC_PARTITION_TYPE_GPT_DISK;
  198. mbr.entries[0].start = grub_cpu_to_le32 (1);
  199. lba_to_chs (1,
  200. &(mbr.entries[0].start_sector),
  201. &(mbr.entries[0].start_cylinder),
  202. &(mbr.entries[0].start_head));
  203. lba_to_chs (first_sector,
  204. &(mbr.entries[0].end_sector),
  205. &(mbr.entries[0].end_cylinder),
  206. &(mbr.entries[0].end_head));
  207. mbr.entries[0].length = grub_cpu_to_le32 (first_sector);
  208. mbr.signature = grub_cpu_to_le16 (GRUB_PC_PARTITION_SIGNATURE);
  209. if (grub_disk_write (dev->disk, 0, 0, sizeof (mbr), &mbr))
  210. {
  211. grub_device_close (dev);
  212. return grub_errno;
  213. }
  214. grub_printf ("New MBR is written to '%s'\n", args[0]);
  215. return GRUB_ERR_NONE;
  216. }
  217. static grub_command_t cmd;
  218. GRUB_MOD_INIT(gptsync)
  219. {
  220. (void) mod; /* To stop warning. */
  221. cmd = grub_register_command ("gptsync", grub_cmd_gptsync,
  222. N_("[--pc] DEVICE [PARTITION[+/-[TYPE]]] ..."),
  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. }