mirror of
				https://git.proxmox.com/git/grub2
				synced 2025-11-04 12:55:16 +00:00 
			
		
		
		
	Add helper grub_util_free_path_list and use it where appropriate. Found by: Coverity scan. CID: 73727
		
			
				
	
	
		
			288 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			288 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 *  GRUB  --  GRand Unified Bootloader
 | 
						|
 *  Copyright (C) 2002,2007  Free Software Foundation, Inc.
 | 
						|
 *
 | 
						|
 *  GRUB is free software: you can redistribute it and/or modify
 | 
						|
 *  it under the terms of the GNU General Public License as published by
 | 
						|
 *  the Free Software Foundation, either version 3 of the License, or
 | 
						|
 *  (at your option) any later version.
 | 
						|
 *
 | 
						|
 *  GRUB is distributed in the hope that it will be useful,
 | 
						|
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
 *  GNU General Public License for more details.
 | 
						|
 *
 | 
						|
 *  You should have received a copy of the GNU General Public License
 | 
						|
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | 
						|
 */
 | 
						|
 | 
						|
#include <config.h>
 | 
						|
 | 
						|
#include <stdio.h>
 | 
						|
#include <string.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <ctype.h>
 | 
						|
#include <errno.h>
 | 
						|
 | 
						|
#include <grub/emu/misc.h>
 | 
						|
#include <grub/misc.h>
 | 
						|
#include <grub/util/misc.h>
 | 
						|
#include <grub/util/resolve.h>
 | 
						|
#include <grub/i18n.h>
 | 
						|
 | 
						|
/* Module.  */
 | 
						|
struct mod_list
 | 
						|
{
 | 
						|
  const char *name;
 | 
						|
  struct mod_list *next;
 | 
						|
};
 | 
						|
 | 
						|
/* Dependency.  */
 | 
						|
struct dep_list
 | 
						|
{
 | 
						|
  const char *name;
 | 
						|
  struct mod_list *list;
 | 
						|
  struct dep_list *next;
 | 
						|
};
 | 
						|
 | 
						|
static char buf[1024];
 | 
						|
 | 
						|
static void
 | 
						|
