Пример #1
0
static grub_err_t
grub_cpio_find_file (struct grub_archelp_data *data, char **name,
		     grub_int32_t *mtime,
		     grub_uint32_t *mode)
{
  struct head hd;
  int reread = 0, have_longname = 0, have_longlink = 0;

  data->hofs = data->next_hofs;

  for (reread = 0; reread < 3; reread++)
    {
      if (grub_disk_read (data->disk, 0, data->hofs, sizeof (hd), &hd))
	return grub_errno;

      if (!hd.name[0] && !hd.prefix[0])
	{
	  *mode = GRUB_ARCHELP_ATTR_END;
	  return GRUB_ERR_NONE;
	}

      if (grub_memcmp (hd.magic, MAGIC, sizeof (MAGIC) - 1))
	return grub_error (GRUB_ERR_BAD_FS, "invalid tar archive");

      if (hd.typeflag == 'L')
	{
	  grub_err_t err;
	  grub_size_t namesize = read_number (hd.size, sizeof (hd.size));
	  *name = grub_malloc (namesize + 1);
	  if (*name == NULL)
	    return grub_errno;
	  err = grub_disk_read (data->disk, 0,
				data->hofs + GRUB_DISK_SECTOR_SIZE, namesize,
				*name);
	  (*name)[namesize] = 0;
	  if (err)
	    return err;
	  data->hofs += GRUB_DISK_SECTOR_SIZE
	    + ((namesize + GRUB_DISK_SECTOR_SIZE - 1) &
	       ~(GRUB_DISK_SECTOR_SIZE - 1));
	  have_longname = 1;
	  continue;
	}

      if (hd.typeflag == 'K')
	{
	  grub_err_t err;
	  grub_size_t linksize = read_number (hd.size, sizeof (hd.size));
	  if (data->linkname_alloc < linksize + 1)
	    {
	      char *n;
	      n = grub_malloc (2 * (linksize + 1));
	      if (!n)
		return grub_errno;
	      grub_free (data->linkname);
	      data->linkname = n;
	      data->linkname_alloc = 2 * (linksize + 1);
	    }

	  err = grub_disk_read (data->disk, 0,
				data->hofs + GRUB_DISK_SECTOR_SIZE, linksize,
				data->linkname);
	  if (err)
	    return err;
	  data->linkname[linksize] = 0;
	  data->hofs += GRUB_DISK_SECTOR_SIZE
	    + ((linksize + GRUB_DISK_SECTOR_SIZE - 1) &
	       ~(GRUB_DISK_SECTOR_SIZE - 1));
	  have_longlink = 1;
	  continue;
	}

      if (!have_longname)
	{
	  grub_size_t extra_size = 0;

	  while (extra_size < sizeof (hd.prefix)
		 && hd.prefix[extra_size])
	    extra_size++;
	  *name = grub_malloc (sizeof (hd.name) + extra_size + 2);
	  if (*name == NULL)
	    return grub_errno;
	  if (hd.prefix[0])
	    {
	      grub_memcpy (*name, hd.prefix, extra_size);
	      (*name)[extra_size++] = '/';
	    }
	  grub_memcpy (*name + extra_size, hd.name, sizeof (hd.name));
	  (*name)[extra_size + sizeof (hd.name)] = 0;
	}

      data->size = read_number (hd.size, sizeof (hd.size));
      data->dofs = data->hofs + GRUB_DISK_SECTOR_SIZE;
      data->next_hofs = data->dofs + ((data->size + GRUB_DISK_SECTOR_SIZE - 1) &
			   ~(GRUB_DISK_SECTOR_SIZE - 1));
      if (mtime)
	*mtime = read_number (hd.mtime, sizeof (hd.mtime));
      if (mode)
	{
	  *mode = read_number (hd.mode, sizeof (hd.mode));
	  switch (hd.typeflag)
	    {
	      /* Hardlink.  */
	    case '1':
	      /* Symlink.  */
	    case '2':
	      *mode |= GRUB_ARCHELP_ATTR_LNK;
	      break;
	    case '0':
	      *mode |= GRUB_ARCHELP_ATTR_FILE;
	      break;
	    case '5':
	      *mode |= GRUB_ARCHELP_ATTR_DIR;
	      break;
	    }
	}
      if (!have_longlink)
	{
	  if (data->linkname_alloc < 101)
	    {
	      char *n;
	      n = grub_malloc (101);
	      if (!n)
		return grub_errno;
	      grub_free (data->linkname);
	      data->linkname = n;
	      data->linkname_alloc = 101;
	    }
	  grub_memcpy (data->linkname, hd.linkname, sizeof (hd.linkname));
	  data->linkname[100] = 0;
	}
      return GRUB_ERR_NONE;
    }
  return GRUB_ERR_NONE;
}
Пример #2
0
static grub_err_t
grub_raid6_recover (struct grub_raid_array *array, int disknr, int p,
                    char *buf, grub_disk_addr_t sector, int size)
{
  int i, q, pos;
  int err[2], nerr;
  char *pbuf = 0, *qbuf = 0;

  size <<= GRUB_DISK_SECTOR_BITS;
  pbuf = grub_malloc (size);
  if (!pbuf)
    goto quit;

  qbuf = grub_malloc (size);
  if (!qbuf)
    goto quit;

  q = p + 1;
  if (q == (int) array->total_devs)
    q = 0;

  grub_memset (pbuf, 0, size);
  grub_memset (qbuf, 0, size);

  pos = q + 1;
  if (pos == (int) array->total_devs)
    pos = 0;

  nerr = 1;
  for (i = 0; i < (int) array->total_devs - 2; i++)
    {
      if (pos == disknr)
        err[0] = i;
      else
        {
          if ((array->device[pos]) &&
              (! grub_disk_read (array->device[pos], sector, 0, size, buf)))
            {
              grub_raid_block_xor (pbuf, buf, size);
              grub_raid_block_mul (raid6_table2[i][i], buf, size);
              grub_raid_block_xor (qbuf, buf, size);
            }
          else
            {
              if (nerr >= 2)
                goto quit;

              err[nerr++] = i;
              grub_errno = GRUB_ERR_NONE;
            }
        }

      pos++;
      if (pos == (int) array->total_devs)
        pos = 0;
    }

  if (nerr == 1)
    {
      if ((array->device[p]) &&
          (! grub_disk_read (array->device[p], sector, 0, size, buf)))
        {
          grub_raid_block_xor (buf, pbuf, size);
          goto quit;
        }

      if (! array->device[q])
        {
          grub_error (GRUB_ERR_READ_ERROR, "Not enough disk to restore");
          goto quit;
        }

      grub_errno = GRUB_ERR_NONE;
      if (grub_disk_read (array->device[q], sector, 0, size, buf))
        goto quit;

      grub_raid_block_xor (buf, qbuf, size);
      grub_raid_block_mul (raid6_table2[255 - err[0]][255 - err[0]], buf,
                           size);
    }
  else
    {
      grub_uint8_t c;

      if ((! array->device[p]) || (! array->device[q]))
        {
          grub_error (GRUB_ERR_READ_ERROR, "Not enough disk to restore");
          goto quit;
        }

      if (grub_disk_read (array->device[p], sector, 0, size, buf))
        goto quit;

      grub_raid_block_xor (pbuf, buf, size);

      if (grub_disk_read (array->device[q], sector, 0, size, buf))
        goto quit;

      grub_raid_block_xor (qbuf, buf, size);

      c = raid6_table2[err[1]][err[0]];
      grub_raid_block_mul (c, qbuf, size);

      c = raid6_table1[raid6_table2[err[1]][err[1]]][c];
      grub_raid_block_mul (c, pbuf, size);

      grub_raid_block_xor (pbuf, qbuf, size);
      grub_memcpy (buf, pbuf, size);
    }

quit:
  grub_free (pbuf);
  grub_free (qbuf);

  return grub_errno;
}
Пример #3
0
grub_command_t
grub_register_command (const char *name,
		       grub_err_t (*func) (struct grub_arg_list *state,
					   int argc, char **args),
		       unsigned flags,
		       const char *summary,
		       const char *description,
		       const struct grub_arg_option *options)
{
  grub_command_t cmd, *p;

  cmd = (grub_command_t) grub_malloc (sizeof (*cmd));
  if (! cmd)
    return 0;

  cmd->name = grub_strdup (name);
  if (! cmd->name)
    {
      grub_free (cmd);
      return 0;
    }
  
  cmd->func = func;
  cmd->flags = flags;
  cmd->summary = summary;
  cmd->description = description;
  cmd->options = options;
  cmd->module_name = 0;

  /* Keep the list sorted for simplicity.  */
  p = &grub_command_list;
  while (*p)
    {
      if (grub_strcmp ((*p)->name, name) >= 0)
	break;

      p = &((*p)->next);
    }

  if (*p && grub_strcmp ((*p)->name, name) == 0)
    {
      grub_command_t q;

      q = *p;
      if (q->flags & GRUB_COMMAND_FLAG_NOT_LOADED)
	{
	  q->func = cmd->func;
	  q->flags = cmd->flags;
	  q->summary = cmd->summary;
	  q->description = cmd->description;
	  q->options = cmd->options;
	  grub_free (cmd->name);
	  grub_free (cmd->module_name);
	  grub_free (cmd);
	  cmd = q;
	}
      else
	{
	  grub_free (cmd->name);
	  grub_free (cmd);
	  cmd = 0;
	}
    }
  else
    {
      cmd->next = *p;
      *p = cmd;
    }

  return cmd;
}
Пример #4
0
static int
grub_ext2_iterate_dir (grub_fshelp_node_t dir,
		       int NESTED_FUNC_ATTR
		       (*hook) (const char *filename,
				enum grub_fshelp_filetype filetype,
				grub_fshelp_node_t node))
{
  unsigned int fpos = 0;
  struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir;

  if (! diro->inode_read)
    {
      grub_ext2_read_inode (diro->data, diro->ino, &diro->inode);
      if (grub_errno)
	return 0;
    }

  /* Search the file.  */
  while (fpos < grub_le_to_cpu32 (diro->inode.size))
    {
      struct ext2_dirent dirent;

      grub_ext2_read_file (diro, 0, fpos, sizeof (struct ext2_dirent),
			   (char *) &dirent);
      if (grub_errno)
	return 0;

      if (dirent.direntlen == 0)
        return 0;

      if (dirent.namelen != 0)
	{
	  char filename[dirent.namelen + 1];
	  struct grub_fshelp_node *fdiro;
	  enum grub_fshelp_filetype type = GRUB_FSHELP_UNKNOWN;

	  grub_ext2_read_file (diro, 0, fpos + sizeof (struct ext2_dirent),
			       dirent.namelen, filename);
	  if (grub_errno)
	    return 0;

	  fdiro = grub_malloc (sizeof (struct grub_fshelp_node));
	  if (! fdiro)
	    return 0;

	  fdiro->data = diro->data;
	  fdiro->ino = grub_le_to_cpu32 (dirent.inode);

	  filename[dirent.namelen] = '\0';

	  if (dirent.filetype != FILETYPE_UNKNOWN)
	    {
	      fdiro->inode_read = 0;

	      if (dirent.filetype == FILETYPE_DIRECTORY)
		type = GRUB_FSHELP_DIR;
	      else if (dirent.filetype == FILETYPE_SYMLINK)
		type = GRUB_FSHELP_SYMLINK;
	      else if (dirent.filetype == FILETYPE_REG)
		type = GRUB_FSHELP_REG;
	    }
	  else
	    {
	      /* The filetype can not be read from the dirent, read
		 the inode to get more information.  */
	      grub_ext2_read_inode (diro->data,
                                    grub_le_to_cpu32 (dirent.inode),
				    &fdiro->inode);
	      if (grub_errno)
		{
		  grub_free (fdiro);
		  return 0;
		}

	      fdiro->inode_read = 1;

	      if ((grub_le_to_cpu16 (fdiro->inode.mode)
		   & FILETYPE_INO_MASK) == FILETYPE_INO_DIRECTORY)
		type = GRUB_FSHELP_DIR;
	      else if ((grub_le_to_cpu16 (fdiro->inode.mode)
			& FILETYPE_INO_MASK) == FILETYPE_INO_SYMLINK)
		type = GRUB_FSHELP_SYMLINK;
	      else if ((grub_le_to_cpu16 (fdiro->inode.mode)
			& FILETYPE_INO_MASK) == FILETYPE_INO_REG)
		type = GRUB_FSHELP_REG;
	    }

	  if (hook (filename, type, fdiro))
	    return 1;
	}

      fpos += grub_le_to_cpu16 (dirent.direntlen);
    }

  return 0;
}
Пример #5
0
static grub_err_t
grub_cbfs_find_file (struct grub_archelp_data *data, char **name,
		     grub_int32_t *mtime,
		     grub_uint32_t *mode)
{
  grub_size_t offset;
  for (;;
       data->dofs = data->hofs + offset,
	 data->next_hofs = ALIGN_UP (data->dofs + data->size, data->cbfs_align))
    {
      struct cbfs_file hd;
      grub_size_t namesize;

      data->hofs = data->next_hofs;

      if (data->hofs >= data->cbfs_end)
	{
	  *mode = GRUB_ARCHELP_ATTR_END;
	  return GRUB_ERR_NONE;
	}

      if (grub_disk_read (data->disk, 0, data->hofs, sizeof (hd), &hd))
	return grub_errno;

      if (grub_memcmp (hd.magic, CBFS_FILE_MAGIC, sizeof (hd.magic)) != 0)
	{
	  *mode = GRUB_ARCHELP_ATTR_END;
	  return GRUB_ERR_NONE;
	}
      data->size = grub_be_to_cpu32 (hd.len);
      (void) mtime;
      offset = grub_be_to_cpu32 (hd.offset);

      *mode = GRUB_ARCHELP_ATTR_FILE | GRUB_ARCHELP_ATTR_NOTIME;

      namesize = offset;
      if (namesize >= sizeof (hd))
	namesize -= sizeof (hd);
      if (namesize == 0)
	continue;
      *name = grub_malloc (namesize + 1);
      if (*name == NULL)
	return grub_errno;

      if (grub_disk_read (data->disk, 0, data->hofs + sizeof (hd),
			  namesize, *name))
	{
	  grub_free (*name);
	  return grub_errno;
	}

      if ((*name)[0] == '\0')
	{
	  grub_free (*name);
	  *name = NULL;
	  continue;
	}

      (*name)[namesize] = 0;

      data->dofs = data->hofs + offset;
      data->next_hofs = ALIGN_UP (data->dofs + data->size, data->cbfs_align);
      return GRUB_ERR_NONE;
    }
}
Пример #6
0
grub_err_t
grub_multiboot_load (grub_file_t file)
{
  char *buffer;
  grub_ssize_t len;
  struct multiboot_header *header;
  grub_err_t err;

  buffer = grub_malloc (MULTIBOOT_SEARCH);
  if (!buffer)
    return grub_errno;

  len = grub_file_read (file, buffer, MULTIBOOT_SEARCH);
  if (len < 32)
    {
      grub_free (buffer);
      return grub_error (GRUB_ERR_BAD_OS, "file too small");
    }

  /* Look for the multiboot header in the buffer.  The header should
     be at least 12 bytes and aligned on a 4-byte boundary.  */
  for (header = (struct multiboot_header *) buffer;
       ((char *) header <= buffer + len - 12) || (header = 0);
       header = (struct multiboot_header *) ((char *) header + MULTIBOOT_HEADER_ALIGN))
    {
      if (header->magic == MULTIBOOT_HEADER_MAGIC
	  && !(header->magic + header->flags + header->checksum))
	break;
    }

  if (header == 0)
    {
      grub_free (buffer);
      return grub_error (GRUB_ERR_BAD_ARGUMENT, "no multiboot header found");
    }

  if (header->flags & UNSUPPORTED_FLAGS)
    {
      grub_free (buffer);
      return grub_error (GRUB_ERR_UNKNOWN_OS,
			 "unsupported flag: 0x%x", header->flags);
    }

  if (header->flags & MULTIBOOT_AOUT_KLUDGE)
    {
      int offset = ((char *) header - buffer -
		    (header->header_addr - header->load_addr));
      int load_size = ((header->load_end_addr == 0) ? file->size - offset :
		       header->load_end_addr - header->load_addr);
      grub_size_t code_size;

      if (header->bss_end_addr)
	code_size = (header->bss_end_addr - header->load_addr);
      else
	code_size = load_size;
      grub_multiboot_payload_dest = header->load_addr;

      grub_multiboot_pure_size += code_size;

      /* Allocate a bit more to avoid relocations in most cases.  */
      grub_multiboot_alloc_mbi = grub_multiboot_get_mbi_size () + 65536;
      grub_multiboot_payload_orig
	= grub_relocator32_alloc (grub_multiboot_pure_size + grub_multiboot_alloc_mbi);

      if (! grub_multiboot_payload_orig)
	{
	  grub_free (buffer);
	  return grub_errno;
	}

      if ((grub_file_seek (file, offset)) == (grub_off_t) -1)
	{
	  grub_free (buffer);
	  return grub_errno;
	}

      grub_file_read (file, (void *) grub_multiboot_payload_orig, load_size);
      if (grub_errno)
	{
	  grub_free (buffer);
	  return grub_errno;
	}

      if (header->bss_end_addr)
	grub_memset ((void *) (grub_multiboot_payload_orig + load_size), 0,
		     header->bss_end_addr - header->load_addr - load_size);

      grub_multiboot_payload_eip = header->entry_addr;

    }
  else
    {
      err = grub_multiboot_load_elf (file, buffer);
      if (err)
	{
	  grub_free (buffer);
	  return err;
	}
    }

  if (header->flags & MULTIBOOT_VIDEO_MODE)
    {
      switch (header->mode_type)
	{
	case 1:
	  err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, 
					    GRUB_MULTIBOOT_CONSOLE_EGA_TEXT
					    | GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER,
					    0, 0, 0, 0);
	  break;
	case 0:
	  err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER,
					    GRUB_MULTIBOOT_CONSOLE_EGA_TEXT
					    | GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER,
					    header->width, header->height,
					    header->depth, 0);
	  break;
	default:
	  err = grub_error (GRUB_ERR_BAD_OS, 
			    "unsupported graphical mode type %d",
			    header->mode_type);
	  break;
	}
    }
  else
    err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, 
				      GRUB_MULTIBOOT_CONSOLE_EGA_TEXT,
				      0, 0, 0, 0);
  return err;
}
Пример #7
0
char *
grub_legacy_parse (const char *buf, char **entryname, char **suffix)
{
  const char *ptr;
  const char *cmdname;
  unsigned i, cmdnum;
  char *args[ARRAY_SIZE (legacy_commands[0].argt)];

  *suffix = NULL;

  for (ptr = buf; *ptr && grub_isspace (*ptr); ptr++);
  if (!*ptr || *ptr == '#')
    {
      char *ret;
      int len = grub_strlen (buf);
      ret = grub_malloc (len + 2);
      grub_memcpy (ret, buf, len);
      if (len && ret[len - 1] == '\n')
	ret[len] = 0;
      else
	{
	  ret[len] = '\n';
	  ret[len + 1] = 0;
	}
      return ret;
    }

  cmdname = ptr;
  for (ptr = buf; *ptr && !grub_isspace (*ptr) && *ptr != '='; ptr++);

  for (cmdnum = 0; cmdnum < ARRAY_SIZE (legacy_commands); cmdnum++)
    if (grub_strncmp (legacy_commands[cmdnum].name, cmdname, ptr - cmdname) == 0
	&& legacy_commands[cmdnum].name[ptr - cmdname] == 0
	&& (!(*entryname != NULL && (legacy_commands[cmdnum].flags
				     & FLAG_NO_MENUENTRY)))
	&& (!(*entryname == NULL && (legacy_commands[cmdnum].flags
				     & FLAG_MENUENTRY_ONLY))))
      break;
  if (cmdnum == ARRAY_SIZE (legacy_commands))
    return grub_xasprintf ("# Unsupported legacy command: %s\n", buf);

  for (; grub_isspace (*ptr) || *ptr == '='; ptr++);

  if (legacy_commands[cmdnum].flags & FLAG_TITLE)
    {
      const char *ptr2;
      ptr2 = ptr + grub_strlen (ptr);
      while (ptr2 > ptr && grub_isspace (*(ptr2 - 1)))
	ptr2--;
      *entryname = grub_strndup (ptr, ptr2 - ptr);
      return NULL;
    }

  if (legacy_commands[cmdnum].flags & FLAG_TERMINAL)
    {
      int dumb = 0, lines = 24;
#ifdef TODO
      int no_echo = 0, no_edit = 0;
#endif
      int hercules = 0;
      int console = 0, serial = 0, graphics = 0;
      /* Big enough for any possible resulting command. */
      char outbuf[512] = "";
      char *outptr;
      while (*ptr)
	{
	  /*	  "[--timeout=SECS] [--silent]"
		  " [console] [serial] [hercules]"*/
	  if (grub_memcmp (ptr, "--dumb", sizeof ("--dumb") - 1) == 0)
	    dumb = 1;
#ifdef TODO
	  if (grub_memcmp (ptr, "--no-echo", sizeof ("--no-echo") - 1) == 0)
	    no_echo = 1;

	  if (grub_memcmp (ptr, "--no-edit", sizeof ("--no-edit") - 1) == 0)
	    no_edit = 1;
#endif
	  if (grub_memcmp (ptr, "--lines=", sizeof ("--lines=") - 1) == 0)
	    {
	      lines = grub_strtoul (ptr + sizeof ("--lines=") - 1, 0, 0);
	      if (grub_errno)
		{
		  lines = 24;
		  grub_errno = GRUB_ERR_NONE;
		}
	    }

	  if (grub_memcmp (ptr, "console", sizeof ("console") - 1) == 0)
	    console = 1;

	  if (grub_memcmp (ptr, "serial", sizeof ("serial") - 1) == 0)
	    serial = 1;
	  if (grub_memcmp (ptr, "hercules", sizeof ("hercules") - 1) == 0)
	    hercules = 1;
	  if (grub_memcmp (ptr, "graphics", sizeof ("graphics") - 1) == 0)
	    graphics = 1;
	  while (*ptr && !grub_isspace (*ptr))
	    ptr++;
	  while (*ptr && grub_isspace (*ptr))
	    ptr++;
	}

      if (!console && !serial && !hercules && !graphics)
	return grub_strdup ("terminal_input; terminal_output; terminfo\n");

      outptr = outbuf;

      if (graphics)
	outptr = grub_stpcpy (outptr, "insmod all_video; ");

      outptr = grub_stpcpy (outptr, "terminal_input ");
      if (serial)
	outptr = grub_stpcpy (outptr, "serial ");
      if (console || hercules || graphics)
	outptr = grub_stpcpy (outptr, "console ");
      outptr = grub_stpcpy (outptr, "; terminal_output ");
      if (serial)
	outptr = grub_stpcpy (outptr, "serial ");
      if (console)
	outptr = grub_stpcpy (outptr, "console ");
      if (hercules)
	outptr = grub_stpcpy (outptr, "mda_text ");
      if (graphics)
	outptr = grub_stpcpy (outptr, "gfxterm ");
      outptr = grub_stpcpy (outptr, "; ");
      *outptr = '\0';
      if (serial)
	{
	  grub_snprintf (outptr, outbuf + sizeof (outbuf) - outptr,
			 "terminfo serial -g 80x%d %s; ",
			 lines, dumb ? "dumb" : "vt100");
	  outptr += grub_strlen (outptr);
	}

      grub_strcpy (outptr, "\n");

      return grub_strdup (outbuf);
    }

  grub_memset (args, 0, sizeof (args));

  {
    int hold_arg = 0;
    const char *curarg = NULL; 
    for (i = 0; i < legacy_commands[cmdnum].argc; i++)
      {
 	grub_size_t curarglen;
	if (hold_arg)
	  {
	    ptr = curarg;
	    hold_arg = 0;
	  }
	for (; grub_isspace (*ptr); ptr++);
	curarg = ptr;
	if (!*curarg)
	  break;
	for (; *ptr && !grub_isspace (*ptr); ptr++);
	if (i != legacy_commands[cmdnum].argc - 1
	    || (legacy_commands[cmdnum].flags & FLAG_IGNORE_REST))
	  curarglen = ptr - curarg;
	else
	  {
	    curarglen = grub_strlen (curarg);
	    while (curarglen > 0 && grub_isspace (curarg[curarglen - 1]))
	      curarglen--;
	  }
	if (*ptr)
	  ptr++;
	switch (legacy_commands[cmdnum].argt[i])
	  {
	  case TYPE_FILE_NO_CONSUME:
	    hold_arg = 1;
	  case TYPE_PARTITION:
	  case TYPE_FILE:
	    args[i] = adjust_file (curarg, curarglen);
	    break;

	  case TYPE_REST_VERBATIM:
	    {
	      char *outptr, *outptr0;
	      int overhead = 3;
	      ptr = curarg;
	      while (*ptr)
		{
		  for (; *ptr && grub_isspace (*ptr); ptr++);
		  for (; *ptr && !grub_isspace (*ptr); ptr++)
		    if (*ptr == '\'')
		      overhead += 3;
		  if (*ptr)
		    ptr++;
		  overhead += 3;
		}
		
	      outptr0 = args[i] = grub_malloc (overhead + (ptr - curarg));
	      if (!outptr0)
		return NULL;
	      ptr = curarg;
	      outptr = outptr0;
	      while (*ptr)
		{
		  for (; *ptr && grub_isspace (*ptr); ptr++);
		  if (outptr != outptr0)
		    *outptr++ = ' ';
		  *outptr++ = '\'';
		  for (; *ptr && !grub_isspace (*ptr); ptr++)
		    {
		      if (*ptr == '\'')
			{
			  *outptr++ = '\'';
			  *outptr++ = '\\';
			  *outptr++ = '\'';
			  *outptr++ = '\'';
			}
		      else
			*outptr++ = *ptr;
		    }
		  *outptr++ = '\'';
		  if (*ptr)
		    ptr++;
		}
	      *outptr++ = 0;
	    }
	    break;

	  case TYPE_VERBATIM:
	    args[i] = grub_legacy_escape (curarg, curarglen);
	    break;
	  case TYPE_WITH_CONFIGFILE_OPTION:
	  case TYPE_FORCE_OPTION:
	  case TYPE_NOAPM_OPTION:
	  case TYPE_TYPE_OR_NOMEM_OPTION:
	  case TYPE_OPTION:
	    if (is_option (legacy_commands[cmdnum].argt[i], curarg, curarglen))
	      {
		args[i] = grub_strndup (curarg, curarglen);
		break;
	      }
	    args[i] = grub_strdup ("");
	    hold_arg = 1;
	    break;
	  case TYPE_INT:
	    {
	      const char *brk;
	      int base = 10;
	      brk = curarg;
	      if (brk[0] == '0' && brk[1] == 'x')
		{
		  base = 16;
		  brk += 2;
		}
	      else if (brk[0] == '0')
		base = 8;
	      for (; *brk && brk < curarg + curarglen; brk++)
		{
		  if (base == 8 &&  (*brk == '8' || *brk == '9'))
		    break;
		  if (grub_isdigit (*brk))
		    continue;
		  if (base != 16)
		    break;
		  if (!(*brk >= 'a' && *brk <= 'f')
		      && !(*brk >= 'A' && *brk <= 'F'))
		    break;
		}
	      if (brk == curarg)
		args[i] = grub_strdup ("0");
	      else
		args[i] = grub_strndup (curarg, brk - curarg);
	    }
	    break;
	  case TYPE_VBE_MODE:
	    {
	      unsigned mod;
	      struct grub_vesa_mode_table_entry *modedesc;

	      mod = grub_strtoul (curarg, 0, 0);
	      if (grub_errno)
		{
		  mod = 0;
		  grub_errno = GRUB_ERR_NONE;
		}
	      if (mod < GRUB_VESA_MODE_TABLE_START
		  || mod > GRUB_VESA_MODE_TABLE_END)
		{
		  args[i] = grub_strdup ("auto");
		  break;
		}
	      modedesc = &grub_vesa_mode_table[mod - GRUB_VESA_MODE_TABLE_START];
	      if (!modedesc->width)
		{
		  args[i] = grub_strdup ("auto");
		  break;
		}
	      args[i] = grub_xasprintf ("%ux%ux%u",
					modedesc->width, modedesc->height,
					modedesc->depth);
	      break;
	    }
	  case TYPE_BOOL:
	    if (curarglen == 2 && curarg[0] == 'o' && curarg[1] == 'n')
	      args[i] = grub_strdup ("1");
	    else
	      args[i] = grub_strdup ("0");
	    break;
	  }
      }
  }

  while (legacy_commands[cmdnum].argc > 0
	 && args[legacy_commands[cmdnum].argc - 1] == NULL
	 && (legacy_commands[cmdnum].flags & FLAG_FALLBACK_AVAILABLE)
	 && args[legacy_commands[cmdnum + 1].argc] == NULL)
    cmdnum++;

  for (; i < legacy_commands[cmdnum].argc; i++)
    switch (legacy_commands[cmdnum].argt[i])
      {
      case TYPE_FILE_NO_CONSUME:
      case TYPE_PARTITION:
      case TYPE_FILE:
      case TYPE_REST_VERBATIM:
      case TYPE_VERBATIM:
      case TYPE_WITH_CONFIGFILE_OPTION:
      case TYPE_FORCE_OPTION:
      case TYPE_NOAPM_OPTION:
      case TYPE_TYPE_OR_NOMEM_OPTION:
      case TYPE_OPTION:	
	args[i] = grub_strdup ("");
	break;
      case TYPE_BOOL:
      case TYPE_INT:
	args[i] = grub_strdup ("0");
	break;
      case TYPE_VBE_MODE:    
	args[i] = grub_strdup ("auto");
	break;
      }

  if (legacy_commands[cmdnum].flags & FLAG_COLOR_INVERT)
    {
      char *corig = args[legacy_commands[cmdnum].argc - 1];
      char *slash = grub_strchr (corig, '/');
      char *invert;
      grub_size_t len;

      len = grub_strlen (corig);
      if (!slash)
	{
	  grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid color specification `%s'"),
		      args[0]);
	  return NULL;
	}
      invert = grub_malloc (len + 1);
      if (!invert)
	return NULL;
      grub_memcpy (invert, slash + 1, len - (slash - corig) - 1);
      invert[len - (slash - args[0]) - 1] = '/'; 
      grub_memcpy (invert + len - (slash - corig), corig, slash - corig);
      invert[len] = 0;
      args[legacy_commands[cmdnum].argc] = invert;
    }

  if (legacy_commands[cmdnum].suffix)
    {
      *suffix = grub_xasprintf (legacy_commands[cmdnum].suffix,
				args[legacy_commands[cmdnum].suffixarg]);
      if (*suffix)
	return NULL;
    }

  {
    char *ret = grub_xasprintf (legacy_commands[cmdnum].map, args[0], args[1],
				args[2], args[3]);
    grub_free (args[0]);
    grub_free (args[1]);
    grub_free (args[2]);
    grub_free (args[3]);
    return ret;
  }
}
Пример #8
0
static grub_err_t
sun_partition_map_iterate (grub_disk_t disk,
                           int (*hook) (grub_disk_t disk,
					const grub_partition_t partition))
{
  grub_partition_t p;
  struct grub_sun_block block;
  int partnum;
  grub_err_t err;

  p = (grub_partition_t) grub_zalloc (sizeof (struct grub_partition));
  if (! p)
    return grub_errno;

  p->partmap = &grub_sun_partition_map;
  err = grub_disk_read (disk, 0, 0, sizeof (struct grub_sun_block),
			&block);
  if (err)
    {
      grub_free (p);
      return err;
    }

  if (GRUB_PARTMAP_SUN_MAGIC != grub_be_to_cpu16 (block.magic))
    {
      grub_free (p);
      return grub_error (GRUB_ERR_BAD_PART_TABLE, "not a sun partition table");
    }

  if (! grub_sun_is_valid (&block))
    {
      grub_free (p);      
      return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid checksum");
    }

  /* Maybe another error value would be better, because partition
     table _is_ recognized but invalid.  */
  for (partnum = 0; partnum < GRUB_PARTMAP_SUN_MAX_PARTS; partnum++)
    {
      struct grub_sun_partition_descriptor *desc;

      if (block.infos[partnum].id == 0
	  || block.infos[partnum].id == GRUB_PARTMAP_SUN_WHOLE_DISK_ID)
	continue;

      desc = &block.partitions[partnum];
      p->start = ((grub_uint64_t) grub_be_to_cpu32 (desc->start_cylinder)
		  * grub_be_to_cpu16 (block.ntrks)
		  * grub_be_to_cpu16 (block.nsect));
      p->len = grub_be_to_cpu32 (desc->num_sectors);
      p->number = p->index = partnum;
      if (p->len)
	{
	  if (hook (disk, p))
	    partnum = GRUB_PARTMAP_SUN_MAX_PARTS;
	}
    }

  grub_free (p);

  return grub_errno;
}
Пример #9
0
static void
free_iterator (struct grub_btrfs_leaf_descriptor *desc)
{
  grub_free (desc->data);
}
Пример #10
0
/* Read a GUI object specification from the theme file.
   Any components created will be added to the GUI container PARENT.  */
static grub_err_t
read_object (struct parsebuf *p, grub_gui_container_t parent)
{
  grub_video_rect_t bounds;

  char *name;
  name = read_identifier (p);
  if (! name)
    goto cleanup;

  grub_gui_component_t component = 0;
  if (grub_strcmp (name, "label") == 0)
    {
      component = grub_gui_label_new ();
    }
  else if (grub_strcmp (name, "image") == 0)
    {
      component = grub_gui_image_new ();
    }
  else if (grub_strcmp (name, "vbox") == 0)
    {
      component = (grub_gui_component_t) grub_gui_vbox_new ();
    }
  else if (grub_strcmp (name, "hbox") == 0)
    {
      component = (grub_gui_component_t) grub_gui_hbox_new ();
    }
  else if (grub_strcmp (name, "canvas") == 0)
    {
      component = (grub_gui_component_t) grub_gui_canvas_new ();
    }
  else if (grub_strcmp (name, "progress_bar") == 0)
    {
      component = grub_gui_progress_bar_new ();
    }
  else if (grub_strcmp (name, "circular_progress") == 0)
    {
      component = grub_gui_circular_progress_new ();
    }
  else if (grub_strcmp (name, "boot_menu") == 0)
    {
      component = grub_gui_list_new ();
    }
  else
    {
      /* Unknown type.  */
      grub_error (GRUB_ERR_IO, "%s:%d:%d unknown object type `%s'",
                  p->filename, p->line_num, p->col_num, name);
      goto cleanup;
    }

  if (! component)
    goto cleanup;

  /* Inform the component about the theme so it can find its resources.  */
  component->ops->set_property (component, "theme_dir", p->theme_dir);
  component->ops->set_property (component, "theme_path", p->filename);

  /* Add the component as a child of PARENT.  */
  bounds.x = 0;
  bounds.y = 0;
  bounds.width = -1;
  bounds.height = -1;
  component->ops->set_bounds (component, &bounds);
  parent->ops->add (parent, component);

  skip_whitespace (p);
  if (read_char (p) != '{')
    {
      grub_error (GRUB_ERR_IO,
                  "%s:%d:%d expected `{' after object type name `%s'",
                  p->filename, p->line_num, p->col_num, name);
      goto cleanup;
    }

  while (has_more (p))
    {
      skip_whitespace (p);

      /* Check whether the end has been encountered.  */
      if (peek_char (p) == '}')
        {
          /* Skip the closing brace.  */
          read_char (p);
          break;
        }

      if (peek_char (p) == '#')
        {
          /* Skip comments.  */
          advance_to_next_line (p);
          continue;
        }

      if (peek_char (p) == '+')
        {
          /* Skip the '+'.  */
          read_char (p);

          /* Check whether this component is a container.  */
          if (component->ops->is_instance (component, "container"))
            {
              /* Read the sub-object recursively and add it as a child.  */
              if (read_object (p, (grub_gui_container_t) component) != 0)
                goto cleanup;
              /* After reading the sub-object, resume parsing, expecting
                 another property assignment or sub-object definition.  */
              continue;
            }
          else
            {
              grub_error (GRUB_ERR_IO,
                          "%s:%d:%d attempted to add object to non-container",
                          p->filename, p->line_num, p->col_num);
              goto cleanup;
            }
        }

      char *property;
      property = read_identifier (p);
      if (! property)
        {
          grub_error (GRUB_ERR_IO, "%s:%d:%d identifier expected in theme file",
                      p->filename, p->line_num, p->col_num);
          goto cleanup;
        }

      skip_whitespace (p);
      if (read_char (p) != '=')
        {
          grub_error (GRUB_ERR_IO,
                      "%s:%d:%d expected `=' after property name `%s'",
                      p->filename, p->line_num, p->col_num, property);
          grub_free (property);
          goto cleanup;
        }
      skip_whitespace (p);

      char *value;
      value = read_expression (p);
      if (! value)
        {
          grub_free (property);
          goto cleanup;
        }

      /* Handle the property value.  */
      if (grub_strcmp (property, "left") == 0)
	parse_proportional_spec (value, &component->x, &component->xfrac);
      else if (grub_strcmp (property, "top") == 0)
	parse_proportional_spec (value, &component->y, &component->yfrac);
      else if (grub_strcmp (property, "width") == 0)
	parse_proportional_spec (value, &component->w, &component->wfrac);
      else if (grub_strcmp (property, "height") == 0)
	parse_proportional_spec (value, &component->h, &component->hfrac);
      else
	/* General property handling.  */
	component->ops->set_property (component, property, value);

      grub_free (value);
      grub_free (property);
      if (grub_errno != GRUB_ERR_NONE)
        goto cleanup;
    }

cleanup:
  grub_free (name);
  return grub_errno;
}
Пример #11
0
/* Set properties on the view based on settings from the specified
   theme file.  */
