Upgraded GRUB2 to 2.00 release.
[AROS.git] / arch / all-pc / boot / grub2-aros / grub-core / commands / gptsync.c
blob1a203dc59d2fa70c23c62ba3b61d77eca83412e5
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.
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.
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.
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/>.
21 #include <grub/command.h>
22 #include <grub/dl.h>
23 #include <grub/device.h>
24 #include <grub/disk.h>
25 #include <grub/msdos_partition.h>
26 #include <grub/partition.h>
27 #include <grub/misc.h>
28 #include <grub/mm.h>
29 #include <grub/fs.h>
30 #include <grub/i18n.h>
32 GRUB_MOD_LICENSE ("GPLv3+");
34 /* Convert a LBA address to a CHS address in the INT 13 format. */
35 /* Taken from grub1. */
36 /* XXX: use hardcoded geometry of C = 1024, H = 255, S = 63.
37 Is it a problem?
39 static void
40 lba_to_chs (int lba, grub_uint8_t *cl, grub_uint8_t *ch,
41 grub_uint8_t *dh)
43 int cylinder, head, sector;
44 int sectors = 63, heads = 255, cylinders = 1024;
46 sector = lba % sectors + 1;
47 head = (lba / sectors) % heads;
48 cylinder = lba / (sectors * heads);
50 if (cylinder >= cylinders)
52 *cl = *ch = *dh = 0xff;
53 return;
56 *cl = sector | ((cylinder & 0x300) >> 2);
57 *ch = cylinder & 0xFF;
58 *dh = head;
61 static grub_err_t
62 grub_cmd_gptsync (grub_command_t cmd __attribute__ ((unused)),
63 int argc, char **args)
65 grub_device_t dev;
66 struct grub_msdos_partition_mbr mbr;
67 struct grub_partition *partition;
68 grub_disk_addr_t first_sector;
69 int numactive = 0;
70 int i;
72 if (argc < 1)
73 return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
74 if (argc > 4)
75 return grub_error (GRUB_ERR_BAD_ARGUMENT, "only 3 partitions can be "
76 "in hybrid MBR");
78 if (args[0][0] == '(' && args[0][grub_strlen (args[0]) - 1] == ')')
80 args[0][grub_strlen (args[0]) - 1] = 0;
81 dev = grub_device_open (args[0] + 1);
82 args[0][grub_strlen (args[0])] = ')';
84 else
85 dev = grub_device_open (args[0]);
87 if (! dev)
88 return grub_errno;
90 if (! dev->disk)
92 grub_device_close (dev);
93 return grub_error (GRUB_ERR_BAD_ARGUMENT, "not a disk");
96 /* Read the protective MBR. */
97 if (grub_disk_read (dev->disk, 0, 0, sizeof (mbr), &mbr))
99 grub_device_close (dev);
100 return grub_errno;
103 /* Check if it is valid. */
104 if (mbr.signature != grub_cpu_to_le16 (GRUB_PC_PARTITION_SIGNATURE))
106 grub_device_close (dev);
107 return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");
110 /* Make sure the MBR is a protective MBR and not a normal MBR. */
111 for (i = 0; i < 4; i++)
112 if (mbr.entries[i].type == GRUB_PC_PARTITION_TYPE_GPT_DISK)
113 break;
114 if (i == 4)
116 grub_device_close (dev);
117 return grub_error (GRUB_ERR_BAD_PART_TABLE, "no GPT partition map found");
120 first_sector = dev->disk->total_sectors;
121 for (i = 1; i < argc; i++)
123 char *separator, csep = 0;
124 grub_uint8_t type;
125 separator = grub_strchr (args[i], '+');
126 if (! separator)
127 separator = grub_strchr (args[i], '-');
128 if (separator)
130 csep = *separator;
131 *separator = 0;
133 partition = grub_partition_probe (dev->disk, args[i]);
134 if (separator)
135 *separator = csep;
136 if (! partition)
138 grub_device_close (dev);
139 return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
140 N_("no such partition"));
143 if (partition->start + partition->len > 0xffffffff)
145 grub_device_close (dev);
146 return grub_error (GRUB_ERR_OUT_OF_RANGE,
147 "only partitions residing in the first 2TB "
148 "can be present in hybrid MBR");
152 if (first_sector > partition->start)
153 first_sector = partition->start;
155 if (separator && *(separator + 1))
156 type = grub_strtoul (separator + 1, 0, 0);
157 else
159 grub_fs_t fs = 0;
160 dev->disk->partition = partition;
161 fs = grub_fs_probe (dev);
163 /* Unknown filesystem isn't fatal. */
164 if (grub_errno == GRUB_ERR_UNKNOWN_FS)
166 fs = 0;
167 grub_errno = GRUB_ERR_NONE;
170 if (fs && grub_strcmp (fs->name, "ntfs") == 0)
171 type = GRUB_PC_PARTITION_TYPE_NTFS;
172 else if (fs && grub_strcmp (fs->name, "fat") == 0)
173 /* FIXME: detect FAT16. */
174 type = GRUB_PC_PARTITION_TYPE_FAT32_LBA;
175 else if (fs && (grub_strcmp (fs->name, "hfsplus") == 0
176 || grub_strcmp (fs->name, "hfs") == 0))
177 type = GRUB_PC_PARTITION_TYPE_HFS;
178 else
179 /* FIXME: detect more types. */
180 type = GRUB_PC_PARTITION_TYPE_EXT2FS;
182 dev->disk->partition = 0;
185 mbr.entries[i].flag = (csep == '+') ? 0x80 : 0;
186 if (csep == '+')
188 numactive++;
189 if (numactive == 2)
191 grub_device_close (dev);
192 return grub_error (GRUB_ERR_BAD_ARGUMENT,
193 "only one partition can be active");
196 mbr.entries[i].type = type;
197 mbr.entries[i].start = grub_cpu_to_le32 (partition->start);
198 lba_to_chs (partition->start,
199 &(mbr.entries[i].start_sector),
200 &(mbr.entries[i].start_cylinder),
201 &(mbr.entries[i].start_head));
202 lba_to_chs (partition->start + partition->len - 1,
203 &(mbr.entries[i].end_sector),
204 &(mbr.entries[i].end_cylinder),
205 &(mbr.entries[i].end_head));
206 mbr.entries[i].length = grub_cpu_to_le32 (partition->len);
207 grub_free (partition);
209 for (; i < 4; i++)
210 grub_memset (&(mbr.entries[i]), 0, sizeof (mbr.entries[i]));
212 /* The protective partition. */
213 if (first_sector > 0xffffffff)
214 first_sector = 0xffffffff;
215 else
216 first_sector--;
217 mbr.entries[0].flag = 0;
218 mbr.entries[0].type = GRUB_PC_PARTITION_TYPE_GPT_DISK;
219 mbr.entries[0].start = grub_cpu_to_le32 (1);
220 lba_to_chs (1,
221 &(mbr.entries[0].start_sector),
222 &(mbr.entries[0].start_cylinder),
223 &(mbr.entries[0].start_head));
224 lba_to_chs (first_sector,
225 &(mbr.entries[0].end_sector),
226 &(mbr.entries[0].end_cylinder),
227 &(mbr.entries[0].end_head));
228 mbr.entries[0].length = grub_cpu_to_le32 (first_sector);
230 mbr.signature = grub_cpu_to_le16 (GRUB_PC_PARTITION_SIGNATURE);
232 if (grub_disk_write (dev->disk, 0, 0, sizeof (mbr), &mbr))
234 grub_device_close (dev);
235 return grub_errno;
238 grub_printf_ (N_("New MBR is written to `%s'\n"), args[0]);
240 return GRUB_ERR_NONE;
244 static grub_command_t cmd;
246 GRUB_MOD_INIT(gptsync)
248 (void) mod; /* To stop warning. */
249 cmd = grub_register_command ("gptsync", grub_cmd_gptsync,
250 N_("DEVICE [PARTITION[+/-[TYPE]]] ..."),
251 /* TRANSLATORS: MBR type is one-byte partition
252 type id. */
253 N_("Fill hybrid MBR of GPT drive DEVICE. "
254 "Specified partitions will be a part "
255 "of hybrid MBR. Up to 3 partitions are "
256 "allowed. TYPE is an MBR type. "
257 "+ means that partition is active. "
258 "Only one partition can be active."));
261 GRUB_MOD_FINI(gptsync)
263 grub_unregister_command (cmd);