123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- //
- // Copyright © 2021 osy. All rights reserved.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- //
- #include "Bootstrap.h"
- #include <dlfcn.h>
- #include <pthread.h>
- #include <sys/event.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- typedef struct {
- int (*main)(int, const char *[]);
- int (*qemu_init)(int, const char *[], const char *[]);
- void (*qemu_main_loop)(void);
- void (*qemu_cleanup)(void);
- int (*swtpm_main)(int argc, const char *argv[], const char *prgname, const char *iface);
- } qemu_main_t;
- // http://mac-os-x.10953.n7.nabble.com/Ensure-NSTask-terminates-when-parent-application-does-td31477.html
- static void *WatchForParentTermination(void *args) {
- pid_t ppid = getppid(); // get parent pid
- int kq = kqueue();
- if (kq != -1) {
- struct kevent procEvent; // wait for parent to exit
- EV_SET(&procEvent, // kevent
- ppid, // ident
- EVFILT_PROC, // filter
- EV_ADD, // flags
- NOTE_EXIT, // fflags
- 0, // data
- 0); // udata
- kevent(kq, &procEvent, 1, &procEvent, 1, NULL);
- }
- exit(0);
- return NULL;
- }
- static int loadQemu(const char *dylibPath, qemu_main_t *funcs) {
- void *dlctx;
-
- if ((dlctx = dlopen(dylibPath, RTLD_LOCAL | RTLD_LAZY | RTLD_FIRST)) == NULL) {
- fprintf(stderr, "Error loading %s: %s\n", dylibPath, dlerror());
- return -1;
- }
- funcs->main = dlsym(dlctx, "main");
- funcs->qemu_init = dlsym(dlctx, "qemu_init");
- funcs->qemu_main_loop = dlsym(dlctx, "qemu_main_loop");
- funcs->qemu_cleanup = dlsym(dlctx, "qemu_cleanup");
- funcs->swtpm_main = dlsym(dlctx, "swtpm_main");
- if (funcs->main == NULL && funcs->swtpm_main == NULL && (funcs->qemu_init == NULL || funcs->qemu_main_loop == NULL || funcs->qemu_cleanup == NULL)) {
- fprintf(stderr, "Error resolving %s: %s\n", dylibPath, dlerror());
- return -1;
- }
- return 0;
- }
- static void __attribute__((noreturn)) runQemu(qemu_main_t *funcs, int argc, const char **argv, const char **envp) {
- if (funcs->qemu_init) {
- funcs->qemu_init(argc, argv, envp);
- }
- pthread_t thread;
- pthread_create(&thread, NULL, WatchForParentTermination, NULL);
- pthread_detach(thread);
- if (funcs->main) {
- funcs->main(argc, argv);
- } else if (funcs->swtpm_main) {
- funcs->swtpm_main(argc, argv, "swtpm", "socket");
- } else {
- funcs->qemu_main_loop();
- funcs->qemu_cleanup();
- }
- exit(0);
- }
- pid_t startQemuFork(const char *dylibPath, int argc, const char **argv, const char **envp, int newStdout, int newStderr) {
- qemu_main_t funcs = {};
- int res = loadQemu(dylibPath, &funcs);
- if (res < 0) {
- return res;
- }
- pid_t pid = fork();
- if (pid != 0) { // parent or error
- return pid;
- }
- // set up console output
- dup2(newStdout, STDOUT_FILENO);
- dup2(newStderr, STDERR_FILENO);
- close(newStdout);
- close(newStderr);
- // set thread QoS
- pthread_set_qos_class_self_np(QOS_CLASS_USER_INTERACTIVE, 0);
- // launch qemu
- runQemu(&funcs, argc, argv, envp);
- }
- int startQemuProcess(const char *dylibPath, int argc, const char **argv, const char **envp) {
- qemu_main_t funcs = {};
- int res = loadQemu(dylibPath, &funcs);
- if (res < 0) {
- return res;
- }
- // launch qemu
- runQemu(&funcs, argc, argv, envp);
- return 0;
- }
|