Print this page
12721 would like svcadm disable -c
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/svc/svcs/explain.c
+++ new/usr/src/cmd/svc/svcs/explain.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 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 - * Copyright (c) 2015, Joyent, Inc. All rights reserved.
25 + * Copyright 2020 Joyent, Inc.
26 26 */
27 27
28 28 /*
29 29 * Service state explanation. For select services, display a description, the
30 30 * state, and possibly why the service is in that state, what's causing it to
31 31 * be in that state, and what other services it is keeping offline (impact).
32 32 *
33 33 * Explaining states other than offline is easy. For maintenance and
34 34 * degraded, we just use the auxiliary state. For offline, we must determine
35 35 * which dependencies are unsatisfied and recurse. If a causal service is not
36 36 * offline, then a svcptr to it is added to the offline service's causes list.
37 37 * If a causal service is offline, then we recurse to determine its causes and
38 38 * merge them into the causes list of the service in question (see
39 39 * add_causes()). Note that by adding a self-pointing svcptr to the causes
40 40 * lists of services which are not offline or are offline for unknown reasons,
41 41 * we can always merge the unsatisfied dependency's causes into the
42 42 * dependent's list.
43 43 *
44 44 * Computing an impact list is more involved because the dependencies in the
45 45 * repository are unidirectional; it requires determining the causes of all
46 46 * offline services. For each unsatisfied dependency of an offline service,
47 47 * a svcptr to the dependent is added to the dependency's impact_dependents
48 48 * list (see add_causes()). determine_impact() uses the lists to build an
49 49 * impact list. The direct dependency is used so that a path from the
50 50 * affected service to the causal service can be constructed (see
51 51 * print_dependency_reasons()).
52 52 *
53 53 * Because we always need at least impact counts, we always run
54 54 * determine_causes() on all services.
55 55 *
56 56 * If no arguments are given, we must select the services which are causing
57 57 * other services to be offline. We do so by adding services which are not
58 58 * running for any reason other than another service to the g_causes list in
59 59 * determine_causes().
60 60 *
61 61 * Since all services must be examined, and their states may be consulted
62 62 * a lot, it is important that we only read volatile data (like states) from
63 63 * the repository once. add_instance() reads data for an instance from the
64 64 * repository into an inst_t and puts it into the "services" cache, which is
65 65 * organized as a hash table of svc_t's, each of which has a list of inst_t's.
66 66 */
67 67
68 68 #include "svcs.h"
69 69
70 70 #include <sys/stat.h>
71 71 #include <sys/wait.h>
72 72
73 73 #include <assert.h>
74 74 #include <errno.h>
75 75 #include <libintl.h>
76 76 #include <libuutil.h>
77 77 #include <libscf.h>
78 78 #include <libscf_priv.h>
79 79 #include <string.h>
80 80 #include <stdio.h>
81 81 #include <stdlib.h>
82 82 #include <time.h>
83 83
84 84
85 85 #define DC_DISABLED "SMF-8000-05"
86 86 #define DC_TEMPDISABLED "SMF-8000-1S"
87 87 #define DC_RSTRINVALID "SMF-8000-2A"
88 88 #define DC_RSTRABSENT "SMF-8000-3P"
89 89 #define DC_UNINIT "SMF-8000-4D"
90 90 #define DC_RSTRDEAD "SMF-8000-5H"
91 91 #define DC_ADMINMAINT "SMF-8000-63"
92 92 #define DC_SVCREQMAINT "SMF-8000-R4"
93 93 #define DC_REPTFAIL "SMF-8000-7Y"
94 94 #define DC_METHFAIL "SMF-8000-8Q"
95 95 #define DC_NONE "SMF-8000-9C"
96 96 #define DC_UNKNOWN "SMF-8000-AR"
97 97 #define DC_STARTING "SMF-8000-C4"
98 98 #define DC_ADMINDEGR "SMF-8000-DX"
99 99 #define DC_DEPABSENT "SMF-8000-E2"
100 100 #define DC_DEPRUNNING "SMF-8000-FJ"
101 101 #define DC_DEPOTHER "SMF-8000-GE"
102 102 #define DC_DEPCYCLE "SMF-8000-HP"
103 103 #define DC_INVALIDDEP "SMF-8000-JA"
104 104 #define DC_STARTFAIL "SMF-8000-KS"
105 105 #define DC_TOOQUICKLY "SMF-8000-L5"
106 106 #define DC_INVALIDSTATE "SMF-8000-N3"
107 107 #define DC_TRANSITION "SMF-8000-PH"
108 108
109 109 #define DEFAULT_MAN_PATH "/usr/share/man"
110 110
111 111 #define AUX_STATE_INVALID "invalid_aux_state"
112 112
113 113 #define uu_list_append(lst, e) uu_list_insert_before(lst, NULL, e)
114 114
115 115 #define bad_error(func, err) \
116 116 uu_panic("%s:%d: %s() failed with unknown error %d.\n", \
117 117 __FILE__, __LINE__, func, err);
118 118
119 119 typedef struct {
120 120 const char *svcname;
121 121 const char *instname;
122 122
123 123 /* restarter pg properties */
124 124 char state[MAX_SCF_STATE_STRING_SZ];
125 125 char next_state[MAX_SCF_STATE_STRING_SZ];
↓ open down ↓ |
90 lines elided |
↑ open up ↑ |
126 126 struct timeval stime;
127 127 const char *aux_state;
128 128 const char *aux_fmri;
129 129 int64_t start_method_waitstatus;
130 130
131 131 uint8_t enabled;
132 132 int temporary;
133 133 const char *restarter;
134 134 uu_list_t *dependencies; /* list of dependency_group's */
135 135
136 + char comment[SCF_COMMENT_MAX_LENGTH];
137 +
136 138 int active; /* In use? (cycle detection) */
137 139 int restarter_bad;
138 140 const char *summary;
139 141 uu_list_t *baddeps; /* list of dependency's */
140 142 uu_list_t *causes; /* list of svcptrs */
141 143 uu_list_t *impact_dependents; /* list of svcptrs */
142 144 uu_list_t *impact; /* list of svcptrs */
143 145
144 146 uu_list_node_t node;
145 147 } inst_t;
146 148
147 149 typedef struct service {
148 150 const char *svcname;
149 151 uu_list_t *instances;
150 152 struct service *next;
151 153 } svc_t;
152 154
153 155 struct svcptr {
154 156 inst_t *svcp;
155 157 inst_t *next_hop;
156 158 uu_list_node_t node;
157 159 };
158 160
159 161 struct dependency_group {
160 162 enum { DGG_REQALL, DGG_REQANY, DGG_OPTALL, DGG_EXCALL } grouping;
161 163 const char *type;
162 164 uu_list_t *entities; /* List of struct dependency's */
163 165 uu_list_node_t node;
164 166 };
165 167
166 168 struct dependency {
167 169 const char *fmri;
168 170 uu_list_node_t node;
169 171 };
170 172
171 173 /* Hash table of service names -> svc_t's */
172 174 #define SVC_HASH_NBUCKETS 256
173 175 #define SVC_HASH_MASK (SVC_HASH_NBUCKETS - 1)
174 176
175 177 static svc_t **services;
176 178
177 179 static uu_list_pool_t *insts, *svcptrs, *depgroups, *deps;
178 180 static uu_list_t *g_causes; /* list of svcptrs */
179 181
180 182 static scf_scope_t *g_local_scope;
181 183 static scf_service_t *g_svc;
182 184 static scf_instance_t *g_inst;
183 185 static scf_snapshot_t *g_snap;
184 186 static scf_propertygroup_t *g_pg;
185 187 static scf_property_t *g_prop;
186 188 static scf_value_t *g_val;
187 189 static scf_iter_t *g_iter, *g_viter;
188 190 static char *g_fmri, *g_value;
189 191 static size_t g_fmri_sz, g_value_sz;
190 192 static const char *g_msgbase = "http://illumos.org/msg/";
191 193
192 194 static char *emsg_nomem;
193 195 static char *emsg_invalid_dep;
194 196
195 197 extern scf_handle_t *h;
196 198 extern char *g_zonename;
197 199
198 200 /* ARGSUSED */
199 201 static int
200 202 svcptr_compare(struct svcptr *a, struct svcptr *b, void *data)
201 203 {
202 204 return (b->svcp - a->svcp);
203 205 }
204 206
205 207 static uint32_t
206 208 hash_name(const char *name)
207 209 {
208 210 uint32_t h = 0, g;
209 211 const char *p;
210 212
211 213 for (p = name; *p != '\0'; ++p) {
212 214 h = (h << 4) + *p;
213 215 if ((g = (h & 0xf0000000)) != 0) {
214 216 h ^= (g >> 24);
215 217 h ^= g;
216 218 }
217 219 }
218 220
219 221 return (h);
220 222 }
221 223
222 224 static void
223 225 x_init(void)
224 226 {
225 227 emsg_nomem = gettext("Out of memory.\n");
226 228 emsg_invalid_dep =
227 229 gettext("svc:/%s:%s has invalid dependency \"%s\".\n");
228 230
229 231 services = calloc(SVC_HASH_NBUCKETS, sizeof (*services));
230 232 if (services == NULL)
231 233 uu_die(emsg_nomem);
232 234
233 235 insts = uu_list_pool_create("insts", sizeof (inst_t),
234 236 offsetof(inst_t, node), NULL, UU_LIST_POOL_DEBUG);
235 237 svcptrs = uu_list_pool_create("svcptrs", sizeof (struct svcptr),
236 238 offsetof(struct svcptr, node), (uu_compare_fn_t *)svcptr_compare,
237 239 UU_LIST_POOL_DEBUG);
238 240 depgroups = uu_list_pool_create("depgroups",
239 241 sizeof (struct dependency_group),
240 242 offsetof(struct dependency_group, node), NULL, UU_LIST_POOL_DEBUG);
241 243 deps = uu_list_pool_create("deps", sizeof (struct dependency),
242 244 offsetof(struct dependency, node), NULL, UU_LIST_POOL_DEBUG);
243 245 g_causes = uu_list_create(svcptrs, NULL, UU_LIST_DEBUG);
244 246 if (insts == NULL || svcptrs == NULL || depgroups == NULL ||
245 247 deps == NULL || g_causes == NULL)
246 248 uu_die(emsg_nomem);
247 249
248 250 if ((g_local_scope = scf_scope_create(h)) == NULL ||
249 251 (g_svc = scf_service_create(h)) == NULL ||
250 252 (g_inst = scf_instance_create(h)) == NULL ||
251 253 (g_snap = scf_snapshot_create(h)) == NULL ||
252 254 (g_pg = scf_pg_create(h)) == NULL ||
253 255 (g_prop = scf_property_create(h)) == NULL ||
254 256 (g_val = scf_value_create(h)) == NULL ||
255 257 (g_iter = scf_iter_create(h)) == NULL ||
256 258 (g_viter = scf_iter_create(h)) == NULL)
257 259 scfdie();
258 260
259 261 if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, g_local_scope) != 0)
260 262 scfdie();
261 263
262 264 g_fmri_sz = max_scf_fmri_length + 1;
263 265 g_fmri = safe_malloc(g_fmri_sz);
264 266
265 267 g_value_sz = max_scf_value_length + 1;
266 268 g_value = safe_malloc(g_value_sz);
267 269 }
268 270
269 271 /*
270 272 * Repository loading routines.
271 273 */
272 274
273 275 /*
274 276 * Returns
275 277 * 0 - success
276 278 * ECANCELED - inst was deleted
277 279 * EINVAL - inst is invalid
278 280 */
279 281 static int
280 282 load_dependencies(inst_t *svcp, scf_instance_t *inst)
281 283 {
282 284 scf_snapshot_t *snap;
283 285 struct dependency_group *dg;
284 286 struct dependency *d;
285 287 int r;
286 288
287 289 assert(svcp->dependencies == NULL);
288 290 svcp->dependencies = uu_list_create(depgroups, svcp, UU_LIST_DEBUG);
289 291 if (svcp->dependencies == NULL)
290 292 uu_die(emsg_nomem);
291 293
292 294 if (scf_instance_get_snapshot(inst, "running", g_snap) == 0) {
293 295 snap = g_snap;
294 296 } else {
295 297 if (scf_error() != SCF_ERROR_NOT_FOUND)
296 298 scfdie();
297 299
298 300 snap = NULL;
299 301 }
300 302
301 303 if (scf_iter_instance_pgs_typed_composed(g_iter, inst, snap,
302 304 SCF_GROUP_DEPENDENCY) != 0) {
303 305 if (scf_error() != SCF_ERROR_DELETED)
304 306 scfdie();
305 307 return (ECANCELED);
306 308 }
307 309
308 310 for (;;) {
309 311 r = scf_iter_next_pg(g_iter, g_pg);
310 312 if (r == 0)
311 313 break;
312 314 if (r != 1) {
313 315 if (scf_error() != SCF_ERROR_DELETED)
314 316 scfdie();
315 317 return (ECANCELED);
316 318 }
317 319
318 320 dg = safe_malloc(sizeof (*dg));
319 321 (void) memset(dg, 0, sizeof (*dg));
320 322 dg->entities = uu_list_create(deps, dg, UU_LIST_DEBUG);
321 323 if (dg->entities == NULL)
322 324 uu_die(emsg_nomem);
323 325
324 326 if (pg_get_single_val(g_pg, SCF_PROPERTY_GROUPING,
325 327 SCF_TYPE_ASTRING, g_value, g_value_sz, 0) != 0)
326 328 return (EINVAL);
327 329
328 330 if (strcmp(g_value, "require_all") == 0)
329 331 dg->grouping = DGG_REQALL;
330 332 else if (strcmp(g_value, "require_any") == 0)
331 333 dg->grouping = DGG_REQANY;
332 334 else if (strcmp(g_value, "optional_all") == 0)
333 335 dg->grouping = DGG_OPTALL;
334 336 else if (strcmp(g_value, "exclude_all") == 0)
335 337 dg->grouping = DGG_EXCALL;
336 338 else {
337 339 (void) fprintf(stderr, gettext("svc:/%s:%s has "
338 340 "dependency with unknown type \"%s\".\n"),
339 341 svcp->svcname, svcp->instname, g_value);
340 342 return (EINVAL);
341 343 }
342 344
343 345 if (pg_get_single_val(g_pg, SCF_PROPERTY_TYPE, SCF_TYPE_ASTRING,
344 346 g_value, g_value_sz, 0) != 0)
345 347 return (EINVAL);
346 348 dg->type = safe_strdup(g_value);
347 349
348 350 if (scf_pg_get_property(g_pg, SCF_PROPERTY_ENTITIES, g_prop) !=
349 351 0) {
350 352 switch (scf_error()) {
351 353 case SCF_ERROR_NOT_FOUND:
352 354 (void) fprintf(stderr, gettext("svc:/%s:%s has "
353 355 "dependency without an entities "
354 356 "property.\n"), svcp->svcname,
355 357 svcp->instname);
356 358 return (EINVAL);
357 359
358 360 case SCF_ERROR_DELETED:
359 361 return (ECANCELED);
360 362
361 363 default:
362 364 scfdie();
363 365 }
364 366 }
365 367
366 368 if (scf_iter_property_values(g_viter, g_prop) != 0) {
367 369 if (scf_error() != SCF_ERROR_DELETED)
368 370 scfdie();
369 371 return (ECANCELED);
370 372 }
371 373
372 374 for (;;) {
373 375 r = scf_iter_next_value(g_viter, g_val);
374 376 if (r == 0)
375 377 break;
376 378 if (r != 1) {
377 379 if (scf_error() != SCF_ERROR_DELETED)
378 380 scfdie();
379 381 return (ECANCELED);
380 382 }
381 383
382 384 d = safe_malloc(sizeof (*d));
383 385 d->fmri = safe_malloc(max_scf_fmri_length + 1);
384 386
385 387 if (scf_value_get_astring(g_val, (char *)d->fmri,
386 388 max_scf_fmri_length + 1) < 0)
387 389 scfdie();
388 390
389 391 uu_list_node_init(d, &d->node, deps);
390 392 (void) uu_list_append(dg->entities, d);
391 393 }
392 394
393 395 uu_list_node_init(dg, &dg->node, depgroups);
394 396 r = uu_list_append(svcp->dependencies, dg);
395 397 assert(r == 0);
↓ open down ↓ |
250 lines elided |
↑ open up ↑ |
396 398 }
397 399
398 400 return (0);
399 401 }
400 402
401 403 static void
402 404 add_instance(const char *svcname, const char *instname, scf_instance_t *inst)
403 405 {
404 406 inst_t *instp;
405 407 svc_t *svcp;
406 - int have_enabled = 0;
408 + int ovr_set = 0;
407 409 uint8_t i;
408 410 uint32_t h;
409 411 int r;
410 412
411 413 h = hash_name(svcname) & SVC_HASH_MASK;
412 414 for (svcp = services[h]; svcp != NULL; svcp = svcp->next) {
413 415 if (strcmp(svcp->svcname, svcname) == 0)
414 416 break;
415 417 }
416 418
417 419 if (svcp == NULL) {
418 420 svcp = safe_malloc(sizeof (*svcp));
419 421 svcp->svcname = safe_strdup(svcname);
420 422 svcp->instances = uu_list_create(insts, svcp, UU_LIST_DEBUG);
421 423 if (svcp->instances == NULL)
422 424 uu_die(emsg_nomem);
423 425 svcp->next = services[h];
424 426 services[h] = svcp;
425 427 }
426 428
427 429 instp = safe_malloc(sizeof (*instp));
428 430 (void) memset(instp, 0, sizeof (*instp));
429 431 instp->svcname = svcp->svcname;
430 432 instp->instname = safe_strdup(instname);
431 433 instp->impact_dependents =
432 434 uu_list_create(svcptrs, instp, UU_LIST_DEBUG);
433 435 if (instp->impact_dependents == NULL)
434 436 uu_die(emsg_nomem);
435 437
436 438 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, g_pg) != 0) {
437 439 switch (scf_error()) {
438 440 case SCF_ERROR_DELETED:
439 441 return;
440 442
441 443 case SCF_ERROR_NOT_FOUND:
442 444 (void) fprintf(stderr, gettext("svc:/%s:%s has no "
443 445 "\"%s\" property group; ignoring.\n"),
444 446 instp->svcname, instp->instname, SCF_PG_RESTARTER);
445 447 return;
446 448
447 449 default:
448 450 scfdie();
449 451 }
450 452 }
451 453
452 454 if (pg_get_single_val(g_pg, SCF_PROPERTY_STATE, SCF_TYPE_ASTRING,
453 455 (void *)instp->state, sizeof (instp->state), 0) != 0)
454 456 return;
455 457
456 458 if (pg_get_single_val(g_pg, SCF_PROPERTY_NEXT_STATE, SCF_TYPE_ASTRING,
457 459 (void *)instp->next_state, sizeof (instp->next_state), 0) != 0)
458 460 return;
459 461
460 462 if (pg_get_single_val(g_pg, SCF_PROPERTY_STATE_TIMESTAMP,
461 463 SCF_TYPE_TIME, &instp->stime, 0, 0) != 0)
462 464 return;
463 465
464 466 /* restarter may not set aux_state, allow to continue in that case */
465 467 if (pg_get_single_val(g_pg, SCF_PROPERTY_AUX_STATE, SCF_TYPE_ASTRING,
466 468 g_fmri, g_fmri_sz, 0) == 0)
467 469 instp->aux_state = safe_strdup(g_fmri);
468 470 else
469 471 instp->aux_state = safe_strdup(AUX_STATE_INVALID);
470 472
471 473 (void) pg_get_single_val(g_pg, SCF_PROPERTY_START_METHOD_WAITSTATUS,
↓ open down ↓ |
55 lines elided |
↑ open up ↑ |
472 474 SCF_TYPE_INTEGER, &instp->start_method_waitstatus, 0, 0);
473 475
474 476 /* Get the optional auxiliary_fmri */
475 477 if (pg_get_single_val(g_pg, SCF_PROPERTY_AUX_FMRI, SCF_TYPE_ASTRING,
476 478 g_fmri, g_fmri_sz, 0) == 0)
477 479 instp->aux_fmri = safe_strdup(g_fmri);
478 480
479 481 if (scf_instance_get_pg(inst, SCF_PG_GENERAL_OVR, g_pg) == 0) {
480 482 if (pg_get_single_val(g_pg, SCF_PROPERTY_ENABLED,
481 483 SCF_TYPE_BOOLEAN, &instp->enabled, 0, 0) == 0)
482 - have_enabled = 1;
484 + ovr_set = 1;
485 + (void) pg_get_single_val(g_pg, SCF_PROPERTY_COMMENT,
486 + SCF_TYPE_ASTRING, instp->comment,
487 + sizeof (instp->comment), EMPTY_OK);
483 488 } else {
484 489 switch (scf_error()) {
485 490 case SCF_ERROR_NOT_FOUND:
486 491 break;
487 492
488 493 case SCF_ERROR_DELETED:
489 494 return;
490 495
491 496 default:
492 497 scfdie();
493 498 }
494 499 }
495 500
496 501 if (scf_instance_get_pg_composed(inst, NULL, SCF_PG_GENERAL, g_pg) !=
497 502 0) {
498 503 switch (scf_error()) {
499 504 case SCF_ERROR_DELETED:
500 505 case SCF_ERROR_NOT_FOUND:
↓ open down ↓ |
8 lines elided |
↑ open up ↑ |
501 506 return;
502 507
503 508 default:
504 509 scfdie();
505 510 }
506 511 }
507 512
508 513 if (pg_get_single_val(g_pg, SCF_PROPERTY_ENABLED, SCF_TYPE_BOOLEAN,
509 514 &i, 0, 0) != 0)
510 515 return;
511 - if (!have_enabled) {
516 +
517 + if (ovr_set) {
518 + instp->temporary = (instp->enabled != i);
519 + } else {
512 520 instp->enabled = i;
513 521 instp->temporary = 0;
514 - } else {
515 - instp->temporary = (instp->enabled != i);
516 522 }
517 523
524 + if (!instp->temporary) {
525 + (void) pg_get_single_val(g_pg, SCF_PROPERTY_COMMENT,
526 + SCF_TYPE_ASTRING, instp->comment,
527 + sizeof (instp->comment), EMPTY_OK);
528 + }
529 +
518 530 if (pg_get_single_val(g_pg, SCF_PROPERTY_RESTARTER, SCF_TYPE_ASTRING,
519 531 g_fmri, g_fmri_sz, 0) == 0)
520 532 instp->restarter = safe_strdup(g_fmri);
521 533 else
522 534 instp->restarter = SCF_SERVICE_STARTD;
523 535
524 536 if (strcmp(instp->state, SCF_STATE_STRING_OFFLINE) == 0 &&
525 537 load_dependencies(instp, inst) != 0)
526 538 return;
527 539
528 540 uu_list_node_init(instp, &instp->node, insts);
529 541 r = uu_list_append(svcp->instances, instp);
530 542 assert(r == 0);
531 543 }
532 544
533 545 static void
534 546 load_services(void)
535 547 {
536 548 scf_iter_t *siter, *iiter;
537 549 int r;
538 550 char *svcname, *instname;
539 551
540 552 if ((siter = scf_iter_create(h)) == NULL ||
541 553 (iiter = scf_iter_create(h)) == NULL)
542 554 scfdie();
543 555
544 556 svcname = safe_malloc(max_scf_name_length + 1);
545 557 instname = safe_malloc(max_scf_name_length + 1);
546 558
547 559 if (scf_iter_scope_services(siter, g_local_scope) != 0)
548 560 scfdie();
549 561
550 562 for (;;) {
551 563 r = scf_iter_next_service(siter, g_svc);
552 564 if (r == 0)
553 565 break;
554 566 if (r != 1)
555 567 scfdie();
556 568
557 569 if (scf_service_get_name(g_svc, svcname,
558 570 max_scf_name_length + 1) < 0) {
559 571 if (scf_error() != SCF_ERROR_DELETED)
560 572 scfdie();
561 573 continue;
562 574 }
563 575
564 576 if (scf_iter_service_instances(iiter, g_svc) != 0) {
565 577 if (scf_error() != SCF_ERROR_DELETED)
566 578 scfdie();
567 579 continue;
568 580 }
569 581
570 582 for (;;) {
571 583 r = scf_iter_next_instance(iiter, g_inst);
572 584 if (r == 0)
573 585 break;
574 586 if (r != 1) {
575 587 if (scf_error() != SCF_ERROR_DELETED)
576 588 scfdie();
577 589 break;
578 590 }
579 591
580 592 if (scf_instance_get_name(g_inst, instname,
581 593 max_scf_name_length + 1) < 0) {
582 594 if (scf_error() != SCF_ERROR_DELETED)
583 595 scfdie();
584 596 continue;
585 597 }
586 598
587 599 add_instance(svcname, instname, g_inst);
588 600 }
589 601 }
590 602
591 603 free(svcname);
592 604 free(instname);
593 605 scf_iter_destroy(siter);
594 606 scf_iter_destroy(iiter);
595 607 }
596 608
597 609 /*
598 610 * Dependency analysis routines.
599 611 */
600 612
601 613 static void
602 614 add_svcptr(uu_list_t *lst, inst_t *svcp)
603 615 {
604 616 struct svcptr *spp;
605 617 uu_list_index_t idx;
606 618 int r;
607 619
608 620 spp = safe_malloc(sizeof (*spp));
609 621 spp->svcp = svcp;
610 622 spp->next_hop = NULL;
611 623
612 624 if (uu_list_find(lst, spp, NULL, &idx) != NULL) {
613 625 free(spp);
614 626 return;
615 627 }
616 628
617 629 uu_list_node_init(spp, &spp->node, svcptrs);
618 630 r = uu_list_append(lst, spp);
619 631 assert(r == 0);
620 632 }
621 633
622 634 static int determine_causes(inst_t *, void *);
623 635
624 636 /*
625 637 * Determine the causes of src and add them to the causes list of dst.
626 638 * Returns ELOOP if src is active, and 0 otherwise.
627 639 */
628 640 static int
629 641 add_causes(inst_t *dst, inst_t *src)
630 642 {
631 643 struct svcptr *spp, *copy;
632 644 uu_list_index_t idx;
633 645
634 646 if (determine_causes(src, (void *)1) != UU_WALK_NEXT) {
635 647 /* Dependency cycle. */
636 648 (void) fprintf(stderr, " svc:/%s:%s\n", dst->svcname,
637 649 dst->instname);
638 650 return (ELOOP);
639 651 }
640 652
641 653 add_svcptr(src->impact_dependents, dst);
642 654
643 655 for (spp = uu_list_first(src->causes);
644 656 spp != NULL;
645 657 spp = uu_list_next(src->causes, spp)) {
646 658 if (uu_list_find(dst->causes, spp, NULL, &idx) != NULL)
647 659 continue;
648 660
649 661 copy = safe_malloc(sizeof (*copy));
650 662 copy->svcp = spp->svcp;
651 663 copy->next_hop = src;
652 664 uu_list_node_init(copy, ©->node, svcptrs);
653 665 uu_list_insert(dst->causes, copy, idx);
654 666
655 667 add_svcptr(g_causes, spp->svcp);
656 668 }
657 669
658 670 return (0);
659 671 }
660 672
661 673 static int
662 674 inst_running(inst_t *ip)
663 675 {
664 676 return (strcmp(ip->state, SCF_STATE_STRING_ONLINE) == 0 ||
665 677 strcmp(ip->state, SCF_STATE_STRING_DEGRADED) == 0);
666 678 }
667 679
668 680 static int
669 681 inst_running_or_maint(inst_t *ip)
670 682 {
671 683 return (inst_running(ip) ||
672 684 strcmp(ip->state, SCF_STATE_STRING_MAINT) == 0);
673 685 }
674 686
675 687 static svc_t *
676 688 get_svc(const char *sn)
677 689 {
678 690 uint32_t h;
679 691 svc_t *svcp;
680 692
681 693 h = hash_name(sn) & SVC_HASH_MASK;
682 694
683 695 for (svcp = services[h]; svcp != NULL; svcp = svcp->next) {
684 696 if (strcmp(svcp->svcname, sn) == 0)
685 697 break;
686 698 }
687 699
688 700 return (svcp);
689 701 }
690 702
691 703 /* ARGSUSED */
692 704 static inst_t *
693 705 get_inst(svc_t *svcp, const char *in)
694 706 {
695 707 inst_t *instp;
696 708
697 709 for (instp = uu_list_first(svcp->instances);
698 710 instp != NULL;
699 711 instp = uu_list_next(svcp->instances, instp)) {
700 712 if (strcmp(instp->instname, in) == 0)
701 713 return (instp);
702 714 }
703 715
704 716 return (NULL);
705 717 }
706 718
707 719 static int
708 720 get_fmri(const char *fmri, svc_t **spp, inst_t **ipp)
709 721 {
710 722 const char *sn, *in;
711 723 svc_t *sp;
712 724 inst_t *ip;
713 725
714 726 if (strlcpy(g_fmri, fmri, g_fmri_sz) >= g_fmri_sz)
715 727 return (EINVAL);
716 728
717 729 if (scf_parse_svc_fmri(g_fmri, NULL, &sn, &in, NULL, NULL) != 0)
718 730 return (EINVAL);
719 731
720 732 if (sn == NULL)
721 733 return (EINVAL);
722 734
723 735 sp = get_svc(sn);
724 736 if (sp == NULL)
725 737 return (ENOENT);
726 738
727 739 if (in != NULL) {
728 740 ip = get_inst(sp, in);
729 741 if (ip == NULL)
730 742 return (ENOENT);
731 743 }
732 744
733 745 if (spp != NULL)
734 746 *spp = sp;
735 747 if (ipp != NULL)
736 748 *ipp = ((in == NULL) ? NULL : ip);
737 749
738 750 return (0);
739 751 }
740 752
741 753 static int
742 754 process_reqall(inst_t *svcp, struct dependency_group *dg)
743 755 {
744 756 uu_list_walk_t *walk;
745 757 struct dependency *d;
746 758 int r, svcrunning;
747 759 svc_t *sp;
748 760 inst_t *ip;
749 761
750 762 walk = uu_list_walk_start(dg->entities, UU_WALK_ROBUST);
751 763 if (walk == NULL)
752 764 uu_die(emsg_nomem);
753 765
754 766 while ((d = uu_list_walk_next(walk)) != NULL) {
755 767 r = get_fmri(d->fmri, &sp, &ip);
756 768 switch (r) {
757 769 case EINVAL:
758 770 /* LINTED */
759 771 (void) fprintf(stderr, emsg_invalid_dep, svcp->svcname,
760 772 svcp->instname, d->fmri);
761 773 continue;
762 774
763 775 case ENOENT:
764 776 uu_list_remove(dg->entities, d);
765 777 r = uu_list_append(svcp->baddeps, d);
766 778 assert(r == 0);
767 779 continue;
768 780
769 781 case 0:
770 782 break;
771 783
772 784 default:
773 785 bad_error("get_fmri", r);
774 786 }
775 787
776 788 if (ip != NULL) {
777 789 if (inst_running(ip))
778 790 continue;
779 791 r = add_causes(svcp, ip);
780 792 if (r != 0) {
781 793 assert(r == ELOOP);
782 794 return (r);
783 795 }
784 796 continue;
785 797 }
786 798
787 799 svcrunning = 0;
788 800
789 801 for (ip = uu_list_first(sp->instances);
790 802 ip != NULL;
791 803 ip = uu_list_next(sp->instances, ip)) {
792 804 if (inst_running(ip))
793 805 svcrunning = 1;
794 806 }
795 807
796 808 if (!svcrunning) {
797 809 for (ip = uu_list_first(sp->instances);
798 810 ip != NULL;
799 811 ip = uu_list_next(sp->instances, ip)) {
800 812 r = add_causes(svcp, ip);
801 813 if (r != 0) {
802 814 assert(r == ELOOP);
803 815 uu_list_walk_end(walk);
804 816 return (r);
805 817 }
806 818 }
807 819 }
808 820 }
809 821
810 822 uu_list_walk_end(walk);
811 823 return (0);
812 824 }
813 825
814 826 static int
815 827 process_reqany(inst_t *svcp, struct dependency_group *dg)
816 828 {
817 829 svc_t *sp;
818 830 inst_t *ip;
819 831 struct dependency *d;
820 832 int r;
821 833 uu_list_walk_t *walk;
822 834
823 835 for (d = uu_list_first(dg->entities);
824 836 d != NULL;
825 837 d = uu_list_next(dg->entities, d)) {
826 838 r = get_fmri(d->fmri, &sp, &ip);
827 839 switch (r) {
828 840 case 0:
829 841 break;
830 842
831 843 case EINVAL:
832 844 /* LINTED */
833 845 (void) fprintf(stderr, emsg_invalid_dep, svcp->svcname,
834 846 svcp->instname, d->fmri);
835 847 continue;
836 848
837 849 case ENOENT:
838 850 continue;
839 851
840 852 default:
841 853 bad_error("eval_svc_dep", r);
842 854 }
843 855
844 856 if (ip != NULL) {
845 857 if (inst_running(ip))
846 858 return (0);
847 859 continue;
848 860 }
849 861
850 862 for (ip = uu_list_first(sp->instances);
851 863 ip != NULL;
852 864 ip = uu_list_next(sp->instances, ip)) {
853 865 if (inst_running(ip))
854 866 return (0);
855 867 }
856 868 }
857 869
858 870 /*
859 871 * The dependency group is not satisfied. Add all unsatisfied members
860 872 * to the cause list.
861 873 */
862 874
863 875 walk = uu_list_walk_start(dg->entities, UU_WALK_ROBUST);
864 876 if (walk == NULL)
865 877 uu_die(emsg_nomem);
866 878
867 879 while ((d = uu_list_walk_next(walk)) != NULL) {
868 880 r = get_fmri(d->fmri, &sp, &ip);
869 881 switch (r) {
870 882 case 0:
871 883 break;
872 884
873 885 case ENOENT:
874 886 uu_list_remove(dg->entities, d);
875 887 r = uu_list_append(svcp->baddeps, d);
876 888 assert(r == 0);
877 889 continue;
878 890
879 891 case EINVAL:
880 892 /* Should have caught above. */
881 893 default:
882 894 bad_error("eval_svc_dep", r);
883 895 }
884 896
885 897 if (ip != NULL) {
886 898 if (inst_running(ip))
887 899 continue;
888 900 r = add_causes(svcp, ip);
889 901 if (r != 0) {
890 902 assert(r == ELOOP);
891 903 return (r);
892 904 }
893 905 continue;
894 906 }
895 907
896 908 for (ip = uu_list_first(sp->instances);
897 909 ip != NULL;
898 910 ip = uu_list_next(sp->instances, ip)) {
899 911 if (inst_running(ip))
900 912 continue;
901 913 r = add_causes(svcp, ip);
902 914 if (r != 0) {
903 915 assert(r == ELOOP);
904 916 return (r);
905 917 }
906 918 }
907 919 }
908 920
909 921 return (0);
910 922 }
911 923
912 924 static int
913 925 process_optall(inst_t *svcp, struct dependency_group *dg)
914 926 {
915 927 uu_list_walk_t *walk;
916 928 struct dependency *d;
917 929 int r;
918 930 inst_t *ip;
919 931 svc_t *sp;
920 932
921 933 walk = uu_list_walk_start(dg->entities, UU_WALK_ROBUST);
922 934 if (walk == NULL)
923 935 uu_die(emsg_nomem);
924 936
925 937 while ((d = uu_list_walk_next(walk)) != NULL) {
926 938 r = get_fmri(d->fmri, &sp, &ip);
927 939
928 940 switch (r) {
929 941 case 0:
930 942 break;
931 943
932 944 case EINVAL:
933 945 /* LINTED */
934 946 (void) fprintf(stderr, emsg_invalid_dep, svcp->svcname,
935 947 svcp->instname, d->fmri);
936 948 continue;
937 949
938 950 case ENOENT:
939 951 continue;
940 952
941 953 default:
942 954 bad_error("get_fmri", r);
943 955 }
944 956
945 957 if (ip != NULL) {
946 958 if ((ip->enabled != 0) && !inst_running_or_maint(ip)) {
947 959 r = add_causes(svcp, ip);
948 960 if (r != 0) {
949 961 assert(r == ELOOP);
950 962 uu_list_walk_end(walk);
951 963 return (r);
952 964 }
953 965 }
954 966 continue;
955 967 }
956 968
957 969 for (ip = uu_list_first(sp->instances);
958 970 ip != NULL;
959 971 ip = uu_list_next(sp->instances, ip)) {
960 972 if ((ip->enabled != 0) && !inst_running_or_maint(ip)) {
961 973 r = add_causes(svcp, ip);
962 974 if (r != 0) {
963 975 assert(r == ELOOP);
964 976 uu_list_walk_end(walk);
965 977 return (r);
966 978 }
967 979 }
968 980 }
969 981 }
970 982
971 983 uu_list_walk_end(walk);
972 984 return (0);
973 985 }
974 986
975 987 static int
976 988 process_excall(inst_t *svcp, struct dependency_group *dg)
977 989 {
978 990 struct dependency *d;
979 991 int r;
980 992 svc_t *sp;
981 993 inst_t *ip;
982 994
983 995 for (d = uu_list_first(dg->entities);
984 996 d != NULL;
985 997 d = uu_list_next(dg->entities, d)) {
986 998 r = get_fmri(d->fmri, &sp, &ip);
987 999
988 1000 switch (r) {
989 1001 case 0:
990 1002 break;
991 1003
992 1004 case EINVAL:
993 1005 /* LINTED */
994 1006 (void) fprintf(stderr, emsg_invalid_dep, svcp->svcname,
995 1007 svcp->instname, d->fmri);
996 1008 continue;
997 1009
998 1010 case ENOENT:
999 1011 continue;
1000 1012
1001 1013 default:
1002 1014 bad_error("eval_svc_dep", r);
1003 1015 }
1004 1016
1005 1017 if (ip != NULL) {
1006 1018 if (inst_running(ip)) {
1007 1019 r = add_causes(svcp, ip);
1008 1020 if (r != 0) {
1009 1021 assert(r == ELOOP);
1010 1022 return (r);
1011 1023 }
1012 1024 }
1013 1025 continue;
1014 1026 }
1015 1027
1016 1028 for (ip = uu_list_first(sp->instances);
1017 1029 ip != NULL;
1018 1030 ip = uu_list_next(sp->instances, ip)) {
1019 1031 if (inst_running(ip)) {
1020 1032 r = add_causes(svcp, ip);
1021 1033 if (r != 0) {
1022 1034 assert(r == ELOOP);
1023 1035 return (r);
1024 1036 }
1025 1037 }
1026 1038 }
1027 1039 }
1028 1040
1029 1041 return (0);
1030 1042 }
1031 1043
1032 1044 static int
1033 1045 process_svc_dg(inst_t *svcp, struct dependency_group *dg)
1034 1046 {
1035 1047 switch (dg->grouping) {
1036 1048 case DGG_REQALL:
1037 1049 return (process_reqall(svcp, dg));
1038 1050
1039 1051 case DGG_REQANY:
1040 1052 return (process_reqany(svcp, dg));
1041 1053
1042 1054 case DGG_OPTALL:
1043 1055 return (process_optall(svcp, dg));
1044 1056
1045 1057 case DGG_EXCALL:
1046 1058 return (process_excall(svcp, dg));
1047 1059
1048 1060 default:
1049 1061 #ifndef NDEBUG
1050 1062 (void) fprintf(stderr,
1051 1063 "%s:%d: Unknown dependency grouping %d.\n", __FILE__,
1052 1064 __LINE__, dg->grouping);
1053 1065 #endif
1054 1066 abort();
1055 1067 /* NOTREACHED */
1056 1068 }
1057 1069 }
1058 1070
1059 1071 /*
1060 1072 * Returns
1061 1073 * EINVAL - fmri is not a valid FMRI
1062 1074 * 0 - the file indicated by fmri is missing
1063 1075 * 1 - the file indicated by fmri is present
1064 1076 */
1065 1077 static int
1066 1078 eval_file_dep(const char *fmri)
1067 1079 {
1068 1080 const char *path;
1069 1081 struct stat st;
1070 1082
1071 1083 if (strncmp(fmri, "file:", sizeof ("file:") - 1) != 0)
1072 1084 return (EINVAL);
1073 1085
1074 1086 path = fmri + (sizeof ("file:") - 1);
1075 1087
1076 1088 if (path[0] != '/')
1077 1089 return (EINVAL);
1078 1090
1079 1091 if (path[1] == '/') {
1080 1092 path += 2;
1081 1093 if (strncmp(path, "localhost/", sizeof ("localhost/") - 1) == 0)
1082 1094 path += sizeof ("localhost") - 1;
1083 1095 else if (path[0] != '/')
1084 1096 return (EINVAL);
1085 1097 }
1086 1098
1087 1099 return (stat(path, &st) == 0 ? 1 : 0);
1088 1100 }
1089 1101
1090 1102 static void
1091 1103 process_file_dg(inst_t *svcp, struct dependency_group *dg)
1092 1104 {
1093 1105 uu_list_walk_t *walk;
1094 1106 struct dependency *d, **deps;
1095 1107 int r, i = 0, any_satisfied = 0;
1096 1108
1097 1109 if (dg->grouping == DGG_REQANY) {
1098 1110 deps = calloc(uu_list_numnodes(dg->entities), sizeof (*deps));
1099 1111 if (deps == NULL)
1100 1112 uu_die(emsg_nomem);
1101 1113 }
1102 1114
1103 1115 walk = uu_list_walk_start(dg->entities, UU_WALK_ROBUST);
1104 1116 if (walk == NULL)
1105 1117 uu_die(emsg_nomem);
1106 1118
1107 1119 while ((d = uu_list_walk_next(walk)) != NULL) {
1108 1120 r = eval_file_dep(d->fmri);
1109 1121 if (r == EINVAL) {
1110 1122 /* LINTED */
1111 1123 (void) fprintf(stderr, emsg_invalid_dep, svcp->svcname,
1112 1124 svcp->instname, d->fmri);
1113 1125 continue;
1114 1126 }
1115 1127
1116 1128 assert(r == 0 || r == 1);
1117 1129
1118 1130 switch (dg->grouping) {
1119 1131 case DGG_REQALL:
1120 1132 case DGG_OPTALL:
1121 1133 if (r == 0) {
1122 1134 uu_list_remove(dg->entities, d);
1123 1135 r = uu_list_append(svcp->baddeps, d);
1124 1136 assert(r == 0);
1125 1137 }
1126 1138 break;
1127 1139
1128 1140 case DGG_REQANY:
1129 1141 if (r == 1)
1130 1142 any_satisfied = 1;
1131 1143 else
1132 1144 deps[i++] = d;
1133 1145 break;
1134 1146
1135 1147 case DGG_EXCALL:
1136 1148 if (r == 1) {
1137 1149 uu_list_remove(dg->entities, d);
1138 1150 r = uu_list_append(svcp->baddeps, d);
1139 1151 assert(r == 0);
1140 1152 }
1141 1153 break;
1142 1154
1143 1155 default:
1144 1156 #ifndef NDEBUG
1145 1157 (void) fprintf(stderr, "%s:%d: Unknown grouping %d.\n",
1146 1158 __FILE__, __LINE__, dg->grouping);
1147 1159 #endif
1148 1160 abort();
1149 1161 }
1150 1162 }
1151 1163
1152 1164 uu_list_walk_end(walk);
1153 1165
1154 1166 if (dg->grouping != DGG_REQANY)
1155 1167 return;
1156 1168
1157 1169 if (!any_satisfied) {
1158 1170 while (--i >= 0) {
1159 1171 uu_list_remove(dg->entities, deps[i]);
1160 1172 r = uu_list_append(svcp->baddeps, deps[i]);
1161 1173 assert(r == 0);
1162 1174 }
1163 1175 }
1164 1176
1165 1177 free(deps);
1166 1178 }
1167 1179
1168 1180 /*
1169 1181 * Populate the causes list of svcp. This function should not return with
1170 1182 * causes empty.
1171 1183 */
1172 1184 static int
1173 1185 determine_causes(inst_t *svcp, void *canfailp)
1174 1186 {
1175 1187 struct dependency_group *dg;
1176 1188 int r;
1177 1189
1178 1190 if (svcp->active) {
1179 1191 (void) fprintf(stderr, gettext("Dependency cycle detected:\n"
1180 1192 " svc:/%s:%s\n"), svcp->svcname, svcp->instname);
1181 1193 return ((int)canfailp != 0 ? UU_WALK_ERROR : UU_WALK_NEXT);
1182 1194 }
1183 1195
1184 1196 if (svcp->causes != NULL)
1185 1197 return (UU_WALK_NEXT);
1186 1198
1187 1199 svcp->causes = uu_list_create(svcptrs, svcp, UU_LIST_DEBUG);
1188 1200 svcp->baddeps = uu_list_create(deps, svcp, UU_LIST_DEBUG);
1189 1201 if (svcp->causes == NULL || svcp->baddeps == NULL)
1190 1202 uu_die(emsg_nomem);
1191 1203
1192 1204 if (inst_running(svcp) ||
1193 1205 strcmp(svcp->state, SCF_STATE_STRING_UNINIT) == 0) {
1194 1206 /*
1195 1207 * If we're running, add a self-pointer in case we're
1196 1208 * excluding another service.
1197 1209 */
1198 1210 add_svcptr(svcp->causes, svcp);
1199 1211 return (UU_WALK_NEXT);
1200 1212 }
1201 1213
1202 1214 if (strcmp(svcp->state, SCF_STATE_STRING_MAINT) == 0) {
1203 1215 add_svcptr(svcp->causes, svcp);
1204 1216 add_svcptr(g_causes, svcp);
1205 1217 return (UU_WALK_NEXT);
1206 1218 }
1207 1219
1208 1220 if (strcmp(svcp->state, SCF_STATE_STRING_DISABLED) == 0) {
1209 1221 add_svcptr(svcp->causes, svcp);
1210 1222 if (svcp->enabled != 0)
1211 1223 add_svcptr(g_causes, svcp);
1212 1224
1213 1225 return (UU_WALK_NEXT);
1214 1226 }
1215 1227
1216 1228 if (strcmp(svcp->state, SCF_STATE_STRING_OFFLINE) != 0) {
1217 1229 (void) fprintf(stderr,
1218 1230 gettext("svc:/%s:%s has invalid state \"%s\".\n"),
1219 1231 svcp->svcname, svcp->instname, svcp->state);
1220 1232 add_svcptr(svcp->causes, svcp);
1221 1233 add_svcptr(g_causes, svcp);
1222 1234 return (UU_WALK_NEXT);
1223 1235 }
1224 1236
1225 1237 if (strcmp(svcp->next_state, SCF_STATE_STRING_NONE) != 0) {
1226 1238 add_svcptr(svcp->causes, svcp);
1227 1239 add_svcptr(g_causes, svcp);
1228 1240 return (UU_WALK_NEXT);
1229 1241 }
1230 1242
1231 1243 svcp->active = 1;
1232 1244
1233 1245 /*
1234 1246 * Dependency analysis can add elements to our baddeps list (absent
1235 1247 * dependency, unsatisfied file dependency), or to our cause list
1236 1248 * (unsatisfied dependency).
1237 1249 */
1238 1250 for (dg = uu_list_first(svcp->dependencies);
1239 1251 dg != NULL;
1240 1252 dg = uu_list_next(svcp->dependencies, dg)) {
1241 1253 if (strcmp(dg->type, "path") == 0) {
1242 1254 process_file_dg(svcp, dg);
1243 1255 } else if (strcmp(dg->type, "service") == 0) {
1244 1256 int r;
1245 1257
1246 1258 r = process_svc_dg(svcp, dg);
1247 1259 if (r != 0) {
1248 1260 assert(r == ELOOP);
1249 1261 svcp->active = 0;
1250 1262 return ((int)canfailp != 0 ?
1251 1263 UU_WALK_ERROR : UU_WALK_NEXT);
1252 1264 }
1253 1265 } else {
1254 1266 (void) fprintf(stderr, gettext("svc:/%s:%s has "
1255 1267 "dependency group with invalid type \"%s\".\n"),
1256 1268 svcp->svcname, svcp->instname, dg->type);
1257 1269 }
1258 1270 }
1259 1271
1260 1272 if (uu_list_numnodes(svcp->causes) == 0) {
1261 1273 if (uu_list_numnodes(svcp->baddeps) > 0) {
1262 1274 add_svcptr(g_causes, svcp);
1263 1275 add_svcptr(svcp->causes, svcp);
1264 1276 } else {
1265 1277 inst_t *restarter;
1266 1278
1267 1279 r = get_fmri(svcp->restarter, NULL, &restarter);
1268 1280 if (r == 0 && !inst_running(restarter)) {
1269 1281 r = add_causes(svcp, restarter);
1270 1282 if (r != 0) {
1271 1283 assert(r == ELOOP);
1272 1284 svcp->active = 0;
1273 1285 return ((int)canfailp != 0 ?
1274 1286 UU_WALK_ERROR : UU_WALK_NEXT);
1275 1287 }
1276 1288 } else {
1277 1289 svcp->restarter_bad = r;
1278 1290 add_svcptr(svcp->causes, svcp);
1279 1291 add_svcptr(g_causes, svcp);
1280 1292 }
1281 1293 }
1282 1294 }
1283 1295
1284 1296 assert(uu_list_numnodes(svcp->causes) > 0);
1285 1297
1286 1298 svcp->active = 0;
1287 1299 return (UU_WALK_NEXT);
1288 1300 }
1289 1301
1290 1302 static void
1291 1303 determine_all_causes(void)
1292 1304 {
1293 1305 svc_t *svcp;
1294 1306 int i;
1295 1307
1296 1308 for (i = 0; i < SVC_HASH_NBUCKETS; ++i) {
1297 1309 for (svcp = services[i]; svcp != NULL; svcp = svcp->next)
1298 1310 (void) uu_list_walk(svcp->instances,
1299 1311 (uu_walk_fn_t *)determine_causes, 0, 0);
1300 1312 }
1301 1313 }
1302 1314
1303 1315 /*
1304 1316 * Returns
1305 1317 * 0 - success
1306 1318 * ELOOP - dependency cycle detected
1307 1319 */
1308 1320 static int
1309 1321 determine_impact(inst_t *ip)
1310 1322 {
1311 1323 struct svcptr *idsp, *spp, *copy;
1312 1324 uu_list_index_t idx;
1313 1325
1314 1326 if (ip->active) {
1315 1327 (void) fprintf(stderr, gettext("Dependency cycle detected:\n"
1316 1328 " svc:/%s:%s\n"), ip->svcname, ip->instname);
1317 1329 return (ELOOP);
1318 1330 }
1319 1331
1320 1332 if (ip->impact != NULL)
1321 1333 return (0);
1322 1334
1323 1335 ip->impact = uu_list_create(svcptrs, ip, UU_LIST_DEBUG);
1324 1336 if (ip->impact == NULL)
1325 1337 uu_die(emsg_nomem);
1326 1338 ip->active = 1;
1327 1339
1328 1340 for (idsp = uu_list_first(ip->impact_dependents);
1329 1341 idsp != NULL;
1330 1342 idsp = uu_list_next(ip->impact_dependents, idsp)) {
1331 1343 if (determine_impact(idsp->svcp) != 0) {
1332 1344 (void) fprintf(stderr, " svc:/%s:%s\n",
1333 1345 ip->svcname, ip->instname);
1334 1346 return (ELOOP);
1335 1347 }
1336 1348
1337 1349 add_svcptr(ip->impact, idsp->svcp);
1338 1350
1339 1351 for (spp = uu_list_first(idsp->svcp->impact);
1340 1352 spp != NULL;
1341 1353 spp = uu_list_next(idsp->svcp->impact, spp)) {
1342 1354 if (uu_list_find(ip->impact, spp, NULL, &idx) != NULL)
1343 1355 continue;
1344 1356
1345 1357 copy = safe_malloc(sizeof (*copy));
1346 1358 copy->svcp = spp->svcp;
1347 1359 copy->next_hop = NULL;
1348 1360 uu_list_node_init(copy, ©->node, svcptrs);
1349 1361 uu_list_insert(ip->impact, copy, idx);
1350 1362 }
1351 1363 }
1352 1364
1353 1365 ip->active = 0;
1354 1366 return (0);
1355 1367 }
1356 1368
1357 1369 /*
1358 1370 * Printing routines.
1359 1371 */
1360 1372
1361 1373 static void
1362 1374 check_msgbase(void)
1363 1375 {
1364 1376 if (scf_handle_decode_fmri(h, SCF_SERVICE_STARTD, NULL, NULL, g_inst,
1365 1377 NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0) {
1366 1378 if (scf_error() != SCF_ERROR_NOT_FOUND)
1367 1379 scfdie();
1368 1380
1369 1381 return;
1370 1382 }
1371 1383
1372 1384 if (scf_instance_get_pg_composed(g_inst, NULL, "msg", g_pg) != 0) {
1373 1385 switch (scf_error()) {
1374 1386 case SCF_ERROR_NOT_FOUND:
1375 1387 case SCF_ERROR_DELETED:
1376 1388 return;
1377 1389
1378 1390 default:
1379 1391 scfdie();
1380 1392 }
1381 1393 }
1382 1394
1383 1395 if (scf_pg_get_property(g_pg, "base", g_prop) != 0) {
1384 1396 switch (scf_error()) {
1385 1397 case SCF_ERROR_NOT_FOUND:
1386 1398 case SCF_ERROR_DELETED:
1387 1399 return;
1388 1400
1389 1401 default:
1390 1402 scfdie();
1391 1403 }
1392 1404 }
1393 1405
1394 1406 if (scf_property_get_value(g_prop, g_val) != 0) {
1395 1407 switch (scf_error()) {
1396 1408 case SCF_ERROR_NOT_FOUND:
1397 1409 case SCF_ERROR_CONSTRAINT_VIOLATED:
1398 1410 case SCF_ERROR_PERMISSION_DENIED:
1399 1411 g_msgbase = NULL;
1400 1412 return;
1401 1413
1402 1414 case SCF_ERROR_DELETED:
1403 1415 return;
1404 1416
1405 1417 default:
1406 1418 scfdie();
1407 1419 }
1408 1420 }
1409 1421
1410 1422 if (scf_value_get_astring(g_val, g_value, g_value_sz) < 0) {
1411 1423 if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
1412 1424 scfdie();
1413 1425 return;
1414 1426 }
1415 1427
1416 1428 g_msgbase = safe_strdup(g_value);
1417 1429 }
1418 1430
1419 1431 static void
1420 1432 determine_summary(inst_t *ip)
1421 1433 {
1422 1434 if (ip->summary != NULL)
1423 1435 return;
1424 1436
1425 1437 if (inst_running(ip)) {
1426 1438 ip->summary = gettext("is running.");
1427 1439 return;
1428 1440 }
1429 1441
1430 1442 if (strcmp(ip->state, SCF_STATE_STRING_UNINIT) == 0) {
1431 1443 ip->summary = gettext("is uninitialized.");
1432 1444 } else if (strcmp(ip->state, SCF_STATE_STRING_DISABLED) == 0) {
1433 1445 if (!ip->temporary)
1434 1446 ip->summary = gettext("is disabled.");
1435 1447 else
1436 1448 ip->summary = gettext("is temporarily disabled.");
1437 1449 } else if (strcmp(ip->state, SCF_STATE_STRING_OFFLINE) == 0) {
1438 1450 if (uu_list_numnodes(ip->baddeps) != 0)
1439 1451 ip->summary = gettext("has missing dependencies.");
1440 1452 else if (strcmp(ip->next_state, SCF_STATE_STRING_ONLINE) == 0)
1441 1453 ip->summary = gettext("is starting.");
1442 1454 else
1443 1455 ip->summary = gettext("is offline.");
1444 1456 } else if (strcmp(ip->state, SCF_STATE_STRING_MAINT) == 0) {
1445 1457 if (strcmp(ip->aux_state, "administrative_request") == 0) {
1446 1458 ip->summary = gettext("was taken down for maintenace "
1447 1459 "by an administrator.");
1448 1460 } else if (strcmp(ip->aux_state, "dependency_cycle") == 0) {
1449 1461 ip->summary = gettext("completed a dependency cycle.");
1450 1462 } else if (strcmp(ip->aux_state, "fault_threshold_reached") ==
1451 1463 0) {
1452 1464 ip->summary = gettext("is not running because "
1453 1465 "a method failed repeatedly.");
1454 1466 } else if (strcmp(ip->aux_state, "invalid_dependency") == 0) {
1455 1467 ip->summary = gettext("has an invalid dependency.");
1456 1468 } else if (strcmp(ip->aux_state, "invalid_restarter") == 0) {
1457 1469 ip->summary = gettext("has an invalid restarter.");
1458 1470 } else if (strcmp(ip->aux_state, "method_failed") == 0) {
1459 1471 ip->summary = gettext("is not running because "
1460 1472 "a method failed.");
1461 1473 } else if (strcmp(ip->aux_state, "none") == 0) {
1462 1474 ip->summary =
1463 1475 gettext("is not running for an unknown reason.");
1464 1476 } else if (strcmp(ip->aux_state, "restarting_too_quickly") ==
1465 1477 0) {
1466 1478 ip->summary = gettext("was restarting too quickly.");
1467 1479 } else {
1468 1480 ip->summary = gettext("requires maintenance.");
1469 1481 }
1470 1482 } else {
1471 1483 ip->summary = gettext("is in an invalid state.");
1472 1484 }
1473 1485 }
1474 1486
1475 1487 static void
1476 1488 print_method_failure(const inst_t *ip, const char **dcp)
1477 1489 {
1478 1490 char buf[50];
1479 1491 int stat = ip->start_method_waitstatus;
1480 1492
1481 1493 if (stat != 0) {
1482 1494 if (WIFEXITED(stat)) {
1483 1495 if (WEXITSTATUS(stat) == SMF_EXIT_ERR_CONFIG) {
1484 1496 (void) strlcpy(buf, gettext(
1485 1497 "exited with $SMF_EXIT_ERR_CONFIG"),
1486 1498 sizeof (buf));
1487 1499 } else if (WEXITSTATUS(stat) == SMF_EXIT_ERR_FATAL) {
1488 1500 (void) strlcpy(buf, gettext(
1489 1501 "exited with $SMF_EXIT_ERR_FATAL"),
1490 1502 sizeof (buf));
1491 1503 } else {
1492 1504 (void) snprintf(buf, sizeof (buf),
1493 1505 gettext("exited with status %d"),
1494 1506 WEXITSTATUS(stat));
1495 1507 }
1496 1508 } else if (WIFSIGNALED(stat)) {
1497 1509 if (WCOREDUMP(stat)) {
1498 1510 if (strsignal(WTERMSIG(stat)) != NULL)
1499 1511 (void) snprintf(buf, sizeof (buf),
1500 1512 gettext("dumped core on %s (%d)"),
1501 1513 strsignal(WTERMSIG(stat)),
1502 1514 WTERMSIG(stat));
1503 1515 else
1504 1516 (void) snprintf(buf, sizeof (buf),
1505 1517 gettext("dumped core signal %d"),
1506 1518 WTERMSIG(stat));
1507 1519 } else {
1508 1520 if (strsignal(WTERMSIG(stat)) != NULL) {
1509 1521 (void) snprintf(buf, sizeof (buf),
1510 1522 gettext("died on %s (%d)"),
1511 1523 strsignal(WTERMSIG(stat)),
1512 1524 WTERMSIG(stat));
1513 1525 } else {
1514 1526 (void) snprintf(buf, sizeof (buf),
1515 1527 gettext("died on signal %d"),
1516 1528 WTERMSIG(stat));
1517 1529 }
1518 1530 }
1519 1531 } else {
1520 1532 goto fail;
1521 1533 }
1522 1534
1523 1535 if (strcmp(ip->aux_state, "fault_threshold_reached") != 0)
1524 1536 (void) printf(gettext("Reason: Start method %s.\n"),
1525 1537 buf);
1526 1538 else
1527 1539 (void) printf(gettext("Reason: "
1528 1540 "Start method failed repeatedly, last %s.\n"), buf);
1529 1541 *dcp = DC_STARTFAIL;
1530 1542 } else {
1531 1543 fail:
1532 1544 if (strcmp(ip->aux_state, "fault_threshold_reached") == 0)
1533 1545 (void) puts(gettext(
1534 1546 "Reason: Method failed repeatedly."));
1535 1547 else
1536 1548 (void) puts(gettext("Reason: Method failed."));
1537 1549 *dcp = DC_METHFAIL;
1538 1550 }
1539 1551 }
1540 1552
1541 1553 static void
1542 1554 print_dependency_reasons(const inst_t *svcp, int verbose)
1543 1555 {
1544 1556 struct dependency *d;
1545 1557 struct svcptr *spp;
1546 1558 const char *dc;
1547 1559
1548 1560 /*
1549 1561 * If we couldn't determine why the service is offline, then baddeps
1550 1562 * will be empty and causes will have a pointer to self.
1551 1563 */
1552 1564 if (uu_list_numnodes(svcp->baddeps) == 0 &&
1553 1565 uu_list_numnodes(svcp->causes) == 1) {
1554 1566 spp = uu_list_first(svcp->causes);
1555 1567 if (spp->svcp == svcp) {
1556 1568 switch (svcp->restarter_bad) {
1557 1569 case 0:
1558 1570 (void) puts(gettext("Reason: Unknown."));
1559 1571 dc = DC_UNKNOWN;
1560 1572 break;
1561 1573
1562 1574 case EINVAL:
1563 1575 (void) printf(gettext("Reason: "
1564 1576 "Restarter \"%s\" is invalid.\n"),
1565 1577 svcp->restarter);
1566 1578 dc = DC_RSTRINVALID;
1567 1579 break;
1568 1580
1569 1581 case ENOENT:
1570 1582 (void) printf(gettext("Reason: "
1571 1583 "Restarter \"%s\" does not exist.\n"),
1572 1584 svcp->restarter);
1573 1585 dc = DC_RSTRABSENT;
1574 1586 break;
1575 1587
1576 1588 default:
1577 1589 #ifndef NDEBUG
1578 1590 (void) fprintf(stderr, "%s:%d: Bad "
1579 1591 "restarter_bad value %d. Aborting.\n",
1580 1592 __FILE__, __LINE__, svcp->restarter_bad);
1581 1593 #endif
1582 1594 abort();
1583 1595 }
1584 1596
1585 1597 if (g_msgbase)
1586 1598 (void) printf(gettext(" See: %s%s\n"),
1587 1599 g_msgbase, dc);
1588 1600 return;
1589 1601 }
1590 1602 }
1591 1603
1592 1604 for (d = uu_list_first(svcp->baddeps);
1593 1605 d != NULL;
1594 1606 d = uu_list_next(svcp->baddeps, d)) {
1595 1607 (void) printf(gettext("Reason: Dependency %s is absent.\n"),
1596 1608 d->fmri);
1597 1609 if (g_msgbase)
1598 1610 (void) printf(gettext(" See: %s%s\n"), g_msgbase,
1599 1611 DC_DEPABSENT);
1600 1612 }
1601 1613
1602 1614 for (spp = uu_list_first(svcp->causes);
1603 1615 spp != NULL && spp->svcp != svcp;
1604 1616 spp = uu_list_next(svcp->causes, spp)) {
1605 1617 determine_summary(spp->svcp);
1606 1618
1607 1619 if (inst_running(spp->svcp)) {
1608 1620 (void) printf(gettext("Reason: "
1609 1621 "Service svc:/%s:%s is running.\n"),
1610 1622 spp->svcp->svcname, spp->svcp->instname);
1611 1623 dc = DC_DEPRUNNING;
1612 1624 } else {
1613 1625 if (snprintf(NULL, 0,
1614 1626 gettext("Reason: Service svc:/%s:%s %s"),
1615 1627 spp->svcp->svcname, spp->svcp->instname,
1616 1628 spp->svcp->summary) <= 80) {
1617 1629 (void) printf(gettext(
1618 1630 "Reason: Service svc:/%s:%s %s\n"),
1619 1631 spp->svcp->svcname, spp->svcp->instname,
1620 1632 spp->svcp->summary);
1621 1633 } else {
1622 1634 (void) printf(gettext(
1623 1635 "Reason: Service svc:/%s:%s\n"
1624 1636 " %s\n"), spp->svcp->svcname,
1625 1637 spp->svcp->instname, spp->svcp->summary);
1626 1638 }
1627 1639
1628 1640 dc = DC_DEPOTHER;
1629 1641 }
1630 1642
1631 1643 if (g_msgbase != NULL)
1632 1644 (void) printf(gettext(" See: %s%s\n"), g_msgbase, dc);
1633 1645
1634 1646 if (verbose) {
1635 1647 inst_t *pp;
1636 1648 int indent;
1637 1649
1638 1650 (void) printf(gettext(" Path: svc:/%s:%s\n"),
1639 1651 svcp->svcname, svcp->instname);
1640 1652
1641 1653 indent = 1;
1642 1654 for (pp = spp->next_hop; ; ) {
1643 1655 struct svcptr *tmp;
1644 1656
1645 1657 (void) printf(gettext("%6s %*ssvc:/%s:%s\n"),
1646 1658 "", indent++ * 2, "", pp->svcname,
1647 1659 pp->instname);
1648 1660
1649 1661 if (pp == spp->svcp)
1650 1662 break;
1651 1663
1652 1664 /* set pp to next_hop of cause with same svcp */
1653 1665 tmp = uu_list_find(pp->causes, spp, NULL, NULL);
1654 1666 pp = tmp->next_hop;
1655 1667 }
1656 1668 }
1657 1669 }
1658 1670 }
1659 1671
1660 1672 static void
1661 1673 print_logs(scf_instance_t *inst)
1662 1674 {
1663 1675 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, g_pg) != 0)
1664 1676 return;
1665 1677
1666 1678 if (pg_get_single_val(g_pg, SCF_PROPERTY_ALT_LOGFILE,
1667 1679 SCF_TYPE_ASTRING, (void *)g_value, g_value_sz, 0) == 0)
1668 1680 (void) printf(gettext(" See: %s\n"), g_value);
1669 1681
1670 1682 if (pg_get_single_val(g_pg, SCF_PROPERTY_LOGFILE,
1671 1683 SCF_TYPE_ASTRING, (void *)g_value, g_value_sz, 0) == 0)
1672 1684 (void) printf(gettext(" See: %s\n"), g_value);
1673 1685 }
1674 1686
1675 1687 static void
1676 1688 print_aux_fmri_logs(const char *fmri)
1677 1689 {
1678 1690 scf_instance_t *scf_inst = scf_instance_create(h);
1679 1691 if (scf_inst == NULL)
1680 1692 return;
1681 1693
1682 1694 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, scf_inst,
1683 1695 NULL, NULL, SCF_DECODE_FMRI_EXACT) == 0)
1684 1696 print_logs(scf_inst);
1685 1697
1686 1698 scf_instance_destroy(scf_inst);
1687 1699 }
1688 1700
1689 1701 static void
1690 1702 print_reasons(const inst_t *svcp, int verbose)
1691 1703 {
1692 1704 int r;
1693 1705 const char *dc = NULL;
1694 1706
1695 1707 if (strcmp(svcp->state, SCF_STATE_STRING_ONLINE) == 0)
1696 1708 return;
1697 1709
1698 1710 if (strcmp(svcp->state, SCF_STATE_STRING_UNINIT) == 0) {
1699 1711 inst_t *rsp;
1700 1712
1701 1713 r = get_fmri(svcp->restarter, NULL, &rsp);
1702 1714 switch (r) {
1703 1715 case 0:
1704 1716 if (rsp != NULL)
1705 1717 break;
1706 1718 /* FALLTHROUGH */
1707 1719
1708 1720 case EINVAL:
1709 1721 (void) printf(gettext("Reason: "
1710 1722 "Restarter \"%s\" is invalid.\n"), svcp->restarter);
1711 1723 dc = DC_RSTRINVALID;
1712 1724 goto diagcode;
1713 1725
1714 1726 case ENOENT:
1715 1727 (void) printf(gettext("Reason: "
1716 1728 "Restarter \"%s\" does not exist.\n"),
1717 1729 svcp->restarter);
1718 1730 dc = DC_RSTRABSENT;
1719 1731 goto diagcode;
1720 1732
1721 1733 default:
1722 1734 bad_error("get_fmri", r);
1723 1735 }
1724 1736
1725 1737 if (inst_running(rsp)) {
1726 1738 (void) printf(gettext("Reason: Restarter %s "
1727 1739 "has not initialized service state.\n"),
1728 1740 svcp->restarter);
↓ open down ↓ |
1201 lines elided |
↑ open up ↑ |
1729 1741 dc = DC_UNINIT;
1730 1742 } else {
1731 1743 (void) printf(gettext(
1732 1744 "Reason: Restarter %s is not running.\n"),
1733 1745 svcp->restarter);
1734 1746 dc = DC_RSTRDEAD;
1735 1747 }
1736 1748
1737 1749 } else if (strcmp(svcp->state, SCF_STATE_STRING_DISABLED) == 0) {
1738 1750 if (!svcp->temporary) {
1739 - (void) puts(gettext(
1740 - "Reason: Disabled by an administrator."));
1751 + if (svcp->comment[0] != '\0') {
1752 + (void) printf(gettext("Reason: Disabled by "
1753 + "an administrator: %s\n"), svcp->comment);
1754 + } else {
1755 + (void) printf(gettext("Reason: Disabled by "
1756 + "an administrator.\n"));
1757 + }
1741 1758 dc = DC_DISABLED;
1742 1759 } else {
1743 - (void) puts(gettext("Reason: "
1744 - "Temporarily disabled by an administrator."));
1760 + if (svcp->comment[0] != '\0') {
1761 + (void) printf(gettext("Reason: Temporarily "
1762 + "disabled by an administrator: %s\n"),
1763 + svcp->comment);
1764 + } else {
1765 + (void) printf(gettext("Reason: Temporarily "
1766 + "disabled by an administrator.\n"));
1767 + }
1745 1768 dc = DC_TEMPDISABLED;
1746 1769 }
1747 1770
1748 1771 } else if (strcmp(svcp->state, SCF_STATE_STRING_MAINT) == 0) {
1749 1772 if (strcmp(svcp->aux_state, "administrative_request") == 0) {
1750 1773 (void) puts(gettext("Reason: "
1751 1774 "Maintenance requested by an administrator."));
1752 1775 dc = DC_ADMINMAINT;
1753 1776 } else if (strcmp(svcp->aux_state, "dependency_cycle") == 0) {
1754 1777 (void) puts(gettext(
1755 1778 "Reason: Completes a dependency cycle."));
1756 1779 dc = DC_DEPCYCLE;
1757 1780 } else if (strcmp(svcp->aux_state, "fault_threshold_reached") ==
1758 1781 0) {
1759 1782 print_method_failure(svcp, &dc);
1760 1783 } else if (strcmp(svcp->aux_state, "service_request") == 0) {
1761 1784 if (svcp->aux_fmri) {
1762 1785 (void) printf(gettext("Reason: Maintenance "
1763 1786 "requested by \"%s\"\n"), svcp->aux_fmri);
1764 1787 print_aux_fmri_logs(svcp->aux_fmri);
1765 1788 } else {
1766 1789 (void) puts(gettext("Reason: Maintenance "
1767 1790 "requested by another service."));
1768 1791 }
1769 1792 dc = DC_SVCREQMAINT;
1770 1793 } else if (strcmp(svcp->aux_state, "invalid_dependency") == 0) {
1771 1794 (void) puts(gettext("Reason: Has invalid dependency."));
1772 1795 dc = DC_INVALIDDEP;
1773 1796 } else if (strcmp(svcp->aux_state, "invalid_restarter") == 0) {
1774 1797 (void) printf(gettext("Reason: Restarter \"%s\" is "
1775 1798 "invalid.\n"), svcp->restarter);
1776 1799 dc = DC_RSTRINVALID;
1777 1800 } else if (strcmp(svcp->aux_state, "method_failed") == 0) {
1778 1801 print_method_failure(svcp, &dc);
1779 1802 } else if (strcmp(svcp->aux_state, "restarting_too_quickly") ==
1780 1803 0) {
1781 1804 (void) puts(gettext("Reason: Restarting too quickly."));
1782 1805 dc = DC_TOOQUICKLY;
1783 1806 } else if (strcmp(svcp->aux_state, "none") == 0) {
1784 1807 (void) printf(gettext(
1785 1808 "Reason: Restarter %s gave no explanation.\n"),
1786 1809 svcp->restarter);
1787 1810 dc = DC_NONE;
1788 1811 } else {
1789 1812 (void) puts(gettext("Reason: Unknown."));
1790 1813 dc = DC_UNKNOWN;
1791 1814 }
1792 1815
1793 1816 } else if (strcmp(svcp->state, SCF_STATE_STRING_OFFLINE) == 0) {
1794 1817 if (strcmp(svcp->next_state, SCF_STATE_STRING_ONLINE) == 0) {
1795 1818 (void) puts(gettext(
1796 1819 "Reason: Start method is running."));
1797 1820 dc = DC_STARTING;
1798 1821 } else if (strcmp(svcp->next_state, SCF_STATE_STRING_NONE) ==
1799 1822 0) {
1800 1823 print_dependency_reasons(svcp, verbose);
1801 1824 /* Function prints diagcodes. */
1802 1825 return;
1803 1826 } else {
1804 1827 (void) printf(gettext(
1805 1828 "Reason: Transitioning to state %s.\n"),
1806 1829 svcp->next_state);
1807 1830 dc = DC_TRANSITION;
1808 1831 }
1809 1832
1810 1833 } else if (strcmp(svcp->state, SCF_STATE_STRING_DEGRADED) == 0) {
1811 1834 (void) puts(gettext("Reason: Degraded by an administrator."));
1812 1835 dc = DC_ADMINDEGR;
1813 1836
1814 1837 } else {
1815 1838 (void) printf(gettext("Reason: Not in valid state (%s).\n"),
1816 1839 svcp->state);
1817 1840 dc = DC_INVALIDSTATE;
1818 1841 }
1819 1842
1820 1843 diagcode:
1821 1844 if (g_msgbase != NULL)
1822 1845 (void) printf(gettext(" See: %s%s\n"), g_msgbase, dc);
1823 1846 }
1824 1847
1825 1848 static void
1826 1849 print_manpage(int verbose)
1827 1850 {
1828 1851 static char *title = NULL;
1829 1852 static char *section = NULL;
1830 1853
1831 1854 if (title == NULL) {
1832 1855 title = safe_malloc(g_value_sz);
1833 1856 section = safe_malloc(g_value_sz);
1834 1857 }
1835 1858
1836 1859 if (pg_get_single_val(g_pg, SCF_PROPERTY_TM_TITLE, SCF_TYPE_ASTRING,
1837 1860 (void *)title, g_value_sz, 0) != 0)
1838 1861 return;
1839 1862
1840 1863 if (pg_get_single_val(g_pg, SCF_PROPERTY_TM_SECTION,
1841 1864 SCF_TYPE_ASTRING, (void *)section, g_value_sz, 0) != 0)
1842 1865 return;
1843 1866
1844 1867 if (!verbose) {
1845 1868 (void) printf(gettext(" See: %s(%s)\n"), title, section);
1846 1869 return;
1847 1870 }
1848 1871
1849 1872 if (pg_get_single_val(g_pg, SCF_PROPERTY_TM_MANPATH, SCF_TYPE_ASTRING,
1850 1873 (void *)g_value, g_value_sz, 0) != 0)
1851 1874 return;
1852 1875
1853 1876 if (strcmp(g_value, ":default") == 0) {
1854 1877 assert(sizeof (DEFAULT_MAN_PATH) < g_value_sz);
1855 1878 (void) strcpy(g_value, DEFAULT_MAN_PATH);
1856 1879 }
1857 1880
1858 1881 (void) printf(gettext(" See: man -M %s -s %s %s\n"), g_value,
1859 1882 section, title);
1860 1883 }
1861 1884
1862 1885 static void
1863 1886 print_doclink()
1864 1887 {
1865 1888 static char *uri = NULL;
1866 1889
1867 1890 if (uri == NULL) {
1868 1891 uri = safe_malloc(g_value_sz);
1869 1892 }
1870 1893
1871 1894 if (pg_get_single_val(g_pg, SCF_PROPERTY_TM_URI, SCF_TYPE_ASTRING,
1872 1895 (void *)uri, g_value_sz, 0) != 0)
1873 1896 return;
1874 1897
1875 1898 (void) printf(gettext(" See: %s\n"), uri);
1876 1899 }
1877 1900
1878 1901
1879 1902 /*
1880 1903 * Returns
1881 1904 * 0 - success
1882 1905 * 1 - inst was deleted
1883 1906 */
1884 1907 static int
1885 1908 print_docs(scf_instance_t *inst, int verbose)
1886 1909 {
1887 1910 scf_snapshot_t *snap;
1888 1911 int r;
1889 1912
1890 1913 if (scf_instance_get_snapshot(inst, "running", g_snap) != 0) {
1891 1914 switch (scf_error()) {
1892 1915 case SCF_ERROR_NOT_FOUND:
1893 1916 break;
1894 1917
1895 1918 case SCF_ERROR_DELETED:
1896 1919 return (1);
1897 1920
1898 1921 default:
1899 1922 scfdie();
1900 1923 }
1901 1924
1902 1925 snap = NULL;
1903 1926 } else {
1904 1927 snap = g_snap;
1905 1928 }
1906 1929
1907 1930 if (scf_iter_instance_pgs_typed_composed(g_iter, inst, snap,
1908 1931 SCF_GROUP_TEMPLATE) != 0) {
1909 1932 if (scf_error() != SCF_ERROR_DELETED)
1910 1933 scfdie();
1911 1934
1912 1935 return (1);
1913 1936 }
1914 1937
1915 1938 for (;;) {
1916 1939 r = scf_iter_next_pg(g_iter, g_pg);
1917 1940 if (r == 0)
1918 1941 break;
1919 1942 if (r != 1) {
1920 1943 if (scf_error() != SCF_ERROR_DELETED)
1921 1944 scfdie();
1922 1945
1923 1946 return (1);
1924 1947 }
1925 1948
1926 1949 if (scf_pg_get_name(g_pg, g_fmri, g_fmri_sz) < 0) {
1927 1950 if (scf_error() != SCF_ERROR_DELETED)
1928 1951 scfdie();
1929 1952
1930 1953 continue;
1931 1954 }
1932 1955
1933 1956 if (strncmp(g_fmri, SCF_PG_TM_MAN_PREFIX,
1934 1957 strlen(SCF_PG_TM_MAN_PREFIX)) == 0) {
1935 1958 print_manpage(verbose);
1936 1959 continue;
1937 1960 }
1938 1961
1939 1962 if (strncmp(g_fmri, SCF_PG_TM_DOC_PREFIX,
1940 1963 strlen(SCF_PG_TM_DOC_PREFIX)) == 0) {
1941 1964 print_doclink();
1942 1965 continue;
1943 1966 }
1944 1967 }
1945 1968 return (0);
1946 1969 }
1947 1970
1948 1971 static int first = 1;
1949 1972
1950 1973 /*
1951 1974 * Explain why the given service is in the state it's in.
1952 1975 */
1953 1976 static void
1954 1977 print_service(inst_t *svcp, int verbose)
1955 1978 {
1956 1979 struct svcptr *spp;
1957 1980 time_t stime;
1958 1981 char *timebuf;
1959 1982 size_t tbsz;
1960 1983 struct tm *tmp;
1961 1984 int deleted = 0;
1962 1985
1963 1986 if (first)
1964 1987 first = 0;
1965 1988 else
1966 1989 (void) putchar('\n');
1967 1990
1968 1991 (void) printf(gettext("svc:/%s:%s"), svcp->svcname, svcp->instname);
1969 1992
1970 1993 if (scf_scope_get_service(g_local_scope, svcp->svcname, g_svc) != 0) {
1971 1994 if (scf_error() != SCF_ERROR_NOT_FOUND)
1972 1995 scfdie();
1973 1996 deleted = 1;
1974 1997 } else if (scf_service_get_instance(g_svc, svcp->instname, g_inst) !=
1975 1998 0) {
1976 1999 if (scf_error() != SCF_ERROR_NOT_FOUND)
1977 2000 scfdie();
1978 2001 deleted = 1;
1979 2002 }
1980 2003
1981 2004 if (!deleted) {
1982 2005 if (inst_get_single_val(g_inst, SCF_PG_TM_COMMON_NAME, locale,
1983 2006 SCF_TYPE_USTRING, g_value, g_value_sz, 0, 0, 1) == 0)
1984 2007 /* EMPTY */;
1985 2008 else if (inst_get_single_val(g_inst, SCF_PG_TM_COMMON_NAME, "C",
1986 2009 SCF_TYPE_USTRING, g_value, g_value_sz, 0, 0, 1) != 0)
1987 2010 (void) strcpy(g_value, "?");
1988 2011
1989 2012 (void) printf(gettext(" (%s)\n"), g_value);
1990 2013 } else {
1991 2014 (void) putchar('\n');
1992 2015 }
1993 2016
1994 2017 if (g_zonename != NULL)
1995 2018 (void) printf(gettext(" Zone: %s\n"), g_zonename);
1996 2019
1997 2020 stime = svcp->stime.tv_sec;
1998 2021 tmp = localtime(&stime);
1999 2022
2000 2023 for (tbsz = 50; ; tbsz *= 2) {
2001 2024 timebuf = safe_malloc(tbsz);
2002 2025 if (strftime(timebuf, tbsz, NULL, tmp) != 0)
2003 2026 break;
2004 2027 free(timebuf);
2005 2028 }
2006 2029
2007 2030 (void) printf(gettext(" State: %s since %s\n"), svcp->state, timebuf);
2008 2031
2009 2032 free(timebuf);
2010 2033
2011 2034 /* Reasons */
2012 2035 print_reasons(svcp, verbose);
2013 2036
2014 2037 if (!deleted)
2015 2038 deleted = print_docs(g_inst, verbose);
2016 2039 if (!deleted)
2017 2040 print_logs(g_inst);
2018 2041
2019 2042 (void) determine_impact(svcp);
2020 2043
2021 2044 switch (uu_list_numnodes(svcp->impact)) {
2022 2045 case 0:
2023 2046 if (inst_running(svcp))
2024 2047 (void) puts(gettext("Impact: None."));
2025 2048 else
2026 2049 (void) puts(gettext(
2027 2050 "Impact: This service is not running."));
2028 2051 break;
2029 2052
2030 2053 case 1:
2031 2054 if (!verbose)
2032 2055 (void) puts(gettext("Impact: 1 dependent service "
2033 2056 "is not running. (Use -v for list.)"));
2034 2057 else
2035 2058 (void) puts(gettext(
2036 2059 "Impact: 1 dependent service is not running:"));
2037 2060 break;
2038 2061
2039 2062 default:
2040 2063 if (!verbose)
2041 2064 (void) printf(gettext("Impact: %d dependent services "
2042 2065 "are not running. (Use -v for list.)\n"),
2043 2066 uu_list_numnodes(svcp->impact));
2044 2067 else
2045 2068 (void) printf(gettext(
2046 2069 "Impact: %d dependent services are not running:\n"),
2047 2070 uu_list_numnodes(svcp->impact));
2048 2071 }
2049 2072
2050 2073 if (verbose) {
2051 2074 for (spp = uu_list_first(svcp->impact);
2052 2075 spp != NULL;
2053 2076 spp = uu_list_next(svcp->impact, spp))
2054 2077 (void) printf(gettext(" svc:/%s:%s\n"),
2055 2078 spp->svcp->svcname, spp->svcp->instname);
2056 2079 }
2057 2080 }
2058 2081
2059 2082 /*
2060 2083 * Top level routine.
2061 2084 */
2062 2085
2063 2086 static int
2064 2087 impact_compar(const void *a, const void *b)
2065 2088 {
2066 2089 int n, m;
2067 2090
2068 2091 n = uu_list_numnodes((*(inst_t **)a)->impact);
2069 2092 m = uu_list_numnodes((*(inst_t **)b)->impact);
2070 2093
2071 2094 return (m - n);
2072 2095 }
2073 2096
2074 2097 static int
2075 2098 print_service_cb(void *verbose, scf_walkinfo_t *wip)
2076 2099 {
2077 2100 int r;
2078 2101 inst_t *ip;
2079 2102
2080 2103 assert(wip->pg == NULL);
2081 2104
2082 2105 r = get_fmri(wip->fmri, NULL, &ip);
2083 2106 assert(r != EINVAL);
2084 2107 if (r == ENOENT)
2085 2108 return (0);
2086 2109
2087 2110 assert(r == 0);
2088 2111 assert(ip != NULL);
2089 2112
2090 2113 print_service(ip, (int)verbose);
2091 2114
2092 2115 return (0);
2093 2116 }
2094 2117
2095 2118 void
2096 2119 explain(int verbose, int argc, char **argv)
2097 2120 {
2098 2121 /*
2099 2122 * Initialize globals. If we have been called before (e.g., for a
2100 2123 * different zone), this will clobber the previous globals -- keeping
2101 2124 * with the proud svcs(1) tradition of not bothering to ever clean
2102 2125 * anything up.
2103 2126 */
2104 2127 x_init();
2105 2128
2106 2129 /* Walk the graph and populate services with inst_t's */
2107 2130 load_services();
2108 2131
2109 2132 /* Populate causes for services. */
2110 2133 determine_all_causes();
2111 2134
2112 2135 if (argc > 0) {
2113 2136 scf_error_t err;
2114 2137
2115 2138 check_msgbase();
2116 2139
2117 2140 /* Call print_service() for each operand. */
2118 2141
2119 2142 err = scf_walk_fmri(h, argc, argv, SCF_WALK_MULTIPLE,
2120 2143 print_service_cb, (void *)verbose, &exit_status, uu_warn);
2121 2144 if (err != 0) {
2122 2145 uu_warn(gettext(
2123 2146 "failed to iterate over instances: %s\n"),
2124 2147 scf_strerror(err));
2125 2148 exit_status = UU_EXIT_FATAL;
2126 2149 }
2127 2150 } else {
2128 2151 struct svcptr *spp;
2129 2152 int n, i;
2130 2153 inst_t **ary;
2131 2154
2132 2155 /* Sort g_causes. */
2133 2156
2134 2157 n = uu_list_numnodes(g_causes);
2135 2158 if (n == 0)
2136 2159 return;
2137 2160
2138 2161 check_msgbase();
2139 2162
2140 2163 ary = calloc(n, sizeof (*ary));
2141 2164 if (ary == NULL)
2142 2165 uu_die(emsg_nomem);
2143 2166
2144 2167 i = 0;
2145 2168 for (spp = uu_list_first(g_causes);
2146 2169 spp != NULL;
2147 2170 spp = uu_list_next(g_causes, spp)) {
2148 2171 (void) determine_impact(spp->svcp);
2149 2172 ary[i++] = spp->svcp;
2150 2173 }
2151 2174
2152 2175 qsort(ary, n, sizeof (*ary), impact_compar);
2153 2176
2154 2177 /* Call print_service() for each service. */
2155 2178
2156 2179 for (i = 0; i < n; ++i)
2157 2180 print_service(ary[i], verbose);
2158 2181 }
2159 2182 }
↓ open down ↓ |
405 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX