2N/A/*
2N/A * GRUB -- GRand Unified Bootloader
2N/A * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A *
2N/A * GRUB is free software: you can redistribute it and/or modify
2N/A * it under the terms of the GNU General Public License as published by
2N/A * the Free Software Foundation, either version 3 of the License, or
2N/A * (at your option) any later version.
2N/A *
2N/A * GRUB is distributed in the hope that it will be useful,
2N/A * but WITHOUT ANY WARRANTY; without even the implied warranty of
2N/A * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2N/A * GNU General Public License for more details.
2N/A *
2N/A * You should have received a copy of the GNU General Public License
2N/A * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
2N/A */
2N/A
2N/A#include <config.h>
2N/A
2N/A#include <grub/mm.h>
2N/A#include <grub/types.h>
2N/A#include <grub/misc.h>
2N/A#include <grub/util/misc.h>
2N/A#include <grub/util/version.h>
2N/A
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <ctype.h>
2N/A#include <string.h>
2N/A
2N/Astatic int compare_version (const char *, const char *);
2N/A
2N/Astruct grub_util_version_info grub_util_solaris_grub_version =
2N/A{
2N/A "solaris_grub_version",
2N/A compare_version,
2N/A NULL,
2N/A 0
2N/A};
2N/A
2N/A/*
2N/A * compare_dotted_version()
2N/A * Compares two strings with an arbitrary long number of dot-separated numbers.
2N/A * Returns: 0 - if the version numbers are equal
2N/A * >0 - if str1 version number is more recent than str2
2N/A * <0 - if str2 version number is more recent than str1
2N/A *
2N/A * Comparison is done field by field, by retrieving an unsigned integer value,
2N/A * (missing fields are assumed as 0, but explict zeroes take precedence) so:
2N/A * 4.1.2.11 > 4.1.2.2 > 4.1.2.0 > 4.1.2
2N/A *
2N/A * where ">" means "more recent than".
2N/A */
2N/Astatic int
2N/Acompare_dotted_version(const char *str1, const char *str2)
2N/A{
2N/A int retval = 0;
2N/A char *verstr1, *verstr2, *freeptr1, *freeptr2;
2N/A char *parsep1, *parsep2;
2N/A int val_str1, val_str2;
2N/A
2N/A freeptr1 = verstr1 = xstrdup (str1);
2N/A freeptr2 = verstr2 = xstrdup (str2);
2N/A
2N/A while (verstr1 != NULL && verstr2 != NULL)
2N/A {
2N/A parsep1 = strsep (&verstr1, ".");
2N/A parsep2 = strsep (&verstr2, ".");
2N/A
2N/A val_str1 = atoi (parsep1);
2N/A val_str2 = atoi (parsep2);
2N/A
2N/A retval = val_str1 - val_str2;
2N/A if (retval != 0)
2N/A goto out;
2N/A }
2N/A
2N/A /* Common portion of the version string is equal. */
2N/A if (verstr1 == NULL && verstr2 != NULL)
2N/A retval = -1;
2N/A if (verstr2 == NULL && verstr1 != NULL)
2N/A retval = 1;
2N/A
2N/Aout:
2N/A free (freeptr1);
2N/A free (freeptr2);
2N/A grub_util_info("comparing dotted version %s %s returning %d",
2N/A str1, str2, retval);
2N/A return (retval);
2N/A}
2N/A
2N/A/*
2N/A * compare_timestamps()
2N/A * Currently, timestamp is in %Y%m%dT%H%M%SZ format in UTC, which means that
2N/A * we can simply do a lexicographic comparison to know which one is the most
2N/A * recent.
2N/A *
2N/A * Returns: 0 - if timestamps coincide
2N/A * 1 - if the timestamp in str1 is more recent
2N/A * 2 - if the timestamp in str2 is more recent
2N/A */
2N/Astatic int
2N/Acompare_timestamps (const char *str1, const char *str2)
2N/A{
2N/A int retval;
2N/A
2N/A retval = strcmp (str1, str2);
2N/A grub_util_info("comparing timestamps %s %s returning %d", str1, str2, retval);
2N/A return (retval);
2N/A}
2N/A
2N/A/*
2N/A * compare_version()
2N/A * Given two solaris versions, compare the two and returns which one is more
2N/A * "recent". Comparison is based on dotted version number fields and a
2N/A * timestamp.
2N/A *
2N/A * Returns: 0 - if the two versions coincide
2N/A * >0 - if the version in str1 is more recent
2N/A * <0 - if the version in str2 is more recent
2N/A */
2N/Astatic int
2N/Acompare_version (const char *str1, const char *str2)
2N/A{
2N/A int retval = 0;
2N/A char *verstr1, *verstr2, *freeptr1, *freeptr2;
2N/A char *parsep1, *parsep2;
2N/A
2N/A freeptr1 = verstr1 = xstrdup(str1);
2N/A freeptr2 = verstr2 = xstrdup(str2);
2N/A
2N/A parsep1 = verstr1;
2N/A parsep2 = verstr2;
2N/A
2N/A while (parsep1 != NULL && parsep2 != NULL)
2N/A {
2N/A parsep1 = strsep (&verstr1, ",:-");
2N/A parsep2 = strsep (&verstr2, ",:-");
2N/A
2N/A /* verstr1 or verstr2 will be NULL before parsep1 or parsep2. */
2N/A if (verstr1 == NULL || verstr2 == NULL)
2N/A {
2N/A retval = compare_timestamps (parsep1, parsep2);
2N/A goto out;
2N/A }
2N/A
2N/A retval = compare_dotted_version (parsep1, parsep2);
2N/A if (retval == 0)
2N/A continue;
2N/A else
2N/A goto out;
2N/A }
2N/A
2N/Aout:
2N/A free (freeptr1);
2N/A free (freeptr2);
2N/A return (retval);
2N/A}