/* * 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 * or http://www.opensolaris.org/os/licensing. * 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 #include #include #include #include #include #include #include #include #include #include #include #ifndef TEXT_DOMAIN #define TEXT_DOMAIN "SUNW_OST_OSCMD" #endif /* TEXT_DOMAIN */ /* * Error functions. These can change if the quiet (-q) option is used. */ static void (*warn)(const char *, ...) = uu_warn; static __NORETURN void (*die)(const char *, ...) = uu_die; /* * Entity encapsulation. This allows me to treat services and instances * similarly, and avoid duplicating process_ent(). */ typedef struct { char type; /* !=0: service, 0: instance */ union { scf_service_t *svc; scf_instance_t *inst; } u; } scf_entityp_t; #define ENT_INSTANCE 0 #define SCF_ENTITY_SET_TO_SERVICE(ent, s) { ent.type = 1; ent.u.svc = s; } #define SCF_ENTITY_SET_TO_INSTANCE(ent, i) \ { ent.type = ENT_INSTANCE; ent.u.inst = i; } #define scf_entity_get_pg(ent, name, pg) \ (ent.type ? scf_service_get_pg(ent.u.svc, name, pg) : \ scf_instance_get_pg(ent.u.inst, name, pg)) #define scf_entity_to_fmri(ent, buf, buf_sz) \ (ent.type ? scf_service_to_fmri(ent.u.svc, buf, buf_sz) : \ scf_instance_to_fmri(ent.u.inst, buf, buf_sz)) #define SCF_ENTITY_TYPE_NAME(ent) (ent.type ? "service" : "instance") /* * Data structure for -p arguments. Since they may be name or name/name, we * just track the components. */ typedef struct svcprop_prop_node { uu_list_node_t spn_list_node; const char *spn_comp1; const char *spn_comp2; } svcprop_prop_node_t; static uu_list_pool_t *prop_pool; static uu_list_t *prop_list; static scf_handle_t *hndl; static ssize_t max_scf_name_length; static ssize_t max_scf_value_length; static ssize_t max_scf_fmri_length; /* Options */ static int quiet = 0; /* No output. Nothing found, exit(1) */ static int types = 0; /* Display types of properties. */ static int verbose = 0; /* Print not found errors to stderr. */ static int fmris = 0; /* Display full FMRIs for properties. */ static int wait = 0; /* Wait mode. */ static char *snapshot = "running"; /* Snapshot to use. */ static int Cflag = 0; /* C option supplied */ static int cflag = 0; /* c option supplied */ static int sflag = 0; /* s option supplied */ static int return_code; /* main's return code */ #define PRINT_NOPROP_ERRORS (!quiet || verbose) /* * For unexpected libscf errors. The ending newline is necessary to keep * uu_die() from appending the errno error. */ static void scfdie(void) { die(gettext("Unexpected libscf error: %s. Exiting.\n"), scf_strerror(scf_error())); } static void * safe_malloc(size_t sz) { void *p; p = malloc(sz); if (p == NULL) die(gettext("Could not allocate memory")); return (p); } static void usage(void) { (void) fprintf(stderr, gettext("Usage: %1$s [-fqtv] " "[-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()); exit(UU_EXIT_USAGE); } /* * Return an allocated copy of str, with the Bourne shell's metacharacters * escaped by '\'. * * What about unicode? */ static char * quote_for_shell(const char *str) { const char *sp; char *dst, *dp; size_t dst_len; const char * const metachars = ";&()|^<>\n \t\\\"\'`"; if (str[0] == '\0') return (strdup("\"\"")); dst_len = 0; for (sp = str; *sp != '\0'; ++sp) { ++dst_len; if (strchr(metachars, *sp) != NULL) ++dst_len; } if (sp - str == dst_len) return (strdup(str)); dst = safe_malloc(dst_len + 1); for (dp = dst, sp = str; *sp != '\0'; ++dp, ++sp) { if (strchr(metachars, *sp) != NULL) *dp++ = '\\'; *dp = *sp; } *dp = '\0'; return (dst); } static void print_value(scf_value_t *val) { char *buf, *qbuf; ssize_t bufsz, r; bufsz = scf_value_get_as_string(val, NULL, 0) + 1; if (bufsz - 1 < 0) scfdie(); buf = safe_malloc(bufsz); r = scf_value_get_as_string(val, buf, bufsz); assert(r + 1 == bufsz); qbuf = quote_for_shell(buf); (void) fputs(qbuf, stdout); free(qbuf); free(buf); } /* * Display a property's values on a line. If types is true, prepend * identification (the FMRI if fmris is true, pg/prop otherwise) and the type * of the property. */ static void display_prop(scf_propertygroup_t *pg, scf_property_t *prop) { scf_value_t *val; scf_iter_t *iter; int ret, first, err; const char * const permission_denied_emsg = gettext("Permission denied.\n"); if (types) { scf_type_t ty; char *buf; size_t buf_sz; if (fmris) { buf_sz = max_scf_fmri_length + 1; buf = safe_malloc(buf_sz); if (scf_property_to_fmri(prop, buf, buf_sz) == -1) scfdie(); (void) fputs(buf, stdout); free(buf); } else { buf_sz = max_scf_name_length + 1; buf = safe_malloc(buf_sz); if (scf_pg_get_name(pg, buf, buf_sz) < 0) scfdie(); (void) fputs(buf, stdout); (void) putchar('/'); if (scf_property_get_name(prop, buf, buf_sz) < 0) scfdie(); (void) fputs(buf, stdout); free(buf); } (void) putchar(' '); if (scf_property_type(prop, &ty) == -1) scfdie(); (void) fputs(scf_type_to_string(ty), stdout); (void) putchar(' '); } if ((iter = scf_iter_create(hndl)) == NULL || (val = scf_value_create(hndl)) == NULL) scfdie(); if (scf_iter_property_values(iter, prop) == -1) scfdie(); first = 1; while ((ret = scf_iter_next_value(iter, val)) == 1) { if (first) first = 0; else (void) putchar(' '); print_value(val); } if (ret == -1) { err = scf_error(); if (err == SCF_ERROR_PERMISSION_DENIED) { if (uu_list_numnodes(prop_list) > 0) die(permission_denied_emsg); } else { scfdie(); } } (void) putchar('\n'); scf_iter_destroy(iter); (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 display_pg(scf_propertygroup_t *pg) { scf_property_t *prop; scf_iter_t *iter; int ret; types = 1; /* Always display types for whole propertygroups. */ if ((prop = scf_property_create(hndl)) == NULL || (iter = scf_iter_create(hndl)) == NULL) scfdie(); if (scf_iter_pg_properties(iter, pg) == -1) scfdie(); while ((ret = scf_iter_next_property(iter, prop)) == 1) display_prop(pg, prop); if (ret == -1) scfdie(); scf_iter_destroy(iter); scf_property_destroy(prop); } /* * Common code to execute when a nonexistant property is encountered. */ static void noprop_common_action() { if (!PRINT_NOPROP_ERRORS) /* We're not printing errors, so we can cut out early. */ exit(UU_EXIT_FATAL); return_code = UU_EXIT_FATAL; } /* * Iterate the properties of a service or an instance when no snapshot * is specified. */ static int scf_iter_entity_pgs(scf_iter_t *iter, scf_entityp_t ent) { int ret = 0; if (ent.type) { /* * 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) die(gettext("Only instances have " "snapshots.\n")); ret = scf_iter_service_pgs(iter, ent.u.svc); } else { if (Cflag) ret = scf_iter_instance_pgs(iter, ent.u.inst); else ret = scf_iter_instance_pgs_composed(iter, ent.u.inst, NULL); } return (ret); } /* * Return a snapshot for the supplied instance and snapshot name. */ static scf_snapshot_t * get_snapshot(const scf_instance_t *inst, const char *snapshot) { scf_snapshot_t *snap = scf_snapshot_create(hndl); if (snap == NULL) scfdie(); if (scf_instance_get_snapshot(inst, snapshot, snap) == -1) { switch (scf_error()) { case SCF_ERROR_INVALID_ARGUMENT: die(gettext("Invalid snapshot name.\n")); /* NOTREACHED */ case SCF_ERROR_NOT_FOUND: if (sflag == 0) { scf_snapshot_destroy(snap); snap = NULL; } else die(gettext("No such snapshot.\n")); break; default: scfdie(); } } return (snap); } /* * Entity (service or instance): If there are -p options, * display_{pg,prop}() the named property groups and/or properties. Otherwise * display_pg() all property groups. */ static void process_ent(scf_entityp_t ent) { scf_snapshot_t *snap = NULL; scf_propertygroup_t *pg; scf_property_t *prop; scf_iter_t *iter; svcprop_prop_node_t *spn; int ret, err; if (uu_list_numnodes(prop_list) == 0) { if (quiet) return; if ((pg = scf_pg_create(hndl)) == NULL || (iter = scf_iter_create(hndl)) == NULL) scfdie(); if (cflag || Cflag || ent.type != ENT_INSTANCE) { if (scf_iter_entity_pgs(iter, ent) == -1) scfdie(); } else { if (snapshot != NULL) snap = get_snapshot(ent.u.inst, snapshot); if (scf_iter_instance_pgs_composed(iter, ent.u.inst, snap) == -1) scfdie(); if (snap) scf_snapshot_destroy(snap); } while ((ret = scf_iter_next_pg(iter, pg)) == 1) 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. */ if (sflag == 0 && snap != NULL) { scf_iter_reset(iter); if (scf_iter_instance_pgs_composed(iter, ent.u.inst, NULL) == -1) scfdie(); while ((ret = scf_iter_next_pg(iter, pg)) == 1) { uint32_t flags; if (scf_pg_get_flags(pg, &flags) == -1) scfdie(); if (flags & SCF_PG_FLAG_NONPERSISTENT) display_pg(pg); } } if (ret == -1) scfdie(); scf_iter_destroy(iter); scf_pg_destroy(pg); return; } if ((pg = scf_pg_create(hndl)) == NULL || (prop = scf_property_create(hndl)) == NULL) scfdie(); if (ent.type == ENT_INSTANCE && snapshot != NULL) snap = get_snapshot(ent.u.inst, snapshot); for (spn = uu_list_first(prop_list); spn != NULL; spn = uu_list_next(prop_list, spn)) { if (ent.type == ENT_INSTANCE) { if (Cflag) ret = scf_instance_get_pg(ent.u.inst, spn->spn_comp1, pg); else ret = scf_instance_get_pg_composed(ent.u.inst, snap, spn->spn_comp1, pg); err = scf_error(); /* * If we didn't find it in the specified snapshot, use * the current values if the pg is nonpersistent. */ if (ret == -1 && !Cflag &&snap != NULL && err == SCF_ERROR_NOT_FOUND) { ret = scf_instance_get_pg_composed( ent.u.inst, NULL, spn->spn_comp1, pg); if (ret == 0) { uint32_t flags; if (scf_pg_get_flags(pg, &flags) == -1) 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) die(gettext("Only instances have " "snapshots.\n")); ret = scf_entity_get_pg(ent, spn->spn_comp1, pg); err = scf_error(); } if (ret == -1) { if (err != SCF_ERROR_NOT_FOUND) scfdie(); if (PRINT_NOPROP_ERRORS) { char *buf; buf = safe_malloc(max_scf_fmri_length + 1); if (scf_entity_to_fmri(ent, buf, max_scf_fmri_length + 1) == -1) scfdie(); uu_warn(gettext("Couldn't find property group " "`%s' for %s `%s'.\n"), spn->spn_comp1, SCF_ENTITY_TYPE_NAME(ent), buf); free(buf); } noprop_common_action(); continue; } if (spn->spn_comp2 == NULL) { if (!quiet) display_pg(pg); continue; } if (scf_pg_get_property(pg, spn->spn_comp2, prop) == -1) { if (scf_error() != SCF_ERROR_NOT_FOUND) scfdie(); if (PRINT_NOPROP_ERRORS) { char *buf; buf = safe_malloc(max_scf_fmri_length + 1); if (scf_entity_to_fmri(ent, buf, max_scf_fmri_length + 1) == -1) scfdie(); /* FMRI syntax knowledge */ uu_warn(gettext("Couldn't find property " "`%s/%s' for %s `%s'.\n"), spn->spn_comp1, spn->spn_comp2, SCF_ENTITY_TYPE_NAME(ent), buf); free(buf); } noprop_common_action(); continue; } if (!quiet) display_prop(pg, prop); } scf_property_destroy(prop); scf_pg_destroy(pg); if (snap) scf_snapshot_destroy(snap); } /* * Without -p options, just call display_pg(). Otherwise display_prop() the * named properties of the property group. */ static void process_pg(scf_propertygroup_t *pg) { scf_property_t *prop; svcprop_prop_node_t *spn; if (uu_list_first(prop_list) == NULL) { if (quiet) return; display_pg(pg); return; } prop = scf_property_create(hndl); if (prop == NULL) scfdie(); for (spn = uu_list_first(prop_list); spn != NULL; spn = uu_list_next(prop_list, spn)) { if (spn->spn_comp2 != NULL) { char *buf; buf = safe_malloc(max_scf_fmri_length + 1); if (scf_pg_to_fmri(pg, buf, max_scf_fmri_length + 1) == -1) scfdie(); uu_xdie(UU_EXIT_USAGE, gettext("-p argument `%s/%s' " "has too many components for property " "group `%s'.\n"), spn->spn_comp1, spn->spn_comp2, buf); free(buf); } if (scf_pg_get_property(pg, spn->spn_comp1, prop) == 0) { if (!quiet) display_prop(pg, prop); continue; } if (scf_error() != SCF_ERROR_NOT_FOUND) scfdie(); if (PRINT_NOPROP_ERRORS) { char *buf; buf = safe_malloc(max_scf_fmri_length + 1); if (scf_pg_to_fmri(pg, buf, max_scf_fmri_length + 1) == -1) scfdie(); uu_warn(gettext("Couldn't find property `%s' in " "property group `%s'.\n"), spn->spn_comp1, buf); free(buf); } noprop_common_action(); } } /* * If there are -p options, show the error. Otherwise just call * display_prop(). */ static void process_prop(scf_propertygroup_t *pg, scf_property_t *prop) { if (uu_list_first(prop_list) != NULL) { uu_warn(gettext("The -p option cannot be used with property " "operands.\n")); usage(); } if (quiet) return; display_prop(pg, prop); } /* Decode an operand & dispatch. */ /* ARGSUSED */ static int process_fmri(void *unused, scf_walkinfo_t *wip) { scf_entityp_t ent; /* Multiple matches imply multiple entities. */ if (wip->count > 1) types = fmris = 1; if (wip->prop != NULL) { process_prop(wip->pg, wip->prop); } else if (wip->pg != NULL) { process_pg(wip->pg); } else if (wip->inst != NULL) { SCF_ENTITY_SET_TO_INSTANCE(ent, wip->inst); process_ent(ent); } else { /* scf_walk_fmri() won't let this happen */ assert(wip->svc != NULL); SCF_ENTITY_SET_TO_SERVICE(ent, wip->svc); process_ent(ent); } return (0); } static void add_prop(char *property) { svcprop_prop_node_t *p, *last; char *slash; const char * const invalid_component_emsg = gettext("Invalid component name `%s'.\n"); /* FMRI syntax knowledge. */ slash = strchr(property, '/'); if (slash != NULL) { if (strchr(slash + 1, '/') != NULL) { uu_warn(gettext("-p argument `%s' has too many " "components.\n"), property); usage(); } } if (slash != NULL) *slash = '\0'; p = safe_malloc(sizeof (svcprop_prop_node_t)); uu_list_node_init(p, &p->spn_list_node, prop_pool); p->spn_comp1 = property; p->spn_comp2 = (slash == NULL) ? NULL : slash + 1; if (uu_check_name(p->spn_comp1, UU_NAME_DOMAIN) == -1) uu_xdie(UU_EXIT_USAGE, invalid_component_emsg, p->spn_comp1); if (p->spn_comp2 != NULL && uu_check_name(p->spn_comp2, UU_NAME_DOMAIN) == -1) uu_xdie(UU_EXIT_USAGE, invalid_component_emsg, p->spn_comp2); last = uu_list_last(prop_list); if (last != NULL) { if ((last->spn_comp2 == NULL) ^ (p->spn_comp2 == NULL)) { /* * 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; } } (void) uu_list_insert_after(prop_list, NULL, p); } /* * 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 do_wait(void *unused, scf_walkinfo_t *wip) { scf_property_t *prop; scf_propertygroup_t *lpg, *pg; const char *propname; svcprop_prop_node_t *p; const char *emsg_not_found = gettext("Not found.\n"); if ((lpg = scf_pg_create(hndl)) == NULL || (prop = scf_property_create(hndl)) == NULL) scfdie(); if (wip->prop != NULL) { if (uu_list_numnodes(prop_list) > 0) uu_xdie(UU_EXIT_USAGE, gettext("-p cannot be used with " "property FMRIs.\n")); pg = wip->pg; assert(strrchr(wip->fmri, '/') != NULL); propname = strrchr(wip->fmri, '/') + 1; } else if (wip->pg != NULL) { p = uu_list_first(prop_list); if (p != NULL) { if (p->spn_comp2 != NULL) uu_xdie(UU_EXIT_USAGE, gettext("-p argument " "\"%s/%s\" has too many components for " "property group %s.\n"), p->spn_comp1, p->spn_comp2, wip->fmri); propname = p->spn_comp1; if (scf_pg_get_property(wip->pg, propname, prop) != SCF_SUCCESS) { switch (scf_error()) { case SCF_ERROR_INVALID_ARGUMENT: uu_xdie(UU_EXIT_USAGE, gettext("Invalid property name " "\"%s\".\n"), propname); /* NOTREACHED */ case SCF_ERROR_NOT_FOUND: die(emsg_not_found); default: scfdie(); } } } else { propname = NULL; } pg = wip->pg; } else if (wip->inst != NULL) { p = uu_list_first(prop_list); if (p == NULL) uu_xdie(UU_EXIT_USAGE, gettext("Cannot wait for an instance.\n")); if (scf_instance_get_pg(wip->inst, p->spn_comp1, lpg) != SCF_SUCCESS) { switch (scf_error()) { case SCF_ERROR_INVALID_ARGUMENT: uu_xdie(UU_EXIT_USAGE, gettext("Invalid " "property group name \"%s\".\n"), p->spn_comp1); /* NOTREACHED */ case SCF_ERROR_NOT_FOUND: die(emsg_not_found); default: scfdie(); } } propname = p->spn_comp2; if (propname != NULL) { if (scf_pg_get_property(lpg, propname, prop) != SCF_SUCCESS) { switch (scf_error()) { case SCF_ERROR_INVALID_ARGUMENT: uu_xdie(UU_EXIT_USAGE, gettext("Invalid property name " "\"%s\".\n"), propname); /* NOTREACHED */ case SCF_ERROR_NOT_FOUND: die(emsg_not_found); default: scfdie(); } } } pg = lpg; } else if (wip->svc != NULL) { p = uu_list_first(prop_list); if (p == NULL) uu_xdie(UU_EXIT_USAGE, gettext("Cannot wait for a service.\n")); if (scf_service_get_pg(wip->svc, p->spn_comp1, lpg) != SCF_SUCCESS) { switch (scf_error()) { case SCF_ERROR_INVALID_ARGUMENT: uu_xdie(UU_EXIT_USAGE, gettext("Invalid " "property group name \"%s\".\n"), p->spn_comp1); /* NOTREACHED */ case SCF_ERROR_NOT_FOUND: die(emsg_not_found); default: scfdie(); } } propname = p->spn_comp2; if (propname != NULL) { if (scf_pg_get_property(lpg, propname, prop) != SCF_SUCCESS) { switch (scf_error()) { case SCF_ERROR_INVALID_ARGUMENT: uu_xdie(UU_EXIT_USAGE, gettext("Invalid property name " "\"%s\".\n"), propname); /* NOTREACHED */ case SCF_ERROR_NOT_FOUND: die(emsg_not_found); default: scfdie(); } } } pg = lpg; } else { uu_xdie(UU_EXIT_USAGE, gettext("FMRI must specify an entity, " "property group, or property.\n")); } for (;;) { int ret; ret = _scf_pg_wait(pg, -1); if (ret != SCF_SUCCESS) scfdie(); ret = scf_pg_update(pg); if (ret < 0) { if (scf_error() != SCF_ERROR_DELETED) scfdie(); die(emsg_not_found); } if (ret == SCF_COMPLETE) break; } if (propname != NULL) { if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS) { if (!quiet) display_prop(pg, prop); } else { if (scf_error() != SCF_ERROR_NOT_FOUND) scfdie(); if (PRINT_NOPROP_ERRORS) uu_warn(emsg_not_found); return_code = UU_EXIT_FATAL; } } else { if (!quiet) display_pg(pg); } scf_property_destroy(prop); scf_pg_destroy(lpg); 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 quiet_warn(const char *fmt, ...) { /* Do nothing */ } /*ARGSUSED*/ static __NORETURN void quiet_die(const char *fmt, ...) { exit(UU_EXIT_FATAL); } int main(int argc, char *argv[]) { int c; scf_walk_callback callback; int flags; int err; (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); return_code = UU_EXIT_OK; (void) uu_setpname(argv[0]); prop_pool = uu_list_pool_create("properties", sizeof (svcprop_prop_node_t), offsetof(svcprop_prop_node_t, spn_list_node), NULL, 0); if (prop_pool == NULL) uu_die("%s\n", uu_strerror(uu_error())); prop_list = uu_list_create(prop_pool, NULL, 0); hndl = scf_handle_create(SCF_VERSION); if (hndl == NULL) scfdie(); while ((c = getopt(argc, argv, "Ccfp:qs:tvwz:")) != -1) { switch (c) { case 'C': if (cflag || sflag || wait) usage(); /* Not with -c, -s or -w */ Cflag++; snapshot = NULL; break; case 'c': if (Cflag || sflag || wait) usage(); /* Not with -C, -s or -w */ cflag++; snapshot = NULL; break; case 'f': types = 1; fmris = 1; break; case 'p': add_prop(optarg); break; case 'q': quiet = 1; warn = quiet_warn; die = quiet_die; break; case 's': if (Cflag || cflag || wait) usage(); /* Not with -C, -c or -w */ snapshot = optarg; sflag++; break; case 't': types = 1; break; case 'v': verbose = 1; break; case 'w': if (Cflag || cflag || sflag) usage(); /* Not with -C, -c or -s */ wait = 1; break; case 'z': { scf_value_t *zone; scf_handle_t *h = hndl; if (getzoneid() != GLOBAL_ZONEID) uu_die(gettext("svcprop -z may only be used " "from the global zone\n")); if ((zone = scf_value_create(h)) == NULL) scfdie(); if (scf_value_set_astring(zone, optarg) != SCF_SUCCESS) scfdie(); if (scf_handle_decorate(h, "zone", zone) != SCF_SUCCESS) uu_die(gettext("invalid zone '%s'\n"), optarg); scf_value_destroy(zone); break; } case '?': switch (optopt) { case 'p': usage(); default: break; } /* FALLTHROUGH */ default: usage(); } } if (optind == argc) usage(); max_scf_name_length = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH); max_scf_value_length = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); max_scf_fmri_length = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH); if (max_scf_name_length == -1 || max_scf_value_length == -1 || max_scf_fmri_length == -1) scfdie(); if (scf_handle_bind(hndl) == -1) die(gettext("Could not connect to configuration repository: " "%s.\n"), scf_strerror(scf_error())); flags = SCF_WALK_PROPERTY | SCF_WALK_SERVICE | SCF_WALK_EXPLICIT; if (wait) { if (uu_list_numnodes(prop_list) > 1) usage(); if (argc - optind > 1) usage(); callback = do_wait; } else { callback = process_fmri; flags |= SCF_WALK_MULTIPLE; } if ((err = scf_walk_fmri(hndl, argc - optind, argv + optind, flags, callback, NULL, &return_code, warn)) != 0) { warn(gettext("failed to iterate over instances: %s\n"), scf_strerror(err)); return_code = UU_EXIT_FATAL; } scf_handle_destroy(hndl); return (return_code); }