10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51597Slianep * Common Development and Distribution License (the "License").
61597Slianep * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
228823STruong.Q.Nguyen@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate * svcadm - request adminstrative actions for service instances
280Sstevel@tonic-gate */
290Sstevel@tonic-gate
300Sstevel@tonic-gate #include <locale.h>
310Sstevel@tonic-gate #include <libintl.h>
320Sstevel@tonic-gate #include <libscf.h>
330Sstevel@tonic-gate #include <libscf_priv.h>
348823STruong.Q.Nguyen@Sun.COM #include <libcontract.h>
358823STruong.Q.Nguyen@Sun.COM #include <libcontract_priv.h>
368823STruong.Q.Nguyen@Sun.COM #include <sys/contract/process.h>
370Sstevel@tonic-gate #include <libuutil.h>
380Sstevel@tonic-gate #include <stddef.h>
390Sstevel@tonic-gate #include <stdio.h>
400Sstevel@tonic-gate #include <stdlib.h>
410Sstevel@tonic-gate #include <string.h>
420Sstevel@tonic-gate #include <unistd.h>
438823STruong.Q.Nguyen@Sun.COM #include <fcntl.h>
448823STruong.Q.Nguyen@Sun.COM #include <procfs.h>
450Sstevel@tonic-gate #include <assert.h>
460Sstevel@tonic-gate #include <errno.h>
470Sstevel@tonic-gate
480Sstevel@tonic-gate #ifndef TEXT_DOMAIN
490Sstevel@tonic-gate #define TEXT_DOMAIN "SUNW_OST_OSCMD"
500Sstevel@tonic-gate #endif /* TEXT_DOMAIN */
510Sstevel@tonic-gate
520Sstevel@tonic-gate /* Must be a power of two */
530Sstevel@tonic-gate #define HT_BUCKETS 64
540Sstevel@tonic-gate
550Sstevel@tonic-gate /*
560Sstevel@tonic-gate * Exit codes for enable and disable -s.
570Sstevel@tonic-gate */
580Sstevel@tonic-gate #define EXIT_SVC_FAILURE 3
590Sstevel@tonic-gate #define EXIT_DEP_FAILURE 4
600Sstevel@tonic-gate
610Sstevel@tonic-gate /*
620Sstevel@tonic-gate * How long we will wait (in seconds) for a service to change state
630Sstevel@tonic-gate * before re-checking its dependencies.
640Sstevel@tonic-gate */
650Sstevel@tonic-gate #define WAIT_INTERVAL 3
660Sstevel@tonic-gate
670Sstevel@tonic-gate #ifndef NDEBUG
680Sstevel@tonic-gate #define bad_error(func, err) { \
690Sstevel@tonic-gate uu_warn("%s:%d: %s() failed with unexpected error %d.\n", \
700Sstevel@tonic-gate __FILE__, __LINE__, (func), (err)); \
710Sstevel@tonic-gate abort(); \
720Sstevel@tonic-gate }
730Sstevel@tonic-gate #else
740Sstevel@tonic-gate #define bad_error(func, err) abort()
750Sstevel@tonic-gate #endif
760Sstevel@tonic-gate
770Sstevel@tonic-gate
780Sstevel@tonic-gate struct ht_elt {
790Sstevel@tonic-gate struct ht_elt *next;
800Sstevel@tonic-gate boolean_t active;
810Sstevel@tonic-gate char str[1];
820Sstevel@tonic-gate };
830Sstevel@tonic-gate
840Sstevel@tonic-gate
850Sstevel@tonic-gate scf_handle_t *h;
860Sstevel@tonic-gate ssize_t max_scf_fmri_sz;
870Sstevel@tonic-gate static const char *emsg_permission_denied;
880Sstevel@tonic-gate static const char *emsg_nomem;
890Sstevel@tonic-gate static const char *emsg_create_pg_perm_denied;
900Sstevel@tonic-gate static const char *emsg_pg_perm_denied;
910Sstevel@tonic-gate static const char *emsg_prop_perm_denied;
920Sstevel@tonic-gate static const char *emsg_no_service;
930Sstevel@tonic-gate
940Sstevel@tonic-gate static int exit_status = 0;
950Sstevel@tonic-gate static int verbose = 0;
960Sstevel@tonic-gate static char *scratch_fmri;
970Sstevel@tonic-gate
980Sstevel@tonic-gate static struct ht_elt **visited;
990Sstevel@tonic-gate
100471Shg115875 void do_scfdie(int lineno) __NORETURN;
101471Shg115875 static void usage_milestone(void) __NORETURN;
1028823STruong.Q.Nguyen@Sun.COM static void set_astring_prop(const char *, const char *, const char *,
1038823STruong.Q.Nguyen@Sun.COM uint32_t, const char *, const char *);
104471Shg115875
1050Sstevel@tonic-gate /*
1060Sstevel@tonic-gate * Visitors from synch.c, needed for enable -s and disable -s.
1070Sstevel@tonic-gate */
1080Sstevel@tonic-gate extern int is_enabled(scf_instance_t *);
1090Sstevel@tonic-gate extern int has_potential(scf_instance_t *, int);
1100Sstevel@tonic-gate
1110Sstevel@tonic-gate void
do_scfdie(int lineno)1120Sstevel@tonic-gate do_scfdie(int lineno)
1130Sstevel@tonic-gate {
1140Sstevel@tonic-gate scf_error_t err;
1150Sstevel@tonic-gate
1160Sstevel@tonic-gate switch (err = scf_error()) {
1170Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN:
1180Sstevel@tonic-gate uu_die(gettext("Connection to repository server broken. "
1190Sstevel@tonic-gate "Exiting.\n"));
1200Sstevel@tonic-gate /* NOTREACHED */
1210Sstevel@tonic-gate
1220Sstevel@tonic-gate case SCF_ERROR_BACKEND_READONLY:
1230Sstevel@tonic-gate uu_die(gettext("Repository is read-only. Exiting.\n"));
1240Sstevel@tonic-gate /* NOTREACHED */
1250Sstevel@tonic-gate
1260Sstevel@tonic-gate default:
1270Sstevel@tonic-gate #ifdef NDEBUG
1280Sstevel@tonic-gate uu_die(gettext("Unexpected libscf error: %s. Exiting.\n"),
1290Sstevel@tonic-gate scf_strerror(err));
1300Sstevel@tonic-gate #else
1310Sstevel@tonic-gate uu_die("Unexpected libscf error on line %d: %s.\n", lineno,
1320Sstevel@tonic-gate scf_strerror(err));
1330Sstevel@tonic-gate #endif
1340Sstevel@tonic-gate }
1350Sstevel@tonic-gate }
1360Sstevel@tonic-gate
1370Sstevel@tonic-gate #define scfdie() do_scfdie(__LINE__)
1380Sstevel@tonic-gate
1390Sstevel@tonic-gate static void
usage()1400Sstevel@tonic-gate usage()
1410Sstevel@tonic-gate {
1420Sstevel@tonic-gate (void) fprintf(stderr, gettext(
1430Sstevel@tonic-gate "Usage: %1$s [-v] [cmd [args ... ]]\n\n"
1440Sstevel@tonic-gate "\t%1$s enable [-rst] <service> ...\t- enable and online service(s)\n"
1450Sstevel@tonic-gate "\t%1$s disable [-st] <service> ...\t- disable and offline service(s)\n"
1460Sstevel@tonic-gate "\t%1$s restart <service> ...\t\t- restart specified service(s)\n"
1470Sstevel@tonic-gate "\t%1$s refresh <service> ...\t\t- re-read service configuration\n"
1480Sstevel@tonic-gate "\t%1$s mark [-It] <state> <service> ...\t- set maintenance state\n"
1490Sstevel@tonic-gate "\t%1$s clear <service> ...\t\t- clear maintenance state\n"
1500Sstevel@tonic-gate "\t%1$s milestone [-d] <milestone>\t- advance to a service milestone\n"
1510Sstevel@tonic-gate "\n\t"
1520Sstevel@tonic-gate "Services can be specified using an FMRI, abbreviation, or fnmatch(5)\n"
1530Sstevel@tonic-gate "\tpattern, as shown in these examples for svc:/network/smtp:sendmail\n"
1540Sstevel@tonic-gate "\n"
1550Sstevel@tonic-gate "\t%1$s <cmd> svc:/network/smtp:sendmail\n"
1560Sstevel@tonic-gate "\t%1$s <cmd> network/smtp:sendmail\n"
1570Sstevel@tonic-gate "\t%1$s <cmd> network/*mail\n"
1580Sstevel@tonic-gate "\t%1$s <cmd> network/smtp\n"
1590Sstevel@tonic-gate "\t%1$s <cmd> smtp:sendmail\n"
1600Sstevel@tonic-gate "\t%1$s <cmd> smtp\n"
1610Sstevel@tonic-gate "\t%1$s <cmd> sendmail\n"), uu_getpname());
1620Sstevel@tonic-gate
1630Sstevel@tonic-gate exit(UU_EXIT_USAGE);
1640Sstevel@tonic-gate }
1650Sstevel@tonic-gate
1660Sstevel@tonic-gate
1670Sstevel@tonic-gate /*
1680Sstevel@tonic-gate * FMRI hash table for recursive enable.
1690Sstevel@tonic-gate */
1700Sstevel@tonic-gate
1710Sstevel@tonic-gate static uint32_t
hash_fmri(const char * str)1720Sstevel@tonic-gate hash_fmri(const char *str)
1730Sstevel@tonic-gate {
1740Sstevel@tonic-gate uint32_t h = 0, g;
1750Sstevel@tonic-gate const char *p;
1760Sstevel@tonic-gate
1770Sstevel@tonic-gate /* Generic hash function from uts/common/os/modhash.c . */
1780Sstevel@tonic-gate for (p = str; *p != '\0'; ++p) {
1790Sstevel@tonic-gate h = (h << 4) + *p;
1800Sstevel@tonic-gate if ((g = (h & 0xf0000000)) != 0) {
1810Sstevel@tonic-gate h ^= (g >> 24);
1820Sstevel@tonic-gate h ^= g;
1830Sstevel@tonic-gate }
1840Sstevel@tonic-gate }
1850Sstevel@tonic-gate
1860Sstevel@tonic-gate return (h);
1870Sstevel@tonic-gate }
1880Sstevel@tonic-gate
1890Sstevel@tonic-gate /*
1900Sstevel@tonic-gate * Return 1 if str has been visited, 0 if it has not, and -1 if memory could not
1910Sstevel@tonic-gate * be allocated.
1920Sstevel@tonic-gate */
1930Sstevel@tonic-gate static int
visited_find_or_add(const char * str,struct ht_elt ** hep)1940Sstevel@tonic-gate visited_find_or_add(const char *str, struct ht_elt **hep)
1950Sstevel@tonic-gate {
1960Sstevel@tonic-gate uint32_t h;
1970Sstevel@tonic-gate uint_t i;
1980Sstevel@tonic-gate struct ht_elt *he;
1990Sstevel@tonic-gate
2000Sstevel@tonic-gate h = hash_fmri(str);
2010Sstevel@tonic-gate i = h & (HT_BUCKETS - 1);
2020Sstevel@tonic-gate
2030Sstevel@tonic-gate for (he = visited[i]; he != NULL; he = he->next) {
2040Sstevel@tonic-gate if (strcmp(he->str, str) == 0) {
2050Sstevel@tonic-gate if (hep)
2060Sstevel@tonic-gate *hep = he;
2070Sstevel@tonic-gate return (1);
2080Sstevel@tonic-gate }
2090Sstevel@tonic-gate }
2100Sstevel@tonic-gate
2110Sstevel@tonic-gate he = malloc(offsetof(struct ht_elt, str) + strlen(str) + 1);
2120Sstevel@tonic-gate if (he == NULL)
2130Sstevel@tonic-gate return (-1);
2140Sstevel@tonic-gate
2150Sstevel@tonic-gate (void) strcpy(he->str, str);
2160Sstevel@tonic-gate
2170Sstevel@tonic-gate he->next = visited[i];
2180Sstevel@tonic-gate visited[i] = he;
2190Sstevel@tonic-gate
2200Sstevel@tonic-gate if (hep)
2210Sstevel@tonic-gate *hep = he;
2220Sstevel@tonic-gate return (0);
2230Sstevel@tonic-gate }
2240Sstevel@tonic-gate
2250Sstevel@tonic-gate
2260Sstevel@tonic-gate /*
2270Sstevel@tonic-gate * Returns 0, ECANCELED if pg is deleted, ENOENT if propname doesn't exist,
2280Sstevel@tonic-gate * EINVAL if the property is not of boolean type or has no values, and E2BIG
2290Sstevel@tonic-gate * if it has more than one value. *bp is set if 0 or E2BIG is returned.
2300Sstevel@tonic-gate */
2310Sstevel@tonic-gate int
get_bool_prop(scf_propertygroup_t * pg,const char * propname,uint8_t * bp)2320Sstevel@tonic-gate get_bool_prop(scf_propertygroup_t *pg, const char *propname, uint8_t *bp)
2330Sstevel@tonic-gate {
2340Sstevel@tonic-gate scf_property_t *prop;
2350Sstevel@tonic-gate scf_value_t *val;
2360Sstevel@tonic-gate int ret;
2370Sstevel@tonic-gate
2380Sstevel@tonic-gate if ((prop = scf_property_create(h)) == NULL ||
2390Sstevel@tonic-gate (val = scf_value_create(h)) == NULL)
2400Sstevel@tonic-gate scfdie();
2410Sstevel@tonic-gate
2420Sstevel@tonic-gate if (scf_pg_get_property(pg, propname, prop) != 0) {
2430Sstevel@tonic-gate switch (scf_error()) {
2440Sstevel@tonic-gate case SCF_ERROR_DELETED:
2450Sstevel@tonic-gate ret = ECANCELED;
2460Sstevel@tonic-gate goto out;
2470Sstevel@tonic-gate
2480Sstevel@tonic-gate case SCF_ERROR_NOT_FOUND:
2490Sstevel@tonic-gate ret = ENOENT;
2500Sstevel@tonic-gate goto out;
2510Sstevel@tonic-gate
2520Sstevel@tonic-gate case SCF_ERROR_NOT_SET:
2530Sstevel@tonic-gate assert(0);
2540Sstevel@tonic-gate abort();
2550Sstevel@tonic-gate /* NOTREACHED */
2560Sstevel@tonic-gate
2570Sstevel@tonic-gate default:
2580Sstevel@tonic-gate scfdie();
2590Sstevel@tonic-gate }
2600Sstevel@tonic-gate }
2610Sstevel@tonic-gate
2620Sstevel@tonic-gate if (scf_property_get_value(prop, val) == 0) {
2630Sstevel@tonic-gate ret = 0;
2640Sstevel@tonic-gate } else {
2650Sstevel@tonic-gate switch (scf_error()) {
2660Sstevel@tonic-gate case SCF_ERROR_DELETED:
2670Sstevel@tonic-gate ret = ENOENT;
2680Sstevel@tonic-gate goto out;
2690Sstevel@tonic-gate
2700Sstevel@tonic-gate case SCF_ERROR_NOT_FOUND:
2710Sstevel@tonic-gate ret = EINVAL;
2720Sstevel@tonic-gate goto out;
2730Sstevel@tonic-gate
2740Sstevel@tonic-gate case SCF_ERROR_CONSTRAINT_VIOLATED:
2750Sstevel@tonic-gate ret = E2BIG;
2760Sstevel@tonic-gate break;
2770Sstevel@tonic-gate
2780Sstevel@tonic-gate case SCF_ERROR_NOT_SET:
2790Sstevel@tonic-gate assert(0);
2800Sstevel@tonic-gate abort();
2810Sstevel@tonic-gate /* NOTREACHED */
2820Sstevel@tonic-gate
2830Sstevel@tonic-gate default:
2840Sstevel@tonic-gate scfdie();
2850Sstevel@tonic-gate }
2860Sstevel@tonic-gate }
2870Sstevel@tonic-gate
2880Sstevel@tonic-gate if (scf_value_get_boolean(val, bp) != 0) {
2890Sstevel@tonic-gate if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
2900Sstevel@tonic-gate scfdie();
2910Sstevel@tonic-gate
2920Sstevel@tonic-gate ret = EINVAL;
2930Sstevel@tonic-gate goto out;
2940Sstevel@tonic-gate }
2950Sstevel@tonic-gate
2960Sstevel@tonic-gate out:
2970Sstevel@tonic-gate scf_value_destroy(val);
2980Sstevel@tonic-gate scf_property_destroy(prop);
2990Sstevel@tonic-gate return (ret);
3000Sstevel@tonic-gate }
3010Sstevel@tonic-gate
3020Sstevel@tonic-gate /*
3030Sstevel@tonic-gate * Returns 0, EPERM, or EROFS.
3040Sstevel@tonic-gate */
3050Sstevel@tonic-gate static int
set_bool_prop(scf_propertygroup_t * pg,const char * propname,boolean_t b)3060Sstevel@tonic-gate set_bool_prop(scf_propertygroup_t *pg, const char *propname, boolean_t b)
3070Sstevel@tonic-gate {
3080Sstevel@tonic-gate scf_value_t *v;
3090Sstevel@tonic-gate scf_transaction_t *tx;
3100Sstevel@tonic-gate scf_transaction_entry_t *ent;
3110Sstevel@tonic-gate int ret = 0, r;
3120Sstevel@tonic-gate
3130Sstevel@tonic-gate if ((tx = scf_transaction_create(h)) == NULL ||
3140Sstevel@tonic-gate (ent = scf_entry_create(h)) == NULL ||
3150Sstevel@tonic-gate (v = scf_value_create(h)) == NULL)
3160Sstevel@tonic-gate scfdie();
3170Sstevel@tonic-gate
3180Sstevel@tonic-gate scf_value_set_boolean(v, b);
3190Sstevel@tonic-gate
3200Sstevel@tonic-gate for (;;) {
3210Sstevel@tonic-gate if (scf_transaction_start(tx, pg) == -1) {
3220Sstevel@tonic-gate switch (scf_error()) {
3230Sstevel@tonic-gate case SCF_ERROR_PERMISSION_DENIED:
3240Sstevel@tonic-gate ret = EPERM;
3250Sstevel@tonic-gate goto out;
3260Sstevel@tonic-gate
3270Sstevel@tonic-gate case SCF_ERROR_BACKEND_READONLY:
3280Sstevel@tonic-gate ret = EROFS;
3290Sstevel@tonic-gate goto out;
3300Sstevel@tonic-gate
3310Sstevel@tonic-gate default:
3320Sstevel@tonic-gate scfdie();
3330Sstevel@tonic-gate }
3340Sstevel@tonic-gate }
3350Sstevel@tonic-gate
3360Sstevel@tonic-gate if (scf_transaction_property_change_type(tx, ent, propname,
3370Sstevel@tonic-gate SCF_TYPE_BOOLEAN) != 0) {
3380Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NOT_FOUND)
3390Sstevel@tonic-gate scfdie();
3400Sstevel@tonic-gate
3410Sstevel@tonic-gate if (scf_transaction_property_new(tx, ent, propname,
3420Sstevel@tonic-gate SCF_TYPE_BOOLEAN) != 0)
3430Sstevel@tonic-gate scfdie();
3440Sstevel@tonic-gate }
3450Sstevel@tonic-gate
3460Sstevel@tonic-gate r = scf_entry_add_value(ent, v);
3470Sstevel@tonic-gate assert(r == 0);
3480Sstevel@tonic-gate
3490Sstevel@tonic-gate r = scf_transaction_commit(tx);
3500Sstevel@tonic-gate if (r == 1)
3510Sstevel@tonic-gate break;
3520Sstevel@tonic-gate
3530Sstevel@tonic-gate scf_transaction_reset(tx);
3540Sstevel@tonic-gate
3550Sstevel@tonic-gate if (r != 0) {
3560Sstevel@tonic-gate switch (scf_error()) {
3570Sstevel@tonic-gate case SCF_ERROR_PERMISSION_DENIED:
3580Sstevel@tonic-gate ret = EPERM;
3590Sstevel@tonic-gate goto out;
3600Sstevel@tonic-gate
3610Sstevel@tonic-gate case SCF_ERROR_BACKEND_READONLY:
3620Sstevel@tonic-gate ret = EROFS;
3630Sstevel@tonic-gate goto out;
3640Sstevel@tonic-gate
3650Sstevel@tonic-gate default:
3660Sstevel@tonic-gate scfdie();
3670Sstevel@tonic-gate }
3680Sstevel@tonic-gate }
3690Sstevel@tonic-gate
3700Sstevel@tonic-gate if (scf_pg_update(pg) == -1)
3710Sstevel@tonic-gate scfdie();
3720Sstevel@tonic-gate }
3730Sstevel@tonic-gate
3740Sstevel@tonic-gate out:
3750Sstevel@tonic-gate scf_transaction_destroy(tx);
3760Sstevel@tonic-gate scf_entry_destroy(ent);
3770Sstevel@tonic-gate scf_value_destroy(v);
3780Sstevel@tonic-gate return (ret);
3790Sstevel@tonic-gate }
3800Sstevel@tonic-gate
3810Sstevel@tonic-gate /*
3820Sstevel@tonic-gate * Gets the single astring value of the propname property of pg. prop & v are
3830Sstevel@tonic-gate * scratch space. Returns the length of the string on success or
3840Sstevel@tonic-gate * -ENOENT - pg has no property named propname
3850Sstevel@tonic-gate * -E2BIG - property has no values or multiple values
3860Sstevel@tonic-gate * -EINVAL - property type is not compatible with astring
3870Sstevel@tonic-gate */
3880Sstevel@tonic-gate ssize_t
get_astring_prop(const scf_propertygroup_t * pg,const char * propname,scf_property_t * prop,scf_value_t * v,char * buf,size_t bufsz)3890Sstevel@tonic-gate get_astring_prop(const scf_propertygroup_t *pg, const char *propname,
3900Sstevel@tonic-gate scf_property_t *prop, scf_value_t *v, char *buf, size_t bufsz)
3910Sstevel@tonic-gate {
3920Sstevel@tonic-gate ssize_t sz;
3930Sstevel@tonic-gate
3940Sstevel@tonic-gate if (scf_pg_get_property(pg, propname, prop) != 0) {
3950Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NOT_FOUND)
3960Sstevel@tonic-gate scfdie();
3970Sstevel@tonic-gate
3980Sstevel@tonic-gate return (-ENOENT);
3990Sstevel@tonic-gate }
4000Sstevel@tonic-gate
4010Sstevel@tonic-gate if (scf_property_get_value(prop, v) != 0) {
4020Sstevel@tonic-gate switch (scf_error()) {
4030Sstevel@tonic-gate case SCF_ERROR_NOT_FOUND:
4040Sstevel@tonic-gate case SCF_ERROR_CONSTRAINT_VIOLATED:
4050Sstevel@tonic-gate return (-E2BIG);
4060Sstevel@tonic-gate
4070Sstevel@tonic-gate default:
4080Sstevel@tonic-gate scfdie();
4090Sstevel@tonic-gate }
4100Sstevel@tonic-gate }
4110Sstevel@tonic-gate
4120Sstevel@tonic-gate sz = scf_value_get_astring(v, buf, bufsz);
4130Sstevel@tonic-gate if (sz < 0) {
4140Sstevel@tonic-gate if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
4150Sstevel@tonic-gate scfdie();
4160Sstevel@tonic-gate
4170Sstevel@tonic-gate return (-EINVAL);
4180Sstevel@tonic-gate }
4190Sstevel@tonic-gate
4200Sstevel@tonic-gate return (sz);
4210Sstevel@tonic-gate }
4220Sstevel@tonic-gate
4230Sstevel@tonic-gate /*
4240Sstevel@tonic-gate * Returns 0 or EPERM.
4250Sstevel@tonic-gate */
4260Sstevel@tonic-gate static int
pg_get_or_add(const scf_instance_t * inst,const char * pgname,const char * pgtype,uint32_t pgflags,scf_propertygroup_t * pg)4278823STruong.Q.Nguyen@Sun.COM pg_get_or_add(const scf_instance_t *inst, const char *pgname,
4288823STruong.Q.Nguyen@Sun.COM const char *pgtype, uint32_t pgflags, scf_propertygroup_t *pg)
4290Sstevel@tonic-gate {
4300Sstevel@tonic-gate again:
4310Sstevel@tonic-gate if (scf_instance_get_pg(inst, pgname, pg) == 0)
4320Sstevel@tonic-gate return (0);
4330Sstevel@tonic-gate
4340Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NOT_FOUND)
4350Sstevel@tonic-gate scfdie();
4360Sstevel@tonic-gate
4370Sstevel@tonic-gate if (scf_instance_add_pg(inst, pgname, pgtype, pgflags, pg) == 0)
4380Sstevel@tonic-gate return (0);
4390Sstevel@tonic-gate
4400Sstevel@tonic-gate switch (scf_error()) {
4410Sstevel@tonic-gate case SCF_ERROR_EXISTS:
4420Sstevel@tonic-gate goto again;
4430Sstevel@tonic-gate
4440Sstevel@tonic-gate case SCF_ERROR_PERMISSION_DENIED:
4450Sstevel@tonic-gate return (EPERM);
4460Sstevel@tonic-gate
4470Sstevel@tonic-gate default:
4480Sstevel@tonic-gate scfdie();
4490Sstevel@tonic-gate /* NOTREACHED */
4500Sstevel@tonic-gate }
4510Sstevel@tonic-gate }
4520Sstevel@tonic-gate
4538823STruong.Q.Nguyen@Sun.COM static int
my_ct_name(char * out,size_t len)4548823STruong.Q.Nguyen@Sun.COM my_ct_name(char *out, size_t len)
4558823STruong.Q.Nguyen@Sun.COM {
4568823STruong.Q.Nguyen@Sun.COM ct_stathdl_t st;
4578823STruong.Q.Nguyen@Sun.COM char *ct_fmri;
4588823STruong.Q.Nguyen@Sun.COM ctid_t ct;
4598823STruong.Q.Nguyen@Sun.COM int fd, errno, ret;
4608823STruong.Q.Nguyen@Sun.COM
4618823STruong.Q.Nguyen@Sun.COM if ((ct = getctid()) == -1)
4628823STruong.Q.Nguyen@Sun.COM uu_die(gettext("Could not get contract id for process"));
4638823STruong.Q.Nguyen@Sun.COM
4648823STruong.Q.Nguyen@Sun.COM fd = contract_open(ct, "process", "status", O_RDONLY);
4658823STruong.Q.Nguyen@Sun.COM
4668823STruong.Q.Nguyen@Sun.COM if ((errno = ct_status_read(fd, CTD_ALL, &st)) != 0)
4678823STruong.Q.Nguyen@Sun.COM uu_warn(gettext("Could not read status of contract "
4688823STruong.Q.Nguyen@Sun.COM "%ld: %s.\n"), ct, strerror(errno));
4698823STruong.Q.Nguyen@Sun.COM
4708823STruong.Q.Nguyen@Sun.COM if ((errno = ct_pr_status_get_svc_fmri(st, &ct_fmri)) != 0)
4718823STruong.Q.Nguyen@Sun.COM uu_warn(gettext("Could not get svc_fmri for contract "
4728823STruong.Q.Nguyen@Sun.COM "%ld: %s.\n"), ct, strerror(errno));
4738823STruong.Q.Nguyen@Sun.COM
4748823STruong.Q.Nguyen@Sun.COM ret = strlcpy(out, ct_fmri, len);
4758823STruong.Q.Nguyen@Sun.COM
4768823STruong.Q.Nguyen@Sun.COM ct_status_free(st);
4778823STruong.Q.Nguyen@Sun.COM (void) close(fd);
4788823STruong.Q.Nguyen@Sun.COM
4798823STruong.Q.Nguyen@Sun.COM return (ret);
4808823STruong.Q.Nguyen@Sun.COM }
4818823STruong.Q.Nguyen@Sun.COM
4828823STruong.Q.Nguyen@Sun.COM /*
4838823STruong.Q.Nguyen@Sun.COM * Set auxiliary_tty and auxiliary_fmri properties in restarter_actions pg to
4848823STruong.Q.Nguyen@Sun.COM * communicate whether the action is requested from a tty and the fmri of the
4858823STruong.Q.Nguyen@Sun.COM * responsible process.
486*11223STruong.Q.Nguyen@Sun.COM *
487*11223STruong.Q.Nguyen@Sun.COM * Returns 0, EPERM, or EROFS
4888823STruong.Q.Nguyen@Sun.COM */
4898823STruong.Q.Nguyen@Sun.COM static int
restarter_setup(const char * fmri,const scf_instance_t * inst)4908823STruong.Q.Nguyen@Sun.COM restarter_setup(const char *fmri, const scf_instance_t *inst)
4918823STruong.Q.Nguyen@Sun.COM {
4928823STruong.Q.Nguyen@Sun.COM boolean_t b = B_FALSE;
4938823STruong.Q.Nguyen@Sun.COM scf_propertygroup_t *pg = NULL;
494*11223STruong.Q.Nguyen@Sun.COM int ret = 0;
4958823STruong.Q.Nguyen@Sun.COM
4968823STruong.Q.Nguyen@Sun.COM if ((pg = scf_pg_create(h)) == NULL)
4978823STruong.Q.Nguyen@Sun.COM scfdie();
4988823STruong.Q.Nguyen@Sun.COM
4998823STruong.Q.Nguyen@Sun.COM if (pg_get_or_add(inst, SCF_PG_RESTARTER_ACTIONS,
5008823STruong.Q.Nguyen@Sun.COM SCF_PG_RESTARTER_ACTIONS_TYPE, SCF_PG_RESTARTER_ACTIONS_FLAGS,
501*11223STruong.Q.Nguyen@Sun.COM pg) == EPERM) {
502*11223STruong.Q.Nguyen@Sun.COM if (!verbose)
503*11223STruong.Q.Nguyen@Sun.COM uu_warn(emsg_permission_denied, fmri);
504*11223STruong.Q.Nguyen@Sun.COM else
505*11223STruong.Q.Nguyen@Sun.COM uu_warn(emsg_create_pg_perm_denied, fmri,
506*11223STruong.Q.Nguyen@Sun.COM SCF_PG_RESTARTER_ACTIONS);
507*11223STruong.Q.Nguyen@Sun.COM
508*11223STruong.Q.Nguyen@Sun.COM ret = EPERM;
509*11223STruong.Q.Nguyen@Sun.COM goto out;
510*11223STruong.Q.Nguyen@Sun.COM }
5118823STruong.Q.Nguyen@Sun.COM
5128823STruong.Q.Nguyen@Sun.COM /* Set auxiliary_tty property */
5138823STruong.Q.Nguyen@Sun.COM if (isatty(STDIN_FILENO))
5148823STruong.Q.Nguyen@Sun.COM b = B_TRUE;
5158823STruong.Q.Nguyen@Sun.COM
5168823STruong.Q.Nguyen@Sun.COM /* Create and set state to disabled */
5178823STruong.Q.Nguyen@Sun.COM switch (set_bool_prop(pg, SCF_PROPERTY_AUX_TTY, b) != 0) {
5188823STruong.Q.Nguyen@Sun.COM case 0:
5198823STruong.Q.Nguyen@Sun.COM break;
5208823STruong.Q.Nguyen@Sun.COM
5218823STruong.Q.Nguyen@Sun.COM case EPERM:
522*11223STruong.Q.Nguyen@Sun.COM if (!verbose)
523*11223STruong.Q.Nguyen@Sun.COM uu_warn(emsg_permission_denied, fmri);
524*11223STruong.Q.Nguyen@Sun.COM else
525*11223STruong.Q.Nguyen@Sun.COM uu_warn(emsg_prop_perm_denied, fmri,
526*11223STruong.Q.Nguyen@Sun.COM SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_AUX_TTY);
527*11223STruong.Q.Nguyen@Sun.COM
528*11223STruong.Q.Nguyen@Sun.COM ret = EPERM;
529*11223STruong.Q.Nguyen@Sun.COM goto out;
530*11223STruong.Q.Nguyen@Sun.COM /* NOTREACHED */
5318823STruong.Q.Nguyen@Sun.COM
5328823STruong.Q.Nguyen@Sun.COM case EROFS:
533*11223STruong.Q.Nguyen@Sun.COM /* Shouldn't happen, but it can. */
534*11223STruong.Q.Nguyen@Sun.COM if (!verbose)
535*11223STruong.Q.Nguyen@Sun.COM uu_warn(gettext("%s: Repository read-only.\n"), fmri);
536*11223STruong.Q.Nguyen@Sun.COM else
537*11223STruong.Q.Nguyen@Sun.COM uu_warn(gettext("%s: Could not set %s/%s "
538*11223STruong.Q.Nguyen@Sun.COM "(repository read-only).\n"), fmri,
539*11223STruong.Q.Nguyen@Sun.COM SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_AUX_TTY);
540*11223STruong.Q.Nguyen@Sun.COM
541*11223STruong.Q.Nguyen@Sun.COM ret = EROFS;
542*11223STruong.Q.Nguyen@Sun.COM goto out;
543*11223STruong.Q.Nguyen@Sun.COM /* NOTREACHED */
5448823STruong.Q.Nguyen@Sun.COM
5458823STruong.Q.Nguyen@Sun.COM default:
5468823STruong.Q.Nguyen@Sun.COM scfdie();
5478823STruong.Q.Nguyen@Sun.COM }
5488823STruong.Q.Nguyen@Sun.COM
5498823STruong.Q.Nguyen@Sun.COM if (my_ct_name(scratch_fmri, max_scf_fmri_sz) > 0) {
5508823STruong.Q.Nguyen@Sun.COM set_astring_prop(fmri, SCF_PG_RESTARTER_ACTIONS,
5518823STruong.Q.Nguyen@Sun.COM SCF_PG_RESTARTER_ACTIONS_TYPE,
5528823STruong.Q.Nguyen@Sun.COM SCF_PG_RESTARTER_ACTIONS_FLAGS,
5538823STruong.Q.Nguyen@Sun.COM SCF_PROPERTY_AUX_FMRI, scratch_fmri);
5548823STruong.Q.Nguyen@Sun.COM } else {
5558823STruong.Q.Nguyen@Sun.COM uu_warn(gettext("%s: Could not set %s/%s: "
5568823STruong.Q.Nguyen@Sun.COM "my_ct_name failed.\n"), fmri,
5578823STruong.Q.Nguyen@Sun.COM SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_AUX_FMRI);
5588823STruong.Q.Nguyen@Sun.COM }
5598823STruong.Q.Nguyen@Sun.COM
560*11223STruong.Q.Nguyen@Sun.COM out:
5618823STruong.Q.Nguyen@Sun.COM scf_pg_destroy(pg);
562*11223STruong.Q.Nguyen@Sun.COM return (ret);
5638823STruong.Q.Nguyen@Sun.COM }
5648823STruong.Q.Nguyen@Sun.COM
5650Sstevel@tonic-gate /*
5660Sstevel@tonic-gate * Enable or disable inst, per enable. If temp is true, set
5670Sstevel@tonic-gate * general_ovr/enabled. Otherwise set general/enabled and delete
5680Sstevel@tonic-gate * general_ovr/enabled if it exists (order is important here: we don't want the
5690Sstevel@tonic-gate * enabled status to glitch).
5700Sstevel@tonic-gate */
5710Sstevel@tonic-gate static void
set_inst_enabled(const char * fmri,scf_instance_t * inst,boolean_t temp,boolean_t enable)5720Sstevel@tonic-gate set_inst_enabled(const char *fmri, scf_instance_t *inst, boolean_t temp,
5730Sstevel@tonic-gate boolean_t enable)
5740Sstevel@tonic-gate {
5750Sstevel@tonic-gate scf_propertygroup_t *pg;
5760Sstevel@tonic-gate uint8_t b;
5770Sstevel@tonic-gate const char *pgname = NULL; /* For emsg_pg_perm_denied */
5780Sstevel@tonic-gate int r;
5790Sstevel@tonic-gate
5800Sstevel@tonic-gate pg = scf_pg_create(h);
5810Sstevel@tonic-gate if (pg == NULL)
5820Sstevel@tonic-gate scfdie();
5830Sstevel@tonic-gate
5848823STruong.Q.Nguyen@Sun.COM if (restarter_setup(fmri, inst))
585*11223STruong.Q.Nguyen@Sun.COM goto out;
5868823STruong.Q.Nguyen@Sun.COM
5874171Stn143363 /*
5884171Stn143363 * An instance's configuration is incomplete if general/enabled
5894171Stn143363 * doesn't exist. Create both the property group and property
5904171Stn143363 * here if they don't exist.
5914171Stn143363 */
5924171Stn143363 pgname = SCF_PG_GENERAL;
5934171Stn143363 if (pg_get_or_add(inst, pgname, SCF_PG_GENERAL_TYPE,
5944171Stn143363 SCF_PG_GENERAL_FLAGS, pg) != 0)
5954171Stn143363 goto eperm;
5964171Stn143363
5974171Stn143363 if (get_bool_prop(pg, SCF_PROPERTY_ENABLED, &b) != 0) {
5984171Stn143363 /* Create and set state to disabled */
5994171Stn143363 switch (set_bool_prop(pg, SCF_PROPERTY_ENABLED, B_FALSE) != 0) {
6004171Stn143363 case 0:
6014171Stn143363 break;
6024171Stn143363
6034171Stn143363 case EPERM:
6044171Stn143363 goto eperm;
6054171Stn143363
6064171Stn143363 case EROFS:
6074171Stn143363 /* Shouldn't happen, but it can. */
6084171Stn143363 if (!verbose)
6094171Stn143363 uu_warn(gettext("%s: Repository read-only.\n"),
6104171Stn143363 fmri);
6114171Stn143363 else
6124171Stn143363 uu_warn(gettext("%s: Could not set %s/%s "
6134171Stn143363 "(repository read-only).\n"), fmri,
6144171Stn143363 SCF_PG_GENERAL, SCF_PROPERTY_ENABLED);
6154171Stn143363 goto out;
6164171Stn143363
6174171Stn143363 default:
6184171Stn143363 assert(0);
6194171Stn143363 abort();
6204171Stn143363 }
6214171Stn143363 }
6224171Stn143363
6230Sstevel@tonic-gate if (temp) {
6240Sstevel@tonic-gate /* Set general_ovr/enabled */
6250Sstevel@tonic-gate pgname = SCF_PG_GENERAL_OVR;
6260Sstevel@tonic-gate if (pg_get_or_add(inst, pgname, SCF_PG_GENERAL_OVR_TYPE,
6270Sstevel@tonic-gate SCF_PG_GENERAL_OVR_FLAGS, pg) != 0)
6280Sstevel@tonic-gate goto eperm;
6290Sstevel@tonic-gate
6300Sstevel@tonic-gate switch (set_bool_prop(pg, SCF_PROPERTY_ENABLED, enable) != 0) {
6310Sstevel@tonic-gate case 0:
6320Sstevel@tonic-gate break;
6330Sstevel@tonic-gate
6340Sstevel@tonic-gate case EPERM:
6350Sstevel@tonic-gate goto eperm;
6360Sstevel@tonic-gate
6370Sstevel@tonic-gate case EROFS:
6380Sstevel@tonic-gate /* Shouldn't happen, but it can. */
6390Sstevel@tonic-gate if (!verbose)
6400Sstevel@tonic-gate uu_warn(gettext("%s: Repository read-only.\n"),
6410Sstevel@tonic-gate fmri);
6420Sstevel@tonic-gate else
6430Sstevel@tonic-gate uu_warn(gettext("%s: Could not set %s/%s "
6440Sstevel@tonic-gate "(repository read-only).\n"), fmri,
6450Sstevel@tonic-gate SCF_PG_GENERAL_OVR, SCF_PROPERTY_ENABLED);
6460Sstevel@tonic-gate goto out;
6470Sstevel@tonic-gate
6480Sstevel@tonic-gate default:
6490Sstevel@tonic-gate assert(0);
6500Sstevel@tonic-gate abort();
6510Sstevel@tonic-gate }
6520Sstevel@tonic-gate
6530Sstevel@tonic-gate if (verbose)
6540Sstevel@tonic-gate (void) printf(enable ?
6550Sstevel@tonic-gate gettext("%s temporarily enabled.\n") :
6560Sstevel@tonic-gate gettext("%s temporarily disabled.\n"), fmri);
6570Sstevel@tonic-gate } else {
6580Sstevel@tonic-gate again:
6594171Stn143363 /*
6604171Stn143363 * Both pg and property should exist since we created
6614171Stn143363 * them earlier. However, there's still a chance that
6624171Stn143363 * someone may have deleted the property out from under
6634171Stn143363 * us.
6644171Stn143363 */
6650Sstevel@tonic-gate if (pg_get_or_add(inst, pgname, SCF_PG_GENERAL_TYPE,
6660Sstevel@tonic-gate SCF_PG_GENERAL_FLAGS, pg) != 0)
6670Sstevel@tonic-gate goto eperm;
6680Sstevel@tonic-gate
6690Sstevel@tonic-gate switch (set_bool_prop(pg, SCF_PROPERTY_ENABLED, enable)) {
6700Sstevel@tonic-gate case 0:
6710Sstevel@tonic-gate break;
6720Sstevel@tonic-gate
6730Sstevel@tonic-gate case EPERM:
6740Sstevel@tonic-gate goto eperm;
6750Sstevel@tonic-gate
6760Sstevel@tonic-gate case EROFS:
6770Sstevel@tonic-gate /*
6780Sstevel@tonic-gate * If general/enabled is already set the way we want,
6790Sstevel@tonic-gate * proceed.
6800Sstevel@tonic-gate */
6810Sstevel@tonic-gate switch (get_bool_prop(pg, SCF_PROPERTY_ENABLED, &b)) {
6820Sstevel@tonic-gate case 0:
6830Sstevel@tonic-gate if ((b != 0) == (enable != B_FALSE))
6840Sstevel@tonic-gate break;
6850Sstevel@tonic-gate /* FALLTHROUGH */
6860Sstevel@tonic-gate
6870Sstevel@tonic-gate case ENOENT:
6880Sstevel@tonic-gate case EINVAL:
6890Sstevel@tonic-gate case E2BIG:
6900Sstevel@tonic-gate if (!verbose)
6910Sstevel@tonic-gate uu_warn(gettext("%s: Repository "
6920Sstevel@tonic-gate "read-only.\n"), fmri);
6930Sstevel@tonic-gate else
6940Sstevel@tonic-gate uu_warn(gettext("%s: Could not set "
6950Sstevel@tonic-gate "%s/%s (repository read-only).\n"),
6960Sstevel@tonic-gate fmri, SCF_PG_GENERAL,
6970Sstevel@tonic-gate SCF_PROPERTY_ENABLED);
6980Sstevel@tonic-gate goto out;
6990Sstevel@tonic-gate
7000Sstevel@tonic-gate case ECANCELED:
7010Sstevel@tonic-gate goto again;
7020Sstevel@tonic-gate
7030Sstevel@tonic-gate default:
7040Sstevel@tonic-gate assert(0);
7050Sstevel@tonic-gate abort();
7060Sstevel@tonic-gate }
7070Sstevel@tonic-gate break;
7080Sstevel@tonic-gate
7090Sstevel@tonic-gate default:
7100Sstevel@tonic-gate assert(0);
7110Sstevel@tonic-gate abort();
7120Sstevel@tonic-gate }
7130Sstevel@tonic-gate
7140Sstevel@tonic-gate pgname = SCF_PG_GENERAL_OVR;
7158823STruong.Q.Nguyen@Sun.COM r = scf_instance_delete_prop(inst, pgname,
7168823STruong.Q.Nguyen@Sun.COM SCF_PROPERTY_ENABLED);
7178823STruong.Q.Nguyen@Sun.COM switch (r) {
7188823STruong.Q.Nguyen@Sun.COM case 0:
7198823STruong.Q.Nguyen@Sun.COM break;
7208823STruong.Q.Nguyen@Sun.COM
7218823STruong.Q.Nguyen@Sun.COM case ECANCELED:
7228823STruong.Q.Nguyen@Sun.COM uu_warn(emsg_no_service, fmri);
7238823STruong.Q.Nguyen@Sun.COM goto out;
7248823STruong.Q.Nguyen@Sun.COM
7258823STruong.Q.Nguyen@Sun.COM case EPERM:
7268823STruong.Q.Nguyen@Sun.COM goto eperm;
7278823STruong.Q.Nguyen@Sun.COM
7288823STruong.Q.Nguyen@Sun.COM case EACCES:
7298823STruong.Q.Nguyen@Sun.COM uu_warn(gettext("Could not delete %s/%s "
7308823STruong.Q.Nguyen@Sun.COM "property of %s: backend access denied.\n"),
7318823STruong.Q.Nguyen@Sun.COM pgname, SCF_PROPERTY_ENABLED, fmri);
7328823STruong.Q.Nguyen@Sun.COM goto out;
7338823STruong.Q.Nguyen@Sun.COM
7348823STruong.Q.Nguyen@Sun.COM case EROFS:
7358823STruong.Q.Nguyen@Sun.COM uu_warn(gettext("Could not delete %s/%s "
7368823STruong.Q.Nguyen@Sun.COM "property of %s: backend is read-only.\n"),
7378823STruong.Q.Nguyen@Sun.COM pgname, SCF_PROPERTY_ENABLED, fmri);
7388823STruong.Q.Nguyen@Sun.COM goto out;
7398823STruong.Q.Nguyen@Sun.COM
7408823STruong.Q.Nguyen@Sun.COM default:
7418823STruong.Q.Nguyen@Sun.COM bad_error("scf_instance_delete_prop", r);
7420Sstevel@tonic-gate }
7430Sstevel@tonic-gate
7440Sstevel@tonic-gate if (verbose)
7450Sstevel@tonic-gate (void) printf(enable ? gettext("%s enabled.\n") :
7460Sstevel@tonic-gate gettext("%s disabled.\n"), fmri);
7470Sstevel@tonic-gate }
7480Sstevel@tonic-gate
7490Sstevel@tonic-gate scf_pg_destroy(pg);
7500Sstevel@tonic-gate return;
7510Sstevel@tonic-gate
7520Sstevel@tonic-gate eperm:
7530Sstevel@tonic-gate assert(pgname != NULL);
7540Sstevel@tonic-gate if (!verbose)
7550Sstevel@tonic-gate uu_warn(emsg_permission_denied, fmri);
7560Sstevel@tonic-gate else
7570Sstevel@tonic-gate uu_warn(emsg_pg_perm_denied, fmri, pgname);
7580Sstevel@tonic-gate
7590Sstevel@tonic-gate out:
7600Sstevel@tonic-gate scf_pg_destroy(pg);
7610Sstevel@tonic-gate exit_status = 1;
7620Sstevel@tonic-gate }
7630Sstevel@tonic-gate
7640Sstevel@tonic-gate /*
7650Sstevel@tonic-gate * Set inst to the instance which corresponds to fmri. If fmri identifies
7660Sstevel@tonic-gate * a service with a single instance, get that instance.
7670Sstevel@tonic-gate *
7680Sstevel@tonic-gate * Fails with
7690Sstevel@tonic-gate * ENOTSUP - fmri has an unsupported scheme
7700Sstevel@tonic-gate * EINVAL - fmri is invalid
7710Sstevel@tonic-gate * ENOTDIR - fmri does not identify a service or instance
7720Sstevel@tonic-gate * ENOENT - could not locate instance
7730Sstevel@tonic-gate * E2BIG - fmri is a service with multiple instances (warning not printed)
7740Sstevel@tonic-gate */
7750Sstevel@tonic-gate static int
get_inst_mult(const char * fmri,scf_instance_t * inst)7760Sstevel@tonic-gate get_inst_mult(const char *fmri, scf_instance_t *inst)
7770Sstevel@tonic-gate {
7780Sstevel@tonic-gate char *cfmri;
7790Sstevel@tonic-gate const char *svc_name, *inst_name, *pg_name;
7800Sstevel@tonic-gate scf_service_t *svc;
7810Sstevel@tonic-gate scf_instance_t *inst2;
7820Sstevel@tonic-gate scf_iter_t *iter;
7830Sstevel@tonic-gate int ret;
7840Sstevel@tonic-gate
7850Sstevel@tonic-gate if (strncmp(fmri, "lrc:", sizeof ("lrc:") - 1) == 0) {
7860Sstevel@tonic-gate uu_warn(gettext("FMRI \"%s\" is a legacy service.\n"), fmri);
7870Sstevel@tonic-gate exit_status = 1;
7880Sstevel@tonic-gate return (ENOTSUP);
7890Sstevel@tonic-gate }
7900Sstevel@tonic-gate
7910Sstevel@tonic-gate cfmri = strdup(fmri);
7920Sstevel@tonic-gate if (cfmri == NULL)
7930Sstevel@tonic-gate uu_die(emsg_nomem);
7940Sstevel@tonic-gate
7950Sstevel@tonic-gate if (scf_parse_svc_fmri(cfmri, NULL, &svc_name, &inst_name, &pg_name,
7960Sstevel@tonic-gate NULL) != SCF_SUCCESS) {
7970Sstevel@tonic-gate free(cfmri);
7980Sstevel@tonic-gate uu_warn(gettext("FMRI \"%s\" is invalid.\n"), fmri);
7990Sstevel@tonic-gate exit_status = 1;
8000Sstevel@tonic-gate return (EINVAL);
8010Sstevel@tonic-gate }
8020Sstevel@tonic-gate
8030Sstevel@tonic-gate free(cfmri);
8040Sstevel@tonic-gate
8050Sstevel@tonic-gate if (svc_name == NULL || pg_name != NULL) {
8060Sstevel@tonic-gate uu_warn(gettext(
8070Sstevel@tonic-gate "FMRI \"%s\" does not designate a service or instance.\n"),
8080Sstevel@tonic-gate fmri);
8090Sstevel@tonic-gate exit_status = 1;
8100Sstevel@tonic-gate return (ENOTDIR);
8110Sstevel@tonic-gate }
8120Sstevel@tonic-gate
8130Sstevel@tonic-gate if (inst_name != NULL) {
8140Sstevel@tonic-gate if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
8150Sstevel@tonic-gate NULL, SCF_DECODE_FMRI_EXACT) == 0)
8160Sstevel@tonic-gate return (0);
8170Sstevel@tonic-gate
8180Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NOT_FOUND)
8190Sstevel@tonic-gate scfdie();
8200Sstevel@tonic-gate
8210Sstevel@tonic-gate uu_warn(gettext("No such instance \"%s\".\n"), fmri);
8220Sstevel@tonic-gate exit_status = 1;
8230Sstevel@tonic-gate
8240Sstevel@tonic-gate return (ENOENT);
8250Sstevel@tonic-gate }
8260Sstevel@tonic-gate
8270Sstevel@tonic-gate if ((svc = scf_service_create(h)) == NULL ||
8280Sstevel@tonic-gate (inst2 = scf_instance_create(h)) == NULL ||
8290Sstevel@tonic-gate (iter = scf_iter_create(h)) == NULL)
8300Sstevel@tonic-gate scfdie();
8310Sstevel@tonic-gate
8320Sstevel@tonic-gate if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
8330Sstevel@tonic-gate SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
8340Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NOT_FOUND)
8350Sstevel@tonic-gate scfdie();
8360Sstevel@tonic-gate
8370Sstevel@tonic-gate uu_warn(emsg_no_service, fmri);
8380Sstevel@tonic-gate exit_status = 1;
8390Sstevel@tonic-gate
8400Sstevel@tonic-gate ret = ENOENT;
8410Sstevel@tonic-gate goto out;
8420Sstevel@tonic-gate }
8430Sstevel@tonic-gate
8440Sstevel@tonic-gate /* If the service has only one child, use it. */
8450Sstevel@tonic-gate if (scf_iter_service_instances(iter, svc) != SCF_SUCCESS)
8460Sstevel@tonic-gate scfdie();
8470Sstevel@tonic-gate
8480Sstevel@tonic-gate ret = scf_iter_next_instance(iter, inst);
8490Sstevel@tonic-gate if (ret < 0)
8500Sstevel@tonic-gate scfdie();
8510Sstevel@tonic-gate if (ret != 1) {
8520Sstevel@tonic-gate uu_warn(gettext("Service \"%s\" has no instances.\n"),
8530Sstevel@tonic-gate fmri);
8540Sstevel@tonic-gate exit_status = 1;
8550Sstevel@tonic-gate ret = ENOENT;
8560Sstevel@tonic-gate goto out;
8570Sstevel@tonic-gate }
8580Sstevel@tonic-gate
8590Sstevel@tonic-gate ret = scf_iter_next_instance(iter, inst2);
8600Sstevel@tonic-gate if (ret < 0)
8610Sstevel@tonic-gate scfdie();
8620Sstevel@tonic-gate
8630Sstevel@tonic-gate if (ret != 0) {
8640Sstevel@tonic-gate ret = E2BIG;
8650Sstevel@tonic-gate goto out;
8660Sstevel@tonic-gate }
8670Sstevel@tonic-gate
8680Sstevel@tonic-gate ret = 0;
8690Sstevel@tonic-gate
8700Sstevel@tonic-gate out:
8710Sstevel@tonic-gate scf_iter_destroy(iter);
8720Sstevel@tonic-gate scf_instance_destroy(inst2);
8730Sstevel@tonic-gate scf_service_destroy(svc);
8740Sstevel@tonic-gate return (ret);
8750Sstevel@tonic-gate }
8760Sstevel@tonic-gate
8770Sstevel@tonic-gate /*
8780Sstevel@tonic-gate * Same as get_inst_mult(), but on E2BIG prints a warning and returns ENOENT.
8790Sstevel@tonic-gate */
8800Sstevel@tonic-gate static int
get_inst(const char * fmri,scf_instance_t * inst)8810Sstevel@tonic-gate get_inst(const char *fmri, scf_instance_t *inst)
8820Sstevel@tonic-gate {
8830Sstevel@tonic-gate int r;
8840Sstevel@tonic-gate
8850Sstevel@tonic-gate r = get_inst_mult(fmri, inst);
8860Sstevel@tonic-gate if (r != E2BIG)
8870Sstevel@tonic-gate return (r);
8880Sstevel@tonic-gate
8890Sstevel@tonic-gate uu_warn(gettext("operation on service %s is ambiguous; "
8900Sstevel@tonic-gate "instance specification needed.\n"), fmri);
8910Sstevel@tonic-gate return (ENOENT);
8920Sstevel@tonic-gate }
8930Sstevel@tonic-gate
8940Sstevel@tonic-gate static char *
inst_get_fmri(const scf_instance_t * inst)8950Sstevel@tonic-gate inst_get_fmri(const scf_instance_t *inst)
8960Sstevel@tonic-gate {
8970Sstevel@tonic-gate ssize_t sz;
8980Sstevel@tonic-gate
8990Sstevel@tonic-gate sz = scf_instance_to_fmri(inst, scratch_fmri, max_scf_fmri_sz);
9000Sstevel@tonic-gate if (sz < 0)
9010Sstevel@tonic-gate scfdie();
9020Sstevel@tonic-gate if (sz >= max_scf_fmri_sz)
9030Sstevel@tonic-gate uu_die(gettext("scf_instance_to_fmri() returned unexpectedly "
9040Sstevel@tonic-gate "long value.\n"));
9050Sstevel@tonic-gate
9060Sstevel@tonic-gate return (scratch_fmri);
9070Sstevel@tonic-gate }
9080Sstevel@tonic-gate
9090Sstevel@tonic-gate static ssize_t
dep_get_astring(const char * fmri,const char * pgname,const scf_propertygroup_t * pg,const char * propname,scf_property_t * prop,scf_value_t * v,char * buf,size_t bufsz)9100Sstevel@tonic-gate dep_get_astring(const char *fmri, const char *pgname,
9110Sstevel@tonic-gate const scf_propertygroup_t *pg, const char *propname, scf_property_t *prop,
9120Sstevel@tonic-gate scf_value_t *v, char *buf, size_t bufsz)
9130Sstevel@tonic-gate {
9140Sstevel@tonic-gate ssize_t sz;
9150Sstevel@tonic-gate
9160Sstevel@tonic-gate sz = get_astring_prop(pg, propname, prop, v, buf, bufsz);
9170Sstevel@tonic-gate if (sz >= 0)
9180Sstevel@tonic-gate return (sz);
9190Sstevel@tonic-gate
9200Sstevel@tonic-gate switch (-sz) {
9210Sstevel@tonic-gate case ENOENT:
9220Sstevel@tonic-gate uu_warn(gettext("\"%s\" is misconfigured (\"%s\" dependency "
9230Sstevel@tonic-gate "lacks \"%s\" property.)\n"), fmri, pgname, propname);
9240Sstevel@tonic-gate return (-1);
9250Sstevel@tonic-gate
9260Sstevel@tonic-gate case E2BIG:
9270Sstevel@tonic-gate uu_warn(gettext("\"%s\" is misconfigured (\"%s/%s\" property "
9280Sstevel@tonic-gate "is not single-valued.)\n"), fmri, pgname, propname);
9290Sstevel@tonic-gate return (-1);
9300Sstevel@tonic-gate
9310Sstevel@tonic-gate case EINVAL:
9320Sstevel@tonic-gate uu_warn(gettext("\"%s\" is misconfigured (\"%s/%s\" property "
9330Sstevel@tonic-gate "is not of astring type.)\n"), fmri, pgname, propname);
9340Sstevel@tonic-gate return (-1);
9350Sstevel@tonic-gate
9360Sstevel@tonic-gate default:
9370Sstevel@tonic-gate assert(0);
9380Sstevel@tonic-gate abort();
9390Sstevel@tonic-gate /* NOTREACHED */
9400Sstevel@tonic-gate }
9410Sstevel@tonic-gate }
9420Sstevel@tonic-gate
9430Sstevel@tonic-gate static boolean_t
multiple_instances(scf_iter_t * iter,scf_value_t * v,char * buf)9440Sstevel@tonic-gate multiple_instances(scf_iter_t *iter, scf_value_t *v, char *buf)
9450Sstevel@tonic-gate {
9460Sstevel@tonic-gate int count = 0, r;
9470Sstevel@tonic-gate boolean_t ret;
9480Sstevel@tonic-gate scf_instance_t *inst;
9490Sstevel@tonic-gate
9500Sstevel@tonic-gate inst = scf_instance_create(h);
9510Sstevel@tonic-gate if (inst == NULL)
9520Sstevel@tonic-gate scfdie();
9530Sstevel@tonic-gate
9540Sstevel@tonic-gate for (;;) {
9550Sstevel@tonic-gate r = scf_iter_next_value(iter, v);
9560Sstevel@tonic-gate if (r == 0) {
9570Sstevel@tonic-gate ret = B_FALSE;
9580Sstevel@tonic-gate goto out;
9590Sstevel@tonic-gate }
9600Sstevel@tonic-gate if (r != 1)
9610Sstevel@tonic-gate scfdie();
9620Sstevel@tonic-gate
9630Sstevel@tonic-gate if (scf_value_get_astring(v, buf, max_scf_fmri_sz) < 0)
9640Sstevel@tonic-gate scfdie();
9650Sstevel@tonic-gate
9660Sstevel@tonic-gate switch (get_inst_mult(buf, inst)) {
9670Sstevel@tonic-gate case 0:
9680Sstevel@tonic-gate ++count;
9690Sstevel@tonic-gate if (count > 1) {
9700Sstevel@tonic-gate ret = B_TRUE;
9710Sstevel@tonic-gate goto out;
9720Sstevel@tonic-gate }
9730Sstevel@tonic-gate break;
9740Sstevel@tonic-gate
9750Sstevel@tonic-gate case ENOTSUP:
9760Sstevel@tonic-gate case EINVAL:
9770Sstevel@tonic-gate case ENOTDIR:
9780Sstevel@tonic-gate case ENOENT:
9790Sstevel@tonic-gate continue;
9800Sstevel@tonic-gate
9810Sstevel@tonic-gate case E2BIG:
9820Sstevel@tonic-gate ret = B_TRUE;
9830Sstevel@tonic-gate goto out;
9840Sstevel@tonic-gate
9850Sstevel@tonic-gate default:
9860Sstevel@tonic-gate assert(0);
9870Sstevel@tonic-gate abort();
9880Sstevel@tonic-gate }
9890Sstevel@tonic-gate }
9900Sstevel@tonic-gate
9910Sstevel@tonic-gate out:
9920Sstevel@tonic-gate scf_instance_destroy(inst);
9930Sstevel@tonic-gate return (ret);
9940Sstevel@tonic-gate }
9950Sstevel@tonic-gate
9960Sstevel@tonic-gate /*
9970Sstevel@tonic-gate * Enable the service or instance identified by fmri and its dependencies,
9980Sstevel@tonic-gate * recursively. Specifically, call get_inst(fmri), enable the result, and
9990Sstevel@tonic-gate * recurse on its restarter and the dependencies. To avoid duplication of
10000Sstevel@tonic-gate * effort or looping around a dependency cycle, each FMRI is entered into the
10010Sstevel@tonic-gate * "visited" hash table. While recursing, the hash table entry is marked
10020Sstevel@tonic-gate * "active", so that if we come upon it again, we know we've hit a cycle.
10030Sstevel@tonic-gate * exclude_all and optional_all dependencies are ignored. require_any
10040Sstevel@tonic-gate * dependencies are followed only if they comprise a single service; otherwise
10050Sstevel@tonic-gate * the user is warned.
10060Sstevel@tonic-gate *
10070Sstevel@tonic-gate * fmri must point to a writable max_scf_fmri_sz buffer. Returns EINVAL if fmri
10080Sstevel@tonic-gate * is invalid, E2BIG if fmri identifies a service with multiple instances, ELOOP
10090Sstevel@tonic-gate * on cycle detection, or 0 on success.
10100Sstevel@tonic-gate */
10110Sstevel@tonic-gate static int
enable_fmri_rec(char * fmri,boolean_t temp)10120Sstevel@tonic-gate enable_fmri_rec(char *fmri, boolean_t temp)
10130Sstevel@tonic-gate {
10140Sstevel@tonic-gate scf_instance_t *inst;
10150Sstevel@tonic-gate scf_snapshot_t *snap;
10160Sstevel@tonic-gate scf_propertygroup_t *pg;
10170Sstevel@tonic-gate scf_property_t *prop;
10180Sstevel@tonic-gate scf_value_t *v;
10190Sstevel@tonic-gate scf_iter_t *pg_iter, *val_iter;
10200Sstevel@tonic-gate scf_type_t ty;
10210Sstevel@tonic-gate char *buf, *pgname;
10220Sstevel@tonic-gate ssize_t name_sz, len, sz;
10230Sstevel@tonic-gate int ret;
10240Sstevel@tonic-gate struct ht_elt *he;
10250Sstevel@tonic-gate
10260Sstevel@tonic-gate len = scf_canonify_fmri(fmri, fmri, max_scf_fmri_sz);
10270Sstevel@tonic-gate if (len < 0) {
10280Sstevel@tonic-gate assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
10290Sstevel@tonic-gate return (EINVAL);
10300Sstevel@tonic-gate }
10310Sstevel@tonic-gate assert(len < max_scf_fmri_sz);
10320Sstevel@tonic-gate
10330Sstevel@tonic-gate switch (visited_find_or_add(fmri, &he)) {
10340Sstevel@tonic-gate case 0:
10350Sstevel@tonic-gate he->active = B_TRUE;
10360Sstevel@tonic-gate break;
10370Sstevel@tonic-gate
10380Sstevel@tonic-gate case 1:
10390Sstevel@tonic-gate return (he->active ? ELOOP : 0);
10400Sstevel@tonic-gate
10410Sstevel@tonic-gate case -1:
10420Sstevel@tonic-gate uu_die(emsg_nomem);
10430Sstevel@tonic-gate
10440Sstevel@tonic-gate default:
10450Sstevel@tonic-gate assert(0);
10460Sstevel@tonic-gate abort();
10470Sstevel@tonic-gate }
10480Sstevel@tonic-gate
10490Sstevel@tonic-gate inst = scf_instance_create(h);
10500Sstevel@tonic-gate if (inst == NULL)
10510Sstevel@tonic-gate scfdie();
10520Sstevel@tonic-gate
10530Sstevel@tonic-gate switch (get_inst_mult(fmri, inst)) {
10540Sstevel@tonic-gate case 0:
10550Sstevel@tonic-gate break;
10560Sstevel@tonic-gate
10570Sstevel@tonic-gate case E2BIG:
10580Sstevel@tonic-gate he->active = B_FALSE;
10590Sstevel@tonic-gate return (E2BIG);
10600Sstevel@tonic-gate
10610Sstevel@tonic-gate default:
10620Sstevel@tonic-gate he->active = B_FALSE;
10630Sstevel@tonic-gate return (0);
10640Sstevel@tonic-gate }
10650Sstevel@tonic-gate
10660Sstevel@tonic-gate set_inst_enabled(fmri, inst, temp, B_TRUE);
10670Sstevel@tonic-gate
10680Sstevel@tonic-gate if ((snap = scf_snapshot_create(h)) == NULL ||
10690Sstevel@tonic-gate (pg = scf_pg_create(h)) == NULL ||
10700Sstevel@tonic-gate (prop = scf_property_create(h)) == NULL ||
10710Sstevel@tonic-gate (v = scf_value_create(h)) == NULL ||
10720Sstevel@tonic-gate (pg_iter = scf_iter_create(h)) == NULL ||
10730Sstevel@tonic-gate (val_iter = scf_iter_create(h)) == NULL)
10740Sstevel@tonic-gate scfdie();
10750Sstevel@tonic-gate
10760Sstevel@tonic-gate buf = malloc(max_scf_fmri_sz);
10770Sstevel@tonic-gate if (buf == NULL)
10780Sstevel@tonic-gate uu_die(emsg_nomem);
10790Sstevel@tonic-gate
10800Sstevel@tonic-gate name_sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
10810Sstevel@tonic-gate if (name_sz < 0)
10820Sstevel@tonic-gate scfdie();
10830Sstevel@tonic-gate ++name_sz;
10840Sstevel@tonic-gate pgname = malloc(name_sz);
10850Sstevel@tonic-gate if (pgname == NULL)
10860Sstevel@tonic-gate uu_die(emsg_nomem);
10870Sstevel@tonic-gate
10880Sstevel@tonic-gate if (scf_instance_get_snapshot(inst, "running", snap) != 0) {
10890Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NOT_FOUND)
10900Sstevel@tonic-gate scfdie();
10910Sstevel@tonic-gate
10920Sstevel@tonic-gate scf_snapshot_destroy(snap);
10930Sstevel@tonic-gate snap = NULL;
10940Sstevel@tonic-gate }
10950Sstevel@tonic-gate
10960Sstevel@tonic-gate /* Enable restarter */
10970Sstevel@tonic-gate if (scf_instance_get_pg_composed(inst, snap, SCF_PG_GENERAL, pg) != 0) {
10980Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NOT_FOUND)
10990Sstevel@tonic-gate scfdie();
11000Sstevel@tonic-gate
11010Sstevel@tonic-gate uu_warn(gettext("\"%s\" is misconfigured (lacks \"%s\" "
11020Sstevel@tonic-gate "property group).\n"), fmri, SCF_PG_GENERAL);
11030Sstevel@tonic-gate ret = 0;
11040Sstevel@tonic-gate goto out;
11050Sstevel@tonic-gate }
11060Sstevel@tonic-gate
11070Sstevel@tonic-gate sz = get_astring_prop(pg, SCF_PROPERTY_RESTARTER, prop, v, buf,
11080Sstevel@tonic-gate max_scf_fmri_sz);
11090Sstevel@tonic-gate if (sz > max_scf_fmri_sz) {
11100Sstevel@tonic-gate uu_warn(gettext("\"%s\" is misconfigured (the value of "
11110Sstevel@tonic-gate "\"%s/%s\" is too long).\n"), fmri, SCF_PG_GENERAL,
11120Sstevel@tonic-gate SCF_PROPERTY_RESTARTER);
11130Sstevel@tonic-gate ret = 0;
11140Sstevel@tonic-gate goto out;
11150Sstevel@tonic-gate } else if (sz >= 0) {
11160Sstevel@tonic-gate switch (enable_fmri_rec(buf, temp)) {
11170Sstevel@tonic-gate case 0:
11180Sstevel@tonic-gate break;
11190Sstevel@tonic-gate
11200Sstevel@tonic-gate case EINVAL:
11210Sstevel@tonic-gate uu_warn(gettext("Restarter FMRI for \"%s\" is "
11220Sstevel@tonic-gate "invalid.\n"), fmri);
11230Sstevel@tonic-gate break;
11240Sstevel@tonic-gate
11250Sstevel@tonic-gate case E2BIG:
11260Sstevel@tonic-gate uu_warn(gettext("Restarter FMRI for \"%s\" identifies "
11270Sstevel@tonic-gate "a service with multiple instances.\n"), fmri);
11280Sstevel@tonic-gate break;
11290Sstevel@tonic-gate
11300Sstevel@tonic-gate case ELOOP:
11310Sstevel@tonic-gate ret = ELOOP;
11320Sstevel@tonic-gate goto out;
11330Sstevel@tonic-gate
11340Sstevel@tonic-gate default:
11350Sstevel@tonic-gate assert(0);
11360Sstevel@tonic-gate abort();
11370Sstevel@tonic-gate }
11380Sstevel@tonic-gate } else if (sz < 0) {
11390Sstevel@tonic-gate switch (-sz) {
11400Sstevel@tonic-gate case ENOENT:
11410Sstevel@tonic-gate break;
11420Sstevel@tonic-gate
11430Sstevel@tonic-gate case E2BIG:
11440Sstevel@tonic-gate uu_warn(gettext("\"%s\" is misconfigured (\"%s/%s\" "
11450Sstevel@tonic-gate "property is not single-valued).\n"), fmri,
11460Sstevel@tonic-gate SCF_PG_GENERAL, SCF_PROPERTY_RESTARTER);
11470Sstevel@tonic-gate ret = 0;
11480Sstevel@tonic-gate goto out;
11490Sstevel@tonic-gate
11500Sstevel@tonic-gate case EINVAL:
11510Sstevel@tonic-gate uu_warn(gettext("\"%s\" is misconfigured (\"%s/%s\" "
11520Sstevel@tonic-gate "property is not of astring type).\n"), fmri,
11530Sstevel@tonic-gate SCF_PG_GENERAL, SCF_PROPERTY_RESTARTER);
11540Sstevel@tonic-gate ret = 0;
11550Sstevel@tonic-gate goto out;
11560Sstevel@tonic-gate
11570Sstevel@tonic-gate default:
11580Sstevel@tonic-gate assert(0);
11590Sstevel@tonic-gate abort();
11600Sstevel@tonic-gate }
11610Sstevel@tonic-gate }
11620Sstevel@tonic-gate
11630Sstevel@tonic-gate if (scf_iter_instance_pgs_typed_composed(pg_iter, inst, snap,
11640Sstevel@tonic-gate SCF_GROUP_DEPENDENCY) == -1)
11650Sstevel@tonic-gate scfdie();
11660Sstevel@tonic-gate
11670Sstevel@tonic-gate while (scf_iter_next_pg(pg_iter, pg) > 0) {
11680Sstevel@tonic-gate len = scf_pg_get_name(pg, pgname, name_sz);
11690Sstevel@tonic-gate if (len < 0)
11700Sstevel@tonic-gate scfdie();
11710Sstevel@tonic-gate assert(len < name_sz);
11720Sstevel@tonic-gate
11730Sstevel@tonic-gate if (dep_get_astring(fmri, pgname, pg, SCF_PROPERTY_TYPE, prop,
11740Sstevel@tonic-gate v, buf, max_scf_fmri_sz) < 0)
11750Sstevel@tonic-gate continue;
11760Sstevel@tonic-gate
11770Sstevel@tonic-gate if (strcmp(buf, "service") != 0)
11780Sstevel@tonic-gate continue;
11790Sstevel@tonic-gate
11800Sstevel@tonic-gate if (dep_get_astring(fmri, pgname, pg, SCF_PROPERTY_GROUPING,
11810Sstevel@tonic-gate prop, v, buf, max_scf_fmri_sz) < 0)
11820Sstevel@tonic-gate continue;
11830Sstevel@tonic-gate
11840Sstevel@tonic-gate if (strcmp(buf, SCF_DEP_EXCLUDE_ALL) == 0 ||
11850Sstevel@tonic-gate strcmp(buf, SCF_DEP_OPTIONAL_ALL) == 0)
11860Sstevel@tonic-gate continue;
11870Sstevel@tonic-gate
11880Sstevel@tonic-gate if (strcmp(buf, SCF_DEP_REQUIRE_ALL) != 0 &&
11890Sstevel@tonic-gate strcmp(buf, SCF_DEP_REQUIRE_ANY) != 0) {
11900Sstevel@tonic-gate uu_warn(gettext("Dependency \"%s\" of \"%s\" has "
11910Sstevel@tonic-gate "unknown type \"%s\".\n"), pgname, fmri, buf);
11920Sstevel@tonic-gate continue;
11930Sstevel@tonic-gate }
11940Sstevel@tonic-gate
11950Sstevel@tonic-gate if (scf_pg_get_property(pg, SCF_PROPERTY_ENTITIES, prop) ==
11960Sstevel@tonic-gate -1) {
11970Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NOT_FOUND)
11980Sstevel@tonic-gate scfdie();
11990Sstevel@tonic-gate
12000Sstevel@tonic-gate uu_warn(gettext("\"%s\" is misconfigured (\"%s\" "
12010Sstevel@tonic-gate "dependency lacks \"%s\" property.)\n"), fmri,
12020Sstevel@tonic-gate pgname, SCF_PROPERTY_ENTITIES);
12030Sstevel@tonic-gate continue;
12040Sstevel@tonic-gate }
12050Sstevel@tonic-gate
12060Sstevel@tonic-gate if (scf_property_type(prop, &ty) != SCF_SUCCESS)
12070Sstevel@tonic-gate scfdie();
12080Sstevel@tonic-gate
12090Sstevel@tonic-gate if (ty != SCF_TYPE_FMRI) {
12100Sstevel@tonic-gate uu_warn(gettext("\"%s\" is misconfigured (property "
12110Sstevel@tonic-gate "\"%s/%s\" is not of fmri type).\n"), fmri, pgname,
12120Sstevel@tonic-gate SCF_PROPERTY_ENTITIES);
12130Sstevel@tonic-gate continue;
12140Sstevel@tonic-gate }
12150Sstevel@tonic-gate
12160Sstevel@tonic-gate if (scf_iter_property_values(val_iter, prop) == -1)
12170Sstevel@tonic-gate scfdie();
12180Sstevel@tonic-gate
12190Sstevel@tonic-gate if (strcmp(buf, SCF_DEP_REQUIRE_ANY) == 0) {
12200Sstevel@tonic-gate if (multiple_instances(val_iter, v, buf)) {
12210Sstevel@tonic-gate (void) printf(gettext("%s requires one of:\n"),
12220Sstevel@tonic-gate fmri);
12230Sstevel@tonic-gate
12240Sstevel@tonic-gate if (scf_iter_property_values(val_iter, prop) !=
12250Sstevel@tonic-gate 0)
12260Sstevel@tonic-gate scfdie();
12270Sstevel@tonic-gate
12280Sstevel@tonic-gate for (;;) {
12290Sstevel@tonic-gate int r;
12300Sstevel@tonic-gate
12310Sstevel@tonic-gate r = scf_iter_next_value(val_iter, v);
12320Sstevel@tonic-gate if (r == 0)
12330Sstevel@tonic-gate break;
12340Sstevel@tonic-gate if (r != 1)
12350Sstevel@tonic-gate scfdie();
12360Sstevel@tonic-gate
12370Sstevel@tonic-gate if (scf_value_get_astring(v, buf,
12380Sstevel@tonic-gate max_scf_fmri_sz) < 0)
12390Sstevel@tonic-gate scfdie();
12400Sstevel@tonic-gate
12410Sstevel@tonic-gate (void) fputs(" ", stdout);
12420Sstevel@tonic-gate (void) puts(buf);
12430Sstevel@tonic-gate }
12440Sstevel@tonic-gate
12450Sstevel@tonic-gate continue;
12460Sstevel@tonic-gate }
12470Sstevel@tonic-gate
12480Sstevel@tonic-gate /*
12490Sstevel@tonic-gate * Since there's only one instance, we can enable it.
12500Sstevel@tonic-gate * Reset val_iter and continue.
12510Sstevel@tonic-gate */
12520Sstevel@tonic-gate if (scf_iter_property_values(val_iter, prop) != 0)
12530Sstevel@tonic-gate scfdie();
12540Sstevel@tonic-gate }
12550Sstevel@tonic-gate
12560Sstevel@tonic-gate for (;;) {
12570Sstevel@tonic-gate ret = scf_iter_next_value(val_iter, v);
12580Sstevel@tonic-gate if (ret == 0)
12590Sstevel@tonic-gate break;
12600Sstevel@tonic-gate if (ret != 1)
12610Sstevel@tonic-gate scfdie();
12620Sstevel@tonic-gate
12630Sstevel@tonic-gate if (scf_value_get_astring(v, buf, max_scf_fmri_sz) ==
12640Sstevel@tonic-gate -1)
12650Sstevel@tonic-gate scfdie();
12660Sstevel@tonic-gate
12670Sstevel@tonic-gate switch (enable_fmri_rec(buf, temp)) {
12680Sstevel@tonic-gate case 0:
12690Sstevel@tonic-gate break;
12700Sstevel@tonic-gate
12710Sstevel@tonic-gate case EINVAL:
12720Sstevel@tonic-gate uu_warn(gettext("\"%s\" dependency of \"%s\" "
12730Sstevel@tonic-gate "has invalid FMRI \"%s\".\n"), pgname,
12740Sstevel@tonic-gate fmri, buf);
12750Sstevel@tonic-gate break;
12760Sstevel@tonic-gate
12770Sstevel@tonic-gate case E2BIG:
12780Sstevel@tonic-gate uu_warn(gettext("%s depends on %s, which has "
12790Sstevel@tonic-gate "multiple instances.\n"), fmri, buf);
12800Sstevel@tonic-gate break;
12810Sstevel@tonic-gate
12820Sstevel@tonic-gate case ELOOP:
12830Sstevel@tonic-gate ret = ELOOP;
12840Sstevel@tonic-gate goto out;
12850Sstevel@tonic-gate
12860Sstevel@tonic-gate default:
12870Sstevel@tonic-gate assert(0);
12880Sstevel@tonic-gate abort();
12890Sstevel@tonic-gate }
12900Sstevel@tonic-gate }
12910Sstevel@tonic-gate }
12920Sstevel@tonic-gate
12930Sstevel@tonic-gate ret = 0;
12940Sstevel@tonic-gate
12950Sstevel@tonic-gate out:
12960Sstevel@tonic-gate he->active = B_FALSE;
12970Sstevel@tonic-gate
12980Sstevel@tonic-gate free(buf);
12990Sstevel@tonic-gate free(pgname);
13000Sstevel@tonic-gate
13010Sstevel@tonic-gate (void) scf_value_destroy(v);
13020Sstevel@tonic-gate scf_property_destroy(prop);
13030Sstevel@tonic-gate scf_pg_destroy(pg);
13040Sstevel@tonic-gate scf_snapshot_destroy(snap);
13050Sstevel@tonic-gate scf_iter_destroy(pg_iter);
13060Sstevel@tonic-gate scf_iter_destroy(val_iter);
13070Sstevel@tonic-gate
13080Sstevel@tonic-gate return (ret);
13090Sstevel@tonic-gate }
13100Sstevel@tonic-gate
13110Sstevel@tonic-gate /*
13120Sstevel@tonic-gate * fmri here is only used for verbose messages.
13130Sstevel@tonic-gate */
13140Sstevel@tonic-gate static void
set_inst_action(const char * fmri,const scf_instance_t * inst,const char * action)13150Sstevel@tonic-gate set_inst_action(const char *fmri, const scf_instance_t *inst,
13160Sstevel@tonic-gate const char *action)
13170Sstevel@tonic-gate {
13180Sstevel@tonic-gate scf_transaction_t *tx;
13190Sstevel@tonic-gate scf_transaction_entry_t *ent;
13200Sstevel@tonic-gate scf_propertygroup_t *pg;
13210Sstevel@tonic-gate scf_property_t *prop;
13220Sstevel@tonic-gate scf_value_t *v;
13230Sstevel@tonic-gate int ret;
13240Sstevel@tonic-gate int64_t t;
13250Sstevel@tonic-gate hrtime_t timestamp;
13260Sstevel@tonic-gate
13270Sstevel@tonic-gate const char * const scf_pg_restarter_actions = SCF_PG_RESTARTER_ACTIONS;
13280Sstevel@tonic-gate
13290Sstevel@tonic-gate if ((pg = scf_pg_create(h)) == NULL ||
13300Sstevel@tonic-gate (prop = scf_property_create(h)) == NULL ||
13310Sstevel@tonic-gate (v = scf_value_create(h)) == NULL ||
13320Sstevel@tonic-gate (tx = scf_transaction_create(h)) == NULL ||
13330Sstevel@tonic-gate (ent = scf_entry_create(h)) == NULL)
13340Sstevel@tonic-gate scfdie();
13350Sstevel@tonic-gate
13368823STruong.Q.Nguyen@Sun.COM if (restarter_setup(fmri, inst))
1337*11223STruong.Q.Nguyen@Sun.COM goto out;
13388823STruong.Q.Nguyen@Sun.COM
13390Sstevel@tonic-gate if (scf_instance_get_pg(inst, scf_pg_restarter_actions, pg) == -1) {
13400Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NOT_FOUND)
13410Sstevel@tonic-gate scfdie();
13420Sstevel@tonic-gate
13430Sstevel@tonic-gate /* Try creating the restarter_actions property group. */
13440Sstevel@tonic-gate if (scf_instance_add_pg(inst, scf_pg_restarter_actions,
13450Sstevel@tonic-gate SCF_PG_RESTARTER_ACTIONS_TYPE,
13460Sstevel@tonic-gate SCF_PG_RESTARTER_ACTIONS_FLAGS, pg) == -1) {
13470Sstevel@tonic-gate switch (scf_error()) {
13480Sstevel@tonic-gate case SCF_ERROR_EXISTS:
13490Sstevel@tonic-gate /* Someone must have added it. */
13500Sstevel@tonic-gate break;
13510Sstevel@tonic-gate
13520Sstevel@tonic-gate case SCF_ERROR_PERMISSION_DENIED:
13530Sstevel@tonic-gate if (!verbose)
13540Sstevel@tonic-gate uu_warn(emsg_permission_denied, fmri);
13550Sstevel@tonic-gate else
13560Sstevel@tonic-gate uu_warn(emsg_create_pg_perm_denied,
13570Sstevel@tonic-gate fmri, scf_pg_restarter_actions);
13580Sstevel@tonic-gate goto out;
13590Sstevel@tonic-gate
13600Sstevel@tonic-gate default:
13610Sstevel@tonic-gate scfdie();
13620Sstevel@tonic-gate }
13630Sstevel@tonic-gate }
13640Sstevel@tonic-gate }
13650Sstevel@tonic-gate
13660Sstevel@tonic-gate /*
13670Sstevel@tonic-gate * If we lose the transaction race and need to retry, there are 2
13680Sstevel@tonic-gate * potential other winners:
13690Sstevel@tonic-gate * - another process setting actions
13700Sstevel@tonic-gate * - the restarter marking the action complete
13710Sstevel@tonic-gate * Therefore, re-read the property every time through the loop before
13720Sstevel@tonic-gate * making any decisions based on their values.
13730Sstevel@tonic-gate */
13740Sstevel@tonic-gate do {
13750Sstevel@tonic-gate timestamp = gethrtime();
13760Sstevel@tonic-gate
13770Sstevel@tonic-gate if (scf_transaction_start(tx, pg) == -1) {
13780Sstevel@tonic-gate if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13790Sstevel@tonic-gate scfdie();
13800Sstevel@tonic-gate
13810Sstevel@tonic-gate if (!verbose)
13820Sstevel@tonic-gate uu_warn(emsg_permission_denied, fmri);
13830Sstevel@tonic-gate else
13840Sstevel@tonic-gate uu_warn(emsg_pg_perm_denied, fmri,
13850Sstevel@tonic-gate scf_pg_restarter_actions);
13860Sstevel@tonic-gate goto out;
13870Sstevel@tonic-gate }
13880Sstevel@tonic-gate
13890Sstevel@tonic-gate if (scf_pg_get_property(pg, action, prop) == -1) {
13900Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NOT_FOUND)
13910Sstevel@tonic-gate scfdie();
13920Sstevel@tonic-gate if (scf_transaction_property_new(tx, ent,
13930Sstevel@tonic-gate action, SCF_TYPE_INTEGER) == -1)
13940Sstevel@tonic-gate scfdie();
13950Sstevel@tonic-gate goto action_set;
13960Sstevel@tonic-gate } else {
13970Sstevel@tonic-gate if (scf_transaction_property_change_type(tx, ent,
13980Sstevel@tonic-gate action, SCF_TYPE_INTEGER) == -1)
13990Sstevel@tonic-gate scfdie();
14000Sstevel@tonic-gate }
14010Sstevel@tonic-gate
14020Sstevel@tonic-gate if (scf_property_get_value(prop, v) == -1) {
14030Sstevel@tonic-gate switch (scf_error()) {
14040Sstevel@tonic-gate case SCF_ERROR_CONSTRAINT_VIOLATED:
14050Sstevel@tonic-gate case SCF_ERROR_NOT_FOUND:
14060Sstevel@tonic-gate /* Misconfigured, so set anyway. */
14070Sstevel@tonic-gate goto action_set;
14080Sstevel@tonic-gate
14090Sstevel@tonic-gate default:
14100Sstevel@tonic-gate scfdie();
14110Sstevel@tonic-gate }
14120Sstevel@tonic-gate } else {
14130Sstevel@tonic-gate if (scf_value_get_integer(v, &t) == -1) {
14140Sstevel@tonic-gate assert(scf_error() == SCF_ERROR_TYPE_MISMATCH);
14150Sstevel@tonic-gate goto action_set;
14160Sstevel@tonic-gate }
14170Sstevel@tonic-gate if (t > timestamp)
14180Sstevel@tonic-gate break;
14190Sstevel@tonic-gate }
14200Sstevel@tonic-gate
14210Sstevel@tonic-gate action_set:
14220Sstevel@tonic-gate scf_value_set_integer(v, timestamp);
14230Sstevel@tonic-gate if (scf_entry_add_value(ent, v) == -1)
14240Sstevel@tonic-gate scfdie();
14250Sstevel@tonic-gate
14260Sstevel@tonic-gate ret = scf_transaction_commit(tx);
14270Sstevel@tonic-gate if (ret == -1) {
14280Sstevel@tonic-gate if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14290Sstevel@tonic-gate scfdie();
14300Sstevel@tonic-gate
14310Sstevel@tonic-gate if (!verbose)
14320Sstevel@tonic-gate uu_warn(emsg_permission_denied, fmri);
14330Sstevel@tonic-gate else
14340Sstevel@tonic-gate uu_warn(emsg_prop_perm_denied, fmri,
14350Sstevel@tonic-gate scf_pg_restarter_actions, action);
14360Sstevel@tonic-gate scf_transaction_reset(tx);
14370Sstevel@tonic-gate goto out;
14380Sstevel@tonic-gate }
14390Sstevel@tonic-gate
14400Sstevel@tonic-gate scf_transaction_reset(tx);
14410Sstevel@tonic-gate
14420Sstevel@tonic-gate if (ret == 0) {
14430Sstevel@tonic-gate if (scf_pg_update(pg) == -1)
14440Sstevel@tonic-gate scfdie();
14450Sstevel@tonic-gate }
14460Sstevel@tonic-gate } while (ret == 0);
14470Sstevel@tonic-gate
14480Sstevel@tonic-gate if (verbose)
14490Sstevel@tonic-gate (void) printf(gettext("Action %s set for %s.\n"), action, fmri);
14500Sstevel@tonic-gate
14510Sstevel@tonic-gate out:
14520Sstevel@tonic-gate scf_value_destroy(v);
14530Sstevel@tonic-gate scf_entry_destroy(ent);
14540Sstevel@tonic-gate scf_transaction_destroy(tx);
14550Sstevel@tonic-gate scf_property_destroy(prop);
14560Sstevel@tonic-gate scf_pg_destroy(pg);
14570Sstevel@tonic-gate }
14580Sstevel@tonic-gate
14590Sstevel@tonic-gate /*
14600Sstevel@tonic-gate * Get the state of inst. state should point to a buffer of
14610Sstevel@tonic-gate * MAX_SCF_STATE_STRING_SZ bytes. Returns 0 on success or -1 if
14620Sstevel@tonic-gate * no restarter property group
14630Sstevel@tonic-gate * no state property
14640Sstevel@tonic-gate * state property is misconfigured (wrong type, not single-valued)
14650Sstevel@tonic-gate * state value is too long
14660Sstevel@tonic-gate * In these cases, fmri is used to print a warning.
14670Sstevel@tonic-gate *
14680Sstevel@tonic-gate * If pgp is non-NULL, a successful call to inst_get_state will store
14690Sstevel@tonic-gate * the SCF_PG_RESTARTER property group in *pgp, and the caller will be
14700Sstevel@tonic-gate * responsible for calling scf_pg_destroy on the property group.
14710Sstevel@tonic-gate */
14720Sstevel@tonic-gate int
inst_get_state(scf_instance_t * inst,char * state,const char * fmri,scf_propertygroup_t ** pgp)14730Sstevel@tonic-gate inst_get_state(scf_instance_t *inst, char *state, const char *fmri,
14740Sstevel@tonic-gate scf_propertygroup_t **pgp)
14750Sstevel@tonic-gate {
14760Sstevel@tonic-gate scf_propertygroup_t *pg;
14770Sstevel@tonic-gate scf_property_t *prop;
14780Sstevel@tonic-gate scf_value_t *val;
14790Sstevel@tonic-gate int ret = -1;
14800Sstevel@tonic-gate ssize_t szret;
14810Sstevel@tonic-gate
14820Sstevel@tonic-gate if ((pg = scf_pg_create(h)) == NULL ||
14830Sstevel@tonic-gate (prop = scf_property_create(h)) == NULL ||
14840Sstevel@tonic-gate (val = scf_value_create(h)) == NULL)
14850Sstevel@tonic-gate scfdie();
14860Sstevel@tonic-gate
14870Sstevel@tonic-gate if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
14880Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NOT_FOUND)
14890Sstevel@tonic-gate scfdie();
14900Sstevel@tonic-gate
14910Sstevel@tonic-gate uu_warn(gettext("%s is misconfigured (lacks \"%s\" property "
14920Sstevel@tonic-gate "group).\n"), fmri ? fmri : inst_get_fmri(inst),
14930Sstevel@tonic-gate SCF_PG_RESTARTER);
14940Sstevel@tonic-gate goto out;
14950Sstevel@tonic-gate }
14960Sstevel@tonic-gate
14970Sstevel@tonic-gate szret = get_astring_prop(pg, SCF_PROPERTY_STATE, prop, val, state,
14980Sstevel@tonic-gate MAX_SCF_STATE_STRING_SZ);
14990Sstevel@tonic-gate if (szret < 0) {
15000Sstevel@tonic-gate switch (-szret) {
15010Sstevel@tonic-gate case ENOENT:
15020Sstevel@tonic-gate uu_warn(gettext("%s is misconfigured (\"%s\" property "
15030Sstevel@tonic-gate "group lacks \"%s\" property).\n"),
15040Sstevel@tonic-gate fmri ? fmri : inst_get_fmri(inst), SCF_PG_RESTARTER,
15050Sstevel@tonic-gate SCF_PROPERTY_STATE);
15060Sstevel@tonic-gate goto out;
15070Sstevel@tonic-gate
15080Sstevel@tonic-gate case E2BIG:
15090Sstevel@tonic-gate uu_warn(gettext("%s is misconfigured (\"%s/%s\" "
15100Sstevel@tonic-gate "property is not single-valued).\n"),
15110Sstevel@tonic-gate fmri ? fmri : inst_get_fmri(inst), SCF_PG_RESTARTER,
15120Sstevel@tonic-gate SCF_PROPERTY_STATE);
15130Sstevel@tonic-gate goto out;
15140Sstevel@tonic-gate
15150Sstevel@tonic-gate case EINVAL:
15160Sstevel@tonic-gate uu_warn(gettext("%s is misconfigured (\"%s/%s\" "
15170Sstevel@tonic-gate "property is not of type astring).\n"),
15180Sstevel@tonic-gate fmri ? fmri : inst_get_fmri(inst), SCF_PG_RESTARTER,
15190Sstevel@tonic-gate SCF_PROPERTY_STATE);
15200Sstevel@tonic-gate goto out;
15210Sstevel@tonic-gate
15220Sstevel@tonic-gate default:
15230Sstevel@tonic-gate assert(0);
15240Sstevel@tonic-gate abort();
15250Sstevel@tonic-gate }
15260Sstevel@tonic-gate }
15270Sstevel@tonic-gate if (szret >= MAX_SCF_STATE_STRING_SZ) {
15280Sstevel@tonic-gate uu_warn(gettext("%s is misconfigured (\"%s/%s\" property value "
15290Sstevel@tonic-gate "is too long).\n"), fmri ? fmri : inst_get_fmri(inst),
15300Sstevel@tonic-gate SCF_PG_RESTARTER, SCF_PROPERTY_STATE);
15310Sstevel@tonic-gate goto out;
15320Sstevel@tonic-gate }
15330Sstevel@tonic-gate
15340Sstevel@tonic-gate ret = 0;
15350Sstevel@tonic-gate if (pgp)
15360Sstevel@tonic-gate *pgp = pg;
15370Sstevel@tonic-gate
15380Sstevel@tonic-gate out:
15390Sstevel@tonic-gate (void) scf_value_destroy(val);
15400Sstevel@tonic-gate scf_property_destroy(prop);
15410Sstevel@tonic-gate if (ret || pgp == NULL)
15420Sstevel@tonic-gate scf_pg_destroy(pg);
15430Sstevel@tonic-gate return (ret);
15440Sstevel@tonic-gate }
15450Sstevel@tonic-gate
15460Sstevel@tonic-gate static void
set_astring_prop(const char * fmri,const char * pgname,const char * pgtype,uint32_t pgflags,const char * propname,const char * str)15470Sstevel@tonic-gate set_astring_prop(const char *fmri, const char *pgname, const char *pgtype,
15480Sstevel@tonic-gate uint32_t pgflags, const char *propname, const char *str)
15490Sstevel@tonic-gate {
15500Sstevel@tonic-gate scf_instance_t *inst;
15510Sstevel@tonic-gate scf_propertygroup_t *pg;
15520Sstevel@tonic-gate scf_property_t *prop;
15530Sstevel@tonic-gate scf_value_t *val;
15540Sstevel@tonic-gate scf_transaction_t *tx;
15550Sstevel@tonic-gate scf_transaction_entry_t *txent;
15560Sstevel@tonic-gate int ret;
15570Sstevel@tonic-gate
15580Sstevel@tonic-gate inst = scf_instance_create(h);
15590Sstevel@tonic-gate if (inst == NULL)
15600Sstevel@tonic-gate scfdie();
15610Sstevel@tonic-gate
15620Sstevel@tonic-gate if (get_inst(fmri, inst) != 0)
15630Sstevel@tonic-gate return;
15640Sstevel@tonic-gate
15650Sstevel@tonic-gate if ((pg = scf_pg_create(h)) == NULL ||
15660Sstevel@tonic-gate (prop = scf_property_create(h)) == NULL ||
15670Sstevel@tonic-gate (val = scf_value_create(h)) == NULL ||
15680Sstevel@tonic-gate (tx = scf_transaction_create(h)) == NULL ||
15690Sstevel@tonic-gate (txent = scf_entry_create(h)) == NULL)
15700Sstevel@tonic-gate scfdie();
15710Sstevel@tonic-gate
15720Sstevel@tonic-gate if (scf_instance_get_pg(inst, pgname, pg) != SCF_SUCCESS) {
15730Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NOT_FOUND)
15740Sstevel@tonic-gate scfdie();
15750Sstevel@tonic-gate
15760Sstevel@tonic-gate if (scf_instance_add_pg(inst, pgname, pgtype, pgflags, pg) !=
15770Sstevel@tonic-gate SCF_SUCCESS) {
15780Sstevel@tonic-gate switch (scf_error()) {
15790Sstevel@tonic-gate case SCF_ERROR_EXISTS:
15800Sstevel@tonic-gate if (scf_instance_get_pg(inst, pgname, pg) !=
15810Sstevel@tonic-gate SCF_SUCCESS) {
15820Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NOT_FOUND)
15830Sstevel@tonic-gate scfdie();
15840Sstevel@tonic-gate
15850Sstevel@tonic-gate uu_warn(gettext("Repository write "
15860Sstevel@tonic-gate "contention.\n"));
15870Sstevel@tonic-gate goto out;
15880Sstevel@tonic-gate }
15890Sstevel@tonic-gate break;
15900Sstevel@tonic-gate
15910Sstevel@tonic-gate case SCF_ERROR_PERMISSION_DENIED:
15920Sstevel@tonic-gate if (!verbose)
15930Sstevel@tonic-gate uu_warn(emsg_permission_denied, fmri);
15940Sstevel@tonic-gate else
15950Sstevel@tonic-gate uu_warn(emsg_create_pg_perm_denied,
15960Sstevel@tonic-gate fmri, pgname);
15970Sstevel@tonic-gate goto out;
15980Sstevel@tonic-gate
15990Sstevel@tonic-gate default:
16000Sstevel@tonic-gate scfdie();
16010Sstevel@tonic-gate }
16020Sstevel@tonic-gate }
16030Sstevel@tonic-gate }
16040Sstevel@tonic-gate
16050Sstevel@tonic-gate do {
16060Sstevel@tonic-gate if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
16070Sstevel@tonic-gate if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
16080Sstevel@tonic-gate scfdie();
16090Sstevel@tonic-gate
16100Sstevel@tonic-gate if (!verbose)
16110Sstevel@tonic-gate uu_warn(emsg_permission_denied, fmri);
16120Sstevel@tonic-gate else
16130Sstevel@tonic-gate uu_warn(emsg_pg_perm_denied, fmri, pgname);
16140Sstevel@tonic-gate goto out;
16150Sstevel@tonic-gate }
16160Sstevel@tonic-gate
16170Sstevel@tonic-gate if (scf_transaction_property_change_type(tx, txent, propname,
16180Sstevel@tonic-gate SCF_TYPE_ASTRING) != 0) {
16190Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NOT_FOUND)
16200Sstevel@tonic-gate scfdie();
16210Sstevel@tonic-gate
16220Sstevel@tonic-gate if (scf_transaction_property_new(tx, txent, propname,
16230Sstevel@tonic-gate SCF_TYPE_ASTRING) != 0)
16240Sstevel@tonic-gate scfdie();
16250Sstevel@tonic-gate }
16260Sstevel@tonic-gate
16270Sstevel@tonic-gate if (scf_value_set_astring(val, str) != SCF_SUCCESS)
16280Sstevel@tonic-gate scfdie();
16290Sstevel@tonic-gate
16300Sstevel@tonic-gate if (scf_entry_add_value(txent, val) != SCF_SUCCESS)
16310Sstevel@tonic-gate scfdie();
16320Sstevel@tonic-gate
16330Sstevel@tonic-gate ret = scf_transaction_commit(tx);
16340Sstevel@tonic-gate if (ret == -1) {
16350Sstevel@tonic-gate if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
16360Sstevel@tonic-gate scfdie();
16370Sstevel@tonic-gate
16380Sstevel@tonic-gate if (!verbose)
16390Sstevel@tonic-gate uu_warn(emsg_permission_denied, fmri);
16400Sstevel@tonic-gate else
16410Sstevel@tonic-gate uu_warn(emsg_prop_perm_denied, fmri, pgname,
16420Sstevel@tonic-gate propname);
16430Sstevel@tonic-gate goto out;
16440Sstevel@tonic-gate }
16450Sstevel@tonic-gate
16460Sstevel@tonic-gate if (ret == 0) {
16470Sstevel@tonic-gate scf_transaction_reset(tx);
16480Sstevel@tonic-gate
16496575Stn143363 if (scf_pg_update(pg) == -1)
16500Sstevel@tonic-gate scfdie();
16510Sstevel@tonic-gate }
16520Sstevel@tonic-gate } while (ret == 0);
16530Sstevel@tonic-gate
16540Sstevel@tonic-gate out:
16550Sstevel@tonic-gate scf_transaction_destroy(tx);
16560Sstevel@tonic-gate scf_entry_destroy(txent);
16570Sstevel@tonic-gate scf_value_destroy(val);
16580Sstevel@tonic-gate scf_property_destroy(prop);
16590Sstevel@tonic-gate scf_pg_destroy(pg);
16600Sstevel@tonic-gate scf_instance_destroy(inst);
16610Sstevel@tonic-gate }
16620Sstevel@tonic-gate
16630Sstevel@tonic-gate
16640Sstevel@tonic-gate /*
16650Sstevel@tonic-gate * Flags to control enable and disable actions.
16660Sstevel@tonic-gate */
16670Sstevel@tonic-gate #define SET_ENABLED 0x1
16680Sstevel@tonic-gate #define SET_TEMPORARY 0x2
16690Sstevel@tonic-gate #define SET_RECURSIVE 0x4
16700Sstevel@tonic-gate
16710Sstevel@tonic-gate static int
set_fmri_enabled(void * data,scf_walkinfo_t * wip)16720Sstevel@tonic-gate set_fmri_enabled(void *data, scf_walkinfo_t *wip)
16730Sstevel@tonic-gate {
16740Sstevel@tonic-gate int flags = (int)data;
16750Sstevel@tonic-gate
16760Sstevel@tonic-gate assert(wip->inst != NULL);
16770Sstevel@tonic-gate assert(wip->pg == NULL);
16780Sstevel@tonic-gate
16790Sstevel@tonic-gate if (flags & SET_RECURSIVE) {
16800Sstevel@tonic-gate char *fmri_buf = malloc(max_scf_fmri_sz);
16810Sstevel@tonic-gate if (fmri_buf == NULL)
16820Sstevel@tonic-gate uu_die(emsg_nomem);
16830Sstevel@tonic-gate
16840Sstevel@tonic-gate visited = calloc(HT_BUCKETS, sizeof (*visited));
16850Sstevel@tonic-gate if (visited == NULL)
16860Sstevel@tonic-gate uu_die(emsg_nomem);
16870Sstevel@tonic-gate
16880Sstevel@tonic-gate /* scf_walk_fmri() guarantees that fmri isn't too long */
16890Sstevel@tonic-gate assert(strlen(wip->fmri) <= max_scf_fmri_sz);
16900Sstevel@tonic-gate (void) strlcpy(fmri_buf, wip->fmri, max_scf_fmri_sz);
16910Sstevel@tonic-gate
16920Sstevel@tonic-gate switch (enable_fmri_rec(fmri_buf, (flags & SET_TEMPORARY))) {
16930Sstevel@tonic-gate case E2BIG:
16940Sstevel@tonic-gate uu_warn(gettext("operation on service %s is ambiguous; "
16950Sstevel@tonic-gate "instance specification needed.\n"), fmri_buf);
16960Sstevel@tonic-gate break;
16970Sstevel@tonic-gate
16980Sstevel@tonic-gate case ELOOP:
16990Sstevel@tonic-gate uu_warn(gettext("%s: Dependency cycle detected.\n"),
17000Sstevel@tonic-gate fmri_buf);
17010Sstevel@tonic-gate }
17020Sstevel@tonic-gate
17030Sstevel@tonic-gate free(visited);
17040Sstevel@tonic-gate free(fmri_buf);
17050Sstevel@tonic-gate
17060Sstevel@tonic-gate } else {
17070Sstevel@tonic-gate set_inst_enabled(wip->fmri, wip->inst,
17080Sstevel@tonic-gate (flags & SET_TEMPORARY) != 0, (flags & SET_ENABLED) != 0);
17090Sstevel@tonic-gate }
17100Sstevel@tonic-gate
17110Sstevel@tonic-gate return (0);
17120Sstevel@tonic-gate }
17130Sstevel@tonic-gate
17140Sstevel@tonic-gate /* ARGSUSED */
17150Sstevel@tonic-gate static int
wait_fmri_enabled(void * data,scf_walkinfo_t * wip)17160Sstevel@tonic-gate wait_fmri_enabled(void *data, scf_walkinfo_t *wip)
17170Sstevel@tonic-gate {
17180Sstevel@tonic-gate scf_propertygroup_t *pg = NULL;
17190Sstevel@tonic-gate char state[MAX_SCF_STATE_STRING_SZ];
17200Sstevel@tonic-gate
17210Sstevel@tonic-gate assert(wip->inst != NULL);
17220Sstevel@tonic-gate assert(wip->pg == NULL);
17230Sstevel@tonic-gate
17240Sstevel@tonic-gate do {
17250Sstevel@tonic-gate if (pg)
17260Sstevel@tonic-gate scf_pg_destroy(pg);
17270Sstevel@tonic-gate if (inst_get_state(wip->inst, state, wip->fmri, &pg) != 0) {
17280Sstevel@tonic-gate exit_status = EXIT_SVC_FAILURE;
17290Sstevel@tonic-gate return (0);
17300Sstevel@tonic-gate }
17310Sstevel@tonic-gate
17320Sstevel@tonic-gate if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0 ||
17330Sstevel@tonic-gate strcmp(state, SCF_STATE_STRING_DEGRADED) == 0) {
17340Sstevel@tonic-gate /*
17350Sstevel@tonic-gate * We're done.
17360Sstevel@tonic-gate */
17370Sstevel@tonic-gate goto out;
17380Sstevel@tonic-gate }
17390Sstevel@tonic-gate
17400Sstevel@tonic-gate if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) {
17410Sstevel@tonic-gate /*
17420Sstevel@tonic-gate * The service is ill.
17430Sstevel@tonic-gate */
17440Sstevel@tonic-gate uu_warn(gettext("Instance \"%s\" is in maintenance"
17450Sstevel@tonic-gate " state.\n"), wip->fmri);
17460Sstevel@tonic-gate exit_status = EXIT_SVC_FAILURE;
17470Sstevel@tonic-gate goto out;
17480Sstevel@tonic-gate }
17490Sstevel@tonic-gate
17500Sstevel@tonic-gate if (!is_enabled(wip->inst)) {
17510Sstevel@tonic-gate /*
17520Sstevel@tonic-gate * Someone stepped in and disabled the service.
17530Sstevel@tonic-gate */
17540Sstevel@tonic-gate uu_warn(gettext("Instance \"%s\" has been disabled"
17550Sstevel@tonic-gate " by another entity.\n"), wip->fmri);
17560Sstevel@tonic-gate exit_status = EXIT_SVC_FAILURE;
17570Sstevel@tonic-gate goto out;
17580Sstevel@tonic-gate }
17590Sstevel@tonic-gate
17600Sstevel@tonic-gate if (!has_potential(wip->inst, B_FALSE)) {
17610Sstevel@tonic-gate /*
17620Sstevel@tonic-gate * Our dependencies aren't met. We'll never
17630Sstevel@tonic-gate * amount to anything.
17640Sstevel@tonic-gate */
17650Sstevel@tonic-gate uu_warn(gettext("Instance \"%s\" has unsatisfied"
17660Sstevel@tonic-gate " dependencies.\n"), wip->fmri);
17670Sstevel@tonic-gate /*
17680Sstevel@tonic-gate * EXIT_SVC_FAILURE takes precedence over
17690Sstevel@tonic-gate * EXIT_DEP_FAILURE
17700Sstevel@tonic-gate */
17710Sstevel@tonic-gate if (exit_status == 0)
17720Sstevel@tonic-gate exit_status = EXIT_DEP_FAILURE;
17730Sstevel@tonic-gate goto out;
17740Sstevel@tonic-gate }
17750Sstevel@tonic-gate } while (_scf_pg_wait(pg, WAIT_INTERVAL) >= 0);
17760Sstevel@tonic-gate scfdie();
17770Sstevel@tonic-gate /* NOTREACHED */
17780Sstevel@tonic-gate
17790Sstevel@tonic-gate out:
17800Sstevel@tonic-gate scf_pg_destroy(pg);
17810Sstevel@tonic-gate return (0);
17820Sstevel@tonic-gate }
17830Sstevel@tonic-gate
17840Sstevel@tonic-gate /* ARGSUSED */
17850Sstevel@tonic-gate static int
wait_fmri_disabled(void * data,scf_walkinfo_t * wip)17860Sstevel@tonic-gate wait_fmri_disabled(void *data, scf_walkinfo_t *wip)
17870Sstevel@tonic-gate {
17880Sstevel@tonic-gate scf_propertygroup_t *pg = NULL;
17890Sstevel@tonic-gate char state[MAX_SCF_STATE_STRING_SZ];
17900Sstevel@tonic-gate
17910Sstevel@tonic-gate assert(wip->inst != NULL);
17920Sstevel@tonic-gate assert(wip->pg == NULL);
17930Sstevel@tonic-gate
17940Sstevel@tonic-gate do {
17950Sstevel@tonic-gate if (pg)
17960Sstevel@tonic-gate scf_pg_destroy(pg);
17970Sstevel@tonic-gate if (inst_get_state(wip->inst, state, wip->fmri, &pg) != 0) {
17980Sstevel@tonic-gate exit_status = EXIT_SVC_FAILURE;
17990Sstevel@tonic-gate return (0);
18000Sstevel@tonic-gate }
18010Sstevel@tonic-gate
18020Sstevel@tonic-gate if (strcmp(state, SCF_STATE_STRING_DISABLED) == 0) {
18030Sstevel@tonic-gate /*
18040Sstevel@tonic-gate * We're done.
18050Sstevel@tonic-gate */
18060Sstevel@tonic-gate goto out;
18070Sstevel@tonic-gate }
18080Sstevel@tonic-gate
18090Sstevel@tonic-gate if (is_enabled(wip->inst)) {
18100Sstevel@tonic-gate /*
18110Sstevel@tonic-gate * Someone stepped in and enabled the service.
18120Sstevel@tonic-gate */
18130Sstevel@tonic-gate uu_warn(gettext("Instance \"%s\" has been enabled"
18140Sstevel@tonic-gate " by another entity.\n"), wip->fmri);
18150Sstevel@tonic-gate exit_status = EXIT_SVC_FAILURE;
18160Sstevel@tonic-gate goto out;
18170Sstevel@tonic-gate }
18180Sstevel@tonic-gate
18190Sstevel@tonic-gate if (!has_potential(wip->inst, B_TRUE)) {
18200Sstevel@tonic-gate /*
18210Sstevel@tonic-gate * Our restarter is hopeless.
18220Sstevel@tonic-gate */
18230Sstevel@tonic-gate uu_warn(gettext("Restarter for instance \"%s\" is"
18240Sstevel@tonic-gate " unavailable.\n"), wip->fmri);
18250Sstevel@tonic-gate /*
18260Sstevel@tonic-gate * EXIT_SVC_FAILURE takes precedence over
18270Sstevel@tonic-gate * EXIT_DEP_FAILURE
18280Sstevel@tonic-gate */
18290Sstevel@tonic-gate if (exit_status == 0)
18300Sstevel@tonic-gate exit_status = EXIT_DEP_FAILURE;
18310Sstevel@tonic-gate goto out;
18320Sstevel@tonic-gate }
18330Sstevel@tonic-gate
18340Sstevel@tonic-gate } while (_scf_pg_wait(pg, WAIT_INTERVAL) >= 0);
18350Sstevel@tonic-gate scfdie();
18360Sstevel@tonic-gate /* NOTREACHED */
18370Sstevel@tonic-gate
18380Sstevel@tonic-gate out:
18390Sstevel@tonic-gate scf_pg_destroy(pg);
18400Sstevel@tonic-gate return (0);
18410Sstevel@tonic-gate }
18420Sstevel@tonic-gate
18430Sstevel@tonic-gate /* ARGSUSED */
18440Sstevel@tonic-gate static int
clear_instance(void * data,scf_walkinfo_t * wip)18450Sstevel@tonic-gate clear_instance(void *data, scf_walkinfo_t *wip)
18460Sstevel@tonic-gate {
18470Sstevel@tonic-gate char state[MAX_SCF_STATE_STRING_SZ];
18480Sstevel@tonic-gate
18490Sstevel@tonic-gate assert(wip->inst != NULL);
18500Sstevel@tonic-gate assert(wip->pg == NULL);
18510Sstevel@tonic-gate
18520Sstevel@tonic-gate if (inst_get_state(wip->inst, state, wip->fmri, NULL) != 0)
18530Sstevel@tonic-gate return (0);
18540Sstevel@tonic-gate
18550Sstevel@tonic-gate if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) {
18560Sstevel@tonic-gate set_inst_action(wip->fmri, wip->inst, SCF_PROPERTY_MAINT_OFF);
18570Sstevel@tonic-gate } else if (strcmp(state, SCF_STATE_STRING_DEGRADED) ==
18580Sstevel@tonic-gate 0) {
18590Sstevel@tonic-gate set_inst_action(wip->fmri, wip->inst, SCF_PROPERTY_RESTORE);
18600Sstevel@tonic-gate } else {
18610Sstevel@tonic-gate uu_warn(gettext("Instance \"%s\" is not in a "
18620Sstevel@tonic-gate "maintenance or degraded state.\n"), wip->fmri);
18630Sstevel@tonic-gate
18640Sstevel@tonic-gate exit_status = 1;
18650Sstevel@tonic-gate }
18660Sstevel@tonic-gate
18670Sstevel@tonic-gate return (0);
18680Sstevel@tonic-gate }
18690Sstevel@tonic-gate
18700Sstevel@tonic-gate static int
set_fmri_action(void * action,scf_walkinfo_t * wip)18710Sstevel@tonic-gate set_fmri_action(void *action, scf_walkinfo_t *wip)
18720Sstevel@tonic-gate {
18730Sstevel@tonic-gate assert(wip->inst != NULL && wip->pg == NULL);
18740Sstevel@tonic-gate
18750Sstevel@tonic-gate set_inst_action(wip->fmri, wip->inst, action);
18760Sstevel@tonic-gate
18770Sstevel@tonic-gate return (0);
18780Sstevel@tonic-gate }
18790Sstevel@tonic-gate
18800Sstevel@tonic-gate /*
18810Sstevel@tonic-gate * Flags to control 'mark' action.
18820Sstevel@tonic-gate */
18830Sstevel@tonic-gate #define MARK_IMMEDIATE 0x1
18840Sstevel@tonic-gate #define MARK_TEMPORARY 0x2
18850Sstevel@tonic-gate
18860Sstevel@tonic-gate static int
force_degraded(void * data,scf_walkinfo_t * wip)18870Sstevel@tonic-gate force_degraded(void *data, scf_walkinfo_t *wip)
18880Sstevel@tonic-gate {
18890Sstevel@tonic-gate int flags = (int)data;
18900Sstevel@tonic-gate char state[MAX_SCF_STATE_STRING_SZ];
18910Sstevel@tonic-gate
18920Sstevel@tonic-gate if (inst_get_state(wip->inst, state, wip->fmri, NULL) != 0) {
18930Sstevel@tonic-gate exit_status = 1;
18940Sstevel@tonic-gate return (0);
18950Sstevel@tonic-gate }
18960Sstevel@tonic-gate
18970Sstevel@tonic-gate if (strcmp(state, SCF_STATE_STRING_ONLINE) != 0) {
18980Sstevel@tonic-gate uu_warn(gettext("Instance \"%s\" is not online.\n"), wip->fmri);
18990Sstevel@tonic-gate exit_status = 1;
19000Sstevel@tonic-gate return (0);
19010Sstevel@tonic-gate }
19020Sstevel@tonic-gate
19030Sstevel@tonic-gate set_inst_action(wip->fmri, wip->inst, (flags & MARK_IMMEDIATE) ?
19040Sstevel@tonic-gate SCF_PROPERTY_DEGRADE_IMMEDIATE : SCF_PROPERTY_DEGRADED);
19050Sstevel@tonic-gate
19060Sstevel@tonic-gate return (0);
19070Sstevel@tonic-gate }
19080Sstevel@tonic-gate
19090Sstevel@tonic-gate static int
force_maintenance(void * data,scf_walkinfo_t * wip)19100Sstevel@tonic-gate force_maintenance(void *data, scf_walkinfo_t *wip)
19110Sstevel@tonic-gate {
19120Sstevel@tonic-gate int flags = (int)data;
19130Sstevel@tonic-gate const char *prop;
19140Sstevel@tonic-gate
19150Sstevel@tonic-gate if (flags & MARK_IMMEDIATE) {
19160Sstevel@tonic-gate prop = (flags & MARK_TEMPORARY) ?
19170Sstevel@tonic-gate SCF_PROPERTY_MAINT_ON_IMMTEMP :
19180Sstevel@tonic-gate SCF_PROPERTY_MAINT_ON_IMMEDIATE;
19190Sstevel@tonic-gate } else {
19200Sstevel@tonic-gate prop = (flags & MARK_TEMPORARY) ?
19210Sstevel@tonic-gate SCF_PROPERTY_MAINT_ON_TEMPORARY :
19220Sstevel@tonic-gate SCF_PROPERTY_MAINT_ON;
19230Sstevel@tonic-gate }
19240Sstevel@tonic-gate
19250Sstevel@tonic-gate set_inst_action(wip->fmri, wip->inst, prop);
19260Sstevel@tonic-gate
19270Sstevel@tonic-gate return (0);
19280Sstevel@tonic-gate }
19290Sstevel@tonic-gate
19300Sstevel@tonic-gate static void
set_milestone(const char * fmri,boolean_t temporary)19310Sstevel@tonic-gate set_milestone(const char *fmri, boolean_t temporary)
19320Sstevel@tonic-gate {
19330Sstevel@tonic-gate scf_instance_t *inst;
19340Sstevel@tonic-gate scf_propertygroup_t *pg;
19350Sstevel@tonic-gate int r;
19360Sstevel@tonic-gate
19370Sstevel@tonic-gate if (temporary) {
19380Sstevel@tonic-gate set_astring_prop(SCF_SERVICE_STARTD, SCF_PG_OPTIONS_OVR,
19390Sstevel@tonic-gate SCF_PG_OPTIONS_OVR_TYPE, SCF_PG_OPTIONS_OVR_FLAGS,
19400Sstevel@tonic-gate SCF_PROPERTY_MILESTONE, fmri);
19410Sstevel@tonic-gate return;
19420Sstevel@tonic-gate }
19430Sstevel@tonic-gate
19440Sstevel@tonic-gate if ((inst = scf_instance_create(h)) == NULL ||
19450Sstevel@tonic-gate (pg = scf_pg_create(h)) == NULL)
19460Sstevel@tonic-gate scfdie();
19470Sstevel@tonic-gate
19480Sstevel@tonic-gate if (get_inst(SCF_SERVICE_STARTD, inst) != 0) {
19490Sstevel@tonic-gate scf_instance_destroy(inst);
19500Sstevel@tonic-gate return;
19510Sstevel@tonic-gate }
19520Sstevel@tonic-gate
19530Sstevel@tonic-gate /*
19540Sstevel@tonic-gate * Set the persistent milestone before deleting the override so we don't
19550Sstevel@tonic-gate * glitch.
19560Sstevel@tonic-gate */
19570Sstevel@tonic-gate set_astring_prop(SCF_SERVICE_STARTD, SCF_PG_OPTIONS,
19580Sstevel@tonic-gate SCF_PG_OPTIONS_TYPE, SCF_PG_OPTIONS_FLAGS, SCF_PROPERTY_MILESTONE,
19590Sstevel@tonic-gate fmri);
19600Sstevel@tonic-gate
19618823STruong.Q.Nguyen@Sun.COM r = scf_instance_delete_prop(inst, SCF_PG_OPTIONS_OVR,
19628823STruong.Q.Nguyen@Sun.COM SCF_PROPERTY_MILESTONE);
19638823STruong.Q.Nguyen@Sun.COM switch (r) {
19648823STruong.Q.Nguyen@Sun.COM case 0:
19658823STruong.Q.Nguyen@Sun.COM break;
19668823STruong.Q.Nguyen@Sun.COM
19678823STruong.Q.Nguyen@Sun.COM case ECANCELED:
19688823STruong.Q.Nguyen@Sun.COM uu_warn(emsg_no_service, fmri);
19698823STruong.Q.Nguyen@Sun.COM exit_status = 1;
19708823STruong.Q.Nguyen@Sun.COM goto out;
19718823STruong.Q.Nguyen@Sun.COM
19728823STruong.Q.Nguyen@Sun.COM case EPERM:
19738823STruong.Q.Nguyen@Sun.COM uu_warn(gettext("Could not delete %s/%s property of "
19748823STruong.Q.Nguyen@Sun.COM "%s: permission denied.\n"), SCF_PG_OPTIONS_OVR,
19758823STruong.Q.Nguyen@Sun.COM SCF_PROPERTY_MILESTONE, SCF_SERVICE_STARTD);
19768823STruong.Q.Nguyen@Sun.COM exit_status = 1;
19778823STruong.Q.Nguyen@Sun.COM goto out;
19788823STruong.Q.Nguyen@Sun.COM
19798823STruong.Q.Nguyen@Sun.COM case EACCES:
19808823STruong.Q.Nguyen@Sun.COM uu_warn(gettext("Could not delete %s/%s property of "
19818823STruong.Q.Nguyen@Sun.COM "%s: access denied.\n"), SCF_PG_OPTIONS_OVR,
19828823STruong.Q.Nguyen@Sun.COM SCF_PROPERTY_MILESTONE, SCF_SERVICE_STARTD);
19838823STruong.Q.Nguyen@Sun.COM exit_status = 1;
19848823STruong.Q.Nguyen@Sun.COM goto out;
19858823STruong.Q.Nguyen@Sun.COM
19868823STruong.Q.Nguyen@Sun.COM case EROFS:
19878823STruong.Q.Nguyen@Sun.COM uu_warn(gettext("Could not delete %s/%s property of "
19888823STruong.Q.Nguyen@Sun.COM "%s: backend read-only.\n"), SCF_PG_OPTIONS_OVR,
19898823STruong.Q.Nguyen@Sun.COM SCF_PROPERTY_MILESTONE, SCF_SERVICE_STARTD);
19908823STruong.Q.Nguyen@Sun.COM exit_status = 1;
19918823STruong.Q.Nguyen@Sun.COM goto out;
19928823STruong.Q.Nguyen@Sun.COM
19938823STruong.Q.Nguyen@Sun.COM default:
19948823STruong.Q.Nguyen@Sun.COM bad_error("scf_instance_delete_prop", r);
19950Sstevel@tonic-gate }
19960Sstevel@tonic-gate
19970Sstevel@tonic-gate out:
19980Sstevel@tonic-gate scf_pg_destroy(pg);
19990Sstevel@tonic-gate scf_instance_destroy(inst);
20000Sstevel@tonic-gate }
20010Sstevel@tonic-gate
20020Sstevel@tonic-gate static char const *milestones[] = {
20030Sstevel@tonic-gate SCF_MILESTONE_SINGLE_USER,
20040Sstevel@tonic-gate SCF_MILESTONE_MULTI_USER,
20050Sstevel@tonic-gate SCF_MILESTONE_MULTI_USER_SERVER,
20060Sstevel@tonic-gate NULL
20070Sstevel@tonic-gate };
20080Sstevel@tonic-gate
20090Sstevel@tonic-gate static void
usage_milestone(void)2010471Shg115875 usage_milestone(void)
20110Sstevel@tonic-gate {
20120Sstevel@tonic-gate const char **ms;
20130Sstevel@tonic-gate
20140Sstevel@tonic-gate (void) fprintf(stderr, gettext(
20150Sstevel@tonic-gate "Usage: svcadm milestone [-d] <milestone>\n\n"
20160Sstevel@tonic-gate "\t-d\tmake the specified milestone the default for system boot\n\n"
20170Sstevel@tonic-gate "\tMilestones can be specified using an FMRI or abbreviation.\n"
20180Sstevel@tonic-gate "\tThe major milestones are as follows:\n\n"
20190Sstevel@tonic-gate "\tall\n"
20200Sstevel@tonic-gate "\tnone\n"));
20210Sstevel@tonic-gate
20220Sstevel@tonic-gate for (ms = milestones; *ms != NULL; ms++)
20230Sstevel@tonic-gate (void) fprintf(stderr, "\t%s\n", *ms);
20240Sstevel@tonic-gate
20250Sstevel@tonic-gate exit(UU_EXIT_USAGE);
20260Sstevel@tonic-gate }
20270Sstevel@tonic-gate
20280Sstevel@tonic-gate static const char *
validate_milestone(const char * milestone)20290Sstevel@tonic-gate validate_milestone(const char *milestone)
20300Sstevel@tonic-gate {
20310Sstevel@tonic-gate const char **ms;
20320Sstevel@tonic-gate const char *tmp;
20330Sstevel@tonic-gate size_t len;
20340Sstevel@tonic-gate
20350Sstevel@tonic-gate if (strcmp(milestone, "all") == 0)
20360Sstevel@tonic-gate return (milestone);
20370Sstevel@tonic-gate
20380Sstevel@tonic-gate if (strcmp(milestone, "none") == 0)
20390Sstevel@tonic-gate return (milestone);
20400Sstevel@tonic-gate
20410Sstevel@tonic-gate /*
20420Sstevel@tonic-gate * Determine if this is a full or partial milestone
20430Sstevel@tonic-gate */
20440Sstevel@tonic-gate for (ms = milestones; *ms != NULL; ms++) {
20450Sstevel@tonic-gate if ((tmp = strstr(*ms, milestone)) != NULL) {
20460Sstevel@tonic-gate len = strlen(milestone);
20470Sstevel@tonic-gate
20480Sstevel@tonic-gate /*
20490Sstevel@tonic-gate * The beginning of the string must align with the start
20500Sstevel@tonic-gate * of a milestone fmri, or on the boundary between
20510Sstevel@tonic-gate * elements. The end of the string must align with the
20520Sstevel@tonic-gate * end of the milestone, or at the instance boundary.
20530Sstevel@tonic-gate */
20540Sstevel@tonic-gate if ((tmp == *ms || tmp[-1] == '/') &&
20550Sstevel@tonic-gate (tmp[len] == '\0' || tmp[len] == ':'))
20560Sstevel@tonic-gate return (*ms);
20570Sstevel@tonic-gate }
20580Sstevel@tonic-gate }
20590Sstevel@tonic-gate
20600Sstevel@tonic-gate (void) fprintf(stderr,
20610Sstevel@tonic-gate gettext("\"%s\" is not a valid major milestone.\n"), milestone);
20620Sstevel@tonic-gate
20630Sstevel@tonic-gate usage_milestone();
20640Sstevel@tonic-gate /* NOTREACHED */
20650Sstevel@tonic-gate }
20660Sstevel@tonic-gate
20670Sstevel@tonic-gate /*ARGSUSED*/
20680Sstevel@tonic-gate static void
quiet(const char * fmt,...)20690Sstevel@tonic-gate quiet(const char *fmt, ...)
20700Sstevel@tonic-gate {
20710Sstevel@tonic-gate /* Do nothing */
20720Sstevel@tonic-gate }
20730Sstevel@tonic-gate
20740Sstevel@tonic-gate int
main(int argc,char * argv[])20750Sstevel@tonic-gate main(int argc, char *argv[])
20760Sstevel@tonic-gate {
20770Sstevel@tonic-gate int o;
20780Sstevel@tonic-gate int err;
20796035Sstevep int sw_back;
20800Sstevel@tonic-gate
20810Sstevel@tonic-gate (void) setlocale(LC_ALL, "");
20820Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN);
20830Sstevel@tonic-gate
20840Sstevel@tonic-gate (void) uu_setpname(argv[0]);
20850Sstevel@tonic-gate
20860Sstevel@tonic-gate if (argc < 2)
20870Sstevel@tonic-gate usage();
20880Sstevel@tonic-gate
20890Sstevel@tonic-gate max_scf_fmri_sz = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
20900Sstevel@tonic-gate if (max_scf_fmri_sz < 0)
20910Sstevel@tonic-gate scfdie();
20920Sstevel@tonic-gate ++max_scf_fmri_sz;
20930Sstevel@tonic-gate
20940Sstevel@tonic-gate scratch_fmri = malloc(max_scf_fmri_sz);
20950Sstevel@tonic-gate if (scratch_fmri == NULL)
20960Sstevel@tonic-gate uu_die(emsg_nomem);
20970Sstevel@tonic-gate
20980Sstevel@tonic-gate h = scf_handle_create(SCF_VERSION);
20990Sstevel@tonic-gate if (h == NULL)
21000Sstevel@tonic-gate scfdie();
21010Sstevel@tonic-gate
21020Sstevel@tonic-gate if (scf_handle_bind(h) == -1)
21030Sstevel@tonic-gate uu_die(gettext("Couldn't bind to svc.configd.\n"));
21040Sstevel@tonic-gate
21050Sstevel@tonic-gate while ((o = getopt(argc, argv, "v")) != -1) {
21060Sstevel@tonic-gate if (o == 'v')
21070Sstevel@tonic-gate verbose = 1;
21080Sstevel@tonic-gate else
21090Sstevel@tonic-gate usage();
21100Sstevel@tonic-gate }
21110Sstevel@tonic-gate
21120Sstevel@tonic-gate if (optind >= argc)
21130Sstevel@tonic-gate usage();
21140Sstevel@tonic-gate
21150Sstevel@tonic-gate emsg_permission_denied = gettext("%s: Permission denied.\n");
21160Sstevel@tonic-gate emsg_nomem = gettext("Out of memory.\n");
21170Sstevel@tonic-gate emsg_create_pg_perm_denied = gettext("%s: Couldn't create \"%s\" "
21180Sstevel@tonic-gate "property group (permission denied).\n");
21190Sstevel@tonic-gate emsg_pg_perm_denied = gettext("%s: Couldn't modify \"%s\" property "
21200Sstevel@tonic-gate "group (permission denied).\n");
21210Sstevel@tonic-gate emsg_prop_perm_denied = gettext("%s: Couldn't modify \"%s/%s\" "
21220Sstevel@tonic-gate "property (permission denied).\n");
21230Sstevel@tonic-gate emsg_no_service = gettext("No such service \"%s\".\n");
21240Sstevel@tonic-gate
21250Sstevel@tonic-gate if (strcmp(argv[optind], "enable") == 0) {
21260Sstevel@tonic-gate int flags = SET_ENABLED;
21270Sstevel@tonic-gate int wait = 0;
21280Sstevel@tonic-gate int error = 0;
21290Sstevel@tonic-gate
21300Sstevel@tonic-gate ++optind;
21310Sstevel@tonic-gate
21320Sstevel@tonic-gate while ((o = getopt(argc, argv, "rst")) != -1) {
21330Sstevel@tonic-gate if (o == 'r')
21340Sstevel@tonic-gate flags |= SET_RECURSIVE;
21350Sstevel@tonic-gate else if (o == 't')
21360Sstevel@tonic-gate flags |= SET_TEMPORARY;
21370Sstevel@tonic-gate else if (o == 's')
21380Sstevel@tonic-gate wait = 1;
21390Sstevel@tonic-gate else if (o == '?')
21400Sstevel@tonic-gate usage();
21410Sstevel@tonic-gate else {
21420Sstevel@tonic-gate assert(0);
21430Sstevel@tonic-gate abort();
21440Sstevel@tonic-gate }
21450Sstevel@tonic-gate }
21460Sstevel@tonic-gate argc -= optind;
21470Sstevel@tonic-gate argv += optind;
21480Sstevel@tonic-gate
21490Sstevel@tonic-gate if (argc <= 0)
21500Sstevel@tonic-gate usage();
21510Sstevel@tonic-gate
21520Sstevel@tonic-gate /*
21530Sstevel@tonic-gate * We want to continue with -s processing if we had
21540Sstevel@tonic-gate * invalid options, but not if an enable failed. We
21550Sstevel@tonic-gate * squelch output the second time we walk fmris; we saw
21560Sstevel@tonic-gate * the errors the first time.
21570Sstevel@tonic-gate */
21580Sstevel@tonic-gate if ((err = scf_walk_fmri(h, argc, argv, 0, set_fmri_enabled,
21590Sstevel@tonic-gate (void *)flags, &error, uu_warn)) != 0) {
21600Sstevel@tonic-gate
21610Sstevel@tonic-gate uu_warn(gettext("failed to iterate over "
21620Sstevel@tonic-gate "instances: %s\n"), scf_strerror(err));
21630Sstevel@tonic-gate exit_status = UU_EXIT_FATAL;
21640Sstevel@tonic-gate
21650Sstevel@tonic-gate } else if (wait && exit_status == 0 &&
21660Sstevel@tonic-gate (err = scf_walk_fmri(h, argc, argv, 0, wait_fmri_enabled,
21670Sstevel@tonic-gate (void *)flags, &error, quiet)) != 0) {
21680Sstevel@tonic-gate
21690Sstevel@tonic-gate uu_warn(gettext("failed to iterate over "
21700Sstevel@tonic-gate "instances: %s\n"), scf_strerror(err));
21710Sstevel@tonic-gate exit_status = UU_EXIT_FATAL;
21720Sstevel@tonic-gate }
21730Sstevel@tonic-gate
21740Sstevel@tonic-gate if (error > 0)
21750Sstevel@tonic-gate exit_status = error;
21760Sstevel@tonic-gate
21770Sstevel@tonic-gate } else if (strcmp(argv[optind], "disable") == 0) {
21780Sstevel@tonic-gate int flags = 0;
21790Sstevel@tonic-gate int wait = 0;
21800Sstevel@tonic-gate int error = 0;
21810Sstevel@tonic-gate
21820Sstevel@tonic-gate ++optind;
21830Sstevel@tonic-gate
21840Sstevel@tonic-gate while ((o = getopt(argc, argv, "st")) != -1) {
21850Sstevel@tonic-gate if (o == 't')
21860Sstevel@tonic-gate flags |= SET_TEMPORARY;
21870Sstevel@tonic-gate else if (o == 's')
21880Sstevel@tonic-gate wait = 1;
21890Sstevel@tonic-gate else if (o == '?')
21900Sstevel@tonic-gate usage();
21910Sstevel@tonic-gate else {
21920Sstevel@tonic-gate assert(0);
21930Sstevel@tonic-gate abort();
21940Sstevel@tonic-gate }
21950Sstevel@tonic-gate }
21960Sstevel@tonic-gate argc -= optind;
21970Sstevel@tonic-gate argv += optind;
21980Sstevel@tonic-gate
21990Sstevel@tonic-gate if (argc <= 0)
22000Sstevel@tonic-gate usage();
22010Sstevel@tonic-gate
22020Sstevel@tonic-gate /*
22030Sstevel@tonic-gate * We want to continue with -s processing if we had
22040Sstevel@tonic-gate * invalid options, but not if a disable failed. We
22050Sstevel@tonic-gate * squelch output the second time we walk fmris; we saw
22060Sstevel@tonic-gate * the errors the first time.
22070Sstevel@tonic-gate */
22080Sstevel@tonic-gate if ((err = scf_walk_fmri(h, argc, argv, 0, set_fmri_enabled,
22090Sstevel@tonic-gate (void *)flags, &exit_status, uu_warn)) != 0) {
22100Sstevel@tonic-gate
22110Sstevel@tonic-gate uu_warn(gettext("failed to iterate over "
22120Sstevel@tonic-gate "instances: %s\n"), scf_strerror(err));
22130Sstevel@tonic-gate exit_status = UU_EXIT_FATAL;
22140Sstevel@tonic-gate
22150Sstevel@tonic-gate } else if (wait && exit_status == 0 &&
22160Sstevel@tonic-gate (err = scf_walk_fmri(h, argc, argv, 0, wait_fmri_disabled,
22170Sstevel@tonic-gate (void *)flags, &error, quiet)) != 0) {
22180Sstevel@tonic-gate
22190Sstevel@tonic-gate uu_warn(gettext("failed to iterate over "
22200Sstevel@tonic-gate "instances: %s\n"), scf_strerror(err));
22210Sstevel@tonic-gate exit_status = UU_EXIT_FATAL;
22220Sstevel@tonic-gate }
22230Sstevel@tonic-gate
22240Sstevel@tonic-gate if (error > 0)
22250Sstevel@tonic-gate exit_status = error;
22260Sstevel@tonic-gate
22270Sstevel@tonic-gate } else if (strcmp(argv[optind], "restart") == 0) {
22280Sstevel@tonic-gate ++optind;
22290Sstevel@tonic-gate
22300Sstevel@tonic-gate if (optind >= argc)
22310Sstevel@tonic-gate usage();
22320Sstevel@tonic-gate
22330Sstevel@tonic-gate if ((err = scf_walk_fmri(h, argc - optind, argv + optind, 0,
22340Sstevel@tonic-gate set_fmri_action, (void *)SCF_PROPERTY_RESTART,
22350Sstevel@tonic-gate &exit_status, uu_warn)) != 0) {
22360Sstevel@tonic-gate uu_warn(gettext("failed to iterate over "
22370Sstevel@tonic-gate "instances: %s\n"), scf_strerror(err));
22380Sstevel@tonic-gate exit_status = UU_EXIT_FATAL;
22390Sstevel@tonic-gate }
22400Sstevel@tonic-gate
22410Sstevel@tonic-gate } else if (strcmp(argv[optind], "refresh") == 0) {
22420Sstevel@tonic-gate ++optind;
22430Sstevel@tonic-gate
22440Sstevel@tonic-gate if (optind >= argc)
22450Sstevel@tonic-gate usage();
22460Sstevel@tonic-gate
22470Sstevel@tonic-gate if ((err = scf_walk_fmri(h, argc - optind, argv + optind, 0,
22480Sstevel@tonic-gate set_fmri_action, (void *)SCF_PROPERTY_REFRESH,
22490Sstevel@tonic-gate &exit_status, uu_warn)) != 0) {
22500Sstevel@tonic-gate uu_warn(gettext("failed to iterate over "
22510Sstevel@tonic-gate "instances: %s\n"), scf_strerror(scf_error()));
22520Sstevel@tonic-gate exit_status = UU_EXIT_FATAL;
22530Sstevel@tonic-gate }
22540Sstevel@tonic-gate
22550Sstevel@tonic-gate } else if (strcmp(argv[optind], "mark") == 0) {
22560Sstevel@tonic-gate int flags = 0;
22570Sstevel@tonic-gate scf_walk_callback callback;
22580Sstevel@tonic-gate
22590Sstevel@tonic-gate ++optind;
22600Sstevel@tonic-gate
22610Sstevel@tonic-gate while ((o = getopt(argc, argv, "It")) != -1) {
22620Sstevel@tonic-gate if (o == 'I')
22630Sstevel@tonic-gate flags |= MARK_IMMEDIATE;
22640Sstevel@tonic-gate else if (o == 't')
22650Sstevel@tonic-gate flags |= MARK_TEMPORARY;
22660Sstevel@tonic-gate else if (o == '?')
22670Sstevel@tonic-gate usage();
22680Sstevel@tonic-gate else {
22690Sstevel@tonic-gate assert(0);
22700Sstevel@tonic-gate abort();
22710Sstevel@tonic-gate }
22720Sstevel@tonic-gate }
22730Sstevel@tonic-gate
22740Sstevel@tonic-gate if (argc - optind < 2)
22750Sstevel@tonic-gate usage();
22760Sstevel@tonic-gate
22770Sstevel@tonic-gate if (strcmp(argv[optind], "degraded") == 0) {
22780Sstevel@tonic-gate if (flags & MARK_TEMPORARY)
22790Sstevel@tonic-gate uu_xdie(UU_EXIT_USAGE, gettext("-t may not be "
22800Sstevel@tonic-gate "used with degraded.\n"));
22810Sstevel@tonic-gate callback = force_degraded;
22820Sstevel@tonic-gate
22830Sstevel@tonic-gate } else if (strcmp(argv[optind], "maintenance") == 0) {
22840Sstevel@tonic-gate callback = force_maintenance;
22850Sstevel@tonic-gate } else {
22860Sstevel@tonic-gate usage();
22870Sstevel@tonic-gate }
22880Sstevel@tonic-gate
22890Sstevel@tonic-gate if ((err = scf_walk_fmri(h, argc - optind - 1,
22900Sstevel@tonic-gate argv + optind + 1, 0, callback, NULL, &exit_status,
22910Sstevel@tonic-gate uu_warn)) != 0) {
22920Sstevel@tonic-gate uu_warn(gettext("failed to iterate over "
22930Sstevel@tonic-gate "instances: %s\n"),
22940Sstevel@tonic-gate scf_strerror(err));
22950Sstevel@tonic-gate exit_status = UU_EXIT_FATAL;
22960Sstevel@tonic-gate }
22970Sstevel@tonic-gate
22980Sstevel@tonic-gate } else if (strcmp(argv[optind], "clear") == 0) {
22990Sstevel@tonic-gate ++optind;
23000Sstevel@tonic-gate
23010Sstevel@tonic-gate if (optind >= argc)
23020Sstevel@tonic-gate usage();
23030Sstevel@tonic-gate
23040Sstevel@tonic-gate if ((err = scf_walk_fmri(h, argc - optind, argv + optind, 0,
23050Sstevel@tonic-gate clear_instance, NULL, &exit_status, uu_warn)) != 0) {
23060Sstevel@tonic-gate uu_warn(gettext("failed to iterate over "
23070Sstevel@tonic-gate "instances: %s\n"), scf_strerror(err));
23080Sstevel@tonic-gate exit_status = UU_EXIT_FATAL;
23090Sstevel@tonic-gate }
23100Sstevel@tonic-gate
23110Sstevel@tonic-gate } else if (strcmp(argv[optind], "milestone") == 0) {
23120Sstevel@tonic-gate boolean_t temporary = B_TRUE;
23130Sstevel@tonic-gate const char *milestone;
23140Sstevel@tonic-gate
23150Sstevel@tonic-gate ++optind;
23160Sstevel@tonic-gate
23170Sstevel@tonic-gate while ((o = getopt(argc, argv, "d")) != -1) {
23180Sstevel@tonic-gate if (o == 'd')
23190Sstevel@tonic-gate temporary = B_FALSE;
23200Sstevel@tonic-gate else if (o == '?')
23210Sstevel@tonic-gate usage_milestone();
23220Sstevel@tonic-gate else {
23230Sstevel@tonic-gate assert(0);
23240Sstevel@tonic-gate abort();
23250Sstevel@tonic-gate }
23260Sstevel@tonic-gate }
23270Sstevel@tonic-gate
23280Sstevel@tonic-gate if (optind >= argc)
23290Sstevel@tonic-gate usage_milestone();
23300Sstevel@tonic-gate
23310Sstevel@tonic-gate milestone = validate_milestone(argv[optind]);
23320Sstevel@tonic-gate
23330Sstevel@tonic-gate set_milestone(milestone, temporary);
23340Sstevel@tonic-gate } else if (strcmp(argv[optind], "_smf_backup") == 0) {
23350Sstevel@tonic-gate const char *reason = NULL;
23360Sstevel@tonic-gate
23370Sstevel@tonic-gate ++optind;
23380Sstevel@tonic-gate
23390Sstevel@tonic-gate if (optind != argc - 1)
23400Sstevel@tonic-gate usage();
23410Sstevel@tonic-gate
23420Sstevel@tonic-gate if ((err = _scf_request_backup(h, argv[optind])) !=
23430Sstevel@tonic-gate SCF_SUCCESS) {
23440Sstevel@tonic-gate switch (scf_error()) {
23450Sstevel@tonic-gate case SCF_ERROR_NOT_BOUND:
23460Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN:
23470Sstevel@tonic-gate case SCF_ERROR_BACKEND_READONLY:
23480Sstevel@tonic-gate scfdie();
23490Sstevel@tonic-gate break;
23500Sstevel@tonic-gate
23510Sstevel@tonic-gate case SCF_ERROR_PERMISSION_DENIED:
23520Sstevel@tonic-gate case SCF_ERROR_INVALID_ARGUMENT:
23530Sstevel@tonic-gate reason = scf_strerror(scf_error());
23540Sstevel@tonic-gate break;
23550Sstevel@tonic-gate
23560Sstevel@tonic-gate case SCF_ERROR_INTERNAL:
23570Sstevel@tonic-gate reason =
23580Sstevel@tonic-gate "unknown error (see console for details)";
23590Sstevel@tonic-gate break;
23600Sstevel@tonic-gate }
23616035Sstevep
23620Sstevel@tonic-gate uu_warn("failed to backup repository: %s\n", reason);
23630Sstevel@tonic-gate exit_status = UU_EXIT_FATAL;
23640Sstevel@tonic-gate }
23656035Sstevep } else if (strcmp(argv[optind], "_smf_repository_switch") == 0) {
23666035Sstevep const char *reason = NULL;
23676035Sstevep
23686035Sstevep ++optind;
23696035Sstevep
23706035Sstevep /*
23716035Sstevep * Check argument and setup scf_switch structure
23726035Sstevep */
23736035Sstevep if (optind != argc - 1)
23746035Sstevep exit(1);
23756035Sstevep
23766035Sstevep if (strcmp(argv[optind], "fast") == 0) {
23776035Sstevep sw_back = 0;
23786035Sstevep } else if (strcmp(argv[optind], "perm") == 0) {
23796035Sstevep sw_back = 1;
23806035Sstevep } else {
23816035Sstevep exit(UU_EXIT_USAGE);
23826035Sstevep }
23836035Sstevep
23846035Sstevep /*
23856035Sstevep * Call into switch primitive
23866035Sstevep */
23876035Sstevep if ((err = _scf_repository_switch(h, sw_back)) !=
23886035Sstevep SCF_SUCCESS) {
23896035Sstevep /*
23906035Sstevep * Retrieve per thread SCF error code
23916035Sstevep */
23926035Sstevep switch (scf_error()) {
23936035Sstevep case SCF_ERROR_NOT_BOUND:
23946035Sstevep abort();
23956035Sstevep /* NOTREACHED */
23966035Sstevep
23976035Sstevep case SCF_ERROR_CONNECTION_BROKEN:
23986035Sstevep case SCF_ERROR_BACKEND_READONLY:
23996035Sstevep scfdie();
24006035Sstevep /* NOTREACHED */
24016035Sstevep
24026035Sstevep case SCF_ERROR_PERMISSION_DENIED:
24036035Sstevep case SCF_ERROR_INVALID_ARGUMENT:
24046035Sstevep reason = scf_strerror(scf_error());
24056035Sstevep break;
24066035Sstevep
24076035Sstevep case SCF_ERROR_INTERNAL:
24086035Sstevep reason = "File operation error: (see console)";
24096035Sstevep break;
24106035Sstevep
24116035Sstevep default:
24126035Sstevep abort();
24136035Sstevep /* NOTREACHED */
24146035Sstevep }
24156035Sstevep
24166035Sstevep uu_warn("failed to switch repository: %s\n", reason);
24176035Sstevep exit_status = UU_EXIT_FATAL;
24186035Sstevep }
24190Sstevel@tonic-gate } else {
24200Sstevel@tonic-gate usage();
24210Sstevel@tonic-gate }
24220Sstevel@tonic-gate
24230Sstevel@tonic-gate if (scf_handle_unbind(h) == -1)
24240Sstevel@tonic-gate scfdie();
24250Sstevel@tonic-gate scf_handle_destroy(h);
24260Sstevel@tonic-gate
24270Sstevel@tonic-gate return (exit_status);
24280Sstevel@tonic-gate }
2429