[PATCH] sysprep: handle distro specific sysv scripts
by Olaf Hering
Currently firstboot would only work on redhat-based images.
Handle redhat-based, suse-based and debian guests, error out in case of an
unknown distro.
Update firstboot.sh:
- make sure scripts exists and can be executed
- add LSB header to avoid insserv warnings later on
- run script only if called with "start"
Update functions, pass only required options.
Signed-off-by: Olaf Hering <olaf(a)aepfle.de>
diff --git a/sysprep/firstboot.ml b/sysprep/firstboot.ml
index 97cd8a9..c5296a1 100644
--- a/sysprep/firstboot.ml
+++ b/sysprep/firstboot.ml
@@ -28,14 +28,35 @@ let firstboot_dir = "/usr/lib/virt-sysprep"
let firstboot_sh = sprintf "\
#!/bin/sh -
+### BEGIN INIT INFO
+# Provides: virt-sysprep
+# Required-Start: $null
+# Should-Start: $all
+# Required-Stop: $null
+# Should-Stop: $all
+# Default-Start: 2 3 5
+# Default-Stop: 0 1 6
+# Short-Description: Start scripts to run once at next boot
+# Description: Start scripts to run once at next boot
+# These scripts run the first time the guest boots,
+# and then are deleted. Output or errors from the scripts
+# are written to ~root/virt-sysprep-firstboot.log.
+### END INIT INFO
+
d=%s/scripts
logfile=~root/virt-sysprep-firstboot.log
-for f in $d/* ; do
- echo '=== Running' $f '===' >>$logfile
- $f >>$logfile 2>&1
- rm $f
-done
+if test \"$1\" = \"start\"
+then
+ for f in $d/* ; do
+ if test -x \"$f\"
+ then
+ echo '=== Running' $f '===' >>$logfile
+ $f >>$logfile 2>&1
+ rm -f $f
+ fi
+ done
+fi
" firstboot_dir
let firstboot_service = sprintf "\
@@ -56,7 +77,7 @@ WantedBy=default.target
let failed fs =
ksprintf (fun msg -> failwith (s_"firstboot: failed: " ^ msg)) fs
-let rec install_service g root =
+let rec install_service g distro =
g#mkdir_p firstboot_dir;
g#mkdir_p (sprintf "%s/scripts" firstboot_dir);
g#write (sprintf "%s/firstboot.sh" firstboot_dir) firstboot_sh;
@@ -64,18 +85,18 @@ let rec install_service g root =
(* systemd, else assume sysvinit *)
if g#is_dir "/etc/systemd" then
- install_systemd_service g root
+ install_systemd_service g
else
- install_sysvinit_service g root
+ install_sysvinit_service g distro
(* Install the systemd firstboot service, if not installed already. *)
-and install_systemd_service g root =
+and install_systemd_service g =
g#write (sprintf "%s/firstboot.service" firstboot_dir) firstboot_service;
g#mkdir_p "/etc/systemd/system/default.target.wants";
g#ln_sf (sprintf "%s/firstboot.service" firstboot_dir)
"/etc/systemd/system/default.target.wants"
-and install_sysvinit_service g root =
+and install_sysvinit_redhat g =
g#mkdir_p "/etc/rc.d/rc2.d";
g#mkdir_p "/etc/rc.d/rc3.d";
g#mkdir_p "/etc/rc.d/rc5.d";
@@ -86,12 +107,51 @@ and install_sysvinit_service g root =
g#ln_sf (sprintf "%s/firstboot.sh" firstboot_dir)
"/etc/rc.d/rc5.d/99virt-sysprep-firstboot"
+(* Make firstboot.sh look like a runlevel script to avoid insserv warnings. *)
+and install_sysvinit_suse g =
+ g#mkdir_p "/etc/init.d/rc2.d";
+ g#mkdir_p "/etc/init.d/rc3.d";
+ g#mkdir_p "/etc/init.d/rc5.d";
+ g#ln_sf (sprintf "%s/firstboot.sh" firstboot_dir)
+ "/etc/init.d/virt-sysprep-firstboot";
+ g#ln_sf "../virt-sysprep-firstboot"
+ "/etc/init.d/rc2.d/S99virt-sysprep-firstboot";
+ g#ln_sf "../virt-sysprep-firstboot"
+ "/etc/init.d/rc3.d/S99virt-sysprep-firstboot";
+ g#ln_sf "../virt-sysprep-firstboot"
+ "/etc/init.d/rc5.d/S99virt-sysprep-firstboot"
+
+and install_sysvinit_debian g =
+ g#mkdir_p "/etc/init.d";
+ g#mkdir_p "/etc/rc2.d";
+ g#mkdir_p "/etc/rc3.d";
+ g#mkdir_p "/etc/rc5.d";
+ g#ln_sf (sprintf "%s/firstboot.sh" firstboot_dir)
+ "/etc/init.d/virt-sysprep-firstboot";
+ g#ln_sf "/etc/init.d/virt-sysprep-firstboot"
+ "/etc/rc2.d/S99virt-sysprep-firstboot";
+ g#ln_sf "/etc/init.d/virt-sysprep-firstboot"
+ "/etc/rc3.d/S99virt-sysprep-firstboot";
+ g#ln_sf "/etc/init.d/virt-sysprep-firstboot"
+ "/etc/rc5.d/S99virt-sysprep-firstboot"
+
+and install_sysvinit_service g distro =
+ match distro with
+ | ("fedora"|"rhel"|"centos"|"scientificlinux"|"redhat-based") ->
+ install_sysvinit_redhat g
+ | ("opensuse"|"sles"|"suse-based") ->
+ install_sysvinit_suse g
+ | "debian" ->
+ install_sysvinit_debian g
+ | _ ->
+ failed "guest type %s is not supported" distro
+
let add_firstboot_script g root id content =
let typ = g#inspect_get_type root in
let distro = g#inspect_get_distro root in
match typ, distro with
| "linux", _ ->
- install_service g root;
+ install_service g distro;
let t = Int64.of_float (Unix.time ()) in
let r = string_random8 () in
let filename = sprintf "%s/scripts/%Ld-%s-%s" firstboot_dir t r id in
--
1.7.12
11 years
[PATCH] message catalogs don't need to be executable
by Hilko Bengen
---
po/Makefile.am | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/po/Makefile.am b/po/Makefile.am
index 141896a..f401a6f 100644
--- a/po/Makefile.am
+++ b/po/Makefile.am
@@ -97,7 +97,7 @@ install-data-hook: $(GMOFILES)
for lang in $(linguas); do \
d=$(DESTDIR)$(langinstdir)/$$lang/LC_MESSAGES; \
mkdir -p $$d; \
- install -m 0755 $$lang.gmo $$d/$(DOMAIN).mo; \
+ install -m 0644 $$lang.gmo $$d/$(DOMAIN).mo; \
done
.PRECIOUS: $(DOMAIN).pot $(POFILES)
--
1.7.10.4
12 years, 1 month
[PATCH v2 0/7] Add symbol versioning (now working).
by Richard W.M. Jones
This rather more complex patch series adds symbol versioning (7/7
shows it in action). This works for me, tested by running old and new
virt-inspector binaries against the new library.
Rich.
12 years, 1 month
[PATCH 1/2] sysprep: remove fontconfig cache
by Wanlong Gao
Remove the cache files generated by fontconfig.
Signed-off-by: Wanlong Gao <gaowanlong(a)cn.fujitsu.com>
---
sysprep/sysprep_operation_logfiles.ml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/sysprep/sysprep_operation_logfiles.ml b/sysprep/sysprep_operation_logfiles.ml
index a2b1585..1bca0dd 100644
--- a/sysprep/sysprep_operation_logfiles.ml
+++ b/sysprep/sysprep_operation_logfiles.ml
@@ -72,6 +72,9 @@ let globs = List.sort compare [
"/var/cache/gdm/*";
"/var/lib/AccountService/users/*";
"/var/lib/fprint/*"; (* Fingerprint service files *)
+
+ (* fontconfig caches *)
+ "/var/cache/fontconfig/*";
]
let globs_as_pod = String.concat "\n" (List.map ((^) " ") globs)
--
1.8.0
12 years, 1 month
[PATCH V2] virt-diff: add new virt-diff tool
by Wanlong Gao
add new virt-diff tool
Signed-off-by: Wanlong Gao <gaowanlong(a)cn.fujitsu.com>
---
Hi Rich,
It can work now, please give some comments. ;)
Cheers,
Wanlong Gao
cat/Makefile.am | 20 ++-
cat/virt-diff.c | 525 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
po/POTFILES | 1 +
3 files changed, 545 insertions(+), 1 deletion(-)
create mode 100644 cat/virt-diff.c
diff --git a/cat/Makefile.am b/cat/Makefile.am
index f7c763a..5f6a986 100644
--- a/cat/Makefile.am
+++ b/cat/Makefile.am
@@ -27,7 +27,7 @@ EXTRA_DIST = \
CLEANFILES = stamp-virt-cat.pod stamp-virt-ls.pod stamp-virt-filesystems.pod
-bin_PROGRAMS = virt-cat virt-filesystems virt-ls
+bin_PROGRAMS = virt-cat virt-filesystems virt-ls virt-diff
SHARED_SOURCE_FILES = \
../fish/config.c \
@@ -91,6 +91,24 @@ virt_ls_LDADD = \
$(top_builddir)/src/libguestfs.la \
../gnulib/lib/libgnu.la
+virt_diff_SOURCES = \
+ ../fish/keys.c \
+ virt-diff.c
+
+virt_diff_CFLAGS = \
+ -DGUESTFS_WARN_DEPRECATED=1 \
+ -I$(top_srcdir)/src -I$(top_builddir)/src \
+ -I$(top_srcdir)/fish \
+ -I$(srcdir)/../gnulib/lib -I../gnulib/lib \
+ -DLOCALEBASEDIR=\""$(datadir)/locale"\" \
+ $(WARN_CFLAGS) $(WERROR_CFLAGS) \
+ $(LIBCONFIG_CFLAGS)
+
+virt_diff_LDADD = \
+ $(LIBCONFIG_LIBS) \
+ $(top_builddir)/src/libguestfs.la \
+ ../gnulib/lib/libgnu.la
+
# Manual pages and HTML files for the website.
man_MANS = virt-cat.1 virt-filesystems.1 virt-ls.1
diff --git a/cat/virt-diff.c b/cat/virt-diff.c
new file mode 100644
index 0000000..c2c59a6
--- /dev/null
+++ b/cat/virt-diff.c
@@ -0,0 +1,525 @@
+/* virt-diff
+ * Copyright (C) 2012 Fujitsu Limited.
+ * 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 <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <termios.h>
+#include <string.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <assert.h>
+#include <time.h>
+#include <libintl.h>
+#include <sys/wait.h>
+
+#include "c-ctype.h"
+
+#include "human.h"
+#include "progname.h"
+
+#include "guestfs.h"
+#include "options.h"
+
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
+
+int keys_from_stdin = 0;
+int echo_keys = 0;
+/* libguestfs handle for seed. */
+static guestfs_h *sg;
+
+/* libguestfs handle for temp. */
+static guestfs_h *dg;
+
+const char *libvirt_uri = NULL;
+
+static inline char *
+diff_bad_case (char const *s)
+{
+ return (char *) s;
+}
+
+static void __attribute__((noreturn))
+diff_usage (int status)
+{
+ if (status != EXIT_SUCCESS) {
+ fprintf (stderr, _("Try `%s --help' for more information.\n"),
+ program_name);
+ } else {
+ fprintf (stdout,
+ _("%s: Show the differences between seed Guest and the others\n"
+ "Copyright (C) 2012 Fujitsu Limited.\n"
+ "Copyright (C) 2012 Red Hat Inc.\n"
+ "Usage:\n"
+ " %s [--options] -s domname -d domname path\n"
+ "Options:\n"
+ " -c|--connect uri Specify libvirt URI for -s and -d options\n"
+ " -s|--seed guest Add seed disk from libvirt guest\n"
+ " -d|--domain guest Add target disk from libvirt guest\n"
+ " --keys-from-stdin Read passphrases from stdin\n"
+ " --echo-keys Don't turn off echo for passphrases\n"
+ " --help Display brief help\n"),
+ program_name, program_name);
+ }
+ exit (status);
+}
+
+/* Make a LUKS map name from the partition name,
+ * eg "/dev/vda2" => "luksvda2"
+ */
+static void
+diff_make_mapname (const char *device, char *mapname, size_t len)
+{
+ size_t i = 0;
+
+ if (len < 5)
+ abort ();
+ strcpy (mapname, "luks");
+ mapname += 4;
+ len -= 4;
+
+ if (STRPREFIX (device, "/dev/"))
+ i = 5;
+
+ for (; device[i] != '\0' && len >= 1; ++i) {
+ if (c_isalnum (device[i])) {
+ *mapname++ = device[i];
+ len--;
+ }
+ }
+
+ *mapname = '\0';
+}
+
+static void
+free_strings (char **strings)
+{
+ size_t i;
+
+ for (i = 0; strings[i] != NULL; ++i)
+ free (strings[i]);
+ free (strings);
+}
+
+static size_t
+count_strings (char **strings)
+{
+ size_t i;
+
+ for (i = 0; strings[i] != NULL; ++i)
+ ;
+ return i;
+}
+
+/* Simple implementation of decryption: look for any crypto_LUKS
+ * partitions and decrypt them, then rescan for VGs. This only works
+ * for Fedora whole-disk encryption. WIP to make this work for other
+ * encryption schemes.
+ */
+static void
+diff_inspect_do_decrypt (guestfs_h *g)
+{
+ char **partitions = guestfs_list_partitions (g);
+ if (partitions == NULL)
+ exit (EXIT_FAILURE);
+
+ int need_rescan = 0;
+ size_t i;
+ for (i = 0; partitions[i] != NULL; ++i) {
+ char *type = guestfs_vfs_type (g, partitions[i]);
+ if (type && STREQ (type, "crypto_LUKS")) {
+ char mapname[32];
+ diff_make_mapname (partitions[i], mapname, sizeof mapname);
+
+ char *key = read_key (partitions[i]);
+ /* XXX Should we call guestfs_luks_open_ro if readonly flag
+ * is set? This might break 'mount_ro'.
+ */
+ if (guestfs_luks_open (g, partitions[i], key, mapname) == -1)
+ exit (EXIT_FAILURE);
+
+ free (key);
+
+ need_rescan = 1;
+ }
+ free (type);
+ }
+
+ free_strings (partitions);
+
+ if (need_rescan) {
+ if (guestfs_vgscan (g) == -1)
+ exit (EXIT_FAILURE);
+ if (guestfs_vg_activate_all (g, 1) == -1)
+ exit (EXIT_FAILURE);
+ }
+}
+
+static int
+compare_keys (const void *p1, const void *p2)
+{
+ const char *key1 = * (char * const *) p1;
+ const char *key2 = * (char * const *) p2;
+
+ return strcmp (key1, key2);
+}
+
+static int
+compare_keys_len (const void *p1, const void *p2)
+{
+ const char *key1 = * (char * const *) p1;
+ const char *key2 = * (char * const *) p2;
+ int c;
+
+ c = strlen (key1) - strlen (key2);
+ if (c != 0)
+ return c;
+
+ return compare_keys (p1, p2);
+}
+
+static void
+diff_inspect_mount_root (guestfs_h *g, const char *root)
+{
+ char **mountpoints = guestfs_inspect_get_mountpoints (g, root);
+ if (mountpoints == NULL)
+ exit (EXIT_FAILURE);
+
+ /* Sort by key length, shortest key first, so that we end up
+ * mounting the filesystems in the correct order.
+ */
+ qsort (mountpoints, count_strings (mountpoints) / 2, 2 * sizeof (char *),
+ compare_keys_len);
+
+ size_t i;
+ size_t mount_errors = 0;
+ for (i = 0; mountpoints[i] != NULL; i += 2) {
+ int r;
+ r = guestfs_mount_ro (g, mountpoints[i+1], mountpoints[i]);
+ if (r == -1) {
+ /* If the "/" filesystem could not be mounted, give up, else
+ * just count the errors and print a warning.
+ */
+ if (STREQ (mountpoints[i], "/"))
+ exit (EXIT_FAILURE);
+ mount_errors++;
+ }
+ }
+
+ free_strings (mountpoints);
+
+ if (mount_errors)
+ fprintf (stderr, _("%s: some filesystems could not be mounted (ignored)\n"),
+ program_name);
+}
+
+/* This function implements the -i option. */
+static void
+diff_inspect_mount (guestfs_h *g)
+{
+ const char *root = NULL;
+ diff_inspect_do_decrypt (g);
+
+ char **roots = guestfs_inspect_os (g);
+ if (roots == NULL)
+ exit (EXIT_FAILURE);
+
+ if (roots[0] == NULL) {
+ fprintf (stderr,
+ _("%s: no operating system was found on this disk\n"
+ "\n"
+ "If using guestfish '-i' option, remove this option and instead\n"
+ "use the commands 'run' followed by 'list-filesystems'.\n"
+ "You can then mount filesystems you want by hand using the\n"
+ "'mount' or 'mount-ro' command.\n"
+ "\n"
+ "If using guestmount '-i', remove this option and choose the\n"
+ "filesystem(s) you want to see by manually adding '-m' option(s).\n"
+ "Use 'virt-filesystems' to see what filesystems are available.\n"
+ "\n"
+ "If using other virt tools, this disk image won't work\n"
+ "with these tools. Use the guestfish equivalent commands\n"
+ "(see the virt tool manual page).\n"),
+ program_name);
+ free_strings (roots);
+ exit (EXIT_FAILURE);
+ }
+
+ if (roots[1] != NULL) {
+ fprintf (stderr,
+ _("%s: multi-boot operating systems are not supported\n"
+ "\n"
+ "If using guestfish '-i' option, remove this option and instead\n"
+ "use the commands 'run' followed by 'list-filesystems'.\n"
+ "You can then mount filesystems you want by hand using the\n"
+ "'mount' or 'mount-ro' command.\n"
+ "\n"
+ "If using guestmount '-i', remove this option and choose the\n"
+ "filesystem(s) you want to see by manually adding '-m' option(s).\n"
+ "Use 'virt-filesystems' to see what filesystems are available.\n"
+ "\n"
+ "If using other virt tools, multi-boot operating systems won't work\n"
+ "with these tools. Use the guestfish equivalent commands\n"
+ "(see the virt tool manual page).\n"),
+ program_name);
+ free_strings (roots);
+ exit (EXIT_FAILURE);
+ }
+
+ root = roots[0];
+ free (roots);
+
+ diff_inspect_mount_root (g, root);
+}
+
+static void
+free_drive (struct drv *drv)
+{
+ if (!drv) return;
+
+ free (drv->device);
+ free (drv);
+}
+
+int
+main (int argc, char *argv[])
+{
+ /* set global program name that is not polluted with libtool artifacts. */
+ set_program_name (argv[0]);
+ bindtextdomain (PACKAGE, LOCALEBASEDIR);
+ textdomain (PACKAGE);
+
+ enum { HELP_OPTION = CHAR_MAX + 1 };
+
+ static const char *options = "s:d:";
+ static const struct option long_options[] = {
+ {"seed", 1, 0, 's'},
+ {"domain", 1, 0, 'd'},
+ {"help", 0, 0, HELP_OPTION},
+ {0, 0, 0, 0}
+ };
+
+ struct drv *sdrv = NULL;
+ struct drv *ddrv = NULL;
+ int c, nr;
+ int option_index;
+ int spid, dpid;
+
+ sg = guestfs_create ();
+ if (sg == NULL) {
+ fprintf (stderr, _("guestfs_create: failed to create seed handle\n"));
+ exit (EXIT_FAILURE);
+ }
+
+ dg = guestfs_create ();
+ if (dg == NULL) {
+ fprintf (stderr, _("guestfs_create: failed to create comparison handle\n"));
+ exit (EXIT_FAILURE);
+ }
+
+ argv[0] = diff_bad_case (program_name);
+
+ for (;;) {
+ c = getopt_long (argc, argv, options, long_options, &option_index);
+ if (c == -1) break;
+
+ switch (c) {
+ case 0:
+ if (STREQ (long_options[option_index].name, "keys-from-stdin")) {
+ keys_from_stdin = 1;
+ } else if (STREQ (long_options[option_index].name, "echo-keys")) {
+ echo_keys = 1;
+ } else if (STREQ (long_options[option_index].name, "seed")) {
+ if (sdrv) {
+ fprintf(stderr, _("Only one seed device"));
+ exit (EXIT_FAILURE);
+ }
+ sdrv = calloc (1, sizeof (struct drv));
+ if (!sdrv) {
+ perror ("malloc");
+ exit (EXIT_FAILURE);
+ }
+ sdrv->type = drv_d;
+ sdrv->nr_drives = -1;
+ sdrv->d.guest = optarg;
+ sdrv->next = NULL;
+ } else if (STREQ (long_options[option_index].name, "domain")) {
+ if (ddrv) {
+ fprintf (stderr, _("Only one diff device"));
+ exit (EXIT_FAILURE);
+ }
+ ddrv = calloc (1, sizeof (struct drv));
+ if (!ddrv) {
+ perror ("malloc");
+ exit (EXIT_FAILURE);
+ }
+ ddrv->type = drv_d;
+ ddrv->nr_drives = -1;
+ ddrv->d.guest = optarg;
+ ddrv->next = NULL;
+ } else {
+ fprintf (stderr, _("%s: unknown long option: %s (%d)\n"),
+ program_name, long_options[option_index].name, option_index);
+ exit (EXIT_FAILURE);
+ }
+ break;
+
+ case 'c':
+ libvirt_uri = optarg;
+
+ case 's':
+ if (sdrv) {
+ fprintf(stderr, _("Only one seed device"));
+ exit (EXIT_FAILURE);
+ }
+ sdrv = calloc (1, sizeof (struct drv));
+ if (!sdrv) {
+ perror ("malloc");
+ exit (EXIT_FAILURE);
+ }
+ sdrv->type = drv_d;
+ sdrv->nr_drives = -1;
+ sdrv->d.guest = optarg;
+ sdrv->next = NULL;
+ break;
+
+ case 'd':
+ if (ddrv) {
+ fprintf (stderr, _("Only one diff device"));
+ exit (EXIT_FAILURE);
+ }
+ ddrv = calloc (1, sizeof (struct drv));
+ if (!ddrv) {
+ perror ("malloc");
+ exit (EXIT_FAILURE);
+ }
+ ddrv->type = drv_d;
+ ddrv->nr_drives = -1;
+ ddrv->d.guest = optarg;
+ ddrv->next = NULL;
+ break;
+
+ case HELP_OPTION:
+ diff_usage (EXIT_SUCCESS);
+
+ default:
+ diff_usage (EXIT_FAILURE);
+ }
+ }
+
+ if (sdrv == NULL)
+ diff_usage (EXIT_FAILURE);
+ if (ddrv == NULL)
+ diff_usage (EXIT_FAILURE);
+
+ struct guestfs_add_domain_argv optargs = {
+ .bitmask = 0,
+ .libvirturi = libvirt_uri,
+ .readonly = 1,
+ .allowuuid = 1,
+ .readonlydisk = "read",
+ };
+ nr = guestfs_add_domain_argv (sg, sdrv->d.guest, &optargs);
+ if (nr == -1)
+ exit (EXIT_FAILURE);
+ sdrv->nr_drives = nr;
+ nr = guestfs_add_domain_argv (dg, ddrv->d.guest, &optargs);
+ if (nr == -1)
+ exit (EXIT_FAILURE);
+ ddrv->nr_drives = nr;
+
+ if (guestfs_launch (sg) == -1)
+ exit (EXIT_FAILURE);
+ if (guestfs_launch (dg) == -1)
+ exit (EXIT_FAILURE);
+
+ diff_inspect_mount (sg);
+ diff_inspect_mount (dg);
+
+ char stempdir[] = "/tmp/sGuestXXXXXX";
+ char dtempdir[] = "/tmp/dGuestXXXXXX";
+
+ if (mkdtemp (stempdir) == NULL) {
+ perror ("mkdtemp");
+ exit (EXIT_FAILURE);
+ }
+ if (mkdtemp (dtempdir) == NULL) {
+ perror ("mkdtemp");
+ exit (EXIT_FAILURE);
+ }
+
+ if (guestfs_mount_local (sg, stempdir, -1) == -1)
+ exit (EXIT_FAILURE);
+ if (guestfs_mount_local (dg, dtempdir, -1) == -1)
+ exit (EXIT_FAILURE);
+
+ spid = fork ();
+ if (spid == -1) {
+ perror ("fork");
+ exit (EXIT_FAILURE);
+ }
+ if (spid == 0) {
+ if (guestfs_mount_local_run (sg) == -1)
+ exit (EXIT_FAILURE);
+ _exit (EXIT_SUCCESS);
+ }
+
+ dpid = fork();
+ if (dpid == -1) {
+ perror ("fork");
+ exit (EXIT_FAILURE);
+ }
+ if (dpid == 0) {
+ if (guestfs_mount_local_run (dg) == -1)
+ exit (EXIT_FAILURE);
+ _exit (EXIT_SUCCESS);
+ }
+
+ const char *dir = argv[optind];
+ char system_arg[BUFSIZ];
+ sprintf (system_arg, "diff -urN %s%s %s%s", stempdir, dir,
+ dtempdir, dir);
+ sleep (5);
+ if (system (system_arg) == -1)
+ exit (EXIT_FAILURE);
+
+ guestfs_umount_local (sg, GUESTFS_UMOUNT_LOCAL_RETRY, 1, -1);
+ waitpid (spid, NULL, 0);
+ guestfs_umount_local (dg, GUESTFS_UMOUNT_LOCAL_RETRY, 1, -1);
+ waitpid (dpid, NULL, 0);
+
+ if (guestfs_shutdown (sg) == -1)
+ exit (EXIT_FAILURE);
+ if (guestfs_shutdown (dg) == -1)
+ exit (EXIT_FAILURE);
+
+ free_drive (sdrv);
+ free_drive (ddrv);
+
+ guestfs_close (sg);
+ guestfs_close (dg);
+
+ exit (EXIT_SUCCESS);
+}
diff --git a/po/POTFILES b/po/POTFILES
index dffa899..3f51648 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -1,6 +1,7 @@
align/domains.c
align/scan.c
cat/virt-cat.c
+cat/virt-diff.c
cat/virt-filesystems.c
cat/virt-ls.c
daemon/9p.c
--
1.7.12.rc1
12 years, 1 month
[PATCH] lib: update inspect_list_applications to return all installed RPMs (RHBZ#859885)
by John Eckersberg
Note that because of RHBZ#859949, this will return two identical
entries for RPMs which differ only by arch.
---
src/inspect-apps.c | 98 ++++++++++++++++++++++++++++++------------------------
1 file changed, 54 insertions(+), 44 deletions(-)
diff --git a/src/inspect-apps.c b/src/inspect-apps.c
index f65c70a..9586611 100644
--- a/src/inspect-apps.c
+++ b/src/inspect-apps.c
@@ -125,7 +125,7 @@ guestfs__inspect_list_applications (guestfs_h *g, const char *root)
#ifdef DB_DUMP
/* This data comes from the Name database, and contains the application
- * names and the first 4 bytes of the link field.
+ * names and the first 4 bytes of each link field.
*/
struct rpm_names_list {
struct rpm_name *names;
@@ -161,26 +161,62 @@ read_rpm_name (guestfs_h *g,
void *listv)
{
struct rpm_names_list *list = listv;
+ const unsigned char *link_p;
char *name;
/* Ignore bogus entries. */
if (keylen == 0 || valuelen < 4)
return 0;
- /* The name (key) field won't be NUL-terminated, so we must do that. */
- name = safe_malloc (g, keylen+1);
- memcpy (name, key, keylen);
- name[keylen] = '\0';
-
- list->names = safe_realloc (g, list->names,
- (list->len + 1) * sizeof (struct rpm_name));
- list->names[list->len].name = name;
- memcpy (list->names[list->len].link, value, 4);
- list->len++;
+ /* A name entry will have as many links as installed instances of
+ * that pacakge. For example, if glibc.i686 and glibc.x86_64 are
+ * both installed, then there will be a link for each Packages
+ * entry. Add an entry onto list for all installed instances.
+ */
+ for (link_p = value; link_p < value + valuelen; link_p += 8) {
+ name = safe_strndup (g, key, keylen);
+
+ list->names = safe_realloc (g, list->names,
+ (list->len + 1) * sizeof (struct rpm_name));
+ list->names[list->len].name = name;
+ memcpy (list->names[list->len].link, link_p, 4);
+ list->len++;
+ }
return 0;
}
+/* tag constants, see rpmtag.h in RPM for complete list */
+#define RPMTAG_VERSION 1001
+#define RPMTAG_RELEASE 1002
+#define RPMTAG_ARCH 1022
+
+static char *
+get_rpm_header_tag (guestfs_h *g, const void *header_start, size_t header_len, uint32_t tag)
+{
+ uint32_t num_fields, offset;
+ const void *cursor = header_start + 8, *store;
+
+ /* This function parses the RPM header structure to pull out various
+ * tag strings (version, release, arch, etc.). For more detail on the
+ * header format, see:
+ * http://www.rpm.org/max-rpm/s1-rpm-file-format-rpm-file-format.html#S2-RPM...
+ */
+
+ num_fields = be32toh (*(uint32_t *) header_start);
+ store = header_start + 8 + (16 * num_fields);
+
+ while (cursor < store && cursor < header_start + header_len) {
+ if (be32toh (*(uint32_t *) cursor) == tag){
+ offset = be32toh(*(uint32_t *) (cursor + 8));
+ return safe_strdup(g, store + offset);
+ }
+ cursor += 16;
+ }
+
+ return NULL;
+}
+
struct read_package_data {
struct rpm_names_list *list;
struct guestfs_application_list *apps;
@@ -194,16 +230,13 @@ read_package (guestfs_h *g,
{
struct read_package_data *data = datav;
struct rpm_name nkey, *entry;
- char *p;
- size_t len;
- ssize_t max;
- char *nul_name_nul, *version, *release;
+ char *version, *release;
/* This function reads one (key, value) pair from the Packages
* database. The key is the link field (see struct rpm_name). The
- * value is a long binary string, but we can extract the version
- * number from it as below. First we have to look up the link field
- * in the list of links (which is sorted by link field).
+ * value is a long binary string, but we can extract the header data
+ * from it as below. First we have to look up the link field in the
+ * list of links (which is sorted by link field).
*/
/* Ignore bogus entries. */
@@ -219,34 +252,11 @@ read_package (guestfs_h *g,
/* We found a matching link entry, so that gives us the application
* name (entry->name). Now we can get other data for this
- * application out of the binary value string. XXX This is a real
- * hack.
+ * application out of the binary value string.
*/
- /* Look for \0<name>\0 */
- len = strlen (entry->name);
- nul_name_nul = safe_malloc (g, len + 2);
- nul_name_nul[0] = '\0';
- memcpy (&nul_name_nul[1], entry->name, len);
- nul_name_nul[len+1] = '\0';
- p = memmem (value, valuelen, nul_name_nul, len+2);
- free (nul_name_nul);
- if (!p)
- return 0;
-
- /* Following that are \0-delimited version and release fields. */
- p += len + 2; /* Note we have to skip \0 + name + \0. */
- max = valuelen - (p - (char *) value);
- if (max < 0)
- max = 0;
- version = safe_strndup (g, p, max);
-
- len = strlen (version);
- p += len + 1;
- max = valuelen - (p - (char *) value);
- if (max < 0)
- max = 0;
- release = safe_strndup (g, p, max);
+ version = get_rpm_header_tag(g, value, valuelen, RPMTAG_VERSION);
+ release = get_rpm_header_tag(g, value, valuelen, RPMTAG_RELEASE);
/* Add the application and what we know. */
add_application (g, data->apps, entry->name, "", 0, version, release,
--
1.7.11.7
12 years, 1 month
[PATCH] NEW API: add a new api restorecon
by Wanlong Gao
Add a new api restorecon to restore file(s) default
SELinux security contexts.
Signed-off-by: Wanlong Gao <gaowanlong(a)cn.fujitsu.com>
---
daemon/selinux.c | 69 +
generator/actions.ml | 25 +
gobject/Makefile.inc | 6 +-
po/POTFILES | 2 +
src/MAX_PROC_NR | 2 +-
21 files changed, 13282 insertions(+), 28030 deletions(-)
diff --git a/daemon/selinux.c b/daemon/selinux.c
index 40590e1..14bc666 100644
--- a/daemon/selinux.c
+++ b/daemon/selinux.c
@@ -31,6 +31,10 @@
#include "actions.h"
#include "optgroups.h"
+#define MAX_ARGS 128
+
+GUESTFSD_EXT_CMD(str_restorecon, restorecon);
+
#if defined(HAVE_LIBSELINUX)
int
@@ -106,3 +110,68 @@ do_getcon (void)
}
#endif /* !HAVE_LIBSELINUX */
+
+int
+do_restorecon (const char *pathname,
+ const char *excludedir,
+ const char *labelprefix,
+ int recursion,
+ int force)
+{
+ int r;
+ size_t i = 0;
+ char *buf;
+ char *exdir;
+ char *err;
+ const char *argv[MAX_ARGS];
+
+ buf = sysroot_path (pathname);
+ if (!buf) {
+ reply_with_error ("malloc");
+ return -1;
+ }
+
+ ADD_ARG (argv, i, str_restorecon);
+
+ if (optargs_bitmask & GUESTFS_RESTORECON_EXCLUDEDIR_BITMASK) {
+ if (excludedir) {
+ exdir = sysroot_path (excludedir);
+ if (!exdir) {
+ reply_with_error ("malloc");
+ return -1;
+ }
+ ADD_ARG (argv, i, "-e");
+ ADD_ARG (argv, i, exdir);
+ }
+ }
+
+ if (optargs_bitmask & GUESTFS_RESTORECON_LABELPREFIX_BITMASK) {
+ if (labelprefix) {
+ ADD_ARG (argv, i, "-L");
+ ADD_ARG (argv, i, labelprefix);
+ }
+ }
+
+ if (optargs_bitmask & GUESTFS_RESTORECON_RECURSION_BITMASK)
+ if (recursion)
+ ADD_ARG (argv, i, "-R");
+
+ if (optargs_bitmask & GUESTFS_RESTORECON_FORCE_BITMASK)
+ if (force)
+ ADD_ARG (argv, i, "-F");
+
+ ADD_ARG (argv, i, buf);
+ ADD_ARG (argv, i, NULL);
+
+ r = commandv (NULL, &err, argv);
+ free (buf);
+ if (exdir) free (exdir);
+ if (r == -1) {
+ reply_with_error ("%s: %s", pathname, err);
+ free (err);
+ return -1;
+ }
+
+ free (err);
+ return 0;
+}
diff --git a/generator/actions.ml b/generator/actions.ml
index 71aee37..12796a7 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -10241,6 +10241,31 @@ If the optional C<suffix> parameter is given, then the suffix
See also: C<guestfs_mkdtemp>." };
+ { defaults with
+ name = "restorecon";
+ style = RErr, [Pathname "pathname"], [OString "excludedir"; OString "labelprefix"; OBool "recursion"; OBool "force"];
+ proc_nr = Some 374;
+ tests = [
+ InitScratchFS, Always, TestRun (
+ [["mkdir"; "/a"];
+ ["mkdir"; "/a/b"];
+ ["touch"; "/a/b/c"];
+ ["mkdir"; "/a/d"];
+ ["touch"; "/a/d/e"];
+ ["restorecon"; "/a"; "/a/d"; "NOARG"; "true"; "true"]])
+ ];
+ shortdesc = "restore file(s) default SELinux security contexts";
+ longdesc = "\
+This program is primarily used to reset the security context (type)
+(extended attributes) on one or more files.
+
+It can be run at any time to correct errors, to add support for new policy.
+
+If a file object does not have a context, restorecon will write the default
+context to the file object's extended attributes. If a file object has a
+context, C<restorecon> will only modify the type portion of the security
+context. The C<force> option will force a replacement of the entire context."};
+
]
(* Non-API meta-commands available only in guestfish.
diff --git a/gobject/Makefile.inc b/gobject/Makefile.inc
index 95a4b6b..7451d8e 100644
--- a/gobject/Makefile.inc
+++ b/gobject/Makefile.inc
@@ -82,7 +82,8 @@ guestfs_gobject_headers= \
include/guestfs-gobject/optargs-hivex_open.h \
include/guestfs-gobject/optargs-xfs_repair.h \
include/guestfs-gobject/optargs-mke2fs.h \
- include/guestfs-gobject/optargs-mktemp.h
+ include/guestfs-gobject/optargs-mktemp.h \
+ include/guestfs-gobject/optargs-restorecon.h
guestfs_gobject_sources= \
src/session.c \
@@ -146,4 +147,5 @@ guestfs_gobject_sources= \
src/optargs-hivex_open.c \
src/optargs-xfs_repair.c \
src/optargs-mke2fs.c \
- src/optargs-mktemp.c
+ src/optargs-mktemp.c \
+ src/optargs-restorecon.c
diff --git a/po/POTFILES b/po/POTFILES
index a73377d..5cded4e 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -138,6 +138,7 @@ fish/tilde.c
fish/time.c
format/format.c
fuse/guestmount.c
+gobject/docs/guestfs-scan.c
gobject/src/optargs-add_domain.c
gobject/src/optargs-add_drive.c
gobject/src/optargs-btrfs_filesystem_resize.c
@@ -167,6 +168,7 @@ gobject/src/optargs-mount_local.c
gobject/src/optargs-ntfsclone_out.c
gobject/src/optargs-ntfsfix.c
gobject/src/optargs-ntfsresize.c
+gobject/src/optargs-restorecon.c
gobject/src/optargs-rsync.c
gobject/src/optargs-rsync_in.c
gobject/src/optargs-rsync_out.c
diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR
index a5c3fde..38a45c3 100644
--- a/src/MAX_PROC_NR
+++ b/src/MAX_PROC_NR
@@ -1 +1 @@
-373
+374
--
1.8.0
12 years, 1 month
Re: [Libguestfs] Porting febootstrap to urpmi-based distributions
by Richard W.M. Jones
On Mon, Oct 29, 2012 at 11:10:04AM +0100, Guillaume Rousse wrote:
> Hello Richard.
>
> I didn't find any dedicated mailing-list for febootstrap, so sending
> this directly seems the best option.
CC-ing this to libguestfs(a)redhat.com which is the right list.
> I'm interested to have
> libguestfs on mageia, meaning I have to port febootstrap first. I
> had a quick look at the code, and it seems all I have to do is to
> provide a new dedicated package handler.
>
> From the content of the febootstrap_yum_rpm.ml file, it seems I just
> have to rewrite the yum_rpm_resolve_dependencies_and_download
> function, given than all other adress rpm command directly.
Starting from an existing similar plugin is a good idea, so yes.
See also: src/febootstrap_package_handlers.mli where the interface is
precisely defined.
> My
> current understanding of this function tells me that its purpose is
> to download a given package and all its dependency. I think I could
> basically achieve the same result by calling urpmi (the functional
> equivalent of yum install) with the --no-install flag, wrapping its
> output to return the list of downloaded filenames. Or am I missing
> an obvious trap ?
The purpose of ph_resolve_dependencies_and_download is described as:
Take a list of package names, and using the package manager
resolve those to a list of all the packages that are required
including dependencies. Download the full list of packages and
dependencies into a tmpdir. Return the list of full filenames.
Note this should also process the [excludes] list.
Unfortunately for the RPM/Yum plugin we have to do this with some
complex Python code, which keeps breaking because they keep changing
their ill-defined "API". For the dpkg/apt plugin it's a lot simpler,
just running the command:
apt-cache depends --recurse -i [package list]
The obvious(?) trap might be that urpmi requires root. Hopefully not,
but if it does require root unnecessarily, please get urpmi upstream
to fix this.
Rich.
--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming blog: http://rwmj.wordpress.com
Fedora now supports 80 OCaml packages (the OPEN alternative to F#)
http://cocan.org/getting_started_with_ocaml_on_red_hat_and_fedora
12 years, 2 months