From 7496f55fd4a7dd8604fcc324153dcf37ab69e5c1 Mon Sep 17 00:00:00 2001 From: Richard W.M. Jones Date: Mar 31 2021 15:32:48 +0000 Subject: Switch from genisoimage to xorriso. (cherry picked from commit 928729ea6e48c4114b7721013e772595604a0b6b) --- diff --git a/0001-daemon-xfs.c-Fix-error-message.patch b/0001-daemon-xfs.c-Fix-error-message.patch new file mode 100644 index 0000000..4174452 --- /dev/null +++ b/0001-daemon-xfs.c-Fix-error-message.patch @@ -0,0 +1,35 @@ +From 49b8b69cb8e10e5476bbe86a708ee1babfe330e8 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 30 Mar 2021 12:56:06 +0100 +Subject: [PATCH 1/3] daemon/xfs.c: Fix error message. + +Fixes: commit 87206e4e9e3b0ca813a4ff7b5fac0eccc07a484a +--- + daemon/xfs.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/daemon/xfs.c b/daemon/xfs.c +index 3707f56d9..aa056ddff 100644 +--- a/daemon/xfs.c ++++ b/daemon/xfs.c +@@ -62,7 +62,7 @@ parse_uint32 (uint32_t *ret, const char *str) + uint32_t r; + + if (sscanf (str, "%" SCNu32, &r) != 1) { +- reply_with_error ("cannot parse numeric field from isoinfo: %s", str); ++ reply_with_error ("cannot parse numeric field from xfs_info: %s", str); + return -1; + } + +@@ -76,7 +76,7 @@ parse_uint64 (uint64_t *ret, const char *str) + uint64_t r; + + if (sscanf (str, "%" SCNu64, &r) != 1) { +- reply_with_error ("cannot parse numeric field from isoinfo: %s", str); ++ reply_with_error ("cannot parse numeric field from xfs_info: %s", str); + return -1; + } + +-- +2.29.0.rc2 + diff --git a/0002-tests-Prefer-xorriso-over-genisoimage-to-generate-te.patch b/0002-tests-Prefer-xorriso-over-genisoimage-to-generate-te.patch new file mode 100644 index 0000000..d5aac41 --- /dev/null +++ b/0002-tests-Prefer-xorriso-over-genisoimage-to-generate-te.patch @@ -0,0 +1,67 @@ +From 2216ab2e328457ef172d6bfa534272edf2f81a3a Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 30 Mar 2021 12:41:58 +0100 +Subject: [PATCH 2/3] tests: Prefer xorriso over genisoimage to generate + test.iso + +This Debian page explains the upstream situation: +https://wiki.debian.org/genisoimage + +On Fedora, xorriso provides a compatibility program called "mkisofs". +However this is not present in Debian. Hence the choice to look for +the program called "xorrisofs". +--- + docs/guestfs-building.pod | 4 ++-- + m4/guestfs-progs.m4 | 6 +++--- + test-data/Makefile.am | 2 +- + 3 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/docs/guestfs-building.pod b/docs/guestfs-building.pod +index 8fb2361b2..4d0e943cb 100644 +--- a/docs/guestfs-building.pod ++++ b/docs/guestfs-building.pod +@@ -152,9 +152,9 @@ I. + + I. + +-=item genisoimage ++=item xorriso, genisoimage or mkisofs + +-I. ++One of these is I. + + =item libxml2 + +diff --git a/m4/guestfs-progs.m4 b/m4/guestfs-progs.m4 +index 4819df627..cd8662e86 100644 +--- a/m4/guestfs-progs.m4 ++++ b/m4/guestfs-progs.m4 +@@ -49,10 +49,10 @@ AC_CHECK_PROG([GPERF],[gperf],[gperf],[no]) + test "x$GPERF" = "xno" && + AC_MSG_ERROR([gperf must be installed]) + +-dnl Check for genisoimage/mkisofs +-AC_PATH_PROGS([GENISOIMAGE],[genisoimage mkisofs],[no], ++dnl Check for xorriso/genisoimage/mkisofs. ++AC_PATH_PROGS([MKISOFS],[xorrisofs genisoimage mkisofs],[no], + [$PATH$PATH_SEPARATOR/usr/sbin$PATH_SEPARATOR/sbin]) +-test "x$GENISOIMAGE" = "xno" && AC_MSG_ERROR([genisoimage must be installed]) ++test "x$MKISOFS" = "xno" && AC_MSG_ERROR([xorriso or genisoimage or mkisofs must be installed]) + + dnl Check for optional xmllint. + AC_CHECK_PROG([XMLLINT],[xmllint],[xmllint],[no]) +diff --git a/test-data/Makefile.am b/test-data/Makefile.am +index 8a832c94c..b603311a1 100644 +--- a/test-data/Makefile.am ++++ b/test-data/Makefile.am +@@ -98,6 +98,6 @@ test.iso: $(images_files) + cp $(image_files) d/ + mkdir -p d/directory + cd d && ln -sf /10klines abssymlink +- cd d && $(GENISOIMAGE) -J -r -o ../$@-t . ++ cd d && $(MKISOFS) -J -r -o ../$@-t . + rm -rf d + mv $@-t $@ +-- +2.29.0.rc2 + diff --git a/0003-daemon-Allow-xorriso-as-an-alternative-to-isoinfo.patch b/0003-daemon-Allow-xorriso-as-an-alternative-to-isoinfo.patch new file mode 100644 index 0000000..8f03f0a --- /dev/null +++ b/0003-daemon-Allow-xorriso-as-an-alternative-to-isoinfo.patch @@ -0,0 +1,684 @@ +From efb8a766cac4ba8e413594946136bf91e176bb8c Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 30 Mar 2021 13:54:22 +0100 +Subject: [PATCH 3/3] daemon: Allow xorriso as an alternative to isoinfo. + +Currently the guestfs_isoinfo and guestfs_isoinfo_device APIs run +isoinfo inside the appliance to extract the information. + +isoinfo is part of genisoimage which is somewhat dead upstream. +xorriso is supposedly the new thing. (For a summary of the situation +see: https://wiki.debian.org/genisoimage). + +This commit rewrites the parsing from C to OCaml to make it easier to +deal with, and allows you to use either isoinfo or xorriso. + +Mostly the same fields are available from either tool, but xorriso is +a bit more awkward to parse. +--- + .gitignore | 1 + + appliance/packagelist.in | 2 + + daemon/Makefile.am | 4 +- + daemon/isoinfo.c | 279 -------------------------------------- + daemon/isoinfo.ml | 248 +++++++++++++++++++++++++++++++++ + docs/C_SOURCE_FILES | 1 - + generator/actions_core.ml | 2 + + po/POTFILES | 1 - + 8 files changed, 256 insertions(+), 282 deletions(-) + delete mode 100644 daemon/isoinfo.c + create mode 100644 daemon/isoinfo.ml + +diff --git a/.gitignore b/.gitignore +index f9b95a6c5..de4abff58 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -92,6 +92,7 @@ Makefile.in + /daemon/guestfsd.exe + /daemon/inspect.mli + /daemon/is.mli ++/daemon/isoinfo.mli + /daemon/ldm.mli + /daemon/link.mli + /daemon/listfs.mli +diff --git a/appliance/packagelist.in b/appliance/packagelist.in +index 2f75a1c17..f4ad50b79 100644 +--- a/appliance/packagelist.in ++++ b/appliance/packagelist.in +@@ -45,6 +45,7 @@ ifelse(REDHAT,1, + syslinux-extlinux + systemd dnl for /sbin/reboot and udevd + vim-minimal ++ xorriso dnl alternative for genisoimage + xz + zfs-fuse + ) +@@ -84,6 +85,7 @@ dnl iproute has been renamed to iproute2 + systemd dnl alternative for /sbin/reboot + ufsutils + vim-tiny ++ xorriso dnl alternative for genisoimage + xz-utils + zfs-fuse + uuid-runtime +diff --git a/daemon/Makefile.am b/daemon/Makefile.am +index 216029b7c..6f13bd43c 100644 +--- a/daemon/Makefile.am ++++ b/daemon/Makefile.am +@@ -46,6 +46,7 @@ generator_built = \ + findfs.mli \ + inspect.mli \ + is.mli \ ++ isoinfo.mli \ + ldm.mli \ + link.mli \ + listfs.mli \ +@@ -142,7 +143,6 @@ guestfsd_SOURCES = \ + inotify.c \ + internal.c \ + is.c \ +- isoinfo.c \ + journal.c \ + labels.c \ + ldm.c \ +@@ -291,6 +291,7 @@ SOURCES_MLI = \ + inspect_types.mli \ + inspect_utils.mli \ + is.mli \ ++ isoinfo.mli \ + ldm.mli \ + link.mli \ + listfs.mli \ +@@ -324,6 +325,7 @@ SOURCES_ML = \ + devsparts.ml \ + file.ml \ + filearch.ml \ ++ isoinfo.ml \ + is.ml \ + ldm.ml \ + link.ml \ +diff --git a/daemon/isoinfo.c b/daemon/isoinfo.c +deleted file mode 100644 +index e616df82f..000000000 +--- a/daemon/isoinfo.c ++++ /dev/null +@@ -1,279 +0,0 @@ +-/* libguestfs - the guestfsd daemon +- * Copyright (C) 2012 Red Hat Inc. +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +- */ +- +-#include +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "guestfs_protocol.h" +-#include "daemon.h" +-#include "actions.h" +- +-static int +-parse_uint32 (uint32_t *ret, const char *str) +-{ +- uint32_t r; +- +- if (sscanf (str, "%" SCNu32, &r) != 1) { +- reply_with_error ("cannot parse numeric field from isoinfo: %s", str); +- return -1; +- } +- +- *ret = r; +- return 0; +-} +- +-/* This is always in a fixed format: +- * "2012 03 16 11:05:46.00" +- * or if the field is not present, then: +- * "0000 00 00 00:00:00.00" +- */ +-static int +-parse_time_t (int64_t *ret, const char *str) +-{ +- struct tm tm; +- time_t r; +- +- if (STREQ (str, "0000 00 00 00:00:00.00") || +- STREQ (str, " : : . ")) { +- *ret = -1; +- return 0; +- } +- +- if (sscanf (str, "%04d %02d %02d %02d:%02d:%02d", +- &tm.tm_year, &tm.tm_mon, &tm.tm_mday, +- &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) { +- reply_with_error ("cannot parse date from isoinfo: %s", str); +- return -1; +- } +- +- /* Adjust fields. */ +- tm.tm_year -= 1900; +- tm.tm_mon--; +- tm.tm_isdst = -1; +- +- /* Convert to time_t. */ +- r = timegm (&tm); +- if (r == -1) { +- reply_with_error ("invalid date or time: %s", str); +- return -1; +- } +- +- *ret = r; +- return 0; +-} +- +-static guestfs_int_isoinfo * +-parse_isoinfo (char **lines) +-{ +- guestfs_int_isoinfo *ret; +- size_t i; +- +- ret = calloc (1, sizeof *ret); +- if (ret == NULL) { +- reply_with_perror ("calloc"); +- return NULL; +- } +- +- /* Default each int field in the struct to -1. */ +- ret->iso_volume_space_size = (uint32_t) -1; +- ret->iso_volume_set_size = (uint32_t) -1; +- ret->iso_volume_sequence_number = (uint32_t) -1; +- ret->iso_logical_block_size = (uint32_t) -1; +- ret->iso_volume_creation_t = -1; +- ret->iso_volume_modification_t = -1; +- ret->iso_volume_expiration_t = -1; +- ret->iso_volume_effective_t = -1; +- +- for (i = 0; lines[i] != NULL; ++i) { +- if (STRPREFIX (lines[i], "System id: ")) { +- ret->iso_system_id = strdup (&lines[i][11]); +- if (ret->iso_system_id == NULL) goto error; +- } +- else if (STRPREFIX (lines[i], "Volume id: ")) { +- ret->iso_volume_id = strdup (&lines[i][11]); +- if (ret->iso_volume_id == NULL) goto error; +- } +- else if (STRPREFIX (lines[i], "Volume set id: ")) { +- ret->iso_volume_set_id = strdup (&lines[i][15]); +- if (ret->iso_volume_set_id == NULL) goto error; +- } +- else if (STRPREFIX (lines[i], "Publisher id: ")) { +- ret->iso_publisher_id = strdup (&lines[i][14]); +- if (ret->iso_publisher_id == NULL) goto error; +- } +- else if (STRPREFIX (lines[i], "Data preparer id: ")) { +- ret->iso_data_preparer_id = strdup (&lines[i][18]); +- if (ret->iso_data_preparer_id == NULL) goto error; +- } +- else if (STRPREFIX (lines[i], "Application id: ")) { +- ret->iso_application_id = strdup (&lines[i][16]); +- if (ret->iso_application_id == NULL) goto error; +- } +- else if (STRPREFIX (lines[i], "Copyright File id: ")) { +- ret->iso_copyright_file_id = strdup (&lines[i][19]); +- if (ret->iso_copyright_file_id == NULL) goto error; +- } +- else if (STRPREFIX (lines[i], "Abstract File id: ")) { +- ret->iso_abstract_file_id = strdup (&lines[i][18]); +- if (ret->iso_abstract_file_id == NULL) goto error; +- } +- else if (STRPREFIX (lines[i], "Bibliographic File id: ")) { +- ret->iso_bibliographic_file_id = strdup (&lines[i][23]); +- if (ret->iso_bibliographic_file_id == NULL) goto error; +- } +- else if (STRPREFIX (lines[i], "Volume size is: ")) { +- if (parse_uint32 (&ret->iso_volume_space_size, &lines[i][16]) == -1) +- goto error; +- } +- else if (STRPREFIX (lines[i], "Volume set size is: ")) { +- if (parse_uint32 (&ret->iso_volume_set_size, &lines[i][20]) == -1) +- goto error; +- } +- else if (STRPREFIX (lines[i], "Volume set sequence number is: ")) { +- if (parse_uint32 (&ret->iso_volume_sequence_number, &lines[i][31]) == -1) +- goto error; +- } +- else if (STRPREFIX (lines[i], "Logical block size is: ")) { +- if (parse_uint32 (&ret->iso_logical_block_size, &lines[i][23]) == -1) +- goto error; +- } +- else if (STRPREFIX (lines[i], "Creation Date: ")) { +- if (parse_time_t (&ret->iso_volume_creation_t, &lines[i][19]) == -1) +- goto error; +- } +- else if (STRPREFIX (lines[i], "Modification Date: ")) { +- if (parse_time_t (&ret->iso_volume_modification_t, &lines[i][19]) == -1) +- goto error; +- } +- else if (STRPREFIX (lines[i], "Expiration Date: ")) { +- if (parse_time_t (&ret->iso_volume_expiration_t, &lines[i][19]) == -1) +- goto error; +- } +- else if (STRPREFIX (lines[i], "Effective Date: ")) { +- if (parse_time_t (&ret->iso_volume_effective_t, &lines[i][19]) == -1) +- goto error; +- } +- } +- +- /* Any string fields which were not set above will be NULL. However +- * we cannot return NULL fields in structs, so we convert these to +- * empty strings here. +- */ +- if (ret->iso_system_id == NULL) { +- ret->iso_system_id = strdup (""); +- if (ret->iso_system_id == NULL) goto error; +- } +- if (ret->iso_volume_id == NULL) { +- ret->iso_volume_id = strdup (""); +- if (ret->iso_volume_id == NULL) goto error; +- } +- if (ret->iso_volume_set_id == NULL) { +- ret->iso_volume_set_id = strdup (""); +- if (ret->iso_volume_set_id == NULL) goto error; +- } +- if (ret->iso_publisher_id == NULL) { +- ret->iso_publisher_id = strdup (""); +- if (ret->iso_publisher_id == NULL) goto error; +- } +- if (ret->iso_data_preparer_id == NULL) { +- ret->iso_data_preparer_id = strdup (""); +- if (ret->iso_data_preparer_id == NULL) goto error; +- } +- if (ret->iso_application_id == NULL) { +- ret->iso_application_id = strdup (""); +- if (ret->iso_application_id == NULL) goto error; +- } +- if (ret->iso_copyright_file_id == NULL) { +- ret->iso_copyright_file_id = strdup (""); +- if (ret->iso_copyright_file_id == NULL) goto error; +- } +- if (ret->iso_abstract_file_id == NULL) { +- ret->iso_abstract_file_id = strdup (""); +- if (ret->iso_abstract_file_id == NULL) goto error; +- } +- if (ret->iso_bibliographic_file_id == NULL) { +- ret->iso_bibliographic_file_id = strdup (""); +- if (ret->iso_bibliographic_file_id == NULL) goto error; +- } +- +- return ret; +- +- error: +- free (ret->iso_system_id); +- free (ret->iso_volume_id); +- free (ret->iso_volume_set_id); +- free (ret->iso_publisher_id); +- free (ret->iso_data_preparer_id); +- free (ret->iso_application_id); +- free (ret->iso_copyright_file_id); +- free (ret->iso_abstract_file_id); +- free (ret->iso_bibliographic_file_id); +- free (ret); +- return NULL; +-} +- +-static guestfs_int_isoinfo * +-isoinfo (const char *path) +-{ +- int r; +- CLEANUP_FREE char *out = NULL, *err = NULL; +- CLEANUP_FREE_STRING_LIST char **lines = NULL; +- +- /* --debug is necessary to get additional fields, in particular +- * the date & time fields. +- */ +- r = command (&out, &err, "isoinfo", "--debug", "-d", "-i", path, NULL); +- if (r == -1) { +- reply_with_error ("%s", err); +- return NULL; +- } +- +- lines = split_lines (out); +- if (lines == NULL) +- return NULL; +- +- return parse_isoinfo (lines); +-} +- +-guestfs_int_isoinfo * +-do_isoinfo_device (const char *device) +-{ +- return isoinfo (device); +-} +- +-guestfs_int_isoinfo * +-do_isoinfo (const char *path) +-{ +- guestfs_int_isoinfo *ret; +- CLEANUP_FREE char *buf = sysroot_path (path); +- if (!buf) { +- reply_with_perror ("malloc"); +- return NULL; +- } +- +- ret = isoinfo (buf); +- +- return ret; +-} +diff --git a/daemon/isoinfo.ml b/daemon/isoinfo.ml +new file mode 100644 +index 000000000..b7fe0af7e +--- /dev/null ++++ b/daemon/isoinfo.ml +@@ -0,0 +1,248 @@ ++(* Parse isoinfo or xorriso output. ++ * Copyright (C) 2009-2021 Red Hat Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ *) ++ ++open Printf ++open Scanf ++open Unix ++ ++open Std_utils ++open Unix_utils ++ ++open Mountable ++open Utils ++ ++include Structs ++ ++type tool = Isoinfo | Xorriso ++let tool = ref None ++ ++let get_tool () = ++ match !tool with ++ | Some t -> t ++ | None -> ++ (* Prefer isoinfo because we've been using that tool for longer. *) ++ if Sys.command "isoinfo -version" = 0 then ( ++ tool := Some Isoinfo; ++ Isoinfo ++ ) ++ else if Sys.command "xorriso -version" = 0 then ( ++ tool := Some Xorriso; ++ Xorriso ++ ) ++ else ++ failwith "isoinfo or xorriso not available" ++ ++(* Default each int field in the struct to -1 and each string to "". *) ++let default_iso = { ++ iso_system_id = ""; ++ iso_volume_id = ""; ++ iso_volume_space_size = -1_l; ++ iso_volume_set_size = -1_l; ++ iso_volume_sequence_number = -1_l; ++ (* This is almost always true for CDs because of the media itself, ++ * and is not available from xorriso. ++ *) ++ iso_logical_block_size = 2048_l; ++ iso_volume_set_id = ""; ++ iso_publisher_id = ""; ++ iso_data_preparer_id = ""; ++ iso_application_id = ""; ++ iso_copyright_file_id = ""; ++ iso_abstract_file_id = ""; ++ iso_bibliographic_file_id = ""; ++ iso_volume_creation_t = -1_L; ++ iso_volume_modification_t = -1_L; ++ iso_volume_expiration_t = -1_L; ++ iso_volume_effective_t = -1_L; ++} ++ ++(* This is always in a fixed format: ++ * "2012 03 16 11:05:46.00" ++ * or if the field is not present, then: ++ * "0000 00 00 00:00:00.00" ++ *) ++let parse_isoinfo_date str = ++ if str = "0000 00 00 00:00:00.00" || ++ str = " : : . " then ++ -1_L ++ else ( ++ sscanf str "%04d %02d %02d %02d:%02d:%02d" ++ (fun tm_year tm_mon tm_mday tm_hour tm_min tm_sec -> ++ (* Adjust fields. *) ++ let tm_year = tm_year - 1900 in ++ let tm_mon = tm_mon - 1 in ++ ++ (* Convert to time_t *) ++ let tm = { tm_sec; tm_min; tm_hour; tm_mday; tm_mon; tm_year; ++ tm_wday = -1; tm_yday = -1; tm_isdst = false } in ++ Int64.of_float (fst (Unix.mktime tm)) ++ ) ++ ) ++ ++let do_isoinfo dev = ++ (* --debug is necessary to get additional fields, in particular ++ * the date & time fields. ++ *) ++ let lines = command "isoinfo" ["--debug"; "-d"; "-i"; dev] in ++ let lines = String.nsplit "\n" lines in ++ ++ let ret = ref default_iso in ++ List.iter ( ++ fun line -> ++ let n = String.length line in ++ if String.is_prefix line "System id: " then ++ ret := { !ret with iso_system_id = String.sub line 11 (n-11) } ++ else if String.is_prefix line "Volume id: " then ++ ret := { !ret with iso_volume_id = String.sub line 11 (n-11) } ++ else if String.is_prefix line "Volume set id: " then ++ ret := { !ret with iso_volume_set_id = String.sub line 15 (n-15) } ++ else if String.is_prefix line "Publisher id: " then ++ ret := { !ret with iso_publisher_id = String.sub line 14 (n-14) } ++ else if String.is_prefix line "Data preparer id: " then ++ ret := { !ret with iso_data_preparer_id = String.sub line 18 (n-18) } ++ else if String.is_prefix line "Application id: " then ++ ret := { !ret with iso_application_id = String.sub line 16 (n-16) } ++ else if String.is_prefix line "Copyright File id: " then ++ ret := { !ret with iso_copyright_file_id = String.sub line 19 (n-19) } ++ else if String.is_prefix line "Abstract File id: " then ++ ret := { !ret with iso_abstract_file_id = String.sub line 18 (n-18) } ++ else if String.is_prefix line "Bibliographic File id: " then ++ ret := { !ret with ++ iso_bibliographic_file_id = String.sub line 23 (n-23) } ++ else if String.is_prefix line "Volume size is: " then ( ++ let i = Int32.of_string (String.sub line 16 (n-16)) in ++ ret := { !ret with iso_volume_space_size = i } ++ ) ++ else if String.is_prefix line "Volume set size is: " then ( ++ let i = Int32.of_string (String.sub line 20 (n-20)) in ++ ret := { !ret with iso_volume_set_size = i } ++ ) ++ else if String.is_prefix line "Volume set sequence number is: " then ( ++ let i = Int32.of_string (String.sub line 31 (n-31)) in ++ ret := { !ret with iso_volume_sequence_number = i } ++ ) ++ else if String.is_prefix line "Logical block size is: " then ( ++ let i = Int32.of_string (String.sub line 23 (n-23)) in ++ ret := { !ret with iso_logical_block_size = i } ++ ) ++ else if String.is_prefix line "Creation Date: " then ( ++ let t = parse_isoinfo_date (String.sub line 19 (n-19)) in ++ ret := { !ret with iso_volume_creation_t = t } ++ ) ++ else if String.is_prefix line "Modification Date: " then ( ++ let t = parse_isoinfo_date (String.sub line 19 (n-19)) in ++ ret := { !ret with iso_volume_modification_t = t } ++ ) ++ else if String.is_prefix line "Expiration Date: " then ( ++ let t = parse_isoinfo_date (String.sub line 19 (n-19)) in ++ ret := { !ret with iso_volume_expiration_t = t } ++ ) ++ else if String.is_prefix line "Effective Date: " then ( ++ let t = parse_isoinfo_date (String.sub line 19 (n-19)) in ++ ret := { !ret with iso_volume_effective_t = t } ++ ) ++ ) lines; ++ !ret ++ ++(* This is always in a fixed format: ++ * "2021033012313200" ++ * or if the field is not present, then: ++ * "0000000000000000" ++ * XXX Parse the time zone fields too. ++ *) ++let parse_xorriso_date str = ++ if str = "0000000000000000" then -1_L ++ else if String.length str <> 16 then -1_L ++ else ( ++ let tm_year = int_of_string (String.sub str 0 4) in ++ let tm_mon = int_of_string (String.sub str 4 2) in ++ let tm_mday = int_of_string (String.sub str 6 2) in ++ let tm_hour = int_of_string (String.sub str 8 2) in ++ let tm_min = int_of_string (String.sub str 10 2) in ++ let tm_sec = int_of_string (String.sub str 12 2) in ++ ++ (* Adjust fields. *) ++ let tm_year = tm_year - 1900 in ++ let tm_mon = tm_mon - 1 in ++ ++ (* Convert to time_t *) ++ let tm = { tm_sec; tm_min; tm_hour; tm_mday; tm_mon; tm_year; ++ tm_wday = -1; tm_yday = -1; tm_isdst = false } in ++ Int64.of_float (fst (Unix.mktime tm)) ++ ) ++ ++let do_xorriso dev = ++ (* stdio: prefix is to work around a stupidity of xorriso. *) ++ let lines = command "xorriso" ["-indev"; "stdio:" ^ dev; "-pvd_info"] in ++ let lines = String.nsplit "\n" lines in ++ ++ let ret = ref default_iso in ++ List.iter ( ++ fun line -> ++ let n = String.length line in ++ if String.is_prefix line "System Id : " then ++ ret := { !ret with iso_system_id = String.sub line 15 (n-15) } ++ else if String.is_prefix line "Volume Id : " then ++ ret := { !ret with iso_volume_id = String.sub line 15 (n-15) } ++ else if String.is_prefix line "Volume Set Id: " then ++ ret := { !ret with iso_volume_set_id = String.sub line 15 (n-15) } ++ else if String.is_prefix line "Publisher Id : " then ++ ret := { !ret with iso_publisher_id = String.sub line 15 (n-15) } ++ else if String.is_prefix line "App Id : " then ++ ret := { !ret with iso_application_id = String.sub line 15 (n-15) } ++ else if String.is_prefix line "CopyrightFile: " then ++ ret := { !ret with iso_copyright_file_id = String.sub line 15 (n-15) } ++ else if String.is_prefix line "Abstract File: " then ++ ret := { !ret with iso_abstract_file_id = String.sub line 15 (n-15) } ++ else if String.is_prefix line "Biblio File : " then ++ ret := { !ret with ++ iso_bibliographic_file_id = String.sub line 15 (n-15) } ++ (* XXX The following fields don't appear to be available ++ * with xorriso: ++ * - iso_volume_space_size (only available on stderr) ++ * - iso_volume_sequence_number ++ * - iso_logical_block_size ++ *) ++ (* XXX xorriso provides a timezone for these fields, but ++ * we don't use it here. ++ *) ++ else if String.is_prefix line "Creation Time: " then ( ++ let t = parse_xorriso_date (String.sub line 15 (n-15)) in ++ ret := { !ret with iso_volume_creation_t = t } ++ ) ++ else if String.is_prefix line "Modif. Time : " then ( ++ let t = parse_xorriso_date (String.sub line 15 (n-15)) in ++ ret := { !ret with iso_volume_modification_t = t } ++ ) ++ else if String.is_prefix line "Expir. Time : " then ( ++ let t = parse_xorriso_date (String.sub line 15 (n-15)) in ++ ret := { !ret with iso_volume_expiration_t = t } ++ ) ++ else if String.is_prefix line "Eff. Time : " then ( ++ let t = parse_xorriso_date (String.sub line 15 (n-15)) in ++ ret := { !ret with iso_volume_effective_t = t } ++ ) ++ ) lines; ++ !ret ++ ++let isoinfo dev = ++ match get_tool () with ++ | Isoinfo -> do_isoinfo dev ++ | Xorriso -> do_xorriso dev ++ ++let isoinfo_device = isoinfo +diff --git a/docs/C_SOURCE_FILES b/docs/C_SOURCE_FILES +index 060be051b..e65c2f9d9 100644 +--- a/docs/C_SOURCE_FILES ++++ b/docs/C_SOURCE_FILES +@@ -103,7 +103,6 @@ daemon/initrd.c + daemon/inotify.c + daemon/internal.c + daemon/is.c +-daemon/isoinfo.c + daemon/journal.c + daemon/labels.c + daemon/ldm.c +diff --git a/generator/actions_core.ml b/generator/actions_core.ml +index bb92ef2ca..40505d8b5 100644 +--- a/generator/actions_core.ml ++++ b/generator/actions_core.ml +@@ -6878,6 +6878,7 @@ this will create the largest possible LV." }; + { defaults with + name = "isoinfo_device"; added = (1, 17, 19); + style = RStruct ("isodata", "isoinfo"), [String (Device, "device")], []; ++ impl = OCaml "Isoinfo.isoinfo_device"; + tests = [ + InitNone, Always, TestResult ( + [["isoinfo_device"; "/dev/sdd"]], +@@ -6904,6 +6905,7 @@ L" }; + { defaults with + name = "isoinfo"; added = (1, 17, 19); + style = RStruct ("isodata", "isoinfo"), [String (Pathname, "isofile")], []; ++ impl = OCaml "Isoinfo.isoinfo"; + shortdesc = "get ISO information from primary volume descriptor of ISO file"; + longdesc = "\ + This is the same as C except that it +diff --git a/po/POTFILES b/po/POTFILES +index c5f4e6aa7..717579d56 100644 +--- a/po/POTFILES ++++ b/po/POTFILES +@@ -82,7 +82,6 @@ daemon/initrd.c + daemon/inotify.c + daemon/internal.c + daemon/is.c +-daemon/isoinfo.c + daemon/journal.c + daemon/labels.c + daemon/ldm.c +-- +2.29.0.rc2 + diff --git a/libguestfs.spec b/libguestfs.spec index 50ceb37..a423087 100644 --- a/libguestfs.spec +++ b/libguestfs.spec @@ -42,7 +42,7 @@ # If there are patches which touch autotools files, set this to 1. %if !0%{?rhel} -%global patches_touch_autotools %{nil} +%global patches_touch_autotools 1 %else # On RHEL the downstream patches always touch autotools files. %global patches_touch_autotools 1 @@ -61,7 +61,7 @@ Summary: Access and modify virtual machine disk images Name: libguestfs Epoch: 1 Version: 1.45.3 -Release: 3%{?dist} +Release: 4%{?dist} License: LGPLv2+ # Build only for architectures that have a kernel @@ -91,6 +91,11 @@ Source7: libguestfs.keyring # Maintainer script which helps with handling patches. Source8: copy-patches.sh +# Upstream patches since 1.45.3. +Patch0001: 0001-daemon-xfs.c-Fix-error-message.patch +Patch0002: 0002-tests-Prefer-xorriso-over-genisoimage-to-generate-te.patch +Patch0003: 0003-daemon-Allow-xorriso-as-an-alternative-to-isoinfo.patch + # Downstream (RHEL-only) patches. %if 0%{?rhel} Patch9001: 0001-RHEL-Remove-libguestfs-live-RHBZ-798980.patch @@ -123,7 +128,7 @@ BuildRequires: /usr/bin/pod2text BuildRequires: po4a BuildRequires: augeas-devel >= 1.7.0 BuildRequires: readline-devel -BuildRequires: genisoimage +BuildRequires: xorriso BuildRequires: libxml2-devel BuildRequires: createrepo_c BuildRequires: glibc-static @@ -240,7 +245,6 @@ BuildRequires: file BuildRequires: findutils BuildRequires: gawk BuildRequires: gdisk -BuildRequires: genisoimage %if !0%{?rhel} BuildRequires: gfs2-utils %endif @@ -303,6 +307,7 @@ BuildRequires: vim-minimal BuildRequires: which %endif BuildRequires: xfsprogs +BuildRequires: xorriso BuildRequires: xz BuildRequires: yajl %if !0%{?rhel} @@ -1126,8 +1131,9 @@ rm ocaml/html/.gitignore %changelog -* Tue Mar 30 2021 Richard W.M. Jones - 1:1.45.3-3 +* Tue Mar 30 2021 Richard W.M. Jones - 1:1.45.3-4 - Add downstream (RHEL-only) patches (RHBZ#1931724). +- Switch from genisoimage to xorriso. * Mon Mar 29 2021 Richard W.M. Jones - 1:1.45.3-2 - New upstream release 1.45.3.