diff options
-rw-r--r-- | usr/src/cmd/svc/svcs/explain.c | 13 | ||||
-rw-r--r-- | usr/src/cmd/svc/svcs/svcs.c | 284 | ||||
-rw-r--r-- | usr/src/lib/libscf/common/lowlevel.c | 64 |
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)); } |