On 03.02.2012 13:04, Diego Guella wrote:

From: "Vladimir 'φ-coder/phcoder' Serbinenko" <phco...@gmail.com>
Both Colin Watson and I tried to reproduce it or similar problems but couldn't other than on heavily desynced and corrupted disk. If you can supply the test images (just GRUB+kernel) using latest bzr upstream I'd happily fix it, otherwise I don't see what I can do.

I need to understand better what you need.
Do you need the dd images of all the disks?
Here is replacement for getext.c. It had several problems leading it to attempt to translate a message about failed translation and failing again until stack overflow.

This is a summary of the first disk:
-----
root@devilserver:~# fdisk -u -l /dev/sda

Disk /dev/sda: 2000.4 GB, 2000398934016 bytes
255 heads, 63 sectors/track, 243201 cylinders, total 3907029168 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x0007982f

  Device Boot      Start         End      Blocks   Id  System
/dev/sda1 2048 1953791 975872 82 Linux swap / Solaris
Partition 1 does not end on cylinder boundary.
/dev/sda2 1953792 99610623 48828416 fd Linux raid autodetect /dev/sda3 99610624 3907028991 1903709184 fd Linux raid autodetect
-----

Supplying the entire image, even omitting the 3rd partition (/home) is not feasible, both for size (40+GiB) and for security reasons. What I can do for sure is blank out one of the 5 disks, and do whatever you tell me to do on it.
Or supply a dd image of the first 2048 sectors of the disk.
Or the first sectors of the / partition.
Or the files in my /boot directory.

I want to remember you this:
-When the system works, the "Welcome to GRUB" appears for some milliseconds, then I see the GRUB menu. -When the system does not work (original installation HDDs missing), "Welcome to GRUB" appears for some time, then the system reboots.
This is way before loading the kernel.




--
Regards
Vladimir 'φ-coder/phcoder' Serbinenko

/* gettext.c - gettext module */
/*
 *  GRUB  --  GRand Unified Bootloader
 *  Copyright (C) 2009 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 <grub/types.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/err.h>
#include <grub/dl.h>
#include <grub/normal.h>
#include <grub/file.h>
#include <grub/kernel.h>
#include <grub/i18n.h>

GRUB_MOD_LICENSE ("GPLv3+");

/*
   .mo file information from:
   http://www.gnu.org/software/autoconf/manual/gettext/MO-Files.html .
*/


static grub_file_t fd_mo;

static grub_off_t grub_gettext_offset_original;
static grub_off_t grub_gettext_offset_translation;
static grub_size_t grub_gettext_max;
static int grub_gettext_max_log;

static const char *(*grub_gettext_original) (const char *s);

struct grub_gettext_msg
{
  char *name;
  char *translated;
};

static struct grub_gettext_msg *grub_gettext_msg_list = NULL;

struct header
{
  grub_uint32_t magic;
  grub_uint32_t version;
  grub_uint32_t number_of_strings;
  grub_uint32_t offset_original;
  grub_uint32_t offset_translation;
};

struct string_descriptor 
{
  grub_uint32_t length;
  grub_uint32_t offset;
};

#define MO_MAGIC_NUMBER 		0x950412de

static grub_err_t
grub_gettext_pread (grub_file_t file, void *buf, grub_size_t len,
		    grub_off_t offset)
{
  if (grub_file_seek (file, offset) == (grub_off_t) - 1)
    return grub_errno;
  if (grub_file_read (file, buf, len) != (grub_ssize_t) len)
    {
      if (!grub_errno)
	grub_error (GRUB_ERR_READ_ERROR, N_("premature end of file"));
      return grub_errno;
    }
  return GRUB_ERR_NONE;
}

