manually apply --sysroot to configuration
The previous chroot-based sysroot often broke due to glibc's delayed loading for much of its functionality when the sysroot did not contain compatible copies of the necessary libraries. This approach instead manually prepends the sysroot to all configuration paths. BREAKING CHANGE: targets to -U are no longer interpreted relative to sysroot Signed-off-by: Andrew Gregory <andrew.gregory.8@gmail.com> Signed-off-by: Allan McRae <allan@archlinux.org>
This commit is contained in:
parent
2180e4d127
commit
7016adcb70
5 changed files with 174 additions and 18 deletions
|
@ -195,11 +195,10 @@ Options
|
||||||
Disable defaults for low speed limit and timeout on downloads. Use this
|
Disable defaults for low speed limit and timeout on downloads. Use this
|
||||||
if you have issues downloading files with proxy and/or security gateway.
|
if you have issues downloading files with proxy and/or security gateway.
|
||||||
|
|
||||||
*\--sysroot* <dir>::
|
*\--sysroot* <dir>:: Specify an alternative system root. This path will be
|
||||||
Specify an alternative system root. Pacman will chroot and chdir into the
|
prepended to all other configuration directories and any repository servers
|
||||||
system root prior to running. This allows mounted guest systems to be
|
beginning with `file://`. Any paths or URLs passed as targets will not be
|
||||||
properly operated on. Any other paths given will be interpreted as relative
|
modified. This allows mounted guest systems to be properly operated on.
|
||||||
to the system root. Requires root privileges.
|
|
||||||
|
|
||||||
|
|
||||||
Transaction Options (apply to '-S', '-R' and '-U')
|
Transaction Options (apply to '-S', '-R' and '-U')
|
||||||
|
|
|
@ -108,6 +108,7 @@ config_t *config_new(void)
|
||||||
newconfig->op = PM_OP_MAIN;
|
newconfig->op = PM_OP_MAIN;
|
||||||
newconfig->logmask = ALPM_LOG_ERROR | ALPM_LOG_WARNING;
|
newconfig->logmask = ALPM_LOG_ERROR | ALPM_LOG_WARNING;
|
||||||
newconfig->configfile = strdup(CONFFILE);
|
newconfig->configfile = strdup(CONFFILE);
|
||||||
|
newconfig->sysroot = strdup("/");
|
||||||
if(alpm_capabilities() & ALPM_CAPABILITY_SIGNATURES) {
|
if(alpm_capabilities() & ALPM_CAPABILITY_SIGNATURES) {
|
||||||
newconfig->siglevel = ALPM_SIG_PACKAGE | ALPM_SIG_PACKAGE_OPTIONAL |
|
newconfig->siglevel = ALPM_SIG_PACKAGE | ALPM_SIG_PACKAGE_OPTIONAL |
|
||||||
ALPM_SIG_DATABASE | ALPM_SIG_DATABASE_OPTIONAL;
|
ALPM_SIG_DATABASE | ALPM_SIG_DATABASE_OPTIONAL;
|
||||||
|
@ -151,6 +152,7 @@ int config_free(config_t *oldconfig)
|
||||||
FREELIST(oldconfig->noextract);
|
FREELIST(oldconfig->noextract);
|
||||||
FREELIST(oldconfig->overwrite_files);
|
FREELIST(oldconfig->overwrite_files);
|
||||||
free(oldconfig->configfile);
|
free(oldconfig->configfile);
|
||||||
|
free(oldconfig->sysroot);
|
||||||
free(oldconfig->rootdir);
|
free(oldconfig->rootdir);
|
||||||
free(oldconfig->dbpath);
|
free(oldconfig->dbpath);
|
||||||
free(oldconfig->logfile);
|
free(oldconfig->logfile);
|
||||||
|
@ -1047,6 +1049,100 @@ static int _parse_repo(const char *key, char *value, const char *file,
|
||||||
static int _parse_directive(const char *file, int linenum, const char *name,
|
static int _parse_directive(const char *file, int linenum, const char *name,
|
||||||
char *key, char *value, void *data);
|
char *key, char *value, void *data);
|
||||||
|
|
||||||
|
static char *escape_chars(const char *pattern, const char *escape)
|
||||||
|
{
|
||||||
|
size_t escape_len, len, pattern_chars;
|
||||||
|
const char *c;
|
||||||
|
char *escaped, *e;
|
||||||
|
|
||||||
|
if(pattern == NULL || escape == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = strlen(pattern);
|
||||||
|
escape_len = strlen(escape);
|
||||||
|
pattern_chars = 0;
|
||||||
|
for(c = pattern; *c; c++) {
|
||||||
|
if(memchr(escape, *c, escape_len)) {
|
||||||
|
pattern_chars++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pattern_chars == 0) {
|
||||||
|
return strdup(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate new string with overflow check */
|
||||||
|
if(SIZE_MAX - len < pattern_chars
|
||||||
|
|| !(escaped = malloc(len + pattern_chars))) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(c = pattern, e = escaped; *c; c++, e++) {
|
||||||
|
if(memchr(escape, *c, escape_len)) {
|
||||||
|
*e = '\\';
|
||||||
|
e++;
|
||||||
|
}
|
||||||
|
*e = *c;
|
||||||
|
}
|
||||||
|
*e = '\0';
|
||||||
|
|
||||||
|
return escaped;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *escape_glob_pattern(const char *pattern)
|
||||||
|
{
|
||||||
|
return escape_chars(pattern, "\\*?[");
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *prepend_dir(const char *dir, const char *path)
|
||||||
|
{
|
||||||
|
char *newpath;
|
||||||
|
size_t dlen = strlen(dir);
|
||||||
|
const char *sep = dlen && dir[dlen - 1] == '/' ? "" : "/";
|
||||||
|
while(path[0] == '/') { path++; }
|
||||||
|
return pm_asprintf(&newpath, "%s%s%s", dir, sep, path) == -1 ? NULL : newpath;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int globdir(const char *dir, const char *pattern, int flags,
|
||||||
|
int (*errfunc) (const char *epath, int eerrno), glob_t *globbuf)
|
||||||
|
{
|
||||||
|
int gret;
|
||||||
|
char *fullpattern = NULL, *escaped_dir = NULL;
|
||||||
|
|
||||||
|
if((escaped_dir = escape_glob_pattern(dir)) == NULL) {
|
||||||
|
goto nospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(flags & GLOB_NOESCAPE) {
|
||||||
|
/* "disable" backslash escaping by escaping any backlashes */
|
||||||
|
char *escaped_pattern = escape_chars(pattern, "\\");
|
||||||
|
if(escaped_pattern == NULL) {
|
||||||
|
goto nospace;
|
||||||
|
}
|
||||||
|
fullpattern = prepend_dir(escaped_dir, escaped_pattern);
|
||||||
|
free(escaped_pattern);
|
||||||
|
flags &= ~GLOB_NOESCAPE;
|
||||||
|
} else {
|
||||||
|
fullpattern = prepend_dir(escaped_dir, pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fullpattern == NULL) {
|
||||||
|
goto nospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
gret = glob(fullpattern, flags, errfunc, globbuf);
|
||||||
|
free(escaped_dir);
|
||||||
|
free(fullpattern);
|
||||||
|
return gret;
|
||||||
|
|
||||||
|
nospace:
|
||||||
|
free(escaped_dir);
|
||||||
|
free(fullpattern);
|
||||||
|
return GLOB_NOSPACE;
|
||||||
|
}
|
||||||
|
|
||||||
static int process_include(const char *value, void *data,
|
static int process_include(const char *value, void *data,
|
||||||
const char *file, int linenum)
|
const char *file, int linenum)
|
||||||
{
|
{
|
||||||
|
@ -1072,7 +1168,7 @@ static int process_include(const char *value, void *data,
|
||||||
section->depth++;
|
section->depth++;
|
||||||
|
|
||||||
/* Ignore include failures... assume non-critical */
|
/* Ignore include failures... assume non-critical */
|
||||||
globret = glob(value, GLOB_NOCHECK, NULL, &globbuf);
|
globret = globdir(config->sysroot, value, GLOB_NOCHECK, NULL, &globbuf);
|
||||||
switch(globret) {
|
switch(globret) {
|
||||||
case GLOB_NOSPACE:
|
case GLOB_NOSPACE:
|
||||||
pm_printf(ALPM_LOG_DEBUG,
|
pm_printf(ALPM_LOG_DEBUG,
|
||||||
|
@ -1149,6 +1245,58 @@ static int _parse_directive(const char *file, int linenum, const char *name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int prepend_sysroot(config_t *c)
|
||||||
|
{
|
||||||
|
alpm_list_t *i;
|
||||||
|
|
||||||
|
if(c->sysroot == NULL || c->sysroot[0] == '\0'
|
||||||
|
|| strcmp(c->sysroot, "/") == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SETSYSROOT(opt) \
|
||||||
|
if(opt) { \
|
||||||
|
char *n = prepend_dir(c->sysroot, opt);\
|
||||||
|
if(n == NULL) { return -1; } \
|
||||||
|
else { free(opt); opt = n; } \
|
||||||
|
}
|
||||||
|
|
||||||
|
SETSYSROOT(c->rootdir);
|
||||||
|
SETSYSROOT(c->dbpath);
|
||||||
|
SETSYSROOT(c->logfile);
|
||||||
|
SETSYSROOT(c->gpgdir);
|
||||||
|
for(i = c->cachedirs; i; i = i->next) {
|
||||||
|
SETSYSROOT(i->data);
|
||||||
|
}
|
||||||
|
for(i = c->hookdirs; i; i = i->next) {
|
||||||
|
SETSYSROOT(i->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = c->repos; i; i = i->next) {
|
||||||
|
config_repo_t *r = i->data;
|
||||||
|
alpm_list_t *j;
|
||||||
|
for(j = r->servers; j; j = j->next) {
|
||||||
|
if(strncmp("file://", j->data, 7) == 0) {
|
||||||
|
char *newdir = NULL, *newurl = NULL, *oldurl = j->data;
|
||||||
|
const char *olddir = oldurl + 7;
|
||||||
|
if((newdir = prepend_dir(c->sysroot, olddir)) == NULL
|
||||||
|
|| (pm_asprintf(&newurl, "file://%s", newdir)) == -1) {
|
||||||
|
free(newdir);
|
||||||
|
free(newurl);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
free(newdir);
|
||||||
|
free(j->data);
|
||||||
|
j->data = newurl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef SETSYSROOT
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int setdefaults(config_t *c)
|
int setdefaults(config_t *c)
|
||||||
{
|
{
|
||||||
alpm_list_t *i;
|
alpm_list_t *i;
|
||||||
|
@ -1212,14 +1360,22 @@ int setdefaults(config_t *c)
|
||||||
|
|
||||||
#undef SETDEFAULT
|
#undef SETDEFAULT
|
||||||
|
|
||||||
|
prepend_sysroot(c);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int parseconfigfile(const char *file)
|
int parseconfigfile(const char *file)
|
||||||
{
|
{
|
||||||
struct section_t section = {0};
|
struct section_t section = {0};
|
||||||
pm_printf(ALPM_LOG_DEBUG, "config: attempting to read file %s\n", file);
|
char *realfile;
|
||||||
return parse_ini(file, _parse_directive, §ion);
|
if((realfile = prepend_dir(config->sysroot, file)) == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
pm_printf(ALPM_LOG_DEBUG, "config: attempting to read file %s\n", realfile);
|
||||||
|
free(config->configfile);
|
||||||
|
config->configfile = realfile;
|
||||||
|
return parse_ini(realfile, _parse_directive, §ion);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Parse a configuration file.
|
/** Parse a configuration file.
|
||||||
|
|
|
@ -44,6 +44,7 @@ static void usage(int ret)
|
||||||
fputs(_("options:\n"), stream);
|
fputs(_("options:\n"), stream);
|
||||||
fputs(_(" -c, --config=<path> set an alternate configuration file\n"), stream);
|
fputs(_(" -c, --config=<path> set an alternate configuration file\n"), stream);
|
||||||
fputs(_(" -R, --rootdir=<path> set an alternate installation root\n"), stream);
|
fputs(_(" -R, --rootdir=<path> set an alternate installation root\n"), stream);
|
||||||
|
fputs(_(" -S, --sysroot=<path> set an alternate system root\n"), stream);
|
||||||
fputs(_(" -r, --repo=<remote> query options for a specific repo\n"), stream);
|
fputs(_(" -r, --repo=<remote> query options for a specific repo\n"), stream);
|
||||||
fputs(_(" -v, --verbose always show directive names\n"), stream);
|
fputs(_(" -v, --verbose always show directive names\n"), stream);
|
||||||
fputs(_(" -l, --repo-list list configured repositories\n"), stream);
|
fputs(_(" -l, --repo-list list configured repositories\n"), stream);
|
||||||
|
@ -58,10 +59,11 @@ static void parse_opts(int argc, char **argv)
|
||||||
int c;
|
int c;
|
||||||
config_file = CONFFILE;
|
config_file = CONFFILE;
|
||||||
|
|
||||||
const char *short_opts = "c:hlR:r:Vv";
|
const char *short_opts = "c:hlR:S:r:Vv";
|
||||||
struct option long_opts[] = {
|
struct option long_opts[] = {
|
||||||
{ "config" , required_argument , NULL , 'c' },
|
{ "config" , required_argument , NULL , 'c' },
|
||||||
{ "rootdir" , required_argument , NULL , 'R' },
|
{ "rootdir" , required_argument , NULL , 'R' },
|
||||||
|
{ "sysroot" , required_argument , NULL , 'S' },
|
||||||
{ "repo" , required_argument , NULL , 'r' },
|
{ "repo" , required_argument , NULL , 'r' },
|
||||||
{ "repo-list" , no_argument , NULL , 'l' },
|
{ "repo-list" , no_argument , NULL , 'l' },
|
||||||
{ "verbose" , no_argument , NULL , 'v' },
|
{ "verbose" , no_argument , NULL , 'v' },
|
||||||
|
@ -83,6 +85,14 @@ static void parse_opts(int argc, char **argv)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'S':
|
||||||
|
free(config->sysroot);
|
||||||
|
if((config->sysroot = strdup(optarg)) == NULL) {
|
||||||
|
fprintf(stderr, _("error setting sysroot '%s': out of memory\n"), optarg);
|
||||||
|
cleanup();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
repo_list = 1;
|
repo_list = 1;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1187,12 +1187,6 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
pm_printf(ALPM_LOG_DEBUG, "pacman v%s - libalpm v%s\n", PACKAGE_VERSION, alpm_version());
|
pm_printf(ALPM_LOG_DEBUG, "pacman v%s - libalpm v%s\n", PACKAGE_VERSION, alpm_version());
|
||||||
|
|
||||||
/* parse the config file */
|
/* parse the config file */
|
||||||
|
|
|
@ -121,9 +121,6 @@ int trans_release(void)
|
||||||
|
|
||||||
int needs_root(void)
|
int needs_root(void)
|
||||||
{
|
{
|
||||||
if(config->sysroot) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
switch(config->op) {
|
switch(config->op) {
|
||||||
case PM_OP_DATABASE:
|
case PM_OP_DATABASE:
|
||||||
return !config->op_q_check;
|
return !config->op_q_check;
|
||||||
|
|
Loading…
Add table
Reference in a new issue