1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <assert.h> 30*7c478bd9Sstevel@tonic-gate #include <libscf.h> 31*7c478bd9Sstevel@tonic-gate #include <libscf_priv.h> 32*7c478bd9Sstevel@tonic-gate #include <libuutil.h> 33*7c478bd9Sstevel@tonic-gate #include <stdio.h> 34*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 35*7c478bd9Sstevel@tonic-gate #include <strings.h> 36*7c478bd9Sstevel@tonic-gate #include <errno.h> 37*7c478bd9Sstevel@tonic-gate 38*7c478bd9Sstevel@tonic-gate #include "startd.h" 39*7c478bd9Sstevel@tonic-gate 40*7c478bd9Sstevel@tonic-gate /* 41*7c478bd9Sstevel@tonic-gate * Return an allocated copy of str, with the Bourne shell's metacharacters 42*7c478bd9Sstevel@tonic-gate * escaped by '\'. Returns NULL on (allocation) failure. 43*7c478bd9Sstevel@tonic-gate */ 44*7c478bd9Sstevel@tonic-gate static char * 45*7c478bd9Sstevel@tonic-gate quote_for_shell(const char *str) 46*7c478bd9Sstevel@tonic-gate { 47*7c478bd9Sstevel@tonic-gate const char *sp; 48*7c478bd9Sstevel@tonic-gate char *dst, *dp; 49*7c478bd9Sstevel@tonic-gate size_t dst_len; 50*7c478bd9Sstevel@tonic-gate 51*7c478bd9Sstevel@tonic-gate const char * const metachars = ";&()|^<>\n \t\\\"\'`"; 52*7c478bd9Sstevel@tonic-gate 53*7c478bd9Sstevel@tonic-gate dst_len = 0; 54*7c478bd9Sstevel@tonic-gate for (sp = str; *sp != '\0'; ++sp) { 55*7c478bd9Sstevel@tonic-gate ++dst_len; 56*7c478bd9Sstevel@tonic-gate 57*7c478bd9Sstevel@tonic-gate if (strchr(metachars, *sp) != NULL) 58*7c478bd9Sstevel@tonic-gate ++dst_len; 59*7c478bd9Sstevel@tonic-gate } 60*7c478bd9Sstevel@tonic-gate 61*7c478bd9Sstevel@tonic-gate if (sp - str == dst_len) 62*7c478bd9Sstevel@tonic-gate return (safe_strdup(str)); 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate dst = malloc(dst_len + 1); 65*7c478bd9Sstevel@tonic-gate if (dst == NULL) 66*7c478bd9Sstevel@tonic-gate return (NULL); 67*7c478bd9Sstevel@tonic-gate 68*7c478bd9Sstevel@tonic-gate for (dp = dst, sp = str; *sp != '\0'; ++dp, ++sp) { 69*7c478bd9Sstevel@tonic-gate if (strchr(metachars, *sp) != NULL) 70*7c478bd9Sstevel@tonic-gate *dp++ = '\\'; 71*7c478bd9Sstevel@tonic-gate 72*7c478bd9Sstevel@tonic-gate *dp = *sp; 73*7c478bd9Sstevel@tonic-gate } 74*7c478bd9Sstevel@tonic-gate *dp = '\0'; 75*7c478bd9Sstevel@tonic-gate 76*7c478bd9Sstevel@tonic-gate return (dst); 77*7c478bd9Sstevel@tonic-gate } 78*7c478bd9Sstevel@tonic-gate 79*7c478bd9Sstevel@tonic-gate /* 80*7c478bd9Sstevel@tonic-gate * Return an allocated string representation of the value v. 81*7c478bd9Sstevel@tonic-gate * Return NULL on error. 82*7c478bd9Sstevel@tonic-gate */ 83*7c478bd9Sstevel@tonic-gate static char * 84*7c478bd9Sstevel@tonic-gate val_to_str(scf_value_t *v) 85*7c478bd9Sstevel@tonic-gate { 86*7c478bd9Sstevel@tonic-gate char *buf; 87*7c478bd9Sstevel@tonic-gate ssize_t buflen, ret; 88*7c478bd9Sstevel@tonic-gate 89*7c478bd9Sstevel@tonic-gate buflen = scf_value_get_as_string(v, NULL, 0); 90*7c478bd9Sstevel@tonic-gate assert(buflen >= 0); 91*7c478bd9Sstevel@tonic-gate 92*7c478bd9Sstevel@tonic-gate buf = malloc(buflen + 1); 93*7c478bd9Sstevel@tonic-gate if (buf == NULL) 94*7c478bd9Sstevel@tonic-gate return (NULL); 95*7c478bd9Sstevel@tonic-gate 96*7c478bd9Sstevel@tonic-gate ret = scf_value_get_as_string(v, buf, buflen + 1); 97*7c478bd9Sstevel@tonic-gate assert(ret == buflen); 98*7c478bd9Sstevel@tonic-gate 99*7c478bd9Sstevel@tonic-gate return (buf); 100*7c478bd9Sstevel@tonic-gate } 101*7c478bd9Sstevel@tonic-gate 102*7c478bd9Sstevel@tonic-gate /* 103*7c478bd9Sstevel@tonic-gate * Look up a property in the given snapshot, or the editing one 104*7c478bd9Sstevel@tonic-gate * if not found. Returns scf_error() on failure, or 0 otherwise. 105*7c478bd9Sstevel@tonic-gate */ 106*7c478bd9Sstevel@tonic-gate static int 107*7c478bd9Sstevel@tonic-gate get_prop(const scf_instance_t *inst, scf_snapshot_t *snap, 108*7c478bd9Sstevel@tonic-gate const char *pgn, const char *pn, scf_propertygroup_t *pg, 109*7c478bd9Sstevel@tonic-gate scf_property_t *prop) 110*7c478bd9Sstevel@tonic-gate { 111*7c478bd9Sstevel@tonic-gate int ret; 112*7c478bd9Sstevel@tonic-gate 113*7c478bd9Sstevel@tonic-gate ret = scf_instance_get_pg_composed(inst, snap, pgn, pg); 114*7c478bd9Sstevel@tonic-gate if (ret != 0) { 115*7c478bd9Sstevel@tonic-gate snap = NULL; 116*7c478bd9Sstevel@tonic-gate if (scf_error() == SCF_ERROR_NOT_FOUND) 117*7c478bd9Sstevel@tonic-gate ret = scf_instance_get_pg_composed(inst, snap, pgn, pg); 118*7c478bd9Sstevel@tonic-gate if (ret != 0) 119*7c478bd9Sstevel@tonic-gate return (scf_error()); 120*7c478bd9Sstevel@tonic-gate } 121*7c478bd9Sstevel@tonic-gate 122*7c478bd9Sstevel@tonic-gate if (scf_pg_get_property(pg, pn, prop) == 0) 123*7c478bd9Sstevel@tonic-gate return (0); 124*7c478bd9Sstevel@tonic-gate 125*7c478bd9Sstevel@tonic-gate if (snap == NULL) 126*7c478bd9Sstevel@tonic-gate return (scf_error()); 127*7c478bd9Sstevel@tonic-gate 128*7c478bd9Sstevel@tonic-gate ret = scf_instance_get_pg_composed(inst, NULL, pgn, pg); 129*7c478bd9Sstevel@tonic-gate if (ret != 0) 130*7c478bd9Sstevel@tonic-gate return (scf_error()); 131*7c478bd9Sstevel@tonic-gate 132*7c478bd9Sstevel@tonic-gate if (scf_pg_get_property(pg, pn, prop) == 0) 133*7c478bd9Sstevel@tonic-gate return (0); 134*7c478bd9Sstevel@tonic-gate 135*7c478bd9Sstevel@tonic-gate return (scf_error()); 136*7c478bd9Sstevel@tonic-gate } 137*7c478bd9Sstevel@tonic-gate 138*7c478bd9Sstevel@tonic-gate /* 139*7c478bd9Sstevel@tonic-gate * Get an allocated string representation of the values of the property 140*7c478bd9Sstevel@tonic-gate * specified by inst & prop_spec and store it in *retstr. prop_spec may 141*7c478bd9Sstevel@tonic-gate * be a full property FMRI, or a "property-group/property" pair relative 142*7c478bd9Sstevel@tonic-gate * to inst, or the name of a property in inst's "application" property 143*7c478bd9Sstevel@tonic-gate * group. In the latter two cases, the property is looked up in inst's 144*7c478bd9Sstevel@tonic-gate * snap snapshot. In the first case, the target instance's running 145*7c478bd9Sstevel@tonic-gate * snapshot will be used. In any case, if the property or its group 146*7c478bd9Sstevel@tonic-gate * can't be found, the "editing" snapshot will be checked. Multiple 147*7c478bd9Sstevel@tonic-gate * values will be separated by sep. 148*7c478bd9Sstevel@tonic-gate * 149*7c478bd9Sstevel@tonic-gate * On error, non-zero is returned, and *retstr is set to an error 150*7c478bd9Sstevel@tonic-gate * string. 151*7c478bd9Sstevel@tonic-gate * 152*7c478bd9Sstevel@tonic-gate * *retstr should always be freed by the caller. 153*7c478bd9Sstevel@tonic-gate */ 154*7c478bd9Sstevel@tonic-gate static int 155*7c478bd9Sstevel@tonic-gate get_prop_val_str(const scf_instance_t *inst, scf_snapshot_t *snap, 156*7c478bd9Sstevel@tonic-gate const char *prop_spec, char sep, char **retstr) 157*7c478bd9Sstevel@tonic-gate { 158*7c478bd9Sstevel@tonic-gate scf_handle_t *h = scf_instance_handle(inst); 159*7c478bd9Sstevel@tonic-gate scf_scope_t *scope = NULL; 160*7c478bd9Sstevel@tonic-gate scf_service_t *svc = NULL; 161*7c478bd9Sstevel@tonic-gate scf_instance_t *tmpinst = NULL; 162*7c478bd9Sstevel@tonic-gate scf_snapshot_t *tmpsnap = NULL; 163*7c478bd9Sstevel@tonic-gate scf_propertygroup_t *pg = NULL; 164*7c478bd9Sstevel@tonic-gate scf_iter_t *iter = NULL; 165*7c478bd9Sstevel@tonic-gate scf_property_t *prop = NULL; 166*7c478bd9Sstevel@tonic-gate scf_value_t *val = NULL; 167*7c478bd9Sstevel@tonic-gate char *spec; 168*7c478bd9Sstevel@tonic-gate char *str, *qstr; 169*7c478bd9Sstevel@tonic-gate size_t strl; 170*7c478bd9Sstevel@tonic-gate int ret; 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate spec = safe_strdup(prop_spec); 173*7c478bd9Sstevel@tonic-gate 174*7c478bd9Sstevel@tonic-gate if (strstr(spec, ":properties") != NULL) { 175*7c478bd9Sstevel@tonic-gate const char *scn, *sn, *in, *pgn, *pn; 176*7c478bd9Sstevel@tonic-gate 177*7c478bd9Sstevel@tonic-gate if (scf_parse_svc_fmri(spec, &scn, &sn, &in, &pgn, 178*7c478bd9Sstevel@tonic-gate &pn) != 0) 179*7c478bd9Sstevel@tonic-gate goto scferr; 180*7c478bd9Sstevel@tonic-gate 181*7c478bd9Sstevel@tonic-gate if (sn == NULL || pgn == NULL || pn == NULL) { 182*7c478bd9Sstevel@tonic-gate free(spec); 183*7c478bd9Sstevel@tonic-gate *retstr = safe_strdup("parse error"); 184*7c478bd9Sstevel@tonic-gate return (-1); 185*7c478bd9Sstevel@tonic-gate } 186*7c478bd9Sstevel@tonic-gate 187*7c478bd9Sstevel@tonic-gate if ((scope = scf_scope_create(h)) == NULL || 188*7c478bd9Sstevel@tonic-gate (svc = scf_service_create(h)) == NULL || 189*7c478bd9Sstevel@tonic-gate (pg = scf_pg_create(h)) == NULL || 190*7c478bd9Sstevel@tonic-gate (prop = scf_property_create(h)) == NULL) 191*7c478bd9Sstevel@tonic-gate goto scferr; 192*7c478bd9Sstevel@tonic-gate 193*7c478bd9Sstevel@tonic-gate if (scf_handle_get_scope(h, scn == NULL ? SCF_SCOPE_LOCAL : scn, 194*7c478bd9Sstevel@tonic-gate scope) != 0) 195*7c478bd9Sstevel@tonic-gate goto properr; 196*7c478bd9Sstevel@tonic-gate 197*7c478bd9Sstevel@tonic-gate if (scf_scope_get_service(scope, sn, svc) != 0) 198*7c478bd9Sstevel@tonic-gate goto properr; 199*7c478bd9Sstevel@tonic-gate 200*7c478bd9Sstevel@tonic-gate if (in == NULL) { 201*7c478bd9Sstevel@tonic-gate if (scf_service_get_pg(svc, pgn, pg) != 0) 202*7c478bd9Sstevel@tonic-gate goto properr; 203*7c478bd9Sstevel@tonic-gate if (scf_pg_get_property(pg, pn, prop) != 0) 204*7c478bd9Sstevel@tonic-gate goto properr; 205*7c478bd9Sstevel@tonic-gate } else { 206*7c478bd9Sstevel@tonic-gate if ((tmpinst = scf_instance_create(h)) == NULL) 207*7c478bd9Sstevel@tonic-gate goto scferr; 208*7c478bd9Sstevel@tonic-gate if (scf_service_get_instance(svc, in, tmpinst) != 0) 209*7c478bd9Sstevel@tonic-gate goto properr; 210*7c478bd9Sstevel@tonic-gate 211*7c478bd9Sstevel@tonic-gate tmpsnap = libscf_get_running_snapshot(tmpinst); 212*7c478bd9Sstevel@tonic-gate if (tmpsnap == NULL) 213*7c478bd9Sstevel@tonic-gate goto scferr; 214*7c478bd9Sstevel@tonic-gate 215*7c478bd9Sstevel@tonic-gate if (get_prop(tmpinst, tmpsnap, pgn, pn, pg, prop) != 0) 216*7c478bd9Sstevel@tonic-gate goto properr; 217*7c478bd9Sstevel@tonic-gate } 218*7c478bd9Sstevel@tonic-gate } else { 219*7c478bd9Sstevel@tonic-gate char *slash, *pgn, *pn; 220*7c478bd9Sstevel@tonic-gate 221*7c478bd9Sstevel@tonic-gate /* Try prop or pg/prop in inst. */ 222*7c478bd9Sstevel@tonic-gate 223*7c478bd9Sstevel@tonic-gate prop = scf_property_create(h); 224*7c478bd9Sstevel@tonic-gate if (prop == NULL) 225*7c478bd9Sstevel@tonic-gate goto scferr; 226*7c478bd9Sstevel@tonic-gate 227*7c478bd9Sstevel@tonic-gate pg = scf_pg_create(h); 228*7c478bd9Sstevel@tonic-gate if (pg == NULL) 229*7c478bd9Sstevel@tonic-gate goto scferr; 230*7c478bd9Sstevel@tonic-gate 231*7c478bd9Sstevel@tonic-gate slash = strchr(spec, '/'); 232*7c478bd9Sstevel@tonic-gate if (slash == NULL) { 233*7c478bd9Sstevel@tonic-gate pgn = "application"; 234*7c478bd9Sstevel@tonic-gate pn = spec; 235*7c478bd9Sstevel@tonic-gate } else { 236*7c478bd9Sstevel@tonic-gate *slash = '\0'; 237*7c478bd9Sstevel@tonic-gate pgn = spec; 238*7c478bd9Sstevel@tonic-gate pn = slash + 1; 239*7c478bd9Sstevel@tonic-gate } 240*7c478bd9Sstevel@tonic-gate 241*7c478bd9Sstevel@tonic-gate if (get_prop(inst, snap, pgn, pn, pg, prop) != 0) 242*7c478bd9Sstevel@tonic-gate goto properr; 243*7c478bd9Sstevel@tonic-gate } 244*7c478bd9Sstevel@tonic-gate 245*7c478bd9Sstevel@tonic-gate iter = scf_iter_create(h); 246*7c478bd9Sstevel@tonic-gate if (iter == NULL) 247*7c478bd9Sstevel@tonic-gate goto scferr; 248*7c478bd9Sstevel@tonic-gate 249*7c478bd9Sstevel@tonic-gate 250*7c478bd9Sstevel@tonic-gate if (scf_iter_property_values(iter, prop) == -1) 251*7c478bd9Sstevel@tonic-gate goto scferr; 252*7c478bd9Sstevel@tonic-gate 253*7c478bd9Sstevel@tonic-gate val = scf_value_create(h); 254*7c478bd9Sstevel@tonic-gate if (val == NULL) 255*7c478bd9Sstevel@tonic-gate goto scferr; 256*7c478bd9Sstevel@tonic-gate 257*7c478bd9Sstevel@tonic-gate ret = scf_iter_next_value(iter, val); 258*7c478bd9Sstevel@tonic-gate if (ret == 0) { 259*7c478bd9Sstevel@tonic-gate *retstr = safe_strdup(""); 260*7c478bd9Sstevel@tonic-gate goto out; 261*7c478bd9Sstevel@tonic-gate } else if (ret == -1) { 262*7c478bd9Sstevel@tonic-gate goto scferr; 263*7c478bd9Sstevel@tonic-gate } 264*7c478bd9Sstevel@tonic-gate 265*7c478bd9Sstevel@tonic-gate str = val_to_str(val); 266*7c478bd9Sstevel@tonic-gate if (str == NULL) 267*7c478bd9Sstevel@tonic-gate goto err; 268*7c478bd9Sstevel@tonic-gate 269*7c478bd9Sstevel@tonic-gate qstr = quote_for_shell(str); 270*7c478bd9Sstevel@tonic-gate free(str); 271*7c478bd9Sstevel@tonic-gate str = qstr; 272*7c478bd9Sstevel@tonic-gate if (qstr == NULL) 273*7c478bd9Sstevel@tonic-gate goto err; 274*7c478bd9Sstevel@tonic-gate 275*7c478bd9Sstevel@tonic-gate strl = strlen(str); 276*7c478bd9Sstevel@tonic-gate 277*7c478bd9Sstevel@tonic-gate while ((ret = scf_iter_next_value(iter, val)) == 1) { 278*7c478bd9Sstevel@tonic-gate char *nv, *qnv; 279*7c478bd9Sstevel@tonic-gate size_t nl; 280*7c478bd9Sstevel@tonic-gate void *p; 281*7c478bd9Sstevel@tonic-gate 282*7c478bd9Sstevel@tonic-gate /* Append sep & val_to_str(val) to str. */ 283*7c478bd9Sstevel@tonic-gate 284*7c478bd9Sstevel@tonic-gate nv = val_to_str(val); 285*7c478bd9Sstevel@tonic-gate if (nv == NULL) { 286*7c478bd9Sstevel@tonic-gate free(str); 287*7c478bd9Sstevel@tonic-gate goto err; 288*7c478bd9Sstevel@tonic-gate } 289*7c478bd9Sstevel@tonic-gate qnv = quote_for_shell(nv); 290*7c478bd9Sstevel@tonic-gate free(nv); 291*7c478bd9Sstevel@tonic-gate if (qnv == NULL) { 292*7c478bd9Sstevel@tonic-gate free(str); 293*7c478bd9Sstevel@tonic-gate goto err; 294*7c478bd9Sstevel@tonic-gate } 295*7c478bd9Sstevel@tonic-gate nv = qnv; 296*7c478bd9Sstevel@tonic-gate 297*7c478bd9Sstevel@tonic-gate nl = strl + 1 + strlen(nv); 298*7c478bd9Sstevel@tonic-gate p = realloc(str, nl + 1); 299*7c478bd9Sstevel@tonic-gate if (p == NULL) { 300*7c478bd9Sstevel@tonic-gate free(str); 301*7c478bd9Sstevel@tonic-gate free(nv); 302*7c478bd9Sstevel@tonic-gate goto err; 303*7c478bd9Sstevel@tonic-gate } 304*7c478bd9Sstevel@tonic-gate str = p; 305*7c478bd9Sstevel@tonic-gate 306*7c478bd9Sstevel@tonic-gate str[strl] = sep; 307*7c478bd9Sstevel@tonic-gate (void) strcpy(&str[strl + 1], nv); 308*7c478bd9Sstevel@tonic-gate 309*7c478bd9Sstevel@tonic-gate free(nv); 310*7c478bd9Sstevel@tonic-gate 311*7c478bd9Sstevel@tonic-gate strl = nl; 312*7c478bd9Sstevel@tonic-gate } 313*7c478bd9Sstevel@tonic-gate if (ret == -1) { 314*7c478bd9Sstevel@tonic-gate free(str); 315*7c478bd9Sstevel@tonic-gate goto scferr; 316*7c478bd9Sstevel@tonic-gate } 317*7c478bd9Sstevel@tonic-gate 318*7c478bd9Sstevel@tonic-gate *retstr = str; 319*7c478bd9Sstevel@tonic-gate 320*7c478bd9Sstevel@tonic-gate out: 321*7c478bd9Sstevel@tonic-gate scf_value_destroy(val); 322*7c478bd9Sstevel@tonic-gate scf_iter_destroy(iter); 323*7c478bd9Sstevel@tonic-gate scf_property_destroy(prop); 324*7c478bd9Sstevel@tonic-gate scf_pg_destroy(pg); 325*7c478bd9Sstevel@tonic-gate scf_instance_destroy(tmpinst); 326*7c478bd9Sstevel@tonic-gate scf_snapshot_destroy(tmpsnap); 327*7c478bd9Sstevel@tonic-gate scf_service_destroy(svc); 328*7c478bd9Sstevel@tonic-gate scf_scope_destroy(scope); 329*7c478bd9Sstevel@tonic-gate free(spec); 330*7c478bd9Sstevel@tonic-gate return (ret); 331*7c478bd9Sstevel@tonic-gate scferr: 332*7c478bd9Sstevel@tonic-gate *retstr = safe_strdup(scf_strerror(scf_error())); 333*7c478bd9Sstevel@tonic-gate ret = -1; 334*7c478bd9Sstevel@tonic-gate goto out; 335*7c478bd9Sstevel@tonic-gate properr: 336*7c478bd9Sstevel@tonic-gate ret = -1; 337*7c478bd9Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NOT_FOUND) 338*7c478bd9Sstevel@tonic-gate goto scferr; 339*7c478bd9Sstevel@tonic-gate *retstr = uu_msprintf("property \"%s\" not found", prop_spec); 340*7c478bd9Sstevel@tonic-gate if (*retstr != NULL) 341*7c478bd9Sstevel@tonic-gate goto out; 342*7c478bd9Sstevel@tonic-gate err: 343*7c478bd9Sstevel@tonic-gate *retstr = safe_strdup(strerror(errno)); 344*7c478bd9Sstevel@tonic-gate ret = -1; 345*7c478bd9Sstevel@tonic-gate goto out; 346*7c478bd9Sstevel@tonic-gate } 347*7c478bd9Sstevel@tonic-gate 348*7c478bd9Sstevel@tonic-gate /* 349*7c478bd9Sstevel@tonic-gate * Interpret the token at the beginning of str (which should be just 350*7c478bd9Sstevel@tonic-gate * after the escape character), and set *retstr to point at it. Returns 351*7c478bd9Sstevel@tonic-gate * the number of characters swallowed. On error, this returns -1, and 352*7c478bd9Sstevel@tonic-gate * *retstr is set to an error string. 353*7c478bd9Sstevel@tonic-gate * 354*7c478bd9Sstevel@tonic-gate * *retstr should always be freed by the caller. 355*7c478bd9Sstevel@tonic-gate */ 356*7c478bd9Sstevel@tonic-gate static int 357*7c478bd9Sstevel@tonic-gate expand_token(const char *str, scf_instance_t *inst, scf_snapshot_t *snap, 358*7c478bd9Sstevel@tonic-gate int method_type, char **retstr) 359*7c478bd9Sstevel@tonic-gate { 360*7c478bd9Sstevel@tonic-gate scf_handle_t *h = scf_instance_handle(inst); 361*7c478bd9Sstevel@tonic-gate 362*7c478bd9Sstevel@tonic-gate switch (str[0]) { 363*7c478bd9Sstevel@tonic-gate case 's': { /* service */ 364*7c478bd9Sstevel@tonic-gate scf_service_t *svc; 365*7c478bd9Sstevel@tonic-gate char *sname; 366*7c478bd9Sstevel@tonic-gate ssize_t sname_len, szret; 367*7c478bd9Sstevel@tonic-gate int ret; 368*7c478bd9Sstevel@tonic-gate 369*7c478bd9Sstevel@tonic-gate svc = scf_service_create(h); 370*7c478bd9Sstevel@tonic-gate if (svc == NULL) { 371*7c478bd9Sstevel@tonic-gate *retstr = safe_strdup(strerror(scf_error())); 372*7c478bd9Sstevel@tonic-gate return (-1); 373*7c478bd9Sstevel@tonic-gate } 374*7c478bd9Sstevel@tonic-gate 375*7c478bd9Sstevel@tonic-gate ret = scf_instance_get_parent(inst, svc); 376*7c478bd9Sstevel@tonic-gate if (ret != 0) { 377*7c478bd9Sstevel@tonic-gate int err = scf_error(); 378*7c478bd9Sstevel@tonic-gate scf_service_destroy(svc); 379*7c478bd9Sstevel@tonic-gate *retstr = safe_strdup(scf_strerror(err)); 380*7c478bd9Sstevel@tonic-gate return (-1); 381*7c478bd9Sstevel@tonic-gate } 382*7c478bd9Sstevel@tonic-gate 383*7c478bd9Sstevel@tonic-gate sname_len = scf_service_get_name(svc, NULL, 0); 384*7c478bd9Sstevel@tonic-gate if (sname_len < 0) { 385*7c478bd9Sstevel@tonic-gate int err = scf_error(); 386*7c478bd9Sstevel@tonic-gate scf_service_destroy(svc); 387*7c478bd9Sstevel@tonic-gate *retstr = safe_strdup(scf_strerror(err)); 388*7c478bd9Sstevel@tonic-gate return (-1); 389*7c478bd9Sstevel@tonic-gate } 390*7c478bd9Sstevel@tonic-gate 391*7c478bd9Sstevel@tonic-gate sname = malloc(sname_len + 1); 392*7c478bd9Sstevel@tonic-gate if (sname == NULL) { 393*7c478bd9Sstevel@tonic-gate int err = scf_error(); 394*7c478bd9Sstevel@tonic-gate scf_service_destroy(svc); 395*7c478bd9Sstevel@tonic-gate *retstr = safe_strdup(scf_strerror(err)); 396*7c478bd9Sstevel@tonic-gate return (-1); 397*7c478bd9Sstevel@tonic-gate } 398*7c478bd9Sstevel@tonic-gate 399*7c478bd9Sstevel@tonic-gate szret = scf_service_get_name(svc, sname, sname_len + 1); 400*7c478bd9Sstevel@tonic-gate 401*7c478bd9Sstevel@tonic-gate if (szret < 0) { 402*7c478bd9Sstevel@tonic-gate int err = scf_error(); 403*7c478bd9Sstevel@tonic-gate free(sname); 404*7c478bd9Sstevel@tonic-gate scf_service_destroy(svc); 405*7c478bd9Sstevel@tonic-gate *retstr = safe_strdup(scf_strerror(err)); 406*7c478bd9Sstevel@tonic-gate return (-1); 407*7c478bd9Sstevel@tonic-gate } 408*7c478bd9Sstevel@tonic-gate 409*7c478bd9Sstevel@tonic-gate scf_service_destroy(svc); 410*7c478bd9Sstevel@tonic-gate *retstr = sname; 411*7c478bd9Sstevel@tonic-gate return (1); 412*7c478bd9Sstevel@tonic-gate } 413*7c478bd9Sstevel@tonic-gate 414*7c478bd9Sstevel@tonic-gate case 'i': { /* instance */ 415*7c478bd9Sstevel@tonic-gate char *iname; 416*7c478bd9Sstevel@tonic-gate ssize_t iname_len, szret; 417*7c478bd9Sstevel@tonic-gate 418*7c478bd9Sstevel@tonic-gate iname_len = scf_instance_get_name(inst, NULL, 0); 419*7c478bd9Sstevel@tonic-gate if (iname_len < 0) { 420*7c478bd9Sstevel@tonic-gate *retstr = safe_strdup(scf_strerror(scf_error())); 421*7c478bd9Sstevel@tonic-gate return (-1); 422*7c478bd9Sstevel@tonic-gate } 423*7c478bd9Sstevel@tonic-gate 424*7c478bd9Sstevel@tonic-gate iname = malloc(iname_len + 1); 425*7c478bd9Sstevel@tonic-gate if (iname == NULL) { 426*7c478bd9Sstevel@tonic-gate *retstr = safe_strdup(strerror(errno)); 427*7c478bd9Sstevel@tonic-gate return (-1); 428*7c478bd9Sstevel@tonic-gate } 429*7c478bd9Sstevel@tonic-gate 430*7c478bd9Sstevel@tonic-gate szret = scf_instance_get_name(inst, iname, iname_len + 1); 431*7c478bd9Sstevel@tonic-gate if (szret < 0) { 432*7c478bd9Sstevel@tonic-gate free(iname); 433*7c478bd9Sstevel@tonic-gate *retstr = safe_strdup(scf_strerror(scf_error())); 434*7c478bd9Sstevel@tonic-gate return (-1); 435*7c478bd9Sstevel@tonic-gate } 436*7c478bd9Sstevel@tonic-gate 437*7c478bd9Sstevel@tonic-gate *retstr = iname; 438*7c478bd9Sstevel@tonic-gate return (1); 439*7c478bd9Sstevel@tonic-gate } 440*7c478bd9Sstevel@tonic-gate 441*7c478bd9Sstevel@tonic-gate case 'f': { /* fmri */ 442*7c478bd9Sstevel@tonic-gate char *fmri; 443*7c478bd9Sstevel@tonic-gate ssize_t fmri_len; 444*7c478bd9Sstevel@tonic-gate int ret; 445*7c478bd9Sstevel@tonic-gate 446*7c478bd9Sstevel@tonic-gate fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH); 447*7c478bd9Sstevel@tonic-gate if (fmri_len == -1) { 448*7c478bd9Sstevel@tonic-gate *retstr = safe_strdup(scf_strerror(scf_error())); 449*7c478bd9Sstevel@tonic-gate return (-1); 450*7c478bd9Sstevel@tonic-gate } 451*7c478bd9Sstevel@tonic-gate 452*7c478bd9Sstevel@tonic-gate fmri = malloc(fmri_len + 1); 453*7c478bd9Sstevel@tonic-gate if (fmri == NULL) { 454*7c478bd9Sstevel@tonic-gate *retstr = safe_strdup(strerror(errno)); 455*7c478bd9Sstevel@tonic-gate return (-1); 456*7c478bd9Sstevel@tonic-gate } 457*7c478bd9Sstevel@tonic-gate 458*7c478bd9Sstevel@tonic-gate ret = scf_instance_to_fmri(inst, fmri, fmri_len + 1); 459*7c478bd9Sstevel@tonic-gate if (ret == -1) { 460*7c478bd9Sstevel@tonic-gate free(fmri); 461*7c478bd9Sstevel@tonic-gate *retstr = safe_strdup(scf_strerror(scf_error())); 462*7c478bd9Sstevel@tonic-gate return (-1); 463*7c478bd9Sstevel@tonic-gate } 464*7c478bd9Sstevel@tonic-gate 465*7c478bd9Sstevel@tonic-gate *retstr = fmri; 466*7c478bd9Sstevel@tonic-gate return (1); 467*7c478bd9Sstevel@tonic-gate } 468*7c478bd9Sstevel@tonic-gate 469*7c478bd9Sstevel@tonic-gate case 'm': { /* method */ 470*7c478bd9Sstevel@tonic-gate char *str = NULL; 471*7c478bd9Sstevel@tonic-gate switch (method_type) { 472*7c478bd9Sstevel@tonic-gate case METHOD_START: 473*7c478bd9Sstevel@tonic-gate str = "start"; 474*7c478bd9Sstevel@tonic-gate break; 475*7c478bd9Sstevel@tonic-gate case METHOD_STOP: 476*7c478bd9Sstevel@tonic-gate str = "stop"; 477*7c478bd9Sstevel@tonic-gate break; 478*7c478bd9Sstevel@tonic-gate case METHOD_REFRESH: 479*7c478bd9Sstevel@tonic-gate str = "refresh"; 480*7c478bd9Sstevel@tonic-gate break; 481*7c478bd9Sstevel@tonic-gate default: 482*7c478bd9Sstevel@tonic-gate assert(0); 483*7c478bd9Sstevel@tonic-gate return (-1); 484*7c478bd9Sstevel@tonic-gate } 485*7c478bd9Sstevel@tonic-gate *retstr = safe_strdup(str); 486*7c478bd9Sstevel@tonic-gate return (1); 487*7c478bd9Sstevel@tonic-gate } 488*7c478bd9Sstevel@tonic-gate 489*7c478bd9Sstevel@tonic-gate case 'r': /* restarter */ 490*7c478bd9Sstevel@tonic-gate *retstr = safe_strdup("svc.startd"); 491*7c478bd9Sstevel@tonic-gate return (1); 492*7c478bd9Sstevel@tonic-gate 493*7c478bd9Sstevel@tonic-gate case '{': { 494*7c478bd9Sstevel@tonic-gate /* prop_spec[,:]? See get_prop_val_str() for prop_spec. */ 495*7c478bd9Sstevel@tonic-gate 496*7c478bd9Sstevel@tonic-gate char *close; 497*7c478bd9Sstevel@tonic-gate size_t len; 498*7c478bd9Sstevel@tonic-gate char *buf; 499*7c478bd9Sstevel@tonic-gate char sep; 500*7c478bd9Sstevel@tonic-gate int ret; 501*7c478bd9Sstevel@tonic-gate int skip; 502*7c478bd9Sstevel@tonic-gate 503*7c478bd9Sstevel@tonic-gate close = strchr(str + 1, '}'); 504*7c478bd9Sstevel@tonic-gate if (close == NULL) { 505*7c478bd9Sstevel@tonic-gate *retstr = safe_strdup("parse error"); 506*7c478bd9Sstevel@tonic-gate return (-1); 507*7c478bd9Sstevel@tonic-gate } 508*7c478bd9Sstevel@tonic-gate 509*7c478bd9Sstevel@tonic-gate len = close - (str + 1); /* between the {}'s */ 510*7c478bd9Sstevel@tonic-gate skip = len + 2; /* including the {}'s */ 511*7c478bd9Sstevel@tonic-gate 512*7c478bd9Sstevel@tonic-gate /* 513*7c478bd9Sstevel@tonic-gate * If the last character is , or :, use it as the separator. 514*7c478bd9Sstevel@tonic-gate * Otherwise default to space. 515*7c478bd9Sstevel@tonic-gate */ 516*7c478bd9Sstevel@tonic-gate sep = *(close - 1); 517*7c478bd9Sstevel@tonic-gate if (sep == ',' || sep == ':') 518*7c478bd9Sstevel@tonic-gate --len; 519*7c478bd9Sstevel@tonic-gate else 520*7c478bd9Sstevel@tonic-gate sep = ' '; 521*7c478bd9Sstevel@tonic-gate 522*7c478bd9Sstevel@tonic-gate buf = malloc(len + 1); 523*7c478bd9Sstevel@tonic-gate if (buf == NULL) { 524*7c478bd9Sstevel@tonic-gate *retstr = safe_strdup(strerror(errno)); 525*7c478bd9Sstevel@tonic-gate return (-1); 526*7c478bd9Sstevel@tonic-gate } 527*7c478bd9Sstevel@tonic-gate 528*7c478bd9Sstevel@tonic-gate (void) strlcpy(buf, str + 1, len + 1); 529*7c478bd9Sstevel@tonic-gate 530*7c478bd9Sstevel@tonic-gate ret = get_prop_val_str(inst, snap, buf, sep, retstr); 531*7c478bd9Sstevel@tonic-gate 532*7c478bd9Sstevel@tonic-gate if (ret != 0) { 533*7c478bd9Sstevel@tonic-gate free(buf); 534*7c478bd9Sstevel@tonic-gate return (-1); 535*7c478bd9Sstevel@tonic-gate } 536*7c478bd9Sstevel@tonic-gate 537*7c478bd9Sstevel@tonic-gate free(buf); 538*7c478bd9Sstevel@tonic-gate return (skip); 539*7c478bd9Sstevel@tonic-gate } 540*7c478bd9Sstevel@tonic-gate 541*7c478bd9Sstevel@tonic-gate default: 542*7c478bd9Sstevel@tonic-gate *retstr = safe_strdup("unknown method token"); 543*7c478bd9Sstevel@tonic-gate return (-1); 544*7c478bd9Sstevel@tonic-gate } 545*7c478bd9Sstevel@tonic-gate } 546*7c478bd9Sstevel@tonic-gate 547*7c478bd9Sstevel@tonic-gate /* 548*7c478bd9Sstevel@tonic-gate * Expand method tokens in the given string, and place the result in 549*7c478bd9Sstevel@tonic-gate * *retstr. Tokens begin with the ESCAPE character. Returns 0 on 550*7c478bd9Sstevel@tonic-gate * success. On failure, returns -1 and an error string is placed in 551*7c478bd9Sstevel@tonic-gate * *retstr. Caller should free *retstr. 552*7c478bd9Sstevel@tonic-gate */ 553*7c478bd9Sstevel@tonic-gate #define ESCAPE '%' 554*7c478bd9Sstevel@tonic-gate 555*7c478bd9Sstevel@tonic-gate int 556*7c478bd9Sstevel@tonic-gate expand_method_tokens(const char *str, scf_instance_t *inst, 557*7c478bd9Sstevel@tonic-gate scf_snapshot_t *snap, int method_type, char **retstr) 558*7c478bd9Sstevel@tonic-gate { 559*7c478bd9Sstevel@tonic-gate char *expanded; 560*7c478bd9Sstevel@tonic-gate size_t exp_sz; 561*7c478bd9Sstevel@tonic-gate const char *sp; 562*7c478bd9Sstevel@tonic-gate int ei; 563*7c478bd9Sstevel@tonic-gate 564*7c478bd9Sstevel@tonic-gate if (scf_instance_handle(inst) == NULL) { 565*7c478bd9Sstevel@tonic-gate *retstr = safe_strdup(scf_strerror(scf_error())); 566*7c478bd9Sstevel@tonic-gate return (-1); 567*7c478bd9Sstevel@tonic-gate } 568*7c478bd9Sstevel@tonic-gate 569*7c478bd9Sstevel@tonic-gate exp_sz = strlen(str) + 1; 570*7c478bd9Sstevel@tonic-gate expanded = malloc(exp_sz); 571*7c478bd9Sstevel@tonic-gate if (expanded == NULL) { 572*7c478bd9Sstevel@tonic-gate *retstr = safe_strdup(strerror(errno)); 573*7c478bd9Sstevel@tonic-gate return (-1); 574*7c478bd9Sstevel@tonic-gate } 575*7c478bd9Sstevel@tonic-gate 576*7c478bd9Sstevel@tonic-gate /* 577*7c478bd9Sstevel@tonic-gate * Copy str into expanded, expanding %-tokens & realloc()ing as we go. 578*7c478bd9Sstevel@tonic-gate */ 579*7c478bd9Sstevel@tonic-gate 580*7c478bd9Sstevel@tonic-gate sp = str; 581*7c478bd9Sstevel@tonic-gate ei = 0; 582*7c478bd9Sstevel@tonic-gate 583*7c478bd9Sstevel@tonic-gate for (;;) { 584*7c478bd9Sstevel@tonic-gate char *esc; 585*7c478bd9Sstevel@tonic-gate size_t len; 586*7c478bd9Sstevel@tonic-gate 587*7c478bd9Sstevel@tonic-gate esc = strchr(sp, ESCAPE); 588*7c478bd9Sstevel@tonic-gate if (esc == NULL) { 589*7c478bd9Sstevel@tonic-gate (void) strcpy(expanded + ei, sp); 590*7c478bd9Sstevel@tonic-gate *retstr = expanded; 591*7c478bd9Sstevel@tonic-gate return (0); 592*7c478bd9Sstevel@tonic-gate } 593*7c478bd9Sstevel@tonic-gate 594*7c478bd9Sstevel@tonic-gate /* Copy up to the escape character. */ 595*7c478bd9Sstevel@tonic-gate len = esc - sp; 596*7c478bd9Sstevel@tonic-gate 597*7c478bd9Sstevel@tonic-gate (void) strncpy(expanded + ei, sp, len); 598*7c478bd9Sstevel@tonic-gate 599*7c478bd9Sstevel@tonic-gate sp += len; 600*7c478bd9Sstevel@tonic-gate ei += len; 601*7c478bd9Sstevel@tonic-gate 602*7c478bd9Sstevel@tonic-gate if (sp[1] == '\0') { 603*7c478bd9Sstevel@tonic-gate expanded[ei] = '\0'; 604*7c478bd9Sstevel@tonic-gate *retstr = expanded; 605*7c478bd9Sstevel@tonic-gate return (0); 606*7c478bd9Sstevel@tonic-gate } 607*7c478bd9Sstevel@tonic-gate 608*7c478bd9Sstevel@tonic-gate if (sp[1] == ESCAPE) { 609*7c478bd9Sstevel@tonic-gate expanded[ei] = ESCAPE; 610*7c478bd9Sstevel@tonic-gate 611*7c478bd9Sstevel@tonic-gate sp += 2; 612*7c478bd9Sstevel@tonic-gate ei++; 613*7c478bd9Sstevel@tonic-gate } else { 614*7c478bd9Sstevel@tonic-gate char *tokval; 615*7c478bd9Sstevel@tonic-gate int skip; 616*7c478bd9Sstevel@tonic-gate char *p; 617*7c478bd9Sstevel@tonic-gate 618*7c478bd9Sstevel@tonic-gate skip = expand_token(sp + 1, inst, snap, 619*7c478bd9Sstevel@tonic-gate method_type, &tokval); 620*7c478bd9Sstevel@tonic-gate if (skip == -1) { 621*7c478bd9Sstevel@tonic-gate free(expanded); 622*7c478bd9Sstevel@tonic-gate *retstr = tokval; 623*7c478bd9Sstevel@tonic-gate return (-1); 624*7c478bd9Sstevel@tonic-gate } 625*7c478bd9Sstevel@tonic-gate 626*7c478bd9Sstevel@tonic-gate len = strlen(tokval); 627*7c478bd9Sstevel@tonic-gate exp_sz += len; 628*7c478bd9Sstevel@tonic-gate p = realloc(expanded, exp_sz); 629*7c478bd9Sstevel@tonic-gate if (p == NULL) { 630*7c478bd9Sstevel@tonic-gate *retstr = safe_strdup(strerror(errno)); 631*7c478bd9Sstevel@tonic-gate free(expanded); 632*7c478bd9Sstevel@tonic-gate free(tokval); 633*7c478bd9Sstevel@tonic-gate return (-1); 634*7c478bd9Sstevel@tonic-gate } 635*7c478bd9Sstevel@tonic-gate expanded = p; 636*7c478bd9Sstevel@tonic-gate 637*7c478bd9Sstevel@tonic-gate (void) strcpy(expanded + ei, tokval); 638*7c478bd9Sstevel@tonic-gate sp += 1 + skip; 639*7c478bd9Sstevel@tonic-gate ei += len; 640*7c478bd9Sstevel@tonic-gate 641*7c478bd9Sstevel@tonic-gate free(tokval); 642*7c478bd9Sstevel@tonic-gate } 643*7c478bd9Sstevel@tonic-gate } 644*7c478bd9Sstevel@tonic-gate 645*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 646*7c478bd9Sstevel@tonic-gate } 647