4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2012, Joyent, Inc. All rights reserved.
25 * Copyright 2012 Milan Jurik. All rights reserved.
38 #include <libnvpair.h>
40 #include <libscf_priv.h>
53 #include <libxml/tree.h>
55 #include <sys/param.h>
61 #include "notify_params.h"
62 #include "manifest_hash.h"
63 #include "manifest_find.h"
65 /* The colon namespaces in each entity (each followed by a newline). */
66 #define COLON_NAMESPACES ":properties\n"
68 #define TEMP_FILE_PATTERN "/tmp/svccfg-XXXXXX"
70 /* These are characters which the lexer requires to be in double-quotes. */
71 #define CHARS_TO_QUOTE " \t\n\\>=\"()"
74 #define HASH_PG_TYPE "framework"
75 #define HASH_PG_FLAGS 0
76 #define HASH_PROP "md5sum"
79 * Indentation used in the output of the describe subcommand.
81 #define TMPL_VALUE_INDENT " "
82 #define TMPL_INDENT " "
83 #define TMPL_INDENT_2X " "
84 #define TMPL_CHOICE_INDENT " "
87 * Directory locations for manifests
89 #define VARSVC_DIR "/var/svc/manifest"
90 #define LIBSVC_DIR "/lib/svc/manifest"
91 #define VARSVC_PR "var_svc_manifest"
92 #define LIBSVC_PR "lib_svc_manifest"
93 #define MFSTFILEPR "manifestfile"
95 #define SUPPORTPROP "support"
97 #define MFSTHISTFILE "/lib/svc/share/mfsthistory"
99 #define MFSTFILE_MAX 16
102 * These are the classes of elements which may appear as children of service
103 * or instance elements in XML manifests.
106 xmlNodePtr create_default_instance
;
107 xmlNodePtr single_instance
;
108 xmlNodePtr restarter
;
109 xmlNodePtr dependencies
;
110 xmlNodePtr dependents
;
111 xmlNodePtr method_context
;
112 xmlNodePtr exec_methods
;
113 xmlNodePtr notify_params
;
114 xmlNodePtr property_groups
;
115 xmlNodePtr instances
;
116 xmlNodePtr stability
;
121 * Likewise for property_group elements.
124 xmlNodePtr stability
;
126 xmlNodePtr properties
;
130 * Likewise for template elements.
132 struct template_elts
{
133 xmlNodePtr common_name
;
134 xmlNodePtr description
;
135 xmlNodePtr documentation
;
139 * Likewise for type (for notification parameters) elements.
143 xmlNodePtr parameter
;
147 * This structure is for snaplevel lists. They are convenient because libscf
148 * only allows traversing snaplevels in one direction.
151 uu_list_node_t list_node
;
156 * This is used for communication between lscf_service_export and
160 const char *filename
;
165 * The service_manifest structure is used by the upgrade process
166 * to create a list of service to manifest linkages from the manifests
167 * in a set of given directories.
169 typedef struct service_manifest
{
170 const char *servicename
;
174 uu_avl_node_t svcmfst_node
;
175 } service_manifest_t
;
178 * Structure to track the manifest file property group
179 * and the manifest file associated with that property
180 * group. Also, a flag to keep the access once it has
189 const char * const scf_pg_general
= SCF_PG_GENERAL
;
190 const char * const scf_group_framework
= SCF_GROUP_FRAMEWORK
;
191 const char * const scf_property_enabled
= SCF_PROPERTY_ENABLED
;
192 const char * const scf_property_external
= "external";
194 const char * const snap_initial
= "initial";
195 const char * const snap_lastimport
= "last-import";
196 const char * const snap_previous
= "previous";
197 const char * const snap_running
= "running";
199 scf_handle_t
*g_hndl
= NULL
; /* only valid after lscf_prep_hndl() */
201 ssize_t max_scf_fmri_len
;
202 ssize_t max_scf_name_len
;
203 ssize_t max_scf_pg_type_len
;
204 ssize_t max_scf_value_len
;
205 static size_t max_scf_len
;
207 static scf_scope_t
*cur_scope
;
208 static scf_service_t
*cur_svc
= NULL
;
209 static scf_instance_t
*cur_inst
= NULL
;
210 static scf_snapshot_t
*cur_snap
= NULL
;
211 static scf_snaplevel_t
*cur_level
= NULL
;
213 static uu_list_pool_t
*snaplevel_pool
;
214 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
215 static uu_list_t
*cur_levels
;
216 static struct snaplevel
*cur_elt
; /* cur_elt->sl == cur_level */
218 static FILE *tempfile
= NULL
;
219 static char tempfilename
[sizeof (TEMP_FILE_PATTERN
)] = "";
221 static const char *emsg_entity_not_selected
;
222 static const char *emsg_permission_denied
;
223 static const char *emsg_create_xml
;
224 static const char *emsg_cant_modify_snapshots
;
225 static const char *emsg_invalid_for_snapshot
;
226 static const char *emsg_read_only
;
227 static const char *emsg_deleted
;
228 static const char *emsg_invalid_pg_name
;
229 static const char *emsg_invalid_prop_name
;
230 static const char *emsg_no_such_pg
;
231 static const char *emsg_fmri_invalid_pg_name
;
232 static const char *emsg_fmri_invalid_pg_name_type
;
233 static const char *emsg_pg_added
;
234 static const char *emsg_pg_changed
;
235 static const char *emsg_pg_deleted
;
236 static const char *emsg_pg_mod_perm
;
237 static const char *emsg_pg_add_perm
;
238 static const char *emsg_pg_del_perm
;
239 static const char *emsg_snap_perm
;
240 static const char *emsg_dpt_dangling
;
241 static const char *emsg_dpt_no_dep
;
243 static int li_only
= 0;
244 static int no_refresh
= 0;
246 /* how long in ns we should wait between checks for a pg */
247 static uint64_t pg_timeout
= 100 * (NANOSEC
/ MILLISEC
);
249 /* import globals, to minimize allocations */
250 static scf_scope_t
*imp_scope
= NULL
;
251 static scf_service_t
*imp_svc
= NULL
, *imp_tsvc
= NULL
;
252 static scf_instance_t
*imp_inst
= NULL
, *imp_tinst
= NULL
;
253 static scf_snapshot_t
*imp_snap
= NULL
, *imp_lisnap
= NULL
, *imp_tlisnap
= NULL
;
254 static scf_snapshot_t
*imp_rsnap
= NULL
;
255 static scf_snaplevel_t
*imp_snpl
= NULL
, *imp_rsnpl
= NULL
;
256 static scf_propertygroup_t
*imp_pg
= NULL
, *imp_pg2
= NULL
;
257 static scf_property_t
*imp_prop
= NULL
;
258 static scf_iter_t
*imp_iter
= NULL
;
259 static scf_iter_t
*imp_rpg_iter
= NULL
;
260 static scf_iter_t
*imp_up_iter
= NULL
;
261 static scf_transaction_t
*imp_tx
= NULL
; /* always reset this */
262 static char *imp_str
= NULL
;
263 static size_t imp_str_sz
;
264 static char *imp_tsname
= NULL
;
265 static char *imp_fe1
= NULL
; /* for fmri_equal() */
266 static char *imp_fe2
= NULL
;
267 static uu_list_t
*imp_deleted_dpts
= NULL
; /* pgroup_t's to refresh */
269 /* upgrade_dependents() globals */
270 static scf_instance_t
*ud_inst
= NULL
;
271 static scf_snaplevel_t
*ud_snpl
= NULL
;
272 static scf_propertygroup_t
*ud_pg
= NULL
;
273 static scf_propertygroup_t
*ud_cur_depts_pg
= NULL
;
274 static scf_propertygroup_t
*ud_run_dpts_pg
= NULL
;
275 static int ud_run_dpts_pg_set
= 0;
276 static scf_property_t
*ud_prop
= NULL
;
277 static scf_property_t
*ud_dpt_prop
= NULL
;
278 static scf_value_t
*ud_val
= NULL
;
279 static scf_iter_t
*ud_iter
= NULL
, *ud_iter2
= NULL
;
280 static scf_transaction_t
*ud_tx
= NULL
;
281 static char *ud_ctarg
= NULL
;
282 static char *ud_oldtarg
= NULL
;
283 static char *ud_name
= NULL
;
286 static scf_instance_t
*exp_inst
;
287 static scf_propertygroup_t
*exp_pg
;
288 static scf_property_t
*exp_prop
;
289 static scf_value_t
*exp_val
;
290 static scf_iter_t
*exp_inst_iter
, *exp_pg_iter
, *exp_prop_iter
, *exp_val_iter
;
291 static char *exp_str
;
292 static size_t exp_str_sz
;
294 /* cleanup globals */
295 static uu_avl_pool_t
*service_manifest_pool
= NULL
;
296 static uu_avl_t
*service_manifest_tree
= NULL
;
298 static void scfdie_lineno(int lineno
) __NORETURN
;
300 static char *start_method_names
[] = {
306 static struct uri_scheme
{
308 const char *protocol
;
310 { "mailto", "smtp" },
312 { "syslog", "syslog" },
315 #define URI_SCHEME_NUM ((sizeof (uri_scheme) / \
316 sizeof (struct uri_scheme)) - 1)
319 check_uri_scheme(const char *scheme
)
323 for (i
= 0; uri_scheme
[i
].scheme
!= NULL
; ++i
) {
324 if (strcmp(scheme
, uri_scheme
[i
].scheme
) == 0)
332 check_uri_protocol(const char *p
)
336 for (i
= 0; uri_scheme
[i
].protocol
!= NULL
; ++i
) {
337 if (strcmp(p
, uri_scheme
[i
].protocol
) == 0)
345 * For unexpected libscf errors.
349 static void scfdie(void) __NORETURN
;
354 scf_error_t err
= scf_error();
356 if (err
== SCF_ERROR_CONNECTION_BROKEN
)
357 uu_die(gettext("Repository connection broken. Exiting.\n"));
359 uu_die(gettext("Unexpected fatal libscf error: %s. Exiting.\n"),
365 #define scfdie() scfdie_lineno(__LINE__)
368 scfdie_lineno(int lineno
)
370 scf_error_t err
= scf_error();
372 if (err
== SCF_ERROR_CONNECTION_BROKEN
)
373 uu_die(gettext("Repository connection broken. Exiting.\n"));
375 uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
376 ": %s.\n"), lineno
, scf_strerror(err
));
384 warn(gettext("Unexpected libscf error: %s.\n"),
385 scf_strerror(scf_error()));
389 * Clear a field of a structure.
392 clear_int(void *a
, void *b
)
395 *(int *)((char *)a
+ (size_t)b
) = 0;
397 return (UU_WALK_NEXT
);
401 scferror2errno(scf_error_t err
)
404 case SCF_ERROR_BACKEND_ACCESS
:
407 case SCF_ERROR_BACKEND_READONLY
:
410 case SCF_ERROR_CONNECTION_BROKEN
:
411 return (ECONNABORTED
);
413 case SCF_ERROR_CONSTRAINT_VIOLATED
:
414 case SCF_ERROR_INVALID_ARGUMENT
:
417 case SCF_ERROR_DELETED
:
420 case SCF_ERROR_EXISTS
:
423 case SCF_ERROR_NO_MEMORY
:
426 case SCF_ERROR_NO_RESOURCES
:
429 case SCF_ERROR_NOT_FOUND
:
432 case SCF_ERROR_PERMISSION_DENIED
:
437 (void) fprintf(stderr
, "%s:%d: Unknown libscf error %d.\n",
438 __FILE__
, __LINE__
, err
);
440 (void) fprintf(stderr
, "Unknown libscf error %d.\n", err
);
448 entity_get_pg(void *ent
, int issvc
, const char *name
,
449 scf_propertygroup_t
*pg
)
452 return (scf_service_get_pg(ent
, name
, pg
));
454 return (scf_instance_get_pg(ent
, name
, pg
));
458 entity_destroy(void *ent
, int issvc
)
461 scf_service_destroy(ent
);
463 scf_instance_destroy(ent
);
467 get_pg(const char *pg_name
, scf_propertygroup_t
*pg
)
471 if (cur_level
!= NULL
)
472 ret
= scf_snaplevel_get_pg(cur_level
, pg_name
, pg
);
473 else if (cur_inst
!= NULL
)
474 ret
= scf_instance_get_pg(cur_inst
, pg_name
, pg
);
476 ret
= scf_service_get_pg(cur_svc
, pg_name
, pg
);
482 * Find a snaplevel in a snapshot. If get_svc is true, find the service
483 * snaplevel. Otherwise find the instance snaplevel.
487 * ECONNABORTED - repository connection broken
488 * ECANCELED - instance containing snap was deleted
489 * ENOENT - snap has no snaplevels
490 * - requested snaplevel not found
493 get_snaplevel(scf_snapshot_t
*snap
, int get_svc
, scf_snaplevel_t
*snpl
)
495 if (scf_snapshot_get_base_snaplevel(snap
, snpl
) != 0) {
496 switch (scf_error()) {
497 case SCF_ERROR_CONNECTION_BROKEN
:
498 case SCF_ERROR_DELETED
:
499 case SCF_ERROR_NOT_FOUND
:
500 return (scferror2errno(scf_error()));
502 case SCF_ERROR_HANDLE_MISMATCH
:
503 case SCF_ERROR_NOT_BOUND
:
504 case SCF_ERROR_NOT_SET
:
506 bad_error("scf_snapshot_get_base_snaplevel",
514 ssz
= scf_snaplevel_get_instance_name(snpl
, NULL
, 0);
519 switch (scf_error()) {
520 case SCF_ERROR_CONSTRAINT_VIOLATED
:
525 case SCF_ERROR_DELETED
:
526 case SCF_ERROR_CONNECTION_BROKEN
:
527 return (scferror2errno(scf_error()));
529 case SCF_ERROR_NOT_SET
:
530 case SCF_ERROR_NOT_BOUND
:
532 bad_error("scf_snaplevel_get_instance_name",
537 if (scf_snaplevel_get_next_snaplevel(snpl
, snpl
) != 0) {
538 switch (scf_error()) {
539 case SCF_ERROR_NOT_FOUND
:
540 case SCF_ERROR_CONNECTION_BROKEN
:
541 case SCF_ERROR_DELETED
:
542 return (scferror2errno(scf_error()));
544 case SCF_ERROR_HANDLE_MISMATCH
:
545 case SCF_ERROR_NOT_BOUND
:
546 case SCF_ERROR_NOT_SET
:
547 case SCF_ERROR_INVALID_ARGUMENT
:
549 bad_error("scf_snaplevel_get_next_snaplevel",
557 * If issvc is 0, take ent to be a pointer to an scf_instance_t. If it has
558 * a running snapshot, and that snapshot has an instance snaplevel, set pg to
559 * the property group named name in it. If it doesn't have a running
560 * snapshot, set pg to the instance's current property group named name.
562 * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
563 * its instances. If one has a running snapshot with a service snaplevel, set
564 * pg to the property group named name in it. If no such snaplevel could be
565 * found, set pg to the service's current property group named name.
567 * iter, inst, snap, and snpl are required scratch objects.
571 * ECONNABORTED - repository connection broken
572 * ECANCELED - ent was deleted
573 * ENOENT - no such property group
574 * EINVAL - name is an invalid property group name
575 * EBADF - found running snapshot is missing a snaplevel
578 entity_get_running_pg(void *ent
, int issvc
, const char *name
,
579 scf_propertygroup_t
*pg
, scf_iter_t
*iter
, scf_instance_t
*inst
,
580 scf_snapshot_t
*snap
, scf_snaplevel_t
*snpl
)
585 /* Search for an instance with a running snapshot. */
586 if (scf_iter_service_instances(iter
, ent
) != 0) {
587 switch (scf_error()) {
588 case SCF_ERROR_DELETED
:
589 case SCF_ERROR_CONNECTION_BROKEN
:
590 return (scferror2errno(scf_error()));
592 case SCF_ERROR_NOT_SET
:
593 case SCF_ERROR_NOT_BOUND
:
594 case SCF_ERROR_HANDLE_MISMATCH
:
596 bad_error("scf_iter_service_instances",
602 r
= scf_iter_next_instance(iter
, inst
);
604 if (scf_service_get_pg(ent
, name
, pg
) == 0)
607 switch (scf_error()) {
608 case SCF_ERROR_DELETED
:
609 case SCF_ERROR_NOT_FOUND
:
610 case SCF_ERROR_INVALID_ARGUMENT
:
611 case SCF_ERROR_CONNECTION_BROKEN
:
612 return (scferror2errno(scf_error()));
614 case SCF_ERROR_NOT_BOUND
:
615 case SCF_ERROR_HANDLE_MISMATCH
:
616 case SCF_ERROR_NOT_SET
:
618 bad_error("scf_service_get_pg",
623 switch (scf_error()) {
624 case SCF_ERROR_DELETED
:
625 case SCF_ERROR_CONNECTION_BROKEN
:
626 return (scferror2errno(scf_error()));
628 case SCF_ERROR_INVALID_ARGUMENT
:
629 case SCF_ERROR_NOT_SET
:
630 case SCF_ERROR_NOT_BOUND
:
631 case SCF_ERROR_HANDLE_MISMATCH
:
633 bad_error("scf_iter_next_instance",
638 if (scf_instance_get_snapshot(inst
, snap_running
,
642 switch (scf_error()) {
643 case SCF_ERROR_NOT_FOUND
:
644 case SCF_ERROR_DELETED
:
647 case SCF_ERROR_CONNECTION_BROKEN
:
648 return (ECONNABORTED
);
650 case SCF_ERROR_HANDLE_MISMATCH
:
651 case SCF_ERROR_INVALID_ARGUMENT
:
652 case SCF_ERROR_NOT_SET
:
653 case SCF_ERROR_NOT_BOUND
:
655 bad_error("scf_instance_get_snapshot",
660 if (scf_instance_get_snapshot(ent
, snap_running
, snap
) != 0) {
661 switch (scf_error()) {
662 case SCF_ERROR_NOT_FOUND
:
665 case SCF_ERROR_DELETED
:
666 case SCF_ERROR_CONNECTION_BROKEN
:
667 return (scferror2errno(scf_error()));
669 case SCF_ERROR_NOT_BOUND
:
670 case SCF_ERROR_HANDLE_MISMATCH
:
671 case SCF_ERROR_INVALID_ARGUMENT
:
672 case SCF_ERROR_NOT_SET
:
674 bad_error("scf_instance_get_snapshot",
678 if (scf_instance_get_pg(ent
, name
, pg
) == 0)
681 switch (scf_error()) {
682 case SCF_ERROR_DELETED
:
683 case SCF_ERROR_NOT_FOUND
:
684 case SCF_ERROR_INVALID_ARGUMENT
:
685 case SCF_ERROR_CONNECTION_BROKEN
:
686 return (scferror2errno(scf_error()));
688 case SCF_ERROR_NOT_BOUND
:
689 case SCF_ERROR_HANDLE_MISMATCH
:
690 case SCF_ERROR_NOT_SET
:
692 bad_error("scf_instance_get_pg", scf_error());
697 r
= get_snaplevel(snap
, issvc
, snpl
);
710 bad_error("get_snaplevel", r
);
713 if (scf_snaplevel_get_pg(snpl
, name
, pg
) == 0)
716 switch (scf_error()) {
717 case SCF_ERROR_DELETED
:
718 case SCF_ERROR_INVALID_ARGUMENT
:
719 case SCF_ERROR_CONNECTION_BROKEN
:
720 case SCF_ERROR_NOT_FOUND
:
721 return (scferror2errno(scf_error()));
723 case SCF_ERROR_NOT_BOUND
:
724 case SCF_ERROR_HANDLE_MISMATCH
:
725 case SCF_ERROR_NOT_SET
:
727 bad_error("scf_snaplevel_get_pg", scf_error());
733 * To be registered with atexit().
736 remove_tempfile(void)
740 if (tempfile
!= NULL
) {
741 if (fclose(tempfile
) == EOF
)
742 (void) warn(gettext("Could not close temporary file"));
746 if (tempfilename
[0] != '\0') {
748 ret
= remove(tempfilename
);
749 } while (ret
== -1 && errno
== EINTR
);
751 warn(gettext("Could not remove temporary file"));
752 tempfilename
[0] = '\0';
757 * Launch private svc.configd(1M) for manipulating alternate repositories.
760 start_private_repository(engine_state_t
*est
)
763 struct door_info info
;
767 * 1. Create a temporary file for the door.
769 if (est
->sc_repo_doorname
!= NULL
)
770 free((void *)est
->sc_repo_doorname
);
772 est
->sc_repo_doorname
= tempnam(est
->sc_repo_doordir
, "scfdr");
773 if (est
->sc_repo_doorname
== NULL
)
774 uu_die(gettext("Could not acquire temporary filename"));
776 fd
= open(est
->sc_repo_doorname
, O_CREAT
| O_EXCL
| O_RDWR
, 0600);
778 uu_die(gettext("Could not create temporary file for "
779 "repository server"));
784 * 2. Launch a configd with that door, using the specified
787 if ((est
->sc_repo_pid
= fork()) == 0) {
788 (void) execlp(est
->sc_repo_server
, est
->sc_repo_server
, "-p",
789 "-d", est
->sc_repo_doorname
, "-r", est
->sc_repo_filename
,
791 uu_die(gettext("Could not execute %s"), est
->sc_repo_server
);
792 } else if (est
->sc_repo_pid
== -1)
793 uu_die(gettext("Attempt to fork failed"));
796 pid
= waitpid(est
->sc_repo_pid
, &stat
, 0);
797 } while (pid
== -1 && errno
== EINTR
);
800 uu_die(gettext("Could not waitpid() for repository server"));
802 if (!WIFEXITED(stat
)) {
803 uu_die(gettext("Repository server failed (status %d).\n"),
805 } else if (WEXITSTATUS(stat
) != 0) {
806 uu_die(gettext("Repository server failed (exit %d).\n"),
811 * See if it was successful by checking if the door is a door.
814 fd
= open(est
->sc_repo_doorname
, O_RDWR
);
816 uu_die(gettext("Could not open door \"%s\""),
817 est
->sc_repo_doorname
);
819 if (door_info(fd
, &info
) < 0)
820 uu_die(gettext("Unexpected door_info() error"));
823 warn(gettext("Could not close repository door"),
826 est
->sc_repo_pid
= info
.di_target
;
833 * In the case where we've launched a private svc.configd(1M)
834 * instance, we must terminate our child and remove the temporary
837 if (est
->sc_repo_pid
> 0) {
838 (void) kill(est
->sc_repo_pid
, SIGTERM
);
839 (void) waitpid(est
->sc_repo_pid
, NULL
, 0);
840 (void) unlink(est
->sc_repo_doorname
);
842 est
->sc_repo_pid
= 0;
847 unselect_cursnap(void)
854 while ((cur_elt
= uu_list_teardown(cur_levels
, &cookie
)) != NULL
) {
855 scf_snaplevel_destroy(cur_elt
->sl
);
859 scf_snapshot_destroy(cur_snap
);
869 g_hndl
= scf_handle_create(SCF_VERSION
);
873 if (est
->sc_repo_filename
!= NULL
)
874 start_private_repository(est
);
876 if (est
->sc_repo_doorname
!= NULL
) {
877 scf_value_t
*repo_value
;
880 repo_value
= scf_value_create(g_hndl
);
881 if (repo_value
== NULL
)
884 ret
= scf_value_set_astring(repo_value
, est
->sc_repo_doorname
);
885 assert(ret
== SCF_SUCCESS
);
887 if (scf_handle_decorate(g_hndl
, "door_path", repo_value
) !=
891 scf_value_destroy(repo_value
);
894 if (scf_handle_bind(g_hndl
) != 0)
895 uu_die(gettext("Could not connect to repository server: %s.\n"),
896 scf_strerror(scf_error()));
898 cur_scope
= scf_scope_create(g_hndl
);
899 if (cur_scope
== NULL
)
902 if (scf_handle_get_local_scope(g_hndl
, cur_scope
) != 0)
907 repository_teardown(void)
909 if (g_hndl
!= NULL
) {
910 if (cur_snap
!= NULL
)
912 scf_instance_destroy(cur_inst
);
913 scf_service_destroy(cur_svc
);
914 scf_scope_destroy(cur_scope
);
915 scf_handle_destroy(g_hndl
);
925 lscf_set_repository(const char *repfile
, int force
)
927 repository_teardown();
929 if (est
->sc_repo_filename
!= NULL
) {
930 free((void *)est
->sc_repo_filename
);
931 est
->sc_repo_filename
= NULL
;
934 if ((force
== 0) && (access(repfile
, R_OK
) != 0)) {
936 * Repository file does not exist
937 * or has no read permission.
939 warn(gettext("Cannot access \"%s\": %s\n"),
940 repfile
, strerror(errno
));
942 est
->sc_repo_filename
= safe_strdup(repfile
);
951 if ((max_scf_fmri_len
= scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH
)) < 0 ||
952 (max_scf_name_len
= scf_limit(SCF_LIMIT_MAX_NAME_LENGTH
)) < 0 ||
953 (max_scf_pg_type_len
= scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH
)) <
955 (max_scf_value_len
= scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH
)) < 0)
958 max_scf_len
= max_scf_fmri_len
;
959 if (max_scf_name_len
> max_scf_len
)
960 max_scf_len
= max_scf_name_len
;
961 if (max_scf_pg_type_len
> max_scf_len
)
962 max_scf_len
= max_scf_pg_type_len
;
964 * When a value of type opaque is represented as a string, the
965 * string contains 2 characters for every byte of data. That is
966 * because the string contains the hex representation of the opaque
969 if (2 * max_scf_value_len
> max_scf_len
)
970 max_scf_len
= 2 * max_scf_value_len
;
972 if (atexit(remove_tempfile
) != 0)
973 uu_die(gettext("Could not register atexit() function"));
975 emsg_entity_not_selected
= gettext("An entity is not selected.\n");
976 emsg_permission_denied
= gettext("Permission denied.\n");
977 emsg_create_xml
= gettext("Could not create XML node.\n");
978 emsg_cant_modify_snapshots
= gettext("Cannot modify snapshots.\n");
979 emsg_invalid_for_snapshot
=
980 gettext("Invalid operation on a snapshot.\n");
981 emsg_read_only
= gettext("Backend read-only.\n");
982 emsg_deleted
= gettext("Current selection has been deleted.\n");
983 emsg_invalid_pg_name
=
984 gettext("Invalid property group name \"%s\".\n");
985 emsg_invalid_prop_name
= gettext("Invalid property name \"%s\".\n");
986 emsg_no_such_pg
= gettext("No such property group \"%s\".\n");
987 emsg_fmri_invalid_pg_name
= gettext("Service %s has property group "
988 "with invalid name \"%s\".\n");
989 emsg_fmri_invalid_pg_name_type
= gettext("Service %s has property "
990 "group with invalid name \"%s\" or type \"%s\".\n");
991 emsg_pg_added
= gettext("%s changed unexpectedly "
992 "(property group \"%s\" added).\n");
993 emsg_pg_changed
= gettext("%s changed unexpectedly "
994 "(property group \"%s\" changed).\n");
995 emsg_pg_deleted
= gettext("%s changed unexpectedly "
996 "(property group \"%s\" or an ancestor was deleted).\n");
997 emsg_pg_mod_perm
= gettext("Could not modify property group \"%s\" "
998 "in %s (permission denied).\n");
999 emsg_pg_add_perm
= gettext("Could not create property group \"%s\" "
1000 "in %s (permission denied).\n");
1001 emsg_pg_del_perm
= gettext("Could not delete property group \"%s\" "
1002 "in %s (permission denied).\n");
1003 emsg_snap_perm
= gettext("Could not take \"%s\" snapshot of %s "
1004 "(permission denied).\n");
1005 emsg_dpt_dangling
= gettext("Conflict upgrading %s (not importing "
1006 "new dependent \"%s\" because it already exists). Warning: The "
1007 "current dependent's target (%s) does not exist.\n");
1008 emsg_dpt_no_dep
= gettext("Conflict upgrading %s (not importing new "
1009 "dependent \"%s\" because it already exists). Warning: The "
1010 "current dependent's target (%s) does not have a dependency named "
1011 "\"%s\" as expected.\n");
1013 string_pool
= uu_list_pool_create("strings", sizeof (string_list_t
),
1014 offsetof(string_list_t
, node
), NULL
, 0);
1015 snaplevel_pool
= uu_list_pool_create("snaplevels",
1016 sizeof (struct snaplevel
), offsetof(struct snaplevel
, list_node
),
1022 prop_to_typestr(const scf_property_t
*prop
)
1026 if (scf_property_type(prop
, &ty
) != SCF_SUCCESS
)
1029 return (scf_type_to_string(ty
));
1033 string_to_type(const char *type
)
1035 size_t len
= strlen(type
);
1038 if (len
== 0 || type
[len
- 1] != ':')
1039 return (SCF_TYPE_INVALID
);
1041 buf
= (char *)alloca(len
+ 1);
1042 (void) strlcpy(buf
, type
, len
+ 1);
1045 return (scf_string_to_type(buf
));
1048 static scf_value_t
*
1049 string_to_value(const char *str
, scf_type_t ty
, boolean_t require_quotes
)
1055 v
= scf_value_create(g_hndl
);
1060 if (require_quotes
&&
1061 (len
< 2 || str
[0] != '\"' || str
[len
- 1] != '\"')) {
1062 semerr(gettext("Multiple string values or string values "
1063 "with spaces must be quoted with '\"'.\n"));
1064 scf_value_destroy(v
);
1068 nstr
= dup
= safe_strdup(str
);
1069 if (dup
[0] == '\"') {
1071 * Strip out the first and the last quote.
1073 dup
[len
- 1] = '\0';
1077 if (scf_value_set_from_string(v
, ty
, (const char *)nstr
) != 0) {
1078 assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT
);
1079 semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1080 scf_type_to_string(ty
), nstr
);
1081 scf_value_destroy(v
);
1089 * Print str to strm, quoting double-quotes and backslashes with backslashes.
1090 * Optionally append a comment prefix ('#') to newlines ('\n').
1093 quote_and_print(const char *str
, FILE *strm
, int commentnl
)
1097 for (cp
= str
; *cp
!= '\0'; ++cp
) {
1098 if (*cp
== '"' || *cp
== '\\')
1099 (void) putc('\\', strm
);
1101 (void) putc(*cp
, strm
);
1103 if (commentnl
&& *cp
== '\n') {
1104 (void) putc('#', strm
);
1108 return (ferror(strm
));
1112 * These wrappers around lowlevel functions provide consistent error checking
1116 pg_get_prop(scf_propertygroup_t
*pg
, const char *propname
, scf_property_t
*prop
)
1118 if (scf_pg_get_property(pg
, propname
, prop
) == SCF_SUCCESS
)
1121 if (scf_error() != SCF_ERROR_NOT_FOUND
)
1128 len
= scf_pg_to_fmri(pg
, NULL
, 0);
1132 fmri
= safe_malloc(len
+ 1);
1134 if (scf_pg_to_fmri(pg
, fmri
, len
+ 1) < 0)
1137 warn(gettext("Expected property %s of property group %s is "
1138 "missing.\n"), propname
, fmri
);
1147 prop_check_type(scf_property_t
*prop
, scf_type_t ty
)
1151 if (scf_property_type(prop
, &pty
) != SCF_SUCCESS
)
1162 len
= scf_property_to_fmri(prop
, NULL
, 0);
1166 fmri
= safe_malloc(len
+ 1);
1168 if (scf_property_to_fmri(prop
, fmri
, len
+ 1) < 0)
1171 tystr
= scf_type_to_string(ty
);
1175 warn(gettext("Property %s is not of expected type %s.\n"),
1185 prop_get_val(scf_property_t
*prop
, scf_value_t
*val
)
1189 if (scf_property_get_value(prop
, val
) == SCF_SUCCESS
)
1194 if (err
!= SCF_ERROR_NOT_FOUND
&&
1195 err
!= SCF_ERROR_CONSTRAINT_VIOLATED
&&
1196 err
!= SCF_ERROR_PERMISSION_DENIED
)
1203 len
= scf_property_to_fmri(prop
, NULL
, 0);
1207 fmri
= safe_malloc(len
+ 1);
1209 if (scf_property_to_fmri(prop
, fmri
, len
+ 1) < 0)
1212 if (err
== SCF_ERROR_NOT_FOUND
)
1213 emsg
= gettext("Property %s has no values; expected "
1215 else if (err
== SCF_ERROR_CONSTRAINT_VIOLATED
)
1216 emsg
= gettext("Property %s has multiple values; "
1219 emsg
= gettext("No permission to read property %s.\n");
1231 snaplevel_is_instance(const scf_snaplevel_t
*level
)
1233 if (scf_snaplevel_get_instance_name(level
, NULL
, 0) < 0) {
1234 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED
)
1243 * Decode FMRI into a service or instance, and put the result in *ep. If
1244 * memory cannot be allocated, return SCF_ERROR_NO_MEMORY. If the FMRI is
1245 * invalid, return SCF_ERROR_INVALID_ARGUMENT. If the FMRI does not specify
1246 * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED. If the entity cannot be
1247 * found, return SCF_ERROR_NOT_FOUND. Otherwise return SCF_ERROR_NONE, point
1248 * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1249 * whether *ep is a service.
1252 fmri_to_entity(scf_handle_t
*h
, const char *fmri
, void **ep
, int *isservice
)
1255 const char *sstr
, *istr
, *pgstr
;
1257 scf_instance_t
*inst
;
1259 fmri_copy
= strdup(fmri
);
1260 if (fmri_copy
== NULL
)
1261 return (SCF_ERROR_NO_MEMORY
);
1263 if (scf_parse_svc_fmri(fmri_copy
, NULL
, &sstr
, &istr
, &pgstr
, NULL
) !=
1266 return (SCF_ERROR_INVALID_ARGUMENT
);
1271 if (sstr
== NULL
|| pgstr
!= NULL
)
1272 return (SCF_ERROR_CONSTRAINT_VIOLATED
);
1275 svc
= scf_service_create(h
);
1277 return (SCF_ERROR_NO_MEMORY
);
1279 if (scf_handle_decode_fmri(h
, fmri
, NULL
, svc
, NULL
, NULL
, NULL
,
1280 SCF_DECODE_FMRI_EXACT
) != SCF_SUCCESS
) {
1281 if (scf_error() != SCF_ERROR_NOT_FOUND
)
1284 return (SCF_ERROR_NOT_FOUND
);
1290 inst
= scf_instance_create(h
);
1292 return (SCF_ERROR_NO_MEMORY
);
1294 if (scf_handle_decode_fmri(h
, fmri
, NULL
, NULL
, inst
, NULL
,
1295 NULL
, SCF_DECODE_FMRI_EXACT
) != SCF_SUCCESS
) {
1296 if (scf_error() != SCF_ERROR_NOT_FOUND
)
1299 return (SCF_ERROR_NOT_FOUND
);
1306 return (SCF_ERROR_NONE
);
1310 * Create the entity named by fmri. Place a pointer to its libscf handle in
1311 * *ep, and set or clear *isservicep if it is a service or an instance.
1313 * SCF_ERROR_NONE - success
1314 * SCF_ERROR_NO_MEMORY - scf_*_create() failed
1315 * SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1316 * SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1317 * SCF_ERROR_NOT_FOUND - no such scope
1318 * SCF_ERROR_PERMISSION_DENIED
1319 * SCF_ERROR_BACKEND_READONLY
1320 * SCF_ERROR_BACKEND_ACCESS
1323 create_entity(scf_handle_t
*h
, const char *fmri
, void **ep
, int *isservicep
)
1326 const char *scstr
, *sstr
, *istr
, *pgstr
;
1327 scf_scope_t
*scope
= NULL
;
1328 scf_service_t
*svc
= NULL
;
1329 scf_instance_t
*inst
= NULL
;
1332 fmri_copy
= safe_strdup(fmri
);
1334 if (scf_parse_svc_fmri(fmri_copy
, &scstr
, &sstr
, &istr
, &pgstr
, NULL
) !=
1337 return (SCF_ERROR_INVALID_ARGUMENT
);
1340 if (scstr
== NULL
|| sstr
== NULL
|| pgstr
!= NULL
) {
1342 return (SCF_ERROR_CONSTRAINT_VIOLATED
);
1347 if ((scope
= scf_scope_create(h
)) == NULL
||
1348 (svc
= scf_service_create(h
)) == NULL
||
1349 (inst
= scf_instance_create(h
)) == NULL
) {
1350 scfe
= SCF_ERROR_NO_MEMORY
;
1355 if (scf_handle_get_scope(h
, scstr
, scope
) != 0) {
1356 switch (scf_error()) {
1357 case SCF_ERROR_CONNECTION_BROKEN
:
1361 case SCF_ERROR_NOT_FOUND
:
1362 scfe
= SCF_ERROR_NOT_FOUND
;
1365 case SCF_ERROR_HANDLE_MISMATCH
:
1366 case SCF_ERROR_NOT_BOUND
:
1367 case SCF_ERROR_INVALID_ARGUMENT
:
1369 bad_error("scf_handle_get_scope", scf_error());
1374 if (scf_scope_get_service(scope
, sstr
, svc
) != 0) {
1375 switch (scf_error()) {
1376 case SCF_ERROR_CONNECTION_BROKEN
:
1380 case SCF_ERROR_DELETED
:
1383 case SCF_ERROR_NOT_FOUND
:
1386 case SCF_ERROR_HANDLE_MISMATCH
:
1387 case SCF_ERROR_INVALID_ARGUMENT
:
1388 case SCF_ERROR_NOT_BOUND
:
1389 case SCF_ERROR_NOT_SET
:
1391 bad_error("scf_scope_get_service", scf_error());
1394 if (scf_scope_add_service(scope
, sstr
, svc
) != 0) {
1395 switch (scf_error()) {
1396 case SCF_ERROR_CONNECTION_BROKEN
:
1400 case SCF_ERROR_DELETED
:
1403 case SCF_ERROR_PERMISSION_DENIED
:
1404 case SCF_ERROR_BACKEND_READONLY
:
1405 case SCF_ERROR_BACKEND_ACCESS
:
1409 case SCF_ERROR_HANDLE_MISMATCH
:
1410 case SCF_ERROR_INVALID_ARGUMENT
:
1411 case SCF_ERROR_NOT_BOUND
:
1412 case SCF_ERROR_NOT_SET
:
1414 bad_error("scf_scope_get_service", scf_error());
1420 scfe
= SCF_ERROR_NONE
;
1427 if (scf_service_get_instance(svc
, istr
, inst
) != 0) {
1428 switch (scf_error()) {
1429 case SCF_ERROR_CONNECTION_BROKEN
:
1433 case SCF_ERROR_DELETED
:
1436 case SCF_ERROR_NOT_FOUND
:
1439 case SCF_ERROR_HANDLE_MISMATCH
:
1440 case SCF_ERROR_INVALID_ARGUMENT
:
1441 case SCF_ERROR_NOT_BOUND
:
1442 case SCF_ERROR_NOT_SET
:
1444 bad_error("scf_service_get_instance", scf_error());
1447 if (scf_service_add_instance(svc
, istr
, inst
) != 0) {
1448 switch (scf_error()) {
1449 case SCF_ERROR_CONNECTION_BROKEN
:
1453 case SCF_ERROR_DELETED
:
1456 case SCF_ERROR_PERMISSION_DENIED
:
1457 case SCF_ERROR_BACKEND_READONLY
:
1458 case SCF_ERROR_BACKEND_ACCESS
:
1462 case SCF_ERROR_HANDLE_MISMATCH
:
1463 case SCF_ERROR_INVALID_ARGUMENT
:
1464 case SCF_ERROR_NOT_BOUND
:
1465 case SCF_ERROR_NOT_SET
:
1467 bad_error("scf_service_add_instance",
1473 scfe
= SCF_ERROR_NONE
;
1479 scf_instance_destroy(inst
);
1481 scf_service_destroy(svc
);
1482 scf_scope_destroy(scope
);
1488 * Create or update a snapshot of inst. snap is a required scratch object.
1492 * ECONNABORTED - repository connection broken
1493 * EPERM - permission denied
1494 * ENOSPC - configd is out of resources
1495 * ECANCELED - inst was deleted
1496 * -1 - unknown libscf error (message printed)
1499 take_snap(scf_instance_t
*inst
, const char *name
, scf_snapshot_t
*snap
)
1502 if (scf_instance_get_snapshot(inst
, name
, snap
) == 0) {
1503 if (_scf_snapshot_take_attach(inst
, snap
) != 0) {
1504 switch (scf_error()) {
1505 case SCF_ERROR_CONNECTION_BROKEN
:
1506 case SCF_ERROR_PERMISSION_DENIED
:
1507 case SCF_ERROR_NO_RESOURCES
:
1508 return (scferror2errno(scf_error()));
1510 case SCF_ERROR_NOT_SET
:
1511 case SCF_ERROR_INVALID_ARGUMENT
:
1513 bad_error("_scf_snapshot_take_attach",
1518 switch (scf_error()) {
1519 case SCF_ERROR_NOT_FOUND
:
1522 case SCF_ERROR_DELETED
:
1523 case SCF_ERROR_CONNECTION_BROKEN
:
1524 return (scferror2errno(scf_error()));
1526 case SCF_ERROR_HANDLE_MISMATCH
:
1527 case SCF_ERROR_NOT_BOUND
:
1528 case SCF_ERROR_INVALID_ARGUMENT
:
1529 case SCF_ERROR_NOT_SET
:
1531 bad_error("scf_instance_get_snapshot", scf_error());
1534 if (_scf_snapshot_take_new(inst
, name
, snap
) != 0) {
1535 switch (scf_error()) {
1536 case SCF_ERROR_EXISTS
:
1539 case SCF_ERROR_CONNECTION_BROKEN
:
1540 case SCF_ERROR_NO_RESOURCES
:
1541 case SCF_ERROR_PERMISSION_DENIED
:
1542 return (scferror2errno(scf_error()));
1548 case SCF_ERROR_NOT_SET
:
1549 case SCF_ERROR_INTERNAL
:
1550 case SCF_ERROR_INVALID_ARGUMENT
:
1551 case SCF_ERROR_HANDLE_MISMATCH
:
1552 bad_error("_scf_snapshot_take_new",
1562 refresh_running_snapshot(void *entity
)
1564 scf_snapshot_t
*snap
;
1567 if ((snap
= scf_snapshot_create(g_hndl
)) == NULL
)
1569 r
= take_snap(entity
, snap_running
, snap
);
1570 scf_snapshot_destroy(snap
);
1576 * Refresh entity. If isservice is zero, take entity to be an scf_instance_t *.
1577 * Otherwise take entity to be an scf_service_t * and refresh all of its child
1578 * instances. fmri is used for messages. inst, iter, and name_buf are used
1579 * for scratch space. Returns
1581 * ECONNABORTED - repository connection broken
1582 * ECANCELED - entity was deleted
1583 * EACCES - backend denied access
1584 * EPERM - permission denied
1585 * ENOSPC - repository server out of resources
1586 * -1 - _smf_refresh_instance_i() failed. scf_error() should be set.
1589 refresh_entity(int isservice
, void *entity
, const char *fmri
,
1590 scf_instance_t
*inst
, scf_iter_t
*iter
, char *name_buf
)
1597 * Let restarter handles refreshing and making new running
1598 * snapshot only if operating on a live repository and not
1599 * running in early import.
1601 if (est
->sc_repo_filename
== NULL
&&
1602 est
->sc_repo_doorname
== NULL
&&
1603 est
->sc_in_emi
== 0) {
1604 if (_smf_refresh_instance_i(entity
) == 0) {
1606 warn(gettext("Refreshed %s.\n"), fmri
);
1610 switch (scf_error()) {
1611 case SCF_ERROR_BACKEND_ACCESS
:
1614 case SCF_ERROR_PERMISSION_DENIED
:
1621 r
= refresh_running_snapshot(entity
);
1633 bad_error("refresh_running_snapshot",
1641 if (scf_iter_service_instances(iter
, entity
) != 0) {
1642 switch (scf_error()) {
1643 case SCF_ERROR_CONNECTION_BROKEN
:
1644 return (ECONNABORTED
);
1646 case SCF_ERROR_DELETED
:
1649 case SCF_ERROR_HANDLE_MISMATCH
:
1650 case SCF_ERROR_NOT_BOUND
:
1651 case SCF_ERROR_NOT_SET
:
1653 bad_error("scf_iter_service_instances", scf_error());
1658 r
= scf_iter_next_instance(iter
, inst
);
1662 switch (scf_error()) {
1663 case SCF_ERROR_CONNECTION_BROKEN
:
1664 return (ECONNABORTED
);
1666 case SCF_ERROR_DELETED
:
1669 case SCF_ERROR_HANDLE_MISMATCH
:
1670 case SCF_ERROR_NOT_BOUND
:
1671 case SCF_ERROR_NOT_SET
:
1672 case SCF_ERROR_INVALID_ARGUMENT
:
1674 bad_error("scf_iter_next_instance",
1680 * Similarly, just take a new running snapshot if operating on
1681 * a non-live repository or running during early import.
1683 if (est
->sc_repo_filename
!= NULL
||
1684 est
->sc_repo_doorname
!= NULL
||
1685 est
->sc_in_emi
== 1) {
1686 r
= refresh_running_snapshot(inst
);
1697 bad_error("refresh_running_snapshot",
1705 if (_smf_refresh_instance_i(inst
) == 0) {
1707 if (scf_instance_get_name(inst
, name_buf
,
1708 max_scf_name_len
+ 1) < 0)
1709 (void) strcpy(name_buf
, "?");
1711 warn(gettext("Refreshed %s:%s.\n"),
1715 if (scf_error() != SCF_ERROR_BACKEND_ACCESS
||
1719 if (scf_instance_to_fmri(inst
, name_buf
,
1720 max_scf_name_len
+ 1) < 0)
1721 (void) strcpy(name_buf
, "?");
1724 "Refresh of %s:%s failed: %s.\n"), fmri
,
1725 name_buf
, scf_strerror(scfe
));
1734 private_refresh(void)
1736 scf_instance_t
*pinst
= NULL
;
1737 scf_iter_t
*piter
= NULL
;
1745 if (est
->sc_repo_filename
== NULL
&& est
->sc_repo_doorname
== NULL
)
1748 assert(cur_svc
!= NULL
);
1750 bufsz
= max_scf_fmri_len
+ 1;
1751 fmribuf
= safe_malloc(bufsz
);
1755 fmrilen
= scf_instance_to_fmri(ent
, fmribuf
, bufsz
);
1759 fmrilen
= scf_service_to_fmri(ent
, fmribuf
, bufsz
);
1760 if ((pinst
= scf_instance_create(g_hndl
)) == NULL
)
1763 if ((piter
= scf_iter_create(g_hndl
)) == NULL
)
1768 if (scf_error() != SCF_ERROR_DELETED
)
1774 assert(fmrilen
< bufsz
);
1776 r
= refresh_entity(issvc
, ent
, fmribuf
, pinst
, piter
, NULL
);
1782 warn(gettext("Could not refresh %s "
1783 "(repository connection broken).\n"), fmribuf
);
1791 warn(gettext("Could not refresh %s "
1792 "(permission denied).\n"), fmribuf
);
1796 warn(gettext("Could not refresh %s "
1797 "(repository server out of resources).\n"),
1803 bad_error("refresh_entity", scf_error());
1807 scf_instance_destroy(pinst
);
1808 scf_iter_destroy(piter
);
1816 stash_scferror_err(scf_callback_t
*cbp
, scf_error_t err
)
1818 cbp
->sc_err
= scferror2errno(err
);
1819 return (UU_WALK_ERROR
);
1823 stash_scferror(scf_callback_t
*cbp
)
1825 return (stash_scferror_err(cbp
, scf_error()));
1828 static int select_inst(const char *);
1829 static int select_svc(const char *);
1832 * Take a property that does not have a type and check to see if a type
1833 * exists or can be gleened from the current data. Set the type.
1835 * Check the current level (instance) and then check the higher level
1836 * (service). This could be the case for adding a new property to
1837 * the instance that's going to "override" a service level property.
1840 * 1. Take the type from an existing property
1841 * 2. Take the type from a template entry
1843 * If the type can not be found, then leave the type as is, and let the import
1844 * report the problem of the missing type.
1847 find_current_prop_type(void *p
, void *g
)
1849 property_t
*prop
= p
;
1850 scf_callback_t
*lcb
= g
;
1851 pgroup_t
*pg
= NULL
;
1853 const char *fmri
= NULL
;
1855 char *cur_selection
= NULL
;
1857 scf_propertygroup_t
*sc_pg
= NULL
;
1858 scf_property_t
*sc_prop
= NULL
;
1859 scf_pg_tmpl_t
*t_pg
= NULL
;
1860 scf_prop_tmpl_t
*t_prop
= NULL
;
1861 scf_type_t prop_type
;
1864 int issvc
= lcb
->sc_service
;
1865 int r
= UU_WALK_ERROR
;
1867 if (prop
->sc_value_type
!= SCF_TYPE_INVALID
)
1868 return (UU_WALK_NEXT
);
1870 t_prop
= scf_tmpl_prop_create(g_hndl
);
1871 sc_prop
= scf_property_create(g_hndl
);
1872 if (sc_prop
== NULL
|| t_prop
== NULL
) {
1873 warn(gettext("Unable to create the property to attempt and "
1874 "find a missing type.\n"));
1876 scf_property_destroy(sc_prop
);
1877 scf_tmpl_prop_destroy(t_prop
);
1879 return (UU_WALK_ERROR
);
1882 if (lcb
->sc_flags
== 1) {
1883 pg
= lcb
->sc_parent
;
1884 issvc
= (pg
->sc_parent
->sc_etype
== SVCCFG_SERVICE_OBJECT
);
1885 fmri
= pg
->sc_parent
->sc_fmri
;
1887 if (cur_svc
&& cur_selection
== NULL
) {
1888 cur_selection
= safe_malloc(max_scf_fmri_len
+ 1);
1889 lscf_get_selection_str(cur_selection
,
1890 max_scf_fmri_len
+ 1);
1892 if (strcmp(cur_selection
, fmri
) != 0) {
1895 free(cur_selection
);
1896 cur_selection
= NULL
;
1902 if (sc_pg
== NULL
&& (sc_pg
= scf_pg_create(g_hndl
)) == NULL
) {
1903 warn(gettext("Unable to create property group to "
1904 "find a missing property type.\n"));
1909 if (get_pg(pg
->sc_pgroup_name
, sc_pg
) != SCF_SUCCESS
) {
1911 * If this is the sc_pg from the parent
1912 * let the caller clean up the sc_pg,
1913 * and just throw it away in this case.
1915 if (sc_pg
!= lcb
->sc_parent
)
1916 scf_pg_destroy(sc_pg
);
1919 if ((t_pg
= scf_tmpl_pg_create(g_hndl
)) == NULL
) {
1920 warn(gettext("Unable to create template "
1921 "property group to find a property "
1927 if (scf_tmpl_get_by_pg_name(fmri
, NULL
,
1928 pg
->sc_pgroup_name
, NULL
, t_pg
,
1929 SCF_PG_TMPL_FLAG_EXACT
) != SCF_SUCCESS
) {
1931 * if instance get service and jump back
1933 scf_tmpl_pg_destroy(t_pg
);
1936 entity_t
*e
= pg
->sc_parent
->sc_parent
;
1947 sc_pg
= lcb
->sc_parent
;
1951 * Attempt to get the type from an existing property. If the property
1952 * cannot be found then attempt to get the type from a template entry
1955 * Finally, if at the instance level look at the service level.
1957 if (sc_pg
!= NULL
&&
1958 pg_get_prop(sc_pg
, prop
->sc_property_name
,
1959 sc_prop
) == SCF_SUCCESS
&&
1960 scf_property_type(sc_prop
, &prop_type
) == SCF_SUCCESS
) {
1961 prop
->sc_value_type
= prop_type
;
1964 * Found a type, update the value types and validate
1965 * the actual value against this type.
1967 for (vp
= uu_list_first(prop
->sc_property_values
);
1969 vp
= uu_list_next(prop
->sc_property_values
, vp
)) {
1970 vp
->sc_type
= prop
->sc_value_type
;
1971 lxml_store_value(vp
, 0, NULL
);
1979 * If we get here with t_pg set to NULL then we had to have
1980 * gotten an sc_pg but that sc_pg did not have the property
1981 * we are looking for. So if the t_pg is not null look up
1982 * the template entry for the property.
1984 * If the t_pg is null then need to attempt to get a matching
1985 * template entry for the sc_pg, and see if there is a property
1986 * entry for that template entry.
1990 scf_tmpl_get_by_prop(t_pg
, prop
->sc_property_name
,
1991 t_prop
, 0) == SCF_SUCCESS
) {
1992 if (scf_tmpl_prop_type(t_prop
, &prop_type
) == SCF_SUCCESS
) {
1993 prop
->sc_value_type
= prop_type
;
1996 * Found a type, update the value types and validate
1997 * the actual value against this type.
1999 for (vp
= uu_list_first(prop
->sc_property_values
);
2001 vp
= uu_list_next(prop
->sc_property_values
, vp
)) {
2002 vp
->sc_type
= prop
->sc_value_type
;
2003 lxml_store_value(vp
, 0, NULL
);
2010 if (t_pg
== NULL
&& sc_pg
) {
2011 if ((t_pg
= scf_tmpl_pg_create(g_hndl
)) == NULL
) {
2012 warn(gettext("Unable to create template "
2013 "property group to find a property "
2019 if (scf_tmpl_get_by_pg(sc_pg
, t_pg
, 0) != SCF_SUCCESS
) {
2020 scf_tmpl_pg_destroy(t_pg
);
2033 if (lcb
->sc_flags
== 1) {
2034 entity_t
*e
= pg
->sc_parent
->sc_parent
;
2041 * because lcb->sc_flags was not set then this means
2042 * the pg was not used and can be used here.
2044 if ((pg
= internal_pgroup_new()) == NULL
) {
2045 warn(gettext("Could not create internal property group "
2046 "to find a missing type."));
2051 pg
->sc_pgroup_name
= safe_malloc(max_scf_name_len
+ 1);
2052 if (scf_pg_get_name(sc_pg
, (char *)pg
->sc_pgroup_name
,
2053 max_scf_name_len
+ 1) < 0)
2056 i
= scf_instance_create(g_hndl
);
2057 s
= scf_service_create(g_hndl
);
2058 if (i
== NULL
|| s
== NULL
||
2059 scf_pg_get_parent_instance(sc_pg
, i
) != SCF_SUCCESS
) {
2060 warn(gettext("Could not get a service for the instance "
2061 "to find a missing type."));
2067 * Check to see truly at the instance level.
2069 lfmri
= safe_malloc(max_scf_fmri_len
+ 1);
2070 if (scf_instance_get_parent(i
, s
) == SCF_SUCCESS
&&
2071 scf_service_to_fmri(s
, lfmri
, max_scf_fmri_len
+ 1) < 0)
2074 fmri
= (const char *)lfmri
;
2080 if (sc_pg
!= lcb
->sc_parent
) {
2081 scf_pg_destroy(sc_pg
);
2085 * If this is true then the pg was allocated
2086 * here, and the name was set so need to free
2087 * the name and the pg.
2089 if (pg
!= NULL
&& pg
!= lcb
->sc_parent
) {
2090 free((char *)pg
->sc_pgroup_name
);
2091 internal_pgroup_free(pg
);
2094 if (cur_selection
) {
2095 lscf_select(cur_selection
);
2096 free(cur_selection
);
2099 scf_tmpl_pg_destroy(t_pg
);
2100 scf_tmpl_prop_destroy(t_prop
);
2101 scf_property_destroy(sc_prop
);
2103 if (r
!= UU_WALK_NEXT
)
2104 warn(gettext("Could not find property type for \"%s\" "
2105 "from \"%s\"\n"), prop
->sc_property_name
,
2106 fmri
!= NULL
? fmri
: lcb
->sc_source_fmri
);
2114 * Take a property group that does not have a type and check to see if a type
2115 * exists or can be gleened from the current data. Set the type.
2117 * Check the current level (instance) and then check the higher level
2118 * (service). This could be the case for adding a new property to
2119 * the instance that's going to "override" a service level property.
2121 * For a property group
2122 * 1. Take the type from an existing property group
2123 * 2. Take the type from a template entry
2125 * If the type can not be found, then leave the type as is, and let the import
2126 * report the problem of the missing type.
2129 find_current_pg_type(void *p
, void *sori
)
2131 entity_t
*si
= sori
;
2134 const char *ofmri
, *fmri
;
2135 char *cur_selection
= NULL
;
2136 char *pg_type
= NULL
;
2138 scf_propertygroup_t
*sc_pg
= NULL
;
2139 scf_pg_tmpl_t
*t_pg
= NULL
;
2141 int issvc
= (si
->sc_etype
== SVCCFG_SERVICE_OBJECT
);
2142 int r
= UU_WALK_ERROR
;
2144 ofmri
= fmri
= si
->sc_fmri
;
2145 if (pg
->sc_pgroup_type
!= NULL
) {
2151 sc_pg
= scf_pg_create(g_hndl
);
2152 if (sc_pg
== NULL
) {
2153 warn(gettext("Unable to create property group to attempt "
2154 "and find a missing type.\n"));
2156 return (UU_WALK_ERROR
);
2160 * Using get_pg() requires that the cur_svc/cur_inst be
2161 * via lscf_select. Need to preserve the current selection
2162 * if going to use lscf_select() to set up the cur_svc/cur_inst
2165 cur_selection
= safe_malloc(max_scf_fmri_len
+ 1);
2166 lscf_get_selection_str(cur_selection
, max_scf_fmri_len
+ 1);
2170 * If the property group exists get the type, and set
2171 * the pgroup_t type of that type.
2173 * If not the check for a template pg_pattern entry
2174 * and take the type from that.
2179 if (get_pg(pg
->sc_pgroup_name
, sc_pg
) == SCF_SUCCESS
) {
2180 pg_type
= safe_malloc(max_scf_pg_type_len
+ 1);
2181 if (pg_type
!= NULL
&& scf_pg_get_type(sc_pg
, pg_type
,
2182 max_scf_pg_type_len
+ 1) != -1) {
2183 pg
->sc_pgroup_type
= pg_type
;
2191 if ((t_pg
== NULL
) &&
2192 (t_pg
= scf_tmpl_pg_create(g_hndl
)) == NULL
)
2195 if (scf_tmpl_get_by_pg_name(fmri
, NULL
, pg
->sc_pgroup_name
,
2196 NULL
, t_pg
, SCF_PG_TMPL_FLAG_EXACT
) == SCF_SUCCESS
&&
2197 scf_tmpl_pg_type(t_pg
, &pg_type
) != -1) {
2198 pg
->sc_pgroup_type
= pg_type
;
2206 * If type is not found at the instance level then attempt to
2207 * find the type at the service level.
2212 issvc
= (si
->sc_etype
== SVCCFG_SERVICE_OBJECT
);
2217 if (cur_selection
) {
2218 lscf_select(cur_selection
);
2219 free(cur_selection
);
2223 * Now walk the properties of the property group to make sure that
2224 * all properties have the correct type and values are valid for
2227 if (r
== UU_WALK_NEXT
) {
2230 cb
.sc_service
= issvc
;
2231 cb
.sc_source_fmri
= ofmri
;
2232 if (sc_pg
!= NULL
) {
2233 cb
.sc_parent
= sc_pg
;
2240 if (uu_list_walk(pg
->sc_pgroup_props
, find_current_prop_type
,
2241 &cb
, UU_DEFAULT
) != 0) {
2242 if (uu_error() != UU_ERROR_CALLBACK_FAILED
)
2243 bad_error("uu_list_walk", uu_error());
2248 warn(gettext("Could not find property group type for "
2249 "\"%s\" from \"%s\"\n"), pg
->sc_pgroup_name
, fmri
);
2252 scf_tmpl_pg_destroy(t_pg
);
2253 scf_pg_destroy(sc_pg
);
2259 * Import. These functions import a bundle into the repository.
2263 * Add a transaction entry to lcbdata->sc_trans for this property_t. Uses
2264 * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata. On success,
2265 * returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
2266 * lcbdata->sc_err to
2267 * ENOMEM - out of memory
2268 * ECONNABORTED - repository connection broken
2269 * ECANCELED - sc_trans's property group was deleted
2270 * EINVAL - p's name is invalid (error printed)
2271 * - p has an invalid value (error printed)
2274 lscf_property_import(void *v
, void *pvt
)
2277 scf_callback_t
*lcbdata
= pvt
;
2279 scf_transaction_t
*trans
= lcbdata
->sc_trans
;
2280 scf_transaction_entry_t
*entr
;
2284 if ((lcbdata
->sc_flags
& SCI_NOENABLED
||
2285 lcbdata
->sc_flags
& SCI_DELAYENABLE
) &&
2286 strcmp(p
->sc_property_name
, SCF_PROPERTY_ENABLED
) == 0) {
2287 lcbdata
->sc_enable
= p
;
2288 return (UU_WALK_NEXT
);
2291 entr
= scf_entry_create(lcbdata
->sc_handle
);
2293 switch (scf_error()) {
2294 case SCF_ERROR_NO_MEMORY
:
2295 return (stash_scferror(lcbdata
));
2297 case SCF_ERROR_INVALID_ARGUMENT
:
2299 bad_error("scf_entry_create", scf_error());
2303 tp
= p
->sc_value_type
;
2305 if (scf_transaction_property_new(trans
, entr
,
2306 p
->sc_property_name
, tp
) != 0) {
2307 switch (scf_error()) {
2308 case SCF_ERROR_INVALID_ARGUMENT
:
2309 semerr(emsg_invalid_prop_name
, p
->sc_property_name
);
2310 scf_entry_destroy(entr
);
2311 return (stash_scferror(lcbdata
));
2313 case SCF_ERROR_EXISTS
:
2316 case SCF_ERROR_DELETED
:
2317 case SCF_ERROR_CONNECTION_BROKEN
:
2318 scf_entry_destroy(entr
);
2319 return (stash_scferror(lcbdata
));
2321 case SCF_ERROR_NOT_BOUND
:
2322 case SCF_ERROR_HANDLE_MISMATCH
:
2323 case SCF_ERROR_NOT_SET
:
2325 bad_error("scf_transaction_property_new", scf_error());
2328 if (scf_transaction_property_change_type(trans
, entr
,
2329 p
->sc_property_name
, tp
) != 0) {
2330 switch (scf_error()) {
2331 case SCF_ERROR_DELETED
:
2332 case SCF_ERROR_CONNECTION_BROKEN
:
2333 scf_entry_destroy(entr
);
2334 return (stash_scferror(lcbdata
));
2336 case SCF_ERROR_INVALID_ARGUMENT
:
2337 semerr(emsg_invalid_prop_name
,
2338 p
->sc_property_name
);
2339 scf_entry_destroy(entr
);
2340 return (stash_scferror(lcbdata
));
2342 case SCF_ERROR_NOT_FOUND
:
2343 case SCF_ERROR_NOT_SET
:
2344 case SCF_ERROR_HANDLE_MISMATCH
:
2345 case SCF_ERROR_NOT_BOUND
:
2348 "scf_transaction_property_change_type",
2354 for (vp
= uu_list_first(p
->sc_property_values
);
2356 vp
= uu_list_next(p
->sc_property_values
, vp
)) {
2357 val
= scf_value_create(g_hndl
);
2359 switch (scf_error()) {
2360 case SCF_ERROR_NO_MEMORY
:
2361 return (stash_scferror(lcbdata
));
2363 case SCF_ERROR_INVALID_ARGUMENT
:
2365 bad_error("scf_value_create", scf_error());
2370 case SCF_TYPE_BOOLEAN
:
2371 scf_value_set_boolean(val
, vp
->sc_u
.sc_count
);
2373 case SCF_TYPE_COUNT
:
2374 scf_value_set_count(val
, vp
->sc_u
.sc_count
);
2376 case SCF_TYPE_INTEGER
:
2377 scf_value_set_integer(val
, vp
->sc_u
.sc_integer
);
2380 assert(vp
->sc_u
.sc_string
!= NULL
);
2381 if (scf_value_set_from_string(val
, tp
,
2382 vp
->sc_u
.sc_string
) != 0) {
2383 if (scf_error() != SCF_ERROR_INVALID_ARGUMENT
)
2384 bad_error("scf_value_set_from_string",
2387 warn(gettext("Value \"%s\" is not a valid "
2388 "%s.\n"), vp
->sc_u
.sc_string
,
2389 scf_type_to_string(tp
));
2390 scf_value_destroy(val
);
2391 return (stash_scferror(lcbdata
));
2396 if (scf_entry_add_value(entr
, val
) != 0)
2397 bad_error("scf_entry_add_value", scf_error());
2400 return (UU_WALK_NEXT
);
2404 * Import a pgroup_t into the repository. Uses sc_handle, sc_parent,
2405 * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2406 * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2407 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
2408 * lcbdata->sc_err to
2409 * ECONNABORTED - repository connection broken
2410 * ENOMEM - out of memory
2411 * ENOSPC - svc.configd is out of resources
2412 * ECANCELED - sc_parent was deleted
2413 * EPERM - could not create property group (permission denied) (error printed)
2414 * - could not modify property group (permission denied) (error printed)
2415 * - could not delete property group (permission denied) (error printed)
2416 * EROFS - could not create property group (repository is read-only)
2417 * - could not delete property group (repository is read-only)
2418 * EACCES - could not create property group (backend access denied)
2419 * - could not delete property group (backend access denied)
2420 * EEXIST - could not create property group (already exists)
2421 * EINVAL - invalid property group name (error printed)
2422 * - invalid property name (error printed)
2423 * - invalid value (error printed)
2424 * EBUSY - new property group deleted (error printed)
2425 * - new property group changed (error printed)
2426 * - property group added (error printed)
2427 * - property group deleted (error printed)
2430 entity_pgroup_import(void *v
, void *pvt
)
2433 scf_callback_t cbdata
;
2434 scf_callback_t
*lcbdata
= pvt
;
2435 void *ent
= lcbdata
->sc_parent
;
2436 int issvc
= lcbdata
->sc_service
;
2439 const char * const pg_changed
= gettext("%s changed unexpectedly "
2440 "(new property group \"%s\" changed).\n");
2442 /* Never import deleted property groups. */
2443 if (p
->sc_pgroup_delete
) {
2444 if ((lcbdata
->sc_flags
& SCI_OP_APPLY
) == SCI_OP_APPLY
&&
2445 entity_get_pg(ent
, issvc
, p
->sc_pgroup_name
, imp_pg
) == 0) {
2448 return (UU_WALK_NEXT
);
2451 if (!issvc
&& (lcbdata
->sc_flags
& SCI_GENERALLAST
) &&
2452 strcmp(p
->sc_pgroup_name
, SCF_PG_GENERAL
) == 0) {
2453 lcbdata
->sc_general
= p
;
2454 return (UU_WALK_NEXT
);
2459 r
= scf_service_add_pg(ent
, p
->sc_pgroup_name
,
2460 p
->sc_pgroup_type
, p
->sc_pgroup_flags
, imp_pg
);
2462 r
= scf_instance_add_pg(ent
, p
->sc_pgroup_name
,
2463 p
->sc_pgroup_type
, p
->sc_pgroup_flags
, imp_pg
);
2465 switch (scf_error()) {
2466 case SCF_ERROR_DELETED
:
2467 case SCF_ERROR_CONNECTION_BROKEN
:
2468 case SCF_ERROR_BACKEND_READONLY
:
2469 case SCF_ERROR_BACKEND_ACCESS
:
2470 case SCF_ERROR_NO_RESOURCES
:
2471 return (stash_scferror(lcbdata
));
2473 case SCF_ERROR_EXISTS
:
2474 if (lcbdata
->sc_flags
& SCI_FORCE
)
2476 return (stash_scferror(lcbdata
));
2478 case SCF_ERROR_INVALID_ARGUMENT
:
2479 warn(emsg_fmri_invalid_pg_name_type
,
2480 lcbdata
->sc_source_fmri
,
2481 p
->sc_pgroup_name
, p
->sc_pgroup_type
);
2482 return (stash_scferror(lcbdata
));
2484 case SCF_ERROR_PERMISSION_DENIED
:
2485 warn(emsg_pg_add_perm
, p
->sc_pgroup_name
,
2486 lcbdata
->sc_target_fmri
);
2487 return (stash_scferror(lcbdata
));
2489 case SCF_ERROR_NOT_BOUND
:
2490 case SCF_ERROR_HANDLE_MISMATCH
:
2491 case SCF_ERROR_NOT_SET
:
2493 bad_error("scf_service_add_pg", scf_error());
2496 if (entity_get_pg(ent
, issvc
, p
->sc_pgroup_name
, imp_pg
) != 0) {
2497 switch (scf_error()) {
2498 case SCF_ERROR_CONNECTION_BROKEN
:
2499 case SCF_ERROR_DELETED
:
2500 return (stash_scferror(lcbdata
));
2502 case SCF_ERROR_INVALID_ARGUMENT
:
2503 warn(emsg_fmri_invalid_pg_name
,
2504 lcbdata
->sc_source_fmri
,
2506 return (stash_scferror(lcbdata
));
2508 case SCF_ERROR_NOT_FOUND
:
2509 warn(emsg_pg_deleted
, lcbdata
->sc_target_fmri
,
2511 lcbdata
->sc_err
= EBUSY
;
2512 return (UU_WALK_ERROR
);
2514 case SCF_ERROR_NOT_BOUND
:
2515 case SCF_ERROR_HANDLE_MISMATCH
:
2516 case SCF_ERROR_NOT_SET
:
2518 bad_error("entity_get_pg", scf_error());
2522 if (lcbdata
->sc_flags
& SCI_KEEP
)
2526 if (scf_pg_delete(imp_pg
) != 0) {
2527 switch (scf_error()) {
2528 case SCF_ERROR_DELETED
:
2529 warn(emsg_pg_deleted
, lcbdata
->sc_target_fmri
,
2531 lcbdata
->sc_err
= EBUSY
;
2532 return (UU_WALK_ERROR
);
2534 case SCF_ERROR_PERMISSION_DENIED
:
2535 warn(emsg_pg_del_perm
, p
->sc_pgroup_name
,
2536 lcbdata
->sc_target_fmri
);
2537 return (stash_scferror(lcbdata
));
2539 case SCF_ERROR_BACKEND_READONLY
:
2540 case SCF_ERROR_BACKEND_ACCESS
:
2541 case SCF_ERROR_CONNECTION_BROKEN
:
2542 return (stash_scferror(lcbdata
));
2544 case SCF_ERROR_NOT_SET
:
2546 bad_error("scf_pg_delete", scf_error());
2550 if (p
->sc_pgroup_delete
)
2551 return (UU_WALK_NEXT
);
2559 * Add properties to property group, if any.
2561 cbdata
.sc_handle
= lcbdata
->sc_handle
;
2562 cbdata
.sc_parent
= imp_pg
;
2563 cbdata
.sc_flags
= lcbdata
->sc_flags
;
2564 cbdata
.sc_trans
= imp_tx
;
2565 cbdata
.sc_enable
= NULL
;
2567 if (scf_transaction_start(imp_tx
, imp_pg
) != 0) {
2568 switch (scf_error()) {
2569 case SCF_ERROR_BACKEND_ACCESS
:
2570 case SCF_ERROR_BACKEND_READONLY
:
2571 case SCF_ERROR_CONNECTION_BROKEN
:
2572 return (stash_scferror(lcbdata
));
2574 case SCF_ERROR_DELETED
:
2575 warn(pg_changed
, lcbdata
->sc_target_fmri
,
2577 lcbdata
->sc_err
= EBUSY
;
2578 return (UU_WALK_ERROR
);
2580 case SCF_ERROR_PERMISSION_DENIED
:
2581 warn(emsg_pg_mod_perm
, p
->sc_pgroup_name
,
2582 lcbdata
->sc_target_fmri
);
2583 return (stash_scferror(lcbdata
));
2585 case SCF_ERROR_NOT_BOUND
:
2586 case SCF_ERROR_NOT_SET
:
2587 case SCF_ERROR_IN_USE
:
2588 case SCF_ERROR_HANDLE_MISMATCH
:
2590 bad_error("scf_transaction_start", scf_error());
2594 if (uu_list_walk(p
->sc_pgroup_props
, lscf_property_import
, &cbdata
,
2596 if (uu_error() != UU_ERROR_CALLBACK_FAILED
)
2597 bad_error("uu_list_walk", uu_error());
2598 scf_transaction_reset(imp_tx
);
2600 lcbdata
->sc_err
= cbdata
.sc_err
;
2601 if (cbdata
.sc_err
== ECANCELED
) {
2602 warn(pg_changed
, lcbdata
->sc_target_fmri
,
2604 lcbdata
->sc_err
= EBUSY
;
2606 return (UU_WALK_ERROR
);
2609 if ((lcbdata
->sc_flags
& SCI_DELAYENABLE
) && cbdata
.sc_enable
) {
2610 cbdata
.sc_flags
= cbdata
.sc_flags
& (~SCI_DELAYENABLE
);
2613 * take the snapshot running snapshot then
2614 * import the stored general/enable property
2616 r
= take_snap(ent
, snap_running
, imp_rsnap
);
2622 warn(gettext("Could not take %s snapshot on import "
2623 "(repository connection broken).\n"),
2625 lcbdata
->sc_err
= r
;
2626 return (UU_WALK_ERROR
);
2629 lcbdata
->sc_err
= r
;
2630 return (UU_WALK_ERROR
);
2633 warn(gettext("Could not take %s snapshot "
2634 "(permission denied).\n"), snap_running
);
2635 lcbdata
->sc_err
= r
;
2636 return (UU_WALK_ERROR
);
2639 warn(gettext("Could not take %s snapshot"
2640 "(repository server out of resources).\n"),
2642 lcbdata
->sc_err
= r
;
2643 return (UU_WALK_ERROR
);
2646 bad_error("take_snap", r
);
2649 r
= lscf_property_import(cbdata
.sc_enable
, &cbdata
);
2650 if (r
!= UU_WALK_NEXT
) {
2651 if (r
!= UU_WALK_ERROR
)
2652 bad_error("lscf_property_import", r
);
2657 r
= scf_transaction_commit(imp_tx
);
2664 warn(pg_changed
, lcbdata
->sc_target_fmri
, p
->sc_pgroup_name
);
2665 lcbdata
->sc_err
= EBUSY
;
2670 switch (scf_error()) {
2671 case SCF_ERROR_BACKEND_READONLY
:
2672 case SCF_ERROR_BACKEND_ACCESS
:
2673 case SCF_ERROR_CONNECTION_BROKEN
:
2674 case SCF_ERROR_NO_RESOURCES
:
2675 r
= stash_scferror(lcbdata
);
2678 case SCF_ERROR_DELETED
:
2679 warn(emsg_pg_deleted
, lcbdata
->sc_target_fmri
,
2681 lcbdata
->sc_err
= EBUSY
;
2685 case SCF_ERROR_PERMISSION_DENIED
:
2686 warn(emsg_pg_mod_perm
, p
->sc_pgroup_name
,
2687 lcbdata
->sc_target_fmri
);
2688 r
= stash_scferror(lcbdata
);
2691 case SCF_ERROR_NOT_SET
:
2692 case SCF_ERROR_INVALID_ARGUMENT
:
2693 case SCF_ERROR_NOT_BOUND
:
2695 bad_error("scf_transaction_commit", scf_error());
2700 bad_error("scf_transaction_commit", r
);
2703 scf_transaction_destroy_children(imp_tx
);
2711 * ECONNABORTED - repository connection broken
2712 * ENOMEM - out of memory
2713 * ENOSPC - svc.configd is out of resources
2714 * ECANCELED - inst was deleted
2715 * EPERM - could not create property group (permission denied) (error printed)
2716 * - could not modify property group (permission denied) (error printed)
2717 * EROFS - could not create property group (repository is read-only)
2718 * EACCES - could not create property group (backend access denied)
2719 * EEXIST - could not create property group (already exists)
2720 * EINVAL - invalid property group name (error printed)
2721 * - invalid property name (error printed)
2722 * - invalid value (error printed)
2723 * EBUSY - new property group changed (error printed)
2726 lscf_import_service_pgs(scf_service_t
*svc
, const char *target_fmri
,
2727 const entity_t
*isvc
, int flags
)
2729 scf_callback_t cbdata
;
2731 cbdata
.sc_handle
= scf_service_handle(svc
);
2732 cbdata
.sc_parent
= svc
;
2733 cbdata
.sc_service
= 1;
2734 cbdata
.sc_general
= 0;
2735 cbdata
.sc_enable
= 0;
2736 cbdata
.sc_flags
= flags
;
2737 cbdata
.sc_source_fmri
= isvc
->sc_fmri
;
2738 cbdata
.sc_target_fmri
= target_fmri
;
2741 * If the op is set, then add the flag to the callback
2742 * flags for later use.
2744 if (isvc
->sc_op
!= SVCCFG_OP_NONE
) {
2745 switch (isvc
->sc_op
) {
2746 case SVCCFG_OP_IMPORT
:
2747 cbdata
.sc_flags
|= SCI_OP_IMPORT
;
2749 case SVCCFG_OP_APPLY
:
2750 cbdata
.sc_flags
|= SCI_OP_APPLY
;
2752 case SVCCFG_OP_RESTORE
:
2753 cbdata
.sc_flags
|= SCI_OP_RESTORE
;
2756 uu_die(gettext("lscf_import_service_pgs : "
2757 "Unknown op stored in the service entity\n"));
2762 if (uu_list_walk(isvc
->sc_pgroups
, entity_pgroup_import
, &cbdata
,
2764 if (uu_error() != UU_ERROR_CALLBACK_FAILED
)
2765 bad_error("uu_list_walk", uu_error());
2767 return (cbdata
.sc_err
);
2776 * ECONNABORTED - repository connection broken
2777 * ENOMEM - out of memory
2778 * ENOSPC - svc.configd is out of resources
2779 * ECANCELED - inst was deleted
2780 * EPERM - could not create property group (permission denied) (error printed)
2781 * - could not modify property group (permission denied) (error printed)
2782 * EROFS - could not create property group (repository is read-only)
2783 * EACCES - could not create property group (backend access denied)
2784 * EEXIST - could not create property group (already exists)
2785 * EINVAL - invalid property group name (error printed)
2786 * - invalid property name (error printed)
2787 * - invalid value (error printed)
2788 * EBUSY - new property group changed (error printed)
2791 lscf_import_instance_pgs(scf_instance_t
*inst
, const char *target_fmri
,
2792 const entity_t
*iinst
, int flags
)
2794 scf_callback_t cbdata
;
2796 cbdata
.sc_handle
= scf_instance_handle(inst
);
2797 cbdata
.sc_parent
= inst
;
2798 cbdata
.sc_service
= 0;
2799 cbdata
.sc_general
= NULL
;
2800 cbdata
.sc_enable
= NULL
;
2801 cbdata
.sc_flags
= flags
;
2802 cbdata
.sc_source_fmri
= iinst
->sc_fmri
;
2803 cbdata
.sc_target_fmri
= target_fmri
;
2806 * If the op is set, then add the flag to the callback
2807 * flags for later use.
2809 if (iinst
->sc_op
!= SVCCFG_OP_NONE
) {
2810 switch (iinst
->sc_op
) {
2811 case SVCCFG_OP_IMPORT
:
2812 cbdata
.sc_flags
|= SCI_OP_IMPORT
;
2814 case SVCCFG_OP_APPLY
:
2815 cbdata
.sc_flags
|= SCI_OP_APPLY
;
2817 case SVCCFG_OP_RESTORE
:
2818 cbdata
.sc_flags
|= SCI_OP_RESTORE
;
2821 uu_die(gettext("lscf_import_instance_pgs : "
2822 "Unknown op stored in the instance entity\n"));
2826 if (uu_list_walk(iinst
->sc_pgroups
, entity_pgroup_import
, &cbdata
,
2828 if (uu_error() != UU_ERROR_CALLBACK_FAILED
)
2829 bad_error("uu_list_walk", uu_error());
2831 return (cbdata
.sc_err
);
2834 if ((flags
& SCI_GENERALLAST
) && cbdata
.sc_general
) {
2835 cbdata
.sc_flags
= flags
& (~SCI_GENERALLAST
);
2837 * If importing with the SCI_NOENABLED flag then
2838 * skip the delay, but if not then add the delay
2839 * of the enable property.
2841 if (!(cbdata
.sc_flags
& SCI_NOENABLED
)) {
2842 cbdata
.sc_flags
|= SCI_DELAYENABLE
;
2845 if (entity_pgroup_import(cbdata
.sc_general
, &cbdata
)
2847 return (cbdata
.sc_err
);
2854 * Report the reasons why we can't upgrade pg2 to pg1.
2857 report_pg_diffs(const pgroup_t
*pg1
, const pgroup_t
*pg2
, const char *fmri
,
2860 property_t
*p1
, *p2
;
2862 assert(strcmp(pg1
->sc_pgroup_name
, pg2
->sc_pgroup_name
) == 0);
2864 if (!pg_attrs_equal(pg1
, pg2
, fmri
, new))
2867 for (p1
= uu_list_first(pg1
->sc_pgroup_props
);
2869 p1
= uu_list_next(pg1
->sc_pgroup_props
, p1
)) {
2870 p2
= uu_list_find(pg2
->sc_pgroup_props
, p1
, NULL
, NULL
);
2872 (void) prop_equal(p1
, p2
, fmri
, pg1
->sc_pgroup_name
,
2878 warn(gettext("Conflict upgrading %s (new property "
2879 "group \"%s\" is missing property \"%s\").\n"),
2880 fmri
, pg1
->sc_pgroup_name
, p1
->sc_property_name
);
2882 warn(gettext("Conflict upgrading %s (property "
2883 "\"%s/%s\" is missing).\n"), fmri
,
2884 pg1
->sc_pgroup_name
, p1
->sc_property_name
);
2888 * Since pg1 should be from the manifest, any properties in pg2 which
2889 * aren't in pg1 shouldn't be reported as conflicts.
2894 * Add transaction entries to tx which will upgrade cur's pg according to old
2899 * EINVAL - new has a property with an invalid name or value (message emitted)
2900 * ENOMEM - out of memory
2903 add_upgrade_entries(scf_transaction_t
*tx
, pgroup_t
*old
, pgroup_t
*new,
2904 pgroup_t
*cur
, int speak
, const char *fmri
)
2906 property_t
*p
, *new_p
, *cur_p
;
2907 scf_transaction_entry_t
*e
;
2912 if (uu_list_walk(new->sc_pgroup_props
, clear_int
,
2913 (void *)offsetof(property_t
, sc_seen
), UU_DEFAULT
) != 0)
2914 bad_error("uu_list_walk", uu_error());
2916 is_general
= strcmp(old
->sc_pgroup_name
, SCF_PG_GENERAL
) == 0;
2918 for (p
= uu_list_first(old
->sc_pgroup_props
);
2920 p
= uu_list_next(old
->sc_pgroup_props
, p
)) {
2921 /* p is a property in the old property group. */
2923 /* Protect live properties. */
2926 if (strcmp(p
->sc_property_name
, SCF_PROPERTY_ENABLED
) ==
2928 strcmp(p
->sc_property_name
,
2929 SCF_PROPERTY_RESTARTER
) == 0)
2933 /* Look for the same property in the new properties. */
2934 new_p
= uu_list_find(new->sc_pgroup_props
, p
, NULL
, NULL
);
2935 if (new_p
!= NULL
) {
2939 * If the new property is the same as the old, don't do
2940 * anything (leave any user customizations).
2942 if (prop_equal(p
, new_p
, NULL
, NULL
, 0))
2945 if (new_p
->sc_property_override
)
2949 cur_p
= uu_list_find(cur
->sc_pgroup_props
, p
, NULL
, NULL
);
2950 if (cur_p
== NULL
) {
2952 * p has been deleted from the repository. If we were
2953 * going to delete it anyway, do nothing. Otherwise
2954 * report a conflict.
2962 warn(gettext("Conflict upgrading %s "
2963 "(property \"%s/%s\" is missing).\n"), fmri
,
2964 old
->sc_pgroup_name
, p
->sc_property_name
);
2968 if (!prop_equal(p
, cur_p
, NULL
, NULL
, 0)) {
2970 * Conflict. Don't warn if the property is already the
2971 * way we want it, though.
2977 (void) prop_equal(p
, cur_p
, fmri
,
2978 old
->sc_pgroup_name
, 0);
2980 (void) prop_equal(cur_p
, new_p
, fmri
,
2981 old
->sc_pgroup_name
, 0);
2987 warn(gettext("%s: Refusing to upgrade "
2988 "\"%s/%s\" (live property).\n"), fmri
,
2989 old
->sc_pgroup_name
, p
->sc_property_name
);
2994 /* p hasn't been customized in the repository. Upgrade it. */
2995 if (new_p
== NULL
) {
2996 /* p was deleted. Delete from cur if unchanged. */
2999 "%s: Deleting property \"%s/%s\".\n"),
3000 fmri
, old
->sc_pgroup_name
,
3001 p
->sc_property_name
);
3003 e
= scf_entry_create(g_hndl
);
3007 if (scf_transaction_property_delete(tx
, e
,
3008 p
->sc_property_name
) != 0) {
3009 switch (scf_error()) {
3010 case SCF_ERROR_DELETED
:
3011 scf_entry_destroy(e
);
3014 case SCF_ERROR_CONNECTION_BROKEN
:
3015 scf_entry_destroy(e
);
3016 return (ECONNABORTED
);
3018 case SCF_ERROR_NOT_FOUND
:
3020 * This can happen if cur is from the
3021 * running snapshot (and it differs
3022 * from the live properties).
3024 scf_entry_destroy(e
);
3027 case SCF_ERROR_HANDLE_MISMATCH
:
3028 case SCF_ERROR_NOT_BOUND
:
3029 case SCF_ERROR_NOT_SET
:
3030 case SCF_ERROR_INVALID_ARGUMENT
:
3033 "scf_transaction_property_delete",
3042 "%s: Upgrading property \"%s/%s\".\n"),
3043 fmri
, old
->sc_pgroup_name
,
3044 p
->sc_property_name
);
3046 ctx
.sc_handle
= g_hndl
;
3050 r
= lscf_property_import(new_p
, &ctx
);
3051 if (r
!= UU_WALK_NEXT
) {
3052 if (r
!= UU_WALK_ERROR
)
3053 bad_error("lscf_property_import", r
);
3059 /* Go over the properties which were added. */
3060 for (new_p
= uu_list_first(new->sc_pgroup_props
);
3062 new_p
= uu_list_next(new->sc_pgroup_props
, new_p
)) {
3066 /* This is a new property. */
3067 cur_p
= uu_list_find(cur
->sc_pgroup_props
, new_p
, NULL
, NULL
);
3068 if (cur_p
== NULL
) {
3071 ctx
.sc_handle
= g_hndl
;
3075 r
= lscf_property_import(new_p
, &ctx
);
3076 if (r
!= UU_WALK_NEXT
) {
3077 if (r
!= UU_WALK_ERROR
)
3078 bad_error("lscf_property_import", r
);
3085 * Report a conflict if the new property differs from the
3086 * current one. Unless it's general/enabled, since that's
3087 * never in the last-import snapshot.
3089 if (strcmp(new_p
->sc_property_name
, SCF_PROPERTY_ENABLED
) ==
3091 strcmp(cur
->sc_pgroup_name
, SCF_PG_GENERAL
) == 0)
3094 (void) prop_equal(cur_p
, new_p
, fmri
, old
->sc_pgroup_name
, 1);
3101 * Upgrade pg according to old & new.
3105 * ECONNABORTED - repository connection broken
3106 * ENOMEM - out of memory
3107 * ENOSPC - svc.configd is out of resources
3108 * ECANCELED - pg was deleted
3109 * EPERM - couldn't modify pg (permission denied)
3110 * EROFS - couldn't modify pg (backend read-only)
3111 * EACCES - couldn't modify pg (backend access denied)
3112 * EINVAL - new has a property with invalid name or value (error printed)
3113 * EBUSY - pg changed unexpectedly
3116 upgrade_pg(scf_propertygroup_t
*pg
, pgroup_t
*cur
, pgroup_t
*old
,
3117 pgroup_t
*new, int speak
, const char *fmri
)
3121 if (scf_transaction_start(imp_tx
, pg
) != 0) {
3122 switch (scf_error()) {
3123 case SCF_ERROR_CONNECTION_BROKEN
:
3124 case SCF_ERROR_DELETED
:
3125 case SCF_ERROR_PERMISSION_DENIED
:
3126 case SCF_ERROR_BACKEND_READONLY
:
3127 case SCF_ERROR_BACKEND_ACCESS
:
3128 return (scferror2errno(scf_error()));
3130 case SCF_ERROR_HANDLE_MISMATCH
:
3131 case SCF_ERROR_IN_USE
:
3132 case SCF_ERROR_NOT_BOUND
:
3133 case SCF_ERROR_NOT_SET
:
3135 bad_error("scf_transaction_start", scf_error());
3139 r
= add_upgrade_entries(imp_tx
, old
, new, cur
, speak
, fmri
);
3146 scf_transaction_destroy_children(imp_tx
);
3150 bad_error("add_upgrade_entries", r
);
3153 r
= scf_transaction_commit(imp_tx
);
3155 scf_transaction_destroy_children(imp_tx
);
3165 switch (scf_error()) {
3166 case SCF_ERROR_CONNECTION_BROKEN
:
3167 case SCF_ERROR_NO_RESOURCES
:
3168 case SCF_ERROR_PERMISSION_DENIED
:
3169 case SCF_ERROR_BACKEND_READONLY
:
3170 case SCF_ERROR_BACKEND_ACCESS
:
3171 case SCF_ERROR_DELETED
:
3172 return (scferror2errno(scf_error()));
3174 case SCF_ERROR_NOT_BOUND
:
3175 case SCF_ERROR_INVALID_ARGUMENT
:
3176 case SCF_ERROR_NOT_SET
:
3178 bad_error("scf_transaction_commit", scf_error());
3182 bad_error("scf_transaction_commit", r
);
3189 * Compares two entity FMRIs. Returns
3193 * -1 - f1 is invalid or not an entity
3194 * -2 - f2 is invalid or not an entity
3197 fmri_equal(const char *f1
, const char *f2
)
3200 const char *s1
, *i1
, *pg1
;
3201 const char *s2
, *i2
, *pg2
;
3203 if (strlcpy(imp_fe1
, f1
, max_scf_fmri_len
+ 1) >= max_scf_fmri_len
+ 1)
3205 if (scf_parse_svc_fmri(imp_fe1
, NULL
, &s1
, &i1
, &pg1
, NULL
) != 0)
3208 if (s1
== NULL
|| pg1
!= NULL
)
3211 if (strlcpy(imp_fe2
, f2
, max_scf_fmri_len
+ 1) >= max_scf_fmri_len
+ 1)
3213 if (scf_parse_svc_fmri(imp_fe2
, NULL
, &s2
, &i2
, &pg2
, NULL
) != 0)
3216 if (s2
== NULL
|| pg2
!= NULL
)
3223 if (i1
== NULL
&& i2
== NULL
)
3226 if (i1
== NULL
|| i2
== NULL
)
3229 return (strcmp(i1
, i2
) == 0);
3233 * Import a dependent by creating a dependency property group in the dependent
3234 * entity. If lcbdata->sc_trans is set, assume it's been started on the
3235 * dependents pg, and add an entry to create a new property for this
3236 * dependent. Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3238 * On success, returns UU_WALK_NEXT. On error, returns UU_WALK_ERROR and sets
3239 * lcbdata->sc_err to
3240 * ECONNABORTED - repository connection broken
3241 * ENOMEM - out of memory
3242 * ENOSPC - configd is out of resources
3243 * EINVAL - target is invalid (error printed)
3244 * - target is not an entity (error printed)
3245 * - dependent has invalid name (error printed)
3246 * - invalid property name (error printed)
3247 * - invalid value (error printed)
3248 * - scope of target does not exist (error printed)
3249 * EPERM - couldn't create target (permission denied) (error printed)
3250 * - couldn't create dependency pg (permission denied) (error printed)
3251 * - couldn't modify dependency pg (permission denied) (error printed)
3252 * EROFS - couldn't create target (repository read-only)
3253 * - couldn't create dependency pg (repository read-only)
3254 * EACCES - couldn't create target (backend access denied)
3255 * - couldn't create dependency pg (backend access denied)
3256 * ECANCELED - sc_trans's pg was deleted
3257 * EALREADY - property for dependent already exists in sc_trans's pg
3258 * EEXIST - dependency pg already exists in target (error printed)
3259 * EBUSY - target deleted (error printed)
3260 * - property group changed during import (error printed)
3263 lscf_dependent_import(void *a1
, void *pvt
)
3265 pgroup_t
*pgrp
= a1
;
3266 scf_callback_t
*lcbdata
= pvt
;
3270 scf_transaction_entry_t
*e
;
3272 scf_callback_t dependent_cbdata
;
3276 * Decode the FMRI into dependent_cbdata->sc_parent. Do it here so if
3277 * it's invalid, we fail before modifying the repository.
3279 scfe
= fmri_to_entity(lcbdata
->sc_handle
, pgrp
->sc_pgroup_fmri
,
3280 &dependent_cbdata
.sc_parent
, &isservice
);
3282 case SCF_ERROR_NONE
:
3285 case SCF_ERROR_NO_MEMORY
:
3286 return (stash_scferror_err(lcbdata
, scfe
));
3288 case SCF_ERROR_INVALID_ARGUMENT
:
3289 semerr(gettext("The FMRI for the \"%s\" dependent is "
3290 "invalid.\n"), pgrp
->sc_pgroup_name
);
3291 return (stash_scferror_err(lcbdata
, scfe
));
3293 case SCF_ERROR_CONSTRAINT_VIOLATED
:
3294 semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3295 "specifies neither a service nor an instance.\n"),
3296 pgrp
->sc_pgroup_fmri
, pgrp
->sc_pgroup_name
);
3297 return (stash_scferror_err(lcbdata
, scfe
));
3299 case SCF_ERROR_NOT_FOUND
:
3300 scfe
= create_entity(lcbdata
->sc_handle
, pgrp
->sc_pgroup_fmri
,
3301 &dependent_cbdata
.sc_parent
, &isservice
);
3303 case SCF_ERROR_NONE
:
3306 case SCF_ERROR_NO_MEMORY
:
3307 case SCF_ERROR_BACKEND_READONLY
:
3308 case SCF_ERROR_BACKEND_ACCESS
:
3309 return (stash_scferror_err(lcbdata
, scfe
));
3311 case SCF_ERROR_NOT_FOUND
:
3312 semerr(gettext("The scope in FMRI \"%s\" for the "
3313 "\"%s\" dependent does not exist.\n"),
3314 pgrp
->sc_pgroup_fmri
, pgrp
->sc_pgroup_name
);
3315 lcbdata
->sc_err
= EINVAL
;
3316 return (UU_WALK_ERROR
);
3318 case SCF_ERROR_PERMISSION_DENIED
:
3320 "Could not create %s (permission denied).\n"),
3321 pgrp
->sc_pgroup_fmri
);
3322 return (stash_scferror_err(lcbdata
, scfe
));
3324 case SCF_ERROR_INVALID_ARGUMENT
:
3325 case SCF_ERROR_CONSTRAINT_VIOLATED
:
3327 bad_error("create_entity", scfe
);
3332 bad_error("fmri_to_entity", scfe
);
3335 if (lcbdata
->sc_trans
!= NULL
) {
3336 e
= scf_entry_create(lcbdata
->sc_handle
);
3338 if (scf_error() != SCF_ERROR_NO_MEMORY
)
3339 bad_error("scf_entry_create", scf_error());
3341 entity_destroy(dependent_cbdata
.sc_parent
, isservice
);
3342 return (stash_scferror(lcbdata
));
3345 if (scf_transaction_property_new(lcbdata
->sc_trans
, e
,
3346 pgrp
->sc_pgroup_name
, SCF_TYPE_FMRI
) != 0) {
3347 switch (scf_error()) {
3348 case SCF_ERROR_INVALID_ARGUMENT
:
3349 warn(gettext("Dependent of %s has invalid name "
3350 "\"%s\".\n"), pgrp
->sc_parent
->sc_fmri
,
3351 pgrp
->sc_pgroup_name
);
3354 case SCF_ERROR_DELETED
:
3355 case SCF_ERROR_CONNECTION_BROKEN
:
3356 scf_entry_destroy(e
);
3357 entity_destroy(dependent_cbdata
.sc_parent
,
3359 return (stash_scferror(lcbdata
));
3361 case SCF_ERROR_EXISTS
:
3362 scf_entry_destroy(e
);
3363 entity_destroy(dependent_cbdata
.sc_parent
,
3365 lcbdata
->sc_err
= EALREADY
;
3366 return (UU_WALK_ERROR
);
3368 case SCF_ERROR_NOT_BOUND
:
3369 case SCF_ERROR_HANDLE_MISMATCH
:
3370 case SCF_ERROR_NOT_SET
:
3372 bad_error("scf_transaction_property_new",
3377 val
= scf_value_create(lcbdata
->sc_handle
);
3379 if (scf_error() != SCF_ERROR_NO_MEMORY
)
3380 bad_error("scf_value_create", scf_error());
3382 entity_destroy(dependent_cbdata
.sc_parent
, isservice
);
3383 return (stash_scferror(lcbdata
));
3386 if (scf_value_set_from_string(val
, SCF_TYPE_FMRI
,
3387 pgrp
->sc_pgroup_fmri
) != 0)
3388 /* invalid should have been caught above */
3389 bad_error("scf_value_set_from_string", scf_error());
3391 if (scf_entry_add_value(e
, val
) != 0)
3392 bad_error("scf_entry_add_value", scf_error());
3395 /* Add the property group to the target entity. */
3397 dependent_cbdata
.sc_handle
= lcbdata
->sc_handle
;
3398 dependent_cbdata
.sc_flags
= lcbdata
->sc_flags
;
3399 dependent_cbdata
.sc_source_fmri
= lcbdata
->sc_source_fmri
;
3400 dependent_cbdata
.sc_target_fmri
= pgrp
->sc_pgroup_fmri
;
3402 ret
= entity_pgroup_import(pgrp
, &dependent_cbdata
);
3404 entity_destroy(dependent_cbdata
.sc_parent
, isservice
);
3406 if (ret
== UU_WALK_NEXT
)
3409 if (ret
!= UU_WALK_ERROR
)
3410 bad_error("entity_pgroup_import", ret
);
3412 switch (dependent_cbdata
.sc_err
) {
3414 warn(gettext("%s deleted unexpectedly.\n"),
3415 pgrp
->sc_pgroup_fmri
);
3416 lcbdata
->sc_err
= EBUSY
;
3420 warn(gettext("Could not create \"%s\" dependency in %s "
3421 "(already exists).\n"), pgrp
->sc_pgroup_name
,
3422 pgrp
->sc_pgroup_fmri
);
3426 lcbdata
->sc_err
= dependent_cbdata
.sc_err
;
3429 return (UU_WALK_ERROR
);
3432 static int upgrade_dependent(const scf_property_t
*, const entity_t
*,
3433 const scf_snaplevel_t
*, scf_transaction_t
*);
3434 static int handle_dependent_conflict(const entity_t
*, const scf_property_t
*,
3438 * Upgrade uncustomized dependents of ent to those specified in ient. Read
3439 * the current dependent targets from running (the snaplevel of a running
3440 * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3441 * scf_instance_t * according to ient, otherwise). Draw the ancestral
3442 * dependent targets and dependency properties from li_dpts_pg (the
3443 * "dependents" property group in snpl) and snpl (the snaplevel which
3444 * corresponds to ent in a last-import snapshot). If li_dpts_pg is NULL, then
3445 * snpl doesn't have a "dependents" property group, and any dependents in ient
3450 * ECONNABORTED - repository connection broken
3451 * ENOMEM - out of memory
3452 * ENOSPC - configd is out of resources
3453 * ECANCELED - ent was deleted
3454 * ENODEV - the entity containing li_dpts_pg was deleted
3455 * EPERM - could not modify dependents pg (permission denied) (error printed)
3456 * - couldn't upgrade dependent (permission denied) (error printed)
3457 * - couldn't create dependent (permission denied) (error printed)
3458 * EROFS - could not modify dependents pg (repository read-only)
3459 * - couldn't upgrade dependent (repository read-only)
3460 * - couldn't create dependent (repository read-only)
3461 * EACCES - could not modify dependents pg (backend access denied)
3462 * - could not upgrade dependent (backend access denied)
3463 * - could not create dependent (backend access denied)
3464 * EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3465 * - dependent target deleted (error printed)
3466 * - dependent pg changed (error printed)
3467 * EINVAL - new dependent is invalid (error printed)
3468 * EBADF - snpl is corrupt (error printed)
3469 * - snpl has corrupt pg (error printed)
3470 * - dependency pg in target is corrupt (error printed)
3471 * - target has corrupt snapshot (error printed)
3472 * EEXIST - dependency pg already existed in target service (error printed)
3475 upgrade_dependents(const scf_propertygroup_t
*li_dpts_pg
,
3476 const scf_snaplevel_t
*snpl
, const entity_t
*ient
,
3477 const scf_snaplevel_t
*running
, void *ent
)
3479 pgroup_t
*new_dpt_pgroup
;
3480 scf_callback_t cbdata
;
3481 int r
, unseen
, tx_started
= 0;
3484 const char * const dependents
= "dependents";
3486 const int issvc
= (ient
->sc_etype
== SVCCFG_SERVICE_OBJECT
);
3488 if (li_dpts_pg
== NULL
&& uu_list_numnodes(ient
->sc_dependents
) == 0)
3489 /* Nothing to do. */
3492 /* Fetch the current version of the "dependents" property group. */
3494 if (entity_get_pg(ent
, issvc
, dependents
, ud_cur_depts_pg
) != 0) {
3495 switch (scf_error()) {
3496 case SCF_ERROR_NOT_FOUND
:
3499 case SCF_ERROR_DELETED
:
3500 case SCF_ERROR_CONNECTION_BROKEN
:
3501 return (scferror2errno(scf_error()));
3503 case SCF_ERROR_NOT_SET
:
3504 case SCF_ERROR_INVALID_ARGUMENT
:
3505 case SCF_ERROR_HANDLE_MISMATCH
:
3506 case SCF_ERROR_NOT_BOUND
:
3508 bad_error("entity_get_pg", scf_error());
3514 /* Fetch the running version of the "dependents" property group. */
3515 ud_run_dpts_pg_set
= 0;
3516 if (running
!= NULL
)
3517 r
= scf_snaplevel_get_pg(running
, dependents
, ud_run_dpts_pg
);
3519 r
= entity_get_pg(ent
, issvc
, dependents
, ud_run_dpts_pg
);
3521 ud_run_dpts_pg_set
= 1;
3523 switch (scf_error()) {
3524 case SCF_ERROR_NOT_FOUND
:
3527 case SCF_ERROR_DELETED
:
3528 case SCF_ERROR_CONNECTION_BROKEN
:
3529 return (scferror2errno(scf_error()));
3531 case SCF_ERROR_NOT_SET
:
3532 case SCF_ERROR_INVALID_ARGUMENT
:
3533 case SCF_ERROR_HANDLE_MISMATCH
:
3534 case SCF_ERROR_NOT_BOUND
:
3536 bad_error(running
? "scf_snaplevel_get_pg" :
3537 "entity_get_pg", scf_error());
3542 * Clear the seen fields of the dependents, so we can tell which ones
3545 if (uu_list_walk(ient
->sc_dependents
, clear_int
,
3546 (void *)offsetof(pgroup_t
, sc_pgroup_seen
), UU_DEFAULT
) != 0)
3547 bad_error("uu_list_walk", uu_error());
3549 if (li_dpts_pg
!= NULL
) {
3551 * Each property in li_dpts_pg represents a dependent tag in
3552 * the old manifest. For each, call upgrade_dependent(),
3553 * which will change ud_cur_depts_pg or dependencies in other
3554 * services as appropriate. Note (a) that changes to
3555 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3556 * made en masse, and (b) it's ok if the entity doesn't have
3557 * a current version of the "dependents" property group,
3558 * because we'll just consider all dependents as customized
3559 * (by being deleted).
3562 if (scf_iter_pg_properties(ud_iter
, li_dpts_pg
) != 0) {
3563 switch (scf_error()) {
3564 case SCF_ERROR_DELETED
:
3567 case SCF_ERROR_CONNECTION_BROKEN
:
3568 return (ECONNABORTED
);
3570 case SCF_ERROR_HANDLE_MISMATCH
:
3571 case SCF_ERROR_NOT_BOUND
:
3572 case SCF_ERROR_NOT_SET
:
3574 bad_error("scf_iter_pg_properties",
3579 if (have_cur_depts
&&
3580 scf_transaction_start(ud_tx
, ud_cur_depts_pg
) != 0) {
3581 switch (scf_error()) {
3582 case SCF_ERROR_BACKEND_ACCESS
:
3583 case SCF_ERROR_BACKEND_READONLY
:
3584 case SCF_ERROR_CONNECTION_BROKEN
:
3585 return (scferror2errno(scf_error()));
3587 case SCF_ERROR_DELETED
:
3588 warn(emsg_pg_deleted
, ient
->sc_fmri
,
3592 case SCF_ERROR_PERMISSION_DENIED
:
3593 warn(emsg_pg_mod_perm
, dependents
,
3595 return (scferror2errno(scf_error()));
3597 case SCF_ERROR_HANDLE_MISMATCH
:
3598 case SCF_ERROR_IN_USE
:
3599 case SCF_ERROR_NOT_BOUND
:
3600 case SCF_ERROR_NOT_SET
:
3602 bad_error("scf_transaction_start", scf_error());
3605 tx_started
= have_cur_depts
;
3608 r
= scf_iter_next_property(ud_iter
, ud_dpt_prop
);
3612 r
= upgrade_dependent(ud_dpt_prop
, ient
, snpl
,
3613 tx_started
? ud_tx
: NULL
);
3635 bad_error("upgrade_dependent", r
);
3639 scf_transaction_destroy_children(ud_tx
);
3643 bad_error("scf_iter_next_property", r
);
3645 switch (scf_error()) {
3646 case SCF_ERROR_DELETED
:
3650 case SCF_ERROR_CONNECTION_BROKEN
:
3654 case SCF_ERROR_NOT_SET
:
3655 case SCF_ERROR_INVALID_ARGUMENT
:
3656 case SCF_ERROR_NOT_BOUND
:
3657 case SCF_ERROR_HANDLE_MISMATCH
:
3659 bad_error("scf_iter_next_property",
3664 scf_transaction_destroy_children(ud_tx
);
3669 /* import unseen dependents */
3671 for (new_dpt_pgroup
= uu_list_first(ient
->sc_dependents
);
3672 new_dpt_pgroup
!= NULL
;
3673 new_dpt_pgroup
= uu_list_next(ient
->sc_dependents
,
3675 if (!new_dpt_pgroup
->sc_pgroup_seen
) {
3681 /* If there are none, exit early. */
3685 /* Set up for lscf_dependent_import() */
3686 cbdata
.sc_handle
= g_hndl
;
3687 cbdata
.sc_parent
= ent
;
3688 cbdata
.sc_service
= issvc
;
3689 cbdata
.sc_flags
= 0;
3691 if (!have_cur_depts
) {
3693 * We have new dependents to import, so we need a "dependents"
3697 r
= scf_service_add_pg(ent
, dependents
,
3698 SCF_GROUP_FRAMEWORK
, 0, ud_cur_depts_pg
);
3700 r
= scf_instance_add_pg(ent
, dependents
,
3701 SCF_GROUP_FRAMEWORK
, 0, ud_cur_depts_pg
);
3703 switch (scf_error()) {
3704 case SCF_ERROR_DELETED
:
3705 case SCF_ERROR_CONNECTION_BROKEN
:
3706 case SCF_ERROR_BACKEND_READONLY
:
3707 case SCF_ERROR_BACKEND_ACCESS
:
3708 case SCF_ERROR_NO_RESOURCES
:
3709 return (scferror2errno(scf_error()));
3711 case SCF_ERROR_EXISTS
:
3712 warn(emsg_pg_added
, ient
->sc_fmri
, dependents
);
3715 case SCF_ERROR_PERMISSION_DENIED
:
3716 warn(emsg_pg_add_perm
, dependents
,
3718 return (scferror2errno(scf_error()));
3720 case SCF_ERROR_NOT_BOUND
:
3721 case SCF_ERROR_HANDLE_MISMATCH
:
3722 case SCF_ERROR_INVALID_ARGUMENT
:
3723 case SCF_ERROR_NOT_SET
:
3725 bad_error("scf_service_add_pg", scf_error());
3730 cbdata
.sc_trans
= ud_tx
;
3732 if (!tx_started
&& scf_transaction_start(ud_tx
, ud_cur_depts_pg
) != 0) {
3733 switch (scf_error()) {
3734 case SCF_ERROR_CONNECTION_BROKEN
:
3735 case SCF_ERROR_BACKEND_ACCESS
:
3736 case SCF_ERROR_BACKEND_READONLY
:
3737 return (scferror2errno(scf_error()));
3739 case SCF_ERROR_DELETED
:
3740 warn(emsg_pg_deleted
, ient
->sc_fmri
, dependents
);
3743 case SCF_ERROR_PERMISSION_DENIED
:
3744 warn(emsg_pg_mod_perm
, dependents
, ient
->sc_fmri
);
3745 return (scferror2errno(scf_error()));
3747 case SCF_ERROR_HANDLE_MISMATCH
:
3748 case SCF_ERROR_IN_USE
:
3749 case SCF_ERROR_NOT_BOUND
:
3750 case SCF_ERROR_NOT_SET
:
3752 bad_error("scf_transaction_start", scf_error());
3757 for (new_dpt_pgroup
= uu_list_first(ient
->sc_dependents
);
3758 new_dpt_pgroup
!= NULL
;
3759 new_dpt_pgroup
= uu_list_next(ient
->sc_dependents
,
3761 if (new_dpt_pgroup
->sc_pgroup_seen
)
3764 if (ud_run_dpts_pg_set
) {
3766 * If the dependent is already there, then we have
3769 if (scf_pg_get_property(ud_run_dpts_pg
,
3770 new_dpt_pgroup
->sc_pgroup_name
, ud_prop
) == 0) {
3771 r
= handle_dependent_conflict(ient
, ud_prop
,
3782 scf_transaction_destroy_children(ud_tx
);
3786 bad_error("handle_dependent_conflict",
3790 switch (scf_error()) {
3791 case SCF_ERROR_NOT_FOUND
:
3794 case SCF_ERROR_INVALID_ARGUMENT
:
3795 warn(emsg_fmri_invalid_pg_name
,
3797 new_dpt_pgroup
->sc_pgroup_name
);
3798 scf_transaction_destroy_children(ud_tx
);
3801 case SCF_ERROR_DELETED
:
3802 warn(emsg_pg_deleted
, ient
->sc_fmri
,
3803 new_dpt_pgroup
->sc_pgroup_name
);
3804 scf_transaction_destroy_children(ud_tx
);
3807 case SCF_ERROR_CONNECTION_BROKEN
:
3808 scf_transaction_destroy_children(ud_tx
);
3809 return (ECONNABORTED
);
3811 case SCF_ERROR_NOT_BOUND
:
3812 case SCF_ERROR_HANDLE_MISMATCH
:
3813 case SCF_ERROR_NOT_SET
:
3815 bad_error("scf_pg_get_property",
3821 r
= lscf_dependent_import(new_dpt_pgroup
, &cbdata
);
3822 if (r
!= UU_WALK_NEXT
) {
3823 if (r
!= UU_WALK_ERROR
)
3824 bad_error("lscf_dependent_import", r
);
3826 if (cbdata
.sc_err
== EALREADY
) {
3827 /* Collisions were handled preemptively. */
3828 bad_error("lscf_dependent_import",
3832 scf_transaction_destroy_children(ud_tx
);
3833 return (cbdata
.sc_err
);
3841 r
= scf_transaction_commit(ud_tx
);
3843 scf_transaction_destroy_children(ud_tx
);
3850 warn(emsg_pg_changed
, ient
->sc_fmri
, dependents
);
3857 bad_error("scf_transaction_commit", r
);
3860 switch (scf_error()) {
3861 case SCF_ERROR_CONNECTION_BROKEN
:
3862 case SCF_ERROR_BACKEND_READONLY
:
3863 case SCF_ERROR_BACKEND_ACCESS
:
3864 case SCF_ERROR_NO_RESOURCES
:
3865 return (scferror2errno(scf_error()));
3867 case SCF_ERROR_DELETED
:
3868 warn(emsg_pg_deleted
, ient
->sc_fmri
, dependents
);
3871 case SCF_ERROR_PERMISSION_DENIED
:
3872 warn(emsg_pg_mod_perm
, dependents
, ient
->sc_fmri
);
3873 return (scferror2errno(scf_error()));
3875 case SCF_ERROR_NOT_BOUND
:
3876 case SCF_ERROR_INVALID_ARGUMENT
:
3877 case SCF_ERROR_NOT_SET
:
3879 bad_error("scf_transaction_destroy", scf_error());
3885 * Used to add the manifests to the list of currently supported manifests.
3886 * We can modify the existing manifest list removing entries if the files
3889 * Get the old list and the new file name
3890 * If the new file name is in the list return
3891 * If not then add the file to the list.
3892 * As we process the list check to see if the files in the old list exist
3893 * if not then remove the file from the list.
3894 * Commit the list of manifest file names.
3898 upgrade_manifestfiles(pgroup_t
*pg
, const entity_t
*ient
,
3899 const scf_snaplevel_t
*running
, void *ent
)
3901 scf_propertygroup_t
*ud_mfsts_pg
= NULL
;
3902 scf_property_t
*ud_prop
= NULL
;
3903 scf_iter_t
*ud_prop_iter
;
3904 scf_value_t
*fname_value
;
3905 scf_callback_t cbdata
;
3906 pgroup_t
*mfst_pgroup
;
3907 property_t
*mfst_prop
;
3908 property_t
*old_prop
;
3917 const int issvc
= (ient
->sc_etype
== SVCCFG_SERVICE_OBJECT
);
3920 * This should always be the service base on the code
3921 * path, and the fact that the manifests pg is a service
3922 * level property group only.
3924 ud_mfsts_pg
= scf_pg_create(g_hndl
);
3925 ud_prop
= scf_property_create(g_hndl
);
3926 ud_prop_iter
= scf_iter_create(g_hndl
);
3927 fname_value
= scf_value_create(g_hndl
);
3929 /* Fetch the "manifests" property group */
3931 r
= entity_get_pg(ent
, issvc
, SCF_PG_MANIFESTFILES
,
3934 switch (scf_error()) {
3935 case SCF_ERROR_NOT_FOUND
:
3939 case SCF_ERROR_DELETED
:
3940 case SCF_ERROR_CONNECTION_BROKEN
:
3941 return (scferror2errno(scf_error()));
3943 case SCF_ERROR_NOT_SET
:
3944 case SCF_ERROR_INVALID_ARGUMENT
:
3945 case SCF_ERROR_HANDLE_MISMATCH
:
3946 case SCF_ERROR_NOT_BOUND
:
3948 bad_error(running
? "scf_snaplevel_get_pg" :
3949 "entity_get_pg", scf_error());
3953 if (no_upgrade_pg
) {
3954 cbdata
.sc_handle
= g_hndl
;
3955 cbdata
.sc_parent
= ent
;
3956 cbdata
.sc_service
= issvc
;
3957 cbdata
.sc_flags
= SCI_FORCE
;
3958 cbdata
.sc_source_fmri
= ient
->sc_fmri
;
3959 cbdata
.sc_target_fmri
= ient
->sc_fmri
;
3961 if (entity_pgroup_import(pg
, &cbdata
) != UU_WALK_NEXT
)
3962 return (cbdata
.sc_err
);
3967 /* Fetch the new manifests property group */
3968 for (mfst_pgroup
= uu_list_first(ient
->sc_pgroups
);
3969 mfst_pgroup
!= NULL
;
3970 mfst_pgroup
= uu_list_next(ient
->sc_pgroups
, mfst_pgroup
)) {
3971 if (strcmp(mfst_pgroup
->sc_pgroup_name
,
3972 SCF_PG_MANIFESTFILES
) == 0)
3976 if ((r
= scf_iter_pg_properties(ud_prop_iter
, ud_mfsts_pg
)) !=
3980 if ((pname
= malloc(MAXPATHLEN
)) == NULL
)
3982 if ((fval
= malloc(MAXPATHLEN
)) == NULL
) {
3987 while ((r
= scf_iter_next_property(ud_prop_iter
, ud_prop
)) == 1) {
3989 if (scf_property_get_name(ud_prop
, pname
, MAXPATHLEN
) < 0)
3992 for (mfst_prop
= uu_list_first(mfst_pgroup
->sc_pgroup_props
);
3994 mfst_prop
= uu_list_next(mfst_pgroup
->sc_pgroup_props
,
3996 if (strcmp(mfst_prop
->sc_property_name
, pname
) == 0) {
4002 * If the manifest is not seen then add it to the new mfst
4003 * property list to get proccessed into the repo.
4005 if (mfst_seen
== 0) {
4007 * If we cannot get the value then there is no
4008 * reason to attempt to attach the value to
4009 * the property group
4011 if (prop_get_val(ud_prop
, fname_value
) == 0 &&
4012 scf_value_get_astring(fname_value
, fval
,
4013 MAXPATHLEN
) != -1) {
4014 old_pname
= safe_strdup(pname
);
4015 old_fval
= safe_strdup(fval
);
4016 old_prop
= internal_property_create(old_pname
,
4017 SCF_TYPE_ASTRING
, 1, old_fval
);
4020 * Already checked to see if the property exists
4021 * in the group, and it does not.
4023 (void) internal_attach_property(mfst_pgroup
,
4031 cbdata
.sc_handle
= g_hndl
;
4032 cbdata
.sc_parent
= ent
;
4033 cbdata
.sc_service
= issvc
;
4034 cbdata
.sc_flags
= SCI_FORCE
;
4035 cbdata
.sc_source_fmri
= ient
->sc_fmri
;
4036 cbdata
.sc_target_fmri
= ient
->sc_fmri
;
4038 if (entity_pgroup_import(mfst_pgroup
, &cbdata
) != UU_WALK_NEXT
)
4039 return (cbdata
.sc_err
);
4045 * prop is taken to be a property in the "dependents" property group of snpl,
4046 * which is taken to be the snaplevel of a last-import snapshot corresponding
4047 * to ient. If prop is a valid dependents property, upgrade the dependent it
4048 * represents according to the repository & ient. If ud_run_dpts_pg_set is
4049 * true, then ud_run_dpts_pg is taken to be the "dependents" property group
4050 * of the entity ient represents (possibly in the running snapshot). If it
4051 * needs to be changed, an entry will be added to tx, if not NULL.
4055 * ECONNABORTED - repository connection broken
4056 * ENOMEM - out of memory
4057 * ENOSPC - configd was out of resources
4058 * ECANCELED - snpl's entity was deleted
4059 * EINVAL - dependent target is invalid (error printed)
4060 * - dependent is invalid (error printed)
4061 * EBADF - snpl is corrupt (error printed)
4062 * - snpl has corrupt pg (error printed)
4063 * - dependency pg in target is corrupt (error printed)
4064 * - running snapshot in dependent is missing snaplevel (error printed)
4065 * EPERM - couldn't delete dependency pg (permission denied) (error printed)
4066 * - couldn't create dependent (permission denied) (error printed)
4067 * - couldn't modify dependent pg (permission denied) (error printed)
4068 * EROFS - couldn't delete dependency pg (repository read-only)
4069 * - couldn't create dependent (repository read-only)
4070 * EACCES - couldn't delete dependency pg (backend access denied)
4071 * - couldn't create dependent (backend access denied)
4072 * EBUSY - ud_run_dpts_pg was deleted (error printed)
4073 * - tx's pg was deleted (error printed)
4074 * - dependent pg was changed or deleted (error printed)
4075 * EEXIST - dependency pg already exists in new target (error printed)
4078 upgrade_dependent(const scf_property_t
*prop
, const entity_t
*ient
,
4079 const scf_snaplevel_t
*snpl
, scf_transaction_t
*tx
)
4083 pgroup_t
*new_dpt_pgroup
;
4084 pgroup_t
*old_dpt_pgroup
= NULL
;
4085 pgroup_t
*current_pg
;
4087 scf_callback_t cbdata
;
4092 scf_transaction_entry_t
*ent
;
4094 const char * const cf_inval
= gettext("Conflict upgrading %s "
4095 "(dependent \"%s\" has invalid dependents property).\n");
4096 const char * const cf_missing
= gettext("Conflict upgrading %s "
4097 "(dependent \"%s\" is missing).\n");
4098 const char * const cf_newdpg
= gettext("Conflict upgrading %s "
4099 "(dependent \"%s\" has new dependency property group).\n");
4100 const char * const cf_newtarg
= gettext("Conflict upgrading %s "
4101 "(dependent \"%s\" has new target).\n");
4102 const char * const li_corrupt
=
4103 gettext("%s: \"last-import\" snapshot is corrupt.\n");
4104 const char * const upgrading
=
4105 gettext("%s: Upgrading dependent \"%s\".\n");
4106 const char * const r_no_lvl
= gettext("%s: \"running\" snapshot is "
4107 "corrupt (missing snaplevel).\n");
4109 if (scf_property_type(prop
, &ty
) != 0) {
4110 switch (scf_error()) {
4111 case SCF_ERROR_DELETED
:
4112 case SCF_ERROR_CONNECTION_BROKEN
:
4113 return (scferror2errno(scf_error()));
4115 case SCF_ERROR_NOT_BOUND
:
4116 case SCF_ERROR_NOT_SET
:
4118 bad_error("scf_property_type", scf_error());
4122 if (!(ty
== SCF_TYPE_FMRI
|| ty
== SCF_TYPE_ASTRING
)) {
4123 warn(li_corrupt
, ient
->sc_fmri
);
4128 * prop represents a dependent in the old manifest. It is named after
4131 if (scf_property_get_name(prop
, ud_name
, max_scf_name_len
+ 1) < 0) {
4132 switch (scf_error()) {
4133 case SCF_ERROR_DELETED
:
4134 case SCF_ERROR_CONNECTION_BROKEN
:
4135 return (scferror2errno(scf_error()));
4137 case SCF_ERROR_NOT_BOUND
:
4138 case SCF_ERROR_NOT_SET
:
4140 bad_error("scf_property_get_name", scf_error());
4144 /* See if it's in the new manifest. */
4145 pgrp
.sc_pgroup_name
= ud_name
;
4147 uu_list_find(ient
->sc_dependents
, &pgrp
, NULL
, UU_DEFAULT
);
4149 /* If it's not, delete it... if it hasn't been customized. */
4150 if (new_dpt_pgroup
== NULL
) {
4151 if (!ud_run_dpts_pg_set
)
4154 if (scf_property_get_value(prop
, ud_val
) != 0) {
4155 switch (scf_error()) {
4156 case SCF_ERROR_NOT_FOUND
:
4157 case SCF_ERROR_CONSTRAINT_VIOLATED
:
4158 warn(li_corrupt
, ient
->sc_fmri
);
4161 case SCF_ERROR_DELETED
:
4162 case SCF_ERROR_CONNECTION_BROKEN
:
4163 return (scferror2errno(scf_error()));
4165 case SCF_ERROR_HANDLE_MISMATCH
:
4166 case SCF_ERROR_NOT_BOUND
:
4167 case SCF_ERROR_NOT_SET
:
4168 case SCF_ERROR_PERMISSION_DENIED
:
4170 bad_error("scf_property_get_value",
4175 if (scf_value_get_as_string(ud_val
, ud_oldtarg
,
4176 max_scf_value_len
+ 1) < 0)
4177 bad_error("scf_value_get_as_string", scf_error());
4179 if (scf_pg_get_property(ud_run_dpts_pg
, ud_name
, ud_prop
) !=
4181 switch (scf_error()) {
4182 case SCF_ERROR_NOT_FOUND
:
4185 case SCF_ERROR_CONNECTION_BROKEN
:
4186 return (scferror2errno(scf_error()));
4188 case SCF_ERROR_DELETED
:
4189 warn(emsg_pg_deleted
, ient
->sc_fmri
,
4193 case SCF_ERROR_INVALID_ARGUMENT
:
4194 case SCF_ERROR_NOT_BOUND
:
4195 case SCF_ERROR_HANDLE_MISMATCH
:
4196 case SCF_ERROR_NOT_SET
:
4198 bad_error("scf_pg_get_property", scf_error());
4201 if (scf_property_get_value(ud_prop
, ud_val
) != 0) {
4202 switch (scf_error()) {
4203 case SCF_ERROR_NOT_FOUND
:
4204 case SCF_ERROR_CONSTRAINT_VIOLATED
:
4205 warn(cf_inval
, ient
->sc_fmri
, ud_name
);
4208 case SCF_ERROR_DELETED
:
4209 case SCF_ERROR_CONNECTION_BROKEN
:
4210 return (scferror2errno(scf_error()));
4212 case SCF_ERROR_HANDLE_MISMATCH
:
4213 case SCF_ERROR_NOT_BOUND
:
4214 case SCF_ERROR_NOT_SET
:
4215 case SCF_ERROR_PERMISSION_DENIED
:
4217 bad_error("scf_property_get_value",
4222 ty
= scf_value_type(ud_val
);
4223 assert(ty
!= SCF_TYPE_INVALID
);
4224 if (!(ty
== SCF_TYPE_FMRI
|| ty
== SCF_TYPE_ASTRING
)) {
4225 warn(cf_inval
, ient
->sc_fmri
, ud_name
);
4229 if (scf_value_get_as_string(ud_val
, ud_ctarg
,
4230 max_scf_value_len
+ 1) < 0)
4231 bad_error("scf_value_get_as_string", scf_error());
4233 r
= fmri_equal(ud_ctarg
, ud_oldtarg
);
4239 case -1: /* warn? */
4240 warn(cf_newtarg
, ient
->sc_fmri
, ud_name
);
4244 warn(li_corrupt
, ient
->sc_fmri
);
4248 bad_error("fmri_equal", r
);
4251 if (scf_snaplevel_get_pg(snpl
, ud_name
, ud_pg
) != 0) {
4252 switch (scf_error()) {
4253 case SCF_ERROR_NOT_FOUND
:
4254 warn(li_corrupt
, ient
->sc_fmri
);
4257 case SCF_ERROR_DELETED
:
4258 case SCF_ERROR_CONNECTION_BROKEN
:
4259 return (scferror2errno(scf_error()));
4261 case SCF_ERROR_NOT_BOUND
:
4262 case SCF_ERROR_HANDLE_MISMATCH
:
4263 case SCF_ERROR_INVALID_ARGUMENT
:
4264 case SCF_ERROR_NOT_SET
:
4266 bad_error("scf_snaplevel_get_pg", scf_error());
4270 r
= load_pg(ud_pg
, &old_dpt_pgroup
, ient
->sc_fmri
,
4284 bad_error("load_pg", r
);
4287 serr
= fmri_to_entity(g_hndl
, ud_ctarg
, &target_ent
, &tissvc
);
4289 case SCF_ERROR_NONE
:
4292 case SCF_ERROR_NO_MEMORY
:
4293 internal_pgroup_free(old_dpt_pgroup
);
4296 case SCF_ERROR_NOT_FOUND
:
4297 internal_pgroup_free(old_dpt_pgroup
);
4300 case SCF_ERROR_CONSTRAINT_VIOLATED
: /* caught above */
4301 case SCF_ERROR_INVALID_ARGUMENT
: /* caught above */
4303 bad_error("fmri_to_entity", serr
);
4306 r
= entity_get_running_pg(target_ent
, tissvc
, ud_name
,
4307 ud_pg
, ud_iter2
, ud_inst
, imp_snap
, ud_snpl
);
4313 internal_pgroup_free(old_dpt_pgroup
);
4318 internal_pgroup_free(old_dpt_pgroup
);
4322 warn(r_no_lvl
, ud_ctarg
);
4323 internal_pgroup_free(old_dpt_pgroup
);
4328 bad_error("entity_get_running_pg", r
);
4332 r
= load_pg(ud_pg
, ¤t_pg
, ud_ctarg
, NULL
);
4338 internal_pgroup_free(old_dpt_pgroup
);
4344 internal_pgroup_free(old_dpt_pgroup
);
4349 bad_error("load_pg", r
);
4352 /* compare property groups */
4353 if (!pg_equal(old_dpt_pgroup
, current_pg
)) {
4354 warn(cf_newdpg
, ient
->sc_fmri
, ud_name
);
4355 internal_pgroup_free(old_dpt_pgroup
);
4356 internal_pgroup_free(current_pg
);
4360 internal_pgroup_free(old_dpt_pgroup
);
4361 internal_pgroup_free(current_pg
);
4364 warn(gettext("%s: Deleting dependent \"%s\".\n"),
4365 ient
->sc_fmri
, ud_name
);
4367 if (entity_get_pg(target_ent
, tissvc
, ud_name
, ud_pg
) != 0) {
4368 switch (scf_error()) {
4369 case SCF_ERROR_NOT_FOUND
:
4370 case SCF_ERROR_DELETED
:
4371 internal_pgroup_free(old_dpt_pgroup
);
4374 case SCF_ERROR_CONNECTION_BROKEN
:
4375 internal_pgroup_free(old_dpt_pgroup
);
4376 return (ECONNABORTED
);
4378 case SCF_ERROR_NOT_SET
:
4379 case SCF_ERROR_INVALID_ARGUMENT
:
4380 case SCF_ERROR_HANDLE_MISMATCH
:
4381 case SCF_ERROR_NOT_BOUND
:
4383 bad_error("entity_get_pg", scf_error());
4387 if (scf_pg_delete(ud_pg
) != 0) {
4388 switch (scf_error()) {
4389 case SCF_ERROR_DELETED
:
4392 case SCF_ERROR_CONNECTION_BROKEN
:
4393 case SCF_ERROR_BACKEND_READONLY
:
4394 case SCF_ERROR_BACKEND_ACCESS
:
4395 return (scferror2errno(scf_error()));
4397 case SCF_ERROR_PERMISSION_DENIED
:
4398 warn(emsg_pg_del_perm
, ud_name
, ient
->sc_fmri
);
4399 return (scferror2errno(scf_error()));
4401 case SCF_ERROR_NOT_SET
:
4403 bad_error("scf_pg_delete", scf_error());
4408 * This service was changed, so it must be refreshed. But
4409 * since it's not mentioned in the new manifest, we have to
4410 * record its FMRI here for use later. We record the name
4411 * & the entity (via sc_parent) in case we need to print error
4412 * messages during the refresh.
4414 dpt
= internal_pgroup_new();
4417 dpt
->sc_pgroup_name
= strdup(ud_name
);
4418 dpt
->sc_pgroup_fmri
= strdup(ud_ctarg
);
4419 if (dpt
->sc_pgroup_name
== NULL
|| dpt
->sc_pgroup_fmri
== NULL
)
4421 dpt
->sc_parent
= (entity_t
*)ient
;
4422 if (uu_list_insert_after(imp_deleted_dpts
, NULL
, dpt
) != 0)
4423 uu_die(gettext("libuutil error: %s\n"),
4424 uu_strerror(uu_error()));
4430 ent
= scf_entry_create(g_hndl
);
4434 if (scf_transaction_property_delete(tx
, ent
, ud_name
) != 0) {
4435 scf_entry_destroy(ent
);
4436 switch (scf_error()) {
4437 case SCF_ERROR_DELETED
:
4438 warn(emsg_pg_deleted
, ient
->sc_fmri
,
4442 case SCF_ERROR_CONNECTION_BROKEN
:
4443 return (scferror2errno(scf_error()));
4445 case SCF_ERROR_NOT_FOUND
:
4448 case SCF_ERROR_HANDLE_MISMATCH
:
4449 case SCF_ERROR_NOT_BOUND
:
4450 case SCF_ERROR_INVALID_ARGUMENT
:
4451 case SCF_ERROR_NOT_SET
:
4453 bad_error("scf_transaction_property_delete",
4461 new_dpt_pgroup
->sc_pgroup_seen
= 1;
4464 * Decide whether the dependent has changed in the manifest.
4466 /* Compare the target. */
4467 if (scf_property_get_value(prop
, ud_val
) != 0) {
4468 switch (scf_error()) {
4469 case SCF_ERROR_NOT_FOUND
:
4470 case SCF_ERROR_CONSTRAINT_VIOLATED
:
4471 warn(li_corrupt
, ient
->sc_fmri
);
4474 case SCF_ERROR_DELETED
:
4475 case SCF_ERROR_CONNECTION_BROKEN
:
4476 return (scferror2errno(scf_error()));
4478 case SCF_ERROR_HANDLE_MISMATCH
:
4479 case SCF_ERROR_NOT_BOUND
:
4480 case SCF_ERROR_NOT_SET
:
4481 case SCF_ERROR_PERMISSION_DENIED
:
4483 bad_error("scf_property_get_value", scf_error());
4487 if (scf_value_get_as_string(ud_val
, ud_oldtarg
, max_scf_value_len
+ 1) <
4489 bad_error("scf_value_get_as_string", scf_error());
4492 * If the fmri's are not equal then the old fmri will need to
4493 * be refreshed to ensure that the changes are properly updated
4496 r
= fmri_equal(ud_oldtarg
, new_dpt_pgroup
->sc_pgroup_fmri
);
4499 dpt
= internal_pgroup_new();
4502 dpt
->sc_pgroup_name
= strdup(ud_name
);
4503 dpt
->sc_pgroup_fmri
= strdup(ud_oldtarg
);
4504 if (dpt
->sc_pgroup_name
== NULL
|| dpt
->sc_pgroup_fmri
== NULL
)
4506 dpt
->sc_parent
= (entity_t
*)ient
;
4507 if (uu_list_insert_after(imp_deleted_dpts
, NULL
, dpt
) != 0)
4508 uu_die(gettext("libuutil error: %s\n"),
4509 uu_strerror(uu_error()));
4513 /* Compare the dependency pgs. */
4514 if (scf_snaplevel_get_pg(snpl
, ud_name
, ud_pg
) != 0) {
4515 switch (scf_error()) {
4516 case SCF_ERROR_NOT_FOUND
:
4517 warn(li_corrupt
, ient
->sc_fmri
);
4520 case SCF_ERROR_DELETED
:
4521 case SCF_ERROR_CONNECTION_BROKEN
:
4522 return (scferror2errno(scf_error()));
4524 case SCF_ERROR_NOT_BOUND
:
4525 case SCF_ERROR_HANDLE_MISMATCH
:
4526 case SCF_ERROR_INVALID_ARGUMENT
:
4527 case SCF_ERROR_NOT_SET
:
4529 bad_error("scf_snaplevel_get_pg", scf_error());
4533 r
= load_pg(ud_pg
, &old_dpt_pgroup
, ient
->sc_fmri
,
4547 bad_error("load_pg", r
);
4550 if (pg_equal(old_dpt_pgroup
, new_dpt_pgroup
)) {
4551 /* no change, leave customizations */
4552 internal_pgroup_free(old_dpt_pgroup
);
4558 warn(li_corrupt
, ient
->sc_fmri
);
4562 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4563 ud_name
, new_dpt_pgroup
->sc_pgroup_fmri
);
4567 bad_error("fmri_equal", r
);
4571 * The dependent has changed in the manifest. Upgrade the current
4572 * properties if they haven't been customized.
4576 * If new_dpt_pgroup->sc_override, then act as though the property
4577 * group hasn't been customized.
4579 if (new_dpt_pgroup
->sc_pgroup_override
) {
4580 (void) strcpy(ud_ctarg
, ud_oldtarg
);
4584 if (!ud_run_dpts_pg_set
) {
4585 warn(cf_missing
, ient
->sc_fmri
, ud_name
);
4588 } else if (scf_pg_get_property(ud_run_dpts_pg
, ud_name
, ud_prop
) != 0) {
4589 switch (scf_error()) {
4590 case SCF_ERROR_NOT_FOUND
:
4591 warn(cf_missing
, ient
->sc_fmri
, ud_name
);
4595 case SCF_ERROR_CONNECTION_BROKEN
:
4596 r
= scferror2errno(scf_error());
4599 case SCF_ERROR_DELETED
:
4600 warn(emsg_pg_deleted
, ient
->sc_fmri
, "dependents");
4604 case SCF_ERROR_INVALID_ARGUMENT
:
4605 case SCF_ERROR_NOT_BOUND
:
4606 case SCF_ERROR_HANDLE_MISMATCH
:
4607 case SCF_ERROR_NOT_SET
:
4609 bad_error("scf_pg_get_property", scf_error());
4613 if (scf_property_get_value(ud_prop
, ud_val
) != 0) {
4614 switch (scf_error()) {
4615 case SCF_ERROR_NOT_FOUND
:
4616 case SCF_ERROR_CONSTRAINT_VIOLATED
:
4617 warn(cf_inval
, ient
->sc_fmri
, ud_name
);
4621 case SCF_ERROR_DELETED
:
4622 case SCF_ERROR_CONNECTION_BROKEN
:
4623 r
= scferror2errno(scf_error());
4626 case SCF_ERROR_HANDLE_MISMATCH
:
4627 case SCF_ERROR_NOT_BOUND
:
4628 case SCF_ERROR_NOT_SET
:
4629 case SCF_ERROR_PERMISSION_DENIED
:
4631 bad_error("scf_property_get_value", scf_error());
4635 ty
= scf_value_type(ud_val
);
4636 assert(ty
!= SCF_TYPE_INVALID
);
4637 if (!(ty
== SCF_TYPE_FMRI
|| ty
== SCF_TYPE_ASTRING
)) {
4638 warn(cf_inval
, ient
->sc_fmri
, ud_name
);
4642 if (scf_value_get_as_string(ud_val
, ud_ctarg
, max_scf_value_len
+ 1) <
4644 bad_error("scf_value_get_as_string", scf_error());
4646 r
= fmri_equal(ud_ctarg
, ud_oldtarg
);
4648 warn(cf_inval
, ient
->sc_fmri
, ud_name
);
4651 } else if (r
== -2) {
4652 warn(li_corrupt
, ient
->sc_fmri
);
4655 } else if (r
== 0) {
4657 * Target has been changed. Only abort now if it's been
4658 * changed to something other than what's in the manifest.
4660 r
= fmri_equal(ud_ctarg
, new_dpt_pgroup
->sc_pgroup_fmri
);
4662 warn(cf_inval
, ient
->sc_fmri
, ud_name
);
4665 } else if (r
== 0) {
4666 warn(cf_newtarg
, ient
->sc_fmri
, ud_name
);
4669 } else if (r
!= 1) {
4670 /* invalid sc_pgroup_fmri caught above */
4671 bad_error("fmri_equal", r
);
4675 * Fetch the current dependency pg. If it's what the manifest
4676 * says, then no problem.
4678 serr
= fmri_to_entity(g_hndl
, ud_ctarg
, &target_ent
, &tissvc
);
4680 case SCF_ERROR_NONE
:
4683 case SCF_ERROR_NOT_FOUND
:
4684 warn(cf_missing
, ient
->sc_fmri
, ud_name
);
4688 case SCF_ERROR_NO_MEMORY
:
4692 case SCF_ERROR_CONSTRAINT_VIOLATED
:
4693 case SCF_ERROR_INVALID_ARGUMENT
:
4695 bad_error("fmri_to_entity", serr
);
4698 r
= entity_get_running_pg(target_ent
, tissvc
, ud_name
,
4699 ud_pg
, ud_iter2
, ud_inst
, imp_snap
, ud_snpl
);
4709 warn(cf_missing
, ient
->sc_fmri
, ud_name
);
4714 warn(r_no_lvl
, ud_ctarg
);
4719 bad_error("entity_get_running_pg", r
);
4722 r
= load_pg(ud_pg
, ¤t_pg
, ud_ctarg
, NULL
);
4728 warn(cf_missing
, ient
->sc_fmri
, ud_name
);
4739 bad_error("load_pg", r
);
4742 if (!pg_equal(current_pg
, new_dpt_pgroup
))
4743 warn(cf_newdpg
, ient
->sc_fmri
, ud_name
);
4744 internal_pgroup_free(current_pg
);
4747 } else if (r
!= 1) {
4748 bad_error("fmri_equal", r
);
4753 * Target has not been customized. Check the dependency property
4757 if (old_dpt_pgroup
== NULL
) {
4758 if (scf_snaplevel_get_pg(snpl
, new_dpt_pgroup
->sc_pgroup_name
,
4760 switch (scf_error()) {
4761 case SCF_ERROR_NOT_FOUND
:
4762 warn(li_corrupt
, ient
->sc_fmri
);
4765 case SCF_ERROR_DELETED
:
4766 case SCF_ERROR_CONNECTION_BROKEN
:
4767 return (scferror2errno(scf_error()));
4769 case SCF_ERROR_NOT_BOUND
:
4770 case SCF_ERROR_HANDLE_MISMATCH
:
4771 case SCF_ERROR_INVALID_ARGUMENT
:
4772 case SCF_ERROR_NOT_SET
:
4774 bad_error("scf_snaplevel_get_pg", scf_error());
4778 r
= load_pg(ud_pg
, &old_dpt_pgroup
, ient
->sc_fmri
,
4792 bad_error("load_pg", r
);
4795 serr
= fmri_to_entity(g_hndl
, ud_ctarg
, &target_ent
, &tissvc
);
4797 case SCF_ERROR_NONE
:
4800 case SCF_ERROR_NOT_FOUND
:
4801 warn(cf_missing
, ient
->sc_fmri
, ud_name
);
4805 case SCF_ERROR_NO_MEMORY
:
4809 case SCF_ERROR_CONSTRAINT_VIOLATED
:
4810 case SCF_ERROR_INVALID_ARGUMENT
:
4812 bad_error("fmri_to_entity", serr
);
4815 r
= entity_get_running_pg(target_ent
, tissvc
, ud_name
, ud_pg
,
4816 ud_iter2
, ud_inst
, imp_snap
, ud_snpl
);
4826 warn(cf_missing
, ient
->sc_fmri
, ud_name
);
4831 warn(r_no_lvl
, ud_ctarg
);
4836 bad_error("entity_get_running_pg", r
);
4839 r
= load_pg(ud_pg
, ¤t_pg
, ud_ctarg
, NULL
);
4845 warn(cf_missing
, ient
->sc_fmri
, ud_name
);
4855 bad_error("load_pg", r
);
4858 if (!pg_equal(current_pg
, old_dpt_pgroup
)) {
4859 if (!pg_equal(current_pg
, new_dpt_pgroup
))
4860 warn(cf_newdpg
, ient
->sc_fmri
, ud_name
);
4861 internal_pgroup_free(current_pg
);
4866 /* Uncustomized. Upgrade. */
4868 r
= fmri_equal(new_dpt_pgroup
->sc_pgroup_fmri
, ud_oldtarg
);
4871 if (pg_equal(current_pg
, new_dpt_pgroup
)) {
4872 /* Already upgraded. */
4873 internal_pgroup_free(current_pg
);
4878 internal_pgroup_free(current_pg
);
4880 /* upgrade current_pg */
4881 if (entity_get_pg(target_ent
, tissvc
, ud_name
, ud_pg
) != 0) {
4882 switch (scf_error()) {
4883 case SCF_ERROR_CONNECTION_BROKEN
:
4884 r
= scferror2errno(scf_error());
4887 case SCF_ERROR_DELETED
:
4888 warn(cf_missing
, ient
->sc_fmri
, ud_name
);
4892 case SCF_ERROR_NOT_FOUND
:
4895 case SCF_ERROR_INVALID_ARGUMENT
:
4896 case SCF_ERROR_NOT_BOUND
:
4897 case SCF_ERROR_NOT_SET
:
4898 case SCF_ERROR_HANDLE_MISMATCH
:
4900 bad_error("entity_get_pg", scf_error());
4904 r
= scf_service_add_pg(target_ent
, ud_name
,
4905 SCF_GROUP_DEPENDENCY
, 0, ud_pg
);
4907 r
= scf_instance_add_pg(target_ent
, ud_name
,
4908 SCF_GROUP_DEPENDENCY
, 0, ud_pg
);
4910 switch (scf_error()) {
4911 case SCF_ERROR_CONNECTION_BROKEN
:
4912 case SCF_ERROR_NO_RESOURCES
:
4913 case SCF_ERROR_BACKEND_READONLY
:
4914 case SCF_ERROR_BACKEND_ACCESS
:
4915 r
= scferror2errno(scf_error());
4918 case SCF_ERROR_DELETED
:
4919 warn(cf_missing
, ient
->sc_fmri
,
4924 case SCF_ERROR_PERMISSION_DENIED
:
4925 warn(emsg_pg_deleted
, ud_ctarg
,
4930 case SCF_ERROR_EXISTS
:
4931 warn(emsg_pg_added
, ud_ctarg
, ud_name
);
4935 case SCF_ERROR_NOT_BOUND
:
4936 case SCF_ERROR_HANDLE_MISMATCH
:
4937 case SCF_ERROR_INVALID_ARGUMENT
:
4938 case SCF_ERROR_NOT_SET
:
4940 bad_error("entity_add_pg", scf_error());
4945 r
= load_pg(ud_pg
, ¤t_pg
, ud_ctarg
, NULL
);
4951 warn(cf_missing
, ient
->sc_fmri
, ud_name
);
4961 bad_error("load_pg", r
);
4965 warn(upgrading
, ient
->sc_fmri
, ud_name
);
4967 r
= upgrade_pg(ud_pg
, current_pg
, old_dpt_pgroup
,
4968 new_dpt_pgroup
, 0, ient
->sc_fmri
);
4974 warn(emsg_pg_deleted
, ud_ctarg
, ud_name
);
4979 warn(emsg_pg_mod_perm
, ud_name
, ud_ctarg
);
4983 warn(emsg_pg_changed
, ud_ctarg
, ud_name
);
4995 bad_error("upgrade_pg", r
);
5000 scf_transaction_entry_t
*ent
;
5003 internal_pgroup_free(current_pg
);
5007 warn(upgrading
, ient
->sc_fmri
, ud_name
);
5009 if (entity_get_pg(target_ent
, tissvc
, ud_name
, ud_pg
) != 0) {
5010 switch (scf_error()) {
5011 case SCF_ERROR_CONNECTION_BROKEN
:
5012 r
= scferror2errno(scf_error());
5015 case SCF_ERROR_DELETED
:
5016 warn(cf_missing
, ient
->sc_fmri
, ud_name
);
5020 case SCF_ERROR_NOT_FOUND
:
5023 case SCF_ERROR_INVALID_ARGUMENT
:
5024 case SCF_ERROR_NOT_BOUND
:
5025 case SCF_ERROR_NOT_SET
:
5026 case SCF_ERROR_HANDLE_MISMATCH
:
5028 bad_error("entity_get_pg", scf_error());
5030 } else if (scf_pg_delete(ud_pg
) != 0) {
5031 switch (scf_error()) {
5032 case SCF_ERROR_DELETED
:
5035 case SCF_ERROR_CONNECTION_BROKEN
:
5036 case SCF_ERROR_BACKEND_READONLY
:
5037 case SCF_ERROR_BACKEND_ACCESS
:
5038 r
= scferror2errno(scf_error());
5041 case SCF_ERROR_PERMISSION_DENIED
:
5042 warn(emsg_pg_del_perm
, ud_name
, ient
->sc_fmri
);
5043 r
= scferror2errno(scf_error());
5046 case SCF_ERROR_NOT_SET
:
5048 bad_error("scf_pg_delete", scf_error());
5052 /* import new one */
5053 cbdata
.sc_handle
= g_hndl
;
5054 cbdata
.sc_trans
= NULL
; /* handled below */
5055 cbdata
.sc_flags
= 0;
5057 r
= lscf_dependent_import(new_dpt_pgroup
, &cbdata
);
5058 if (r
!= UU_WALK_NEXT
) {
5059 if (r
!= UU_WALK_ERROR
)
5060 bad_error("lscf_dependent_import", r
);
5069 if ((ent
= scf_entry_create(g_hndl
)) == NULL
||
5070 (val
= scf_value_create(g_hndl
)) == NULL
) {
5071 if (scf_error() == SCF_ERROR_NO_MEMORY
)
5074 bad_error("scf_entry_create", scf_error());
5077 if (scf_transaction_property_change_type(tx
, ent
, ud_name
,
5078 SCF_TYPE_FMRI
) != 0) {
5079 switch (scf_error()) {
5080 case SCF_ERROR_CONNECTION_BROKEN
:
5081 r
= scferror2errno(scf_error());
5084 case SCF_ERROR_DELETED
:
5085 warn(emsg_pg_deleted
, ient
->sc_fmri
,
5090 case SCF_ERROR_NOT_FOUND
:
5093 case SCF_ERROR_NOT_BOUND
:
5094 case SCF_ERROR_HANDLE_MISMATCH
:
5095 case SCF_ERROR_INVALID_ARGUMENT
:
5096 case SCF_ERROR_NOT_SET
:
5098 bad_error("scf_transaction_property_"
5099 "change_type", scf_error());
5102 if (scf_transaction_property_new(tx
, ent
, ud_name
,
5103 SCF_TYPE_FMRI
) != 0) {
5104 switch (scf_error()) {
5105 case SCF_ERROR_CONNECTION_BROKEN
:
5106 r
= scferror2errno(scf_error());
5109 case SCF_ERROR_DELETED
:
5110 warn(emsg_pg_deleted
, ient
->sc_fmri
,
5115 case SCF_ERROR_EXISTS
:
5116 warn(emsg_pg_changed
, ient
->sc_fmri
,
5121 case SCF_ERROR_INVALID_ARGUMENT
:
5122 case SCF_ERROR_HANDLE_MISMATCH
:
5123 case SCF_ERROR_NOT_BOUND
:
5124 case SCF_ERROR_NOT_SET
:
5126 bad_error("scf_transaction_property_"
5127 "new", scf_error());
5132 if (scf_value_set_from_string(val
, SCF_TYPE_FMRI
,
5133 new_dpt_pgroup
->sc_pgroup_fmri
) != 0)
5134 /* invalid sc_pgroup_fmri caught above */
5135 bad_error("scf_value_set_from_string",
5138 if (scf_entry_add_value(ent
, val
) != 0)
5139 bad_error("scf_entry_add_value", scf_error());
5144 warn(li_corrupt
, ient
->sc_fmri
);
5145 internal_pgroup_free(current_pg
);
5151 /* invalid sc_pgroup_fmri caught above */
5152 bad_error("fmri_equal", r
);
5158 if (old_dpt_pgroup
!= NULL
)
5159 internal_pgroup_free(old_dpt_pgroup
);
5165 * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
5166 * would import it, except it seems to exist in the service anyway. Compare
5167 * the existent dependent with the one we would import, and report any
5168 * differences (if there are none, be silent). prop is the property which
5169 * represents the existent dependent (in the dependents property group) in the
5170 * entity corresponding to ient.
5173 * 0 - success (Sort of. At least, we can continue importing.)
5174 * ECONNABORTED - repository connection broken
5175 * EBUSY - ancestor of prop was deleted (error printed)
5176 * ENOMEM - out of memory
5177 * EBADF - corrupt property group (error printed)
5178 * EINVAL - new_dpt_pgroup has invalid target (error printed)
5181 handle_dependent_conflict(const entity_t
* const ient
,
5182 const scf_property_t
* const prop
, const pgroup_t
* const new_dpt_pgroup
)
5191 if (scf_property_get_value(prop
, ud_val
) != 0) {
5192 switch (scf_error()) {
5193 case SCF_ERROR_CONNECTION_BROKEN
:
5194 return (scferror2errno(scf_error()));
5196 case SCF_ERROR_DELETED
:
5197 warn(emsg_pg_deleted
, ient
->sc_fmri
,
5198 new_dpt_pgroup
->sc_pgroup_name
);
5201 case SCF_ERROR_CONSTRAINT_VIOLATED
:
5202 case SCF_ERROR_NOT_FOUND
:
5203 warn(gettext("Conflict upgrading %s (not importing "
5204 "dependent \"%s\" because it already exists.) "
5205 "Warning: The \"%s/%2$s\" property has more or "
5206 "fewer than one value)).\n"), ient
->sc_fmri
,
5207 new_dpt_pgroup
->sc_pgroup_name
, "dependents");
5210 case SCF_ERROR_HANDLE_MISMATCH
:
5211 case SCF_ERROR_NOT_BOUND
:
5212 case SCF_ERROR_NOT_SET
:
5213 case SCF_ERROR_PERMISSION_DENIED
:
5215 bad_error("scf_property_get_value",
5220 ty
= scf_value_type(ud_val
);
5221 assert(ty
!= SCF_TYPE_INVALID
);
5222 if (!(ty
== SCF_TYPE_FMRI
|| ty
== SCF_TYPE_ASTRING
)) {
5223 warn(gettext("Conflict upgrading %s (not importing dependent "
5224 "\"%s\" because it already exists). Warning: The "
5225 "\"%s/%s\" property has unexpected type \"%s\")).\n"),
5226 ient
->sc_fmri
, new_dpt_pgroup
->sc_pgroup_name
,
5227 scf_type_to_string(ty
), "dependents");
5231 if (scf_value_get_as_string(ud_val
, ud_ctarg
, max_scf_value_len
+ 1) <
5233 bad_error("scf_value_get_as_string", scf_error());
5235 r
= fmri_equal(ud_ctarg
, new_dpt_pgroup
->sc_pgroup_fmri
);
5238 warn(gettext("Conflict upgrading %s (not importing dependent "
5239 "\"%s\" (target \"%s\") because it already exists with "
5240 "target \"%s\").\n"), ient
->sc_fmri
,
5241 new_dpt_pgroup
->sc_pgroup_name
,
5242 new_dpt_pgroup
->sc_pgroup_fmri
, ud_ctarg
);
5249 warn(gettext("Conflict upgrading %s (not importing dependent "
5250 "\"%s\" because it already exists). Warning: The current "
5251 "dependent's target (%s) is invalid.\n"), ient
->sc_fmri
,
5252 new_dpt_pgroup
->sc_pgroup_name
, ud_ctarg
);
5256 warn(gettext("Dependent \"%s\" of %s has invalid target "
5257 "\"%s\".\n"), new_dpt_pgroup
->sc_pgroup_name
, ient
->sc_fmri
,
5258 new_dpt_pgroup
->sc_pgroup_fmri
);
5262 bad_error("fmri_equal", r
);
5265 /* compare dependency pgs in target */
5266 scfe
= fmri_to_entity(g_hndl
, ud_ctarg
, &tptr
, &tissvc
);
5268 case SCF_ERROR_NONE
:
5271 case SCF_ERROR_NO_MEMORY
:
5274 case SCF_ERROR_NOT_FOUND
:
5275 warn(emsg_dpt_dangling
, ient
->sc_fmri
,
5276 new_dpt_pgroup
->sc_pgroup_name
, ud_ctarg
);
5279 case SCF_ERROR_CONSTRAINT_VIOLATED
:
5280 case SCF_ERROR_INVALID_ARGUMENT
:
5282 bad_error("fmri_to_entity", scfe
);
5285 r
= entity_get_running_pg(tptr
, tissvc
, new_dpt_pgroup
->sc_pgroup_name
,
5286 ud_pg
, ud_iter
, ud_inst
, imp_snap
, ud_snpl
);
5295 warn(emsg_dpt_dangling
, ient
->sc_fmri
,
5296 new_dpt_pgroup
->sc_pgroup_name
, ud_ctarg
);
5301 warn(gettext("%s has an instance with a \"%s\" "
5302 "snapshot which is missing a snaplevel.\n"),
5303 ud_ctarg
, "running");
5305 warn(gettext("%s has a \"%s\" snapshot which is "
5306 "missing a snaplevel.\n"), ud_ctarg
, "running");
5310 warn(emsg_dpt_no_dep
, ient
->sc_fmri
,
5311 new_dpt_pgroup
->sc_pgroup_name
, ud_ctarg
,
5312 new_dpt_pgroup
->sc_pgroup_name
);
5317 bad_error("entity_get_running_pg", r
);
5320 pgroup
= internal_pgroup_new();
5324 r
= load_pg(ud_pg
, &pgroup
, ud_ctarg
, NULL
);
5332 internal_pgroup_free(pgroup
);
5336 warn(emsg_dpt_no_dep
, ient
->sc_fmri
,
5337 new_dpt_pgroup
->sc_pgroup_name
, ud_ctarg
,
5338 new_dpt_pgroup
->sc_pgroup_name
);
5339 internal_pgroup_free(pgroup
);
5344 bad_error("load_pg", r
);
5347 /* report differences */
5348 report_pg_diffs(new_dpt_pgroup
, pgroup
, ud_ctarg
, 1);
5349 internal_pgroup_free(pgroup
);
5354 * lipg is a property group in the last-import snapshot of ent, which is an
5355 * scf_service_t or an scf_instance_t (according to ient). If lipg is not in
5356 * ient's pgroups, delete it from ent if it hasn't been customized. If it is
5357 * in ents's property groups, compare and upgrade ent appropriately.
5361 * ECONNABORTED - repository connection broken
5362 * ENOMEM - out of memory
5363 * ENOSPC - configd is out of resources
5364 * EINVAL - ient has invalid dependent (error printed)
5365 * - ient has invalid pgroup_t (error printed)
5366 * ECANCELED - ent has been deleted
5367 * ENODEV - entity containing lipg has been deleted
5368 * - entity containing running has been deleted
5369 * EPERM - could not delete pg (permission denied) (error printed)
5370 * - couldn't upgrade dependents (permission denied) (error printed)
5371 * - couldn't import pg (permission denied) (error printed)
5372 * - couldn't upgrade pg (permission denied) (error printed)
5373 * EROFS - could not delete pg (repository read-only)
5374 * - couldn't upgrade dependents (repository read-only)
5375 * - couldn't import pg (repository read-only)
5376 * - couldn't upgrade pg (repository read-only)
5377 * EACCES - could not delete pg (backend access denied)
5378 * - couldn't upgrade dependents (backend access denied)
5379 * - couldn't import pg (backend access denied)
5380 * - couldn't upgrade pg (backend access denied)
5381 * - couldn't read property (backend access denied)
5382 * EBUSY - property group was added (error printed)
5383 * - property group was deleted (error printed)
5384 * - property group changed (error printed)
5385 * - "dependents" pg was added, changed, or deleted (error printed)
5386 * - dependent target deleted (error printed)
5387 * - dependent pg changed (error printed)
5388 * EBADF - imp_snpl is corrupt (error printed)
5389 * - ent has bad pg (error printed)
5390 * EEXIST - dependent collision in target service (error printed)
5393 process_old_pg(const scf_propertygroup_t
*lipg
, entity_t
*ient
, void *ent
,
5394 const scf_snaplevel_t
*running
)
5397 pgroup_t
*mpg
, *lipg_i
, *curpg_i
, pgrp
;
5398 scf_callback_t cbdata
;
5400 const char * const cf_pg_missing
=
5401 gettext("Conflict upgrading %s (property group %s is missing)\n");
5402 const char * const deleting
=
5403 gettext("%s: Deleting property group \"%s\".\n");
5405 const int issvc
= (ient
->sc_etype
== SVCCFG_SERVICE_OBJECT
);
5407 /* Skip dependent property groups. */
5408 if (scf_pg_get_type(lipg
, imp_str
, imp_str_sz
) < 0) {
5409 switch (scf_error()) {
5410 case SCF_ERROR_DELETED
:
5413 case SCF_ERROR_CONNECTION_BROKEN
:
5414 return (ECONNABORTED
);
5416 case SCF_ERROR_NOT_SET
:
5417 case SCF_ERROR_NOT_BOUND
:
5419 bad_error("scf_pg_get_type", scf_error());
5423 if (strcmp(imp_str
, SCF_GROUP_DEPENDENCY
) == 0) {
5424 if (scf_pg_get_property(lipg
, "external", NULL
) == 0)
5427 switch (scf_error()) {
5428 case SCF_ERROR_NOT_FOUND
:
5431 case SCF_ERROR_CONNECTION_BROKEN
:
5432 return (ECONNABORTED
);
5434 case SCF_ERROR_DELETED
:
5437 case SCF_ERROR_INVALID_ARGUMENT
:
5438 case SCF_ERROR_NOT_BOUND
:
5439 case SCF_ERROR_HANDLE_MISMATCH
:
5440 case SCF_ERROR_NOT_SET
:
5442 bad_error("scf_pg_get_property", scf_error());
5446 /* lookup pg in new properties */
5447 if (scf_pg_get_name(lipg
, imp_str
, imp_str_sz
) < 0) {
5448 switch (scf_error()) {
5449 case SCF_ERROR_DELETED
:
5452 case SCF_ERROR_CONNECTION_BROKEN
:
5453 return (ECONNABORTED
);
5455 case SCF_ERROR_NOT_SET
:
5456 case SCF_ERROR_NOT_BOUND
:
5458 bad_error("scf_pg_get_name", scf_error());
5462 pgrp
.sc_pgroup_name
= imp_str
;
5463 mpg
= uu_list_find(ient
->sc_pgroups
, &pgrp
, NULL
, NULL
);
5466 mpg
->sc_pgroup_seen
= 1;
5468 /* Special handling for dependents */
5469 if (strcmp(imp_str
, "dependents") == 0)
5470 return (upgrade_dependents(lipg
, imp_snpl
, ient
, running
, ent
));
5472 if (strcmp(imp_str
, SCF_PG_MANIFESTFILES
) == 0)
5473 return (upgrade_manifestfiles(NULL
, ient
, running
, ent
));
5475 if (mpg
== NULL
|| mpg
->sc_pgroup_delete
) {
5476 /* property group was deleted from manifest */
5477 if (entity_get_pg(ent
, issvc
, imp_str
, imp_pg2
) != 0) {
5478 switch (scf_error()) {
5479 case SCF_ERROR_NOT_FOUND
:
5482 case SCF_ERROR_DELETED
:
5483 case SCF_ERROR_CONNECTION_BROKEN
:
5484 return (scferror2errno(scf_error()));
5486 case SCF_ERROR_INVALID_ARGUMENT
:
5487 case SCF_ERROR_HANDLE_MISMATCH
:
5488 case SCF_ERROR_NOT_BOUND
:
5489 case SCF_ERROR_NOT_SET
:
5491 bad_error("entity_get_pg", scf_error());
5495 if (mpg
!= NULL
&& mpg
->sc_pgroup_delete
) {
5497 warn(deleting
, ient
->sc_fmri
, imp_str
);
5498 if (scf_pg_delete(imp_pg2
) == 0)
5501 switch (scf_error()) {
5502 case SCF_ERROR_DELETED
:
5505 case SCF_ERROR_CONNECTION_BROKEN
:
5506 case SCF_ERROR_BACKEND_READONLY
:
5507 case SCF_ERROR_BACKEND_ACCESS
:
5508 return (scferror2errno(scf_error()));
5510 case SCF_ERROR_PERMISSION_DENIED
:
5511 warn(emsg_pg_del_perm
, imp_str
, ient
->sc_fmri
);
5512 return (scferror2errno(scf_error()));
5514 case SCF_ERROR_NOT_SET
:
5516 bad_error("scf_pg_delete", scf_error());
5520 r
= load_pg(lipg
, &lipg_i
, ient
->sc_fmri
, snap_lastimport
);
5535 bad_error("load_pg", r
);
5538 r
= load_pg(imp_pg2
, &curpg_i
, ient
->sc_fmri
, NULL
);
5548 internal_pgroup_free(lipg_i
);
5552 bad_error("load_pg", r
);
5555 if (pg_equal(lipg_i
, curpg_i
)) {
5557 warn(deleting
, ient
->sc_fmri
, imp_str
);
5558 if (scf_pg_delete(imp_pg2
) != 0) {
5559 switch (scf_error()) {
5560 case SCF_ERROR_DELETED
:
5563 case SCF_ERROR_CONNECTION_BROKEN
:
5564 internal_pgroup_free(lipg_i
);
5565 internal_pgroup_free(curpg_i
);
5566 return (ECONNABORTED
);
5568 case SCF_ERROR_NOT_SET
:
5569 case SCF_ERROR_NOT_BOUND
:
5571 bad_error("scf_pg_delete", scf_error());
5575 report_pg_diffs(lipg_i
, curpg_i
, ient
->sc_fmri
, 0);
5578 internal_pgroup_free(lipg_i
);
5579 internal_pgroup_free(curpg_i
);
5585 * Only dependent pgs can have override set, and we skipped those
5588 assert(!mpg
->sc_pgroup_override
);
5591 r
= load_pg(lipg
, &lipg_i
, ient
->sc_fmri
, snap_lastimport
);
5606 bad_error("load_pg", r
);
5609 if (pg_equal(mpg
, lipg_i
)) {
5610 /* The manifest pg has not changed. Move on. */
5615 /* upgrade current properties according to lipg & mpg */
5616 if (running
!= NULL
)
5617 r
= scf_snaplevel_get_pg(running
, imp_str
, imp_pg2
);
5619 r
= entity_get_pg(ent
, issvc
, imp_str
, imp_pg2
);
5621 switch (scf_error()) {
5622 case SCF_ERROR_CONNECTION_BROKEN
:
5623 r
= scferror2errno(scf_error());
5626 case SCF_ERROR_DELETED
:
5627 if (running
!= NULL
)
5633 case SCF_ERROR_NOT_FOUND
:
5636 case SCF_ERROR_INVALID_ARGUMENT
:
5637 case SCF_ERROR_HANDLE_MISMATCH
:
5638 case SCF_ERROR_NOT_BOUND
:
5639 case SCF_ERROR_NOT_SET
:
5641 bad_error("entity_get_pg", scf_error());
5644 warn(cf_pg_missing
, ient
->sc_fmri
, imp_str
);
5650 r
= load_pg_attrs(imp_pg2
, &curpg_i
);
5656 warn(cf_pg_missing
, ient
->sc_fmri
, imp_str
);
5665 bad_error("load_pg_attrs", r
);
5668 if (!pg_attrs_equal(lipg_i
, curpg_i
, NULL
, 0)) {
5669 (void) pg_attrs_equal(curpg_i
, mpg
, ient
->sc_fmri
, 0);
5670 internal_pgroup_free(curpg_i
);
5675 internal_pgroup_free(curpg_i
);
5677 r
= load_pg(imp_pg2
, &curpg_i
, ient
->sc_fmri
, NULL
);
5683 warn(cf_pg_missing
, ient
->sc_fmri
, imp_str
);
5694 bad_error("load_pg", r
);
5697 if (pg_equal(lipg_i
, curpg_i
) &&
5698 !pg_attrs_equal(lipg_i
, mpg
, NULL
, 0)) {
5702 warn(gettext("%s: Upgrading property group \"%s\".\n"),
5703 ient
->sc_fmri
, mpg
->sc_pgroup_name
);
5705 internal_pgroup_free(curpg_i
);
5707 if (running
!= NULL
&&
5708 entity_get_pg(ent
, issvc
, imp_str
, imp_pg2
) != 0) {
5709 switch (scf_error()) {
5710 case SCF_ERROR_DELETED
:
5714 case SCF_ERROR_NOT_FOUND
:
5718 case SCF_ERROR_CONNECTION_BROKEN
:
5719 r
= scferror2errno(scf_error());
5722 case SCF_ERROR_HANDLE_MISMATCH
:
5723 case SCF_ERROR_INVALID_ARGUMENT
:
5724 case SCF_ERROR_NOT_SET
:
5725 case SCF_ERROR_NOT_BOUND
:
5727 bad_error("entity_get_pg", scf_error());
5731 if (do_delete
&& scf_pg_delete(imp_pg2
) != 0) {
5732 switch (scf_error()) {
5733 case SCF_ERROR_DELETED
:
5736 case SCF_ERROR_CONNECTION_BROKEN
:
5737 case SCF_ERROR_BACKEND_READONLY
:
5738 case SCF_ERROR_BACKEND_ACCESS
:
5739 r
= scferror2errno(scf_error());
5742 case SCF_ERROR_PERMISSION_DENIED
:
5743 warn(emsg_pg_del_perm
, mpg
->sc_pgroup_name
,
5745 r
= scferror2errno(scf_error());
5748 case SCF_ERROR_NOT_SET
:
5749 case SCF_ERROR_NOT_BOUND
:
5751 bad_error("scf_pg_delete", scf_error());
5755 cbdata
.sc_handle
= g_hndl
;
5756 cbdata
.sc_parent
= ent
;
5757 cbdata
.sc_service
= issvc
;
5758 cbdata
.sc_flags
= 0;
5759 cbdata
.sc_source_fmri
= ient
->sc_fmri
;
5760 cbdata
.sc_target_fmri
= ient
->sc_fmri
;
5762 r
= entity_pgroup_import(mpg
, &cbdata
);
5769 if (cbdata
.sc_err
== EEXIST
) {
5770 warn(emsg_pg_added
, ient
->sc_fmri
,
5771 mpg
->sc_pgroup_name
);
5779 bad_error("entity_pgroup_import", r
);
5783 if (running
!= NULL
&&
5784 entity_get_pg(ent
, issvc
, imp_str
, imp_pg2
) != 0) {
5785 switch (scf_error()) {
5786 case SCF_ERROR_CONNECTION_BROKEN
:
5787 case SCF_ERROR_DELETED
:
5788 r
= scferror2errno(scf_error());
5791 case SCF_ERROR_NOT_FOUND
:
5794 case SCF_ERROR_HANDLE_MISMATCH
:
5795 case SCF_ERROR_INVALID_ARGUMENT
:
5796 case SCF_ERROR_NOT_SET
:
5797 case SCF_ERROR_NOT_BOUND
:
5799 bad_error("entity_get_pg", scf_error());
5802 cbdata
.sc_handle
= g_hndl
;
5803 cbdata
.sc_parent
= ent
;
5804 cbdata
.sc_service
= issvc
;
5805 cbdata
.sc_flags
= SCI_FORCE
;
5806 cbdata
.sc_source_fmri
= ient
->sc_fmri
;
5807 cbdata
.sc_target_fmri
= ient
->sc_fmri
;
5809 r
= entity_pgroup_import(mpg
, &cbdata
);
5816 if (cbdata
.sc_err
== EEXIST
) {
5817 warn(emsg_pg_added
, ient
->sc_fmri
,
5818 mpg
->sc_pgroup_name
);
5826 bad_error("entity_pgroup_import", r
);
5830 r
= upgrade_pg(imp_pg2
, curpg_i
, lipg_i
, mpg
, g_verbose
, ient
->sc_fmri
);
5831 internal_pgroup_free(curpg_i
);
5834 ient
->sc_import_state
= IMPORT_PROP_BEGUN
;
5838 warn(emsg_pg_deleted
, ient
->sc_fmri
, mpg
->sc_pgroup_name
);
5843 warn(emsg_pg_mod_perm
, mpg
->sc_pgroup_name
, ient
->sc_fmri
);
5847 warn(emsg_pg_changed
, ient
->sc_fmri
, mpg
->sc_pgroup_name
);
5859 bad_error("upgrade_pg", r
);
5863 internal_pgroup_free(lipg_i
);
5868 * Upgrade the properties of ent according to snpl & ient.
5872 * ECONNABORTED - repository connection broken
5873 * ENOMEM - out of memory
5874 * ENOSPC - configd is out of resources
5875 * ECANCELED - ent was deleted
5876 * ENODEV - entity containing snpl was deleted
5877 * - entity containing running was deleted
5878 * EBADF - imp_snpl is corrupt (error printed)
5879 * - ent has corrupt pg (error printed)
5880 * - dependent has corrupt pg (error printed)
5881 * - dependent target has a corrupt snapshot (error printed)
5882 * EBUSY - pg was added, changed, or deleted (error printed)
5883 * - dependent target was deleted (error printed)
5884 * - dependent pg changed (error printed)
5885 * EINVAL - invalid property group name (error printed)
5886 * - invalid property name (error printed)
5887 * - invalid value (error printed)
5888 * - ient has invalid pgroup or dependent (error printed)
5889 * EPERM - could not create property group (permission denied) (error printed)
5890 * - could not modify property group (permission denied) (error printed)
5891 * - couldn't delete, upgrade, or import pg or dependent (error printed)
5892 * EROFS - could not create property group (repository read-only)
5893 * - couldn't delete, upgrade, or import pg or dependent
5894 * EACCES - could not create property group (backend access denied)
5895 * - couldn't delete, upgrade, or import pg or dependent
5896 * EEXIST - dependent collision in target service (error printed)
5899 upgrade_props(void *ent
, scf_snaplevel_t
*running
, scf_snaplevel_t
*snpl
,
5904 uu_list_t
*pgs
= ient
->sc_pgroups
;
5906 const int issvc
= (ient
->sc_etype
== SVCCFG_SERVICE_OBJECT
);
5908 /* clear sc_sceen for pgs */
5909 if (uu_list_walk(pgs
, clear_int
,
5910 (void *)offsetof(pgroup_t
, sc_pgroup_seen
), UU_DEFAULT
) != 0)
5911 bad_error("uu_list_walk", uu_error());
5913 if (scf_iter_snaplevel_pgs(imp_up_iter
, snpl
) != 0) {
5914 switch (scf_error()) {
5915 case SCF_ERROR_DELETED
:
5918 case SCF_ERROR_CONNECTION_BROKEN
:
5919 return (ECONNABORTED
);
5921 case SCF_ERROR_NOT_SET
:
5922 case SCF_ERROR_NOT_BOUND
:
5923 case SCF_ERROR_HANDLE_MISMATCH
:
5925 bad_error("scf_iter_snaplevel_pgs", scf_error());
5930 r
= scf_iter_next_pg(imp_up_iter
, imp_pg
);
5934 r
= process_old_pg(imp_pg
, ient
, ent
, running
);
5954 bad_error("process_old_pg", r
);
5959 bad_error("scf_iter_next_pg", r
);
5961 switch (scf_error()) {
5962 case SCF_ERROR_DELETED
:
5965 case SCF_ERROR_CONNECTION_BROKEN
:
5966 return (ECONNABORTED
);
5968 case SCF_ERROR_HANDLE_MISMATCH
:
5969 case SCF_ERROR_NOT_BOUND
:
5970 case SCF_ERROR_NOT_SET
:
5971 case SCF_ERROR_INVALID_ARGUMENT
:
5973 bad_error("scf_iter_next_pg", scf_error());
5977 for (pg
= uu_list_first(pgs
); pg
!= NULL
; pg
= uu_list_next(pgs
, pg
)) {
5978 if (pg
->sc_pgroup_seen
)
5983 if (strcmp(pg
->sc_pgroup_name
, "dependents") == 0) {
5984 r
= upgrade_dependents(NULL
, imp_snpl
, ient
, running
,
6005 bad_error("upgrade_dependents", r
);
6010 if (strcmp(pg
->sc_pgroup_name
, SCF_PG_MANIFESTFILES
) == 0) {
6011 r
= upgrade_manifestfiles(pg
, ient
, running
, ent
);
6031 bad_error("upgrade_manifestfiles", r
);
6036 if (running
!= NULL
) {
6037 r
= scf_snaplevel_get_pg(running
, pg
->sc_pgroup_name
,
6040 r
= entity_get_pg(ent
, issvc
, pg
->sc_pgroup_name
,
6044 scf_callback_t cbdata
;
6046 switch (scf_error()) {
6047 case SCF_ERROR_NOT_FOUND
:
6050 case SCF_ERROR_CONNECTION_BROKEN
:
6051 return (scferror2errno(scf_error()));
6053 case SCF_ERROR_DELETED
:
6054 if (running
!= NULL
)
6057 return (scferror2errno(scf_error()));
6059 case SCF_ERROR_INVALID_ARGUMENT
:
6060 warn(emsg_fmri_invalid_pg_name
, ient
->sc_fmri
,
6061 pg
->sc_pgroup_name
);
6064 case SCF_ERROR_NOT_SET
:
6065 case SCF_ERROR_HANDLE_MISMATCH
:
6066 case SCF_ERROR_NOT_BOUND
:
6068 bad_error("entity_get_pg", scf_error());
6071 /* User doesn't have pg, so import it. */
6073 cbdata
.sc_handle
= g_hndl
;
6074 cbdata
.sc_parent
= ent
;
6075 cbdata
.sc_service
= issvc
;
6076 cbdata
.sc_flags
= SCI_FORCE
;
6077 cbdata
.sc_source_fmri
= ient
->sc_fmri
;
6078 cbdata
.sc_target_fmri
= ient
->sc_fmri
;
6080 r
= entity_pgroup_import(pg
, &cbdata
);
6083 ient
->sc_import_state
= IMPORT_PROP_BEGUN
;
6087 if (cbdata
.sc_err
== EEXIST
) {
6088 warn(emsg_pg_added
, ient
->sc_fmri
,
6089 pg
->sc_pgroup_name
);
6092 return (cbdata
.sc_err
);
6095 bad_error("entity_pgroup_import", r
);
6099 /* report differences between pg & current */
6100 r
= load_pg(imp_pg
, &rpg
, ient
->sc_fmri
, NULL
);
6106 warn(emsg_pg_deleted
, ient
->sc_fmri
,
6107 pg
->sc_pgroup_name
);
6117 bad_error("load_pg", r
);
6119 report_pg_diffs(pg
, rpg
, ient
->sc_fmri
, 1);
6120 internal_pgroup_free(rpg
);
6128 * Import an instance. If it doesn't exist, create it. If it has
6129 * a last-import snapshot, upgrade its properties. Finish by updating its
6130 * last-import snapshot. If it doesn't have a last-import snapshot then it
6131 * could have been created for a dependent tag in another manifest. Import the
6132 * new properties. If there's a conflict, don't override, like now?
6134 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
6135 * lcbdata->sc_err to
6136 * ECONNABORTED - repository connection broken
6137 * ENOMEM - out of memory
6138 * ENOSPC - svc.configd is out of resources
6139 * EEXIST - dependency collision in dependent service (error printed)
6140 * EPERM - couldn't create temporary instance (permission denied)
6141 * - couldn't import into temporary instance (permission denied)
6142 * - couldn't take snapshot (permission denied)
6143 * - couldn't upgrade properties (permission denied)
6144 * - couldn't import properties (permission denied)
6145 * - couldn't import dependents (permission denied)
6146 * EROFS - couldn't create temporary instance (repository read-only)
6147 * - couldn't import into temporary instance (repository read-only)
6148 * - couldn't upgrade properties (repository read-only)
6149 * - couldn't import properties (repository read-only)
6150 * - couldn't import dependents (repository read-only)
6151 * EACCES - couldn't create temporary instance (backend access denied)
6152 * - couldn't import into temporary instance (backend access denied)
6153 * - couldn't upgrade properties (backend access denied)
6154 * - couldn't import properties (backend access denied)
6155 * - couldn't import dependents (backend access denied)
6156 * EINVAL - invalid instance name (error printed)
6157 * - invalid pgroup_t's (error printed)
6158 * - invalid dependents (error printed)
6159 * EBUSY - temporary service deleted (error printed)
6160 * - temporary instance deleted (error printed)
6161 * - temporary instance changed (error printed)
6162 * - temporary instance already exists (error printed)
6163 * - instance deleted (error printed)
6164 * EBADF - instance has corrupt last-import snapshot (error printed)
6165 * - instance is corrupt (error printed)
6166 * - dependent has corrupt pg (error printed)
6167 * - dependent target has a corrupt snapshot (error printed)
6168 * -1 - unknown libscf error (error printed)
6171 lscf_instance_import(void *v
, void *pvt
)
6175 scf_callback_t
*lcbdata
= pvt
;
6176 scf_service_t
*rsvc
= lcbdata
->sc_parent
;
6178 scf_snaplevel_t
*running
;
6179 int flags
= lcbdata
->sc_flags
;
6181 const char * const emsg_tdel
=
6182 gettext("Temporary instance svc:/%s:%s was deleted.\n");
6183 const char * const emsg_tchg
= gettext("Temporary instance svc:/%s:%s "
6184 "changed unexpectedly.\n");
6185 const char * const emsg_del
= gettext("%s changed unexpectedly "
6186 "(instance \"%s\" was deleted.)\n");
6187 const char * const emsg_badsnap
= gettext(
6188 "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
6191 * prepare last-import snapshot:
6192 * create temporary instance (service was precreated)
6193 * populate with properties from bundle
6196 if (scf_service_add_instance(imp_tsvc
, inst
->sc_name
, imp_tinst
) != 0) {
6197 switch (scf_error()) {
6198 case SCF_ERROR_CONNECTION_BROKEN
:
6199 case SCF_ERROR_NO_RESOURCES
:
6200 case SCF_ERROR_BACKEND_READONLY
:
6201 case SCF_ERROR_BACKEND_ACCESS
:
6202 return (stash_scferror(lcbdata
));
6204 case SCF_ERROR_EXISTS
:
6205 warn(gettext("Temporary service svc:/%s "
6206 "changed unexpectedly (instance \"%s\" added).\n"),
6207 imp_tsname
, inst
->sc_name
);
6208 lcbdata
->sc_err
= EBUSY
;
6209 return (UU_WALK_ERROR
);
6211 case SCF_ERROR_DELETED
:
6212 warn(gettext("Temporary service svc:/%s "
6213 "was deleted unexpectedly.\n"), imp_tsname
);
6214 lcbdata
->sc_err
= EBUSY
;
6215 return (UU_WALK_ERROR
);
6217 case SCF_ERROR_INVALID_ARGUMENT
:
6218 warn(gettext("Invalid instance name \"%s\".\n"),
6220 return (stash_scferror(lcbdata
));
6222 case SCF_ERROR_PERMISSION_DENIED
:
6223 warn(gettext("Could not create temporary instance "
6224 "\"%s\" in svc:/%s (permission denied).\n"),
6225 inst
->sc_name
, imp_tsname
);
6226 return (stash_scferror(lcbdata
));
6228 case SCF_ERROR_HANDLE_MISMATCH
:
6229 case SCF_ERROR_NOT_BOUND
:
6230 case SCF_ERROR_NOT_SET
:
6232 bad_error("scf_service_add_instance", scf_error());
6236 r
= snprintf(imp_str
, imp_str_sz
, "svc:/%s:%s", imp_tsname
,
6239 bad_error("snprintf", errno
);
6241 r
= lscf_import_instance_pgs(imp_tinst
, imp_str
, inst
,
6242 lcbdata
->sc_flags
| SCI_NOENABLED
);
6248 warn(emsg_tdel
, imp_tsname
, inst
->sc_name
);
6249 lcbdata
->sc_err
= EBUSY
;
6254 warn(emsg_tchg
, imp_tsname
, inst
->sc_name
);
6255 lcbdata
->sc_err
= EBUSY
;
6269 lcbdata
->sc_err
= r
;
6274 bad_error("lscf_import_instance_pgs", r
);
6277 r
= snprintf(imp_str
, imp_str_sz
, "svc:/%s:%s", imp_tsname
,
6280 bad_error("snprintf", errno
);
6282 ctx
.sc_handle
= lcbdata
->sc_handle
;
6283 ctx
.sc_parent
= imp_tinst
;
6285 ctx
.sc_source_fmri
= inst
->sc_fmri
;
6286 ctx
.sc_target_fmri
= imp_str
;
6287 if (uu_list_walk(inst
->sc_dependents
, entity_pgroup_import
, &ctx
,
6289 if (uu_error() != UU_ERROR_CALLBACK_FAILED
)
6290 bad_error("uu_list_walk", uu_error());
6292 switch (ctx
.sc_err
) {
6297 warn(emsg_tdel
, imp_tsname
, inst
->sc_name
);
6298 lcbdata
->sc_err
= EBUSY
;
6302 warn(emsg_tchg
, imp_tsname
, inst
->sc_name
);
6303 lcbdata
->sc_err
= EBUSY
;
6307 lcbdata
->sc_err
= ctx
.sc_err
;
6313 if (_scf_snapshot_take_new_named(imp_tinst
, inst
->sc_parent
->sc_name
,
6314 inst
->sc_name
, snap_lastimport
, imp_tlisnap
) != 0) {
6315 switch (scf_error()) {
6316 case SCF_ERROR_CONNECTION_BROKEN
:
6319 case SCF_ERROR_NO_RESOURCES
:
6320 r
= stash_scferror(lcbdata
);
6323 case SCF_ERROR_EXISTS
:
6324 warn(emsg_tchg
, imp_tsname
, inst
->sc_name
);
6325 lcbdata
->sc_err
= EBUSY
;
6329 case SCF_ERROR_PERMISSION_DENIED
:
6330 warn(gettext("Could not take \"%s\" snapshot of %s "
6331 "(permission denied).\n"), snap_lastimport
,
6333 r
= stash_scferror(lcbdata
);
6338 lcbdata
->sc_err
= -1;
6342 case SCF_ERROR_HANDLE_MISMATCH
:
6343 case SCF_ERROR_INVALID_ARGUMENT
:
6344 case SCF_ERROR_NOT_SET
:
6345 bad_error("_scf_snapshot_take_new_named", scf_error());
6349 if (lcbdata
->sc_flags
& SCI_FRESH
)
6352 if (scf_service_get_instance(rsvc
, inst
->sc_name
, imp_inst
) == 0) {
6353 if (scf_instance_get_snapshot(imp_inst
, snap_lastimport
,
6355 switch (scf_error()) {
6356 case SCF_ERROR_DELETED
:
6357 warn(emsg_del
, inst
->sc_parent
->sc_fmri
,
6359 lcbdata
->sc_err
= EBUSY
;
6363 case SCF_ERROR_NOT_FOUND
:
6367 case SCF_ERROR_CONNECTION_BROKEN
:
6370 case SCF_ERROR_INVALID_ARGUMENT
:
6371 case SCF_ERROR_HANDLE_MISMATCH
:
6372 case SCF_ERROR_NOT_BOUND
:
6373 case SCF_ERROR_NOT_SET
:
6375 bad_error("scf_instance_get_snapshot",
6383 * compare new properties with last-import properties
6384 * upgrade current properties
6386 /* clear sc_sceen for pgs */
6387 if (uu_list_walk(inst
->sc_pgroups
, clear_int
,
6388 (void *)offsetof(pgroup_t
, sc_pgroup_seen
), UU_DEFAULT
) !=
6390 bad_error("uu_list_walk", uu_error());
6392 r
= get_snaplevel(imp_lisnap
, 0, imp_snpl
);
6401 warn(emsg_del
, inst
->sc_parent
->sc_fmri
, inst
->sc_name
);
6402 lcbdata
->sc_err
= EBUSY
;
6407 warn(emsg_badsnap
, snap_lastimport
, inst
->sc_fmri
);
6408 lcbdata
->sc_err
= EBADF
;
6413 bad_error("get_snaplevel", r
);
6416 if (scf_instance_get_snapshot(imp_inst
, snap_running
,
6418 switch (scf_error()) {
6419 case SCF_ERROR_DELETED
:
6420 warn(emsg_del
, inst
->sc_parent
->sc_fmri
,
6422 lcbdata
->sc_err
= EBUSY
;
6426 case SCF_ERROR_NOT_FOUND
:
6429 case SCF_ERROR_CONNECTION_BROKEN
:
6432 case SCF_ERROR_INVALID_ARGUMENT
:
6433 case SCF_ERROR_HANDLE_MISMATCH
:
6434 case SCF_ERROR_NOT_BOUND
:
6435 case SCF_ERROR_NOT_SET
:
6437 bad_error("scf_instance_get_snapshot",
6443 r
= get_snaplevel(imp_rsnap
, 0, imp_rsnpl
);
6446 running
= imp_rsnpl
;
6453 warn(emsg_del
, inst
->sc_parent
->sc_fmri
,
6455 lcbdata
->sc_err
= EBUSY
;
6460 warn(emsg_badsnap
, snap_running
, inst
->sc_fmri
);
6461 lcbdata
->sc_err
= EBADF
;
6466 bad_error("get_snaplevel", r
);
6470 r
= upgrade_props(imp_inst
, running
, imp_snpl
, inst
);
6477 warn(emsg_del
, inst
->sc_parent
->sc_fmri
, inst
->sc_name
);
6478 lcbdata
->sc_err
= EBUSY
;
6494 lcbdata
->sc_err
= r
;
6499 bad_error("upgrade_props", r
);
6502 inst
->sc_import_state
= IMPORT_PROP_DONE
;
6504 switch (scf_error()) {
6505 case SCF_ERROR_CONNECTION_BROKEN
:
6508 case SCF_ERROR_NOT_FOUND
:
6511 case SCF_ERROR_INVALID_ARGUMENT
: /* caught above */
6512 case SCF_ERROR_HANDLE_MISMATCH
:
6513 case SCF_ERROR_NOT_BOUND
:
6514 case SCF_ERROR_NOT_SET
:
6516 bad_error("scf_service_get_instance", scf_error());
6520 /* create instance */
6521 if (scf_service_add_instance(rsvc
, inst
->sc_name
,
6523 switch (scf_error()) {
6524 case SCF_ERROR_CONNECTION_BROKEN
:
6527 case SCF_ERROR_NO_RESOURCES
:
6528 case SCF_ERROR_BACKEND_READONLY
:
6529 case SCF_ERROR_BACKEND_ACCESS
:
6530 r
= stash_scferror(lcbdata
);
6533 case SCF_ERROR_EXISTS
:
6534 warn(gettext("%s changed unexpectedly "
6535 "(instance \"%s\" added).\n"),
6536 inst
->sc_parent
->sc_fmri
, inst
->sc_name
);
6537 lcbdata
->sc_err
= EBUSY
;
6541 case SCF_ERROR_PERMISSION_DENIED
:
6542 warn(gettext("Could not create \"%s\" instance "
6543 "in %s (permission denied).\n"),
6544 inst
->sc_name
, inst
->sc_parent
->sc_fmri
);
6545 r
= stash_scferror(lcbdata
);
6548 case SCF_ERROR_INVALID_ARGUMENT
: /* caught above */
6549 case SCF_ERROR_HANDLE_MISMATCH
:
6550 case SCF_ERROR_NOT_BOUND
:
6551 case SCF_ERROR_NOT_SET
:
6553 bad_error("scf_service_add_instance",
6560 * Create a last-import snapshot to serve as an attachment
6561 * point for the real one from the temporary instance. Since
6562 * the contents is irrelevant, take it now, while the instance
6563 * is empty, to minimize svc.configd's work.
6565 if (_scf_snapshot_take_new(imp_inst
, snap_lastimport
,
6567 switch (scf_error()) {
6568 case SCF_ERROR_CONNECTION_BROKEN
:
6571 case SCF_ERROR_NO_RESOURCES
:
6572 r
= stash_scferror(lcbdata
);
6575 case SCF_ERROR_EXISTS
:
6576 warn(gettext("%s changed unexpectedly "
6577 "(snapshot \"%s\" added).\n"),
6578 inst
->sc_fmri
, snap_lastimport
);
6579 lcbdata
->sc_err
= EBUSY
;
6583 case SCF_ERROR_PERMISSION_DENIED
:
6584 warn(gettext("Could not take \"%s\" snapshot "
6585 "of %s (permission denied).\n"),
6586 snap_lastimport
, inst
->sc_fmri
);
6587 r
= stash_scferror(lcbdata
);
6592 lcbdata
->sc_err
= -1;
6596 case SCF_ERROR_NOT_SET
:
6597 case SCF_ERROR_INTERNAL
:
6598 case SCF_ERROR_INVALID_ARGUMENT
:
6599 case SCF_ERROR_HANDLE_MISMATCH
:
6600 bad_error("_scf_snapshot_take_new",
6608 inst
->sc_import_state
= IMPORT_PROP_BEGUN
;
6610 r
= lscf_import_instance_pgs(imp_inst
, inst
->sc_fmri
, inst
,
6620 warn(gettext("%s changed unexpectedly "
6621 "(instance \"%s\" deleted).\n"),
6622 inst
->sc_parent
->sc_fmri
, inst
->sc_name
);
6623 lcbdata
->sc_err
= EBUSY
;
6628 warn(gettext("%s changed unexpectedly "
6629 "(property group added).\n"), inst
->sc_fmri
);
6630 lcbdata
->sc_err
= EBUSY
;
6635 lcbdata
->sc_err
= r
;
6639 case EINVAL
: /* caught above */
6640 bad_error("lscf_import_instance_pgs", r
);
6643 ctx
.sc_parent
= imp_inst
;
6645 ctx
.sc_trans
= NULL
;
6647 if (uu_list_walk(inst
->sc_dependents
, lscf_dependent_import
,
6648 &ctx
, UU_DEFAULT
) != 0) {
6649 if (uu_error() != UU_ERROR_CALLBACK_FAILED
)
6650 bad_error("uu_list_walk", uu_error());
6652 if (ctx
.sc_err
== ECONNABORTED
)
6654 lcbdata
->sc_err
= ctx
.sc_err
;
6659 inst
->sc_import_state
= IMPORT_PROP_DONE
;
6662 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6663 snap_initial
, inst
->sc_fmri
);
6664 r
= take_snap(imp_inst
, snap_initial
, imp_snap
);
6674 lcbdata
->sc_err
= r
;
6679 warn(gettext("%s changed unexpectedly "
6680 "(instance %s deleted).\n"),
6681 inst
->sc_parent
->sc_fmri
, inst
->sc_name
);
6682 lcbdata
->sc_err
= r
;
6687 warn(emsg_snap_perm
, snap_initial
, inst
->sc_fmri
);
6688 lcbdata
->sc_err
= r
;
6693 bad_error("take_snap", r
);
6698 if (lcbdata
->sc_flags
& SCI_NOSNAP
)
6701 /* transfer snapshot from temporary instance */
6703 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6704 snap_lastimport
, inst
->sc_fmri
);
6705 if (_scf_snapshot_attach(imp_tlisnap
, imp_lisnap
) != 0) {
6706 switch (scf_error()) {
6707 case SCF_ERROR_CONNECTION_BROKEN
:
6710 case SCF_ERROR_NO_RESOURCES
:
6711 r
= stash_scferror(lcbdata
);
6714 case SCF_ERROR_PERMISSION_DENIED
:
6715 warn(gettext("Could not take \"%s\" snapshot for %s "
6716 "(permission denied).\n"), snap_lastimport
,
6718 r
= stash_scferror(lcbdata
);
6721 case SCF_ERROR_NOT_SET
:
6722 case SCF_ERROR_HANDLE_MISMATCH
:
6724 bad_error("_scf_snapshot_attach", scf_error());
6728 inst
->sc_import_state
= IMPORT_COMPLETE
;
6733 /* delete temporary instance */
6734 if (scf_instance_delete(imp_tinst
) != 0) {
6735 switch (scf_error()) {
6736 case SCF_ERROR_DELETED
:
6739 case SCF_ERROR_CONNECTION_BROKEN
:
6742 case SCF_ERROR_NOT_SET
:
6743 case SCF_ERROR_NOT_BOUND
:
6745 bad_error("scf_instance_delete", scf_error());
6752 warn(gettext("Could not delete svc:/%s:%s "
6753 "(repository connection broken).\n"), imp_tsname
, inst
->sc_name
);
6754 lcbdata
->sc_err
= ECONNABORTED
;
6755 return (UU_WALK_ERROR
);
6759 * When an instance is imported we end up telling configd about it. Once we tell
6760 * configd about these changes, startd eventually notices. If this is a new
6761 * instance, the manifest may not specify the SCF_PG_RESTARTER (restarter)
6762 * property group. However, many of the other tools expect that this property
6763 * group exists and has certain values.
6765 * These values are added asynchronously by startd. We should not return from
6766 * this routine until we can verify that the property group we need is there.
6768 * Before we go ahead and verify this, we have to ask ourselves an important
6769 * question: Is the early manifest service currently running? Because if it is
6770 * running and it has invoked us, then the service will never get a restarter
6771 * property because svc.startd is blocked on EMI finishing before it lets itself
6772 * fully connect to svc.configd. Of course, this means that this race condition
6773 * is in fact impossible to 100% eliminate.
6775 * svc.startd makes sure that EMI only runs once and has succeeded by checking
6776 * the state of the EMI instance. If it is online it bails out and makes sure
6777 * that it doesn't run again. In this case, we're going to do something similar,
6778 * only if the state is online, then we're going to actually verify. EMI always
6779 * has to be present, but it can be explicitly disabled to reduce the amount of
6780 * damage it can cause. If EMI has been disabled then we no longer have to worry
6781 * about the implicit race condition and can go ahead and check things. If EMI
6782 * is in some state that isn't online or disabled and isn't runinng, then we
6783 * assume that things are rather bad and we're not going to get in your way,
6784 * even if the rest of SMF does.
6786 * Returns 0 on success or returns an errno.
6788 #ifndef NATIVE_BUILD
6790 lscf_instance_verify(scf_scope_t
*scope
, entity_t
*svc
, entity_t
*inst
)
6797 * smf_get_state does not distinguish between its different failure
6798 * modes: memory allocation failures and SMF internal failures.
6800 if ((emi_state
= smf_get_state(SCF_INSTANCE_EMI
)) == NULL
)
6804 * As per the block comment for this function check the state of EMI
6806 if (strcmp(emi_state
, SCF_STATE_STRING_ONLINE
) != 0 &&
6807 strcmp(emi_state
, SCF_STATE_STRING_DISABLED
) != 0) {
6808 warn(gettext("Not validating instance %s:%s because EMI's "
6809 "state is %s\n"), svc
->sc_name
, inst
->sc_name
, emi_state
);
6817 * First we have to get the property.
6819 if ((ret
= scf_scope_get_service(scope
, svc
->sc_name
, imp_svc
)) != 0) {
6821 warn(gettext("Failed to look up service: %s\n"), svc
->sc_name
);
6826 * We should always be able to get the instance. It should already
6827 * exist because we just created it or got it. There probably is a
6828 * slim chance that someone may have come in and deleted it though from
6831 if ((ret
= scf_service_get_instance(imp_svc
, inst
->sc_name
, imp_inst
))
6834 warn(gettext("Failed to verify instance: %s\n"), inst
->sc_name
);
6836 case SCF_ERROR_DELETED
:
6839 case SCF_ERROR_CONNECTION_BROKEN
:
6840 warn(gettext("Lost repository connection\n"));
6843 case SCF_ERROR_NOT_FOUND
:
6844 warn(gettext("Instance \"%s\" disappeared out from "
6845 "under us.\n"), inst
->sc_name
);
6849 bad_error("scf_service_get_instance", ret
);
6856 * An astute observer may want to use _scf_wait_pg which would notify us
6857 * of a property group change, unfortunately that does not work if the
6858 * property group in question does not exist. So instead we have to
6859 * manually poll and ask smf the best way to get to it.
6861 while ((ret
= scf_instance_get_pg(imp_inst
, SCF_PG_RESTARTER
, imp_pg
))
6864 if (ret
!= SCF_ERROR_NOT_FOUND
) {
6865 warn(gettext("Failed to get restarter property "
6866 "group for instance: %s\n"), inst
->sc_name
);
6868 case SCF_ERROR_DELETED
:
6871 case SCF_ERROR_CONNECTION_BROKEN
:
6872 warn(gettext("Lost repository connection\n"));
6876 bad_error("scf_service_get_instance", ret
);
6882 ts
.tv_sec
= pg_timeout
/ NANOSEC
;
6883 ts
.tv_nsec
= pg_timeout
% NANOSEC
;
6885 (void) nanosleep(&ts
, NULL
);
6889 * svcadm also expects that the SCF_PROPERTY_STATE property is present.
6890 * So in addition to the property group being present, we need to wait
6891 * for the property to be there in some form.
6893 * Note that a property group is a frozen snapshot in time. To properly
6894 * get beyond this, you have to refresh the property group each time.
6896 while ((ret
= scf_pg_get_property(imp_pg
, SCF_PROPERTY_STATE
,
6900 if (ret
!= SCF_ERROR_NOT_FOUND
) {
6901 warn(gettext("Failed to get property %s from the "
6902 "restarter property group of instance %s\n"),
6903 SCF_PROPERTY_STATE
, inst
->sc_name
);
6905 case SCF_ERROR_CONNECTION_BROKEN
:
6906 warn(gettext("Lost repository connection\n"));
6909 case SCF_ERROR_DELETED
:
6913 bad_error("scf_pg_get_property", ret
);
6919 ts
.tv_sec
= pg_timeout
/ NANOSEC
;
6920 ts
.tv_nsec
= pg_timeout
% NANOSEC
;
6922 (void) nanosleep(&ts
, NULL
);
6924 ret
= scf_instance_get_pg(imp_inst
, SCF_PG_RESTARTER
, imp_pg
);
6925 if (ret
!= SCF_SUCCESS
) {
6926 warn(gettext("Failed to get restarter property "
6927 "group for instance: %s\n"), inst
->sc_name
);
6929 case SCF_ERROR_DELETED
:
6932 case SCF_ERROR_CONNECTION_BROKEN
:
6933 warn(gettext("Lost repository connection\n"));
6937 bad_error("scf_service_get_instance", ret
);
6945 * We don't have to free the property groups or other values that we got
6946 * because we stored them in global variables that are allocated and
6947 * freed by the routines that call into these functions. Unless of
6948 * course the rest of the code here that we are basing this on is
6956 * If the service is missing, create it, import its properties, and import the
6957 * instances. Since the service is brand new, it should be empty, and if we
6958 * run into any existing entities (SCF_ERROR_EXISTS), abort.
6960 * If the service exists, we want to upgrade its properties and import the
6961 * instances. Upgrade requires a last-import snapshot, though, which are
6962 * children of instances, so first we'll have to go through the instances
6963 * looking for a last-import snapshot. If we don't find one then we'll just
6964 * override-import the service properties (but don't delete existing
6965 * properties: another service might have declared us as a dependent). Before
6966 * we change anything, though, we want to take the previous snapshots. We
6967 * also give lscf_instance_import() a leg up on taking last-import snapshots
6968 * by importing the manifest's service properties into a temporary service.
6970 * On success, returns UU_WALK_NEXT. On failure, returns UU_WALK_ERROR and
6971 * sets lcbdata->sc_err to
6972 * ECONNABORTED - repository connection broken
6973 * ENOMEM - out of memory
6974 * ENOSPC - svc.configd is out of resources
6975 * EPERM - couldn't create temporary service (error printed)
6976 * - couldn't import into temp service (error printed)
6977 * - couldn't create service (error printed)
6978 * - couldn't import dependent (error printed)
6979 * - couldn't take snapshot (error printed)
6980 * - couldn't create instance (error printed)
6981 * - couldn't create, modify, or delete pg (error printed)
6982 * - couldn't create, modify, or delete dependent (error printed)
6983 * - couldn't import instance (error printed)
6984 * EROFS - couldn't create temporary service (repository read-only)
6985 * - couldn't import into temporary service (repository read-only)
6986 * - couldn't create service (repository read-only)
6987 * - couldn't import dependent (repository read-only)
6988 * - couldn't create instance (repository read-only)
6989 * - couldn't create, modify, or delete pg or dependent
6990 * - couldn't import instance (repository read-only)
6991 * EACCES - couldn't create temporary service (backend access denied)
6992 * - couldn't import into temporary service (backend access denied)
6993 * - couldn't create service (backend access denied)
6994 * - couldn't import dependent (backend access denied)
6995 * - couldn't create instance (backend access denied)
6996 * - couldn't create, modify, or delete pg or dependent
6997 * - couldn't import instance (backend access denied)
6998 * EINVAL - service name is invalid (error printed)
6999 * - service name is too long (error printed)
7000 * - s has invalid pgroup (error printed)
7001 * - s has invalid dependent (error printed)
7002 * - instance name is invalid (error printed)
7003 * - instance entity_t is invalid (error printed)
7004 * EEXIST - couldn't create temporary service (already exists) (error printed)
7005 * - couldn't import dependent (dependency pg already exists) (printed)
7006 * - dependency collision in dependent service (error printed)
7007 * EBUSY - temporary service deleted (error printed)
7008 * - property group added to temporary service (error printed)
7009 * - new property group changed or was deleted (error printed)
7010 * - service was added unexpectedly (error printed)
7011 * - service was deleted unexpectedly (error printed)
7012 * - property group added to new service (error printed)
7013 * - instance added unexpectedly (error printed)
7014 * - instance deleted unexpectedly (error printed)
7015 * - dependent service deleted unexpectedly (error printed)
7016 * - pg was added, changed, or deleted (error printed)
7017 * - dependent pg changed (error printed)
7018 * - temporary instance added, changed, or deleted (error printed)
7019 * EBADF - a last-import snapshot is corrupt (error printed)
7020 * - the service is corrupt (error printed)
7021 * - a dependent is corrupt (error printed)
7022 * - an instance is corrupt (error printed)
7023 * - an instance has a corrupt last-import snapshot (error printed)
7024 * - dependent target has a corrupt snapshot (error printed)
7025 * -1 - unknown libscf error (error printed)
7028 lscf_service_import(void *v
, void *pvt
)
7031 scf_callback_t cbdata
;
7032 scf_callback_t
*lcbdata
= pvt
;
7033 scf_scope_t
*scope
= lcbdata
->sc_parent
;
7034 entity_t
*inst
, linst
;
7037 scf_snaplevel_t
*running
;
7039 boolean_t retried
= B_FALSE
;
7041 const char * const ts_deleted
= gettext("Temporary service svc:/%s "
7042 "was deleted unexpectedly.\n");
7043 const char * const ts_pg_added
= gettext("Temporary service svc:/%s "
7044 "changed unexpectedly (property group added).\n");
7045 const char * const s_deleted
=
7046 gettext("%s was deleted unexpectedly.\n");
7047 const char * const i_deleted
=
7048 gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
7049 const char * const badsnap
= gettext("\"%s\" snapshot of svc:/%s:%s "
7050 "is corrupt (missing service snaplevel).\n");
7051 const char * const s_mfile_upd
=
7052 gettext("Unable to update the manifest file connection "
7056 /* Validate the service name */
7057 if (scf_scope_get_service(scope
, s
->sc_name
, imp_svc
) != 0) {
7058 switch (scf_error()) {
7059 case SCF_ERROR_CONNECTION_BROKEN
:
7060 return (stash_scferror(lcbdata
));
7062 case SCF_ERROR_INVALID_ARGUMENT
:
7063 warn(gettext("\"%s\" is an invalid service name. "
7064 "Cannot import.\n"), s
->sc_name
);
7065 return (stash_scferror(lcbdata
));
7067 case SCF_ERROR_NOT_FOUND
:
7070 case SCF_ERROR_HANDLE_MISMATCH
:
7071 case SCF_ERROR_NOT_BOUND
:
7072 case SCF_ERROR_NOT_SET
:
7074 bad_error("scf_scope_get_service", scf_error());
7078 /* create temporary service */
7080 * the size of the buffer was reduced to max_scf_name_len to prevent
7081 * hitting bug 6681151. After the bug fix, the size of the buffer
7082 * should be restored to its original value (max_scf_name_len +1)
7084 r
= snprintf(imp_tsname
, max_scf_name_len
, "TEMP/%s", s
->sc_name
);
7086 bad_error("snprintf", errno
);
7087 if (r
> max_scf_name_len
) {
7089 "Service name \"%s\" is too long. Cannot import.\n"),
7091 lcbdata
->sc_err
= EINVAL
;
7092 return (UU_WALK_ERROR
);
7096 if (scf_scope_add_service(imp_scope
, imp_tsname
, imp_tsvc
) != 0) {
7097 switch (scf_error()) {
7098 case SCF_ERROR_CONNECTION_BROKEN
:
7099 case SCF_ERROR_NO_RESOURCES
:
7100 case SCF_ERROR_BACKEND_READONLY
:
7101 case SCF_ERROR_BACKEND_ACCESS
:
7102 return (stash_scferror(lcbdata
));
7104 case SCF_ERROR_EXISTS
:
7106 lscf_delete(imp_tsname
, 0);
7111 "Temporary service \"%s\" must be deleted before "
7112 "this manifest can be imported.\n"), imp_tsname
);
7113 return (stash_scferror(lcbdata
));
7115 case SCF_ERROR_PERMISSION_DENIED
:
7116 warn(gettext("Could not create temporary service "
7117 "\"%s\" (permission denied).\n"), imp_tsname
);
7118 return (stash_scferror(lcbdata
));
7120 case SCF_ERROR_INVALID_ARGUMENT
:
7121 case SCF_ERROR_HANDLE_MISMATCH
:
7122 case SCF_ERROR_NOT_BOUND
:
7123 case SCF_ERROR_NOT_SET
:
7125 bad_error("scf_scope_add_service", scf_error());
7129 r
= snprintf(imp_str
, imp_str_sz
, "svc:/%s", imp_tsname
);
7131 bad_error("snprintf", errno
);
7133 cbdata
.sc_handle
= lcbdata
->sc_handle
;
7134 cbdata
.sc_parent
= imp_tsvc
;
7135 cbdata
.sc_service
= 1;
7136 cbdata
.sc_source_fmri
= s
->sc_fmri
;
7137 cbdata
.sc_target_fmri
= imp_str
;
7138 cbdata
.sc_flags
= 0;
7140 if (uu_list_walk(s
->sc_pgroups
, entity_pgroup_import
, &cbdata
,
7142 if (uu_error() != UU_ERROR_CALLBACK_FAILED
)
7143 bad_error("uu_list_walk", uu_error());
7145 lcbdata
->sc_err
= cbdata
.sc_err
;
7146 switch (cbdata
.sc_err
) {
7151 warn(ts_deleted
, imp_tsname
);
7152 lcbdata
->sc_err
= EBUSY
;
7153 return (UU_WALK_ERROR
);
7156 warn(ts_pg_added
, imp_tsname
);
7157 lcbdata
->sc_err
= EBUSY
;
7158 return (UU_WALK_ERROR
);
7165 if (uu_list_walk(s
->sc_dependents
, entity_pgroup_import
, &cbdata
,
7167 if (uu_error() != UU_ERROR_CALLBACK_FAILED
)
7168 bad_error("uu_list_walk", uu_error());
7170 lcbdata
->sc_err
= cbdata
.sc_err
;
7171 switch (cbdata
.sc_err
) {
7176 warn(ts_deleted
, imp_tsname
);
7177 lcbdata
->sc_err
= EBUSY
;
7178 return (UU_WALK_ERROR
);
7181 warn(ts_pg_added
, imp_tsname
);
7182 lcbdata
->sc_err
= EBUSY
;
7183 return (UU_WALK_ERROR
);
7190 if (scf_scope_get_service(scope
, s
->sc_name
, imp_svc
) != 0) {
7191 switch (scf_error()) {
7192 case SCF_ERROR_NOT_FOUND
:
7195 case SCF_ERROR_CONNECTION_BROKEN
:
7198 case SCF_ERROR_INVALID_ARGUMENT
:
7199 case SCF_ERROR_HANDLE_MISMATCH
:
7200 case SCF_ERROR_NOT_BOUND
:
7201 case SCF_ERROR_NOT_SET
:
7203 bad_error("scf_scope_get_service", scf_error());
7206 if (scf_scope_add_service(scope
, s
->sc_name
, imp_svc
) != 0) {
7207 switch (scf_error()) {
7208 case SCF_ERROR_CONNECTION_BROKEN
:
7211 case SCF_ERROR_NO_RESOURCES
:
7212 case SCF_ERROR_BACKEND_READONLY
:
7213 case SCF_ERROR_BACKEND_ACCESS
:
7214 r
= stash_scferror(lcbdata
);
7217 case SCF_ERROR_EXISTS
:
7218 warn(gettext("Scope \"%s\" changed unexpectedly"
7219 " (service \"%s\" added).\n"),
7220 SCF_SCOPE_LOCAL
, s
->sc_name
);
7221 lcbdata
->sc_err
= EBUSY
;
7224 case SCF_ERROR_PERMISSION_DENIED
:
7225 warn(gettext("Could not create service \"%s\" "
7226 "(permission denied).\n"), s
->sc_name
);
7229 case SCF_ERROR_INVALID_ARGUMENT
:
7230 case SCF_ERROR_HANDLE_MISMATCH
:
7231 case SCF_ERROR_NOT_BOUND
:
7232 case SCF_ERROR_NOT_SET
:
7234 bad_error("scf_scope_add_service", scf_error());
7238 s
->sc_import_state
= IMPORT_PROP_BEGUN
;
7240 /* import service properties */
7241 cbdata
.sc_handle
= lcbdata
->sc_handle
;
7242 cbdata
.sc_parent
= imp_svc
;
7243 cbdata
.sc_service
= 1;
7244 cbdata
.sc_flags
= lcbdata
->sc_flags
;
7245 cbdata
.sc_source_fmri
= s
->sc_fmri
;
7246 cbdata
.sc_target_fmri
= s
->sc_fmri
;
7248 if (uu_list_walk(s
->sc_pgroups
, entity_pgroup_import
,
7249 &cbdata
, UU_DEFAULT
) != 0) {
7250 if (uu_error() != UU_ERROR_CALLBACK_FAILED
)
7251 bad_error("uu_list_walk", uu_error());
7253 lcbdata
->sc_err
= cbdata
.sc_err
;
7254 switch (cbdata
.sc_err
) {
7259 warn(s_deleted
, s
->sc_fmri
);
7260 lcbdata
->sc_err
= EBUSY
;
7261 return (UU_WALK_ERROR
);
7264 warn(gettext("%s changed unexpectedly "
7265 "(property group added).\n"), s
->sc_fmri
);
7266 lcbdata
->sc_err
= EBUSY
;
7267 return (UU_WALK_ERROR
);
7271 bad_error("entity_pgroup_import",
7279 cbdata
.sc_trans
= NULL
;
7280 cbdata
.sc_flags
= 0;
7281 if (uu_list_walk(s
->sc_dependents
, lscf_dependent_import
,
7282 &cbdata
, UU_DEFAULT
) != 0) {
7283 if (uu_error() != UU_ERROR_CALLBACK_FAILED
)
7284 bad_error("uu_list_walk", uu_error());
7286 lcbdata
->sc_err
= cbdata
.sc_err
;
7287 if (cbdata
.sc_err
== ECONNABORTED
)
7293 s
->sc_import_state
= IMPORT_PROP_DONE
;
7296 * This is a new service, so we can't take previous snapshots
7297 * or upgrade service properties.
7303 /* Clear sc_seen for the instances. */
7304 if (uu_list_walk(s
->sc_u
.sc_service
.sc_service_instances
, clear_int
,
7305 (void *)offsetof(entity_t
, sc_seen
), UU_DEFAULT
) != 0)
7306 bad_error("uu_list_walk", uu_error());
7309 * Take previous snapshots for all instances. Even for ones not
7310 * mentioned in the bundle, since we might change their service
7313 if (scf_iter_service_instances(imp_iter
, imp_svc
) != 0) {
7314 switch (scf_error()) {
7315 case SCF_ERROR_CONNECTION_BROKEN
:
7318 case SCF_ERROR_DELETED
:
7319 warn(s_deleted
, s
->sc_fmri
);
7320 lcbdata
->sc_err
= EBUSY
;
7324 case SCF_ERROR_HANDLE_MISMATCH
:
7325 case SCF_ERROR_NOT_BOUND
:
7326 case SCF_ERROR_NOT_SET
:
7328 bad_error("scf_iter_service_instances", scf_error());
7333 r
= scf_iter_next_instance(imp_iter
, imp_inst
);
7337 switch (scf_error()) {
7338 case SCF_ERROR_DELETED
:
7339 warn(s_deleted
, s
->sc_fmri
);
7340 lcbdata
->sc_err
= EBUSY
;
7344 case SCF_ERROR_CONNECTION_BROKEN
:
7347 case SCF_ERROR_NOT_BOUND
:
7348 case SCF_ERROR_HANDLE_MISMATCH
:
7349 case SCF_ERROR_INVALID_ARGUMENT
:
7350 case SCF_ERROR_NOT_SET
:
7352 bad_error("scf_iter_next_instance",
7357 if (scf_instance_get_name(imp_inst
, imp_str
, imp_str_sz
) < 0) {
7358 switch (scf_error()) {
7359 case SCF_ERROR_DELETED
:
7362 case SCF_ERROR_CONNECTION_BROKEN
:
7365 case SCF_ERROR_NOT_SET
:
7366 case SCF_ERROR_NOT_BOUND
:
7368 bad_error("scf_instance_get_name", scf_error());
7374 "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
7375 snap_previous
, s
->sc_name
, imp_str
);
7377 r
= take_snap(imp_inst
, snap_previous
, imp_snap
);
7389 warn(gettext("Could not take \"%s\" snapshot of "
7390 "svc:/%s:%s (permission denied).\n"),
7391 snap_previous
, s
->sc_name
, imp_str
);
7392 lcbdata
->sc_err
= r
;
7393 return (UU_WALK_ERROR
);
7397 lcbdata
->sc_err
= r
;
7402 bad_error("take_snap", r
);
7405 linst
.sc_name
= imp_str
;
7406 inst
= uu_list_find(s
->sc_u
.sc_service
.sc_service_instances
,
7407 &linst
, NULL
, NULL
);
7409 inst
->sc_import_state
= IMPORT_PREVIOUS
;
7415 * Create the new instances and take previous snapshots of
7416 * them. This is not necessary, but it maximizes data preservation.
7418 for (inst
= uu_list_first(s
->sc_u
.sc_service
.sc_service_instances
);
7420 inst
= uu_list_next(s
->sc_u
.sc_service
.sc_service_instances
,
7425 if (scf_service_add_instance(imp_svc
, inst
->sc_name
,
7427 switch (scf_error()) {
7428 case SCF_ERROR_CONNECTION_BROKEN
:
7431 case SCF_ERROR_BACKEND_READONLY
:
7432 case SCF_ERROR_BACKEND_ACCESS
:
7433 case SCF_ERROR_NO_RESOURCES
:
7434 r
= stash_scferror(lcbdata
);
7437 case SCF_ERROR_EXISTS
:
7438 warn(gettext("%s changed unexpectedly "
7439 "(instance \"%s\" added).\n"), s
->sc_fmri
,
7441 lcbdata
->sc_err
= EBUSY
;
7445 case SCF_ERROR_INVALID_ARGUMENT
:
7446 warn(gettext("Service \"%s\" has instance with "
7447 "invalid name \"%s\".\n"), s
->sc_name
,
7449 r
= stash_scferror(lcbdata
);
7452 case SCF_ERROR_PERMISSION_DENIED
:
7453 warn(gettext("Could not create instance \"%s\" "
7454 "in %s (permission denied).\n"),
7455 inst
->sc_name
, s
->sc_fmri
);
7456 r
= stash_scferror(lcbdata
);
7459 case SCF_ERROR_HANDLE_MISMATCH
:
7460 case SCF_ERROR_NOT_BOUND
:
7461 case SCF_ERROR_NOT_SET
:
7463 bad_error("scf_service_add_instance",
7469 warn(gettext("Taking \"%s\" snapshot for "
7470 "new service %s.\n"), snap_previous
, inst
->sc_fmri
);
7471 r
= take_snap(imp_inst
, snap_previous
, imp_snap
);
7477 warn(i_deleted
, s
->sc_fmri
, inst
->sc_name
);
7478 lcbdata
->sc_err
= EBUSY
;
7486 warn(emsg_snap_perm
, snap_previous
, inst
->sc_fmri
);
7487 lcbdata
->sc_err
= r
;
7497 bad_error("take_snap", r
);
7501 s
->sc_import_state
= IMPORT_PREVIOUS
;
7504 * Upgrade service properties, if we can find a last-import snapshot.
7505 * Any will do because we don't support different service properties
7506 * in different manifests, so all snaplevels of the service in all of
7507 * the last-import snapshots of the instances should be the same.
7509 if (scf_iter_service_instances(imp_iter
, imp_svc
) != 0) {
7510 switch (scf_error()) {
7511 case SCF_ERROR_CONNECTION_BROKEN
:
7514 case SCF_ERROR_DELETED
:
7515 warn(s_deleted
, s
->sc_fmri
);
7516 lcbdata
->sc_err
= EBUSY
;
7520 case SCF_ERROR_HANDLE_MISMATCH
:
7521 case SCF_ERROR_NOT_BOUND
:
7522 case SCF_ERROR_NOT_SET
:
7524 bad_error("scf_iter_service_instances", scf_error());
7529 r
= scf_iter_next_instance(imp_iter
, imp_inst
);
7531 switch (scf_error()) {
7532 case SCF_ERROR_DELETED
:
7533 warn(s_deleted
, s
->sc_fmri
);
7534 lcbdata
->sc_err
= EBUSY
;
7538 case SCF_ERROR_CONNECTION_BROKEN
:
7541 case SCF_ERROR_NOT_BOUND
:
7542 case SCF_ERROR_HANDLE_MISMATCH
:
7543 case SCF_ERROR_INVALID_ARGUMENT
:
7544 case SCF_ERROR_NOT_SET
:
7546 bad_error("scf_iter_next_instance",
7553 * Didn't find any last-import snapshots. Override-
7554 * import the properties. Unless one of the instances
7555 * has a general/enabled property, in which case we're
7556 * probably running a last-import-capable svccfg for
7557 * the first time, and we should only take the
7558 * last-import snapshot.
7562 scf_callback_t mfcbdata
;
7567 * Need to go ahead and import the manifestfiles
7568 * pg if it exists. If the last-import snapshot
7569 * upgrade code is ever removed this code can
7570 * be removed as well.
7572 mfpg
= internal_pgroup_find(s
,
7573 SCF_PG_MANIFESTFILES
, SCF_GROUP_FRAMEWORK
);
7576 mfcbdata
.sc_handle
= g_hndl
;
7577 mfcbdata
.sc_parent
= imp_svc
;
7578 mfcbdata
.sc_service
= 1;
7579 mfcbdata
.sc_flags
= SCI_FORCE
;
7580 mfcbdata
.sc_source_fmri
= s
->sc_fmri
;
7581 mfcbdata
.sc_target_fmri
= s
->sc_fmri
;
7582 if (entity_pgroup_import(mfpg
,
7583 &mfcbdata
) != UU_WALK_NEXT
) {
7584 warn(s_mfile_upd
, s
->sc_fmri
);
7592 s
->sc_import_state
= IMPORT_PROP_BEGUN
;
7594 cbdata
.sc_handle
= g_hndl
;
7595 cbdata
.sc_parent
= imp_svc
;
7596 cbdata
.sc_service
= 1;
7597 cbdata
.sc_flags
= SCI_FORCE
;
7598 cbdata
.sc_source_fmri
= s
->sc_fmri
;
7599 cbdata
.sc_target_fmri
= s
->sc_fmri
;
7600 if (uu_list_walk(s
->sc_pgroups
, entity_pgroup_import
,
7601 &cbdata
, UU_DEFAULT
) != 0) {
7602 if (uu_error() != UU_ERROR_CALLBACK_FAILED
)
7603 bad_error("uu_list_walk", uu_error());
7604 lcbdata
->sc_err
= cbdata
.sc_err
;
7605 switch (cbdata
.sc_err
) {
7610 warn(s_deleted
, s
->sc_fmri
);
7611 lcbdata
->sc_err
= EBUSY
;
7614 case EINVAL
: /* caught above */
7616 bad_error("entity_pgroup_import",
7624 cbdata
.sc_trans
= NULL
;
7625 cbdata
.sc_flags
= 0;
7626 if (uu_list_walk(s
->sc_dependents
,
7627 lscf_dependent_import
, &cbdata
, UU_DEFAULT
) != 0) {
7628 if (uu_error() != UU_ERROR_CALLBACK_FAILED
)
7629 bad_error("uu_list_walk", uu_error());
7630 lcbdata
->sc_err
= cbdata
.sc_err
;
7631 if (cbdata
.sc_err
== ECONNABORTED
)
7639 if (scf_instance_get_snapshot(imp_inst
, snap_lastimport
,
7641 switch (scf_error()) {
7642 case SCF_ERROR_DELETED
:
7645 case SCF_ERROR_NOT_FOUND
:
7648 case SCF_ERROR_CONNECTION_BROKEN
:
7651 case SCF_ERROR_HANDLE_MISMATCH
:
7652 case SCF_ERROR_NOT_BOUND
:
7653 case SCF_ERROR_INVALID_ARGUMENT
:
7654 case SCF_ERROR_NOT_SET
:
7656 bad_error("scf_instance_get_snapshot",
7664 * Check for a general/enabled property. This is how
7665 * we tell whether to import if there turn out to be
7666 * no last-import snapshots.
7668 if (scf_instance_get_pg(imp_inst
, SCF_PG_GENERAL
,
7670 if (scf_pg_get_property(imp_pg
,
7671 SCF_PROPERTY_ENABLED
, imp_prop
) == 0) {
7674 switch (scf_error()) {
7675 case SCF_ERROR_DELETED
:
7676 case SCF_ERROR_NOT_FOUND
:
7679 case SCF_ERROR_INVALID_ARGUMENT
:
7680 case SCF_ERROR_HANDLE_MISMATCH
:
7681 case SCF_ERROR_CONNECTION_BROKEN
:
7682 case SCF_ERROR_NOT_BOUND
:
7683 case SCF_ERROR_NOT_SET
:
7685 bad_error("scf_pg_get_property",
7690 switch (scf_error()) {
7691 case SCF_ERROR_DELETED
:
7692 case SCF_ERROR_NOT_FOUND
:
7695 case SCF_ERROR_CONNECTION_BROKEN
:
7698 case SCF_ERROR_NOT_BOUND
:
7699 case SCF_ERROR_NOT_SET
:
7700 case SCF_ERROR_INVALID_ARGUMENT
:
7701 case SCF_ERROR_HANDLE_MISMATCH
:
7703 bad_error("scf_instance_get_pg",
7710 /* find service snaplevel */
7711 r
= get_snaplevel(imp_snap
, 1, imp_snpl
);
7723 if (scf_instance_get_name(imp_inst
, imp_str
,
7725 (void) strcpy(imp_str
, "?");
7726 warn(badsnap
, snap_lastimport
, s
->sc_name
, imp_str
);
7727 lcbdata
->sc_err
= EBADF
;
7732 bad_error("get_snaplevel", r
);
7735 if (scf_instance_get_snapshot(imp_inst
, snap_running
,
7737 switch (scf_error()) {
7738 case SCF_ERROR_DELETED
:
7741 case SCF_ERROR_NOT_FOUND
:
7744 case SCF_ERROR_CONNECTION_BROKEN
:
7747 case SCF_ERROR_INVALID_ARGUMENT
:
7748 case SCF_ERROR_HANDLE_MISMATCH
:
7749 case SCF_ERROR_NOT_BOUND
:
7750 case SCF_ERROR_NOT_SET
:
7752 bad_error("scf_instance_get_snapshot",
7757 r
= get_snaplevel(imp_rsnap
, 1, imp_rsnpl
);
7760 running
= imp_rsnpl
;
7770 if (scf_instance_get_name(imp_inst
, imp_str
,
7772 (void) strcpy(imp_str
, "?");
7773 warn(badsnap
, snap_running
, s
->sc_name
,
7775 lcbdata
->sc_err
= EBADF
;
7780 bad_error("get_snaplevel", r
);
7785 if (scf_instance_get_name(imp_inst
, imp_str
,
7787 (void) strcpy(imp_str
, "?");
7788 warn(gettext("Upgrading properties of %s according to "
7789 "instance \"%s\".\n"), s
->sc_fmri
, imp_str
);
7792 /* upgrade service properties */
7793 r
= upgrade_props(imp_svc
, running
, imp_snpl
, s
);
7802 warn(s_deleted
, s
->sc_fmri
);
7803 lcbdata
->sc_err
= EBUSY
;
7807 if (scf_instance_get_name(imp_inst
, imp_str
,
7809 (void) strcpy(imp_str
, "?");
7810 warn(i_deleted
, s
->sc_fmri
, imp_str
);
7811 lcbdata
->sc_err
= EBUSY
;
7815 lcbdata
->sc_err
= r
;
7822 s
->sc_import_state
= IMPORT_PROP_DONE
;
7825 /* import instances */
7826 cbdata
.sc_handle
= lcbdata
->sc_handle
;
7827 cbdata
.sc_parent
= imp_svc
;
7828 cbdata
.sc_service
= 1;
7829 cbdata
.sc_flags
= lcbdata
->sc_flags
| (fresh
? SCI_FRESH
: 0);
7830 cbdata
.sc_general
= NULL
;
7832 if (uu_list_walk(s
->sc_u
.sc_service
.sc_service_instances
,
7833 lscf_instance_import
, &cbdata
, UU_DEFAULT
) != 0) {
7834 if (uu_error() != UU_ERROR_CALLBACK_FAILED
)
7835 bad_error("uu_list_walk", uu_error());
7837 lcbdata
->sc_err
= cbdata
.sc_err
;
7838 if (cbdata
.sc_err
== ECONNABORTED
)
7844 s
->sc_import_state
= IMPORT_COMPLETE
;
7848 /* delete temporary service */
7849 if (scf_service_delete(imp_tsvc
) != 0) {
7850 switch (scf_error()) {
7851 case SCF_ERROR_DELETED
:
7854 case SCF_ERROR_CONNECTION_BROKEN
:
7857 case SCF_ERROR_EXISTS
:
7859 "Could not delete svc:/%s (instances exist).\n"),
7863 case SCF_ERROR_NOT_SET
:
7864 case SCF_ERROR_NOT_BOUND
:
7866 bad_error("scf_service_delete", scf_error());
7873 warn(gettext("Could not delete svc:/%s "
7874 "(repository connection broken).\n"), imp_tsname
);
7875 lcbdata
->sc_err
= ECONNABORTED
;
7876 return (UU_WALK_ERROR
);
7880 import_progress(int st
)
7884 return (gettext("not reached."));
7886 case IMPORT_PREVIOUS
:
7887 return (gettext("previous snapshot taken."));
7889 case IMPORT_PROP_BEGUN
:
7890 return (gettext("some properties imported."));
7892 case IMPORT_PROP_DONE
:
7893 return (gettext("properties imported."));
7895 case IMPORT_COMPLETE
:
7896 return (gettext("imported."));
7898 case IMPORT_REFRESHED
:
7899 return (gettext("refresh requested."));
7903 (void) fprintf(stderr
, "%s:%d: Unknown entity state %d.\n",
7904 __FILE__
, __LINE__
, st
);
7914 * - fmri wasn't found (error printed)
7915 * - entity was deleted (error printed)
7916 * - backend denied access (error printed)
7917 * ENOMEM - out of memory (error printed)
7918 * ECONNABORTED - repository connection broken (error printed)
7919 * EPERM - permission denied (error printed)
7920 * -1 - unknown libscf error (error printed)
7923 imp_refresh_fmri(const char *fmri
, const char *name
, const char *d_fmri
)
7930 const char *deleted
= gettext("Could not refresh %s (deleted).\n");
7931 const char *dpt_deleted
= gettext("Could not refresh %s "
7932 "(dependent \"%s\" of %s) (deleted).\n");
7934 serr
= fmri_to_entity(g_hndl
, fmri
, &ent
, &issvc
);
7936 case SCF_ERROR_NONE
:
7939 case SCF_ERROR_NO_MEMORY
:
7941 warn(gettext("Could not refresh %s (out of memory).\n"),
7944 warn(gettext("Could not refresh %s "
7945 "(dependent \"%s\" of %s) (out of memory).\n"),
7946 fmri
, name
, d_fmri
);
7949 case SCF_ERROR_NOT_FOUND
:
7951 warn(deleted
, fmri
);
7953 warn(dpt_deleted
, fmri
, name
, d_fmri
);
7956 case SCF_ERROR_INVALID_ARGUMENT
:
7957 case SCF_ERROR_CONSTRAINT_VIOLATED
:
7959 bad_error("fmri_to_entity", serr
);
7962 r
= refresh_entity(issvc
, ent
, fmri
, imp_inst
, imp_iter
, imp_str
);
7969 warn(gettext("Could not refresh %s "
7970 "(dependent \"%s\" of %s) "
7971 "(repository connection broken).\n"), fmri
, name
,
7977 warn(deleted
, fmri
);
7979 warn(dpt_deleted
, fmri
, name
, d_fmri
);
7986 warn(gettext("Could not refresh %s "
7987 "(backend access denied).\n"), fmri
);
7989 warn(gettext("Could not refresh %s "
7990 "(dependent \"%s\" of %s) "
7991 "(backend access denied).\n"), fmri
, name
, d_fmri
);
7996 warn(gettext("Could not refresh %s "
7997 "(permission denied).\n"), fmri
);
7999 warn(gettext("Could not refresh %s "
8000 "(dependent \"%s\" of %s) "
8001 "(permission denied).\n"), fmri
, name
, d_fmri
);
8006 warn(gettext("Could not refresh %s "
8007 "(repository server out of resources).\n"),
8010 warn(gettext("Could not refresh %s "
8011 "(dependent \"%s\" of %s) "
8012 "(repository server out of resources).\n"),
8013 fmri
, name
, d_fmri
);
8021 bad_error("refresh_entity", r
);
8025 scf_service_destroy(ent
);
8027 scf_instance_destroy(ent
);
8037 const char * const emsg_nomem
= gettext("Out of memory.\n");
8038 const char * const emsg_nores
=
8039 gettext("svc.configd is out of resources.\n");
8041 imp_str_sz
= ((max_scf_name_len
> max_scf_fmri_len
) ?
8042 max_scf_name_len
: max_scf_fmri_len
) + 1;
8044 if ((imp_scope
= scf_scope_create(g_hndl
)) == NULL
||
8045 (imp_svc
= scf_service_create(g_hndl
)) == NULL
||
8046 (imp_tsvc
= scf_service_create(g_hndl
)) == NULL
||
8047 (imp_inst
= scf_instance_create(g_hndl
)) == NULL
||
8048 (imp_tinst
= scf_instance_create(g_hndl
)) == NULL
||
8049 (imp_snap
= scf_snapshot_create(g_hndl
)) == NULL
||
8050 (imp_lisnap
= scf_snapshot_create(g_hndl
)) == NULL
||
8051 (imp_tlisnap
= scf_snapshot_create(g_hndl
)) == NULL
||
8052 (imp_rsnap
= scf_snapshot_create(g_hndl
)) == NULL
||
8053 (imp_snpl
= scf_snaplevel_create(g_hndl
)) == NULL
||
8054 (imp_rsnpl
= scf_snaplevel_create(g_hndl
)) == NULL
||
8055 (imp_pg
= scf_pg_create(g_hndl
)) == NULL
||
8056 (imp_pg2
= scf_pg_create(g_hndl
)) == NULL
||
8057 (imp_prop
= scf_property_create(g_hndl
)) == NULL
||
8058 (imp_iter
= scf_iter_create(g_hndl
)) == NULL
||
8059 (imp_rpg_iter
= scf_iter_create(g_hndl
)) == NULL
||
8060 (imp_up_iter
= scf_iter_create(g_hndl
)) == NULL
||
8061 (imp_tx
= scf_transaction_create(g_hndl
)) == NULL
||
8062 (imp_str
= malloc(imp_str_sz
)) == NULL
||
8063 (imp_tsname
= malloc(max_scf_name_len
+ 1)) == NULL
||
8064 (imp_fe1
= malloc(max_scf_fmri_len
+ 1)) == NULL
||
8065 (imp_fe2
= malloc(max_scf_fmri_len
+ 1)) == NULL
||
8066 (imp_deleted_dpts
= uu_list_create(string_pool
, NULL
, 0)) == NULL
||
8067 (ud_inst
= scf_instance_create(g_hndl
)) == NULL
||
8068 (ud_snpl
= scf_snaplevel_create(g_hndl
)) == NULL
||
8069 (ud_pg
= scf_pg_create(g_hndl
)) == NULL
||
8070 (ud_cur_depts_pg
= scf_pg_create(g_hndl
)) == NULL
||
8071 (ud_run_dpts_pg
= scf_pg_create(g_hndl
)) == NULL
||
8072 (ud_prop
= scf_property_create(g_hndl
)) == NULL
||
8073 (ud_dpt_prop
= scf_property_create(g_hndl
)) == NULL
||
8074 (ud_val
= scf_value_create(g_hndl
)) == NULL
||
8075 (ud_iter
= scf_iter_create(g_hndl
)) == NULL
||
8076 (ud_iter2
= scf_iter_create(g_hndl
)) == NULL
||
8077 (ud_tx
= scf_transaction_create(g_hndl
)) == NULL
||
8078 (ud_ctarg
= malloc(max_scf_value_len
+ 1)) == NULL
||
8079 (ud_oldtarg
= malloc(max_scf_value_len
+ 1)) == NULL
||
8080 (ud_name
= malloc(max_scf_name_len
+ 1)) == NULL
) {
8081 if (scf_error() == SCF_ERROR_NO_RESOURCES
)
8099 bad_error("load_init", r
);
8116 ud_ctarg
= ud_oldtarg
= ud_name
= NULL
;
8118 scf_transaction_destroy(ud_tx
);
8120 scf_iter_destroy(ud_iter
);
8121 scf_iter_destroy(ud_iter2
);
8122 ud_iter
= ud_iter2
= NULL
;
8123 scf_value_destroy(ud_val
);
8125 scf_property_destroy(ud_prop
);
8126 scf_property_destroy(ud_dpt_prop
);
8127 ud_prop
= ud_dpt_prop
= NULL
;
8128 scf_pg_destroy(ud_pg
);
8129 scf_pg_destroy(ud_cur_depts_pg
);
8130 scf_pg_destroy(ud_run_dpts_pg
);
8131 ud_pg
= ud_cur_depts_pg
= ud_run_dpts_pg
= NULL
;
8132 scf_snaplevel_destroy(ud_snpl
);
8134 scf_instance_destroy(ud_inst
);
8141 imp_str
= imp_tsname
= imp_fe1
= imp_fe2
= NULL
;
8144 while ((old_dpt
= uu_list_teardown(imp_deleted_dpts
, &cookie
)) !=
8146 free((char *)old_dpt
->sc_pgroup_name
);
8147 free((char *)old_dpt
->sc_pgroup_fmri
);
8148 internal_pgroup_free(old_dpt
);
8150 uu_list_destroy(imp_deleted_dpts
);
8152 scf_transaction_destroy(imp_tx
);
8154 scf_iter_destroy(imp_iter
);
8155 scf_iter_destroy(imp_rpg_iter
);
8156 scf_iter_destroy(imp_up_iter
);
8157 imp_iter
= imp_rpg_iter
= imp_up_iter
= NULL
;
8158 scf_property_destroy(imp_prop
);
8160 scf_pg_destroy(imp_pg
);
8161 scf_pg_destroy(imp_pg2
);
8162 imp_pg
= imp_pg2
= NULL
;
8163 scf_snaplevel_destroy(imp_snpl
);
8164 scf_snaplevel_destroy(imp_rsnpl
);
8165 imp_snpl
= imp_rsnpl
= NULL
;
8166 scf_snapshot_destroy(imp_snap
);
8167 scf_snapshot_destroy(imp_lisnap
);
8168 scf_snapshot_destroy(imp_tlisnap
);
8169 scf_snapshot_destroy(imp_rsnap
);
8170 imp_snap
= imp_lisnap
= imp_tlisnap
= imp_rsnap
= NULL
;
8171 scf_instance_destroy(imp_inst
);
8172 scf_instance_destroy(imp_tinst
);
8173 imp_inst
= imp_tinst
= NULL
;
8174 scf_service_destroy(imp_svc
);
8175 scf_service_destroy(imp_tsvc
);
8176 imp_svc
= imp_tsvc
= NULL
;
8177 scf_scope_destroy(imp_scope
);
8184 lscf_bundle_import(bundle_t
*bndl
, const char *filename
, uint_t flags
)
8186 scf_callback_t cbdata
;
8188 entity_t
*svc
, *inst
;
8192 int annotation_set
= 0;
8194 const char * const emsg_nomem
= gettext("Out of memory.\n");
8195 const char * const emsg_nores
=
8196 gettext("svc.configd is out of resources.\n");
8200 if (alloc_imp_globals())
8203 if (scf_handle_get_scope(g_hndl
, SCF_SCOPE_LOCAL
, imp_scope
) != 0) {
8204 switch (scf_error()) {
8205 case SCF_ERROR_CONNECTION_BROKEN
:
8206 warn(gettext("Repository connection broken.\n"));
8207 repository_teardown();
8211 case SCF_ERROR_NOT_FOUND
:
8212 case SCF_ERROR_INVALID_ARGUMENT
:
8213 case SCF_ERROR_NOT_BOUND
:
8214 case SCF_ERROR_HANDLE_MISMATCH
:
8216 bad_error("scf_handle_get_scope", scf_error());
8220 /* Set up the auditing annotation. */
8221 if (_scf_set_annotation(g_hndl
, "svccfg import", filename
) == 0) {
8224 switch (scf_error()) {
8225 case SCF_ERROR_CONNECTION_BROKEN
:
8226 warn(gettext("Repository connection broken.\n"));
8227 repository_teardown();
8231 case SCF_ERROR_INVALID_ARGUMENT
:
8232 case SCF_ERROR_NOT_BOUND
:
8233 case SCF_ERROR_NO_RESOURCES
:
8234 case SCF_ERROR_INTERNAL
:
8235 bad_error("_scf_set_annotation", scf_error());
8240 * Do not terminate import because of inability to
8241 * generate annotation audit event.
8243 warn(gettext("_scf_set_annotation() unexpectedly "
8244 "failed with return code of %d\n"), scf_error());
8250 * Clear the sc_import_state's of all services & instances so we can
8251 * report how far we got if we fail.
8253 for (svc
= uu_list_first(bndl
->sc_bundle_services
);
8255 svc
= uu_list_next(bndl
->sc_bundle_services
, svc
)) {
8256 svc
->sc_import_state
= 0;
8258 if (uu_list_walk(svc
->sc_u
.sc_service
.sc_service_instances
,
8259 clear_int
, (void *)offsetof(entity_t
, sc_import_state
),
8261 bad_error("uu_list_walk", uu_error());
8264 cbdata
.sc_handle
= g_hndl
;
8265 cbdata
.sc_parent
= imp_scope
;
8266 cbdata
.sc_flags
= flags
;
8267 cbdata
.sc_general
= NULL
;
8269 if (uu_list_walk(bndl
->sc_bundle_services
, lscf_service_import
,
8270 &cbdata
, UU_DEFAULT
) == 0) {
8271 /* Success. Refresh everything. */
8273 if (flags
& SCI_NOREFRESH
|| no_refresh
) {
8279 for (svc
= uu_list_first(bndl
->sc_bundle_services
);
8281 svc
= uu_list_next(bndl
->sc_bundle_services
, svc
)) {
8284 insts
= svc
->sc_u
.sc_service
.sc_service_instances
;
8286 for (inst
= uu_list_first(insts
);
8288 inst
= uu_list_next(insts
, inst
)) {
8289 r
= imp_refresh_fmri(inst
->sc_fmri
, NULL
, NULL
);
8301 bad_error("imp_refresh_fmri", r
);
8304 inst
->sc_import_state
= IMPORT_REFRESHED
;
8306 for (dpt
= uu_list_first(inst
->sc_dependents
);
8308 dpt
= uu_list_next(inst
->sc_dependents
,
8310 if (imp_refresh_fmri(
8311 dpt
->sc_pgroup_fmri
,
8312 dpt
->sc_pgroup_name
,
8313 inst
->sc_fmri
) != 0)
8317 for (dpt
= uu_list_first(svc
->sc_dependents
);
8319 dpt
= uu_list_next(svc
->sc_dependents
, dpt
))
8320 if (imp_refresh_fmri(dpt
->sc_pgroup_fmri
,
8321 dpt
->sc_pgroup_name
, svc
->sc_fmri
) != 0)
8325 for (old_dpt
= uu_list_first(imp_deleted_dpts
);
8327 old_dpt
= uu_list_next(imp_deleted_dpts
, old_dpt
))
8328 if (imp_refresh_fmri(old_dpt
->sc_pgroup_fmri
,
8329 old_dpt
->sc_pgroup_name
,
8330 old_dpt
->sc_parent
->sc_fmri
) != 0)
8336 * This snippet of code assumes that we are running svccfg as we
8337 * normally do -- witih svc.startd running. Of course, that is
8338 * not actually the case all the time because we also use a
8339 * varient of svc.configd and svccfg which are only meant to
8340 * run during the build process. During this time we have no
8341 * svc.startd, so this check would hang the build process.
8343 #ifndef NATIVE_BUILD
8345 * Verify that the restarter group is preset
8347 for (svc
= uu_list_first(bndl
->sc_bundle_services
);
8349 svc
= uu_list_next(bndl
->sc_bundle_services
, svc
)) {
8351 insts
= svc
->sc_u
.sc_service
.sc_service_instances
;
8353 for (inst
= uu_list_first(insts
);
8355 inst
= uu_list_next(insts
, inst
)) {
8356 if (lscf_instance_verify(imp_scope
, svc
,
8366 if (uu_error() != UU_ERROR_CALLBACK_FAILED
)
8367 bad_error("uu_list_walk", uu_error());
8370 /* If the error hasn't been printed yet, do so here. */
8371 switch (cbdata
.sc_err
) {
8373 warn(gettext("Repository connection broken.\n"));
8385 warn(gettext("Repository is read-only.\n"));
8389 warn(gettext("Repository backend denied access.\n"));
8401 bad_error("lscf_service_import", cbdata
.sc_err
);
8405 warn(gettext("Import of %s failed. Progress:\n"), filename
);
8407 for (svc
= uu_list_first(bndl
->sc_bundle_services
);
8409 svc
= uu_list_next(bndl
->sc_bundle_services
, svc
)) {
8410 insts
= svc
->sc_u
.sc_service
.sc_service_instances
;
8412 warn(gettext(" Service \"%s\": %s\n"), svc
->sc_name
,
8413 import_progress(svc
->sc_import_state
));
8415 for (inst
= uu_list_first(insts
);
8417 inst
= uu_list_next(insts
, inst
))
8418 warn(gettext(" Instance \"%s\": %s\n"),
8420 import_progress(inst
->sc_import_state
));
8423 if (cbdata
.sc_err
== ECONNABORTED
)
8424 repository_teardown();
8430 if (annotation_set
!= 0) {
8431 /* Turn off annotation. It is no longer needed. */
8432 (void) _scf_set_annotation(g_hndl
, NULL
, NULL
);
8441 * _lscf_import_err() summarize the error handling returned by
8442 * lscf_import_{instance | service}_pgs
8443 * Return values are:
8449 #define IMPORT_BAD -1
8450 #define IMPORT_NEXT 0
8451 #define IMPORT_OUT 1
8454 _lscf_import_err(int err
, const char *fmri
)
8459 warn(gettext("%s updated.\n"), fmri
);
8460 return (IMPORT_NEXT
);
8463 warn(gettext("Could not update %s "
8464 "(repository connection broken).\n"), fmri
);
8465 return (IMPORT_OUT
);
8468 warn(gettext("Could not update %s (out of memory).\n"), fmri
);
8469 return (IMPORT_OUT
);
8472 warn(gettext("Could not update %s "
8473 "(repository server out of resources).\n"), fmri
);
8474 return (IMPORT_OUT
);
8478 "Could not update %s (deleted).\n"), fmri
);
8479 return (IMPORT_NEXT
);
8484 return (IMPORT_NEXT
);
8487 warn(gettext("Could not update %s (repository read-only).\n"),
8489 return (IMPORT_OUT
);
8492 warn(gettext("Could not update %s "
8493 "(backend access denied).\n"), fmri
);
8494 return (IMPORT_NEXT
);
8498 return (IMPORT_BAD
);
8505 * The global imp_svc and imp_inst should be set by the caller in the
8506 * check to make sure the service and instance exist that the apply is
8510 lscf_dependent_apply(void *dpg
, void *e
)
8513 pgroup_t
*dpt_pgroup
= dpg
;
8517 void *sc_ent
, *tent
;
8521 const char * const dependents
= "dependents";
8522 const int issvc
= (ent
->sc_etype
== SVCCFG_SERVICE_OBJECT
);
8529 if (entity_get_running_pg(sc_ent
, issvc
, dependents
, imp_pg
,
8530 imp_iter
, imp_tinst
, imp_snap
, imp_snpl
) != 0 ||
8531 scf_pg_get_property(imp_pg
, dpt_pgroup
->sc_pgroup_name
,
8533 switch (scf_error()) {
8534 case SCF_ERROR_NOT_FOUND
:
8535 case SCF_ERROR_DELETED
:
8538 case SCF_ERROR_CONNECTION_BROKEN
:
8539 case SCF_ERROR_NOT_SET
:
8540 case SCF_ERROR_INVALID_ARGUMENT
:
8541 case SCF_ERROR_HANDLE_MISMATCH
:
8542 case SCF_ERROR_NOT_BOUND
:
8544 bad_error("entity_get_pg", scf_error());
8548 * Found the dependents/<wip dep> so check to
8549 * see if the service is different. If so
8550 * store the service for later refresh, and
8551 * delete the wip dependency from the service
8553 if (scf_property_get_value(imp_prop
, ud_val
) != 0) {
8554 switch (scf_error()) {
8555 case SCF_ERROR_DELETED
:
8558 case SCF_ERROR_CONNECTION_BROKEN
:
8559 case SCF_ERROR_NOT_SET
:
8560 case SCF_ERROR_INVALID_ARGUMENT
:
8561 case SCF_ERROR_HANDLE_MISMATCH
:
8562 case SCF_ERROR_NOT_BOUND
:
8564 bad_error("scf_property_get_value",
8569 if (scf_value_get_as_string(ud_val
, ud_oldtarg
,
8570 max_scf_value_len
+ 1) < 0)
8571 bad_error("scf_value_get_as_string", scf_error());
8573 r
= fmri_equal(dpt_pgroup
->sc_pgroup_fmri
, ud_oldtarg
);
8578 if ((serr
= fmri_to_entity(g_hndl
, ud_oldtarg
, &tent
,
8579 &tissvc
)) != SCF_ERROR_NONE
) {
8580 if (serr
== SCF_ERROR_NOT_FOUND
) {
8583 bad_error("fmri_to_entity", serr
);
8587 if (entity_get_pg(tent
, tissvc
,
8588 dpt_pgroup
->sc_pgroup_name
, imp_pg
) != 0) {
8590 if (serr
== SCF_ERROR_NOT_FOUND
||
8591 serr
== SCF_ERROR_DELETED
) {
8594 bad_error("entity_get_pg", scf_error());
8598 if (scf_pg_delete(imp_pg
) != 0) {
8600 if (serr
== SCF_ERROR_NOT_FOUND
||
8601 serr
== SCF_ERROR_DELETED
) {
8604 bad_error("scf_pg_delete", scf_error());
8608 deldpt
= internal_pgroup_new();
8611 deldpt
->sc_pgroup_name
=
8612 strdup(dpt_pgroup
->sc_pgroup_name
);
8613 deldpt
->sc_pgroup_fmri
= strdup(ud_oldtarg
);
8614 if (deldpt
->sc_pgroup_name
== NULL
||
8615 deldpt
->sc_pgroup_fmri
== NULL
)
8617 deldpt
->sc_parent
= (entity_t
*)ent
;
8618 if (uu_list_insert_after(imp_deleted_dpts
, NULL
,
8620 uu_die(gettext("libuutil error: %s\n"),
8621 uu_strerror(uu_error()));
8625 bad_error("fmri_equal", r
);
8629 cb
.sc_handle
= g_hndl
;
8631 cb
.sc_service
= ent
->sc_etype
== SVCCFG_SERVICE_OBJECT
;
8632 cb
.sc_source_fmri
= ent
->sc_fmri
;
8633 cb
.sc_target_fmri
= ent
->sc_fmri
;
8635 cb
.sc_flags
= SCI_FORCE
;
8637 if (lscf_dependent_import(dpt_pgroup
, &cb
) != UU_WALK_NEXT
)
8638 return (UU_WALK_ERROR
);
8640 r
= imp_refresh_fmri(dpt_pgroup
->sc_pgroup_fmri
, NULL
, NULL
);
8649 warn(gettext("Unable to refresh \"%s\"\n"),
8650 dpt_pgroup
->sc_pgroup_fmri
);
8651 return (UU_WALK_ERROR
);
8654 bad_error("imp_refresh_fmri", r
);
8657 return (UU_WALK_NEXT
);
8663 * -1 - lscf_import_instance_pgs() failed.
8666 lscf_bundle_apply(bundle_t
*bndl
, const char *file
)
8669 entity_t
*svc
, *inst
;
8670 int annotation_set
= 0;
8676 if ((ret
= alloc_imp_globals()))
8679 if (scf_handle_get_scope(g_hndl
, SCF_SCOPE_LOCAL
, imp_scope
) != 0)
8683 * Set the strings to be used for the security audit annotation
8686 if (_scf_set_annotation(g_hndl
, "svccfg apply", file
) == 0) {
8689 switch (scf_error()) {
8690 case SCF_ERROR_CONNECTION_BROKEN
:
8691 warn(gettext("Repository connection broken.\n"));
8694 case SCF_ERROR_INVALID_ARGUMENT
:
8695 case SCF_ERROR_NOT_BOUND
:
8696 case SCF_ERROR_NO_RESOURCES
:
8697 case SCF_ERROR_INTERNAL
:
8698 bad_error("_scf_set_annotation", scf_error());
8703 * Do not abort apply operation because of
8704 * inability to create annotation audit event.
8706 warn(gettext("_scf_set_annotation() unexpectedly "
8707 "failed with return code of %d\n"), scf_error());
8712 for (svc
= uu_list_first(bndl
->sc_bundle_services
);
8714 svc
= uu_list_next(bndl
->sc_bundle_services
, svc
)) {
8717 if (scf_scope_get_service(imp_scope
, svc
->sc_name
,
8719 switch (scf_error()) {
8720 case SCF_ERROR_NOT_FOUND
:
8722 warn(gettext("Ignoring nonexistent "
8723 "service %s.\n"), svc
->sc_name
);
8732 * If there were missing types in the profile, then need to
8733 * attempt to find the types.
8735 if (svc
->sc_miss_type
) {
8736 if (uu_list_numnodes(svc
->sc_pgroups
) &&
8737 uu_list_walk(svc
->sc_pgroups
, find_current_pg_type
,
8738 svc
, UU_DEFAULT
) != 0) {
8739 if (uu_error() != UU_ERROR_CALLBACK_FAILED
)
8740 bad_error("uu_list_walk", uu_error());
8746 for (inst
= uu_list_first(
8747 svc
->sc_u
.sc_service
.sc_service_instances
);
8749 inst
= uu_list_next(
8750 svc
->sc_u
.sc_service
.sc_service_instances
, inst
)) {
8752 * If the instance doesn't exist just
8753 * skip to the next instance and let the
8754 * import note the missing instance.
8756 if (scf_service_get_instance(imp_svc
,
8757 inst
->sc_name
, imp_inst
) != 0)
8760 if (uu_list_walk(inst
->sc_pgroups
,
8761 find_current_pg_type
, inst
,
8764 UU_ERROR_CALLBACK_FAILED
)
8765 bad_error("uu_list_walk",
8769 inst
->sc_miss_type
= B_TRUE
;
8775 * if we have pgs in the profile, we need to refresh ALL
8776 * instances of the service
8778 if (uu_list_numnodes(svc
->sc_pgroups
) != 0) {
8780 r
= lscf_import_service_pgs(imp_svc
, svc
->sc_fmri
, svc
,
8781 SCI_FORCE
| SCI_KEEP
);
8782 switch (_lscf_import_err(r
, svc
->sc_fmri
)) {
8791 bad_error("lscf_import_service_pgs", r
);
8795 if (uu_list_numnodes(svc
->sc_dependents
) != 0) {
8796 uu_list_walk(svc
->sc_dependents
,
8797 lscf_dependent_apply
, svc
, UU_DEFAULT
);
8800 for (inst
= uu_list_first(
8801 svc
->sc_u
.sc_service
.sc_service_instances
);
8803 inst
= uu_list_next(
8804 svc
->sc_u
.sc_service
.sc_service_instances
, inst
)) {
8806 * This instance still has missing types
8809 if (inst
->sc_miss_type
) {
8811 warn(gettext("Ignoring instance "
8812 "%s:%s with missing types\n"),
8813 inst
->sc_parent
->sc_name
,
8819 if (scf_service_get_instance(imp_svc
, inst
->sc_name
,
8821 switch (scf_error()) {
8822 case SCF_ERROR_NOT_FOUND
:
8824 warn(gettext("Ignoring "
8825 "nonexistant instance "
8827 inst
->sc_parent
->sc_name
,
8837 * If the instance does not have a general/enabled
8838 * property and no last-import snapshot then the
8839 * instance is not a fully installed instance and
8840 * should not have a profile applied to it.
8842 * This could happen if a service/instance declares
8843 * a dependent on behalf of another service/instance.
8846 if (scf_instance_get_snapshot(imp_inst
, snap_lastimport
,
8848 if (scf_instance_get_pg(imp_inst
,
8849 SCF_PG_GENERAL
, imp_pg
) != 0 ||
8850 scf_pg_get_property(imp_pg
,
8851 SCF_PROPERTY_ENABLED
, imp_prop
) != 0) {
8853 warn(gettext("Ignoreing "
8856 inst
->sc_parent
->sc_name
,
8862 r
= lscf_import_instance_pgs(imp_inst
, inst
->sc_fmri
,
8863 inst
, SCI_FORCE
| SCI_KEEP
);
8864 switch (_lscf_import_err(r
, inst
->sc_fmri
)) {
8873 bad_error("lscf_import_instance_pgs", r
);
8876 if (uu_list_numnodes(inst
->sc_dependents
) != 0) {
8877 uu_list_walk(inst
->sc_dependents
,
8878 lscf_dependent_apply
, inst
, UU_DEFAULT
);
8881 /* refresh only if there is no pgs in the service */
8883 (void) refresh_entity(0, imp_inst
,
8884 inst
->sc_fmri
, NULL
, NULL
, NULL
);
8888 char *name_buf
= safe_malloc(max_scf_name_len
+ 1);
8890 (void) refresh_entity(1, imp_svc
, svc
->sc_name
,
8891 imp_inst
, imp_iter
, name_buf
);
8895 for (old_dpt
= uu_list_first(imp_deleted_dpts
);
8897 old_dpt
= uu_list_next(imp_deleted_dpts
, old_dpt
)) {
8898 if (imp_refresh_fmri(old_dpt
->sc_pgroup_fmri
,
8899 old_dpt
->sc_pgroup_name
,
8900 old_dpt
->sc_parent
->sc_fmri
) != 0) {
8901 warn(gettext("Unable to refresh \"%s\"\n"),
8902 old_dpt
->sc_pgroup_fmri
);
8908 if (annotation_set
) {
8909 /* Remove security audit annotation strings. */
8910 (void) _scf_set_annotation(g_hndl
, NULL
, NULL
);
8919 * Export. These functions create and output an XML tree of a service
8920 * description from the repository. This is largely the inverse of
8921 * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
8923 * - We must include any properties which are not represented specifically by
8924 * a service manifest, e.g., properties created by an admin post-import. To
8925 * do so we'll iterate through all properties and deal with each
8928 * - Children of services and instances must must be in the order set by the
8929 * DTD, but we iterate over the properties in undefined order. The elements
8930 * are not easily (or efficiently) sortable by name. Since there's a fixed
8931 * number of classes of them, however, we'll keep the classes separate and
8932 * assemble them in order.
8936 * Convenience function to handle xmlSetProp errors (and type casting).
8939 safe_setprop(xmlNodePtr n
, const char *name
, const char *val
)
8941 if (xmlSetProp(n
, (const xmlChar
*)name
, (const xmlChar
*)val
) == NULL
)
8942 uu_die(gettext("Could not set XML property.\n"));
8946 * Convenience function to set an XML attribute to the single value of an
8947 * astring property. If the value happens to be the default, don't set the
8948 * attribute. "dval" should be the default value supplied by the DTD, or
8949 * NULL for no default.
8952 set_attr_from_prop_default(scf_property_t
*prop
, xmlNodePtr n
,
8953 const char *name
, const char *dval
)
8959 val
= scf_value_create(g_hndl
);
8963 if (prop_get_val(prop
, val
) != 0) {
8964 scf_value_destroy(val
);
8968 len
= scf_value_get_as_string(val
, NULL
, 0);
8972 str
= safe_malloc(len
+ 1);
8974 if (scf_value_get_as_string(val
, str
, len
+ 1) < 0)
8977 scf_value_destroy(val
);
8979 if (dval
== NULL
|| strcmp(str
, dval
) != 0)
8980 safe_setprop(n
, name
, str
);
8988 * As above, but the attribute is always set.
8991 set_attr_from_prop(scf_property_t
*prop
, xmlNodePtr n
, const char *name
)
8993 return (set_attr_from_prop_default(prop
, n
, name
, NULL
));
8997 * Dump the given document onto f, with "'s replaced by ''s.
9000 write_service_bundle(xmlDocPtr doc
, FILE *f
)
9006 xmlDocDumpFormatMemory(doc
, &mem
, &sz
, 1);
9009 semerr(gettext("Could not dump XML tree.\n"));
9014 * Fortunately libxml produces " instead of ", so we can blindly
9015 * replace all " with '. Cursed libxml2! Why must you #ifdef out the
9018 for (i
= 0; i
< sz
; ++i
) {
9019 char c
= (char)mem
[i
];
9022 (void) fputc('\'', f
);
9024 (void) fwrite("'", sizeof ("'") - 1, 1, f
);
9033 * Create the DOM elements in elts necessary to (generically) represent prop
9034 * (i.e., a property or propval element). If the name of the property is
9035 * known, it should be passed as name_arg. Otherwise, pass NULL.
9038 export_property(scf_property_t
*prop
, const char *name_arg
,
9039 struct pg_elts
*elts
, int flags
)
9042 scf_error_t err
= 0;
9043 xmlNodePtr pnode
, lnode
;
9048 if (name_arg
!= NULL
) {
9049 (void) strcpy(exp_str
, name_arg
);
9051 if (scf_property_get_name(prop
, exp_str
, exp_str_sz
) < 0)
9056 type
= prop_to_typestr(prop
);
9058 uu_die(gettext("Can't export property %s: unknown type.\n"),
9061 /* If we're exporting values, and there's just one, export it here. */
9062 if (!(flags
& SCE_ALL_VALUES
))
9065 if (scf_property_get_value(prop
, exp_val
) == SCF_SUCCESS
) {
9068 /* Single value, so use propval */
9069 n
= xmlNewNode(NULL
, (xmlChar
*)"propval");
9071 uu_die(emsg_create_xml
);
9073 safe_setprop(n
, name_attr
, exp_str
);
9074 safe_setprop(n
, type_attr
, type
);
9076 if (scf_value_get_as_string(exp_val
, exp_str
, exp_str_sz
) < 0)
9078 safe_setprop(n
, value_attr
, exp_str
);
9080 if (elts
->propvals
== NULL
)
9083 (void) xmlAddSibling(elts
->propvals
, n
);
9090 if (err
== SCF_ERROR_PERMISSION_DENIED
) {
9091 semerr(emsg_permission_denied
);
9095 if (err
!= SCF_ERROR_CONSTRAINT_VIOLATED
&&
9096 err
!= SCF_ERROR_NOT_FOUND
&&
9097 err
!= SCF_ERROR_PERMISSION_DENIED
)
9101 /* Multiple (or no) values, so use property */
9102 pnode
= xmlNewNode(NULL
, (xmlChar
*)"property");
9104 uu_die(emsg_create_xml
);
9106 safe_setprop(pnode
, name_attr
, exp_str
);
9107 safe_setprop(pnode
, type_attr
, type
);
9109 if (err
== SCF_ERROR_CONSTRAINT_VIOLATED
) {
9110 lnname
= uu_msprintf("%s_list", type
);
9112 uu_die(gettext("Could not create string"));
9114 lnode
= xmlNewChild(pnode
, NULL
, (xmlChar
*)lnname
, NULL
);
9116 uu_die(emsg_create_xml
);
9120 if (scf_iter_property_values(exp_val_iter
, prop
) != SCF_SUCCESS
)
9123 while ((ret
= scf_iter_next_value(exp_val_iter
, exp_val
)) ==
9127 vn
= xmlNewChild(lnode
, NULL
, (xmlChar
*)"value_node",
9130 uu_die(emsg_create_xml
);
9132 if (scf_value_get_as_string(exp_val
, exp_str
,
9135 safe_setprop(vn
, value_attr
, exp_str
);
9141 if (elts
->properties
== NULL
)
9142 elts
->properties
= pnode
;
9144 (void) xmlAddSibling(elts
->properties
, pnode
);
9148 * Add a property_group element for this property group to elts.
9151 export_pg(scf_propertygroup_t
*pg
, struct entity_elts
*eelts
, int flags
)
9154 struct pg_elts elts
;
9156 boolean_t read_protected
;
9158 n
= xmlNewNode(NULL
, (xmlChar
*)"property_group");
9161 if (scf_pg_get_name(pg
, exp_str
, max_scf_name_len
+ 1) < 0)
9163 safe_setprop(n
, name_attr
, exp_str
);
9166 if (scf_pg_get_type(pg
, exp_str
, exp_str_sz
) < 0)
9168 safe_setprop(n
, type_attr
, exp_str
);
9171 if (scf_iter_pg_properties(exp_prop_iter
, pg
) != SCF_SUCCESS
)
9174 (void) memset(&elts
, 0, sizeof (elts
));
9177 * If this property group is not read protected, we always want to
9178 * output all the values. Otherwise, we only output the values if the
9179 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
9181 if (_scf_pg_is_read_protected(pg
, &read_protected
) != SCF_SUCCESS
)
9184 if (!read_protected
)
9185 flags
|= SCE_ALL_VALUES
;
9187 while ((ret
= scf_iter_next_property(exp_prop_iter
, exp_prop
)) == 1) {
9188 if (scf_property_get_name(exp_prop
, exp_str
, exp_str_sz
) < 0)
9191 if (strcmp(exp_str
, SCF_PROPERTY_STABILITY
) == 0) {
9194 m
= xmlNewNode(NULL
, (xmlChar
*)"stability");
9196 uu_die(emsg_create_xml
);
9198 if (set_attr_from_prop(exp_prop
, m
, value_attr
) == 0) {
9206 export_property(exp_prop
, NULL
, &elts
, flags
);
9211 (void) xmlAddChild(n
, elts
.stability
);
9212 (void) xmlAddChildList(n
, elts
.propvals
);
9213 (void) xmlAddChildList(n
, elts
.properties
);
9215 if (eelts
->property_groups
== NULL
)
9216 eelts
->property_groups
= n
;
9218 (void) xmlAddSibling(eelts
->property_groups
, n
);
9222 * Create an XML node representing the dependency described by the given
9223 * property group and put it in eelts. Unless the dependency is not valid, in
9224 * which case create a generic property_group element which represents it and
9228 export_dependency(scf_propertygroup_t
*pg
, struct entity_elts
*eelts
)
9232 struct pg_elts elts
;
9234 n
= xmlNewNode(NULL
, (xmlChar
*)"dependency");
9236 uu_die(emsg_create_xml
);
9239 * If the external flag is present, skip this dependency because it
9240 * should have been created by another manifest.
9242 if (scf_pg_get_property(pg
, scf_property_external
, exp_prop
) == 0) {
9243 if (prop_check_type(exp_prop
, SCF_TYPE_BOOLEAN
) == 0 &&
9244 prop_get_val(exp_prop
, exp_val
) == 0) {
9247 if (scf_value_get_boolean(exp_val
, &b
) != SCF_SUCCESS
)
9253 } else if (scf_error() != SCF_ERROR_NOT_FOUND
)
9256 /* Get the required attributes. */
9259 if (scf_pg_get_name(pg
, exp_str
, max_scf_name_len
+ 1) < 0)
9261 safe_setprop(n
, name_attr
, exp_str
);
9264 if (pg_get_prop(pg
, SCF_PROPERTY_GROUPING
, exp_prop
) != 0 ||
9265 set_attr_from_prop(exp_prop
, n
, "grouping") != 0)
9269 if (pg_get_prop(pg
, SCF_PROPERTY_RESTART_ON
, exp_prop
) != 0 ||
9270 set_attr_from_prop(exp_prop
, n
, "restart_on") != 0)
9274 if (pg_get_prop(pg
, SCF_PROPERTY_TYPE
, exp_prop
) != 0 ||
9275 set_attr_from_prop(exp_prop
, n
, type_attr
) != 0)
9279 * entities: Not required, but if we create no children, it will be
9280 * created as empty on import, so fail if it's missing.
9282 if (pg_get_prop(pg
, SCF_PROPERTY_ENTITIES
, exp_prop
) == 0 &&
9283 prop_check_type(exp_prop
, SCF_TYPE_FMRI
) == 0) {
9287 eiter
= scf_iter_create(g_hndl
);
9291 if (scf_iter_property_values(eiter
, exp_prop
) != SCF_SUCCESS
)
9294 while ((ret2
= scf_iter_next_value(eiter
, exp_val
)) == 1) {
9297 if (scf_value_get_astring(exp_val
, exp_str
,
9302 * service_fmri's must be first, so we can add them
9305 ch
= xmlNewChild(n
, NULL
, (xmlChar
*)"service_fmri",
9308 uu_die(emsg_create_xml
);
9310 safe_setprop(ch
, value_attr
, exp_str
);
9315 scf_iter_destroy(eiter
);
9322 export_pg(pg
, eelts
, SCE_ALL_VALUES
);
9327 /* Iterate through the properties & handle each. */
9328 if (scf_iter_pg_properties(exp_prop_iter
, pg
) != SCF_SUCCESS
)
9331 (void) memset(&elts
, 0, sizeof (elts
));
9333 while ((ret
= scf_iter_next_property(exp_prop_iter
, exp_prop
)) == 1) {
9334 if (scf_property_get_name(exp_prop
, exp_str
, exp_str_sz
) < 0)
9337 if (strcmp(exp_str
, SCF_PROPERTY_GROUPING
) == 0 ||
9338 strcmp(exp_str
, SCF_PROPERTY_RESTART_ON
) == 0 ||
9339 strcmp(exp_str
, SCF_PROPERTY_TYPE
) == 0 ||
9340 strcmp(exp_str
, SCF_PROPERTY_ENTITIES
) == 0) {
9342 } else if (strcmp(exp_str
, SCF_PROPERTY_STABILITY
) == 0) {
9345 m
= xmlNewNode(NULL
, (xmlChar
*)"stability");
9347 uu_die(emsg_create_xml
);
9349 if (set_attr_from_prop(exp_prop
, m
, value_attr
) == 0) {
9357 export_property(exp_prop
, exp_str
, &elts
, SCE_ALL_VALUES
);
9362 (void) xmlAddChild(n
, elts
.stability
);
9363 (void) xmlAddChildList(n
, elts
.propvals
);
9364 (void) xmlAddChildList(n
, elts
.properties
);
9366 if (eelts
->dependencies
== NULL
)
9367 eelts
->dependencies
= n
;
9369 (void) xmlAddSibling(eelts
->dependencies
, n
);
9373 export_method_environment(scf_propertygroup_t
*pg
)
9379 if (scf_pg_get_property(pg
, SCF_PROPERTY_ENVIRONMENT
, NULL
) != 0)
9382 env
= xmlNewNode(NULL
, (xmlChar
*)"method_environment");
9384 uu_die(emsg_create_xml
);
9386 if (pg_get_prop(pg
, SCF_PROPERTY_ENVIRONMENT
, exp_prop
) != 0)
9389 if (scf_iter_property_values(exp_val_iter
, exp_prop
) != SCF_SUCCESS
)
9392 while ((ret
= scf_iter_next_value(exp_val_iter
, exp_val
)) == 1) {
9396 if (scf_value_get_as_string(exp_val
, exp_str
, exp_str_sz
) < 0)
9399 if ((cp
= strchr(exp_str
, '=')) == NULL
|| cp
== exp_str
) {
9400 warn(gettext("Invalid environment variable \"%s\".\n"),
9403 } else if (strncmp(exp_str
, "SMF_", 4) == 0) {
9404 warn(gettext("Invalid environment variable \"%s\"; "
9405 "\"SMF_\" prefix is reserved.\n"), exp_str
);
9412 ev
= xmlNewChild(env
, NULL
, (xmlChar
*)"envvar", NULL
);
9414 uu_die(emsg_create_xml
);
9416 safe_setprop(ev
, name_attr
, exp_str
);
9417 safe_setprop(ev
, value_attr
, cp
);
9424 if (children
== 0) {
9433 * As above, but for a method property group.
9436 export_method(scf_propertygroup_t
*pg
, struct entity_elts
*eelts
)
9440 int err
= 0, nonenv
, ret
;
9441 uint8_t use_profile
;
9442 struct pg_elts elts
;
9443 xmlNodePtr ctxt
= NULL
;
9445 n
= xmlNewNode(NULL
, (xmlChar
*)"exec_method");
9447 /* Get the required attributes. */
9450 if (scf_pg_get_name(pg
, exp_str
, max_scf_name_len
+ 1) < 0)
9452 safe_setprop(n
, name_attr
, exp_str
);
9455 if (pg_get_prop(pg
, SCF_PROPERTY_TYPE
, exp_prop
) != 0 ||
9456 set_attr_from_prop(exp_prop
, n
, type_attr
) != 0)
9460 if (pg_get_prop(pg
, SCF_PROPERTY_EXEC
, exp_prop
) != 0 ||
9461 set_attr_from_prop(exp_prop
, n
, "exec") != 0)
9465 if (pg_get_prop(pg
, SCF_PROPERTY_TIMEOUT
, exp_prop
) == 0 &&
9466 prop_check_type(exp_prop
, SCF_TYPE_COUNT
) == 0 &&
9467 prop_get_val(exp_prop
, exp_val
) == 0) {
9470 if (scf_value_get_count(exp_val
, &c
) != SCF_SUCCESS
)
9473 str
= uu_msprintf("%llu", c
);
9475 uu_die(gettext("Could not create string"));
9477 safe_setprop(n
, "timeout_seconds", str
);
9485 export_pg(pg
, eelts
, SCE_ALL_VALUES
);
9492 * If we're going to have a method_context child, we need to know
9493 * before we iterate through the properties. Since method_context's
9494 * are optional, we don't want to complain about any properties
9495 * missing if none of them are there. Thus we can't use the
9496 * convenience functions.
9499 scf_pg_get_property(pg
, SCF_PROPERTY_WORKING_DIRECTORY
, NULL
) ==
9501 scf_pg_get_property(pg
, SCF_PROPERTY_PROJECT
, NULL
) ==
9503 scf_pg_get_property(pg
, SCF_PROPERTY_RESOURCE_POOL
, NULL
) ==
9505 scf_pg_get_property(pg
, SCF_PROPERTY_USE_PROFILE
, NULL
) ==
9509 ctxt
= xmlNewNode(NULL
, (xmlChar
*)"method_context");
9511 uu_die(emsg_create_xml
);
9513 if (pg_get_prop(pg
, SCF_PROPERTY_WORKING_DIRECTORY
, exp_prop
) ==
9515 set_attr_from_prop_default(exp_prop
, ctxt
,
9516 "working_directory", ":default") != 0)
9519 if (pg_get_prop(pg
, SCF_PROPERTY_PROJECT
, exp_prop
) == 0 &&
9520 set_attr_from_prop_default(exp_prop
, ctxt
, "project",
9524 if (pg_get_prop(pg
, SCF_PROPERTY_RESOURCE_POOL
, exp_prop
) ==
9526 set_attr_from_prop_default(exp_prop
, ctxt
,
9527 "resource_pool", ":default") != 0)
9530 * We only want to complain about profile or credential
9531 * properties if we will use them. To determine that we must
9532 * examine USE_PROFILE.
9534 if (pg_get_prop(pg
, SCF_PROPERTY_USE_PROFILE
, exp_prop
) == 0 &&
9535 prop_check_type(exp_prop
, SCF_TYPE_BOOLEAN
) == 0 &&
9536 prop_get_val(exp_prop
, exp_val
) == 0) {
9537 if (scf_value_get_boolean(exp_val
, &use_profile
) !=
9545 prof
= xmlNewChild(ctxt
, NULL
,
9546 (xmlChar
*)"method_profile", NULL
);
9548 uu_die(emsg_create_xml
);
9550 if (pg_get_prop(pg
, SCF_PROPERTY_PROFILE
,
9552 set_attr_from_prop(exp_prop
, prof
,
9558 cred
= xmlNewChild(ctxt
, NULL
,
9559 (xmlChar
*)"method_credential", NULL
);
9561 uu_die(emsg_create_xml
);
9563 if (pg_get_prop(pg
, SCF_PROPERTY_USER
,
9565 set_attr_from_prop(exp_prop
, cred
,
9570 if (pg_get_prop(pg
, SCF_PROPERTY_GROUP
,
9572 set_attr_from_prop_default(exp_prop
, cred
,
9573 "group", ":default") != 0)
9576 if (pg_get_prop(pg
, SCF_PROPERTY_SUPP_GROUPS
,
9578 set_attr_from_prop_default(exp_prop
, cred
,
9579 "supp_groups", ":default") != 0)
9582 if (pg_get_prop(pg
, SCF_PROPERTY_PRIVILEGES
,
9584 set_attr_from_prop_default(exp_prop
, cred
,
9585 "privileges", ":default") != 0)
9589 SCF_PROPERTY_LIMIT_PRIVILEGES
,
9591 set_attr_from_prop_default(exp_prop
, cred
,
9592 "limit_privileges", ":default") != 0)
9598 if ((env
= export_method_environment(pg
)) != NULL
) {
9600 ctxt
= xmlNewNode(NULL
, (xmlChar
*)"method_context");
9602 uu_die(emsg_create_xml
);
9604 (void) xmlAddChild(ctxt
, env
);
9607 if (env
!= NULL
|| (nonenv
&& err
== 0))
9608 (void) xmlAddChild(n
, ctxt
);
9612 nonenv
= (err
== 0);
9614 if (scf_iter_pg_properties(exp_prop_iter
, pg
) != SCF_SUCCESS
)
9617 (void) memset(&elts
, 0, sizeof (elts
));
9619 while ((ret
= scf_iter_next_property(exp_prop_iter
, exp_prop
)) == 1) {
9620 if (scf_property_get_name(exp_prop
, exp_str
, exp_str_sz
) < 0)
9623 if (strcmp(exp_str
, SCF_PROPERTY_TYPE
) == 0 ||
9624 strcmp(exp_str
, SCF_PROPERTY_EXEC
) == 0 ||
9625 strcmp(exp_str
, SCF_PROPERTY_TIMEOUT
) == 0) {
9627 } else if (strcmp(exp_str
, SCF_PROPERTY_STABILITY
) == 0) {
9630 m
= xmlNewNode(NULL
, (xmlChar
*)"stability");
9632 uu_die(emsg_create_xml
);
9634 if (set_attr_from_prop(exp_prop
, m
, value_attr
) == 0) {
9640 } else if (strcmp(exp_str
, SCF_PROPERTY_WORKING_DIRECTORY
) ==
9642 strcmp(exp_str
, SCF_PROPERTY_PROJECT
) == 0 ||
9643 strcmp(exp_str
, SCF_PROPERTY_RESOURCE_POOL
) == 0 ||
9644 strcmp(exp_str
, SCF_PROPERTY_USE_PROFILE
) == 0) {
9647 } else if (strcmp(exp_str
, SCF_PROPERTY_USER
) == 0 ||
9648 strcmp(exp_str
, SCF_PROPERTY_GROUP
) == 0 ||
9649 strcmp(exp_str
, SCF_PROPERTY_SUPP_GROUPS
) == 0 ||
9650 strcmp(exp_str
, SCF_PROPERTY_PRIVILEGES
) == 0 ||
9651 strcmp(exp_str
, SCF_PROPERTY_LIMIT_PRIVILEGES
) == 0) {
9652 if (nonenv
&& !use_profile
)
9654 } else if (strcmp(exp_str
, SCF_PROPERTY_PROFILE
) == 0) {
9655 if (nonenv
&& use_profile
)
9657 } else if (strcmp(exp_str
, SCF_PROPERTY_ENVIRONMENT
) == 0) {
9662 export_property(exp_prop
, exp_str
, &elts
, SCE_ALL_VALUES
);
9667 (void) xmlAddChild(n
, elts
.stability
);
9668 (void) xmlAddChildList(n
, elts
.propvals
);
9669 (void) xmlAddChildList(n
, elts
.properties
);
9671 if (eelts
->exec_methods
== NULL
)
9672 eelts
->exec_methods
= n
;
9674 (void) xmlAddSibling(eelts
->exec_methods
, n
);
9678 export_pg_elts(struct pg_elts
*elts
, const char *name
, const char *type
,
9679 struct entity_elts
*eelts
)
9683 pgnode
= xmlNewNode(NULL
, (xmlChar
*)"property_group");
9685 uu_die(emsg_create_xml
);
9687 safe_setprop(pgnode
, name_attr
, name
);
9688 safe_setprop(pgnode
, type_attr
, type
);
9690 (void) xmlAddChildList(pgnode
, elts
->propvals
);
9691 (void) xmlAddChildList(pgnode
, elts
->properties
);
9693 if (eelts
->property_groups
== NULL
)
9694 eelts
->property_groups
= pgnode
;
9696 (void) xmlAddSibling(eelts
->property_groups
, pgnode
);
9700 * Process the general property group for a service. This is the one with the
9704 export_svc_general(scf_propertygroup_t
*pg
, struct entity_elts
*selts
)
9706 struct pg_elts elts
;
9710 * In case there are properties which don't correspond to child
9711 * entities of the service entity, we'll set up a pg_elts structure to
9714 (void) memset(&elts
, 0, sizeof (elts
));
9716 /* Walk the properties, looking for special ones. */
9717 if (scf_iter_pg_properties(exp_prop_iter
, pg
) != SCF_SUCCESS
)
9720 while ((ret
= scf_iter_next_property(exp_prop_iter
, exp_prop
)) == 1) {
9721 if (scf_property_get_name(exp_prop
, exp_str
, exp_str_sz
) < 0)
9724 if (strcmp(exp_str
, SCF_PROPERTY_SINGLE_INSTANCE
) == 0) {
9725 if (prop_check_type(exp_prop
, SCF_TYPE_BOOLEAN
) == 0 &&
9726 prop_get_val(exp_prop
, exp_val
) == 0) {
9729 if (scf_value_get_boolean(exp_val
, &b
) !=
9734 selts
->single_instance
=
9736 (xmlChar
*)"single_instance");
9737 if (selts
->single_instance
== NULL
)
9738 uu_die(emsg_create_xml
);
9743 } else if (strcmp(exp_str
, SCF_PROPERTY_RESTARTER
) == 0) {
9744 xmlNodePtr rnode
, sfnode
;
9746 rnode
= xmlNewNode(NULL
, (xmlChar
*)"restarter");
9748 uu_die(emsg_create_xml
);
9750 sfnode
= xmlNewChild(rnode
, NULL
,
9751 (xmlChar
*)"service_fmri", NULL
);
9753 uu_die(emsg_create_xml
);
9755 if (set_attr_from_prop(exp_prop
, sfnode
,
9757 selts
->restarter
= rnode
;
9762 } else if (strcmp(exp_str
, SCF_PROPERTY_ENTITY_STABILITY
) ==
9766 s
= xmlNewNode(NULL
, (xmlChar
*)"stability");
9768 uu_die(emsg_create_xml
);
9770 if (set_attr_from_prop(exp_prop
, s
, value_attr
) == 0) {
9771 selts
->stability
= s
;
9778 export_property(exp_prop
, exp_str
, &elts
, SCE_ALL_VALUES
);
9783 if (elts
.propvals
!= NULL
|| elts
.properties
!= NULL
)
9784 export_pg_elts(&elts
, scf_pg_general
, scf_group_framework
,
9789 export_method_context(scf_propertygroup_t
*pg
, struct entity_elts
*elts
)
9791 xmlNodePtr n
, prof
, cred
, env
;
9792 uint8_t use_profile
;
9795 n
= xmlNewNode(NULL
, (xmlChar
*)"method_context");
9797 env
= export_method_environment(pg
);
9799 /* Need to know whether we'll use a profile or not. */
9800 if (pg_get_prop(pg
, SCF_PROPERTY_USE_PROFILE
, exp_prop
) == 0 &&
9801 prop_check_type(exp_prop
, SCF_TYPE_BOOLEAN
) == 0 &&
9802 prop_get_val(exp_prop
, exp_val
) == 0) {
9803 if (scf_value_get_boolean(exp_val
, &use_profile
) != SCF_SUCCESS
)
9808 xmlNewChild(n
, NULL
, (xmlChar
*)"method_profile",
9812 xmlNewChild(n
, NULL
, (xmlChar
*)"method_credential",
9817 (void) xmlAddChild(n
, env
);
9819 if (scf_iter_pg_properties(exp_prop_iter
, pg
) != SCF_SUCCESS
)
9822 while ((ret
= scf_iter_next_property(exp_prop_iter
, exp_prop
)) == 1) {
9823 if (scf_property_get_name(exp_prop
, exp_str
, exp_str_sz
) < 0)
9826 if (strcmp(exp_str
, SCF_PROPERTY_WORKING_DIRECTORY
) == 0) {
9827 if (set_attr_from_prop(exp_prop
, n
,
9828 "working_directory") != 0)
9830 } else if (strcmp(exp_str
, SCF_PROPERTY_PROJECT
) == 0) {
9831 if (set_attr_from_prop(exp_prop
, n
, "project") != 0)
9833 } else if (strcmp(exp_str
, SCF_PROPERTY_RESOURCE_POOL
) == 0) {
9834 if (set_attr_from_prop(exp_prop
, n
,
9835 "resource_pool") != 0)
9837 } else if (strcmp(exp_str
, SCF_PROPERTY_USE_PROFILE
) == 0) {
9839 } else if (strcmp(exp_str
, SCF_PROPERTY_USER
) == 0) {
9841 set_attr_from_prop(exp_prop
, cred
, "user") != 0)
9843 } else if (strcmp(exp_str
, SCF_PROPERTY_GROUP
) == 0) {
9845 set_attr_from_prop(exp_prop
, cred
, "group") != 0)
9847 } else if (strcmp(exp_str
, SCF_PROPERTY_SUPP_GROUPS
) == 0) {
9848 if (use_profile
|| set_attr_from_prop(exp_prop
, cred
,
9849 "supp_groups") != 0)
9851 } else if (strcmp(exp_str
, SCF_PROPERTY_PRIVILEGES
) == 0) {
9852 if (use_profile
|| set_attr_from_prop(exp_prop
, cred
,
9855 } else if (strcmp(exp_str
, SCF_PROPERTY_LIMIT_PRIVILEGES
) ==
9857 if (use_profile
|| set_attr_from_prop(exp_prop
, cred
,
9858 "limit_privileges") != 0)
9860 } else if (strcmp(exp_str
, SCF_PROPERTY_PROFILE
) == 0) {
9861 if (!use_profile
|| set_attr_from_prop(exp_prop
,
9862 prof
, name_attr
) != 0)
9865 /* Can't have generic properties in method_context's */
9872 if (err
&& env
== NULL
) {
9874 export_pg(pg
, elts
, SCE_ALL_VALUES
);
9878 elts
->method_context
= n
;
9882 * Given a dependency property group in the tfmri entity (target fmri), return
9883 * a dependent element which represents it.
9886 export_dependent(scf_propertygroup_t
*pg
, const char *name
, const char *tfmri
)
9891 struct pg_elts pgelts
;
9894 * If external isn't set to true then exporting the service will
9895 * export this as a normal dependency, so we should stop to avoid
9898 if (scf_pg_get_property(pg
, scf_property_external
, exp_prop
) != 0 ||
9899 scf_property_get_value(exp_prop
, exp_val
) != 0 ||
9900 scf_value_get_boolean(exp_val
, &b
) != 0 || !b
) {
9902 warn(gettext("Dependent \"%s\" cannot be exported "
9903 "properly because the \"%s\" property of the "
9904 "\"%s\" dependency of %s is not set to true.\n"),
9905 name
, scf_property_external
, name
, tfmri
);
9911 n
= xmlNewNode(NULL
, (xmlChar
*)"dependent");
9913 uu_die(emsg_create_xml
);
9915 safe_setprop(n
, name_attr
, name
);
9917 /* Get the required attributes */
9918 if (pg_get_prop(pg
, SCF_PROPERTY_RESTART_ON
, exp_prop
) != 0 ||
9919 set_attr_from_prop(exp_prop
, n
, "restart_on") != 0)
9922 if (pg_get_prop(pg
, SCF_PROPERTY_GROUPING
, exp_prop
) != 0 ||
9923 set_attr_from_prop(exp_prop
, n
, "grouping") != 0)
9926 if (pg_get_prop(pg
, SCF_PROPERTY_ENTITIES
, exp_prop
) == 0 &&
9927 prop_check_type(exp_prop
, SCF_TYPE_FMRI
) == 0 &&
9928 prop_get_val(exp_prop
, exp_val
) == 0) {
9938 sf
= xmlNewChild(n
, NULL
, (xmlChar
*)"service_fmri", NULL
);
9940 uu_die(emsg_create_xml
);
9942 safe_setprop(sf
, value_attr
, tfmri
);
9945 * Now add elements for the other properties.
9947 if (scf_iter_pg_properties(exp_prop_iter
, pg
) != SCF_SUCCESS
)
9950 (void) memset(&pgelts
, 0, sizeof (pgelts
));
9952 while ((ret
= scf_iter_next_property(exp_prop_iter
, exp_prop
)) == 1) {
9953 if (scf_property_get_name(exp_prop
, exp_str
, exp_str_sz
) < 0)
9956 if (strcmp(exp_str
, scf_property_external
) == 0 ||
9957 strcmp(exp_str
, SCF_PROPERTY_RESTART_ON
) == 0 ||
9958 strcmp(exp_str
, SCF_PROPERTY_GROUPING
) == 0 ||
9959 strcmp(exp_str
, SCF_PROPERTY_ENTITIES
) == 0) {
9961 } else if (strcmp(exp_str
, SCF_PROPERTY_TYPE
) == 0) {
9962 if (prop_check_type(exp_prop
, SCF_TYPE_ASTRING
) == 0 &&
9963 prop_get_val(exp_prop
, exp_val
) == 0) {
9964 char type
[sizeof ("service") + 1];
9966 if (scf_value_get_astring(exp_val
, type
,
9970 if (strcmp(type
, "service") == 0)
9973 } else if (strcmp(exp_str
, SCF_PROPERTY_STABILITY
) == 0) {
9976 s
= xmlNewNode(NULL
, (xmlChar
*)"stability");
9978 uu_die(emsg_create_xml
);
9980 if (set_attr_from_prop(exp_prop
, s
, value_attr
) == 0) {
9981 pgelts
.stability
= s
;
9988 export_property(exp_prop
, exp_str
, &pgelts
, SCE_ALL_VALUES
);
9993 (void) xmlAddChild(n
, pgelts
.stability
);
9994 (void) xmlAddChildList(n
, pgelts
.propvals
);
9995 (void) xmlAddChildList(n
, pgelts
.properties
);
10001 export_dependents(scf_propertygroup_t
*pg
, struct entity_elts
*eelts
)
10003 scf_propertygroup_t
*opg
;
10007 struct pg_elts pgelts
;
10011 if ((opg
= scf_pg_create(g_hndl
)) == NULL
||
10012 (iter
= scf_iter_create(g_hndl
)) == NULL
)
10015 /* Can't use exp_prop_iter due to export_dependent(). */
10016 if (scf_iter_pg_properties(iter
, pg
) != SCF_SUCCESS
)
10019 type
= safe_malloc(max_scf_pg_type_len
+ 1);
10021 /* Get an extra byte so we can tell if values are too long. */
10022 fmri
= safe_malloc(max_scf_fmri_len
+ 2);
10024 (void) memset(&pgelts
, 0, sizeof (pgelts
));
10026 while ((ret
= scf_iter_next_property(iter
, exp_prop
)) == 1) {
10031 if (scf_property_type(exp_prop
, &ty
) != SCF_SUCCESS
)
10034 if ((ty
!= SCF_TYPE_ASTRING
&&
10035 prop_check_type(exp_prop
, SCF_TYPE_FMRI
) != 0) ||
10036 prop_get_val(exp_prop
, exp_val
) != 0) {
10037 export_property(exp_prop
, NULL
, &pgelts
,
10042 if (scf_property_get_name(exp_prop
, exp_str
, exp_str_sz
) < 0)
10045 if (scf_value_get_astring(exp_val
, fmri
,
10046 max_scf_fmri_len
+ 2) < 0)
10049 /* Look for a dependency group in the target fmri. */
10050 serr
= fmri_to_entity(g_hndl
, fmri
, &entity
, &isservice
);
10052 case SCF_ERROR_NONE
:
10055 case SCF_ERROR_NO_MEMORY
:
10056 uu_die(gettext("Out of memory.\n"));
10059 case SCF_ERROR_INVALID_ARGUMENT
:
10061 if (scf_property_to_fmri(exp_prop
, fmri
,
10062 max_scf_fmri_len
+ 2) < 0)
10065 warn(gettext("The value of %s is not a valid "
10069 export_property(exp_prop
, exp_str
, &pgelts
,
10073 case SCF_ERROR_CONSTRAINT_VIOLATED
:
10075 if (scf_property_to_fmri(exp_prop
, fmri
,
10076 max_scf_fmri_len
+ 2) < 0)
10079 warn(gettext("The value of %s does not specify "
10080 "a service or an instance.\n"), fmri
);
10083 export_property(exp_prop
, exp_str
, &pgelts
,
10087 case SCF_ERROR_NOT_FOUND
:
10089 if (scf_property_to_fmri(exp_prop
, fmri
,
10090 max_scf_fmri_len
+ 2) < 0)
10093 warn(gettext("The entity specified by %s does "
10094 "not exist.\n"), fmri
);
10097 export_property(exp_prop
, exp_str
, &pgelts
,
10103 (void) fprintf(stderr
, "%s:%d: %s() failed with "
10104 "unexpected error %d.\n", __FILE__
, __LINE__
,
10105 "fmri_to_entity", serr
);
10110 if (entity_get_pg(entity
, isservice
, exp_str
, opg
) != 0) {
10111 if (scf_error() != SCF_ERROR_NOT_FOUND
)
10114 warn(gettext("Entity %s is missing dependency property "
10115 "group %s.\n"), fmri
, exp_str
);
10117 export_property(exp_prop
, NULL
, &pgelts
,
10122 if (scf_pg_get_type(opg
, type
, max_scf_pg_type_len
+ 1) < 0)
10125 if (strcmp(type
, SCF_GROUP_DEPENDENCY
) != 0) {
10126 if (scf_pg_to_fmri(opg
, fmri
, max_scf_fmri_len
+ 2) < 0)
10129 warn(gettext("Property group %s is not of "
10130 "expected type %s.\n"), fmri
, SCF_GROUP_DEPENDENCY
);
10132 export_property(exp_prop
, NULL
, &pgelts
,
10137 n
= export_dependent(opg
, exp_str
, fmri
);
10139 export_property(exp_prop
, exp_str
, &pgelts
,
10142 if (eelts
->dependents
== NULL
)
10143 eelts
->dependents
= n
;
10145 (void) xmlAddSibling(eelts
->dependents
,
10155 scf_iter_destroy(iter
);
10156 scf_pg_destroy(opg
);
10158 if (pgelts
.propvals
!= NULL
|| pgelts
.properties
!= NULL
)
10159 export_pg_elts(&pgelts
, SCF_PG_DEPENDENTS
, scf_group_framework
,
10164 make_node(xmlNodePtr
*nodep
, const char *name
)
10166 if (*nodep
== NULL
) {
10167 *nodep
= xmlNewNode(NULL
, (xmlChar
*)name
);
10168 if (*nodep
== NULL
)
10169 uu_die(emsg_create_xml
);
10174 export_tm_loctext(scf_propertygroup_t
*pg
, const char *parname
)
10177 xmlNodePtr parent
= NULL
;
10178 xmlNodePtr loctext
= NULL
;
10180 if (scf_iter_pg_properties(exp_prop_iter
, pg
) != SCF_SUCCESS
)
10183 while ((ret
= scf_iter_next_property(exp_prop_iter
, exp_prop
)) == 1) {
10184 if (prop_check_type(exp_prop
, SCF_TYPE_USTRING
) != 0 ||
10185 prop_get_val(exp_prop
, exp_val
) != 0)
10188 if (scf_value_get_ustring(exp_val
, exp_str
, exp_str_sz
) < 0)
10191 make_node(&parent
, parname
);
10192 loctext
= xmlNewTextChild(parent
, NULL
, (xmlChar
*)"loctext",
10193 (xmlChar
*)exp_str
);
10194 if (loctext
== NULL
)
10195 uu_die(emsg_create_xml
);
10197 if (scf_property_get_name(exp_prop
, exp_str
, exp_str_sz
) < 0)
10200 safe_setprop(loctext
, "xml:lang", exp_str
);
10210 export_tm_manpage(scf_propertygroup_t
*pg
)
10212 xmlNodePtr manpage
= xmlNewNode(NULL
, (xmlChar
*)"manpage");
10213 if (manpage
== NULL
)
10214 uu_die(emsg_create_xml
);
10216 if (pg_get_prop(pg
, SCF_PROPERTY_TM_TITLE
, exp_prop
) != 0 ||
10217 set_attr_from_prop(exp_prop
, manpage
, "title") != 0 ||
10218 pg_get_prop(pg
, SCF_PROPERTY_TM_SECTION
, exp_prop
) != 0 ||
10219 set_attr_from_prop(exp_prop
, manpage
, "section") != 0) {
10220 xmlFreeNode(manpage
);
10224 if (pg_get_prop(pg
, SCF_PROPERTY_TM_MANPATH
, exp_prop
) == 0)
10225 (void) set_attr_from_prop_default(exp_prop
,
10226 manpage
, "manpath", ":default");
10232 export_tm_doc_link(scf_propertygroup_t
*pg
)
10234 xmlNodePtr doc_link
= xmlNewNode(NULL
, (xmlChar
*)"doc_link");
10235 if (doc_link
== NULL
)
10236 uu_die(emsg_create_xml
);
10238 if (pg_get_prop(pg
, SCF_PROPERTY_TM_NAME
, exp_prop
) != 0 ||
10239 set_attr_from_prop(exp_prop
, doc_link
, "name") != 0 ||
10240 pg_get_prop(pg
, SCF_PROPERTY_TM_URI
, exp_prop
) != 0 ||
10241 set_attr_from_prop(exp_prop
, doc_link
, "uri") != 0) {
10242 xmlFreeNode(doc_link
);
10249 * Process template information for a service or instances.
10252 export_template(scf_propertygroup_t
*pg
, struct entity_elts
*elts
,
10253 struct template_elts
*telts
)
10255 size_t mansz
= strlen(SCF_PG_TM_MAN_PREFIX
);
10256 size_t docsz
= strlen(SCF_PG_TM_DOC_PREFIX
);
10257 xmlNodePtr child
= NULL
;
10259 if (scf_pg_get_name(pg
, exp_str
, exp_str_sz
) < 0)
10262 if (strcmp(exp_str
, SCF_PG_TM_COMMON_NAME
) == 0) {
10263 telts
->common_name
= export_tm_loctext(pg
, "common_name");
10264 if (telts
->common_name
== NULL
)
10265 export_pg(pg
, elts
, SCE_ALL_VALUES
);
10267 } else if (strcmp(exp_str
, SCF_PG_TM_DESCRIPTION
) == 0) {
10268 telts
->description
= export_tm_loctext(pg
, "description");
10269 if (telts
->description
== NULL
)
10270 export_pg(pg
, elts
, SCE_ALL_VALUES
);
10274 if (strncmp(exp_str
, SCF_PG_TM_MAN_PREFIX
, mansz
) == 0) {
10275 child
= export_tm_manpage(pg
);
10276 } else if (strncmp(exp_str
, SCF_PG_TM_DOC_PREFIX
, docsz
) == 0) {
10277 child
= export_tm_doc_link(pg
);
10280 if (child
!= NULL
) {
10281 make_node(&telts
->documentation
, "documentation");
10282 (void) xmlAddChild(telts
->documentation
, child
);
10284 export_pg(pg
, elts
, SCE_ALL_VALUES
);
10289 * Process parameter and paramval elements
10292 export_parameter(scf_property_t
*prop
, const char *name
,
10293 struct params_elts
*elts
)
10296 scf_error_t err
= 0;
10299 if (scf_property_get_value(prop
, exp_val
) == SCF_SUCCESS
) {
10300 if ((param
= xmlNewNode(NULL
, (xmlChar
*)"paramval")) == NULL
)
10301 uu_die(emsg_create_xml
);
10303 safe_setprop(param
, name_attr
, name
);
10305 if (scf_value_get_as_string(exp_val
, exp_str
, exp_str_sz
) < 0)
10307 safe_setprop(param
, value_attr
, exp_str
);
10309 if (elts
->paramval
== NULL
)
10310 elts
->paramval
= param
;
10312 (void) xmlAddSibling(elts
->paramval
, param
);
10319 if (err
!= SCF_ERROR_CONSTRAINT_VIOLATED
&&
10320 err
!= SCF_ERROR_NOT_FOUND
)
10323 if ((param
= xmlNewNode(NULL
, (xmlChar
*)"parameter")) == NULL
)
10324 uu_die(emsg_create_xml
);
10326 safe_setprop(param
, name_attr
, name
);
10328 if (err
== SCF_ERROR_CONSTRAINT_VIOLATED
) {
10329 if (scf_iter_property_values(exp_val_iter
, prop
) != SCF_SUCCESS
)
10332 while ((ret
= scf_iter_next_value(exp_val_iter
, exp_val
)) ==
10336 if ((vn
= xmlNewChild(param
, NULL
,
10337 (xmlChar
*)"value_node", NULL
)) == NULL
)
10338 uu_die(emsg_create_xml
);
10340 if (scf_value_get_as_string(exp_val
, exp_str
,
10344 safe_setprop(vn
, value_attr
, exp_str
);
10350 if (elts
->parameter
== NULL
)
10351 elts
->parameter
= param
;
10353 (void) xmlAddSibling(elts
->parameter
, param
);
10357 * Process notification parameters for a service or instance
10360 export_notify_params(scf_propertygroup_t
*pg
, struct entity_elts
*elts
)
10362 xmlNodePtr n
, event
, *type
;
10363 struct params_elts
*eelts
;
10366 n
= xmlNewNode(NULL
, (xmlChar
*)"notification_parameters");
10367 event
= xmlNewNode(NULL
, (xmlChar
*)"event");
10368 if (n
== NULL
|| event
== NULL
)
10369 uu_die(emsg_create_xml
);
10372 if (scf_pg_get_name(pg
, exp_str
, max_scf_name_len
+ 1) < 0)
10374 safe_setprop(event
, value_attr
, exp_str
);
10376 (void) xmlAddChild(n
, event
);
10378 if ((type
= calloc(URI_SCHEME_NUM
, sizeof (xmlNodePtr
))) == NULL
||
10379 (eelts
= calloc(URI_SCHEME_NUM
,
10380 sizeof (struct params_elts
))) == NULL
)
10381 uu_die(gettext("Out of memory.\n"));
10385 if (scf_iter_pg_properties(exp_prop_iter
, pg
) != SCF_SUCCESS
)
10388 while ((ret
= scf_iter_next_property(exp_prop_iter
, exp_prop
)) == 1) {
10391 if (scf_property_get_name(exp_prop
, exp_str
, exp_str_sz
) < 0)
10394 if ((t
= strtok_r(exp_str
, ",", &p
)) == NULL
|| p
== NULL
) {
10396 * this is not a well formed notification parameters
10397 * element, we should export as regular pg
10403 if ((i
= check_uri_protocol(t
)) < 0) {
10408 if (type
[i
] == NULL
) {
10409 if ((type
[i
] = xmlNewNode(NULL
, (xmlChar
*)"type")) ==
10411 uu_die(emsg_create_xml
);
10413 safe_setprop(type
[i
], name_attr
, t
);
10415 if (strcmp(p
, active_attr
) == 0) {
10416 if (set_attr_from_prop(exp_prop
, type
[i
],
10417 active_attr
) != 0) {
10424 * We export the parameter
10426 export_parameter(exp_prop
, p
, &eelts
[i
]);
10433 for (i
= 0; i
< URI_SCHEME_NUM
; ++i
)
10437 export_pg(pg
, elts
, SCE_ALL_VALUES
);
10441 for (i
= 0; i
< URI_SCHEME_NUM
; ++i
)
10442 if (type
[i
] != NULL
) {
10443 (void) xmlAddChildList(type
[i
],
10444 eelts
[i
].paramval
);
10445 (void) xmlAddChildList(type
[i
],
10446 eelts
[i
].parameter
);
10447 (void) xmlAddSibling(event
, type
[i
]);
10452 if (elts
->notify_params
== NULL
)
10453 elts
->notify_params
= n
;
10455 (void) xmlAddSibling(elts
->notify_params
, n
);
10459 * Process the general property group for an instance.
10462 export_inst_general(scf_propertygroup_t
*pg
, xmlNodePtr inode
,
10463 struct entity_elts
*elts
)
10466 struct pg_elts pgelts
;
10470 if (pg_get_prop(pg
, scf_property_enabled
, exp_prop
) == 0 &&
10471 prop_check_type(exp_prop
, SCF_TYPE_BOOLEAN
) == 0 &&
10472 prop_get_val(exp_prop
, exp_val
) == 0) {
10473 if (scf_value_get_boolean(exp_val
, &enabled
) != SCF_SUCCESS
)
10479 safe_setprop(inode
, enabled_attr
, enabled
? true : false);
10481 if (scf_iter_pg_properties(exp_prop_iter
, pg
) != SCF_SUCCESS
)
10484 (void) memset(&pgelts
, 0, sizeof (pgelts
));
10486 while ((ret
= scf_iter_next_property(exp_prop_iter
, exp_prop
)) == 1) {
10487 if (scf_property_get_name(exp_prop
, exp_str
, exp_str_sz
) < 0)
10490 if (strcmp(exp_str
, scf_property_enabled
) == 0) {
10492 } else if (strcmp(exp_str
, SCF_PROPERTY_RESTARTER
) == 0) {
10493 xmlNodePtr rnode
, sfnode
;
10495 rnode
= xmlNewNode(NULL
, (xmlChar
*)"restarter");
10497 uu_die(emsg_create_xml
);
10499 sfnode
= xmlNewChild(rnode
, NULL
,
10500 (xmlChar
*)"service_fmri", NULL
);
10501 if (sfnode
== NULL
)
10502 uu_die(emsg_create_xml
);
10504 if (set_attr_from_prop(exp_prop
, sfnode
,
10505 value_attr
) == 0) {
10506 elts
->restarter
= rnode
;
10510 xmlFreeNode(rnode
);
10513 export_property(exp_prop
, exp_str
, &pgelts
, SCE_ALL_VALUES
);
10518 if (pgelts
.propvals
!= NULL
|| pgelts
.properties
!= NULL
)
10519 export_pg_elts(&pgelts
, scf_pg_general
, scf_group_framework
,
10524 * Put an instance element for the given instance into selts.
10527 export_instance(scf_instance_t
*inst
, struct entity_elts
*selts
, int flags
)
10530 boolean_t isdefault
;
10531 struct entity_elts elts
;
10532 struct template_elts template_elts
;
10535 n
= xmlNewNode(NULL
, (xmlChar
*)"instance");
10537 uu_die(emsg_create_xml
);
10540 if (scf_instance_get_name(inst
, exp_str
, exp_str_sz
) < 0)
10542 safe_setprop(n
, name_attr
, exp_str
);
10543 isdefault
= strcmp(exp_str
, "default") == 0;
10545 /* check existance of general pg (since general/enabled is required) */
10546 if (scf_instance_get_pg(inst
, scf_pg_general
, exp_pg
) != SCF_SUCCESS
) {
10547 if (scf_error() != SCF_ERROR_NOT_FOUND
)
10551 if (scf_instance_to_fmri(inst
, exp_str
, exp_str_sz
) < 0)
10554 warn(gettext("Instance %s has no general property "
10555 "group; it will be marked disabled.\n"), exp_str
);
10558 safe_setprop(n
, enabled_attr
, false);
10559 } else if (scf_pg_get_type(exp_pg
, exp_str
, exp_str_sz
) < 0 ||
10560 strcmp(exp_str
, scf_group_framework
) != 0) {
10562 if (scf_pg_to_fmri(exp_pg
, exp_str
, exp_str_sz
) < 0)
10565 warn(gettext("Property group %s is not of type "
10566 "framework; the instance will be marked "
10567 "disabled.\n"), exp_str
);
10570 safe_setprop(n
, enabled_attr
, false);
10573 /* property groups */
10574 if (scf_iter_instance_pgs(exp_pg_iter
, inst
) < 0)
10577 (void) memset(&elts
, 0, sizeof (elts
));
10578 (void) memset(&template_elts
, 0, sizeof (template_elts
));
10580 while ((ret
= scf_iter_next_pg(exp_pg_iter
, exp_pg
)) == 1) {
10583 if (scf_pg_get_flags(exp_pg
, &pgflags
) != 0)
10586 if (pgflags
& SCF_PG_FLAG_NONPERSISTENT
)
10589 if (scf_pg_get_type(exp_pg
, exp_str
, exp_str_sz
) < 0)
10592 if (strcmp(exp_str
, SCF_GROUP_DEPENDENCY
) == 0) {
10593 export_dependency(exp_pg
, &elts
);
10595 } else if (strcmp(exp_str
, SCF_GROUP_METHOD
) == 0) {
10596 export_method(exp_pg
, &elts
);
10598 } else if (strcmp(exp_str
, scf_group_framework
) == 0) {
10599 if (scf_pg_get_name(exp_pg
, exp_str
,
10600 max_scf_name_len
+ 1) < 0)
10603 if (strcmp(exp_str
, scf_pg_general
) == 0) {
10604 export_inst_general(exp_pg
, n
, &elts
);
10606 } else if (strcmp(exp_str
, SCF_PG_METHOD_CONTEXT
) ==
10608 export_method_context(exp_pg
, &elts
);
10610 } else if (strcmp(exp_str
, SCF_PG_DEPENDENTS
) == 0) {
10611 export_dependents(exp_pg
, &elts
);
10614 } else if (strcmp(exp_str
, SCF_GROUP_TEMPLATE
) == 0) {
10615 export_template(exp_pg
, &elts
, &template_elts
);
10617 } else if (strcmp(exp_str
, SCF_NOTIFY_PARAMS_PG_TYPE
) == 0) {
10618 export_notify_params(exp_pg
, &elts
);
10623 export_pg(exp_pg
, &elts
, flags
);
10628 if (template_elts
.common_name
!= NULL
) {
10629 elts
.template = xmlNewNode(NULL
, (xmlChar
*)"template");
10630 (void) xmlAddChild(elts
.template, template_elts
.common_name
);
10631 (void) xmlAddChild(elts
.template, template_elts
.description
);
10632 (void) xmlAddChild(elts
.template, template_elts
.documentation
);
10634 xmlFreeNode(template_elts
.description
);
10635 xmlFreeNode(template_elts
.documentation
);
10638 if (isdefault
&& elts
.restarter
== NULL
&&
10639 elts
.dependencies
== NULL
&& elts
.method_context
== NULL
&&
10640 elts
.exec_methods
== NULL
&& elts
.notify_params
== NULL
&&
10641 elts
.property_groups
== NULL
&& elts
.template == NULL
) {
10644 /* This is a default instance */
10645 eval
= xmlGetProp(n
, (xmlChar
*)enabled_attr
);
10649 n
= xmlNewNode(NULL
, (xmlChar
*)"create_default_instance");
10651 uu_die(emsg_create_xml
);
10653 safe_setprop(n
, enabled_attr
, (char *)eval
);
10656 selts
->create_default_instance
= n
;
10658 /* Assemble the children in order. */
10659 (void) xmlAddChild(n
, elts
.restarter
);
10660 (void) xmlAddChildList(n
, elts
.dependencies
);
10661 (void) xmlAddChildList(n
, elts
.dependents
);
10662 (void) xmlAddChild(n
, elts
.method_context
);
10663 (void) xmlAddChildList(n
, elts
.exec_methods
);
10664 (void) xmlAddChildList(n
, elts
.notify_params
);
10665 (void) xmlAddChildList(n
, elts
.property_groups
);
10666 (void) xmlAddChild(n
, elts
.template);
10668 if (selts
->instances
== NULL
)
10669 selts
->instances
= n
;
10671 (void) xmlAddSibling(selts
->instances
, n
);
10676 * Return a service element for the given service.
10679 export_service(scf_service_t
*svc
, int flags
)
10682 struct entity_elts elts
;
10683 struct template_elts template_elts
;
10686 snode
= xmlNewNode(NULL
, (xmlChar
*)"service");
10688 uu_die(emsg_create_xml
);
10690 /* Get & set name attribute */
10691 if (scf_service_get_name(svc
, exp_str
, max_scf_name_len
+ 1) < 0)
10693 safe_setprop(snode
, name_attr
, exp_str
);
10695 safe_setprop(snode
, type_attr
, "service");
10696 safe_setprop(snode
, "version", "0");
10698 /* Acquire child elements. */
10699 if (scf_iter_service_pgs(exp_pg_iter
, svc
) != SCF_SUCCESS
)
10702 (void) memset(&elts
, 0, sizeof (elts
));
10703 (void) memset(&template_elts
, 0, sizeof (template_elts
));
10705 while ((ret
= scf_iter_next_pg(exp_pg_iter
, exp_pg
)) == 1) {
10708 if (scf_pg_get_flags(exp_pg
, &pgflags
) != 0)
10711 if (pgflags
& SCF_PG_FLAG_NONPERSISTENT
)
10714 if (scf_pg_get_type(exp_pg
, exp_str
, exp_str_sz
) < 0)
10717 if (strcmp(exp_str
, SCF_GROUP_DEPENDENCY
) == 0) {
10718 export_dependency(exp_pg
, &elts
);
10720 } else if (strcmp(exp_str
, SCF_GROUP_METHOD
) == 0) {
10721 export_method(exp_pg
, &elts
);
10723 } else if (strcmp(exp_str
, scf_group_framework
) == 0) {
10724 if (scf_pg_get_name(exp_pg
, exp_str
,
10725 max_scf_name_len
+ 1) < 0)
10728 if (strcmp(exp_str
, scf_pg_general
) == 0) {
10729 export_svc_general(exp_pg
, &elts
);
10731 } else if (strcmp(exp_str
, SCF_PG_METHOD_CONTEXT
) ==
10733 export_method_context(exp_pg
, &elts
);
10735 } else if (strcmp(exp_str
, SCF_PG_DEPENDENTS
) == 0) {
10736 export_dependents(exp_pg
, &elts
);
10738 } else if (strcmp(exp_str
, SCF_PG_MANIFESTFILES
) == 0) {
10741 } else if (strcmp(exp_str
, SCF_GROUP_TEMPLATE
) == 0) {
10742 export_template(exp_pg
, &elts
, &template_elts
);
10744 } else if (strcmp(exp_str
, SCF_NOTIFY_PARAMS_PG_TYPE
) == 0) {
10745 export_notify_params(exp_pg
, &elts
);
10749 export_pg(exp_pg
, &elts
, flags
);
10754 if (template_elts
.common_name
!= NULL
) {
10755 elts
.template = xmlNewNode(NULL
, (xmlChar
*)"template");
10756 (void) xmlAddChild(elts
.template, template_elts
.common_name
);
10757 (void) xmlAddChild(elts
.template, template_elts
.description
);
10758 (void) xmlAddChild(elts
.template, template_elts
.documentation
);
10760 xmlFreeNode(template_elts
.description
);
10761 xmlFreeNode(template_elts
.documentation
);
10764 /* Iterate instances */
10765 if (scf_iter_service_instances(exp_inst_iter
, svc
) != SCF_SUCCESS
)
10768 while ((ret
= scf_iter_next_instance(exp_inst_iter
, exp_inst
)) == 1)
10769 export_instance(exp_inst
, &elts
, flags
);
10773 /* Now add all of the accumulated elements in order. */
10774 (void) xmlAddChild(snode
, elts
.create_default_instance
);
10775 (void) xmlAddChild(snode
, elts
.single_instance
);
10776 (void) xmlAddChild(snode
, elts
.restarter
);
10777 (void) xmlAddChildList(snode
, elts
.dependencies
);
10778 (void) xmlAddChildList(snode
, elts
.dependents
);
10779 (void) xmlAddChild(snode
, elts
.method_context
);
10780 (void) xmlAddChildList(snode
, elts
.exec_methods
);
10781 (void) xmlAddChildList(snode
, elts
.notify_params
);
10782 (void) xmlAddChildList(snode
, elts
.property_groups
);
10783 (void) xmlAddChildList(snode
, elts
.instances
);
10784 (void) xmlAddChild(snode
, elts
.stability
);
10785 (void) xmlAddChild(snode
, elts
.template);
10791 export_callback(void *data
, scf_walkinfo_t
*wip
)
10797 struct export_args
*argsp
= (struct export_args
*)data
;
10799 if ((exp_inst
= scf_instance_create(g_hndl
)) == NULL
||
10800 (exp_pg
= scf_pg_create(g_hndl
)) == NULL
||
10801 (exp_prop
= scf_property_create(g_hndl
)) == NULL
||
10802 (exp_val
= scf_value_create(g_hndl
)) == NULL
||
10803 (exp_inst_iter
= scf_iter_create(g_hndl
)) == NULL
||
10804 (exp_pg_iter
= scf_iter_create(g_hndl
)) == NULL
||
10805 (exp_prop_iter
= scf_iter_create(g_hndl
)) == NULL
||
10806 (exp_val_iter
= scf_iter_create(g_hndl
)) == NULL
)
10809 exp_str_sz
= max_scf_len
+ 1;
10810 exp_str
= safe_malloc(exp_str_sz
);
10812 if (argsp
->filename
!= NULL
) {
10814 f
= fopen(argsp
->filename
, "wb");
10817 uu_die(gettext("Could not open \"%s\": no free "
10818 "stdio streams.\n"), argsp
->filename
);
10820 uu_die(gettext("Could not open \"%s\""),
10826 doc
= xmlNewDoc((xmlChar
*)"1.0");
10828 uu_die(gettext("Could not create XML document.\n"));
10830 if (xmlCreateIntSubset(doc
, (xmlChar
*)"service_bundle", NULL
,
10831 (xmlChar
*)MANIFEST_DTD_PATH
) == NULL
)
10832 uu_die(emsg_create_xml
);
10834 sb
= xmlNewNode(NULL
, (xmlChar
*)"service_bundle");
10836 uu_die(emsg_create_xml
);
10837 safe_setprop(sb
, type_attr
, "manifest");
10838 safe_setprop(sb
, name_attr
, "export");
10839 (void) xmlAddSibling(doc
->children
, sb
);
10841 (void) xmlAddChild(sb
, export_service(wip
->svc
, argsp
->flags
));
10843 result
= write_service_bundle(doc
, f
);
10846 scf_iter_destroy(exp_val_iter
);
10847 scf_iter_destroy(exp_prop_iter
);
10848 scf_iter_destroy(exp_pg_iter
);
10849 scf_iter_destroy(exp_inst_iter
);
10850 scf_value_destroy(exp_val
);
10851 scf_property_destroy(exp_prop
);
10852 scf_pg_destroy(exp_pg
);
10853 scf_instance_destroy(exp_inst
);
10864 * Get the service named by fmri, build an XML tree which represents it, and
10865 * dump it into filename (or stdout if filename is NULL).
10868 lscf_service_export(char *fmri
, const char *filename
, int flags
)
10870 struct export_args args
;
10872 const char *scope
, *svc
, *inst
;
10873 size_t cblen
= 3 * max_scf_name_len
;
10874 char *canonbuf
= alloca(cblen
);
10879 bzero(&args
, sizeof (args
));
10880 args
.filename
= filename
;
10881 args
.flags
= flags
;
10884 * If some poor user has passed an exact instance FMRI, of the sort
10885 * one might cut and paste from svcs(1) or an error message, warn
10886 * and chop off the instance instead of failing.
10888 fmridup
= alloca(strlen(fmri
) + 1);
10889 (void) strcpy(fmridup
, fmri
);
10890 if (strncmp(fmridup
, SCF_FMRI_SVC_PREFIX
,
10891 sizeof (SCF_FMRI_SVC_PREFIX
) -1) == 0 &&
10892 scf_parse_svc_fmri(fmridup
, &scope
, &svc
, &inst
, NULL
, NULL
) == 0 &&
10894 (void) strlcpy(canonbuf
, "svc:/", cblen
);
10895 if (strcmp(scope
, SCF_FMRI_LOCAL_SCOPE
) != 0) {
10896 (void) strlcat(canonbuf
, "/", cblen
);
10897 (void) strlcat(canonbuf
, scope
, cblen
);
10899 (void) strlcat(canonbuf
, svc
, cblen
);
10902 warn(gettext("Only services may be exported; ignoring "
10903 "instance portion of argument.\n"));
10907 if ((ret
= scf_walk_fmri(g_hndl
, 1, (char **)&fmri
,
10908 SCF_WALK_SERVICE
| SCF_WALK_NOINSTANCE
, export_callback
,
10909 &args
, &err
, semerr
)) != 0) {
10911 semerr(gettext("Failed to walk instances: %s\n"),
10912 scf_strerror(ret
));
10917 * Error message has already been printed.
10931 make_archive(int flags
)
10934 scf_scope_t
*scope
;
10935 scf_service_t
*svc
;
10939 if ((scope
= scf_scope_create(g_hndl
)) == NULL
||
10940 (svc
= scf_service_create(g_hndl
)) == NULL
||
10941 (iter
= scf_iter_create(g_hndl
)) == NULL
||
10942 (exp_inst
= scf_instance_create(g_hndl
)) == NULL
||
10943 (exp_pg
= scf_pg_create(g_hndl
)) == NULL
||
10944 (exp_prop
= scf_property_create(g_hndl
)) == NULL
||
10945 (exp_val
= scf_value_create(g_hndl
)) == NULL
||
10946 (exp_inst_iter
= scf_iter_create(g_hndl
)) == NULL
||
10947 (exp_pg_iter
= scf_iter_create(g_hndl
)) == NULL
||
10948 (exp_prop_iter
= scf_iter_create(g_hndl
)) == NULL
||
10949 (exp_val_iter
= scf_iter_create(g_hndl
)) == NULL
)
10952 exp_str_sz
= max_scf_len
+ 1;
10953 exp_str
= safe_malloc(exp_str_sz
);
10955 sb
= xmlNewNode(NULL
, (xmlChar
*)"service_bundle");
10957 uu_die(emsg_create_xml
);
10958 safe_setprop(sb
, type_attr
, "archive");
10959 safe_setprop(sb
, name_attr
, "none");
10961 if (scf_handle_get_scope(g_hndl
, SCF_SCOPE_LOCAL
, scope
) != 0)
10963 if (scf_iter_scope_services(iter
, scope
) != 0)
10967 r
= scf_iter_next_service(iter
, svc
);
10973 if (scf_service_get_name(svc
, exp_str
,
10974 max_scf_name_len
+ 1) < 0)
10977 if (strcmp(exp_str
, SCF_LEGACY_SERVICE
) == 0)
10980 (void) xmlAddChild(sb
, export_service(svc
, flags
));
10985 scf_iter_destroy(exp_val_iter
);
10986 scf_iter_destroy(exp_prop_iter
);
10987 scf_iter_destroy(exp_pg_iter
);
10988 scf_iter_destroy(exp_inst_iter
);
10989 scf_value_destroy(exp_val
);
10990 scf_property_destroy(exp_prop
);
10991 scf_pg_destroy(exp_pg
);
10992 scf_instance_destroy(exp_inst
);
10993 scf_iter_destroy(iter
);
10994 scf_service_destroy(svc
);
10995 scf_scope_destroy(scope
);
11001 lscf_archive(const char *filename
, int flags
)
11009 if (filename
!= NULL
) {
11011 f
= fopen(filename
, "wb");
11014 uu_die(gettext("Could not open \"%s\": no free "
11015 "stdio streams.\n"), filename
);
11017 uu_die(gettext("Could not open \"%s\""),
11023 doc
= xmlNewDoc((xmlChar
*)"1.0");
11025 uu_die(gettext("Could not create XML document.\n"));
11027 if (xmlCreateIntSubset(doc
, (xmlChar
*)"service_bundle", NULL
,
11028 (xmlChar
*)MANIFEST_DTD_PATH
) == NULL
)
11029 uu_die(emsg_create_xml
);
11031 (void) xmlAddSibling(doc
->children
, make_archive(flags
));
11033 result
= write_service_bundle(doc
, f
);
11045 * "Extract" a profile.
11048 lscf_profile_extract(const char *filename
)
11052 xmlNodePtr sb
, snode
, inode
;
11053 scf_scope_t
*scope
;
11054 scf_service_t
*svc
;
11055 scf_instance_t
*inst
;
11056 scf_propertygroup_t
*pg
;
11057 scf_property_t
*prop
;
11059 scf_iter_t
*siter
, *iiter
;
11067 if (filename
!= NULL
) {
11069 f
= fopen(filename
, "wb");
11072 uu_die(gettext("Could not open \"%s\": no "
11073 "free stdio streams.\n"), filename
);
11075 uu_die(gettext("Could not open \"%s\""),
11081 doc
= xmlNewDoc((xmlChar
*)"1.0");
11083 uu_die(gettext("Could not create XML document.\n"));
11085 if (xmlCreateIntSubset(doc
, (xmlChar
*)"service_bundle", NULL
,
11086 (xmlChar
*)MANIFEST_DTD_PATH
) == NULL
)
11087 uu_die(emsg_create_xml
);
11089 sb
= xmlNewNode(NULL
, (xmlChar
*)"service_bundle");
11091 uu_die(emsg_create_xml
);
11092 safe_setprop(sb
, type_attr
, "profile");
11093 safe_setprop(sb
, name_attr
, "extract");
11094 (void) xmlAddSibling(doc
->children
, sb
);
11096 if ((scope
= scf_scope_create(g_hndl
)) == NULL
||
11097 (svc
= scf_service_create(g_hndl
)) == NULL
||
11098 (inst
= scf_instance_create(g_hndl
)) == NULL
||
11099 (pg
= scf_pg_create(g_hndl
)) == NULL
||
11100 (prop
= scf_property_create(g_hndl
)) == NULL
||
11101 (val
= scf_value_create(g_hndl
)) == NULL
||
11102 (siter
= scf_iter_create(g_hndl
)) == NULL
||
11103 (iiter
= scf_iter_create(g_hndl
)) == NULL
)
11106 if (scf_handle_get_local_scope(g_hndl
, scope
) != SCF_SUCCESS
)
11109 if (scf_iter_scope_services(siter
, scope
) != SCF_SUCCESS
)
11112 namebuf
= safe_malloc(max_scf_name_len
+ 1);
11114 while ((r
= scf_iter_next_service(siter
, svc
)) == 1) {
11115 if (scf_iter_service_instances(iiter
, svc
) != SCF_SUCCESS
)
11118 snode
= xmlNewNode(NULL
, (xmlChar
*)"service");
11120 uu_die(emsg_create_xml
);
11122 if (scf_service_get_name(svc
, namebuf
, max_scf_name_len
+ 1) <
11126 safe_setprop(snode
, name_attr
, namebuf
);
11128 safe_setprop(snode
, type_attr
, "service");
11129 safe_setprop(snode
, "version", "0");
11131 while ((s
= scf_iter_next_instance(iiter
, inst
)) == 1) {
11132 if (scf_instance_get_pg(inst
, scf_pg_general
, pg
) !=
11134 if (scf_error() != SCF_ERROR_NOT_FOUND
)
11142 scf_instance_to_fmri(inst
, NULL
, 0);
11146 fmri
= safe_malloc(len
+ 1);
11148 if (scf_instance_to_fmri(inst
, fmri
,
11152 warn("Instance %s has no \"%s\" "
11153 "property group.\n", fmri
,
11162 if (pg_get_prop(pg
, scf_property_enabled
, prop
) != 0 ||
11163 prop_check_type(prop
, SCF_TYPE_BOOLEAN
) != 0 ||
11164 prop_get_val(prop
, val
) != 0)
11167 inode
= xmlNewChild(snode
, NULL
, (xmlChar
*)"instance",
11170 uu_die(emsg_create_xml
);
11172 if (scf_instance_get_name(inst
, namebuf
,
11173 max_scf_name_len
+ 1) < 0)
11176 safe_setprop(inode
, name_attr
, namebuf
);
11178 if (scf_value_get_boolean(val
, &b
) != SCF_SUCCESS
)
11181 safe_setprop(inode
, enabled_attr
, b
? true : false);
11186 if (snode
->children
!= NULL
)
11187 (void) xmlAddChild(sb
, snode
);
11189 xmlFreeNode(snode
);
11196 result
= write_service_bundle(doc
, f
);
11208 * Entity manipulation commands
11212 * Entity selection. If no entity is selected, then the current scope is in
11213 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected,
11214 * only cur_inst is NULL, and when an instance is selected, none are NULL.
11215 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
11216 * cur_inst will be non-NULL.
11219 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
11221 select_inst(const char *name
)
11223 scf_instance_t
*inst
;
11226 assert(cur_svc
!= NULL
);
11228 inst
= scf_instance_create(g_hndl
);
11232 if (scf_service_get_instance(cur_svc
, name
, inst
) == SCF_SUCCESS
) {
11238 if (err
!= SCF_ERROR_NOT_FOUND
&& err
!= SCF_ERROR_INVALID_ARGUMENT
)
11241 scf_instance_destroy(inst
);
11245 /* Returns as above. */
11247 select_svc(const char *name
)
11249 scf_service_t
*svc
;
11252 assert(cur_scope
!= NULL
);
11254 svc
= scf_service_create(g_hndl
);
11258 if (scf_scope_get_service(cur_scope
, name
, svc
) == SCF_SUCCESS
) {
11264 if (err
!= SCF_ERROR_NOT_FOUND
&& err
!= SCF_ERROR_INVALID_ARGUMENT
)
11267 scf_service_destroy(svc
);
11273 select_callback(void *unused
, scf_walkinfo_t
*wip
)
11275 scf_instance_t
*inst
;
11276 scf_service_t
*svc
;
11277 scf_scope_t
*scope
;
11279 if (wip
->inst
!= NULL
) {
11280 if ((scope
= scf_scope_create(g_hndl
)) == NULL
||
11281 (svc
= scf_service_create(g_hndl
)) == NULL
||
11282 (inst
= scf_instance_create(g_hndl
)) == NULL
)
11285 if (scf_handle_decode_fmri(g_hndl
, wip
->fmri
, scope
, svc
,
11286 inst
, NULL
, NULL
, SCF_DECODE_FMRI_EXACT
) != SCF_SUCCESS
)
11289 assert(wip
->svc
!= NULL
);
11291 if ((scope
= scf_scope_create(g_hndl
)) == NULL
||
11292 (svc
= scf_service_create(g_hndl
)) == NULL
)
11295 if (scf_handle_decode_fmri(g_hndl
, wip
->fmri
, scope
, svc
,
11296 NULL
, NULL
, NULL
, SCF_DECODE_FMRI_EXACT
) != SCF_SUCCESS
)
11302 /* Clear out the current selection */
11303 assert(cur_scope
!= NULL
);
11304 scf_scope_destroy(cur_scope
);
11305 scf_service_destroy(cur_svc
);
11306 scf_instance_destroy(cur_inst
);
11316 validate_callback(void *fmri_p
, scf_walkinfo_t
*wip
)
11318 char **fmri
= fmri_p
;
11320 *fmri
= strdup(wip
->fmri
);
11322 uu_die(gettext("Out of memory.\n"));
11329 * Perform the validation of an FMRI instance.
11332 lscf_validate_fmri(const char *fmri
)
11336 char *inst_fmri
= NULL
;
11337 scf_tmpl_errors_t
*errs
= NULL
;
11338 char *snapbuf
= NULL
;
11342 if (fmri
== NULL
) {
11343 inst_sz
= max_scf_fmri_len
+ 1;
11344 inst_fmri
= safe_malloc(inst_sz
);
11346 if (cur_snap
!= NULL
) {
11347 snapbuf
= safe_malloc(max_scf_name_len
+ 1);
11348 if (scf_snapshot_get_name(cur_snap
, snapbuf
,
11349 max_scf_name_len
+ 1) < 0)
11352 if (cur_inst
== NULL
) {
11353 semerr(gettext("No instance selected\n"));
11355 } else if (scf_instance_to_fmri(cur_inst
, inst_fmri
,
11356 inst_sz
) >= inst_sz
) {
11357 /* sanity check. Should never get here */
11358 uu_die(gettext("Unexpected error! file %s, line %d\n"),
11359 __FILE__
, __LINE__
);
11362 scf_error_t scf_err
;
11365 if ((scf_err
= scf_walk_fmri(g_hndl
, 1, (char **)&fmri
, 0,
11366 validate_callback
, &inst_fmri
, &err
, semerr
)) != 0) {
11367 uu_warn("Failed to walk instances: %s\n",
11368 scf_strerror(scf_err
));
11372 /* error message displayed by scf_walk_fmri */
11377 ret
= scf_tmpl_validate_fmri(g_hndl
, inst_fmri
, snapbuf
, &errs
,
11378 SCF_TMPL_VALIDATE_FLAG_CURRENT
);
11380 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID
) {
11381 warn(gettext("Template data for %s is invalid. "
11382 "Consider reverting to a previous snapshot or "
11383 "restoring original configuration.\n"), inst_fmri
);
11385 uu_warn("%s: %s\n",
11386 gettext("Error validating the instance"),
11387 scf_strerror(scf_error()));
11389 } else if (ret
== 1 && errs
!= NULL
) {
11390 scf_tmpl_error_t
*err
= NULL
;
11392 size_t len
= 256; /* initial error buffer size */
11393 int flag
= (est
->sc_cmd_flags
& SC_CMD_IACTIVE
) ?
11394 SCF_TMPL_STRERROR_HUMAN
: 0;
11396 msg
= safe_malloc(len
);
11398 while ((err
= scf_tmpl_next_error(errs
)) != NULL
) {
11401 if ((ret
= scf_tmpl_strerror(err
, msg
, len
,
11404 msg
= realloc(msg
, len
);
11407 "Out of memory.\n"));
11408 (void) scf_tmpl_strerror(err
, msg
, len
,
11411 (void) fprintf(stderr
, "%s\n", msg
);
11417 scf_tmpl_errors_destroy(errs
);
11425 lscf_validate_file(const char *filename
)
11427 tmpl_errors_t
*errs
;
11429 bundle_t
*b
= internal_bundle_new();
11430 if (lxml_get_bundle_file(b
, filename
, SVCCFG_OP_IMPORT
) == 0) {
11431 if (tmpl_validate_bundle(b
, &errs
) != TVS_SUCCESS
) {
11432 tmpl_errors_print(stderr
, errs
, "");
11433 semerr(gettext("Validation failed.\n"));
11435 tmpl_errors_destroy(errs
);
11437 (void) internal_bundle_free(b
);
11441 * validate [fmri|file]
11444 lscf_validate(const char *arg
)
11448 if (strncmp(arg
, SCF_FMRI_FILE_PREFIX
,
11449 sizeof (SCF_FMRI_FILE_PREFIX
) - 1) == 0) {
11450 str
= arg
+ sizeof (SCF_FMRI_FILE_PREFIX
) - 1;
11451 lscf_validate_file(str
);
11452 } else if (strncmp(arg
, SCF_FMRI_SVC_PREFIX
,
11453 sizeof (SCF_FMRI_SVC_PREFIX
) - 1) == 0) {
11454 str
= arg
+ sizeof (SCF_FMRI_SVC_PREFIX
) - 1;
11455 lscf_validate_fmri(str
);
11456 } else if (access(arg
, R_OK
| F_OK
) == 0) {
11457 lscf_validate_file(arg
);
11459 lscf_validate_fmri(arg
);
11464 lscf_select(const char *fmri
)
11470 if (cur_snap
!= NULL
) {
11471 struct snaplevel
*elt
;
11474 /* Error unless name is that of the next level. */
11475 elt
= uu_list_next(cur_levels
, cur_elt
);
11477 semerr(gettext("No children.\n"));
11481 buf
= safe_malloc(max_scf_name_len
+ 1);
11483 if (scf_snaplevel_get_instance_name(elt
->sl
, buf
,
11484 max_scf_name_len
+ 1) < 0)
11487 if (strcmp(buf
, fmri
) != 0) {
11488 semerr(gettext("No such child.\n"));
11496 cur_level
= elt
->sl
;
11501 * Special case for 'svc:', which takes the user to the scope level.
11503 if (strcmp(fmri
, "svc:") == 0) {
11504 scf_instance_destroy(cur_inst
);
11505 scf_service_destroy(cur_svc
);
11512 * Special case for ':properties'. This appears as part of 'list' but
11513 * can't be selected. Give a more helpful error message in this case.
11515 if (strcmp(fmri
, ":properties") == 0) {
11516 semerr(gettext(":properties is not an entity. Try 'listprop' "
11517 "to list properties.\n"));
11522 * First try the argument as relative to the current selection.
11524 if (cur_inst
!= NULL
) {
11526 } else if (cur_svc
!= NULL
) {
11527 if (select_inst(fmri
) != 1)
11530 if (select_svc(fmri
) != 1)
11535 if ((ret
= scf_walk_fmri(g_hndl
, 1, (char **)&fmri
, SCF_WALK_SERVICE
,
11536 select_callback
, NULL
, &err
, semerr
)) != 0) {
11537 semerr(gettext("Failed to walk instances: %s\n"),
11538 scf_strerror(ret
));
11543 lscf_unselect(void)
11547 if (cur_snap
!= NULL
) {
11548 struct snaplevel
*elt
;
11550 elt
= uu_list_prev(cur_levels
, cur_elt
);
11552 semerr(gettext("No parent levels.\n"));
11555 cur_level
= elt
->sl
;
11557 } else if (cur_inst
!= NULL
) {
11558 scf_instance_destroy(cur_inst
);
11560 } else if (cur_svc
!= NULL
) {
11561 scf_service_destroy(cur_svc
);
11564 semerr(gettext("Cannot unselect at scope level.\n"));
11569 * Return the FMRI of the current selection, for the prompt.
11572 lscf_get_selection_str(char *buf
, size_t bufsz
)
11575 ssize_t fmrilen
, szret
;
11576 boolean_t deleted
= B_FALSE
;
11578 if (g_hndl
== NULL
) {
11579 (void) strlcpy(buf
, "svc:", bufsz
);
11583 if (cur_level
!= NULL
) {
11584 assert(cur_snap
!= NULL
);
11586 /* [ snapshot ] FMRI [: instance ] */
11587 assert(bufsz
>= 1 + max_scf_name_len
+ 1 + max_scf_fmri_len
11588 + 2 + max_scf_name_len
+ 1 + 1);
11592 szret
= scf_snapshot_get_name(cur_snap
, buf
+ 1,
11593 max_scf_name_len
+ 1);
11595 if (scf_error() != SCF_ERROR_DELETED
)
11601 (void) strcat(buf
, "]svc:/");
11603 cp
= strchr(buf
, '\0');
11605 szret
= scf_snaplevel_get_service_name(cur_level
, cp
,
11606 max_scf_name_len
+ 1);
11608 if (scf_error() != SCF_ERROR_DELETED
)
11614 cp
= strchr(cp
, '\0');
11616 if (snaplevel_is_instance(cur_level
)) {
11619 if (scf_snaplevel_get_instance_name(cur_level
, cp
,
11620 max_scf_name_len
+ 1) < 0) {
11621 if (scf_error() != SCF_ERROR_DELETED
)
11630 if (scf_instance_get_name(cur_inst
, cp
,
11631 max_scf_name_len
+ 1) < 0) {
11632 if (scf_error() != SCF_ERROR_DELETED
)
11638 (void) strcat(buf
, "]");
11646 unselect_cursnap();
11649 assert(cur_snap
== NULL
);
11651 if (cur_inst
!= NULL
) {
11652 assert(cur_svc
!= NULL
);
11653 assert(cur_scope
!= NULL
);
11655 fmrilen
= scf_instance_to_fmri(cur_inst
, buf
, bufsz
);
11656 if (fmrilen
>= 0) {
11657 assert(fmrilen
< bufsz
);
11659 warn(emsg_deleted
);
11663 if (scf_error() != SCF_ERROR_DELETED
)
11668 scf_instance_destroy(cur_inst
);
11672 if (cur_svc
!= NULL
) {
11673 assert(cur_scope
!= NULL
);
11675 szret
= scf_service_to_fmri(cur_svc
, buf
, bufsz
);
11677 assert(szret
< bufsz
);
11679 warn(emsg_deleted
);
11683 if (scf_error() != SCF_ERROR_DELETED
)
11687 scf_service_destroy(cur_svc
);
11691 assert(cur_scope
!= NULL
);
11692 fmrilen
= scf_scope_to_fmri(cur_scope
, buf
, bufsz
);
11697 assert(fmrilen
< bufsz
);
11699 warn(emsg_deleted
);
11703 * Entity listing. Entities and colon namespaces (e.g., :properties and
11704 * :statistics) are listed for the current selection.
11707 lscf_list(const char *pattern
)
11715 if (cur_level
!= NULL
) {
11716 struct snaplevel
*elt
;
11718 (void) fputs(COLON_NAMESPACES
, stdout
);
11720 elt
= uu_list_next(cur_levels
, cur_elt
);
11725 * For now, we know that the next level is an instance. But
11726 * if we ever have multiple scopes, this could be complicated.
11728 buf
= safe_malloc(max_scf_name_len
+ 1);
11729 if (scf_snaplevel_get_instance_name(elt
->sl
, buf
,
11730 max_scf_name_len
+ 1) >= 0) {
11733 if (scf_error() != SCF_ERROR_DELETED
)
11742 if (cur_inst
!= NULL
) {
11743 (void) fputs(COLON_NAMESPACES
, stdout
);
11747 iter
= scf_iter_create(g_hndl
);
11751 buf
= safe_malloc(max_scf_name_len
+ 1);
11753 if (cur_svc
!= NULL
) {
11754 /* List the instances in this service. */
11755 scf_instance_t
*inst
;
11757 inst
= scf_instance_create(g_hndl
);
11761 if (scf_iter_service_instances(iter
, cur_svc
) == 0) {
11762 safe_printf(COLON_NAMESPACES
);
11765 ret
= scf_iter_next_instance(iter
, inst
);
11769 if (scf_error() != SCF_ERROR_DELETED
)
11775 if (scf_instance_get_name(inst
, buf
,
11776 max_scf_name_len
+ 1) >= 0) {
11777 if (pattern
== NULL
||
11778 fnmatch(pattern
, buf
, 0) == 0)
11781 if (scf_error() != SCF_ERROR_DELETED
)
11786 if (scf_error() != SCF_ERROR_DELETED
)
11790 scf_instance_destroy(inst
);
11792 /* List the services in this scope. */
11793 scf_service_t
*svc
;
11795 assert(cur_scope
!= NULL
);
11797 svc
= scf_service_create(g_hndl
);
11801 if (scf_iter_scope_services(iter
, cur_scope
) != SCF_SUCCESS
)
11805 ret
= scf_iter_next_service(iter
, svc
);
11811 if (scf_service_get_name(svc
, buf
,
11812 max_scf_name_len
+ 1) >= 0) {
11813 if (pattern
== NULL
||
11814 fnmatch(pattern
, buf
, 0) == 0)
11815 safe_printf("%s\n", buf
);
11817 if (scf_error() != SCF_ERROR_DELETED
)
11822 scf_service_destroy(svc
);
11826 scf_iter_destroy(iter
);
11830 * Entity addition. Creates an empty entity in the current selection.
11833 lscf_add(const char *name
)
11837 if (cur_snap
!= NULL
) {
11838 semerr(emsg_cant_modify_snapshots
);
11839 } else if (cur_inst
!= NULL
) {
11840 semerr(gettext("Cannot add entities to an instance.\n"));
11841 } else if (cur_svc
!= NULL
) {
11843 if (scf_service_add_instance(cur_svc
, name
, NULL
) !=
11845 switch (scf_error()) {
11846 case SCF_ERROR_INVALID_ARGUMENT
:
11847 semerr(gettext("Invalid name.\n"));
11850 case SCF_ERROR_EXISTS
:
11851 semerr(gettext("Instance already exists.\n"));
11854 case SCF_ERROR_PERMISSION_DENIED
:
11855 semerr(emsg_permission_denied
);
11863 assert(cur_scope
!= NULL
);
11865 if (scf_scope_add_service(cur_scope
, name
, NULL
) !=
11867 switch (scf_error()) {
11868 case SCF_ERROR_INVALID_ARGUMENT
:
11869 semerr(gettext("Invalid name.\n"));
11872 case SCF_ERROR_EXISTS
:
11873 semerr(gettext("Service already exists.\n"));
11876 case SCF_ERROR_PERMISSION_DENIED
:
11877 semerr(emsg_permission_denied
);
11880 case SCF_ERROR_BACKEND_READONLY
:
11881 semerr(emsg_read_only
);
11891 /* return 1 if the entity has no persistent pgs, else return 0 */
11893 entity_has_no_pgs(void *ent
, int isservice
)
11895 scf_iter_t
*iter
= NULL
;
11896 scf_propertygroup_t
*pg
= NULL
;
11901 if ((iter
= scf_iter_create(g_hndl
)) == NULL
||
11902 (pg
= scf_pg_create(g_hndl
)) == NULL
)
11906 if (scf_iter_service_pgs(iter
, (scf_service_t
*)ent
) < 0)
11909 if (scf_iter_instance_pgs(iter
, (scf_instance_t
*)ent
) < 0)
11913 while ((err
= scf_iter_next_pg(iter
, pg
)) == 1) {
11914 if (scf_pg_get_flags(pg
, &flags
) != 0)
11917 /* skip nonpersistent pgs */
11918 if (flags
& SCF_PG_FLAG_NONPERSISTENT
)
11928 scf_pg_destroy(pg
);
11929 scf_iter_destroy(iter
);
11934 /* return 1 if the service has no instances, else return 0 */
11936 svc_has_no_insts(scf_service_t
*svc
)
11938 scf_instance_t
*inst
;
11943 if ((inst
= scf_instance_create(g_hndl
)) == NULL
||
11944 (iter
= scf_iter_create(g_hndl
)) == NULL
)
11947 if (scf_iter_service_instances(iter
, svc
) != 0)
11950 r
= scf_iter_next_instance(iter
, inst
);
11953 } else if (r
== 0) {
11955 } else if (r
== -1) {
11958 bad_error("scf_iter_next_instance", r
);
11961 scf_iter_destroy(iter
);
11962 scf_instance_destroy(inst
);
11972 * Delete the property group <fmri>/:properties/<name>. Returns
11973 * SCF_ERROR_NONE on success (or if the entity is not found),
11974 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
11975 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
11979 delete_dependency_pg(const char *fmri
, const char *name
)
11981 void *entity
= NULL
;
11983 scf_propertygroup_t
*pg
= NULL
;
11984 scf_error_t result
;
11986 scf_service_t
*svc
= NULL
;
11987 scf_instance_t
*inst
= NULL
;
11988 scf_iter_t
*iter
= NULL
;
11989 char *name_buf
= NULL
;
11991 result
= fmri_to_entity(g_hndl
, fmri
, &entity
, &isservice
);
11993 case SCF_ERROR_NONE
:
11996 case SCF_ERROR_NO_MEMORY
:
11997 uu_die(gettext("Out of memory.\n"));
12000 case SCF_ERROR_INVALID_ARGUMENT
:
12001 case SCF_ERROR_CONSTRAINT_VIOLATED
:
12002 return (SCF_ERROR_INVALID_ARGUMENT
);
12004 case SCF_ERROR_NOT_FOUND
:
12005 result
= SCF_ERROR_NONE
;
12009 bad_error("fmri_to_entity", result
);
12012 pg
= scf_pg_create(g_hndl
);
12016 if (entity_get_pg(entity
, isservice
, name
, pg
) != 0) {
12017 if (scf_error() != SCF_ERROR_NOT_FOUND
)
12020 result
= SCF_ERROR_NONE
;
12024 pgty
= safe_malloc(max_scf_pg_type_len
+ 1);
12026 if (scf_pg_get_type(pg
, pgty
, max_scf_pg_type_len
+ 1) < 0)
12029 if (strcmp(pgty
, SCF_GROUP_DEPENDENCY
) != 0) {
12030 result
= SCF_ERROR_TYPE_MISMATCH
;
12037 if (scf_pg_delete(pg
) != 0) {
12038 result
= scf_error();
12039 if (result
!= SCF_ERROR_PERMISSION_DENIED
)
12045 * We have to handle the case where we've just deleted the last
12046 * property group of a "dummy" entity (instance or service).
12047 * A "dummy" entity is an entity only present to hold an
12048 * external dependency.
12049 * So, in the case we deleted the last property group then we
12050 * can also delete the entity. If the entity is an instance then
12051 * we must verify if this was the last instance for the service
12052 * and if it is, we can also delete the service if it doesn't
12053 * have any property group either.
12056 result
= SCF_ERROR_NONE
;
12059 svc
= (scf_service_t
*)entity
;
12061 if ((inst
= scf_instance_create(g_hndl
)) == NULL
||
12062 (iter
= scf_iter_create(g_hndl
)) == NULL
)
12065 name_buf
= safe_malloc(max_scf_name_len
+ 1);
12067 inst
= (scf_instance_t
*)entity
;
12071 * If the entity is an instance and we've just deleted its last
12072 * property group then we should delete it.
12074 if (!isservice
&& entity_has_no_pgs(entity
, isservice
)) {
12075 /* find the service before deleting the inst. - needed later */
12076 if ((svc
= scf_service_create(g_hndl
)) == NULL
)
12079 if (scf_instance_get_parent(inst
, svc
) != 0)
12082 /* delete the instance */
12083 if (scf_instance_delete(inst
) != 0) {
12084 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
12087 result
= SCF_ERROR_PERMISSION_DENIED
;
12090 /* no need to refresh the instance */
12095 * If the service has no more instances and pgs or we just deleted the
12096 * last instance and the service doesn't have anymore propery groups
12097 * then the service should be deleted.
12100 svc_has_no_insts(svc
) &&
12101 entity_has_no_pgs((void *)svc
, 1)) {
12102 if (scf_service_delete(svc
) == 0) {
12104 /* no need to refresh the service */
12111 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
12114 result
= SCF_ERROR_PERMISSION_DENIED
;
12117 /* if the entity has not been deleted, refresh it */
12118 if ((isservice
&& svc
!= NULL
) || (!isservice
&& inst
!= NULL
)) {
12119 (void) refresh_entity(isservice
, entity
, fmri
, inst
, iter
,
12124 if (isservice
&& (inst
!= NULL
&& iter
!= NULL
)) {
12126 scf_iter_destroy(iter
);
12127 scf_instance_destroy(inst
);
12130 if (!isservice
&& svc
!= NULL
) {
12131 scf_service_destroy(svc
);
12134 scf_pg_destroy(pg
);
12135 if (entity
!= NULL
)
12136 entity_destroy(entity
, isservice
);
12142 delete_dependents(scf_propertygroup_t
*pg
)
12144 char *pgty
, *name
, *fmri
;
12145 scf_property_t
*prop
;
12151 /* Verify that the pg has the correct type. */
12152 pgty
= safe_malloc(max_scf_pg_type_len
+ 1);
12153 if (scf_pg_get_type(pg
, pgty
, max_scf_pg_type_len
+ 1) < 0)
12156 if (strcmp(pgty
, scf_group_framework
) != 0) {
12158 fmri
= safe_malloc(max_scf_fmri_len
+ 1);
12159 if (scf_pg_to_fmri(pg
, fmri
, max_scf_fmri_len
+ 1) < 0)
12162 warn(gettext("Property group %s is not of expected "
12163 "type %s.\n"), fmri
, scf_group_framework
);
12174 /* map delete_dependency_pg onto the properties. */
12175 if ((prop
= scf_property_create(g_hndl
)) == NULL
||
12176 (val
= scf_value_create(g_hndl
)) == NULL
||
12177 (iter
= scf_iter_create(g_hndl
)) == NULL
)
12180 if (scf_iter_pg_properties(iter
, pg
) != SCF_SUCCESS
)
12183 name
= safe_malloc(max_scf_name_len
+ 1);
12184 fmri
= safe_malloc(max_scf_fmri_len
+ 2);
12186 while ((r
= scf_iter_next_property(iter
, prop
)) == 1) {
12189 if (scf_property_get_name(prop
, name
, max_scf_name_len
+ 1) < 0)
12192 if (scf_property_type(prop
, &ty
) != SCF_SUCCESS
)
12195 if ((ty
!= SCF_TYPE_ASTRING
&&
12196 prop_check_type(prop
, SCF_TYPE_FMRI
) != 0) ||
12197 prop_get_val(prop
, val
) != 0)
12200 if (scf_value_get_astring(val
, fmri
, max_scf_fmri_len
+ 2) < 0)
12203 err
= delete_dependency_pg(fmri
, name
);
12204 if (err
== SCF_ERROR_INVALID_ARGUMENT
&& g_verbose
) {
12205 if (scf_property_to_fmri(prop
, fmri
,
12206 max_scf_fmri_len
+ 2) < 0)
12209 warn(gettext("Value of %s is not a valid FMRI.\n"),
12211 } else if (err
== SCF_ERROR_TYPE_MISMATCH
&& g_verbose
) {
12212 warn(gettext("Property group \"%s\" of entity \"%s\" "
12213 "does not have dependency type.\n"), name
, fmri
);
12214 } else if (err
== SCF_ERROR_PERMISSION_DENIED
&& g_verbose
) {
12215 warn(gettext("Could not delete property group \"%s\" "
12216 "of entity \"%s\" (permission denied).\n"), name
,
12223 scf_value_destroy(val
);
12224 scf_property_destroy(prop
);
12230 * Returns 1 if the instance may be running, and 0 otherwise.
12233 inst_is_running(scf_instance_t
*inst
)
12235 scf_propertygroup_t
*pg
;
12236 scf_property_t
*prop
;
12238 char buf
[MAX_SCF_STATE_STRING_SZ
];
12242 if ((pg
= scf_pg_create(g_hndl
)) == NULL
||
12243 (prop
= scf_property_create(g_hndl
)) == NULL
||
12244 (val
= scf_value_create(g_hndl
)) == NULL
)
12247 if (scf_instance_get_pg(inst
, SCF_PG_RESTARTER
, pg
) != SCF_SUCCESS
) {
12248 if (scf_error() != SCF_ERROR_NOT_FOUND
)
12253 if (pg_get_prop(pg
, SCF_PROPERTY_STATE
, prop
) != 0 ||
12254 prop_check_type(prop
, SCF_TYPE_ASTRING
) != 0 ||
12255 prop_get_val(prop
, val
) != 0)
12258 szret
= scf_value_get_astring(val
, buf
, sizeof (buf
));
12259 assert(szret
>= 0);
12261 ret
= (strcmp(buf
, SCF_STATE_STRING_ONLINE
) == 0 ||
12262 strcmp(buf
, SCF_STATE_STRING_DEGRADED
) == 0) ? 1 : 0;
12265 scf_value_destroy(val
);
12266 scf_property_destroy(prop
);
12267 scf_pg_destroy(pg
);
12272 pg_is_external_dependency(scf_propertygroup_t
*pg
)
12276 scf_property_t
*prop
;
12277 uint8_t b
= B_FALSE
;
12279 type
= safe_malloc(max_scf_pg_type_len
+ 1);
12281 if (scf_pg_get_type(pg
, type
, max_scf_pg_type_len
+ 1) < 0)
12284 if ((prop
= scf_property_create(g_hndl
)) == NULL
||
12285 (val
= scf_value_create(g_hndl
)) == NULL
)
12288 if (strcmp(type
, SCF_GROUP_DEPENDENCY
) == 0) {
12289 if (pg_get_prop(pg
, scf_property_external
, prop
) == 0) {
12290 if (scf_property_get_value(prop
, val
) != 0)
12292 if (scf_value_get_boolean(val
, &b
) != 0)
12298 (void) scf_value_destroy(val
);
12299 (void) scf_property_destroy(prop
);
12304 #define DELETE_FAILURE -1
12305 #define DELETE_SUCCESS_NOEXTDEPS 0
12306 #define DELETE_SUCCESS_EXTDEPS 1
12309 * lscf_instance_delete() deletes an instance. Before calling
12310 * scf_instance_delete(), though, we make sure the instance isn't
12311 * running and delete dependencies in other entities which the instance
12312 * declared as "dependents". If there are dependencies which were
12313 * created for other entities, then instead of deleting the instance we
12314 * make it "empty" by deleting all other property groups and all
12317 * lscf_instance_delete() verifies that there is no external dependency pgs
12318 * before suppressing the instance. If there is, then we must not remove them
12319 * now in case the instance is re-created otherwise the dependencies would be
12320 * lost. The external dependency pgs will be removed if the dependencies are
12324 * DELETE_FAILURE on failure
12325 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12326 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12329 lscf_instance_delete(scf_instance_t
*inst
, int force
)
12331 scf_propertygroup_t
*pg
;
12332 scf_snapshot_t
*snap
;
12337 /* If we're not forcing and the instance is running, refuse. */
12338 if (!force
&& inst_is_running(inst
)) {
12341 fmri
= safe_malloc(max_scf_fmri_len
+ 1);
12343 if (scf_instance_to_fmri(inst
, fmri
, max_scf_fmri_len
+ 1) < 0)
12346 semerr(gettext("Instance %s may be running. "
12347 "Use delete -f if it is not.\n"), fmri
);
12350 return (DELETE_FAILURE
);
12353 pg
= scf_pg_create(g_hndl
);
12357 if (scf_instance_get_pg(inst
, SCF_PG_DEPENDENTS
, pg
) == 0)
12358 (void) delete_dependents(pg
);
12359 else if (scf_error() != SCF_ERROR_NOT_FOUND
)
12362 scf_pg_destroy(pg
);
12365 * If the instance has some external dependencies then we must
12366 * keep them in case the instance is reimported otherwise the
12367 * dependencies would be lost on reimport.
12369 if ((iter
= scf_iter_create(g_hndl
)) == NULL
||
12370 (pg
= scf_pg_create(g_hndl
)) == NULL
)
12373 if (scf_iter_instance_pgs(iter
, inst
) < 0)
12376 while ((err
= scf_iter_next_pg(iter
, pg
)) == 1) {
12377 if (pg_is_external_dependency(pg
)) {
12382 if (scf_pg_delete(pg
) != 0) {
12383 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
12386 semerr(emsg_permission_denied
);
12388 (void) scf_iter_destroy(iter
);
12389 (void) scf_pg_destroy(pg
);
12390 return (DELETE_FAILURE
);
12398 (void) scf_iter_destroy(iter
);
12399 (void) scf_pg_destroy(pg
);
12403 * All the pgs have been deleted for the instance except
12404 * the ones holding the external dependencies.
12405 * For the job to be complete, we must also delete the
12406 * snapshots associated with the instance.
12408 if ((snap
= scf_snapshot_create((scf_handle_t
*)g_hndl
)) ==
12411 if ((iter
= scf_iter_create((scf_handle_t
*)g_hndl
)) == NULL
)
12414 if (scf_iter_instance_snapshots(iter
, inst
) == -1)
12417 while ((err
= scf_iter_next_snapshot(iter
, snap
)) == 1) {
12418 if (_scf_snapshot_delete(snap
) != 0) {
12419 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
12422 semerr(emsg_permission_denied
);
12424 (void) scf_iter_destroy(iter
);
12425 (void) scf_snapshot_destroy(snap
);
12426 return (DELETE_FAILURE
);
12433 (void) scf_iter_destroy(iter
);
12434 (void) scf_snapshot_destroy(snap
);
12435 return (DELETE_SUCCESS_EXTDEPS
);
12438 if (scf_instance_delete(inst
) != 0) {
12439 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
12442 semerr(emsg_permission_denied
);
12444 return (DELETE_FAILURE
);
12447 return (DELETE_SUCCESS_NOEXTDEPS
);
12451 * lscf_service_delete() deletes a service. Before calling
12452 * scf_service_delete(), though, we call lscf_instance_delete() for
12453 * each of the instances and delete dependencies in other entities
12454 * which were created as "dependents" of this service. If there are
12455 * dependencies which were created for other entities, then we delete
12456 * all other property groups in the service and leave it as "empty".
12458 * lscf_service_delete() verifies that there is no external dependency
12459 * pgs at the instance & service level before suppressing the service.
12460 * If there is, then we must not remove them now in case the service
12461 * is re-imported otherwise the dependencies would be lost. The external
12462 * dependency pgs will be removed if the dependencies are removed.
12465 * DELETE_FAILURE on failure
12466 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12467 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12470 lscf_service_delete(scf_service_t
*svc
, int force
)
12473 scf_instance_t
*inst
;
12474 scf_propertygroup_t
*pg
;
12479 if ((inst
= scf_instance_create(g_hndl
)) == NULL
||
12480 (pg
= scf_pg_create(g_hndl
)) == NULL
||
12481 (iter
= scf_iter_create(g_hndl
)) == NULL
)
12484 if (scf_iter_service_instances(iter
, svc
) != 0)
12487 for (r
= scf_iter_next_instance(iter
, inst
);
12489 r
= scf_iter_next_instance(iter
, inst
)) {
12491 ret
= lscf_instance_delete(inst
, force
);
12492 if (ret
== DELETE_FAILURE
) {
12493 scf_iter_destroy(iter
);
12494 scf_pg_destroy(pg
);
12495 scf_instance_destroy(inst
);
12496 return (DELETE_FAILURE
);
12500 * Record the fact that there is some external dependencies
12501 * at the instance level.
12503 if (ret
== DELETE_SUCCESS_EXTDEPS
)
12510 /* Delete dependency property groups in dependent services. */
12511 if (scf_service_get_pg(svc
, SCF_PG_DEPENDENTS
, pg
) == 0)
12512 (void) delete_dependents(pg
);
12513 else if (scf_error() != SCF_ERROR_NOT_FOUND
)
12516 scf_iter_destroy(iter
);
12517 scf_pg_destroy(pg
);
12518 scf_instance_destroy(inst
);
12521 * If the service has some external dependencies then we don't
12522 * want to remove them in case the service is re-imported.
12524 if ((pg
= scf_pg_create(g_hndl
)) == NULL
||
12525 (iter
= scf_iter_create(g_hndl
)) == NULL
)
12528 if (scf_iter_service_pgs(iter
, svc
) < 0)
12531 while ((r
= scf_iter_next_pg(iter
, pg
)) == 1) {
12532 if (pg_is_external_dependency(pg
)) {
12537 if (scf_pg_delete(pg
) != 0) {
12538 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
12541 semerr(emsg_permission_denied
);
12543 (void) scf_iter_destroy(iter
);
12544 (void) scf_pg_destroy(pg
);
12545 return (DELETE_FAILURE
);
12553 (void) scf_iter_destroy(iter
);
12554 (void) scf_pg_destroy(pg
);
12557 return (DELETE_SUCCESS_EXTDEPS
);
12559 if (scf_service_delete(svc
) == 0)
12560 return (DELETE_SUCCESS_NOEXTDEPS
);
12562 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
12565 semerr(emsg_permission_denied
);
12566 return (DELETE_FAILURE
);
12570 delete_callback(void *data
, scf_walkinfo_t
*wip
)
12572 int force
= (int)data
;
12574 if (wip
->inst
!= NULL
)
12575 (void) lscf_instance_delete(wip
->inst
, force
);
12577 (void) lscf_service_delete(wip
->svc
, force
);
12583 lscf_delete(const char *fmri
, int force
)
12585 scf_service_t
*svc
;
12586 scf_instance_t
*inst
;
12591 if (cur_snap
!= NULL
) {
12592 if (!snaplevel_is_instance(cur_level
)) {
12595 buf
= safe_malloc(max_scf_name_len
+ 1);
12596 if (scf_instance_get_name(cur_inst
, buf
,
12597 max_scf_name_len
+ 1) >= 0) {
12598 if (strcmp(buf
, fmri
) == 0) {
12599 semerr(emsg_cant_modify_snapshots
);
12603 } else if (scf_error() != SCF_ERROR_DELETED
) {
12608 } else if (cur_inst
!= NULL
) {
12610 } else if (cur_svc
!= NULL
) {
12611 inst
= scf_instance_create(g_hndl
);
12615 if (scf_service_get_instance(cur_svc
, fmri
, inst
) ==
12617 (void) lscf_instance_delete(inst
, force
);
12618 scf_instance_destroy(inst
);
12622 if (scf_error() != SCF_ERROR_NOT_FOUND
&&
12623 scf_error() != SCF_ERROR_INVALID_ARGUMENT
)
12626 scf_instance_destroy(inst
);
12628 assert(cur_scope
!= NULL
);
12630 svc
= scf_service_create(g_hndl
);
12634 if (scf_scope_get_service(cur_scope
, fmri
, svc
) ==
12636 (void) lscf_service_delete(svc
, force
);
12637 scf_service_destroy(svc
);
12641 if (scf_error() != SCF_ERROR_NOT_FOUND
&&
12642 scf_error() != SCF_ERROR_INVALID_ARGUMENT
)
12645 scf_service_destroy(svc
);
12649 * Match FMRI to entity.
12651 if ((ret
= scf_walk_fmri(g_hndl
, 1, (char **)&fmri
, SCF_WALK_SERVICE
,
12652 delete_callback
, (void *)force
, NULL
, semerr
)) != 0) {
12653 semerr(gettext("Failed to walk instances: %s\n"),
12654 scf_strerror(ret
));
12661 * :properties commands. These all end with "pg" or "prop" and generally
12662 * operate on the currently selected entity.
12666 * Property listing. List the property groups, properties, their types and
12667 * their values for the currently selected entity.
12670 list_pg_info(const scf_propertygroup_t
*pg
, const char *name
, size_t namewidth
)
12675 buf
= safe_malloc(max_scf_pg_type_len
+ 1);
12677 if (scf_pg_get_type(pg
, buf
, max_scf_pg_type_len
+ 1) < 0)
12680 if (scf_pg_get_flags(pg
, &flags
) != SCF_SUCCESS
)
12683 safe_printf("%-*s %s", namewidth
, name
, buf
);
12685 if (flags
& SCF_PG_FLAG_NONPERSISTENT
)
12686 safe_printf("\tNONPERSISTENT");
12694 prop_has_multiple_values(const scf_property_t
*prop
, scf_value_t
*val
)
12696 if (scf_property_get_value(prop
, val
) == 0) {
12699 switch (scf_error()) {
12700 case SCF_ERROR_NOT_FOUND
:
12702 case SCF_ERROR_PERMISSION_DENIED
:
12703 case SCF_ERROR_CONSTRAINT_VIOLATED
:
12713 list_prop_info(const scf_property_t
*prop
, const char *name
, size_t len
)
12718 int multiple_strings
= 0;
12721 if ((iter
= scf_iter_create(g_hndl
)) == NULL
||
12722 (val
= scf_value_create(g_hndl
)) == NULL
)
12725 type
= prop_to_typestr(prop
);
12726 assert(type
!= NULL
);
12728 safe_printf("%-*s %-7s ", len
, name
, type
);
12730 if (prop_has_multiple_values(prop
, val
) &&
12731 (scf_value_type(val
) == SCF_TYPE_ASTRING
||
12732 scf_value_type(val
) == SCF_TYPE_USTRING
))
12733 multiple_strings
= 1;
12735 if (scf_iter_property_values(iter
, prop
) != SCF_SUCCESS
)
12738 while ((ret
= scf_iter_next_value(iter
, val
)) == 1) {
12740 ssize_t vlen
, szret
;
12742 vlen
= scf_value_get_as_string(val
, NULL
, 0);
12746 buf
= safe_malloc(vlen
+ 1);
12748 szret
= scf_value_get_as_string(val
, buf
, vlen
+ 1);
12751 assert(szret
<= vlen
);
12753 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12754 if (multiple_strings
|| strpbrk(buf
, " \t\n\"()") != NULL
) {
12755 safe_printf(" \"");
12756 (void) quote_and_print(buf
, stdout
, 0);
12757 (void) putchar('"');
12758 if (ferror(stdout
)) {
12759 (void) putchar('\n');
12760 uu_die(gettext("Error writing to stdout.\n"));
12763 safe_printf(" %s", buf
);
12768 if (ret
!= 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED
)
12771 if (putchar('\n') != '\n')
12772 uu_die(gettext("Could not output newline"));
12776 * Outputs template property group info for the describe subcommand.
12777 * If 'templates' == 2, verbose output is printed in the format expected
12778 * for describe -v, which includes all templates fields. If pg is
12779 * not NULL, we're describing the template data, not an existing property
12780 * group, and formatting should be appropriate for describe -t.
12783 list_pg_tmpl(scf_pg_tmpl_t
*pgt
, scf_propertygroup_t
*pg
, int templates
)
12787 scf_property_t
*stability_prop
;
12788 scf_value_t
*stability_val
;
12790 if (templates
== 0)
12793 if ((stability_prop
= scf_property_create(g_hndl
)) == NULL
||
12794 (stability_val
= scf_value_create(g_hndl
)) == NULL
)
12797 if (templates
== 2 && pg
!= NULL
) {
12798 if (scf_pg_get_property(pg
, SCF_PROPERTY_STABILITY
,
12799 stability_prop
) == 0) {
12800 if (prop_check_type(stability_prop
,
12801 SCF_TYPE_ASTRING
) == 0 &&
12802 prop_get_val(stability_prop
, stability_val
) == 0) {
12805 stability
= safe_malloc(max_scf_value_len
+ 1);
12807 if (scf_value_get_astring(stability_val
,
12808 stability
, max_scf_value_len
+ 1) == -1 &&
12809 scf_error() != SCF_ERROR_NOT_FOUND
)
12812 safe_printf("%s%s: %s\n", TMPL_INDENT
,
12813 gettext("stability"), stability
);
12817 } else if (scf_error() != SCF_ERROR_NOT_FOUND
)
12821 scf_property_destroy(stability_prop
);
12822 scf_value_destroy(stability_val
);
12827 if (pg
== NULL
|| templates
== 2) {
12828 /* print type info only if scf_tmpl_pg_name succeeds */
12829 if (scf_tmpl_pg_name(pgt
, &buf
) != -1) {
12831 safe_printf("%s", TMPL_INDENT
);
12832 safe_printf("%s: ", gettext("name"));
12833 safe_printf("%s\n", buf
);
12837 /* print type info only if scf_tmpl_pg_type succeeds */
12838 if (scf_tmpl_pg_type(pgt
, &buf
) != -1) {
12840 safe_printf("%s", TMPL_INDENT
);
12841 safe_printf("%s: ", gettext("type"));
12842 safe_printf("%s\n", buf
);
12847 if (templates
== 2 && scf_tmpl_pg_required(pgt
, &required
) == 0)
12848 safe_printf("%s%s: %s\n", TMPL_INDENT
, gettext("required"),
12849 required
? "true" : "false");
12851 if (templates
== 2 && scf_tmpl_pg_target(pgt
, &buf
) > 0) {
12852 safe_printf("%s%s: %s\n", TMPL_INDENT
, gettext("target"),
12857 if (templates
== 2 && scf_tmpl_pg_common_name(pgt
, NULL
, &buf
) > 0) {
12858 safe_printf("%s%s: %s\n", TMPL_INDENT
, gettext("common name"),
12863 if (scf_tmpl_pg_description(pgt
, NULL
, &buf
) > 0) {
12864 if (templates
== 2)
12865 safe_printf("%s%s: %s\n", TMPL_INDENT
,
12866 gettext("description"), buf
);
12868 safe_printf("%s%s\n", TMPL_INDENT
, buf
);
12875 * With as_value set to true, indent as appropriate for the value level.
12876 * If false, indent to appropriate level for inclusion in constraint
12877 * or choice printout.
12880 print_template_value_details(scf_prop_tmpl_t
*prt
, const char *val_buf
,
12885 if (scf_tmpl_value_common_name(prt
, NULL
, val_buf
, &buf
) > 0) {
12887 safe_printf("%s", TMPL_CHOICE_INDENT
);
12889 safe_printf("%s", TMPL_INDENT
);
12890 safe_printf("%s: %s\n", gettext("value common name"), buf
);
12894 if (scf_tmpl_value_description(prt
, NULL
, val_buf
, &buf
) > 0) {
12896 safe_printf("%s", TMPL_CHOICE_INDENT
);
12898 safe_printf("%s", TMPL_INDENT
);
12899 safe_printf("%s: %s\n", gettext("value description"), buf
);
12905 print_template_value(scf_prop_tmpl_t
*prt
, const char *val_buf
)
12907 safe_printf("%s%s: ", TMPL_VALUE_INDENT
, gettext("value"));
12908 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12909 safe_printf("%s\n", val_buf
);
12911 print_template_value_details(prt
, val_buf
, 1);
12915 print_template_constraints(scf_prop_tmpl_t
*prt
, int verbose
)
12917 int i
, printed
= 0;
12918 scf_values_t values
;
12919 scf_count_ranges_t c_ranges
;
12920 scf_int_ranges_t i_ranges
;
12924 if (scf_tmpl_value_name_constraints(prt
, &values
) == 0) {
12925 safe_printf("%s%s:\n", TMPL_VALUE_INDENT
,
12926 gettext("value constraints"));
12928 for (i
= 0; i
< values
.value_count
; ++i
) {
12929 safe_printf("%s%s: %s\n", TMPL_INDENT
,
12930 gettext("value name"), values
.values_as_strings
[i
]);
12932 print_template_value_details(prt
,
12933 values
.values_as_strings
[i
], 0);
12936 scf_values_destroy(&values
);
12939 if (scf_tmpl_value_count_range_constraints(prt
, &c_ranges
) == 0) {
12940 if (printed
++ == 0)
12941 safe_printf("%s%s:\n", TMPL_VALUE_INDENT
,
12942 gettext("value constraints"));
12943 for (i
= 0; i
< c_ranges
.scr_num_ranges
; ++i
) {
12944 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT
,
12945 gettext("range"), c_ranges
.scr_min
[i
],
12946 c_ranges
.scr_max
[i
]);
12948 scf_count_ranges_destroy(&c_ranges
);
12949 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED
&&
12950 scf_tmpl_value_int_range_constraints(prt
, &i_ranges
) == 0) {
12951 if (printed
++ == 0)
12952 safe_printf("%s%s:\n", TMPL_VALUE_INDENT
,
12953 gettext("value constraints"));
12954 for (i
= 0; i
< i_ranges
.sir_num_ranges
; ++i
) {
12955 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT
,
12956 gettext("range"), i_ranges
.sir_min
[i
],
12957 i_ranges
.sir_max
[i
]);
12959 scf_int_ranges_destroy(&i_ranges
);
12964 print_template_choices(scf_prop_tmpl_t
*prt
, int verbose
)
12966 int i
= 0, printed
= 0;
12967 scf_values_t values
;
12968 scf_count_ranges_t c_ranges
;
12969 scf_int_ranges_t i_ranges
;
12972 if (scf_tmpl_value_name_choices(prt
, &values
) == 0) {
12973 safe_printf("%s%s:\n", TMPL_VALUE_INDENT
,
12974 gettext("value constraints"));
12976 for (i
= 0; i
< values
.value_count
; i
++) {
12977 safe_printf("%s%s: %s\n", TMPL_INDENT
,
12978 gettext("value name"), values
.values_as_strings
[i
]);
12980 print_template_value_details(prt
,
12981 values
.values_as_strings
[i
], 0);
12984 scf_values_destroy(&values
);
12987 if (scf_tmpl_value_count_range_choices(prt
, &c_ranges
) == 0) {
12988 for (i
= 0; i
< c_ranges
.scr_num_ranges
; ++i
) {
12989 if (printed
++ == 0)
12990 safe_printf("%s%s:\n", TMPL_VALUE_INDENT
,
12991 gettext("value choices"));
12992 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT
,
12993 gettext("range"), c_ranges
.scr_min
[i
],
12994 c_ranges
.scr_max
[i
]);
12996 scf_count_ranges_destroy(&c_ranges
);
12997 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED
&&
12998 scf_tmpl_value_int_range_choices(prt
, &i_ranges
) == 0) {
12999 for (i
= 0; i
< i_ranges
.sir_num_ranges
; ++i
) {
13000 if (printed
++ == 0)
13001 safe_printf("%s%s:\n", TMPL_VALUE_INDENT
,
13002 gettext("value choices"));
13003 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT
,
13004 gettext("range"), i_ranges
.sir_min
[i
],
13005 i_ranges
.sir_max
[i
]);
13007 scf_int_ranges_destroy(&i_ranges
);
13012 list_values_by_template(scf_prop_tmpl_t
*prt
)
13014 print_template_constraints(prt
, 1);
13015 print_template_choices(prt
, 1);
13019 list_values_tmpl(scf_prop_tmpl_t
*prt
, scf_property_t
*prop
)
13026 if ((iter
= scf_iter_create(g_hndl
)) == NULL
||
13027 (val
= scf_value_create(g_hndl
)) == NULL
)
13030 if (scf_iter_property_values(iter
, prop
) != SCF_SUCCESS
)
13033 val_buf
= safe_malloc(max_scf_value_len
+ 1);
13035 while ((ret
= scf_iter_next_value(iter
, val
)) == 1) {
13036 if (scf_value_get_as_string(val
, val_buf
,
13037 max_scf_value_len
+ 1) < 0)
13040 print_template_value(prt
, val_buf
);
13042 if (ret
!= 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED
)
13046 print_template_constraints(prt
, 0);
13047 print_template_choices(prt
, 0);
13052 * Outputs property info for the describe subcommand
13053 * Verbose output if templates == 2, -v option of svccfg describe
13054 * Displays template data if prop is not NULL, -t option of svccfg describe
13057 list_prop_tmpl(scf_prop_tmpl_t
*prt
, scf_property_t
*prop
, int templates
)
13063 scf_values_t values
;
13065 if (prt
== NULL
|| templates
== 0)
13068 if (prop
== NULL
) {
13069 safe_printf("%s%s: ", TMPL_VALUE_INDENT
, gettext("name"));
13070 if (scf_tmpl_prop_name(prt
, &buf
) > 0) {
13071 safe_printf("%s\n", buf
);
13074 safe_printf("(%s)\n", gettext("any"));
13077 if (prop
== NULL
|| templates
== 2) {
13079 safe_printf("%s", TMPL_INDENT
);
13081 safe_printf("%s", TMPL_VALUE_INDENT
);
13082 safe_printf("%s: ", gettext("type"));
13083 if ((buf
= _scf_read_tmpl_prop_type_as_string(prt
)) != NULL
) {
13084 safe_printf("%s\n", buf
);
13087 safe_printf("(%s)\n", gettext("any"));
13090 if (templates
== 2 && scf_tmpl_prop_required(prt
, &u_buf
) == 0)
13091 safe_printf("%s%s: %s\n", TMPL_INDENT
, gettext("required"),
13092 u_buf
? "true" : "false");
13094 if (templates
== 2 && scf_tmpl_prop_common_name(prt
, NULL
, &buf
) > 0) {
13095 safe_printf("%s%s: %s\n", TMPL_INDENT
, gettext("common name"),
13100 if (templates
== 2 && scf_tmpl_prop_units(prt
, NULL
, &buf
) > 0) {
13101 safe_printf("%s%s: %s\n", TMPL_INDENT
, gettext("units"),
13106 if (scf_tmpl_prop_description(prt
, NULL
, &buf
) > 0) {
13107 safe_printf("%s%s\n", TMPL_INDENT
, buf
);
13111 if (templates
== 2 && scf_tmpl_prop_visibility(prt
, &u_buf
) == 0)
13112 safe_printf("%s%s: %s\n", TMPL_INDENT
, gettext("visibility"),
13113 scf_tmpl_visibility_to_string(u_buf
));
13115 if (templates
== 2 && scf_tmpl_prop_cardinality(prt
, &min
, &max
) == 0) {
13116 safe_printf("%s%s: %" PRIu64
"\n", TMPL_INDENT
,
13117 gettext("minimum number of values"), min
);
13118 if (max
== ULLONG_MAX
) {
13119 safe_printf("%s%s: %s\n", TMPL_INDENT
,
13120 gettext("maximum number of values"),
13121 gettext("unlimited"));
13123 safe_printf("%s%s: %" PRIu64
"\n", TMPL_INDENT
,
13124 gettext("maximum number of values"), max
);
13128 if (templates
== 2 && scf_tmpl_prop_internal_seps(prt
, &values
) == 0) {
13129 for (i
= 0; i
< values
.value_count
; i
++) {
13131 safe_printf("%s%s:", TMPL_INDENT
,
13132 gettext("internal separators"));
13134 safe_printf(" \"%s\"", values
.values_as_strings
[i
]);
13139 if (templates
!= 2)
13143 list_values_tmpl(prt
, prop
);
13145 list_values_by_template(prt
);
13149 read_astring(scf_propertygroup_t
*pg
, const char *prop_name
)
13153 rv
= _scf_read_single_astring_from_pg(pg
, prop_name
);
13155 switch (scf_error()) {
13156 case SCF_ERROR_NOT_FOUND
:
13166 display_documentation(scf_iter_t
*iter
, scf_propertygroup_t
*pg
)
13174 doc_len
= strlen(SCF_PG_TM_DOC_PREFIX
);
13175 man_len
= strlen(SCF_PG_TM_MAN_PREFIX
);
13176 pg_name
= safe_malloc(max_scf_name_len
+ 1);
13177 while ((rv
= scf_iter_next_pg(iter
, pg
)) == 1) {
13178 if (scf_pg_get_name(pg
, pg_name
, max_scf_name_len
+ 1) == -1) {
13181 if (strncmp(pg_name
, SCF_PG_TM_DOC_PREFIX
, doc_len
) == 0) {
13182 /* Display doc_link and and uri */
13183 safe_printf("%s%s:\n", TMPL_INDENT
,
13184 gettext("doc_link"));
13185 text
= read_astring(pg
, SCF_PROPERTY_TM_NAME
);
13186 if (text
!= NULL
) {
13187 safe_printf("%s%s%s: %s\n", TMPL_INDENT
,
13188 TMPL_INDENT
, gettext("name"), text
);
13191 text
= read_astring(pg
, SCF_PROPERTY_TM_URI
);
13192 if (text
!= NULL
) {
13193 safe_printf("%s%s: %s\n", TMPL_INDENT_2X
,
13194 gettext("uri"), text
);
13197 } else if (strncmp(pg_name
, SCF_PG_TM_MAN_PREFIX
,
13199 /* Display manpage title, section and path */
13200 safe_printf("%s%s:\n", TMPL_INDENT
,
13201 gettext("manpage"));
13202 text
= read_astring(pg
, SCF_PROPERTY_TM_TITLE
);
13203 if (text
!= NULL
) {
13204 safe_printf("%s%s%s: %s\n", TMPL_INDENT
,
13205 TMPL_INDENT
, gettext("title"), text
);
13208 text
= read_astring(pg
, SCF_PROPERTY_TM_SECTION
);
13209 if (text
!= NULL
) {
13210 safe_printf("%s%s%s: %s\n", TMPL_INDENT
,
13211 TMPL_INDENT
, gettext("section"), text
);
13214 text
= read_astring(pg
, SCF_PROPERTY_TM_MANPATH
);
13215 if (text
!= NULL
) {
13216 safe_printf("%s%s%s: %s\n", TMPL_INDENT
,
13217 TMPL_INDENT
, gettext("manpath"), text
);
13230 list_entity_tmpl(int templates
)
13232 char *common_name
= NULL
;
13233 char *description
= NULL
;
13234 char *locale
= NULL
;
13236 scf_propertygroup_t
*pg
;
13237 scf_property_t
*prop
;
13241 if ((pg
= scf_pg_create(g_hndl
)) == NULL
||
13242 (prop
= scf_property_create(g_hndl
)) == NULL
||
13243 (val
= scf_value_create(g_hndl
)) == NULL
||
13244 (iter
= scf_iter_create(g_hndl
)) == NULL
)
13247 locale
= setlocale(LC_MESSAGES
, NULL
);
13249 if (get_pg(SCF_PG_TM_COMMON_NAME
, pg
) == 0) {
13250 common_name
= safe_malloc(max_scf_value_len
+ 1);
13252 /* Try both the current locale and the "C" locale. */
13253 if (scf_pg_get_property(pg
, locale
, prop
) == 0 ||
13254 (scf_error() == SCF_ERROR_NOT_FOUND
&&
13255 scf_pg_get_property(pg
, "C", prop
) == 0)) {
13256 if (prop_get_val(prop
, val
) == 0 &&
13257 scf_value_get_ustring(val
, common_name
,
13258 max_scf_value_len
+ 1) != -1) {
13259 safe_printf("%s%s: %s\n", TMPL_INDENT
,
13260 gettext("common name"), common_name
);
13266 * Do description, manpages, and doc links if templates == 2.
13268 if (templates
== 2) {
13269 /* Get the description. */
13270 if (get_pg(SCF_PG_TM_DESCRIPTION
, pg
) == 0) {
13271 description
= safe_malloc(max_scf_value_len
+ 1);
13273 /* Try both the current locale and the "C" locale. */
13274 if (scf_pg_get_property(pg
, locale
, prop
) == 0 ||
13275 (scf_error() == SCF_ERROR_NOT_FOUND
&&
13276 scf_pg_get_property(pg
, "C", prop
) == 0)) {
13277 if (prop_get_val(prop
, val
) == 0 &&
13278 scf_value_get_ustring(val
, description
,
13279 max_scf_value_len
+ 1) != -1) {
13280 safe_printf("%s%s: %s\n", TMPL_INDENT
,
13281 gettext("description"),
13287 /* Process doc_link & manpage elements. */
13288 if (cur_level
!= NULL
) {
13289 r
= scf_iter_snaplevel_pgs_typed(iter
, cur_level
,
13290 SCF_GROUP_TEMPLATE
);
13291 } else if (cur_inst
!= NULL
) {
13292 r
= scf_iter_instance_pgs_typed(iter
, cur_inst
,
13293 SCF_GROUP_TEMPLATE
);
13295 r
= scf_iter_service_pgs_typed(iter
, cur_svc
,
13296 SCF_GROUP_TEMPLATE
);
13299 display_documentation(iter
, pg
);
13305 scf_pg_destroy(pg
);
13306 scf_property_destroy(prop
);
13307 scf_value_destroy(val
);
13308 scf_iter_destroy(iter
);
13312 listtmpl(const char *pattern
, int templates
)
13314 scf_pg_tmpl_t
*pgt
;
13315 scf_prop_tmpl_t
*prt
;
13316 char *snapbuf
= NULL
;
13318 char *pg_name
= NULL
, *prop_name
= NULL
;
13319 ssize_t prop_name_size
;
13320 char *qual_prop_name
;
13324 if ((pgt
= scf_tmpl_pg_create(g_hndl
)) == NULL
||
13325 (prt
= scf_tmpl_prop_create(g_hndl
)) == NULL
)
13328 fmribuf
= safe_malloc(max_scf_name_len
+ 1);
13329 qual_prop_name
= safe_malloc(max_scf_name_len
+ 1);
13331 if (cur_snap
!= NULL
) {
13332 snapbuf
= safe_malloc(max_scf_name_len
+ 1);
13333 if (scf_snapshot_get_name(cur_snap
, snapbuf
,
13334 max_scf_name_len
+ 1) < 0)
13338 if (cur_inst
!= NULL
) {
13339 if (scf_instance_to_fmri(cur_inst
, fmribuf
,
13340 max_scf_name_len
+ 1) < 0)
13342 } else if (cur_svc
!= NULL
) {
13343 if (scf_service_to_fmri(cur_svc
, fmribuf
,
13344 max_scf_name_len
+ 1) < 0)
13349 /* If pattern is specified, we want to list only those items. */
13350 while (scf_tmpl_iter_pgs(pgt
, fmribuf
, snapbuf
, NULL
, 0) == 1) {
13352 if (pattern
== NULL
|| (scf_tmpl_pg_name(pgt
, &pg_name
) > 0 &&
13353 fnmatch(pattern
, pg_name
, 0) == 0)) {
13354 list_pg_tmpl(pgt
, NULL
, templates
);
13358 scf_tmpl_prop_reset(prt
);
13360 while (scf_tmpl_iter_props(pgt
, prt
, 0) == 0) {
13361 search_name
= NULL
;
13362 prop_name_size
= scf_tmpl_prop_name(prt
, &prop_name
);
13363 if ((prop_name_size
> 0) && (pg_name
!= NULL
)) {
13364 if (snprintf(qual_prop_name
,
13365 max_scf_name_len
+ 1, "%s/%s",
13366 pg_name
, prop_name
) >=
13367 max_scf_name_len
+ 1) {
13368 prop_name_size
= -1;
13370 search_name
= qual_prop_name
;
13373 if (listed
> 0 || pattern
== NULL
||
13374 (prop_name_size
> 0 &&
13375 fnmatch(pattern
, search_name
,
13376 FNM_PATHNAME
) == 0))
13377 list_prop_tmpl(prt
, NULL
, templates
);
13378 if (prop_name
!= NULL
) {
13383 if (pg_name
!= NULL
) {
13389 scf_tmpl_prop_destroy(prt
);
13390 scf_tmpl_pg_destroy(pgt
);
13393 free(qual_prop_name
);
13397 listprop(const char *pattern
, int only_pgs
, int templates
)
13399 scf_propertygroup_t
*pg
;
13400 scf_property_t
*prop
;
13401 scf_iter_t
*iter
, *piter
;
13402 char *pgnbuf
, *prnbuf
, *ppnbuf
;
13403 scf_pg_tmpl_t
*pgt
, *pgtp
;
13404 scf_prop_tmpl_t
*prt
;
13412 ssize_t pgnlen
, prnlen
, szret
;
13413 size_t max_len
= 0;
13415 if (cur_svc
== NULL
&& cur_inst
== NULL
) {
13416 semerr(emsg_entity_not_selected
);
13420 if ((pg
= scf_pg_create(g_hndl
)) == NULL
||
13421 (prop
= scf_property_create(g_hndl
)) == NULL
||
13422 (iter
= scf_iter_create(g_hndl
)) == NULL
||
13423 (piter
= scf_iter_create(g_hndl
)) == NULL
||
13424 (prt
= scf_tmpl_prop_create(g_hndl
)) == NULL
||
13425 (pgt
= scf_tmpl_pg_create(g_hndl
)) == NULL
)
13428 prnbuf
= safe_malloc(max_scf_name_len
+ 1);
13430 if (cur_level
!= NULL
)
13431 ret
= scf_iter_snaplevel_pgs(iter
, cur_level
);
13432 else if (cur_inst
!= NULL
)
13433 ret
= scf_iter_instance_pgs(iter
, cur_inst
);
13435 ret
= scf_iter_service_pgs(iter
, cur_svc
);
13441 * We want to only list items which match pattern, and we want the
13442 * second column to line up, so during the first pass we'll save
13443 * matching items, their names, and their templates in objects,
13444 * names, and tmpls, computing the maximum name length as we go,
13445 * and then we'll print them out.
13447 * Note: We always keep an extra slot available so the array can be
13452 objects
= safe_malloc(sizeof (*objects
));
13453 names
= safe_malloc(sizeof (*names
));
13454 tmpls
= safe_malloc(sizeof (*tmpls
));
13456 while ((ret
= scf_iter_next_pg(iter
, pg
)) == 1) {
13458 int print_props
= 0;
13461 pgnlen
= scf_pg_get_name(pg
, NULL
, 0);
13465 pgnbuf
= safe_malloc(pgnlen
+ 1);
13467 szret
= scf_pg_get_name(pg
, pgnbuf
, pgnlen
+ 1);
13470 assert(szret
<= pgnlen
);
13472 if (scf_tmpl_get_by_pg(pg
, pgt
, 0) == -1) {
13473 if (scf_error() != SCF_ERROR_NOT_FOUND
)
13480 if (pattern
== NULL
||
13481 fnmatch(pattern
, pgnbuf
, 0) == 0) {
13482 if (i
+1 >= allocd
) {
13484 objects
= realloc(objects
,
13485 sizeof (*objects
) * allocd
);
13487 realloc(names
, sizeof (*names
) * allocd
);
13488 tmpls
= realloc(tmpls
,
13489 sizeof (*tmpls
) * allocd
);
13490 if (objects
== NULL
|| names
== NULL
||
13492 uu_die(gettext("Out of memory"));
13504 if (pgnlen
> max_len
)
13513 pg
= scf_pg_create(g_hndl
);
13516 pgt
= scf_tmpl_pg_create(g_hndl
);
13525 if (scf_iter_pg_properties(piter
, pg
) != SCF_SUCCESS
)
13528 while ((ret
= scf_iter_next_property(piter
, prop
)) == 1) {
13529 prnlen
= scf_property_get_name(prop
, prnbuf
,
13530 max_scf_name_len
+ 1);
13534 /* Will prepend the property group name and a slash. */
13535 prnlen
+= pgnlen
+ 1;
13537 ppnbuf
= safe_malloc(prnlen
+ 1);
13539 if (snprintf(ppnbuf
, prnlen
+ 1, "%s/%s", pgnbuf
,
13541 uu_die("snprintf");
13543 if (pattern
== NULL
|| print_props
== 1 ||
13544 fnmatch(pattern
, ppnbuf
, 0) == 0) {
13545 if (i
+1 >= allocd
) {
13547 objects
= realloc(objects
,
13548 sizeof (*objects
) * allocd
);
13549 names
= realloc(names
,
13550 sizeof (*names
) * allocd
);
13551 tmpls
= realloc(tmpls
,
13552 sizeof (*tmpls
) * allocd
);
13553 if (objects
== NULL
|| names
== NULL
||
13562 if (pgtp
!= NULL
) {
13563 if (scf_tmpl_get_by_prop(pgt
, prnbuf
,
13566 SCF_ERROR_NOT_FOUND
)
13578 if (prnlen
> max_len
)
13581 prop
= scf_property_create(g_hndl
);
13582 prt
= scf_tmpl_prop_create(g_hndl
);
13589 pg
= scf_pg_create(g_hndl
);
13592 pgt
= scf_tmpl_pg_create(g_hndl
);
13603 scf_pg_destroy(pg
);
13604 scf_tmpl_pg_destroy(pgt
);
13605 scf_property_destroy(prop
);
13606 scf_tmpl_prop_destroy(prt
);
13608 for (i
= 0; objects
[i
] != NULL
; ++i
) {
13609 if (strchr(names
[i
], '/') == NULL
) {
13610 /* property group */
13611 pg
= (scf_propertygroup_t
*)objects
[i
];
13612 pgt
= (scf_pg_tmpl_t
*)tmpls
[i
];
13613 list_pg_info(pg
, names
[i
], max_len
);
13614 list_pg_tmpl(pgt
, pg
, templates
);
13616 scf_pg_destroy(pg
);
13618 scf_tmpl_pg_destroy(pgt
);
13621 prop
= (scf_property_t
*)objects
[i
];
13622 prt
= (scf_prop_tmpl_t
*)tmpls
[i
];
13623 list_prop_info(prop
, names
[i
], max_len
);
13624 list_prop_tmpl(prt
, prop
, templates
);
13626 scf_property_destroy(prop
);
13628 scf_tmpl_prop_destroy(prt
);
13638 lscf_listpg(const char *pattern
)
13642 listprop(pattern
, 1, 0);
13646 * Property group and property creation, setting, and deletion. setprop (and
13647 * its alias, addprop) can either create a property group of a given type, or
13648 * it can create or set a property to a given type and list of values.
13651 lscf_addpg(const char *name
, const char *type
, const char *flags
)
13653 scf_propertygroup_t
*pg
;
13661 if (cur_snap
!= NULL
) {
13662 semerr(emsg_cant_modify_snapshots
);
13666 if (cur_inst
== NULL
&& cur_svc
== NULL
) {
13667 semerr(emsg_entity_not_selected
);
13671 if (flags
!= NULL
) {
13672 for (cp
= flags
; *cp
!= '\0'; ++cp
) {
13675 flgs
|= SCF_PG_FLAG_NONPERSISTENT
;
13679 flgs
&= ~SCF_PG_FLAG_NONPERSISTENT
;
13683 semerr(gettext("Invalid property group flag "
13690 pg
= scf_pg_create(g_hndl
);
13694 if (cur_inst
!= NULL
)
13695 ret
= scf_instance_add_pg(cur_inst
, name
, type
, flgs
, pg
);
13697 ret
= scf_service_add_pg(cur_svc
, name
, type
, flgs
, pg
);
13699 if (ret
!= SCF_SUCCESS
) {
13700 switch (scf_error()) {
13701 case SCF_ERROR_INVALID_ARGUMENT
:
13702 semerr(gettext("Name, type, or flags are invalid.\n"));
13705 case SCF_ERROR_EXISTS
:
13706 semerr(gettext("Property group already exists.\n"));
13709 case SCF_ERROR_PERMISSION_DENIED
:
13710 semerr(emsg_permission_denied
);
13713 case SCF_ERROR_BACKEND_ACCESS
:
13714 semerr(gettext("Backend refused access.\n"));
13722 scf_pg_destroy(pg
);
13728 lscf_delpg(char *name
)
13732 if (cur_snap
!= NULL
) {
13733 semerr(emsg_cant_modify_snapshots
);
13737 if (cur_inst
== NULL
&& cur_svc
== NULL
) {
13738 semerr(emsg_entity_not_selected
);
13742 if (strchr(name
, '/') != NULL
) {
13743 semerr(emsg_invalid_pg_name
, name
);
13747 lscf_delprop(name
);
13751 * scf_delhash() is used to remove the property group related to the
13752 * hash entry for a specific manifest in the repository. pgname will be
13753 * constructed from the location of the manifest file. If deathrow isn't 0,
13754 * manifest file doesn't need to exist (manifest string will be used as
13755 * an absolute path).
13758 lscf_delhash(char *manifest
, int deathrow
)
13762 if (cur_snap
!= NULL
||
13763 cur_inst
!= NULL
|| cur_svc
!= NULL
) {
13764 warn(gettext("error, an entity is selected\n"));
13768 /* select smf/manifest */
13769 lscf_select(HASH_SVC
);
13771 * Translate the manifest file name to property name. In the deathrow
13772 * case, the manifest file does not need to exist.
13774 pgname
= mhash_filename_to_propname(manifest
,
13775 deathrow
? B_TRUE
: B_FALSE
);
13776 if (pgname
== NULL
) {
13777 warn(gettext("cannot resolve pathname for %s\n"), manifest
);
13780 /* delete the hash property name */
13781 lscf_delpg(pgname
);
13785 lscf_listprop(const char *pattern
)
13789 listprop(pattern
, 0, 0);
13793 lscf_setprop(const char *pgname
, const char *type
, const char *value
,
13794 const uu_list_t
*values
)
13796 scf_type_t ty
, current_ty
;
13797 scf_service_t
*svc
;
13798 scf_propertygroup_t
*pg
, *parent_pg
;
13799 scf_property_t
*prop
, *parent_prop
;
13800 scf_pg_tmpl_t
*pgt
;
13801 scf_prop_tmpl_t
*prt
;
13802 int ret
, result
= 0;
13803 scf_transaction_t
*tx
;
13804 scf_transaction_entry_t
*e
;
13806 uu_list_walk_t
*walk
;
13809 int req_quotes
= 0;
13813 if ((e
= scf_entry_create(g_hndl
)) == NULL
||
13814 (svc
= scf_service_create(g_hndl
)) == NULL
||
13815 (parent_pg
= scf_pg_create(g_hndl
)) == NULL
||
13816 (pg
= scf_pg_create(g_hndl
)) == NULL
||
13817 (parent_prop
= scf_property_create(g_hndl
)) == NULL
||
13818 (prop
= scf_property_create(g_hndl
)) == NULL
||
13819 (pgt
= scf_tmpl_pg_create(g_hndl
)) == NULL
||
13820 (prt
= scf_tmpl_prop_create(g_hndl
)) == NULL
||
13821 (tx
= scf_transaction_create(g_hndl
)) == NULL
)
13824 if (cur_snap
!= NULL
) {
13825 semerr(emsg_cant_modify_snapshots
);
13829 if (cur_inst
== NULL
&& cur_svc
== NULL
) {
13830 semerr(emsg_entity_not_selected
);
13834 propname
= strchr(pgname
, '/');
13835 if (propname
== NULL
) {
13836 semerr(gettext("Property names must contain a `/'.\n"));
13843 if (type
!= NULL
) {
13844 ty
= string_to_type(type
);
13845 if (ty
== SCF_TYPE_INVALID
) {
13846 semerr(gettext("Unknown type \"%s\".\n"), type
);
13851 if (cur_inst
!= NULL
)
13852 ret
= scf_instance_get_pg(cur_inst
, pgname
, pg
);
13854 ret
= scf_service_get_pg(cur_svc
, pgname
, pg
);
13855 if (ret
!= SCF_SUCCESS
) {
13856 switch (scf_error()) {
13857 case SCF_ERROR_NOT_FOUND
:
13858 semerr(emsg_no_such_pg
, pgname
);
13861 case SCF_ERROR_INVALID_ARGUMENT
:
13862 semerr(emsg_invalid_pg_name
, pgname
);
13872 if (scf_pg_update(pg
) == -1)
13874 if (scf_transaction_start(tx
, pg
) != SCF_SUCCESS
) {
13875 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
13878 semerr(emsg_permission_denied
);
13882 ret
= scf_pg_get_property(pg
, propname
, prop
);
13883 if (ret
== SCF_SUCCESS
) {
13884 if (scf_property_type(prop
, ¤t_ty
) != SCF_SUCCESS
)
13889 if (scf_transaction_property_change_type(tx
, e
,
13890 propname
, ty
) == -1)
13893 } else if (scf_error() == SCF_ERROR_NOT_FOUND
) {
13894 /* Infer the type, if possible. */
13895 if (type
== NULL
) {
13897 * First check if we're an instance and the
13898 * property is set on the service.
13900 if (cur_inst
!= NULL
&&
13901 scf_instance_get_parent(cur_inst
,
13903 scf_service_get_pg(cur_svc
, pgname
,
13905 scf_pg_get_property(parent_pg
, propname
,
13906 parent_prop
) == 0 &&
13907 scf_property_type(parent_prop
,
13908 ¤t_ty
) == 0) {
13911 /* Then check for a type set in a template. */
13912 } else if (scf_tmpl_get_by_pg(pg
, pgt
,
13914 scf_tmpl_get_by_prop(pgt
, propname
, prt
,
13916 scf_tmpl_prop_type(prt
, ¤t_ty
) == 0) {
13919 /* If type can't be inferred, fail. */
13921 semerr(gettext("Type required for new "
13926 if (scf_transaction_property_new(tx
, e
, propname
,
13929 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT
) {
13930 semerr(emsg_invalid_prop_name
, propname
);
13936 if (ty
== SCF_TYPE_ASTRING
|| ty
== SCF_TYPE_USTRING
)
13939 if (value
!= NULL
) {
13940 v
= string_to_value(value
, ty
, 0);
13945 ret
= scf_entry_add_value(e
, v
);
13946 assert(ret
== SCF_SUCCESS
);
13948 assert(values
!= NULL
);
13950 walk
= uu_list_walk_start((uu_list_t
*)values
,
13953 uu_die(gettext("Could not walk list"));
13955 for (sp
= uu_list_walk_next(walk
); sp
!= NULL
;
13956 sp
= uu_list_walk_next(walk
)) {
13957 v
= string_to_value(sp
->str
, ty
, req_quotes
);
13960 scf_entry_destroy_children(e
);
13964 ret
= scf_entry_add_value(e
, v
);
13965 assert(ret
== SCF_SUCCESS
);
13967 uu_list_walk_end(walk
);
13969 result
= scf_transaction_commit(tx
);
13971 scf_transaction_reset(tx
);
13972 scf_entry_destroy_children(e
);
13973 } while (result
== 0);
13976 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
13979 semerr(emsg_permission_denied
);
13993 scf_transaction_destroy(tx
);
13994 scf_entry_destroy(e
);
13995 scf_service_destroy(svc
);
13996 scf_pg_destroy(parent_pg
);
13997 scf_pg_destroy(pg
);
13998 scf_property_destroy(parent_prop
);
13999 scf_property_destroy(prop
);
14000 scf_tmpl_pg_destroy(pgt
);
14001 scf_tmpl_prop_destroy(prt
);
14007 lscf_delprop(char *pgn
)
14010 scf_propertygroup_t
*pg
;
14011 scf_transaction_t
*tx
;
14012 scf_transaction_entry_t
*e
;
14018 if (cur_snap
!= NULL
) {
14019 semerr(emsg_cant_modify_snapshots
);
14023 if (cur_inst
== NULL
&& cur_svc
== NULL
) {
14024 semerr(emsg_entity_not_selected
);
14028 pg
= scf_pg_create(g_hndl
);
14032 slash
= strchr(pgn
, '/');
14033 if (slash
== NULL
) {
14040 if (cur_inst
!= NULL
)
14041 ret
= scf_instance_get_pg(cur_inst
, pgn
, pg
);
14043 ret
= scf_service_get_pg(cur_svc
, pgn
, pg
);
14044 if (ret
!= SCF_SUCCESS
) {
14045 switch (scf_error()) {
14046 case SCF_ERROR_NOT_FOUND
:
14047 semerr(emsg_no_such_pg
, pgn
);
14050 case SCF_ERROR_INVALID_ARGUMENT
:
14051 semerr(emsg_invalid_pg_name
, pgn
);
14058 scf_pg_destroy(pg
);
14064 /* Try to delete the property group. */
14065 if (scf_pg_delete(pg
) != SCF_SUCCESS
) {
14066 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
14069 semerr(emsg_permission_denied
);
14074 scf_pg_destroy(pg
);
14078 e
= scf_entry_create(g_hndl
);
14079 tx
= scf_transaction_create(g_hndl
);
14082 if (scf_pg_update(pg
) == -1)
14084 if (scf_transaction_start(tx
, pg
) != SCF_SUCCESS
) {
14085 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
14088 semerr(emsg_permission_denied
);
14092 if (scf_transaction_property_delete(tx
, e
, pn
) != SCF_SUCCESS
) {
14093 if (scf_error() == SCF_ERROR_NOT_FOUND
) {
14094 semerr(gettext("No such property %s/%s.\n"),
14097 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT
) {
14098 semerr(emsg_invalid_prop_name
, pn
);
14105 ret
= scf_transaction_commit(tx
);
14108 scf_transaction_reset(tx
);
14109 } while (ret
== 0);
14112 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
14115 semerr(emsg_permission_denied
);
14120 scf_transaction_destroy(tx
);
14121 scf_entry_destroy(e
);
14122 scf_pg_destroy(pg
);
14126 * Property editing.
14130 write_edit_script(FILE *strm
)
14135 scf_propertygroup_t
*pg
;
14136 scf_property_t
*prop
;
14139 int ret
, result
= 0;
14140 scf_iter_t
*iter
, *piter
, *viter
;
14141 char *buf
, *tybuf
, *pname
;
14142 const char *emsg_write_error
;
14145 emsg_write_error
= gettext("Error writing temoprary file: %s.\n");
14149 if (cur_inst
!= NULL
) {
14150 fmrilen
= scf_instance_to_fmri(cur_inst
, NULL
, 0);
14153 fmribuf
= safe_malloc(fmrilen
+ 1);
14154 if (scf_instance_to_fmri(cur_inst
, fmribuf
, fmrilen
+ 1) < 0)
14157 assert(cur_svc
!= NULL
);
14158 fmrilen
= scf_service_to_fmri(cur_svc
, NULL
, 0);
14161 fmribuf
= safe_malloc(fmrilen
+ 1);
14162 if (scf_service_to_fmri(cur_svc
, fmribuf
, fmrilen
+ 1) < 0)
14166 if (fprintf(strm
, "select %s\n\n", fmribuf
) < 0) {
14167 warn(emsg_write_error
, strerror(errno
));
14175 if ((pg
= scf_pg_create(g_hndl
)) == NULL
||
14176 (prop
= scf_property_create(g_hndl
)) == NULL
||
14177 (val
= scf_value_create(g_hndl
)) == NULL
||
14178 (iter
= scf_iter_create(g_hndl
)) == NULL
||
14179 (piter
= scf_iter_create(g_hndl
)) == NULL
||
14180 (viter
= scf_iter_create(g_hndl
)) == NULL
)
14183 buf
= safe_malloc(max_scf_name_len
+ 1);
14184 tybuf
= safe_malloc(max_scf_pg_type_len
+ 1);
14185 pname
= safe_malloc(max_scf_name_len
+ 1);
14187 if (cur_inst
!= NULL
)
14188 ret
= scf_iter_instance_pgs(iter
, cur_inst
);
14190 ret
= scf_iter_service_pgs(iter
, cur_svc
);
14191 if (ret
!= SCF_SUCCESS
)
14194 while ((ret
= scf_iter_next_pg(iter
, pg
)) == 1) {
14201 if (scf_pg_get_name(pg
, buf
, max_scf_name_len
+ 1) < 0)
14204 if (scf_pg_get_type(pg
, tybuf
, max_scf_pg_type_len
+ 1) < 0)
14207 if (fprintf(strm
, "# Property group \"%s\"\n"
14209 "# addpg %s %s\n", buf
, buf
, buf
, tybuf
) < 0) {
14210 warn(emsg_write_error
, strerror(errno
));
14215 /* # setprop pg/prop = (values) */
14217 if (scf_iter_pg_properties(piter
, pg
) != SCF_SUCCESS
)
14220 while ((ret2
= scf_iter_next_property(piter
, prop
)) == 1) {
14227 if (scf_property_get_name(prop
, pname
,
14228 max_scf_name_len
+ 1) < 0)
14231 if (scf_property_type(prop
, &ty
) != 0)
14234 multiple
= prop_has_multiple_values(prop
, val
);
14236 if (fprintf(strm
, "# setprop %s/%s = %s: %s", buf
,
14237 pname
, scf_type_to_string(ty
), multiple
? "(" : "")
14239 warn(emsg_write_error
, strerror(errno
));
14244 (void) scf_type_base_type(ty
, &bty
);
14245 is_str
= (bty
== SCF_TYPE_ASTRING
);
14247 if (scf_iter_property_values(viter
, prop
) !=
14251 while ((ret3
= scf_iter_next_value(viter
, val
)) == 1) {
14255 buflen
= scf_value_get_as_string(val
, NULL
, 0);
14259 buf
= safe_malloc(buflen
+ 1);
14261 if (scf_value_get_as_string(val
, buf
,
14268 if (putc(' ', strm
) != ' ') {
14269 warn(emsg_write_error
,
14276 if ((is_str
&& multiple
) ||
14277 strpbrk(buf
, CHARS_TO_QUOTE
) != NULL
) {
14278 (void) putc('"', strm
);
14279 (void) quote_and_print(buf
, strm
, 1);
14280 (void) putc('"', strm
);
14282 if (ferror(strm
)) {
14283 warn(emsg_write_error
,
14289 if (fprintf(strm
, "%s", buf
) < 0) {
14290 warn(emsg_write_error
,
14300 scf_error() != SCF_ERROR_PERMISSION_DENIED
)
14303 /* Write closing paren if mult-value property */
14304 if ((multiple
&& putc(')', strm
) == EOF
) ||
14306 /* Write final newline */
14307 fputc('\n', strm
) == EOF
) {
14308 warn(emsg_write_error
, strerror(errno
));
14316 if (fputc('\n', strm
) == EOF
) {
14317 warn(emsg_write_error
, strerror(errno
));
14329 scf_iter_destroy(viter
);
14330 scf_iter_destroy(piter
);
14331 scf_iter_destroy(iter
);
14332 scf_value_destroy(val
);
14333 scf_property_destroy(prop
);
14334 scf_pg_destroy(pg
);
14337 if (fflush(strm
) != 0) {
14338 warn(emsg_write_error
, strerror(errno
));
14349 char *buf
, *editor
;
14352 char tempname
[] = TEMP_FILE_PATTERN
;
14356 if (cur_snap
!= NULL
) {
14357 semerr(emsg_cant_modify_snapshots
);
14361 if (cur_svc
== NULL
&& cur_inst
== NULL
) {
14362 semerr(emsg_entity_not_selected
);
14366 tmpfd
= mkstemp(tempname
);
14368 semerr(gettext("Could not create temporary file.\n"));
14372 (void) strcpy(tempfilename
, tempname
);
14374 tempfile
= fdopen(tmpfd
, "r+");
14375 if (tempfile
== NULL
) {
14376 warn(gettext("Could not create temporary file.\n"));
14377 if (close(tmpfd
) == -1)
14378 warn(gettext("Could not close temporary file: %s.\n"),
14386 if (write_edit_script(tempfile
) == -1) {
14391 editor
= getenv("EDITOR");
14392 if (editor
== NULL
)
14395 bufsz
= strlen(editor
) + 1 + strlen(tempname
) + 1;
14396 buf
= safe_malloc(bufsz
);
14398 if (snprintf(buf
, bufsz
, "%s %s", editor
, tempname
) < 0)
14399 uu_die(gettext("Error creating editor command"));
14401 if (system(buf
) == -1) {
14402 semerr(gettext("Could not launch editor %s: %s\n"), editor
,
14411 (void) engine_source(tempname
, est
->sc_cmd_flags
& SC_CMD_IACTIVE
);
14419 add_string(uu_list_t
*strlist
, const char *str
)
14421 string_list_t
*elem
;
14422 elem
= safe_malloc(sizeof (*elem
));
14423 uu_list_node_init(elem
, &elem
->node
, string_pool
);
14424 elem
->str
= safe_strdup(str
);
14425 if (uu_list_append(strlist
, elem
) != 0)
14426 uu_die(gettext("libuutil error: %s\n"),
14427 uu_strerror(uu_error()));
14431 remove_string(uu_list_t
*strlist
, const char *str
)
14433 uu_list_walk_t
*elems
;
14437 * Find the element that needs to be removed.
14439 elems
= uu_list_walk_start(strlist
, UU_DEFAULT
);
14440 while ((sp
= uu_list_walk_next(elems
)) != NULL
) {
14441 if (strcmp(sp
->str
, str
) == 0)
14444 uu_list_walk_end(elems
);
14447 * Returning 1 here as the value was not found, this
14448 * might not be an error. Leave it to the caller to
14455 uu_list_remove(strlist
, sp
);
14464 * Get all property values that don't match the given glob pattern,
14465 * if a pattern is specified.
14468 get_prop_values(scf_property_t
*prop
, uu_list_t
*values
,
14469 const char *pattern
)
14475 if ((iter
= scf_iter_create(g_hndl
)) == NULL
||
14476 (val
= scf_value_create(g_hndl
)) == NULL
)
14479 if (scf_iter_property_values(iter
, prop
) != 0)
14482 while ((ret
= scf_iter_next_value(iter
, val
)) == 1) {
14484 ssize_t vlen
, szret
;
14486 vlen
= scf_value_get_as_string(val
, NULL
, 0);
14490 buf
= safe_malloc(vlen
+ 1);
14492 szret
= scf_value_get_as_string(val
, buf
, vlen
+ 1);
14495 assert(szret
<= vlen
);
14497 if (pattern
== NULL
|| fnmatch(pattern
, buf
, 0) != 0)
14498 add_string(values
, buf
);
14506 scf_value_destroy(val
);
14507 scf_iter_destroy(iter
);
14511 lscf_setpropvalue(const char *pgname
, const char *type
,
14512 const char *arg
, int isadd
, int isnotfoundok
)
14515 scf_propertygroup_t
*pg
;
14516 scf_property_t
*prop
;
14517 int ret
, result
= 0;
14518 scf_transaction_t
*tx
;
14519 scf_transaction_entry_t
*e
;
14524 uu_list_walk_t
*walk
;
14525 void *cookie
= NULL
;
14526 char *pattern
= NULL
;
14530 if ((values
= uu_list_create(string_pool
, NULL
, 0)) == NULL
)
14531 uu_die(gettext("Could not create property list: %s\n"),
14532 uu_strerror(uu_error()));
14535 pattern
= safe_strdup(arg
);
14537 if ((e
= scf_entry_create(g_hndl
)) == NULL
||
14538 (pg
= scf_pg_create(g_hndl
)) == NULL
||
14539 (prop
= scf_property_create(g_hndl
)) == NULL
||
14540 (tx
= scf_transaction_create(g_hndl
)) == NULL
)
14543 if (cur_snap
!= NULL
) {
14544 semerr(emsg_cant_modify_snapshots
);
14548 if (cur_inst
== NULL
&& cur_svc
== NULL
) {
14549 semerr(emsg_entity_not_selected
);
14553 propname
= strchr(pgname
, '/');
14554 if (propname
== NULL
) {
14555 semerr(gettext("Property names must contain a `/'.\n"));
14562 if (type
!= NULL
) {
14563 ty
= string_to_type(type
);
14564 if (ty
== SCF_TYPE_INVALID
) {
14565 semerr(gettext("Unknown type \"%s\".\n"), type
);
14570 if (cur_inst
!= NULL
)
14571 ret
= scf_instance_get_pg(cur_inst
, pgname
, pg
);
14573 ret
= scf_service_get_pg(cur_svc
, pgname
, pg
);
14575 switch (scf_error()) {
14576 case SCF_ERROR_NOT_FOUND
:
14577 if (isnotfoundok
) {
14580 semerr(emsg_no_such_pg
, pgname
);
14585 case SCF_ERROR_INVALID_ARGUMENT
:
14586 semerr(emsg_invalid_pg_name
, pgname
);
14595 if (scf_pg_update(pg
) == -1)
14597 if (scf_transaction_start(tx
, pg
) != 0) {
14598 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
14601 semerr(emsg_permission_denied
);
14605 ret
= scf_pg_get_property(pg
, propname
, prop
);
14608 char *pat
= pattern
;
14610 if (scf_property_type(prop
, &ptype
) != 0)
14614 if (type
!= NULL
&& ptype
!= ty
) {
14615 semerr(gettext("Property \"%s\" is not "
14616 "of type \"%s\".\n"), propname
,
14623 size_t len
= strlen(pat
);
14624 if (len
> 0 && pat
[len
- 1] == '\"')
14625 pat
[len
- 1] = '\0';
14626 if (len
> 0 && pat
[0] == '\"')
14632 get_prop_values(prop
, values
, pat
);
14635 add_string(values
, arg
);
14637 if (scf_transaction_property_change(tx
, e
,
14638 propname
, ty
) == -1)
14640 } else if (scf_error() == SCF_ERROR_NOT_FOUND
) {
14642 if (type
== NULL
) {
14643 semerr(gettext("Type required "
14644 "for new properties.\n"));
14648 add_string(values
, arg
);
14650 if (scf_transaction_property_new(tx
, e
,
14651 propname
, ty
) == -1)
14653 } else if (isnotfoundok
) {
14657 semerr(gettext("No such property %s/%s.\n"),
14662 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT
) {
14663 semerr(emsg_invalid_prop_name
, propname
);
14669 walk
= uu_list_walk_start(values
, UU_DEFAULT
);
14671 uu_die(gettext("Could not walk property list.\n"));
14673 for (sp
= uu_list_walk_next(walk
); sp
!= NULL
;
14674 sp
= uu_list_walk_next(walk
)) {
14675 v
= string_to_value(sp
->str
, ty
, 0);
14678 scf_entry_destroy_children(e
);
14681 ret
= scf_entry_add_value(e
, v
);
14684 uu_list_walk_end(walk
);
14686 result
= scf_transaction_commit(tx
);
14688 scf_transaction_reset(tx
);
14689 scf_entry_destroy_children(e
);
14690 } while (result
== 0);
14693 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
14696 semerr(emsg_permission_denied
);
14705 scf_transaction_destroy(tx
);
14706 scf_entry_destroy(e
);
14707 scf_pg_destroy(pg
);
14708 scf_property_destroy(prop
);
14711 while ((sp
= uu_list_teardown(values
, &cookie
)) != NULL
) {
14716 uu_list_destroy(values
);
14726 lscf_addpropvalue(const char *pgname
, const char *type
, const char *value
)
14728 return (lscf_setpropvalue(pgname
, type
, value
, 1, 0));
14732 lscf_delpropvalue(const char *pgname
, const char *pattern
, int isnotfoundok
)
14734 return (lscf_setpropvalue(pgname
, NULL
, pattern
, 0, isnotfoundok
));
14738 * Look for a standard start method, first in the instance (if any),
14739 * then the service.
14741 static const char *
14742 start_method_name(int *in_instance
)
14744 scf_propertygroup_t
*pg
;
14747 scf_instance_t
*inst
= cur_inst
;
14749 if ((pg
= scf_pg_create(g_hndl
)) == NULL
)
14753 for (p
= start_method_names
; *p
!= NULL
; p
++) {
14755 ret
= scf_instance_get_pg(inst
, *p
, pg
);
14757 ret
= scf_service_get_pg(cur_svc
, *p
, pg
);
14760 size_t bufsz
= strlen(SCF_GROUP_METHOD
) + 1;
14761 char *buf
= safe_malloc(bufsz
);
14763 if ((ret
= scf_pg_get_type(pg
, buf
, bufsz
)) < 0) {
14767 if (strcmp(buf
, SCF_GROUP_METHOD
) != 0) {
14773 *in_instance
= (inst
!= NULL
);
14774 scf_pg_destroy(pg
);
14778 if (scf_error() == SCF_ERROR_NOT_FOUND
)
14784 if (inst
!= NULL
) {
14789 scf_pg_destroy(pg
);
14794 addpg(const char *name
, const char *type
)
14796 scf_propertygroup_t
*pg
;
14799 pg
= scf_pg_create(g_hndl
);
14803 if (cur_inst
!= NULL
)
14804 ret
= scf_instance_add_pg(cur_inst
, name
, type
, 0, pg
);
14806 ret
= scf_service_add_pg(cur_svc
, name
, type
, 0, pg
);
14809 switch (scf_error()) {
14810 case SCF_ERROR_EXISTS
:
14814 case SCF_ERROR_PERMISSION_DENIED
:
14815 semerr(emsg_permission_denied
);
14823 scf_pg_destroy(pg
);
14828 lscf_setenv(uu_list_t
*args
, int isunset
)
14833 char **argv
= NULL
;
14834 string_list_t
*slp
;
14837 int do_service
= 0;
14838 int do_instance
= 0;
14839 const char *method
= NULL
;
14840 const char *name
= NULL
;
14841 const char *value
= NULL
;
14842 scf_instance_t
*saved_cur_inst
= cur_inst
;
14846 argc
= uu_list_numnodes(args
);
14850 argv
= calloc(argc
+ 1, sizeof (char *));
14852 uu_die(gettext("Out of memory.\n"));
14854 for (slp
= uu_list_first(args
), i
= 0;
14856 slp
= uu_list_next(args
, slp
), ++i
)
14857 argv
[i
] = slp
->str
;
14864 ret
= getopt(argc
, argv
, "sim:");
14886 bad_error("getopt", ret
);
14891 if ((do_service
&& do_instance
) ||
14892 (isunset
&& argc
!= 1) ||
14893 (!isunset
&& argc
!= 2))
14896 name
= argv
[optind
];
14898 value
= argv
[optind
+ 1];
14900 if (cur_snap
!= NULL
) {
14901 semerr(emsg_cant_modify_snapshots
);
14906 if (cur_inst
== NULL
&& cur_svc
== NULL
) {
14907 semerr(emsg_entity_not_selected
);
14912 if (do_instance
&& cur_inst
== NULL
) {
14913 semerr(gettext("No instance is selected.\n"));
14918 if (do_service
&& cur_svc
== NULL
) {
14919 semerr(gettext("No service is selected.\n"));
14924 if (method
== NULL
) {
14925 if (do_instance
|| do_service
) {
14926 method
= "method_context";
14928 ret
= addpg("method_context",
14929 SCF_GROUP_FRAMEWORK
);
14935 method
= start_method_name(&in_instance
);
14936 if (method
== NULL
) {
14938 "Couldn't find start method; please "
14939 "specify a method with '-m'.\n"));
14947 scf_propertygroup_t
*pg
;
14952 if ((pg
= scf_pg_create(g_hndl
)) == NULL
)
14955 if (cur_inst
!= NULL
)
14956 ret
= scf_instance_get_pg(cur_inst
, method
, pg
);
14958 ret
= scf_service_get_pg(cur_svc
, method
, pg
);
14961 scf_pg_destroy(pg
);
14962 switch (scf_error()) {
14963 case SCF_ERROR_NOT_FOUND
:
14964 semerr(gettext("Couldn't find the method "
14965 "\"%s\".\n"), method
);
14968 case SCF_ERROR_INVALID_ARGUMENT
:
14969 semerr(gettext("Invalid method name \"%s\".\n"),
14978 bufsz
= strlen(SCF_GROUP_METHOD
) + 1;
14979 buf
= safe_malloc(bufsz
);
14981 if (scf_pg_get_type(pg
, buf
, bufsz
) < 0 ||
14982 strcmp(buf
, SCF_GROUP_METHOD
) != 0) {
14983 semerr(gettext("Property group \"%s\" is not of type "
14984 "\"method\".\n"), method
);
14987 scf_pg_destroy(pg
);
14992 scf_pg_destroy(pg
);
14995 prop
= uu_msprintf("%s/environment", method
);
14996 pattern
= uu_msprintf("%s=*", name
);
14998 if (prop
== NULL
|| pattern
== NULL
)
14999 uu_die(gettext("Out of memory.\n"));
15001 ret
= lscf_delpropvalue(prop
, pattern
, !isunset
);
15003 if (ret
== 0 && !isunset
) {
15006 prop
= uu_msprintf("%s/environment", method
);
15007 pattern
= uu_msprintf("%s=%s", name
, value
);
15008 if (prop
== NULL
|| pattern
== NULL
)
15009 uu_die(gettext("Out of memory.\n"));
15010 ret
= lscf_addpropvalue(prop
, "astring:", pattern
);
15016 cur_inst
= saved_cur_inst
;
15026 * Snapshot commands
15032 scf_snapshot_t
*snap
;
15039 if (cur_inst
== NULL
) {
15040 semerr(gettext("Instance not selected.\n"));
15044 if ((snap
= scf_snapshot_create(g_hndl
)) == NULL
||
15045 (iter
= scf_iter_create(g_hndl
)) == NULL
)
15048 if (scf_iter_instance_snapshots(iter
, cur_inst
) != SCF_SUCCESS
)
15051 nb
= safe_malloc(max_scf_name_len
+ 1);
15053 while ((r
= scf_iter_next_snapshot(iter
, snap
)) == 1) {
15054 if (scf_snapshot_get_name(snap
, nb
, max_scf_name_len
+ 1) < 0)
15063 scf_iter_destroy(iter
);
15064 scf_snapshot_destroy(snap
);
15068 lscf_selectsnap(const char *name
)
15070 scf_snapshot_t
*snap
;
15071 scf_snaplevel_t
*level
;
15075 if (cur_inst
== NULL
) {
15076 semerr(gettext("Instance not selected.\n"));
15080 if (cur_snap
!= NULL
) {
15081 if (name
!= NULL
) {
15082 char *cur_snap_name
;
15083 boolean_t nochange
;
15085 cur_snap_name
= safe_malloc(max_scf_name_len
+ 1);
15087 if (scf_snapshot_get_name(cur_snap
, cur_snap_name
,
15088 max_scf_name_len
+ 1) < 0)
15091 nochange
= strcmp(name
, cur_snap_name
) == 0;
15093 free(cur_snap_name
);
15099 unselect_cursnap();
15105 if ((snap
= scf_snapshot_create(g_hndl
)) == NULL
||
15106 (level
= scf_snaplevel_create(g_hndl
)) == NULL
)
15109 if (scf_instance_get_snapshot(cur_inst
, name
, snap
) !=
15111 switch (scf_error()) {
15112 case SCF_ERROR_INVALID_ARGUMENT
:
15113 semerr(gettext("Invalid name \"%s\".\n"), name
);
15116 case SCF_ERROR_NOT_FOUND
:
15117 semerr(gettext("No such snapshot \"%s\".\n"), name
);
15124 scf_snaplevel_destroy(level
);
15125 scf_snapshot_destroy(snap
);
15129 /* Load the snaplevels into our list. */
15130 cur_levels
= uu_list_create(snaplevel_pool
, NULL
, 0);
15131 if (cur_levels
== NULL
)
15132 uu_die(gettext("Could not create list: %s\n"),
15133 uu_strerror(uu_error()));
15135 if (scf_snapshot_get_base_snaplevel(snap
, level
) != SCF_SUCCESS
) {
15136 if (scf_error() != SCF_ERROR_NOT_FOUND
)
15139 semerr(gettext("Snapshot has no snaplevels.\n"));
15141 scf_snaplevel_destroy(level
);
15142 scf_snapshot_destroy(snap
);
15149 cur_elt
= safe_malloc(sizeof (*cur_elt
));
15150 uu_list_node_init(cur_elt
, &cur_elt
->list_node
,
15152 cur_elt
->sl
= level
;
15153 if (uu_list_insert_after(cur_levels
, NULL
, cur_elt
) != 0)
15154 uu_die(gettext("libuutil error: %s\n"),
15155 uu_strerror(uu_error()));
15157 level
= scf_snaplevel_create(g_hndl
);
15161 if (scf_snaplevel_get_next_snaplevel(cur_elt
->sl
,
15162 level
) != SCF_SUCCESS
) {
15163 if (scf_error() != SCF_ERROR_NOT_FOUND
)
15166 scf_snaplevel_destroy(level
);
15171 cur_elt
= uu_list_last(cur_levels
);
15172 cur_level
= cur_elt
->sl
;
15176 * Copies the properties & values in src to dst. Assumes src won't change.
15177 * Returns -1 if permission is denied, -2 if another transaction interrupts,
15178 * and 0 on success.
15180 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
15181 * property, if it is copied and has type boolean. (See comment in
15185 pg_copy(const scf_propertygroup_t
*src
, scf_propertygroup_t
*dst
,
15188 scf_transaction_t
*tx
;
15189 scf_iter_t
*iter
, *viter
;
15190 scf_property_t
*prop
;
15195 tx
= scf_transaction_create(g_hndl
);
15199 if (scf_transaction_start(tx
, dst
) != SCF_SUCCESS
) {
15200 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
15203 scf_transaction_destroy(tx
);
15208 if ((iter
= scf_iter_create(g_hndl
)) == NULL
||
15209 (prop
= scf_property_create(g_hndl
)) == NULL
||
15210 (viter
= scf_iter_create(g_hndl
)) == NULL
)
15213 nbuf
= safe_malloc(max_scf_name_len
+ 1);
15215 if (scf_iter_pg_properties(iter
, src
) != SCF_SUCCESS
)
15219 scf_transaction_entry_t
*e
;
15222 r
= scf_iter_next_property(iter
, prop
);
15228 e
= scf_entry_create(g_hndl
);
15232 if (scf_property_type(prop
, &ty
) != SCF_SUCCESS
)
15235 if (scf_property_get_name(prop
, nbuf
, max_scf_name_len
+ 1) < 0)
15238 if (scf_transaction_property_new(tx
, e
, nbuf
,
15239 ty
) != SCF_SUCCESS
)
15242 if ((enabled
== 0 || enabled
== 1) &&
15243 strcmp(nbuf
, scf_property_enabled
) == 0 &&
15244 ty
== SCF_TYPE_BOOLEAN
) {
15245 v
= scf_value_create(g_hndl
);
15249 scf_value_set_boolean(v
, enabled
);
15251 if (scf_entry_add_value(e
, v
) != 0)
15254 if (scf_iter_property_values(viter
, prop
) != 0)
15258 v
= scf_value_create(g_hndl
);
15262 r
= scf_iter_next_value(viter
, v
);
15266 scf_value_destroy(v
);
15270 if (scf_entry_add_value(e
, v
) != SCF_SUCCESS
)
15277 scf_iter_destroy(viter
);
15278 scf_property_destroy(prop
);
15279 scf_iter_destroy(iter
);
15281 r
= scf_transaction_commit(tx
);
15282 if (r
== -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED
)
15285 scf_transaction_destroy_children(tx
);
15286 scf_transaction_destroy(tx
);
15289 case 1: return (0);
15290 case 0: return (-2);
15291 case -1: return (-1);
15301 lscf_revert(const char *snapname
)
15303 scf_snapshot_t
*snap
, *prev
;
15304 scf_snaplevel_t
*level
, *nlevel
;
15306 scf_propertygroup_t
*pg
, *npg
;
15307 scf_property_t
*prop
;
15314 if (cur_inst
== NULL
) {
15315 semerr(gettext("Instance not selected.\n"));
15319 if (snapname
!= NULL
) {
15320 snap
= scf_snapshot_create(g_hndl
);
15324 if (scf_instance_get_snapshot(cur_inst
, snapname
, snap
) !=
15326 switch (scf_error()) {
15327 case SCF_ERROR_INVALID_ARGUMENT
:
15328 semerr(gettext("Invalid snapshot name "
15329 "\"%s\".\n"), snapname
);
15332 case SCF_ERROR_NOT_FOUND
:
15333 semerr(gettext("No such snapshot.\n"));
15340 scf_snapshot_destroy(snap
);
15344 if (cur_snap
!= NULL
) {
15347 semerr(gettext("No snapshot selected.\n"));
15352 if ((prev
= scf_snapshot_create(g_hndl
)) == NULL
||
15353 (level
= scf_snaplevel_create(g_hndl
)) == NULL
||
15354 (iter
= scf_iter_create(g_hndl
)) == NULL
||
15355 (pg
= scf_pg_create(g_hndl
)) == NULL
||
15356 (npg
= scf_pg_create(g_hndl
)) == NULL
||
15357 (prop
= scf_property_create(g_hndl
)) == NULL
||
15358 (val
= scf_value_create(g_hndl
)) == NULL
)
15361 nbuf
= safe_malloc(max_scf_name_len
+ 1);
15362 tbuf
= safe_malloc(max_scf_pg_type_len
+ 1);
15364 /* Take the "previous" snapshot before we blow away the properties. */
15365 if (scf_instance_get_snapshot(cur_inst
, snap_previous
, prev
) == 0) {
15366 if (_scf_snapshot_take_attach(cur_inst
, prev
) != 0)
15369 if (scf_error() != SCF_ERROR_NOT_FOUND
)
15372 if (_scf_snapshot_take_new(cur_inst
, snap_previous
, prev
) != 0)
15376 /* Save general/enabled, since we're probably going to replace it. */
15378 if (scf_instance_get_pg(cur_inst
, scf_pg_general
, pg
) == 0 &&
15379 scf_pg_get_property(pg
, scf_property_enabled
, prop
) == 0 &&
15380 scf_property_get_value(prop
, val
) == 0)
15381 (void) scf_value_get_boolean(val
, &enabled
);
15383 if (scf_snapshot_get_base_snaplevel(snap
, level
) != SCF_SUCCESS
) {
15384 if (scf_error() != SCF_ERROR_NOT_FOUND
)
15395 /* Clear the properties from the corresponding entity. */
15396 isinst
= snaplevel_is_instance(level
);
15399 r
= scf_iter_service_pgs(iter
, cur_svc
);
15401 r
= scf_iter_instance_pgs(iter
, cur_inst
);
15402 if (r
!= SCF_SUCCESS
)
15405 while ((r
= scf_iter_next_pg(iter
, pg
)) == 1) {
15406 if (scf_pg_get_flags(pg
, &flags
) != SCF_SUCCESS
)
15409 /* Skip nonpersistent pgs. */
15410 if (flags
& SCF_PG_FLAG_NONPERSISTENT
)
15413 if (scf_pg_delete(pg
) != SCF_SUCCESS
) {
15414 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
15417 semerr(emsg_permission_denied
);
15424 /* Copy the properties to the corresponding entity. */
15425 if (scf_iter_snaplevel_pgs(iter
, level
) != SCF_SUCCESS
)
15428 while ((r
= scf_iter_next_pg(iter
, pg
)) == 1) {
15429 if (scf_pg_get_name(pg
, nbuf
, max_scf_name_len
+ 1) < 0)
15432 if (scf_pg_get_type(pg
, tbuf
, max_scf_pg_type_len
+ 1) <
15436 if (scf_pg_get_flags(pg
, &flags
) != SCF_SUCCESS
)
15440 r
= scf_service_add_pg(cur_svc
, nbuf
, tbuf
,
15443 r
= scf_instance_add_pg(cur_inst
, nbuf
, tbuf
,
15445 if (r
!= SCF_SUCCESS
) {
15446 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
15449 semerr(emsg_permission_denied
);
15453 if ((enabled
== 0 || enabled
== 1) &&
15454 strcmp(nbuf
, scf_pg_general
) == 0)
15455 r
= pg_copy(pg
, npg
, enabled
);
15457 r
= pg_copy(pg
, npg
, 2);
15464 semerr(emsg_permission_denied
);
15469 "Interrupted by another change.\n"));
15479 /* Get next level. */
15480 nlevel
= scf_snaplevel_create(g_hndl
);
15481 if (nlevel
== NULL
)
15484 if (scf_snaplevel_get_next_snaplevel(level
, nlevel
) !=
15486 if (scf_error() != SCF_ERROR_NOT_FOUND
)
15489 scf_snaplevel_destroy(nlevel
);
15493 scf_snaplevel_destroy(level
);
15497 if (snapname
== NULL
) {
15498 lscf_selectsnap(NULL
);
15499 snap
= NULL
; /* cur_snap has been destroyed */
15505 scf_value_destroy(val
);
15506 scf_property_destroy(prop
);
15507 scf_pg_destroy(npg
);
15508 scf_pg_destroy(pg
);
15509 scf_iter_destroy(iter
);
15510 scf_snaplevel_destroy(level
);
15511 scf_snapshot_destroy(prev
);
15512 if (snap
!= cur_snap
)
15513 scf_snapshot_destroy(snap
);
15526 if (cur_inst
== NULL
) {
15527 semerr(gettext("Instance not selected.\n"));
15531 bufsz
= max_scf_fmri_len
+ 1;
15532 fmribuf
= safe_malloc(bufsz
);
15533 fmrilen
= scf_instance_to_fmri(cur_inst
, fmribuf
, bufsz
);
15536 if (scf_error() != SCF_ERROR_DELETED
)
15538 scf_instance_destroy(cur_inst
);
15540 warn(emsg_deleted
);
15543 assert(fmrilen
< bufsz
);
15545 r
= refresh_entity(0, cur_inst
, fmribuf
, NULL
, NULL
, NULL
);
15551 warn(gettext("Could not refresh %s "
15552 "(repository connection broken).\n"), fmribuf
);
15556 warn(emsg_deleted
);
15560 warn(gettext("Could not refresh %s "
15561 "(permission denied).\n"), fmribuf
);
15565 warn(gettext("Could not refresh %s "
15566 "(repository server out of resources).\n"),
15572 bad_error("refresh_entity", scf_error());
15579 * describe [-v] [-t] [pg/prop]
15582 lscf_describe(uu_list_t
*args
, int hasargs
)
15587 char **argv
= NULL
;
15588 string_list_t
*slp
;
15589 int do_verbose
= 0;
15590 int do_templates
= 0;
15591 char *pattern
= NULL
;
15595 if (hasargs
!= 0) {
15596 argc
= uu_list_numnodes(args
);
15600 argv
= calloc(argc
+ 1, sizeof (char *));
15602 uu_die(gettext("Out of memory.\n"));
15604 for (slp
= uu_list_first(args
), i
= 0;
15606 slp
= uu_list_next(args
, slp
), ++i
)
15607 argv
[i
] = slp
->str
;
15612 * We start optind = 0 because our list of arguments
15613 * starts at argv[0]
15618 ret
= getopt(argc
, argv
, "vt");
15635 bad_error("getopt", ret
);
15639 pattern
= argv
[optind
];
15642 if (cur_inst
== NULL
&& cur_svc
== NULL
) {
15643 semerr(emsg_entity_not_selected
);
15649 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15650 * output if their last parameter is set to 2. Less information is
15651 * produced if the parameter is set to 1.
15653 if (pattern
== NULL
) {
15654 if (do_verbose
== 1)
15655 list_entity_tmpl(2);
15657 list_entity_tmpl(1);
15660 if (do_templates
== 0) {
15661 if (do_verbose
== 1)
15662 listprop(pattern
, 0, 2);
15664 listprop(pattern
, 0, 1);
15666 if (do_verbose
== 1)
15667 listtmpl(pattern
, 2);
15669 listtmpl(pattern
, 1);
15682 #define PARAM_ACTIVE ((const char *) "active")
15683 #define PARAM_INACTIVE ((const char *) "inactive")
15684 #define PARAM_SMTP_TO ((const char *) "to")
15688 * Breaks down the string according to the tokens passed.
15689 * Caller is responsible for freeing array of pointers returned.
15690 * Returns NULL on failure
15693 tokenize(char *str
, const char *sep
)
15695 char *token
, *lasts
;
15697 int n
= 0; /* number of elements */
15698 int size
= 8; /* size of the array (initial) */
15700 buf
= safe_malloc(size
* sizeof (char *));
15702 for (token
= strtok_r(str
, sep
, &lasts
); token
!= NULL
;
15703 token
= strtok_r(NULL
, sep
, &lasts
), ++n
) {
15704 if (n
+ 1 >= size
) {
15706 if ((buf
= realloc(buf
, size
* sizeof (char *))) ==
15708 uu_die(gettext("Out of memory"));
15713 /* NULL terminate the pointer array */
15720 check_tokens(char **p
)
15726 int32_t t
= string_to_tset(*p
);
15729 if (is_fma_token(*p
) == 0)
15730 return (INVALID_TOKENS
);
15731 fma
= 1; /* this token is an fma event */
15736 if (smf
!= 0 && fma
== 1)
15737 return (MIXED_TOKENS
);
15744 return (FMA_TOKENS
);
15746 return (INVALID_TOKENS
);
15750 get_selection_str(char *fmri
, size_t sz
)
15752 if (g_hndl
== NULL
) {
15753 semerr(emsg_entity_not_selected
);
15755 } else if (cur_level
!= NULL
) {
15756 semerr(emsg_invalid_for_snapshot
);
15759 lscf_get_selection_str(fmri
, sz
);
15766 lscf_delnotify(const char *set
, int global
)
15768 char *str
= strdup(set
);
15775 uu_die(gettext("Out of memory.\n"));
15777 pgs
= tokenize(str
, ",");
15779 if ((tset
= check_tokens(pgs
)) > 0) {
15780 size_t sz
= max_scf_fmri_len
+ 1;
15782 fmri
= safe_malloc(sz
);
15784 (void) strlcpy(fmri
, SCF_INSTANCE_GLOBAL
, sz
);
15785 } else if (get_selection_str(fmri
, sz
) != 0) {
15789 if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS
, fmri
,
15790 tset
) != SCF_SUCCESS
) {
15791 uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15792 scf_strerror(scf_error()));
15794 } else if (tset
== FMA_TOKENS
) {
15796 semerr(gettext("Can't use option '-g' with FMA event "
15801 for (p
= pgs
; *p
; ++p
) {
15802 if (smf_notify_del_params(de_tag(*p
), NULL
, 0) !=
15804 uu_warn(gettext("Failed for \"%s\": %s\n"), *p
,
15805 scf_strerror(scf_error()));
15809 } else if (tset
== MIXED_TOKENS
) {
15810 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15813 uu_die(gettext("Invalid input.\n"));
15823 lscf_listnotify(const char *set
, int global
)
15825 char *str
= safe_strdup(set
);
15832 if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, 0) != 0)
15833 uu_die(gettext("Out of memory.\n"));
15835 pgs
= tokenize(str
, ",");
15837 if ((tset
= check_tokens(pgs
)) > 0) {
15838 size_t sz
= max_scf_fmri_len
+ 1;
15840 fmri
= safe_malloc(sz
);
15842 (void) strlcpy(fmri
, SCF_INSTANCE_GLOBAL
, sz
);
15843 } else if (get_selection_str(fmri
, sz
) != 0) {
15847 if (_scf_get_svc_notify_params(fmri
, nvl
, tset
, 1, 1) !=
15849 if (scf_error() != SCF_ERROR_NOT_FOUND
&&
15850 scf_error() != SCF_ERROR_DELETED
)
15852 "Failed listnotify: %s\n"),
15853 scf_strerror(scf_error()));
15857 listnotify_print(nvl
, NULL
);
15858 } else if (tset
== FMA_TOKENS
) {
15860 semerr(gettext("Can't use option '-g' with FMA event "
15865 for (p
= pgs
; *p
; ++p
) {
15866 if (_scf_get_fma_notify_params(de_tag(*p
), nvl
, 1) !=
15869 * if the preferences have just been deleted
15870 * or does not exist, just skip.
15872 if (scf_error() == SCF_ERROR_NOT_FOUND
||
15873 scf_error() == SCF_ERROR_DELETED
)
15876 "Failed listnotify: %s\n"),
15877 scf_strerror(scf_error()));
15880 listnotify_print(nvl
, re_tag(*p
));
15882 } else if (tset
== MIXED_TOKENS
) {
15883 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15886 semerr(gettext("Invalid input.\n"));
15897 strip_quotes_and_blanks(char *s
)
15900 char *end
= strrchr(s
, '\"');
15902 if (s
[0] == '\"' && end
!= NULL
&& *(end
+ 1) == '\0') {
15904 while (isblank(*start
))
15906 while (isblank(*(end
- 1)) && end
> start
) {
15916 set_active(nvlist_t
*mech
, const char *hier_part
)
15920 if (*hier_part
== '\0' || strcmp(hier_part
, PARAM_ACTIVE
) == 0) {
15922 } else if (strcmp(hier_part
, PARAM_INACTIVE
) == 0) {
15928 if (nvlist_add_boolean_value(mech
, PARAM_ACTIVE
, b
) != 0)
15929 uu_die(gettext("Out of memory.\n"));
15935 add_snmp_params(nvlist_t
*mech
, char *hier_part
)
15937 return (set_active(mech
, hier_part
));
15941 add_syslog_params(nvlist_t
*mech
, char *hier_part
)
15943 return (set_active(mech
, hier_part
));
15947 * add_mailto_paramas()
15948 * parse the hier_part of mailto URI
15949 * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
15950 * or mailto:{[active]|inactive}
15953 add_mailto_params(nvlist_t
*mech
, char *hier_part
)
15955 const char *tok
= "?&";
15962 * If the notification parametes are in the form of
15964 * malito:{[active]|inactive}
15966 * we set the property accordingly and return.
15967 * Otherwise, we make the notification type active and
15968 * process the hier_part.
15970 if (set_active(mech
, hier_part
) == 0)
15972 else if (set_active(mech
, PARAM_ACTIVE
) != 0)
15975 if ((p
= strtok_r(hier_part
, tok
, &lasts
)) == NULL
) {
15977 * sanity check: we only get here if hier_part = "", but
15978 * that's handled by set_active
15980 uu_die("strtok_r");
15983 if (nvlist_add_string(mech
, PARAM_SMTP_TO
, p
) != 0)
15984 uu_die(gettext("Out of memory.\n"));
15986 while ((p
= strtok_r(NULL
, tok
, &lasts
)) != NULL
)
15987 if ((param
= strtok_r(p
, "=", &val
)) != NULL
)
15988 if (nvlist_add_string(mech
, param
, val
) != 0)
15989 uu_die(gettext("Out of memory.\n"));
15995 uri_split(char *uri
, char **scheme
, char **hier_part
)
15999 if ((*scheme
= strtok_r(uri
, ":", hier_part
)) == NULL
||
16000 *hier_part
== NULL
) {
16001 semerr(gettext("'%s' is not an URI\n"), uri
);
16005 if ((r
= check_uri_scheme(*scheme
)) < 0) {
16006 semerr(gettext("Unkown URI scheme: %s\n"), *scheme
);
16014 process_uri(nvlist_t
*params
, char *uri
)
16022 if ((index
= uri_split(uri
, &scheme
, &hier_part
)) < 0)
16025 if (nvlist_alloc(&mech
, NV_UNIQUE_NAME
, 0) != 0)
16026 uu_die(gettext("Out of memory.\n"));
16030 /* error messages displayed by called function */
16031 r
= add_mailto_params(mech
, hier_part
);
16035 if ((r
= add_snmp_params(mech
, hier_part
)) != 0)
16036 semerr(gettext("Not valid parameters: '%s'\n"),
16041 if ((r
= add_syslog_params(mech
, hier_part
)) != 0)
16042 semerr(gettext("Not valid parameters: '%s'\n"),
16050 if (r
== 0 && nvlist_add_nvlist(params
, uri_scheme
[index
].protocol
,
16052 uu_die(gettext("Out of memory.\n"));
16059 set_params(nvlist_t
*params
, char **p
)
16065 uu_die("set_params");
16068 uri
= strip_quotes_and_blanks(*p
);
16069 if (process_uri(params
, uri
) != 0)
16079 setnotify(const char *e
, char **p
, int global
)
16081 char *str
= safe_strdup(e
);
16085 nvlist_t
*nvl
, *params
;
16088 if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, 0) != 0 ||
16089 nvlist_alloc(¶ms
, NV_UNIQUE_NAME
, 0) != 0 ||
16090 nvlist_add_uint32(nvl
, SCF_NOTIFY_NAME_VERSION
,
16091 SCF_NOTIFY_PARAMS_VERSION
) != 0)
16092 uu_die(gettext("Out of memory.\n"));
16094 events
= tokenize(str
, ",");
16096 if ((tset
= check_tokens(events
)) > 0) {
16097 /* SMF state transitions parameters */
16098 size_t sz
= max_scf_fmri_len
+ 1;
16100 fmri
= safe_malloc(sz
);
16102 (void) strlcpy(fmri
, SCF_INSTANCE_GLOBAL
, sz
);
16103 } else if (get_selection_str(fmri
, sz
) != 0) {
16107 if (nvlist_add_string(nvl
, SCF_NOTIFY_NAME_FMRI
, fmri
) != 0 ||
16108 nvlist_add_int32(nvl
, SCF_NOTIFY_NAME_TSET
, tset
) != 0)
16109 uu_die(gettext("Out of memory.\n"));
16111 if ((r
= set_params(params
, p
)) == 0) {
16112 if (nvlist_add_nvlist(nvl
, SCF_NOTIFY_PARAMS
,
16114 uu_die(gettext("Out of memory.\n"));
16116 if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS
,
16117 nvl
) != SCF_SUCCESS
) {
16120 "Failed smf_notify_set_params(3SCF): %s\n"),
16121 scf_strerror(scf_error()));
16124 } else if (tset
== FMA_TOKENS
) {
16125 /* FMA event parameters */
16127 semerr(gettext("Can't use option '-g' with FMA event "
16132 if ((r
= set_params(params
, p
)) != 0)
16135 if (nvlist_add_nvlist(nvl
, SCF_NOTIFY_PARAMS
, params
) != 0)
16136 uu_die(gettext("Out of memory.\n"));
16139 if (smf_notify_set_params(de_tag(*events
), nvl
) !=
16142 "Failed smf_notify_set_params(3SCF) for "
16143 "event %s: %s\n"), *events
,
16144 scf_strerror(scf_error()));
16147 } else if (tset
== MIXED_TOKENS
) {
16148 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
16151 uu_die(gettext("Invalid input.\n"));
16156 nvlist_free(params
);
16164 lscf_setnotify(uu_list_t
*args
)
16167 char **argv
= NULL
;
16168 string_list_t
*slp
;
16175 if ((argc
= uu_list_numnodes(args
)) < 2)
16178 argv
= calloc(argc
+ 1, sizeof (char *));
16180 uu_die(gettext("Out of memory.\n"));
16182 for (slp
= uu_list_first(args
), i
= 0;
16184 slp
= uu_list_next(args
, slp
), ++i
)
16185 argv
[i
] = slp
->str
;
16189 if (strcmp(argv
[0], "-g") == 0) {
16199 ret
= setnotify(events
, p
, global
);
16211 * Creates a list of instance name strings associated with a service. If
16212 * wohandcrafted flag is set, get only instances that have a last-import
16213 * snapshot, instances that were imported via svccfg.
16216 create_instance_list(scf_service_t
*svc
, int wohandcrafted
)
16218 scf_snapshot_t
*snap
= NULL
;
16219 scf_instance_t
*inst
;
16220 scf_iter_t
*inst_iter
;
16221 uu_list_t
*instances
;
16225 inst_iter
= scf_iter_create(g_hndl
);
16226 inst
= scf_instance_create(g_hndl
);
16227 if (inst_iter
== NULL
|| inst
== NULL
) {
16228 uu_warn(gettext("Could not create instance or iterator\n"));
16232 if ((instances
= uu_list_create(string_pool
, NULL
, 0)) == NULL
)
16233 return (instances
);
16235 if (scf_iter_service_instances(inst_iter
, svc
) != 0) {
16236 switch (scf_error()) {
16237 case SCF_ERROR_CONNECTION_BROKEN
:
16238 case SCF_ERROR_DELETED
:
16239 uu_list_destroy(instances
);
16243 case SCF_ERROR_HANDLE_MISMATCH
:
16244 case SCF_ERROR_NOT_BOUND
:
16245 case SCF_ERROR_NOT_SET
:
16247 bad_error("scf_iter_service_instances", scf_error());
16251 instname
= safe_malloc(max_scf_name_len
+ 1);
16252 while ((r
= scf_iter_next_instance(inst_iter
, inst
)) != 0) {
16254 (void) uu_warn(gettext("Unable to iterate through "
16255 "instances to create instance list : %s\n"),
16256 scf_strerror(scf_error()));
16258 uu_list_destroy(instances
);
16264 * If the instance does not have a last-import snapshot
16265 * then do not add it to the list as it is a hand-crafted
16266 * instance that should not be managed.
16268 if (wohandcrafted
) {
16269 if (snap
== NULL
&&
16270 (snap
= scf_snapshot_create(g_hndl
)) == NULL
) {
16271 uu_warn(gettext("Unable to create snapshot "
16276 if (scf_instance_get_snapshot(inst
,
16277 snap_lastimport
, snap
) != 0) {
16278 switch (scf_error()) {
16279 case SCF_ERROR_NOT_FOUND
:
16280 case SCF_ERROR_DELETED
:
16283 case SCF_ERROR_CONNECTION_BROKEN
:
16284 uu_list_destroy(instances
);
16288 case SCF_ERROR_HANDLE_MISMATCH
:
16289 case SCF_ERROR_NOT_BOUND
:
16290 case SCF_ERROR_NOT_SET
:
16292 bad_error("scf_iter_service_instances",
16298 if (scf_instance_get_name(inst
, instname
,
16299 max_scf_name_len
+ 1) < 0) {
16300 switch (scf_error()) {
16301 case SCF_ERROR_NOT_FOUND
:
16304 case SCF_ERROR_CONNECTION_BROKEN
:
16305 case SCF_ERROR_DELETED
:
16306 uu_list_destroy(instances
);
16310 case SCF_ERROR_HANDLE_MISMATCH
:
16311 case SCF_ERROR_NOT_BOUND
:
16312 case SCF_ERROR_NOT_SET
:
16314 bad_error("scf_iter_service_instances",
16319 add_string(instances
, instname
);
16324 scf_snapshot_destroy(snap
);
16326 scf_instance_destroy(inst
);
16327 scf_iter_destroy(inst_iter
);
16329 return (instances
);
16333 * disable an instance but wait for the instance to
16334 * move out of the running state.
16336 * Returns 0 : if the instance did not disable
16337 * Returns non-zero : if the instance disabled.
16341 disable_instance(scf_instance_t
*instance
)
16344 int enabled
= 10000;
16346 if (inst_is_running(instance
)) {
16347 fmribuf
= safe_malloc(max_scf_name_len
+ 1);
16348 if (scf_instance_to_fmri(instance
, fmribuf
,
16349 max_scf_name_len
+ 1) < 0) {
16355 * If the instance cannot be disabled then return
16356 * failure to disable and let the caller decide
16357 * if that is of importance.
16359 if (smf_disable_instance(fmribuf
, 0) != 0) {
16365 if (!inst_is_running(instance
))
16368 (void) poll(NULL
, 0, 5);
16369 enabled
= enabled
- 5;
16379 * Function to compare two service_manifest structures.
16383 service_manifest_compare(const void *left
, const void *right
, void *unused
)
16385 service_manifest_t
*l
= (service_manifest_t
*)left
;
16386 service_manifest_t
*r
= (service_manifest_t
*)right
;
16389 rc
= strcmp(l
->servicename
, r
->servicename
);
16395 * Look for the provided service in the service to manifest
16396 * tree. If the service exists, and a manifest was provided
16397 * then add the manifest to that service. If the service
16398 * does not exist, then add the service and manifest to the
16401 * If the manifest is NULL, return the element if found. If
16402 * the service is not found return NULL.
16404 service_manifest_t
*
16405 find_add_svc_mfst(const char *svnbuf
, const char *mfst
)
16407 service_manifest_t elem
;
16408 service_manifest_t
*fnelem
;
16409 uu_avl_index_t marker
;
16411 elem
.servicename
= svnbuf
;
16412 fnelem
= uu_avl_find(service_manifest_tree
, &elem
, NULL
, &marker
);
16416 add_string(fnelem
->mfstlist
, strdup(mfst
));
16418 fnelem
= safe_malloc(sizeof (*fnelem
));
16419 fnelem
->servicename
= safe_strdup(svnbuf
);
16420 if ((fnelem
->mfstlist
=
16421 uu_list_create(string_pool
, NULL
, 0)) == NULL
)
16422 uu_die(gettext("Could not create property "
16423 "list: %s\n"), uu_strerror(uu_error()));
16425 add_string(fnelem
->mfstlist
, safe_strdup(mfst
));
16427 uu_avl_insert(service_manifest_tree
, fnelem
, marker
);
16435 * Create the service to manifest avl tree.
16437 * Walk each of the manifests currently installed in the supported
16438 * directories, /lib/svc/manifests and /var/svc/manifests. For
16439 * each of the manifests, inventory the services and add them to
16442 * Code that calls this function should make sure fileystem/minimal is online,
16443 * /var is available, since this function walks the /var/svc/manifest directory.
16446 create_manifest_tree(void)
16448 manifest_info_t
**entry
;
16449 manifest_info_t
**manifests
;
16450 uu_list_walk_t
*svcs
;
16453 char *dirs
[] = {LIBSVC_DIR
, VARSVC_DIR
, NULL
};
16456 if (service_manifest_pool
)
16460 * Create the list pool for the service manifest list
16462 service_manifest_pool
= uu_avl_pool_create("service_manifest",
16463 sizeof (service_manifest_t
),
16464 offsetof(service_manifest_t
, svcmfst_node
),
16465 service_manifest_compare
, UU_DEFAULT
);
16466 if (service_manifest_pool
== NULL
)
16467 uu_die(gettext("service_manifest pool creation failed: %s\n"),
16468 uu_strerror(uu_error()));
16473 service_manifest_tree
= uu_avl_create(service_manifest_pool
, NULL
,
16475 if (service_manifest_tree
== NULL
)
16476 uu_die(gettext("service_manifest tree creation failed: %s\n"),
16477 uu_strerror(uu_error()));
16480 * Walk the manifests adding the service(s) from each manifest.
16482 * If a service already exists add the manifest to the manifest
16483 * list for that service. This covers the case of a service that
16484 * is supported by multiple manifest files.
16486 for (c
= 0; dirs
[c
]; c
++) {
16487 status
= find_manifests(g_hndl
, dirs
[c
], &manifests
, CHECKEXT
);
16489 uu_warn(gettext("file tree walk of %s encountered "
16490 "error %s\n"), dirs
[c
], strerror(errno
));
16492 uu_avl_destroy(service_manifest_tree
);
16493 service_manifest_tree
= NULL
;
16498 * If a manifest that was in the list is not found
16499 * then skip and go to the next manifest file.
16501 if (manifests
!= NULL
) {
16502 for (entry
= manifests
; *entry
!= NULL
; entry
++) {
16503 b
= internal_bundle_new();
16504 if (lxml_get_bundle_file(b
, (*entry
)->mi_path
,
16505 SVCCFG_OP_IMPORT
) != 0) {
16506 internal_bundle_free(b
);
16510 svcs
= uu_list_walk_start(b
->sc_bundle_services
,
16512 if (svcs
== NULL
) {
16513 internal_bundle_free(b
);
16517 while ((mfsvc
= uu_list_walk_next(svcs
)) !=
16519 /* Add manifest to service */
16520 (void) find_add_svc_mfst(mfsvc
->sc_name
,
16521 (*entry
)->mi_path
);
16524 uu_list_walk_end(svcs
);
16525 internal_bundle_free(b
);
16528 free_manifest_array(manifests
);
16534 * Check the manifest history file to see
16535 * if the service was ever installed from
16536 * one of the supported directories.
16539 * -1 - if there's error reading manifest history file
16540 * 1 - if the service is not found
16541 * 0 - if the service is found
16544 check_mfst_history(const char *svcname
)
16547 caddr_t mfsthist_start
;
16552 fd
= open(MFSTHISTFILE
, O_RDONLY
);
16554 uu_warn(gettext("Unable to open the history file\n"));
16558 if (fstat(fd
, &st
) == -1) {
16559 uu_warn(gettext("Unable to stat the history file\n"));
16563 mfsthist_start
= mmap(0, st
.st_size
, PROT_READ
,
16564 MAP_PRIVATE
, fd
, 0);
16567 if (mfsthist_start
== MAP_FAILED
||
16568 *(mfsthist_start
+ st
.st_size
) != '\0') {
16569 (void) munmap(mfsthist_start
, st
.st_size
);
16574 * The manifest history file is a space delimited list
16575 * of service and instance to manifest linkage. Adding
16576 * a space to the end of the service name so to get only
16577 * the service that is being searched for.
16579 svnbuf
= uu_msprintf("%s ", svcname
);
16580 if (svnbuf
== NULL
)
16581 uu_die(gettext("Out of memory"));
16583 if (strstr(mfsthist_start
, svnbuf
) != NULL
)
16586 (void) munmap(mfsthist_start
, st
.st_size
);
16592 * Take down each of the instances in the service
16593 * and remove them, then delete the service.
16596 teardown_service(scf_service_t
*svc
, const char *svnbuf
)
16598 scf_instance_t
*instance
;
16602 safe_printf(gettext("Delete service %s as there are no "
16603 "supporting manifests\n"), svnbuf
);
16605 instance
= scf_instance_create(g_hndl
);
16606 iter
= scf_iter_create(g_hndl
);
16607 if (iter
== NULL
|| instance
== NULL
) {
16608 uu_warn(gettext("Unable to create supporting entities to "
16609 "teardown the service\n"));
16610 uu_warn(gettext("scf error is : %s\n"),
16611 scf_strerror(scf_error()));
16615 if (scf_iter_service_instances(iter
, svc
) != 0) {
16616 switch (scf_error()) {
16617 case SCF_ERROR_CONNECTION_BROKEN
:
16618 case SCF_ERROR_DELETED
:
16621 case SCF_ERROR_HANDLE_MISMATCH
:
16622 case SCF_ERROR_NOT_BOUND
:
16623 case SCF_ERROR_NOT_SET
:
16625 bad_error("scf_iter_service_instances",
16630 while ((r
= scf_iter_next_instance(iter
, instance
)) != 0) {
16632 uu_warn(gettext("Error - %s\n"),
16633 scf_strerror(scf_error()));
16637 (void) disable_instance(instance
);
16641 * Delete the service... forcing the deletion in case
16642 * any of the instances did not disable.
16644 (void) lscf_service_delete(svc
, 1);
16646 scf_instance_destroy(instance
);
16647 scf_iter_destroy(iter
);
16651 * Get the list of instances supported by the manifest
16654 * Return 0 if there are no instances.
16656 * Return -1 if there are errors attempting to collect instances.
16658 * Return the count of instances found if there are no errors.
16662 check_instance_support(char *mfstfile
, const char *svcname
,
16663 uu_list_t
*instances
)
16665 uu_list_walk_t
*svcs
, *insts
;
16668 entity_t
*mfsvc
, *mfinst
;
16673 b
= internal_bundle_new();
16675 if (lxml_get_bundle_file(b
, mfstfile
, SVCCFG_OP_IMPORT
) != 0) {
16677 * Unable to process the manifest file for
16678 * instance support, so just return as
16679 * don't want to remove instances that could
16680 * not be accounted for that might exist here.
16682 internal_bundle_free(b
);
16686 svcs
= uu_list_walk_start(b
->sc_bundle_services
, 0);
16687 if (svcs
== NULL
) {
16688 internal_bundle_free(b
);
16692 svcn
= svcname
+ (sizeof (SCF_FMRI_SVC_PREFIX
) - 1) +
16693 (sizeof (SCF_FMRI_SERVICE_PREFIX
) - 1);
16695 while ((mfsvc
= uu_list_walk_next(svcs
)) != NULL
) {
16696 if (strcmp(mfsvc
->sc_name
, svcn
) == 0)
16699 uu_list_walk_end(svcs
);
16701 if (mfsvc
== NULL
) {
16702 internal_bundle_free(b
);
16706 ilist
= mfsvc
->sc_u
.sc_service
.sc_service_instances
;
16707 if ((insts
= uu_list_walk_start(ilist
, 0)) == NULL
) {
16708 internal_bundle_free(b
);
16712 while ((mfinst
= uu_list_walk_next(insts
)) != NULL
) {
16714 * Remove the instance from the instances list.
16715 * The unaccounted for instances will be removed
16716 * from the service once all manifests are
16719 (void) remove_string(instances
,
16724 uu_list_walk_end(insts
);
16725 internal_bundle_free(b
);
16727 return (rminstcnt
);
16731 * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16732 * 'false' to indicate there's no manifest file(s) found for the service.
16735 svc_add_no_support(scf_service_t
*svc
)
16739 /* Add no support */
16741 if (addpg(SCF_PG_MANIFESTFILES
, SCF_GROUP_FRAMEWORK
))
16744 pname
= uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES
, SUPPORTPROP
);
16746 uu_die(gettext("Out of memory.\n"));
16748 (void) lscf_addpropvalue(pname
, "boolean:", "0");
16755 * This function handles all upgrade scenarios for a service that doesn't have
16756 * SCF_PG_MANIFESTFILES pg. The function creates and populates
16757 * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16758 * manifest(s) mapping. Manifests under supported directories are inventoried
16759 * and a property is added for each file that delivers configuration to the
16760 * service. A service that has no corresponding manifest files (deleted) are
16761 * removed from repository.
16763 * Unsupported services:
16765 * A service is considered unsupported if there is no corresponding manifest
16766 * in the supported directories for that service and the service isn't in the
16767 * history file list. The history file, MFSTHISTFILE, contains a list of all
16768 * services and instances that were delivered by Solaris before the introduction
16769 * of the SCF_PG_MANIFESTFILES property group. The history file also contains
16770 * the path to the manifest file that defined the service or instance.
16772 * Another type of unsupported services is 'handcrafted' services,
16773 * programmatically created services or services created by dependent entries
16774 * in other manifests. A handcrafted service is identified by its lack of any
16775 * instance containing last-import snapshot which is created during svccfg
16778 * This function sets a flag for unsupported services by setting services'
16779 * SCF_PG_MANIFESTFILES/support property to false.
16782 upgrade_svc_mfst_connection(scf_service_t
*svc
, const char *svcname
)
16784 service_manifest_t
*elem
;
16785 uu_list_walk_t
*mfwalk
;
16786 string_list_t
*mfile
;
16787 uu_list_t
*instances
;
16793 * Since there's no guarantee manifests under /var are available during
16794 * early import, don't perform any upgrade during early import.
16799 if (service_manifest_tree
== NULL
) {
16800 create_manifest_tree();
16804 * Find service's supporting manifest(s) after
16805 * stripping off the svc:/ prefix that is part
16806 * of the fmri that is not used in the service
16807 * manifest bundle list.
16809 sname
= svcname
+ strlen(SCF_FMRI_SVC_PREFIX
) +
16810 strlen(SCF_FMRI_SERVICE_PREFIX
);
16811 elem
= find_add_svc_mfst(sname
, NULL
);
16812 if (elem
== NULL
) {
16815 * A handcrafted service, one that has no instance containing
16816 * last-import snapshot, should get unsupported flag.
16818 instances
= create_instance_list(svc
, 1);
16819 if (instances
== NULL
) {
16820 uu_warn(gettext("Unable to create instance list %s\n"),
16825 if (uu_list_numnodes(instances
) == 0) {
16826 svc_add_no_support(svc
);
16831 * If the service is in the history file, and its supporting
16832 * manifests are not found, we can safely delete the service
16833 * because its manifests are removed from the system.
16835 * Services not found in the history file are not delivered by
16836 * Solaris and/or delivered outside supported directories, set
16837 * unsupported flag for these services.
16839 r
= check_mfst_history(svcname
);
16844 /* Set unsupported flag for service */
16845 svc_add_no_support(svc
);
16847 /* Delete the service */
16848 teardown_service(svc
, svcname
);
16855 * Walk through the list of manifests and add them
16858 * Create a manifestfiles pg and add the property.
16860 mfwalk
= uu_list_walk_start(elem
->mfstlist
, 0);
16861 if (mfwalk
== NULL
)
16865 r
= addpg(SCF_PG_MANIFESTFILES
, SCF_GROUP_FRAMEWORK
);
16871 while ((mfile
= uu_list_walk_next(mfwalk
)) != NULL
) {
16872 pname
= uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES
,
16873 mhash_filename_to_propname(mfile
->str
, 0));
16875 uu_die(gettext("Out of memory.\n"));
16877 (void) lscf_addpropvalue(pname
, "astring:", mfile
->str
);
16880 uu_list_walk_end(mfwalk
);
16886 * Take a service and process the manifest file entires to see if
16887 * there is continued support for the service and instances. If
16888 * not cleanup as appropriate.
16890 * If a service does not have a manifest files entry flag it for
16891 * upgrade and return.
16893 * For each manifestfiles property check if the manifest file is
16894 * under the supported /lib/svc/manifest or /var/svc/manifest path
16895 * and if not then return immediately as this service is not supported
16896 * by the cleanup mechanism and should be ignored.
16898 * For each manifest file that is supported, check to see if the
16899 * file exists. If not then remove the manifest file property
16900 * from the service and the smf/manifest hash table. If the manifest
16901 * file exists then verify that it supports the instances that are
16902 * part of the service.
16904 * Once all manifest files have been accounted for remove any instances
16905 * that are no longer supported in the service.
16908 * 0 - Successfully processed the service
16909 * non-zero - failed to process the service
16911 * On most errors, will just return to wait and get the next service,
16912 * unless in case of unable to create the needed structures which is
16913 * most likely a fatal error that is not going to be recoverable.
16916 lscf_service_cleanup(void *act
, scf_walkinfo_t
*wip
)
16918 struct mpg_mfile
*mpntov
;
16919 struct mpg_mfile
**mpvarry
= NULL
;
16920 scf_service_t
*svc
;
16921 scf_propertygroup_t
*mpg
;
16922 scf_property_t
*mp
;
16925 scf_instance_t
*instance
;
16926 uu_list_walk_t
*insts
;
16927 uu_list_t
*instances
= NULL
;
16928 boolean_t activity
= (boolean_t
)act
;
16932 int mfstcnt
, rminstct
, instct
, mfstmax
;
16936 assert(g_hndl
!= NULL
);
16937 assert(wip
->svc
!= NULL
);
16938 assert(wip
->fmri
!= NULL
);
16942 mpg
= scf_pg_create(g_hndl
);
16943 mp
= scf_property_create(g_hndl
);
16944 mi
= scf_iter_create(g_hndl
);
16945 mv
= scf_value_create(g_hndl
);
16946 instance
= scf_instance_create(g_hndl
);
16948 if (mpg
== NULL
|| mp
== NULL
|| mi
== NULL
|| mv
== NULL
||
16949 instance
== NULL
) {
16950 uu_warn(gettext("Unable to create the supporting entities\n"));
16951 uu_warn(gettext("scf error is : %s\n"),
16952 scf_strerror(scf_error()));
16957 * Get the manifestfiles property group to be parsed for
16960 if (scf_service_get_pg(svc
, SCF_PG_MANIFESTFILES
, mpg
) != SCF_SUCCESS
) {
16961 switch (scf_error()) {
16962 case SCF_ERROR_NOT_FOUND
:
16963 upgrade_svc_mfst_connection(svc
, wip
->fmri
);
16965 case SCF_ERROR_DELETED
:
16966 case SCF_ERROR_CONNECTION_BROKEN
:
16969 case SCF_ERROR_HANDLE_MISMATCH
:
16970 case SCF_ERROR_NOT_BOUND
:
16971 case SCF_ERROR_NOT_SET
:
16973 bad_error("scf_iter_pg_properties",
16981 * Iterate through each of the manifestfiles properties
16982 * to determine what manifestfiles are available.
16984 * If a manifest file is supported then increment the
16985 * count and therefore the service is safe.
16987 if (scf_iter_pg_properties(mi
, mpg
) != 0) {
16988 switch (scf_error()) {
16989 case SCF_ERROR_DELETED
:
16990 case SCF_ERROR_CONNECTION_BROKEN
:
16993 case SCF_ERROR_HANDLE_MISMATCH
:
16994 case SCF_ERROR_NOT_BOUND
:
16995 case SCF_ERROR_NOT_SET
:
16997 bad_error("scf_iter_pg_properties",
17003 mfstmax
= MFSTFILE_MAX
;
17004 mpvarry
= safe_malloc(sizeof (struct mpg_file
*) * MFSTFILE_MAX
);
17005 while ((r
= scf_iter_next_property(mi
, mp
)) != 0) {
17007 bad_error(gettext("Unable to iterate through "
17008 "manifestfiles properties : %s"),
17011 mpntov
= safe_malloc(sizeof (struct mpg_mfile
));
17012 mpnbuf
= safe_malloc(max_scf_name_len
+ 1);
17013 mpvbuf
= safe_malloc(max_scf_value_len
+ 1);
17014 mpntov
->mpg
= mpnbuf
;
17015 mpntov
->mfile
= mpvbuf
;
17016 mpntov
->access
= 1;
17017 if (scf_property_get_name(mp
, mpnbuf
,
17018 max_scf_name_len
+ 1) < 0) {
17019 uu_warn(gettext("Unable to get manifest file "
17020 "property : %s\n"),
17021 scf_strerror(scf_error()));
17023 switch (scf_error()) {
17024 case SCF_ERROR_DELETED
:
17025 case SCF_ERROR_CONNECTION_BROKEN
:
17026 r
= scferror2errno(scf_error());
17029 case SCF_ERROR_HANDLE_MISMATCH
:
17030 case SCF_ERROR_NOT_BOUND
:
17031 case SCF_ERROR_NOT_SET
:
17033 bad_error("scf_iter_pg_properties",
17039 * The support property is a boolean value that indicates
17040 * if the service is supported for manifest file deletion.
17041 * Currently at this time there is no code that sets this
17042 * value to true. So while we could just let this be caught
17043 * by the support check below, in the future this by be set
17044 * to true and require processing. So for that, go ahead
17045 * and check here, and just return if false. Otherwise,
17046 * fall through expecting that other support checks will
17047 * handle the entries.
17049 if (strcmp(mpnbuf
, SUPPORTPROP
) == 0) {
17052 if (scf_property_get_value(mp
, mv
) != 0 ||
17053 scf_value_get_boolean(mv
, &support
) != 0) {
17054 uu_warn(gettext("Unable to get the manifest "
17055 "support value: %s\n"),
17056 scf_strerror(scf_error()));
17058 switch (scf_error()) {
17059 case SCF_ERROR_DELETED
:
17060 case SCF_ERROR_CONNECTION_BROKEN
:
17061 r
= scferror2errno(scf_error());
17064 case SCF_ERROR_HANDLE_MISMATCH
:
17065 case SCF_ERROR_NOT_BOUND
:
17066 case SCF_ERROR_NOT_SET
:
17068 bad_error("scf_iter_pg_properties",
17073 if (support
== B_FALSE
)
17078 * Anything with a manifest outside of the supported
17079 * directories, immediately bail out because that makes
17080 * this service non-supported. We don't even want
17081 * to do instance processing in this case because the
17082 * instances could be part of the non-supported manifest.
17084 if (strncmp(mpnbuf
, LIBSVC_PR
, strlen(LIBSVC_PR
)) != 0) {
17086 * Manifest is not in /lib/svc, so we need to
17087 * consider the /var/svc case.
17089 if (strncmp(mpnbuf
, VARSVC_PR
,
17090 strlen(VARSVC_PR
)) != 0 || IGNORE_VAR
) {
17092 * Either the manifest is not in /var/svc or
17093 * /var is not yet mounted. We ignore the
17094 * manifest either because it is not in a
17095 * standard location or because we cannot
17096 * currently access the manifest.
17103 * Get the value to of the manifest file for this entry
17104 * for access verification and instance support
17105 * verification if it still exists.
17107 * During Early Manifest Import if the manifest is in
17108 * /var/svc then it may not yet be available for checking
17109 * so we must determine if /var/svc is available. If not
17110 * then defer until Late Manifest Import to cleanup.
17112 if (scf_property_get_value(mp
, mv
) != 0) {
17113 uu_warn(gettext("Unable to get the manifest file "
17115 scf_strerror(scf_error()));
17117 switch (scf_error()) {
17118 case SCF_ERROR_DELETED
:
17119 case SCF_ERROR_CONNECTION_BROKEN
:
17120 r
= scferror2errno(scf_error());
17123 case SCF_ERROR_HANDLE_MISMATCH
:
17124 case SCF_ERROR_NOT_BOUND
:
17125 case SCF_ERROR_NOT_SET
:
17127 bad_error("scf_property_get_value",
17132 if (scf_value_get_astring(mv
, mpvbuf
,
17133 max_scf_value_len
+ 1) < 0) {
17134 uu_warn(gettext("Unable to get the manifest "
17136 scf_strerror(scf_error()));
17138 switch (scf_error()) {
17139 case SCF_ERROR_DELETED
:
17140 case SCF_ERROR_CONNECTION_BROKEN
:
17141 r
= scferror2errno(scf_error());
17144 case SCF_ERROR_HANDLE_MISMATCH
:
17145 case SCF_ERROR_NOT_BOUND
:
17146 case SCF_ERROR_NOT_SET
:
17148 bad_error("scf_value_get_astring",
17153 mpvarry
[mfstcnt
] = mpntov
;
17157 * Check for the need to reallocate array
17159 if (mfstcnt
>= (mfstmax
- 1)) {
17160 struct mpg_mfile
**newmpvarry
;
17162 mfstmax
= mfstmax
* 2;
17163 newmpvarry
= realloc(mpvarry
,
17164 sizeof (struct mpg_mfile
*) * mfstmax
);
17166 if (newmpvarry
== NULL
)
17169 mpvarry
= newmpvarry
;
17172 mpvarry
[mfstcnt
] = NULL
;
17175 for (index
= 0; mpvarry
[index
]; index
++) {
17176 mpntov
= mpvarry
[index
];
17179 * Check to see if the manifestfile is accessable, if so hand
17180 * this service and manifestfile off to be processed for
17181 * instance support.
17183 mpnbuf
= mpntov
->mpg
;
17184 mpvbuf
= mpntov
->mfile
;
17185 if (access(mpvbuf
, F_OK
) != 0) {
17186 mpntov
->access
= 0;
17189 /* Remove the entry from the service */
17191 pgpropbuf
= uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES
,
17193 if (pgpropbuf
== NULL
)
17194 uu_die(gettext("Out of memory.\n"));
17196 lscf_delprop(pgpropbuf
);
17199 uu_free(pgpropbuf
);
17204 * If mfstcnt is 0, none of the manifests that supported the service
17205 * existed so remove the service.
17207 if (mfstcnt
== 0) {
17208 teardown_service(svc
, wip
->fmri
);
17214 int nosvcsupport
= 0;
17217 * If the list of service instances is NULL then
17220 instances
= create_instance_list(svc
, 1);
17221 if (instances
== NULL
) {
17222 uu_warn(gettext("Unable to create instance list %s\n"),
17227 rminstct
= uu_list_numnodes(instances
);
17230 for (index
= 0; mpvarry
[index
]; index
++) {
17231 mpntov
= mpvarry
[index
];
17232 if (mpntov
->access
== 0)
17235 mpnbuf
= mpntov
->mpg
;
17236 mpvbuf
= mpntov
->mfile
;
17237 r
= check_instance_support(mpvbuf
, wip
->fmri
,
17246 if (instct
&& instct
== rminstct
&& nosvcsupport
== mfstcnt
) {
17247 teardown_service(svc
, wip
->fmri
);
17254 * If there are instances left on the instance list, then
17255 * we must remove them.
17257 if (instances
!= NULL
&& uu_list_numnodes(instances
)) {
17260 insts
= uu_list_walk_start(instances
, 0);
17261 while ((sp
= uu_list_walk_next(insts
)) != NULL
) {
17263 * Remove the instance from the instances list.
17265 safe_printf(gettext("Delete instance %s from "
17266 "service %s\n"), sp
->str
, wip
->fmri
);
17267 if (scf_service_get_instance(svc
, sp
->str
,
17268 instance
) != SCF_SUCCESS
) {
17269 (void) uu_warn("scf_error - %s\n",
17270 scf_strerror(scf_error()));
17275 (void) disable_instance(instance
);
17277 (void) lscf_instance_delete(instance
, 1);
17279 scf_instance_destroy(instance
);
17280 uu_list_walk_end(insts
);
17285 struct mpg_mfile
*fmpntov
;
17287 for (index
= 0; mpvarry
[index
]; index
++) {
17288 fmpntov
= mpvarry
[index
];
17289 if (fmpntov
->mpg
== mpnbuf
)
17291 free(fmpntov
->mpg
);
17293 if (fmpntov
->mfile
== mpvbuf
)
17295 free(fmpntov
->mfile
);
17297 if (fmpntov
== mpntov
)
17311 scf_pg_destroy(mpg
);
17312 scf_property_destroy(mp
);
17313 scf_iter_destroy(mi
);
17314 scf_value_destroy(mv
);
17320 * Take the service and search for the manifestfiles property
17321 * in each of the property groups. If the manifest file
17322 * associated with the property does not exist then remove
17323 * the property group.
17326 lscf_hash_cleanup()
17328 scf_service_t
*svc
;
17329 scf_scope_t
*scope
;
17330 scf_propertygroup_t
*pg
;
17331 scf_property_t
*prop
;
17334 char *pgname
= NULL
;
17335 char *mfile
= NULL
;
17338 svc
= scf_service_create(g_hndl
);
17339 scope
= scf_scope_create(g_hndl
);
17340 pg
= scf_pg_create(g_hndl
);
17341 prop
= scf_property_create(g_hndl
);
17342 val
= scf_value_create(g_hndl
);
17343 iter
= scf_iter_create(g_hndl
);
17344 if (pg
== NULL
|| prop
== NULL
|| val
== NULL
|| iter
== NULL
||
17345 svc
== NULL
|| scope
== NULL
) {
17346 uu_warn(gettext("Unable to create a property group, or "
17348 uu_warn("%s\n", pg
== NULL
? "pg is NULL" :
17350 uu_warn("%s\n", prop
== NULL
? "prop is NULL" :
17351 "prop is not NULL");
17352 uu_warn("%s\n", val
== NULL
? "val is NULL" :
17353 "val is not NULL");
17354 uu_warn("%s\n", iter
== NULL
? "iter is NULL" :
17355 "iter is not NULL");
17356 uu_warn("%s\n", svc
== NULL
? "svc is NULL" :
17357 "svc is not NULL");
17358 uu_warn("%s\n", scope
== NULL
? "scope is NULL" :
17359 "scope is not NULL");
17360 uu_warn(gettext("scf error is : %s\n"),
17361 scf_strerror(scf_error()));
17365 if (scf_handle_get_scope(g_hndl
, SCF_SCOPE_LOCAL
, scope
) != 0) {
17366 switch (scf_error()) {
17367 case SCF_ERROR_CONNECTION_BROKEN
:
17368 case SCF_ERROR_NOT_FOUND
:
17371 case SCF_ERROR_HANDLE_MISMATCH
:
17372 case SCF_ERROR_NOT_BOUND
:
17373 case SCF_ERROR_INVALID_ARGUMENT
:
17375 bad_error("scf_handle_get_scope", scf_error());
17379 if (scf_scope_get_service(scope
, HASH_SVC
, svc
) != 0) {
17380 uu_warn(gettext("Unable to process the hash service, %s\n"),
17385 pgname
= safe_malloc(max_scf_name_len
+ 1);
17386 mfile
= safe_malloc(max_scf_value_len
+ 1);
17388 if (scf_iter_service_pgs(iter
, svc
) != SCF_SUCCESS
) {
17389 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17390 scf_strerror(scf_error()));
17394 while ((r
= scf_iter_next_pg(iter
, pg
)) != 0) {
17398 if (scf_pg_get_name(pg
, pgname
, max_scf_name_len
+ 1) < 0) {
17399 switch (scf_error()) {
17400 case SCF_ERROR_DELETED
:
17403 case SCF_ERROR_CONNECTION_BROKEN
:
17404 return (ECONNABORTED
);
17406 case SCF_ERROR_NOT_SET
:
17407 case SCF_ERROR_NOT_BOUND
:
17409 bad_error("scf_pg_get_name", scf_error());
17413 if (strncmp(pgname
, VARSVC_PR
, strlen(VARSVC_PR
)) == 0)
17418 * If unable to get the property continue as this is an
17419 * entry that has no location to check against.
17421 if (scf_pg_get_property(pg
, MFSTFILEPR
, prop
) != SCF_SUCCESS
) {
17425 if (scf_property_get_value(prop
, val
) != SCF_SUCCESS
) {
17426 uu_warn(gettext("Unable to get value from %s\n"),
17429 switch (scf_error()) {
17430 case SCF_ERROR_DELETED
:
17431 case SCF_ERROR_CONSTRAINT_VIOLATED
:
17432 case SCF_ERROR_NOT_FOUND
:
17433 case SCF_ERROR_NOT_SET
:
17436 case SCF_ERROR_CONNECTION_BROKEN
:
17437 r
= scferror2errno(scf_error());
17440 case SCF_ERROR_HANDLE_MISMATCH
:
17441 case SCF_ERROR_NOT_BOUND
:
17443 bad_error("scf_property_get_value",
17448 if (scf_value_get_astring(val
, mfile
, max_scf_value_len
+ 1)
17450 uu_warn(gettext("Unable to get astring from %s : %s\n"),
17451 pgname
, scf_strerror(scf_error()));
17453 switch (scf_error()) {
17454 case SCF_ERROR_NOT_SET
:
17455 case SCF_ERROR_TYPE_MISMATCH
:
17459 bad_error("scf_value_get_astring", scf_error());
17463 if (access(mfile
, F_OK
) == 0)
17466 (void) scf_pg_delete(pg
);
17470 scf_scope_destroy(scope
);
17471 scf_service_destroy(svc
);
17472 scf_pg_destroy(pg
);
17473 scf_property_destroy(prop
);
17474 scf_value_destroy(val
);
17475 scf_iter_destroy(iter
);
17482 #ifndef NATIVE_BUILD
17484 CPL_MATCH_FN(complete_select
)
17486 const char *arg0
, *arg1
, *arg1end
;
17487 int word_start
, err
= 0, r
;
17493 arg0
= line
+ strspn(line
, " \t");
17494 assert(strncmp(arg0
, "select", sizeof ("select") - 1) == 0);
17496 arg1
= arg0
+ sizeof ("select") - 1;
17497 arg1
+= strspn(arg1
, " \t");
17498 word_start
= arg1
- line
;
17500 arg1end
= arg1
+ strcspn(arg1
, " \t");
17501 if (arg1end
< line
+ word_end
)
17504 len
= line
+ word_end
- arg1
;
17506 buf
= safe_malloc(max_scf_name_len
+ 1);
17508 if (cur_snap
!= NULL
) {
17510 } else if (cur_inst
!= NULL
) {
17512 } else if (cur_svc
!= NULL
) {
17513 scf_instance_t
*inst
;
17516 if ((inst
= scf_instance_create(g_hndl
)) == NULL
||
17517 (iter
= scf_iter_create(g_hndl
)) == NULL
)
17520 if (scf_iter_service_instances(iter
, cur_svc
) != 0)
17524 r
= scf_iter_next_instance(iter
, inst
);
17530 if (scf_instance_get_name(inst
, buf
,
17531 max_scf_name_len
+ 1) < 0)
17534 if (strncmp(buf
, arg1
, len
) == 0) {
17535 err
= cpl_add_completion(cpl
, line
, word_start
,
17536 word_end
, buf
+ len
, "", " ");
17542 scf_iter_destroy(iter
);
17543 scf_instance_destroy(inst
);
17547 scf_service_t
*svc
;
17550 assert(cur_scope
!= NULL
);
17552 if ((svc
= scf_service_create(g_hndl
)) == NULL
||
17553 (iter
= scf_iter_create(g_hndl
)) == NULL
)
17556 if (scf_iter_scope_services(iter
, cur_scope
) != 0)
17560 r
= scf_iter_next_service(iter
, svc
);
17566 if (scf_service_get_name(svc
, buf
,
17567 max_scf_name_len
+ 1) < 0)
17570 if (strncmp(buf
, arg1
, len
) == 0) {
17571 err
= cpl_add_completion(cpl
, line
, word_start
,
17572 word_end
, buf
+ len
, "", " ");
17578 scf_iter_destroy(iter
);
17579 scf_service_destroy(svc
);
17586 CPL_MATCH_FN(complete_command
)
17588 uint32_t scope
= 0;
17590 if (cur_snap
!= NULL
)
17592 else if (cur_inst
!= NULL
)
17594 else if (cur_svc
!= NULL
)
17599 return (scope
? add_cmd_matches(cpl
, line
, word_end
, scope
) : 0);
17601 #endif /* NATIVE_BUILD */