Print this page
7711 SMF: Finish implementing support for degraded state
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/svc/startd/startd.c
+++ new/usr/src/cmd/svc/startd/startd.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 * Copyright 2015, Joyent, Inc.
25 + * Copyright 2017 RackTop Systems.
25 26 */
26 27
27 28 /*
28 29 * startd.c - the master restarter
29 30 *
30 31 * svc.startd comprises two halves. The graph engine is based in graph.c and
31 32 * maintains the service dependency graph based on the information in the
32 33 * repository. For each service it also tracks the current state and the
33 34 * restarter responsible for the service. Based on the graph, events from the
34 35 * repository (mostly administrative requests from svcadm), and messages from
35 36 * the restarters, the graph engine makes decisions about how the services
36 37 * should be manipulated and sends commands to the appropriate restarters.
37 38 * Communication between the graph engine and the restarters is embodied in
38 39 * protocol.c.
39 40 *
40 41 * The second half of svc.startd is the restarter for services managed by
41 42 * svc.startd and is primarily contained in restarter.c. It responds to graph
42 43 * engine commands by executing methods, updating the repository, and sending
43 44 * feedback (mostly state updates) to the graph engine.
44 45 *
45 46 * Overview of the SMF Architecture
46 47 *
47 48 * There are a few different components that make up SMF and are responsible
48 49 * for different pieces of functionality that are used:
49 50 *
50 51 * svc.startd(1M): A daemon that is in charge of starting, stopping, and
51 52 * restarting services and instances.
52 53 * svc.configd(1M): A daemon that manages the repository that stores
53 54 * information, property groups, and state of the different services and
54 55 * instances.
55 56 * libscf(3LIB): A C library that provides the glue for communicating,
56 57 * accessing, and updating information about services and instances.
57 58 * svccfg(1M): A utility to add and remove services as well as change the
58 59 * properties associated with different services and instances.
59 60 * svcadm(1M): A utility to control the different instance of a service. You
60 61 * can use this to enable and disable them among some other useful things.
61 62 * svcs(1): A utility that reports on the status of various services on the
62 63 * system.
63 64 *
64 65 * The following block diagram explains how these components communicate:
65 66 *
66 67 * The SMF Block Diagram
67 68 * Repository
68 69 * This attempts to show +---------+ +--------+
69 70 * the relations between | | SQL | |
70 71 * the different pieces | configd |<----------->| SQLite |
71 72 * that make SMF work and | | Transaction | |
72 73 * users/administrators +---------+ +--------+
73 74 * call into. ^ ^
74 75 * | |
75 76 * door_call(3C)| | door_call(3C)
76 77 * | |
77 78 * v v
78 79 * +----------+ +--------+ +--------+ +----------+
79 80 * | | | | | | | svccfg |
80 81 * | startd |<--->| libscf | | libscf |<---->| svcadm |
81 82 * | | | (3LIB) | | (3LIB) | | svcs |
82 83 * +----------+ +--------+ +--------+ +----------+
83 84 * ^ ^
84 85 * | | fork(2)/exec(2)
85 86 * | | libcontract(3LIB)
86 87 * v v Various System/User services
87 88 * +-------------------------------------------------------------------+
88 89 * | system/filesystem/local:default system/coreadm:default |
89 90 * | network/loopback:default system/zones:default |
90 91 * | milestone/multi-user:default system/cron:default |
91 92 * | system/console-login:default network/ssh:default |
92 93 * | system/pfexec:default system/svc/restarter:default |
93 94 * +-------------------------------------------------------------------+
94 95 *
95 96 * Chatting with Configd and Sharing Repository Information
96 97 *
97 98 * As you run commands with svcs, svccfg, and svcadm, they are all creating a
98 99 * libscf handle to communicate with configd. As calls are made via libscf they
99 100 * ultimately go and talk to configd to get information. However, how we
100 101 * actually are talking to configd is not as straightforward as it appears.
101 102 *
102 103 * When configd starts up it creates a door located at
103 104 * /etc/svc/volatile/repository_door. This door runs the routine called
104 105 * main_switcher() from usr/src/cmd/svc/configd/maindoor.c. When you first
105 106 * invoke svc(cfg|s|adm), one of the first things that occurs is creating a
106 107 * scf_handle_t and binding it to configd by calling scf_handle_bind(). This
107 108 * function makes a door call to configd and gets returned a new file
108 109 * descriptor. This file descriptor is itself another door which calls into
109 110 * configd's client_switcher(). This is the door that is actually used when
110 111 * getting and fetching properties, and many other useful things.
111 112 *
112 113 * svc.startd needs a way to notice the changes that occur to the repository.
113 114 * For example, if you enabled a service that was not previously running, it's
114 115 * up to startd to notice that this has happened, check dependencies, and
115 116 * eventually start up the service. The way it gets these notifications is via
116 117 * a thread who's sole purpose in life is to call _scf_notify_wait(). This
117 118 * function acts like poll(2) but for changes that occur in the repository.
118 119 * Once this thread gets the event, it dispatches the event appropriately.
119 120 *
120 121 * The Events of svc.startd
121 122 *
122 123 * svc.startd has to handle a lot of complexity. Understanding how you go from
123 124 * getting the notification that a service was enabled to actually enabling it
124 125 * is not obvious from a cursory glance. The first thing to keep in mind is
125 126 * that startd maintains a graph of all the related services and instances so
126 127 * it can keep track of what is enabled, what dependencies exist, etc. all so
127 128 * that it can answer the question of what is affected by a change. Internally
128 129 * there are a lot of different queues for events, threads to process these
129 130 * queues, and different paths to have events enter these queues. What follows
130 131 * is a diagram that attempts to explain some of those paths, though it's
131 132 * important to note that for some of these pieces, such as the graph and
132 133 * vertex events, there are many additional ways and code paths these threads
133 134 * and functions can take. And yes, restarter_event_enqueue() is not the same
134 135 * thing as restarter_queue_event().
135 136 *
136 137 * Threads/Functions Queues Threads/Functions
137 138 *
138 139 * called by various
139 140 * +----------------+ +-------+ +-------------+
140 141 * --->| graph_protocol | graph_event | graph | graph_event_ | graph_event |
141 142 * --->| _send_event() |------------>| event |----------------->| _thread |
142 143 * +----------------+ _enqueue() | queue | dequeue() +-------------+
143 144 * +-------+ |
144 145 * _scf_notify_wait() vertex_send_event()|
145 146 * | v
146 147 * | +------------------+ +--------------------+
147 148 * +->| repository_event | vertex_send_event() | restarter_protocol |
148 149 * | _thread |----------------------------->| _send_event() |
149 150 * +------------------+ +--------------------+
150 151 * | | out to other
151 152 * restarter_ restarter_ | | restarters
152 153 * event_dequeue() +-----------+ event_ | | not startd
153 154 * +----------------| restarter |<------------+ +------------->
154 155 * v | event | enqueue()
155 156 * +-----------------+ | queue | +------------------>
156 157 * | restarter_event | +-----------+ |+----------------->
157 158 * | _thread | ||+---------------->
158 159 * +-----------------+ ||| start/stop inst
159 160 * | +--------------+ +--------------------+
160 161 * | | instance | | restarter_process_ |
161 162 * +-------------->| event |------>| events |
162 163 * restarter_ | queue | | per-instance lwp |
163 164 * queue_event() +--------------+ +--------------------+
164 165 * ||| various funcs
165 166 * ||| controlling
166 167 * ||| instance state
167 168 * ||+--------------->
168 169 * |+---------------->
169 170 * +----------------->
170 171 *
171 172 * What's important to take away is that there is a queue for each instance on
172 173 * the system that handles events related to dealing directly with that
173 174 * instance and that events can be added to it because of changes to properties
174 175 * that are made to configd and acted upon asynchronously by startd.
175 176 *
176 177 * Error handling
177 178 *
178 179 * In general, when svc.startd runs out of memory it reattempts a few times,
179 180 * sleeping inbetween, before giving up and exiting (see startd_alloc_retry()).
180 181 * When a repository connection is broken (libscf calls fail with
181 182 * SCF_ERROR_CONNECTION_BROKEN, librestart and internal functions return
182 183 * ECONNABORTED), svc.startd calls libscf_rebind_handle(), which coordinates
183 184 * with the svc.configd-restarting thread, fork_configd_thread(), via
184 185 * st->st_configd_live_cv, and rebinds the repository handle. Doing so resets
185 186 * all libscf state associated with that handle, so functions which do this
186 187 * should communicate the event to their callers (usually by returning
187 188 * ECONNRESET) so they may reset their state appropriately.
188 189 *
189 190 * External references
190 191 *
191 192 * svc.configd generates special security audit events for changes to some
192 193 * restarter related properties. See the special_props_list array in
193 194 * usr/src/cmd/svc/configd/rc_node.c for the properties that cause these audit
194 195 * events. If you change the semantics of these propereties within startd, you
195 196 * will probably need to update rc_node.c
196 197 */
197 198
198 199 #include <stdio.h>
199 200 #include <stdio_ext.h>
200 201 #include <sys/mnttab.h> /* uses FILE * without including stdio.h */
201 202 #include <alloca.h>
202 203 #include <sys/mount.h>
203 204 #include <sys/stat.h>
204 205 #include <sys/types.h>
205 206 #include <sys/wait.h>
206 207 #include <assert.h>
207 208 #include <errno.h>
208 209 #include <fcntl.h>
209 210 #include <ftw.h>
210 211 #include <libintl.h>
211 212 #include <libscf.h>
212 213 #include <libscf_priv.h>
213 214 #include <libuutil.h>
214 215 #include <locale.h>
215 216 #include <poll.h>
216 217 #include <pthread.h>
217 218 #include <signal.h>
218 219 #include <stdarg.h>
219 220 #include <stdlib.h>
220 221 #include <string.h>
221 222 #include <strings.h>
222 223 #include <unistd.h>
223 224
224 225 #include "startd.h"
225 226 #include "protocol.h"
226 227
227 228 ssize_t max_scf_name_size;
228 229 ssize_t max_scf_fmri_size;
229 230 ssize_t max_scf_value_size;
230 231
231 232 mode_t fmask;
↓ open down ↓ |
197 lines elided |
↑ open up ↑ |
232 233 mode_t dmask;
233 234
234 235 graph_update_t *gu;
235 236 restarter_update_t *ru;
236 237
237 238 startd_state_t *st;
238 239
239 240 boolean_t booting_to_single_user = B_FALSE;
240 241
241 242 const char * const admin_actions[] = {
243 + SCF_PROPERTY_RESTORE,
242 244 SCF_PROPERTY_DEGRADED,
245 + SCF_PROPERTY_DEGRADE_IMMEDIATE,
243 246 SCF_PROPERTY_MAINT_OFF,
244 247 SCF_PROPERTY_MAINT_ON,
245 248 SCF_PROPERTY_MAINT_ON_IMMEDIATE,
246 249 SCF_PROPERTY_REFRESH,
247 250 SCF_PROPERTY_RESTART
248 251 };
249 252
250 253 const int admin_events[NACTIONS] = {
254 + RESTARTER_EVENT_TYPE_ADMIN_RESTORE,
251 255 RESTARTER_EVENT_TYPE_ADMIN_DEGRADED,
256 + RESTARTER_EVENT_TYPE_ADMIN_DEGRADE_IMMEDIATE,
252 257 RESTARTER_EVENT_TYPE_ADMIN_MAINT_OFF,
253 258 RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON,
254 259 RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON_IMMEDIATE,
255 260 RESTARTER_EVENT_TYPE_ADMIN_REFRESH,
256 261 RESTARTER_EVENT_TYPE_ADMIN_RESTART
257 262 };
258 263
259 264 const char * const instance_state_str[] = {
260 265 "none",
261 266 "uninitialized",
262 267 "maintenance",
263 268 "offline",
264 269 "disabled",
265 270 "online",
266 271 "degraded"
267 272 };
268 273
269 274 static int finished = 0;
270 275 static int opt_reconfig = 0;
271 276 static uint8_t prop_reconfig = 0;
272 277
273 278 #define INITIAL_REBIND_ATTEMPTS 5
274 279 #define INITIAL_REBIND_DELAY 3
275 280
276 281 pthread_mutexattr_t mutex_attrs;
277 282
278 283 #ifdef DEBUG
279 284 const char *
280 285 _umem_debug_init(void)
281 286 {
282 287 return ("default,verbose"); /* UMEM_DEBUG setting */
283 288 }
284 289
285 290 const char *
286 291 _umem_logging_init(void)
287 292 {
288 293 return ("fail,contents"); /* UMEM_LOGGING setting */
289 294 }
290 295 #endif
291 296
292 297 const char *
293 298 _umem_options_init(void)
294 299 {
295 300 /*
296 301 * To reduce our memory footprint, we set our UMEM_OPTIONS to indicate
297 302 * that we do not wish to have per-CPU magazines -- if svc.startd is so
298 303 * hot on CPU such that this becomes a scalability problem, there are
299 304 * likely deeper things amiss...
300 305 */
301 306 return ("nomagazines"); /* UMEM_OPTIONS setting */
302 307 }
303 308
304 309 /*
305 310 * startd_alloc_retry()
306 311 * Wrapper for allocation functions. Retries with a decaying time
307 312 * value on failure to allocate, and aborts startd if failure is
308 313 * persistent.
309 314 */
310 315 void *
311 316 startd_alloc_retry(void *f(size_t, int), size_t sz)
312 317 {
313 318 void *p;
314 319 uint_t try, msecs;
315 320
316 321 p = f(sz, UMEM_DEFAULT);
317 322 if (p != NULL || sz == 0)
318 323 return (p);
319 324
320 325 msecs = ALLOC_DELAY;
321 326
322 327 for (try = 0; p == NULL && try < ALLOC_RETRY; ++try) {
323 328 (void) poll(NULL, 0, msecs);
324 329 msecs *= ALLOC_DELAY_MULT;
325 330 p = f(sz, UMEM_DEFAULT);
326 331 if (p != NULL)
327 332 return (p);
328 333 }
329 334
330 335 uu_die("Insufficient memory.\n");
331 336 /* NOTREACHED */
332 337 }
333 338
334 339 void *
335 340 safe_realloc(void *p, size_t sz)
336 341 {
337 342 uint_t try, msecs;
338 343
339 344 p = realloc(p, sz);
340 345 if (p != NULL || sz == 0)
341 346 return (p);
342 347
343 348 msecs = ALLOC_DELAY;
344 349
345 350 for (try = 0; errno == EAGAIN && try < ALLOC_RETRY; ++try) {
346 351 (void) poll(NULL, 0, msecs);
347 352 p = realloc(p, sz);
348 353 if (p != NULL)
349 354 return (p);
350 355 msecs *= ALLOC_DELAY_MULT;
351 356 }
352 357
353 358 uu_die("Insufficient memory.\n");
354 359 /* NOTREACHED */
355 360 }
356 361
357 362 char *
358 363 safe_strdup(const char *s)
359 364 {
360 365 uint_t try, msecs;
361 366 char *d;
362 367
363 368 d = strdup(s);
364 369 if (d != NULL)
365 370 return (d);
366 371
367 372 msecs = ALLOC_DELAY;
368 373
369 374 for (try = 0;
370 375 (errno == EAGAIN || errno == ENOMEM) && try < ALLOC_RETRY;
371 376 ++try) {
372 377 (void) poll(NULL, 0, msecs);
373 378 d = strdup(s);
374 379 if (d != NULL)
375 380 return (d);
376 381 msecs *= ALLOC_DELAY_MULT;
377 382 }
378 383
379 384 uu_die("Insufficient memory.\n");
380 385 /* NOTREACHED */
381 386 }
382 387
383 388
384 389 void
385 390 startd_free(void *p, size_t sz)
386 391 {
387 392 umem_free(p, sz);
388 393 }
389 394
390 395 /*
391 396 * Creates a uu_list_pool_t with the same retry policy as startd_alloc().
392 397 * Only returns NULL for UU_ERROR_UNKNOWN_FLAG and UU_ERROR_NOT_SUPPORTED.
393 398 */
394 399 uu_list_pool_t *
395 400 startd_list_pool_create(const char *name, size_t e, size_t o,
396 401 uu_compare_fn_t *f, uint32_t flags)
397 402 {
398 403 uu_list_pool_t *pool;
399 404 uint_t try, msecs;
400 405
401 406 pool = uu_list_pool_create(name, e, o, f, flags);
402 407 if (pool != NULL)
403 408 return (pool);
404 409
405 410 msecs = ALLOC_DELAY;
406 411
407 412 for (try = 0; uu_error() == UU_ERROR_NO_MEMORY && try < ALLOC_RETRY;
408 413 ++try) {
409 414 (void) poll(NULL, 0, msecs);
410 415 pool = uu_list_pool_create(name, e, o, f, flags);
411 416 if (pool != NULL)
412 417 return (pool);
413 418 msecs *= ALLOC_DELAY_MULT;
414 419 }
415 420
416 421 if (try < ALLOC_RETRY)
417 422 return (NULL);
418 423
419 424 uu_die("Insufficient memory.\n");
420 425 /* NOTREACHED */
421 426 }
422 427
423 428 /*
424 429 * Creates a uu_list_t with the same retry policy as startd_alloc(). Only
425 430 * returns NULL for UU_ERROR_UNKNOWN_FLAG and UU_ERROR_NOT_SUPPORTED.
426 431 */
427 432 uu_list_t *
428 433 startd_list_create(uu_list_pool_t *pool, void *parent, uint32_t flags)
429 434 {
430 435 uu_list_t *list;
431 436 uint_t try, msecs;
432 437
433 438 list = uu_list_create(pool, parent, flags);
434 439 if (list != NULL)
435 440 return (list);
436 441
437 442 msecs = ALLOC_DELAY;
438 443
439 444 for (try = 0; uu_error() == UU_ERROR_NO_MEMORY && try < ALLOC_RETRY;
440 445 ++try) {
441 446 (void) poll(NULL, 0, msecs);
442 447 list = uu_list_create(pool, parent, flags);
443 448 if (list != NULL)
444 449 return (list);
445 450 msecs *= ALLOC_DELAY_MULT;
446 451 }
447 452
448 453 if (try < ALLOC_RETRY)
449 454 return (NULL);
450 455
451 456 uu_die("Insufficient memory.\n");
452 457 /* NOTREACHED */
453 458 }
454 459
455 460 pthread_t
456 461 startd_thread_create(void *(*func)(void *), void *ptr)
457 462 {
458 463 int err;
459 464 pthread_t tid;
460 465
461 466 err = pthread_create(&tid, NULL, func, ptr);
462 467 if (err != 0) {
463 468 assert(err == EAGAIN);
464 469 uu_die("Could not create thread.\n");
465 470 }
466 471
467 472 err = pthread_detach(tid);
468 473 assert(err == 0);
469 474
470 475 return (tid);
471 476 }
472 477
473 478 extern int info_events_all;
474 479
475 480 static int
476 481 read_startd_config(void)
477 482 {
478 483 scf_handle_t *hndl;
479 484 scf_instance_t *inst;
480 485 scf_propertygroup_t *pg;
481 486 scf_property_t *prop;
482 487 scf_value_t *val;
483 488 scf_iter_t *iter, *piter;
484 489 instance_data_t idata;
485 490 char *buf, *vbuf;
486 491 char *startd_options_fmri = uu_msprintf("%s/:properties/options",
487 492 SCF_SERVICE_STARTD);
488 493 char *startd_reconfigure_fmri = uu_msprintf(
489 494 "%s/:properties/system/reconfigure", SCF_SERVICE_STARTD);
490 495 char *env_opts, *lasts, *cp;
491 496 int bind_fails = 0;
492 497 int ret = 0, r;
493 498 uint_t count = 0, msecs = ALLOC_DELAY;
494 499 size_t sz;
495 500 ctid_t ctid;
496 501 uint64_t uint64;
497 502
498 503 buf = startd_alloc(max_scf_fmri_size);
499 504
500 505 if (startd_options_fmri == NULL || startd_reconfigure_fmri == NULL)
501 506 uu_die("Allocation failure\n");
502 507
503 508 st->st_log_prefix = LOG_PREFIX_EARLY;
504 509
505 510 if ((st->st_log_file = getenv("STARTD_DEFAULT_LOG")) == NULL) {
506 511 st->st_log_file = startd_alloc(strlen(STARTD_DEFAULT_LOG) + 1);
507 512
508 513 (void) strcpy(st->st_log_file, STARTD_DEFAULT_LOG);
509 514 }
510 515
511 516 st->st_door_path = getenv("STARTD_ALT_DOOR");
512 517
513 518 /*
514 519 * Read "options" property group.
515 520 */
516 521 for (hndl = libscf_handle_create_bound(SCF_VERSION); hndl == NULL;
517 522 hndl = libscf_handle_create_bound(SCF_VERSION), bind_fails++) {
518 523 (void) sleep(INITIAL_REBIND_DELAY);
519 524
520 525 if (bind_fails > INITIAL_REBIND_ATTEMPTS) {
521 526 /*
522 527 * In the case that we can't bind to the repository
523 528 * (which should have been started), we need to allow
524 529 * the user into maintenance mode to determine what's
525 530 * failed.
526 531 */
527 532 log_framework(LOG_INFO, "Couldn't fetch "
528 533 "default settings: %s\n",
529 534 scf_strerror(scf_error()));
530 535
531 536 ret = -1;
532 537
533 538 goto noscfout;
534 539 }
535 540 }
536 541
537 542 idata.i_fmri = SCF_SERVICE_STARTD;
538 543 idata.i_state = RESTARTER_STATE_NONE;
539 544 idata.i_next_state = RESTARTER_STATE_NONE;
540 545 timestamp:
541 546 switch (r = _restarter_commit_states(hndl, &idata,
542 547 RESTARTER_STATE_ONLINE, RESTARTER_STATE_NONE,
543 548 restarter_get_str_short(restarter_str_insert_in_graph))) {
544 549 case 0:
545 550 break;
546 551
547 552 case ENOMEM:
548 553 ++count;
549 554 if (count < ALLOC_RETRY) {
550 555 (void) poll(NULL, 0, msecs);
551 556 msecs *= ALLOC_DELAY_MULT;
552 557 goto timestamp;
553 558 }
554 559
555 560 uu_die("Insufficient memory.\n");
556 561 /* NOTREACHED */
557 562
558 563 case ECONNABORTED:
559 564 libscf_handle_rebind(hndl);
560 565 goto timestamp;
561 566
562 567 case ENOENT:
563 568 case EPERM:
564 569 case EACCES:
565 570 case EROFS:
566 571 log_error(LOG_INFO, "Could set state of %s: %s.\n",
567 572 idata.i_fmri, strerror(r));
568 573 break;
569 574
570 575 case EINVAL:
571 576 default:
572 577 bad_error("_restarter_commit_states", r);
573 578 }
574 579
575 580 pg = safe_scf_pg_create(hndl);
576 581 prop = safe_scf_property_create(hndl);
577 582 val = safe_scf_value_create(hndl);
578 583 inst = safe_scf_instance_create(hndl);
579 584
580 585 /* set startd's restarter properties */
581 586 if (scf_handle_decode_fmri(hndl, SCF_SERVICE_STARTD, NULL, NULL, inst,
582 587 NULL, NULL, SCF_DECODE_FMRI_EXACT) == 0) {
583 588 (void) libscf_write_start_pid(inst, getpid());
584 589 ctid = proc_get_ctid();
585 590 if (ctid != -1) {
586 591 uint64 = (uint64_t)ctid;
587 592 (void) libscf_inst_set_count_prop(inst,
588 593 SCF_PG_RESTARTER, SCF_PG_RESTARTER_TYPE,
589 594 SCF_PG_RESTARTER_FLAGS, SCF_PROPERTY_CONTRACT,
590 595 uint64);
591 596 }
592 597 (void) libscf_note_method_log(inst, LOG_PREFIX_EARLY,
593 598 STARTD_DEFAULT_LOG);
594 599 (void) libscf_note_method_log(inst, LOG_PREFIX_NORMAL,
595 600 STARTD_DEFAULT_LOG);
596 601 }
597 602
598 603 /* Read reconfigure property for recovery. */
599 604 if (scf_handle_decode_fmri(hndl, startd_reconfigure_fmri, NULL, NULL,
600 605 NULL, NULL, prop, NULL) != -1 &&
601 606 scf_property_get_value(prop, val) == 0)
602 607 (void) scf_value_get_boolean(val, &prop_reconfig);
603 608
604 609 if (scf_handle_decode_fmri(hndl, startd_options_fmri, NULL, NULL, NULL,
605 610 pg, NULL, SCF_DECODE_FMRI_TRUNCATE) == -1) {
606 611 /*
607 612 * No configuration options defined.
608 613 */
609 614 if (scf_error() != SCF_ERROR_NOT_FOUND)
610 615 uu_warn("Couldn't read configuration from 'options' "
611 616 "group: %s\n", scf_strerror(scf_error()));
612 617 goto scfout;
613 618 }
614 619
615 620 /*
616 621 * If there is no "options" group defined, then our defaults are fine.
617 622 */
618 623 if (scf_pg_get_name(pg, NULL, 0) < 0)
619 624 goto scfout;
620 625
621 626 /* get info_events_all */
622 627 info_events_all = libscf_get_info_events_all(pg);
623 628
624 629 /* Iterate through. */
625 630 iter = safe_scf_iter_create(hndl);
626 631
627 632 (void) scf_iter_pg_properties(iter, pg);
628 633
629 634 piter = safe_scf_iter_create(hndl);
630 635 vbuf = startd_alloc(max_scf_value_size);
631 636
632 637 while ((scf_iter_next_property(iter, prop) == 1)) {
633 638 scf_type_t ty;
634 639
635 640 if (scf_property_get_name(prop, buf, max_scf_fmri_size) < 0)
636 641 continue;
637 642
638 643 if (strcmp(buf, "logging") != 0 &&
639 644 strcmp(buf, "boot_messages") != 0)
640 645 continue;
641 646
642 647 if (scf_property_type(prop, &ty) != 0) {
643 648 switch (scf_error()) {
644 649 case SCF_ERROR_CONNECTION_BROKEN:
645 650 default:
646 651 libscf_handle_rebind(hndl);
647 652 continue;
648 653
649 654 case SCF_ERROR_DELETED:
650 655 continue;
651 656
652 657 case SCF_ERROR_NOT_BOUND:
653 658 case SCF_ERROR_NOT_SET:
654 659 bad_error("scf_property_type", scf_error());
655 660 }
656 661 }
657 662
658 663 if (ty != SCF_TYPE_ASTRING) {
659 664 uu_warn("property \"options/%s\" is not of type "
660 665 "astring; ignored.\n", buf);
661 666 continue;
662 667 }
663 668
664 669 if (scf_property_get_value(prop, val) != 0) {
665 670 switch (scf_error()) {
666 671 case SCF_ERROR_CONNECTION_BROKEN:
667 672 default:
668 673 return (ECONNABORTED);
669 674
670 675 case SCF_ERROR_DELETED:
671 676 case SCF_ERROR_NOT_FOUND:
672 677 return (0);
673 678
674 679 case SCF_ERROR_CONSTRAINT_VIOLATED:
675 680 uu_warn("property \"options/%s\" has multiple "
676 681 "values; ignored.\n", buf);
677 682 continue;
678 683
679 684 case SCF_ERROR_PERMISSION_DENIED:
680 685 uu_warn("property \"options/%s\" cannot be "
681 686 "read because startd has insufficient "
682 687 "permission; ignored.\n", buf);
683 688 continue;
684 689
685 690 case SCF_ERROR_HANDLE_MISMATCH:
686 691 case SCF_ERROR_NOT_BOUND:
687 692 case SCF_ERROR_NOT_SET:
688 693 bad_error("scf_property_get_value",
689 694 scf_error());
690 695 }
691 696 }
692 697
693 698 if (scf_value_get_astring(val, vbuf, max_scf_value_size) < 0)
694 699 bad_error("scf_value_get_astring", scf_error());
695 700
696 701 if (strcmp("logging", buf) == 0) {
697 702 if (strcmp("verbose", vbuf) == 0) {
698 703 st->st_boot_flags = STARTD_BOOT_VERBOSE;
699 704 st->st_log_level_min = LOG_INFO;
700 705 } else if (strcmp("debug", vbuf) == 0) {
701 706 st->st_boot_flags = STARTD_BOOT_VERBOSE;
702 707 st->st_log_level_min = LOG_DEBUG;
703 708 } else if (strcmp("quiet", vbuf) == 0) {
704 709 st->st_log_level_min = LOG_NOTICE;
705 710 } else {
706 711 uu_warn("unknown options/logging "
707 712 "value '%s' ignored\n", vbuf);
708 713 }
709 714
710 715 } else if (strcmp("boot_messages", buf) == 0) {
711 716 if (strcmp("quiet", vbuf) == 0) {
712 717 st->st_boot_flags = STARTD_BOOT_QUIET;
713 718 } else if (strcmp("verbose", vbuf) == 0) {
714 719 st->st_boot_flags = STARTD_BOOT_VERBOSE;
715 720 } else {
716 721 log_framework(LOG_NOTICE, "unknown "
717 722 "options/boot_messages value '%s' "
718 723 "ignored\n", vbuf);
719 724 }
720 725
721 726 }
722 727 }
723 728
724 729 startd_free(vbuf, max_scf_value_size);
725 730 scf_iter_destroy(piter);
726 731
727 732 scf_iter_destroy(iter);
728 733
729 734 scfout:
730 735 scf_value_destroy(val);
731 736 scf_pg_destroy(pg);
732 737 scf_property_destroy(prop);
733 738 scf_instance_destroy(inst);
734 739 (void) scf_handle_unbind(hndl);
735 740 scf_handle_destroy(hndl);
736 741
737 742 noscfout:
738 743 startd_free(buf, max_scf_fmri_size);
739 744 uu_free(startd_options_fmri);
740 745 uu_free(startd_reconfigure_fmri);
741 746
742 747 if (booting_to_single_user) {
743 748 st->st_subgraph = startd_alloc(max_scf_fmri_size);
744 749 sz = strlcpy(st->st_subgraph, "milestone/single-user:default",
745 750 max_scf_fmri_size);
746 751 assert(sz < max_scf_fmri_size);
747 752 }
748 753
749 754 /*
750 755 * Options passed in as boot arguments override repository defaults.
751 756 */
752 757 env_opts = getenv("SMF_OPTIONS");
753 758 if (env_opts == NULL)
754 759 return (ret);
755 760
756 761 for (cp = strtok_r(env_opts, ",", &lasts); cp != NULL;
757 762 cp = strtok_r(NULL, ",", &lasts)) {
758 763 if (strcmp(cp, "debug") == 0) {
759 764 st->st_boot_flags = STARTD_BOOT_VERBOSE;
760 765 st->st_log_level_min = LOG_DEBUG;
761 766
762 767 /* -m debug should send messages to console */
763 768 st->st_log_flags =
764 769 st->st_log_flags | STARTD_LOG_TERMINAL;
765 770 } else if (strcmp(cp, "verbose") == 0) {
766 771 st->st_boot_flags = STARTD_BOOT_VERBOSE;
767 772 st->st_log_level_min = LOG_INFO;
768 773 } else if (strcmp(cp, "seed") == 0) {
769 774 uu_warn("SMF option \"%s\" unimplemented.\n", cp);
770 775 } else if (strcmp(cp, "quiet") == 0) {
771 776 st->st_log_level_min = LOG_NOTICE;
772 777 } else if (strncmp(cp, "milestone=",
773 778 sizeof ("milestone=") - 1) == 0) {
774 779 char *mp = cp + sizeof ("milestone=") - 1;
775 780
776 781 if (booting_to_single_user)
777 782 continue;
778 783
779 784 if (st->st_subgraph == NULL) {
780 785 st->st_subgraph =
781 786 startd_alloc(max_scf_fmri_size);
782 787 st->st_subgraph[0] = '\0';
783 788 }
784 789
785 790 if (mp[0] == '\0' || strcmp(mp, "all") == 0) {
786 791 (void) strcpy(st->st_subgraph, "all");
787 792 } else if (strcmp(mp, "su") == 0 ||
788 793 strcmp(mp, "single-user") == 0) {
789 794 (void) strcpy(st->st_subgraph,
790 795 "milestone/single-user:default");
791 796 } else if (strcmp(mp, "mu") == 0 ||
792 797 strcmp(mp, "multi-user") == 0) {
793 798 (void) strcpy(st->st_subgraph,
794 799 "milestone/multi-user:default");
795 800 } else if (strcmp(mp, "mus") == 0 ||
796 801 strcmp(mp, "multi-user-server") == 0) {
797 802 (void) strcpy(st->st_subgraph,
798 803 "milestone/multi-user-server:default");
799 804 } else if (strcmp(mp, "none") == 0) {
800 805 (void) strcpy(st->st_subgraph, "none");
801 806 } else {
802 807 log_framework(LOG_NOTICE,
803 808 "invalid milestone option value "
804 809 "'%s' ignored\n", mp);
805 810 }
806 811 } else {
807 812 uu_warn("Unknown SMF option \"%s\".\n", cp);
808 813 }
809 814 }
810 815
811 816 return (ret);
812 817 }
813 818
814 819 /*
815 820 * void set_boot_env()
816 821 *
817 822 * If -r was passed or /reconfigure exists, this is a reconfig
818 823 * reboot. We need to make sure that this information is given
819 824 * to the appropriate services the first time they're started
820 825 * by setting the system/reconfigure repository property,
821 826 * as well as pass the _INIT_RECONFIG variable on to the rcS
822 827 * start method so that legacy services can continue to use it.
823 828 *
824 829 * This function must never be called before contract_init(), as
825 830 * it sets st_initial. get_startd_config() sets prop_reconfig from
826 831 * pre-existing repository state.
827 832 */
828 833 static void
829 834 set_boot_env()
830 835 {
831 836 struct stat sb;
832 837 int r;
833 838
834 839 /*
835 840 * Check if property still is set -- indicates we didn't get
836 841 * far enough previously to unset it. Otherwise, if this isn't
837 842 * the first startup, don't re-process /reconfigure or the
838 843 * boot flag.
839 844 */
840 845 if (prop_reconfig != 1 && st->st_initial != 1)
841 846 return;
842 847
843 848 /* If /reconfigure exists, also set opt_reconfig. */
844 849 if (stat("/reconfigure", &sb) != -1)
845 850 opt_reconfig = 1;
846 851
847 852 /* Nothing to do. Just return. */
848 853 if (opt_reconfig == 0 && prop_reconfig == 0)
849 854 return;
850 855
851 856 /*
852 857 * Set startd's reconfigure property. This property is
853 858 * then cleared by successful completion of the single-user
854 859 * milestone.
855 860 */
856 861 if (prop_reconfig != 1) {
857 862 r = libscf_set_reconfig(1);
858 863 switch (r) {
859 864 case 0:
860 865 break;
861 866
862 867 case ENOENT:
863 868 case EPERM:
864 869 case EACCES:
865 870 case EROFS:
866 871 log_error(LOG_WARNING, "Could not set reconfiguration "
867 872 "property: %s\n", strerror(r));
868 873 break;
869 874
870 875 default:
871 876 bad_error("libscf_set_reconfig", r);
872 877 }
873 878 }
874 879 }
875 880
876 881 static void
877 882 startup(void)
878 883 {
879 884 ctid_t configd_ctid;
880 885 int err;
881 886
882 887 /*
883 888 * Initialize data structures.
884 889 */
885 890 gu = startd_zalloc(sizeof (graph_update_t));
886 891 ru = startd_zalloc(sizeof (restarter_update_t));
887 892
888 893 (void) pthread_cond_init(&st->st_load_cv, NULL);
889 894 (void) pthread_cond_init(&st->st_configd_live_cv, NULL);
890 895 (void) pthread_cond_init(&gu->gu_cv, NULL);
891 896 (void) pthread_cond_init(&gu->gu_freeze_cv, NULL);
892 897 (void) pthread_cond_init(&ru->restarter_update_cv, NULL);
893 898 (void) pthread_mutex_init(&st->st_load_lock, &mutex_attrs);
894 899 (void) pthread_mutex_init(&st->st_configd_live_lock, &mutex_attrs);
895 900 (void) pthread_mutex_init(&gu->gu_lock, &mutex_attrs);
896 901 (void) pthread_mutex_init(&gu->gu_freeze_lock, &mutex_attrs);
897 902 (void) pthread_mutex_init(&ru->restarter_update_lock, &mutex_attrs);
898 903
899 904 configd_ctid = contract_init();
900 905
901 906 if (configd_ctid != -1)
902 907 log_framework(LOG_DEBUG, "Existing configd contract %ld; not "
903 908 "starting svc.configd\n", configd_ctid);
904 909
905 910 /*
906 911 * Call utmpx_init() before creating the fork_configd() thread.
907 912 */
908 913 utmpx_init();
909 914
910 915 (void) startd_thread_create(fork_configd_thread, (void *)configd_ctid);
911 916
912 917 /*
913 918 * Await, if necessary, configd's initial arrival.
914 919 */
915 920 MUTEX_LOCK(&st->st_configd_live_lock);
916 921 while (!st->st_configd_lives) {
917 922 log_framework(LOG_DEBUG, "Awaiting cv signal on "
918 923 "configd_live_cv\n");
919 924 err = pthread_cond_wait(&st->st_configd_live_cv,
920 925 &st->st_configd_live_lock);
921 926 assert(err == 0);
922 927 }
923 928 MUTEX_UNLOCK(&st->st_configd_live_lock);
924 929
925 930 wait_init();
926 931
927 932 if (read_startd_config())
928 933 log_framework(LOG_INFO, "svc.configd unable to provide startd "
929 934 "optional settings\n");
930 935
931 936 log_init();
932 937 dict_init();
933 938 timeout_init();
934 939 restarter_protocol_init();
935 940 restarter_init();
936 941
937 942 /*
938 943 * svc.configd is started by fork_configd_thread so repository access is
939 944 * available, run early manifest import before continuing with starting
940 945 * graph engine and the rest of startd.
941 946 */
942 947 log_framework(LOG_DEBUG, "Calling fork_emi...\n");
943 948 fork_emi();
944 949
945 950 graph_protocol_init();
946 951 graph_init();
947 952
948 953 init_env();
949 954
950 955 set_boot_env();
951 956 restarter_start();
952 957 graph_engine_start();
953 958 }
954 959
955 960 static void
956 961 usage(const char *name)
957 962 {
958 963 uu_warn(gettext("usage: %s [-n]\n"), name);
959 964 exit(UU_EXIT_USAGE);
960 965 }
961 966
962 967 static int
963 968 daemonize_start(void)
964 969 {
965 970 pid_t pid;
966 971 int fd;
967 972
968 973 if ((pid = fork1()) < 0)
969 974 return (-1);
970 975
971 976 if (pid != 0)
972 977 exit(0);
973 978
974 979 (void) close(STDIN_FILENO);
975 980
976 981 if ((fd = open("/dev/null", O_RDONLY)) == -1) {
977 982 uu_warn(gettext("can't connect stdin to /dev/null"));
978 983 } else if (fd != STDIN_FILENO) {
979 984 (void) dup2(fd, STDIN_FILENO);
980 985 startd_close(fd);
981 986 }
982 987
983 988 closefrom(3);
984 989 (void) dup2(STDERR_FILENO, STDOUT_FILENO);
985 990
986 991 (void) setsid();
987 992 (void) chdir("/");
988 993
989 994 /* Use default umask that init handed us, but 022 to create files. */
990 995 dmask = umask(022);
991 996 fmask = umask(dmask);
992 997
993 998 return (0);
994 999 }
995 1000
996 1001 /*ARGSUSED*/
997 1002 static void
998 1003 die_handler(int sig, siginfo_t *info, void *data)
999 1004 {
1000 1005 finished = 1;
1001 1006 }
1002 1007
1003 1008 int
1004 1009 main(int argc, char *argv[])
1005 1010 {
1006 1011 int opt;
1007 1012 int daemonize = 1;
1008 1013 struct sigaction act;
1009 1014 sigset_t nullset;
1010 1015 struct stat sb;
1011 1016
1012 1017 (void) uu_setpname(argv[0]);
1013 1018
1014 1019 st = startd_zalloc(sizeof (startd_state_t));
1015 1020
1016 1021 (void) pthread_mutexattr_init(&mutex_attrs);
1017 1022 #ifndef NDEBUG
1018 1023 (void) pthread_mutexattr_settype(&mutex_attrs,
1019 1024 PTHREAD_MUTEX_ERRORCHECK);
1020 1025 #endif
1021 1026
1022 1027 max_scf_name_size = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
1023 1028 max_scf_value_size = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
1024 1029 max_scf_fmri_size = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
1025 1030
1026 1031 if (max_scf_name_size == -1 || max_scf_value_size == -1 ||
1027 1032 max_scf_value_size == -1)
1028 1033 uu_die("Can't determine repository maximum lengths.\n");
1029 1034
1030 1035 max_scf_name_size++;
1031 1036 max_scf_value_size++;
1032 1037 max_scf_fmri_size++;
1033 1038
1034 1039 st->st_log_flags = STARTD_LOG_FILE | STARTD_LOG_SYSLOG;
1035 1040 st->st_log_level_min = LOG_NOTICE;
1036 1041
1037 1042 while ((opt = getopt(argc, argv, "nrs")) != EOF) {
1038 1043 switch (opt) {
1039 1044 case 'n':
1040 1045 daemonize = 0;
1041 1046 break;
1042 1047 case 'r': /* reconfiguration boot */
1043 1048 opt_reconfig = 1;
1044 1049 break;
1045 1050 case 's': /* single-user mode */
1046 1051 booting_to_single_user = B_TRUE;
1047 1052 break;
1048 1053 default:
1049 1054 usage(argv[0]); /* exits */
1050 1055 }
1051 1056 }
1052 1057
1053 1058 if (optind != argc)
1054 1059 usage(argv[0]);
1055 1060
1056 1061 (void) enable_extended_FILE_stdio(-1, -1);
1057 1062
1058 1063 if (daemonize)
1059 1064 if (daemonize_start() < 0)
1060 1065 uu_die("Can't daemonize\n");
1061 1066
1062 1067 log_init();
1063 1068
1064 1069 if (stat("/etc/svc/volatile/resetting", &sb) != -1) {
1065 1070 log_framework(LOG_NOTICE, "Restarter quiesced.\n");
1066 1071
1067 1072 for (;;)
1068 1073 (void) pause();
1069 1074 }
1070 1075
1071 1076 act.sa_sigaction = &die_handler;
1072 1077 (void) sigfillset(&act.sa_mask);
1073 1078 act.sa_flags = SA_SIGINFO;
1074 1079 (void) sigaction(SIGINT, &act, NULL);
1075 1080 (void) sigaction(SIGTERM, &act, NULL);
1076 1081
1077 1082 startup();
1078 1083
1079 1084 (void) sigemptyset(&nullset);
1080 1085 while (!finished) {
1081 1086 log_framework(LOG_DEBUG, "Main thread paused\n");
1082 1087 (void) sigsuspend(&nullset);
1083 1088 }
1084 1089
1085 1090 (void) log_framework(LOG_DEBUG, "Restarter exiting.\n");
1086 1091 return (0);
1087 1092 }
↓ open down ↓ |
826 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX