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

« back to all changes in this revision

Viewing changes to fs/fshelp.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Evan Broder, Mario Limonciello
  • Date: 2010-11-24 13:59:55 UTC
  • mfrom: (1.17.6 upstream) (17.6.15 experimental)
  • Revision ID: james.westby@ubuntu.com-20101124135955-r6ii5sepayr7jt53
Tags: 1.99~20101124-1ubuntu1
[ Colin Watson ]
* Resynchronise with Debian experimental.  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.
  - 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.
  - Suppress progress messages as the kernel and initrd load for
    non-recovery kernel menu entries.
  - 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.
  - Don't generate /boot/grub/device.map during grub-install or
    grub-mkconfig by default.
  - Adjust upgrade version checks for Ubuntu.
  - Don't display "GRUB loading" unless Shift is held down.
  - Adjust versions of grub-doc and grub-legacy-doc conflicts to tolerate
    our backport of the grub-doc split.
  - Fix LVM/RAID probing in the absence of /boot/grub/device.map.
  - Look for .mo files in /usr/share/locale-langpack as well, in
    preference.
  - Make sure GRUB_TIMEOUT isn't quoted unnecessarily.
  - Probe all devices in 'grub-probe --target=drive' if
    /boot/grub/device.map is missing.
  - Build-depend on qemu-kvm rather than qemu-system for grub-pc tests.
  - Use qemu rather than qemu-system-i386.
  - Program vesafb on BIOS systems rather than efifb.
  - Add a grub-rescue-efi-amd64 package containing a rescue CD-ROM image
    for EFI-AMD64.
  - On Wubi, don't ask for an install device, but just update wubildr
    using the diverted grub-install.
  - When embedding the core image in a post-MBR gap, check for and avoid
    sectors matching any of a list of known signatures.
  - Disable video_bochs and video_cirrus on PC BIOS systems, as probing
    PCI space seems to break on some systems.
* Downgrade "ACPI shutdown failed" error to a debug message, since it can
  cause spurious test failures.

[ Evan Broder ]
* Enable lua from grub-extras.
* Incorporate the bitop library into lua.
* Add enum_pci function to grub module in lua.
* Switch back to gfxpayload=keep by default, unless the video hardware
  is known to not support it.

