Mercurial > illumos > illumos-gate
annotate usr/src/cmd/svc/startd/startd.c @ 14129:790945ad7848
3986 svc.startd dies in getutxent_frec()
3987 svc.startd dies in utmpx_postfork()
Reviewed by: Keith Wesolowski <keith.wesolowski@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Saso Kiselkov <skiselkov@gmail.com>
Approved by: Richard Lowe <richlowe@richlowe.net>
author | Bryan Cantrill <bryan@joyent.com> |
---|---|
date | Sun, 04 Aug 2013 09:58:38 -0700 |
parents | da056fdd2d14 |
children |
rev | line source |
---|---|
0 | 1 /* |
2 * CDDL HEADER START | |
3 * | |
4 * The contents of this file are subject to the terms of the | |
1914
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
195
diff
changeset
|
5 * Common Development and Distribution License (the "License"). |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
195
diff
changeset
|
6 * You may not use this file except in compliance with the License. |
0 | 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 */ | |
5040
ff6ebd8761a6
PSARC 2007/177 SMF read-protected property storage
wesolows
parents:
2258
diff
changeset
|
21 |
0 | 22 /* |
12979
ab9ae749152f
PSARC/2009/617 Software Events Notification Parameters CLI
Gavin Maltby <gavin.maltby@oracle.com>
parents:
11996
diff
changeset
|
23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. |
13719
da056fdd2d14
2831 bring Joyent/SmartOS OS-1186 and OS-1187 to Illumos
Bryan Cantrill <bryan@joyent.com>
parents:
13718
diff
changeset
|
24 * Copyright (c) 2012, Joyent, Inc. All rights reserved. |
0 | 25 */ |
26 | |
27 /* | |
28 * startd.c - the master restarter | |
29 * | |
30 * svc.startd comprises two halves. The graph engine is based in graph.c and | |
31 * maintains the service dependency graph based on the information in the | |
32 * repository. For each service it also tracks the current state and the | |
33 * restarter responsible for the service. Based on the graph, events from the | |
34 * repository (mostly administrative requests from svcadm), and messages from | |
35 * the restarters, the graph engine makes decisions about how the services | |
36 * should be manipulated and sends commands to the appropriate restarters. | |
37 * Communication between the graph engine and the restarters is embodied in | |
38 * protocol.c. | |
39 * | |
40 * The second half of svc.startd is the restarter for services managed by | |
41 * svc.startd and is primarily contained in restarter.c. It responds to graph | |
42 * engine commands by executing methods, updating the repository, and sending | |
43 * feedback (mostly state updates) to the graph engine. | |
44 * | |
45 * Error handling | |
46 * | |
47 * In general, when svc.startd runs out of memory it reattempts a few times, | |
48 * sleeping inbetween, before giving up and exiting (see startd_alloc_retry()). | |
49 * When a repository connection is broken (libscf calls fail with | |
50 * SCF_ERROR_CONNECTION_BROKEN, librestart and internal functions return | |
51 * ECONNABORTED), svc.startd calls libscf_rebind_handle(), which coordinates | |
52 * with the svc.configd-restarting thread, fork_configd_thread(), via | |
53 * st->st_configd_live_cv, and rebinds the repository handle. Doing so resets | |
54 * all libscf state associated with that handle, so functions which do this | |
55 * should communicate the event to their callers (usually by returning | |
56 * ECONNRESET) so they may reset their state appropriately. | |
5777
e3276fcb93e7
5079356 Framework should provide administrative audit trail/history
tw21770
parents:
5617
diff
changeset
|
57 * |
e3276fcb93e7
5079356 Framework should provide administrative audit trail/history
tw21770
parents:
5617
diff
changeset
|
58 * External references |
e3276fcb93e7
5079356 Framework should provide administrative audit trail/history
tw21770
parents:
5617
diff
changeset
|
59 * |
e3276fcb93e7
5079356 Framework should provide administrative audit trail/history
tw21770
parents:
5617
diff
changeset
|
60 * svc.configd generates special security audit events for changes to some |
e3276fcb93e7
5079356 Framework should provide administrative audit trail/history
tw21770
parents:
5617
diff
changeset
|
61 * restarter related properties. See the special_props_list array in |
e3276fcb93e7
5079356 Framework should provide administrative audit trail/history
tw21770
parents:
5617
diff
changeset
|
62 * usr/src/cmd/svc/configd/rc_node.c for the properties that cause these audit |
e3276fcb93e7
5079356 Framework should provide administrative audit trail/history
tw21770
parents:
5617
diff
changeset
|
63 * events. If you change the semantics of these propereties within startd, you |
e3276fcb93e7
5079356 Framework should provide administrative audit trail/history
tw21770
parents:
5617
diff
changeset
|
64 * will probably need to update rc_node.c |
0 | 65 */ |
66 | |
67 #include <stdio.h> | |
1914
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
195
diff
changeset
|
68 #include <stdio_ext.h> |
0 | 69 #include <sys/mnttab.h> /* uses FILE * without including stdio.h */ |
70 #include <alloca.h> | |
71 #include <sys/mount.h> | |
72 #include <sys/stat.h> | |
73 #include <sys/types.h> | |
74 #include <sys/wait.h> | |
75 #include <assert.h> | |
76 #include <errno.h> | |
77 #include <fcntl.h> | |
78 #include <ftw.h> | |
79 #include <libintl.h> | |
80 #include <libscf.h> | |
81 #include <libscf_priv.h> | |
82 #include <libuutil.h> | |
83 #include <locale.h> | |
84 #include <poll.h> | |
85 #include <pthread.h> | |
86 #include <signal.h> | |
87 #include <stdarg.h> | |
88 #include <stdlib.h> | |
89 #include <string.h> | |
90 #include <strings.h> | |
91 #include <unistd.h> | |
92 | |
93 #include "startd.h" | |
94 #include "protocol.h" | |
95 | |
96 ssize_t max_scf_name_size; | |
97 ssize_t max_scf_fmri_size; | |
98 ssize_t max_scf_value_size; | |
99 | |
100 mode_t fmask; | |
101 mode_t dmask; | |
102 | |
103 graph_update_t *gu; | |
104 restarter_update_t *ru; | |
105 | |
106 startd_state_t *st; | |
107 | |
108 boolean_t booting_to_single_user = B_FALSE; | |
109 | |
110 const char * const admin_actions[] = { | |
111 SCF_PROPERTY_DEGRADED, | |
112 SCF_PROPERTY_MAINT_OFF, | |
113 SCF_PROPERTY_MAINT_ON, | |
114 SCF_PROPERTY_MAINT_ON_IMMEDIATE, | |
115 SCF_PROPERTY_REFRESH, | |
116 SCF_PROPERTY_RESTART | |
117 }; | |
118 | |
119 const int admin_events[NACTIONS] = { | |
120 RESTARTER_EVENT_TYPE_ADMIN_DEGRADED, | |
121 RESTARTER_EVENT_TYPE_ADMIN_MAINT_OFF, | |
122 RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON, | |
123 RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON_IMMEDIATE, | |
124 RESTARTER_EVENT_TYPE_ADMIN_REFRESH, | |
125 RESTARTER_EVENT_TYPE_ADMIN_RESTART | |
126 }; | |
127 | |
128 const char * const instance_state_str[] = { | |
129 "none", | |
130 "uninitialized", | |
131 "maintenance", | |
132 "offline", | |
133 "disabled", | |
134 "online", | |
135 "degraded" | |
136 }; | |
137 | |
138 static int finished = 0; | |
139 static int opt_reconfig = 0; | |
140 static uint8_t prop_reconfig = 0; | |
141 | |
142 #define INITIAL_REBIND_ATTEMPTS 5 | |
143 #define INITIAL_REBIND_DELAY 3 | |
144 | |
145 pthread_mutexattr_t mutex_attrs; | |
146 | |
13719
da056fdd2d14
2831 bring Joyent/SmartOS OS-1186 and OS-1187 to Illumos
Bryan Cantrill <bryan@joyent.com>
parents:
13718
diff
changeset
|
147 #ifdef DEBUG |
0 | 148 const char * |
149 _umem_debug_init(void) | |
150 { | |
151 return ("default,verbose"); /* UMEM_DEBUG setting */ | |
152 } | |
153 | |
154 const char * | |
155 _umem_logging_init(void) | |
156 { | |
157 return ("fail,contents"); /* UMEM_LOGGING setting */ | |
158 } | |
13719
da056fdd2d14
2831 bring Joyent/SmartOS OS-1186 and OS-1187 to Illumos
Bryan Cantrill <bryan@joyent.com>
parents:
13718
diff
changeset
|
159 #endif |
da056fdd2d14
2831 bring Joyent/SmartOS OS-1186 and OS-1187 to Illumos
Bryan Cantrill <bryan@joyent.com>
parents:
13718
diff
changeset
|
160 |
da056fdd2d14
2831 bring Joyent/SmartOS OS-1186 and OS-1187 to Illumos
Bryan Cantrill <bryan@joyent.com>
parents:
13718
diff
changeset
|
161 const char * |
da056fdd2d14
2831 bring Joyent/SmartOS OS-1186 and OS-1187 to Illumos
Bryan Cantrill <bryan@joyent.com>
parents:
13718
diff
changeset
|
162 _umem_options_init(void) |
da056fdd2d14
2831 bring Joyent/SmartOS OS-1186 and OS-1187 to Illumos
Bryan Cantrill <bryan@joyent.com>
parents:
13718
diff
changeset
|
163 { |
da056fdd2d14
2831 bring Joyent/SmartOS OS-1186 and OS-1187 to Illumos
Bryan Cantrill <bryan@joyent.com>
parents:
13718
diff
changeset
|
164 /* |
da056fdd2d14
2831 bring Joyent/SmartOS OS-1186 and OS-1187 to Illumos
Bryan Cantrill <bryan@joyent.com>
parents:
13718
diff
changeset
|
165 * To reduce our memory footprint, we set our UMEM_OPTIONS to indicate |
da056fdd2d14
2831 bring Joyent/SmartOS OS-1186 and OS-1187 to Illumos
Bryan Cantrill <bryan@joyent.com>
parents:
13718
diff
changeset
|
166 * that we do not wish to have per-CPU magazines -- if svc.startd is so |
da056fdd2d14
2831 bring Joyent/SmartOS OS-1186 and OS-1187 to Illumos
Bryan Cantrill <bryan@joyent.com>
parents:
13718
diff
changeset
|
167 * hot on CPU such that this becomes a scalability problem, there are |
da056fdd2d14
2831 bring Joyent/SmartOS OS-1186 and OS-1187 to Illumos
Bryan Cantrill <bryan@joyent.com>
parents:
13718
diff
changeset
|
168 * likely deeper things amiss... |
da056fdd2d14
2831 bring Joyent/SmartOS OS-1186 and OS-1187 to Illumos
Bryan Cantrill <bryan@joyent.com>
parents:
13718
diff
changeset
|
169 */ |
da056fdd2d14
2831 bring Joyent/SmartOS OS-1186 and OS-1187 to Illumos
Bryan Cantrill <bryan@joyent.com>
parents:
13718
diff
changeset
|
170 return ("nomagazines"); /* UMEM_OPTIONS setting */ |
da056fdd2d14
2831 bring Joyent/SmartOS OS-1186 and OS-1187 to Illumos
Bryan Cantrill <bryan@joyent.com>
parents:
13718
diff
changeset
|
171 } |
0 | 172 |
173 /* | |
174 * startd_alloc_retry() | |
175 * Wrapper for allocation functions. Retries with a decaying time | |
176 * value on failure to allocate, and aborts startd if failure is | |
177 * persistent. | |
178 */ | |
179 void * | |
180 startd_alloc_retry(void *f(size_t, int), size_t sz) | |
181 { | |
182 void *p; | |
183 uint_t try, msecs; | |
184 | |
185 p = f(sz, UMEM_DEFAULT); | |
186 if (p != NULL || sz == 0) | |
187 return (p); | |
188 | |
189 msecs = ALLOC_DELAY; | |
190 | |
191 for (try = 0; p == NULL && try < ALLOC_RETRY; ++try) { | |
192 (void) poll(NULL, 0, msecs); | |
193 msecs *= ALLOC_DELAY_MULT; | |
194 p = f(sz, UMEM_DEFAULT); | |
195 if (p != NULL) | |
196 return (p); | |
197 } | |
198 | |
199 uu_die("Insufficient memory.\n"); | |
200 /* NOTREACHED */ | |
201 } | |
202 | |
203 void * | |
204 safe_realloc(void *p, size_t sz) | |
205 { | |
206 uint_t try, msecs; | |
207 | |
208 p = realloc(p, sz); | |
209 if (p != NULL || sz == 0) | |
210 return (p); | |
211 | |
212 msecs = ALLOC_DELAY; | |
213 | |
214 for (try = 0; errno == EAGAIN && try < ALLOC_RETRY; ++try) { | |
215 (void) poll(NULL, 0, msecs); | |
216 p = realloc(p, sz); | |
217 if (p != NULL) | |
218 return (p); | |
219 msecs *= ALLOC_DELAY_MULT; | |
220 } | |
221 | |
222 uu_die("Insufficient memory.\n"); | |
223 /* NOTREACHED */ | |
224 } | |
225 | |
226 char * | |
227 safe_strdup(const char *s) | |
228 { | |
229 uint_t try, msecs; | |
230 char *d; | |
231 | |
232 d = strdup(s); | |
233 if (d != NULL) | |
234 return (d); | |
235 | |
236 msecs = ALLOC_DELAY; | |
237 | |
238 for (try = 0; | |
239 (errno == EAGAIN || errno == ENOMEM) && try < ALLOC_RETRY; | |
240 ++try) { | |
241 (void) poll(NULL, 0, msecs); | |
242 d = strdup(s); | |
243 if (d != NULL) | |
244 return (d); | |
245 msecs *= ALLOC_DELAY_MULT; | |
246 } | |
247 | |
248 uu_die("Insufficient memory.\n"); | |
249 /* NOTREACHED */ | |
250 } | |
251 | |
252 | |
253 void | |
254 startd_free(void *p, size_t sz) | |
255 { | |
256 umem_free(p, sz); | |
257 } | |
258 | |
259 /* | |
260 * Creates a uu_list_pool_t with the same retry policy as startd_alloc(). | |
261 * Only returns NULL for UU_ERROR_UNKNOWN_FLAG and UU_ERROR_NOT_SUPPORTED. | |
262 */ | |
263 uu_list_pool_t * | |
264 startd_list_pool_create(const char *name, size_t e, size_t o, | |
265 uu_compare_fn_t *f, uint32_t flags) | |
266 { | |
267 uu_list_pool_t *pool; | |
268 uint_t try, msecs; | |
269 | |
270 pool = uu_list_pool_create(name, e, o, f, flags); | |
271 if (pool != NULL) | |
272 return (pool); | |
273 | |
274 msecs = ALLOC_DELAY; | |
275 | |
276 for (try = 0; uu_error() == UU_ERROR_NO_MEMORY && try < ALLOC_RETRY; | |
277 ++try) { | |
278 (void) poll(NULL, 0, msecs); | |
279 pool = uu_list_pool_create(name, e, o, f, flags); | |
280 if (pool != NULL) | |
281 return (pool); | |
282 msecs *= ALLOC_DELAY_MULT; | |
283 } | |
284 | |
285 if (try < ALLOC_RETRY) | |
286 return (NULL); | |
287 | |
288 uu_die("Insufficient memory.\n"); | |
289 /* NOTREACHED */ | |
290 } | |
291 | |
292 /* | |
293 * Creates a uu_list_t with the same retry policy as startd_alloc(). Only | |
294 * returns NULL for UU_ERROR_UNKNOWN_FLAG and UU_ERROR_NOT_SUPPORTED. | |
295 */ | |
296 uu_list_t * | |
297 startd_list_create(uu_list_pool_t *pool, void *parent, uint32_t flags) | |
298 { | |
299 uu_list_t *list; | |
300 uint_t try, msecs; | |
301 | |
302 list = uu_list_create(pool, parent, flags); | |
303 if (list != NULL) | |
304 return (list); | |
305 | |
306 msecs = ALLOC_DELAY; | |
307 | |
308 for (try = 0; uu_error() == UU_ERROR_NO_MEMORY && try < ALLOC_RETRY; | |
309 ++try) { | |
310 (void) poll(NULL, 0, msecs); | |
311 list = uu_list_create(pool, parent, flags); | |
312 if (list != NULL) | |
313 return (list); | |
314 msecs *= ALLOC_DELAY_MULT; | |
315 } | |
316 | |
317 if (try < ALLOC_RETRY) | |
318 return (NULL); | |
319 | |
320 uu_die("Insufficient memory.\n"); | |
321 /* NOTREACHED */ | |
322 } | |
323 | |
324 pthread_t | |
325 startd_thread_create(void *(*func)(void *), void *ptr) | |
326 { | |
327 int err; | |
328 pthread_t tid; | |
329 | |
330 err = pthread_create(&tid, NULL, func, ptr); | |
331 if (err != 0) { | |
332 assert(err == EAGAIN); | |
333 uu_die("Could not create thread.\n"); | |
334 } | |
335 | |
336 err = pthread_detach(tid); | |
337 assert(err == 0); | |
338 | |
339 return (tid); | |
340 } | |
341 | |
12979
ab9ae749152f
PSARC/2009/617 Software Events Notification Parameters CLI
Gavin Maltby <gavin.maltby@oracle.com>
parents:
11996
diff
changeset
|
342 extern int info_events_all; |
0 | 343 |
344 static int | |
1958 | 345 read_startd_config(void) |
0 | 346 { |
347 scf_handle_t *hndl; | |
348 scf_instance_t *inst; | |
349 scf_propertygroup_t *pg; | |
350 scf_property_t *prop; | |
351 scf_value_t *val; | |
352 scf_iter_t *iter, *piter; | |
353 instance_data_t idata; | |
354 char *buf, *vbuf; | |
355 char *startd_options_fmri = uu_msprintf("%s/:properties/options", | |
356 SCF_SERVICE_STARTD); | |
357 char *startd_reconfigure_fmri = uu_msprintf( | |
358 "%s/:properties/system/reconfigure", SCF_SERVICE_STARTD); | |
359 char *env_opts, *lasts, *cp; | |
360 int bind_fails = 0; | |
361 int ret = 0, r; | |
362 uint_t count = 0, msecs = ALLOC_DELAY; | |
363 size_t sz; | |
364 ctid_t ctid; | |
365 uint64_t uint64; | |
366 | |
367 buf = startd_alloc(max_scf_fmri_size); | |
368 | |
369 if (startd_options_fmri == NULL || startd_reconfigure_fmri == NULL) | |
370 uu_die("Allocation failure\n"); | |
371 | |
372 st->st_log_prefix = LOG_PREFIX_EARLY; | |
373 | |
374 if ((st->st_log_file = getenv("STARTD_DEFAULT_LOG")) == NULL) { | |
375 st->st_log_file = startd_alloc(strlen(STARTD_DEFAULT_LOG) + 1); | |
376 | |
377 (void) strcpy(st->st_log_file, STARTD_DEFAULT_LOG); | |
378 } | |
379 | |
380 st->st_door_path = getenv("STARTD_ALT_DOOR"); | |
381 | |
382 /* | |
383 * Read "options" property group. | |
384 */ | |
385 for (hndl = libscf_handle_create_bound(SCF_VERSION); hndl == NULL; | |
386 hndl = libscf_handle_create_bound(SCF_VERSION), bind_fails++) { | |
387 (void) sleep(INITIAL_REBIND_DELAY); | |
388 | |
389 if (bind_fails > INITIAL_REBIND_ATTEMPTS) { | |
390 /* | |
391 * In the case that we can't bind to the repository | |
392 * (which should have been started), we need to allow | |
393 * the user into maintenance mode to determine what's | |
394 * failed. | |
395 */ | |
396 log_framework(LOG_INFO, "Couldn't fetch " | |
397 "default settings: %s\n", | |
398 scf_strerror(scf_error())); | |
399 | |
400 ret = -1; | |
401 | |
402 goto noscfout; | |
403 } | |
404 } | |
405 | |
406 idata.i_fmri = SCF_SERVICE_STARTD; | |
407 idata.i_state = RESTARTER_STATE_NONE; | |
408 idata.i_next_state = RESTARTER_STATE_NONE; | |
409 timestamp: | |
410 switch (r = _restarter_commit_states(hndl, &idata, | |
12979
ab9ae749152f
PSARC/2009/617 Software Events Notification Parameters CLI
Gavin Maltby <gavin.maltby@oracle.com>
parents:
11996
diff
changeset
|
411 RESTARTER_STATE_ONLINE, RESTARTER_STATE_NONE, |
ab9ae749152f
PSARC/2009/617 Software Events Notification Parameters CLI
Gavin Maltby <gavin.maltby@oracle.com>
parents:
11996
diff
changeset
|
412 restarter_get_str_short(restarter_str_insert_in_graph))) { |
0 | 413 case 0: |
414 break; | |
415 | |
416 case ENOMEM: | |
417 ++count; | |
418 if (count < ALLOC_RETRY) { | |
419 (void) poll(NULL, 0, msecs); | |
420 msecs *= ALLOC_DELAY_MULT; | |
421 goto timestamp; | |
422 } | |
423 | |
424 uu_die("Insufficient memory.\n"); | |
425 /* NOTREACHED */ | |
426 | |
427 case ECONNABORTED: | |
428 libscf_handle_rebind(hndl); | |
429 goto timestamp; | |
430 | |
431 case ENOENT: | |
432 case EPERM: | |
433 case EACCES: | |
434 case EROFS: | |
435 log_error(LOG_INFO, "Could set state of %s: %s.\n", | |
436 idata.i_fmri, strerror(r)); | |
437 break; | |
438 | |
439 case EINVAL: | |
440 default: | |
441 bad_error("_restarter_commit_states", r); | |
442 } | |
443 | |
444 pg = safe_scf_pg_create(hndl); | |
445 prop = safe_scf_property_create(hndl); | |
446 val = safe_scf_value_create(hndl); | |
447 inst = safe_scf_instance_create(hndl); | |
448 | |
449 /* set startd's restarter properties */ | |
450 if (scf_handle_decode_fmri(hndl, SCF_SERVICE_STARTD, NULL, NULL, inst, | |
451 NULL, NULL, SCF_DECODE_FMRI_EXACT) == 0) { | |
452 (void) libscf_write_start_pid(inst, getpid()); | |
453 ctid = proc_get_ctid(); | |
454 if (ctid != -1) { | |
455 uint64 = (uint64_t)ctid; | |
456 (void) libscf_inst_set_count_prop(inst, | |
457 SCF_PG_RESTARTER, SCF_PG_RESTARTER_TYPE, | |
458 SCF_PG_RESTARTER_FLAGS, SCF_PROPERTY_CONTRACT, | |
459 uint64); | |
460 } | |
461 (void) libscf_note_method_log(inst, LOG_PREFIX_EARLY, | |
462 STARTD_DEFAULT_LOG); | |
463 (void) libscf_note_method_log(inst, LOG_PREFIX_NORMAL, | |
464 STARTD_DEFAULT_LOG); | |
465 } | |
466 | |
467 /* Read reconfigure property for recovery. */ | |
468 if (scf_handle_decode_fmri(hndl, startd_reconfigure_fmri, NULL, NULL, | |
469 NULL, NULL, prop, NULL) != -1 && | |
470 scf_property_get_value(prop, val) == 0) | |
471 (void) scf_value_get_boolean(val, &prop_reconfig); | |
472 | |
473 if (scf_handle_decode_fmri(hndl, startd_options_fmri, NULL, NULL, NULL, | |
474 pg, NULL, SCF_DECODE_FMRI_TRUNCATE) == -1) { | |
475 /* | |
476 * No configuration options defined. | |
477 */ | |
478 if (scf_error() != SCF_ERROR_NOT_FOUND) | |
479 uu_warn("Couldn't read configuration from 'options' " | |
480 "group: %s\n", scf_strerror(scf_error())); | |
481 goto scfout; | |
482 } | |
483 | |
484 /* | |
485 * If there is no "options" group defined, then our defaults are fine. | |
486 */ | |
487 if (scf_pg_get_name(pg, NULL, 0) < 0) | |
488 goto scfout; | |
489 | |
12979
ab9ae749152f
PSARC/2009/617 Software Events Notification Parameters CLI
Gavin Maltby <gavin.maltby@oracle.com>
parents:
11996
diff
changeset
|
490 /* get info_events_all */ |
ab9ae749152f
PSARC/2009/617 Software Events Notification Parameters CLI
Gavin Maltby <gavin.maltby@oracle.com>
parents:
11996
diff
changeset
|
491 info_events_all = libscf_get_info_events_all(pg); |
ab9ae749152f
PSARC/2009/617 Software Events Notification Parameters CLI
Gavin Maltby <gavin.maltby@oracle.com>
parents:
11996
diff
changeset
|
492 |
0 | 493 /* Iterate through. */ |
494 iter = safe_scf_iter_create(hndl); | |
495 | |
496 (void) scf_iter_pg_properties(iter, pg); | |
497 | |
498 piter = safe_scf_iter_create(hndl); | |
499 vbuf = startd_alloc(max_scf_value_size); | |
500 | |
501 while ((scf_iter_next_property(iter, prop) == 1)) { | |
502 scf_type_t ty; | |
503 | |
504 if (scf_property_get_name(prop, buf, max_scf_fmri_size) < 0) | |
505 continue; | |
506 | |
507 if (strcmp(buf, "logging") != 0 && | |
508 strcmp(buf, "boot_messages") != 0) | |
509 continue; | |
510 | |
511 if (scf_property_type(prop, &ty) != 0) { | |
512 switch (scf_error()) { | |
513 case SCF_ERROR_CONNECTION_BROKEN: | |
514 default: | |
515 libscf_handle_rebind(hndl); | |
516 continue; | |
517 | |
518 case SCF_ERROR_DELETED: | |
519 continue; | |
520 | |
521 case SCF_ERROR_NOT_BOUND: | |
522 case SCF_ERROR_NOT_SET: | |
523 bad_error("scf_property_type", scf_error()); | |
524 } | |
525 } | |
526 | |
527 if (ty != SCF_TYPE_ASTRING) { | |
528 uu_warn("property \"options/%s\" is not of type " | |
529 "astring; ignored.\n", buf); | |
530 continue; | |
531 } | |
532 | |
533 if (scf_property_get_value(prop, val) != 0) { | |
534 switch (scf_error()) { | |
535 case SCF_ERROR_CONNECTION_BROKEN: | |
536 default: | |
537 return (ECONNABORTED); | |
538 | |
539 case SCF_ERROR_DELETED: | |
540 case SCF_ERROR_NOT_FOUND: | |
541 return (0); | |
542 | |
543 case SCF_ERROR_CONSTRAINT_VIOLATED: | |
544 uu_warn("property \"options/%s\" has multiple " | |
545 "values; ignored.\n", buf); | |
546 continue; | |
547 | |
5040
ff6ebd8761a6
PSARC 2007/177 SMF read-protected property storage
wesolows
parents:
2258
diff
changeset
|
548 case SCF_ERROR_PERMISSION_DENIED: |
ff6ebd8761a6
PSARC 2007/177 SMF read-protected property storage
wesolows
parents:
2258
diff
changeset
|
549 uu_warn("property \"options/%s\" cannot be " |
ff6ebd8761a6
PSARC 2007/177 SMF read-protected property storage
wesolows
parents:
2258
diff
changeset
|
550 "read because startd has insufficient " |
ff6ebd8761a6
PSARC 2007/177 SMF read-protected property storage
wesolows
parents:
2258
diff
changeset
|
551 "permission; ignored.\n", buf); |
ff6ebd8761a6
PSARC 2007/177 SMF read-protected property storage
wesolows
parents:
2258
diff
changeset
|
552 continue; |
ff6ebd8761a6
PSARC 2007/177 SMF read-protected property storage
wesolows
parents:
2258
diff
changeset
|
553 |
0 | 554 case SCF_ERROR_HANDLE_MISMATCH: |
555 case SCF_ERROR_NOT_BOUND: | |
556 case SCF_ERROR_NOT_SET: | |
557 bad_error("scf_property_get_value", | |
558 scf_error()); | |
559 } | |
560 } | |
561 | |
562 if (scf_value_get_astring(val, vbuf, max_scf_value_size) < 0) | |
563 bad_error("scf_value_get_astring", scf_error()); | |
564 | |
1958 | 565 if (strcmp("logging", buf) == 0) { |
0 | 566 if (strcmp("verbose", vbuf) == 0) { |
567 st->st_boot_flags = STARTD_BOOT_VERBOSE; | |
568 st->st_log_level_min = LOG_INFO; | |
569 } else if (strcmp("debug", vbuf) == 0) { | |
570 st->st_boot_flags = STARTD_BOOT_VERBOSE; | |
571 st->st_log_level_min = LOG_DEBUG; | |
572 } else if (strcmp("quiet", vbuf) == 0) { | |
573 st->st_log_level_min = LOG_NOTICE; | |
574 } else { | |
575 uu_warn("unknown options/logging " | |
576 "value '%s' ignored\n", vbuf); | |
577 } | |
578 | |
579 } else if (strcmp("boot_messages", buf) == 0) { | |
580 if (strcmp("quiet", vbuf) == 0) { | |
581 st->st_boot_flags = STARTD_BOOT_QUIET; | |
582 } else if (strcmp("verbose", vbuf) == 0) { | |
583 st->st_boot_flags = STARTD_BOOT_VERBOSE; | |
584 } else { | |
585 log_framework(LOG_NOTICE, "unknown " | |
586 "options/boot_messages value '%s' " | |
587 "ignored\n", vbuf); | |
588 } | |
589 | |
590 } | |
591 } | |
592 | |
593 startd_free(vbuf, max_scf_value_size); | |
594 scf_iter_destroy(piter); | |
595 | |
596 scf_iter_destroy(iter); | |
597 | |
598 scfout: | |
599 scf_value_destroy(val); | |
600 scf_pg_destroy(pg); | |
601 scf_property_destroy(prop); | |
602 scf_instance_destroy(inst); | |
603 (void) scf_handle_unbind(hndl); | |
604 scf_handle_destroy(hndl); | |
605 | |
606 noscfout: | |
607 startd_free(buf, max_scf_fmri_size); | |
608 uu_free(startd_options_fmri); | |
609 uu_free(startd_reconfigure_fmri); | |
610 | |
611 if (booting_to_single_user) { | |
612 st->st_subgraph = startd_alloc(max_scf_fmri_size); | |
613 sz = strlcpy(st->st_subgraph, "milestone/single-user:default", | |
614 max_scf_fmri_size); | |
615 assert(sz < max_scf_fmri_size); | |
616 } | |
617 | |
618 /* | |
619 * Options passed in as boot arguments override repository defaults. | |
620 */ | |
621 env_opts = getenv("SMF_OPTIONS"); | |
622 if (env_opts == NULL) | |
623 return (ret); | |
624 | |
195
1bf388d71529
6298507 kernel options -s and -m milestone don't play nice
dstaff
parents:
0
diff
changeset
|
625 for (cp = strtok_r(env_opts, ",", &lasts); cp != NULL; |
1bf388d71529
6298507 kernel options -s and -m milestone don't play nice
dstaff
parents:
0
diff
changeset
|
626 cp = strtok_r(NULL, ",", &lasts)) { |
0 | 627 if (strcmp(cp, "debug") == 0) { |
628 st->st_boot_flags = STARTD_BOOT_VERBOSE; | |
629 st->st_log_level_min = LOG_DEBUG; | |
1958 | 630 |
631 /* -m debug should send messages to console */ | |
632 st->st_log_flags = | |
633 st->st_log_flags | STARTD_LOG_TERMINAL; | |
0 | 634 } else if (strcmp(cp, "verbose") == 0) { |
635 st->st_boot_flags = STARTD_BOOT_VERBOSE; | |
636 st->st_log_level_min = LOG_INFO; | |
637 } else if (strcmp(cp, "seed") == 0) { | |
638 uu_warn("SMF option \"%s\" unimplemented.\n", cp); | |
639 } else if (strcmp(cp, "quiet") == 0) { | |
640 st->st_log_level_min = LOG_NOTICE; | |
641 } else if (strncmp(cp, "milestone=", | |
642 sizeof ("milestone=") - 1) == 0) { | |
643 char *mp = cp + sizeof ("milestone=") - 1; | |
644 | |
645 if (booting_to_single_user) | |
646 continue; | |
647 | |
648 if (st->st_subgraph == NULL) { | |
649 st->st_subgraph = | |
650 startd_alloc(max_scf_fmri_size); | |
651 st->st_subgraph[0] = '\0'; | |
652 } | |
653 | |
654 if (mp[0] == '\0' || strcmp(mp, "all") == 0) { | |
655 (void) strcpy(st->st_subgraph, "all"); | |
656 } else if (strcmp(mp, "su") == 0 || | |
657 strcmp(mp, "single-user") == 0) { | |
658 (void) strcpy(st->st_subgraph, | |
659 "milestone/single-user:default"); | |
660 } else if (strcmp(mp, "mu") == 0 || | |
661 strcmp(mp, "multi-user") == 0) { | |
662 (void) strcpy(st->st_subgraph, | |
663 "milestone/multi-user:default"); | |
664 } else if (strcmp(mp, "mus") == 0 || | |
665 strcmp(mp, "multi-user-server") == 0) { | |
666 (void) strcpy(st->st_subgraph, | |
667 "milestone/multi-user-server:default"); | |
668 } else if (strcmp(mp, "none") == 0) { | |
669 (void) strcpy(st->st_subgraph, "none"); | |
670 } else { | |
671 log_framework(LOG_NOTICE, | |
672 "invalid milestone option value " | |
673 "'%s' ignored\n", mp); | |
674 } | |
675 } else { | |
676 uu_warn("Unknown SMF option \"%s\".\n", cp); | |
677 } | |
678 } | |
679 | |
680 return (ret); | |
681 } | |
682 | |
683 /* | |
684 * void set_boot_env() | |
685 * | |
686 * If -r was passed or /reconfigure exists, this is a reconfig | |
687 * reboot. We need to make sure that this information is given | |
688 * to the appropriate services the first time they're started | |
689 * by setting the system/reconfigure repository property, | |
690 * as well as pass the _INIT_RECONFIG variable on to the rcS | |
691 * start method so that legacy services can continue to use it. | |
692 * | |
693 * This function must never be called before contract_init(), as | |
694 * it sets st_initial. get_startd_config() sets prop_reconfig from | |
695 * pre-existing repository state. | |
696 */ | |
697 static void | |
698 set_boot_env() | |
699 { | |
700 struct stat sb; | |
701 int r; | |
702 | |
703 /* | |
704 * Check if property still is set -- indicates we didn't get | |
705 * far enough previously to unset it. Otherwise, if this isn't | |
706 * the first startup, don't re-process /reconfigure or the | |
707 * boot flag. | |
708 */ | |
709 if (prop_reconfig != 1 && st->st_initial != 1) | |
710 return; | |
711 | |
712 /* If /reconfigure exists, also set opt_reconfig. */ | |
713 if (stat("/reconfigure", &sb) != -1) | |
714 opt_reconfig = 1; | |
715 | |
716 /* Nothing to do. Just return. */ | |
717 if (opt_reconfig == 0 && prop_reconfig == 0) | |
718 return; | |
719 | |
720 /* | |
721 * Set startd's reconfigure property. This property is | |
722 * then cleared by successful completion of the single-user | |
723 * milestone. | |
724 */ | |
725 if (prop_reconfig != 1) { | |
726 r = libscf_set_reconfig(1); | |
727 switch (r) { | |
728 case 0: | |
729 break; | |
730 | |
731 case ENOENT: | |
732 case EPERM: | |
733 case EACCES: | |
734 case EROFS: | |
735 log_error(LOG_WARNING, "Could not set reconfiguration " | |
736 "property: %s\n", strerror(r)); | |
737 break; | |
738 | |
739 default: | |
740 bad_error("libscf_set_reconfig", r); | |
741 } | |
742 } | |
743 } | |
744 | |
745 static void | |
1958 | 746 startup(void) |
0 | 747 { |
748 ctid_t configd_ctid; | |
749 int err; | |
750 | |
751 /* | |
752 * Initialize data structures. | |
753 */ | |
754 gu = startd_zalloc(sizeof (graph_update_t)); | |
755 ru = startd_zalloc(sizeof (restarter_update_t)); | |
756 | |
757 (void) pthread_cond_init(&st->st_load_cv, NULL); | |
758 (void) pthread_cond_init(&st->st_configd_live_cv, NULL); | |
759 (void) pthread_cond_init(&gu->gu_cv, NULL); | |
760 (void) pthread_cond_init(&gu->gu_freeze_cv, NULL); | |
761 (void) pthread_cond_init(&ru->restarter_update_cv, NULL); | |
762 (void) pthread_mutex_init(&st->st_load_lock, &mutex_attrs); | |
763 (void) pthread_mutex_init(&st->st_configd_live_lock, &mutex_attrs); | |
764 (void) pthread_mutex_init(&gu->gu_lock, &mutex_attrs); | |
765 (void) pthread_mutex_init(&gu->gu_freeze_lock, &mutex_attrs); | |
766 (void) pthread_mutex_init(&ru->restarter_update_lock, &mutex_attrs); | |
767 | |
768 configd_ctid = contract_init(); | |
769 | |
770 if (configd_ctid != -1) | |
771 log_framework(LOG_DEBUG, "Existing configd contract %ld; not " | |
772 "starting svc.configd\n", configd_ctid); | |
773 | |
14129
790945ad7848
3986 svc.startd dies in getutxent_frec()
Bryan Cantrill <bryan@joyent.com>
parents:
13719
diff
changeset
|
774 /* |
790945ad7848
3986 svc.startd dies in getutxent_frec()
Bryan Cantrill <bryan@joyent.com>
parents:
13719
diff
changeset
|
775 * Call utmpx_init() before creating the fork_configd() thread. |
790945ad7848
3986 svc.startd dies in getutxent_frec()
Bryan Cantrill <bryan@joyent.com>
parents:
13719
diff
changeset
|
776 */ |
790945ad7848
3986 svc.startd dies in getutxent_frec()
Bryan Cantrill <bryan@joyent.com>
parents:
13719
diff
changeset
|
777 utmpx_init(); |
790945ad7848
3986 svc.startd dies in getutxent_frec()
Bryan Cantrill <bryan@joyent.com>
parents:
13719
diff
changeset
|
778 |
0 | 779 (void) startd_thread_create(fork_configd_thread, (void *)configd_ctid); |
780 | |
781 /* | |
782 * Await, if necessary, configd's initial arrival. | |
783 */ | |
784 MUTEX_LOCK(&st->st_configd_live_lock); | |
785 while (!st->st_configd_lives) { | |
786 log_framework(LOG_DEBUG, "Awaiting cv signal on " | |
787 "configd_live_cv\n"); | |
788 err = pthread_cond_wait(&st->st_configd_live_cv, | |
789 &st->st_configd_live_lock); | |
790 assert(err == 0); | |
791 } | |
792 MUTEX_UNLOCK(&st->st_configd_live_lock); | |
793 | |
794 wait_init(); | |
795 | |
1958 | 796 if (read_startd_config()) |
0 | 797 log_framework(LOG_INFO, "svc.configd unable to provide startd " |
798 "optional settings\n"); | |
799 | |
800 log_init(); | |
801 dict_init(); | |
802 timeout_init(); | |
803 restarter_protocol_init(); | |
804 restarter_init(); | |
11996
91b62f7b8186
PSARC 2010/013 SMF Early Manifest Import
Tom Whitten <Thomas.Whitten@Sun.COM>
parents:
5777
diff
changeset
|
805 |
91b62f7b8186
PSARC 2010/013 SMF Early Manifest Import
Tom Whitten <Thomas.Whitten@Sun.COM>
parents:
5777
diff
changeset
|
806 /* |
91b62f7b8186
PSARC 2010/013 SMF Early Manifest Import
Tom Whitten <Thomas.Whitten@Sun.COM>
parents:
5777
diff
changeset
|
807 * svc.configd is started by fork_configd_thread so repository access is |
91b62f7b8186
PSARC 2010/013 SMF Early Manifest Import
Tom Whitten <Thomas.Whitten@Sun.COM>
parents:
5777
diff
changeset
|
808 * available, run early manifest import before continuing with starting |
91b62f7b8186
PSARC 2010/013 SMF Early Manifest Import
Tom Whitten <Thomas.Whitten@Sun.COM>
parents:
5777
diff
changeset
|
809 * graph engine and the rest of startd. |
91b62f7b8186
PSARC 2010/013 SMF Early Manifest Import
Tom Whitten <Thomas.Whitten@Sun.COM>
parents:
5777
diff
changeset
|
810 */ |
91b62f7b8186
PSARC 2010/013 SMF Early Manifest Import
Tom Whitten <Thomas.Whitten@Sun.COM>
parents:
5777
diff
changeset
|
811 log_framework(LOG_DEBUG, "Calling fork_emi...\n"); |
91b62f7b8186
PSARC 2010/013 SMF Early Manifest Import
Tom Whitten <Thomas.Whitten@Sun.COM>
parents:
5777
diff
changeset
|
812 fork_emi(); |
91b62f7b8186
PSARC 2010/013 SMF Early Manifest Import
Tom Whitten <Thomas.Whitten@Sun.COM>
parents:
5777
diff
changeset
|
813 |
0 | 814 graph_protocol_init(); |
815 graph_init(); | |
816 | |
817 init_env(); | |
818 | |
819 set_boot_env(); | |
820 restarter_start(); | |
821 graph_engine_start(); | |
822 } | |
823 | |
824 static void | |
825 usage(const char *name) | |
826 { | |
2258
fb20891389ee
6440415 *svc.startd* traces of obsolete flags should be removed from source code
rm88369
parents:
1958
diff
changeset
|
827 uu_warn(gettext("usage: %s [-n]\n"), name); |
0 | 828 exit(UU_EXIT_USAGE); |
829 } | |
830 | |
831 static int | |
832 daemonize_start(void) | |
833 { | |
834 pid_t pid; | |
835 int fd; | |
836 | |
837 if ((pid = fork1()) < 0) | |
838 return (-1); | |
839 | |
840 if (pid != 0) | |
841 exit(0); | |
842 | |
5617
2ad824648def
6613845 setlog(), daemonize_start() should use STD{ERR,OUT}_FILENO constants
acruz
parents:
5496
diff
changeset
|
843 (void) close(STDIN_FILENO); |
0 | 844 |
845 if ((fd = open("/dev/null", O_RDONLY)) == -1) { | |
846 uu_warn(gettext("can't connect stdin to /dev/null")); | |
5617
2ad824648def
6613845 setlog(), daemonize_start() should use STD{ERR,OUT}_FILENO constants
acruz
parents:
5496
diff
changeset
|
847 } else if (fd != STDIN_FILENO) { |
2ad824648def
6613845 setlog(), daemonize_start() should use STD{ERR,OUT}_FILENO constants
acruz
parents:
5496
diff
changeset
|
848 (void) dup2(fd, STDIN_FILENO); |
0 | 849 startd_close(fd); |
850 } | |
851 | |
852 closefrom(3); | |
5617
2ad824648def
6613845 setlog(), daemonize_start() should use STD{ERR,OUT}_FILENO constants
acruz
parents:
5496
diff
changeset
|
853 (void) dup2(STDERR_FILENO, STDOUT_FILENO); |
0 | 854 |
855 (void) setsid(); | |
856 (void) chdir("/"); | |
857 | |
858 /* Use default umask that init handed us, but 022 to create files. */ | |
859 dmask = umask(022); | |
860 fmask = umask(dmask); | |
861 | |
862 return (0); | |
863 } | |
864 | |
865 /*ARGSUSED*/ | |
866 static void | |
867 die_handler(int sig, siginfo_t *info, void *data) | |
868 { | |
869 finished = 1; | |
870 } | |
871 | |
872 int | |
873 main(int argc, char *argv[]) | |
874 { | |
875 int opt; | |
876 int daemonize = 1; | |
877 struct sigaction act; | |
878 sigset_t nullset; | |
879 struct stat sb; | |
880 | |
881 (void) uu_setpname(argv[0]); | |
882 | |
883 st = startd_zalloc(sizeof (startd_state_t)); | |
884 | |
885 (void) pthread_mutexattr_init(&mutex_attrs); | |
886 #ifndef NDEBUG | |
887 (void) pthread_mutexattr_settype(&mutex_attrs, | |
888 PTHREAD_MUTEX_ERRORCHECK); | |
889 #endif | |
890 | |
891 max_scf_name_size = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH); | |
892 max_scf_value_size = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); | |
893 max_scf_fmri_size = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH); | |
894 | |
895 if (max_scf_name_size == -1 || max_scf_value_size == -1 || | |
896 max_scf_value_size == -1) | |
897 uu_die("Can't determine repository maximum lengths.\n"); | |
898 | |
899 max_scf_name_size++; | |
900 max_scf_value_size++; | |
901 max_scf_fmri_size++; | |
902 | |
1958 | 903 st->st_log_flags = STARTD_LOG_FILE | STARTD_LOG_SYSLOG; |
904 st->st_log_level_min = LOG_NOTICE; | |
0 | 905 |
1958 | 906 while ((opt = getopt(argc, argv, "nrs")) != EOF) { |
0 | 907 switch (opt) { |
908 case 'n': | |
909 daemonize = 0; | |
910 break; | |
911 case 'r': /* reconfiguration boot */ | |
912 opt_reconfig = 1; | |
913 break; | |
914 case 's': /* single-user mode */ | |
915 booting_to_single_user = B_TRUE; | |
916 break; | |
917 default: | |
918 usage(argv[0]); /* exits */ | |
919 } | |
920 } | |
921 | |
922 if (optind != argc) | |
923 usage(argv[0]); | |
924 | |
1914
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
195
diff
changeset
|
925 (void) enable_extended_FILE_stdio(-1, -1); |
8a8c5f225b1b
4916205 libcmd should not use file operation routines from C library
casper
parents:
195
diff
changeset
|
926 |
0 | 927 if (daemonize) |
928 if (daemonize_start() < 0) | |
929 uu_die("Can't daemonize\n"); | |
930 | |
931 log_init(); | |
932 | |
933 if (stat("/etc/svc/volatile/resetting", &sb) != -1) { | |
934 log_framework(LOG_NOTICE, "Restarter quiesced.\n"); | |
935 | |
936 for (;;) | |
937 (void) pause(); | |
938 } | |
939 | |
940 act.sa_sigaction = &die_handler; | |
941 (void) sigfillset(&act.sa_mask); | |
942 act.sa_flags = SA_SIGINFO; | |
943 (void) sigaction(SIGINT, &act, NULL); | |
944 (void) sigaction(SIGTERM, &act, NULL); | |
945 | |
1958 | 946 startup(); |
0 | 947 |
948 (void) sigemptyset(&nullset); | |
949 while (!finished) { | |
950 log_framework(LOG_DEBUG, "Main thread paused\n"); | |
951 (void) sigsuspend(&nullset); | |
952 } | |
953 | |
954 (void) log_framework(LOG_DEBUG, "Restarter exiting.\n"); | |
955 return (0); | |
956 } |