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