trinidad_init_services 1.1.3 → 1.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. data/.gitignore +5 -0
  2. data/Gemfile +3 -0
  3. data/History.txt +6 -0
  4. data/README.md +95 -0
  5. data/Rakefile +9 -58
  6. data/bin/trinidad_init_service +3 -4
  7. data/init.d/trinidad.erb +33 -12
  8. data/jsvc-unix-src/CHANGES.txt +62 -0
  9. data/jsvc-unix-src/INSTALL.txt +81 -0
  10. data/jsvc-unix-src/Makedefs.in +32 -0
  11. data/jsvc-unix-src/Makefile.in +42 -0
  12. data/jsvc-unix-src/configure +4417 -0
  13. data/jsvc-unix-src/configure.in +141 -0
  14. data/jsvc-unix-src/man/README +20 -0
  15. data/jsvc-unix-src/man/fetch.sh +36 -0
  16. data/jsvc-unix-src/man/jsvc.1.xml +214 -0
  17. data/jsvc-unix-src/native/.indent.pro +7 -0
  18. data/jsvc-unix-src/native/Makefile.in +46 -0
  19. data/jsvc-unix-src/native/arguments.c +476 -0
  20. data/jsvc-unix-src/native/arguments.h +94 -0
  21. data/jsvc-unix-src/native/debug.c +87 -0
  22. data/jsvc-unix-src/native/debug.h +65 -0
  23. data/jsvc-unix-src/native/dso-dlfcn.c +62 -0
  24. data/jsvc-unix-src/native/dso-dyld.c +153 -0
  25. data/jsvc-unix-src/native/dso.h +38 -0
  26. data/jsvc-unix-src/native/help.c +106 -0
  27. data/jsvc-unix-src/native/help.h +24 -0
  28. data/jsvc-unix-src/native/home.c +265 -0
  29. data/jsvc-unix-src/native/home.h +47 -0
  30. data/jsvc-unix-src/native/java.c +608 -0
  31. data/jsvc-unix-src/native/java.h +35 -0
  32. data/jsvc-unix-src/native/jsvc-unix.c +1267 -0
  33. data/jsvc-unix-src/native/jsvc.h +55 -0
  34. data/jsvc-unix-src/native/location.c +151 -0
  35. data/jsvc-unix-src/native/location.h +29 -0
  36. data/jsvc-unix-src/native/locks.c +52 -0
  37. data/jsvc-unix-src/native/locks.h +40 -0
  38. data/jsvc-unix-src/native/replace.c +121 -0
  39. data/jsvc-unix-src/native/replace.h +39 -0
  40. data/jsvc-unix-src/native/signals.c +105 -0
  41. data/jsvc-unix-src/native/signals.h +34 -0
  42. data/jsvc-unix-src/native/version.h +63 -0
  43. data/jsvc-unix-src/support/apfunctions.m4 +110 -0
  44. data/jsvc-unix-src/support/apjava.m4 +94 -0
  45. data/jsvc-unix-src/support/apsupport.m4 +155 -0
  46. data/jsvc-unix-src/support/buildconf.sh +33 -0
  47. data/jsvc-unix-src/support/config.guess +1371 -0
  48. data/jsvc-unix-src/support/config.sub +1760 -0
  49. data/jsvc-unix-src/support/install.sh +128 -0
  50. data/jsvc-unix-src/support/mkdist.sh +104 -0
  51. data/lib/trinidad/daemon.rb +31 -0
  52. data/lib/trinidad_init_services.rb +2 -30
  53. data/lib/trinidad_init_services/configuration.rb +91 -14
  54. data/lib/trinidad_init_services/version.rb +5 -0
  55. data/spec/spec_helper.rb +5 -6
  56. data/spec/trinidad_daemon_spec.rb +0 -1
  57. data/spec/trinidad_init_services/configuration_spec.rb +34 -1
  58. data/trinidad_init_services.gemspec +14 -51
  59. metadata +146 -87
  60. data/README +0 -63
  61. data/trinidad-libs/jsvc_linux +0 -0
