svcadm.c revision e8f5b3f5917b8c9ec939f5a505922bab6e7b6f3f
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* svcadm - request adminstrative actions for service instances
*/
#include <locale.h>
#include <libintl.h>
#include <libscf.h>
#include <libscf_priv.h>
#include <libcontract.h>
#include <libcontract_priv.h>
#include <libuutil.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <procfs.h>
#include <assert.h>
#include <errno.h>
#ifndef TEXT_DOMAIN
#define TEXT_DOMAIN "SUNW_OST_OSCMD"
#endif /* TEXT_DOMAIN */
/* Must be a power of two */
#define HT_BUCKETS 64
/*
* Exit codes for enable and disable -s.
*/
#define EXIT_SVC_FAILURE 3
#define EXIT_DEP_FAILURE 4
/*
* How long we will wait (in seconds) for a service to change state
* before re-checking its dependencies.
*/
#define WAIT_INTERVAL 3
#ifndef NDEBUG
uu_warn("%s:%d: %s() failed with unexpected error %d.\n", \
abort(); \
}
#else
#endif
struct ht_elt {
char str[1];
};
scf_handle_t *h;
static const char *emsg_permission_denied;
static const char *emsg_nomem;
static const char *emsg_create_pg_perm_denied;
static const char *emsg_pg_perm_denied;
static const char *emsg_prop_perm_denied;
static const char *emsg_no_service;
static int exit_status = 0;
static int verbose = 0;
static char *scratch_fmri;
static void usage_milestone(void) __NORETURN;
static void set_astring_prop(const char *, const char *, const char *,
uint32_t, const char *, const char *);
/*
* Visitors from synch.c, needed for enable -s and disable -s.
*/
extern int is_enabled(scf_instance_t *);
extern int has_potential(scf_instance_t *, int);
void
{
"Exiting.\n"));
/* NOTREACHED */
/* NOTREACHED */
default:
#ifdef NDEBUG
scf_strerror(err));
#else
scf_strerror(err));
#endif
}
}
static void
usage()
{
"Usage: %1$s [-v] [cmd [args ... ]]\n\n"
"\t%1$s enable [-rst] <service> ...\t- enable and online service(s)\n"
"\t%1$s disable [-st] <service> ...\t- disable and offline service(s)\n"
"\t%1$s restart <service> ...\t\t- restart specified service(s)\n"
"\t%1$s refresh <service> ...\t\t- re-read service configuration\n"
"\t%1$s mark [-It] <state> <service> ...\t- set maintenance state\n"
"\t%1$s clear <service> ...\t\t- clear maintenance state\n"
"\t%1$s milestone [-d] <milestone>\t- advance to a service milestone\n"
"\n\t"
"Services can be specified using an FMRI, abbreviation, or fnmatch(5)\n"
"\n"
"\t%1$s <cmd> network/*mail\n"
"\t%1$s <cmd> smtp:sendmail\n"
"\t%1$s <cmd> smtp\n"
"\t%1$s <cmd> sendmail\n"), uu_getpname());
}
/*
* FMRI hash table for recursive enable.
*/
static uint32_t
{
uint32_t h = 0, g;
const char *p;
for (p = str; *p != '\0'; ++p) {
h = (h << 4) + *p;
if ((g = (h & 0xf0000000)) != 0) {
h ^= (g >> 24);
h ^= g;
}
}
return (h);
}
/*
* Return 1 if str has been visited, 0 if it has not, and -1 if memory could not
* be allocated.
*/
static int
{
uint32_t h;
uint_t i;
i = h & (HT_BUCKETS - 1);
if (hep)
return (1);
}
}
return (-1);
if (hep)
return (0);
}
/*
* Returns 0, ECANCELED if pg is deleted, ENOENT if propname doesn't exist,
* EINVAL if the property is not of boolean type or has no values, and E2BIG
* if it has more than one value. *bp is set if 0 or E2BIG is returned.
*/
int
{
int ret;
scfdie();
switch (scf_error()) {
case SCF_ERROR_DELETED:
goto out;
case SCF_ERROR_NOT_FOUND:
goto out;
case SCF_ERROR_NOT_SET:
assert(0);
abort();
/* NOTREACHED */
default:
scfdie();
}
}
ret = 0;
} else {
switch (scf_error()) {
case SCF_ERROR_DELETED:
goto out;
case SCF_ERROR_NOT_FOUND:
goto out;
break;
case SCF_ERROR_NOT_SET:
assert(0);
abort();
/* NOTREACHED */
default:
scfdie();
}
}
if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
scfdie();
goto out;
}
out:
return (ret);
}
/*
* Returns 0, EPERM, or EROFS.
*/
static int
{
scf_value_t *v;
int ret = 0, r;
(v = scf_value_create(h)) == NULL)
scfdie();
scf_value_set_boolean(v, b);
for (;;) {
switch (scf_error()) {
goto out;
goto out;
default:
scfdie();
}
}
SCF_TYPE_BOOLEAN) != 0) {
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
SCF_TYPE_BOOLEAN) != 0)
scfdie();
}
r = scf_entry_add_value(ent, v);
assert(r == 0);
r = scf_transaction_commit(tx);
if (r == 1)
break;
if (r != 0) {
switch (scf_error()) {
goto out;
goto out;
default:
scfdie();
}
}
scfdie();
}
out:
return (ret);
}
/*
* Gets the single astring value of the propname property of pg. prop & v are
* scratch space. Returns the length of the string on success or
* -ENOENT - pg has no property named propname
* -E2BIG - property has no values or multiple values
* -EINVAL - property type is not compatible with astring
*/
{
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
return (-ENOENT);
}
if (scf_property_get_value(prop, v) != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
return (-E2BIG);
default:
scfdie();
}
}
if (sz < 0) {
if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
scfdie();
return (-EINVAL);
}
return (sz);
}
/*
* Returns 0 or EPERM.
*/
static int
{
return (0);
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
return (0);
switch (scf_error()) {
case SCF_ERROR_EXISTS:
goto again;
return (EPERM);
default:
scfdie();
/* NOTREACHED */
}
}
static int
{
char *ct_fmri;
return (ret);
}
/*
* Set auxiliary_tty and auxiliary_fmri properties in restarter_actions pg to
* communicate whether the action is requested from a tty and the fmri of the
* responsible process.
*
* Returns 0, EPERM, or EROFS
*/
static int
{
int ret = 0;
scfdie();
if (!verbose)
else
goto out;
}
/* Set auxiliary_tty property */
if (isatty(STDIN_FILENO))
b = B_TRUE;
/* Create and set state to disabled */
case 0:
break;
case EPERM:
if (!verbose)
else
goto out;
/* NOTREACHED */
case EROFS:
/* Shouldn't happen, but it can. */
if (!verbose)
else
"(repository read-only).\n"), fmri,
goto out;
/* NOTREACHED */
default:
scfdie();
}
} else {
"my_ct_name failed.\n"), fmri,
}
out:
return (ret);
}
/*
* Enable or disable inst, per enable. If temp is true, set
* general_ovr/enabled. Otherwise set general/enabled and delete
* general_ovr/enabled if it exists (order is important here: we don't want the
* enabled status to glitch).
*/
static void
{
uint8_t b;
int r;
pg = scf_pg_create(h);
scfdie();
goto out;
/*
* doesn't exist. Create both the property group and property
* here if they don't exist.
*/
SCF_PG_GENERAL_FLAGS, pg) != 0)
goto eperm;
/* Create and set state to disabled */
case 0:
break;
case EPERM:
goto eperm;
case EROFS:
/* Shouldn't happen, but it can. */
if (!verbose)
fmri);
else
"(repository read-only).\n"), fmri,
goto out;
default:
assert(0);
abort();
}
}
if (temp) {
/* Set general_ovr/enabled */
SCF_PG_GENERAL_OVR_FLAGS, pg) != 0)
goto eperm;
case 0:
break;
case EPERM:
goto eperm;
case EROFS:
/* Shouldn't happen, but it can. */
if (!verbose)
fmri);
else
"(repository read-only).\n"), fmri,
goto out;
default:
assert(0);
abort();
}
if (verbose)
gettext("%s temporarily enabled.\n") :
} else {
/*
* Both pg and property should exist since we created
* them earlier. However, there's still a chance that
* someone may have deleted the property out from under
* us.
*/
SCF_PG_GENERAL_FLAGS, pg) != 0)
goto eperm;
case 0:
break;
case EPERM:
goto eperm;
case EROFS:
/*
* proceed.
*/
case 0:
break;
/* FALLTHROUGH */
case ENOENT:
case EINVAL:
case E2BIG:
if (!verbose)
"read-only.\n"), fmri);
else
"%s/%s (repository read-only).\n"),
goto out;
case ECANCELED:
goto again;
default:
assert(0);
abort();
}
break;
default:
assert(0);
abort();
}
switch (r) {
case 0:
break;
case ECANCELED:
goto out;
case EPERM:
goto eperm;
case EACCES:
"property of %s: backend access denied.\n"),
goto out;
case EROFS:
"property of %s: backend is read-only.\n"),
goto out;
default:
bad_error("scf_instance_delete_prop", r);
}
if (verbose)
}
return;
if (!verbose)
else
out:
exit_status = 1;
}
/*
* Set inst to the instance which corresponds to fmri. If fmri identifies
* a service with a single instance, get that instance.
*
* Fails with
* ENOTSUP - fmri has an unsupported scheme
* EINVAL - fmri is invalid
* ENOTDIR - fmri does not identify a service or instance
* ENOENT - could not locate instance
* E2BIG - fmri is a service with multiple instances (warning not printed)
*/
static int
{
char *cfmri;
int ret;
exit_status = 1;
return (ENOTSUP);
}
NULL) != SCF_SUCCESS) {
exit_status = 1;
return (EINVAL);
}
"FMRI \"%s\" does not designate a service or instance.\n"),
fmri);
exit_status = 1;
return (ENOTDIR);
}
NULL, SCF_DECODE_FMRI_EXACT) == 0)
return (0);
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
exit_status = 1;
return (ENOENT);
}
scfdie();
SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
exit_status = 1;
goto out;
}
/* If the service has only one child, use it. */
scfdie();
if (ret < 0)
scfdie();
if (ret != 1) {
fmri);
exit_status = 1;
goto out;
}
if (ret < 0)
scfdie();
if (ret != 0) {
goto out;
}
ret = 0;
out:
return (ret);
}
/*
* Same as get_inst_mult(), but on E2BIG prints a warning and returns ENOENT.
*/
static int
{
int r;
if (r != E2BIG)
return (r);
"instance specification needed.\n"), fmri);
return (ENOENT);
}
static char *
{
if (sz < 0)
scfdie();
if (sz >= max_scf_fmri_sz)
"long value.\n"));
return (scratch_fmri);
}
static ssize_t
{
if (sz >= 0)
return (sz);
switch (-sz) {
case ENOENT:
return (-1);
case E2BIG:
return (-1);
case EINVAL:
return (-1);
default:
assert(0);
abort();
/* NOTREACHED */
}
}
static boolean_t
{
int count = 0, r;
inst = scf_instance_create(h);
scfdie();
for (;;) {
r = scf_iter_next_value(iter, v);
if (r == 0) {
goto out;
}
if (r != 1)
scfdie();
scfdie();
case 0:
++count;
if (count > 1) {
goto out;
}
break;
case ENOTSUP:
case EINVAL:
case ENOTDIR:
case ENOENT:
continue;
case E2BIG:
goto out;
default:
assert(0);
abort();
}
}
out:
return (ret);
}
/*
* Enable the service or instance identified by fmri and its dependencies,
* recursively. Specifically, call get_inst(fmri), enable the result, and
* recurse on its restarter and the dependencies. To avoid duplication of
* effort or looping around a dependency cycle, each FMRI is entered into the
* "visited" hash table. While recursing, the hash table entry is marked
* "active", so that if we come upon it again, we know we've hit a cycle.
* exclude_all and optional_all dependencies are ignored. require_any
* dependencies are followed only if they comprise a single service; otherwise
* the user is warned.
*
* fmri must point to a writable max_scf_fmri_sz buffer. Returns EINVAL if fmri
* is invalid, E2BIG if fmri identifies a service with multiple instances, ELOOP
* on cycle detection, or 0 on success.
*/
static int
{
scf_value_t *v;
int ret;
if (len < 0) {
return (EINVAL);
}
case 0:
break;
case 1:
case -1:
default:
assert(0);
abort();
}
inst = scf_instance_create(h);
scfdie();
case 0:
break;
case E2BIG:
return (E2BIG);
default:
return (0);
}
(v = scf_value_create(h)) == NULL ||
scfdie();
if (name_sz < 0)
scfdie();
++name_sz;
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
}
/* Enable restarter */
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
ret = 0;
goto out;
}
if (sz > max_scf_fmri_sz) {
ret = 0;
goto out;
} else if (sz >= 0) {
case 0:
break;
case EINVAL:
"invalid.\n"), fmri);
break;
case E2BIG:
"a service with multiple instances.\n"), fmri);
break;
case ELOOP:
goto out;
default:
assert(0);
abort();
}
} else if (sz < 0) {
switch (-sz) {
case ENOENT:
break;
case E2BIG:
"property is not single-valued).\n"), fmri,
ret = 0;
goto out;
case EINVAL:
"property is not of astring type).\n"), fmri,
ret = 0;
goto out;
default:
assert(0);
abort();
}
}
SCF_GROUP_DEPENDENCY) == -1)
scfdie();
if (len < 0)
scfdie();
v, buf, max_scf_fmri_sz) < 0)
continue;
continue;
continue;
continue;
continue;
}
-1) {
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
"dependency lacks \"%s\" property.)\n"), fmri,
continue;
}
scfdie();
if (ty != SCF_TYPE_FMRI) {
continue;
}
scfdie();
fmri);
0)
scfdie();
for (;;) {
int r;
r = scf_iter_next_value(val_iter, v);
if (r == 0)
break;
if (r != 1)
scfdie();
if (scf_value_get_astring(v, buf,
max_scf_fmri_sz) < 0)
scfdie();
}
continue;
}
/*
* Since there's only one instance, we can enable it.
* Reset val_iter and continue.
*/
scfdie();
}
for (;;) {
if (ret == 0)
break;
if (ret != 1)
scfdie();
-1)
scfdie();
case 0:
break;
case EINVAL:
"has invalid FMRI \"%s\".\n"), pgname,
break;
case E2BIG:
break;
case ELOOP:
goto out;
default:
assert(0);
abort();
}
}
}
ret = 0;
out:
(void) scf_value_destroy(v);
return (ret);
}
/*
* fmri here is only used for verbose messages.
*/
static void
const char *action)
{
scf_value_t *v;
int ret;
int64_t t;
const char * const scf_pg_restarter_actions = SCF_PG_RESTARTER_ACTIONS;
(v = scf_value_create(h)) == NULL ||
scfdie();
goto out;
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
/* Try creating the restarter_actions property group. */
switch (scf_error()) {
case SCF_ERROR_EXISTS:
/* Someone must have added it. */
break;
if (!verbose)
else
goto out;
default:
scfdie();
}
}
}
/*
* If we lose the transaction race and need to retry, there are 2
* potential other winners:
* - another process setting actions
* - the restarter marking the action complete
* Therefore, re-read the property every time through the loop before
* making any decisions based on their values.
*/
do {
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
if (!verbose)
else
goto out;
}
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
scfdie();
goto action_set;
} else {
scfdie();
}
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
/* Misconfigured, so set anyway. */
goto action_set;
default:
scfdie();
}
} else {
if (scf_value_get_integer(v, &t) == -1) {
goto action_set;
}
if (t > timestamp)
break;
}
scfdie();
if (ret == -1) {
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
if (!verbose)
else
goto out;
}
if (ret == 0) {
scfdie();
}
} while (ret == 0);
if (verbose)
out:
}
/*
* Get the state of inst. state should point to a buffer of
* MAX_SCF_STATE_STRING_SZ bytes. Returns 0 on success or -1 if
* no restarter property group
* no state property
* state property is misconfigured (wrong type, not single-valued)
* state value is too long
* In these cases, fmri is used to print a warning.
*
* If pgp is non-NULL, a successful call to inst_get_state will store
* the SCF_PG_RESTARTER property group in *pgp, and the caller will be
* responsible for calling scf_pg_destroy on the property group.
*/
int
{
int ret = -1;
scfdie();
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
goto out;
}
if (szret < 0) {
switch (-szret) {
case ENOENT:
"group lacks \"%s\" property).\n"),
goto out;
case E2BIG:
"property is not single-valued).\n"),
goto out;
case EINVAL:
"property is not of type astring).\n"),
goto out;
default:
assert(0);
abort();
}
}
if (szret >= MAX_SCF_STATE_STRING_SZ) {
goto out;
}
ret = 0;
if (pgp)
out:
(void) scf_value_destroy(val);
return (ret);
}
static void
{
int ret;
inst = scf_instance_create(h);
scfdie();
return;
scfdie();
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
SCF_SUCCESS) {
switch (scf_error()) {
case SCF_ERROR_EXISTS:
SCF_SUCCESS) {
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
"contention.\n"));
goto out;
}
break;
if (!verbose)
else
goto out;
default:
scfdie();
}
}
}
do {
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
if (!verbose)
else
goto out;
}
SCF_TYPE_ASTRING) != 0) {
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
SCF_TYPE_ASTRING) != 0)
scfdie();
}
scfdie();
scfdie();
if (ret == -1) {
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
if (!verbose)
else
propname);
goto out;
}
if (ret == 0) {
scfdie();
}
} while (ret == 0);
out:
}
/*
* Flags to control enable and disable actions.
*/
#define SET_ENABLED 0x1
#define SET_TEMPORARY 0x2
#define SET_RECURSIVE 0x4
static int
{
if (flags & SET_RECURSIVE) {
/* scf_walk_fmri() guarantees that fmri isn't too long */
case E2BIG:
"instance specification needed.\n"), fmri_buf);
break;
case ELOOP:
fmri_buf);
}
} else {
}
return (0);
}
/* ARGSUSED */
static int
{
char state[MAX_SCF_STATE_STRING_SZ];
do {
if (pg)
return (0);
}
/*
* We're done.
*/
goto out;
}
/*
* The service is ill.
*/
goto out;
}
/*
* Someone stepped in and disabled the service.
*/
goto out;
}
/*
* Our dependencies aren't met. We'll never
* amount to anything.
*/
/*
* EXIT_SVC_FAILURE takes precedence over
* EXIT_DEP_FAILURE
*/
if (exit_status == 0)
goto out;
}
scfdie();
/* NOTREACHED */
out:
return (0);
}
/* ARGSUSED */
static int
{
char state[MAX_SCF_STATE_STRING_SZ];
do {
if (pg)
return (0);
}
/*
* We're done.
*/
goto out;
}
/*
* Someone stepped in and enabled the service.
*/
goto out;
}
/*
* Our restarter is hopeless.
*/
/*
* EXIT_SVC_FAILURE takes precedence over
* EXIT_DEP_FAILURE
*/
if (exit_status == 0)
goto out;
}
scfdie();
/* NOTREACHED */
out:
return (0);
}
/* ARGSUSED */
static int
{
char state[MAX_SCF_STATE_STRING_SZ];
return (0);
0) {
} else {
exit_status = 1;
}
return (0);
}
static int
{
return (0);
}
/*
* Flags to control 'mark' action.
*/
#define MARK_IMMEDIATE 0x1
#define MARK_TEMPORARY 0x2
static int
{
char state[MAX_SCF_STATE_STRING_SZ];
exit_status = 1;
return (0);
}
exit_status = 1;
return (0);
}
return (0);
}
static int
{
const char *prop;
if (flags & MARK_IMMEDIATE) {
} else {
}
return (0);
}
static void
{
int r;
if (temporary) {
return;
}
scfdie();
return;
}
/*
* Set the persistent milestone before deleting the override so we don't
* glitch.
*/
fmri);
switch (r) {
case 0:
break;
case ECANCELED:
exit_status = 1;
goto out;
case EPERM:
"%s: permission denied.\n"), SCF_PG_OPTIONS_OVR,
exit_status = 1;
goto out;
case EACCES:
"%s: access denied.\n"), SCF_PG_OPTIONS_OVR,
exit_status = 1;
goto out;
case EROFS:
"%s: backend read-only.\n"), SCF_PG_OPTIONS_OVR,
exit_status = 1;
goto out;
default:
bad_error("scf_instance_delete_prop", r);
}
out:
}
static char const *milestones[] = {
};
static void
usage_milestone(void)
{
const char **ms;
"Usage: svcadm milestone [-d] <milestone>\n\n"
"\t-d\tmake the specified milestone the default for system boot\n\n"
"\tMilestones can be specified using an FMRI or abbreviation.\n"
"\tThe major milestones are as follows:\n\n"
"\tall\n"
"\tnone\n"));
}
static const char *
validate_milestone(const char *milestone)
{
const char **ms;
const char *tmp;
return (milestone);
return (milestone);
/*
* Determine if this is a full or partial milestone
*/
/*
* The beginning of the string must align with the start
* of a milestone fmri, or on the boundary between
* elements. The end of the string must align with the
* end of the milestone, or at the instance boundary.
*/
return (*ms);
}
}
/* NOTREACHED */
}
/*ARGSUSED*/
static void
{
/* Do nothing */
}
int
{
int o;
int err;
int sw_back;
(void) textdomain(TEXT_DOMAIN);
(void) uu_setpname(argv[0]);
if (argc < 2)
usage();
if (max_scf_fmri_sz < 0)
scfdie();
if (scratch_fmri == NULL)
h = scf_handle_create(SCF_VERSION);
if (h == NULL)
scfdie();
if (scf_handle_bind(h) == -1)
if (o == 'v')
verbose = 1;
else
usage();
}
usage();
"property group (permission denied).\n");
"group (permission denied).\n");
"property (permission denied).\n");
int flags = SET_ENABLED;
int wait = 0;
int error = 0;
++optind;
if (o == 'r')
flags |= SET_RECURSIVE;
else if (o == 't')
flags |= SET_TEMPORARY;
else if (o == 's')
wait = 1;
else if (o == '?')
usage();
else {
assert(0);
abort();
}
}
if (argc <= 0)
usage();
/*
* We want to continue with -s processing if we had
* invalid options, but not if an enable failed. We
* squelch output the second time we walk fmris; we saw
* the errors the first time.
*/
} else if (wait && exit_status == 0 &&
}
if (error > 0)
exit_status = error;
int flags = 0;
int wait = 0;
int error = 0;
++optind;
if (o == 't')
flags |= SET_TEMPORARY;
else if (o == 's')
wait = 1;
else if (o == '?')
usage();
else {
assert(0);
abort();
}
}
if (argc <= 0)
usage();
/*
* We want to continue with -s processing if we had
* invalid options, but not if a disable failed. We
* squelch output the second time we walk fmris; we saw
* the errors the first time.
*/
} else if (wait && exit_status == 0 &&
}
if (error > 0)
exit_status = error;
++optind;
usage();
set_fmri_action, (void *)SCF_PROPERTY_RESTART,
&exit_status, uu_warn)) != 0) {
}
++optind;
usage();
set_fmri_action, (void *)SCF_PROPERTY_REFRESH,
&exit_status, uu_warn)) != 0) {
}
int flags = 0;
++optind;
if (o == 'I')
flags |= MARK_IMMEDIATE;
else if (o == 't')
flags |= MARK_TEMPORARY;
else if (o == '?')
usage();
else {
assert(0);
abort();
}
}
usage();
if (flags & MARK_TEMPORARY)
"used with degraded.\n"));
} else {
usage();
}
uu_warn)) != 0) {
"instances: %s\n"),
scf_strerror(err));
}
++optind;
usage();
}
const char *milestone;
++optind;
if (o == 'd')
else if (o == '?')
else {
assert(0);
abort();
}
}
++optind;
usage();
SCF_SUCCESS) {
switch (scf_error()) {
case SCF_ERROR_NOT_BOUND:
scfdie();
break;
break;
case SCF_ERROR_INTERNAL:
reason =
"unknown error (see console for details)";
break;
}
}
++optind;
/*
* Check argument and setup scf_switch structure
*/
exit(1);
sw_back = 0;
sw_back = 1;
} else {
}
/*
* Call into switch primitive
*/
SCF_SUCCESS) {
/*
* Retrieve per thread SCF error code
*/
switch (scf_error()) {
case SCF_ERROR_NOT_BOUND:
abort();
/* NOTREACHED */
scfdie();
/* NOTREACHED */
break;
case SCF_ERROR_INTERNAL:
reason = "File operation error: (see console)";
break;
default:
abort();
/* NOTREACHED */
}
}
} else {
usage();
}
if (scf_handle_unbind(h) == -1)
scfdie();
return (exit_status);
}