2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * fork.c - safe forking for svc.startd
28 *
29 * fork_configd() and fork_sulogin() are related, special cases that handle the
30 * spawning of specific client processes for svc.startd.
31 */
32
33 #include <sys/contract/process.h>
34 #include <sys/corectl.h>
35 #include <sys/ctfs.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38 #include <sys/uio.h>
39 #include <sys/wait.h>
40 #include <assert.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <libcontract.h>
44 #include <libcontract_priv.h>
45 #include <libscf_priv.h>
46 #include <limits.h>
47 #include <port.h>
48 #include <signal.h>
49 #include <stdarg.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <unistd.h>
54 #include <utmpx.h>
55
56 #include "configd_exit.h"
57 #include "protocol.h"
58 #include "startd.h"
59
60 static struct utmpx *utmpp; /* pointer for getutxent() */
61
62 pid_t
63 startd_fork1(int *forkerr)
64 {
65 pid_t p;
66
67 /*
68 * prefork stack
69 */
70 wait_prefork();
71
72 p = fork1();
73
74 if (p == -1 && forkerr != NULL)
661 setlog(log);
662
663 now = time(NULL);
664 sz = strftime(timebuf, sizeof (timebuf), "%b %e %T",
665 localtime_r(&now, <ime));
666 assert(sz != 0);
667
668 (void) fprintf(stderr, "%s Executing %s %s\n", timebuf, path, arg);
669
670 if (rl == 'S')
671 pathenv = "PATH=/sbin:/usr/sbin:/usr/bin";
672 else
673 pathenv = "PATH=/usr/sbin:/usr/bin";
674
675 nenv = set_smf_env(NULL, 0, pathenv, NULL, NULL);
676
677 (void) execle(path, path, arg, 0, nenv);
678
679 perror("exec");
680 exit(0);
681 }
|
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * fork.c - safe forking for svc.startd
28 *
29 * fork_configd() and fork_sulogin() are related, special cases that handle the
30 * spawning of specific client processes for svc.startd.
31 */
32
33 #include <sys/contract/process.h>
34 #include <sys/corectl.h>
35 #include <sys/ctfs.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38 #include <sys/uio.h>
39 #include <sys/wait.h>
40 #include <assert.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <libcontract.h>
44 #include <libcontract_priv.h>
45 #include <libscf_priv.h>
46 #include <limits.h>
47 #include <poll.h>
48 #include <port.h>
49 #include <signal.h>
50 #include <stdarg.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <unistd.h>
55 #include <utmpx.h>
56 #include <spawn.h>
57
58 #include "configd_exit.h"
59 #include "protocol.h"
60 #include "startd.h"
61
62 static struct utmpx *utmpp; /* pointer for getutxent() */
63
64 pid_t
65 startd_fork1(int *forkerr)
66 {
67 pid_t p;
68
69 /*
70 * prefork stack
71 */
72 wait_prefork();
73
74 p = fork1();
75
76 if (p == -1 && forkerr != NULL)
663 setlog(log);
664
665 now = time(NULL);
666 sz = strftime(timebuf, sizeof (timebuf), "%b %e %T",
667 localtime_r(&now, <ime));
668 assert(sz != 0);
669
670 (void) fprintf(stderr, "%s Executing %s %s\n", timebuf, path, arg);
671
672 if (rl == 'S')
673 pathenv = "PATH=/sbin:/usr/sbin:/usr/bin";
674 else
675 pathenv = "PATH=/usr/sbin:/usr/bin";
676
677 nenv = set_smf_env(NULL, 0, pathenv, NULL, NULL);
678
679 (void) execle(path, path, arg, 0, nenv);
680
681 perror("exec");
682 exit(0);
683 }
684
685 extern char **environ;
686
687 /*
688 * A local variation on system(3c) which accepts a timeout argument. This
689 * allows us to better ensure that the system will actually shut down.
690 *
691 * gracetime specifies an amount of time in seconds which the routine must wait
692 * after the command exits, to allow for asynchronous effects (like sent
693 * signals) to take effect. This can be zero.
694 */
695 void
696 fork_with_timeout(const char *cmd, uint_t gracetime, uint_t timeout)
697 {
698 int err = 0;
699 pid_t pid;
700 char *argv[4];
701 posix_spawnattr_t attr;
702 posix_spawn_file_actions_t factions;
703
704 sigset_t mask, savemask;
705 uint_t msec_timeout;
706 uint_t msec_spent = 0;
707 uint_t msec_gracetime;
708 int status;
709
710 msec_timeout = timeout * 1000;
711 msec_gracetime = gracetime * 1000;
712
713 /*
714 * See also system(3c) in libc. This is very similar, except
715 * that we avoid some unneeded complexity.
716 */
717 err = posix_spawnattr_init(&attr);
718 if (err == 0)
719 err = posix_spawnattr_setflags(&attr,
720 POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF |
721 POSIX_SPAWN_NOSIGCHLD_NP | POSIX_SPAWN_WAITPID_NP |
722 POSIX_SPAWN_NOEXECERR_NP);
723
724 /*
725 * We choose to close fd's above 2, a deviation from system.
726 */
727 if (err == 0)
728 err = posix_spawn_file_actions_init(&factions);
729 if (err == 0)
730 err = posix_spawn_file_actions_addclosefrom_np(&factions,
731 STDERR_FILENO + 1);
732
733 (void) sigemptyset(&mask);
734 (void) sigaddset(&mask, SIGCHLD);
735 (void) thr_sigsetmask(SIG_BLOCK, &mask, &savemask);
736
737 argv[0] = "/bin/sh";
738 argv[1] = "-c";
739 argv[2] = (char *)cmd;
740 argv[3] = NULL;
741
742 if (err == 0)
743 err = posix_spawn(&pid, "/bin/sh", &factions, &attr,
744 (char *const *)argv, (char *const *)environ);
745
746 (void) posix_spawnattr_destroy(&attr);
747 (void) posix_spawn_file_actions_destroy(&factions);
748
749 if (err) {
750 uu_warn("Failed to spawn %s: %s\n", cmd, strerror(err));
751 } else {
752 for (;;) {
753 int w;
754 w = waitpid(pid, &status, WNOHANG);
755 if (w == -1 && errno != EINTR)
756 break;
757 if (w > 0) {
758 /*
759 * Command succeeded, so give it gracetime
760 * seconds for it to have an effect.
761 */
762 if (status == 0 && msec_gracetime != 0)
763 (void) poll(NULL, 0, msec_gracetime);
764 break;
765 }
766
767 (void) poll(NULL, 0, 100);
768 msec_spent += 100;
769 /*
770 * If we timed out, kill off the process, then try to
771 * wait for it-- it's possible that we could accumulate
772 * a zombie here since we don't allow waitpid to hang,
773 * but it's better to let that happen and continue to
774 * make progress.
775 */
776 if (msec_spent >= msec_timeout) {
777 uu_warn("'%s' timed out after %d "
778 "seconds. Killing.\n", cmd,
779 timeout);
780 (void) kill(pid, SIGTERM);
781 (void) poll(NULL, 0, 100);
782 (void) kill(pid, SIGKILL);
783 (void) poll(NULL, 0, 100);
784 (void) waitpid(pid, &status, WNOHANG);
785 break;
786 }
787 }
788 }
789 (void) thr_sigsetmask(SIG_BLOCK, &savemask, NULL);
790 }
|