1 // This is a supervisor program that handles start/stop/restart of
2 // the various Citadel System components, when we are running in
5 // Copyright (c) 2021 by the citadel.org team
7 // This program is open source software. Use, duplication, or disclosure
8 // is subject to the terms of the GNU General Public License, version 3.
9 // The program is distributed without any warranty, expressed or implied.
11 #define CTDL_DIR "/citadel-data"
21 #include <sys/types.h>
27 int shutting_down = 0;
29 // Call this instead of exit() just for common diagnostics etc.
30 void ctdlvisor_exit(int code) {
31 printf("ctdlvisor: exit code %d\n", code);
36 // Interrupting this program with a signal will begin an orderly shutdown.
37 void signal_handler(int signal) {
38 fprintf(stderr, "ctdlvisor: caught signal %d\n", signal);
40 while(shutting_down) {
41 fprintf(stderr, "ctdlvisor: already shutting down\n");
47 char *what_exited = NULL;
50 kill(citserver_pid, SIGTERM);
51 kill(webcit_pid, SIGTERM);
52 kill(webcits_pid, SIGTERM);
54 fprintf(stderr, "ctdlvisor: waiting for all child process to exit...\n");
55 who_exited = waitpid(-1, &status, 0);
56 if (who_exited == citserver_pid) {
57 what_exited = "Citadel Server";
59 else if (who_exited == webcit_pid) {
60 what_exited = "WebCit HTTP";
62 else if (who_exited == webcits_pid) {
63 what_exited = "WebCit HTTPS";
66 what_exited = "unknown";
68 if (who_exited >= 0) {
69 fprintf(stderr, "ctdlvisor: %d (%s) ended, status=%d\n", who_exited, what_exited, status);
71 } while (who_exited >= 0);
76 void detach_from_tty(void) {
77 signal(SIGHUP, SIG_IGN);
78 signal(SIGINT, SIG_IGN);
79 signal(SIGQUIT, SIG_IGN);
81 setsid(); // become our own process group leader
83 if ( (freopen("/dev/null", "r", stdin) != stdin) ||
84 (freopen("/dev/null", "w", stdout) != stdout) ||
85 (freopen("/dev/null", "w", stderr) != stderr)
87 fprintf(stderr, "sysdep: unable to reopen stdio: %s\n", strerror(errno));
92 pid_t start_citadel() {
95 fprintf(stderr, "ctdlvisor: executing citserver\n");
97 execlp("/usr/local/citadel/citserver", "citserver", "-x9", "-h", CTDL_DIR, NULL);
101 fprintf(stderr, "ctdlvisor: citserver running on pid=%d\n", pid);
107 pid_t start_webcit() {
110 fprintf(stderr, "ctdlvisor: executing webcit (http)\n");
112 execlp("/usr/local/webcit/webcit", "webcit", "-x9", "-p", "80", "uds", CTDL_DIR, NULL);
116 fprintf(stderr, "ctdlvisor: webcit (HTTP) running on pid=%d\n", pid);
122 pid_t start_webcits() {
125 fprintf(stderr, "ctdlvisor: executing webcit (https)\n");
127 execlp("/usr/local/webcit/webcit", "webcit", "-x9", "-s", "-p", "443", "uds", CTDL_DIR, NULL);
131 fprintf(stderr, "ctdlvisor: webcit (HTTPS) running on pid=%d\n", pid);
137 void main_loop(void) {
140 int citserver_exit_code = 0;
143 who_exited = waitpid(-1, &status, 0);
144 fprintf(stderr, "ctdlvisor: pid=%d exited, status=%d, exitcode=%d\n", who_exited, status, WEXITSTATUS(status));
146 // A *deliberate* exit of citserver will cause ctdlvisor to shut the whole container down.
147 // If it crashes, however, we will start it back up.
148 if (who_exited == citserver_pid) {
149 citserver_exit_code = WEXITSTATUS(status);
150 if ((WIFEXITED(status)) && (citserver_exit_code == 0)) {
151 fprintf(stderr, "ctdlvisor: citserver exited normally - ending container session\n");
153 kill(webcit_pid, SIGTERM);
154 kill(webcits_pid, SIGTERM);
156 else if ((WIFEXITED(status)) && (citserver_exit_code >= 101) && (citserver_exit_code <= 109)) {
157 fprintf(stderr, "ctdlvisor: citserver exited intentionally - ending container session\n");
159 kill(webcit_pid, SIGTERM);
160 kill(webcits_pid, SIGTERM);
163 if (WIFSIGNALED(status)) {
164 fprintf(stderr, "ctdlvisor: citserver crashed on signal %d\n", WTERMSIG(status));
166 citserver_pid = start_citadel();
170 // WebCit processes are restarted if they exit for any reason.
171 if ((who_exited == webcit_pid) && (!shutting_down)) webcit_pid = start_webcit();
172 if ((who_exited == webcits_pid) && (!shutting_down)) webcits_pid = start_webcits();
174 // If we somehow end up in an endless loop, at least slow it down.
177 } while (who_exited >= 0);
178 ctdlvisor_exit(citserver_exit_code);
182 void install_client_link(void) { // FIXME this is all furkokt and needs to be rethought now that it's docker and not appimage
185 char path_to_link[PATH_MAX];
186 snprintf(path_to_link, sizeof path_to_link, CTDL_DIR "citadel");
187 fp = fopen(path_to_link, "w");
189 fprintf(stderr, "%s\n", strerror(errno));
193 fprintf(fp, "#!/bin/bash\n"
195 "export LD_LIBRARY_PATH=${APPDIR}/usr/bin:$LD_LIBRARY_PATH\n"
196 "export PATH=${APPDIR}/usr/bin:$PATH\n"
202 fchmod(fileno(fp), 0755);
207 int main(int argc, char **argv) {
209 int migrate_mode = 0;
211 fprintf(stderr, "ctdlvisor: Welcome to the Citadel System running in a container.\n");
212 fprintf(stderr, "ctdlvisor: command line arguments: ");
213 for (a=0; a<argc; ++a) {
214 fprintf(stderr, "%s ", argv[a]);
216 fprintf(stderr, "\n");
225 for (a=0; a<4; ++a) {
226 mkdir(dirs[a], 0777);
227 if (access(dirs[a], R_OK|W_OK|X_OK)) {
228 fprintf(stderr, "ctdlvisor: %s: %s\n", dirs[a], strerror(errno));
229 ctdlvisor_exit(errno);
232 fprintf(stderr, "ctdlvisor: %s is writable\n", dirs[a]);
236 symlink(CTDL_DIR "/keys", "/usr/local/webcit/keys");
238 /* parse command-line arguments */
239 while ((a=getopt(argc, argv, "cm")) != EOF) switch(a) {
241 // test this binary for compatibility and exit
243 fprintf(stderr, "%s: binary compatibility confirmed\n", argv[0]);
247 // run ctdlmigrate only
252 // any other parameter makes it crash and burn
254 fprintf(stderr, "usage\n");
259 signal(SIGHUP, signal_handler);
261 // "migrate mode" means we just start the server and then run ctdlmigrate interactively.
263 citserver_pid = start_citadel();
264 fprintf(stderr, "ctdlvisor: waiting a moment for citserver to initialize...\n");
267 sprintf(bin, "/usr/local/citadel/ctdlmigrate -h %s", CTDL_DIR);
269 kill(citserver_pid, SIGTERM);
272 // Otherwise, it's just a normal happy day in Citadel land.
274 signal(SIGTERM, signal_handler);
275 signal(SIGINT, signal_handler);
276 signal(SIGQUIT, signal_handler);
278 citserver_pid = start_citadel(); // start Citadel Server
279 webcit_pid = start_webcit(); // start WebCit HTTP
280 webcits_pid = start_webcits(); // start WebCit HTTPS
282 install_client_link();