2 * Copyright (c) 2014 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * Handle remote listen/connect and parsing operations.
40 pthread_mutex_t serial_mtx
;
41 time_t LastStart
; /* uptime */
42 time_t LastStop
; /* uptime */
44 runstate_t RunState
= RS_STOPPED
;
48 static void *logger_thread(void *arg
);
49 static void setstate_stopped(command_t
*cmd
, struct timespec
*ts
);
50 static int setup_gid(command_t
*cmd
);
51 static int setup_uid(command_t
*cmd
);
52 static int setup_jail(command_t
*cmd
);
53 static int setup_chroot(command_t
*cmd
);
54 static int setup_devfs(command_t
*cmd
, const char *dir
, int domount
);
55 static int escapewrite(FILE *fp
, char *buf
, int n
, int *statep
);
58 execute_init(command_t
*cmd
)
62 pid_t stoppingpid
= -1;
65 int lfd
; /* unix domain listen socket */
66 int pfd
; /* pid file */
72 if (cmd
->label
== NULL
|| cmd
->ext_ac
== 0) {
73 fprintf(cmd
->fp
, "init requires a label and command\n");
76 fprintf(cmd
->fp
, "initializing new service: %s\n", cmd
->label
);
78 if ((xfd
= open("/dev/null", O_RDWR
)) < 0) {
79 fprintf(cmd
->fp
, "Unable to open /dev/null: %s\n",
85 * Setup pidfile and unix domain listen socket and lock the
88 rc
= setup_pid_and_socket(cmd
, &lfd
, &pfd
);
95 if (cmd
->foreground
) {
104 fprintf(cmd
->fp
, "Unable to create pipe: %s\n",
108 remove_pid_and_socket(cmd
, cmd
->label
);
120 fprintf(cmd
->fp
, "fork failed: %s\n", strerror(errno
));
125 remove_pid_and_socket(cmd
, cmd
->label
);
129 * Fill-in pfd before returning.
131 snprintf(buf
, sizeof(buf
), "%d\n", (int)pid
);
132 write(pfd
, buf
, strlen(buf
));
138 * Wait for child to completely detach from the tty
148 * Forked child is now the service demon.
150 * Detach from terminal, scrap tty, set process title.
152 if (cmd
->proctitle
) {
153 setproctitle("%s - %s", cmd
->label
, cmd
->proctitle
);
155 setproctitle("%s", cmd
->label
);
159 setup_devfs(cmd
, cmd
->jaildir
, 1);
160 else if (cmd
->rootdir
)
161 setup_devfs(cmd
, cmd
->rootdir
, 1);
164 if (cmd
->foreground
== 0) {
169 if (xfd
!= 0) /* scrap tty inputs */
171 if (cmd
->foreground
== 0) {
174 if (xfd
!= 1) /* scrap tty outputs */
179 if ((tfd
= open("/dev/tty", O_RDWR
)) >= 0) {
180 ioctl(tfd
, TIOCNOTTY
, 0); /* no controlling tty */
183 setsid(); /* new session */
187 * Setup log file. The log file must not use descriptors 0, 1, or 2.
189 if (cmd
->logfile
&& strcmp(cmd
->logfile
, "/dev/null") == 0)
191 else if (cmd
->logfile
)
192 cmd
->logfd
= open(cmd
->logfile
, O_WRONLY
|O_CREAT
|O_APPEND
, 0640);
193 else if (cmd
->foreground
)
199 * Signal parent that we are completely detached now.
202 if (cmd
->foreground
== 0) {
203 write(fds
[1], &c
, 1);
210 * Setup log pipe. The logger thread copies the pipe to a buffer
211 * for the 'log' directive and also writes it to logfd.
214 if (cmd
->fp
!= stdout
)
216 cmd
->fp
= fdopen(cmd
->logfds
[1], "w");
223 pthread_cond_init(&cmd
->logcond
, NULL
);
226 * Start accept thread for unix domain listen socket.
228 pthread_mutex_lock(&serial_mtx
);
229 pthread_create(&logtd
, NULL
, logger_thread
, cmd
);
230 remote_listener(cmd
, lfd
);
233 * Become the reaper for all children recursively.
235 if (procctl(P_PID
, getpid(), PROC_REAP_ACQUIRE
, NULL
) < 0) {
236 fprintf(cmd
->fp
, "svc is unable to become the "
237 "reaper for its children\n");
242 * Initial service start
247 * Main loop is the reaper
250 union reaper_info info
;
257 * If we are running just block doing normal reaping,
258 * if we are stopping we have to poll for reaping while
259 * we handle stopping.
262 if (RunState
== RS_STARTED
) {
263 pthread_mutex_unlock(&serial_mtx
);
264 pid
= wait3(&status
, 0, NULL
);
265 pthread_mutex_lock(&serial_mtx
);
267 pid
= wait3(&status
, WNOHANG
, NULL
);
269 clock_gettime(CLOCK_MONOTONIC_FAST
, &ts
);
272 if (pid
== DirectPid
) {
274 "svc %s: lost direct child %d\n",
278 if (cmd
->restart_some
) {
279 setstate_stopped(cmd
, &ts
);
280 } /* else still considered normal run state */
281 } else if (cmd
->debug
) {
283 * Reap random disconnected child, but don't
284 * spew to the log unless debugging is
288 "svc %s: reap indirect child %d\n",
295 * Calculate the pid to potentially act on and/or
296 * determine if any children still exist.
298 if (DirectPid
>= 0) {
300 } else if (procctl(P_PID
, getpid(),
301 PROC_REAP_STATUS
, &info
) == 0) {
302 usepid
= info
.status
.pid_head
;
307 fprintf(stderr
, "svc %s: usepid %d\n",
313 * If stoppingpid changes we have to reset the TERM->KILL
317 setstate_stopped(cmd
, &ts
);
318 } else if (stoppingpid
!= usepid
&&
319 (RunState
== RS_STOPPING2
||
320 RunState
== RS_STOPPING3
)) {
321 RunState
= RS_STOPPING1
;
323 stoppingpid
= usepid
;
331 setstate_stopped(cmd
, &ts
);
334 dt
= (int)(ts
.tv_sec
- LastStop
);
336 if (cmd
->exit_mode
) {
338 * Service demon was told to exit on service
339 * stop (-x passed to init).
342 "svc %s: service demon exiting\n",
344 remove_pid_and_socket(cmd
, cmd
->label
);
346 } else if (cmd
->manual_stop
) {
348 * Service demon was told to stop via
349 * commanded (not automatic) action. We
350 * do not auto-restart the service in
353 pthread_mutex_unlock(&serial_mtx
);
354 if (dt
< 0 || dt
> 60)
358 pthread_mutex_lock(&serial_mtx
);
359 } else if (cmd
->restart_some
|| cmd
->restart_all
) {
361 * Handle automatic restarts
363 if (dt
> cmd
->restart_timo
) {
366 pthread_mutex_unlock(&serial_mtx
);
368 pthread_mutex_lock(&serial_mtx
);
372 * No automatic restart was configured,
373 * wait for commanded action.
375 pthread_mutex_unlock(&serial_mtx
);
376 if (dt
< 0 || dt
> 60)
380 pthread_mutex_lock(&serial_mtx
);
385 * Reset TERM->KILL timer
387 nextstop
= ts
.tv_sec
;
388 RunState
= RS_STOPPING2
;
391 if (cmd
->termkill_timo
== 0) {
392 nextstop
= ts
.tv_sec
- 1;
394 kill(stoppingpid
, SIGTERM
);
395 fprintf(cmd
->fp
, "svc %s: sigterm %d\n",
396 cmd
->label
, stoppingpid
);
399 RunState
= RS_STOPPING3
;
402 dt
= (int)(ts
.tv_sec
- nextstop
);
403 if (dt
> cmd
->termkill_timo
) {
404 fprintf(cmd
->fp
, "svc %s: sigkill %d\n",
405 cmd
->label
, stoppingpid
);
406 kill(stoppingpid
, SIGKILL
);
413 pthread_mutex_unlock(&serial_mtx
);
416 setup_devfs(cmd
, cmd
->jaildir
, 0);
417 else if (cmd
->rootdir
)
418 setup_devfs(cmd
, cmd
->rootdir
, 0);
421 /* does not return */
425 execute_start(command_t
*cmd
)
430 while (RunState
== RS_STOPPING1
||
431 RunState
== RS_STOPPING2
||
432 RunState
== RS_STOPPING3
) {
434 "svc %s: Waiting for previous action to complete\n",
437 pthread_mutex_unlock(&serial_mtx
);
439 pthread_mutex_lock(&serial_mtx
);
440 if (--maxwait
== 0) {
442 "svc %s: Giving up waiting for action\n",
448 if (RunState
== RS_STARTED
) {
449 fprintf(cmd
->fp
, "svc %s: Already started pid %d\n",
450 cmd
->label
, DirectPid
);
455 clock_gettime(CLOCK_MONOTONIC_FAST
, &ts
);
456 if ((DirectPid
= fork()) == 0) {
458 /* leave stdin /dev/null */
459 dup2(fileno(InitCmd
->fp
), 1); /* setup stdout */
460 dup2(fileno(InitCmd
->fp
), 2); /* setup stderr */
463 if (cmd
->jaildir
) /* jail or chroot */
465 else if (cmd
->rootdir
)
470 execvp(InitCmd
->ext_av
[0], InitCmd
->ext_av
);
473 if (DirectPid
>= 0) {
474 RunState
= RS_STARTED
;
475 LastStart
= ts
.tv_sec
;
477 setstate_stopped(InitCmd
, &ts
);
479 InitCmd
->manual_stop
= 0;
480 fprintf(cmd
->fp
, "svc %s: Starting pid %d\n", cmd
->label
, DirectPid
);
487 execute_restart(command_t
*cmd
)
491 rc
= execute_stop(cmd
) + execute_start(cmd
);
496 execute_stop(command_t
*cmd
)
498 union reaper_info info
;
500 int save_restart_some
;
501 int save_restart_all
;
504 save_restart_some
= InitCmd
->restart_some
;
505 save_restart_all
= InitCmd
->restart_all
;
507 InitCmd
->manual_stop
= 1;
508 if (cmd
->commanded
&& (cmd
->restart_some
|| cmd
->restart_all
)) {
509 InitCmd
->restart_some
= cmd
->restart_some
;
510 InitCmd
->restart_all
= cmd
->restart_all
;
512 fprintf(cmd
->fp
, "svc %s: Stopping\n", cmd
->label
);
516 * Start the kill chain going so the master loop's wait3 wakes up.
518 if (DirectPid
>= 0) {
519 kill(DirectPid
, SIGTERM
);
521 if (procctl(P_PID
, getpid(), PROC_REAP_STATUS
, &info
) == 0 &&
522 info
.status
.pid_head
> 0) {
523 kill(info
.status
.pid_head
, SIGTERM
);
527 clock_gettime(CLOCK_MONOTONIC_FAST
, &ts
);
528 LastStop
= ts
.tv_sec
;
529 RunState
= RS_STOPPING1
;
532 * If commanded (verses automatic), we are running remote in our
533 * own thread and we need to wait for the action to complete.
535 if (cmd
->commanded
) {
536 while (RunState
== RS_STOPPING1
||
537 RunState
== RS_STOPPING2
||
538 RunState
== RS_STOPPING3
) {
540 "svc %s: Waiting for service to stop\n",
543 pthread_mutex_unlock(&serial_mtx
);
545 pthread_mutex_lock(&serial_mtx
);
546 if (--maxwait
== 0) {
548 "svc %s: Giving up waiting for stop\n",
554 if (cmd
->restart_some
|| cmd
->restart_all
) {
555 InitCmd
->restart_some
= save_restart_some
;
556 InitCmd
->restart_all
= save_restart_all
;
564 execute_exit(command_t
*cmd
)
566 if (cmd
->commanded
) {
567 InitCmd
->restart_some
= 0;
568 InitCmd
->restart_all
= 1; /* kill all children */
569 InitCmd
->exit_mode
= 1; /* exit after stop */
573 fprintf(cmd
->fp
, "svc %s: Stopping and Exiting\n", cmd
->label
);
580 execute_list(command_t
*cmd
)
582 fprintf(cmd
->fp
, "%-16s\n", cmd
->label
);
588 execute_status(command_t
*cmd
)
594 if (InitCmd
&& InitCmd
->exit_mode
)
595 state
= "stopped (exiting)";
596 else if (InitCmd
&& InitCmd
->manual_stop
)
597 state
= "stopped (manual)";
614 fprintf(cmd
->fp
, "%-16s %s\n", cmd
->label
, state
);
620 execute_log(command_t
*cmd
)
622 int lbsize
= (int)sizeof(cmd
->logbuf
);
623 int lbmask
= lbsize
- 1;
633 * mode 0 - Dump everything then exit
634 * mode 1 - Dump everything then block/loop
635 * mode 2 - Skeep to end then block/loop
637 if (cmd
->tail_mode
== 2)
638 windex
= InitCmd
->logwindex
;
640 windex
= InitCmd
->logwindex
- InitCmd
->logcount
;
642 dotstate
= 0; /* 0=start-of-line 1=middle-of-line 2=dot */
646 * Calculate the amount of data we missed and determine
647 * if some data was lost.
649 n
= InitCmd
->logwindex
- windex
;
650 if (n
< 0 || n
> InitCmd
->logcount
) {
651 windex
= InitCmd
->logwindex
- InitCmd
->logcount
;
652 pthread_mutex_unlock(&serial_mtx
);
653 fprintf(cmd
->fp
, "\n(LOG DATA LOST)\n");
654 pthread_mutex_lock(&serial_mtx
);
659 * Circular buffer and copy size limitations. If no
660 * data ready, wait for some.
662 if (n
> lbsize
- (windex
& lbmask
))
663 n
= lbsize
- (windex
& lbmask
);
667 if (cmd
->tail_mode
== 0)
669 pthread_cond_wait(&InitCmd
->logcond
, &serial_mtx
);
672 bcopy(InitCmd
->logbuf
+ (windex
& lbmask
), buf
, n
);
675 * Dump log output, escape any '.' on a line by itself.
677 pthread_mutex_unlock(&serial_mtx
);
678 n
= escapewrite(cmd
->fp
, buf
, n
, &dotstate
);
681 lastnl
= (buf
[n
-1] == '\n');
682 pthread_mutex_lock(&serial_mtx
);
689 pthread_mutex_unlock(&serial_mtx
);
690 fprintf(cmd
->fp
, "\n");
691 pthread_mutex_lock(&serial_mtx
);
697 * Change or reopen logfile.
700 execute_logfile(command_t
*cmd
)
708 logfile
= cmd
->logfile
;
709 if (cmd
->ext_av
&& cmd
->ext_av
[0])
710 logfile
= cmd
->ext_av
[0];
712 logfile
= InitCmd
->logfile
;
716 if (InitCmd
->logfile
&&
717 strcmp(InitCmd
->logfile
, logfile
) == 0) {
718 fprintf(cmd
->fp
, "svc %s: Reopen logfile %s\n",
719 cmd
->label
, logfile
);
721 fprintf(cmd
->fp
, "svc %s: Change logfile to %s\n",
722 cmd
->label
, logfile
);
724 if (InitCmd
->logfd
>= 0) {
725 close(InitCmd
->logfd
);
728 if (strcmp(logfile
, "/dev/null") == 0) {
729 sreplace(&InitCmd
->logfile
, logfile
);
731 fd
= open(logfile
, O_WRONLY
|O_CREAT
|O_APPEND
, 0640);
734 sreplace(&InitCmd
->logfile
, logfile
);
737 "svc %s: Unable to open/create "
740 logfile
, strerror(errno
));
749 execute_help(command_t
*cmd
)
752 "svc [options] directive [label [additional_args]]\n"
754 "Directives: init start stop stopall restart exit\n"
755 " kill list status log logf tailf logfile\n"
763 logger_thread(void *arg
)
765 command_t
*cmd
= arg
;
766 int lbsize
= (int)sizeof(cmd
->logbuf
);
767 int lbmask
= lbsize
- 1;
771 pthread_detach(pthread_self());
772 pthread_mutex_lock(&serial_mtx
);
775 * slip circular buffer to make room for new data.
777 n
= cmd
->logcount
- (lbsize
- LOGCHUNK
);
782 windex
= cmd
->logwindex
& lbmask
;
786 pthread_mutex_unlock(&serial_mtx
);
787 n
= read(cmd
->logfds
[0], cmd
->logbuf
+ windex
, n
);
788 pthread_mutex_lock(&serial_mtx
);
791 write(cmd
->logfd
, cmd
->logbuf
+ windex
, n
);
794 pthread_cond_signal(&cmd
->logcond
);
796 if (n
== 0 || (n
< 0 && errno
!= EINTR
))
799 pthread_mutex_unlock(&serial_mtx
);
804 * Put us in the STOPPED state if we are not already there, and
805 * handle post-stop options (aka sync).
809 setstate_stopped(command_t
*cmd
, struct timespec
*ts
)
811 if (RunState
!= RS_STOPPED
) {
812 RunState
= RS_STOPPED
;
813 LastStop
= ts
->tv_sec
;
814 if (cmd
->sync_mode
) /* support -s option */
821 setup_gid(command_t
*cmd
)
826 setgid(cmd
->grent
.gr_gid
) < 0) {
827 fprintf(cmd
->fp
, "unable to setgid to \"%s\": %s\n",
828 cmd
->grent
.gr_name
, strerror(errno
));
833 * -G overrides all group ids.
836 if (setgroups(cmd
->ngroups
, cmd
->groups
) < 0) {
837 fprintf(cmd
->fp
, "unable to setgroups to (");
838 for (i
= 0; i
< cmd
->ngroups
; ++i
) {
840 fprintf(cmd
->fp
, ", ");
841 fprintf(cmd
->fp
, "%d", cmd
->groups
[i
]);
843 fprintf(cmd
->fp
, "): %s\n", strerror(errno
));
852 setup_uid(command_t
*cmd
)
854 fprintf(stderr
, "UIDMODE %d %d\n", cmd
->uid_mode
, cmd
->pwent
.pw_uid
);
856 cmd
->gid_mode
== 0 &&
858 setgid(cmd
->pwent
.pw_gid
) < 0) {
859 fprintf(cmd
->fp
, "unable to setgid for user \"%s\": %s\n",
865 setuid(cmd
->pwent
.pw_uid
) < 0) {
866 fprintf(cmd
->fp
, "unable to setuid for user \"%s\": %s\n",
876 setup_jail(command_t
*cmd
)
881 if (gethostname(hostbuf
, sizeof(hostbuf
) - 1) < 0) {
882 fprintf(cmd
->fp
, "gethostname() failed: %s\n", strerror(errno
));
885 /* make sure it is zero terminated */
886 hostbuf
[sizeof(hostbuf
) -1] = 0;
888 bzero(&info
, sizeof(info
));
890 info
.path
= cmd
->jaildir
;
891 info
.hostname
= hostbuf
;
892 /* info.n_ips, sockaddr_storage ips[] */
894 if (jail(&info
) < 0) {
895 fprintf(cmd
->fp
, "unable to create jail \"%s\": %s\n",
905 setup_chroot(command_t
*cmd
)
907 if (chroot(cmd
->rootdir
) < 0) {
908 fprintf(cmd
->fp
, "unable to chroot to \"%s\": %s\n",
918 setup_devfs(command_t
*cmd
, const char *dir
, int domount
)
920 struct devfs_mount_info info
;
925 bzero(&info
, sizeof(info
));
927 asprintf(&path
, "%s/dev", dir
);
930 if (statfs(path
, &fs
) == 0 &&
931 strcmp(fs
.f_fstypename
, "devfs") == 0) {
932 fprintf(cmd
->fp
, "devfs already mounted\n");
934 if (mount("devfs", path
, MNT_NOEXEC
|MNT_NOSUID
, &info
) < 0) {
935 fprintf(cmd
->fp
, "cannot mount devfs on %s: %s\n",
936 path
, strerror(errno
));
940 if (statfs(path
, &fs
) < 0 ||
941 strcmp(fs
.f_fstypename
, "devfs") != 0) {
942 fprintf(cmd
->fp
, "devfs already unmounted\n");
944 if (unmount(path
, 0) < 0) {
945 fprintf(cmd
->fp
, "cannot unmount devfs from %s: %s\n",
946 path
, strerror(errno
));
955 * Escape writes. A '.' on a line by itself must be escaped to '..'.
959 escapewrite(FILE *fp
, char *buf
, int n
, int *statep
)
970 for (i
= b
; i
< n
; ++i
) {
992 * dot was output at beginning of line
1002 if (*statep
== 3) /* flush with escape */
1006 n
= fwrite(buf
, 1, i
- b
, fp
);
1012 if (*statep
== 3) { /* added escape */
1013 n
= fwrite(".", 1, 1, fp
);
1014 /* escapes not counted in r */