~ubuntu-branches/ubuntu/trusty/grub2/trusty-updates

« back to all changes in this revision

Viewing changes to commands/gptsync.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson
  • Date: 2011-02-08 11:39:26 UTC
  • mfrom: (17.6.26 experimental)
  • mto: (17.6.27 experimental)
  • mto: This revision was merged to the branch mainline in revision 104.
  • Revision ID: james.westby@ubuntu.com-20110208113926-clfs90haboyk9zip
Tags: 1.99~rc1-2
* Merge 1.98+20100804-13 and 1.98+20100804-14, updating translations:
  - Kazakh (Baurzhan Muftakhidinov / Timur Birsh).
* mkconfig_skip_dmcrypt.patch: Refer to GRUB_PRELOAD_MODULES rather than
  suggesting people write a /etc/grub.d/01_modules script (thanks, Jordan
  Uggla).
* Handle empty dir passed to grub_find_root_device_from_mountinfo; fixes
  grub-mkrelpath on btrfs subvolumes (LP: #712029).
* Add rootflags=subvol=<name> if / is on a btrfs subvolume (LP: #712029).
* Upload to unstable.

Show diffs side-by-side

added added

removed removed

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