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