static char *
grub_gettext_getstr_from_position (grub_off_t off,
				   grub_size_t position)
{
  grub_off_t internal_position;
  grub_size_t length;
  grub_off_t offset;
  char *translation;
  struct string_descriptor desc;
  grub_err_t err;

  internal_position = (off + position * sizeof (desc));

  err = grub_gettext_pread (fd_mo, (char *) &desc,
			    sizeof (desc), internal_position);
  if (err)
    return NULL;
  length = grub_cpu_to_le32 (desc.length);
  offset = grub_cpu_to_le32 (desc.offset);

  translation = grub_malloc (length + 1);
  if (!translation)
    return NULL;

  err = grub_gettext_pread (fd_mo, translation, length, offset);
  if (err)
    {
      grub_free (translation);
      return NULL;
    }
  translation[length] = '\0';

  return translation;
}

static const char *
grub_gettext_gettranslation_from_position (grub_size_t position)
{
  if (!grub_gettext_msg_list[position].translated)
    grub_gettext_msg_list[position].translated
      = grub_gettext_getstr_from_position (grub_gettext_offset_translation,
					   position);
  return grub_gettext_msg_list[position].translated;
}

static const char *
grub_gettext_getstring_from_position (grub_size_t position)
{
  if (!grub_gettext_msg_list[position].name)
    grub_gettext_msg_list[position].name
      = grub_gettext_getstr_from_position (grub_gettext_offset_original,
					   position);
  return grub_gettext_msg_list[position].name;
}

static const char *
grub_gettext_translate (const char *orig)
{
  grub_size_t current = 0;
  int i;
  const char *current_string;

  if (!grub_gettext_msg_list || !fd_mo)
    return orig;

  /* Make sure we can use grub_gettext_translate for error messages.  Push
     active error message to error stack and reset error message.  */
  grub_error_push ();

  for (i = grub_gettext_max_log; i >= 0; i--)
    {
      grub_size_t test;
      int cmp;

      test = current | (1 << i);
      if (test >= grub_gettext_max)
	continue;

      current_string = grub_gettext_getstring_from_position (test);

      if (!current_string)
	{
	  grub_errno = GRUB_ERR_NONE;
	  grub_error_pop ();
	  return orig;
	}

      /* Search by bisection.  */
      cmp = grub_strcmp (current_string, orig);
      if (cmp <= 0)
	current = test;
      if (cmp == 0)
	{
	  const char *ret = 0;
	  ret = grub_gettext_gettranslation_from_position (current);
	  if (!ret)
	    {
	      grub_errno = GRUB_ERR_NONE;
	      grub_error_pop ();
	      return orig;
	    }
	  grub_error_pop ();
	  return ret;      
	}
    }

  grub_error_pop ();
  return orig;    
}

static void
grub_gettext_delete_list (void)
{
  struct grub_gettext_msg *l = grub_gettext_msg_list;
  grub_size_t i;

  if (!l)
    return;
  grub_gettext_msg_list = 0;
  for (i = 0; i < grub_gettext_max; i++)
    grub_free (l[i].name);
  /* Don't delete the translated message because could be in use.  */
  grub_free (l);
}

/* This is similar to grub_file_open. */
static grub_err_t
grub_mofile_open (const char *filename)
{
  struct header head;
  grub_err_t err;
  grub_file_t fd;

  /* Using fd_mo and not another variable because
     it's needed for grub_gettext_get_info.  */

  fd = grub_file_open (filename);

  if (!fd)
    return grub_errno;

  err = grub_gettext_pread (fd, &head, sizeof (head), 0);
  if (err)
    {
      grub_file_close (fd);
      return err;
    }

  if (head.magic != grub_cpu_to_le32_compile_time (MO_MAGIC_NUMBER))
    {
      grub_file_close (fd);
      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
			 "mo: invalid mo magic in file: %s", filename);
    }

  if (head.version != 0)
    {
      grub_file_close (fd);
      return grub_error (GRUB_ERR_BAD_FILE_TYPE,
			 "mo: invalid mo version in file: %s", filename);
    }

  grub_gettext_offset_original = grub_le_to_cpu32 (head.offset_original);
  grub_gettext_offset_translation = grub_le_to_cpu32 (head.offset_translation);
  grub_gettext_max = grub_le_to_cpu32 (head.number_of_strings);
  for (grub_gettext_max_log = 0; grub_gettext_max >> grub_gettext_max_log;
       grub_gettext_max_log++);
  if (fd_mo)
    grub_file_close (fd_mo);
  fd_mo = 0;

  grub_gettext_delete_list ();
  grub_gettext_msg_list = grub_zalloc (grub_gettext_max
				       * sizeof (grub_gettext_msg_list[0]));
  if (!grub_gettext_msg_list)
    {
      grub_file_close (fd);
      return grub_errno;
    }
  fd_mo = fd;
  if (grub_gettext != grub_gettext_translate)
    {
      grub_gettext_original = grub_gettext;
      grub_gettext = grub_gettext_translate;
    }
  return 0;
}

