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