2
0

Bootstrap.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. //
  2. // Copyright © 2021 osy. All rights reserved.
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. //
  16. #include "Bootstrap.h"
  17. #include <dlfcn.h>
  18. #include <pthread.h>
  19. #include <sys/event.h>
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <unistd.h>
  23. typedef struct {
  24. int (*main)(int, const char *[]);
  25. int (*qemu_init)(int, const char *[], const char *[]);
  26. void (*qemu_main_loop)(void);
  27. void (*qemu_cleanup)(void);
  28. int (*swtpm_main)(int argc, const char *argv[], const char *prgname, const char *iface);
  29. } qemu_main_t;
  30. // http://mac-os-x.10953.n7.nabble.com/Ensure-NSTask-terminates-when-parent-application-does-td31477.html
  31. static void *WatchForParentTermination(void *args) {
  32. pid_t ppid = getppid(); // get parent pid
  33. int kq = kqueue();
  34. if (kq != -1) {
  35. struct kevent procEvent; // wait for parent to exit
  36. EV_SET(&procEvent, // kevent
  37. ppid, // ident
  38. EVFILT_PROC, // filter
  39. EV_ADD, // flags
  40. NOTE_EXIT, // fflags
  41. 0, // data
  42. 0); // udata
  43. kevent(kq, &procEvent, 1, &procEvent, 1, NULL);
  44. }
  45. exit(0);
  46. return NULL;
  47. }
  48. static int loadQemu(const char *dylibPath, qemu_main_t *funcs) {
  49. void *dlctx;
  50. if ((dlctx = dlopen(dylibPath, RTLD_LOCAL | RTLD_LAZY | RTLD_FIRST)) == NULL) {
  51. fprintf(stderr, "Error loading %s: %s\n", dylibPath, dlerror());
  52. return -1;
  53. }
  54. funcs->main = dlsym(dlctx, "main");
  55. funcs->qemu_init = dlsym(dlctx, "qemu_init");
  56. funcs->qemu_main_loop = dlsym(dlctx, "qemu_main_loop");
  57. funcs->qemu_cleanup = dlsym(dlctx, "qemu_cleanup");
  58. funcs->swtpm_main = dlsym(dlctx, "swtpm_main");
  59. if (funcs->main == NULL && funcs->swtpm_main == NULL && (funcs->qemu_init == NULL || funcs->qemu_main_loop == NULL || funcs->qemu_cleanup == NULL)) {
  60. fprintf(stderr, "Error resolving %s: %s\n", dylibPath, dlerror());
  61. return -1;
  62. }
  63. return 0;
  64. }
  65. static void __attribute__((noreturn)) runQemu(qemu_main_t *funcs, int argc, const char **argv, const char **envp) {
  66. if (funcs->qemu_init) {
  67. funcs->qemu_init(argc, argv, envp);
  68. }
  69. pthread_t thread;
  70. pthread_create(&thread, NULL, WatchForParentTermination, NULL);
  71. pthread_detach(thread);
  72. if (funcs->main) {
  73. funcs->main(argc, argv);
  74. } else if (funcs->swtpm_main) {
  75. funcs->swtpm_main(argc, argv, "swtpm", "socket");
  76. } else {
  77. funcs->qemu_main_loop();
  78. funcs->qemu_cleanup();
  79. }
  80. exit(0);
  81. }
  82. pid_t startQemuFork(const char *dylibPath, int argc, const char **argv, const char **envp, int newStdout, int newStderr) {
  83. qemu_main_t funcs = {};
  84. int res = loadQemu(dylibPath, &funcs);
  85. if (res < 0) {
  86. return res;
  87. }
  88. pid_t pid = fork();
  89. if (pid != 0) { // parent or error
  90. return pid;
  91. }
  92. // set up console output
  93. dup2(newStdout, STDOUT_FILENO);
  94. dup2(newStderr, STDERR_FILENO);
  95. close(newStdout);
  96. close(newStderr);
  97. // set thread QoS
  98. pthread_set_qos_class_self_np(QOS_CLASS_USER_INTERACTIVE, 0);
  99. // launch qemu
  100. runQemu(&funcs, argc, argv, envp);
  101. }
  102. int startQemuProcess(const char *dylibPath, int argc, const char **argv, const char **envp) {
  103. qemu_main_t funcs = {};
  104. int res = loadQemu(dylibPath, &funcs);
  105. if (res < 0) {
  106. return res;
  107. }
  108. // launch qemu
  109. runQemu(&funcs, argc, argv, envp);
  110. return 0;
  111. }