summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr/src/cmd/svc/svcs/explain.c13
-rw-r--r--usr/src/cmd/svc/svcs/svcs.c284
-rw-r--r--usr/src/lib/libscf/common/lowlevel.c64
3 files changed, 304 insertions, 57 deletions
diff --git a/usr/src/cmd/svc/svcs/explain.c b/usr/src/cmd/svc/svcs/explain.c
index 5bb1674a9d..84f5e8f693 100644
--- a/usr/src/cmd/svc/svcs/explain.c
+++ b/usr/src/cmd/svc/svcs/explain.c
@@ -22,6 +22,7 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright (c) 2011, Joyent, Inc. All rights reserved.
*/
/*
@@ -198,6 +199,7 @@ static char *emsg_nomem;
static char *emsg_invalid_dep;
extern scf_handle_t *h;
+extern char *g_zonename;
/* ARGSUSED */
static int
@@ -223,7 +225,6 @@ hash_name(const char *name)
return (h);
}
-
static void
x_init(void)
{
@@ -1996,6 +1997,9 @@ print_service(inst_t *svcp, int verbose)
(void) putchar('\n');
}
+ if (g_zonename != NULL)
+ (void) printf(gettext(" Zone: %s\n"), g_zonename);
+
stime = svcp->stime.tv_sec;
tmp = localtime(&stime);
@@ -2097,7 +2101,12 @@ print_service_cb(void *verbose, scf_walkinfo_t *wip)
void
explain(int verbose, int argc, char **argv)
{
- /* Initialize globals. */
+ /*
+ * Initialize globals. If we have been called before (e.g., for a
+ * different zone), this will clobber the previous globals -- keeping
+ * with the proud svcs(1) tradition of not bothering to ever clean
+ * anything up.
+ */
x_init();
/* Walk the graph and populate services with inst_t's */
diff --git a/usr/src/cmd/svc/svcs/svcs.c b/usr/src/cmd/svc/svcs/svcs.c
index 3ad142ef53..ce43f32c9f 100644
--- a/usr/src/cmd/svc/svcs/svcs.c
+++ b/usr/src/cmd/svc/svcs/svcs.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, Joyent, Inc. All rights reserved.
*/
/*
@@ -76,7 +77,7 @@
#include <stdlib.h>
#include <strings.h>
#include <time.h>
-
+#include <zone.h>
#ifndef TEXT_DOMAIN
#define TEXT_DOMAIN "SUNW_OST_OSCMD"
@@ -131,6 +132,7 @@ static struct pfmri_list *restarters = NULL;
static int first_paragraph = 1; /* For -l mode. */
static char *common_name_buf; /* Sized for maximal length value. */
char *locale; /* Current locale. */
+char *g_zonename; /* zone being operated upon */
/*
* Pathname storage for path generated from the fmri.
@@ -146,6 +148,7 @@ static int *opt_sort = NULL; /* Indices into columns to sort. */
static int opt_snum = 0;
static int opt_nstate_shown = 0; /* Will nstate be shown? */
static int opt_verbose = 0;
+static char *opt_zone; /* zone selected, if any */
/* Minimize string constants. */
static const char * const scf_property_state = SCF_PROPERTY_STATE;
@@ -217,6 +220,26 @@ static uint_t ht_num;
static void
ht_init()
{
+ if (ht_buckets != NULL) {
+ /*
+ * If we already have a hash table (e.g., because we are
+ * processing multiple zones), destroy it before creating
+ * a new one.
+ */
+ struct ht_elem *elem, *next;
+ int i;
+
+ for (i = 0; i < ht_buckets_num; i++) {
+ for (elem = ht_buckets[i]; elem != NULL; elem = next) {
+ next = elem->next;
+ free((char *)elem->fmri);
+ free(elem);
+ }
+ }
+
+ free(ht_buckets);
+ }
+
ht_buckets_num = 8;
ht_buckets = safe_malloc(sizeof (*ht_buckets) * ht_buckets_num);
bzero(ht_buckets, sizeof (*ht_buckets) * ht_buckets_num);
@@ -1683,6 +1706,49 @@ sortkey_stime(char *buf, int reverse, scf_walkinfo_t *wip)
reverse_bytes(buf, STIME_SORTKEY_WIDTH);
}
+/* ZONE */
+#define ZONE_COLUMN_WIDTH 16
+/*ARGSUSED*/
+static void
+sprint_zone(char **buf, scf_walkinfo_t *wip)
+{
+ size_t newsize;
+ char *newbuf, *zonename = g_zonename, b[ZONENAME_MAX];
+
+ if (zonename == NULL) {
+ zoneid_t zoneid = getzoneid();
+
+ if (getzonenamebyid(zoneid, b, sizeof (b)) < 0)
+ uu_die(gettext("could not determine zone name"));
+
+ zonename = b;
+ }
+
+ if (strlen(zonename) > ZONE_COLUMN_WIDTH)
+ newsize = (*buf ? strlen(*buf) : 0) + strlen(zonename) + 2;
+ else
+ newsize = (*buf ? strlen(*buf) : 0) + ZONE_COLUMN_WIDTH + 2;
+
+ newbuf = safe_malloc(newsize);
+ (void) snprintf(newbuf, newsize, "%s%-*s ", *buf ? *buf : "",
+ ZONE_COLUMN_WIDTH, zonename);
+
+ if (*buf)
+ free(*buf);
+ *buf = newbuf;
+}
+
+static void
+sortkey_zone(char *buf, int reverse, scf_walkinfo_t *wip)
+{
+ char *tmp = NULL;
+
+ sprint_zone(&tmp, wip);
+ bcopy(tmp, buf, ZONE_COLUMN_WIDTH);
+ free(tmp);
+ if (reverse)
+ reverse_bytes(buf, ZONE_COLUMN_WIDTH);
+}
/*
* Information about columns which can be displayed. If you add something,
@@ -1712,6 +1778,8 @@ static const struct column columns[] = {
1, sortkey_state },
{ "STIME", STIME_COLUMN_WIDTH, sprint_stime,
STIME_SORTKEY_WIDTH, sortkey_stime },
+ { "ZONE", ZONE_COLUMN_WIDTH, sprint_zone,
+ ZONE_COLUMN_WIDTH, sortkey_zone },
};
#define MAX_COLUMN_NAME_LENGTH_STR "6"
@@ -1769,6 +1837,9 @@ description_of_column(int c)
case 13:
s = gettext("time of last state change");
break;
+ case 14:
+ s = gettext("name of zone");
+ break;
}
assert(s != NULL);
@@ -1781,11 +1852,11 @@ print_usage(const char *progname, FILE *f, boolean_t do_exit)
{
(void) fprintf(f, gettext(
"Usage: %1$s [-aHpv] [-o col[,col ... ]] [-R restarter] "
- "[-sS col] [<service> ...]\n"
+ "[-sS col] [-Z | -z zone ]\n [<service> ...]\n"
" %1$s -d | -D [-Hpv] [-o col[,col ... ]] [-sS col] "
- "[<service> ...]\n"
- " %1$s -l <service> ...\n"
- " %1$s -x [-v] [<service> ...]\n"
+ "[-Z | -z zone ]\n [<service> ...]\n"
+ " %1$s -l [-Z | -z zone] <service> ...\n"
+ " %1$s -x [-v] [-Z | -z zone] [<service> ...]\n"
" %1$s -?\n"), progname);
if (do_exit)
@@ -1816,6 +1887,8 @@ print_help(const char *progname)
"\t-v list verbose information appropriate to the type of output\n"
"\t-x explain the status of services that might require maintenance,\n"
"\t or explain the status of the specified service(s)\n"
+ "\t-z from global zone, show services in a specified zone\n"
+ "\t-Z from global zone, show services in all zones\n"
"\n\t"
"Services can be specified using an FMRI, abbreviation, or fnmatch(5)\n"
"\tpattern, as shown in these examples for svc:/network/smtp:sendmail\n"
@@ -2372,6 +2445,9 @@ print_detailed(void *unused, scf_walkinfo_t *wip)
(void) printf(fmt, DETAILED_WIDTH, gettext("name"),
common_name_buf);
+ if (g_zonename != NULL)
+ (void) printf(fmt, DETAILED_WIDTH, gettext("zone"), g_zonename);
+
/*
* Synthesize an 'enabled' property that hides the enabled_ovr
* implementation from the user. If the service has been temporarily
@@ -3319,11 +3395,15 @@ main(int argc, char **argv)
char *cp;
const char *progname;
int err;
+ uint_t nzents = 0, zent = 0;
+ zoneid_t *zids = NULL;
+ char zonename[ZONENAME_MAX];
int show_all = 0;
int show_header = 1;
+ int show_zones = 0;
- const char * const options = "aHpvno:R:s:S:dDl?x";
+ const char * const options = "aHpvno:R:s:S:dDl?xZz:";
(void) setlocale(LC_ALL, "");
@@ -3451,6 +3531,20 @@ main(int argc, char **argv)
assert(opt_mode == optopt);
break;
+ case 'z':
+ if (show_zones)
+ argserr(progname);
+
+ opt_zone = optarg;
+ break;
+
+ case 'Z':
+ if (opt_zone != NULL)
+ argserr(progname);
+
+ show_zones = 1;
+ break;
+
case '?':
argserr(progname);
/* NOTREACHED */
@@ -3467,22 +3561,88 @@ main(int argc, char **argv)
if (show_all && optind != argc)
uu_warn(gettext("-a ignored when used with arguments.\n"));
+ while (show_zones) {
+ uint_t found;
+
+ if (zone_list(NULL, &nzents) != 0)
+ uu_die(gettext("could not get number of zones"));
+
+ if ((zids = malloc(nzents * sizeof (zoneid_t))) == NULL) {
+ uu_die(gettext("could not allocate array for "
+ "%d zone IDs"), nzents);
+ }
+
+ found = nzents;
+
+ if (zone_list(zids, &found) != 0)
+ uu_die(gettext("could not get zone list"));
+
+ /*
+ * If the number of zones has not changed between our calls to
+ * zone_list(), we're done -- otherwise, we must free our array
+ * of zone IDs and take another lap.
+ */
+ if (found == nzents)
+ break;
+
+ free(zids);
+ }
+
+ argc -= optind;
+ argv += optind;
+
+again:
h = scf_handle_create(SCF_VERSION);
if (h == NULL)
scfdie();
- if (scf_handle_bind(h) == -1)
+ if (opt_zone != NULL || zids != NULL) {
+ scf_value_t *zone;
+
+ assert(opt_zone == NULL || zids == NULL);
+
+ if (opt_zone == NULL) {
+ if (getzonenamebyid(zids[zent++],
+ zonename, sizeof (zonename)) < 0) {
+ uu_warn(gettext("could not get name for "
+ "zone %d; ignoring"), zids[zent - 1]);
+ goto nextzone;
+ }
+
+ g_zonename = zonename;
+ } else {
+ g_zonename = opt_zone;
+ }
+
+ if ((zone = scf_value_create(h)) == NULL)
+ scfdie();
+
+ if (scf_value_set_astring(zone, g_zonename) != SCF_SUCCESS)
+ scfdie();
+
+ if (scf_handle_decorate(h, "zone", zone) != SCF_SUCCESS)
+ scfdie();
+
+ scf_value_destroy(zone);
+ }
+
+ if (scf_handle_bind(h) == -1) {
+ if (g_zonename != NULL) {
+ uu_warn(gettext("Could not bind to repository "
+ "server for zone %s: %s\n"), g_zonename,
+ scf_strerror(scf_error()));
+ goto nextzone;
+ }
+
uu_die(gettext("Could not bind to repository server: %s. "
"Exiting.\n"), scf_strerror(scf_error()));
+ }
if ((g_pg = scf_pg_create(h)) == NULL ||
(g_prop = scf_property_create(h)) == NULL ||
(g_val = scf_value_create(h)) == NULL)
scfdie();
- argc -= optind;
- argv += optind;
-
/*
* If we're in long mode, take care of it now before we deal with the
* sorting and the columns, since we won't use them anyway.
@@ -3498,7 +3658,7 @@ main(int argc, char **argv)
exit_status = UU_EXIT_FATAL;
}
- return (exit_status);
+ goto nextzone;
}
if (opt_mode == 'n') {
@@ -3510,67 +3670,72 @@ main(int argc, char **argv)
exit_status = UU_EXIT_FATAL;
}
- return (exit_status);
+ goto nextzone;
}
if (opt_mode == 'x') {
explain(opt_verbose, argc, argv);
-
- return (exit_status);
+ goto nextzone;
}
+ if (columns_str == NULL) {
+ if (opt_snum == 0) {
+ if (show_zones)
+ add_sort_column("zone", 0);
+
+ /* Default sort. */
+ add_sort_column("state", 0);
+ add_sort_column("stime", 0);
+ add_sort_column("fmri", 0);
+ }
- if (opt_snum == 0) {
- /* Default sort. */
- add_sort_column("state", 0);
- add_sort_column("stime", 0);
- add_sort_column("fmri", 0);
+ if (!opt_verbose) {
+ columns_str = safe_strdup(show_zones ?
+ "zone,state,stime,fmri" : "state,stime,fmri");
+ } else {
+ columns_str = safe_strdup(show_zones ?
+ "zone,state,nstate,stime,ctid,fmri" :
+ "state,nstate,stime,ctid,fmri");
+ }
}
- if (columns_str == NULL) {
- if (!opt_verbose)
- columns_str = safe_strdup("state,stime,fmri");
- else
- columns_str =
- safe_strdup("state,nstate,stime,ctid,fmri");
- }
+ if (opt_columns == NULL) {
+ /* Decode columns_str into opt_columns. */
+ line_sz = 0;
- /* Decode columns_str into opt_columns. */
- line_sz = 0;
+ opt_cnum = 1;
+ for (cp = columns_str; *cp != '\0'; ++cp)
+ if (*cp == ',')
+ ++opt_cnum;
- opt_cnum = 1;
- for (cp = columns_str; *cp != '\0'; ++cp)
- if (*cp == ',')
- ++opt_cnum;
+ opt_columns = malloc(opt_cnum * sizeof (*opt_columns));
+ if (opt_columns == NULL)
+ uu_die(gettext("Too many columns.\n"));
- opt_columns = malloc(opt_cnum * sizeof (*opt_columns));
- if (opt_columns == NULL)
- uu_die(gettext("Too many columns.\n"));
+ for (n = 0; *columns_str != '\0'; ++n) {
+ i = getcolumnopt(&columns_str);
+ if (i == -1)
+ uu_die(gettext("Unknown column \"%s\".\n"),
+ columns_str);
- for (n = 0; *columns_str != '\0'; ++n) {
- i = getcolumnopt(&columns_str);
- if (i == -1)
- uu_die(gettext("Unknown column \"%s\".\n"),
- columns_str);
+ if (strcmp(columns[i].name, "N") == 0 ||
+ strcmp(columns[i].name, "SN") == 0 ||
+ strcmp(columns[i].name, "NSTA") == 0 ||
+ strcmp(columns[i].name, "NSTATE") == 0)
+ opt_nstate_shown = 1;
- if (strcmp(columns[i].name, "N") == 0 ||
- strcmp(columns[i].name, "SN") == 0 ||
- strcmp(columns[i].name, "NSTA") == 0 ||
- strcmp(columns[i].name, "NSTATE") == 0)
- opt_nstate_shown = 1;
+ opt_columns[n] = i;
+ line_sz += columns[i].width + 1;
+ }
- opt_columns[n] = i;
- line_sz += columns[i].width + 1;
+ if ((lines_pool = uu_avl_pool_create("lines_pool",
+ sizeof (struct avl_string), offsetof(struct avl_string,
+ node), line_cmp, UU_AVL_DEBUG)) == NULL ||
+ (lines = uu_avl_create(lines_pool, NULL, 0)) == NULL)
+ uu_die(gettext("Unexpected libuutil error: %s\n"),
+ uu_strerror(uu_error()));
}
-
- if ((lines_pool = uu_avl_pool_create("lines_pool",
- sizeof (struct avl_string), offsetof(struct avl_string, node),
- line_cmp, UU_AVL_DEBUG)) == NULL ||
- (lines = uu_avl_create(lines_pool, NULL, 0)) == NULL)
- uu_die(gettext("Unexpected libuutil error: %s. Exiting.\n"),
- uu_strerror(uu_error()));
-
switch (opt_mode) {
case 0:
ht_init();
@@ -3631,6 +3796,15 @@ main(int argc, char **argv)
abort();
}
+nextzone:
+ if (show_zones && zent < nzents && exit_status == 0) {
+ scf_handle_destroy(h);
+ goto again;
+ }
+
+ if (opt_columns == NULL)
+ return (exit_status);
+
if (show_header)
print_header();
diff --git a/usr/src/lib/libscf/common/lowlevel.c b/usr/src/lib/libscf/common/lowlevel.c
index 7363c7fc9c..3bf4d31372 100644
--- a/usr/src/lib/libscf/common/lowlevel.c
+++ b/usr/src/lib/libscf/common/lowlevel.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, Joyent, Inc. All rights reserved.
*/
/*
@@ -49,7 +50,9 @@
#include <string.h>
#include <sys/mman.h>
#include <sys/sysmacros.h>
+#include <libzonecfg.h>
#include <unistd.h>
+#include <dlfcn.h>
#define ENV_SCF_DEBUG "LIBSCF_DEBUG"
#define ENV_SCF_DOORPATH "LIBSCF_DOORPATH"
@@ -879,6 +882,67 @@ scf_handle_decorate(scf_handle_t *handle, const char *name, scf_value_t *v)
}
return (0);
}
+
+ if (strcmp(name, "zone") == 0) {
+ char zone[MAXPATHLEN], root[MAXPATHLEN], door[MAXPATHLEN];
+ static int (*zone_get_rootpath)(char *, char *, size_t);
+ ssize_t len;
+
+ /*
+ * In order to be able to set the zone on a handle, we want
+ * to determine the zone's path, which requires us to call into
+ * libzonecfg -- but libzonecfg.so links against libscf.so so
+ * we must not explicitly link to it. To circumvent the
+ * circular dependency, we will pull it in here via dlopen().
+ */
+ if (zone_get_rootpath == NULL) {
+ void *dl = dlopen("libzonecfg.so.1", RTLD_LAZY), *sym;
+
+ if (dl == NULL)
+ return (scf_set_error(SCF_ERROR_NOT_FOUND));
+
+ if ((sym = dlsym(dl, "zone_get_rootpath")) == NULL) {
+ (void) dlclose(dl);
+ return (scf_set_error(SCF_ERROR_INTERNAL));
+ }
+
+ zone_get_rootpath = (int(*)(char *, char *, size_t))sym;
+ }
+
+ if (v == SCF_DECORATE_CLEAR) {
+ (void) pthread_mutex_lock(&handle->rh_lock);
+ handle->rh_doorpath[0] = 0;
+ (void) pthread_mutex_unlock(&handle->rh_lock);
+
+ return (0);
+ }
+
+ if ((len = scf_value_get_astring(v, zone, sizeof (zone))) < 0)
+ return (-1);
+
+ if (len == 0 || len >= sizeof (zone))
+ return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
+
+ if (zone_get_rootpath(zone, root, sizeof (root)) != Z_OK) {
+ if (strcmp(zone, GLOBAL_ZONENAME) == 0) {
+ root[0] = '\0';
+ } else {
+ return (scf_set_error(SCF_ERROR_NOT_FOUND));
+ }
+ }
+
+ if (snprintf(door, sizeof (door), "%s/%s", root,
+ default_door_path) >= sizeof (door))
+ return (scf_set_error(SCF_ERROR_INTERNAL));
+
+ (void) pthread_mutex_lock(&handle->rh_lock);
+ (void) strlcpy(handle->rh_doorpath, door,
+ sizeof (handle->rh_doorpath));
+ (void) pthread_mutex_unlock(&handle->rh_lock);
+
+ return (0);
+ }
+
return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
}