From 76ac76a0d52cad3b555a8f1d0822cf1fcf884d77 Mon Sep 17 00:00:00 2001
From: Riku Voipio <riku.voipio@linaro.org>
Date: Fri, 15 Aug 2014 13:22:44 +0300
Subject: [PATCH] Add support for preserve-argv0 flag

Qemu will start requiring setting P in binfmt_misc
flags [P]. Unfortunately update-binfmts doesn't just
pass flags section as-is. The only supported flag
so far is credentials, which is supported via --credentials
command line flag.

I've implemented a similar --preserve flag in this commit.

This commit (or something similar) needs to land to Debian
before qemu 2.2 can be uploaded.

[P] https://www.kernel.org/doc/Documentation/binfmt_misc.txt

Signed-off-by: Riku Voipio <riku.voipio@linaro.org>
---
 src/format.c         |  5 +++++
 src/format.h         |  1 +
 src/tests/detectors  |  3 +++
 src/tests/display    |  2 ++
 src/tests/enable     |  2 ++
 src/tests/import     |  2 ++
 src/tests/install    |  4 ++++
 src/update-binfmts.c | 18 +++++++++++++++---
 8 files changed, 34 insertions(+), 3 deletions(-)

diff --git a/src/format.c b/src/format.c
index d7620b0..0bfdfe1 100644
--- a/src/format.c
+++ b/src/format.c
@@ -76,6 +76,7 @@ struct binfmt *binfmt_load (const char *name, const char *filename, int quiet)
     READ_LINE (interpreter, 0);
     READ_LINE (detector, 1);
     READ_LINE (credentials, 1);
+    READ_LINE (preserve, 1);
 
 #undef READ_LINE
 
@@ -106,6 +107,7 @@ struct binfmt *binfmt_new (const char *name, Hash_table *args)
     SET_FIELD (interpreter);
     SET_FIELD (detector);
     SET_FIELD (credentials);
+    SET_FIELD (preserve);
 
 #undef SET_FIELD
 
@@ -179,6 +181,7 @@ int binfmt_write (const struct binfmt *binfmt, const char *filename)
     WRITE_FIELD (interpreter);
     WRITE_FIELD (detector);
     WRITE_FIELD (credentials);
+    WRITE_FIELD (preserve);
 
 #undef WRITE_FIELD
 
@@ -203,6 +206,7 @@ void binfmt_print (const struct binfmt *binfmt)
     PRINT_FIELD (interpreter);
     PRINT_FIELD (detector);
     PRINT_FIELD (credentials);
+    PRINT_FIELD (preserve);
 
 #undef PRINT_FIELD
 }
@@ -226,6 +230,7 @@ void binfmt_free (struct binfmt *binfmt)
     free (binfmt->interpreter);
     free (binfmt->detector);
     free (binfmt->credentials);
+    free (binfmt->preserve);
     free (binfmt);
 }
 
diff --git a/src/format.h b/src/format.h
index 2d1e3e6..54a09e0 100644
--- a/src/format.h
+++ b/src/format.h
@@ -31,6 +31,7 @@ struct binfmt {
     char *interpreter;
     char *detector;
     char *credentials;
+    char *preserve;
 };
 
 struct binfmt *binfmt_load (const char *name, const char *filename, int quiet);
diff --git a/src/tests/detectors b/src/tests/detectors
index 4bcfdc6..f3481f8 100755
--- a/src/tests/detectors
+++ b/src/tests/detectors
@@ -59,6 +59,7 @@ ext
 $tmpdir/program-1
 $tmpdir/detector-1
 
+
 EOF
 expect_pass 'detector 1: admindir entry OK' \
 	    'diff -u "$tmpdir/var/lib/binfmts/test-1" "$tmpdir/1-admin.exp"'
@@ -82,6 +83,7 @@ ext
 $tmpdir/program-2
 $tmpdir/detector-2
 
+
 EOF
 expect_pass 'detector 2: admindir entry OK' \
 	    'diff -u "$tmpdir/var/lib/binfmts/test-2" "$tmpdir/2-admin.exp"'
@@ -105,6 +107,7 @@ ext
 $tmpdir/program-3
 
 
+
 EOF
 expect_pass 'no detector: admindir entry OK' \
 	    'diff -u "$tmpdir/var/lib/binfmts/test-3" "$tmpdir/3-admin.exp"'
diff --git a/src/tests/display b/src/tests/display
index 3844f04..4df4a25 100755
--- a/src/tests/display
+++ b/src/tests/display
@@ -37,6 +37,7 @@ ABCD
 /bin/sh
 
 
+
 EOF
 expect_pass 'magic: admindir entry OK' \
 	    'diff -u "$tmpdir/var/lib/binfmts/test-magic" "$tmpdir/1-admin.exp"'
@@ -61,6 +62,7 @@ ext
 /bin/sh
 
 
+
 EOF
 expect_pass 'extension with package: admindir entry OK' \
 	    'diff -u "$tmpdir/var/lib/binfmts/test-extension" "$tmpdir/2-admin.exp"'
diff --git a/src/tests/enable b/src/tests/enable
index d709a16..b5c08dd 100755
--- a/src/tests/enable
+++ b/src/tests/enable
@@ -37,6 +37,7 @@ ABCD
 /bin/sh
 
 
+
 EOF
 expect_pass 'magic: admindir entry OK' \
 	    'diff -u "$tmpdir/var/lib/binfmts/test-magic" "$tmpdir/1-admin.exp"'
