qemu: Add binfmt preserve-argv[0] wrapper

main
Zhaofeng Li 3 years ago
parent 34ad3ffe08
commit 3011531cf9
  1. 79
      pkgs/applications/virtualization/qemu/binfmt-p-wrapper.c
  2. 31
      pkgs/applications/virtualization/qemu/binfmt-p-wrapper.nix
  3. 2
      pkgs/top-level/all-packages.nix

@ -0,0 +1,79 @@
// This is a tiny wrapper that converts the extra arv[0] argument
// from binfmt-misc with the P flag enabled to QEMU parameters.
// It also prevents LD_* environment variables from being applied
// to QEMU itself.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifndef TARGET_QEMU
#error "Define TARGET_QEMU to be the path to the qemu-user binary (e.g., -DTARGET_QEMU=\"/full/path/to/qemu-riscv64\")"
#endif
extern char **environ;
int main(int argc, char *argv[]) {
if (argc < 3) {
fprintf(stderr, "%s: This should be run as the binfmt interpreter with the P flag\n", argv[0]);
fprintf(stderr, "%s: My preconfigured qemu-user binary: %s\n", argv[0], TARGET_QEMU);
return 1;
}
size_t environ_count = 0;
for (char **cur = environ; *cur != NULL; ++cur) {
environ_count++;
}
size_t new_argc = 3;
size_t new_argv_alloc = argc + 2 * environ_count + 2; // [ "-E", env ] for each LD_* env + [ "-0", argv0 ]
char **new_argv = (char**)malloc((new_argv_alloc + 1) * sizeof(char*));
if (!new_argv) {
fprintf(stderr, "FATAL: Failed to allocate new argv array\n");
abort();
}
new_argv[0] = TARGET_QEMU;
new_argv[1] = "-0";
new_argv[2] = argv[2];
// Pass all LD_ env variables as -E and strip them in `new_environ`
size_t new_environc = 0;
char **new_environ = (char**)malloc((environ_count + 1) * sizeof(char*));
if (!new_environ) {
fprintf(stderr, "FATAL: Failed to allocate new environ array\n");
abort();
}
for (char **cur = environ; *cur != NULL; ++cur) {
if (strncmp("LD_", *cur, 3) == 0) {
new_argv[new_argc++] = "-E";
new_argv[new_argc++] = *cur;
} else {
new_environ[new_environc++] = *cur;
}
}
new_environ[new_environc] = NULL;
size_t new_arg_start = new_argc;
new_argc += argc - 3 + 2; // [ "--", full_binary_path ]
if (argc > 3) {
memcpy(&new_argv[new_arg_start + 2], &argv[3], (argc - 3) * sizeof(char**));
}
new_argv[new_arg_start] = "--";
new_argv[new_arg_start + 1] = argv[1];
new_argv[new_argc] = NULL;
#ifdef DEBUG
for (size_t i = 0; i < new_argc; ++i) {
fprintf(stderr, "argv[%zu] = %s\n", i, new_argv[i]);
}
#endif
return execve(new_argv[0], new_argv, new_environ);
}
// vim: et:ts=4:sw=4

@ -0,0 +1,31 @@
# binfmt preserve-argv[0] wrapper
#
# More details in binfmt-p-wrapper.c
#
# The wrapper has to be static so LD_* environment variables
# cannot affect the execution of the wrapper itself.
{ lib, stdenv, pkgsStatic, enableDebug ? false }:
name: emulator:
pkgsStatic.stdenv.mkDerivation {
inherit name;
src = ./binfmt-p-wrapper.c;
dontUnpack = true;
dontInstall = true;
buildPhase = ''
runHook preBuild
mkdir -p $out/bin
$CC -o $out/bin/${name} -static -std=c99 -O2 \
-DTARGET_QEMU=\"${emulator}\" \
${lib.optionalString enableDebug "-DDEBUG"} \
$src
runHook postBuild
'';
}

@ -27324,6 +27324,8 @@ with pkgs;
qemu-utils = callPackage ../applications/virtualization/qemu/utils.nix {};
wrapQemuBinfmtP = callPackage ../applications/virtualization/qemu/binfmt-p-wrapper.nix { };
qgis-unwrapped = libsForQt5.callPackage ../applications/gis/qgis/unwrapped.nix {
withGrass = false;
};

Loading…
Cancel
Save