trinidad_init_services 1.1.3 → 1.1.4

Sign up to get free protection for your applications and to get access to all the features.
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
+ }