grub_err_t
grub_gfxmenu_view_load_theme (grub_gfxmenu_view_t view, const char *theme_path)
{
  grub_file_t file;
  struct parsebuf p;

  p.view = view;
  p.theme_dir = grub_get_dirname (theme_path);

  file = grub_file_open (theme_path, GRUB_FILE_TYPE_THEME);
  if (! file)
    {
      grub_free (p.theme_dir);
      return grub_errno;
    }

  p.len = grub_file_size (file);
  p.buf = grub_malloc (p.len);
  p.pos = 0;
  p.line_num = 1;
  p.col_num = 1;
  p.filename = theme_path;
  if (! p.buf)
    {
      grub_file_close (file);
      grub_free (p.theme_dir);
      return grub_errno;
    }
  if (grub_file_read (file, p.buf, p.len) != p.len)
    {
      grub_free (p.buf);
      grub_file_close (file);
      grub_free (p.theme_dir);
      return grub_errno;
    }

  if (view->canvas)
    view->canvas->component.ops->destroy (view->canvas);

  view->canvas = grub_gui_canvas_new ();
  if (!view->canvas)
    goto fail;
  ((grub_gui_component_t) view->canvas)
    ->ops->set_bounds ((grub_gui_component_t) view->canvas,
                       &view->screen);

  while (has_more (&p))
    {
      /* Skip comments (lines beginning with #).  */
      if (peek_char (&p) == '#')
        {
          advance_to_next_line (&p);
          continue;
        }

      /* Find the first non-whitespace character.  */
      skip_whitespace (&p);

      /* Handle the content.  */
      if (peek_char (&p) == '+')
        {
          /* Skip the '+'.  */
          read_char (&p);
          read_object (&p, view->canvas);
        }
      else
        {
          read_property (&p);
        }

      if (grub_errno != GRUB_ERR_NONE)
        goto fail;
    }

  /* Set the new theme path.  */
  grub_free (view->theme_path);
  view->theme_path = grub_strdup (theme_path);
  goto cleanup;

fail:
  if (view->canvas)
    {
      view->canvas->component.ops->destroy (view->canvas);
      view->canvas = 0;
    }

cleanup:
  grub_free (p.buf);
  grub_file_close (file);
  grub_free (p.theme_dir);
  return grub_errno;
}
Пример #12
0
/* Set the specified property NAME on the view to the given string VALUE.
   The caller is responsible for the lifetimes of NAME and VALUE.  */
