diff --git a/0001-postprocess-Handle-f26-etc-nsswitch.conf-configurati.patch b/0001-postprocess-Handle-f26-etc-nsswitch.conf-configurati.patch new file mode 100644 index 0000000..8dfd082 --- /dev/null +++ b/0001-postprocess-Handle-f26-etc-nsswitch.conf-configurati.patch @@ -0,0 +1,279 @@ +From 62a93c78500edd9c67b2300cba1134b373138258 Mon Sep 17 00:00:00 2001 +From: Colin Walters +Date: Thu, 16 Mar 2017 11:29:21 -0400 +Subject: [PATCH] postprocess: Handle f26 /etc/nsswitch.conf configuration +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +F26 put sss first, which broke our regexp. When we switch to sysusers, man it'll +be nice to dump ♲ this. + +Closes: https://github.com/projectatomic/rpm-ostree/issues/685 + +Closes: #686 +Approved by: jlebon +--- + Makefile-tests.am | 5 ++ + src/libpriv/rpmostree-postprocess.c | 95 +++++++++++++++++++++++++++++-------- + src/libpriv/rpmostree-postprocess.h | 5 ++ + tests/check/postprocess.c | 93 ++++++++++++++++++++++++++++++++++++ + 4 files changed, 179 insertions(+), 19 deletions(-) + create mode 100644 tests/check/postprocess.c + +diff --git a/Makefile-tests.am b/Makefile-tests.am +index ab9f9cc..b173877 100644 +--- a/Makefile-tests.am ++++ b/Makefile-tests.am +@@ -75,6 +75,10 @@ tests_check_cache_branch_to_nevra_CPPFLAGS = $(AM_CPPFLAGS) -I $(srcdir)/src/lib + tests_check_cache_branch_to_nevra_CFLAGS = $(AM_CFLAGS) $(PKGDEP_RPMOSTREE_CFLAGS) + tests_check_cache_branch_to_nevra_LDADD = $(PKGDEP_RPMOSTREE_LIBS) librpmostreepriv.la + ++tests_check_postprocess_CPPFLAGS = $(AM_CPPFLAGS) -I $(srcdir)/src/libpriv -I $(srcdir)/libglnx ++tests_check_postprocess_CFLAGS = $(AM_CFLAGS) $(PKGDEP_RPMOSTREE_CFLAGS) ++tests_check_postprocess_LDADD = $(PKGDEP_RPMOSTREE_LIBS) librpmostreepriv.la ++ + tests/check/test-compose.sh: tests/common/compose/test-repo.repo + + tests/check/test-ucontainer.sh: tests/common/compose/test-repo.repo +@@ -82,6 +86,7 @@ tests/check/test-ucontainer.sh: tests/common/compose/test-repo.repo + uninstalled_test_programs = \ + tests/check/jsonutil \ + tests/check/cache_branch_to_nevra \ ++ tests/check/postprocess \ + $(NULL) + + uninstalled_test_scripts = \ +diff --git a/src/libpriv/rpmostree-postprocess.c b/src/libpriv/rpmostree-postprocess.c +index dce8ddc..cff6e8d 100644 +--- a/src/libpriv/rpmostree-postprocess.c ++++ b/src/libpriv/rpmostree-postprocess.c +@@ -512,34 +512,91 @@ rpmostree_prepare_rootfs_get_sepolicy (int dfd, + return ret; + } + +-static gboolean +-replace_nsswitch (int dfd, +- GCancellable *cancellable, +- GError **error) ++static char * ++replace_nsswitch_string (const char *buf, ++ GError **error) + { +- g_autofree char *nsswitch_contents = NULL; +- g_autofree char *new_nsswitch_contents = NULL; ++ gboolean is_passwd; ++ gboolean is_group; ++ ++ is_passwd = g_str_has_prefix (buf, "passwd:"); ++ is_group = g_str_has_prefix (buf, "group:"); ++ ++ if (!(is_passwd || is_group)) ++ return g_strdup (buf); ++ ++ const char *colon = strchr (buf, ':'); ++ g_assert (colon); ++ ++ g_autoptr(GString) retbuf = g_string_new (""); ++ /* Insert the prefix */ ++ g_string_append_len (retbuf, buf, (colon - buf) + 1); ++ ++ /* Now parse the elements and try to insert `altfiles` ++ * after `files`. ++ */ ++ g_auto(GStrv) elts = g_strsplit_set (colon + 1, " \t", -1); ++ gboolean inserted = FALSE; ++ for (char **iter = elts; iter && *iter; iter++) ++ { ++ const char *v = *iter; ++ if (!*v) ++ continue; ++ /* Already have altfiles? We're done */ ++ if (strcmp (v, "altfiles") == 0) ++ return g_strdup (buf); ++ /* We prefer `files altfiles` */ ++ else if (!inserted && strcmp (v, "files") == 0) ++ { ++ g_string_append (retbuf, " files altfiles"); ++ inserted = TRUE; ++ } ++ else ++ { ++ g_string_append_c (retbuf, ' '); ++ g_string_append (retbuf, v); ++ } ++ } ++ /* Last ditch effort if we didn't find `files` */ ++ if (!inserted) ++ g_string_append (retbuf, " altfiles"); ++ return g_string_free (g_steal_pointer (&retbuf), FALSE); ++} + +- static gsize regex_initialized; +- static GRegex *passwd_regex; ++char * ++rpmostree_postprocess_replace_nsswitch (const char *buf, ++ GError **error) ++{ ++ g_autoptr(GString) new_buf = g_string_new (""); + +- if (g_once_init_enter (®ex_initialized)) ++ g_auto(GStrv) lines = g_strsplit (buf, "\n", -1); ++ for (char **iter = lines; iter && *iter; iter++) + { +- passwd_regex = g_regex_new ("^(passwd|group):\\s+files(.*)$", +- G_REGEX_MULTILINE, 0, NULL); +- g_assert (passwd_regex); +- g_once_init_leave (®ex_initialized, 1); ++ const char *line = *iter; ++ g_autofree char *replaced_line = replace_nsswitch_string (line, error); ++ if (!replaced_line) ++ return NULL; ++ g_string_append (new_buf, replaced_line); ++ if (*(iter+1)) ++ g_string_append_c (new_buf, '\n'); + } ++ return g_string_free (g_steal_pointer (&new_buf), FALSE); ++} ++ + +- nsswitch_contents = glnx_file_get_contents_utf8_at (dfd, "etc/nsswitch.conf", NULL, +- cancellable, error); ++static gboolean ++replace_nsswitch (int dfd, ++ GCancellable *cancellable, ++ GError **error) ++{ ++ g_autofree char *nsswitch_contents = ++ glnx_file_get_contents_utf8_at (dfd, "etc/nsswitch.conf", NULL, ++ cancellable, error); + if (!nsswitch_contents) + return FALSE; + +- new_nsswitch_contents = g_regex_replace (passwd_regex, +- nsswitch_contents, -1, 0, +- "\\1: files altfiles\\2", +- 0, error); ++ g_autofree char *new_nsswitch_contents = ++ rpmostree_postprocess_replace_nsswitch (nsswitch_contents, error); + if (!new_nsswitch_contents) + return FALSE; + +diff --git a/src/libpriv/rpmostree-postprocess.h b/src/libpriv/rpmostree-postprocess.h +index a270c98..1c972ac 100644 +--- a/src/libpriv/rpmostree-postprocess.h ++++ b/src/libpriv/rpmostree-postprocess.h +@@ -23,6 +23,11 @@ + #include + #include "rpmostree-json-parsing.h" + ++/* "public" for unit tests */ ++char * ++rpmostree_postprocess_replace_nsswitch (const char *buf, ++ GError **error); ++ + gboolean + rpmostree_treefile_postprocessing (int rootfs_fd, + GFile *context_directory, +diff --git a/tests/check/postprocess.c b/tests/check/postprocess.c +new file mode 100644 +index 0000000..135be94 +--- /dev/null ++++ b/tests/check/postprocess.c +@@ -0,0 +1,93 @@ ++#include "config.h" ++ ++#include ++#include ++#include ++ ++#include ++#include "libglnx.h" ++#include "rpmostree-postprocess.h" ++ ++typedef struct { ++ const char *input; ++ const char *output; ++} AltfilesTest; ++ ++static AltfilesTest altfiles_tests[] = { ++ { ++ /* F25 */ ++ .input = "# An nsswitch.conf\n" \ ++ "\npasswd: files sss\n" \ ++ "\ngroup: files sss\n" \ ++ "\nhosts: files mdns4_minimal [NOTFOUND=return] dns myhostname\n", ++ .output = "# An nsswitch.conf\n" \ ++ "\npasswd: files altfiles sss\n" \ ++ "\ngroup: files altfiles sss\n" \ ++ "\nhosts: files mdns4_minimal [NOTFOUND=return] dns myhostname\n" ++ }, ++ { ++ /* F26 */ ++ .input = "# An nsswitch.conf\n" \ ++ "\npasswd: sss files systemd\n" \ ++ "\ngroup: sss files systemd\n" \ ++ "\nhosts: files mdns4_minimal [NOTFOUND=return] dns myhostname\n", ++ .output = "# An nsswitch.conf\n" \ ++ "\npasswd: sss files altfiles systemd\n" \ ++ "\ngroup: sss files altfiles systemd\n" \ ++ "\nhosts: files mdns4_minimal [NOTFOUND=return] dns myhostname\n" ++ }, ++ { ++ /* Already have altfiles, input/output identical */ ++ .input = "# An nsswitch.conf\n" \ ++ "\npasswd: sss files altfiles systemd\n" \ ++ "\ngroup: sss files altfiles systemd\n" \ ++ "\nhosts: files mdns4_minimal [NOTFOUND=return] dns myhostname\n", ++ .output = "# An nsswitch.conf\n" \ ++ "\npasswd: sss files altfiles systemd\n" \ ++ "\ngroup: sss files altfiles systemd\n" \ ++ "\nhosts: files mdns4_minimal [NOTFOUND=return] dns myhostname\n", ++ }, ++ { ++ /* Test having `files` as a substring */ ++ .input = "# An nsswitch.conf\n" \ ++ "\npasswd: sss foofiles files systemd\n" \ ++ "\ngroup: sss foofiles files systemd\n" \ ++ "\nhosts: files mdns4_minimal [NOTFOUND=return] dns myhostname\n", ++ .output = "# An nsswitch.conf\n" \ ++ "\npasswd: sss foofiles files altfiles systemd\n" \ ++ "\ngroup: sss foofiles files altfiles systemd\n" \ ++ "\nhosts: files mdns4_minimal [NOTFOUND=return] dns myhostname\n", ++ } ++}; ++ ++static void ++test_postprocess_altfiles (void) ++{ ++ g_autoptr(GError) local_error = NULL; ++ GError **error = &local_error; ++ ++ for (guint i = 0; i < G_N_ELEMENTS(altfiles_tests); i++) ++ { ++ AltfilesTest *test = &altfiles_tests[i]; ++ g_autofree char *newbuf = rpmostree_postprocess_replace_nsswitch (test->input, error); ++ ++ if (!newbuf) ++ goto out; ++ ++ g_assert_cmpstr (newbuf, ==, test->output); ++ } ++ ++ out: ++ g_assert_no_error (local_error); ++} ++ ++int ++main (int argc, ++ char *argv[]) ++{ ++ g_test_init (&argc, &argv, NULL); ++ ++ g_test_add_func ("/altfiles", test_postprocess_altfiles); ++ ++ return g_test_run (); ++} +-- +2.9.3 + diff --git a/2017.3-maint.patch b/2017.3-maint.patch index f1c3356..dc172b0 100644 --- a/2017.3-maint.patch +++ b/2017.3-maint.patch @@ -1,7 +1,7 @@ From cea2812fc01f8e37a6cdee3abcff511f2554703a Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Mon, 6 Mar 2017 14:17:06 -0500 -Subject: [PATCH 1/3] Allow and start using C99 declaration-after-statement +Subject: [PATCH 1/4] Allow and start using C99 declaration-after-statement The equivalent of https://github.com/ostreedev/ostree/pull/718 but for this codebase. @@ -87,7 +87,7 @@ index b0aaec7..0f994e9 100644 From 94e386fc86e4208dda03090f543f3e0f415d32e4 Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Thu, 9 Mar 2017 16:39:03 -0500 -Subject: [PATCH 2/3] status: always include the packages entries +Subject: [PATCH 2/4] status: always include the packages entries Pull #646 introduced a subtle regression: we went from always including a "packages" entry to only including it if there are packages present. @@ -156,7 +156,7 @@ index 79e9562..ce10201 100755 From 8df6672500c3404847b0e42e94dba076af4f5eb6 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Fri, 10 Mar 2017 09:48:03 -0500 -Subject: [PATCH 3/3] bwrap: Don't use --unshare-net in nspawn by default +Subject: [PATCH 3/4] bwrap: Don't use --unshare-net in nspawn by default This will fix rpm-ostree-in-mock-in-koji. The drawback is minor: post scripts will have network access. But we're going to be testing the no-network case in @@ -231,3 +231,282 @@ index 9d40059..5258439 100644 -- 2.9.3 + +From 530d009df3afe4d769f065a2d5007e683bf81250 Mon Sep 17 00:00:00 2001 +From: Colin Walters +Date: Thu, 16 Mar 2017 11:29:21 -0400 +Subject: [PATCH 4/4] postprocess: Handle f26 /etc/nsswitch.conf configuration +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +F26 put sss first, which broke our regexp. When we switch to sysusers, man it'll +be nice to dump ♲ this. + +Closes: https://github.com/projectatomic/rpm-ostree/issues/685 + +Closes: #686 +Approved by: jlebon +--- + Makefile-tests.am | 5 ++ + src/libpriv/rpmostree-postprocess.c | 95 +++++++++++++++++++++++++++++-------- + src/libpriv/rpmostree-postprocess.h | 5 ++ + tests/check/postprocess.c | 93 ++++++++++++++++++++++++++++++++++++ + 4 files changed, 179 insertions(+), 19 deletions(-) + create mode 100644 tests/check/postprocess.c + +diff --git a/Makefile-tests.am b/Makefile-tests.am +index 85c0fb4..a2163cf 100644 +--- a/Makefile-tests.am ++++ b/Makefile-tests.am +@@ -71,12 +71,17 @@ tests_check_jsonutil_CPPFLAGS = $(AM_CPPFLAGS) -I $(srcdir)/src/libpriv -I $(src + tests_check_jsonutil_CFLAGS = $(AM_CFLAGS) $(PKGDEP_RPMOSTREE_CFLAGS) + tests_check_jsonutil_LDADD = $(PKGDEP_RPMOSTREE_LIBS) librpmostreepriv.la + ++tests_check_postprocess_CPPFLAGS = $(AM_CPPFLAGS) -I $(srcdir)/src/libpriv -I $(srcdir)/libglnx ++tests_check_postprocess_CFLAGS = $(AM_CFLAGS) $(PKGDEP_RPMOSTREE_CFLAGS) ++tests_check_postprocess_LDADD = $(PKGDEP_RPMOSTREE_LIBS) librpmostreepriv.la ++ + tests/check/test-compose.sh: tests/common/compose/test-repo.repo + + tests/check/test-ucontainer.sh: tests/common/compose/test-repo.repo + + uninstalled_test_programs = \ + tests/check/jsonutil \ ++ tests/check/postprocess \ + $(NULL) + + uninstalled_test_scripts = \ +diff --git a/src/libpriv/rpmostree-postprocess.c b/src/libpriv/rpmostree-postprocess.c +index e75b010..43b1251 100644 +--- a/src/libpriv/rpmostree-postprocess.c ++++ b/src/libpriv/rpmostree-postprocess.c +@@ -512,34 +512,91 @@ rpmostree_prepare_rootfs_get_sepolicy (int dfd, + return ret; + } + +-static gboolean +-replace_nsswitch (int dfd, +- GCancellable *cancellable, +- GError **error) ++static char * ++replace_nsswitch_string (const char *buf, ++ GError **error) + { +- g_autofree char *nsswitch_contents = NULL; +- g_autofree char *new_nsswitch_contents = NULL; ++ gboolean is_passwd; ++ gboolean is_group; ++ ++ is_passwd = g_str_has_prefix (buf, "passwd:"); ++ is_group = g_str_has_prefix (buf, "group:"); ++ ++ if (!(is_passwd || is_group)) ++ return g_strdup (buf); ++ ++ const char *colon = strchr (buf, ':'); ++ g_assert (colon); ++ ++ g_autoptr(GString) retbuf = g_string_new (""); ++ /* Insert the prefix */ ++ g_string_append_len (retbuf, buf, (colon - buf) + 1); ++ ++ /* Now parse the elements and try to insert `altfiles` ++ * after `files`. ++ */ ++ g_auto(GStrv) elts = g_strsplit_set (colon + 1, " \t", -1); ++ gboolean inserted = FALSE; ++ for (char **iter = elts; iter && *iter; iter++) ++ { ++ const char *v = *iter; ++ if (!*v) ++ continue; ++ /* Already have altfiles? We're done */ ++ if (strcmp (v, "altfiles") == 0) ++ return g_strdup (buf); ++ /* We prefer `files altfiles` */ ++ else if (!inserted && strcmp (v, "files") == 0) ++ { ++ g_string_append (retbuf, " files altfiles"); ++ inserted = TRUE; ++ } ++ else ++ { ++ g_string_append_c (retbuf, ' '); ++ g_string_append (retbuf, v); ++ } ++ } ++ /* Last ditch effort if we didn't find `files` */ ++ if (!inserted) ++ g_string_append (retbuf, " altfiles"); ++ return g_string_free (g_steal_pointer (&retbuf), FALSE); ++} + +- static gsize regex_initialized; +- static GRegex *passwd_regex; ++char * ++rpmostree_postprocess_replace_nsswitch (const char *buf, ++ GError **error) ++{ ++ g_autoptr(GString) new_buf = g_string_new (""); + +- if (g_once_init_enter (®ex_initialized)) ++ g_auto(GStrv) lines = g_strsplit (buf, "\n", -1); ++ for (char **iter = lines; iter && *iter; iter++) + { +- passwd_regex = g_regex_new ("^(passwd|group):\\s+files(.*)$", +- G_REGEX_MULTILINE, 0, NULL); +- g_assert (passwd_regex); +- g_once_init_leave (®ex_initialized, 1); ++ const char *line = *iter; ++ g_autofree char *replaced_line = replace_nsswitch_string (line, error); ++ if (!replaced_line) ++ return NULL; ++ g_string_append (new_buf, replaced_line); ++ if (*(iter+1)) ++ g_string_append_c (new_buf, '\n'); + } ++ return g_string_free (g_steal_pointer (&new_buf), FALSE); ++} ++ + +- nsswitch_contents = glnx_file_get_contents_utf8_at (dfd, "etc/nsswitch.conf", NULL, +- cancellable, error); ++static gboolean ++replace_nsswitch (int dfd, ++ GCancellable *cancellable, ++ GError **error) ++{ ++ g_autofree char *nsswitch_contents = ++ glnx_file_get_contents_utf8_at (dfd, "etc/nsswitch.conf", NULL, ++ cancellable, error); + if (!nsswitch_contents) + return FALSE; + +- new_nsswitch_contents = g_regex_replace (passwd_regex, +- nsswitch_contents, -1, 0, +- "\\1: files altfiles\\2", +- 0, error); ++ g_autofree char *new_nsswitch_contents = ++ rpmostree_postprocess_replace_nsswitch (nsswitch_contents, error); + if (!new_nsswitch_contents) + return FALSE; + +diff --git a/src/libpriv/rpmostree-postprocess.h b/src/libpriv/rpmostree-postprocess.h +index a270c98..1c972ac 100644 +--- a/src/libpriv/rpmostree-postprocess.h ++++ b/src/libpriv/rpmostree-postprocess.h +@@ -23,6 +23,11 @@ + #include + #include "rpmostree-json-parsing.h" + ++/* "public" for unit tests */ ++char * ++rpmostree_postprocess_replace_nsswitch (const char *buf, ++ GError **error); ++ + gboolean + rpmostree_treefile_postprocessing (int rootfs_fd, + GFile *context_directory, +diff --git a/tests/check/postprocess.c b/tests/check/postprocess.c +new file mode 100644 +index 0000000..135be94 +--- /dev/null ++++ b/tests/check/postprocess.c +@@ -0,0 +1,93 @@ ++#include "config.h" ++ ++#include ++#include ++#include ++ ++#include ++#include "libglnx.h" ++#include "rpmostree-postprocess.h" ++ ++typedef struct { ++ const char *input; ++ const char *output; ++} AltfilesTest; ++ ++static AltfilesTest altfiles_tests[] = { ++ { ++ /* F25 */ ++ .input = "# An nsswitch.conf\n" \ ++ "\npasswd: files sss\n" \ ++ "\ngroup: files sss\n" \ ++ "\nhosts: files mdns4_minimal [NOTFOUND=return] dns myhostname\n", ++ .output = "# An nsswitch.conf\n" \ ++ "\npasswd: files altfiles sss\n" \ ++ "\ngroup: files altfiles sss\n" \ ++ "\nhosts: files mdns4_minimal [NOTFOUND=return] dns myhostname\n" ++ }, ++ { ++ /* F26 */ ++ .input = "# An nsswitch.conf\n" \ ++ "\npasswd: sss files systemd\n" \ ++ "\ngroup: sss files systemd\n" \ ++ "\nhosts: files mdns4_minimal [NOTFOUND=return] dns myhostname\n", ++ .output = "# An nsswitch.conf\n" \ ++ "\npasswd: sss files altfiles systemd\n" \ ++ "\ngroup: sss files altfiles systemd\n" \ ++ "\nhosts: files mdns4_minimal [NOTFOUND=return] dns myhostname\n" ++ }, ++ { ++ /* Already have altfiles, input/output identical */ ++ .input = "# An nsswitch.conf\n" \ ++ "\npasswd: sss files altfiles systemd\n" \ ++ "\ngroup: sss files altfiles systemd\n" \ ++ "\nhosts: files mdns4_minimal [NOTFOUND=return] dns myhostname\n", ++ .output = "# An nsswitch.conf\n" \ ++ "\npasswd: sss files altfiles systemd\n" \ ++ "\ngroup: sss files altfiles systemd\n" \ ++ "\nhosts: files mdns4_minimal [NOTFOUND=return] dns myhostname\n", ++ }, ++ { ++ /* Test having `files` as a substring */ ++ .input = "# An nsswitch.conf\n" \ ++ "\npasswd: sss foofiles files systemd\n" \ ++ "\ngroup: sss foofiles files systemd\n" \ ++ "\nhosts: files mdns4_minimal [NOTFOUND=return] dns myhostname\n", ++ .output = "# An nsswitch.conf\n" \ ++ "\npasswd: sss foofiles files altfiles systemd\n" \ ++ "\ngroup: sss foofiles files altfiles systemd\n" \ ++ "\nhosts: files mdns4_minimal [NOTFOUND=return] dns myhostname\n", ++ } ++}; ++ ++static void ++test_postprocess_altfiles (void) ++{ ++ g_autoptr(GError) local_error = NULL; ++ GError **error = &local_error; ++ ++ for (guint i = 0; i < G_N_ELEMENTS(altfiles_tests); i++) ++ { ++ AltfilesTest *test = &altfiles_tests[i]; ++ g_autofree char *newbuf = rpmostree_postprocess_replace_nsswitch (test->input, error); ++ ++ if (!newbuf) ++ goto out; ++ ++ g_assert_cmpstr (newbuf, ==, test->output); ++ } ++ ++ out: ++ g_assert_no_error (local_error); ++} ++ ++int ++main (int argc, ++ char *argv[]) ++{ ++ g_test_init (&argc, &argv, NULL); ++ ++ g_test_add_func ("/altfiles", test_postprocess_altfiles); ++ ++ return g_test_run (); ++} +-- +2.9.3 + diff --git a/rpm-ostree.spec b/rpm-ostree.spec index 667fe78..7247064 100644 --- a/rpm-ostree.spec +++ b/rpm-ostree.spec @@ -1,7 +1,7 @@ Summary: Hybrid image/package system Name: rpm-ostree Version: 2017.3 -Release: 2%{?dist} +Release: 3%{?dist} #VCS: https://github.com/cgwalters/rpm-ostree # This tarball is generated via "make -f Makefile.dist-packaging dist-snapshot" Source0: rpm-ostree-%{version}.tar.xz @@ -134,6 +134,9 @@ python autofiles.py > files.devel \ %files devel -f files.devel %changelog +* Thu Mar 16 2017 Colin Walters - 2017.3-3 +- Add patch to fix f26 altfiles + * Fri Mar 10 2017 Colin Walters - 2017.3-2 - Backport patch for running in koji