diff --git a/0008-Add-usr-libexec-rpm-sort.patch b/0008-Add-usr-libexec-rpm-sort.patch new file mode 100644 index 0000000..b3e5faa --- /dev/null +++ b/0008-Add-usr-libexec-rpm-sort.patch @@ -0,0 +1,418 @@ +From b8a581014170c6a9bb8ffb799090401a57a4bbe6 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Fri, 12 Oct 2018 16:39:37 -0400 +Subject: [PATCH 8/8] Add /usr/libexec/rpm-sort + +Signed-off-by: Peter Jones +--- + rpm-sort.c | 355 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + Makefile | 9 +- + .gitignore | 1 + + 3 files changed, 363 insertions(+), 2 deletions(-) + create mode 100644 rpm-sort.c + +diff --git a/rpm-sort.c b/rpm-sort.c +new file mode 100644 +index 00000000000..f19635645ba +--- /dev/null ++++ b/rpm-sort.c +@@ -0,0 +1,355 @@ ++#define _GNU_SOURCE ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++typedef enum { ++ RPMNVRCMP, ++ VERSNVRCMP, ++ RPMVERCMP, ++ STRVERSCMP, ++} comparitors; ++ ++static comparitors comparitor = RPMNVRCMP; ++ ++static inline void *xmalloc(size_t sz) ++{ ++ void *ret = malloc(sz); ++ ++ assert(sz == 0 || ret != NULL); ++ return ret; ++} ++ ++static inline void *xrealloc(void *p, size_t sz) ++{ ++ void *ret = realloc(p, sz); ++ ++ assert(sz == 0 || ret != NULL); ++ return ret; ++} ++ ++static inline char *xstrdup(const char * const s) ++{ ++ void *ret = strdup(s); ++ ++ assert(s == NULL || ret != NULL); ++ return ret; ++} ++ ++static size_t ++read_file (const char *input, char **ret) ++{ ++ FILE *in; ++ size_t s; ++ size_t sz = 2048; ++ size_t offset = 0; ++ char *text; ++ ++ if (!strcmp(input, "-")) ++ in = stdin; ++ else ++ in = fopen(input, "r"); ++ ++ text = xmalloc (sz); ++ ++ if (!in) ++ err(1, "cannot open `%s'", input); ++ ++ while ((s = fread (text + offset, 1, sz - offset, in)) != 0) ++ { ++ offset += s; ++ if (sz - offset == 0) ++ { ++ sz += 2048; ++ text = xrealloc (text, sz); ++ } ++ } ++ ++ text[offset] = '\0'; ++ *ret = text; ++ ++ if (in != stdin) ++ fclose(in); ++ ++ return offset + 1; ++} ++ ++/* returns name/version/release */ ++/* NULL string pointer returned if nothing found */ ++static void ++split_package_string (char *package_string, char **name, ++ char **version, char **release) ++{ ++ char *package_version, *package_release; ++ ++ /* Release */ ++ package_release = strrchr (package_string, '-'); ++ ++ if (package_release != NULL) ++ *package_release++ = '\0'; ++ ++ *release = package_release; ++ ++ /* Version */ ++ package_version = strrchr(package_string, '-'); ++ ++ if (package_version != NULL) ++ *package_version++ = '\0'; ++ ++ *version = package_version; ++ /* Name */ ++ *name = package_string; ++ ++ /* Bubble up non-null values from release to name */ ++ if (*name == NULL) ++ { ++ *name = (*version == NULL ? *release : *version); ++ *version = *release; ++ *release = NULL; ++ } ++ if (*version == NULL) ++ { ++ *version = *release; ++ *release = NULL; ++ } ++} ++ ++static int ++cmprpmversp(const void *p1, const void *p2) ++{ ++ return rpmvercmp(*(char * const *)p1, *(char * const *)p2); ++} ++ ++static int ++cmpstrversp(const void *p1, const void *p2) ++{ ++ return strverscmp(*(char * const *)p1, *(char * const *)p2); ++} ++ ++/* ++ * package name-version-release comparator for qsort ++ * expects p, q which are pointers to character strings (char *) ++ * which will not be altered in this function ++ */ ++static int ++package_version_compare (const void *p, const void *q) ++{ ++ char *local_p, *local_q; ++ char *lhs_name, *lhs_version, *lhs_release; ++ char *rhs_name, *rhs_version, *rhs_release; ++ int vercmpflag = 0; ++ int (*cmp)(const char *s1, const char *s2); ++ ++ switch(comparitor) ++ { ++ default: /* just to shut up -Werror=maybe-uninitialized */ ++ case RPMNVRCMP: ++ cmp = rpmvercmp; ++ break; ++ case VERSNVRCMP: ++ cmp = strverscmp; ++ break; ++ case RPMVERCMP: ++ return cmprpmversp(p, q); ++ break; ++ case STRVERSCMP: ++ return cmpstrversp(p, q); ++ break; ++ } ++ ++ local_p = alloca (strlen (*(char * const *)p) + 1); ++ local_q = alloca (strlen (*(char * const *)q) + 1); ++ ++ /* make sure these allocated */ ++ assert (local_p); ++ assert (local_q); ++ ++ strcpy (local_p, *(char * const *)p); ++ strcpy (local_q, *(char * const *)q); ++ ++ split_package_string (local_p, &lhs_name, &lhs_version, &lhs_release); ++ split_package_string (local_q, &rhs_name, &rhs_version, &rhs_release); ++ ++ /* Check Name and return if unequal */ ++ vercmpflag = cmp ((lhs_name == NULL ? "" : lhs_name), ++ (rhs_name == NULL ? "" : rhs_name)); ++ if (vercmpflag != 0) ++ return vercmpflag; ++ ++ /* Check version and return if unequal */ ++ vercmpflag = cmp ((lhs_version == NULL ? "" : lhs_version), ++ (rhs_version == NULL ? "" : rhs_version)); ++ if (vercmpflag != 0) ++ return vercmpflag; ++ ++ /* Check release and return the version compare value */ ++ vercmpflag = cmp ((lhs_release == NULL ? "" : lhs_release), ++ (rhs_release == NULL ? "" : rhs_release)); ++ ++ return vercmpflag; ++} ++ ++static void ++add_input (const char *filename, char ***package_names, size_t *n_package_names) ++{ ++ char *orig_input_buffer = NULL; ++ char *input_buffer; ++ char *position_of_newline; ++ char **names = *package_names; ++ char **new_names = NULL; ++ size_t n_names = *n_package_names; ++ ++ if (!*package_names) ++ new_names = names = xmalloc (sizeof (char *) * 2); ++ ++ if (read_file (filename, &orig_input_buffer) < 2) ++ { ++ if (new_names) ++ free (new_names); ++ if (orig_input_buffer) ++ free (orig_input_buffer); ++ return; ++ } ++ ++ input_buffer = orig_input_buffer; ++ while (input_buffer && *input_buffer && ++ (position_of_newline = strchrnul (input_buffer, '\n'))) ++ { ++ size_t sz = position_of_newline - input_buffer; ++ char *new; ++ ++ if (sz == 0) ++ { ++ input_buffer = position_of_newline + 1; ++ continue; ++ } ++ ++ new = xmalloc (sz+1); ++ strncpy (new, input_buffer, sz); ++ new[sz] = '\0'; ++ ++ names = xrealloc (names, sizeof (char *) * (n_names + 1)); ++ names[n_names] = new; ++ n_names++; ++ ++ /* move buffer ahead to next line */ ++ input_buffer = position_of_newline + 1; ++ if (*position_of_newline == '\0') ++ input_buffer = NULL; ++ } ++ ++ free (orig_input_buffer); ++ ++ *package_names = names; ++ *n_package_names = n_names; ++} ++ ++static char * ++help_filter (int key, const char *text, void *input __attribute__ ((unused))) ++{ ++ return (char *)text; ++} ++ ++static struct argp_option options[] = { ++ { "comparitor", 'c', "COMPARITOR", 0, "[rpm-nvr-cmp|vers-nvr-cmp|rpmvercmp|strverscmp]", 0}, ++ { 0, } ++}; ++ ++struct arguments ++{ ++ size_t ninputs; ++ size_t input_max; ++ char **inputs; ++}; ++ ++static error_t ++argp_parser (int key, char *arg, struct argp_state *state) ++{ ++ struct arguments *arguments = state->input; ++ switch (key) ++ { ++ case 'c': ++ if (!strcmp(arg, "rpm-nvr-cmp") || !strcmp(arg, "rpmnvrcmp")) ++ comparitor = RPMNVRCMP; ++ else if (!strcmp(arg, "vers-nvr-cmp") || !strcmp(arg, "versnvrcmp")) ++ comparitor = VERSNVRCMP; ++ else if (!strcmp(arg, "rpmvercmp")) ++ comparitor = RPMVERCMP; ++ else if (!strcmp(arg, "strverscmp")) ++ comparitor = STRVERSCMP; ++ else ++ err(1, "Invalid comparitor \"%s\"", arg); ++ break; ++ case ARGP_KEY_ARG: ++ assert (arguments->ninputs < arguments->input_max); ++ arguments->inputs[arguments->ninputs++] = xstrdup (arg); ++ break; ++ default: ++ return ARGP_ERR_UNKNOWN; ++ } ++ return 0; ++} ++ ++static struct argp argp = { ++ options, argp_parser, "[INPUT_FILES]", ++ "Sort a list of strings in RPM version sort order.", ++ NULL, help_filter, NULL ++}; ++ ++int ++main (int argc, char *argv[]) ++{ ++ struct arguments arguments; ++ char **package_names = NULL; ++ size_t n_package_names = 0; ++ int i; ++ ++ memset (&arguments, 0, sizeof (struct arguments)); ++ arguments.input_max = argc+1; ++ arguments.inputs = xmalloc ((arguments.input_max + 1) ++ * sizeof (arguments.inputs[0])); ++ memset (arguments.inputs, 0, (arguments.input_max + 1) ++ * sizeof (arguments.inputs[0])); ++ ++ /* Parse our arguments */ ++ if (argp_parse (&argp, argc, argv, 0, 0, &arguments) != 0) ++ errx(1, "%s", "Error in parsing command line arguments\n"); ++ ++ /* If there's no inputs in argv, add one for stdin */ ++ if (!arguments.ninputs) ++ { ++ arguments.ninputs = 1; ++ arguments.inputs[0] = xmalloc (2); ++ strcpy(arguments.inputs[0], "-"); ++ } ++ ++ for (i = 0; i < arguments.ninputs; i++) ++ add_input(arguments.inputs[i], &package_names, &n_package_names); ++ ++ if (package_names == NULL || n_package_names < 1) ++ errx(1, "Invalid input"); ++ ++ qsort (package_names, n_package_names, sizeof (char *), ++ package_version_compare); ++ ++ /* send sorted list to stdout */ ++ for (i = 0; i < n_package_names; i++) ++ { ++ fprintf (stdout, "%s\n", package_names[i]); ++ free (package_names[i]); ++ } ++ ++ free (package_names); ++ for (i = 0; i < arguments.ninputs; i++) ++ free (arguments.inputs[i]); ++ ++ free (arguments.inputs); ++ ++ return 0; ++} +diff --git a/Makefile b/Makefile +index cfa8e0d60ab..1ab58aeb039 100644 +--- a/Makefile ++++ b/Makefile +@@ -29,7 +29,7 @@ LDFLAGS := $(RPM_LD_FLAGS) + + grubby_LIBS = -lblkid -lpopt + +-all: grubby ++all: grubby rpm-sort + + debug : clean + $(MAKE) CFLAGS="${CFLAGS} -DDEBUG=1" all +@@ -52,12 +52,17 @@ install: all + install -m 755 grubby $(DESTDIR)$(PREFIX)$(sbindir) ; \ + install -m 644 grubby.8 $(DESTDIR)/$(mandir)/man8 ; \ + fi ++ install -m 755 -d $(DESTDIR)$(PREFIX)$(libexecdir)/grubby/ ++ install -m 755 rpm-sort $(DESTDIR)$(PREFIX)$(libexecdir)/grubby/rpm-sort + + grubby:: $(OBJECTS) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(grubby_LIBS) + ++rpm-sort::rpm-sort.o ++ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ -lrpm ++ + clean: +- rm -f *.o grubby *~ ++ rm -f *.o grubby rpm-sort *~ + + GITTAG = $(VERSION)-1 + +diff --git a/.gitignore b/.gitignore +index e64d3bc0986..1a5a546eee3 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -1,3 +1,4 @@ + grubby ++rpm-sort + version.h + *.o +-- +2.17.1 + diff --git a/grubby-bls b/grubby-bls index c9c608b..6fa3fe4 100755 --- a/grubby-bls +++ b/grubby-bls @@ -76,21 +76,32 @@ append_bls_value() { local key="$1" && shift local value="$1" && shift - old_value="$(get_bls_value ${bls} ${key})" + old_value="$(get_bls_value "${bls}" ${key})" set_bls_value "${bls}" "${key}" "${old_value}${value}" } get_bls_values() { count=0 - for bls in $(ls -vr ${blsdir}/*.conf 2> /dev/null); do - bls_file[$count]="${bls}" - bls_title[$count]="$(get_bls_value ${bls} title)" - bls_version[$count]="$(get_bls_value ${bls} version)" - bls_linux[$count]="$(get_bls_value ${bls} linux)" - bls_initrd[$count]="$(get_bls_value ${bls} initrd)" - bls_options[$count]="$(get_bls_value ${bls} options)" - bls_id[$count]="${bls%.conf}" - bls_id[$count]="${bls_id[$count]##*/}" + local -a files + local IFS=$'\n' + files=($(for bls in ${blsdir}/*.conf ; do + if ! [[ -e "${bls}" ]] ; then + continue + fi + bls="${bls%.conf}" + bls="${bls##*/}" + echo "${bls}" + done | /usr/libexec/grubby/rpm-sort -c rpmnvrcmp | tac)) || : + + for bls in "${files[@]}" ; do + blspath="${blsdir}/${bls}.conf" + bls_file[$count]="${blspath}" + bls_title[$count]="$(get_bls_value ${blspath} title)" + bls_version[$count]="$(get_bls_value ${blspath} version)" + bls_linux[$count]="$(get_bls_value ${blspath} linux)" + bls_initrd[$count]="$(get_bls_value ${blspath} initrd)" + bls_options[$count]="$(get_bls_value ${blspath} options)" + bls_id[$count]="${bls}" count=$((count+1)) done @@ -194,10 +205,10 @@ display_info_values() { for i in ${indexes[*]}; do echo "index=$i" - echo "kernel=${bls_linux[$i]}" + echo "kernel=\"${bls_linux[$i]}\"" echo "args=\"${bls_options[$i]}\"" - echo "initrd=${bls_initrd[$i]}" - echo "title=${bls_title[$i]}" + echo "initrd=\"${bls_initrd[$i]}\"" + echo "title=\"${bls_title[$i]}\"" echo "id=\"${bls_id[$i]}\"" done exit 0 @@ -239,7 +250,7 @@ remove_bls_fragment() { print_error "The param $1 is incorrect" fi - for i in ${indexes[*]}; do + for i in "${indexes[@]}"; do rm -f "${bls_file[$i]}" done diff --git a/grubby.spec b/grubby.spec index 9df4e4a..45d41c8 100644 --- a/grubby.spec +++ b/grubby.spec @@ -20,12 +20,14 @@ Patch0004: 0004-Add-tests-for-btrfs-support.patch Patch0005: 0005-Use-system-LDFLAGS.patch Patch0006: 0006-Honor-sbindir.patch Patch0007: 0007-Make-installkernel-to-use-kernel-install-scripts-on-.patch +Patch0008: 0008-Add-usr-libexec-rpm-sort.patch BuildRequires: gcc BuildRequires: pkgconfig glib2-devel popt-devel BuildRequires: libblkid-devel git-core sed make # for make test / getopt: BuildRequires: util-linux-ng +BuildRequires: rpm-devel %ifarch aarch64 i686 x86_64 %{power64} BuildRequires: grub2-tools-minimal Requires: grub2-tools-minimal @@ -34,6 +36,7 @@ Requires: grub2-tools %ifarch s390 s390x Requires: s390utils-base %endif +Requires: findutils %description This package provides a grubby compatibility script that manages @@ -61,7 +64,7 @@ make test %endif %install -make install DESTDIR=$RPM_BUILD_ROOT mandir=%{_mandir} sbindir=%{_sbindir} +make install DESTDIR=$RPM_BUILD_ROOT mandir=%{_mandir} sbindir=%{_sbindir} libexecdir=%{_libexecdir} mkdir -p %{buildroot}%{_libexecdir}/{grubby,installkernel}/ %{buildroot}%{_sbindir}/ mv -v %{buildroot}%{_sbindir}/grubby %{buildroot}%{_libexecdir}/grubby/grubby @@ -93,6 +96,7 @@ current boot environment. %dir %{_libexecdir}/grubby %dir %{_libexecdir}/installkernel %attr(0755,root,root) %{_libexecdir}/grubby/grubby-bls +%attr(0755,root,root) %{_libexecdir}/grubby/rpm-sort %attr(0755,root,root) %{_sbindir}/grubby %attr(0755,root,root) %{_libexecdir}/installkernel/installkernel-bls %attr(0755,root,root) %{_sbindir}/installkernel