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