static grub_err_t
theme_set_string (grub_gfxmenu_view_t view,
                  const char *name,
                  const char *value,
                  const char *theme_dir,
                  const char *filename,
                  int line_num,
                  int col_num)
{
  if (! grub_strcmp ("title-font", name))
    view->title_font = grub_font_get (value);
  else if (! grub_strcmp ("message-font", name))
    view->message_font = grub_font_get (value);
  else if (! grub_strcmp ("terminal-font", name))
    {
      grub_free (view->terminal_font_name);
      view->terminal_font_name = grub_strdup (value);
      if (! view->terminal_font_name)
        return grub_errno;
    }
  else if (! grub_strcmp ("title-color", name))
    grub_video_parse_color (value, &view->title_color);
  else if (! grub_strcmp ("message-color", name))
    grub_video_parse_color (value, &view->message_color);
  else if (! grub_strcmp ("message-bg-color", name))
    grub_video_parse_color (value, &view->message_bg_color);
  else if (! grub_strcmp ("desktop-image", name))
    {
      struct grub_video_bitmap *raw_bitmap;
      char *path;
      path = grub_resolve_relative_path (theme_dir, value);
      if (! path)
        return grub_errno;
      if (grub_video_bitmap_load (&raw_bitmap, path) != GRUB_ERR_NONE)
        {
          grub_free (path);
          return grub_errno;
        }
      grub_free(path);
      grub_video_bitmap_destroy (view->raw_desktop_image);
      view->raw_desktop_image = raw_bitmap;
    }
  else if (! grub_strcmp ("desktop-image-scale-method", name))
    {
      if (! value || ! grub_strcmp ("stretch", value))
        view->desktop_image_scale_method =
            GRUB_VIDEO_BITMAP_SELECTION_METHOD_STRETCH;
      else if (! grub_strcmp ("crop", value))
        view->desktop_image_scale_method =
            GRUB_VIDEO_BITMAP_SELECTION_METHOD_CROP;
      else if (! grub_strcmp ("padding", value))
        view->desktop_image_scale_method =
            GRUB_VIDEO_BITMAP_SELECTION_METHOD_PADDING;
      else if (! grub_strcmp ("fitwidth", value))
        view->desktop_image_scale_method =
            GRUB_VIDEO_BITMAP_SELECTION_METHOD_FITWIDTH;
      else if (! grub_strcmp ("fitheight", value))
        view->desktop_image_scale_method =
            GRUB_VIDEO_BITMAP_SELECTION_METHOD_FITHEIGHT;
      else
        return grub_error (GRUB_ERR_BAD_ARGUMENT,
                           "Unsupported scale method: %s",
                           value);
    }
  else if (! grub_strcmp ("desktop-image-h-align", name))
    {
      if (! grub_strcmp ("left", value))
        view->desktop_image_h_align = GRUB_VIDEO_BITMAP_H_ALIGN_LEFT;
      else if (! grub_strcmp ("center", value))
        view->desktop_image_h_align = GRUB_VIDEO_BITMAP_H_ALIGN_CENTER;
      else if (! grub_strcmp ("right", value))
        view->desktop_image_h_align = GRUB_VIDEO_BITMAP_H_ALIGN_RIGHT;
      else
        return grub_error (GRUB_ERR_BAD_ARGUMENT,
                           "Unsupported horizontal align method: %s",
                           value);
    }
  else if (! grub_strcmp ("desktop-image-v-align", name))
    {
      if (! grub_strcmp ("top", value))
        view->desktop_image_v_align = GRUB_VIDEO_BITMAP_V_ALIGN_TOP;
      else if (! grub_strcmp ("center", value))
        view->desktop_image_v_align = GRUB_VIDEO_BITMAP_V_ALIGN_CENTER;
      else if (! grub_strcmp ("bottom", value))
        view->desktop_image_v_align = GRUB_VIDEO_BITMAP_V_ALIGN_BOTTOM;
      else
        return grub_error (GRUB_ERR_BAD_ARGUMENT,
                           "Unsupported vertical align method: %s",
                           value);
    }
  else if (! grub_strcmp ("desktop-color", name))
     grub_video_parse_color (value, &view->desktop_color);
  else if (! grub_strcmp ("terminal-box", name))
    {
        grub_err_t err;
        err = grub_gui_recreate_box (&view->terminal_box, value, theme_dir);
        if (err != GRUB_ERR_NONE)
          return err;
    }
  else if (! grub_strcmp ("terminal-border", name))
    {
      view->terminal_border = grub_strtoul (value, 0, 10);
      if (grub_errno)
        return grub_errno;
    }
  else if (! grub_strcmp ("terminal-left", name))
    {
      unsigned int tmp;
      int err = theme_get_unsigned_int_from_proportional (value,
                                                          view->screen.width,
                                                          &tmp);
      if (err != GRUB_ERR_NONE)
        return err;
      view->terminal_rect.x = tmp;
    }
  else if (! grub_strcmp ("terminal-top", name))
    {
      unsigned int tmp;
      int err = theme_get_unsigned_int_from_proportional (value,
                                                          view->screen.height,
                                                          &tmp);
      if (err != GRUB_ERR_NONE)
        return err;
      view->terminal_rect.y = tmp;
    }
  else if (! grub_strcmp ("terminal-width", name))
    {
      unsigned int tmp;
      int err = theme_get_unsigned_int_from_proportional (value,
                                                          view->screen.width,
                                                          &tmp);
      if (err != GRUB_ERR_NONE)
        return err;
      view->terminal_rect.width = tmp;
    }
  else if (! grub_strcmp ("terminal-height", name))
    {
      unsigned int tmp;
      int err = theme_get_unsigned_int_from_proportional (value,
                                                          view->screen.height,
                                                          &tmp);
      if (err != GRUB_ERR_NONE)
        return err;
      view->terminal_rect.height = tmp;
    }
  else if (! grub_strcmp ("title-text", name))
    {
      grub_free (view->title_text);
      view->title_text = grub_strdup (value);
      if (! view->title_text)
        return grub_errno;
    }
  else
    {
      return grub_error (GRUB_ERR_BAD_ARGUMENT,
                         "%s:%d:%d unknown property `%s'",
                         filename, line_num, col_num, name);
    }
  return grub_errno;
}
Пример #13
0
static grub_file_t
grub_xzio_open (grub_file_t io)
{
  grub_file_t file;
  grub_xzio_t xzio;

  file = (grub_file_t) grub_zalloc (sizeof (*file));
  if (!file)
    return 0;

  xzio = grub_zalloc (sizeof (*xzio));
  if (!xzio)
    {
      grub_free (file);
      return 0;
    }

  xzio->file = io;
  xzio->saved_offset = 0;

  file->device = io->device;
  file->offset = 0;
  file->data = xzio;
  file->read_hook = 0;
  file->fs = &grub_xzio_fs;
  file->size = GRUB_FILE_SIZE_UNKNOWN;
  file->not_easly_seekable = 1;

  if (grub_file_tell (xzio->file) != 0)
    grub_file_seek (xzio->file, 0);

  /* Allocated 64KiB for dictionary.
   * Decoder will relocate if bigger is needed.  */
  xzio->dec = xz_dec_init (1 << 16);
  if (!xzio->dec)
    {
      grub_free (file);
      grub_free (xzio);
      return 0;
    }

  xzio->buf.in = xzio->inbuf;
  xzio->buf.in_pos = 0;
  xzio->buf.in_size = 0;
  xzio->buf.out = xzio->outbuf;
  xzio->buf.out_pos = 0;
  xzio->buf.out_size = XZBUFSIZ;

  /* FIXME: don't test footer on not easily seekable files.  */
  if (!test_header (file) || !test_footer (file))
    {
      grub_errno = GRUB_ERR_NONE;
      grub_file_seek (io, 0);
      xz_dec_end (xzio->dec);
      grub_free (xzio);
      grub_free (file);

      return io;
    }

  return file;
}
Пример #14
0
grub_partition_t
grub_partition_probe (struct grub_disk *disk, const char *str)
{
  grub_partition_t part = 0;
  grub_partition_t curpart = 0;
  grub_partition_t tail;
  const char *ptr;

  part = tail = disk->partition;

  for (ptr = str; *ptr;)
    {
      grub_partition_map_t partmap;
      int num;
      const char *partname, *partname_end;

      partname = ptr;
      while (*ptr && grub_isalpha (*ptr))
	ptr++;
      partname_end = ptr;
      num = grub_strtoul (ptr, (char **) &ptr, 0) - 1;

      curpart = 0;
      /* Use the first partition map type found.  */
      FOR_PARTITION_MAPS(partmap)
      {
	if (partname_end != partname &&
	    (grub_strncmp (partmap->name, partname, partname_end - partname)
	     != 0 || partmap->name[partname_end - partname] != 0))
	  continue;

	disk->partition = part;
	curpart = grub_partition_map_probe (partmap, disk, num);
	disk->partition = tail;
	if (curpart)
	  break;

	if (grub_errno == GRUB_ERR_BAD_PART_TABLE)
	  {
	    /* Continue to next partition map type.  */
	    grub_errno = GRUB_ERR_NONE;
	    continue;
	  }

	break;
      }

      if (! curpart)
	{
	  while (part)
	    {
	      curpart = part->parent;
	      grub_free (part);
	      part = curpart;
	    }
	  return 0;
	}
      curpart->parent = part;
      part = curpart;
      if (! ptr || *ptr != ',')
	break;
      ptr++;
    }

  return part;
}
Пример #15
0
/* Search for the block FILEBLOCK inside the file NODE.  Return the
   blocknumber of this block on disk.  */
