/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* synchronous svcadm logic
*/
#include <locale.h>
#include <libintl.h>
#include <libscf.h>
#include <libscf_priv.h>
#include <libuutil.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
/*
* Definitions from svcadm.c.
*/
extern scf_handle_t *h;
extern ssize_t max_scf_fmri_sz;
extern void do_scfdie(int) __NORETURN;
extern int inst_get_state(scf_instance_t *, char *, const char *,
scf_propertygroup_t **);
int has_potential(scf_instance_t *, int);
/*
* Determines if the specified instance is enabled, composing the
* general and general_ovr property groups. For simplicity, we map
* most errors to "not enabled".
*/
int
{
scfdie();
return (bp);
}
return (bp);
}
return (B_FALSE);
}
/*
* Reads an astring property from a property group. If the named
* property doesn't exist, returns NULL. The result of a successful
* call should be freed.
*/
static char *
{
char *value;
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_DELETED:
return (NULL);
default:
scfdie();
}
}
switch (scf_error()) {
case SCF_ERROR_DELETED:
case SCF_ERROR_NOT_FOUND:
return (NULL);
default:
scfdie();
}
}
scfdie();
return (NULL);
}
return (value);
}
/*
* Creates and returns an scf_iter for the values of the named
* multi-value property. Returns NULL on failure.
*/
static scf_iter_t *
{
scfdie();
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_DELETED:
goto error;
default:
scfdie();
}
}
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
goto error;
}
return (iter);
return (NULL);
}
/*
* Reads the next value from the multi-value property using the
* scf_iter obtained by prop_walk_init, and places it in the buffer
* pointed to by fmri. Returns -1 on failure, 0 when done, and non-0
* when returning a value.
*/
static int
{
int r;
scfdie();
if (r == 0)
goto out;
if (r == -1) {
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
goto out;
}
r = -1;
goto out;
}
out:
return (r);
}
/*
* Determines if a file dependency is satisfied, taking into account
* whether it is an exclusion dependency or not. If we can't access
* the file, we err on the side of caution and assume the dependency
* isn't satisfied.
*/
static int
{
const char *path;
return (good);
return (good);
return (B_FALSE);
}
return (!good);
}
/*
* Determines if a dependency on a service instance is satisfiable.
* Returns 0 if not, 1 if it is, or 2 if it is an optional or exclude
* dependency and the service only "weakly" satisfies (i.e. is disabled
* or is in maintenance state).
*/
static int
{
if (!enabled)
/*
* Normally we would return a positive value on failure;
* relying on startd to place the service in maintenance. But
* if we can't read a service's state, we have to assume it is
* out to lunch.
*/
return (0);
/*
* Optional dependencies which are offline always have a possibility of
* coming online.
*/
return (2);
/*
* Enabled services in maintenance state satisfy
* optional-all dependencies.
*/
}
/*
* We're enabled and not in maintenance.
*/
if (exclude)
return (0);
return (1);
}
/*
* Determines if a dependency on an fmri is satisfiable, handling the
* separate cases for file, service, and instance fmris. Returns false
* if not, or true if it is. Takes into account if the dependency is
* an optional or exclusive one.
*/
static int
int restarter)
{
int enabled;
int r, result;
int optbad;
if (isfile)
scfdie();
SCF_DECODE_FMRI_EXACT) == 0) {
result =
goto out;
}
SCF_DECODE_FMRI_EXACT) != 0) {
/*
* If we are checking a restarter dependency, a bad
* or nonexistent service will never be noticed.
*/
goto out;
}
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
goto out;
}
optbad = 0;
for (;;) {
if (r == 0) {
goto out;
}
if (r == -1) {
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
goto out;
}
/*
* Exclusion dependencies over services map to
* require-none for its instances.
*/
if (exclude)
r = (r == 0);
if (r == 1) {
/*
* Remember, if this is an exclusion dependency
* (which means we are here because there
* exists an instance which wasn't satisfiable
* in that regard), good means bad.
*/
goto out;
}
if (optional && r == 0)
optbad = 1;
}
out:
return (result);
}
static int
{
for (;;) {
/*
* For reasons unknown, an empty require_any dependency
* group is considered by startd to be satisfied.
* This insanity fortunately doesn't extend to
* dependencies on services with no instances.
*/
B_FALSE))
return (1);
}
}
static int
{
int r;
for (;;) {
return ((r == 0) ? 1 : r);
B_FALSE))
return (0);
}
}
static int
{
}
static int
{
}
static int
{
}
/*
* Examines the state and health of an instance's restarter and
* dependencies, and determines the impact of both on the instance's
* ability to be brought on line. A true return value indicates that
* instance appears to be a likely candidate for the online club.
* False indicates that there is no hope for the instance.
*/
int
{
char *value;
int isfile;
scfdie();
/*
* First we check our restarter as an implicit dependency.
*/
scfdie();
value_sz);
if (r == -ENOENT) {
} else if (r < 0 || r > max_scf_fmri_sz) {
/*
* Normally we would return true and let the restarter
* tell our caller there is a problem by changing the
* instance's state, but that's not going to happen if
* the restarter is invalid.
*/
goto out;
}
goto out;
}
if (restarter_only)
goto out;
/*
* Now we check explicit dependencies.
*/
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
}
SCF_GROUP_DEPENDENCY) != 0) {
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
goto out;
}
for (;;) {
if (r == 0)
break;
if (r == -1) {
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
goto out;
}
SCF_PROPERTY_GROUPING)) == NULL)
goto out;
SCF_PROPERTY_TYPE)) == NULL)
goto out;
} else {
goto out;
}
goto out;
} else {
goto out;
}
if (r == 0) {
goto out;
} else if (r == -1) {
goto out;
}
}
out:
return (result);
}