The add_tar_files() function currently iterates through a directory's content using readdir(), which doesn't guarantee a specific order. This lack of deterministic behavior impacts reproducibility in the build process. This commit resolves the issue by introducing sorting functionality. The list retrieved by readdir() is now sorted alphabetically before incorporation into the tar archive, ensuring consistent and predictable file ordering within the archive. On the occasion fix tfp memory leak. Signed-off-by: Michael Chang <mchang@suse.com> Signed-off-by: Bernhard Wiedemann <bwiedemann@suse.com> Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
385 lines
8.9 KiB
C
385 lines
8.9 KiB
C
|
|
/*
|
|
* Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013 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 <grub/util/install.h>
|
|
#include <grub/util/misc.h>
|
|
#include <grub/emu/config.h>
|
|
|
|
#include <string.h>
|
|
|
|
#pragma GCC diagnostic ignored "-Wmissing-prototypes"
|
|
#pragma GCC diagnostic ignored "-Wmissing-declarations"
|
|
#include <argp.h>
|
|
#pragma GCC diagnostic error "-Wmissing-prototypes"
|
|
#pragma GCC diagnostic error "-Wmissing-declarations"
|
|
|
|
/* use 2015-01-01T00:00:00+0000 as a stock timestamp */
|
|
#define STABLE_EMBEDDING_TIMESTAMP 1420070400
|
|
|
|
static char *output_image;
|
|
static char **files;
|
|
static int nfiles;
|
|
const struct grub_install_image_target_desc *format;
|
|
static FILE *memdisk;
|
|
|
|
enum
|
|
{
|
|
OPTION_OUTPUT = 'o',
|
|
OPTION_FORMAT = 'O'
|
|
};
|
|
|
|
static struct argp_option options[] = {
|
|
GRUB_INSTALL_OPTIONS,
|
|
{"output", 'o', N_("FILE"),
|
|
0, N_("save output in FILE [required]"), 2},
|
|
{"format", 'O', N_("FILE"), 0, 0, 2},
|
|
{"compression", 'C', "xz|none|auto", OPTION_HIDDEN, 0, 2},
|
|
{0, 0, 0, 0, 0, 0}
|
|
};
|
|
|
|
static char *
|
|
help_filter (int key, const char *text, void *input __attribute__ ((unused)))
|
|
{
|
|
switch (key)
|
|
{
|
|
case 'O':
|
|
{
|
|
char *formats = grub_install_get_image_targets_string (), *ret;
|
|
ret = xasprintf ("%s\n%s %s", _("generate an image in FORMAT"),
|
|
_("available formats:"), formats);
|
|
free (formats);
|
|
return ret;
|
|
}
|
|
default:
|
|
return grub_install_help_filter (key, text, input);
|
|
}
|
|
}
|
|
|
|
static error_t
|
|
argp_parser (int key, char *arg, struct argp_state *state)
|
|
{
|
|
if (key == 'C')
|
|
key = GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS;
|
|
|
|
if (grub_install_parse (key, arg))
|
|
return 0;
|
|
|
|
switch (key)
|
|
{
|
|
|
|
case 'o':
|
|
if (output_image)
|
|
free (output_image);
|
|
|
|
output_image = xstrdup (arg);
|
|
break;
|
|
|
|
case 'O':
|
|
{
|
|
format = grub_install_get_image_target (arg);
|
|
if (!format)
|
|
{
|
|
printf (_("unknown target format %s\n"), arg);
|
|
argp_usage (state);
|
|
exit (1);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ARGP_KEY_ARG:
|
|
files[nfiles++] = xstrdup (arg);
|
|
break;
|
|
|
|
default:
|
|
return ARGP_ERR_UNKNOWN;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
struct argp argp = {
|
|
options, argp_parser, N_("[OPTION] SOURCE..."),
|
|
N_("Generate a standalone image (containing all modules) in the selected format")"\v"N_("Graft point syntax (E.g. /boot/grub/grub.cfg=./grub.cfg) is accepted"),
|
|
NULL, help_filter, NULL
|
|
};
|
|
|
|
/* tar support */
|
|
#define MAGIC "ustar"
|
|
struct head
|
|
{
|
|
char name[100];
|
|
char mode[8];
|
|
char uid[8];
|
|
char gid[8];
|
|
char size[12];
|
|
char mtime[12];
|
|
char chksum[8];
|
|
char typeflag;
|
|
char linkname[100];
|
|
char magic[6];
|
|
char version[2];
|
|
char uname[32];
|
|
char gname[32];
|
|
char devmajor[8];
|
|
char devminor[8];
|
|
char prefix[155];
|
|
char pad[12];
|
|
} GRUB_PACKED;
|
|
|
|
static void
|
|
write_zeros (unsigned rsz)
|
|
{
|
|
char buf[512];
|
|
|
|
memset (buf, 0, 512);
|
|
fwrite (buf, 1, rsz, memdisk);
|
|
}
|
|
|
|
static void
|
|
write_pad (unsigned sz)
|
|
{
|
|
write_zeros ((~sz + 1) & 511);
|
|
}
|
|
|
|
static void
|
|
set_tar_value (char *field, grub_uint32_t val,
|
|
unsigned len)
|
|
{
|
|
unsigned i;
|
|
for (i = 0; i < len - 1; i++)
|
|
field[len - 2 - i] = '0' + ((val >> (3 * i)) & 7);
|
|
}
|
|
|
|
static void
|
|
compute_checksum (struct head *hd)
|
|
{
|
|
unsigned int chk = 0;
|
|
unsigned char *ptr;
|
|
memset (hd->chksum, ' ', 8);
|
|
for (ptr = (unsigned char *) hd; ptr < (unsigned char *) (hd + 1); ptr++)
|
|
chk += *ptr;
|
|
set_tar_value (hd->chksum, chk, 8);
|
|
}
|
|
|
|
static void
|
|
add_tar_file (const char *from,
|
|
const char *to)
|
|
{
|
|
char *tcn;
|
|
const char *iptr;
|
|
char *optr;
|
|
struct head hd;
|
|
grub_util_fd_t in;
|
|
ssize_t r;
|
|
grub_uint32_t size;
|
|
|
|
COMPILE_TIME_ASSERT (sizeof (hd) == 512);
|
|
|
|
if (grub_util_is_special_file (from))
|
|
return;
|
|
|
|
optr = tcn = xmalloc (strlen (to) + 1);
|
|
for (iptr = to; *iptr == '/'; iptr++);
|
|
for (; *iptr; iptr++)
|
|
if (!(iptr[0] == '/' && iptr[1] == '/'))
|
|
*optr++ = *iptr;
|
|
*optr = '\0';
|
|
|
|
if (grub_util_is_directory (from))
|
|
{
|
|
grub_util_fd_dir_t d;
|
|
grub_util_fd_dirent_t de;
|
|
char **from_files;
|
|
grub_size_t alloc = 8, used = 0;
|
|
grub_size_t i;
|
|
|
|
d = grub_util_fd_opendir (from);
|
|
|
|
from_files = xmalloc (alloc * sizeof (*from_files));
|
|
while ((de = grub_util_fd_readdir (d)))
|
|
{
|
|
if (strcmp (de->d_name, ".") == 0)
|
|
continue;
|
|
if (strcmp (de->d_name, "..") == 0)
|
|
continue;
|
|
if (alloc <= used)
|
|
{
|
|
alloc <<= 1;
|
|
from_files = xrealloc (from_files, alloc * sizeof (*from_files));
|
|
}
|
|
from_files[used++] = xstrdup (de->d_name);
|
|
}
|
|
|
|
qsort (from_files, used, sizeof (*from_files), grub_qsort_strcmp);
|
|
|
|
for (i = 0; i < used; i++)
|
|
{
|
|
char *fp, *tfp;
|
|
|
|
fp = grub_util_path_concat (2, from, from_files[i]);
|
|
tfp = xasprintf ("%s/%s", to, from_files[i]);
|
|
add_tar_file (fp, tfp);
|
|
free (tfp);
|
|
free (fp);
|
|
free (from_files[i]);
|
|
}
|
|
|
|
grub_util_fd_closedir (d);
|
|
free (from_files);
|
|
free (tcn);
|
|
return;
|
|
}
|
|
|
|
if (optr - tcn > 99)
|
|
{
|
|
memset (&hd, 0, sizeof (hd));
|
|
memcpy (hd.name, tcn, 99);
|
|
memcpy (hd.mode, "0000600", 7);
|
|
memcpy (hd.uid, "0001750", 7);
|
|
memcpy (hd.gid, "0001750", 7);
|
|
|
|
set_tar_value (hd.size, optr - tcn, 12);
|
|
set_tar_value (hd.mtime, STABLE_EMBEDDING_TIMESTAMP, 12);
|
|
hd.typeflag = 'L';
|
|
memcpy (hd.magic, MAGIC, sizeof (hd.magic));
|
|
memcpy (hd.uname, "grub", 4);
|
|
memcpy (hd.gname, "grub", 4);
|
|
|
|
compute_checksum (&hd);
|
|
|
|
fwrite (&hd, 1, sizeof (hd), memdisk);
|
|
fwrite (tcn, 1, optr - tcn, memdisk);
|
|
|
|
write_pad (optr - tcn);
|
|
}
|
|
|
|
in = grub_util_fd_open (from, GRUB_UTIL_FD_O_RDONLY);
|
|
if (!GRUB_UTIL_FD_IS_VALID (in))
|
|
grub_util_error (_("cannot open `%s': %s"), from, grub_util_fd_strerror ());
|
|
|
|
if (!grub_install_copy_buffer)
|
|
grub_install_copy_buffer = xmalloc (GRUB_INSTALL_COPY_BUFFER_SIZE);
|
|
|
|
size = grub_util_get_fd_size (in, from, NULL);
|
|
|
|
memset (&hd, 0, sizeof (hd));
|
|
memcpy (hd.name, tcn, optr - tcn < 99 ? optr - tcn : 99);
|
|
memcpy (hd.mode, "0000600", 7);
|
|
memcpy (hd.uid, "0001750", 7);
|
|
memcpy (hd.gid, "0001750", 7);
|
|
|
|
set_tar_value (hd.size, size, 12);
|
|
set_tar_value (hd.mtime, STABLE_EMBEDDING_TIMESTAMP, 12);
|
|
hd.typeflag = '0';
|
|
memcpy (hd.magic, MAGIC, sizeof (hd.magic));
|
|
memcpy (hd.uname, "grub", 4);
|
|
memcpy (hd.gname, "grub", 4);
|
|
|
|
compute_checksum (&hd);
|
|
|
|
fwrite (&hd, 1, sizeof (hd), memdisk);
|
|
|
|
while (1)
|
|
{
|
|
r = grub_util_fd_read (in, grub_install_copy_buffer, GRUB_INSTALL_COPY_BUFFER_SIZE);
|
|
if (r <= 0)
|
|
break;
|
|
fwrite (grub_install_copy_buffer, 1, r, memdisk);
|
|
}
|
|
grub_util_fd_close (in);
|
|
|
|
write_pad (size);
|
|
free (tcn);
|
|
}
|
|
|
|
int
|
|
main (int argc, char *argv[])
|
|
{
|
|
const char *pkglibdir;
|
|
int i;
|
|
|
|
grub_util_host_init (&argc, &argv);
|
|
grub_util_disable_fd_syncs ();
|
|
|
|
files = xcalloc (argc + 1, sizeof (files[0]));
|
|
|
|
argp_parse (&argp, argc, argv, 0, 0, 0);
|
|
|
|
pkglibdir = grub_util_get_pkglibdir ();
|
|
|
|
if (!output_image)
|
|
grub_util_error ("%s", _("output file must be specified"));
|
|
|
|
if (!format)
|
|
grub_util_error ("%s", _("Target format not specified (use the -O option)."));
|
|
|
|
if (!grub_install_source_directory)
|
|
grub_install_source_directory = grub_util_path_concat (2, pkglibdir, grub_util_get_target_dirname (format));
|
|
|
|
enum grub_install_plat plat = grub_install_get_target (grub_install_source_directory);
|
|
|
|
char *memdisk_dir = grub_util_make_temporary_dir ();
|
|
char *boot_grub = grub_util_path_concat (3, memdisk_dir, "boot", "grub");
|
|
grub_install_copy_files (grub_install_source_directory,
|
|
boot_grub, plat);
|
|
|
|
grub_set_install_backup_ponr ();
|
|
|
|
char *memdisk_img = grub_util_make_temporary_file ();
|
|
|
|
memdisk = grub_util_fopen (memdisk_img, "wb");
|
|
|
|
add_tar_file (memdisk_dir, "");
|
|
for (i = 0; i < nfiles; i++)
|
|
{
|
|
char *eq = grub_strchr (files[i], '=');
|
|
char *from, *to;
|
|
if (!eq)
|
|
{
|
|
from = files[i];
|
|
to = files[i];
|
|
}
|
|
else
|
|
{
|
|
*eq = '\0';
|
|
to = files[i];
|
|
from = eq + 1;
|
|
}
|
|
while (*to == '/')
|
|
to++;
|
|
add_tar_file (from, to);
|
|
}
|
|
write_zeros (512);
|
|
|
|
fclose (memdisk);
|
|
|
|
grub_util_unlink_recursive (memdisk_dir);
|
|
|
|
grub_install_push_module ("memdisk");
|
|
grub_install_push_module ("tar");
|
|
|
|
grub_install_make_image_wrap (grub_install_source_directory,
|
|
"(memdisk)/boot/grub", output_image,
|
|
memdisk_img, NULL,
|
|
grub_util_get_target_name (format), 0);
|
|
|
|
grub_util_unlink (memdisk_img);
|
|
return 0;
|
|
}
|