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

« back to all changes in this revision

Viewing changes to loader/machoXX.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:
 
1
 
 
2
#include <grub/file.h>
 
3
#include <grub/mm.h>
 
4
#include <grub/misc.h>
 
5
 
 
6
#define min(a,b) (((a) < (b)) ? (a) : (b))
 
7
 
 
8
int
 
9
SUFFIX (grub_macho_contains_macho) (grub_macho_t macho)
 
10
{
 
11
  return macho->offsetXX != -1;
 
12
}
 
13
 
 
14
void
 
15
SUFFIX (grub_macho_parse) (grub_macho_t macho)
 
16
{
 
17
  grub_macho_header_t head;
 
18
 
 
19
  /* Is there any candidate at all? */
 
20
  if (macho->offsetXX == -1)
 
21
    return;
 
22
 
 
23
  /* Read header and check magic*/
 
24
  if (grub_file_seek (macho->file, macho->offsetXX) == (grub_off_t) -1
 
25
      || grub_file_read (macho->file, &head, sizeof (head))
 
26
      != sizeof(head))
 
27
    {
 
28
      grub_error (GRUB_ERR_READ_ERROR, "cannot read Mach-O header");
 
29
      macho->offsetXX = -1;
 
30
      return;
 
31
    }
 
32
  if (head.magic != GRUB_MACHO_MAGIC)
 
33
    {
 
34
      grub_error (GRUB_ERR_BAD_OS, "invalid Mach-O " XX "-bit header");
 
35
      macho->offsetXX = -1;
 
36
      return;
 
37
    }
 
38
 
 
39
  /* Read commands. */
 
40
  macho->ncmdsXX = head.ncmds;
 
41
  macho->cmdsizeXX = head.sizeofcmds;
 
42
  macho->cmdsXX = grub_malloc(macho->cmdsizeXX);
 
43
  if (! macho->cmdsXX)
 
44
    {
 
45
      grub_error (GRUB_ERR_OUT_OF_MEMORY, "not enough memory to read commands");
 
46
      return;
 
47
    }
 
48
  if (grub_file_read (macho->file, macho->cmdsXX,
 
49
                      (grub_size_t) macho->cmdsizeXX)
 
50
      != (grub_ssize_t) macho->cmdsizeXX)
 
51
    {
 
52
      grub_error (GRUB_ERR_READ_ERROR, "cannot read Mach-O header");
 
53
      macho->offsetXX = -1;
 
54
    }
 
55
}
 
56
 
 
57
typedef int NESTED_FUNC_ATTR (*grub_macho_iter_hook_t)
 
58
(grub_macho_t , struct grub_macho_cmd *,
 
59
               void *);
 
60
 
 
61
static grub_err_t
 
62
grub_macho_cmds_iterate (grub_macho_t macho,
 
63
                         grub_macho_iter_hook_t hook,
 
64
                         void *hook_arg)
 
65
{
 
66
  grub_uint8_t *hdrs = macho->cmdsXX;
 
67
  int i;
 
68
  if (! macho->cmdsXX)
 
69
    return grub_error (GRUB_ERR_BAD_OS, "couldn't find " XX "-bit Mach-O");
 
70
  for (i = 0; i < macho->ncmdsXX; i++)
 
71
    {
 
72
      struct grub_macho_cmd *hdr = (struct grub_macho_cmd *) hdrs;
 
73
      if (hook (macho, hdr, hook_arg))
 
74
        break;
 
75
      hdrs += hdr->cmdsize;
 
76
    }
 
77
 
 
78
  return grub_errno;
 
79
}
 
80
 
 
81
grub_size_t
 
82
SUFFIX (grub_macho_filesize) (grub_macho_t macho)
 
83
{
 
84
  if (SUFFIX (grub_macho_contains_macho) (macho))
 
85
    return macho->endXX - macho->offsetXX;
 
86
  return 0;
 
87
}
 
88
 
 
89
grub_err_t
 
90
SUFFIX (grub_macho_readfile) (grub_macho_t macho, void *dest)
 
91
{
 
92
  grub_ssize_t read;
 
93
  if (! SUFFIX (grub_macho_contains_macho) (macho))
 
94
    return grub_error (GRUB_ERR_BAD_OS,
 
95
                       "couldn't read architecture-specific part");
 
96
 
 
97
  if (grub_file_seek (macho->file, macho->offsetXX) == (grub_off_t) -1)
 
98
    {
 
99
      grub_error_push ();
 
100
      return grub_error (GRUB_ERR_BAD_OS,
 
101
                         "invalid offset in program header");
 
102
    }
 
103
 
 
104
  read = grub_file_read (macho->file, dest,
 
105
                         macho->endXX - macho->offsetXX);
 
106
  if (read != (grub_ssize_t) (macho->endXX - macho->offsetXX))
 
107
    {
 
108
      grub_error_push ();
 
109
      return grub_error (GRUB_ERR_BAD_OS,
 
110
                         "couldn't read architecture-specific part");
 
111
    }
 
112
  return GRUB_ERR_NONE;
 
113
}
 
114
 
 
115
/* Calculate the amount of memory spanned by the segments. */
 
116
grub_err_t
 
117
SUFFIX (grub_macho_size) (grub_macho_t macho, grub_macho_addr_t *segments_start,
 
118
                          grub_macho_addr_t *segments_end, int flags)
 
