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