[ Mario Limonciello ]
* Built part_msdos and vfat into bootx64.efi (LP: #677758)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* fshelp.c -- Filesystem helper functions */
2
 
/*
3
 
 *  GRUB  --  GRand Unified Bootloader
4
 
 *  Copyright (C) 2004,2005,2006,2007,2008  Free Software Foundation, Inc.
5
 
 *
6
 
 *  GRUB is free software: you can redistribute it and/or modify
7
 
 *  it under the terms of the GNU General Public License as published by
8
 
 *  the Free Software Foundation, either version 3 of the License, or
9
 
 *  (at your option) any later version.
10
 
 *
11
 
 *  GRUB is distributed in the hope that it will be useful,
12
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
 *  GNU General Public License for more details.
15
 
 *
16
 
 *  You should have received a copy of the GNU General Public License
17
 
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
18
 
 */
19
 
 
20
 
#include <grub/err.h>
21
 
#include <grub/mm.h>
22
 
#include <grub/misc.h>
23
 
#include <grub/disk.h>
24
 
#include <grub/fshelp.h>
25
 
 
26
 
 
27
 
/* Lookup the node PATH.  The node ROOTNODE describes the root of the
28
 
   directory tree.  The node found is returned in FOUNDNODE, which is
29
 
   either a ROOTNODE or a new malloc'ed node.  ITERATE_DIR is used to
30
 
   iterate over all directory entries in the current node.
31
 
   READ_SYMLINK is used to read the symlink if a node is a symlink.
32
 
   EXPECTTYPE is the type node that is expected by the called, an
33
 
   error is generated if the node is not of the expected type.  Make
34
 
   sure you use the NESTED_FUNC_ATTR macro for HOOK, this is required
35
 
   because GCC has a nasty bug when using regparm=3.  */
36
 
grub_err_t
37
 
grub_fshelp_find_file (const char *path, grub_fshelp_node_t rootnode,
38
 
                       grub_fshelp_node_t *foundnode,
39
 
                       int (*iterate_dir) (grub_fshelp_node_t dir,
40
 
                                           int NESTED_FUNC_ATTR (*hook)
41
 
                                           (const char *filename,
42
 
                                            enum grub_fshelp_filetype filetype,
43
 
                                            grub_fshelp_node_t node)),
44
 
                       char *(*read_symlink) (grub_fshelp_node_t node),
45
 
                       enum grub_fshelp_filetype expecttype)
46
 
{
47
 
  grub_err_t err;
48
 
  enum grub_fshelp_filetype foundtype = GRUB_FSHELP_DIR;
49
 
  int symlinknest = 0;
50
 
 
51
 
  auto grub_err_t NESTED_FUNC_ATTR find_file (const char *currpath,
52
 
                                              grub_fshelp_node_t currroot,
53
 
                                              grub_fshelp_node_t *currfound);
54
 
 
55
 
  grub_err_t NESTED_FUNC_ATTR find_file (const char *currpath,
56
 
                                         grub_fshelp_node_t currroot,
57
 
                                         grub_fshelp_node_t *currfound)
58
 
    {
59
 
      char fpath[grub_strlen (currpath) + 1];
60
 
      char *name = fpath;
61
 
      char *next;
62
 
      //  unsigned int pos = 0;
63
 
      enum grub_fshelp_filetype type = GRUB_FSHELP_DIR;
64
 
      grub_fshelp_node_t currnode = currroot;
65
 
      grub_fshelp_node_t oldnode = currroot;
66
 
 
67
 
      auto int NESTED_FUNC_ATTR iterate (const char *filename,
68
 
                                         enum grub_fshelp_filetype filetype,
69
 
                                         grub_fshelp_node_t node);
70
 
 
71
 
      auto void free_node (grub_fshelp_node_t node);
72
 
 
73
 
      void free_node (grub_fshelp_node_t node)
74
 
        {
75
 
          if (node != rootnode && node != currroot)
76
 
            grub_free (node);
77
 
        }
78
 
 
79
 
      int NESTED_FUNC_ATTR iterate (const char *filename,
80
 
                                    enum grub_fshelp_filetype filetype,
81
 
                                    grub_fshelp_node_t node)
82
 
        {
83
 
          if (filetype == GRUB_FSHELP_UNKNOWN ||
84
 
              (grub_strcmp (name, filename) &&
85
 
               (! (filetype & GRUB_FSHELP_CASE_INSENSITIVE) ||
86
 
                grub_strncasecmp (name, filename, GRUB_LONG_MAX))))
87
 
            {
88
 
              grub_free (node);
89
 
              return 0;
90
 
            }
91
 
 
92
 
          /* The node is found, stop iterating over the nodes.  */
93
 
          type = filetype & ~GRUB_FSHELP_CASE_INSENSITIVE;
94
 
          oldnode = currnode;
95
 
          currnode = node;
96
 
 
97
 
          return 1;
98
 
        }
99
 
 
100
 
      grub_strncpy (fpath, currpath, grub_strlen (currpath) + 1);
101
 
 
102
 
      /* Remove all leading slashes.  */
103
 
      while (*name == '/')
104
 
        name++;
105
 
 
106
 
      if (! *name)
107
 
        {
108
 
          *currfound = currnode;
109
 
          return 0;
110
 
        }
111
 
 
112
 
      for (;;)
113
 
        {
114
 
          int found;
115
 
 
116
 
          /* Extract the actual part from the pathname.  */
117
 
          next = grub_strchr (name, '/');
118
 
          if (next)
119
 
            {
120
 
              /* Remove all leading slashes.  */
121
 
              while (*next == '/')
122
 
                *(next++) = '\0';
123
 
            }
124
 
 
125
 
          /* At this point it is expected that the current node is a
126
 
             directory, check if this is true.  */
127
 
          if (type != GRUB_FSHELP_DIR)
128
 
            {
129
 
              free_node (currnode);
130
 
              return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
131
 
            }
132
 
 
133
 
          /* Iterate over the directory.  */
134
 
          found = iterate_dir (currnode, iterate);
135
 
          if (! found)
136
 
            {
137
 
              if (grub_errno)
138
 
                return grub_errno;
139
 
 
140
 
              break;
141
 
            }
142
 
 
143
 
          /* Read in the symlink and follow it.  */
144
 
          if (type == GRUB_FSHELP_SYMLINK)
145
 
            {
146
 
              char *symlink;
147
 
 
148
 
              /* Test if the symlink does not loop.  */
149
 
              if (++symlinknest == 8)
150
 
                {
151
 
                  free_node (currnode);
152
 
                  free_node (oldnode);
153
 
                  return grub_error (GRUB_ERR_SYMLINK_LOOP,
154
 
                                     "too deep nesting of symlinks");
155
 
                }
156
 
 
157
 
              symlink = read_symlink (currnode);
158
 
              free_node (currnode);
159
 
 
160
 
              if (!symlink)
161
 
                {
162
 
                  free_node (oldnode);
163
 
                  return grub_errno;
164
 
                }
165
 
 
166
 
              /* The symlink is an absolute path, go back to the root inode.  */
167
 
              if (symlink[0] == '/')
168
 
                {
169
 
                  free_node (oldnode);
170
 
                  oldnode = rootnode;
171
 
                }
172
 
 
173
 
              /* Lookup the node the symlink points to.  */
174
 
              find_file (symlink, oldnode, &currnode);
175
 
              type = foundtype;
176
 
              grub_free (symlink);
177
 
 
178
 
              if (grub_errno)
179
 
                {
180
 
                  free_node (oldnode);
181
 
                  return grub_errno;
182
 
                }
183
 
            }
184
 
 
185
 
          free_node (oldnode);
186
 
 
187
 
          /* Found the node!  */
188
 
          if (! next || *next == '\0')
189
 
            {
190
 
              *currfound = currnode;
191
 
              foundtype = type;
192
 
              return 0;
193
 
            }
194
 
 
195
 
          name = next;
196
 
        }
197
 
 
198
 
      return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
199
 
    }
200
 
 
201
 
  if (!path || path[0] != '/')
202
 
    {
203
 
      grub_error (GRUB_ERR_BAD_FILENAME, "bad filename");
204
 
      return grub_errno;
205
 
    }
206
 
 
207
 
  err = find_file (path, rootnode, foundnode);
208
 
  if (err)
209
 
    return err;
210
 
 
211
 
  /* Check if the node that was found was of the expected type.  */
212
 
  if (expecttype == GRUB_FSHELP_REG && foundtype != expecttype)
213
 
    return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a regular file");
214
 
  else if (expecttype == GRUB_FSHELP_DIR && foundtype != expecttype)
215
 
    return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
216
 
 
217
 
  return 0;
218
 
}
219
 
 
220
 
/* Read LEN bytes from the file NODE on disk DISK into the buffer BUF,
221
 
   beginning with the block POS.  READ_HOOK should be set before
222
 
   reading a block from the file.  GET_BLOCK is used to translate file
223
 
   blocks to disk blocks.  The file is FILESIZE bytes big and the
224
 
   blocks have a size of LOG2BLOCKSIZE (in log2).  */
225
 
grub_ssize_t
226
 
grub_fshelp_read_file (grub_disk_t disk, grub_fshelp_node_t node,
227
 
                       void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
228
 
                                                           unsigned offset,
229
 
                                                           unsigned length),
230
 
                       grub_off_t pos, grub_size_t len, char *buf,
231
 
                       grub_disk_addr_t (*get_block) (grub_fshelp_node_t node,
232
 
                                                      grub_disk_addr_t block),
233
 
                       grub_off_t filesize, int log2blocksize)
