~darkmuggle-deactivatedaccount/ubuntu/quantal/grub2/fix-872244

« back to all changes in this revision

Viewing changes to loader/macho.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson
  • Date: 2010-01-11 11:12:55 UTC
  • mfrom: (17.3.7 squeeze)
  • Revision ID: james.westby@ubuntu.com-20100111111255-lr8ebkqw5x41gq6j
Tags: 1.98~20100101-1ubuntu1
* Resynchronise with Debian. Remaining changes:
  - Adjust for default Ubuntu boot options ("quiet splash").
  - Default to hiding the menu; holding down Shift at boot will show it.
  - Set a monochromatic theme for Ubuntu.
  - Apply Ubuntu GRUB Legacy changes to legacy update-grub script: title,
    recovery mode, quiet option, tweak how memtest86+ is displayed, and
    use UUIDs where appropriate.
  - Conflict with grub (<< 0.97-54) as well as grub-legacy.
  - Fix backslash-escaping in merge_debconf_into_conf.
  - Remove "GNU/Linux" from default distributor string.
  - Add crashkernel= options if kdump and makedumpfile are available.
  - If other operating systems are installed, then automatically unhide
    the menu. Otherwise, if GRUB_HIDDEN_TIMEOUT is 0, then use keystatus
    if available to check whether Shift is pressed. If it is, show the
    menu, otherwise boot immediately. If keystatus is not available, then
    fall back to a short delay interruptible with Escape.
  - Allow Shift to interrupt 'sleep --interruptible'.
  - Don't display introductory message about line editing unless we're
    actually offering a shell prompt. Don't clear the screen just before
    booting if we never drew the menu in the first place.
  - Remove some verbose messages printed before reading the configuration
    file.
  - If the environment variable "quiet" is set to something other than 0,
    suppress progress messages as the kernel and initrd load. Set this for
    non-recovery kernel menu entries.
  - Add GRUB_DEFAULT=saved, as well as grub-set-default and grub-reboot
    utilities. Provides functionality essentially equivalent to GRUB
    Legacy's savedefault.
  - Keep the loopback file open so that subsequent changes to the "root"
    environment variable don't affect it.
  - Change prepare_grub_to_access_device to handle filesystems
    loop-mounted on file images.
  - Ignore devices loop-mounted from files in 10_linux.
  - Show the boot menu if the previous boot failed, that is if it failed
    to get to the end of one of the normal runlevels.
  - Handle RAID devices containing virtio components.
* Update savedefault patch from current Bazaar branch, fixing grub-reboot
  to have distinct behaviour from grub-set-default (LP: #497326).
* Fix grub-mkisofs compilation error with FORTIFY_SOURCE.
* Convert recordfail boilerplate in each menu entry to use a function.

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
#include <grub/misc.h>
31
31
#include <grub/mm.h>
32
32
 
33
 
#define min(a,b) (((a) < (b)) ? (a) : (b))
34
 
 
35
 
/* 32-bit. */
36
 
 
37
 
int
38
 
grub_macho_contains_macho32 (grub_macho_t macho)
39
 
{
40
 
  return macho->offset32 != -1;
41
 
}
42
 
 
43
 
static void
44
 
grub_macho_parse32 (grub_macho_t macho)
45
 
{
46
 
  struct grub_macho_header32 head;
47
 
 
48
 
  /* Is there any candidate at all? */
49
 
  if (macho->offset32 == -1)
50
 
    return;
51
 
 
52
 
  /* Read header and check magic*/
53
 
  if (grub_file_seek (macho->file, macho->offset32) == (grub_off_t) -1
54
 
      || grub_file_read (macho->file, &head, sizeof (head))
55
 
      != sizeof(head))
56
 
    {
57
 
      grub_error (GRUB_ERR_READ_ERROR, "Cannot read Mach-O header.");
58
 
      macho->offset32 = -1;
59
 
      return;
60
 
    }
61
 
  if (head.magic != GRUB_MACHO_MAGIC32)
62
 
    {
63
 
      grub_error (GRUB_ERR_BAD_OS, "Invalid Mach-O 32-bit header.");
64
 
      macho->offset32 = -1;
65
 
      return;
66
 
    }
67
 
 
68
 
  /* Read commands. */
69
 
  macho->ncmds32 = head.ncmds;
70
 
  macho->cmdsize32 = head.sizeofcmds;
71
 
  macho->cmds32 = grub_malloc(macho->cmdsize32);
72
 
  if (! macho->cmds32)
73
 
    {
74
 
      grub_error (GRUB_ERR_OUT_OF_MEMORY, "not enough memory to read commands");
75
 
      return;
76
 
    }
77
 
  if (grub_file_read (macho->file, macho->cmds32,
78
 
                      (grub_size_t) macho->cmdsize32)
79
 
      != (grub_ssize_t) macho->cmdsize32)
80
 
    {
81
 
      grub_error (GRUB_ERR_READ_ERROR, "Cannot read Mach-O header.");
82
 
      macho->offset32 = -1;
83
 
    }
84
 
}
85
 
 
86
 
typedef int NESTED_FUNC_ATTR (*grub_macho_iter_hook_t)
87
 
(grub_macho_t , struct grub_macho_cmd *,
88
 
               void *);
89
 
 
90
 
static grub_err_t
91
 
grub_macho32_cmds_iterate (grub_macho_t macho,
92
 
                           grub_macho_iter_hook_t hook,
93
 
                           void *hook_arg)
94
 
{
95
 
  grub_uint8_t *hdrs = macho->cmds32;
96
 
  int i;
97
 
  if (! macho->cmds32)
98
 
    return grub_error (GRUB_ERR_BAD_OS, "Couldn't find 32-bit Mach-O");
99
 
  for (i = 0; i < macho->ncmds32; i++)
100
 
    {
101
 
      struct grub_macho_cmd *hdr = (struct grub_macho_cmd *) hdrs;
102
 
      if (hook (macho, hdr, hook_arg))
103
 
        break;
104
 
      hdrs += hdr->cmdsize;
105
 
    }
106
 
 
107
 
  return grub_errno;
108
 
}
109
 
 
110
 
grub_size_t
111
 
grub_macho32_filesize (grub_macho_t macho)
112
 
{
113
 
  if (grub_macho_contains_macho32 (macho))
114
 
    return macho->end32 - macho->offset32;
115
 
  return 0;
116
 
}
117
 
 
118
 
grub_err_t
119
 
grub_macho32_readfile (grub_macho_t macho, void *dest)
120
 
{
121
 
  grub_ssize_t read;
122
 
  if (! grub_macho_contains_macho32 (macho))
123
 
    return grub_error (GRUB_ERR_BAD_OS,
124
 
                       "Couldn't read architecture-specific part");
125
 
 
126
 
  if (grub_file_seek (macho->file, macho->offset32) == (grub_off_t) -1)
127
 
    {
128
 
      grub_error_push ();
129
 
      return grub_error (GRUB_ERR_BAD_OS,
130
 
                         "Invalid offset in program header.");
131
 
    }
132
 
 
133
 
  read = grub_file_read (macho->file, dest,
134
 
                         macho->end32 - macho->offset32);
135
 
  if (read != (grub_ssize_t) (macho->end32 - macho->offset32))
136
 
    {
137
 
      grub_error_push ();
138
 
      return grub_error (GRUB_ERR_BAD_OS,
139
 
                         "Couldn't read architecture-specific part");
140
 
    }
141
 
  return GRUB_ERR_NONE;
142
 
}
143
 
 
144
 
/* Calculate the amount of memory spanned by the segments. */
145
 
grub_err_t
146
 
grub_macho32_size (grub_macho_t macho, grub_addr_t *segments_start,
147
 
                   grub_addr_t *segments_end, int flags)
148
 
{
149
 
  int nr_phdrs = 0;
150
 
 
151
 
  /* Run through the program headers to calculate the total memory size we
152
 
     should claim.  */
153
 
  auto int NESTED_FUNC_ATTR calcsize (grub_macho_t _macho,
154
 
                                      struct grub_macho_cmd *phdr, void *_arg);
155
 
  int NESTED_FUNC_ATTR calcsize (grub_macho_t UNUSED _macho,
156
 
                                 struct grub_macho_cmd *hdr0, void UNUSED *_arg)
157
 
    {
158
 
      struct grub_macho_segment32 *hdr = (struct grub_macho_segment32 *) hdr0;
159
 
      if (hdr->cmd != GRUB_MACHO_CMD_SEGMENT32)
160
 
        return 0;
161
 
      if (! hdr->filesize && (flags & GRUB_MACHO_NOBSS))
162
 
        return 0;
163
 
 
164
 
      nr_phdrs++;
165
 
      if (hdr->vmaddr < *segments_start)
166
 
        *segments_start = hdr->vmaddr;
167
 
      if (hdr->vmaddr + hdr->vmsize > *segments_end)
168
 
        *segments_end = hdr->vmaddr + hdr->vmsize;
169
 
      return 0;
170
 
    }
171
 
 
172
 
  *segments_start = (grub_uint32_t) -1;
173
 
  *segments_end = 0;
174
 
 
175
 
  grub_macho32_cmds_iterate (macho, calcsize, 0);
176
 
 
177
 
  if (nr_phdrs == 0)
178
 
    return grub_error (GRUB_ERR_BAD_OS, "No program headers present");
179
 
 
180
 
  if (*segments_end < *segments_start)
181
 
    /* Very bad addresses.  */
182
 
    return grub_error (GRUB_ERR_BAD_OS, "Bad program header load addresses");
183
 
 
184
 
  return GRUB_ERR_NONE;
185
 
}
186
 
 
187
 
/* Load every loadable segment into memory specified by `_load_hook'.  */
188
 
grub_err_t
189
 
grub_macho32_load (grub_macho_t macho, char *offset, int flags)
190
 
{
191
 
  grub_err_t err = 0;
192
 
  auto int NESTED_FUNC_ATTR do_load(grub_macho_t _macho,
193
 
                               struct grub_macho_cmd *hdr0,
194
 
                               void UNUSED *_arg);
195
 
  int NESTED_FUNC_ATTR do_load(grub_macho_t _macho,
196
 
                               struct grub_macho_cmd *hdr0,
197
 
                               void UNUSED *_arg)
198
 
  {
199
 
    struct grub_macho_segment32 *hdr = (struct grub_macho_segment32 *) hdr0;
200
 
 
201
 
    if (hdr->cmd != GRUB_MACHO_CMD_SEGMENT32)
202
 
      return 0;
203
 
 
204
 
    if (! hdr->filesize && (flags & GRUB_MACHO_NOBSS))
205
 
      return 0;
206
 
    if (! hdr->vmsize)
207
 
      return 0;
208
 
 
209
 
    if (grub_file_seek (_macho->file, hdr->fileoff
210
 
                        + _macho->offset32) == (grub_off_t) -1)
211
 
      {
212
 
        grub_error_push ();
213
 
        grub_error (GRUB_ERR_BAD_OS,
214
 
                    "Invalid offset in program header.");
215
 
        return 1;
216
 
      }
217
 
 
218
 
    if (hdr->filesize)
219
 
      {
220
 
        grub_ssize_t read;
221
 
        read = grub_file_read (_macho->file, offset + hdr->vmaddr,
222
 
                                   min (hdr->filesize, hdr->vmsize));
223
 
        if (read != (grub_ssize_t) min (hdr->filesize, hdr->vmsize))
224
 
          {
225
 
            /* XXX How can we free memory from `load_hook'? */
226
 
            grub_error_push ();
227
 
            err=grub_error (GRUB_ERR_BAD_OS,
228
 
                            "Couldn't read segment from file: "
229
 
                            "wanted 0x%lx bytes; read 0x%lx bytes.",
230
 
                            hdr->filesize, read);
231
 
            return 1;
232
 
          }
233
 
      }
234
 
 
235
 
    if (hdr->filesize < hdr->vmsize)
236
 
      grub_memset (offset + hdr->vmaddr + hdr->filesize,
237
 
                   0, hdr->vmsize - hdr->filesize);
238
 
    return 0;
239
 
  }
240
 
 
241
 
  grub_macho32_cmds_iterate (macho, do_load, 0);
242
 
 
243
 
  return err;
244
 
}
245
 
 
246
 
grub_uint32_t
247
 
grub_macho32_get_entry_point (grub_macho_t macho)
248
 
{
249
 
  grub_uint32_t entry_point = 0;
250
 
  auto int NESTED_FUNC_ATTR hook(grub_macho_t _macho,
251
 
                               struct grub_macho_cmd *hdr,
252
 
                               void UNUSED *_arg);
253
 
  int NESTED_FUNC_ATTR hook(grub_macho_t UNUSED _macho,
254
 
                               struct grub_macho_cmd *hdr,
255
 
                               void UNUSED *_arg)
256
 
  {
257
 
    if (hdr->cmd == GRUB_MACHO_CMD_THREAD)
258
 
      entry_point = ((struct grub_macho_thread32 *) hdr)->entry_point;
259
 
    return 0;
260
 
  }
261
 
  grub_macho32_cmds_iterate (macho, hook, 0);
262
 
  return entry_point;
263
 
}
264
 
 
265
 
 
266
33
grub_err_t
267
34
grub_macho_close (grub_macho_t macho)
268
35
{
304
71
      != sizeof (filestart))
305
72
    {
306
73
      grub_error_push ();
307
 
      grub_error (GRUB_ERR_READ_ERROR, "Cannot read Mach-O header.");
 
74
      grub_error (GRUB_ERR_READ_ERROR, "cannot read Mach-O header");
308
75
      goto fail;
309
76
    }
310
77
 
328
95
        {
329
96
          grub_free (archs);
330
97
          grub_error_push ();
331
 
          grub_error (GRUB_ERR_READ_ERROR, "Cannot read Mach-O header.");
 
98
          grub_error (GRUB_ERR_READ_ERROR, "cannot read Mach-O header");
332
99
          goto fail;
333
100
        }
334
101
 
367
134
    }
368
135
 
369
136
  grub_macho_parse32 (macho);
370
 
  /* FIXME: implement 64-bit.*/
371
 
  /*  grub_macho_parse64 (macho); */
 
137
  grub_macho_parse64 (macho);
372
138
 
373
139
  return macho;
374
140