119
{
 
120
  int nr_phdrs = 0;
 
121
 
 
122
  /* Run through the program headers to calculate the total memory size we
 
123
     should claim.  */
 
124
  auto int NESTED_FUNC_ATTR calcsize (grub_macho_t _macho,
 
125
                                      struct grub_macho_cmd *phdr, void *_arg);
 
126
  int NESTED_FUNC_ATTR calcsize (grub_macho_t _macho __attribute__ ((unused)),
 
127
                                 struct grub_macho_cmd *hdr0,
 
128
                                 void *_arg __attribute__ ((unused)))
 
129
    {
 
130
      grub_macho_segment_t *hdr = (grub_macho_segment_t *) hdr0;
 
131
      if (hdr->cmd != GRUB_MACHO_CMD_SEGMENT)
 
132
        return 0;
 
133
 
 
134
      if (! hdr->vmsize)
 
135
        return 0;
 
136
 
 
137
      if (! hdr->filesize && (flags & GRUB_MACHO_NOBSS))
 
138
        return 0;
 
139
 
 
140
      nr_phdrs++;
 
141
      if (hdr->vmaddr < *segments_start)
 
142
        *segments_start = hdr->vmaddr;
 
143
      if (hdr->vmaddr + hdr->vmsize > *segments_end)
 
144
        *segments_end = hdr->vmaddr + hdr->vmsize;
 
145
      return 0;
 
146
    }
 
147
 
 
148
  *segments_start = (grub_macho_addr_t) -1;
 
149
  *segments_end = 0;
 
150
 
 
151
  grub_macho_cmds_iterate (macho, calcsize, 0);
 
152
 
 
153
  if (nr_phdrs == 0)
 
154
    return grub_error (GRUB_ERR_BAD_OS, "no program headers present");
 
155
 
 
156
  if (*segments_end < *segments_start)
 
157
    /* Very bad addresses.  */
 
158
    return grub_error (GRUB_ERR_BAD_OS, "bad program header load addresses");
 
159
 
 
160
  return GRUB_ERR_NONE;
 
161
}
 
162
 
 
163
/* Load every loadable segment into memory specified by `_load_hook'.  */
 
164
grub_err_t
 
165
SUFFIX (grub_macho_load) (grub_macho_t macho, char *offset, int flags)
 
166
{
 
167
  grub_err_t err = 0;
 
168
  auto int NESTED_FUNC_ATTR do_load(grub_macho_t _macho,
 
169
                               struct grub_macho_cmd *hdr0,
 
170
                               void *_arg __attribute__ ((unused)));
 
171
  int NESTED_FUNC_ATTR do_load(grub_macho_t _macho,
 
172
                               struct grub_macho_cmd *hdr0,
 
173
                               void *_arg __attribute__ ((unused)))
 
174
  {
 
175
    grub_macho_segment_t *hdr = (grub_macho_segment_t *) hdr0;
 
176
 
 
177
    if (hdr->cmd != GRUB_MACHO_CMD_SEGMENT)
 
178
      return 0;
 
179
 
 
180
    if (! hdr->filesize && (flags & GRUB_MACHO_NOBSS))
 
181
      return 0;
 
182
    if (! hdr->vmsize)
 
183
      return 0;
 
184
 
 
185
    if (grub_file_seek (_macho->file, hdr->fileoff
 
186
                        + _macho->offsetXX) == (grub_off_t) -1)
 
187
      {
 
188
        grub_error_push ();
 
189
        grub_error (GRUB_ERR_BAD_OS,
 
190
                    "invalid offset in program header");
 
191
        return 1;
 
192
      }
 
193
 
 
194
    if (hdr->filesize)
 
195
      {
 
196
        grub_ssize_t read;
 
197
        read = grub_file_read (_macho->file, offset + hdr->vmaddr,
 
198
                                   min (hdr->filesize, hdr->vmsize));
 
199
        if (read != (grub_ssize_t) min (hdr->filesize, hdr->vmsize))
 
200
          {
 
201
            /* XXX How can we free memory from `load_hook'? */
 
202
            grub_error_push ();
 
203
            err=grub_error (GRUB_ERR_BAD_OS,
 
204
                            "couldn't read segment from file: "
 
205
                            "wanted 0x%lx bytes; read 0x%lx bytes",
 
206
                            hdr->filesize, read);
 
207
            return 1;
 
208
          }
 
209
      }
 
210
 
 
211
    if (hdr->filesize < hdr->vmsize)
 
212
      grub_memset (offset + hdr->vmaddr + hdr->filesize,
 
213
                   0, hdr->vmsize - hdr->filesize);
 
214
    return 0;
 
215
  }
 
216
 
 
217
  grub_macho_cmds_iterate (macho, do_load, 0);
 
218
 
 
219
  return err;
 
220
}
 
221
 
 
222
grub_macho_addr_t
 
223
SUFFIX (grub_macho_get_entry_point) (grub_macho_t macho)
 
224
{
 
225
  grub_macho_addr_t entry_point = 0;
 
226
  auto int NESTED_FUNC_ATTR hook(grub_macho_t _macho,
 
227
                                 struct grub_macho_cmd *hdr,
 
228
                                 void *_arg __attribute__ ((unused)));
 
229
  int NESTED_FUNC_ATTR hook(grub_macho_t _macho __attribute__ ((unused)),
 
230
                            struct grub_macho_cmd *hdr,
 
231
                            void *_arg __attribute__ ((unused)))
 
232
  {
 
233
    if (hdr->cmd == GRUB_MACHO_CMD_THREAD)
 
234
      entry_point = ((grub_macho_thread_t *) hdr)->entry_point;
 
235
    return 0;
 
236
  }
 
237
  grub_macho_cmds_iterate (macho, hook, 0);
 
238
  return entry_point;
 
239
}