4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
31 #include <libscf_priv.h>
41 * Return an allocated copy of str, with the Bourne shell's metacharacters
42 * escaped by '\'. Returns NULL on (allocation) failure.
45 quote_for_shell(const char *str
)
51 const char * const metachars
= ";&()|^<>\n \t\\\"\'`";
54 for (sp
= str
; *sp
!= '\0'; ++sp
) {
57 if (strchr(metachars
, *sp
) != NULL
)
61 if (sp
- str
== dst_len
)
62 return (safe_strdup(str
));
64 dst
= malloc(dst_len
+ 1);
68 for (dp
= dst
, sp
= str
; *sp
!= '\0'; ++dp
, ++sp
) {
69 if (strchr(metachars
, *sp
) != NULL
)
80 * Return an allocated string representation of the value v.
81 * Return NULL on error.
84 val_to_str(scf_value_t
*v
)
89 buflen
= scf_value_get_as_string(v
, NULL
, 0);
92 buf
= malloc(buflen
+ 1);
96 ret
= scf_value_get_as_string(v
, buf
, buflen
+ 1);
97 assert(ret
== buflen
);
103 * Look up a property in the given snapshot, or the editing one
104 * if not found. Returns scf_error() on failure, or 0 otherwise.
107 get_prop(const scf_instance_t
*inst
, scf_snapshot_t
*snap
,
108 const char *pgn
, const char *pn
, scf_propertygroup_t
*pg
,
109 scf_property_t
*prop
)
113 ret
= scf_instance_get_pg_composed(inst
, snap
, pgn
, pg
);
116 if (scf_error() == SCF_ERROR_NOT_FOUND
)
117 ret
= scf_instance_get_pg_composed(inst
, snap
, pgn
, pg
);
119 return (scf_error());
122 if (scf_pg_get_property(pg
, pn
, prop
) == 0)
126 return (scf_error());
128 ret
= scf_instance_get_pg_composed(inst
, NULL
, pgn
, pg
);
130 return (scf_error());
132 if (scf_pg_get_property(pg
, pn
, prop
) == 0)
135 return (scf_error());
139 * Get an allocated string representation of the values of the property
140 * specified by inst & prop_spec and store it in *retstr. prop_spec may
141 * be a full property FMRI, or a "property-group/property" pair relative
142 * to inst, or the name of a property in inst's "application" property
143 * group. In the latter two cases, the property is looked up in inst's
144 * snap snapshot. In the first case, the target instance's running
145 * snapshot will be used. In any case, if the property or its group
146 * can't be found, the "editing" snapshot will be checked. Multiple
147 * values will be separated by sep.
149 * On error, non-zero is returned, and *retstr is set to an error
152 * *retstr should always be freed by the caller.
155 get_prop_val_str(const scf_instance_t
*inst
, scf_snapshot_t
*snap
,
156 const char *prop_spec
, char sep
, char **retstr
)
158 scf_handle_t
*h
= scf_instance_handle(inst
);
159 scf_scope_t
*scope
= NULL
;
160 scf_service_t
*svc
= NULL
;
161 scf_instance_t
*tmpinst
= NULL
;
162 scf_snapshot_t
*tmpsnap
= NULL
;
163 scf_propertygroup_t
*pg
= NULL
;
164 scf_iter_t
*iter
= NULL
;
165 scf_property_t
*prop
= NULL
;
166 scf_value_t
*val
= NULL
;
172 spec
= safe_strdup(prop_spec
);
174 if (strstr(spec
, ":properties") != NULL
) {
175 const char *scn
, *sn
, *in
, *pgn
, *pn
;
177 if (scf_parse_svc_fmri(spec
, &scn
, &sn
, &in
, &pgn
,
181 if (sn
== NULL
|| pgn
== NULL
|| pn
== NULL
) {
183 *retstr
= safe_strdup("parse error");
187 if ((scope
= scf_scope_create(h
)) == NULL
||
188 (svc
= scf_service_create(h
)) == NULL
||
189 (pg
= scf_pg_create(h
)) == NULL
||
190 (prop
= scf_property_create(h
)) == NULL
)
193 if (scf_handle_get_scope(h
, scn
== NULL
? SCF_SCOPE_LOCAL
: scn
,
197 if (scf_scope_get_service(scope
, sn
, svc
) != 0)
201 if (scf_service_get_pg(svc
, pgn
, pg
) != 0)
203 if (scf_pg_get_property(pg
, pn
, prop
) != 0)
206 if ((tmpinst
= scf_instance_create(h
)) == NULL
)
208 if (scf_service_get_instance(svc
, in
, tmpinst
) != 0)
211 tmpsnap
= libscf_get_running_snapshot(tmpinst
);
215 if (get_prop(tmpinst
, tmpsnap
, pgn
, pn
, pg
, prop
) != 0)
219 char *slash
, *pgn
, *pn
;
221 /* Try prop or pg/prop in inst. */
223 prop
= scf_property_create(h
);
227 pg
= scf_pg_create(h
);
231 slash
= strchr(spec
, '/');
241 if (get_prop(inst
, snap
, pgn
, pn
, pg
, prop
) != 0)
245 iter
= scf_iter_create(h
);
250 if (scf_iter_property_values(iter
, prop
) == -1)
253 val
= scf_value_create(h
);
257 ret
= scf_iter_next_value(iter
, val
);
259 *retstr
= safe_strdup("");
261 } else if (ret
== -1) {
265 str
= val_to_str(val
);
269 qstr
= quote_for_shell(str
);
277 while ((ret
= scf_iter_next_value(iter
, val
)) == 1) {
282 /* Append sep & val_to_str(val) to str. */
284 nv
= val_to_str(val
);
289 qnv
= quote_for_shell(nv
);
297 nl
= strl
+ 1 + strlen(nv
);
298 p
= realloc(str
, nl
+ 1);
307 (void) strcpy(&str
[strl
+ 1], nv
);
321 scf_value_destroy(val
);
322 scf_iter_destroy(iter
);
323 scf_property_destroy(prop
);
325 scf_instance_destroy(tmpinst
);
326 scf_snapshot_destroy(tmpsnap
);
327 scf_service_destroy(svc
);
328 scf_scope_destroy(scope
);
332 *retstr
= safe_strdup(scf_strerror(scf_error()));
337 if (scf_error() != SCF_ERROR_NOT_FOUND
)
339 *retstr
= uu_msprintf("property \"%s\" not found", prop_spec
);
343 *retstr
= safe_strdup(strerror(errno
));
349 * Interpret the token at the beginning of str (which should be just
350 * after the escape character), and set *retstr to point at it. Returns
351 * the number of characters swallowed. On error, this returns -1, and
352 * *retstr is set to an error string.
354 * *retstr should always be freed by the caller.
357 expand_token(const char *str
, scf_instance_t
*inst
, scf_snapshot_t
*snap
,
358 int method_type
, char **retstr
)
360 scf_handle_t
*h
= scf_instance_handle(inst
);
363 case 's': { /* service */
366 ssize_t sname_len
, szret
;
369 svc
= scf_service_create(h
);
371 *retstr
= safe_strdup(strerror(scf_error()));
375 ret
= scf_instance_get_parent(inst
, svc
);
377 int err
= scf_error();
378 scf_service_destroy(svc
);
379 *retstr
= safe_strdup(scf_strerror(err
));
383 sname_len
= scf_service_get_name(svc
, NULL
, 0);
385 int err
= scf_error();
386 scf_service_destroy(svc
);
387 *retstr
= safe_strdup(scf_strerror(err
));
391 sname
= malloc(sname_len
+ 1);
393 int err
= scf_error();
394 scf_service_destroy(svc
);
395 *retstr
= safe_strdup(scf_strerror(err
));
399 szret
= scf_service_get_name(svc
, sname
, sname_len
+ 1);
402 int err
= scf_error();
404 scf_service_destroy(svc
);
405 *retstr
= safe_strdup(scf_strerror(err
));
409 scf_service_destroy(svc
);
414 case 'i': { /* instance */
416 ssize_t iname_len
, szret
;
418 iname_len
= scf_instance_get_name(inst
, NULL
, 0);
420 *retstr
= safe_strdup(scf_strerror(scf_error()));
424 iname
= malloc(iname_len
+ 1);
426 *retstr
= safe_strdup(strerror(errno
));
430 szret
= scf_instance_get_name(inst
, iname
, iname_len
+ 1);
433 *retstr
= safe_strdup(scf_strerror(scf_error()));
441 case 'f': { /* fmri */
446 fmri_len
= scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH
);
447 if (fmri_len
== -1) {
448 *retstr
= safe_strdup(scf_strerror(scf_error()));
452 fmri
= malloc(fmri_len
+ 1);
454 *retstr
= safe_strdup(strerror(errno
));
458 ret
= scf_instance_to_fmri(inst
, fmri
, fmri_len
+ 1);
461 *retstr
= safe_strdup(scf_strerror(scf_error()));
469 case 'm': { /* method */
471 switch (method_type
) {
485 *retstr
= safe_strdup(str
);
489 case 'r': /* restarter */
490 *retstr
= safe_strdup("svc.startd");
494 /* prop_spec[,:]? See get_prop_val_str() for prop_spec. */
503 close
= strchr(str
+ 1, '}');
505 *retstr
= safe_strdup("parse error");
509 len
= close
- (str
+ 1); /* between the {}'s */
510 skip
= len
+ 2; /* including the {}'s */
513 * If the last character is , or :, use it as the separator.
514 * Otherwise default to space.
517 if (sep
== ',' || sep
== ':')
522 buf
= malloc(len
+ 1);
524 *retstr
= safe_strdup(strerror(errno
));
528 (void) strlcpy(buf
, str
+ 1, len
+ 1);
530 ret
= get_prop_val_str(inst
, snap
, buf
, sep
, retstr
);
542 *retstr
= safe_strdup("unknown method token");
548 * Expand method tokens in the given string, and place the result in
549 * *retstr. Tokens begin with the ESCAPE character. Returns 0 on
550 * success. On failure, returns -1 and an error string is placed in
551 * *retstr. Caller should free *retstr.
556 expand_method_tokens(const char *str
, scf_instance_t
*inst
,
557 scf_snapshot_t
*snap
, int method_type
, char **retstr
)
564 if (scf_instance_handle(inst
) == NULL
) {
565 *retstr
= safe_strdup(scf_strerror(scf_error()));
569 exp_sz
= strlen(str
) + 1;
570 expanded
= malloc(exp_sz
);
571 if (expanded
== NULL
) {
572 *retstr
= safe_strdup(strerror(errno
));
577 * Copy str into expanded, expanding %-tokens & realloc()ing as we go.
587 esc
= strchr(sp
, ESCAPE
);
589 (void) strcpy(expanded
+ ei
, sp
);
594 /* Copy up to the escape character. */
597 (void) strncpy(expanded
+ ei
, sp
, len
);
608 if (sp
[1] == ESCAPE
) {
609 expanded
[ei
] = ESCAPE
;
618 skip
= expand_token(sp
+ 1, inst
, snap
,
619 method_type
, &tokval
);
626 len
= strlen(tokval
);
628 p
= realloc(expanded
, exp_sz
);
630 *retstr
= safe_strdup(strerror(errno
));
637 (void) strcpy(expanded
+ ei
, tokval
);