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