[pacman-dev] [PATCH] add --sysroot option

Andrew Gregory andrew.gregory.8 at gmail.com
Sun Apr 16 04:31:57 UTC 2017


--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 <andrew.gregory.8 at gmail.com>
---

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


More information about the pacman-dev mailing list