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 * Copyright (c) 2012, Joyent, Inc. All rights reserved.
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.
57 *
58 * External references
59 *
60 * svc.configd generates special security audit events for changes to some
61 * restarter related properties. See the special_props_list array in
62 * usr/src/cmd/svc/configd/rc_node.c for the properties that cause these audit
63 * events. If you change the semantics of these propereties within startd, you
64 * will probably need to update rc_node.c
65 */
66
67 #include <stdio.h>
68 #include <stdio_ext.h>
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
147 #ifdef DEBUG
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 }
159 #endif
160
161 const char *
162 _umem_options_init(void)
163 {
164 /*
165 * To reduce our memory footprint, we set our UMEM_OPTIONS to indicate
166 * that we do not wish to have per-CPU magazines -- if svc.startd is so
167 * hot on CPU such that this becomes a scalability problem, there are
168 * likely deeper things amiss...
169 */
170 return ("nomagazines"); /* UMEM_OPTIONS setting */
171 }
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
342 extern int info_events_all;
343
344 static int
345 read_startd_config(void)
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,
411 RESTARTER_STATE_ONLINE, RESTARTER_STATE_NONE,
412 restarter_get_str_short(restarter_str_insert_in_graph))) {
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
490 /* get info_events_all */
491 info_events_all = libscf_get_info_events_all(pg);
492
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
548 case SCF_ERROR_PERMISSION_DENIED:
549 uu_warn("property \"options/%s\" cannot be "
550 "read because startd has insufficient "
551 "permission; ignored.\n", buf);
552 continue;
553
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
565 if (strcmp("logging", buf) == 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
625 for (cp = strtok_r(env_opts, ",", &lasts); cp != NULL;
626 cp = strtok_r(NULL, ",", &lasts)) {
627 if (strcmp(cp, "debug") == 0) {
628 st->st_boot_flags = STARTD_BOOT_VERBOSE;
629 st->st_log_level_min = LOG_DEBUG;
630
631 /* -m debug should send messages to console */
632 st->st_log_flags =
633 st->st_log_flags | STARTD_LOG_TERMINAL;
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
746 startup(void)
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
774 (void) startd_thread_create(fork_configd_thread, (void *)configd_ctid);
775
776 /*
777 * Await, if necessary, configd's initial arrival.
778 */
779 MUTEX_LOCK(&st->st_configd_live_lock);
780 while (!st->st_configd_lives) {
781 log_framework(LOG_DEBUG, "Awaiting cv signal on "
782 "configd_live_cv\n");
783 err = pthread_cond_wait(&st->st_configd_live_cv,
784 &st->st_configd_live_lock);
785 assert(err == 0);
786 }
787 MUTEX_UNLOCK(&st->st_configd_live_lock);
788
789 utmpx_init();
790 wait_init();
791
792 if (read_startd_config())
793 log_framework(LOG_INFO, "svc.configd unable to provide startd "
794 "optional settings\n");
795
796 log_init();
797 dict_init();
798 timeout_init();
799 restarter_protocol_init();
800 restarter_init();
801
802 /*
803 * svc.configd is started by fork_configd_thread so repository access is
804 * available, run early manifest import before continuing with starting
805 * graph engine and the rest of startd.
806 */
807 log_framework(LOG_DEBUG, "Calling fork_emi...\n");
808 fork_emi();
809
810 graph_protocol_init();
811 graph_init();
812
813 init_env();
814
815 set_boot_env();
816 restarter_start();
817 graph_engine_start();
818 }
819
820 static void
821 usage(const char *name)
822 {
823 uu_warn(gettext("usage: %s [-n]\n"), name);
824 exit(UU_EXIT_USAGE);
825 }
826
827 static int
828 daemonize_start(void)
829 {
830 pid_t pid;
831 int fd;
832
833 if ((pid = fork1()) < 0)
834 return (-1);
835
836 if (pid != 0)
837 exit(0);
838
839 (void) close(STDIN_FILENO);
840
841 if ((fd = open("/dev/null", O_RDONLY)) == -1) {
842 uu_warn(gettext("can't connect stdin to /dev/null"));
843 } else if (fd != STDIN_FILENO) {
844 (void) dup2(fd, STDIN_FILENO);
845 startd_close(fd);
846 }
847
848 closefrom(3);
849 (void) dup2(STDERR_FILENO, STDOUT_FILENO);
850
851 (void) setsid();
852 (void) chdir("/");
853
854 /* Use default umask that init handed us, but 022 to create files. */
855 dmask = umask(022);
856 fmask = umask(dmask);
857
858 return (0);
859 }
860
861 /*ARGSUSED*/
862 static void
863 die_handler(int sig, siginfo_t *info, void *data)
864 {
865 finished = 1;
866 }
867
868 int
869 main(int argc, char *argv[])
870 {
871 int opt;
872 int daemonize = 1;
873 struct sigaction act;
874 sigset_t nullset;
875 struct stat sb;
876
877 (void) uu_setpname(argv[0]);
878
879 st = startd_zalloc(sizeof (startd_state_t));
880
881 (void) pthread_mutexattr_init(&mutex_attrs);
882 #ifndef NDEBUG
883 (void) pthread_mutexattr_settype(&mutex_attrs,
884 PTHREAD_MUTEX_ERRORCHECK);
885 #endif
886
887 max_scf_name_size = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
888 max_scf_value_size = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
889 max_scf_fmri_size = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
890
891 if (max_scf_name_size == -1 || max_scf_value_size == -1 ||
892 max_scf_value_size == -1)
893 uu_die("Can't determine repository maximum lengths.\n");
894
895 max_scf_name_size++;
896 max_scf_value_size++;
897 max_scf_fmri_size++;
898
899 st->st_log_flags = STARTD_LOG_FILE | STARTD_LOG_SYSLOG;
900 st->st_log_level_min = LOG_NOTICE;
901
902 while ((opt = getopt(argc, argv, "nrs")) != EOF) {
903 switch (opt) {
904 case 'n':
905 daemonize = 0;
906 break;
907 case 'r': /* reconfiguration boot */
908 opt_reconfig = 1;
909 break;
910 case 's': /* single-user mode */
911 booting_to_single_user = B_TRUE;
912 break;
913 default:
914 usage(argv[0]); /* exits */
915 }
916 }
917
918 if (optind != argc)
919 usage(argv[0]);
920
921 (void) enable_extended_FILE_stdio(-1, -1);
922
923 if (daemonize)
924 if (daemonize_start() < 0)
925 uu_die("Can't daemonize\n");
926
927 log_init();
928
929 if (stat("/etc/svc/volatile/resetting", &sb) != -1) {
930 log_framework(LOG_NOTICE, "Restarter quiesced.\n");
931
932 for (;;)
933 (void) pause();
934 }
935
936 act.sa_sigaction = &die_handler;
937 (void) sigfillset(&act.sa_mask);
938 act.sa_flags = SA_SIGINFO;
939 (void) sigaction(SIGINT, &act, NULL);
940 (void) sigaction(SIGTERM, &act, NULL);
941
942 startup();
943
944 (void) sigemptyset(&nullset);
945 while (!finished) {
946 log_framework(LOG_DEBUG, "Main thread paused\n");
947 (void) sigsuspend(&nullset);
948 }
949
950 (void) log_framework(LOG_DEBUG, "Restarter exiting.\n");
951 return (0);
952 }