[RFC PATCH 1/2] dpkg: Add option --cross-bootstrap

2014-08-28 Thread Andreas Oberritter
If --cross-bootstrap is set, don't chroot into the target root
directory, but just export DPKG_INSTDIR for the execution of
maintscripts.

This is useful for Yocto/OpenEmbedded, where programs like
update-alternatives, update-rc.d or systemctl run natively or
emulated on the build system when creating the cross-compiled
root filesystem with apt-get.

Signed-off-by: Andreas Oberritter 
---
 src/main.c   | 3 +++
 src/main.h   | 1 +
 src/script.c | 6 --
 3 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/src/main.c b/src/main.c
index 65c3626..cd0f395 100644
--- a/src/main.c
+++ b/src/main.c
@@ -134,6 +134,7 @@ usage(const struct cmdinfo *ci, const char *value)
 "  --admindir= Use  instead of %s.\n"
 "  --root= Install on a different root directory.\n"
 "  --instdir=  Change installation dir without changing admin 
dir.\n"
+"  --cross-bootstrap  Don't chroot into root directory for scripts.\n"
 "  --path-exclude=   Do not install paths which match a shell 
pattern.\n"
 "  --path-include=   Re-include a pattern after a previous 
exclusion.\n"
 "  -O|--selected-only Skip packages not selected for 
install/upgrade.\n"
@@ -184,6 +185,7 @@ static const char printforhelp[] = N_(
 int f_pending=0, f_recursive=0, f_alsoselect=1, f_skipsame=0, f_noact=0;
 int f_autodeconf=0, f_nodebsig=0;
 int f_triggers = 0;
+int f_cross = 0;
 int fc_downgrade=1, fc_configureany=0, fc_hold=0, fc_removereinstreq=0, 
fc_overwrite=0;
 int fc_removeessential=0, fc_conflicts=0, fc_depends=0, fc_dependsversion=0;
 int fc_breaks=0, fc_badpath=0, fc_overwritediverted=0, fc_architecture=0;
@@ -711,6 +713,7 @@ static const struct cmdinfo cmdinfos[]= {
   { "abort-after",   0,   1, &errabort, NULL,  set_integer,   0 },
   { "admindir",  0,   1, NULL,  &admindir, NULL,  0 },
   { "instdir",   0,   1, NULL,  &instdir,  NULL,  0 },
+  { "cross-bootstrap",   0,   0, &f_cross,  NULL,  NULL,  1 },
   { "ignore-depends",0,   1, NULL,  NULL,  set_ignore_depends, 
0 },
   { "force", 0,   2, NULL,  NULL,  set_force, 1 },
   { "refuse",0,   2, NULL,  NULL,  set_force, 0 },
diff --git a/src/main.h b/src/main.h
index 5a35808..1b6d78a 100644
--- a/src/main.h
+++ b/src/main.h
@@ -124,6 +124,7 @@ extern const char *const statusstrings[];
 extern int f_pending, f_recursive, f_alsoselect, f_skipsame, f_noact;
 extern int f_autodeconf, f_nodebsig;
 extern int f_triggers;
+extern int f_cross;
 extern int fc_downgrade, fc_configureany, fc_hold, fc_removereinstreq, 
fc_overwrite;
 extern int fc_removeessential, fc_conflicts, fc_depends, fc_dependsversion;
 extern int fc_breaks, fc_badpath, fc_overwritediverted, fc_architecture;
diff --git a/src/script.c b/src/script.c
index d552f3f..4a56cdc 100644
--- a/src/script.c
+++ b/src/script.c
@@ -105,8 +105,10 @@ maintscript_pre_exec(struct command *cmd)
if (setenv("DPKG_ADMINDIR", admindir + instdirl, 1) < 0)
ohshite(_("unable to setenv for subprocesses"));
 
-   if (chroot(instdir))
+   if (!f_cross && chroot(instdir))
ohshite(_("failed to chroot to `%.250s'"), instdir);
+   if (setenv("DPKG_INSTDIR", f_cross ? instdir : "", 1) < 0)
+   ohshite(_("unable to setenv for subprocesses"));
}
/* Switch to a known good directory to give the maintainer script
 * a saner environment, also needed after the chroot(). */
@@ -125,7 +127,7 @@ maintscript_pre_exec(struct command *cmd)
  args.buf);
varbuf_destroy(&args);
}
-   if (!instdirl)
+   if (f_cross || !instdirl)
return cmd->filename;
 
assert(strlen(cmd->filename) >= instdirl);
-- 
1.9.1


-- 
To UNSUBSCRIBE, email to debian-dpkg-requ...@lists.debian.org
with a subject of "unsubscribe". Trouble? Contact listmas...@lists.debian.org
Archive: 
https://lists.debian.org/1409230398-18083-2-git-send-email-...@opendreambox.org



[RFC PATCH 0/2] Running maintscripts for a different architecture

2014-08-28 Thread Andreas Oberritter
Dear dpkg developers,

in OE-Core (Yocto / OpenEmbedded Core), we cross-compile complete
distributions and create root filesystem images. You can choose between
several package formats (deb, ipk, rpm) and related managers.

Because these root filesystems usually are built for an architecture
(instruction set) that's incompatible with the build system's CPU, dpkg's
habit of chrooting into the 'instdir' before running maintscripts (if
the --root option was given) doesn't work.

To compensate, we can add a new option --cross-bootstrap, which stops
dpkg from chrooting and instead exports DPKG_INSTDIR for maintscripts.

Then we can adjust update-alternatives to use this variable, in order to
be able to use it in a cross-compile environment. Previously, we had to
use a different implementation of update-alternatives, that comes with
opkg.

So far, I've successfully tested these patches to create root filesystems,
i.e. "update-alternatives --install". The other options still need testing,
but at least with an empty or unset DPKG_INSTDIR, nothing should have
changed.

The second patch has room for improvements, e.g. you seem to avoid
using predeclarations, and I believe calling alternative_path_classify()
from fileset_*() may violate your coding style. But I'd like to get some
feedback first, in order to be able fix it properly. I could also split
the patch into smaller components:

 1.) Predeclare/move/rename alternative_path_classify and enum
 alternative_path_status.
 2.) Replace direct use of stat with calls to alternative_path_classify
 where possible.
 3.) Predeclare/move xasprintf.
 4.) Introduce instdir.

Best regards,
Andreas

Andreas Oberritter (2):
  dpkg: Add option --cross-bootstrap
  update-alternatives: Implement offline mode

 src/main.c  |   3 +
 src/main.h  |   1 +
 src/script.c|   6 +-
 utils/update-alternatives.c | 162 
 4 files changed, 110 insertions(+), 62 deletions(-)

-- 
1.9.1


-- 
To UNSUBSCRIBE, email to debian-dpkg-requ...@lists.debian.org
with a subject of "unsubscribe". Trouble? Contact listmas...@lists.debian.org
Archive: 
https://lists.debian.org/1409230398-18083-1-git-send-email-...@opendreambox.org



[RFC PATCH 2/2] update-alternatives: Implement offline mode

2014-08-28 Thread Andreas Oberritter
Lets update-alternatives manage symlinks inside a cross-arch root
filesystem in a directory specified by DPKG_INSTDIR.

Signed-off-by: Andreas Oberritter 
---
 utils/update-alternatives.c | 162 
 1 file changed, 102 insertions(+), 60 deletions(-)

diff --git a/utils/update-alternatives.c b/utils/update-alternatives.c
index 62675e8..83d5d9e 100644
--- a/utils/update-alternatives.c
+++ b/utils/update-alternatives.c
@@ -51,6 +51,7 @@
 #define PROGNAME "update-alternatives"
 
 static const char *altdir = SYSCONFDIR "/alternatives";
+static const char *instdir;
 static const char *admdir;
 
 static const char *prog_path = "update-alternatives";
@@ -71,6 +72,27 @@ static int nb_opts = 0;
 #define ALT_TMP_EXT ".dpkg-tmp"
 
 /*
+ * Types.
+ */
+
+enum alternative_path_status {
+   ALT_PATH_SYMLINK,
+   ALT_PATH_MISSING,
+   ALT_PATH_OTHER,
+};
+
+
+/*
+ * Predeclarations.
+ */
+
+static int DPKG_ATTR_PRINTF(2)
+xasprintf(char **strp, const char *fmt, ...);
+
+static enum alternative_path_status
+alternative_path_classify(const char *linkname);
+
+/*
  * Functions.
  */
 
