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.
29 #include <libscf_priv.h>
39 * Return an allocated copy of str, with the Bourne shell's metacharacters
40 * escaped by '\'. Returns NULL on (allocation) failure.
43 quote_for_shell(const char *str
)
49 const char * const metachars
= ";&()|^<>\n \t\\\"\'`";
52 for (sp
= str
; *sp
!= '\0'; ++sp
) {
55 if (strchr(metachars
, *sp
) != NULL
)
59 if (sp
- str
== dst_len
)
60 return (safe_strdup(str
));
62 dst
= malloc(dst_len
+ 1);
66 for (dp
= dst
, sp
= str
; *sp
!= '\0'; ++dp
, ++sp
) {
67 if (strchr(metachars
, *sp
) != NULL
)
78 * Return an allocated string representation of the value v.
79 * Return NULL on error.
82 val_to_str(scf_value_t
*v
)
87 buflen
= scf_value_get_as_string(v
, NULL
, 0);
90 buf
= malloc(buflen
+ 1);
94 ret
= scf_value_get_as_string(v
, buf
, buflen
+ 1);
95 assert(ret
== buflen
);
101 * Look up a property in the given snapshot, or the editing one
102 * if not found. Returns scf_error() on failure, or 0 otherwise.
105 get_prop(const scf_instance_t
*inst
, scf_snapshot_t
*snap
,
106 const char *pgn
, const char *pn
, scf_propertygroup_t
*pg
,
107 scf_property_t
*prop
)
111 ret
= scf_instance_get_pg_composed(inst
, snap
, pgn
, pg
);
114 if (scf_error() == SCF_ERROR_NOT_FOUND
)
115 ret
= scf_instance_get_pg_composed(inst
, snap
, pgn
, pg
);
117 return (scf_error());
120 if (scf_pg_get_property(pg
, pn
, prop
) == 0)
124 return (scf_error());
126 ret
= scf_instance_get_pg_composed(inst
, NULL
, pgn
, pg
);
128 return (scf_error());
130 if (scf_pg_get_property(pg
, pn
, prop
) == 0)
133 return (scf_error());
137 * Get an allocated string representation of the values of the property
138 * specified by inst & prop_spec and store it in *retstr. prop_spec may
139 * be a full property FMRI, or a "property-group/property" pair relative
140 * to inst, or the name of a property in inst's "application" property
141 * group. In the latter two cases, the property is looked up in inst's
142 * snap snapshot. In the first case, the target instance's running
143 * snapshot will be used. In any case, if the property or its group
144 * can't be found, the "editing" snapshot will be checked. Multiple
145 * values will be separated by sep.
147 * On error, non-zero is returned, and *retstr is set to an error
150 * *retstr should always be freed by the caller.
153 get_prop_val_str(const scf_instance_t
*inst
, scf_snapshot_t
*snap
,
154 const char *prop_spec
, char sep
, char **retstr
)
156 scf_handle_t
*h
= scf_instance_handle(inst
);
157 scf_scope_t
*scope
= NULL
;
158 scf_service_t
*svc
= NULL
;
159 scf_instance_t
*tmpinst
= NULL
;
160 scf_snapshot_t
*tmpsnap
= NULL
;
161 scf_propertygroup_t
*pg
= NULL
;
162 scf_iter_t
*iter
= NULL
;
163 scf_property_t
*prop
= NULL
;
164 scf_value_t
*val
= NULL
;
170 spec
= safe_strdup(prop_spec
);
172 if (strstr(spec
, ":properties") != NULL
) {
173 const char *scn
, *sn
, *in
, *pgn
, *pn
;
175 if (scf_parse_svc_fmri(spec
, &scn
, &sn
, &in
, &pgn
,
179 if (sn
== NULL
|| pgn
== NULL
|| pn
== NULL
) {
181 *retstr
= safe_strdup("parse error");
185 if ((scope
= scf_scope_create(h
)) == NULL
||
186 (svc
= scf_service_create(h
)) == NULL
||
187 (pg
= scf_pg_create(h
)) == NULL
||
188 (prop
= scf_property_create(h
)) == NULL
)
191 if (scf_handle_get_scope(h
, scn
== NULL
? SCF_SCOPE_LOCAL
: scn
,
195 if (scf_scope_get_service(scope
, sn
, svc
) != 0)
199 if (scf_service_get_pg(svc
, pgn
, pg
) != 0)
201 if (scf_pg_get_property(pg
, pn
, prop
) != 0)
204 if ((tmpinst
= scf_instance_create(h
)) == NULL
)
206 if (scf_service_get_instance(svc
, in
, tmpinst
) != 0)
209 tmpsnap
= libscf_get_running_snapshot(tmpinst
);
213 if (get_prop(tmpinst
, tmpsnap
, pgn
, pn
, pg
, prop
) != 0)
217 char *slash
, *pgn
, *pn
;
219 /* Try prop or pg/prop in inst. */
221 prop
= scf_property_create(h
);
225 pg
= scf_pg_create(h
);
229 slash
= strchr(spec
, '/');
239 if (get_prop(inst
, snap
, pgn
, pn
, pg
, prop
) != 0)
243 iter
= scf_iter_create(h
);
248 if (scf_iter_property_values(iter
, prop
) == -1)
251 val
= scf_value_create(h
);
255 ret
= scf_iter_next_value(iter
, val
);
257 *retstr
= safe_strdup("");
259 } else if (ret
== -1) {
263 str
= val_to_str(val
);
267 qstr
= quote_for_shell(str
);
275 while ((ret
= scf_iter_next_value(iter
, val
)) == 1) {
280 /* Append sep & val_to_str(val) to str. */
282 nv
= val_to_str(val
);
287 qnv
= quote_for_shell(nv
);
295 nl
= strl
+ 1 + strlen(nv
);
296 p
= realloc(str
, nl
+ 1);
305 (void) strcpy(&str
[strl
+ 1], nv
);
319 scf_value_destroy(val
);
320 scf_iter_destroy(iter
);
321 scf_property_destroy(prop
);
323 scf_instance_destroy(tmpinst
);
324 scf_snapshot_destroy(tmpsnap
);
325 scf_service_destroy(svc
);
326 scf_scope_destroy(scope
);
330 *retstr
= safe_strdup(scf_strerror(scf_error()));
335 if (scf_error() != SCF_ERROR_NOT_FOUND
)
337 *retstr
= uu_msprintf("property \"%s\" not found", prop_spec
);
341 *retstr
= safe_strdup(strerror(errno
));
347 * Interpret the token at the beginning of str (which should be just
348 * after the escape character), and set *retstr to point at it. Returns
349 * the number of characters swallowed. On error, this returns -1, and
350 * *retstr is set to an error string.
352 * *retstr should always be freed by the caller.
355 expand_token(const char *str
, scf_instance_t
*inst
, scf_snapshot_t
*snap
,
356 int method_type
, char **retstr
)
358 scf_handle_t
*h
= scf_instance_handle(inst
);
361 case 's': { /* service */
364 ssize_t sname_len
, szret
;
367 svc
= scf_service_create(h
);
369 *retstr
= safe_strdup(strerror(scf_error()));
373 ret
= scf_instance_get_parent(inst
, svc
);
375 int err
= scf_error();
376 scf_service_destroy(svc
);
377 *retstr
= safe_strdup(scf_strerror(err
));
381 sname_len
= scf_service_get_name(svc
, NULL
, 0);
383 int err
= scf_error();
384 scf_service_destroy(svc
);
385 *retstr
= safe_strdup(scf_strerror(err
));
389 sname
= malloc(sname_len
+ 1);
391 int err
= scf_error();
392 scf_service_destroy(svc
);
393 *retstr
= safe_strdup(scf_strerror(err
));
397 szret
= scf_service_get_name(svc
, sname
, sname_len
+ 1);
400 int err
= scf_error();
402 scf_service_destroy(svc
);
403 *retstr
= safe_strdup(scf_strerror(err
));
407 scf_service_destroy(svc
);
412 case 'i': { /* instance */
414 ssize_t iname_len
, szret
;
416 iname_len
= scf_instance_get_name(inst
, NULL
, 0);
418 *retstr
= safe_strdup(scf_strerror(scf_error()));
422 iname
= malloc(iname_len
+ 1);
424 *retstr
= safe_strdup(strerror(errno
));
428 szret
= scf_instance_get_name(inst
, iname
, iname_len
+ 1);
431 *retstr
= safe_strdup(scf_strerror(scf_error()));
439 case 'f': { /* fmri */
444 fmri_len
= scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH
);
445 if (fmri_len
== -1) {
446 *retstr
= safe_strdup(scf_strerror(scf_error()));
450 fmri
= malloc(fmri_len
+ 1);
452 *retstr
= safe_strdup(strerror(errno
));
456 ret
= scf_instance_to_fmri(inst
, fmri
, fmri_len
+ 1);
459 *retstr
= safe_strdup(scf_strerror(scf_error()));
467 case 'm': { /* method */
469 switch (method_type
) {
483 *retstr
= safe_strdup(str
);
487 case 'r': /* restarter */
488 *retstr
= safe_strdup("svc.startd");
492 /* prop_spec[,:]? See get_prop_val_str() for prop_spec. */
501 close
= strchr(str
+ 1, '}');
503 *retstr
= safe_strdup("parse error");
507 len
= close
- (str
+ 1); /* between the {}'s */
508 skip
= len
+ 2; /* including the {}'s */
511 * If the last character is , or :, use it as the separator.
512 * Otherwise default to space.
515 if (sep
== ',' || sep
== ':')
520 buf
= malloc(len
+ 1);
522 *retstr
= safe_strdup(strerror(errno
));
526 (void) strlcpy(buf
, str
+ 1, len
+ 1);
528 ret
= get_prop_val_str(inst
, snap
, buf
, sep
, retstr
);
540 *retstr
= safe_strdup("unknown method token");
546 * Expand method tokens in the given string, and place the result in
547 * *retstr. Tokens begin with the ESCAPE character. Returns 0 on
548 * success. On failure, returns -1 and an error string is placed in
549 * *retstr. Caller should free *retstr.
554 expand_method_tokens(const char *str
, scf_instance_t
*inst
,
555 scf_snapshot_t
*snap
, int method_type
, char **retstr
)
562 if (scf_instance_handle(inst
) == NULL
) {
563 *retstr
= safe_strdup(scf_strerror(scf_error()));
567 exp_sz
= strlen(str
) + 1;
568 expanded
= malloc(exp_sz
);
569 if (expanded
== NULL
) {
570 *retstr
= safe_strdup(strerror(errno
));
575 * Copy str into expanded, expanding %-tokens & realloc()ing as we go.
585 esc
= strchr(sp
, ESCAPE
);
587 (void) strcpy(expanded
+ ei
, sp
);
592 /* Copy up to the escape character. */
595 (void) strncpy(expanded
+ ei
, sp
, len
);
606 if (sp
[1] == ESCAPE
) {
607 expanded
[ei
] = ESCAPE
;
616 skip
= expand_token(sp
+ 1, inst
, snap
,
617 method_type
, &tokval
);
624 len
= strlen(tokval
);
626 p
= realloc(expanded
, exp_sz
);
628 *retstr
= safe_strdup(strerror(errno
));
635 (void) strcpy(expanded
+ ei
, tokval
);