@@ -0,0 +1,35 @@
1
+ /* Licensed to the Apache Software Foundation (ASF) under one or more
2
+ * contributor license agreements. See the NOTICE file distributed with
3
+ * this work for additional information regarding copyright ownership.
4
+ * The ASF licenses this file to You under the Apache License, Version 2.0
5
+ * (the "License"); you may not use this file except in compliance with
6
+ * the License. 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
+
17
+ /* @version $Id: java.h 1130635 2011-06-02 16:29:44Z mturk $ */
18
+ #ifndef __JSVC_JAVA_H__
19
+ #define __JSVC_JAVA_H__
20
+
21
+ #define LOADER "org/apache/commons/daemon/support/DaemonLoader"
22
+
23
+ char *java_library(arg_data *args, home_data *data);
24
+ bool java_init(arg_data *args, home_data *data);
25
+ bool java_destroy(void);
26
+ bool java_load(arg_data *args);
27
+ bool java_signal(void);
28
+ bool java_start(void);
29
+ bool java_stop(void);
30
+ bool java_version(void);
31
+ bool java_check(arg_data *args);
32
+ bool JVM_destroy(int exit);
33
+
34
+ #endif /* __JSVC_JAVA_H__ */
35
+
@@ -0,0 +1,1267 @@
1
+ /* Licensed to the Apache Software Foundation (ASF) under one or more
2
+ * contributor license agreements. See the NOTICE file distributed with
3
+ * this work for additional information regarding copyright ownership.
4
+ * The ASF licenses this file to You under the Apache License, Version 2.0
5
+ * (the "License"); you may not use this file except in compliance with
6
+ * the License. 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
+
17
+ /* @version $Id: jsvc-unix.c 1293002 2012-02-23 22:48:24Z mturk $ */
18
+ #include "jsvc.h"
19
+
20
+ #include <signal.h>
21
+ #include <unistd.h>
22
+ #include <sys/types.h>
23
+ #include <sys/stat.h>
24
+ #include <sys/wait.h>
25
+ #include <fcntl.h>
26
+ #include <stdio.h>
27
+ #include <string.h>
28
+ #include <pwd.h>
29
+ #include <grp.h>
30
+ #include <syslog.h>
31
+ #include <errno.h>
32
+ #ifdef OS_LINUX
33
+ #include <sys/prctl.h>
34
+ #include <sys/syscall.h>
35
+ #define _LINUX_FS_H
36
+ #include <linux/capability.h>
37
+ #ifdef HAVE_LIBCAP
38
+ #include <sys/capability.h>
39
+ #endif
40
+ #endif
41
+ #include <time.h>
42
+
43
+ #ifdef OS_CYGWIN
44
+ #include <sys/fcntl.h>
45
+ #define F_ULOCK 0 /* Unlock a previously locked region */
46
+ #define F_LOCK 1 /* Lock a region for exclusive use */
47
+ #endif
48
+ extern char **environ;
49
+
50
+ static mode_t envmask; /* mask to create the files */
51
+
52
+ pid_t controlled = 0; /* the child process pid */
53
+ pid_t logger_pid = 0; /* the logger process pid */
54
+ static bool stopping = false;
55
+ static bool doreload = false;
56
+ static bool doreopen = false;
57
+ static bool dosignal = false;
58
+ typedef void (*sighandler_t)(int);
59
+ static sighandler_t handler_int = NULL;
60
+ static sighandler_t handler_usr1 = NULL;
61
+ static sighandler_t handler_usr2 = NULL;
62
+ static sighandler_t handler_hup = NULL;
63
+ static sighandler_t handler_trm = NULL;
64
+
65
+ static int run_controller(arg_data *args, home_data *data, uid_t uid,
66
+ gid_t gid);
67
+ static void set_output(char *outfile, char *errfile, bool redirectstdin,
68
+ char *procname);
69
+
70
+ #ifdef OS_CYGWIN
71
+ /*
72
+ * File locking routine
73
+ */
74
+ static int lockf(int fildes, int function, off_t size)
75
+ {
76
+ struct flock buf;
77
+
78
+ switch (function) {
79
+ case F_LOCK:
80
+ buf.l_type = F_WRLCK;
81
+ break;
82
+ case F_ULOCK:
83
+ buf.l_type = F_UNLCK;
84
+ break;
85
+ default:
86
+ return -1;
87
+ }
88
+ buf.l_whence = 0;
89
+ buf.l_start = 0;
90
+ buf.l_len = size;
91
+
92
+ return fcntl(fildes, F_SETLK, &buf);
93
+ }
94
+
95
+ #endif
96
+
97
+ static void handler(int sig)
98
+ {
99
+ switch (sig) {
100
+ case SIGTERM:
101
+ log_debug("Caught SIGTERM: Scheduling a shutdown");
102
+ if (stopping == true) {
103
+ log_error("Shutdown or reload already scheduled");
104
+ }
105
+ else {
106
+ stopping = true;
107
+ }
108
+ break;
109
+ case SIGINT:
110
+ log_debug("Caught SIGINT: Scheduling a shutdown");
111
+ if (stopping == true) {
112
+ log_error("Shutdown or reload already scheduled");
113
+ }
114
+ else {
115
+ stopping = true;
116
+ }
117
+ break;
118
+ case SIGHUP:
119
+ log_debug("Caught SIGHUP: Scheduling a reload");
120
+ if (stopping == true) {
121
+ log_error("Shutdown or reload already scheduled");
122
+ }
123
+ else {
124
+ stopping = true;
125
+ doreload = true;
126
+ }
127
+ break;
128
+ case SIGUSR1:
129
+ log_debug("Caught SIGUSR1: Reopening logs");
130
+ doreopen = true;
131
+ break;
132
+ case SIGUSR2:
133
+ log_debug("Caught SIGUSR2: Scheduling a custom signal");
134
+ dosignal = true;
135
+ break;
136
+ default:
137
+ log_debug("Caught unknown signal %d", sig);
138
+ break;
139
+ }
140
+ }
141
+
142
+ /* user and group */
143
+ static int set_user_group(const char *user, int uid, int gid)
144
+ {
145
+ if (user != NULL) {
146
+ if (setgid(gid) != 0) {
147
+ log_error("Cannot set group id for user '%s'", user);
148
+ return -1;
149
+ }
150
+ if (initgroups(user, gid) != 0) {
151
+ if (getuid() != uid) {
152
+ log_error("Cannot set supplement group list for user '%s'",
153
+ user);
154
+ return -1;
155
+ }
156
+ else
157
+ log_debug("Cannot set supplement group list for user '%s'",
158
+ user);
159
+ }
160
+ if (getuid() == uid) {
161
+ log_debug("No need to change user to '%s'!", user);
162
+ return 0;
163
+ }
164
+ if (setuid(uid) != 0) {
165
+ log_error("Cannot set user id for user '%s'", user);
166
+ return -1;
167
+ }
168
+ log_debug("user changed to '%s'", user);
169
+ }
170
+ return 0;
171
+ }
172
+
173
+ /* Set linux capability, user and group */
174
+ #ifdef OS_LINUX
175
+ /* CAPSALL is to allow to read/write at any location */
176
+ #define LEGACY_CAPSALL (1 << CAP_NET_BIND_SERVICE) + \
177
+ (1 << CAP_SETUID) + \
178
+ (1 << CAP_SETGID) + \
179
+ (1 << CAP_DAC_READ_SEARCH) + \
180
+ (1 << CAP_DAC_OVERRIDE)
181
+
182
+ #define LEGACY_CAPSMAX (1 << CAP_NET_BIND_SERVICE) + \
183
+ (1 << CAP_DAC_READ_SEARCH) + \
184
+ (1 << CAP_DAC_OVERRIDE)
185
+
186
+ /* That a more reasonable configuration */
187
+ #define LEGACY_CAPS (1 << CAP_NET_BIND_SERVICE) + \
188
+ (1 << CAP_DAC_READ_SEARCH) + \
189
+ (1 << CAP_SETUID) + \
190
+ (1 << CAP_SETGID)
191
+
192
+ /* probably the only one Java could use */
193
+ #define LEGACY_CAPSMIN (1 << CAP_NET_BIND_SERVICE) + \
194
+ (1 << CAP_DAC_READ_SEARCH)
195
+
196
+ #define LEGACY_CAP_VERSION 0x19980330
197
+ static int set_legacy_caps(int caps)
198
+ {
199
+ struct __user_cap_header_struct caphead;
200
+ struct __user_cap_data_struct cap;
201
+
202
+ memset(&caphead, 0, sizeof caphead);
203
+ caphead.version = LEGACY_CAP_VERSION;
204
+ caphead.pid = 0;
205
+ memset(&cap, 0, sizeof cap);
206
+ cap.effective = caps;
207
+ cap.permitted = caps;
208
+ cap.inheritable = caps;
209
+ if (syscall(__NR_capset, &caphead, &cap) < 0) {
210
+ log_error("set_caps: failed to set capabilities");
211
+ log_error("check that your kernel supports capabilities");
212
+ return -1;
213
+ }
214
+ return 0;
215
+ }
216
+
217
+ #ifdef HAVE_LIBCAP
218
+ static cap_value_t caps_std[] = {
219
+ CAP_NET_BIND_SERVICE,
220
+ CAP_SETUID,
221
+ CAP_SETGID,
222
+ CAP_DAC_READ_SEARCH
223
+ };
224
+
225
+ static cap_value_t caps_min[] = {
226
+ CAP_NET_BIND_SERVICE,
227
+ CAP_DAC_READ_SEARCH
228
+ };
229
+
230
+ #define CAPS 1
231
+ #define CAPSMIN 2
232
+
233
+
234
+ typedef int (*fd_cap_free)(void *);
235
+ typedef cap_t (*fd_cap_init)(void);
236
+ typedef int (*fd_cap_clear)(cap_t);
237
+ typedef int (*fd_cap_get_flag)(cap_t, cap_value_t, cap_flag_t, cap_flag_value_t *);
238
+ typedef int (*fd_cap_set_flag)(cap_t, cap_flag_t, int, const cap_value_t *, cap_flag_value_t);
239
+ typedef int (*fd_cap_set_proc)(cap_t);
240
+
241
+ static dso_handle hlibcap = NULL;
242
+ static fd_cap_free fp_cap_free;
243
+ static fd_cap_init fp_cap_init;
244
+ static fd_cap_clear fp_cap_clear;
245
+ static fd_cap_get_flag fp_cap_get_flag;
246
+ static fd_cap_set_flag fp_cap_set_flag;
247
+ static fd_cap_set_proc fp_cap_set_proc;
248
+
249
+ static const char *libcap_locs[] = {
250
+ "/lib/libcap.so.2",
251
+ "/lib/libcap.so.1",
252
+ "/lib/libcap.so",
253
+ "/usr/lib/libcap.so.2",
254
+ "/usr/lib/libcap.so.1",
255
+ "/usr/lib/libcap.so",
256
+ NULL
257
+ };
258
+
259
+ static int ld_libcap(void)
260
+ {
261
+ int i = 0;
262
+ dso_handle dso = NULL;
263
+ #define CAP_LDD(name) \
264
+ if ((fp_##name = dso_symbol(dso, #name)) == NULL) { \
265
+ log_error("cannot locate " #name " in libcap.so -- %s", dso_error()); \
266
+ dso_unlink(dso); \
267
+ return -1; \
268
+ } else log_debug("loaded " #name " from libcap.")
269
+
270
+ if (hlibcap != NULL)
271
+ return 0;
272
+ while (libcap_locs[i] && dso == NULL) {
273
+ if ((dso = dso_link(libcap_locs[i++])))
274
+ break;
275
+ };
276
+ if (dso == NULL) {
277
+ log_error("failed loading capabilities library -- %s.", dso_error());
278
+ return -1;
279
+ }
280
+ CAP_LDD(cap_free);
281
+ CAP_LDD(cap_init);
282
+ CAP_LDD(cap_clear);
283
+
284
+ CAP_LDD(cap_get_flag);
285
+ CAP_LDD(cap_set_flag);
286
+ CAP_LDD(cap_set_proc);
287
+ hlibcap = dso;
288
+ #undef CAP_LDD
289
+ return 0;
290
+ }
291
+
292
+
293
+ static int set_caps(int cap_type)
294
+ {
295
+ cap_t c;
296
+ int ncap;
297
+ int flag = CAP_SET;
298
+ cap_value_t *caps;
299
+ const char *type;
300
+
301
+ if (ld_libcap()) {
302
+ return set_legacy_caps(cap_type);
303
+ }
304
+ if (cap_type == CAPS) {
305
+ ncap = sizeof(caps_std)/sizeof(cap_value_t);
306
+ caps = caps_std;
307
+ type = "default";
308
+ }
309
+ else if (cap_type == CAPSMIN) {
310
+ ncap = sizeof(caps_min)/sizeof(cap_value_t);
311
+ caps = caps_min;
312
+ type = "min";
313
+ }
314
+ else {
315
+ ncap = sizeof(caps_min)/sizeof(cap_value_t);
316
+ caps = caps_min;
317
+ type = "null";
318
+ flag = CAP_CLEAR;
319
+ }
320
+ c = (*fp_cap_init)();
321
+ (*fp_cap_clear)(c);
322
+ (*fp_cap_set_flag)(c, CAP_EFFECTIVE, ncap, caps, flag);
323
+ (*fp_cap_set_flag)(c, CAP_INHERITABLE, ncap, caps, flag);
324
+ (*fp_cap_set_flag)(c, CAP_PERMITTED, ncap, caps, flag);
325
+ if ((*fp_cap_set_proc)(c) != 0) {
326
+ log_error("failed setting %s capabilities.", type);
327
+ return -1;
328
+ }
329
+ (*fp_cap_free)(c);
330
+ if (cap_type == CAPS)
331
+ log_debug("increased capability set.");
332
+ else if (cap_type == CAPSMIN)
333
+ log_debug("decreased capability set to min required.");
334
+ else
335
+ log_debug("dropped capabilities.");
336
+ return 0;
337
+ }
338
+
339
+ #else /* !HAVE_LIBCAP */
340
+ /* CAPSALL is to allow to read/write at any location */
341
+ #define CAPSALL LEGACY_CAPSALL
342
+ #define CAPSMAX LEGACY_CAPSMAX
343
+ #define CAPS LEGACY_CAPS
344
+ #define CAPSMIN LEGACY_CAPSMIN
345
+ static int set_caps(int caps)
346
+ {
347
+ return set_legacy_caps(caps);
348
+ }
349
+ #endif
350
+
351
+ static int linuxset_user_group(const char *user, int uid, int gid)
352
+ {
353
+ int caps_set = 0;
354
+
355
+ if (user == NULL)
356
+ return 0;
357
+ /* set capabilities enough for binding port 80 setuid/getuid */
358
+ if (getuid() == 0) {
359
+ if (set_caps(CAPS) != 0) {
360
+ if (getuid() != uid) {
361
+ log_error("set_caps(CAPS) failed for user '%s'", user);
362
+ return -1;
363
+ }
364
+ log_debug("set_caps(CAPS) failed for user '%s'", user);
365
+ }
366
+ /* make sure they are kept after setuid */
367
+ if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) {
368
+ log_error("prctl failed in for user '%s'", user);
369
+ return -1;
370
+ }
371
+ caps_set = 1;
372
+ }
373
+
374
+ /* set setuid/getuid */
375
+ if (set_user_group(user, uid, gid) != 0) {
376
+ log_error("set_user_group failed for user '%s'", user);
377
+ return -1;
378
+ }
379
+
380
+ if (caps_set) {
381
+ /* set capability to binding port 80 read conf */
382
+ if (set_caps(CAPSMIN) != 0) {
383
+ if (getuid() != uid) {
384
+ log_error("set_caps(CAPSMIN) failed for user '%s'", user);
385
+ return -1;
386
+ }
387
+ log_debug("set_caps(CAPSMIN) failed for user '%s'", user);
388
+ }
389
+ }
390
+
391
+ return 0;
392
+ }
393
+ #endif
394
+
395
+
396
+ static bool checkuser(char *user, uid_t * uid, gid_t * gid)
397
+ {
398
+ struct passwd *pwds = NULL;
399
+ int status = 0;
400
+ pid_t pid = 0;
401
+
402
+ /* Do we actually _have_ to switch user? */
403
+ if (user == NULL)
404
+ return true;
405
+
406
+ pwds = getpwnam(user);
407
+ if (pwds == NULL) {
408
+ log_error("Invalid user name '%s' specified", user);
409
+ return false;
410
+ }
411
+
412
+ *uid = pwds->pw_uid;
413
+ *gid = pwds->pw_gid;
414
+
415
+ /* Validate the user name in another process */
416
+ pid = fork();
417
+ if (pid == -1) {
418
+ log_error("Cannot validate user name");
419
+ return false;
420
+ }
421
+
422
+ /* If we're in the child process, let's validate */
423
+ if (pid == 0) {
424
+ if (set_user_group(user, *uid, *gid) != 0)
425
+ exit(1);
426
+ /* If we got here we switched user/group */
427
+ exit(0);
428
+ }
429
+
430
+ while (waitpid(pid, &status, 0) != pid) {
431
+ /* Just wait */
432
+ }
433
+
434
+ /* The child must have exited cleanly */
435
+ if (WIFEXITED(status)) {
436
+ status = WEXITSTATUS(status);
437
+
438
+ /* If the child got out with 0 the user is ok */
439
+ if (status == 0) {
440
+ log_debug("User '%s' validated", user);
441
+ return true;
442
+ }
443
+ }
444
+
445
+ log_error("Error validating user '%s'", user);
446
+ return false;
447
+ }
448
+
449
+ #ifdef OS_CYGWIN
450
+ static void cygwincontroller(void)
451
+ {
452
+ raise(SIGTERM);
453
+ }
454
+ #endif
455
+ static void controller(int sig)
456
+ {
457
+ switch (sig) {
458
+ case SIGTERM:
459
+ case SIGINT:
460
+ case SIGHUP:
461
+ case SIGUSR1:
462
+ case SIGUSR2:
463
+ log_debug("Forwarding signal %d to process %d", sig, controlled);
464
+ kill(controlled, sig);
465
+ signal(sig, controller);
466
+ break;
467
+ default:
468
+ log_debug("Caught unknown signal %d", sig);
469
+ break;
470
+ }
471
+ }
472
+
473
+ /*
474
+ * Return the address of the current signal handler and set the new one.
475
+ */
476
+ static sighandler_t signal_set(int sig, sighandler_t newHandler)
477
+ {
478
+ sighandler_t hand;
479
+
480
+ hand = signal(sig, newHandler);
481
+ #ifdef SIG_ERR
482
+ if (hand == SIG_ERR)
483
+ hand = NULL;
484
+ #endif
485
+ if (hand == handler || hand == controller)
486
+ hand = NULL;
487
+ return hand;
488
+ }
489
+
490
+ /*
491
+ * Check pid and if still running
492
+ */
493
+
494
+ static int check_pid(arg_data *args)
495
+ {
496
+ int fd;
497
+ FILE *pidf;
498
+ char buff[80];
499
+ pid_t pidn = getpid();
500
+ int i, pid;
501
+
502
+ fd = open(args->pidf, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
503
+ if (fd < 0) {
504
+ log_error("Cannot open PID file %s, PID is %d", args->pidf, pidn);
505
+ return -1;
506
+ }
507
+ else {
508
+ lockf(fd, F_LOCK, 0);
509
+ i = read(fd, buff, sizeof(buff));
510
+ if (i > 0) {
511
+ buff[i] = '\0';
512
+ pid = atoi(buff);
513
+ if (kill(pid, 0) == 0) {
514
+ log_error("Still running according to PID file %s, PID is %d",
515
+ args->pidf, pid);
516
+ lockf(fd, F_ULOCK, 0);
517
+ close(fd);
518
+ return 122;
519
+ }
520
+ }
521
+
522
+ /* skip writing the pid file if version or check */
523
+ if (args->vers != true && args->chck != true) {
524
+ lseek(fd, SEEK_SET, 0);
525
+ pidf = fdopen(fd, "r+");
526
+ fprintf(pidf, "%d\n", (int)getpid());
527
+ fflush(pidf);
528
+ lockf(fd, F_ULOCK, 0);
529
+ fclose(pidf);
530
+ close(fd);
531
+ }
532
+ else {
533
+ lockf(fd, F_ULOCK, 0);
534
+ close(fd);
535
+ }
536
+ }
537
+ return 0;
538
+ }
539
+
540
+ /*
541
+ * read the pid from the pidfile
542
+ */
543
+ static int get_pidf(arg_data *args, bool quiet)
544
+ {
545
+ int fd;
546
+ int i;
547
+ char buff[80];
548
+
549
+ fd = open(args->pidf, O_RDONLY, 0);
550
+ if (!quiet)
551
+ log_debug("get_pidf: %d in %s", fd, args->pidf);
552
+ if (fd < 0) {
553
+ /* something has gone wrong the JVM has stopped */
554
+ return -1;
555
+ }
556
+ lockf(fd, F_LOCK, 0);
557
+ i = read(fd, buff, sizeof(buff));
558
+ lockf(fd, F_ULOCK, 0);
559
+ close(fd);
560
+ if (i > 0) {
561
+ buff[i] = '\0';
562
+ i = atoi(buff);
563
+ if (!quiet)
564
+ log_debug("get_pidf: pid %d", i);
565
+ if (kill(i, 0) == 0)
566
+ return i;
567
+ }
568
+ return -1;
569
+ }
570
+
571
+ /*
572
+ * Check temporatory file created by controller
573
+ * /tmp/pid.jsvc_up
574
+ * Notes:
575
+ * we fork several times
576
+ * 1 - to be a daemon before the setsid(), the child is the controler process.
577
+ * 2 - to start the JVM in the child process. (whose pid is stored in pidfile).
578
+ */
579
+ static int check_tmp_file(arg_data *args)
580
+ {
581
+ int pid;
582
+ char buff[80];
583
+ int fd;
584
+
585
+ pid = get_pidf(args, false);
586
+ if (pid < 0)
587
+ return -1;
588
+ sprintf(buff, "/tmp/%d.jsvc_up", pid);
589
+ log_debug("check_tmp_file: %s", buff);
590
+ fd = open(buff, O_RDONLY);
591
+ if (fd == -1)
592
+ return -1;
593
+ close(fd);
594
+ return 0;
595
+ }
596
+
597
+ static void create_tmp_file(arg_data *args)
598
+ {
599
+ char buff[80];
600
+ int fd;
601
+
602
+ sprintf(buff, "/tmp/%d.jsvc_up", (int)getpid());
603
+ log_debug("create_tmp_file: %s", buff);
604
+ fd = open(buff, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
605
+ if (fd != -1)
606
+ close(fd);
607
+ }
608
+
609
+ static void remove_tmp_file(arg_data *args)
610
+ {
611
+ char buff[80];
612
+
613
+ sprintf(buff, "/tmp/%d.jsvc_up", (int)getpid());
614
+ log_debug("remove_tmp_file: %s", buff);
615
+ unlink(buff);
616
+ }
617
+
618
+ /*
619
+ * wait until jsvc create the I am ready file
620
+ * pid is the controller and args->pidf the JVM itself.
621
+ */
622
+ static int wait_child(arg_data *args, int pid)
623
+ {
624
+ int count = 10;
625
+ bool havejvm = false;
626
+ int fd;
627
+ char buff[80];
628
+ int i, status, waittime;
629
+
630
+ log_debug("wait_child %d", pid);
631
+ waittime = args->wait / 10;
632
+ if (waittime > 10) {
633
+ count = waittime;
634
+ waittime = 10;
635
+ }
636
+ while (count > 0) {
637
+ sleep(1);
638
+ /* check if the controler is still running */
639
+ if (waitpid(pid, &status, WNOHANG) == pid) {
640
+ if (WIFEXITED(status))
641
+ return (WEXITSTATUS(status));
642
+ else
643
+ return 1;
644
+ }
645
+
646
+ /* check if the pid file process exists */
647
+ fd = open(args->pidf, O_RDONLY);
648
+ if (fd < 0 && havejvm) {
649
+ /* something has gone wrong the JVM has stopped */
650
+ return 1;
651
+ }
652
+ lockf(fd, F_LOCK, 0);
653
+ i = read(fd, buff, sizeof(buff));
654
+ lockf(fd, F_ULOCK, 0);
655
+ close(fd);
656
+ if (i > 0) {
657
+ buff[i] = '\0';
658
+ i = atoi(buff);
659
+ if (kill(i, 0) == 0) {
660
+ /* the JVM process has started */
661
+ havejvm = true;
662
+ if (check_tmp_file(args) == 0) {
663
+ /* the JVM is started */
664
+ if (waitpid(pid, &status, WNOHANG) == pid) {
665
+ if (WIFEXITED(status))
666
+ return (WEXITSTATUS(status));
667
+ else
668
+ return 1;
669
+ }
670
+ return 0; /* ready JVM started */
671
+ }
672
+ }
673
+ }
674
+ sleep(waittime);
675
+ count--;
676
+ }
677
+ /* It takes more than the wait time to start,
678
+ * something must be wrong
679
+ */
680
+ return 1;
681
+ }
682
+
683
+ /*
684
+ * stop the running jsvc
685
+ */
686
+ static int stop_child(arg_data *args)
687
+ {
688
+ int pid = get_pidf(args, false);
689
+ int count = 60;
690
+
691
+ if (pid > 0) {
692
+ /* kill the process and wait until the pidfile has been
693
+ * removed by the controler
694
+ */
695
+ kill(pid, SIGTERM);
696
+ while (count > 0) {
697
+ sleep(1);
698
+ pid = get_pidf(args, true);
699
+ if (pid <= 0) {
700
+ /* JVM has stopped */
701
+ return 0;
702
+ }
703
+ count--;
704
+ }
705
+ }
706
+ return -1;
707
+ }
708
+
709
+ /*
710
+ * child process logic.
711
+ */
712
+
713
+ static int child(arg_data *args, home_data *data, uid_t uid, gid_t gid)
714
+ {
715
+ int ret = 0;
716
+
717
+ /* check the pid file */
718
+ ret = check_pid(args);
719
+ if (args->vers != true && args->chck != true) {
720
+ if (ret == 122)
721
+ return ret;
722
+ if (ret < 0)
723
+ return ret;
724
+ }
725
+
726
+ #ifdef OS_LINUX
727
+ /* setuid()/setgid() only apply the current thread so we must do it now */
728
+ if (linuxset_user_group(args->user, uid, gid) != 0)
729
+ return 4;
730
+ #endif
731
+ /* Initialize the Java VM */
732
+ if (java_init(args, data) != true) {
733
+ log_debug("java_init failed");
734
+ return 1;
735
+ }
736
+ else
737
+ log_debug("java_init done");
738
+
739
+ /* Check wether we need to dump the VM version */
740
+ if (args->vers == true) {
741
+ log_error("jsvc (Apache Commons Daemon) " JSVC_VERSION_STRING);
742
+ log_error("Copyright (c) 1999-2011 Apache Software Foundation.");
743
+ if (java_version() != true) {
744
+ return -1;
745
+ }
746
+ else
747
+ return 0;
748
+ }
749
+ /* Check wether we need to dump the VM version */
750
+ else if (args->vershow == true) {
751
+ if (java_version() != true) {
752
+ return 7;
753
+ }
754
+ }
755
+
756
+ /* Do we have to do a "check-only" initialization? */
757
+ if (args->chck == true) {
758
+ if (java_check(args) != true)
759
+ return 2;
760
+ printf("Service \"%s\" checked successfully\n", args->clas);
761
+ return 0;
762
+ }
763
+
764
+ /* Load the service */
765
+ if (java_load(args) != true) {
766
+ log_debug("java_load failed");
767
+ return 3;
768
+ }
769
+ else
770
+ log_debug("java_load done");
771
+
772
+ /* Downgrade user */
773
+ #ifdef OS_LINUX
774
+ if (args->user && set_caps(0) != 0) {
775
+ log_debug("set_caps (0) failed");
776
+ return 4;
777
+ }
778
+ #else
779
+ if (set_user_group(args->user, uid, gid) != 0)
780
+ return 4;
781
+ #endif
782
+
783
+ /* Start the service */
784
+ umask(envmask);
785
+ if (java_start() != true) {
786
+ log_debug("java_start failed");
787
+ return 5;
788
+ }
789
+ else
790
+ log_debug("java_start done");
791
+
792
+ /* Install signal handlers */
793
+ handler_hup = signal_set(SIGHUP, handler);
794
+ handler_usr1 = signal_set(SIGUSR1, handler);
795
+ handler_usr2 = signal_set(SIGUSR2, handler);
796
+ handler_trm = signal_set(SIGTERM, handler);
797
+ handler_int = signal_set(SIGINT, handler);
798
+ controlled = getpid();
799
+
800
+ log_debug("Waiting for a signal to be delivered");
801
+ create_tmp_file(args);
802
+ while (!stopping) {
803
+ #if defined(OSD_POSIX)
804
+ java_sleep(60);
805
+ /* pause(); */
806
+ #else
807
+ /* pause() is not threadsafe */
808
+ sleep(60);
809
+ #endif
810
+ if(doreopen) {
811
+ doreopen = false;
812
+ set_output(args->outfile, args->errfile, args->redirectstdin, args->procname);
813
+ }
814
+ if(dosignal) {
815
+ dosignal = false;
816
+ java_signal();
817
+ }
818
+ }
819
+ remove_tmp_file(args);
820
+ log_debug("Shutdown or reload requested: exiting");
821
+
822
+ /* Stop the service */
823
+ if (java_stop() != true)
824
+ return 6;
825
+
826
+ if (doreload == true)
827
+ ret = 123;
828
+ else
829
+ ret = 0;
830
+
831
+ /* Destroy the service */
832
+ java_destroy();
833
+
834
+ /* Destroy the Java VM */
835
+ if (JVM_destroy(ret) != true)
836
+ return 7;
837
+
838
+ return ret;
839
+ }
840
+
841
+ /*
842
+ * freopen close the file first and then open the new file
843
+ * that is not very good if we are try to trace the output
844
+ * note the code assumes that the errors are configuration errors.
845
+ */
846
+ static FILE *loc_freopen(char *outfile, char *mode, FILE * stream)
847
+ {
848
+ FILE *ftest;
849
+
850
+ ftest = fopen(outfile, mode);
851
+ if (ftest == NULL) {
852
+ fprintf(stderr, "Unable to redirect to %s\n", outfile);
853
+ return stream;
854
+ }
855
+ fclose(ftest);
856
+ return freopen(outfile, mode, stream);
857
+ }
858
+
859
+ #define LOGBUF_SIZE 1024
860
+
861
+ /* Read from file descriptors. Log to syslog. */
862
+ static int logger_child(int out_fd, int err_fd, char *procname)
863
+ {
864
+ fd_set rfds;
865
+ struct timeval tv;
866
+ int retval, nfd = -1, rc = 0;
867
+ ssize_t n;
868
+ char buf[LOGBUF_SIZE];
869
+
870
+ if (out_fd == -1 && err_fd == -1)
871
+ return EINVAL;
872
+ if (out_fd == -1)
873
+ nfd = err_fd;
874
+ else if (err_fd == -1)
875
+ nfd = out_fd;
876
+ else
877
+ nfd = out_fd > err_fd ? out_fd : err_fd;
878
+ ++nfd;
879
+
880
+ openlog(procname, LOG_PID, LOG_DAEMON);
881
+
882
+ while (out_fd != -1 || err_fd != -1) {
883
+ FD_ZERO(&rfds);
884
+ if (out_fd != -1) {
885
+ FD_SET(out_fd, &rfds);
886
+ }
887
+ if (err_fd != -1) {
888
+ FD_SET(err_fd, &rfds);
889
+ }
890
+ tv.tv_sec = 60;
891
+ tv.tv_usec = 0;
892
+ retval = select(nfd, &rfds, NULL, NULL, &tv);
893
+ if (retval == -1) {
894
+ rc = errno;
895
+ syslog(LOG_ERR, "select: %s", strerror(errno));
896
+ /* If select failed no point to continue */
897
+ break;
898
+ }
899
+ else if (retval) {
900
+ if (out_fd != -1 && FD_ISSET(out_fd, &rfds)) {
901
+ do {
902
+ n = read(out_fd, buf, LOGBUF_SIZE-1);
903
+ } while (n == -1 && errno == EINTR);
904
+ if (n == -1) {
905
+ syslog(LOG_ERR, "read: %s", strerror(errno));
906
+ close(out_fd);
907
+ if (err_fd == -1)
908
+ break;
909
+ nfd = err_fd + 1;
910
+ out_fd = -1;
911
+ }
912
+ else if (n > 0 && buf[0] != '\n') {
913
+ buf[n] = 0;
914
+ syslog(LOG_INFO, "%s", buf);
915
+ }
916
+ }
917
+ if (err_fd != -1 && FD_ISSET(err_fd, &rfds)) {
918
+ do {
919
+ n = read(err_fd, buf, LOGBUF_SIZE-1);
920
+ } while (n == -1 && errno == EINTR);
921
+ if (n == -1) {
922
+ syslog(LOG_ERR, "read: %s", strerror(errno));
923
+ close(err_fd);
924
+ if (out_fd == -1)
925
+ break;
926
+ nfd = out_fd + 1;
927
+ err_fd = -1;
928
+ }
929
+ else if (n > 0 && buf[0] != '\n') {
930
+ buf[n] = 0;
931
+ syslog(LOG_ERR, "%s", buf);
932
+ }
933
+ }
934
+ }
935
+ }
936
+ return rc;
937
+ }
938
+
939
+ /**
940
+ * Redirect stdin, stdout, stderr.
941
+ */
942
+ static void set_output(char *outfile, char *errfile, bool redirectstdin, char *procname)
943
+ {
944
+ int out_pipe[2] = {-1, -1};
945
+ int err_pipe[2] = {-1, -1};
946
+ int fork_needed = 0;
947
+
948
+ if (redirectstdin == true) {
949
+ freopen("/dev/null", "r", stdin);
950
+ }
951
+
952
+ log_debug("redirecting stdout to %s and stderr to %s", outfile, errfile);
953
+
954
+ /* make sure the debug goes out */
955
+ if (log_debug_flag == true && strcmp(errfile, "/dev/null") == 0)
956
+ return;
957
+ if (strcmp(outfile, "&1") == 0 && strcmp(errfile, "&2") == 0)
958
+ return;
959
+ if (strcmp(outfile, "SYSLOG") == 0) {
960
+ freopen("/dev/null", "a", stdout);
961
+ /* Send stdout to syslog through a logger process */
962
+ if (pipe(out_pipe) == -1) {
963
+ log_error("cannot create stdout pipe: %s",
964
+ strerror(errno));
965
+ }
966
+ else {
967
+ fork_needed = 1;
968
+ log_stdout_syslog_flag = true;
969
+ }
970
+ }
971
+ else if (strcmp(outfile, "&2")) {
972
+ if (strcmp(outfile, "&1")) {
973
+ /* Redirect stdout to a file */
974
+ loc_freopen(outfile, "a", stdout);
975
+ }
976
+ }
977
+
978
+ if (strcmp(errfile, "SYSLOG") == 0) {
979
+ freopen("/dev/null", "a", stderr);
980
+ /* Send stderr to syslog through a logger process */
981
+ if (pipe(err_pipe) == -1) {
982
+ log_error("cannot create stderr pipe: %s",
983
+ strerror(errno));
984
+ }
985
+ else {
986
+ fork_needed = 1;
987
+ log_stderr_syslog_flag = true;
988
+ }
989
+ }
990
+ else if (strcmp(errfile, "&1")) {
991
+ if (strcmp(errfile, "&2")) {
992
+ /* Redirect stderr to a file */
993
+ loc_freopen(errfile, "a", stderr);
994
+ }
995
+ }
996
+ if (strcmp(errfile, "&1") == 0 && strcmp(outfile, "&1")) {
997
+ /*
998
+ * -errfile &1 -outfile foo
999
+ * Redirect stderr to stdout
1000
+ */
1001
+ close(2);
1002
+ dup2(1, 2);
1003
+ }
1004
+ if (strcmp(outfile, "&2") == 0 && strcmp(errfile, "&2")) {
1005
+ /*
1006
+ * -outfile &2 -errfile foo
1007
+ * Redirect stdout to stderr
1008
+ */
1009
+ close(1);
1010
+ dup2(2, 1);
1011
+ }
1012
+
1013
+ if (fork_needed) {
1014
+ pid_t pid = fork();
1015
+ if (pid == -1) {
1016
+ log_error("cannot create logger process: %s", strerror(errno));
1017
+ }
1018
+ else {
1019
+ if (pid != 0) {
1020
+ /* Parent process.
1021
+ * Close child pipe endpoints.
1022
+ */
1023
+ logger_pid = pid;
1024
+ if (out_pipe[0] != -1) {
1025
+ close(out_pipe[0]);
1026
+ if (dup2(out_pipe[1], 1) == -1) {
1027
+ log_error("cannot redirect stdout to pipe for syslog: %s",
1028
+ strerror(errno));
1029
+ }
1030
+ }
1031
+ if (err_pipe[0] != -1) {
1032
+ close(err_pipe[0]);
1033
+ if (dup2(err_pipe[1], 2) == -1) {
1034
+ log_error("cannot redirect stderr to pipe for syslog: %s",
1035
+ strerror(errno));
1036
+ }
1037
+ }
1038
+ }
1039
+ else {
1040
+ exit(logger_child(out_pipe[0], err_pipe[0], procname));
1041
+ }
1042
+ }
1043
+ }
1044
+ }
1045
+
1046
+ int main(int argc, char *argv[])
1047
+ {
1048
+ arg_data *args = NULL;
1049
+ home_data *data = NULL;
1050
+ pid_t pid = 0;
1051
+ uid_t uid = 0;
1052
+ gid_t gid = 0;
1053
+ int res;
1054
+
1055
+ /* Parse command line arguments */
1056
+ args = arguments(argc, argv);
1057
+ if (args == NULL)
1058
+ return 1;
1059
+
1060
+ /* Stop running jsvc if required */
1061
+ if (args->stop == true)
1062
+ return (stop_child(args));
1063
+
1064
+ /* Let's check if we can switch user/group IDs */
1065
+ if (checkuser(args->user, &uid, &gid) == false)
1066
+ return 1;
1067
+
1068
+ /* Retrieve JAVA_HOME layout */
1069
+ data = home(args->home);
1070
+ if (data == NULL)
1071
+ return 1;
1072
+
1073
+ /* Check for help */
1074
+ if (args->help == true) {
1075
+ help(data);
1076
+ return 0;
1077
+ }
1078
+
1079
+ #ifdef OS_LINUX
1080
+ /* On some UNIX operating systems, we need to REPLACE this current
1081
+ process image with another one (thru execve) to allow the correct
1082
+ loading of VMs (notably this is for Linux). Set, replace, and go. */
1083
+ if (strcmp(argv[0], args->procname) != 0) {
1084
+ char *oldpath = getenv("LD_LIBRARY_PATH");
1085
+ char *libf = java_library(args, data);
1086
+ char *filename;
1087
+ char buf[2048];
1088
+ int ret;
1089
+ char *tmp = NULL;
1090
+ char *p1 = NULL;
1091
+ char *p2 = NULL;
1092
+
1093
+ /*
1094
+ * There is no need to change LD_LIBRARY_PATH
1095
+ * if we were not able to find a path to libjvm.so
1096
+ * (additionaly a strdup(NULL) cores dump on my machine).
1097
+ */
1098
+ if (libf != NULL) {
1099
+ p1 = strdup(libf);
1100
+ tmp = strrchr(p1, '/');
1101
+ if (tmp != NULL)
1102
+ tmp[0] = '\0';
1103
+
1104
+ p2 = strdup(p1);
1105
+ tmp = strrchr(p2, '/');
1106
+ if (tmp != NULL)
1107
+ tmp[0] = '\0';
1108
+
1109
+ if (oldpath == NULL)
1110
+ snprintf(buf, 2048, "%s:%s", p1, p2);
1111
+ else
1112
+ snprintf(buf, 2048, "%s:%s:%s", oldpath, p1, p2);
1113
+
1114
+ tmp = strdup(buf);
1115
+ setenv("LD_LIBRARY_PATH", tmp, 1);
1116
+
1117
+ log_debug("Invoking w/ LD_LIBRARY_PATH=%s",
1118
+ getenv("LD_LIBRARY_PATH"));
1119
+ }
1120
+
1121
+ /* execve needs a full path */
1122
+ ret = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
1123
+ if (ret <= 0)
1124
+ strcpy(buf, argv[0]);
1125
+ else
1126
+ buf[ret] = '\0';
1127
+
1128
+ filename = buf;
1129
+
1130
+ argv[0] = args->procname;
1131
+ execve(filename, argv, environ);
1132
+ log_error("Cannot execute JSVC executor process (%s)", filename);
1133
+ return 1;
1134
+ }
1135
+ log_debug("Running w/ LD_LIBRARY_PATH=%s", getenv("LD_LIBRARY_PATH"));
1136
+ #endif /* ifdef OS_LINUX */
1137
+
1138
+ /* If we have to detach, let's do it now */
1139
+ if (args->dtch == true) {
1140
+ pid = fork();
1141
+ if (pid == -1) {
1142
+ log_error("Cannot detach from parent process");
1143
+ return 1;
1144
+ }
1145
+ /* If we're in the parent process */
1146
+ if (pid != 0) {
1147
+ if (args->wait >= 10)
1148
+ return wait_child(args, pid);
1149
+ else
1150
+ return 0;
1151
+ }
1152
+ #ifndef NO_SETSID
1153
+ setsid();
1154
+ #endif
1155
+ }
1156
+
1157
+ /*
1158
+ * umask() uses inverse logic; bits are CLEAR for allowed access.
1159
+ */
1160
+ if (~args->umask & 0022) {
1161
+ log_error("NOTICE: jsvc umask of %03o allows "
1162
+ "write permission to group and/or other", args->umask);
1163
+ }
1164
+ envmask = umask(args->umask);
1165
+ set_output(args->outfile, args->errfile, args->redirectstdin, args->procname);
1166
+ log_debug("Switching umask back to %03o from %03o", envmask, args->umask);
1167
+ res = run_controller(args, data, uid, gid);
1168
+ if (logger_pid != 0) {
1169
+ kill(logger_pid, SIGTERM);
1170
+ }
1171
+
1172
+ return res;
1173
+ }
1174
+
1175
+ static int run_controller(arg_data *args, home_data *data, uid_t uid,
1176
+ gid_t gid)
1177
+ {
1178
+ pid_t pid = 0;
1179
+
1180
+
1181
+ /* We have to fork: this process will become the controller and the other
1182
+ will be the child */
1183
+ while ((pid = fork()) != -1) {
1184
+ time_t laststart;
1185
+ int status = 0;
1186
+ /* We forked (again), if this is the child, we go on normally */
1187
+ if (pid == 0)
1188
+ exit(child(args, data, uid, gid));
1189
+ laststart = time(NULL);
1190
+
1191
+ /* We are in the controller, we have to forward all interesting signals
1192
+ to the child, and wait for it to die */
1193
+ controlled = pid;
1194
+ #ifdef OS_CYGWIN
1195
+ SetTerm(cygwincontroller);
1196
+ #endif
1197
+ signal(SIGHUP, controller);
1198
+ signal(SIGUSR1, controller);
1199
+ signal(SIGUSR2, controller);
1200
+ signal(SIGTERM, controller);
1201
+ signal(SIGINT, controller);
1202
+
1203
+ while (waitpid(pid, &status, 0) != pid) {
1204
+ /* Waith for process */
1205
+ }
1206
+
1207
+ /* The child must have exited cleanly */
1208
+ if (WIFEXITED(status)) {
1209
+ status = WEXITSTATUS(status);
1210
+
1211
+ /* Delete the pid file */
1212
+ if (args->vers != true && args->chck != true && status != 122)
1213
+ unlink(args->pidf);
1214
+
1215
+ /* If the child got out with 123 he wants to be restarted */
1216
+ /* See java_abort123 (we use this return code to restart when the JVM aborts) */
1217
+ if (status == 123) {
1218
+ log_debug("Reloading service");
1219
+ /* prevent looping */
1220
+ if (laststart + 60 > time(NULL)) {
1221
+ log_debug("Waiting 60 s to prevent looping");
1222
+ sleep(60);
1223
+ }
1224
+ continue;
1225
+ }
1226
+ /* If the child got out with 0 he is shutting down */
1227
+ if (status == 0) {
1228
+ log_debug("Service shut down");
1229
+ return 0;
1230
+ }
1231
+ /* Otherwise we don't rerun it */
1232
+ log_error("Service exit with a return value of %d", status);
1233
+ return 1;
1234
+
1235
+ }
1236
+ else {
1237
+ if (WIFSIGNALED(status)) {
1238
+ log_error("Service killed by signal %d", WTERMSIG(status));
1239
+ /* prevent looping */
1240
+ if (laststart + 60 > time(NULL)) {
1241
+ log_debug("Waiting 60 s to prevent looping");
1242
+ sleep(60);
1243
+ }
1244
+ continue;
1245
+ }
1246
+ log_error("Service did not exit cleanly", status);
1247
+ return 1;
1248
+ }
1249
+ }
1250
+
1251
+ /* Got out of the loop? A fork() failed then. */
1252
+ log_error("Cannot decouple controller/child processes");
1253
+ return 1;
1254
+
1255
+ }
1256
+
1257
+ void main_reload(void)
1258
+ {
1259
+ log_debug("Killing self with HUP signal");
1260
+ kill(controlled, SIGHUP);
1261
+ }
1262
+
1263
+ void main_shutdown(void)
1264
+ {
1265
+ log_debug("Killing self with TERM signal");
1266
+ kill(controlled, SIGTERM);
1267
+ }