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