234
 
{
235
 
  grub_disk_addr_t i, blockcnt;
236
 
  int blocksize = 1 << (log2blocksize + GRUB_DISK_SECTOR_BITS);
237
 
 
238
 
  /* Adjust LEN so it we can't read past the end of the file.  */
239
 
  if (pos + len > filesize)
240
 
    len = filesize - pos;
241
 
 
242
 
  blockcnt = ((len + pos) + blocksize - 1) >> (log2blocksize + GRUB_DISK_SECTOR_BITS);
243
 
 
244
 
  for (i = pos >> (log2blocksize + GRUB_DISK_SECTOR_BITS); i < blockcnt; i++)
245
 
    {
246
 
      grub_disk_addr_t blknr;
247
 
      int blockoff = pos & (blocksize - 1);
248
 
      int blockend = blocksize;
249
 
 
250
 
      int skipfirst = 0;
251
 
 
252
 
      blknr = get_block (node, i);
253
 
      if (grub_errno)
254
 
        return -1;
255
 
 
256
 
      blknr = blknr << log2blocksize;
257
 
 
258
 
      /* Last block.  */
259
 
      if (i == blockcnt - 1)
260
 
        {
261
 
          blockend = (len + pos) & (blocksize - 1);
262
 
 
263
 
          /* The last portion is exactly blocksize.  */
264
 
          if (! blockend)
265
 
            blockend = blocksize;
266
 
        }
267
 
 
268
 
      /* First block.  */
269
 
      if (i == (pos >> (log2blocksize + GRUB_DISK_SECTOR_BITS)))
270
 
        {
271
 
          skipfirst = blockoff;
272
 
          blockend -= skipfirst;
273
 
        }
274
 
 
275
 
      /* If the block number is 0 this block is not stored on disk but
276
 
         is zero filled instead.  */
277
 
      if (blknr)
278
 
        {
279
 
          disk->read_hook = read_hook;
280
 
 
281
 
          grub_disk_read (disk, blknr, skipfirst,
282
 
                          blockend, buf);
283
 
          disk->read_hook = 0;
284
 
          if (grub_errno)
285
 
            return -1;
286
 
        }
287
 
      else
288
 
        grub_memset (buf, 0, blockend);
289
 
 
290
 
      buf += blocksize - skipfirst;
291
 
    }
292
 
 
293
 
  return len;
294
 
}
295
 
 
296
 
unsigned int
297
 
grub_fshelp_log2blksize (unsigned int blksize, unsigned int *pow)
298
 
{
299
 
  int mod;
300
 
 
301
 
  *pow = 0;
302
 
  while (blksize > 1)
303
 
    {
304
 
      mod = blksize - ((blksize >> 1) << 1);
305
 
      blksize >>= 1;
306
 
 
307
 
      /* Check if it really is a power of two.  */
308
 
      if (mod)
309
 
        return grub_error (GRUB_ERR_BAD_NUMBER,
310
 
                           "the blocksize is not a power of two");
311
 
      (*pow)++;
312
 
    }
313
 
 
314
 
  return GRUB_ERR_NONE;
315
 
}