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 2015 Joyent, Inc.
25 * Copyright 2012 Milan Jurik. All rights reserved.
26 * Copyright 2017 RackTop Systems.
27 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
40 #include <libnvpair.h>
42 #include <libscf_priv.h>
55 #include <libxml/tree.h>
57 #include <sys/param.h>
63 #include "notify_params.h"
64 #include "manifest_hash.h"
65 #include "manifest_find.h"
67 /* The colon namespaces in each entity (each followed by a newline). */
68 #define COLON_NAMESPACES ":properties\n"
70 #define TEMP_FILE_PATTERN "/tmp/svccfg-XXXXXX"
72 /* These are characters which the lexer requires to be in double-quotes. */
73 #define CHARS_TO_QUOTE " \t\n\\>=\"()"
76 #define HASH_PG_TYPE "framework"
77 #define HASH_PG_FLAGS 0
78 #define HASH_PROP "md5sum"
81 * Indentation used in the output of the describe subcommand.
83 #define TMPL_VALUE_INDENT " "
84 #define TMPL_INDENT " "
85 #define TMPL_INDENT_2X " "
86 #define TMPL_CHOICE_INDENT " "
89 * Directory locations for manifests
91 #define VARSVC_DIR "/var/svc/manifest"
92 #define LIBSVC_DIR "/lib/svc/manifest"
93 #define VARSVC_PR "var_svc_manifest"
94 #define LIBSVC_PR "lib_svc_manifest"
95 #define MFSTFILEPR "manifestfile"
97 #define SUPPORTPROP "support"
99 #define MFSTHISTFILE "/lib/svc/share/mfsthistory"
101 #define MFSTFILE_MAX 16
104 * These are the classes of elements which may appear as children of service
105 * or instance elements in XML manifests.
108 xmlNodePtr create_default_instance
;
109 xmlNodePtr single_instance
;
110 xmlNodePtr restarter
;
111 xmlNodePtr dependencies
;
112 xmlNodePtr dependents
;
113 xmlNodePtr method_context
;
114 xmlNodePtr exec_methods
;
115 xmlNodePtr notify_params
;
116 xmlNodePtr property_groups
;
117 xmlNodePtr instances
;
118 xmlNodePtr stability
;
123 * Likewise for property_group elements.
126 xmlNodePtr stability
;
128 xmlNodePtr properties
;
132 * Likewise for template elements.
134 struct template_elts
{
135 xmlNodePtr common_name
;
136 xmlNodePtr description
;
137 xmlNodePtr documentation
;
141 * Likewise for type (for notification parameters) elements.
145 xmlNodePtr parameter
;
149 * This structure is for snaplevel lists. They are convenient because libscf
150 * only allows traversing snaplevels in one direction.
153 uu_list_node_t list_node
;
158 * This is used for communication between lscf_service_export and
162 const char *filename
;
167 * The service_manifest structure is used by the upgrade process
168 * to create a list of service to manifest linkages from the manifests
169 * in a set of given directories.
171 typedef struct service_manifest
{
172 const char *servicename
;
176 uu_avl_node_t svcmfst_node
;
177 } service_manifest_t
;
180 * Structure to track the manifest file property group
181 * and the manifest file associated with that property
182 * group. Also, a flag to keep the access once it has
191 const char * const scf_pg_general
= SCF_PG_GENERAL
;
192 const char * const scf_group_framework
= SCF_GROUP_FRAMEWORK
;
193 const char * const scf_property_enabled
= SCF_PROPERTY_ENABLED
;
194 const char * const scf_property_external
= "external";
196 const char * const snap_initial
= "initial";
197 const char * const snap_lastimport
= "last-import";
198 const char * const snap_previous
= "previous";
199 const char * const snap_running
= "running";
201 scf_handle_t
*g_hndl
= NULL
; /* only valid after lscf_prep_hndl() */
203 ssize_t max_scf_fmri_len
;
204 ssize_t max_scf_name_len
;
205 ssize_t max_scf_pg_type_len
;
206 ssize_t max_scf_value_len
;
207 static size_t max_scf_len
;
209 static scf_scope_t
*cur_scope
;
210 static scf_service_t
*cur_svc
= NULL
;
211 static scf_instance_t
*cur_inst
= NULL
;
212 static scf_snapshot_t
*cur_snap
= NULL
;
213 static scf_snaplevel_t
*cur_level
= NULL
;
215 static uu_list_pool_t
*snaplevel_pool
;
216 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
217 static uu_list_t
*cur_levels
;
218 static struct snaplevel
*cur_elt
; /* cur_elt->sl == cur_level */
220 static FILE *tempfile
= NULL
;
221 static char tempfilename
[sizeof (TEMP_FILE_PATTERN
)] = "";
223 static const char *emsg_entity_not_selected
;
224 static const char *emsg_permission_denied
;
225 static const char *emsg_create_xml
;
226 static const char *emsg_cant_modify_snapshots
;
227 static const char *emsg_invalid_for_snapshot
;
228 static const char *emsg_read_only
;
229 static const char *emsg_deleted
;
230 static const char *emsg_invalid_pg_name
;
231 static const char *emsg_invalid_prop_name
;
232 static const char *emsg_no_such_pg
;
233 static const char *emsg_fmri_invalid_pg_name
;
234 static const char *emsg_fmri_invalid_pg_name_type
;
235 static const char *emsg_pg_added
;
236 static const char *emsg_pg_changed
;
237 static const char *emsg_pg_deleted
;
238 static const char *emsg_pg_mod_perm
;
239 static const char *emsg_pg_add_perm
;
240 static const char *emsg_pg_del_perm
;
241 static const char *emsg_snap_perm
;
242 static const char *emsg_dpt_dangling
;
243 static const char *emsg_dpt_no_dep
;
245 static int li_only
= 0;
246 static int no_refresh
= 0;
248 /* how long in ns we should wait between checks for a pg */
249 static uint64_t pg_timeout
= 100 * (NANOSEC
/ MILLISEC
);
251 /* import globals, to minimize allocations */
252 static scf_scope_t
*imp_scope
= NULL
;
253 static scf_service_t
*imp_svc
= NULL
, *imp_tsvc
= NULL
;
254 static scf_instance_t
*imp_inst
= NULL
, *imp_tinst
= NULL
;
255 static scf_snapshot_t
*imp_snap
= NULL
, *imp_lisnap
= NULL
, *imp_tlisnap
= NULL
;
256 static scf_snapshot_t
*imp_rsnap
= NULL
;
257 static scf_snaplevel_t
*imp_snpl
= NULL
, *imp_rsnpl
= NULL
;
258 static scf_propertygroup_t
*imp_pg
= NULL
, *imp_pg2
= NULL
;
259 static scf_property_t
*imp_prop
= NULL
;
260 static scf_iter_t
*imp_iter
= NULL
;
261 static scf_iter_t
*imp_rpg_iter
= NULL
;
262 static scf_iter_t
*imp_up_iter
= NULL
;
263 static scf_transaction_t
*imp_tx
= NULL
; /* always reset this */
264 static char *imp_str
= NULL
;
265 static size_t imp_str_sz
;
266 static char *imp_tsname
= NULL
;
267 static char *imp_fe1
= NULL
; /* for fmri_equal() */
268 static char *imp_fe2
= NULL
;
269 static uu_list_t
*imp_deleted_dpts
= NULL
; /* pgroup_t's to refresh */
271 /* upgrade_dependents() globals */
272 static scf_instance_t
*ud_inst
= NULL
;
273 static scf_snaplevel_t
*ud_snpl
= NULL
;
274 static scf_propertygroup_t
*ud_pg
= NULL
;
275 static scf_propertygroup_t
*ud_cur_depts_pg
= NULL
;
276 static scf_propertygroup_t
*ud_run_dpts_pg
= NULL
;
277 static int ud_run_dpts_pg_set
= 0;
278 static scf_property_t
*ud_prop
= NULL
;
279 static scf_property_t
*ud_dpt_prop
= NULL
;
280 static scf_value_t
*ud_val
= NULL
;
281 static scf_iter_t
*ud_iter
= NULL
, *ud_iter2
= NULL
;
282 static scf_transaction_t
*ud_tx
= NULL
;
283 static char *ud_ctarg
= NULL
;
284 static char *ud_oldtarg
= NULL
;
285 static char *ud_name
= NULL
;
288 static scf_instance_t
*exp_inst
;
289 static scf_propertygroup_t
*exp_pg
;
290 static scf_property_t
*exp_prop
;
291 static scf_value_t
*exp_val
;
292 static scf_iter_t
*exp_inst_iter
, *exp_pg_iter
, *exp_prop_iter
, *exp_val_iter
;
293 static char *exp_str
;
294 static size_t exp_str_sz
;
296 /* cleanup globals */
297 static uu_avl_pool_t
*service_manifest_pool
= NULL
;
298 static uu_avl_t
*service_manifest_tree
= NULL
;
300 static void scfdie_lineno(int lineno
) __NORETURN
;
302 static char *start_method_names
[] = {
308 static struct uri_scheme
{
310 const char *protocol
;
312 { "mailto", "smtp" },
314 { "syslog", "syslog" },
317 #define URI_SCHEME_NUM ((sizeof (uri_scheme) / \
318 sizeof (struct uri_scheme)) - 1)
321 check_uri_scheme(const char *scheme
)
325 for (i
= 0; uri_scheme
[i
].scheme
!= NULL
; ++i
) {
326 if (strcmp(scheme
, uri_scheme
[i
].scheme
) == 0)
334 check_uri_protocol(const char *p
)
338 for (i
= 0; uri_scheme
[i
].protocol
!= NULL
; ++i
) {
339 if (strcmp(p
, uri_scheme
[i
].protocol
) == 0)
347 * For unexpected libscf errors.
351 static void scfdie(void) __NORETURN
;
356 scf_error_t err
= scf_error();
358 if (err
== SCF_ERROR_CONNECTION_BROKEN
)
359 uu_die(gettext("Repository connection broken. Exiting.\n"));
361 uu_die(gettext("Unexpected fatal libscf error: %s. Exiting.\n"),
367 #define scfdie() scfdie_lineno(__LINE__)
370 scfdie_lineno(int lineno
)
372 scf_error_t err
= scf_error();
374 if (err
== SCF_ERROR_CONNECTION_BROKEN
)
375 uu_die(gettext("Repository connection broken. Exiting.\n"));
377 uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
378 ": %s.\n"), lineno
, scf_strerror(err
));
386 warn(gettext("Unexpected libscf error: %s.\n"),
387 scf_strerror(scf_error()));
391 * Clear a field of a structure.
394 clear_int(void *a
, void *b
)
397 *(int *)((char *)a
+ (size_t)b
) = 0;
399 return (UU_WALK_NEXT
);
403 scferror2errno(scf_error_t err
)
406 case SCF_ERROR_BACKEND_ACCESS
:
409 case SCF_ERROR_BACKEND_READONLY
:
412 case SCF_ERROR_CONNECTION_BROKEN
:
413 return (ECONNABORTED
);
415 case SCF_ERROR_CONSTRAINT_VIOLATED
:
416 case SCF_ERROR_INVALID_ARGUMENT
:
419 case SCF_ERROR_DELETED
:
422 case SCF_ERROR_EXISTS
:
425 case SCF_ERROR_NO_MEMORY
:
428 case SCF_ERROR_NO_RESOURCES
:
431 case SCF_ERROR_NOT_FOUND
:
434 case SCF_ERROR_PERMISSION_DENIED
:
439 (void) fprintf(stderr
, "%s:%d: Unknown libscf error %d.\n",
440 __FILE__
, __LINE__
, err
);
442 (void) fprintf(stderr
, "Unknown libscf error %d.\n", err
);
450 entity_get_pg(void *ent
, int issvc
, const char *name
,
451 scf_propertygroup_t
*pg
)
454 return (scf_service_get_pg(ent
, name
, pg
));
456 return (scf_instance_get_pg(ent
, name
, pg
));
460 entity_destroy(void *ent
, int issvc
)
463 scf_service_destroy(ent
);
465 scf_instance_destroy(ent
);
469 get_pg(const char *pg_name
, scf_propertygroup_t
*pg
)
473 if (cur_level
!= NULL
)
474 ret
= scf_snaplevel_get_pg(cur_level
, pg_name
, pg
);
475 else if (cur_inst
!= NULL
)
476 ret
= scf_instance_get_pg(cur_inst
, pg_name
, pg
);
478 ret
= scf_service_get_pg(cur_svc
, pg_name
, pg
);
484 * Find a snaplevel in a snapshot. If get_svc is true, find the service
485 * snaplevel. Otherwise find the instance snaplevel.
489 * ECONNABORTED - repository connection broken
490 * ECANCELED - instance containing snap was deleted
491 * ENOENT - snap has no snaplevels
492 * - requested snaplevel not found
495 get_snaplevel(scf_snapshot_t
*snap
, int get_svc
, scf_snaplevel_t
*snpl
)
497 if (scf_snapshot_get_base_snaplevel(snap
, snpl
) != 0) {
498 switch (scf_error()) {
499 case SCF_ERROR_CONNECTION_BROKEN
:
500 case SCF_ERROR_DELETED
:
501 case SCF_ERROR_NOT_FOUND
:
502 return (scferror2errno(scf_error()));
504 case SCF_ERROR_HANDLE_MISMATCH
:
505 case SCF_ERROR_NOT_BOUND
:
506 case SCF_ERROR_NOT_SET
:
508 bad_error("scf_snapshot_get_base_snaplevel",
516 ssz
= scf_snaplevel_get_instance_name(snpl
, NULL
, 0);
521 switch (scf_error()) {
522 case SCF_ERROR_CONSTRAINT_VIOLATED
:
527 case SCF_ERROR_DELETED
:
528 case SCF_ERROR_CONNECTION_BROKEN
:
529 return (scferror2errno(scf_error()));
531 case SCF_ERROR_NOT_SET
:
532 case SCF_ERROR_NOT_BOUND
:
534 bad_error("scf_snaplevel_get_instance_name",
539 if (scf_snaplevel_get_next_snaplevel(snpl
, snpl
) != 0) {
540 switch (scf_error()) {
541 case SCF_ERROR_NOT_FOUND
:
542 case SCF_ERROR_CONNECTION_BROKEN
:
543 case SCF_ERROR_DELETED
:
544 return (scferror2errno(scf_error()));
546 case SCF_ERROR_HANDLE_MISMATCH
:
547 case SCF_ERROR_NOT_BOUND
:
548 case SCF_ERROR_NOT_SET
:
549 case SCF_ERROR_INVALID_ARGUMENT
:
551 bad_error("scf_snaplevel_get_next_snaplevel",
559 * If issvc is 0, take ent to be a pointer to an scf_instance_t. If it has
560 * a running snapshot, and that snapshot has an instance snaplevel, set pg to
561 * the property group named name in it. If it doesn't have a running
562 * snapshot, set pg to the instance's current property group named name.
564 * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
565 * its instances. If one has a running snapshot with a service snaplevel, set
566 * pg to the property group named name in it. If no such snaplevel could be
567 * found, set pg to the service's current property group named name.
569 * iter, inst, snap, and snpl are required scratch objects.
573 * ECONNABORTED - repository connection broken
574 * ECANCELED - ent was deleted
575 * ENOENT - no such property group
576 * EINVAL - name is an invalid property group name
577 * EBADF - found running snapshot is missing a snaplevel
580 entity_get_running_pg(void *ent
, int issvc
, const char *name
,
581 scf_propertygroup_t
*pg
, scf_iter_t
*iter
, scf_instance_t
*inst
,
582 scf_snapshot_t
*snap
, scf_snaplevel_t
*snpl
)
587 /* Search for an instance with a running snapshot. */
588 if (scf_iter_service_instances(iter
, ent
) != 0) {
589 switch (scf_error()) {
590 case SCF_ERROR_DELETED
:
591 case SCF_ERROR_CONNECTION_BROKEN
:
592 return (scferror2errno(scf_error()));
594 case SCF_ERROR_NOT_SET
:
595 case SCF_ERROR_NOT_BOUND
:
596 case SCF_ERROR_HANDLE_MISMATCH
:
598 bad_error("scf_iter_service_instances",
604 r
= scf_iter_next_instance(iter
, inst
);
606 if (scf_service_get_pg(ent
, name
, pg
) == 0)
609 switch (scf_error()) {
610 case SCF_ERROR_DELETED
:
611 case SCF_ERROR_NOT_FOUND
:
612 case SCF_ERROR_INVALID_ARGUMENT
:
613 case SCF_ERROR_CONNECTION_BROKEN
:
614 return (scferror2errno(scf_error()));
616 case SCF_ERROR_NOT_BOUND
:
617 case SCF_ERROR_HANDLE_MISMATCH
:
618 case SCF_ERROR_NOT_SET
:
620 bad_error("scf_service_get_pg",
625 switch (scf_error()) {
626 case SCF_ERROR_DELETED
:
627 case SCF_ERROR_CONNECTION_BROKEN
:
628 return (scferror2errno(scf_error()));
630 case SCF_ERROR_INVALID_ARGUMENT
:
631 case SCF_ERROR_NOT_SET
:
632 case SCF_ERROR_NOT_BOUND
:
633 case SCF_ERROR_HANDLE_MISMATCH
:
635 bad_error("scf_iter_next_instance",
640 if (scf_instance_get_snapshot(inst
, snap_running
,
644 switch (scf_error()) {
645 case SCF_ERROR_NOT_FOUND
:
646 case SCF_ERROR_DELETED
:
649 case SCF_ERROR_CONNECTION_BROKEN
:
650 return (ECONNABORTED
);
652 case SCF_ERROR_HANDLE_MISMATCH
:
653 case SCF_ERROR_INVALID_ARGUMENT
:
654 case SCF_ERROR_NOT_SET
:
655 case SCF_ERROR_NOT_BOUND
:
657 bad_error("scf_instance_get_snapshot",
662 if (scf_instance_get_snapshot(ent
, snap_running
, snap
) != 0) {
663 switch (scf_error()) {
664 case SCF_ERROR_NOT_FOUND
:
667 case SCF_ERROR_DELETED
:
668 case SCF_ERROR_CONNECTION_BROKEN
:
669 return (scferror2errno(scf_error()));
671 case SCF_ERROR_NOT_BOUND
:
672 case SCF_ERROR_HANDLE_MISMATCH
:
673 case SCF_ERROR_INVALID_ARGUMENT
:
674 case SCF_ERROR_NOT_SET
:
676 bad_error("scf_instance_get_snapshot",
680 if (scf_instance_get_pg(ent
, name
, pg
) == 0)
683 switch (scf_error()) {
684 case SCF_ERROR_DELETED
:
685 case SCF_ERROR_NOT_FOUND
:
686 case SCF_ERROR_INVALID_ARGUMENT
:
687 case SCF_ERROR_CONNECTION_BROKEN
:
688 return (scferror2errno(scf_error()));
690 case SCF_ERROR_NOT_BOUND
:
691 case SCF_ERROR_HANDLE_MISMATCH
:
692 case SCF_ERROR_NOT_SET
:
694 bad_error("scf_instance_get_pg", scf_error());
699 r
= get_snaplevel(snap
, issvc
, snpl
);
712 bad_error("get_snaplevel", r
);
715 if (scf_snaplevel_get_pg(snpl
, name
, pg
) == 0)
718 switch (scf_error()) {
719 case SCF_ERROR_DELETED
:
720 case SCF_ERROR_INVALID_ARGUMENT
:
721 case SCF_ERROR_CONNECTION_BROKEN
:
722 case SCF_ERROR_NOT_FOUND
:
723 return (scferror2errno(scf_error()));
725 case SCF_ERROR_NOT_BOUND
:
726 case SCF_ERROR_HANDLE_MISMATCH
:
727 case SCF_ERROR_NOT_SET
:
729 bad_error("scf_snaplevel_get_pg", scf_error());
735 * To be registered with atexit().
738 remove_tempfile(void)
742 if (tempfile
!= NULL
) {
743 if (fclose(tempfile
) == EOF
)
744 (void) warn(gettext("Could not close temporary file"));
748 if (tempfilename
[0] != '\0') {
750 ret
= remove(tempfilename
);
751 } while (ret
== -1 && errno
== EINTR
);
753 warn(gettext("Could not remove temporary file"));
754 tempfilename
[0] = '\0';
759 * Launch private svc.configd(8) for manipulating alternate repositories.
762 start_private_repository(engine_state_t
*est
)
765 struct door_info info
;
769 * 1. Create a temporary file for the door.
771 if (est
->sc_repo_doorname
!= NULL
)
772 free((void *)est
->sc_repo_doorname
);
774 est
->sc_repo_doorname
= tempnam(est
->sc_repo_doordir
, "scfdr");
775 if (est
->sc_repo_doorname
== NULL
)
776 uu_die(gettext("Could not acquire temporary filename"));
778 fd
= open(est
->sc_repo_doorname
, O_CREAT
| O_EXCL
| O_RDWR
, 0600);
780 uu_die(gettext("Could not create temporary file for "
781 "repository server"));
786 * 2. Launch a configd with that door, using the specified
789 if ((est
->sc_repo_pid
= fork()) == 0) {
790 (void) execlp(est
->sc_repo_server
, est
->sc_repo_server
, "-p",
791 "-d", est
->sc_repo_doorname
, "-r", est
->sc_repo_filename
,
793 uu_die(gettext("Could not execute %s"), est
->sc_repo_server
);
794 } else if (est
->sc_repo_pid
== -1)
795 uu_die(gettext("Attempt to fork failed"));
798 pid
= waitpid(est
->sc_repo_pid
, &stat
, 0);
799 } while (pid
== -1 && errno
== EINTR
);
802 uu_die(gettext("Could not waitpid() for repository server"));
804 if (!WIFEXITED(stat
)) {
805 uu_die(gettext("Repository server failed (status %d).\n"),
807 } else if (WEXITSTATUS(stat
) != 0) {
808 uu_die(gettext("Repository server failed (exit %d).\n"),
813 * See if it was successful by checking if the door is a door.
816 fd
= open(est
->sc_repo_doorname
, O_RDWR
);
818 uu_die(gettext("Could not open door \"%s\""),
819 est
->sc_repo_doorname
);
821 if (door_info(fd
, &info
) < 0)
822 uu_die(gettext("Unexpected door_info() error"));
825 warn(gettext("Could not close repository door"),
828 est
->sc_repo_pid
= info
.di_target
;
835 * In the case where we've launched a private svc.configd(8)
836 * instance, we must terminate our child and remove the temporary
839 if (est
->sc_repo_pid
> 0) {
840 (void) kill(est
->sc_repo_pid
, SIGTERM
);
841 (void) waitpid(est
->sc_repo_pid
, NULL
, 0);
842 (void) unlink(est
->sc_repo_doorname
);
844 est
->sc_repo_pid
= 0;
849 unselect_cursnap(void)
856 while ((cur_elt
= uu_list_teardown(cur_levels
, &cookie
)) != NULL
) {
857 scf_snaplevel_destroy(cur_elt
->sl
);
861 scf_snapshot_destroy(cur_snap
);
871 g_hndl
= scf_handle_create(SCF_VERSION
);
875 if (est
->sc_repo_filename
!= NULL
)
876 start_private_repository(est
);
878 if (est
->sc_repo_doorname
!= NULL
) {
879 scf_value_t
*repo_value
;
882 repo_value
= scf_value_create(g_hndl
);
883 if (repo_value
== NULL
)
886 ret
= scf_value_set_astring(repo_value
, est
->sc_repo_doorname
);
887 assert(ret
== SCF_SUCCESS
);
889 if (scf_handle_decorate(g_hndl
, "door_path", repo_value
) !=
893 scf_value_destroy(repo_value
);
896 if (scf_handle_bind(g_hndl
) != 0)
897 uu_die(gettext("Could not connect to repository server: %s.\n"),
898 scf_strerror(scf_error()));
900 cur_scope
= scf_scope_create(g_hndl
);
901 if (cur_scope
== NULL
)
904 if (scf_handle_get_local_scope(g_hndl
, cur_scope
) != 0)
909 repository_teardown(void)
911 if (g_hndl
!= NULL
) {
912 if (cur_snap
!= NULL
)
914 scf_instance_destroy(cur_inst
);
915 scf_service_destroy(cur_svc
);
916 scf_scope_destroy(cur_scope
);
917 scf_handle_destroy(g_hndl
);
927 lscf_set_repository(const char *repfile
, int force
)
929 repository_teardown();
931 if (est
->sc_repo_filename
!= NULL
) {
932 free((void *)est
->sc_repo_filename
);
933 est
->sc_repo_filename
= NULL
;
936 if ((force
== 0) && (access(repfile
, R_OK
) != 0)) {
938 * Repository file does not exist
939 * or has no read permission.
941 warn(gettext("Cannot access \"%s\": %s\n"),
942 repfile
, strerror(errno
));
944 est
->sc_repo_filename
= safe_strdup(repfile
);
953 if ((max_scf_fmri_len
= scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH
)) < 0 ||
954 (max_scf_name_len
= scf_limit(SCF_LIMIT_MAX_NAME_LENGTH
)) < 0 ||
955 (max_scf_pg_type_len
= scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH
)) <
957 (max_scf_value_len
= scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH
)) < 0)
960 max_scf_len
= max_scf_fmri_len
;
961 if (max_scf_name_len
> max_scf_len
)
962 max_scf_len
= max_scf_name_len
;
963 if (max_scf_pg_type_len
> max_scf_len
)
964 max_scf_len
= max_scf_pg_type_len
;
966 * When a value of type opaque is represented as a string, the
967 * string contains 2 characters for every byte of data. That is
968 * because the string contains the hex representation of the opaque
971 if (2 * max_scf_value_len
> max_scf_len
)
972 max_scf_len
= 2 * max_scf_value_len
;
974 if (atexit(remove_tempfile
) != 0)
975 uu_die(gettext("Could not register atexit() function"));
977 emsg_entity_not_selected
= gettext("An entity is not selected.\n");
978 emsg_permission_denied
= gettext("Permission denied.\n");
979 emsg_create_xml
= gettext("Could not create XML node.\n");
980 emsg_cant_modify_snapshots
= gettext("Cannot modify snapshots.\n");
981 emsg_invalid_for_snapshot
=
982 gettext("Invalid operation on a snapshot.\n");
983 emsg_read_only
= gettext("Backend read-only.\n");
984 emsg_deleted
= gettext("Current selection has been deleted.\n");
985 emsg_invalid_pg_name
=
986 gettext("Invalid property group name \"%s\".\n");
987 emsg_invalid_prop_name
= gettext("Invalid property name \"%s\".\n");
988 emsg_no_such_pg
= gettext("No such property group \"%s\".\n");
989 emsg_fmri_invalid_pg_name
= gettext("Service %s has property group "
990 "with invalid name \"%s\".\n");
991 emsg_fmri_invalid_pg_name_type
= gettext("Service %s has property "
992 "group with invalid name \"%s\" or type \"%s\".\n");
993 emsg_pg_added
= gettext("%s changed unexpectedly "
994 "(property group \"%s\" added).\n");
995 emsg_pg_changed
= gettext("%s changed unexpectedly "
996 "(property group \"%s\" changed).\n");
997 emsg_pg_deleted
= gettext("%s changed unexpectedly "
998 "(property group \"%s\" or an ancestor was deleted).\n");
999 emsg_pg_mod_perm
= gettext("Could not modify property group \"%s\" "
1000 "in %s (permission denied).\n");
1001 emsg_pg_add_perm
= gettext("Could not create property group \"%s\" "
1002 "in %s (permission denied).\n");
1003 emsg_pg_del_perm
= gettext("Could not delete property group \"%s\" "
1004 "in %s (permission denied).\n");
1005 emsg_snap_perm
= gettext("Could not take \"%s\" snapshot of %s "
1006 "(permission denied).\n");
1007 emsg_dpt_dangling
= gettext("Conflict upgrading %s (not importing "
1008 "new dependent \"%s\" because it already exists). Warning: The "
1009 "current dependent's target (%s) does not exist.\n");
1010 emsg_dpt_no_dep
= gettext("Conflict upgrading %s (not importing new "
1011 "dependent \"%s\" because it already exists). Warning: The "
1012 "current dependent's target (%s) does not have a dependency named "
1013 "\"%s\" as expected.\n");
1015 string_pool
= uu_list_pool_create("strings", sizeof (string_list_t
),
1016 offsetof(string_list_t
, node
), NULL
, 0);
1017 snaplevel_pool
= uu_list_pool_create("snaplevels",
1018 sizeof (struct snaplevel
), offsetof(struct snaplevel
, list_node
),
1024 prop_to_typestr(const scf_property_t
*prop
)
1028 if (scf_property_type(prop
, &ty
) != SCF_SUCCESS
)
1031 return (scf_type_to_string(ty
));
1035 string_to_type(const char *type
)
1037 size_t len
= strlen(type
);
1040 if (len
== 0 || type
[len
- 1] != ':')
1041 return (SCF_TYPE_INVALID
);
1043 buf
= (char *)alloca(len
+ 1);
1044 (void) strlcpy(buf
, type
, len
+ 1);
1047 return (scf_string_to_type(buf
));
1050 static scf_value_t
*
1051 string_to_value(const char *str
, scf_type_t ty
, boolean_t require_quotes
)
1057 v
= scf_value_create(g_hndl
);
1062 if (require_quotes
&&
1063 (len
< 2 || str
[0] != '\"' || str
[len
- 1] != '\"')) {
1064 semerr(gettext("Multiple string values or string values "
1065 "with spaces must be quoted with '\"'.\n"));
1066 scf_value_destroy(v
);
1070 nstr
= dup
= safe_strdup(str
);
1071 if (dup
[0] == '\"') {
1073 * Strip out the first and the last quote.
1075 dup
[len
- 1] = '\0';
1079 if (scf_value_set_from_string(v
, ty
, (const char *)nstr
) != 0) {
1080 assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT
);
1081 semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1082 scf_type_to_string(ty
), nstr
);
1083 scf_value_destroy(v
);
1091 * Print str to strm, quoting double-quotes and backslashes with backslashes.
1092 * Optionally append a comment prefix ('#') to newlines ('\n').
1095 quote_and_print(const char *str
, FILE *strm
, int commentnl
)
1099 for (cp
= str
; *cp
!= '\0'; ++cp
) {
1100 if (*cp
== '"' || *cp
== '\\')
1101 (void) putc('\\', strm
);
1103 (void) putc(*cp
, strm
);
1105 if (commentnl
&& *cp
== '\n') {
1106 (void) putc('#', strm
);
1110 return (ferror(strm
));
1114 * These wrappers around lowlevel functions provide consistent error checking
1118 pg_get_prop(scf_propertygroup_t
*pg
, const char *propname
, scf_property_t
*prop
)
1120 if (scf_pg_get_property(pg
, propname
, prop
) == SCF_SUCCESS
)
1123 if (scf_error() != SCF_ERROR_NOT_FOUND
)
1130 len
= scf_pg_to_fmri(pg
, NULL
, 0);
1134 fmri
= safe_malloc(len
+ 1);
1136 if (scf_pg_to_fmri(pg
, fmri
, len
+ 1) < 0)
1139 warn(gettext("Expected property %s of property group %s is "
1140 "missing.\n"), propname
, fmri
);
1149 prop_check_type(scf_property_t
*prop
, scf_type_t ty
)
1153 if (scf_property_type(prop
, &pty
) != SCF_SUCCESS
)
1164 len
= scf_property_to_fmri(prop
, NULL
, 0);
1168 fmri
= safe_malloc(len
+ 1);
1170 if (scf_property_to_fmri(prop
, fmri
, len
+ 1) < 0)
1173 tystr
= scf_type_to_string(ty
);
1177 warn(gettext("Property %s is not of expected type %s.\n"),
1187 prop_get_val(scf_property_t
*prop
, scf_value_t
*val
)
1191 if (scf_property_get_value(prop
, val
) == SCF_SUCCESS
)
1196 if (err
!= SCF_ERROR_NOT_FOUND
&&
1197 err
!= SCF_ERROR_CONSTRAINT_VIOLATED
&&
1198 err
!= SCF_ERROR_PERMISSION_DENIED
)
1205 len
= scf_property_to_fmri(prop
, NULL
, 0);
1209 fmri
= safe_malloc(len
+ 1);
1211 if (scf_property_to_fmri(prop
, fmri
, len
+ 1) < 0)
1214 if (err
== SCF_ERROR_NOT_FOUND
)
1215 emsg
= gettext("Property %s has no values; expected "
1217 else if (err
== SCF_ERROR_CONSTRAINT_VIOLATED
)
1218 emsg
= gettext("Property %s has multiple values; "
1221 emsg
= gettext("No permission to read property %s.\n");
1233 snaplevel_is_instance(const scf_snaplevel_t
*level
)
1235 if (scf_snaplevel_get_instance_name(level
, NULL
, 0) < 0) {
1236 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED
)
1245 * Decode FMRI into a service or instance, and put the result in *ep. If
1246 * memory cannot be allocated, return SCF_ERROR_NO_MEMORY. If the FMRI is
1247 * invalid, return SCF_ERROR_INVALID_ARGUMENT. If the FMRI does not specify
1248 * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED. If the entity cannot be
1249 * found, return SCF_ERROR_NOT_FOUND. Otherwise return SCF_ERROR_NONE, point
1250 * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1251 * whether *ep is a service.
1254 fmri_to_entity(scf_handle_t
*h
, const char *fmri
, void **ep
, int *isservice
)
1257 const char *sstr
, *istr
, *pgstr
;
1259 scf_instance_t
*inst
;
1261 fmri_copy
= strdup(fmri
);
1262 if (fmri_copy
== NULL
)
1263 return (SCF_ERROR_NO_MEMORY
);
1265 if (scf_parse_svc_fmri(fmri_copy
, NULL
, &sstr
, &istr
, &pgstr
, NULL
) !=
1268 return (SCF_ERROR_INVALID_ARGUMENT
);
1273 if (sstr
== NULL
|| pgstr
!= NULL
)
1274 return (SCF_ERROR_CONSTRAINT_VIOLATED
);
1277 svc
= scf_service_create(h
);
1279 return (SCF_ERROR_NO_MEMORY
);
1281 if (scf_handle_decode_fmri(h
, fmri
, NULL
, svc
, NULL
, NULL
, NULL
,
1282 SCF_DECODE_FMRI_EXACT
) != SCF_SUCCESS
) {
1283 if (scf_error() != SCF_ERROR_NOT_FOUND
)
1286 return (SCF_ERROR_NOT_FOUND
);
1292 inst
= scf_instance_create(h
);
1294 return (SCF_ERROR_NO_MEMORY
);
1296 if (scf_handle_decode_fmri(h
, fmri
, NULL
, NULL
, inst
, NULL
,
1297 NULL
, SCF_DECODE_FMRI_EXACT
) != SCF_SUCCESS
) {
1298 if (scf_error() != SCF_ERROR_NOT_FOUND
)
1301 return (SCF_ERROR_NOT_FOUND
);
1308 return (SCF_ERROR_NONE
);
1312 * Create the entity named by fmri. Place a pointer to its libscf handle in
1313 * *ep, and set or clear *isservicep if it is a service or an instance.
1315 * SCF_ERROR_NONE - success
1316 * SCF_ERROR_NO_MEMORY - scf_*_create() failed
1317 * SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1318 * SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1319 * SCF_ERROR_NOT_FOUND - no such scope
1320 * SCF_ERROR_PERMISSION_DENIED
1321 * SCF_ERROR_BACKEND_READONLY
1322 * SCF_ERROR_BACKEND_ACCESS
1325 create_entity(scf_handle_t
*h
, const char *fmri
, void **ep
, int *isservicep
)
1328 const char *scstr
, *sstr
, *istr
, *pgstr
;
1329 scf_scope_t
*scope
= NULL
;
1330 scf_service_t
*svc
= NULL
;
1331 scf_instance_t
*inst
= NULL
;
1334 fmri_copy
= safe_strdup(fmri
);
1336 if (scf_parse_svc_fmri(fmri_copy
, &scstr
, &sstr
, &istr
, &pgstr
, NULL
) !=
1339 return (SCF_ERROR_INVALID_ARGUMENT
);
1342 if (scstr
== NULL
|| sstr
== NULL
|| pgstr
!= NULL
) {
1344 return (SCF_ERROR_CONSTRAINT_VIOLATED
);
1349 if ((scope
= scf_scope_create(h
)) == NULL
||
1350 (svc
= scf_service_create(h
)) == NULL
||
1351 (inst
= scf_instance_create(h
)) == NULL
) {
1352 scfe
= SCF_ERROR_NO_MEMORY
;
1357 if (scf_handle_get_scope(h
, scstr
, scope
) != 0) {
1358 switch (scf_error()) {
1359 case SCF_ERROR_CONNECTION_BROKEN
:
1363 case SCF_ERROR_NOT_FOUND
:
1364 scfe
= SCF_ERROR_NOT_FOUND
;
1367 case SCF_ERROR_HANDLE_MISMATCH
:
1368 case SCF_ERROR_NOT_BOUND
:
1369 case SCF_ERROR_INVALID_ARGUMENT
:
1371 bad_error("scf_handle_get_scope", scf_error());
1376 if (scf_scope_get_service(scope
, sstr
, svc
) != 0) {
1377 switch (scf_error()) {
1378 case SCF_ERROR_CONNECTION_BROKEN
:
1382 case SCF_ERROR_DELETED
:
1385 case SCF_ERROR_NOT_FOUND
:
1388 case SCF_ERROR_HANDLE_MISMATCH
:
1389 case SCF_ERROR_INVALID_ARGUMENT
:
1390 case SCF_ERROR_NOT_BOUND
:
1391 case SCF_ERROR_NOT_SET
:
1393 bad_error("scf_scope_get_service", scf_error());
1396 if (scf_scope_add_service(scope
, sstr
, svc
) != 0) {
1397 switch (scf_error()) {
1398 case SCF_ERROR_CONNECTION_BROKEN
:
1402 case SCF_ERROR_DELETED
:
1405 case SCF_ERROR_PERMISSION_DENIED
:
1406 case SCF_ERROR_BACKEND_READONLY
:
1407 case SCF_ERROR_BACKEND_ACCESS
:
1411 case SCF_ERROR_HANDLE_MISMATCH
:
1412 case SCF_ERROR_INVALID_ARGUMENT
:
1413 case SCF_ERROR_NOT_BOUND
:
1414 case SCF_ERROR_NOT_SET
:
1416 bad_error("scf_scope_get_service", scf_error());
1422 scfe
= SCF_ERROR_NONE
;
1429 if (scf_service_get_instance(svc
, istr
, inst
) != 0) {
1430 switch (scf_error()) {
1431 case SCF_ERROR_CONNECTION_BROKEN
:
1435 case SCF_ERROR_DELETED
:
1438 case SCF_ERROR_NOT_FOUND
:
1441 case SCF_ERROR_HANDLE_MISMATCH
:
1442 case SCF_ERROR_INVALID_ARGUMENT
:
1443 case SCF_ERROR_NOT_BOUND
:
1444 case SCF_ERROR_NOT_SET
:
1446 bad_error("scf_service_get_instance", scf_error());
1449 if (scf_service_add_instance(svc
, istr
, inst
) != 0) {
1450 switch (scf_error()) {
1451 case SCF_ERROR_CONNECTION_BROKEN
:
1455 case SCF_ERROR_DELETED
:
1458 case SCF_ERROR_PERMISSION_DENIED
:
1459 case SCF_ERROR_BACKEND_READONLY
:
1460 case SCF_ERROR_BACKEND_ACCESS
:
1464 case SCF_ERROR_HANDLE_MISMATCH
:
1465 case SCF_ERROR_INVALID_ARGUMENT
:
1466 case SCF_ERROR_NOT_BOUND
:
1467 case SCF_ERROR_NOT_SET
:
1469 bad_error("scf_service_add_instance",
1475 scfe
= SCF_ERROR_NONE
;
1481 scf_instance_destroy(inst
);
1483 scf_service_destroy(svc
);
1484 scf_scope_destroy(scope
);
1490 * Create or update a snapshot of inst. snap is a required scratch object.
1494 * ECONNABORTED - repository connection broken
1495 * EPERM - permission denied
1496 * ENOSPC - configd is out of resources
1497 * ECANCELED - inst was deleted
1498 * -1 - unknown libscf error (message printed)
1501 take_snap(scf_instance_t
*inst
, const char *name
, scf_snapshot_t
*snap
)
1504 if (scf_instance_get_snapshot(inst
, name
, snap
) == 0) {
1505 if (_scf_snapshot_take_attach(inst
, snap
) != 0) {
1506 switch (scf_error()) {
1507 case SCF_ERROR_CONNECTION_BROKEN
:
1508 case SCF_ERROR_PERMISSION_DENIED
:
1509 case SCF_ERROR_NO_RESOURCES
:
1510 return (scferror2errno(scf_error()));
1512 case SCF_ERROR_NOT_SET
:
1513 case SCF_ERROR_INVALID_ARGUMENT
:
1515 bad_error("_scf_snapshot_take_attach",
1520 switch (scf_error()) {
1521 case SCF_ERROR_NOT_FOUND
:
1524 case SCF_ERROR_DELETED
:
1525 case SCF_ERROR_CONNECTION_BROKEN
:
1526 return (scferror2errno(scf_error()));
1528 case SCF_ERROR_HANDLE_MISMATCH
:
1529 case SCF_ERROR_NOT_BOUND
:
1530 case SCF_ERROR_INVALID_ARGUMENT
:
1531 case SCF_ERROR_NOT_SET
:
1533 bad_error("scf_instance_get_snapshot", scf_error());
1536 if (_scf_snapshot_take_new(inst
, name
, snap
) != 0) {
1537 switch (scf_error()) {
1538 case SCF_ERROR_EXISTS
:
1541 case SCF_ERROR_CONNECTION_BROKEN
:
1542 case SCF_ERROR_NO_RESOURCES
:
1543 case SCF_ERROR_PERMISSION_DENIED
:
1544 return (scferror2errno(scf_error()));
1550 case SCF_ERROR_NOT_SET
:
1551 case SCF_ERROR_INTERNAL
:
1552 case SCF_ERROR_INVALID_ARGUMENT
:
1553 case SCF_ERROR_HANDLE_MISMATCH
:
1554 bad_error("_scf_snapshot_take_new",
1564 refresh_running_snapshot(void *entity
)
1566 scf_snapshot_t
*snap
;
1569 if ((snap
= scf_snapshot_create(g_hndl
)) == NULL
)
1571 r
= take_snap(entity
, snap_running
, snap
);
1572 scf_snapshot_destroy(snap
);
1578 * Refresh entity. If isservice is zero, take entity to be an scf_instance_t *.
1579 * Otherwise take entity to be an scf_service_t * and refresh all of its child
1580 * instances. fmri is used for messages. inst, iter, and name_buf are used
1581 * for scratch space. Returns
1583 * ECONNABORTED - repository connection broken
1584 * ECANCELED - entity was deleted
1585 * EACCES - backend denied access
1586 * EPERM - permission denied
1587 * ENOSPC - repository server out of resources
1588 * -1 - _smf_refresh_instance_i() failed. scf_error() should be set.
1591 refresh_entity(int isservice
, void *entity
, const char *fmri
,
1592 scf_instance_t
*inst
, scf_iter_t
*iter
, char *name_buf
)
1599 * Let restarter handles refreshing and making new running
1600 * snapshot only if operating on a live repository and not
1601 * running in early import.
1603 if (est
->sc_repo_filename
== NULL
&&
1604 est
->sc_repo_doorname
== NULL
&&
1605 est
->sc_in_emi
== 0) {
1606 if (_smf_refresh_instance_i(entity
) == 0) {
1608 warn(gettext("Refreshed %s.\n"), fmri
);
1612 switch (scf_error()) {
1613 case SCF_ERROR_BACKEND_ACCESS
:
1616 case SCF_ERROR_PERMISSION_DENIED
:
1623 r
= refresh_running_snapshot(entity
);
1635 bad_error("refresh_running_snapshot",
1643 if (scf_iter_service_instances(iter
, entity
) != 0) {
1644 switch (scf_error()) {
1645 case SCF_ERROR_CONNECTION_BROKEN
:
1646 return (ECONNABORTED
);
1648 case SCF_ERROR_DELETED
:
1651 case SCF_ERROR_HANDLE_MISMATCH
:
1652 case SCF_ERROR_NOT_BOUND
:
1653 case SCF_ERROR_NOT_SET
:
1655 bad_error("scf_iter_service_instances", scf_error());
1660 r
= scf_iter_next_instance(iter
, inst
);
1664 switch (scf_error()) {
1665 case SCF_ERROR_CONNECTION_BROKEN
:
1666 return (ECONNABORTED
);
1668 case SCF_ERROR_DELETED
:
1671 case SCF_ERROR_HANDLE_MISMATCH
:
1672 case SCF_ERROR_NOT_BOUND
:
1673 case SCF_ERROR_NOT_SET
:
1674 case SCF_ERROR_INVALID_ARGUMENT
:
1676 bad_error("scf_iter_next_instance",
1682 * Similarly, just take a new running snapshot if operating on
1683 * a non-live repository or running during early import.
1685 if (est
->sc_repo_filename
!= NULL
||
1686 est
->sc_repo_doorname
!= NULL
||
1687 est
->sc_in_emi
== 1) {
1688 r
= refresh_running_snapshot(inst
);
1699 bad_error("refresh_running_snapshot",
1707 if (_smf_refresh_instance_i(inst
) == 0) {
1709 if (scf_instance_get_name(inst
, name_buf
,
1710 max_scf_name_len
+ 1) < 0)
1711 (void) strcpy(name_buf
, "?");
1713 warn(gettext("Refreshed %s:%s.\n"),
1717 if (scf_error() != SCF_ERROR_BACKEND_ACCESS
||
1721 if (scf_instance_to_fmri(inst
, name_buf
,
1722 max_scf_name_len
+ 1) < 0)
1723 (void) strcpy(name_buf
, "?");
1726 "Refresh of %s:%s failed: %s.\n"), fmri
,
1727 name_buf
, scf_strerror(scfe
));
1736 private_refresh(void)
1738 scf_instance_t
*pinst
= NULL
;
1739 scf_iter_t
*piter
= NULL
;
1747 if (est
->sc_repo_filename
== NULL
&& est
->sc_repo_doorname
== NULL
)
1750 assert(cur_svc
!= NULL
);
1752 bufsz
= max_scf_fmri_len
+ 1;
1753 fmribuf
= safe_malloc(bufsz
);
1757 fmrilen
= scf_instance_to_fmri(ent
, fmribuf
, bufsz
);
1761 fmrilen
= scf_service_to_fmri(ent
, fmribuf
, bufsz
);
1762 if ((pinst
= scf_instance_create(g_hndl
)) == NULL
)
1765 if ((piter
= scf_iter_create(g_hndl
)) == NULL
)
1770 if (scf_error() != SCF_ERROR_DELETED
)
1776 assert(fmrilen
< bufsz
);
1778 r
= refresh_entity(issvc
, ent
, fmribuf
, pinst
, piter
, NULL
);
1784 warn(gettext("Could not refresh %s "
1785 "(repository connection broken).\n"), fmribuf
);
1793 warn(gettext("Could not refresh %s "
1794 "(permission denied).\n"), fmribuf
);
1798 warn(gettext("Could not refresh %s "
1799 "(repository server out of resources).\n"),
1805 bad_error("refresh_entity", scf_error());
1809 scf_instance_destroy(pinst
);
1810 scf_iter_destroy(piter
);
1818 stash_scferror_err(scf_callback_t
*cbp
, scf_error_t err
)
1820 cbp
->sc_err
= scferror2errno(err
);
1821 return (UU_WALK_ERROR
);
1825 stash_scferror(scf_callback_t
*cbp
)
1827 return (stash_scferror_err(cbp
, scf_error()));
1830 static int select_inst(const char *);
1831 static int select_svc(const char *);
1834 * Take a property that does not have a type and check to see if a type
1835 * exists or can be gleened from the current data. Set the type.
1837 * Check the current level (instance) and then check the higher level
1838 * (service). This could be the case for adding a new property to
1839 * the instance that's going to "override" a service level property.
1842 * 1. Take the type from an existing property
1843 * 2. Take the type from a template entry
1845 * If the type can not be found, then leave the type as is, and let the import
1846 * report the problem of the missing type.
1849 find_current_prop_type(void *p
, void *g
)
1851 property_t
*prop
= p
;
1852 scf_callback_t
*lcb
= g
;
1853 pgroup_t
*pg
= NULL
;
1855 const char *fmri
= NULL
;
1857 char *cur_selection
= NULL
;
1859 scf_propertygroup_t
*sc_pg
= NULL
;
1860 scf_property_t
*sc_prop
= NULL
;
1861 scf_pg_tmpl_t
*t_pg
= NULL
;
1862 scf_prop_tmpl_t
*t_prop
= NULL
;
1863 scf_type_t prop_type
;
1866 int issvc
= lcb
->sc_service
;
1867 int r
= UU_WALK_ERROR
;
1869 if (prop
->sc_value_type
!= SCF_TYPE_INVALID
)
1870 return (UU_WALK_NEXT
);
1872 t_prop
= scf_tmpl_prop_create(g_hndl
);
1873 sc_prop
= scf_property_create(g_hndl
);
1874 if (sc_prop
== NULL
|| t_prop
== NULL
) {
1875 warn(gettext("Unable to create the property to attempt and "
1876 "find a missing type.\n"));
1878 scf_property_destroy(sc_prop
);
1879 scf_tmpl_prop_destroy(t_prop
);
1881 return (UU_WALK_ERROR
);
1884 if (lcb
->sc_flags
== 1) {
1885 pg
= lcb
->sc_parent
;
1886 issvc
= (pg
->sc_parent
->sc_etype
== SVCCFG_SERVICE_OBJECT
);
1887 fmri
= pg
->sc_parent
->sc_fmri
;
1889 if (cur_svc
&& cur_selection
== NULL
) {
1890 cur_selection
= safe_malloc(max_scf_fmri_len
+ 1);
1891 lscf_get_selection_str(cur_selection
,
1892 max_scf_fmri_len
+ 1);
1894 if (strcmp(cur_selection
, fmri
) != 0) {
1897 free(cur_selection
);
1898 cur_selection
= NULL
;
1904 if (sc_pg
== NULL
&& (sc_pg
= scf_pg_create(g_hndl
)) == NULL
) {
1905 warn(gettext("Unable to create property group to "
1906 "find a missing property type.\n"));
1911 if (get_pg(pg
->sc_pgroup_name
, sc_pg
) != SCF_SUCCESS
) {
1913 * If this is the sc_pg from the parent
1914 * let the caller clean up the sc_pg,
1915 * and just throw it away in this case.
1917 if (sc_pg
!= lcb
->sc_parent
)
1918 scf_pg_destroy(sc_pg
);
1921 if ((t_pg
= scf_tmpl_pg_create(g_hndl
)) == NULL
) {
1922 warn(gettext("Unable to create template "
1923 "property group to find a property "
1929 if (scf_tmpl_get_by_pg_name(fmri
, NULL
,
1930 pg
->sc_pgroup_name
, NULL
, t_pg
,
1931 SCF_PG_TMPL_FLAG_EXACT
) != SCF_SUCCESS
) {
1933 * if instance get service and jump back
1935 scf_tmpl_pg_destroy(t_pg
);
1938 entity_t
*e
= pg
->sc_parent
->sc_parent
;
1949 sc_pg
= lcb
->sc_parent
;
1953 * Attempt to get the type from an existing property. If the property
1954 * cannot be found then attempt to get the type from a template entry
1957 * Finally, if at the instance level look at the service level.
1959 if (sc_pg
!= NULL
&&
1960 pg_get_prop(sc_pg
, prop
->sc_property_name
,
1961 sc_prop
) == SCF_SUCCESS
&&
1962 scf_property_type(sc_prop
, &prop_type
) == SCF_SUCCESS
) {
1963 prop
->sc_value_type
= prop_type
;
1966 * Found a type, update the value types and validate
1967 * the actual value against this type.
1969 for (vp
= uu_list_first(prop
->sc_property_values
);
1971 vp
= uu_list_next(prop
->sc_property_values
, vp
)) {
1972 vp
->sc_type
= prop
->sc_value_type
;
1973 lxml_store_value(vp
, 0, NULL
);
1981 * If we get here with t_pg set to NULL then we had to have
1982 * gotten an sc_pg but that sc_pg did not have the property
1983 * we are looking for. So if the t_pg is not null look up
1984 * the template entry for the property.
1986 * If the t_pg is null then need to attempt to get a matching
1987 * template entry for the sc_pg, and see if there is a property
1988 * entry for that template entry.
1992 scf_tmpl_get_by_prop(t_pg
, prop
->sc_property_name
,
1993 t_prop
, 0) == SCF_SUCCESS
) {
1994 if (scf_tmpl_prop_type(t_prop
, &prop_type
) == SCF_SUCCESS
) {
1995 prop
->sc_value_type
= prop_type
;
1998 * Found a type, update the value types and validate
1999 * the actual value against this type.
2001 for (vp
= uu_list_first(prop
->sc_property_values
);
2003 vp
= uu_list_next(prop
->sc_property_values
, vp
)) {
2004 vp
->sc_type
= prop
->sc_value_type
;
2005 lxml_store_value(vp
, 0, NULL
);
2012 if (t_pg
== NULL
&& sc_pg
) {
2013 if ((t_pg
= scf_tmpl_pg_create(g_hndl
)) == NULL
) {
2014 warn(gettext("Unable to create template "
2015 "property group to find a property "
2021 if (scf_tmpl_get_by_pg(sc_pg
, t_pg
, 0) != SCF_SUCCESS
) {
2022 scf_tmpl_pg_destroy(t_pg
);
2035 if (lcb
->sc_flags
== 1) {
2036 entity_t
*e
= pg
->sc_parent
->sc_parent
;
2043 * because lcb->sc_flags was not set then this means
2044 * the pg was not used and can be used here.
2046 if ((pg
= internal_pgroup_new()) == NULL
) {
2047 warn(gettext("Could not create internal property group "
2048 "to find a missing type."));
2053 pg
->sc_pgroup_name
= safe_malloc(max_scf_name_len
+ 1);
2054 if (scf_pg_get_name(sc_pg
, (char *)pg
->sc_pgroup_name
,
2055 max_scf_name_len
+ 1) < 0)
2058 i
= scf_instance_create(g_hndl
);
2059 s
= scf_service_create(g_hndl
);
2060 if (i
== NULL
|| s
== NULL
||
2061 scf_pg_get_parent_instance(sc_pg
, i
) != SCF_SUCCESS
) {
2062 warn(gettext("Could not get a service for the instance "
2063 "to find a missing type."));
2069 * Check to see truly at the instance level.
2071 lfmri
= safe_malloc(max_scf_fmri_len
+ 1);
2072 if (scf_instance_get_parent(i
, s
) == SCF_SUCCESS
&&
2073 scf_service_to_fmri(s
, lfmri
, max_scf_fmri_len
+ 1) < 0)
2076 fmri
= (const char *)lfmri
;
2082 if (sc_pg
!= lcb
->sc_parent
) {
2083 scf_pg_destroy(sc_pg
);
2087 * If this is true then the pg was allocated
2088 * here, and the name was set so need to free
2089 * the name and the pg.
2091 if (pg
!= NULL
&& pg
!= lcb
->sc_parent
) {
2092 free((char *)pg
->sc_pgroup_name
);
2093 internal_pgroup_free(pg
);
2096 if (cur_selection
) {
2097 lscf_select(cur_selection
);
2098 free(cur_selection
);
2101 scf_tmpl_pg_destroy(t_pg
);
2102 scf_tmpl_prop_destroy(t_prop
);
2103 scf_property_destroy(sc_prop
);
2105 if (r
!= UU_WALK_NEXT
)
2106 warn(gettext("Could not find property type for \"%s\" "
2107 "from \"%s\"\n"), prop
->sc_property_name
,
2108 fmri
!= NULL
? fmri
: lcb
->sc_source_fmri
);
2116 * Take a property group that does not have a type and check to see if a type
2117 * exists or can be gleened from the current data. Set the type.
2119 * Check the current level (instance) and then check the higher level
2120 * (service). This could be the case for adding a new property to
2121 * the instance that's going to "override" a service level property.
2123 * For a property group
2124 * 1. Take the type from an existing property group
2125 * 2. Take the type from a template entry
2127 * If the type can not be found, then leave the type as is, and let the import
2128 * report the problem of the missing type.
2131 find_current_pg_type(void *p
, void *sori
)
2133 entity_t
*si
= sori
;
2136 const char *ofmri
, *fmri
;
2137 char *cur_selection
= NULL
;
2138 char *pg_type
= NULL
;
2140 scf_propertygroup_t
*sc_pg
= NULL
;
2141 scf_pg_tmpl_t
*t_pg
= NULL
;
2143 int issvc
= (si
->sc_etype
== SVCCFG_SERVICE_OBJECT
);
2144 int r
= UU_WALK_ERROR
;
2146 ofmri
= fmri
= si
->sc_fmri
;
2147 if (pg
->sc_pgroup_type
!= NULL
) {
2153 sc_pg
= scf_pg_create(g_hndl
);
2154 if (sc_pg
== NULL
) {
2155 warn(gettext("Unable to create property group to attempt "
2156 "and find a missing type.\n"));
2158 return (UU_WALK_ERROR
);
2162 * Using get_pg() requires that the cur_svc/cur_inst be
2163 * via lscf_select. Need to preserve the current selection
2164 * if going to use lscf_select() to set up the cur_svc/cur_inst
2167 cur_selection
= safe_malloc(max_scf_fmri_len
+ 1);
2168 lscf_get_selection_str(cur_selection
, max_scf_fmri_len
+ 1);
2172 * If the property group exists get the type, and set
2173 * the pgroup_t type of that type.
2175 * If not the check for a template pg_pattern entry
2176 * and take the type from that.
2181 if (get_pg(pg
->sc_pgroup_name
, sc_pg
) == SCF_SUCCESS
) {
2182 pg_type
= safe_malloc(max_scf_pg_type_len
+ 1);
2183 if (pg_type
!= NULL
&& scf_pg_get_type(sc_pg
, pg_type
,
2184 max_scf_pg_type_len
+ 1) != -1) {
2185 pg
->sc_pgroup_type
= pg_type
;
2193 if ((t_pg
== NULL
) &&
2194 (t_pg
= scf_tmpl_pg_create(g_hndl
)) == NULL
)
2197 if (scf_tmpl_get_by_pg_name(fmri
, NULL
, pg
->sc_pgroup_name
,
2198 NULL
, t_pg
, SCF_PG_TMPL_FLAG_EXACT
) == SCF_SUCCESS
&&
2199 scf_tmpl_pg_type(t_pg
, &pg_type
) != -1) {
2200 pg
->sc_pgroup_type
= pg_type
;
2208 * If type is not found at the instance level then attempt to
2209 * find the type at the service level.
2214 issvc
= (si
->sc_etype
== SVCCFG_SERVICE_OBJECT
);
2219 if (cur_selection
) {
2220 lscf_select(cur_selection
);
2221 free(cur_selection
);
2225 * Now walk the properties of the property group to make sure that
2226 * all properties have the correct type and values are valid for
2229 if (r
== UU_WALK_NEXT
) {
2232 cb
.sc_service
= issvc
;
2233 cb
.sc_source_fmri
= ofmri
;
2234 if (sc_pg
!= NULL
) {
2235 cb
.sc_parent
= sc_pg
;
2242 if (uu_list_walk(pg
->sc_pgroup_props
, find_current_prop_type
,
2243 &cb
, UU_DEFAULT
) != 0) {
2244 if (uu_error() != UU_ERROR_CALLBACK_FAILED
)
2245 bad_error("uu_list_walk", uu_error());
2250 warn(gettext("Could not find property group type for "
2251 "\"%s\" from \"%s\"\n"), pg
->sc_pgroup_name
, fmri
);
2254 scf_tmpl_pg_destroy(t_pg
);
2255 scf_pg_destroy(sc_pg
);
2261 * Import. These functions import a bundle into the repository.
2265 * Add a transaction entry to lcbdata->sc_trans for this property_t. Uses
2266 * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata. On success,
2267 * returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
2268 * lcbdata->sc_err to
2269 * ENOMEM - out of memory
2270 * ECONNABORTED - repository connection broken
2271 * ECANCELED - sc_trans's property group was deleted
2272 * EINVAL - p's name is invalid (error printed)
2273 * - p has an invalid value (error printed)
2276 lscf_property_import(void *v
, void *pvt
)
2279 scf_callback_t
*lcbdata
= pvt
;
2281 scf_transaction_t
*trans
= lcbdata
->sc_trans
;
2282 scf_transaction_entry_t
*entr
;
2286 if ((lcbdata
->sc_flags
& SCI_NOENABLED
||
2287 lcbdata
->sc_flags
& SCI_DELAYENABLE
) &&
2288 strcmp(p
->sc_property_name
, SCF_PROPERTY_ENABLED
) == 0) {
2289 lcbdata
->sc_enable
= p
;
2290 return (UU_WALK_NEXT
);
2293 entr
= scf_entry_create(lcbdata
->sc_handle
);
2295 switch (scf_error()) {
2296 case SCF_ERROR_NO_MEMORY
:
2297 return (stash_scferror(lcbdata
));
2299 case SCF_ERROR_INVALID_ARGUMENT
:
2301 bad_error("scf_entry_create", scf_error());
2305 tp
= p
->sc_value_type
;
2307 if (scf_transaction_property_new(trans
, entr
,
2308 p
->sc_property_name
, tp
) != 0) {
2309 switch (scf_error()) {
2310 case SCF_ERROR_INVALID_ARGUMENT
:
2311 semerr(emsg_invalid_prop_name
, p
->sc_property_name
);
2312 scf_entry_destroy(entr
);
2313 return (stash_scferror(lcbdata
));
2315 case SCF_ERROR_EXISTS
:
2318 case SCF_ERROR_DELETED
:
2319 case SCF_ERROR_CONNECTION_BROKEN
:
2320 scf_entry_destroy(entr
);
2321 return (stash_scferror(lcbdata
));
2323 case SCF_ERROR_NOT_BOUND
:
2324 case SCF_ERROR_HANDLE_MISMATCH
:
2325 case SCF_ERROR_NOT_SET
:
2327 bad_error("scf_transaction_property_new", scf_error());
2330 if (scf_transaction_property_change_type(trans
, entr
,
2331 p
->sc_property_name
, tp
) != 0) {
2332 switch (scf_error()) {
2333 case SCF_ERROR_DELETED
:
2334 case SCF_ERROR_CONNECTION_BROKEN
:
2335 scf_entry_destroy(entr
);
2336 return (stash_scferror(lcbdata
));
2338 case SCF_ERROR_INVALID_ARGUMENT
:
2339 semerr(emsg_invalid_prop_name
,
2340 p
->sc_property_name
);
2341 scf_entry_destroy(entr
);
2342 return (stash_scferror(lcbdata
));
2344 case SCF_ERROR_NOT_FOUND
:
2345 case SCF_ERROR_NOT_SET
:
2346 case SCF_ERROR_HANDLE_MISMATCH
:
2347 case SCF_ERROR_NOT_BOUND
:
2350 "scf_transaction_property_change_type",
2356 for (vp
= uu_list_first(p
->sc_property_values
);
2358 vp
= uu_list_next(p
->sc_property_values
, vp
)) {
2359 val
= scf_value_create(g_hndl
);
2361 switch (scf_error()) {
2362 case SCF_ERROR_NO_MEMORY
:
2363 return (stash_scferror(lcbdata
));
2365 case SCF_ERROR_INVALID_ARGUMENT
:
2367 bad_error("scf_value_create", scf_error());
2372 case SCF_TYPE_BOOLEAN
:
2373 scf_value_set_boolean(val
, vp
->sc_u
.sc_count
);
2375 case SCF_TYPE_COUNT
:
2376 scf_value_set_count(val
, vp
->sc_u
.sc_count
);
2378 case SCF_TYPE_INTEGER
:
2379 scf_value_set_integer(val
, vp
->sc_u
.sc_integer
);
2382 assert(vp
->sc_u
.sc_string
!= NULL
);
2383 if (scf_value_set_from_string(val
, tp
,
2384 vp
->sc_u
.sc_string
) != 0) {
2385 if (scf_error() != SCF_ERROR_INVALID_ARGUMENT
)
2386 bad_error("scf_value_set_from_string",
2389 warn(gettext("Value \"%s\" is not a valid "
2390 "%s.\n"), vp
->sc_u
.sc_string
,
2391 scf_type_to_string(tp
));
2392 scf_value_destroy(val
);
2393 return (stash_scferror(lcbdata
));
2398 if (scf_entry_add_value(entr
, val
) != 0)
2399 bad_error("scf_entry_add_value", scf_error());
2402 return (UU_WALK_NEXT
);
2406 * Import a pgroup_t into the repository. Uses sc_handle, sc_parent,
2407 * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2408 * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2409 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
2410 * lcbdata->sc_err to
2411 * ECONNABORTED - repository connection broken
2412 * ENOMEM - out of memory
2413 * ENOSPC - svc.configd is out of resources
2414 * ECANCELED - sc_parent was deleted
2415 * EPERM - could not create property group (permission denied) (error printed)
2416 * - could not modify property group (permission denied) (error printed)
2417 * - could not delete property group (permission denied) (error printed)
2418 * EROFS - could not create property group (repository is read-only)
2419 * - could not delete property group (repository is read-only)
2420 * EACCES - could not create property group (backend access denied)
2421 * - could not delete property group (backend access denied)
2422 * EEXIST - could not create property group (already exists)
2423 * EINVAL - invalid property group name (error printed)
2424 * - invalid property name (error printed)
2425 * - invalid value (error printed)
2426 * EBUSY - new property group deleted (error printed)
2427 * - new property group changed (error printed)
2428 * - property group added (error printed)
2429 * - property group deleted (error printed)
2432 entity_pgroup_import(void *v
, void *pvt
)
2435 scf_callback_t cbdata
;
2436 scf_callback_t
*lcbdata
= pvt
;
2437 void *ent
= lcbdata
->sc_parent
;
2438 int issvc
= lcbdata
->sc_service
;
2441 const char * const pg_changed
= gettext("%s changed unexpectedly "
2442 "(new property group \"%s\" changed).\n");
2444 /* Never import deleted property groups. */
2445 if (p
->sc_pgroup_delete
) {
2446 if ((lcbdata
->sc_flags
& SCI_OP_APPLY
) == SCI_OP_APPLY
&&
2447 entity_get_pg(ent
, issvc
, p
->sc_pgroup_name
, imp_pg
) == 0) {
2450 return (UU_WALK_NEXT
);
2453 if (!issvc
&& (lcbdata
->sc_flags
& SCI_GENERALLAST
) &&
2454 strcmp(p
->sc_pgroup_name
, SCF_PG_GENERAL
) == 0) {
2455 lcbdata
->sc_general
= p
;
2456 return (UU_WALK_NEXT
);
2461 r
= scf_service_add_pg(ent
, p
->sc_pgroup_name
,
2462 p
->sc_pgroup_type
, p
->sc_pgroup_flags
, imp_pg
);
2464 r
= scf_instance_add_pg(ent
, p
->sc_pgroup_name
,
2465 p
->sc_pgroup_type
, p
->sc_pgroup_flags
, imp_pg
);
2467 switch (scf_error()) {
2468 case SCF_ERROR_DELETED
:
2469 case SCF_ERROR_CONNECTION_BROKEN
:
2470 case SCF_ERROR_BACKEND_READONLY
:
2471 case SCF_ERROR_BACKEND_ACCESS
:
2472 case SCF_ERROR_NO_RESOURCES
:
2473 return (stash_scferror(lcbdata
));
2475 case SCF_ERROR_EXISTS
:
2476 if (lcbdata
->sc_flags
& SCI_FORCE
)
2478 return (stash_scferror(lcbdata
));
2480 case SCF_ERROR_INVALID_ARGUMENT
:
2481 warn(emsg_fmri_invalid_pg_name_type
,
2482 lcbdata
->sc_source_fmri
,
2483 p
->sc_pgroup_name
, p
->sc_pgroup_type
);
2484 return (stash_scferror(lcbdata
));
2486 case SCF_ERROR_PERMISSION_DENIED
:
2487 warn(emsg_pg_add_perm
, p
->sc_pgroup_name
,
2488 lcbdata
->sc_target_fmri
);
2489 return (stash_scferror(lcbdata
));
2491 case SCF_ERROR_NOT_BOUND
:
2492 case SCF_ERROR_HANDLE_MISMATCH
:
2493 case SCF_ERROR_NOT_SET
:
2495 bad_error("scf_service_add_pg", scf_error());
2498 if (entity_get_pg(ent
, issvc
, p
->sc_pgroup_name
, imp_pg
) != 0) {
2499 switch (scf_error()) {
2500 case SCF_ERROR_CONNECTION_BROKEN
:
2501 case SCF_ERROR_DELETED
:
2502 return (stash_scferror(lcbdata
));
2504 case SCF_ERROR_INVALID_ARGUMENT
:
2505 warn(emsg_fmri_invalid_pg_name
,
2506 lcbdata
->sc_source_fmri
,
2508 return (stash_scferror(lcbdata
));
2510 case SCF_ERROR_NOT_FOUND
:
2511 warn(emsg_pg_deleted
, lcbdata
->sc_target_fmri
,
2513 lcbdata
->sc_err
= EBUSY
;
2514 return (UU_WALK_ERROR
);
2516 case SCF_ERROR_NOT_BOUND
:
2517 case SCF_ERROR_HANDLE_MISMATCH
:
2518 case SCF_ERROR_NOT_SET
:
2520 bad_error("entity_get_pg", scf_error());
2524 if (lcbdata
->sc_flags
& SCI_KEEP
)
2528 if (scf_pg_delete(imp_pg
) != 0) {
2529 switch (scf_error()) {
2530 case SCF_ERROR_DELETED
:
2531 warn(emsg_pg_deleted
, lcbdata
->sc_target_fmri
,
2533 lcbdata
->sc_err
= EBUSY
;
2534 return (UU_WALK_ERROR
);
2536 case SCF_ERROR_PERMISSION_DENIED
:
2537 warn(emsg_pg_del_perm
, p
->sc_pgroup_name
,
2538 lcbdata
->sc_target_fmri
);
2539 return (stash_scferror(lcbdata
));
2541 case SCF_ERROR_BACKEND_READONLY
:
2542 case SCF_ERROR_BACKEND_ACCESS
:
2543 case SCF_ERROR_CONNECTION_BROKEN
:
2544 return (stash_scferror(lcbdata
));
2546 case SCF_ERROR_NOT_SET
:
2548 bad_error("scf_pg_delete", scf_error());
2552 if (p
->sc_pgroup_delete
)
2553 return (UU_WALK_NEXT
);
2561 * Add properties to property group, if any.
2563 cbdata
.sc_handle
= lcbdata
->sc_handle
;
2564 cbdata
.sc_parent
= imp_pg
;
2565 cbdata
.sc_flags
= lcbdata
->sc_flags
;
2566 cbdata
.sc_trans
= imp_tx
;
2567 cbdata
.sc_enable
= NULL
;
2569 if (scf_transaction_start(imp_tx
, imp_pg
) != 0) {
2570 switch (scf_error()) {
2571 case SCF_ERROR_BACKEND_ACCESS
:
2572 case SCF_ERROR_BACKEND_READONLY
:
2573 case SCF_ERROR_CONNECTION_BROKEN
:
2574 return (stash_scferror(lcbdata
));
2576 case SCF_ERROR_DELETED
:
2577 warn(pg_changed
, lcbdata
->sc_target_fmri
,
2579 lcbdata
->sc_err
= EBUSY
;
2580 return (UU_WALK_ERROR
);
2582 case SCF_ERROR_PERMISSION_DENIED
:
2583 warn(emsg_pg_mod_perm
, p
->sc_pgroup_name
,
2584 lcbdata
->sc_target_fmri
);
2585 return (stash_scferror(lcbdata
));
2587 case SCF_ERROR_NOT_BOUND
:
2588 case SCF_ERROR_NOT_SET
:
2589 case SCF_ERROR_IN_USE
:
2590 case SCF_ERROR_HANDLE_MISMATCH
:
2592 bad_error("scf_transaction_start", scf_error());
2596 if (uu_list_walk(p
->sc_pgroup_props
, lscf_property_import
, &cbdata
,
2598 if (uu_error() != UU_ERROR_CALLBACK_FAILED
)
2599 bad_error("uu_list_walk", uu_error());
2600 scf_transaction_reset(imp_tx
);
2602 lcbdata
->sc_err
= cbdata
.sc_err
;
2603 if (cbdata
.sc_err
== ECANCELED
) {
2604 warn(pg_changed
, lcbdata
->sc_target_fmri
,
2606 lcbdata
->sc_err
= EBUSY
;
2608 return (UU_WALK_ERROR
);
2611 if ((lcbdata
->sc_flags
& SCI_DELAYENABLE
) && cbdata
.sc_enable
) {
2612 cbdata
.sc_flags
= cbdata
.sc_flags
& (~SCI_DELAYENABLE
);
2615 * take the snapshot running snapshot then
2616 * import the stored general/enable property
2618 r
= take_snap(ent
, snap_running
, imp_rsnap
);
2624 warn(gettext("Could not take %s snapshot on import "
2625 "(repository connection broken).\n"),
2627 lcbdata
->sc_err
= r
;
2628 return (UU_WALK_ERROR
);
2631 lcbdata
->sc_err
= r
;
2632 return (UU_WALK_ERROR
);
2635 warn(gettext("Could not take %s snapshot "
2636 "(permission denied).\n"), snap_running
);
2637 lcbdata
->sc_err
= r
;
2638 return (UU_WALK_ERROR
);
2641 warn(gettext("Could not take %s snapshot"
2642 "(repository server out of resources).\n"),
2644 lcbdata
->sc_err
= r
;
2645 return (UU_WALK_ERROR
);
2648 bad_error("take_snap", r
);
2651 r
= lscf_property_import(cbdata
.sc_enable
, &cbdata
);
2652 if (r
!= UU_WALK_NEXT
) {
2653 if (r
!= UU_WALK_ERROR
)
2654 bad_error("lscf_property_import", r
);
2659 r
= scf_transaction_commit(imp_tx
);
2666 warn(pg_changed
, lcbdata
->sc_target_fmri
, p
->sc_pgroup_name
);
2667 lcbdata
->sc_err
= EBUSY
;
2672 switch (scf_error()) {
2673 case SCF_ERROR_BACKEND_READONLY
:
2674 case SCF_ERROR_BACKEND_ACCESS
:
2675 case SCF_ERROR_CONNECTION_BROKEN
:
2676 case SCF_ERROR_NO_RESOURCES
:
2677 r
= stash_scferror(lcbdata
);
2680 case SCF_ERROR_DELETED
:
2681 warn(emsg_pg_deleted
, lcbdata
->sc_target_fmri
,
2683 lcbdata
->sc_err
= EBUSY
;
2687 case SCF_ERROR_PERMISSION_DENIED
:
2688 warn(emsg_pg_mod_perm
, p
->sc_pgroup_name
,
2689 lcbdata
->sc_target_fmri
);
2690 r
= stash_scferror(lcbdata
);
2693 case SCF_ERROR_NOT_SET
:
2694 case SCF_ERROR_INVALID_ARGUMENT
:
2695 case SCF_ERROR_NOT_BOUND
:
2697 bad_error("scf_transaction_commit", scf_error());
2702 bad_error("scf_transaction_commit", r
);
2705 scf_transaction_destroy_children(imp_tx
);
2713 * ECONNABORTED - repository connection broken
2714 * ENOMEM - out of memory
2715 * ENOSPC - svc.configd is out of resources
2716 * ECANCELED - inst was deleted
2717 * EPERM - could not create property group (permission denied) (error printed)
2718 * - could not modify property group (permission denied) (error printed)
2719 * EROFS - could not create property group (repository is read-only)
2720 * EACCES - could not create property group (backend access denied)
2721 * EEXIST - could not create property group (already exists)
2722 * EINVAL - invalid property group name (error printed)
2723 * - invalid property name (error printed)
2724 * - invalid value (error printed)
2725 * EBUSY - new property group changed (error printed)
2728 lscf_import_service_pgs(scf_service_t
*svc
, const char *target_fmri
,
2729 const entity_t
*isvc
, int flags
)
2731 scf_callback_t cbdata
;
2733 cbdata
.sc_handle
= scf_service_handle(svc
);
2734 cbdata
.sc_parent
= svc
;
2735 cbdata
.sc_service
= 1;
2736 cbdata
.sc_general
= 0;
2737 cbdata
.sc_enable
= 0;
2738 cbdata
.sc_flags
= flags
;
2739 cbdata
.sc_source_fmri
= isvc
->sc_fmri
;
2740 cbdata
.sc_target_fmri
= target_fmri
;
2743 * If the op is set, then add the flag to the callback
2744 * flags for later use.
2746 if (isvc
->sc_op
!= SVCCFG_OP_NONE
) {
2747 switch (isvc
->sc_op
) {
2748 case SVCCFG_OP_IMPORT
:
2749 cbdata
.sc_flags
|= SCI_OP_IMPORT
;
2751 case SVCCFG_OP_APPLY
:
2752 cbdata
.sc_flags
|= SCI_OP_APPLY
;
2754 case SVCCFG_OP_RESTORE
:
2755 cbdata
.sc_flags
|= SCI_OP_RESTORE
;
2758 uu_die(gettext("lscf_import_service_pgs : "
2759 "Unknown op stored in the service entity\n"));
2764 if (uu_list_walk(isvc
->sc_pgroups
, entity_pgroup_import
, &cbdata
,
2766 if (uu_error() != UU_ERROR_CALLBACK_FAILED
)
2767 bad_error("uu_list_walk", uu_error());
2769 return (cbdata
.sc_err
);
2778 * ECONNABORTED - repository connection broken
2779 * ENOMEM - out of memory
2780 * ENOSPC - svc.configd is out of resources
2781 * ECANCELED - inst was deleted
2782 * EPERM - could not create property group (permission denied) (error printed)
2783 * - could not modify property group (permission denied) (error printed)
2784 * EROFS - could not create property group (repository is read-only)
2785 * EACCES - could not create property group (backend access denied)
2786 * EEXIST - could not create property group (already exists)
2787 * EINVAL - invalid property group name (error printed)
2788 * - invalid property name (error printed)
2789 * - invalid value (error printed)
2790 * EBUSY - new property group changed (error printed)
2793 lscf_import_instance_pgs(scf_instance_t
*inst
, const char *target_fmri
,
2794 const entity_t
*iinst
, int flags
)
2796 scf_callback_t cbdata
;
2798 cbdata
.sc_handle
= scf_instance_handle(inst
);
2799 cbdata
.sc_parent
= inst
;
2800 cbdata
.sc_service
= 0;
2801 cbdata
.sc_general
= NULL
;
2802 cbdata
.sc_enable
= NULL
;
2803 cbdata
.sc_flags
= flags
;
2804 cbdata
.sc_source_fmri
= iinst
->sc_fmri
;
2805 cbdata
.sc_target_fmri
= target_fmri
;
2808 * If the op is set, then add the flag to the callback
2809 * flags for later use.
2811 if (iinst
->sc_op
!= SVCCFG_OP_NONE
) {
2812 switch (iinst
->sc_op
) {
2813 case SVCCFG_OP_IMPORT
:
2814 cbdata
.sc_flags
|= SCI_OP_IMPORT
;
2816 case SVCCFG_OP_APPLY
:
2817 cbdata
.sc_flags
|= SCI_OP_APPLY
;
2819 case SVCCFG_OP_RESTORE
:
2820 cbdata
.sc_flags
|= SCI_OP_RESTORE
;
2823 uu_die(gettext("lscf_import_instance_pgs : "
2824 "Unknown op stored in the instance entity\n"));
2828 if (uu_list_walk(iinst
->sc_pgroups
, entity_pgroup_import
, &cbdata
,
2830 if (uu_error() != UU_ERROR_CALLBACK_FAILED
)
2831 bad_error("uu_list_walk", uu_error());
2833 return (cbdata
.sc_err
);
2836 if ((flags
& SCI_GENERALLAST
) && cbdata
.sc_general
) {
2837 cbdata
.sc_flags
= flags
& (~SCI_GENERALLAST
);
2839 * If importing with the SCI_NOENABLED flag then
2840 * skip the delay, but if not then add the delay
2841 * of the enable property.
2843 if (!(cbdata
.sc_flags
& SCI_NOENABLED
)) {
2844 cbdata
.sc_flags
|= SCI_DELAYENABLE
;
2847 if (entity_pgroup_import(cbdata
.sc_general
, &cbdata
)
2849 return (cbdata
.sc_err
);
2856 * Report the reasons why we can't upgrade pg2 to pg1.
2859 report_pg_diffs(const pgroup_t
*pg1
, const pgroup_t
*pg2
, const char *fmri
,
2862 property_t
*p1
, *p2
;
2864 assert(strcmp(pg1
->sc_pgroup_name
, pg2
->sc_pgroup_name
) == 0);
2866 if (!pg_attrs_equal(pg1
, pg2
, fmri
, new))
2869 for (p1
= uu_list_first(pg1
->sc_pgroup_props
);
2871 p1
= uu_list_next(pg1
->sc_pgroup_props
, p1
)) {
2872 p2
= uu_list_find(pg2
->sc_pgroup_props
, p1
, NULL
, NULL
);
2874 (void) prop_equal(p1
, p2
, fmri
, pg1
->sc_pgroup_name
,
2880 warn(gettext("Conflict upgrading %s (new property "
2881 "group \"%s\" is missing property \"%s\").\n"),
2882 fmri
, pg1
->sc_pgroup_name
, p1
->sc_property_name
);
2884 warn(gettext("Conflict upgrading %s (property "
2885 "\"%s/%s\" is missing).\n"), fmri
,
2886 pg1
->sc_pgroup_name
, p1
->sc_property_name
);
2890 * Since pg1 should be from the manifest, any properties in pg2 which
2891 * aren't in pg1 shouldn't be reported as conflicts.
2896 * Add transaction entries to tx which will upgrade cur's pg according to old
2901 * EINVAL - new has a property with an invalid name or value (message emitted)
2902 * ENOMEM - out of memory
2905 add_upgrade_entries(scf_transaction_t
*tx
, pgroup_t
*old
, pgroup_t
*new,
2906 pgroup_t
*cur
, int speak
, const char *fmri
)
2908 property_t
*p
, *new_p
, *cur_p
;
2909 scf_transaction_entry_t
*e
;
2914 if (uu_list_walk(new->sc_pgroup_props
, clear_int
,
2915 (void *)offsetof(property_t
, sc_seen
), UU_DEFAULT
) != 0)
2916 bad_error("uu_list_walk", uu_error());
2918 is_general
= strcmp(old
->sc_pgroup_name
, SCF_PG_GENERAL
) == 0;
2920 for (p
= uu_list_first(old
->sc_pgroup_props
);
2922 p
= uu_list_next(old
->sc_pgroup_props
, p
)) {
2923 /* p is a property in the old property group. */
2925 /* Protect live properties. */
2928 if (strcmp(p
->sc_property_name
, SCF_PROPERTY_ENABLED
) ==
2930 strcmp(p
->sc_property_name
,
2931 SCF_PROPERTY_RESTARTER
) == 0)
2935 /* Look for the same property in the new properties. */
2936 new_p
= uu_list_find(new->sc_pgroup_props
, p
, NULL
, NULL
);
2937 if (new_p
!= NULL
) {
2941 * If the new property is the same as the old, don't do
2942 * anything (leave any user customizations).
2944 if (prop_equal(p
, new_p
, NULL
, NULL
, 0))
2947 if (new_p
->sc_property_override
)
2951 cur_p
= uu_list_find(cur
->sc_pgroup_props
, p
, NULL
, NULL
);
2952 if (cur_p
== NULL
) {
2954 * p has been deleted from the repository. If we were
2955 * going to delete it anyway, do nothing. Otherwise
2956 * report a conflict.
2964 warn(gettext("Conflict upgrading %s "
2965 "(property \"%s/%s\" is missing).\n"), fmri
,
2966 old
->sc_pgroup_name
, p
->sc_property_name
);
2970 if (!prop_equal(p
, cur_p
, NULL
, NULL
, 0)) {
2972 * Conflict. Don't warn if the property is already the
2973 * way we want it, though.
2979 (void) prop_equal(p
, cur_p
, fmri
,
2980 old
->sc_pgroup_name
, 0);
2982 (void) prop_equal(cur_p
, new_p
, fmri
,
2983 old
->sc_pgroup_name
, 0);
2989 warn(gettext("%s: Refusing to upgrade "
2990 "\"%s/%s\" (live property).\n"), fmri
,
2991 old
->sc_pgroup_name
, p
->sc_property_name
);
2996 /* p hasn't been customized in the repository. Upgrade it. */
2997 if (new_p
== NULL
) {
2998 /* p was deleted. Delete from cur if unchanged. */
3001 "%s: Deleting property \"%s/%s\".\n"),
3002 fmri
, old
->sc_pgroup_name
,
3003 p
->sc_property_name
);
3005 e
= scf_entry_create(g_hndl
);
3009 if (scf_transaction_property_delete(tx
, e
,
3010 p
->sc_property_name
) != 0) {
3011 switch (scf_error()) {
3012 case SCF_ERROR_DELETED
:
3013 scf_entry_destroy(e
);
3016 case SCF_ERROR_CONNECTION_BROKEN
:
3017 scf_entry_destroy(e
);
3018 return (ECONNABORTED
);
3020 case SCF_ERROR_NOT_FOUND
:
3022 * This can happen if cur is from the
3023 * running snapshot (and it differs
3024 * from the live properties).
3026 scf_entry_destroy(e
);
3029 case SCF_ERROR_HANDLE_MISMATCH
:
3030 case SCF_ERROR_NOT_BOUND
:
3031 case SCF_ERROR_NOT_SET
:
3032 case SCF_ERROR_INVALID_ARGUMENT
:
3035 "scf_transaction_property_delete",
3044 "%s: Upgrading property \"%s/%s\".\n"),
3045 fmri
, old
->sc_pgroup_name
,
3046 p
->sc_property_name
);
3048 ctx
.sc_handle
= g_hndl
;
3052 r
= lscf_property_import(new_p
, &ctx
);
3053 if (r
!= UU_WALK_NEXT
) {
3054 if (r
!= UU_WALK_ERROR
)
3055 bad_error("lscf_property_import", r
);
3061 /* Go over the properties which were added. */
3062 for (new_p
= uu_list_first(new->sc_pgroup_props
);
3064 new_p
= uu_list_next(new->sc_pgroup_props
, new_p
)) {
3068 /* This is a new property. */
3069 cur_p
= uu_list_find(cur
->sc_pgroup_props
, new_p
, NULL
, NULL
);
3070 if (cur_p
== NULL
) {
3073 ctx
.sc_handle
= g_hndl
;
3077 r
= lscf_property_import(new_p
, &ctx
);
3078 if (r
!= UU_WALK_NEXT
) {
3079 if (r
!= UU_WALK_ERROR
)
3080 bad_error("lscf_property_import", r
);
3087 * Report a conflict if the new property differs from the
3088 * current one. Unless it's general/enabled, since that's
3089 * never in the last-import snapshot.
3091 if (strcmp(new_p
->sc_property_name
, SCF_PROPERTY_ENABLED
) ==
3093 strcmp(cur
->sc_pgroup_name
, SCF_PG_GENERAL
) == 0)
3096 (void) prop_equal(cur_p
, new_p
, fmri
, old
->sc_pgroup_name
, 1);
3103 * Upgrade pg according to old & new.
3107 * ECONNABORTED - repository connection broken
3108 * ENOMEM - out of memory
3109 * ENOSPC - svc.configd is out of resources
3110 * ECANCELED - pg was deleted
3111 * EPERM - couldn't modify pg (permission denied)
3112 * EROFS - couldn't modify pg (backend read-only)
3113 * EACCES - couldn't modify pg (backend access denied)
3114 * EINVAL - new has a property with invalid name or value (error printed)
3115 * EBUSY - pg changed unexpectedly
3118 upgrade_pg(scf_propertygroup_t
*pg
, pgroup_t
*cur
, pgroup_t
*old
,
3119 pgroup_t
*new, int speak
, const char *fmri
)
3123 if (scf_transaction_start(imp_tx
, pg
) != 0) {
3124 switch (scf_error()) {
3125 case SCF_ERROR_CONNECTION_BROKEN
:
3126 case SCF_ERROR_DELETED
:
3127 case SCF_ERROR_PERMISSION_DENIED
:
3128 case SCF_ERROR_BACKEND_READONLY
:
3129 case SCF_ERROR_BACKEND_ACCESS
:
3130 return (scferror2errno(scf_error()));
3132 case SCF_ERROR_HANDLE_MISMATCH
:
3133 case SCF_ERROR_IN_USE
:
3134 case SCF_ERROR_NOT_BOUND
:
3135 case SCF_ERROR_NOT_SET
:
3137 bad_error("scf_transaction_start", scf_error());
3141 r
= add_upgrade_entries(imp_tx
, old
, new, cur
, speak
, fmri
);
3148 scf_transaction_destroy_children(imp_tx
);
3152 bad_error("add_upgrade_entries", r
);
3155 r
= scf_transaction_commit(imp_tx
);
3157 scf_transaction_destroy_children(imp_tx
);
3167 switch (scf_error()) {
3168 case SCF_ERROR_CONNECTION_BROKEN
:
3169 case SCF_ERROR_NO_RESOURCES
:
3170 case SCF_ERROR_PERMISSION_DENIED
:
3171 case SCF_ERROR_BACKEND_READONLY
:
3172 case SCF_ERROR_BACKEND_ACCESS
:
3173 case SCF_ERROR_DELETED
:
3174 return (scferror2errno(scf_error()));
3176 case SCF_ERROR_NOT_BOUND
:
3177 case SCF_ERROR_INVALID_ARGUMENT
:
3178 case SCF_ERROR_NOT_SET
:
3180 bad_error("scf_transaction_commit", scf_error());
3184 bad_error("scf_transaction_commit", r
);
3191 * Compares two entity FMRIs. Returns
3195 * -1 - f1 is invalid or not an entity
3196 * -2 - f2 is invalid or not an entity
3199 fmri_equal(const char *f1
, const char *f2
)
3202 const char *s1
, *i1
, *pg1
;
3203 const char *s2
, *i2
, *pg2
;
3205 if (strlcpy(imp_fe1
, f1
, max_scf_fmri_len
+ 1) >= max_scf_fmri_len
+ 1)
3207 if (scf_parse_svc_fmri(imp_fe1
, NULL
, &s1
, &i1
, &pg1
, NULL
) != 0)
3210 if (s1
== NULL
|| pg1
!= NULL
)
3213 if (strlcpy(imp_fe2
, f2
, max_scf_fmri_len
+ 1) >= max_scf_fmri_len
+ 1)
3215 if (scf_parse_svc_fmri(imp_fe2
, NULL
, &s2
, &i2
, &pg2
, NULL
) != 0)
3218 if (s2
== NULL
|| pg2
!= NULL
)
3225 if (i1
== NULL
&& i2
== NULL
)
3228 if (i1
== NULL
|| i2
== NULL
)
3231 return (strcmp(i1
, i2
) == 0);
3235 * Import a dependent by creating a dependency property group in the dependent
3236 * entity. If lcbdata->sc_trans is set, assume it's been started on the
3237 * dependents pg, and add an entry to create a new property for this
3238 * dependent. Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3240 * On success, returns UU_WALK_NEXT. On error, returns UU_WALK_ERROR and sets
3241 * lcbdata->sc_err to
3242 * ECONNABORTED - repository connection broken
3243 * ENOMEM - out of memory
3244 * ENOSPC - configd is out of resources
3245 * EINVAL - target is invalid (error printed)
3246 * - target is not an entity (error printed)
3247 * - dependent has invalid name (error printed)
3248 * - invalid property name (error printed)
3249 * - invalid value (error printed)
3250 * - scope of target does not exist (error printed)
3251 * EPERM - couldn't create target (permission denied) (error printed)
3252 * - couldn't create dependency pg (permission denied) (error printed)
3253 * - couldn't modify dependency pg (permission denied) (error printed)
3254 * EROFS - couldn't create target (repository read-only)
3255 * - couldn't create dependency pg (repository read-only)
3256 * EACCES - couldn't create target (backend access denied)
3257 * - couldn't create dependency pg (backend access denied)
3258 * ECANCELED - sc_trans's pg was deleted
3259 * EALREADY - property for dependent already exists in sc_trans's pg
3260 * EEXIST - dependency pg already exists in target (error printed)
3261 * EBUSY - target deleted (error printed)
3262 * - property group changed during import (error printed)
3265 lscf_dependent_import(void *a1
, void *pvt
)
3267 pgroup_t
*pgrp
= a1
;
3268 scf_callback_t
*lcbdata
= pvt
;
3272 scf_transaction_entry_t
*e
;
3274 scf_callback_t dependent_cbdata
;
3278 * Decode the FMRI into dependent_cbdata->sc_parent. Do it here so if
3279 * it's invalid, we fail before modifying the repository.
3281 scfe
= fmri_to_entity(lcbdata
->sc_handle
, pgrp
->sc_pgroup_fmri
,
3282 &dependent_cbdata
.sc_parent
, &isservice
);
3284 case SCF_ERROR_NONE
:
3287 case SCF_ERROR_NO_MEMORY
:
3288 return (stash_scferror_err(lcbdata
, scfe
));
3290 case SCF_ERROR_INVALID_ARGUMENT
:
3291 semerr(gettext("The FMRI for the \"%s\" dependent is "
3292 "invalid.\n"), pgrp
->sc_pgroup_name
);
3293 return (stash_scferror_err(lcbdata
, scfe
));
3295 case SCF_ERROR_CONSTRAINT_VIOLATED
:
3296 semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3297 "specifies neither a service nor an instance.\n"),
3298 pgrp
->sc_pgroup_fmri
, pgrp
->sc_pgroup_name
);
3299 return (stash_scferror_err(lcbdata
, scfe
));
3301 case SCF_ERROR_NOT_FOUND
:
3302 scfe
= create_entity(lcbdata
->sc_handle
, pgrp
->sc_pgroup_fmri
,
3303 &dependent_cbdata
.sc_parent
, &isservice
);
3305 case SCF_ERROR_NONE
:
3308 case SCF_ERROR_NO_MEMORY
:
3309 case SCF_ERROR_BACKEND_READONLY
:
3310 case SCF_ERROR_BACKEND_ACCESS
:
3311 return (stash_scferror_err(lcbdata
, scfe
));
3313 case SCF_ERROR_NOT_FOUND
:
3314 semerr(gettext("The scope in FMRI \"%s\" for the "
3315 "\"%s\" dependent does not exist.\n"),
3316 pgrp
->sc_pgroup_fmri
, pgrp
->sc_pgroup_name
);
3317 lcbdata
->sc_err
= EINVAL
;
3318 return (UU_WALK_ERROR
);
3320 case SCF_ERROR_PERMISSION_DENIED
:
3322 "Could not create %s (permission denied).\n"),
3323 pgrp
->sc_pgroup_fmri
);
3324 return (stash_scferror_err(lcbdata
, scfe
));
3326 case SCF_ERROR_INVALID_ARGUMENT
:
3327 case SCF_ERROR_CONSTRAINT_VIOLATED
:
3329 bad_error("create_entity", scfe
);
3334 bad_error("fmri_to_entity", scfe
);
3337 if (lcbdata
->sc_trans
!= NULL
) {
3338 e
= scf_entry_create(lcbdata
->sc_handle
);
3340 if (scf_error() != SCF_ERROR_NO_MEMORY
)
3341 bad_error("scf_entry_create", scf_error());
3343 entity_destroy(dependent_cbdata
.sc_parent
, isservice
);
3344 return (stash_scferror(lcbdata
));
3347 if (scf_transaction_property_new(lcbdata
->sc_trans
, e
,
3348 pgrp
->sc_pgroup_name
, SCF_TYPE_FMRI
) != 0) {
3349 switch (scf_error()) {
3350 case SCF_ERROR_INVALID_ARGUMENT
:
3351 warn(gettext("Dependent of %s has invalid name "
3352 "\"%s\".\n"), pgrp
->sc_parent
->sc_fmri
,
3353 pgrp
->sc_pgroup_name
);
3356 case SCF_ERROR_DELETED
:
3357 case SCF_ERROR_CONNECTION_BROKEN
:
3358 scf_entry_destroy(e
);
3359 entity_destroy(dependent_cbdata
.sc_parent
,
3361 return (stash_scferror(lcbdata
));
3363 case SCF_ERROR_EXISTS
:
3364 scf_entry_destroy(e
);
3365 entity_destroy(dependent_cbdata
.sc_parent
,
3367 lcbdata
->sc_err
= EALREADY
;
3368 return (UU_WALK_ERROR
);
3370 case SCF_ERROR_NOT_BOUND
:
3371 case SCF_ERROR_HANDLE_MISMATCH
:
3372 case SCF_ERROR_NOT_SET
:
3374 bad_error("scf_transaction_property_new",
3379 val
= scf_value_create(lcbdata
->sc_handle
);
3381 if (scf_error() != SCF_ERROR_NO_MEMORY
)
3382 bad_error("scf_value_create", scf_error());
3384 entity_destroy(dependent_cbdata
.sc_parent
, isservice
);
3385 return (stash_scferror(lcbdata
));
3388 if (scf_value_set_from_string(val
, SCF_TYPE_FMRI
,
3389 pgrp
->sc_pgroup_fmri
) != 0)
3390 /* invalid should have been caught above */
3391 bad_error("scf_value_set_from_string", scf_error());
3393 if (scf_entry_add_value(e
, val
) != 0)
3394 bad_error("scf_entry_add_value", scf_error());
3397 /* Add the property group to the target entity. */
3399 dependent_cbdata
.sc_handle
= lcbdata
->sc_handle
;
3400 dependent_cbdata
.sc_flags
= lcbdata
->sc_flags
;
3401 dependent_cbdata
.sc_source_fmri
= lcbdata
->sc_source_fmri
;
3402 dependent_cbdata
.sc_target_fmri
= pgrp
->sc_pgroup_fmri
;
3404 ret
= entity_pgroup_import(pgrp
, &dependent_cbdata
);
3406 entity_destroy(dependent_cbdata
.sc_parent
, isservice
);
3408 if (ret
== UU_WALK_NEXT
)
3411 if (ret
!= UU_WALK_ERROR
)
3412 bad_error("entity_pgroup_import", ret
);
3414 switch (dependent_cbdata
.sc_err
) {
3416 warn(gettext("%s deleted unexpectedly.\n"),
3417 pgrp
->sc_pgroup_fmri
);
3418 lcbdata
->sc_err
= EBUSY
;
3422 warn(gettext("Could not create \"%s\" dependency in %s "
3423 "(already exists).\n"), pgrp
->sc_pgroup_name
,
3424 pgrp
->sc_pgroup_fmri
);
3428 lcbdata
->sc_err
= dependent_cbdata
.sc_err
;
3431 return (UU_WALK_ERROR
);
3434 static int upgrade_dependent(const scf_property_t
*, const entity_t
*,
3435 const scf_snaplevel_t
*, scf_transaction_t
*);
3436 static int handle_dependent_conflict(const entity_t
*, const scf_property_t
*,
3440 * Upgrade uncustomized dependents of ent to those specified in ient. Read
3441 * the current dependent targets from running (the snaplevel of a running
3442 * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3443 * scf_instance_t * according to ient, otherwise). Draw the ancestral
3444 * dependent targets and dependency properties from li_dpts_pg (the
3445 * "dependents" property group in snpl) and snpl (the snaplevel which
3446 * corresponds to ent in a last-import snapshot). If li_dpts_pg is NULL, then
3447 * snpl doesn't have a "dependents" property group, and any dependents in ient
3452 * ECONNABORTED - repository connection broken
3453 * ENOMEM - out of memory
3454 * ENOSPC - configd is out of resources
3455 * ECANCELED - ent was deleted
3456 * ENODEV - the entity containing li_dpts_pg was deleted
3457 * EPERM - could not modify dependents pg (permission denied) (error printed)
3458 * - couldn't upgrade dependent (permission denied) (error printed)
3459 * - couldn't create dependent (permission denied) (error printed)
3460 * EROFS - could not modify dependents pg (repository read-only)
3461 * - couldn't upgrade dependent (repository read-only)
3462 * - couldn't create dependent (repository read-only)
3463 * EACCES - could not modify dependents pg (backend access denied)
3464 * - could not upgrade dependent (backend access denied)
3465 * - could not create dependent (backend access denied)
3466 * EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3467 * - dependent target deleted (error printed)
3468 * - dependent pg changed (error printed)
3469 * EINVAL - new dependent is invalid (error printed)
3470 * EBADF - snpl is corrupt (error printed)
3471 * - snpl has corrupt pg (error printed)
3472 * - dependency pg in target is corrupt (error printed)
3473 * - target has corrupt snapshot (error printed)
3474 * EEXIST - dependency pg already existed in target service (error printed)
3477 upgrade_dependents(const scf_propertygroup_t
*li_dpts_pg
,
3478 const scf_snaplevel_t
*snpl
, const entity_t
*ient
,
3479 const scf_snaplevel_t
*running
, void *ent
)
3481 pgroup_t
*new_dpt_pgroup
;
3482 scf_callback_t cbdata
;
3483 int r
, unseen
, tx_started
= 0;
3486 const char * const dependents
= "dependents";
3488 const int issvc
= (ient
->sc_etype
== SVCCFG_SERVICE_OBJECT
);
3490 if (li_dpts_pg
== NULL
&& uu_list_numnodes(ient
->sc_dependents
) == 0)
3491 /* Nothing to do. */
3494 /* Fetch the current version of the "dependents" property group. */
3496 if (entity_get_pg(ent
, issvc
, dependents
, ud_cur_depts_pg
) != 0) {
3497 switch (scf_error()) {
3498 case SCF_ERROR_NOT_FOUND
:
3501 case SCF_ERROR_DELETED
:
3502 case SCF_ERROR_CONNECTION_BROKEN
:
3503 return (scferror2errno(scf_error()));
3505 case SCF_ERROR_NOT_SET
:
3506 case SCF_ERROR_INVALID_ARGUMENT
:
3507 case SCF_ERROR_HANDLE_MISMATCH
:
3508 case SCF_ERROR_NOT_BOUND
:
3510 bad_error("entity_get_pg", scf_error());
3516 /* Fetch the running version of the "dependents" property group. */
3517 ud_run_dpts_pg_set
= 0;
3518 if (running
!= NULL
)
3519 r
= scf_snaplevel_get_pg(running
, dependents
, ud_run_dpts_pg
);
3521 r
= entity_get_pg(ent
, issvc
, dependents
, ud_run_dpts_pg
);
3523 ud_run_dpts_pg_set
= 1;
3525 switch (scf_error()) {
3526 case SCF_ERROR_NOT_FOUND
:
3529 case SCF_ERROR_DELETED
:
3530 case SCF_ERROR_CONNECTION_BROKEN
:
3531 return (scferror2errno(scf_error()));
3533 case SCF_ERROR_NOT_SET
:
3534 case SCF_ERROR_INVALID_ARGUMENT
:
3535 case SCF_ERROR_HANDLE_MISMATCH
:
3536 case SCF_ERROR_NOT_BOUND
:
3538 bad_error(running
? "scf_snaplevel_get_pg" :
3539 "entity_get_pg", scf_error());
3544 * Clear the seen fields of the dependents, so we can tell which ones
3547 if (uu_list_walk(ient
->sc_dependents
, clear_int
,
3548 (void *)offsetof(pgroup_t
, sc_pgroup_seen
), UU_DEFAULT
) != 0)
3549 bad_error("uu_list_walk", uu_error());
3551 if (li_dpts_pg
!= NULL
) {
3553 * Each property in li_dpts_pg represents a dependent tag in
3554 * the old manifest. For each, call upgrade_dependent(),
3555 * which will change ud_cur_depts_pg or dependencies in other
3556 * services as appropriate. Note (a) that changes to
3557 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3558 * made en masse, and (b) it's ok if the entity doesn't have
3559 * a current version of the "dependents" property group,
3560 * because we'll just consider all dependents as customized
3561 * (by being deleted).
3564 if (scf_iter_pg_properties(ud_iter
, li_dpts_pg
) != 0) {
3565 switch (scf_error()) {
3566 case SCF_ERROR_DELETED
:
3569 case SCF_ERROR_CONNECTION_BROKEN
:
3570 return (ECONNABORTED
);
3572 case SCF_ERROR_HANDLE_MISMATCH
:
3573 case SCF_ERROR_NOT_BOUND
:
3574 case SCF_ERROR_NOT_SET
:
3576 bad_error("scf_iter_pg_properties",
3581 if (have_cur_depts
&&
3582 scf_transaction_start(ud_tx
, ud_cur_depts_pg
) != 0) {
3583 switch (scf_error()) {
3584 case SCF_ERROR_BACKEND_ACCESS
:
3585 case SCF_ERROR_BACKEND_READONLY
:
3586 case SCF_ERROR_CONNECTION_BROKEN
:
3587 return (scferror2errno(scf_error()));
3589 case SCF_ERROR_DELETED
:
3590 warn(emsg_pg_deleted
, ient
->sc_fmri
,
3594 case SCF_ERROR_PERMISSION_DENIED
:
3595 warn(emsg_pg_mod_perm
, dependents
,
3597 return (scferror2errno(scf_error()));
3599 case SCF_ERROR_HANDLE_MISMATCH
:
3600 case SCF_ERROR_IN_USE
:
3601 case SCF_ERROR_NOT_BOUND
:
3602 case SCF_ERROR_NOT_SET
:
3604 bad_error("scf_transaction_start", scf_error());
3607 tx_started
= have_cur_depts
;
3610 r
= scf_iter_next_property(ud_iter
, ud_dpt_prop
);
3614 r
= upgrade_dependent(ud_dpt_prop
, ient
, snpl
,
3615 tx_started
? ud_tx
: NULL
);
3637 bad_error("upgrade_dependent", r
);
3641 scf_transaction_destroy_children(ud_tx
);
3645 bad_error("scf_iter_next_property", r
);
3647 switch (scf_error()) {
3648 case SCF_ERROR_DELETED
:
3652 case SCF_ERROR_CONNECTION_BROKEN
:
3656 case SCF_ERROR_NOT_SET
:
3657 case SCF_ERROR_INVALID_ARGUMENT
:
3658 case SCF_ERROR_NOT_BOUND
:
3659 case SCF_ERROR_HANDLE_MISMATCH
:
3661 bad_error("scf_iter_next_property",
3666 scf_transaction_destroy_children(ud_tx
);
3671 /* import unseen dependents */
3673 for (new_dpt_pgroup
= uu_list_first(ient
->sc_dependents
);
3674 new_dpt_pgroup
!= NULL
;
3675 new_dpt_pgroup
= uu_list_next(ient
->sc_dependents
,
3677 if (!new_dpt_pgroup
->sc_pgroup_seen
) {
3683 /* If there are none, exit early. */
3687 /* Set up for lscf_dependent_import() */
3688 cbdata
.sc_handle
= g_hndl
;
3689 cbdata
.sc_parent
= ent
;
3690 cbdata
.sc_service
= issvc
;
3691 cbdata
.sc_flags
= 0;
3693 if (!have_cur_depts
) {
3695 * We have new dependents to import, so we need a "dependents"
3699 r
= scf_service_add_pg(ent
, dependents
,
3700 SCF_GROUP_FRAMEWORK
, 0, ud_cur_depts_pg
);
3702 r
= scf_instance_add_pg(ent
, dependents
,
3703 SCF_GROUP_FRAMEWORK
, 0, ud_cur_depts_pg
);
3705 switch (scf_error()) {
3706 case SCF_ERROR_DELETED
:
3707 case SCF_ERROR_CONNECTION_BROKEN
:
3708 case SCF_ERROR_BACKEND_READONLY
:
3709 case SCF_ERROR_BACKEND_ACCESS
:
3710 case SCF_ERROR_NO_RESOURCES
:
3711 return (scferror2errno(scf_error()));
3713 case SCF_ERROR_EXISTS
:
3714 warn(emsg_pg_added
, ient
->sc_fmri
, dependents
);
3717 case SCF_ERROR_PERMISSION_DENIED
:
3718 warn(emsg_pg_add_perm
, dependents
,
3720 return (scferror2errno(scf_error()));
3722 case SCF_ERROR_NOT_BOUND
:
3723 case SCF_ERROR_HANDLE_MISMATCH
:
3724 case SCF_ERROR_INVALID_ARGUMENT
:
3725 case SCF_ERROR_NOT_SET
:
3727 bad_error("scf_service_add_pg", scf_error());
3732 cbdata
.sc_trans
= ud_tx
;
3734 if (!tx_started
&& scf_transaction_start(ud_tx
, ud_cur_depts_pg
) != 0) {
3735 switch (scf_error()) {
3736 case SCF_ERROR_CONNECTION_BROKEN
:
3737 case SCF_ERROR_BACKEND_ACCESS
:
3738 case SCF_ERROR_BACKEND_READONLY
:
3739 return (scferror2errno(scf_error()));
3741 case SCF_ERROR_DELETED
:
3742 warn(emsg_pg_deleted
, ient
->sc_fmri
, dependents
);
3745 case SCF_ERROR_PERMISSION_DENIED
:
3746 warn(emsg_pg_mod_perm
, dependents
, ient
->sc_fmri
);
3747 return (scferror2errno(scf_error()));
3749 case SCF_ERROR_HANDLE_MISMATCH
:
3750 case SCF_ERROR_IN_USE
:
3751 case SCF_ERROR_NOT_BOUND
:
3752 case SCF_ERROR_NOT_SET
:
3754 bad_error("scf_transaction_start", scf_error());
3759 for (new_dpt_pgroup
= uu_list_first(ient
->sc_dependents
);
3760 new_dpt_pgroup
!= NULL
;
3761 new_dpt_pgroup
= uu_list_next(ient
->sc_dependents
,
3763 if (new_dpt_pgroup
->sc_pgroup_seen
)
3766 if (ud_run_dpts_pg_set
) {
3768 * If the dependent is already there, then we have
3771 if (scf_pg_get_property(ud_run_dpts_pg
,
3772 new_dpt_pgroup
->sc_pgroup_name
, ud_prop
) == 0) {
3773 r
= handle_dependent_conflict(ient
, ud_prop
,
3784 scf_transaction_destroy_children(ud_tx
);
3788 bad_error("handle_dependent_conflict",
3792 switch (scf_error()) {
3793 case SCF_ERROR_NOT_FOUND
:
3796 case SCF_ERROR_INVALID_ARGUMENT
:
3797 warn(emsg_fmri_invalid_pg_name
,
3799 new_dpt_pgroup
->sc_pgroup_name
);
3800 scf_transaction_destroy_children(ud_tx
);
3803 case SCF_ERROR_DELETED
:
3804 warn(emsg_pg_deleted
, ient
->sc_fmri
,
3805 new_dpt_pgroup
->sc_pgroup_name
);
3806 scf_transaction_destroy_children(ud_tx
);
3809 case SCF_ERROR_CONNECTION_BROKEN
:
3810 scf_transaction_destroy_children(ud_tx
);
3811 return (ECONNABORTED
);
3813 case SCF_ERROR_NOT_BOUND
:
3814 case SCF_ERROR_HANDLE_MISMATCH
:
3815 case SCF_ERROR_NOT_SET
:
3817 bad_error("scf_pg_get_property",
3823 r
= lscf_dependent_import(new_dpt_pgroup
, &cbdata
);
3824 if (r
!= UU_WALK_NEXT
) {
3825 if (r
!= UU_WALK_ERROR
)
3826 bad_error("lscf_dependent_import", r
);
3828 if (cbdata
.sc_err
== EALREADY
) {
3829 /* Collisions were handled preemptively. */
3830 bad_error("lscf_dependent_import",
3834 scf_transaction_destroy_children(ud_tx
);
3835 return (cbdata
.sc_err
);
3843 r
= scf_transaction_commit(ud_tx
);
3845 scf_transaction_destroy_children(ud_tx
);
3852 warn(emsg_pg_changed
, ient
->sc_fmri
, dependents
);
3859 bad_error("scf_transaction_commit", r
);
3862 switch (scf_error()) {
3863 case SCF_ERROR_CONNECTION_BROKEN
:
3864 case SCF_ERROR_BACKEND_READONLY
:
3865 case SCF_ERROR_BACKEND_ACCESS
:
3866 case SCF_ERROR_NO_RESOURCES
:
3867 return (scferror2errno(scf_error()));
3869 case SCF_ERROR_DELETED
:
3870 warn(emsg_pg_deleted
, ient
->sc_fmri
, dependents
);
3873 case SCF_ERROR_PERMISSION_DENIED
:
3874 warn(emsg_pg_mod_perm
, dependents
, ient
->sc_fmri
);
3875 return (scferror2errno(scf_error()));
3877 case SCF_ERROR_NOT_BOUND
:
3878 case SCF_ERROR_INVALID_ARGUMENT
:
3879 case SCF_ERROR_NOT_SET
:
3881 bad_error("scf_transaction_destroy", scf_error());
3887 * Used to add the manifests to the list of currently supported manifests.
3888 * We can modify the existing manifest list removing entries if the files
3891 * Get the old list and the new file name
3892 * If the new file name is in the list return
3893 * If not then add the file to the list.
3894 * As we process the list check to see if the files in the old list exist
3895 * if not then remove the file from the list.
3896 * Commit the list of manifest file names.
3900 upgrade_manifestfiles(pgroup_t
*pg
, entity_t
*ient
,
3901 const scf_snaplevel_t
*running
, void *ent
)
3903 scf_propertygroup_t
*ud_mfsts_pg
= NULL
;
3904 scf_property_t
*ud_prop
= NULL
;
3905 scf_iter_t
*ud_prop_iter
;
3906 scf_value_t
*fname_value
;
3907 scf_callback_t cbdata
;
3908 pgroup_t
*mfst_pgroup
;
3909 property_t
*mfst_prop
;
3910 property_t
*old_prop
;
3919 const int issvc
= (ient
->sc_etype
== SVCCFG_SERVICE_OBJECT
);
3922 * This should always be the service base on the code
3923 * path, and the fact that the manifests pg is a service
3924 * level property group only.
3926 ud_mfsts_pg
= scf_pg_create(g_hndl
);
3927 ud_prop
= scf_property_create(g_hndl
);
3928 ud_prop_iter
= scf_iter_create(g_hndl
);
3929 fname_value
= scf_value_create(g_hndl
);
3931 /* Fetch the "manifests" property group */
3933 r
= entity_get_pg(ent
, issvc
, SCF_PG_MANIFESTFILES
,
3936 switch (scf_error()) {
3937 case SCF_ERROR_NOT_FOUND
:
3941 case SCF_ERROR_DELETED
:
3942 case SCF_ERROR_CONNECTION_BROKEN
:
3943 return (scferror2errno(scf_error()));
3945 case SCF_ERROR_NOT_SET
:
3946 case SCF_ERROR_INVALID_ARGUMENT
:
3947 case SCF_ERROR_HANDLE_MISMATCH
:
3948 case SCF_ERROR_NOT_BOUND
:
3950 bad_error(running
? "scf_snaplevel_get_pg" :
3951 "entity_get_pg", scf_error());
3955 if (no_upgrade_pg
) {
3956 cbdata
.sc_handle
= g_hndl
;
3957 cbdata
.sc_parent
= ent
;
3958 cbdata
.sc_service
= issvc
;
3959 cbdata
.sc_flags
= SCI_FORCE
;
3960 cbdata
.sc_source_fmri
= ient
->sc_fmri
;
3961 cbdata
.sc_target_fmri
= ient
->sc_fmri
;
3963 if (entity_pgroup_import(pg
, &cbdata
) != UU_WALK_NEXT
)
3964 return (cbdata
.sc_err
);
3969 /* Fetch the new manifests property group */
3970 mfst_pgroup
= internal_pgroup_find_or_create(ient
,
3971 SCF_PG_MANIFESTFILES
, SCF_GROUP_FRAMEWORK
);
3972 assert(mfst_pgroup
!= NULL
);
3974 if ((r
= scf_iter_pg_properties(ud_prop_iter
, ud_mfsts_pg
)) !=
3978 if ((pname
= malloc(MAXPATHLEN
)) == NULL
)
3980 if ((fval
= malloc(MAXPATHLEN
)) == NULL
) {
3985 while ((r
= scf_iter_next_property(ud_prop_iter
, ud_prop
)) == 1) {
3987 if (scf_property_get_name(ud_prop
, pname
, MAXPATHLEN
) < 0)
3990 for (mfst_prop
= uu_list_first(mfst_pgroup
->sc_pgroup_props
);
3992 mfst_prop
= uu_list_next(mfst_pgroup
->sc_pgroup_props
,
3994 if (strcmp(mfst_prop
->sc_property_name
, pname
) == 0) {
4000 * If the manifest is not seen then add it to the new mfst
4001 * property list to get proccessed into the repo.
4003 if (mfst_seen
== 0) {
4005 * If we cannot get the value then there is no
4006 * reason to attempt to attach the value to
4007 * the property group
4009 if (prop_get_val(ud_prop
, fname_value
) == 0 &&
4010 scf_value_get_astring(fname_value
, fval
,
4011 MAXPATHLEN
) != -1) {
4012 old_pname
= safe_strdup(pname
);
4013 old_fval
= safe_strdup(fval
);
4014 old_prop
= internal_property_create(old_pname
,
4015 SCF_TYPE_ASTRING
, 1, old_fval
);
4018 * Already checked to see if the property exists
4019 * in the group, and it does not.
4021 (void) internal_attach_property(mfst_pgroup
,
4029 cbdata
.sc_handle
= g_hndl
;
4030 cbdata
.sc_parent
= ent
;
4031 cbdata
.sc_service
= issvc
;
4032 cbdata
.sc_flags
= SCI_FORCE
;
4033 cbdata
.sc_source_fmri
= ient
->sc_fmri
;
4034 cbdata
.sc_target_fmri
= ient
->sc_fmri
;
4036 if (entity_pgroup_import(mfst_pgroup
, &cbdata
) != UU_WALK_NEXT
)
4037 return (cbdata
.sc_err
);
4043 * prop is taken to be a property in the "dependents" property group of snpl,
4044 * which is taken to be the snaplevel of a last-import snapshot corresponding
4045 * to ient. If prop is a valid dependents property, upgrade the dependent it
4046 * represents according to the repository & ient. If ud_run_dpts_pg_set is
4047 * true, then ud_run_dpts_pg is taken to be the "dependents" property group
4048 * of the entity ient represents (possibly in the running snapshot). If it
4049 * needs to be changed, an entry will be added to tx, if not NULL.
4053 * ECONNABORTED - repository connection broken
4054 * ENOMEM - out of memory
4055 * ENOSPC - configd was out of resources
4056 * ECANCELED - snpl's entity was deleted
4057 * EINVAL - dependent target is invalid (error printed)
4058 * - dependent is invalid (error printed)
4059 * EBADF - snpl is corrupt (error printed)
4060 * - snpl has corrupt pg (error printed)
4061 * - dependency pg in target is corrupt (error printed)
4062 * - running snapshot in dependent is missing snaplevel (error printed)
4063 * EPERM - couldn't delete dependency pg (permission denied) (error printed)
4064 * - couldn't create dependent (permission denied) (error printed)
4065 * - couldn't modify dependent pg (permission denied) (error printed)
4066 * EROFS - couldn't delete dependency pg (repository read-only)
4067 * - couldn't create dependent (repository read-only)
4068 * EACCES - couldn't delete dependency pg (backend access denied)
4069 * - couldn't create dependent (backend access denied)
4070 * EBUSY - ud_run_dpts_pg was deleted (error printed)
4071 * - tx's pg was deleted (error printed)
4072 * - dependent pg was changed or deleted (error printed)
4073 * EEXIST - dependency pg already exists in new target (error printed)
4076 upgrade_dependent(const scf_property_t
*prop
, const entity_t
*ient
,
4077 const scf_snaplevel_t
*snpl
, scf_transaction_t
*tx
)
4081 pgroup_t
*new_dpt_pgroup
;
4082 pgroup_t
*old_dpt_pgroup
= NULL
;
4083 pgroup_t
*current_pg
;
4085 scf_callback_t cbdata
;
4090 scf_transaction_entry_t
*ent
;
4092 const char * const cf_inval
= gettext("Conflict upgrading %s "
4093 "(dependent \"%s\" has invalid dependents property).\n");
4094 const char * const cf_missing
= gettext("Conflict upgrading %s "
4095 "(dependent \"%s\" is missing).\n");
4096 const char * const cf_newdpg
= gettext("Conflict upgrading %s "
4097 "(dependent \"%s\" has new dependency property group).\n");
4098 const char * const cf_newtarg
= gettext("Conflict upgrading %s "
4099 "(dependent \"%s\" has new target).\n");
4100 const char * const li_corrupt
=
4101 gettext("%s: \"last-import\" snapshot is corrupt.\n");
4102 const char * const upgrading
=
4103 gettext("%s: Upgrading dependent \"%s\".\n");
4104 const char * const r_no_lvl
= gettext("%s: \"running\" snapshot is "
4105 "corrupt (missing snaplevel).\n");
4107 if (scf_property_type(prop
, &ty
) != 0) {
4108 switch (scf_error()) {
4109 case SCF_ERROR_DELETED
:
4110 case SCF_ERROR_CONNECTION_BROKEN
:
4111 return (scferror2errno(scf_error()));
4113 case SCF_ERROR_NOT_BOUND
:
4114 case SCF_ERROR_NOT_SET
:
4116 bad_error("scf_property_type", scf_error());
4120 if (!(ty
== SCF_TYPE_FMRI
|| ty
== SCF_TYPE_ASTRING
)) {
4121 warn(li_corrupt
, ient
->sc_fmri
);
4126 * prop represents a dependent in the old manifest. It is named after
4129 if (scf_property_get_name(prop
, ud_name
, max_scf_name_len
+ 1) < 0) {
4130 switch (scf_error()) {
4131 case SCF_ERROR_DELETED
:
4132 case SCF_ERROR_CONNECTION_BROKEN
:
4133 return (scferror2errno(scf_error()));
4135 case SCF_ERROR_NOT_BOUND
:
4136 case SCF_ERROR_NOT_SET
:
4138 bad_error("scf_property_get_name", scf_error());
4142 /* See if it's in the new manifest. */
4143 pgrp
.sc_pgroup_name
= ud_name
;
4145 uu_list_find(ient
->sc_dependents
, &pgrp
, NULL
, UU_DEFAULT
);
4147 /* If it's not, delete it... if it hasn't been customized. */
4148 if (new_dpt_pgroup
== NULL
) {
4149 if (!ud_run_dpts_pg_set
)
4152 if (scf_property_get_value(prop
, ud_val
) != 0) {
4153 switch (scf_error()) {
4154 case SCF_ERROR_NOT_FOUND
:
4155 case SCF_ERROR_CONSTRAINT_VIOLATED
:
4156 warn(li_corrupt
, ient
->sc_fmri
);
4159 case SCF_ERROR_DELETED
:
4160 case SCF_ERROR_CONNECTION_BROKEN
:
4161 return (scferror2errno(scf_error()));
4163 case SCF_ERROR_HANDLE_MISMATCH
:
4164 case SCF_ERROR_NOT_BOUND
:
4165 case SCF_ERROR_NOT_SET
:
4166 case SCF_ERROR_PERMISSION_DENIED
:
4168 bad_error("scf_property_get_value",
4173 if (scf_value_get_as_string(ud_val
, ud_oldtarg
,
4174 max_scf_value_len
+ 1) < 0)
4175 bad_error("scf_value_get_as_string", scf_error());
4177 if (scf_pg_get_property(ud_run_dpts_pg
, ud_name
, ud_prop
) !=
4179 switch (scf_error()) {
4180 case SCF_ERROR_NOT_FOUND
:
4183 case SCF_ERROR_CONNECTION_BROKEN
:
4184 return (scferror2errno(scf_error()));
4186 case SCF_ERROR_DELETED
:
4187 warn(emsg_pg_deleted
, ient
->sc_fmri
,
4191 case SCF_ERROR_INVALID_ARGUMENT
:
4192 case SCF_ERROR_NOT_BOUND
:
4193 case SCF_ERROR_HANDLE_MISMATCH
:
4194 case SCF_ERROR_NOT_SET
:
4196 bad_error("scf_pg_get_property", scf_error());
4199 if (scf_property_get_value(ud_prop
, ud_val
) != 0) {
4200 switch (scf_error()) {
4201 case SCF_ERROR_NOT_FOUND
:
4202 case SCF_ERROR_CONSTRAINT_VIOLATED
:
4203 warn(cf_inval
, ient
->sc_fmri
, ud_name
);
4206 case SCF_ERROR_DELETED
:
4207 case SCF_ERROR_CONNECTION_BROKEN
:
4208 return (scferror2errno(scf_error()));
4210 case SCF_ERROR_HANDLE_MISMATCH
:
4211 case SCF_ERROR_NOT_BOUND
:
4212 case SCF_ERROR_NOT_SET
:
4213 case SCF_ERROR_PERMISSION_DENIED
:
4215 bad_error("scf_property_get_value",
4220 ty
= scf_value_type(ud_val
);
4221 assert(ty
!= SCF_TYPE_INVALID
);
4222 if (!(ty
== SCF_TYPE_FMRI
|| ty
== SCF_TYPE_ASTRING
)) {
4223 warn(cf_inval
, ient
->sc_fmri
, ud_name
);
4227 if (scf_value_get_as_string(ud_val
, ud_ctarg
,
4228 max_scf_value_len
+ 1) < 0)
4229 bad_error("scf_value_get_as_string", scf_error());
4231 r
= fmri_equal(ud_ctarg
, ud_oldtarg
);
4237 case -1: /* warn? */
4238 warn(cf_newtarg
, ient
->sc_fmri
, ud_name
);
4242 warn(li_corrupt
, ient
->sc_fmri
);
4246 bad_error("fmri_equal", r
);
4249 if (scf_snaplevel_get_pg(snpl
, ud_name
, ud_pg
) != 0) {
4250 switch (scf_error()) {
4251 case SCF_ERROR_NOT_FOUND
:
4252 warn(li_corrupt
, ient
->sc_fmri
);
4255 case SCF_ERROR_DELETED
:
4256 case SCF_ERROR_CONNECTION_BROKEN
:
4257 return (scferror2errno(scf_error()));
4259 case SCF_ERROR_NOT_BOUND
:
4260 case SCF_ERROR_HANDLE_MISMATCH
:
4261 case SCF_ERROR_INVALID_ARGUMENT
:
4262 case SCF_ERROR_NOT_SET
:
4264 bad_error("scf_snaplevel_get_pg", scf_error());
4268 r
= load_pg(ud_pg
, &old_dpt_pgroup
, ient
->sc_fmri
,
4282 bad_error("load_pg", r
);
4285 serr
= fmri_to_entity(g_hndl
, ud_ctarg
, &target_ent
, &tissvc
);
4287 case SCF_ERROR_NONE
:
4290 case SCF_ERROR_NO_MEMORY
:
4291 internal_pgroup_free(old_dpt_pgroup
);
4294 case SCF_ERROR_NOT_FOUND
:
4295 internal_pgroup_free(old_dpt_pgroup
);
4298 case SCF_ERROR_CONSTRAINT_VIOLATED
: /* caught above */
4299 case SCF_ERROR_INVALID_ARGUMENT
: /* caught above */
4301 bad_error("fmri_to_entity", serr
);
4304 r
= entity_get_running_pg(target_ent
, tissvc
, ud_name
,
4305 ud_pg
, ud_iter2
, ud_inst
, imp_snap
, ud_snpl
);
4311 internal_pgroup_free(old_dpt_pgroup
);
4316 internal_pgroup_free(old_dpt_pgroup
);
4320 warn(r_no_lvl
, ud_ctarg
);
4321 internal_pgroup_free(old_dpt_pgroup
);
4326 bad_error("entity_get_running_pg", r
);
4330 r
= load_pg(ud_pg
, ¤t_pg
, ud_ctarg
, NULL
);
4336 internal_pgroup_free(old_dpt_pgroup
);
4342 internal_pgroup_free(old_dpt_pgroup
);
4347 bad_error("load_pg", r
);
4350 /* compare property groups */
4351 if (!pg_equal(old_dpt_pgroup
, current_pg
)) {
4352 warn(cf_newdpg
, ient
->sc_fmri
, ud_name
);
4353 internal_pgroup_free(old_dpt_pgroup
);
4354 internal_pgroup_free(current_pg
);
4358 internal_pgroup_free(old_dpt_pgroup
);
4359 internal_pgroup_free(current_pg
);
4362 warn(gettext("%s: Deleting dependent \"%s\".\n"),
4363 ient
->sc_fmri
, ud_name
);
4365 if (entity_get_pg(target_ent
, tissvc
, ud_name
, ud_pg
) != 0) {
4366 switch (scf_error()) {
4367 case SCF_ERROR_NOT_FOUND
:
4368 case SCF_ERROR_DELETED
:
4369 internal_pgroup_free(old_dpt_pgroup
);
4372 case SCF_ERROR_CONNECTION_BROKEN
:
4373 internal_pgroup_free(old_dpt_pgroup
);
4374 return (ECONNABORTED
);
4376 case SCF_ERROR_NOT_SET
:
4377 case SCF_ERROR_INVALID_ARGUMENT
:
4378 case SCF_ERROR_HANDLE_MISMATCH
:
4379 case SCF_ERROR_NOT_BOUND
:
4381 bad_error("entity_get_pg", scf_error());
4385 if (scf_pg_delete(ud_pg
) != 0) {
4386 switch (scf_error()) {
4387 case SCF_ERROR_DELETED
:
4390 case SCF_ERROR_CONNECTION_BROKEN
:
4391 case SCF_ERROR_BACKEND_READONLY
:
4392 case SCF_ERROR_BACKEND_ACCESS
:
4393 return (scferror2errno(scf_error()));
4395 case SCF_ERROR_PERMISSION_DENIED
:
4396 warn(emsg_pg_del_perm
, ud_name
, ient
->sc_fmri
);
4397 return (scferror2errno(scf_error()));
4399 case SCF_ERROR_NOT_SET
:
4401 bad_error("scf_pg_delete", scf_error());
4406 * This service was changed, so it must be refreshed. But
4407 * since it's not mentioned in the new manifest, we have to
4408 * record its FMRI here for use later. We record the name
4409 * & the entity (via sc_parent) in case we need to print error
4410 * messages during the refresh.
4412 dpt
= internal_pgroup_new();
4415 dpt
->sc_pgroup_name
= strdup(ud_name
);
4416 dpt
->sc_pgroup_fmri
= strdup(ud_ctarg
);
4417 if (dpt
->sc_pgroup_name
== NULL
|| dpt
->sc_pgroup_fmri
== NULL
)
4419 dpt
->sc_parent
= (entity_t
*)ient
;
4420 if (uu_list_insert_after(imp_deleted_dpts
, NULL
, dpt
) != 0)
4421 uu_die(gettext("libuutil error: %s\n"),
4422 uu_strerror(uu_error()));
4428 ent
= scf_entry_create(g_hndl
);
4432 if (scf_transaction_property_delete(tx
, ent
, ud_name
) != 0) {
4433 scf_entry_destroy(ent
);
4434 switch (scf_error()) {
4435 case SCF_ERROR_DELETED
:
4436 warn(emsg_pg_deleted
, ient
->sc_fmri
,
4440 case SCF_ERROR_CONNECTION_BROKEN
:
4441 return (scferror2errno(scf_error()));
4443 case SCF_ERROR_NOT_FOUND
:
4446 case SCF_ERROR_HANDLE_MISMATCH
:
4447 case SCF_ERROR_NOT_BOUND
:
4448 case SCF_ERROR_INVALID_ARGUMENT
:
4449 case SCF_ERROR_NOT_SET
:
4451 bad_error("scf_transaction_property_delete",
4459 new_dpt_pgroup
->sc_pgroup_seen
= 1;
4462 * Decide whether the dependent has changed in the manifest.
4464 /* Compare the target. */
4465 if (scf_property_get_value(prop
, ud_val
) != 0) {
4466 switch (scf_error()) {
4467 case SCF_ERROR_NOT_FOUND
:
4468 case SCF_ERROR_CONSTRAINT_VIOLATED
:
4469 warn(li_corrupt
, ient
->sc_fmri
);
4472 case SCF_ERROR_DELETED
:
4473 case SCF_ERROR_CONNECTION_BROKEN
:
4474 return (scferror2errno(scf_error()));
4476 case SCF_ERROR_HANDLE_MISMATCH
:
4477 case SCF_ERROR_NOT_BOUND
:
4478 case SCF_ERROR_NOT_SET
:
4479 case SCF_ERROR_PERMISSION_DENIED
:
4481 bad_error("scf_property_get_value", scf_error());
4485 if (scf_value_get_as_string(ud_val
, ud_oldtarg
, max_scf_value_len
+ 1) <
4487 bad_error("scf_value_get_as_string", scf_error());
4490 * If the fmri's are not equal then the old fmri will need to
4491 * be refreshed to ensure that the changes are properly updated
4494 r
= fmri_equal(ud_oldtarg
, new_dpt_pgroup
->sc_pgroup_fmri
);
4497 dpt
= internal_pgroup_new();
4500 dpt
->sc_pgroup_name
= strdup(ud_name
);
4501 dpt
->sc_pgroup_fmri
= strdup(ud_oldtarg
);
4502 if (dpt
->sc_pgroup_name
== NULL
|| dpt
->sc_pgroup_fmri
== NULL
)
4504 dpt
->sc_parent
= (entity_t
*)ient
;
4505 if (uu_list_insert_after(imp_deleted_dpts
, NULL
, dpt
) != 0)
4506 uu_die(gettext("libuutil error: %s\n"),
4507 uu_strerror(uu_error()));
4511 /* Compare the dependency pgs. */
4512 if (scf_snaplevel_get_pg(snpl
, ud_name
, ud_pg
) != 0) {
4513 switch (scf_error()) {
4514 case SCF_ERROR_NOT_FOUND
:
4515 warn(li_corrupt
, ient
->sc_fmri
);
4518 case SCF_ERROR_DELETED
:
4519 case SCF_ERROR_CONNECTION_BROKEN
:
4520 return (scferror2errno(scf_error()));
4522 case SCF_ERROR_NOT_BOUND
:
4523 case SCF_ERROR_HANDLE_MISMATCH
:
4524 case SCF_ERROR_INVALID_ARGUMENT
:
4525 case SCF_ERROR_NOT_SET
:
4527 bad_error("scf_snaplevel_get_pg", scf_error());
4531 r
= load_pg(ud_pg
, &old_dpt_pgroup
, ient
->sc_fmri
,
4545 bad_error("load_pg", r
);
4548 if (pg_equal(old_dpt_pgroup
, new_dpt_pgroup
)) {
4549 /* no change, leave customizations */
4550 internal_pgroup_free(old_dpt_pgroup
);
4556 warn(li_corrupt
, ient
->sc_fmri
);
4560 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4561 ud_name
, new_dpt_pgroup
->sc_pgroup_fmri
);
4565 bad_error("fmri_equal", r
);
4569 * The dependent has changed in the manifest. Upgrade the current
4570 * properties if they haven't been customized.
4574 * If new_dpt_pgroup->sc_override, then act as though the property
4575 * group hasn't been customized.
4577 if (new_dpt_pgroup
->sc_pgroup_override
) {
4578 (void) strcpy(ud_ctarg
, ud_oldtarg
);
4582 if (!ud_run_dpts_pg_set
) {
4583 warn(cf_missing
, ient
->sc_fmri
, ud_name
);
4586 } else if (scf_pg_get_property(ud_run_dpts_pg
, ud_name
, ud_prop
) != 0) {
4587 switch (scf_error()) {
4588 case SCF_ERROR_NOT_FOUND
:
4589 warn(cf_missing
, ient
->sc_fmri
, ud_name
);
4593 case SCF_ERROR_CONNECTION_BROKEN
:
4594 r
= scferror2errno(scf_error());
4597 case SCF_ERROR_DELETED
:
4598 warn(emsg_pg_deleted
, ient
->sc_fmri
, "dependents");
4602 case SCF_ERROR_INVALID_ARGUMENT
:
4603 case SCF_ERROR_NOT_BOUND
:
4604 case SCF_ERROR_HANDLE_MISMATCH
:
4605 case SCF_ERROR_NOT_SET
:
4607 bad_error("scf_pg_get_property", scf_error());
4611 if (scf_property_get_value(ud_prop
, ud_val
) != 0) {
4612 switch (scf_error()) {
4613 case SCF_ERROR_NOT_FOUND
:
4614 case SCF_ERROR_CONSTRAINT_VIOLATED
:
4615 warn(cf_inval
, ient
->sc_fmri
, ud_name
);
4619 case SCF_ERROR_DELETED
:
4620 case SCF_ERROR_CONNECTION_BROKEN
:
4621 r
= scferror2errno(scf_error());
4624 case SCF_ERROR_HANDLE_MISMATCH
:
4625 case SCF_ERROR_NOT_BOUND
:
4626 case SCF_ERROR_NOT_SET
:
4627 case SCF_ERROR_PERMISSION_DENIED
:
4629 bad_error("scf_property_get_value", scf_error());
4633 ty
= scf_value_type(ud_val
);
4634 assert(ty
!= SCF_TYPE_INVALID
);
4635 if (!(ty
== SCF_TYPE_FMRI
|| ty
== SCF_TYPE_ASTRING
)) {
4636 warn(cf_inval
, ient
->sc_fmri
, ud_name
);
4640 if (scf_value_get_as_string(ud_val
, ud_ctarg
, max_scf_value_len
+ 1) <
4642 bad_error("scf_value_get_as_string", scf_error());
4644 r
= fmri_equal(ud_ctarg
, ud_oldtarg
);
4646 warn(cf_inval
, ient
->sc_fmri
, ud_name
);
4649 } else if (r
== -2) {
4650 warn(li_corrupt
, ient
->sc_fmri
);
4653 } else if (r
== 0) {
4655 * Target has been changed. Only abort now if it's been
4656 * changed to something other than what's in the manifest.
4658 r
= fmri_equal(ud_ctarg
, new_dpt_pgroup
->sc_pgroup_fmri
);
4660 warn(cf_inval
, ient
->sc_fmri
, ud_name
);
4663 } else if (r
== 0) {
4664 warn(cf_newtarg
, ient
->sc_fmri
, ud_name
);
4667 } else if (r
!= 1) {
4668 /* invalid sc_pgroup_fmri caught above */
4669 bad_error("fmri_equal", r
);
4673 * Fetch the current dependency pg. If it's what the manifest
4674 * says, then no problem.
4676 serr
= fmri_to_entity(g_hndl
, ud_ctarg
, &target_ent
, &tissvc
);
4678 case SCF_ERROR_NONE
:
4681 case SCF_ERROR_NOT_FOUND
:
4682 warn(cf_missing
, ient
->sc_fmri
, ud_name
);
4686 case SCF_ERROR_NO_MEMORY
:
4690 case SCF_ERROR_CONSTRAINT_VIOLATED
:
4691 case SCF_ERROR_INVALID_ARGUMENT
:
4693 bad_error("fmri_to_entity", serr
);
4696 r
= entity_get_running_pg(target_ent
, tissvc
, ud_name
,
4697 ud_pg
, ud_iter2
, ud_inst
, imp_snap
, ud_snpl
);
4707 warn(cf_missing
, ient
->sc_fmri
, ud_name
);
4712 warn(r_no_lvl
, ud_ctarg
);
4717 bad_error("entity_get_running_pg", r
);
4720 r
= load_pg(ud_pg
, ¤t_pg
, ud_ctarg
, NULL
);
4726 warn(cf_missing
, ient
->sc_fmri
, ud_name
);
4737 bad_error("load_pg", r
);
4740 if (!pg_equal(current_pg
, new_dpt_pgroup
))
4741 warn(cf_newdpg
, ient
->sc_fmri
, ud_name
);
4742 internal_pgroup_free(current_pg
);
4745 } else if (r
!= 1) {
4746 bad_error("fmri_equal", r
);
4751 * Target has not been customized. Check the dependency property
4755 if (old_dpt_pgroup
== NULL
) {
4756 if (scf_snaplevel_get_pg(snpl
, new_dpt_pgroup
->sc_pgroup_name
,
4758 switch (scf_error()) {
4759 case SCF_ERROR_NOT_FOUND
:
4760 warn(li_corrupt
, ient
->sc_fmri
);
4763 case SCF_ERROR_DELETED
:
4764 case SCF_ERROR_CONNECTION_BROKEN
:
4765 return (scferror2errno(scf_error()));
4767 case SCF_ERROR_NOT_BOUND
:
4768 case SCF_ERROR_HANDLE_MISMATCH
:
4769 case SCF_ERROR_INVALID_ARGUMENT
:
4770 case SCF_ERROR_NOT_SET
:
4772 bad_error("scf_snaplevel_get_pg", scf_error());
4776 r
= load_pg(ud_pg
, &old_dpt_pgroup
, ient
->sc_fmri
,
4790 bad_error("load_pg", r
);
4793 serr
= fmri_to_entity(g_hndl
, ud_ctarg
, &target_ent
, &tissvc
);
4795 case SCF_ERROR_NONE
:
4798 case SCF_ERROR_NOT_FOUND
:
4799 warn(cf_missing
, ient
->sc_fmri
, ud_name
);
4803 case SCF_ERROR_NO_MEMORY
:
4807 case SCF_ERROR_CONSTRAINT_VIOLATED
:
4808 case SCF_ERROR_INVALID_ARGUMENT
:
4810 bad_error("fmri_to_entity", serr
);
4813 r
= entity_get_running_pg(target_ent
, tissvc
, ud_name
, ud_pg
,
4814 ud_iter2
, ud_inst
, imp_snap
, ud_snpl
);
4824 warn(cf_missing
, ient
->sc_fmri
, ud_name
);
4829 warn(r_no_lvl
, ud_ctarg
);
4834 bad_error("entity_get_running_pg", r
);
4837 r
= load_pg(ud_pg
, ¤t_pg
, ud_ctarg
, NULL
);
4843 warn(cf_missing
, ient
->sc_fmri
, ud_name
);
4853 bad_error("load_pg", r
);
4856 if (!pg_equal(current_pg
, old_dpt_pgroup
)) {
4857 if (!pg_equal(current_pg
, new_dpt_pgroup
))
4858 warn(cf_newdpg
, ient
->sc_fmri
, ud_name
);
4859 internal_pgroup_free(current_pg
);
4864 /* Uncustomized. Upgrade. */
4866 r
= fmri_equal(new_dpt_pgroup
->sc_pgroup_fmri
, ud_oldtarg
);
4869 if (pg_equal(current_pg
, new_dpt_pgroup
)) {
4870 /* Already upgraded. */
4871 internal_pgroup_free(current_pg
);
4876 internal_pgroup_free(current_pg
);
4878 /* upgrade current_pg */
4879 if (entity_get_pg(target_ent
, tissvc
, ud_name
, ud_pg
) != 0) {
4880 switch (scf_error()) {
4881 case SCF_ERROR_CONNECTION_BROKEN
:
4882 r
= scferror2errno(scf_error());
4885 case SCF_ERROR_DELETED
:
4886 warn(cf_missing
, ient
->sc_fmri
, ud_name
);
4890 case SCF_ERROR_NOT_FOUND
:
4893 case SCF_ERROR_INVALID_ARGUMENT
:
4894 case SCF_ERROR_NOT_BOUND
:
4895 case SCF_ERROR_NOT_SET
:
4896 case SCF_ERROR_HANDLE_MISMATCH
:
4898 bad_error("entity_get_pg", scf_error());
4902 r
= scf_service_add_pg(target_ent
, ud_name
,
4903 SCF_GROUP_DEPENDENCY
, 0, ud_pg
);
4905 r
= scf_instance_add_pg(target_ent
, ud_name
,
4906 SCF_GROUP_DEPENDENCY
, 0, ud_pg
);
4908 switch (scf_error()) {
4909 case SCF_ERROR_CONNECTION_BROKEN
:
4910 case SCF_ERROR_NO_RESOURCES
:
4911 case SCF_ERROR_BACKEND_READONLY
:
4912 case SCF_ERROR_BACKEND_ACCESS
:
4913 r
= scferror2errno(scf_error());
4916 case SCF_ERROR_DELETED
:
4917 warn(cf_missing
, ient
->sc_fmri
,
4922 case SCF_ERROR_PERMISSION_DENIED
:
4923 warn(emsg_pg_deleted
, ud_ctarg
,
4928 case SCF_ERROR_EXISTS
:
4929 warn(emsg_pg_added
, ud_ctarg
, ud_name
);
4933 case SCF_ERROR_NOT_BOUND
:
4934 case SCF_ERROR_HANDLE_MISMATCH
:
4935 case SCF_ERROR_INVALID_ARGUMENT
:
4936 case SCF_ERROR_NOT_SET
:
4938 bad_error("entity_add_pg", scf_error());
4943 r
= load_pg(ud_pg
, ¤t_pg
, ud_ctarg
, NULL
);
4949 warn(cf_missing
, ient
->sc_fmri
, ud_name
);
4959 bad_error("load_pg", r
);
4963 warn(upgrading
, ient
->sc_fmri
, ud_name
);
4965 r
= upgrade_pg(ud_pg
, current_pg
, old_dpt_pgroup
,
4966 new_dpt_pgroup
, 0, ient
->sc_fmri
);
4972 warn(emsg_pg_deleted
, ud_ctarg
, ud_name
);
4977 warn(emsg_pg_mod_perm
, ud_name
, ud_ctarg
);
4981 warn(emsg_pg_changed
, ud_ctarg
, ud_name
);
4993 bad_error("upgrade_pg", r
);
4998 scf_transaction_entry_t
*ent
;
5001 internal_pgroup_free(current_pg
);
5005 warn(upgrading
, ient
->sc_fmri
, ud_name
);
5007 if (entity_get_pg(target_ent
, tissvc
, ud_name
, ud_pg
) != 0) {
5008 switch (scf_error()) {
5009 case SCF_ERROR_CONNECTION_BROKEN
:
5010 r
= scferror2errno(scf_error());
5013 case SCF_ERROR_DELETED
:
5014 warn(cf_missing
, ient
->sc_fmri
, ud_name
);
5018 case SCF_ERROR_NOT_FOUND
:
5021 case SCF_ERROR_INVALID_ARGUMENT
:
5022 case SCF_ERROR_NOT_BOUND
:
5023 case SCF_ERROR_NOT_SET
:
5024 case SCF_ERROR_HANDLE_MISMATCH
:
5026 bad_error("entity_get_pg", scf_error());
5028 } else if (scf_pg_delete(ud_pg
) != 0) {
5029 switch (scf_error()) {
5030 case SCF_ERROR_DELETED
:
5033 case SCF_ERROR_CONNECTION_BROKEN
:
5034 case SCF_ERROR_BACKEND_READONLY
:
5035 case SCF_ERROR_BACKEND_ACCESS
:
5036 r
= scferror2errno(scf_error());
5039 case SCF_ERROR_PERMISSION_DENIED
:
5040 warn(emsg_pg_del_perm
, ud_name
, ient
->sc_fmri
);
5041 r
= scferror2errno(scf_error());
5044 case SCF_ERROR_NOT_SET
:
5046 bad_error("scf_pg_delete", scf_error());
5050 /* import new one */
5051 cbdata
.sc_handle
= g_hndl
;
5052 cbdata
.sc_trans
= NULL
; /* handled below */
5053 cbdata
.sc_flags
= 0;
5055 r
= lscf_dependent_import(new_dpt_pgroup
, &cbdata
);
5056 if (r
!= UU_WALK_NEXT
) {
5057 if (r
!= UU_WALK_ERROR
)
5058 bad_error("lscf_dependent_import", r
);
5067 if ((ent
= scf_entry_create(g_hndl
)) == NULL
||
5068 (val
= scf_value_create(g_hndl
)) == NULL
) {
5069 if (scf_error() == SCF_ERROR_NO_MEMORY
)
5072 bad_error("scf_entry_create", scf_error());
5075 if (scf_transaction_property_change_type(tx
, ent
, ud_name
,
5076 SCF_TYPE_FMRI
) != 0) {
5077 switch (scf_error()) {
5078 case SCF_ERROR_CONNECTION_BROKEN
:
5079 r
= scferror2errno(scf_error());
5082 case SCF_ERROR_DELETED
:
5083 warn(emsg_pg_deleted
, ient
->sc_fmri
,
5088 case SCF_ERROR_NOT_FOUND
:
5091 case SCF_ERROR_NOT_BOUND
:
5092 case SCF_ERROR_HANDLE_MISMATCH
:
5093 case SCF_ERROR_INVALID_ARGUMENT
:
5094 case SCF_ERROR_NOT_SET
:
5096 bad_error("scf_transaction_property_"
5097 "change_type", scf_error());
5100 if (scf_transaction_property_new(tx
, ent
, ud_name
,
5101 SCF_TYPE_FMRI
) != 0) {
5102 switch (scf_error()) {
5103 case SCF_ERROR_CONNECTION_BROKEN
:
5104 r
= scferror2errno(scf_error());
5107 case SCF_ERROR_DELETED
:
5108 warn(emsg_pg_deleted
, ient
->sc_fmri
,
5113 case SCF_ERROR_EXISTS
:
5114 warn(emsg_pg_changed
, ient
->sc_fmri
,
5119 case SCF_ERROR_INVALID_ARGUMENT
:
5120 case SCF_ERROR_HANDLE_MISMATCH
:
5121 case SCF_ERROR_NOT_BOUND
:
5122 case SCF_ERROR_NOT_SET
:
5124 bad_error("scf_transaction_property_"
5125 "new", scf_error());
5130 if (scf_value_set_from_string(val
, SCF_TYPE_FMRI
,
5131 new_dpt_pgroup
->sc_pgroup_fmri
) != 0)
5132 /* invalid sc_pgroup_fmri caught above */
5133 bad_error("scf_value_set_from_string",
5136 if (scf_entry_add_value(ent
, val
) != 0)
5137 bad_error("scf_entry_add_value", scf_error());
5142 warn(li_corrupt
, ient
->sc_fmri
);
5143 internal_pgroup_free(current_pg
);
5149 /* invalid sc_pgroup_fmri caught above */
5150 bad_error("fmri_equal", r
);
5156 if (old_dpt_pgroup
!= NULL
)
5157 internal_pgroup_free(old_dpt_pgroup
);
5163 * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
5164 * would import it, except it seems to exist in the service anyway. Compare
5165 * the existent dependent with the one we would import, and report any
5166 * differences (if there are none, be silent). prop is the property which
5167 * represents the existent dependent (in the dependents property group) in the
5168 * entity corresponding to ient.
5171 * 0 - success (Sort of. At least, we can continue importing.)
5172 * ECONNABORTED - repository connection broken
5173 * EBUSY - ancestor of prop was deleted (error printed)
5174 * ENOMEM - out of memory
5175 * EBADF - corrupt property group (error printed)
5176 * EINVAL - new_dpt_pgroup has invalid target (error printed)
5179 handle_dependent_conflict(const entity_t
* const ient
,
5180 const scf_property_t
* const prop
, const pgroup_t
* const new_dpt_pgroup
)
5189 if (scf_property_get_value(prop
, ud_val
) != 0) {
5190 switch (scf_error()) {
5191 case SCF_ERROR_CONNECTION_BROKEN
:
5192 return (scferror2errno(scf_error()));
5194 case SCF_ERROR_DELETED
:
5195 warn(emsg_pg_deleted
, ient
->sc_fmri
,
5196 new_dpt_pgroup
->sc_pgroup_name
);
5199 case SCF_ERROR_CONSTRAINT_VIOLATED
:
5200 case SCF_ERROR_NOT_FOUND
:
5201 warn(gettext("Conflict upgrading %s (not importing "
5202 "dependent \"%s\" because it already exists.) "
5203 "Warning: The \"%s/%2$s\" property has more or "
5204 "fewer than one value)).\n"), ient
->sc_fmri
,
5205 new_dpt_pgroup
->sc_pgroup_name
, "dependents");
5208 case SCF_ERROR_HANDLE_MISMATCH
:
5209 case SCF_ERROR_NOT_BOUND
:
5210 case SCF_ERROR_NOT_SET
:
5211 case SCF_ERROR_PERMISSION_DENIED
:
5213 bad_error("scf_property_get_value",
5218 ty
= scf_value_type(ud_val
);
5219 assert(ty
!= SCF_TYPE_INVALID
);
5220 if (!(ty
== SCF_TYPE_FMRI
|| ty
== SCF_TYPE_ASTRING
)) {
5221 warn(gettext("Conflict upgrading %s (not importing dependent "
5222 "\"%s\" because it already exists). Warning: The "
5223 "\"%s/%s\" property has unexpected type \"%s\")).\n"),
5224 ient
->sc_fmri
, new_dpt_pgroup
->sc_pgroup_name
,
5225 scf_type_to_string(ty
), "dependents");
5229 if (scf_value_get_as_string(ud_val
, ud_ctarg
, max_scf_value_len
+ 1) <
5231 bad_error("scf_value_get_as_string", scf_error());
5233 r
= fmri_equal(ud_ctarg
, new_dpt_pgroup
->sc_pgroup_fmri
);
5236 warn(gettext("Conflict upgrading %s (not importing dependent "
5237 "\"%s\" (target \"%s\") because it already exists with "
5238 "target \"%s\").\n"), ient
->sc_fmri
,
5239 new_dpt_pgroup
->sc_pgroup_name
,
5240 new_dpt_pgroup
->sc_pgroup_fmri
, ud_ctarg
);
5247 warn(gettext("Conflict upgrading %s (not importing dependent "
5248 "\"%s\" because it already exists). Warning: The current "
5249 "dependent's target (%s) is invalid.\n"), ient
->sc_fmri
,
5250 new_dpt_pgroup
->sc_pgroup_name
, ud_ctarg
);
5254 warn(gettext("Dependent \"%s\" of %s has invalid target "
5255 "\"%s\".\n"), new_dpt_pgroup
->sc_pgroup_name
, ient
->sc_fmri
,
5256 new_dpt_pgroup
->sc_pgroup_fmri
);
5260 bad_error("fmri_equal", r
);
5263 /* compare dependency pgs in target */
5264 scfe
= fmri_to_entity(g_hndl
, ud_ctarg
, &tptr
, &tissvc
);
5266 case SCF_ERROR_NONE
:
5269 case SCF_ERROR_NO_MEMORY
:
5272 case SCF_ERROR_NOT_FOUND
:
5273 warn(emsg_dpt_dangling
, ient
->sc_fmri
,
5274 new_dpt_pgroup
->sc_pgroup_name
, ud_ctarg
);
5277 case SCF_ERROR_CONSTRAINT_VIOLATED
:
5278 case SCF_ERROR_INVALID_ARGUMENT
:
5280 bad_error("fmri_to_entity", scfe
);
5283 r
= entity_get_running_pg(tptr
, tissvc
, new_dpt_pgroup
->sc_pgroup_name
,
5284 ud_pg
, ud_iter
, ud_inst
, imp_snap
, ud_snpl
);
5293 warn(emsg_dpt_dangling
, ient
->sc_fmri
,
5294 new_dpt_pgroup
->sc_pgroup_name
, ud_ctarg
);
5299 warn(gettext("%s has an instance with a \"%s\" "
5300 "snapshot which is missing a snaplevel.\n"),
5301 ud_ctarg
, "running");
5303 warn(gettext("%s has a \"%s\" snapshot which is "
5304 "missing a snaplevel.\n"), ud_ctarg
, "running");
5308 warn(emsg_dpt_no_dep
, ient
->sc_fmri
,
5309 new_dpt_pgroup
->sc_pgroup_name
, ud_ctarg
,
5310 new_dpt_pgroup
->sc_pgroup_name
);
5315 bad_error("entity_get_running_pg", r
);
5318 pgroup
= internal_pgroup_new();
5322 r
= load_pg(ud_pg
, &pgroup
, ud_ctarg
, NULL
);
5330 internal_pgroup_free(pgroup
);
5334 warn(emsg_dpt_no_dep
, ient
->sc_fmri
,
5335 new_dpt_pgroup
->sc_pgroup_name
, ud_ctarg
,
5336 new_dpt_pgroup
->sc_pgroup_name
);
5337 internal_pgroup_free(pgroup
);
5342 bad_error("load_pg", r
);
5345 /* report differences */
5346 report_pg_diffs(new_dpt_pgroup
, pgroup
, ud_ctarg
, 1);
5347 internal_pgroup_free(pgroup
);
5352 * lipg is a property group in the last-import snapshot of ent, which is an
5353 * scf_service_t or an scf_instance_t (according to ient). If lipg is not in
5354 * ient's pgroups, delete it from ent if it hasn't been customized. If it is
5355 * in ents's property groups, compare and upgrade ent appropriately.
5359 * ECONNABORTED - repository connection broken
5360 * ENOMEM - out of memory
5361 * ENOSPC - configd is out of resources
5362 * EINVAL - ient has invalid dependent (error printed)
5363 * - ient has invalid pgroup_t (error printed)
5364 * ECANCELED - ent has been deleted
5365 * ENODEV - entity containing lipg has been deleted
5366 * - entity containing running has been deleted
5367 * EPERM - could not delete pg (permission denied) (error printed)
5368 * - couldn't upgrade dependents (permission denied) (error printed)
5369 * - couldn't import pg (permission denied) (error printed)
5370 * - couldn't upgrade pg (permission denied) (error printed)
5371 * EROFS - could not delete pg (repository read-only)
5372 * - couldn't upgrade dependents (repository read-only)
5373 * - couldn't import pg (repository read-only)
5374 * - couldn't upgrade pg (repository read-only)
5375 * EACCES - could not delete pg (backend access denied)
5376 * - couldn't upgrade dependents (backend access denied)
5377 * - couldn't import pg (backend access denied)
5378 * - couldn't upgrade pg (backend access denied)
5379 * - couldn't read property (backend access denied)
5380 * EBUSY - property group was added (error printed)
5381 * - property group was deleted (error printed)
5382 * - property group changed (error printed)
5383 * - "dependents" pg was added, changed, or deleted (error printed)
5384 * - dependent target deleted (error printed)
5385 * - dependent pg changed (error printed)
5386 * EBADF - imp_snpl is corrupt (error printed)
5387 * - ent has bad pg (error printed)
5388 * EEXIST - dependent collision in target service (error printed)
5391 process_old_pg(const scf_propertygroup_t
*lipg
, entity_t
*ient
, void *ent
,
5392 const scf_snaplevel_t
*running
)
5395 pgroup_t
*mpg
, *lipg_i
, *curpg_i
, pgrp
;
5396 scf_callback_t cbdata
;
5398 const char * const cf_pg_missing
=
5399 gettext("Conflict upgrading %s (property group %s is missing)\n");
5400 const char * const deleting
=
5401 gettext("%s: Deleting property group \"%s\".\n");
5403 const int issvc
= (ient
->sc_etype
== SVCCFG_SERVICE_OBJECT
);
5405 /* Skip dependent property groups. */
5406 if (scf_pg_get_type(lipg
, imp_str
, imp_str_sz
) < 0) {
5407 switch (scf_error()) {
5408 case SCF_ERROR_DELETED
:
5411 case SCF_ERROR_CONNECTION_BROKEN
:
5412 return (ECONNABORTED
);
5414 case SCF_ERROR_NOT_SET
:
5415 case SCF_ERROR_NOT_BOUND
:
5417 bad_error("scf_pg_get_type", scf_error());
5421 if (strcmp(imp_str
, SCF_GROUP_DEPENDENCY
) == 0) {
5422 if (scf_pg_get_property(lipg
, "external", NULL
) == 0)
5425 switch (scf_error()) {
5426 case SCF_ERROR_NOT_FOUND
:
5429 case SCF_ERROR_CONNECTION_BROKEN
:
5430 return (ECONNABORTED
);
5432 case SCF_ERROR_DELETED
:
5435 case SCF_ERROR_INVALID_ARGUMENT
:
5436 case SCF_ERROR_NOT_BOUND
:
5437 case SCF_ERROR_HANDLE_MISMATCH
:
5438 case SCF_ERROR_NOT_SET
:
5440 bad_error("scf_pg_get_property", scf_error());
5444 /* lookup pg in new properties */
5445 if (scf_pg_get_name(lipg
, imp_str
, imp_str_sz
) < 0) {
5446 switch (scf_error()) {
5447 case SCF_ERROR_DELETED
:
5450 case SCF_ERROR_CONNECTION_BROKEN
:
5451 return (ECONNABORTED
);
5453 case SCF_ERROR_NOT_SET
:
5454 case SCF_ERROR_NOT_BOUND
:
5456 bad_error("scf_pg_get_name", scf_error());
5460 pgrp
.sc_pgroup_name
= imp_str
;
5461 mpg
= uu_list_find(ient
->sc_pgroups
, &pgrp
, NULL
, NULL
);
5464 mpg
->sc_pgroup_seen
= 1;
5466 /* Special handling for dependents */
5467 if (strcmp(imp_str
, "dependents") == 0)
5468 return (upgrade_dependents(lipg
, imp_snpl
, ient
, running
, ent
));
5470 if (strcmp(imp_str
, SCF_PG_MANIFESTFILES
) == 0)
5471 return (upgrade_manifestfiles(NULL
, ient
, running
, ent
));
5473 if (mpg
== NULL
|| mpg
->sc_pgroup_delete
) {
5474 /* property group was deleted from manifest */
5475 if (entity_get_pg(ent
, issvc
, imp_str
, imp_pg2
) != 0) {
5476 switch (scf_error()) {
5477 case SCF_ERROR_NOT_FOUND
:
5480 case SCF_ERROR_DELETED
:
5481 case SCF_ERROR_CONNECTION_BROKEN
:
5482 return (scferror2errno(scf_error()));
5484 case SCF_ERROR_INVALID_ARGUMENT
:
5485 case SCF_ERROR_HANDLE_MISMATCH
:
5486 case SCF_ERROR_NOT_BOUND
:
5487 case SCF_ERROR_NOT_SET
:
5489 bad_error("entity_get_pg", scf_error());
5493 if (mpg
!= NULL
&& mpg
->sc_pgroup_delete
) {
5495 warn(deleting
, ient
->sc_fmri
, imp_str
);
5496 if (scf_pg_delete(imp_pg2
) == 0)
5499 switch (scf_error()) {
5500 case SCF_ERROR_DELETED
:
5503 case SCF_ERROR_CONNECTION_BROKEN
:
5504 case SCF_ERROR_BACKEND_READONLY
:
5505 case SCF_ERROR_BACKEND_ACCESS
:
5506 return (scferror2errno(scf_error()));
5508 case SCF_ERROR_PERMISSION_DENIED
:
5509 warn(emsg_pg_del_perm
, imp_str
, ient
->sc_fmri
);
5510 return (scferror2errno(scf_error()));
5512 case SCF_ERROR_NOT_SET
:
5514 bad_error("scf_pg_delete", scf_error());
5518 r
= load_pg(lipg
, &lipg_i
, ient
->sc_fmri
, snap_lastimport
);
5533 bad_error("load_pg", r
);
5536 r
= load_pg(imp_pg2
, &curpg_i
, ient
->sc_fmri
, NULL
);
5546 internal_pgroup_free(lipg_i
);
5550 bad_error("load_pg", r
);
5553 if (pg_equal(lipg_i
, curpg_i
)) {
5555 warn(deleting
, ient
->sc_fmri
, imp_str
);
5556 if (scf_pg_delete(imp_pg2
) != 0) {
5557 switch (scf_error()) {
5558 case SCF_ERROR_DELETED
:
5561 case SCF_ERROR_CONNECTION_BROKEN
:
5562 internal_pgroup_free(lipg_i
);
5563 internal_pgroup_free(curpg_i
);
5564 return (ECONNABORTED
);
5566 case SCF_ERROR_NOT_SET
:
5567 case SCF_ERROR_NOT_BOUND
:
5569 bad_error("scf_pg_delete", scf_error());
5573 report_pg_diffs(lipg_i
, curpg_i
, ient
->sc_fmri
, 0);
5576 internal_pgroup_free(lipg_i
);
5577 internal_pgroup_free(curpg_i
);
5583 * Only dependent pgs can have override set, and we skipped those
5586 assert(!mpg
->sc_pgroup_override
);
5589 r
= load_pg(lipg
, &lipg_i
, ient
->sc_fmri
, snap_lastimport
);
5604 bad_error("load_pg", r
);
5607 if (pg_equal(mpg
, lipg_i
)) {
5608 /* The manifest pg has not changed. Move on. */
5613 /* upgrade current properties according to lipg & mpg */
5614 if (running
!= NULL
)
5615 r
= scf_snaplevel_get_pg(running
, imp_str
, imp_pg2
);
5617 r
= entity_get_pg(ent
, issvc
, imp_str
, imp_pg2
);
5619 switch (scf_error()) {
5620 case SCF_ERROR_CONNECTION_BROKEN
:
5621 r
= scferror2errno(scf_error());
5624 case SCF_ERROR_DELETED
:
5625 if (running
!= NULL
)
5631 case SCF_ERROR_NOT_FOUND
:
5634 case SCF_ERROR_INVALID_ARGUMENT
:
5635 case SCF_ERROR_HANDLE_MISMATCH
:
5636 case SCF_ERROR_NOT_BOUND
:
5637 case SCF_ERROR_NOT_SET
:
5639 bad_error("entity_get_pg", scf_error());
5642 warn(cf_pg_missing
, ient
->sc_fmri
, imp_str
);
5648 r
= load_pg_attrs(imp_pg2
, &curpg_i
);
5654 warn(cf_pg_missing
, ient
->sc_fmri
, imp_str
);
5663 bad_error("load_pg_attrs", r
);
5666 if (!pg_attrs_equal(lipg_i
, curpg_i
, NULL
, 0)) {
5667 (void) pg_attrs_equal(curpg_i
, mpg
, ient
->sc_fmri
, 0);
5668 internal_pgroup_free(curpg_i
);
5673 internal_pgroup_free(curpg_i
);
5675 r
= load_pg(imp_pg2
, &curpg_i
, ient
->sc_fmri
, NULL
);
5681 warn(cf_pg_missing
, ient
->sc_fmri
, imp_str
);
5692 bad_error("load_pg", r
);
5695 if (pg_equal(lipg_i
, curpg_i
) &&
5696 !pg_attrs_equal(lipg_i
, mpg
, NULL
, 0)) {
5700 warn(gettext("%s: Upgrading property group \"%s\".\n"),
5701 ient
->sc_fmri
, mpg
->sc_pgroup_name
);
5703 internal_pgroup_free(curpg_i
);
5705 if (running
!= NULL
&&
5706 entity_get_pg(ent
, issvc
, imp_str
, imp_pg2
) != 0) {
5707 switch (scf_error()) {
5708 case SCF_ERROR_DELETED
:
5712 case SCF_ERROR_NOT_FOUND
:
5716 case SCF_ERROR_CONNECTION_BROKEN
:
5717 r
= scferror2errno(scf_error());
5720 case SCF_ERROR_HANDLE_MISMATCH
:
5721 case SCF_ERROR_INVALID_ARGUMENT
:
5722 case SCF_ERROR_NOT_SET
:
5723 case SCF_ERROR_NOT_BOUND
:
5725 bad_error("entity_get_pg", scf_error());
5729 if (do_delete
&& scf_pg_delete(imp_pg2
) != 0) {
5730 switch (scf_error()) {
5731 case SCF_ERROR_DELETED
:
5734 case SCF_ERROR_CONNECTION_BROKEN
:
5735 case SCF_ERROR_BACKEND_READONLY
:
5736 case SCF_ERROR_BACKEND_ACCESS
:
5737 r
= scferror2errno(scf_error());
5740 case SCF_ERROR_PERMISSION_DENIED
:
5741 warn(emsg_pg_del_perm
, mpg
->sc_pgroup_name
,
5743 r
= scferror2errno(scf_error());
5746 case SCF_ERROR_NOT_SET
:
5747 case SCF_ERROR_NOT_BOUND
:
5749 bad_error("scf_pg_delete", scf_error());
5753 cbdata
.sc_handle
= g_hndl
;
5754 cbdata
.sc_parent
= ent
;
5755 cbdata
.sc_service
= issvc
;
5756 cbdata
.sc_flags
= 0;
5757 cbdata
.sc_source_fmri
= ient
->sc_fmri
;
5758 cbdata
.sc_target_fmri
= ient
->sc_fmri
;
5760 r
= entity_pgroup_import(mpg
, &cbdata
);
5767 if (cbdata
.sc_err
== EEXIST
) {
5768 warn(emsg_pg_added
, ient
->sc_fmri
,
5769 mpg
->sc_pgroup_name
);
5777 bad_error("entity_pgroup_import", r
);
5781 if (running
!= NULL
&&
5782 entity_get_pg(ent
, issvc
, imp_str
, imp_pg2
) != 0) {
5783 switch (scf_error()) {
5784 case SCF_ERROR_CONNECTION_BROKEN
:
5785 case SCF_ERROR_DELETED
:
5786 r
= scferror2errno(scf_error());
5789 case SCF_ERROR_NOT_FOUND
:
5792 case SCF_ERROR_HANDLE_MISMATCH
:
5793 case SCF_ERROR_INVALID_ARGUMENT
:
5794 case SCF_ERROR_NOT_SET
:
5795 case SCF_ERROR_NOT_BOUND
:
5797 bad_error("entity_get_pg", scf_error());
5800 cbdata
.sc_handle
= g_hndl
;
5801 cbdata
.sc_parent
= ent
;
5802 cbdata
.sc_service
= issvc
;
5803 cbdata
.sc_flags
= SCI_FORCE
;
5804 cbdata
.sc_source_fmri
= ient
->sc_fmri
;
5805 cbdata
.sc_target_fmri
= ient
->sc_fmri
;
5807 r
= entity_pgroup_import(mpg
, &cbdata
);
5814 if (cbdata
.sc_err
== EEXIST
) {
5815 warn(emsg_pg_added
, ient
->sc_fmri
,
5816 mpg
->sc_pgroup_name
);
5824 bad_error("entity_pgroup_import", r
);
5828 r
= upgrade_pg(imp_pg2
, curpg_i
, lipg_i
, mpg
, g_verbose
, ient
->sc_fmri
);
5829 internal_pgroup_free(curpg_i
);
5832 ient
->sc_import_state
= IMPORT_PROP_BEGUN
;
5836 warn(emsg_pg_deleted
, ient
->sc_fmri
, mpg
->sc_pgroup_name
);
5841 warn(emsg_pg_mod_perm
, mpg
->sc_pgroup_name
, ient
->sc_fmri
);
5845 warn(emsg_pg_changed
, ient
->sc_fmri
, mpg
->sc_pgroup_name
);
5857 bad_error("upgrade_pg", r
);
5861 internal_pgroup_free(lipg_i
);
5866 * Upgrade the properties of ent according to snpl & ient.
5870 * ECONNABORTED - repository connection broken
5871 * ENOMEM - out of memory
5872 * ENOSPC - configd is out of resources
5873 * ECANCELED - ent was deleted
5874 * ENODEV - entity containing snpl was deleted
5875 * - entity containing running was deleted
5876 * EBADF - imp_snpl is corrupt (error printed)
5877 * - ent has corrupt pg (error printed)
5878 * - dependent has corrupt pg (error printed)
5879 * - dependent target has a corrupt snapshot (error printed)
5880 * EBUSY - pg was added, changed, or deleted (error printed)
5881 * - dependent target was deleted (error printed)
5882 * - dependent pg changed (error printed)
5883 * EINVAL - invalid property group name (error printed)
5884 * - invalid property name (error printed)
5885 * - invalid value (error printed)
5886 * - ient has invalid pgroup or dependent (error printed)
5887 * EPERM - could not create property group (permission denied) (error printed)
5888 * - could not modify property group (permission denied) (error printed)
5889 * - couldn't delete, upgrade, or import pg or dependent (error printed)
5890 * EROFS - could not create property group (repository read-only)
5891 * - couldn't delete, upgrade, or import pg or dependent
5892 * EACCES - could not create property group (backend access denied)
5893 * - couldn't delete, upgrade, or import pg or dependent
5894 * EEXIST - dependent collision in target service (error printed)
5897 upgrade_props(void *ent
, scf_snaplevel_t
*running
, scf_snaplevel_t
*snpl
,
5902 uu_list_t
*pgs
= ient
->sc_pgroups
;
5904 const int issvc
= (ient
->sc_etype
== SVCCFG_SERVICE_OBJECT
);
5906 /* clear sc_sceen for pgs */
5907 if (uu_list_walk(pgs
, clear_int
,
5908 (void *)offsetof(pgroup_t
, sc_pgroup_seen
), UU_DEFAULT
) != 0)
5909 bad_error("uu_list_walk", uu_error());
5911 if (scf_iter_snaplevel_pgs(imp_up_iter
, snpl
) != 0) {
5912 switch (scf_error()) {
5913 case SCF_ERROR_DELETED
:
5916 case SCF_ERROR_CONNECTION_BROKEN
:
5917 return (ECONNABORTED
);
5919 case SCF_ERROR_NOT_SET
:
5920 case SCF_ERROR_NOT_BOUND
:
5921 case SCF_ERROR_HANDLE_MISMATCH
:
5923 bad_error("scf_iter_snaplevel_pgs", scf_error());
5928 r
= scf_iter_next_pg(imp_up_iter
, imp_pg
);
5932 r
= process_old_pg(imp_pg
, ient
, ent
, running
);
5952 bad_error("process_old_pg", r
);
5957 bad_error("scf_iter_next_pg", r
);
5959 switch (scf_error()) {
5960 case SCF_ERROR_DELETED
:
5963 case SCF_ERROR_CONNECTION_BROKEN
:
5964 return (ECONNABORTED
);
5966 case SCF_ERROR_HANDLE_MISMATCH
:
5967 case SCF_ERROR_NOT_BOUND
:
5968 case SCF_ERROR_NOT_SET
:
5969 case SCF_ERROR_INVALID_ARGUMENT
:
5971 bad_error("scf_iter_next_pg", scf_error());
5975 for (pg
= uu_list_first(pgs
); pg
!= NULL
; pg
= uu_list_next(pgs
, pg
)) {
5976 if (pg
->sc_pgroup_seen
)
5981 if (strcmp(pg
->sc_pgroup_name
, "dependents") == 0) {
5982 r
= upgrade_dependents(NULL
, imp_snpl
, ient
, running
,
6003 bad_error("upgrade_dependents", r
);
6008 if (strcmp(pg
->sc_pgroup_name
, SCF_PG_MANIFESTFILES
) == 0) {
6009 r
= upgrade_manifestfiles(pg
, ient
, running
, ent
);
6029 bad_error("upgrade_manifestfiles", r
);
6034 if (running
!= NULL
) {
6035 r
= scf_snaplevel_get_pg(running
, pg
->sc_pgroup_name
,
6038 r
= entity_get_pg(ent
, issvc
, pg
->sc_pgroup_name
,
6042 scf_callback_t cbdata
;
6044 switch (scf_error()) {
6045 case SCF_ERROR_NOT_FOUND
:
6048 case SCF_ERROR_CONNECTION_BROKEN
:
6049 return (scferror2errno(scf_error()));
6051 case SCF_ERROR_DELETED
:
6052 if (running
!= NULL
)
6055 return (scferror2errno(scf_error()));
6057 case SCF_ERROR_INVALID_ARGUMENT
:
6058 warn(emsg_fmri_invalid_pg_name
, ient
->sc_fmri
,
6059 pg
->sc_pgroup_name
);
6062 case SCF_ERROR_NOT_SET
:
6063 case SCF_ERROR_HANDLE_MISMATCH
:
6064 case SCF_ERROR_NOT_BOUND
:
6066 bad_error("entity_get_pg", scf_error());
6069 /* User doesn't have pg, so import it. */
6071 cbdata
.sc_handle
= g_hndl
;
6072 cbdata
.sc_parent
= ent
;
6073 cbdata
.sc_service
= issvc
;
6074 cbdata
.sc_flags
= SCI_FORCE
;
6075 cbdata
.sc_source_fmri
= ient
->sc_fmri
;
6076 cbdata
.sc_target_fmri
= ient
->sc_fmri
;
6078 r
= entity_pgroup_import(pg
, &cbdata
);
6081 ient
->sc_import_state
= IMPORT_PROP_BEGUN
;
6085 if (cbdata
.sc_err
== EEXIST
) {
6086 warn(emsg_pg_added
, ient
->sc_fmri
,
6087 pg
->sc_pgroup_name
);
6090 return (cbdata
.sc_err
);
6093 bad_error("entity_pgroup_import", r
);
6097 /* report differences between pg & current */
6098 r
= load_pg(imp_pg
, &rpg
, ient
->sc_fmri
, NULL
);
6104 warn(emsg_pg_deleted
, ient
->sc_fmri
,
6105 pg
->sc_pgroup_name
);
6115 bad_error("load_pg", r
);
6117 report_pg_diffs(pg
, rpg
, ient
->sc_fmri
, 1);
6118 internal_pgroup_free(rpg
);
6126 * Import an instance. If it doesn't exist, create it. If it has
6127 * a last-import snapshot, upgrade its properties. Finish by updating its
6128 * last-import snapshot. If it doesn't have a last-import snapshot then it
6129 * could have been created for a dependent tag in another manifest. Import the
6130 * new properties. If there's a conflict, don't override, like now?
6132 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
6133 * lcbdata->sc_err to
6134 * ECONNABORTED - repository connection broken
6135 * ENOMEM - out of memory
6136 * ENOSPC - svc.configd is out of resources
6137 * EEXIST - dependency collision in dependent service (error printed)
6138 * EPERM - couldn't create temporary instance (permission denied)
6139 * - couldn't import into temporary instance (permission denied)
6140 * - couldn't take snapshot (permission denied)
6141 * - couldn't upgrade properties (permission denied)
6142 * - couldn't import properties (permission denied)
6143 * - couldn't import dependents (permission denied)
6144 * EROFS - couldn't create temporary instance (repository read-only)
6145 * - couldn't import into temporary instance (repository read-only)
6146 * - couldn't upgrade properties (repository read-only)
6147 * - couldn't import properties (repository read-only)
6148 * - couldn't import dependents (repository read-only)
6149 * EACCES - couldn't create temporary instance (backend access denied)
6150 * - couldn't import into temporary instance (backend access denied)
6151 * - couldn't upgrade properties (backend access denied)
6152 * - couldn't import properties (backend access denied)
6153 * - couldn't import dependents (backend access denied)
6154 * EINVAL - invalid instance name (error printed)
6155 * - invalid pgroup_t's (error printed)
6156 * - invalid dependents (error printed)
6157 * EBUSY - temporary service deleted (error printed)
6158 * - temporary instance deleted (error printed)
6159 * - temporary instance changed (error printed)
6160 * - temporary instance already exists (error printed)
6161 * - instance deleted (error printed)
6162 * EBADF - instance has corrupt last-import snapshot (error printed)
6163 * - instance is corrupt (error printed)
6164 * - dependent has corrupt pg (error printed)
6165 * - dependent target has a corrupt snapshot (error printed)
6166 * -1 - unknown libscf error (error printed)
6169 lscf_instance_import(void *v
, void *pvt
)
6173 scf_callback_t
*lcbdata
= pvt
;
6174 scf_service_t
*rsvc
= lcbdata
->sc_parent
;
6176 scf_snaplevel_t
*running
;
6177 int flags
= lcbdata
->sc_flags
;
6179 const char * const emsg_tdel
=
6180 gettext("Temporary instance svc:/%s:%s was deleted.\n");
6181 const char * const emsg_tchg
= gettext("Temporary instance svc:/%s:%s "
6182 "changed unexpectedly.\n");
6183 const char * const emsg_del
= gettext("%s changed unexpectedly "
6184 "(instance \"%s\" was deleted.)\n");
6185 const char * const emsg_badsnap
= gettext(
6186 "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
6189 * prepare last-import snapshot:
6190 * create temporary instance (service was precreated)
6191 * populate with properties from bundle
6194 if (scf_service_add_instance(imp_tsvc
, inst
->sc_name
, imp_tinst
) != 0) {
6195 switch (scf_error()) {
6196 case SCF_ERROR_CONNECTION_BROKEN
:
6197 case SCF_ERROR_NO_RESOURCES
:
6198 case SCF_ERROR_BACKEND_READONLY
:
6199 case SCF_ERROR_BACKEND_ACCESS
:
6200 return (stash_scferror(lcbdata
));
6202 case SCF_ERROR_EXISTS
:
6203 warn(gettext("Temporary service svc:/%s "
6204 "changed unexpectedly (instance \"%s\" added).\n"),
6205 imp_tsname
, inst
->sc_name
);
6206 lcbdata
->sc_err
= EBUSY
;
6207 return (UU_WALK_ERROR
);
6209 case SCF_ERROR_DELETED
:
6210 warn(gettext("Temporary service svc:/%s "
6211 "was deleted unexpectedly.\n"), imp_tsname
);
6212 lcbdata
->sc_err
= EBUSY
;
6213 return (UU_WALK_ERROR
);
6215 case SCF_ERROR_INVALID_ARGUMENT
:
6216 warn(gettext("Invalid instance name \"%s\".\n"),
6218 return (stash_scferror(lcbdata
));
6220 case SCF_ERROR_PERMISSION_DENIED
:
6221 warn(gettext("Could not create temporary instance "
6222 "\"%s\" in svc:/%s (permission denied).\n"),
6223 inst
->sc_name
, imp_tsname
);
6224 return (stash_scferror(lcbdata
));
6226 case SCF_ERROR_HANDLE_MISMATCH
:
6227 case SCF_ERROR_NOT_BOUND
:
6228 case SCF_ERROR_NOT_SET
:
6230 bad_error("scf_service_add_instance", scf_error());
6234 r
= snprintf(imp_str
, imp_str_sz
, "svc:/%s:%s", imp_tsname
,
6237 bad_error("snprintf", errno
);
6239 r
= lscf_import_instance_pgs(imp_tinst
, imp_str
, inst
,
6240 lcbdata
->sc_flags
| SCI_NOENABLED
);
6246 warn(emsg_tdel
, imp_tsname
, inst
->sc_name
);
6247 lcbdata
->sc_err
= EBUSY
;
6252 warn(emsg_tchg
, imp_tsname
, inst
->sc_name
);
6253 lcbdata
->sc_err
= EBUSY
;
6267 lcbdata
->sc_err
= r
;
6272 bad_error("lscf_import_instance_pgs", r
);
6275 r
= snprintf(imp_str
, imp_str_sz
, "svc:/%s:%s", imp_tsname
,
6278 bad_error("snprintf", errno
);
6280 ctx
.sc_handle
= lcbdata
->sc_handle
;
6281 ctx
.sc_parent
= imp_tinst
;
6283 ctx
.sc_source_fmri
= inst
->sc_fmri
;
6284 ctx
.sc_target_fmri
= imp_str
;
6285 if (uu_list_walk(inst
->sc_dependents
, entity_pgroup_import
, &ctx
,
6287 if (uu_error() != UU_ERROR_CALLBACK_FAILED
)
6288 bad_error("uu_list_walk", uu_error());
6290 switch (ctx
.sc_err
) {
6295 warn(emsg_tdel
, imp_tsname
, inst
->sc_name
);
6296 lcbdata
->sc_err
= EBUSY
;
6300 warn(emsg_tchg
, imp_tsname
, inst
->sc_name
);
6301 lcbdata
->sc_err
= EBUSY
;
6305 lcbdata
->sc_err
= ctx
.sc_err
;
6311 if (_scf_snapshot_take_new_named(imp_tinst
, inst
->sc_parent
->sc_name
,
6312 inst
->sc_name
, snap_lastimport
, imp_tlisnap
) != 0) {
6313 switch (scf_error()) {
6314 case SCF_ERROR_CONNECTION_BROKEN
:
6317 case SCF_ERROR_NO_RESOURCES
:
6318 r
= stash_scferror(lcbdata
);
6321 case SCF_ERROR_EXISTS
:
6322 warn(emsg_tchg
, imp_tsname
, inst
->sc_name
);
6323 lcbdata
->sc_err
= EBUSY
;
6327 case SCF_ERROR_PERMISSION_DENIED
:
6328 warn(gettext("Could not take \"%s\" snapshot of %s "
6329 "(permission denied).\n"), snap_lastimport
,
6331 r
= stash_scferror(lcbdata
);
6336 lcbdata
->sc_err
= -1;
6340 case SCF_ERROR_HANDLE_MISMATCH
:
6341 case SCF_ERROR_INVALID_ARGUMENT
:
6342 case SCF_ERROR_NOT_SET
:
6343 bad_error("_scf_snapshot_take_new_named", scf_error());
6347 if (lcbdata
->sc_flags
& SCI_FRESH
)
6350 if (scf_service_get_instance(rsvc
, inst
->sc_name
, imp_inst
) == 0) {
6351 if (scf_instance_get_snapshot(imp_inst
, snap_lastimport
,
6353 switch (scf_error()) {
6354 case SCF_ERROR_DELETED
:
6355 warn(emsg_del
, inst
->sc_parent
->sc_fmri
,
6357 lcbdata
->sc_err
= EBUSY
;
6361 case SCF_ERROR_NOT_FOUND
:
6365 case SCF_ERROR_CONNECTION_BROKEN
:
6368 case SCF_ERROR_INVALID_ARGUMENT
:
6369 case SCF_ERROR_HANDLE_MISMATCH
:
6370 case SCF_ERROR_NOT_BOUND
:
6371 case SCF_ERROR_NOT_SET
:
6373 bad_error("scf_instance_get_snapshot",
6381 * compare new properties with last-import properties
6382 * upgrade current properties
6384 /* clear sc_sceen for pgs */
6385 if (uu_list_walk(inst
->sc_pgroups
, clear_int
,
6386 (void *)offsetof(pgroup_t
, sc_pgroup_seen
), UU_DEFAULT
) !=
6388 bad_error("uu_list_walk", uu_error());
6390 r
= get_snaplevel(imp_lisnap
, 0, imp_snpl
);
6399 warn(emsg_del
, inst
->sc_parent
->sc_fmri
, inst
->sc_name
);
6400 lcbdata
->sc_err
= EBUSY
;
6405 warn(emsg_badsnap
, snap_lastimport
, inst
->sc_fmri
);
6406 lcbdata
->sc_err
= EBADF
;
6411 bad_error("get_snaplevel", r
);
6414 if (scf_instance_get_snapshot(imp_inst
, snap_running
,
6416 switch (scf_error()) {
6417 case SCF_ERROR_DELETED
:
6418 warn(emsg_del
, inst
->sc_parent
->sc_fmri
,
6420 lcbdata
->sc_err
= EBUSY
;
6424 case SCF_ERROR_NOT_FOUND
:
6427 case SCF_ERROR_CONNECTION_BROKEN
:
6430 case SCF_ERROR_INVALID_ARGUMENT
:
6431 case SCF_ERROR_HANDLE_MISMATCH
:
6432 case SCF_ERROR_NOT_BOUND
:
6433 case SCF_ERROR_NOT_SET
:
6435 bad_error("scf_instance_get_snapshot",
6441 r
= get_snaplevel(imp_rsnap
, 0, imp_rsnpl
);
6444 running
= imp_rsnpl
;
6451 warn(emsg_del
, inst
->sc_parent
->sc_fmri
,
6453 lcbdata
->sc_err
= EBUSY
;
6458 warn(emsg_badsnap
, snap_running
, inst
->sc_fmri
);
6459 lcbdata
->sc_err
= EBADF
;
6464 bad_error("get_snaplevel", r
);
6468 r
= upgrade_props(imp_inst
, running
, imp_snpl
, inst
);
6475 warn(emsg_del
, inst
->sc_parent
->sc_fmri
, inst
->sc_name
);
6476 lcbdata
->sc_err
= EBUSY
;
6492 lcbdata
->sc_err
= r
;
6497 bad_error("upgrade_props", r
);
6500 inst
->sc_import_state
= IMPORT_PROP_DONE
;
6502 switch (scf_error()) {
6503 case SCF_ERROR_CONNECTION_BROKEN
:
6506 case SCF_ERROR_NOT_FOUND
:
6509 case SCF_ERROR_INVALID_ARGUMENT
: /* caught above */
6510 case SCF_ERROR_HANDLE_MISMATCH
:
6511 case SCF_ERROR_NOT_BOUND
:
6512 case SCF_ERROR_NOT_SET
:
6514 bad_error("scf_service_get_instance", scf_error());
6518 /* create instance */
6519 if (scf_service_add_instance(rsvc
, inst
->sc_name
,
6521 switch (scf_error()) {
6522 case SCF_ERROR_CONNECTION_BROKEN
:
6525 case SCF_ERROR_NO_RESOURCES
:
6526 case SCF_ERROR_BACKEND_READONLY
:
6527 case SCF_ERROR_BACKEND_ACCESS
:
6528 r
= stash_scferror(lcbdata
);
6531 case SCF_ERROR_EXISTS
:
6532 warn(gettext("%s changed unexpectedly "
6533 "(instance \"%s\" added).\n"),
6534 inst
->sc_parent
->sc_fmri
, inst
->sc_name
);
6535 lcbdata
->sc_err
= EBUSY
;
6539 case SCF_ERROR_PERMISSION_DENIED
:
6540 warn(gettext("Could not create \"%s\" instance "
6541 "in %s (permission denied).\n"),
6542 inst
->sc_name
, inst
->sc_parent
->sc_fmri
);
6543 r
= stash_scferror(lcbdata
);
6546 case SCF_ERROR_INVALID_ARGUMENT
: /* caught above */
6547 case SCF_ERROR_HANDLE_MISMATCH
:
6548 case SCF_ERROR_NOT_BOUND
:
6549 case SCF_ERROR_NOT_SET
:
6551 bad_error("scf_service_add_instance",
6558 * Create a last-import snapshot to serve as an attachment
6559 * point for the real one from the temporary instance. Since
6560 * the contents is irrelevant, take it now, while the instance
6561 * is empty, to minimize svc.configd's work.
6563 if (_scf_snapshot_take_new(imp_inst
, snap_lastimport
,
6565 switch (scf_error()) {
6566 case SCF_ERROR_CONNECTION_BROKEN
:
6569 case SCF_ERROR_NO_RESOURCES
:
6570 r
= stash_scferror(lcbdata
);
6573 case SCF_ERROR_EXISTS
:
6574 warn(gettext("%s changed unexpectedly "
6575 "(snapshot \"%s\" added).\n"),
6576 inst
->sc_fmri
, snap_lastimport
);
6577 lcbdata
->sc_err
= EBUSY
;
6581 case SCF_ERROR_PERMISSION_DENIED
:
6582 warn(gettext("Could not take \"%s\" snapshot "
6583 "of %s (permission denied).\n"),
6584 snap_lastimport
, inst
->sc_fmri
);
6585 r
= stash_scferror(lcbdata
);
6590 lcbdata
->sc_err
= -1;
6594 case SCF_ERROR_NOT_SET
:
6595 case SCF_ERROR_INTERNAL
:
6596 case SCF_ERROR_INVALID_ARGUMENT
:
6597 case SCF_ERROR_HANDLE_MISMATCH
:
6598 bad_error("_scf_snapshot_take_new",
6606 inst
->sc_import_state
= IMPORT_PROP_BEGUN
;
6608 r
= lscf_import_instance_pgs(imp_inst
, inst
->sc_fmri
, inst
,
6618 warn(gettext("%s changed unexpectedly "
6619 "(instance \"%s\" deleted).\n"),
6620 inst
->sc_parent
->sc_fmri
, inst
->sc_name
);
6621 lcbdata
->sc_err
= EBUSY
;
6626 warn(gettext("%s changed unexpectedly "
6627 "(property group added).\n"), inst
->sc_fmri
);
6628 lcbdata
->sc_err
= EBUSY
;
6633 lcbdata
->sc_err
= r
;
6637 case EINVAL
: /* caught above */
6638 bad_error("lscf_import_instance_pgs", r
);
6641 ctx
.sc_parent
= imp_inst
;
6643 ctx
.sc_trans
= NULL
;
6645 if (uu_list_walk(inst
->sc_dependents
, lscf_dependent_import
,
6646 &ctx
, UU_DEFAULT
) != 0) {
6647 if (uu_error() != UU_ERROR_CALLBACK_FAILED
)
6648 bad_error("uu_list_walk", uu_error());
6650 if (ctx
.sc_err
== ECONNABORTED
)
6652 lcbdata
->sc_err
= ctx
.sc_err
;
6657 inst
->sc_import_state
= IMPORT_PROP_DONE
;
6660 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6661 snap_initial
, inst
->sc_fmri
);
6662 r
= take_snap(imp_inst
, snap_initial
, imp_snap
);
6672 lcbdata
->sc_err
= r
;
6677 warn(gettext("%s changed unexpectedly "
6678 "(instance %s deleted).\n"),
6679 inst
->sc_parent
->sc_fmri
, inst
->sc_name
);
6680 lcbdata
->sc_err
= r
;
6685 warn(emsg_snap_perm
, snap_initial
, inst
->sc_fmri
);
6686 lcbdata
->sc_err
= r
;
6691 bad_error("take_snap", r
);
6696 if (lcbdata
->sc_flags
& SCI_NOSNAP
)
6699 /* transfer snapshot from temporary instance */
6701 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6702 snap_lastimport
, inst
->sc_fmri
);
6703 if (_scf_snapshot_attach(imp_tlisnap
, imp_lisnap
) != 0) {
6704 switch (scf_error()) {
6705 case SCF_ERROR_CONNECTION_BROKEN
:
6708 case SCF_ERROR_NO_RESOURCES
:
6709 r
= stash_scferror(lcbdata
);
6712 case SCF_ERROR_PERMISSION_DENIED
:
6713 warn(gettext("Could not take \"%s\" snapshot for %s "
6714 "(permission denied).\n"), snap_lastimport
,
6716 r
= stash_scferror(lcbdata
);
6719 case SCF_ERROR_NOT_SET
:
6720 case SCF_ERROR_HANDLE_MISMATCH
:
6722 bad_error("_scf_snapshot_attach", scf_error());
6726 inst
->sc_import_state
= IMPORT_COMPLETE
;
6731 /* delete temporary instance */
6732 if (scf_instance_delete(imp_tinst
) != 0) {
6733 switch (scf_error()) {
6734 case SCF_ERROR_DELETED
:
6737 case SCF_ERROR_CONNECTION_BROKEN
:
6740 case SCF_ERROR_NOT_SET
:
6741 case SCF_ERROR_NOT_BOUND
:
6743 bad_error("scf_instance_delete", scf_error());
6750 warn(gettext("Could not delete svc:/%s:%s "
6751 "(repository connection broken).\n"), imp_tsname
, inst
->sc_name
);
6752 lcbdata
->sc_err
= ECONNABORTED
;
6753 return (UU_WALK_ERROR
);
6757 * When an instance is imported we end up telling configd about it. Once we tell
6758 * configd about these changes, startd eventually notices. If this is a new
6759 * instance, the manifest may not specify the SCF_PG_RESTARTER (restarter)
6760 * property group. However, many of the other tools expect that this property
6761 * group exists and has certain values.
6763 * These values are added asynchronously by startd. We should not return from
6764 * this routine until we can verify that the property group we need is there.
6766 * Before we go ahead and verify this, we have to ask ourselves an important
6767 * question: Is the early manifest service currently running? Because if it is
6768 * running and it has invoked us, then the service will never get a restarter
6769 * property because svc.startd is blocked on EMI finishing before it lets itself
6770 * fully connect to svc.configd. Of course, this means that this race condition
6771 * is in fact impossible to 100% eliminate.
6773 * svc.startd makes sure that EMI only runs once and has succeeded by checking
6774 * the state of the EMI instance. If it is online it bails out and makes sure
6775 * that it doesn't run again. In this case, we're going to do something similar,
6776 * only if the state is online, then we're going to actually verify. EMI always
6777 * has to be present, but it can be explicitly disabled to reduce the amount of
6778 * damage it can cause. If EMI has been disabled then we no longer have to worry
6779 * about the implicit race condition and can go ahead and check things. If EMI
6780 * is in some state that isn't online or disabled and isn't runinng, then we
6781 * assume that things are rather bad and we're not going to get in your way,
6782 * even if the rest of SMF does.
6784 * Returns 0 on success or returns an errno.
6786 #ifndef NATIVE_BUILD
6788 lscf_instance_verify(scf_scope_t
*scope
, entity_t
*svc
, entity_t
*inst
)
6795 * smf_get_state does not distinguish between its different failure
6796 * modes: memory allocation failures, SMF internal failures, and a lack
6797 * of EMI entirely because it's been removed. In these cases, we're
6798 * going to be conservative and opt to say that if we don't know, better
6799 * to not block import or falsely warn to the user.
6801 if ((emi_state
= smf_get_state(SCF_INSTANCE_EMI
)) == NULL
) {
6806 * As per the block comment for this function check the state of EMI
6808 if (strcmp(emi_state
, SCF_STATE_STRING_ONLINE
) != 0 &&
6809 strcmp(emi_state
, SCF_STATE_STRING_DISABLED
) != 0) {
6810 warn(gettext("Not validating instance %s:%s because EMI's "
6811 "state is %s\n"), svc
->sc_name
, inst
->sc_name
, emi_state
);
6819 * First we have to get the property.
6821 if ((ret
= scf_scope_get_service(scope
, svc
->sc_name
, imp_svc
)) != 0) {
6823 warn(gettext("Failed to look up service: %s\n"), svc
->sc_name
);
6828 * We should always be able to get the instance. It should already
6829 * exist because we just created it or got it. There probably is a
6830 * slim chance that someone may have come in and deleted it though from
6833 if ((ret
= scf_service_get_instance(imp_svc
, inst
->sc_name
, imp_inst
))
6836 warn(gettext("Failed to verify instance: %s\n"), inst
->sc_name
);
6838 case SCF_ERROR_DELETED
:
6841 case SCF_ERROR_CONNECTION_BROKEN
:
6842 warn(gettext("Lost repository connection\n"));
6845 case SCF_ERROR_NOT_FOUND
:
6846 warn(gettext("Instance \"%s\" disappeared out from "
6847 "under us.\n"), inst
->sc_name
);
6851 bad_error("scf_service_get_instance", ret
);
6858 * An astute observer may want to use _scf_wait_pg which would notify us
6859 * of a property group change, unfortunately that does not work if the
6860 * property group in question does not exist. So instead we have to
6861 * manually poll and ask smf the best way to get to it.
6863 while ((ret
= scf_instance_get_pg(imp_inst
, SCF_PG_RESTARTER
, imp_pg
))
6866 if (ret
!= SCF_ERROR_NOT_FOUND
) {
6867 warn(gettext("Failed to get restarter property "
6868 "group for instance: %s\n"), inst
->sc_name
);
6870 case SCF_ERROR_DELETED
:
6873 case SCF_ERROR_CONNECTION_BROKEN
:
6874 warn(gettext("Lost repository connection\n"));
6878 bad_error("scf_service_get_instance", ret
);
6884 ts
.tv_sec
= pg_timeout
/ NANOSEC
;
6885 ts
.tv_nsec
= pg_timeout
% NANOSEC
;
6887 (void) nanosleep(&ts
, NULL
);
6891 * svcadm also expects that the SCF_PROPERTY_STATE property is present.
6892 * So in addition to the property group being present, we need to wait
6893 * for the property to be there in some form.
6895 * Note that a property group is a frozen snapshot in time. To properly
6896 * get beyond this, you have to refresh the property group each time.
6898 while ((ret
= scf_pg_get_property(imp_pg
, SCF_PROPERTY_STATE
,
6902 if (ret
!= SCF_ERROR_NOT_FOUND
) {
6903 warn(gettext("Failed to get property %s from the "
6904 "restarter property group of instance %s\n"),
6905 SCF_PROPERTY_STATE
, inst
->sc_name
);
6907 case SCF_ERROR_CONNECTION_BROKEN
:
6908 warn(gettext("Lost repository connection\n"));
6911 case SCF_ERROR_DELETED
:
6915 bad_error("scf_pg_get_property", ret
);
6921 ts
.tv_sec
= pg_timeout
/ NANOSEC
;
6922 ts
.tv_nsec
= pg_timeout
% NANOSEC
;
6924 (void) nanosleep(&ts
, NULL
);
6926 ret
= scf_instance_get_pg(imp_inst
, SCF_PG_RESTARTER
, imp_pg
);
6927 if (ret
!= SCF_SUCCESS
) {
6928 warn(gettext("Failed to get restarter property "
6929 "group for instance: %s\n"), inst
->sc_name
);
6931 case SCF_ERROR_DELETED
:
6934 case SCF_ERROR_CONNECTION_BROKEN
:
6935 warn(gettext("Lost repository connection\n"));
6939 bad_error("scf_service_get_instance", ret
);
6947 * We don't have to free the property groups or other values that we got
6948 * because we stored them in global variables that are allocated and
6949 * freed by the routines that call into these functions. Unless of
6950 * course the rest of the code here that we are basing this on is
6958 del_tmp_service(void)
6960 if (scf_service_delete(imp_tsvc
) != 0) {
6961 switch (scf_error()) {
6962 case SCF_ERROR_DELETED
:
6965 case SCF_ERROR_CONNECTION_BROKEN
:
6966 warn(gettext("Could not delete svc:/%s "
6967 "(repository connection broken).\n"), imp_tsname
);
6970 case SCF_ERROR_EXISTS
:
6972 "Could not delete svc:/%s (instances exist).\n"),
6976 case SCF_ERROR_NOT_SET
:
6977 case SCF_ERROR_NOT_BOUND
:
6979 bad_error("scf_service_delete", scf_error());
6985 * If the service is missing, create it, import its properties, and import the
6986 * instances. Since the service is brand new, it should be empty, and if we
6987 * run into any existing entities (SCF_ERROR_EXISTS), abort.
6989 * If the service exists, we want to upgrade its properties and import the
6990 * instances. Upgrade requires a last-import snapshot, though, which are
6991 * children of instances, so first we'll have to go through the instances
6992 * looking for a last-import snapshot. If we don't find one then we'll just
6993 * override-import the service properties (but don't delete existing
6994 * properties: another service might have declared us as a dependent). Before
6995 * we change anything, though, we want to take the previous snapshots. We
6996 * also give lscf_instance_import() a leg up on taking last-import snapshots
6997 * by importing the manifest's service properties into a temporary service.
6999 * On success, returns UU_WALK_NEXT. On failure, returns UU_WALK_ERROR and
7000 * sets lcbdata->sc_err to
7001 * ECONNABORTED - repository connection broken
7002 * ENOMEM - out of memory
7003 * ENOSPC - svc.configd is out of resources
7004 * EPERM - couldn't create temporary service (error printed)
7005 * - couldn't import into temp service (error printed)
7006 * - couldn't create service (error printed)
7007 * - couldn't import dependent (error printed)
7008 * - couldn't take snapshot (error printed)
7009 * - couldn't create instance (error printed)
7010 * - couldn't create, modify, or delete pg (error printed)
7011 * - couldn't create, modify, or delete dependent (error printed)
7012 * - couldn't import instance (error printed)
7013 * EROFS - couldn't create temporary service (repository read-only)
7014 * - couldn't import into temporary service (repository read-only)
7015 * - couldn't create service (repository read-only)
7016 * - couldn't import dependent (repository read-only)
7017 * - couldn't create instance (repository read-only)
7018 * - couldn't create, modify, or delete pg or dependent
7019 * - couldn't import instance (repository read-only)
7020 * EACCES - couldn't create temporary service (backend access denied)
7021 * - couldn't import into temporary service (backend access denied)
7022 * - couldn't create service (backend access denied)
7023 * - couldn't import dependent (backend access denied)
7024 * - couldn't create instance (backend access denied)
7025 * - couldn't create, modify, or delete pg or dependent
7026 * - couldn't import instance (backend access denied)
7027 * EINVAL - service name is invalid (error printed)
7028 * - service name is too long (error printed)
7029 * - s has invalid pgroup (error printed)
7030 * - s has invalid dependent (error printed)
7031 * - instance name is invalid (error printed)
7032 * - instance entity_t is invalid (error printed)
7033 * EEXIST - couldn't create temporary service (already exists) (error printed)
7034 * - couldn't import dependent (dependency pg already exists) (printed)
7035 * - dependency collision in dependent service (error printed)
7036 * EBUSY - temporary service deleted (error printed)
7037 * - property group added to temporary service (error printed)
7038 * - new property group changed or was deleted (error printed)
7039 * - service was added unexpectedly (error printed)
7040 * - service was deleted unexpectedly (error printed)
7041 * - property group added to new service (error printed)
7042 * - instance added unexpectedly (error printed)
7043 * - instance deleted unexpectedly (error printed)
7044 * - dependent service deleted unexpectedly (error printed)
7045 * - pg was added, changed, or deleted (error printed)
7046 * - dependent pg changed (error printed)
7047 * - temporary instance added, changed, or deleted (error printed)
7048 * EBADF - a last-import snapshot is corrupt (error printed)
7049 * - the service is corrupt (error printed)
7050 * - a dependent is corrupt (error printed)
7051 * - an instance is corrupt (error printed)
7052 * - an instance has a corrupt last-import snapshot (error printed)
7053 * - dependent target has a corrupt snapshot (error printed)
7054 * -1 - unknown libscf error (error printed)
7057 lscf_service_import(void *v
, void *pvt
)
7060 scf_callback_t cbdata
;
7061 scf_callback_t
*lcbdata
= pvt
;
7062 scf_scope_t
*scope
= lcbdata
->sc_parent
;
7063 entity_t
*inst
, linst
;
7066 scf_snaplevel_t
*running
;
7068 boolean_t retried
= B_FALSE
;
7070 const char * const ts_deleted
= gettext("Temporary service svc:/%s "
7071 "was deleted unexpectedly.\n");
7072 const char * const ts_pg_added
= gettext("Temporary service svc:/%s "
7073 "changed unexpectedly (property group added).\n");
7074 const char * const s_deleted
=
7075 gettext("%s was deleted unexpectedly.\n");
7076 const char * const i_deleted
=
7077 gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
7078 const char * const badsnap
= gettext("\"%s\" snapshot of svc:/%s:%s "
7079 "is corrupt (missing service snaplevel).\n");
7080 const char * const s_mfile_upd
=
7081 gettext("Unable to update the manifest file connection "
7085 /* Validate the service name */
7086 if (scf_scope_get_service(scope
, s
->sc_name
, imp_svc
) != 0) {
7087 switch (scf_error()) {
7088 case SCF_ERROR_CONNECTION_BROKEN
:
7089 return (stash_scferror(lcbdata
));
7091 case SCF_ERROR_INVALID_ARGUMENT
:
7092 warn(gettext("\"%s\" is an invalid service name. "
7093 "Cannot import.\n"), s
->sc_name
);
7094 return (stash_scferror(lcbdata
));
7096 case SCF_ERROR_NOT_FOUND
:
7099 case SCF_ERROR_HANDLE_MISMATCH
:
7100 case SCF_ERROR_NOT_BOUND
:
7101 case SCF_ERROR_NOT_SET
:
7103 bad_error("scf_scope_get_service", scf_error());
7107 /* create temporary service */
7109 * the size of the buffer was reduced to max_scf_name_len to prevent
7110 * hitting bug 6681151. After the bug fix, the size of the buffer
7111 * should be restored to its original value (max_scf_name_len +1)
7113 r
= snprintf(imp_tsname
, max_scf_name_len
, "TEMP/%s", s
->sc_name
);
7115 bad_error("snprintf", errno
);
7116 if (r
> max_scf_name_len
) {
7118 "Service name \"%s\" is too long. Cannot import.\n"),
7120 lcbdata
->sc_err
= EINVAL
;
7121 return (UU_WALK_ERROR
);
7125 if (scf_scope_add_service(imp_scope
, imp_tsname
, imp_tsvc
) != 0) {
7126 switch (scf_error()) {
7127 case SCF_ERROR_CONNECTION_BROKEN
:
7128 case SCF_ERROR_NO_RESOURCES
:
7129 case SCF_ERROR_BACKEND_READONLY
:
7130 case SCF_ERROR_BACKEND_ACCESS
:
7131 return (stash_scferror(lcbdata
));
7133 case SCF_ERROR_EXISTS
:
7135 lscf_delete(imp_tsname
, 0);
7140 "Temporary service \"%s\" must be deleted before "
7141 "this manifest can be imported.\n"), imp_tsname
);
7142 return (stash_scferror(lcbdata
));
7144 case SCF_ERROR_PERMISSION_DENIED
:
7145 warn(gettext("Could not create temporary service "
7146 "\"%s\" (permission denied).\n"), imp_tsname
);
7147 return (stash_scferror(lcbdata
));
7149 case SCF_ERROR_INVALID_ARGUMENT
:
7150 case SCF_ERROR_HANDLE_MISMATCH
:
7151 case SCF_ERROR_NOT_BOUND
:
7152 case SCF_ERROR_NOT_SET
:
7154 bad_error("scf_scope_add_service", scf_error());
7158 r
= snprintf(imp_str
, imp_str_sz
, "svc:/%s", imp_tsname
);
7160 bad_error("snprintf", errno
);
7162 cbdata
.sc_handle
= lcbdata
->sc_handle
;
7163 cbdata
.sc_parent
= imp_tsvc
;
7164 cbdata
.sc_service
= 1;
7165 cbdata
.sc_source_fmri
= s
->sc_fmri
;
7166 cbdata
.sc_target_fmri
= imp_str
;
7167 cbdata
.sc_flags
= 0;
7169 if (uu_list_walk(s
->sc_pgroups
, entity_pgroup_import
, &cbdata
,
7171 if (uu_error() != UU_ERROR_CALLBACK_FAILED
)
7172 bad_error("uu_list_walk", uu_error());
7174 lcbdata
->sc_err
= cbdata
.sc_err
;
7175 switch (cbdata
.sc_err
) {
7180 warn(ts_deleted
, imp_tsname
);
7181 lcbdata
->sc_err
= EBUSY
;
7182 return (UU_WALK_ERROR
);
7185 warn(ts_pg_added
, imp_tsname
);
7186 lcbdata
->sc_err
= EBUSY
;
7187 return (UU_WALK_ERROR
);
7195 if (uu_list_walk(s
->sc_dependents
, entity_pgroup_import
, &cbdata
,
7197 if (uu_error() != UU_ERROR_CALLBACK_FAILED
)
7198 bad_error("uu_list_walk", uu_error());
7200 lcbdata
->sc_err
= cbdata
.sc_err
;
7201 switch (cbdata
.sc_err
) {
7206 warn(ts_deleted
, imp_tsname
);
7207 lcbdata
->sc_err
= EBUSY
;
7208 return (UU_WALK_ERROR
);
7211 warn(ts_pg_added
, imp_tsname
);
7212 lcbdata
->sc_err
= EBUSY
;
7213 return (UU_WALK_ERROR
);
7217 return (UU_WALK_ERROR
);
7220 if (scf_scope_get_service(scope
, s
->sc_name
, imp_svc
) != 0) {
7221 switch (scf_error()) {
7222 case SCF_ERROR_NOT_FOUND
:
7225 case SCF_ERROR_CONNECTION_BROKEN
:
7228 case SCF_ERROR_INVALID_ARGUMENT
:
7229 case SCF_ERROR_HANDLE_MISMATCH
:
7230 case SCF_ERROR_NOT_BOUND
:
7231 case SCF_ERROR_NOT_SET
:
7233 bad_error("scf_scope_get_service", scf_error());
7236 if (scf_scope_add_service(scope
, s
->sc_name
, imp_svc
) != 0) {
7237 switch (scf_error()) {
7238 case SCF_ERROR_CONNECTION_BROKEN
:
7241 case SCF_ERROR_NO_RESOURCES
:
7242 case SCF_ERROR_BACKEND_READONLY
:
7243 case SCF_ERROR_BACKEND_ACCESS
:
7245 return (stash_scferror(lcbdata
));
7247 case SCF_ERROR_EXISTS
:
7248 warn(gettext("Scope \"%s\" changed unexpectedly"
7249 " (service \"%s\" added).\n"),
7250 SCF_SCOPE_LOCAL
, s
->sc_name
);
7251 lcbdata
->sc_err
= EBUSY
;
7253 return (UU_WALK_ERROR
);
7255 case SCF_ERROR_PERMISSION_DENIED
:
7256 warn(gettext("Could not create service \"%s\" "
7257 "(permission denied).\n"), s
->sc_name
);
7259 return (UU_WALK_ERROR
);
7261 case SCF_ERROR_INVALID_ARGUMENT
:
7262 case SCF_ERROR_HANDLE_MISMATCH
:
7263 case SCF_ERROR_NOT_BOUND
:
7264 case SCF_ERROR_NOT_SET
:
7266 bad_error("scf_scope_add_service", scf_error());
7270 s
->sc_import_state
= IMPORT_PROP_BEGUN
;
7272 /* import service properties */
7273 cbdata
.sc_handle
= lcbdata
->sc_handle
;
7274 cbdata
.sc_parent
= imp_svc
;
7275 cbdata
.sc_service
= 1;
7276 cbdata
.sc_flags
= lcbdata
->sc_flags
;
7277 cbdata
.sc_source_fmri
= s
->sc_fmri
;
7278 cbdata
.sc_target_fmri
= s
->sc_fmri
;
7280 if (uu_list_walk(s
->sc_pgroups
, entity_pgroup_import
,
7281 &cbdata
, UU_DEFAULT
) != 0) {
7282 if (uu_error() != UU_ERROR_CALLBACK_FAILED
)
7283 bad_error("uu_list_walk", uu_error());
7285 lcbdata
->sc_err
= cbdata
.sc_err
;
7286 switch (cbdata
.sc_err
) {
7291 warn(s_deleted
, s
->sc_fmri
);
7292 lcbdata
->sc_err
= EBUSY
;
7293 return (UU_WALK_ERROR
);
7296 warn(gettext("%s changed unexpectedly "
7297 "(property group added).\n"), s
->sc_fmri
);
7298 lcbdata
->sc_err
= EBUSY
;
7299 return (UU_WALK_ERROR
);
7303 bad_error("entity_pgroup_import",
7308 return (UU_WALK_ERROR
);
7311 cbdata
.sc_trans
= NULL
;
7312 cbdata
.sc_flags
= 0;
7313 if (uu_list_walk(s
->sc_dependents
, lscf_dependent_import
,
7314 &cbdata
, UU_DEFAULT
) != 0) {
7315 if (uu_error() != UU_ERROR_CALLBACK_FAILED
)
7316 bad_error("uu_list_walk", uu_error());
7318 lcbdata
->sc_err
= cbdata
.sc_err
;
7319 if (cbdata
.sc_err
== ECONNABORTED
)
7322 return (UU_WALK_ERROR
);
7325 s
->sc_import_state
= IMPORT_PROP_DONE
;
7328 * This is a new service, so we can't take previous snapshots
7329 * or upgrade service properties.
7335 /* Clear sc_seen for the instances. */
7336 if (uu_list_walk(s
->sc_u
.sc_service
.sc_service_instances
, clear_int
,
7337 (void *)offsetof(entity_t
, sc_seen
), UU_DEFAULT
) != 0)
7338 bad_error("uu_list_walk", uu_error());
7341 * Take previous snapshots for all instances. Even for ones not
7342 * mentioned in the bundle, since we might change their service
7345 if (scf_iter_service_instances(imp_iter
, imp_svc
) != 0) {
7346 switch (scf_error()) {
7347 case SCF_ERROR_CONNECTION_BROKEN
:
7350 case SCF_ERROR_DELETED
:
7351 warn(s_deleted
, s
->sc_fmri
);
7352 lcbdata
->sc_err
= EBUSY
;
7354 return (UU_WALK_ERROR
);
7356 case SCF_ERROR_HANDLE_MISMATCH
:
7357 case SCF_ERROR_NOT_BOUND
:
7358 case SCF_ERROR_NOT_SET
:
7360 bad_error("scf_iter_service_instances", scf_error());
7365 r
= scf_iter_next_instance(imp_iter
, imp_inst
);
7369 switch (scf_error()) {
7370 case SCF_ERROR_DELETED
:
7371 warn(s_deleted
, s
->sc_fmri
);
7372 lcbdata
->sc_err
= EBUSY
;
7374 return (UU_WALK_ERROR
);
7376 case SCF_ERROR_CONNECTION_BROKEN
:
7379 case SCF_ERROR_NOT_BOUND
:
7380 case SCF_ERROR_HANDLE_MISMATCH
:
7381 case SCF_ERROR_INVALID_ARGUMENT
:
7382 case SCF_ERROR_NOT_SET
:
7384 bad_error("scf_iter_next_instance",
7389 if (scf_instance_get_name(imp_inst
, imp_str
, imp_str_sz
) < 0) {
7390 switch (scf_error()) {
7391 case SCF_ERROR_DELETED
:
7394 case SCF_ERROR_CONNECTION_BROKEN
:
7397 case SCF_ERROR_NOT_SET
:
7398 case SCF_ERROR_NOT_BOUND
:
7400 bad_error("scf_instance_get_name", scf_error());
7406 "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
7407 snap_previous
, s
->sc_name
, imp_str
);
7409 r
= take_snap(imp_inst
, snap_previous
, imp_snap
);
7421 warn(gettext("Could not take \"%s\" snapshot of "
7422 "svc:/%s:%s (permission denied).\n"),
7423 snap_previous
, s
->sc_name
, imp_str
);
7424 lcbdata
->sc_err
= r
;
7425 return (UU_WALK_ERROR
);
7429 lcbdata
->sc_err
= r
;
7431 return (UU_WALK_ERROR
);
7434 bad_error("take_snap", r
);
7437 linst
.sc_name
= imp_str
;
7438 inst
= uu_list_find(s
->sc_u
.sc_service
.sc_service_instances
,
7439 &linst
, NULL
, NULL
);
7441 inst
->sc_import_state
= IMPORT_PREVIOUS
;
7447 * Create the new instances and take previous snapshots of
7448 * them. This is not necessary, but it maximizes data preservation.
7450 for (inst
= uu_list_first(s
->sc_u
.sc_service
.sc_service_instances
);
7452 inst
= uu_list_next(s
->sc_u
.sc_service
.sc_service_instances
,
7457 if (scf_service_add_instance(imp_svc
, inst
->sc_name
,
7459 switch (scf_error()) {
7460 case SCF_ERROR_CONNECTION_BROKEN
:
7463 case SCF_ERROR_BACKEND_READONLY
:
7464 case SCF_ERROR_BACKEND_ACCESS
:
7465 case SCF_ERROR_NO_RESOURCES
:
7467 return (stash_scferror(lcbdata
));
7469 case SCF_ERROR_EXISTS
:
7470 warn(gettext("%s changed unexpectedly "
7471 "(instance \"%s\" added).\n"), s
->sc_fmri
,
7473 lcbdata
->sc_err
= EBUSY
;
7475 return (UU_WALK_ERROR
);
7477 case SCF_ERROR_INVALID_ARGUMENT
:
7478 warn(gettext("Service \"%s\" has instance with "
7479 "invalid name \"%s\".\n"), s
->sc_name
,
7483 case SCF_ERROR_PERMISSION_DENIED
:
7484 warn(gettext("Could not create instance \"%s\" "
7485 "in %s (permission denied).\n"),
7486 inst
->sc_name
, s
->sc_fmri
);
7488 return (stash_scferror(lcbdata
));
7490 case SCF_ERROR_HANDLE_MISMATCH
:
7491 case SCF_ERROR_NOT_BOUND
:
7492 case SCF_ERROR_NOT_SET
:
7494 bad_error("scf_service_add_instance",
7500 warn(gettext("Taking \"%s\" snapshot for "
7501 "new service %s.\n"), snap_previous
, inst
->sc_fmri
);
7502 r
= take_snap(imp_inst
, snap_previous
, imp_snap
);
7508 warn(i_deleted
, s
->sc_fmri
, inst
->sc_name
);
7509 lcbdata
->sc_err
= EBUSY
;
7511 return (UU_WALK_ERROR
);
7517 warn(emsg_snap_perm
, snap_previous
, inst
->sc_fmri
);
7518 lcbdata
->sc_err
= r
;
7520 return (UU_WALK_ERROR
);
7525 return (UU_WALK_ERROR
);
7528 bad_error("take_snap", r
);
7532 s
->sc_import_state
= IMPORT_PREVIOUS
;
7535 * Upgrade service properties, if we can find a last-import snapshot.
7536 * Any will do because we don't support different service properties
7537 * in different manifests, so all snaplevels of the service in all of
7538 * the last-import snapshots of the instances should be the same.
7540 if (scf_iter_service_instances(imp_iter
, imp_svc
) != 0) {
7541 switch (scf_error()) {
7542 case SCF_ERROR_CONNECTION_BROKEN
:
7545 case SCF_ERROR_DELETED
:
7546 warn(s_deleted
, s
->sc_fmri
);
7547 lcbdata
->sc_err
= EBUSY
;
7549 return (UU_WALK_ERROR
);
7551 case SCF_ERROR_HANDLE_MISMATCH
:
7552 case SCF_ERROR_NOT_BOUND
:
7553 case SCF_ERROR_NOT_SET
:
7555 bad_error("scf_iter_service_instances", scf_error());
7560 r
= scf_iter_next_instance(imp_iter
, imp_inst
);
7562 switch (scf_error()) {
7563 case SCF_ERROR_DELETED
:
7564 warn(s_deleted
, s
->sc_fmri
);
7565 lcbdata
->sc_err
= EBUSY
;
7567 return (UU_WALK_ERROR
);
7569 case SCF_ERROR_CONNECTION_BROKEN
:
7572 case SCF_ERROR_NOT_BOUND
:
7573 case SCF_ERROR_HANDLE_MISMATCH
:
7574 case SCF_ERROR_INVALID_ARGUMENT
:
7575 case SCF_ERROR_NOT_SET
:
7577 bad_error("scf_iter_next_instance",
7584 * Didn't find any last-import snapshots. Override-
7585 * import the properties. Unless one of the instances
7586 * has a general/enabled property, in which case we're
7587 * probably running a last-import-capable svccfg for
7588 * the first time, and we should only take the
7589 * last-import snapshot.
7593 scf_callback_t mfcbdata
;
7598 * Need to go ahead and import the manifestfiles
7599 * pg if it exists. If the last-import snapshot
7600 * upgrade code is ever removed this code can
7601 * be removed as well.
7603 mfpg
= internal_pgroup_find(s
,
7604 SCF_PG_MANIFESTFILES
, SCF_GROUP_FRAMEWORK
);
7607 mfcbdata
.sc_handle
= g_hndl
;
7608 mfcbdata
.sc_parent
= imp_svc
;
7609 mfcbdata
.sc_service
= 1;
7610 mfcbdata
.sc_flags
= SCI_FORCE
;
7611 mfcbdata
.sc_source_fmri
= s
->sc_fmri
;
7612 mfcbdata
.sc_target_fmri
= s
->sc_fmri
;
7613 if (entity_pgroup_import(mfpg
,
7614 &mfcbdata
) != UU_WALK_NEXT
) {
7615 warn(s_mfile_upd
, s
->sc_fmri
);
7617 return (UU_WALK_ERROR
);
7623 s
->sc_import_state
= IMPORT_PROP_BEGUN
;
7625 cbdata
.sc_handle
= g_hndl
;
7626 cbdata
.sc_parent
= imp_svc
;
7627 cbdata
.sc_service
= 1;
7628 cbdata
.sc_flags
= SCI_FORCE
;
7629 cbdata
.sc_source_fmri
= s
->sc_fmri
;
7630 cbdata
.sc_target_fmri
= s
->sc_fmri
;
7631 if (uu_list_walk(s
->sc_pgroups
, entity_pgroup_import
,
7632 &cbdata
, UU_DEFAULT
) != 0) {
7633 if (uu_error() != UU_ERROR_CALLBACK_FAILED
)
7634 bad_error("uu_list_walk", uu_error());
7635 lcbdata
->sc_err
= cbdata
.sc_err
;
7636 switch (cbdata
.sc_err
) {
7641 warn(s_deleted
, s
->sc_fmri
);
7642 lcbdata
->sc_err
= EBUSY
;
7645 case EINVAL
: /* caught above */
7647 bad_error("entity_pgroup_import",
7652 return (UU_WALK_ERROR
);
7655 cbdata
.sc_trans
= NULL
;
7656 cbdata
.sc_flags
= 0;
7657 if (uu_list_walk(s
->sc_dependents
,
7658 lscf_dependent_import
, &cbdata
, UU_DEFAULT
) != 0) {
7659 if (uu_error() != UU_ERROR_CALLBACK_FAILED
)
7660 bad_error("uu_list_walk", uu_error());
7661 lcbdata
->sc_err
= cbdata
.sc_err
;
7662 if (cbdata
.sc_err
== ECONNABORTED
)
7665 return (UU_WALK_ERROR
);
7670 if (scf_instance_get_snapshot(imp_inst
, snap_lastimport
,
7672 switch (scf_error()) {
7673 case SCF_ERROR_DELETED
:
7676 case SCF_ERROR_NOT_FOUND
:
7679 case SCF_ERROR_CONNECTION_BROKEN
:
7682 case SCF_ERROR_HANDLE_MISMATCH
:
7683 case SCF_ERROR_NOT_BOUND
:
7684 case SCF_ERROR_INVALID_ARGUMENT
:
7685 case SCF_ERROR_NOT_SET
:
7687 bad_error("scf_instance_get_snapshot",
7695 * Check for a general/enabled property. This is how
7696 * we tell whether to import if there turn out to be
7697 * no last-import snapshots.
7699 if (scf_instance_get_pg(imp_inst
, SCF_PG_GENERAL
,
7701 if (scf_pg_get_property(imp_pg
,
7702 SCF_PROPERTY_ENABLED
, imp_prop
) == 0) {
7705 switch (scf_error()) {
7706 case SCF_ERROR_DELETED
:
7707 case SCF_ERROR_NOT_FOUND
:
7710 case SCF_ERROR_INVALID_ARGUMENT
:
7711 case SCF_ERROR_HANDLE_MISMATCH
:
7712 case SCF_ERROR_CONNECTION_BROKEN
:
7713 case SCF_ERROR_NOT_BOUND
:
7714 case SCF_ERROR_NOT_SET
:
7716 bad_error("scf_pg_get_property",
7721 switch (scf_error()) {
7722 case SCF_ERROR_DELETED
:
7723 case SCF_ERROR_NOT_FOUND
:
7726 case SCF_ERROR_CONNECTION_BROKEN
:
7729 case SCF_ERROR_NOT_BOUND
:
7730 case SCF_ERROR_NOT_SET
:
7731 case SCF_ERROR_INVALID_ARGUMENT
:
7732 case SCF_ERROR_HANDLE_MISMATCH
:
7734 bad_error("scf_instance_get_pg",
7741 /* find service snaplevel */
7742 r
= get_snaplevel(imp_snap
, 1, imp_snpl
);
7754 if (scf_instance_get_name(imp_inst
, imp_str
,
7756 (void) strcpy(imp_str
, "?");
7757 warn(badsnap
, snap_lastimport
, s
->sc_name
, imp_str
);
7758 lcbdata
->sc_err
= EBADF
;
7760 return (UU_WALK_ERROR
);
7763 bad_error("get_snaplevel", r
);
7766 if (scf_instance_get_snapshot(imp_inst
, snap_running
,
7768 switch (scf_error()) {
7769 case SCF_ERROR_DELETED
:
7772 case SCF_ERROR_NOT_FOUND
:
7775 case SCF_ERROR_CONNECTION_BROKEN
:
7778 case SCF_ERROR_INVALID_ARGUMENT
:
7779 case SCF_ERROR_HANDLE_MISMATCH
:
7780 case SCF_ERROR_NOT_BOUND
:
7781 case SCF_ERROR_NOT_SET
:
7783 bad_error("scf_instance_get_snapshot",
7788 r
= get_snaplevel(imp_rsnap
, 1, imp_rsnpl
);
7791 running
= imp_rsnpl
;
7801 if (scf_instance_get_name(imp_inst
, imp_str
,
7803 (void) strcpy(imp_str
, "?");
7804 warn(badsnap
, snap_running
, s
->sc_name
,
7806 lcbdata
->sc_err
= EBADF
;
7808 return (UU_WALK_ERROR
);
7811 bad_error("get_snaplevel", r
);
7816 if (scf_instance_get_name(imp_inst
, imp_str
,
7818 (void) strcpy(imp_str
, "?");
7819 warn(gettext("Upgrading properties of %s according to "
7820 "instance \"%s\".\n"), s
->sc_fmri
, imp_str
);
7823 /* upgrade service properties */
7824 r
= upgrade_props(imp_svc
, running
, imp_snpl
, s
);
7833 warn(s_deleted
, s
->sc_fmri
);
7834 lcbdata
->sc_err
= EBUSY
;
7838 if (scf_instance_get_name(imp_inst
, imp_str
,
7840 (void) strcpy(imp_str
, "?");
7841 warn(i_deleted
, s
->sc_fmri
, imp_str
);
7842 lcbdata
->sc_err
= EBUSY
;
7846 lcbdata
->sc_err
= r
;
7850 return (UU_WALK_ERROR
);
7853 s
->sc_import_state
= IMPORT_PROP_DONE
;
7856 /* import instances */
7857 cbdata
.sc_handle
= lcbdata
->sc_handle
;
7858 cbdata
.sc_parent
= imp_svc
;
7859 cbdata
.sc_service
= 1;
7860 cbdata
.sc_flags
= lcbdata
->sc_flags
| (fresh
? SCI_FRESH
: 0);
7861 cbdata
.sc_general
= NULL
;
7863 if (uu_list_walk(s
->sc_u
.sc_service
.sc_service_instances
,
7864 lscf_instance_import
, &cbdata
, UU_DEFAULT
) != 0) {
7865 if (uu_error() != UU_ERROR_CALLBACK_FAILED
)
7866 bad_error("uu_list_walk", uu_error());
7868 lcbdata
->sc_err
= cbdata
.sc_err
;
7869 if (cbdata
.sc_err
== ECONNABORTED
)
7872 return (UU_WALK_ERROR
);
7875 s
->sc_import_state
= IMPORT_COMPLETE
;
7877 return (UU_WALK_NEXT
);
7880 lcbdata
->sc_err
= ECONNABORTED
;
7881 return (UU_WALK_ERROR
);
7885 import_progress(int st
)
7889 return (gettext("not reached."));
7891 case IMPORT_PREVIOUS
:
7892 return (gettext("previous snapshot taken."));
7894 case IMPORT_PROP_BEGUN
:
7895 return (gettext("some properties imported."));
7897 case IMPORT_PROP_DONE
:
7898 return (gettext("properties imported."));
7900 case IMPORT_COMPLETE
:
7901 return (gettext("imported."));
7903 case IMPORT_REFRESHED
:
7904 return (gettext("refresh requested."));
7908 (void) fprintf(stderr
, "%s:%d: Unknown entity state %d.\n",
7909 __FILE__
, __LINE__
, st
);
7919 * - fmri wasn't found (error printed)
7920 * - entity was deleted (error printed)
7921 * - backend denied access (error printed)
7922 * ENOMEM - out of memory (error printed)
7923 * ECONNABORTED - repository connection broken (error printed)
7924 * EPERM - permission denied (error printed)
7925 * -1 - unknown libscf error (error printed)
7928 imp_refresh_fmri(const char *fmri
, const char *name
, const char *d_fmri
)
7935 const char *deleted
= gettext("Could not refresh %s (deleted).\n");
7936 const char *dpt_deleted
= gettext("Could not refresh %s "
7937 "(dependent \"%s\" of %s) (deleted).\n");
7939 serr
= fmri_to_entity(g_hndl
, fmri
, &ent
, &issvc
);
7941 case SCF_ERROR_NONE
:
7944 case SCF_ERROR_NO_MEMORY
:
7946 warn(gettext("Could not refresh %s (out of memory).\n"),
7949 warn(gettext("Could not refresh %s "
7950 "(dependent \"%s\" of %s) (out of memory).\n"),
7951 fmri
, name
, d_fmri
);
7954 case SCF_ERROR_NOT_FOUND
:
7956 warn(deleted
, fmri
);
7958 warn(dpt_deleted
, fmri
, name
, d_fmri
);
7961 case SCF_ERROR_INVALID_ARGUMENT
:
7962 case SCF_ERROR_CONSTRAINT_VIOLATED
:
7964 bad_error("fmri_to_entity", serr
);
7967 r
= refresh_entity(issvc
, ent
, fmri
, imp_inst
, imp_iter
, imp_str
);
7974 warn(gettext("Could not refresh %s "
7975 "(dependent \"%s\" of %s) "
7976 "(repository connection broken).\n"), fmri
, name
,
7982 warn(deleted
, fmri
);
7984 warn(dpt_deleted
, fmri
, name
, d_fmri
);
7991 warn(gettext("Could not refresh %s "
7992 "(backend access denied).\n"), fmri
);
7994 warn(gettext("Could not refresh %s "
7995 "(dependent \"%s\" of %s) "
7996 "(backend access denied).\n"), fmri
, name
, d_fmri
);
8001 warn(gettext("Could not refresh %s "
8002 "(permission denied).\n"), fmri
);
8004 warn(gettext("Could not refresh %s "
8005 "(dependent \"%s\" of %s) "
8006 "(permission denied).\n"), fmri
, name
, d_fmri
);
8011 warn(gettext("Could not refresh %s "
8012 "(repository server out of resources).\n"),
8015 warn(gettext("Could not refresh %s "
8016 "(dependent \"%s\" of %s) "
8017 "(repository server out of resources).\n"),
8018 fmri
, name
, d_fmri
);
8026 bad_error("refresh_entity", r
);
8030 scf_service_destroy(ent
);
8032 scf_instance_destroy(ent
);
8042 const char * const emsg_nomem
= gettext("Out of memory.\n");
8043 const char * const emsg_nores
=
8044 gettext("svc.configd is out of resources.\n");
8046 imp_str_sz
= ((max_scf_name_len
> max_scf_fmri_len
) ?
8047 max_scf_name_len
: max_scf_fmri_len
) + 1;
8049 if ((imp_scope
= scf_scope_create(g_hndl
)) == NULL
||
8050 (imp_svc
= scf_service_create(g_hndl
)) == NULL
||
8051 (imp_tsvc
= scf_service_create(g_hndl
)) == NULL
||
8052 (imp_inst
= scf_instance_create(g_hndl
)) == NULL
||
8053 (imp_tinst
= scf_instance_create(g_hndl
)) == NULL
||
8054 (imp_snap
= scf_snapshot_create(g_hndl
)) == NULL
||
8055 (imp_lisnap
= scf_snapshot_create(g_hndl
)) == NULL
||
8056 (imp_tlisnap
= scf_snapshot_create(g_hndl
)) == NULL
||
8057 (imp_rsnap
= scf_snapshot_create(g_hndl
)) == NULL
||
8058 (imp_snpl
= scf_snaplevel_create(g_hndl
)) == NULL
||
8059 (imp_rsnpl
= scf_snaplevel_create(g_hndl
)) == NULL
||
8060 (imp_pg
= scf_pg_create(g_hndl
)) == NULL
||
8061 (imp_pg2
= scf_pg_create(g_hndl
)) == NULL
||
8062 (imp_prop
= scf_property_create(g_hndl
)) == NULL
||
8063 (imp_iter
= scf_iter_create(g_hndl
)) == NULL
||
8064 (imp_rpg_iter
= scf_iter_create(g_hndl
)) == NULL
||
8065 (imp_up_iter
= scf_iter_create(g_hndl
)) == NULL
||
8066 (imp_tx
= scf_transaction_create(g_hndl
)) == NULL
||
8067 (imp_str
= malloc(imp_str_sz
)) == NULL
||
8068 (imp_tsname
= malloc(max_scf_name_len
+ 1)) == NULL
||
8069 (imp_fe1
= malloc(max_scf_fmri_len
+ 1)) == NULL
||
8070 (imp_fe2
= malloc(max_scf_fmri_len
+ 1)) == NULL
||
8071 (imp_deleted_dpts
= uu_list_create(string_pool
, NULL
, 0)) == NULL
||
8072 (ud_inst
= scf_instance_create(g_hndl
)) == NULL
||
8073 (ud_snpl
= scf_snaplevel_create(g_hndl
)) == NULL
||
8074 (ud_pg
= scf_pg_create(g_hndl
)) == NULL
||
8075 (ud_cur_depts_pg
= scf_pg_create(g_hndl
)) == NULL
||
8076 (ud_run_dpts_pg
= scf_pg_create(g_hndl
)) == NULL
||
8077 (ud_prop
= scf_property_create(g_hndl
)) == NULL
||
8078 (ud_dpt_prop
= scf_property_create(g_hndl
)) == NULL
||
8079 (ud_val
= scf_value_create(g_hndl
)) == NULL
||
8080 (ud_iter
= scf_iter_create(g_hndl
)) == NULL
||
8081 (ud_iter2
= scf_iter_create(g_hndl
)) == NULL
||
8082 (ud_tx
= scf_transaction_create(g_hndl
)) == NULL
||
8083 (ud_ctarg
= malloc(max_scf_value_len
+ 1)) == NULL
||
8084 (ud_oldtarg
= malloc(max_scf_value_len
+ 1)) == NULL
||
8085 (ud_name
= malloc(max_scf_name_len
+ 1)) == NULL
) {
8086 if (scf_error() == SCF_ERROR_NO_RESOURCES
)
8104 bad_error("load_init", r
);
8121 ud_ctarg
= ud_oldtarg
= ud_name
= NULL
;
8123 scf_transaction_destroy(ud_tx
);
8125 scf_iter_destroy(ud_iter
);
8126 scf_iter_destroy(ud_iter2
);
8127 ud_iter
= ud_iter2
= NULL
;
8128 scf_value_destroy(ud_val
);
8130 scf_property_destroy(ud_prop
);
8131 scf_property_destroy(ud_dpt_prop
);
8132 ud_prop
= ud_dpt_prop
= NULL
;
8133 scf_pg_destroy(ud_pg
);
8134 scf_pg_destroy(ud_cur_depts_pg
);
8135 scf_pg_destroy(ud_run_dpts_pg
);
8136 ud_pg
= ud_cur_depts_pg
= ud_run_dpts_pg
= NULL
;
8137 scf_snaplevel_destroy(ud_snpl
);
8139 scf_instance_destroy(ud_inst
);
8146 imp_str
= imp_tsname
= imp_fe1
= imp_fe2
= NULL
;
8149 while ((old_dpt
= uu_list_teardown(imp_deleted_dpts
, &cookie
)) !=
8151 free((char *)old_dpt
->sc_pgroup_name
);
8152 free((char *)old_dpt
->sc_pgroup_fmri
);
8153 internal_pgroup_free(old_dpt
);
8155 uu_list_destroy(imp_deleted_dpts
);
8157 scf_transaction_destroy(imp_tx
);
8159 scf_iter_destroy(imp_iter
);
8160 scf_iter_destroy(imp_rpg_iter
);
8161 scf_iter_destroy(imp_up_iter
);
8162 imp_iter
= imp_rpg_iter
= imp_up_iter
= NULL
;
8163 scf_property_destroy(imp_prop
);
8165 scf_pg_destroy(imp_pg
);
8166 scf_pg_destroy(imp_pg2
);
8167 imp_pg
= imp_pg2
= NULL
;
8168 scf_snaplevel_destroy(imp_snpl
);
8169 scf_snaplevel_destroy(imp_rsnpl
);
8170 imp_snpl
= imp_rsnpl
= NULL
;
8171 scf_snapshot_destroy(imp_snap
);
8172 scf_snapshot_destroy(imp_lisnap
);
8173 scf_snapshot_destroy(imp_tlisnap
);
8174 scf_snapshot_destroy(imp_rsnap
);
8175 imp_snap
= imp_lisnap
= imp_tlisnap
= imp_rsnap
= NULL
;
8176 scf_instance_destroy(imp_inst
);
8177 scf_instance_destroy(imp_tinst
);
8178 imp_inst
= imp_tinst
= NULL
;
8179 scf_service_destroy(imp_svc
);
8180 scf_service_destroy(imp_tsvc
);
8181 imp_svc
= imp_tsvc
= NULL
;
8182 scf_scope_destroy(imp_scope
);
8189 lscf_bundle_import(bundle_t
*bndl
, const char *filename
, uint_t flags
)
8191 scf_callback_t cbdata
;
8193 entity_t
*svc
, *inst
;
8197 int annotation_set
= 0;
8199 const char * const emsg_nomem
= gettext("Out of memory.\n");
8200 const char * const emsg_nores
=
8201 gettext("svc.configd is out of resources.\n");
8205 if (alloc_imp_globals())
8208 if (scf_handle_get_scope(g_hndl
, SCF_SCOPE_LOCAL
, imp_scope
) != 0) {
8209 switch (scf_error()) {
8210 case SCF_ERROR_CONNECTION_BROKEN
:
8211 warn(gettext("Repository connection broken.\n"));
8212 repository_teardown();
8216 case SCF_ERROR_NOT_FOUND
:
8217 case SCF_ERROR_INVALID_ARGUMENT
:
8218 case SCF_ERROR_NOT_BOUND
:
8219 case SCF_ERROR_HANDLE_MISMATCH
:
8221 bad_error("scf_handle_get_scope", scf_error());
8225 /* Set up the auditing annotation. */
8226 if (_scf_set_annotation(g_hndl
, "svccfg import", filename
) == 0) {
8229 switch (scf_error()) {
8230 case SCF_ERROR_CONNECTION_BROKEN
:
8231 warn(gettext("Repository connection broken.\n"));
8232 repository_teardown();
8236 case SCF_ERROR_INVALID_ARGUMENT
:
8237 case SCF_ERROR_NOT_BOUND
:
8238 case SCF_ERROR_NO_RESOURCES
:
8239 case SCF_ERROR_INTERNAL
:
8240 bad_error("_scf_set_annotation", scf_error());
8245 * Do not terminate import because of inability to
8246 * generate annotation audit event.
8248 warn(gettext("_scf_set_annotation() unexpectedly "
8249 "failed with return code of %d\n"), scf_error());
8255 * Clear the sc_import_state's of all services & instances so we can
8256 * report how far we got if we fail.
8258 for (svc
= uu_list_first(bndl
->sc_bundle_services
);
8260 svc
= uu_list_next(bndl
->sc_bundle_services
, svc
)) {
8261 svc
->sc_import_state
= 0;
8263 if (uu_list_walk(svc
->sc_u
.sc_service
.sc_service_instances
,
8264 clear_int
, (void *)offsetof(entity_t
, sc_import_state
),
8266 bad_error("uu_list_walk", uu_error());
8269 cbdata
.sc_handle
= g_hndl
;
8270 cbdata
.sc_parent
= imp_scope
;
8271 cbdata
.sc_flags
= flags
;
8272 cbdata
.sc_general
= NULL
;
8274 if (uu_list_walk(bndl
->sc_bundle_services
, lscf_service_import
,
8275 &cbdata
, UU_DEFAULT
) == 0) {
8277 /* Success. Refresh everything. */
8279 if (flags
& SCI_NOREFRESH
|| no_refresh
) {
8285 for (svc
= uu_list_first(bndl
->sc_bundle_services
);
8287 svc
= uu_list_next(bndl
->sc_bundle_services
, svc
)) {
8290 insts
= svc
->sc_u
.sc_service
.sc_service_instances
;
8292 for (inst
= uu_list_first(insts
);
8294 inst
= uu_list_next(insts
, inst
)) {
8295 r
= imp_refresh_fmri(inst
->sc_fmri
, NULL
, NULL
);
8307 bad_error("imp_refresh_fmri", r
);
8310 inst
->sc_import_state
= IMPORT_REFRESHED
;
8312 for (dpt
= uu_list_first(inst
->sc_dependents
);
8314 dpt
= uu_list_next(inst
->sc_dependents
,
8316 if (imp_refresh_fmri(
8317 dpt
->sc_pgroup_fmri
,
8318 dpt
->sc_pgroup_name
,
8319 inst
->sc_fmri
) != 0)
8323 for (dpt
= uu_list_first(svc
->sc_dependents
);
8325 dpt
= uu_list_next(svc
->sc_dependents
, dpt
))
8326 if (imp_refresh_fmri(dpt
->sc_pgroup_fmri
,
8327 dpt
->sc_pgroup_name
, svc
->sc_fmri
) != 0)
8331 for (old_dpt
= uu_list_first(imp_deleted_dpts
);
8333 old_dpt
= uu_list_next(imp_deleted_dpts
, old_dpt
))
8334 if (imp_refresh_fmri(old_dpt
->sc_pgroup_fmri
,
8335 old_dpt
->sc_pgroup_name
,
8336 old_dpt
->sc_parent
->sc_fmri
) != 0)
8342 * This snippet of code assumes that we are running svccfg as we
8343 * normally do -- witih svc.startd running. Of course, that is
8344 * not actually the case all the time because we also use a
8345 * varient of svc.configd and svccfg which are only meant to
8346 * run during the build process. During this time we have no
8347 * svc.startd, so this check would hang the build process.
8349 * However, we've also given other consolidations, a bit of a
8350 * means to tie themselves into a knot. They're not properly
8351 * using the native build equivalents, but they've been getting
8352 * away with it anyways. Therefore, if we've found that
8353 * SVCCFG_REPOSITORY is set indicating that a separate configd
8354 * should be spun up, then we have to assume it's not using a
8355 * startd and we should not do this check.
8357 #ifndef NATIVE_BUILD
8359 * Verify that the restarter group is preset
8361 eptr
= getenv("SVCCFG_REPOSITORY");
8362 for (svc
= uu_list_first(bndl
->sc_bundle_services
);
8363 svc
!= NULL
&& eptr
== NULL
;
8364 svc
= uu_list_next(bndl
->sc_bundle_services
, svc
)) {
8366 insts
= svc
->sc_u
.sc_service
.sc_service_instances
;
8368 for (inst
= uu_list_first(insts
);
8370 inst
= uu_list_next(insts
, inst
)) {
8371 if (lscf_instance_verify(imp_scope
, svc
,
8381 if (uu_error() != UU_ERROR_CALLBACK_FAILED
)
8382 bad_error("uu_list_walk", uu_error());
8385 /* If the error hasn't been printed yet, do so here. */
8386 switch (cbdata
.sc_err
) {
8388 warn(gettext("Repository connection broken.\n"));
8400 warn(gettext("Repository is read-only.\n"));
8404 warn(gettext("Repository backend denied access.\n"));
8416 bad_error("lscf_service_import", cbdata
.sc_err
);
8420 warn(gettext("Import of %s failed. Progress:\n"), filename
);
8422 for (svc
= uu_list_first(bndl
->sc_bundle_services
);
8424 svc
= uu_list_next(bndl
->sc_bundle_services
, svc
)) {
8425 insts
= svc
->sc_u
.sc_service
.sc_service_instances
;
8427 warn(gettext(" Service \"%s\": %s\n"), svc
->sc_name
,
8428 import_progress(svc
->sc_import_state
));
8430 for (inst
= uu_list_first(insts
);
8432 inst
= uu_list_next(insts
, inst
))
8433 warn(gettext(" Instance \"%s\": %s\n"),
8435 import_progress(inst
->sc_import_state
));
8438 if (cbdata
.sc_err
== ECONNABORTED
)
8439 repository_teardown();
8445 if (annotation_set
!= 0) {
8446 /* Turn off annotation. It is no longer needed. */
8447 (void) _scf_set_annotation(g_hndl
, NULL
, NULL
);
8456 * _lscf_import_err() summarize the error handling returned by
8457 * lscf_import_{instance | service}_pgs
8458 * Return values are:
8464 #define IMPORT_BAD -1
8465 #define IMPORT_NEXT 0
8466 #define IMPORT_OUT 1
8469 _lscf_import_err(int err
, const char *fmri
)
8474 warn(gettext("%s updated.\n"), fmri
);
8475 return (IMPORT_NEXT
);
8478 warn(gettext("Could not update %s "
8479 "(repository connection broken).\n"), fmri
);
8480 return (IMPORT_OUT
);
8483 warn(gettext("Could not update %s (out of memory).\n"), fmri
);
8484 return (IMPORT_OUT
);
8487 warn(gettext("Could not update %s "
8488 "(repository server out of resources).\n"), fmri
);
8489 return (IMPORT_OUT
);
8493 "Could not update %s (deleted).\n"), fmri
);
8494 return (IMPORT_NEXT
);
8499 return (IMPORT_NEXT
);
8502 warn(gettext("Could not update %s (repository read-only).\n"),
8504 return (IMPORT_OUT
);
8507 warn(gettext("Could not update %s "
8508 "(backend access denied).\n"), fmri
);
8509 return (IMPORT_NEXT
);
8513 return (IMPORT_BAD
);
8520 * The global imp_svc and imp_inst should be set by the caller in the
8521 * check to make sure the service and instance exist that the apply is
8525 lscf_dependent_apply(void *dpg
, void *e
)
8528 pgroup_t
*dpt_pgroup
= dpg
;
8532 void *sc_ent
, *tent
;
8536 const char * const dependents
= "dependents";
8537 const int issvc
= (ent
->sc_etype
== SVCCFG_SERVICE_OBJECT
);
8544 if (entity_get_running_pg(sc_ent
, issvc
, dependents
, imp_pg
,
8545 imp_iter
, imp_tinst
, imp_snap
, imp_snpl
) != 0 ||
8546 scf_pg_get_property(imp_pg
, dpt_pgroup
->sc_pgroup_name
,
8548 switch (scf_error()) {
8549 case SCF_ERROR_NOT_FOUND
:
8550 case SCF_ERROR_DELETED
:
8553 case SCF_ERROR_CONNECTION_BROKEN
:
8554 case SCF_ERROR_NOT_SET
:
8555 case SCF_ERROR_INVALID_ARGUMENT
:
8556 case SCF_ERROR_HANDLE_MISMATCH
:
8557 case SCF_ERROR_NOT_BOUND
:
8559 bad_error("entity_get_pg", scf_error());
8563 * Found the dependents/<wip dep> so check to
8564 * see if the service is different. If so
8565 * store the service for later refresh, and
8566 * delete the wip dependency from the service
8568 if (scf_property_get_value(imp_prop
, ud_val
) != 0) {
8569 switch (scf_error()) {
8570 case SCF_ERROR_DELETED
:
8573 case SCF_ERROR_CONNECTION_BROKEN
:
8574 case SCF_ERROR_NOT_SET
:
8575 case SCF_ERROR_INVALID_ARGUMENT
:
8576 case SCF_ERROR_HANDLE_MISMATCH
:
8577 case SCF_ERROR_NOT_BOUND
:
8579 bad_error("scf_property_get_value",
8584 if (scf_value_get_as_string(ud_val
, ud_oldtarg
,
8585 max_scf_value_len
+ 1) < 0)
8586 bad_error("scf_value_get_as_string", scf_error());
8588 r
= fmri_equal(dpt_pgroup
->sc_pgroup_fmri
, ud_oldtarg
);
8593 if ((serr
= fmri_to_entity(g_hndl
, ud_oldtarg
, &tent
,
8594 &tissvc
)) != SCF_ERROR_NONE
) {
8595 if (serr
== SCF_ERROR_NOT_FOUND
) {
8598 bad_error("fmri_to_entity", serr
);
8602 if (entity_get_pg(tent
, tissvc
,
8603 dpt_pgroup
->sc_pgroup_name
, imp_pg
) != 0) {
8605 if (serr
== SCF_ERROR_NOT_FOUND
||
8606 serr
== SCF_ERROR_DELETED
) {
8609 bad_error("entity_get_pg", scf_error());
8613 if (scf_pg_delete(imp_pg
) != 0) {
8615 if (serr
== SCF_ERROR_NOT_FOUND
||
8616 serr
== SCF_ERROR_DELETED
) {
8619 bad_error("scf_pg_delete", scf_error());
8623 deldpt
= internal_pgroup_new();
8626 deldpt
->sc_pgroup_name
=
8627 strdup(dpt_pgroup
->sc_pgroup_name
);
8628 deldpt
->sc_pgroup_fmri
= strdup(ud_oldtarg
);
8629 if (deldpt
->sc_pgroup_name
== NULL
||
8630 deldpt
->sc_pgroup_fmri
== NULL
)
8632 deldpt
->sc_parent
= (entity_t
*)ent
;
8633 if (uu_list_insert_after(imp_deleted_dpts
, NULL
,
8635 uu_die(gettext("libuutil error: %s\n"),
8636 uu_strerror(uu_error()));
8640 bad_error("fmri_equal", r
);
8644 cb
.sc_handle
= g_hndl
;
8646 cb
.sc_service
= ent
->sc_etype
== SVCCFG_SERVICE_OBJECT
;
8647 cb
.sc_source_fmri
= ent
->sc_fmri
;
8648 cb
.sc_target_fmri
= ent
->sc_fmri
;
8650 cb
.sc_flags
= SCI_FORCE
;
8652 if (lscf_dependent_import(dpt_pgroup
, &cb
) != UU_WALK_NEXT
)
8653 return (UU_WALK_ERROR
);
8655 r
= imp_refresh_fmri(dpt_pgroup
->sc_pgroup_fmri
, NULL
, NULL
);
8664 warn(gettext("Unable to refresh \"%s\"\n"),
8665 dpt_pgroup
->sc_pgroup_fmri
);
8666 return (UU_WALK_ERROR
);
8669 bad_error("imp_refresh_fmri", r
);
8672 return (UU_WALK_NEXT
);
8678 * -1 - lscf_import_instance_pgs() failed.
8681 lscf_bundle_apply(bundle_t
*bndl
, const char *file
)
8684 entity_t
*svc
, *inst
;
8685 int annotation_set
= 0;
8691 if ((ret
= alloc_imp_globals()))
8694 if (scf_handle_get_scope(g_hndl
, SCF_SCOPE_LOCAL
, imp_scope
) != 0)
8698 * Set the strings to be used for the security audit annotation
8701 if (_scf_set_annotation(g_hndl
, "svccfg apply", file
) == 0) {
8704 switch (scf_error()) {
8705 case SCF_ERROR_CONNECTION_BROKEN
:
8706 warn(gettext("Repository connection broken.\n"));
8709 case SCF_ERROR_INVALID_ARGUMENT
:
8710 case SCF_ERROR_NOT_BOUND
:
8711 case SCF_ERROR_NO_RESOURCES
:
8712 case SCF_ERROR_INTERNAL
:
8713 bad_error("_scf_set_annotation", scf_error());
8718 * Do not abort apply operation because of
8719 * inability to create annotation audit event.
8721 warn(gettext("_scf_set_annotation() unexpectedly "
8722 "failed with return code of %d\n"), scf_error());
8727 for (svc
= uu_list_first(bndl
->sc_bundle_services
);
8729 svc
= uu_list_next(bndl
->sc_bundle_services
, svc
)) {
8732 if (scf_scope_get_service(imp_scope
, svc
->sc_name
,
8734 switch (scf_error()) {
8735 case SCF_ERROR_NOT_FOUND
:
8737 warn(gettext("Ignoring nonexistent "
8738 "service %s.\n"), svc
->sc_name
);
8747 * If there were missing types in the profile, then need to
8748 * attempt to find the types.
8750 if (svc
->sc_miss_type
) {
8751 if (uu_list_numnodes(svc
->sc_pgroups
) &&
8752 uu_list_walk(svc
->sc_pgroups
, find_current_pg_type
,
8753 svc
, UU_DEFAULT
) != 0) {
8754 if (uu_error() != UU_ERROR_CALLBACK_FAILED
)
8755 bad_error("uu_list_walk", uu_error());
8761 for (inst
= uu_list_first(
8762 svc
->sc_u
.sc_service
.sc_service_instances
);
8764 inst
= uu_list_next(
8765 svc
->sc_u
.sc_service
.sc_service_instances
, inst
)) {
8767 * If the instance doesn't exist just
8768 * skip to the next instance and let the
8769 * import note the missing instance.
8771 if (scf_service_get_instance(imp_svc
,
8772 inst
->sc_name
, imp_inst
) != 0)
8775 if (uu_list_walk(inst
->sc_pgroups
,
8776 find_current_pg_type
, inst
,
8779 UU_ERROR_CALLBACK_FAILED
)
8780 bad_error("uu_list_walk",
8784 inst
->sc_miss_type
= B_TRUE
;
8790 * if we have pgs in the profile, we need to refresh ALL
8791 * instances of the service
8793 if (uu_list_numnodes(svc
->sc_pgroups
) != 0) {
8795 r
= lscf_import_service_pgs(imp_svc
, svc
->sc_fmri
, svc
,
8796 SCI_FORCE
| SCI_KEEP
);
8797 switch (_lscf_import_err(r
, svc
->sc_fmri
)) {
8806 bad_error("lscf_import_service_pgs", r
);
8810 if (uu_list_numnodes(svc
->sc_dependents
) != 0) {
8811 uu_list_walk(svc
->sc_dependents
,
8812 lscf_dependent_apply
, svc
, UU_DEFAULT
);
8815 for (inst
= uu_list_first(
8816 svc
->sc_u
.sc_service
.sc_service_instances
);
8818 inst
= uu_list_next(
8819 svc
->sc_u
.sc_service
.sc_service_instances
, inst
)) {
8821 * This instance still has missing types
8824 if (inst
->sc_miss_type
) {
8826 warn(gettext("Ignoring instance "
8827 "%s:%s with missing types\n"),
8828 inst
->sc_parent
->sc_name
,
8834 if (scf_service_get_instance(imp_svc
, inst
->sc_name
,
8836 switch (scf_error()) {
8837 case SCF_ERROR_NOT_FOUND
:
8839 warn(gettext("Ignoring "
8840 "nonexistant instance "
8842 inst
->sc_parent
->sc_name
,
8852 * If the instance does not have a general/enabled
8853 * property and no last-import snapshot then the
8854 * instance is not a fully installed instance and
8855 * should not have a profile applied to it.
8857 * This could happen if a service/instance declares
8858 * a dependent on behalf of another service/instance.
8861 if (scf_instance_get_snapshot(imp_inst
, snap_lastimport
,
8863 if (scf_instance_get_pg(imp_inst
,
8864 SCF_PG_GENERAL
, imp_pg
) != 0 ||
8865 scf_pg_get_property(imp_pg
,
8866 SCF_PROPERTY_ENABLED
, imp_prop
) != 0) {
8868 warn(gettext("Ignoreing "
8871 inst
->sc_parent
->sc_name
,
8877 r
= lscf_import_instance_pgs(imp_inst
, inst
->sc_fmri
,
8878 inst
, SCI_FORCE
| SCI_KEEP
);
8879 switch (_lscf_import_err(r
, inst
->sc_fmri
)) {
8888 bad_error("lscf_import_instance_pgs", r
);
8891 if (uu_list_numnodes(inst
->sc_dependents
) != 0) {
8892 uu_list_walk(inst
->sc_dependents
,
8893 lscf_dependent_apply
, inst
, UU_DEFAULT
);
8896 /* refresh only if there is no pgs in the service */
8898 (void) refresh_entity(0, imp_inst
,
8899 inst
->sc_fmri
, NULL
, NULL
, NULL
);
8903 char *name_buf
= safe_malloc(max_scf_name_len
+ 1);
8905 (void) refresh_entity(1, imp_svc
, svc
->sc_name
,
8906 imp_inst
, imp_iter
, name_buf
);
8910 for (old_dpt
= uu_list_first(imp_deleted_dpts
);
8912 old_dpt
= uu_list_next(imp_deleted_dpts
, old_dpt
)) {
8913 if (imp_refresh_fmri(old_dpt
->sc_pgroup_fmri
,
8914 old_dpt
->sc_pgroup_name
,
8915 old_dpt
->sc_parent
->sc_fmri
) != 0) {
8916 warn(gettext("Unable to refresh \"%s\"\n"),
8917 old_dpt
->sc_pgroup_fmri
);
8923 if (annotation_set
) {
8924 /* Remove security audit annotation strings. */
8925 (void) _scf_set_annotation(g_hndl
, NULL
, NULL
);
8934 * Export. These functions create and output an XML tree of a service
8935 * description from the repository. This is largely the inverse of
8936 * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
8938 * - We must include any properties which are not represented specifically by
8939 * a service manifest, e.g., properties created by an admin post-import. To
8940 * do so we'll iterate through all properties and deal with each
8943 * - Children of services and instances must must be in the order set by the
8944 * DTD, but we iterate over the properties in undefined order. The elements
8945 * are not easily (or efficiently) sortable by name. Since there's a fixed
8946 * number of classes of them, however, we'll keep the classes separate and
8947 * assemble them in order.
8951 * Convenience function to handle xmlSetProp errors (and type casting).
8954 safe_setprop(xmlNodePtr n
, const char *name
, const char *val
)
8956 if (xmlSetProp(n
, (const xmlChar
*)name
, (const xmlChar
*)val
) == NULL
)
8957 uu_die(gettext("Could not set XML property.\n"));
8961 * Convenience function to set an XML attribute to the single value of an
8962 * astring property. If the value happens to be the default, don't set the
8963 * attribute. "dval" should be the default value supplied by the DTD, or
8964 * NULL for no default.
8967 set_attr_from_prop_default(scf_property_t
*prop
, xmlNodePtr n
,
8968 const char *name
, const char *dval
)
8974 val
= scf_value_create(g_hndl
);
8978 if (prop_get_val(prop
, val
) != 0) {
8979 scf_value_destroy(val
);
8983 len
= scf_value_get_as_string(val
, NULL
, 0);
8987 str
= safe_malloc(len
+ 1);
8989 if (scf_value_get_as_string(val
, str
, len
+ 1) < 0)
8992 scf_value_destroy(val
);
8994 if (dval
== NULL
|| strcmp(str
, dval
) != 0)
8995 safe_setprop(n
, name
, str
);
9003 * As above, but the attribute is always set.
9006 set_attr_from_prop(scf_property_t
*prop
, xmlNodePtr n
, const char *name
)
9008 return (set_attr_from_prop_default(prop
, n
, name
, NULL
));
9012 * Dump the given document onto f, with "'s replaced by ''s.
9015 write_service_bundle(xmlDocPtr doc
, FILE *f
)
9021 xmlDocDumpFormatMemory(doc
, &mem
, &sz
, 1);
9024 semerr(gettext("Could not dump XML tree.\n"));
9029 * Fortunately libxml produces " instead of ", so we can blindly
9030 * replace all " with '. Cursed libxml2! Why must you #ifdef out the
9033 for (i
= 0; i
< sz
; ++i
) {
9034 char c
= (char)mem
[i
];
9037 (void) fputc('\'', f
);
9039 (void) fwrite("'", sizeof ("'") - 1, 1, f
);
9048 * Create the DOM elements in elts necessary to (generically) represent prop
9049 * (i.e., a property or propval element). If the name of the property is
9050 * known, it should be passed as name_arg. Otherwise, pass NULL.
9053 export_property(scf_property_t
*prop
, const char *name_arg
,
9054 struct pg_elts
*elts
, int flags
)
9057 scf_error_t err
= 0;
9058 xmlNodePtr pnode
, lnode
;
9063 if (name_arg
!= NULL
) {
9064 (void) strcpy(exp_str
, name_arg
);
9066 if (scf_property_get_name(prop
, exp_str
, exp_str_sz
) < 0)
9071 type
= prop_to_typestr(prop
);
9073 uu_die(gettext("Can't export property %s: unknown type.\n"),
9076 /* If we're exporting values, and there's just one, export it here. */
9077 if (!(flags
& SCE_ALL_VALUES
))
9080 if (scf_property_get_value(prop
, exp_val
) == SCF_SUCCESS
) {
9083 /* Single value, so use propval */
9084 n
= xmlNewNode(NULL
, (xmlChar
*)"propval");
9086 uu_die(emsg_create_xml
);
9088 safe_setprop(n
, name_attr
, exp_str
);
9089 safe_setprop(n
, type_attr
, type
);
9091 if (scf_value_get_as_string(exp_val
, exp_str
, exp_str_sz
) < 0)
9093 safe_setprop(n
, value_attr
, exp_str
);
9095 if (elts
->propvals
== NULL
)
9098 (void) xmlAddSibling(elts
->propvals
, n
);
9105 if (err
== SCF_ERROR_PERMISSION_DENIED
) {
9106 semerr(emsg_permission_denied
);
9110 if (err
!= SCF_ERROR_CONSTRAINT_VIOLATED
&&
9111 err
!= SCF_ERROR_NOT_FOUND
&&
9112 err
!= SCF_ERROR_PERMISSION_DENIED
)
9116 /* Multiple (or no) values, so use property */
9117 pnode
= xmlNewNode(NULL
, (xmlChar
*)"property");
9119 uu_die(emsg_create_xml
);
9121 safe_setprop(pnode
, name_attr
, exp_str
);
9122 safe_setprop(pnode
, type_attr
, type
);
9124 if (err
== SCF_ERROR_CONSTRAINT_VIOLATED
) {
9125 lnname
= uu_msprintf("%s_list", type
);
9127 uu_die(gettext("Could not create string"));
9129 lnode
= xmlNewChild(pnode
, NULL
, (xmlChar
*)lnname
, NULL
);
9131 uu_die(emsg_create_xml
);
9135 if (scf_iter_property_values(exp_val_iter
, prop
) != SCF_SUCCESS
)
9138 while ((ret
= scf_iter_next_value(exp_val_iter
, exp_val
)) ==
9142 vn
= xmlNewChild(lnode
, NULL
, (xmlChar
*)"value_node",
9145 uu_die(emsg_create_xml
);
9147 if (scf_value_get_as_string(exp_val
, exp_str
,
9150 safe_setprop(vn
, value_attr
, exp_str
);
9156 if (elts
->properties
== NULL
)
9157 elts
->properties
= pnode
;
9159 (void) xmlAddSibling(elts
->properties
, pnode
);
9163 * Add a property_group element for this property group to elts.
9166 export_pg(scf_propertygroup_t
*pg
, struct entity_elts
*eelts
, int flags
)
9169 struct pg_elts elts
;
9171 boolean_t read_protected
;
9173 n
= xmlNewNode(NULL
, (xmlChar
*)"property_group");
9176 if (scf_pg_get_name(pg
, exp_str
, max_scf_name_len
+ 1) < 0)
9178 safe_setprop(n
, name_attr
, exp_str
);
9181 if (scf_pg_get_type(pg
, exp_str
, exp_str_sz
) < 0)
9183 safe_setprop(n
, type_attr
, exp_str
);
9186 if (scf_iter_pg_properties(exp_prop_iter
, pg
) != SCF_SUCCESS
)
9189 (void) memset(&elts
, 0, sizeof (elts
));
9192 * If this property group is not read protected, we always want to
9193 * output all the values. Otherwise, we only output the values if the
9194 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
9196 if (_scf_pg_is_read_protected(pg
, &read_protected
) != SCF_SUCCESS
)
9199 if (!read_protected
)
9200 flags
|= SCE_ALL_VALUES
;
9202 while ((ret
= scf_iter_next_property(exp_prop_iter
, exp_prop
)) == 1) {
9203 if (scf_property_get_name(exp_prop
, exp_str
, exp_str_sz
) < 0)
9206 if (strcmp(exp_str
, SCF_PROPERTY_STABILITY
) == 0) {
9209 m
= xmlNewNode(NULL
, (xmlChar
*)"stability");
9211 uu_die(emsg_create_xml
);
9213 if (set_attr_from_prop(exp_prop
, m
, value_attr
) == 0) {
9221 export_property(exp_prop
, NULL
, &elts
, flags
);
9226 (void) xmlAddChild(n
, elts
.stability
);
9227 (void) xmlAddChildList(n
, elts
.propvals
);
9228 (void) xmlAddChildList(n
, elts
.properties
);
9230 if (eelts
->property_groups
== NULL
)
9231 eelts
->property_groups
= n
;
9233 (void) xmlAddSibling(eelts
->property_groups
, n
);
9237 * Create an XML node representing the dependency described by the given
9238 * property group and put it in eelts. Unless the dependency is not valid, in
9239 * which case create a generic property_group element which represents it and
9243 export_dependency(scf_propertygroup_t
*pg
, struct entity_elts
*eelts
)
9247 struct pg_elts elts
;
9249 n
= xmlNewNode(NULL
, (xmlChar
*)"dependency");
9251 uu_die(emsg_create_xml
);
9254 * If the external flag is present, skip this dependency because it
9255 * should have been created by another manifest.
9257 if (scf_pg_get_property(pg
, scf_property_external
, exp_prop
) == 0) {
9258 if (prop_check_type(exp_prop
, SCF_TYPE_BOOLEAN
) == 0 &&
9259 prop_get_val(exp_prop
, exp_val
) == 0) {
9262 if (scf_value_get_boolean(exp_val
, &b
) != SCF_SUCCESS
)
9268 } else if (scf_error() != SCF_ERROR_NOT_FOUND
)
9271 /* Get the required attributes. */
9274 if (scf_pg_get_name(pg
, exp_str
, max_scf_name_len
+ 1) < 0)
9276 safe_setprop(n
, name_attr
, exp_str
);
9279 if (pg_get_prop(pg
, SCF_PROPERTY_GROUPING
, exp_prop
) != 0 ||
9280 set_attr_from_prop(exp_prop
, n
, "grouping") != 0)
9284 if (pg_get_prop(pg
, SCF_PROPERTY_RESTART_ON
, exp_prop
) != 0 ||
9285 set_attr_from_prop(exp_prop
, n
, "restart_on") != 0)
9289 if (pg_get_prop(pg
, SCF_PROPERTY_TYPE
, exp_prop
) != 0 ||
9290 set_attr_from_prop(exp_prop
, n
, type_attr
) != 0)
9294 * entities: Not required, but if we create no children, it will be
9295 * created as empty on import, so fail if it's missing.
9297 if (pg_get_prop(pg
, SCF_PROPERTY_ENTITIES
, exp_prop
) == 0 &&
9298 prop_check_type(exp_prop
, SCF_TYPE_FMRI
) == 0) {
9302 eiter
= scf_iter_create(g_hndl
);
9306 if (scf_iter_property_values(eiter
, exp_prop
) != SCF_SUCCESS
)
9309 while ((ret2
= scf_iter_next_value(eiter
, exp_val
)) == 1) {
9312 if (scf_value_get_astring(exp_val
, exp_str
,
9317 * service_fmri's must be first, so we can add them
9320 ch
= xmlNewChild(n
, NULL
, (xmlChar
*)"service_fmri",
9323 uu_die(emsg_create_xml
);
9325 safe_setprop(ch
, value_attr
, exp_str
);
9330 scf_iter_destroy(eiter
);
9337 export_pg(pg
, eelts
, SCE_ALL_VALUES
);
9342 /* Iterate through the properties & handle each. */
9343 if (scf_iter_pg_properties(exp_prop_iter
, pg
) != SCF_SUCCESS
)
9346 (void) memset(&elts
, 0, sizeof (elts
));
9348 while ((ret
= scf_iter_next_property(exp_prop_iter
, exp_prop
)) == 1) {
9349 if (scf_property_get_name(exp_prop
, exp_str
, exp_str_sz
) < 0)
9352 if (strcmp(exp_str
, SCF_PROPERTY_GROUPING
) == 0 ||
9353 strcmp(exp_str
, SCF_PROPERTY_RESTART_ON
) == 0 ||
9354 strcmp(exp_str
, SCF_PROPERTY_TYPE
) == 0 ||
9355 strcmp(exp_str
, SCF_PROPERTY_ENTITIES
) == 0) {
9357 } else if (strcmp(exp_str
, SCF_PROPERTY_STABILITY
) == 0) {
9360 m
= xmlNewNode(NULL
, (xmlChar
*)"stability");
9362 uu_die(emsg_create_xml
);
9364 if (set_attr_from_prop(exp_prop
, m
, value_attr
) == 0) {
9372 export_property(exp_prop
, exp_str
, &elts
, SCE_ALL_VALUES
);
9377 (void) xmlAddChild(n
, elts
.stability
);
9378 (void) xmlAddChildList(n
, elts
.propvals
);
9379 (void) xmlAddChildList(n
, elts
.properties
);
9381 if (eelts
->dependencies
== NULL
)
9382 eelts
->dependencies
= n
;
9384 (void) xmlAddSibling(eelts
->dependencies
, n
);
9388 export_method_environment(scf_propertygroup_t
*pg
)
9394 if (scf_pg_get_property(pg
, SCF_PROPERTY_ENVIRONMENT
, NULL
) != 0)
9397 env
= xmlNewNode(NULL
, (xmlChar
*)"method_environment");
9399 uu_die(emsg_create_xml
);
9401 if (pg_get_prop(pg
, SCF_PROPERTY_ENVIRONMENT
, exp_prop
) != 0)
9404 if (scf_iter_property_values(exp_val_iter
, exp_prop
) != SCF_SUCCESS
)
9407 while ((ret
= scf_iter_next_value(exp_val_iter
, exp_val
)) == 1) {
9411 if (scf_value_get_as_string(exp_val
, exp_str
, exp_str_sz
) < 0)
9414 if ((cp
= strchr(exp_str
, '=')) == NULL
|| cp
== exp_str
) {
9415 warn(gettext("Invalid environment variable \"%s\".\n"),
9418 } else if (strncmp(exp_str
, "SMF_", 4) == 0) {
9419 warn(gettext("Invalid environment variable \"%s\"; "
9420 "\"SMF_\" prefix is reserved.\n"), exp_str
);
9427 ev
= xmlNewChild(env
, NULL
, (xmlChar
*)"envvar", NULL
);
9429 uu_die(emsg_create_xml
);
9431 safe_setprop(ev
, name_attr
, exp_str
);
9432 safe_setprop(ev
, value_attr
, cp
);
9439 if (children
== 0) {
9448 * As above, but for a method property group.
9451 export_method(scf_propertygroup_t
*pg
, struct entity_elts
*eelts
)
9455 int err
= 0, nonenv
, ret
;
9456 uint8_t use_profile
;
9457 struct pg_elts elts
;
9458 xmlNodePtr ctxt
= NULL
;
9460 n
= xmlNewNode(NULL
, (xmlChar
*)"exec_method");
9462 /* Get the required attributes. */
9465 if (scf_pg_get_name(pg
, exp_str
, max_scf_name_len
+ 1) < 0)
9467 safe_setprop(n
, name_attr
, exp_str
);
9470 if (pg_get_prop(pg
, SCF_PROPERTY_TYPE
, exp_prop
) != 0 ||
9471 set_attr_from_prop(exp_prop
, n
, type_attr
) != 0)
9475 if (pg_get_prop(pg
, SCF_PROPERTY_EXEC
, exp_prop
) != 0 ||
9476 set_attr_from_prop(exp_prop
, n
, "exec") != 0)
9480 if (pg_get_prop(pg
, SCF_PROPERTY_TIMEOUT
, exp_prop
) == 0 &&
9481 prop_check_type(exp_prop
, SCF_TYPE_COUNT
) == 0 &&
9482 prop_get_val(exp_prop
, exp_val
) == 0) {
9485 if (scf_value_get_count(exp_val
, &c
) != SCF_SUCCESS
)
9488 str
= uu_msprintf("%llu", c
);
9490 uu_die(gettext("Could not create string"));
9492 safe_setprop(n
, "timeout_seconds", str
);
9500 export_pg(pg
, eelts
, SCE_ALL_VALUES
);
9507 * If we're going to have a method_context child, we need to know
9508 * before we iterate through the properties. Since method_context's
9509 * are optional, we don't want to complain about any properties
9510 * missing if none of them are there. Thus we can't use the
9511 * convenience functions.
9514 scf_pg_get_property(pg
, SCF_PROPERTY_WORKING_DIRECTORY
, NULL
) ==
9516 scf_pg_get_property(pg
, SCF_PROPERTY_PROJECT
, NULL
) ==
9518 scf_pg_get_property(pg
, SCF_PROPERTY_RESOURCE_POOL
, NULL
) ==
9520 scf_pg_get_property(pg
, SCF_PROPERTY_SECFLAGS
, NULL
) ==
9522 scf_pg_get_property(pg
, SCF_PROPERTY_USE_PROFILE
, NULL
) ==
9526 ctxt
= xmlNewNode(NULL
, (xmlChar
*)"method_context");
9528 uu_die(emsg_create_xml
);
9530 if (pg_get_prop(pg
, SCF_PROPERTY_WORKING_DIRECTORY
, exp_prop
) ==
9532 set_attr_from_prop_default(exp_prop
, ctxt
,
9533 "working_directory", ":default") != 0)
9536 if (pg_get_prop(pg
, SCF_PROPERTY_PROJECT
, exp_prop
) == 0 &&
9537 set_attr_from_prop_default(exp_prop
, ctxt
, "project",
9541 if (pg_get_prop(pg
, SCF_PROPERTY_RESOURCE_POOL
, exp_prop
) ==
9543 set_attr_from_prop_default(exp_prop
, ctxt
,
9544 "resource_pool", ":default") != 0)
9547 if (pg_get_prop(pg
, SCF_PROPERTY_SECFLAGS
, exp_prop
) == 0 &&
9548 set_attr_from_prop_default(exp_prop
, ctxt
,
9549 "security_flags", ":default") != 0)
9553 * We only want to complain about profile or credential
9554 * properties if we will use them. To determine that we must
9555 * examine USE_PROFILE.
9557 if (pg_get_prop(pg
, SCF_PROPERTY_USE_PROFILE
, exp_prop
) == 0 &&
9558 prop_check_type(exp_prop
, SCF_TYPE_BOOLEAN
) == 0 &&
9559 prop_get_val(exp_prop
, exp_val
) == 0) {
9560 if (scf_value_get_boolean(exp_val
, &use_profile
) !=
9568 prof
= xmlNewChild(ctxt
, NULL
,
9569 (xmlChar
*)"method_profile", NULL
);
9571 uu_die(emsg_create_xml
);
9573 if (pg_get_prop(pg
, SCF_PROPERTY_PROFILE
,
9575 set_attr_from_prop(exp_prop
, prof
,
9581 cred
= xmlNewChild(ctxt
, NULL
,
9582 (xmlChar
*)"method_credential", NULL
);
9584 uu_die(emsg_create_xml
);
9586 if (pg_get_prop(pg
, SCF_PROPERTY_USER
,
9588 set_attr_from_prop(exp_prop
, cred
,
9593 if (pg_get_prop(pg
, SCF_PROPERTY_GROUP
,
9595 set_attr_from_prop_default(exp_prop
, cred
,
9596 "group", ":default") != 0)
9599 if (pg_get_prop(pg
, SCF_PROPERTY_SUPP_GROUPS
,
9601 set_attr_from_prop_default(exp_prop
, cred
,
9602 "supp_groups", ":default") != 0)
9605 if (pg_get_prop(pg
, SCF_PROPERTY_PRIVILEGES
,
9607 set_attr_from_prop_default(exp_prop
, cred
,
9608 "privileges", ":default") != 0)
9612 SCF_PROPERTY_LIMIT_PRIVILEGES
,
9614 set_attr_from_prop_default(exp_prop
, cred
,
9615 "limit_privileges", ":default") != 0)
9621 if ((env
= export_method_environment(pg
)) != NULL
) {
9623 ctxt
= xmlNewNode(NULL
, (xmlChar
*)"method_context");
9625 uu_die(emsg_create_xml
);
9627 (void) xmlAddChild(ctxt
, env
);
9630 if (env
!= NULL
|| (nonenv
&& err
== 0))
9631 (void) xmlAddChild(n
, ctxt
);
9635 nonenv
= (err
== 0);
9637 if (scf_iter_pg_properties(exp_prop_iter
, pg
) != SCF_SUCCESS
)
9640 (void) memset(&elts
, 0, sizeof (elts
));
9642 while ((ret
= scf_iter_next_property(exp_prop_iter
, exp_prop
)) == 1) {
9643 if (scf_property_get_name(exp_prop
, exp_str
, exp_str_sz
) < 0)
9646 if (strcmp(exp_str
, SCF_PROPERTY_TYPE
) == 0 ||
9647 strcmp(exp_str
, SCF_PROPERTY_EXEC
) == 0 ||
9648 strcmp(exp_str
, SCF_PROPERTY_TIMEOUT
) == 0) {
9650 } else if (strcmp(exp_str
, SCF_PROPERTY_STABILITY
) == 0) {
9653 m
= xmlNewNode(NULL
, (xmlChar
*)"stability");
9655 uu_die(emsg_create_xml
);
9657 if (set_attr_from_prop(exp_prop
, m
, value_attr
) == 0) {
9663 } else if (strcmp(exp_str
, SCF_PROPERTY_WORKING_DIRECTORY
) ==
9665 strcmp(exp_str
, SCF_PROPERTY_PROJECT
) == 0 ||
9666 strcmp(exp_str
, SCF_PROPERTY_RESOURCE_POOL
) == 0 ||
9667 strcmp(exp_str
, SCF_PROPERTY_USE_PROFILE
) == 0) {
9670 } else if (strcmp(exp_str
, SCF_PROPERTY_USER
) == 0 ||
9671 strcmp(exp_str
, SCF_PROPERTY_GROUP
) == 0 ||
9672 strcmp(exp_str
, SCF_PROPERTY_SUPP_GROUPS
) == 0 ||
9673 strcmp(exp_str
, SCF_PROPERTY_PRIVILEGES
) == 0 ||
9674 strcmp(exp_str
, SCF_PROPERTY_LIMIT_PRIVILEGES
) == 0 ||
9675 strcmp(exp_str
, SCF_PROPERTY_SECFLAGS
) == 0) {
9676 if (nonenv
&& !use_profile
)
9678 } else if (strcmp(exp_str
, SCF_PROPERTY_PROFILE
) == 0) {
9679 if (nonenv
&& use_profile
)
9681 } else if (strcmp(exp_str
, SCF_PROPERTY_ENVIRONMENT
) == 0) {
9686 export_property(exp_prop
, exp_str
, &elts
, SCE_ALL_VALUES
);
9691 (void) xmlAddChild(n
, elts
.stability
);
9692 (void) xmlAddChildList(n
, elts
.propvals
);
9693 (void) xmlAddChildList(n
, elts
.properties
);
9695 if (eelts
->exec_methods
== NULL
)
9696 eelts
->exec_methods
= n
;
9698 (void) xmlAddSibling(eelts
->exec_methods
, n
);
9702 export_pg_elts(struct pg_elts
*elts
, const char *name
, const char *type
,
9703 struct entity_elts
*eelts
)
9707 pgnode
= xmlNewNode(NULL
, (xmlChar
*)"property_group");
9709 uu_die(emsg_create_xml
);
9711 safe_setprop(pgnode
, name_attr
, name
);
9712 safe_setprop(pgnode
, type_attr
, type
);
9714 (void) xmlAddChildList(pgnode
, elts
->propvals
);
9715 (void) xmlAddChildList(pgnode
, elts
->properties
);
9717 if (eelts
->property_groups
== NULL
)
9718 eelts
->property_groups
= pgnode
;
9720 (void) xmlAddSibling(eelts
->property_groups
, pgnode
);
9724 * Process the general property group for a service. This is the one with the
9728 export_svc_general(scf_propertygroup_t
*pg
, struct entity_elts
*selts
)
9730 struct pg_elts elts
;
9734 * In case there are properties which don't correspond to child
9735 * entities of the service entity, we'll set up a pg_elts structure to
9738 (void) memset(&elts
, 0, sizeof (elts
));
9740 /* Walk the properties, looking for special ones. */
9741 if (scf_iter_pg_properties(exp_prop_iter
, pg
) != SCF_SUCCESS
)
9744 while ((ret
= scf_iter_next_property(exp_prop_iter
, exp_prop
)) == 1) {
9745 if (scf_property_get_name(exp_prop
, exp_str
, exp_str_sz
) < 0)
9748 if (strcmp(exp_str
, SCF_PROPERTY_SINGLE_INSTANCE
) == 0) {
9749 if (prop_check_type(exp_prop
, SCF_TYPE_BOOLEAN
) == 0 &&
9750 prop_get_val(exp_prop
, exp_val
) == 0) {
9753 if (scf_value_get_boolean(exp_val
, &b
) !=
9758 selts
->single_instance
=
9760 (xmlChar
*)"single_instance");
9761 if (selts
->single_instance
== NULL
)
9762 uu_die(emsg_create_xml
);
9767 } else if (strcmp(exp_str
, SCF_PROPERTY_RESTARTER
) == 0) {
9768 xmlNodePtr rnode
, sfnode
;
9770 rnode
= xmlNewNode(NULL
, (xmlChar
*)"restarter");
9772 uu_die(emsg_create_xml
);
9774 sfnode
= xmlNewChild(rnode
, NULL
,
9775 (xmlChar
*)"service_fmri", NULL
);
9777 uu_die(emsg_create_xml
);
9779 if (set_attr_from_prop(exp_prop
, sfnode
,
9781 selts
->restarter
= rnode
;
9786 } else if (strcmp(exp_str
, SCF_PROPERTY_ENTITY_STABILITY
) ==
9790 s
= xmlNewNode(NULL
, (xmlChar
*)"stability");
9792 uu_die(emsg_create_xml
);
9794 if (set_attr_from_prop(exp_prop
, s
, value_attr
) == 0) {
9795 selts
->stability
= s
;
9802 export_property(exp_prop
, exp_str
, &elts
, SCE_ALL_VALUES
);
9807 if (elts
.propvals
!= NULL
|| elts
.properties
!= NULL
)
9808 export_pg_elts(&elts
, scf_pg_general
, scf_group_framework
,
9813 export_method_context(scf_propertygroup_t
*pg
, struct entity_elts
*elts
)
9815 xmlNodePtr n
, prof
, cred
, env
;
9816 uint8_t use_profile
;
9819 n
= xmlNewNode(NULL
, (xmlChar
*)"method_context");
9823 env
= export_method_environment(pg
);
9825 /* Need to know whether we'll use a profile or not. */
9826 if (pg_get_prop(pg
, SCF_PROPERTY_USE_PROFILE
, exp_prop
) == 0 &&
9827 prop_check_type(exp_prop
, SCF_TYPE_BOOLEAN
) == 0 &&
9828 prop_get_val(exp_prop
, exp_val
) == 0) {
9829 if (scf_value_get_boolean(exp_val
, &use_profile
) != SCF_SUCCESS
)
9834 xmlNewChild(n
, NULL
, (xmlChar
*)"method_profile",
9838 xmlNewChild(n
, NULL
, (xmlChar
*)"method_credential",
9843 (void) xmlAddChild(n
, env
);
9845 if (scf_iter_pg_properties(exp_prop_iter
, pg
) != SCF_SUCCESS
)
9848 while ((ret
= scf_iter_next_property(exp_prop_iter
, exp_prop
)) == 1) {
9849 if (scf_property_get_name(exp_prop
, exp_str
, exp_str_sz
) < 0)
9852 if (strcmp(exp_str
, SCF_PROPERTY_WORKING_DIRECTORY
) == 0) {
9853 if (set_attr_from_prop(exp_prop
, n
,
9854 "working_directory") != 0)
9856 } else if (strcmp(exp_str
, SCF_PROPERTY_PROJECT
) == 0) {
9857 if (set_attr_from_prop(exp_prop
, n
, "project") != 0)
9859 } else if (strcmp(exp_str
, SCF_PROPERTY_RESOURCE_POOL
) == 0) {
9860 if (set_attr_from_prop(exp_prop
, n
,
9861 "resource_pool") != 0)
9863 } else if (strcmp(exp_str
, SCF_PROPERTY_SECFLAGS
) == 0) {
9864 if (set_attr_from_prop(exp_prop
, n
,
9865 "security_flags") != 0)
9867 } else if (strcmp(exp_str
, SCF_PROPERTY_USE_PROFILE
) == 0) {
9869 } else if (strcmp(exp_str
, SCF_PROPERTY_USER
) == 0) {
9871 set_attr_from_prop(exp_prop
, cred
, "user") != 0)
9873 } else if (strcmp(exp_str
, SCF_PROPERTY_GROUP
) == 0) {
9875 set_attr_from_prop(exp_prop
, cred
, "group") != 0)
9877 } else if (strcmp(exp_str
, SCF_PROPERTY_SUPP_GROUPS
) == 0) {
9878 if (use_profile
|| set_attr_from_prop(exp_prop
, cred
,
9879 "supp_groups") != 0)
9881 } else if (strcmp(exp_str
, SCF_PROPERTY_PRIVILEGES
) == 0) {
9882 if (use_profile
|| set_attr_from_prop(exp_prop
, cred
,
9885 } else if (strcmp(exp_str
, SCF_PROPERTY_LIMIT_PRIVILEGES
) ==
9887 if (use_profile
|| set_attr_from_prop(exp_prop
, cred
,
9888 "limit_privileges") != 0)
9890 } else if (strcmp(exp_str
, SCF_PROPERTY_PROFILE
) == 0) {
9891 if (!use_profile
|| set_attr_from_prop(exp_prop
,
9892 prof
, name_attr
) != 0)
9895 /* Can't have generic properties in method_context's */
9902 if (err
&& env
== NULL
) {
9904 export_pg(pg
, elts
, SCE_ALL_VALUES
);
9908 elts
->method_context
= n
;
9912 * Given a dependency property group in the tfmri entity (target fmri), return
9913 * a dependent element which represents it.
9916 export_dependent(scf_propertygroup_t
*pg
, const char *name
, const char *tfmri
)
9921 struct pg_elts pgelts
;
9924 * If external isn't set to true then exporting the service will
9925 * export this as a normal dependency, so we should stop to avoid
9928 if (scf_pg_get_property(pg
, scf_property_external
, exp_prop
) != 0 ||
9929 scf_property_get_value(exp_prop
, exp_val
) != 0 ||
9930 scf_value_get_boolean(exp_val
, &b
) != 0 || !b
) {
9932 warn(gettext("Dependent \"%s\" cannot be exported "
9933 "properly because the \"%s\" property of the "
9934 "\"%s\" dependency of %s is not set to true.\n"),
9935 name
, scf_property_external
, name
, tfmri
);
9941 n
= xmlNewNode(NULL
, (xmlChar
*)"dependent");
9943 uu_die(emsg_create_xml
);
9945 safe_setprop(n
, name_attr
, name
);
9947 /* Get the required attributes */
9948 if (pg_get_prop(pg
, SCF_PROPERTY_RESTART_ON
, exp_prop
) != 0 ||
9949 set_attr_from_prop(exp_prop
, n
, "restart_on") != 0)
9952 if (pg_get_prop(pg
, SCF_PROPERTY_GROUPING
, exp_prop
) != 0 ||
9953 set_attr_from_prop(exp_prop
, n
, "grouping") != 0)
9956 if (pg_get_prop(pg
, SCF_PROPERTY_ENTITIES
, exp_prop
) == 0 &&
9957 prop_check_type(exp_prop
, SCF_TYPE_FMRI
) == 0 &&
9958 prop_get_val(exp_prop
, exp_val
) == 0) {
9968 sf
= xmlNewChild(n
, NULL
, (xmlChar
*)"service_fmri", NULL
);
9970 uu_die(emsg_create_xml
);
9972 safe_setprop(sf
, value_attr
, tfmri
);
9975 * Now add elements for the other properties.
9977 if (scf_iter_pg_properties(exp_prop_iter
, pg
) != SCF_SUCCESS
)
9980 (void) memset(&pgelts
, 0, sizeof (pgelts
));
9982 while ((ret
= scf_iter_next_property(exp_prop_iter
, exp_prop
)) == 1) {
9983 if (scf_property_get_name(exp_prop
, exp_str
, exp_str_sz
) < 0)
9986 if (strcmp(exp_str
, scf_property_external
) == 0 ||
9987 strcmp(exp_str
, SCF_PROPERTY_RESTART_ON
) == 0 ||
9988 strcmp(exp_str
, SCF_PROPERTY_GROUPING
) == 0 ||
9989 strcmp(exp_str
, SCF_PROPERTY_ENTITIES
) == 0) {
9991 } else if (strcmp(exp_str
, SCF_PROPERTY_TYPE
) == 0) {
9992 if (prop_check_type(exp_prop
, SCF_TYPE_ASTRING
) == 0 &&
9993 prop_get_val(exp_prop
, exp_val
) == 0) {
9994 char type
[sizeof ("service") + 1];
9996 if (scf_value_get_astring(exp_val
, type
,
10000 if (strcmp(type
, "service") == 0)
10003 } else if (strcmp(exp_str
, SCF_PROPERTY_STABILITY
) == 0) {
10006 s
= xmlNewNode(NULL
, (xmlChar
*)"stability");
10008 uu_die(emsg_create_xml
);
10010 if (set_attr_from_prop(exp_prop
, s
, value_attr
) == 0) {
10011 pgelts
.stability
= s
;
10018 export_property(exp_prop
, exp_str
, &pgelts
, SCE_ALL_VALUES
);
10023 (void) xmlAddChild(n
, pgelts
.stability
);
10024 (void) xmlAddChildList(n
, pgelts
.propvals
);
10025 (void) xmlAddChildList(n
, pgelts
.properties
);
10031 export_dependents(scf_propertygroup_t
*pg
, struct entity_elts
*eelts
)
10033 scf_propertygroup_t
*opg
;
10037 struct pg_elts pgelts
;
10041 if ((opg
= scf_pg_create(g_hndl
)) == NULL
||
10042 (iter
= scf_iter_create(g_hndl
)) == NULL
)
10045 /* Can't use exp_prop_iter due to export_dependent(). */
10046 if (scf_iter_pg_properties(iter
, pg
) != SCF_SUCCESS
)
10049 type
= safe_malloc(max_scf_pg_type_len
+ 1);
10051 /* Get an extra byte so we can tell if values are too long. */
10052 fmri
= safe_malloc(max_scf_fmri_len
+ 2);
10054 (void) memset(&pgelts
, 0, sizeof (pgelts
));
10056 while ((ret
= scf_iter_next_property(iter
, exp_prop
)) == 1) {
10061 if (scf_property_type(exp_prop
, &ty
) != SCF_SUCCESS
)
10064 if ((ty
!= SCF_TYPE_ASTRING
&&
10065 prop_check_type(exp_prop
, SCF_TYPE_FMRI
) != 0) ||
10066 prop_get_val(exp_prop
, exp_val
) != 0) {
10067 export_property(exp_prop
, NULL
, &pgelts
,
10072 if (scf_property_get_name(exp_prop
, exp_str
, exp_str_sz
) < 0)
10075 if (scf_value_get_astring(exp_val
, fmri
,
10076 max_scf_fmri_len
+ 2) < 0)
10079 /* Look for a dependency group in the target fmri. */
10080 serr
= fmri_to_entity(g_hndl
, fmri
, &entity
, &isservice
);
10082 case SCF_ERROR_NONE
:
10085 case SCF_ERROR_NO_MEMORY
:
10086 uu_die(gettext("Out of memory.\n"));
10089 case SCF_ERROR_INVALID_ARGUMENT
:
10091 if (scf_property_to_fmri(exp_prop
, fmri
,
10092 max_scf_fmri_len
+ 2) < 0)
10095 warn(gettext("The value of %s is not a valid "
10099 export_property(exp_prop
, exp_str
, &pgelts
,
10103 case SCF_ERROR_CONSTRAINT_VIOLATED
:
10105 if (scf_property_to_fmri(exp_prop
, fmri
,
10106 max_scf_fmri_len
+ 2) < 0)
10109 warn(gettext("The value of %s does not specify "
10110 "a service or an instance.\n"), fmri
);
10113 export_property(exp_prop
, exp_str
, &pgelts
,
10117 case SCF_ERROR_NOT_FOUND
:
10119 if (scf_property_to_fmri(exp_prop
, fmri
,
10120 max_scf_fmri_len
+ 2) < 0)
10123 warn(gettext("The entity specified by %s does "
10124 "not exist.\n"), fmri
);
10127 export_property(exp_prop
, exp_str
, &pgelts
,
10133 (void) fprintf(stderr
, "%s:%d: %s() failed with "
10134 "unexpected error %d.\n", __FILE__
, __LINE__
,
10135 "fmri_to_entity", serr
);
10140 if (entity_get_pg(entity
, isservice
, exp_str
, opg
) != 0) {
10141 if (scf_error() != SCF_ERROR_NOT_FOUND
)
10144 warn(gettext("Entity %s is missing dependency property "
10145 "group %s.\n"), fmri
, exp_str
);
10147 export_property(exp_prop
, NULL
, &pgelts
,
10152 if (scf_pg_get_type(opg
, type
, max_scf_pg_type_len
+ 1) < 0)
10155 if (strcmp(type
, SCF_GROUP_DEPENDENCY
) != 0) {
10156 if (scf_pg_to_fmri(opg
, fmri
, max_scf_fmri_len
+ 2) < 0)
10159 warn(gettext("Property group %s is not of "
10160 "expected type %s.\n"), fmri
, SCF_GROUP_DEPENDENCY
);
10162 export_property(exp_prop
, NULL
, &pgelts
,
10167 n
= export_dependent(opg
, exp_str
, fmri
);
10169 export_property(exp_prop
, exp_str
, &pgelts
,
10172 if (eelts
->dependents
== NULL
)
10173 eelts
->dependents
= n
;
10175 (void) xmlAddSibling(eelts
->dependents
,
10185 scf_iter_destroy(iter
);
10186 scf_pg_destroy(opg
);
10188 if (pgelts
.propvals
!= NULL
|| pgelts
.properties
!= NULL
)
10189 export_pg_elts(&pgelts
, SCF_PG_DEPENDENTS
, scf_group_framework
,
10194 make_node(xmlNodePtr
*nodep
, const char *name
)
10196 if (*nodep
== NULL
) {
10197 *nodep
= xmlNewNode(NULL
, (xmlChar
*)name
);
10198 if (*nodep
== NULL
)
10199 uu_die(emsg_create_xml
);
10204 export_tm_loctext(scf_propertygroup_t
*pg
, const char *parname
)
10207 xmlNodePtr parent
= NULL
;
10208 xmlNodePtr loctext
= NULL
;
10210 if (scf_iter_pg_properties(exp_prop_iter
, pg
) != SCF_SUCCESS
)
10213 while ((ret
= scf_iter_next_property(exp_prop_iter
, exp_prop
)) == 1) {
10214 if (prop_check_type(exp_prop
, SCF_TYPE_USTRING
) != 0 ||
10215 prop_get_val(exp_prop
, exp_val
) != 0)
10218 if (scf_value_get_ustring(exp_val
, exp_str
, exp_str_sz
) < 0)
10221 make_node(&parent
, parname
);
10222 loctext
= xmlNewTextChild(parent
, NULL
, (xmlChar
*)"loctext",
10223 (xmlChar
*)exp_str
);
10224 if (loctext
== NULL
)
10225 uu_die(emsg_create_xml
);
10227 if (scf_property_get_name(exp_prop
, exp_str
, exp_str_sz
) < 0)
10230 safe_setprop(loctext
, "xml:lang", exp_str
);
10240 export_tm_manpage(scf_propertygroup_t
*pg
)
10242 xmlNodePtr manpage
= xmlNewNode(NULL
, (xmlChar
*)"manpage");
10243 if (manpage
== NULL
)
10244 uu_die(emsg_create_xml
);
10246 if (pg_get_prop(pg
, SCF_PROPERTY_TM_TITLE
, exp_prop
) != 0 ||
10247 set_attr_from_prop(exp_prop
, manpage
, "title") != 0 ||
10248 pg_get_prop(pg
, SCF_PROPERTY_TM_SECTION
, exp_prop
) != 0 ||
10249 set_attr_from_prop(exp_prop
, manpage
, "section") != 0) {
10250 xmlFreeNode(manpage
);
10254 if (pg_get_prop(pg
, SCF_PROPERTY_TM_MANPATH
, exp_prop
) == 0)
10255 (void) set_attr_from_prop_default(exp_prop
,
10256 manpage
, "manpath", ":default");
10262 export_tm_doc_link(scf_propertygroup_t
*pg
)
10264 xmlNodePtr doc_link
= xmlNewNode(NULL
, (xmlChar
*)"doc_link");
10265 if (doc_link
== NULL
)
10266 uu_die(emsg_create_xml
);
10268 if (pg_get_prop(pg
, SCF_PROPERTY_TM_NAME
, exp_prop
) != 0 ||
10269 set_attr_from_prop(exp_prop
, doc_link
, "name") != 0 ||
10270 pg_get_prop(pg
, SCF_PROPERTY_TM_URI
, exp_prop
) != 0 ||
10271 set_attr_from_prop(exp_prop
, doc_link
, "uri") != 0) {
10272 xmlFreeNode(doc_link
);
10279 * Process template information for a service or instances.
10282 export_template(scf_propertygroup_t
*pg
, struct entity_elts
*elts
,
10283 struct template_elts
*telts
)
10285 size_t mansz
= strlen(SCF_PG_TM_MAN_PREFIX
);
10286 size_t docsz
= strlen(SCF_PG_TM_DOC_PREFIX
);
10287 xmlNodePtr child
= NULL
;
10289 if (scf_pg_get_name(pg
, exp_str
, exp_str_sz
) < 0)
10292 if (strcmp(exp_str
, SCF_PG_TM_COMMON_NAME
) == 0) {
10293 telts
->common_name
= export_tm_loctext(pg
, "common_name");
10294 if (telts
->common_name
== NULL
)
10295 export_pg(pg
, elts
, SCE_ALL_VALUES
);
10297 } else if (strcmp(exp_str
, SCF_PG_TM_DESCRIPTION
) == 0) {
10298 telts
->description
= export_tm_loctext(pg
, "description");
10299 if (telts
->description
== NULL
)
10300 export_pg(pg
, elts
, SCE_ALL_VALUES
);
10304 if (strncmp(exp_str
, SCF_PG_TM_MAN_PREFIX
, mansz
) == 0) {
10305 child
= export_tm_manpage(pg
);
10306 } else if (strncmp(exp_str
, SCF_PG_TM_DOC_PREFIX
, docsz
) == 0) {
10307 child
= export_tm_doc_link(pg
);
10310 if (child
!= NULL
) {
10311 make_node(&telts
->documentation
, "documentation");
10312 (void) xmlAddChild(telts
->documentation
, child
);
10314 export_pg(pg
, elts
, SCE_ALL_VALUES
);
10319 * Process parameter and paramval elements
10322 export_parameter(scf_property_t
*prop
, const char *name
,
10323 struct params_elts
*elts
)
10326 scf_error_t err
= 0;
10329 if (scf_property_get_value(prop
, exp_val
) == SCF_SUCCESS
) {
10330 if ((param
= xmlNewNode(NULL
, (xmlChar
*)"paramval")) == NULL
)
10331 uu_die(emsg_create_xml
);
10333 safe_setprop(param
, name_attr
, name
);
10335 if (scf_value_get_as_string(exp_val
, exp_str
, exp_str_sz
) < 0)
10337 safe_setprop(param
, value_attr
, exp_str
);
10339 if (elts
->paramval
== NULL
)
10340 elts
->paramval
= param
;
10342 (void) xmlAddSibling(elts
->paramval
, param
);
10349 if (err
!= SCF_ERROR_CONSTRAINT_VIOLATED
&&
10350 err
!= SCF_ERROR_NOT_FOUND
)
10353 if ((param
= xmlNewNode(NULL
, (xmlChar
*)"parameter")) == NULL
)
10354 uu_die(emsg_create_xml
);
10356 safe_setprop(param
, name_attr
, name
);
10358 if (err
== SCF_ERROR_CONSTRAINT_VIOLATED
) {
10359 if (scf_iter_property_values(exp_val_iter
, prop
) != SCF_SUCCESS
)
10362 while ((ret
= scf_iter_next_value(exp_val_iter
, exp_val
)) ==
10366 if ((vn
= xmlNewChild(param
, NULL
,
10367 (xmlChar
*)"value_node", NULL
)) == NULL
)
10368 uu_die(emsg_create_xml
);
10370 if (scf_value_get_as_string(exp_val
, exp_str
,
10374 safe_setprop(vn
, value_attr
, exp_str
);
10380 if (elts
->parameter
== NULL
)
10381 elts
->parameter
= param
;
10383 (void) xmlAddSibling(elts
->parameter
, param
);
10387 * Process notification parameters for a service or instance
10390 export_notify_params(scf_propertygroup_t
*pg
, struct entity_elts
*elts
)
10392 xmlNodePtr n
, event
, *type
;
10393 struct params_elts
*eelts
;
10397 n
= xmlNewNode(NULL
, (xmlChar
*)"notification_parameters");
10398 event
= xmlNewNode(NULL
, (xmlChar
*)"event");
10399 if (n
== NULL
|| event
== NULL
)
10400 uu_die(emsg_create_xml
);
10403 if (scf_pg_get_name(pg
, exp_str
, max_scf_name_len
+ 1) < 0)
10405 /* trim SCF_NOTIFY_PG_POSTFIX appended to name on import */
10406 if ((s
= strchr(exp_str
, ',')) != NULL
)
10408 safe_setprop(event
, value_attr
, exp_str
);
10410 (void) xmlAddChild(n
, event
);
10412 if ((type
= calloc(URI_SCHEME_NUM
, sizeof (xmlNodePtr
))) == NULL
||
10413 (eelts
= calloc(URI_SCHEME_NUM
,
10414 sizeof (struct params_elts
))) == NULL
)
10415 uu_die(gettext("Out of memory.\n"));
10419 if (scf_iter_pg_properties(exp_prop_iter
, pg
) != SCF_SUCCESS
)
10422 while ((ret
= scf_iter_next_property(exp_prop_iter
, exp_prop
)) == 1) {
10425 if (scf_property_get_name(exp_prop
, exp_str
, exp_str_sz
) < 0)
10428 if ((t
= strtok_r(exp_str
, ",", &p
)) == NULL
|| p
== NULL
) {
10430 * this is not a well formed notification parameters
10431 * element, we should export as regular pg
10437 if ((i
= check_uri_protocol(t
)) < 0) {
10442 if (type
[i
] == NULL
) {
10443 if ((type
[i
] = xmlNewNode(NULL
, (xmlChar
*)"type")) ==
10445 uu_die(emsg_create_xml
);
10447 safe_setprop(type
[i
], name_attr
, t
);
10449 if (strcmp(p
, active_attr
) == 0) {
10450 if (set_attr_from_prop(exp_prop
, type
[i
],
10451 active_attr
) != 0) {
10458 * We export the parameter
10460 export_parameter(exp_prop
, p
, &eelts
[i
]);
10467 for (i
= 0; i
< URI_SCHEME_NUM
; ++i
)
10471 export_pg(pg
, elts
, SCE_ALL_VALUES
);
10475 for (i
= 0; i
< URI_SCHEME_NUM
; ++i
)
10476 if (type
[i
] != NULL
) {
10477 (void) xmlAddChildList(type
[i
],
10478 eelts
[i
].paramval
);
10479 (void) xmlAddChildList(type
[i
],
10480 eelts
[i
].parameter
);
10481 (void) xmlAddSibling(event
, type
[i
]);
10486 if (elts
->notify_params
== NULL
)
10487 elts
->notify_params
= n
;
10489 (void) xmlAddSibling(elts
->notify_params
, n
);
10493 * Process the general property group for an instance.
10496 export_inst_general(scf_propertygroup_t
*pg
, xmlNodePtr inode
,
10497 struct entity_elts
*elts
)
10500 struct pg_elts pgelts
;
10504 if (pg_get_prop(pg
, scf_property_enabled
, exp_prop
) == 0 &&
10505 prop_check_type(exp_prop
, SCF_TYPE_BOOLEAN
) == 0 &&
10506 prop_get_val(exp_prop
, exp_val
) == 0) {
10507 if (scf_value_get_boolean(exp_val
, &enabled
) != SCF_SUCCESS
)
10513 safe_setprop(inode
, enabled_attr
, enabled
? true : false);
10515 if (scf_iter_pg_properties(exp_prop_iter
, pg
) != SCF_SUCCESS
)
10518 (void) memset(&pgelts
, 0, sizeof (pgelts
));
10520 while ((ret
= scf_iter_next_property(exp_prop_iter
, exp_prop
)) == 1) {
10521 if (scf_property_get_name(exp_prop
, exp_str
, exp_str_sz
) < 0)
10524 if (strcmp(exp_str
, scf_property_enabled
) == 0) {
10526 } else if (strcmp(exp_str
, SCF_PROPERTY_RESTARTER
) == 0) {
10527 xmlNodePtr rnode
, sfnode
;
10529 rnode
= xmlNewNode(NULL
, (xmlChar
*)"restarter");
10531 uu_die(emsg_create_xml
);
10533 sfnode
= xmlNewChild(rnode
, NULL
,
10534 (xmlChar
*)"service_fmri", NULL
);
10535 if (sfnode
== NULL
)
10536 uu_die(emsg_create_xml
);
10538 if (set_attr_from_prop(exp_prop
, sfnode
,
10539 value_attr
) == 0) {
10540 elts
->restarter
= rnode
;
10544 xmlFreeNode(rnode
);
10547 export_property(exp_prop
, exp_str
, &pgelts
, SCE_ALL_VALUES
);
10552 if (pgelts
.propvals
!= NULL
|| pgelts
.properties
!= NULL
)
10553 export_pg_elts(&pgelts
, scf_pg_general
, scf_group_framework
,
10558 * Put an instance element for the given instance into selts.
10561 export_instance(scf_instance_t
*inst
, struct entity_elts
*selts
, int flags
)
10564 boolean_t isdefault
;
10565 struct entity_elts elts
;
10566 struct template_elts template_elts
;
10569 n
= xmlNewNode(NULL
, (xmlChar
*)"instance");
10571 uu_die(emsg_create_xml
);
10574 if (scf_instance_get_name(inst
, exp_str
, exp_str_sz
) < 0)
10576 safe_setprop(n
, name_attr
, exp_str
);
10577 isdefault
= strcmp(exp_str
, "default") == 0;
10579 /* check existance of general pg (since general/enabled is required) */
10580 if (scf_instance_get_pg(inst
, scf_pg_general
, exp_pg
) != SCF_SUCCESS
) {
10581 if (scf_error() != SCF_ERROR_NOT_FOUND
)
10585 if (scf_instance_to_fmri(inst
, exp_str
, exp_str_sz
) < 0)
10588 warn(gettext("Instance %s has no general property "
10589 "group; it will be marked disabled.\n"), exp_str
);
10592 safe_setprop(n
, enabled_attr
, false);
10593 } else if (scf_pg_get_type(exp_pg
, exp_str
, exp_str_sz
) < 0 ||
10594 strcmp(exp_str
, scf_group_framework
) != 0) {
10596 if (scf_pg_to_fmri(exp_pg
, exp_str
, exp_str_sz
) < 0)
10599 warn(gettext("Property group %s is not of type "
10600 "framework; the instance will be marked "
10601 "disabled.\n"), exp_str
);
10604 safe_setprop(n
, enabled_attr
, false);
10607 /* property groups */
10608 if (scf_iter_instance_pgs(exp_pg_iter
, inst
) < 0)
10611 (void) memset(&elts
, 0, sizeof (elts
));
10612 (void) memset(&template_elts
, 0, sizeof (template_elts
));
10614 while ((ret
= scf_iter_next_pg(exp_pg_iter
, exp_pg
)) == 1) {
10617 if (scf_pg_get_flags(exp_pg
, &pgflags
) != 0)
10620 if (pgflags
& SCF_PG_FLAG_NONPERSISTENT
)
10623 if (scf_pg_get_type(exp_pg
, exp_str
, exp_str_sz
) < 0)
10626 if (strcmp(exp_str
, SCF_GROUP_DEPENDENCY
) == 0) {
10627 export_dependency(exp_pg
, &elts
);
10629 } else if (strcmp(exp_str
, SCF_GROUP_METHOD
) == 0) {
10630 export_method(exp_pg
, &elts
);
10632 } else if (strcmp(exp_str
, scf_group_framework
) == 0) {
10633 if (scf_pg_get_name(exp_pg
, exp_str
,
10634 max_scf_name_len
+ 1) < 0)
10637 if (strcmp(exp_str
, scf_pg_general
) == 0) {
10638 export_inst_general(exp_pg
, n
, &elts
);
10640 } else if (strcmp(exp_str
, SCF_PG_METHOD_CONTEXT
) ==
10642 export_method_context(exp_pg
, &elts
);
10644 } else if (strcmp(exp_str
, SCF_PG_DEPENDENTS
) == 0) {
10645 export_dependents(exp_pg
, &elts
);
10648 } else if (strcmp(exp_str
, SCF_GROUP_TEMPLATE
) == 0) {
10649 export_template(exp_pg
, &elts
, &template_elts
);
10651 } else if (strcmp(exp_str
, SCF_NOTIFY_PARAMS_PG_TYPE
) == 0) {
10652 export_notify_params(exp_pg
, &elts
);
10657 export_pg(exp_pg
, &elts
, flags
);
10662 if (template_elts
.common_name
!= NULL
) {
10663 elts
.template = xmlNewNode(NULL
, (xmlChar
*)"template");
10664 (void) xmlAddChild(elts
.template, template_elts
.common_name
);
10665 (void) xmlAddChild(elts
.template, template_elts
.description
);
10666 (void) xmlAddChild(elts
.template, template_elts
.documentation
);
10668 xmlFreeNode(template_elts
.description
);
10669 xmlFreeNode(template_elts
.documentation
);
10672 if (isdefault
&& elts
.restarter
== NULL
&&
10673 elts
.dependencies
== NULL
&& elts
.method_context
== NULL
&&
10674 elts
.exec_methods
== NULL
&& elts
.notify_params
== NULL
&&
10675 elts
.property_groups
== NULL
&& elts
.template == NULL
) {
10678 /* This is a default instance */
10679 eval
= xmlGetProp(n
, (xmlChar
*)enabled_attr
);
10683 n
= xmlNewNode(NULL
, (xmlChar
*)"create_default_instance");
10685 uu_die(emsg_create_xml
);
10687 safe_setprop(n
, enabled_attr
, (char *)eval
);
10690 selts
->create_default_instance
= n
;
10692 /* Assemble the children in order. */
10693 (void) xmlAddChild(n
, elts
.restarter
);
10694 (void) xmlAddChildList(n
, elts
.dependencies
);
10695 (void) xmlAddChildList(n
, elts
.dependents
);
10696 (void) xmlAddChild(n
, elts
.method_context
);
10697 (void) xmlAddChildList(n
, elts
.exec_methods
);
10698 (void) xmlAddChildList(n
, elts
.notify_params
);
10699 (void) xmlAddChildList(n
, elts
.property_groups
);
10700 (void) xmlAddChild(n
, elts
.template);
10702 if (selts
->instances
== NULL
)
10703 selts
->instances
= n
;
10705 (void) xmlAddSibling(selts
->instances
, n
);
10710 * Return a service element for the given service.
10713 export_service(scf_service_t
*svc
, int flags
)
10716 struct entity_elts elts
;
10717 struct template_elts template_elts
;
10720 snode
= xmlNewNode(NULL
, (xmlChar
*)"service");
10722 uu_die(emsg_create_xml
);
10724 /* Get & set name attribute */
10725 if (scf_service_get_name(svc
, exp_str
, max_scf_name_len
+ 1) < 0)
10727 safe_setprop(snode
, name_attr
, exp_str
);
10729 safe_setprop(snode
, type_attr
, "service");
10730 safe_setprop(snode
, "version", "0");
10732 /* Acquire child elements. */
10733 if (scf_iter_service_pgs(exp_pg_iter
, svc
) != SCF_SUCCESS
)
10736 (void) memset(&elts
, 0, sizeof (elts
));
10737 (void) memset(&template_elts
, 0, sizeof (template_elts
));
10739 while ((ret
= scf_iter_next_pg(exp_pg_iter
, exp_pg
)) == 1) {
10742 if (scf_pg_get_flags(exp_pg
, &pgflags
) != 0)
10745 if (pgflags
& SCF_PG_FLAG_NONPERSISTENT
)
10748 if (scf_pg_get_type(exp_pg
, exp_str
, exp_str_sz
) < 0)
10751 if (strcmp(exp_str
, SCF_GROUP_DEPENDENCY
) == 0) {
10752 export_dependency(exp_pg
, &elts
);
10754 } else if (strcmp(exp_str
, SCF_GROUP_METHOD
) == 0) {
10755 export_method(exp_pg
, &elts
);
10757 } else if (strcmp(exp_str
, scf_group_framework
) == 0) {
10758 if (scf_pg_get_name(exp_pg
, exp_str
,
10759 max_scf_name_len
+ 1) < 0)
10762 if (strcmp(exp_str
, scf_pg_general
) == 0) {
10763 export_svc_general(exp_pg
, &elts
);
10765 } else if (strcmp(exp_str
, SCF_PG_METHOD_CONTEXT
) ==
10767 export_method_context(exp_pg
, &elts
);
10769 } else if (strcmp(exp_str
, SCF_PG_DEPENDENTS
) == 0) {
10770 export_dependents(exp_pg
, &elts
);
10772 } else if (strcmp(exp_str
, SCF_PG_MANIFESTFILES
) == 0) {
10775 } else if (strcmp(exp_str
, SCF_GROUP_TEMPLATE
) == 0) {
10776 export_template(exp_pg
, &elts
, &template_elts
);
10778 } else if (strcmp(exp_str
, SCF_NOTIFY_PARAMS_PG_TYPE
) == 0) {
10779 export_notify_params(exp_pg
, &elts
);
10783 export_pg(exp_pg
, &elts
, flags
);
10788 if (template_elts
.common_name
!= NULL
) {
10789 elts
.template = xmlNewNode(NULL
, (xmlChar
*)"template");
10790 (void) xmlAddChild(elts
.template, template_elts
.common_name
);
10791 (void) xmlAddChild(elts
.template, template_elts
.description
);
10792 (void) xmlAddChild(elts
.template, template_elts
.documentation
);
10794 xmlFreeNode(template_elts
.description
);
10795 xmlFreeNode(template_elts
.documentation
);
10798 /* Iterate instances */
10799 if (scf_iter_service_instances(exp_inst_iter
, svc
) != SCF_SUCCESS
)
10802 while ((ret
= scf_iter_next_instance(exp_inst_iter
, exp_inst
)) == 1)
10803 export_instance(exp_inst
, &elts
, flags
);
10807 /* Now add all of the accumulated elements in order. */
10808 (void) xmlAddChild(snode
, elts
.create_default_instance
);
10809 (void) xmlAddChild(snode
, elts
.single_instance
);
10810 (void) xmlAddChild(snode
, elts
.restarter
);
10811 (void) xmlAddChildList(snode
, elts
.dependencies
);
10812 (void) xmlAddChildList(snode
, elts
.dependents
);
10813 (void) xmlAddChild(snode
, elts
.method_context
);
10814 (void) xmlAddChildList(snode
, elts
.exec_methods
);
10815 (void) xmlAddChildList(snode
, elts
.notify_params
);
10816 (void) xmlAddChildList(snode
, elts
.property_groups
);
10817 (void) xmlAddChildList(snode
, elts
.instances
);
10818 (void) xmlAddChild(snode
, elts
.stability
);
10819 (void) xmlAddChild(snode
, elts
.template);
10825 export_callback(void *data
, scf_walkinfo_t
*wip
)
10831 struct export_args
*argsp
= (struct export_args
*)data
;
10833 if ((exp_inst
= scf_instance_create(g_hndl
)) == NULL
||
10834 (exp_pg
= scf_pg_create(g_hndl
)) == NULL
||
10835 (exp_prop
= scf_property_create(g_hndl
)) == NULL
||
10836 (exp_val
= scf_value_create(g_hndl
)) == NULL
||
10837 (exp_inst_iter
= scf_iter_create(g_hndl
)) == NULL
||
10838 (exp_pg_iter
= scf_iter_create(g_hndl
)) == NULL
||
10839 (exp_prop_iter
= scf_iter_create(g_hndl
)) == NULL
||
10840 (exp_val_iter
= scf_iter_create(g_hndl
)) == NULL
)
10843 exp_str_sz
= max_scf_len
+ 1;
10844 exp_str
= safe_malloc(exp_str_sz
);
10846 if (argsp
->filename
!= NULL
) {
10848 f
= fopen(argsp
->filename
, "wb");
10851 uu_die(gettext("Could not open \"%s\": no free "
10852 "stdio streams.\n"), argsp
->filename
);
10854 uu_die(gettext("Could not open \"%s\""),
10860 doc
= xmlNewDoc((xmlChar
*)"1.0");
10862 uu_die(gettext("Could not create XML document.\n"));
10864 if (xmlCreateIntSubset(doc
, (xmlChar
*)"service_bundle", NULL
,
10865 (xmlChar
*)MANIFEST_DTD_PATH
) == NULL
)
10866 uu_die(emsg_create_xml
);
10868 sb
= xmlNewNode(NULL
, (xmlChar
*)"service_bundle");
10870 uu_die(emsg_create_xml
);
10871 safe_setprop(sb
, type_attr
, "manifest");
10872 safe_setprop(sb
, name_attr
, "export");
10873 (void) xmlAddSibling(doc
->children
, sb
);
10875 (void) xmlAddChild(sb
, export_service(wip
->svc
, argsp
->flags
));
10877 result
= write_service_bundle(doc
, f
);
10880 scf_iter_destroy(exp_val_iter
);
10881 scf_iter_destroy(exp_prop_iter
);
10882 scf_iter_destroy(exp_pg_iter
);
10883 scf_iter_destroy(exp_inst_iter
);
10884 scf_value_destroy(exp_val
);
10885 scf_property_destroy(exp_prop
);
10886 scf_pg_destroy(exp_pg
);
10887 scf_instance_destroy(exp_inst
);
10898 * Get the service named by fmri, build an XML tree which represents it, and
10899 * dump it into filename (or stdout if filename is NULL).
10902 lscf_service_export(char *fmri
, const char *filename
, int flags
)
10904 struct export_args args
;
10906 const char *scope
, *svc
, *inst
;
10907 size_t cblen
= 3 * max_scf_name_len
;
10908 char *canonbuf
= alloca(cblen
);
10913 bzero(&args
, sizeof (args
));
10914 args
.filename
= filename
;
10915 args
.flags
= flags
;
10918 * If some poor user has passed an exact instance FMRI, of the sort
10919 * one might cut and paste from svcs(1) or an error message, warn
10920 * and chop off the instance instead of failing.
10922 fmridup
= alloca(strlen(fmri
) + 1);
10923 (void) strcpy(fmridup
, fmri
);
10924 if (strncmp(fmridup
, SCF_FMRI_SVC_PREFIX
,
10925 sizeof (SCF_FMRI_SVC_PREFIX
) -1) == 0 &&
10926 scf_parse_svc_fmri(fmridup
, &scope
, &svc
, &inst
, NULL
, NULL
) == 0 &&
10928 (void) strlcpy(canonbuf
, "svc:/", cblen
);
10929 if (strcmp(scope
, SCF_FMRI_LOCAL_SCOPE
) != 0) {
10930 (void) strlcat(canonbuf
, "/", cblen
);
10931 (void) strlcat(canonbuf
, scope
, cblen
);
10933 (void) strlcat(canonbuf
, svc
, cblen
);
10936 warn(gettext("Only services may be exported; ignoring "
10937 "instance portion of argument.\n"));
10941 if ((ret
= scf_walk_fmri(g_hndl
, 1, (char **)&fmri
,
10942 SCF_WALK_SERVICE
| SCF_WALK_NOINSTANCE
, export_callback
,
10943 &args
, &err
, semerr
)) != 0) {
10945 semerr(gettext("Failed to walk instances: %s\n"),
10946 scf_strerror(ret
));
10951 * Error message has already been printed.
10965 make_archive(int flags
)
10968 scf_scope_t
*scope
;
10969 scf_service_t
*svc
;
10973 if ((scope
= scf_scope_create(g_hndl
)) == NULL
||
10974 (svc
= scf_service_create(g_hndl
)) == NULL
||
10975 (iter
= scf_iter_create(g_hndl
)) == NULL
||
10976 (exp_inst
= scf_instance_create(g_hndl
)) == NULL
||
10977 (exp_pg
= scf_pg_create(g_hndl
)) == NULL
||
10978 (exp_prop
= scf_property_create(g_hndl
)) == NULL
||
10979 (exp_val
= scf_value_create(g_hndl
)) == NULL
||
10980 (exp_inst_iter
= scf_iter_create(g_hndl
)) == NULL
||
10981 (exp_pg_iter
= scf_iter_create(g_hndl
)) == NULL
||
10982 (exp_prop_iter
= scf_iter_create(g_hndl
)) == NULL
||
10983 (exp_val_iter
= scf_iter_create(g_hndl
)) == NULL
)
10986 exp_str_sz
= max_scf_len
+ 1;
10987 exp_str
= safe_malloc(exp_str_sz
);
10989 sb
= xmlNewNode(NULL
, (xmlChar
*)"service_bundle");
10991 uu_die(emsg_create_xml
);
10992 safe_setprop(sb
, type_attr
, "archive");
10993 safe_setprop(sb
, name_attr
, "none");
10995 if (scf_handle_get_scope(g_hndl
, SCF_SCOPE_LOCAL
, scope
) != 0)
10997 if (scf_iter_scope_services(iter
, scope
) != 0)
11001 r
= scf_iter_next_service(iter
, svc
);
11007 if (scf_service_get_name(svc
, exp_str
,
11008 max_scf_name_len
+ 1) < 0)
11011 if (strcmp(exp_str
, SCF_LEGACY_SERVICE
) == 0)
11014 (void) xmlAddChild(sb
, export_service(svc
, flags
));
11019 scf_iter_destroy(exp_val_iter
);
11020 scf_iter_destroy(exp_prop_iter
);
11021 scf_iter_destroy(exp_pg_iter
);
11022 scf_iter_destroy(exp_inst_iter
);
11023 scf_value_destroy(exp_val
);
11024 scf_property_destroy(exp_prop
);
11025 scf_pg_destroy(exp_pg
);
11026 scf_instance_destroy(exp_inst
);
11027 scf_iter_destroy(iter
);
11028 scf_service_destroy(svc
);
11029 scf_scope_destroy(scope
);
11035 lscf_archive(const char *filename
, int flags
)
11043 if (filename
!= NULL
) {
11045 f
= fopen(filename
, "wb");
11048 uu_die(gettext("Could not open \"%s\": no free "
11049 "stdio streams.\n"), filename
);
11051 uu_die(gettext("Could not open \"%s\""),
11057 doc
= xmlNewDoc((xmlChar
*)"1.0");
11059 uu_die(gettext("Could not create XML document.\n"));
11061 if (xmlCreateIntSubset(doc
, (xmlChar
*)"service_bundle", NULL
,
11062 (xmlChar
*)MANIFEST_DTD_PATH
) == NULL
)
11063 uu_die(emsg_create_xml
);
11065 (void) xmlAddSibling(doc
->children
, make_archive(flags
));
11067 result
= write_service_bundle(doc
, f
);
11079 * "Extract" a profile.
11082 lscf_profile_extract(const char *filename
)
11086 xmlNodePtr sb
, snode
, inode
;
11087 scf_scope_t
*scope
;
11088 scf_service_t
*svc
;
11089 scf_instance_t
*inst
;
11090 scf_propertygroup_t
*pg
;
11091 scf_property_t
*prop
;
11093 scf_iter_t
*siter
, *iiter
;
11101 if (filename
!= NULL
) {
11103 f
= fopen(filename
, "wb");
11106 uu_die(gettext("Could not open \"%s\": no "
11107 "free stdio streams.\n"), filename
);
11109 uu_die(gettext("Could not open \"%s\""),
11115 doc
= xmlNewDoc((xmlChar
*)"1.0");
11117 uu_die(gettext("Could not create XML document.\n"));
11119 if (xmlCreateIntSubset(doc
, (xmlChar
*)"service_bundle", NULL
,
11120 (xmlChar
*)MANIFEST_DTD_PATH
) == NULL
)
11121 uu_die(emsg_create_xml
);
11123 sb
= xmlNewNode(NULL
, (xmlChar
*)"service_bundle");
11125 uu_die(emsg_create_xml
);
11126 safe_setprop(sb
, type_attr
, "profile");
11127 safe_setprop(sb
, name_attr
, "extract");
11128 (void) xmlAddSibling(doc
->children
, sb
);
11130 if ((scope
= scf_scope_create(g_hndl
)) == NULL
||
11131 (svc
= scf_service_create(g_hndl
)) == NULL
||
11132 (inst
= scf_instance_create(g_hndl
)) == NULL
||
11133 (pg
= scf_pg_create(g_hndl
)) == NULL
||
11134 (prop
= scf_property_create(g_hndl
)) == NULL
||
11135 (val
= scf_value_create(g_hndl
)) == NULL
||
11136 (siter
= scf_iter_create(g_hndl
)) == NULL
||
11137 (iiter
= scf_iter_create(g_hndl
)) == NULL
)
11140 if (scf_handle_get_local_scope(g_hndl
, scope
) != SCF_SUCCESS
)
11143 if (scf_iter_scope_services(siter
, scope
) != SCF_SUCCESS
)
11146 namebuf
= safe_malloc(max_scf_name_len
+ 1);
11148 while ((r
= scf_iter_next_service(siter
, svc
)) == 1) {
11149 if (scf_iter_service_instances(iiter
, svc
) != SCF_SUCCESS
)
11152 snode
= xmlNewNode(NULL
, (xmlChar
*)"service");
11154 uu_die(emsg_create_xml
);
11156 if (scf_service_get_name(svc
, namebuf
, max_scf_name_len
+ 1) <
11160 safe_setprop(snode
, name_attr
, namebuf
);
11162 safe_setprop(snode
, type_attr
, "service");
11163 safe_setprop(snode
, "version", "0");
11165 while ((s
= scf_iter_next_instance(iiter
, inst
)) == 1) {
11166 if (scf_instance_get_pg(inst
, scf_pg_general
, pg
) !=
11168 if (scf_error() != SCF_ERROR_NOT_FOUND
)
11176 scf_instance_to_fmri(inst
, NULL
, 0);
11180 fmri
= safe_malloc(len
+ 1);
11182 if (scf_instance_to_fmri(inst
, fmri
,
11186 warn("Instance %s has no \"%s\" "
11187 "property group.\n", fmri
,
11196 if (pg_get_prop(pg
, scf_property_enabled
, prop
) != 0 ||
11197 prop_check_type(prop
, SCF_TYPE_BOOLEAN
) != 0 ||
11198 prop_get_val(prop
, val
) != 0)
11201 inode
= xmlNewChild(snode
, NULL
, (xmlChar
*)"instance",
11204 uu_die(emsg_create_xml
);
11206 if (scf_instance_get_name(inst
, namebuf
,
11207 max_scf_name_len
+ 1) < 0)
11210 safe_setprop(inode
, name_attr
, namebuf
);
11212 if (scf_value_get_boolean(val
, &b
) != SCF_SUCCESS
)
11215 safe_setprop(inode
, enabled_attr
, b
? true : false);
11220 if (snode
->children
!= NULL
)
11221 (void) xmlAddChild(sb
, snode
);
11223 xmlFreeNode(snode
);
11230 result
= write_service_bundle(doc
, f
);
11242 * Entity manipulation commands
11246 * Entity selection. If no entity is selected, then the current scope is in
11247 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected,
11248 * only cur_inst is NULL, and when an instance is selected, none are NULL.
11249 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
11250 * cur_inst will be non-NULL.
11253 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
11255 select_inst(const char *name
)
11257 scf_instance_t
*inst
;
11260 assert(cur_svc
!= NULL
);
11262 inst
= scf_instance_create(g_hndl
);
11266 if (scf_service_get_instance(cur_svc
, name
, inst
) == SCF_SUCCESS
) {
11272 if (err
!= SCF_ERROR_NOT_FOUND
&& err
!= SCF_ERROR_INVALID_ARGUMENT
)
11275 scf_instance_destroy(inst
);
11279 /* Returns as above. */
11281 select_svc(const char *name
)
11283 scf_service_t
*svc
;
11286 assert(cur_scope
!= NULL
);
11288 svc
= scf_service_create(g_hndl
);
11292 if (scf_scope_get_service(cur_scope
, name
, svc
) == SCF_SUCCESS
) {
11298 if (err
!= SCF_ERROR_NOT_FOUND
&& err
!= SCF_ERROR_INVALID_ARGUMENT
)
11301 scf_service_destroy(svc
);
11307 select_callback(void *unused
, scf_walkinfo_t
*wip
)
11309 scf_instance_t
*inst
;
11310 scf_service_t
*svc
;
11311 scf_scope_t
*scope
;
11313 if (wip
->inst
!= NULL
) {
11314 if ((scope
= scf_scope_create(g_hndl
)) == NULL
||
11315 (svc
= scf_service_create(g_hndl
)) == NULL
||
11316 (inst
= scf_instance_create(g_hndl
)) == NULL
)
11319 if (scf_handle_decode_fmri(g_hndl
, wip
->fmri
, scope
, svc
,
11320 inst
, NULL
, NULL
, SCF_DECODE_FMRI_EXACT
) != SCF_SUCCESS
)
11323 assert(wip
->svc
!= NULL
);
11325 if ((scope
= scf_scope_create(g_hndl
)) == NULL
||
11326 (svc
= scf_service_create(g_hndl
)) == NULL
)
11329 if (scf_handle_decode_fmri(g_hndl
, wip
->fmri
, scope
, svc
,
11330 NULL
, NULL
, NULL
, SCF_DECODE_FMRI_EXACT
) != SCF_SUCCESS
)
11336 /* Clear out the current selection */
11337 assert(cur_scope
!= NULL
);
11338 scf_scope_destroy(cur_scope
);
11339 scf_service_destroy(cur_svc
);
11340 scf_instance_destroy(cur_inst
);
11350 validate_callback(void *fmri_p
, scf_walkinfo_t
*wip
)
11352 char **fmri
= fmri_p
;
11354 *fmri
= strdup(wip
->fmri
);
11356 uu_die(gettext("Out of memory.\n"));
11363 * Perform the validation of an FMRI instance.
11366 lscf_validate_fmri(const char *fmri
)
11370 char *inst_fmri
= NULL
;
11371 scf_tmpl_errors_t
*errs
= NULL
;
11372 char *snapbuf
= NULL
;
11376 if (fmri
== NULL
) {
11377 inst_sz
= max_scf_fmri_len
+ 1;
11378 inst_fmri
= safe_malloc(inst_sz
);
11380 if (cur_snap
!= NULL
) {
11381 snapbuf
= safe_malloc(max_scf_name_len
+ 1);
11382 if (scf_snapshot_get_name(cur_snap
, snapbuf
,
11383 max_scf_name_len
+ 1) < 0)
11386 if (cur_inst
== NULL
) {
11387 semerr(gettext("No instance selected\n"));
11389 } else if (scf_instance_to_fmri(cur_inst
, inst_fmri
,
11390 inst_sz
) >= inst_sz
) {
11391 /* sanity check. Should never get here */
11392 uu_die(gettext("Unexpected error! file %s, line %d\n"),
11393 __FILE__
, __LINE__
);
11396 scf_error_t scf_err
;
11399 if ((scf_err
= scf_walk_fmri(g_hndl
, 1, (char **)&fmri
, 0,
11400 validate_callback
, &inst_fmri
, &err
, semerr
)) != 0) {
11401 uu_warn("Failed to walk instances: %s\n",
11402 scf_strerror(scf_err
));
11406 /* error message displayed by scf_walk_fmri */
11411 ret
= scf_tmpl_validate_fmri(g_hndl
, inst_fmri
, snapbuf
, &errs
,
11412 SCF_TMPL_VALIDATE_FLAG_CURRENT
);
11414 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID
) {
11415 warn(gettext("Template data for %s is invalid. "
11416 "Consider reverting to a previous snapshot or "
11417 "restoring original configuration.\n"), inst_fmri
);
11419 uu_warn("%s: %s\n",
11420 gettext("Error validating the instance"),
11421 scf_strerror(scf_error()));
11423 } else if (ret
== 1 && errs
!= NULL
) {
11424 scf_tmpl_error_t
*err
= NULL
;
11426 size_t len
= 256; /* initial error buffer size */
11427 int flag
= (est
->sc_cmd_flags
& SC_CMD_IACTIVE
) ?
11428 SCF_TMPL_STRERROR_HUMAN
: 0;
11430 msg
= safe_malloc(len
);
11432 while ((err
= scf_tmpl_next_error(errs
)) != NULL
) {
11435 if ((ret
= scf_tmpl_strerror(err
, msg
, len
,
11438 msg
= realloc(msg
, len
);
11441 "Out of memory.\n"));
11442 (void) scf_tmpl_strerror(err
, msg
, len
,
11445 (void) fprintf(stderr
, "%s\n", msg
);
11450 scf_tmpl_errors_destroy(errs
);
11458 lscf_validate_file(const char *filename
)
11460 tmpl_errors_t
*errs
;
11462 bundle_t
*b
= internal_bundle_new();
11463 if (lxml_get_bundle_file(b
, filename
, SVCCFG_OP_IMPORT
) == 0) {
11464 if (tmpl_validate_bundle(b
, &errs
) != TVS_SUCCESS
) {
11465 tmpl_errors_print(stderr
, errs
, "");
11466 semerr(gettext("Validation failed.\n"));
11468 tmpl_errors_destroy(errs
);
11470 (void) internal_bundle_free(b
);
11474 * validate [fmri|file]
11477 lscf_validate(const char *arg
)
11481 if (strncmp(arg
, SCF_FMRI_FILE_PREFIX
,
11482 sizeof (SCF_FMRI_FILE_PREFIX
) - 1) == 0) {
11483 str
= arg
+ sizeof (SCF_FMRI_FILE_PREFIX
) - 1;
11484 lscf_validate_file(str
);
11485 } else if (strncmp(arg
, SCF_FMRI_SVC_PREFIX
,
11486 sizeof (SCF_FMRI_SVC_PREFIX
) - 1) == 0) {
11487 str
= arg
+ sizeof (SCF_FMRI_SVC_PREFIX
) - 1;
11488 lscf_validate_fmri(str
);
11489 } else if (access(arg
, R_OK
| F_OK
) == 0) {
11490 lscf_validate_file(arg
);
11492 lscf_validate_fmri(arg
);
11497 lscf_select(const char *fmri
)
11503 if (cur_snap
!= NULL
) {
11504 struct snaplevel
*elt
;
11507 /* Error unless name is that of the next level. */
11508 elt
= uu_list_next(cur_levels
, cur_elt
);
11510 semerr(gettext("No children.\n"));
11514 buf
= safe_malloc(max_scf_name_len
+ 1);
11516 if (scf_snaplevel_get_instance_name(elt
->sl
, buf
,
11517 max_scf_name_len
+ 1) < 0)
11520 if (strcmp(buf
, fmri
) != 0) {
11521 semerr(gettext("No such child.\n"));
11529 cur_level
= elt
->sl
;
11534 * Special case for 'svc:', which takes the user to the scope level.
11536 if (strcmp(fmri
, "svc:") == 0) {
11537 scf_instance_destroy(cur_inst
);
11538 scf_service_destroy(cur_svc
);
11545 * Special case for ':properties'. This appears as part of 'list' but
11546 * can't be selected. Give a more helpful error message in this case.
11548 if (strcmp(fmri
, ":properties") == 0) {
11549 semerr(gettext(":properties is not an entity. Try 'listprop' "
11550 "to list properties.\n"));
11555 * First try the argument as relative to the current selection.
11557 if (cur_inst
!= NULL
) {
11559 } else if (cur_svc
!= NULL
) {
11560 if (select_inst(fmri
) != 1)
11563 if (select_svc(fmri
) != 1)
11568 if ((ret
= scf_walk_fmri(g_hndl
, 1, (char **)&fmri
, SCF_WALK_SERVICE
,
11569 select_callback
, NULL
, &err
, semerr
)) != 0) {
11570 semerr(gettext("Failed to walk instances: %s\n"),
11571 scf_strerror(ret
));
11576 lscf_unselect(void)
11580 if (cur_snap
!= NULL
) {
11581 struct snaplevel
*elt
;
11583 elt
= uu_list_prev(cur_levels
, cur_elt
);
11585 semerr(gettext("No parent levels.\n"));
11588 cur_level
= elt
->sl
;
11590 } else if (cur_inst
!= NULL
) {
11591 scf_instance_destroy(cur_inst
);
11593 } else if (cur_svc
!= NULL
) {
11594 scf_service_destroy(cur_svc
);
11597 semerr(gettext("Cannot unselect at scope level.\n"));
11602 * Return the FMRI of the current selection, for the prompt.
11605 lscf_get_selection_str(char *buf
, size_t bufsz
)
11608 ssize_t fmrilen
, szret
;
11609 boolean_t deleted
= B_FALSE
;
11611 if (g_hndl
== NULL
) {
11612 (void) strlcpy(buf
, "svc:", bufsz
);
11616 if (cur_level
!= NULL
) {
11617 assert(cur_snap
!= NULL
);
11619 /* [ snapshot ] FMRI [: instance ] */
11620 assert(bufsz
>= 1 + max_scf_name_len
+ 1 + max_scf_fmri_len
11621 + 2 + max_scf_name_len
+ 1 + 1);
11625 szret
= scf_snapshot_get_name(cur_snap
, buf
+ 1,
11626 max_scf_name_len
+ 1);
11628 if (scf_error() != SCF_ERROR_DELETED
)
11634 (void) strcat(buf
, "]svc:/");
11636 cp
= strchr(buf
, '\0');
11638 szret
= scf_snaplevel_get_service_name(cur_level
, cp
,
11639 max_scf_name_len
+ 1);
11641 if (scf_error() != SCF_ERROR_DELETED
)
11647 cp
= strchr(cp
, '\0');
11649 if (snaplevel_is_instance(cur_level
)) {
11652 if (scf_snaplevel_get_instance_name(cur_level
, cp
,
11653 max_scf_name_len
+ 1) < 0) {
11654 if (scf_error() != SCF_ERROR_DELETED
)
11663 if (scf_instance_get_name(cur_inst
, cp
,
11664 max_scf_name_len
+ 1) < 0) {
11665 if (scf_error() != SCF_ERROR_DELETED
)
11671 (void) strcat(buf
, "]");
11679 unselect_cursnap();
11682 assert(cur_snap
== NULL
);
11684 if (cur_inst
!= NULL
) {
11685 assert(cur_svc
!= NULL
);
11686 assert(cur_scope
!= NULL
);
11688 fmrilen
= scf_instance_to_fmri(cur_inst
, buf
, bufsz
);
11689 if (fmrilen
>= 0) {
11690 assert(fmrilen
< bufsz
);
11692 warn(emsg_deleted
);
11696 if (scf_error() != SCF_ERROR_DELETED
)
11701 scf_instance_destroy(cur_inst
);
11705 if (cur_svc
!= NULL
) {
11706 assert(cur_scope
!= NULL
);
11708 szret
= scf_service_to_fmri(cur_svc
, buf
, bufsz
);
11710 assert(szret
< bufsz
);
11712 warn(emsg_deleted
);
11716 if (scf_error() != SCF_ERROR_DELETED
)
11720 scf_service_destroy(cur_svc
);
11724 assert(cur_scope
!= NULL
);
11725 fmrilen
= scf_scope_to_fmri(cur_scope
, buf
, bufsz
);
11730 assert(fmrilen
< bufsz
);
11732 warn(emsg_deleted
);
11736 * Entity listing. Entities and colon namespaces (e.g., :properties and
11737 * :statistics) are listed for the current selection.
11740 lscf_list(const char *pattern
)
11748 if (cur_level
!= NULL
) {
11749 struct snaplevel
*elt
;
11751 (void) fputs(COLON_NAMESPACES
, stdout
);
11753 elt
= uu_list_next(cur_levels
, cur_elt
);
11758 * For now, we know that the next level is an instance. But
11759 * if we ever have multiple scopes, this could be complicated.
11761 buf
= safe_malloc(max_scf_name_len
+ 1);
11762 if (scf_snaplevel_get_instance_name(elt
->sl
, buf
,
11763 max_scf_name_len
+ 1) >= 0) {
11766 if (scf_error() != SCF_ERROR_DELETED
)
11775 if (cur_inst
!= NULL
) {
11776 (void) fputs(COLON_NAMESPACES
, stdout
);
11780 iter
= scf_iter_create(g_hndl
);
11784 buf
= safe_malloc(max_scf_name_len
+ 1);
11786 if (cur_svc
!= NULL
) {
11787 /* List the instances in this service. */
11788 scf_instance_t
*inst
;
11790 inst
= scf_instance_create(g_hndl
);
11794 if (scf_iter_service_instances(iter
, cur_svc
) == 0) {
11795 safe_printf(COLON_NAMESPACES
);
11798 ret
= scf_iter_next_instance(iter
, inst
);
11802 if (scf_error() != SCF_ERROR_DELETED
)
11808 if (scf_instance_get_name(inst
, buf
,
11809 max_scf_name_len
+ 1) >= 0) {
11810 if (pattern
== NULL
||
11811 fnmatch(pattern
, buf
, 0) == 0)
11814 if (scf_error() != SCF_ERROR_DELETED
)
11819 if (scf_error() != SCF_ERROR_DELETED
)
11823 scf_instance_destroy(inst
);
11825 /* List the services in this scope. */
11826 scf_service_t
*svc
;
11828 assert(cur_scope
!= NULL
);
11830 svc
= scf_service_create(g_hndl
);
11834 if (scf_iter_scope_services(iter
, cur_scope
) != SCF_SUCCESS
)
11838 ret
= scf_iter_next_service(iter
, svc
);
11844 if (scf_service_get_name(svc
, buf
,
11845 max_scf_name_len
+ 1) >= 0) {
11846 if (pattern
== NULL
||
11847 fnmatch(pattern
, buf
, 0) == 0)
11848 safe_printf("%s\n", buf
);
11850 if (scf_error() != SCF_ERROR_DELETED
)
11855 scf_service_destroy(svc
);
11859 scf_iter_destroy(iter
);
11863 * Entity addition. Creates an empty entity in the current selection.
11866 lscf_add(const char *name
)
11870 if (cur_snap
!= NULL
) {
11871 semerr(emsg_cant_modify_snapshots
);
11872 } else if (cur_inst
!= NULL
) {
11873 semerr(gettext("Cannot add entities to an instance.\n"));
11874 } else if (cur_svc
!= NULL
) {
11876 if (scf_service_add_instance(cur_svc
, name
, NULL
) !=
11878 switch (scf_error()) {
11879 case SCF_ERROR_INVALID_ARGUMENT
:
11880 semerr(gettext("Invalid name.\n"));
11883 case SCF_ERROR_EXISTS
:
11884 semerr(gettext("Instance already exists.\n"));
11887 case SCF_ERROR_PERMISSION_DENIED
:
11888 semerr(emsg_permission_denied
);
11896 assert(cur_scope
!= NULL
);
11898 if (scf_scope_add_service(cur_scope
, name
, NULL
) !=
11900 switch (scf_error()) {
11901 case SCF_ERROR_INVALID_ARGUMENT
:
11902 semerr(gettext("Invalid name.\n"));
11905 case SCF_ERROR_EXISTS
:
11906 semerr(gettext("Service already exists.\n"));
11909 case SCF_ERROR_PERMISSION_DENIED
:
11910 semerr(emsg_permission_denied
);
11913 case SCF_ERROR_BACKEND_READONLY
:
11914 semerr(emsg_read_only
);
11924 /* return 1 if the entity has no persistent pgs, else return 0 */
11926 entity_has_no_pgs(void *ent
, int isservice
)
11928 scf_iter_t
*iter
= NULL
;
11929 scf_propertygroup_t
*pg
= NULL
;
11934 if ((iter
= scf_iter_create(g_hndl
)) == NULL
||
11935 (pg
= scf_pg_create(g_hndl
)) == NULL
)
11939 if (scf_iter_service_pgs(iter
, (scf_service_t
*)ent
) < 0)
11942 if (scf_iter_instance_pgs(iter
, (scf_instance_t
*)ent
) < 0)
11946 while ((err
= scf_iter_next_pg(iter
, pg
)) == 1) {
11947 if (scf_pg_get_flags(pg
, &flags
) != 0)
11950 /* skip nonpersistent pgs */
11951 if (flags
& SCF_PG_FLAG_NONPERSISTENT
)
11961 scf_pg_destroy(pg
);
11962 scf_iter_destroy(iter
);
11967 /* return 1 if the service has no instances, else return 0 */
11969 svc_has_no_insts(scf_service_t
*svc
)
11971 scf_instance_t
*inst
;
11976 if ((inst
= scf_instance_create(g_hndl
)) == NULL
||
11977 (iter
= scf_iter_create(g_hndl
)) == NULL
)
11980 if (scf_iter_service_instances(iter
, svc
) != 0)
11983 r
= scf_iter_next_instance(iter
, inst
);
11986 } else if (r
== 0) {
11988 } else if (r
== -1) {
11991 bad_error("scf_iter_next_instance", r
);
11994 scf_iter_destroy(iter
);
11995 scf_instance_destroy(inst
);
12005 * Delete the property group <fmri>/:properties/<name>. Returns
12006 * SCF_ERROR_NONE on success (or if the entity is not found),
12007 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
12008 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
12012 delete_dependency_pg(const char *fmri
, const char *name
)
12014 void *entity
= NULL
;
12016 scf_propertygroup_t
*pg
= NULL
;
12017 scf_error_t result
;
12019 scf_service_t
*svc
= NULL
;
12020 scf_instance_t
*inst
= NULL
;
12021 scf_iter_t
*iter
= NULL
;
12022 char *name_buf
= NULL
;
12024 result
= fmri_to_entity(g_hndl
, fmri
, &entity
, &isservice
);
12026 case SCF_ERROR_NONE
:
12029 case SCF_ERROR_NO_MEMORY
:
12030 uu_die(gettext("Out of memory.\n"));
12033 case SCF_ERROR_INVALID_ARGUMENT
:
12034 case SCF_ERROR_CONSTRAINT_VIOLATED
:
12035 return (SCF_ERROR_INVALID_ARGUMENT
);
12037 case SCF_ERROR_NOT_FOUND
:
12038 result
= SCF_ERROR_NONE
;
12042 bad_error("fmri_to_entity", result
);
12045 pg
= scf_pg_create(g_hndl
);
12049 if (entity_get_pg(entity
, isservice
, name
, pg
) != 0) {
12050 if (scf_error() != SCF_ERROR_NOT_FOUND
)
12053 result
= SCF_ERROR_NONE
;
12057 pgty
= safe_malloc(max_scf_pg_type_len
+ 1);
12059 if (scf_pg_get_type(pg
, pgty
, max_scf_pg_type_len
+ 1) < 0)
12062 if (strcmp(pgty
, SCF_GROUP_DEPENDENCY
) != 0) {
12063 result
= SCF_ERROR_TYPE_MISMATCH
;
12070 if (scf_pg_delete(pg
) != 0) {
12071 result
= scf_error();
12072 if (result
!= SCF_ERROR_PERMISSION_DENIED
)
12078 * We have to handle the case where we've just deleted the last
12079 * property group of a "dummy" entity (instance or service).
12080 * A "dummy" entity is an entity only present to hold an
12081 * external dependency.
12082 * So, in the case we deleted the last property group then we
12083 * can also delete the entity. If the entity is an instance then
12084 * we must verify if this was the last instance for the service
12085 * and if it is, we can also delete the service if it doesn't
12086 * have any property group either.
12089 result
= SCF_ERROR_NONE
;
12092 svc
= (scf_service_t
*)entity
;
12094 if ((inst
= scf_instance_create(g_hndl
)) == NULL
||
12095 (iter
= scf_iter_create(g_hndl
)) == NULL
)
12098 name_buf
= safe_malloc(max_scf_name_len
+ 1);
12100 inst
= (scf_instance_t
*)entity
;
12104 * If the entity is an instance and we've just deleted its last
12105 * property group then we should delete it.
12107 if (!isservice
&& entity_has_no_pgs(entity
, isservice
)) {
12108 /* find the service before deleting the inst. - needed later */
12109 if ((svc
= scf_service_create(g_hndl
)) == NULL
)
12112 if (scf_instance_get_parent(inst
, svc
) != 0)
12115 /* delete the instance */
12116 if (scf_instance_delete(inst
) != 0) {
12117 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
12120 result
= SCF_ERROR_PERMISSION_DENIED
;
12123 /* no need to refresh the instance */
12128 * If the service has no more instances and pgs or we just deleted the
12129 * last instance and the service doesn't have anymore propery groups
12130 * then the service should be deleted.
12133 svc_has_no_insts(svc
) &&
12134 entity_has_no_pgs((void *)svc
, 1)) {
12135 if (scf_service_delete(svc
) == 0) {
12137 /* no need to refresh the service */
12144 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
12147 result
= SCF_ERROR_PERMISSION_DENIED
;
12150 /* if the entity has not been deleted, refresh it */
12151 if ((isservice
&& svc
!= NULL
) || (!isservice
&& inst
!= NULL
)) {
12152 (void) refresh_entity(isservice
, entity
, fmri
, inst
, iter
,
12157 if (isservice
&& (inst
!= NULL
&& iter
!= NULL
)) {
12159 scf_iter_destroy(iter
);
12160 scf_instance_destroy(inst
);
12163 if (!isservice
&& svc
!= NULL
) {
12164 scf_service_destroy(svc
);
12167 scf_pg_destroy(pg
);
12168 if (entity
!= NULL
)
12169 entity_destroy(entity
, isservice
);
12175 delete_dependents(scf_propertygroup_t
*pg
)
12177 char *pgty
, *name
, *fmri
;
12178 scf_property_t
*prop
;
12184 /* Verify that the pg has the correct type. */
12185 pgty
= safe_malloc(max_scf_pg_type_len
+ 1);
12186 if (scf_pg_get_type(pg
, pgty
, max_scf_pg_type_len
+ 1) < 0)
12189 if (strcmp(pgty
, scf_group_framework
) != 0) {
12191 fmri
= safe_malloc(max_scf_fmri_len
+ 1);
12192 if (scf_pg_to_fmri(pg
, fmri
, max_scf_fmri_len
+ 1) < 0)
12195 warn(gettext("Property group %s is not of expected "
12196 "type %s.\n"), fmri
, scf_group_framework
);
12207 /* map delete_dependency_pg onto the properties. */
12208 if ((prop
= scf_property_create(g_hndl
)) == NULL
||
12209 (val
= scf_value_create(g_hndl
)) == NULL
||
12210 (iter
= scf_iter_create(g_hndl
)) == NULL
)
12213 if (scf_iter_pg_properties(iter
, pg
) != SCF_SUCCESS
)
12216 name
= safe_malloc(max_scf_name_len
+ 1);
12217 fmri
= safe_malloc(max_scf_fmri_len
+ 2);
12219 while ((r
= scf_iter_next_property(iter
, prop
)) == 1) {
12222 if (scf_property_get_name(prop
, name
, max_scf_name_len
+ 1) < 0)
12225 if (scf_property_type(prop
, &ty
) != SCF_SUCCESS
)
12228 if ((ty
!= SCF_TYPE_ASTRING
&&
12229 prop_check_type(prop
, SCF_TYPE_FMRI
) != 0) ||
12230 prop_get_val(prop
, val
) != 0)
12233 if (scf_value_get_astring(val
, fmri
, max_scf_fmri_len
+ 2) < 0)
12236 err
= delete_dependency_pg(fmri
, name
);
12237 if (err
== SCF_ERROR_INVALID_ARGUMENT
&& g_verbose
) {
12238 if (scf_property_to_fmri(prop
, fmri
,
12239 max_scf_fmri_len
+ 2) < 0)
12242 warn(gettext("Value of %s is not a valid FMRI.\n"),
12244 } else if (err
== SCF_ERROR_TYPE_MISMATCH
&& g_verbose
) {
12245 warn(gettext("Property group \"%s\" of entity \"%s\" "
12246 "does not have dependency type.\n"), name
, fmri
);
12247 } else if (err
== SCF_ERROR_PERMISSION_DENIED
&& g_verbose
) {
12248 warn(gettext("Could not delete property group \"%s\" "
12249 "of entity \"%s\" (permission denied).\n"), name
,
12256 scf_value_destroy(val
);
12257 scf_property_destroy(prop
);
12263 * Returns 1 if the instance may be running, and 0 otherwise.
12266 inst_is_running(scf_instance_t
*inst
)
12268 scf_propertygroup_t
*pg
;
12269 scf_property_t
*prop
;
12271 char buf
[MAX_SCF_STATE_STRING_SZ
];
12275 if ((pg
= scf_pg_create(g_hndl
)) == NULL
||
12276 (prop
= scf_property_create(g_hndl
)) == NULL
||
12277 (val
= scf_value_create(g_hndl
)) == NULL
)
12280 if (scf_instance_get_pg(inst
, SCF_PG_RESTARTER
, pg
) != SCF_SUCCESS
) {
12281 if (scf_error() != SCF_ERROR_NOT_FOUND
)
12286 if (pg_get_prop(pg
, SCF_PROPERTY_STATE
, prop
) != 0 ||
12287 prop_check_type(prop
, SCF_TYPE_ASTRING
) != 0 ||
12288 prop_get_val(prop
, val
) != 0)
12291 szret
= scf_value_get_astring(val
, buf
, sizeof (buf
));
12292 assert(szret
>= 0);
12294 ret
= (strcmp(buf
, SCF_STATE_STRING_ONLINE
) == 0 ||
12295 strcmp(buf
, SCF_STATE_STRING_DEGRADED
) == 0) ? 1 : 0;
12298 scf_value_destroy(val
);
12299 scf_property_destroy(prop
);
12300 scf_pg_destroy(pg
);
12305 pg_is_external_dependency(scf_propertygroup_t
*pg
)
12309 scf_property_t
*prop
;
12310 uint8_t b
= B_FALSE
;
12312 type
= safe_malloc(max_scf_pg_type_len
+ 1);
12314 if (scf_pg_get_type(pg
, type
, max_scf_pg_type_len
+ 1) < 0)
12317 if ((prop
= scf_property_create(g_hndl
)) == NULL
||
12318 (val
= scf_value_create(g_hndl
)) == NULL
)
12321 if (strcmp(type
, SCF_GROUP_DEPENDENCY
) == 0) {
12322 if (pg_get_prop(pg
, scf_property_external
, prop
) == 0) {
12323 if (scf_property_get_value(prop
, val
) != 0)
12325 if (scf_value_get_boolean(val
, &b
) != 0)
12331 (void) scf_value_destroy(val
);
12332 (void) scf_property_destroy(prop
);
12337 #define DELETE_FAILURE -1
12338 #define DELETE_SUCCESS_NOEXTDEPS 0
12339 #define DELETE_SUCCESS_EXTDEPS 1
12342 * lscf_instance_delete() deletes an instance. Before calling
12343 * scf_instance_delete(), though, we make sure the instance isn't
12344 * running and delete dependencies in other entities which the instance
12345 * declared as "dependents". If there are dependencies which were
12346 * created for other entities, then instead of deleting the instance we
12347 * make it "empty" by deleting all other property groups and all
12350 * lscf_instance_delete() verifies that there is no external dependency pgs
12351 * before suppressing the instance. If there is, then we must not remove them
12352 * now in case the instance is re-created otherwise the dependencies would be
12353 * lost. The external dependency pgs will be removed if the dependencies are
12357 * DELETE_FAILURE on failure
12358 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12359 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12362 lscf_instance_delete(scf_instance_t
*inst
, int force
)
12364 scf_propertygroup_t
*pg
;
12365 scf_snapshot_t
*snap
;
12370 /* If we're not forcing and the instance is running, refuse. */
12371 if (!force
&& inst_is_running(inst
)) {
12374 fmri
= safe_malloc(max_scf_fmri_len
+ 1);
12376 if (scf_instance_to_fmri(inst
, fmri
, max_scf_fmri_len
+ 1) < 0)
12379 semerr(gettext("Instance %s may be running. "
12380 "Use delete -f if it is not.\n"), fmri
);
12383 return (DELETE_FAILURE
);
12386 pg
= scf_pg_create(g_hndl
);
12390 if (scf_instance_get_pg(inst
, SCF_PG_DEPENDENTS
, pg
) == 0)
12391 (void) delete_dependents(pg
);
12392 else if (scf_error() != SCF_ERROR_NOT_FOUND
)
12395 scf_pg_destroy(pg
);
12398 * If the instance has some external dependencies then we must
12399 * keep them in case the instance is reimported otherwise the
12400 * dependencies would be lost on reimport.
12402 if ((iter
= scf_iter_create(g_hndl
)) == NULL
||
12403 (pg
= scf_pg_create(g_hndl
)) == NULL
)
12406 if (scf_iter_instance_pgs(iter
, inst
) < 0)
12409 while ((err
= scf_iter_next_pg(iter
, pg
)) == 1) {
12410 if (pg_is_external_dependency(pg
)) {
12415 if (scf_pg_delete(pg
) != 0) {
12416 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
12419 semerr(emsg_permission_denied
);
12421 (void) scf_iter_destroy(iter
);
12422 (void) scf_pg_destroy(pg
);
12423 return (DELETE_FAILURE
);
12431 (void) scf_iter_destroy(iter
);
12432 (void) scf_pg_destroy(pg
);
12436 * All the pgs have been deleted for the instance except
12437 * the ones holding the external dependencies.
12438 * For the job to be complete, we must also delete the
12439 * snapshots associated with the instance.
12441 if ((snap
= scf_snapshot_create((scf_handle_t
*)g_hndl
)) ==
12444 if ((iter
= scf_iter_create((scf_handle_t
*)g_hndl
)) == NULL
)
12447 if (scf_iter_instance_snapshots(iter
, inst
) == -1)
12450 while ((err
= scf_iter_next_snapshot(iter
, snap
)) == 1) {
12451 if (_scf_snapshot_delete(snap
) != 0) {
12452 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
12455 semerr(emsg_permission_denied
);
12457 (void) scf_iter_destroy(iter
);
12458 (void) scf_snapshot_destroy(snap
);
12459 return (DELETE_FAILURE
);
12466 (void) scf_iter_destroy(iter
);
12467 (void) scf_snapshot_destroy(snap
);
12468 return (DELETE_SUCCESS_EXTDEPS
);
12471 if (scf_instance_delete(inst
) != 0) {
12472 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
12475 semerr(emsg_permission_denied
);
12477 return (DELETE_FAILURE
);
12480 return (DELETE_SUCCESS_NOEXTDEPS
);
12484 * lscf_service_delete() deletes a service. Before calling
12485 * scf_service_delete(), though, we call lscf_instance_delete() for
12486 * each of the instances and delete dependencies in other entities
12487 * which were created as "dependents" of this service. If there are
12488 * dependencies which were created for other entities, then we delete
12489 * all other property groups in the service and leave it as "empty".
12491 * lscf_service_delete() verifies that there is no external dependency
12492 * pgs at the instance & service level before suppressing the service.
12493 * If there is, then we must not remove them now in case the service
12494 * is re-imported otherwise the dependencies would be lost. The external
12495 * dependency pgs will be removed if the dependencies are removed.
12498 * DELETE_FAILURE on failure
12499 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12500 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12503 lscf_service_delete(scf_service_t
*svc
, int force
)
12506 scf_instance_t
*inst
;
12507 scf_propertygroup_t
*pg
;
12512 if ((inst
= scf_instance_create(g_hndl
)) == NULL
||
12513 (pg
= scf_pg_create(g_hndl
)) == NULL
||
12514 (iter
= scf_iter_create(g_hndl
)) == NULL
)
12517 if (scf_iter_service_instances(iter
, svc
) != 0)
12520 for (r
= scf_iter_next_instance(iter
, inst
);
12522 r
= scf_iter_next_instance(iter
, inst
)) {
12524 ret
= lscf_instance_delete(inst
, force
);
12525 if (ret
== DELETE_FAILURE
) {
12526 scf_iter_destroy(iter
);
12527 scf_pg_destroy(pg
);
12528 scf_instance_destroy(inst
);
12529 return (DELETE_FAILURE
);
12533 * Record the fact that there is some external dependencies
12534 * at the instance level.
12536 if (ret
== DELETE_SUCCESS_EXTDEPS
)
12543 /* Delete dependency property groups in dependent services. */
12544 if (scf_service_get_pg(svc
, SCF_PG_DEPENDENTS
, pg
) == 0)
12545 (void) delete_dependents(pg
);
12546 else if (scf_error() != SCF_ERROR_NOT_FOUND
)
12549 scf_iter_destroy(iter
);
12550 scf_pg_destroy(pg
);
12551 scf_instance_destroy(inst
);
12554 * If the service has some external dependencies then we don't
12555 * want to remove them in case the service is re-imported.
12557 if ((pg
= scf_pg_create(g_hndl
)) == NULL
||
12558 (iter
= scf_iter_create(g_hndl
)) == NULL
)
12561 if (scf_iter_service_pgs(iter
, svc
) < 0)
12564 while ((r
= scf_iter_next_pg(iter
, pg
)) == 1) {
12565 if (pg_is_external_dependency(pg
)) {
12570 if (scf_pg_delete(pg
) != 0) {
12571 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
12574 semerr(emsg_permission_denied
);
12576 (void) scf_iter_destroy(iter
);
12577 (void) scf_pg_destroy(pg
);
12578 return (DELETE_FAILURE
);
12586 (void) scf_iter_destroy(iter
);
12587 (void) scf_pg_destroy(pg
);
12590 return (DELETE_SUCCESS_EXTDEPS
);
12592 if (scf_service_delete(svc
) == 0)
12593 return (DELETE_SUCCESS_NOEXTDEPS
);
12595 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
12598 semerr(emsg_permission_denied
);
12599 return (DELETE_FAILURE
);
12603 delete_callback(void *data
, scf_walkinfo_t
*wip
)
12605 int force
= (int)data
;
12607 if (wip
->inst
!= NULL
)
12608 (void) lscf_instance_delete(wip
->inst
, force
);
12610 (void) lscf_service_delete(wip
->svc
, force
);
12616 lscf_delete(const char *fmri
, int force
)
12618 scf_service_t
*svc
;
12619 scf_instance_t
*inst
;
12624 if (cur_snap
!= NULL
) {
12625 if (!snaplevel_is_instance(cur_level
)) {
12628 buf
= safe_malloc(max_scf_name_len
+ 1);
12629 if (scf_instance_get_name(cur_inst
, buf
,
12630 max_scf_name_len
+ 1) >= 0) {
12631 if (strcmp(buf
, fmri
) == 0) {
12632 semerr(emsg_cant_modify_snapshots
);
12636 } else if (scf_error() != SCF_ERROR_DELETED
) {
12641 } else if (cur_inst
!= NULL
) {
12643 } else if (cur_svc
!= NULL
) {
12644 inst
= scf_instance_create(g_hndl
);
12648 if (scf_service_get_instance(cur_svc
, fmri
, inst
) ==
12650 (void) lscf_instance_delete(inst
, force
);
12651 scf_instance_destroy(inst
);
12655 if (scf_error() != SCF_ERROR_NOT_FOUND
&&
12656 scf_error() != SCF_ERROR_INVALID_ARGUMENT
)
12659 scf_instance_destroy(inst
);
12661 assert(cur_scope
!= NULL
);
12663 svc
= scf_service_create(g_hndl
);
12667 if (scf_scope_get_service(cur_scope
, fmri
, svc
) ==
12669 (void) lscf_service_delete(svc
, force
);
12670 scf_service_destroy(svc
);
12674 if (scf_error() != SCF_ERROR_NOT_FOUND
&&
12675 scf_error() != SCF_ERROR_INVALID_ARGUMENT
)
12678 scf_service_destroy(svc
);
12682 * Match FMRI to entity.
12684 if ((ret
= scf_walk_fmri(g_hndl
, 1, (char **)&fmri
, SCF_WALK_SERVICE
,
12685 delete_callback
, (void *)force
, NULL
, semerr
)) != 0) {
12686 semerr(gettext("Failed to walk instances: %s\n"),
12687 scf_strerror(ret
));
12694 * :properties commands. These all end with "pg" or "prop" and generally
12695 * operate on the currently selected entity.
12699 * Property listing. List the property groups, properties, their types and
12700 * their values for the currently selected entity.
12703 list_pg_info(const scf_propertygroup_t
*pg
, const char *name
, size_t namewidth
)
12708 buf
= safe_malloc(max_scf_pg_type_len
+ 1);
12710 if (scf_pg_get_type(pg
, buf
, max_scf_pg_type_len
+ 1) < 0)
12713 if (scf_pg_get_flags(pg
, &flags
) != SCF_SUCCESS
)
12716 safe_printf("%-*s %s", namewidth
, name
, buf
);
12718 if (flags
& SCF_PG_FLAG_NONPERSISTENT
)
12719 safe_printf("\tNONPERSISTENT");
12727 prop_has_multiple_values(const scf_property_t
*prop
, scf_value_t
*val
)
12729 if (scf_property_get_value(prop
, val
) == 0) {
12732 switch (scf_error()) {
12733 case SCF_ERROR_NOT_FOUND
:
12735 case SCF_ERROR_PERMISSION_DENIED
:
12736 case SCF_ERROR_CONSTRAINT_VIOLATED
:
12746 list_prop_info(const scf_property_t
*prop
, const char *name
, size_t len
)
12751 int multiple_strings
= 0;
12754 if ((iter
= scf_iter_create(g_hndl
)) == NULL
||
12755 (val
= scf_value_create(g_hndl
)) == NULL
)
12758 type
= prop_to_typestr(prop
);
12759 assert(type
!= NULL
);
12761 safe_printf("%-*s %-7s ", len
, name
, type
);
12763 if (prop_has_multiple_values(prop
, val
) &&
12764 (scf_value_type(val
) == SCF_TYPE_ASTRING
||
12765 scf_value_type(val
) == SCF_TYPE_USTRING
))
12766 multiple_strings
= 1;
12768 if (scf_iter_property_values(iter
, prop
) != SCF_SUCCESS
)
12771 while ((ret
= scf_iter_next_value(iter
, val
)) == 1) {
12773 ssize_t vlen
, szret
;
12775 vlen
= scf_value_get_as_string(val
, NULL
, 0);
12779 buf
= safe_malloc(vlen
+ 1);
12781 szret
= scf_value_get_as_string(val
, buf
, vlen
+ 1);
12784 assert(szret
<= vlen
);
12786 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12787 if (multiple_strings
|| strpbrk(buf
, " \t\n\"()") != NULL
) {
12788 safe_printf(" \"");
12789 (void) quote_and_print(buf
, stdout
, 0);
12790 (void) putchar('"');
12791 if (ferror(stdout
)) {
12792 (void) putchar('\n');
12793 uu_die(gettext("Error writing to stdout.\n"));
12796 safe_printf(" %s", buf
);
12801 if (ret
!= 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED
)
12804 if (putchar('\n') != '\n')
12805 uu_die(gettext("Could not output newline"));
12809 * Outputs template property group info for the describe subcommand.
12810 * If 'templates' == 2, verbose output is printed in the format expected
12811 * for describe -v, which includes all templates fields. If pg is
12812 * not NULL, we're describing the template data, not an existing property
12813 * group, and formatting should be appropriate for describe -t.
12816 list_pg_tmpl(scf_pg_tmpl_t
*pgt
, scf_propertygroup_t
*pg
, int templates
)
12820 scf_property_t
*stability_prop
;
12821 scf_value_t
*stability_val
;
12823 if (templates
== 0)
12826 if ((stability_prop
= scf_property_create(g_hndl
)) == NULL
||
12827 (stability_val
= scf_value_create(g_hndl
)) == NULL
)
12830 if (templates
== 2 && pg
!= NULL
) {
12831 if (scf_pg_get_property(pg
, SCF_PROPERTY_STABILITY
,
12832 stability_prop
) == 0) {
12833 if (prop_check_type(stability_prop
,
12834 SCF_TYPE_ASTRING
) == 0 &&
12835 prop_get_val(stability_prop
, stability_val
) == 0) {
12838 stability
= safe_malloc(max_scf_value_len
+ 1);
12840 if (scf_value_get_astring(stability_val
,
12841 stability
, max_scf_value_len
+ 1) == -1 &&
12842 scf_error() != SCF_ERROR_NOT_FOUND
)
12845 safe_printf("%s%s: %s\n", TMPL_INDENT
,
12846 gettext("stability"), stability
);
12850 } else if (scf_error() != SCF_ERROR_NOT_FOUND
)
12854 scf_property_destroy(stability_prop
);
12855 scf_value_destroy(stability_val
);
12860 if (pg
== NULL
|| templates
== 2) {
12861 /* print type info only if scf_tmpl_pg_name succeeds */
12862 if (scf_tmpl_pg_name(pgt
, &buf
) != -1) {
12864 safe_printf("%s", TMPL_INDENT
);
12865 safe_printf("%s: ", gettext("name"));
12866 safe_printf("%s\n", buf
);
12870 /* print type info only if scf_tmpl_pg_type succeeds */
12871 if (scf_tmpl_pg_type(pgt
, &buf
) != -1) {
12873 safe_printf("%s", TMPL_INDENT
);
12874 safe_printf("%s: ", gettext("type"));
12875 safe_printf("%s\n", buf
);
12880 if (templates
== 2 && scf_tmpl_pg_required(pgt
, &required
) == 0)
12881 safe_printf("%s%s: %s\n", TMPL_INDENT
, gettext("required"),
12882 required
? "true" : "false");
12884 if (templates
== 2 && scf_tmpl_pg_target(pgt
, &buf
) > 0) {
12885 safe_printf("%s%s: %s\n", TMPL_INDENT
, gettext("target"),
12890 if (templates
== 2 && scf_tmpl_pg_common_name(pgt
, NULL
, &buf
) > 0) {
12891 safe_printf("%s%s: %s\n", TMPL_INDENT
, gettext("common name"),
12896 if (scf_tmpl_pg_description(pgt
, NULL
, &buf
) > 0) {
12897 if (templates
== 2)
12898 safe_printf("%s%s: %s\n", TMPL_INDENT
,
12899 gettext("description"), buf
);
12901 safe_printf("%s%s\n", TMPL_INDENT
, buf
);
12908 * With as_value set to true, indent as appropriate for the value level.
12909 * If false, indent to appropriate level for inclusion in constraint
12910 * or choice printout.
12913 print_template_value_details(scf_prop_tmpl_t
*prt
, const char *val_buf
,
12918 if (scf_tmpl_value_common_name(prt
, NULL
, val_buf
, &buf
) > 0) {
12920 safe_printf("%s", TMPL_CHOICE_INDENT
);
12922 safe_printf("%s", TMPL_INDENT
);
12923 safe_printf("%s: %s\n", gettext("value common name"), buf
);
12927 if (scf_tmpl_value_description(prt
, NULL
, val_buf
, &buf
) > 0) {
12929 safe_printf("%s", TMPL_CHOICE_INDENT
);
12931 safe_printf("%s", TMPL_INDENT
);
12932 safe_printf("%s: %s\n", gettext("value description"), buf
);
12938 print_template_value(scf_prop_tmpl_t
*prt
, const char *val_buf
)
12940 safe_printf("%s%s: ", TMPL_VALUE_INDENT
, gettext("value"));
12941 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12942 safe_printf("%s\n", val_buf
);
12944 print_template_value_details(prt
, val_buf
, 1);
12948 print_template_constraints(scf_prop_tmpl_t
*prt
, int verbose
)
12950 int i
, printed
= 0;
12951 scf_values_t values
;
12952 scf_count_ranges_t c_ranges
;
12953 scf_int_ranges_t i_ranges
;
12957 if (scf_tmpl_value_name_constraints(prt
, &values
) == 0) {
12958 safe_printf("%s%s:\n", TMPL_VALUE_INDENT
,
12959 gettext("value constraints"));
12961 for (i
= 0; i
< values
.value_count
; ++i
) {
12962 safe_printf("%s%s: %s\n", TMPL_INDENT
,
12963 gettext("value name"), values
.values_as_strings
[i
]);
12965 print_template_value_details(prt
,
12966 values
.values_as_strings
[i
], 0);
12969 scf_values_destroy(&values
);
12972 if (scf_tmpl_value_count_range_constraints(prt
, &c_ranges
) == 0) {
12973 if (printed
++ == 0)
12974 safe_printf("%s%s:\n", TMPL_VALUE_INDENT
,
12975 gettext("value constraints"));
12976 for (i
= 0; i
< c_ranges
.scr_num_ranges
; ++i
) {
12977 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT
,
12978 gettext("range"), c_ranges
.scr_min
[i
],
12979 c_ranges
.scr_max
[i
]);
12981 scf_count_ranges_destroy(&c_ranges
);
12982 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED
&&
12983 scf_tmpl_value_int_range_constraints(prt
, &i_ranges
) == 0) {
12984 if (printed
++ == 0)
12985 safe_printf("%s%s:\n", TMPL_VALUE_INDENT
,
12986 gettext("value constraints"));
12987 for (i
= 0; i
< i_ranges
.sir_num_ranges
; ++i
) {
12988 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT
,
12989 gettext("range"), i_ranges
.sir_min
[i
],
12990 i_ranges
.sir_max
[i
]);
12992 scf_int_ranges_destroy(&i_ranges
);
12997 print_template_choices(scf_prop_tmpl_t
*prt
, int verbose
)
12999 int i
= 0, printed
= 0;
13000 scf_values_t values
;
13001 scf_count_ranges_t c_ranges
;
13002 scf_int_ranges_t i_ranges
;
13005 if (scf_tmpl_value_name_choices(prt
, &values
) == 0) {
13006 safe_printf("%s%s:\n", TMPL_VALUE_INDENT
,
13007 gettext("value constraints"));
13009 for (i
= 0; i
< values
.value_count
; i
++) {
13010 safe_printf("%s%s: %s\n", TMPL_INDENT
,
13011 gettext("value name"), values
.values_as_strings
[i
]);
13013 print_template_value_details(prt
,
13014 values
.values_as_strings
[i
], 0);
13017 scf_values_destroy(&values
);
13020 if (scf_tmpl_value_count_range_choices(prt
, &c_ranges
) == 0) {
13021 for (i
= 0; i
< c_ranges
.scr_num_ranges
; ++i
) {
13022 if (printed
++ == 0)
13023 safe_printf("%s%s:\n", TMPL_VALUE_INDENT
,
13024 gettext("value choices"));
13025 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT
,
13026 gettext("range"), c_ranges
.scr_min
[i
],
13027 c_ranges
.scr_max
[i
]);
13029 scf_count_ranges_destroy(&c_ranges
);
13030 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED
&&
13031 scf_tmpl_value_int_range_choices(prt
, &i_ranges
) == 0) {
13032 for (i
= 0; i
< i_ranges
.sir_num_ranges
; ++i
) {
13033 if (printed
++ == 0)
13034 safe_printf("%s%s:\n", TMPL_VALUE_INDENT
,
13035 gettext("value choices"));
13036 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT
,
13037 gettext("range"), i_ranges
.sir_min
[i
],
13038 i_ranges
.sir_max
[i
]);
13040 scf_int_ranges_destroy(&i_ranges
);
13045 list_values_by_template(scf_prop_tmpl_t
*prt
)
13047 print_template_constraints(prt
, 1);
13048 print_template_choices(prt
, 1);
13052 list_values_tmpl(scf_prop_tmpl_t
*prt
, scf_property_t
*prop
)
13059 if ((iter
= scf_iter_create(g_hndl
)) == NULL
||
13060 (val
= scf_value_create(g_hndl
)) == NULL
)
13063 if (scf_iter_property_values(iter
, prop
) != SCF_SUCCESS
)
13066 val_buf
= safe_malloc(max_scf_value_len
+ 1);
13068 while ((ret
= scf_iter_next_value(iter
, val
)) == 1) {
13069 if (scf_value_get_as_string(val
, val_buf
,
13070 max_scf_value_len
+ 1) < 0)
13073 print_template_value(prt
, val_buf
);
13075 if (ret
!= 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED
)
13079 print_template_constraints(prt
, 0);
13080 print_template_choices(prt
, 0);
13085 * Outputs property info for the describe subcommand
13086 * Verbose output if templates == 2, -v option of svccfg describe
13087 * Displays template data if prop is not NULL, -t option of svccfg describe
13090 list_prop_tmpl(scf_prop_tmpl_t
*prt
, scf_property_t
*prop
, int templates
)
13096 scf_values_t values
;
13098 if (prt
== NULL
|| templates
== 0)
13101 if (prop
== NULL
) {
13102 safe_printf("%s%s: ", TMPL_VALUE_INDENT
, gettext("name"));
13103 if (scf_tmpl_prop_name(prt
, &buf
) > 0) {
13104 safe_printf("%s\n", buf
);
13107 safe_printf("(%s)\n", gettext("any"));
13110 if (prop
== NULL
|| templates
== 2) {
13112 safe_printf("%s", TMPL_INDENT
);
13114 safe_printf("%s", TMPL_VALUE_INDENT
);
13115 safe_printf("%s: ", gettext("type"));
13116 if ((buf
= _scf_read_tmpl_prop_type_as_string(prt
)) != NULL
) {
13117 safe_printf("%s\n", buf
);
13120 safe_printf("(%s)\n", gettext("any"));
13123 if (templates
== 2 && scf_tmpl_prop_required(prt
, &u_buf
) == 0)
13124 safe_printf("%s%s: %s\n", TMPL_INDENT
, gettext("required"),
13125 u_buf
? "true" : "false");
13127 if (templates
== 2 && scf_tmpl_prop_common_name(prt
, NULL
, &buf
) > 0) {
13128 safe_printf("%s%s: %s\n", TMPL_INDENT
, gettext("common name"),
13133 if (templates
== 2 && scf_tmpl_prop_units(prt
, NULL
, &buf
) > 0) {
13134 safe_printf("%s%s: %s\n", TMPL_INDENT
, gettext("units"),
13139 if (scf_tmpl_prop_description(prt
, NULL
, &buf
) > 0) {
13140 safe_printf("%s%s\n", TMPL_INDENT
, buf
);
13144 if (templates
== 2 && scf_tmpl_prop_visibility(prt
, &u_buf
) == 0)
13145 safe_printf("%s%s: %s\n", TMPL_INDENT
, gettext("visibility"),
13146 scf_tmpl_visibility_to_string(u_buf
));
13148 if (templates
== 2 && scf_tmpl_prop_cardinality(prt
, &min
, &max
) == 0) {
13149 safe_printf("%s%s: %" PRIu64
"\n", TMPL_INDENT
,
13150 gettext("minimum number of values"), min
);
13151 if (max
== ULLONG_MAX
) {
13152 safe_printf("%s%s: %s\n", TMPL_INDENT
,
13153 gettext("maximum number of values"),
13154 gettext("unlimited"));
13156 safe_printf("%s%s: %" PRIu64
"\n", TMPL_INDENT
,
13157 gettext("maximum number of values"), max
);
13161 if (templates
== 2 && scf_tmpl_prop_internal_seps(prt
, &values
) == 0) {
13162 for (i
= 0; i
< values
.value_count
; i
++) {
13164 safe_printf("%s%s:", TMPL_INDENT
,
13165 gettext("internal separators"));
13167 safe_printf(" \"%s\"", values
.values_as_strings
[i
]);
13172 if (templates
!= 2)
13176 list_values_tmpl(prt
, prop
);
13178 list_values_by_template(prt
);
13182 read_astring(scf_propertygroup_t
*pg
, const char *prop_name
)
13186 rv
= _scf_read_single_astring_from_pg(pg
, prop_name
);
13188 switch (scf_error()) {
13189 case SCF_ERROR_NOT_FOUND
:
13199 display_documentation(scf_iter_t
*iter
, scf_propertygroup_t
*pg
)
13207 doc_len
= strlen(SCF_PG_TM_DOC_PREFIX
);
13208 man_len
= strlen(SCF_PG_TM_MAN_PREFIX
);
13209 pg_name
= safe_malloc(max_scf_name_len
+ 1);
13210 while ((rv
= scf_iter_next_pg(iter
, pg
)) == 1) {
13211 if (scf_pg_get_name(pg
, pg_name
, max_scf_name_len
+ 1) == -1) {
13214 if (strncmp(pg_name
, SCF_PG_TM_DOC_PREFIX
, doc_len
) == 0) {
13215 /* Display doc_link and and uri */
13216 safe_printf("%s%s:\n", TMPL_INDENT
,
13217 gettext("doc_link"));
13218 text
= read_astring(pg
, SCF_PROPERTY_TM_NAME
);
13219 if (text
!= NULL
) {
13220 safe_printf("%s%s%s: %s\n", TMPL_INDENT
,
13221 TMPL_INDENT
, gettext("name"), text
);
13224 text
= read_astring(pg
, SCF_PROPERTY_TM_URI
);
13225 if (text
!= NULL
) {
13226 safe_printf("%s%s: %s\n", TMPL_INDENT_2X
,
13227 gettext("uri"), text
);
13230 } else if (strncmp(pg_name
, SCF_PG_TM_MAN_PREFIX
,
13232 /* Display manpage title, section and path */
13233 safe_printf("%s%s:\n", TMPL_INDENT
,
13234 gettext("manpage"));
13235 text
= read_astring(pg
, SCF_PROPERTY_TM_TITLE
);
13236 if (text
!= NULL
) {
13237 safe_printf("%s%s%s: %s\n", TMPL_INDENT
,
13238 TMPL_INDENT
, gettext("title"), text
);
13241 text
= read_astring(pg
, SCF_PROPERTY_TM_SECTION
);
13242 if (text
!= NULL
) {
13243 safe_printf("%s%s%s: %s\n", TMPL_INDENT
,
13244 TMPL_INDENT
, gettext("section"), text
);
13247 text
= read_astring(pg
, SCF_PROPERTY_TM_MANPATH
);
13248 if (text
!= NULL
) {
13249 safe_printf("%s%s%s: %s\n", TMPL_INDENT
,
13250 TMPL_INDENT
, gettext("manpath"), text
);
13263 list_entity_tmpl(int templates
)
13265 char *common_name
= NULL
;
13266 char *description
= NULL
;
13267 char *locale
= NULL
;
13269 scf_propertygroup_t
*pg
;
13270 scf_property_t
*prop
;
13274 if ((pg
= scf_pg_create(g_hndl
)) == NULL
||
13275 (prop
= scf_property_create(g_hndl
)) == NULL
||
13276 (val
= scf_value_create(g_hndl
)) == NULL
||
13277 (iter
= scf_iter_create(g_hndl
)) == NULL
)
13280 locale
= setlocale(LC_MESSAGES
, NULL
);
13282 if (get_pg(SCF_PG_TM_COMMON_NAME
, pg
) == 0) {
13283 common_name
= safe_malloc(max_scf_value_len
+ 1);
13285 /* Try both the current locale and the "C" locale. */
13286 if (scf_pg_get_property(pg
, locale
, prop
) == 0 ||
13287 (scf_error() == SCF_ERROR_NOT_FOUND
&&
13288 scf_pg_get_property(pg
, "C", prop
) == 0)) {
13289 if (prop_get_val(prop
, val
) == 0 &&
13290 scf_value_get_ustring(val
, common_name
,
13291 max_scf_value_len
+ 1) != -1) {
13292 safe_printf("%s%s: %s\n", TMPL_INDENT
,
13293 gettext("common name"), common_name
);
13299 * Do description, manpages, and doc links if templates == 2.
13301 if (templates
== 2) {
13302 /* Get the description. */
13303 if (get_pg(SCF_PG_TM_DESCRIPTION
, pg
) == 0) {
13304 description
= safe_malloc(max_scf_value_len
+ 1);
13306 /* Try both the current locale and the "C" locale. */
13307 if (scf_pg_get_property(pg
, locale
, prop
) == 0 ||
13308 (scf_error() == SCF_ERROR_NOT_FOUND
&&
13309 scf_pg_get_property(pg
, "C", prop
) == 0)) {
13310 if (prop_get_val(prop
, val
) == 0 &&
13311 scf_value_get_ustring(val
, description
,
13312 max_scf_value_len
+ 1) != -1) {
13313 safe_printf("%s%s: %s\n", TMPL_INDENT
,
13314 gettext("description"),
13320 /* Process doc_link & manpage elements. */
13321 if (cur_level
!= NULL
) {
13322 r
= scf_iter_snaplevel_pgs_typed(iter
, cur_level
,
13323 SCF_GROUP_TEMPLATE
);
13324 } else if (cur_inst
!= NULL
) {
13325 r
= scf_iter_instance_pgs_typed(iter
, cur_inst
,
13326 SCF_GROUP_TEMPLATE
);
13328 r
= scf_iter_service_pgs_typed(iter
, cur_svc
,
13329 SCF_GROUP_TEMPLATE
);
13332 display_documentation(iter
, pg
);
13338 scf_pg_destroy(pg
);
13339 scf_property_destroy(prop
);
13340 scf_value_destroy(val
);
13341 scf_iter_destroy(iter
);
13345 listtmpl(const char *pattern
, int templates
)
13347 scf_pg_tmpl_t
*pgt
;
13348 scf_prop_tmpl_t
*prt
;
13349 char *snapbuf
= NULL
;
13351 char *pg_name
= NULL
, *prop_name
= NULL
;
13352 ssize_t prop_name_size
;
13353 char *qual_prop_name
;
13357 if ((pgt
= scf_tmpl_pg_create(g_hndl
)) == NULL
||
13358 (prt
= scf_tmpl_prop_create(g_hndl
)) == NULL
)
13361 fmribuf
= safe_malloc(max_scf_name_len
+ 1);
13362 qual_prop_name
= safe_malloc(max_scf_name_len
+ 1);
13364 if (cur_snap
!= NULL
) {
13365 snapbuf
= safe_malloc(max_scf_name_len
+ 1);
13366 if (scf_snapshot_get_name(cur_snap
, snapbuf
,
13367 max_scf_name_len
+ 1) < 0)
13371 if (cur_inst
!= NULL
) {
13372 if (scf_instance_to_fmri(cur_inst
, fmribuf
,
13373 max_scf_name_len
+ 1) < 0)
13375 } else if (cur_svc
!= NULL
) {
13376 if (scf_service_to_fmri(cur_svc
, fmribuf
,
13377 max_scf_name_len
+ 1) < 0)
13382 /* If pattern is specified, we want to list only those items. */
13383 while (scf_tmpl_iter_pgs(pgt
, fmribuf
, snapbuf
, NULL
, 0) == 1) {
13385 if (pattern
== NULL
|| (scf_tmpl_pg_name(pgt
, &pg_name
) > 0 &&
13386 fnmatch(pattern
, pg_name
, 0) == 0)) {
13387 list_pg_tmpl(pgt
, NULL
, templates
);
13391 scf_tmpl_prop_reset(prt
);
13393 while (scf_tmpl_iter_props(pgt
, prt
, 0) == 0) {
13394 search_name
= NULL
;
13395 prop_name_size
= scf_tmpl_prop_name(prt
, &prop_name
);
13396 if ((prop_name_size
> 0) && (pg_name
!= NULL
)) {
13397 if (snprintf(qual_prop_name
,
13398 max_scf_name_len
+ 1, "%s/%s",
13399 pg_name
, prop_name
) >=
13400 max_scf_name_len
+ 1) {
13401 prop_name_size
= -1;
13403 search_name
= qual_prop_name
;
13406 if (listed
> 0 || pattern
== NULL
||
13407 (prop_name_size
> 0 &&
13408 fnmatch(pattern
, search_name
,
13409 FNM_PATHNAME
) == 0))
13410 list_prop_tmpl(prt
, NULL
, templates
);
13411 if (prop_name
!= NULL
) {
13416 if (pg_name
!= NULL
) {
13422 scf_tmpl_prop_destroy(prt
);
13423 scf_tmpl_pg_destroy(pgt
);
13426 free(qual_prop_name
);
13430 listprop(const char *pattern
, int only_pgs
, int templates
)
13432 scf_propertygroup_t
*pg
;
13433 scf_property_t
*prop
;
13434 scf_iter_t
*iter
, *piter
;
13435 char *pgnbuf
, *prnbuf
, *ppnbuf
;
13436 scf_pg_tmpl_t
*pgt
, *pgtp
;
13437 scf_prop_tmpl_t
*prt
;
13445 ssize_t pgnlen
, prnlen
, szret
;
13446 size_t max_len
= 0;
13448 if (cur_svc
== NULL
&& cur_inst
== NULL
) {
13449 semerr(emsg_entity_not_selected
);
13453 if ((pg
= scf_pg_create(g_hndl
)) == NULL
||
13454 (prop
= scf_property_create(g_hndl
)) == NULL
||
13455 (iter
= scf_iter_create(g_hndl
)) == NULL
||
13456 (piter
= scf_iter_create(g_hndl
)) == NULL
||
13457 (prt
= scf_tmpl_prop_create(g_hndl
)) == NULL
||
13458 (pgt
= scf_tmpl_pg_create(g_hndl
)) == NULL
)
13461 prnbuf
= safe_malloc(max_scf_name_len
+ 1);
13463 if (cur_level
!= NULL
)
13464 ret
= scf_iter_snaplevel_pgs(iter
, cur_level
);
13465 else if (cur_inst
!= NULL
)
13466 ret
= scf_iter_instance_pgs(iter
, cur_inst
);
13468 ret
= scf_iter_service_pgs(iter
, cur_svc
);
13474 * We want to only list items which match pattern, and we want the
13475 * second column to line up, so during the first pass we'll save
13476 * matching items, their names, and their templates in objects,
13477 * names, and tmpls, computing the maximum name length as we go,
13478 * and then we'll print them out.
13480 * Note: We always keep an extra slot available so the array can be
13485 objects
= safe_malloc(sizeof (*objects
));
13486 names
= safe_malloc(sizeof (*names
));
13487 tmpls
= safe_malloc(sizeof (*tmpls
));
13489 while ((ret
= scf_iter_next_pg(iter
, pg
)) == 1) {
13491 int print_props
= 0;
13494 pgnlen
= scf_pg_get_name(pg
, NULL
, 0);
13498 pgnbuf
= safe_malloc(pgnlen
+ 1);
13500 szret
= scf_pg_get_name(pg
, pgnbuf
, pgnlen
+ 1);
13503 assert(szret
<= pgnlen
);
13505 if (scf_tmpl_get_by_pg(pg
, pgt
, 0) == -1) {
13506 if (scf_error() != SCF_ERROR_NOT_FOUND
)
13513 if (pattern
== NULL
||
13514 fnmatch(pattern
, pgnbuf
, 0) == 0) {
13515 if (i
+1 >= allocd
) {
13517 objects
= reallocarray(objects
, allocd
,
13518 sizeof (*objects
));
13520 reallocarray(names
, allocd
,
13522 tmpls
= reallocarray(tmpls
, allocd
,
13524 if (objects
== NULL
|| names
== NULL
||
13526 uu_die(gettext("Out of memory"));
13538 if (pgnlen
> max_len
)
13547 pg
= scf_pg_create(g_hndl
);
13550 pgt
= scf_tmpl_pg_create(g_hndl
);
13559 if (scf_iter_pg_properties(piter
, pg
) != SCF_SUCCESS
)
13562 while ((ret
= scf_iter_next_property(piter
, prop
)) == 1) {
13563 prnlen
= scf_property_get_name(prop
, prnbuf
,
13564 max_scf_name_len
+ 1);
13568 /* Will prepend the property group name and a slash. */
13569 prnlen
+= pgnlen
+ 1;
13571 ppnbuf
= safe_malloc(prnlen
+ 1);
13573 if (snprintf(ppnbuf
, prnlen
+ 1, "%s/%s", pgnbuf
,
13575 uu_die("snprintf");
13577 if (pattern
== NULL
|| print_props
== 1 ||
13578 fnmatch(pattern
, ppnbuf
, 0) == 0) {
13579 if (i
+1 >= allocd
) {
13581 objects
= reallocarray(objects
,
13582 allocd
, sizeof (*objects
));
13583 names
= reallocarray(names
, allocd
,
13585 tmpls
= reallocarray(tmpls
, allocd
,
13587 if (objects
== NULL
|| names
== NULL
||
13596 if (pgtp
!= NULL
) {
13597 if (scf_tmpl_get_by_prop(pgt
, prnbuf
,
13600 SCF_ERROR_NOT_FOUND
)
13612 if (prnlen
> max_len
)
13615 prop
= scf_property_create(g_hndl
);
13616 prt
= scf_tmpl_prop_create(g_hndl
);
13623 pg
= scf_pg_create(g_hndl
);
13626 pgt
= scf_tmpl_pg_create(g_hndl
);
13637 scf_pg_destroy(pg
);
13638 scf_tmpl_pg_destroy(pgt
);
13639 scf_property_destroy(prop
);
13640 scf_tmpl_prop_destroy(prt
);
13642 for (i
= 0; objects
[i
] != NULL
; ++i
) {
13643 if (strchr(names
[i
], '/') == NULL
) {
13644 /* property group */
13645 pg
= (scf_propertygroup_t
*)objects
[i
];
13646 pgt
= (scf_pg_tmpl_t
*)tmpls
[i
];
13647 list_pg_info(pg
, names
[i
], max_len
);
13648 list_pg_tmpl(pgt
, pg
, templates
);
13650 scf_pg_destroy(pg
);
13652 scf_tmpl_pg_destroy(pgt
);
13655 prop
= (scf_property_t
*)objects
[i
];
13656 prt
= (scf_prop_tmpl_t
*)tmpls
[i
];
13657 list_prop_info(prop
, names
[i
], max_len
);
13658 list_prop_tmpl(prt
, prop
, templates
);
13660 scf_property_destroy(prop
);
13662 scf_tmpl_prop_destroy(prt
);
13672 lscf_listpg(const char *pattern
)
13676 listprop(pattern
, 1, 0);
13680 * Property group and property creation, setting, and deletion. setprop (and
13681 * its alias, addprop) can either create a property group of a given type, or
13682 * it can create or set a property to a given type and list of values.
13685 lscf_addpg(const char *name
, const char *type
, const char *flags
)
13687 scf_propertygroup_t
*pg
;
13695 if (cur_snap
!= NULL
) {
13696 semerr(emsg_cant_modify_snapshots
);
13700 if (cur_inst
== NULL
&& cur_svc
== NULL
) {
13701 semerr(emsg_entity_not_selected
);
13705 if (flags
!= NULL
) {
13706 for (cp
= flags
; *cp
!= '\0'; ++cp
) {
13709 flgs
|= SCF_PG_FLAG_NONPERSISTENT
;
13713 flgs
&= ~SCF_PG_FLAG_NONPERSISTENT
;
13717 semerr(gettext("Invalid property group flag "
13724 pg
= scf_pg_create(g_hndl
);
13728 if (cur_inst
!= NULL
)
13729 ret
= scf_instance_add_pg(cur_inst
, name
, type
, flgs
, pg
);
13731 ret
= scf_service_add_pg(cur_svc
, name
, type
, flgs
, pg
);
13733 if (ret
!= SCF_SUCCESS
) {
13734 switch (scf_error()) {
13735 case SCF_ERROR_INVALID_ARGUMENT
:
13736 semerr(gettext("Name, type, or flags are invalid.\n"));
13739 case SCF_ERROR_EXISTS
:
13740 semerr(gettext("Property group already exists.\n"));
13743 case SCF_ERROR_PERMISSION_DENIED
:
13744 semerr(emsg_permission_denied
);
13747 case SCF_ERROR_BACKEND_ACCESS
:
13748 semerr(gettext("Backend refused access.\n"));
13756 scf_pg_destroy(pg
);
13762 lscf_delpg(char *name
)
13766 if (cur_snap
!= NULL
) {
13767 semerr(emsg_cant_modify_snapshots
);
13771 if (cur_inst
== NULL
&& cur_svc
== NULL
) {
13772 semerr(emsg_entity_not_selected
);
13776 if (strchr(name
, '/') != NULL
) {
13777 semerr(emsg_invalid_pg_name
, name
);
13781 lscf_delprop(name
);
13785 * scf_delhash() is used to remove the property group related to the
13786 * hash entry for a specific manifest in the repository. pgname will be
13787 * constructed from the location of the manifest file. If deathrow isn't 0,
13788 * manifest file doesn't need to exist (manifest string will be used as
13789 * an absolute path).
13792 lscf_delhash(char *manifest
, int deathrow
)
13796 if (cur_snap
!= NULL
||
13797 cur_inst
!= NULL
|| cur_svc
!= NULL
) {
13798 warn(gettext("error, an entity is selected\n"));
13802 /* select smf/manifest */
13803 lscf_select(HASH_SVC
);
13805 * Translate the manifest file name to property name. In the deathrow
13806 * case, the manifest file does not need to exist.
13808 pgname
= mhash_filename_to_propname(manifest
,
13809 deathrow
? B_TRUE
: B_FALSE
);
13810 if (pgname
== NULL
) {
13811 warn(gettext("cannot resolve pathname for %s\n"), manifest
);
13814 /* delete the hash property name */
13815 lscf_delpg(pgname
);
13819 lscf_listprop(const char *pattern
)
13823 listprop(pattern
, 0, 0);
13827 lscf_setprop(const char *pgname
, const char *type
, const char *value
,
13828 const uu_list_t
*values
)
13830 scf_type_t ty
= SCF_TYPE_INVALID
, current_ty
;
13831 scf_service_t
*svc
;
13832 scf_propertygroup_t
*pg
, *parent_pg
;
13833 scf_property_t
*prop
, *parent_prop
;
13834 scf_pg_tmpl_t
*pgt
;
13835 scf_prop_tmpl_t
*prt
;
13836 int ret
, result
= 0;
13837 scf_transaction_t
*tx
;
13838 scf_transaction_entry_t
*e
;
13840 uu_list_walk_t
*walk
;
13843 int req_quotes
= 0;
13847 if ((e
= scf_entry_create(g_hndl
)) == NULL
||
13848 (svc
= scf_service_create(g_hndl
)) == NULL
||
13849 (parent_pg
= scf_pg_create(g_hndl
)) == NULL
||
13850 (pg
= scf_pg_create(g_hndl
)) == NULL
||
13851 (parent_prop
= scf_property_create(g_hndl
)) == NULL
||
13852 (prop
= scf_property_create(g_hndl
)) == NULL
||
13853 (pgt
= scf_tmpl_pg_create(g_hndl
)) == NULL
||
13854 (prt
= scf_tmpl_prop_create(g_hndl
)) == NULL
||
13855 (tx
= scf_transaction_create(g_hndl
)) == NULL
)
13858 if (cur_snap
!= NULL
) {
13859 semerr(emsg_cant_modify_snapshots
);
13863 if (cur_inst
== NULL
&& cur_svc
== NULL
) {
13864 semerr(emsg_entity_not_selected
);
13868 propname
= strchr(pgname
, '/');
13869 if (propname
== NULL
) {
13870 semerr(gettext("Property names must contain a `/'.\n"));
13877 if (type
!= NULL
) {
13878 ty
= string_to_type(type
);
13879 if (ty
== SCF_TYPE_INVALID
) {
13880 semerr(gettext("Unknown type \"%s\".\n"), type
);
13885 if (cur_inst
!= NULL
)
13886 ret
= scf_instance_get_pg(cur_inst
, pgname
, pg
);
13888 ret
= scf_service_get_pg(cur_svc
, pgname
, pg
);
13889 if (ret
!= SCF_SUCCESS
) {
13890 switch (scf_error()) {
13891 case SCF_ERROR_NOT_FOUND
:
13892 semerr(emsg_no_such_pg
, pgname
);
13895 case SCF_ERROR_INVALID_ARGUMENT
:
13896 semerr(emsg_invalid_pg_name
, pgname
);
13906 if (scf_pg_update(pg
) == -1)
13908 if (scf_transaction_start(tx
, pg
) != SCF_SUCCESS
) {
13909 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
13912 semerr(emsg_permission_denied
);
13916 ret
= scf_pg_get_property(pg
, propname
, prop
);
13917 if (ret
== SCF_SUCCESS
) {
13918 if (scf_property_type(prop
, ¤t_ty
) != SCF_SUCCESS
)
13923 if (scf_transaction_property_change_type(tx
, e
,
13924 propname
, ty
) == -1)
13927 } else if (scf_error() == SCF_ERROR_NOT_FOUND
) {
13928 /* Infer the type, if possible. */
13929 if (type
== NULL
) {
13931 * First check if we're an instance and the
13932 * property is set on the service.
13934 if (cur_inst
!= NULL
&&
13935 scf_instance_get_parent(cur_inst
,
13937 scf_service_get_pg(cur_svc
, pgname
,
13939 scf_pg_get_property(parent_pg
, propname
,
13940 parent_prop
) == 0 &&
13941 scf_property_type(parent_prop
,
13942 ¤t_ty
) == 0) {
13945 /* Then check for a type set in a template. */
13946 } else if (scf_tmpl_get_by_pg(pg
, pgt
,
13948 scf_tmpl_get_by_prop(pgt
, propname
, prt
,
13950 scf_tmpl_prop_type(prt
, ¤t_ty
) == 0) {
13953 /* If type can't be inferred, fail. */
13955 semerr(gettext("Type required for new "
13960 if (scf_transaction_property_new(tx
, e
, propname
,
13963 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT
) {
13964 semerr(emsg_invalid_prop_name
, propname
);
13970 if (ty
== SCF_TYPE_ASTRING
|| ty
== SCF_TYPE_USTRING
)
13973 if (value
!= NULL
) {
13974 v
= string_to_value(value
, ty
, 0);
13979 ret
= scf_entry_add_value(e
, v
);
13980 assert(ret
== SCF_SUCCESS
);
13982 assert(values
!= NULL
);
13984 walk
= uu_list_walk_start((uu_list_t
*)values
,
13987 uu_die(gettext("Could not walk list"));
13989 for (sp
= uu_list_walk_next(walk
); sp
!= NULL
;
13990 sp
= uu_list_walk_next(walk
)) {
13991 v
= string_to_value(sp
->str
, ty
, req_quotes
);
13994 scf_entry_destroy_children(e
);
13998 ret
= scf_entry_add_value(e
, v
);
13999 assert(ret
== SCF_SUCCESS
);
14001 uu_list_walk_end(walk
);
14003 result
= scf_transaction_commit(tx
);
14005 scf_transaction_reset(tx
);
14006 scf_entry_destroy_children(e
);
14007 } while (result
== 0);
14010 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
14013 semerr(emsg_permission_denied
);
14027 scf_transaction_destroy(tx
);
14028 scf_entry_destroy(e
);
14029 scf_service_destroy(svc
);
14030 scf_pg_destroy(parent_pg
);
14031 scf_pg_destroy(pg
);
14032 scf_property_destroy(parent_prop
);
14033 scf_property_destroy(prop
);
14034 scf_tmpl_pg_destroy(pgt
);
14035 scf_tmpl_prop_destroy(prt
);
14041 lscf_delprop(char *pgn
)
14044 scf_propertygroup_t
*pg
;
14045 scf_transaction_t
*tx
;
14046 scf_transaction_entry_t
*e
;
14052 if (cur_snap
!= NULL
) {
14053 semerr(emsg_cant_modify_snapshots
);
14057 if (cur_inst
== NULL
&& cur_svc
== NULL
) {
14058 semerr(emsg_entity_not_selected
);
14062 pg
= scf_pg_create(g_hndl
);
14066 slash
= strchr(pgn
, '/');
14067 if (slash
== NULL
) {
14074 if (cur_inst
!= NULL
)
14075 ret
= scf_instance_get_pg(cur_inst
, pgn
, pg
);
14077 ret
= scf_service_get_pg(cur_svc
, pgn
, pg
);
14078 if (ret
!= SCF_SUCCESS
) {
14079 switch (scf_error()) {
14080 case SCF_ERROR_NOT_FOUND
:
14081 semerr(emsg_no_such_pg
, pgn
);
14084 case SCF_ERROR_INVALID_ARGUMENT
:
14085 semerr(emsg_invalid_pg_name
, pgn
);
14092 scf_pg_destroy(pg
);
14098 /* Try to delete the property group. */
14099 if (scf_pg_delete(pg
) != SCF_SUCCESS
) {
14100 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
14103 semerr(emsg_permission_denied
);
14108 scf_pg_destroy(pg
);
14112 e
= scf_entry_create(g_hndl
);
14113 tx
= scf_transaction_create(g_hndl
);
14116 if (scf_pg_update(pg
) == -1)
14118 if (scf_transaction_start(tx
, pg
) != SCF_SUCCESS
) {
14119 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
14122 semerr(emsg_permission_denied
);
14126 if (scf_transaction_property_delete(tx
, e
, pn
) != SCF_SUCCESS
) {
14127 if (scf_error() == SCF_ERROR_NOT_FOUND
) {
14128 semerr(gettext("No such property %s/%s.\n"),
14131 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT
) {
14132 semerr(emsg_invalid_prop_name
, pn
);
14139 ret
= scf_transaction_commit(tx
);
14142 scf_transaction_reset(tx
);
14143 } while (ret
== 0);
14146 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
14149 semerr(emsg_permission_denied
);
14154 scf_transaction_destroy(tx
);
14155 scf_entry_destroy(e
);
14156 scf_pg_destroy(pg
);
14160 * Property editing.
14164 write_edit_script(FILE *strm
)
14169 scf_propertygroup_t
*pg
;
14170 scf_property_t
*prop
;
14173 int ret
, result
= 0;
14174 scf_iter_t
*iter
, *piter
, *viter
;
14175 char *buf
, *tybuf
, *pname
;
14176 const char *emsg_write_error
;
14179 emsg_write_error
= gettext("Error writing temoprary file: %s.\n");
14183 if (cur_inst
!= NULL
) {
14184 fmrilen
= scf_instance_to_fmri(cur_inst
, NULL
, 0);
14187 fmribuf
= safe_malloc(fmrilen
+ 1);
14188 if (scf_instance_to_fmri(cur_inst
, fmribuf
, fmrilen
+ 1) < 0)
14191 assert(cur_svc
!= NULL
);
14192 fmrilen
= scf_service_to_fmri(cur_svc
, NULL
, 0);
14195 fmribuf
= safe_malloc(fmrilen
+ 1);
14196 if (scf_service_to_fmri(cur_svc
, fmribuf
, fmrilen
+ 1) < 0)
14200 if (fprintf(strm
, "select %s\n\n", fmribuf
) < 0) {
14201 warn(emsg_write_error
, strerror(errno
));
14209 if ((pg
= scf_pg_create(g_hndl
)) == NULL
||
14210 (prop
= scf_property_create(g_hndl
)) == NULL
||
14211 (val
= scf_value_create(g_hndl
)) == NULL
||
14212 (iter
= scf_iter_create(g_hndl
)) == NULL
||
14213 (piter
= scf_iter_create(g_hndl
)) == NULL
||
14214 (viter
= scf_iter_create(g_hndl
)) == NULL
)
14217 buf
= safe_malloc(max_scf_name_len
+ 1);
14218 tybuf
= safe_malloc(max_scf_pg_type_len
+ 1);
14219 pname
= safe_malloc(max_scf_name_len
+ 1);
14221 if (cur_inst
!= NULL
)
14222 ret
= scf_iter_instance_pgs(iter
, cur_inst
);
14224 ret
= scf_iter_service_pgs(iter
, cur_svc
);
14225 if (ret
!= SCF_SUCCESS
)
14228 while ((ret
= scf_iter_next_pg(iter
, pg
)) == 1) {
14235 if (scf_pg_get_name(pg
, buf
, max_scf_name_len
+ 1) < 0)
14238 if (scf_pg_get_type(pg
, tybuf
, max_scf_pg_type_len
+ 1) < 0)
14241 if (fprintf(strm
, "# Property group \"%s\"\n"
14243 "# addpg %s %s\n", buf
, buf
, buf
, tybuf
) < 0) {
14244 warn(emsg_write_error
, strerror(errno
));
14249 /* # setprop pg/prop = (values) */
14251 if (scf_iter_pg_properties(piter
, pg
) != SCF_SUCCESS
)
14254 while ((ret2
= scf_iter_next_property(piter
, prop
)) == 1) {
14261 if (scf_property_get_name(prop
, pname
,
14262 max_scf_name_len
+ 1) < 0)
14265 if (scf_property_type(prop
, &ty
) != 0)
14268 multiple
= prop_has_multiple_values(prop
, val
);
14270 if (fprintf(strm
, "# setprop %s/%s = %s: %s", buf
,
14271 pname
, scf_type_to_string(ty
), multiple
? "(" : "")
14273 warn(emsg_write_error
, strerror(errno
));
14278 (void) scf_type_base_type(ty
, &bty
);
14279 is_str
= (bty
== SCF_TYPE_ASTRING
);
14281 if (scf_iter_property_values(viter
, prop
) !=
14285 while ((ret3
= scf_iter_next_value(viter
, val
)) == 1) {
14289 buflen
= scf_value_get_as_string(val
, NULL
, 0);
14293 buf
= safe_malloc(buflen
+ 1);
14295 if (scf_value_get_as_string(val
, buf
,
14302 if (putc(' ', strm
) != ' ') {
14303 warn(emsg_write_error
,
14310 if ((is_str
&& multiple
) ||
14311 strpbrk(buf
, CHARS_TO_QUOTE
) != NULL
) {
14312 (void) putc('"', strm
);
14313 (void) quote_and_print(buf
, strm
, 1);
14314 (void) putc('"', strm
);
14316 if (ferror(strm
)) {
14317 warn(emsg_write_error
,
14323 if (fprintf(strm
, "%s", buf
) < 0) {
14324 warn(emsg_write_error
,
14334 scf_error() != SCF_ERROR_PERMISSION_DENIED
)
14337 /* Write closing paren if mult-value property */
14338 if ((multiple
&& putc(')', strm
) == EOF
) ||
14340 /* Write final newline */
14341 fputc('\n', strm
) == EOF
) {
14342 warn(emsg_write_error
, strerror(errno
));
14350 if (fputc('\n', strm
) == EOF
) {
14351 warn(emsg_write_error
, strerror(errno
));
14363 scf_iter_destroy(viter
);
14364 scf_iter_destroy(piter
);
14365 scf_iter_destroy(iter
);
14366 scf_value_destroy(val
);
14367 scf_property_destroy(prop
);
14368 scf_pg_destroy(pg
);
14371 if (fflush(strm
) != 0) {
14372 warn(emsg_write_error
, strerror(errno
));
14383 char *buf
, *editor
;
14386 char tempname
[] = TEMP_FILE_PATTERN
;
14390 if (cur_snap
!= NULL
) {
14391 semerr(emsg_cant_modify_snapshots
);
14395 if (cur_svc
== NULL
&& cur_inst
== NULL
) {
14396 semerr(emsg_entity_not_selected
);
14400 tmpfd
= mkstemp(tempname
);
14402 semerr(gettext("Could not create temporary file.\n"));
14406 (void) strcpy(tempfilename
, tempname
);
14408 tempfile
= fdopen(tmpfd
, "r+");
14409 if (tempfile
== NULL
) {
14410 warn(gettext("Could not create temporary file.\n"));
14411 if (close(tmpfd
) == -1)
14412 warn(gettext("Could not close temporary file: %s.\n"),
14420 if (write_edit_script(tempfile
) == -1) {
14425 editor
= getenv("EDITOR");
14426 if (editor
== NULL
)
14429 bufsz
= strlen(editor
) + 1 + strlen(tempname
) + 1;
14430 buf
= safe_malloc(bufsz
);
14432 if (snprintf(buf
, bufsz
, "%s %s", editor
, tempname
) < 0)
14433 uu_die(gettext("Error creating editor command"));
14435 if (system(buf
) == -1) {
14436 semerr(gettext("Could not launch editor %s: %s\n"), editor
,
14445 (void) engine_source(tempname
, est
->sc_cmd_flags
& SC_CMD_IACTIVE
);
14453 add_string(uu_list_t
*strlist
, const char *str
)
14455 string_list_t
*elem
;
14456 elem
= safe_malloc(sizeof (*elem
));
14457 uu_list_node_init(elem
, &elem
->node
, string_pool
);
14458 elem
->str
= safe_strdup(str
);
14459 if (uu_list_append(strlist
, elem
) != 0)
14460 uu_die(gettext("libuutil error: %s\n"),
14461 uu_strerror(uu_error()));
14465 remove_string(uu_list_t
*strlist
, const char *str
)
14467 uu_list_walk_t
*elems
;
14471 * Find the element that needs to be removed.
14473 elems
= uu_list_walk_start(strlist
, UU_DEFAULT
);
14474 while ((sp
= uu_list_walk_next(elems
)) != NULL
) {
14475 if (strcmp(sp
->str
, str
) == 0)
14478 uu_list_walk_end(elems
);
14481 * Returning 1 here as the value was not found, this
14482 * might not be an error. Leave it to the caller to
14489 uu_list_remove(strlist
, sp
);
14498 * Get all property values that don't match the given glob pattern,
14499 * if a pattern is specified.
14502 get_prop_values(scf_property_t
*prop
, uu_list_t
*values
,
14503 const char *pattern
)
14509 if ((iter
= scf_iter_create(g_hndl
)) == NULL
||
14510 (val
= scf_value_create(g_hndl
)) == NULL
)
14513 if (scf_iter_property_values(iter
, prop
) != 0)
14516 while ((ret
= scf_iter_next_value(iter
, val
)) == 1) {
14518 ssize_t vlen
, szret
;
14520 vlen
= scf_value_get_as_string(val
, NULL
, 0);
14524 buf
= safe_malloc(vlen
+ 1);
14526 szret
= scf_value_get_as_string(val
, buf
, vlen
+ 1);
14529 assert(szret
<= vlen
);
14531 if (pattern
== NULL
|| fnmatch(pattern
, buf
, 0) != 0)
14532 add_string(values
, buf
);
14540 scf_value_destroy(val
);
14541 scf_iter_destroy(iter
);
14545 lscf_setpropvalue(const char *pgname
, const char *type
,
14546 const char *arg
, int isadd
, int isnotfoundok
)
14548 scf_type_t ty
= SCF_TYPE_INVALID
;
14549 scf_propertygroup_t
*pg
;
14550 scf_property_t
*prop
;
14551 int ret
, result
= 0;
14552 scf_transaction_t
*tx
;
14553 scf_transaction_entry_t
*e
;
14558 uu_list_walk_t
*walk
;
14559 void *cookie
= NULL
;
14560 char *pattern
= NULL
;
14564 if ((values
= uu_list_create(string_pool
, NULL
, 0)) == NULL
)
14565 uu_die(gettext("Could not create property list: %s\n"),
14566 uu_strerror(uu_error()));
14569 pattern
= safe_strdup(arg
);
14571 if ((e
= scf_entry_create(g_hndl
)) == NULL
||
14572 (pg
= scf_pg_create(g_hndl
)) == NULL
||
14573 (prop
= scf_property_create(g_hndl
)) == NULL
||
14574 (tx
= scf_transaction_create(g_hndl
)) == NULL
)
14577 if (cur_snap
!= NULL
) {
14578 semerr(emsg_cant_modify_snapshots
);
14582 if (cur_inst
== NULL
&& cur_svc
== NULL
) {
14583 semerr(emsg_entity_not_selected
);
14587 propname
= strchr(pgname
, '/');
14588 if (propname
== NULL
) {
14589 semerr(gettext("Property names must contain a `/'.\n"));
14596 if (type
!= NULL
) {
14597 ty
= string_to_type(type
);
14598 if (ty
== SCF_TYPE_INVALID
) {
14599 semerr(gettext("Unknown type \"%s\".\n"), type
);
14604 if (cur_inst
!= NULL
)
14605 ret
= scf_instance_get_pg(cur_inst
, pgname
, pg
);
14607 ret
= scf_service_get_pg(cur_svc
, pgname
, pg
);
14609 switch (scf_error()) {
14610 case SCF_ERROR_NOT_FOUND
:
14611 if (isnotfoundok
) {
14614 semerr(emsg_no_such_pg
, pgname
);
14619 case SCF_ERROR_INVALID_ARGUMENT
:
14620 semerr(emsg_invalid_pg_name
, pgname
);
14629 if (scf_pg_update(pg
) == -1)
14631 if (scf_transaction_start(tx
, pg
) != 0) {
14632 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
14635 semerr(emsg_permission_denied
);
14639 ret
= scf_pg_get_property(pg
, propname
, prop
);
14642 char *pat
= pattern
;
14644 if (scf_property_type(prop
, &ptype
) != 0)
14648 if (type
!= NULL
&& ptype
!= ty
) {
14649 semerr(gettext("Property \"%s\" is not "
14650 "of type \"%s\".\n"), propname
,
14657 size_t len
= strlen(pat
);
14658 if (len
> 0 && pat
[len
- 1] == '\"')
14659 pat
[len
- 1] = '\0';
14660 if (len
> 0 && pat
[0] == '\"')
14666 get_prop_values(prop
, values
, pat
);
14669 add_string(values
, arg
);
14671 if (scf_transaction_property_change(tx
, e
,
14672 propname
, ty
) == -1)
14674 } else if (scf_error() == SCF_ERROR_NOT_FOUND
) {
14676 if (type
== NULL
) {
14677 semerr(gettext("Type required "
14678 "for new properties.\n"));
14682 add_string(values
, arg
);
14684 if (scf_transaction_property_new(tx
, e
,
14685 propname
, ty
) == -1)
14687 } else if (isnotfoundok
) {
14691 semerr(gettext("No such property %s/%s.\n"),
14696 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT
) {
14697 semerr(emsg_invalid_prop_name
, propname
);
14703 walk
= uu_list_walk_start(values
, UU_DEFAULT
);
14705 uu_die(gettext("Could not walk property list.\n"));
14707 for (sp
= uu_list_walk_next(walk
); sp
!= NULL
;
14708 sp
= uu_list_walk_next(walk
)) {
14709 v
= string_to_value(sp
->str
, ty
, 0);
14712 scf_entry_destroy_children(e
);
14715 ret
= scf_entry_add_value(e
, v
);
14718 uu_list_walk_end(walk
);
14720 result
= scf_transaction_commit(tx
);
14722 scf_transaction_reset(tx
);
14723 scf_entry_destroy_children(e
);
14724 } while (result
== 0);
14727 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
14730 semerr(emsg_permission_denied
);
14739 scf_transaction_destroy(tx
);
14740 scf_entry_destroy(e
);
14741 scf_pg_destroy(pg
);
14742 scf_property_destroy(prop
);
14745 while ((sp
= uu_list_teardown(values
, &cookie
)) != NULL
) {
14750 uu_list_destroy(values
);
14760 lscf_addpropvalue(const char *pgname
, const char *type
, const char *value
)
14762 return (lscf_setpropvalue(pgname
, type
, value
, 1, 0));
14766 lscf_delpropvalue(const char *pgname
, const char *pattern
, int isnotfoundok
)
14768 return (lscf_setpropvalue(pgname
, NULL
, pattern
, 0, isnotfoundok
));
14772 * Look for a standard start method, first in the instance (if any),
14773 * then the service.
14775 static const char *
14776 start_method_name(int *in_instance
)
14778 scf_propertygroup_t
*pg
;
14781 scf_instance_t
*inst
= cur_inst
;
14783 if ((pg
= scf_pg_create(g_hndl
)) == NULL
)
14787 for (p
= start_method_names
; *p
!= NULL
; p
++) {
14789 ret
= scf_instance_get_pg(inst
, *p
, pg
);
14791 ret
= scf_service_get_pg(cur_svc
, *p
, pg
);
14794 size_t bufsz
= strlen(SCF_GROUP_METHOD
) + 1;
14795 char *buf
= safe_malloc(bufsz
);
14797 if ((ret
= scf_pg_get_type(pg
, buf
, bufsz
)) < 0) {
14801 if (strcmp(buf
, SCF_GROUP_METHOD
) != 0) {
14807 *in_instance
= (inst
!= NULL
);
14808 scf_pg_destroy(pg
);
14812 if (scf_error() == SCF_ERROR_NOT_FOUND
)
14818 if (inst
!= NULL
) {
14823 scf_pg_destroy(pg
);
14828 addpg(const char *name
, const char *type
)
14830 scf_propertygroup_t
*pg
;
14833 pg
= scf_pg_create(g_hndl
);
14837 if (cur_inst
!= NULL
)
14838 ret
= scf_instance_add_pg(cur_inst
, name
, type
, 0, pg
);
14840 ret
= scf_service_add_pg(cur_svc
, name
, type
, 0, pg
);
14843 switch (scf_error()) {
14844 case SCF_ERROR_EXISTS
:
14848 case SCF_ERROR_PERMISSION_DENIED
:
14849 semerr(emsg_permission_denied
);
14857 scf_pg_destroy(pg
);
14862 lscf_setenv(uu_list_t
*args
, int isunset
)
14867 char **argv
= NULL
;
14868 string_list_t
*slp
;
14871 int do_service
= 0;
14872 int do_instance
= 0;
14873 const char *method
= NULL
;
14874 const char *name
= NULL
;
14875 const char *value
= NULL
;
14876 scf_instance_t
*saved_cur_inst
= cur_inst
;
14880 argc
= uu_list_numnodes(args
);
14884 argv
= calloc(argc
+ 1, sizeof (char *));
14886 uu_die(gettext("Out of memory.\n"));
14888 for (slp
= uu_list_first(args
), i
= 0;
14890 slp
= uu_list_next(args
, slp
), ++i
)
14891 argv
[i
] = slp
->str
;
14898 ret
= getopt(argc
, argv
, "sim:");
14920 bad_error("getopt", ret
);
14925 if ((do_service
&& do_instance
) ||
14926 (isunset
&& argc
!= 1) ||
14927 (!isunset
&& argc
!= 2))
14930 name
= argv
[optind
];
14932 value
= argv
[optind
+ 1];
14934 if (cur_snap
!= NULL
) {
14935 semerr(emsg_cant_modify_snapshots
);
14940 if (cur_inst
== NULL
&& cur_svc
== NULL
) {
14941 semerr(emsg_entity_not_selected
);
14946 if (do_instance
&& cur_inst
== NULL
) {
14947 semerr(gettext("No instance is selected.\n"));
14952 if (do_service
&& cur_svc
== NULL
) {
14953 semerr(gettext("No service is selected.\n"));
14958 if (method
== NULL
) {
14959 if (do_instance
|| do_service
) {
14960 method
= "method_context";
14962 ret
= addpg("method_context",
14963 SCF_GROUP_FRAMEWORK
);
14969 method
= start_method_name(&in_instance
);
14970 if (method
== NULL
) {
14972 "Couldn't find start method; please "
14973 "specify a method with '-m'.\n"));
14981 scf_propertygroup_t
*pg
;
14986 if ((pg
= scf_pg_create(g_hndl
)) == NULL
)
14989 if (cur_inst
!= NULL
)
14990 ret
= scf_instance_get_pg(cur_inst
, method
, pg
);
14992 ret
= scf_service_get_pg(cur_svc
, method
, pg
);
14995 scf_pg_destroy(pg
);
14996 switch (scf_error()) {
14997 case SCF_ERROR_NOT_FOUND
:
14998 semerr(gettext("Couldn't find the method "
14999 "\"%s\".\n"), method
);
15002 case SCF_ERROR_INVALID_ARGUMENT
:
15003 semerr(gettext("Invalid method name \"%s\".\n"),
15012 bufsz
= strlen(SCF_GROUP_METHOD
) + 1;
15013 buf
= safe_malloc(bufsz
);
15015 if (scf_pg_get_type(pg
, buf
, bufsz
) < 0 ||
15016 strcmp(buf
, SCF_GROUP_METHOD
) != 0) {
15017 semerr(gettext("Property group \"%s\" is not of type "
15018 "\"method\".\n"), method
);
15021 scf_pg_destroy(pg
);
15026 scf_pg_destroy(pg
);
15029 prop
= uu_msprintf("%s/environment", method
);
15030 pattern
= uu_msprintf("%s=*", name
);
15032 if (prop
== NULL
|| pattern
== NULL
)
15033 uu_die(gettext("Out of memory.\n"));
15035 ret
= lscf_delpropvalue(prop
, pattern
, !isunset
);
15037 if (ret
== 0 && !isunset
) {
15040 prop
= uu_msprintf("%s/environment", method
);
15041 pattern
= uu_msprintf("%s=%s", name
, value
);
15042 if (prop
== NULL
|| pattern
== NULL
)
15043 uu_die(gettext("Out of memory.\n"));
15044 ret
= lscf_addpropvalue(prop
, "astring:", pattern
);
15050 cur_inst
= saved_cur_inst
;
15060 * Snapshot commands
15066 scf_snapshot_t
*snap
;
15073 if (cur_inst
== NULL
) {
15074 semerr(gettext("Instance not selected.\n"));
15078 if ((snap
= scf_snapshot_create(g_hndl
)) == NULL
||
15079 (iter
= scf_iter_create(g_hndl
)) == NULL
)
15082 if (scf_iter_instance_snapshots(iter
, cur_inst
) != SCF_SUCCESS
)
15085 nb
= safe_malloc(max_scf_name_len
+ 1);
15087 while ((r
= scf_iter_next_snapshot(iter
, snap
)) == 1) {
15088 if (scf_snapshot_get_name(snap
, nb
, max_scf_name_len
+ 1) < 0)
15097 scf_iter_destroy(iter
);
15098 scf_snapshot_destroy(snap
);
15102 lscf_selectsnap(const char *name
)
15104 scf_snapshot_t
*snap
;
15105 scf_snaplevel_t
*level
;
15109 if (cur_inst
== NULL
) {
15110 semerr(gettext("Instance not selected.\n"));
15114 if (cur_snap
!= NULL
) {
15115 if (name
!= NULL
) {
15116 char *cur_snap_name
;
15117 boolean_t nochange
;
15119 cur_snap_name
= safe_malloc(max_scf_name_len
+ 1);
15121 if (scf_snapshot_get_name(cur_snap
, cur_snap_name
,
15122 max_scf_name_len
+ 1) < 0)
15125 nochange
= strcmp(name
, cur_snap_name
) == 0;
15127 free(cur_snap_name
);
15133 unselect_cursnap();
15139 if ((snap
= scf_snapshot_create(g_hndl
)) == NULL
||
15140 (level
= scf_snaplevel_create(g_hndl
)) == NULL
)
15143 if (scf_instance_get_snapshot(cur_inst
, name
, snap
) !=
15145 switch (scf_error()) {
15146 case SCF_ERROR_INVALID_ARGUMENT
:
15147 semerr(gettext("Invalid name \"%s\".\n"), name
);
15150 case SCF_ERROR_NOT_FOUND
:
15151 semerr(gettext("No such snapshot \"%s\".\n"), name
);
15158 scf_snaplevel_destroy(level
);
15159 scf_snapshot_destroy(snap
);
15163 /* Load the snaplevels into our list. */
15164 cur_levels
= uu_list_create(snaplevel_pool
, NULL
, 0);
15165 if (cur_levels
== NULL
)
15166 uu_die(gettext("Could not create list: %s\n"),
15167 uu_strerror(uu_error()));
15169 if (scf_snapshot_get_base_snaplevel(snap
, level
) != SCF_SUCCESS
) {
15170 if (scf_error() != SCF_ERROR_NOT_FOUND
)
15173 semerr(gettext("Snapshot has no snaplevels.\n"));
15175 scf_snaplevel_destroy(level
);
15176 scf_snapshot_destroy(snap
);
15183 cur_elt
= safe_malloc(sizeof (*cur_elt
));
15184 uu_list_node_init(cur_elt
, &cur_elt
->list_node
,
15186 cur_elt
->sl
= level
;
15187 if (uu_list_insert_after(cur_levels
, NULL
, cur_elt
) != 0)
15188 uu_die(gettext("libuutil error: %s\n"),
15189 uu_strerror(uu_error()));
15191 level
= scf_snaplevel_create(g_hndl
);
15195 if (scf_snaplevel_get_next_snaplevel(cur_elt
->sl
,
15196 level
) != SCF_SUCCESS
) {
15197 if (scf_error() != SCF_ERROR_NOT_FOUND
)
15200 scf_snaplevel_destroy(level
);
15205 cur_elt
= uu_list_last(cur_levels
);
15206 cur_level
= cur_elt
->sl
;
15210 * Copies the properties & values in src to dst. Assumes src won't change.
15211 * Returns -1 if permission is denied, -2 if another transaction interrupts,
15212 * and 0 on success.
15214 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
15215 * property, if it is copied and has type boolean. (See comment in
15219 pg_copy(const scf_propertygroup_t
*src
, scf_propertygroup_t
*dst
,
15222 scf_transaction_t
*tx
;
15223 scf_iter_t
*iter
, *viter
;
15224 scf_property_t
*prop
;
15229 tx
= scf_transaction_create(g_hndl
);
15233 if (scf_transaction_start(tx
, dst
) != SCF_SUCCESS
) {
15234 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
15237 scf_transaction_destroy(tx
);
15242 if ((iter
= scf_iter_create(g_hndl
)) == NULL
||
15243 (prop
= scf_property_create(g_hndl
)) == NULL
||
15244 (viter
= scf_iter_create(g_hndl
)) == NULL
)
15247 nbuf
= safe_malloc(max_scf_name_len
+ 1);
15249 if (scf_iter_pg_properties(iter
, src
) != SCF_SUCCESS
)
15253 scf_transaction_entry_t
*e
;
15256 r
= scf_iter_next_property(iter
, prop
);
15262 e
= scf_entry_create(g_hndl
);
15266 if (scf_property_type(prop
, &ty
) != SCF_SUCCESS
)
15269 if (scf_property_get_name(prop
, nbuf
, max_scf_name_len
+ 1) < 0)
15272 if (scf_transaction_property_new(tx
, e
, nbuf
,
15273 ty
) != SCF_SUCCESS
)
15276 if ((enabled
== 0 || enabled
== 1) &&
15277 strcmp(nbuf
, scf_property_enabled
) == 0 &&
15278 ty
== SCF_TYPE_BOOLEAN
) {
15279 v
= scf_value_create(g_hndl
);
15283 scf_value_set_boolean(v
, enabled
);
15285 if (scf_entry_add_value(e
, v
) != 0)
15288 if (scf_iter_property_values(viter
, prop
) != 0)
15292 v
= scf_value_create(g_hndl
);
15296 r
= scf_iter_next_value(viter
, v
);
15300 scf_value_destroy(v
);
15304 if (scf_entry_add_value(e
, v
) != SCF_SUCCESS
)
15311 scf_iter_destroy(viter
);
15312 scf_property_destroy(prop
);
15313 scf_iter_destroy(iter
);
15315 r
= scf_transaction_commit(tx
);
15316 if (r
== -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED
)
15319 scf_transaction_destroy_children(tx
);
15320 scf_transaction_destroy(tx
);
15323 case 1: return (0);
15324 case 0: return (-2);
15325 case -1: return (-1);
15335 lscf_revert(const char *snapname
)
15337 scf_snapshot_t
*snap
, *prev
;
15338 scf_snaplevel_t
*level
, *nlevel
;
15340 scf_propertygroup_t
*pg
, *npg
;
15341 scf_property_t
*prop
;
15348 if (cur_inst
== NULL
) {
15349 semerr(gettext("Instance not selected.\n"));
15353 if (snapname
!= NULL
) {
15354 snap
= scf_snapshot_create(g_hndl
);
15358 if (scf_instance_get_snapshot(cur_inst
, snapname
, snap
) !=
15360 switch (scf_error()) {
15361 case SCF_ERROR_INVALID_ARGUMENT
:
15362 semerr(gettext("Invalid snapshot name "
15363 "\"%s\".\n"), snapname
);
15366 case SCF_ERROR_NOT_FOUND
:
15367 semerr(gettext("No such snapshot.\n"));
15374 scf_snapshot_destroy(snap
);
15378 if (cur_snap
!= NULL
) {
15381 semerr(gettext("No snapshot selected.\n"));
15386 if ((prev
= scf_snapshot_create(g_hndl
)) == NULL
||
15387 (level
= scf_snaplevel_create(g_hndl
)) == NULL
||
15388 (iter
= scf_iter_create(g_hndl
)) == NULL
||
15389 (pg
= scf_pg_create(g_hndl
)) == NULL
||
15390 (npg
= scf_pg_create(g_hndl
)) == NULL
||
15391 (prop
= scf_property_create(g_hndl
)) == NULL
||
15392 (val
= scf_value_create(g_hndl
)) == NULL
)
15395 nbuf
= safe_malloc(max_scf_name_len
+ 1);
15396 tbuf
= safe_malloc(max_scf_pg_type_len
+ 1);
15398 /* Take the "previous" snapshot before we blow away the properties. */
15399 if (scf_instance_get_snapshot(cur_inst
, snap_previous
, prev
) == 0) {
15400 if (_scf_snapshot_take_attach(cur_inst
, prev
) != 0)
15403 if (scf_error() != SCF_ERROR_NOT_FOUND
)
15406 if (_scf_snapshot_take_new(cur_inst
, snap_previous
, prev
) != 0)
15410 /* Save general/enabled, since we're probably going to replace it. */
15412 if (scf_instance_get_pg(cur_inst
, scf_pg_general
, pg
) == 0 &&
15413 scf_pg_get_property(pg
, scf_property_enabled
, prop
) == 0 &&
15414 scf_property_get_value(prop
, val
) == 0)
15415 (void) scf_value_get_boolean(val
, &enabled
);
15417 if (scf_snapshot_get_base_snaplevel(snap
, level
) != SCF_SUCCESS
) {
15418 if (scf_error() != SCF_ERROR_NOT_FOUND
)
15429 /* Clear the properties from the corresponding entity. */
15430 isinst
= snaplevel_is_instance(level
);
15433 r
= scf_iter_service_pgs(iter
, cur_svc
);
15435 r
= scf_iter_instance_pgs(iter
, cur_inst
);
15436 if (r
!= SCF_SUCCESS
)
15439 while ((r
= scf_iter_next_pg(iter
, pg
)) == 1) {
15440 if (scf_pg_get_flags(pg
, &flags
) != SCF_SUCCESS
)
15443 /* Skip nonpersistent pgs. */
15444 if (flags
& SCF_PG_FLAG_NONPERSISTENT
)
15447 if (scf_pg_delete(pg
) != SCF_SUCCESS
) {
15448 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
15451 semerr(emsg_permission_denied
);
15458 /* Copy the properties to the corresponding entity. */
15459 if (scf_iter_snaplevel_pgs(iter
, level
) != SCF_SUCCESS
)
15462 while ((r
= scf_iter_next_pg(iter
, pg
)) == 1) {
15463 if (scf_pg_get_name(pg
, nbuf
, max_scf_name_len
+ 1) < 0)
15466 if (scf_pg_get_type(pg
, tbuf
, max_scf_pg_type_len
+ 1) <
15470 if (scf_pg_get_flags(pg
, &flags
) != SCF_SUCCESS
)
15474 r
= scf_service_add_pg(cur_svc
, nbuf
, tbuf
,
15477 r
= scf_instance_add_pg(cur_inst
, nbuf
, tbuf
,
15479 if (r
!= SCF_SUCCESS
) {
15480 if (scf_error() != SCF_ERROR_PERMISSION_DENIED
)
15483 semerr(emsg_permission_denied
);
15487 if ((enabled
== 0 || enabled
== 1) &&
15488 strcmp(nbuf
, scf_pg_general
) == 0)
15489 r
= pg_copy(pg
, npg
, enabled
);
15491 r
= pg_copy(pg
, npg
, 2);
15498 semerr(emsg_permission_denied
);
15503 "Interrupted by another change.\n"));
15513 /* Get next level. */
15514 nlevel
= scf_snaplevel_create(g_hndl
);
15515 if (nlevel
== NULL
)
15518 if (scf_snaplevel_get_next_snaplevel(level
, nlevel
) !=
15520 if (scf_error() != SCF_ERROR_NOT_FOUND
)
15523 scf_snaplevel_destroy(nlevel
);
15527 scf_snaplevel_destroy(level
);
15531 if (snapname
== NULL
) {
15532 lscf_selectsnap(NULL
);
15533 snap
= NULL
; /* cur_snap has been destroyed */
15539 scf_value_destroy(val
);
15540 scf_property_destroy(prop
);
15541 scf_pg_destroy(npg
);
15542 scf_pg_destroy(pg
);
15543 scf_iter_destroy(iter
);
15544 scf_snaplevel_destroy(level
);
15545 scf_snapshot_destroy(prev
);
15546 if (snap
!= cur_snap
)
15547 scf_snapshot_destroy(snap
);
15560 if (cur_inst
== NULL
) {
15561 semerr(gettext("Instance not selected.\n"));
15565 bufsz
= max_scf_fmri_len
+ 1;
15566 fmribuf
= safe_malloc(bufsz
);
15567 fmrilen
= scf_instance_to_fmri(cur_inst
, fmribuf
, bufsz
);
15570 if (scf_error() != SCF_ERROR_DELETED
)
15572 scf_instance_destroy(cur_inst
);
15574 warn(emsg_deleted
);
15577 assert(fmrilen
< bufsz
);
15579 r
= refresh_entity(0, cur_inst
, fmribuf
, NULL
, NULL
, NULL
);
15585 warn(gettext("Could not refresh %s "
15586 "(repository connection broken).\n"), fmribuf
);
15590 warn(emsg_deleted
);
15594 warn(gettext("Could not refresh %s "
15595 "(permission denied).\n"), fmribuf
);
15599 warn(gettext("Could not refresh %s "
15600 "(repository server out of resources).\n"),
15606 bad_error("refresh_entity", scf_error());
15613 * describe [-v] [-t] [pg/prop]
15616 lscf_describe(uu_list_t
*args
, int hasargs
)
15621 char **argv
= NULL
;
15622 string_list_t
*slp
;
15623 int do_verbose
= 0;
15624 int do_templates
= 0;
15625 char *pattern
= NULL
;
15629 if (hasargs
!= 0) {
15630 argc
= uu_list_numnodes(args
);
15634 argv
= calloc(argc
+ 1, sizeof (char *));
15636 uu_die(gettext("Out of memory.\n"));
15638 for (slp
= uu_list_first(args
), i
= 0;
15640 slp
= uu_list_next(args
, slp
), ++i
)
15641 argv
[i
] = slp
->str
;
15646 * We start optind = 0 because our list of arguments
15647 * starts at argv[0]
15652 ret
= getopt(argc
, argv
, "vt");
15669 bad_error("getopt", ret
);
15673 pattern
= argv
[optind
];
15676 if (cur_inst
== NULL
&& cur_svc
== NULL
) {
15677 semerr(emsg_entity_not_selected
);
15683 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15684 * output if their last parameter is set to 2. Less information is
15685 * produced if the parameter is set to 1.
15687 if (pattern
== NULL
) {
15688 if (do_verbose
== 1)
15689 list_entity_tmpl(2);
15691 list_entity_tmpl(1);
15694 if (do_templates
== 0) {
15695 if (do_verbose
== 1)
15696 listprop(pattern
, 0, 2);
15698 listprop(pattern
, 0, 1);
15700 if (do_verbose
== 1)
15701 listtmpl(pattern
, 2);
15703 listtmpl(pattern
, 1);
15715 #define PARAM_ACTIVE ((const char *) "active")
15716 #define PARAM_INACTIVE ((const char *) "inactive")
15717 #define PARAM_SMTP_TO ((const char *) "to")
15721 * Breaks down the string according to the tokens passed.
15722 * Caller is responsible for freeing array of pointers returned.
15723 * Returns NULL on failure
15726 tokenize(char *str
, const char *sep
)
15728 char *token
, *lasts
;
15730 int n
= 0; /* number of elements */
15731 int size
= 8; /* size of the array (initial) */
15733 buf
= safe_malloc(size
* sizeof (char *));
15735 for (token
= strtok_r(str
, sep
, &lasts
); token
!= NULL
;
15736 token
= strtok_r(NULL
, sep
, &lasts
), ++n
) {
15737 if (n
+ 1 >= size
) {
15739 if ((buf
= reallocarray(buf
, size
, sizeof (char *))) ==
15741 uu_die(gettext("Out of memory"));
15746 /* NULL terminate the pointer array */
15753 check_tokens(char **p
)
15759 int32_t t
= string_to_tset(*p
);
15762 if (is_fma_token(*p
) == 0)
15763 return (INVALID_TOKENS
);
15764 fma
= 1; /* this token is an fma event */
15769 if (smf
!= 0 && fma
== 1)
15770 return (MIXED_TOKENS
);
15777 return (FMA_TOKENS
);
15779 return (INVALID_TOKENS
);
15783 get_selection_str(char *fmri
, size_t sz
)
15785 if (g_hndl
== NULL
) {
15786 semerr(emsg_entity_not_selected
);
15788 } else if (cur_level
!= NULL
) {
15789 semerr(emsg_invalid_for_snapshot
);
15792 lscf_get_selection_str(fmri
, sz
);
15799 lscf_delnotify(const char *set
, int global
)
15801 char *str
= strdup(set
);
15808 uu_die(gettext("Out of memory.\n"));
15810 pgs
= tokenize(str
, ",");
15812 if ((tset
= check_tokens(pgs
)) > 0) {
15813 size_t sz
= max_scf_fmri_len
+ 1;
15815 fmri
= safe_malloc(sz
);
15817 (void) strlcpy(fmri
, SCF_INSTANCE_GLOBAL
, sz
);
15818 } else if (get_selection_str(fmri
, sz
) != 0) {
15822 if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS
, fmri
,
15823 tset
) != SCF_SUCCESS
) {
15824 uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15825 scf_strerror(scf_error()));
15827 } else if (tset
== FMA_TOKENS
) {
15829 semerr(gettext("Can't use option '-g' with FMA event "
15834 for (p
= pgs
; *p
; ++p
) {
15835 if (smf_notify_del_params(de_tag(*p
), NULL
, 0) !=
15837 uu_warn(gettext("Failed for \"%s\": %s\n"), *p
,
15838 scf_strerror(scf_error()));
15842 } else if (tset
== MIXED_TOKENS
) {
15843 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15846 uu_die(gettext("Invalid input.\n"));
15856 lscf_listnotify(const char *set
, int global
)
15858 char *str
= safe_strdup(set
);
15865 if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, 0) != 0)
15866 uu_die(gettext("Out of memory.\n"));
15868 pgs
= tokenize(str
, ",");
15870 if ((tset
= check_tokens(pgs
)) > 0) {
15871 size_t sz
= max_scf_fmri_len
+ 1;
15873 fmri
= safe_malloc(sz
);
15875 (void) strlcpy(fmri
, SCF_INSTANCE_GLOBAL
, sz
);
15876 } else if (get_selection_str(fmri
, sz
) != 0) {
15880 if (_scf_get_svc_notify_params(fmri
, nvl
, tset
, 1, 1) !=
15882 if (scf_error() != SCF_ERROR_NOT_FOUND
&&
15883 scf_error() != SCF_ERROR_DELETED
)
15885 "Failed listnotify: %s\n"),
15886 scf_strerror(scf_error()));
15890 listnotify_print(nvl
, NULL
);
15891 } else if (tset
== FMA_TOKENS
) {
15893 semerr(gettext("Can't use option '-g' with FMA event "
15898 for (p
= pgs
; *p
; ++p
) {
15899 if (_scf_get_fma_notify_params(de_tag(*p
), nvl
, 1) !=
15902 * if the preferences have just been deleted
15903 * or does not exist, just skip.
15905 if (scf_error() == SCF_ERROR_NOT_FOUND
||
15906 scf_error() == SCF_ERROR_DELETED
)
15909 "Failed listnotify: %s\n"),
15910 scf_strerror(scf_error()));
15913 listnotify_print(nvl
, re_tag(*p
));
15915 } else if (tset
== MIXED_TOKENS
) {
15916 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15919 semerr(gettext("Invalid input.\n"));
15930 strip_quotes_and_blanks(char *s
)
15933 char *end
= strrchr(s
, '\"');
15935 if (s
[0] == '\"' && end
!= NULL
&& *(end
+ 1) == '\0') {
15937 while (isblank(*start
))
15939 while (isblank(*(end
- 1)) && end
> start
) {
15949 set_active(nvlist_t
*mech
, const char *hier_part
)
15953 if (*hier_part
== '\0' || strcmp(hier_part
, PARAM_ACTIVE
) == 0) {
15955 } else if (strcmp(hier_part
, PARAM_INACTIVE
) == 0) {
15961 if (nvlist_add_boolean_value(mech
, PARAM_ACTIVE
, b
) != 0)
15962 uu_die(gettext("Out of memory.\n"));
15968 add_snmp_params(nvlist_t
*mech
, char *hier_part
)
15970 return (set_active(mech
, hier_part
));
15974 add_syslog_params(nvlist_t
*mech
, char *hier_part
)
15976 return (set_active(mech
, hier_part
));
15980 * add_mailto_paramas()
15981 * parse the hier_part of mailto URI
15982 * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
15983 * or mailto:{[active]|inactive}
15986 add_mailto_params(nvlist_t
*mech
, char *hier_part
)
15988 const char *tok
= "?&";
15995 * If the notification parametes are in the form of
15997 * malito:{[active]|inactive}
15999 * we set the property accordingly and return.
16000 * Otherwise, we make the notification type active and
16001 * process the hier_part.
16003 if (set_active(mech
, hier_part
) == 0)
16005 else if (set_active(mech
, PARAM_ACTIVE
) != 0)
16008 if ((p
= strtok_r(hier_part
, tok
, &lasts
)) == NULL
) {
16010 * sanity check: we only get here if hier_part = "", but
16011 * that's handled by set_active
16013 uu_die("strtok_r");
16016 if (nvlist_add_string(mech
, PARAM_SMTP_TO
, p
) != 0)
16017 uu_die(gettext("Out of memory.\n"));
16019 while ((p
= strtok_r(NULL
, tok
, &lasts
)) != NULL
)
16020 if ((param
= strtok_r(p
, "=", &val
)) != NULL
)
16021 if (nvlist_add_string(mech
, param
, val
) != 0)
16022 uu_die(gettext("Out of memory.\n"));
16028 uri_split(char *uri
, char **scheme
, char **hier_part
)
16032 if ((*scheme
= strtok_r(uri
, ":", hier_part
)) == NULL
||
16033 *hier_part
== NULL
) {
16034 semerr(gettext("'%s' is not an URI\n"), uri
);
16038 if ((r
= check_uri_scheme(*scheme
)) < 0) {
16039 semerr(gettext("Unkown URI scheme: %s\n"), *scheme
);
16047 process_uri(nvlist_t
*params
, char *uri
)
16055 if ((index
= uri_split(uri
, &scheme
, &hier_part
)) < 0)
16058 if (nvlist_alloc(&mech
, NV_UNIQUE_NAME
, 0) != 0)
16059 uu_die(gettext("Out of memory.\n"));
16063 /* error messages displayed by called function */
16064 r
= add_mailto_params(mech
, hier_part
);
16068 if ((r
= add_snmp_params(mech
, hier_part
)) != 0)
16069 semerr(gettext("Not valid parameters: '%s'\n"),
16074 if ((r
= add_syslog_params(mech
, hier_part
)) != 0)
16075 semerr(gettext("Not valid parameters: '%s'\n"),
16083 if (r
== 0 && nvlist_add_nvlist(params
, uri_scheme
[index
].protocol
,
16085 uu_die(gettext("Out of memory.\n"));
16092 set_params(nvlist_t
*params
, char **p
)
16098 uu_die("set_params");
16101 uri
= strip_quotes_and_blanks(*p
);
16102 if (process_uri(params
, uri
) != 0)
16112 setnotify(const char *e
, char **p
, int global
)
16114 char *str
= safe_strdup(e
);
16118 nvlist_t
*nvl
, *params
;
16121 if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, 0) != 0 ||
16122 nvlist_alloc(¶ms
, NV_UNIQUE_NAME
, 0) != 0 ||
16123 nvlist_add_uint32(nvl
, SCF_NOTIFY_NAME_VERSION
,
16124 SCF_NOTIFY_PARAMS_VERSION
) != 0)
16125 uu_die(gettext("Out of memory.\n"));
16127 events
= tokenize(str
, ",");
16129 if ((tset
= check_tokens(events
)) > 0) {
16130 /* SMF state transitions parameters */
16131 size_t sz
= max_scf_fmri_len
+ 1;
16133 fmri
= safe_malloc(sz
);
16135 (void) strlcpy(fmri
, SCF_INSTANCE_GLOBAL
, sz
);
16136 } else if (get_selection_str(fmri
, sz
) != 0) {
16140 if (nvlist_add_string(nvl
, SCF_NOTIFY_NAME_FMRI
, fmri
) != 0 ||
16141 nvlist_add_int32(nvl
, SCF_NOTIFY_NAME_TSET
, tset
) != 0)
16142 uu_die(gettext("Out of memory.\n"));
16144 if ((r
= set_params(params
, p
)) == 0) {
16145 if (nvlist_add_nvlist(nvl
, SCF_NOTIFY_PARAMS
,
16147 uu_die(gettext("Out of memory.\n"));
16149 if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS
,
16150 nvl
) != SCF_SUCCESS
) {
16153 "Failed smf_notify_set_params(3SCF): %s\n"),
16154 scf_strerror(scf_error()));
16157 } else if (tset
== FMA_TOKENS
) {
16158 /* FMA event parameters */
16160 semerr(gettext("Can't use option '-g' with FMA event "
16165 if ((r
= set_params(params
, p
)) != 0)
16168 if (nvlist_add_nvlist(nvl
, SCF_NOTIFY_PARAMS
, params
) != 0)
16169 uu_die(gettext("Out of memory.\n"));
16172 if (smf_notify_set_params(de_tag(*events
), nvl
) !=
16175 "Failed smf_notify_set_params(3SCF) for "
16176 "event %s: %s\n"), *events
,
16177 scf_strerror(scf_error()));
16180 } else if (tset
== MIXED_TOKENS
) {
16181 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
16184 uu_die(gettext("Invalid input.\n"));
16189 nvlist_free(params
);
16197 lscf_setnotify(uu_list_t
*args
)
16200 char **argv
= NULL
;
16201 string_list_t
*slp
;
16208 if ((argc
= uu_list_numnodes(args
)) < 2)
16211 argv
= calloc(argc
+ 1, sizeof (char *));
16213 uu_die(gettext("Out of memory.\n"));
16215 for (slp
= uu_list_first(args
), i
= 0;
16217 slp
= uu_list_next(args
, slp
), ++i
)
16218 argv
[i
] = slp
->str
;
16222 if (strcmp(argv
[0], "-g") == 0) {
16232 ret
= setnotify(events
, p
, global
);
16244 * Creates a list of instance name strings associated with a service. If
16245 * wohandcrafted flag is set, get only instances that have a last-import
16246 * snapshot, instances that were imported via svccfg.
16249 create_instance_list(scf_service_t
*svc
, int wohandcrafted
)
16251 scf_snapshot_t
*snap
= NULL
;
16252 scf_instance_t
*inst
;
16253 scf_iter_t
*inst_iter
;
16254 uu_list_t
*instances
;
16255 char *instname
= NULL
;
16258 inst_iter
= scf_iter_create(g_hndl
);
16259 inst
= scf_instance_create(g_hndl
);
16260 if (inst_iter
== NULL
|| inst
== NULL
) {
16261 uu_warn(gettext("Could not create instance or iterator\n"));
16265 if ((instances
= uu_list_create(string_pool
, NULL
, 0)) == NULL
)
16266 return (instances
);
16268 if (scf_iter_service_instances(inst_iter
, svc
) != 0) {
16269 switch (scf_error()) {
16270 case SCF_ERROR_CONNECTION_BROKEN
:
16271 case SCF_ERROR_DELETED
:
16272 uu_list_destroy(instances
);
16276 case SCF_ERROR_HANDLE_MISMATCH
:
16277 case SCF_ERROR_NOT_BOUND
:
16278 case SCF_ERROR_NOT_SET
:
16280 bad_error("scf_iter_service_instances", scf_error());
16284 instname
= safe_malloc(max_scf_name_len
+ 1);
16285 while ((r
= scf_iter_next_instance(inst_iter
, inst
)) != 0) {
16287 (void) uu_warn(gettext("Unable to iterate through "
16288 "instances to create instance list : %s\n"),
16289 scf_strerror(scf_error()));
16291 uu_list_destroy(instances
);
16297 * If the instance does not have a last-import snapshot
16298 * then do not add it to the list as it is a hand-crafted
16299 * instance that should not be managed.
16301 if (wohandcrafted
) {
16302 if (snap
== NULL
&&
16303 (snap
= scf_snapshot_create(g_hndl
)) == NULL
) {
16304 uu_warn(gettext("Unable to create snapshot "
16309 if (scf_instance_get_snapshot(inst
,
16310 snap_lastimport
, snap
) != 0) {
16311 switch (scf_error()) {
16312 case SCF_ERROR_NOT_FOUND
:
16313 case SCF_ERROR_DELETED
:
16316 case SCF_ERROR_CONNECTION_BROKEN
:
16317 uu_list_destroy(instances
);
16321 case SCF_ERROR_HANDLE_MISMATCH
:
16322 case SCF_ERROR_NOT_BOUND
:
16323 case SCF_ERROR_NOT_SET
:
16325 bad_error("scf_iter_service_instances",
16331 if (scf_instance_get_name(inst
, instname
,
16332 max_scf_name_len
+ 1) < 0) {
16333 switch (scf_error()) {
16334 case SCF_ERROR_NOT_FOUND
:
16337 case SCF_ERROR_CONNECTION_BROKEN
:
16338 case SCF_ERROR_DELETED
:
16339 uu_list_destroy(instances
);
16343 case SCF_ERROR_HANDLE_MISMATCH
:
16344 case SCF_ERROR_NOT_BOUND
:
16345 case SCF_ERROR_NOT_SET
:
16347 bad_error("scf_iter_service_instances",
16352 add_string(instances
, instname
);
16357 scf_snapshot_destroy(snap
);
16359 scf_instance_destroy(inst
);
16360 scf_iter_destroy(inst_iter
);
16362 return (instances
);
16366 * disable an instance but wait for the instance to
16367 * move out of the running state.
16369 * Returns 0 : if the instance did not disable
16370 * Returns non-zero : if the instance disabled.
16374 disable_instance(scf_instance_t
*instance
)
16377 int enabled
= 10000;
16379 if (inst_is_running(instance
)) {
16380 fmribuf
= safe_malloc(max_scf_name_len
+ 1);
16381 if (scf_instance_to_fmri(instance
, fmribuf
,
16382 max_scf_name_len
+ 1) < 0) {
16388 * If the instance cannot be disabled then return
16389 * failure to disable and let the caller decide
16390 * if that is of importance.
16392 if (smf_disable_instance(fmribuf
, 0) != 0) {
16398 if (!inst_is_running(instance
))
16401 (void) poll(NULL
, 0, 5);
16402 enabled
= enabled
- 5;
16412 * Function to compare two service_manifest structures.
16416 service_manifest_compare(const void *left
, const void *right
, void *unused
)
16418 service_manifest_t
*l
= (service_manifest_t
*)left
;
16419 service_manifest_t
*r
= (service_manifest_t
*)right
;
16422 rc
= strcmp(l
->servicename
, r
->servicename
);
16428 * Look for the provided service in the service to manifest
16429 * tree. If the service exists, and a manifest was provided
16430 * then add the manifest to that service. If the service
16431 * does not exist, then add the service and manifest to the
16434 * If the manifest is NULL, return the element if found. If
16435 * the service is not found return NULL.
16437 service_manifest_t
*
16438 find_add_svc_mfst(const char *svnbuf
, const char *mfst
)
16440 service_manifest_t elem
;
16441 service_manifest_t
*fnelem
;
16442 uu_avl_index_t marker
;
16444 elem
.servicename
= svnbuf
;
16445 fnelem
= uu_avl_find(service_manifest_tree
, &elem
, NULL
, &marker
);
16449 add_string(fnelem
->mfstlist
, strdup(mfst
));
16451 fnelem
= safe_malloc(sizeof (*fnelem
));
16452 fnelem
->servicename
= safe_strdup(svnbuf
);
16453 if ((fnelem
->mfstlist
=
16454 uu_list_create(string_pool
, NULL
, 0)) == NULL
)
16455 uu_die(gettext("Could not create property "
16456 "list: %s\n"), uu_strerror(uu_error()));
16458 add_string(fnelem
->mfstlist
, safe_strdup(mfst
));
16460 uu_avl_insert(service_manifest_tree
, fnelem
, marker
);
16468 * Create the service to manifest avl tree.
16470 * Walk each of the manifests currently installed in the supported
16471 * directories, /lib/svc/manifests and /var/svc/manifests. For
16472 * each of the manifests, inventory the services and add them to
16475 * Code that calls this function should make sure fileystem/minimal is online,
16476 * /var is available, since this function walks the /var/svc/manifest directory.
16479 create_manifest_tree(void)
16481 manifest_info_t
**entry
;
16482 manifest_info_t
**manifests
;
16483 uu_list_walk_t
*svcs
;
16486 char *dirs
[] = {LIBSVC_DIR
, VARSVC_DIR
, NULL
};
16489 if (service_manifest_pool
)
16493 * Create the list pool for the service manifest list
16495 service_manifest_pool
= uu_avl_pool_create("service_manifest",
16496 sizeof (service_manifest_t
),
16497 offsetof(service_manifest_t
, svcmfst_node
),
16498 service_manifest_compare
, UU_DEFAULT
);
16499 if (service_manifest_pool
== NULL
)
16500 uu_die(gettext("service_manifest pool creation failed: %s\n"),
16501 uu_strerror(uu_error()));
16506 service_manifest_tree
= uu_avl_create(service_manifest_pool
, NULL
,
16508 if (service_manifest_tree
== NULL
)
16509 uu_die(gettext("service_manifest tree creation failed: %s\n"),
16510 uu_strerror(uu_error()));
16513 * Walk the manifests adding the service(s) from each manifest.
16515 * If a service already exists add the manifest to the manifest
16516 * list for that service. This covers the case of a service that
16517 * is supported by multiple manifest files.
16519 for (c
= 0; dirs
[c
]; c
++) {
16520 status
= find_manifests(g_hndl
, dirs
[c
], &manifests
, CHECKEXT
);
16522 uu_warn(gettext("file tree walk of %s encountered "
16523 "error %s\n"), dirs
[c
], strerror(errno
));
16525 uu_avl_destroy(service_manifest_tree
);
16526 service_manifest_tree
= NULL
;
16531 * If a manifest that was in the list is not found
16532 * then skip and go to the next manifest file.
16534 if (manifests
!= NULL
) {
16535 for (entry
= manifests
; *entry
!= NULL
; entry
++) {
16536 b
= internal_bundle_new();
16537 if (lxml_get_bundle_file(b
, (*entry
)->mi_path
,
16538 SVCCFG_OP_IMPORT
) != 0) {
16539 internal_bundle_free(b
);
16543 svcs
= uu_list_walk_start(b
->sc_bundle_services
,
16545 if (svcs
== NULL
) {
16546 internal_bundle_free(b
);
16550 while ((mfsvc
= uu_list_walk_next(svcs
)) !=
16552 /* Add manifest to service */
16553 (void) find_add_svc_mfst(mfsvc
->sc_name
,
16554 (*entry
)->mi_path
);
16557 uu_list_walk_end(svcs
);
16558 internal_bundle_free(b
);
16561 free_manifest_array(manifests
);
16567 * Check the manifest history file to see
16568 * if the service was ever installed from
16569 * one of the supported directories.
16572 * -1 - if there's error reading manifest history file
16573 * 1 - if the service is not found
16574 * 0 - if the service is found
16577 check_mfst_history(const char *svcname
)
16580 caddr_t mfsthist_start
;
16585 fd
= open(MFSTHISTFILE
, O_RDONLY
);
16587 uu_warn(gettext("Unable to open the history file\n"));
16591 if (fstat(fd
, &st
) == -1) {
16592 uu_warn(gettext("Unable to stat the history file\n"));
16596 mfsthist_start
= mmap(NULL
, st
.st_size
, PROT_READ
,
16597 MAP_PRIVATE
, fd
, 0);
16600 if (mfsthist_start
== MAP_FAILED
||
16601 *(mfsthist_start
+ st
.st_size
) != '\0') {
16602 (void) munmap(mfsthist_start
, st
.st_size
);
16607 * The manifest history file is a space delimited list
16608 * of service and instance to manifest linkage. Adding
16609 * a space to the end of the service name so to get only
16610 * the service that is being searched for.
16612 svnbuf
= uu_msprintf("%s ", svcname
);
16613 if (svnbuf
== NULL
)
16614 uu_die(gettext("Out of memory"));
16616 if (strstr(mfsthist_start
, svnbuf
) != NULL
)
16619 (void) munmap(mfsthist_start
, st
.st_size
);
16625 * Take down each of the instances in the service
16626 * and remove them, then delete the service.
16629 teardown_service(scf_service_t
*svc
, const char *svnbuf
)
16631 scf_instance_t
*instance
;
16635 safe_printf(gettext("Delete service %s as there are no "
16636 "supporting manifests\n"), svnbuf
);
16638 instance
= scf_instance_create(g_hndl
);
16639 iter
= scf_iter_create(g_hndl
);
16640 if (iter
== NULL
|| instance
== NULL
) {
16641 uu_warn(gettext("Unable to create supporting entities to "
16642 "teardown the service\n"));
16643 uu_warn(gettext("scf error is : %s\n"),
16644 scf_strerror(scf_error()));
16648 if (scf_iter_service_instances(iter
, svc
) != 0) {
16649 switch (scf_error()) {
16650 case SCF_ERROR_CONNECTION_BROKEN
:
16651 case SCF_ERROR_DELETED
:
16654 case SCF_ERROR_HANDLE_MISMATCH
:
16655 case SCF_ERROR_NOT_BOUND
:
16656 case SCF_ERROR_NOT_SET
:
16658 bad_error("scf_iter_service_instances",
16663 while ((r
= scf_iter_next_instance(iter
, instance
)) != 0) {
16665 uu_warn(gettext("Error - %s\n"),
16666 scf_strerror(scf_error()));
16670 (void) disable_instance(instance
);
16674 * Delete the service... forcing the deletion in case
16675 * any of the instances did not disable.
16677 (void) lscf_service_delete(svc
, 1);
16679 scf_instance_destroy(instance
);
16680 scf_iter_destroy(iter
);
16684 * Get the list of instances supported by the manifest
16687 * Return 0 if there are no instances.
16689 * Return -1 if there are errors attempting to collect instances.
16691 * Return the count of instances found if there are no errors.
16695 check_instance_support(char *mfstfile
, const char *svcname
,
16696 uu_list_t
*instances
)
16698 uu_list_walk_t
*svcs
, *insts
;
16701 entity_t
*mfsvc
, *mfinst
;
16706 b
= internal_bundle_new();
16708 if (lxml_get_bundle_file(b
, mfstfile
, SVCCFG_OP_IMPORT
) != 0) {
16710 * Unable to process the manifest file for
16711 * instance support, so just return as
16712 * don't want to remove instances that could
16713 * not be accounted for that might exist here.
16715 internal_bundle_free(b
);
16719 svcs
= uu_list_walk_start(b
->sc_bundle_services
, 0);
16720 if (svcs
== NULL
) {
16721 internal_bundle_free(b
);
16725 svcn
= svcname
+ (sizeof (SCF_FMRI_SVC_PREFIX
) - 1) +
16726 (sizeof (SCF_FMRI_SERVICE_PREFIX
) - 1);
16728 while ((mfsvc
= uu_list_walk_next(svcs
)) != NULL
) {
16729 if (strcmp(mfsvc
->sc_name
, svcn
) == 0)
16732 uu_list_walk_end(svcs
);
16734 if (mfsvc
== NULL
) {
16735 internal_bundle_free(b
);
16739 ilist
= mfsvc
->sc_u
.sc_service
.sc_service_instances
;
16740 if ((insts
= uu_list_walk_start(ilist
, 0)) == NULL
) {
16741 internal_bundle_free(b
);
16745 while ((mfinst
= uu_list_walk_next(insts
)) != NULL
) {
16747 * Remove the instance from the instances list.
16748 * The unaccounted for instances will be removed
16749 * from the service once all manifests are
16752 (void) remove_string(instances
,
16757 uu_list_walk_end(insts
);
16758 internal_bundle_free(b
);
16760 return (rminstcnt
);
16764 * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16765 * 'false' to indicate there's no manifest file(s) found for the service.
16768 svc_add_no_support(scf_service_t
*svc
)
16772 /* Add no support */
16774 if (addpg(SCF_PG_MANIFESTFILES
, SCF_GROUP_FRAMEWORK
))
16777 pname
= uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES
, SUPPORTPROP
);
16779 uu_die(gettext("Out of memory.\n"));
16781 (void) lscf_addpropvalue(pname
, "boolean:", "0");
16788 * This function handles all upgrade scenarios for a service that doesn't have
16789 * SCF_PG_MANIFESTFILES pg. The function creates and populates
16790 * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16791 * manifest(s) mapping. Manifests under supported directories are inventoried
16792 * and a property is added for each file that delivers configuration to the
16793 * service. A service that has no corresponding manifest files (deleted) are
16794 * removed from repository.
16796 * Unsupported services:
16798 * A service is considered unsupported if there is no corresponding manifest
16799 * in the supported directories for that service and the service isn't in the
16800 * history file list. The history file, MFSTHISTFILE, contains a list of all
16801 * services and instances that were delivered by Solaris before the introduction
16802 * of the SCF_PG_MANIFESTFILES property group. The history file also contains
16803 * the path to the manifest file that defined the service or instance.
16805 * Another type of unsupported services is 'handcrafted' services,
16806 * programmatically created services or services created by dependent entries
16807 * in other manifests. A handcrafted service is identified by its lack of any
16808 * instance containing last-import snapshot which is created during svccfg
16811 * This function sets a flag for unsupported services by setting services'
16812 * SCF_PG_MANIFESTFILES/support property to false.
16815 upgrade_svc_mfst_connection(scf_service_t
*svc
, const char *svcname
)
16817 service_manifest_t
*elem
;
16818 uu_list_walk_t
*mfwalk
;
16819 string_list_t
*mfile
;
16820 uu_list_t
*instances
;
16826 * Since there's no guarantee manifests under /var are available during
16827 * early import, don't perform any upgrade during early import.
16832 if (service_manifest_tree
== NULL
) {
16833 create_manifest_tree();
16837 * Find service's supporting manifest(s) after
16838 * stripping off the svc:/ prefix that is part
16839 * of the fmri that is not used in the service
16840 * manifest bundle list.
16842 sname
= svcname
+ strlen(SCF_FMRI_SVC_PREFIX
) +
16843 strlen(SCF_FMRI_SERVICE_PREFIX
);
16844 elem
= find_add_svc_mfst(sname
, NULL
);
16845 if (elem
== NULL
) {
16848 * A handcrafted service, one that has no instance containing
16849 * last-import snapshot, should get unsupported flag.
16851 instances
= create_instance_list(svc
, 1);
16852 if (instances
== NULL
) {
16853 uu_warn(gettext("Unable to create instance list %s\n"),
16858 if (uu_list_numnodes(instances
) == 0) {
16859 svc_add_no_support(svc
);
16864 * If the service is in the history file, and its supporting
16865 * manifests are not found, we can safely delete the service
16866 * because its manifests are removed from the system.
16868 * Services not found in the history file are not delivered by
16869 * Solaris and/or delivered outside supported directories, set
16870 * unsupported flag for these services.
16872 r
= check_mfst_history(svcname
);
16877 /* Set unsupported flag for service */
16878 svc_add_no_support(svc
);
16880 /* Delete the service */
16881 teardown_service(svc
, svcname
);
16888 * Walk through the list of manifests and add them
16891 * Create a manifestfiles pg and add the property.
16893 mfwalk
= uu_list_walk_start(elem
->mfstlist
, 0);
16894 if (mfwalk
== NULL
)
16898 r
= addpg(SCF_PG_MANIFESTFILES
, SCF_GROUP_FRAMEWORK
);
16904 while ((mfile
= uu_list_walk_next(mfwalk
)) != NULL
) {
16905 pname
= uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES
,
16906 mhash_filename_to_propname(mfile
->str
, 0));
16908 uu_die(gettext("Out of memory.\n"));
16910 (void) lscf_addpropvalue(pname
, "astring:", mfile
->str
);
16913 uu_list_walk_end(mfwalk
);
16919 * Take a service and process the manifest file entires to see if
16920 * there is continued support for the service and instances. If
16921 * not cleanup as appropriate.
16923 * If a service does not have a manifest files entry flag it for
16924 * upgrade and return.
16926 * For each manifestfiles property check if the manifest file is
16927 * under the supported /lib/svc/manifest or /var/svc/manifest path
16928 * and if not then return immediately as this service is not supported
16929 * by the cleanup mechanism and should be ignored.
16931 * For each manifest file that is supported, check to see if the
16932 * file exists. If not then remove the manifest file property
16933 * from the service and the smf/manifest hash table. If the manifest
16934 * file exists then verify that it supports the instances that are
16935 * part of the service.
16937 * Once all manifest files have been accounted for remove any instances
16938 * that are no longer supported in the service.
16941 * 0 - Successfully processed the service
16942 * non-zero - failed to process the service
16944 * On most errors, will just return to wait and get the next service,
16945 * unless in case of unable to create the needed structures which is
16946 * most likely a fatal error that is not going to be recoverable.
16949 lscf_service_cleanup(void *act
, scf_walkinfo_t
*wip
)
16951 struct mpg_mfile
*mpntov
= NULL
;
16952 struct mpg_mfile
**mpvarry
= NULL
;
16953 scf_service_t
*svc
;
16954 scf_propertygroup_t
*mpg
;
16955 scf_property_t
*mp
;
16958 scf_instance_t
*instance
;
16959 uu_list_walk_t
*insts
;
16960 uu_list_t
*instances
= NULL
;
16961 boolean_t activity
= (boolean_t
)act
;
16962 char *mpnbuf
= NULL
;
16963 char *mpvbuf
= NULL
;
16965 int mfstcnt
, rminstct
, instct
, mfstmax
;
16969 assert(g_hndl
!= NULL
);
16970 assert(wip
->svc
!= NULL
);
16971 assert(wip
->fmri
!= NULL
);
16975 mpg
= scf_pg_create(g_hndl
);
16976 mp
= scf_property_create(g_hndl
);
16977 mi
= scf_iter_create(g_hndl
);
16978 mv
= scf_value_create(g_hndl
);
16979 instance
= scf_instance_create(g_hndl
);
16981 if (mpg
== NULL
|| mp
== NULL
|| mi
== NULL
|| mv
== NULL
||
16982 instance
== NULL
) {
16983 uu_warn(gettext("Unable to create the supporting entities\n"));
16984 uu_warn(gettext("scf error is : %s\n"),
16985 scf_strerror(scf_error()));
16990 * Get the manifestfiles property group to be parsed for
16993 if (scf_service_get_pg(svc
, SCF_PG_MANIFESTFILES
, mpg
) != SCF_SUCCESS
) {
16994 switch (scf_error()) {
16995 case SCF_ERROR_NOT_FOUND
:
16996 upgrade_svc_mfst_connection(svc
, wip
->fmri
);
16998 case SCF_ERROR_DELETED
:
16999 case SCF_ERROR_CONNECTION_BROKEN
:
17002 case SCF_ERROR_HANDLE_MISMATCH
:
17003 case SCF_ERROR_NOT_BOUND
:
17004 case SCF_ERROR_NOT_SET
:
17006 bad_error("scf_iter_pg_properties",
17014 * Iterate through each of the manifestfiles properties
17015 * to determine what manifestfiles are available.
17017 * If a manifest file is supported then increment the
17018 * count and therefore the service is safe.
17020 if (scf_iter_pg_properties(mi
, mpg
) != 0) {
17021 switch (scf_error()) {
17022 case SCF_ERROR_DELETED
:
17023 case SCF_ERROR_CONNECTION_BROKEN
:
17026 case SCF_ERROR_HANDLE_MISMATCH
:
17027 case SCF_ERROR_NOT_BOUND
:
17028 case SCF_ERROR_NOT_SET
:
17030 bad_error("scf_iter_pg_properties",
17036 mfstmax
= MFSTFILE_MAX
;
17037 mpvarry
= safe_malloc(sizeof (struct mpg_file
*) * MFSTFILE_MAX
);
17038 while ((r
= scf_iter_next_property(mi
, mp
)) != 0) {
17040 bad_error(gettext("Unable to iterate through "
17041 "manifestfiles properties : %s"),
17044 mpntov
= safe_malloc(sizeof (struct mpg_mfile
));
17045 mpnbuf
= safe_malloc(max_scf_name_len
+ 1);
17046 mpvbuf
= safe_malloc(max_scf_value_len
+ 1);
17047 mpntov
->mpg
= mpnbuf
;
17048 mpntov
->mfile
= mpvbuf
;
17049 mpntov
->access
= 1;
17050 if (scf_property_get_name(mp
, mpnbuf
,
17051 max_scf_name_len
+ 1) < 0) {
17052 uu_warn(gettext("Unable to get manifest file "
17053 "property : %s\n"),
17054 scf_strerror(scf_error()));
17056 switch (scf_error()) {
17057 case SCF_ERROR_DELETED
:
17058 case SCF_ERROR_CONNECTION_BROKEN
:
17059 r
= scferror2errno(scf_error());
17062 case SCF_ERROR_HANDLE_MISMATCH
:
17063 case SCF_ERROR_NOT_BOUND
:
17064 case SCF_ERROR_NOT_SET
:
17066 bad_error("scf_iter_pg_properties",
17072 * The support property is a boolean value that indicates
17073 * if the service is supported for manifest file deletion.
17074 * Currently at this time there is no code that sets this
17075 * value to true. So while we could just let this be caught
17076 * by the support check below, in the future this by be set
17077 * to true and require processing. So for that, go ahead
17078 * and check here, and just return if false. Otherwise,
17079 * fall through expecting that other support checks will
17080 * handle the entries.
17082 if (strcmp(mpnbuf
, SUPPORTPROP
) == 0) {
17085 if (scf_property_get_value(mp
, mv
) != 0 ||
17086 scf_value_get_boolean(mv
, &support
) != 0) {
17087 uu_warn(gettext("Unable to get the manifest "
17088 "support value: %s\n"),
17089 scf_strerror(scf_error()));
17091 switch (scf_error()) {
17092 case SCF_ERROR_DELETED
:
17093 case SCF_ERROR_CONNECTION_BROKEN
:
17094 r
= scferror2errno(scf_error());
17097 case SCF_ERROR_HANDLE_MISMATCH
:
17098 case SCF_ERROR_NOT_BOUND
:
17099 case SCF_ERROR_NOT_SET
:
17101 bad_error("scf_iter_pg_properties",
17106 if (support
== B_FALSE
)
17111 * Anything with a manifest outside of the supported
17112 * directories, immediately bail out because that makes
17113 * this service non-supported. We don't even want
17114 * to do instance processing in this case because the
17115 * instances could be part of the non-supported manifest.
17117 if (strncmp(mpnbuf
, LIBSVC_PR
, strlen(LIBSVC_PR
)) != 0) {
17119 * Manifest is not in /lib/svc, so we need to
17120 * consider the /var/svc case.
17122 if (strncmp(mpnbuf
, VARSVC_PR
,
17123 strlen(VARSVC_PR
)) != 0 || IGNORE_VAR
) {
17125 * Either the manifest is not in /var/svc or
17126 * /var is not yet mounted. We ignore the
17127 * manifest either because it is not in a
17128 * standard location or because we cannot
17129 * currently access the manifest.
17136 * Get the value to of the manifest file for this entry
17137 * for access verification and instance support
17138 * verification if it still exists.
17140 * During Early Manifest Import if the manifest is in
17141 * /var/svc then it may not yet be available for checking
17142 * so we must determine if /var/svc is available. If not
17143 * then defer until Late Manifest Import to cleanup.
17145 if (scf_property_get_value(mp
, mv
) != 0) {
17146 uu_warn(gettext("Unable to get the manifest file "
17148 scf_strerror(scf_error()));
17150 switch (scf_error()) {
17151 case SCF_ERROR_DELETED
:
17152 case SCF_ERROR_CONNECTION_BROKEN
:
17153 r
= scferror2errno(scf_error());
17156 case SCF_ERROR_HANDLE_MISMATCH
:
17157 case SCF_ERROR_NOT_BOUND
:
17158 case SCF_ERROR_NOT_SET
:
17160 bad_error("scf_property_get_value",
17165 if (scf_value_get_astring(mv
, mpvbuf
,
17166 max_scf_value_len
+ 1) < 0) {
17167 uu_warn(gettext("Unable to get the manifest "
17169 scf_strerror(scf_error()));
17171 switch (scf_error()) {
17172 case SCF_ERROR_DELETED
:
17173 case SCF_ERROR_CONNECTION_BROKEN
:
17174 r
= scferror2errno(scf_error());
17177 case SCF_ERROR_HANDLE_MISMATCH
:
17178 case SCF_ERROR_NOT_BOUND
:
17179 case SCF_ERROR_NOT_SET
:
17181 bad_error("scf_value_get_astring",
17186 mpvarry
[mfstcnt
] = mpntov
;
17190 * Check for the need to reallocate array
17192 if (mfstcnt
>= (mfstmax
- 1)) {
17193 struct mpg_mfile
**newmpvarry
;
17195 mfstmax
= mfstmax
* 2;
17196 newmpvarry
= reallocarray(mpvarry
, mfstmax
,
17197 sizeof (struct mpg_mfile
*));
17199 if (newmpvarry
== NULL
)
17202 mpvarry
= newmpvarry
;
17205 mpvarry
[mfstcnt
] = NULL
;
17208 for (index
= 0; mpvarry
[index
]; index
++) {
17209 mpntov
= mpvarry
[index
];
17212 * Check to see if the manifestfile is accessable, if so hand
17213 * this service and manifestfile off to be processed for
17214 * instance support.
17216 mpnbuf
= mpntov
->mpg
;
17217 mpvbuf
= mpntov
->mfile
;
17218 if (access(mpvbuf
, F_OK
) != 0) {
17219 mpntov
->access
= 0;
17222 /* Remove the entry from the service */
17224 pgpropbuf
= uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES
,
17226 if (pgpropbuf
== NULL
)
17227 uu_die(gettext("Out of memory.\n"));
17229 lscf_delprop(pgpropbuf
);
17232 uu_free(pgpropbuf
);
17237 * If mfstcnt is 0, none of the manifests that supported the service
17238 * existed so remove the service.
17240 if (mfstcnt
== 0) {
17241 teardown_service(svc
, wip
->fmri
);
17247 int nosvcsupport
= 0;
17250 * If the list of service instances is NULL then
17253 instances
= create_instance_list(svc
, 1);
17254 if (instances
== NULL
) {
17255 uu_warn(gettext("Unable to create instance list %s\n"),
17260 rminstct
= uu_list_numnodes(instances
);
17263 for (index
= 0; mpvarry
[index
]; index
++) {
17264 mpntov
= mpvarry
[index
];
17265 if (mpntov
->access
== 0)
17268 mpnbuf
= mpntov
->mpg
;
17269 mpvbuf
= mpntov
->mfile
;
17270 r
= check_instance_support(mpvbuf
, wip
->fmri
,
17279 if (instct
&& instct
== rminstct
&& nosvcsupport
== mfstcnt
) {
17280 teardown_service(svc
, wip
->fmri
);
17287 * If there are instances left on the instance list, then
17288 * we must remove them.
17290 if (instances
!= NULL
&& uu_list_numnodes(instances
)) {
17293 insts
= uu_list_walk_start(instances
, 0);
17294 while ((sp
= uu_list_walk_next(insts
)) != NULL
) {
17296 * Remove the instance from the instances list.
17298 safe_printf(gettext("Delete instance %s from "
17299 "service %s\n"), sp
->str
, wip
->fmri
);
17300 if (scf_service_get_instance(svc
, sp
->str
,
17301 instance
) != SCF_SUCCESS
) {
17302 (void) uu_warn("scf_error - %s\n",
17303 scf_strerror(scf_error()));
17308 (void) disable_instance(instance
);
17310 (void) lscf_instance_delete(instance
, 1);
17312 scf_instance_destroy(instance
);
17313 uu_list_walk_end(insts
);
17318 struct mpg_mfile
*fmpntov
;
17320 for (index
= 0; mpvarry
[index
]; index
++) {
17321 fmpntov
= mpvarry
[index
];
17322 if (fmpntov
->mpg
== mpnbuf
)
17324 free(fmpntov
->mpg
);
17326 if (fmpntov
->mfile
== mpvbuf
)
17328 free(fmpntov
->mfile
);
17330 if (fmpntov
== mpntov
)
17341 scf_pg_destroy(mpg
);
17342 scf_property_destroy(mp
);
17343 scf_iter_destroy(mi
);
17344 scf_value_destroy(mv
);
17350 * Take the service and search for the manifestfiles property
17351 * in each of the property groups. If the manifest file
17352 * associated with the property does not exist then remove
17353 * the property group.
17356 lscf_hash_cleanup()
17358 scf_service_t
*svc
;
17359 scf_scope_t
*scope
;
17360 scf_propertygroup_t
*pg
;
17361 scf_property_t
*prop
;
17364 char *pgname
= NULL
;
17365 char *mfile
= NULL
;
17368 svc
= scf_service_create(g_hndl
);
17369 scope
= scf_scope_create(g_hndl
);
17370 pg
= scf_pg_create(g_hndl
);
17371 prop
= scf_property_create(g_hndl
);
17372 val
= scf_value_create(g_hndl
);
17373 iter
= scf_iter_create(g_hndl
);
17374 if (pg
== NULL
|| prop
== NULL
|| val
== NULL
|| iter
== NULL
||
17375 svc
== NULL
|| scope
== NULL
) {
17376 uu_warn(gettext("Unable to create a property group, or "
17378 uu_warn("%s\n", pg
== NULL
? "pg is NULL" :
17380 uu_warn("%s\n", prop
== NULL
? "prop is NULL" :
17381 "prop is not NULL");
17382 uu_warn("%s\n", val
== NULL
? "val is NULL" :
17383 "val is not NULL");
17384 uu_warn("%s\n", iter
== NULL
? "iter is NULL" :
17385 "iter is not NULL");
17386 uu_warn("%s\n", svc
== NULL
? "svc is NULL" :
17387 "svc is not NULL");
17388 uu_warn("%s\n", scope
== NULL
? "scope is NULL" :
17389 "scope is not NULL");
17390 uu_warn(gettext("scf error is : %s\n"),
17391 scf_strerror(scf_error()));
17395 if (scf_handle_get_scope(g_hndl
, SCF_SCOPE_LOCAL
, scope
) != 0) {
17396 switch (scf_error()) {
17397 case SCF_ERROR_CONNECTION_BROKEN
:
17398 case SCF_ERROR_NOT_FOUND
:
17401 case SCF_ERROR_HANDLE_MISMATCH
:
17402 case SCF_ERROR_NOT_BOUND
:
17403 case SCF_ERROR_INVALID_ARGUMENT
:
17405 bad_error("scf_handle_get_scope", scf_error());
17409 if (scf_scope_get_service(scope
, HASH_SVC
, svc
) != 0) {
17410 uu_warn(gettext("Unable to process the hash service, %s\n"),
17415 pgname
= safe_malloc(max_scf_name_len
+ 1);
17416 mfile
= safe_malloc(max_scf_value_len
+ 1);
17418 if (scf_iter_service_pgs(iter
, svc
) != SCF_SUCCESS
) {
17419 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17420 scf_strerror(scf_error()));
17424 while ((r
= scf_iter_next_pg(iter
, pg
)) != 0) {
17428 if (scf_pg_get_name(pg
, pgname
, max_scf_name_len
+ 1) < 0) {
17429 switch (scf_error()) {
17430 case SCF_ERROR_DELETED
:
17433 case SCF_ERROR_CONNECTION_BROKEN
:
17434 return (ECONNABORTED
);
17436 case SCF_ERROR_NOT_SET
:
17437 case SCF_ERROR_NOT_BOUND
:
17439 bad_error("scf_pg_get_name", scf_error());
17443 if (strncmp(pgname
, VARSVC_PR
, strlen(VARSVC_PR
)) == 0)
17448 * If unable to get the property continue as this is an
17449 * entry that has no location to check against.
17451 if (scf_pg_get_property(pg
, MFSTFILEPR
, prop
) != SCF_SUCCESS
) {
17455 if (scf_property_get_value(prop
, val
) != SCF_SUCCESS
) {
17456 uu_warn(gettext("Unable to get value from %s\n"),
17459 switch (scf_error()) {
17460 case SCF_ERROR_DELETED
:
17461 case SCF_ERROR_CONSTRAINT_VIOLATED
:
17462 case SCF_ERROR_NOT_FOUND
:
17463 case SCF_ERROR_NOT_SET
:
17466 case SCF_ERROR_CONNECTION_BROKEN
:
17467 r
= scferror2errno(scf_error());
17470 case SCF_ERROR_HANDLE_MISMATCH
:
17471 case SCF_ERROR_NOT_BOUND
:
17473 bad_error("scf_property_get_value",
17478 if (scf_value_get_astring(val
, mfile
, max_scf_value_len
+ 1)
17480 uu_warn(gettext("Unable to get astring from %s : %s\n"),
17481 pgname
, scf_strerror(scf_error()));
17483 switch (scf_error()) {
17484 case SCF_ERROR_NOT_SET
:
17485 case SCF_ERROR_TYPE_MISMATCH
:
17489 bad_error("scf_value_get_astring", scf_error());
17493 if (access(mfile
, F_OK
) == 0)
17496 (void) scf_pg_delete(pg
);
17500 scf_scope_destroy(scope
);
17501 scf_service_destroy(svc
);
17502 scf_pg_destroy(pg
);
17503 scf_property_destroy(prop
);
17504 scf_value_destroy(val
);
17505 scf_iter_destroy(iter
);
17512 #ifndef NATIVE_BUILD
17514 CPL_MATCH_FN(complete_select
)
17516 const char *arg0
, *arg1
, *arg1end
;
17517 int word_start
, err
= 0, r
;
17523 arg0
= line
+ strspn(line
, " \t");
17524 assert(strncmp(arg0
, "select", sizeof ("select") - 1) == 0);
17526 arg1
= arg0
+ sizeof ("select") - 1;
17527 arg1
+= strspn(arg1
, " \t");
17528 word_start
= arg1
- line
;
17530 arg1end
= arg1
+ strcspn(arg1
, " \t");
17531 if (arg1end
< line
+ word_end
)
17534 len
= line
+ word_end
- arg1
;
17536 buf
= safe_malloc(max_scf_name_len
+ 1);
17538 if (cur_snap
!= NULL
) {
17540 } else if (cur_inst
!= NULL
) {
17542 } else if (cur_svc
!= NULL
) {
17543 scf_instance_t
*inst
;
17546 if ((inst
= scf_instance_create(g_hndl
)) == NULL
||
17547 (iter
= scf_iter_create(g_hndl
)) == NULL
)
17550 if (scf_iter_service_instances(iter
, cur_svc
) != 0)
17554 r
= scf_iter_next_instance(iter
, inst
);
17560 if (scf_instance_get_name(inst
, buf
,
17561 max_scf_name_len
+ 1) < 0)
17564 if (strncmp(buf
, arg1
, len
) == 0) {
17565 err
= cpl_add_completion(cpl
, line
, word_start
,
17566 word_end
, buf
+ len
, "", " ");
17572 scf_iter_destroy(iter
);
17573 scf_instance_destroy(inst
);
17577 scf_service_t
*svc
;
17580 assert(cur_scope
!= NULL
);
17582 if ((svc
= scf_service_create(g_hndl
)) == NULL
||
17583 (iter
= scf_iter_create(g_hndl
)) == NULL
)
17586 if (scf_iter_scope_services(iter
, cur_scope
) != 0)
17590 r
= scf_iter_next_service(iter
, svc
);
17596 if (scf_service_get_name(svc
, buf
,
17597 max_scf_name_len
+ 1) < 0)
17600 if (strncmp(buf
, arg1
, len
) == 0) {
17601 err
= cpl_add_completion(cpl
, line
, word_start
,
17602 word_end
, buf
+ len
, "", " ");
17608 scf_iter_destroy(iter
);
17609 scf_service_destroy(svc
);
17616 CPL_MATCH_FN(complete_command
)
17618 uint32_t scope
= 0;
17620 if (cur_snap
!= NULL
)
17622 else if (cur_inst
!= NULL
)
17624 else if (cur_svc
!= NULL
)
17629 return (scope
? add_cmd_matches(cpl
, line
, word_end
, scope
) : 0);
17631 #endif /* NATIVE_BUILD */