source: grub-pc/trunk/fuentes/grub-core/commands/gptsync.c @ 22

Last change on this file since 22 was 22, checked in by mabarracus, 4 years ago

updated version and apply net.ifnames=0 into debian/rules

File size: 7.3 KB
Line 
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
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>
31
32GRUB_MOD_LICENSE ("GPLv3+");
33
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?
38*/
39static void
40lba_to_chs (grub_uint32_t lba, grub_uint8_t *cl, grub_uint8_t *ch,
41            grub_uint8_t *dh)
42{
43  grub_uint32_t cylinder, head, sector;
44  grub_uint32_t sectors = 63, heads = 255, cylinders = 1024;
45
46  sector = lba % sectors + 1;
47  head = (lba / sectors) % heads;
48  cylinder = lba / (sectors * heads);
49
50  if (cylinder >= cylinders)
51    {
52      *cl = *ch = *dh = 0xff;
53      return;
54    }
55
56  *cl = sector | ((cylinder & 0x300) >> 2);
57  *ch = cylinder & 0xFF;
58  *dh = head;
59}
60
61static grub_err_t
62grub_cmd_gptsync (grub_command_t cmd __attribute__ ((unused)),
63                  int argc, char **args)
64{
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;
71
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");
77
78  if (args[0][0] == '(' && args[0][grub_strlen (args[0]) - 1] == ')')
79    {
80      args[0][grub_strlen (args[0]) - 1] = 0;
81      dev = grub_device_open (args[0] + 1);
82      args[0][grub_strlen (args[0])] = ')';
83    }
84  else
85    dev = grub_device_open (args[0]);
86
87  if (! dev)
88    return grub_errno;
89
90  if (! dev->disk)
91    {
92      grub_device_close (dev);
93      return grub_error (GRUB_ERR_BAD_ARGUMENT, "not a disk");
94    }
95
96  /* Read the protective MBR.  */
97  if (grub_disk_read (dev->disk, 0, 0, sizeof (mbr), &mbr))
98    {
99      grub_device_close (dev);
100      return grub_errno;
101    }
102
103  /* Check if it is valid.  */
104  if (mbr.signature != grub_cpu_to_le16 (GRUB_PC_PARTITION_SIGNATURE))
105    {
106      grub_device_close (dev);
107      return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");
108    }
109
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)
115    {
116      grub_device_close (dev);
117      return grub_error (GRUB_ERR_BAD_PART_TABLE, "no GPT partition map found");
118    }
119
120  first_sector = dev->disk->total_sectors;
121  for (i = 1; i < argc; i++)
122    {
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)
129        {
130          csep = *separator;
131          *separator = 0;
132        }
133      partition = grub_partition_probe (dev->disk, args[i]);
134      if (separator)
135        *separator = csep;
136      if (! partition)
137        {
138          grub_device_close (dev);
139          return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
140                             N_("no such partition"));
141        }
142
143      if (partition->start + partition->len > 0xffffffff)
144        {
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");
149        }
150
151
152      if (first_sector > partition->start)
153        first_sector = partition->start;
154
155      if (separator && *(separator + 1))
156        type = grub_strtoul (separator + 1, 0, 0);
157      else
158        {
159          grub_fs_t fs = 0;
160          dev->disk->partition = partition;
161          fs = grub_fs_probe (dev);
162
163          /* Unknown filesystem isn't fatal. */
164          if (grub_errno == GRUB_ERR_UNKNOWN_FS)
165            {
166              fs = 0;
167              grub_errno = GRUB_ERR_NONE;
168            }
169
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;
181
182          dev->disk->partition = 0;
183        }
184
185      mbr.entries[i].flag = (csep == '+') ? 0x80 : 0;
186      if (csep == '+')
187        {
188          numactive++;
189          if (numactive == 2)
190            {
191              grub_device_close (dev);
192              return grub_error (GRUB_ERR_BAD_ARGUMENT,
193                                 "only one partition can be active");
194            }
195        }
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);
208    }
209  for (; i < 4; i++)
210    grub_memset (&(mbr.entries[i]), 0, sizeof (mbr.entries[i]));
211
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);
229
230  mbr.signature = grub_cpu_to_le16 (GRUB_PC_PARTITION_SIGNATURE);
231
232  if (grub_disk_write (dev->disk, 0, 0, sizeof (mbr), &mbr))
233    {
234      grub_device_close (dev);
235      return grub_errno;
236    }
237
238  grub_printf_ (N_("New MBR is written to `%s'\n"), args[0]);
239
240  return GRUB_ERR_NONE;
241}
242
243
244static grub_command_t cmd;
245
246GRUB_MOD_INIT(gptsync)
247{
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."));
259}
260
261GRUB_MOD_FINI(gptsync)
262{
263  grub_unregister_command (cmd);
264}
Note: See TracBrowser for help on using the repository browser.