static grub_disk_addr_t
grub_hfsplus_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
{
  struct grub_hfsplus_btnode *nnode = 0;
  grub_disk_addr_t blksleft = fileblock;
  struct grub_hfsplus_extent *extents = &node->extents[0];

  while (1)
    {
      struct grub_hfsplus_extkey *key;
      struct grub_hfsplus_key_internal extoverflow;
      grub_disk_addr_t blk;
      grub_off_t ptr;

      /* Try to find this block in the current set of extents.  */
      blk = grub_hfsplus_find_block (extents, &blksleft);

      /* The previous iteration of this loop allocated memory.  The
	 code above used this memory, it can be freed now.  */
      grub_free (nnode);
      nnode = 0;

      if (blk != 0xffffffffffffffffULL)
	return blk;

      /* For the extent overflow file, extra extents can't be found in
	 the extent overflow file.  If this happens, you found a
	 bug...  */
      if (node->fileid == GRUB_HFSPLUS_FILEID_OVERFLOW)
	{
	  grub_error (GRUB_ERR_READ_ERROR,
		      "extra extents found in an extend overflow file");
	  break;
	}

      /* Set up the key to look for in the extent overflow file.  */
      extoverflow.extkey.fileid = node->fileid;
      extoverflow.extkey.type = 0;
      extoverflow.extkey.start = fileblock - blksleft;

      if (grub_hfsplus_btree_search (&node->data->extoverflow_tree,
				     &extoverflow,
				     grub_hfsplus_cmp_extkey, &nnode, &ptr))
	{
	  grub_error (GRUB_ERR_READ_ERROR,
		      "no block found for the file id 0x%x and the block offset 0x%x",
		      node->fileid, fileblock);
	  break;
	}

      /* The extent overflow file has 8 extents right after the key.  */
      key = (struct grub_hfsplus_extkey *)
	grub_hfsplus_btree_recptr (&node->data->extoverflow_tree, nnode, ptr);
      extents = (struct grub_hfsplus_extent *) (key + 1);

      /* The block wasn't found.  Perhaps the next iteration will find
	 it.  The last block we found is stored in BLKSLEFT now.  */
    }

  grub_free (nnode);

  /* Too bad, you lose.  */
  return -1;
}
Пример #16
0
static void
grub_biosdisk_close (grub_disk_t disk)
{
  grub_free (disk->data);
}
Пример #17
0
/* Read the file fs.lst for auto-loading.  */
void
read_fs_list (const char *prefix)
{
  if (prefix)
    {
      char *filename;

      filename = grub_xasprintf ("%s/fs.lst", prefix);
      if (filename)
	{
	  grub_file_t file;
	  grub_fs_autoload_hook_t tmp_autoload_hook;

	  /* This rules out the possibility that read_fs_list() is invoked
	     recursively when we call grub_file_open() below.  */
	  tmp_autoload_hook = grub_fs_autoload_hook;
	  grub_fs_autoload_hook = NULL;

	  file = grub_file_open (filename);
	  if (file)
	    {
	      /* Override previous fs.lst.  */
	      while (fs_module_list)
		{
		  grub_named_list_t tmp;
		  tmp = fs_module_list->next;
		  grub_free (fs_module_list);
		  fs_module_list = tmp;
		}

	      while (1)
		{
		  char *buf;
		  char *p;
		  char *q;
		  grub_named_list_t fs_mod;

		  buf = grub_getline (file);
		  if (! buf)
		    break;

		  p = buf;
		  q = buf + grub_strlen (buf) - 1;

		  /* Ignore space.  */
		  while (grub_isspace (*p))
		    p++;

		  while (p < q && grub_isspace (*q))
		    *q-- = '\0';

		  /* If the line is empty, skip it.  */
		  if (p >= q)
		    continue;

		  fs_mod = grub_malloc (sizeof (*fs_mod));
		  if (! fs_mod)
		    continue;

		  fs_mod->name = grub_strdup (p);
		  if (! fs_mod->name)
		    {
		      grub_free (fs_mod);
		      continue;
		    }

		  fs_mod->next = fs_module_list;
		  fs_module_list = fs_mod;
		}

	      grub_file_close (file);
	      grub_fs_autoload_hook = tmp_autoload_hook;
	    }

	  grub_free (filename);
	}
    }

  /* Ignore errors.  */
  grub_errno = GRUB_ERR_NONE;

  /* Set the hook.  */
  grub_fs_autoload_hook = autoload_fs_module;
}
Пример #18
0
static grub_err_t
grub_biosdisk_open (const char *name, grub_disk_t disk)
{
  grub_uint64_t total_sectors = 0;
  int drive;
  struct grub_biosdisk_data *data;

  drive = grub_biosdisk_get_drive (name);
  if (drive < 0)
    return grub_errno;

  disk->has_partitions = ((drive & 0x80) && (drive != cd_drive));
  disk->id = drive;

  data = (struct grub_biosdisk_data *) grub_zalloc (sizeof (*data));
  if (! data)
    return grub_errno;

  data->drive = drive;

  if ((cd_drive) && (drive == cd_drive))
    {
      data->flags = GRUB_BIOSDISK_FLAG_LBA | GRUB_BIOSDISK_FLAG_CDROM;
      data->sectors = 32;
      total_sectors = GRUB_ULONG_MAX;  /* TODO: get the correct size.  */
    }
  else if (drive & 0x80)
    {
      /* HDD */
      int version;

      version = grub_biosdisk_check_int13_extensions (drive);
      if (version)
	{
	  struct grub_biosdisk_drp *drp
	    = (struct grub_biosdisk_drp *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;

	  /* Clear out the DRP.  */
	  grub_memset (drp, 0, sizeof (*drp));
	  drp->size = sizeof (*drp);
	  if (! grub_biosdisk_get_diskinfo_int13_extensions (drive, drp))
	    {
	      data->flags = GRUB_BIOSDISK_FLAG_LBA;

	      if (drp->total_sectors)
		total_sectors = drp->total_sectors;
	      else
                /* Some buggy BIOSes doesn't return the total sectors
                   correctly but returns zero. So if it is zero, compute
                   it by C/H/S returned by the LBA BIOS call.  */
                total_sectors = drp->cylinders * drp->heads * drp->sectors;
	    }
	}
    }

  if (! (data->flags & GRUB_BIOSDISK_FLAG_CDROM))
    {
      if (grub_biosdisk_get_diskinfo_standard (drive,
					       &data->cylinders,
					       &data->heads,
					       &data->sectors) != 0)
        {
	  if (total_sectors && (data->flags & GRUB_BIOSDISK_FLAG_LBA))
	    {
	      data->sectors = 63;
	      data->heads = 255;
	      data->cylinders
		= grub_divmod64 (total_sectors
				 + data->heads * data->sectors - 1,
				 data->heads * data->sectors, 0);
	    }
	  else
	    {
	      grub_free (data);
	      return grub_error (GRUB_ERR_BAD_DEVICE, "%s cannot get C/H/S values", disk->name);
	    }
        }

      if (! total_sectors)
        total_sectors = data->cylinders * data->heads * data->sectors;
    }

  disk->total_sectors = total_sectors;
  disk->data = data;

  return GRUB_ERR_NONE;
}
Пример #19
0
grub_err_t
SUFFIX(grub_openbsd_find_ramdisk) (grub_file_t file,
				   grub_addr_t kern_start,
				   void *kern_chunk_src,
				   struct grub_openbsd_ramdisk_descriptor *desc)
{
  unsigned symoff, stroff, symsize, strsize, symentsize;

  {
    grub_err_t err;
    Elf_Ehdr e;
    Elf_Shdr *s;
    char *shdr = NULL;
    
    err = read_headers (file, &e, &shdr);
    if (err)
      return err;

    for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) (shdr
						  + e.e_shnum * e.e_shentsize);
	 s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
      if (s->sh_type == SHT_SYMTAB)
	break;
    if (s >= (Elf_Shdr *) ((char *) shdr + e.e_shnum * e.e_shentsize))
      {
	grub_free (shdr);
	return GRUB_ERR_NONE;
      }

    symsize = s->sh_size;
    symentsize = s->sh_entsize;
    symoff = s->sh_offset;
    
    s = (Elf_Shdr *) (shdr + e.e_shentsize * s->sh_link);
    stroff = s->sh_offset;
    strsize = s->sh_size;
    grub_free (shdr);
  }
  {
    Elf_Sym *syms, *sym, *imagesym = NULL, *sizesym = NULL;
    unsigned i;
    char *strs;

    syms = grub_malloc (symsize);
    if (!syms)
      return grub_errno;

    if (grub_file_seek (file, symoff) == (grub_off_t) -1)
      {
	grub_free (syms);
	return grub_errno;
      }
    if (grub_file_read (file, syms, symsize) != (grub_ssize_t) symsize)
      {
	grub_free (syms);
	if (! grub_errno)
	  return grub_error (GRUB_ERR_BAD_OS, "invalid ELF");
	return grub_errno;
      }

    strs = grub_malloc (strsize);
    if (!strs)
      {
	grub_free (syms);
	return grub_errno;
      }

    if (grub_file_seek (file, stroff) == (grub_off_t) -1)
      return grub_errno;
    if (grub_file_read (file, strs, strsize) != (grub_ssize_t) strsize)
      {
	grub_free (syms);
	grub_free (strs);
	if (! grub_errno)
	  return grub_error (GRUB_ERR_BAD_OS, "invalid ELF");
	return grub_errno;
      }

    for (i = 0, sym = syms; i < symsize / symentsize;
       i++, sym = (Elf_Sym *) ((char *) sym + symentsize))
      {
	if (ELF_ST_TYPE (sym->st_info) != STT_OBJECT)
	  continue;
	if (!sym->st_name)
	  continue;
	if (grub_strcmp (strs + sym->st_name, "rd_root_image") == 0)
	  imagesym = sym;
	if (grub_strcmp (strs + sym->st_name, "rd_root_size") == 0)
	  sizesym = sym;
	if (imagesym && sizesym)
	  break;
      }
    if (!imagesym || !sizesym)
      {
	grub_free (syms);
	grub_free (strs);
	return GRUB_ERR_NONE;
      }
    if (sizeof (*desc->size) != sizesym->st_size)
      {
	grub_free (syms);
	grub_free (strs);
	return grub_error (GRUB_ERR_BAD_OS, "unexpected size of rd_root_size");
      }
    desc->max_size = imagesym->st_size;
    desc->target = (imagesym->st_value & 0xFFFFFF) - kern_start
      + (grub_uint8_t *) kern_chunk_src;
    desc->size = (grub_uint32_t *) ((sizesym->st_value & 0xFFFFFF) - kern_start
				    + (grub_uint8_t *) kern_chunk_src);
    grub_free (syms);
    grub_free (strs);

    return GRUB_ERR_NONE;
  }
}
Пример #20
0
grub_err_t
grub_multiboot_load (grub_file_t file, const char *filename)
{
  grub_properly_aligned_t *buffer;
  grub_ssize_t len;
  struct multiboot_header *header;
  grub_err_t err;
  struct multiboot_header_tag *tag;
  struct multiboot_header_tag_address *addr_tag = NULL;
  int entry_specified = 0;
  grub_addr_t entry = 0;
  grub_uint32_t console_required = 0;
  struct multiboot_header_tag_framebuffer *fbtag = NULL;
  int accepted_consoles = GRUB_MULTIBOOT_CONSOLE_EGA_TEXT;

  buffer = grub_malloc (MULTIBOOT_SEARCH);
  if (!buffer)
    return grub_errno;

  len = grub_file_read (file, buffer, MULTIBOOT_SEARCH);
  if (len < 32)
    {
      grub_free (buffer);
      return grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), filename);
    }

  COMPILE_TIME_ASSERT (MULTIBOOT_HEADER_ALIGN % 4 == 0);

  grub_tpm_measure ((unsigned char *)buffer, len, GRUB_BINARY_PCR, "grub_multiboot", filename);

  header = find_header (buffer, len);

  if (header == 0)
    {
      grub_free (buffer);
      return grub_error (GRUB_ERR_BAD_ARGUMENT, "no multiboot header found");
    }

  COMPILE_TIME_ASSERT (MULTIBOOT_TAG_ALIGN % 4 == 0);

  keep_bs = 0;

  for (tag = (struct multiboot_header_tag *) (header + 1);
       tag->type != MULTIBOOT_TAG_TYPE_END;
       tag = (struct multiboot_header_tag *) ((grub_uint32_t *) tag + ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN) / 4))
    switch (tag->type)
      {
      case MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST:
	{
	  unsigned i;
	  struct multiboot_header_tag_information_request *request_tag
	    = (struct multiboot_header_tag_information_request *) tag;
	  if (request_tag->flags & MULTIBOOT_HEADER_TAG_OPTIONAL)
	    break;
	  for (i = 0; i < (request_tag->size - sizeof (*request_tag))
		 / sizeof (request_tag->requests[0]); i++)
	    switch (request_tag->requests[i])
	      {
	      case MULTIBOOT_TAG_TYPE_END:
	      case MULTIBOOT_TAG_TYPE_CMDLINE:
	      case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME:
	      case MULTIBOOT_TAG_TYPE_MODULE:
	      case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO:
	      case MULTIBOOT_TAG_TYPE_BOOTDEV:
	      case MULTIBOOT_TAG_TYPE_MMAP:
	      case MULTIBOOT_TAG_TYPE_FRAMEBUFFER:
	      case MULTIBOOT_TAG_TYPE_VBE:
	      case MULTIBOOT_TAG_TYPE_ELF_SECTIONS:
	      case MULTIBOOT_TAG_TYPE_APM:
	      case MULTIBOOT_TAG_TYPE_EFI32:
	      case MULTIBOOT_TAG_TYPE_EFI64:
	      case MULTIBOOT_TAG_TYPE_ACPI_OLD:
	      case MULTIBOOT_TAG_TYPE_ACPI_NEW:
	      case MULTIBOOT_TAG_TYPE_NETWORK:
	      case MULTIBOOT_TAG_TYPE_EFI_MMAP:
	      case MULTIBOOT_TAG_TYPE_EFI_BS:
		break;

	      default:
		grub_free (buffer);
		return grub_error (GRUB_ERR_UNKNOWN_OS,
				   "unsupported information tag: 0x%x",
				   request_tag->requests[i]);
	      }
	  break;
	}
	       
      case MULTIBOOT_HEADER_TAG_ADDRESS:
	addr_tag = (struct multiboot_header_tag_address *) tag;
	break;

      case MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS:
	entry_specified = 1;
	entry = ((struct multiboot_header_tag_entry_address *) tag)->entry_addr;
	break;

      case MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS:
	if (!(((struct multiboot_header_tag_console_flags *) tag)->console_flags
	    & MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED))
	  accepted_consoles &= ~GRUB_MULTIBOOT_CONSOLE_EGA_TEXT;
	if (((struct multiboot_header_tag_console_flags *) tag)->console_flags
	    & MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED)
	  console_required = 1;
	break;

      case MULTIBOOT_HEADER_TAG_FRAMEBUFFER:
	fbtag = (struct multiboot_header_tag_framebuffer *) tag;
	accepted_consoles |= GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER;
	break;

	/* GRUB always page-aligns modules.  */
      case MULTIBOOT_HEADER_TAG_MODULE_ALIGN:
	break;

      case MULTIBOOT_HEADER_TAG_EFI_BS:
	keep_bs = 1;
	break;

      default:
	if (! (tag->flags & MULTIBOOT_HEADER_TAG_OPTIONAL))
	  {
	    grub_free (buffer);
	    return grub_error (GRUB_ERR_UNKNOWN_OS,
			       "unsupported tag: 0x%x", tag->type);
	  }
	break;
      }

  if (addr_tag && !entry_specified)
    {
      grub_free (buffer);
      return grub_error (GRUB_ERR_UNKNOWN_OS,
			 "load address tag without entry address tag");
    }
 
  if (addr_tag)
    {
      grub_uint64_t load_addr = (addr_tag->load_addr + 1)
	? addr_tag->load_addr : (addr_tag->header_addr
				 - ((char *) header - (char *) buffer));
      int offset = ((char *) header - (char *) buffer -
	   (addr_tag->header_addr - load_addr));
      int load_size = ((addr_tag->load_end_addr == 0) ? file->size - offset :
		       addr_tag->load_end_addr - addr_tag->load_addr);
      grub_size_t code_size;
      void *source;
      grub_relocator_chunk_t ch;

      if (addr_tag->bss_end_addr)
	code_size = (addr_tag->bss_end_addr - load_addr);
      else
	code_size = load_size;

      err = grub_relocator_alloc_chunk_addr (grub_multiboot_relocator, 
					     &ch, load_addr,
					     code_size);
      if (err)
	{
	  grub_dprintf ("multiboot_loader", "Error loading aout kludge\n");
	  grub_free (buffer);
	  return err;
	}
      source = get_virtual_current_address (ch);

      if ((grub_file_seek (file, offset)) == (grub_off_t) -1)
	{
	  grub_free (buffer);
	  return grub_errno;
	}

      grub_file_read (file, source, load_size);
      if (grub_errno)
	{
	  grub_free (buffer);
	  return grub_errno;
	}

      if (addr_tag->bss_end_addr)
	grub_memset ((grub_uint8_t *) source + load_size, 0,
		     addr_tag->bss_end_addr - load_addr - load_size);
    }
  else
    {
      err = grub_multiboot_load_elf (file, filename, buffer);
      if (err)
	{
	  grub_free (buffer);
	  return err;
	}
    }

  if (entry_specified)
    grub_multiboot_payload_eip = entry;

  if (fbtag)
    err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER,
				      accepted_consoles,
				      fbtag->width, fbtag->height,
				      fbtag->depth, console_required);
  else
    err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT,
				      accepted_consoles,
				      0, 0, 0, console_required);
  return err;
}
Пример #21
0
grub_err_t
grub_multiboot_load (grub_file_t file)
{
  char *buffer;
  grub_ssize_t len;
  struct multiboot_header *header;
  grub_err_t err;

  buffer = grub_malloc (MULTIBOOT_SEARCH);
  if (!buffer)
    return grub_errno;

  len = grub_file_read (file, buffer, MULTIBOOT_SEARCH);
  if (len < 32)
    {
      grub_free (buffer);
      return grub_error (GRUB_ERR_BAD_OS, "file too small");
    }

  /* Look for the multiboot header in the buffer.  The header should
     be at least 12 bytes and aligned on a 4-byte boundary.  */
  for (header = (struct multiboot_header *) buffer;
       ((char *) header <= buffer + len - 12) || (header = 0);
       header = (struct multiboot_header *) ((char *) header + MULTIBOOT_HEADER_ALIGN))
    {
      if (header->magic == MULTIBOOT_HEADER_MAGIC
	  && !(header->magic + header->flags + header->checksum))
	break;
    }

  if (header == 0)
    {
      grub_free (buffer);
      return grub_error (GRUB_ERR_BAD_ARGUMENT, "no multiboot header found");
    }

  if (header->flags & UNSUPPORTED_FLAGS)
    {
      grub_free (buffer);
      return grub_error (GRUB_ERR_UNKNOWN_OS,
			 "unsupported flag: 0x%x", header->flags);
    }

  if (header->flags & MULTIBOOT_AOUT_KLUDGE)
    {
      int offset = ((char *) header - buffer -
		    (header->header_addr - header->load_addr));
      int load_size = ((header->load_end_addr == 0) ? file->size - offset :
		       header->load_end_addr - header->load_addr);
      grub_size_t code_size;
      void *source;
      grub_relocator_chunk_t ch;

      if (header->bss_end_addr)
	code_size = (header->bss_end_addr - header->load_addr);
      else
	code_size = load_size;

      err = grub_relocator_alloc_chunk_addr (grub_multiboot_relocator, 
					     &ch, header->load_addr,
					     code_size);
      if (err)
	{
	  grub_dprintf ("multiboot_loader", "Error loading aout kludge\n");
	  grub_free (buffer);
	  return err;
	}
      source = get_virtual_current_address (ch);

      if ((grub_file_seek (file, offset)) == (grub_off_t) -1)
	{
	  grub_free (buffer);
	  return grub_errno;
	}

      grub_file_read (file, source, load_size);
      if (grub_errno)
	{
	  grub_free (buffer);
	  return grub_errno;
	}

      if (header->bss_end_addr)
	grub_memset ((grub_uint8_t *) source + load_size, 0,
		     header->bss_end_addr - header->load_addr - load_size);

      grub_multiboot_payload_eip = header->entry_addr;
    }
  else
    {
      err = grub_multiboot_load_elf (file, buffer);
      if (err)
	{
	  grub_free (buffer);
	  return err;
	}
    }

  if (header->flags & MULTIBOOT_VIDEO_MODE)
    {
      switch (header->mode_type)
	{
	case 1:
	  err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, 
					    GRUB_MULTIBOOT_CONSOLE_EGA_TEXT
					    | GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER,
					    0, 0, 0, 0);
	  break;
	case 0:
	  err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER,
					    GRUB_MULTIBOOT_CONSOLE_EGA_TEXT
					    | GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER,
					    header->width, header->height,
					    header->depth, 0);
	  break;
	default:
	  err = grub_error (GRUB_ERR_BAD_OS, 
			    "unsupported graphical mode type %d",
			    header->mode_type);
	  break;
	}
    }
  else
    err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT, 
				      GRUB_MULTIBOOT_CONSOLE_EGA_TEXT,
				      0, 0, 0, 0);
  return err;
}
Пример #22
0
/* Parse a test expression starting from *argn. */
static int
test_parse (char **args, int *argn, int argc)
{
  int ret = 0, discard = 0, invert = 0;
  int file_exists;
  struct grub_dirhook_info file_info;

  auto void update_val (int val);
  auto void get_fileinfo (char *pathname);

  /* Take care of discarding and inverting. */
  void update_val (int val)
  {
    if (! discard)
      ret = invert ? ! val : val;
    invert = discard = 0;
  }

  /* Check if file exists and fetch its information. */
  void get_fileinfo (char *path)
  {
    char *filename, *pathname;
    char *device_name;
    grub_fs_t fs;
    grub_device_t dev;

    /* A hook for iterating directories. */
    auto int find_file (const char *cur_filename,
			const struct grub_dirhook_info *info);
    int find_file (const char *cur_filename,
		   const struct grub_dirhook_info *info)
    {
      if ((info->case_insensitive ? grub_strcasecmp (cur_filename, filename)
	   : grub_strcmp (cur_filename, filename)) == 0)
	{
	  file_info = *info;
	  file_exists = 1;
	  return 1;
	}
      return 0;
    }

    file_exists = 0;
    device_name = grub_file_get_device_name (path);
    dev = grub_device_open (device_name);
    if (! dev)
      {
	grub_free (device_name);
	return;
      }

    fs = grub_fs_probe (dev);
    if (! fs)
      {
	grub_free (device_name);
	grub_device_close (dev);
	return;
      }

    pathname = grub_strchr (path, ')');
    if (! pathname)
      pathname = path;
    else
      pathname++;

    /* Remove trailing '/'. */
    while (*pathname && pathname[grub_strlen (pathname) - 1] == '/')
      pathname[grub_strlen (pathname) - 1] = 0;

    /* Split into path and filename. */
    filename = grub_strrchr (pathname, '/');
    if (! filename)
      {
	path = grub_strdup ("/");
	filename = pathname;
      }
    else
      {
	filename++;
	path = grub_strdup (pathname);
	path[filename - pathname] = 0;
      }

    /* It's the whole device. */
    if (! *pathname)
      {
	file_exists = 1;
	grub_memset (&file_info, 0, sizeof (file_info));
	/* Root is always a directory. */
	file_info.dir = 1;

	/* Fetch writing time. */
	file_info.mtimeset = 0;
	if (fs->mtime)
	  {
	    if (! fs->mtime (dev, &file_info.mtime))
	      file_info.mtimeset = 1;
	    grub_errno = GRUB_ERR_NONE;
	  }
      }
    else
      (fs->dir) (dev, path, find_file);

    grub_device_close (dev);
    grub_free (path);
    grub_free (device_name);
  }
Пример #23
0
static void
grub_ofnet_findcards (void)
{
  auto int search_net_devices (struct grub_ieee1275_devalias *alias);

  int search_net_devices (struct grub_ieee1275_devalias *alias)
  {
    if (!grub_strcmp (alias->type, "network"))
      {
	struct grub_ofnetcard_data *ofdata;
	struct grub_net_card *card;
	grub_ieee1275_phandle_t devhandle;
	grub_net_link_level_address_t lla;
	char *shortname;

	ofdata = grub_malloc (sizeof (struct grub_ofnetcard_data));
	if (!ofdata)
	  {
	    grub_print_error ();
	    return 1;
	  }
	card = grub_zalloc (sizeof (struct grub_net_card));
	if (!card)
	  {
	    grub_free (ofdata);
	    grub_print_error ();
	    return 1;
	  }

	ofdata->path = grub_strdup (alias->path);

	grub_ieee1275_finddevice (ofdata->path, &devhandle);

	if (grub_ieee1275_get_integer_property
	    (devhandle, "max-frame-size", &(ofdata->mtu),
	     sizeof (ofdata->mtu), 0))
	  {
	    ofdata->mtu = 1500;
	  }

	if (grub_ieee1275_get_property (devhandle, "mac-address",
					&(lla.mac), 6, 0)
	    && grub_ieee1275_get_property (devhandle, "local-mac-address",
					   &(lla.mac), 6, 0))
	  {
	    grub_error (GRUB_ERR_IO, "Couldn't retrieve mac address.");
	    grub_print_error ();
	    return 0;
	  }

	lla.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
	card->default_address = lla;

	card->driver = NULL;
	card->data = ofdata;
	card->flags = 0;
	shortname = find_alias (alias->path);
	card->name = grub_xasprintf ("ofnet_%s", shortname ? : alias->path);
	card->idle_poll_delay_ms = 1;
	grub_free (shortname);

	card->driver = &ofdriver;
	grub_net_card_register (card);
	return 0;
      }
    return 0;
  }

  /* Look at all nodes for devices of the type network.  */
  grub_ieee1275_devices_iterate (search_net_devices);
}
Пример #24
0
static grub_err_t
grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
                 int argc, char *argv[])
{
    grub_file_t *files = 0;
    int i, nfiles = 0;
    grub_size_t size = 0;
    grub_uint8_t *ptr;

    if (argc == 0)
    {
        grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
        goto fail;
    }

    if (!loaded)
    {
        grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first"));
        goto fail;
    }

    files = grub_zalloc (argc * sizeof (files[0]));
    if (!files)
        goto fail;

    for (i = 0; i < argc; i++)
    {
        grub_file_filter_disable_compression ();
        files[i] = grub_file_open (argv[i]);
        if (! files[i])
            goto fail;
        nfiles++;
        size += ALIGN_UP (grub_file_size (files[i]), 4);
    }

    initrd_mem = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(size));

    if (!initrd_mem)
    {
        grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate initrd"));
        goto fail;
    }

    params->ramdisk_size = size;
    params->ramdisk_image = (grub_uint32_t)(grub_uint64_t) initrd_mem;

    ptr = initrd_mem;

    for (i = 0; i < nfiles; i++)
    {
        grub_ssize_t cursize = grub_file_size (files[i]);
        if (grub_file_read (files[i], ptr, cursize) != cursize)
        {
            if (!grub_errno)
                grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
                            argv[i]);
            goto fail;
        }
        grub_tpm_measure (ptr, cursize, GRUB_INITRD_PCR);
        ptr += cursize;
        grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
        ptr += ALIGN_UP_OVERHEAD (cursize, 4);
    }

    params->ramdisk_size = size;

