/*
* 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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 2011, Joyent, Inc. All rights reserved.
*/
/*
* svcprop - report service configuration properties
*/
#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 <unistd.h>
#include <strings.h>
#include <assert.h>
#include <zone.h>
#ifndef TEXT_DOMAIN
#endif /* TEXT_DOMAIN */
/*
* Error functions. These can change if the quiet (-q) option is used.
*/
/*
* Entity encapsulation. This allows me to treat services and instances
* similarly, and avoid duplicating process_ent().
*/
typedef struct {
union {
} u;
#define ENT_INSTANCE 0
/*
* just track the components.
*/
typedef struct svcprop_prop_node {
const char *spn_comp1;
const char *spn_comp2;
/* Options */
/*
* For unexpected libscf errors. The ending newline is necessary to keep
* uu_die() from appending the errno error.
*/
static void
scfdie()
{
scf_strerror(scf_error()));
}
static void *
{
void *p;
if (p == NULL)
return (p);
}
static void
usage()
{
"[-C | -c | -s snapshot] [-z zone] "
"[-p [name/]name]... \n"
" {FMRI | pattern}...\n"
" %1$s -w [-fqtv] [-z zone] [-p [name/]name] "
"{FMRI | pattern}\n"), uu_getpname());
}
/*
* Return an allocated copy of str, with the Bourne shell's metacharacters
* escaped by '\'.
*
* What about unicode?
*/
static char *
{
const char *sp;
if (str[0] == '\0')
return (strdup("\"\""));
dst_len = 0;
++dst_len;
++dst_len;
}
*dp++ = '\\';
}
*dp = '\0';
return (dst);
}
static void
{
if (bufsz - 1 < 0)
scfdie();
}
/*
* Display a property's values on a line. If types is true, prepend
* of the property.
*/
static void
{
const char * const permission_denied_emsg =
gettext("Permission denied.\n");
if (types) {
char *buf;
if (fmris) {
scfdie();
} else {
scfdie();
(void) putchar('/');
scfdie();
}
(void) putchar(' ');
scfdie();
(void) putchar(' ');
}
scfdie();
scfdie();
first = 1;
if (first)
first = 0;
else
(void) putchar(' ');
}
if (ret == -1) {
if (err == SCF_ERROR_PERMISSION_DENIED) {
if (uu_list_numnodes(prop_list) > 0)
} else {
scfdie();
}
}
(void) putchar('\n');
(void) scf_value_destroy(val);
}
/*
* display_prop() all of the properties in the given property group. Force
* types to true so identification will be displayed.
*/
static void
{
int ret;
scfdie();
scfdie();
if (ret == -1)
scfdie();
}
/*
* Common code to execute when a nonexistant property is encountered.
*/
static void
{
if (!PRINT_NOPROP_ERRORS)
/* We're not printing errors, so we can cut out early. */
}
/*
* Iterate the properties of a service or an instance when no snapshot
* is specified.
*/
static int
{
int ret = 0;
/*
* If we are displaying properties for a service,
* treat it as though it were a composed, current
* lookup. (implicit cflag) However, if a snapshot
* was specified, fail.
*/
if (sflag)
"snapshots.\n"));
} else {
if (Cflag)
else
NULL);
}
return (ret);
}
/*
* Return a snapshot for the supplied instance and snapshot name.
*/
static scf_snapshot_t *
{
scfdie();
switch (scf_error()) {
/* NOTREACHED */
case SCF_ERROR_NOT_FOUND:
if (sflag == 0) {
} else
break;
default:
scfdie();
}
}
return (snap);
}
/*
* Entity (service or instance): If there are -p options,
* display_pg() all property groups.
*/
static void
{
if (uu_list_numnodes(prop_list) == 0) {
if (quiet)
return;
scfdie();
scfdie();
} else {
snap) == -1)
scfdie();
if (snap)
}
display_pg(pg);
if (ret == -1)
scfdie();
/*
* In normal usage, i.e. against the running snapshot,
* we must iterate over the current non-persistent
* pg's.
*/
NULL) == -1)
scfdie();
scfdie();
if (flags & SCF_PG_FLAG_NONPERSISTENT)
display_pg(pg);
}
}
if (ret == -1)
scfdie();
return;
}
scfdie();
if (Cflag)
else
/*
* If we didn't find it in the specified snapshot, use
* the current values if the pg is nonpersistent.
*/
pg);
if (ret == 0) {
scfdie();
if ((flags & SCF_PG_FLAG_NONPERSISTENT)
== 0) {
ret = -1;
}
}
}
} else {
/*
* If we are displaying properties for a service,
* treat it as though it were a composed, current
* lookup. (implicit cflag) However, if a snapshot
* was specified, fail.
*/
if (sflag)
"snapshots.\n"));
}
if (ret == -1) {
if (err != SCF_ERROR_NOT_FOUND)
scfdie();
if (PRINT_NOPROP_ERRORS) {
char *buf;
scfdie();
}
continue;
}
if (!quiet)
display_pg(pg);
continue;
}
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
if (PRINT_NOPROP_ERRORS) {
char *buf;
scfdie();
/* FMRI syntax knowledge */
buf);
}
continue;
}
if (!quiet)
}
if (snap)
}
/*
* Without -p options, just call display_pg(). Otherwise display_prop() the
* named properties of the property group.
*/
static void
{
if (quiet)
return;
display_pg(pg);
return;
}
scfdie();
char *buf;
-1)
scfdie();
"has too many components for property "
buf);
}
if (!quiet)
continue;
}
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
if (PRINT_NOPROP_ERRORS) {
char *buf;
-1)
scfdie();
}
}
}
/*
* If there are -p options, show the error. Otherwise just call
* display_prop().
*/
static void
{
"operands.\n"));
usage();
}
if (quiet)
return;
}
/* Decode an operand & dispatch. */
/* ARGSUSED */
static int
{
/* Multiple matches imply multiple entities. */
} else {
/* scf_walk_fmri() won't let this happen */
}
return (0);
}
static void
{
char *slash;
const char * const invalid_component_emsg =
gettext("Invalid component name `%s'.\n");
/* FMRI syntax knowledge. */
"components.\n"), property);
usage();
}
}
*slash = '\0';
p = safe_malloc(sizeof (svcprop_prop_node_t));
/*
* The -p options have mixed numbers of components.
* If they both turn out to be valid, then the
* single-component ones will specify property groups,
* so we need to turn on types to keep the output of
* display_prop() consistent with display_pg().
*/
types = 1;
}
}
}
/*
* Wait for a property group or property change.
*
* Extract a pg and optionally a property name from fmri & prop_list.
* _scf_pg_wait() for the pg, and display_pg(pg) or display_prop(pg, prop)
* when it returns.
*/
/* ARGSUSED */
static int
{
const char *propname;
scfdie();
if (uu_list_numnodes(prop_list) > 0)
"property FMRIs.\n"));
p = uu_list_first(prop_list);
if (p != NULL) {
"\"%s/%s\" has too many components for "
"property group %s.\n"),
SCF_SUCCESS) {
switch (scf_error()) {
gettext("Invalid property name "
"\"%s\".\n"), propname);
/* NOTREACHED */
case SCF_ERROR_NOT_FOUND:
/* NOTREACHED */
default:
scfdie();
}
}
} else {
}
p = uu_list_first(prop_list);
if (p == NULL)
gettext("Cannot wait for an instance.\n"));
SCF_SUCCESS) {
switch (scf_error()) {
"property group name \"%s\".\n"),
p->spn_comp1);
case SCF_ERROR_NOT_FOUND:
/* NOTREACHED */
default:
scfdie();
}
}
SCF_SUCCESS) {
switch (scf_error()) {
gettext("Invalid property name "
"\"%s\".\n"), propname);
case SCF_ERROR_NOT_FOUND:
/* NOTREACHED */
default:
scfdie();
}
}
}
p = uu_list_first(prop_list);
if (p == NULL)
gettext("Cannot wait for a service.\n"));
SCF_SUCCESS) {
switch (scf_error()) {
"property group name \"%s\".\n"),
p->spn_comp1);
case SCF_ERROR_NOT_FOUND:
default:
scfdie();
}
}
SCF_SUCCESS) {
switch (scf_error()) {
gettext("Invalid property name "
"\"%s\".\n"), propname);
/* NOTREACHED */
case SCF_ERROR_NOT_FOUND:
/* NOTREACHED */
default:
scfdie();
}
}
}
} else {
"property group, or property.\n"));
}
for (;;) {
int ret;
if (ret != SCF_SUCCESS)
scfdie();
if (ret < 0) {
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
}
if (ret == SCF_COMPLETE)
break;
}
if (!quiet)
} else {
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
if (PRINT_NOPROP_ERRORS)
}
} else {
if (!quiet)
display_pg(pg);
}
return (0);
}
/*
* These functions replace uu_warn() and uu_die() when the quiet (-q) option is
* used, and silently ignore any output.
*/
/*ARGSUSED*/
static void
{
/* Do nothing */
}
/*ARGSUSED*/
static void
{
}
int
{
int c;
int flags;
int err;
(void) textdomain(TEXT_DOMAIN);
(void) uu_setpname(argv[0]);
sizeof (svcprop_prop_node_t),
scfdie();
switch (c) {
case 'C':
usage(); /* Not with -c, -s or -w */
Cflag++;
break;
case 'c':
usage(); /* Not with -C, -s or -w */
cflag++;
break;
case 'f':
types = 1;
fmris = 1;
break;
case 'p':
break;
case 'q':
quiet = 1;
warn = quiet_warn;
break;
case 's':
usage(); /* Not with -C, -c or -w */
sflag++;
break;
case 't':
types = 1;
break;
case 'v':
verbose = 1;
break;
case 'w':
usage(); /* Not with -C, -c or -s */
wait = 1;
break;
case 'z': {
scf_handle_t *h = hndl;
if (getzoneid() != GLOBAL_ZONEID)
"from the global zone\n"));
scfdie();
scfdie();
break;
}
case '?':
switch (optopt) {
case 'p':
usage();
default:
break;
}
/* FALLTHROUGH */
default:
usage();
}
}
usage();
max_scf_fmri_length == -1)
scfdie();
if (wait) {
usage();
usage();
} else {
}
scf_strerror(err));
}
return (return_code);
}