--root is not sufficient to properly operate on a mounted guest system.
Using --root still uses the host system's configuration and there is no
way to correctly use the guest configuration without manually modifying
any Include directives.  --sysroot provides an easier way to operate on
a guest system by chrooting immediately after option parsing before
configuration parsing or performing any operations.  It is currently
limited to the root user, but that's enough for restoring a guest system
to a working state, which is the primary intended use case.

Signed-off-by: Andrew Gregory <[email protected]>
---

I originally intended to put something in place to allow read-only operations
for unprivileged users, but that is considerably more complex and, I think,
a less important use case.

 doc/pacman.8.txt    | 11 +++++++++--
 src/pacman/conf.h   |  2 ++
 src/pacman/pacman.c | 24 ++++++++++++++++++------
 src/pacman/util.c   |  3 +++
 4 files changed, 32 insertions(+), 8 deletions(-)

diff --git a/doc/pacman.8.txt b/doc/pacman.8.txt
index f01f4aa4..d670e82a 100644
--- a/doc/pacman.8.txt
+++ b/doc/pacman.8.txt
@@ -136,11 +136,12 @@ Options
 *-r, \--root* <path>::
        Specify an alternative installation root (default is `/`). This should
        not be used as a way to install software into `/usr/local` instead of
-       `/usr`. This option is used if you want to install a package on a
-       temporarily mounted partition that is "owned" by another system.
+       `/usr`.
        *NOTE*: If database path or log file are not specified on either the
        command line or in linkman:pacman.conf[5], their default location will
        be inside this root path.
+       *NOTE*: This option is not suitable for performing operations on a 
mounted
+       guest system. See '\--sysroot' instead.
 
 *-v, \--verbose*::
        Output paths such as as the Root, Conf File, DB Path, Cache Dirs, etc.
@@ -197,6 +198,12 @@ Options
        Disable defaults for low speed limit and timeout on downloads. Use this
        if you have issues downloading files with proxy and/or security gateway.
 
+*\--sysroot* <dir>::
+       Specify an alternative system root.  Pacman will chroot and chdir into 
the
+       system root prior to running. This allows mounted guest systems to be
+       properly operated on. Any other paths given will be interpreted as 
relative
+       to the system root. Requires root privileges.
+
 
 Transaction Options (apply to '-S', '-R' and '-U')
 --------------------------------------------------
diff --git a/src/pacman/conf.h b/src/pacman/conf.h
index e67f7c51..53b44be6 100644
--- a/src/pacman/conf.h
+++ b/src/pacman/conf.h
@@ -67,6 +67,7 @@ typedef struct __config_t {
        char *dbpath;
        char *logfile;
        char *gpgdir;
+       char *sysroot;
        alpm_list_t *hookdirs;
        alpm_list_t *cachedirs;
 
@@ -195,6 +196,7 @@ enum {
        OP_PRINT,
        OP_QUIET,
        OP_ROOT,
+       OP_SYSROOT,
        OP_RECURSIVE,
        OP_SEARCH,
        OP_REGEX,
diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c
index 9d1cf6bb..605aec3e 100644
--- a/src/pacman/pacman.c
+++ b/src/pacman/pacman.c
@@ -214,6 +214,7 @@ static void usage(int op, const char * const myname)
                addlist(_("  -r, --root <path>    set an alternate installation 
root\n"));
                addlist(_("  -v, --verbose        be verbose\n"));
                addlist(_("      --arch <arch>    set an alternate 
architecture\n"));
+               addlist(_("      --sysroot        operate on a mounted guest 
system (root-only)\n"));
                addlist(_("      --cachedir <dir> set an alternate package 
cache location\n"));
                addlist(_("      --hookdir <dir>  set an alternate hook 
location\n"));
                addlist(_("      --color <when>   colorize the output\n"));
@@ -447,6 +448,10 @@ static int parsearg_global(int opt)
                        free(config->rootdir);
                        config->rootdir = strdup(optarg);
                        break;
+               case OP_SYSROOT:
+                       free(config->sysroot);
+                       config->sysroot = strdup(optarg);
+                       break;
                case OP_DISABLEDLTIMEOUT:
                        config->disable_dl_timeout = 1;
                        break;
@@ -917,6 +922,7 @@ static int parseargs(int argc, char *argv[])
                {"print",      no_argument,       0, OP_PRINT},
                {"quiet",      no_argument,       0, OP_QUIET},
                {"root",       required_argument, 0, OP_ROOT},
+               {"sysroot",    required_argument, 0, OP_SYSROOT},
                {"recursive",  no_argument,       0, OP_RECURSIVE},
                {"search",     no_argument,       0, OP_SEARCH},
                {"regex",      no_argument,       0, OP_REGEX},
@@ -1150,6 +1156,18 @@ int main(int argc, char *argv[])
                cleanup(ret);
        }
 
+       /* check if we have sufficient permission for the requested operation */
+       if(myuid > 0 && needs_root()) {
+               pm_printf(ALPM_LOG_ERROR, _("you cannot perform this operation 
unless you are root.\n"));
+               cleanup(EXIT_FAILURE);
+       }
+
+       if(config->sysroot && (chroot(config->sysroot) != 0 || chdir("/") != 
0)) {
+               pm_printf(ALPM_LOG_ERROR,
+                               _("chroot to '%s' failed: (%s)\n"), 
config->sysroot, strerror(errno));
+               cleanup(EXIT_FAILURE);
+       }
+
        /* we support reading targets from stdin if a cmdline parameter is '-' 
*/
        if(alpm_list_find_str(pm_targets, "-")) {
                if(!isatty(fileno(stdin))) {
@@ -1222,12 +1240,6 @@ int main(int argc, char *argv[])
                config->logmask &= ~ALPM_LOG_WARNING;
        }
 
-       /* check if we have sufficient permission for the requested operation */
-       if(myuid > 0 && needs_root()) {
-               pm_printf(ALPM_LOG_ERROR, _("you cannot perform this operation 
unless you are root.\n"));
-               cleanup(EXIT_FAILURE);
-       }
-
        if(config->verbose > 0) {
                alpm_list_t *j;
                printf("Root      : %s\n", 
alpm_option_get_root(config->handle));
diff --git a/src/pacman/util.c b/src/pacman/util.c
index 64ea8c57..ae8a74d3 100644
--- a/src/pacman/util.c
+++ b/src/pacman/util.c
@@ -103,6 +103,9 @@ int trans_release(void)
 
 int needs_root(void)
 {
+       if(config->sysroot) {
+               return 1;
+       }
        switch(config->op) {
                case PM_OP_DATABASE:
                        return !config->op_q_check;
-- 
2.12.2

Reply via email to