fail:
    for (i = 0; i < nfiles; i++)
        grub_file_close (files[i]);
    grub_free (files);

    if (initrd_mem && grub_errno)
        grub_efi_free_pages((grub_efi_physical_address_t)initrd_mem, BYTES_TO_PAGES(size));

    return grub_errno;
}
Пример #25
0
/* The command to add and remove loopback devices.  */
static grub_err_t
grub_cmd_loopback (grub_extcmd_t cmd, int argc, char **args)
{
  struct grub_arg_list *state = state = cmd->state;
  grub_file_t file;
  struct grub_loopback *newdev;

  if (argc < 1)
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");

  /* Check if `-d' was used.  */
  if (state[0].set)
      return delete_loopback (args[0]);

  if (argc < 2)
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");

  file = grub_file_open (args[1]);
  if (! file)
    return grub_errno;

  /* First try to replace the old device.  */
  for (newdev = loopback_list; newdev; newdev = newdev->next)
    if (grub_strcmp (newdev->devname, args[0]) == 0)
      break;

  if (newdev)
    {
      char *newname = grub_strdup (args[1]);
      if (! newname)
	goto fail;

      grub_free (newdev->filename);
      newdev->filename = newname;
      grub_file_close (newdev->file);
      newdev->file = file;

      /* Set has_partitions when `--partitions' was used.  */
      newdev->has_partitions = state[1].set;

      return 0;
    }

  /* Unable to replace it, make a new entry.  */
  newdev = grub_malloc (sizeof (struct grub_loopback));
  if (! newdev)
    goto fail;

  newdev->devname = grub_strdup (args[0]);
  if (! newdev->devname)
    {
      grub_free (newdev);
      goto fail;
    }

  newdev->filename = grub_strdup (args[1]);
  if (! newdev->filename)
    {
      grub_free (newdev->devname);
      grub_free (newdev);
      goto fail;
    }

  newdev->file = file;

  /* Set has_partitions when `--partitions' was used.  */
  newdev->has_partitions = state[1].set;

  /* Add the new entry to the list.  */
  newdev->next = loopback_list;
  loopback_list = newdev;

  return 0;

fail:
  grub_file_close (file);
  return grub_errno;
}
Пример #26
0
static grub_err_t
grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
                int argc, char *argv[])
{
    grub_file_t file = 0;
    struct linux_kernel_header lh;
    grub_ssize_t len, start, filelen;
    void *kernel = NULL;

    grub_dl_ref (my_mod);

    if (argc == 0)
    {
        grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
        goto fail;
    }

    file = grub_file_open (argv[0]);
    if (! file)
        goto fail;

    filelen = grub_file_size (file);

    kernel = grub_malloc(filelen);

    if (!kernel)
    {
        grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer"));
        goto fail;
    }

    if (grub_file_read (file, kernel, filelen) != filelen)
    {
        grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"), argv[0]);
        goto fail;
    }

    grub_tpm_measure (kernel, filelen, GRUB_KERNEL_PCR);

    if (! grub_linuxefi_secure_validate (kernel, filelen))
    {
        grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]);
        grub_free (kernel);
        goto fail;
    }

    params = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(16384));

    if (! params)
    {
        grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters");
        goto fail;
    }

    grub_memset (params, 0, 16384);

    grub_memcpy (&lh, kernel, sizeof (lh));

    if (lh.boot_flag != grub_cpu_to_le16 (0xaa55))
    {
        grub_error (GRUB_ERR_BAD_OS, N_("invalid magic number"));
        goto fail;
    }

    if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS)
    {
        grub_error (GRUB_ERR_BAD_OS, N_("too many setup sectors"));
        goto fail;
    }

    if (lh.version < grub_cpu_to_le16 (0x020b))
    {
        grub_error (GRUB_ERR_BAD_OS, N_("kernel too old"));
        goto fail;
    }

    if (!lh.handover_offset)
    {
        grub_error (GRUB_ERR_BAD_OS, N_("kernel doesn't support EFI handover"));
        goto fail;
    }

    linux_cmdline = grub_efi_allocate_pages_max(0x3fffffff,
                    BYTES_TO_PAGES(lh.cmdline_size + 1));

    if (!linux_cmdline)
    {
        grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline"));
        goto fail;
    }

    grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE));
    grub_create_loader_cmdline (argc, argv,
                                linux_cmdline + sizeof (LINUX_IMAGE) - 1,
                                lh.cmdline_size - (sizeof (LINUX_IMAGE) - 1));

    grub_pass_verity_hash(&lh, linux_cmdline);
    lh.cmd_line_ptr = (grub_uint32_t)(grub_uint64_t)linux_cmdline;

    handover_offset = lh.handover_offset;

    start = (lh.setup_sects + 1) * 512;
    len = grub_file_size(file) - start;

    kernel_mem = grub_efi_allocate_pages(lh.pref_address,
                                         BYTES_TO_PAGES(lh.init_size));

    if (!kernel_mem)
        kernel_mem = grub_efi_allocate_pages_max(0x3fffffff,
                     BYTES_TO_PAGES(lh.init_size));

    if (!kernel_mem)
    {
        grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel"));
        goto fail;
    }

    grub_memcpy (kernel_mem, (char *)kernel + start, len);
    grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0);
    loaded=1;

    lh.code32_start = (grub_uint32_t)(grub_uint64_t) kernel_mem;
    grub_memcpy (params, &lh, 2 * 512);

    params->type_of_loader = 0x21;