free_mod_list (struct mod_list *head)
 | 
						|
{
 | 
						|
  while (head)
 | 
						|
    {
 | 
						|
      struct mod_list *next;
 | 
						|
 | 
						|
      next = head->next;
 | 
						|
      free ((void *) head->name);
 | 
						|
      free (head);
 | 
						|
      head = next;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
free_dep_list (struct dep_list *head)
 | 
						|
{
 | 
						|
  while (head)
 | 
						|
    {
 | 
						|
      struct dep_list *next;
 | 
						|
 | 
						|
      next = head->next;
 | 
						|
      free ((void *) head->name);
 | 
						|
      free_mod_list (head->list);
 | 
						|
      free (head);
 | 
						|
      head = next;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/* Read the list of dependencies.  */
 | 
						|
static struct dep_list *
 | 
						|
read_dep_list (FILE *fp)
 | 
						|
{
 | 
						|
  struct dep_list *dep_list = 0;
 | 
						|
 | 
						|
  while (fgets (buf, sizeof (buf), fp))
 | 
						|
    {
 | 
						|
      char *p;
 | 
						|
      struct dep_list *dep;
 | 
						|
 | 
						|
      /* Get the target name.  */
 | 
						|
      p = strchr (buf, ':');
 | 
						|
      if (! p)
 | 
						|
	grub_util_error (_("invalid line format: %s"), buf);
 | 
						|
 | 
						|
      *p++ = '\0';
 | 
						|
 | 
						|
      dep = xmalloc (sizeof (*dep));
 | 
						|
      dep->name = xstrdup (buf);
 | 
						|
      dep->list = 0;
 | 
						|
 | 
						|
      dep->next = dep_list;
 | 
						|
      dep_list = dep;
 | 
						|
 | 
						|
      /* Add dependencies.  */
 | 
						|
      while (*p)
 | 
						|
	{
 | 
						|
	  struct mod_list *mod;
 | 
						|
	  char *name;
 | 
						|
 | 
						|
	  /* Skip whitespace.  */
 | 
						|
	  while (*p && grub_isspace (*p))
 | 
						|
	    p++;
 | 
						|
 | 
						|
	  if (! *p)
 | 
						|
	    break;
 | 
						|
 | 
						|
	  name = p;
 | 
						|
 | 
						|
	  /* Skip non-whitespace.  */
 | 
						|
	  while (*p && ! grub_isspace (*p))
 | 
						|
	    p++;
 | 
						|
 | 
						|
	  *p++ = '\0';
 | 
						|
 | 
						|
	  mod = (struct mod_list *) xmalloc (sizeof (*mod));
 | 
						|
	  mod->name = xstrdup (name);
 | 
						|
	  mod->next = dep->list;
 | 
						|
	  dep->list = mod;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  return dep_list;
 | 
						|
}
 | 
						|
 | 
						|
static char *
 | 
						|
get_module_name (const char *str)
 | 
						|
{
 | 
						|
  char *base;
 | 
						|
  char *ext;
 | 
						|
 | 
						|
  base = strrchr (str, '/');
 | 
						|
  if (! base)
 | 
						|
    base = (char *) str;
 | 
						|
  else
 | 
						|
    base++;
 | 
						|
 | 
						|
  ext = strrchr (base, '.');
 | 
						|
  if (ext && strcmp (ext, ".mod") == 0)
 | 
						|
    {
 | 
						|
      char *name;
 | 
						|
 | 
						|
      name = xmalloc (ext - base + 1);
 | 
						|
      memcpy (name, base, ext - base);
 | 
						|
      name[ext - base] = '\0';
 | 
						|
      return name;
 | 
						|
    }
 | 
						|
 | 
						|
  return xstrdup (base);
 | 
						|
}
 | 
						|
 | 
						|
static char *
 | 
						|
get_module_path (const char *prefix, const char *str)
 | 
						|
{
 | 
						|
  char *dir;
 | 
						|
  char *base;
 | 
						|
  char *ext;
 | 
						|
  char *ret;
 | 
						|
 | 
						|
  ext = strrchr (str, '.');
 | 
						|
  if (ext && strcmp (ext, ".mod") == 0)
 | 
						|
    base = xstrdup (str);
 | 
						|
  else
 | 
						|
    {
 | 
						|
      base = xmalloc (strlen (str) + 4 + 1);
 | 
						|
      sprintf (base, "%s.mod", str);
 | 
						|
    }
 | 
						|
 | 
						|
  dir = strchr (str, '/');
 | 
						|
  if (dir)
 | 
						|
    return base;
 | 
						|
 | 
						|
  ret = grub_util_get_path (prefix, base);
 | 
						|
  free (base);
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
add_module (const char *dir,
 | 
						|
	    struct dep_list *dep_list,
 | 
						|
	    struct mod_list **mod_head,
 | 
						|
	    struct grub_util_path_list **path_head,
 | 
						|
	    const char *name)
 | 
						|
{
 | 
						|
  char *mod_name;
 | 
						|
  struct grub_util_path_list *path;
 | 
						|
  struct mod_list *mod;
 | 
						|
  struct dep_list *dep;
 | 
						|
 | 
						|
  mod_name = get_module_name (name);
 | 
						|
 | 
						|
  /* Check if the module has already been added.  */
 | 
						|
  for (mod = *mod_head; mod; mod = mod->next)
 | 
						|
    if (strcmp (mod->name, mod_name) == 0)
 | 
						|
      {
 | 
						|
	free (mod_name);
 | 
						|
	return;
 | 
						|
      }
 | 
						|
 | 
						|
  /* Resolve dependencies.  */
 | 
						|
  for (dep = dep_list; dep; dep = dep->next)
 | 
						|
    if (strcmp (dep->name, mod_name) == 0)
 | 
						|
      {
 | 
						|
	for (mod = dep->list; mod; mod = mod->next)
 | 
						|
	  add_module (dir, dep_list, mod_head, path_head, mod->name);
 | 
						|
 | 
						|
	break;
 | 
						|
      }
 | 
						|
 | 
						|
  /* Add this module.  */
 | 
						|
  mod = (struct mod_list *) xmalloc (sizeof (*mod));
 | 
						|
  mod->name = mod_name;
 | 
						|
  mod->next = *mod_head;
 | 
						|
  *mod_head = mod;
 | 
						|
 | 
						|
  /* Add this path.  */
 | 
						|
  path = (struct grub_util_path_list *) xmalloc (sizeof (*path));
 | 
						|
  path->name = get_module_path (dir, name);
 | 
						|
  path->next = *path_head;
 | 
						|
  *path_head = path;
 | 
						|
}
 | 
						|
 | 
						|
struct grub_util_path_list *
 | 
						|
grub_util_resolve_dependencies (const char *prefix,
 | 
						|
				const char *dep_list_file,
 | 
						|
				char *modules[])
 | 
						|
{
 | 
						|
  char *path;
 | 
						|
  FILE *fp;
 | 
						|
  struct dep_list *dep_list;
 | 
						|
  struct mod_list *mod_list = 0;
 | 
						|
  struct grub_util_path_list *path_list = 0;
 | 
						|
 | 
						|
  path = grub_util_get_path (prefix, dep_list_file);
 | 
						|
  fp = grub_util_fopen (path, "r");
 | 
						|
  if (! fp)
 | 
						|
    grub_util_error (_("cannot open `%s': %s"), path, strerror (errno));
 | 
						|
 | 
						|
  free (path);
 | 
						|
  dep_list = read_dep_list (fp);
 | 
						|
  fclose (fp);
 | 
						|
 | 
						|
  while (*modules)
 | 
						|
    {
 | 
						|
      add_module (prefix, dep_list, &mod_list, &path_list, *modules);
 | 
						|
      modules++;
 | 
						|
    }
 | 
						|
 | 
						|
  free_dep_list (dep_list);
 | 
						|
  free_mod_list (mod_list);
 | 
						|
 | 
						|
  { /* Reverse the path_list */
 | 
						|
    struct grub_util_path_list *p, *prev, *next;
 | 
						|
 | 
						|
    for (p = path_list, prev = NULL; p; p = next)
 | 
						|
      {
 | 
						|
	next = p->next;
 | 
						|
	p->next = prev;
 | 
						|
	prev = p;
 | 
						|
      }
 | 
						|
 | 
						|
    return prev;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
grub_util_free_path_list (struct grub_util_path_list *path_list)
 | 
						|
{
 | 
						|
  struct grub_util_path_list *next;
 | 
						|
 | 
						|
  while (path_list)
 | 
						|
    {
 | 
						|
      next = path_list->next;
 | 
						|
      free ((void *) path_list->name);
 | 
						|
      free (path_list);
 | 
						|
      path_list = next;
 | 
						|
    }
 | 
						|
}
 |