|
| 1 | +#define _GNU_SOURCE |
1 | 2 | #include <stdlib.h>
|
2 | 3 | #include <string.h>
|
3 | 4 | #include <stdio.h>
|
4 |
| -#include <unistd.h> |
5 |
| -#include <glib.h> |
| 5 | +#include <spawn.h> |
| 6 | +#include <sys/types.h> |
| 7 | +#include <sys/wait.h> |
| 8 | +#include <signal.h> |
6 | 9 | #include <glib-object.h>
|
7 | 10 | #include <luna-service2/lunaservice.h>
|
8 | 11 | #include <pbnjson.h>
|
@@ -32,49 +35,128 @@ char *hyperiond_cmdline(char *args)
|
32 | 35 | return tmp;
|
33 | 36 | }
|
34 | 37 |
|
35 |
| -char *hyperiond_start_cmdline() |
| 38 | +int daemon_start(pid_t *pid) |
36 | 39 | {
|
37 |
| - // Run hyperiond in background |
38 |
| - return hyperiond_cmdline("&"); |
| 40 | + int res = 0; |
| 41 | + |
| 42 | + char *env_library_path; |
| 43 | + char *env_armcap; |
| 44 | + char *application_executable_path; |
| 45 | + |
| 46 | + asprintf(&env_library_path, "LD_LIBRARY_PATH=%s", HYPERION_PATH); |
| 47 | + asprintf(&env_armcap, "OPENSSL_armcap=%d", 0); |
| 48 | + asprintf(&application_executable_path, "%s/hyperiond", HYPERION_PATH); |
| 49 | + |
| 50 | + char *env_vars[] = {env_library_path, env_armcap, NULL}; |
| 51 | + char *argv[] = {application_executable_path}; |
| 52 | + |
| 53 | + res = posix_spawn(pid, application_executable_path, NULL, NULL, argv, env_vars); |
| 54 | + DBG("posix_spawn: pid=%d, application_path=%s, env={%s,%s}", |
| 55 | + *pid, application_executable_path, env_library_path, env_armcap); |
| 56 | + |
| 57 | + free(env_library_path); |
| 58 | + free(env_armcap); |
| 59 | + free(application_executable_path); |
| 60 | + |
| 61 | + return res; |
| 62 | +} |
| 63 | + |
| 64 | +void *execution_task(void *data) |
| 65 | +{ |
| 66 | + int res = 0; |
| 67 | + int status = 0; |
| 68 | + |
| 69 | + service_t *service = (service_t *)data; |
| 70 | + |
| 71 | + do { |
| 72 | + if (service->daemon_pid <= 0) { |
| 73 | + WARN("Invalid daemon PID: %d - exiting execution loop"); |
| 74 | + break; |
| 75 | + } |
| 76 | + res = waitpid(service->daemon_pid, &status, WNOHANG); |
| 77 | + DBG("waitpid: pid=%d, status=%d, res=%d", service->daemon_pid, status, res); |
| 78 | + |
| 79 | + if (res == -1) { |
| 80 | + ERR("waitpid: res=%d", res); |
| 81 | + break; |
| 82 | + } |
| 83 | + |
| 84 | + if (WIFEXITED(status)) { |
| 85 | + INFO("Child status: exited, status=%d\n", WEXITSTATUS(status)); |
| 86 | + } else if (WIFSIGNALED(status)) { |
| 87 | + INFO("Child status: killed by signal %d\n", WTERMSIG(status)); |
| 88 | + } else if (WIFSTOPPED(status)) { |
| 89 | + INFO("Child status: stopped by signal %d\n", WSTOPSIG(status)); |
| 90 | + } else if (WIFCONTINUED(status)) { |
| 91 | + INFO("Child status: continued\n"); |
| 92 | + } |
| 93 | + |
| 94 | + usleep(200 * 1000); // 200ms |
| 95 | + |
| 96 | + } while (!WIFEXITED(status) && !WIFSIGNALED(status)); |
| 97 | + |
| 98 | + service->daemon_pid = 0; |
| 99 | + return NULL; |
39 | 100 | }
|
40 | 101 |
|
41 | 102 | char *hyperiond_version_cmdline()
|
42 | 103 | {
|
43 | 104 | return hyperiond_cmdline("--version");
|
44 | 105 | }
|
45 | 106 |
|
| 107 | +bool is_running(pid_t pid) |
| 108 | +{ |
| 109 | + return (pid > 0); |
| 110 | +} |
| 111 | + |
46 | 112 | int hyperiond_start(service_t* service)
|
47 | 113 | {
|
| 114 | + int res = 0; |
48 | 115 | if (!is_elevated()) {
|
49 | 116 | return 1;
|
50 |
| - } else if (service->running) { |
| 117 | + } else if (is_running(service->daemon_pid)) { |
51 | 118 | return 2;
|
52 | 119 | }
|
53 | 120 |
|
54 |
| - service->running = true; |
55 |
| - // TODO: system() ftw |
56 |
| - char *command = hyperiond_start_cmdline(); |
57 |
| - int res = system(command); |
| 121 | + res = daemon_start(&service->daemon_pid); |
| 122 | + DBG("hyperiond_start: daemon_start -> PID=%d", service->daemon_pid); |
58 | 123 |
|
59 | 124 | if (res != 0) {
|
60 |
| - service->running = false; |
| 125 | + ERR("hyperiond_start: Failed daemon_start with res=%d", res); |
61 | 126 | return 3;
|
62 | 127 | }
|
63 | 128 |
|
| 129 | + res = pthread_create(&service->execution_thread, NULL, execution_task, service); |
| 130 | + if (res != 0) { |
| 131 | + ERR("hyperiond_start: pthread_create failed, res=%d", res); |
| 132 | + return 4; |
| 133 | + } |
| 134 | + |
64 | 135 | return 0;
|
65 | 136 | }
|
66 | 137 |
|
67 | 138 | int hyperiond_stop(service_t* service)
|
68 | 139 | {
|
| 140 | + int res = 0; |
| 141 | + |
69 | 142 | if (!is_elevated()) {
|
70 | 143 | return 1;
|
71 |
| - } else if (!service->running) { |
| 144 | + } else if (!is_running(service->daemon_pid)) { |
72 | 145 | return 2;
|
73 | 146 | }
|
74 | 147 |
|
75 |
| - // TODO: system() ftw |
76 |
| - system("killall -9 hyperiond"); |
77 |
| - service->running = false; |
| 148 | + res = kill(service->daemon_pid, SIGTERM); |
| 149 | + if (res != 0) { |
| 150 | + ERR("hyperiond_stop: kill failed, res=%d", res); |
| 151 | + return 3; |
| 152 | + } |
| 153 | + |
| 154 | + res = pthread_join(service->execution_thread, NULL); |
| 155 | + if (res != 0) { |
| 156 | + ERR("hyperiond_stop: pthread_join failed, res=%d", res); |
| 157 | + return 4; |
| 158 | + } |
| 159 | + service->execution_thread = NULL; |
78 | 160 |
|
79 | 161 | return 0;
|
80 | 162 | }
|
@@ -131,8 +213,13 @@ bool service_method_start(LSHandle* sh, LSMessage* msg, void* data)
|
131 | 213 | jobject_set(jobj, j_cstr_to_buffer("status"), jstring_create("Hyperion.NG was already running"));
|
132 | 214 | break;
|
133 | 215 | case 3:
|
134 |
| - jobject_set(jobj, j_cstr_to_buffer("status"), jstring_create("Hyperion.NG failed to start, reason: Unknown")); |
| 216 | + jobject_set(jobj, j_cstr_to_buffer("status"), jstring_create("Hyperion.NG failed to start, posix_spawn failed")); |
| 217 | + break; |
| 218 | + case 4: |
| 219 | + jobject_set(jobj, j_cstr_to_buffer("status"), jstring_create("Hyperion.NG failed to start, pthread_create failed")); |
135 | 220 | break;
|
| 221 | + default: |
| 222 | + jobject_set(jobj, j_cstr_to_buffer("status"), jstring_create("Hyperion.NG failed to start, reason: Unknown")); |
136 | 223 | }
|
137 | 224 | LSMessageReply(sh, msg, jvalue_tostring_simple(jobj), &lserror);
|
138 | 225 |
|
@@ -160,6 +247,8 @@ bool service_method_stop(LSHandle* sh, LSMessage* msg, void* data)
|
160 | 247 | case 2:
|
161 | 248 | jobject_set(jobj, j_cstr_to_buffer("status"), jstring_create("Hyperion.NG was not running"));
|
162 | 249 | break;
|
| 250 | + default: |
| 251 | + jobject_set(jobj, j_cstr_to_buffer("status"), jstring_create("Hyperion.NG failed to stop, reason: Unknown")); |
163 | 252 | }
|
164 | 253 | LSMessageReply(sh, msg, jvalue_tostring_simple(jobj), &lserror);
|
165 | 254 |
|
@@ -201,7 +290,7 @@ bool service_method_status(LSHandle* sh, LSMessage* msg, void* data)
|
201 | 290 |
|
202 | 291 | jvalue_ref jobj = jobject_create();
|
203 | 292 | jobject_set(jobj, j_cstr_to_buffer("returnValue"), jboolean_create(true));
|
204 |
| - jobject_set(jobj, j_cstr_to_buffer("running"), jboolean_create(service->running)); |
| 293 | + jobject_set(jobj, j_cstr_to_buffer("running"), jboolean_create(is_running(service->daemon_pid))); |
205 | 294 | jobject_set(jobj, j_cstr_to_buffer("elevated"), jboolean_create(is_elevated()));
|
206 | 295 |
|
207 | 296 | LSMessageReply(sh, msg, jvalue_tostring_simple(jobj), &lserror);
|
@@ -240,11 +329,11 @@ LSMethod methods[] = {
|
240 | 329 |
|
241 | 330 | int main()
|
242 | 331 | {
|
243 |
| - service_t service; |
| 332 | + service_t service = {0}; |
244 | 333 | LSHandle *handle = NULL;
|
245 | 334 | LSError lserror;
|
246 | 335 |
|
247 |
| - service.running = FALSE; |
| 336 | + service.daemon_pid = 0; |
248 | 337 | service.hyperiond_version = NULL;
|
249 | 338 |
|
250 | 339 | LSErrorInit(&lserror);
|
|
0 commit comments