fail:

    if (file)
        grub_file_close (file);

    if (kernel)
        grub_free (kernel);

    if (grub_errno != GRUB_ERR_NONE)
    {
        grub_dl_unref (my_mod);
        loaded = 0;
    }

    if (linux_cmdline && !loaded)
        grub_efi_free_pages((grub_efi_physical_address_t)linux_cmdline, BYTES_TO_PAGES(lh.cmdline_size + 1));

    if (kernel_mem && !loaded)
        grub_efi_free_pages((grub_efi_physical_address_t)kernel_mem, BYTES_TO_PAGES(kernel_size));

    if (params && !loaded)
        grub_efi_free_pages((grub_efi_physical_address_t)params, BYTES_TO_PAGES(16384));

    return grub_errno;
}
Пример #27
0
/* Creates new bitmap, saves created bitmap on success to *bitmap.  */
grub_err_t
grub_video_bitmap_create (struct grub_video_bitmap **bitmap,
                          unsigned int width, unsigned int height,
                          enum grub_video_blit_format blit_format)
{
  struct grub_video_mode_info *mode_info;
  unsigned int size;

  if (!bitmap)
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid argument");

  *bitmap = 0;

  if (width == 0 || height == 0)
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid argument");

  *bitmap = (struct grub_video_bitmap *)grub_malloc (sizeof (struct grub_video_bitmap));
  if (! *bitmap)
    return grub_errno;

  mode_info = &((*bitmap)->mode_info);

  /* Populate mode_info.  */
  mode_info->width = width;
  mode_info->height = height;
  mode_info->blit_format = blit_format;

  switch (blit_format)
    {
      case GRUB_VIDEO_BLIT_FORMAT_RGBA_8888:
        mode_info->mode_type = GRUB_VIDEO_MODE_TYPE_RGB
                               | GRUB_VIDEO_MODE_TYPE_ALPHA;
        mode_info->bpp = 32;
        mode_info->bytes_per_pixel = 4;
        mode_info->number_of_colors = 256;
        mode_info->red_mask_size = 8;
        mode_info->red_field_pos = 0;
        mode_info->green_mask_size = 8;
        mode_info->green_field_pos = 8;
        mode_info->blue_mask_size = 8;
        mode_info->blue_field_pos = 16;
        mode_info->reserved_mask_size = 8;
        mode_info->reserved_field_pos = 24;
        break;

      case GRUB_VIDEO_BLIT_FORMAT_RGB_888:
        mode_info->mode_type = GRUB_VIDEO_MODE_TYPE_RGB;
        mode_info->bpp = 24;
        mode_info->bytes_per_pixel = 3;
        mode_info->number_of_colors = 256;
        mode_info->red_mask_size = 8;
        mode_info->red_field_pos = 0;
        mode_info->green_mask_size = 8;
        mode_info->green_field_pos = 8;
        mode_info->blue_mask_size = 8;
        mode_info->blue_field_pos = 16;
        mode_info->reserved_mask_size = 0;
        mode_info->reserved_field_pos = 0;
        break;

      case GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR:
        mode_info->mode_type = GRUB_VIDEO_MODE_TYPE_INDEX_COLOR;
        mode_info->bpp = 8;
        mode_info->bytes_per_pixel = 1;
        mode_info->number_of_colors = 256;
        mode_info->red_mask_size = 0;
        mode_info->red_field_pos = 0;
        mode_info->green_mask_size = 0;
        mode_info->green_field_pos = 0;
        mode_info->blue_mask_size = 0;
        mode_info->blue_field_pos = 0;
        mode_info->reserved_mask_size = 0;
        mode_info->reserved_field_pos = 0;
        break;

      default:
        grub_free (*bitmap);
        *bitmap = 0;

        return grub_error (GRUB_ERR_BAD_ARGUMENT,
                           "unsupported bitmap format");
    }

