#############################################################################*/
#include <ctype.h>
+#include <errno.h>
+#include <fts.h>
+#include <linux/limits.h>
#include <stddef.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <sys/personality.h>
#include <sys/utsname.h>
const char* platform;
const char* compatible[5];
unsigned long personality;
+ const char magic[41];
};
static const struct pakfire_arch PAKFIRE_ARCHES[] = {
.platform = "x86",
.compatible = { "i686", NULL },
.personality = PER_LINUX,
+ .magic = "7f454c4602010100000000000000000002003e00",
},
{
.name = "i686",
.platform = "x86",
.personality = PER_LINUX32,
+ .magic = "7f454c4601010100000000000000000002000300",
},
// ARM
.name = "aarch64",
.platform = "arm",
.personality = PER_LINUX,
+ .magic = "7f454c460201010000000000000000000200b700",
},
{
.name = "armv7hl",
.platform = "arm",
.compatible = { "armv7l", "armv6l", "armv5tejl", "armv5tel", NULL },
.personality = PER_LINUX32,
+ .magic = "7f454c4601010100000000000000000002002800",
},
{
.name = "armv7l",
.platform = "arm",
.compatible = { "armv6l", "armv5tejl", "armv5tel", NULL },
.personality = PER_LINUX32,
+ .magic = "7f454c4601010100000000000000000002002800",
},
{
.name = "armv6l",
.platform = "arm",
.compatible = { "armv5tejl", "armv5tel", NULL },
.personality = PER_LINUX32,
+ .magic = "7f454c4601010100000000000000000002002800",
},
{
.name = "armv5tejl",
.platform = "arm",
.compatible = { "armv5tel", NULL },
.personality = PER_LINUX32,
+ .magic = "7f454c4601010100000000000000000002002800",
},
{
.name = "armv5tel",
.platform = "arm",
.personality = PER_LINUX32,
+ .magic = "7f454c4601010100000000000000000002002800",
},
// RISC-V
.name = "riscv64",
.platform = "riscv",
.personality = PER_LINUX,
+ .magic = "7f454c460201010000000000000000000200f300",
},
// The end
// Check if those two architectures are compatible
return pakfire_arch_is_compatible(native_arch, name);
}
+
+static char* find_interpreter(const char* path, const char* magic) {
+ FILE* f = fopen(path, "r");
+ if (!f)
+ return NULL;
+
+ char* line = NULL;
+ size_t length = 0;
+
+ int enabled = 0;
+ int match = 0;
+ char interpreter[PATH_MAX];
+
+ while (1) {
+ ssize_t bytes_read = getline(&line, &length, f);
+ if (bytes_read < 0)
+ break;
+
+ // Remove the newline
+ pakfire_remove_trailing_newline(line);
+
+ // Look for the "enabled" line
+ if (strcmp("enabled", line) == 0) {
+ enabled = 1;
+
+ // Store the interpreter for later
+ } else if (pakfire_string_startswith(line, "interpreter ")) {
+ pakfire_string_set(interpreter, line + strlen("interpreter "));
+
+ // If we found the magic, we check if it is a match
+ } else if (pakfire_string_startswith(line, "magic ")) {
+ const char* m = line + strlen("magic ");
+
+ if (strcmp(magic, m) == 0)
+ match = 1;
+ }
+ }
+
+ // Free resources
+ if (line)
+ free(line);
+ fclose(f);
+
+ // Return the interpreter if it is a match
+ if (enabled && match && *interpreter)
+ return strdup(interpreter);
+
+ // Otherwise return NULL
+ return NULL;
+}
+
+char* pakfire_arch_find_interpreter(const char* name) {
+ const struct pakfire_arch* arch = pakfire_arch_find(name);
+ if (!arch)
+ return NULL;
+
+ char* interpreter = NULL;
+
+ char* paths[] = {
+ "/proc/sys/fs/binfmt_misc", NULL,
+ };
+
+ FTS* f = fts_open(paths, FTS_NOCHDIR|FTS_NOSTAT, NULL);
+ if (!f)
+ goto ERROR;
+
+ for (;;) {
+ FTSENT* fent = fts_read(f);
+ if (!fent)
+ break;
+
+ // Only handle files
+ if (!(fent->fts_info & FTS_F))
+ continue;
+
+ interpreter = find_interpreter(fent->fts_path, arch->magic);
+
+ // End search if we have found a match
+ if (interpreter)
+ break;
+ }
+
+ERROR:
+ if (f)
+ fts_close(f);
+
+ return interpreter;
+}
return r;
}
+static int pakfire_mount_interpreter(Pakfire pakfire) {
+ char target[PATH_MAX];
+
+ // Can we emulate this architecture?
+ char* interpreter = pakfire_arch_find_interpreter(pakfire->arch);
+
+ // No interpreter required
+ if (!interpreter)
+ return 0;
+
+ DEBUG(pakfire, "Mounting interpreter %s for %s\n", interpreter, pakfire->arch);
+
+ // Where to mount this?
+ int r = pakfire_make_path(pakfire, target, interpreter);
+ if (r < 0)
+ return r;
+
+ // Create directory
+ r = pakfire_mkparentdir(target, 0);
+ if (r)
+ return r;
+
+ // Create an empty file
+ FILE* f = fopen(target, "w");
+ if (!f)
+ return 1;
+ fclose(f);
+
+ r = __mount(pakfire, interpreter, target, NULL, MS_BIND|MS_RDONLY, NULL);
+ if (r)
+ ERROR(pakfire, "Could not mount interpreter %s to %s: %s\n",
+ interpreter, target, strerror(errno));
+
+ return r;
+}
+
static void pakfire_free(Pakfire pakfire) {
DEBUG(pakfire, "Releasing Pakfire at %p\n", pakfire);
if (r)
goto ERROR;
+ // Mount the interpreter (if needed)
+ r = pakfire_mount_interpreter(p);
+ if (r)
+ goto ERROR;
+
// Make path for private files
char private_dir[PATH_MAX];
r = pakfire_make_path(p, private_dir, PAKFIRE_PRIVATE_DIR);