Merge commit 'b1e7e97d3b60469b243b3b2e22c7d8cbd11c7c90'
[unleashed.git] / usr / src / cmd / svc / svccfg / svccfg_libscf.c
blob5a094c5a3db9f85469f6fe0f41f59e5431302206
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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.
31 #include <alloca.h>
32 #include <assert.h>
33 #include <ctype.h>
34 #include <door.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <fnmatch.h>
38 #include <inttypes.h>
39 #include <libintl.h>
40 #include <libnvpair.h>
41 #include <libscf.h>
42 #include <libscf_priv.h>
43 #include <libtecla.h>
44 #include <libuutil.h>
45 #include <limits.h>
46 #include <locale.h>
47 #include <stdarg.h>
48 #include <string.h>
49 #include <strings.h>
50 #include <time.h>
51 #include <unistd.h>
52 #include <wait.h>
53 #include <poll.h>
55 #include <libxml/tree.h>
57 #include <sys/param.h>
59 #include <sys/stat.h>
60 #include <sys/mman.h>
62 #include "svccfg.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\\>=\"()"
75 #define HASH_SIZE 16
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.
107 struct entity_elts {
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;
119 xmlNodePtr template;
123 * Likewise for property_group elements.
125 struct pg_elts {
126 xmlNodePtr stability;
127 xmlNodePtr propvals;
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.
143 struct params_elts {
144 xmlNodePtr paramval;
145 xmlNodePtr parameter;
149 * This structure is for snaplevel lists. They are convenient because libscf
150 * only allows traversing snaplevels in one direction.
152 struct snaplevel {
153 uu_list_node_t list_node;
154 scf_snaplevel_t *sl;
158 * This is used for communication between lscf_service_export and
159 * export_callback.
161 struct export_args {
162 const char *filename;
163 int flags;
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;
173 uu_list_t *mfstlist;
174 size_t mfstlist_sz;
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
183 * been checked.
185 struct mpg_mfile {
186 char *mpg;
187 char *mfile;
188 int access;
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;
287 /* export globals */
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[] = {
303 "start",
304 "inetd_start",
305 NULL
308 static struct uri_scheme {
309 const char *scheme;
310 const char *protocol;
311 } uri_scheme[] = {
312 { "mailto", "smtp" },
313 { "snmp", "snmp" },
314 { "syslog", "syslog" },
315 { NULL, NULL }
317 #define URI_SCHEME_NUM ((sizeof (uri_scheme) / \
318 sizeof (struct uri_scheme)) - 1)
320 static int
321 check_uri_scheme(const char *scheme)
323 int i;
325 for (i = 0; uri_scheme[i].scheme != NULL; ++i) {
326 if (strcmp(scheme, uri_scheme[i].scheme) == 0)
327 return (i);
330 return (-1);
333 static int
334 check_uri_protocol(const char *p)
336 int i;
338 for (i = 0; uri_scheme[i].protocol != NULL; ++i) {
339 if (strcmp(p, uri_scheme[i].protocol) == 0)
340 return (i);
343 return (-1);
347 * For unexpected libscf errors.
349 #ifdef NDEBUG
351 static void scfdie(void) __NORETURN;
353 static void
354 scfdie(void)
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"),
362 scf_strerror(err));
365 #else
367 #define scfdie() scfdie_lineno(__LINE__)
369 static void
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));
381 #endif
383 static void
384 scfwarn(void)
386 warn(gettext("Unexpected libscf error: %s.\n"),
387 scf_strerror(scf_error()));
391 * Clear a field of a structure.
393 static int
394 clear_int(void *a, void *b)
396 /* LINTED */
397 *(int *)((char *)a + (size_t)b) = 0;
399 return (UU_WALK_NEXT);
402 static int
403 scferror2errno(scf_error_t err)
405 switch (err) {
406 case SCF_ERROR_BACKEND_ACCESS:
407 return (EACCES);
409 case SCF_ERROR_BACKEND_READONLY:
410 return (EROFS);
412 case SCF_ERROR_CONNECTION_BROKEN:
413 return (ECONNABORTED);
415 case SCF_ERROR_CONSTRAINT_VIOLATED:
416 case SCF_ERROR_INVALID_ARGUMENT:
417 return (EINVAL);
419 case SCF_ERROR_DELETED:
420 return (ECANCELED);
422 case SCF_ERROR_EXISTS:
423 return (EEXIST);
425 case SCF_ERROR_NO_MEMORY:
426 return (ENOMEM);
428 case SCF_ERROR_NO_RESOURCES:
429 return (ENOSPC);
431 case SCF_ERROR_NOT_FOUND:
432 return (ENOENT);
434 case SCF_ERROR_PERMISSION_DENIED:
435 return (EPERM);
437 default:
438 #ifndef NDEBUG
439 (void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
440 __FILE__, __LINE__, err);
441 #else
442 (void) fprintf(stderr, "Unknown libscf error %d.\n", err);
443 #endif
444 abort();
445 /* NOTREACHED */
449 static int
450 entity_get_pg(void *ent, int issvc, const char *name,
451 scf_propertygroup_t *pg)
453 if (issvc)
454 return (scf_service_get_pg(ent, name, pg));
455 else
456 return (scf_instance_get_pg(ent, name, pg));
459 static void
460 entity_destroy(void *ent, int issvc)
462 if (issvc)
463 scf_service_destroy(ent);
464 else
465 scf_instance_destroy(ent);
468 static int
469 get_pg(const char *pg_name, scf_propertygroup_t *pg)
471 int ret;
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);
477 else
478 ret = scf_service_get_pg(cur_svc, pg_name, pg);
480 return (ret);
484 * Find a snaplevel in a snapshot. If get_svc is true, find the service
485 * snaplevel. Otherwise find the instance snaplevel.
487 * Returns
488 * 0 - success
489 * ECONNABORTED - repository connection broken
490 * ECANCELED - instance containing snap was deleted
491 * ENOENT - snap has no snaplevels
492 * - requested snaplevel not found
494 static int
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:
507 default:
508 bad_error("scf_snapshot_get_base_snaplevel",
509 scf_error());
513 for (;;) {
514 ssize_t ssz;
516 ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
517 if (ssz >= 0) {
518 if (!get_svc)
519 return (0);
520 } else {
521 switch (scf_error()) {
522 case SCF_ERROR_CONSTRAINT_VIOLATED:
523 if (get_svc)
524 return (0);
525 break;
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:
533 default:
534 bad_error("scf_snaplevel_get_instance_name",
535 scf_error());
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:
550 default:
551 bad_error("scf_snaplevel_get_next_snaplevel",
552 scf_error());
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.
571 * Returns
572 * 0 - success
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
579 static int
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)
584 int r;
586 if (issvc) {
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:
597 default:
598 bad_error("scf_iter_service_instances",
599 scf_error());
603 for (;;) {
604 r = scf_iter_next_instance(iter, inst);
605 if (r == 0) {
606 if (scf_service_get_pg(ent, name, pg) == 0)
607 return (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:
619 default:
620 bad_error("scf_service_get_pg",
621 scf_error());
624 if (r != 1) {
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:
634 default:
635 bad_error("scf_iter_next_instance",
636 scf_error());
640 if (scf_instance_get_snapshot(inst, snap_running,
641 snap) == 0)
642 break;
644 switch (scf_error()) {
645 case SCF_ERROR_NOT_FOUND:
646 case SCF_ERROR_DELETED:
647 continue;
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:
656 default:
657 bad_error("scf_instance_get_snapshot",
658 scf_error());
661 } else {
662 if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
663 switch (scf_error()) {
664 case SCF_ERROR_NOT_FOUND:
665 break;
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:
675 default:
676 bad_error("scf_instance_get_snapshot",
677 scf_error());
680 if (scf_instance_get_pg(ent, name, pg) == 0)
681 return (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:
693 default:
694 bad_error("scf_instance_get_pg", scf_error());
699 r = get_snaplevel(snap, issvc, snpl);
700 switch (r) {
701 case 0:
702 break;
704 case ECONNABORTED:
705 case ECANCELED:
706 return (r);
708 case ENOENT:
709 return (EBADF);
711 default:
712 bad_error("get_snaplevel", r);
715 if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
716 return (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:
728 default:
729 bad_error("scf_snaplevel_get_pg", scf_error());
730 /* NOTREACHED */
735 * To be registered with atexit().
737 static void
738 remove_tempfile(void)
740 int ret;
742 if (tempfile != NULL) {
743 if (fclose(tempfile) == EOF)
744 (void) warn(gettext("Could not close temporary file"));
745 tempfile = NULL;
748 if (tempfilename[0] != '\0') {
749 do {
750 ret = remove(tempfilename);
751 } while (ret == -1 && errno == EINTR);
752 if (ret == -1)
753 warn(gettext("Could not remove temporary file"));
754 tempfilename[0] = '\0';
759 * Launch private svc.configd(8) for manipulating alternate repositories.
761 static void
762 start_private_repository(engine_state_t *est)
764 int fd, stat;
765 struct door_info info;
766 pid_t pid;
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);
779 if (fd < 0)
780 uu_die(gettext("Could not create temporary file for "
781 "repository server"));
783 (void) close(fd);
786 * 2. Launch a configd with that door, using the specified
787 * repository.
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,
792 NULL);
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"));
797 do {
798 pid = waitpid(est->sc_repo_pid, &stat, 0);
799 } while (pid == -1 && errno == EINTR);
801 if (pid == -1)
802 uu_die(gettext("Could not waitpid() for repository server"));
804 if (!WIFEXITED(stat)) {
805 uu_die(gettext("Repository server failed (status %d).\n"),
806 stat);
807 } else if (WEXITSTATUS(stat) != 0) {
808 uu_die(gettext("Repository server failed (exit %d).\n"),
809 WEXITSTATUS(stat));
813 * See if it was successful by checking if the door is a door.
816 fd = open(est->sc_repo_doorname, O_RDWR);
817 if (fd < 0)
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"));
824 if (close(fd) == -1)
825 warn(gettext("Could not close repository door"),
826 strerror(errno));
828 est->sc_repo_pid = info.di_target;
831 void
832 lscf_cleanup(void)
835 * In the case where we've launched a private svc.configd(8)
836 * instance, we must terminate our child and remove the temporary
837 * rendezvous point.
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;
848 void
849 unselect_cursnap(void)
851 void *cookie;
853 cur_level = NULL;
855 cookie = NULL;
856 while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
857 scf_snaplevel_destroy(cur_elt->sl);
858 free(cur_elt);
861 scf_snapshot_destroy(cur_snap);
862 cur_snap = NULL;
865 void
866 lscf_prep_hndl(void)
868 if (g_hndl != NULL)
869 return;
871 g_hndl = scf_handle_create(SCF_VERSION);
872 if (g_hndl == NULL)
873 scfdie();
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;
880 int ret;
882 repo_value = scf_value_create(g_hndl);
883 if (repo_value == NULL)
884 scfdie();
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) !=
890 SCF_SUCCESS)
891 scfdie();
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)
902 scfdie();
904 if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
905 scfdie();
908 static void
909 repository_teardown(void)
911 if (g_hndl != NULL) {
912 if (cur_snap != NULL)
913 unselect_cursnap();
914 scf_instance_destroy(cur_inst);
915 scf_service_destroy(cur_svc);
916 scf_scope_destroy(cur_scope);
917 scf_handle_destroy(g_hndl);
918 cur_inst = NULL;
919 cur_svc = NULL;
920 cur_scope = NULL;
921 g_hndl = NULL;
922 lscf_cleanup();
926 void
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));
943 } else {
944 est->sc_repo_filename = safe_strdup(repfile);
947 lscf_prep_hndl();
950 void
951 lscf_init()
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)) <
956 0 ||
957 (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
958 scfdie();
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
969 * value.
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),
1019 NULL, 0);
1023 static const char *
1024 prop_to_typestr(const scf_property_t *prop)
1026 scf_type_t ty;
1028 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
1029 scfdie();
1031 return (scf_type_to_string(ty));
1034 static scf_type_t
1035 string_to_type(const char *type)
1037 size_t len = strlen(type);
1038 char *buf;
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);
1045 buf[len - 1] = 0;
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)
1053 scf_value_t *v;
1054 char *dup, *nstr;
1055 size_t len;
1057 v = scf_value_create(g_hndl);
1058 if (v == NULL)
1059 scfdie();
1061 len = strlen(str);
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);
1067 return (NULL);
1070 nstr = dup = safe_strdup(str);
1071 if (dup[0] == '\"') {
1073 * Strip out the first and the last quote.
1075 dup[len - 1] = '\0';
1076 nstr = dup + 1;
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);
1084 v = NULL;
1086 free(dup);
1087 return (v);
1091 * Print str to strm, quoting double-quotes and backslashes with backslashes.
1092 * Optionally append a comment prefix ('#') to newlines ('\n').
1094 static int
1095 quote_and_print(const char *str, FILE *strm, int commentnl)
1097 const char *cp;
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
1115 * and warnings.
1117 static int
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)
1121 return (0);
1123 if (scf_error() != SCF_ERROR_NOT_FOUND)
1124 scfdie();
1126 if (g_verbose) {
1127 ssize_t len;
1128 char *fmri;
1130 len = scf_pg_to_fmri(pg, NULL, 0);
1131 if (len < 0)
1132 scfdie();
1134 fmri = safe_malloc(len + 1);
1136 if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1137 scfdie();
1139 warn(gettext("Expected property %s of property group %s is "
1140 "missing.\n"), propname, fmri);
1142 free(fmri);
1145 return (-1);
1148 static int
1149 prop_check_type(scf_property_t *prop, scf_type_t ty)
1151 scf_type_t pty;
1153 if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1154 scfdie();
1156 if (ty == pty)
1157 return (0);
1159 if (g_verbose) {
1160 ssize_t len;
1161 char *fmri;
1162 const char *tystr;
1164 len = scf_property_to_fmri(prop, NULL, 0);
1165 if (len < 0)
1166 scfdie();
1168 fmri = safe_malloc(len + 1);
1170 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1171 scfdie();
1173 tystr = scf_type_to_string(ty);
1174 if (tystr == NULL)
1175 tystr = "?";
1177 warn(gettext("Property %s is not of expected type %s.\n"),
1178 fmri, tystr);
1180 free(fmri);
1183 return (-1);
1186 static int
1187 prop_get_val(scf_property_t *prop, scf_value_t *val)
1189 scf_error_t err;
1191 if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1192 return (0);
1194 err = scf_error();
1196 if (err != SCF_ERROR_NOT_FOUND &&
1197 err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1198 err != SCF_ERROR_PERMISSION_DENIED)
1199 scfdie();
1201 if (g_verbose) {
1202 ssize_t len;
1203 char *fmri, *emsg;
1205 len = scf_property_to_fmri(prop, NULL, 0);
1206 if (len < 0)
1207 scfdie();
1209 fmri = safe_malloc(len + 1);
1211 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1212 scfdie();
1214 if (err == SCF_ERROR_NOT_FOUND)
1215 emsg = gettext("Property %s has no values; expected "
1216 "one.\n");
1217 else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1218 emsg = gettext("Property %s has multiple values; "
1219 "expected one.\n");
1220 else
1221 emsg = gettext("No permission to read property %s.\n");
1223 warn(emsg, fmri);
1225 free(fmri);
1228 return (-1);
1232 static boolean_t
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)
1237 scfdie();
1238 return (0);
1239 } else {
1240 return (1);
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.
1253 static scf_error_t
1254 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1256 char *fmri_copy;
1257 const char *sstr, *istr, *pgstr;
1258 scf_service_t *svc;
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) !=
1266 SCF_SUCCESS) {
1267 free(fmri_copy);
1268 return (SCF_ERROR_INVALID_ARGUMENT);
1271 free(fmri_copy);
1273 if (sstr == NULL || pgstr != NULL)
1274 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1276 if (istr == NULL) {
1277 svc = scf_service_create(h);
1278 if (svc == NULL)
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)
1284 scfdie();
1286 return (SCF_ERROR_NOT_FOUND);
1289 *ep = svc;
1290 *isservice = 1;
1291 } else {
1292 inst = scf_instance_create(h);
1293 if (inst == NULL)
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)
1299 scfdie();
1301 return (SCF_ERROR_NOT_FOUND);
1304 *ep = inst;
1305 *isservice = 0;
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.
1314 * Returns
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
1324 static scf_error_t
1325 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1327 char *fmri_copy;
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;
1332 scf_error_t scfe;
1334 fmri_copy = safe_strdup(fmri);
1336 if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1337 0) {
1338 free(fmri_copy);
1339 return (SCF_ERROR_INVALID_ARGUMENT);
1342 if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1343 free(fmri_copy);
1344 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1347 *ep = NULL;
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;
1353 goto out;
1356 get_scope:
1357 if (scf_handle_get_scope(h, scstr, scope) != 0) {
1358 switch (scf_error()) {
1359 case SCF_ERROR_CONNECTION_BROKEN:
1360 scfdie();
1361 /* NOTREACHED */
1363 case SCF_ERROR_NOT_FOUND:
1364 scfe = SCF_ERROR_NOT_FOUND;
1365 goto out;
1367 case SCF_ERROR_HANDLE_MISMATCH:
1368 case SCF_ERROR_NOT_BOUND:
1369 case SCF_ERROR_INVALID_ARGUMENT:
1370 default:
1371 bad_error("scf_handle_get_scope", scf_error());
1375 get_svc:
1376 if (scf_scope_get_service(scope, sstr, svc) != 0) {
1377 switch (scf_error()) {
1378 case SCF_ERROR_CONNECTION_BROKEN:
1379 scfdie();
1380 /* NOTREACHED */
1382 case SCF_ERROR_DELETED:
1383 goto get_scope;
1385 case SCF_ERROR_NOT_FOUND:
1386 break;
1388 case SCF_ERROR_HANDLE_MISMATCH:
1389 case SCF_ERROR_INVALID_ARGUMENT:
1390 case SCF_ERROR_NOT_BOUND:
1391 case SCF_ERROR_NOT_SET:
1392 default:
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:
1399 scfdie();
1400 /* NOTREACHED */
1402 case SCF_ERROR_DELETED:
1403 goto get_scope;
1405 case SCF_ERROR_PERMISSION_DENIED:
1406 case SCF_ERROR_BACKEND_READONLY:
1407 case SCF_ERROR_BACKEND_ACCESS:
1408 scfe = scf_error();
1409 goto out;
1411 case SCF_ERROR_HANDLE_MISMATCH:
1412 case SCF_ERROR_INVALID_ARGUMENT:
1413 case SCF_ERROR_NOT_BOUND:
1414 case SCF_ERROR_NOT_SET:
1415 default:
1416 bad_error("scf_scope_get_service", scf_error());
1421 if (istr == NULL) {
1422 scfe = SCF_ERROR_NONE;
1423 *ep = svc;
1424 *isservicep = 1;
1425 goto out;
1428 get_inst:
1429 if (scf_service_get_instance(svc, istr, inst) != 0) {
1430 switch (scf_error()) {
1431 case SCF_ERROR_CONNECTION_BROKEN:
1432 scfdie();
1433 /* NOTREACHED */
1435 case SCF_ERROR_DELETED:
1436 goto get_svc;
1438 case SCF_ERROR_NOT_FOUND:
1439 break;
1441 case SCF_ERROR_HANDLE_MISMATCH:
1442 case SCF_ERROR_INVALID_ARGUMENT:
1443 case SCF_ERROR_NOT_BOUND:
1444 case SCF_ERROR_NOT_SET:
1445 default:
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:
1452 scfdie();
1453 /* NOTREACHED */
1455 case SCF_ERROR_DELETED:
1456 goto get_svc;
1458 case SCF_ERROR_PERMISSION_DENIED:
1459 case SCF_ERROR_BACKEND_READONLY:
1460 case SCF_ERROR_BACKEND_ACCESS:
1461 scfe = scf_error();
1462 goto out;
1464 case SCF_ERROR_HANDLE_MISMATCH:
1465 case SCF_ERROR_INVALID_ARGUMENT:
1466 case SCF_ERROR_NOT_BOUND:
1467 case SCF_ERROR_NOT_SET:
1468 default:
1469 bad_error("scf_service_add_instance",
1470 scf_error());
1475 scfe = SCF_ERROR_NONE;
1476 *ep = inst;
1477 *isservicep = 0;
1479 out:
1480 if (*ep != inst)
1481 scf_instance_destroy(inst);
1482 if (*ep != svc)
1483 scf_service_destroy(svc);
1484 scf_scope_destroy(scope);
1485 free(fmri_copy);
1486 return (scfe);
1490 * Create or update a snapshot of inst. snap is a required scratch object.
1492 * Returns
1493 * 0 - success
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)
1500 static int
1501 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1503 again:
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:
1514 default:
1515 bad_error("_scf_snapshot_take_attach",
1516 scf_error());
1519 } else {
1520 switch (scf_error()) {
1521 case SCF_ERROR_NOT_FOUND:
1522 break;
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:
1532 default:
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:
1539 goto again;
1541 case SCF_ERROR_CONNECTION_BROKEN:
1542 case SCF_ERROR_NO_RESOURCES:
1543 case SCF_ERROR_PERMISSION_DENIED:
1544 return (scferror2errno(scf_error()));
1546 default:
1547 scfwarn();
1548 return (-1);
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",
1555 scf_error());
1560 return (0);
1563 static int
1564 refresh_running_snapshot(void *entity)
1566 scf_snapshot_t *snap;
1567 int r;
1569 if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1570 scfdie();
1571 r = take_snap(entity, snap_running, snap);
1572 scf_snapshot_destroy(snap);
1574 return (r);
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
1582 * 0 - success
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.
1590 static int
1591 refresh_entity(int isservice, void *entity, const char *fmri,
1592 scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1594 scf_error_t scfe;
1595 int r;
1597 if (!isservice) {
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) {
1607 if (g_verbose)
1608 warn(gettext("Refreshed %s.\n"), fmri);
1609 return (0);
1612 switch (scf_error()) {
1613 case SCF_ERROR_BACKEND_ACCESS:
1614 return (EACCES);
1616 case SCF_ERROR_PERMISSION_DENIED:
1617 return (EPERM);
1619 default:
1620 return (-1);
1622 } else {
1623 r = refresh_running_snapshot(entity);
1624 switch (r) {
1625 case 0:
1626 break;
1628 case ECONNABORTED:
1629 case ECANCELED:
1630 case EPERM:
1631 case ENOSPC:
1632 break;
1634 default:
1635 bad_error("refresh_running_snapshot",
1636 scf_error());
1639 return (r);
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:
1649 return (ECANCELED);
1651 case SCF_ERROR_HANDLE_MISMATCH:
1652 case SCF_ERROR_NOT_BOUND:
1653 case SCF_ERROR_NOT_SET:
1654 default:
1655 bad_error("scf_iter_service_instances", scf_error());
1659 for (;;) {
1660 r = scf_iter_next_instance(iter, inst);
1661 if (r == 0)
1662 break;
1663 if (r != 1) {
1664 switch (scf_error()) {
1665 case SCF_ERROR_CONNECTION_BROKEN:
1666 return (ECONNABORTED);
1668 case SCF_ERROR_DELETED:
1669 return (ECANCELED);
1671 case SCF_ERROR_HANDLE_MISMATCH:
1672 case SCF_ERROR_NOT_BOUND:
1673 case SCF_ERROR_NOT_SET:
1674 case SCF_ERROR_INVALID_ARGUMENT:
1675 default:
1676 bad_error("scf_iter_next_instance",
1677 scf_error());
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);
1689 switch (r) {
1690 case 0:
1691 continue;
1693 case ECONNABORTED:
1694 case ECANCELED:
1695 case EPERM:
1696 case ENOSPC:
1697 break;
1698 default:
1699 bad_error("refresh_running_snapshot",
1700 scf_error());
1703 return (r);
1707 if (_smf_refresh_instance_i(inst) == 0) {
1708 if (g_verbose) {
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"),
1714 fmri, name_buf);
1716 } else {
1717 if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1718 g_verbose) {
1719 scfe = scf_error();
1721 if (scf_instance_to_fmri(inst, name_buf,
1722 max_scf_name_len + 1) < 0)
1723 (void) strcpy(name_buf, "?");
1725 warn(gettext(
1726 "Refresh of %s:%s failed: %s.\n"), fmri,
1727 name_buf, scf_strerror(scfe));
1732 return (0);
1735 static void
1736 private_refresh(void)
1738 scf_instance_t *pinst = NULL;
1739 scf_iter_t *piter = NULL;
1740 ssize_t fmrilen;
1741 size_t bufsz;
1742 char *fmribuf;
1743 void *ent;
1744 int issvc;
1745 int r;
1747 if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1748 return;
1750 assert(cur_svc != NULL);
1752 bufsz = max_scf_fmri_len + 1;
1753 fmribuf = safe_malloc(bufsz);
1754 if (cur_inst) {
1755 issvc = 0;
1756 ent = cur_inst;
1757 fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1758 } else {
1759 issvc = 1;
1760 ent = cur_svc;
1761 fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1762 if ((pinst = scf_instance_create(g_hndl)) == NULL)
1763 scfdie();
1765 if ((piter = scf_iter_create(g_hndl)) == NULL)
1766 scfdie();
1768 if (fmrilen < 0) {
1769 free(fmribuf);
1770 if (scf_error() != SCF_ERROR_DELETED)
1771 scfdie();
1773 warn(emsg_deleted);
1774 return;
1776 assert(fmrilen < bufsz);
1778 r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1779 switch (r) {
1780 case 0:
1781 break;
1783 case ECONNABORTED:
1784 warn(gettext("Could not refresh %s "
1785 "(repository connection broken).\n"), fmribuf);
1786 break;
1788 case ECANCELED:
1789 warn(emsg_deleted);
1790 break;
1792 case EPERM:
1793 warn(gettext("Could not refresh %s "
1794 "(permission denied).\n"), fmribuf);
1795 break;
1797 case ENOSPC:
1798 warn(gettext("Could not refresh %s "
1799 "(repository server out of resources).\n"),
1800 fmribuf);
1801 break;
1803 case EACCES:
1804 default:
1805 bad_error("refresh_entity", scf_error());
1808 if (issvc) {
1809 scf_instance_destroy(pinst);
1810 scf_iter_destroy(piter);
1813 free(fmribuf);
1817 static int
1818 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1820 cbp->sc_err = scferror2errno(err);
1821 return (UU_WALK_ERROR);
1824 static int
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.
1841 * For a 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.
1848 static int
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;
1856 char *lfmri = 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;
1865 value_t *vp;
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;
1888 retry_pg:
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) {
1895 lscf_select(fmri);
1896 } else {
1897 free(cur_selection);
1898 cur_selection = NULL;
1900 } else {
1901 lscf_select(fmri);
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"));
1908 goto out;
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);
1920 sc_pg = NULL;
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 "
1924 "type.\n"));
1926 goto out;
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);
1936 t_pg = NULL;
1937 if (issvc == 0) {
1938 entity_t *e = pg->sc_parent->sc_parent;
1940 fmri = e->sc_fmri;
1941 issvc = 1;
1942 goto retry_pg;
1943 } else {
1944 goto out;
1948 } else {
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
1955 * for the property.
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);
1970 vp != NULL;
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);
1976 r = UU_WALK_NEXT;
1977 goto out;
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.
1990 do_tmpl :
1991 if (t_pg != NULL &&
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);
2002 vp != NULL;
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);
2008 r = UU_WALK_NEXT;
2009 goto out;
2011 } else {
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 "
2016 "type.\n"));
2018 goto out;
2021 if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
2022 scf_tmpl_pg_destroy(t_pg);
2023 t_pg = NULL;
2024 } else {
2025 goto do_tmpl;
2030 if (issvc == 0) {
2031 scf_instance_t *i;
2032 scf_service_t *s;
2034 issvc = 1;
2035 if (lcb->sc_flags == 1) {
2036 entity_t *e = pg->sc_parent->sc_parent;
2038 fmri = e->sc_fmri;
2039 goto retry_pg;
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."));
2050 goto out;
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)
2056 goto out;
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."));
2065 goto out;
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)
2074 goto out;
2075 else
2076 fmri = (const char *)lfmri;
2078 goto retry_pg;
2081 out :
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);
2110 free(lfmri);
2112 return (r);
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.
2130 static int
2131 find_current_pg_type(void *p, void *sori)
2133 entity_t *si = sori;
2134 pgroup_t *pg = p;
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) {
2148 r = UU_WALK_NEXT;
2150 goto out;
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
2166 if (cur_svc) {
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.
2178 retry_svc:
2179 lscf_select(fmri);
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;
2187 r = UU_WALK_NEXT;
2188 goto out;
2189 } else {
2190 free(pg_type);
2192 } else {
2193 if ((t_pg == NULL) &&
2194 (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
2195 goto out;
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;
2202 r = UU_WALK_NEXT;
2203 goto out;
2208 * If type is not found at the instance level then attempt to
2209 * find the type at the service level.
2211 if (!issvc) {
2212 si = si->sc_parent;
2213 fmri = si->sc_fmri;
2214 issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2215 goto retry_svc;
2218 out :
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
2227 * those types.
2229 if (r == UU_WALK_NEXT) {
2230 scf_callback_t cb;
2232 cb.sc_service = issvc;
2233 cb.sc_source_fmri = ofmri;
2234 if (sc_pg != NULL) {
2235 cb.sc_parent = sc_pg;
2236 cb.sc_flags = 0;
2237 } else {
2238 cb.sc_parent = pg;
2239 cb.sc_flags = 1;
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());
2247 r = UU_WALK_ERROR;
2249 } else {
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);
2257 return (r);
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)
2275 static int
2276 lscf_property_import(void *v, void *pvt)
2278 property_t *p = v;
2279 scf_callback_t *lcbdata = pvt;
2280 value_t *vp;
2281 scf_transaction_t *trans = lcbdata->sc_trans;
2282 scf_transaction_entry_t *entr;
2283 scf_value_t *val;
2284 scf_type_t tp;
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);
2294 if (entr == NULL) {
2295 switch (scf_error()) {
2296 case SCF_ERROR_NO_MEMORY:
2297 return (stash_scferror(lcbdata));
2299 case SCF_ERROR_INVALID_ARGUMENT:
2300 default:
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:
2316 break;
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:
2326 default:
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:
2348 default:
2349 bad_error(
2350 "scf_transaction_property_change_type",
2351 scf_error());
2356 for (vp = uu_list_first(p->sc_property_values);
2357 vp != NULL;
2358 vp = uu_list_next(p->sc_property_values, vp)) {
2359 val = scf_value_create(g_hndl);
2360 if (val == NULL) {
2361 switch (scf_error()) {
2362 case SCF_ERROR_NO_MEMORY:
2363 return (stash_scferror(lcbdata));
2365 case SCF_ERROR_INVALID_ARGUMENT:
2366 default:
2367 bad_error("scf_value_create", scf_error());
2371 switch (tp) {
2372 case SCF_TYPE_BOOLEAN:
2373 scf_value_set_boolean(val, vp->sc_u.sc_count);
2374 break;
2375 case SCF_TYPE_COUNT:
2376 scf_value_set_count(val, vp->sc_u.sc_count);
2377 break;
2378 case SCF_TYPE_INTEGER:
2379 scf_value_set_integer(val, vp->sc_u.sc_integer);
2380 break;
2381 default:
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",
2387 scf_error());
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));
2395 break;
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)
2431 static int
2432 entity_pgroup_import(void *v, void *pvt)
2434 pgroup_t *p = v;
2435 scf_callback_t cbdata;
2436 scf_callback_t *lcbdata = pvt;
2437 void *ent = lcbdata->sc_parent;
2438 int issvc = lcbdata->sc_service;
2439 int r;
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) {
2448 goto delete_pg;
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);
2459 add_pg:
2460 if (issvc)
2461 r = scf_service_add_pg(ent, p->sc_pgroup_name,
2462 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2463 else
2464 r = scf_instance_add_pg(ent, p->sc_pgroup_name,
2465 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2466 if (r != 0) {
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)
2477 break;
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:
2494 default:
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,
2507 p->sc_pgroup_name);
2508 return (stash_scferror(lcbdata));
2510 case SCF_ERROR_NOT_FOUND:
2511 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2512 p->sc_pgroup_name);
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:
2519 default:
2520 bad_error("entity_get_pg", scf_error());
2524 if (lcbdata->sc_flags & SCI_KEEP)
2525 goto props;
2527 delete_pg:
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,
2532 p->sc_pgroup_name);
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:
2547 default:
2548 bad_error("scf_pg_delete", scf_error());
2552 if (p->sc_pgroup_delete)
2553 return (UU_WALK_NEXT);
2555 goto add_pg;
2558 props:
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,
2578 p->sc_pgroup_name);
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:
2591 default:
2592 bad_error("scf_transaction_start", scf_error());
2596 if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2597 UU_DEFAULT) != 0) {
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,
2605 p->sc_pgroup_name);
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);
2619 switch (r) {
2620 case 0:
2621 break;
2623 case ECONNABORTED:
2624 warn(gettext("Could not take %s snapshot on import "
2625 "(repository connection broken).\n"),
2626 snap_running);
2627 lcbdata->sc_err = r;
2628 return (UU_WALK_ERROR);
2629 case ECANCELED:
2630 warn(emsg_deleted);
2631 lcbdata->sc_err = r;
2632 return (UU_WALK_ERROR);
2634 case EPERM:
2635 warn(gettext("Could not take %s snapshot "
2636 "(permission denied).\n"), snap_running);
2637 lcbdata->sc_err = r;
2638 return (UU_WALK_ERROR);
2640 case ENOSPC:
2641 warn(gettext("Could not take %s snapshot"
2642 "(repository server out of resources).\n"),
2643 snap_running);
2644 lcbdata->sc_err = r;
2645 return (UU_WALK_ERROR);
2647 default:
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);
2655 return (EINVAL);
2659 r = scf_transaction_commit(imp_tx);
2660 switch (r) {
2661 case 1:
2662 r = UU_WALK_NEXT;
2663 break;
2665 case 0:
2666 warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2667 lcbdata->sc_err = EBUSY;
2668 r = UU_WALK_ERROR;
2669 break;
2671 case -1:
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);
2678 break;
2680 case SCF_ERROR_DELETED:
2681 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2682 p->sc_pgroup_name);
2683 lcbdata->sc_err = EBUSY;
2684 r = UU_WALK_ERROR;
2685 break;
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);
2691 break;
2693 case SCF_ERROR_NOT_SET:
2694 case SCF_ERROR_INVALID_ARGUMENT:
2695 case SCF_ERROR_NOT_BOUND:
2696 default:
2697 bad_error("scf_transaction_commit", scf_error());
2699 break;
2701 default:
2702 bad_error("scf_transaction_commit", r);
2705 scf_transaction_destroy_children(imp_tx);
2707 return (r);
2711 * Returns
2712 * 0 - success
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)
2727 static int
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;
2750 break;
2751 case SVCCFG_OP_APPLY :
2752 cbdata.sc_flags |= SCI_OP_APPLY;
2753 break;
2754 case SVCCFG_OP_RESTORE :
2755 cbdata.sc_flags |= SCI_OP_RESTORE;
2756 break;
2757 default :
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,
2765 UU_DEFAULT) != 0) {
2766 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2767 bad_error("uu_list_walk", uu_error());
2769 return (cbdata.sc_err);
2772 return (0);
2776 * Returns
2777 * 0 - success
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)
2792 static int
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;
2815 break;
2816 case SVCCFG_OP_APPLY :
2817 cbdata.sc_flags |= SCI_OP_APPLY;
2818 break;
2819 case SVCCFG_OP_RESTORE :
2820 cbdata.sc_flags |= SCI_OP_RESTORE;
2821 break;
2822 default :
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,
2829 UU_DEFAULT) != 0) {
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)
2848 != UU_WALK_NEXT)
2849 return (cbdata.sc_err);
2852 return (0);
2856 * Report the reasons why we can't upgrade pg2 to pg1.
2858 static void
2859 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2860 int new)
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))
2867 return;
2869 for (p1 = uu_list_first(pg1->sc_pgroup_props);
2870 p1 != NULL;
2871 p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2872 p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2873 if (p2 != NULL) {
2874 (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2875 new);
2876 continue;
2879 if (new)
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);
2883 else
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
2897 * & new.
2899 * Returns
2900 * 0 - success
2901 * EINVAL - new has a property with an invalid name or value (message emitted)
2902 * ENOMEM - out of memory
2904 static int
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;
2910 int r;
2911 int is_general;
2912 int is_protected;
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);
2921 p != NULL;
2922 p = uu_list_next(old->sc_pgroup_props, p)) {
2923 /* p is a property in the old property group. */
2925 /* Protect live properties. */
2926 is_protected = 0;
2927 if (is_general) {
2928 if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2929 0 ||
2930 strcmp(p->sc_property_name,
2931 SCF_PROPERTY_RESTARTER) == 0)
2932 is_protected = 1;
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) {
2938 new_p->sc_seen = 1;
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))
2945 continue;
2947 if (new_p->sc_property_override)
2948 goto upgrade;
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.
2958 if (new_p == NULL)
2959 continue;
2961 if (is_protected)
2962 continue;
2964 warn(gettext("Conflict upgrading %s "
2965 "(property \"%s/%s\" is missing).\n"), fmri,
2966 old->sc_pgroup_name, p->sc_property_name);
2967 continue;
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.
2975 if (is_protected)
2976 continue;
2978 if (new_p == NULL)
2979 (void) prop_equal(p, cur_p, fmri,
2980 old->sc_pgroup_name, 0);
2981 else
2982 (void) prop_equal(cur_p, new_p, fmri,
2983 old->sc_pgroup_name, 0);
2984 continue;
2987 if (is_protected) {
2988 if (speak)
2989 warn(gettext("%s: Refusing to upgrade "
2990 "\"%s/%s\" (live property).\n"), fmri,
2991 old->sc_pgroup_name, p->sc_property_name);
2992 continue;
2995 upgrade:
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. */
2999 if (speak)
3000 warn(gettext(
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);
3006 if (e == NULL)
3007 return (ENOMEM);
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);
3014 return (ECANCELED);
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);
3027 break;
3029 case SCF_ERROR_HANDLE_MISMATCH:
3030 case SCF_ERROR_NOT_BOUND:
3031 case SCF_ERROR_NOT_SET:
3032 case SCF_ERROR_INVALID_ARGUMENT:
3033 default:
3034 bad_error(
3035 "scf_transaction_property_delete",
3036 scf_error());
3039 } else {
3040 scf_callback_t ctx;
3042 if (speak)
3043 warn(gettext(
3044 "%s: Upgrading property \"%s/%s\".\n"),
3045 fmri, old->sc_pgroup_name,
3046 p->sc_property_name);
3048 ctx.sc_handle = g_hndl;
3049 ctx.sc_trans = tx;
3050 ctx.sc_flags = 0;
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);
3056 return (EINVAL);
3061 /* Go over the properties which were added. */
3062 for (new_p = uu_list_first(new->sc_pgroup_props);
3063 new_p != NULL;
3064 new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
3065 if (new_p->sc_seen)
3066 continue;
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) {
3071 scf_callback_t ctx;
3073 ctx.sc_handle = g_hndl;
3074 ctx.sc_trans = tx;
3075 ctx.sc_flags = 0;
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);
3081 return (EINVAL);
3083 continue;
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) ==
3092 0 &&
3093 strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
3094 continue;
3096 (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
3099 return (0);
3103 * Upgrade pg according to old & new.
3105 * Returns
3106 * 0 - success
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
3117 static int
3118 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
3119 pgroup_t *new, int speak, const char *fmri)
3121 int r;
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:
3136 default:
3137 bad_error("scf_transaction_start", scf_error());
3141 r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
3142 switch (r) {
3143 case 0:
3144 break;
3146 case EINVAL:
3147 case ENOMEM:
3148 scf_transaction_destroy_children(imp_tx);
3149 return (r);
3151 default:
3152 bad_error("add_upgrade_entries", r);
3155 r = scf_transaction_commit(imp_tx);
3157 scf_transaction_destroy_children(imp_tx);
3159 switch (r) {
3160 case 1:
3161 break;
3163 case 0:
3164 return (EBUSY);
3166 case -1:
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:
3179 default:
3180 bad_error("scf_transaction_commit", scf_error());
3183 default:
3184 bad_error("scf_transaction_commit", r);
3187 return (0);
3191 * Compares two entity FMRIs. Returns
3193 * 1 - equal
3194 * 0 - not equal
3195 * -1 - f1 is invalid or not an entity
3196 * -2 - f2 is invalid or not an entity
3198 static int
3199 fmri_equal(const char *f1, const char *f2)
3201 int r;
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)
3206 return (-1);
3207 if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
3208 return (-1);
3210 if (s1 == NULL || pg1 != NULL)
3211 return (-1);
3213 if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3214 return (-2);
3215 if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
3216 return (-2);
3218 if (s2 == NULL || pg2 != NULL)
3219 return (-2);
3221 r = strcmp(s1, s2);
3222 if (r != 0)
3223 return (0);
3225 if (i1 == NULL && i2 == NULL)
3226 return (1);
3228 if (i1 == NULL || i2 == NULL)
3229 return (0);
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)
3264 static int
3265 lscf_dependent_import(void *a1, void *pvt)
3267 pgroup_t *pgrp = a1;
3268 scf_callback_t *lcbdata = pvt;
3270 int isservice;
3271 int ret;
3272 scf_transaction_entry_t *e;
3273 scf_value_t *val;
3274 scf_callback_t dependent_cbdata;
3275 scf_error_t scfe;
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);
3283 switch (scfe) {
3284 case SCF_ERROR_NONE:
3285 break;
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);
3304 switch (scfe) {
3305 case SCF_ERROR_NONE:
3306 break;
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:
3321 warn(gettext(
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:
3328 default:
3329 bad_error("create_entity", scfe);
3331 break;
3333 default:
3334 bad_error("fmri_to_entity", scfe);
3337 if (lcbdata->sc_trans != NULL) {
3338 e = scf_entry_create(lcbdata->sc_handle);
3339 if (e == NULL) {
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);
3354 /* FALLTHROUGH */
3356 case SCF_ERROR_DELETED:
3357 case SCF_ERROR_CONNECTION_BROKEN:
3358 scf_entry_destroy(e);
3359 entity_destroy(dependent_cbdata.sc_parent,
3360 isservice);
3361 return (stash_scferror(lcbdata));
3363 case SCF_ERROR_EXISTS:
3364 scf_entry_destroy(e);
3365 entity_destroy(dependent_cbdata.sc_parent,
3366 isservice);
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:
3373 default:
3374 bad_error("scf_transaction_property_new",
3375 scf_error());
3379 val = scf_value_create(lcbdata->sc_handle);
3380 if (val == NULL) {
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)
3409 return (ret);
3411 if (ret != UU_WALK_ERROR)
3412 bad_error("entity_pgroup_import", ret);
3414 switch (dependent_cbdata.sc_err) {
3415 case ECANCELED:
3416 warn(gettext("%s deleted unexpectedly.\n"),
3417 pgrp->sc_pgroup_fmri);
3418 lcbdata->sc_err = EBUSY;
3419 break;
3421 case EEXIST:
3422 warn(gettext("Could not create \"%s\" dependency in %s "
3423 "(already exists).\n"), pgrp->sc_pgroup_name,
3424 pgrp->sc_pgroup_fmri);
3425 /* FALLTHROUGH */
3427 default:
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 *,
3437 const pgroup_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
3448 * are new.
3450 * Returns
3451 * 0 - success
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)
3476 static int
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;
3484 int have_cur_depts;
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. */
3492 return (0);
3494 /* Fetch the current version of the "dependents" property group. */
3495 have_cur_depts = 1;
3496 if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
3497 switch (scf_error()) {
3498 case SCF_ERROR_NOT_FOUND:
3499 break;
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:
3509 default:
3510 bad_error("entity_get_pg", scf_error());
3513 have_cur_depts = 0;
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);
3520 else
3521 r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
3522 if (r == 0) {
3523 ud_run_dpts_pg_set = 1;
3524 } else {
3525 switch (scf_error()) {
3526 case SCF_ERROR_NOT_FOUND:
3527 break;
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:
3537 default:
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
3545 * are new.
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:
3567 return (ENODEV);
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:
3575 default:
3576 bad_error("scf_iter_pg_properties",
3577 scf_error());
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,
3591 dependents);
3592 return (EBUSY);
3594 case SCF_ERROR_PERMISSION_DENIED:
3595 warn(emsg_pg_mod_perm, dependents,
3596 ient->sc_fmri);
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:
3603 default:
3604 bad_error("scf_transaction_start", scf_error());
3607 tx_started = have_cur_depts;
3609 for (;;) {
3610 r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3611 if (r == 0)
3612 break;
3613 if (r == 1) {
3614 r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3615 tx_started ? ud_tx : NULL);
3616 switch (r) {
3617 case 0:
3618 continue;
3620 case ECONNABORTED:
3621 case ENOMEM:
3622 case ENOSPC:
3623 case EBADF:
3624 case EBUSY:
3625 case EINVAL:
3626 case EPERM:
3627 case EROFS:
3628 case EACCES:
3629 case EEXIST:
3630 break;
3632 case ECANCELED:
3633 r = ENODEV;
3634 break;
3636 default:
3637 bad_error("upgrade_dependent", r);
3640 if (tx_started)
3641 scf_transaction_destroy_children(ud_tx);
3642 return (r);
3644 if (r != -1)
3645 bad_error("scf_iter_next_property", r);
3647 switch (scf_error()) {
3648 case SCF_ERROR_DELETED:
3649 r = ENODEV;
3650 break;
3652 case SCF_ERROR_CONNECTION_BROKEN:
3653 r = ECONNABORTED;
3654 break;
3656 case SCF_ERROR_NOT_SET:
3657 case SCF_ERROR_INVALID_ARGUMENT:
3658 case SCF_ERROR_NOT_BOUND:
3659 case SCF_ERROR_HANDLE_MISMATCH:
3660 default:
3661 bad_error("scf_iter_next_property",
3662 scf_error());
3665 if (tx_started)
3666 scf_transaction_destroy_children(ud_tx);
3667 return (r);
3671 /* import unseen dependents */
3672 unseen = 0;
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,
3676 new_dpt_pgroup)) {
3677 if (!new_dpt_pgroup->sc_pgroup_seen) {
3678 unseen = 1;
3679 break;
3683 /* If there are none, exit early. */
3684 if (unseen == 0)
3685 goto commit;
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"
3696 * property group.
3698 if (issvc)
3699 r = scf_service_add_pg(ent, dependents,
3700 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3701 else
3702 r = scf_instance_add_pg(ent, dependents,
3703 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3704 if (r != 0) {
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);
3715 return (EBUSY);
3717 case SCF_ERROR_PERMISSION_DENIED:
3718 warn(emsg_pg_add_perm, dependents,
3719 ient->sc_fmri);
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:
3726 default:
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);
3743 return (EBUSY);
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:
3753 default:
3754 bad_error("scf_transaction_start", scf_error());
3757 tx_started = 1;
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,
3762 new_dpt_pgroup)) {
3763 if (new_dpt_pgroup->sc_pgroup_seen)
3764 continue;
3766 if (ud_run_dpts_pg_set) {
3768 * If the dependent is already there, then we have
3769 * a conflict.
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,
3774 new_dpt_pgroup);
3775 switch (r) {
3776 case 0:
3777 continue;
3779 case ECONNABORTED:
3780 case ENOMEM:
3781 case EBUSY:
3782 case EBADF:
3783 case EINVAL:
3784 scf_transaction_destroy_children(ud_tx);
3785 return (r);
3787 default:
3788 bad_error("handle_dependent_conflict",
3791 } else {
3792 switch (scf_error()) {
3793 case SCF_ERROR_NOT_FOUND:
3794 break;
3796 case SCF_ERROR_INVALID_ARGUMENT:
3797 warn(emsg_fmri_invalid_pg_name,
3798 ient->sc_fmri,
3799 new_dpt_pgroup->sc_pgroup_name);
3800 scf_transaction_destroy_children(ud_tx);
3801 return (EINVAL);
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);
3807 return (EBUSY);
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:
3816 default:
3817 bad_error("scf_pg_get_property",
3818 scf_error());
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",
3831 cbdata.sc_err);
3834 scf_transaction_destroy_children(ud_tx);
3835 return (cbdata.sc_err);
3839 commit:
3840 if (!tx_started)
3841 return (0);
3843 r = scf_transaction_commit(ud_tx);
3845 scf_transaction_destroy_children(ud_tx);
3847 switch (r) {
3848 case 1:
3849 return (0);
3851 case 0:
3852 warn(emsg_pg_changed, ient->sc_fmri, dependents);
3853 return (EBUSY);
3855 case -1:
3856 break;
3858 default:
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);
3871 return (EBUSY);
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:
3880 default:
3881 bad_error("scf_transaction_destroy", scf_error());
3882 /* NOTREACHED */
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
3889 * don't exist.
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.
3899 static int
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;
3911 char *pname;
3912 char *fval;
3913 char *old_pname;
3914 char *old_fval;
3915 int no_upgrade_pg;
3916 int mfst_seen;
3917 int r;
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 */
3932 no_upgrade_pg = 0;
3933 r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3934 ud_mfsts_pg);
3935 if (r != 0) {
3936 switch (scf_error()) {
3937 case SCF_ERROR_NOT_FOUND:
3938 no_upgrade_pg = 1;
3939 break;
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:
3949 default:
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);
3966 return (0);
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)) !=
3975 SCF_SUCCESS)
3976 return (-1);
3978 if ((pname = malloc(MAXPATHLEN)) == NULL)
3979 return (ENOMEM);
3980 if ((fval = malloc(MAXPATHLEN)) == NULL) {
3981 free(pname);
3982 return (ENOMEM);
3985 while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
3986 mfst_seen = 0;
3987 if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
3988 continue;
3990 for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
3991 mfst_prop != NULL;
3992 mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
3993 mfst_prop)) {
3994 if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
3995 mfst_seen = 1;
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,
4022 old_prop);
4026 free(pname);
4027 free(fval);
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);
4039 return (r);
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.
4051 * Returns
4052 * 0 - success
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)
4075 static int
4076 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
4077 const scf_snaplevel_t *snpl, scf_transaction_t *tx)
4079 pgroup_t pgrp;
4080 scf_type_t ty;
4081 pgroup_t *new_dpt_pgroup;
4082 pgroup_t *old_dpt_pgroup = NULL;
4083 pgroup_t *current_pg;
4084 pgroup_t *dpt;
4085 scf_callback_t cbdata;
4086 int tissvc;
4087 void *target_ent;
4088 scf_error_t serr;
4089 int r;
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:
4115 default:
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);
4122 return (EBADF);
4126 * prop represents a dependent in the old manifest. It is named after
4127 * the dependent.
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:
4137 default:
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;
4144 new_dpt_pgroup =
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)
4150 return (0);
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);
4157 return (EBADF);
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:
4167 default:
4168 bad_error("scf_property_get_value",
4169 scf_error());
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) !=
4178 0) {
4179 switch (scf_error()) {
4180 case SCF_ERROR_NOT_FOUND:
4181 return (0);
4183 case SCF_ERROR_CONNECTION_BROKEN:
4184 return (scferror2errno(scf_error()));
4186 case SCF_ERROR_DELETED:
4187 warn(emsg_pg_deleted, ient->sc_fmri,
4188 "dependents");
4189 return (EBUSY);
4191 case SCF_ERROR_INVALID_ARGUMENT:
4192 case SCF_ERROR_NOT_BOUND:
4193 case SCF_ERROR_HANDLE_MISMATCH:
4194 case SCF_ERROR_NOT_SET:
4195 default:
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);
4204 return (0);
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:
4214 default:
4215 bad_error("scf_property_get_value",
4216 scf_error());
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);
4224 return (0);
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);
4232 switch (r) {
4233 case 1:
4234 break;
4236 case 0:
4237 case -1: /* warn? */
4238 warn(cf_newtarg, ient->sc_fmri, ud_name);
4239 return (0);
4241 case -2:
4242 warn(li_corrupt, ient->sc_fmri);
4243 return (EBADF);
4245 default:
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);
4253 return (EBADF);
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:
4263 default:
4264 bad_error("scf_snaplevel_get_pg", scf_error());
4268 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4269 snap_lastimport);
4270 switch (r) {
4271 case 0:
4272 break;
4274 case ECANCELED:
4275 case ECONNABORTED:
4276 case ENOMEM:
4277 case EBADF:
4278 return (r);
4280 case EACCES:
4281 default:
4282 bad_error("load_pg", r);
4285 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4286 switch (serr) {
4287 case SCF_ERROR_NONE:
4288 break;
4290 case SCF_ERROR_NO_MEMORY:
4291 internal_pgroup_free(old_dpt_pgroup);
4292 return (ENOMEM);
4294 case SCF_ERROR_NOT_FOUND:
4295 internal_pgroup_free(old_dpt_pgroup);
4296 goto delprop;
4298 case SCF_ERROR_CONSTRAINT_VIOLATED: /* caught above */
4299 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
4300 default:
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);
4306 switch (r) {
4307 case 0:
4308 break;
4310 case ECONNABORTED:
4311 internal_pgroup_free(old_dpt_pgroup);
4312 return (r);
4314 case ECANCELED:
4315 case ENOENT:
4316 internal_pgroup_free(old_dpt_pgroup);
4317 goto delprop;
4319 case EBADF:
4320 warn(r_no_lvl, ud_ctarg);
4321 internal_pgroup_free(old_dpt_pgroup);
4322 return (r);
4324 case EINVAL:
4325 default:
4326 bad_error("entity_get_running_pg", r);
4329 /* load it */
4330 r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4331 switch (r) {
4332 case 0:
4333 break;
4335 case ECANCELED:
4336 internal_pgroup_free(old_dpt_pgroup);
4337 goto delprop;
4339 case ECONNABORTED:
4340 case ENOMEM:
4341 case EBADF:
4342 internal_pgroup_free(old_dpt_pgroup);
4343 return (r);
4345 case EACCES:
4346 default:
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);
4355 return (0);
4358 internal_pgroup_free(old_dpt_pgroup);
4359 internal_pgroup_free(current_pg);
4361 if (g_verbose)
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);
4370 goto delprop;
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:
4380 default:
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:
4388 break;
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:
4400 default:
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();
4413 if (dpt == NULL)
4414 return (ENOMEM);
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)
4418 return (ENOMEM);
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()));
4424 delprop:
4425 if (tx == NULL)
4426 return (0);
4428 ent = scf_entry_create(g_hndl);
4429 if (ent == NULL)
4430 return (ENOMEM);
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,
4437 "dependents");
4438 return (EBUSY);
4440 case SCF_ERROR_CONNECTION_BROKEN:
4441 return (scferror2errno(scf_error()));
4443 case SCF_ERROR_NOT_FOUND:
4444 break;
4446 case SCF_ERROR_HANDLE_MISMATCH:
4447 case SCF_ERROR_NOT_BOUND:
4448 case SCF_ERROR_INVALID_ARGUMENT:
4449 case SCF_ERROR_NOT_SET:
4450 default:
4451 bad_error("scf_transaction_property_delete",
4452 scf_error());
4456 return (0);
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);
4470 return (EBADF);
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:
4480 default:
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
4492 * in that service.
4494 r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
4495 switch (r) {
4496 case 0:
4497 dpt = internal_pgroup_new();
4498 if (dpt == NULL)
4499 return (ENOMEM);
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)
4503 return (ENOMEM);
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()));
4508 break;
4510 case 1:
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);
4516 return (EBADF);
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:
4526 default:
4527 bad_error("scf_snaplevel_get_pg", scf_error());
4531 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4532 snap_lastimport);
4533 switch (r) {
4534 case 0:
4535 break;
4537 case ECANCELED:
4538 case ECONNABORTED:
4539 case ENOMEM:
4540 case EBADF:
4541 return (r);
4543 case EACCES:
4544 default:
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);
4551 return (0);
4553 break;
4555 case -1:
4556 warn(li_corrupt, ient->sc_fmri);
4557 return (EBADF);
4559 case -2:
4560 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4561 ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4562 return (EINVAL);
4564 default:
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);
4579 goto nocust;
4582 if (!ud_run_dpts_pg_set) {
4583 warn(cf_missing, ient->sc_fmri, ud_name);
4584 r = 0;
4585 goto out;
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);
4590 r = 0;
4591 goto out;
4593 case SCF_ERROR_CONNECTION_BROKEN:
4594 r = scferror2errno(scf_error());
4595 goto out;
4597 case SCF_ERROR_DELETED:
4598 warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4599 r = EBUSY;
4600 goto out;
4602 case SCF_ERROR_INVALID_ARGUMENT:
4603 case SCF_ERROR_NOT_BOUND:
4604 case SCF_ERROR_HANDLE_MISMATCH:
4605 case SCF_ERROR_NOT_SET:
4606 default:
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);
4616 r = 0;
4617 goto out;
4619 case SCF_ERROR_DELETED:
4620 case SCF_ERROR_CONNECTION_BROKEN:
4621 r = scferror2errno(scf_error());
4622 goto out;
4624 case SCF_ERROR_HANDLE_MISMATCH:
4625 case SCF_ERROR_NOT_BOUND:
4626 case SCF_ERROR_NOT_SET:
4627 case SCF_ERROR_PERMISSION_DENIED:
4628 default:
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);
4637 r = 0;
4638 goto out;
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);
4645 if (r == -1) {
4646 warn(cf_inval, ient->sc_fmri, ud_name);
4647 r = 0;
4648 goto out;
4649 } else if (r == -2) {
4650 warn(li_corrupt, ient->sc_fmri);
4651 r = EBADF;
4652 goto out;
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);
4659 if (r == -1) {
4660 warn(cf_inval, ient->sc_fmri, ud_name);
4661 r = 0;
4662 goto out;
4663 } else if (r == 0) {
4664 warn(cf_newtarg, ient->sc_fmri, ud_name);
4665 r = 0;
4666 goto out;
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);
4677 switch (serr) {
4678 case SCF_ERROR_NONE:
4679 break;
4681 case SCF_ERROR_NOT_FOUND:
4682 warn(cf_missing, ient->sc_fmri, ud_name);
4683 r = 0;
4684 goto out;
4686 case SCF_ERROR_NO_MEMORY:
4687 r = ENOMEM;
4688 goto out;
4690 case SCF_ERROR_CONSTRAINT_VIOLATED:
4691 case SCF_ERROR_INVALID_ARGUMENT:
4692 default:
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);
4698 switch (r) {
4699 case 0:
4700 break;
4702 case ECONNABORTED:
4703 goto out;
4705 case ECANCELED:
4706 case ENOENT:
4707 warn(cf_missing, ient->sc_fmri, ud_name);
4708 r = 0;
4709 goto out;
4711 case EBADF:
4712 warn(r_no_lvl, ud_ctarg);
4713 goto out;
4715 case EINVAL:
4716 default:
4717 bad_error("entity_get_running_pg", r);
4720 r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4721 switch (r) {
4722 case 0:
4723 break;
4725 case ECANCELED:
4726 warn(cf_missing, ient->sc_fmri, ud_name);
4727 r = 0;
4728 goto out;
4730 case ECONNABORTED:
4731 case ENOMEM:
4732 case EBADF:
4733 goto out;
4735 case EACCES:
4736 default:
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);
4743 r = 0;
4744 goto out;
4745 } else if (r != 1) {
4746 bad_error("fmri_equal", r);
4749 nocust:
4751 * Target has not been customized. Check the dependency property
4752 * group.
4755 if (old_dpt_pgroup == NULL) {
4756 if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4757 ud_pg) != 0) {
4758 switch (scf_error()) {
4759 case SCF_ERROR_NOT_FOUND:
4760 warn(li_corrupt, ient->sc_fmri);
4761 return (EBADF);
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:
4771 default:
4772 bad_error("scf_snaplevel_get_pg", scf_error());
4776 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4777 snap_lastimport);
4778 switch (r) {
4779 case 0:
4780 break;
4782 case ECANCELED:
4783 case ECONNABORTED:
4784 case ENOMEM:
4785 case EBADF:
4786 return (r);
4788 case EACCES:
4789 default:
4790 bad_error("load_pg", r);
4793 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4794 switch (serr) {
4795 case SCF_ERROR_NONE:
4796 break;
4798 case SCF_ERROR_NOT_FOUND:
4799 warn(cf_missing, ient->sc_fmri, ud_name);
4800 r = 0;
4801 goto out;
4803 case SCF_ERROR_NO_MEMORY:
4804 r = ENOMEM;
4805 goto out;
4807 case SCF_ERROR_CONSTRAINT_VIOLATED:
4808 case SCF_ERROR_INVALID_ARGUMENT:
4809 default:
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);
4815 switch (r) {
4816 case 0:
4817 break;
4819 case ECONNABORTED:
4820 goto out;
4822 case ECANCELED:
4823 case ENOENT:
4824 warn(cf_missing, ient->sc_fmri, ud_name);
4825 r = 0;
4826 goto out;
4828 case EBADF:
4829 warn(r_no_lvl, ud_ctarg);
4830 goto out;
4832 case EINVAL:
4833 default:
4834 bad_error("entity_get_running_pg", r);
4837 r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4838 switch (r) {
4839 case 0:
4840 break;
4842 case ECANCELED:
4843 warn(cf_missing, ient->sc_fmri, ud_name);
4844 goto out;
4846 case ECONNABORTED:
4847 case ENOMEM:
4848 case EBADF:
4849 goto out;
4851 case EACCES:
4852 default:
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);
4860 r = 0;
4861 goto out;
4864 /* Uncustomized. Upgrade. */
4866 r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4867 switch (r) {
4868 case 1:
4869 if (pg_equal(current_pg, new_dpt_pgroup)) {
4870 /* Already upgraded. */
4871 internal_pgroup_free(current_pg);
4872 r = 0;
4873 goto out;
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());
4883 goto out;
4885 case SCF_ERROR_DELETED:
4886 warn(cf_missing, ient->sc_fmri, ud_name);
4887 r = 0;
4888 goto out;
4890 case SCF_ERROR_NOT_FOUND:
4891 break;
4893 case SCF_ERROR_INVALID_ARGUMENT:
4894 case SCF_ERROR_NOT_BOUND:
4895 case SCF_ERROR_NOT_SET:
4896 case SCF_ERROR_HANDLE_MISMATCH:
4897 default:
4898 bad_error("entity_get_pg", scf_error());
4901 if (tissvc)
4902 r = scf_service_add_pg(target_ent, ud_name,
4903 SCF_GROUP_DEPENDENCY, 0, ud_pg);
4904 else
4905 r = scf_instance_add_pg(target_ent, ud_name,
4906 SCF_GROUP_DEPENDENCY, 0, ud_pg);
4907 if (r != 0) {
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());
4914 goto out;
4916 case SCF_ERROR_DELETED:
4917 warn(cf_missing, ient->sc_fmri,
4918 ud_name);
4919 r = 0;
4920 goto out;
4922 case SCF_ERROR_PERMISSION_DENIED:
4923 warn(emsg_pg_deleted, ud_ctarg,
4924 ud_name);
4925 r = EPERM;
4926 goto out;
4928 case SCF_ERROR_EXISTS:
4929 warn(emsg_pg_added, ud_ctarg, ud_name);
4930 r = EBUSY;
4931 goto out;
4933 case SCF_ERROR_NOT_BOUND:
4934 case SCF_ERROR_HANDLE_MISMATCH:
4935 case SCF_ERROR_INVALID_ARGUMENT:
4936 case SCF_ERROR_NOT_SET:
4937 default:
4938 bad_error("entity_add_pg", scf_error());
4943 r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4944 switch (r) {
4945 case 0:
4946 break;
4948 case ECANCELED:
4949 warn(cf_missing, ient->sc_fmri, ud_name);
4950 goto out;
4952 case ECONNABORTED:
4953 case ENOMEM:
4954 case EBADF:
4955 goto out;
4957 case EACCES:
4958 default:
4959 bad_error("load_pg", r);
4962 if (g_verbose)
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);
4967 switch (r) {
4968 case 0:
4969 break;
4971 case ECANCELED:
4972 warn(emsg_pg_deleted, ud_ctarg, ud_name);
4973 r = EBUSY;
4974 goto out;
4976 case EPERM:
4977 warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4978 goto out;
4980 case EBUSY:
4981 warn(emsg_pg_changed, ud_ctarg, ud_name);
4982 goto out;
4984 case ECONNABORTED:
4985 case ENOMEM:
4986 case ENOSPC:
4987 case EROFS:
4988 case EACCES:
4989 case EINVAL:
4990 goto out;
4992 default:
4993 bad_error("upgrade_pg", r);
4995 break;
4997 case 0: {
4998 scf_transaction_entry_t *ent;
4999 scf_value_t *val;
5001 internal_pgroup_free(current_pg);
5003 /* delete old pg */
5004 if (g_verbose)
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());
5011 goto out;
5013 case SCF_ERROR_DELETED:
5014 warn(cf_missing, ient->sc_fmri, ud_name);
5015 r = 0;
5016 goto out;
5018 case SCF_ERROR_NOT_FOUND:
5019 break;
5021 case SCF_ERROR_INVALID_ARGUMENT:
5022 case SCF_ERROR_NOT_BOUND:
5023 case SCF_ERROR_NOT_SET:
5024 case SCF_ERROR_HANDLE_MISMATCH:
5025 default:
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:
5031 break;
5033 case SCF_ERROR_CONNECTION_BROKEN:
5034 case SCF_ERROR_BACKEND_READONLY:
5035 case SCF_ERROR_BACKEND_ACCESS:
5036 r = scferror2errno(scf_error());
5037 goto out;
5039 case SCF_ERROR_PERMISSION_DENIED:
5040 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
5041 r = scferror2errno(scf_error());
5042 goto out;
5044 case SCF_ERROR_NOT_SET:
5045 default:
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);
5060 r = cbdata.sc_err;
5061 goto out;
5064 if (tx == NULL)
5065 break;
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)
5070 return (ENOMEM);
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());
5080 goto out;
5082 case SCF_ERROR_DELETED:
5083 warn(emsg_pg_deleted, ient->sc_fmri,
5084 "dependents");
5085 r = EBUSY;
5086 goto out;
5088 case SCF_ERROR_NOT_FOUND:
5089 break;
5091 case SCF_ERROR_NOT_BOUND:
5092 case SCF_ERROR_HANDLE_MISMATCH:
5093 case SCF_ERROR_INVALID_ARGUMENT:
5094 case SCF_ERROR_NOT_SET:
5095 default:
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());
5105 goto out;
5107 case SCF_ERROR_DELETED:
5108 warn(emsg_pg_deleted, ient->sc_fmri,
5109 "dependents");
5110 r = EBUSY;
5111 goto out;
5113 case SCF_ERROR_EXISTS:
5114 warn(emsg_pg_changed, ient->sc_fmri,
5115 "dependents");
5116 r = EBUSY;
5117 goto out;
5119 case SCF_ERROR_INVALID_ARGUMENT:
5120 case SCF_ERROR_HANDLE_MISMATCH:
5121 case SCF_ERROR_NOT_BOUND:
5122 case SCF_ERROR_NOT_SET:
5123 default:
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",
5134 scf_error());
5136 if (scf_entry_add_value(ent, val) != 0)
5137 bad_error("scf_entry_add_value", scf_error());
5138 break;
5141 case -2:
5142 warn(li_corrupt, ient->sc_fmri);
5143 internal_pgroup_free(current_pg);
5144 r = EBADF;
5145 goto out;
5147 case -1:
5148 default:
5149 /* invalid sc_pgroup_fmri caught above */
5150 bad_error("fmri_equal", r);
5153 r = 0;
5155 out:
5156 if (old_dpt_pgroup != NULL)
5157 internal_pgroup_free(old_dpt_pgroup);
5159 return (r);
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.
5170 * Returns
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)
5178 static int
5179 handle_dependent_conflict(const entity_t * const ient,
5180 const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
5182 int r;
5183 scf_type_t ty;
5184 scf_error_t scfe;
5185 void *tptr;
5186 int tissvc;
5187 pgroup_t *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);
5197 return (EBUSY);
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");
5206 return (0);
5208 case SCF_ERROR_HANDLE_MISMATCH:
5209 case SCF_ERROR_NOT_BOUND:
5210 case SCF_ERROR_NOT_SET:
5211 case SCF_ERROR_PERMISSION_DENIED:
5212 default:
5213 bad_error("scf_property_get_value",
5214 scf_error());
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");
5226 return (0);
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);
5234 switch (r) {
5235 case 0:
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);
5241 return (0);
5243 case 1:
5244 break;
5246 case -1:
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);
5251 return (0);
5253 case -2:
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);
5257 return (EINVAL);
5259 default:
5260 bad_error("fmri_equal", r);
5263 /* compare dependency pgs in target */
5264 scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
5265 switch (scfe) {
5266 case SCF_ERROR_NONE:
5267 break;
5269 case SCF_ERROR_NO_MEMORY:
5270 return (ENOMEM);
5272 case SCF_ERROR_NOT_FOUND:
5273 warn(emsg_dpt_dangling, ient->sc_fmri,
5274 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5275 return (0);
5277 case SCF_ERROR_CONSTRAINT_VIOLATED:
5278 case SCF_ERROR_INVALID_ARGUMENT:
5279 default:
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);
5285 switch (r) {
5286 case 0:
5287 break;
5289 case ECONNABORTED:
5290 return (r);
5292 case ECANCELED:
5293 warn(emsg_dpt_dangling, ient->sc_fmri,
5294 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5295 return (0);
5297 case EBADF:
5298 if (tissvc)
5299 warn(gettext("%s has an instance with a \"%s\" "
5300 "snapshot which is missing a snaplevel.\n"),
5301 ud_ctarg, "running");
5302 else
5303 warn(gettext("%s has a \"%s\" snapshot which is "
5304 "missing a snaplevel.\n"), ud_ctarg, "running");
5305 /* FALLTHROUGH */
5307 case ENOENT:
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);
5311 return (0);
5313 case EINVAL:
5314 default:
5315 bad_error("entity_get_running_pg", r);
5318 pgroup = internal_pgroup_new();
5319 if (pgroup == NULL)
5320 return (ENOMEM);
5322 r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
5323 switch (r) {
5324 case 0:
5325 break;
5327 case ECONNABORTED:
5328 case EBADF:
5329 case ENOMEM:
5330 internal_pgroup_free(pgroup);
5331 return (r);
5333 case ECANCELED:
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);
5338 return (0);
5340 case EACCES:
5341 default:
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);
5348 return (0);
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.
5357 * Returns
5358 * 0 - success
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)
5390 static int
5391 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
5392 const scf_snaplevel_t *running)
5394 int r;
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:
5409 return (ENODEV);
5411 case SCF_ERROR_CONNECTION_BROKEN:
5412 return (ECONNABORTED);
5414 case SCF_ERROR_NOT_SET:
5415 case SCF_ERROR_NOT_BOUND:
5416 default:
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)
5423 return (0);
5425 switch (scf_error()) {
5426 case SCF_ERROR_NOT_FOUND:
5427 break;
5429 case SCF_ERROR_CONNECTION_BROKEN:
5430 return (ECONNABORTED);
5432 case SCF_ERROR_DELETED:
5433 return (ENODEV);
5435 case SCF_ERROR_INVALID_ARGUMENT:
5436 case SCF_ERROR_NOT_BOUND:
5437 case SCF_ERROR_HANDLE_MISMATCH:
5438 case SCF_ERROR_NOT_SET:
5439 default:
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:
5448 return (ENODEV);
5450 case SCF_ERROR_CONNECTION_BROKEN:
5451 return (ECONNABORTED);
5453 case SCF_ERROR_NOT_SET:
5454 case SCF_ERROR_NOT_BOUND:
5455 default:
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);
5463 if (mpg != 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:
5478 return (0);
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:
5488 default:
5489 bad_error("entity_get_pg", scf_error());
5493 if (mpg != NULL && mpg->sc_pgroup_delete) {
5494 if (g_verbose)
5495 warn(deleting, ient->sc_fmri, imp_str);
5496 if (scf_pg_delete(imp_pg2) == 0)
5497 return (0);
5499 switch (scf_error()) {
5500 case SCF_ERROR_DELETED:
5501 return (0);
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:
5513 default:
5514 bad_error("scf_pg_delete", scf_error());
5518 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5519 switch (r) {
5520 case 0:
5521 break;
5523 case ECANCELED:
5524 return (ENODEV);
5526 case ECONNABORTED:
5527 case ENOMEM:
5528 case EBADF:
5529 case EACCES:
5530 return (r);
5532 default:
5533 bad_error("load_pg", r);
5536 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5537 switch (r) {
5538 case 0:
5539 break;
5541 case ECANCELED:
5542 case ECONNABORTED:
5543 case ENOMEM:
5544 case EBADF:
5545 case EACCES:
5546 internal_pgroup_free(lipg_i);
5547 return (r);
5549 default:
5550 bad_error("load_pg", r);
5553 if (pg_equal(lipg_i, curpg_i)) {
5554 if (g_verbose)
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:
5559 break;
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:
5568 default:
5569 bad_error("scf_pg_delete", scf_error());
5572 } else {
5573 report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5576 internal_pgroup_free(lipg_i);
5577 internal_pgroup_free(curpg_i);
5579 return (0);
5583 * Only dependent pgs can have override set, and we skipped those
5584 * above.
5586 assert(!mpg->sc_pgroup_override);
5588 /* compare */
5589 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5590 switch (r) {
5591 case 0:
5592 break;
5594 case ECANCELED:
5595 return (ENODEV);
5597 case ECONNABORTED:
5598 case EBADF:
5599 case ENOMEM:
5600 case EACCES:
5601 return (r);
5603 default:
5604 bad_error("load_pg", r);
5607 if (pg_equal(mpg, lipg_i)) {
5608 /* The manifest pg has not changed. Move on. */
5609 r = 0;
5610 goto out;
5613 /* upgrade current properties according to lipg & mpg */
5614 if (running != NULL)
5615 r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5616 else
5617 r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5618 if (r != 0) {
5619 switch (scf_error()) {
5620 case SCF_ERROR_CONNECTION_BROKEN:
5621 r = scferror2errno(scf_error());
5622 goto out;
5624 case SCF_ERROR_DELETED:
5625 if (running != NULL)
5626 r = ENODEV;
5627 else
5628 r = ECANCELED;
5629 goto out;
5631 case SCF_ERROR_NOT_FOUND:
5632 break;
5634 case SCF_ERROR_INVALID_ARGUMENT:
5635 case SCF_ERROR_HANDLE_MISMATCH:
5636 case SCF_ERROR_NOT_BOUND:
5637 case SCF_ERROR_NOT_SET:
5638 default:
5639 bad_error("entity_get_pg", scf_error());
5642 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5644 r = 0;
5645 goto out;
5648 r = load_pg_attrs(imp_pg2, &curpg_i);
5649 switch (r) {
5650 case 0:
5651 break;
5653 case ECANCELED:
5654 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5655 r = 0;
5656 goto out;
5658 case ECONNABORTED:
5659 case ENOMEM:
5660 goto out;
5662 default:
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);
5669 r = 0;
5670 goto out;
5673 internal_pgroup_free(curpg_i);
5675 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5676 switch (r) {
5677 case 0:
5678 break;
5680 case ECANCELED:
5681 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5682 r = 0;
5683 goto out;
5685 case ECONNABORTED:
5686 case EBADF:
5687 case ENOMEM:
5688 case EACCES:
5689 goto out;
5691 default:
5692 bad_error("load_pg", r);
5695 if (pg_equal(lipg_i, curpg_i) &&
5696 !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5697 int do_delete = 1;
5699 if (g_verbose)
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:
5709 r = ECANCELED;
5710 goto out;
5712 case SCF_ERROR_NOT_FOUND:
5713 do_delete = 0;
5714 break;
5716 case SCF_ERROR_CONNECTION_BROKEN:
5717 r = scferror2errno(scf_error());
5718 goto out;
5720 case SCF_ERROR_HANDLE_MISMATCH:
5721 case SCF_ERROR_INVALID_ARGUMENT:
5722 case SCF_ERROR_NOT_SET:
5723 case SCF_ERROR_NOT_BOUND:
5724 default:
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:
5732 break;
5734 case SCF_ERROR_CONNECTION_BROKEN:
5735 case SCF_ERROR_BACKEND_READONLY:
5736 case SCF_ERROR_BACKEND_ACCESS:
5737 r = scferror2errno(scf_error());
5738 goto out;
5740 case SCF_ERROR_PERMISSION_DENIED:
5741 warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5742 ient->sc_fmri);
5743 r = scferror2errno(scf_error());
5744 goto out;
5746 case SCF_ERROR_NOT_SET:
5747 case SCF_ERROR_NOT_BOUND:
5748 default:
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);
5761 switch (r) {
5762 case UU_WALK_NEXT:
5763 r = 0;
5764 goto out;
5766 case UU_WALK_ERROR:
5767 if (cbdata.sc_err == EEXIST) {
5768 warn(emsg_pg_added, ient->sc_fmri,
5769 mpg->sc_pgroup_name);
5770 r = EBUSY;
5771 } else {
5772 r = cbdata.sc_err;
5774 goto out;
5776 default:
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());
5787 goto out;
5789 case SCF_ERROR_NOT_FOUND:
5790 break;
5792 case SCF_ERROR_HANDLE_MISMATCH:
5793 case SCF_ERROR_INVALID_ARGUMENT:
5794 case SCF_ERROR_NOT_SET:
5795 case SCF_ERROR_NOT_BOUND:
5796 default:
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);
5808 switch (r) {
5809 case UU_WALK_NEXT:
5810 r = 0;
5811 goto out;
5813 case UU_WALK_ERROR:
5814 if (cbdata.sc_err == EEXIST) {
5815 warn(emsg_pg_added, ient->sc_fmri,
5816 mpg->sc_pgroup_name);
5817 r = EBUSY;
5818 } else {
5819 r = cbdata.sc_err;
5821 goto out;
5823 default:
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);
5830 switch (r) {
5831 case 0:
5832 ient->sc_import_state = IMPORT_PROP_BEGUN;
5833 break;
5835 case ECANCELED:
5836 warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5837 r = EBUSY;
5838 break;
5840 case EPERM:
5841 warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5842 break;
5844 case EBUSY:
5845 warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5846 break;
5848 case ECONNABORTED:
5849 case ENOMEM:
5850 case ENOSPC:
5851 case EROFS:
5852 case EACCES:
5853 case EINVAL:
5854 break;
5856 default:
5857 bad_error("upgrade_pg", r);
5860 out:
5861 internal_pgroup_free(lipg_i);
5862 return (r);
5866 * Upgrade the properties of ent according to snpl & ient.
5868 * Returns
5869 * 0 - success
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)
5896 static int
5897 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5898 entity_t *ient)
5900 pgroup_t *pg, *rpg;
5901 int r;
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:
5914 return (ENODEV);
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:
5922 default:
5923 bad_error("scf_iter_snaplevel_pgs", scf_error());
5927 for (;;) {
5928 r = scf_iter_next_pg(imp_up_iter, imp_pg);
5929 if (r == 0)
5930 break;
5931 if (r == 1) {
5932 r = process_old_pg(imp_pg, ient, ent, running);
5933 switch (r) {
5934 case 0:
5935 break;
5937 case ECONNABORTED:
5938 case ENOMEM:
5939 case ENOSPC:
5940 case ECANCELED:
5941 case ENODEV:
5942 case EPERM:
5943 case EROFS:
5944 case EACCES:
5945 case EBADF:
5946 case EBUSY:
5947 case EINVAL:
5948 case EEXIST:
5949 return (r);
5951 default:
5952 bad_error("process_old_pg", r);
5954 continue;
5956 if (r != -1)
5957 bad_error("scf_iter_next_pg", r);
5959 switch (scf_error()) {
5960 case SCF_ERROR_DELETED:
5961 return (ENODEV);
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:
5970 default:
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)
5977 continue;
5979 /* pg is new */
5981 if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5982 r = upgrade_dependents(NULL, imp_snpl, ient, running,
5983 ent);
5984 switch (r) {
5985 case 0:
5986 break;
5988 case ECONNABORTED:
5989 case ENOMEM:
5990 case ENOSPC:
5991 case ECANCELED:
5992 case ENODEV:
5993 case EBADF:
5994 case EBUSY:
5995 case EINVAL:
5996 case EPERM:
5997 case EROFS:
5998 case EACCES:
5999 case EEXIST:
6000 return (r);
6002 default:
6003 bad_error("upgrade_dependents", r);
6005 continue;
6008 if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
6009 r = upgrade_manifestfiles(pg, ient, running, ent);
6010 switch (r) {
6011 case 0:
6012 break;
6014 case ECONNABORTED:
6015 case ENOMEM:
6016 case ENOSPC:
6017 case ECANCELED:
6018 case ENODEV:
6019 case EBADF:
6020 case EBUSY:
6021 case EINVAL:
6022 case EPERM:
6023 case EROFS:
6024 case EACCES:
6025 case EEXIST:
6026 return (r);
6028 default:
6029 bad_error("upgrade_manifestfiles", r);
6031 continue;
6034 if (running != NULL) {
6035 r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
6036 imp_pg);
6037 } else {
6038 r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
6039 imp_pg);
6041 if (r != 0) {
6042 scf_callback_t cbdata;
6044 switch (scf_error()) {
6045 case SCF_ERROR_NOT_FOUND:
6046 break;
6048 case SCF_ERROR_CONNECTION_BROKEN:
6049 return (scferror2errno(scf_error()));
6051 case SCF_ERROR_DELETED:
6052 if (running != NULL)
6053 return (ENODEV);
6054 else
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);
6060 return (EINVAL);
6062 case SCF_ERROR_NOT_SET:
6063 case SCF_ERROR_HANDLE_MISMATCH:
6064 case SCF_ERROR_NOT_BOUND:
6065 default:
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);
6079 switch (r) {
6080 case UU_WALK_NEXT:
6081 ient->sc_import_state = IMPORT_PROP_BEGUN;
6082 continue;
6084 case UU_WALK_ERROR:
6085 if (cbdata.sc_err == EEXIST) {
6086 warn(emsg_pg_added, ient->sc_fmri,
6087 pg->sc_pgroup_name);
6088 return (EBUSY);
6090 return (cbdata.sc_err);
6092 default:
6093 bad_error("entity_pgroup_import", r);
6097 /* report differences between pg & current */
6098 r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
6099 switch (r) {
6100 case 0:
6101 break;
6103 case ECANCELED:
6104 warn(emsg_pg_deleted, ient->sc_fmri,
6105 pg->sc_pgroup_name);
6106 return (EBUSY);
6108 case ECONNABORTED:
6109 case EBADF:
6110 case ENOMEM:
6111 case EACCES:
6112 return (r);
6114 default:
6115 bad_error("load_pg", r);
6117 report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
6118 internal_pgroup_free(rpg);
6119 rpg = NULL;
6122 return (0);
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)
6168 static int
6169 lscf_instance_import(void *v, void *pvt)
6171 entity_t *inst = v;
6172 scf_callback_t ctx;
6173 scf_callback_t *lcbdata = pvt;
6174 scf_service_t *rsvc = lcbdata->sc_parent;
6175 int r;
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
6192 * take snapshot
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"),
6217 inst->sc_name);
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:
6229 default:
6230 bad_error("scf_service_add_instance", scf_error());
6234 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6235 inst->sc_name);
6236 if (r < 0)
6237 bad_error("snprintf", errno);
6239 r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
6240 lcbdata->sc_flags | SCI_NOENABLED);
6241 switch (r) {
6242 case 0:
6243 break;
6245 case ECANCELED:
6246 warn(emsg_tdel, imp_tsname, inst->sc_name);
6247 lcbdata->sc_err = EBUSY;
6248 r = UU_WALK_ERROR;
6249 goto deltemp;
6251 case EEXIST:
6252 warn(emsg_tchg, imp_tsname, inst->sc_name);
6253 lcbdata->sc_err = EBUSY;
6254 r = UU_WALK_ERROR;
6255 goto deltemp;
6257 case ECONNABORTED:
6258 goto connaborted;
6260 case ENOMEM:
6261 case ENOSPC:
6262 case EPERM:
6263 case EROFS:
6264 case EACCES:
6265 case EINVAL:
6266 case EBUSY:
6267 lcbdata->sc_err = r;
6268 r = UU_WALK_ERROR;
6269 goto deltemp;
6271 default:
6272 bad_error("lscf_import_instance_pgs", r);
6275 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6276 inst->sc_name);
6277 if (r < 0)
6278 bad_error("snprintf", errno);
6280 ctx.sc_handle = lcbdata->sc_handle;
6281 ctx.sc_parent = imp_tinst;
6282 ctx.sc_service = 0;
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,
6286 UU_DEFAULT) != 0) {
6287 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6288 bad_error("uu_list_walk", uu_error());
6290 switch (ctx.sc_err) {
6291 case ECONNABORTED:
6292 goto connaborted;
6294 case ECANCELED:
6295 warn(emsg_tdel, imp_tsname, inst->sc_name);
6296 lcbdata->sc_err = EBUSY;
6297 break;
6299 case EEXIST:
6300 warn(emsg_tchg, imp_tsname, inst->sc_name);
6301 lcbdata->sc_err = EBUSY;
6302 break;
6304 default:
6305 lcbdata->sc_err = ctx.sc_err;
6307 r = UU_WALK_ERROR;
6308 goto deltemp;
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:
6315 goto connaborted;
6317 case SCF_ERROR_NO_RESOURCES:
6318 r = stash_scferror(lcbdata);
6319 goto deltemp;
6321 case SCF_ERROR_EXISTS:
6322 warn(emsg_tchg, imp_tsname, inst->sc_name);
6323 lcbdata->sc_err = EBUSY;
6324 r = UU_WALK_ERROR;
6325 goto deltemp;
6327 case SCF_ERROR_PERMISSION_DENIED:
6328 warn(gettext("Could not take \"%s\" snapshot of %s "
6329 "(permission denied).\n"), snap_lastimport,
6330 imp_str);
6331 r = stash_scferror(lcbdata);
6332 goto deltemp;
6334 default:
6335 scfwarn();
6336 lcbdata->sc_err = -1;
6337 r = UU_WALK_ERROR;
6338 goto deltemp;
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)
6348 goto fresh;
6350 if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
6351 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6352 imp_lisnap) != 0) {
6353 switch (scf_error()) {
6354 case SCF_ERROR_DELETED:
6355 warn(emsg_del, inst->sc_parent->sc_fmri,
6356 inst->sc_name);
6357 lcbdata->sc_err = EBUSY;
6358 r = UU_WALK_ERROR;
6359 goto deltemp;
6361 case SCF_ERROR_NOT_FOUND:
6362 flags |= SCI_FORCE;
6363 goto nosnap;
6365 case SCF_ERROR_CONNECTION_BROKEN:
6366 goto connaborted;
6368 case SCF_ERROR_INVALID_ARGUMENT:
6369 case SCF_ERROR_HANDLE_MISMATCH:
6370 case SCF_ERROR_NOT_BOUND:
6371 case SCF_ERROR_NOT_SET:
6372 default:
6373 bad_error("scf_instance_get_snapshot",
6374 scf_error());
6378 /* upgrade */
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);
6391 switch (r) {
6392 case 0:
6393 break;
6395 case ECONNABORTED:
6396 goto connaborted;
6398 case ECANCELED:
6399 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6400 lcbdata->sc_err = EBUSY;
6401 r = UU_WALK_ERROR;
6402 goto deltemp;
6404 case ENOENT:
6405 warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
6406 lcbdata->sc_err = EBADF;
6407 r = UU_WALK_ERROR;
6408 goto deltemp;
6410 default:
6411 bad_error("get_snaplevel", r);
6414 if (scf_instance_get_snapshot(imp_inst, snap_running,
6415 imp_rsnap) != 0) {
6416 switch (scf_error()) {
6417 case SCF_ERROR_DELETED:
6418 warn(emsg_del, inst->sc_parent->sc_fmri,
6419 inst->sc_name);
6420 lcbdata->sc_err = EBUSY;
6421 r = UU_WALK_ERROR;
6422 goto deltemp;
6424 case SCF_ERROR_NOT_FOUND:
6425 break;
6427 case SCF_ERROR_CONNECTION_BROKEN:
6428 goto connaborted;
6430 case SCF_ERROR_INVALID_ARGUMENT:
6431 case SCF_ERROR_HANDLE_MISMATCH:
6432 case SCF_ERROR_NOT_BOUND:
6433 case SCF_ERROR_NOT_SET:
6434 default:
6435 bad_error("scf_instance_get_snapshot",
6436 scf_error());
6439 running = NULL;
6440 } else {
6441 r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
6442 switch (r) {
6443 case 0:
6444 running = imp_rsnpl;
6445 break;
6447 case ECONNABORTED:
6448 goto connaborted;
6450 case ECANCELED:
6451 warn(emsg_del, inst->sc_parent->sc_fmri,
6452 inst->sc_name);
6453 lcbdata->sc_err = EBUSY;
6454 r = UU_WALK_ERROR;
6455 goto deltemp;
6457 case ENOENT:
6458 warn(emsg_badsnap, snap_running, inst->sc_fmri);
6459 lcbdata->sc_err = EBADF;
6460 r = UU_WALK_ERROR;
6461 goto deltemp;
6463 default:
6464 bad_error("get_snaplevel", r);
6468 r = upgrade_props(imp_inst, running, imp_snpl, inst);
6469 switch (r) {
6470 case 0:
6471 break;
6473 case ECANCELED:
6474 case ENODEV:
6475 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6476 lcbdata->sc_err = EBUSY;
6477 r = UU_WALK_ERROR;
6478 goto deltemp;
6480 case ECONNABORTED:
6481 goto connaborted;
6483 case ENOMEM:
6484 case ENOSPC:
6485 case EBADF:
6486 case EBUSY:
6487 case EINVAL:
6488 case EPERM:
6489 case EROFS:
6490 case EACCES:
6491 case EEXIST:
6492 lcbdata->sc_err = r;
6493 r = UU_WALK_ERROR;
6494 goto deltemp;
6496 default:
6497 bad_error("upgrade_props", r);
6500 inst->sc_import_state = IMPORT_PROP_DONE;
6501 } else {
6502 switch (scf_error()) {
6503 case SCF_ERROR_CONNECTION_BROKEN:
6504 goto connaborted;
6506 case SCF_ERROR_NOT_FOUND:
6507 break;
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:
6513 default:
6514 bad_error("scf_service_get_instance", scf_error());
6517 fresh:
6518 /* create instance */
6519 if (scf_service_add_instance(rsvc, inst->sc_name,
6520 imp_inst) != 0) {
6521 switch (scf_error()) {
6522 case SCF_ERROR_CONNECTION_BROKEN:
6523 goto connaborted;
6525 case SCF_ERROR_NO_RESOURCES:
6526 case SCF_ERROR_BACKEND_READONLY:
6527 case SCF_ERROR_BACKEND_ACCESS:
6528 r = stash_scferror(lcbdata);
6529 goto deltemp;
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;
6536 r = UU_WALK_ERROR;
6537 goto deltemp;
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);
6544 goto deltemp;
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:
6550 default:
6551 bad_error("scf_service_add_instance",
6552 scf_error());
6556 nosnap:
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,
6564 imp_lisnap) != 0) {
6565 switch (scf_error()) {
6566 case SCF_ERROR_CONNECTION_BROKEN:
6567 goto connaborted;
6569 case SCF_ERROR_NO_RESOURCES:
6570 r = stash_scferror(lcbdata);
6571 goto deltemp;
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;
6578 r = UU_WALK_ERROR;
6579 goto deltemp;
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);
6586 goto deltemp;
6588 default:
6589 scfwarn();
6590 lcbdata->sc_err = -1;
6591 r = UU_WALK_ERROR;
6592 goto deltemp;
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",
6599 scf_error());
6603 if (li_only)
6604 goto lionly;
6606 inst->sc_import_state = IMPORT_PROP_BEGUN;
6608 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6609 flags);
6610 switch (r) {
6611 case 0:
6612 break;
6614 case ECONNABORTED:
6615 goto connaborted;
6617 case ECANCELED:
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;
6622 r = UU_WALK_ERROR;
6623 goto deltemp;
6625 case EEXIST:
6626 warn(gettext("%s changed unexpectedly "
6627 "(property group added).\n"), inst->sc_fmri);
6628 lcbdata->sc_err = EBUSY;
6629 r = UU_WALK_ERROR;
6630 goto deltemp;
6632 default:
6633 lcbdata->sc_err = r;
6634 r = UU_WALK_ERROR;
6635 goto deltemp;
6637 case EINVAL: /* caught above */
6638 bad_error("lscf_import_instance_pgs", r);
6641 ctx.sc_parent = imp_inst;
6642 ctx.sc_service = 0;
6643 ctx.sc_trans = NULL;
6644 ctx.sc_flags = 0;
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)
6651 goto connaborted;
6652 lcbdata->sc_err = ctx.sc_err;
6653 r = UU_WALK_ERROR;
6654 goto deltemp;
6657 inst->sc_import_state = IMPORT_PROP_DONE;
6659 if (g_verbose)
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);
6663 switch (r) {
6664 case 0:
6665 break;
6667 case ECONNABORTED:
6668 goto connaborted;
6670 case ENOSPC:
6671 case -1:
6672 lcbdata->sc_err = r;
6673 r = UU_WALK_ERROR;
6674 goto deltemp;
6676 case ECANCELED:
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;
6681 r = UU_WALK_ERROR;
6682 goto deltemp;
6684 case EPERM:
6685 warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6686 lcbdata->sc_err = r;
6687 r = UU_WALK_ERROR;
6688 goto deltemp;
6690 default:
6691 bad_error("take_snap", r);
6695 lionly:
6696 if (lcbdata->sc_flags & SCI_NOSNAP)
6697 goto deltemp;
6699 /* transfer snapshot from temporary instance */
6700 if (g_verbose)
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:
6706 goto connaborted;
6708 case SCF_ERROR_NO_RESOURCES:
6709 r = stash_scferror(lcbdata);
6710 goto deltemp;
6712 case SCF_ERROR_PERMISSION_DENIED:
6713 warn(gettext("Could not take \"%s\" snapshot for %s "
6714 "(permission denied).\n"), snap_lastimport,
6715 inst->sc_fmri);
6716 r = stash_scferror(lcbdata);
6717 goto deltemp;
6719 case SCF_ERROR_NOT_SET:
6720 case SCF_ERROR_HANDLE_MISMATCH:
6721 default:
6722 bad_error("_scf_snapshot_attach", scf_error());
6726 inst->sc_import_state = IMPORT_COMPLETE;
6728 r = UU_WALK_NEXT;
6730 deltemp:
6731 /* delete temporary instance */
6732 if (scf_instance_delete(imp_tinst) != 0) {
6733 switch (scf_error()) {
6734 case SCF_ERROR_DELETED:
6735 break;
6737 case SCF_ERROR_CONNECTION_BROKEN:
6738 goto connaborted;
6740 case SCF_ERROR_NOT_SET:
6741 case SCF_ERROR_NOT_BOUND:
6742 default:
6743 bad_error("scf_instance_delete", scf_error());
6747 return (r);
6749 connaborted:
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
6787 static int
6788 lscf_instance_verify(scf_scope_t *scope, entity_t *svc, entity_t *inst)
6790 int ret, err;
6791 struct timespec ts;
6792 char *emi_state;
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) {
6802 return (0);
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);
6812 free(emi_state);
6813 return (0);
6816 free(emi_state);
6819 * First we have to get the property.
6821 if ((ret = scf_scope_get_service(scope, svc->sc_name, imp_svc)) != 0) {
6822 ret = scf_error();
6823 warn(gettext("Failed to look up service: %s\n"), svc->sc_name);
6824 return (ret);
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
6831 * under us.
6833 if ((ret = scf_service_get_instance(imp_svc, inst->sc_name, imp_inst))
6834 != 0) {
6835 ret = scf_error();
6836 warn(gettext("Failed to verify instance: %s\n"), inst->sc_name);
6837 switch (ret) {
6838 case SCF_ERROR_DELETED:
6839 err = ENODEV;
6840 break;
6841 case SCF_ERROR_CONNECTION_BROKEN:
6842 warn(gettext("Lost repository connection\n"));
6843 err = ECONNABORTED;
6844 break;
6845 case SCF_ERROR_NOT_FOUND:
6846 warn(gettext("Instance \"%s\" disappeared out from "
6847 "under us.\n"), inst->sc_name);
6848 err = ENOENT;
6849 break;
6850 default:
6851 bad_error("scf_service_get_instance", ret);
6854 return (err);
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))
6864 != SCF_SUCCESS) {
6865 ret = scf_error();
6866 if (ret != SCF_ERROR_NOT_FOUND) {
6867 warn(gettext("Failed to get restarter property "
6868 "group for instance: %s\n"), inst->sc_name);
6869 switch (ret) {
6870 case SCF_ERROR_DELETED:
6871 err = ENODEV;
6872 break;
6873 case SCF_ERROR_CONNECTION_BROKEN:
6874 warn(gettext("Lost repository connection\n"));
6875 err = ECONNABORTED;
6876 break;
6877 default:
6878 bad_error("scf_service_get_instance", ret);
6881 return (err);
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,
6899 imp_prop)) != 0) {
6901 ret = scf_error();
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);
6906 switch (ret) {
6907 case SCF_ERROR_CONNECTION_BROKEN:
6908 warn(gettext("Lost repository connection\n"));
6909 err = ECONNABORTED;
6910 break;
6911 case SCF_ERROR_DELETED:
6912 err = ENODEV;
6913 break;
6914 default:
6915 bad_error("scf_pg_get_property", ret);
6918 return (err);
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);
6930 switch (ret) {
6931 case SCF_ERROR_DELETED:
6932 err = ENODEV;
6933 break;
6934 case SCF_ERROR_CONNECTION_BROKEN:
6935 warn(gettext("Lost repository connection\n"));
6936 err = ECONNABORTED;
6937 break;
6938 default:
6939 bad_error("scf_service_get_instance", ret);
6942 return (err);
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
6951 * mistaken.
6953 return (0);
6955 #endif
6957 static void
6958 del_tmp_service(void)
6960 if (scf_service_delete(imp_tsvc) != 0) {
6961 switch (scf_error()) {
6962 case SCF_ERROR_DELETED:
6963 break;
6965 case SCF_ERROR_CONNECTION_BROKEN:
6966 warn(gettext("Could not delete svc:/%s "
6967 "(repository connection broken).\n"), imp_tsname);
6968 break;
6970 case SCF_ERROR_EXISTS:
6971 warn(gettext(
6972 "Could not delete svc:/%s (instances exist).\n"),
6973 imp_tsname);
6974 break;
6976 case SCF_ERROR_NOT_SET:
6977 case SCF_ERROR_NOT_BOUND:
6978 default:
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)
7056 static int
7057 lscf_service_import(void *v, void *pvt)
7059 entity_t *s = v;
7060 scf_callback_t cbdata;
7061 scf_callback_t *lcbdata = pvt;
7062 scf_scope_t *scope = lcbdata->sc_parent;
7063 entity_t *inst, linst;
7064 int r;
7065 int fresh = 0;
7066 scf_snaplevel_t *running;
7067 int have_ge = 0;
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 "
7082 "for %s\n");
7084 li_only = 0;
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:
7097 break;
7099 case SCF_ERROR_HANDLE_MISMATCH:
7100 case SCF_ERROR_NOT_BOUND:
7101 case SCF_ERROR_NOT_SET:
7102 default:
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);
7114 if (r < 0)
7115 bad_error("snprintf", errno);
7116 if (r > max_scf_name_len) {
7117 warn(gettext(
7118 "Service name \"%s\" is too long. Cannot import.\n"),
7119 s->sc_name);
7120 lcbdata->sc_err = EINVAL;
7121 return (UU_WALK_ERROR);
7124 retry:
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:
7134 if (!retried) {
7135 lscf_delete(imp_tsname, 0);
7136 retried = B_TRUE;
7137 goto retry;
7139 warn(gettext(
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:
7153 default:
7154 bad_error("scf_scope_add_service", scf_error());
7158 r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
7159 if (r < 0)
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,
7170 UU_DEFAULT) != 0) {
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) {
7176 case ECONNABORTED:
7177 goto connaborted;
7179 case ECANCELED:
7180 warn(ts_deleted, imp_tsname);
7181 lcbdata->sc_err = EBUSY;
7182 return (UU_WALK_ERROR);
7184 case EEXIST:
7185 warn(ts_pg_added, imp_tsname);
7186 lcbdata->sc_err = EBUSY;
7187 return (UU_WALK_ERROR);
7190 r = UU_WALK_ERROR;
7191 del_tmp_service();
7192 return (r);
7195 if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
7196 UU_DEFAULT) != 0) {
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) {
7202 case ECONNABORTED:
7203 goto connaborted;
7205 case ECANCELED:
7206 warn(ts_deleted, imp_tsname);
7207 lcbdata->sc_err = EBUSY;
7208 return (UU_WALK_ERROR);
7210 case EEXIST:
7211 warn(ts_pg_added, imp_tsname);
7212 lcbdata->sc_err = EBUSY;
7213 return (UU_WALK_ERROR);
7216 del_tmp_service();
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:
7223 break;
7225 case SCF_ERROR_CONNECTION_BROKEN:
7226 goto connaborted;
7228 case SCF_ERROR_INVALID_ARGUMENT:
7229 case SCF_ERROR_HANDLE_MISMATCH:
7230 case SCF_ERROR_NOT_BOUND:
7231 case SCF_ERROR_NOT_SET:
7232 default:
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:
7239 goto connaborted;
7241 case SCF_ERROR_NO_RESOURCES:
7242 case SCF_ERROR_BACKEND_READONLY:
7243 case SCF_ERROR_BACKEND_ACCESS:
7244 del_tmp_service();
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;
7252 del_tmp_service();
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);
7258 del_tmp_service();
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:
7265 default:
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) {
7287 case ECONNABORTED:
7288 goto connaborted;
7290 case ECANCELED:
7291 warn(s_deleted, s->sc_fmri);
7292 lcbdata->sc_err = EBUSY;
7293 return (UU_WALK_ERROR);
7295 case EEXIST:
7296 warn(gettext("%s changed unexpectedly "
7297 "(property group added).\n"), s->sc_fmri);
7298 lcbdata->sc_err = EBUSY;
7299 return (UU_WALK_ERROR);
7301 case EINVAL:
7302 /* caught above */
7303 bad_error("entity_pgroup_import",
7304 cbdata.sc_err);
7307 del_tmp_service();
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)
7320 goto connaborted;
7321 del_tmp_service();
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.
7331 fresh = 1;
7332 goto instances;
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
7343 * properties.
7345 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7346 switch (scf_error()) {
7347 case SCF_ERROR_CONNECTION_BROKEN:
7348 goto connaborted;
7350 case SCF_ERROR_DELETED:
7351 warn(s_deleted, s->sc_fmri);
7352 lcbdata->sc_err = EBUSY;
7353 del_tmp_service();
7354 return (UU_WALK_ERROR);
7356 case SCF_ERROR_HANDLE_MISMATCH:
7357 case SCF_ERROR_NOT_BOUND:
7358 case SCF_ERROR_NOT_SET:
7359 default:
7360 bad_error("scf_iter_service_instances", scf_error());
7364 for (;;) {
7365 r = scf_iter_next_instance(imp_iter, imp_inst);
7366 if (r == 0)
7367 break;
7368 if (r != 1) {
7369 switch (scf_error()) {
7370 case SCF_ERROR_DELETED:
7371 warn(s_deleted, s->sc_fmri);
7372 lcbdata->sc_err = EBUSY;
7373 del_tmp_service();
7374 return (UU_WALK_ERROR);
7376 case SCF_ERROR_CONNECTION_BROKEN:
7377 goto connaborted;
7379 case SCF_ERROR_NOT_BOUND:
7380 case SCF_ERROR_HANDLE_MISMATCH:
7381 case SCF_ERROR_INVALID_ARGUMENT:
7382 case SCF_ERROR_NOT_SET:
7383 default:
7384 bad_error("scf_iter_next_instance",
7385 scf_error());
7389 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
7390 switch (scf_error()) {
7391 case SCF_ERROR_DELETED:
7392 continue;
7394 case SCF_ERROR_CONNECTION_BROKEN:
7395 goto connaborted;
7397 case SCF_ERROR_NOT_SET:
7398 case SCF_ERROR_NOT_BOUND:
7399 default:
7400 bad_error("scf_instance_get_name", scf_error());
7404 if (g_verbose)
7405 warn(gettext(
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);
7410 switch (r) {
7411 case 0:
7412 break;
7414 case ECANCELED:
7415 continue;
7417 case ECONNABORTED:
7418 goto connaborted;
7420 case EPERM:
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);
7427 case ENOSPC:
7428 case -1:
7429 lcbdata->sc_err = r;
7430 del_tmp_service();
7431 return (UU_WALK_ERROR);
7433 default:
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);
7440 if (inst != NULL) {
7441 inst->sc_import_state = IMPORT_PREVIOUS;
7442 inst->sc_seen = 1;
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);
7451 inst != NULL;
7452 inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
7453 inst)) {
7454 if (inst->sc_seen)
7455 continue;
7457 if (scf_service_add_instance(imp_svc, inst->sc_name,
7458 imp_inst) != 0) {
7459 switch (scf_error()) {
7460 case SCF_ERROR_CONNECTION_BROKEN:
7461 goto connaborted;
7463 case SCF_ERROR_BACKEND_READONLY:
7464 case SCF_ERROR_BACKEND_ACCESS:
7465 case SCF_ERROR_NO_RESOURCES:
7466 del_tmp_service();
7467 return (stash_scferror(lcbdata));
7469 case SCF_ERROR_EXISTS:
7470 warn(gettext("%s changed unexpectedly "
7471 "(instance \"%s\" added).\n"), s->sc_fmri,
7472 inst->sc_name);
7473 lcbdata->sc_err = EBUSY;
7474 del_tmp_service();
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,
7480 inst->sc_name);
7481 del_tmp_service();
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);
7487 del_tmp_service();
7488 return (stash_scferror(lcbdata));
7490 case SCF_ERROR_HANDLE_MISMATCH:
7491 case SCF_ERROR_NOT_BOUND:
7492 case SCF_ERROR_NOT_SET:
7493 default:
7494 bad_error("scf_service_add_instance",
7495 scf_error());
7499 if (g_verbose)
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);
7503 switch (r) {
7504 case 0:
7505 break;
7507 case ECANCELED:
7508 warn(i_deleted, s->sc_fmri, inst->sc_name);
7509 lcbdata->sc_err = EBUSY;
7510 del_tmp_service();
7511 return (UU_WALK_ERROR);
7513 case ECONNABORTED:
7514 goto connaborted;
7516 case EPERM:
7517 warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
7518 lcbdata->sc_err = r;
7519 del_tmp_service();
7520 return (UU_WALK_ERROR);
7522 case ENOSPC:
7523 case -1:
7524 del_tmp_service();
7525 return (UU_WALK_ERROR);
7527 default:
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:
7543 goto connaborted;
7545 case SCF_ERROR_DELETED:
7546 warn(s_deleted, s->sc_fmri);
7547 lcbdata->sc_err = EBUSY;
7548 del_tmp_service();
7549 return (UU_WALK_ERROR);
7551 case SCF_ERROR_HANDLE_MISMATCH:
7552 case SCF_ERROR_NOT_BOUND:
7553 case SCF_ERROR_NOT_SET:
7554 default:
7555 bad_error("scf_iter_service_instances", scf_error());
7559 for (;;) {
7560 r = scf_iter_next_instance(imp_iter, imp_inst);
7561 if (r == -1) {
7562 switch (scf_error()) {
7563 case SCF_ERROR_DELETED:
7564 warn(s_deleted, s->sc_fmri);
7565 lcbdata->sc_err = EBUSY;
7566 del_tmp_service();
7567 return (UU_WALK_ERROR);
7569 case SCF_ERROR_CONNECTION_BROKEN:
7570 goto connaborted;
7572 case SCF_ERROR_NOT_BOUND:
7573 case SCF_ERROR_HANDLE_MISMATCH:
7574 case SCF_ERROR_INVALID_ARGUMENT:
7575 case SCF_ERROR_NOT_SET:
7576 default:
7577 bad_error("scf_iter_next_instance",
7578 scf_error());
7582 if (r == 0) {
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.
7591 if (have_ge) {
7592 pgroup_t *mfpg;
7593 scf_callback_t mfcbdata;
7595 li_only = 1;
7596 no_refresh = 1;
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);
7606 if (mfpg) {
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);
7616 del_tmp_service();
7617 return (UU_WALK_ERROR);
7620 break;
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) {
7637 case ECONNABORTED:
7638 goto connaborted;
7640 case ECANCELED:
7641 warn(s_deleted, s->sc_fmri);
7642 lcbdata->sc_err = EBUSY;
7643 break;
7645 case EINVAL: /* caught above */
7646 case EEXIST:
7647 bad_error("entity_pgroup_import",
7648 cbdata.sc_err);
7651 del_tmp_service();
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)
7663 goto connaborted;
7664 del_tmp_service();
7665 return (UU_WALK_ERROR);
7667 break;
7670 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
7671 imp_snap) != 0) {
7672 switch (scf_error()) {
7673 case SCF_ERROR_DELETED:
7674 continue;
7676 case SCF_ERROR_NOT_FOUND:
7677 break;
7679 case SCF_ERROR_CONNECTION_BROKEN:
7680 goto connaborted;
7682 case SCF_ERROR_HANDLE_MISMATCH:
7683 case SCF_ERROR_NOT_BOUND:
7684 case SCF_ERROR_INVALID_ARGUMENT:
7685 case SCF_ERROR_NOT_SET:
7686 default:
7687 bad_error("scf_instance_get_snapshot",
7688 scf_error());
7691 if (have_ge)
7692 continue;
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,
7700 imp_pg) == 0) {
7701 if (scf_pg_get_property(imp_pg,
7702 SCF_PROPERTY_ENABLED, imp_prop) == 0) {
7703 have_ge = 1;
7704 } else {
7705 switch (scf_error()) {
7706 case SCF_ERROR_DELETED:
7707 case SCF_ERROR_NOT_FOUND:
7708 continue;
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:
7715 default:
7716 bad_error("scf_pg_get_property",
7717 scf_error());
7720 } else {
7721 switch (scf_error()) {
7722 case SCF_ERROR_DELETED:
7723 case SCF_ERROR_NOT_FOUND:
7724 continue;
7726 case SCF_ERROR_CONNECTION_BROKEN:
7727 goto connaborted;
7729 case SCF_ERROR_NOT_BOUND:
7730 case SCF_ERROR_NOT_SET:
7731 case SCF_ERROR_INVALID_ARGUMENT:
7732 case SCF_ERROR_HANDLE_MISMATCH:
7733 default:
7734 bad_error("scf_instance_get_pg",
7735 scf_error());
7738 continue;
7741 /* find service snaplevel */
7742 r = get_snaplevel(imp_snap, 1, imp_snpl);
7743 switch (r) {
7744 case 0:
7745 break;
7747 case ECONNABORTED:
7748 goto connaborted;
7750 case ECANCELED:
7751 continue;
7753 case ENOENT:
7754 if (scf_instance_get_name(imp_inst, imp_str,
7755 imp_str_sz) < 0)
7756 (void) strcpy(imp_str, "?");
7757 warn(badsnap, snap_lastimport, s->sc_name, imp_str);
7758 lcbdata->sc_err = EBADF;
7759 del_tmp_service();
7760 return (UU_WALK_ERROR);
7762 default:
7763 bad_error("get_snaplevel", r);
7766 if (scf_instance_get_snapshot(imp_inst, snap_running,
7767 imp_rsnap) != 0) {
7768 switch (scf_error()) {
7769 case SCF_ERROR_DELETED:
7770 continue;
7772 case SCF_ERROR_NOT_FOUND:
7773 break;
7775 case SCF_ERROR_CONNECTION_BROKEN:
7776 goto connaborted;
7778 case SCF_ERROR_INVALID_ARGUMENT:
7779 case SCF_ERROR_HANDLE_MISMATCH:
7780 case SCF_ERROR_NOT_BOUND:
7781 case SCF_ERROR_NOT_SET:
7782 default:
7783 bad_error("scf_instance_get_snapshot",
7784 scf_error());
7786 running = NULL;
7787 } else {
7788 r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
7789 switch (r) {
7790 case 0:
7791 running = imp_rsnpl;
7792 break;
7794 case ECONNABORTED:
7795 goto connaborted;
7797 case ECANCELED:
7798 continue;
7800 case ENOENT:
7801 if (scf_instance_get_name(imp_inst, imp_str,
7802 imp_str_sz) < 0)
7803 (void) strcpy(imp_str, "?");
7804 warn(badsnap, snap_running, s->sc_name,
7805 imp_str);
7806 lcbdata->sc_err = EBADF;
7807 del_tmp_service();
7808 return (UU_WALK_ERROR);
7810 default:
7811 bad_error("get_snaplevel", r);
7815 if (g_verbose) {
7816 if (scf_instance_get_name(imp_inst, imp_str,
7817 imp_str_sz) < 0)
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);
7825 if (r == 0)
7826 break;
7828 switch (r) {
7829 case ECONNABORTED:
7830 goto connaborted;
7832 case ECANCELED:
7833 warn(s_deleted, s->sc_fmri);
7834 lcbdata->sc_err = EBUSY;
7835 break;
7837 case ENODEV:
7838 if (scf_instance_get_name(imp_inst, imp_str,
7839 imp_str_sz) < 0)
7840 (void) strcpy(imp_str, "?");
7841 warn(i_deleted, s->sc_fmri, imp_str);
7842 lcbdata->sc_err = EBUSY;
7843 break;
7845 default:
7846 lcbdata->sc_err = r;
7849 del_tmp_service();
7850 return (UU_WALK_ERROR);
7853 s->sc_import_state = IMPORT_PROP_DONE;
7855 instances:
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)
7870 goto connaborted;
7871 del_tmp_service();
7872 return (UU_WALK_ERROR);
7875 s->sc_import_state = IMPORT_COMPLETE;
7876 del_tmp_service();
7877 return (UU_WALK_NEXT);
7879 connaborted:
7880 lcbdata->sc_err = ECONNABORTED;
7881 return (UU_WALK_ERROR);
7884 static const char *
7885 import_progress(int st)
7887 switch (st) {
7888 case 0:
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."));
7906 default:
7907 #ifndef NDEBUG
7908 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7909 __FILE__, __LINE__, st);
7910 #endif
7911 abort();
7912 /* NOTREACHED */
7917 * Returns
7918 * 0 - success
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)
7927 static int
7928 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7930 scf_error_t serr;
7931 void *ent;
7932 int issvc;
7933 int r;
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);
7940 switch (serr) {
7941 case SCF_ERROR_NONE:
7942 break;
7944 case SCF_ERROR_NO_MEMORY:
7945 if (name == NULL)
7946 warn(gettext("Could not refresh %s (out of memory).\n"),
7947 fmri);
7948 else
7949 warn(gettext("Could not refresh %s "
7950 "(dependent \"%s\" of %s) (out of memory).\n"),
7951 fmri, name, d_fmri);
7952 return (ENOMEM);
7954 case SCF_ERROR_NOT_FOUND:
7955 if (name == NULL)
7956 warn(deleted, fmri);
7957 else
7958 warn(dpt_deleted, fmri, name, d_fmri);
7959 return (0);
7961 case SCF_ERROR_INVALID_ARGUMENT:
7962 case SCF_ERROR_CONSTRAINT_VIOLATED:
7963 default:
7964 bad_error("fmri_to_entity", serr);
7967 r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7968 switch (r) {
7969 case 0:
7970 break;
7972 case ECONNABORTED:
7973 if (name != NULL)
7974 warn(gettext("Could not refresh %s "
7975 "(dependent \"%s\" of %s) "
7976 "(repository connection broken).\n"), fmri, name,
7977 d_fmri);
7978 return (r);
7980 case ECANCELED:
7981 if (name == NULL)
7982 warn(deleted, fmri);
7983 else
7984 warn(dpt_deleted, fmri, name, d_fmri);
7985 return (0);
7987 case EACCES:
7988 if (!g_verbose)
7989 return (0);
7990 if (name == NULL)
7991 warn(gettext("Could not refresh %s "
7992 "(backend access denied).\n"), fmri);
7993 else
7994 warn(gettext("Could not refresh %s "
7995 "(dependent \"%s\" of %s) "
7996 "(backend access denied).\n"), fmri, name, d_fmri);
7997 return (0);
7999 case EPERM:
8000 if (name == NULL)
8001 warn(gettext("Could not refresh %s "
8002 "(permission denied).\n"), fmri);
8003 else
8004 warn(gettext("Could not refresh %s "
8005 "(dependent \"%s\" of %s) "
8006 "(permission denied).\n"), fmri, name, d_fmri);
8007 return (r);
8009 case ENOSPC:
8010 if (name == NULL)
8011 warn(gettext("Could not refresh %s "
8012 "(repository server out of resources).\n"),
8013 fmri);
8014 else
8015 warn(gettext("Could not refresh %s "
8016 "(dependent \"%s\" of %s) "
8017 "(repository server out of resources).\n"),
8018 fmri, name, d_fmri);
8019 return (r);
8021 case -1:
8022 scfwarn();
8023 return (r);
8025 default:
8026 bad_error("refresh_entity", r);
8029 if (issvc)
8030 scf_service_destroy(ent);
8031 else
8032 scf_instance_destroy(ent);
8034 return (0);
8037 static int
8038 alloc_imp_globals()
8040 int r;
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)
8087 warn(emsg_nores);
8088 else
8089 warn(emsg_nomem);
8091 return (-1);
8094 r = load_init();
8095 switch (r) {
8096 case 0:
8097 break;
8099 case ENOMEM:
8100 warn(emsg_nomem);
8101 return (-1);
8103 default:
8104 bad_error("load_init", r);
8107 return (0);
8110 static void
8111 free_imp_globals()
8113 pgroup_t *old_dpt;
8114 void *cookie;
8116 load_fini();
8118 free(ud_ctarg);
8119 free(ud_oldtarg);
8120 free(ud_name);
8121 ud_ctarg = ud_oldtarg = ud_name = NULL;
8123 scf_transaction_destroy(ud_tx);
8124 ud_tx = NULL;
8125 scf_iter_destroy(ud_iter);
8126 scf_iter_destroy(ud_iter2);
8127 ud_iter = ud_iter2 = NULL;
8128 scf_value_destroy(ud_val);
8129 ud_val = NULL;
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);
8138 ud_snpl = NULL;
8139 scf_instance_destroy(ud_inst);
8140 ud_inst = NULL;
8142 free(imp_str);
8143 free(imp_tsname);
8144 free(imp_fe1);
8145 free(imp_fe2);
8146 imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
8148 cookie = NULL;
8149 while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
8150 NULL) {
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);
8158 imp_tx = NULL;
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);
8164 imp_prop = NULL;
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);
8183 imp_scope = NULL;
8185 load_fini();
8189 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
8191 scf_callback_t cbdata;
8192 int result = 0;
8193 entity_t *svc, *inst;
8194 uu_list_t *insts;
8195 int r;
8196 pgroup_t *old_dpt;
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");
8203 lscf_prep_hndl();
8205 if (alloc_imp_globals())
8206 goto out;
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();
8213 result = -1;
8214 goto out;
8216 case SCF_ERROR_NOT_FOUND:
8217 case SCF_ERROR_INVALID_ARGUMENT:
8218 case SCF_ERROR_NOT_BOUND:
8219 case SCF_ERROR_HANDLE_MISMATCH:
8220 default:
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) {
8227 annotation_set = 1;
8228 } else {
8229 switch (scf_error()) {
8230 case SCF_ERROR_CONNECTION_BROKEN:
8231 warn(gettext("Repository connection broken.\n"));
8232 repository_teardown();
8233 result = -1;
8234 goto out;
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());
8241 /* NOTREACHED */
8243 default:
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());
8250 break;
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);
8259 svc != NULL;
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),
8265 UU_DEFAULT) != 0)
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) {
8276 char *eptr;
8277 /* Success. Refresh everything. */
8279 if (flags & SCI_NOREFRESH || no_refresh) {
8280 no_refresh = 0;
8281 result = 0;
8282 goto out;
8285 for (svc = uu_list_first(bndl->sc_bundle_services);
8286 svc != NULL;
8287 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8288 pgroup_t *dpt;
8290 insts = svc->sc_u.sc_service.sc_service_instances;
8292 for (inst = uu_list_first(insts);
8293 inst != NULL;
8294 inst = uu_list_next(insts, inst)) {
8295 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
8296 switch (r) {
8297 case 0:
8298 break;
8300 case ENOMEM:
8301 case ECONNABORTED:
8302 case EPERM:
8303 case -1:
8304 goto progress;
8306 default:
8307 bad_error("imp_refresh_fmri", r);
8310 inst->sc_import_state = IMPORT_REFRESHED;
8312 for (dpt = uu_list_first(inst->sc_dependents);
8313 dpt != NULL;
8314 dpt = uu_list_next(inst->sc_dependents,
8315 dpt))
8316 if (imp_refresh_fmri(
8317 dpt->sc_pgroup_fmri,
8318 dpt->sc_pgroup_name,
8319 inst->sc_fmri) != 0)
8320 goto progress;
8323 for (dpt = uu_list_first(svc->sc_dependents);
8324 dpt != NULL;
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)
8328 goto progress;
8331 for (old_dpt = uu_list_first(imp_deleted_dpts);
8332 old_dpt != NULL;
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)
8337 goto progress;
8339 result = 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);
8369 inst != NULL;
8370 inst = uu_list_next(insts, inst)) {
8371 if (lscf_instance_verify(imp_scope, svc,
8372 inst) != 0)
8373 goto progress;
8376 #endif
8377 goto out;
8381 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8382 bad_error("uu_list_walk", uu_error());
8384 printerr:
8385 /* If the error hasn't been printed yet, do so here. */
8386 switch (cbdata.sc_err) {
8387 case ECONNABORTED:
8388 warn(gettext("Repository connection broken.\n"));
8389 break;
8391 case ENOMEM:
8392 warn(emsg_nomem);
8393 break;
8395 case ENOSPC:
8396 warn(emsg_nores);
8397 break;
8399 case EROFS:
8400 warn(gettext("Repository is read-only.\n"));
8401 break;
8403 case EACCES:
8404 warn(gettext("Repository backend denied access.\n"));
8405 break;
8407 case EPERM:
8408 case EINVAL:
8409 case EEXIST:
8410 case EBUSY:
8411 case EBADF:
8412 case -1:
8413 break;
8415 default:
8416 bad_error("lscf_service_import", cbdata.sc_err);
8419 progress:
8420 warn(gettext("Import of %s failed. Progress:\n"), filename);
8422 for (svc = uu_list_first(bndl->sc_bundle_services);
8423 svc != NULL;
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);
8431 inst != NULL;
8432 inst = uu_list_next(insts, inst))
8433 warn(gettext(" Instance \"%s\": %s\n"),
8434 inst->sc_name,
8435 import_progress(inst->sc_import_state));
8438 if (cbdata.sc_err == ECONNABORTED)
8439 repository_teardown();
8442 result = -1;
8444 out:
8445 if (annotation_set != 0) {
8446 /* Turn off annotation. It is no longer needed. */
8447 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8450 free_imp_globals();
8452 return (result);
8456 * _lscf_import_err() summarize the error handling returned by
8457 * lscf_import_{instance | service}_pgs
8458 * Return values are:
8459 * IMPORT_NEXT
8460 * IMPORT_OUT
8461 * IMPORT_BAD
8464 #define IMPORT_BAD -1
8465 #define IMPORT_NEXT 0
8466 #define IMPORT_OUT 1
8468 static int
8469 _lscf_import_err(int err, const char *fmri)
8471 switch (err) {
8472 case 0:
8473 if (g_verbose)
8474 warn(gettext("%s updated.\n"), fmri);
8475 return (IMPORT_NEXT);
8477 case ECONNABORTED:
8478 warn(gettext("Could not update %s "
8479 "(repository connection broken).\n"), fmri);
8480 return (IMPORT_OUT);
8482 case ENOMEM:
8483 warn(gettext("Could not update %s (out of memory).\n"), fmri);
8484 return (IMPORT_OUT);
8486 case ENOSPC:
8487 warn(gettext("Could not update %s "
8488 "(repository server out of resources).\n"), fmri);
8489 return (IMPORT_OUT);
8491 case ECANCELED:
8492 warn(gettext(
8493 "Could not update %s (deleted).\n"), fmri);
8494 return (IMPORT_NEXT);
8496 case EPERM:
8497 case EINVAL:
8498 case EBUSY:
8499 return (IMPORT_NEXT);
8501 case EROFS:
8502 warn(gettext("Could not update %s (repository read-only).\n"),
8503 fmri);
8504 return (IMPORT_OUT);
8506 case EACCES:
8507 warn(gettext("Could not update %s "
8508 "(backend access denied).\n"), fmri);
8509 return (IMPORT_NEXT);
8511 case EEXIST:
8512 default:
8513 return (IMPORT_BAD);
8516 /*NOTREACHED*/
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
8522 * working on.
8524 static int
8525 lscf_dependent_apply(void *dpg, void *e)
8527 scf_callback_t cb;
8528 pgroup_t *dpt_pgroup = dpg;
8529 pgroup_t *deldpt;
8530 entity_t *ent = e;
8531 int tissvc;
8532 void *sc_ent, *tent;
8533 scf_error_t serr;
8534 int r;
8536 const char * const dependents = "dependents";
8537 const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT);
8539 if (issvc)
8540 sc_ent = imp_svc;
8541 else
8542 sc_ent = imp_inst;
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,
8547 imp_prop) != 0) {
8548 switch (scf_error()) {
8549 case SCF_ERROR_NOT_FOUND:
8550 case SCF_ERROR_DELETED:
8551 break;
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:
8558 default:
8559 bad_error("entity_get_pg", scf_error());
8561 } else {
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:
8571 break;
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:
8578 default:
8579 bad_error("scf_property_get_value",
8580 scf_error());
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);
8589 switch (r) {
8590 case 1:
8591 break;
8592 case 0:
8593 if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent,
8594 &tissvc)) != SCF_ERROR_NONE) {
8595 if (serr == SCF_ERROR_NOT_FOUND) {
8596 break;
8597 } else {
8598 bad_error("fmri_to_entity", serr);
8602 if (entity_get_pg(tent, tissvc,
8603 dpt_pgroup->sc_pgroup_name, imp_pg) != 0) {
8604 serr = scf_error();
8605 if (serr == SCF_ERROR_NOT_FOUND ||
8606 serr == SCF_ERROR_DELETED) {
8607 break;
8608 } else {
8609 bad_error("entity_get_pg", scf_error());
8613 if (scf_pg_delete(imp_pg) != 0) {
8614 serr = scf_error();
8615 if (serr == SCF_ERROR_NOT_FOUND ||
8616 serr == SCF_ERROR_DELETED) {
8617 break;
8618 } else {
8619 bad_error("scf_pg_delete", scf_error());
8623 deldpt = internal_pgroup_new();
8624 if (deldpt == NULL)
8625 return (ENOMEM);
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)
8631 return (ENOMEM);
8632 deldpt->sc_parent = (entity_t *)ent;
8633 if (uu_list_insert_after(imp_deleted_dpts, NULL,
8634 deldpt) != 0)
8635 uu_die(gettext("libuutil error: %s\n"),
8636 uu_strerror(uu_error()));
8638 break;
8639 default:
8640 bad_error("fmri_equal", r);
8644 cb.sc_handle = g_hndl;
8645 cb.sc_parent = ent;
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;
8649 cb.sc_trans = NULL;
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);
8656 switch (r) {
8657 case 0:
8658 break;
8660 case ENOMEM:
8661 case ECONNABORTED:
8662 case EPERM:
8663 case -1:
8664 warn(gettext("Unable to refresh \"%s\"\n"),
8665 dpt_pgroup->sc_pgroup_fmri);
8666 return (UU_WALK_ERROR);
8668 default:
8669 bad_error("imp_refresh_fmri", r);
8672 return (UU_WALK_NEXT);
8676 * Returns
8677 * 0 - success
8678 * -1 - lscf_import_instance_pgs() failed.
8681 lscf_bundle_apply(bundle_t *bndl, const char *file)
8683 pgroup_t *old_dpt;
8684 entity_t *svc, *inst;
8685 int annotation_set = 0;
8686 int ret = 0;
8687 int r = 0;
8689 lscf_prep_hndl();
8691 if ((ret = alloc_imp_globals()))
8692 goto out;
8694 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0)
8695 scfdie();
8698 * Set the strings to be used for the security audit annotation
8699 * event.
8701 if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
8702 annotation_set = 1;
8703 } else {
8704 switch (scf_error()) {
8705 case SCF_ERROR_CONNECTION_BROKEN:
8706 warn(gettext("Repository connection broken.\n"));
8707 goto out;
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());
8714 /* NOTREACHED */
8716 default:
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());
8723 break;
8727 for (svc = uu_list_first(bndl->sc_bundle_services);
8728 svc != NULL;
8729 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8730 int refresh = 0;
8732 if (scf_scope_get_service(imp_scope, svc->sc_name,
8733 imp_svc) != 0) {
8734 switch (scf_error()) {
8735 case SCF_ERROR_NOT_FOUND:
8736 if (g_verbose)
8737 warn(gettext("Ignoring nonexistent "
8738 "service %s.\n"), svc->sc_name);
8739 continue;
8741 default:
8742 scfdie();
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());
8757 ret = -1;
8758 continue;
8761 for (inst = uu_list_first(
8762 svc->sc_u.sc_service.sc_service_instances);
8763 inst != NULL;
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)
8773 continue;
8775 if (uu_list_walk(inst->sc_pgroups,
8776 find_current_pg_type, inst,
8777 UU_DEFAULT) != 0) {
8778 if (uu_error() !=
8779 UU_ERROR_CALLBACK_FAILED)
8780 bad_error("uu_list_walk",
8781 uu_error());
8783 ret = -1;
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) {
8794 refresh = 1;
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)) {
8798 case IMPORT_NEXT:
8799 break;
8801 case IMPORT_OUT:
8802 goto out;
8804 case IMPORT_BAD:
8805 default:
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);
8817 inst != NULL;
8818 inst = uu_list_next(
8819 svc->sc_u.sc_service.sc_service_instances, inst)) {
8821 * This instance still has missing types
8822 * so skip it.
8824 if (inst->sc_miss_type) {
8825 if (g_verbose)
8826 warn(gettext("Ignoring instance "
8827 "%s:%s with missing types\n"),
8828 inst->sc_parent->sc_name,
8829 inst->sc_name);
8831 continue;
8834 if (scf_service_get_instance(imp_svc, inst->sc_name,
8835 imp_inst) != 0) {
8836 switch (scf_error()) {
8837 case SCF_ERROR_NOT_FOUND:
8838 if (g_verbose)
8839 warn(gettext("Ignoring "
8840 "nonexistant instance "
8841 "%s:%s.\n"),
8842 inst->sc_parent->sc_name,
8843 inst->sc_name);
8844 continue;
8846 default:
8847 scfdie();
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,
8862 imp_snap) != 0) {
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) {
8867 if (g_verbose)
8868 warn(gettext("Ignoreing "
8869 "partial instance "
8870 "%s:%s.\n"),
8871 inst->sc_parent->sc_name,
8872 inst->sc_name);
8873 continue;
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)) {
8880 case IMPORT_NEXT:
8881 break;
8883 case IMPORT_OUT:
8884 goto out;
8886 case IMPORT_BAD:
8887 default:
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 */
8897 if (refresh == 0)
8898 (void) refresh_entity(0, imp_inst,
8899 inst->sc_fmri, NULL, NULL, NULL);
8902 if (refresh == 1) {
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);
8907 free(name_buf);
8910 for (old_dpt = uu_list_first(imp_deleted_dpts);
8911 old_dpt != NULL;
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);
8922 out:
8923 if (annotation_set) {
8924 /* Remove security audit annotation strings. */
8925 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8928 free_imp_globals();
8929 return (ret);
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
8941 * apropriately.
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).
8953 static void
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.
8966 static int
8967 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
8968 const char *name, const char *dval)
8970 scf_value_t *val;
8971 ssize_t len;
8972 char *str;
8974 val = scf_value_create(g_hndl);
8975 if (val == NULL)
8976 scfdie();
8978 if (prop_get_val(prop, val) != 0) {
8979 scf_value_destroy(val);
8980 return (-1);
8983 len = scf_value_get_as_string(val, NULL, 0);
8984 if (len < 0)
8985 scfdie();
8987 str = safe_malloc(len + 1);
8989 if (scf_value_get_as_string(val, str, len + 1) < 0)
8990 scfdie();
8992 scf_value_destroy(val);
8994 if (dval == NULL || strcmp(str, dval) != 0)
8995 safe_setprop(n, name, str);
8997 free(str);
8999 return (0);
9003 * As above, but the attribute is always set.
9005 static int
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.
9014 static int
9015 write_service_bundle(xmlDocPtr doc, FILE *f)
9017 xmlChar *mem;
9018 int sz, i;
9020 mem = NULL;
9021 xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
9023 if (mem == NULL) {
9024 semerr(gettext("Could not dump XML tree.\n"));
9025 return (-1);
9029 * Fortunately libxml produces &quot; instead of ", so we can blindly
9030 * replace all " with '. Cursed libxml2! Why must you #ifdef out the
9031 * &apos; code?!
9033 for (i = 0; i < sz; ++i) {
9034 char c = (char)mem[i];
9036 if (c == '"')
9037 (void) fputc('\'', f);
9038 else if (c == '\'')
9039 (void) fwrite("&apos;", sizeof ("&apos;") - 1, 1, f);
9040 else
9041 (void) fputc(c, f);
9044 return (0);
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.
9052 static void
9053 export_property(scf_property_t *prop, const char *name_arg,
9054 struct pg_elts *elts, int flags)
9056 const char *type;
9057 scf_error_t err = 0;
9058 xmlNodePtr pnode, lnode;
9059 char *lnname;
9060 int ret;
9062 /* name */
9063 if (name_arg != NULL) {
9064 (void) strcpy(exp_str, name_arg);
9065 } else {
9066 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
9067 scfdie();
9070 /* type */
9071 type = prop_to_typestr(prop);
9072 if (type == NULL)
9073 uu_die(gettext("Can't export property %s: unknown type.\n"),
9074 exp_str);
9076 /* If we're exporting values, and there's just one, export it here. */
9077 if (!(flags & SCE_ALL_VALUES))
9078 goto empty;
9080 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
9081 xmlNodePtr n;
9083 /* Single value, so use propval */
9084 n = xmlNewNode(NULL, (xmlChar *)"propval");
9085 if (n == NULL)
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)
9092 scfdie();
9093 safe_setprop(n, value_attr, exp_str);
9095 if (elts->propvals == NULL)
9096 elts->propvals = n;
9097 else
9098 (void) xmlAddSibling(elts->propvals, n);
9100 return;
9103 err = scf_error();
9105 if (err == SCF_ERROR_PERMISSION_DENIED) {
9106 semerr(emsg_permission_denied);
9107 return;
9110 if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
9111 err != SCF_ERROR_NOT_FOUND &&
9112 err != SCF_ERROR_PERMISSION_DENIED)
9113 scfdie();
9115 empty:
9116 /* Multiple (or no) values, so use property */
9117 pnode = xmlNewNode(NULL, (xmlChar *)"property");
9118 if (pnode == NULL)
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);
9126 if (lnname == NULL)
9127 uu_die(gettext("Could not create string"));
9129 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
9130 if (lnode == NULL)
9131 uu_die(emsg_create_xml);
9133 uu_free(lnname);
9135 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
9136 scfdie();
9138 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
9139 1) {
9140 xmlNodePtr vn;
9142 vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
9143 NULL);
9144 if (vn == NULL)
9145 uu_die(emsg_create_xml);
9147 if (scf_value_get_as_string(exp_val, exp_str,
9148 exp_str_sz) < 0)
9149 scfdie();
9150 safe_setprop(vn, value_attr, exp_str);
9152 if (ret != 0)
9153 scfdie();
9156 if (elts->properties == NULL)
9157 elts->properties = pnode;
9158 else
9159 (void) xmlAddSibling(elts->properties, pnode);
9163 * Add a property_group element for this property group to elts.
9165 static void
9166 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
9168 xmlNodePtr n;
9169 struct pg_elts elts;
9170 int ret;
9171 boolean_t read_protected;
9173 n = xmlNewNode(NULL, (xmlChar *)"property_group");
9175 /* name */
9176 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9177 scfdie();
9178 safe_setprop(n, name_attr, exp_str);
9180 /* type */
9181 if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
9182 scfdie();
9183 safe_setprop(n, type_attr, exp_str);
9185 /* properties */
9186 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9187 scfdie();
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)
9197 scfdie();
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)
9204 scfdie();
9206 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9207 xmlNodePtr m;
9209 m = xmlNewNode(NULL, (xmlChar *)"stability");
9210 if (m == NULL)
9211 uu_die(emsg_create_xml);
9213 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9214 elts.stability = m;
9215 continue;
9218 xmlFreeNode(m);
9221 export_property(exp_prop, NULL, &elts, flags);
9223 if (ret == -1)
9224 scfdie();
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;
9232 else
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
9240 * put it in eelts.
9242 static void
9243 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
9245 xmlNodePtr n;
9246 int err = 0, ret;
9247 struct pg_elts elts;
9249 n = xmlNewNode(NULL, (xmlChar *)"dependency");
9250 if (n == NULL)
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) {
9260 uint8_t b;
9262 if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
9263 scfdie();
9265 if (b)
9266 return;
9268 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
9269 scfdie();
9271 /* Get the required attributes. */
9273 /* name */
9274 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9275 scfdie();
9276 safe_setprop(n, name_attr, exp_str);
9278 /* grouping */
9279 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9280 set_attr_from_prop(exp_prop, n, "grouping") != 0)
9281 err = 1;
9283 /* restart_on */
9284 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9285 set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9286 err = 1;
9288 /* type */
9289 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9290 set_attr_from_prop(exp_prop, n, type_attr) != 0)
9291 err = 1;
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) {
9299 scf_iter_t *eiter;
9300 int ret2;
9302 eiter = scf_iter_create(g_hndl);
9303 if (eiter == NULL)
9304 scfdie();
9306 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
9307 scfdie();
9309 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
9310 xmlNodePtr ch;
9312 if (scf_value_get_astring(exp_val, exp_str,
9313 exp_str_sz) < 0)
9314 scfdie();
9317 * service_fmri's must be first, so we can add them
9318 * here.
9320 ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
9321 NULL);
9322 if (ch == NULL)
9323 uu_die(emsg_create_xml);
9325 safe_setprop(ch, value_attr, exp_str);
9327 if (ret2 == -1)
9328 scfdie();
9330 scf_iter_destroy(eiter);
9331 } else
9332 err = 1;
9334 if (err) {
9335 xmlFreeNode(n);
9337 export_pg(pg, eelts, SCE_ALL_VALUES);
9339 return;
9342 /* Iterate through the properties & handle each. */
9343 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9344 scfdie();
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)
9350 scfdie();
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) {
9356 continue;
9357 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9358 xmlNodePtr m;
9360 m = xmlNewNode(NULL, (xmlChar *)"stability");
9361 if (m == NULL)
9362 uu_die(emsg_create_xml);
9364 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9365 elts.stability = m;
9366 continue;
9369 xmlFreeNode(m);
9372 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9374 if (ret == -1)
9375 scfdie();
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;
9383 else
9384 (void) xmlAddSibling(eelts->dependencies, n);
9387 static xmlNodePtr
9388 export_method_environment(scf_propertygroup_t *pg)
9390 xmlNodePtr env;
9391 int ret;
9392 int children = 0;
9394 if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
9395 return (NULL);
9397 env = xmlNewNode(NULL, (xmlChar *)"method_environment");
9398 if (env == NULL)
9399 uu_die(emsg_create_xml);
9401 if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
9402 scfdie();
9404 if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
9405 scfdie();
9407 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
9408 xmlNodePtr ev;
9409 char *cp;
9411 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9412 scfdie();
9414 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
9415 warn(gettext("Invalid environment variable \"%s\".\n"),
9416 exp_str);
9417 continue;
9418 } else if (strncmp(exp_str, "SMF_", 4) == 0) {
9419 warn(gettext("Invalid environment variable \"%s\"; "
9420 "\"SMF_\" prefix is reserved.\n"), exp_str);
9421 continue;
9424 *cp = '\0';
9425 cp++;
9427 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
9428 if (ev == NULL)
9429 uu_die(emsg_create_xml);
9431 safe_setprop(ev, name_attr, exp_str);
9432 safe_setprop(ev, value_attr, cp);
9433 children++;
9436 if (ret != 0)
9437 scfdie();
9439 if (children == 0) {
9440 xmlFreeNode(env);
9441 return (NULL);
9444 return (env);
9448 * As above, but for a method property group.
9450 static void
9451 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
9453 xmlNodePtr n, env;
9454 char *str;
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. */
9464 /* name */
9465 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9466 scfdie();
9467 safe_setprop(n, name_attr, exp_str);
9469 /* type */
9470 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9471 set_attr_from_prop(exp_prop, n, type_attr) != 0)
9472 err = 1;
9474 /* exec */
9475 if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
9476 set_attr_from_prop(exp_prop, n, "exec") != 0)
9477 err = 1;
9479 /* timeout */
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) {
9483 uint64_t c;
9485 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
9486 scfdie();
9488 str = uu_msprintf("%llu", c);
9489 if (str == NULL)
9490 uu_die(gettext("Could not create string"));
9492 safe_setprop(n, "timeout_seconds", str);
9493 free(str);
9494 } else
9495 err = 1;
9497 if (err) {
9498 xmlFreeNode(n);
9500 export_pg(pg, eelts, SCE_ALL_VALUES);
9502 return;
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.
9513 nonenv =
9514 scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
9515 SCF_SUCCESS ||
9516 scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
9517 SCF_SUCCESS ||
9518 scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
9519 SCF_SUCCESS ||
9520 scf_pg_get_property(pg, SCF_PROPERTY_SECFLAGS, NULL) ==
9521 SCF_SUCCESS ||
9522 scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
9523 SCF_SUCCESS;
9525 if (nonenv) {
9526 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9527 if (ctxt == NULL)
9528 uu_die(emsg_create_xml);
9530 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
9531 0 &&
9532 set_attr_from_prop_default(exp_prop, ctxt,
9533 "working_directory", ":default") != 0)
9534 err = 1;
9536 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
9537 set_attr_from_prop_default(exp_prop, ctxt, "project",
9538 ":default") != 0)
9539 err = 1;
9541 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
9542 0 &&
9543 set_attr_from_prop_default(exp_prop, ctxt,
9544 "resource_pool", ":default") != 0)
9545 err = 1;
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)
9550 err = 1;
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) !=
9561 SCF_SUCCESS) {
9562 scfdie();
9565 if (use_profile) {
9566 xmlNodePtr prof;
9568 prof = xmlNewChild(ctxt, NULL,
9569 (xmlChar *)"method_profile", NULL);
9570 if (prof == NULL)
9571 uu_die(emsg_create_xml);
9573 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
9574 exp_prop) != 0 ||
9575 set_attr_from_prop(exp_prop, prof,
9576 name_attr) != 0)
9577 err = 1;
9578 } else {
9579 xmlNodePtr cred;
9581 cred = xmlNewChild(ctxt, NULL,
9582 (xmlChar *)"method_credential", NULL);
9583 if (cred == NULL)
9584 uu_die(emsg_create_xml);
9586 if (pg_get_prop(pg, SCF_PROPERTY_USER,
9587 exp_prop) != 0 ||
9588 set_attr_from_prop(exp_prop, cred,
9589 "user") != 0) {
9590 err = 1;
9593 if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
9594 exp_prop) == 0 &&
9595 set_attr_from_prop_default(exp_prop, cred,
9596 "group", ":default") != 0)
9597 err = 1;
9599 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
9600 exp_prop) == 0 &&
9601 set_attr_from_prop_default(exp_prop, cred,
9602 "supp_groups", ":default") != 0)
9603 err = 1;
9605 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
9606 exp_prop) == 0 &&
9607 set_attr_from_prop_default(exp_prop, cred,
9608 "privileges", ":default") != 0)
9609 err = 1;
9611 if (pg_get_prop(pg,
9612 SCF_PROPERTY_LIMIT_PRIVILEGES,
9613 exp_prop) == 0 &&
9614 set_attr_from_prop_default(exp_prop, cred,
9615 "limit_privileges", ":default") != 0)
9616 err = 1;
9621 if ((env = export_method_environment(pg)) != NULL) {
9622 if (ctxt == NULL) {
9623 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9624 if (ctxt == NULL)
9625 uu_die(emsg_create_xml);
9627 (void) xmlAddChild(ctxt, env);
9630 if (env != NULL || (nonenv && err == 0))
9631 (void) xmlAddChild(n, ctxt);
9632 else
9633 xmlFreeNode(ctxt);
9635 nonenv = (err == 0);
9637 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9638 scfdie();
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)
9644 scfdie();
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) {
9649 continue;
9650 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9651 xmlNodePtr m;
9653 m = xmlNewNode(NULL, (xmlChar *)"stability");
9654 if (m == NULL)
9655 uu_die(emsg_create_xml);
9657 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9658 elts.stability = m;
9659 continue;
9662 xmlFreeNode(m);
9663 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
9664 0 ||
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) {
9668 if (nonenv)
9669 continue;
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)
9677 continue;
9678 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9679 if (nonenv && use_profile)
9680 continue;
9681 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
9682 if (env != NULL)
9683 continue;
9686 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9688 if (ret == -1)
9689 scfdie();
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;
9697 else
9698 (void) xmlAddSibling(eelts->exec_methods, n);
9701 static void
9702 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
9703 struct entity_elts *eelts)
9705 xmlNodePtr pgnode;
9707 pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
9708 if (pgnode == NULL)
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;
9719 else
9720 (void) xmlAddSibling(eelts->property_groups, pgnode);
9724 * Process the general property group for a service. This is the one with the
9725 * goodies.
9727 static void
9728 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
9730 struct pg_elts elts;
9731 int ret;
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
9736 * put them in.
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)
9742 scfdie();
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)
9746 scfdie();
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) {
9751 uint8_t b;
9753 if (scf_value_get_boolean(exp_val, &b) !=
9754 SCF_SUCCESS)
9755 scfdie();
9757 if (b) {
9758 selts->single_instance =
9759 xmlNewNode(NULL,
9760 (xmlChar *)"single_instance");
9761 if (selts->single_instance == NULL)
9762 uu_die(emsg_create_xml);
9765 continue;
9767 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9768 xmlNodePtr rnode, sfnode;
9770 rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9771 if (rnode == NULL)
9772 uu_die(emsg_create_xml);
9774 sfnode = xmlNewChild(rnode, NULL,
9775 (xmlChar *)"service_fmri", NULL);
9776 if (sfnode == NULL)
9777 uu_die(emsg_create_xml);
9779 if (set_attr_from_prop(exp_prop, sfnode,
9780 value_attr) == 0) {
9781 selts->restarter = rnode;
9782 continue;
9785 xmlFreeNode(rnode);
9786 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
9787 0) {
9788 xmlNodePtr s;
9790 s = xmlNewNode(NULL, (xmlChar *)"stability");
9791 if (s == NULL)
9792 uu_die(emsg_create_xml);
9794 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9795 selts->stability = s;
9796 continue;
9799 xmlFreeNode(s);
9802 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9804 if (ret == -1)
9805 scfdie();
9807 if (elts.propvals != NULL || elts.properties != NULL)
9808 export_pg_elts(&elts, scf_pg_general, scf_group_framework,
9809 selts);
9812 static void
9813 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
9815 xmlNodePtr n, prof, cred, env;
9816 uint8_t use_profile;
9817 int ret, err = 0;
9819 n = xmlNewNode(NULL, (xmlChar *)"method_context");
9820 prof = NULL;
9821 cred = NULL;
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)
9830 scfdie();
9832 if (use_profile)
9833 prof =
9834 xmlNewChild(n, NULL, (xmlChar *)"method_profile",
9835 NULL);
9836 else
9837 cred =
9838 xmlNewChild(n, NULL, (xmlChar *)"method_credential",
9839 NULL);
9842 if (env != NULL)
9843 (void) xmlAddChild(n, env);
9845 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9846 scfdie();
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)
9850 scfdie();
9852 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
9853 if (set_attr_from_prop(exp_prop, n,
9854 "working_directory") != 0)
9855 err = 1;
9856 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
9857 if (set_attr_from_prop(exp_prop, n, "project") != 0)
9858 err = 1;
9859 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
9860 if (set_attr_from_prop(exp_prop, n,
9861 "resource_pool") != 0)
9862 err = 1;
9863 } else if (strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9864 if (set_attr_from_prop(exp_prop, n,
9865 "security_flags") != 0)
9866 err = 1;
9867 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9868 /* EMPTY */
9869 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
9870 if (use_profile ||
9871 set_attr_from_prop(exp_prop, cred, "user") != 0)
9872 err = 1;
9873 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
9874 if (use_profile ||
9875 set_attr_from_prop(exp_prop, cred, "group") != 0)
9876 err = 1;
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)
9880 err = 1;
9881 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
9882 if (use_profile || set_attr_from_prop(exp_prop, cred,
9883 "privileges") != 0)
9884 err = 1;
9885 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
9886 0) {
9887 if (use_profile || set_attr_from_prop(exp_prop, cred,
9888 "limit_privileges") != 0)
9889 err = 1;
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)
9893 err = 1;
9894 } else {
9895 /* Can't have generic properties in method_context's */
9896 err = 1;
9899 if (ret == -1)
9900 scfdie();
9902 if (err && env == NULL) {
9903 xmlFreeNode(n);
9904 export_pg(pg, elts, SCE_ALL_VALUES);
9905 return;
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.
9915 static xmlNodePtr
9916 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
9918 uint8_t b;
9919 xmlNodePtr n, sf;
9920 int err = 0, ret;
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
9926 * duplication.
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) {
9931 if (g_verbose) {
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);
9938 return (NULL);
9941 n = xmlNewNode(NULL, (xmlChar *)"dependent");
9942 if (n == NULL)
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)
9950 err = 1;
9952 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9953 set_attr_from_prop(exp_prop, n, "grouping") != 0)
9954 err = 1;
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) {
9959 /* EMPTY */
9960 } else
9961 err = 1;
9963 if (err) {
9964 xmlFreeNode(n);
9965 return (NULL);
9968 sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
9969 if (sf == 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)
9978 scfdie();
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)
9984 scfdie();
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) {
9990 continue;
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,
9997 sizeof (type)) < 0)
9998 scfdie();
10000 if (strcmp(type, "service") == 0)
10001 continue;
10003 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
10004 xmlNodePtr s;
10006 s = xmlNewNode(NULL, (xmlChar *)"stability");
10007 if (s == NULL)
10008 uu_die(emsg_create_xml);
10010 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
10011 pgelts.stability = s;
10012 continue;
10015 xmlFreeNode(s);
10018 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10020 if (ret == -1)
10021 scfdie();
10023 (void) xmlAddChild(n, pgelts.stability);
10024 (void) xmlAddChildList(n, pgelts.propvals);
10025 (void) xmlAddChildList(n, pgelts.properties);
10027 return (n);
10030 static void
10031 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
10033 scf_propertygroup_t *opg;
10034 scf_iter_t *iter;
10035 char *type, *fmri;
10036 int ret;
10037 struct pg_elts pgelts;
10038 xmlNodePtr n;
10039 scf_error_t serr;
10041 if ((opg = scf_pg_create(g_hndl)) == NULL ||
10042 (iter = scf_iter_create(g_hndl)) == NULL)
10043 scfdie();
10045 /* Can't use exp_prop_iter due to export_dependent(). */
10046 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
10047 scfdie();
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) {
10057 void *entity;
10058 int isservice;
10059 scf_type_t ty;
10061 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
10062 scfdie();
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,
10068 SCE_ALL_VALUES);
10069 continue;
10072 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10073 scfdie();
10075 if (scf_value_get_astring(exp_val, fmri,
10076 max_scf_fmri_len + 2) < 0)
10077 scfdie();
10079 /* Look for a dependency group in the target fmri. */
10080 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
10081 switch (serr) {
10082 case SCF_ERROR_NONE:
10083 break;
10085 case SCF_ERROR_NO_MEMORY:
10086 uu_die(gettext("Out of memory.\n"));
10087 /* NOTREACHED */
10089 case SCF_ERROR_INVALID_ARGUMENT:
10090 if (g_verbose) {
10091 if (scf_property_to_fmri(exp_prop, fmri,
10092 max_scf_fmri_len + 2) < 0)
10093 scfdie();
10095 warn(gettext("The value of %s is not a valid "
10096 "FMRI.\n"), fmri);
10099 export_property(exp_prop, exp_str, &pgelts,
10100 SCE_ALL_VALUES);
10101 continue;
10103 case SCF_ERROR_CONSTRAINT_VIOLATED:
10104 if (g_verbose) {
10105 if (scf_property_to_fmri(exp_prop, fmri,
10106 max_scf_fmri_len + 2) < 0)
10107 scfdie();
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,
10114 SCE_ALL_VALUES);
10115 continue;
10117 case SCF_ERROR_NOT_FOUND:
10118 if (g_verbose) {
10119 if (scf_property_to_fmri(exp_prop, fmri,
10120 max_scf_fmri_len + 2) < 0)
10121 scfdie();
10123 warn(gettext("The entity specified by %s does "
10124 "not exist.\n"), fmri);
10127 export_property(exp_prop, exp_str, &pgelts,
10128 SCE_ALL_VALUES);
10129 continue;
10131 default:
10132 #ifndef NDEBUG
10133 (void) fprintf(stderr, "%s:%d: %s() failed with "
10134 "unexpected error %d.\n", __FILE__, __LINE__,
10135 "fmri_to_entity", serr);
10136 #endif
10137 abort();
10140 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
10141 if (scf_error() != SCF_ERROR_NOT_FOUND)
10142 scfdie();
10144 warn(gettext("Entity %s is missing dependency property "
10145 "group %s.\n"), fmri, exp_str);
10147 export_property(exp_prop, NULL, &pgelts,
10148 SCE_ALL_VALUES);
10149 continue;
10152 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
10153 scfdie();
10155 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
10156 if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
10157 scfdie();
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,
10163 SCE_ALL_VALUES);
10164 continue;
10167 n = export_dependent(opg, exp_str, fmri);
10168 if (n == NULL) {
10169 export_property(exp_prop, exp_str, &pgelts,
10170 SCE_ALL_VALUES);
10171 } else {
10172 if (eelts->dependents == NULL)
10173 eelts->dependents = n;
10174 else
10175 (void) xmlAddSibling(eelts->dependents,
10179 if (ret == -1)
10180 scfdie();
10182 free(fmri);
10183 free(type);
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,
10190 eelts);
10193 static void
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);
10203 static xmlNodePtr
10204 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
10206 int ret;
10207 xmlNodePtr parent = NULL;
10208 xmlNodePtr loctext = NULL;
10210 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10211 scfdie();
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)
10216 continue;
10218 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
10219 scfdie();
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)
10228 scfdie();
10230 safe_setprop(loctext, "xml:lang", exp_str);
10233 if (ret == -1)
10234 scfdie();
10236 return (parent);
10239 static xmlNodePtr
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);
10251 return (NULL);
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");
10258 return (manpage);
10261 static xmlNodePtr
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);
10273 return (NULL);
10275 return (doc_link);
10279 * Process template information for a service or instances.
10281 static void
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)
10290 scfdie();
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);
10296 return;
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);
10301 return;
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);
10313 } else {
10314 export_pg(pg, elts, SCE_ALL_VALUES);
10319 * Process parameter and paramval elements
10321 static void
10322 export_parameter(scf_property_t *prop, const char *name,
10323 struct params_elts *elts)
10325 xmlNodePtr param;
10326 scf_error_t err = 0;
10327 int ret;
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)
10336 scfdie();
10337 safe_setprop(param, value_attr, exp_str);
10339 if (elts->paramval == NULL)
10340 elts->paramval = param;
10341 else
10342 (void) xmlAddSibling(elts->paramval, param);
10344 return;
10347 err = scf_error();
10349 if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
10350 err != SCF_ERROR_NOT_FOUND)
10351 scfdie();
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)
10360 scfdie();
10362 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
10363 1) {
10364 xmlNodePtr vn;
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,
10371 exp_str_sz) < 0)
10372 scfdie();
10374 safe_setprop(vn, value_attr, exp_str);
10376 if (ret != 0)
10377 scfdie();
10380 if (elts->parameter == NULL)
10381 elts->parameter = param;
10382 else
10383 (void) xmlAddSibling(elts->parameter, param);
10387 * Process notification parameters for a service or instance
10389 static void
10390 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts)
10392 xmlNodePtr n, event, *type;
10393 struct params_elts *eelts;
10394 int ret, err, i;
10395 char *s;
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);
10402 /* event value */
10403 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
10404 scfdie();
10405 /* trim SCF_NOTIFY_PG_POSTFIX appended to name on import */
10406 if ((s = strchr(exp_str, ',')) != NULL)
10407 *s = '\0';
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"));
10417 err = 0;
10419 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10420 scfdie();
10422 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10423 char *t, *p;
10425 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10426 scfdie();
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
10433 err = 1;
10434 break;
10437 if ((i = check_uri_protocol(t)) < 0) {
10438 err = 1;
10439 break;
10442 if (type[i] == NULL) {
10443 if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) ==
10444 NULL)
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) {
10452 err = 1;
10453 break;
10455 continue;
10458 * We export the parameter
10460 export_parameter(exp_prop, p, &eelts[i]);
10463 if (ret == -1)
10464 scfdie();
10466 if (err == 1) {
10467 for (i = 0; i < URI_SCHEME_NUM; ++i)
10468 xmlFree(type[i]);
10469 free(type);
10471 export_pg(pg, elts, SCE_ALL_VALUES);
10473 return;
10474 } else {
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]);
10484 free(type);
10486 if (elts->notify_params == NULL)
10487 elts->notify_params = n;
10488 else
10489 (void) xmlAddSibling(elts->notify_params, n);
10493 * Process the general property group for an instance.
10495 static void
10496 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
10497 struct entity_elts *elts)
10499 uint8_t enabled;
10500 struct pg_elts pgelts;
10501 int ret;
10503 /* enabled */
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)
10508 scfdie();
10509 } else {
10510 enabled = 0;
10513 safe_setprop(inode, enabled_attr, enabled ? true : false);
10515 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10516 scfdie();
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)
10522 scfdie();
10524 if (strcmp(exp_str, scf_property_enabled) == 0) {
10525 continue;
10526 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
10527 xmlNodePtr rnode, sfnode;
10529 rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10530 if (rnode == NULL)
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;
10541 continue;
10544 xmlFreeNode(rnode);
10547 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10549 if (ret == -1)
10550 scfdie();
10552 if (pgelts.propvals != NULL || pgelts.properties != NULL)
10553 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10554 elts);
10558 * Put an instance element for the given instance into selts.
10560 static void
10561 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10563 xmlNodePtr n;
10564 boolean_t isdefault;
10565 struct entity_elts elts;
10566 struct template_elts template_elts;
10567 int ret;
10569 n = xmlNewNode(NULL, (xmlChar *)"instance");
10570 if (n == NULL)
10571 uu_die(emsg_create_xml);
10573 /* name */
10574 if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10575 scfdie();
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)
10582 scfdie();
10584 if (g_verbose) {
10585 if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10586 scfdie();
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) {
10595 if (g_verbose) {
10596 if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10597 scfdie();
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)
10609 scfdie();
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) {
10615 uint32_t pgflags;
10617 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10618 scfdie();
10620 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10621 continue;
10623 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10624 scfdie();
10626 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10627 export_dependency(exp_pg, &elts);
10628 continue;
10629 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10630 export_method(exp_pg, &elts);
10631 continue;
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)
10635 scfdie();
10637 if (strcmp(exp_str, scf_pg_general) == 0) {
10638 export_inst_general(exp_pg, n, &elts);
10639 continue;
10640 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10641 0) {
10642 export_method_context(exp_pg, &elts);
10643 continue;
10644 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10645 export_dependents(exp_pg, &elts);
10646 continue;
10648 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10649 export_template(exp_pg, &elts, &template_elts);
10650 continue;
10651 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10652 export_notify_params(exp_pg, &elts);
10653 continue;
10656 /* Ordinary pg. */
10657 export_pg(exp_pg, &elts, flags);
10659 if (ret == -1)
10660 scfdie();
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);
10667 } else {
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) {
10676 xmlChar *eval;
10678 /* This is a default instance */
10679 eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10681 xmlFreeNode(n);
10683 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10684 if (n == NULL)
10685 uu_die(emsg_create_xml);
10687 safe_setprop(n, enabled_attr, (char *)eval);
10688 xmlFree(eval);
10690 selts->create_default_instance = n;
10691 } else {
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;
10704 else
10705 (void) xmlAddSibling(selts->instances, n);
10710 * Return a service element for the given service.
10712 static xmlNodePtr
10713 export_service(scf_service_t *svc, int flags)
10715 xmlNodePtr snode;
10716 struct entity_elts elts;
10717 struct template_elts template_elts;
10718 int ret;
10720 snode = xmlNewNode(NULL, (xmlChar *)"service");
10721 if (snode == NULL)
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)
10726 scfdie();
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)
10734 scfdie();
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) {
10740 uint32_t pgflags;
10742 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10743 scfdie();
10745 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10746 continue;
10748 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10749 scfdie();
10751 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10752 export_dependency(exp_pg, &elts);
10753 continue;
10754 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10755 export_method(exp_pg, &elts);
10756 continue;
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)
10760 scfdie();
10762 if (strcmp(exp_str, scf_pg_general) == 0) {
10763 export_svc_general(exp_pg, &elts);
10764 continue;
10765 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10766 0) {
10767 export_method_context(exp_pg, &elts);
10768 continue;
10769 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10770 export_dependents(exp_pg, &elts);
10771 continue;
10772 } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10773 continue;
10775 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10776 export_template(exp_pg, &elts, &template_elts);
10777 continue;
10778 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10779 export_notify_params(exp_pg, &elts);
10780 continue;
10783 export_pg(exp_pg, &elts, flags);
10785 if (ret == -1)
10786 scfdie();
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);
10793 } else {
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)
10800 scfdie();
10802 while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10803 export_instance(exp_inst, &elts, flags);
10804 if (ret == -1)
10805 scfdie();
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);
10821 return (snode);
10824 static int
10825 export_callback(void *data, scf_walkinfo_t *wip)
10827 FILE *f;
10828 xmlDocPtr doc;
10829 xmlNodePtr sb;
10830 int result;
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)
10841 scfdie();
10843 exp_str_sz = max_scf_len + 1;
10844 exp_str = safe_malloc(exp_str_sz);
10846 if (argsp->filename != NULL) {
10847 errno = 0;
10848 f = fopen(argsp->filename, "wb");
10849 if (f == NULL) {
10850 if (errno == 0)
10851 uu_die(gettext("Could not open \"%s\": no free "
10852 "stdio streams.\n"), argsp->filename);
10853 else
10854 uu_die(gettext("Could not open \"%s\""),
10855 argsp->filename);
10857 } else
10858 f = stdout;
10860 doc = xmlNewDoc((xmlChar *)"1.0");
10861 if (doc == NULL)
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");
10869 if (sb == NULL)
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);
10879 free(exp_str);
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);
10889 xmlFreeDoc(doc);
10891 if (f != stdout)
10892 (void) fclose(f);
10894 return (result);
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;
10905 char *fmridup;
10906 const char *scope, *svc, *inst;
10907 size_t cblen = 3 * max_scf_name_len;
10908 char *canonbuf = alloca(cblen);
10909 int ret, err;
10911 lscf_prep_hndl();
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 &&
10927 inst != NULL) {
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);
10934 fmri = canonbuf;
10936 warn(gettext("Only services may be exported; ignoring "
10937 "instance portion of argument.\n"));
10940 err = 0;
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) {
10944 if (ret != -1)
10945 semerr(gettext("Failed to walk instances: %s\n"),
10946 scf_strerror(ret));
10947 return (-1);
10951 * Error message has already been printed.
10953 if (err != 0)
10954 return (-1);
10956 return (0);
10961 * Archive
10964 static xmlNodePtr
10965 make_archive(int flags)
10967 xmlNodePtr sb;
10968 scf_scope_t *scope;
10969 scf_service_t *svc;
10970 scf_iter_t *iter;
10971 int r;
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)
10984 scfdie();
10986 exp_str_sz = max_scf_len + 1;
10987 exp_str = safe_malloc(exp_str_sz);
10989 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10990 if (sb == NULL)
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)
10996 scfdie();
10997 if (scf_iter_scope_services(iter, scope) != 0)
10998 scfdie();
11000 for (;;) {
11001 r = scf_iter_next_service(iter, svc);
11002 if (r == 0)
11003 break;
11004 if (r != 1)
11005 scfdie();
11007 if (scf_service_get_name(svc, exp_str,
11008 max_scf_name_len + 1) < 0)
11009 scfdie();
11011 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
11012 continue;
11014 (void) xmlAddChild(sb, export_service(svc, flags));
11017 free(exp_str);
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);
11031 return (sb);
11035 lscf_archive(const char *filename, int flags)
11037 FILE *f;
11038 xmlDocPtr doc;
11039 int result;
11041 lscf_prep_hndl();
11043 if (filename != NULL) {
11044 errno = 0;
11045 f = fopen(filename, "wb");
11046 if (f == NULL) {
11047 if (errno == 0)
11048 uu_die(gettext("Could not open \"%s\": no free "
11049 "stdio streams.\n"), filename);
11050 else
11051 uu_die(gettext("Could not open \"%s\""),
11052 filename);
11054 } else
11055 f = stdout;
11057 doc = xmlNewDoc((xmlChar *)"1.0");
11058 if (doc == NULL)
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);
11069 xmlFreeDoc(doc);
11071 if (f != stdout)
11072 (void) fclose(f);
11074 return (result);
11079 * "Extract" a profile.
11082 lscf_profile_extract(const char *filename)
11084 FILE *f;
11085 xmlDocPtr doc;
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;
11092 scf_value_t *val;
11093 scf_iter_t *siter, *iiter;
11094 int r, s;
11095 char *namebuf;
11096 uint8_t b;
11097 int result;
11099 lscf_prep_hndl();
11101 if (filename != NULL) {
11102 errno = 0;
11103 f = fopen(filename, "wb");
11104 if (f == NULL) {
11105 if (errno == 0)
11106 uu_die(gettext("Could not open \"%s\": no "
11107 "free stdio streams.\n"), filename);
11108 else
11109 uu_die(gettext("Could not open \"%s\""),
11110 filename);
11112 } else
11113 f = stdout;
11115 doc = xmlNewDoc((xmlChar *)"1.0");
11116 if (doc == NULL)
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");
11124 if (sb == NULL)
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)
11138 scfdie();
11140 if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
11141 scfdie();
11143 if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
11144 scfdie();
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)
11150 scfdie();
11152 snode = xmlNewNode(NULL, (xmlChar *)"service");
11153 if (snode == NULL)
11154 uu_die(emsg_create_xml);
11156 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
11158 scfdie();
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) !=
11167 SCF_SUCCESS) {
11168 if (scf_error() != SCF_ERROR_NOT_FOUND)
11169 scfdie();
11171 if (g_verbose) {
11172 ssize_t len;
11173 char *fmri;
11175 len =
11176 scf_instance_to_fmri(inst, NULL, 0);
11177 if (len < 0)
11178 scfdie();
11180 fmri = safe_malloc(len + 1);
11182 if (scf_instance_to_fmri(inst, fmri,
11183 len + 1) < 0)
11184 scfdie();
11186 warn("Instance %s has no \"%s\" "
11187 "property group.\n", fmri,
11188 scf_pg_general);
11190 free(fmri);
11193 continue;
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)
11199 continue;
11201 inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
11202 NULL);
11203 if (inode == NULL)
11204 uu_die(emsg_create_xml);
11206 if (scf_instance_get_name(inst, namebuf,
11207 max_scf_name_len + 1) < 0)
11208 scfdie();
11210 safe_setprop(inode, name_attr, namebuf);
11212 if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
11213 scfdie();
11215 safe_setprop(inode, enabled_attr, b ? true : false);
11217 if (s < 0)
11218 scfdie();
11220 if (snode->children != NULL)
11221 (void) xmlAddChild(sb, snode);
11222 else
11223 xmlFreeNode(snode);
11225 if (r < 0)
11226 scfdie();
11228 free(namebuf);
11230 result = write_service_bundle(doc, f);
11232 xmlFreeDoc(doc);
11234 if (f != stdout)
11235 (void) fclose(f);
11237 return (result);
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) */
11254 static int
11255 select_inst(const char *name)
11257 scf_instance_t *inst;
11258 scf_error_t err;
11260 assert(cur_svc != NULL);
11262 inst = scf_instance_create(g_hndl);
11263 if (inst == NULL)
11264 scfdie();
11266 if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
11267 cur_inst = inst;
11268 return (0);
11271 err = scf_error();
11272 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11273 scfdie();
11275 scf_instance_destroy(inst);
11276 return (1);
11279 /* Returns as above. */
11280 static int
11281 select_svc(const char *name)
11283 scf_service_t *svc;
11284 scf_error_t err;
11286 assert(cur_scope != NULL);
11288 svc = scf_service_create(g_hndl);
11289 if (svc == NULL)
11290 scfdie();
11292 if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
11293 cur_svc = svc;
11294 return (0);
11297 err = scf_error();
11298 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11299 scfdie();
11301 scf_service_destroy(svc);
11302 return (1);
11305 /* ARGSUSED */
11306 static int
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)
11317 scfdie();
11319 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11320 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11321 scfdie();
11322 } else {
11323 assert(wip->svc != NULL);
11325 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11326 (svc = scf_service_create(g_hndl)) == NULL)
11327 scfdie();
11329 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11330 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11331 scfdie();
11333 inst = NULL;
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);
11342 cur_scope = scope;
11343 cur_svc = svc;
11344 cur_inst = inst;
11346 return (0);
11349 static int
11350 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
11352 char **fmri = fmri_p;
11354 *fmri = strdup(wip->fmri);
11355 if (*fmri == NULL)
11356 uu_die(gettext("Out of memory.\n"));
11358 return (0);
11362 * validate [fmri]
11363 * Perform the validation of an FMRI instance.
11365 void
11366 lscf_validate_fmri(const char *fmri)
11368 int ret = 0;
11369 size_t inst_sz;
11370 char *inst_fmri = NULL;
11371 scf_tmpl_errors_t *errs = NULL;
11372 char *snapbuf = NULL;
11374 lscf_prep_hndl();
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)
11384 scfdie();
11386 if (cur_inst == NULL) {
11387 semerr(gettext("No instance selected\n"));
11388 goto cleanup;
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__);
11395 } else {
11396 scf_error_t scf_err;
11397 int err = 0;
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));
11403 goto cleanup;
11405 if (err != 0) {
11406 /* error message displayed by scf_walk_fmri */
11407 goto cleanup;
11411 ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
11412 SCF_TMPL_VALIDATE_FLAG_CURRENT);
11413 if (ret == -1) {
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);
11418 } else {
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;
11425 char *msg;
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) {
11433 int ret;
11435 if ((ret = scf_tmpl_strerror(err, msg, len,
11436 flag)) >= len) {
11437 len = ret + 1;
11438 msg = realloc(msg, len);
11439 if (msg == NULL)
11440 uu_die(gettext(
11441 "Out of memory.\n"));
11442 (void) scf_tmpl_strerror(err, msg, len,
11443 flag);
11445 (void) fprintf(stderr, "%s\n", msg);
11447 free(msg);
11449 if (errs != NULL)
11450 scf_tmpl_errors_destroy(errs);
11452 cleanup:
11453 free(inst_fmri);
11454 free(snapbuf);
11457 static void
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]
11476 void
11477 lscf_validate(const char *arg)
11479 const char *str;
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);
11491 } else {
11492 lscf_validate_fmri(arg);
11496 void
11497 lscf_select(const char *fmri)
11499 int ret, err;
11501 lscf_prep_hndl();
11503 if (cur_snap != NULL) {
11504 struct snaplevel *elt;
11505 char *buf;
11507 /* Error unless name is that of the next level. */
11508 elt = uu_list_next(cur_levels, cur_elt);
11509 if (elt == NULL) {
11510 semerr(gettext("No children.\n"));
11511 return;
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)
11518 scfdie();
11520 if (strcmp(buf, fmri) != 0) {
11521 semerr(gettext("No such child.\n"));
11522 free(buf);
11523 return;
11526 free(buf);
11528 cur_elt = elt;
11529 cur_level = elt->sl;
11530 return;
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);
11539 cur_inst = NULL;
11540 cur_svc = NULL;
11541 return;
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"));
11551 return;
11555 * First try the argument as relative to the current selection.
11557 if (cur_inst != NULL) {
11558 /* EMPTY */;
11559 } else if (cur_svc != NULL) {
11560 if (select_inst(fmri) != 1)
11561 return;
11562 } else {
11563 if (select_svc(fmri) != 1)
11564 return;
11567 err = 0;
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));
11575 void
11576 lscf_unselect(void)
11578 lscf_prep_hndl();
11580 if (cur_snap != NULL) {
11581 struct snaplevel *elt;
11583 elt = uu_list_prev(cur_levels, cur_elt);
11584 if (elt == NULL) {
11585 semerr(gettext("No parent levels.\n"));
11586 } else {
11587 cur_elt = elt;
11588 cur_level = elt->sl;
11590 } else if (cur_inst != NULL) {
11591 scf_instance_destroy(cur_inst);
11592 cur_inst = NULL;
11593 } else if (cur_svc != NULL) {
11594 scf_service_destroy(cur_svc);
11595 cur_svc = NULL;
11596 } else {
11597 semerr(gettext("Cannot unselect at scope level.\n"));
11602 * Return the FMRI of the current selection, for the prompt.
11604 void
11605 lscf_get_selection_str(char *buf, size_t bufsz)
11607 char *cp;
11608 ssize_t fmrilen, szret;
11609 boolean_t deleted = B_FALSE;
11611 if (g_hndl == NULL) {
11612 (void) strlcpy(buf, "svc:", bufsz);
11613 return;
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);
11623 buf[0] = '[';
11625 szret = scf_snapshot_get_name(cur_snap, buf + 1,
11626 max_scf_name_len + 1);
11627 if (szret < 0) {
11628 if (scf_error() != SCF_ERROR_DELETED)
11629 scfdie();
11631 goto snap_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);
11640 if (szret < 0) {
11641 if (scf_error() != SCF_ERROR_DELETED)
11642 scfdie();
11644 goto snap_deleted;
11647 cp = strchr(cp, '\0');
11649 if (snaplevel_is_instance(cur_level)) {
11650 *cp++ = ':';
11652 if (scf_snaplevel_get_instance_name(cur_level, cp,
11653 max_scf_name_len + 1) < 0) {
11654 if (scf_error() != SCF_ERROR_DELETED)
11655 scfdie();
11657 goto snap_deleted;
11659 } else {
11660 *cp++ = '[';
11661 *cp++ = ':';
11663 if (scf_instance_get_name(cur_inst, cp,
11664 max_scf_name_len + 1) < 0) {
11665 if (scf_error() != SCF_ERROR_DELETED)
11666 scfdie();
11668 goto snap_deleted;
11671 (void) strcat(buf, "]");
11674 return;
11676 snap_deleted:
11677 deleted = B_TRUE;
11678 free(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);
11691 if (deleted)
11692 warn(emsg_deleted);
11693 return;
11696 if (scf_error() != SCF_ERROR_DELETED)
11697 scfdie();
11699 deleted = B_TRUE;
11701 scf_instance_destroy(cur_inst);
11702 cur_inst = NULL;
11705 if (cur_svc != NULL) {
11706 assert(cur_scope != NULL);
11708 szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11709 if (szret >= 0) {
11710 assert(szret < bufsz);
11711 if (deleted)
11712 warn(emsg_deleted);
11713 return;
11716 if (scf_error() != SCF_ERROR_DELETED)
11717 scfdie();
11719 deleted = B_TRUE;
11720 scf_service_destroy(cur_svc);
11721 cur_svc = NULL;
11724 assert(cur_scope != NULL);
11725 fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11727 if (fmrilen < 0)
11728 scfdie();
11730 assert(fmrilen < bufsz);
11731 if (deleted)
11732 warn(emsg_deleted);
11736 * Entity listing. Entities and colon namespaces (e.g., :properties and
11737 * :statistics) are listed for the current selection.
11739 void
11740 lscf_list(const char *pattern)
11742 scf_iter_t *iter;
11743 char *buf;
11744 int ret;
11746 lscf_prep_hndl();
11748 if (cur_level != NULL) {
11749 struct snaplevel *elt;
11751 (void) fputs(COLON_NAMESPACES, stdout);
11753 elt = uu_list_next(cur_levels, cur_elt);
11754 if (elt == NULL)
11755 return;
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) {
11764 (void) puts(buf);
11765 } else {
11766 if (scf_error() != SCF_ERROR_DELETED)
11767 scfdie();
11770 free(buf);
11772 return;
11775 if (cur_inst != NULL) {
11776 (void) fputs(COLON_NAMESPACES, stdout);
11777 return;
11780 iter = scf_iter_create(g_hndl);
11781 if (iter == NULL)
11782 scfdie();
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);
11791 if (inst == NULL)
11792 scfdie();
11794 if (scf_iter_service_instances(iter, cur_svc) == 0) {
11795 safe_printf(COLON_NAMESPACES);
11797 for (;;) {
11798 ret = scf_iter_next_instance(iter, inst);
11799 if (ret == 0)
11800 break;
11801 if (ret != 1) {
11802 if (scf_error() != SCF_ERROR_DELETED)
11803 scfdie();
11805 break;
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)
11812 (void) puts(buf);
11813 } else {
11814 if (scf_error() != SCF_ERROR_DELETED)
11815 scfdie();
11818 } else {
11819 if (scf_error() != SCF_ERROR_DELETED)
11820 scfdie();
11823 scf_instance_destroy(inst);
11824 } else {
11825 /* List the services in this scope. */
11826 scf_service_t *svc;
11828 assert(cur_scope != NULL);
11830 svc = scf_service_create(g_hndl);
11831 if (svc == NULL)
11832 scfdie();
11834 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11835 scfdie();
11837 for (;;) {
11838 ret = scf_iter_next_service(iter, svc);
11839 if (ret == 0)
11840 break;
11841 if (ret != 1)
11842 scfdie();
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);
11849 } else {
11850 if (scf_error() != SCF_ERROR_DELETED)
11851 scfdie();
11855 scf_service_destroy(svc);
11858 free(buf);
11859 scf_iter_destroy(iter);
11863 * Entity addition. Creates an empty entity in the current selection.
11865 void
11866 lscf_add(const char *name)
11868 lscf_prep_hndl();
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) !=
11877 SCF_SUCCESS) {
11878 switch (scf_error()) {
11879 case SCF_ERROR_INVALID_ARGUMENT:
11880 semerr(gettext("Invalid name.\n"));
11881 break;
11883 case SCF_ERROR_EXISTS:
11884 semerr(gettext("Instance already exists.\n"));
11885 break;
11887 case SCF_ERROR_PERMISSION_DENIED:
11888 semerr(emsg_permission_denied);
11889 break;
11891 default:
11892 scfdie();
11895 } else {
11896 assert(cur_scope != NULL);
11898 if (scf_scope_add_service(cur_scope, name, NULL) !=
11899 SCF_SUCCESS) {
11900 switch (scf_error()) {
11901 case SCF_ERROR_INVALID_ARGUMENT:
11902 semerr(gettext("Invalid name.\n"));
11903 break;
11905 case SCF_ERROR_EXISTS:
11906 semerr(gettext("Service already exists.\n"));
11907 break;
11909 case SCF_ERROR_PERMISSION_DENIED:
11910 semerr(emsg_permission_denied);
11911 break;
11913 case SCF_ERROR_BACKEND_READONLY:
11914 semerr(emsg_read_only);
11915 break;
11917 default:
11918 scfdie();
11924 /* return 1 if the entity has no persistent pgs, else return 0 */
11925 static int
11926 entity_has_no_pgs(void *ent, int isservice)
11928 scf_iter_t *iter = NULL;
11929 scf_propertygroup_t *pg = NULL;
11930 uint32_t flags;
11931 int err;
11932 int ret = 1;
11934 if ((iter = scf_iter_create(g_hndl)) == NULL ||
11935 (pg = scf_pg_create(g_hndl)) == NULL)
11936 scfdie();
11938 if (isservice) {
11939 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11940 scfdie();
11941 } else {
11942 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11943 scfdie();
11946 while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11947 if (scf_pg_get_flags(pg, &flags) != 0)
11948 scfdie();
11950 /* skip nonpersistent pgs */
11951 if (flags & SCF_PG_FLAG_NONPERSISTENT)
11952 continue;
11954 ret = 0;
11955 break;
11958 if (err == -1)
11959 scfdie();
11961 scf_pg_destroy(pg);
11962 scf_iter_destroy(iter);
11964 return (ret);
11967 /* return 1 if the service has no instances, else return 0 */
11968 static int
11969 svc_has_no_insts(scf_service_t *svc)
11971 scf_instance_t *inst;
11972 scf_iter_t *iter;
11973 int r;
11974 int ret = 1;
11976 if ((inst = scf_instance_create(g_hndl)) == NULL ||
11977 (iter = scf_iter_create(g_hndl)) == NULL)
11978 scfdie();
11980 if (scf_iter_service_instances(iter, svc) != 0)
11981 scfdie();
11983 r = scf_iter_next_instance(iter, inst);
11984 if (r == 1) {
11985 ret = 0;
11986 } else if (r == 0) {
11987 ret = 1;
11988 } else if (r == -1) {
11989 scfdie();
11990 } else {
11991 bad_error("scf_iter_next_instance", r);
11994 scf_iter_destroy(iter);
11995 scf_instance_destroy(inst);
11997 return (ret);
12001 * Entity deletion.
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
12009 * denied.
12011 static scf_error_t
12012 delete_dependency_pg(const char *fmri, const char *name)
12014 void *entity = NULL;
12015 int isservice;
12016 scf_propertygroup_t *pg = NULL;
12017 scf_error_t result;
12018 char *pgty;
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);
12025 switch (result) {
12026 case SCF_ERROR_NONE:
12027 break;
12029 case SCF_ERROR_NO_MEMORY:
12030 uu_die(gettext("Out of memory.\n"));
12031 /* NOTREACHED */
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;
12039 goto out;
12041 default:
12042 bad_error("fmri_to_entity", result);
12045 pg = scf_pg_create(g_hndl);
12046 if (pg == NULL)
12047 scfdie();
12049 if (entity_get_pg(entity, isservice, name, pg) != 0) {
12050 if (scf_error() != SCF_ERROR_NOT_FOUND)
12051 scfdie();
12053 result = SCF_ERROR_NONE;
12054 goto out;
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)
12060 scfdie();
12062 if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
12063 result = SCF_ERROR_TYPE_MISMATCH;
12064 free(pgty);
12065 goto out;
12068 free(pgty);
12070 if (scf_pg_delete(pg) != 0) {
12071 result = scf_error();
12072 if (result != SCF_ERROR_PERMISSION_DENIED)
12073 scfdie();
12074 goto out;
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;
12091 if (isservice) {
12092 svc = (scf_service_t *)entity;
12094 if ((inst = scf_instance_create(g_hndl)) == NULL ||
12095 (iter = scf_iter_create(g_hndl)) == NULL)
12096 scfdie();
12098 name_buf = safe_malloc(max_scf_name_len + 1);
12099 } else {
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)
12110 scfdie();
12112 if (scf_instance_get_parent(inst, svc) != 0)
12113 scfdie();
12115 /* delete the instance */
12116 if (scf_instance_delete(inst) != 0) {
12117 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12118 scfdie();
12120 result = SCF_ERROR_PERMISSION_DENIED;
12121 goto out;
12123 /* no need to refresh the instance */
12124 inst = NULL;
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.
12132 if (svc != NULL &&
12133 svc_has_no_insts(svc) &&
12134 entity_has_no_pgs((void *)svc, 1)) {
12135 if (scf_service_delete(svc) == 0) {
12136 if (isservice) {
12137 /* no need to refresh the service */
12138 svc = NULL;
12141 goto out;
12144 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12145 scfdie();
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,
12153 name_buf);
12156 out:
12157 if (isservice && (inst != NULL && iter != NULL)) {
12158 free(name_buf);
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);
12171 return (result);
12174 static int
12175 delete_dependents(scf_propertygroup_t *pg)
12177 char *pgty, *name, *fmri;
12178 scf_property_t *prop;
12179 scf_value_t *val;
12180 scf_iter_t *iter;
12181 int r;
12182 scf_error_t err;
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)
12187 scfdie();
12189 if (strcmp(pgty, scf_group_framework) != 0) {
12190 if (g_verbose) {
12191 fmri = safe_malloc(max_scf_fmri_len + 1);
12192 if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
12193 scfdie();
12195 warn(gettext("Property group %s is not of expected "
12196 "type %s.\n"), fmri, scf_group_framework);
12198 free(fmri);
12201 free(pgty);
12202 return (-1);
12205 free(pgty);
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)
12211 scfdie();
12213 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
12214 scfdie();
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) {
12220 scf_type_t ty;
12222 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
12223 scfdie();
12225 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
12226 scfdie();
12228 if ((ty != SCF_TYPE_ASTRING &&
12229 prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
12230 prop_get_val(prop, val) != 0)
12231 continue;
12233 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
12234 scfdie();
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)
12240 scfdie();
12242 warn(gettext("Value of %s is not a valid FMRI.\n"),
12243 fmri);
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,
12250 fmri);
12253 if (r == -1)
12254 scfdie();
12256 scf_value_destroy(val);
12257 scf_property_destroy(prop);
12259 return (0);
12263 * Returns 1 if the instance may be running, and 0 otherwise.
12265 static int
12266 inst_is_running(scf_instance_t *inst)
12268 scf_propertygroup_t *pg;
12269 scf_property_t *prop;
12270 scf_value_t *val;
12271 char buf[MAX_SCF_STATE_STRING_SZ];
12272 int ret = 0;
12273 ssize_t szret;
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)
12278 scfdie();
12280 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
12281 if (scf_error() != SCF_ERROR_NOT_FOUND)
12282 scfdie();
12283 goto out;
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)
12289 goto out;
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;
12297 out:
12298 scf_value_destroy(val);
12299 scf_property_destroy(prop);
12300 scf_pg_destroy(pg);
12301 return (ret);
12304 static uint8_t
12305 pg_is_external_dependency(scf_propertygroup_t *pg)
12307 char *type;
12308 scf_value_t *val;
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)
12315 scfdie();
12317 if ((prop = scf_property_create(g_hndl)) == NULL ||
12318 (val = scf_value_create(g_hndl)) == NULL)
12319 scfdie();
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)
12324 scfdie();
12325 if (scf_value_get_boolean(val, &b) != 0)
12326 scfdie();
12330 free(type);
12331 (void) scf_value_destroy(val);
12332 (void) scf_property_destroy(prop);
12334 return (b);
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
12348 * snapshots.
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
12354 * removed.
12356 * Returns:
12357 * DELETE_FAILURE on failure
12358 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12359 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12361 static int
12362 lscf_instance_delete(scf_instance_t *inst, int force)
12364 scf_propertygroup_t *pg;
12365 scf_snapshot_t *snap;
12366 scf_iter_t *iter;
12367 int err;
12368 int external = 0;
12370 /* If we're not forcing and the instance is running, refuse. */
12371 if (!force && inst_is_running(inst)) {
12372 char *fmri;
12374 fmri = safe_malloc(max_scf_fmri_len + 1);
12376 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
12377 scfdie();
12379 semerr(gettext("Instance %s may be running. "
12380 "Use delete -f if it is not.\n"), fmri);
12382 free(fmri);
12383 return (DELETE_FAILURE);
12386 pg = scf_pg_create(g_hndl);
12387 if (pg == NULL)
12388 scfdie();
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)
12393 scfdie();
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)
12404 scfdie();
12406 if (scf_iter_instance_pgs(iter, inst) < 0)
12407 scfdie();
12409 while ((err = scf_iter_next_pg(iter, pg)) == 1) {
12410 if (pg_is_external_dependency(pg)) {
12411 external = 1;
12412 continue;
12415 if (scf_pg_delete(pg) != 0) {
12416 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12417 scfdie();
12418 else {
12419 semerr(emsg_permission_denied);
12421 (void) scf_iter_destroy(iter);
12422 (void) scf_pg_destroy(pg);
12423 return (DELETE_FAILURE);
12428 if (err == -1)
12429 scfdie();
12431 (void) scf_iter_destroy(iter);
12432 (void) scf_pg_destroy(pg);
12434 if (external) {
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)) ==
12442 NULL)
12443 scfdie();
12444 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
12445 scfdie();
12447 if (scf_iter_instance_snapshots(iter, inst) == -1)
12448 scfdie();
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)
12453 scfdie();
12455 semerr(emsg_permission_denied);
12457 (void) scf_iter_destroy(iter);
12458 (void) scf_snapshot_destroy(snap);
12459 return (DELETE_FAILURE);
12463 if (err == -1)
12464 scfdie();
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)
12473 scfdie();
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.
12497 * Returns:
12498 * DELETE_FAILURE on failure
12499 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12500 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12502 static int
12503 lscf_service_delete(scf_service_t *svc, int force)
12505 int r;
12506 scf_instance_t *inst;
12507 scf_propertygroup_t *pg;
12508 scf_iter_t *iter;
12509 int ret;
12510 int external = 0;
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)
12515 scfdie();
12517 if (scf_iter_service_instances(iter, svc) != 0)
12518 scfdie();
12520 for (r = scf_iter_next_instance(iter, inst);
12521 r == 1;
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)
12537 external |= 1;
12540 if (r != 0)
12541 scfdie();
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)
12547 scfdie();
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)
12559 scfdie();
12561 if (scf_iter_service_pgs(iter, svc) < 0)
12562 scfdie();
12564 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12565 if (pg_is_external_dependency(pg)) {
12566 external |= 2;
12567 continue;
12570 if (scf_pg_delete(pg) != 0) {
12571 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12572 scfdie();
12573 else {
12574 semerr(emsg_permission_denied);
12576 (void) scf_iter_destroy(iter);
12577 (void) scf_pg_destroy(pg);
12578 return (DELETE_FAILURE);
12583 if (r == -1)
12584 scfdie();
12586 (void) scf_iter_destroy(iter);
12587 (void) scf_pg_destroy(pg);
12589 if (external != 0)
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)
12596 scfdie();
12598 semerr(emsg_permission_denied);
12599 return (DELETE_FAILURE);
12602 static int
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);
12609 else
12610 (void) lscf_service_delete(wip->svc, force);
12612 return (0);
12615 void
12616 lscf_delete(const char *fmri, int force)
12618 scf_service_t *svc;
12619 scf_instance_t *inst;
12620 int ret;
12622 lscf_prep_hndl();
12624 if (cur_snap != NULL) {
12625 if (!snaplevel_is_instance(cur_level)) {
12626 char *buf;
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);
12633 free(buf);
12634 return;
12636 } else if (scf_error() != SCF_ERROR_DELETED) {
12637 scfdie();
12639 free(buf);
12641 } else if (cur_inst != NULL) {
12642 /* EMPTY */;
12643 } else if (cur_svc != NULL) {
12644 inst = scf_instance_create(g_hndl);
12645 if (inst == NULL)
12646 scfdie();
12648 if (scf_service_get_instance(cur_svc, fmri, inst) ==
12649 SCF_SUCCESS) {
12650 (void) lscf_instance_delete(inst, force);
12651 scf_instance_destroy(inst);
12652 return;
12655 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12656 scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12657 scfdie();
12659 scf_instance_destroy(inst);
12660 } else {
12661 assert(cur_scope != NULL);
12663 svc = scf_service_create(g_hndl);
12664 if (svc == NULL)
12665 scfdie();
12667 if (scf_scope_get_service(cur_scope, fmri, svc) ==
12668 SCF_SUCCESS) {
12669 (void) lscf_service_delete(svc, force);
12670 scf_service_destroy(svc);
12671 return;
12674 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12675 scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12676 scfdie();
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.
12702 static void
12703 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12705 char *buf;
12706 uint32_t flags;
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)
12711 scfdie();
12713 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12714 scfdie();
12716 safe_printf("%-*s %s", namewidth, name, buf);
12718 if (flags & SCF_PG_FLAG_NONPERSISTENT)
12719 safe_printf("\tNONPERSISTENT");
12721 safe_printf("\n");
12723 free(buf);
12726 static boolean_t
12727 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12729 if (scf_property_get_value(prop, val) == 0) {
12730 return (B_FALSE);
12731 } else {
12732 switch (scf_error()) {
12733 case SCF_ERROR_NOT_FOUND:
12734 return (B_FALSE);
12735 case SCF_ERROR_PERMISSION_DENIED:
12736 case SCF_ERROR_CONSTRAINT_VIOLATED:
12737 return (B_TRUE);
12738 default:
12739 scfdie();
12740 /*NOTREACHED*/
12745 static void
12746 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12748 scf_iter_t *iter;
12749 scf_value_t *val;
12750 const char *type;
12751 int multiple_strings = 0;
12752 int ret;
12754 if ((iter = scf_iter_create(g_hndl)) == NULL ||
12755 (val = scf_value_create(g_hndl)) == NULL)
12756 scfdie();
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)
12769 scfdie();
12771 while ((ret = scf_iter_next_value(iter, val)) == 1) {
12772 char *buf;
12773 ssize_t vlen, szret;
12775 vlen = scf_value_get_as_string(val, NULL, 0);
12776 if (vlen < 0)
12777 scfdie();
12779 buf = safe_malloc(vlen + 1);
12781 szret = scf_value_get_as_string(val, buf, vlen + 1);
12782 if (szret < 0)
12783 scfdie();
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"));
12795 } else {
12796 safe_printf(" %s", buf);
12799 free(buf);
12801 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12802 scfdie();
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.
12815 static void
12816 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12818 char *buf;
12819 uint8_t required;
12820 scf_property_t *stability_prop;
12821 scf_value_t *stability_val;
12823 if (templates == 0)
12824 return;
12826 if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12827 (stability_val = scf_value_create(g_hndl)) == NULL)
12828 scfdie();
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) {
12836 char *stability;
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)
12843 scfdie();
12845 safe_printf("%s%s: %s\n", TMPL_INDENT,
12846 gettext("stability"), stability);
12848 free(stability);
12850 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
12851 scfdie();
12854 scf_property_destroy(stability_prop);
12855 scf_value_destroy(stability_val);
12857 if (pgt == NULL)
12858 return;
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) {
12863 if (pg != NULL)
12864 safe_printf("%s", TMPL_INDENT);
12865 safe_printf("%s: ", gettext("name"));
12866 safe_printf("%s\n", buf);
12867 free(buf);
12870 /* print type info only if scf_tmpl_pg_type succeeds */
12871 if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12872 if (pg != NULL)
12873 safe_printf("%s", TMPL_INDENT);
12874 safe_printf("%s: ", gettext("type"));
12875 safe_printf("%s\n", buf);
12876 free(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"),
12886 buf);
12887 free(buf);
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"),
12892 buf);
12893 free(buf);
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);
12900 else
12901 safe_printf("%s%s\n", TMPL_INDENT, buf);
12902 free(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.
12912 static void
12913 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12914 int as_value)
12916 char *buf;
12918 if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12919 if (as_value == 0)
12920 safe_printf("%s", TMPL_CHOICE_INDENT);
12921 else
12922 safe_printf("%s", TMPL_INDENT);
12923 safe_printf("%s: %s\n", gettext("value common name"), buf);
12924 free(buf);
12927 if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12928 if (as_value == 0)
12929 safe_printf("%s", TMPL_CHOICE_INDENT);
12930 else
12931 safe_printf("%s", TMPL_INDENT);
12932 safe_printf("%s: %s\n", gettext("value description"), buf);
12933 free(buf);
12937 static void
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);
12947 static void
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;
12955 printed = 0;
12956 i = 0;
12957 if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12958 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12959 gettext("value constraints"));
12960 printed++;
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]);
12964 if (verbose == 1)
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);
12996 static void
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;
13004 printed = 0;
13005 if (scf_tmpl_value_name_choices(prt, &values) == 0) {
13006 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13007 gettext("value constraints"));
13008 printed++;
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]);
13012 if (verbose == 1)
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);
13044 static void
13045 list_values_by_template(scf_prop_tmpl_t *prt)
13047 print_template_constraints(prt, 1);
13048 print_template_choices(prt, 1);
13051 static void
13052 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
13054 char *val_buf;
13055 scf_iter_t *iter;
13056 scf_value_t *val;
13057 int ret;
13059 if ((iter = scf_iter_create(g_hndl)) == NULL ||
13060 (val = scf_value_create(g_hndl)) == NULL)
13061 scfdie();
13063 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
13064 scfdie();
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)
13071 scfdie();
13073 print_template_value(prt, val_buf);
13075 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
13076 scfdie();
13077 free(val_buf);
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
13089 static void
13090 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
13092 char *buf;
13093 uint8_t u_buf;
13094 int i;
13095 uint64_t min, max;
13096 scf_values_t values;
13098 if (prt == NULL || templates == 0)
13099 return;
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);
13105 free(buf);
13106 } else
13107 safe_printf("(%s)\n", gettext("any"));
13110 if (prop == NULL || templates == 2) {
13111 if (prop != NULL)
13112 safe_printf("%s", TMPL_INDENT);
13113 else
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);
13118 free(buf);
13119 } else
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"),
13129 buf);
13130 free(buf);
13133 if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
13134 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
13135 buf);
13136 free(buf);
13139 if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
13140 safe_printf("%s%s\n", TMPL_INDENT, buf);
13141 free(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"));
13155 } else {
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++) {
13163 if (i == 0) {
13164 safe_printf("%s%s:", TMPL_INDENT,
13165 gettext("internal separators"));
13167 safe_printf(" \"%s\"", values.values_as_strings[i]);
13169 safe_printf("\n");
13172 if (templates != 2)
13173 return;
13175 if (prop != NULL)
13176 list_values_tmpl(prt, prop);
13177 else
13178 list_values_by_template(prt);
13181 static char *
13182 read_astring(scf_propertygroup_t *pg, const char *prop_name)
13184 char *rv;
13186 rv = _scf_read_single_astring_from_pg(pg, prop_name);
13187 if (rv == NULL) {
13188 switch (scf_error()) {
13189 case SCF_ERROR_NOT_FOUND:
13190 break;
13191 default:
13192 scfdie();
13195 return (rv);
13198 static void
13199 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
13201 size_t doc_len;
13202 size_t man_len;
13203 char *pg_name;
13204 char *text = NULL;
13205 int rv;
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) {
13212 scfdie();
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);
13222 uu_free(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);
13228 uu_free(text);
13230 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
13231 man_len) == 0) {
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);
13239 uu_free(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);
13245 uu_free(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);
13251 uu_free(text);
13255 if (rv == -1)
13256 scfdie();
13258 done:
13259 free(pg_name);
13262 static void
13263 list_entity_tmpl(int templates)
13265 char *common_name = NULL;
13266 char *description = NULL;
13267 char *locale = NULL;
13268 scf_iter_t *iter;
13269 scf_propertygroup_t *pg;
13270 scf_property_t *prop;
13271 int r;
13272 scf_value_t *val;
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)
13278 scfdie();
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"),
13315 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);
13327 } else {
13328 r = scf_iter_service_pgs_typed(iter, cur_svc,
13329 SCF_GROUP_TEMPLATE);
13331 if (r == 0) {
13332 display_documentation(iter, pg);
13336 free(common_name);
13337 free(description);
13338 scf_pg_destroy(pg);
13339 scf_property_destroy(prop);
13340 scf_value_destroy(val);
13341 scf_iter_destroy(iter);
13344 static void
13345 listtmpl(const char *pattern, int templates)
13347 scf_pg_tmpl_t *pgt;
13348 scf_prop_tmpl_t *prt;
13349 char *snapbuf = NULL;
13350 char *fmribuf;
13351 char *pg_name = NULL, *prop_name = NULL;
13352 ssize_t prop_name_size;
13353 char *qual_prop_name;
13354 char *search_name;
13355 int listed = 0;
13357 if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13358 (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
13359 scfdie();
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)
13368 scfdie();
13371 if (cur_inst != NULL) {
13372 if (scf_instance_to_fmri(cur_inst, fmribuf,
13373 max_scf_name_len + 1) < 0)
13374 scfdie();
13375 } else if (cur_svc != NULL) {
13376 if (scf_service_to_fmri(cur_svc, fmribuf,
13377 max_scf_name_len + 1) < 0)
13378 scfdie();
13379 } else
13380 abort();
13382 /* If pattern is specified, we want to list only those items. */
13383 while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) {
13384 listed = 0;
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);
13388 listed++;
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;
13402 } else {
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) {
13412 free(prop_name);
13413 prop_name = NULL;
13416 if (pg_name != NULL) {
13417 free(pg_name);
13418 pg_name = NULL;
13422 scf_tmpl_prop_destroy(prt);
13423 scf_tmpl_pg_destroy(pgt);
13424 free(snapbuf);
13425 free(fmribuf);
13426 free(qual_prop_name);
13429 static void
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;
13439 void **objects;
13440 char **names;
13441 void **tmpls;
13442 int allocd, i;
13444 int ret;
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);
13450 return;
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)
13459 scfdie();
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);
13467 else
13468 ret = scf_iter_service_pgs(iter, cur_svc);
13469 if (ret != 0) {
13470 return;
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
13481 * NULL-terminated.
13483 i = 0;
13484 allocd = 1;
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) {
13490 int new_pg = 0;
13491 int print_props = 0;
13492 pgtp = NULL;
13494 pgnlen = scf_pg_get_name(pg, NULL, 0);
13495 if (pgnlen < 0)
13496 scfdie();
13498 pgnbuf = safe_malloc(pgnlen + 1);
13500 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
13501 if (szret < 0)
13502 scfdie();
13503 assert(szret <= pgnlen);
13505 if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) {
13506 if (scf_error() != SCF_ERROR_NOT_FOUND)
13507 scfdie();
13508 pgtp = NULL;
13509 } else {
13510 pgtp = pgt;
13513 if (pattern == NULL ||
13514 fnmatch(pattern, pgnbuf, 0) == 0) {
13515 if (i+1 >= allocd) {
13516 allocd *= 2;
13517 objects = reallocarray(objects, allocd,
13518 sizeof (*objects));
13519 names =
13520 reallocarray(names, allocd,
13521 sizeof (*names));
13522 tmpls = reallocarray(tmpls, allocd,
13523 sizeof (*tmpls));
13524 if (objects == NULL || names == NULL ||
13525 tmpls == NULL)
13526 uu_die(gettext("Out of memory"));
13528 objects[i] = pg;
13529 names[i] = pgnbuf;
13531 if (pgtp == NULL)
13532 tmpls[i] = NULL;
13533 else
13534 tmpls[i] = pgt;
13536 ++i;
13538 if (pgnlen > max_len)
13539 max_len = pgnlen;
13541 new_pg = 1;
13542 print_props = 1;
13545 if (only_pgs) {
13546 if (new_pg) {
13547 pg = scf_pg_create(g_hndl);
13548 if (pg == NULL)
13549 scfdie();
13550 pgt = scf_tmpl_pg_create(g_hndl);
13551 if (pgt == NULL)
13552 scfdie();
13553 } else
13554 free(pgnbuf);
13556 continue;
13559 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13560 scfdie();
13562 while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13563 prnlen = scf_property_get_name(prop, prnbuf,
13564 max_scf_name_len + 1);
13565 if (prnlen < 0)
13566 scfdie();
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,
13574 prnbuf) < 0)
13575 uu_die("snprintf");
13577 if (pattern == NULL || print_props == 1 ||
13578 fnmatch(pattern, ppnbuf, 0) == 0) {
13579 if (i+1 >= allocd) {
13580 allocd *= 2;
13581 objects = reallocarray(objects,
13582 allocd, sizeof (*objects));
13583 names = reallocarray(names, allocd,
13584 sizeof (*names));
13585 tmpls = reallocarray(tmpls, allocd,
13586 sizeof (*tmpls));
13587 if (objects == NULL || names == NULL ||
13588 tmpls == NULL)
13589 uu_die(gettext(
13590 "Out of memory"));
13593 objects[i] = prop;
13594 names[i] = ppnbuf;
13596 if (pgtp != NULL) {
13597 if (scf_tmpl_get_by_prop(pgt, prnbuf,
13598 prt, 0) < 0) {
13599 if (scf_error() !=
13600 SCF_ERROR_NOT_FOUND)
13601 scfdie();
13602 tmpls[i] = NULL;
13603 } else {
13604 tmpls[i] = prt;
13606 } else {
13607 tmpls[i] = NULL;
13610 ++i;
13612 if (prnlen > max_len)
13613 max_len = prnlen;
13615 prop = scf_property_create(g_hndl);
13616 prt = scf_tmpl_prop_create(g_hndl);
13617 } else {
13618 free(ppnbuf);
13622 if (new_pg) {
13623 pg = scf_pg_create(g_hndl);
13624 if (pg == NULL)
13625 scfdie();
13626 pgt = scf_tmpl_pg_create(g_hndl);
13627 if (pgt == NULL)
13628 scfdie();
13629 } else
13630 free(pgnbuf);
13632 if (ret != 0)
13633 scfdie();
13635 objects[i] = NULL;
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);
13649 free(names[i]);
13650 scf_pg_destroy(pg);
13651 if (pgt != NULL)
13652 scf_tmpl_pg_destroy(pgt);
13653 } else {
13654 /* property */
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);
13659 free(names[i]);
13660 scf_property_destroy(prop);
13661 if (prt != NULL)
13662 scf_tmpl_prop_destroy(prt);
13666 free(names);
13667 free(objects);
13668 free(tmpls);
13671 void
13672 lscf_listpg(const char *pattern)
13674 lscf_prep_hndl();
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.
13684 void
13685 lscf_addpg(const char *name, const char *type, const char *flags)
13687 scf_propertygroup_t *pg;
13688 int ret;
13689 uint32_t flgs = 0;
13690 const char *cp;
13693 lscf_prep_hndl();
13695 if (cur_snap != NULL) {
13696 semerr(emsg_cant_modify_snapshots);
13697 return;
13700 if (cur_inst == NULL && cur_svc == NULL) {
13701 semerr(emsg_entity_not_selected);
13702 return;
13705 if (flags != NULL) {
13706 for (cp = flags; *cp != '\0'; ++cp) {
13707 switch (*cp) {
13708 case 'P':
13709 flgs |= SCF_PG_FLAG_NONPERSISTENT;
13710 break;
13712 case 'p':
13713 flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13714 break;
13716 default:
13717 semerr(gettext("Invalid property group flag "
13718 "%c."), *cp);
13719 return;
13724 pg = scf_pg_create(g_hndl);
13725 if (pg == NULL)
13726 scfdie();
13728 if (cur_inst != NULL)
13729 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13730 else
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"));
13737 break;
13739 case SCF_ERROR_EXISTS:
13740 semerr(gettext("Property group already exists.\n"));
13741 break;
13743 case SCF_ERROR_PERMISSION_DENIED:
13744 semerr(emsg_permission_denied);
13745 break;
13747 case SCF_ERROR_BACKEND_ACCESS:
13748 semerr(gettext("Backend refused access.\n"));
13749 break;
13751 default:
13752 scfdie();
13756 scf_pg_destroy(pg);
13758 private_refresh();
13761 void
13762 lscf_delpg(char *name)
13764 lscf_prep_hndl();
13766 if (cur_snap != NULL) {
13767 semerr(emsg_cant_modify_snapshots);
13768 return;
13771 if (cur_inst == NULL && cur_svc == NULL) {
13772 semerr(emsg_entity_not_selected);
13773 return;
13776 if (strchr(name, '/') != NULL) {
13777 semerr(emsg_invalid_pg_name, name);
13778 return;
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).
13791 void
13792 lscf_delhash(char *manifest, int deathrow)
13794 char *pgname;
13796 if (cur_snap != NULL ||
13797 cur_inst != NULL || cur_svc != NULL) {
13798 warn(gettext("error, an entity is selected\n"));
13799 return;
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);
13812 return;
13814 /* delete the hash property name */
13815 lscf_delpg(pgname);
13818 void
13819 lscf_listprop(const char *pattern)
13821 lscf_prep_hndl();
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;
13839 scf_value_t *v;
13840 uu_list_walk_t *walk;
13841 string_list_t *sp;
13842 char *propname;
13843 int req_quotes = 0;
13845 lscf_prep_hndl();
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)
13856 scfdie();
13858 if (cur_snap != NULL) {
13859 semerr(emsg_cant_modify_snapshots);
13860 goto fail;
13863 if (cur_inst == NULL && cur_svc == NULL) {
13864 semerr(emsg_entity_not_selected);
13865 goto fail;
13868 propname = strchr(pgname, '/');
13869 if (propname == NULL) {
13870 semerr(gettext("Property names must contain a `/'.\n"));
13871 goto fail;
13874 *propname = '\0';
13875 ++propname;
13877 if (type != NULL) {
13878 ty = string_to_type(type);
13879 if (ty == SCF_TYPE_INVALID) {
13880 semerr(gettext("Unknown type \"%s\".\n"), type);
13881 goto fail;
13885 if (cur_inst != NULL)
13886 ret = scf_instance_get_pg(cur_inst, pgname, pg);
13887 else
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);
13893 goto fail;
13895 case SCF_ERROR_INVALID_ARGUMENT:
13896 semerr(emsg_invalid_pg_name, pgname);
13897 goto fail;
13899 default:
13900 scfdie();
13901 break;
13905 do {
13906 if (scf_pg_update(pg) == -1)
13907 scfdie();
13908 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13909 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13910 scfdie();
13912 semerr(emsg_permission_denied);
13913 goto fail;
13916 ret = scf_pg_get_property(pg, propname, prop);
13917 if (ret == SCF_SUCCESS) {
13918 if (scf_property_type(prop, &current_ty) != SCF_SUCCESS)
13919 scfdie();
13921 if (type == NULL)
13922 ty = current_ty;
13923 if (scf_transaction_property_change_type(tx, e,
13924 propname, ty) == -1)
13925 scfdie();
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,
13936 svc) == 0 &&
13937 scf_service_get_pg(cur_svc, pgname,
13938 parent_pg) == 0 &&
13939 scf_pg_get_property(parent_pg, propname,
13940 parent_prop) == 0 &&
13941 scf_property_type(parent_prop,
13942 &current_ty) == 0) {
13943 ty = current_ty;
13945 /* Then check for a type set in a template. */
13946 } else if (scf_tmpl_get_by_pg(pg, pgt,
13947 0) == 0 &&
13948 scf_tmpl_get_by_prop(pgt, propname, prt,
13949 0) == 0 &&
13950 scf_tmpl_prop_type(prt, &current_ty) == 0) {
13951 ty = current_ty;
13953 /* If type can't be inferred, fail. */
13954 } else {
13955 semerr(gettext("Type required for new "
13956 "properties.\n"));
13957 goto fail;
13960 if (scf_transaction_property_new(tx, e, propname,
13961 ty) == -1)
13962 scfdie();
13963 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13964 semerr(emsg_invalid_prop_name, propname);
13965 goto fail;
13966 } else {
13967 scfdie();
13970 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13971 req_quotes = 1;
13973 if (value != NULL) {
13974 v = string_to_value(value, ty, 0);
13976 if (v == NULL)
13977 goto fail;
13979 ret = scf_entry_add_value(e, v);
13980 assert(ret == SCF_SUCCESS);
13981 } else {
13982 assert(values != NULL);
13984 walk = uu_list_walk_start((uu_list_t *)values,
13985 UU_DEFAULT);
13986 if (walk == NULL)
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);
13993 if (v == NULL) {
13994 scf_entry_destroy_children(e);
13995 goto fail;
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);
14009 if (result < 0) {
14010 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14011 scfdie();
14013 semerr(emsg_permission_denied);
14014 goto fail;
14017 ret = 0;
14019 private_refresh();
14021 goto cleanup;
14023 fail:
14024 ret = -1;
14026 cleanup:
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);
14037 return (ret);
14040 void
14041 lscf_delprop(char *pgn)
14043 char *slash, *pn;
14044 scf_propertygroup_t *pg;
14045 scf_transaction_t *tx;
14046 scf_transaction_entry_t *e;
14047 int ret;
14050 lscf_prep_hndl();
14052 if (cur_snap != NULL) {
14053 semerr(emsg_cant_modify_snapshots);
14054 return;
14057 if (cur_inst == NULL && cur_svc == NULL) {
14058 semerr(emsg_entity_not_selected);
14059 return;
14062 pg = scf_pg_create(g_hndl);
14063 if (pg == NULL)
14064 scfdie();
14066 slash = strchr(pgn, '/');
14067 if (slash == NULL) {
14068 pn = NULL;
14069 } else {
14070 *slash = '\0';
14071 pn = slash + 1;
14074 if (cur_inst != NULL)
14075 ret = scf_instance_get_pg(cur_inst, pgn, pg);
14076 else
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);
14082 break;
14084 case SCF_ERROR_INVALID_ARGUMENT:
14085 semerr(emsg_invalid_pg_name, pgn);
14086 break;
14088 default:
14089 scfdie();
14092 scf_pg_destroy(pg);
14094 return;
14097 if (pn == NULL) {
14098 /* Try to delete the property group. */
14099 if (scf_pg_delete(pg) != SCF_SUCCESS) {
14100 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14101 scfdie();
14103 semerr(emsg_permission_denied);
14104 } else {
14105 private_refresh();
14108 scf_pg_destroy(pg);
14109 return;
14112 e = scf_entry_create(g_hndl);
14113 tx = scf_transaction_create(g_hndl);
14115 do {
14116 if (scf_pg_update(pg) == -1)
14117 scfdie();
14118 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
14119 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14120 scfdie();
14122 semerr(emsg_permission_denied);
14123 break;
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"),
14129 pgn, pn);
14130 break;
14131 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14132 semerr(emsg_invalid_prop_name, pn);
14133 break;
14134 } else {
14135 scfdie();
14139 ret = scf_transaction_commit(tx);
14141 if (ret == 0)
14142 scf_transaction_reset(tx);
14143 } while (ret == 0);
14145 if (ret < 0) {
14146 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14147 scfdie();
14149 semerr(emsg_permission_denied);
14150 } else {
14151 private_refresh();
14154 scf_transaction_destroy(tx);
14155 scf_entry_destroy(e);
14156 scf_pg_destroy(pg);
14160 * Property editing.
14163 static int
14164 write_edit_script(FILE *strm)
14166 char *fmribuf;
14167 ssize_t fmrilen;
14169 scf_propertygroup_t *pg;
14170 scf_property_t *prop;
14171 scf_value_t *val;
14172 scf_type_t ty;
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");
14182 /* select fmri */
14183 if (cur_inst != NULL) {
14184 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
14185 if (fmrilen < 0)
14186 scfdie();
14187 fmribuf = safe_malloc(fmrilen + 1);
14188 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
14189 scfdie();
14190 } else {
14191 assert(cur_svc != NULL);
14192 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
14193 if (fmrilen < 0)
14194 scfdie();
14195 fmribuf = safe_malloc(fmrilen + 1);
14196 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
14197 scfdie();
14200 if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
14201 warn(emsg_write_error, strerror(errno));
14202 free(fmribuf);
14203 return (-1);
14206 free(fmribuf);
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)
14215 scfdie();
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);
14223 else
14224 ret = scf_iter_service_pgs(iter, cur_svc);
14225 if (ret != SCF_SUCCESS)
14226 scfdie();
14228 while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
14229 int ret2;
14232 * # delprop pg
14233 * # addpg pg type
14235 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
14236 scfdie();
14238 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
14239 scfdie();
14241 if (fprintf(strm, "# Property group \"%s\"\n"
14242 "# delprop %s\n"
14243 "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
14244 warn(emsg_write_error, strerror(errno));
14245 result = -1;
14246 goto out;
14249 /* # setprop pg/prop = (values) */
14251 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
14252 scfdie();
14254 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
14255 int first = 1;
14256 int ret3;
14257 int multiple;
14258 int is_str;
14259 scf_type_t bty;
14261 if (scf_property_get_name(prop, pname,
14262 max_scf_name_len + 1) < 0)
14263 scfdie();
14265 if (scf_property_type(prop, &ty) != 0)
14266 scfdie();
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 ? "(" : "")
14272 < 0) {
14273 warn(emsg_write_error, strerror(errno));
14274 result = -1;
14275 goto out;
14278 (void) scf_type_base_type(ty, &bty);
14279 is_str = (bty == SCF_TYPE_ASTRING);
14281 if (scf_iter_property_values(viter, prop) !=
14282 SCF_SUCCESS)
14283 scfdie();
14285 while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
14286 char *buf;
14287 ssize_t buflen;
14289 buflen = scf_value_get_as_string(val, NULL, 0);
14290 if (buflen < 0)
14291 scfdie();
14293 buf = safe_malloc(buflen + 1);
14295 if (scf_value_get_as_string(val, buf,
14296 buflen + 1) < 0)
14297 scfdie();
14299 if (first)
14300 first = 0;
14301 else {
14302 if (putc(' ', strm) != ' ') {
14303 warn(emsg_write_error,
14304 strerror(errno));
14305 result = -1;
14306 goto out;
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,
14318 strerror(errno));
14319 result = -1;
14320 goto out;
14322 } else {
14323 if (fprintf(strm, "%s", buf) < 0) {
14324 warn(emsg_write_error,
14325 strerror(errno));
14326 result = -1;
14327 goto out;
14331 free(buf);
14333 if (ret3 < 0 &&
14334 scf_error() != SCF_ERROR_PERMISSION_DENIED)
14335 scfdie();
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));
14343 result = -1;
14344 goto out;
14347 if (ret2 < 0)
14348 scfdie();
14350 if (fputc('\n', strm) == EOF) {
14351 warn(emsg_write_error, strerror(errno));
14352 result = -1;
14353 goto out;
14356 if (ret < 0)
14357 scfdie();
14359 out:
14360 free(pname);
14361 free(tybuf);
14362 free(buf);
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);
14370 if (result == 0) {
14371 if (fflush(strm) != 0) {
14372 warn(emsg_write_error, strerror(errno));
14373 return (-1);
14377 return (result);
14381 lscf_editprop()
14383 char *buf, *editor;
14384 size_t bufsz;
14385 int tmpfd;
14386 char tempname[] = TEMP_FILE_PATTERN;
14388 lscf_prep_hndl();
14390 if (cur_snap != NULL) {
14391 semerr(emsg_cant_modify_snapshots);
14392 return (-1);
14395 if (cur_svc == NULL && cur_inst == NULL) {
14396 semerr(emsg_entity_not_selected);
14397 return (-1);
14400 tmpfd = mkstemp(tempname);
14401 if (tmpfd == -1) {
14402 semerr(gettext("Could not create temporary file.\n"));
14403 return (-1);
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"),
14413 strerror(errno));
14415 remove_tempfile();
14417 return (-1);
14420 if (write_edit_script(tempfile) == -1) {
14421 remove_tempfile();
14422 return (-1);
14425 editor = getenv("EDITOR");
14426 if (editor == NULL)
14427 editor = "vi";
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,
14437 strerror(errno));
14438 free(buf);
14439 remove_tempfile();
14440 return (-1);
14443 free(buf);
14445 (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
14447 remove_tempfile();
14449 return (0);
14452 static void
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()));
14464 static int
14465 remove_string(uu_list_t *strlist, const char *str)
14467 uu_list_walk_t *elems;
14468 string_list_t *sp;
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)
14476 break;
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
14483 * decide.
14485 if (sp == NULL) {
14486 return (1);
14489 uu_list_remove(strlist, sp);
14491 free(sp->str);
14492 free(sp);
14494 return (0);
14498 * Get all property values that don't match the given glob pattern,
14499 * if a pattern is specified.
14501 static void
14502 get_prop_values(scf_property_t *prop, uu_list_t *values,
14503 const char *pattern)
14505 scf_iter_t *iter;
14506 scf_value_t *val;
14507 int ret;
14509 if ((iter = scf_iter_create(g_hndl)) == NULL ||
14510 (val = scf_value_create(g_hndl)) == NULL)
14511 scfdie();
14513 if (scf_iter_property_values(iter, prop) != 0)
14514 scfdie();
14516 while ((ret = scf_iter_next_value(iter, val)) == 1) {
14517 char *buf;
14518 ssize_t vlen, szret;
14520 vlen = scf_value_get_as_string(val, NULL, 0);
14521 if (vlen < 0)
14522 scfdie();
14524 buf = safe_malloc(vlen + 1);
14526 szret = scf_value_get_as_string(val, buf, vlen + 1);
14527 if (szret < 0)
14528 scfdie();
14529 assert(szret <= vlen);
14531 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14532 add_string(values, buf);
14534 free(buf);
14537 if (ret == -1)
14538 scfdie();
14540 scf_value_destroy(val);
14541 scf_iter_destroy(iter);
14544 static int
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;
14554 scf_value_t *v;
14555 string_list_t *sp;
14556 char *propname;
14557 uu_list_t *values;
14558 uu_list_walk_t *walk;
14559 void *cookie = NULL;
14560 char *pattern = NULL;
14562 lscf_prep_hndl();
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()));
14568 if (!isadd)
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)
14575 scfdie();
14577 if (cur_snap != NULL) {
14578 semerr(emsg_cant_modify_snapshots);
14579 goto fail;
14582 if (cur_inst == NULL && cur_svc == NULL) {
14583 semerr(emsg_entity_not_selected);
14584 goto fail;
14587 propname = strchr(pgname, '/');
14588 if (propname == NULL) {
14589 semerr(gettext("Property names must contain a `/'.\n"));
14590 goto fail;
14593 *propname = '\0';
14594 ++propname;
14596 if (type != NULL) {
14597 ty = string_to_type(type);
14598 if (ty == SCF_TYPE_INVALID) {
14599 semerr(gettext("Unknown type \"%s\".\n"), type);
14600 goto fail;
14604 if (cur_inst != NULL)
14605 ret = scf_instance_get_pg(cur_inst, pgname, pg);
14606 else
14607 ret = scf_service_get_pg(cur_svc, pgname, pg);
14608 if (ret != 0) {
14609 switch (scf_error()) {
14610 case SCF_ERROR_NOT_FOUND:
14611 if (isnotfoundok) {
14612 result = 0;
14613 } else {
14614 semerr(emsg_no_such_pg, pgname);
14615 result = -1;
14617 goto out;
14619 case SCF_ERROR_INVALID_ARGUMENT:
14620 semerr(emsg_invalid_pg_name, pgname);
14621 goto fail;
14623 default:
14624 scfdie();
14628 do {
14629 if (scf_pg_update(pg) == -1)
14630 scfdie();
14631 if (scf_transaction_start(tx, pg) != 0) {
14632 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14633 scfdie();
14635 semerr(emsg_permission_denied);
14636 goto fail;
14639 ret = scf_pg_get_property(pg, propname, prop);
14640 if (ret == 0) {
14641 scf_type_t ptype;
14642 char *pat = pattern;
14644 if (scf_property_type(prop, &ptype) != 0)
14645 scfdie();
14647 if (isadd) {
14648 if (type != NULL && ptype != ty) {
14649 semerr(gettext("Property \"%s\" is not "
14650 "of type \"%s\".\n"), propname,
14651 type);
14652 goto fail;
14655 pat = NULL;
14656 } else {
14657 size_t len = strlen(pat);
14658 if (len > 0 && pat[len - 1] == '\"')
14659 pat[len - 1] = '\0';
14660 if (len > 0 && pat[0] == '\"')
14661 pat++;
14664 ty = ptype;
14666 get_prop_values(prop, values, pat);
14668 if (isadd)
14669 add_string(values, arg);
14671 if (scf_transaction_property_change(tx, e,
14672 propname, ty) == -1)
14673 scfdie();
14674 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14675 if (isadd) {
14676 if (type == NULL) {
14677 semerr(gettext("Type required "
14678 "for new properties.\n"));
14679 goto fail;
14682 add_string(values, arg);
14684 if (scf_transaction_property_new(tx, e,
14685 propname, ty) == -1)
14686 scfdie();
14687 } else if (isnotfoundok) {
14688 result = 0;
14689 goto out;
14690 } else {
14691 semerr(gettext("No such property %s/%s.\n"),
14692 pgname, propname);
14693 result = -1;
14694 goto out;
14696 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14697 semerr(emsg_invalid_prop_name, propname);
14698 goto fail;
14699 } else {
14700 scfdie();
14703 walk = uu_list_walk_start(values, UU_DEFAULT);
14704 if (walk == NULL)
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);
14711 if (v == NULL) {
14712 scf_entry_destroy_children(e);
14713 goto fail;
14715 ret = scf_entry_add_value(e, v);
14716 assert(ret == 0);
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);
14726 if (result < 0) {
14727 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14728 scfdie();
14730 semerr(emsg_permission_denied);
14731 goto fail;
14734 result = 0;
14736 private_refresh();
14738 out:
14739 scf_transaction_destroy(tx);
14740 scf_entry_destroy(e);
14741 scf_pg_destroy(pg);
14742 scf_property_destroy(prop);
14743 free(pattern);
14745 while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14746 free(sp->str);
14747 free(sp);
14750 uu_list_destroy(values);
14752 return (result);
14754 fail:
14755 result = -1;
14756 goto out;
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;
14779 char **p;
14780 int ret;
14781 scf_instance_t *inst = cur_inst;
14783 if ((pg = scf_pg_create(g_hndl)) == NULL)
14784 scfdie();
14786 again:
14787 for (p = start_method_names; *p != NULL; p++) {
14788 if (inst != NULL)
14789 ret = scf_instance_get_pg(inst, *p, pg);
14790 else
14791 ret = scf_service_get_pg(cur_svc, *p, pg);
14793 if (ret == 0) {
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) {
14798 free(buf);
14799 continue;
14801 if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14802 free(buf);
14803 continue;
14806 free(buf);
14807 *in_instance = (inst != NULL);
14808 scf_pg_destroy(pg);
14809 return (*p);
14812 if (scf_error() == SCF_ERROR_NOT_FOUND)
14813 continue;
14815 scfdie();
14818 if (inst != NULL) {
14819 inst = NULL;
14820 goto again;
14823 scf_pg_destroy(pg);
14824 return (NULL);
14827 static int
14828 addpg(const char *name, const char *type)
14830 scf_propertygroup_t *pg;
14831 int ret;
14833 pg = scf_pg_create(g_hndl);
14834 if (pg == NULL)
14835 scfdie();
14837 if (cur_inst != NULL)
14838 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14839 else
14840 ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14842 if (ret != 0) {
14843 switch (scf_error()) {
14844 case SCF_ERROR_EXISTS:
14845 ret = 0;
14846 break;
14848 case SCF_ERROR_PERMISSION_DENIED:
14849 semerr(emsg_permission_denied);
14850 break;
14852 default:
14853 scfdie();
14857 scf_pg_destroy(pg);
14858 return (ret);
14862 lscf_setenv(uu_list_t *args, int isunset)
14864 int ret = 0;
14865 size_t i;
14866 int argc;
14867 char **argv = NULL;
14868 string_list_t *slp;
14869 char *pattern;
14870 char *prop;
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;
14878 lscf_prep_hndl();
14880 argc = uu_list_numnodes(args);
14881 if (argc < 1)
14882 goto usage;
14884 argv = calloc(argc + 1, sizeof (char *));
14885 if (argv == NULL)
14886 uu_die(gettext("Out of memory.\n"));
14888 for (slp = uu_list_first(args), i = 0;
14889 slp != NULL;
14890 slp = uu_list_next(args, slp), ++i)
14891 argv[i] = slp->str;
14893 argv[i] = NULL;
14895 opterr = 0;
14896 optind = 0;
14897 for (;;) {
14898 ret = getopt(argc, argv, "sim:");
14899 if (ret == -1)
14900 break;
14902 switch (ret) {
14903 case 's':
14904 do_service = 1;
14905 cur_inst = NULL;
14906 break;
14908 case 'i':
14909 do_instance = 1;
14910 break;
14912 case 'm':
14913 method = optarg;
14914 break;
14916 case '?':
14917 goto usage;
14919 default:
14920 bad_error("getopt", ret);
14924 argc -= optind;
14925 if ((do_service && do_instance) ||
14926 (isunset && argc != 1) ||
14927 (!isunset && argc != 2))
14928 goto usage;
14930 name = argv[optind];
14931 if (!isunset)
14932 value = argv[optind + 1];
14934 if (cur_snap != NULL) {
14935 semerr(emsg_cant_modify_snapshots);
14936 ret = -1;
14937 goto out;
14940 if (cur_inst == NULL && cur_svc == NULL) {
14941 semerr(emsg_entity_not_selected);
14942 ret = -1;
14943 goto out;
14946 if (do_instance && cur_inst == NULL) {
14947 semerr(gettext("No instance is selected.\n"));
14948 ret = -1;
14949 goto out;
14952 if (do_service && cur_svc == NULL) {
14953 semerr(gettext("No service is selected.\n"));
14954 ret = -1;
14955 goto out;
14958 if (method == NULL) {
14959 if (do_instance || do_service) {
14960 method = "method_context";
14961 if (!isunset) {
14962 ret = addpg("method_context",
14963 SCF_GROUP_FRAMEWORK);
14964 if (ret != 0)
14965 goto out;
14967 } else {
14968 int in_instance;
14969 method = start_method_name(&in_instance);
14970 if (method == NULL) {
14971 semerr(gettext(
14972 "Couldn't find start method; please "
14973 "specify a method with '-m'.\n"));
14974 ret = -1;
14975 goto out;
14977 if (!in_instance)
14978 cur_inst = NULL;
14980 } else {
14981 scf_propertygroup_t *pg;
14982 size_t bufsz;
14983 char *buf;
14984 int ret;
14986 if ((pg = scf_pg_create(g_hndl)) == NULL)
14987 scfdie();
14989 if (cur_inst != NULL)
14990 ret = scf_instance_get_pg(cur_inst, method, pg);
14991 else
14992 ret = scf_service_get_pg(cur_svc, method, pg);
14994 if (ret != 0) {
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);
15000 goto out;
15002 case SCF_ERROR_INVALID_ARGUMENT:
15003 semerr(gettext("Invalid method name \"%s\".\n"),
15004 method);
15005 goto out;
15007 default:
15008 scfdie();
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);
15019 ret = -1;
15020 free(buf);
15021 scf_pg_destroy(pg);
15022 goto out;
15025 free(buf);
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) {
15038 uu_free(pattern);
15039 uu_free(prop);
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);
15046 uu_free(pattern);
15047 uu_free(prop);
15049 out:
15050 cur_inst = saved_cur_inst;
15052 free(argv);
15053 return (ret);
15054 usage:
15055 ret = -2;
15056 goto out;
15060 * Snapshot commands
15063 void
15064 lscf_listsnap()
15066 scf_snapshot_t *snap;
15067 scf_iter_t *iter;
15068 char *nb;
15069 int r;
15071 lscf_prep_hndl();
15073 if (cur_inst == NULL) {
15074 semerr(gettext("Instance not selected.\n"));
15075 return;
15078 if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15079 (iter = scf_iter_create(g_hndl)) == NULL)
15080 scfdie();
15082 if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
15083 scfdie();
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)
15089 scfdie();
15091 (void) puts(nb);
15093 if (r < 0)
15094 scfdie();
15096 free(nb);
15097 scf_iter_destroy(iter);
15098 scf_snapshot_destroy(snap);
15101 void
15102 lscf_selectsnap(const char *name)
15104 scf_snapshot_t *snap;
15105 scf_snaplevel_t *level;
15107 lscf_prep_hndl();
15109 if (cur_inst == NULL) {
15110 semerr(gettext("Instance not selected.\n"));
15111 return;
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)
15123 scfdie();
15125 nochange = strcmp(name, cur_snap_name) == 0;
15127 free(cur_snap_name);
15129 if (nochange)
15130 return;
15133 unselect_cursnap();
15136 if (name == NULL)
15137 return;
15139 if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15140 (level = scf_snaplevel_create(g_hndl)) == NULL)
15141 scfdie();
15143 if (scf_instance_get_snapshot(cur_inst, name, snap) !=
15144 SCF_SUCCESS) {
15145 switch (scf_error()) {
15146 case SCF_ERROR_INVALID_ARGUMENT:
15147 semerr(gettext("Invalid name \"%s\".\n"), name);
15148 break;
15150 case SCF_ERROR_NOT_FOUND:
15151 semerr(gettext("No such snapshot \"%s\".\n"), name);
15152 break;
15154 default:
15155 scfdie();
15158 scf_snaplevel_destroy(level);
15159 scf_snapshot_destroy(snap);
15160 return;
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)
15171 scfdie();
15173 semerr(gettext("Snapshot has no snaplevels.\n"));
15175 scf_snaplevel_destroy(level);
15176 scf_snapshot_destroy(snap);
15177 return;
15180 cur_snap = snap;
15182 for (;;) {
15183 cur_elt = safe_malloc(sizeof (*cur_elt));
15184 uu_list_node_init(cur_elt, &cur_elt->list_node,
15185 snaplevel_pool);
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);
15192 if (level == NULL)
15193 scfdie();
15195 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
15196 level) != SCF_SUCCESS) {
15197 if (scf_error() != SCF_ERROR_NOT_FOUND)
15198 scfdie();
15200 scf_snaplevel_destroy(level);
15201 break;
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
15216 * lscf_revert()).
15218 static int
15219 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
15220 uint8_t enabled)
15222 scf_transaction_t *tx;
15223 scf_iter_t *iter, *viter;
15224 scf_property_t *prop;
15225 scf_value_t *v;
15226 char *nbuf;
15227 int r;
15229 tx = scf_transaction_create(g_hndl);
15230 if (tx == NULL)
15231 scfdie();
15233 if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
15234 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15235 scfdie();
15237 scf_transaction_destroy(tx);
15239 return (-1);
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)
15245 scfdie();
15247 nbuf = safe_malloc(max_scf_name_len + 1);
15249 if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
15250 scfdie();
15252 for (;;) {
15253 scf_transaction_entry_t *e;
15254 scf_type_t ty;
15256 r = scf_iter_next_property(iter, prop);
15257 if (r == -1)
15258 scfdie();
15259 if (r == 0)
15260 break;
15262 e = scf_entry_create(g_hndl);
15263 if (e == NULL)
15264 scfdie();
15266 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
15267 scfdie();
15269 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
15270 scfdie();
15272 if (scf_transaction_property_new(tx, e, nbuf,
15273 ty) != SCF_SUCCESS)
15274 scfdie();
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);
15280 if (v == NULL)
15281 scfdie();
15283 scf_value_set_boolean(v, enabled);
15285 if (scf_entry_add_value(e, v) != 0)
15286 scfdie();
15287 } else {
15288 if (scf_iter_property_values(viter, prop) != 0)
15289 scfdie();
15291 for (;;) {
15292 v = scf_value_create(g_hndl);
15293 if (v == NULL)
15294 scfdie();
15296 r = scf_iter_next_value(viter, v);
15297 if (r == -1)
15298 scfdie();
15299 if (r == 0) {
15300 scf_value_destroy(v);
15301 break;
15304 if (scf_entry_add_value(e, v) != SCF_SUCCESS)
15305 scfdie();
15310 free(nbuf);
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)
15317 scfdie();
15319 scf_transaction_destroy_children(tx);
15320 scf_transaction_destroy(tx);
15322 switch (r) {
15323 case 1: return (0);
15324 case 0: return (-2);
15325 case -1: return (-1);
15327 default:
15328 abort();
15331 /* NOTREACHED */
15334 void
15335 lscf_revert(const char *snapname)
15337 scf_snapshot_t *snap, *prev;
15338 scf_snaplevel_t *level, *nlevel;
15339 scf_iter_t *iter;
15340 scf_propertygroup_t *pg, *npg;
15341 scf_property_t *prop;
15342 scf_value_t *val;
15343 char *nbuf, *tbuf;
15344 uint8_t enabled;
15346 lscf_prep_hndl();
15348 if (cur_inst == NULL) {
15349 semerr(gettext("Instance not selected.\n"));
15350 return;
15353 if (snapname != NULL) {
15354 snap = scf_snapshot_create(g_hndl);
15355 if (snap == NULL)
15356 scfdie();
15358 if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
15359 SCF_SUCCESS) {
15360 switch (scf_error()) {
15361 case SCF_ERROR_INVALID_ARGUMENT:
15362 semerr(gettext("Invalid snapshot name "
15363 "\"%s\".\n"), snapname);
15364 break;
15366 case SCF_ERROR_NOT_FOUND:
15367 semerr(gettext("No such snapshot.\n"));
15368 break;
15370 default:
15371 scfdie();
15374 scf_snapshot_destroy(snap);
15375 return;
15377 } else {
15378 if (cur_snap != NULL) {
15379 snap = cur_snap;
15380 } else {
15381 semerr(gettext("No snapshot selected.\n"));
15382 return;
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)
15393 scfdie();
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)
15401 scfdie();
15402 } else {
15403 if (scf_error() != SCF_ERROR_NOT_FOUND)
15404 scfdie();
15406 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
15407 scfdie();
15410 /* Save general/enabled, since we're probably going to replace it. */
15411 enabled = 2;
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)
15419 scfdie();
15421 goto out;
15424 for (;;) {
15425 boolean_t isinst;
15426 uint32_t flags;
15427 int r;
15429 /* Clear the properties from the corresponding entity. */
15430 isinst = snaplevel_is_instance(level);
15432 if (!isinst)
15433 r = scf_iter_service_pgs(iter, cur_svc);
15434 else
15435 r = scf_iter_instance_pgs(iter, cur_inst);
15436 if (r != SCF_SUCCESS)
15437 scfdie();
15439 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15440 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15441 scfdie();
15443 /* Skip nonpersistent pgs. */
15444 if (flags & SCF_PG_FLAG_NONPERSISTENT)
15445 continue;
15447 if (scf_pg_delete(pg) != SCF_SUCCESS) {
15448 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15449 scfdie();
15451 semerr(emsg_permission_denied);
15452 goto out;
15455 if (r == -1)
15456 scfdie();
15458 /* Copy the properties to the corresponding entity. */
15459 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
15460 scfdie();
15462 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15463 if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
15464 scfdie();
15466 if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
15468 scfdie();
15470 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15471 scfdie();
15473 if (!isinst)
15474 r = scf_service_add_pg(cur_svc, nbuf, tbuf,
15475 flags, npg);
15476 else
15477 r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
15478 flags, npg);
15479 if (r != SCF_SUCCESS) {
15480 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15481 scfdie();
15483 semerr(emsg_permission_denied);
15484 goto out;
15487 if ((enabled == 0 || enabled == 1) &&
15488 strcmp(nbuf, scf_pg_general) == 0)
15489 r = pg_copy(pg, npg, enabled);
15490 else
15491 r = pg_copy(pg, npg, 2);
15493 switch (r) {
15494 case 0:
15495 break;
15497 case -1:
15498 semerr(emsg_permission_denied);
15499 goto out;
15501 case -2:
15502 semerr(gettext(
15503 "Interrupted by another change.\n"));
15504 goto out;
15506 default:
15507 abort();
15510 if (r == -1)
15511 scfdie();
15513 /* Get next level. */
15514 nlevel = scf_snaplevel_create(g_hndl);
15515 if (nlevel == NULL)
15516 scfdie();
15518 if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
15519 SCF_SUCCESS) {
15520 if (scf_error() != SCF_ERROR_NOT_FOUND)
15521 scfdie();
15523 scf_snaplevel_destroy(nlevel);
15524 break;
15527 scf_snaplevel_destroy(level);
15528 level = nlevel;
15531 if (snapname == NULL) {
15532 lscf_selectsnap(NULL);
15533 snap = NULL; /* cur_snap has been destroyed */
15536 out:
15537 free(tbuf);
15538 free(nbuf);
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);
15550 void
15551 lscf_refresh(void)
15553 ssize_t fmrilen;
15554 size_t bufsz;
15555 char *fmribuf;
15556 int r;
15558 lscf_prep_hndl();
15560 if (cur_inst == NULL) {
15561 semerr(gettext("Instance not selected.\n"));
15562 return;
15565 bufsz = max_scf_fmri_len + 1;
15566 fmribuf = safe_malloc(bufsz);
15567 fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15568 if (fmrilen < 0) {
15569 free(fmribuf);
15570 if (scf_error() != SCF_ERROR_DELETED)
15571 scfdie();
15572 scf_instance_destroy(cur_inst);
15573 cur_inst = NULL;
15574 warn(emsg_deleted);
15575 return;
15577 assert(fmrilen < bufsz);
15579 r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15580 switch (r) {
15581 case 0:
15582 break;
15584 case ECONNABORTED:
15585 warn(gettext("Could not refresh %s "
15586 "(repository connection broken).\n"), fmribuf);
15587 break;
15589 case ECANCELED:
15590 warn(emsg_deleted);
15591 break;
15593 case EPERM:
15594 warn(gettext("Could not refresh %s "
15595 "(permission denied).\n"), fmribuf);
15596 break;
15598 case ENOSPC:
15599 warn(gettext("Could not refresh %s "
15600 "(repository server out of resources).\n"),
15601 fmribuf);
15602 break;
15604 case EACCES:
15605 default:
15606 bad_error("refresh_entity", scf_error());
15609 free(fmribuf);
15613 * describe [-v] [-t] [pg/prop]
15616 lscf_describe(uu_list_t *args, int hasargs)
15618 int ret = 0;
15619 size_t i;
15620 int argc;
15621 char **argv = NULL;
15622 string_list_t *slp;
15623 int do_verbose = 0;
15624 int do_templates = 0;
15625 char *pattern = NULL;
15627 lscf_prep_hndl();
15629 if (hasargs != 0) {
15630 argc = uu_list_numnodes(args);
15631 if (argc < 1)
15632 goto usage;
15634 argv = calloc(argc + 1, sizeof (char *));
15635 if (argv == NULL)
15636 uu_die(gettext("Out of memory.\n"));
15638 for (slp = uu_list_first(args), i = 0;
15639 slp != NULL;
15640 slp = uu_list_next(args, slp), ++i)
15641 argv[i] = slp->str;
15643 argv[i] = NULL;
15646 * We start optind = 0 because our list of arguments
15647 * starts at argv[0]
15649 optind = 0;
15650 opterr = 0;
15651 for (;;) {
15652 ret = getopt(argc, argv, "vt");
15653 if (ret == -1)
15654 break;
15656 switch (ret) {
15657 case 'v':
15658 do_verbose = 1;
15659 break;
15661 case 't':
15662 do_templates = 1;
15663 break;
15665 case '?':
15666 goto usage;
15668 default:
15669 bad_error("getopt", ret);
15673 pattern = argv[optind];
15676 if (cur_inst == NULL && cur_svc == NULL) {
15677 semerr(emsg_entity_not_selected);
15678 ret = -1;
15679 goto out;
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);
15690 else
15691 list_entity_tmpl(1);
15694 if (do_templates == 0) {
15695 if (do_verbose == 1)
15696 listprop(pattern, 0, 2);
15697 else
15698 listprop(pattern, 0, 1);
15699 } else {
15700 if (do_verbose == 1)
15701 listtmpl(pattern, 2);
15702 else
15703 listtmpl(pattern, 1);
15706 ret = 0;
15707 out:
15708 free(argv);
15709 return (ret);
15710 usage:
15711 ret = -2;
15712 goto out;
15715 #define PARAM_ACTIVE ((const char *) "active")
15716 #define PARAM_INACTIVE ((const char *) "inactive")
15717 #define PARAM_SMTP_TO ((const char *) "to")
15720 * tokenize()
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
15725 char **
15726 tokenize(char *str, const char *sep)
15728 char *token, *lasts;
15729 char **buf;
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) {
15738 size *= 2;
15739 if ((buf = reallocarray(buf, size, sizeof (char *))) ==
15740 NULL) {
15741 uu_die(gettext("Out of memory"));
15744 buf[n] = token;
15746 /* NULL terminate the pointer array */
15747 buf[n] = NULL;
15749 return (buf);
15752 int32_t
15753 check_tokens(char **p)
15755 int32_t smf = 0;
15756 int32_t fma = 0;
15758 while (*p) {
15759 int32_t t = string_to_tset(*p);
15761 if (t == 0) {
15762 if (is_fma_token(*p) == 0)
15763 return (INVALID_TOKENS);
15764 fma = 1; /* this token is an fma event */
15765 } else {
15766 smf |= t;
15769 if (smf != 0 && fma == 1)
15770 return (MIXED_TOKENS);
15771 ++p;
15774 if (smf > 0)
15775 return (smf);
15776 else if (fma == 1)
15777 return (FMA_TOKENS);
15779 return (INVALID_TOKENS);
15782 static int
15783 get_selection_str(char *fmri, size_t sz)
15785 if (g_hndl == NULL) {
15786 semerr(emsg_entity_not_selected);
15787 return (-1);
15788 } else if (cur_level != NULL) {
15789 semerr(emsg_invalid_for_snapshot);
15790 return (-1);
15791 } else {
15792 lscf_get_selection_str(fmri, sz);
15795 return (0);
15798 void
15799 lscf_delnotify(const char *set, int global)
15801 char *str = strdup(set);
15802 char **pgs;
15803 char **p;
15804 int32_t tset;
15805 char *fmri = NULL;
15807 if (str == NULL)
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);
15816 if (global) {
15817 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15818 } else if (get_selection_str(fmri, sz) != 0) {
15819 goto out;
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) {
15828 if (global) {
15829 semerr(gettext("Can't use option '-g' with FMA event "
15830 "definitions\n"));
15831 goto out;
15834 for (p = pgs; *p; ++p) {
15835 if (smf_notify_del_params(de_tag(*p), NULL, 0) !=
15836 SCF_SUCCESS) {
15837 uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
15838 scf_strerror(scf_error()));
15839 goto out;
15842 } else if (tset == MIXED_TOKENS) {
15843 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15844 goto out;
15845 } else {
15846 uu_die(gettext("Invalid input.\n"));
15849 out:
15850 free(fmri);
15851 free(pgs);
15852 free(str);
15855 void
15856 lscf_listnotify(const char *set, int global)
15858 char *str = safe_strdup(set);
15859 char **pgs;
15860 char **p;
15861 int32_t tset;
15862 nvlist_t *nvl;
15863 char *fmri = NULL;
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);
15874 if (global) {
15875 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15876 } else if (get_selection_str(fmri, sz) != 0) {
15877 goto out;
15880 if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
15881 SCF_SUCCESS) {
15882 if (scf_error() != SCF_ERROR_NOT_FOUND &&
15883 scf_error() != SCF_ERROR_DELETED)
15884 uu_warn(gettext(
15885 "Failed listnotify: %s\n"),
15886 scf_strerror(scf_error()));
15887 goto out;
15890 listnotify_print(nvl, NULL);
15891 } else if (tset == FMA_TOKENS) {
15892 if (global) {
15893 semerr(gettext("Can't use option '-g' with FMA event "
15894 "definitions\n"));
15895 goto out;
15898 for (p = pgs; *p; ++p) {
15899 if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
15900 SCF_SUCCESS) {
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)
15907 continue;
15908 uu_warn(gettext(
15909 "Failed listnotify: %s\n"),
15910 scf_strerror(scf_error()));
15911 goto out;
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"));
15917 goto out;
15918 } else {
15919 semerr(gettext("Invalid input.\n"));
15922 out:
15923 nvlist_free(nvl);
15924 free(fmri);
15925 free(pgs);
15926 free(str);
15929 static char *
15930 strip_quotes_and_blanks(char *s)
15932 char *start = s;
15933 char *end = strrchr(s, '\"');
15935 if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
15936 start = s + 1;
15937 while (isblank(*start))
15938 start++;
15939 while (isblank(*(end - 1)) && end > start) {
15940 end--;
15942 *end = '\0';
15945 return (start);
15948 static int
15949 set_active(nvlist_t *mech, const char *hier_part)
15951 boolean_t b;
15953 if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
15954 b = B_TRUE;
15955 } else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
15956 b = B_FALSE;
15957 } else {
15958 return (-1);
15961 if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
15962 uu_die(gettext("Out of memory.\n"));
15964 return (0);
15967 static int
15968 add_snmp_params(nvlist_t *mech, char *hier_part)
15970 return (set_active(mech, hier_part));
15973 static int
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}
15985 static int
15986 add_mailto_params(nvlist_t *mech, char *hier_part)
15988 const char *tok = "?&";
15989 char *p;
15990 char *lasts;
15991 char *param;
15992 char *val;
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)
16004 return (0);
16005 else if (set_active(mech, PARAM_ACTIVE) != 0)
16006 return (-1);
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"));
16024 return (0);
16027 static int
16028 uri_split(char *uri, char **scheme, char **hier_part)
16030 int r = -1;
16032 if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
16033 *hier_part == NULL) {
16034 semerr(gettext("'%s' is not an URI\n"), uri);
16035 return (r);
16038 if ((r = check_uri_scheme(*scheme)) < 0) {
16039 semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
16040 return (r);
16043 return (r);
16046 static int
16047 process_uri(nvlist_t *params, char *uri)
16049 char *scheme;
16050 char *hier_part;
16051 nvlist_t *mech;
16052 int index;
16053 int r;
16055 if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
16056 return (-1);
16058 if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
16059 uu_die(gettext("Out of memory.\n"));
16061 switch (index) {
16062 case 0:
16063 /* error messages displayed by called function */
16064 r = add_mailto_params(mech, hier_part);
16065 break;
16067 case 1:
16068 if ((r = add_snmp_params(mech, hier_part)) != 0)
16069 semerr(gettext("Not valid parameters: '%s'\n"),
16070 hier_part);
16071 break;
16073 case 2:
16074 if ((r = add_syslog_params(mech, hier_part)) != 0)
16075 semerr(gettext("Not valid parameters: '%s'\n"),
16076 hier_part);
16077 break;
16079 default:
16080 r = -1;
16083 if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
16084 mech) != 0)
16085 uu_die(gettext("Out of memory.\n"));
16087 nvlist_free(mech);
16088 return (r);
16091 static int
16092 set_params(nvlist_t *params, char **p)
16094 char *uri;
16096 if (p == NULL)
16097 /* sanity check */
16098 uu_die("set_params");
16100 while (*p) {
16101 uri = strip_quotes_and_blanks(*p);
16102 if (process_uri(params, uri) != 0)
16103 return (-1);
16105 ++p;
16108 return (0);
16111 static int
16112 setnotify(const char *e, char **p, int global)
16114 char *str = safe_strdup(e);
16115 char **events;
16116 int32_t tset;
16117 int r = -1;
16118 nvlist_t *nvl, *params;
16119 char *fmri = NULL;
16121 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
16122 nvlist_alloc(&params, 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);
16134 if (global) {
16135 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
16136 } else if (get_selection_str(fmri, sz) != 0) {
16137 goto out;
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,
16146 params) != 0)
16147 uu_die(gettext("Out of memory.\n"));
16149 if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
16150 nvl) != SCF_SUCCESS) {
16151 r = -1;
16152 uu_warn(gettext(
16153 "Failed smf_notify_set_params(3SCF): %s\n"),
16154 scf_strerror(scf_error()));
16157 } else if (tset == FMA_TOKENS) {
16158 /* FMA event parameters */
16159 if (global) {
16160 semerr(gettext("Can't use option '-g' with FMA event "
16161 "definitions\n"));
16162 goto out;
16165 if ((r = set_params(params, p)) != 0)
16166 goto out;
16168 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
16169 uu_die(gettext("Out of memory.\n"));
16171 while (*events) {
16172 if (smf_notify_set_params(de_tag(*events), nvl) !=
16173 SCF_SUCCESS)
16174 uu_warn(gettext(
16175 "Failed smf_notify_set_params(3SCF) for "
16176 "event %s: %s\n"), *events,
16177 scf_strerror(scf_error()));
16178 events++;
16180 } else if (tset == MIXED_TOKENS) {
16181 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
16182 } else {
16183 /* Sanity check */
16184 uu_die(gettext("Invalid input.\n"));
16187 out:
16188 nvlist_free(nvl);
16189 nvlist_free(params);
16190 free(fmri);
16191 free(str);
16193 return (r);
16197 lscf_setnotify(uu_list_t *args)
16199 int argc;
16200 char **argv = NULL;
16201 string_list_t *slp;
16202 int global;
16203 char *events;
16204 char **p;
16205 int i;
16206 int ret;
16208 if ((argc = uu_list_numnodes(args)) < 2)
16209 goto usage;
16211 argv = calloc(argc + 1, sizeof (char *));
16212 if (argv == NULL)
16213 uu_die(gettext("Out of memory.\n"));
16215 for (slp = uu_list_first(args), i = 0;
16216 slp != NULL;
16217 slp = uu_list_next(args, slp), ++i)
16218 argv[i] = slp->str;
16220 argv[i] = NULL;
16222 if (strcmp(argv[0], "-g") == 0) {
16223 global = 1;
16224 events = argv[1];
16225 p = argv + 2;
16226 } else {
16227 global = 0;
16228 events = argv[0];
16229 p = argv + 1;
16232 ret = setnotify(events, p, global);
16234 out:
16235 free(argv);
16236 return (ret);
16238 usage:
16239 ret = -2;
16240 goto out;
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.
16248 static uu_list_t *
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;
16256 int r;
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"));
16262 scfdie();
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);
16273 instances = NULL;
16274 goto out;
16276 case SCF_ERROR_HANDLE_MISMATCH:
16277 case SCF_ERROR_NOT_BOUND:
16278 case SCF_ERROR_NOT_SET:
16279 default:
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) {
16286 if (r == -1) {
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);
16292 instances = NULL;
16293 goto out;
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 "
16305 "entity\n"));
16306 scfdie();
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:
16314 continue;
16316 case SCF_ERROR_CONNECTION_BROKEN:
16317 uu_list_destroy(instances);
16318 instances = NULL;
16319 goto out;
16321 case SCF_ERROR_HANDLE_MISMATCH:
16322 case SCF_ERROR_NOT_BOUND:
16323 case SCF_ERROR_NOT_SET:
16324 default:
16325 bad_error("scf_iter_service_instances",
16326 scf_error());
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 :
16335 continue;
16337 case SCF_ERROR_CONNECTION_BROKEN:
16338 case SCF_ERROR_DELETED:
16339 uu_list_destroy(instances);
16340 instances = NULL;
16341 goto out;
16343 case SCF_ERROR_HANDLE_MISMATCH:
16344 case SCF_ERROR_NOT_BOUND:
16345 case SCF_ERROR_NOT_SET:
16346 default:
16347 bad_error("scf_iter_service_instances",
16348 scf_error());
16352 add_string(instances, instname);
16355 out:
16356 if (snap)
16357 scf_snapshot_destroy(snap);
16359 scf_instance_destroy(inst);
16360 scf_iter_destroy(inst_iter);
16361 free(instname);
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.
16373 static int
16374 disable_instance(scf_instance_t *instance)
16376 char *fmribuf;
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) {
16383 free(fmribuf);
16384 return (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) {
16393 free(fmribuf);
16394 return (0);
16397 while (enabled) {
16398 if (!inst_is_running(instance))
16399 break;
16401 (void) poll(NULL, 0, 5);
16402 enabled = enabled - 5;
16405 free(fmribuf);
16408 return (enabled);
16412 * Function to compare two service_manifest structures.
16414 /* ARGSUSED2 */
16415 static int
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;
16420 int rc;
16422 rc = strcmp(l->servicename, r->servicename);
16424 return (rc);
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
16432 * list.
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);
16447 if (mfst) {
16448 if (fnelem) {
16449 add_string(fnelem->mfstlist, strdup(mfst));
16450 } else {
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);
16464 return (fnelem);
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
16473 * the tree.
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.
16478 static void
16479 create_manifest_tree(void)
16481 manifest_info_t **entry;
16482 manifest_info_t **manifests;
16483 uu_list_walk_t *svcs;
16484 bundle_t *b;
16485 entity_t *mfsvc;
16486 char *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
16487 int c, status;
16489 if (service_manifest_pool)
16490 return;
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()));
16504 * Create the list
16506 service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
16507 UU_DEFAULT);
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);
16521 if (status < 0) {
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;
16527 return;
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);
16540 continue;
16543 svcs = uu_list_walk_start(b->sc_bundle_services,
16545 if (svcs == NULL) {
16546 internal_bundle_free(b);
16547 continue;
16550 while ((mfsvc = uu_list_walk_next(svcs)) !=
16551 NULL) {
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.
16571 * Return Values :
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
16576 static int
16577 check_mfst_history(const char *svcname)
16579 struct stat st;
16580 caddr_t mfsthist_start;
16581 char *svnbuf;
16582 int fd;
16583 int r = 1;
16585 fd = open(MFSTHISTFILE, O_RDONLY);
16586 if (fd == -1) {
16587 uu_warn(gettext("Unable to open the history file\n"));
16588 return (-1);
16591 if (fstat(fd, &st) == -1) {
16592 uu_warn(gettext("Unable to stat the history file\n"));
16593 return (-1);
16596 mfsthist_start = mmap(NULL, st.st_size, PROT_READ,
16597 MAP_PRIVATE, fd, 0);
16599 (void) close(fd);
16600 if (mfsthist_start == MAP_FAILED ||
16601 *(mfsthist_start + st.st_size) != '\0') {
16602 (void) munmap(mfsthist_start, st.st_size);
16603 return (-1);
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)
16617 r = 0;
16619 (void) munmap(mfsthist_start, st.st_size);
16620 uu_free(svnbuf);
16621 return (r);
16625 * Take down each of the instances in the service
16626 * and remove them, then delete the service.
16628 static void
16629 teardown_service(scf_service_t *svc, const char *svnbuf)
16631 scf_instance_t *instance;
16632 scf_iter_t *iter;
16633 int r;
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()));
16645 scfdie();
16648 if (scf_iter_service_instances(iter, svc) != 0) {
16649 switch (scf_error()) {
16650 case SCF_ERROR_CONNECTION_BROKEN:
16651 case SCF_ERROR_DELETED:
16652 goto out;
16654 case SCF_ERROR_HANDLE_MISMATCH:
16655 case SCF_ERROR_NOT_BOUND:
16656 case SCF_ERROR_NOT_SET:
16657 default:
16658 bad_error("scf_iter_service_instances",
16659 scf_error());
16663 while ((r = scf_iter_next_instance(iter, instance)) != 0) {
16664 if (r == -1) {
16665 uu_warn(gettext("Error - %s\n"),
16666 scf_strerror(scf_error()));
16667 goto out;
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);
16678 out:
16679 scf_instance_destroy(instance);
16680 scf_iter_destroy(iter);
16684 * Get the list of instances supported by the manifest
16685 * file.
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.
16694 static int
16695 check_instance_support(char *mfstfile, const char *svcname,
16696 uu_list_t *instances)
16698 uu_list_walk_t *svcs, *insts;
16699 uu_list_t *ilist;
16700 bundle_t *b;
16701 entity_t *mfsvc, *mfinst;
16702 const char *svcn;
16703 int rminstcnt = 0;
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);
16716 return (0);
16719 svcs = uu_list_walk_start(b->sc_bundle_services, 0);
16720 if (svcs == NULL) {
16721 internal_bundle_free(b);
16722 return (0);
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)
16730 break;
16732 uu_list_walk_end(svcs);
16734 if (mfsvc == NULL) {
16735 internal_bundle_free(b);
16736 return (-1);
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);
16742 return (0);
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
16750 * processed.
16752 (void) remove_string(instances,
16753 mfinst->sc_name);
16754 rminstcnt++;
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.
16767 static void
16768 svc_add_no_support(scf_service_t *svc)
16770 char *pname;
16772 /* Add no support */
16773 cur_svc = svc;
16774 if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
16775 return;
16777 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
16778 if (pname == NULL)
16779 uu_die(gettext("Out of memory.\n"));
16781 (void) lscf_addpropvalue(pname, "boolean:", "0");
16783 uu_free(pname);
16784 cur_svc = NULL;
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
16809 * import.
16811 * This function sets a flag for unsupported services by setting services'
16812 * SCF_PG_MANIFESTFILES/support property to false.
16814 static void
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;
16821 const char *sname;
16822 char *pname;
16823 int r;
16826 * Since there's no guarantee manifests under /var are available during
16827 * early import, don't perform any upgrade during early import.
16829 if (IGNORE_VAR)
16830 return;
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"),
16854 svcname);
16855 return;
16858 if (uu_list_numnodes(instances) == 0) {
16859 svc_add_no_support(svc);
16860 return;
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);
16873 if (r == -1)
16874 return;
16876 if (r) {
16877 /* Set unsupported flag for service */
16878 svc_add_no_support(svc);
16879 } else {
16880 /* Delete the service */
16881 teardown_service(svc, svcname);
16884 return;
16888 * Walk through the list of manifests and add them
16889 * to the service.
16891 * Create a manifestfiles pg and add the property.
16893 mfwalk = uu_list_walk_start(elem->mfstlist, 0);
16894 if (mfwalk == NULL)
16895 return;
16897 cur_svc = svc;
16898 r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
16899 if (r != 0) {
16900 cur_svc = NULL;
16901 return;
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));
16907 if (pname == NULL)
16908 uu_die(gettext("Out of memory.\n"));
16910 (void) lscf_addpropvalue(pname, "astring:", mfile->str);
16911 uu_free(pname);
16913 uu_list_walk_end(mfwalk);
16915 cur_svc = NULL;
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.
16940 * Return values :
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;
16956 scf_value_t *mv;
16957 scf_iter_t *mi;
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;
16964 char *pgpropbuf;
16965 int mfstcnt, rminstct, instct, mfstmax;
16966 int index;
16967 int r = 0;
16969 assert(g_hndl != NULL);
16970 assert(wip->svc != NULL);
16971 assert(wip->fmri != NULL);
16973 svc = wip->svc;
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()));
16986 scfdie();
16990 * Get the manifestfiles property group to be parsed for
16991 * files existence.
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);
16997 break;
16998 case SCF_ERROR_DELETED:
16999 case SCF_ERROR_CONNECTION_BROKEN:
17000 goto out;
17002 case SCF_ERROR_HANDLE_MISMATCH:
17003 case SCF_ERROR_NOT_BOUND:
17004 case SCF_ERROR_NOT_SET:
17005 default:
17006 bad_error("scf_iter_pg_properties",
17007 scf_error());
17010 goto out;
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:
17024 goto out;
17026 case SCF_ERROR_HANDLE_MISMATCH:
17027 case SCF_ERROR_NOT_BOUND:
17028 case SCF_ERROR_NOT_SET:
17029 default:
17030 bad_error("scf_iter_pg_properties",
17031 scf_error());
17035 mfstcnt = 0;
17036 mfstmax = MFSTFILE_MAX;
17037 mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
17038 while ((r = scf_iter_next_property(mi, mp)) != 0) {
17039 if (r == -1)
17040 bad_error(gettext("Unable to iterate through "
17041 "manifestfiles properties : %s"),
17042 scf_error());
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());
17060 goto out_free;
17062 case SCF_ERROR_HANDLE_MISMATCH:
17063 case SCF_ERROR_NOT_BOUND:
17064 case SCF_ERROR_NOT_SET:
17065 default:
17066 bad_error("scf_iter_pg_properties",
17067 scf_error());
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) {
17083 uint8_t support;
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());
17095 goto out_free;
17097 case SCF_ERROR_HANDLE_MISMATCH:
17098 case SCF_ERROR_NOT_BOUND:
17099 case SCF_ERROR_NOT_SET:
17100 default:
17101 bad_error("scf_iter_pg_properties",
17102 scf_error());
17106 if (support == B_FALSE)
17107 goto out_free;
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.
17131 goto out_free;
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 "
17147 "value: %s\n"),
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());
17154 goto out_free;
17156 case SCF_ERROR_HANDLE_MISMATCH:
17157 case SCF_ERROR_NOT_BOUND:
17158 case SCF_ERROR_NOT_SET:
17159 default:
17160 bad_error("scf_property_get_value",
17161 scf_error());
17165 if (scf_value_get_astring(mv, mpvbuf,
17166 max_scf_value_len + 1) < 0) {
17167 uu_warn(gettext("Unable to get the manifest "
17168 "file : %s\n"),
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());
17175 goto out_free;
17177 case SCF_ERROR_HANDLE_MISMATCH:
17178 case SCF_ERROR_NOT_BOUND:
17179 case SCF_ERROR_NOT_SET:
17180 default:
17181 bad_error("scf_value_get_astring",
17182 scf_error());
17186 mpvarry[mfstcnt] = mpntov;
17187 mfstcnt++;
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)
17200 goto out_free;
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;
17220 activity++;
17221 mfstcnt--;
17222 /* Remove the entry from the service */
17223 cur_svc = svc;
17224 pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
17225 mpnbuf);
17226 if (pgpropbuf == NULL)
17227 uu_die(gettext("Out of memory.\n"));
17229 lscf_delprop(pgpropbuf);
17230 cur_svc = NULL;
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);
17243 goto out_free;
17246 if (activity) {
17247 int nosvcsupport = 0;
17250 * If the list of service instances is NULL then
17251 * create the list.
17253 instances = create_instance_list(svc, 1);
17254 if (instances == NULL) {
17255 uu_warn(gettext("Unable to create instance list %s\n"),
17256 wip->fmri);
17257 goto out_free;
17260 rminstct = uu_list_numnodes(instances);
17261 instct = rminstct;
17263 for (index = 0; mpvarry[index]; index++) {
17264 mpntov = mpvarry[index];
17265 if (mpntov->access == 0)
17266 continue;
17268 mpnbuf = mpntov->mpg;
17269 mpvbuf = mpntov->mfile;
17270 r = check_instance_support(mpvbuf, wip->fmri,
17271 instances);
17272 if (r == -1) {
17273 nosvcsupport++;
17274 } else {
17275 rminstct -= r;
17279 if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
17280 teardown_service(svc, wip->fmri);
17282 goto out_free;
17287 * If there are instances left on the instance list, then
17288 * we must remove them.
17290 if (instances != NULL && uu_list_numnodes(instances)) {
17291 string_list_t *sp;
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()));
17305 continue;
17308 (void) disable_instance(instance);
17310 (void) lscf_instance_delete(instance, 1);
17312 scf_instance_destroy(instance);
17313 uu_list_walk_end(insts);
17316 out_free:
17317 if (mpvarry) {
17318 struct mpg_mfile *fmpntov;
17320 for (index = 0; mpvarry[index]; index++) {
17321 fmpntov = mpvarry[index];
17322 if (fmpntov->mpg == mpnbuf)
17323 mpnbuf = NULL;
17324 free(fmpntov->mpg);
17326 if (fmpntov->mfile == mpvbuf)
17327 mpvbuf = NULL;
17328 free(fmpntov->mfile);
17330 if (fmpntov == mpntov)
17331 mpntov = NULL;
17332 free(fmpntov);
17334 free(mpnbuf);
17335 free(mpvbuf);
17336 free(mpntov);
17338 free(mpvarry);
17340 out:
17341 scf_pg_destroy(mpg);
17342 scf_property_destroy(mp);
17343 scf_iter_destroy(mi);
17344 scf_value_destroy(mv);
17346 return (0);
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;
17362 scf_value_t *val;
17363 scf_iter_t *iter;
17364 char *pgname = NULL;
17365 char *mfile = NULL;
17366 int r;
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 "
17377 "property\n"));
17378 uu_warn("%s\n", pg == NULL ? "pg is NULL" :
17379 "pg is not 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()));
17392 scfdie();
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:
17399 goto out;
17401 case SCF_ERROR_HANDLE_MISMATCH:
17402 case SCF_ERROR_NOT_BOUND:
17403 case SCF_ERROR_INVALID_ARGUMENT:
17404 default:
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"),
17411 HASH_SVC);
17412 goto out;
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()));
17421 goto out;
17424 while ((r = scf_iter_next_pg(iter, pg)) != 0) {
17425 if (r == -1)
17426 goto out;
17428 if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
17429 switch (scf_error()) {
17430 case SCF_ERROR_DELETED:
17431 return (ENODEV);
17433 case SCF_ERROR_CONNECTION_BROKEN:
17434 return (ECONNABORTED);
17436 case SCF_ERROR_NOT_SET:
17437 case SCF_ERROR_NOT_BOUND:
17438 default:
17439 bad_error("scf_pg_get_name", scf_error());
17442 if (IGNORE_VAR) {
17443 if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
17444 continue;
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) {
17452 continue;
17455 if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
17456 uu_warn(gettext("Unable to get value from %s\n"),
17457 pgname);
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:
17464 continue;
17466 case SCF_ERROR_CONNECTION_BROKEN:
17467 r = scferror2errno(scf_error());
17468 goto out;
17470 case SCF_ERROR_HANDLE_MISMATCH:
17471 case SCF_ERROR_NOT_BOUND:
17472 default:
17473 bad_error("scf_property_get_value",
17474 scf_error());
17478 if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
17479 == -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:
17486 continue;
17488 default:
17489 bad_error("scf_value_get_astring", scf_error());
17493 if (access(mfile, F_OK) == 0)
17494 continue;
17496 (void) scf_pg_delete(pg);
17499 out:
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);
17506 free(pgname);
17507 free(mfile);
17509 return (0);
17512 #ifndef NATIVE_BUILD
17513 /* ARGSUSED */
17514 CPL_MATCH_FN(complete_select)
17516 const char *arg0, *arg1, *arg1end;
17517 int word_start, err = 0, r;
17518 size_t len;
17519 char *buf;
17521 lscf_prep_hndl();
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)
17532 return (0);
17534 len = line + word_end - arg1;
17536 buf = safe_malloc(max_scf_name_len + 1);
17538 if (cur_snap != NULL) {
17539 return (0);
17540 } else if (cur_inst != NULL) {
17541 return (0);
17542 } else if (cur_svc != NULL) {
17543 scf_instance_t *inst;
17544 scf_iter_t *iter;
17546 if ((inst = scf_instance_create(g_hndl)) == NULL ||
17547 (iter = scf_iter_create(g_hndl)) == NULL)
17548 scfdie();
17550 if (scf_iter_service_instances(iter, cur_svc) != 0)
17551 scfdie();
17553 for (;;) {
17554 r = scf_iter_next_instance(iter, inst);
17555 if (r == 0)
17556 break;
17557 if (r != 1)
17558 scfdie();
17560 if (scf_instance_get_name(inst, buf,
17561 max_scf_name_len + 1) < 0)
17562 scfdie();
17564 if (strncmp(buf, arg1, len) == 0) {
17565 err = cpl_add_completion(cpl, line, word_start,
17566 word_end, buf + len, "", " ");
17567 if (err != 0)
17568 break;
17572 scf_iter_destroy(iter);
17573 scf_instance_destroy(inst);
17575 return (err);
17576 } else {
17577 scf_service_t *svc;
17578 scf_iter_t *iter;
17580 assert(cur_scope != NULL);
17582 if ((svc = scf_service_create(g_hndl)) == NULL ||
17583 (iter = scf_iter_create(g_hndl)) == NULL)
17584 scfdie();
17586 if (scf_iter_scope_services(iter, cur_scope) != 0)
17587 scfdie();
17589 for (;;) {
17590 r = scf_iter_next_service(iter, svc);
17591 if (r == 0)
17592 break;
17593 if (r != 1)
17594 scfdie();
17596 if (scf_service_get_name(svc, buf,
17597 max_scf_name_len + 1) < 0)
17598 scfdie();
17600 if (strncmp(buf, arg1, len) == 0) {
17601 err = cpl_add_completion(cpl, line, word_start,
17602 word_end, buf + len, "", " ");
17603 if (err != 0)
17604 break;
17608 scf_iter_destroy(iter);
17609 scf_service_destroy(svc);
17611 return (err);
17615 /* ARGSUSED */
17616 CPL_MATCH_FN(complete_command)
17618 uint32_t scope = 0;
17620 if (cur_snap != NULL)
17621 scope = CS_SNAP;
17622 else if (cur_inst != NULL)
17623 scope = CS_INST;
17624 else if (cur_svc != NULL)
17625 scope = CS_SVC;
17626 else
17627 scope = CS_SCOPE;
17629 return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
17631 #endif /* NATIVE_BUILD */