@@ -61,6 +62,7 @@ ext
 /bin/sh
 
 
+
 EOF
 expect_pass 'extension: admindir entry OK' \
 	    'diff -u "$tmpdir/var/lib/binfmts/test-extension" "$tmpdir/2-admin.exp"'
diff --git a/src/tests/import b/src/tests/import
index cd33ab0..dde5e59 100755
--- a/src/tests/import
+++ b/src/tests/import
@@ -42,6 +42,7 @@ ABCD
 /bin/sh
 
 
+
 EOF
 expect_pass 'magic: admindir entry OK' \
 	    'diff -u "$tmpdir/var/lib/binfmts/test-magic" "$tmpdir/1-admin.exp"'
@@ -72,6 +73,7 @@ ABCD
 /bin/sh
 
 
+
 EOF
 expect_pass 'magic with mask: admindir entry OK' \
 	    'diff -u "$tmpdir/var/lib/binfmts/test-magic-mask" "$tmpdir/2-admin.exp"'
diff --git a/src/tests/install b/src/tests/install
index ecaa456..5659679 100755
--- a/src/tests/install
+++ b/src/tests/install
@@ -37,6 +37,7 @@ ABCD
 /bin/sh
 
 
+
 EOF
 expect_pass 'magic: admindir entry OK' \
 	    'diff -u "$tmpdir/var/lib/binfmts/test" "$tmpdir/1-admin.exp"'
@@ -67,6 +68,7 @@ ABCD
 /bin/sh
 
 
+
 EOF
 expect_pass 'magic with offset and mask: admindir entry OK' \
 	    'diff -u "$tmpdir/var/lib/binfmts/test" "$tmpdir/2-admin.exp"'
@@ -98,6 +100,7 @@ ext
 /bin/sh
 
 
+
 EOF
 expect_pass 'extension: admindir entry OK' \
 	    'diff -u "$tmpdir/var/lib/binfmts/test" "$tmpdir/3-admin.exp"'
@@ -133,6 +136,7 @@ ext
 /bin/sh
 
 
+
 EOF
 expect_pass 'extension with package: admindir entry OK' \
 	    'diff -u "$tmpdir/var/lib/binfmts/test" "$tmpdir/4-admin.exp"'
diff --git a/src/update-binfmts.c b/src/update-binfmts.c
index 96ff1e0..8c11a86 100644
--- a/src/update-binfmts.c
+++ b/src/update-binfmts.c
@@ -362,6 +362,7 @@ static int act_enable (const char *name)
 	int need_detector;
 	const char *interpreter;
 	const char *flags;
+	const char *preserve;
 	char *regstring;
 
 	procdir_name = xasprintf ("%s/%s", procdir, name);
@@ -411,11 +412,13 @@ static int act_enable (const char *name)
 	/* Fake the interpreter if we need a userspace detector program. */
 	interpreter = need_detector ? run_detectors : binfmt->interpreter;
 
+	preserve = (binfmt->preserve && !strcmp (binfmt->preserve, "yes"))
+		? "P" : "";
 	flags = (binfmt->credentials && !strcmp (binfmt->credentials, "yes"))
 		? "C" : "";
-	regstring = xasprintf (":%s:%c:%s:%s:%s:%s:%s\n",
+	regstring = xasprintf (":%s:%c:%s:%s:%s:%s:%s%s\n",
 			       name, type, binfmt->offset, binfmt->magic,
-			       binfmt->mask, interpreter, flags);
+			       binfmt->mask, interpreter, flags, preserve);
 	if (test)
 	    printf ("enable %s with the following format string:\n %s",
 		    name, regstring);
@@ -827,7 +830,8 @@ enum opts {
     OPT_ADMINDIR,
     OPT_IMPORTDIR,
     OPT_PROCDIR,
-    OPT_TEST
+    OPT_TEST,
+    OPT_PRESERVE
 };
 
 static struct argp_option options[] = {
@@ -863,6 +867,8 @@ static struct argp_option options[] = {
 	"use this userspace detector program" },
     { "credentials",	OPT_CREDENTIALS, "YES/NO",	OPTION_HIDDEN,
 	"use credentials of original binary for interpreter (yes/no)" },
+    { "preserve",	OPT_PRESERVE, "YES/NO",	OPTION_HIDDEN,
+	"preserve argv0 of original binary for interpreter (yes/no)" },
     { "package",	OPT_PACKAGE,	"PACKAGE-NAME",	0,
 	"for --install and --remove, specify the current package name", 1 },
     { "admindir",	OPT_ADMINDIR,	"DIRECTORY",	0,
@@ -888,6 +894,7 @@ static struct {
     const char *interpreter;
     const char *detector;
     const char *credentials;
+    const char *preserve;
 } spec;
 
 static const char *mode_name (enum opts m)
@@ -1012,6 +1019,10 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state)
 	    spec.credentials = arg;
 	    return 0;
 
+	case OPT_PRESERVE:
+	    spec.preserve = arg;
+	    return 0;
+
 	case OPT_PACKAGE:
 	    if (package)
 		argp_error (state, "more than one --package option given");
@@ -1123,6 +1134,7 @@ int main (int argc, char **argv)
 	ADD_SPEC (interpreter);
 	ADD_SPEC (detector);
 	ADD_SPEC (credentials);
+	ADD_SPEC (preserve);
 #undef ADD_SPEC
 	binfmt = binfmt_new (name, format_args);
 
-- 
2.0.1

