Print this page
7711 SMF: Finish implementing support for degraded state
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/svc/svcadm/svcadm.c
+++ new/usr/src/cmd/svc/svcadm/svcadm.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
↓ open down ↓ |
17 lines elided |
↑ open up ↑ |
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26 /*
27 27 * Copyright 2015, Joyent, Inc. All rights reserved.
28 + * Copyright 2017 RackTop Systems.
28 29 */
29 30
30 31 /*
31 32 * svcadm - request adminstrative actions for service instances
32 33 */
33 34
34 35 #include <locale.h>
35 36 #include <libintl.h>
36 37 #include <libscf.h>
37 38 #include <libscf_priv.h>
38 39 #include <libcontract.h>
39 40 #include <libcontract_priv.h>
40 41 #include <sys/contract/process.h>
41 42 #include <libuutil.h>
42 43 #include <stddef.h>
43 44 #include <stdio.h>
44 45 #include <stdlib.h>
45 46 #include <string.h>
46 47 #include <unistd.h>
47 48 #include <fcntl.h>
48 49 #include <procfs.h>
49 50 #include <assert.h>
50 51 #include <errno.h>
51 52 #include <zone.h>
52 53
53 54 #ifndef TEXT_DOMAIN
54 55 #define TEXT_DOMAIN "SUNW_OST_OSCMD"
55 56 #endif /* TEXT_DOMAIN */
56 57
57 58 /* Must be a power of two */
58 59 #define HT_BUCKETS 64
59 60
60 61 /*
61 62 * Exit codes for enable and disable -s.
62 63 */
63 64 #define EXIT_SVC_FAILURE 3
64 65 #define EXIT_DEP_FAILURE 4
65 66
66 67 #define WALK_FLAGS (SCF_WALK_UNIPARTIAL | SCF_WALK_MULTIPLE)
67 68
68 69 /*
69 70 * How long we will wait (in seconds) for a service to change state
70 71 * before re-checking its dependencies.
71 72 */
72 73 #define WAIT_INTERVAL 3
73 74
74 75 #define bad_error(func, err) \
75 76 uu_panic("%s:%d: %s() failed with unexpected error %d.\n", \
76 77 __FILE__, __LINE__, (func), (err));
77 78
78 79 struct ht_elt {
79 80 struct ht_elt *next;
80 81 boolean_t active;
81 82 char str[1];
82 83 };
83 84
84 85
85 86 scf_handle_t *h;
86 87 ssize_t max_scf_fmri_sz;
87 88 static const char *emsg_permission_denied;
88 89 static const char *emsg_nomem;
89 90 static const char *emsg_create_pg_perm_denied;
90 91 static const char *emsg_pg_perm_denied;
91 92 static const char *emsg_prop_perm_denied;
92 93 static const char *emsg_no_service;
93 94
94 95 static int exit_status = 0;
95 96 static int verbose = 0;
96 97 static char *scratch_fmri;
97 98 static char *g_zonename = NULL;
98 99 static char svcstate[80];
99 100 static boolean_t svcsearch = B_FALSE;
100 101
101 102 static struct ht_elt **visited;
102 103
103 104 void do_scfdie(int lineno) __NORETURN;
104 105 static void usage_milestone(void) __NORETURN;
105 106 static void set_astring_prop(const char *, const char *, const char *,
106 107 uint32_t, const char *, const char *);
107 108 static void pr_warn(const char *format, ...);
108 109
109 110 /*
110 111 * Visitors from synch.c, needed for enable -s and disable -s.
111 112 */
112 113 extern int is_enabled(scf_instance_t *);
113 114 extern int has_potential(scf_instance_t *, int);
114 115
115 116 void
116 117 do_scfdie(int lineno)
117 118 {
118 119 scf_error_t err;
119 120
120 121 switch (err = scf_error()) {
121 122 case SCF_ERROR_CONNECTION_BROKEN:
122 123 uu_die(gettext("Connection to repository server broken. "
123 124 "Exiting.\n"));
124 125 /* NOTREACHED */
125 126
126 127 case SCF_ERROR_BACKEND_READONLY:
127 128 uu_die(gettext("Repository is read-only. Exiting.\n"));
128 129 /* NOTREACHED */
129 130
130 131 default:
131 132 #ifdef NDEBUG
132 133 uu_die(gettext("Unexpected libscf error: %s. Exiting.\n"),
133 134 scf_strerror(err));
134 135 #else
135 136 uu_die("Unexpected libscf error on line %d: %s.\n", lineno,
136 137 scf_strerror(err));
137 138 #endif
138 139 }
139 140 }
140 141
141 142 #define scfdie() do_scfdie(__LINE__)
142 143
143 144 static void
144 145 usage()
145 146 {
146 147 (void) fprintf(stderr, gettext(
147 148 "Usage: %1$s [-S <state>] [-v] [-Z | -z zone] [cmd [args ... ]]\n\n"
148 149 "\t%1$s enable [-rst] [<service> ...]\t- enable and online service(s)\n"
149 150 "\t%1$s disable [-st] [<service> ...]\t- disable and offline "
150 151 "service(s)\n"
151 152 "\t%1$s restart [-d] [<service> ...]\t- restart specified service(s)\n"
152 153 "\t%1$s refresh [<service> ...]\t\t- re-read service configuration\n"
153 154 "\t%1$s mark [-It] <state> [<service> ...] - set maintenance state\n"
154 155 "\t%1$s clear [<service> ...]\t\t- clear maintenance state\n"
155 156 "\t%1$s milestone [-d] <milestone>\t- advance to a service milestone\n"
156 157 "\n\t"
157 158 "Services can be specified using an FMRI, abbreviation, or fnmatch(5)\n"
158 159 "\tpattern, as shown in these examples for svc:/network/smtp:sendmail\n"
159 160 "\n"
160 161 "\t%1$s <cmd> svc:/network/smtp:sendmail\n"
161 162 "\t%1$s <cmd> network/smtp:sendmail\n"
162 163 "\t%1$s <cmd> network/*mail\n"
163 164 "\t%1$s <cmd> network/smtp\n"
164 165 "\t%1$s <cmd> smtp:sendmail\n"
165 166 "\t%1$s <cmd> smtp\n"
166 167 "\t%1$s <cmd> sendmail\n"), uu_getpname());
167 168
168 169 exit(UU_EXIT_USAGE);
169 170 }
170 171
171 172
172 173 /*
173 174 * FMRI hash table for recursive enable.
174 175 */
175 176
176 177 static uint32_t
177 178 hash_fmri(const char *str)
178 179 {
179 180 uint32_t h = 0, g;
180 181 const char *p;
181 182
182 183 /* Generic hash function from uts/common/os/modhash.c . */
183 184 for (p = str; *p != '\0'; ++p) {
184 185 h = (h << 4) + *p;
185 186 if ((g = (h & 0xf0000000)) != 0) {
186 187 h ^= (g >> 24);
187 188 h ^= g;
188 189 }
189 190 }
190 191
191 192 return (h);
192 193 }
193 194
194 195 /*
195 196 * Return 1 if str has been visited, 0 if it has not, and -1 if memory could not
196 197 * be allocated.
197 198 */
198 199 static int
199 200 visited_find_or_add(const char *str, struct ht_elt **hep)
200 201 {
201 202 uint32_t h;
202 203 uint_t i;
203 204 struct ht_elt *he;
204 205
205 206 h = hash_fmri(str);
206 207 i = h & (HT_BUCKETS - 1);
207 208
208 209 for (he = visited[i]; he != NULL; he = he->next) {
209 210 if (strcmp(he->str, str) == 0) {
210 211 if (hep)
211 212 *hep = he;
212 213 return (1);
213 214 }
214 215 }
215 216
216 217 he = malloc(offsetof(struct ht_elt, str) + strlen(str) + 1);
217 218 if (he == NULL)
218 219 return (-1);
219 220
220 221 (void) strcpy(he->str, str);
221 222
222 223 he->next = visited[i];
223 224 visited[i] = he;
224 225
225 226 if (hep)
226 227 *hep = he;
227 228 return (0);
228 229 }
229 230
230 231
231 232 /*
232 233 * Returns 0, ECANCELED if pg is deleted, ENOENT if propname doesn't exist,
233 234 * EINVAL if the property is not of boolean type or has no values, and E2BIG
234 235 * if it has more than one value. *bp is set if 0 or E2BIG is returned.
235 236 */
236 237 int
237 238 get_bool_prop(scf_propertygroup_t *pg, const char *propname, uint8_t *bp)
238 239 {
239 240 scf_property_t *prop;
240 241 scf_value_t *val;
241 242 int ret;
242 243
243 244 if ((prop = scf_property_create(h)) == NULL ||
244 245 (val = scf_value_create(h)) == NULL)
245 246 scfdie();
246 247
247 248 if (scf_pg_get_property(pg, propname, prop) != 0) {
248 249 switch (scf_error()) {
249 250 case SCF_ERROR_DELETED:
250 251 ret = ECANCELED;
251 252 goto out;
252 253
253 254 case SCF_ERROR_NOT_FOUND:
254 255 ret = ENOENT;
255 256 goto out;
256 257
257 258 case SCF_ERROR_NOT_SET:
258 259 assert(0);
259 260 abort();
260 261 /* NOTREACHED */
261 262
262 263 default:
263 264 scfdie();
264 265 }
265 266 }
266 267
267 268 if (scf_property_get_value(prop, val) == 0) {
268 269 ret = 0;
269 270 } else {
270 271 switch (scf_error()) {
271 272 case SCF_ERROR_DELETED:
272 273 ret = ENOENT;
273 274 goto out;
274 275
275 276 case SCF_ERROR_NOT_FOUND:
276 277 ret = EINVAL;
277 278 goto out;
278 279
279 280 case SCF_ERROR_CONSTRAINT_VIOLATED:
280 281 ret = E2BIG;
281 282 break;
282 283
283 284 case SCF_ERROR_NOT_SET:
284 285 assert(0);
285 286 abort();
286 287 /* NOTREACHED */
287 288
288 289 default:
289 290 scfdie();
290 291 }
291 292 }
292 293
293 294 if (scf_value_get_boolean(val, bp) != 0) {
294 295 if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
295 296 scfdie();
296 297
297 298 ret = EINVAL;
298 299 goto out;
299 300 }
300 301
301 302 out:
302 303 scf_value_destroy(val);
303 304 scf_property_destroy(prop);
304 305 return (ret);
305 306 }
306 307
307 308 /*
308 309 * Returns 0, EPERM, or EROFS.
309 310 */
310 311 static int
311 312 set_bool_prop(scf_propertygroup_t *pg, const char *propname, boolean_t b)
312 313 {
313 314 scf_value_t *v;
314 315 scf_transaction_t *tx;
315 316 scf_transaction_entry_t *ent;
316 317 int ret = 0, r;
317 318
318 319 if ((tx = scf_transaction_create(h)) == NULL ||
319 320 (ent = scf_entry_create(h)) == NULL ||
320 321 (v = scf_value_create(h)) == NULL)
321 322 scfdie();
322 323
323 324 scf_value_set_boolean(v, b);
324 325
325 326 for (;;) {
326 327 if (scf_transaction_start(tx, pg) == -1) {
327 328 switch (scf_error()) {
328 329 case SCF_ERROR_PERMISSION_DENIED:
329 330 ret = EPERM;
330 331 goto out;
331 332
332 333 case SCF_ERROR_BACKEND_READONLY:
333 334 ret = EROFS;
334 335 goto out;
335 336
336 337 default:
337 338 scfdie();
338 339 }
339 340 }
340 341
341 342 if (scf_transaction_property_change_type(tx, ent, propname,
342 343 SCF_TYPE_BOOLEAN) != 0) {
343 344 if (scf_error() != SCF_ERROR_NOT_FOUND)
344 345 scfdie();
345 346
346 347 if (scf_transaction_property_new(tx, ent, propname,
347 348 SCF_TYPE_BOOLEAN) != 0)
348 349 scfdie();
349 350 }
350 351
351 352 r = scf_entry_add_value(ent, v);
352 353 assert(r == 0);
353 354
354 355 r = scf_transaction_commit(tx);
355 356 if (r == 1)
356 357 break;
357 358
358 359 scf_transaction_reset(tx);
359 360
360 361 if (r != 0) {
361 362 switch (scf_error()) {
362 363 case SCF_ERROR_PERMISSION_DENIED:
363 364 ret = EPERM;
364 365 goto out;
365 366
366 367 case SCF_ERROR_BACKEND_READONLY:
367 368 ret = EROFS;
368 369 goto out;
369 370
370 371 default:
371 372 scfdie();
372 373 }
373 374 }
374 375
375 376 if (scf_pg_update(pg) == -1)
376 377 scfdie();
377 378 }
378 379
379 380 out:
380 381 scf_transaction_destroy(tx);
381 382 scf_entry_destroy(ent);
382 383 scf_value_destroy(v);
383 384 return (ret);
384 385 }
385 386
386 387 /*
387 388 * Gets the single astring value of the propname property of pg. prop & v are
388 389 * scratch space. Returns the length of the string on success or
389 390 * -ENOENT - pg has no property named propname
390 391 * -E2BIG - property has no values or multiple values
391 392 * -EINVAL - property type is not compatible with astring
392 393 */
393 394 ssize_t
394 395 get_astring_prop(const scf_propertygroup_t *pg, const char *propname,
395 396 scf_property_t *prop, scf_value_t *v, char *buf, size_t bufsz)
396 397 {
397 398 ssize_t sz;
398 399
399 400 if (scf_pg_get_property(pg, propname, prop) != 0) {
400 401 if (scf_error() != SCF_ERROR_NOT_FOUND)
401 402 scfdie();
402 403
403 404 return (-ENOENT);
404 405 }
405 406
406 407 if (scf_property_get_value(prop, v) != 0) {
407 408 switch (scf_error()) {
408 409 case SCF_ERROR_NOT_FOUND:
409 410 case SCF_ERROR_CONSTRAINT_VIOLATED:
410 411 return (-E2BIG);
411 412
412 413 default:
413 414 scfdie();
414 415 }
415 416 }
416 417
417 418 sz = scf_value_get_astring(v, buf, bufsz);
418 419 if (sz < 0) {
419 420 if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
420 421 scfdie();
421 422
422 423 return (-EINVAL);
423 424 }
424 425
425 426 return (sz);
426 427 }
427 428
428 429 /*
429 430 * Returns 0 or EPERM.
430 431 */
431 432 static int
432 433 pg_get_or_add(const scf_instance_t *inst, const char *pgname,
433 434 const char *pgtype, uint32_t pgflags, scf_propertygroup_t *pg)
434 435 {
435 436 again:
436 437 if (scf_instance_get_pg(inst, pgname, pg) == 0)
437 438 return (0);
438 439
439 440 if (scf_error() != SCF_ERROR_NOT_FOUND)
440 441 scfdie();
441 442
442 443 if (scf_instance_add_pg(inst, pgname, pgtype, pgflags, pg) == 0)
443 444 return (0);
444 445
445 446 switch (scf_error()) {
446 447 case SCF_ERROR_EXISTS:
447 448 goto again;
448 449
449 450 case SCF_ERROR_PERMISSION_DENIED:
450 451 return (EPERM);
451 452
452 453 default:
453 454 scfdie();
454 455 /* NOTREACHED */
455 456 }
456 457 }
457 458
458 459 static int
459 460 my_ct_name(char *out, size_t len)
460 461 {
461 462 ct_stathdl_t st;
462 463 char *ct_fmri;
463 464 ctid_t ct;
464 465 int fd, errno, ret;
465 466
466 467 if ((ct = getctid()) == -1)
467 468 uu_die(gettext("Could not get contract id for process"));
468 469
469 470 fd = contract_open(ct, "process", "status", O_RDONLY);
470 471
471 472 if ((errno = ct_status_read(fd, CTD_ALL, &st)) != 0)
472 473 uu_warn(gettext("Could not read status of contract "
473 474 "%ld: %s.\n"), ct, strerror(errno));
474 475
475 476 if ((errno = ct_pr_status_get_svc_fmri(st, &ct_fmri)) != 0)
476 477 uu_warn(gettext("Could not get svc_fmri for contract "
477 478 "%ld: %s.\n"), ct, strerror(errno));
478 479
479 480 ret = strlcpy(out, ct_fmri, len);
480 481
481 482 ct_status_free(st);
482 483 (void) close(fd);
483 484
484 485 return (ret);
485 486 }
486 487
487 488 /*
488 489 * Set auxiliary_tty and auxiliary_fmri properties in restarter_actions pg to
489 490 * communicate whether the action is requested from a tty and the fmri of the
490 491 * responsible process.
491 492 *
492 493 * Returns 0, EPERM, or EROFS
493 494 */
494 495 static int
495 496 restarter_setup(const char *fmri, const scf_instance_t *inst)
496 497 {
497 498 boolean_t b = B_FALSE;
498 499 scf_propertygroup_t *pg = NULL;
499 500 int ret = 0;
500 501
501 502 if ((pg = scf_pg_create(h)) == NULL)
502 503 scfdie();
503 504
504 505 if (pg_get_or_add(inst, SCF_PG_RESTARTER_ACTIONS,
505 506 SCF_PG_RESTARTER_ACTIONS_TYPE, SCF_PG_RESTARTER_ACTIONS_FLAGS,
506 507 pg) == EPERM) {
507 508 if (!verbose)
508 509 uu_warn(emsg_permission_denied, fmri);
509 510 else
510 511 uu_warn(emsg_create_pg_perm_denied, fmri,
511 512 SCF_PG_RESTARTER_ACTIONS);
512 513
513 514 ret = EPERM;
514 515 goto out;
515 516 }
516 517
517 518 /* Set auxiliary_tty property */
518 519 if (isatty(STDIN_FILENO))
519 520 b = B_TRUE;
520 521
521 522 /* Create and set state to disabled */
522 523 switch (set_bool_prop(pg, SCF_PROPERTY_AUX_TTY, b)) {
523 524 case 0:
524 525 break;
525 526
526 527 case EPERM:
527 528 if (!verbose)
528 529 uu_warn(emsg_permission_denied, fmri);
529 530 else
530 531 uu_warn(emsg_prop_perm_denied, fmri,
531 532 SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_AUX_TTY);
532 533
533 534 ret = EPERM;
534 535 goto out;
535 536 /* NOTREACHED */
536 537
537 538 case EROFS:
538 539 /* Shouldn't happen, but it can. */
539 540 if (!verbose)
540 541 uu_warn(gettext("%s: Repository read-only.\n"), fmri);
541 542 else
542 543 uu_warn(gettext("%s: Could not set %s/%s "
543 544 "(repository read-only).\n"), fmri,
544 545 SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_AUX_TTY);
545 546
546 547 ret = EROFS;
547 548 goto out;
548 549 /* NOTREACHED */
549 550
550 551 default:
551 552 scfdie();
552 553 }
553 554
554 555 if (my_ct_name(scratch_fmri, max_scf_fmri_sz) > 0) {
555 556 set_astring_prop(fmri, SCF_PG_RESTARTER_ACTIONS,
556 557 SCF_PG_RESTARTER_ACTIONS_TYPE,
557 558 SCF_PG_RESTARTER_ACTIONS_FLAGS,
558 559 SCF_PROPERTY_AUX_FMRI, scratch_fmri);
559 560 } else {
560 561 uu_warn(gettext("%s: Could not set %s/%s: "
561 562 "my_ct_name failed.\n"), fmri,
562 563 SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_AUX_FMRI);
563 564 }
564 565
565 566 out:
566 567 scf_pg_destroy(pg);
567 568 return (ret);
568 569 }
569 570
570 571 /*
571 572 * Enable or disable inst, per enable. If temp is true, set
572 573 * general_ovr/enabled. Otherwise set general/enabled and delete
573 574 * general_ovr/enabled if it exists (order is important here: we don't want the
574 575 * enabled status to glitch).
575 576 */
576 577 static void
577 578 set_inst_enabled(const char *fmri, scf_instance_t *inst, boolean_t temp,
578 579 boolean_t enable)
579 580 {
580 581 scf_propertygroup_t *pg;
581 582 uint8_t b;
582 583 const char *pgname = NULL; /* For emsg_pg_perm_denied */
583 584 int r;
584 585
585 586 pg = scf_pg_create(h);
586 587 if (pg == NULL)
587 588 scfdie();
588 589
589 590 if (restarter_setup(fmri, inst))
590 591 goto out;
591 592
592 593 /*
593 594 * An instance's configuration is incomplete if general/enabled
594 595 * doesn't exist. Create both the property group and property
595 596 * here if they don't exist.
596 597 */
597 598 pgname = SCF_PG_GENERAL;
598 599 if (pg_get_or_add(inst, pgname, SCF_PG_GENERAL_TYPE,
599 600 SCF_PG_GENERAL_FLAGS, pg) != 0)
600 601 goto eperm;
601 602
602 603 if (get_bool_prop(pg, SCF_PROPERTY_ENABLED, &b) != 0) {
603 604 /* Create and set state to disabled */
604 605 switch (set_bool_prop(pg, SCF_PROPERTY_ENABLED, B_FALSE)) {
605 606 case 0:
606 607 break;
607 608
608 609 case EPERM:
609 610 goto eperm;
610 611
611 612 case EROFS:
612 613 /* Shouldn't happen, but it can. */
613 614 if (!verbose)
614 615 uu_warn(gettext("%s: Repository read-only.\n"),
615 616 fmri);
616 617 else
617 618 uu_warn(gettext("%s: Could not set %s/%s "
618 619 "(repository read-only).\n"), fmri,
619 620 SCF_PG_GENERAL, SCF_PROPERTY_ENABLED);
620 621 goto out;
621 622
622 623 default:
623 624 assert(0);
624 625 abort();
625 626 }
626 627 }
627 628
628 629 if (temp) {
629 630 /* Set general_ovr/enabled */
630 631 pgname = SCF_PG_GENERAL_OVR;
631 632 if (pg_get_or_add(inst, pgname, SCF_PG_GENERAL_OVR_TYPE,
632 633 SCF_PG_GENERAL_OVR_FLAGS, pg) != 0)
633 634 goto eperm;
634 635
635 636 switch (set_bool_prop(pg, SCF_PROPERTY_ENABLED, enable)) {
636 637 case 0:
637 638 break;
638 639
639 640 case EPERM:
640 641 goto eperm;
641 642
642 643 case EROFS:
643 644 /* Shouldn't happen, but it can. */
644 645 if (!verbose)
645 646 uu_warn(gettext("%s: Repository read-only.\n"),
646 647 fmri);
647 648 else
648 649 uu_warn(gettext("%s: Could not set %s/%s "
649 650 "(repository read-only).\n"), fmri,
650 651 SCF_PG_GENERAL_OVR, SCF_PROPERTY_ENABLED);
651 652 goto out;
652 653
653 654 default:
654 655 assert(0);
655 656 abort();
656 657 }
657 658
658 659 if (verbose)
659 660 (void) printf(enable ?
660 661 gettext("%s temporarily enabled.\n") :
661 662 gettext("%s temporarily disabled.\n"), fmri);
662 663 } else {
663 664 again:
664 665 /*
665 666 * Both pg and property should exist since we created
666 667 * them earlier. However, there's still a chance that
667 668 * someone may have deleted the property out from under
668 669 * us.
669 670 */
670 671 if (pg_get_or_add(inst, pgname, SCF_PG_GENERAL_TYPE,
671 672 SCF_PG_GENERAL_FLAGS, pg) != 0)
672 673 goto eperm;
673 674
674 675 switch (set_bool_prop(pg, SCF_PROPERTY_ENABLED, enable)) {
675 676 case 0:
676 677 break;
677 678
678 679 case EPERM:
679 680 goto eperm;
680 681
681 682 case EROFS:
682 683 /*
683 684 * If general/enabled is already set the way we want,
684 685 * proceed.
685 686 */
686 687 switch (get_bool_prop(pg, SCF_PROPERTY_ENABLED, &b)) {
687 688 case 0:
688 689 if ((b != 0) == (enable != B_FALSE))
689 690 break;
690 691 /* FALLTHROUGH */
691 692
692 693 case ENOENT:
693 694 case EINVAL:
694 695 case E2BIG:
695 696 if (!verbose)
696 697 uu_warn(gettext("%s: Repository "
697 698 "read-only.\n"), fmri);
698 699 else
699 700 uu_warn(gettext("%s: Could not set "
700 701 "%s/%s (repository read-only).\n"),
701 702 fmri, SCF_PG_GENERAL,
702 703 SCF_PROPERTY_ENABLED);
703 704 goto out;
704 705
705 706 case ECANCELED:
706 707 goto again;
707 708
708 709 default:
709 710 assert(0);
710 711 abort();
711 712 }
712 713 break;
713 714
714 715 default:
715 716 assert(0);
716 717 abort();
717 718 }
718 719
719 720 pgname = SCF_PG_GENERAL_OVR;
720 721 r = scf_instance_delete_prop(inst, pgname,
721 722 SCF_PROPERTY_ENABLED);
722 723 switch (r) {
723 724 case 0:
724 725 break;
725 726
726 727 case ECANCELED:
727 728 uu_warn(emsg_no_service, fmri);
728 729 goto out;
729 730
730 731 case EPERM:
731 732 goto eperm;
732 733
733 734 case EACCES:
734 735 uu_warn(gettext("Could not delete %s/%s "
735 736 "property of %s: backend access denied.\n"),
736 737 pgname, SCF_PROPERTY_ENABLED, fmri);
737 738 goto out;
738 739
739 740 case EROFS:
740 741 uu_warn(gettext("Could not delete %s/%s "
741 742 "property of %s: backend is read-only.\n"),
742 743 pgname, SCF_PROPERTY_ENABLED, fmri);
743 744 goto out;
744 745
745 746 default:
746 747 bad_error("scf_instance_delete_prop", r);
747 748 }
748 749
749 750 if (verbose)
750 751 (void) printf(enable ? gettext("%s enabled.\n") :
751 752 gettext("%s disabled.\n"), fmri);
752 753 }
753 754
754 755 scf_pg_destroy(pg);
755 756 return;
756 757
757 758 eperm:
758 759 assert(pgname != NULL);
759 760 if (!verbose)
760 761 uu_warn(emsg_permission_denied, fmri);
761 762 else
762 763 uu_warn(emsg_pg_perm_denied, fmri, pgname);
763 764
764 765 out:
765 766 scf_pg_destroy(pg);
766 767 exit_status = 1;
767 768 }
768 769
769 770 /*
770 771 * Set inst to the instance which corresponds to fmri. If fmri identifies
771 772 * a service with a single instance, get that instance.
772 773 *
773 774 * Fails with
774 775 * ENOTSUP - fmri has an unsupported scheme
775 776 * EINVAL - fmri is invalid
776 777 * ENOTDIR - fmri does not identify a service or instance
777 778 * ENOENT - could not locate instance
778 779 * E2BIG - fmri is a service with multiple instances (warning not printed)
779 780 */
780 781 static int
781 782 get_inst_mult(const char *fmri, scf_instance_t *inst)
782 783 {
783 784 char *cfmri;
784 785 const char *svc_name, *inst_name, *pg_name;
785 786 scf_service_t *svc;
786 787 scf_instance_t *inst2;
787 788 scf_iter_t *iter;
788 789 int ret;
789 790
790 791 if (strncmp(fmri, "lrc:", sizeof ("lrc:") - 1) == 0) {
791 792 uu_warn(gettext("FMRI \"%s\" is a legacy service.\n"), fmri);
792 793 exit_status = 1;
793 794 return (ENOTSUP);
794 795 }
795 796
796 797 cfmri = strdup(fmri);
797 798 if (cfmri == NULL)
798 799 uu_die(emsg_nomem);
799 800
800 801 if (scf_parse_svc_fmri(cfmri, NULL, &svc_name, &inst_name, &pg_name,
801 802 NULL) != SCF_SUCCESS) {
802 803 free(cfmri);
803 804 uu_warn(gettext("FMRI \"%s\" is invalid.\n"), fmri);
804 805 exit_status = 1;
805 806 return (EINVAL);
806 807 }
807 808
808 809 free(cfmri);
809 810
810 811 if (svc_name == NULL || pg_name != NULL) {
811 812 uu_warn(gettext(
812 813 "FMRI \"%s\" does not designate a service or instance.\n"),
813 814 fmri);
814 815 exit_status = 1;
815 816 return (ENOTDIR);
816 817 }
817 818
818 819 if (inst_name != NULL) {
819 820 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
820 821 NULL, SCF_DECODE_FMRI_EXACT) == 0)
821 822 return (0);
822 823
823 824 if (scf_error() != SCF_ERROR_NOT_FOUND)
824 825 scfdie();
825 826
826 827 uu_warn(gettext("No such instance \"%s\".\n"), fmri);
827 828 exit_status = 1;
828 829
829 830 return (ENOENT);
830 831 }
831 832
832 833 if ((svc = scf_service_create(h)) == NULL ||
833 834 (inst2 = scf_instance_create(h)) == NULL ||
834 835 (iter = scf_iter_create(h)) == NULL)
835 836 scfdie();
836 837
837 838 if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
838 839 SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
839 840 if (scf_error() != SCF_ERROR_NOT_FOUND)
840 841 scfdie();
841 842
842 843 uu_warn(emsg_no_service, fmri);
843 844 exit_status = 1;
844 845
845 846 ret = ENOENT;
846 847 goto out;
847 848 }
848 849
849 850 /* If the service has only one child, use it. */
850 851 if (scf_iter_service_instances(iter, svc) != SCF_SUCCESS)
851 852 scfdie();
852 853
853 854 ret = scf_iter_next_instance(iter, inst);
854 855 if (ret < 0)
855 856 scfdie();
856 857 if (ret != 1) {
857 858 uu_warn(gettext("Service \"%s\" has no instances.\n"),
858 859 fmri);
859 860 exit_status = 1;
860 861 ret = ENOENT;
861 862 goto out;
862 863 }
863 864
864 865 ret = scf_iter_next_instance(iter, inst2);
865 866 if (ret < 0)
866 867 scfdie();
867 868
868 869 if (ret != 0) {
869 870 ret = E2BIG;
870 871 goto out;
871 872 }
872 873
873 874 ret = 0;
874 875
875 876 out:
876 877 scf_iter_destroy(iter);
877 878 scf_instance_destroy(inst2);
878 879 scf_service_destroy(svc);
879 880 return (ret);
880 881 }
881 882
882 883 /*
883 884 * Same as get_inst_mult(), but on E2BIG prints a warning and returns ENOENT.
884 885 */
885 886 static int
886 887 get_inst(const char *fmri, scf_instance_t *inst)
887 888 {
888 889 int r;
889 890
890 891 r = get_inst_mult(fmri, inst);
891 892 if (r != E2BIG)
892 893 return (r);
893 894
894 895 uu_warn(gettext("operation on service %s is ambiguous; "
895 896 "instance specification needed.\n"), fmri);
896 897 return (ENOENT);
897 898 }
898 899
899 900 static char *
900 901 inst_get_fmri(const scf_instance_t *inst)
901 902 {
902 903 ssize_t sz;
903 904
904 905 sz = scf_instance_to_fmri(inst, scratch_fmri, max_scf_fmri_sz);
905 906 if (sz < 0)
906 907 scfdie();
907 908 if (sz >= max_scf_fmri_sz)
908 909 uu_die(gettext("scf_instance_to_fmri() returned unexpectedly "
909 910 "long value.\n"));
910 911
911 912 return (scratch_fmri);
912 913 }
913 914
914 915 static ssize_t
915 916 dep_get_astring(const char *fmri, const char *pgname,
916 917 const scf_propertygroup_t *pg, const char *propname, scf_property_t *prop,
917 918 scf_value_t *v, char *buf, size_t bufsz)
918 919 {
919 920 ssize_t sz;
920 921
921 922 sz = get_astring_prop(pg, propname, prop, v, buf, bufsz);
922 923 if (sz >= 0)
923 924 return (sz);
924 925
925 926 switch (-sz) {
926 927 case ENOENT:
927 928 uu_warn(gettext("\"%s\" is misconfigured (\"%s\" dependency "
928 929 "lacks \"%s\" property.)\n"), fmri, pgname, propname);
929 930 return (-1);
930 931
931 932 case E2BIG:
932 933 uu_warn(gettext("\"%s\" is misconfigured (\"%s/%s\" property "
933 934 "is not single-valued.)\n"), fmri, pgname, propname);
934 935 return (-1);
935 936
936 937 case EINVAL:
937 938 uu_warn(gettext("\"%s\" is misconfigured (\"%s/%s\" property "
938 939 "is not of astring type.)\n"), fmri, pgname, propname);
939 940 return (-1);
940 941
941 942 default:
942 943 assert(0);
943 944 abort();
944 945 /* NOTREACHED */
945 946 }
946 947 }
947 948
948 949 static boolean_t
949 950 multiple_instances(scf_iter_t *iter, scf_value_t *v, char *buf)
950 951 {
951 952 int count = 0, r;
952 953 boolean_t ret;
953 954 scf_instance_t *inst;
954 955
955 956 inst = scf_instance_create(h);
956 957 if (inst == NULL)
957 958 scfdie();
958 959
959 960 for (;;) {
960 961 r = scf_iter_next_value(iter, v);
961 962 if (r == 0) {
962 963 ret = B_FALSE;
963 964 goto out;
964 965 }
965 966 if (r != 1)
966 967 scfdie();
967 968
968 969 if (scf_value_get_astring(v, buf, max_scf_fmri_sz) < 0)
969 970 scfdie();
970 971
971 972 switch (get_inst_mult(buf, inst)) {
972 973 case 0:
973 974 ++count;
974 975 if (count > 1) {
975 976 ret = B_TRUE;
976 977 goto out;
977 978 }
978 979 break;
979 980
980 981 case ENOTSUP:
981 982 case EINVAL:
982 983 case ENOTDIR:
983 984 case ENOENT:
984 985 continue;
985 986
986 987 case E2BIG:
987 988 ret = B_TRUE;
988 989 goto out;
989 990
990 991 default:
991 992 assert(0);
992 993 abort();
993 994 }
994 995 }
995 996
996 997 out:
997 998 scf_instance_destroy(inst);
998 999 return (ret);
999 1000 }
1000 1001
1001 1002 /*
1002 1003 * Enable the service or instance identified by fmri and its dependencies,
1003 1004 * recursively. Specifically, call get_inst(fmri), enable the result, and
1004 1005 * recurse on its restarter and the dependencies. To avoid duplication of
1005 1006 * effort or looping around a dependency cycle, each FMRI is entered into the
1006 1007 * "visited" hash table. While recursing, the hash table entry is marked
1007 1008 * "active", so that if we come upon it again, we know we've hit a cycle.
1008 1009 * exclude_all and optional_all dependencies are ignored. require_any
1009 1010 * dependencies are followed only if they comprise a single service; otherwise
1010 1011 * the user is warned.
1011 1012 *
1012 1013 * fmri must point to a writable max_scf_fmri_sz buffer. Returns EINVAL if fmri
1013 1014 * is invalid, E2BIG if fmri identifies a service with multiple instances, ELOOP
1014 1015 * on cycle detection, or 0 on success.
1015 1016 */
1016 1017 static int
1017 1018 enable_fmri_rec(char *fmri, boolean_t temp)
1018 1019 {
1019 1020 scf_instance_t *inst;
1020 1021 scf_snapshot_t *snap;
1021 1022 scf_propertygroup_t *pg;
1022 1023 scf_property_t *prop;
1023 1024 scf_value_t *v;
1024 1025 scf_iter_t *pg_iter, *val_iter;
1025 1026 scf_type_t ty;
1026 1027 char *buf, *pgname;
1027 1028 ssize_t name_sz, len, sz;
1028 1029 int ret;
1029 1030 struct ht_elt *he;
1030 1031
1031 1032 len = scf_canonify_fmri(fmri, fmri, max_scf_fmri_sz);
1032 1033 if (len < 0) {
1033 1034 assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1034 1035 return (EINVAL);
1035 1036 }
1036 1037 assert(len < max_scf_fmri_sz);
1037 1038
1038 1039 switch (visited_find_or_add(fmri, &he)) {
1039 1040 case 0:
1040 1041 he->active = B_TRUE;
1041 1042 break;
1042 1043
1043 1044 case 1:
1044 1045 return (he->active ? ELOOP : 0);
1045 1046
1046 1047 case -1:
1047 1048 uu_die(emsg_nomem);
1048 1049
1049 1050 default:
1050 1051 assert(0);
1051 1052 abort();
1052 1053 }
1053 1054
1054 1055 inst = scf_instance_create(h);
1055 1056 if (inst == NULL)
1056 1057 scfdie();
1057 1058
1058 1059 switch (get_inst_mult(fmri, inst)) {
1059 1060 case 0:
1060 1061 break;
1061 1062
1062 1063 case E2BIG:
1063 1064 he->active = B_FALSE;
1064 1065 return (E2BIG);
1065 1066
1066 1067 default:
1067 1068 he->active = B_FALSE;
1068 1069 return (0);
1069 1070 }
1070 1071
1071 1072 set_inst_enabled(fmri, inst, temp, B_TRUE);
1072 1073
1073 1074 if ((snap = scf_snapshot_create(h)) == NULL ||
1074 1075 (pg = scf_pg_create(h)) == NULL ||
1075 1076 (prop = scf_property_create(h)) == NULL ||
1076 1077 (v = scf_value_create(h)) == NULL ||
1077 1078 (pg_iter = scf_iter_create(h)) == NULL ||
1078 1079 (val_iter = scf_iter_create(h)) == NULL)
1079 1080 scfdie();
1080 1081
1081 1082 buf = malloc(max_scf_fmri_sz);
1082 1083 if (buf == NULL)
1083 1084 uu_die(emsg_nomem);
1084 1085
1085 1086 name_sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
1086 1087 if (name_sz < 0)
1087 1088 scfdie();
1088 1089 ++name_sz;
1089 1090 pgname = malloc(name_sz);
1090 1091 if (pgname == NULL)
1091 1092 uu_die(emsg_nomem);
1092 1093
1093 1094 if (scf_instance_get_snapshot(inst, "running", snap) != 0) {
1094 1095 if (scf_error() != SCF_ERROR_NOT_FOUND)
1095 1096 scfdie();
1096 1097
1097 1098 scf_snapshot_destroy(snap);
1098 1099 snap = NULL;
1099 1100 }
1100 1101
1101 1102 /* Enable restarter */
1102 1103 if (scf_instance_get_pg_composed(inst, snap, SCF_PG_GENERAL, pg) != 0) {
1103 1104 if (scf_error() != SCF_ERROR_NOT_FOUND)
1104 1105 scfdie();
1105 1106
1106 1107 uu_warn(gettext("\"%s\" is misconfigured (lacks \"%s\" "
1107 1108 "property group).\n"), fmri, SCF_PG_GENERAL);
1108 1109 ret = 0;
1109 1110 goto out;
1110 1111 }
1111 1112
1112 1113 sz = get_astring_prop(pg, SCF_PROPERTY_RESTARTER, prop, v, buf,
1113 1114 max_scf_fmri_sz);
1114 1115 if (sz > max_scf_fmri_sz) {
1115 1116 uu_warn(gettext("\"%s\" is misconfigured (the value of "
1116 1117 "\"%s/%s\" is too long).\n"), fmri, SCF_PG_GENERAL,
1117 1118 SCF_PROPERTY_RESTARTER);
1118 1119 ret = 0;
1119 1120 goto out;
1120 1121 } else if (sz >= 0) {
1121 1122 switch (enable_fmri_rec(buf, temp)) {
1122 1123 case 0:
1123 1124 break;
1124 1125
1125 1126 case EINVAL:
1126 1127 uu_warn(gettext("Restarter FMRI for \"%s\" is "
1127 1128 "invalid.\n"), fmri);
1128 1129 break;
1129 1130
1130 1131 case E2BIG:
1131 1132 uu_warn(gettext("Restarter FMRI for \"%s\" identifies "
1132 1133 "a service with multiple instances.\n"), fmri);
1133 1134 break;
1134 1135
1135 1136 case ELOOP:
1136 1137 ret = ELOOP;
1137 1138 goto out;
1138 1139
1139 1140 default:
1140 1141 assert(0);
1141 1142 abort();
1142 1143 }
1143 1144 } else if (sz < 0) {
1144 1145 switch (-sz) {
1145 1146 case ENOENT:
1146 1147 break;
1147 1148
1148 1149 case E2BIG:
1149 1150 uu_warn(gettext("\"%s\" is misconfigured (\"%s/%s\" "
1150 1151 "property is not single-valued).\n"), fmri,
1151 1152 SCF_PG_GENERAL, SCF_PROPERTY_RESTARTER);
1152 1153 ret = 0;
1153 1154 goto out;
1154 1155
1155 1156 case EINVAL:
1156 1157 uu_warn(gettext("\"%s\" is misconfigured (\"%s/%s\" "
1157 1158 "property is not of astring type).\n"), fmri,
1158 1159 SCF_PG_GENERAL, SCF_PROPERTY_RESTARTER);
1159 1160 ret = 0;
1160 1161 goto out;
1161 1162
1162 1163 default:
1163 1164 assert(0);
1164 1165 abort();
1165 1166 }
1166 1167 }
1167 1168
1168 1169 if (scf_iter_instance_pgs_typed_composed(pg_iter, inst, snap,
1169 1170 SCF_GROUP_DEPENDENCY) == -1)
1170 1171 scfdie();
1171 1172
1172 1173 while (scf_iter_next_pg(pg_iter, pg) > 0) {
1173 1174 len = scf_pg_get_name(pg, pgname, name_sz);
1174 1175 if (len < 0)
1175 1176 scfdie();
1176 1177 assert(len < name_sz);
1177 1178
1178 1179 if (dep_get_astring(fmri, pgname, pg, SCF_PROPERTY_TYPE, prop,
1179 1180 v, buf, max_scf_fmri_sz) < 0)
1180 1181 continue;
1181 1182
1182 1183 if (strcmp(buf, "service") != 0)
1183 1184 continue;
1184 1185
1185 1186 if (dep_get_astring(fmri, pgname, pg, SCF_PROPERTY_GROUPING,
1186 1187 prop, v, buf, max_scf_fmri_sz) < 0)
1187 1188 continue;
1188 1189
1189 1190 if (strcmp(buf, SCF_DEP_EXCLUDE_ALL) == 0 ||
1190 1191 strcmp(buf, SCF_DEP_OPTIONAL_ALL) == 0)
1191 1192 continue;
1192 1193
1193 1194 if (strcmp(buf, SCF_DEP_REQUIRE_ALL) != 0 &&
1194 1195 strcmp(buf, SCF_DEP_REQUIRE_ANY) != 0) {
1195 1196 uu_warn(gettext("Dependency \"%s\" of \"%s\" has "
1196 1197 "unknown type \"%s\".\n"), pgname, fmri, buf);
1197 1198 continue;
1198 1199 }
1199 1200
1200 1201 if (scf_pg_get_property(pg, SCF_PROPERTY_ENTITIES, prop) ==
1201 1202 -1) {
1202 1203 if (scf_error() != SCF_ERROR_NOT_FOUND)
1203 1204 scfdie();
1204 1205
1205 1206 uu_warn(gettext("\"%s\" is misconfigured (\"%s\" "
1206 1207 "dependency lacks \"%s\" property.)\n"), fmri,
1207 1208 pgname, SCF_PROPERTY_ENTITIES);
1208 1209 continue;
1209 1210 }
1210 1211
1211 1212 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
1212 1213 scfdie();
1213 1214
1214 1215 if (ty != SCF_TYPE_FMRI) {
1215 1216 uu_warn(gettext("\"%s\" is misconfigured (property "
1216 1217 "\"%s/%s\" is not of fmri type).\n"), fmri, pgname,
1217 1218 SCF_PROPERTY_ENTITIES);
1218 1219 continue;
1219 1220 }
1220 1221
1221 1222 if (scf_iter_property_values(val_iter, prop) == -1)
1222 1223 scfdie();
1223 1224
1224 1225 if (strcmp(buf, SCF_DEP_REQUIRE_ANY) == 0) {
1225 1226 if (multiple_instances(val_iter, v, buf)) {
1226 1227 (void) printf(gettext("%s requires one of:\n"),
1227 1228 fmri);
1228 1229
1229 1230 if (scf_iter_property_values(val_iter, prop) !=
1230 1231 0)
1231 1232 scfdie();
1232 1233
1233 1234 for (;;) {
1234 1235 int r;
1235 1236
1236 1237 r = scf_iter_next_value(val_iter, v);
1237 1238 if (r == 0)
1238 1239 break;
1239 1240 if (r != 1)
1240 1241 scfdie();
1241 1242
1242 1243 if (scf_value_get_astring(v, buf,
1243 1244 max_scf_fmri_sz) < 0)
1244 1245 scfdie();
1245 1246
1246 1247 (void) fputs(" ", stdout);
1247 1248 (void) puts(buf);
1248 1249 }
1249 1250
1250 1251 continue;
1251 1252 }
1252 1253
1253 1254 /*
1254 1255 * Since there's only one instance, we can enable it.
1255 1256 * Reset val_iter and continue.
1256 1257 */
1257 1258 if (scf_iter_property_values(val_iter, prop) != 0)
1258 1259 scfdie();
1259 1260 }
1260 1261
1261 1262 for (;;) {
1262 1263 ret = scf_iter_next_value(val_iter, v);
1263 1264 if (ret == 0)
1264 1265 break;
1265 1266 if (ret != 1)
1266 1267 scfdie();
1267 1268
1268 1269 if (scf_value_get_astring(v, buf, max_scf_fmri_sz) ==
1269 1270 -1)
1270 1271 scfdie();
1271 1272
1272 1273 switch (enable_fmri_rec(buf, temp)) {
1273 1274 case 0:
1274 1275 break;
1275 1276
1276 1277 case EINVAL:
1277 1278 uu_warn(gettext("\"%s\" dependency of \"%s\" "
1278 1279 "has invalid FMRI \"%s\".\n"), pgname,
1279 1280 fmri, buf);
1280 1281 break;
1281 1282
1282 1283 case E2BIG:
1283 1284 uu_warn(gettext("%s depends on %s, which has "
1284 1285 "multiple instances.\n"), fmri, buf);
1285 1286 break;
1286 1287
1287 1288 case ELOOP:
1288 1289 ret = ELOOP;
1289 1290 goto out;
1290 1291
1291 1292 default:
1292 1293 assert(0);
1293 1294 abort();
1294 1295 }
1295 1296 }
1296 1297 }
1297 1298
1298 1299 ret = 0;
1299 1300
1300 1301 out:
1301 1302 he->active = B_FALSE;
1302 1303
1303 1304 free(buf);
1304 1305 free(pgname);
1305 1306
1306 1307 (void) scf_value_destroy(v);
1307 1308 scf_property_destroy(prop);
1308 1309 scf_pg_destroy(pg);
1309 1310 scf_snapshot_destroy(snap);
1310 1311 scf_iter_destroy(pg_iter);
1311 1312 scf_iter_destroy(val_iter);
1312 1313
1313 1314 return (ret);
1314 1315 }
1315 1316
1316 1317 /*
1317 1318 * fmri here is only used for verbose messages.
1318 1319 */
1319 1320 static void
1320 1321 set_inst_action(const char *fmri, const scf_instance_t *inst,
1321 1322 const char *action)
1322 1323 {
1323 1324 scf_transaction_t *tx;
1324 1325 scf_transaction_entry_t *ent;
1325 1326 scf_propertygroup_t *pg;
1326 1327 scf_property_t *prop;
1327 1328 scf_value_t *v;
1328 1329 int ret;
1329 1330 int64_t t;
1330 1331 hrtime_t timestamp;
1331 1332
1332 1333 const char * const scf_pg_restarter_actions = SCF_PG_RESTARTER_ACTIONS;
1333 1334
1334 1335 if ((pg = scf_pg_create(h)) == NULL ||
1335 1336 (prop = scf_property_create(h)) == NULL ||
1336 1337 (v = scf_value_create(h)) == NULL ||
1337 1338 (tx = scf_transaction_create(h)) == NULL ||
1338 1339 (ent = scf_entry_create(h)) == NULL)
1339 1340 scfdie();
1340 1341
1341 1342 if (restarter_setup(fmri, inst)) {
1342 1343 exit_status = 1;
1343 1344 goto out;
1344 1345 }
1345 1346
1346 1347 if (scf_instance_get_pg(inst, scf_pg_restarter_actions, pg) == -1) {
1347 1348 if (scf_error() != SCF_ERROR_NOT_FOUND)
1348 1349 scfdie();
1349 1350
1350 1351 /* Try creating the restarter_actions property group. */
1351 1352 if (scf_instance_add_pg(inst, scf_pg_restarter_actions,
1352 1353 SCF_PG_RESTARTER_ACTIONS_TYPE,
1353 1354 SCF_PG_RESTARTER_ACTIONS_FLAGS, pg) == -1) {
1354 1355 switch (scf_error()) {
1355 1356 case SCF_ERROR_EXISTS:
1356 1357 /* Someone must have added it. */
1357 1358 break;
1358 1359
1359 1360 case SCF_ERROR_PERMISSION_DENIED:
1360 1361 if (!verbose)
1361 1362 uu_warn(emsg_permission_denied, fmri);
1362 1363 else
1363 1364 uu_warn(emsg_create_pg_perm_denied,
1364 1365 fmri, scf_pg_restarter_actions);
1365 1366 goto out;
1366 1367
1367 1368 default:
1368 1369 scfdie();
1369 1370 }
1370 1371 }
1371 1372 }
1372 1373
1373 1374 /*
1374 1375 * If we lose the transaction race and need to retry, there are 2
1375 1376 * potential other winners:
1376 1377 * - another process setting actions
1377 1378 * - the restarter marking the action complete
1378 1379 * Therefore, re-read the property every time through the loop before
1379 1380 * making any decisions based on their values.
1380 1381 */
1381 1382 do {
1382 1383 timestamp = gethrtime();
1383 1384
1384 1385 if (scf_transaction_start(tx, pg) == -1) {
1385 1386 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
1386 1387 scfdie();
1387 1388
1388 1389 if (!verbose)
1389 1390 uu_warn(emsg_permission_denied, fmri);
1390 1391 else
1391 1392 uu_warn(emsg_pg_perm_denied, fmri,
1392 1393 scf_pg_restarter_actions);
1393 1394 goto out;
1394 1395 }
1395 1396
1396 1397 if (scf_pg_get_property(pg, action, prop) == -1) {
1397 1398 if (scf_error() != SCF_ERROR_NOT_FOUND)
1398 1399 scfdie();
1399 1400 if (scf_transaction_property_new(tx, ent,
1400 1401 action, SCF_TYPE_INTEGER) == -1)
1401 1402 scfdie();
1402 1403 goto action_set;
1403 1404 } else {
1404 1405 if (scf_transaction_property_change_type(tx, ent,
1405 1406 action, SCF_TYPE_INTEGER) == -1)
1406 1407 scfdie();
1407 1408 }
1408 1409
1409 1410 if (scf_property_get_value(prop, v) == -1) {
1410 1411 switch (scf_error()) {
1411 1412 case SCF_ERROR_CONSTRAINT_VIOLATED:
1412 1413 case SCF_ERROR_NOT_FOUND:
1413 1414 /* Misconfigured, so set anyway. */
1414 1415 goto action_set;
1415 1416
1416 1417 default:
1417 1418 scfdie();
1418 1419 }
1419 1420 } else {
1420 1421 if (scf_value_get_integer(v, &t) == -1) {
1421 1422 assert(scf_error() == SCF_ERROR_TYPE_MISMATCH);
1422 1423 goto action_set;
1423 1424 }
1424 1425 if (t > timestamp)
1425 1426 break;
1426 1427 }
1427 1428
1428 1429 action_set:
1429 1430 scf_value_set_integer(v, timestamp);
1430 1431 if (scf_entry_add_value(ent, v) == -1)
1431 1432 scfdie();
1432 1433
1433 1434 ret = scf_transaction_commit(tx);
1434 1435 if (ret == -1) {
1435 1436 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
1436 1437 scfdie();
1437 1438
1438 1439 if (!verbose)
1439 1440 uu_warn(emsg_permission_denied, fmri);
1440 1441 else
1441 1442 uu_warn(emsg_prop_perm_denied, fmri,
1442 1443 scf_pg_restarter_actions, action);
1443 1444 scf_transaction_reset(tx);
1444 1445 goto out;
1445 1446 }
1446 1447
1447 1448 scf_transaction_reset(tx);
1448 1449
1449 1450 if (ret == 0) {
1450 1451 if (scf_pg_update(pg) == -1)
1451 1452 scfdie();
1452 1453 }
1453 1454 } while (ret == 0);
1454 1455
1455 1456 if (verbose)
1456 1457 (void) printf(gettext("Action %s set for %s.\n"), action, fmri);
1457 1458
1458 1459 out:
1459 1460 scf_value_destroy(v);
1460 1461 scf_entry_destroy(ent);
1461 1462 scf_transaction_destroy(tx);
1462 1463 scf_property_destroy(prop);
1463 1464 scf_pg_destroy(pg);
1464 1465 }
1465 1466
1466 1467 /*
1467 1468 * Get the state of inst. state should point to a buffer of
1468 1469 * MAX_SCF_STATE_STRING_SZ bytes. Returns 0 on success or -1 if
1469 1470 * no restarter property group
1470 1471 * no state property
1471 1472 * state property is misconfigured (wrong type, not single-valued)
1472 1473 * state value is too long
1473 1474 * In these cases, fmri is used to print a warning.
1474 1475 *
1475 1476 * If pgp is non-NULL, a successful call to inst_get_state will store
1476 1477 * the SCF_PG_RESTARTER property group in *pgp, and the caller will be
1477 1478 * responsible for calling scf_pg_destroy on the property group.
1478 1479 */
1479 1480 int
1480 1481 inst_get_state(scf_instance_t *inst, char *state, const char *fmri,
1481 1482 scf_propertygroup_t **pgp)
1482 1483 {
1483 1484 scf_propertygroup_t *pg;
1484 1485 scf_property_t *prop;
1485 1486 scf_value_t *val;
1486 1487 int ret = -1;
1487 1488 ssize_t szret;
1488 1489
1489 1490 if ((pg = scf_pg_create(h)) == NULL ||
1490 1491 (prop = scf_property_create(h)) == NULL ||
1491 1492 (val = scf_value_create(h)) == NULL)
1492 1493 scfdie();
1493 1494
1494 1495 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
1495 1496 if (scf_error() != SCF_ERROR_NOT_FOUND)
1496 1497 scfdie();
1497 1498
1498 1499 uu_warn(gettext("%s is misconfigured (lacks \"%s\" property "
1499 1500 "group).\n"), fmri ? fmri : inst_get_fmri(inst),
1500 1501 SCF_PG_RESTARTER);
1501 1502 goto out;
1502 1503 }
1503 1504
1504 1505 szret = get_astring_prop(pg, SCF_PROPERTY_STATE, prop, val, state,
1505 1506 MAX_SCF_STATE_STRING_SZ);
1506 1507 if (szret < 0) {
1507 1508 switch (-szret) {
1508 1509 case ENOENT:
1509 1510 uu_warn(gettext("%s is misconfigured (\"%s\" property "
1510 1511 "group lacks \"%s\" property).\n"),
1511 1512 fmri ? fmri : inst_get_fmri(inst), SCF_PG_RESTARTER,
1512 1513 SCF_PROPERTY_STATE);
1513 1514 goto out;
1514 1515
1515 1516 case E2BIG:
1516 1517 uu_warn(gettext("%s is misconfigured (\"%s/%s\" "
1517 1518 "property is not single-valued).\n"),
1518 1519 fmri ? fmri : inst_get_fmri(inst), SCF_PG_RESTARTER,
1519 1520 SCF_PROPERTY_STATE);
1520 1521 goto out;
1521 1522
1522 1523 case EINVAL:
1523 1524 uu_warn(gettext("%s is misconfigured (\"%s/%s\" "
1524 1525 "property is not of type astring).\n"),
1525 1526 fmri ? fmri : inst_get_fmri(inst), SCF_PG_RESTARTER,
1526 1527 SCF_PROPERTY_STATE);
1527 1528 goto out;
1528 1529
1529 1530 default:
1530 1531 assert(0);
1531 1532 abort();
1532 1533 }
1533 1534 }
1534 1535 if (szret >= MAX_SCF_STATE_STRING_SZ) {
1535 1536 uu_warn(gettext("%s is misconfigured (\"%s/%s\" property value "
1536 1537 "is too long).\n"), fmri ? fmri : inst_get_fmri(inst),
1537 1538 SCF_PG_RESTARTER, SCF_PROPERTY_STATE);
1538 1539 goto out;
1539 1540 }
1540 1541
1541 1542 ret = 0;
1542 1543 if (pgp)
1543 1544 *pgp = pg;
1544 1545
1545 1546 out:
1546 1547 (void) scf_value_destroy(val);
1547 1548 scf_property_destroy(prop);
1548 1549 if (ret || pgp == NULL)
1549 1550 scf_pg_destroy(pg);
1550 1551 return (ret);
1551 1552 }
1552 1553
1553 1554 static void
1554 1555 set_astring_prop(const char *fmri, const char *pgname, const char *pgtype,
1555 1556 uint32_t pgflags, const char *propname, const char *str)
1556 1557 {
1557 1558 scf_instance_t *inst;
1558 1559 scf_propertygroup_t *pg;
1559 1560 scf_property_t *prop;
1560 1561 scf_value_t *val;
1561 1562 scf_transaction_t *tx;
1562 1563 scf_transaction_entry_t *txent;
1563 1564 int ret;
1564 1565
1565 1566 inst = scf_instance_create(h);
1566 1567 if (inst == NULL)
1567 1568 scfdie();
1568 1569
1569 1570 if (get_inst(fmri, inst) != 0)
1570 1571 return;
1571 1572
1572 1573 if ((pg = scf_pg_create(h)) == NULL ||
1573 1574 (prop = scf_property_create(h)) == NULL ||
1574 1575 (val = scf_value_create(h)) == NULL ||
1575 1576 (tx = scf_transaction_create(h)) == NULL ||
1576 1577 (txent = scf_entry_create(h)) == NULL)
1577 1578 scfdie();
1578 1579
1579 1580 if (scf_instance_get_pg(inst, pgname, pg) != SCF_SUCCESS) {
1580 1581 if (scf_error() != SCF_ERROR_NOT_FOUND)
1581 1582 scfdie();
1582 1583
1583 1584 if (scf_instance_add_pg(inst, pgname, pgtype, pgflags, pg) !=
1584 1585 SCF_SUCCESS) {
1585 1586 switch (scf_error()) {
1586 1587 case SCF_ERROR_EXISTS:
1587 1588 if (scf_instance_get_pg(inst, pgname, pg) !=
1588 1589 SCF_SUCCESS) {
1589 1590 if (scf_error() != SCF_ERROR_NOT_FOUND)
1590 1591 scfdie();
1591 1592
1592 1593 uu_warn(gettext("Repository write "
1593 1594 "contention.\n"));
1594 1595 goto out;
1595 1596 }
1596 1597 break;
1597 1598
1598 1599 case SCF_ERROR_PERMISSION_DENIED:
1599 1600 if (!verbose)
1600 1601 uu_warn(emsg_permission_denied, fmri);
1601 1602 else
1602 1603 uu_warn(emsg_create_pg_perm_denied,
1603 1604 fmri, pgname);
1604 1605 goto out;
1605 1606
1606 1607 default:
1607 1608 scfdie();
1608 1609 }
1609 1610 }
1610 1611 }
1611 1612
1612 1613 do {
1613 1614 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
1614 1615 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
1615 1616 scfdie();
1616 1617
1617 1618 if (!verbose)
1618 1619 uu_warn(emsg_permission_denied, fmri);
1619 1620 else
1620 1621 uu_warn(emsg_pg_perm_denied, fmri, pgname);
1621 1622 goto out;
1622 1623 }
1623 1624
1624 1625 if (scf_transaction_property_change_type(tx, txent, propname,
1625 1626 SCF_TYPE_ASTRING) != 0) {
1626 1627 if (scf_error() != SCF_ERROR_NOT_FOUND)
1627 1628 scfdie();
1628 1629
1629 1630 if (scf_transaction_property_new(tx, txent, propname,
1630 1631 SCF_TYPE_ASTRING) != 0)
1631 1632 scfdie();
1632 1633 }
1633 1634
1634 1635 if (scf_value_set_astring(val, str) != SCF_SUCCESS)
1635 1636 scfdie();
1636 1637
1637 1638 if (scf_entry_add_value(txent, val) != SCF_SUCCESS)
1638 1639 scfdie();
1639 1640
1640 1641 ret = scf_transaction_commit(tx);
1641 1642 if (ret == -1) {
1642 1643 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
1643 1644 scfdie();
1644 1645
1645 1646 if (!verbose)
1646 1647 uu_warn(emsg_permission_denied, fmri);
1647 1648 else
1648 1649 uu_warn(emsg_prop_perm_denied, fmri, pgname,
1649 1650 propname);
1650 1651 goto out;
1651 1652 }
1652 1653
1653 1654 if (ret == 0) {
1654 1655 scf_transaction_reset(tx);
1655 1656
1656 1657 if (scf_pg_update(pg) == -1)
1657 1658 scfdie();
1658 1659 }
1659 1660 } while (ret == 0);
1660 1661
1661 1662 out:
1662 1663 scf_transaction_destroy(tx);
1663 1664 scf_entry_destroy(txent);
1664 1665 scf_value_destroy(val);
1665 1666 scf_property_destroy(prop);
1666 1667 scf_pg_destroy(pg);
1667 1668 scf_instance_destroy(inst);
1668 1669 }
1669 1670
1670 1671
1671 1672 /*
1672 1673 * Flags to control enable and disable actions.
1673 1674 */
1674 1675 #define SET_ENABLED 0x1
1675 1676 #define SET_TEMPORARY 0x2
1676 1677 #define SET_RECURSIVE 0x4
1677 1678
1678 1679 static int
1679 1680 set_fmri_enabled(void *data, scf_walkinfo_t *wip)
1680 1681 {
1681 1682 int flags = (int)data;
1682 1683
1683 1684 assert(wip->inst != NULL);
1684 1685 assert(wip->pg == NULL);
1685 1686
1686 1687 if (svcsearch) {
1687 1688 char state[MAX_SCF_STATE_STRING_SZ];
1688 1689
1689 1690 if (inst_get_state(wip->inst, state, wip->fmri, NULL) != 0)
1690 1691 return (0);
1691 1692 if (strcmp(state, svcstate) != 0)
1692 1693 return (0);
1693 1694 }
1694 1695
1695 1696 if (flags & SET_RECURSIVE) {
1696 1697 char *fmri_buf = malloc(max_scf_fmri_sz);
1697 1698 if (fmri_buf == NULL)
1698 1699 uu_die(emsg_nomem);
1699 1700
1700 1701 visited = calloc(HT_BUCKETS, sizeof (*visited));
1701 1702 if (visited == NULL)
1702 1703 uu_die(emsg_nomem);
1703 1704
1704 1705 /* scf_walk_fmri() guarantees that fmri isn't too long */
1705 1706 assert(strlen(wip->fmri) <= max_scf_fmri_sz);
1706 1707 (void) strlcpy(fmri_buf, wip->fmri, max_scf_fmri_sz);
1707 1708
1708 1709 switch (enable_fmri_rec(fmri_buf, (flags & SET_TEMPORARY))) {
1709 1710 case E2BIG:
1710 1711 uu_warn(gettext("operation on service %s is ambiguous; "
1711 1712 "instance specification needed.\n"), fmri_buf);
1712 1713 break;
1713 1714
1714 1715 case ELOOP:
1715 1716 uu_warn(gettext("%s: Dependency cycle detected.\n"),
1716 1717 fmri_buf);
1717 1718 }
1718 1719
1719 1720 free(visited);
1720 1721 free(fmri_buf);
1721 1722
1722 1723 } else {
1723 1724 set_inst_enabled(wip->fmri, wip->inst,
1724 1725 (flags & SET_TEMPORARY) != 0, (flags & SET_ENABLED) != 0);
1725 1726 }
1726 1727
1727 1728 return (0);
1728 1729 }
1729 1730
1730 1731 /* ARGSUSED */
1731 1732 static int
1732 1733 wait_fmri_enabled(void *data, scf_walkinfo_t *wip)
1733 1734 {
1734 1735 scf_propertygroup_t *pg = NULL;
1735 1736 char state[MAX_SCF_STATE_STRING_SZ];
1736 1737
1737 1738 assert(wip->inst != NULL);
1738 1739 assert(wip->pg == NULL);
1739 1740
1740 1741 do {
1741 1742 if (pg)
1742 1743 scf_pg_destroy(pg);
1743 1744 if (inst_get_state(wip->inst, state, wip->fmri, &pg) != 0) {
1744 1745 exit_status = EXIT_SVC_FAILURE;
1745 1746 return (0);
1746 1747 }
1747 1748
1748 1749 if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0 ||
1749 1750 strcmp(state, SCF_STATE_STRING_DEGRADED) == 0) {
1750 1751 /*
1751 1752 * We're done.
1752 1753 */
1753 1754 goto out;
1754 1755 }
1755 1756
1756 1757 if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) {
1757 1758 /*
1758 1759 * The service is ill.
1759 1760 */
1760 1761 uu_warn(gettext("Instance \"%s\" is in maintenance"
1761 1762 " state.\n"), wip->fmri);
1762 1763 exit_status = EXIT_SVC_FAILURE;
1763 1764 goto out;
1764 1765 }
1765 1766
1766 1767 if (!is_enabled(wip->inst)) {
1767 1768 /*
1768 1769 * Someone stepped in and disabled the service.
1769 1770 */
1770 1771 uu_warn(gettext("Instance \"%s\" has been disabled"
1771 1772 " by another entity.\n"), wip->fmri);
1772 1773 exit_status = EXIT_SVC_FAILURE;
1773 1774 goto out;
1774 1775 }
1775 1776
1776 1777 if (!has_potential(wip->inst, B_FALSE)) {
1777 1778 /*
1778 1779 * Our dependencies aren't met. We'll never
1779 1780 * amount to anything.
1780 1781 */
1781 1782 uu_warn(gettext("Instance \"%s\" has unsatisfied"
1782 1783 " dependencies.\n"), wip->fmri);
1783 1784 /*
1784 1785 * EXIT_SVC_FAILURE takes precedence over
1785 1786 * EXIT_DEP_FAILURE
1786 1787 */
1787 1788 if (exit_status == 0)
1788 1789 exit_status = EXIT_DEP_FAILURE;
1789 1790 goto out;
1790 1791 }
1791 1792 } while (_scf_pg_wait(pg, WAIT_INTERVAL) >= 0);
1792 1793 scfdie();
1793 1794 /* NOTREACHED */
1794 1795
1795 1796 out:
1796 1797 scf_pg_destroy(pg);
1797 1798 return (0);
1798 1799 }
1799 1800
1800 1801 /* ARGSUSED */
1801 1802 static int
1802 1803 wait_fmri_disabled(void *data, scf_walkinfo_t *wip)
1803 1804 {
1804 1805 scf_propertygroup_t *pg = NULL;
1805 1806 char state[MAX_SCF_STATE_STRING_SZ];
1806 1807
1807 1808 assert(wip->inst != NULL);
1808 1809 assert(wip->pg == NULL);
1809 1810
1810 1811 do {
1811 1812 if (pg)
1812 1813 scf_pg_destroy(pg);
1813 1814 if (inst_get_state(wip->inst, state, wip->fmri, &pg) != 0) {
1814 1815 exit_status = EXIT_SVC_FAILURE;
1815 1816 return (0);
1816 1817 }
1817 1818
1818 1819 if (strcmp(state, SCF_STATE_STRING_DISABLED) == 0) {
1819 1820 /*
1820 1821 * We're done.
1821 1822 */
1822 1823 goto out;
1823 1824 }
1824 1825
1825 1826 if (is_enabled(wip->inst)) {
1826 1827 /*
1827 1828 * Someone stepped in and enabled the service.
1828 1829 */
1829 1830 uu_warn(gettext("Instance \"%s\" has been enabled"
1830 1831 " by another entity.\n"), wip->fmri);
1831 1832 exit_status = EXIT_SVC_FAILURE;
1832 1833 goto out;
1833 1834 }
1834 1835
1835 1836 if (!has_potential(wip->inst, B_TRUE)) {
1836 1837 /*
1837 1838 * Our restarter is hopeless.
1838 1839 */
1839 1840 uu_warn(gettext("Restarter for instance \"%s\" is"
1840 1841 " unavailable.\n"), wip->fmri);
1841 1842 /*
1842 1843 * EXIT_SVC_FAILURE takes precedence over
1843 1844 * EXIT_DEP_FAILURE
1844 1845 */
1845 1846 if (exit_status == 0)
1846 1847 exit_status = EXIT_DEP_FAILURE;
1847 1848 goto out;
1848 1849 }
1849 1850
1850 1851 } while (_scf_pg_wait(pg, WAIT_INTERVAL) >= 0);
1851 1852 scfdie();
1852 1853 /* NOTREACHED */
1853 1854
1854 1855 out:
1855 1856 scf_pg_destroy(pg);
1856 1857 return (0);
1857 1858 }
1858 1859
1859 1860 /* ARGSUSED */
1860 1861 static int
1861 1862 clear_instance(void *data, scf_walkinfo_t *wip)
1862 1863 {
1863 1864 char state[MAX_SCF_STATE_STRING_SZ];
1864 1865
1865 1866 assert(wip->inst != NULL);
1866 1867 assert(wip->pg == NULL);
1867 1868
1868 1869 if (inst_get_state(wip->inst, state, wip->fmri, NULL) != 0)
1869 1870 return (0);
1870 1871
1871 1872 if (svcsearch && strcmp(state, svcstate) != 0)
1872 1873 return (0);
1873 1874
1874 1875 if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) {
1875 1876 set_inst_action(wip->fmri, wip->inst, SCF_PROPERTY_MAINT_OFF);
1876 1877 } else if (strcmp(state, SCF_STATE_STRING_DEGRADED) ==
1877 1878 0) {
1878 1879 set_inst_action(wip->fmri, wip->inst, SCF_PROPERTY_RESTORE);
1879 1880 } else {
1880 1881 uu_warn(gettext("Instance \"%s\" is not in a "
1881 1882 "maintenance or degraded state.\n"), wip->fmri);
1882 1883
1883 1884 exit_status = 1;
1884 1885 }
1885 1886
1886 1887 return (0);
1887 1888 }
1888 1889
1889 1890 static int
1890 1891 set_fmri_action(void *action, scf_walkinfo_t *wip)
1891 1892 {
1892 1893 assert(wip->inst != NULL && wip->pg == NULL);
1893 1894
1894 1895 if (svcsearch) {
1895 1896 char state[MAX_SCF_STATE_STRING_SZ];
1896 1897
1897 1898 if (inst_get_state(wip->inst, state, wip->fmri, NULL) != 0)
1898 1899 return (0);
1899 1900 if (strcmp(state, svcstate) != 0)
1900 1901 return (0);
1901 1902 }
1902 1903
1903 1904 set_inst_action(wip->fmri, wip->inst, action);
1904 1905
1905 1906 return (0);
1906 1907 }
1907 1908
1908 1909 /*
1909 1910 * Flags to control 'mark' action.
1910 1911 */
1911 1912 #define MARK_IMMEDIATE 0x1
1912 1913 #define MARK_TEMPORARY 0x2
1913 1914
1914 1915 static int
1915 1916 force_degraded(void *data, scf_walkinfo_t *wip)
1916 1917 {
1917 1918 int flags = (int)data;
1918 1919 char state[MAX_SCF_STATE_STRING_SZ];
1919 1920
1920 1921 if (inst_get_state(wip->inst, state, wip->fmri, NULL) != 0) {
1921 1922 exit_status = 1;
1922 1923 return (0);
1923 1924 }
↓ open down ↓ |
1886 lines elided |
↑ open up ↑ |
1924 1925
1925 1926 if (svcsearch && strcmp(state, svcstate) != 0)
1926 1927 return (0);
1927 1928
1928 1929 if (strcmp(state, SCF_STATE_STRING_ONLINE) != 0) {
1929 1930 uu_warn(gettext("Instance \"%s\" is not online.\n"), wip->fmri);
1930 1931 exit_status = 1;
1931 1932 return (0);
1932 1933 }
1933 1934
1935 + if ((flags & MARK_TEMPORARY) == 0) {
1936 + uu_warn(gettext("Instance \"%s\" cannot be degraded "
1937 + "permantently.\n"), wip->fmri);
1938 + exit_status = 1;
1939 + return (0);
1940 + }
1941 +
1934 1942 set_inst_action(wip->fmri, wip->inst, (flags & MARK_IMMEDIATE) ?
1935 1943 SCF_PROPERTY_DEGRADE_IMMEDIATE : SCF_PROPERTY_DEGRADED);
1936 1944
1937 1945 return (0);
1938 1946 }
1939 1947
1940 1948 static int
1941 1949 force_maintenance(void *data, scf_walkinfo_t *wip)
1942 1950 {
1943 1951 int flags = (int)data;
1944 1952 const char *prop;
1945 1953
1946 1954 if (svcsearch) {
1947 1955 char state[MAX_SCF_STATE_STRING_SZ];
1948 1956
1949 1957 if (inst_get_state(wip->inst, state, wip->fmri, NULL) != 0)
1950 1958 return (0);
1951 1959 if (strcmp(state, svcstate) != 0)
1952 1960 return (0);
1953 1961 }
1954 1962
1955 1963 if (flags & MARK_IMMEDIATE) {
1956 1964 prop = (flags & MARK_TEMPORARY) ?
1957 1965 SCF_PROPERTY_MAINT_ON_IMMTEMP :
1958 1966 SCF_PROPERTY_MAINT_ON_IMMEDIATE;
1959 1967 } else {
1960 1968 prop = (flags & MARK_TEMPORARY) ?
1961 1969 SCF_PROPERTY_MAINT_ON_TEMPORARY :
1962 1970 SCF_PROPERTY_MAINT_ON;
1963 1971 }
1964 1972
1965 1973 set_inst_action(wip->fmri, wip->inst, prop);
1966 1974
1967 1975 return (0);
1968 1976 }
1969 1977
1970 1978 static void
1971 1979 set_milestone(const char *fmri, boolean_t temporary)
1972 1980 {
1973 1981 scf_instance_t *inst;
1974 1982 scf_propertygroup_t *pg;
1975 1983 int r;
1976 1984
1977 1985 if (temporary) {
1978 1986 set_astring_prop(SCF_SERVICE_STARTD, SCF_PG_OPTIONS_OVR,
1979 1987 SCF_PG_OPTIONS_OVR_TYPE, SCF_PG_OPTIONS_OVR_FLAGS,
1980 1988 SCF_PROPERTY_MILESTONE, fmri);
1981 1989 return;
1982 1990 }
1983 1991
1984 1992 if ((inst = scf_instance_create(h)) == NULL ||
1985 1993 (pg = scf_pg_create(h)) == NULL)
1986 1994 scfdie();
1987 1995
1988 1996 if (get_inst(SCF_SERVICE_STARTD, inst) != 0) {
1989 1997 scf_instance_destroy(inst);
1990 1998 return;
1991 1999 }
1992 2000
1993 2001 /*
1994 2002 * Set the persistent milestone before deleting the override so we don't
1995 2003 * glitch.
1996 2004 */
1997 2005 set_astring_prop(SCF_SERVICE_STARTD, SCF_PG_OPTIONS,
1998 2006 SCF_PG_OPTIONS_TYPE, SCF_PG_OPTIONS_FLAGS, SCF_PROPERTY_MILESTONE,
1999 2007 fmri);
2000 2008
2001 2009 r = scf_instance_delete_prop(inst, SCF_PG_OPTIONS_OVR,
2002 2010 SCF_PROPERTY_MILESTONE);
2003 2011 switch (r) {
2004 2012 case 0:
2005 2013 break;
2006 2014
2007 2015 case ECANCELED:
2008 2016 uu_warn(emsg_no_service, fmri);
2009 2017 exit_status = 1;
2010 2018 goto out;
2011 2019
2012 2020 case EPERM:
2013 2021 uu_warn(gettext("Could not delete %s/%s property of "
2014 2022 "%s: permission denied.\n"), SCF_PG_OPTIONS_OVR,
2015 2023 SCF_PROPERTY_MILESTONE, SCF_SERVICE_STARTD);
2016 2024 exit_status = 1;
2017 2025 goto out;
2018 2026
2019 2027 case EACCES:
2020 2028 uu_warn(gettext("Could not delete %s/%s property of "
2021 2029 "%s: access denied.\n"), SCF_PG_OPTIONS_OVR,
2022 2030 SCF_PROPERTY_MILESTONE, SCF_SERVICE_STARTD);
2023 2031 exit_status = 1;
2024 2032 goto out;
2025 2033
2026 2034 case EROFS:
2027 2035 uu_warn(gettext("Could not delete %s/%s property of "
2028 2036 "%s: backend read-only.\n"), SCF_PG_OPTIONS_OVR,
2029 2037 SCF_PROPERTY_MILESTONE, SCF_SERVICE_STARTD);
2030 2038 exit_status = 1;
2031 2039 goto out;
2032 2040
2033 2041 default:
2034 2042 bad_error("scf_instance_delete_prop", r);
2035 2043 }
2036 2044
2037 2045 out:
2038 2046 scf_pg_destroy(pg);
2039 2047 scf_instance_destroy(inst);
2040 2048 }
2041 2049
2042 2050 static char const *milestones[] = {
2043 2051 SCF_MILESTONE_SINGLE_USER,
2044 2052 SCF_MILESTONE_MULTI_USER,
2045 2053 SCF_MILESTONE_MULTI_USER_SERVER,
2046 2054 NULL
2047 2055 };
2048 2056
2049 2057 static void
2050 2058 usage_milestone(void)
2051 2059 {
2052 2060 const char **ms;
2053 2061
2054 2062 (void) fprintf(stderr, gettext(
2055 2063 "Usage: svcadm milestone [-d] <milestone>\n\n"
2056 2064 "\t-d\tmake the specified milestone the default for system boot\n\n"
2057 2065 "\tMilestones can be specified using an FMRI or abbreviation.\n"
2058 2066 "\tThe major milestones are as follows:\n\n"
2059 2067 "\tall\n"
2060 2068 "\tnone\n"));
2061 2069
2062 2070 for (ms = milestones; *ms != NULL; ms++)
2063 2071 (void) fprintf(stderr, "\t%s\n", *ms);
2064 2072
2065 2073 exit(UU_EXIT_USAGE);
2066 2074 }
2067 2075
2068 2076 static const char *
2069 2077 validate_milestone(const char *milestone)
2070 2078 {
2071 2079 const char **ms;
2072 2080 const char *tmp;
2073 2081 size_t len;
2074 2082
2075 2083 if (strcmp(milestone, "all") == 0)
2076 2084 return (milestone);
2077 2085
2078 2086 if (strcmp(milestone, "none") == 0)
2079 2087 return (milestone);
2080 2088
2081 2089 /*
2082 2090 * Determine if this is a full or partial milestone
2083 2091 */
2084 2092 for (ms = milestones; *ms != NULL; ms++) {
2085 2093 if ((tmp = strstr(*ms, milestone)) != NULL) {
2086 2094 len = strlen(milestone);
2087 2095
2088 2096 /*
2089 2097 * The beginning of the string must align with the start
2090 2098 * of a milestone fmri, or on the boundary between
2091 2099 * elements. The end of the string must align with the
2092 2100 * end of the milestone, or at the instance boundary.
2093 2101 */
2094 2102 if ((tmp == *ms || tmp[-1] == '/') &&
2095 2103 (tmp[len] == '\0' || tmp[len] == ':'))
2096 2104 return (*ms);
2097 2105 }
2098 2106 }
2099 2107
2100 2108 (void) fprintf(stderr,
2101 2109 gettext("\"%s\" is not a valid major milestone.\n"), milestone);
2102 2110
2103 2111 usage_milestone();
2104 2112 /* NOTREACHED */
2105 2113 }
2106 2114
2107 2115 /*PRINTFLIKE1*/
2108 2116 static void
2109 2117 pr_warn(const char *format, ...)
2110 2118 {
2111 2119 const char *pname = uu_getpname();
2112 2120 va_list alist;
2113 2121
2114 2122 va_start(alist, format);
2115 2123
2116 2124 if (pname != NULL)
2117 2125 (void) fprintf(stderr, "%s", pname);
2118 2126
2119 2127 if (g_zonename != NULL)
2120 2128 (void) fprintf(stderr, " (%s)", g_zonename);
2121 2129
2122 2130 (void) fprintf(stderr, ": ");
2123 2131
2124 2132 (void) vfprintf(stderr, format, alist);
2125 2133
2126 2134 if (strrchr(format, '\n') == NULL)
2127 2135 (void) fprintf(stderr, ": %s\n", strerror(errno));
2128 2136
2129 2137 va_end(alist);
2130 2138 }
2131 2139
2132 2140 /*ARGSUSED*/
2133 2141 static void
2134 2142 quiet(const char *fmt, ...)
2135 2143 {
2136 2144 /* Do nothing */
2137 2145 }
2138 2146
2139 2147 int
2140 2148 main(int argc, char *argv[])
2141 2149 {
2142 2150 int o;
2143 2151 int err;
2144 2152 int sw_back;
2145 2153 boolean_t do_zones = B_FALSE;
2146 2154 boolean_t do_a_zone = B_FALSE;
2147 2155 char zonename[ZONENAME_MAX];
2148 2156 uint_t nzents = 0, zent = 0;
2149 2157 zoneid_t *zids = NULL;
2150 2158 int orig_optind, orig_argc;
2151 2159 char **orig_argv;
2152 2160
2153 2161 (void) setlocale(LC_ALL, "");
2154 2162 (void) textdomain(TEXT_DOMAIN);
2155 2163
2156 2164 (void) uu_setpname(argv[0]);
2157 2165
2158 2166 if (argc < 2)
2159 2167 usage();
2160 2168
2161 2169 max_scf_fmri_sz = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
2162 2170 if (max_scf_fmri_sz < 0)
2163 2171 scfdie();
2164 2172 ++max_scf_fmri_sz;
2165 2173
2166 2174 scratch_fmri = malloc(max_scf_fmri_sz);
2167 2175 if (scratch_fmri == NULL)
2168 2176 uu_die(emsg_nomem);
2169 2177
2170 2178 while ((o = getopt(argc, argv, "S:vZz:")) != -1) {
2171 2179 switch (o) {
2172 2180 case 'S':
2173 2181 (void) strlcpy(svcstate, optarg, sizeof (svcstate));
2174 2182 svcsearch = B_TRUE;
2175 2183 break;
2176 2184
2177 2185 case 'v':
2178 2186 verbose = 1;
2179 2187 break;
2180 2188
2181 2189 case 'z':
2182 2190 if (getzoneid() != GLOBAL_ZONEID)
2183 2191 uu_die(gettext("svcadm -z may only be used "
2184 2192 "from the global zone\n"));
2185 2193 if (do_zones)
2186 2194 usage();
2187 2195
2188 2196 (void) strlcpy(zonename, optarg, sizeof (zonename));
2189 2197 do_a_zone = B_TRUE;
2190 2198 break;
2191 2199
2192 2200 case 'Z':
2193 2201 if (getzoneid() != GLOBAL_ZONEID)
2194 2202 uu_die(gettext("svcadm -Z may only be used "
2195 2203 "from the global zone\n"));
2196 2204 if (do_a_zone)
2197 2205 usage();
2198 2206
2199 2207 do_zones = B_TRUE;
2200 2208 break;
2201 2209
2202 2210 default:
2203 2211 usage();
2204 2212 }
2205 2213 }
2206 2214
2207 2215 while (do_zones) {
2208 2216 uint_t found;
2209 2217
2210 2218 if (zone_list(NULL, &nzents) != 0)
2211 2219 uu_die(gettext("could not get number of zones"));
2212 2220
2213 2221 if ((zids = malloc(nzents * sizeof (zoneid_t))) == NULL) {
2214 2222 uu_die(gettext("could not allocate array for "
2215 2223 "%d zone IDs"), nzents);
2216 2224 }
2217 2225
2218 2226 found = nzents;
2219 2227
2220 2228 if (zone_list(zids, &found) != 0)
2221 2229 uu_die(gettext("could not get zone list"));
2222 2230
2223 2231 /*
2224 2232 * If the number of zones has not changed between our calls to
2225 2233 * zone_list(), we're done -- otherwise, we must free our array
2226 2234 * of zone IDs and take another lap.
2227 2235 */
2228 2236 if (found == nzents)
2229 2237 break;
2230 2238
2231 2239 free(zids);
2232 2240 }
2233 2241
2234 2242 emsg_permission_denied = gettext("%s: Permission denied.\n");
2235 2243 emsg_nomem = gettext("Out of memory.\n");
2236 2244 emsg_create_pg_perm_denied = gettext("%s: Couldn't create \"%s\" "
2237 2245 "property group (permission denied).\n");
2238 2246 emsg_pg_perm_denied = gettext("%s: Couldn't modify \"%s\" property "
2239 2247 "group (permission denied).\n");
2240 2248 emsg_prop_perm_denied = gettext("%s: Couldn't modify \"%s/%s\" "
2241 2249 "property (permission denied).\n");
2242 2250 emsg_no_service = gettext("No such service \"%s\".\n");
2243 2251
2244 2252 orig_optind = optind;
2245 2253 orig_argc = argc;
2246 2254 orig_argv = argv;
2247 2255
2248 2256 again:
2249 2257 h = scf_handle_create(SCF_VERSION);
2250 2258 if (h == NULL)
2251 2259 scfdie();
2252 2260
2253 2261 if (do_zones) {
2254 2262 zone_status_t status;
2255 2263
2256 2264 if (zone_getattr(zids[zent], ZONE_ATTR_STATUS, &status,
2257 2265 sizeof (status)) < 0 || status != ZONE_IS_RUNNING) {
2258 2266 /*
2259 2267 * If this zone is not running or we cannot
2260 2268 * get its status, we do not want to attempt
2261 2269 * to bind an SCF handle to it, lest we
2262 2270 * accidentally interfere with a zone that
2263 2271 * is not yet running by looking up a door
2264 2272 * to its svc.configd (which could potentially
2265 2273 * block a mount with an EBUSY).
2266 2274 */
2267 2275 zent++;
2268 2276 goto nextzone;
2269 2277 }
2270 2278
2271 2279 if (getzonenamebyid(zids[zent++], zonename,
2272 2280 sizeof (zonename)) < 0) {
2273 2281 uu_warn(gettext("could not get name for "
2274 2282 "zone %d; ignoring"), zids[zent - 1]);
2275 2283 goto nextzone;
2276 2284 }
2277 2285
2278 2286 g_zonename = zonename;
2279 2287 }
2280 2288
2281 2289 if (do_a_zone || do_zones) {
2282 2290 scf_value_t *zone;
2283 2291
2284 2292 if ((zone = scf_value_create(h)) == NULL)
2285 2293 scfdie();
2286 2294
2287 2295 if (scf_value_set_astring(zone, zonename) != SCF_SUCCESS)
2288 2296 scfdie();
2289 2297
2290 2298 if (scf_handle_decorate(h, "zone", zone) != SCF_SUCCESS) {
2291 2299 if (do_a_zone) {
2292 2300 uu_die(gettext("invalid zone '%s'\n"), optarg);
2293 2301 } else {
2294 2302 scf_value_destroy(zone);
2295 2303 goto nextzone;
2296 2304 }
2297 2305 }
2298 2306
2299 2307 scf_value_destroy(zone);
2300 2308 }
2301 2309
2302 2310 if (scf_handle_bind(h) == -1) {
2303 2311 if (do_zones)
2304 2312 goto nextzone;
2305 2313
2306 2314 uu_die(gettext("Couldn't bind to configuration repository: "
2307 2315 "%s.\n"), scf_strerror(scf_error()));
2308 2316 }
2309 2317
2310 2318 optind = orig_optind;
2311 2319 argc = orig_argc;
2312 2320 argv = orig_argv;
2313 2321
2314 2322 if (optind >= argc)
2315 2323 usage();
2316 2324
2317 2325 if (strcmp(argv[optind], "enable") == 0) {
2318 2326 int flags = SET_ENABLED;
2319 2327 int wait = 0;
2320 2328 int error = 0;
2321 2329
2322 2330 ++optind;
2323 2331
2324 2332 while ((o = getopt(argc, argv, "rst")) != -1) {
2325 2333 if (o == 'r')
2326 2334 flags |= SET_RECURSIVE;
2327 2335 else if (o == 't')
2328 2336 flags |= SET_TEMPORARY;
2329 2337 else if (o == 's')
2330 2338 wait = 1;
2331 2339 else if (o == '?')
2332 2340 usage();
2333 2341 else {
2334 2342 assert(0);
2335 2343 abort();
2336 2344 }
2337 2345 }
2338 2346 argc -= optind;
2339 2347 argv += optind;
2340 2348
2341 2349 if (argc == 0 && !svcsearch)
2342 2350 usage();
2343 2351
2344 2352 if (argc > 0 && svcsearch)
2345 2353 usage();
2346 2354
2347 2355 /*
2348 2356 * We want to continue with -s processing if we had
2349 2357 * invalid options, but not if an enable failed. We
2350 2358 * squelch output the second time we walk fmris; we saw
2351 2359 * the errors the first time.
2352 2360 */
2353 2361 if ((err = scf_walk_fmri(h, argc, argv, WALK_FLAGS,
2354 2362 set_fmri_enabled, (void *)flags, &error, pr_warn)) != 0) {
2355 2363
2356 2364 pr_warn(gettext("failed to iterate over "
2357 2365 "instances: %s\n"), scf_strerror(err));
2358 2366 exit_status = UU_EXIT_FATAL;
2359 2367
2360 2368 } else if (wait && exit_status == 0 &&
2361 2369 (err = scf_walk_fmri(h, argc, argv, WALK_FLAGS,
2362 2370 wait_fmri_enabled, (void *)flags, &error, quiet)) != 0) {
2363 2371
2364 2372 pr_warn(gettext("failed to iterate over "
2365 2373 "instances: %s\n"), scf_strerror(err));
2366 2374 exit_status = UU_EXIT_FATAL;
2367 2375 }
2368 2376
2369 2377 if (error > 0)
2370 2378 exit_status = error;
2371 2379
2372 2380 } else if (strcmp(argv[optind], "disable") == 0) {
2373 2381 int flags = 0;
2374 2382 int wait = 0;
2375 2383 int error = 0;
2376 2384
2377 2385 ++optind;
2378 2386
2379 2387 while ((o = getopt(argc, argv, "st")) != -1) {
2380 2388 if (o == 't')
2381 2389 flags |= SET_TEMPORARY;
2382 2390 else if (o == 's')
2383 2391 wait = 1;
2384 2392 else if (o == '?')
2385 2393 usage();
2386 2394 else {
2387 2395 assert(0);
2388 2396 abort();
2389 2397 }
2390 2398 }
2391 2399 argc -= optind;
2392 2400 argv += optind;
2393 2401
2394 2402 if (argc == 0 && !svcsearch)
2395 2403 usage();
2396 2404
2397 2405 if (argc > 0 && svcsearch)
2398 2406 usage();
2399 2407
2400 2408 /*
2401 2409 * We want to continue with -s processing if we had
2402 2410 * invalid options, but not if a disable failed. We
2403 2411 * squelch output the second time we walk fmris; we saw
2404 2412 * the errors the first time.
2405 2413 */
2406 2414 if ((err = scf_walk_fmri(h, argc, argv, WALK_FLAGS,
2407 2415 set_fmri_enabled, (void *)flags, &exit_status,
2408 2416 pr_warn)) != 0) {
2409 2417
2410 2418 pr_warn(gettext("failed to iterate over "
2411 2419 "instances: %s\n"), scf_strerror(err));
2412 2420 exit_status = UU_EXIT_FATAL;
2413 2421
2414 2422 } else if (wait && exit_status == 0 &&
2415 2423 (err = scf_walk_fmri(h, argc, argv, WALK_FLAGS,
2416 2424 wait_fmri_disabled, (void *)flags, &error, quiet)) != 0) {
2417 2425
2418 2426 pr_warn(gettext("failed to iterate over "
2419 2427 "instances: %s\n"), scf_strerror(err));
2420 2428 exit_status = UU_EXIT_FATAL;
2421 2429 }
2422 2430
2423 2431 if (error > 0)
2424 2432 exit_status = error;
2425 2433
2426 2434 } else if (strcmp(argv[optind], "restart") == 0) {
2427 2435 boolean_t do_dump = B_FALSE;
2428 2436
2429 2437 ++optind;
2430 2438
2431 2439 while ((o = getopt(argc, argv, "d")) != -1) {
2432 2440 if (o == 'd')
2433 2441 do_dump = B_TRUE;
2434 2442 else if (o == '?')
2435 2443 usage();
2436 2444 else {
2437 2445 assert(0);
2438 2446 abort();
2439 2447 }
2440 2448 }
2441 2449 argc -= optind;
2442 2450 argv += optind;
2443 2451
2444 2452 if (argc == 0 && !svcsearch)
2445 2453 usage();
2446 2454
2447 2455 if (argc > 0 && svcsearch)
2448 2456 usage();
2449 2457
2450 2458 if (do_dump) {
2451 2459 if ((err = scf_walk_fmri(h, argc, argv, WALK_FLAGS,
2452 2460 set_fmri_action, (void *)SCF_PROPERTY_DODUMP,
2453 2461 &exit_status, pr_warn)) != 0) {
2454 2462 pr_warn(gettext("failed to iterate over "
2455 2463 "instances: %s\n"), scf_strerror(err));
2456 2464 exit_status = UU_EXIT_FATAL;
2457 2465 }
2458 2466 }
2459 2467
2460 2468 if ((err = scf_walk_fmri(h, argc, argv, WALK_FLAGS,
2461 2469 set_fmri_action, (void *)SCF_PROPERTY_RESTART, &exit_status,
2462 2470 pr_warn)) != 0) {
2463 2471 pr_warn(gettext("failed to iterate over "
2464 2472 "instances: %s\n"), scf_strerror(err));
2465 2473 exit_status = UU_EXIT_FATAL;
2466 2474 }
2467 2475
2468 2476 } else if (strcmp(argv[optind], "refresh") == 0) {
2469 2477 ++optind;
2470 2478 argc -= optind;
2471 2479 argv += optind;
2472 2480
2473 2481 if (argc == 0 && !svcsearch)
2474 2482 usage();
2475 2483
2476 2484 if (argc > 0 && svcsearch)
2477 2485 usage();
2478 2486
2479 2487 if ((err = scf_walk_fmri(h, argc, argv, WALK_FLAGS,
2480 2488 set_fmri_action, (void *)SCF_PROPERTY_REFRESH, &exit_status,
2481 2489 pr_warn)) != 0) {
2482 2490 pr_warn(gettext("failed to iterate over "
2483 2491 "instances: %s\n"), scf_strerror(scf_error()));
2484 2492 exit_status = UU_EXIT_FATAL;
2485 2493 }
2486 2494
2487 2495 } else if (strcmp(argv[optind], "mark") == 0) {
2488 2496 int flags = 0;
2489 2497 scf_walk_callback callback;
2490 2498
2491 2499 ++optind;
2492 2500
2493 2501 while ((o = getopt(argc, argv, "It")) != -1) {
2494 2502 if (o == 'I')
2495 2503 flags |= MARK_IMMEDIATE;
2496 2504 else if (o == 't')
2497 2505 flags |= MARK_TEMPORARY;
2498 2506 else if (o == '?')
2499 2507 usage();
↓ open down ↓ |
556 lines elided |
↑ open up ↑ |
2500 2508 else {
2501 2509 assert(0);
2502 2510 abort();
2503 2511 }
2504 2512 }
2505 2513
2506 2514 if (argc - optind < 2)
2507 2515 usage();
2508 2516
2509 2517 if (strcmp(argv[optind], "degraded") == 0) {
2510 - if (flags & MARK_TEMPORARY)
2511 - uu_xdie(UU_EXIT_USAGE, gettext("-t may not be "
2512 - "used with degraded.\n"));
2513 2518 callback = force_degraded;
2514 -
2515 2519 } else if (strcmp(argv[optind], "maintenance") == 0) {
2516 2520 callback = force_maintenance;
2517 2521 } else {
2518 2522 usage();
2519 2523 }
2520 2524
2521 2525 optind++;
2522 2526 argc -= optind;
2523 2527 argv += optind;
2524 2528
2525 2529 if (argc == 0 && !svcsearch)
2526 2530 usage();
2527 2531
2528 2532 if (argc > 0 && svcsearch)
2529 2533 usage();
2530 2534
2531 2535 if ((err = scf_walk_fmri(h, argc, argv, WALK_FLAGS, callback,
2532 - NULL, &exit_status, pr_warn)) != 0) {
2536 + (void *)flags, &exit_status, pr_warn)) != 0) {
2533 2537 pr_warn(gettext("failed to iterate over "
2534 2538 "instances: %s\n"),
2535 2539 scf_strerror(err));
2536 2540 exit_status = UU_EXIT_FATAL;
2537 2541 }
2538 2542
2539 2543 } else if (strcmp(argv[optind], "clear") == 0) {
2540 2544 ++optind;
2541 2545 argc -= optind;
2542 2546 argv += optind;
2543 2547
2544 2548 if (argc == 0 && !svcsearch)
2545 2549 usage();
2546 2550
2547 2551 if (svcsearch) {
2548 2552 if (argc > 0)
2549 2553 usage();
2550 2554 if (strcmp(svcstate, SCF_STATE_STRING_MAINT) != 0 &&
2551 2555 strcmp(svcstate, SCF_STATE_STRING_DEGRADED) != 0)
2552 2556 uu_die(gettext("State must be '%s' or '%s'\n"),
2553 2557 SCF_STATE_STRING_MAINT,
2554 2558 SCF_STATE_STRING_DEGRADED);
2555 2559 }
2556 2560
2557 2561 if ((err = scf_walk_fmri(h, argc, argv, WALK_FLAGS,
2558 2562 clear_instance, NULL, &exit_status, pr_warn)) != 0) {
2559 2563 pr_warn(gettext("failed to iterate over "
2560 2564 "instances: %s\n"), scf_strerror(err));
2561 2565 exit_status = UU_EXIT_FATAL;
2562 2566 }
2563 2567
2564 2568 } else if (strcmp(argv[optind], "milestone") == 0) {
2565 2569 boolean_t temporary = B_TRUE;
2566 2570 const char *milestone;
2567 2571
2568 2572 ++optind;
2569 2573
2570 2574 while ((o = getopt(argc, argv, "d")) != -1) {
2571 2575 if (o == 'd')
2572 2576 temporary = B_FALSE;
2573 2577 else if (o == '?')
2574 2578 usage_milestone();
2575 2579 else {
2576 2580 assert(0);
2577 2581 abort();
2578 2582 }
2579 2583 }
2580 2584
2581 2585 if (optind >= argc)
2582 2586 usage_milestone();
2583 2587
2584 2588 milestone = validate_milestone(argv[optind]);
2585 2589
2586 2590 set_milestone(milestone, temporary);
2587 2591 } else if (strcmp(argv[optind], "_smf_backup") == 0) {
2588 2592 const char *reason = NULL;
2589 2593
2590 2594 ++optind;
2591 2595
2592 2596 if (optind != argc - 1)
2593 2597 usage();
2594 2598
2595 2599 if ((err = _scf_request_backup(h, argv[optind])) !=
2596 2600 SCF_SUCCESS) {
2597 2601 switch (scf_error()) {
2598 2602 case SCF_ERROR_NOT_BOUND:
2599 2603 case SCF_ERROR_CONNECTION_BROKEN:
2600 2604 case SCF_ERROR_BACKEND_READONLY:
2601 2605 scfdie();
2602 2606 break;
2603 2607
2604 2608 case SCF_ERROR_PERMISSION_DENIED:
2605 2609 case SCF_ERROR_INVALID_ARGUMENT:
2606 2610 reason = scf_strerror(scf_error());
2607 2611 break;
2608 2612
2609 2613 case SCF_ERROR_INTERNAL:
2610 2614 reason =
2611 2615 "unknown error (see console for details)";
2612 2616 break;
2613 2617 }
2614 2618
2615 2619 pr_warn("failed to backup repository: %s\n", reason);
2616 2620 exit_status = UU_EXIT_FATAL;
2617 2621 }
2618 2622 } else if (strcmp(argv[optind], "_smf_repository_switch") == 0) {
2619 2623 const char *reason = NULL;
2620 2624
2621 2625 ++optind;
2622 2626
2623 2627 /*
2624 2628 * Check argument and setup scf_switch structure
2625 2629 */
2626 2630 if (optind != argc - 1)
2627 2631 exit(1);
2628 2632
2629 2633 if (strcmp(argv[optind], "fast") == 0) {
2630 2634 sw_back = 0;
2631 2635 } else if (strcmp(argv[optind], "perm") == 0) {
2632 2636 sw_back = 1;
2633 2637 } else {
2634 2638 exit(UU_EXIT_USAGE);
2635 2639 }
2636 2640
2637 2641 /*
2638 2642 * Call into switch primitive
2639 2643 */
2640 2644 if ((err = _scf_repository_switch(h, sw_back)) !=
2641 2645 SCF_SUCCESS) {
2642 2646 /*
2643 2647 * Retrieve per thread SCF error code
2644 2648 */
2645 2649 switch (scf_error()) {
2646 2650 case SCF_ERROR_NOT_BOUND:
2647 2651 abort();
2648 2652 /* NOTREACHED */
2649 2653
2650 2654 case SCF_ERROR_CONNECTION_BROKEN:
2651 2655 case SCF_ERROR_BACKEND_READONLY:
2652 2656 scfdie();
2653 2657 /* NOTREACHED */
2654 2658
2655 2659 case SCF_ERROR_PERMISSION_DENIED:
2656 2660 case SCF_ERROR_INVALID_ARGUMENT:
2657 2661 reason = scf_strerror(scf_error());
2658 2662 break;
2659 2663
2660 2664 case SCF_ERROR_INTERNAL:
2661 2665 reason = "File operation error: (see console)";
2662 2666 break;
2663 2667
2664 2668 default:
2665 2669 abort();
2666 2670 /* NOTREACHED */
2667 2671 }
2668 2672
2669 2673 pr_warn("failed to switch repository: %s\n", reason);
2670 2674 exit_status = UU_EXIT_FATAL;
2671 2675 }
2672 2676 } else {
2673 2677 usage();
2674 2678 }
2675 2679
2676 2680 if (scf_handle_unbind(h) == -1)
2677 2681 scfdie();
2678 2682 nextzone:
2679 2683 scf_handle_destroy(h);
2680 2684 if (do_zones && zent < nzents)
2681 2685 goto again;
2682 2686
2683 2687 return (exit_status);
2684 2688 }
↓ open down ↓ |
142 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX