5931 after svccfg import is killed, subsequent import fails
[unleashed.git] / usr / src / cmd / svc / svccfg / svccfg_libscf.c
blob017965783b57598c723c29accb940d1184206369
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 (c) 2012, Joyent, Inc. All rights reserved.
25 * Copyright 2012 Milan Jurik. All rights reserved.
29 #include <alloca.h>
30 #include <assert.h>
31 #include <ctype.h>
32 #include <door.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <fnmatch.h>
36 #include <inttypes.h>
37 #include <libintl.h>
38 #include <libnvpair.h>
39 #include <libscf.h>
40 #include <libscf_priv.h>
41 #include <libtecla.h>
42 #include <libuutil.h>
43 #include <limits.h>
44 #include <locale.h>
45 #include <stdarg.h>
46 #include <string.h>
47 #include <strings.h>
48 #include <time.h>
49 #include <unistd.h>
50 #include <wait.h>
51 #include <poll.h>
53 #include <libxml/tree.h>
55 #include <sys/param.h>
57 #include <sys/stat.h>
58 #include <sys/mman.h>
60 #include "svccfg.h"
61 #include "notify_params.h"
62 #include "manifest_hash.h"
63 #include "manifest_find.h"
65 /* The colon namespaces in each entity (each followed by a newline). */
66 #define COLON_NAMESPACES ":properties\n"
68 #define TEMP_FILE_PATTERN "/tmp/svccfg-XXXXXX"
70 /* These are characters which the lexer requires to be in double-quotes. */
71 #define CHARS_TO_QUOTE " \t\n\\>=\"()"
73 #define HASH_SIZE 16
74 #define HASH_PG_TYPE "framework"
75 #define HASH_PG_FLAGS 0
76 #define HASH_PROP "md5sum"
79 * Indentation used in the output of the describe subcommand.
81 #define TMPL_VALUE_INDENT " "
82 #define TMPL_INDENT " "
83 #define TMPL_INDENT_2X " "
84 #define TMPL_CHOICE_INDENT " "
87 * Directory locations for manifests
89 #define VARSVC_DIR "/var/svc/manifest"
90 #define LIBSVC_DIR "/lib/svc/manifest"
91 #define VARSVC_PR "var_svc_manifest"
92 #define LIBSVC_PR "lib_svc_manifest"
93 #define MFSTFILEPR "manifestfile"
95 #define SUPPORTPROP "support"
97 #define MFSTHISTFILE "/lib/svc/share/mfsthistory"
99 #define MFSTFILE_MAX 16
102 * These are the classes of elements which may appear as children of service
103 * or instance elements in XML manifests.
105 struct entity_elts {
106 xmlNodePtr create_default_instance;
107 xmlNodePtr single_instance;
108 xmlNodePtr restarter;
109 xmlNodePtr dependencies;
110 xmlNodePtr dependents;
111 xmlNodePtr method_context;
112 xmlNodePtr exec_methods;
113 xmlNodePtr notify_params;
114 xmlNodePtr property_groups;
115 xmlNodePtr instances;
116 xmlNodePtr stability;
117 xmlNodePtr template;
121 * Likewise for property_group elements.
123 struct pg_elts {
124 xmlNodePtr stability;
125 xmlNodePtr propvals;
126 xmlNodePtr properties;
130 * Likewise for template elements.
132 struct template_elts {
133 xmlNodePtr common_name;
134 xmlNodePtr description;
135 xmlNodePtr documentation;
139 * Likewise for type (for notification parameters) elements.
141 struct params_elts {
142 xmlNodePtr paramval;
143 xmlNodePtr parameter;
147 * This structure is for snaplevel lists. They are convenient because libscf
148 * only allows traversing snaplevels in one direction.
150 struct snaplevel {
151 uu_list_node_t list_node;
152 scf_snaplevel_t *sl;
156 * This is used for communication between lscf_service_export and
157 * export_callback.
159 struct export_args {
160 const char *filename;
161 int flags;
165 * The service_manifest structure is used by the upgrade process
166 * to create a list of service to manifest linkages from the manifests
167 * in a set of given directories.
169 typedef struct service_manifest {
170 const char *servicename;
171 uu_list_t *mfstlist;
172 size_t mfstlist_sz;
174 uu_avl_node_t svcmfst_node;
175 } service_manifest_t;
178 * Structure to track the manifest file property group
179 * and the manifest file associated with that property
180 * group. Also, a flag to keep the access once it has
181 * been checked.
183 struct mpg_mfile {
184 char *mpg;
185 char *mfile;
186 int access;
189 const char * const scf_pg_general = SCF_PG_GENERAL;
190 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
191 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
192 const char * const scf_property_external = "external";
194 const char * const snap_initial = "initial";
195 const char * const snap_lastimport = "last-import";
196 const char * const snap_previous = "previous";
197 const char * const snap_running = "running";
199 scf_handle_t *g_hndl = NULL; /* only valid after lscf_prep_hndl() */
201 ssize_t max_scf_fmri_len;
202 ssize_t max_scf_name_len;
203 ssize_t max_scf_pg_type_len;
204 ssize_t max_scf_value_len;
205 static size_t max_scf_len;
207 static scf_scope_t *cur_scope;
208 static scf_service_t *cur_svc = NULL;
209 static scf_instance_t *cur_inst = NULL;
210 static scf_snapshot_t *cur_snap = NULL;
211 static scf_snaplevel_t *cur_level = NULL;
213 static uu_list_pool_t *snaplevel_pool;
214 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
215 static uu_list_t *cur_levels;
216 static struct snaplevel *cur_elt; /* cur_elt->sl == cur_level */
218 static FILE *tempfile = NULL;
219 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
221 static const char *emsg_entity_not_selected;
222 static const char *emsg_permission_denied;
223 static const char *emsg_create_xml;
224 static const char *emsg_cant_modify_snapshots;
225 static const char *emsg_invalid_for_snapshot;
226 static const char *emsg_read_only;
227 static const char *emsg_deleted;
228 static const char *emsg_invalid_pg_name;
229 static const char *emsg_invalid_prop_name;
230 static const char *emsg_no_such_pg;
231 static const char *emsg_fmri_invalid_pg_name;
232 static const char *emsg_fmri_invalid_pg_name_type;
233 static const char *emsg_pg_added;
234 static const char *emsg_pg_changed;
235 static const char *emsg_pg_deleted;
236 static const char *emsg_pg_mod_perm;
237 static const char *emsg_pg_add_perm;
238 static const char *emsg_pg_del_perm;
239 static const char *emsg_snap_perm;
240 static const char *emsg_dpt_dangling;
241 static const char *emsg_dpt_no_dep;
243 static int li_only = 0;
244 static int no_refresh = 0;
246 /* how long in ns we should wait between checks for a pg */
247 static uint64_t pg_timeout = 100 * (NANOSEC / MILLISEC);
249 /* import globals, to minimize allocations */
250 static scf_scope_t *imp_scope = NULL;
251 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
252 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
253 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
254 static scf_snapshot_t *imp_rsnap = NULL;
255 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
256 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
257 static scf_property_t *imp_prop = NULL;
258 static scf_iter_t *imp_iter = NULL;
259 static scf_iter_t *imp_rpg_iter = NULL;
260 static scf_iter_t *imp_up_iter = NULL;
261 static scf_transaction_t *imp_tx = NULL; /* always reset this */
262 static char *imp_str = NULL;
263 static size_t imp_str_sz;
264 static char *imp_tsname = NULL;
265 static char *imp_fe1 = NULL; /* for fmri_equal() */
266 static char *imp_fe2 = NULL;
267 static uu_list_t *imp_deleted_dpts = NULL; /* pgroup_t's to refresh */
269 /* upgrade_dependents() globals */
270 static scf_instance_t *ud_inst = NULL;
271 static scf_snaplevel_t *ud_snpl = NULL;
272 static scf_propertygroup_t *ud_pg = NULL;
273 static scf_propertygroup_t *ud_cur_depts_pg = NULL;
274 static scf_propertygroup_t *ud_run_dpts_pg = NULL;
275 static int ud_run_dpts_pg_set = 0;
276 static scf_property_t *ud_prop = NULL;
277 static scf_property_t *ud_dpt_prop = NULL;
278 static scf_value_t *ud_val = NULL;
279 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
280 static scf_transaction_t *ud_tx = NULL;
281 static char *ud_ctarg = NULL;
282 static char *ud_oldtarg = NULL;
283 static char *ud_name = NULL;
285 /* export globals */
286 static scf_instance_t *exp_inst;
287 static scf_propertygroup_t *exp_pg;
288 static scf_property_t *exp_prop;
289 static scf_value_t *exp_val;
290 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
291 static char *exp_str;
292 static size_t exp_str_sz;
294 /* cleanup globals */
295 static uu_avl_pool_t *service_manifest_pool = NULL;
296 static uu_avl_t *service_manifest_tree = NULL;
298 static void scfdie_lineno(int lineno) __NORETURN;
300 static char *start_method_names[] = {
301 "start",
302 "inetd_start",
303 NULL
306 static struct uri_scheme {
307 const char *scheme;
308 const char *protocol;
309 } uri_scheme[] = {
310 { "mailto", "smtp" },
311 { "snmp", "snmp" },
312 { "syslog", "syslog" },
313 { NULL, NULL }
315 #define URI_SCHEME_NUM ((sizeof (uri_scheme) / \
316 sizeof (struct uri_scheme)) - 1)
318 static int
319 check_uri_scheme(const char *scheme)
321 int i;
323 for (i = 0; uri_scheme[i].scheme != NULL; ++i) {
324 if (strcmp(scheme, uri_scheme[i].scheme) == 0)
325 return (i);
328 return (-1);
331 static int
332 check_uri_protocol(const char *p)
334 int i;
336 for (i = 0; uri_scheme[i].protocol != NULL; ++i) {
337 if (strcmp(p, uri_scheme[i].protocol) == 0)
338 return (i);
341 return (-1);
345 * For unexpected libscf errors.
347 #ifdef NDEBUG
349 static void scfdie(void) __NORETURN;
351 static void
352 scfdie(void)
354 scf_error_t err = scf_error();
356 if (err == SCF_ERROR_CONNECTION_BROKEN)
357 uu_die(gettext("Repository connection broken. Exiting.\n"));
359 uu_die(gettext("Unexpected fatal libscf error: %s. Exiting.\n"),
360 scf_strerror(err));
363 #else
365 #define scfdie() scfdie_lineno(__LINE__)
367 static void
368 scfdie_lineno(int lineno)
370 scf_error_t err = scf_error();
372 if (err == SCF_ERROR_CONNECTION_BROKEN)
373 uu_die(gettext("Repository connection broken. Exiting.\n"));
375 uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
376 ": %s.\n"), lineno, scf_strerror(err));
379 #endif
381 static void
382 scfwarn(void)
384 warn(gettext("Unexpected libscf error: %s.\n"),
385 scf_strerror(scf_error()));
389 * Clear a field of a structure.
391 static int
392 clear_int(void *a, void *b)
394 /* LINTED */
395 *(int *)((char *)a + (size_t)b) = 0;
397 return (UU_WALK_NEXT);
400 static int
401 scferror2errno(scf_error_t err)
403 switch (err) {
404 case SCF_ERROR_BACKEND_ACCESS:
405 return (EACCES);
407 case SCF_ERROR_BACKEND_READONLY:
408 return (EROFS);
410 case SCF_ERROR_CONNECTION_BROKEN:
411 return (ECONNABORTED);
413 case SCF_ERROR_CONSTRAINT_VIOLATED:
414 case SCF_ERROR_INVALID_ARGUMENT:
415 return (EINVAL);
417 case SCF_ERROR_DELETED:
418 return (ECANCELED);
420 case SCF_ERROR_EXISTS:
421 return (EEXIST);
423 case SCF_ERROR_NO_MEMORY:
424 return (ENOMEM);
426 case SCF_ERROR_NO_RESOURCES:
427 return (ENOSPC);
429 case SCF_ERROR_NOT_FOUND:
430 return (ENOENT);
432 case SCF_ERROR_PERMISSION_DENIED:
433 return (EPERM);
435 default:
436 #ifndef NDEBUG
437 (void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
438 __FILE__, __LINE__, err);
439 #else
440 (void) fprintf(stderr, "Unknown libscf error %d.\n", err);
441 #endif
442 abort();
443 /* NOTREACHED */
447 static int
448 entity_get_pg(void *ent, int issvc, const char *name,
449 scf_propertygroup_t *pg)
451 if (issvc)
452 return (scf_service_get_pg(ent, name, pg));
453 else
454 return (scf_instance_get_pg(ent, name, pg));
457 static void
458 entity_destroy(void *ent, int issvc)
460 if (issvc)
461 scf_service_destroy(ent);
462 else
463 scf_instance_destroy(ent);
466 static int
467 get_pg(const char *pg_name, scf_propertygroup_t *pg)
469 int ret;
471 if (cur_level != NULL)
472 ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
473 else if (cur_inst != NULL)
474 ret = scf_instance_get_pg(cur_inst, pg_name, pg);
475 else
476 ret = scf_service_get_pg(cur_svc, pg_name, pg);
478 return (ret);
482 * Find a snaplevel in a snapshot. If get_svc is true, find the service
483 * snaplevel. Otherwise find the instance snaplevel.
485 * Returns
486 * 0 - success
487 * ECONNABORTED - repository connection broken
488 * ECANCELED - instance containing snap was deleted
489 * ENOENT - snap has no snaplevels
490 * - requested snaplevel not found
492 static int
493 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
495 if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
496 switch (scf_error()) {
497 case SCF_ERROR_CONNECTION_BROKEN:
498 case SCF_ERROR_DELETED:
499 case SCF_ERROR_NOT_FOUND:
500 return (scferror2errno(scf_error()));
502 case SCF_ERROR_HANDLE_MISMATCH:
503 case SCF_ERROR_NOT_BOUND:
504 case SCF_ERROR_NOT_SET:
505 default:
506 bad_error("scf_snapshot_get_base_snaplevel",
507 scf_error());
511 for (;;) {
512 ssize_t ssz;
514 ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
515 if (ssz >= 0) {
516 if (!get_svc)
517 return (0);
518 } else {
519 switch (scf_error()) {
520 case SCF_ERROR_CONSTRAINT_VIOLATED:
521 if (get_svc)
522 return (0);
523 break;
525 case SCF_ERROR_DELETED:
526 case SCF_ERROR_CONNECTION_BROKEN:
527 return (scferror2errno(scf_error()));
529 case SCF_ERROR_NOT_SET:
530 case SCF_ERROR_NOT_BOUND:
531 default:
532 bad_error("scf_snaplevel_get_instance_name",
533 scf_error());
537 if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
538 switch (scf_error()) {
539 case SCF_ERROR_NOT_FOUND:
540 case SCF_ERROR_CONNECTION_BROKEN:
541 case SCF_ERROR_DELETED:
542 return (scferror2errno(scf_error()));
544 case SCF_ERROR_HANDLE_MISMATCH:
545 case SCF_ERROR_NOT_BOUND:
546 case SCF_ERROR_NOT_SET:
547 case SCF_ERROR_INVALID_ARGUMENT:
548 default:
549 bad_error("scf_snaplevel_get_next_snaplevel",
550 scf_error());
557 * If issvc is 0, take ent to be a pointer to an scf_instance_t. If it has
558 * a running snapshot, and that snapshot has an instance snaplevel, set pg to
559 * the property group named name in it. If it doesn't have a running
560 * snapshot, set pg to the instance's current property group named name.
562 * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
563 * its instances. If one has a running snapshot with a service snaplevel, set
564 * pg to the property group named name in it. If no such snaplevel could be
565 * found, set pg to the service's current property group named name.
567 * iter, inst, snap, and snpl are required scratch objects.
569 * Returns
570 * 0 - success
571 * ECONNABORTED - repository connection broken
572 * ECANCELED - ent was deleted
573 * ENOENT - no such property group
574 * EINVAL - name is an invalid property group name
575 * EBADF - found running snapshot is missing a snaplevel
577 static int
578 entity_get_running_pg(void *ent, int issvc, const char *name,
579 scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
580 scf_snapshot_t *snap, scf_snaplevel_t *snpl)
582 int r;
584 if (issvc) {
585 /* Search for an instance with a running snapshot. */
586 if (scf_iter_service_instances(iter, ent) != 0) {
587 switch (scf_error()) {
588 case SCF_ERROR_DELETED:
589 case SCF_ERROR_CONNECTION_BROKEN:
590 return (scferror2errno(scf_error()));
592 case SCF_ERROR_NOT_SET:
593 case SCF_ERROR_NOT_BOUND:
594 case SCF_ERROR_HANDLE_MISMATCH:
595 default:
596 bad_error("scf_iter_service_instances",
597 scf_error());
601 for (;;) {
602 r = scf_iter_next_instance(iter, inst);
603 if (r == 0) {
604 if (scf_service_get_pg(ent, name, pg) == 0)
605 return (0);
607 switch (scf_error()) {
608 case SCF_ERROR_DELETED:
609 case SCF_ERROR_NOT_FOUND:
610 case SCF_ERROR_INVALID_ARGUMENT:
611 case SCF_ERROR_CONNECTION_BROKEN:
612 return (scferror2errno(scf_error()));
614 case SCF_ERROR_NOT_BOUND:
615 case SCF_ERROR_HANDLE_MISMATCH:
616 case SCF_ERROR_NOT_SET:
617 default:
618 bad_error("scf_service_get_pg",
619 scf_error());
622 if (r != 1) {
623 switch (scf_error()) {
624 case SCF_ERROR_DELETED:
625 case SCF_ERROR_CONNECTION_BROKEN:
626 return (scferror2errno(scf_error()));
628 case SCF_ERROR_INVALID_ARGUMENT:
629 case SCF_ERROR_NOT_SET:
630 case SCF_ERROR_NOT_BOUND:
631 case SCF_ERROR_HANDLE_MISMATCH:
632 default:
633 bad_error("scf_iter_next_instance",
634 scf_error());
638 if (scf_instance_get_snapshot(inst, snap_running,
639 snap) == 0)
640 break;
642 switch (scf_error()) {
643 case SCF_ERROR_NOT_FOUND:
644 case SCF_ERROR_DELETED:
645 continue;
647 case SCF_ERROR_CONNECTION_BROKEN:
648 return (ECONNABORTED);
650 case SCF_ERROR_HANDLE_MISMATCH:
651 case SCF_ERROR_INVALID_ARGUMENT:
652 case SCF_ERROR_NOT_SET:
653 case SCF_ERROR_NOT_BOUND:
654 default:
655 bad_error("scf_instance_get_snapshot",
656 scf_error());
659 } else {
660 if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
661 switch (scf_error()) {
662 case SCF_ERROR_NOT_FOUND:
663 break;
665 case SCF_ERROR_DELETED:
666 case SCF_ERROR_CONNECTION_BROKEN:
667 return (scferror2errno(scf_error()));
669 case SCF_ERROR_NOT_BOUND:
670 case SCF_ERROR_HANDLE_MISMATCH:
671 case SCF_ERROR_INVALID_ARGUMENT:
672 case SCF_ERROR_NOT_SET:
673 default:
674 bad_error("scf_instance_get_snapshot",
675 scf_error());
678 if (scf_instance_get_pg(ent, name, pg) == 0)
679 return (0);
681 switch (scf_error()) {
682 case SCF_ERROR_DELETED:
683 case SCF_ERROR_NOT_FOUND:
684 case SCF_ERROR_INVALID_ARGUMENT:
685 case SCF_ERROR_CONNECTION_BROKEN:
686 return (scferror2errno(scf_error()));
688 case SCF_ERROR_NOT_BOUND:
689 case SCF_ERROR_HANDLE_MISMATCH:
690 case SCF_ERROR_NOT_SET:
691 default:
692 bad_error("scf_instance_get_pg", scf_error());
697 r = get_snaplevel(snap, issvc, snpl);
698 switch (r) {
699 case 0:
700 break;
702 case ECONNABORTED:
703 case ECANCELED:
704 return (r);
706 case ENOENT:
707 return (EBADF);
709 default:
710 bad_error("get_snaplevel", r);
713 if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
714 return (0);
716 switch (scf_error()) {
717 case SCF_ERROR_DELETED:
718 case SCF_ERROR_INVALID_ARGUMENT:
719 case SCF_ERROR_CONNECTION_BROKEN:
720 case SCF_ERROR_NOT_FOUND:
721 return (scferror2errno(scf_error()));
723 case SCF_ERROR_NOT_BOUND:
724 case SCF_ERROR_HANDLE_MISMATCH:
725 case SCF_ERROR_NOT_SET:
726 default:
727 bad_error("scf_snaplevel_get_pg", scf_error());
728 /* NOTREACHED */
733 * To be registered with atexit().
735 static void
736 remove_tempfile(void)
738 int ret;
740 if (tempfile != NULL) {
741 if (fclose(tempfile) == EOF)
742 (void) warn(gettext("Could not close temporary file"));
743 tempfile = NULL;
746 if (tempfilename[0] != '\0') {
747 do {
748 ret = remove(tempfilename);
749 } while (ret == -1 && errno == EINTR);
750 if (ret == -1)
751 warn(gettext("Could not remove temporary file"));
752 tempfilename[0] = '\0';
757 * Launch private svc.configd(1M) for manipulating alternate repositories.
759 static void
760 start_private_repository(engine_state_t *est)
762 int fd, stat;
763 struct door_info info;
764 pid_t pid;
767 * 1. Create a temporary file for the door.
769 if (est->sc_repo_doorname != NULL)
770 free((void *)est->sc_repo_doorname);
772 est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
773 if (est->sc_repo_doorname == NULL)
774 uu_die(gettext("Could not acquire temporary filename"));
776 fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
777 if (fd < 0)
778 uu_die(gettext("Could not create temporary file for "
779 "repository server"));
781 (void) close(fd);
784 * 2. Launch a configd with that door, using the specified
785 * repository.
787 if ((est->sc_repo_pid = fork()) == 0) {
788 (void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
789 "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
790 NULL);
791 uu_die(gettext("Could not execute %s"), est->sc_repo_server);
792 } else if (est->sc_repo_pid == -1)
793 uu_die(gettext("Attempt to fork failed"));
795 do {
796 pid = waitpid(est->sc_repo_pid, &stat, 0);
797 } while (pid == -1 && errno == EINTR);
799 if (pid == -1)
800 uu_die(gettext("Could not waitpid() for repository server"));
802 if (!WIFEXITED(stat)) {
803 uu_die(gettext("Repository server failed (status %d).\n"),
804 stat);
805 } else if (WEXITSTATUS(stat) != 0) {
806 uu_die(gettext("Repository server failed (exit %d).\n"),
807 WEXITSTATUS(stat));
811 * See if it was successful by checking if the door is a door.
814 fd = open(est->sc_repo_doorname, O_RDWR);
815 if (fd < 0)
816 uu_die(gettext("Could not open door \"%s\""),
817 est->sc_repo_doorname);
819 if (door_info(fd, &info) < 0)
820 uu_die(gettext("Unexpected door_info() error"));
822 if (close(fd) == -1)
823 warn(gettext("Could not close repository door"),
824 strerror(errno));
826 est->sc_repo_pid = info.di_target;
829 void
830 lscf_cleanup(void)
833 * In the case where we've launched a private svc.configd(1M)
834 * instance, we must terminate our child and remove the temporary
835 * rendezvous point.
837 if (est->sc_repo_pid > 0) {
838 (void) kill(est->sc_repo_pid, SIGTERM);
839 (void) waitpid(est->sc_repo_pid, NULL, 0);
840 (void) unlink(est->sc_repo_doorname);
842 est->sc_repo_pid = 0;
846 void
847 unselect_cursnap(void)
849 void *cookie;
851 cur_level = NULL;
853 cookie = NULL;
854 while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
855 scf_snaplevel_destroy(cur_elt->sl);
856 free(cur_elt);
859 scf_snapshot_destroy(cur_snap);
860 cur_snap = NULL;
863 void
864 lscf_prep_hndl(void)
866 if (g_hndl != NULL)
867 return;
869 g_hndl = scf_handle_create(SCF_VERSION);
870 if (g_hndl == NULL)
871 scfdie();
873 if (est->sc_repo_filename != NULL)
874 start_private_repository(est);
876 if (est->sc_repo_doorname != NULL) {
877 scf_value_t *repo_value;
878 int ret;
880 repo_value = scf_value_create(g_hndl);
881 if (repo_value == NULL)
882 scfdie();
884 ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
885 assert(ret == SCF_SUCCESS);
887 if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
888 SCF_SUCCESS)
889 scfdie();
891 scf_value_destroy(repo_value);
894 if (scf_handle_bind(g_hndl) != 0)
895 uu_die(gettext("Could not connect to repository server: %s.\n"),
896 scf_strerror(scf_error()));
898 cur_scope = scf_scope_create(g_hndl);
899 if (cur_scope == NULL)
900 scfdie();
902 if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
903 scfdie();
906 static void
907 repository_teardown(void)
909 if (g_hndl != NULL) {
910 if (cur_snap != NULL)
911 unselect_cursnap();
912 scf_instance_destroy(cur_inst);
913 scf_service_destroy(cur_svc);
914 scf_scope_destroy(cur_scope);
915 scf_handle_destroy(g_hndl);
916 cur_inst = NULL;
917 cur_svc = NULL;
918 cur_scope = NULL;
919 g_hndl = NULL;
920 lscf_cleanup();
924 void
925 lscf_set_repository(const char *repfile, int force)
927 repository_teardown();
929 if (est->sc_repo_filename != NULL) {
930 free((void *)est->sc_repo_filename);
931 est->sc_repo_filename = NULL;
934 if ((force == 0) && (access(repfile, R_OK) != 0)) {
936 * Repository file does not exist
937 * or has no read permission.
939 warn(gettext("Cannot access \"%s\": %s\n"),
940 repfile, strerror(errno));
941 } else {
942 est->sc_repo_filename = safe_strdup(repfile);
945 lscf_prep_hndl();
948 void
949 lscf_init()
951 if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
952 (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
953 (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
954 0 ||
955 (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
956 scfdie();
958 max_scf_len = max_scf_fmri_len;
959 if (max_scf_name_len > max_scf_len)
960 max_scf_len = max_scf_name_len;
961 if (max_scf_pg_type_len > max_scf_len)
962 max_scf_len = max_scf_pg_type_len;
964 * When a value of type opaque is represented as a string, the
965 * string contains 2 characters for every byte of data. That is
966 * because the string contains the hex representation of the opaque
967 * value.
969 if (2 * max_scf_value_len > max_scf_len)
970 max_scf_len = 2 * max_scf_value_len;
972 if (atexit(remove_tempfile) != 0)
973 uu_die(gettext("Could not register atexit() function"));
975 emsg_entity_not_selected = gettext("An entity is not selected.\n");
976 emsg_permission_denied = gettext("Permission denied.\n");
977 emsg_create_xml = gettext("Could not create XML node.\n");
978 emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
979 emsg_invalid_for_snapshot =
980 gettext("Invalid operation on a snapshot.\n");
981 emsg_read_only = gettext("Backend read-only.\n");
982 emsg_deleted = gettext("Current selection has been deleted.\n");
983 emsg_invalid_pg_name =
984 gettext("Invalid property group name \"%s\".\n");
985 emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
986 emsg_no_such_pg = gettext("No such property group \"%s\".\n");
987 emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
988 "with invalid name \"%s\".\n");
989 emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
990 "group with invalid name \"%s\" or type \"%s\".\n");
991 emsg_pg_added = gettext("%s changed unexpectedly "
992 "(property group \"%s\" added).\n");
993 emsg_pg_changed = gettext("%s changed unexpectedly "
994 "(property group \"%s\" changed).\n");
995 emsg_pg_deleted = gettext("%s changed unexpectedly "
996 "(property group \"%s\" or an ancestor was deleted).\n");
997 emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
998 "in %s (permission denied).\n");
999 emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
1000 "in %s (permission denied).\n");
1001 emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
1002 "in %s (permission denied).\n");
1003 emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
1004 "(permission denied).\n");
1005 emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
1006 "new dependent \"%s\" because it already exists). Warning: The "
1007 "current dependent's target (%s) does not exist.\n");
1008 emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
1009 "dependent \"%s\" because it already exists). Warning: The "
1010 "current dependent's target (%s) does not have a dependency named "
1011 "\"%s\" as expected.\n");
1013 string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
1014 offsetof(string_list_t, node), NULL, 0);
1015 snaplevel_pool = uu_list_pool_create("snaplevels",
1016 sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
1017 NULL, 0);
1021 static const char *
1022 prop_to_typestr(const scf_property_t *prop)
1024 scf_type_t ty;
1026 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
1027 scfdie();
1029 return (scf_type_to_string(ty));
1032 static scf_type_t
1033 string_to_type(const char *type)
1035 size_t len = strlen(type);
1036 char *buf;
1038 if (len == 0 || type[len - 1] != ':')
1039 return (SCF_TYPE_INVALID);
1041 buf = (char *)alloca(len + 1);
1042 (void) strlcpy(buf, type, len + 1);
1043 buf[len - 1] = 0;
1045 return (scf_string_to_type(buf));
1048 static scf_value_t *
1049 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
1051 scf_value_t *v;
1052 char *dup, *nstr;
1053 size_t len;
1055 v = scf_value_create(g_hndl);
1056 if (v == NULL)
1057 scfdie();
1059 len = strlen(str);
1060 if (require_quotes &&
1061 (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
1062 semerr(gettext("Multiple string values or string values "
1063 "with spaces must be quoted with '\"'.\n"));
1064 scf_value_destroy(v);
1065 return (NULL);
1068 nstr = dup = safe_strdup(str);
1069 if (dup[0] == '\"') {
1071 * Strip out the first and the last quote.
1073 dup[len - 1] = '\0';
1074 nstr = dup + 1;
1077 if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
1078 assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1079 semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1080 scf_type_to_string(ty), nstr);
1081 scf_value_destroy(v);
1082 v = NULL;
1084 free(dup);
1085 return (v);
1089 * Print str to strm, quoting double-quotes and backslashes with backslashes.
1090 * Optionally append a comment prefix ('#') to newlines ('\n').
1092 static int
1093 quote_and_print(const char *str, FILE *strm, int commentnl)
1095 const char *cp;
1097 for (cp = str; *cp != '\0'; ++cp) {
1098 if (*cp == '"' || *cp == '\\')
1099 (void) putc('\\', strm);
1101 (void) putc(*cp, strm);
1103 if (commentnl && *cp == '\n') {
1104 (void) putc('#', strm);
1108 return (ferror(strm));
1112 * These wrappers around lowlevel functions provide consistent error checking
1113 * and warnings.
1115 static int
1116 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1118 if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1119 return (0);
1121 if (scf_error() != SCF_ERROR_NOT_FOUND)
1122 scfdie();
1124 if (g_verbose) {
1125 ssize_t len;
1126 char *fmri;
1128 len = scf_pg_to_fmri(pg, NULL, 0);
1129 if (len < 0)
1130 scfdie();
1132 fmri = safe_malloc(len + 1);
1134 if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1135 scfdie();
1137 warn(gettext("Expected property %s of property group %s is "
1138 "missing.\n"), propname, fmri);
1140 free(fmri);
1143 return (-1);
1146 static int
1147 prop_check_type(scf_property_t *prop, scf_type_t ty)
1149 scf_type_t pty;
1151 if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1152 scfdie();
1154 if (ty == pty)
1155 return (0);
1157 if (g_verbose) {
1158 ssize_t len;
1159 char *fmri;
1160 const char *tystr;
1162 len = scf_property_to_fmri(prop, NULL, 0);
1163 if (len < 0)
1164 scfdie();
1166 fmri = safe_malloc(len + 1);
1168 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1169 scfdie();
1171 tystr = scf_type_to_string(ty);
1172 if (tystr == NULL)
1173 tystr = "?";
1175 warn(gettext("Property %s is not of expected type %s.\n"),
1176 fmri, tystr);
1178 free(fmri);
1181 return (-1);
1184 static int
1185 prop_get_val(scf_property_t *prop, scf_value_t *val)
1187 scf_error_t err;
1189 if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1190 return (0);
1192 err = scf_error();
1194 if (err != SCF_ERROR_NOT_FOUND &&
1195 err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1196 err != SCF_ERROR_PERMISSION_DENIED)
1197 scfdie();
1199 if (g_verbose) {
1200 ssize_t len;
1201 char *fmri, *emsg;
1203 len = scf_property_to_fmri(prop, NULL, 0);
1204 if (len < 0)
1205 scfdie();
1207 fmri = safe_malloc(len + 1);
1209 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1210 scfdie();
1212 if (err == SCF_ERROR_NOT_FOUND)
1213 emsg = gettext("Property %s has no values; expected "
1214 "one.\n");
1215 else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1216 emsg = gettext("Property %s has multiple values; "
1217 "expected one.\n");
1218 else
1219 emsg = gettext("No permission to read property %s.\n");
1221 warn(emsg, fmri);
1223 free(fmri);
1226 return (-1);
1230 static boolean_t
1231 snaplevel_is_instance(const scf_snaplevel_t *level)
1233 if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1234 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1235 scfdie();
1236 return (0);
1237 } else {
1238 return (1);
1243 * Decode FMRI into a service or instance, and put the result in *ep. If
1244 * memory cannot be allocated, return SCF_ERROR_NO_MEMORY. If the FMRI is
1245 * invalid, return SCF_ERROR_INVALID_ARGUMENT. If the FMRI does not specify
1246 * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED. If the entity cannot be
1247 * found, return SCF_ERROR_NOT_FOUND. Otherwise return SCF_ERROR_NONE, point
1248 * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1249 * whether *ep is a service.
1251 static scf_error_t
1252 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1254 char *fmri_copy;
1255 const char *sstr, *istr, *pgstr;
1256 scf_service_t *svc;
1257 scf_instance_t *inst;
1259 fmri_copy = strdup(fmri);
1260 if (fmri_copy == NULL)
1261 return (SCF_ERROR_NO_MEMORY);
1263 if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1264 SCF_SUCCESS) {
1265 free(fmri_copy);
1266 return (SCF_ERROR_INVALID_ARGUMENT);
1269 free(fmri_copy);
1271 if (sstr == NULL || pgstr != NULL)
1272 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1274 if (istr == NULL) {
1275 svc = scf_service_create(h);
1276 if (svc == NULL)
1277 return (SCF_ERROR_NO_MEMORY);
1279 if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1280 SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1281 if (scf_error() != SCF_ERROR_NOT_FOUND)
1282 scfdie();
1284 return (SCF_ERROR_NOT_FOUND);
1287 *ep = svc;
1288 *isservice = 1;
1289 } else {
1290 inst = scf_instance_create(h);
1291 if (inst == NULL)
1292 return (SCF_ERROR_NO_MEMORY);
1294 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1295 NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1296 if (scf_error() != SCF_ERROR_NOT_FOUND)
1297 scfdie();
1299 return (SCF_ERROR_NOT_FOUND);
1302 *ep = inst;
1303 *isservice = 0;
1306 return (SCF_ERROR_NONE);
1310 * Create the entity named by fmri. Place a pointer to its libscf handle in
1311 * *ep, and set or clear *isservicep if it is a service or an instance.
1312 * Returns
1313 * SCF_ERROR_NONE - success
1314 * SCF_ERROR_NO_MEMORY - scf_*_create() failed
1315 * SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1316 * SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1317 * SCF_ERROR_NOT_FOUND - no such scope
1318 * SCF_ERROR_PERMISSION_DENIED
1319 * SCF_ERROR_BACKEND_READONLY
1320 * SCF_ERROR_BACKEND_ACCESS
1322 static scf_error_t
1323 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1325 char *fmri_copy;
1326 const char *scstr, *sstr, *istr, *pgstr;
1327 scf_scope_t *scope = NULL;
1328 scf_service_t *svc = NULL;
1329 scf_instance_t *inst = NULL;
1330 scf_error_t scfe;
1332 fmri_copy = safe_strdup(fmri);
1334 if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1335 0) {
1336 free(fmri_copy);
1337 return (SCF_ERROR_INVALID_ARGUMENT);
1340 if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1341 free(fmri_copy);
1342 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1345 *ep = NULL;
1347 if ((scope = scf_scope_create(h)) == NULL ||
1348 (svc = scf_service_create(h)) == NULL ||
1349 (inst = scf_instance_create(h)) == NULL) {
1350 scfe = SCF_ERROR_NO_MEMORY;
1351 goto out;
1354 get_scope:
1355 if (scf_handle_get_scope(h, scstr, scope) != 0) {
1356 switch (scf_error()) {
1357 case SCF_ERROR_CONNECTION_BROKEN:
1358 scfdie();
1359 /* NOTREACHED */
1361 case SCF_ERROR_NOT_FOUND:
1362 scfe = SCF_ERROR_NOT_FOUND;
1363 goto out;
1365 case SCF_ERROR_HANDLE_MISMATCH:
1366 case SCF_ERROR_NOT_BOUND:
1367 case SCF_ERROR_INVALID_ARGUMENT:
1368 default:
1369 bad_error("scf_handle_get_scope", scf_error());
1373 get_svc:
1374 if (scf_scope_get_service(scope, sstr, svc) != 0) {
1375 switch (scf_error()) {
1376 case SCF_ERROR_CONNECTION_BROKEN:
1377 scfdie();
1378 /* NOTREACHED */
1380 case SCF_ERROR_DELETED:
1381 goto get_scope;
1383 case SCF_ERROR_NOT_FOUND:
1384 break;
1386 case SCF_ERROR_HANDLE_MISMATCH:
1387 case SCF_ERROR_INVALID_ARGUMENT:
1388 case SCF_ERROR_NOT_BOUND:
1389 case SCF_ERROR_NOT_SET:
1390 default:
1391 bad_error("scf_scope_get_service", scf_error());
1394 if (scf_scope_add_service(scope, sstr, svc) != 0) {
1395 switch (scf_error()) {
1396 case SCF_ERROR_CONNECTION_BROKEN:
1397 scfdie();
1398 /* NOTREACHED */
1400 case SCF_ERROR_DELETED:
1401 goto get_scope;
1403 case SCF_ERROR_PERMISSION_DENIED:
1404 case SCF_ERROR_BACKEND_READONLY:
1405 case SCF_ERROR_BACKEND_ACCESS:
1406 scfe = scf_error();
1407 goto out;
1409 case SCF_ERROR_HANDLE_MISMATCH:
1410 case SCF_ERROR_INVALID_ARGUMENT:
1411 case SCF_ERROR_NOT_BOUND:
1412 case SCF_ERROR_NOT_SET:
1413 default:
1414 bad_error("scf_scope_get_service", scf_error());
1419 if (istr == NULL) {
1420 scfe = SCF_ERROR_NONE;
1421 *ep = svc;
1422 *isservicep = 1;
1423 goto out;
1426 get_inst:
1427 if (scf_service_get_instance(svc, istr, inst) != 0) {
1428 switch (scf_error()) {
1429 case SCF_ERROR_CONNECTION_BROKEN:
1430 scfdie();
1431 /* NOTREACHED */
1433 case SCF_ERROR_DELETED:
1434 goto get_svc;
1436 case SCF_ERROR_NOT_FOUND:
1437 break;
1439 case SCF_ERROR_HANDLE_MISMATCH:
1440 case SCF_ERROR_INVALID_ARGUMENT:
1441 case SCF_ERROR_NOT_BOUND:
1442 case SCF_ERROR_NOT_SET:
1443 default:
1444 bad_error("scf_service_get_instance", scf_error());
1447 if (scf_service_add_instance(svc, istr, inst) != 0) {
1448 switch (scf_error()) {
1449 case SCF_ERROR_CONNECTION_BROKEN:
1450 scfdie();
1451 /* NOTREACHED */
1453 case SCF_ERROR_DELETED:
1454 goto get_svc;
1456 case SCF_ERROR_PERMISSION_DENIED:
1457 case SCF_ERROR_BACKEND_READONLY:
1458 case SCF_ERROR_BACKEND_ACCESS:
1459 scfe = scf_error();
1460 goto out;
1462 case SCF_ERROR_HANDLE_MISMATCH:
1463 case SCF_ERROR_INVALID_ARGUMENT:
1464 case SCF_ERROR_NOT_BOUND:
1465 case SCF_ERROR_NOT_SET:
1466 default:
1467 bad_error("scf_service_add_instance",
1468 scf_error());
1473 scfe = SCF_ERROR_NONE;
1474 *ep = inst;
1475 *isservicep = 0;
1477 out:
1478 if (*ep != inst)
1479 scf_instance_destroy(inst);
1480 if (*ep != svc)
1481 scf_service_destroy(svc);
1482 scf_scope_destroy(scope);
1483 free(fmri_copy);
1484 return (scfe);
1488 * Create or update a snapshot of inst. snap is a required scratch object.
1490 * Returns
1491 * 0 - success
1492 * ECONNABORTED - repository connection broken
1493 * EPERM - permission denied
1494 * ENOSPC - configd is out of resources
1495 * ECANCELED - inst was deleted
1496 * -1 - unknown libscf error (message printed)
1498 static int
1499 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1501 again:
1502 if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1503 if (_scf_snapshot_take_attach(inst, snap) != 0) {
1504 switch (scf_error()) {
1505 case SCF_ERROR_CONNECTION_BROKEN:
1506 case SCF_ERROR_PERMISSION_DENIED:
1507 case SCF_ERROR_NO_RESOURCES:
1508 return (scferror2errno(scf_error()));
1510 case SCF_ERROR_NOT_SET:
1511 case SCF_ERROR_INVALID_ARGUMENT:
1512 default:
1513 bad_error("_scf_snapshot_take_attach",
1514 scf_error());
1517 } else {
1518 switch (scf_error()) {
1519 case SCF_ERROR_NOT_FOUND:
1520 break;
1522 case SCF_ERROR_DELETED:
1523 case SCF_ERROR_CONNECTION_BROKEN:
1524 return (scferror2errno(scf_error()));
1526 case SCF_ERROR_HANDLE_MISMATCH:
1527 case SCF_ERROR_NOT_BOUND:
1528 case SCF_ERROR_INVALID_ARGUMENT:
1529 case SCF_ERROR_NOT_SET:
1530 default:
1531 bad_error("scf_instance_get_snapshot", scf_error());
1534 if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1535 switch (scf_error()) {
1536 case SCF_ERROR_EXISTS:
1537 goto again;
1539 case SCF_ERROR_CONNECTION_BROKEN:
1540 case SCF_ERROR_NO_RESOURCES:
1541 case SCF_ERROR_PERMISSION_DENIED:
1542 return (scferror2errno(scf_error()));
1544 default:
1545 scfwarn();
1546 return (-1);
1548 case SCF_ERROR_NOT_SET:
1549 case SCF_ERROR_INTERNAL:
1550 case SCF_ERROR_INVALID_ARGUMENT:
1551 case SCF_ERROR_HANDLE_MISMATCH:
1552 bad_error("_scf_snapshot_take_new",
1553 scf_error());
1558 return (0);
1561 static int
1562 refresh_running_snapshot(void *entity)
1564 scf_snapshot_t *snap;
1565 int r;
1567 if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1568 scfdie();
1569 r = take_snap(entity, snap_running, snap);
1570 scf_snapshot_destroy(snap);
1572 return (r);
1576 * Refresh entity. If isservice is zero, take entity to be an scf_instance_t *.
1577 * Otherwise take entity to be an scf_service_t * and refresh all of its child
1578 * instances. fmri is used for messages. inst, iter, and name_buf are used
1579 * for scratch space. Returns
1580 * 0 - success
1581 * ECONNABORTED - repository connection broken
1582 * ECANCELED - entity was deleted
1583 * EACCES - backend denied access
1584 * EPERM - permission denied
1585 * ENOSPC - repository server out of resources
1586 * -1 - _smf_refresh_instance_i() failed. scf_error() should be set.
1588 static int
1589 refresh_entity(int isservice, void *entity, const char *fmri,
1590 scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1592 scf_error_t scfe;
1593 int r;
1595 if (!isservice) {
1597 * Let restarter handles refreshing and making new running
1598 * snapshot only if operating on a live repository and not
1599 * running in early import.
1601 if (est->sc_repo_filename == NULL &&
1602 est->sc_repo_doorname == NULL &&
1603 est->sc_in_emi == 0) {
1604 if (_smf_refresh_instance_i(entity) == 0) {
1605 if (g_verbose)
1606 warn(gettext("Refreshed %s.\n"), fmri);
1607 return (0);
1610 switch (scf_error()) {
1611 case SCF_ERROR_BACKEND_ACCESS:
1612 return (EACCES);
1614 case SCF_ERROR_PERMISSION_DENIED:
1615 return (EPERM);
1617 default:
1618 return (-1);
1620 } else {
1621 r = refresh_running_snapshot(entity);
1622 switch (r) {
1623 case 0:
1624 break;
1626 case ECONNABORTED:
1627 case ECANCELED:
1628 case EPERM:
1629 case ENOSPC:
1630 break;
1632 default:
1633 bad_error("refresh_running_snapshot",
1634 scf_error());
1637 return (r);
1641 if (scf_iter_service_instances(iter, entity) != 0) {
1642 switch (scf_error()) {
1643 case SCF_ERROR_CONNECTION_BROKEN:
1644 return (ECONNABORTED);
1646 case SCF_ERROR_DELETED:
1647 return (ECANCELED);
1649 case SCF_ERROR_HANDLE_MISMATCH:
1650 case SCF_ERROR_NOT_BOUND:
1651 case SCF_ERROR_NOT_SET:
1652 default:
1653 bad_error("scf_iter_service_instances", scf_error());
1657 for (;;) {
1658 r = scf_iter_next_instance(iter, inst);
1659 if (r == 0)
1660 break;
1661 if (r != 1) {
1662 switch (scf_error()) {
1663 case SCF_ERROR_CONNECTION_BROKEN:
1664 return (ECONNABORTED);
1666 case SCF_ERROR_DELETED:
1667 return (ECANCELED);
1669 case SCF_ERROR_HANDLE_MISMATCH:
1670 case SCF_ERROR_NOT_BOUND:
1671 case SCF_ERROR_NOT_SET:
1672 case SCF_ERROR_INVALID_ARGUMENT:
1673 default:
1674 bad_error("scf_iter_next_instance",
1675 scf_error());
1680 * Similarly, just take a new running snapshot if operating on
1681 * a non-live repository or running during early import.
1683 if (est->sc_repo_filename != NULL ||
1684 est->sc_repo_doorname != NULL ||
1685 est->sc_in_emi == 1) {
1686 r = refresh_running_snapshot(inst);
1687 switch (r) {
1688 case 0:
1689 continue;
1691 case ECONNABORTED:
1692 case ECANCELED:
1693 case EPERM:
1694 case ENOSPC:
1695 break;
1696 default:
1697 bad_error("refresh_running_snapshot",
1698 scf_error());
1701 return (r);
1705 if (_smf_refresh_instance_i(inst) == 0) {
1706 if (g_verbose) {
1707 if (scf_instance_get_name(inst, name_buf,
1708 max_scf_name_len + 1) < 0)
1709 (void) strcpy(name_buf, "?");
1711 warn(gettext("Refreshed %s:%s.\n"),
1712 fmri, name_buf);
1714 } else {
1715 if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1716 g_verbose) {
1717 scfe = scf_error();
1719 if (scf_instance_to_fmri(inst, name_buf,
1720 max_scf_name_len + 1) < 0)
1721 (void) strcpy(name_buf, "?");
1723 warn(gettext(
1724 "Refresh of %s:%s failed: %s.\n"), fmri,
1725 name_buf, scf_strerror(scfe));
1730 return (0);
1733 static void
1734 private_refresh(void)
1736 scf_instance_t *pinst = NULL;
1737 scf_iter_t *piter = NULL;
1738 ssize_t fmrilen;
1739 size_t bufsz;
1740 char *fmribuf;
1741 void *ent;
1742 int issvc;
1743 int r;
1745 if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1746 return;
1748 assert(cur_svc != NULL);
1750 bufsz = max_scf_fmri_len + 1;
1751 fmribuf = safe_malloc(bufsz);
1752 if (cur_inst) {
1753 issvc = 0;
1754 ent = cur_inst;
1755 fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1756 } else {
1757 issvc = 1;
1758 ent = cur_svc;
1759 fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1760 if ((pinst = scf_instance_create(g_hndl)) == NULL)
1761 scfdie();
1763 if ((piter = scf_iter_create(g_hndl)) == NULL)
1764 scfdie();
1766 if (fmrilen < 0) {
1767 free(fmribuf);
1768 if (scf_error() != SCF_ERROR_DELETED)
1769 scfdie();
1771 warn(emsg_deleted);
1772 return;
1774 assert(fmrilen < bufsz);
1776 r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1777 switch (r) {
1778 case 0:
1779 break;
1781 case ECONNABORTED:
1782 warn(gettext("Could not refresh %s "
1783 "(repository connection broken).\n"), fmribuf);
1784 break;
1786 case ECANCELED:
1787 warn(emsg_deleted);
1788 break;
1790 case EPERM:
1791 warn(gettext("Could not refresh %s "
1792 "(permission denied).\n"), fmribuf);
1793 break;
1795 case ENOSPC:
1796 warn(gettext("Could not refresh %s "
1797 "(repository server out of resources).\n"),
1798 fmribuf);
1799 break;
1801 case EACCES:
1802 default:
1803 bad_error("refresh_entity", scf_error());
1806 if (issvc) {
1807 scf_instance_destroy(pinst);
1808 scf_iter_destroy(piter);
1811 free(fmribuf);
1815 static int
1816 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1818 cbp->sc_err = scferror2errno(err);
1819 return (UU_WALK_ERROR);
1822 static int
1823 stash_scferror(scf_callback_t *cbp)
1825 return (stash_scferror_err(cbp, scf_error()));
1828 static int select_inst(const char *);
1829 static int select_svc(const char *);
1832 * Take a property that does not have a type and check to see if a type
1833 * exists or can be gleened from the current data. Set the type.
1835 * Check the current level (instance) and then check the higher level
1836 * (service). This could be the case for adding a new property to
1837 * the instance that's going to "override" a service level property.
1839 * For a property :
1840 * 1. Take the type from an existing property
1841 * 2. Take the type from a template entry
1843 * If the type can not be found, then leave the type as is, and let the import
1844 * report the problem of the missing type.
1846 static int
1847 find_current_prop_type(void *p, void *g)
1849 property_t *prop = p;
1850 scf_callback_t *lcb = g;
1851 pgroup_t *pg = NULL;
1853 const char *fmri = NULL;
1854 char *lfmri = NULL;
1855 char *cur_selection = NULL;
1857 scf_propertygroup_t *sc_pg = NULL;
1858 scf_property_t *sc_prop = NULL;
1859 scf_pg_tmpl_t *t_pg = NULL;
1860 scf_prop_tmpl_t *t_prop = NULL;
1861 scf_type_t prop_type;
1863 value_t *vp;
1864 int issvc = lcb->sc_service;
1865 int r = UU_WALK_ERROR;
1867 if (prop->sc_value_type != SCF_TYPE_INVALID)
1868 return (UU_WALK_NEXT);
1870 t_prop = scf_tmpl_prop_create(g_hndl);
1871 sc_prop = scf_property_create(g_hndl);
1872 if (sc_prop == NULL || t_prop == NULL) {
1873 warn(gettext("Unable to create the property to attempt and "
1874 "find a missing type.\n"));
1876 scf_property_destroy(sc_prop);
1877 scf_tmpl_prop_destroy(t_prop);
1879 return (UU_WALK_ERROR);
1882 if (lcb->sc_flags == 1) {
1883 pg = lcb->sc_parent;
1884 issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT);
1885 fmri = pg->sc_parent->sc_fmri;
1886 retry_pg:
1887 if (cur_svc && cur_selection == NULL) {
1888 cur_selection = safe_malloc(max_scf_fmri_len + 1);
1889 lscf_get_selection_str(cur_selection,
1890 max_scf_fmri_len + 1);
1892 if (strcmp(cur_selection, fmri) != 0) {
1893 lscf_select(fmri);
1894 } else {
1895 free(cur_selection);
1896 cur_selection = NULL;
1898 } else {
1899 lscf_select(fmri);
1902 if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) {
1903 warn(gettext("Unable to create property group to "
1904 "find a missing property type.\n"));
1906 goto out;
1909 if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) {
1911 * If this is the sc_pg from the parent
1912 * let the caller clean up the sc_pg,
1913 * and just throw it away in this case.
1915 if (sc_pg != lcb->sc_parent)
1916 scf_pg_destroy(sc_pg);
1918 sc_pg = NULL;
1919 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1920 warn(gettext("Unable to create template "
1921 "property group to find a property "
1922 "type.\n"));
1924 goto out;
1927 if (scf_tmpl_get_by_pg_name(fmri, NULL,
1928 pg->sc_pgroup_name, NULL, t_pg,
1929 SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) {
1931 * if instance get service and jump back
1933 scf_tmpl_pg_destroy(t_pg);
1934 t_pg = NULL;
1935 if (issvc == 0) {
1936 entity_t *e = pg->sc_parent->sc_parent;
1938 fmri = e->sc_fmri;
1939 issvc = 1;
1940 goto retry_pg;
1941 } else {
1942 goto out;
1946 } else {
1947 sc_pg = lcb->sc_parent;
1951 * Attempt to get the type from an existing property. If the property
1952 * cannot be found then attempt to get the type from a template entry
1953 * for the property.
1955 * Finally, if at the instance level look at the service level.
1957 if (sc_pg != NULL &&
1958 pg_get_prop(sc_pg, prop->sc_property_name,
1959 sc_prop) == SCF_SUCCESS &&
1960 scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) {
1961 prop->sc_value_type = prop_type;
1964 * Found a type, update the value types and validate
1965 * the actual value against this type.
1967 for (vp = uu_list_first(prop->sc_property_values);
1968 vp != NULL;
1969 vp = uu_list_next(prop->sc_property_values, vp)) {
1970 vp->sc_type = prop->sc_value_type;
1971 lxml_store_value(vp, 0, NULL);
1974 r = UU_WALK_NEXT;
1975 goto out;
1979 * If we get here with t_pg set to NULL then we had to have
1980 * gotten an sc_pg but that sc_pg did not have the property
1981 * we are looking for. So if the t_pg is not null look up
1982 * the template entry for the property.
1984 * If the t_pg is null then need to attempt to get a matching
1985 * template entry for the sc_pg, and see if there is a property
1986 * entry for that template entry.
1988 do_tmpl :
1989 if (t_pg != NULL &&
1990 scf_tmpl_get_by_prop(t_pg, prop->sc_property_name,
1991 t_prop, 0) == SCF_SUCCESS) {
1992 if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) {
1993 prop->sc_value_type = prop_type;
1996 * Found a type, update the value types and validate
1997 * the actual value against this type.
1999 for (vp = uu_list_first(prop->sc_property_values);
2000 vp != NULL;
2001 vp = uu_list_next(prop->sc_property_values, vp)) {
2002 vp->sc_type = prop->sc_value_type;
2003 lxml_store_value(vp, 0, NULL);
2006 r = UU_WALK_NEXT;
2007 goto out;
2009 } else {
2010 if (t_pg == NULL && sc_pg) {
2011 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
2012 warn(gettext("Unable to create template "
2013 "property group to find a property "
2014 "type.\n"));
2016 goto out;
2019 if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
2020 scf_tmpl_pg_destroy(t_pg);
2021 t_pg = NULL;
2022 } else {
2023 goto do_tmpl;
2028 if (issvc == 0) {
2029 scf_instance_t *i;
2030 scf_service_t *s;
2032 issvc = 1;
2033 if (lcb->sc_flags == 1) {
2034 entity_t *e = pg->sc_parent->sc_parent;
2036 fmri = e->sc_fmri;
2037 goto retry_pg;
2041 * because lcb->sc_flags was not set then this means
2042 * the pg was not used and can be used here.
2044 if ((pg = internal_pgroup_new()) == NULL) {
2045 warn(gettext("Could not create internal property group "
2046 "to find a missing type."));
2048 goto out;
2051 pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1);
2052 if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name,
2053 max_scf_name_len + 1) < 0)
2054 goto out;
2056 i = scf_instance_create(g_hndl);
2057 s = scf_service_create(g_hndl);
2058 if (i == NULL || s == NULL ||
2059 scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) {
2060 warn(gettext("Could not get a service for the instance "
2061 "to find a missing type."));
2063 goto out;
2067 * Check to see truly at the instance level.
2069 lfmri = safe_malloc(max_scf_fmri_len + 1);
2070 if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
2071 scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0)
2072 goto out;
2073 else
2074 fmri = (const char *)lfmri;
2076 goto retry_pg;
2079 out :
2080 if (sc_pg != lcb->sc_parent) {
2081 scf_pg_destroy(sc_pg);
2085 * If this is true then the pg was allocated
2086 * here, and the name was set so need to free
2087 * the name and the pg.
2089 if (pg != NULL && pg != lcb->sc_parent) {
2090 free((char *)pg->sc_pgroup_name);
2091 internal_pgroup_free(pg);
2094 if (cur_selection) {
2095 lscf_select(cur_selection);
2096 free(cur_selection);
2099 scf_tmpl_pg_destroy(t_pg);
2100 scf_tmpl_prop_destroy(t_prop);
2101 scf_property_destroy(sc_prop);
2103 if (r != UU_WALK_NEXT)
2104 warn(gettext("Could not find property type for \"%s\" "
2105 "from \"%s\"\n"), prop->sc_property_name,
2106 fmri != NULL ? fmri : lcb->sc_source_fmri);
2108 free(lfmri);
2110 return (r);
2114 * Take a property group that does not have a type and check to see if a type
2115 * exists or can be gleened from the current data. Set the type.
2117 * Check the current level (instance) and then check the higher level
2118 * (service). This could be the case for adding a new property to
2119 * the instance that's going to "override" a service level property.
2121 * For a property group
2122 * 1. Take the type from an existing property group
2123 * 2. Take the type from a template entry
2125 * If the type can not be found, then leave the type as is, and let the import
2126 * report the problem of the missing type.
2128 static int
2129 find_current_pg_type(void *p, void *sori)
2131 entity_t *si = sori;
2132 pgroup_t *pg = p;
2134 const char *ofmri, *fmri;
2135 char *cur_selection = NULL;
2136 char *pg_type = NULL;
2138 scf_propertygroup_t *sc_pg = NULL;
2139 scf_pg_tmpl_t *t_pg = NULL;
2141 int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2142 int r = UU_WALK_ERROR;
2144 ofmri = fmri = si->sc_fmri;
2145 if (pg->sc_pgroup_type != NULL) {
2146 r = UU_WALK_NEXT;
2148 goto out;
2151 sc_pg = scf_pg_create(g_hndl);
2152 if (sc_pg == NULL) {
2153 warn(gettext("Unable to create property group to attempt "
2154 "and find a missing type.\n"));
2156 return (UU_WALK_ERROR);
2160 * Using get_pg() requires that the cur_svc/cur_inst be
2161 * via lscf_select. Need to preserve the current selection
2162 * if going to use lscf_select() to set up the cur_svc/cur_inst
2164 if (cur_svc) {
2165 cur_selection = safe_malloc(max_scf_fmri_len + 1);
2166 lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1);
2170 * If the property group exists get the type, and set
2171 * the pgroup_t type of that type.
2173 * If not the check for a template pg_pattern entry
2174 * and take the type from that.
2176 retry_svc:
2177 lscf_select(fmri);
2179 if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) {
2180 pg_type = safe_malloc(max_scf_pg_type_len + 1);
2181 if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type,
2182 max_scf_pg_type_len + 1) != -1) {
2183 pg->sc_pgroup_type = pg_type;
2185 r = UU_WALK_NEXT;
2186 goto out;
2187 } else {
2188 free(pg_type);
2190 } else {
2191 if ((t_pg == NULL) &&
2192 (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
2193 goto out;
2195 if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name,
2196 NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS &&
2197 scf_tmpl_pg_type(t_pg, &pg_type) != -1) {
2198 pg->sc_pgroup_type = pg_type;
2200 r = UU_WALK_NEXT;
2201 goto out;
2206 * If type is not found at the instance level then attempt to
2207 * find the type at the service level.
2209 if (!issvc) {
2210 si = si->sc_parent;
2211 fmri = si->sc_fmri;
2212 issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2213 goto retry_svc;
2216 out :
2217 if (cur_selection) {
2218 lscf_select(cur_selection);
2219 free(cur_selection);
2223 * Now walk the properties of the property group to make sure that
2224 * all properties have the correct type and values are valid for
2225 * those types.
2227 if (r == UU_WALK_NEXT) {
2228 scf_callback_t cb;
2230 cb.sc_service = issvc;
2231 cb.sc_source_fmri = ofmri;
2232 if (sc_pg != NULL) {
2233 cb.sc_parent = sc_pg;
2234 cb.sc_flags = 0;
2235 } else {
2236 cb.sc_parent = pg;
2237 cb.sc_flags = 1;
2240 if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type,
2241 &cb, UU_DEFAULT) != 0) {
2242 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2243 bad_error("uu_list_walk", uu_error());
2245 r = UU_WALK_ERROR;
2247 } else {
2248 warn(gettext("Could not find property group type for "
2249 "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri);
2252 scf_tmpl_pg_destroy(t_pg);
2253 scf_pg_destroy(sc_pg);
2255 return (r);
2259 * Import. These functions import a bundle into the repository.
2263 * Add a transaction entry to lcbdata->sc_trans for this property_t. Uses
2264 * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata. On success,
2265 * returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
2266 * lcbdata->sc_err to
2267 * ENOMEM - out of memory
2268 * ECONNABORTED - repository connection broken
2269 * ECANCELED - sc_trans's property group was deleted
2270 * EINVAL - p's name is invalid (error printed)
2271 * - p has an invalid value (error printed)
2273 static int
2274 lscf_property_import(void *v, void *pvt)
2276 property_t *p = v;
2277 scf_callback_t *lcbdata = pvt;
2278 value_t *vp;
2279 scf_transaction_t *trans = lcbdata->sc_trans;
2280 scf_transaction_entry_t *entr;
2281 scf_value_t *val;
2282 scf_type_t tp;
2284 if ((lcbdata->sc_flags & SCI_NOENABLED ||
2285 lcbdata->sc_flags & SCI_DELAYENABLE) &&
2286 strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
2287 lcbdata->sc_enable = p;
2288 return (UU_WALK_NEXT);
2291 entr = scf_entry_create(lcbdata->sc_handle);
2292 if (entr == NULL) {
2293 switch (scf_error()) {
2294 case SCF_ERROR_NO_MEMORY:
2295 return (stash_scferror(lcbdata));
2297 case SCF_ERROR_INVALID_ARGUMENT:
2298 default:
2299 bad_error("scf_entry_create", scf_error());
2303 tp = p->sc_value_type;
2305 if (scf_transaction_property_new(trans, entr,
2306 p->sc_property_name, tp) != 0) {
2307 switch (scf_error()) {
2308 case SCF_ERROR_INVALID_ARGUMENT:
2309 semerr(emsg_invalid_prop_name, p->sc_property_name);
2310 scf_entry_destroy(entr);
2311 return (stash_scferror(lcbdata));
2313 case SCF_ERROR_EXISTS:
2314 break;
2316 case SCF_ERROR_DELETED:
2317 case SCF_ERROR_CONNECTION_BROKEN:
2318 scf_entry_destroy(entr);
2319 return (stash_scferror(lcbdata));
2321 case SCF_ERROR_NOT_BOUND:
2322 case SCF_ERROR_HANDLE_MISMATCH:
2323 case SCF_ERROR_NOT_SET:
2324 default:
2325 bad_error("scf_transaction_property_new", scf_error());
2328 if (scf_transaction_property_change_type(trans, entr,
2329 p->sc_property_name, tp) != 0) {
2330 switch (scf_error()) {
2331 case SCF_ERROR_DELETED:
2332 case SCF_ERROR_CONNECTION_BROKEN:
2333 scf_entry_destroy(entr);
2334 return (stash_scferror(lcbdata));
2336 case SCF_ERROR_INVALID_ARGUMENT:
2337 semerr(emsg_invalid_prop_name,
2338 p->sc_property_name);
2339 scf_entry_destroy(entr);
2340 return (stash_scferror(lcbdata));
2342 case SCF_ERROR_NOT_FOUND:
2343 case SCF_ERROR_NOT_SET:
2344 case SCF_ERROR_HANDLE_MISMATCH:
2345 case SCF_ERROR_NOT_BOUND:
2346 default:
2347 bad_error(
2348 "scf_transaction_property_change_type",
2349 scf_error());
2354 for (vp = uu_list_first(p->sc_property_values);
2355 vp != NULL;
2356 vp = uu_list_next(p->sc_property_values, vp)) {
2357 val = scf_value_create(g_hndl);
2358 if (val == NULL) {
2359 switch (scf_error()) {
2360 case SCF_ERROR_NO_MEMORY:
2361 return (stash_scferror(lcbdata));
2363 case SCF_ERROR_INVALID_ARGUMENT:
2364 default:
2365 bad_error("scf_value_create", scf_error());
2369 switch (tp) {
2370 case SCF_TYPE_BOOLEAN:
2371 scf_value_set_boolean(val, vp->sc_u.sc_count);
2372 break;
2373 case SCF_TYPE_COUNT:
2374 scf_value_set_count(val, vp->sc_u.sc_count);
2375 break;
2376 case SCF_TYPE_INTEGER:
2377 scf_value_set_integer(val, vp->sc_u.sc_integer);
2378 break;
2379 default:
2380 assert(vp->sc_u.sc_string != NULL);
2381 if (scf_value_set_from_string(val, tp,
2382 vp->sc_u.sc_string) != 0) {
2383 if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
2384 bad_error("scf_value_set_from_string",
2385 scf_error());
2387 warn(gettext("Value \"%s\" is not a valid "
2388 "%s.\n"), vp->sc_u.sc_string,
2389 scf_type_to_string(tp));
2390 scf_value_destroy(val);
2391 return (stash_scferror(lcbdata));
2393 break;
2396 if (scf_entry_add_value(entr, val) != 0)
2397 bad_error("scf_entry_add_value", scf_error());
2400 return (UU_WALK_NEXT);
2404 * Import a pgroup_t into the repository. Uses sc_handle, sc_parent,
2405 * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2406 * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2407 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
2408 * lcbdata->sc_err to
2409 * ECONNABORTED - repository connection broken
2410 * ENOMEM - out of memory
2411 * ENOSPC - svc.configd is out of resources
2412 * ECANCELED - sc_parent was deleted
2413 * EPERM - could not create property group (permission denied) (error printed)
2414 * - could not modify property group (permission denied) (error printed)
2415 * - could not delete property group (permission denied) (error printed)
2416 * EROFS - could not create property group (repository is read-only)
2417 * - could not delete property group (repository is read-only)
2418 * EACCES - could not create property group (backend access denied)
2419 * - could not delete property group (backend access denied)
2420 * EEXIST - could not create property group (already exists)
2421 * EINVAL - invalid property group name (error printed)
2422 * - invalid property name (error printed)
2423 * - invalid value (error printed)
2424 * EBUSY - new property group deleted (error printed)
2425 * - new property group changed (error printed)
2426 * - property group added (error printed)
2427 * - property group deleted (error printed)
2429 static int
2430 entity_pgroup_import(void *v, void *pvt)
2432 pgroup_t *p = v;
2433 scf_callback_t cbdata;
2434 scf_callback_t *lcbdata = pvt;
2435 void *ent = lcbdata->sc_parent;
2436 int issvc = lcbdata->sc_service;
2437 int r;
2439 const char * const pg_changed = gettext("%s changed unexpectedly "
2440 "(new property group \"%s\" changed).\n");
2442 /* Never import deleted property groups. */
2443 if (p->sc_pgroup_delete) {
2444 if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY &&
2445 entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) {
2446 goto delete_pg;
2448 return (UU_WALK_NEXT);
2451 if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
2452 strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
2453 lcbdata->sc_general = p;
2454 return (UU_WALK_NEXT);
2457 add_pg:
2458 if (issvc)
2459 r = scf_service_add_pg(ent, p->sc_pgroup_name,
2460 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2461 else
2462 r = scf_instance_add_pg(ent, p->sc_pgroup_name,
2463 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2464 if (r != 0) {
2465 switch (scf_error()) {
2466 case SCF_ERROR_DELETED:
2467 case SCF_ERROR_CONNECTION_BROKEN:
2468 case SCF_ERROR_BACKEND_READONLY:
2469 case SCF_ERROR_BACKEND_ACCESS:
2470 case SCF_ERROR_NO_RESOURCES:
2471 return (stash_scferror(lcbdata));
2473 case SCF_ERROR_EXISTS:
2474 if (lcbdata->sc_flags & SCI_FORCE)
2475 break;
2476 return (stash_scferror(lcbdata));
2478 case SCF_ERROR_INVALID_ARGUMENT:
2479 warn(emsg_fmri_invalid_pg_name_type,
2480 lcbdata->sc_source_fmri,
2481 p->sc_pgroup_name, p->sc_pgroup_type);
2482 return (stash_scferror(lcbdata));
2484 case SCF_ERROR_PERMISSION_DENIED:
2485 warn(emsg_pg_add_perm, p->sc_pgroup_name,
2486 lcbdata->sc_target_fmri);
2487 return (stash_scferror(lcbdata));
2489 case SCF_ERROR_NOT_BOUND:
2490 case SCF_ERROR_HANDLE_MISMATCH:
2491 case SCF_ERROR_NOT_SET:
2492 default:
2493 bad_error("scf_service_add_pg", scf_error());
2496 if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2497 switch (scf_error()) {
2498 case SCF_ERROR_CONNECTION_BROKEN:
2499 case SCF_ERROR_DELETED:
2500 return (stash_scferror(lcbdata));
2502 case SCF_ERROR_INVALID_ARGUMENT:
2503 warn(emsg_fmri_invalid_pg_name,
2504 lcbdata->sc_source_fmri,
2505 p->sc_pgroup_name);
2506 return (stash_scferror(lcbdata));
2508 case SCF_ERROR_NOT_FOUND:
2509 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2510 p->sc_pgroup_name);
2511 lcbdata->sc_err = EBUSY;
2512 return (UU_WALK_ERROR);
2514 case SCF_ERROR_NOT_BOUND:
2515 case SCF_ERROR_HANDLE_MISMATCH:
2516 case SCF_ERROR_NOT_SET:
2517 default:
2518 bad_error("entity_get_pg", scf_error());
2522 if (lcbdata->sc_flags & SCI_KEEP)
2523 goto props;
2525 delete_pg:
2526 if (scf_pg_delete(imp_pg) != 0) {
2527 switch (scf_error()) {
2528 case SCF_ERROR_DELETED:
2529 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2530 p->sc_pgroup_name);
2531 lcbdata->sc_err = EBUSY;
2532 return (UU_WALK_ERROR);
2534 case SCF_ERROR_PERMISSION_DENIED:
2535 warn(emsg_pg_del_perm, p->sc_pgroup_name,
2536 lcbdata->sc_target_fmri);
2537 return (stash_scferror(lcbdata));
2539 case SCF_ERROR_BACKEND_READONLY:
2540 case SCF_ERROR_BACKEND_ACCESS:
2541 case SCF_ERROR_CONNECTION_BROKEN:
2542 return (stash_scferror(lcbdata));
2544 case SCF_ERROR_NOT_SET:
2545 default:
2546 bad_error("scf_pg_delete", scf_error());
2550 if (p->sc_pgroup_delete)
2551 return (UU_WALK_NEXT);
2553 goto add_pg;
2556 props:
2559 * Add properties to property group, if any.
2561 cbdata.sc_handle = lcbdata->sc_handle;
2562 cbdata.sc_parent = imp_pg;
2563 cbdata.sc_flags = lcbdata->sc_flags;
2564 cbdata.sc_trans = imp_tx;
2565 cbdata.sc_enable = NULL;
2567 if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2568 switch (scf_error()) {
2569 case SCF_ERROR_BACKEND_ACCESS:
2570 case SCF_ERROR_BACKEND_READONLY:
2571 case SCF_ERROR_CONNECTION_BROKEN:
2572 return (stash_scferror(lcbdata));
2574 case SCF_ERROR_DELETED:
2575 warn(pg_changed, lcbdata->sc_target_fmri,
2576 p->sc_pgroup_name);
2577 lcbdata->sc_err = EBUSY;
2578 return (UU_WALK_ERROR);
2580 case SCF_ERROR_PERMISSION_DENIED:
2581 warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2582 lcbdata->sc_target_fmri);
2583 return (stash_scferror(lcbdata));
2585 case SCF_ERROR_NOT_BOUND:
2586 case SCF_ERROR_NOT_SET:
2587 case SCF_ERROR_IN_USE:
2588 case SCF_ERROR_HANDLE_MISMATCH:
2589 default:
2590 bad_error("scf_transaction_start", scf_error());
2594 if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2595 UU_DEFAULT) != 0) {
2596 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2597 bad_error("uu_list_walk", uu_error());
2598 scf_transaction_reset(imp_tx);
2600 lcbdata->sc_err = cbdata.sc_err;
2601 if (cbdata.sc_err == ECANCELED) {
2602 warn(pg_changed, lcbdata->sc_target_fmri,
2603 p->sc_pgroup_name);
2604 lcbdata->sc_err = EBUSY;
2606 return (UU_WALK_ERROR);
2609 if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2610 cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2613 * take the snapshot running snapshot then
2614 * import the stored general/enable property
2616 r = take_snap(ent, snap_running, imp_rsnap);
2617 switch (r) {
2618 case 0:
2619 break;
2621 case ECONNABORTED:
2622 warn(gettext("Could not take %s snapshot on import "
2623 "(repository connection broken).\n"),
2624 snap_running);
2625 lcbdata->sc_err = r;
2626 return (UU_WALK_ERROR);
2627 case ECANCELED:
2628 warn(emsg_deleted);
2629 lcbdata->sc_err = r;
2630 return (UU_WALK_ERROR);
2632 case EPERM:
2633 warn(gettext("Could not take %s snapshot "
2634 "(permission denied).\n"), snap_running);
2635 lcbdata->sc_err = r;
2636 return (UU_WALK_ERROR);
2638 case ENOSPC:
2639 warn(gettext("Could not take %s snapshot"
2640 "(repository server out of resources).\n"),
2641 snap_running);
2642 lcbdata->sc_err = r;
2643 return (UU_WALK_ERROR);
2645 default:
2646 bad_error("take_snap", r);
2649 r = lscf_property_import(cbdata.sc_enable, &cbdata);
2650 if (r != UU_WALK_NEXT) {
2651 if (r != UU_WALK_ERROR)
2652 bad_error("lscf_property_import", r);
2653 return (EINVAL);
2657 r = scf_transaction_commit(imp_tx);
2658 switch (r) {
2659 case 1:
2660 r = UU_WALK_NEXT;
2661 break;
2663 case 0:
2664 warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2665 lcbdata->sc_err = EBUSY;
2666 r = UU_WALK_ERROR;
2667 break;
2669 case -1:
2670 switch (scf_error()) {
2671 case SCF_ERROR_BACKEND_READONLY:
2672 case SCF_ERROR_BACKEND_ACCESS:
2673 case SCF_ERROR_CONNECTION_BROKEN:
2674 case SCF_ERROR_NO_RESOURCES:
2675 r = stash_scferror(lcbdata);
2676 break;
2678 case SCF_ERROR_DELETED:
2679 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2680 p->sc_pgroup_name);
2681 lcbdata->sc_err = EBUSY;
2682 r = UU_WALK_ERROR;
2683 break;
2685 case SCF_ERROR_PERMISSION_DENIED:
2686 warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2687 lcbdata->sc_target_fmri);
2688 r = stash_scferror(lcbdata);
2689 break;
2691 case SCF_ERROR_NOT_SET:
2692 case SCF_ERROR_INVALID_ARGUMENT:
2693 case SCF_ERROR_NOT_BOUND:
2694 default:
2695 bad_error("scf_transaction_commit", scf_error());
2697 break;
2699 default:
2700 bad_error("scf_transaction_commit", r);
2703 scf_transaction_destroy_children(imp_tx);
2705 return (r);
2709 * Returns
2710 * 0 - success
2711 * ECONNABORTED - repository connection broken
2712 * ENOMEM - out of memory
2713 * ENOSPC - svc.configd is out of resources
2714 * ECANCELED - inst was deleted
2715 * EPERM - could not create property group (permission denied) (error printed)
2716 * - could not modify property group (permission denied) (error printed)
2717 * EROFS - could not create property group (repository is read-only)
2718 * EACCES - could not create property group (backend access denied)
2719 * EEXIST - could not create property group (already exists)
2720 * EINVAL - invalid property group name (error printed)
2721 * - invalid property name (error printed)
2722 * - invalid value (error printed)
2723 * EBUSY - new property group changed (error printed)
2725 static int
2726 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2727 const entity_t *isvc, int flags)
2729 scf_callback_t cbdata;
2731 cbdata.sc_handle = scf_service_handle(svc);
2732 cbdata.sc_parent = svc;
2733 cbdata.sc_service = 1;
2734 cbdata.sc_general = 0;
2735 cbdata.sc_enable = 0;
2736 cbdata.sc_flags = flags;
2737 cbdata.sc_source_fmri = isvc->sc_fmri;
2738 cbdata.sc_target_fmri = target_fmri;
2741 * If the op is set, then add the flag to the callback
2742 * flags for later use.
2744 if (isvc->sc_op != SVCCFG_OP_NONE) {
2745 switch (isvc->sc_op) {
2746 case SVCCFG_OP_IMPORT :
2747 cbdata.sc_flags |= SCI_OP_IMPORT;
2748 break;
2749 case SVCCFG_OP_APPLY :
2750 cbdata.sc_flags |= SCI_OP_APPLY;
2751 break;
2752 case SVCCFG_OP_RESTORE :
2753 cbdata.sc_flags |= SCI_OP_RESTORE;
2754 break;
2755 default :
2756 uu_die(gettext("lscf_import_service_pgs : "
2757 "Unknown op stored in the service entity\n"));
2762 if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2763 UU_DEFAULT) != 0) {
2764 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2765 bad_error("uu_list_walk", uu_error());
2767 return (cbdata.sc_err);
2770 return (0);
2774 * Returns
2775 * 0 - success
2776 * ECONNABORTED - repository connection broken
2777 * ENOMEM - out of memory
2778 * ENOSPC - svc.configd is out of resources
2779 * ECANCELED - inst was deleted
2780 * EPERM - could not create property group (permission denied) (error printed)
2781 * - could not modify property group (permission denied) (error printed)
2782 * EROFS - could not create property group (repository is read-only)
2783 * EACCES - could not create property group (backend access denied)
2784 * EEXIST - could not create property group (already exists)
2785 * EINVAL - invalid property group name (error printed)
2786 * - invalid property name (error printed)
2787 * - invalid value (error printed)
2788 * EBUSY - new property group changed (error printed)
2790 static int
2791 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2792 const entity_t *iinst, int flags)
2794 scf_callback_t cbdata;
2796 cbdata.sc_handle = scf_instance_handle(inst);
2797 cbdata.sc_parent = inst;
2798 cbdata.sc_service = 0;
2799 cbdata.sc_general = NULL;
2800 cbdata.sc_enable = NULL;
2801 cbdata.sc_flags = flags;
2802 cbdata.sc_source_fmri = iinst->sc_fmri;
2803 cbdata.sc_target_fmri = target_fmri;
2806 * If the op is set, then add the flag to the callback
2807 * flags for later use.
2809 if (iinst->sc_op != SVCCFG_OP_NONE) {
2810 switch (iinst->sc_op) {
2811 case SVCCFG_OP_IMPORT :
2812 cbdata.sc_flags |= SCI_OP_IMPORT;
2813 break;
2814 case SVCCFG_OP_APPLY :
2815 cbdata.sc_flags |= SCI_OP_APPLY;
2816 break;
2817 case SVCCFG_OP_RESTORE :
2818 cbdata.sc_flags |= SCI_OP_RESTORE;
2819 break;
2820 default :
2821 uu_die(gettext("lscf_import_instance_pgs : "
2822 "Unknown op stored in the instance entity\n"));
2826 if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2827 UU_DEFAULT) != 0) {
2828 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2829 bad_error("uu_list_walk", uu_error());
2831 return (cbdata.sc_err);
2834 if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2835 cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2837 * If importing with the SCI_NOENABLED flag then
2838 * skip the delay, but if not then add the delay
2839 * of the enable property.
2841 if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2842 cbdata.sc_flags |= SCI_DELAYENABLE;
2845 if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2846 != UU_WALK_NEXT)
2847 return (cbdata.sc_err);
2850 return (0);
2854 * Report the reasons why we can't upgrade pg2 to pg1.
2856 static void
2857 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2858 int new)
2860 property_t *p1, *p2;
2862 assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2864 if (!pg_attrs_equal(pg1, pg2, fmri, new))
2865 return;
2867 for (p1 = uu_list_first(pg1->sc_pgroup_props);
2868 p1 != NULL;
2869 p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2870 p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2871 if (p2 != NULL) {
2872 (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2873 new);
2874 continue;
2877 if (new)
2878 warn(gettext("Conflict upgrading %s (new property "
2879 "group \"%s\" is missing property \"%s\").\n"),
2880 fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2881 else
2882 warn(gettext("Conflict upgrading %s (property "
2883 "\"%s/%s\" is missing).\n"), fmri,
2884 pg1->sc_pgroup_name, p1->sc_property_name);
2888 * Since pg1 should be from the manifest, any properties in pg2 which
2889 * aren't in pg1 shouldn't be reported as conflicts.
2894 * Add transaction entries to tx which will upgrade cur's pg according to old
2895 * & new.
2897 * Returns
2898 * 0 - success
2899 * EINVAL - new has a property with an invalid name or value (message emitted)
2900 * ENOMEM - out of memory
2902 static int
2903 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2904 pgroup_t *cur, int speak, const char *fmri)
2906 property_t *p, *new_p, *cur_p;
2907 scf_transaction_entry_t *e;
2908 int r;
2909 int is_general;
2910 int is_protected;
2912 if (uu_list_walk(new->sc_pgroup_props, clear_int,
2913 (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2914 bad_error("uu_list_walk", uu_error());
2916 is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2918 for (p = uu_list_first(old->sc_pgroup_props);
2919 p != NULL;
2920 p = uu_list_next(old->sc_pgroup_props, p)) {
2921 /* p is a property in the old property group. */
2923 /* Protect live properties. */
2924 is_protected = 0;
2925 if (is_general) {
2926 if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2927 0 ||
2928 strcmp(p->sc_property_name,
2929 SCF_PROPERTY_RESTARTER) == 0)
2930 is_protected = 1;
2933 /* Look for the same property in the new properties. */
2934 new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2935 if (new_p != NULL) {
2936 new_p->sc_seen = 1;
2939 * If the new property is the same as the old, don't do
2940 * anything (leave any user customizations).
2942 if (prop_equal(p, new_p, NULL, NULL, 0))
2943 continue;
2945 if (new_p->sc_property_override)
2946 goto upgrade;
2949 cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2950 if (cur_p == NULL) {
2952 * p has been deleted from the repository. If we were
2953 * going to delete it anyway, do nothing. Otherwise
2954 * report a conflict.
2956 if (new_p == NULL)
2957 continue;
2959 if (is_protected)
2960 continue;
2962 warn(gettext("Conflict upgrading %s "
2963 "(property \"%s/%s\" is missing).\n"), fmri,
2964 old->sc_pgroup_name, p->sc_property_name);
2965 continue;
2968 if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2970 * Conflict. Don't warn if the property is already the
2971 * way we want it, though.
2973 if (is_protected)
2974 continue;
2976 if (new_p == NULL)
2977 (void) prop_equal(p, cur_p, fmri,
2978 old->sc_pgroup_name, 0);
2979 else
2980 (void) prop_equal(cur_p, new_p, fmri,
2981 old->sc_pgroup_name, 0);
2982 continue;
2985 if (is_protected) {
2986 if (speak)
2987 warn(gettext("%s: Refusing to upgrade "
2988 "\"%s/%s\" (live property).\n"), fmri,
2989 old->sc_pgroup_name, p->sc_property_name);
2990 continue;
2993 upgrade:
2994 /* p hasn't been customized in the repository. Upgrade it. */
2995 if (new_p == NULL) {
2996 /* p was deleted. Delete from cur if unchanged. */
2997 if (speak)
2998 warn(gettext(
2999 "%s: Deleting property \"%s/%s\".\n"),
3000 fmri, old->sc_pgroup_name,
3001 p->sc_property_name);
3003 e = scf_entry_create(g_hndl);
3004 if (e == NULL)
3005 return (ENOMEM);
3007 if (scf_transaction_property_delete(tx, e,
3008 p->sc_property_name) != 0) {
3009 switch (scf_error()) {
3010 case SCF_ERROR_DELETED:
3011 scf_entry_destroy(e);
3012 return (ECANCELED);
3014 case SCF_ERROR_CONNECTION_BROKEN:
3015 scf_entry_destroy(e);
3016 return (ECONNABORTED);
3018 case SCF_ERROR_NOT_FOUND:
3020 * This can happen if cur is from the
3021 * running snapshot (and it differs
3022 * from the live properties).
3024 scf_entry_destroy(e);
3025 break;
3027 case SCF_ERROR_HANDLE_MISMATCH:
3028 case SCF_ERROR_NOT_BOUND:
3029 case SCF_ERROR_NOT_SET:
3030 case SCF_ERROR_INVALID_ARGUMENT:
3031 default:
3032 bad_error(
3033 "scf_transaction_property_delete",
3034 scf_error());
3037 } else {
3038 scf_callback_t ctx;
3040 if (speak)
3041 warn(gettext(
3042 "%s: Upgrading property \"%s/%s\".\n"),
3043 fmri, old->sc_pgroup_name,
3044 p->sc_property_name);
3046 ctx.sc_handle = g_hndl;
3047 ctx.sc_trans = tx;
3048 ctx.sc_flags = 0;
3050 r = lscf_property_import(new_p, &ctx);
3051 if (r != UU_WALK_NEXT) {
3052 if (r != UU_WALK_ERROR)
3053 bad_error("lscf_property_import", r);
3054 return (EINVAL);
3059 /* Go over the properties which were added. */
3060 for (new_p = uu_list_first(new->sc_pgroup_props);
3061 new_p != NULL;
3062 new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
3063 if (new_p->sc_seen)
3064 continue;
3066 /* This is a new property. */
3067 cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
3068 if (cur_p == NULL) {
3069 scf_callback_t ctx;
3071 ctx.sc_handle = g_hndl;
3072 ctx.sc_trans = tx;
3073 ctx.sc_flags = 0;
3075 r = lscf_property_import(new_p, &ctx);
3076 if (r != UU_WALK_NEXT) {
3077 if (r != UU_WALK_ERROR)
3078 bad_error("lscf_property_import", r);
3079 return (EINVAL);
3081 continue;
3085 * Report a conflict if the new property differs from the
3086 * current one. Unless it's general/enabled, since that's
3087 * never in the last-import snapshot.
3089 if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
3090 0 &&
3091 strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
3092 continue;
3094 (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
3097 return (0);
3101 * Upgrade pg according to old & new.
3103 * Returns
3104 * 0 - success
3105 * ECONNABORTED - repository connection broken
3106 * ENOMEM - out of memory
3107 * ENOSPC - svc.configd is out of resources
3108 * ECANCELED - pg was deleted
3109 * EPERM - couldn't modify pg (permission denied)
3110 * EROFS - couldn't modify pg (backend read-only)
3111 * EACCES - couldn't modify pg (backend access denied)
3112 * EINVAL - new has a property with invalid name or value (error printed)
3113 * EBUSY - pg changed unexpectedly
3115 static int
3116 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
3117 pgroup_t *new, int speak, const char *fmri)
3119 int r;
3121 if (scf_transaction_start(imp_tx, pg) != 0) {
3122 switch (scf_error()) {
3123 case SCF_ERROR_CONNECTION_BROKEN:
3124 case SCF_ERROR_DELETED:
3125 case SCF_ERROR_PERMISSION_DENIED:
3126 case SCF_ERROR_BACKEND_READONLY:
3127 case SCF_ERROR_BACKEND_ACCESS:
3128 return (scferror2errno(scf_error()));
3130 case SCF_ERROR_HANDLE_MISMATCH:
3131 case SCF_ERROR_IN_USE:
3132 case SCF_ERROR_NOT_BOUND:
3133 case SCF_ERROR_NOT_SET:
3134 default:
3135 bad_error("scf_transaction_start", scf_error());
3139 r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
3140 switch (r) {
3141 case 0:
3142 break;
3144 case EINVAL:
3145 case ENOMEM:
3146 scf_transaction_destroy_children(imp_tx);
3147 return (r);
3149 default:
3150 bad_error("add_upgrade_entries", r);
3153 r = scf_transaction_commit(imp_tx);
3155 scf_transaction_destroy_children(imp_tx);
3157 switch (r) {
3158 case 1:
3159 break;
3161 case 0:
3162 return (EBUSY);
3164 case -1:
3165 switch (scf_error()) {
3166 case SCF_ERROR_CONNECTION_BROKEN:
3167 case SCF_ERROR_NO_RESOURCES:
3168 case SCF_ERROR_PERMISSION_DENIED:
3169 case SCF_ERROR_BACKEND_READONLY:
3170 case SCF_ERROR_BACKEND_ACCESS:
3171 case SCF_ERROR_DELETED:
3172 return (scferror2errno(scf_error()));
3174 case SCF_ERROR_NOT_BOUND:
3175 case SCF_ERROR_INVALID_ARGUMENT:
3176 case SCF_ERROR_NOT_SET:
3177 default:
3178 bad_error("scf_transaction_commit", scf_error());
3181 default:
3182 bad_error("scf_transaction_commit", r);
3185 return (0);
3189 * Compares two entity FMRIs. Returns
3191 * 1 - equal
3192 * 0 - not equal
3193 * -1 - f1 is invalid or not an entity
3194 * -2 - f2 is invalid or not an entity
3196 static int
3197 fmri_equal(const char *f1, const char *f2)
3199 int r;
3200 const char *s1, *i1, *pg1;
3201 const char *s2, *i2, *pg2;
3203 if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3204 return (-1);
3205 if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
3206 return (-1);
3208 if (s1 == NULL || pg1 != NULL)
3209 return (-1);
3211 if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3212 return (-2);
3213 if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
3214 return (-2);
3216 if (s2 == NULL || pg2 != NULL)
3217 return (-2);
3219 r = strcmp(s1, s2);
3220 if (r != 0)
3221 return (0);
3223 if (i1 == NULL && i2 == NULL)
3224 return (1);
3226 if (i1 == NULL || i2 == NULL)
3227 return (0);
3229 return (strcmp(i1, i2) == 0);
3233 * Import a dependent by creating a dependency property group in the dependent
3234 * entity. If lcbdata->sc_trans is set, assume it's been started on the
3235 * dependents pg, and add an entry to create a new property for this
3236 * dependent. Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3238 * On success, returns UU_WALK_NEXT. On error, returns UU_WALK_ERROR and sets
3239 * lcbdata->sc_err to
3240 * ECONNABORTED - repository connection broken
3241 * ENOMEM - out of memory
3242 * ENOSPC - configd is out of resources
3243 * EINVAL - target is invalid (error printed)
3244 * - target is not an entity (error printed)
3245 * - dependent has invalid name (error printed)
3246 * - invalid property name (error printed)
3247 * - invalid value (error printed)
3248 * - scope of target does not exist (error printed)
3249 * EPERM - couldn't create target (permission denied) (error printed)
3250 * - couldn't create dependency pg (permission denied) (error printed)
3251 * - couldn't modify dependency pg (permission denied) (error printed)
3252 * EROFS - couldn't create target (repository read-only)
3253 * - couldn't create dependency pg (repository read-only)
3254 * EACCES - couldn't create target (backend access denied)
3255 * - couldn't create dependency pg (backend access denied)
3256 * ECANCELED - sc_trans's pg was deleted
3257 * EALREADY - property for dependent already exists in sc_trans's pg
3258 * EEXIST - dependency pg already exists in target (error printed)
3259 * EBUSY - target deleted (error printed)
3260 * - property group changed during import (error printed)
3262 static int
3263 lscf_dependent_import(void *a1, void *pvt)
3265 pgroup_t *pgrp = a1;
3266 scf_callback_t *lcbdata = pvt;
3268 int isservice;
3269 int ret;
3270 scf_transaction_entry_t *e;
3271 scf_value_t *val;
3272 scf_callback_t dependent_cbdata;
3273 scf_error_t scfe;
3276 * Decode the FMRI into dependent_cbdata->sc_parent. Do it here so if
3277 * it's invalid, we fail before modifying the repository.
3279 scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3280 &dependent_cbdata.sc_parent, &isservice);
3281 switch (scfe) {
3282 case SCF_ERROR_NONE:
3283 break;
3285 case SCF_ERROR_NO_MEMORY:
3286 return (stash_scferror_err(lcbdata, scfe));
3288 case SCF_ERROR_INVALID_ARGUMENT:
3289 semerr(gettext("The FMRI for the \"%s\" dependent is "
3290 "invalid.\n"), pgrp->sc_pgroup_name);
3291 return (stash_scferror_err(lcbdata, scfe));
3293 case SCF_ERROR_CONSTRAINT_VIOLATED:
3294 semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3295 "specifies neither a service nor an instance.\n"),
3296 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3297 return (stash_scferror_err(lcbdata, scfe));
3299 case SCF_ERROR_NOT_FOUND:
3300 scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3301 &dependent_cbdata.sc_parent, &isservice);
3302 switch (scfe) {
3303 case SCF_ERROR_NONE:
3304 break;
3306 case SCF_ERROR_NO_MEMORY:
3307 case SCF_ERROR_BACKEND_READONLY:
3308 case SCF_ERROR_BACKEND_ACCESS:
3309 return (stash_scferror_err(lcbdata, scfe));
3311 case SCF_ERROR_NOT_FOUND:
3312 semerr(gettext("The scope in FMRI \"%s\" for the "
3313 "\"%s\" dependent does not exist.\n"),
3314 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3315 lcbdata->sc_err = EINVAL;
3316 return (UU_WALK_ERROR);
3318 case SCF_ERROR_PERMISSION_DENIED:
3319 warn(gettext(
3320 "Could not create %s (permission denied).\n"),
3321 pgrp->sc_pgroup_fmri);
3322 return (stash_scferror_err(lcbdata, scfe));
3324 case SCF_ERROR_INVALID_ARGUMENT:
3325 case SCF_ERROR_CONSTRAINT_VIOLATED:
3326 default:
3327 bad_error("create_entity", scfe);
3329 break;
3331 default:
3332 bad_error("fmri_to_entity", scfe);
3335 if (lcbdata->sc_trans != NULL) {
3336 e = scf_entry_create(lcbdata->sc_handle);
3337 if (e == NULL) {
3338 if (scf_error() != SCF_ERROR_NO_MEMORY)
3339 bad_error("scf_entry_create", scf_error());
3341 entity_destroy(dependent_cbdata.sc_parent, isservice);
3342 return (stash_scferror(lcbdata));
3345 if (scf_transaction_property_new(lcbdata->sc_trans, e,
3346 pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
3347 switch (scf_error()) {
3348 case SCF_ERROR_INVALID_ARGUMENT:
3349 warn(gettext("Dependent of %s has invalid name "
3350 "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
3351 pgrp->sc_pgroup_name);
3352 /* FALLTHROUGH */
3354 case SCF_ERROR_DELETED:
3355 case SCF_ERROR_CONNECTION_BROKEN:
3356 scf_entry_destroy(e);
3357 entity_destroy(dependent_cbdata.sc_parent,
3358 isservice);
3359 return (stash_scferror(lcbdata));
3361 case SCF_ERROR_EXISTS:
3362 scf_entry_destroy(e);
3363 entity_destroy(dependent_cbdata.sc_parent,
3364 isservice);
3365 lcbdata->sc_err = EALREADY;
3366 return (UU_WALK_ERROR);
3368 case SCF_ERROR_NOT_BOUND:
3369 case SCF_ERROR_HANDLE_MISMATCH:
3370 case SCF_ERROR_NOT_SET:
3371 default:
3372 bad_error("scf_transaction_property_new",
3373 scf_error());
3377 val = scf_value_create(lcbdata->sc_handle);
3378 if (val == NULL) {
3379 if (scf_error() != SCF_ERROR_NO_MEMORY)
3380 bad_error("scf_value_create", scf_error());
3382 entity_destroy(dependent_cbdata.sc_parent, isservice);
3383 return (stash_scferror(lcbdata));
3386 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
3387 pgrp->sc_pgroup_fmri) != 0)
3388 /* invalid should have been caught above */
3389 bad_error("scf_value_set_from_string", scf_error());
3391 if (scf_entry_add_value(e, val) != 0)
3392 bad_error("scf_entry_add_value", scf_error());
3395 /* Add the property group to the target entity. */
3397 dependent_cbdata.sc_handle = lcbdata->sc_handle;
3398 dependent_cbdata.sc_flags = lcbdata->sc_flags;
3399 dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
3400 dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
3402 ret = entity_pgroup_import(pgrp, &dependent_cbdata);
3404 entity_destroy(dependent_cbdata.sc_parent, isservice);
3406 if (ret == UU_WALK_NEXT)
3407 return (ret);
3409 if (ret != UU_WALK_ERROR)
3410 bad_error("entity_pgroup_import", ret);
3412 switch (dependent_cbdata.sc_err) {
3413 case ECANCELED:
3414 warn(gettext("%s deleted unexpectedly.\n"),
3415 pgrp->sc_pgroup_fmri);
3416 lcbdata->sc_err = EBUSY;
3417 break;
3419 case EEXIST:
3420 warn(gettext("Could not create \"%s\" dependency in %s "
3421 "(already exists).\n"), pgrp->sc_pgroup_name,
3422 pgrp->sc_pgroup_fmri);
3423 /* FALLTHROUGH */
3425 default:
3426 lcbdata->sc_err = dependent_cbdata.sc_err;
3429 return (UU_WALK_ERROR);
3432 static int upgrade_dependent(const scf_property_t *, const entity_t *,
3433 const scf_snaplevel_t *, scf_transaction_t *);
3434 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
3435 const pgroup_t *);
3438 * Upgrade uncustomized dependents of ent to those specified in ient. Read
3439 * the current dependent targets from running (the snaplevel of a running
3440 * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3441 * scf_instance_t * according to ient, otherwise). Draw the ancestral
3442 * dependent targets and dependency properties from li_dpts_pg (the
3443 * "dependents" property group in snpl) and snpl (the snaplevel which
3444 * corresponds to ent in a last-import snapshot). If li_dpts_pg is NULL, then
3445 * snpl doesn't have a "dependents" property group, and any dependents in ient
3446 * are new.
3448 * Returns
3449 * 0 - success
3450 * ECONNABORTED - repository connection broken
3451 * ENOMEM - out of memory
3452 * ENOSPC - configd is out of resources
3453 * ECANCELED - ent was deleted
3454 * ENODEV - the entity containing li_dpts_pg was deleted
3455 * EPERM - could not modify dependents pg (permission denied) (error printed)
3456 * - couldn't upgrade dependent (permission denied) (error printed)
3457 * - couldn't create dependent (permission denied) (error printed)
3458 * EROFS - could not modify dependents pg (repository read-only)
3459 * - couldn't upgrade dependent (repository read-only)
3460 * - couldn't create dependent (repository read-only)
3461 * EACCES - could not modify dependents pg (backend access denied)
3462 * - could not upgrade dependent (backend access denied)
3463 * - could not create dependent (backend access denied)
3464 * EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3465 * - dependent target deleted (error printed)
3466 * - dependent pg changed (error printed)
3467 * EINVAL - new dependent is invalid (error printed)
3468 * EBADF - snpl is corrupt (error printed)
3469 * - snpl has corrupt pg (error printed)
3470 * - dependency pg in target is corrupt (error printed)
3471 * - target has corrupt snapshot (error printed)
3472 * EEXIST - dependency pg already existed in target service (error printed)
3474 static int
3475 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
3476 const scf_snaplevel_t *snpl, const entity_t *ient,
3477 const scf_snaplevel_t *running, void *ent)
3479 pgroup_t *new_dpt_pgroup;
3480 scf_callback_t cbdata;
3481 int r, unseen, tx_started = 0;
3482 int have_cur_depts;
3484 const char * const dependents = "dependents";
3486 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3488 if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
3489 /* Nothing to do. */
3490 return (0);
3492 /* Fetch the current version of the "dependents" property group. */
3493 have_cur_depts = 1;
3494 if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
3495 switch (scf_error()) {
3496 case SCF_ERROR_NOT_FOUND:
3497 break;
3499 case SCF_ERROR_DELETED:
3500 case SCF_ERROR_CONNECTION_BROKEN:
3501 return (scferror2errno(scf_error()));
3503 case SCF_ERROR_NOT_SET:
3504 case SCF_ERROR_INVALID_ARGUMENT:
3505 case SCF_ERROR_HANDLE_MISMATCH:
3506 case SCF_ERROR_NOT_BOUND:
3507 default:
3508 bad_error("entity_get_pg", scf_error());
3511 have_cur_depts = 0;
3514 /* Fetch the running version of the "dependents" property group. */
3515 ud_run_dpts_pg_set = 0;
3516 if (running != NULL)
3517 r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
3518 else
3519 r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
3520 if (r == 0) {
3521 ud_run_dpts_pg_set = 1;
3522 } else {
3523 switch (scf_error()) {
3524 case SCF_ERROR_NOT_FOUND:
3525 break;
3527 case SCF_ERROR_DELETED:
3528 case SCF_ERROR_CONNECTION_BROKEN:
3529 return (scferror2errno(scf_error()));
3531 case SCF_ERROR_NOT_SET:
3532 case SCF_ERROR_INVALID_ARGUMENT:
3533 case SCF_ERROR_HANDLE_MISMATCH:
3534 case SCF_ERROR_NOT_BOUND:
3535 default:
3536 bad_error(running ? "scf_snaplevel_get_pg" :
3537 "entity_get_pg", scf_error());
3542 * Clear the seen fields of the dependents, so we can tell which ones
3543 * are new.
3545 if (uu_list_walk(ient->sc_dependents, clear_int,
3546 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3547 bad_error("uu_list_walk", uu_error());
3549 if (li_dpts_pg != NULL) {
3551 * Each property in li_dpts_pg represents a dependent tag in
3552 * the old manifest. For each, call upgrade_dependent(),
3553 * which will change ud_cur_depts_pg or dependencies in other
3554 * services as appropriate. Note (a) that changes to
3555 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3556 * made en masse, and (b) it's ok if the entity doesn't have
3557 * a current version of the "dependents" property group,
3558 * because we'll just consider all dependents as customized
3559 * (by being deleted).
3562 if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3563 switch (scf_error()) {
3564 case SCF_ERROR_DELETED:
3565 return (ENODEV);
3567 case SCF_ERROR_CONNECTION_BROKEN:
3568 return (ECONNABORTED);
3570 case SCF_ERROR_HANDLE_MISMATCH:
3571 case SCF_ERROR_NOT_BOUND:
3572 case SCF_ERROR_NOT_SET:
3573 default:
3574 bad_error("scf_iter_pg_properties",
3575 scf_error());
3579 if (have_cur_depts &&
3580 scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3581 switch (scf_error()) {
3582 case SCF_ERROR_BACKEND_ACCESS:
3583 case SCF_ERROR_BACKEND_READONLY:
3584 case SCF_ERROR_CONNECTION_BROKEN:
3585 return (scferror2errno(scf_error()));
3587 case SCF_ERROR_DELETED:
3588 warn(emsg_pg_deleted, ient->sc_fmri,
3589 dependents);
3590 return (EBUSY);
3592 case SCF_ERROR_PERMISSION_DENIED:
3593 warn(emsg_pg_mod_perm, dependents,
3594 ient->sc_fmri);
3595 return (scferror2errno(scf_error()));
3597 case SCF_ERROR_HANDLE_MISMATCH:
3598 case SCF_ERROR_IN_USE:
3599 case SCF_ERROR_NOT_BOUND:
3600 case SCF_ERROR_NOT_SET:
3601 default:
3602 bad_error("scf_transaction_start", scf_error());
3605 tx_started = have_cur_depts;
3607 for (;;) {
3608 r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3609 if (r == 0)
3610 break;
3611 if (r == 1) {
3612 r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3613 tx_started ? ud_tx : NULL);
3614 switch (r) {
3615 case 0:
3616 continue;
3618 case ECONNABORTED:
3619 case ENOMEM:
3620 case ENOSPC:
3621 case EBADF:
3622 case EBUSY:
3623 case EINVAL:
3624 case EPERM:
3625 case EROFS:
3626 case EACCES:
3627 case EEXIST:
3628 break;
3630 case ECANCELED:
3631 r = ENODEV;
3632 break;
3634 default:
3635 bad_error("upgrade_dependent", r);
3638 if (tx_started)
3639 scf_transaction_destroy_children(ud_tx);
3640 return (r);
3642 if (r != -1)
3643 bad_error("scf_iter_next_property", r);
3645 switch (scf_error()) {
3646 case SCF_ERROR_DELETED:
3647 r = ENODEV;
3648 break;
3650 case SCF_ERROR_CONNECTION_BROKEN:
3651 r = ECONNABORTED;
3652 break;
3654 case SCF_ERROR_NOT_SET:
3655 case SCF_ERROR_INVALID_ARGUMENT:
3656 case SCF_ERROR_NOT_BOUND:
3657 case SCF_ERROR_HANDLE_MISMATCH:
3658 default:
3659 bad_error("scf_iter_next_property",
3660 scf_error());
3663 if (tx_started)
3664 scf_transaction_destroy_children(ud_tx);
3665 return (r);
3669 /* import unseen dependents */
3670 unseen = 0;
3671 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3672 new_dpt_pgroup != NULL;
3673 new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3674 new_dpt_pgroup)) {
3675 if (!new_dpt_pgroup->sc_pgroup_seen) {
3676 unseen = 1;
3677 break;
3681 /* If there are none, exit early. */
3682 if (unseen == 0)
3683 goto commit;
3685 /* Set up for lscf_dependent_import() */
3686 cbdata.sc_handle = g_hndl;
3687 cbdata.sc_parent = ent;
3688 cbdata.sc_service = issvc;
3689 cbdata.sc_flags = 0;
3691 if (!have_cur_depts) {
3693 * We have new dependents to import, so we need a "dependents"
3694 * property group.
3696 if (issvc)
3697 r = scf_service_add_pg(ent, dependents,
3698 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3699 else
3700 r = scf_instance_add_pg(ent, dependents,
3701 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3702 if (r != 0) {
3703 switch (scf_error()) {
3704 case SCF_ERROR_DELETED:
3705 case SCF_ERROR_CONNECTION_BROKEN:
3706 case SCF_ERROR_BACKEND_READONLY:
3707 case SCF_ERROR_BACKEND_ACCESS:
3708 case SCF_ERROR_NO_RESOURCES:
3709 return (scferror2errno(scf_error()));
3711 case SCF_ERROR_EXISTS:
3712 warn(emsg_pg_added, ient->sc_fmri, dependents);
3713 return (EBUSY);
3715 case SCF_ERROR_PERMISSION_DENIED:
3716 warn(emsg_pg_add_perm, dependents,
3717 ient->sc_fmri);
3718 return (scferror2errno(scf_error()));
3720 case SCF_ERROR_NOT_BOUND:
3721 case SCF_ERROR_HANDLE_MISMATCH:
3722 case SCF_ERROR_INVALID_ARGUMENT:
3723 case SCF_ERROR_NOT_SET:
3724 default:
3725 bad_error("scf_service_add_pg", scf_error());
3730 cbdata.sc_trans = ud_tx;
3732 if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3733 switch (scf_error()) {
3734 case SCF_ERROR_CONNECTION_BROKEN:
3735 case SCF_ERROR_BACKEND_ACCESS:
3736 case SCF_ERROR_BACKEND_READONLY:
3737 return (scferror2errno(scf_error()));
3739 case SCF_ERROR_DELETED:
3740 warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3741 return (EBUSY);
3743 case SCF_ERROR_PERMISSION_DENIED:
3744 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3745 return (scferror2errno(scf_error()));
3747 case SCF_ERROR_HANDLE_MISMATCH:
3748 case SCF_ERROR_IN_USE:
3749 case SCF_ERROR_NOT_BOUND:
3750 case SCF_ERROR_NOT_SET:
3751 default:
3752 bad_error("scf_transaction_start", scf_error());
3755 tx_started = 1;
3757 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3758 new_dpt_pgroup != NULL;
3759 new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3760 new_dpt_pgroup)) {
3761 if (new_dpt_pgroup->sc_pgroup_seen)
3762 continue;
3764 if (ud_run_dpts_pg_set) {
3766 * If the dependent is already there, then we have
3767 * a conflict.
3769 if (scf_pg_get_property(ud_run_dpts_pg,
3770 new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3771 r = handle_dependent_conflict(ient, ud_prop,
3772 new_dpt_pgroup);
3773 switch (r) {
3774 case 0:
3775 continue;
3777 case ECONNABORTED:
3778 case ENOMEM:
3779 case EBUSY:
3780 case EBADF:
3781 case EINVAL:
3782 scf_transaction_destroy_children(ud_tx);
3783 return (r);
3785 default:
3786 bad_error("handle_dependent_conflict",
3789 } else {
3790 switch (scf_error()) {
3791 case SCF_ERROR_NOT_FOUND:
3792 break;
3794 case SCF_ERROR_INVALID_ARGUMENT:
3795 warn(emsg_fmri_invalid_pg_name,
3796 ient->sc_fmri,
3797 new_dpt_pgroup->sc_pgroup_name);
3798 scf_transaction_destroy_children(ud_tx);
3799 return (EINVAL);
3801 case SCF_ERROR_DELETED:
3802 warn(emsg_pg_deleted, ient->sc_fmri,
3803 new_dpt_pgroup->sc_pgroup_name);
3804 scf_transaction_destroy_children(ud_tx);
3805 return (EBUSY);
3807 case SCF_ERROR_CONNECTION_BROKEN:
3808 scf_transaction_destroy_children(ud_tx);
3809 return (ECONNABORTED);
3811 case SCF_ERROR_NOT_BOUND:
3812 case SCF_ERROR_HANDLE_MISMATCH:
3813 case SCF_ERROR_NOT_SET:
3814 default:
3815 bad_error("scf_pg_get_property",
3816 scf_error());
3821 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3822 if (r != UU_WALK_NEXT) {
3823 if (r != UU_WALK_ERROR)
3824 bad_error("lscf_dependent_import", r);
3826 if (cbdata.sc_err == EALREADY) {
3827 /* Collisions were handled preemptively. */
3828 bad_error("lscf_dependent_import",
3829 cbdata.sc_err);
3832 scf_transaction_destroy_children(ud_tx);
3833 return (cbdata.sc_err);
3837 commit:
3838 if (!tx_started)
3839 return (0);
3841 r = scf_transaction_commit(ud_tx);
3843 scf_transaction_destroy_children(ud_tx);
3845 switch (r) {
3846 case 1:
3847 return (0);
3849 case 0:
3850 warn(emsg_pg_changed, ient->sc_fmri, dependents);
3851 return (EBUSY);
3853 case -1:
3854 break;
3856 default:
3857 bad_error("scf_transaction_commit", r);
3860 switch (scf_error()) {
3861 case SCF_ERROR_CONNECTION_BROKEN:
3862 case SCF_ERROR_BACKEND_READONLY:
3863 case SCF_ERROR_BACKEND_ACCESS:
3864 case SCF_ERROR_NO_RESOURCES:
3865 return (scferror2errno(scf_error()));
3867 case SCF_ERROR_DELETED:
3868 warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3869 return (EBUSY);
3871 case SCF_ERROR_PERMISSION_DENIED:
3872 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3873 return (scferror2errno(scf_error()));
3875 case SCF_ERROR_NOT_BOUND:
3876 case SCF_ERROR_INVALID_ARGUMENT:
3877 case SCF_ERROR_NOT_SET:
3878 default:
3879 bad_error("scf_transaction_destroy", scf_error());
3880 /* NOTREACHED */
3885 * Used to add the manifests to the list of currently supported manifests.
3886 * We can modify the existing manifest list removing entries if the files
3887 * don't exist.
3889 * Get the old list and the new file name
3890 * If the new file name is in the list return
3891 * If not then add the file to the list.
3892 * As we process the list check to see if the files in the old list exist
3893 * if not then remove the file from the list.
3894 * Commit the list of manifest file names.
3897 static int
3898 upgrade_manifestfiles(pgroup_t *pg, const entity_t *ient,
3899 const scf_snaplevel_t *running, void *ent)
3901 scf_propertygroup_t *ud_mfsts_pg = NULL;
3902 scf_property_t *ud_prop = NULL;
3903 scf_iter_t *ud_prop_iter;
3904 scf_value_t *fname_value;
3905 scf_callback_t cbdata;
3906 pgroup_t *mfst_pgroup;
3907 property_t *mfst_prop;
3908 property_t *old_prop;
3909 char *pname;
3910 char *fval;
3911 char *old_pname;
3912 char *old_fval;
3913 int no_upgrade_pg;
3914 int mfst_seen;
3915 int r;
3917 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3920 * This should always be the service base on the code
3921 * path, and the fact that the manifests pg is a service
3922 * level property group only.
3924 ud_mfsts_pg = scf_pg_create(g_hndl);
3925 ud_prop = scf_property_create(g_hndl);
3926 ud_prop_iter = scf_iter_create(g_hndl);
3927 fname_value = scf_value_create(g_hndl);
3929 /* Fetch the "manifests" property group */
3930 no_upgrade_pg = 0;
3931 r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3932 ud_mfsts_pg);
3933 if (r != 0) {
3934 switch (scf_error()) {
3935 case SCF_ERROR_NOT_FOUND:
3936 no_upgrade_pg = 1;
3937 break;
3939 case SCF_ERROR_DELETED:
3940 case SCF_ERROR_CONNECTION_BROKEN:
3941 return (scferror2errno(scf_error()));
3943 case SCF_ERROR_NOT_SET:
3944 case SCF_ERROR_INVALID_ARGUMENT:
3945 case SCF_ERROR_HANDLE_MISMATCH:
3946 case SCF_ERROR_NOT_BOUND:
3947 default:
3948 bad_error(running ? "scf_snaplevel_get_pg" :
3949 "entity_get_pg", scf_error());
3953 if (no_upgrade_pg) {
3954 cbdata.sc_handle = g_hndl;
3955 cbdata.sc_parent = ent;
3956 cbdata.sc_service = issvc;
3957 cbdata.sc_flags = SCI_FORCE;
3958 cbdata.sc_source_fmri = ient->sc_fmri;
3959 cbdata.sc_target_fmri = ient->sc_fmri;
3961 if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3962 return (cbdata.sc_err);
3964 return (0);
3967 /* Fetch the new manifests property group */
3968 for (mfst_pgroup = uu_list_first(ient->sc_pgroups);
3969 mfst_pgroup != NULL;
3970 mfst_pgroup = uu_list_next(ient->sc_pgroups, mfst_pgroup)) {
3971 if (strcmp(mfst_pgroup->sc_pgroup_name,
3972 SCF_PG_MANIFESTFILES) == 0)
3973 break;
3976 if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3977 SCF_SUCCESS)
3978 return (-1);
3980 if ((pname = malloc(MAXPATHLEN)) == NULL)
3981 return (ENOMEM);
3982 if ((fval = malloc(MAXPATHLEN)) == NULL) {
3983 free(pname);
3984 return (ENOMEM);
3987 while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
3988 mfst_seen = 0;
3989 if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
3990 continue;
3992 for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
3993 mfst_prop != NULL;
3994 mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
3995 mfst_prop)) {
3996 if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
3997 mfst_seen = 1;
4002 * If the manifest is not seen then add it to the new mfst
4003 * property list to get proccessed into the repo.
4005 if (mfst_seen == 0) {
4007 * If we cannot get the value then there is no
4008 * reason to attempt to attach the value to
4009 * the property group
4011 if (prop_get_val(ud_prop, fname_value) == 0 &&
4012 scf_value_get_astring(fname_value, fval,
4013 MAXPATHLEN) != -1) {
4014 old_pname = safe_strdup(pname);
4015 old_fval = safe_strdup(fval);
4016 old_prop = internal_property_create(old_pname,
4017 SCF_TYPE_ASTRING, 1, old_fval);
4020 * Already checked to see if the property exists
4021 * in the group, and it does not.
4023 (void) internal_attach_property(mfst_pgroup,
4024 old_prop);
4028 free(pname);
4029 free(fval);
4031 cbdata.sc_handle = g_hndl;
4032 cbdata.sc_parent = ent;
4033 cbdata.sc_service = issvc;
4034 cbdata.sc_flags = SCI_FORCE;
4035 cbdata.sc_source_fmri = ient->sc_fmri;
4036 cbdata.sc_target_fmri = ient->sc_fmri;
4038 if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
4039 return (cbdata.sc_err);
4041 return (r);
4045 * prop is taken to be a property in the "dependents" property group of snpl,
4046 * which is taken to be the snaplevel of a last-import snapshot corresponding
4047 * to ient. If prop is a valid dependents property, upgrade the dependent it
4048 * represents according to the repository & ient. If ud_run_dpts_pg_set is
4049 * true, then ud_run_dpts_pg is taken to be the "dependents" property group
4050 * of the entity ient represents (possibly in the running snapshot). If it
4051 * needs to be changed, an entry will be added to tx, if not NULL.
4053 * Returns
4054 * 0 - success
4055 * ECONNABORTED - repository connection broken
4056 * ENOMEM - out of memory
4057 * ENOSPC - configd was out of resources
4058 * ECANCELED - snpl's entity was deleted
4059 * EINVAL - dependent target is invalid (error printed)
4060 * - dependent is invalid (error printed)
4061 * EBADF - snpl is corrupt (error printed)
4062 * - snpl has corrupt pg (error printed)
4063 * - dependency pg in target is corrupt (error printed)
4064 * - running snapshot in dependent is missing snaplevel (error printed)
4065 * EPERM - couldn't delete dependency pg (permission denied) (error printed)
4066 * - couldn't create dependent (permission denied) (error printed)
4067 * - couldn't modify dependent pg (permission denied) (error printed)
4068 * EROFS - couldn't delete dependency pg (repository read-only)
4069 * - couldn't create dependent (repository read-only)
4070 * EACCES - couldn't delete dependency pg (backend access denied)
4071 * - couldn't create dependent (backend access denied)
4072 * EBUSY - ud_run_dpts_pg was deleted (error printed)
4073 * - tx's pg was deleted (error printed)
4074 * - dependent pg was changed or deleted (error printed)
4075 * EEXIST - dependency pg already exists in new target (error printed)
4077 static int
4078 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
4079 const scf_snaplevel_t *snpl, scf_transaction_t *tx)
4081 pgroup_t pgrp;
4082 scf_type_t ty;
4083 pgroup_t *new_dpt_pgroup;
4084 pgroup_t *old_dpt_pgroup = NULL;
4085 pgroup_t *current_pg;
4086 pgroup_t *dpt;
4087 scf_callback_t cbdata;
4088 int tissvc;
4089 void *target_ent;
4090 scf_error_t serr;
4091 int r;
4092 scf_transaction_entry_t *ent;
4094 const char * const cf_inval = gettext("Conflict upgrading %s "
4095 "(dependent \"%s\" has invalid dependents property).\n");
4096 const char * const cf_missing = gettext("Conflict upgrading %s "
4097 "(dependent \"%s\" is missing).\n");
4098 const char * const cf_newdpg = gettext("Conflict upgrading %s "
4099 "(dependent \"%s\" has new dependency property group).\n");
4100 const char * const cf_newtarg = gettext("Conflict upgrading %s "
4101 "(dependent \"%s\" has new target).\n");
4102 const char * const li_corrupt =
4103 gettext("%s: \"last-import\" snapshot is corrupt.\n");
4104 const char * const upgrading =
4105 gettext("%s: Upgrading dependent \"%s\".\n");
4106 const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
4107 "corrupt (missing snaplevel).\n");
4109 if (scf_property_type(prop, &ty) != 0) {
4110 switch (scf_error()) {
4111 case SCF_ERROR_DELETED:
4112 case SCF_ERROR_CONNECTION_BROKEN:
4113 return (scferror2errno(scf_error()));
4115 case SCF_ERROR_NOT_BOUND:
4116 case SCF_ERROR_NOT_SET:
4117 default:
4118 bad_error("scf_property_type", scf_error());
4122 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4123 warn(li_corrupt, ient->sc_fmri);
4124 return (EBADF);
4128 * prop represents a dependent in the old manifest. It is named after
4129 * the dependent.
4131 if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
4132 switch (scf_error()) {
4133 case SCF_ERROR_DELETED:
4134 case SCF_ERROR_CONNECTION_BROKEN:
4135 return (scferror2errno(scf_error()));
4137 case SCF_ERROR_NOT_BOUND:
4138 case SCF_ERROR_NOT_SET:
4139 default:
4140 bad_error("scf_property_get_name", scf_error());
4144 /* See if it's in the new manifest. */
4145 pgrp.sc_pgroup_name = ud_name;
4146 new_dpt_pgroup =
4147 uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
4149 /* If it's not, delete it... if it hasn't been customized. */
4150 if (new_dpt_pgroup == NULL) {
4151 if (!ud_run_dpts_pg_set)
4152 return (0);
4154 if (scf_property_get_value(prop, ud_val) != 0) {
4155 switch (scf_error()) {
4156 case SCF_ERROR_NOT_FOUND:
4157 case SCF_ERROR_CONSTRAINT_VIOLATED:
4158 warn(li_corrupt, ient->sc_fmri);
4159 return (EBADF);
4161 case SCF_ERROR_DELETED:
4162 case SCF_ERROR_CONNECTION_BROKEN:
4163 return (scferror2errno(scf_error()));
4165 case SCF_ERROR_HANDLE_MISMATCH:
4166 case SCF_ERROR_NOT_BOUND:
4167 case SCF_ERROR_NOT_SET:
4168 case SCF_ERROR_PERMISSION_DENIED:
4169 default:
4170 bad_error("scf_property_get_value",
4171 scf_error());
4175 if (scf_value_get_as_string(ud_val, ud_oldtarg,
4176 max_scf_value_len + 1) < 0)
4177 bad_error("scf_value_get_as_string", scf_error());
4179 if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
4180 0) {
4181 switch (scf_error()) {
4182 case SCF_ERROR_NOT_FOUND:
4183 return (0);
4185 case SCF_ERROR_CONNECTION_BROKEN:
4186 return (scferror2errno(scf_error()));
4188 case SCF_ERROR_DELETED:
4189 warn(emsg_pg_deleted, ient->sc_fmri,
4190 "dependents");
4191 return (EBUSY);
4193 case SCF_ERROR_INVALID_ARGUMENT:
4194 case SCF_ERROR_NOT_BOUND:
4195 case SCF_ERROR_HANDLE_MISMATCH:
4196 case SCF_ERROR_NOT_SET:
4197 default:
4198 bad_error("scf_pg_get_property", scf_error());
4201 if (scf_property_get_value(ud_prop, ud_val) != 0) {
4202 switch (scf_error()) {
4203 case SCF_ERROR_NOT_FOUND:
4204 case SCF_ERROR_CONSTRAINT_VIOLATED:
4205 warn(cf_inval, ient->sc_fmri, ud_name);
4206 return (0);
4208 case SCF_ERROR_DELETED:
4209 case SCF_ERROR_CONNECTION_BROKEN:
4210 return (scferror2errno(scf_error()));
4212 case SCF_ERROR_HANDLE_MISMATCH:
4213 case SCF_ERROR_NOT_BOUND:
4214 case SCF_ERROR_NOT_SET:
4215 case SCF_ERROR_PERMISSION_DENIED:
4216 default:
4217 bad_error("scf_property_get_value",
4218 scf_error());
4222 ty = scf_value_type(ud_val);
4223 assert(ty != SCF_TYPE_INVALID);
4224 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4225 warn(cf_inval, ient->sc_fmri, ud_name);
4226 return (0);
4229 if (scf_value_get_as_string(ud_val, ud_ctarg,
4230 max_scf_value_len + 1) < 0)
4231 bad_error("scf_value_get_as_string", scf_error());
4233 r = fmri_equal(ud_ctarg, ud_oldtarg);
4234 switch (r) {
4235 case 1:
4236 break;
4238 case 0:
4239 case -1: /* warn? */
4240 warn(cf_newtarg, ient->sc_fmri, ud_name);
4241 return (0);
4243 case -2:
4244 warn(li_corrupt, ient->sc_fmri);
4245 return (EBADF);
4247 default:
4248 bad_error("fmri_equal", r);
4251 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4252 switch (scf_error()) {
4253 case SCF_ERROR_NOT_FOUND:
4254 warn(li_corrupt, ient->sc_fmri);
4255 return (EBADF);
4257 case SCF_ERROR_DELETED:
4258 case SCF_ERROR_CONNECTION_BROKEN:
4259 return (scferror2errno(scf_error()));
4261 case SCF_ERROR_NOT_BOUND:
4262 case SCF_ERROR_HANDLE_MISMATCH:
4263 case SCF_ERROR_INVALID_ARGUMENT:
4264 case SCF_ERROR_NOT_SET:
4265 default:
4266 bad_error("scf_snaplevel_get_pg", scf_error());
4270 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4271 snap_lastimport);
4272 switch (r) {
4273 case 0:
4274 break;
4276 case ECANCELED:
4277 case ECONNABORTED:
4278 case ENOMEM:
4279 case EBADF:
4280 return (r);
4282 case EACCES:
4283 default:
4284 bad_error("load_pg", r);
4287 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4288 switch (serr) {
4289 case SCF_ERROR_NONE:
4290 break;
4292 case SCF_ERROR_NO_MEMORY:
4293 internal_pgroup_free(old_dpt_pgroup);
4294 return (ENOMEM);
4296 case SCF_ERROR_NOT_FOUND:
4297 internal_pgroup_free(old_dpt_pgroup);
4298 goto delprop;
4300 case SCF_ERROR_CONSTRAINT_VIOLATED: /* caught above */
4301 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
4302 default:
4303 bad_error("fmri_to_entity", serr);
4306 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4307 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4308 switch (r) {
4309 case 0:
4310 break;
4312 case ECONNABORTED:
4313 internal_pgroup_free(old_dpt_pgroup);
4314 return (r);
4316 case ECANCELED:
4317 case ENOENT:
4318 internal_pgroup_free(old_dpt_pgroup);
4319 goto delprop;
4321 case EBADF:
4322 warn(r_no_lvl, ud_ctarg);
4323 internal_pgroup_free(old_dpt_pgroup);
4324 return (r);
4326 case EINVAL:
4327 default:
4328 bad_error("entity_get_running_pg", r);
4331 /* load it */
4332 r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4333 switch (r) {
4334 case 0:
4335 break;
4337 case ECANCELED:
4338 internal_pgroup_free(old_dpt_pgroup);
4339 goto delprop;
4341 case ECONNABORTED:
4342 case ENOMEM:
4343 case EBADF:
4344 internal_pgroup_free(old_dpt_pgroup);
4345 return (r);
4347 case EACCES:
4348 default:
4349 bad_error("load_pg", r);
4352 /* compare property groups */
4353 if (!pg_equal(old_dpt_pgroup, current_pg)) {
4354 warn(cf_newdpg, ient->sc_fmri, ud_name);
4355 internal_pgroup_free(old_dpt_pgroup);
4356 internal_pgroup_free(current_pg);
4357 return (0);
4360 internal_pgroup_free(old_dpt_pgroup);
4361 internal_pgroup_free(current_pg);
4363 if (g_verbose)
4364 warn(gettext("%s: Deleting dependent \"%s\".\n"),
4365 ient->sc_fmri, ud_name);
4367 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4368 switch (scf_error()) {
4369 case SCF_ERROR_NOT_FOUND:
4370 case SCF_ERROR_DELETED:
4371 internal_pgroup_free(old_dpt_pgroup);
4372 goto delprop;
4374 case SCF_ERROR_CONNECTION_BROKEN:
4375 internal_pgroup_free(old_dpt_pgroup);
4376 return (ECONNABORTED);
4378 case SCF_ERROR_NOT_SET:
4379 case SCF_ERROR_INVALID_ARGUMENT:
4380 case SCF_ERROR_HANDLE_MISMATCH:
4381 case SCF_ERROR_NOT_BOUND:
4382 default:
4383 bad_error("entity_get_pg", scf_error());
4387 if (scf_pg_delete(ud_pg) != 0) {
4388 switch (scf_error()) {
4389 case SCF_ERROR_DELETED:
4390 break;
4392 case SCF_ERROR_CONNECTION_BROKEN:
4393 case SCF_ERROR_BACKEND_READONLY:
4394 case SCF_ERROR_BACKEND_ACCESS:
4395 return (scferror2errno(scf_error()));
4397 case SCF_ERROR_PERMISSION_DENIED:
4398 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4399 return (scferror2errno(scf_error()));
4401 case SCF_ERROR_NOT_SET:
4402 default:
4403 bad_error("scf_pg_delete", scf_error());
4408 * This service was changed, so it must be refreshed. But
4409 * since it's not mentioned in the new manifest, we have to
4410 * record its FMRI here for use later. We record the name
4411 * & the entity (via sc_parent) in case we need to print error
4412 * messages during the refresh.
4414 dpt = internal_pgroup_new();
4415 if (dpt == NULL)
4416 return (ENOMEM);
4417 dpt->sc_pgroup_name = strdup(ud_name);
4418 dpt->sc_pgroup_fmri = strdup(ud_ctarg);
4419 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4420 return (ENOMEM);
4421 dpt->sc_parent = (entity_t *)ient;
4422 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4423 uu_die(gettext("libuutil error: %s\n"),
4424 uu_strerror(uu_error()));
4426 delprop:
4427 if (tx == NULL)
4428 return (0);
4430 ent = scf_entry_create(g_hndl);
4431 if (ent == NULL)
4432 return (ENOMEM);
4434 if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
4435 scf_entry_destroy(ent);
4436 switch (scf_error()) {
4437 case SCF_ERROR_DELETED:
4438 warn(emsg_pg_deleted, ient->sc_fmri,
4439 "dependents");
4440 return (EBUSY);
4442 case SCF_ERROR_CONNECTION_BROKEN:
4443 return (scferror2errno(scf_error()));
4445 case SCF_ERROR_NOT_FOUND:
4446 break;
4448 case SCF_ERROR_HANDLE_MISMATCH:
4449 case SCF_ERROR_NOT_BOUND:
4450 case SCF_ERROR_INVALID_ARGUMENT:
4451 case SCF_ERROR_NOT_SET:
4452 default:
4453 bad_error("scf_transaction_property_delete",
4454 scf_error());
4458 return (0);
4461 new_dpt_pgroup->sc_pgroup_seen = 1;
4464 * Decide whether the dependent has changed in the manifest.
4466 /* Compare the target. */
4467 if (scf_property_get_value(prop, ud_val) != 0) {
4468 switch (scf_error()) {
4469 case SCF_ERROR_NOT_FOUND:
4470 case SCF_ERROR_CONSTRAINT_VIOLATED:
4471 warn(li_corrupt, ient->sc_fmri);
4472 return (EBADF);
4474 case SCF_ERROR_DELETED:
4475 case SCF_ERROR_CONNECTION_BROKEN:
4476 return (scferror2errno(scf_error()));
4478 case SCF_ERROR_HANDLE_MISMATCH:
4479 case SCF_ERROR_NOT_BOUND:
4480 case SCF_ERROR_NOT_SET:
4481 case SCF_ERROR_PERMISSION_DENIED:
4482 default:
4483 bad_error("scf_property_get_value", scf_error());
4487 if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
4489 bad_error("scf_value_get_as_string", scf_error());
4492 * If the fmri's are not equal then the old fmri will need to
4493 * be refreshed to ensure that the changes are properly updated
4494 * in that service.
4496 r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
4497 switch (r) {
4498 case 0:
4499 dpt = internal_pgroup_new();
4500 if (dpt == NULL)
4501 return (ENOMEM);
4502 dpt->sc_pgroup_name = strdup(ud_name);
4503 dpt->sc_pgroup_fmri = strdup(ud_oldtarg);
4504 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4505 return (ENOMEM);
4506 dpt->sc_parent = (entity_t *)ient;
4507 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4508 uu_die(gettext("libuutil error: %s\n"),
4509 uu_strerror(uu_error()));
4510 break;
4512 case 1:
4513 /* Compare the dependency pgs. */
4514 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4515 switch (scf_error()) {
4516 case SCF_ERROR_NOT_FOUND:
4517 warn(li_corrupt, ient->sc_fmri);
4518 return (EBADF);
4520 case SCF_ERROR_DELETED:
4521 case SCF_ERROR_CONNECTION_BROKEN:
4522 return (scferror2errno(scf_error()));
4524 case SCF_ERROR_NOT_BOUND:
4525 case SCF_ERROR_HANDLE_MISMATCH:
4526 case SCF_ERROR_INVALID_ARGUMENT:
4527 case SCF_ERROR_NOT_SET:
4528 default:
4529 bad_error("scf_snaplevel_get_pg", scf_error());
4533 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4534 snap_lastimport);
4535 switch (r) {
4536 case 0:
4537 break;
4539 case ECANCELED:
4540 case ECONNABORTED:
4541 case ENOMEM:
4542 case EBADF:
4543 return (r);
4545 case EACCES:
4546 default:
4547 bad_error("load_pg", r);
4550 if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4551 /* no change, leave customizations */
4552 internal_pgroup_free(old_dpt_pgroup);
4553 return (0);
4555 break;
4557 case -1:
4558 warn(li_corrupt, ient->sc_fmri);
4559 return (EBADF);
4561 case -2:
4562 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4563 ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4564 return (EINVAL);
4566 default:
4567 bad_error("fmri_equal", r);
4571 * The dependent has changed in the manifest. Upgrade the current
4572 * properties if they haven't been customized.
4576 * If new_dpt_pgroup->sc_override, then act as though the property
4577 * group hasn't been customized.
4579 if (new_dpt_pgroup->sc_pgroup_override) {
4580 (void) strcpy(ud_ctarg, ud_oldtarg);
4581 goto nocust;
4584 if (!ud_run_dpts_pg_set) {
4585 warn(cf_missing, ient->sc_fmri, ud_name);
4586 r = 0;
4587 goto out;
4588 } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4589 switch (scf_error()) {
4590 case SCF_ERROR_NOT_FOUND:
4591 warn(cf_missing, ient->sc_fmri, ud_name);
4592 r = 0;
4593 goto out;
4595 case SCF_ERROR_CONNECTION_BROKEN:
4596 r = scferror2errno(scf_error());
4597 goto out;
4599 case SCF_ERROR_DELETED:
4600 warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4601 r = EBUSY;
4602 goto out;
4604 case SCF_ERROR_INVALID_ARGUMENT:
4605 case SCF_ERROR_NOT_BOUND:
4606 case SCF_ERROR_HANDLE_MISMATCH:
4607 case SCF_ERROR_NOT_SET:
4608 default:
4609 bad_error("scf_pg_get_property", scf_error());
4613 if (scf_property_get_value(ud_prop, ud_val) != 0) {
4614 switch (scf_error()) {
4615 case SCF_ERROR_NOT_FOUND:
4616 case SCF_ERROR_CONSTRAINT_VIOLATED:
4617 warn(cf_inval, ient->sc_fmri, ud_name);
4618 r = 0;
4619 goto out;
4621 case SCF_ERROR_DELETED:
4622 case SCF_ERROR_CONNECTION_BROKEN:
4623 r = scferror2errno(scf_error());
4624 goto out;
4626 case SCF_ERROR_HANDLE_MISMATCH:
4627 case SCF_ERROR_NOT_BOUND:
4628 case SCF_ERROR_NOT_SET:
4629 case SCF_ERROR_PERMISSION_DENIED:
4630 default:
4631 bad_error("scf_property_get_value", scf_error());
4635 ty = scf_value_type(ud_val);
4636 assert(ty != SCF_TYPE_INVALID);
4637 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4638 warn(cf_inval, ient->sc_fmri, ud_name);
4639 r = 0;
4640 goto out;
4642 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4644 bad_error("scf_value_get_as_string", scf_error());
4646 r = fmri_equal(ud_ctarg, ud_oldtarg);
4647 if (r == -1) {
4648 warn(cf_inval, ient->sc_fmri, ud_name);
4649 r = 0;
4650 goto out;
4651 } else if (r == -2) {
4652 warn(li_corrupt, ient->sc_fmri);
4653 r = EBADF;
4654 goto out;
4655 } else if (r == 0) {
4657 * Target has been changed. Only abort now if it's been
4658 * changed to something other than what's in the manifest.
4660 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4661 if (r == -1) {
4662 warn(cf_inval, ient->sc_fmri, ud_name);
4663 r = 0;
4664 goto out;
4665 } else if (r == 0) {
4666 warn(cf_newtarg, ient->sc_fmri, ud_name);
4667 r = 0;
4668 goto out;
4669 } else if (r != 1) {
4670 /* invalid sc_pgroup_fmri caught above */
4671 bad_error("fmri_equal", r);
4675 * Fetch the current dependency pg. If it's what the manifest
4676 * says, then no problem.
4678 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4679 switch (serr) {
4680 case SCF_ERROR_NONE:
4681 break;
4683 case SCF_ERROR_NOT_FOUND:
4684 warn(cf_missing, ient->sc_fmri, ud_name);
4685 r = 0;
4686 goto out;
4688 case SCF_ERROR_NO_MEMORY:
4689 r = ENOMEM;
4690 goto out;
4692 case SCF_ERROR_CONSTRAINT_VIOLATED:
4693 case SCF_ERROR_INVALID_ARGUMENT:
4694 default:
4695 bad_error("fmri_to_entity", serr);
4698 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4699 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4700 switch (r) {
4701 case 0:
4702 break;
4704 case ECONNABORTED:
4705 goto out;
4707 case ECANCELED:
4708 case ENOENT:
4709 warn(cf_missing, ient->sc_fmri, ud_name);
4710 r = 0;
4711 goto out;
4713 case EBADF:
4714 warn(r_no_lvl, ud_ctarg);
4715 goto out;
4717 case EINVAL:
4718 default:
4719 bad_error("entity_get_running_pg", r);
4722 r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4723 switch (r) {
4724 case 0:
4725 break;
4727 case ECANCELED:
4728 warn(cf_missing, ient->sc_fmri, ud_name);
4729 r = 0;
4730 goto out;
4732 case ECONNABORTED:
4733 case ENOMEM:
4734 case EBADF:
4735 goto out;
4737 case EACCES:
4738 default:
4739 bad_error("load_pg", r);
4742 if (!pg_equal(current_pg, new_dpt_pgroup))
4743 warn(cf_newdpg, ient->sc_fmri, ud_name);
4744 internal_pgroup_free(current_pg);
4745 r = 0;
4746 goto out;
4747 } else if (r != 1) {
4748 bad_error("fmri_equal", r);
4751 nocust:
4753 * Target has not been customized. Check the dependency property
4754 * group.
4757 if (old_dpt_pgroup == NULL) {
4758 if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4759 ud_pg) != 0) {
4760 switch (scf_error()) {
4761 case SCF_ERROR_NOT_FOUND:
4762 warn(li_corrupt, ient->sc_fmri);
4763 return (EBADF);
4765 case SCF_ERROR_DELETED:
4766 case SCF_ERROR_CONNECTION_BROKEN:
4767 return (scferror2errno(scf_error()));
4769 case SCF_ERROR_NOT_BOUND:
4770 case SCF_ERROR_HANDLE_MISMATCH:
4771 case SCF_ERROR_INVALID_ARGUMENT:
4772 case SCF_ERROR_NOT_SET:
4773 default:
4774 bad_error("scf_snaplevel_get_pg", scf_error());
4778 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4779 snap_lastimport);
4780 switch (r) {
4781 case 0:
4782 break;
4784 case ECANCELED:
4785 case ECONNABORTED:
4786 case ENOMEM:
4787 case EBADF:
4788 return (r);
4790 case EACCES:
4791 default:
4792 bad_error("load_pg", r);
4795 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4796 switch (serr) {
4797 case SCF_ERROR_NONE:
4798 break;
4800 case SCF_ERROR_NOT_FOUND:
4801 warn(cf_missing, ient->sc_fmri, ud_name);
4802 r = 0;
4803 goto out;
4805 case SCF_ERROR_NO_MEMORY:
4806 r = ENOMEM;
4807 goto out;
4809 case SCF_ERROR_CONSTRAINT_VIOLATED:
4810 case SCF_ERROR_INVALID_ARGUMENT:
4811 default:
4812 bad_error("fmri_to_entity", serr);
4815 r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4816 ud_iter2, ud_inst, imp_snap, ud_snpl);
4817 switch (r) {
4818 case 0:
4819 break;
4821 case ECONNABORTED:
4822 goto out;
4824 case ECANCELED:
4825 case ENOENT:
4826 warn(cf_missing, ient->sc_fmri, ud_name);
4827 r = 0;
4828 goto out;
4830 case EBADF:
4831 warn(r_no_lvl, ud_ctarg);
4832 goto out;
4834 case EINVAL:
4835 default:
4836 bad_error("entity_get_running_pg", r);
4839 r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4840 switch (r) {
4841 case 0:
4842 break;
4844 case ECANCELED:
4845 warn(cf_missing, ient->sc_fmri, ud_name);
4846 goto out;
4848 case ECONNABORTED:
4849 case ENOMEM:
4850 case EBADF:
4851 goto out;
4853 case EACCES:
4854 default:
4855 bad_error("load_pg", r);
4858 if (!pg_equal(current_pg, old_dpt_pgroup)) {
4859 if (!pg_equal(current_pg, new_dpt_pgroup))
4860 warn(cf_newdpg, ient->sc_fmri, ud_name);
4861 internal_pgroup_free(current_pg);
4862 r = 0;
4863 goto out;
4866 /* Uncustomized. Upgrade. */
4868 r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4869 switch (r) {
4870 case 1:
4871 if (pg_equal(current_pg, new_dpt_pgroup)) {
4872 /* Already upgraded. */
4873 internal_pgroup_free(current_pg);
4874 r = 0;
4875 goto out;
4878 internal_pgroup_free(current_pg);
4880 /* upgrade current_pg */
4881 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4882 switch (scf_error()) {
4883 case SCF_ERROR_CONNECTION_BROKEN:
4884 r = scferror2errno(scf_error());
4885 goto out;
4887 case SCF_ERROR_DELETED:
4888 warn(cf_missing, ient->sc_fmri, ud_name);
4889 r = 0;
4890 goto out;
4892 case SCF_ERROR_NOT_FOUND:
4893 break;
4895 case SCF_ERROR_INVALID_ARGUMENT:
4896 case SCF_ERROR_NOT_BOUND:
4897 case SCF_ERROR_NOT_SET:
4898 case SCF_ERROR_HANDLE_MISMATCH:
4899 default:
4900 bad_error("entity_get_pg", scf_error());
4903 if (tissvc)
4904 r = scf_service_add_pg(target_ent, ud_name,
4905 SCF_GROUP_DEPENDENCY, 0, ud_pg);
4906 else
4907 r = scf_instance_add_pg(target_ent, ud_name,
4908 SCF_GROUP_DEPENDENCY, 0, ud_pg);
4909 if (r != 0) {
4910 switch (scf_error()) {
4911 case SCF_ERROR_CONNECTION_BROKEN:
4912 case SCF_ERROR_NO_RESOURCES:
4913 case SCF_ERROR_BACKEND_READONLY:
4914 case SCF_ERROR_BACKEND_ACCESS:
4915 r = scferror2errno(scf_error());
4916 goto out;
4918 case SCF_ERROR_DELETED:
4919 warn(cf_missing, ient->sc_fmri,
4920 ud_name);
4921 r = 0;
4922 goto out;
4924 case SCF_ERROR_PERMISSION_DENIED:
4925 warn(emsg_pg_deleted, ud_ctarg,
4926 ud_name);
4927 r = EPERM;
4928 goto out;
4930 case SCF_ERROR_EXISTS:
4931 warn(emsg_pg_added, ud_ctarg, ud_name);
4932 r = EBUSY;
4933 goto out;
4935 case SCF_ERROR_NOT_BOUND:
4936 case SCF_ERROR_HANDLE_MISMATCH:
4937 case SCF_ERROR_INVALID_ARGUMENT:
4938 case SCF_ERROR_NOT_SET:
4939 default:
4940 bad_error("entity_add_pg", scf_error());
4945 r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4946 switch (r) {
4947 case 0:
4948 break;
4950 case ECANCELED:
4951 warn(cf_missing, ient->sc_fmri, ud_name);
4952 goto out;
4954 case ECONNABORTED:
4955 case ENOMEM:
4956 case EBADF:
4957 goto out;
4959 case EACCES:
4960 default:
4961 bad_error("load_pg", r);
4964 if (g_verbose)
4965 warn(upgrading, ient->sc_fmri, ud_name);
4967 r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4968 new_dpt_pgroup, 0, ient->sc_fmri);
4969 switch (r) {
4970 case 0:
4971 break;
4973 case ECANCELED:
4974 warn(emsg_pg_deleted, ud_ctarg, ud_name);
4975 r = EBUSY;
4976 goto out;
4978 case EPERM:
4979 warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4980 goto out;
4982 case EBUSY:
4983 warn(emsg_pg_changed, ud_ctarg, ud_name);
4984 goto out;
4986 case ECONNABORTED:
4987 case ENOMEM:
4988 case ENOSPC:
4989 case EROFS:
4990 case EACCES:
4991 case EINVAL:
4992 goto out;
4994 default:
4995 bad_error("upgrade_pg", r);
4997 break;
4999 case 0: {
5000 scf_transaction_entry_t *ent;
5001 scf_value_t *val;
5003 internal_pgroup_free(current_pg);
5005 /* delete old pg */
5006 if (g_verbose)
5007 warn(upgrading, ient->sc_fmri, ud_name);
5009 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
5010 switch (scf_error()) {
5011 case SCF_ERROR_CONNECTION_BROKEN:
5012 r = scferror2errno(scf_error());
5013 goto out;
5015 case SCF_ERROR_DELETED:
5016 warn(cf_missing, ient->sc_fmri, ud_name);
5017 r = 0;
5018 goto out;
5020 case SCF_ERROR_NOT_FOUND:
5021 break;
5023 case SCF_ERROR_INVALID_ARGUMENT:
5024 case SCF_ERROR_NOT_BOUND:
5025 case SCF_ERROR_NOT_SET:
5026 case SCF_ERROR_HANDLE_MISMATCH:
5027 default:
5028 bad_error("entity_get_pg", scf_error());
5030 } else if (scf_pg_delete(ud_pg) != 0) {
5031 switch (scf_error()) {
5032 case SCF_ERROR_DELETED:
5033 break;
5035 case SCF_ERROR_CONNECTION_BROKEN:
5036 case SCF_ERROR_BACKEND_READONLY:
5037 case SCF_ERROR_BACKEND_ACCESS:
5038 r = scferror2errno(scf_error());
5039 goto out;
5041 case SCF_ERROR_PERMISSION_DENIED:
5042 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
5043 r = scferror2errno(scf_error());
5044 goto out;
5046 case SCF_ERROR_NOT_SET:
5047 default:
5048 bad_error("scf_pg_delete", scf_error());
5052 /* import new one */
5053 cbdata.sc_handle = g_hndl;
5054 cbdata.sc_trans = NULL; /* handled below */
5055 cbdata.sc_flags = 0;
5057 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
5058 if (r != UU_WALK_NEXT) {
5059 if (r != UU_WALK_ERROR)
5060 bad_error("lscf_dependent_import", r);
5062 r = cbdata.sc_err;
5063 goto out;
5066 if (tx == NULL)
5067 break;
5069 if ((ent = scf_entry_create(g_hndl)) == NULL ||
5070 (val = scf_value_create(g_hndl)) == NULL) {
5071 if (scf_error() == SCF_ERROR_NO_MEMORY)
5072 return (ENOMEM);
5074 bad_error("scf_entry_create", scf_error());
5077 if (scf_transaction_property_change_type(tx, ent, ud_name,
5078 SCF_TYPE_FMRI) != 0) {
5079 switch (scf_error()) {
5080 case SCF_ERROR_CONNECTION_BROKEN:
5081 r = scferror2errno(scf_error());
5082 goto out;
5084 case SCF_ERROR_DELETED:
5085 warn(emsg_pg_deleted, ient->sc_fmri,
5086 "dependents");
5087 r = EBUSY;
5088 goto out;
5090 case SCF_ERROR_NOT_FOUND:
5091 break;
5093 case SCF_ERROR_NOT_BOUND:
5094 case SCF_ERROR_HANDLE_MISMATCH:
5095 case SCF_ERROR_INVALID_ARGUMENT:
5096 case SCF_ERROR_NOT_SET:
5097 default:
5098 bad_error("scf_transaction_property_"
5099 "change_type", scf_error());
5102 if (scf_transaction_property_new(tx, ent, ud_name,
5103 SCF_TYPE_FMRI) != 0) {
5104 switch (scf_error()) {
5105 case SCF_ERROR_CONNECTION_BROKEN:
5106 r = scferror2errno(scf_error());
5107 goto out;
5109 case SCF_ERROR_DELETED:
5110 warn(emsg_pg_deleted, ient->sc_fmri,
5111 "dependents");
5112 r = EBUSY;
5113 goto out;
5115 case SCF_ERROR_EXISTS:
5116 warn(emsg_pg_changed, ient->sc_fmri,
5117 "dependents");
5118 r = EBUSY;
5119 goto out;
5121 case SCF_ERROR_INVALID_ARGUMENT:
5122 case SCF_ERROR_HANDLE_MISMATCH:
5123 case SCF_ERROR_NOT_BOUND:
5124 case SCF_ERROR_NOT_SET:
5125 default:
5126 bad_error("scf_transaction_property_"
5127 "new", scf_error());
5132 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
5133 new_dpt_pgroup->sc_pgroup_fmri) != 0)
5134 /* invalid sc_pgroup_fmri caught above */
5135 bad_error("scf_value_set_from_string",
5136 scf_error());
5138 if (scf_entry_add_value(ent, val) != 0)
5139 bad_error("scf_entry_add_value", scf_error());
5140 break;
5143 case -2:
5144 warn(li_corrupt, ient->sc_fmri);
5145 internal_pgroup_free(current_pg);
5146 r = EBADF;
5147 goto out;
5149 case -1:
5150 default:
5151 /* invalid sc_pgroup_fmri caught above */
5152 bad_error("fmri_equal", r);
5155 r = 0;
5157 out:
5158 if (old_dpt_pgroup != NULL)
5159 internal_pgroup_free(old_dpt_pgroup);
5161 return (r);
5165 * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
5166 * would import it, except it seems to exist in the service anyway. Compare
5167 * the existent dependent with the one we would import, and report any
5168 * differences (if there are none, be silent). prop is the property which
5169 * represents the existent dependent (in the dependents property group) in the
5170 * entity corresponding to ient.
5172 * Returns
5173 * 0 - success (Sort of. At least, we can continue importing.)
5174 * ECONNABORTED - repository connection broken
5175 * EBUSY - ancestor of prop was deleted (error printed)
5176 * ENOMEM - out of memory
5177 * EBADF - corrupt property group (error printed)
5178 * EINVAL - new_dpt_pgroup has invalid target (error printed)
5180 static int
5181 handle_dependent_conflict(const entity_t * const ient,
5182 const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
5184 int r;
5185 scf_type_t ty;
5186 scf_error_t scfe;
5187 void *tptr;
5188 int tissvc;
5189 pgroup_t *pgroup;
5191 if (scf_property_get_value(prop, ud_val) != 0) {
5192 switch (scf_error()) {
5193 case SCF_ERROR_CONNECTION_BROKEN:
5194 return (scferror2errno(scf_error()));
5196 case SCF_ERROR_DELETED:
5197 warn(emsg_pg_deleted, ient->sc_fmri,
5198 new_dpt_pgroup->sc_pgroup_name);
5199 return (EBUSY);
5201 case SCF_ERROR_CONSTRAINT_VIOLATED:
5202 case SCF_ERROR_NOT_FOUND:
5203 warn(gettext("Conflict upgrading %s (not importing "
5204 "dependent \"%s\" because it already exists.) "
5205 "Warning: The \"%s/%2$s\" property has more or "
5206 "fewer than one value)).\n"), ient->sc_fmri,
5207 new_dpt_pgroup->sc_pgroup_name, "dependents");
5208 return (0);
5210 case SCF_ERROR_HANDLE_MISMATCH:
5211 case SCF_ERROR_NOT_BOUND:
5212 case SCF_ERROR_NOT_SET:
5213 case SCF_ERROR_PERMISSION_DENIED:
5214 default:
5215 bad_error("scf_property_get_value",
5216 scf_error());
5220 ty = scf_value_type(ud_val);
5221 assert(ty != SCF_TYPE_INVALID);
5222 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
5223 warn(gettext("Conflict upgrading %s (not importing dependent "
5224 "\"%s\" because it already exists). Warning: The "
5225 "\"%s/%s\" property has unexpected type \"%s\")).\n"),
5226 ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
5227 scf_type_to_string(ty), "dependents");
5228 return (0);
5231 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
5233 bad_error("scf_value_get_as_string", scf_error());
5235 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
5236 switch (r) {
5237 case 0:
5238 warn(gettext("Conflict upgrading %s (not importing dependent "
5239 "\"%s\" (target \"%s\") because it already exists with "
5240 "target \"%s\").\n"), ient->sc_fmri,
5241 new_dpt_pgroup->sc_pgroup_name,
5242 new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
5243 return (0);
5245 case 1:
5246 break;
5248 case -1:
5249 warn(gettext("Conflict upgrading %s (not importing dependent "
5250 "\"%s\" because it already exists). Warning: The current "
5251 "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
5252 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5253 return (0);
5255 case -2:
5256 warn(gettext("Dependent \"%s\" of %s has invalid target "
5257 "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
5258 new_dpt_pgroup->sc_pgroup_fmri);
5259 return (EINVAL);
5261 default:
5262 bad_error("fmri_equal", r);
5265 /* compare dependency pgs in target */
5266 scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
5267 switch (scfe) {
5268 case SCF_ERROR_NONE:
5269 break;
5271 case SCF_ERROR_NO_MEMORY:
5272 return (ENOMEM);
5274 case SCF_ERROR_NOT_FOUND:
5275 warn(emsg_dpt_dangling, ient->sc_fmri,
5276 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5277 return (0);
5279 case SCF_ERROR_CONSTRAINT_VIOLATED:
5280 case SCF_ERROR_INVALID_ARGUMENT:
5281 default:
5282 bad_error("fmri_to_entity", scfe);
5285 r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
5286 ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
5287 switch (r) {
5288 case 0:
5289 break;
5291 case ECONNABORTED:
5292 return (r);
5294 case ECANCELED:
5295 warn(emsg_dpt_dangling, ient->sc_fmri,
5296 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5297 return (0);
5299 case EBADF:
5300 if (tissvc)
5301 warn(gettext("%s has an instance with a \"%s\" "
5302 "snapshot which is missing a snaplevel.\n"),
5303 ud_ctarg, "running");
5304 else
5305 warn(gettext("%s has a \"%s\" snapshot which is "
5306 "missing a snaplevel.\n"), ud_ctarg, "running");
5307 /* FALLTHROUGH */
5309 case ENOENT:
5310 warn(emsg_dpt_no_dep, ient->sc_fmri,
5311 new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5312 new_dpt_pgroup->sc_pgroup_name);
5313 return (0);
5315 case EINVAL:
5316 default:
5317 bad_error("entity_get_running_pg", r);
5320 pgroup = internal_pgroup_new();
5321 if (pgroup == NULL)
5322 return (ENOMEM);
5324 r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
5325 switch (r) {
5326 case 0:
5327 break;
5329 case ECONNABORTED:
5330 case EBADF:
5331 case ENOMEM:
5332 internal_pgroup_free(pgroup);
5333 return (r);
5335 case ECANCELED:
5336 warn(emsg_dpt_no_dep, ient->sc_fmri,
5337 new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5338 new_dpt_pgroup->sc_pgroup_name);
5339 internal_pgroup_free(pgroup);
5340 return (0);
5342 case EACCES:
5343 default:
5344 bad_error("load_pg", r);
5347 /* report differences */
5348 report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
5349 internal_pgroup_free(pgroup);
5350 return (0);
5354 * lipg is a property group in the last-import snapshot of ent, which is an
5355 * scf_service_t or an scf_instance_t (according to ient). If lipg is not in
5356 * ient's pgroups, delete it from ent if it hasn't been customized. If it is
5357 * in ents's property groups, compare and upgrade ent appropriately.
5359 * Returns
5360 * 0 - success
5361 * ECONNABORTED - repository connection broken
5362 * ENOMEM - out of memory
5363 * ENOSPC - configd is out of resources
5364 * EINVAL - ient has invalid dependent (error printed)
5365 * - ient has invalid pgroup_t (error printed)
5366 * ECANCELED - ent has been deleted
5367 * ENODEV - entity containing lipg has been deleted
5368 * - entity containing running has been deleted
5369 * EPERM - could not delete pg (permission denied) (error printed)
5370 * - couldn't upgrade dependents (permission denied) (error printed)
5371 * - couldn't import pg (permission denied) (error printed)
5372 * - couldn't upgrade pg (permission denied) (error printed)
5373 * EROFS - could not delete pg (repository read-only)
5374 * - couldn't upgrade dependents (repository read-only)
5375 * - couldn't import pg (repository read-only)
5376 * - couldn't upgrade pg (repository read-only)
5377 * EACCES - could not delete pg (backend access denied)
5378 * - couldn't upgrade dependents (backend access denied)
5379 * - couldn't import pg (backend access denied)
5380 * - couldn't upgrade pg (backend access denied)
5381 * - couldn't read property (backend access denied)
5382 * EBUSY - property group was added (error printed)
5383 * - property group was deleted (error printed)
5384 * - property group changed (error printed)
5385 * - "dependents" pg was added, changed, or deleted (error printed)
5386 * - dependent target deleted (error printed)
5387 * - dependent pg changed (error printed)
5388 * EBADF - imp_snpl is corrupt (error printed)
5389 * - ent has bad pg (error printed)
5390 * EEXIST - dependent collision in target service (error printed)
5392 static int
5393 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
5394 const scf_snaplevel_t *running)
5396 int r;
5397 pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
5398 scf_callback_t cbdata;
5400 const char * const cf_pg_missing =
5401 gettext("Conflict upgrading %s (property group %s is missing)\n");
5402 const char * const deleting =
5403 gettext("%s: Deleting property group \"%s\".\n");
5405 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5407 /* Skip dependent property groups. */
5408 if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
5409 switch (scf_error()) {
5410 case SCF_ERROR_DELETED:
5411 return (ENODEV);
5413 case SCF_ERROR_CONNECTION_BROKEN:
5414 return (ECONNABORTED);
5416 case SCF_ERROR_NOT_SET:
5417 case SCF_ERROR_NOT_BOUND:
5418 default:
5419 bad_error("scf_pg_get_type", scf_error());
5423 if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
5424 if (scf_pg_get_property(lipg, "external", NULL) == 0)
5425 return (0);
5427 switch (scf_error()) {
5428 case SCF_ERROR_NOT_FOUND:
5429 break;
5431 case SCF_ERROR_CONNECTION_BROKEN:
5432 return (ECONNABORTED);
5434 case SCF_ERROR_DELETED:
5435 return (ENODEV);
5437 case SCF_ERROR_INVALID_ARGUMENT:
5438 case SCF_ERROR_NOT_BOUND:
5439 case SCF_ERROR_HANDLE_MISMATCH:
5440 case SCF_ERROR_NOT_SET:
5441 default:
5442 bad_error("scf_pg_get_property", scf_error());
5446 /* lookup pg in new properties */
5447 if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
5448 switch (scf_error()) {
5449 case SCF_ERROR_DELETED:
5450 return (ENODEV);
5452 case SCF_ERROR_CONNECTION_BROKEN:
5453 return (ECONNABORTED);
5455 case SCF_ERROR_NOT_SET:
5456 case SCF_ERROR_NOT_BOUND:
5457 default:
5458 bad_error("scf_pg_get_name", scf_error());
5462 pgrp.sc_pgroup_name = imp_str;
5463 mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
5465 if (mpg != NULL)
5466 mpg->sc_pgroup_seen = 1;
5468 /* Special handling for dependents */
5469 if (strcmp(imp_str, "dependents") == 0)
5470 return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
5472 if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
5473 return (upgrade_manifestfiles(NULL, ient, running, ent));
5475 if (mpg == NULL || mpg->sc_pgroup_delete) {
5476 /* property group was deleted from manifest */
5477 if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5478 switch (scf_error()) {
5479 case SCF_ERROR_NOT_FOUND:
5480 return (0);
5482 case SCF_ERROR_DELETED:
5483 case SCF_ERROR_CONNECTION_BROKEN:
5484 return (scferror2errno(scf_error()));
5486 case SCF_ERROR_INVALID_ARGUMENT:
5487 case SCF_ERROR_HANDLE_MISMATCH:
5488 case SCF_ERROR_NOT_BOUND:
5489 case SCF_ERROR_NOT_SET:
5490 default:
5491 bad_error("entity_get_pg", scf_error());
5495 if (mpg != NULL && mpg->sc_pgroup_delete) {
5496 if (g_verbose)
5497 warn(deleting, ient->sc_fmri, imp_str);
5498 if (scf_pg_delete(imp_pg2) == 0)
5499 return (0);
5501 switch (scf_error()) {
5502 case SCF_ERROR_DELETED:
5503 return (0);
5505 case SCF_ERROR_CONNECTION_BROKEN:
5506 case SCF_ERROR_BACKEND_READONLY:
5507 case SCF_ERROR_BACKEND_ACCESS:
5508 return (scferror2errno(scf_error()));
5510 case SCF_ERROR_PERMISSION_DENIED:
5511 warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
5512 return (scferror2errno(scf_error()));
5514 case SCF_ERROR_NOT_SET:
5515 default:
5516 bad_error("scf_pg_delete", scf_error());
5520 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5521 switch (r) {
5522 case 0:
5523 break;
5525 case ECANCELED:
5526 return (ENODEV);
5528 case ECONNABORTED:
5529 case ENOMEM:
5530 case EBADF:
5531 case EACCES:
5532 return (r);
5534 default:
5535 bad_error("load_pg", r);
5538 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5539 switch (r) {
5540 case 0:
5541 break;
5543 case ECANCELED:
5544 case ECONNABORTED:
5545 case ENOMEM:
5546 case EBADF:
5547 case EACCES:
5548 internal_pgroup_free(lipg_i);
5549 return (r);
5551 default:
5552 bad_error("load_pg", r);
5555 if (pg_equal(lipg_i, curpg_i)) {
5556 if (g_verbose)
5557 warn(deleting, ient->sc_fmri, imp_str);
5558 if (scf_pg_delete(imp_pg2) != 0) {
5559 switch (scf_error()) {
5560 case SCF_ERROR_DELETED:
5561 break;
5563 case SCF_ERROR_CONNECTION_BROKEN:
5564 internal_pgroup_free(lipg_i);
5565 internal_pgroup_free(curpg_i);
5566 return (ECONNABORTED);
5568 case SCF_ERROR_NOT_SET:
5569 case SCF_ERROR_NOT_BOUND:
5570 default:
5571 bad_error("scf_pg_delete", scf_error());
5574 } else {
5575 report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5578 internal_pgroup_free(lipg_i);
5579 internal_pgroup_free(curpg_i);
5581 return (0);
5585 * Only dependent pgs can have override set, and we skipped those
5586 * above.
5588 assert(!mpg->sc_pgroup_override);
5590 /* compare */
5591 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5592 switch (r) {
5593 case 0:
5594 break;
5596 case ECANCELED:
5597 return (ENODEV);
5599 case ECONNABORTED:
5600 case EBADF:
5601 case ENOMEM:
5602 case EACCES:
5603 return (r);
5605 default:
5606 bad_error("load_pg", r);
5609 if (pg_equal(mpg, lipg_i)) {
5610 /* The manifest pg has not changed. Move on. */
5611 r = 0;
5612 goto out;
5615 /* upgrade current properties according to lipg & mpg */
5616 if (running != NULL)
5617 r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5618 else
5619 r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5620 if (r != 0) {
5621 switch (scf_error()) {
5622 case SCF_ERROR_CONNECTION_BROKEN:
5623 r = scferror2errno(scf_error());
5624 goto out;
5626 case SCF_ERROR_DELETED:
5627 if (running != NULL)
5628 r = ENODEV;
5629 else
5630 r = ECANCELED;
5631 goto out;
5633 case SCF_ERROR_NOT_FOUND:
5634 break;
5636 case SCF_ERROR_INVALID_ARGUMENT:
5637 case SCF_ERROR_HANDLE_MISMATCH:
5638 case SCF_ERROR_NOT_BOUND:
5639 case SCF_ERROR_NOT_SET:
5640 default:
5641 bad_error("entity_get_pg", scf_error());
5644 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5646 r = 0;
5647 goto out;
5650 r = load_pg_attrs(imp_pg2, &curpg_i);
5651 switch (r) {
5652 case 0:
5653 break;
5655 case ECANCELED:
5656 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5657 r = 0;
5658 goto out;
5660 case ECONNABORTED:
5661 case ENOMEM:
5662 goto out;
5664 default:
5665 bad_error("load_pg_attrs", r);
5668 if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5669 (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5670 internal_pgroup_free(curpg_i);
5671 r = 0;
5672 goto out;
5675 internal_pgroup_free(curpg_i);
5677 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5678 switch (r) {
5679 case 0:
5680 break;
5682 case ECANCELED:
5683 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5684 r = 0;
5685 goto out;
5687 case ECONNABORTED:
5688 case EBADF:
5689 case ENOMEM:
5690 case EACCES:
5691 goto out;
5693 default:
5694 bad_error("load_pg", r);
5697 if (pg_equal(lipg_i, curpg_i) &&
5698 !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5699 int do_delete = 1;
5701 if (g_verbose)
5702 warn(gettext("%s: Upgrading property group \"%s\".\n"),
5703 ient->sc_fmri, mpg->sc_pgroup_name);
5705 internal_pgroup_free(curpg_i);
5707 if (running != NULL &&
5708 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5709 switch (scf_error()) {
5710 case SCF_ERROR_DELETED:
5711 r = ECANCELED;
5712 goto out;
5714 case SCF_ERROR_NOT_FOUND:
5715 do_delete = 0;
5716 break;
5718 case SCF_ERROR_CONNECTION_BROKEN:
5719 r = scferror2errno(scf_error());
5720 goto out;
5722 case SCF_ERROR_HANDLE_MISMATCH:
5723 case SCF_ERROR_INVALID_ARGUMENT:
5724 case SCF_ERROR_NOT_SET:
5725 case SCF_ERROR_NOT_BOUND:
5726 default:
5727 bad_error("entity_get_pg", scf_error());
5731 if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5732 switch (scf_error()) {
5733 case SCF_ERROR_DELETED:
5734 break;
5736 case SCF_ERROR_CONNECTION_BROKEN:
5737 case SCF_ERROR_BACKEND_READONLY:
5738 case SCF_ERROR_BACKEND_ACCESS:
5739 r = scferror2errno(scf_error());
5740 goto out;
5742 case SCF_ERROR_PERMISSION_DENIED:
5743 warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5744 ient->sc_fmri);
5745 r = scferror2errno(scf_error());
5746 goto out;
5748 case SCF_ERROR_NOT_SET:
5749 case SCF_ERROR_NOT_BOUND:
5750 default:
5751 bad_error("scf_pg_delete", scf_error());
5755 cbdata.sc_handle = g_hndl;
5756 cbdata.sc_parent = ent;
5757 cbdata.sc_service = issvc;
5758 cbdata.sc_flags = 0;
5759 cbdata.sc_source_fmri = ient->sc_fmri;
5760 cbdata.sc_target_fmri = ient->sc_fmri;
5762 r = entity_pgroup_import(mpg, &cbdata);
5763 switch (r) {
5764 case UU_WALK_NEXT:
5765 r = 0;
5766 goto out;
5768 case UU_WALK_ERROR:
5769 if (cbdata.sc_err == EEXIST) {
5770 warn(emsg_pg_added, ient->sc_fmri,
5771 mpg->sc_pgroup_name);
5772 r = EBUSY;
5773 } else {
5774 r = cbdata.sc_err;
5776 goto out;
5778 default:
5779 bad_error("entity_pgroup_import", r);
5783 if (running != NULL &&
5784 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5785 switch (scf_error()) {
5786 case SCF_ERROR_CONNECTION_BROKEN:
5787 case SCF_ERROR_DELETED:
5788 r = scferror2errno(scf_error());
5789 goto out;
5791 case SCF_ERROR_NOT_FOUND:
5792 break;
5794 case SCF_ERROR_HANDLE_MISMATCH:
5795 case SCF_ERROR_INVALID_ARGUMENT:
5796 case SCF_ERROR_NOT_SET:
5797 case SCF_ERROR_NOT_BOUND:
5798 default:
5799 bad_error("entity_get_pg", scf_error());
5802 cbdata.sc_handle = g_hndl;
5803 cbdata.sc_parent = ent;
5804 cbdata.sc_service = issvc;
5805 cbdata.sc_flags = SCI_FORCE;
5806 cbdata.sc_source_fmri = ient->sc_fmri;
5807 cbdata.sc_target_fmri = ient->sc_fmri;
5809 r = entity_pgroup_import(mpg, &cbdata);
5810 switch (r) {
5811 case UU_WALK_NEXT:
5812 r = 0;
5813 goto out;
5815 case UU_WALK_ERROR:
5816 if (cbdata.sc_err == EEXIST) {
5817 warn(emsg_pg_added, ient->sc_fmri,
5818 mpg->sc_pgroup_name);
5819 r = EBUSY;
5820 } else {
5821 r = cbdata.sc_err;
5823 goto out;
5825 default:
5826 bad_error("entity_pgroup_import", r);
5830 r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5831 internal_pgroup_free(curpg_i);
5832 switch (r) {
5833 case 0:
5834 ient->sc_import_state = IMPORT_PROP_BEGUN;
5835 break;
5837 case ECANCELED:
5838 warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5839 r = EBUSY;
5840 break;
5842 case EPERM:
5843 warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5844 break;
5846 case EBUSY:
5847 warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5848 break;
5850 case ECONNABORTED:
5851 case ENOMEM:
5852 case ENOSPC:
5853 case EROFS:
5854 case EACCES:
5855 case EINVAL:
5856 break;
5858 default:
5859 bad_error("upgrade_pg", r);
5862 out:
5863 internal_pgroup_free(lipg_i);
5864 return (r);
5868 * Upgrade the properties of ent according to snpl & ient.
5870 * Returns
5871 * 0 - success
5872 * ECONNABORTED - repository connection broken
5873 * ENOMEM - out of memory
5874 * ENOSPC - configd is out of resources
5875 * ECANCELED - ent was deleted
5876 * ENODEV - entity containing snpl was deleted
5877 * - entity containing running was deleted
5878 * EBADF - imp_snpl is corrupt (error printed)
5879 * - ent has corrupt pg (error printed)
5880 * - dependent has corrupt pg (error printed)
5881 * - dependent target has a corrupt snapshot (error printed)
5882 * EBUSY - pg was added, changed, or deleted (error printed)
5883 * - dependent target was deleted (error printed)
5884 * - dependent pg changed (error printed)
5885 * EINVAL - invalid property group name (error printed)
5886 * - invalid property name (error printed)
5887 * - invalid value (error printed)
5888 * - ient has invalid pgroup or dependent (error printed)
5889 * EPERM - could not create property group (permission denied) (error printed)
5890 * - could not modify property group (permission denied) (error printed)
5891 * - couldn't delete, upgrade, or import pg or dependent (error printed)
5892 * EROFS - could not create property group (repository read-only)
5893 * - couldn't delete, upgrade, or import pg or dependent
5894 * EACCES - could not create property group (backend access denied)
5895 * - couldn't delete, upgrade, or import pg or dependent
5896 * EEXIST - dependent collision in target service (error printed)
5898 static int
5899 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5900 entity_t *ient)
5902 pgroup_t *pg, *rpg;
5903 int r;
5904 uu_list_t *pgs = ient->sc_pgroups;
5906 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5908 /* clear sc_sceen for pgs */
5909 if (uu_list_walk(pgs, clear_int,
5910 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5911 bad_error("uu_list_walk", uu_error());
5913 if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5914 switch (scf_error()) {
5915 case SCF_ERROR_DELETED:
5916 return (ENODEV);
5918 case SCF_ERROR_CONNECTION_BROKEN:
5919 return (ECONNABORTED);
5921 case SCF_ERROR_NOT_SET:
5922 case SCF_ERROR_NOT_BOUND:
5923 case SCF_ERROR_HANDLE_MISMATCH:
5924 default:
5925 bad_error("scf_iter_snaplevel_pgs", scf_error());
5929 for (;;) {
5930 r = scf_iter_next_pg(imp_up_iter, imp_pg);
5931 if (r == 0)
5932 break;
5933 if (r == 1) {
5934 r = process_old_pg(imp_pg, ient, ent, running);
5935 switch (r) {
5936 case 0:
5937 break;
5939 case ECONNABORTED:
5940 case ENOMEM:
5941 case ENOSPC:
5942 case ECANCELED:
5943 case ENODEV:
5944 case EPERM:
5945 case EROFS:
5946 case EACCES:
5947 case EBADF:
5948 case EBUSY:
5949 case EINVAL:
5950 case EEXIST:
5951 return (r);
5953 default:
5954 bad_error("process_old_pg", r);
5956 continue;
5958 if (r != -1)
5959 bad_error("scf_iter_next_pg", r);
5961 switch (scf_error()) {
5962 case SCF_ERROR_DELETED:
5963 return (ENODEV);
5965 case SCF_ERROR_CONNECTION_BROKEN:
5966 return (ECONNABORTED);
5968 case SCF_ERROR_HANDLE_MISMATCH:
5969 case SCF_ERROR_NOT_BOUND:
5970 case SCF_ERROR_NOT_SET:
5971 case SCF_ERROR_INVALID_ARGUMENT:
5972 default:
5973 bad_error("scf_iter_next_pg", scf_error());
5977 for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5978 if (pg->sc_pgroup_seen)
5979 continue;
5981 /* pg is new */
5983 if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5984 r = upgrade_dependents(NULL, imp_snpl, ient, running,
5985 ent);
5986 switch (r) {
5987 case 0:
5988 break;
5990 case ECONNABORTED:
5991 case ENOMEM:
5992 case ENOSPC:
5993 case ECANCELED:
5994 case ENODEV:
5995 case EBADF:
5996 case EBUSY:
5997 case EINVAL:
5998 case EPERM:
5999 case EROFS:
6000 case EACCES:
6001 case EEXIST:
6002 return (r);
6004 default:
6005 bad_error("upgrade_dependents", r);
6007 continue;
6010 if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
6011 r = upgrade_manifestfiles(pg, ient, running, ent);
6012 switch (r) {
6013 case 0:
6014 break;
6016 case ECONNABORTED:
6017 case ENOMEM:
6018 case ENOSPC:
6019 case ECANCELED:
6020 case ENODEV:
6021 case EBADF:
6022 case EBUSY:
6023 case EINVAL:
6024 case EPERM:
6025 case EROFS:
6026 case EACCES:
6027 case EEXIST:
6028 return (r);
6030 default:
6031 bad_error("upgrade_manifestfiles", r);
6033 continue;
6036 if (running != NULL) {
6037 r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
6038 imp_pg);
6039 } else {
6040 r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
6041 imp_pg);
6043 if (r != 0) {
6044 scf_callback_t cbdata;
6046 switch (scf_error()) {
6047 case SCF_ERROR_NOT_FOUND:
6048 break;
6050 case SCF_ERROR_CONNECTION_BROKEN:
6051 return (scferror2errno(scf_error()));
6053 case SCF_ERROR_DELETED:
6054 if (running != NULL)
6055 return (ENODEV);
6056 else
6057 return (scferror2errno(scf_error()));
6059 case SCF_ERROR_INVALID_ARGUMENT:
6060 warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
6061 pg->sc_pgroup_name);
6062 return (EINVAL);
6064 case SCF_ERROR_NOT_SET:
6065 case SCF_ERROR_HANDLE_MISMATCH:
6066 case SCF_ERROR_NOT_BOUND:
6067 default:
6068 bad_error("entity_get_pg", scf_error());
6071 /* User doesn't have pg, so import it. */
6073 cbdata.sc_handle = g_hndl;
6074 cbdata.sc_parent = ent;
6075 cbdata.sc_service = issvc;
6076 cbdata.sc_flags = SCI_FORCE;
6077 cbdata.sc_source_fmri = ient->sc_fmri;
6078 cbdata.sc_target_fmri = ient->sc_fmri;
6080 r = entity_pgroup_import(pg, &cbdata);
6081 switch (r) {
6082 case UU_WALK_NEXT:
6083 ient->sc_import_state = IMPORT_PROP_BEGUN;
6084 continue;
6086 case UU_WALK_ERROR:
6087 if (cbdata.sc_err == EEXIST) {
6088 warn(emsg_pg_added, ient->sc_fmri,
6089 pg->sc_pgroup_name);
6090 return (EBUSY);
6092 return (cbdata.sc_err);
6094 default:
6095 bad_error("entity_pgroup_import", r);
6099 /* report differences between pg & current */
6100 r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
6101 switch (r) {
6102 case 0:
6103 break;
6105 case ECANCELED:
6106 warn(emsg_pg_deleted, ient->sc_fmri,
6107 pg->sc_pgroup_name);
6108 return (EBUSY);
6110 case ECONNABORTED:
6111 case EBADF:
6112 case ENOMEM:
6113 case EACCES:
6114 return (r);
6116 default:
6117 bad_error("load_pg", r);
6119 report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
6120 internal_pgroup_free(rpg);
6121 rpg = NULL;
6124 return (0);
6128 * Import an instance. If it doesn't exist, create it. If it has
6129 * a last-import snapshot, upgrade its properties. Finish by updating its
6130 * last-import snapshot. If it doesn't have a last-import snapshot then it
6131 * could have been created for a dependent tag in another manifest. Import the
6132 * new properties. If there's a conflict, don't override, like now?
6134 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
6135 * lcbdata->sc_err to
6136 * ECONNABORTED - repository connection broken
6137 * ENOMEM - out of memory
6138 * ENOSPC - svc.configd is out of resources
6139 * EEXIST - dependency collision in dependent service (error printed)
6140 * EPERM - couldn't create temporary instance (permission denied)
6141 * - couldn't import into temporary instance (permission denied)
6142 * - couldn't take snapshot (permission denied)
6143 * - couldn't upgrade properties (permission denied)
6144 * - couldn't import properties (permission denied)
6145 * - couldn't import dependents (permission denied)
6146 * EROFS - couldn't create temporary instance (repository read-only)
6147 * - couldn't import into temporary instance (repository read-only)
6148 * - couldn't upgrade properties (repository read-only)
6149 * - couldn't import properties (repository read-only)
6150 * - couldn't import dependents (repository read-only)
6151 * EACCES - couldn't create temporary instance (backend access denied)
6152 * - couldn't import into temporary instance (backend access denied)
6153 * - couldn't upgrade properties (backend access denied)
6154 * - couldn't import properties (backend access denied)
6155 * - couldn't import dependents (backend access denied)
6156 * EINVAL - invalid instance name (error printed)
6157 * - invalid pgroup_t's (error printed)
6158 * - invalid dependents (error printed)
6159 * EBUSY - temporary service deleted (error printed)
6160 * - temporary instance deleted (error printed)
6161 * - temporary instance changed (error printed)
6162 * - temporary instance already exists (error printed)
6163 * - instance deleted (error printed)
6164 * EBADF - instance has corrupt last-import snapshot (error printed)
6165 * - instance is corrupt (error printed)
6166 * - dependent has corrupt pg (error printed)
6167 * - dependent target has a corrupt snapshot (error printed)
6168 * -1 - unknown libscf error (error printed)
6170 static int
6171 lscf_instance_import(void *v, void *pvt)
6173 entity_t *inst = v;
6174 scf_callback_t ctx;
6175 scf_callback_t *lcbdata = pvt;
6176 scf_service_t *rsvc = lcbdata->sc_parent;
6177 int r;
6178 scf_snaplevel_t *running;
6179 int flags = lcbdata->sc_flags;
6181 const char * const emsg_tdel =
6182 gettext("Temporary instance svc:/%s:%s was deleted.\n");
6183 const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
6184 "changed unexpectedly.\n");
6185 const char * const emsg_del = gettext("%s changed unexpectedly "
6186 "(instance \"%s\" was deleted.)\n");
6187 const char * const emsg_badsnap = gettext(
6188 "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
6191 * prepare last-import snapshot:
6192 * create temporary instance (service was precreated)
6193 * populate with properties from bundle
6194 * take snapshot
6196 if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
6197 switch (scf_error()) {
6198 case SCF_ERROR_CONNECTION_BROKEN:
6199 case SCF_ERROR_NO_RESOURCES:
6200 case SCF_ERROR_BACKEND_READONLY:
6201 case SCF_ERROR_BACKEND_ACCESS:
6202 return (stash_scferror(lcbdata));
6204 case SCF_ERROR_EXISTS:
6205 warn(gettext("Temporary service svc:/%s "
6206 "changed unexpectedly (instance \"%s\" added).\n"),
6207 imp_tsname, inst->sc_name);
6208 lcbdata->sc_err = EBUSY;
6209 return (UU_WALK_ERROR);
6211 case SCF_ERROR_DELETED:
6212 warn(gettext("Temporary service svc:/%s "
6213 "was deleted unexpectedly.\n"), imp_tsname);
6214 lcbdata->sc_err = EBUSY;
6215 return (UU_WALK_ERROR);
6217 case SCF_ERROR_INVALID_ARGUMENT:
6218 warn(gettext("Invalid instance name \"%s\".\n"),
6219 inst->sc_name);
6220 return (stash_scferror(lcbdata));
6222 case SCF_ERROR_PERMISSION_DENIED:
6223 warn(gettext("Could not create temporary instance "
6224 "\"%s\" in svc:/%s (permission denied).\n"),
6225 inst->sc_name, imp_tsname);
6226 return (stash_scferror(lcbdata));
6228 case SCF_ERROR_HANDLE_MISMATCH:
6229 case SCF_ERROR_NOT_BOUND:
6230 case SCF_ERROR_NOT_SET:
6231 default:
6232 bad_error("scf_service_add_instance", scf_error());
6236 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6237 inst->sc_name);
6238 if (r < 0)
6239 bad_error("snprintf", errno);
6241 r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
6242 lcbdata->sc_flags | SCI_NOENABLED);
6243 switch (r) {
6244 case 0:
6245 break;
6247 case ECANCELED:
6248 warn(emsg_tdel, imp_tsname, inst->sc_name);
6249 lcbdata->sc_err = EBUSY;
6250 r = UU_WALK_ERROR;
6251 goto deltemp;
6253 case EEXIST:
6254 warn(emsg_tchg, imp_tsname, inst->sc_name);
6255 lcbdata->sc_err = EBUSY;
6256 r = UU_WALK_ERROR;
6257 goto deltemp;
6259 case ECONNABORTED:
6260 goto connaborted;
6262 case ENOMEM:
6263 case ENOSPC:
6264 case EPERM:
6265 case EROFS:
6266 case EACCES:
6267 case EINVAL:
6268 case EBUSY:
6269 lcbdata->sc_err = r;
6270 r = UU_WALK_ERROR;
6271 goto deltemp;
6273 default:
6274 bad_error("lscf_import_instance_pgs", r);
6277 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6278 inst->sc_name);
6279 if (r < 0)
6280 bad_error("snprintf", errno);
6282 ctx.sc_handle = lcbdata->sc_handle;
6283 ctx.sc_parent = imp_tinst;
6284 ctx.sc_service = 0;
6285 ctx.sc_source_fmri = inst->sc_fmri;
6286 ctx.sc_target_fmri = imp_str;
6287 if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
6288 UU_DEFAULT) != 0) {
6289 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6290 bad_error("uu_list_walk", uu_error());
6292 switch (ctx.sc_err) {
6293 case ECONNABORTED:
6294 goto connaborted;
6296 case ECANCELED:
6297 warn(emsg_tdel, imp_tsname, inst->sc_name);
6298 lcbdata->sc_err = EBUSY;
6299 break;
6301 case EEXIST:
6302 warn(emsg_tchg, imp_tsname, inst->sc_name);
6303 lcbdata->sc_err = EBUSY;
6304 break;
6306 default:
6307 lcbdata->sc_err = ctx.sc_err;
6309 r = UU_WALK_ERROR;
6310 goto deltemp;
6313 if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
6314 inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
6315 switch (scf_error()) {
6316 case SCF_ERROR_CONNECTION_BROKEN:
6317 goto connaborted;
6319 case SCF_ERROR_NO_RESOURCES:
6320 r = stash_scferror(lcbdata);
6321 goto deltemp;
6323 case SCF_ERROR_EXISTS:
6324 warn(emsg_tchg, imp_tsname, inst->sc_name);
6325 lcbdata->sc_err = EBUSY;
6326 r = UU_WALK_ERROR;
6327 goto deltemp;
6329 case SCF_ERROR_PERMISSION_DENIED:
6330 warn(gettext("Could not take \"%s\" snapshot of %s "
6331 "(permission denied).\n"), snap_lastimport,
6332 imp_str);
6333 r = stash_scferror(lcbdata);
6334 goto deltemp;
6336 default:
6337 scfwarn();
6338 lcbdata->sc_err = -1;
6339 r = UU_WALK_ERROR;
6340 goto deltemp;
6342 case SCF_ERROR_HANDLE_MISMATCH:
6343 case SCF_ERROR_INVALID_ARGUMENT:
6344 case SCF_ERROR_NOT_SET:
6345 bad_error("_scf_snapshot_take_new_named", scf_error());
6349 if (lcbdata->sc_flags & SCI_FRESH)
6350 goto fresh;
6352 if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
6353 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6354 imp_lisnap) != 0) {
6355 switch (scf_error()) {
6356 case SCF_ERROR_DELETED:
6357 warn(emsg_del, inst->sc_parent->sc_fmri,
6358 inst->sc_name);
6359 lcbdata->sc_err = EBUSY;
6360 r = UU_WALK_ERROR;
6361 goto deltemp;
6363 case SCF_ERROR_NOT_FOUND:
6364 flags |= SCI_FORCE;
6365 goto nosnap;
6367 case SCF_ERROR_CONNECTION_BROKEN:
6368 goto connaborted;
6370 case SCF_ERROR_INVALID_ARGUMENT:
6371 case SCF_ERROR_HANDLE_MISMATCH:
6372 case SCF_ERROR_NOT_BOUND:
6373 case SCF_ERROR_NOT_SET:
6374 default:
6375 bad_error("scf_instance_get_snapshot",
6376 scf_error());
6380 /* upgrade */
6383 * compare new properties with last-import properties
6384 * upgrade current properties
6386 /* clear sc_sceen for pgs */
6387 if (uu_list_walk(inst->sc_pgroups, clear_int,
6388 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
6390 bad_error("uu_list_walk", uu_error());
6392 r = get_snaplevel(imp_lisnap, 0, imp_snpl);
6393 switch (r) {
6394 case 0:
6395 break;
6397 case ECONNABORTED:
6398 goto connaborted;
6400 case ECANCELED:
6401 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6402 lcbdata->sc_err = EBUSY;
6403 r = UU_WALK_ERROR;
6404 goto deltemp;
6406 case ENOENT:
6407 warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
6408 lcbdata->sc_err = EBADF;
6409 r = UU_WALK_ERROR;
6410 goto deltemp;
6412 default:
6413 bad_error("get_snaplevel", r);
6416 if (scf_instance_get_snapshot(imp_inst, snap_running,
6417 imp_rsnap) != 0) {
6418 switch (scf_error()) {
6419 case SCF_ERROR_DELETED:
6420 warn(emsg_del, inst->sc_parent->sc_fmri,
6421 inst->sc_name);
6422 lcbdata->sc_err = EBUSY;
6423 r = UU_WALK_ERROR;
6424 goto deltemp;
6426 case SCF_ERROR_NOT_FOUND:
6427 break;
6429 case SCF_ERROR_CONNECTION_BROKEN:
6430 goto connaborted;
6432 case SCF_ERROR_INVALID_ARGUMENT:
6433 case SCF_ERROR_HANDLE_MISMATCH:
6434 case SCF_ERROR_NOT_BOUND:
6435 case SCF_ERROR_NOT_SET:
6436 default:
6437 bad_error("scf_instance_get_snapshot",
6438 scf_error());
6441 running = NULL;
6442 } else {
6443 r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
6444 switch (r) {
6445 case 0:
6446 running = imp_rsnpl;
6447 break;
6449 case ECONNABORTED:
6450 goto connaborted;
6452 case ECANCELED:
6453 warn(emsg_del, inst->sc_parent->sc_fmri,
6454 inst->sc_name);
6455 lcbdata->sc_err = EBUSY;
6456 r = UU_WALK_ERROR;
6457 goto deltemp;
6459 case ENOENT:
6460 warn(emsg_badsnap, snap_running, inst->sc_fmri);
6461 lcbdata->sc_err = EBADF;
6462 r = UU_WALK_ERROR;
6463 goto deltemp;
6465 default:
6466 bad_error("get_snaplevel", r);
6470 r = upgrade_props(imp_inst, running, imp_snpl, inst);
6471 switch (r) {
6472 case 0:
6473 break;
6475 case ECANCELED:
6476 case ENODEV:
6477 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6478 lcbdata->sc_err = EBUSY;
6479 r = UU_WALK_ERROR;
6480 goto deltemp;
6482 case ECONNABORTED:
6483 goto connaborted;
6485 case ENOMEM:
6486 case ENOSPC:
6487 case EBADF:
6488 case EBUSY:
6489 case EINVAL:
6490 case EPERM:
6491 case EROFS:
6492 case EACCES:
6493 case EEXIST:
6494 lcbdata->sc_err = r;
6495 r = UU_WALK_ERROR;
6496 goto deltemp;
6498 default:
6499 bad_error("upgrade_props", r);
6502 inst->sc_import_state = IMPORT_PROP_DONE;
6503 } else {
6504 switch (scf_error()) {
6505 case SCF_ERROR_CONNECTION_BROKEN:
6506 goto connaborted;
6508 case SCF_ERROR_NOT_FOUND:
6509 break;
6511 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
6512 case SCF_ERROR_HANDLE_MISMATCH:
6513 case SCF_ERROR_NOT_BOUND:
6514 case SCF_ERROR_NOT_SET:
6515 default:
6516 bad_error("scf_service_get_instance", scf_error());
6519 fresh:
6520 /* create instance */
6521 if (scf_service_add_instance(rsvc, inst->sc_name,
6522 imp_inst) != 0) {
6523 switch (scf_error()) {
6524 case SCF_ERROR_CONNECTION_BROKEN:
6525 goto connaborted;
6527 case SCF_ERROR_NO_RESOURCES:
6528 case SCF_ERROR_BACKEND_READONLY:
6529 case SCF_ERROR_BACKEND_ACCESS:
6530 r = stash_scferror(lcbdata);
6531 goto deltemp;
6533 case SCF_ERROR_EXISTS:
6534 warn(gettext("%s changed unexpectedly "
6535 "(instance \"%s\" added).\n"),
6536 inst->sc_parent->sc_fmri, inst->sc_name);
6537 lcbdata->sc_err = EBUSY;
6538 r = UU_WALK_ERROR;
6539 goto deltemp;
6541 case SCF_ERROR_PERMISSION_DENIED:
6542 warn(gettext("Could not create \"%s\" instance "
6543 "in %s (permission denied).\n"),
6544 inst->sc_name, inst->sc_parent->sc_fmri);
6545 r = stash_scferror(lcbdata);
6546 goto deltemp;
6548 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
6549 case SCF_ERROR_HANDLE_MISMATCH:
6550 case SCF_ERROR_NOT_BOUND:
6551 case SCF_ERROR_NOT_SET:
6552 default:
6553 bad_error("scf_service_add_instance",
6554 scf_error());
6558 nosnap:
6560 * Create a last-import snapshot to serve as an attachment
6561 * point for the real one from the temporary instance. Since
6562 * the contents is irrelevant, take it now, while the instance
6563 * is empty, to minimize svc.configd's work.
6565 if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6566 imp_lisnap) != 0) {
6567 switch (scf_error()) {
6568 case SCF_ERROR_CONNECTION_BROKEN:
6569 goto connaborted;
6571 case SCF_ERROR_NO_RESOURCES:
6572 r = stash_scferror(lcbdata);
6573 goto deltemp;
6575 case SCF_ERROR_EXISTS:
6576 warn(gettext("%s changed unexpectedly "
6577 "(snapshot \"%s\" added).\n"),
6578 inst->sc_fmri, snap_lastimport);
6579 lcbdata->sc_err = EBUSY;
6580 r = UU_WALK_ERROR;
6581 goto deltemp;
6583 case SCF_ERROR_PERMISSION_DENIED:
6584 warn(gettext("Could not take \"%s\" snapshot "
6585 "of %s (permission denied).\n"),
6586 snap_lastimport, inst->sc_fmri);
6587 r = stash_scferror(lcbdata);
6588 goto deltemp;
6590 default:
6591 scfwarn();
6592 lcbdata->sc_err = -1;
6593 r = UU_WALK_ERROR;
6594 goto deltemp;
6596 case SCF_ERROR_NOT_SET:
6597 case SCF_ERROR_INTERNAL:
6598 case SCF_ERROR_INVALID_ARGUMENT:
6599 case SCF_ERROR_HANDLE_MISMATCH:
6600 bad_error("_scf_snapshot_take_new",
6601 scf_error());
6605 if (li_only)
6606 goto lionly;
6608 inst->sc_import_state = IMPORT_PROP_BEGUN;
6610 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6611 flags);
6612 switch (r) {
6613 case 0:
6614 break;
6616 case ECONNABORTED:
6617 goto connaborted;
6619 case ECANCELED:
6620 warn(gettext("%s changed unexpectedly "
6621 "(instance \"%s\" deleted).\n"),
6622 inst->sc_parent->sc_fmri, inst->sc_name);
6623 lcbdata->sc_err = EBUSY;
6624 r = UU_WALK_ERROR;
6625 goto deltemp;
6627 case EEXIST:
6628 warn(gettext("%s changed unexpectedly "
6629 "(property group added).\n"), inst->sc_fmri);
6630 lcbdata->sc_err = EBUSY;
6631 r = UU_WALK_ERROR;
6632 goto deltemp;
6634 default:
6635 lcbdata->sc_err = r;
6636 r = UU_WALK_ERROR;
6637 goto deltemp;
6639 case EINVAL: /* caught above */
6640 bad_error("lscf_import_instance_pgs", r);
6643 ctx.sc_parent = imp_inst;
6644 ctx.sc_service = 0;
6645 ctx.sc_trans = NULL;
6646 ctx.sc_flags = 0;
6647 if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6648 &ctx, UU_DEFAULT) != 0) {
6649 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6650 bad_error("uu_list_walk", uu_error());
6652 if (ctx.sc_err == ECONNABORTED)
6653 goto connaborted;
6654 lcbdata->sc_err = ctx.sc_err;
6655 r = UU_WALK_ERROR;
6656 goto deltemp;
6659 inst->sc_import_state = IMPORT_PROP_DONE;
6661 if (g_verbose)
6662 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6663 snap_initial, inst->sc_fmri);
6664 r = take_snap(imp_inst, snap_initial, imp_snap);
6665 switch (r) {
6666 case 0:
6667 break;
6669 case ECONNABORTED:
6670 goto connaborted;
6672 case ENOSPC:
6673 case -1:
6674 lcbdata->sc_err = r;
6675 r = UU_WALK_ERROR;
6676 goto deltemp;
6678 case ECANCELED:
6679 warn(gettext("%s changed unexpectedly "
6680 "(instance %s deleted).\n"),
6681 inst->sc_parent->sc_fmri, inst->sc_name);
6682 lcbdata->sc_err = r;
6683 r = UU_WALK_ERROR;
6684 goto deltemp;
6686 case EPERM:
6687 warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6688 lcbdata->sc_err = r;
6689 r = UU_WALK_ERROR;
6690 goto deltemp;
6692 default:
6693 bad_error("take_snap", r);
6697 lionly:
6698 if (lcbdata->sc_flags & SCI_NOSNAP)
6699 goto deltemp;
6701 /* transfer snapshot from temporary instance */
6702 if (g_verbose)
6703 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6704 snap_lastimport, inst->sc_fmri);
6705 if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6706 switch (scf_error()) {
6707 case SCF_ERROR_CONNECTION_BROKEN:
6708 goto connaborted;
6710 case SCF_ERROR_NO_RESOURCES:
6711 r = stash_scferror(lcbdata);
6712 goto deltemp;
6714 case SCF_ERROR_PERMISSION_DENIED:
6715 warn(gettext("Could not take \"%s\" snapshot for %s "
6716 "(permission denied).\n"), snap_lastimport,
6717 inst->sc_fmri);
6718 r = stash_scferror(lcbdata);
6719 goto deltemp;
6721 case SCF_ERROR_NOT_SET:
6722 case SCF_ERROR_HANDLE_MISMATCH:
6723 default:
6724 bad_error("_scf_snapshot_attach", scf_error());
6728 inst->sc_import_state = IMPORT_COMPLETE;
6730 r = UU_WALK_NEXT;
6732 deltemp:
6733 /* delete temporary instance */
6734 if (scf_instance_delete(imp_tinst) != 0) {
6735 switch (scf_error()) {
6736 case SCF_ERROR_DELETED:
6737 break;
6739 case SCF_ERROR_CONNECTION_BROKEN:
6740 goto connaborted;
6742 case SCF_ERROR_NOT_SET:
6743 case SCF_ERROR_NOT_BOUND:
6744 default:
6745 bad_error("scf_instance_delete", scf_error());
6749 return (r);
6751 connaborted:
6752 warn(gettext("Could not delete svc:/%s:%s "
6753 "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6754 lcbdata->sc_err = ECONNABORTED;
6755 return (UU_WALK_ERROR);
6759 * When an instance is imported we end up telling configd about it. Once we tell
6760 * configd about these changes, startd eventually notices. If this is a new
6761 * instance, the manifest may not specify the SCF_PG_RESTARTER (restarter)
6762 * property group. However, many of the other tools expect that this property
6763 * group exists and has certain values.
6765 * These values are added asynchronously by startd. We should not return from
6766 * this routine until we can verify that the property group we need is there.
6768 * Before we go ahead and verify this, we have to ask ourselves an important
6769 * question: Is the early manifest service currently running? Because if it is
6770 * running and it has invoked us, then the service will never get a restarter
6771 * property because svc.startd is blocked on EMI finishing before it lets itself
6772 * fully connect to svc.configd. Of course, this means that this race condition
6773 * is in fact impossible to 100% eliminate.
6775 * svc.startd makes sure that EMI only runs once and has succeeded by checking
6776 * the state of the EMI instance. If it is online it bails out and makes sure
6777 * that it doesn't run again. In this case, we're going to do something similar,
6778 * only if the state is online, then we're going to actually verify. EMI always
6779 * has to be present, but it can be explicitly disabled to reduce the amount of
6780 * damage it can cause. If EMI has been disabled then we no longer have to worry
6781 * about the implicit race condition and can go ahead and check things. If EMI
6782 * is in some state that isn't online or disabled and isn't runinng, then we
6783 * assume that things are rather bad and we're not going to get in your way,
6784 * even if the rest of SMF does.
6786 * Returns 0 on success or returns an errno.
6788 #ifndef NATIVE_BUILD
6789 static int
6790 lscf_instance_verify(scf_scope_t *scope, entity_t *svc, entity_t *inst)
6792 int ret, err;
6793 struct timespec ts;
6794 char *emi_state;
6797 * smf_get_state does not distinguish between its different failure
6798 * modes: memory allocation failures and SMF internal failures.
6800 if ((emi_state = smf_get_state(SCF_INSTANCE_EMI)) == NULL)
6801 return (EAGAIN);
6804 * As per the block comment for this function check the state of EMI
6806 if (strcmp(emi_state, SCF_STATE_STRING_ONLINE) != 0 &&
6807 strcmp(emi_state, SCF_STATE_STRING_DISABLED) != 0) {
6808 warn(gettext("Not validating instance %s:%s because EMI's "
6809 "state is %s\n"), svc->sc_name, inst->sc_name, emi_state);
6810 free(emi_state);
6811 return (0);
6814 free(emi_state);
6817 * First we have to get the property.
6819 if ((ret = scf_scope_get_service(scope, svc->sc_name, imp_svc)) != 0) {
6820 ret = scf_error();
6821 warn(gettext("Failed to look up service: %s\n"), svc->sc_name);
6822 return (ret);
6826 * We should always be able to get the instance. It should already
6827 * exist because we just created it or got it. There probably is a
6828 * slim chance that someone may have come in and deleted it though from
6829 * under us.
6831 if ((ret = scf_service_get_instance(imp_svc, inst->sc_name, imp_inst))
6832 != 0) {
6833 ret = scf_error();
6834 warn(gettext("Failed to verify instance: %s\n"), inst->sc_name);
6835 switch (ret) {
6836 case SCF_ERROR_DELETED:
6837 err = ENODEV;
6838 break;
6839 case SCF_ERROR_CONNECTION_BROKEN:
6840 warn(gettext("Lost repository connection\n"));
6841 err = ECONNABORTED;
6842 break;
6843 case SCF_ERROR_NOT_FOUND:
6844 warn(gettext("Instance \"%s\" disappeared out from "
6845 "under us.\n"), inst->sc_name);
6846 err = ENOENT;
6847 break;
6848 default:
6849 bad_error("scf_service_get_instance", ret);
6852 return (err);
6856 * An astute observer may want to use _scf_wait_pg which would notify us
6857 * of a property group change, unfortunately that does not work if the
6858 * property group in question does not exist. So instead we have to
6859 * manually poll and ask smf the best way to get to it.
6861 while ((ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg))
6862 != SCF_SUCCESS) {
6863 ret = scf_error();
6864 if (ret != SCF_ERROR_NOT_FOUND) {
6865 warn(gettext("Failed to get restarter property "
6866 "group for instance: %s\n"), inst->sc_name);
6867 switch (ret) {
6868 case SCF_ERROR_DELETED:
6869 err = ENODEV;
6870 break;
6871 case SCF_ERROR_CONNECTION_BROKEN:
6872 warn(gettext("Lost repository connection\n"));
6873 err = ECONNABORTED;
6874 break;
6875 default:
6876 bad_error("scf_service_get_instance", ret);
6879 return (err);
6882 ts.tv_sec = pg_timeout / NANOSEC;
6883 ts.tv_nsec = pg_timeout % NANOSEC;
6885 (void) nanosleep(&ts, NULL);
6889 * svcadm also expects that the SCF_PROPERTY_STATE property is present.
6890 * So in addition to the property group being present, we need to wait
6891 * for the property to be there in some form.
6893 * Note that a property group is a frozen snapshot in time. To properly
6894 * get beyond this, you have to refresh the property group each time.
6896 while ((ret = scf_pg_get_property(imp_pg, SCF_PROPERTY_STATE,
6897 imp_prop)) != 0) {
6899 ret = scf_error();
6900 if (ret != SCF_ERROR_NOT_FOUND) {
6901 warn(gettext("Failed to get property %s from the "
6902 "restarter property group of instance %s\n"),
6903 SCF_PROPERTY_STATE, inst->sc_name);
6904 switch (ret) {
6905 case SCF_ERROR_CONNECTION_BROKEN:
6906 warn(gettext("Lost repository connection\n"));
6907 err = ECONNABORTED;
6908 break;
6909 case SCF_ERROR_DELETED:
6910 err = ENODEV;
6911 break;
6912 default:
6913 bad_error("scf_pg_get_property", ret);
6916 return (err);
6919 ts.tv_sec = pg_timeout / NANOSEC;
6920 ts.tv_nsec = pg_timeout % NANOSEC;
6922 (void) nanosleep(&ts, NULL);
6924 ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg);
6925 if (ret != SCF_SUCCESS) {
6926 warn(gettext("Failed to get restarter property "
6927 "group for instance: %s\n"), inst->sc_name);
6928 switch (ret) {
6929 case SCF_ERROR_DELETED:
6930 err = ENODEV;
6931 break;
6932 case SCF_ERROR_CONNECTION_BROKEN:
6933 warn(gettext("Lost repository connection\n"));
6934 err = ECONNABORTED;
6935 break;
6936 default:
6937 bad_error("scf_service_get_instance", ret);
6940 return (err);
6945 * We don't have to free the property groups or other values that we got
6946 * because we stored them in global variables that are allocated and
6947 * freed by the routines that call into these functions. Unless of
6948 * course the rest of the code here that we are basing this on is
6949 * mistaken.
6951 return (0);
6953 #endif
6956 * If the service is missing, create it, import its properties, and import the
6957 * instances. Since the service is brand new, it should be empty, and if we
6958 * run into any existing entities (SCF_ERROR_EXISTS), abort.
6960 * If the service exists, we want to upgrade its properties and import the
6961 * instances. Upgrade requires a last-import snapshot, though, which are
6962 * children of instances, so first we'll have to go through the instances
6963 * looking for a last-import snapshot. If we don't find one then we'll just
6964 * override-import the service properties (but don't delete existing
6965 * properties: another service might have declared us as a dependent). Before
6966 * we change anything, though, we want to take the previous snapshots. We
6967 * also give lscf_instance_import() a leg up on taking last-import snapshots
6968 * by importing the manifest's service properties into a temporary service.
6970 * On success, returns UU_WALK_NEXT. On failure, returns UU_WALK_ERROR and
6971 * sets lcbdata->sc_err to
6972 * ECONNABORTED - repository connection broken
6973 * ENOMEM - out of memory
6974 * ENOSPC - svc.configd is out of resources
6975 * EPERM - couldn't create temporary service (error printed)
6976 * - couldn't import into temp service (error printed)
6977 * - couldn't create service (error printed)
6978 * - couldn't import dependent (error printed)
6979 * - couldn't take snapshot (error printed)
6980 * - couldn't create instance (error printed)
6981 * - couldn't create, modify, or delete pg (error printed)
6982 * - couldn't create, modify, or delete dependent (error printed)
6983 * - couldn't import instance (error printed)
6984 * EROFS - couldn't create temporary service (repository read-only)
6985 * - couldn't import into temporary service (repository read-only)
6986 * - couldn't create service (repository read-only)
6987 * - couldn't import dependent (repository read-only)
6988 * - couldn't create instance (repository read-only)
6989 * - couldn't create, modify, or delete pg or dependent
6990 * - couldn't import instance (repository read-only)
6991 * EACCES - couldn't create temporary service (backend access denied)
6992 * - couldn't import into temporary service (backend access denied)
6993 * - couldn't create service (backend access denied)
6994 * - couldn't import dependent (backend access denied)
6995 * - couldn't create instance (backend access denied)
6996 * - couldn't create, modify, or delete pg or dependent
6997 * - couldn't import instance (backend access denied)
6998 * EINVAL - service name is invalid (error printed)
6999 * - service name is too long (error printed)
7000 * - s has invalid pgroup (error printed)
7001 * - s has invalid dependent (error printed)
7002 * - instance name is invalid (error printed)
7003 * - instance entity_t is invalid (error printed)
7004 * EEXIST - couldn't create temporary service (already exists) (error printed)
7005 * - couldn't import dependent (dependency pg already exists) (printed)
7006 * - dependency collision in dependent service (error printed)
7007 * EBUSY - temporary service deleted (error printed)
7008 * - property group added to temporary service (error printed)
7009 * - new property group changed or was deleted (error printed)
7010 * - service was added unexpectedly (error printed)
7011 * - service was deleted unexpectedly (error printed)
7012 * - property group added to new service (error printed)
7013 * - instance added unexpectedly (error printed)
7014 * - instance deleted unexpectedly (error printed)
7015 * - dependent service deleted unexpectedly (error printed)
7016 * - pg was added, changed, or deleted (error printed)
7017 * - dependent pg changed (error printed)
7018 * - temporary instance added, changed, or deleted (error printed)
7019 * EBADF - a last-import snapshot is corrupt (error printed)
7020 * - the service is corrupt (error printed)
7021 * - a dependent is corrupt (error printed)
7022 * - an instance is corrupt (error printed)
7023 * - an instance has a corrupt last-import snapshot (error printed)
7024 * - dependent target has a corrupt snapshot (error printed)
7025 * -1 - unknown libscf error (error printed)
7027 static int
7028 lscf_service_import(void *v, void *pvt)
7030 entity_t *s = v;
7031 scf_callback_t cbdata;
7032 scf_callback_t *lcbdata = pvt;
7033 scf_scope_t *scope = lcbdata->sc_parent;
7034 entity_t *inst, linst;
7035 int r;
7036 int fresh = 0;
7037 scf_snaplevel_t *running;
7038 int have_ge = 0;
7039 boolean_t retried = B_FALSE;
7041 const char * const ts_deleted = gettext("Temporary service svc:/%s "
7042 "was deleted unexpectedly.\n");
7043 const char * const ts_pg_added = gettext("Temporary service svc:/%s "
7044 "changed unexpectedly (property group added).\n");
7045 const char * const s_deleted =
7046 gettext("%s was deleted unexpectedly.\n");
7047 const char * const i_deleted =
7048 gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
7049 const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
7050 "is corrupt (missing service snaplevel).\n");
7051 const char * const s_mfile_upd =
7052 gettext("Unable to update the manifest file connection "
7053 "for %s\n");
7055 li_only = 0;
7056 /* Validate the service name */
7057 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7058 switch (scf_error()) {
7059 case SCF_ERROR_CONNECTION_BROKEN:
7060 return (stash_scferror(lcbdata));
7062 case SCF_ERROR_INVALID_ARGUMENT:
7063 warn(gettext("\"%s\" is an invalid service name. "
7064 "Cannot import.\n"), s->sc_name);
7065 return (stash_scferror(lcbdata));
7067 case SCF_ERROR_NOT_FOUND:
7068 break;
7070 case SCF_ERROR_HANDLE_MISMATCH:
7071 case SCF_ERROR_NOT_BOUND:
7072 case SCF_ERROR_NOT_SET:
7073 default:
7074 bad_error("scf_scope_get_service", scf_error());
7078 /* create temporary service */
7080 * the size of the buffer was reduced to max_scf_name_len to prevent
7081 * hitting bug 6681151. After the bug fix, the size of the buffer
7082 * should be restored to its original value (max_scf_name_len +1)
7084 r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
7085 if (r < 0)
7086 bad_error("snprintf", errno);
7087 if (r > max_scf_name_len) {
7088 warn(gettext(
7089 "Service name \"%s\" is too long. Cannot import.\n"),
7090 s->sc_name);
7091 lcbdata->sc_err = EINVAL;
7092 return (UU_WALK_ERROR);
7095 retry:
7096 if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
7097 switch (scf_error()) {
7098 case SCF_ERROR_CONNECTION_BROKEN:
7099 case SCF_ERROR_NO_RESOURCES:
7100 case SCF_ERROR_BACKEND_READONLY:
7101 case SCF_ERROR_BACKEND_ACCESS:
7102 return (stash_scferror(lcbdata));
7104 case SCF_ERROR_EXISTS:
7105 if (!retried) {
7106 lscf_delete(imp_tsname, 0);
7107 retried = B_TRUE;
7108 goto retry;
7110 warn(gettext(
7111 "Temporary service \"%s\" must be deleted before "
7112 "this manifest can be imported.\n"), imp_tsname);
7113 return (stash_scferror(lcbdata));
7115 case SCF_ERROR_PERMISSION_DENIED:
7116 warn(gettext("Could not create temporary service "
7117 "\"%s\" (permission denied).\n"), imp_tsname);
7118 return (stash_scferror(lcbdata));
7120 case SCF_ERROR_INVALID_ARGUMENT:
7121 case SCF_ERROR_HANDLE_MISMATCH:
7122 case SCF_ERROR_NOT_BOUND:
7123 case SCF_ERROR_NOT_SET:
7124 default:
7125 bad_error("scf_scope_add_service", scf_error());
7129 r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
7130 if (r < 0)
7131 bad_error("snprintf", errno);
7133 cbdata.sc_handle = lcbdata->sc_handle;
7134 cbdata.sc_parent = imp_tsvc;
7135 cbdata.sc_service = 1;
7136 cbdata.sc_source_fmri = s->sc_fmri;
7137 cbdata.sc_target_fmri = imp_str;
7138 cbdata.sc_flags = 0;
7140 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
7141 UU_DEFAULT) != 0) {
7142 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7143 bad_error("uu_list_walk", uu_error());
7145 lcbdata->sc_err = cbdata.sc_err;
7146 switch (cbdata.sc_err) {
7147 case ECONNABORTED:
7148 goto connaborted;
7150 case ECANCELED:
7151 warn(ts_deleted, imp_tsname);
7152 lcbdata->sc_err = EBUSY;
7153 return (UU_WALK_ERROR);
7155 case EEXIST:
7156 warn(ts_pg_added, imp_tsname);
7157 lcbdata->sc_err = EBUSY;
7158 return (UU_WALK_ERROR);
7161 r = UU_WALK_ERROR;
7162 goto deltemp;
7165 if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
7166 UU_DEFAULT) != 0) {
7167 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7168 bad_error("uu_list_walk", uu_error());
7170 lcbdata->sc_err = cbdata.sc_err;
7171 switch (cbdata.sc_err) {
7172 case ECONNABORTED:
7173 goto connaborted;
7175 case ECANCELED:
7176 warn(ts_deleted, imp_tsname);
7177 lcbdata->sc_err = EBUSY;
7178 return (UU_WALK_ERROR);
7180 case EEXIST:
7181 warn(ts_pg_added, imp_tsname);
7182 lcbdata->sc_err = EBUSY;
7183 return (UU_WALK_ERROR);
7186 r = UU_WALK_ERROR;
7187 goto deltemp;
7190 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7191 switch (scf_error()) {
7192 case SCF_ERROR_NOT_FOUND:
7193 break;
7195 case SCF_ERROR_CONNECTION_BROKEN:
7196 goto connaborted;
7198 case SCF_ERROR_INVALID_ARGUMENT:
7199 case SCF_ERROR_HANDLE_MISMATCH:
7200 case SCF_ERROR_NOT_BOUND:
7201 case SCF_ERROR_NOT_SET:
7202 default:
7203 bad_error("scf_scope_get_service", scf_error());
7206 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
7207 switch (scf_error()) {
7208 case SCF_ERROR_CONNECTION_BROKEN:
7209 goto connaborted;
7211 case SCF_ERROR_NO_RESOURCES:
7212 case SCF_ERROR_BACKEND_READONLY:
7213 case SCF_ERROR_BACKEND_ACCESS:
7214 r = stash_scferror(lcbdata);
7215 goto deltemp;
7217 case SCF_ERROR_EXISTS:
7218 warn(gettext("Scope \"%s\" changed unexpectedly"
7219 " (service \"%s\" added).\n"),
7220 SCF_SCOPE_LOCAL, s->sc_name);
7221 lcbdata->sc_err = EBUSY;
7222 goto deltemp;
7224 case SCF_ERROR_PERMISSION_DENIED:
7225 warn(gettext("Could not create service \"%s\" "
7226 "(permission denied).\n"), s->sc_name);
7227 goto deltemp;
7229 case SCF_ERROR_INVALID_ARGUMENT:
7230 case SCF_ERROR_HANDLE_MISMATCH:
7231 case SCF_ERROR_NOT_BOUND:
7232 case SCF_ERROR_NOT_SET:
7233 default:
7234 bad_error("scf_scope_add_service", scf_error());
7238 s->sc_import_state = IMPORT_PROP_BEGUN;
7240 /* import service properties */
7241 cbdata.sc_handle = lcbdata->sc_handle;
7242 cbdata.sc_parent = imp_svc;
7243 cbdata.sc_service = 1;
7244 cbdata.sc_flags = lcbdata->sc_flags;
7245 cbdata.sc_source_fmri = s->sc_fmri;
7246 cbdata.sc_target_fmri = s->sc_fmri;
7248 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7249 &cbdata, UU_DEFAULT) != 0) {
7250 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7251 bad_error("uu_list_walk", uu_error());
7253 lcbdata->sc_err = cbdata.sc_err;
7254 switch (cbdata.sc_err) {
7255 case ECONNABORTED:
7256 goto connaborted;
7258 case ECANCELED:
7259 warn(s_deleted, s->sc_fmri);
7260 lcbdata->sc_err = EBUSY;
7261 return (UU_WALK_ERROR);
7263 case EEXIST:
7264 warn(gettext("%s changed unexpectedly "
7265 "(property group added).\n"), s->sc_fmri);
7266 lcbdata->sc_err = EBUSY;
7267 return (UU_WALK_ERROR);
7269 case EINVAL:
7270 /* caught above */
7271 bad_error("entity_pgroup_import",
7272 cbdata.sc_err);
7275 r = UU_WALK_ERROR;
7276 goto deltemp;
7279 cbdata.sc_trans = NULL;
7280 cbdata.sc_flags = 0;
7281 if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
7282 &cbdata, UU_DEFAULT) != 0) {
7283 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7284 bad_error("uu_list_walk", uu_error());
7286 lcbdata->sc_err = cbdata.sc_err;
7287 if (cbdata.sc_err == ECONNABORTED)
7288 goto connaborted;
7289 r = UU_WALK_ERROR;
7290 goto deltemp;
7293 s->sc_import_state = IMPORT_PROP_DONE;
7296 * This is a new service, so we can't take previous snapshots
7297 * or upgrade service properties.
7299 fresh = 1;
7300 goto instances;
7303 /* Clear sc_seen for the instances. */
7304 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
7305 (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
7306 bad_error("uu_list_walk", uu_error());
7309 * Take previous snapshots for all instances. Even for ones not
7310 * mentioned in the bundle, since we might change their service
7311 * properties.
7313 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7314 switch (scf_error()) {
7315 case SCF_ERROR_CONNECTION_BROKEN:
7316 goto connaborted;
7318 case SCF_ERROR_DELETED:
7319 warn(s_deleted, s->sc_fmri);
7320 lcbdata->sc_err = EBUSY;
7321 r = UU_WALK_ERROR;
7322 goto deltemp;
7324 case SCF_ERROR_HANDLE_MISMATCH:
7325 case SCF_ERROR_NOT_BOUND:
7326 case SCF_ERROR_NOT_SET:
7327 default:
7328 bad_error("scf_iter_service_instances", scf_error());
7332 for (;;) {
7333 r = scf_iter_next_instance(imp_iter, imp_inst);
7334 if (r == 0)
7335 break;
7336 if (r != 1) {
7337 switch (scf_error()) {
7338 case SCF_ERROR_DELETED:
7339 warn(s_deleted, s->sc_fmri);
7340 lcbdata->sc_err = EBUSY;
7341 r = UU_WALK_ERROR;
7342 goto deltemp;
7344 case SCF_ERROR_CONNECTION_BROKEN:
7345 goto connaborted;
7347 case SCF_ERROR_NOT_BOUND:
7348 case SCF_ERROR_HANDLE_MISMATCH:
7349 case SCF_ERROR_INVALID_ARGUMENT:
7350 case SCF_ERROR_NOT_SET:
7351 default:
7352 bad_error("scf_iter_next_instance",
7353 scf_error());
7357 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
7358 switch (scf_error()) {
7359 case SCF_ERROR_DELETED:
7360 continue;
7362 case SCF_ERROR_CONNECTION_BROKEN:
7363 goto connaborted;
7365 case SCF_ERROR_NOT_SET:
7366 case SCF_ERROR_NOT_BOUND:
7367 default:
7368 bad_error("scf_instance_get_name", scf_error());
7372 if (g_verbose)
7373 warn(gettext(
7374 "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
7375 snap_previous, s->sc_name, imp_str);
7377 r = take_snap(imp_inst, snap_previous, imp_snap);
7378 switch (r) {
7379 case 0:
7380 break;
7382 case ECANCELED:
7383 continue;
7385 case ECONNABORTED:
7386 goto connaborted;
7388 case EPERM:
7389 warn(gettext("Could not take \"%s\" snapshot of "
7390 "svc:/%s:%s (permission denied).\n"),
7391 snap_previous, s->sc_name, imp_str);
7392 lcbdata->sc_err = r;
7393 return (UU_WALK_ERROR);
7395 case ENOSPC:
7396 case -1:
7397 lcbdata->sc_err = r;
7398 r = UU_WALK_ERROR;
7399 goto deltemp;
7401 default:
7402 bad_error("take_snap", r);
7405 linst.sc_name = imp_str;
7406 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
7407 &linst, NULL, NULL);
7408 if (inst != NULL) {
7409 inst->sc_import_state = IMPORT_PREVIOUS;
7410 inst->sc_seen = 1;
7415 * Create the new instances and take previous snapshots of
7416 * them. This is not necessary, but it maximizes data preservation.
7418 for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
7419 inst != NULL;
7420 inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
7421 inst)) {
7422 if (inst->sc_seen)
7423 continue;
7425 if (scf_service_add_instance(imp_svc, inst->sc_name,
7426 imp_inst) != 0) {
7427 switch (scf_error()) {
7428 case SCF_ERROR_CONNECTION_BROKEN:
7429 goto connaborted;
7431 case SCF_ERROR_BACKEND_READONLY:
7432 case SCF_ERROR_BACKEND_ACCESS:
7433 case SCF_ERROR_NO_RESOURCES:
7434 r = stash_scferror(lcbdata);
7435 goto deltemp;
7437 case SCF_ERROR_EXISTS:
7438 warn(gettext("%s changed unexpectedly "
7439 "(instance \"%s\" added).\n"), s->sc_fmri,
7440 inst->sc_name);
7441 lcbdata->sc_err = EBUSY;
7442 r = UU_WALK_ERROR;
7443 goto deltemp;
7445 case SCF_ERROR_INVALID_ARGUMENT:
7446 warn(gettext("Service \"%s\" has instance with "
7447 "invalid name \"%s\".\n"), s->sc_name,
7448 inst->sc_name);
7449 r = stash_scferror(lcbdata);
7450 goto deltemp;
7452 case SCF_ERROR_PERMISSION_DENIED:
7453 warn(gettext("Could not create instance \"%s\" "
7454 "in %s (permission denied).\n"),
7455 inst->sc_name, s->sc_fmri);
7456 r = stash_scferror(lcbdata);
7457 goto deltemp;
7459 case SCF_ERROR_HANDLE_MISMATCH:
7460 case SCF_ERROR_NOT_BOUND:
7461 case SCF_ERROR_NOT_SET:
7462 default:
7463 bad_error("scf_service_add_instance",
7464 scf_error());
7468 if (g_verbose)
7469 warn(gettext("Taking \"%s\" snapshot for "
7470 "new service %s.\n"), snap_previous, inst->sc_fmri);
7471 r = take_snap(imp_inst, snap_previous, imp_snap);
7472 switch (r) {
7473 case 0:
7474 break;
7476 case ECANCELED:
7477 warn(i_deleted, s->sc_fmri, inst->sc_name);
7478 lcbdata->sc_err = EBUSY;
7479 r = UU_WALK_ERROR;
7480 goto deltemp;
7482 case ECONNABORTED:
7483 goto connaborted;
7485 case EPERM:
7486 warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
7487 lcbdata->sc_err = r;
7488 r = UU_WALK_ERROR;
7489 goto deltemp;
7491 case ENOSPC:
7492 case -1:
7493 r = UU_WALK_ERROR;
7494 goto deltemp;
7496 default:
7497 bad_error("take_snap", r);
7501 s->sc_import_state = IMPORT_PREVIOUS;
7504 * Upgrade service properties, if we can find a last-import snapshot.
7505 * Any will do because we don't support different service properties
7506 * in different manifests, so all snaplevels of the service in all of
7507 * the last-import snapshots of the instances should be the same.
7509 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7510 switch (scf_error()) {
7511 case SCF_ERROR_CONNECTION_BROKEN:
7512 goto connaborted;
7514 case SCF_ERROR_DELETED:
7515 warn(s_deleted, s->sc_fmri);
7516 lcbdata->sc_err = EBUSY;
7517 r = UU_WALK_ERROR;
7518 goto deltemp;
7520 case SCF_ERROR_HANDLE_MISMATCH:
7521 case SCF_ERROR_NOT_BOUND:
7522 case SCF_ERROR_NOT_SET:
7523 default:
7524 bad_error("scf_iter_service_instances", scf_error());
7528 for (;;) {
7529 r = scf_iter_next_instance(imp_iter, imp_inst);
7530 if (r == -1) {
7531 switch (scf_error()) {
7532 case SCF_ERROR_DELETED:
7533 warn(s_deleted, s->sc_fmri);
7534 lcbdata->sc_err = EBUSY;
7535 r = UU_WALK_ERROR;
7536 goto deltemp;
7538 case SCF_ERROR_CONNECTION_BROKEN:
7539 goto connaborted;
7541 case SCF_ERROR_NOT_BOUND:
7542 case SCF_ERROR_HANDLE_MISMATCH:
7543 case SCF_ERROR_INVALID_ARGUMENT:
7544 case SCF_ERROR_NOT_SET:
7545 default:
7546 bad_error("scf_iter_next_instance",
7547 scf_error());
7551 if (r == 0) {
7553 * Didn't find any last-import snapshots. Override-
7554 * import the properties. Unless one of the instances
7555 * has a general/enabled property, in which case we're
7556 * probably running a last-import-capable svccfg for
7557 * the first time, and we should only take the
7558 * last-import snapshot.
7560 if (have_ge) {
7561 pgroup_t *mfpg;
7562 scf_callback_t mfcbdata;
7564 li_only = 1;
7565 no_refresh = 1;
7567 * Need to go ahead and import the manifestfiles
7568 * pg if it exists. If the last-import snapshot
7569 * upgrade code is ever removed this code can
7570 * be removed as well.
7572 mfpg = internal_pgroup_find(s,
7573 SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
7575 if (mfpg) {
7576 mfcbdata.sc_handle = g_hndl;
7577 mfcbdata.sc_parent = imp_svc;
7578 mfcbdata.sc_service = 1;
7579 mfcbdata.sc_flags = SCI_FORCE;
7580 mfcbdata.sc_source_fmri = s->sc_fmri;
7581 mfcbdata.sc_target_fmri = s->sc_fmri;
7582 if (entity_pgroup_import(mfpg,
7583 &mfcbdata) != UU_WALK_NEXT) {
7584 warn(s_mfile_upd, s->sc_fmri);
7585 r = UU_WALK_ERROR;
7586 goto deltemp;
7589 break;
7592 s->sc_import_state = IMPORT_PROP_BEGUN;
7594 cbdata.sc_handle = g_hndl;
7595 cbdata.sc_parent = imp_svc;
7596 cbdata.sc_service = 1;
7597 cbdata.sc_flags = SCI_FORCE;
7598 cbdata.sc_source_fmri = s->sc_fmri;
7599 cbdata.sc_target_fmri = s->sc_fmri;
7600 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7601 &cbdata, UU_DEFAULT) != 0) {
7602 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7603 bad_error("uu_list_walk", uu_error());
7604 lcbdata->sc_err = cbdata.sc_err;
7605 switch (cbdata.sc_err) {
7606 case ECONNABORTED:
7607 goto connaborted;
7609 case ECANCELED:
7610 warn(s_deleted, s->sc_fmri);
7611 lcbdata->sc_err = EBUSY;
7612 break;
7614 case EINVAL: /* caught above */
7615 case EEXIST:
7616 bad_error("entity_pgroup_import",
7617 cbdata.sc_err);
7620 r = UU_WALK_ERROR;
7621 goto deltemp;
7624 cbdata.sc_trans = NULL;
7625 cbdata.sc_flags = 0;
7626 if (uu_list_walk(s->sc_dependents,
7627 lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
7628 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7629 bad_error("uu_list_walk", uu_error());
7630 lcbdata->sc_err = cbdata.sc_err;
7631 if (cbdata.sc_err == ECONNABORTED)
7632 goto connaborted;
7633 r = UU_WALK_ERROR;
7634 goto deltemp;
7636 break;
7639 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
7640 imp_snap) != 0) {
7641 switch (scf_error()) {
7642 case SCF_ERROR_DELETED:
7643 continue;
7645 case SCF_ERROR_NOT_FOUND:
7646 break;
7648 case SCF_ERROR_CONNECTION_BROKEN:
7649 goto connaborted;
7651 case SCF_ERROR_HANDLE_MISMATCH:
7652 case SCF_ERROR_NOT_BOUND:
7653 case SCF_ERROR_INVALID_ARGUMENT:
7654 case SCF_ERROR_NOT_SET:
7655 default:
7656 bad_error("scf_instance_get_snapshot",
7657 scf_error());
7660 if (have_ge)
7661 continue;
7664 * Check for a general/enabled property. This is how
7665 * we tell whether to import if there turn out to be
7666 * no last-import snapshots.
7668 if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
7669 imp_pg) == 0) {
7670 if (scf_pg_get_property(imp_pg,
7671 SCF_PROPERTY_ENABLED, imp_prop) == 0) {
7672 have_ge = 1;
7673 } else {
7674 switch (scf_error()) {
7675 case SCF_ERROR_DELETED:
7676 case SCF_ERROR_NOT_FOUND:
7677 continue;
7679 case SCF_ERROR_INVALID_ARGUMENT:
7680 case SCF_ERROR_HANDLE_MISMATCH:
7681 case SCF_ERROR_CONNECTION_BROKEN:
7682 case SCF_ERROR_NOT_BOUND:
7683 case SCF_ERROR_NOT_SET:
7684 default:
7685 bad_error("scf_pg_get_property",
7686 scf_error());
7689 } else {
7690 switch (scf_error()) {
7691 case SCF_ERROR_DELETED:
7692 case SCF_ERROR_NOT_FOUND:
7693 continue;
7695 case SCF_ERROR_CONNECTION_BROKEN:
7696 goto connaborted;
7698 case SCF_ERROR_NOT_BOUND:
7699 case SCF_ERROR_NOT_SET:
7700 case SCF_ERROR_INVALID_ARGUMENT:
7701 case SCF_ERROR_HANDLE_MISMATCH:
7702 default:
7703 bad_error("scf_instance_get_pg",
7704 scf_error());
7707 continue;
7710 /* find service snaplevel */
7711 r = get_snaplevel(imp_snap, 1, imp_snpl);
7712 switch (r) {
7713 case 0:
7714 break;
7716 case ECONNABORTED:
7717 goto connaborted;
7719 case ECANCELED:
7720 continue;
7722 case ENOENT:
7723 if (scf_instance_get_name(imp_inst, imp_str,
7724 imp_str_sz) < 0)
7725 (void) strcpy(imp_str, "?");
7726 warn(badsnap, snap_lastimport, s->sc_name, imp_str);
7727 lcbdata->sc_err = EBADF;
7728 r = UU_WALK_ERROR;
7729 goto deltemp;
7731 default:
7732 bad_error("get_snaplevel", r);
7735 if (scf_instance_get_snapshot(imp_inst, snap_running,
7736 imp_rsnap) != 0) {
7737 switch (scf_error()) {
7738 case SCF_ERROR_DELETED:
7739 continue;
7741 case SCF_ERROR_NOT_FOUND:
7742 break;
7744 case SCF_ERROR_CONNECTION_BROKEN:
7745 goto connaborted;
7747 case SCF_ERROR_INVALID_ARGUMENT:
7748 case SCF_ERROR_HANDLE_MISMATCH:
7749 case SCF_ERROR_NOT_BOUND:
7750 case SCF_ERROR_NOT_SET:
7751 default:
7752 bad_error("scf_instance_get_snapshot",
7753 scf_error());
7755 running = NULL;
7756 } else {
7757 r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
7758 switch (r) {
7759 case 0:
7760 running = imp_rsnpl;
7761 break;
7763 case ECONNABORTED:
7764 goto connaborted;
7766 case ECANCELED:
7767 continue;
7769 case ENOENT:
7770 if (scf_instance_get_name(imp_inst, imp_str,
7771 imp_str_sz) < 0)
7772 (void) strcpy(imp_str, "?");
7773 warn(badsnap, snap_running, s->sc_name,
7774 imp_str);
7775 lcbdata->sc_err = EBADF;
7776 r = UU_WALK_ERROR;
7777 goto deltemp;
7779 default:
7780 bad_error("get_snaplevel", r);
7784 if (g_verbose) {
7785 if (scf_instance_get_name(imp_inst, imp_str,
7786 imp_str_sz) < 0)
7787 (void) strcpy(imp_str, "?");
7788 warn(gettext("Upgrading properties of %s according to "
7789 "instance \"%s\".\n"), s->sc_fmri, imp_str);
7792 /* upgrade service properties */
7793 r = upgrade_props(imp_svc, running, imp_snpl, s);
7794 if (r == 0)
7795 break;
7797 switch (r) {
7798 case ECONNABORTED:
7799 goto connaborted;
7801 case ECANCELED:
7802 warn(s_deleted, s->sc_fmri);
7803 lcbdata->sc_err = EBUSY;
7804 break;
7806 case ENODEV:
7807 if (scf_instance_get_name(imp_inst, imp_str,
7808 imp_str_sz) < 0)
7809 (void) strcpy(imp_str, "?");
7810 warn(i_deleted, s->sc_fmri, imp_str);
7811 lcbdata->sc_err = EBUSY;
7812 break;
7814 default:
7815 lcbdata->sc_err = r;
7818 r = UU_WALK_ERROR;
7819 goto deltemp;
7822 s->sc_import_state = IMPORT_PROP_DONE;
7824 instances:
7825 /* import instances */
7826 cbdata.sc_handle = lcbdata->sc_handle;
7827 cbdata.sc_parent = imp_svc;
7828 cbdata.sc_service = 1;
7829 cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7830 cbdata.sc_general = NULL;
7832 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7833 lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7834 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7835 bad_error("uu_list_walk", uu_error());
7837 lcbdata->sc_err = cbdata.sc_err;
7838 if (cbdata.sc_err == ECONNABORTED)
7839 goto connaborted;
7840 r = UU_WALK_ERROR;
7841 goto deltemp;
7844 s->sc_import_state = IMPORT_COMPLETE;
7845 r = UU_WALK_NEXT;
7847 deltemp:
7848 /* delete temporary service */
7849 if (scf_service_delete(imp_tsvc) != 0) {
7850 switch (scf_error()) {
7851 case SCF_ERROR_DELETED:
7852 break;
7854 case SCF_ERROR_CONNECTION_BROKEN:
7855 goto connaborted;
7857 case SCF_ERROR_EXISTS:
7858 warn(gettext(
7859 "Could not delete svc:/%s (instances exist).\n"),
7860 imp_tsname);
7861 break;
7863 case SCF_ERROR_NOT_SET:
7864 case SCF_ERROR_NOT_BOUND:
7865 default:
7866 bad_error("scf_service_delete", scf_error());
7870 return (r);
7872 connaborted:
7873 warn(gettext("Could not delete svc:/%s "
7874 "(repository connection broken).\n"), imp_tsname);
7875 lcbdata->sc_err = ECONNABORTED;
7876 return (UU_WALK_ERROR);
7879 static const char *
7880 import_progress(int st)
7882 switch (st) {
7883 case 0:
7884 return (gettext("not reached."));
7886 case IMPORT_PREVIOUS:
7887 return (gettext("previous snapshot taken."));
7889 case IMPORT_PROP_BEGUN:
7890 return (gettext("some properties imported."));
7892 case IMPORT_PROP_DONE:
7893 return (gettext("properties imported."));
7895 case IMPORT_COMPLETE:
7896 return (gettext("imported."));
7898 case IMPORT_REFRESHED:
7899 return (gettext("refresh requested."));
7901 default:
7902 #ifndef NDEBUG
7903 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7904 __FILE__, __LINE__, st);
7905 #endif
7906 abort();
7907 /* NOTREACHED */
7912 * Returns
7913 * 0 - success
7914 * - fmri wasn't found (error printed)
7915 * - entity was deleted (error printed)
7916 * - backend denied access (error printed)
7917 * ENOMEM - out of memory (error printed)
7918 * ECONNABORTED - repository connection broken (error printed)
7919 * EPERM - permission denied (error printed)
7920 * -1 - unknown libscf error (error printed)
7922 static int
7923 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7925 scf_error_t serr;
7926 void *ent;
7927 int issvc;
7928 int r;
7930 const char *deleted = gettext("Could not refresh %s (deleted).\n");
7931 const char *dpt_deleted = gettext("Could not refresh %s "
7932 "(dependent \"%s\" of %s) (deleted).\n");
7934 serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7935 switch (serr) {
7936 case SCF_ERROR_NONE:
7937 break;
7939 case SCF_ERROR_NO_MEMORY:
7940 if (name == NULL)
7941 warn(gettext("Could not refresh %s (out of memory).\n"),
7942 fmri);
7943 else
7944 warn(gettext("Could not refresh %s "
7945 "(dependent \"%s\" of %s) (out of memory).\n"),
7946 fmri, name, d_fmri);
7947 return (ENOMEM);
7949 case SCF_ERROR_NOT_FOUND:
7950 if (name == NULL)
7951 warn(deleted, fmri);
7952 else
7953 warn(dpt_deleted, fmri, name, d_fmri);
7954 return (0);
7956 case SCF_ERROR_INVALID_ARGUMENT:
7957 case SCF_ERROR_CONSTRAINT_VIOLATED:
7958 default:
7959 bad_error("fmri_to_entity", serr);
7962 r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7963 switch (r) {
7964 case 0:
7965 break;
7967 case ECONNABORTED:
7968 if (name != NULL)
7969 warn(gettext("Could not refresh %s "
7970 "(dependent \"%s\" of %s) "
7971 "(repository connection broken).\n"), fmri, name,
7972 d_fmri);
7973 return (r);
7975 case ECANCELED:
7976 if (name == NULL)
7977 warn(deleted, fmri);
7978 else
7979 warn(dpt_deleted, fmri, name, d_fmri);
7980 return (0);
7982 case EACCES:
7983 if (!g_verbose)
7984 return (0);
7985 if (name == NULL)
7986 warn(gettext("Could not refresh %s "
7987 "(backend access denied).\n"), fmri);
7988 else
7989 warn(gettext("Could not refresh %s "
7990 "(dependent \"%s\" of %s) "
7991 "(backend access denied).\n"), fmri, name, d_fmri);
7992 return (0);
7994 case EPERM:
7995 if (name == NULL)
7996 warn(gettext("Could not refresh %s "
7997 "(permission denied).\n"), fmri);
7998 else
7999 warn(gettext("Could not refresh %s "
8000 "(dependent \"%s\" of %s) "
8001 "(permission denied).\n"), fmri, name, d_fmri);
8002 return (r);
8004 case ENOSPC:
8005 if (name == NULL)
8006 warn(gettext("Could not refresh %s "
8007 "(repository server out of resources).\n"),
8008 fmri);
8009 else
8010 warn(gettext("Could not refresh %s "
8011 "(dependent \"%s\" of %s) "
8012 "(repository server out of resources).\n"),
8013 fmri, name, d_fmri);
8014 return (r);
8016 case -1:
8017 scfwarn();
8018 return (r);
8020 default:
8021 bad_error("refresh_entity", r);
8024 if (issvc)
8025 scf_service_destroy(ent);
8026 else
8027 scf_instance_destroy(ent);
8029 return (0);
8032 static int
8033 alloc_imp_globals()
8035 int r;
8037 const char * const emsg_nomem = gettext("Out of memory.\n");
8038 const char * const emsg_nores =
8039 gettext("svc.configd is out of resources.\n");
8041 imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
8042 max_scf_name_len : max_scf_fmri_len) + 1;
8044 if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
8045 (imp_svc = scf_service_create(g_hndl)) == NULL ||
8046 (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
8047 (imp_inst = scf_instance_create(g_hndl)) == NULL ||
8048 (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
8049 (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
8050 (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
8051 (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
8052 (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
8053 (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8054 (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
8055 (imp_pg = scf_pg_create(g_hndl)) == NULL ||
8056 (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
8057 (imp_prop = scf_property_create(g_hndl)) == NULL ||
8058 (imp_iter = scf_iter_create(g_hndl)) == NULL ||
8059 (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
8060 (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
8061 (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
8062 (imp_str = malloc(imp_str_sz)) == NULL ||
8063 (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
8064 (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
8065 (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
8066 (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
8067 (ud_inst = scf_instance_create(g_hndl)) == NULL ||
8068 (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8069 (ud_pg = scf_pg_create(g_hndl)) == NULL ||
8070 (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
8071 (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
8072 (ud_prop = scf_property_create(g_hndl)) == NULL ||
8073 (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
8074 (ud_val = scf_value_create(g_hndl)) == NULL ||
8075 (ud_iter = scf_iter_create(g_hndl)) == NULL ||
8076 (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
8077 (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
8078 (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
8079 (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
8080 (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
8081 if (scf_error() == SCF_ERROR_NO_RESOURCES)
8082 warn(emsg_nores);
8083 else
8084 warn(emsg_nomem);
8086 return (-1);
8089 r = load_init();
8090 switch (r) {
8091 case 0:
8092 break;
8094 case ENOMEM:
8095 warn(emsg_nomem);
8096 return (-1);
8098 default:
8099 bad_error("load_init", r);
8102 return (0);
8105 static void
8106 free_imp_globals()
8108 pgroup_t *old_dpt;
8109 void *cookie;
8111 load_fini();
8113 free(ud_ctarg);
8114 free(ud_oldtarg);
8115 free(ud_name);
8116 ud_ctarg = ud_oldtarg = ud_name = NULL;
8118 scf_transaction_destroy(ud_tx);
8119 ud_tx = NULL;
8120 scf_iter_destroy(ud_iter);
8121 scf_iter_destroy(ud_iter2);
8122 ud_iter = ud_iter2 = NULL;
8123 scf_value_destroy(ud_val);
8124 ud_val = NULL;
8125 scf_property_destroy(ud_prop);
8126 scf_property_destroy(ud_dpt_prop);
8127 ud_prop = ud_dpt_prop = NULL;
8128 scf_pg_destroy(ud_pg);
8129 scf_pg_destroy(ud_cur_depts_pg);
8130 scf_pg_destroy(ud_run_dpts_pg);
8131 ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
8132 scf_snaplevel_destroy(ud_snpl);
8133 ud_snpl = NULL;
8134 scf_instance_destroy(ud_inst);
8135 ud_inst = NULL;
8137 free(imp_str);
8138 free(imp_tsname);
8139 free(imp_fe1);
8140 free(imp_fe2);
8141 imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
8143 cookie = NULL;
8144 while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
8145 NULL) {
8146 free((char *)old_dpt->sc_pgroup_name);
8147 free((char *)old_dpt->sc_pgroup_fmri);
8148 internal_pgroup_free(old_dpt);
8150 uu_list_destroy(imp_deleted_dpts);
8152 scf_transaction_destroy(imp_tx);
8153 imp_tx = NULL;
8154 scf_iter_destroy(imp_iter);
8155 scf_iter_destroy(imp_rpg_iter);
8156 scf_iter_destroy(imp_up_iter);
8157 imp_iter = imp_rpg_iter = imp_up_iter = NULL;
8158 scf_property_destroy(imp_prop);
8159 imp_prop = NULL;
8160 scf_pg_destroy(imp_pg);
8161 scf_pg_destroy(imp_pg2);
8162 imp_pg = imp_pg2 = NULL;
8163 scf_snaplevel_destroy(imp_snpl);
8164 scf_snaplevel_destroy(imp_rsnpl);
8165 imp_snpl = imp_rsnpl = NULL;
8166 scf_snapshot_destroy(imp_snap);
8167 scf_snapshot_destroy(imp_lisnap);
8168 scf_snapshot_destroy(imp_tlisnap);
8169 scf_snapshot_destroy(imp_rsnap);
8170 imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
8171 scf_instance_destroy(imp_inst);
8172 scf_instance_destroy(imp_tinst);
8173 imp_inst = imp_tinst = NULL;
8174 scf_service_destroy(imp_svc);
8175 scf_service_destroy(imp_tsvc);
8176 imp_svc = imp_tsvc = NULL;
8177 scf_scope_destroy(imp_scope);
8178 imp_scope = NULL;
8180 load_fini();
8184 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
8186 scf_callback_t cbdata;
8187 int result = 0;
8188 entity_t *svc, *inst;
8189 uu_list_t *insts;
8190 int r;
8191 pgroup_t *old_dpt;
8192 int annotation_set = 0;
8194 const char * const emsg_nomem = gettext("Out of memory.\n");
8195 const char * const emsg_nores =
8196 gettext("svc.configd is out of resources.\n");
8198 lscf_prep_hndl();
8200 if (alloc_imp_globals())
8201 goto out;
8203 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
8204 switch (scf_error()) {
8205 case SCF_ERROR_CONNECTION_BROKEN:
8206 warn(gettext("Repository connection broken.\n"));
8207 repository_teardown();
8208 result = -1;
8209 goto out;
8211 case SCF_ERROR_NOT_FOUND:
8212 case SCF_ERROR_INVALID_ARGUMENT:
8213 case SCF_ERROR_NOT_BOUND:
8214 case SCF_ERROR_HANDLE_MISMATCH:
8215 default:
8216 bad_error("scf_handle_get_scope", scf_error());
8220 /* Set up the auditing annotation. */
8221 if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
8222 annotation_set = 1;
8223 } else {
8224 switch (scf_error()) {
8225 case SCF_ERROR_CONNECTION_BROKEN:
8226 warn(gettext("Repository connection broken.\n"));
8227 repository_teardown();
8228 result = -1;
8229 goto out;
8231 case SCF_ERROR_INVALID_ARGUMENT:
8232 case SCF_ERROR_NOT_BOUND:
8233 case SCF_ERROR_NO_RESOURCES:
8234 case SCF_ERROR_INTERNAL:
8235 bad_error("_scf_set_annotation", scf_error());
8236 /* NOTREACHED */
8238 default:
8240 * Do not terminate import because of inability to
8241 * generate annotation audit event.
8243 warn(gettext("_scf_set_annotation() unexpectedly "
8244 "failed with return code of %d\n"), scf_error());
8245 break;
8250 * Clear the sc_import_state's of all services & instances so we can
8251 * report how far we got if we fail.
8253 for (svc = uu_list_first(bndl->sc_bundle_services);
8254 svc != NULL;
8255 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8256 svc->sc_import_state = 0;
8258 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
8259 clear_int, (void *)offsetof(entity_t, sc_import_state),
8260 UU_DEFAULT) != 0)
8261 bad_error("uu_list_walk", uu_error());
8264 cbdata.sc_handle = g_hndl;
8265 cbdata.sc_parent = imp_scope;
8266 cbdata.sc_flags = flags;
8267 cbdata.sc_general = NULL;
8269 if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
8270 &cbdata, UU_DEFAULT) == 0) {
8271 /* Success. Refresh everything. */
8273 if (flags & SCI_NOREFRESH || no_refresh) {
8274 no_refresh = 0;
8275 result = 0;
8276 goto out;
8279 for (svc = uu_list_first(bndl->sc_bundle_services);
8280 svc != NULL;
8281 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8282 pgroup_t *dpt;
8284 insts = svc->sc_u.sc_service.sc_service_instances;
8286 for (inst = uu_list_first(insts);
8287 inst != NULL;
8288 inst = uu_list_next(insts, inst)) {
8289 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
8290 switch (r) {
8291 case 0:
8292 break;
8294 case ENOMEM:
8295 case ECONNABORTED:
8296 case EPERM:
8297 case -1:
8298 goto progress;
8300 default:
8301 bad_error("imp_refresh_fmri", r);
8304 inst->sc_import_state = IMPORT_REFRESHED;
8306 for (dpt = uu_list_first(inst->sc_dependents);
8307 dpt != NULL;
8308 dpt = uu_list_next(inst->sc_dependents,
8309 dpt))
8310 if (imp_refresh_fmri(
8311 dpt->sc_pgroup_fmri,
8312 dpt->sc_pgroup_name,
8313 inst->sc_fmri) != 0)
8314 goto progress;
8317 for (dpt = uu_list_first(svc->sc_dependents);
8318 dpt != NULL;
8319 dpt = uu_list_next(svc->sc_dependents, dpt))
8320 if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
8321 dpt->sc_pgroup_name, svc->sc_fmri) != 0)
8322 goto progress;
8325 for (old_dpt = uu_list_first(imp_deleted_dpts);
8326 old_dpt != NULL;
8327 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
8328 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8329 old_dpt->sc_pgroup_name,
8330 old_dpt->sc_parent->sc_fmri) != 0)
8331 goto progress;
8333 result = 0;
8336 * This snippet of code assumes that we are running svccfg as we
8337 * normally do -- witih svc.startd running. Of course, that is
8338 * not actually the case all the time because we also use a
8339 * varient of svc.configd and svccfg which are only meant to
8340 * run during the build process. During this time we have no
8341 * svc.startd, so this check would hang the build process.
8343 #ifndef NATIVE_BUILD
8345 * Verify that the restarter group is preset
8347 for (svc = uu_list_first(bndl->sc_bundle_services);
8348 svc != NULL;
8349 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8351 insts = svc->sc_u.sc_service.sc_service_instances;
8353 for (inst = uu_list_first(insts);
8354 inst != NULL;
8355 inst = uu_list_next(insts, inst)) {
8356 if (lscf_instance_verify(imp_scope, svc,
8357 inst) != 0)
8358 goto progress;
8361 #endif
8362 goto out;
8366 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8367 bad_error("uu_list_walk", uu_error());
8369 printerr:
8370 /* If the error hasn't been printed yet, do so here. */
8371 switch (cbdata.sc_err) {
8372 case ECONNABORTED:
8373 warn(gettext("Repository connection broken.\n"));
8374 break;
8376 case ENOMEM:
8377 warn(emsg_nomem);
8378 break;
8380 case ENOSPC:
8381 warn(emsg_nores);
8382 break;
8384 case EROFS:
8385 warn(gettext("Repository is read-only.\n"));
8386 break;
8388 case EACCES:
8389 warn(gettext("Repository backend denied access.\n"));
8390 break;
8392 case EPERM:
8393 case EINVAL:
8394 case EEXIST:
8395 case EBUSY:
8396 case EBADF:
8397 case -1:
8398 break;
8400 default:
8401 bad_error("lscf_service_import", cbdata.sc_err);
8404 progress:
8405 warn(gettext("Import of %s failed. Progress:\n"), filename);
8407 for (svc = uu_list_first(bndl->sc_bundle_services);
8408 svc != NULL;
8409 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8410 insts = svc->sc_u.sc_service.sc_service_instances;
8412 warn(gettext(" Service \"%s\": %s\n"), svc->sc_name,
8413 import_progress(svc->sc_import_state));
8415 for (inst = uu_list_first(insts);
8416 inst != NULL;
8417 inst = uu_list_next(insts, inst))
8418 warn(gettext(" Instance \"%s\": %s\n"),
8419 inst->sc_name,
8420 import_progress(inst->sc_import_state));
8423 if (cbdata.sc_err == ECONNABORTED)
8424 repository_teardown();
8427 result = -1;
8429 out:
8430 if (annotation_set != 0) {
8431 /* Turn off annotation. It is no longer needed. */
8432 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8435 free_imp_globals();
8437 return (result);
8441 * _lscf_import_err() summarize the error handling returned by
8442 * lscf_import_{instance | service}_pgs
8443 * Return values are:
8444 * IMPORT_NEXT
8445 * IMPORT_OUT
8446 * IMPORT_BAD
8449 #define IMPORT_BAD -1
8450 #define IMPORT_NEXT 0
8451 #define IMPORT_OUT 1
8453 static int
8454 _lscf_import_err(int err, const char *fmri)
8456 switch (err) {
8457 case 0:
8458 if (g_verbose)
8459 warn(gettext("%s updated.\n"), fmri);
8460 return (IMPORT_NEXT);
8462 case ECONNABORTED:
8463 warn(gettext("Could not update %s "
8464 "(repository connection broken).\n"), fmri);
8465 return (IMPORT_OUT);
8467 case ENOMEM:
8468 warn(gettext("Could not update %s (out of memory).\n"), fmri);
8469 return (IMPORT_OUT);
8471 case ENOSPC:
8472 warn(gettext("Could not update %s "
8473 "(repository server out of resources).\n"), fmri);
8474 return (IMPORT_OUT);
8476 case ECANCELED:
8477 warn(gettext(
8478 "Could not update %s (deleted).\n"), fmri);
8479 return (IMPORT_NEXT);
8481 case EPERM:
8482 case EINVAL:
8483 case EBUSY:
8484 return (IMPORT_NEXT);
8486 case EROFS:
8487 warn(gettext("Could not update %s (repository read-only).\n"),
8488 fmri);
8489 return (IMPORT_OUT);
8491 case EACCES:
8492 warn(gettext("Could not update %s "
8493 "(backend access denied).\n"), fmri);
8494 return (IMPORT_NEXT);
8496 case EEXIST:
8497 default:
8498 return (IMPORT_BAD);
8501 /*NOTREACHED*/
8505 * The global imp_svc and imp_inst should be set by the caller in the
8506 * check to make sure the service and instance exist that the apply is
8507 * working on.
8509 static int
8510 lscf_dependent_apply(void *dpg, void *e)
8512 scf_callback_t cb;
8513 pgroup_t *dpt_pgroup = dpg;
8514 pgroup_t *deldpt;
8515 entity_t *ent = e;
8516 int tissvc;
8517 void *sc_ent, *tent;
8518 scf_error_t serr;
8519 int r;
8521 const char * const dependents = "dependents";
8522 const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT);
8524 if (issvc)
8525 sc_ent = imp_svc;
8526 else
8527 sc_ent = imp_inst;
8529 if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg,
8530 imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 ||
8531 scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name,
8532 imp_prop) != 0) {
8533 switch (scf_error()) {
8534 case SCF_ERROR_NOT_FOUND:
8535 case SCF_ERROR_DELETED:
8536 break;
8538 case SCF_ERROR_CONNECTION_BROKEN:
8539 case SCF_ERROR_NOT_SET:
8540 case SCF_ERROR_INVALID_ARGUMENT:
8541 case SCF_ERROR_HANDLE_MISMATCH:
8542 case SCF_ERROR_NOT_BOUND:
8543 default:
8544 bad_error("entity_get_pg", scf_error());
8546 } else {
8548 * Found the dependents/<wip dep> so check to
8549 * see if the service is different. If so
8550 * store the service for later refresh, and
8551 * delete the wip dependency from the service
8553 if (scf_property_get_value(imp_prop, ud_val) != 0) {
8554 switch (scf_error()) {
8555 case SCF_ERROR_DELETED:
8556 break;
8558 case SCF_ERROR_CONNECTION_BROKEN:
8559 case SCF_ERROR_NOT_SET:
8560 case SCF_ERROR_INVALID_ARGUMENT:
8561 case SCF_ERROR_HANDLE_MISMATCH:
8562 case SCF_ERROR_NOT_BOUND:
8563 default:
8564 bad_error("scf_property_get_value",
8565 scf_error());
8569 if (scf_value_get_as_string(ud_val, ud_oldtarg,
8570 max_scf_value_len + 1) < 0)
8571 bad_error("scf_value_get_as_string", scf_error());
8573 r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
8574 switch (r) {
8575 case 1:
8576 break;
8577 case 0:
8578 if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent,
8579 &tissvc)) != SCF_ERROR_NONE) {
8580 if (serr == SCF_ERROR_NOT_FOUND) {
8581 break;
8582 } else {
8583 bad_error("fmri_to_entity", serr);
8587 if (entity_get_pg(tent, tissvc,
8588 dpt_pgroup->sc_pgroup_name, imp_pg) != 0) {
8589 serr = scf_error();
8590 if (serr == SCF_ERROR_NOT_FOUND ||
8591 serr == SCF_ERROR_DELETED) {
8592 break;
8593 } else {
8594 bad_error("entity_get_pg", scf_error());
8598 if (scf_pg_delete(imp_pg) != 0) {
8599 serr = scf_error();
8600 if (serr == SCF_ERROR_NOT_FOUND ||
8601 serr == SCF_ERROR_DELETED) {
8602 break;
8603 } else {
8604 bad_error("scf_pg_delete", scf_error());
8608 deldpt = internal_pgroup_new();
8609 if (deldpt == NULL)
8610 return (ENOMEM);
8611 deldpt->sc_pgroup_name =
8612 strdup(dpt_pgroup->sc_pgroup_name);
8613 deldpt->sc_pgroup_fmri = strdup(ud_oldtarg);
8614 if (deldpt->sc_pgroup_name == NULL ||
8615 deldpt->sc_pgroup_fmri == NULL)
8616 return (ENOMEM);
8617 deldpt->sc_parent = (entity_t *)ent;
8618 if (uu_list_insert_after(imp_deleted_dpts, NULL,
8619 deldpt) != 0)
8620 uu_die(gettext("libuutil error: %s\n"),
8621 uu_strerror(uu_error()));
8623 break;
8624 default:
8625 bad_error("fmri_equal", r);
8629 cb.sc_handle = g_hndl;
8630 cb.sc_parent = ent;
8631 cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT;
8632 cb.sc_source_fmri = ent->sc_fmri;
8633 cb.sc_target_fmri = ent->sc_fmri;
8634 cb.sc_trans = NULL;
8635 cb.sc_flags = SCI_FORCE;
8637 if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT)
8638 return (UU_WALK_ERROR);
8640 r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL);
8641 switch (r) {
8642 case 0:
8643 break;
8645 case ENOMEM:
8646 case ECONNABORTED:
8647 case EPERM:
8648 case -1:
8649 warn(gettext("Unable to refresh \"%s\"\n"),
8650 dpt_pgroup->sc_pgroup_fmri);
8651 return (UU_WALK_ERROR);
8653 default:
8654 bad_error("imp_refresh_fmri", r);
8657 return (UU_WALK_NEXT);
8661 * Returns
8662 * 0 - success
8663 * -1 - lscf_import_instance_pgs() failed.
8666 lscf_bundle_apply(bundle_t *bndl, const char *file)
8668 pgroup_t *old_dpt;
8669 entity_t *svc, *inst;
8670 int annotation_set = 0;
8671 int ret = 0;
8672 int r = 0;
8674 lscf_prep_hndl();
8676 if ((ret = alloc_imp_globals()))
8677 goto out;
8679 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0)
8680 scfdie();
8683 * Set the strings to be used for the security audit annotation
8684 * event.
8686 if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
8687 annotation_set = 1;
8688 } else {
8689 switch (scf_error()) {
8690 case SCF_ERROR_CONNECTION_BROKEN:
8691 warn(gettext("Repository connection broken.\n"));
8692 goto out;
8694 case SCF_ERROR_INVALID_ARGUMENT:
8695 case SCF_ERROR_NOT_BOUND:
8696 case SCF_ERROR_NO_RESOURCES:
8697 case SCF_ERROR_INTERNAL:
8698 bad_error("_scf_set_annotation", scf_error());
8699 /* NOTREACHED */
8701 default:
8703 * Do not abort apply operation because of
8704 * inability to create annotation audit event.
8706 warn(gettext("_scf_set_annotation() unexpectedly "
8707 "failed with return code of %d\n"), scf_error());
8708 break;
8712 for (svc = uu_list_first(bndl->sc_bundle_services);
8713 svc != NULL;
8714 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8715 int refresh = 0;
8717 if (scf_scope_get_service(imp_scope, svc->sc_name,
8718 imp_svc) != 0) {
8719 switch (scf_error()) {
8720 case SCF_ERROR_NOT_FOUND:
8721 if (g_verbose)
8722 warn(gettext("Ignoring nonexistent "
8723 "service %s.\n"), svc->sc_name);
8724 continue;
8726 default:
8727 scfdie();
8732 * If there were missing types in the profile, then need to
8733 * attempt to find the types.
8735 if (svc->sc_miss_type) {
8736 if (uu_list_numnodes(svc->sc_pgroups) &&
8737 uu_list_walk(svc->sc_pgroups, find_current_pg_type,
8738 svc, UU_DEFAULT) != 0) {
8739 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8740 bad_error("uu_list_walk", uu_error());
8742 ret = -1;
8743 continue;
8746 for (inst = uu_list_first(
8747 svc->sc_u.sc_service.sc_service_instances);
8748 inst != NULL;
8749 inst = uu_list_next(
8750 svc->sc_u.sc_service.sc_service_instances, inst)) {
8752 * If the instance doesn't exist just
8753 * skip to the next instance and let the
8754 * import note the missing instance.
8756 if (scf_service_get_instance(imp_svc,
8757 inst->sc_name, imp_inst) != 0)
8758 continue;
8760 if (uu_list_walk(inst->sc_pgroups,
8761 find_current_pg_type, inst,
8762 UU_DEFAULT) != 0) {
8763 if (uu_error() !=
8764 UU_ERROR_CALLBACK_FAILED)
8765 bad_error("uu_list_walk",
8766 uu_error());
8768 ret = -1;
8769 inst->sc_miss_type = B_TRUE;
8775 * if we have pgs in the profile, we need to refresh ALL
8776 * instances of the service
8778 if (uu_list_numnodes(svc->sc_pgroups) != 0) {
8779 refresh = 1;
8780 r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc,
8781 SCI_FORCE | SCI_KEEP);
8782 switch (_lscf_import_err(r, svc->sc_fmri)) {
8783 case IMPORT_NEXT:
8784 break;
8786 case IMPORT_OUT:
8787 goto out;
8789 case IMPORT_BAD:
8790 default:
8791 bad_error("lscf_import_service_pgs", r);
8795 if (uu_list_numnodes(svc->sc_dependents) != 0) {
8796 uu_list_walk(svc->sc_dependents,
8797 lscf_dependent_apply, svc, UU_DEFAULT);
8800 for (inst = uu_list_first(
8801 svc->sc_u.sc_service.sc_service_instances);
8802 inst != NULL;
8803 inst = uu_list_next(
8804 svc->sc_u.sc_service.sc_service_instances, inst)) {
8806 * This instance still has missing types
8807 * so skip it.
8809 if (inst->sc_miss_type) {
8810 if (g_verbose)
8811 warn(gettext("Ignoring instance "
8812 "%s:%s with missing types\n"),
8813 inst->sc_parent->sc_name,
8814 inst->sc_name);
8816 continue;
8819 if (scf_service_get_instance(imp_svc, inst->sc_name,
8820 imp_inst) != 0) {
8821 switch (scf_error()) {
8822 case SCF_ERROR_NOT_FOUND:
8823 if (g_verbose)
8824 warn(gettext("Ignoring "
8825 "nonexistant instance "
8826 "%s:%s.\n"),
8827 inst->sc_parent->sc_name,
8828 inst->sc_name);
8829 continue;
8831 default:
8832 scfdie();
8837 * If the instance does not have a general/enabled
8838 * property and no last-import snapshot then the
8839 * instance is not a fully installed instance and
8840 * should not have a profile applied to it.
8842 * This could happen if a service/instance declares
8843 * a dependent on behalf of another service/instance.
8846 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
8847 imp_snap) != 0) {
8848 if (scf_instance_get_pg(imp_inst,
8849 SCF_PG_GENERAL, imp_pg) != 0 ||
8850 scf_pg_get_property(imp_pg,
8851 SCF_PROPERTY_ENABLED, imp_prop) != 0) {
8852 if (g_verbose)
8853 warn(gettext("Ignoreing "
8854 "partial instance "
8855 "%s:%s.\n"),
8856 inst->sc_parent->sc_name,
8857 inst->sc_name);
8858 continue;
8862 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri,
8863 inst, SCI_FORCE | SCI_KEEP);
8864 switch (_lscf_import_err(r, inst->sc_fmri)) {
8865 case IMPORT_NEXT:
8866 break;
8868 case IMPORT_OUT:
8869 goto out;
8871 case IMPORT_BAD:
8872 default:
8873 bad_error("lscf_import_instance_pgs", r);
8876 if (uu_list_numnodes(inst->sc_dependents) != 0) {
8877 uu_list_walk(inst->sc_dependents,
8878 lscf_dependent_apply, inst, UU_DEFAULT);
8881 /* refresh only if there is no pgs in the service */
8882 if (refresh == 0)
8883 (void) refresh_entity(0, imp_inst,
8884 inst->sc_fmri, NULL, NULL, NULL);
8887 if (refresh == 1) {
8888 char *name_buf = safe_malloc(max_scf_name_len + 1);
8890 (void) refresh_entity(1, imp_svc, svc->sc_name,
8891 imp_inst, imp_iter, name_buf);
8892 free(name_buf);
8895 for (old_dpt = uu_list_first(imp_deleted_dpts);
8896 old_dpt != NULL;
8897 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) {
8898 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8899 old_dpt->sc_pgroup_name,
8900 old_dpt->sc_parent->sc_fmri) != 0) {
8901 warn(gettext("Unable to refresh \"%s\"\n"),
8902 old_dpt->sc_pgroup_fmri);
8907 out:
8908 if (annotation_set) {
8909 /* Remove security audit annotation strings. */
8910 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8913 free_imp_globals();
8914 return (ret);
8919 * Export. These functions create and output an XML tree of a service
8920 * description from the repository. This is largely the inverse of
8921 * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
8923 * - We must include any properties which are not represented specifically by
8924 * a service manifest, e.g., properties created by an admin post-import. To
8925 * do so we'll iterate through all properties and deal with each
8926 * apropriately.
8928 * - Children of services and instances must must be in the order set by the
8929 * DTD, but we iterate over the properties in undefined order. The elements
8930 * are not easily (or efficiently) sortable by name. Since there's a fixed
8931 * number of classes of them, however, we'll keep the classes separate and
8932 * assemble them in order.
8936 * Convenience function to handle xmlSetProp errors (and type casting).
8938 static void
8939 safe_setprop(xmlNodePtr n, const char *name, const char *val)
8941 if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
8942 uu_die(gettext("Could not set XML property.\n"));
8946 * Convenience function to set an XML attribute to the single value of an
8947 * astring property. If the value happens to be the default, don't set the
8948 * attribute. "dval" should be the default value supplied by the DTD, or
8949 * NULL for no default.
8951 static int
8952 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
8953 const char *name, const char *dval)
8955 scf_value_t *val;
8956 ssize_t len;
8957 char *str;
8959 val = scf_value_create(g_hndl);
8960 if (val == NULL)
8961 scfdie();
8963 if (prop_get_val(prop, val) != 0) {
8964 scf_value_destroy(val);
8965 return (-1);
8968 len = scf_value_get_as_string(val, NULL, 0);
8969 if (len < 0)
8970 scfdie();
8972 str = safe_malloc(len + 1);
8974 if (scf_value_get_as_string(val, str, len + 1) < 0)
8975 scfdie();
8977 scf_value_destroy(val);
8979 if (dval == NULL || strcmp(str, dval) != 0)
8980 safe_setprop(n, name, str);
8982 free(str);
8984 return (0);
8988 * As above, but the attribute is always set.
8990 static int
8991 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
8993 return (set_attr_from_prop_default(prop, n, name, NULL));
8997 * Dump the given document onto f, with "'s replaced by ''s.
8999 static int
9000 write_service_bundle(xmlDocPtr doc, FILE *f)
9002 xmlChar *mem;
9003 int sz, i;
9005 mem = NULL;
9006 xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
9008 if (mem == NULL) {
9009 semerr(gettext("Could not dump XML tree.\n"));
9010 return (-1);
9014 * Fortunately libxml produces &quot; instead of ", so we can blindly
9015 * replace all " with '. Cursed libxml2! Why must you #ifdef out the
9016 * &apos; code?!
9018 for (i = 0; i < sz; ++i) {
9019 char c = (char)mem[i];
9021 if (c == '"')
9022 (void) fputc('\'', f);
9023 else if (c == '\'')
9024 (void) fwrite("&apos;", sizeof ("&apos;") - 1, 1, f);
9025 else
9026 (void) fputc(c, f);
9029 return (0);
9033 * Create the DOM elements in elts necessary to (generically) represent prop
9034 * (i.e., a property or propval element). If the name of the property is
9035 * known, it should be passed as name_arg. Otherwise, pass NULL.
9037 static void
9038 export_property(scf_property_t *prop, const char *name_arg,
9039 struct pg_elts *elts, int flags)
9041 const char *type;
9042 scf_error_t err = 0;
9043 xmlNodePtr pnode, lnode;
9044 char *lnname;
9045 int ret;
9047 /* name */
9048 if (name_arg != NULL) {
9049 (void) strcpy(exp_str, name_arg);
9050 } else {
9051 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
9052 scfdie();
9055 /* type */
9056 type = prop_to_typestr(prop);
9057 if (type == NULL)
9058 uu_die(gettext("Can't export property %s: unknown type.\n"),
9059 exp_str);
9061 /* If we're exporting values, and there's just one, export it here. */
9062 if (!(flags & SCE_ALL_VALUES))
9063 goto empty;
9065 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
9066 xmlNodePtr n;
9068 /* Single value, so use propval */
9069 n = xmlNewNode(NULL, (xmlChar *)"propval");
9070 if (n == NULL)
9071 uu_die(emsg_create_xml);
9073 safe_setprop(n, name_attr, exp_str);
9074 safe_setprop(n, type_attr, type);
9076 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9077 scfdie();
9078 safe_setprop(n, value_attr, exp_str);
9080 if (elts->propvals == NULL)
9081 elts->propvals = n;
9082 else
9083 (void) xmlAddSibling(elts->propvals, n);
9085 return;
9088 err = scf_error();
9090 if (err == SCF_ERROR_PERMISSION_DENIED) {
9091 semerr(emsg_permission_denied);
9092 return;
9095 if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
9096 err != SCF_ERROR_NOT_FOUND &&
9097 err != SCF_ERROR_PERMISSION_DENIED)
9098 scfdie();
9100 empty:
9101 /* Multiple (or no) values, so use property */
9102 pnode = xmlNewNode(NULL, (xmlChar *)"property");
9103 if (pnode == NULL)
9104 uu_die(emsg_create_xml);
9106 safe_setprop(pnode, name_attr, exp_str);
9107 safe_setprop(pnode, type_attr, type);
9109 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
9110 lnname = uu_msprintf("%s_list", type);
9111 if (lnname == NULL)
9112 uu_die(gettext("Could not create string"));
9114 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
9115 if (lnode == NULL)
9116 uu_die(emsg_create_xml);
9118 uu_free(lnname);
9120 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
9121 scfdie();
9123 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
9124 1) {
9125 xmlNodePtr vn;
9127 vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
9128 NULL);
9129 if (vn == NULL)
9130 uu_die(emsg_create_xml);
9132 if (scf_value_get_as_string(exp_val, exp_str,
9133 exp_str_sz) < 0)
9134 scfdie();
9135 safe_setprop(vn, value_attr, exp_str);
9137 if (ret != 0)
9138 scfdie();
9141 if (elts->properties == NULL)
9142 elts->properties = pnode;
9143 else
9144 (void) xmlAddSibling(elts->properties, pnode);
9148 * Add a property_group element for this property group to elts.
9150 static void
9151 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
9153 xmlNodePtr n;
9154 struct pg_elts elts;
9155 int ret;
9156 boolean_t read_protected;
9158 n = xmlNewNode(NULL, (xmlChar *)"property_group");
9160 /* name */
9161 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9162 scfdie();
9163 safe_setprop(n, name_attr, exp_str);
9165 /* type */
9166 if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
9167 scfdie();
9168 safe_setprop(n, type_attr, exp_str);
9170 /* properties */
9171 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9172 scfdie();
9174 (void) memset(&elts, 0, sizeof (elts));
9177 * If this property group is not read protected, we always want to
9178 * output all the values. Otherwise, we only output the values if the
9179 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
9181 if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
9182 scfdie();
9184 if (!read_protected)
9185 flags |= SCE_ALL_VALUES;
9187 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9188 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9189 scfdie();
9191 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9192 xmlNodePtr m;
9194 m = xmlNewNode(NULL, (xmlChar *)"stability");
9195 if (m == NULL)
9196 uu_die(emsg_create_xml);
9198 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9199 elts.stability = m;
9200 continue;
9203 xmlFreeNode(m);
9206 export_property(exp_prop, NULL, &elts, flags);
9208 if (ret == -1)
9209 scfdie();
9211 (void) xmlAddChild(n, elts.stability);
9212 (void) xmlAddChildList(n, elts.propvals);
9213 (void) xmlAddChildList(n, elts.properties);
9215 if (eelts->property_groups == NULL)
9216 eelts->property_groups = n;
9217 else
9218 (void) xmlAddSibling(eelts->property_groups, n);
9222 * Create an XML node representing the dependency described by the given
9223 * property group and put it in eelts. Unless the dependency is not valid, in
9224 * which case create a generic property_group element which represents it and
9225 * put it in eelts.
9227 static void
9228 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
9230 xmlNodePtr n;
9231 int err = 0, ret;
9232 struct pg_elts elts;
9234 n = xmlNewNode(NULL, (xmlChar *)"dependency");
9235 if (n == NULL)
9236 uu_die(emsg_create_xml);
9239 * If the external flag is present, skip this dependency because it
9240 * should have been created by another manifest.
9242 if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
9243 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9244 prop_get_val(exp_prop, exp_val) == 0) {
9245 uint8_t b;
9247 if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
9248 scfdie();
9250 if (b)
9251 return;
9253 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
9254 scfdie();
9256 /* Get the required attributes. */
9258 /* name */
9259 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9260 scfdie();
9261 safe_setprop(n, name_attr, exp_str);
9263 /* grouping */
9264 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9265 set_attr_from_prop(exp_prop, n, "grouping") != 0)
9266 err = 1;
9268 /* restart_on */
9269 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9270 set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9271 err = 1;
9273 /* type */
9274 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9275 set_attr_from_prop(exp_prop, n, type_attr) != 0)
9276 err = 1;
9279 * entities: Not required, but if we create no children, it will be
9280 * created as empty on import, so fail if it's missing.
9282 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9283 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
9284 scf_iter_t *eiter;
9285 int ret2;
9287 eiter = scf_iter_create(g_hndl);
9288 if (eiter == NULL)
9289 scfdie();
9291 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
9292 scfdie();
9294 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
9295 xmlNodePtr ch;
9297 if (scf_value_get_astring(exp_val, exp_str,
9298 exp_str_sz) < 0)
9299 scfdie();
9302 * service_fmri's must be first, so we can add them
9303 * here.
9305 ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
9306 NULL);
9307 if (ch == NULL)
9308 uu_die(emsg_create_xml);
9310 safe_setprop(ch, value_attr, exp_str);
9312 if (ret2 == -1)
9313 scfdie();
9315 scf_iter_destroy(eiter);
9316 } else
9317 err = 1;
9319 if (err) {
9320 xmlFreeNode(n);
9322 export_pg(pg, eelts, SCE_ALL_VALUES);
9324 return;
9327 /* Iterate through the properties & handle each. */
9328 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9329 scfdie();
9331 (void) memset(&elts, 0, sizeof (elts));
9333 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9334 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9335 scfdie();
9337 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9338 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9339 strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9340 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9341 continue;
9342 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9343 xmlNodePtr m;
9345 m = xmlNewNode(NULL, (xmlChar *)"stability");
9346 if (m == NULL)
9347 uu_die(emsg_create_xml);
9349 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9350 elts.stability = m;
9351 continue;
9354 xmlFreeNode(m);
9357 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9359 if (ret == -1)
9360 scfdie();
9362 (void) xmlAddChild(n, elts.stability);
9363 (void) xmlAddChildList(n, elts.propvals);
9364 (void) xmlAddChildList(n, elts.properties);
9366 if (eelts->dependencies == NULL)
9367 eelts->dependencies = n;
9368 else
9369 (void) xmlAddSibling(eelts->dependencies, n);
9372 static xmlNodePtr
9373 export_method_environment(scf_propertygroup_t *pg)
9375 xmlNodePtr env;
9376 int ret;
9377 int children = 0;
9379 if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
9380 return (NULL);
9382 env = xmlNewNode(NULL, (xmlChar *)"method_environment");
9383 if (env == NULL)
9384 uu_die(emsg_create_xml);
9386 if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
9387 scfdie();
9389 if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
9390 scfdie();
9392 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
9393 xmlNodePtr ev;
9394 char *cp;
9396 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9397 scfdie();
9399 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
9400 warn(gettext("Invalid environment variable \"%s\".\n"),
9401 exp_str);
9402 continue;
9403 } else if (strncmp(exp_str, "SMF_", 4) == 0) {
9404 warn(gettext("Invalid environment variable \"%s\"; "
9405 "\"SMF_\" prefix is reserved.\n"), exp_str);
9406 continue;
9409 *cp = '\0';
9410 cp++;
9412 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
9413 if (ev == NULL)
9414 uu_die(emsg_create_xml);
9416 safe_setprop(ev, name_attr, exp_str);
9417 safe_setprop(ev, value_attr, cp);
9418 children++;
9421 if (ret != 0)
9422 scfdie();
9424 if (children == 0) {
9425 xmlFreeNode(env);
9426 return (NULL);
9429 return (env);
9433 * As above, but for a method property group.
9435 static void
9436 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
9438 xmlNodePtr n, env;
9439 char *str;
9440 int err = 0, nonenv, ret;
9441 uint8_t use_profile;
9442 struct pg_elts elts;
9443 xmlNodePtr ctxt = NULL;
9445 n = xmlNewNode(NULL, (xmlChar *)"exec_method");
9447 /* Get the required attributes. */
9449 /* name */
9450 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9451 scfdie();
9452 safe_setprop(n, name_attr, exp_str);
9454 /* type */
9455 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9456 set_attr_from_prop(exp_prop, n, type_attr) != 0)
9457 err = 1;
9459 /* exec */
9460 if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
9461 set_attr_from_prop(exp_prop, n, "exec") != 0)
9462 err = 1;
9464 /* timeout */
9465 if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
9466 prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
9467 prop_get_val(exp_prop, exp_val) == 0) {
9468 uint64_t c;
9470 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
9471 scfdie();
9473 str = uu_msprintf("%llu", c);
9474 if (str == NULL)
9475 uu_die(gettext("Could not create string"));
9477 safe_setprop(n, "timeout_seconds", str);
9478 free(str);
9479 } else
9480 err = 1;
9482 if (err) {
9483 xmlFreeNode(n);
9485 export_pg(pg, eelts, SCE_ALL_VALUES);
9487 return;
9492 * If we're going to have a method_context child, we need to know
9493 * before we iterate through the properties. Since method_context's
9494 * are optional, we don't want to complain about any properties
9495 * missing if none of them are there. Thus we can't use the
9496 * convenience functions.
9498 nonenv =
9499 scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
9500 SCF_SUCCESS ||
9501 scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
9502 SCF_SUCCESS ||
9503 scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
9504 SCF_SUCCESS ||
9505 scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
9506 SCF_SUCCESS;
9508 if (nonenv) {
9509 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9510 if (ctxt == NULL)
9511 uu_die(emsg_create_xml);
9513 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
9514 0 &&
9515 set_attr_from_prop_default(exp_prop, ctxt,
9516 "working_directory", ":default") != 0)
9517 err = 1;
9519 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
9520 set_attr_from_prop_default(exp_prop, ctxt, "project",
9521 ":default") != 0)
9522 err = 1;
9524 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
9525 0 &&
9526 set_attr_from_prop_default(exp_prop, ctxt,
9527 "resource_pool", ":default") != 0)
9528 err = 1;
9530 * We only want to complain about profile or credential
9531 * properties if we will use them. To determine that we must
9532 * examine USE_PROFILE.
9534 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9535 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9536 prop_get_val(exp_prop, exp_val) == 0) {
9537 if (scf_value_get_boolean(exp_val, &use_profile) !=
9538 SCF_SUCCESS) {
9539 scfdie();
9542 if (use_profile) {
9543 xmlNodePtr prof;
9545 prof = xmlNewChild(ctxt, NULL,
9546 (xmlChar *)"method_profile", NULL);
9547 if (prof == NULL)
9548 uu_die(emsg_create_xml);
9550 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
9551 exp_prop) != 0 ||
9552 set_attr_from_prop(exp_prop, prof,
9553 name_attr) != 0)
9554 err = 1;
9555 } else {
9556 xmlNodePtr cred;
9558 cred = xmlNewChild(ctxt, NULL,
9559 (xmlChar *)"method_credential", NULL);
9560 if (cred == NULL)
9561 uu_die(emsg_create_xml);
9563 if (pg_get_prop(pg, SCF_PROPERTY_USER,
9564 exp_prop) != 0 ||
9565 set_attr_from_prop(exp_prop, cred,
9566 "user") != 0) {
9567 err = 1;
9570 if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
9571 exp_prop) == 0 &&
9572 set_attr_from_prop_default(exp_prop, cred,
9573 "group", ":default") != 0)
9574 err = 1;
9576 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
9577 exp_prop) == 0 &&
9578 set_attr_from_prop_default(exp_prop, cred,
9579 "supp_groups", ":default") != 0)
9580 err = 1;
9582 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
9583 exp_prop) == 0 &&
9584 set_attr_from_prop_default(exp_prop, cred,
9585 "privileges", ":default") != 0)
9586 err = 1;
9588 if (pg_get_prop(pg,
9589 SCF_PROPERTY_LIMIT_PRIVILEGES,
9590 exp_prop) == 0 &&
9591 set_attr_from_prop_default(exp_prop, cred,
9592 "limit_privileges", ":default") != 0)
9593 err = 1;
9598 if ((env = export_method_environment(pg)) != NULL) {
9599 if (ctxt == NULL) {
9600 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9601 if (ctxt == NULL)
9602 uu_die(emsg_create_xml);
9604 (void) xmlAddChild(ctxt, env);
9607 if (env != NULL || (nonenv && err == 0))
9608 (void) xmlAddChild(n, ctxt);
9609 else
9610 xmlFreeNode(ctxt);
9612 nonenv = (err == 0);
9614 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9615 scfdie();
9617 (void) memset(&elts, 0, sizeof (elts));
9619 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9620 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9621 scfdie();
9623 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9624 strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
9625 strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
9626 continue;
9627 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9628 xmlNodePtr m;
9630 m = xmlNewNode(NULL, (xmlChar *)"stability");
9631 if (m == NULL)
9632 uu_die(emsg_create_xml);
9634 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9635 elts.stability = m;
9636 continue;
9639 xmlFreeNode(m);
9640 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
9641 0 ||
9642 strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
9643 strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
9644 strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9645 if (nonenv)
9646 continue;
9647 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
9648 strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
9649 strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
9650 strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
9651 strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) {
9652 if (nonenv && !use_profile)
9653 continue;
9654 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9655 if (nonenv && use_profile)
9656 continue;
9657 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
9658 if (env != NULL)
9659 continue;
9662 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9664 if (ret == -1)
9665 scfdie();
9667 (void) xmlAddChild(n, elts.stability);
9668 (void) xmlAddChildList(n, elts.propvals);
9669 (void) xmlAddChildList(n, elts.properties);
9671 if (eelts->exec_methods == NULL)
9672 eelts->exec_methods = n;
9673 else
9674 (void) xmlAddSibling(eelts->exec_methods, n);
9677 static void
9678 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
9679 struct entity_elts *eelts)
9681 xmlNodePtr pgnode;
9683 pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
9684 if (pgnode == NULL)
9685 uu_die(emsg_create_xml);
9687 safe_setprop(pgnode, name_attr, name);
9688 safe_setprop(pgnode, type_attr, type);
9690 (void) xmlAddChildList(pgnode, elts->propvals);
9691 (void) xmlAddChildList(pgnode, elts->properties);
9693 if (eelts->property_groups == NULL)
9694 eelts->property_groups = pgnode;
9695 else
9696 (void) xmlAddSibling(eelts->property_groups, pgnode);
9700 * Process the general property group for a service. This is the one with the
9701 * goodies.
9703 static void
9704 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
9706 struct pg_elts elts;
9707 int ret;
9710 * In case there are properties which don't correspond to child
9711 * entities of the service entity, we'll set up a pg_elts structure to
9712 * put them in.
9714 (void) memset(&elts, 0, sizeof (elts));
9716 /* Walk the properties, looking for special ones. */
9717 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9718 scfdie();
9720 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9721 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9722 scfdie();
9724 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
9725 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9726 prop_get_val(exp_prop, exp_val) == 0) {
9727 uint8_t b;
9729 if (scf_value_get_boolean(exp_val, &b) !=
9730 SCF_SUCCESS)
9731 scfdie();
9733 if (b) {
9734 selts->single_instance =
9735 xmlNewNode(NULL,
9736 (xmlChar *)"single_instance");
9737 if (selts->single_instance == NULL)
9738 uu_die(emsg_create_xml);
9741 continue;
9743 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9744 xmlNodePtr rnode, sfnode;
9746 rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9747 if (rnode == NULL)
9748 uu_die(emsg_create_xml);
9750 sfnode = xmlNewChild(rnode, NULL,
9751 (xmlChar *)"service_fmri", NULL);
9752 if (sfnode == NULL)
9753 uu_die(emsg_create_xml);
9755 if (set_attr_from_prop(exp_prop, sfnode,
9756 value_attr) == 0) {
9757 selts->restarter = rnode;
9758 continue;
9761 xmlFreeNode(rnode);
9762 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
9763 0) {
9764 xmlNodePtr s;
9766 s = xmlNewNode(NULL, (xmlChar *)"stability");
9767 if (s == NULL)
9768 uu_die(emsg_create_xml);
9770 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9771 selts->stability = s;
9772 continue;
9775 xmlFreeNode(s);
9778 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9780 if (ret == -1)
9781 scfdie();
9783 if (elts.propvals != NULL || elts.properties != NULL)
9784 export_pg_elts(&elts, scf_pg_general, scf_group_framework,
9785 selts);
9788 static void
9789 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
9791 xmlNodePtr n, prof, cred, env;
9792 uint8_t use_profile;
9793 int ret, err = 0;
9795 n = xmlNewNode(NULL, (xmlChar *)"method_context");
9797 env = export_method_environment(pg);
9799 /* Need to know whether we'll use a profile or not. */
9800 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9801 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9802 prop_get_val(exp_prop, exp_val) == 0) {
9803 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
9804 scfdie();
9806 if (use_profile)
9807 prof =
9808 xmlNewChild(n, NULL, (xmlChar *)"method_profile",
9809 NULL);
9810 else
9811 cred =
9812 xmlNewChild(n, NULL, (xmlChar *)"method_credential",
9813 NULL);
9816 if (env != NULL)
9817 (void) xmlAddChild(n, env);
9819 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9820 scfdie();
9822 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9823 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9824 scfdie();
9826 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
9827 if (set_attr_from_prop(exp_prop, n,
9828 "working_directory") != 0)
9829 err = 1;
9830 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
9831 if (set_attr_from_prop(exp_prop, n, "project") != 0)
9832 err = 1;
9833 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
9834 if (set_attr_from_prop(exp_prop, n,
9835 "resource_pool") != 0)
9836 err = 1;
9837 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9838 /* EMPTY */
9839 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
9840 if (use_profile ||
9841 set_attr_from_prop(exp_prop, cred, "user") != 0)
9842 err = 1;
9843 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
9844 if (use_profile ||
9845 set_attr_from_prop(exp_prop, cred, "group") != 0)
9846 err = 1;
9847 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
9848 if (use_profile || set_attr_from_prop(exp_prop, cred,
9849 "supp_groups") != 0)
9850 err = 1;
9851 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
9852 if (use_profile || set_attr_from_prop(exp_prop, cred,
9853 "privileges") != 0)
9854 err = 1;
9855 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
9856 0) {
9857 if (use_profile || set_attr_from_prop(exp_prop, cred,
9858 "limit_privileges") != 0)
9859 err = 1;
9860 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9861 if (!use_profile || set_attr_from_prop(exp_prop,
9862 prof, name_attr) != 0)
9863 err = 1;
9864 } else {
9865 /* Can't have generic properties in method_context's */
9866 err = 1;
9869 if (ret == -1)
9870 scfdie();
9872 if (err && env == NULL) {
9873 xmlFreeNode(n);
9874 export_pg(pg, elts, SCE_ALL_VALUES);
9875 return;
9878 elts->method_context = n;
9882 * Given a dependency property group in the tfmri entity (target fmri), return
9883 * a dependent element which represents it.
9885 static xmlNodePtr
9886 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
9888 uint8_t b;
9889 xmlNodePtr n, sf;
9890 int err = 0, ret;
9891 struct pg_elts pgelts;
9894 * If external isn't set to true then exporting the service will
9895 * export this as a normal dependency, so we should stop to avoid
9896 * duplication.
9898 if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
9899 scf_property_get_value(exp_prop, exp_val) != 0 ||
9900 scf_value_get_boolean(exp_val, &b) != 0 || !b) {
9901 if (g_verbose) {
9902 warn(gettext("Dependent \"%s\" cannot be exported "
9903 "properly because the \"%s\" property of the "
9904 "\"%s\" dependency of %s is not set to true.\n"),
9905 name, scf_property_external, name, tfmri);
9908 return (NULL);
9911 n = xmlNewNode(NULL, (xmlChar *)"dependent");
9912 if (n == NULL)
9913 uu_die(emsg_create_xml);
9915 safe_setprop(n, name_attr, name);
9917 /* Get the required attributes */
9918 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9919 set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9920 err = 1;
9922 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9923 set_attr_from_prop(exp_prop, n, "grouping") != 0)
9924 err = 1;
9926 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9927 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
9928 prop_get_val(exp_prop, exp_val) == 0) {
9929 /* EMPTY */
9930 } else
9931 err = 1;
9933 if (err) {
9934 xmlFreeNode(n);
9935 return (NULL);
9938 sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
9939 if (sf == NULL)
9940 uu_die(emsg_create_xml);
9942 safe_setprop(sf, value_attr, tfmri);
9945 * Now add elements for the other properties.
9947 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9948 scfdie();
9950 (void) memset(&pgelts, 0, sizeof (pgelts));
9952 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9953 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9954 scfdie();
9956 if (strcmp(exp_str, scf_property_external) == 0 ||
9957 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9958 strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9959 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9960 continue;
9961 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
9962 if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
9963 prop_get_val(exp_prop, exp_val) == 0) {
9964 char type[sizeof ("service") + 1];
9966 if (scf_value_get_astring(exp_val, type,
9967 sizeof (type)) < 0)
9968 scfdie();
9970 if (strcmp(type, "service") == 0)
9971 continue;
9973 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9974 xmlNodePtr s;
9976 s = xmlNewNode(NULL, (xmlChar *)"stability");
9977 if (s == NULL)
9978 uu_die(emsg_create_xml);
9980 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9981 pgelts.stability = s;
9982 continue;
9985 xmlFreeNode(s);
9988 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
9990 if (ret == -1)
9991 scfdie();
9993 (void) xmlAddChild(n, pgelts.stability);
9994 (void) xmlAddChildList(n, pgelts.propvals);
9995 (void) xmlAddChildList(n, pgelts.properties);
9997 return (n);
10000 static void
10001 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
10003 scf_propertygroup_t *opg;
10004 scf_iter_t *iter;
10005 char *type, *fmri;
10006 int ret;
10007 struct pg_elts pgelts;
10008 xmlNodePtr n;
10009 scf_error_t serr;
10011 if ((opg = scf_pg_create(g_hndl)) == NULL ||
10012 (iter = scf_iter_create(g_hndl)) == NULL)
10013 scfdie();
10015 /* Can't use exp_prop_iter due to export_dependent(). */
10016 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
10017 scfdie();
10019 type = safe_malloc(max_scf_pg_type_len + 1);
10021 /* Get an extra byte so we can tell if values are too long. */
10022 fmri = safe_malloc(max_scf_fmri_len + 2);
10024 (void) memset(&pgelts, 0, sizeof (pgelts));
10026 while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
10027 void *entity;
10028 int isservice;
10029 scf_type_t ty;
10031 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
10032 scfdie();
10034 if ((ty != SCF_TYPE_ASTRING &&
10035 prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
10036 prop_get_val(exp_prop, exp_val) != 0) {
10037 export_property(exp_prop, NULL, &pgelts,
10038 SCE_ALL_VALUES);
10039 continue;
10042 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10043 scfdie();
10045 if (scf_value_get_astring(exp_val, fmri,
10046 max_scf_fmri_len + 2) < 0)
10047 scfdie();
10049 /* Look for a dependency group in the target fmri. */
10050 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
10051 switch (serr) {
10052 case SCF_ERROR_NONE:
10053 break;
10055 case SCF_ERROR_NO_MEMORY:
10056 uu_die(gettext("Out of memory.\n"));
10057 /* NOTREACHED */
10059 case SCF_ERROR_INVALID_ARGUMENT:
10060 if (g_verbose) {
10061 if (scf_property_to_fmri(exp_prop, fmri,
10062 max_scf_fmri_len + 2) < 0)
10063 scfdie();
10065 warn(gettext("The value of %s is not a valid "
10066 "FMRI.\n"), fmri);
10069 export_property(exp_prop, exp_str, &pgelts,
10070 SCE_ALL_VALUES);
10071 continue;
10073 case SCF_ERROR_CONSTRAINT_VIOLATED:
10074 if (g_verbose) {
10075 if (scf_property_to_fmri(exp_prop, fmri,
10076 max_scf_fmri_len + 2) < 0)
10077 scfdie();
10079 warn(gettext("The value of %s does not specify "
10080 "a service or an instance.\n"), fmri);
10083 export_property(exp_prop, exp_str, &pgelts,
10084 SCE_ALL_VALUES);
10085 continue;
10087 case SCF_ERROR_NOT_FOUND:
10088 if (g_verbose) {
10089 if (scf_property_to_fmri(exp_prop, fmri,
10090 max_scf_fmri_len + 2) < 0)
10091 scfdie();
10093 warn(gettext("The entity specified by %s does "
10094 "not exist.\n"), fmri);
10097 export_property(exp_prop, exp_str, &pgelts,
10098 SCE_ALL_VALUES);
10099 continue;
10101 default:
10102 #ifndef NDEBUG
10103 (void) fprintf(stderr, "%s:%d: %s() failed with "
10104 "unexpected error %d.\n", __FILE__, __LINE__,
10105 "fmri_to_entity", serr);
10106 #endif
10107 abort();
10110 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
10111 if (scf_error() != SCF_ERROR_NOT_FOUND)
10112 scfdie();
10114 warn(gettext("Entity %s is missing dependency property "
10115 "group %s.\n"), fmri, exp_str);
10117 export_property(exp_prop, NULL, &pgelts,
10118 SCE_ALL_VALUES);
10119 continue;
10122 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
10123 scfdie();
10125 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
10126 if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
10127 scfdie();
10129 warn(gettext("Property group %s is not of "
10130 "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
10132 export_property(exp_prop, NULL, &pgelts,
10133 SCE_ALL_VALUES);
10134 continue;
10137 n = export_dependent(opg, exp_str, fmri);
10138 if (n == NULL) {
10139 export_property(exp_prop, exp_str, &pgelts,
10140 SCE_ALL_VALUES);
10141 } else {
10142 if (eelts->dependents == NULL)
10143 eelts->dependents = n;
10144 else
10145 (void) xmlAddSibling(eelts->dependents,
10149 if (ret == -1)
10150 scfdie();
10152 free(fmri);
10153 free(type);
10155 scf_iter_destroy(iter);
10156 scf_pg_destroy(opg);
10158 if (pgelts.propvals != NULL || pgelts.properties != NULL)
10159 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
10160 eelts);
10163 static void
10164 make_node(xmlNodePtr *nodep, const char *name)
10166 if (*nodep == NULL) {
10167 *nodep = xmlNewNode(NULL, (xmlChar *)name);
10168 if (*nodep == NULL)
10169 uu_die(emsg_create_xml);
10173 static xmlNodePtr
10174 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
10176 int ret;
10177 xmlNodePtr parent = NULL;
10178 xmlNodePtr loctext = NULL;
10180 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10181 scfdie();
10183 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10184 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
10185 prop_get_val(exp_prop, exp_val) != 0)
10186 continue;
10188 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
10189 scfdie();
10191 make_node(&parent, parname);
10192 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
10193 (xmlChar *)exp_str);
10194 if (loctext == NULL)
10195 uu_die(emsg_create_xml);
10197 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10198 scfdie();
10200 safe_setprop(loctext, "xml:lang", exp_str);
10203 if (ret == -1)
10204 scfdie();
10206 return (parent);
10209 static xmlNodePtr
10210 export_tm_manpage(scf_propertygroup_t *pg)
10212 xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
10213 if (manpage == NULL)
10214 uu_die(emsg_create_xml);
10216 if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
10217 set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
10218 pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
10219 set_attr_from_prop(exp_prop, manpage, "section") != 0) {
10220 xmlFreeNode(manpage);
10221 return (NULL);
10224 if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
10225 (void) set_attr_from_prop_default(exp_prop,
10226 manpage, "manpath", ":default");
10228 return (manpage);
10231 static xmlNodePtr
10232 export_tm_doc_link(scf_propertygroup_t *pg)
10234 xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
10235 if (doc_link == NULL)
10236 uu_die(emsg_create_xml);
10238 if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
10239 set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
10240 pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
10241 set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
10242 xmlFreeNode(doc_link);
10243 return (NULL);
10245 return (doc_link);
10249 * Process template information for a service or instances.
10251 static void
10252 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
10253 struct template_elts *telts)
10255 size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
10256 size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
10257 xmlNodePtr child = NULL;
10259 if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
10260 scfdie();
10262 if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
10263 telts->common_name = export_tm_loctext(pg, "common_name");
10264 if (telts->common_name == NULL)
10265 export_pg(pg, elts, SCE_ALL_VALUES);
10266 return;
10267 } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
10268 telts->description = export_tm_loctext(pg, "description");
10269 if (telts->description == NULL)
10270 export_pg(pg, elts, SCE_ALL_VALUES);
10271 return;
10274 if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
10275 child = export_tm_manpage(pg);
10276 } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
10277 child = export_tm_doc_link(pg);
10280 if (child != NULL) {
10281 make_node(&telts->documentation, "documentation");
10282 (void) xmlAddChild(telts->documentation, child);
10283 } else {
10284 export_pg(pg, elts, SCE_ALL_VALUES);
10289 * Process parameter and paramval elements
10291 static void
10292 export_parameter(scf_property_t *prop, const char *name,
10293 struct params_elts *elts)
10295 xmlNodePtr param;
10296 scf_error_t err = 0;
10297 int ret;
10299 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
10300 if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL)
10301 uu_die(emsg_create_xml);
10303 safe_setprop(param, name_attr, name);
10305 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
10306 scfdie();
10307 safe_setprop(param, value_attr, exp_str);
10309 if (elts->paramval == NULL)
10310 elts->paramval = param;
10311 else
10312 (void) xmlAddSibling(elts->paramval, param);
10314 return;
10317 err = scf_error();
10319 if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
10320 err != SCF_ERROR_NOT_FOUND)
10321 scfdie();
10323 if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL)
10324 uu_die(emsg_create_xml);
10326 safe_setprop(param, name_attr, name);
10328 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
10329 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
10330 scfdie();
10332 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
10333 1) {
10334 xmlNodePtr vn;
10336 if ((vn = xmlNewChild(param, NULL,
10337 (xmlChar *)"value_node", NULL)) == NULL)
10338 uu_die(emsg_create_xml);
10340 if (scf_value_get_as_string(exp_val, exp_str,
10341 exp_str_sz) < 0)
10342 scfdie();
10344 safe_setprop(vn, value_attr, exp_str);
10346 if (ret != 0)
10347 scfdie();
10350 if (elts->parameter == NULL)
10351 elts->parameter = param;
10352 else
10353 (void) xmlAddSibling(elts->parameter, param);
10357 * Process notification parameters for a service or instance
10359 static void
10360 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts)
10362 xmlNodePtr n, event, *type;
10363 struct params_elts *eelts;
10364 int ret, err, i;
10366 n = xmlNewNode(NULL, (xmlChar *)"notification_parameters");
10367 event = xmlNewNode(NULL, (xmlChar *)"event");
10368 if (n == NULL || event == NULL)
10369 uu_die(emsg_create_xml);
10371 /* event value */
10372 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
10373 scfdie();
10374 safe_setprop(event, value_attr, exp_str);
10376 (void) xmlAddChild(n, event);
10378 if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL ||
10379 (eelts = calloc(URI_SCHEME_NUM,
10380 sizeof (struct params_elts))) == NULL)
10381 uu_die(gettext("Out of memory.\n"));
10383 err = 0;
10385 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10386 scfdie();
10388 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10389 char *t, *p;
10391 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10392 scfdie();
10394 if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) {
10396 * this is not a well formed notification parameters
10397 * element, we should export as regular pg
10399 err = 1;
10400 break;
10403 if ((i = check_uri_protocol(t)) < 0) {
10404 err = 1;
10405 break;
10408 if (type[i] == NULL) {
10409 if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) ==
10410 NULL)
10411 uu_die(emsg_create_xml);
10413 safe_setprop(type[i], name_attr, t);
10415 if (strcmp(p, active_attr) == 0) {
10416 if (set_attr_from_prop(exp_prop, type[i],
10417 active_attr) != 0) {
10418 err = 1;
10419 break;
10421 continue;
10424 * We export the parameter
10426 export_parameter(exp_prop, p, &eelts[i]);
10429 if (ret == -1)
10430 scfdie();
10432 if (err == 1) {
10433 for (i = 0; i < URI_SCHEME_NUM; ++i)
10434 xmlFree(type[i]);
10435 free(type);
10437 export_pg(pg, elts, SCE_ALL_VALUES);
10439 return;
10440 } else {
10441 for (i = 0; i < URI_SCHEME_NUM; ++i)
10442 if (type[i] != NULL) {
10443 (void) xmlAddChildList(type[i],
10444 eelts[i].paramval);
10445 (void) xmlAddChildList(type[i],
10446 eelts[i].parameter);
10447 (void) xmlAddSibling(event, type[i]);
10450 free(type);
10452 if (elts->notify_params == NULL)
10453 elts->notify_params = n;
10454 else
10455 (void) xmlAddSibling(elts->notify_params, n);
10459 * Process the general property group for an instance.
10461 static void
10462 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
10463 struct entity_elts *elts)
10465 uint8_t enabled;
10466 struct pg_elts pgelts;
10467 int ret;
10469 /* enabled */
10470 if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
10471 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
10472 prop_get_val(exp_prop, exp_val) == 0) {
10473 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
10474 scfdie();
10475 } else {
10476 enabled = 0;
10479 safe_setprop(inode, enabled_attr, enabled ? true : false);
10481 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10482 scfdie();
10484 (void) memset(&pgelts, 0, sizeof (pgelts));
10486 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10487 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10488 scfdie();
10490 if (strcmp(exp_str, scf_property_enabled) == 0) {
10491 continue;
10492 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
10493 xmlNodePtr rnode, sfnode;
10495 rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10496 if (rnode == NULL)
10497 uu_die(emsg_create_xml);
10499 sfnode = xmlNewChild(rnode, NULL,
10500 (xmlChar *)"service_fmri", NULL);
10501 if (sfnode == NULL)
10502 uu_die(emsg_create_xml);
10504 if (set_attr_from_prop(exp_prop, sfnode,
10505 value_attr) == 0) {
10506 elts->restarter = rnode;
10507 continue;
10510 xmlFreeNode(rnode);
10513 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10515 if (ret == -1)
10516 scfdie();
10518 if (pgelts.propvals != NULL || pgelts.properties != NULL)
10519 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10520 elts);
10524 * Put an instance element for the given instance into selts.
10526 static void
10527 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10529 xmlNodePtr n;
10530 boolean_t isdefault;
10531 struct entity_elts elts;
10532 struct template_elts template_elts;
10533 int ret;
10535 n = xmlNewNode(NULL, (xmlChar *)"instance");
10536 if (n == NULL)
10537 uu_die(emsg_create_xml);
10539 /* name */
10540 if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10541 scfdie();
10542 safe_setprop(n, name_attr, exp_str);
10543 isdefault = strcmp(exp_str, "default") == 0;
10545 /* check existance of general pg (since general/enabled is required) */
10546 if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
10547 if (scf_error() != SCF_ERROR_NOT_FOUND)
10548 scfdie();
10550 if (g_verbose) {
10551 if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10552 scfdie();
10554 warn(gettext("Instance %s has no general property "
10555 "group; it will be marked disabled.\n"), exp_str);
10558 safe_setprop(n, enabled_attr, false);
10559 } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
10560 strcmp(exp_str, scf_group_framework) != 0) {
10561 if (g_verbose) {
10562 if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10563 scfdie();
10565 warn(gettext("Property group %s is not of type "
10566 "framework; the instance will be marked "
10567 "disabled.\n"), exp_str);
10570 safe_setprop(n, enabled_attr, false);
10573 /* property groups */
10574 if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
10575 scfdie();
10577 (void) memset(&elts, 0, sizeof (elts));
10578 (void) memset(&template_elts, 0, sizeof (template_elts));
10580 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10581 uint32_t pgflags;
10583 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10584 scfdie();
10586 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10587 continue;
10589 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10590 scfdie();
10592 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10593 export_dependency(exp_pg, &elts);
10594 continue;
10595 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10596 export_method(exp_pg, &elts);
10597 continue;
10598 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10599 if (scf_pg_get_name(exp_pg, exp_str,
10600 max_scf_name_len + 1) < 0)
10601 scfdie();
10603 if (strcmp(exp_str, scf_pg_general) == 0) {
10604 export_inst_general(exp_pg, n, &elts);
10605 continue;
10606 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10607 0) {
10608 export_method_context(exp_pg, &elts);
10609 continue;
10610 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10611 export_dependents(exp_pg, &elts);
10612 continue;
10614 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10615 export_template(exp_pg, &elts, &template_elts);
10616 continue;
10617 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10618 export_notify_params(exp_pg, &elts);
10619 continue;
10622 /* Ordinary pg. */
10623 export_pg(exp_pg, &elts, flags);
10625 if (ret == -1)
10626 scfdie();
10628 if (template_elts.common_name != NULL) {
10629 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10630 (void) xmlAddChild(elts.template, template_elts.common_name);
10631 (void) xmlAddChild(elts.template, template_elts.description);
10632 (void) xmlAddChild(elts.template, template_elts.documentation);
10633 } else {
10634 xmlFreeNode(template_elts.description);
10635 xmlFreeNode(template_elts.documentation);
10638 if (isdefault && elts.restarter == NULL &&
10639 elts.dependencies == NULL && elts.method_context == NULL &&
10640 elts.exec_methods == NULL && elts.notify_params == NULL &&
10641 elts.property_groups == NULL && elts.template == NULL) {
10642 xmlChar *eval;
10644 /* This is a default instance */
10645 eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10647 xmlFreeNode(n);
10649 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10650 if (n == NULL)
10651 uu_die(emsg_create_xml);
10653 safe_setprop(n, enabled_attr, (char *)eval);
10654 xmlFree(eval);
10656 selts->create_default_instance = n;
10657 } else {
10658 /* Assemble the children in order. */
10659 (void) xmlAddChild(n, elts.restarter);
10660 (void) xmlAddChildList(n, elts.dependencies);
10661 (void) xmlAddChildList(n, elts.dependents);
10662 (void) xmlAddChild(n, elts.method_context);
10663 (void) xmlAddChildList(n, elts.exec_methods);
10664 (void) xmlAddChildList(n, elts.notify_params);
10665 (void) xmlAddChildList(n, elts.property_groups);
10666 (void) xmlAddChild(n, elts.template);
10668 if (selts->instances == NULL)
10669 selts->instances = n;
10670 else
10671 (void) xmlAddSibling(selts->instances, n);
10676 * Return a service element for the given service.
10678 static xmlNodePtr
10679 export_service(scf_service_t *svc, int flags)
10681 xmlNodePtr snode;
10682 struct entity_elts elts;
10683 struct template_elts template_elts;
10684 int ret;
10686 snode = xmlNewNode(NULL, (xmlChar *)"service");
10687 if (snode == NULL)
10688 uu_die(emsg_create_xml);
10690 /* Get & set name attribute */
10691 if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
10692 scfdie();
10693 safe_setprop(snode, name_attr, exp_str);
10695 safe_setprop(snode, type_attr, "service");
10696 safe_setprop(snode, "version", "0");
10698 /* Acquire child elements. */
10699 if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
10700 scfdie();
10702 (void) memset(&elts, 0, sizeof (elts));
10703 (void) memset(&template_elts, 0, sizeof (template_elts));
10705 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10706 uint32_t pgflags;
10708 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10709 scfdie();
10711 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10712 continue;
10714 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10715 scfdie();
10717 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10718 export_dependency(exp_pg, &elts);
10719 continue;
10720 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10721 export_method(exp_pg, &elts);
10722 continue;
10723 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10724 if (scf_pg_get_name(exp_pg, exp_str,
10725 max_scf_name_len + 1) < 0)
10726 scfdie();
10728 if (strcmp(exp_str, scf_pg_general) == 0) {
10729 export_svc_general(exp_pg, &elts);
10730 continue;
10731 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10732 0) {
10733 export_method_context(exp_pg, &elts);
10734 continue;
10735 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10736 export_dependents(exp_pg, &elts);
10737 continue;
10738 } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10739 continue;
10741 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10742 export_template(exp_pg, &elts, &template_elts);
10743 continue;
10744 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10745 export_notify_params(exp_pg, &elts);
10746 continue;
10749 export_pg(exp_pg, &elts, flags);
10751 if (ret == -1)
10752 scfdie();
10754 if (template_elts.common_name != NULL) {
10755 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10756 (void) xmlAddChild(elts.template, template_elts.common_name);
10757 (void) xmlAddChild(elts.template, template_elts.description);
10758 (void) xmlAddChild(elts.template, template_elts.documentation);
10759 } else {
10760 xmlFreeNode(template_elts.description);
10761 xmlFreeNode(template_elts.documentation);
10764 /* Iterate instances */
10765 if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
10766 scfdie();
10768 while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10769 export_instance(exp_inst, &elts, flags);
10770 if (ret == -1)
10771 scfdie();
10773 /* Now add all of the accumulated elements in order. */
10774 (void) xmlAddChild(snode, elts.create_default_instance);
10775 (void) xmlAddChild(snode, elts.single_instance);
10776 (void) xmlAddChild(snode, elts.restarter);
10777 (void) xmlAddChildList(snode, elts.dependencies);
10778 (void) xmlAddChildList(snode, elts.dependents);
10779 (void) xmlAddChild(snode, elts.method_context);
10780 (void) xmlAddChildList(snode, elts.exec_methods);
10781 (void) xmlAddChildList(snode, elts.notify_params);
10782 (void) xmlAddChildList(snode, elts.property_groups);
10783 (void) xmlAddChildList(snode, elts.instances);
10784 (void) xmlAddChild(snode, elts.stability);
10785 (void) xmlAddChild(snode, elts.template);
10787 return (snode);
10790 static int
10791 export_callback(void *data, scf_walkinfo_t *wip)
10793 FILE *f;
10794 xmlDocPtr doc;
10795 xmlNodePtr sb;
10796 int result;
10797 struct export_args *argsp = (struct export_args *)data;
10799 if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
10800 (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10801 (exp_prop = scf_property_create(g_hndl)) == NULL ||
10802 (exp_val = scf_value_create(g_hndl)) == NULL ||
10803 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10804 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10805 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10806 (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10807 scfdie();
10809 exp_str_sz = max_scf_len + 1;
10810 exp_str = safe_malloc(exp_str_sz);
10812 if (argsp->filename != NULL) {
10813 errno = 0;
10814 f = fopen(argsp->filename, "wb");
10815 if (f == NULL) {
10816 if (errno == 0)
10817 uu_die(gettext("Could not open \"%s\": no free "
10818 "stdio streams.\n"), argsp->filename);
10819 else
10820 uu_die(gettext("Could not open \"%s\""),
10821 argsp->filename);
10823 } else
10824 f = stdout;
10826 doc = xmlNewDoc((xmlChar *)"1.0");
10827 if (doc == NULL)
10828 uu_die(gettext("Could not create XML document.\n"));
10830 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10831 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10832 uu_die(emsg_create_xml);
10834 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10835 if (sb == NULL)
10836 uu_die(emsg_create_xml);
10837 safe_setprop(sb, type_attr, "manifest");
10838 safe_setprop(sb, name_attr, "export");
10839 (void) xmlAddSibling(doc->children, sb);
10841 (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
10843 result = write_service_bundle(doc, f);
10845 free(exp_str);
10846 scf_iter_destroy(exp_val_iter);
10847 scf_iter_destroy(exp_prop_iter);
10848 scf_iter_destroy(exp_pg_iter);
10849 scf_iter_destroy(exp_inst_iter);
10850 scf_value_destroy(exp_val);
10851 scf_property_destroy(exp_prop);
10852 scf_pg_destroy(exp_pg);
10853 scf_instance_destroy(exp_inst);
10855 xmlFreeDoc(doc);
10857 if (f != stdout)
10858 (void) fclose(f);
10860 return (result);
10864 * Get the service named by fmri, build an XML tree which represents it, and
10865 * dump it into filename (or stdout if filename is NULL).
10868 lscf_service_export(char *fmri, const char *filename, int flags)
10870 struct export_args args;
10871 char *fmridup;
10872 const char *scope, *svc, *inst;
10873 size_t cblen = 3 * max_scf_name_len;
10874 char *canonbuf = alloca(cblen);
10875 int ret, err;
10877 lscf_prep_hndl();
10879 bzero(&args, sizeof (args));
10880 args.filename = filename;
10881 args.flags = flags;
10884 * If some poor user has passed an exact instance FMRI, of the sort
10885 * one might cut and paste from svcs(1) or an error message, warn
10886 * and chop off the instance instead of failing.
10888 fmridup = alloca(strlen(fmri) + 1);
10889 (void) strcpy(fmridup, fmri);
10890 if (strncmp(fmridup, SCF_FMRI_SVC_PREFIX,
10891 sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 &&
10892 scf_parse_svc_fmri(fmridup, &scope, &svc, &inst, NULL, NULL) == 0 &&
10893 inst != NULL) {
10894 (void) strlcpy(canonbuf, "svc:/", cblen);
10895 if (strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
10896 (void) strlcat(canonbuf, "/", cblen);
10897 (void) strlcat(canonbuf, scope, cblen);
10899 (void) strlcat(canonbuf, svc, cblen);
10900 fmri = canonbuf;
10902 warn(gettext("Only services may be exported; ignoring "
10903 "instance portion of argument.\n"));
10906 err = 0;
10907 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10908 SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10909 &args, &err, semerr)) != 0) {
10910 if (ret != -1)
10911 semerr(gettext("Failed to walk instances: %s\n"),
10912 scf_strerror(ret));
10913 return (-1);
10917 * Error message has already been printed.
10919 if (err != 0)
10920 return (-1);
10922 return (0);
10927 * Archive
10930 static xmlNodePtr
10931 make_archive(int flags)
10933 xmlNodePtr sb;
10934 scf_scope_t *scope;
10935 scf_service_t *svc;
10936 scf_iter_t *iter;
10937 int r;
10939 if ((scope = scf_scope_create(g_hndl)) == NULL ||
10940 (svc = scf_service_create(g_hndl)) == NULL ||
10941 (iter = scf_iter_create(g_hndl)) == NULL ||
10942 (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10943 (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10944 (exp_prop = scf_property_create(g_hndl)) == NULL ||
10945 (exp_val = scf_value_create(g_hndl)) == NULL ||
10946 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10947 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10948 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10949 (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10950 scfdie();
10952 exp_str_sz = max_scf_len + 1;
10953 exp_str = safe_malloc(exp_str_sz);
10955 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10956 if (sb == NULL)
10957 uu_die(emsg_create_xml);
10958 safe_setprop(sb, type_attr, "archive");
10959 safe_setprop(sb, name_attr, "none");
10961 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
10962 scfdie();
10963 if (scf_iter_scope_services(iter, scope) != 0)
10964 scfdie();
10966 for (;;) {
10967 r = scf_iter_next_service(iter, svc);
10968 if (r == 0)
10969 break;
10970 if (r != 1)
10971 scfdie();
10973 if (scf_service_get_name(svc, exp_str,
10974 max_scf_name_len + 1) < 0)
10975 scfdie();
10977 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
10978 continue;
10980 (void) xmlAddChild(sb, export_service(svc, flags));
10983 free(exp_str);
10985 scf_iter_destroy(exp_val_iter);
10986 scf_iter_destroy(exp_prop_iter);
10987 scf_iter_destroy(exp_pg_iter);
10988 scf_iter_destroy(exp_inst_iter);
10989 scf_value_destroy(exp_val);
10990 scf_property_destroy(exp_prop);
10991 scf_pg_destroy(exp_pg);
10992 scf_instance_destroy(exp_inst);
10993 scf_iter_destroy(iter);
10994 scf_service_destroy(svc);
10995 scf_scope_destroy(scope);
10997 return (sb);
11001 lscf_archive(const char *filename, int flags)
11003 FILE *f;
11004 xmlDocPtr doc;
11005 int result;
11007 lscf_prep_hndl();
11009 if (filename != NULL) {
11010 errno = 0;
11011 f = fopen(filename, "wb");
11012 if (f == NULL) {
11013 if (errno == 0)
11014 uu_die(gettext("Could not open \"%s\": no free "
11015 "stdio streams.\n"), filename);
11016 else
11017 uu_die(gettext("Could not open \"%s\""),
11018 filename);
11020 } else
11021 f = stdout;
11023 doc = xmlNewDoc((xmlChar *)"1.0");
11024 if (doc == NULL)
11025 uu_die(gettext("Could not create XML document.\n"));
11027 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11028 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11029 uu_die(emsg_create_xml);
11031 (void) xmlAddSibling(doc->children, make_archive(flags));
11033 result = write_service_bundle(doc, f);
11035 xmlFreeDoc(doc);
11037 if (f != stdout)
11038 (void) fclose(f);
11040 return (result);
11045 * "Extract" a profile.
11048 lscf_profile_extract(const char *filename)
11050 FILE *f;
11051 xmlDocPtr doc;
11052 xmlNodePtr sb, snode, inode;
11053 scf_scope_t *scope;
11054 scf_service_t *svc;
11055 scf_instance_t *inst;
11056 scf_propertygroup_t *pg;
11057 scf_property_t *prop;
11058 scf_value_t *val;
11059 scf_iter_t *siter, *iiter;
11060 int r, s;
11061 char *namebuf;
11062 uint8_t b;
11063 int result;
11065 lscf_prep_hndl();
11067 if (filename != NULL) {
11068 errno = 0;
11069 f = fopen(filename, "wb");
11070 if (f == NULL) {
11071 if (errno == 0)
11072 uu_die(gettext("Could not open \"%s\": no "
11073 "free stdio streams.\n"), filename);
11074 else
11075 uu_die(gettext("Could not open \"%s\""),
11076 filename);
11078 } else
11079 f = stdout;
11081 doc = xmlNewDoc((xmlChar *)"1.0");
11082 if (doc == NULL)
11083 uu_die(gettext("Could not create XML document.\n"));
11085 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11086 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11087 uu_die(emsg_create_xml);
11089 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
11090 if (sb == NULL)
11091 uu_die(emsg_create_xml);
11092 safe_setprop(sb, type_attr, "profile");
11093 safe_setprop(sb, name_attr, "extract");
11094 (void) xmlAddSibling(doc->children, sb);
11096 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11097 (svc = scf_service_create(g_hndl)) == NULL ||
11098 (inst = scf_instance_create(g_hndl)) == NULL ||
11099 (pg = scf_pg_create(g_hndl)) == NULL ||
11100 (prop = scf_property_create(g_hndl)) == NULL ||
11101 (val = scf_value_create(g_hndl)) == NULL ||
11102 (siter = scf_iter_create(g_hndl)) == NULL ||
11103 (iiter = scf_iter_create(g_hndl)) == NULL)
11104 scfdie();
11106 if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
11107 scfdie();
11109 if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
11110 scfdie();
11112 namebuf = safe_malloc(max_scf_name_len + 1);
11114 while ((r = scf_iter_next_service(siter, svc)) == 1) {
11115 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
11116 scfdie();
11118 snode = xmlNewNode(NULL, (xmlChar *)"service");
11119 if (snode == NULL)
11120 uu_die(emsg_create_xml);
11122 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
11124 scfdie();
11126 safe_setprop(snode, name_attr, namebuf);
11128 safe_setprop(snode, type_attr, "service");
11129 safe_setprop(snode, "version", "0");
11131 while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
11132 if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
11133 SCF_SUCCESS) {
11134 if (scf_error() != SCF_ERROR_NOT_FOUND)
11135 scfdie();
11137 if (g_verbose) {
11138 ssize_t len;
11139 char *fmri;
11141 len =
11142 scf_instance_to_fmri(inst, NULL, 0);
11143 if (len < 0)
11144 scfdie();
11146 fmri = safe_malloc(len + 1);
11148 if (scf_instance_to_fmri(inst, fmri,
11149 len + 1) < 0)
11150 scfdie();
11152 warn("Instance %s has no \"%s\" "
11153 "property group.\n", fmri,
11154 scf_pg_general);
11156 free(fmri);
11159 continue;
11162 if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
11163 prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
11164 prop_get_val(prop, val) != 0)
11165 continue;
11167 inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
11168 NULL);
11169 if (inode == NULL)
11170 uu_die(emsg_create_xml);
11172 if (scf_instance_get_name(inst, namebuf,
11173 max_scf_name_len + 1) < 0)
11174 scfdie();
11176 safe_setprop(inode, name_attr, namebuf);
11178 if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
11179 scfdie();
11181 safe_setprop(inode, enabled_attr, b ? true : false);
11183 if (s < 0)
11184 scfdie();
11186 if (snode->children != NULL)
11187 (void) xmlAddChild(sb, snode);
11188 else
11189 xmlFreeNode(snode);
11191 if (r < 0)
11192 scfdie();
11194 free(namebuf);
11196 result = write_service_bundle(doc, f);
11198 xmlFreeDoc(doc);
11200 if (f != stdout)
11201 (void) fclose(f);
11203 return (result);
11208 * Entity manipulation commands
11212 * Entity selection. If no entity is selected, then the current scope is in
11213 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected,
11214 * only cur_inst is NULL, and when an instance is selected, none are NULL.
11215 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
11216 * cur_inst will be non-NULL.
11219 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
11220 static int
11221 select_inst(const char *name)
11223 scf_instance_t *inst;
11224 scf_error_t err;
11226 assert(cur_svc != NULL);
11228 inst = scf_instance_create(g_hndl);
11229 if (inst == NULL)
11230 scfdie();
11232 if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
11233 cur_inst = inst;
11234 return (0);
11237 err = scf_error();
11238 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11239 scfdie();
11241 scf_instance_destroy(inst);
11242 return (1);
11245 /* Returns as above. */
11246 static int
11247 select_svc(const char *name)
11249 scf_service_t *svc;
11250 scf_error_t err;
11252 assert(cur_scope != NULL);
11254 svc = scf_service_create(g_hndl);
11255 if (svc == NULL)
11256 scfdie();
11258 if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
11259 cur_svc = svc;
11260 return (0);
11263 err = scf_error();
11264 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11265 scfdie();
11267 scf_service_destroy(svc);
11268 return (1);
11271 /* ARGSUSED */
11272 static int
11273 select_callback(void *unused, scf_walkinfo_t *wip)
11275 scf_instance_t *inst;
11276 scf_service_t *svc;
11277 scf_scope_t *scope;
11279 if (wip->inst != NULL) {
11280 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11281 (svc = scf_service_create(g_hndl)) == NULL ||
11282 (inst = scf_instance_create(g_hndl)) == NULL)
11283 scfdie();
11285 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11286 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11287 scfdie();
11288 } else {
11289 assert(wip->svc != NULL);
11291 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11292 (svc = scf_service_create(g_hndl)) == NULL)
11293 scfdie();
11295 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11296 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11297 scfdie();
11299 inst = NULL;
11302 /* Clear out the current selection */
11303 assert(cur_scope != NULL);
11304 scf_scope_destroy(cur_scope);
11305 scf_service_destroy(cur_svc);
11306 scf_instance_destroy(cur_inst);
11308 cur_scope = scope;
11309 cur_svc = svc;
11310 cur_inst = inst;
11312 return (0);
11315 static int
11316 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
11318 char **fmri = fmri_p;
11320 *fmri = strdup(wip->fmri);
11321 if (*fmri == NULL)
11322 uu_die(gettext("Out of memory.\n"));
11324 return (0);
11328 * validate [fmri]
11329 * Perform the validation of an FMRI instance.
11331 void
11332 lscf_validate_fmri(const char *fmri)
11334 int ret = 0;
11335 size_t inst_sz;
11336 char *inst_fmri = NULL;
11337 scf_tmpl_errors_t *errs = NULL;
11338 char *snapbuf = NULL;
11340 lscf_prep_hndl();
11342 if (fmri == NULL) {
11343 inst_sz = max_scf_fmri_len + 1;
11344 inst_fmri = safe_malloc(inst_sz);
11346 if (cur_snap != NULL) {
11347 snapbuf = safe_malloc(max_scf_name_len + 1);
11348 if (scf_snapshot_get_name(cur_snap, snapbuf,
11349 max_scf_name_len + 1) < 0)
11350 scfdie();
11352 if (cur_inst == NULL) {
11353 semerr(gettext("No instance selected\n"));
11354 goto cleanup;
11355 } else if (scf_instance_to_fmri(cur_inst, inst_fmri,
11356 inst_sz) >= inst_sz) {
11357 /* sanity check. Should never get here */
11358 uu_die(gettext("Unexpected error! file %s, line %d\n"),
11359 __FILE__, __LINE__);
11361 } else {
11362 scf_error_t scf_err;
11363 int err = 0;
11365 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
11366 validate_callback, &inst_fmri, &err, semerr)) != 0) {
11367 uu_warn("Failed to walk instances: %s\n",
11368 scf_strerror(scf_err));
11369 goto cleanup;
11371 if (err != 0) {
11372 /* error message displayed by scf_walk_fmri */
11373 goto cleanup;
11377 ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
11378 SCF_TMPL_VALIDATE_FLAG_CURRENT);
11379 if (ret == -1) {
11380 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
11381 warn(gettext("Template data for %s is invalid. "
11382 "Consider reverting to a previous snapshot or "
11383 "restoring original configuration.\n"), inst_fmri);
11384 } else {
11385 uu_warn("%s: %s\n",
11386 gettext("Error validating the instance"),
11387 scf_strerror(scf_error()));
11389 } else if (ret == 1 && errs != NULL) {
11390 scf_tmpl_error_t *err = NULL;
11391 char *msg;
11392 size_t len = 256; /* initial error buffer size */
11393 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
11394 SCF_TMPL_STRERROR_HUMAN : 0;
11396 msg = safe_malloc(len);
11398 while ((err = scf_tmpl_next_error(errs)) != NULL) {
11399 int ret;
11401 if ((ret = scf_tmpl_strerror(err, msg, len,
11402 flag)) >= len) {
11403 len = ret + 1;
11404 msg = realloc(msg, len);
11405 if (msg == NULL)
11406 uu_die(gettext(
11407 "Out of memory.\n"));
11408 (void) scf_tmpl_strerror(err, msg, len,
11409 flag);
11411 (void) fprintf(stderr, "%s\n", msg);
11413 if (msg != NULL)
11414 free(msg);
11416 if (errs != NULL)
11417 scf_tmpl_errors_destroy(errs);
11419 cleanup:
11420 free(inst_fmri);
11421 free(snapbuf);
11424 static void
11425 lscf_validate_file(const char *filename)
11427 tmpl_errors_t *errs;
11429 bundle_t *b = internal_bundle_new();
11430 if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
11431 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
11432 tmpl_errors_print(stderr, errs, "");
11433 semerr(gettext("Validation failed.\n"));
11435 tmpl_errors_destroy(errs);
11437 (void) internal_bundle_free(b);
11441 * validate [fmri|file]
11443 void
11444 lscf_validate(const char *arg)
11446 const char *str;
11448 if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
11449 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
11450 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
11451 lscf_validate_file(str);
11452 } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
11453 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
11454 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
11455 lscf_validate_fmri(str);
11456 } else if (access(arg, R_OK | F_OK) == 0) {
11457 lscf_validate_file(arg);
11458 } else {
11459 lscf_validate_fmri(arg);
11463 void
11464 lscf_select(const char *fmri)
11466 int ret, err;
11468 lscf_prep_hndl();
11470 if (cur_snap != NULL) {
11471 struct snaplevel *elt;
11472 char *buf;
11474 /* Error unless name is that of the next level. */
11475 elt = uu_list_next(cur_levels, cur_elt);
11476 if (elt == NULL) {
11477 semerr(gettext("No children.\n"));
11478 return;
11481 buf = safe_malloc(max_scf_name_len + 1);
11483 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11484 max_scf_name_len + 1) < 0)
11485 scfdie();
11487 if (strcmp(buf, fmri) != 0) {
11488 semerr(gettext("No such child.\n"));
11489 free(buf);
11490 return;
11493 free(buf);
11495 cur_elt = elt;
11496 cur_level = elt->sl;
11497 return;
11501 * Special case for 'svc:', which takes the user to the scope level.
11503 if (strcmp(fmri, "svc:") == 0) {
11504 scf_instance_destroy(cur_inst);
11505 scf_service_destroy(cur_svc);
11506 cur_inst = NULL;
11507 cur_svc = NULL;
11508 return;
11512 * Special case for ':properties'. This appears as part of 'list' but
11513 * can't be selected. Give a more helpful error message in this case.
11515 if (strcmp(fmri, ":properties") == 0) {
11516 semerr(gettext(":properties is not an entity. Try 'listprop' "
11517 "to list properties.\n"));
11518 return;
11522 * First try the argument as relative to the current selection.
11524 if (cur_inst != NULL) {
11525 /* EMPTY */;
11526 } else if (cur_svc != NULL) {
11527 if (select_inst(fmri) != 1)
11528 return;
11529 } else {
11530 if (select_svc(fmri) != 1)
11531 return;
11534 err = 0;
11535 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11536 select_callback, NULL, &err, semerr)) != 0) {
11537 semerr(gettext("Failed to walk instances: %s\n"),
11538 scf_strerror(ret));
11542 void
11543 lscf_unselect(void)
11545 lscf_prep_hndl();
11547 if (cur_snap != NULL) {
11548 struct snaplevel *elt;
11550 elt = uu_list_prev(cur_levels, cur_elt);
11551 if (elt == NULL) {
11552 semerr(gettext("No parent levels.\n"));
11553 } else {
11554 cur_elt = elt;
11555 cur_level = elt->sl;
11557 } else if (cur_inst != NULL) {
11558 scf_instance_destroy(cur_inst);
11559 cur_inst = NULL;
11560 } else if (cur_svc != NULL) {
11561 scf_service_destroy(cur_svc);
11562 cur_svc = NULL;
11563 } else {
11564 semerr(gettext("Cannot unselect at scope level.\n"));
11569 * Return the FMRI of the current selection, for the prompt.
11571 void
11572 lscf_get_selection_str(char *buf, size_t bufsz)
11574 char *cp;
11575 ssize_t fmrilen, szret;
11576 boolean_t deleted = B_FALSE;
11578 if (g_hndl == NULL) {
11579 (void) strlcpy(buf, "svc:", bufsz);
11580 return;
11583 if (cur_level != NULL) {
11584 assert(cur_snap != NULL);
11586 /* [ snapshot ] FMRI [: instance ] */
11587 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11588 + 2 + max_scf_name_len + 1 + 1);
11590 buf[0] = '[';
11592 szret = scf_snapshot_get_name(cur_snap, buf + 1,
11593 max_scf_name_len + 1);
11594 if (szret < 0) {
11595 if (scf_error() != SCF_ERROR_DELETED)
11596 scfdie();
11598 goto snap_deleted;
11601 (void) strcat(buf, "]svc:/");
11603 cp = strchr(buf, '\0');
11605 szret = scf_snaplevel_get_service_name(cur_level, cp,
11606 max_scf_name_len + 1);
11607 if (szret < 0) {
11608 if (scf_error() != SCF_ERROR_DELETED)
11609 scfdie();
11611 goto snap_deleted;
11614 cp = strchr(cp, '\0');
11616 if (snaplevel_is_instance(cur_level)) {
11617 *cp++ = ':';
11619 if (scf_snaplevel_get_instance_name(cur_level, cp,
11620 max_scf_name_len + 1) < 0) {
11621 if (scf_error() != SCF_ERROR_DELETED)
11622 scfdie();
11624 goto snap_deleted;
11626 } else {
11627 *cp++ = '[';
11628 *cp++ = ':';
11630 if (scf_instance_get_name(cur_inst, cp,
11631 max_scf_name_len + 1) < 0) {
11632 if (scf_error() != SCF_ERROR_DELETED)
11633 scfdie();
11635 goto snap_deleted;
11638 (void) strcat(buf, "]");
11641 return;
11643 snap_deleted:
11644 deleted = B_TRUE;
11645 free(buf);
11646 unselect_cursnap();
11649 assert(cur_snap == NULL);
11651 if (cur_inst != NULL) {
11652 assert(cur_svc != NULL);
11653 assert(cur_scope != NULL);
11655 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11656 if (fmrilen >= 0) {
11657 assert(fmrilen < bufsz);
11658 if (deleted)
11659 warn(emsg_deleted);
11660 return;
11663 if (scf_error() != SCF_ERROR_DELETED)
11664 scfdie();
11666 deleted = B_TRUE;
11668 scf_instance_destroy(cur_inst);
11669 cur_inst = NULL;
11672 if (cur_svc != NULL) {
11673 assert(cur_scope != NULL);
11675 szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11676 if (szret >= 0) {
11677 assert(szret < bufsz);
11678 if (deleted)
11679 warn(emsg_deleted);
11680 return;
11683 if (scf_error() != SCF_ERROR_DELETED)
11684 scfdie();
11686 deleted = B_TRUE;
11687 scf_service_destroy(cur_svc);
11688 cur_svc = NULL;
11691 assert(cur_scope != NULL);
11692 fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11694 if (fmrilen < 0)
11695 scfdie();
11697 assert(fmrilen < bufsz);
11698 if (deleted)
11699 warn(emsg_deleted);
11703 * Entity listing. Entities and colon namespaces (e.g., :properties and
11704 * :statistics) are listed for the current selection.
11706 void
11707 lscf_list(const char *pattern)
11709 scf_iter_t *iter;
11710 char *buf;
11711 int ret;
11713 lscf_prep_hndl();
11715 if (cur_level != NULL) {
11716 struct snaplevel *elt;
11718 (void) fputs(COLON_NAMESPACES, stdout);
11720 elt = uu_list_next(cur_levels, cur_elt);
11721 if (elt == NULL)
11722 return;
11725 * For now, we know that the next level is an instance. But
11726 * if we ever have multiple scopes, this could be complicated.
11728 buf = safe_malloc(max_scf_name_len + 1);
11729 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11730 max_scf_name_len + 1) >= 0) {
11731 (void) puts(buf);
11732 } else {
11733 if (scf_error() != SCF_ERROR_DELETED)
11734 scfdie();
11737 free(buf);
11739 return;
11742 if (cur_inst != NULL) {
11743 (void) fputs(COLON_NAMESPACES, stdout);
11744 return;
11747 iter = scf_iter_create(g_hndl);
11748 if (iter == NULL)
11749 scfdie();
11751 buf = safe_malloc(max_scf_name_len + 1);
11753 if (cur_svc != NULL) {
11754 /* List the instances in this service. */
11755 scf_instance_t *inst;
11757 inst = scf_instance_create(g_hndl);
11758 if (inst == NULL)
11759 scfdie();
11761 if (scf_iter_service_instances(iter, cur_svc) == 0) {
11762 safe_printf(COLON_NAMESPACES);
11764 for (;;) {
11765 ret = scf_iter_next_instance(iter, inst);
11766 if (ret == 0)
11767 break;
11768 if (ret != 1) {
11769 if (scf_error() != SCF_ERROR_DELETED)
11770 scfdie();
11772 break;
11775 if (scf_instance_get_name(inst, buf,
11776 max_scf_name_len + 1) >= 0) {
11777 if (pattern == NULL ||
11778 fnmatch(pattern, buf, 0) == 0)
11779 (void) puts(buf);
11780 } else {
11781 if (scf_error() != SCF_ERROR_DELETED)
11782 scfdie();
11785 } else {
11786 if (scf_error() != SCF_ERROR_DELETED)
11787 scfdie();
11790 scf_instance_destroy(inst);
11791 } else {
11792 /* List the services in this scope. */
11793 scf_service_t *svc;
11795 assert(cur_scope != NULL);
11797 svc = scf_service_create(g_hndl);
11798 if (svc == NULL)
11799 scfdie();
11801 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11802 scfdie();
11804 for (;;) {
11805 ret = scf_iter_next_service(iter, svc);
11806 if (ret == 0)
11807 break;
11808 if (ret != 1)
11809 scfdie();
11811 if (scf_service_get_name(svc, buf,
11812 max_scf_name_len + 1) >= 0) {
11813 if (pattern == NULL ||
11814 fnmatch(pattern, buf, 0) == 0)
11815 safe_printf("%s\n", buf);
11816 } else {
11817 if (scf_error() != SCF_ERROR_DELETED)
11818 scfdie();
11822 scf_service_destroy(svc);
11825 free(buf);
11826 scf_iter_destroy(iter);
11830 * Entity addition. Creates an empty entity in the current selection.
11832 void
11833 lscf_add(const char *name)
11835 lscf_prep_hndl();
11837 if (cur_snap != NULL) {
11838 semerr(emsg_cant_modify_snapshots);
11839 } else if (cur_inst != NULL) {
11840 semerr(gettext("Cannot add entities to an instance.\n"));
11841 } else if (cur_svc != NULL) {
11843 if (scf_service_add_instance(cur_svc, name, NULL) !=
11844 SCF_SUCCESS) {
11845 switch (scf_error()) {
11846 case SCF_ERROR_INVALID_ARGUMENT:
11847 semerr(gettext("Invalid name.\n"));
11848 break;
11850 case SCF_ERROR_EXISTS:
11851 semerr(gettext("Instance already exists.\n"));
11852 break;
11854 case SCF_ERROR_PERMISSION_DENIED:
11855 semerr(emsg_permission_denied);
11856 break;
11858 default:
11859 scfdie();
11862 } else {
11863 assert(cur_scope != NULL);
11865 if (scf_scope_add_service(cur_scope, name, NULL) !=
11866 SCF_SUCCESS) {
11867 switch (scf_error()) {
11868 case SCF_ERROR_INVALID_ARGUMENT:
11869 semerr(gettext("Invalid name.\n"));
11870 break;
11872 case SCF_ERROR_EXISTS:
11873 semerr(gettext("Service already exists.\n"));
11874 break;
11876 case SCF_ERROR_PERMISSION_DENIED:
11877 semerr(emsg_permission_denied);
11878 break;
11880 case SCF_ERROR_BACKEND_READONLY:
11881 semerr(emsg_read_only);
11882 break;
11884 default:
11885 scfdie();
11891 /* return 1 if the entity has no persistent pgs, else return 0 */
11892 static int
11893 entity_has_no_pgs(void *ent, int isservice)
11895 scf_iter_t *iter = NULL;
11896 scf_propertygroup_t *pg = NULL;
11897 uint32_t flags;
11898 int err;
11899 int ret = 1;
11901 if ((iter = scf_iter_create(g_hndl)) == NULL ||
11902 (pg = scf_pg_create(g_hndl)) == NULL)
11903 scfdie();
11905 if (isservice) {
11906 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11907 scfdie();
11908 } else {
11909 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11910 scfdie();
11913 while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11914 if (scf_pg_get_flags(pg, &flags) != 0)
11915 scfdie();
11917 /* skip nonpersistent pgs */
11918 if (flags & SCF_PG_FLAG_NONPERSISTENT)
11919 continue;
11921 ret = 0;
11922 break;
11925 if (err == -1)
11926 scfdie();
11928 scf_pg_destroy(pg);
11929 scf_iter_destroy(iter);
11931 return (ret);
11934 /* return 1 if the service has no instances, else return 0 */
11935 static int
11936 svc_has_no_insts(scf_service_t *svc)
11938 scf_instance_t *inst;
11939 scf_iter_t *iter;
11940 int r;
11941 int ret = 1;
11943 if ((inst = scf_instance_create(g_hndl)) == NULL ||
11944 (iter = scf_iter_create(g_hndl)) == NULL)
11945 scfdie();
11947 if (scf_iter_service_instances(iter, svc) != 0)
11948 scfdie();
11950 r = scf_iter_next_instance(iter, inst);
11951 if (r == 1) {
11952 ret = 0;
11953 } else if (r == 0) {
11954 ret = 1;
11955 } else if (r == -1) {
11956 scfdie();
11957 } else {
11958 bad_error("scf_iter_next_instance", r);
11961 scf_iter_destroy(iter);
11962 scf_instance_destroy(inst);
11964 return (ret);
11968 * Entity deletion.
11972 * Delete the property group <fmri>/:properties/<name>. Returns
11973 * SCF_ERROR_NONE on success (or if the entity is not found),
11974 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
11975 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
11976 * denied.
11978 static scf_error_t
11979 delete_dependency_pg(const char *fmri, const char *name)
11981 void *entity = NULL;
11982 int isservice;
11983 scf_propertygroup_t *pg = NULL;
11984 scf_error_t result;
11985 char *pgty;
11986 scf_service_t *svc = NULL;
11987 scf_instance_t *inst = NULL;
11988 scf_iter_t *iter = NULL;
11989 char *name_buf = NULL;
11991 result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
11992 switch (result) {
11993 case SCF_ERROR_NONE:
11994 break;
11996 case SCF_ERROR_NO_MEMORY:
11997 uu_die(gettext("Out of memory.\n"));
11998 /* NOTREACHED */
12000 case SCF_ERROR_INVALID_ARGUMENT:
12001 case SCF_ERROR_CONSTRAINT_VIOLATED:
12002 return (SCF_ERROR_INVALID_ARGUMENT);
12004 case SCF_ERROR_NOT_FOUND:
12005 result = SCF_ERROR_NONE;
12006 goto out;
12008 default:
12009 bad_error("fmri_to_entity", result);
12012 pg = scf_pg_create(g_hndl);
12013 if (pg == NULL)
12014 scfdie();
12016 if (entity_get_pg(entity, isservice, name, pg) != 0) {
12017 if (scf_error() != SCF_ERROR_NOT_FOUND)
12018 scfdie();
12020 result = SCF_ERROR_NONE;
12021 goto out;
12024 pgty = safe_malloc(max_scf_pg_type_len + 1);
12026 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12027 scfdie();
12029 if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
12030 result = SCF_ERROR_TYPE_MISMATCH;
12031 free(pgty);
12032 goto out;
12035 free(pgty);
12037 if (scf_pg_delete(pg) != 0) {
12038 result = scf_error();
12039 if (result != SCF_ERROR_PERMISSION_DENIED)
12040 scfdie();
12041 goto out;
12045 * We have to handle the case where we've just deleted the last
12046 * property group of a "dummy" entity (instance or service).
12047 * A "dummy" entity is an entity only present to hold an
12048 * external dependency.
12049 * So, in the case we deleted the last property group then we
12050 * can also delete the entity. If the entity is an instance then
12051 * we must verify if this was the last instance for the service
12052 * and if it is, we can also delete the service if it doesn't
12053 * have any property group either.
12056 result = SCF_ERROR_NONE;
12058 if (isservice) {
12059 svc = (scf_service_t *)entity;
12061 if ((inst = scf_instance_create(g_hndl)) == NULL ||
12062 (iter = scf_iter_create(g_hndl)) == NULL)
12063 scfdie();
12065 name_buf = safe_malloc(max_scf_name_len + 1);
12066 } else {
12067 inst = (scf_instance_t *)entity;
12071 * If the entity is an instance and we've just deleted its last
12072 * property group then we should delete it.
12074 if (!isservice && entity_has_no_pgs(entity, isservice)) {
12075 /* find the service before deleting the inst. - needed later */
12076 if ((svc = scf_service_create(g_hndl)) == NULL)
12077 scfdie();
12079 if (scf_instance_get_parent(inst, svc) != 0)
12080 scfdie();
12082 /* delete the instance */
12083 if (scf_instance_delete(inst) != 0) {
12084 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12085 scfdie();
12087 result = SCF_ERROR_PERMISSION_DENIED;
12088 goto out;
12090 /* no need to refresh the instance */
12091 inst = NULL;
12095 * If the service has no more instances and pgs or we just deleted the
12096 * last instance and the service doesn't have anymore propery groups
12097 * then the service should be deleted.
12099 if (svc != NULL &&
12100 svc_has_no_insts(svc) &&
12101 entity_has_no_pgs((void *)svc, 1)) {
12102 if (scf_service_delete(svc) == 0) {
12103 if (isservice) {
12104 /* no need to refresh the service */
12105 svc = NULL;
12108 goto out;
12111 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12112 scfdie();
12114 result = SCF_ERROR_PERMISSION_DENIED;
12117 /* if the entity has not been deleted, refresh it */
12118 if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
12119 (void) refresh_entity(isservice, entity, fmri, inst, iter,
12120 name_buf);
12123 out:
12124 if (isservice && (inst != NULL && iter != NULL)) {
12125 free(name_buf);
12126 scf_iter_destroy(iter);
12127 scf_instance_destroy(inst);
12130 if (!isservice && svc != NULL) {
12131 scf_service_destroy(svc);
12134 scf_pg_destroy(pg);
12135 if (entity != NULL)
12136 entity_destroy(entity, isservice);
12138 return (result);
12141 static int
12142 delete_dependents(scf_propertygroup_t *pg)
12144 char *pgty, *name, *fmri;
12145 scf_property_t *prop;
12146 scf_value_t *val;
12147 scf_iter_t *iter;
12148 int r;
12149 scf_error_t err;
12151 /* Verify that the pg has the correct type. */
12152 pgty = safe_malloc(max_scf_pg_type_len + 1);
12153 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12154 scfdie();
12156 if (strcmp(pgty, scf_group_framework) != 0) {
12157 if (g_verbose) {
12158 fmri = safe_malloc(max_scf_fmri_len + 1);
12159 if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
12160 scfdie();
12162 warn(gettext("Property group %s is not of expected "
12163 "type %s.\n"), fmri, scf_group_framework);
12165 free(fmri);
12168 free(pgty);
12169 return (-1);
12172 free(pgty);
12174 /* map delete_dependency_pg onto the properties. */
12175 if ((prop = scf_property_create(g_hndl)) == NULL ||
12176 (val = scf_value_create(g_hndl)) == NULL ||
12177 (iter = scf_iter_create(g_hndl)) == NULL)
12178 scfdie();
12180 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
12181 scfdie();
12183 name = safe_malloc(max_scf_name_len + 1);
12184 fmri = safe_malloc(max_scf_fmri_len + 2);
12186 while ((r = scf_iter_next_property(iter, prop)) == 1) {
12187 scf_type_t ty;
12189 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
12190 scfdie();
12192 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
12193 scfdie();
12195 if ((ty != SCF_TYPE_ASTRING &&
12196 prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
12197 prop_get_val(prop, val) != 0)
12198 continue;
12200 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
12201 scfdie();
12203 err = delete_dependency_pg(fmri, name);
12204 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
12205 if (scf_property_to_fmri(prop, fmri,
12206 max_scf_fmri_len + 2) < 0)
12207 scfdie();
12209 warn(gettext("Value of %s is not a valid FMRI.\n"),
12210 fmri);
12211 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
12212 warn(gettext("Property group \"%s\" of entity \"%s\" "
12213 "does not have dependency type.\n"), name, fmri);
12214 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
12215 warn(gettext("Could not delete property group \"%s\" "
12216 "of entity \"%s\" (permission denied).\n"), name,
12217 fmri);
12220 if (r == -1)
12221 scfdie();
12223 scf_value_destroy(val);
12224 scf_property_destroy(prop);
12226 return (0);
12230 * Returns 1 if the instance may be running, and 0 otherwise.
12232 static int
12233 inst_is_running(scf_instance_t *inst)
12235 scf_propertygroup_t *pg;
12236 scf_property_t *prop;
12237 scf_value_t *val;
12238 char buf[MAX_SCF_STATE_STRING_SZ];
12239 int ret = 0;
12240 ssize_t szret;
12242 if ((pg = scf_pg_create(g_hndl)) == NULL ||
12243 (prop = scf_property_create(g_hndl)) == NULL ||
12244 (val = scf_value_create(g_hndl)) == NULL)
12245 scfdie();
12247 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
12248 if (scf_error() != SCF_ERROR_NOT_FOUND)
12249 scfdie();
12250 goto out;
12253 if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
12254 prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
12255 prop_get_val(prop, val) != 0)
12256 goto out;
12258 szret = scf_value_get_astring(val, buf, sizeof (buf));
12259 assert(szret >= 0);
12261 ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
12262 strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
12264 out:
12265 scf_value_destroy(val);
12266 scf_property_destroy(prop);
12267 scf_pg_destroy(pg);
12268 return (ret);
12271 static uint8_t
12272 pg_is_external_dependency(scf_propertygroup_t *pg)
12274 char *type;
12275 scf_value_t *val;
12276 scf_property_t *prop;
12277 uint8_t b = B_FALSE;
12279 type = safe_malloc(max_scf_pg_type_len + 1);
12281 if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
12282 scfdie();
12284 if ((prop = scf_property_create(g_hndl)) == NULL ||
12285 (val = scf_value_create(g_hndl)) == NULL)
12286 scfdie();
12288 if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
12289 if (pg_get_prop(pg, scf_property_external, prop) == 0) {
12290 if (scf_property_get_value(prop, val) != 0)
12291 scfdie();
12292 if (scf_value_get_boolean(val, &b) != 0)
12293 scfdie();
12297 free(type);
12298 (void) scf_value_destroy(val);
12299 (void) scf_property_destroy(prop);
12301 return (b);
12304 #define DELETE_FAILURE -1
12305 #define DELETE_SUCCESS_NOEXTDEPS 0
12306 #define DELETE_SUCCESS_EXTDEPS 1
12309 * lscf_instance_delete() deletes an instance. Before calling
12310 * scf_instance_delete(), though, we make sure the instance isn't
12311 * running and delete dependencies in other entities which the instance
12312 * declared as "dependents". If there are dependencies which were
12313 * created for other entities, then instead of deleting the instance we
12314 * make it "empty" by deleting all other property groups and all
12315 * snapshots.
12317 * lscf_instance_delete() verifies that there is no external dependency pgs
12318 * before suppressing the instance. If there is, then we must not remove them
12319 * now in case the instance is re-created otherwise the dependencies would be
12320 * lost. The external dependency pgs will be removed if the dependencies are
12321 * removed.
12323 * Returns:
12324 * DELETE_FAILURE on failure
12325 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12326 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12328 static int
12329 lscf_instance_delete(scf_instance_t *inst, int force)
12331 scf_propertygroup_t *pg;
12332 scf_snapshot_t *snap;
12333 scf_iter_t *iter;
12334 int err;
12335 int external = 0;
12337 /* If we're not forcing and the instance is running, refuse. */
12338 if (!force && inst_is_running(inst)) {
12339 char *fmri;
12341 fmri = safe_malloc(max_scf_fmri_len + 1);
12343 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
12344 scfdie();
12346 semerr(gettext("Instance %s may be running. "
12347 "Use delete -f if it is not.\n"), fmri);
12349 free(fmri);
12350 return (DELETE_FAILURE);
12353 pg = scf_pg_create(g_hndl);
12354 if (pg == NULL)
12355 scfdie();
12357 if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
12358 (void) delete_dependents(pg);
12359 else if (scf_error() != SCF_ERROR_NOT_FOUND)
12360 scfdie();
12362 scf_pg_destroy(pg);
12365 * If the instance has some external dependencies then we must
12366 * keep them in case the instance is reimported otherwise the
12367 * dependencies would be lost on reimport.
12369 if ((iter = scf_iter_create(g_hndl)) == NULL ||
12370 (pg = scf_pg_create(g_hndl)) == NULL)
12371 scfdie();
12373 if (scf_iter_instance_pgs(iter, inst) < 0)
12374 scfdie();
12376 while ((err = scf_iter_next_pg(iter, pg)) == 1) {
12377 if (pg_is_external_dependency(pg)) {
12378 external = 1;
12379 continue;
12382 if (scf_pg_delete(pg) != 0) {
12383 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12384 scfdie();
12385 else {
12386 semerr(emsg_permission_denied);
12388 (void) scf_iter_destroy(iter);
12389 (void) scf_pg_destroy(pg);
12390 return (DELETE_FAILURE);
12395 if (err == -1)
12396 scfdie();
12398 (void) scf_iter_destroy(iter);
12399 (void) scf_pg_destroy(pg);
12401 if (external) {
12403 * All the pgs have been deleted for the instance except
12404 * the ones holding the external dependencies.
12405 * For the job to be complete, we must also delete the
12406 * snapshots associated with the instance.
12408 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
12409 NULL)
12410 scfdie();
12411 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
12412 scfdie();
12414 if (scf_iter_instance_snapshots(iter, inst) == -1)
12415 scfdie();
12417 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
12418 if (_scf_snapshot_delete(snap) != 0) {
12419 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12420 scfdie();
12422 semerr(emsg_permission_denied);
12424 (void) scf_iter_destroy(iter);
12425 (void) scf_snapshot_destroy(snap);
12426 return (DELETE_FAILURE);
12430 if (err == -1)
12431 scfdie();
12433 (void) scf_iter_destroy(iter);
12434 (void) scf_snapshot_destroy(snap);
12435 return (DELETE_SUCCESS_EXTDEPS);
12438 if (scf_instance_delete(inst) != 0) {
12439 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12440 scfdie();
12442 semerr(emsg_permission_denied);
12444 return (DELETE_FAILURE);
12447 return (DELETE_SUCCESS_NOEXTDEPS);
12451 * lscf_service_delete() deletes a service. Before calling
12452 * scf_service_delete(), though, we call lscf_instance_delete() for
12453 * each of the instances and delete dependencies in other entities
12454 * which were created as "dependents" of this service. If there are
12455 * dependencies which were created for other entities, then we delete
12456 * all other property groups in the service and leave it as "empty".
12458 * lscf_service_delete() verifies that there is no external dependency
12459 * pgs at the instance & service level before suppressing the service.
12460 * If there is, then we must not remove them now in case the service
12461 * is re-imported otherwise the dependencies would be lost. The external
12462 * dependency pgs will be removed if the dependencies are removed.
12464 * Returns:
12465 * DELETE_FAILURE on failure
12466 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12467 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12469 static int
12470 lscf_service_delete(scf_service_t *svc, int force)
12472 int r;
12473 scf_instance_t *inst;
12474 scf_propertygroup_t *pg;
12475 scf_iter_t *iter;
12476 int ret;
12477 int external = 0;
12479 if ((inst = scf_instance_create(g_hndl)) == NULL ||
12480 (pg = scf_pg_create(g_hndl)) == NULL ||
12481 (iter = scf_iter_create(g_hndl)) == NULL)
12482 scfdie();
12484 if (scf_iter_service_instances(iter, svc) != 0)
12485 scfdie();
12487 for (r = scf_iter_next_instance(iter, inst);
12488 r == 1;
12489 r = scf_iter_next_instance(iter, inst)) {
12491 ret = lscf_instance_delete(inst, force);
12492 if (ret == DELETE_FAILURE) {
12493 scf_iter_destroy(iter);
12494 scf_pg_destroy(pg);
12495 scf_instance_destroy(inst);
12496 return (DELETE_FAILURE);
12500 * Record the fact that there is some external dependencies
12501 * at the instance level.
12503 if (ret == DELETE_SUCCESS_EXTDEPS)
12504 external |= 1;
12507 if (r != 0)
12508 scfdie();
12510 /* Delete dependency property groups in dependent services. */
12511 if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12512 (void) delete_dependents(pg);
12513 else if (scf_error() != SCF_ERROR_NOT_FOUND)
12514 scfdie();
12516 scf_iter_destroy(iter);
12517 scf_pg_destroy(pg);
12518 scf_instance_destroy(inst);
12521 * If the service has some external dependencies then we don't
12522 * want to remove them in case the service is re-imported.
12524 if ((pg = scf_pg_create(g_hndl)) == NULL ||
12525 (iter = scf_iter_create(g_hndl)) == NULL)
12526 scfdie();
12528 if (scf_iter_service_pgs(iter, svc) < 0)
12529 scfdie();
12531 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12532 if (pg_is_external_dependency(pg)) {
12533 external |= 2;
12534 continue;
12537 if (scf_pg_delete(pg) != 0) {
12538 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12539 scfdie();
12540 else {
12541 semerr(emsg_permission_denied);
12543 (void) scf_iter_destroy(iter);
12544 (void) scf_pg_destroy(pg);
12545 return (DELETE_FAILURE);
12550 if (r == -1)
12551 scfdie();
12553 (void) scf_iter_destroy(iter);
12554 (void) scf_pg_destroy(pg);
12556 if (external != 0)
12557 return (DELETE_SUCCESS_EXTDEPS);
12559 if (scf_service_delete(svc) == 0)
12560 return (DELETE_SUCCESS_NOEXTDEPS);
12562 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12563 scfdie();
12565 semerr(emsg_permission_denied);
12566 return (DELETE_FAILURE);
12569 static int
12570 delete_callback(void *data, scf_walkinfo_t *wip)
12572 int force = (int)data;
12574 if (wip->inst != NULL)
12575 (void) lscf_instance_delete(wip->inst, force);
12576 else
12577 (void) lscf_service_delete(wip->svc, force);
12579 return (0);
12582 void
12583 lscf_delete(const char *fmri, int force)
12585 scf_service_t *svc;
12586 scf_instance_t *inst;
12587 int ret;
12589 lscf_prep_hndl();
12591 if (cur_snap != NULL) {
12592 if (!snaplevel_is_instance(cur_level)) {
12593 char *buf;
12595 buf = safe_malloc(max_scf_name_len + 1);
12596 if (scf_instance_get_name(cur_inst, buf,
12597 max_scf_name_len + 1) >= 0) {
12598 if (strcmp(buf, fmri) == 0) {
12599 semerr(emsg_cant_modify_snapshots);
12600 free(buf);
12601 return;
12603 } else if (scf_error() != SCF_ERROR_DELETED) {
12604 scfdie();
12606 free(buf);
12608 } else if (cur_inst != NULL) {
12609 /* EMPTY */;
12610 } else if (cur_svc != NULL) {
12611 inst = scf_instance_create(g_hndl);
12612 if (inst == NULL)
12613 scfdie();
12615 if (scf_service_get_instance(cur_svc, fmri, inst) ==
12616 SCF_SUCCESS) {
12617 (void) lscf_instance_delete(inst, force);
12618 scf_instance_destroy(inst);
12619 return;
12622 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12623 scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12624 scfdie();
12626 scf_instance_destroy(inst);
12627 } else {
12628 assert(cur_scope != NULL);
12630 svc = scf_service_create(g_hndl);
12631 if (svc == NULL)
12632 scfdie();
12634 if (scf_scope_get_service(cur_scope, fmri, svc) ==
12635 SCF_SUCCESS) {
12636 (void) lscf_service_delete(svc, force);
12637 scf_service_destroy(svc);
12638 return;
12641 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12642 scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12643 scfdie();
12645 scf_service_destroy(svc);
12649 * Match FMRI to entity.
12651 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12652 delete_callback, (void *)force, NULL, semerr)) != 0) {
12653 semerr(gettext("Failed to walk instances: %s\n"),
12654 scf_strerror(ret));
12661 * :properties commands. These all end with "pg" or "prop" and generally
12662 * operate on the currently selected entity.
12666 * Property listing. List the property groups, properties, their types and
12667 * their values for the currently selected entity.
12669 static void
12670 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12672 char *buf;
12673 uint32_t flags;
12675 buf = safe_malloc(max_scf_pg_type_len + 1);
12677 if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12678 scfdie();
12680 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12681 scfdie();
12683 safe_printf("%-*s %s", namewidth, name, buf);
12685 if (flags & SCF_PG_FLAG_NONPERSISTENT)
12686 safe_printf("\tNONPERSISTENT");
12688 safe_printf("\n");
12690 free(buf);
12693 static boolean_t
12694 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12696 if (scf_property_get_value(prop, val) == 0) {
12697 return (B_FALSE);
12698 } else {
12699 switch (scf_error()) {
12700 case SCF_ERROR_NOT_FOUND:
12701 return (B_FALSE);
12702 case SCF_ERROR_PERMISSION_DENIED:
12703 case SCF_ERROR_CONSTRAINT_VIOLATED:
12704 return (B_TRUE);
12705 default:
12706 scfdie();
12707 /*NOTREACHED*/
12712 static void
12713 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12715 scf_iter_t *iter;
12716 scf_value_t *val;
12717 const char *type;
12718 int multiple_strings = 0;
12719 int ret;
12721 if ((iter = scf_iter_create(g_hndl)) == NULL ||
12722 (val = scf_value_create(g_hndl)) == NULL)
12723 scfdie();
12725 type = prop_to_typestr(prop);
12726 assert(type != NULL);
12728 safe_printf("%-*s %-7s ", len, name, type);
12730 if (prop_has_multiple_values(prop, val) &&
12731 (scf_value_type(val) == SCF_TYPE_ASTRING ||
12732 scf_value_type(val) == SCF_TYPE_USTRING))
12733 multiple_strings = 1;
12735 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12736 scfdie();
12738 while ((ret = scf_iter_next_value(iter, val)) == 1) {
12739 char *buf;
12740 ssize_t vlen, szret;
12742 vlen = scf_value_get_as_string(val, NULL, 0);
12743 if (vlen < 0)
12744 scfdie();
12746 buf = safe_malloc(vlen + 1);
12748 szret = scf_value_get_as_string(val, buf, vlen + 1);
12749 if (szret < 0)
12750 scfdie();
12751 assert(szret <= vlen);
12753 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12754 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12755 safe_printf(" \"");
12756 (void) quote_and_print(buf, stdout, 0);
12757 (void) putchar('"');
12758 if (ferror(stdout)) {
12759 (void) putchar('\n');
12760 uu_die(gettext("Error writing to stdout.\n"));
12762 } else {
12763 safe_printf(" %s", buf);
12766 free(buf);
12768 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12769 scfdie();
12771 if (putchar('\n') != '\n')
12772 uu_die(gettext("Could not output newline"));
12776 * Outputs template property group info for the describe subcommand.
12777 * If 'templates' == 2, verbose output is printed in the format expected
12778 * for describe -v, which includes all templates fields. If pg is
12779 * not NULL, we're describing the template data, not an existing property
12780 * group, and formatting should be appropriate for describe -t.
12782 static void
12783 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12785 char *buf;
12786 uint8_t required;
12787 scf_property_t *stability_prop;
12788 scf_value_t *stability_val;
12790 if (templates == 0)
12791 return;
12793 if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12794 (stability_val = scf_value_create(g_hndl)) == NULL)
12795 scfdie();
12797 if (templates == 2 && pg != NULL) {
12798 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12799 stability_prop) == 0) {
12800 if (prop_check_type(stability_prop,
12801 SCF_TYPE_ASTRING) == 0 &&
12802 prop_get_val(stability_prop, stability_val) == 0) {
12803 char *stability;
12805 stability = safe_malloc(max_scf_value_len + 1);
12807 if (scf_value_get_astring(stability_val,
12808 stability, max_scf_value_len + 1) == -1 &&
12809 scf_error() != SCF_ERROR_NOT_FOUND)
12810 scfdie();
12812 safe_printf("%s%s: %s\n", TMPL_INDENT,
12813 gettext("stability"), stability);
12815 free(stability);
12817 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
12818 scfdie();
12821 scf_property_destroy(stability_prop);
12822 scf_value_destroy(stability_val);
12824 if (pgt == NULL)
12825 return;
12827 if (pg == NULL || templates == 2) {
12828 /* print type info only if scf_tmpl_pg_name succeeds */
12829 if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12830 if (pg != NULL)
12831 safe_printf("%s", TMPL_INDENT);
12832 safe_printf("%s: ", gettext("name"));
12833 safe_printf("%s\n", buf);
12834 free(buf);
12837 /* print type info only if scf_tmpl_pg_type succeeds */
12838 if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12839 if (pg != NULL)
12840 safe_printf("%s", TMPL_INDENT);
12841 safe_printf("%s: ", gettext("type"));
12842 safe_printf("%s\n", buf);
12843 free(buf);
12847 if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12848 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12849 required ? "true" : "false");
12851 if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12852 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12853 buf);
12854 free(buf);
12857 if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12858 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12859 buf);
12860 free(buf);
12863 if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12864 if (templates == 2)
12865 safe_printf("%s%s: %s\n", TMPL_INDENT,
12866 gettext("description"), buf);
12867 else
12868 safe_printf("%s%s\n", TMPL_INDENT, buf);
12869 free(buf);
12875 * With as_value set to true, indent as appropriate for the value level.
12876 * If false, indent to appropriate level for inclusion in constraint
12877 * or choice printout.
12879 static void
12880 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12881 int as_value)
12883 char *buf;
12885 if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12886 if (as_value == 0)
12887 safe_printf("%s", TMPL_CHOICE_INDENT);
12888 else
12889 safe_printf("%s", TMPL_INDENT);
12890 safe_printf("%s: %s\n", gettext("value common name"), buf);
12891 free(buf);
12894 if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12895 if (as_value == 0)
12896 safe_printf("%s", TMPL_CHOICE_INDENT);
12897 else
12898 safe_printf("%s", TMPL_INDENT);
12899 safe_printf("%s: %s\n", gettext("value description"), buf);
12900 free(buf);
12904 static void
12905 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12907 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12908 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12909 safe_printf("%s\n", val_buf);
12911 print_template_value_details(prt, val_buf, 1);
12914 static void
12915 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12917 int i, printed = 0;
12918 scf_values_t values;
12919 scf_count_ranges_t c_ranges;
12920 scf_int_ranges_t i_ranges;
12922 printed = 0;
12923 i = 0;
12924 if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12925 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12926 gettext("value constraints"));
12927 printed++;
12928 for (i = 0; i < values.value_count; ++i) {
12929 safe_printf("%s%s: %s\n", TMPL_INDENT,
12930 gettext("value name"), values.values_as_strings[i]);
12931 if (verbose == 1)
12932 print_template_value_details(prt,
12933 values.values_as_strings[i], 0);
12936 scf_values_destroy(&values);
12939 if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12940 if (printed++ == 0)
12941 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12942 gettext("value constraints"));
12943 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12944 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12945 gettext("range"), c_ranges.scr_min[i],
12946 c_ranges.scr_max[i]);
12948 scf_count_ranges_destroy(&c_ranges);
12949 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12950 scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
12951 if (printed++ == 0)
12952 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12953 gettext("value constraints"));
12954 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12955 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12956 gettext("range"), i_ranges.sir_min[i],
12957 i_ranges.sir_max[i]);
12959 scf_int_ranges_destroy(&i_ranges);
12963 static void
12964 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
12966 int i = 0, printed = 0;
12967 scf_values_t values;
12968 scf_count_ranges_t c_ranges;
12969 scf_int_ranges_t i_ranges;
12971 printed = 0;
12972 if (scf_tmpl_value_name_choices(prt, &values) == 0) {
12973 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12974 gettext("value constraints"));
12975 printed++;
12976 for (i = 0; i < values.value_count; i++) {
12977 safe_printf("%s%s: %s\n", TMPL_INDENT,
12978 gettext("value name"), values.values_as_strings[i]);
12979 if (verbose == 1)
12980 print_template_value_details(prt,
12981 values.values_as_strings[i], 0);
12984 scf_values_destroy(&values);
12987 if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
12988 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12989 if (printed++ == 0)
12990 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12991 gettext("value choices"));
12992 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12993 gettext("range"), c_ranges.scr_min[i],
12994 c_ranges.scr_max[i]);
12996 scf_count_ranges_destroy(&c_ranges);
12997 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12998 scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
12999 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
13000 if (printed++ == 0)
13001 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13002 gettext("value choices"));
13003 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
13004 gettext("range"), i_ranges.sir_min[i],
13005 i_ranges.sir_max[i]);
13007 scf_int_ranges_destroy(&i_ranges);
13011 static void
13012 list_values_by_template(scf_prop_tmpl_t *prt)
13014 print_template_constraints(prt, 1);
13015 print_template_choices(prt, 1);
13018 static void
13019 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
13021 char *val_buf;
13022 scf_iter_t *iter;
13023 scf_value_t *val;
13024 int ret;
13026 if ((iter = scf_iter_create(g_hndl)) == NULL ||
13027 (val = scf_value_create(g_hndl)) == NULL)
13028 scfdie();
13030 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
13031 scfdie();
13033 val_buf = safe_malloc(max_scf_value_len + 1);
13035 while ((ret = scf_iter_next_value(iter, val)) == 1) {
13036 if (scf_value_get_as_string(val, val_buf,
13037 max_scf_value_len + 1) < 0)
13038 scfdie();
13040 print_template_value(prt, val_buf);
13042 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
13043 scfdie();
13044 free(val_buf);
13046 print_template_constraints(prt, 0);
13047 print_template_choices(prt, 0);
13052 * Outputs property info for the describe subcommand
13053 * Verbose output if templates == 2, -v option of svccfg describe
13054 * Displays template data if prop is not NULL, -t option of svccfg describe
13056 static void
13057 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
13059 char *buf;
13060 uint8_t u_buf;
13061 int i;
13062 uint64_t min, max;
13063 scf_values_t values;
13065 if (prt == NULL || templates == 0)
13066 return;
13068 if (prop == NULL) {
13069 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
13070 if (scf_tmpl_prop_name(prt, &buf) > 0) {
13071 safe_printf("%s\n", buf);
13072 free(buf);
13073 } else
13074 safe_printf("(%s)\n", gettext("any"));
13077 if (prop == NULL || templates == 2) {
13078 if (prop != NULL)
13079 safe_printf("%s", TMPL_INDENT);
13080 else
13081 safe_printf("%s", TMPL_VALUE_INDENT);
13082 safe_printf("%s: ", gettext("type"));
13083 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
13084 safe_printf("%s\n", buf);
13085 free(buf);
13086 } else
13087 safe_printf("(%s)\n", gettext("any"));
13090 if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
13091 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
13092 u_buf ? "true" : "false");
13094 if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
13095 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
13096 buf);
13097 free(buf);
13100 if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
13101 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
13102 buf);
13103 free(buf);
13106 if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
13107 safe_printf("%s%s\n", TMPL_INDENT, buf);
13108 free(buf);
13111 if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
13112 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
13113 scf_tmpl_visibility_to_string(u_buf));
13115 if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
13116 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13117 gettext("minimum number of values"), min);
13118 if (max == ULLONG_MAX) {
13119 safe_printf("%s%s: %s\n", TMPL_INDENT,
13120 gettext("maximum number of values"),
13121 gettext("unlimited"));
13122 } else {
13123 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13124 gettext("maximum number of values"), max);
13128 if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
13129 for (i = 0; i < values.value_count; i++) {
13130 if (i == 0) {
13131 safe_printf("%s%s:", TMPL_INDENT,
13132 gettext("internal separators"));
13134 safe_printf(" \"%s\"", values.values_as_strings[i]);
13136 safe_printf("\n");
13139 if (templates != 2)
13140 return;
13142 if (prop != NULL)
13143 list_values_tmpl(prt, prop);
13144 else
13145 list_values_by_template(prt);
13148 static char *
13149 read_astring(scf_propertygroup_t *pg, const char *prop_name)
13151 char *rv;
13153 rv = _scf_read_single_astring_from_pg(pg, prop_name);
13154 if (rv == NULL) {
13155 switch (scf_error()) {
13156 case SCF_ERROR_NOT_FOUND:
13157 break;
13158 default:
13159 scfdie();
13162 return (rv);
13165 static void
13166 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
13168 size_t doc_len;
13169 size_t man_len;
13170 char *pg_name;
13171 char *text = NULL;
13172 int rv;
13174 doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
13175 man_len = strlen(SCF_PG_TM_MAN_PREFIX);
13176 pg_name = safe_malloc(max_scf_name_len + 1);
13177 while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
13178 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
13179 scfdie();
13181 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
13182 /* Display doc_link and and uri */
13183 safe_printf("%s%s:\n", TMPL_INDENT,
13184 gettext("doc_link"));
13185 text = read_astring(pg, SCF_PROPERTY_TM_NAME);
13186 if (text != NULL) {
13187 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13188 TMPL_INDENT, gettext("name"), text);
13189 uu_free(text);
13191 text = read_astring(pg, SCF_PROPERTY_TM_URI);
13192 if (text != NULL) {
13193 safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
13194 gettext("uri"), text);
13195 uu_free(text);
13197 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
13198 man_len) == 0) {
13199 /* Display manpage title, section and path */
13200 safe_printf("%s%s:\n", TMPL_INDENT,
13201 gettext("manpage"));
13202 text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
13203 if (text != NULL) {
13204 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13205 TMPL_INDENT, gettext("title"), text);
13206 uu_free(text);
13208 text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
13209 if (text != NULL) {
13210 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13211 TMPL_INDENT, gettext("section"), text);
13212 uu_free(text);
13214 text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
13215 if (text != NULL) {
13216 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13217 TMPL_INDENT, gettext("manpath"), text);
13218 uu_free(text);
13222 if (rv == -1)
13223 scfdie();
13225 done:
13226 free(pg_name);
13229 static void
13230 list_entity_tmpl(int templates)
13232 char *common_name = NULL;
13233 char *description = NULL;
13234 char *locale = NULL;
13235 scf_iter_t *iter;
13236 scf_propertygroup_t *pg;
13237 scf_property_t *prop;
13238 int r;
13239 scf_value_t *val;
13241 if ((pg = scf_pg_create(g_hndl)) == NULL ||
13242 (prop = scf_property_create(g_hndl)) == NULL ||
13243 (val = scf_value_create(g_hndl)) == NULL ||
13244 (iter = scf_iter_create(g_hndl)) == NULL)
13245 scfdie();
13247 locale = setlocale(LC_MESSAGES, NULL);
13249 if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
13250 common_name = safe_malloc(max_scf_value_len + 1);
13252 /* Try both the current locale and the "C" locale. */
13253 if (scf_pg_get_property(pg, locale, prop) == 0 ||
13254 (scf_error() == SCF_ERROR_NOT_FOUND &&
13255 scf_pg_get_property(pg, "C", prop) == 0)) {
13256 if (prop_get_val(prop, val) == 0 &&
13257 scf_value_get_ustring(val, common_name,
13258 max_scf_value_len + 1) != -1) {
13259 safe_printf("%s%s: %s\n", TMPL_INDENT,
13260 gettext("common name"), common_name);
13266 * Do description, manpages, and doc links if templates == 2.
13268 if (templates == 2) {
13269 /* Get the description. */
13270 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
13271 description = safe_malloc(max_scf_value_len + 1);
13273 /* Try both the current locale and the "C" locale. */
13274 if (scf_pg_get_property(pg, locale, prop) == 0 ||
13275 (scf_error() == SCF_ERROR_NOT_FOUND &&
13276 scf_pg_get_property(pg, "C", prop) == 0)) {
13277 if (prop_get_val(prop, val) == 0 &&
13278 scf_value_get_ustring(val, description,
13279 max_scf_value_len + 1) != -1) {
13280 safe_printf("%s%s: %s\n", TMPL_INDENT,
13281 gettext("description"),
13282 description);
13287 /* Process doc_link & manpage elements. */
13288 if (cur_level != NULL) {
13289 r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
13290 SCF_GROUP_TEMPLATE);
13291 } else if (cur_inst != NULL) {
13292 r = scf_iter_instance_pgs_typed(iter, cur_inst,
13293 SCF_GROUP_TEMPLATE);
13294 } else {
13295 r = scf_iter_service_pgs_typed(iter, cur_svc,
13296 SCF_GROUP_TEMPLATE);
13298 if (r == 0) {
13299 display_documentation(iter, pg);
13303 free(common_name);
13304 free(description);
13305 scf_pg_destroy(pg);
13306 scf_property_destroy(prop);
13307 scf_value_destroy(val);
13308 scf_iter_destroy(iter);
13311 static void
13312 listtmpl(const char *pattern, int templates)
13314 scf_pg_tmpl_t *pgt;
13315 scf_prop_tmpl_t *prt;
13316 char *snapbuf = NULL;
13317 char *fmribuf;
13318 char *pg_name = NULL, *prop_name = NULL;
13319 ssize_t prop_name_size;
13320 char *qual_prop_name;
13321 char *search_name;
13322 int listed = 0;
13324 if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13325 (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
13326 scfdie();
13328 fmribuf = safe_malloc(max_scf_name_len + 1);
13329 qual_prop_name = safe_malloc(max_scf_name_len + 1);
13331 if (cur_snap != NULL) {
13332 snapbuf = safe_malloc(max_scf_name_len + 1);
13333 if (scf_snapshot_get_name(cur_snap, snapbuf,
13334 max_scf_name_len + 1) < 0)
13335 scfdie();
13338 if (cur_inst != NULL) {
13339 if (scf_instance_to_fmri(cur_inst, fmribuf,
13340 max_scf_name_len + 1) < 0)
13341 scfdie();
13342 } else if (cur_svc != NULL) {
13343 if (scf_service_to_fmri(cur_svc, fmribuf,
13344 max_scf_name_len + 1) < 0)
13345 scfdie();
13346 } else
13347 abort();
13349 /* If pattern is specified, we want to list only those items. */
13350 while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) {
13351 listed = 0;
13352 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
13353 fnmatch(pattern, pg_name, 0) == 0)) {
13354 list_pg_tmpl(pgt, NULL, templates);
13355 listed++;
13358 scf_tmpl_prop_reset(prt);
13360 while (scf_tmpl_iter_props(pgt, prt, 0) == 0) {
13361 search_name = NULL;
13362 prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
13363 if ((prop_name_size > 0) && (pg_name != NULL)) {
13364 if (snprintf(qual_prop_name,
13365 max_scf_name_len + 1, "%s/%s",
13366 pg_name, prop_name) >=
13367 max_scf_name_len + 1) {
13368 prop_name_size = -1;
13369 } else {
13370 search_name = qual_prop_name;
13373 if (listed > 0 || pattern == NULL ||
13374 (prop_name_size > 0 &&
13375 fnmatch(pattern, search_name,
13376 FNM_PATHNAME) == 0))
13377 list_prop_tmpl(prt, NULL, templates);
13378 if (prop_name != NULL) {
13379 free(prop_name);
13380 prop_name = NULL;
13383 if (pg_name != NULL) {
13384 free(pg_name);
13385 pg_name = NULL;
13389 scf_tmpl_prop_destroy(prt);
13390 scf_tmpl_pg_destroy(pgt);
13391 free(snapbuf);
13392 free(fmribuf);
13393 free(qual_prop_name);
13396 static void
13397 listprop(const char *pattern, int only_pgs, int templates)
13399 scf_propertygroup_t *pg;
13400 scf_property_t *prop;
13401 scf_iter_t *iter, *piter;
13402 char *pgnbuf, *prnbuf, *ppnbuf;
13403 scf_pg_tmpl_t *pgt, *pgtp;
13404 scf_prop_tmpl_t *prt;
13406 void **objects;
13407 char **names;
13408 void **tmpls;
13409 int allocd, i;
13411 int ret;
13412 ssize_t pgnlen, prnlen, szret;
13413 size_t max_len = 0;
13415 if (cur_svc == NULL && cur_inst == NULL) {
13416 semerr(emsg_entity_not_selected);
13417 return;
13420 if ((pg = scf_pg_create(g_hndl)) == NULL ||
13421 (prop = scf_property_create(g_hndl)) == NULL ||
13422 (iter = scf_iter_create(g_hndl)) == NULL ||
13423 (piter = scf_iter_create(g_hndl)) == NULL ||
13424 (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13425 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
13426 scfdie();
13428 prnbuf = safe_malloc(max_scf_name_len + 1);
13430 if (cur_level != NULL)
13431 ret = scf_iter_snaplevel_pgs(iter, cur_level);
13432 else if (cur_inst != NULL)
13433 ret = scf_iter_instance_pgs(iter, cur_inst);
13434 else
13435 ret = scf_iter_service_pgs(iter, cur_svc);
13436 if (ret != 0) {
13437 return;
13441 * We want to only list items which match pattern, and we want the
13442 * second column to line up, so during the first pass we'll save
13443 * matching items, their names, and their templates in objects,
13444 * names, and tmpls, computing the maximum name length as we go,
13445 * and then we'll print them out.
13447 * Note: We always keep an extra slot available so the array can be
13448 * NULL-terminated.
13450 i = 0;
13451 allocd = 1;
13452 objects = safe_malloc(sizeof (*objects));
13453 names = safe_malloc(sizeof (*names));
13454 tmpls = safe_malloc(sizeof (*tmpls));
13456 while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13457 int new_pg = 0;
13458 int print_props = 0;
13459 pgtp = NULL;
13461 pgnlen = scf_pg_get_name(pg, NULL, 0);
13462 if (pgnlen < 0)
13463 scfdie();
13465 pgnbuf = safe_malloc(pgnlen + 1);
13467 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
13468 if (szret < 0)
13469 scfdie();
13470 assert(szret <= pgnlen);
13472 if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) {
13473 if (scf_error() != SCF_ERROR_NOT_FOUND)
13474 scfdie();
13475 pgtp = NULL;
13476 } else {
13477 pgtp = pgt;
13480 if (pattern == NULL ||
13481 fnmatch(pattern, pgnbuf, 0) == 0) {
13482 if (i+1 >= allocd) {
13483 allocd *= 2;
13484 objects = realloc(objects,
13485 sizeof (*objects) * allocd);
13486 names =
13487 realloc(names, sizeof (*names) * allocd);
13488 tmpls = realloc(tmpls,
13489 sizeof (*tmpls) * allocd);
13490 if (objects == NULL || names == NULL ||
13491 tmpls == NULL)
13492 uu_die(gettext("Out of memory"));
13494 objects[i] = pg;
13495 names[i] = pgnbuf;
13497 if (pgtp == NULL)
13498 tmpls[i] = NULL;
13499 else
13500 tmpls[i] = pgt;
13502 ++i;
13504 if (pgnlen > max_len)
13505 max_len = pgnlen;
13507 new_pg = 1;
13508 print_props = 1;
13511 if (only_pgs) {
13512 if (new_pg) {
13513 pg = scf_pg_create(g_hndl);
13514 if (pg == NULL)
13515 scfdie();
13516 pgt = scf_tmpl_pg_create(g_hndl);
13517 if (pgt == NULL)
13518 scfdie();
13519 } else
13520 free(pgnbuf);
13522 continue;
13525 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13526 scfdie();
13528 while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13529 prnlen = scf_property_get_name(prop, prnbuf,
13530 max_scf_name_len + 1);
13531 if (prnlen < 0)
13532 scfdie();
13534 /* Will prepend the property group name and a slash. */
13535 prnlen += pgnlen + 1;
13537 ppnbuf = safe_malloc(prnlen + 1);
13539 if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13540 prnbuf) < 0)
13541 uu_die("snprintf");
13543 if (pattern == NULL || print_props == 1 ||
13544 fnmatch(pattern, ppnbuf, 0) == 0) {
13545 if (i+1 >= allocd) {
13546 allocd *= 2;
13547 objects = realloc(objects,
13548 sizeof (*objects) * allocd);
13549 names = realloc(names,
13550 sizeof (*names) * allocd);
13551 tmpls = realloc(tmpls,
13552 sizeof (*tmpls) * allocd);
13553 if (objects == NULL || names == NULL ||
13554 tmpls == NULL)
13555 uu_die(gettext(
13556 "Out of memory"));
13559 objects[i] = prop;
13560 names[i] = ppnbuf;
13562 if (pgtp != NULL) {
13563 if (scf_tmpl_get_by_prop(pgt, prnbuf,
13564 prt, 0) < 0) {
13565 if (scf_error() !=
13566 SCF_ERROR_NOT_FOUND)
13567 scfdie();
13568 tmpls[i] = NULL;
13569 } else {
13570 tmpls[i] = prt;
13572 } else {
13573 tmpls[i] = NULL;
13576 ++i;
13578 if (prnlen > max_len)
13579 max_len = prnlen;
13581 prop = scf_property_create(g_hndl);
13582 prt = scf_tmpl_prop_create(g_hndl);
13583 } else {
13584 free(ppnbuf);
13588 if (new_pg) {
13589 pg = scf_pg_create(g_hndl);
13590 if (pg == NULL)
13591 scfdie();
13592 pgt = scf_tmpl_pg_create(g_hndl);
13593 if (pgt == NULL)
13594 scfdie();
13595 } else
13596 free(pgnbuf);
13598 if (ret != 0)
13599 scfdie();
13601 objects[i] = NULL;
13603 scf_pg_destroy(pg);
13604 scf_tmpl_pg_destroy(pgt);
13605 scf_property_destroy(prop);
13606 scf_tmpl_prop_destroy(prt);
13608 for (i = 0; objects[i] != NULL; ++i) {
13609 if (strchr(names[i], '/') == NULL) {
13610 /* property group */
13611 pg = (scf_propertygroup_t *)objects[i];
13612 pgt = (scf_pg_tmpl_t *)tmpls[i];
13613 list_pg_info(pg, names[i], max_len);
13614 list_pg_tmpl(pgt, pg, templates);
13615 free(names[i]);
13616 scf_pg_destroy(pg);
13617 if (pgt != NULL)
13618 scf_tmpl_pg_destroy(pgt);
13619 } else {
13620 /* property */
13621 prop = (scf_property_t *)objects[i];
13622 prt = (scf_prop_tmpl_t *)tmpls[i];
13623 list_prop_info(prop, names[i], max_len);
13624 list_prop_tmpl(prt, prop, templates);
13625 free(names[i]);
13626 scf_property_destroy(prop);
13627 if (prt != NULL)
13628 scf_tmpl_prop_destroy(prt);
13632 free(names);
13633 free(objects);
13634 free(tmpls);
13637 void
13638 lscf_listpg(const char *pattern)
13640 lscf_prep_hndl();
13642 listprop(pattern, 1, 0);
13646 * Property group and property creation, setting, and deletion. setprop (and
13647 * its alias, addprop) can either create a property group of a given type, or
13648 * it can create or set a property to a given type and list of values.
13650 void
13651 lscf_addpg(const char *name, const char *type, const char *flags)
13653 scf_propertygroup_t *pg;
13654 int ret;
13655 uint32_t flgs = 0;
13656 const char *cp;
13659 lscf_prep_hndl();
13661 if (cur_snap != NULL) {
13662 semerr(emsg_cant_modify_snapshots);
13663 return;
13666 if (cur_inst == NULL && cur_svc == NULL) {
13667 semerr(emsg_entity_not_selected);
13668 return;
13671 if (flags != NULL) {
13672 for (cp = flags; *cp != '\0'; ++cp) {
13673 switch (*cp) {
13674 case 'P':
13675 flgs |= SCF_PG_FLAG_NONPERSISTENT;
13676 break;
13678 case 'p':
13679 flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13680 break;
13682 default:
13683 semerr(gettext("Invalid property group flag "
13684 "%c."), *cp);
13685 return;
13690 pg = scf_pg_create(g_hndl);
13691 if (pg == NULL)
13692 scfdie();
13694 if (cur_inst != NULL)
13695 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13696 else
13697 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13699 if (ret != SCF_SUCCESS) {
13700 switch (scf_error()) {
13701 case SCF_ERROR_INVALID_ARGUMENT:
13702 semerr(gettext("Name, type, or flags are invalid.\n"));
13703 break;
13705 case SCF_ERROR_EXISTS:
13706 semerr(gettext("Property group already exists.\n"));
13707 break;
13709 case SCF_ERROR_PERMISSION_DENIED:
13710 semerr(emsg_permission_denied);
13711 break;
13713 case SCF_ERROR_BACKEND_ACCESS:
13714 semerr(gettext("Backend refused access.\n"));
13715 break;
13717 default:
13718 scfdie();
13722 scf_pg_destroy(pg);
13724 private_refresh();
13727 void
13728 lscf_delpg(char *name)
13730 lscf_prep_hndl();
13732 if (cur_snap != NULL) {
13733 semerr(emsg_cant_modify_snapshots);
13734 return;
13737 if (cur_inst == NULL && cur_svc == NULL) {
13738 semerr(emsg_entity_not_selected);
13739 return;
13742 if (strchr(name, '/') != NULL) {
13743 semerr(emsg_invalid_pg_name, name);
13744 return;
13747 lscf_delprop(name);
13751 * scf_delhash() is used to remove the property group related to the
13752 * hash entry for a specific manifest in the repository. pgname will be
13753 * constructed from the location of the manifest file. If deathrow isn't 0,
13754 * manifest file doesn't need to exist (manifest string will be used as
13755 * an absolute path).
13757 void
13758 lscf_delhash(char *manifest, int deathrow)
13760 char *pgname;
13762 if (cur_snap != NULL ||
13763 cur_inst != NULL || cur_svc != NULL) {
13764 warn(gettext("error, an entity is selected\n"));
13765 return;
13768 /* select smf/manifest */
13769 lscf_select(HASH_SVC);
13771 * Translate the manifest file name to property name. In the deathrow
13772 * case, the manifest file does not need to exist.
13774 pgname = mhash_filename_to_propname(manifest,
13775 deathrow ? B_TRUE : B_FALSE);
13776 if (pgname == NULL) {
13777 warn(gettext("cannot resolve pathname for %s\n"), manifest);
13778 return;
13780 /* delete the hash property name */
13781 lscf_delpg(pgname);
13784 void
13785 lscf_listprop(const char *pattern)
13787 lscf_prep_hndl();
13789 listprop(pattern, 0, 0);
13793 lscf_setprop(const char *pgname, const char *type, const char *value,
13794 const uu_list_t *values)
13796 scf_type_t ty, current_ty;
13797 scf_service_t *svc;
13798 scf_propertygroup_t *pg, *parent_pg;
13799 scf_property_t *prop, *parent_prop;
13800 scf_pg_tmpl_t *pgt;
13801 scf_prop_tmpl_t *prt;
13802 int ret, result = 0;
13803 scf_transaction_t *tx;
13804 scf_transaction_entry_t *e;
13805 scf_value_t *v;
13806 uu_list_walk_t *walk;
13807 string_list_t *sp;
13808 char *propname;
13809 int req_quotes = 0;
13811 lscf_prep_hndl();
13813 if ((e = scf_entry_create(g_hndl)) == NULL ||
13814 (svc = scf_service_create(g_hndl)) == NULL ||
13815 (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13816 (pg = scf_pg_create(g_hndl)) == NULL ||
13817 (parent_prop = scf_property_create(g_hndl)) == NULL ||
13818 (prop = scf_property_create(g_hndl)) == NULL ||
13819 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13820 (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13821 (tx = scf_transaction_create(g_hndl)) == NULL)
13822 scfdie();
13824 if (cur_snap != NULL) {
13825 semerr(emsg_cant_modify_snapshots);
13826 goto fail;
13829 if (cur_inst == NULL && cur_svc == NULL) {
13830 semerr(emsg_entity_not_selected);
13831 goto fail;
13834 propname = strchr(pgname, '/');
13835 if (propname == NULL) {
13836 semerr(gettext("Property names must contain a `/'.\n"));
13837 goto fail;
13840 *propname = '\0';
13841 ++propname;
13843 if (type != NULL) {
13844 ty = string_to_type(type);
13845 if (ty == SCF_TYPE_INVALID) {
13846 semerr(gettext("Unknown type \"%s\".\n"), type);
13847 goto fail;
13851 if (cur_inst != NULL)
13852 ret = scf_instance_get_pg(cur_inst, pgname, pg);
13853 else
13854 ret = scf_service_get_pg(cur_svc, pgname, pg);
13855 if (ret != SCF_SUCCESS) {
13856 switch (scf_error()) {
13857 case SCF_ERROR_NOT_FOUND:
13858 semerr(emsg_no_such_pg, pgname);
13859 goto fail;
13861 case SCF_ERROR_INVALID_ARGUMENT:
13862 semerr(emsg_invalid_pg_name, pgname);
13863 goto fail;
13865 default:
13866 scfdie();
13867 break;
13871 do {
13872 if (scf_pg_update(pg) == -1)
13873 scfdie();
13874 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13875 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13876 scfdie();
13878 semerr(emsg_permission_denied);
13879 goto fail;
13882 ret = scf_pg_get_property(pg, propname, prop);
13883 if (ret == SCF_SUCCESS) {
13884 if (scf_property_type(prop, &current_ty) != SCF_SUCCESS)
13885 scfdie();
13887 if (type == NULL)
13888 ty = current_ty;
13889 if (scf_transaction_property_change_type(tx, e,
13890 propname, ty) == -1)
13891 scfdie();
13893 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13894 /* Infer the type, if possible. */
13895 if (type == NULL) {
13897 * First check if we're an instance and the
13898 * property is set on the service.
13900 if (cur_inst != NULL &&
13901 scf_instance_get_parent(cur_inst,
13902 svc) == 0 &&
13903 scf_service_get_pg(cur_svc, pgname,
13904 parent_pg) == 0 &&
13905 scf_pg_get_property(parent_pg, propname,
13906 parent_prop) == 0 &&
13907 scf_property_type(parent_prop,
13908 &current_ty) == 0) {
13909 ty = current_ty;
13911 /* Then check for a type set in a template. */
13912 } else if (scf_tmpl_get_by_pg(pg, pgt,
13913 0) == 0 &&
13914 scf_tmpl_get_by_prop(pgt, propname, prt,
13915 0) == 0 &&
13916 scf_tmpl_prop_type(prt, &current_ty) == 0) {
13917 ty = current_ty;
13919 /* If type can't be inferred, fail. */
13920 } else {
13921 semerr(gettext("Type required for new "
13922 "properties.\n"));
13923 goto fail;
13926 if (scf_transaction_property_new(tx, e, propname,
13927 ty) == -1)
13928 scfdie();
13929 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13930 semerr(emsg_invalid_prop_name, propname);
13931 goto fail;
13932 } else {
13933 scfdie();
13936 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13937 req_quotes = 1;
13939 if (value != NULL) {
13940 v = string_to_value(value, ty, 0);
13942 if (v == NULL)
13943 goto fail;
13945 ret = scf_entry_add_value(e, v);
13946 assert(ret == SCF_SUCCESS);
13947 } else {
13948 assert(values != NULL);
13950 walk = uu_list_walk_start((uu_list_t *)values,
13951 UU_DEFAULT);
13952 if (walk == NULL)
13953 uu_die(gettext("Could not walk list"));
13955 for (sp = uu_list_walk_next(walk); sp != NULL;
13956 sp = uu_list_walk_next(walk)) {
13957 v = string_to_value(sp->str, ty, req_quotes);
13959 if (v == NULL) {
13960 scf_entry_destroy_children(e);
13961 goto fail;
13964 ret = scf_entry_add_value(e, v);
13965 assert(ret == SCF_SUCCESS);
13967 uu_list_walk_end(walk);
13969 result = scf_transaction_commit(tx);
13971 scf_transaction_reset(tx);
13972 scf_entry_destroy_children(e);
13973 } while (result == 0);
13975 if (result < 0) {
13976 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13977 scfdie();
13979 semerr(emsg_permission_denied);
13980 goto fail;
13983 ret = 0;
13985 private_refresh();
13987 goto cleanup;
13989 fail:
13990 ret = -1;
13992 cleanup:
13993 scf_transaction_destroy(tx);
13994 scf_entry_destroy(e);
13995 scf_service_destroy(svc);
13996 scf_pg_destroy(parent_pg);
13997 scf_pg_destroy(pg);
13998 scf_property_destroy(parent_prop);
13999 scf_property_destroy(prop);
14000 scf_tmpl_pg_destroy(pgt);
14001 scf_tmpl_prop_destroy(prt);
14003 return (ret);
14006 void
14007 lscf_delprop(char *pgn)
14009 char *slash, *pn;
14010 scf_propertygroup_t *pg;
14011 scf_transaction_t *tx;
14012 scf_transaction_entry_t *e;
14013 int ret;
14016 lscf_prep_hndl();
14018 if (cur_snap != NULL) {
14019 semerr(emsg_cant_modify_snapshots);
14020 return;
14023 if (cur_inst == NULL && cur_svc == NULL) {
14024 semerr(emsg_entity_not_selected);
14025 return;
14028 pg = scf_pg_create(g_hndl);
14029 if (pg == NULL)
14030 scfdie();
14032 slash = strchr(pgn, '/');
14033 if (slash == NULL) {
14034 pn = NULL;
14035 } else {
14036 *slash = '\0';
14037 pn = slash + 1;
14040 if (cur_inst != NULL)
14041 ret = scf_instance_get_pg(cur_inst, pgn, pg);
14042 else
14043 ret = scf_service_get_pg(cur_svc, pgn, pg);
14044 if (ret != SCF_SUCCESS) {
14045 switch (scf_error()) {
14046 case SCF_ERROR_NOT_FOUND:
14047 semerr(emsg_no_such_pg, pgn);
14048 break;
14050 case SCF_ERROR_INVALID_ARGUMENT:
14051 semerr(emsg_invalid_pg_name, pgn);
14052 break;
14054 default:
14055 scfdie();
14058 scf_pg_destroy(pg);
14060 return;
14063 if (pn == NULL) {
14064 /* Try to delete the property group. */
14065 if (scf_pg_delete(pg) != SCF_SUCCESS) {
14066 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14067 scfdie();
14069 semerr(emsg_permission_denied);
14070 } else {
14071 private_refresh();
14074 scf_pg_destroy(pg);
14075 return;
14078 e = scf_entry_create(g_hndl);
14079 tx = scf_transaction_create(g_hndl);
14081 do {
14082 if (scf_pg_update(pg) == -1)
14083 scfdie();
14084 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
14085 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14086 scfdie();
14088 semerr(emsg_permission_denied);
14089 break;
14092 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
14093 if (scf_error() == SCF_ERROR_NOT_FOUND) {
14094 semerr(gettext("No such property %s/%s.\n"),
14095 pgn, pn);
14096 break;
14097 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14098 semerr(emsg_invalid_prop_name, pn);
14099 break;
14100 } else {
14101 scfdie();
14105 ret = scf_transaction_commit(tx);
14107 if (ret == 0)
14108 scf_transaction_reset(tx);
14109 } while (ret == 0);
14111 if (ret < 0) {
14112 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14113 scfdie();
14115 semerr(emsg_permission_denied);
14116 } else {
14117 private_refresh();
14120 scf_transaction_destroy(tx);
14121 scf_entry_destroy(e);
14122 scf_pg_destroy(pg);
14126 * Property editing.
14129 static int
14130 write_edit_script(FILE *strm)
14132 char *fmribuf;
14133 ssize_t fmrilen;
14135 scf_propertygroup_t *pg;
14136 scf_property_t *prop;
14137 scf_value_t *val;
14138 scf_type_t ty;
14139 int ret, result = 0;
14140 scf_iter_t *iter, *piter, *viter;
14141 char *buf, *tybuf, *pname;
14142 const char *emsg_write_error;
14145 emsg_write_error = gettext("Error writing temoprary file: %s.\n");
14148 /* select fmri */
14149 if (cur_inst != NULL) {
14150 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
14151 if (fmrilen < 0)
14152 scfdie();
14153 fmribuf = safe_malloc(fmrilen + 1);
14154 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
14155 scfdie();
14156 } else {
14157 assert(cur_svc != NULL);
14158 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
14159 if (fmrilen < 0)
14160 scfdie();
14161 fmribuf = safe_malloc(fmrilen + 1);
14162 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
14163 scfdie();
14166 if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
14167 warn(emsg_write_error, strerror(errno));
14168 free(fmribuf);
14169 return (-1);
14172 free(fmribuf);
14175 if ((pg = scf_pg_create(g_hndl)) == NULL ||
14176 (prop = scf_property_create(g_hndl)) == NULL ||
14177 (val = scf_value_create(g_hndl)) == NULL ||
14178 (iter = scf_iter_create(g_hndl)) == NULL ||
14179 (piter = scf_iter_create(g_hndl)) == NULL ||
14180 (viter = scf_iter_create(g_hndl)) == NULL)
14181 scfdie();
14183 buf = safe_malloc(max_scf_name_len + 1);
14184 tybuf = safe_malloc(max_scf_pg_type_len + 1);
14185 pname = safe_malloc(max_scf_name_len + 1);
14187 if (cur_inst != NULL)
14188 ret = scf_iter_instance_pgs(iter, cur_inst);
14189 else
14190 ret = scf_iter_service_pgs(iter, cur_svc);
14191 if (ret != SCF_SUCCESS)
14192 scfdie();
14194 while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
14195 int ret2;
14198 * # delprop pg
14199 * # addpg pg type
14201 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
14202 scfdie();
14204 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
14205 scfdie();
14207 if (fprintf(strm, "# Property group \"%s\"\n"
14208 "# delprop %s\n"
14209 "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
14210 warn(emsg_write_error, strerror(errno));
14211 result = -1;
14212 goto out;
14215 /* # setprop pg/prop = (values) */
14217 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
14218 scfdie();
14220 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
14221 int first = 1;
14222 int ret3;
14223 int multiple;
14224 int is_str;
14225 scf_type_t bty;
14227 if (scf_property_get_name(prop, pname,
14228 max_scf_name_len + 1) < 0)
14229 scfdie();
14231 if (scf_property_type(prop, &ty) != 0)
14232 scfdie();
14234 multiple = prop_has_multiple_values(prop, val);
14236 if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
14237 pname, scf_type_to_string(ty), multiple ? "(" : "")
14238 < 0) {
14239 warn(emsg_write_error, strerror(errno));
14240 result = -1;
14241 goto out;
14244 (void) scf_type_base_type(ty, &bty);
14245 is_str = (bty == SCF_TYPE_ASTRING);
14247 if (scf_iter_property_values(viter, prop) !=
14248 SCF_SUCCESS)
14249 scfdie();
14251 while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
14252 char *buf;
14253 ssize_t buflen;
14255 buflen = scf_value_get_as_string(val, NULL, 0);
14256 if (buflen < 0)
14257 scfdie();
14259 buf = safe_malloc(buflen + 1);
14261 if (scf_value_get_as_string(val, buf,
14262 buflen + 1) < 0)
14263 scfdie();
14265 if (first)
14266 first = 0;
14267 else {
14268 if (putc(' ', strm) != ' ') {
14269 warn(emsg_write_error,
14270 strerror(errno));
14271 result = -1;
14272 goto out;
14276 if ((is_str && multiple) ||
14277 strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
14278 (void) putc('"', strm);
14279 (void) quote_and_print(buf, strm, 1);
14280 (void) putc('"', strm);
14282 if (ferror(strm)) {
14283 warn(emsg_write_error,
14284 strerror(errno));
14285 result = -1;
14286 goto out;
14288 } else {
14289 if (fprintf(strm, "%s", buf) < 0) {
14290 warn(emsg_write_error,
14291 strerror(errno));
14292 result = -1;
14293 goto out;
14297 free(buf);
14299 if (ret3 < 0 &&
14300 scf_error() != SCF_ERROR_PERMISSION_DENIED)
14301 scfdie();
14303 /* Write closing paren if mult-value property */
14304 if ((multiple && putc(')', strm) == EOF) ||
14306 /* Write final newline */
14307 fputc('\n', strm) == EOF) {
14308 warn(emsg_write_error, strerror(errno));
14309 result = -1;
14310 goto out;
14313 if (ret2 < 0)
14314 scfdie();
14316 if (fputc('\n', strm) == EOF) {
14317 warn(emsg_write_error, strerror(errno));
14318 result = -1;
14319 goto out;
14322 if (ret < 0)
14323 scfdie();
14325 out:
14326 free(pname);
14327 free(tybuf);
14328 free(buf);
14329 scf_iter_destroy(viter);
14330 scf_iter_destroy(piter);
14331 scf_iter_destroy(iter);
14332 scf_value_destroy(val);
14333 scf_property_destroy(prop);
14334 scf_pg_destroy(pg);
14336 if (result == 0) {
14337 if (fflush(strm) != 0) {
14338 warn(emsg_write_error, strerror(errno));
14339 return (-1);
14343 return (result);
14347 lscf_editprop()
14349 char *buf, *editor;
14350 size_t bufsz;
14351 int tmpfd;
14352 char tempname[] = TEMP_FILE_PATTERN;
14354 lscf_prep_hndl();
14356 if (cur_snap != NULL) {
14357 semerr(emsg_cant_modify_snapshots);
14358 return (-1);
14361 if (cur_svc == NULL && cur_inst == NULL) {
14362 semerr(emsg_entity_not_selected);
14363 return (-1);
14366 tmpfd = mkstemp(tempname);
14367 if (tmpfd == -1) {
14368 semerr(gettext("Could not create temporary file.\n"));
14369 return (-1);
14372 (void) strcpy(tempfilename, tempname);
14374 tempfile = fdopen(tmpfd, "r+");
14375 if (tempfile == NULL) {
14376 warn(gettext("Could not create temporary file.\n"));
14377 if (close(tmpfd) == -1)
14378 warn(gettext("Could not close temporary file: %s.\n"),
14379 strerror(errno));
14381 remove_tempfile();
14383 return (-1);
14386 if (write_edit_script(tempfile) == -1) {
14387 remove_tempfile();
14388 return (-1);
14391 editor = getenv("EDITOR");
14392 if (editor == NULL)
14393 editor = "vi";
14395 bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
14396 buf = safe_malloc(bufsz);
14398 if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
14399 uu_die(gettext("Error creating editor command"));
14401 if (system(buf) == -1) {
14402 semerr(gettext("Could not launch editor %s: %s\n"), editor,
14403 strerror(errno));
14404 free(buf);
14405 remove_tempfile();
14406 return (-1);
14409 free(buf);
14411 (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
14413 remove_tempfile();
14415 return (0);
14418 static void
14419 add_string(uu_list_t *strlist, const char *str)
14421 string_list_t *elem;
14422 elem = safe_malloc(sizeof (*elem));
14423 uu_list_node_init(elem, &elem->node, string_pool);
14424 elem->str = safe_strdup(str);
14425 if (uu_list_append(strlist, elem) != 0)
14426 uu_die(gettext("libuutil error: %s\n"),
14427 uu_strerror(uu_error()));
14430 static int
14431 remove_string(uu_list_t *strlist, const char *str)
14433 uu_list_walk_t *elems;
14434 string_list_t *sp;
14437 * Find the element that needs to be removed.
14439 elems = uu_list_walk_start(strlist, UU_DEFAULT);
14440 while ((sp = uu_list_walk_next(elems)) != NULL) {
14441 if (strcmp(sp->str, str) == 0)
14442 break;
14444 uu_list_walk_end(elems);
14447 * Returning 1 here as the value was not found, this
14448 * might not be an error. Leave it to the caller to
14449 * decide.
14451 if (sp == NULL) {
14452 return (1);
14455 uu_list_remove(strlist, sp);
14457 free(sp->str);
14458 free(sp);
14460 return (0);
14464 * Get all property values that don't match the given glob pattern,
14465 * if a pattern is specified.
14467 static void
14468 get_prop_values(scf_property_t *prop, uu_list_t *values,
14469 const char *pattern)
14471 scf_iter_t *iter;
14472 scf_value_t *val;
14473 int ret;
14475 if ((iter = scf_iter_create(g_hndl)) == NULL ||
14476 (val = scf_value_create(g_hndl)) == NULL)
14477 scfdie();
14479 if (scf_iter_property_values(iter, prop) != 0)
14480 scfdie();
14482 while ((ret = scf_iter_next_value(iter, val)) == 1) {
14483 char *buf;
14484 ssize_t vlen, szret;
14486 vlen = scf_value_get_as_string(val, NULL, 0);
14487 if (vlen < 0)
14488 scfdie();
14490 buf = safe_malloc(vlen + 1);
14492 szret = scf_value_get_as_string(val, buf, vlen + 1);
14493 if (szret < 0)
14494 scfdie();
14495 assert(szret <= vlen);
14497 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14498 add_string(values, buf);
14500 free(buf);
14503 if (ret == -1)
14504 scfdie();
14506 scf_value_destroy(val);
14507 scf_iter_destroy(iter);
14510 static int
14511 lscf_setpropvalue(const char *pgname, const char *type,
14512 const char *arg, int isadd, int isnotfoundok)
14514 scf_type_t ty;
14515 scf_propertygroup_t *pg;
14516 scf_property_t *prop;
14517 int ret, result = 0;
14518 scf_transaction_t *tx;
14519 scf_transaction_entry_t *e;
14520 scf_value_t *v;
14521 string_list_t *sp;
14522 char *propname;
14523 uu_list_t *values;
14524 uu_list_walk_t *walk;
14525 void *cookie = NULL;
14526 char *pattern = NULL;
14528 lscf_prep_hndl();
14530 if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14531 uu_die(gettext("Could not create property list: %s\n"),
14532 uu_strerror(uu_error()));
14534 if (!isadd)
14535 pattern = safe_strdup(arg);
14537 if ((e = scf_entry_create(g_hndl)) == NULL ||
14538 (pg = scf_pg_create(g_hndl)) == NULL ||
14539 (prop = scf_property_create(g_hndl)) == NULL ||
14540 (tx = scf_transaction_create(g_hndl)) == NULL)
14541 scfdie();
14543 if (cur_snap != NULL) {
14544 semerr(emsg_cant_modify_snapshots);
14545 goto fail;
14548 if (cur_inst == NULL && cur_svc == NULL) {
14549 semerr(emsg_entity_not_selected);
14550 goto fail;
14553 propname = strchr(pgname, '/');
14554 if (propname == NULL) {
14555 semerr(gettext("Property names must contain a `/'.\n"));
14556 goto fail;
14559 *propname = '\0';
14560 ++propname;
14562 if (type != NULL) {
14563 ty = string_to_type(type);
14564 if (ty == SCF_TYPE_INVALID) {
14565 semerr(gettext("Unknown type \"%s\".\n"), type);
14566 goto fail;
14570 if (cur_inst != NULL)
14571 ret = scf_instance_get_pg(cur_inst, pgname, pg);
14572 else
14573 ret = scf_service_get_pg(cur_svc, pgname, pg);
14574 if (ret != 0) {
14575 switch (scf_error()) {
14576 case SCF_ERROR_NOT_FOUND:
14577 if (isnotfoundok) {
14578 result = 0;
14579 } else {
14580 semerr(emsg_no_such_pg, pgname);
14581 result = -1;
14583 goto out;
14585 case SCF_ERROR_INVALID_ARGUMENT:
14586 semerr(emsg_invalid_pg_name, pgname);
14587 goto fail;
14589 default:
14590 scfdie();
14594 do {
14595 if (scf_pg_update(pg) == -1)
14596 scfdie();
14597 if (scf_transaction_start(tx, pg) != 0) {
14598 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14599 scfdie();
14601 semerr(emsg_permission_denied);
14602 goto fail;
14605 ret = scf_pg_get_property(pg, propname, prop);
14606 if (ret == 0) {
14607 scf_type_t ptype;
14608 char *pat = pattern;
14610 if (scf_property_type(prop, &ptype) != 0)
14611 scfdie();
14613 if (isadd) {
14614 if (type != NULL && ptype != ty) {
14615 semerr(gettext("Property \"%s\" is not "
14616 "of type \"%s\".\n"), propname,
14617 type);
14618 goto fail;
14621 pat = NULL;
14622 } else {
14623 size_t len = strlen(pat);
14624 if (len > 0 && pat[len - 1] == '\"')
14625 pat[len - 1] = '\0';
14626 if (len > 0 && pat[0] == '\"')
14627 pat++;
14630 ty = ptype;
14632 get_prop_values(prop, values, pat);
14634 if (isadd)
14635 add_string(values, arg);
14637 if (scf_transaction_property_change(tx, e,
14638 propname, ty) == -1)
14639 scfdie();
14640 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14641 if (isadd) {
14642 if (type == NULL) {
14643 semerr(gettext("Type required "
14644 "for new properties.\n"));
14645 goto fail;
14648 add_string(values, arg);
14650 if (scf_transaction_property_new(tx, e,
14651 propname, ty) == -1)
14652 scfdie();
14653 } else if (isnotfoundok) {
14654 result = 0;
14655 goto out;
14656 } else {
14657 semerr(gettext("No such property %s/%s.\n"),
14658 pgname, propname);
14659 result = -1;
14660 goto out;
14662 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14663 semerr(emsg_invalid_prop_name, propname);
14664 goto fail;
14665 } else {
14666 scfdie();
14669 walk = uu_list_walk_start(values, UU_DEFAULT);
14670 if (walk == NULL)
14671 uu_die(gettext("Could not walk property list.\n"));
14673 for (sp = uu_list_walk_next(walk); sp != NULL;
14674 sp = uu_list_walk_next(walk)) {
14675 v = string_to_value(sp->str, ty, 0);
14677 if (v == NULL) {
14678 scf_entry_destroy_children(e);
14679 goto fail;
14681 ret = scf_entry_add_value(e, v);
14682 assert(ret == 0);
14684 uu_list_walk_end(walk);
14686 result = scf_transaction_commit(tx);
14688 scf_transaction_reset(tx);
14689 scf_entry_destroy_children(e);
14690 } while (result == 0);
14692 if (result < 0) {
14693 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14694 scfdie();
14696 semerr(emsg_permission_denied);
14697 goto fail;
14700 result = 0;
14702 private_refresh();
14704 out:
14705 scf_transaction_destroy(tx);
14706 scf_entry_destroy(e);
14707 scf_pg_destroy(pg);
14708 scf_property_destroy(prop);
14709 free(pattern);
14711 while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14712 free(sp->str);
14713 free(sp);
14716 uu_list_destroy(values);
14718 return (result);
14720 fail:
14721 result = -1;
14722 goto out;
14726 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14728 return (lscf_setpropvalue(pgname, type, value, 1, 0));
14732 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14734 return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14738 * Look for a standard start method, first in the instance (if any),
14739 * then the service.
14741 static const char *
14742 start_method_name(int *in_instance)
14744 scf_propertygroup_t *pg;
14745 char **p;
14746 int ret;
14747 scf_instance_t *inst = cur_inst;
14749 if ((pg = scf_pg_create(g_hndl)) == NULL)
14750 scfdie();
14752 again:
14753 for (p = start_method_names; *p != NULL; p++) {
14754 if (inst != NULL)
14755 ret = scf_instance_get_pg(inst, *p, pg);
14756 else
14757 ret = scf_service_get_pg(cur_svc, *p, pg);
14759 if (ret == 0) {
14760 size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14761 char *buf = safe_malloc(bufsz);
14763 if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14764 free(buf);
14765 continue;
14767 if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14768 free(buf);
14769 continue;
14772 free(buf);
14773 *in_instance = (inst != NULL);
14774 scf_pg_destroy(pg);
14775 return (*p);
14778 if (scf_error() == SCF_ERROR_NOT_FOUND)
14779 continue;
14781 scfdie();
14784 if (inst != NULL) {
14785 inst = NULL;
14786 goto again;
14789 scf_pg_destroy(pg);
14790 return (NULL);
14793 static int
14794 addpg(const char *name, const char *type)
14796 scf_propertygroup_t *pg;
14797 int ret;
14799 pg = scf_pg_create(g_hndl);
14800 if (pg == NULL)
14801 scfdie();
14803 if (cur_inst != NULL)
14804 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14805 else
14806 ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14808 if (ret != 0) {
14809 switch (scf_error()) {
14810 case SCF_ERROR_EXISTS:
14811 ret = 0;
14812 break;
14814 case SCF_ERROR_PERMISSION_DENIED:
14815 semerr(emsg_permission_denied);
14816 break;
14818 default:
14819 scfdie();
14823 scf_pg_destroy(pg);
14824 return (ret);
14828 lscf_setenv(uu_list_t *args, int isunset)
14830 int ret = 0;
14831 size_t i;
14832 int argc;
14833 char **argv = NULL;
14834 string_list_t *slp;
14835 char *pattern;
14836 char *prop;
14837 int do_service = 0;
14838 int do_instance = 0;
14839 const char *method = NULL;
14840 const char *name = NULL;
14841 const char *value = NULL;
14842 scf_instance_t *saved_cur_inst = cur_inst;
14844 lscf_prep_hndl();
14846 argc = uu_list_numnodes(args);
14847 if (argc < 1)
14848 goto usage;
14850 argv = calloc(argc + 1, sizeof (char *));
14851 if (argv == NULL)
14852 uu_die(gettext("Out of memory.\n"));
14854 for (slp = uu_list_first(args), i = 0;
14855 slp != NULL;
14856 slp = uu_list_next(args, slp), ++i)
14857 argv[i] = slp->str;
14859 argv[i] = NULL;
14861 opterr = 0;
14862 optind = 0;
14863 for (;;) {
14864 ret = getopt(argc, argv, "sim:");
14865 if (ret == -1)
14866 break;
14868 switch (ret) {
14869 case 's':
14870 do_service = 1;
14871 cur_inst = NULL;
14872 break;
14874 case 'i':
14875 do_instance = 1;
14876 break;
14878 case 'm':
14879 method = optarg;
14880 break;
14882 case '?':
14883 goto usage;
14885 default:
14886 bad_error("getopt", ret);
14890 argc -= optind;
14891 if ((do_service && do_instance) ||
14892 (isunset && argc != 1) ||
14893 (!isunset && argc != 2))
14894 goto usage;
14896 name = argv[optind];
14897 if (!isunset)
14898 value = argv[optind + 1];
14900 if (cur_snap != NULL) {
14901 semerr(emsg_cant_modify_snapshots);
14902 ret = -1;
14903 goto out;
14906 if (cur_inst == NULL && cur_svc == NULL) {
14907 semerr(emsg_entity_not_selected);
14908 ret = -1;
14909 goto out;
14912 if (do_instance && cur_inst == NULL) {
14913 semerr(gettext("No instance is selected.\n"));
14914 ret = -1;
14915 goto out;
14918 if (do_service && cur_svc == NULL) {
14919 semerr(gettext("No service is selected.\n"));
14920 ret = -1;
14921 goto out;
14924 if (method == NULL) {
14925 if (do_instance || do_service) {
14926 method = "method_context";
14927 if (!isunset) {
14928 ret = addpg("method_context",
14929 SCF_GROUP_FRAMEWORK);
14930 if (ret != 0)
14931 goto out;
14933 } else {
14934 int in_instance;
14935 method = start_method_name(&in_instance);
14936 if (method == NULL) {
14937 semerr(gettext(
14938 "Couldn't find start method; please "
14939 "specify a method with '-m'.\n"));
14940 ret = -1;
14941 goto out;
14943 if (!in_instance)
14944 cur_inst = NULL;
14946 } else {
14947 scf_propertygroup_t *pg;
14948 size_t bufsz;
14949 char *buf;
14950 int ret;
14952 if ((pg = scf_pg_create(g_hndl)) == NULL)
14953 scfdie();
14955 if (cur_inst != NULL)
14956 ret = scf_instance_get_pg(cur_inst, method, pg);
14957 else
14958 ret = scf_service_get_pg(cur_svc, method, pg);
14960 if (ret != 0) {
14961 scf_pg_destroy(pg);
14962 switch (scf_error()) {
14963 case SCF_ERROR_NOT_FOUND:
14964 semerr(gettext("Couldn't find the method "
14965 "\"%s\".\n"), method);
14966 goto out;
14968 case SCF_ERROR_INVALID_ARGUMENT:
14969 semerr(gettext("Invalid method name \"%s\".\n"),
14970 method);
14971 goto out;
14973 default:
14974 scfdie();
14978 bufsz = strlen(SCF_GROUP_METHOD) + 1;
14979 buf = safe_malloc(bufsz);
14981 if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
14982 strcmp(buf, SCF_GROUP_METHOD) != 0) {
14983 semerr(gettext("Property group \"%s\" is not of type "
14984 "\"method\".\n"), method);
14985 ret = -1;
14986 free(buf);
14987 scf_pg_destroy(pg);
14988 goto out;
14991 free(buf);
14992 scf_pg_destroy(pg);
14995 prop = uu_msprintf("%s/environment", method);
14996 pattern = uu_msprintf("%s=*", name);
14998 if (prop == NULL || pattern == NULL)
14999 uu_die(gettext("Out of memory.\n"));
15001 ret = lscf_delpropvalue(prop, pattern, !isunset);
15003 if (ret == 0 && !isunset) {
15004 uu_free(pattern);
15005 uu_free(prop);
15006 prop = uu_msprintf("%s/environment", method);
15007 pattern = uu_msprintf("%s=%s", name, value);
15008 if (prop == NULL || pattern == NULL)
15009 uu_die(gettext("Out of memory.\n"));
15010 ret = lscf_addpropvalue(prop, "astring:", pattern);
15012 uu_free(pattern);
15013 uu_free(prop);
15015 out:
15016 cur_inst = saved_cur_inst;
15018 free(argv);
15019 return (ret);
15020 usage:
15021 ret = -2;
15022 goto out;
15026 * Snapshot commands
15029 void
15030 lscf_listsnap()
15032 scf_snapshot_t *snap;
15033 scf_iter_t *iter;
15034 char *nb;
15035 int r;
15037 lscf_prep_hndl();
15039 if (cur_inst == NULL) {
15040 semerr(gettext("Instance not selected.\n"));
15041 return;
15044 if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15045 (iter = scf_iter_create(g_hndl)) == NULL)
15046 scfdie();
15048 if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
15049 scfdie();
15051 nb = safe_malloc(max_scf_name_len + 1);
15053 while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
15054 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
15055 scfdie();
15057 (void) puts(nb);
15059 if (r < 0)
15060 scfdie();
15062 free(nb);
15063 scf_iter_destroy(iter);
15064 scf_snapshot_destroy(snap);
15067 void
15068 lscf_selectsnap(const char *name)
15070 scf_snapshot_t *snap;
15071 scf_snaplevel_t *level;
15073 lscf_prep_hndl();
15075 if (cur_inst == NULL) {
15076 semerr(gettext("Instance not selected.\n"));
15077 return;
15080 if (cur_snap != NULL) {
15081 if (name != NULL) {
15082 char *cur_snap_name;
15083 boolean_t nochange;
15085 cur_snap_name = safe_malloc(max_scf_name_len + 1);
15087 if (scf_snapshot_get_name(cur_snap, cur_snap_name,
15088 max_scf_name_len + 1) < 0)
15089 scfdie();
15091 nochange = strcmp(name, cur_snap_name) == 0;
15093 free(cur_snap_name);
15095 if (nochange)
15096 return;
15099 unselect_cursnap();
15102 if (name == NULL)
15103 return;
15105 if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15106 (level = scf_snaplevel_create(g_hndl)) == NULL)
15107 scfdie();
15109 if (scf_instance_get_snapshot(cur_inst, name, snap) !=
15110 SCF_SUCCESS) {
15111 switch (scf_error()) {
15112 case SCF_ERROR_INVALID_ARGUMENT:
15113 semerr(gettext("Invalid name \"%s\".\n"), name);
15114 break;
15116 case SCF_ERROR_NOT_FOUND:
15117 semerr(gettext("No such snapshot \"%s\".\n"), name);
15118 break;
15120 default:
15121 scfdie();
15124 scf_snaplevel_destroy(level);
15125 scf_snapshot_destroy(snap);
15126 return;
15129 /* Load the snaplevels into our list. */
15130 cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
15131 if (cur_levels == NULL)
15132 uu_die(gettext("Could not create list: %s\n"),
15133 uu_strerror(uu_error()));
15135 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15136 if (scf_error() != SCF_ERROR_NOT_FOUND)
15137 scfdie();
15139 semerr(gettext("Snapshot has no snaplevels.\n"));
15141 scf_snaplevel_destroy(level);
15142 scf_snapshot_destroy(snap);
15143 return;
15146 cur_snap = snap;
15148 for (;;) {
15149 cur_elt = safe_malloc(sizeof (*cur_elt));
15150 uu_list_node_init(cur_elt, &cur_elt->list_node,
15151 snaplevel_pool);
15152 cur_elt->sl = level;
15153 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
15154 uu_die(gettext("libuutil error: %s\n"),
15155 uu_strerror(uu_error()));
15157 level = scf_snaplevel_create(g_hndl);
15158 if (level == NULL)
15159 scfdie();
15161 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
15162 level) != SCF_SUCCESS) {
15163 if (scf_error() != SCF_ERROR_NOT_FOUND)
15164 scfdie();
15166 scf_snaplevel_destroy(level);
15167 break;
15171 cur_elt = uu_list_last(cur_levels);
15172 cur_level = cur_elt->sl;
15176 * Copies the properties & values in src to dst. Assumes src won't change.
15177 * Returns -1 if permission is denied, -2 if another transaction interrupts,
15178 * and 0 on success.
15180 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
15181 * property, if it is copied and has type boolean. (See comment in
15182 * lscf_revert()).
15184 static int
15185 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
15186 uint8_t enabled)
15188 scf_transaction_t *tx;
15189 scf_iter_t *iter, *viter;
15190 scf_property_t *prop;
15191 scf_value_t *v;
15192 char *nbuf;
15193 int r;
15195 tx = scf_transaction_create(g_hndl);
15196 if (tx == NULL)
15197 scfdie();
15199 if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
15200 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15201 scfdie();
15203 scf_transaction_destroy(tx);
15205 return (-1);
15208 if ((iter = scf_iter_create(g_hndl)) == NULL ||
15209 (prop = scf_property_create(g_hndl)) == NULL ||
15210 (viter = scf_iter_create(g_hndl)) == NULL)
15211 scfdie();
15213 nbuf = safe_malloc(max_scf_name_len + 1);
15215 if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
15216 scfdie();
15218 for (;;) {
15219 scf_transaction_entry_t *e;
15220 scf_type_t ty;
15222 r = scf_iter_next_property(iter, prop);
15223 if (r == -1)
15224 scfdie();
15225 if (r == 0)
15226 break;
15228 e = scf_entry_create(g_hndl);
15229 if (e == NULL)
15230 scfdie();
15232 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
15233 scfdie();
15235 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
15236 scfdie();
15238 if (scf_transaction_property_new(tx, e, nbuf,
15239 ty) != SCF_SUCCESS)
15240 scfdie();
15242 if ((enabled == 0 || enabled == 1) &&
15243 strcmp(nbuf, scf_property_enabled) == 0 &&
15244 ty == SCF_TYPE_BOOLEAN) {
15245 v = scf_value_create(g_hndl);
15246 if (v == NULL)
15247 scfdie();
15249 scf_value_set_boolean(v, enabled);
15251 if (scf_entry_add_value(e, v) != 0)
15252 scfdie();
15253 } else {
15254 if (scf_iter_property_values(viter, prop) != 0)
15255 scfdie();
15257 for (;;) {
15258 v = scf_value_create(g_hndl);
15259 if (v == NULL)
15260 scfdie();
15262 r = scf_iter_next_value(viter, v);
15263 if (r == -1)
15264 scfdie();
15265 if (r == 0) {
15266 scf_value_destroy(v);
15267 break;
15270 if (scf_entry_add_value(e, v) != SCF_SUCCESS)
15271 scfdie();
15276 free(nbuf);
15277 scf_iter_destroy(viter);
15278 scf_property_destroy(prop);
15279 scf_iter_destroy(iter);
15281 r = scf_transaction_commit(tx);
15282 if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
15283 scfdie();
15285 scf_transaction_destroy_children(tx);
15286 scf_transaction_destroy(tx);
15288 switch (r) {
15289 case 1: return (0);
15290 case 0: return (-2);
15291 case -1: return (-1);
15293 default:
15294 abort();
15297 /* NOTREACHED */
15300 void
15301 lscf_revert(const char *snapname)
15303 scf_snapshot_t *snap, *prev;
15304 scf_snaplevel_t *level, *nlevel;
15305 scf_iter_t *iter;
15306 scf_propertygroup_t *pg, *npg;
15307 scf_property_t *prop;
15308 scf_value_t *val;
15309 char *nbuf, *tbuf;
15310 uint8_t enabled;
15312 lscf_prep_hndl();
15314 if (cur_inst == NULL) {
15315 semerr(gettext("Instance not selected.\n"));
15316 return;
15319 if (snapname != NULL) {
15320 snap = scf_snapshot_create(g_hndl);
15321 if (snap == NULL)
15322 scfdie();
15324 if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
15325 SCF_SUCCESS) {
15326 switch (scf_error()) {
15327 case SCF_ERROR_INVALID_ARGUMENT:
15328 semerr(gettext("Invalid snapshot name "
15329 "\"%s\".\n"), snapname);
15330 break;
15332 case SCF_ERROR_NOT_FOUND:
15333 semerr(gettext("No such snapshot.\n"));
15334 break;
15336 default:
15337 scfdie();
15340 scf_snapshot_destroy(snap);
15341 return;
15343 } else {
15344 if (cur_snap != NULL) {
15345 snap = cur_snap;
15346 } else {
15347 semerr(gettext("No snapshot selected.\n"));
15348 return;
15352 if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
15353 (level = scf_snaplevel_create(g_hndl)) == NULL ||
15354 (iter = scf_iter_create(g_hndl)) == NULL ||
15355 (pg = scf_pg_create(g_hndl)) == NULL ||
15356 (npg = scf_pg_create(g_hndl)) == NULL ||
15357 (prop = scf_property_create(g_hndl)) == NULL ||
15358 (val = scf_value_create(g_hndl)) == NULL)
15359 scfdie();
15361 nbuf = safe_malloc(max_scf_name_len + 1);
15362 tbuf = safe_malloc(max_scf_pg_type_len + 1);
15364 /* Take the "previous" snapshot before we blow away the properties. */
15365 if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
15366 if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
15367 scfdie();
15368 } else {
15369 if (scf_error() != SCF_ERROR_NOT_FOUND)
15370 scfdie();
15372 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
15373 scfdie();
15376 /* Save general/enabled, since we're probably going to replace it. */
15377 enabled = 2;
15378 if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
15379 scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
15380 scf_property_get_value(prop, val) == 0)
15381 (void) scf_value_get_boolean(val, &enabled);
15383 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15384 if (scf_error() != SCF_ERROR_NOT_FOUND)
15385 scfdie();
15387 goto out;
15390 for (;;) {
15391 boolean_t isinst;
15392 uint32_t flags;
15393 int r;
15395 /* Clear the properties from the corresponding entity. */
15396 isinst = snaplevel_is_instance(level);
15398 if (!isinst)
15399 r = scf_iter_service_pgs(iter, cur_svc);
15400 else
15401 r = scf_iter_instance_pgs(iter, cur_inst);
15402 if (r != SCF_SUCCESS)
15403 scfdie();
15405 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15406 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15407 scfdie();
15409 /* Skip nonpersistent pgs. */
15410 if (flags & SCF_PG_FLAG_NONPERSISTENT)
15411 continue;
15413 if (scf_pg_delete(pg) != SCF_SUCCESS) {
15414 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15415 scfdie();
15417 semerr(emsg_permission_denied);
15418 goto out;
15421 if (r == -1)
15422 scfdie();
15424 /* Copy the properties to the corresponding entity. */
15425 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
15426 scfdie();
15428 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15429 if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
15430 scfdie();
15432 if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
15434 scfdie();
15436 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15437 scfdie();
15439 if (!isinst)
15440 r = scf_service_add_pg(cur_svc, nbuf, tbuf,
15441 flags, npg);
15442 else
15443 r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
15444 flags, npg);
15445 if (r != SCF_SUCCESS) {
15446 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15447 scfdie();
15449 semerr(emsg_permission_denied);
15450 goto out;
15453 if ((enabled == 0 || enabled == 1) &&
15454 strcmp(nbuf, scf_pg_general) == 0)
15455 r = pg_copy(pg, npg, enabled);
15456 else
15457 r = pg_copy(pg, npg, 2);
15459 switch (r) {
15460 case 0:
15461 break;
15463 case -1:
15464 semerr(emsg_permission_denied);
15465 goto out;
15467 case -2:
15468 semerr(gettext(
15469 "Interrupted by another change.\n"));
15470 goto out;
15472 default:
15473 abort();
15476 if (r == -1)
15477 scfdie();
15479 /* Get next level. */
15480 nlevel = scf_snaplevel_create(g_hndl);
15481 if (nlevel == NULL)
15482 scfdie();
15484 if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
15485 SCF_SUCCESS) {
15486 if (scf_error() != SCF_ERROR_NOT_FOUND)
15487 scfdie();
15489 scf_snaplevel_destroy(nlevel);
15490 break;
15493 scf_snaplevel_destroy(level);
15494 level = nlevel;
15497 if (snapname == NULL) {
15498 lscf_selectsnap(NULL);
15499 snap = NULL; /* cur_snap has been destroyed */
15502 out:
15503 free(tbuf);
15504 free(nbuf);
15505 scf_value_destroy(val);
15506 scf_property_destroy(prop);
15507 scf_pg_destroy(npg);
15508 scf_pg_destroy(pg);
15509 scf_iter_destroy(iter);
15510 scf_snaplevel_destroy(level);
15511 scf_snapshot_destroy(prev);
15512 if (snap != cur_snap)
15513 scf_snapshot_destroy(snap);
15516 void
15517 lscf_refresh(void)
15519 ssize_t fmrilen;
15520 size_t bufsz;
15521 char *fmribuf;
15522 int r;
15524 lscf_prep_hndl();
15526 if (cur_inst == NULL) {
15527 semerr(gettext("Instance not selected.\n"));
15528 return;
15531 bufsz = max_scf_fmri_len + 1;
15532 fmribuf = safe_malloc(bufsz);
15533 fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15534 if (fmrilen < 0) {
15535 free(fmribuf);
15536 if (scf_error() != SCF_ERROR_DELETED)
15537 scfdie();
15538 scf_instance_destroy(cur_inst);
15539 cur_inst = NULL;
15540 warn(emsg_deleted);
15541 return;
15543 assert(fmrilen < bufsz);
15545 r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15546 switch (r) {
15547 case 0:
15548 break;
15550 case ECONNABORTED:
15551 warn(gettext("Could not refresh %s "
15552 "(repository connection broken).\n"), fmribuf);
15553 break;
15555 case ECANCELED:
15556 warn(emsg_deleted);
15557 break;
15559 case EPERM:
15560 warn(gettext("Could not refresh %s "
15561 "(permission denied).\n"), fmribuf);
15562 break;
15564 case ENOSPC:
15565 warn(gettext("Could not refresh %s "
15566 "(repository server out of resources).\n"),
15567 fmribuf);
15568 break;
15570 case EACCES:
15571 default:
15572 bad_error("refresh_entity", scf_error());
15575 free(fmribuf);
15579 * describe [-v] [-t] [pg/prop]
15582 lscf_describe(uu_list_t *args, int hasargs)
15584 int ret = 0;
15585 size_t i;
15586 int argc;
15587 char **argv = NULL;
15588 string_list_t *slp;
15589 int do_verbose = 0;
15590 int do_templates = 0;
15591 char *pattern = NULL;
15593 lscf_prep_hndl();
15595 if (hasargs != 0) {
15596 argc = uu_list_numnodes(args);
15597 if (argc < 1)
15598 goto usage;
15600 argv = calloc(argc + 1, sizeof (char *));
15601 if (argv == NULL)
15602 uu_die(gettext("Out of memory.\n"));
15604 for (slp = uu_list_first(args), i = 0;
15605 slp != NULL;
15606 slp = uu_list_next(args, slp), ++i)
15607 argv[i] = slp->str;
15609 argv[i] = NULL;
15612 * We start optind = 0 because our list of arguments
15613 * starts at argv[0]
15615 optind = 0;
15616 opterr = 0;
15617 for (;;) {
15618 ret = getopt(argc, argv, "vt");
15619 if (ret == -1)
15620 break;
15622 switch (ret) {
15623 case 'v':
15624 do_verbose = 1;
15625 break;
15627 case 't':
15628 do_templates = 1;
15629 break;
15631 case '?':
15632 goto usage;
15634 default:
15635 bad_error("getopt", ret);
15639 pattern = argv[optind];
15642 if (cur_inst == NULL && cur_svc == NULL) {
15643 semerr(emsg_entity_not_selected);
15644 ret = -1;
15645 goto out;
15649 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15650 * output if their last parameter is set to 2. Less information is
15651 * produced if the parameter is set to 1.
15653 if (pattern == NULL) {
15654 if (do_verbose == 1)
15655 list_entity_tmpl(2);
15656 else
15657 list_entity_tmpl(1);
15660 if (do_templates == 0) {
15661 if (do_verbose == 1)
15662 listprop(pattern, 0, 2);
15663 else
15664 listprop(pattern, 0, 1);
15665 } else {
15666 if (do_verbose == 1)
15667 listtmpl(pattern, 2);
15668 else
15669 listtmpl(pattern, 1);
15672 ret = 0;
15673 out:
15674 if (argv != NULL)
15675 free(argv);
15676 return (ret);
15677 usage:
15678 ret = -2;
15679 goto out;
15682 #define PARAM_ACTIVE ((const char *) "active")
15683 #define PARAM_INACTIVE ((const char *) "inactive")
15684 #define PARAM_SMTP_TO ((const char *) "to")
15687 * tokenize()
15688 * Breaks down the string according to the tokens passed.
15689 * Caller is responsible for freeing array of pointers returned.
15690 * Returns NULL on failure
15692 char **
15693 tokenize(char *str, const char *sep)
15695 char *token, *lasts;
15696 char **buf;
15697 int n = 0; /* number of elements */
15698 int size = 8; /* size of the array (initial) */
15700 buf = safe_malloc(size * sizeof (char *));
15702 for (token = strtok_r(str, sep, &lasts); token != NULL;
15703 token = strtok_r(NULL, sep, &lasts), ++n) {
15704 if (n + 1 >= size) {
15705 size *= 2;
15706 if ((buf = realloc(buf, size * sizeof (char *))) ==
15707 NULL) {
15708 uu_die(gettext("Out of memory"));
15711 buf[n] = token;
15713 /* NULL terminate the pointer array */
15714 buf[n] = NULL;
15716 return (buf);
15719 int32_t
15720 check_tokens(char **p)
15722 int32_t smf = 0;
15723 int32_t fma = 0;
15725 while (*p) {
15726 int32_t t = string_to_tset(*p);
15728 if (t == 0) {
15729 if (is_fma_token(*p) == 0)
15730 return (INVALID_TOKENS);
15731 fma = 1; /* this token is an fma event */
15732 } else {
15733 smf |= t;
15736 if (smf != 0 && fma == 1)
15737 return (MIXED_TOKENS);
15738 ++p;
15741 if (smf > 0)
15742 return (smf);
15743 else if (fma == 1)
15744 return (FMA_TOKENS);
15746 return (INVALID_TOKENS);
15749 static int
15750 get_selection_str(char *fmri, size_t sz)
15752 if (g_hndl == NULL) {
15753 semerr(emsg_entity_not_selected);
15754 return (-1);
15755 } else if (cur_level != NULL) {
15756 semerr(emsg_invalid_for_snapshot);
15757 return (-1);
15758 } else {
15759 lscf_get_selection_str(fmri, sz);
15762 return (0);
15765 void
15766 lscf_delnotify(const char *set, int global)
15768 char *str = strdup(set);
15769 char **pgs;
15770 char **p;
15771 int32_t tset;
15772 char *fmri = NULL;
15774 if (str == NULL)
15775 uu_die(gettext("Out of memory.\n"));
15777 pgs = tokenize(str, ",");
15779 if ((tset = check_tokens(pgs)) > 0) {
15780 size_t sz = max_scf_fmri_len + 1;
15782 fmri = safe_malloc(sz);
15783 if (global) {
15784 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15785 } else if (get_selection_str(fmri, sz) != 0) {
15786 goto out;
15789 if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri,
15790 tset) != SCF_SUCCESS) {
15791 uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15792 scf_strerror(scf_error()));
15794 } else if (tset == FMA_TOKENS) {
15795 if (global) {
15796 semerr(gettext("Can't use option '-g' with FMA event "
15797 "definitions\n"));
15798 goto out;
15801 for (p = pgs; *p; ++p) {
15802 if (smf_notify_del_params(de_tag(*p), NULL, 0) !=
15803 SCF_SUCCESS) {
15804 uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
15805 scf_strerror(scf_error()));
15806 goto out;
15809 } else if (tset == MIXED_TOKENS) {
15810 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15811 goto out;
15812 } else {
15813 uu_die(gettext("Invalid input.\n"));
15816 out:
15817 free(fmri);
15818 free(pgs);
15819 free(str);
15822 void
15823 lscf_listnotify(const char *set, int global)
15825 char *str = safe_strdup(set);
15826 char **pgs;
15827 char **p;
15828 int32_t tset;
15829 nvlist_t *nvl;
15830 char *fmri = NULL;
15832 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
15833 uu_die(gettext("Out of memory.\n"));
15835 pgs = tokenize(str, ",");
15837 if ((tset = check_tokens(pgs)) > 0) {
15838 size_t sz = max_scf_fmri_len + 1;
15840 fmri = safe_malloc(sz);
15841 if (global) {
15842 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15843 } else if (get_selection_str(fmri, sz) != 0) {
15844 goto out;
15847 if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
15848 SCF_SUCCESS) {
15849 if (scf_error() != SCF_ERROR_NOT_FOUND &&
15850 scf_error() != SCF_ERROR_DELETED)
15851 uu_warn(gettext(
15852 "Failed listnotify: %s\n"),
15853 scf_strerror(scf_error()));
15854 goto out;
15857 listnotify_print(nvl, NULL);
15858 } else if (tset == FMA_TOKENS) {
15859 if (global) {
15860 semerr(gettext("Can't use option '-g' with FMA event "
15861 "definitions\n"));
15862 goto out;
15865 for (p = pgs; *p; ++p) {
15866 if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
15867 SCF_SUCCESS) {
15869 * if the preferences have just been deleted
15870 * or does not exist, just skip.
15872 if (scf_error() == SCF_ERROR_NOT_FOUND ||
15873 scf_error() == SCF_ERROR_DELETED)
15874 continue;
15875 uu_warn(gettext(
15876 "Failed listnotify: %s\n"),
15877 scf_strerror(scf_error()));
15878 goto out;
15880 listnotify_print(nvl, re_tag(*p));
15882 } else if (tset == MIXED_TOKENS) {
15883 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15884 goto out;
15885 } else {
15886 semerr(gettext("Invalid input.\n"));
15889 out:
15890 nvlist_free(nvl);
15891 free(fmri);
15892 free(pgs);
15893 free(str);
15896 static char *
15897 strip_quotes_and_blanks(char *s)
15899 char *start = s;
15900 char *end = strrchr(s, '\"');
15902 if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
15903 start = s + 1;
15904 while (isblank(*start))
15905 start++;
15906 while (isblank(*(end - 1)) && end > start) {
15907 end--;
15909 *end = '\0';
15912 return (start);
15915 static int
15916 set_active(nvlist_t *mech, const char *hier_part)
15918 boolean_t b;
15920 if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
15921 b = B_TRUE;
15922 } else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
15923 b = B_FALSE;
15924 } else {
15925 return (-1);
15928 if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
15929 uu_die(gettext("Out of memory.\n"));
15931 return (0);
15934 static int
15935 add_snmp_params(nvlist_t *mech, char *hier_part)
15937 return (set_active(mech, hier_part));
15940 static int
15941 add_syslog_params(nvlist_t *mech, char *hier_part)
15943 return (set_active(mech, hier_part));
15947 * add_mailto_paramas()
15948 * parse the hier_part of mailto URI
15949 * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
15950 * or mailto:{[active]|inactive}
15952 static int
15953 add_mailto_params(nvlist_t *mech, char *hier_part)
15955 const char *tok = "?&";
15956 char *p;
15957 char *lasts;
15958 char *param;
15959 char *val;
15962 * If the notification parametes are in the form of
15964 * malito:{[active]|inactive}
15966 * we set the property accordingly and return.
15967 * Otherwise, we make the notification type active and
15968 * process the hier_part.
15970 if (set_active(mech, hier_part) == 0)
15971 return (0);
15972 else if (set_active(mech, PARAM_ACTIVE) != 0)
15973 return (-1);
15975 if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) {
15977 * sanity check: we only get here if hier_part = "", but
15978 * that's handled by set_active
15980 uu_die("strtok_r");
15983 if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0)
15984 uu_die(gettext("Out of memory.\n"));
15986 while ((p = strtok_r(NULL, tok, &lasts)) != NULL)
15987 if ((param = strtok_r(p, "=", &val)) != NULL)
15988 if (nvlist_add_string(mech, param, val) != 0)
15989 uu_die(gettext("Out of memory.\n"));
15991 return (0);
15994 static int
15995 uri_split(char *uri, char **scheme, char **hier_part)
15997 int r = -1;
15999 if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
16000 *hier_part == NULL) {
16001 semerr(gettext("'%s' is not an URI\n"), uri);
16002 return (r);
16005 if ((r = check_uri_scheme(*scheme)) < 0) {
16006 semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
16007 return (r);
16010 return (r);
16013 static int
16014 process_uri(nvlist_t *params, char *uri)
16016 char *scheme;
16017 char *hier_part;
16018 nvlist_t *mech;
16019 int index;
16020 int r;
16022 if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
16023 return (-1);
16025 if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
16026 uu_die(gettext("Out of memory.\n"));
16028 switch (index) {
16029 case 0:
16030 /* error messages displayed by called function */
16031 r = add_mailto_params(mech, hier_part);
16032 break;
16034 case 1:
16035 if ((r = add_snmp_params(mech, hier_part)) != 0)
16036 semerr(gettext("Not valid parameters: '%s'\n"),
16037 hier_part);
16038 break;
16040 case 2:
16041 if ((r = add_syslog_params(mech, hier_part)) != 0)
16042 semerr(gettext("Not valid parameters: '%s'\n"),
16043 hier_part);
16044 break;
16046 default:
16047 r = -1;
16050 if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
16051 mech) != 0)
16052 uu_die(gettext("Out of memory.\n"));
16054 nvlist_free(mech);
16055 return (r);
16058 static int
16059 set_params(nvlist_t *params, char **p)
16061 char *uri;
16063 if (p == NULL)
16064 /* sanity check */
16065 uu_die("set_params");
16067 while (*p) {
16068 uri = strip_quotes_and_blanks(*p);
16069 if (process_uri(params, uri) != 0)
16070 return (-1);
16072 ++p;
16075 return (0);
16078 static int
16079 setnotify(const char *e, char **p, int global)
16081 char *str = safe_strdup(e);
16082 char **events;
16083 int32_t tset;
16084 int r = -1;
16085 nvlist_t *nvl, *params;
16086 char *fmri = NULL;
16088 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
16089 nvlist_alloc(&params, NV_UNIQUE_NAME, 0) != 0 ||
16090 nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
16091 SCF_NOTIFY_PARAMS_VERSION) != 0)
16092 uu_die(gettext("Out of memory.\n"));
16094 events = tokenize(str, ",");
16096 if ((tset = check_tokens(events)) > 0) {
16097 /* SMF state transitions parameters */
16098 size_t sz = max_scf_fmri_len + 1;
16100 fmri = safe_malloc(sz);
16101 if (global) {
16102 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
16103 } else if (get_selection_str(fmri, sz) != 0) {
16104 goto out;
16107 if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 ||
16108 nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0)
16109 uu_die(gettext("Out of memory.\n"));
16111 if ((r = set_params(params, p)) == 0) {
16112 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS,
16113 params) != 0)
16114 uu_die(gettext("Out of memory.\n"));
16116 if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
16117 nvl) != SCF_SUCCESS) {
16118 r = -1;
16119 uu_warn(gettext(
16120 "Failed smf_notify_set_params(3SCF): %s\n"),
16121 scf_strerror(scf_error()));
16124 } else if (tset == FMA_TOKENS) {
16125 /* FMA event parameters */
16126 if (global) {
16127 semerr(gettext("Can't use option '-g' with FMA event "
16128 "definitions\n"));
16129 goto out;
16132 if ((r = set_params(params, p)) != 0)
16133 goto out;
16135 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
16136 uu_die(gettext("Out of memory.\n"));
16138 while (*events) {
16139 if (smf_notify_set_params(de_tag(*events), nvl) !=
16140 SCF_SUCCESS)
16141 uu_warn(gettext(
16142 "Failed smf_notify_set_params(3SCF) for "
16143 "event %s: %s\n"), *events,
16144 scf_strerror(scf_error()));
16145 events++;
16147 } else if (tset == MIXED_TOKENS) {
16148 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
16149 } else {
16150 /* Sanity check */
16151 uu_die(gettext("Invalid input.\n"));
16154 out:
16155 nvlist_free(nvl);
16156 nvlist_free(params);
16157 free(fmri);
16158 free(str);
16160 return (r);
16164 lscf_setnotify(uu_list_t *args)
16166 int argc;
16167 char **argv = NULL;
16168 string_list_t *slp;
16169 int global;
16170 char *events;
16171 char **p;
16172 int i;
16173 int ret;
16175 if ((argc = uu_list_numnodes(args)) < 2)
16176 goto usage;
16178 argv = calloc(argc + 1, sizeof (char *));
16179 if (argv == NULL)
16180 uu_die(gettext("Out of memory.\n"));
16182 for (slp = uu_list_first(args), i = 0;
16183 slp != NULL;
16184 slp = uu_list_next(args, slp), ++i)
16185 argv[i] = slp->str;
16187 argv[i] = NULL;
16189 if (strcmp(argv[0], "-g") == 0) {
16190 global = 1;
16191 events = argv[1];
16192 p = argv + 2;
16193 } else {
16194 global = 0;
16195 events = argv[0];
16196 p = argv + 1;
16199 ret = setnotify(events, p, global);
16201 out:
16202 free(argv);
16203 return (ret);
16205 usage:
16206 ret = -2;
16207 goto out;
16211 * Creates a list of instance name strings associated with a service. If
16212 * wohandcrafted flag is set, get only instances that have a last-import
16213 * snapshot, instances that were imported via svccfg.
16215 static uu_list_t *
16216 create_instance_list(scf_service_t *svc, int wohandcrafted)
16218 scf_snapshot_t *snap = NULL;
16219 scf_instance_t *inst;
16220 scf_iter_t *inst_iter;
16221 uu_list_t *instances;
16222 char *instname;
16223 int r;
16225 inst_iter = scf_iter_create(g_hndl);
16226 inst = scf_instance_create(g_hndl);
16227 if (inst_iter == NULL || inst == NULL) {
16228 uu_warn(gettext("Could not create instance or iterator\n"));
16229 scfdie();
16232 if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
16233 return (instances);
16235 if (scf_iter_service_instances(inst_iter, svc) != 0) {
16236 switch (scf_error()) {
16237 case SCF_ERROR_CONNECTION_BROKEN:
16238 case SCF_ERROR_DELETED:
16239 uu_list_destroy(instances);
16240 instances = NULL;
16241 goto out;
16243 case SCF_ERROR_HANDLE_MISMATCH:
16244 case SCF_ERROR_NOT_BOUND:
16245 case SCF_ERROR_NOT_SET:
16246 default:
16247 bad_error("scf_iter_service_instances", scf_error());
16251 instname = safe_malloc(max_scf_name_len + 1);
16252 while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
16253 if (r == -1) {
16254 (void) uu_warn(gettext("Unable to iterate through "
16255 "instances to create instance list : %s\n"),
16256 scf_strerror(scf_error()));
16258 uu_list_destroy(instances);
16259 instances = NULL;
16260 goto out;
16264 * If the instance does not have a last-import snapshot
16265 * then do not add it to the list as it is a hand-crafted
16266 * instance that should not be managed.
16268 if (wohandcrafted) {
16269 if (snap == NULL &&
16270 (snap = scf_snapshot_create(g_hndl)) == NULL) {
16271 uu_warn(gettext("Unable to create snapshot "
16272 "entity\n"));
16273 scfdie();
16276 if (scf_instance_get_snapshot(inst,
16277 snap_lastimport, snap) != 0) {
16278 switch (scf_error()) {
16279 case SCF_ERROR_NOT_FOUND :
16280 case SCF_ERROR_DELETED:
16281 continue;
16283 case SCF_ERROR_CONNECTION_BROKEN:
16284 uu_list_destroy(instances);
16285 instances = NULL;
16286 goto out;
16288 case SCF_ERROR_HANDLE_MISMATCH:
16289 case SCF_ERROR_NOT_BOUND:
16290 case SCF_ERROR_NOT_SET:
16291 default:
16292 bad_error("scf_iter_service_instances",
16293 scf_error());
16298 if (scf_instance_get_name(inst, instname,
16299 max_scf_name_len + 1) < 0) {
16300 switch (scf_error()) {
16301 case SCF_ERROR_NOT_FOUND :
16302 continue;
16304 case SCF_ERROR_CONNECTION_BROKEN:
16305 case SCF_ERROR_DELETED:
16306 uu_list_destroy(instances);
16307 instances = NULL;
16308 goto out;
16310 case SCF_ERROR_HANDLE_MISMATCH:
16311 case SCF_ERROR_NOT_BOUND:
16312 case SCF_ERROR_NOT_SET:
16313 default:
16314 bad_error("scf_iter_service_instances",
16315 scf_error());
16319 add_string(instances, instname);
16322 out:
16323 if (snap)
16324 scf_snapshot_destroy(snap);
16326 scf_instance_destroy(inst);
16327 scf_iter_destroy(inst_iter);
16328 free(instname);
16329 return (instances);
16333 * disable an instance but wait for the instance to
16334 * move out of the running state.
16336 * Returns 0 : if the instance did not disable
16337 * Returns non-zero : if the instance disabled.
16340 static int
16341 disable_instance(scf_instance_t *instance)
16343 char *fmribuf;
16344 int enabled = 10000;
16346 if (inst_is_running(instance)) {
16347 fmribuf = safe_malloc(max_scf_name_len + 1);
16348 if (scf_instance_to_fmri(instance, fmribuf,
16349 max_scf_name_len + 1) < 0) {
16350 free(fmribuf);
16351 return (0);
16355 * If the instance cannot be disabled then return
16356 * failure to disable and let the caller decide
16357 * if that is of importance.
16359 if (smf_disable_instance(fmribuf, 0) != 0) {
16360 free(fmribuf);
16361 return (0);
16364 while (enabled) {
16365 if (!inst_is_running(instance))
16366 break;
16368 (void) poll(NULL, 0, 5);
16369 enabled = enabled - 5;
16372 free(fmribuf);
16375 return (enabled);
16379 * Function to compare two service_manifest structures.
16381 /* ARGSUSED2 */
16382 static int
16383 service_manifest_compare(const void *left, const void *right, void *unused)
16385 service_manifest_t *l = (service_manifest_t *)left;
16386 service_manifest_t *r = (service_manifest_t *)right;
16387 int rc;
16389 rc = strcmp(l->servicename, r->servicename);
16391 return (rc);
16395 * Look for the provided service in the service to manifest
16396 * tree. If the service exists, and a manifest was provided
16397 * then add the manifest to that service. If the service
16398 * does not exist, then add the service and manifest to the
16399 * list.
16401 * If the manifest is NULL, return the element if found. If
16402 * the service is not found return NULL.
16404 service_manifest_t *
16405 find_add_svc_mfst(const char *svnbuf, const char *mfst)
16407 service_manifest_t elem;
16408 service_manifest_t *fnelem;
16409 uu_avl_index_t marker;
16411 elem.servicename = svnbuf;
16412 fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
16414 if (mfst) {
16415 if (fnelem) {
16416 add_string(fnelem->mfstlist, strdup(mfst));
16417 } else {
16418 fnelem = safe_malloc(sizeof (*fnelem));
16419 fnelem->servicename = safe_strdup(svnbuf);
16420 if ((fnelem->mfstlist =
16421 uu_list_create(string_pool, NULL, 0)) == NULL)
16422 uu_die(gettext("Could not create property "
16423 "list: %s\n"), uu_strerror(uu_error()));
16425 add_string(fnelem->mfstlist, safe_strdup(mfst));
16427 uu_avl_insert(service_manifest_tree, fnelem, marker);
16431 return (fnelem);
16435 * Create the service to manifest avl tree.
16437 * Walk each of the manifests currently installed in the supported
16438 * directories, /lib/svc/manifests and /var/svc/manifests. For
16439 * each of the manifests, inventory the services and add them to
16440 * the tree.
16442 * Code that calls this function should make sure fileystem/minimal is online,
16443 * /var is available, since this function walks the /var/svc/manifest directory.
16445 static void
16446 create_manifest_tree(void)
16448 manifest_info_t **entry;
16449 manifest_info_t **manifests;
16450 uu_list_walk_t *svcs;
16451 bundle_t *b;
16452 entity_t *mfsvc;
16453 char *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
16454 int c, status;
16456 if (service_manifest_pool)
16457 return;
16460 * Create the list pool for the service manifest list
16462 service_manifest_pool = uu_avl_pool_create("service_manifest",
16463 sizeof (service_manifest_t),
16464 offsetof(service_manifest_t, svcmfst_node),
16465 service_manifest_compare, UU_DEFAULT);
16466 if (service_manifest_pool == NULL)
16467 uu_die(gettext("service_manifest pool creation failed: %s\n"),
16468 uu_strerror(uu_error()));
16471 * Create the list
16473 service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
16474 UU_DEFAULT);
16475 if (service_manifest_tree == NULL)
16476 uu_die(gettext("service_manifest tree creation failed: %s\n"),
16477 uu_strerror(uu_error()));
16480 * Walk the manifests adding the service(s) from each manifest.
16482 * If a service already exists add the manifest to the manifest
16483 * list for that service. This covers the case of a service that
16484 * is supported by multiple manifest files.
16486 for (c = 0; dirs[c]; c++) {
16487 status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT);
16488 if (status < 0) {
16489 uu_warn(gettext("file tree walk of %s encountered "
16490 "error %s\n"), dirs[c], strerror(errno));
16492 uu_avl_destroy(service_manifest_tree);
16493 service_manifest_tree = NULL;
16494 return;
16498 * If a manifest that was in the list is not found
16499 * then skip and go to the next manifest file.
16501 if (manifests != NULL) {
16502 for (entry = manifests; *entry != NULL; entry++) {
16503 b = internal_bundle_new();
16504 if (lxml_get_bundle_file(b, (*entry)->mi_path,
16505 SVCCFG_OP_IMPORT) != 0) {
16506 internal_bundle_free(b);
16507 continue;
16510 svcs = uu_list_walk_start(b->sc_bundle_services,
16512 if (svcs == NULL) {
16513 internal_bundle_free(b);
16514 continue;
16517 while ((mfsvc = uu_list_walk_next(svcs)) !=
16518 NULL) {
16519 /* Add manifest to service */
16520 (void) find_add_svc_mfst(mfsvc->sc_name,
16521 (*entry)->mi_path);
16524 uu_list_walk_end(svcs);
16525 internal_bundle_free(b);
16528 free_manifest_array(manifests);
16534 * Check the manifest history file to see
16535 * if the service was ever installed from
16536 * one of the supported directories.
16538 * Return Values :
16539 * -1 - if there's error reading manifest history file
16540 * 1 - if the service is not found
16541 * 0 - if the service is found
16543 static int
16544 check_mfst_history(const char *svcname)
16546 struct stat st;
16547 caddr_t mfsthist_start;
16548 char *svnbuf;
16549 int fd;
16550 int r = 1;
16552 fd = open(MFSTHISTFILE, O_RDONLY);
16553 if (fd == -1) {
16554 uu_warn(gettext("Unable to open the history file\n"));
16555 return (-1);
16558 if (fstat(fd, &st) == -1) {
16559 uu_warn(gettext("Unable to stat the history file\n"));
16560 return (-1);
16563 mfsthist_start = mmap(0, st.st_size, PROT_READ,
16564 MAP_PRIVATE, fd, 0);
16566 (void) close(fd);
16567 if (mfsthist_start == MAP_FAILED ||
16568 *(mfsthist_start + st.st_size) != '\0') {
16569 (void) munmap(mfsthist_start, st.st_size);
16570 return (-1);
16574 * The manifest history file is a space delimited list
16575 * of service and instance to manifest linkage. Adding
16576 * a space to the end of the service name so to get only
16577 * the service that is being searched for.
16579 svnbuf = uu_msprintf("%s ", svcname);
16580 if (svnbuf == NULL)
16581 uu_die(gettext("Out of memory"));
16583 if (strstr(mfsthist_start, svnbuf) != NULL)
16584 r = 0;
16586 (void) munmap(mfsthist_start, st.st_size);
16587 uu_free(svnbuf);
16588 return (r);
16592 * Take down each of the instances in the service
16593 * and remove them, then delete the service.
16595 static void
16596 teardown_service(scf_service_t *svc, const char *svnbuf)
16598 scf_instance_t *instance;
16599 scf_iter_t *iter;
16600 int r;
16602 safe_printf(gettext("Delete service %s as there are no "
16603 "supporting manifests\n"), svnbuf);
16605 instance = scf_instance_create(g_hndl);
16606 iter = scf_iter_create(g_hndl);
16607 if (iter == NULL || instance == NULL) {
16608 uu_warn(gettext("Unable to create supporting entities to "
16609 "teardown the service\n"));
16610 uu_warn(gettext("scf error is : %s\n"),
16611 scf_strerror(scf_error()));
16612 scfdie();
16615 if (scf_iter_service_instances(iter, svc) != 0) {
16616 switch (scf_error()) {
16617 case SCF_ERROR_CONNECTION_BROKEN:
16618 case SCF_ERROR_DELETED:
16619 goto out;
16621 case SCF_ERROR_HANDLE_MISMATCH:
16622 case SCF_ERROR_NOT_BOUND:
16623 case SCF_ERROR_NOT_SET:
16624 default:
16625 bad_error("scf_iter_service_instances",
16626 scf_error());
16630 while ((r = scf_iter_next_instance(iter, instance)) != 0) {
16631 if (r == -1) {
16632 uu_warn(gettext("Error - %s\n"),
16633 scf_strerror(scf_error()));
16634 goto out;
16637 (void) disable_instance(instance);
16641 * Delete the service... forcing the deletion in case
16642 * any of the instances did not disable.
16644 (void) lscf_service_delete(svc, 1);
16645 out:
16646 scf_instance_destroy(instance);
16647 scf_iter_destroy(iter);
16651 * Get the list of instances supported by the manifest
16652 * file.
16654 * Return 0 if there are no instances.
16656 * Return -1 if there are errors attempting to collect instances.
16658 * Return the count of instances found if there are no errors.
16661 static int
16662 check_instance_support(char *mfstfile, const char *svcname,
16663 uu_list_t *instances)
16665 uu_list_walk_t *svcs, *insts;
16666 uu_list_t *ilist;
16667 bundle_t *b;
16668 entity_t *mfsvc, *mfinst;
16669 const char *svcn;
16670 int rminstcnt = 0;
16673 b = internal_bundle_new();
16675 if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
16677 * Unable to process the manifest file for
16678 * instance support, so just return as
16679 * don't want to remove instances that could
16680 * not be accounted for that might exist here.
16682 internal_bundle_free(b);
16683 return (0);
16686 svcs = uu_list_walk_start(b->sc_bundle_services, 0);
16687 if (svcs == NULL) {
16688 internal_bundle_free(b);
16689 return (0);
16692 svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
16693 (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
16695 while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
16696 if (strcmp(mfsvc->sc_name, svcn) == 0)
16697 break;
16699 uu_list_walk_end(svcs);
16701 if (mfsvc == NULL) {
16702 internal_bundle_free(b);
16703 return (-1);
16706 ilist = mfsvc->sc_u.sc_service.sc_service_instances;
16707 if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
16708 internal_bundle_free(b);
16709 return (0);
16712 while ((mfinst = uu_list_walk_next(insts)) != NULL) {
16714 * Remove the instance from the instances list.
16715 * The unaccounted for instances will be removed
16716 * from the service once all manifests are
16717 * processed.
16719 (void) remove_string(instances,
16720 mfinst->sc_name);
16721 rminstcnt++;
16724 uu_list_walk_end(insts);
16725 internal_bundle_free(b);
16727 return (rminstcnt);
16731 * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16732 * 'false' to indicate there's no manifest file(s) found for the service.
16734 static void
16735 svc_add_no_support(scf_service_t *svc)
16737 char *pname;
16739 /* Add no support */
16740 cur_svc = svc;
16741 if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
16742 return;
16744 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
16745 if (pname == NULL)
16746 uu_die(gettext("Out of memory.\n"));
16748 (void) lscf_addpropvalue(pname, "boolean:", "0");
16750 uu_free(pname);
16751 cur_svc = NULL;
16755 * This function handles all upgrade scenarios for a service that doesn't have
16756 * SCF_PG_MANIFESTFILES pg. The function creates and populates
16757 * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16758 * manifest(s) mapping. Manifests under supported directories are inventoried
16759 * and a property is added for each file that delivers configuration to the
16760 * service. A service that has no corresponding manifest files (deleted) are
16761 * removed from repository.
16763 * Unsupported services:
16765 * A service is considered unsupported if there is no corresponding manifest
16766 * in the supported directories for that service and the service isn't in the
16767 * history file list. The history file, MFSTHISTFILE, contains a list of all
16768 * services and instances that were delivered by Solaris before the introduction
16769 * of the SCF_PG_MANIFESTFILES property group. The history file also contains
16770 * the path to the manifest file that defined the service or instance.
16772 * Another type of unsupported services is 'handcrafted' services,
16773 * programmatically created services or services created by dependent entries
16774 * in other manifests. A handcrafted service is identified by its lack of any
16775 * instance containing last-import snapshot which is created during svccfg
16776 * import.
16778 * This function sets a flag for unsupported services by setting services'
16779 * SCF_PG_MANIFESTFILES/support property to false.
16781 static void
16782 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
16784 service_manifest_t *elem;
16785 uu_list_walk_t *mfwalk;
16786 string_list_t *mfile;
16787 uu_list_t *instances;
16788 const char *sname;
16789 char *pname;
16790 int r;
16793 * Since there's no guarantee manifests under /var are available during
16794 * early import, don't perform any upgrade during early import.
16796 if (IGNORE_VAR)
16797 return;
16799 if (service_manifest_tree == NULL) {
16800 create_manifest_tree();
16804 * Find service's supporting manifest(s) after
16805 * stripping off the svc:/ prefix that is part
16806 * of the fmri that is not used in the service
16807 * manifest bundle list.
16809 sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
16810 strlen(SCF_FMRI_SERVICE_PREFIX);
16811 elem = find_add_svc_mfst(sname, NULL);
16812 if (elem == NULL) {
16815 * A handcrafted service, one that has no instance containing
16816 * last-import snapshot, should get unsupported flag.
16818 instances = create_instance_list(svc, 1);
16819 if (instances == NULL) {
16820 uu_warn(gettext("Unable to create instance list %s\n"),
16821 svcname);
16822 return;
16825 if (uu_list_numnodes(instances) == 0) {
16826 svc_add_no_support(svc);
16827 return;
16831 * If the service is in the history file, and its supporting
16832 * manifests are not found, we can safely delete the service
16833 * because its manifests are removed from the system.
16835 * Services not found in the history file are not delivered by
16836 * Solaris and/or delivered outside supported directories, set
16837 * unsupported flag for these services.
16839 r = check_mfst_history(svcname);
16840 if (r == -1)
16841 return;
16843 if (r) {
16844 /* Set unsupported flag for service */
16845 svc_add_no_support(svc);
16846 } else {
16847 /* Delete the service */
16848 teardown_service(svc, svcname);
16851 return;
16855 * Walk through the list of manifests and add them
16856 * to the service.
16858 * Create a manifestfiles pg and add the property.
16860 mfwalk = uu_list_walk_start(elem->mfstlist, 0);
16861 if (mfwalk == NULL)
16862 return;
16864 cur_svc = svc;
16865 r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
16866 if (r != 0) {
16867 cur_svc = NULL;
16868 return;
16871 while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
16872 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16873 mhash_filename_to_propname(mfile->str, 0));
16874 if (pname == NULL)
16875 uu_die(gettext("Out of memory.\n"));
16877 (void) lscf_addpropvalue(pname, "astring:", mfile->str);
16878 uu_free(pname);
16880 uu_list_walk_end(mfwalk);
16882 cur_svc = NULL;
16886 * Take a service and process the manifest file entires to see if
16887 * there is continued support for the service and instances. If
16888 * not cleanup as appropriate.
16890 * If a service does not have a manifest files entry flag it for
16891 * upgrade and return.
16893 * For each manifestfiles property check if the manifest file is
16894 * under the supported /lib/svc/manifest or /var/svc/manifest path
16895 * and if not then return immediately as this service is not supported
16896 * by the cleanup mechanism and should be ignored.
16898 * For each manifest file that is supported, check to see if the
16899 * file exists. If not then remove the manifest file property
16900 * from the service and the smf/manifest hash table. If the manifest
16901 * file exists then verify that it supports the instances that are
16902 * part of the service.
16904 * Once all manifest files have been accounted for remove any instances
16905 * that are no longer supported in the service.
16907 * Return values :
16908 * 0 - Successfully processed the service
16909 * non-zero - failed to process the service
16911 * On most errors, will just return to wait and get the next service,
16912 * unless in case of unable to create the needed structures which is
16913 * most likely a fatal error that is not going to be recoverable.
16916 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
16918 struct mpg_mfile *mpntov;
16919 struct mpg_mfile **mpvarry = NULL;
16920 scf_service_t *svc;
16921 scf_propertygroup_t *mpg;
16922 scf_property_t *mp;
16923 scf_value_t *mv;
16924 scf_iter_t *mi;
16925 scf_instance_t *instance;
16926 uu_list_walk_t *insts;
16927 uu_list_t *instances = NULL;
16928 boolean_t activity = (boolean_t)act;
16929 char *mpnbuf;
16930 char *mpvbuf;
16931 char *pgpropbuf;
16932 int mfstcnt, rminstct, instct, mfstmax;
16933 int index;
16934 int r = 0;
16936 assert(g_hndl != NULL);
16937 assert(wip->svc != NULL);
16938 assert(wip->fmri != NULL);
16940 svc = wip->svc;
16942 mpg = scf_pg_create(g_hndl);
16943 mp = scf_property_create(g_hndl);
16944 mi = scf_iter_create(g_hndl);
16945 mv = scf_value_create(g_hndl);
16946 instance = scf_instance_create(g_hndl);
16948 if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
16949 instance == NULL) {
16950 uu_warn(gettext("Unable to create the supporting entities\n"));
16951 uu_warn(gettext("scf error is : %s\n"),
16952 scf_strerror(scf_error()));
16953 scfdie();
16957 * Get the manifestfiles property group to be parsed for
16958 * files existence.
16960 if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
16961 switch (scf_error()) {
16962 case SCF_ERROR_NOT_FOUND:
16963 upgrade_svc_mfst_connection(svc, wip->fmri);
16964 break;
16965 case SCF_ERROR_DELETED:
16966 case SCF_ERROR_CONNECTION_BROKEN:
16967 goto out;
16969 case SCF_ERROR_HANDLE_MISMATCH:
16970 case SCF_ERROR_NOT_BOUND:
16971 case SCF_ERROR_NOT_SET:
16972 default:
16973 bad_error("scf_iter_pg_properties",
16974 scf_error());
16977 goto out;
16981 * Iterate through each of the manifestfiles properties
16982 * to determine what manifestfiles are available.
16984 * If a manifest file is supported then increment the
16985 * count and therefore the service is safe.
16987 if (scf_iter_pg_properties(mi, mpg) != 0) {
16988 switch (scf_error()) {
16989 case SCF_ERROR_DELETED:
16990 case SCF_ERROR_CONNECTION_BROKEN:
16991 goto out;
16993 case SCF_ERROR_HANDLE_MISMATCH:
16994 case SCF_ERROR_NOT_BOUND:
16995 case SCF_ERROR_NOT_SET:
16996 default:
16997 bad_error("scf_iter_pg_properties",
16998 scf_error());
17002 mfstcnt = 0;
17003 mfstmax = MFSTFILE_MAX;
17004 mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
17005 while ((r = scf_iter_next_property(mi, mp)) != 0) {
17006 if (r == -1)
17007 bad_error(gettext("Unable to iterate through "
17008 "manifestfiles properties : %s"),
17009 scf_error());
17011 mpntov = safe_malloc(sizeof (struct mpg_mfile));
17012 mpnbuf = safe_malloc(max_scf_name_len + 1);
17013 mpvbuf = safe_malloc(max_scf_value_len + 1);
17014 mpntov->mpg = mpnbuf;
17015 mpntov->mfile = mpvbuf;
17016 mpntov->access = 1;
17017 if (scf_property_get_name(mp, mpnbuf,
17018 max_scf_name_len + 1) < 0) {
17019 uu_warn(gettext("Unable to get manifest file "
17020 "property : %s\n"),
17021 scf_strerror(scf_error()));
17023 switch (scf_error()) {
17024 case SCF_ERROR_DELETED:
17025 case SCF_ERROR_CONNECTION_BROKEN:
17026 r = scferror2errno(scf_error());
17027 goto out_free;
17029 case SCF_ERROR_HANDLE_MISMATCH:
17030 case SCF_ERROR_NOT_BOUND:
17031 case SCF_ERROR_NOT_SET:
17032 default:
17033 bad_error("scf_iter_pg_properties",
17034 scf_error());
17039 * The support property is a boolean value that indicates
17040 * if the service is supported for manifest file deletion.
17041 * Currently at this time there is no code that sets this
17042 * value to true. So while we could just let this be caught
17043 * by the support check below, in the future this by be set
17044 * to true and require processing. So for that, go ahead
17045 * and check here, and just return if false. Otherwise,
17046 * fall through expecting that other support checks will
17047 * handle the entries.
17049 if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
17050 uint8_t support;
17052 if (scf_property_get_value(mp, mv) != 0 ||
17053 scf_value_get_boolean(mv, &support) != 0) {
17054 uu_warn(gettext("Unable to get the manifest "
17055 "support value: %s\n"),
17056 scf_strerror(scf_error()));
17058 switch (scf_error()) {
17059 case SCF_ERROR_DELETED:
17060 case SCF_ERROR_CONNECTION_BROKEN:
17061 r = scferror2errno(scf_error());
17062 goto out_free;
17064 case SCF_ERROR_HANDLE_MISMATCH:
17065 case SCF_ERROR_NOT_BOUND:
17066 case SCF_ERROR_NOT_SET:
17067 default:
17068 bad_error("scf_iter_pg_properties",
17069 scf_error());
17073 if (support == B_FALSE)
17074 goto out_free;
17078 * Anything with a manifest outside of the supported
17079 * directories, immediately bail out because that makes
17080 * this service non-supported. We don't even want
17081 * to do instance processing in this case because the
17082 * instances could be part of the non-supported manifest.
17084 if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
17086 * Manifest is not in /lib/svc, so we need to
17087 * consider the /var/svc case.
17089 if (strncmp(mpnbuf, VARSVC_PR,
17090 strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
17092 * Either the manifest is not in /var/svc or
17093 * /var is not yet mounted. We ignore the
17094 * manifest either because it is not in a
17095 * standard location or because we cannot
17096 * currently access the manifest.
17098 goto out_free;
17103 * Get the value to of the manifest file for this entry
17104 * for access verification and instance support
17105 * verification if it still exists.
17107 * During Early Manifest Import if the manifest is in
17108 * /var/svc then it may not yet be available for checking
17109 * so we must determine if /var/svc is available. If not
17110 * then defer until Late Manifest Import to cleanup.
17112 if (scf_property_get_value(mp, mv) != 0) {
17113 uu_warn(gettext("Unable to get the manifest file "
17114 "value: %s\n"),
17115 scf_strerror(scf_error()));
17117 switch (scf_error()) {
17118 case SCF_ERROR_DELETED:
17119 case SCF_ERROR_CONNECTION_BROKEN:
17120 r = scferror2errno(scf_error());
17121 goto out_free;
17123 case SCF_ERROR_HANDLE_MISMATCH:
17124 case SCF_ERROR_NOT_BOUND:
17125 case SCF_ERROR_NOT_SET:
17126 default:
17127 bad_error("scf_property_get_value",
17128 scf_error());
17132 if (scf_value_get_astring(mv, mpvbuf,
17133 max_scf_value_len + 1) < 0) {
17134 uu_warn(gettext("Unable to get the manifest "
17135 "file : %s\n"),
17136 scf_strerror(scf_error()));
17138 switch (scf_error()) {
17139 case SCF_ERROR_DELETED:
17140 case SCF_ERROR_CONNECTION_BROKEN:
17141 r = scferror2errno(scf_error());
17142 goto out_free;
17144 case SCF_ERROR_HANDLE_MISMATCH:
17145 case SCF_ERROR_NOT_BOUND:
17146 case SCF_ERROR_NOT_SET:
17147 default:
17148 bad_error("scf_value_get_astring",
17149 scf_error());
17153 mpvarry[mfstcnt] = mpntov;
17154 mfstcnt++;
17157 * Check for the need to reallocate array
17159 if (mfstcnt >= (mfstmax - 1)) {
17160 struct mpg_mfile **newmpvarry;
17162 mfstmax = mfstmax * 2;
17163 newmpvarry = realloc(mpvarry,
17164 sizeof (struct mpg_mfile *) * mfstmax);
17166 if (newmpvarry == NULL)
17167 goto out_free;
17169 mpvarry = newmpvarry;
17172 mpvarry[mfstcnt] = NULL;
17175 for (index = 0; mpvarry[index]; index++) {
17176 mpntov = mpvarry[index];
17179 * Check to see if the manifestfile is accessable, if so hand
17180 * this service and manifestfile off to be processed for
17181 * instance support.
17183 mpnbuf = mpntov->mpg;
17184 mpvbuf = mpntov->mfile;
17185 if (access(mpvbuf, F_OK) != 0) {
17186 mpntov->access = 0;
17187 activity++;
17188 mfstcnt--;
17189 /* Remove the entry from the service */
17190 cur_svc = svc;
17191 pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
17192 mpnbuf);
17193 if (pgpropbuf == NULL)
17194 uu_die(gettext("Out of memory.\n"));
17196 lscf_delprop(pgpropbuf);
17197 cur_svc = NULL;
17199 uu_free(pgpropbuf);
17204 * If mfstcnt is 0, none of the manifests that supported the service
17205 * existed so remove the service.
17207 if (mfstcnt == 0) {
17208 teardown_service(svc, wip->fmri);
17210 goto out_free;
17213 if (activity) {
17214 int nosvcsupport = 0;
17217 * If the list of service instances is NULL then
17218 * create the list.
17220 instances = create_instance_list(svc, 1);
17221 if (instances == NULL) {
17222 uu_warn(gettext("Unable to create instance list %s\n"),
17223 wip->fmri);
17224 goto out_free;
17227 rminstct = uu_list_numnodes(instances);
17228 instct = rminstct;
17230 for (index = 0; mpvarry[index]; index++) {
17231 mpntov = mpvarry[index];
17232 if (mpntov->access == 0)
17233 continue;
17235 mpnbuf = mpntov->mpg;
17236 mpvbuf = mpntov->mfile;
17237 r = check_instance_support(mpvbuf, wip->fmri,
17238 instances);
17239 if (r == -1) {
17240 nosvcsupport++;
17241 } else {
17242 rminstct -= r;
17246 if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
17247 teardown_service(svc, wip->fmri);
17249 goto out_free;
17254 * If there are instances left on the instance list, then
17255 * we must remove them.
17257 if (instances != NULL && uu_list_numnodes(instances)) {
17258 string_list_t *sp;
17260 insts = uu_list_walk_start(instances, 0);
17261 while ((sp = uu_list_walk_next(insts)) != NULL) {
17263 * Remove the instance from the instances list.
17265 safe_printf(gettext("Delete instance %s from "
17266 "service %s\n"), sp->str, wip->fmri);
17267 if (scf_service_get_instance(svc, sp->str,
17268 instance) != SCF_SUCCESS) {
17269 (void) uu_warn("scf_error - %s\n",
17270 scf_strerror(scf_error()));
17272 continue;
17275 (void) disable_instance(instance);
17277 (void) lscf_instance_delete(instance, 1);
17279 scf_instance_destroy(instance);
17280 uu_list_walk_end(insts);
17283 out_free:
17284 if (mpvarry) {
17285 struct mpg_mfile *fmpntov;
17287 for (index = 0; mpvarry[index]; index++) {
17288 fmpntov = mpvarry[index];
17289 if (fmpntov->mpg == mpnbuf)
17290 mpnbuf = NULL;
17291 free(fmpntov->mpg);
17293 if (fmpntov->mfile == mpvbuf)
17294 mpvbuf = NULL;
17295 free(fmpntov->mfile);
17297 if (fmpntov == mpntov)
17298 mpntov = NULL;
17299 free(fmpntov);
17301 if (mpnbuf)
17302 free(mpnbuf);
17303 if (mpvbuf)
17304 free(mpvbuf);
17305 if (mpntov)
17306 free(mpntov);
17308 free(mpvarry);
17310 out:
17311 scf_pg_destroy(mpg);
17312 scf_property_destroy(mp);
17313 scf_iter_destroy(mi);
17314 scf_value_destroy(mv);
17316 return (0);
17320 * Take the service and search for the manifestfiles property
17321 * in each of the property groups. If the manifest file
17322 * associated with the property does not exist then remove
17323 * the property group.
17326 lscf_hash_cleanup()
17328 scf_service_t *svc;
17329 scf_scope_t *scope;
17330 scf_propertygroup_t *pg;
17331 scf_property_t *prop;
17332 scf_value_t *val;
17333 scf_iter_t *iter;
17334 char *pgname = NULL;
17335 char *mfile = NULL;
17336 int r;
17338 svc = scf_service_create(g_hndl);
17339 scope = scf_scope_create(g_hndl);
17340 pg = scf_pg_create(g_hndl);
17341 prop = scf_property_create(g_hndl);
17342 val = scf_value_create(g_hndl);
17343 iter = scf_iter_create(g_hndl);
17344 if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
17345 svc == NULL || scope == NULL) {
17346 uu_warn(gettext("Unable to create a property group, or "
17347 "property\n"));
17348 uu_warn("%s\n", pg == NULL ? "pg is NULL" :
17349 "pg is not NULL");
17350 uu_warn("%s\n", prop == NULL ? "prop is NULL" :
17351 "prop is not NULL");
17352 uu_warn("%s\n", val == NULL ? "val is NULL" :
17353 "val is not NULL");
17354 uu_warn("%s\n", iter == NULL ? "iter is NULL" :
17355 "iter is not NULL");
17356 uu_warn("%s\n", svc == NULL ? "svc is NULL" :
17357 "svc is not NULL");
17358 uu_warn("%s\n", scope == NULL ? "scope is NULL" :
17359 "scope is not NULL");
17360 uu_warn(gettext("scf error is : %s\n"),
17361 scf_strerror(scf_error()));
17362 scfdie();
17365 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
17366 switch (scf_error()) {
17367 case SCF_ERROR_CONNECTION_BROKEN:
17368 case SCF_ERROR_NOT_FOUND:
17369 goto out;
17371 case SCF_ERROR_HANDLE_MISMATCH:
17372 case SCF_ERROR_NOT_BOUND:
17373 case SCF_ERROR_INVALID_ARGUMENT:
17374 default:
17375 bad_error("scf_handle_get_scope", scf_error());
17379 if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
17380 uu_warn(gettext("Unable to process the hash service, %s\n"),
17381 HASH_SVC);
17382 goto out;
17385 pgname = safe_malloc(max_scf_name_len + 1);
17386 mfile = safe_malloc(max_scf_value_len + 1);
17388 if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
17389 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17390 scf_strerror(scf_error()));
17391 goto out;
17394 while ((r = scf_iter_next_pg(iter, pg)) != 0) {
17395 if (r == -1)
17396 goto out;
17398 if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
17399 switch (scf_error()) {
17400 case SCF_ERROR_DELETED:
17401 return (ENODEV);
17403 case SCF_ERROR_CONNECTION_BROKEN:
17404 return (ECONNABORTED);
17406 case SCF_ERROR_NOT_SET:
17407 case SCF_ERROR_NOT_BOUND:
17408 default:
17409 bad_error("scf_pg_get_name", scf_error());
17412 if (IGNORE_VAR) {
17413 if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
17414 continue;
17418 * If unable to get the property continue as this is an
17419 * entry that has no location to check against.
17421 if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
17422 continue;
17425 if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
17426 uu_warn(gettext("Unable to get value from %s\n"),
17427 pgname);
17429 switch (scf_error()) {
17430 case SCF_ERROR_DELETED:
17431 case SCF_ERROR_CONSTRAINT_VIOLATED:
17432 case SCF_ERROR_NOT_FOUND:
17433 case SCF_ERROR_NOT_SET:
17434 continue;
17436 case SCF_ERROR_CONNECTION_BROKEN:
17437 r = scferror2errno(scf_error());
17438 goto out;
17440 case SCF_ERROR_HANDLE_MISMATCH:
17441 case SCF_ERROR_NOT_BOUND:
17442 default:
17443 bad_error("scf_property_get_value",
17444 scf_error());
17448 if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
17449 == -1) {
17450 uu_warn(gettext("Unable to get astring from %s : %s\n"),
17451 pgname, scf_strerror(scf_error()));
17453 switch (scf_error()) {
17454 case SCF_ERROR_NOT_SET:
17455 case SCF_ERROR_TYPE_MISMATCH:
17456 continue;
17458 default:
17459 bad_error("scf_value_get_astring", scf_error());
17463 if (access(mfile, F_OK) == 0)
17464 continue;
17466 (void) scf_pg_delete(pg);
17469 out:
17470 scf_scope_destroy(scope);
17471 scf_service_destroy(svc);
17472 scf_pg_destroy(pg);
17473 scf_property_destroy(prop);
17474 scf_value_destroy(val);
17475 scf_iter_destroy(iter);
17476 free(pgname);
17477 free(mfile);
17479 return (0);
17482 #ifndef NATIVE_BUILD
17483 /* ARGSUSED */
17484 CPL_MATCH_FN(complete_select)
17486 const char *arg0, *arg1, *arg1end;
17487 int word_start, err = 0, r;
17488 size_t len;
17489 char *buf;
17491 lscf_prep_hndl();
17493 arg0 = line + strspn(line, " \t");
17494 assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
17496 arg1 = arg0 + sizeof ("select") - 1;
17497 arg1 += strspn(arg1, " \t");
17498 word_start = arg1 - line;
17500 arg1end = arg1 + strcspn(arg1, " \t");
17501 if (arg1end < line + word_end)
17502 return (0);
17504 len = line + word_end - arg1;
17506 buf = safe_malloc(max_scf_name_len + 1);
17508 if (cur_snap != NULL) {
17509 return (0);
17510 } else if (cur_inst != NULL) {
17511 return (0);
17512 } else if (cur_svc != NULL) {
17513 scf_instance_t *inst;
17514 scf_iter_t *iter;
17516 if ((inst = scf_instance_create(g_hndl)) == NULL ||
17517 (iter = scf_iter_create(g_hndl)) == NULL)
17518 scfdie();
17520 if (scf_iter_service_instances(iter, cur_svc) != 0)
17521 scfdie();
17523 for (;;) {
17524 r = scf_iter_next_instance(iter, inst);
17525 if (r == 0)
17526 break;
17527 if (r != 1)
17528 scfdie();
17530 if (scf_instance_get_name(inst, buf,
17531 max_scf_name_len + 1) < 0)
17532 scfdie();
17534 if (strncmp(buf, arg1, len) == 0) {
17535 err = cpl_add_completion(cpl, line, word_start,
17536 word_end, buf + len, "", " ");
17537 if (err != 0)
17538 break;
17542 scf_iter_destroy(iter);
17543 scf_instance_destroy(inst);
17545 return (err);
17546 } else {
17547 scf_service_t *svc;
17548 scf_iter_t *iter;
17550 assert(cur_scope != NULL);
17552 if ((svc = scf_service_create(g_hndl)) == NULL ||
17553 (iter = scf_iter_create(g_hndl)) == NULL)
17554 scfdie();
17556 if (scf_iter_scope_services(iter, cur_scope) != 0)
17557 scfdie();
17559 for (;;) {
17560 r = scf_iter_next_service(iter, svc);
17561 if (r == 0)
17562 break;
17563 if (r != 1)
17564 scfdie();
17566 if (scf_service_get_name(svc, buf,
17567 max_scf_name_len + 1) < 0)
17568 scfdie();
17570 if (strncmp(buf, arg1, len) == 0) {
17571 err = cpl_add_completion(cpl, line, word_start,
17572 word_end, buf + len, "", " ");
17573 if (err != 0)
17574 break;
17578 scf_iter_destroy(iter);
17579 scf_service_destroy(svc);
17581 return (err);
17585 /* ARGSUSED */
17586 CPL_MATCH_FN(complete_command)
17588 uint32_t scope = 0;
17590 if (cur_snap != NULL)
17591 scope = CS_SNAP;
17592 else if (cur_inst != NULL)
17593 scope = CS_INST;
17594 else if (cur_svc != NULL)
17595 scope = CS_SVC;
17596 else
17597 scope = CS_SCOPE;
17599 return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
17601 #endif /* NATIVE_BUILD */