  mode_info->pitch = width * mode_info->bytes_per_pixel;

  /* Calculate size needed for the data.  */
  size = (width * mode_info->bytes_per_pixel) * height;

  (*bitmap)->data = grub_zalloc (size);
  if (! (*bitmap)->data)
    {
      grub_free (*bitmap);
      *bitmap = 0;

      return grub_errno;
    }

  return GRUB_ERR_NONE;
}
Пример #28
0
/* Print the information on the device NAME.  */
grub_err_t
grub_normal_print_device_info (const char *name)
{
    grub_device_t dev;
    char *p;

    p = grub_strchr (name, ',');
    if (p)
    {
        grub_xputs ("\t");
        grub_printf_ (N_("Partition %s:"), name);
        grub_xputs (" ");
    }
    else
    {
        grub_printf_ (N_("Device %s:"), name);
        grub_xputs (" ");
    }

    dev = grub_device_open (name);
    if (! dev)
        grub_printf ("%s", _("Filesystem cannot be accessed"));
    else if (dev->disk)
    {
        grub_fs_t fs;

        fs = grub_fs_probe (dev);
        /* Ignore all errors.  */
        grub_errno = 0;

        if (fs)
        {
            grub_printf_ (N_("Filesystem type %s"), fs->name);
            if (fs->label)
            {
                char *label;
                (fs->label) (dev, &label);
                if (grub_errno == GRUB_ERR_NONE)
                {
                    if (label && grub_strlen (label))
                    {
                        grub_xputs (" ");
                        grub_printf_ (N_("- Label \"%s\""), label);
                    }
                    grub_free (label);
                }
                grub_errno = GRUB_ERR_NONE;
            }
            if (fs->mtime)
            {
                grub_int32_t tm;
                struct grub_datetime datetime;
                (fs->mtime) (dev, &tm);
                if (grub_errno == GRUB_ERR_NONE)
                {
                    grub_unixtime2datetime (tm, &datetime);
                    grub_xputs (" ");
                    grub_printf_ (N_("- Last modification time %d-%02d-%02d "
                                     "%02d:%02d:%02d %s"),
                                  datetime.year, datetime.month, datetime.day,
                                  datetime.hour, datetime.minute, datetime.second,
                                  grub_get_weekday_name (&datetime));

                }
                grub_errno = GRUB_ERR_NONE;
            }
            if (fs->uuid)
            {
                char *uuid;
                (fs->uuid) (dev, &uuid);
                if (grub_errno == GRUB_ERR_NONE)
                {
                    if (uuid && grub_strlen (uuid))
                        grub_printf (", UUID %s", uuid);
                    grub_free (uuid);
                }
                grub_errno = GRUB_ERR_NONE;
            }
        }
        else if (! dev->disk->has_partitions || dev->disk->partition)
            grub_printf ("%s", _("Unknown filesystem"));
        else
            grub_printf ("%s", _("Partition table"));

        grub_device_close (dev);
    }

    grub_xputs ("\n");
    return grub_errno;
}
Пример #29
0
grub_err_t
grub_mmap_iterate (int (*hook) (grub_uint64_t, grub_uint64_t,
				grub_uint32_t, void *), void *closure)
{
  /* This function resolves overlapping regions and sorts the memory map.
     It uses scanline (sweeping) algorithm.
  */
  /* If same page is used by multiple types it's resolved
     according to priority:
     1 - free memory
     2 - memory usable by firmware-aware code
     3 - unusable memory
     4 - a range deliberately empty
  */
  int priority[GRUB_MACHINE_MEMORY_MAX_TYPE + 2] =
    {
#ifdef GRUB_MACHINE_MEMORY_AVAILABLE
      [GRUB_MACHINE_MEMORY_AVAILABLE] = 1,
#endif
#if defined (GRUB_MACHINE_MEMORY_RESERVED) && GRUB_MACHINE_MEMORY_RESERVED != GRUB_MACHINE_MEMORY_HOLE
      [GRUB_MACHINE_MEMORY_RESERVED] = 3,
#endif
#ifdef GRUB_MACHINE_MEMORY_ACPI
      [GRUB_MACHINE_MEMORY_ACPI] = 2,
#endif
#ifdef GRUB_MACHINE_MEMORY_CODE
      [GRUB_MACHINE_MEMORY_CODE] = 3,
#endif
#ifdef GRUB_MACHINE_MEMORY_NVS
      [GRUB_MACHINE_MEMORY_NVS] = 3,
#endif
      [GRUB_MACHINE_MEMORY_HOLE] = 4,
    };

  int i, k, done;

  struct grub_mmap_scan *scanline_events;
  struct grub_mmap_scan t;

  /* Previous scanline event. */
  grub_uint64_t lastaddr;
  int lasttype;
  /* Current scanline event. */
  int curtype;
  /* How many regions of given type overlap at current location? */
  int present[GRUB_MACHINE_MEMORY_MAX_TYPE + 2];
  /* Number of mmap chunks. */
  int mmap_num;
  struct grub_mmap_iterate_closure c;

#ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE
  struct grub_mmap_region *cur;
#endif

  mmap_num = 0;

#ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE
  for (cur = grub_mmap_overlays; cur; cur = cur->next)
    mmap_num++;
#endif

  grub_machine_mmap_iterate (count_hook, &mmap_num);

  /* Initialize variables. */
  grub_memset (present, 0, sizeof (present));
  scanline_events = (struct grub_mmap_scan *)
    grub_malloc (sizeof (struct grub_mmap_scan) * 2 * mmap_num);

  if (! scanline_events)
    {
      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
			 "couldn't allocate space for new memory map");
    }

  i = 0;
#ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE
  /* Register scanline events. */
  for (cur = grub_mmap_overlays; cur; cur = cur->next)
    {
      scanline_events[i].pos = cur->start;
      scanline_events[i].type = 0;
      if (cur->type == GRUB_MACHINE_MEMORY_HOLE
	  || (cur->type >= 0 && cur->type <= GRUB_MACHINE_MEMORY_MAX_TYPE
	      && priority[cur->type]))
	scanline_events[i].memtype = cur->type;
      else
	scanline_events[i].memtype = GRUB_MACHINE_MEMORY_RESERVED;
      i++;

      scanline_events[i].pos = cur->end;
      scanline_events[i].type = 1;
      scanline_events[i].memtype = scanline_events[i - 1].memtype;
      i++;
    }
#endif /* ! GRUB_MMAP_REGISTER_BY_FIRMWARE */

  c.i = i;
  c.scanline_events = scanline_events;
  c.priority = priority;
  grub_machine_mmap_iterate (fill_hook, &c);

  /* Primitive bubble sort. It has complexity O(n^2) but since we're
     unlikely to have more than 100 chunks it's probably one of the
     fastest for one purpose. */
  done = 1;
  while (done)
    {
      done = 0;
      for (i = 0; i < 2 * mmap_num - 1; i++)
	if (scanline_events[i + 1].pos < scanline_events[i].pos
	    || (scanline_events[i + 1].pos == scanline_events[i].pos
		&& scanline_events[i + 1].type == 0
		&& scanline_events[i].type == 1))
	  {
	    t = scanline_events[i + 1];
	    scanline_events[i + 1] = scanline_events[i];
	    scanline_events[i] = t;
	    done = 1;
	  }
    }

  lastaddr = scanline_events[0].pos;
  lasttype = scanline_events[0].memtype;
  for (i = 0; i < 2 * mmap_num; i++)
    {
      /* Process event. */
      if (scanline_events[i].type)
	present[scanline_events[i].memtype]--;
      else
	present[scanline_events[i].memtype]++;

      /* Determine current region type. */
      curtype = -1;
      for (k = 0; k <= GRUB_MACHINE_MEMORY_MAX_TYPE + 1; k++)
	if (present[k] && (curtype == -1 || priority[k] > priority[curtype]))
	  curtype = k;

      /* Announce region to the hook if necessary. */
      if ((curtype == -1 || curtype != lasttype)
	  && lastaddr != scanline_events[i].pos
	  && lasttype != -1
	  && lasttype != GRUB_MACHINE_MEMORY_HOLE
	  && hook (lastaddr, scanline_events[i].pos - lastaddr, lasttype,
		   closure))
	{
	  grub_free (scanline_events);
	  return GRUB_ERR_NONE;
	}

      /* Update last values if necessary. */
      if (curtype == -1 || curtype != lasttype)
	{
	  lasttype = curtype;
	  lastaddr = scanline_events[i].pos;
	}
    }

  grub_free (scanline_events);
  return GRUB_ERR_NONE;
}
Пример #30
0
static grub_err_t
grub_ls_list_files (char *dirname, int longlist, int all, int human)
{
  char *device_name;
  grub_fs_t fs;
  const char *path;
  grub_device_t dev;

  device_name = grub_file_get_device_name (dirname);
  dev = grub_device_open (device_name);
  if (! dev)
    goto fail;

  fs = grub_fs_probe (dev);
  path = grub_strchr (dirname, ')');
  if (! path)
    path = dirname;
  else
    path++;

  if (! path && ! device_name)
    {
      grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid argument");
      goto fail;
    }

  if (! *path)
    {
      if (grub_errno == GRUB_ERR_UNKNOWN_FS)
	grub_errno = GRUB_ERR_NONE;

      grub_normal_print_device_info (device_name);
    }
  else if (fs)
    {
      struct grub_ls_list_files_ctx ctx = {
	.dirname = dirname,
	.all = all,
	.human = human
      };

      if (longlist)
	(fs->dir) (dev, path, print_files_long, &ctx);
      else
	(fs->dir) (dev, path, print_files, &ctx);

      if (grub_errno == GRUB_ERR_BAD_FILE_TYPE
	  && path[grub_strlen (path) - 1] != '/')
	{
	  /* PATH might be a regular file.  */
	  char *p;
	  grub_file_t file;
	  struct grub_dirhook_info info;
	  grub_errno = 0;

	  grub_file_filter_disable_compression ();
	  file = grub_file_open (dirname);
	  if (! file)
	    goto fail;

	  grub_file_close (file);

	  p = grub_strrchr (dirname, '/') + 1;
	  dirname = grub_strndup (dirname, p - dirname);
	  if (! dirname)
	    goto fail;

	  all = 1;
	  grub_memset (&info, 0, sizeof (info));
	  if (longlist)
	    print_files_long (p, &info, &ctx);
	  else
	    print_files (p, &info, &ctx);

	  grub_free (dirname);
	}

      if (grub_errno == GRUB_ERR_NONE)
	grub_xputs ("\n");

      grub_refresh ();
    }

 fail:
  if (dev)
    grub_device_close (dev);

  grub_free (device_name);

  return 0;
}