diff --git a/0001-utils-import-parse_size-from-libguestfs.patch b/0001-utils-import-parse_size-from-libguestfs.patch new file mode 100644 index 0000000..2130fbf --- /dev/null +++ b/0001-utils-import-parse_size-from-libguestfs.patch @@ -0,0 +1,53 @@ +From b6cf15d8f38270d6d6c9df2c8589829c9a3ad176 Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Mon, 13 Jul 2015 17:32:33 +0200 +Subject: [PATCH 1/7] utils: import parse_size from libguestfs + +--- + src/utils.ml | 21 +++++++++++++++++++++ + src/utils.mli | 3 +++ + 2 files changed, 24 insertions(+) + +diff --git a/src/utils.ml b/src/utils.ml +index 3e81c21..7ae24bd 100644 +--- a/src/utils.ml ++++ b/src/utils.ml +@@ -204,3 +204,24 @@ let compare_architecture a1 a2 = + exit 1 + in + compare (index_of_architecture a1) (index_of_architecture a2) ++ ++(* Parse a size field, eg. "10G". *) ++let parse_size = ++ let const_re = Str.regexp "^\\([.0-9]+\\)\\([bKMG]\\)$" in ++ fun field -> ++ let matches rex = Str.string_match rex field 0 in ++ let sub i = Str.matched_group i field in ++ let size_scaled f = function ++ | "b" -> Int64.of_float f ++ | "K" -> Int64.of_float (f *. 1024.) ++ | "M" -> Int64.of_float (f *. 1024. *. 1024.) ++ | "G" -> Int64.of_float (f *. 1024. *. 1024. *. 1024.) ++ | _ -> assert false ++ in ++ ++ if matches const_re then ( ++ size_scaled (float_of_string (sub 1)) (sub 2) ++ ) else ( ++ eprintf "supermin: cannot parse size field '%s'\n" field; ++ exit 1 ++ ) +diff --git a/src/utils.mli b/src/utils.mli +index 5de940d..7896e34 100644 +--- a/src/utils.mli ++++ b/src/utils.mli +@@ -90,3 +90,6 @@ val compare_version : string -> string -> int + + val compare_architecture : string -> string -> int + (** Compare two architecture strings. *) ++ ++val parse_size : string -> int64 ++(** Parse a size field, eg. [10G] *) +-- +2.5.0 + diff --git a/0002-Add-size-for-ext2-filesystem.patch b/0002-Add-size-for-ext2-filesystem.patch new file mode 100644 index 0000000..1e8d7ae --- /dev/null +++ b/0002-Add-size-for-ext2-filesystem.patch @@ -0,0 +1,184 @@ +From 92bc55b54a17d368b43241394ace1d862899f9d7 Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Mon, 13 Jul 2015 17:33:34 +0200 +Subject: [PATCH 2/7] Add --size for ext2 filesystem + +Add a --size option to setting the size of the ext2 filesystem, +so it is possible to create ext2 appliances with smaller disk images. + +The default is like the previously hardcoded value of 4GB. +--- + src/build.ml | 4 ++-- + src/ext2.ml | 19 ++++++++++--------- + src/prepare.ml | 2 +- + src/supermin.ml | 9 +++++++-- + src/supermin.pod | 15 +++++++++++++++ + 5 files changed, 35 insertions(+), 14 deletions(-) + +diff --git a/src/build.ml b/src/build.ml +index d7d0781..fb2e6d3 100644 +--- a/src/build.ml ++++ b/src/build.ml +@@ -59,7 +59,7 @@ and string_of_file_content = function + + let rec build debug + (copy_kernel, dtb_wildcard, format, host_cpu, +- packager_config, tmpdir, use_installed) ++ packager_config, tmpdir, use_installed, size) + inputs outputdir = + if debug >= 1 then + printf "supermin: build: %s\n%!" (String.concat " " inputs); +@@ -210,7 +210,7 @@ let rec build debug + and initrd = outputdir // "initrd" in + let kernel_version, modpath = + Kernel.build_kernel debug host_cpu dtb_wildcard copy_kernel kernel dtb in +- Ext2.build_ext2 debug basedir files modpath kernel_version appliance; ++ Ext2.build_ext2 debug basedir files modpath kernel_version appliance size; + Ext2_initrd.build_initrd debug tmpdir modpath initrd + + and read_appliance debug basedir appliance = function +diff --git a/src/ext2.ml b/src/ext2.ml +index d5c26a7..79539a3 100644 +--- a/src/ext2.ml ++++ b/src/ext2.ml +@@ -23,26 +23,27 @@ open Utils + open Ext2fs + open Package_handler + +-(* The ext2 image that we build always has a fixed size, and we 'hope' +- * that the files fit in (otherwise we'll get an error). Note that +- * the file is sparsely allocated. ++(* The ext2 image that we build has a size of 4GB if not specified, ++ * and we 'hope' that the files fit in (otherwise we'll get an error). ++ * Note that the file is sparsely allocated. + * + * The downside of allocating a very large initial disk is that the + * fixed overhead of ext2 is larger (since ext2 calculates it based on + * the size of the disk). For a 4GB disk the overhead is + * approximately 66MB. +- * +- * In future, make this configurable, or determine it from the input +- * files (XXX). + *) +-let appliance_size = 4L *^ 1024L *^ 1024L *^ 1024L ++let default_appliance_size = 4L *^ 1024L *^ 1024L *^ 1024L + +-let build_ext2 debug basedir files modpath kernel_version appliance = ++let build_ext2 debug basedir files modpath kernel_version appliance size = + if debug >= 1 then + printf "supermin: ext2: creating empty ext2 filesystem '%s'\n%!" appliance; + + let fd = openfile appliance [O_WRONLY;O_CREAT;O_TRUNC;O_NOCTTY] 0o644 in +- LargeFile.ftruncate fd appliance_size; ++ let size = ++ match size with ++ | None -> default_appliance_size ++ | Some s -> s in ++ LargeFile.ftruncate fd size; + close fd; + + let cmd = +diff --git a/src/prepare.ml b/src/prepare.ml +index 75f21dc..7e522e9 100644 +--- a/src/prepare.ml ++++ b/src/prepare.ml +@@ -22,7 +22,7 @@ open Package_handler + open Utils + + let prepare debug (copy_kernel, dtb_wildcard, format, host_cpu, +- packager_config, tmpdir, use_installed) ++ packager_config, tmpdir, use_installed, size) + inputs outputdir = + if debug >= 1 then + printf "supermin: prepare: %s\n%!" (String.concat " " inputs); +diff --git a/src/supermin.ml b/src/supermin.ml +index 14261d6..9623229 100644 +--- a/src/supermin.ml ++++ b/src/supermin.ml +@@ -94,6 +94,7 @@ let main () = + let outputdir = ref "" in + let packager_config = ref "" in + let use_installed = ref false in ++ let size = ref None in + + let set_debug () = incr debug in + +@@ -118,6 +119,8 @@ let main () = + exit 1 + in + ++ let set_size arg = size := Some (parse_size arg) in ++ + let error_supermin_5 () = + eprintf "supermin: *** error: This is supermin version 5.\n"; + eprintf "supermin: *** It looks like you are looking for supermin version 4.\n"; +@@ -143,6 +146,7 @@ let main () = + "-o", Arg.Set_string outputdir, "OUTPUTDIR Set output directory"; + "--packager-config", Arg.Set_string packager_config, "CONFIGFILE Set packager config file"; + "--prepare", Arg.Unit set_prepare_mode, " Prepare a supermin appliance"; ++ "--size", Arg.String set_size, " Set the size of the ext2 filesystem"; + "--use-installed", Arg.Set use_installed, " Use installed files instead of accessing network"; + "-v", Arg.Unit set_debug, " Enable debugging messages"; + "--verbose", Arg.Unit set_debug, ditto; +@@ -165,6 +169,7 @@ let main () = + let packager_config = + match !packager_config with "" -> None | s -> Some s in + let use_installed = !use_installed in ++ let size = !size in + + let format = + match mode, !format with +@@ -184,7 +189,7 @@ let main () = + + debug, mode, if_newer, inputs, lockfile, outputdir, + (copy_kernel, dtb_wildcard, format, host_cpu, +- packager_config, tmpdir, use_installed) in ++ packager_config, tmpdir, use_installed, size) in + + if debug >= 1 then printf "supermin: version: %s\n" Config.package_version; + +@@ -192,7 +197,7 @@ let main () = + * This fails with an error if one could not be located. + *) + let () = +- let (_, _, _, _, packager_config, tmpdir, _) = args in ++ let (_, _, _, _, packager_config, tmpdir, _, _) = args in + let settings = { + debug = debug; + tmpdir = tmpdir; +diff --git a/src/supermin.pod b/src/supermin.pod +index f2e8446..f9b7395 100644 +--- a/src/supermin.pod ++++ b/src/supermin.pod +@@ -189,6 +189,9 @@ appliance to C, and the ext2 filesystem image to + C. (Where C is specified by the I<-o> + option). + ++The filesystem (C) has a default size of 4 GB ++(see also the I<--size> option). ++ + =back + + =item B<--host-cpu> CPU +@@ -283,6 +286,18 @@ However this option is useful in some controlled situations: for + example when using supermin inside a freshly installed chroot, or if + you have no network access during the build. + ++=item B<--size> SIZE ++ ++(I<--build> mode only) ++ ++Select the size of the output ext2 filesystem, where the size can be ++specified using common names such as C<32G> (32 gigabytes) etc. ++ ++If the size is not specified, a default size of 4 GB is used. ++ ++To specify size in bytes, the number must be followed by the lowercase ++letter I, eg: S>. ++ + =item B<-v> + + =item B<--verbose> +-- +2.5.0 + diff --git a/0003-docs-Use-F-for-filenames-instead-of-C.patch b/0003-docs-Use-F-for-filenames-instead-of-C.patch new file mode 100644 index 0000000..e697947 --- /dev/null +++ b/0003-docs-Use-F-for-filenames-instead-of-C.patch @@ -0,0 +1,217 @@ +From d4615d38b2ccbf47642457887d2f4b1a514ee456 Mon Sep 17 00:00:00 2001 +From: Pino Toscano +Date: Tue, 14 Jul 2015 08:57:44 +0200 +Subject: [PATCH 3/7] docs: Use F<> for filenames instead of C<> + +--- + src/supermin.pod | 60 ++++++++++++++++++++++++++++---------------------------- + 1 file changed, 30 insertions(+), 30 deletions(-) + +diff --git a/src/supermin.pod b/src/supermin.pod +index f9b7395..53d1b11 100644 +--- a/src/supermin.pod ++++ b/src/supermin.pod +@@ -46,7 +46,7 @@ For example: + + creates a supermin appliance containing the packages C and + C. Specifically, it creates some files in directory +-C. This directory I the supermin appliance. (See ++F. This directory I the supermin appliance. (See + L below). + + It is intended that the I<--prepare> step is done on a central build +@@ -60,8 +60,8 @@ builds the full appliance from the supermin appliance: + + supermin --build --format ext2 supermin.d -o appliance.d + +-This will create files called C, +-C etc, which is the full sized bootable appliance. ++This will create files called F, ++F etc, which is the full sized bootable appliance. + + It is intended that the I<--build> step is done on the end user's + machine at the last second before the appliance is needed. The +@@ -112,7 +112,7 @@ a separate program called C. + (I<--build> mode only) + + Copy the kernel (and device tree, if created) instead of symlinking to +-the kernel in C. ++the kernel in F. + + This is fractionally slower, but is necessary if you want to change + the permissions or SELinux label on the kernel or device tree. +@@ -124,7 +124,7 @@ the permissions or SELinux label on the kernel or device tree. + If specified, search for a device tree which is compatible with the + selected kernel and the name of which matches the given wildcard. You + can use a wildcard such as C which would match +-C. ++F. + + Notes: + +@@ -170,7 +170,7 @@ Possible formats are: + + A directory tree in the host filesystem. + +-The filesystem tree is written to C (ie. the I<-o> option). ++The filesystem tree is written to F (ie. the I<-o> option). + + This is called a C because you could literally L + into this directory afterwards, although it's a better idea to use a +@@ -183,13 +183,13 @@ assumed that you will be running the appliance using the host kernel. + + An ext2 filesystem disk image. + +-The output kernel is written to C, the device tree +-(if using) to C, a small initramfs which can mount the +-appliance to C, and the ext2 filesystem image to +-C. (Where C is specified by the I<-o> ++The output kernel is written to F, the device tree ++(if using) to F, a small initramfs which can mount the ++appliance to F, and the ext2 filesystem image to ++F. (Where F is specified by the I<-o> + option). + +-The filesystem (C) has a default size of 4 GB ++The filesystem (F) has a default size of 4 GB + (see also the I<--size> option). + + =back +@@ -210,7 +210,7 @@ The output directory is checked and it is I rebuilt unless it + needs to be. + + This is done by consulting the dates of the host package database +-(C etc), the input supermin files, and the output ++(F etc), the input supermin files, and the output + directory. The operation is only carried out if either the host + package database or the input supermin files are newer than the output + directory. +@@ -248,9 +248,9 @@ B, and a + new output directory is created. + + The output directory is created (nearly) atomically by constructing a +-temporary directory called something like C, then ++temporary directory called something like F, then + renaming the old output directory (if present) and deleting it, and +-then renaming the temporary directory to C. By combining ++then renaming the temporary directory to F. By combining + this option with I<--lock> you can ensure that multiple parallel runs + of supermin do not conflict with each other. + +@@ -262,10 +262,10 @@ Set the configuration file for the package manager. This allows you + to specify alternate software repositories. + + For ArchLinux, this sets the pacman configuration file (default +-C). See L. ++F). See L. + + For Yum/RPM distributions, this sets the yum configuration file +-(default C). See L. ++(default F). See L. + + =item B<--prepare> + +@@ -336,8 +336,8 @@ Print the package name and version number, and exit. + Supermin appliances consist of just enough information to be able to + build an appliance containing the same operating system (Linux + version, distro, release etc) as the host OS. Since the host and +-appliance share many common files such as C and +-C there is no reason to ship these files in the ++appliance share many common files such as F and ++F there is no reason to ship these files in the + appliance. They can simply be read from the host on demand when the + appliance is launched. Therefore to save space we just store the + names of the packages we want from the host, and copy those in (plus +@@ -350,20 +350,20 @@ skeleton base image which contains these files and the outline + directory structure. + + Therefore the supermin appliance normally consists of at least two +-control files (C and C). ++control files (F and F). + + =over 4 + +-=item B ++=item F + + The list of packages to be copied from the host. Dependencies are + resolved automatically. + + The file is plain text, one package name per line. + +-=item B ++=item F + +-=item B ++=item F + + This tar file (which may be compressed) contains the skeleton + filesystem. Mostly it contains directories and a few configuration +@@ -372,7 +372,7 @@ files. + All paths in the tar file should be relative to the root directory of + the appliance. + +-=item B ++=item F + + Any other files that are to be copied from the host. This is a plain + text file with one pathname per line. +@@ -382,7 +382,7 @@ is created, eg: + + /etc/yum.repos.d/*.repo + +-would copy all of the C<*.repo> files into the appliance. ++would copy all of the F<*.repo> files into the appliance. + + Each pathname in the file should start with a C character. + +@@ -392,7 +392,7 @@ However you may drop one or more of these files into the supermin + appliance directory if you want to copy random unpackaged files into + the full appliance. + +-=item B ++=item F + + A list of filenames, directory names, or wildcards prefixed by C<-> + which are excluded from the final appliance. +@@ -427,9 +427,9 @@ directories passed to it. A common layout could look like this: + supermin.d/zz-hostfiles + + In this way extra files can be added to the appliance just by creating +-another tar file (C in the example above) and dropping ++another tar file (F in the example above) and dropping + it into the directory, and additional host files can be added +-(C in the example above). When the appliance is ++(F in the example above). When the appliance is + constructed, the extra files will appear in the appliance. + + =head2 MINIMIZING THE SUPERMIN APPLIANCE +@@ -481,7 +481,7 @@ then you should do something like this: + =head2 ENFORCING AVAILABILITY OF PACKAGES + + Supermin builds the appliance by copying in the packages listed in +-C. For this to work those packages must be available. We ++F. For this to work those packages must be available. We + usually enforce this by adding requirements (eg. RPM C + lines) on the package that uses the supermin appliance, so that + package cannot be installed without pulling in the dependent packages +@@ -497,14 +497,14 @@ If this environment variable is set, then automatic selection of the + kernel is bypassed and this kernel is used. + + The environment variable should point to a kernel file, +-eg. C ++eg. F + + =item SUPERMIN_MODULES + + This specifies the kernel modules directory to use. + + The environment variable should point to a module directory, +-eg. C ++eg. F + + =item SUPERMIN_DTB + +-- +2.5.0 + diff --git a/0004-rpm-rpm_is_available-function-can-be-noalloc.patch b/0004-rpm-rpm_is_available-function-can-be-noalloc.patch new file mode 100644 index 0000000..b4039b6 --- /dev/null +++ b/0004-rpm-rpm_is_available-function-can-be-noalloc.patch @@ -0,0 +1,25 @@ +From f7707b743152b96af204e7ef55b33fca7d91bab0 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 13 Oct 2015 12:42:05 +0100 +Subject: [PATCH 4/7] rpm: rpm_is_available function can be "noalloc". + +--- + src/librpm.ml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/librpm.ml b/src/librpm.ml +index dc80286..4eeba77 100644 +--- a/src/librpm.ml ++++ b/src/librpm.ml +@@ -16,7 +16,7 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + *) + +-external rpm_is_available : unit -> bool = "supermin_rpm_is_available" ++external rpm_is_available : unit -> bool = "supermin_rpm_is_available" "noalloc" + + external rpm_version : unit -> string = "supermin_rpm_version" + external rpm_vercmp : string -> string -> int = "supermin_rpm_vercmp" "noalloc" +-- +2.5.0 + diff --git a/0005-rpm-Add-some-documentation-to-librpm.mli.patch b/0005-rpm-Add-some-documentation-to-librpm.mli.patch new file mode 100644 index 0000000..bb38439 --- /dev/null +++ b/0005-rpm-Add-some-documentation-to-librpm.mli.patch @@ -0,0 +1,62 @@ +From 9515c554ca9e725c4094cbbcd9f37bb316a2529f Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 13 Oct 2015 12:48:03 +0100 +Subject: [PATCH 5/7] rpm: Add some documentation to librpm.mli. + +--- + src/librpm.mli | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +diff --git a/src/librpm.mli b/src/librpm.mli +index da73911..5229be6 100644 +--- a/src/librpm.mli ++++ b/src/librpm.mli +@@ -16,17 +16,28 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + *) + ++(** Wrappers around [librpm] functions. *) ++ + val rpm_is_available : unit -> bool ++(** Returns [true] iff librpm is supported. If this returns [false], ++ then all other functions will abort. *) + + val rpm_version : unit -> string ++(** The linked version of librpm. *) ++ + val rpm_vercmp : string -> string -> int ++(** Compare two RPM version strings using RPM version compare rules. *) + + type t ++(** The librpm handle. *) + + exception Multiple_matches of int + + val rpm_open : ?debug:int -> t ++(** Open the librpm (transaction set) handle. *) + val rpm_close : t -> unit ++(** Explicitly close the handle. The handle can also be closed by ++ the garbage collector if it becomes unreachable. *) + + type rpm_t = { + name : string; +@@ -44,6 +55,16 @@ type rpmfile_t = { + | FileConfig + + val rpm_installed : t -> string -> rpm_t array ++(** Return the list of packages matching the name ++ (similar to [rpm -q name]). *) ++ + val rpm_pkg_requires : t -> string -> string array ++(** Return the requires of a package (similar to [rpm -qR]). *) ++ + val rpm_pkg_whatprovides : t -> string -> string array ++(** Return what package(s) provide a particular requirement ++ (similar to [rpm -q --whatprovides]). *) ++ + val rpm_pkg_filelist : t -> string -> rpmfile_t array ++(** Return the list of files contained in a package, and attributes of ++ those files (similar to [rpm -ql]). *) +-- +2.5.0 + diff --git a/0006-rpm-Flush-debugging-messages-in-C-code.patch b/0006-rpm-Flush-debugging-messages-in-C-code.patch new file mode 100644 index 0000000..7ab47f7 --- /dev/null +++ b/0006-rpm-Flush-debugging-messages-in-C-code.patch @@ -0,0 +1,82 @@ +From a843495409d2d1cf1cd966470b57d336d7ad04d4 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 13 Oct 2015 13:40:56 +0100 +Subject: [PATCH 6/7] rpm: Flush debugging messages in C code. + +Because C and OCaml use different implementations of stdio, and +because C stdout is not line-buffered, we can get mixed up debugging +messages. + +Partially fix this by using fflush (stdout) after printing C debugging +messages (this doesn't completely fix it because we'd have to do the +same in OCaml code too). + +This slows down debugging output, but it's only used when debugging so +we don't care about that. +--- + src/librpm-c.c | 28 ++++++++++++++++++++-------- + 1 file changed, 20 insertions(+), 8 deletions(-) + +diff --git a/src/librpm-c.c b/src/librpm-c.c +index fc847d6..3bd25a2 100644 +--- a/src/librpm-c.c ++++ b/src/librpm-c.c +@@ -202,8 +202,11 @@ supermin_rpm_installed (value rpmv, value pkgv) + caml_raise_not_found (); + + count = rpmdbGetIteratorCount (iter); +- if (data.debug >= 2) +- printf ("supermin: rpm: installed: %d occurrences for '%s'\n", count, String_val (pkgv)); ++ if (data.debug >= 2) { ++ printf ("supermin: rpm: installed: %d occurrences for '%s'\n", ++ count, String_val (pkgv)); ++ fflush (stdout); ++ } + + rv = caml_alloc (count, 0); + i = 0; +@@ -287,8 +290,11 @@ supermin_rpm_pkg_requires (value rpmv, value pkgv) + caml_raise_not_found (); + + count = rpmdbGetIteratorCount (iter); +- if (data.debug >= 2) +- printf ("supermin: rpm: pkg_requires: %d occurrences for '%s'\n", count, String_val (pkgv)); ++ if (data.debug >= 2) { ++ printf ("supermin: rpm: pkg_requires: %d occurrences for '%s'\n", ++ count, String_val (pkgv)); ++ fflush (stdout); ++ } + if (count != 1) + librpm_raise_multiple_matches (count); + +@@ -351,8 +357,11 @@ supermin_rpm_pkg_whatprovides (value rpmv, value pkgv) + caml_raise_not_found (); + + count = rpmdbGetIteratorCount (iter); +- if (data.debug >= 2) +- printf ("supermin: rpm: pkg_whatprovides: %d occurrences for '%s'\n", count, String_val (pkgv)); ++ if (data.debug >= 2) { ++ printf ("supermin: rpm: pkg_whatprovides: %d occurrences for '%s'\n", ++ count, String_val (pkgv)); ++ fflush (stdout); ++ } + + rv = caml_alloc (count, 0); + i = 0; +@@ -398,8 +407,11 @@ supermin_rpm_pkg_filelist (value rpmv, value pkgv) + caml_raise_not_found (); + + count = rpmdbGetIteratorCount (iter); +- if (data.debug >= 2) +- printf ("supermin: rpm: pkg_filelist: %d occurrences for '%s'\n", count, String_val (pkgv)); ++ if (data.debug >= 2) { ++ printf ("supermin: rpm: pkg_filelist: %d occurrences for '%s'\n", ++ count, String_val (pkgv)); ++ fflush (stdout); ++ } + if (count != 1) + librpm_raise_multiple_matches (count); + +-- +2.5.0 + diff --git a/0007-rpm-Choose-providers-better-RHBZ-1266918.patch b/0007-rpm-Choose-providers-better-RHBZ-1266918.patch new file mode 100644 index 0000000..f7b4769 --- /dev/null +++ b/0007-rpm-Choose-providers-better-RHBZ-1266918.patch @@ -0,0 +1,123 @@ +From 17b724b5d345f5e9d622bcadf27c57baa102bbba Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 13 Oct 2015 13:42:57 +0100 +Subject: [PATCH 7/7] rpm: Choose providers better (RHBZ#1266918). + +In the referenced bug, a customer had installed a web browser called +'palemoon'. The RPM of this web browser provides and requires various +core libraries, such as: + + Provides: libnss3.so()(64bit) # normally provided by 'nss' + Requires: libxul.so()(64bit) # normally provided by 'firefox' + +Our previous algorithm -- inherited from the days when we used to run +'rpm' commands -- takes every provider of a particular requirement and +adds it to a big list, so if any other package requires +'libnss3.so()(64bit)', then both 'nss' and 'palemoon' are added to the +package list. + +Yum used to handle this differently - it used to only pick the package +with the shortest name. Later on, before yum was retired, it had a +more complex decision algorithm described here: +http://yum.baseurl.org/wiki/CompareProviders + +This change makes supermin use the shortest name algorithm, so in the +case above, it always picks 'nss' over 'palemoon'. + +There is a second possible problem which is not fixed by the current +patch set: If a package both provides and requires the same +dependency, we should ignore that dependency. For example, 'palemoon' +both Provides and Requires 'libxul.so()(64bit)', so if 'palemoon' is +pulled in, then 'firefox' would not be an additional requirement. +Because we store all the packages in a big list, we lose track of +where a dependency originates from, so it is not easy to implement +this second change. +--- + src/rpm.ml | 64 ++++++++++++++++++++++++++++++++++++++++++++++---------------- + 1 file changed, 48 insertions(+), 16 deletions(-) + +diff --git a/src/rpm.ml b/src/rpm.ml +index 4d31472..1db47b6 100644 +--- a/src/rpm.ml ++++ b/src/rpm.ml +@@ -210,8 +210,51 @@ let rpm_package_name pkg = + let rpm_get_package_database_mtime () = + (lstat "/var/lib/rpm/Packages").st_mtime + +-(* Memo of resolved provides. *) +-let rpm_providers = Hashtbl.create 13 ++(* Return the best provider of a particular RPM requirement. ++ * ++ * There may be multiple, or no providers. In case there are multiple, ++ * choose the one with the shortest name (as yum used to). ++ * ++ * We could do better here: http://yum.baseurl.org/wiki/CompareProviders ++ *) ++let provider = ++ (* Memo of resolved provides. *) ++ let rpm_providers = Hashtbl.create 13 in ++ fun req -> ++ try Hashtbl.find rpm_providers req ++ with Not_found -> ++ let ret = ++ try ++ (* 'providers' here is an array of just package names. *) ++ let providers = rpm_pkg_whatprovides (get_rpm ()) req in ++ let providers = Array.to_list providers in ++ (* --whatprovides will return duplicate identical packages, so: *) ++ let providers = sort_uniq providers in ++ (* Only packages which are actually installed: *) ++ let providers = ++ List.filter (fun name -> rpm_package_of_string name <> None) ++ providers in ++ ++ match providers with ++ | [] -> None ++ | [name] -> ++ Some name ++ | names -> ++ if !settings.debug >= 2 then ++ printf "supermin: rpm: multiple providers: requirement %s: providers: %s\n" ++ req (String.concat " " names); ++ let cmp name1 name2 = ++ let len1 = String.length name1 and len2 = String.length name2 in ++ if len1 <> len2 then compare len1 len2 ++ else compare name1 name2 in ++ let names = List.sort cmp names in ++ let best_name = List.hd names in ++ if !settings.debug >= 2 then ++ printf "supermin: rpm: multiple providers: picked %s\n" best_name; ++ Some best_name ++ with Not_found -> None in ++ Hashtbl.add rpm_providers req ret; ++ ret + + let rpm_get_all_requires pkgs = + let get pkg = +@@ -226,20 +269,9 @@ let rpm_get_all_requires pkgs = + rpm_pkg_requires (get_rpm ()) (rpm_package_to_string pkg) in + let pkgs' = Array.fold_left ( + fun set x -> +- try +- let provides = +- try Hashtbl.find rpm_providers x +- with Not_found -> +- let p = rpm_pkg_whatprovides (get_rpm ()) x in +- Hashtbl.add rpm_providers x p; +- p in +- Array.fold_left ( +- fun newset p -> +- match rpm_package_of_string p with +- | None -> newset +- | Some x -> StringSet.add p newset +- ) set provides +- with Not_found -> set ++ match provider x with ++ | None -> set ++ | Some p -> StringSet.add p set + ) StringSet.empty reqs in + pkgs' + in +-- +2.5.0 + diff --git a/supermin.spec b/supermin.spec index 9e1f879..78e7f66 100644 --- a/supermin.spec +++ b/supermin.spec @@ -6,7 +6,7 @@ Summary: Tool for creating supermin appliances Name: supermin Version: 5.1.13 -Release: 3%{?dist} +Release: 4%{?dist} License: GPLv2+ %if 0%{?rhel} >= 7 @@ -16,6 +16,15 @@ ExclusiveArch: x86_64 URL: http://people.redhat.com/~rjones/supermin/ Source0: http://libguestfs.org/download/supermin/%{name}-%{version}.tar.gz +# All upstream patches since 5.1.13. +Patch0001: 0001-utils-import-parse_size-from-libguestfs.patch +Patch0002: 0002-Add-size-for-ext2-filesystem.patch +Patch0003: 0003-docs-Use-F-for-filenames-instead-of-C.patch +Patch0004: 0004-rpm-rpm_is_available-function-can-be-noalloc.patch +Patch0005: 0005-rpm-Add-some-documentation-to-librpm.mli.patch +Patch0006: 0006-rpm-Flush-debugging-messages-in-C-code.patch +Patch0007: 0007-rpm-Choose-providers-better-RHBZ-1266918.patch + BuildRequires: /usr/bin/pod2man BuildRequires: rpm BuildRequires: rpm-devel @@ -85,6 +94,7 @@ from supermin appliances. %prep %setup -q +%autopatch -p1 %build @@ -128,6 +138,11 @@ make check || { %changelog +* Tue Oct 13 2015 Richard W.M. Jones - 5.1.13-4 +- Pull in all upstream patches since 5.1.13. +- Choose providers better (RHBZ#1266918). +- Use autopatch. + * Mon Jul 27 2015 Richard W.M. Jones - 5.1.13-3 - Bump version to rebuild against new RPM in Rawhide.