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
|
||||
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.
|
||||
*\--sysroot* <dir>:: Specify an alternative system root. This path will be
|
||||
prepended to all other configuration directories and any repository servers
|
||||
beginning with `file://`. Any paths or URLs passed as targets will not be
|
||||
modified. This allows mounted guest systems to be properly operated on.
|
||||
|
||||
|
||||
Transaction Options (apply to '-S', '-R' and '-U')
|
||||
|
|
|
@ -108,6 +108,7 @@ config_t *config_new(void)
|
|||
newconfig->op = PM_OP_MAIN;
|
||||
newconfig->logmask = ALPM_LOG_ERROR | ALPM_LOG_WARNING;
|
||||
newconfig->configfile = strdup(CONFFILE);
|
||||
newconfig->sysroot = strdup("/");
|
||||
if(alpm_capabilities() & ALPM_CAPABILITY_SIGNATURES) {
|
||||
newconfig->siglevel = ALPM_SIG_PACKAGE | ALPM_SIG_PACKAGE_OPTIONAL |
|
||||
ALPM_SIG_DATABASE | ALPM_SIG_DATABASE_OPTIONAL;
|
||||
|
@ -151,6 +152,7 @@ int config_free(config_t *oldconfig)
|
|||
FREELIST(oldconfig->noextract);
|
||||
FREELIST(oldconfig->overwrite_files);
|
||||
free(oldconfig->configfile);
|
||||
free(oldconfig->sysroot);
|
||||
free(oldconfig->rootdir);
|
||||
free(oldconfig->dbpath);
|
||||
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,
|
||||
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,
|
||||
const char *file, int linenum)
|
||||
{
|
||||
|
@ -1072,7 +1168,7 @@ static int process_include(const char *value, void *data,
|
|||
section->depth++;
|
||||
|
||||
/* Ignore include failures... assume non-critical */
|
||||
globret = glob(value, GLOB_NOCHECK, NULL, &globbuf);
|
||||
globret = globdir(config->sysroot, value, GLOB_NOCHECK, NULL, &globbuf);
|
||||
switch(globret) {
|
||||
case GLOB_NOSPACE:
|
||||
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)
|
||||
{
|
||||
alpm_list_t *i;
|
||||
|
@ -1212,14 +1360,22 @@ int setdefaults(config_t *c)
|
|||
|
||||
#undef SETDEFAULT
|
||||
|
||||
prepend_sysroot(c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parseconfigfile(const char *file)
|
||||
{
|
||||
struct section_t section = {0};
|
||||
pm_printf(ALPM_LOG_DEBUG, "config: attempting to read file %s\n", file);
|
||||
return parse_ini(file, _parse_directive, §ion);
|
||||
char *realfile;
|
||||
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.
|
||||
|
|
|
@ -44,6 +44,7 @@ static void usage(int ret)
|
|||
fputs(_("options:\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(_(" -S, --sysroot=<path> set an alternate system root\n"), stream);
|
||||
fputs(_(" -r, --repo=<remote> query options for a specific repo\n"), stream);
|
||||
fputs(_(" -v, --verbose always show directive names\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;
|
||||
config_file = CONFFILE;
|
||||
|
||||
const char *short_opts = "c:hlR:r:Vv";
|
||||
const char *short_opts = "c:hlR:S:r:Vv";
|
||||
struct option long_opts[] = {
|
||||
{ "config" , required_argument , NULL , 'c' },
|
||||
{ "rootdir" , required_argument , NULL , 'R' },
|
||||
{ "sysroot" , required_argument , NULL , 'S' },
|
||||
{ "repo" , required_argument , NULL , 'r' },
|
||||
{ "repo-list" , no_argument , NULL , 'l' },
|
||||
{ "verbose" , no_argument , NULL , 'v' },
|
||||
|
@ -83,6 +85,14 @@ static void parse_opts(int argc, char **argv)
|
|||
exit(1);
|
||||
}
|
||||
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':
|
||||
repo_list = 1;
|
||||
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());
|
||||
|
||||
/* parse the config file */
|
||||
|
|
|
@ -121,9 +121,6 @@ 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;
|
||||
|
|
Loading…
Add table
Reference in a new issue