xref: /onnv-gate/usr/src/cmd/svc/startd/specials.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * specials.c - knowledge of special services
31*0Sstevel@tonic-gate  *
32*0Sstevel@tonic-gate  * svc.startd(1M) has duties that cannot be carried out without knowledge of the
33*0Sstevel@tonic-gate  * transition of various services, such as the milestones, to their online
34*0Sstevel@tonic-gate  * states.  Hooks are called with the restarter instance's ri_lock held, so
35*0Sstevel@tonic-gate  * operations on all instances (or on the graph) should be performed
36*0Sstevel@tonic-gate  * asynchronously.
37*0Sstevel@tonic-gate  */
38*0Sstevel@tonic-gate 
39*0Sstevel@tonic-gate #include <sys/statvfs.h>
40*0Sstevel@tonic-gate #include <sys/types.h>
41*0Sstevel@tonic-gate #include <assert.h>
42*0Sstevel@tonic-gate #include <errno.h>
43*0Sstevel@tonic-gate #include <libintl.h>
44*0Sstevel@tonic-gate #include <limits.h>
45*0Sstevel@tonic-gate #include <locale.h>
46*0Sstevel@tonic-gate #include <pthread.h>
47*0Sstevel@tonic-gate #include <signal.h>
48*0Sstevel@tonic-gate #include <stdio.h>
49*0Sstevel@tonic-gate #include <string.h>
50*0Sstevel@tonic-gate #include <strings.h>
51*0Sstevel@tonic-gate #include <time.h>
52*0Sstevel@tonic-gate #include <zone.h>
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate #include "startd.h"
55*0Sstevel@tonic-gate 
56*0Sstevel@tonic-gate void
57*0Sstevel@tonic-gate special_null_transition()
58*0Sstevel@tonic-gate {
59*0Sstevel@tonic-gate }
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate static void
62*0Sstevel@tonic-gate special_fsroot_post_online()
63*0Sstevel@tonic-gate {
64*0Sstevel@tonic-gate 	static int once;
65*0Sstevel@tonic-gate 	char *locale;
66*0Sstevel@tonic-gate 
67*0Sstevel@tonic-gate 	/*
68*0Sstevel@tonic-gate 	 * /usr, with timezone and locale data, is now available.
69*0Sstevel@tonic-gate 	 */
70*0Sstevel@tonic-gate 	if (!st->st_log_timezone_known) {
71*0Sstevel@tonic-gate 		tzset();
72*0Sstevel@tonic-gate 		st->st_log_timezone_known = 1;
73*0Sstevel@tonic-gate 	}
74*0Sstevel@tonic-gate 
75*0Sstevel@tonic-gate 	if (!st->st_log_locale_known) {
76*0Sstevel@tonic-gate 		if (st->st_locale)
77*0Sstevel@tonic-gate 			locale = st->st_locale;
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate 		(void) setlocale(LC_ALL, "");
80*0Sstevel@tonic-gate 		st->st_locale = setlocale(LC_MESSAGES, "");
81*0Sstevel@tonic-gate 		if (st->st_locale) {
82*0Sstevel@tonic-gate 			st->st_locale = safe_strdup(st->st_locale);
83*0Sstevel@tonic-gate 			xstr_sanitize(st->st_locale);
84*0Sstevel@tonic-gate 			free(locale);
85*0Sstevel@tonic-gate 		} else {
86*0Sstevel@tonic-gate 			st->st_locale = locale;
87*0Sstevel@tonic-gate 		}
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate 		(void) textdomain(TEXT_DOMAIN);
90*0Sstevel@tonic-gate 		st->st_log_locale_known = 1;
91*0Sstevel@tonic-gate 	}
92*0Sstevel@tonic-gate 
93*0Sstevel@tonic-gate 	if (once)
94*0Sstevel@tonic-gate 		return;
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate 	/*
97*0Sstevel@tonic-gate 	 * ctime(3C) ends with '\n\0'.
98*0Sstevel@tonic-gate 	 */
99*0Sstevel@tonic-gate 	once++;
100*0Sstevel@tonic-gate 	log_framework(LOG_INFO, "system start time was %s",
101*0Sstevel@tonic-gate 	    ctime(&st->st_start_time.tv_sec));
102*0Sstevel@tonic-gate }
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate static void
105*0Sstevel@tonic-gate special_fsminimal_post_online()
106*0Sstevel@tonic-gate {
107*0Sstevel@tonic-gate 	ulong_t rfsid, vfsid;
108*0Sstevel@tonic-gate 	pid_t init_pid;
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate 	log_framework(LOG_DEBUG, "special_fsminimal_post_online hook "
111*0Sstevel@tonic-gate 	    "executed\n");
112*0Sstevel@tonic-gate 
113*0Sstevel@tonic-gate 	/*
114*0Sstevel@tonic-gate 	 * Are / and /var really writeable?
115*0Sstevel@tonic-gate 	 */
116*0Sstevel@tonic-gate 	switch (fs_is_read_only("/", &rfsid)) {
117*0Sstevel@tonic-gate 	case 1:
118*0Sstevel@tonic-gate 		return;		/* still read-only: install / ro root */
119*0Sstevel@tonic-gate 	case 0:
120*0Sstevel@tonic-gate 		break;
121*0Sstevel@tonic-gate 	case -1:
122*0Sstevel@tonic-gate 	default:
123*0Sstevel@tonic-gate 		log_error(LOG_WARNING, gettext("couldn't check status of "
124*0Sstevel@tonic-gate 			"root filesystem: %s\n"), strerror(errno));
125*0Sstevel@tonic-gate 		break;
126*0Sstevel@tonic-gate 	}
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate 	switch (fs_is_read_only("/var", &vfsid)) {
129*0Sstevel@tonic-gate 	case 1:
130*0Sstevel@tonic-gate 		if (vfsid != rfsid) {
131*0Sstevel@tonic-gate 			log_framework(LOG_WARNING, "/var filesystem "
132*0Sstevel@tonic-gate 			    "read-only after system/filesystem/minimal\n");
133*0Sstevel@tonic-gate 			if (fs_remount("/var"))
134*0Sstevel@tonic-gate 				log_framework(LOG_WARNING, "/var "
135*0Sstevel@tonic-gate 					"filesystem remount failed\n");
136*0Sstevel@tonic-gate 		}
137*0Sstevel@tonic-gate 		break;
138*0Sstevel@tonic-gate 	case 0:
139*0Sstevel@tonic-gate 		break;
140*0Sstevel@tonic-gate 	case -1:
141*0Sstevel@tonic-gate 	default:
142*0Sstevel@tonic-gate 		log_error(LOG_WARNING, gettext("couldn't check status of "
143*0Sstevel@tonic-gate 		    "/var filesystem: %s\n"), strerror(errno));
144*0Sstevel@tonic-gate 		break;
145*0Sstevel@tonic-gate 	}
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate 	/*
148*0Sstevel@tonic-gate 	 * Clear (dead) entries and record boot time.
149*0Sstevel@tonic-gate 	 */
150*0Sstevel@tonic-gate 	utmpx_clear_old();
151*0Sstevel@tonic-gate 	utmpx_write_boottime();
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate 	/*
154*0Sstevel@tonic-gate 	 * Reinitialize the logs to point to LOG_PREFIX_NORMAL.
155*0Sstevel@tonic-gate 	 */
156*0Sstevel@tonic-gate 	log_init();
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate 	/*
159*0Sstevel@tonic-gate 	 * Poke init so it will create /etc/initpipe.
160*0Sstevel@tonic-gate 	 */
161*0Sstevel@tonic-gate 	if (zone_getattr(getzoneid(), ZONE_ATTR_INITPID, &init_pid,
162*0Sstevel@tonic-gate 	    sizeof (init_pid)) != sizeof (init_pid)) {
163*0Sstevel@tonic-gate 		log_error(LOG_WARNING, "Could not get pid of init: %s.\n",
164*0Sstevel@tonic-gate 		    strerror(errno));
165*0Sstevel@tonic-gate 	} else {
166*0Sstevel@tonic-gate 		if (kill(init_pid, SIGHUP) != 0) {
167*0Sstevel@tonic-gate 			switch (errno) {
168*0Sstevel@tonic-gate 			case EPERM:
169*0Sstevel@tonic-gate 			case ESRCH:
170*0Sstevel@tonic-gate 				log_error(LOG_WARNING,
171*0Sstevel@tonic-gate 				    "Could not signal init: %s.\n",
172*0Sstevel@tonic-gate 				    strerror(errno));
173*0Sstevel@tonic-gate 				break;
174*0Sstevel@tonic-gate 
175*0Sstevel@tonic-gate 			case EINVAL:
176*0Sstevel@tonic-gate 			default:
177*0Sstevel@tonic-gate 				bad_error("kill", errno);
178*0Sstevel@tonic-gate 			}
179*0Sstevel@tonic-gate 		}
180*0Sstevel@tonic-gate 	}
181*0Sstevel@tonic-gate 
182*0Sstevel@tonic-gate 	/*
183*0Sstevel@tonic-gate 	 * Take pending snapshots and create a svc.startd instance.
184*0Sstevel@tonic-gate 	 */
185*0Sstevel@tonic-gate 	(void) startd_thread_create(restarter_post_fsminimal_thread, NULL);
186*0Sstevel@tonic-gate }
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate static void
189*0Sstevel@tonic-gate special_single_post_online()
190*0Sstevel@tonic-gate {
191*0Sstevel@tonic-gate 	int r;
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate 	log_framework(LOG_DEBUG, "special_single_post_online hook executed\n");
194*0Sstevel@tonic-gate 
195*0Sstevel@tonic-gate 	/*
196*0Sstevel@tonic-gate 	 * Un-set the special reconfig reboot property.
197*0Sstevel@tonic-gate 	 */
198*0Sstevel@tonic-gate 	r = libscf_set_reconfig(0);
199*0Sstevel@tonic-gate 	switch (r) {
200*0Sstevel@tonic-gate 	case 0:
201*0Sstevel@tonic-gate 	case ENOENT:
202*0Sstevel@tonic-gate 		break;
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate 	case EPERM:
205*0Sstevel@tonic-gate 	case EACCES:
206*0Sstevel@tonic-gate 	case EROFS:
207*0Sstevel@tonic-gate 		log_error(LOG_WARNING, "Could not clear reconfiguration "
208*0Sstevel@tonic-gate 		    "property: %s.\n", strerror(r));
209*0Sstevel@tonic-gate 		break;
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate 	default:
212*0Sstevel@tonic-gate 		bad_error("libscf_set_reconfig", r);
213*0Sstevel@tonic-gate 	}
214*0Sstevel@tonic-gate 
215*0Sstevel@tonic-gate 	if (booting_to_single_user)
216*0Sstevel@tonic-gate 		(void) startd_thread_create(single_user_thread, NULL);
217*0Sstevel@tonic-gate }
218*0Sstevel@tonic-gate 
219*0Sstevel@tonic-gate static service_hook_assn_t special_svcs[] = {
220*0Sstevel@tonic-gate 	{ "svc:/system/filesystem/root:default",
221*0Sstevel@tonic-gate 		special_null_transition,
222*0Sstevel@tonic-gate 		special_fsroot_post_online,
223*0Sstevel@tonic-gate 		special_null_transition },
224*0Sstevel@tonic-gate 	{ "svc:/system/filesystem/minimal:default",
225*0Sstevel@tonic-gate 		special_null_transition,
226*0Sstevel@tonic-gate 		special_fsminimal_post_online,
227*0Sstevel@tonic-gate 		special_null_transition },
228*0Sstevel@tonic-gate 	{ "svc:/milestone/single-user:default",
229*0Sstevel@tonic-gate 		special_null_transition,
230*0Sstevel@tonic-gate 		special_single_post_online,
231*0Sstevel@tonic-gate 		special_null_transition },
232*0Sstevel@tonic-gate };
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate void
235*0Sstevel@tonic-gate special_online_hooks_get(const char *fmri, instance_hook_t *pre_onp,
236*0Sstevel@tonic-gate     instance_hook_t *post_onp, instance_hook_t *post_offp)
237*0Sstevel@tonic-gate {
238*0Sstevel@tonic-gate 	int i;
239*0Sstevel@tonic-gate 
240*0Sstevel@tonic-gate 	for (i = 0; i < sizeof (special_svcs) / sizeof (service_hook_assn_t);
241*0Sstevel@tonic-gate 	    i++)
242*0Sstevel@tonic-gate 		if (strcmp(fmri, special_svcs[i].sh_fmri) == 0) {
243*0Sstevel@tonic-gate 			*pre_onp = special_svcs[i].sh_pre_online_hook;
244*0Sstevel@tonic-gate 			*post_onp = special_svcs[i].sh_post_online_hook;
245*0Sstevel@tonic-gate 			*post_offp = special_svcs[i].sh_post_online_hook;
246*0Sstevel@tonic-gate 			return;
247*0Sstevel@tonic-gate 		}
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate 	*pre_onp = *post_onp = *post_offp = special_null_transition;
250*0Sstevel@tonic-gate }
251