@@ -277,7 +299,7 @@ xstrdup(const char *str)
 }
 
 static char *
-areadlink(const char *linkname)
+_areadlink(const char *linkname)
 {
struct stat st;
char *buf;
@@ -310,6 +332,22 @@ areadlink(const char *linkname)
 }
 
 static char *
+areadlink(const char *linkname)
+{
+   char *instdir_linkname;
+   int saved_errno;
+   char *ret;
+
+   xasprintf(&instdir_linkname, "%s%s", instdir, linkname);
+   ret = _areadlink(instdir_linkname);
+   saved_errno = errno;
+   free(instdir_linkname);
+   errno = saved_errno;
+
+   return ret;
+}
+
+static char *
 xreadlink(const char *linkname)
 {
char *buf;
@@ -356,6 +394,18 @@ set_action(const char *new_action)
 }
 
 static const char *
+instdir_init(void)
+{
+   const char *dpkg_instdir;
+
+   dpkg_instdir = getenv("DPKG_INSTDIR");
+   if (dpkg_instdir)
+   return dpkg_instdir;
+
+   return "";
+}
+
+static const char *
 admindir_init(void)
 {
const char *basedir, *dpkg_basedir;
@@ -477,25 +527,43 @@ rename_mv(const char *src, const char *dst)
 static void
 checked_symlink(const char *filename, const char *linkname)
 {
-   if (symlink(filename, linkname))
+   char *instdir_linkname;
+
+   xasprintf(&instdir_linkname, "%s%s", instdir, linkname);
+
+   if (symlink(filename, instdir_linkname))
syserr(_("error creating symbolic link `%.255s'"), linkname);
+
+   free(instdir_linkname);
 }
 
 static void
 checked_mv(const char *src, const char *dst)
 {
-   if (!rename_mv(src, dst))
+   char *instdir_src;
+   char *instdir_dst;
+
+   xasprintf(&instdir_src, "%s%s", instdir, src);
+   xasprintf(&instdir_dst, "%s%s", instdir, dst);
+
+   if (!rename_mv(instdir_src, instdir_dst))
syserr(_("unable to install `%.250s' as `%.250s'"), src, dst);
+
+   free(instdir_src);
+   free(instdir_dst);
 }
 
 static void
 checked_rm(const char *f)
 {
-   if (!unlink(f))
-   return;
+   char *instdir_f;
 
-   if (errno != ENOENT)
+   xasprintf(&instdir_f, "%s%s", instdir, f);
+
+   if (unlink(instdir_f) && errno != ENOENT)
syserr(_("unable to remove '%s'"), f);
+
+   free(instdir_f);
 }
 
 static void DPKG_ATTR_PRINTF(1)
@@ -612,16 +680,11 @@ fileset_has_slave(struct fileset *fs, const char *name)
 static bool
 fileset_can_install_slave(struct fileset *fs, const char *slave_name)
 {
-   struct stat st;
-
/* Decide whether the slave alternative must be setup */
if (fileset_has_slave(fs, slave_name)) {
const char *slave = fileset_get_slave(fs, slave_name);
 
-   errno = 0;
-   if (stat(slave, &st) == -1 && errno != ENOENT)
-   syserr(_("cannot stat file '%s'"), slave);
-   if (errno == 0)
+   if (alternative_path_classify(slave) != ALT_PATH_MISSING)
return true;
}
 
@@ -1212,7 +1275,6 @@ alternative_parse_fileset(struct alternative *a, struct 
altdb_context *ctx)
 {
struct fileset *fs;
struct slave_link *sl;
-   struct stat st;
char *master_file;
 
master_file = altdb_get_line(ctx, _("master file"));
@@ -1225,12 +1287,9 @@ alternative_parse_fileset(struct alternative *a, struct 
altdb_context *ctx)
if (fs)
ctx->bad_format(ctx, _("duplicate path %s"), master_file);
 
-   if (stat(master_file, &st)) {
+   if (alternative_path_classify(master_file) == ALT_PATH_MISSING) {
char *junk;
 
-   if (errno != ENOENT)
-   syserr(_("cannot stat file '%s'"), master_file);
-
/* File not found - remove. */
if (ctx->flags & ALTDB_WARN_PARSER)
warning(_("alternative %s