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