/* grub-check-version.c - compare grub versioning information. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
*
* 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/types.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/emu/misc.h>
#include <grub/util/misc.h>
#include <grub/util/version.h>
#include <grub/i18n.h>
#define _GNU_SOURCE 1
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include "progname.h"
static struct option options[] =
{
{"source", required_argument, 0, 's'},
{"dest", required_argument, 0, 'd'},
{"type", required_argument, 0, 't'},
{"help", no_argument, 0, 'h'},
{"print", no_argument, 0, 'p'},
{"version", no_argument, 0, 'V'},
{"verbose", no_argument, 0, 'v'},
{0, 0, 0, 0}
};
static struct grub_util_version_info grub_util_module_interface_version;
static struct grub_util_version_info *grub_util_version_list[] =
{
&grub_util_solaris_grub_version,
&grub_util_module_interface_version,
NULL
};
static char buf[1024];
static void
usage (int status)
{
if (status)
fprintf (stderr,
"Try ``%s --help'' for more information.\n", program_name);
else
printf ("\
Usage: %s [PATH]\n\
\n\
Compares grub versioning information..\n\
\n\
-s, --source=FILE read version.lst from FILE.\n\
-d, --dest=FILE read version.lst to compare to from FILE.\n\
-t, --type=(solaris_grub_version, module_interface_version)\n\
versioning scheme to check.\n\
-h, --help display this message and exit\n\
-p, --print print the version obtained from source file (give with -s)\n\
-V, --version print version information and exit\n\
-v, --verbose print the script as it is being processed\n\
\n\
Report bugs to <%s>.\n\
", program_name,
PACKAGE_BUGREPORT);
exit (status);
}
static char *
get_version_from_file (FILE *fp, const char *version_type)
{
char *version = NULL;
if (fp == NULL)
return NULL;
if (version_type == NULL)
return NULL;
/*
* Loop through the various version entries looking for the requested one.
* Keep looping after finding the first occurrence because the last present
* entry overrides the previous ones.
*/
while (fgets (buf, sizeof (buf), fp))
{
char *p;
buf[strlen (buf) - 1] = '\0';
p = strchr (buf, ':');
if (!p)
continue;
*p++ = '\0';
/* Is this the version we want? */
if (strcmp (buf, version_type) != 0)
continue;
while (*p && isspace (*p))
p++;
if (! *p)
continue;
if (version != NULL)
free (version);
version = xstrdup(p);
}
return version;
}
int
main (int argc, char *argv[])
{
char *argument;
int i = 0;
int verbose = 0;
int found_input = 0;
int do_print_only = 0;
char *source_version;
char *dest_version;
char *versioning_type = NULL;
FILE *source_fp = NULL;
FILE *dest_fp = NULL;
struct grub_util_version_info *verp;
set_program_name (argv[0]);
grub_util_init_nls ();
/* Check for options. */
while (1)
{
int c = getopt_long (argc, argv, "s:d:t:hpvV", options, 0);
if (c == -1)
break;
else
switch (c)
{
case 's':
grub_util_info ("source file is: %s", optarg);
source_fp = fopen (optarg, "r");
if (source_fp == NULL)
grub_util_error (_("cannot open %s"), optarg);
break;
case 'd':
grub_util_info ("compare to file is: %s", optarg);
dest_fp = fopen (optarg, "r");
if (dest_fp == NULL)
grub_util_error (_("cannot open %s"), optarg);
break;
case 't':
versioning_type = xstrdup(optarg);
break;
case 'h':
usage (0);
break;
case 'p':
do_print_only = 1;
break;
case 'V':
printf ("%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION);
return 0;
case 'v':
verbosity++;
break;
default:
usage (1);
break;
}
}
if (versioning_type == NULL)
grub_util_error (_("no versioning scheme specified"));
while ((verp = grub_util_version_list[i++]) != NULL)
if (strcmp(verp->versioning_scheme, versioning_type) == 0)
break;
if (verp == NULL)
grub_util_error (_("unsupported versioning scheme specified"));
if (source_fp == NULL && verp->static_version != NULL)
source_version = xstrdup(verp->static_version);
else
source_version = get_version_from_file (source_fp, versioning_type);
if (do_print_only)
{
if (source_version == NULL)
{
grub_util_info ("could not find source matching type");
exit(1);
}
printf("%s\n", source_version);
exit (0);
}
dest_version = get_version_from_file (dest_fp, versioning_type);
if (source_version == NULL || dest_version == NULL)
{
if (verp->compulsory)
{
printf("no\n");
return 0;
}
if (source_version == NULL)
grub_util_info("source was NULL");
if (dest_version == NULL)
grub_util_info("dest was NULL");
if (source_version == NULL && dest_version != NULL)
printf("no\n");
else if (source_version != NULL && dest_version == NULL)
printf("yes\n");
else /* both are NULL */
printf("no\n");
}
else
{
grub_util_info ("going to compare %s with %s", source_version,
dest_version);
if (verp->compare (source_version, dest_version) >= 0)
printf("yes\n");
else
printf("no\n");
}
return 0;
}
static int
compare_modintf_version (const char *a, const char *b)
{
long ai, bi;
errno = 0;
ai = strtoul(a, 0, 0);
bi = strtoul(b, 0, 0);
if (errno != 0)
return -1;
if (ai != bi)
return -1;
return 0;
}
#include <grub/util/modvers.h>
/* 2 levels of macros are needed to stringify the numeric constant in
GRUB_MODULE_INTERFACE_VERSION */
#define STRINGIFY(x) STRINGIFY2(x)
#define STRINGIFY2(x) #x
static struct grub_util_version_info grub_util_module_interface_version =
{
"module_interface_version",
compare_modintf_version,
STRINGIFY(GRUB_MODULE_INTERFACE_VERSION),
1
};