Blame SOURCES/0008-Add-usr-libexec-rpm-sort.patch

3e90b9
From b8a581014170c6a9bb8ffb799090401a57a4bbe6 Mon Sep 17 00:00:00 2001
3e90b9
From: Peter Jones <pjones@redhat.com>
3e90b9
Date: Fri, 12 Oct 2018 16:39:37 -0400
3e90b9
Subject: [PATCH 8/8] Add /usr/libexec/rpm-sort
3e90b9
3e90b9
Signed-off-by: Peter Jones <pjones@redhat.com>
3e90b9
---
3e90b9
 rpm-sort.c | 355 +++++++++++++++++++++++++++++++++++++++++++++++++++++
3e90b9
 Makefile   |   9 +-
3e90b9
 .gitignore |   1 +
3e90b9
 3 files changed, 363 insertions(+), 2 deletions(-)
3e90b9
 create mode 100644 rpm-sort.c
3e90b9
3e90b9
diff --git a/rpm-sort.c b/rpm-sort.c
3e90b9
new file mode 100644
3e90b9
index 00000000000..f19635645ba
3e90b9
--- /dev/null
3e90b9
+++ b/rpm-sort.c
3e90b9
@@ -0,0 +1,355 @@
3e90b9
+#define _GNU_SOURCE
3e90b9
+
3e90b9
+#include <stdio.h>
3e90b9
+#include <stdlib.h>
3e90b9
+#include <unistd.h>
3e90b9
+#include <errno.h>
3e90b9
+#include <assert.h>
3e90b9
+#include <argp.h>
3e90b9
+#include <rpm/rpmlib.h>
3e90b9
+#include <err.h>
3e90b9
+
3e90b9
+typedef enum {
3e90b9
+        RPMNVRCMP,
3e90b9
+        VERSNVRCMP,
3e90b9
+        RPMVERCMP,
3e90b9
+        STRVERSCMP,
3e90b9
+} comparitors;
3e90b9
+
3e90b9
+static comparitors comparitor = RPMNVRCMP;
3e90b9
+
3e90b9
+static inline void *xmalloc(size_t sz)
3e90b9
+{
3e90b9
+        void *ret = malloc(sz);
3e90b9
+
3e90b9
+        assert(sz == 0 || ret != NULL);
3e90b9
+        return ret;
3e90b9
+}
3e90b9
+
3e90b9
+static inline void *xrealloc(void *p, size_t sz)
3e90b9
+{
3e90b9
+        void *ret = realloc(p, sz);
3e90b9
+
3e90b9
+        assert(sz == 0 || ret != NULL);
3e90b9
+        return ret;
3e90b9
+}
3e90b9
+
3e90b9
+static inline char *xstrdup(const char * const s)
3e90b9
+{
3e90b9
+        void *ret = strdup(s);
3e90b9
+
3e90b9
+        assert(s == NULL || ret != NULL);
3e90b9
+        return ret;
3e90b9
+}
3e90b9
+
3e90b9
+static size_t
3e90b9
+read_file (const char *input, char **ret)
3e90b9
+{
3e90b9
+  FILE *in;
3e90b9
+  size_t s;
3e90b9
+  size_t sz = 2048;
3e90b9
+  size_t offset = 0;
3e90b9
+  char *text;
3e90b9
+
3e90b9
+  if (!strcmp(input, "-"))
3e90b9
+    in = stdin;
3e90b9
+  else
3e90b9
+    in = fopen(input, "r");
3e90b9
+
3e90b9
+  text = xmalloc (sz);
3e90b9
+
3e90b9
+  if (!in)
3e90b9
+    err(1, "cannot open `%s'", input);
3e90b9
+
3e90b9
+  while ((s = fread (text + offset, 1, sz - offset, in)) != 0)
3e90b9
+    {
3e90b9
+      offset += s;
3e90b9
+      if (sz - offset == 0)
3e90b9
+	{
3e90b9
+	  sz += 2048;
3e90b9
+	  text = xrealloc (text, sz);
3e90b9
+	}
3e90b9
+    }
3e90b9
+
3e90b9
+  text[offset] = '\0';
3e90b9
+  *ret = text;
3e90b9
+
3e90b9
+  if (in != stdin)
3e90b9
+    fclose(in);
3e90b9
+
3e90b9
+  return offset + 1;
3e90b9
+}
3e90b9
+
3e90b9
+/* returns name/version/release */
3e90b9
+/* NULL string pointer returned if nothing found */
3e90b9
+static void
3e90b9
+split_package_string (char *package_string, char **name,
3e90b9
+                     char **version, char **release)
3e90b9
+{
3e90b9
+  char *package_version, *package_release;
3e90b9
+
3e90b9
+  /* Release */
3e90b9
+  package_release = strrchr (package_string, '-');
3e90b9
+
3e90b9
+  if (package_release != NULL)
3e90b9
+      *package_release++ = '\0';
3e90b9
+
3e90b9
+  *release = package_release;
3e90b9
+
3e90b9
+  /* Version */
3e90b9
+  package_version = strrchr(package_string, '-');
3e90b9
+
3e90b9
+  if (package_version != NULL)
3e90b9
+      *package_version++ = '\0';
3e90b9
+
3e90b9
+  *version = package_version;
3e90b9
+  /* Name */
3e90b9
+  *name = package_string;
3e90b9
+
3e90b9
+  /* Bubble up non-null values from release to name */
3e90b9
+  if (*name == NULL)
3e90b9
+    {
3e90b9
+      *name = (*version == NULL ? *release : *version);
3e90b9
+      *version = *release;
3e90b9
+      *release = NULL;
3e90b9
+    }
3e90b9
+  if (*version == NULL)
3e90b9
+    {
3e90b9
+      *version = *release;
3e90b9
+      *release = NULL;
3e90b9
+    }
3e90b9
+}
3e90b9
+
3e90b9
+static int
3e90b9
+cmprpmversp(const void *p1, const void *p2)
3e90b9
+{
3e90b9
+        return rpmvercmp(*(char * const *)p1, *(char * const *)p2);
3e90b9
+}
3e90b9
+
3e90b9
+static int
3e90b9
+cmpstrversp(const void *p1, const void *p2)
3e90b9
+{
3e90b9
+        return strverscmp(*(char * const *)p1, *(char * const *)p2);
3e90b9
+}
3e90b9
+
3e90b9
+/*
3e90b9
+ * package name-version-release comparator for qsort
3e90b9
+ * expects p, q which are pointers to character strings (char *)
3e90b9
+ * which will not be altered in this function
3e90b9
+ */
3e90b9
+static int
3e90b9
+package_version_compare (const void *p, const void *q)
3e90b9
+{
3e90b9
+  char *local_p, *local_q;
3e90b9
+  char *lhs_name, *lhs_version, *lhs_release;
3e90b9
+  char *rhs_name, *rhs_version, *rhs_release;
3e90b9
+  int vercmpflag = 0;
3e90b9
+  int (*cmp)(const char *s1, const char *s2);
3e90b9
+
3e90b9
+  switch(comparitor)
3e90b9
+    {
3e90b9
+    default: /* just to shut up -Werror=maybe-uninitialized */
3e90b9
+    case RPMNVRCMP:
3e90b9
+      cmp = rpmvercmp;
3e90b9
+      break;
3e90b9
+    case VERSNVRCMP:
3e90b9
+      cmp = strverscmp;
3e90b9
+      break;
3e90b9
+    case RPMVERCMP:
3e90b9
+      return cmprpmversp(p, q);
3e90b9
+      break;
3e90b9
+    case STRVERSCMP:
3e90b9
+      return cmpstrversp(p, q);
3e90b9
+      break;
3e90b9
+    }
3e90b9
+
3e90b9
+  local_p = alloca (strlen (*(char * const *)p) + 1);
3e90b9
+  local_q = alloca (strlen (*(char * const *)q) + 1);
3e90b9
+
3e90b9
+  /* make sure these allocated */
3e90b9
+  assert (local_p);
3e90b9
+  assert (local_q);
3e90b9
+
3e90b9
+  strcpy (local_p, *(char * const *)p);
3e90b9
+  strcpy (local_q, *(char * const *)q);
3e90b9
+
3e90b9
+  split_package_string (local_p, &lhs_name, &lhs_version, &lhs_release);
3e90b9
+  split_package_string (local_q, &rhs_name, &rhs_version, &rhs_release);
3e90b9
+
3e90b9
+  /* Check Name and return if unequal */
3e90b9
+  vercmpflag = cmp ((lhs_name == NULL ? "" : lhs_name),
3e90b9
+                    (rhs_name == NULL ? "" : rhs_name));
3e90b9
+  if (vercmpflag != 0)
3e90b9
+    return vercmpflag;
3e90b9
+
3e90b9
+  /* Check version and return if unequal */
3e90b9
+  vercmpflag = cmp ((lhs_version == NULL ? "" : lhs_version),
3e90b9
+                    (rhs_version == NULL ? "" : rhs_version));
3e90b9
+  if (vercmpflag != 0)
3e90b9
+    return vercmpflag;
3e90b9
+
3e90b9
+  /* Check release and return the version compare value */
3e90b9
+  vercmpflag = cmp ((lhs_release == NULL ? "" : lhs_release),
3e90b9
+                    (rhs_release == NULL ? "" : rhs_release));
3e90b9
+
3e90b9
+  return vercmpflag;
3e90b9
+}
3e90b9
+
3e90b9
+static void
3e90b9
+add_input (const char *filename, char ***package_names, size_t *n_package_names)
3e90b9
+{
3e90b9
+  char *orig_input_buffer = NULL;
3e90b9
+  char *input_buffer;
3e90b9
+  char *position_of_newline;
3e90b9
+  char **names = *package_names;
3e90b9
+  char **new_names = NULL;
3e90b9
+  size_t n_names = *n_package_names;
3e90b9
+
3e90b9
+  if (!*package_names)
3e90b9
+    new_names = names = xmalloc (sizeof (char *) * 2);
3e90b9
+
3e90b9
+  if (read_file (filename, &orig_input_buffer) < 2)
3e90b9
+    {
3e90b9
+      if (new_names)
3e90b9
+	free (new_names);
3e90b9
+      if (orig_input_buffer)
3e90b9
+	free (orig_input_buffer);
3e90b9
+      return;
3e90b9
+    }
3e90b9
+
3e90b9
+  input_buffer = orig_input_buffer;
3e90b9
+  while (input_buffer && *input_buffer &&
3e90b9
+	 (position_of_newline = strchrnul (input_buffer, '\n')))
3e90b9
+    {
3e90b9
+      size_t sz = position_of_newline - input_buffer;
3e90b9
+      char *new;
3e90b9
+
3e90b9
+      if (sz == 0)
3e90b9
+	{
3e90b9
+	  input_buffer = position_of_newline + 1;
3e90b9
+	  continue;
3e90b9
+	}
3e90b9
+
3e90b9
+      new = xmalloc (sz+1);
3e90b9
+      strncpy (new, input_buffer, sz);
3e90b9
+      new[sz] = '\0';
3e90b9
+
3e90b9
+      names = xrealloc (names, sizeof (char *) * (n_names + 1));
3e90b9
+      names[n_names] = new;
3e90b9
+      n_names++;
3e90b9
+
3e90b9
+      /* move buffer ahead to next line */
3e90b9
+      input_buffer = position_of_newline + 1;
3e90b9
+      if (*position_of_newline == '\0')
3e90b9
+	input_buffer = NULL;
3e90b9
+    }
3e90b9
+
3e90b9
+  free (orig_input_buffer);
3e90b9
+
3e90b9
+  *package_names = names;
3e90b9
+  *n_package_names = n_names;
3e90b9
+}
3e90b9
+
3e90b9
+static char *
3e90b9
+help_filter (int key, const char *text, void *input __attribute__ ((unused)))
3e90b9
+{
3e90b9
+  return (char *)text;
3e90b9
+}
3e90b9
+
3e90b9
+static struct argp_option options[] = {
3e90b9
+  { "comparitor", 'c', "COMPARITOR", 0, "[rpm-nvr-cmp|vers-nvr-cmp|rpmvercmp|strverscmp]", 0},
3e90b9
+  { 0, }
3e90b9
+};
3e90b9
+
3e90b9
+struct arguments
3e90b9
+{
3e90b9
+  size_t ninputs;
3e90b9
+  size_t input_max;
3e90b9
+  char **inputs;
3e90b9
+};
3e90b9
+
3e90b9
+static error_t
3e90b9
+argp_parser (int key, char *arg, struct argp_state *state)
3e90b9
+{
3e90b9
+  struct arguments *arguments = state->input;
3e90b9
+  switch (key)
3e90b9
+    {
3e90b9
+    case 'c':
3e90b9
+      if (!strcmp(arg, "rpm-nvr-cmp") || !strcmp(arg, "rpmnvrcmp"))
3e90b9
+        comparitor = RPMNVRCMP;
3e90b9
+      else if (!strcmp(arg, "vers-nvr-cmp") || !strcmp(arg, "versnvrcmp"))
3e90b9
+        comparitor = VERSNVRCMP;
3e90b9
+      else if (!strcmp(arg, "rpmvercmp"))
3e90b9
+        comparitor = RPMVERCMP;
3e90b9
+      else if (!strcmp(arg, "strverscmp"))
3e90b9
+        comparitor = STRVERSCMP;
3e90b9
+      else
3e90b9
+        err(1, "Invalid comparitor \"%s\"", arg);
3e90b9
+      break;
3e90b9
+    case ARGP_KEY_ARG:
3e90b9
+      assert (arguments->ninputs < arguments->input_max);
3e90b9
+      arguments->inputs[arguments->ninputs++] = xstrdup (arg);
3e90b9
+      break;
3e90b9
+    default:
3e90b9
+      return ARGP_ERR_UNKNOWN;
3e90b9
+    }
3e90b9
+  return 0;
3e90b9
+}
3e90b9
+
3e90b9
+static struct argp argp = {
3e90b9
+  options, argp_parser, "[INPUT_FILES]",
3e90b9
+  "Sort a list of strings in RPM version sort order.",
3e90b9
+  NULL, help_filter, NULL
3e90b9
+};
3e90b9
+
3e90b9
+int
3e90b9
+main (int argc, char *argv[])
3e90b9
+{
3e90b9
+  struct arguments arguments;
3e90b9
+  char **package_names = NULL;
3e90b9
+  size_t n_package_names = 0;
3e90b9
+  int i;
3e90b9
+
3e90b9
+  memset (&arguments, 0, sizeof (struct arguments));
3e90b9
+  arguments.input_max = argc+1;
3e90b9
+  arguments.inputs = xmalloc ((arguments.input_max + 1)
3e90b9
+			      * sizeof (arguments.inputs[0]));
3e90b9
+  memset (arguments.inputs, 0, (arguments.input_max + 1)
3e90b9
+	  * sizeof (arguments.inputs[0]));
3e90b9
+
3e90b9
+  /* Parse our arguments */
3e90b9
+  if (argp_parse (&argp, argc, argv, 0, 0, &arguments) != 0)
3e90b9
+    errx(1, "%s", "Error in parsing command line arguments\n");
3e90b9
+
3e90b9
+  /* If there's no inputs in argv, add one for stdin */
3e90b9
+  if (!arguments.ninputs)
3e90b9
+    {
3e90b9
+      arguments.ninputs = 1;
3e90b9
+      arguments.inputs[0] = xmalloc (2);
3e90b9
+      strcpy(arguments.inputs[0], "-");
3e90b9
+    }
3e90b9
+
3e90b9
+  for (i = 0; i < arguments.ninputs; i++)
3e90b9
+    add_input(arguments.inputs[i], &package_names, &n_package_names);
3e90b9
+
3e90b9
+  if (package_names == NULL || n_package_names < 1)
3e90b9
+    errx(1, "Invalid input");
3e90b9
+
3e90b9
+  qsort (package_names, n_package_names, sizeof (char *),
3e90b9
+	 package_version_compare);
3e90b9
+
3e90b9
+  /* send sorted list to stdout */
3e90b9
+  for (i = 0; i < n_package_names; i++)
3e90b9
+    {
3e90b9
+      fprintf (stdout, "%s\n", package_names[i]);
3e90b9
+      free (package_names[i]);
3e90b9
+    }
3e90b9
+
3e90b9
+  free (package_names);
3e90b9
+  for (i = 0; i < arguments.ninputs; i++)
3e90b9
+    free (arguments.inputs[i]);
3e90b9
+
3e90b9
+  free (arguments.inputs);
3e90b9
+
3e90b9
+  return 0;
3e90b9
+}
3e90b9
diff --git a/Makefile b/Makefile
3e90b9
index cfa8e0d60ab..1ab58aeb039 100644
3e90b9
--- a/Makefile
3e90b9
+++ b/Makefile
3e90b9
@@ -29,7 +29,7 @@ LDFLAGS := $(RPM_LD_FLAGS)
3e90b9
 