/* Returning grub_file_t would be more natural, but grub_mofile_open assigns
   to fd_mo anyway ...  */
static grub_err_t
grub_mofile_open_lang (const char *locale_dir, const char *locale)
{
  char *mo_file;
  grub_err_t err;

  /* mo_file e.g.: /boot/grub/locale/ca.mo   */

  mo_file = grub_xasprintf ("%s/%s.mo", locale_dir, locale);
  if (!mo_file)
    return grub_errno;

  err = grub_mofile_open (mo_file);

  /* Will try adding .gz as well.  */
  if (err)
    {
      char *mo_file_old;
      grub_errno = GRUB_ERR_NONE;
      mo_file_old = mo_file;
      mo_file = grub_xasprintf ("%s.gz", mo_file);
      grub_free (mo_file_old);
      if (!mo_file)
	return grub_errno;
      err = grub_mofile_open (mo_file);
    }
  return err;
}

static grub_err_t
grub_gettext_init_ext (const char *locale)
{
  const char *locale_dir;
  grub_err_t err;

  if (!locale)
    return 0;

  locale_dir = grub_env_get ("locale_dir");
  if (locale_dir == NULL)
    {
      grub_dprintf ("gettext", "locale_dir variable is not set up.\n");
      return 0;
    }

  err = grub_mofile_open_lang (locale_dir, locale);

  /* ll_CC didn't work, so try ll.  */
  if (err)
    {
      char *lang = grub_strdup (locale);
      char *underscore = lang ? grub_strchr (lang, '_') : 0;

      if (underscore)
	{
	  *underscore = '\0';
	  grub_errno = GRUB_ERR_NONE;
	  err = grub_mofile_open_lang (locale_dir, lang);
	}

      grub_free (lang);
    }
  return err;
}

static char *
grub_gettext_env_write_lang (struct grub_env_var *var
			     __attribute__ ((unused)), const char *val)
{
  grub_err_t err;
  err = grub_gettext_init_ext (val);
  if (err)
    {
      grub_print_error ();
      return NULL;
    }

  return grub_strdup (val);
}

static grub_err_t
grub_cmd_translate (grub_command_t cmd __attribute__ ((unused)),
		    int argc, char **args)
{
  if (argc != 1)
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "text to translate required");

  const char *translation;
  translation = grub_gettext_translate (args[0]);
  grub_printf ("%s\n", translation);
  return 0;
}

GRUB_MOD_INIT (gettext)
{
  const char *lang;

  lang = grub_env_get ("lang");

  grub_gettext_init_ext (lang);

  grub_register_command_p1 ("gettext", grub_cmd_translate,
			    N_("STRING"),
			    N_("Translates the string with the current settings."));

  /* Reload .mo file information if lang changes.  */
  grub_register_variable_hook ("lang", NULL, grub_gettext_env_write_lang);

  /* Preserve hooks after context changes.  */
  grub_env_export ("lang");
}

GRUB_MOD_FINI (gettext)
{
  if (fd_mo != 0)
    grub_file_close (fd_mo);

  grub_gettext_delete_list ();

  grub_gettext = grub_gettext_original;
}

Reply via email to