diff --git a/configure b/configure index 2ad376a0f..cba1df8ef 100755 --- a/configure +++ b/configure @@ -309,7 +309,7 @@ ac_includes_default="\ #endif" ac_default_prefix=/usr -ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS AWK CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S SET_MAKE RANLIB ac_ct_RANLIB CPP EGREP build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os MSGFMT JOBS STATIC_LINK LVM1 OWNER GROUP CLDFLAGS CLDWHOLEARCHIVE CLDNOWHOLEARCHIVE LD_DEPS LD_FLAGS SOFLAG LVM_VERSION DEBUG DEVMAPPER HAVE_LIBDL HAVE_SELINUX CMDLIB LOCALEDIR INTL_PACKAGE INTL LIBOBJS LTLIBOBJS' +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS AWK CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S SET_MAKE RANLIB ac_ct_RANLIB CPP EGREP build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os MSGFMT JOBS STATIC_LINK LVM1 OWNER GROUP CLDFLAGS CLDWHOLEARCHIVE CLDNOWHOLEARCHIVE LD_DEPS LD_FLAGS SOFLAG LVM_VERSION LVM1_FALLBACK DEBUG DEVMAPPER HAVE_LIBDL HAVE_SELINUX CMDLIB LOCALEDIR INTL_PACKAGE INTL LIBOBJS LTLIBOBJS' ac_subst_files='' # Initialize some variables set by options. @@ -845,6 +845,8 @@ if test -n "$ac_init_help"; then Optional Features: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-lvm1_fallback Use this to fall back and use LVM1 binaries if + device-mapper is missing from the kernel --enable-jobs=NUM Number of jobs to run simultaneously --enable-static_link Use this to link the tools to their libraries statically. Default is dynamic linking @@ -3921,6 +3923,18 @@ else GROUP="root" fi; +# Check whether --enable-lvm1_fallback or --disable-lvm1_fallback was given. +if test "${enable_lvm1_fallback+set}" = set; then + enableval="$enable_lvm1_fallback" + LVM1_FALLBACK=$enableval +else + LVM1_FALLBACK=no +fi; + +if test x$LVM1_FALLBACK = xyes; then + CFLAGS="$CFLAGS -DLVM1_FALLBACK" +fi + # Check whether --with-lvm1 or --without-lvm1 was given. if test "${with_lvm1+set}" = set; then @@ -5070,6 +5084,7 @@ fi + ac_config_files="$ac_config_files Makefile make.tmpl include/Makefile lib/Makefile lib/format1/Makefile man/Makefile po/Makefile tools/Makefile tools/version.h test/mm/Makefile test/device/Makefile test/format1/Makefile test/regex/Makefile test/filters/Makefile" @@ -5762,6 +5777,7 @@ s,@LD_DEPS@,$LD_DEPS,;t t s,@LD_FLAGS@,$LD_FLAGS,;t t s,@SOFLAG@,$SOFLAG,;t t s,@LVM_VERSION@,$LVM_VERSION,;t t +s,@LVM1_FALLBACK@,$LVM1_FALLBACK,;t t s,@DEBUG@,$DEBUG,;t t s,@DEVMAPPER@,$DEVMAPPER,;t t s,@HAVE_LIBDL@,$HAVE_LIBDL,;t t diff --git a/configure.in b/configure.in index 14a106825..1897d9b8f 100644 --- a/configure.in +++ b/configure.in @@ -86,6 +86,14 @@ AC_ARG_WITH(group, [ GROUP="$withval" ], [ GROUP="root" ]) +dnl -- LVM1 tool fallback option +AC_ARG_ENABLE(lvm1_fallback, [ --enable-lvm1_fallback Use this to fall back and use LVM1 binaries if + device-mapper is missing from the kernel], LVM1_FALLBACK=$enableval, LVM1_FALLBACK=no) + +if test x$LVM1_FALLBACK = xyes; then + CFLAGS="$CFLAGS -DLVM1_FALLBACK" +fi + dnl -- format1 inclusion type AC_ARG_WITH(lvm1, [ --with-lvm1=TYPE LVM1 metadata support: internal/shared/none @@ -270,6 +278,7 @@ AC_SUBST(LD_FLAGS) AC_SUBST(SOFLAG) AC_SUBST(LIBS) AC_SUBST(LVM_VERSION) +AC_SUBST(LVM1_FALLBACK) AC_SUBST(DEBUG) AC_SUBST(DEVMAPPER) AC_SUBST(HAVE_LIBDL) diff --git a/doc/example.conf b/doc/example.conf index a0e7ec496..057239699 100644 --- a/doc/example.conf +++ b/doc/example.conf @@ -175,6 +175,16 @@ global { # setting this to 0 should suppress the error messages. activation = 1 + # If we can't communicate with device-mapper, should we try running + # the LVM1 tools? + # This option only applies to 2.4 kernels and is provided to help you + # switch between device-mapper kernels and LVM1 kernels. + # The LVM1 tools need to be installed with .lvm1 suffices + # e.g. vgscan.lvm1 and they will stop working after you start using + # the new lvm2 on-disk metadata format. + # The default value is set when the tools are built. + # fallback_to_lvm1 = 0 + # The default metadata format that commands should use - "lvm1" or "lvm2". # The command line override is -M1 or -M2. # Defaults to "lvm1" if compiled in, else "lvm2". diff --git a/lib/activate/activate.c b/lib/activate/activate.c index cf32ec016..6ed93a31e 100644 --- a/lib/activate/activate.c +++ b/lib/activate/activate.c @@ -19,6 +19,7 @@ #include "memlock.h" #include "display.h" #include "fs.h" +#include "lvm-file.h" #include "lvm-string.h" #include "pool.h" #include "toolcontext.h" @@ -31,6 +32,22 @@ #define _skip(fmt, args...) log_very_verbose("Skipping: " fmt , ## args) +int lvm1_present(struct cmd_context *cmd) +{ + char path[PATH_MAX]; + + if (lvm_snprintf(path, sizeof(path), "%s/lvm/global", cmd->proc_dir) + < 0) { + log_error("LVM1 proc global snprintf failed"); + return 0; + } + + if (path_exists(path)) + return 1; + else + return 0; +} + #ifndef DEVMAPPER_SUPPORT void set_activation(int act) { diff --git a/lib/activate/activate.h b/lib/activate/activate.h index 590ee0b5d..0f9cd530b 100644 --- a/lib/activate/activate.h +++ b/lib/activate/activate.h @@ -36,6 +36,7 @@ int activation(void); int driver_version(char *version, size_t size); int library_version(char *version, size_t size); +int lvm1_present(struct cmd_context *cmd); int target_present(const char *target_name); diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c index 5ce1a034d..c1e6cd82f 100644 --- a/lib/commands/toolcontext.c +++ b/lib/commands/toolcontext.c @@ -462,6 +462,11 @@ static int _set_tag(struct cmd_context *cmd, const char *tag) return 0; } + if (!(cmd->kernel_vsn = pool_strdup(cmd->libmem, uts.release))) { + log_error("_init_hostname: pool_strdup kernel_vsn failed"); + return 0; + } + return 1; } diff --git a/lib/commands/toolcontext.h b/lib/commands/toolcontext.h index 4dd7fb3ec..eebe7c828 100644 --- a/lib/commands/toolcontext.h +++ b/lib/commands/toolcontext.h @@ -58,6 +58,7 @@ struct cmd_context { struct list formats; /* Available formats */ const char *hostname; + const char *kernel_vsn; char *cmd_line; struct command *command; diff --git a/lib/config/defaults.h b/lib/config/defaults.h index c47421259..d1e6d2908 100644 --- a/lib/config/defaults.h +++ b/lib/config/defaults.h @@ -35,6 +35,12 @@ #define DEFAULT_UMASK 0077 +#ifdef LVM1_FALLBACK +# define DEFAULT_FALLBACK_TO_LVM1 1 +#else +# define DEFAULT_FALLBACK_TO_LVM1 0 +#endif + #ifdef LVM1_SUPPORT # define DEFAULT_FORMAT "lvm1" #else diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c index 9b5a85621..7d7fd6aa1 100644 --- a/tools/lvmcmdline.c +++ b/tools/lvmcmdline.c @@ -1054,7 +1054,7 @@ static char *_list_args(const char *text, int state) char c; if (!(c = (the_args + com->valid_args[match_no++])->short_arg)) - continue; + continue; sprintf(s, "-%c", c); if (!strncmp(text, s, len)) @@ -1285,6 +1285,42 @@ void lvm2_exit(void *handle) #endif +/* + * Determine whether we should fall back and exec the equivalent LVM1 tool + */ +static int _lvm1_fallback(struct cmd_context *cmd) +{ + char vsn[80]; + int dm_present; + + if (!find_config_int(cmd->cft->root, "global/fallback_to_lvm1", + DEFAULT_FALLBACK_TO_LVM1) || + strncmp(cmd->kernel_vsn, "2.4.", 4)) + return 0; + + log_suppress(1); + dm_present = driver_version(vsn, sizeof(vsn)); + log_suppress(0); + + if (dm_present || !lvm1_present(cmd)) + return 0; + + return 1; +} + +static void _exec_lvm1_command(struct cmd_context *cmd, int argc, char **argv) +{ + char path[PATH_MAX]; + + if (lvm_snprintf(path, sizeof(path), "%s.lvm1", argv[0]) < 0) { + log_error("Failed to create LVM1 tool pathname"); + return; + } + + execvp(path, argv); + log_sys_error("execvp", path); +} + int lvm2_main(int argc, char **argv) { char *namebase, *base; @@ -1305,6 +1341,21 @@ int lvm2_main(int argc, char **argv) _register_commands(); + if (_lvm1_fallback(cmd)) { + /* Attempt to run equivalent LVM1 tool instead */ + if (!alias) { + argv++; + argc--; + alias = 0; + } + if (!argc) { + log_error("Falling back to LVM1 tools, but no " + "command specified."); + return ECMD_FAILED; + } + _exec_lvm1_command(cmd, argc, argv); + return ECMD_FAILED; + } #ifdef READLINE_SUPPORT if (!alias && argc == 1) { ret = _shell(cmd);