3e90b9
 grubby_LIBS = -lblkid -lpopt
3e90b9
 
3e90b9
-all: grubby
3e90b9
+all: grubby rpm-sort
3e90b9
 
3e90b9
 debug : clean
3e90b9
 	$(MAKE) CFLAGS="${CFLAGS} -DDEBUG=1" all
3e90b9
@@ -52,12 +52,17 @@ install: all
3e90b9
 		install -m 755 grubby $(DESTDIR)$(PREFIX)$(sbindir) ; \
3e90b9
 		install -m 644 grubby.8 $(DESTDIR)/$(mandir)/man8 ; \
3e90b9
 	fi
3e90b9
+	install -m 755 -d $(DESTDIR)$(PREFIX)$(libexecdir)/grubby/
3e90b9
+	install -m 755 rpm-sort $(DESTDIR)$(PREFIX)$(libexecdir)/grubby/rpm-sort
3e90b9
 
3e90b9
 grubby:: $(OBJECTS)
3e90b9
 	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(grubby_LIBS)
3e90b9
 
3e90b9
+rpm-sort::rpm-sort.o
3e90b9
+	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ -lrpm
3e90b9
+
3e90b9
 clean:
3e90b9
-	rm -f *.o grubby *~
3e90b9
+	rm -f *.o grubby rpm-sort *~
3e90b9
 
3e90b9
 GITTAG = $(VERSION)-1
3e90b9
 
3e90b9
diff --git a/.gitignore b/.gitignore
3e90b9
index e64d3bc0986..1a5a546eee3 100644
3e90b9
--- a/.gitignore
3e90b9
+++ b/.gitignore
3e90b9
@@ -1,3 +1,4 @@
3e90b9
 grubby
3e90b9
+rpm-sort
3e90b9
 version.h
3e90b9
 *.o
3e90b9
-- 
3e90b9
2.17.1
3e90b9