1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2015 Joyent, Inc.
25 * Copyright 2012 Milan Jurik. All rights reserved.
26 * Copyright 2017 RackTop Systems.
27 */
28
29
30 #include <alloca.h>
31 #include <assert.h>
32 #include <ctype.h>
33 #include <door.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <fnmatch.h>
37 #include <inttypes.h>
38 #include <libintl.h>
39 #include <libnvpair.h>
40 #include <libscf.h>
41 #include <libscf_priv.h>
42 #include <libtecla.h>
43 #include <libuutil.h>
44 #include <limits.h>
45 #include <locale.h>
46 #include <stdarg.h>
47 #include <string.h>
48 #include <strings.h>
49 #include <time.h>
50 #include <unistd.h>
51 #include <wait.h>
52 #include <poll.h>
53
54 #include <libxml/tree.h>
55
56 #include <sys/param.h>
57
58 #include <sys/stat.h>
59 #include <sys/mman.h>
60
61 #include "svccfg.h"
62 #include "notify_params.h"
63 #include "manifest_hash.h"
64 #include "manifest_find.h"
65
66 /* The colon namespaces in each entity (each followed by a newline). */
67 #define COLON_NAMESPACES ":properties\n"
68
69 #define TEMP_FILE_PATTERN "/tmp/svccfg-XXXXXX"
70
71 /* These are characters which the lexer requires to be in double-quotes. */
72 #define CHARS_TO_QUOTE " \t\n\\>=\"()"
73
74 #define HASH_SIZE 16
75 #define HASH_PG_TYPE "framework"
76 #define HASH_PG_FLAGS 0
77 #define HASH_PROP "md5sum"
78
79 /*
80 * Indentation used in the output of the describe subcommand.
81 */
82 #define TMPL_VALUE_INDENT " "
83 #define TMPL_INDENT " "
84 #define TMPL_INDENT_2X " "
85 #define TMPL_CHOICE_INDENT " "
86
87 /*
88 * Directory locations for manifests
89 */
90 #define VARSVC_DIR "/var/svc/manifest"
91 #define LIBSVC_DIR "/lib/svc/manifest"
92 #define VARSVC_PR "var_svc_manifest"
93 #define LIBSVC_PR "lib_svc_manifest"
94 #define MFSTFILEPR "manifestfile"
95
96 #define SUPPORTPROP "support"
97
98 #define MFSTHISTFILE "/lib/svc/share/mfsthistory"
99
100 #define MFSTFILE_MAX 16
101
102 /*
103 * These are the classes of elements which may appear as children of service
104 * or instance elements in XML manifests.
105 */
106 struct entity_elts {
107 xmlNodePtr create_default_instance;
108 xmlNodePtr single_instance;
109 xmlNodePtr restarter;
110 xmlNodePtr dependencies;
111 xmlNodePtr dependents;
112 xmlNodePtr method_context;
113 xmlNodePtr exec_methods;
114 xmlNodePtr notify_params;
115 xmlNodePtr property_groups;
116 xmlNodePtr instances;
117 xmlNodePtr stability;
118 xmlNodePtr template;
119 };
120
121 /*
122 * Likewise for property_group elements.
123 */
124 struct pg_elts {
125 xmlNodePtr stability;
126 xmlNodePtr propvals;
127 xmlNodePtr properties;
128 };
129
130 /*
131 * Likewise for template elements.
132 */
133 struct template_elts {
134 xmlNodePtr common_name;
135 xmlNodePtr description;
136 xmlNodePtr documentation;
137 };
138
139 /*
140 * Likewise for type (for notification parameters) elements.
141 */
142 struct params_elts {
143 xmlNodePtr paramval;
144 xmlNodePtr parameter;
145 };
146
147 /*
148 * This structure is for snaplevel lists. They are convenient because libscf
149 * only allows traversing snaplevels in one direction.
150 */
151 struct snaplevel {
152 uu_list_node_t list_node;
153 scf_snaplevel_t *sl;
154 };
155
156 /*
157 * This is used for communication between lscf_service_export and
158 * export_callback.
159 */
160 struct export_args {
161 const char *filename;
162 int flags;
163 };
164
165 /*
166 * The service_manifest structure is used by the upgrade process
167 * to create a list of service to manifest linkages from the manifests
168 * in a set of given directories.
169 */
170 typedef struct service_manifest {
171 const char *servicename;
172 uu_list_t *mfstlist;
173 size_t mfstlist_sz;
174
175 uu_avl_node_t svcmfst_node;
176 } service_manifest_t;
177
178 /*
179 * Structure to track the manifest file property group
180 * and the manifest file associated with that property
181 * group. Also, a flag to keep the access once it has
182 * been checked.
183 */
184 struct mpg_mfile {
185 char *mpg;
186 char *mfile;
187 int access;
188 };
189
190 const char * const scf_pg_general = SCF_PG_GENERAL;
191 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
192 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
193 const char * const scf_property_external = "external";
194
195 const char * const snap_initial = "initial";
196 const char * const snap_lastimport = "last-import";
197 const char * const snap_previous = "previous";
198 const char * const snap_running = "running";
199
200 scf_handle_t *g_hndl = NULL; /* only valid after lscf_prep_hndl() */
201
202 ssize_t max_scf_fmri_len;
203 ssize_t max_scf_name_len;
204 ssize_t max_scf_pg_type_len;
205 ssize_t max_scf_value_len;
206 static size_t max_scf_len;
207
208 static scf_scope_t *cur_scope;
209 static scf_service_t *cur_svc = NULL;
210 static scf_instance_t *cur_inst = NULL;
211 static scf_snapshot_t *cur_snap = NULL;
212 static scf_snaplevel_t *cur_level = NULL;
213
214 static uu_list_pool_t *snaplevel_pool;
215 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
216 static uu_list_t *cur_levels;
217 static struct snaplevel *cur_elt; /* cur_elt->sl == cur_level */
218
219 static FILE *tempfile = NULL;
220 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
221
222 static const char *emsg_entity_not_selected;
223 static const char *emsg_permission_denied;
224 static const char *emsg_create_xml;
225 static const char *emsg_cant_modify_snapshots;
226 static const char *emsg_invalid_for_snapshot;
227 static const char *emsg_read_only;
228 static const char *emsg_deleted;
229 static const char *emsg_invalid_pg_name;
230 static const char *emsg_invalid_prop_name;
231 static const char *emsg_no_such_pg;
232 static const char *emsg_fmri_invalid_pg_name;
233 static const char *emsg_fmri_invalid_pg_name_type;
234 static const char *emsg_pg_added;
235 static const char *emsg_pg_changed;
236 static const char *emsg_pg_deleted;
237 static const char *emsg_pg_mod_perm;
238 static const char *emsg_pg_add_perm;
239 static const char *emsg_pg_del_perm;
240 static const char *emsg_snap_perm;
241 static const char *emsg_dpt_dangling;
242 static const char *emsg_dpt_no_dep;
243
244 static int li_only = 0;
245 static int no_refresh = 0;
246
247 /* how long in ns we should wait between checks for a pg */
248 static uint64_t pg_timeout = 100 * (NANOSEC / MILLISEC);
249
250 /* import globals, to minimize allocations */
251 static scf_scope_t *imp_scope = NULL;
252 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
253 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
254 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
255 static scf_snapshot_t *imp_rsnap = NULL;
256 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
257 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
258 static scf_property_t *imp_prop = NULL;
259 static scf_iter_t *imp_iter = NULL;
260 static scf_iter_t *imp_rpg_iter = NULL;
261 static scf_iter_t *imp_up_iter = NULL;
262 static scf_transaction_t *imp_tx = NULL; /* always reset this */
263 static char *imp_str = NULL;
264 static size_t imp_str_sz;
265 static char *imp_tsname = NULL;
266 static char *imp_fe1 = NULL; /* for fmri_equal() */
267 static char *imp_fe2 = NULL;
268 static uu_list_t *imp_deleted_dpts = NULL; /* pgroup_t's to refresh */
269
270 /* upgrade_dependents() globals */
271 static scf_instance_t *ud_inst = NULL;
272 static scf_snaplevel_t *ud_snpl = NULL;
273 static scf_propertygroup_t *ud_pg = NULL;
274 static scf_propertygroup_t *ud_cur_depts_pg = NULL;
275 static scf_propertygroup_t *ud_run_dpts_pg = NULL;
276 static int ud_run_dpts_pg_set = 0;
277 static scf_property_t *ud_prop = NULL;
278 static scf_property_t *ud_dpt_prop = NULL;
279 static scf_value_t *ud_val = NULL;
280 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
281 static scf_transaction_t *ud_tx = NULL;
282 static char *ud_ctarg = NULL;
283 static char *ud_oldtarg = NULL;
284 static char *ud_name = NULL;
285
286 /* export globals */
287 static scf_instance_t *exp_inst;
288 static scf_propertygroup_t *exp_pg;
289 static scf_property_t *exp_prop;
290 static scf_value_t *exp_val;
291 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
292 static char *exp_str;
293 static size_t exp_str_sz;
294
295 /* cleanup globals */
296 static uu_avl_pool_t *service_manifest_pool = NULL;
297 static uu_avl_t *service_manifest_tree = NULL;
298
299 static void scfdie_lineno(int lineno) __NORETURN;
300
301 static char *start_method_names[] = {
302 "start",
303 "inetd_start",
304 NULL
305 };
306
307 static struct uri_scheme {
308 const char *scheme;
309 const char *protocol;
310 } uri_scheme[] = {
311 { "mailto", "smtp" },
312 { "snmp", "snmp" },
313 { "syslog", "syslog" },
314 { NULL, NULL }
315 };
316 #define URI_SCHEME_NUM ((sizeof (uri_scheme) / \
317 sizeof (struct uri_scheme)) - 1)
318
319 static int
320 check_uri_scheme(const char *scheme)
321 {
322 int i;
323
324 for (i = 0; uri_scheme[i].scheme != NULL; ++i) {
325 if (strcmp(scheme, uri_scheme[i].scheme) == 0)
326 return (i);
327 }
328
329 return (-1);
330 }
331
332 static int
333 check_uri_protocol(const char *p)
334 {
335 int i;
336
337 for (i = 0; uri_scheme[i].protocol != NULL; ++i) {
338 if (strcmp(p, uri_scheme[i].protocol) == 0)
339 return (i);
340 }
341
342 return (-1);
343 }
344
345 /*
346 * For unexpected libscf errors.
347 */
348 #ifdef NDEBUG
349
350 static void scfdie(void) __NORETURN;
351
352 static void
353 scfdie(void)
354 {
355 scf_error_t err = scf_error();
356
357 if (err == SCF_ERROR_CONNECTION_BROKEN)
358 uu_die(gettext("Repository connection broken. Exiting.\n"));
359
360 uu_die(gettext("Unexpected fatal libscf error: %s. Exiting.\n"),
361 scf_strerror(err));
362 }
363
364 #else
365
366 #define scfdie() scfdie_lineno(__LINE__)
367
368 static void
369 scfdie_lineno(int lineno)
370 {
371 scf_error_t err = scf_error();
372
373 if (err == SCF_ERROR_CONNECTION_BROKEN)
374 uu_die(gettext("Repository connection broken. Exiting.\n"));
375
376 uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
377 ": %s.\n"), lineno, scf_strerror(err));
378 }
379
380 #endif
381
382 static void
383 scfwarn(void)
384 {
385 warn(gettext("Unexpected libscf error: %s.\n"),
386 scf_strerror(scf_error()));
387 }
388
389 /*
390 * Clear a field of a structure.
391 */
392 static int
393 clear_int(void *a, void *b)
394 {
395 /* LINTED */
396 *(int *)((char *)a + (size_t)b) = 0;
397
398 return (UU_WALK_NEXT);
399 }
400
401 static int
402 scferror2errno(scf_error_t err)
403 {
404 switch (err) {
405 case SCF_ERROR_BACKEND_ACCESS:
406 return (EACCES);
407
408 case SCF_ERROR_BACKEND_READONLY:
409 return (EROFS);
410
411 case SCF_ERROR_CONNECTION_BROKEN:
412 return (ECONNABORTED);
413
414 case SCF_ERROR_CONSTRAINT_VIOLATED:
415 case SCF_ERROR_INVALID_ARGUMENT:
416 return (EINVAL);
417
418 case SCF_ERROR_DELETED:
419 return (ECANCELED);
420
421 case SCF_ERROR_EXISTS:
422 return (EEXIST);
423
424 case SCF_ERROR_NO_MEMORY:
425 return (ENOMEM);
426
427 case SCF_ERROR_NO_RESOURCES:
428 return (ENOSPC);
429
430 case SCF_ERROR_NOT_FOUND:
431 return (ENOENT);
432
433 case SCF_ERROR_PERMISSION_DENIED:
434 return (EPERM);
435
436 default:
437 #ifndef NDEBUG
438 (void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
439 __FILE__, __LINE__, err);
440 #else
441 (void) fprintf(stderr, "Unknown libscf error %d.\n", err);
442 #endif
443 abort();
444 /* NOTREACHED */
445 }
446 }
447
448 static int
449 entity_get_pg(void *ent, int issvc, const char *name,
450 scf_propertygroup_t *pg)
451 {
452 if (issvc)
453 return (scf_service_get_pg(ent, name, pg));
454 else
455 return (scf_instance_get_pg(ent, name, pg));
456 }
457
458 static void
459 entity_destroy(void *ent, int issvc)
460 {
461 if (issvc)
462 scf_service_destroy(ent);
463 else
464 scf_instance_destroy(ent);
465 }
466
467 static int
468 get_pg(const char *pg_name, scf_propertygroup_t *pg)
469 {
470 int ret;
471
472 if (cur_level != NULL)
473 ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
474 else if (cur_inst != NULL)
475 ret = scf_instance_get_pg(cur_inst, pg_name, pg);
476 else
477 ret = scf_service_get_pg(cur_svc, pg_name, pg);
478
479 return (ret);
480 }
481
482 /*
483 * Find a snaplevel in a snapshot. If get_svc is true, find the service
484 * snaplevel. Otherwise find the instance snaplevel.
485 *
486 * Returns
487 * 0 - success
488 * ECONNABORTED - repository connection broken
489 * ECANCELED - instance containing snap was deleted
490 * ENOENT - snap has no snaplevels
491 * - requested snaplevel not found
492 */
493 static int
494 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
495 {
496 if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
497 switch (scf_error()) {
498 case SCF_ERROR_CONNECTION_BROKEN:
499 case SCF_ERROR_DELETED:
500 case SCF_ERROR_NOT_FOUND:
501 return (scferror2errno(scf_error()));
502
503 case SCF_ERROR_HANDLE_MISMATCH:
504 case SCF_ERROR_NOT_BOUND:
505 case SCF_ERROR_NOT_SET:
506 default:
507 bad_error("scf_snapshot_get_base_snaplevel",
508 scf_error());
509 }
510 }
511
512 for (;;) {
513 ssize_t ssz;
514
515 ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
516 if (ssz >= 0) {
517 if (!get_svc)
518 return (0);
519 } else {
520 switch (scf_error()) {
521 case SCF_ERROR_CONSTRAINT_VIOLATED:
522 if (get_svc)
523 return (0);
524 break;
525
526 case SCF_ERROR_DELETED:
527 case SCF_ERROR_CONNECTION_BROKEN:
528 return (scferror2errno(scf_error()));
529
530 case SCF_ERROR_NOT_SET:
531 case SCF_ERROR_NOT_BOUND:
532 default:
533 bad_error("scf_snaplevel_get_instance_name",
534 scf_error());
535 }
536 }
537
538 if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
539 switch (scf_error()) {
540 case SCF_ERROR_NOT_FOUND:
541 case SCF_ERROR_CONNECTION_BROKEN:
542 case SCF_ERROR_DELETED:
543 return (scferror2errno(scf_error()));
544
545 case SCF_ERROR_HANDLE_MISMATCH:
546 case SCF_ERROR_NOT_BOUND:
547 case SCF_ERROR_NOT_SET:
548 case SCF_ERROR_INVALID_ARGUMENT:
549 default:
550 bad_error("scf_snaplevel_get_next_snaplevel",
551 scf_error());
552 }
553 }
554 }
555 }
556
557 /*
558 * If issvc is 0, take ent to be a pointer to an scf_instance_t. If it has
559 * a running snapshot, and that snapshot has an instance snaplevel, set pg to
560 * the property group named name in it. If it doesn't have a running
561 * snapshot, set pg to the instance's current property group named name.
562 *
563 * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
564 * its instances. If one has a running snapshot with a service snaplevel, set
565 * pg to the property group named name in it. If no such snaplevel could be
566 * found, set pg to the service's current property group named name.
567 *
568 * iter, inst, snap, and snpl are required scratch objects.
569 *
570 * Returns
571 * 0 - success
572 * ECONNABORTED - repository connection broken
573 * ECANCELED - ent was deleted
574 * ENOENT - no such property group
575 * EINVAL - name is an invalid property group name
576 * EBADF - found running snapshot is missing a snaplevel
577 */
578 static int
579 entity_get_running_pg(void *ent, int issvc, const char *name,
580 scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
581 scf_snapshot_t *snap, scf_snaplevel_t *snpl)
582 {
583 int r;
584
585 if (issvc) {
586 /* Search for an instance with a running snapshot. */
587 if (scf_iter_service_instances(iter, ent) != 0) {
588 switch (scf_error()) {
589 case SCF_ERROR_DELETED:
590 case SCF_ERROR_CONNECTION_BROKEN:
591 return (scferror2errno(scf_error()));
592
593 case SCF_ERROR_NOT_SET:
594 case SCF_ERROR_NOT_BOUND:
595 case SCF_ERROR_HANDLE_MISMATCH:
596 default:
597 bad_error("scf_iter_service_instances",
598 scf_error());
599 }
600 }
601
602 for (;;) {
603 r = scf_iter_next_instance(iter, inst);
604 if (r == 0) {
605 if (scf_service_get_pg(ent, name, pg) == 0)
606 return (0);
607
608 switch (scf_error()) {
609 case SCF_ERROR_DELETED:
610 case SCF_ERROR_NOT_FOUND:
611 case SCF_ERROR_INVALID_ARGUMENT:
612 case SCF_ERROR_CONNECTION_BROKEN:
613 return (scferror2errno(scf_error()));
614
615 case SCF_ERROR_NOT_BOUND:
616 case SCF_ERROR_HANDLE_MISMATCH:
617 case SCF_ERROR_NOT_SET:
618 default:
619 bad_error("scf_service_get_pg",
620 scf_error());
621 }
622 }
623 if (r != 1) {
624 switch (scf_error()) {
625 case SCF_ERROR_DELETED:
626 case SCF_ERROR_CONNECTION_BROKEN:
627 return (scferror2errno(scf_error()));
628
629 case SCF_ERROR_INVALID_ARGUMENT:
630 case SCF_ERROR_NOT_SET:
631 case SCF_ERROR_NOT_BOUND:
632 case SCF_ERROR_HANDLE_MISMATCH:
633 default:
634 bad_error("scf_iter_next_instance",
635 scf_error());
636 }
637 }
638
639 if (scf_instance_get_snapshot(inst, snap_running,
640 snap) == 0)
641 break;
642
643 switch (scf_error()) {
644 case SCF_ERROR_NOT_FOUND:
645 case SCF_ERROR_DELETED:
646 continue;
647
648 case SCF_ERROR_CONNECTION_BROKEN:
649 return (ECONNABORTED);
650
651 case SCF_ERROR_HANDLE_MISMATCH:
652 case SCF_ERROR_INVALID_ARGUMENT:
653 case SCF_ERROR_NOT_SET:
654 case SCF_ERROR_NOT_BOUND:
655 default:
656 bad_error("scf_instance_get_snapshot",
657 scf_error());
658 }
659 }
660 } else {
661 if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
662 switch (scf_error()) {
663 case SCF_ERROR_NOT_FOUND:
664 break;
665
666 case SCF_ERROR_DELETED:
667 case SCF_ERROR_CONNECTION_BROKEN:
668 return (scferror2errno(scf_error()));
669
670 case SCF_ERROR_NOT_BOUND:
671 case SCF_ERROR_HANDLE_MISMATCH:
672 case SCF_ERROR_INVALID_ARGUMENT:
673 case SCF_ERROR_NOT_SET:
674 default:
675 bad_error("scf_instance_get_snapshot",
676 scf_error());
677 }
678
679 if (scf_instance_get_pg(ent, name, pg) == 0)
680 return (0);
681
682 switch (scf_error()) {
683 case SCF_ERROR_DELETED:
684 case SCF_ERROR_NOT_FOUND:
685 case SCF_ERROR_INVALID_ARGUMENT:
686 case SCF_ERROR_CONNECTION_BROKEN:
687 return (scferror2errno(scf_error()));
688
689 case SCF_ERROR_NOT_BOUND:
690 case SCF_ERROR_HANDLE_MISMATCH:
691 case SCF_ERROR_NOT_SET:
692 default:
693 bad_error("scf_instance_get_pg", scf_error());
694 }
695 }
696 }
697
698 r = get_snaplevel(snap, issvc, snpl);
699 switch (r) {
700 case 0:
701 break;
702
703 case ECONNABORTED:
704 case ECANCELED:
705 return (r);
706
707 case ENOENT:
708 return (EBADF);
709
710 default:
711 bad_error("get_snaplevel", r);
712 }
713
714 if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
715 return (0);
716
717 switch (scf_error()) {
718 case SCF_ERROR_DELETED:
719 case SCF_ERROR_INVALID_ARGUMENT:
720 case SCF_ERROR_CONNECTION_BROKEN:
721 case SCF_ERROR_NOT_FOUND:
722 return (scferror2errno(scf_error()));
723
724 case SCF_ERROR_NOT_BOUND:
725 case SCF_ERROR_HANDLE_MISMATCH:
726 case SCF_ERROR_NOT_SET:
727 default:
728 bad_error("scf_snaplevel_get_pg", scf_error());
729 /* NOTREACHED */
730 }
731 }
732
733 /*
734 * To be registered with atexit().
735 */
736 static void
737 remove_tempfile(void)
738 {
739 int ret;
740
741 if (tempfile != NULL) {
742 if (fclose(tempfile) == EOF)
743 (void) warn(gettext("Could not close temporary file"));
744 tempfile = NULL;
745 }
746
747 if (tempfilename[0] != '\0') {
748 do {
749 ret = remove(tempfilename);
750 } while (ret == -1 && errno == EINTR);
751 if (ret == -1)
752 warn(gettext("Could not remove temporary file"));
753 tempfilename[0] = '\0';
754 }
755 }
756
757 /*
758 * Launch private svc.configd(1M) for manipulating alternate repositories.
759 */
760 static void
761 start_private_repository(engine_state_t *est)
762 {
763 int fd, stat;
764 struct door_info info;
765 pid_t pid;
766
767 /*
768 * 1. Create a temporary file for the door.
769 */
770 if (est->sc_repo_doorname != NULL)
771 free((void *)est->sc_repo_doorname);
772
773 est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
774 if (est->sc_repo_doorname == NULL)
775 uu_die(gettext("Could not acquire temporary filename"));
776
777 fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
778 if (fd < 0)
779 uu_die(gettext("Could not create temporary file for "
780 "repository server"));
781
782 (void) close(fd);
783
784 /*
785 * 2. Launch a configd with that door, using the specified
786 * repository.
787 */
788 if ((est->sc_repo_pid = fork()) == 0) {
789 (void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
790 "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
791 NULL);
792 uu_die(gettext("Could not execute %s"), est->sc_repo_server);
793 } else if (est->sc_repo_pid == -1)
794 uu_die(gettext("Attempt to fork failed"));
795
796 do {
797 pid = waitpid(est->sc_repo_pid, &stat, 0);
798 } while (pid == -1 && errno == EINTR);
799
800 if (pid == -1)
801 uu_die(gettext("Could not waitpid() for repository server"));
802
803 if (!WIFEXITED(stat)) {
804 uu_die(gettext("Repository server failed (status %d).\n"),
805 stat);
806 } else if (WEXITSTATUS(stat) != 0) {
807 uu_die(gettext("Repository server failed (exit %d).\n"),
808 WEXITSTATUS(stat));
809 }
810
811 /*
812 * See if it was successful by checking if the door is a door.
813 */
814
815 fd = open(est->sc_repo_doorname, O_RDWR);
816 if (fd < 0)
817 uu_die(gettext("Could not open door \"%s\""),
818 est->sc_repo_doorname);
819
820 if (door_info(fd, &info) < 0)
821 uu_die(gettext("Unexpected door_info() error"));
822
823 if (close(fd) == -1)
824 warn(gettext("Could not close repository door"),
825 strerror(errno));
826
827 est->sc_repo_pid = info.di_target;
828 }
829
830 void
831 lscf_cleanup(void)
832 {
833 /*
834 * In the case where we've launched a private svc.configd(1M)
835 * instance, we must terminate our child and remove the temporary
836 * rendezvous point.
837 */
838 if (est->sc_repo_pid > 0) {
839 (void) kill(est->sc_repo_pid, SIGTERM);
840 (void) waitpid(est->sc_repo_pid, NULL, 0);
841 (void) unlink(est->sc_repo_doorname);
842
843 est->sc_repo_pid = 0;
844 }
845 }
846
847 void
848 unselect_cursnap(void)
849 {
850 void *cookie;
851
852 cur_level = NULL;
853
854 cookie = NULL;
855 while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
856 scf_snaplevel_destroy(cur_elt->sl);
857 free(cur_elt);
858 }
859
860 scf_snapshot_destroy(cur_snap);
861 cur_snap = NULL;
862 }
863
864 void
865 lscf_prep_hndl(void)
866 {
867 if (g_hndl != NULL)
868 return;
869
870 g_hndl = scf_handle_create(SCF_VERSION);
871 if (g_hndl == NULL)
872 scfdie();
873
874 if (est->sc_repo_filename != NULL)
875 start_private_repository(est);
876
877 if (est->sc_repo_doorname != NULL) {
878 scf_value_t *repo_value;
879 int ret;
880
881 repo_value = scf_value_create(g_hndl);
882 if (repo_value == NULL)
883 scfdie();
884
885 ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
886 assert(ret == SCF_SUCCESS);
887
888 if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
889 SCF_SUCCESS)
890 scfdie();
891
892 scf_value_destroy(repo_value);
893 }
894
895 if (scf_handle_bind(g_hndl) != 0)
896 uu_die(gettext("Could not connect to repository server: %s.\n"),
897 scf_strerror(scf_error()));
898
899 cur_scope = scf_scope_create(g_hndl);
900 if (cur_scope == NULL)
901 scfdie();
902
903 if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
904 scfdie();
905 }
906
907 static void
908 repository_teardown(void)
909 {
910 if (g_hndl != NULL) {
911 if (cur_snap != NULL)
912 unselect_cursnap();
913 scf_instance_destroy(cur_inst);
914 scf_service_destroy(cur_svc);
915 scf_scope_destroy(cur_scope);
916 scf_handle_destroy(g_hndl);
917 cur_inst = NULL;
918 cur_svc = NULL;
919 cur_scope = NULL;
920 g_hndl = NULL;
921 lscf_cleanup();
922 }
923 }
924
925 void
926 lscf_set_repository(const char *repfile, int force)
927 {
928 repository_teardown();
929
930 if (est->sc_repo_filename != NULL) {
931 free((void *)est->sc_repo_filename);
932 est->sc_repo_filename = NULL;
933 }
934
935 if ((force == 0) && (access(repfile, R_OK) != 0)) {
936 /*
937 * Repository file does not exist
938 * or has no read permission.
939 */
940 warn(gettext("Cannot access \"%s\": %s\n"),
941 repfile, strerror(errno));
942 } else {
943 est->sc_repo_filename = safe_strdup(repfile);
944 }
945
946 lscf_prep_hndl();
947 }
948
949 void
950 lscf_init()
951 {
952 if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
953 (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
954 (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
955 0 ||
956 (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
957 scfdie();
958
959 max_scf_len = max_scf_fmri_len;
960 if (max_scf_name_len > max_scf_len)
961 max_scf_len = max_scf_name_len;
962 if (max_scf_pg_type_len > max_scf_len)
963 max_scf_len = max_scf_pg_type_len;
964 /*
965 * When a value of type opaque is represented as a string, the
966 * string contains 2 characters for every byte of data. That is
967 * because the string contains the hex representation of the opaque
968 * value.
969 */
970 if (2 * max_scf_value_len > max_scf_len)
971 max_scf_len = 2 * max_scf_value_len;
972
973 if (atexit(remove_tempfile) != 0)
974 uu_die(gettext("Could not register atexit() function"));
975
976 emsg_entity_not_selected = gettext("An entity is not selected.\n");
977 emsg_permission_denied = gettext("Permission denied.\n");
978 emsg_create_xml = gettext("Could not create XML node.\n");
979 emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
980 emsg_invalid_for_snapshot =
981 gettext("Invalid operation on a snapshot.\n");
982 emsg_read_only = gettext("Backend read-only.\n");
983 emsg_deleted = gettext("Current selection has been deleted.\n");
984 emsg_invalid_pg_name =
985 gettext("Invalid property group name \"%s\".\n");
986 emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
987 emsg_no_such_pg = gettext("No such property group \"%s\".\n");
988 emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
989 "with invalid name \"%s\".\n");
990 emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
991 "group with invalid name \"%s\" or type \"%s\".\n");
992 emsg_pg_added = gettext("%s changed unexpectedly "
993 "(property group \"%s\" added).\n");
994 emsg_pg_changed = gettext("%s changed unexpectedly "
995 "(property group \"%s\" changed).\n");
996 emsg_pg_deleted = gettext("%s changed unexpectedly "
997 "(property group \"%s\" or an ancestor was deleted).\n");
998 emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
999 "in %s (permission denied).\n");
1000 emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
1001 "in %s (permission denied).\n");
1002 emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
1003 "in %s (permission denied).\n");
1004 emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
1005 "(permission denied).\n");
1006 emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
1007 "new dependent \"%s\" because it already exists). Warning: The "
1008 "current dependent's target (%s) does not exist.\n");
1009 emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
1010 "dependent \"%s\" because it already exists). Warning: The "
1011 "current dependent's target (%s) does not have a dependency named "
1012 "\"%s\" as expected.\n");
1013
1014 string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
1015 offsetof(string_list_t, node), NULL, 0);
1016 snaplevel_pool = uu_list_pool_create("snaplevels",
1017 sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
1018 NULL, 0);
1019 }
1020
1021
1022 static const char *
1023 prop_to_typestr(const scf_property_t *prop)
1024 {
1025 scf_type_t ty;
1026
1027 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
1028 scfdie();
1029
1030 return (scf_type_to_string(ty));
1031 }
1032
1033 static scf_type_t
1034 string_to_type(const char *type)
1035 {
1036 size_t len = strlen(type);
1037 char *buf;
1038
1039 if (len == 0 || type[len - 1] != ':')
1040 return (SCF_TYPE_INVALID);
1041
1042 buf = (char *)alloca(len + 1);
1043 (void) strlcpy(buf, type, len + 1);
1044 buf[len - 1] = 0;
1045
1046 return (scf_string_to_type(buf));
1047 }
1048
1049 static scf_value_t *
1050 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
1051 {
1052 scf_value_t *v;
1053 char *dup, *nstr;
1054 size_t len;
1055
1056 v = scf_value_create(g_hndl);
1057 if (v == NULL)
1058 scfdie();
1059
1060 len = strlen(str);
1061 if (require_quotes &&
1062 (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
1063 semerr(gettext("Multiple string values or string values "
1064 "with spaces must be quoted with '\"'.\n"));
1065 scf_value_destroy(v);
1066 return (NULL);
1067 }
1068
1069 nstr = dup = safe_strdup(str);
1070 if (dup[0] == '\"') {
1071 /*
1072 * Strip out the first and the last quote.
1073 */
1074 dup[len - 1] = '\0';
1075 nstr = dup + 1;
1076 }
1077
1078 if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
1079 assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1080 semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1081 scf_type_to_string(ty), nstr);
1082 scf_value_destroy(v);
1083 v = NULL;
1084 }
1085 free(dup);
1086 return (v);
1087 }
1088
1089 /*
1090 * Print str to strm, quoting double-quotes and backslashes with backslashes.
1091 * Optionally append a comment prefix ('#') to newlines ('\n').
1092 */
1093 static int
1094 quote_and_print(const char *str, FILE *strm, int commentnl)
1095 {
1096 const char *cp;
1097
1098 for (cp = str; *cp != '\0'; ++cp) {
1099 if (*cp == '"' || *cp == '\\')
1100 (void) putc('\\', strm);
1101
1102 (void) putc(*cp, strm);
1103
1104 if (commentnl && *cp == '\n') {
1105 (void) putc('#', strm);
1106 }
1107 }
1108
1109 return (ferror(strm));
1110 }
1111
1112 /*
1113 * These wrappers around lowlevel functions provide consistent error checking
1114 * and warnings.
1115 */
1116 static int
1117 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1118 {
1119 if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1120 return (0);
1121
1122 if (scf_error() != SCF_ERROR_NOT_FOUND)
1123 scfdie();
1124
1125 if (g_verbose) {
1126 ssize_t len;
1127 char *fmri;
1128
1129 len = scf_pg_to_fmri(pg, NULL, 0);
1130 if (len < 0)
1131 scfdie();
1132
1133 fmri = safe_malloc(len + 1);
1134
1135 if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1136 scfdie();
1137
1138 warn(gettext("Expected property %s of property group %s is "
1139 "missing.\n"), propname, fmri);
1140
1141 free(fmri);
1142 }
1143
1144 return (-1);
1145 }
1146
1147 static int
1148 prop_check_type(scf_property_t *prop, scf_type_t ty)
1149 {
1150 scf_type_t pty;
1151
1152 if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1153 scfdie();
1154
1155 if (ty == pty)
1156 return (0);
1157
1158 if (g_verbose) {
1159 ssize_t len;
1160 char *fmri;
1161 const char *tystr;
1162
1163 len = scf_property_to_fmri(prop, NULL, 0);
1164 if (len < 0)
1165 scfdie();
1166
1167 fmri = safe_malloc(len + 1);
1168
1169 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1170 scfdie();
1171
1172 tystr = scf_type_to_string(ty);
1173 if (tystr == NULL)
1174 tystr = "?";
1175
1176 warn(gettext("Property %s is not of expected type %s.\n"),
1177 fmri, tystr);
1178
1179 free(fmri);
1180 }
1181
1182 return (-1);
1183 }
1184
1185 static int
1186 prop_get_val(scf_property_t *prop, scf_value_t *val)
1187 {
1188 scf_error_t err;
1189
1190 if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1191 return (0);
1192
1193 err = scf_error();
1194
1195 if (err != SCF_ERROR_NOT_FOUND &&
1196 err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1197 err != SCF_ERROR_PERMISSION_DENIED)
1198 scfdie();
1199
1200 if (g_verbose) {
1201 ssize_t len;
1202 char *fmri, *emsg;
1203
1204 len = scf_property_to_fmri(prop, NULL, 0);
1205 if (len < 0)
1206 scfdie();
1207
1208 fmri = safe_malloc(len + 1);
1209
1210 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1211 scfdie();
1212
1213 if (err == SCF_ERROR_NOT_FOUND)
1214 emsg = gettext("Property %s has no values; expected "
1215 "one.\n");
1216 else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1217 emsg = gettext("Property %s has multiple values; "
1218 "expected one.\n");
1219 else
1220 emsg = gettext("No permission to read property %s.\n");
1221
1222 warn(emsg, fmri);
1223
1224 free(fmri);
1225 }
1226
1227 return (-1);
1228 }
1229
1230
1231 static boolean_t
1232 snaplevel_is_instance(const scf_snaplevel_t *level)
1233 {
1234 if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1235 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1236 scfdie();
1237 return (0);
1238 } else {
1239 return (1);
1240 }
1241 }
1242
1243 /*
1244 * Decode FMRI into a service or instance, and put the result in *ep. If
1245 * memory cannot be allocated, return SCF_ERROR_NO_MEMORY. If the FMRI is
1246 * invalid, return SCF_ERROR_INVALID_ARGUMENT. If the FMRI does not specify
1247 * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED. If the entity cannot be
1248 * found, return SCF_ERROR_NOT_FOUND. Otherwise return SCF_ERROR_NONE, point
1249 * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1250 * whether *ep is a service.
1251 */
1252 static scf_error_t
1253 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1254 {
1255 char *fmri_copy;
1256 const char *sstr, *istr, *pgstr;
1257 scf_service_t *svc;
1258 scf_instance_t *inst;
1259
1260 fmri_copy = strdup(fmri);
1261 if (fmri_copy == NULL)
1262 return (SCF_ERROR_NO_MEMORY);
1263
1264 if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1265 SCF_SUCCESS) {
1266 free(fmri_copy);
1267 return (SCF_ERROR_INVALID_ARGUMENT);
1268 }
1269
1270 free(fmri_copy);
1271
1272 if (sstr == NULL || pgstr != NULL)
1273 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1274
1275 if (istr == NULL) {
1276 svc = scf_service_create(h);
1277 if (svc == NULL)
1278 return (SCF_ERROR_NO_MEMORY);
1279
1280 if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1281 SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1282 if (scf_error() != SCF_ERROR_NOT_FOUND)
1283 scfdie();
1284
1285 return (SCF_ERROR_NOT_FOUND);
1286 }
1287
1288 *ep = svc;
1289 *isservice = 1;
1290 } else {
1291 inst = scf_instance_create(h);
1292 if (inst == NULL)
1293 return (SCF_ERROR_NO_MEMORY);
1294
1295 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1296 NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1297 if (scf_error() != SCF_ERROR_NOT_FOUND)
1298 scfdie();
1299
1300 return (SCF_ERROR_NOT_FOUND);
1301 }
1302
1303 *ep = inst;
1304 *isservice = 0;
1305 }
1306
1307 return (SCF_ERROR_NONE);
1308 }
1309
1310 /*
1311 * Create the entity named by fmri. Place a pointer to its libscf handle in
1312 * *ep, and set or clear *isservicep if it is a service or an instance.
1313 * Returns
1314 * SCF_ERROR_NONE - success
1315 * SCF_ERROR_NO_MEMORY - scf_*_create() failed
1316 * SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1317 * SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1318 * SCF_ERROR_NOT_FOUND - no such scope
1319 * SCF_ERROR_PERMISSION_DENIED
1320 * SCF_ERROR_BACKEND_READONLY
1321 * SCF_ERROR_BACKEND_ACCESS
1322 */
1323 static scf_error_t
1324 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1325 {
1326 char *fmri_copy;
1327 const char *scstr, *sstr, *istr, *pgstr;
1328 scf_scope_t *scope = NULL;
1329 scf_service_t *svc = NULL;
1330 scf_instance_t *inst = NULL;
1331 scf_error_t scfe;
1332
1333 fmri_copy = safe_strdup(fmri);
1334
1335 if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1336 0) {
1337 free(fmri_copy);
1338 return (SCF_ERROR_INVALID_ARGUMENT);
1339 }
1340
1341 if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1342 free(fmri_copy);
1343 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1344 }
1345
1346 *ep = NULL;
1347
1348 if ((scope = scf_scope_create(h)) == NULL ||
1349 (svc = scf_service_create(h)) == NULL ||
1350 (inst = scf_instance_create(h)) == NULL) {
1351 scfe = SCF_ERROR_NO_MEMORY;
1352 goto out;
1353 }
1354
1355 get_scope:
1356 if (scf_handle_get_scope(h, scstr, scope) != 0) {
1357 switch (scf_error()) {
1358 case SCF_ERROR_CONNECTION_BROKEN:
1359 scfdie();
1360 /* NOTREACHED */
1361
1362 case SCF_ERROR_NOT_FOUND:
1363 scfe = SCF_ERROR_NOT_FOUND;
1364 goto out;
1365
1366 case SCF_ERROR_HANDLE_MISMATCH:
1367 case SCF_ERROR_NOT_BOUND:
1368 case SCF_ERROR_INVALID_ARGUMENT:
1369 default:
1370 bad_error("scf_handle_get_scope", scf_error());
1371 }
1372 }
1373
1374 get_svc:
1375 if (scf_scope_get_service(scope, sstr, svc) != 0) {
1376 switch (scf_error()) {
1377 case SCF_ERROR_CONNECTION_BROKEN:
1378 scfdie();
1379 /* NOTREACHED */
1380
1381 case SCF_ERROR_DELETED:
1382 goto get_scope;
1383
1384 case SCF_ERROR_NOT_FOUND:
1385 break;
1386
1387 case SCF_ERROR_HANDLE_MISMATCH:
1388 case SCF_ERROR_INVALID_ARGUMENT:
1389 case SCF_ERROR_NOT_BOUND:
1390 case SCF_ERROR_NOT_SET:
1391 default:
1392 bad_error("scf_scope_get_service", scf_error());
1393 }
1394
1395 if (scf_scope_add_service(scope, sstr, svc) != 0) {
1396 switch (scf_error()) {
1397 case SCF_ERROR_CONNECTION_BROKEN:
1398 scfdie();
1399 /* NOTREACHED */
1400
1401 case SCF_ERROR_DELETED:
1402 goto get_scope;
1403
1404 case SCF_ERROR_PERMISSION_DENIED:
1405 case SCF_ERROR_BACKEND_READONLY:
1406 case SCF_ERROR_BACKEND_ACCESS:
1407 scfe = scf_error();
1408 goto out;
1409
1410 case SCF_ERROR_HANDLE_MISMATCH:
1411 case SCF_ERROR_INVALID_ARGUMENT:
1412 case SCF_ERROR_NOT_BOUND:
1413 case SCF_ERROR_NOT_SET:
1414 default:
1415 bad_error("scf_scope_get_service", scf_error());
1416 }
1417 }
1418 }
1419
1420 if (istr == NULL) {
1421 scfe = SCF_ERROR_NONE;
1422 *ep = svc;
1423 *isservicep = 1;
1424 goto out;
1425 }
1426
1427 get_inst:
1428 if (scf_service_get_instance(svc, istr, inst) != 0) {
1429 switch (scf_error()) {
1430 case SCF_ERROR_CONNECTION_BROKEN:
1431 scfdie();
1432 /* NOTREACHED */
1433
1434 case SCF_ERROR_DELETED:
1435 goto get_svc;
1436
1437 case SCF_ERROR_NOT_FOUND:
1438 break;
1439
1440 case SCF_ERROR_HANDLE_MISMATCH:
1441 case SCF_ERROR_INVALID_ARGUMENT:
1442 case SCF_ERROR_NOT_BOUND:
1443 case SCF_ERROR_NOT_SET:
1444 default:
1445 bad_error("scf_service_get_instance", scf_error());
1446 }
1447
1448 if (scf_service_add_instance(svc, istr, inst) != 0) {
1449 switch (scf_error()) {
1450 case SCF_ERROR_CONNECTION_BROKEN:
1451 scfdie();
1452 /* NOTREACHED */
1453
1454 case SCF_ERROR_DELETED:
1455 goto get_svc;
1456
1457 case SCF_ERROR_PERMISSION_DENIED:
1458 case SCF_ERROR_BACKEND_READONLY:
1459 case SCF_ERROR_BACKEND_ACCESS:
1460 scfe = scf_error();
1461 goto out;
1462
1463 case SCF_ERROR_HANDLE_MISMATCH:
1464 case SCF_ERROR_INVALID_ARGUMENT:
1465 case SCF_ERROR_NOT_BOUND:
1466 case SCF_ERROR_NOT_SET:
1467 default:
1468 bad_error("scf_service_add_instance",
1469 scf_error());
1470 }
1471 }
1472 }
1473
1474 scfe = SCF_ERROR_NONE;
1475 *ep = inst;
1476 *isservicep = 0;
1477
1478 out:
1479 if (*ep != inst)
1480 scf_instance_destroy(inst);
1481 if (*ep != svc)
1482 scf_service_destroy(svc);
1483 scf_scope_destroy(scope);
1484 free(fmri_copy);
1485 return (scfe);
1486 }
1487
1488 /*
1489 * Create or update a snapshot of inst. snap is a required scratch object.
1490 *
1491 * Returns
1492 * 0 - success
1493 * ECONNABORTED - repository connection broken
1494 * EPERM - permission denied
1495 * ENOSPC - configd is out of resources
1496 * ECANCELED - inst was deleted
1497 * -1 - unknown libscf error (message printed)
1498 */
1499 static int
1500 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1501 {
1502 again:
1503 if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1504 if (_scf_snapshot_take_attach(inst, snap) != 0) {
1505 switch (scf_error()) {
1506 case SCF_ERROR_CONNECTION_BROKEN:
1507 case SCF_ERROR_PERMISSION_DENIED:
1508 case SCF_ERROR_NO_RESOURCES:
1509 return (scferror2errno(scf_error()));
1510
1511 case SCF_ERROR_NOT_SET:
1512 case SCF_ERROR_INVALID_ARGUMENT:
1513 default:
1514 bad_error("_scf_snapshot_take_attach",
1515 scf_error());
1516 }
1517 }
1518 } else {
1519 switch (scf_error()) {
1520 case SCF_ERROR_NOT_FOUND:
1521 break;
1522
1523 case SCF_ERROR_DELETED:
1524 case SCF_ERROR_CONNECTION_BROKEN:
1525 return (scferror2errno(scf_error()));
1526
1527 case SCF_ERROR_HANDLE_MISMATCH:
1528 case SCF_ERROR_NOT_BOUND:
1529 case SCF_ERROR_INVALID_ARGUMENT:
1530 case SCF_ERROR_NOT_SET:
1531 default:
1532 bad_error("scf_instance_get_snapshot", scf_error());
1533 }
1534
1535 if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1536 switch (scf_error()) {
1537 case SCF_ERROR_EXISTS:
1538 goto again;
1539
1540 case SCF_ERROR_CONNECTION_BROKEN:
1541 case SCF_ERROR_NO_RESOURCES:
1542 case SCF_ERROR_PERMISSION_DENIED:
1543 return (scferror2errno(scf_error()));
1544
1545 default:
1546 scfwarn();
1547 return (-1);
1548
1549 case SCF_ERROR_NOT_SET:
1550 case SCF_ERROR_INTERNAL:
1551 case SCF_ERROR_INVALID_ARGUMENT:
1552 case SCF_ERROR_HANDLE_MISMATCH:
1553 bad_error("_scf_snapshot_take_new",
1554 scf_error());
1555 }
1556 }
1557 }
1558
1559 return (0);
1560 }
1561
1562 static int
1563 refresh_running_snapshot(void *entity)
1564 {
1565 scf_snapshot_t *snap;
1566 int r;
1567
1568 if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1569 scfdie();
1570 r = take_snap(entity, snap_running, snap);
1571 scf_snapshot_destroy(snap);
1572
1573 return (r);
1574 }
1575
1576 /*
1577 * Refresh entity. If isservice is zero, take entity to be an scf_instance_t *.
1578 * Otherwise take entity to be an scf_service_t * and refresh all of its child
1579 * instances. fmri is used for messages. inst, iter, and name_buf are used
1580 * for scratch space. Returns
1581 * 0 - success
1582 * ECONNABORTED - repository connection broken
1583 * ECANCELED - entity was deleted
1584 * EACCES - backend denied access
1585 * EPERM - permission denied
1586 * ENOSPC - repository server out of resources
1587 * -1 - _smf_refresh_instance_i() failed. scf_error() should be set.
1588 */
1589 static int
1590 refresh_entity(int isservice, void *entity, const char *fmri,
1591 scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1592 {
1593 scf_error_t scfe;
1594 int r;
1595
1596 if (!isservice) {
1597 /*
1598 * Let restarter handles refreshing and making new running
1599 * snapshot only if operating on a live repository and not
1600 * running in early import.
1601 */
1602 if (est->sc_repo_filename == NULL &&
1603 est->sc_repo_doorname == NULL &&
1604 est->sc_in_emi == 0) {
1605 if (_smf_refresh_instance_i(entity) == 0) {
1606 if (g_verbose)
1607 warn(gettext("Refreshed %s.\n"), fmri);
1608 return (0);
1609 }
1610
1611 switch (scf_error()) {
1612 case SCF_ERROR_BACKEND_ACCESS:
1613 return (EACCES);
1614
1615 case SCF_ERROR_PERMISSION_DENIED:
1616 return (EPERM);
1617
1618 default:
1619 return (-1);
1620 }
1621 } else {
1622 r = refresh_running_snapshot(entity);
1623 switch (r) {
1624 case 0:
1625 break;
1626
1627 case ECONNABORTED:
1628 case ECANCELED:
1629 case EPERM:
1630 case ENOSPC:
1631 break;
1632
1633 default:
1634 bad_error("refresh_running_snapshot",
1635 scf_error());
1636 }
1637
1638 return (r);
1639 }
1640 }
1641
1642 if (scf_iter_service_instances(iter, entity) != 0) {
1643 switch (scf_error()) {
1644 case SCF_ERROR_CONNECTION_BROKEN:
1645 return (ECONNABORTED);
1646
1647 case SCF_ERROR_DELETED:
1648 return (ECANCELED);
1649
1650 case SCF_ERROR_HANDLE_MISMATCH:
1651 case SCF_ERROR_NOT_BOUND:
1652 case SCF_ERROR_NOT_SET:
1653 default:
1654 bad_error("scf_iter_service_instances", scf_error());
1655 }
1656 }
1657
1658 for (;;) {
1659 r = scf_iter_next_instance(iter, inst);
1660 if (r == 0)
1661 break;
1662 if (r != 1) {
1663 switch (scf_error()) {
1664 case SCF_ERROR_CONNECTION_BROKEN:
1665 return (ECONNABORTED);
1666
1667 case SCF_ERROR_DELETED:
1668 return (ECANCELED);
1669
1670 case SCF_ERROR_HANDLE_MISMATCH:
1671 case SCF_ERROR_NOT_BOUND:
1672 case SCF_ERROR_NOT_SET:
1673 case SCF_ERROR_INVALID_ARGUMENT:
1674 default:
1675 bad_error("scf_iter_next_instance",
1676 scf_error());
1677 }
1678 }
1679
1680 /*
1681 * Similarly, just take a new running snapshot if operating on
1682 * a non-live repository or running during early import.
1683 */
1684 if (est->sc_repo_filename != NULL ||
1685 est->sc_repo_doorname != NULL ||
1686 est->sc_in_emi == 1) {
1687 r = refresh_running_snapshot(inst);
1688 switch (r) {
1689 case 0:
1690 continue;
1691
1692 case ECONNABORTED:
1693 case ECANCELED:
1694 case EPERM:
1695 case ENOSPC:
1696 break;
1697 default:
1698 bad_error("refresh_running_snapshot",
1699 scf_error());
1700 }
1701
1702 return (r);
1703
1704 }
1705
1706 if (_smf_refresh_instance_i(inst) == 0) {
1707 if (g_verbose) {
1708 if (scf_instance_get_name(inst, name_buf,
1709 max_scf_name_len + 1) < 0)
1710 (void) strcpy(name_buf, "?");
1711
1712 warn(gettext("Refreshed %s:%s.\n"),
1713 fmri, name_buf);
1714 }
1715 } else {
1716 if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1717 g_verbose) {
1718 scfe = scf_error();
1719
1720 if (scf_instance_to_fmri(inst, name_buf,
1721 max_scf_name_len + 1) < 0)
1722 (void) strcpy(name_buf, "?");
1723
1724 warn(gettext(
1725 "Refresh of %s:%s failed: %s.\n"), fmri,
1726 name_buf, scf_strerror(scfe));
1727 }
1728 }
1729 }
1730
1731 return (0);
1732 }
1733
1734 static void
1735 private_refresh(void)
1736 {
1737 scf_instance_t *pinst = NULL;
1738 scf_iter_t *piter = NULL;
1739 ssize_t fmrilen;
1740 size_t bufsz;
1741 char *fmribuf;
1742 void *ent;
1743 int issvc;
1744 int r;
1745
1746 if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1747 return;
1748
1749 assert(cur_svc != NULL);
1750
1751 bufsz = max_scf_fmri_len + 1;
1752 fmribuf = safe_malloc(bufsz);
1753 if (cur_inst) {
1754 issvc = 0;
1755 ent = cur_inst;
1756 fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1757 } else {
1758 issvc = 1;
1759 ent = cur_svc;
1760 fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1761 if ((pinst = scf_instance_create(g_hndl)) == NULL)
1762 scfdie();
1763
1764 if ((piter = scf_iter_create(g_hndl)) == NULL)
1765 scfdie();
1766 }
1767 if (fmrilen < 0) {
1768 free(fmribuf);
1769 if (scf_error() != SCF_ERROR_DELETED)
1770 scfdie();
1771
1772 warn(emsg_deleted);
1773 return;
1774 }
1775 assert(fmrilen < bufsz);
1776
1777 r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1778 switch (r) {
1779 case 0:
1780 break;
1781
1782 case ECONNABORTED:
1783 warn(gettext("Could not refresh %s "
1784 "(repository connection broken).\n"), fmribuf);
1785 break;
1786
1787 case ECANCELED:
1788 warn(emsg_deleted);
1789 break;
1790
1791 case EPERM:
1792 warn(gettext("Could not refresh %s "
1793 "(permission denied).\n"), fmribuf);
1794 break;
1795
1796 case ENOSPC:
1797 warn(gettext("Could not refresh %s "
1798 "(repository server out of resources).\n"),
1799 fmribuf);
1800 break;
1801
1802 case EACCES:
1803 default:
1804 bad_error("refresh_entity", scf_error());
1805 }
1806
1807 if (issvc) {
1808 scf_instance_destroy(pinst);
1809 scf_iter_destroy(piter);
1810 }
1811
1812 free(fmribuf);
1813 }
1814
1815
1816 static int
1817 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1818 {
1819 cbp->sc_err = scferror2errno(err);
1820 return (UU_WALK_ERROR);
1821 }
1822
1823 static int
1824 stash_scferror(scf_callback_t *cbp)
1825 {
1826 return (stash_scferror_err(cbp, scf_error()));
1827 }
1828
1829 static int select_inst(const char *);
1830 static int select_svc(const char *);
1831
1832 /*
1833 * Take a property that does not have a type and check to see if a type
1834 * exists or can be gleened from the current data. Set the type.
1835 *
1836 * Check the current level (instance) and then check the higher level
1837 * (service). This could be the case for adding a new property to
1838 * the instance that's going to "override" a service level property.
1839 *
1840 * For a property :
1841 * 1. Take the type from an existing property
1842 * 2. Take the type from a template entry
1843 *
1844 * If the type can not be found, then leave the type as is, and let the import
1845 * report the problem of the missing type.
1846 */
1847 static int
1848 find_current_prop_type(void *p, void *g)
1849 {
1850 property_t *prop = p;
1851 scf_callback_t *lcb = g;
1852 pgroup_t *pg = NULL;
1853
1854 const char *fmri = NULL;
1855 char *lfmri = NULL;
1856 char *cur_selection = NULL;
1857
1858 scf_propertygroup_t *sc_pg = NULL;
1859 scf_property_t *sc_prop = NULL;
1860 scf_pg_tmpl_t *t_pg = NULL;
1861 scf_prop_tmpl_t *t_prop = NULL;
1862 scf_type_t prop_type;
1863
1864 value_t *vp;
1865 int issvc = lcb->sc_service;
1866 int r = UU_WALK_ERROR;
1867
1868 if (prop->sc_value_type != SCF_TYPE_INVALID)
1869 return (UU_WALK_NEXT);
1870
1871 t_prop = scf_tmpl_prop_create(g_hndl);
1872 sc_prop = scf_property_create(g_hndl);
1873 if (sc_prop == NULL || t_prop == NULL) {
1874 warn(gettext("Unable to create the property to attempt and "
1875 "find a missing type.\n"));
1876
1877 scf_property_destroy(sc_prop);
1878 scf_tmpl_prop_destroy(t_prop);
1879
1880 return (UU_WALK_ERROR);
1881 }
1882
1883 if (lcb->sc_flags == 1) {
1884 pg = lcb->sc_parent;
1885 issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT);
1886 fmri = pg->sc_parent->sc_fmri;
1887 retry_pg:
1888 if (cur_svc && cur_selection == NULL) {
1889 cur_selection = safe_malloc(max_scf_fmri_len + 1);
1890 lscf_get_selection_str(cur_selection,
1891 max_scf_fmri_len + 1);
1892
1893 if (strcmp(cur_selection, fmri) != 0) {
1894 lscf_select(fmri);
1895 } else {
1896 free(cur_selection);
1897 cur_selection = NULL;
1898 }
1899 } else {
1900 lscf_select(fmri);
1901 }
1902
1903 if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) {
1904 warn(gettext("Unable to create property group to "
1905 "find a missing property type.\n"));
1906
1907 goto out;
1908 }
1909
1910 if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) {
1911 /*
1912 * If this is the sc_pg from the parent
1913 * let the caller clean up the sc_pg,
1914 * and just throw it away in this case.
1915 */
1916 if (sc_pg != lcb->sc_parent)
1917 scf_pg_destroy(sc_pg);
1918
1919 sc_pg = NULL;
1920 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1921 warn(gettext("Unable to create template "
1922 "property group to find a property "
1923 "type.\n"));
1924
1925 goto out;
1926 }
1927
1928 if (scf_tmpl_get_by_pg_name(fmri, NULL,
1929 pg->sc_pgroup_name, NULL, t_pg,
1930 SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) {
1931 /*
1932 * if instance get service and jump back
1933 */
1934 scf_tmpl_pg_destroy(t_pg);
1935 t_pg = NULL;
1936 if (issvc == 0) {
1937 entity_t *e = pg->sc_parent->sc_parent;
1938
1939 fmri = e->sc_fmri;
1940 issvc = 1;
1941 goto retry_pg;
1942 } else {
1943 goto out;
1944 }
1945 }
1946 }
1947 } else {
1948 sc_pg = lcb->sc_parent;
1949 }
1950
1951 /*
1952 * Attempt to get the type from an existing property. If the property
1953 * cannot be found then attempt to get the type from a template entry
1954 * for the property.
1955 *
1956 * Finally, if at the instance level look at the service level.
1957 */
1958 if (sc_pg != NULL &&
1959 pg_get_prop(sc_pg, prop->sc_property_name,
1960 sc_prop) == SCF_SUCCESS &&
1961 scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) {
1962 prop->sc_value_type = prop_type;
1963
1964 /*
1965 * Found a type, update the value types and validate
1966 * the actual value against this type.
1967 */
1968 for (vp = uu_list_first(prop->sc_property_values);
1969 vp != NULL;
1970 vp = uu_list_next(prop->sc_property_values, vp)) {
1971 vp->sc_type = prop->sc_value_type;
1972 lxml_store_value(vp, 0, NULL);
1973 }
1974
1975 r = UU_WALK_NEXT;
1976 goto out;
1977 }
1978
1979 /*
1980 * If we get here with t_pg set to NULL then we had to have
1981 * gotten an sc_pg but that sc_pg did not have the property
1982 * we are looking for. So if the t_pg is not null look up
1983 * the template entry for the property.
1984 *
1985 * If the t_pg is null then need to attempt to get a matching
1986 * template entry for the sc_pg, and see if there is a property
1987 * entry for that template entry.
1988 */
1989 do_tmpl :
1990 if (t_pg != NULL &&
1991 scf_tmpl_get_by_prop(t_pg, prop->sc_property_name,
1992 t_prop, 0) == SCF_SUCCESS) {
1993 if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) {
1994 prop->sc_value_type = prop_type;
1995
1996 /*
1997 * Found a type, update the value types and validate
1998 * the actual value against this type.
1999 */
2000 for (vp = uu_list_first(prop->sc_property_values);
2001 vp != NULL;
2002 vp = uu_list_next(prop->sc_property_values, vp)) {
2003 vp->sc_type = prop->sc_value_type;
2004 lxml_store_value(vp, 0, NULL);
2005 }
2006
2007 r = UU_WALK_NEXT;
2008 goto out;
2009 }
2010 } else {
2011 if (t_pg == NULL && sc_pg) {
2012 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
2013 warn(gettext("Unable to create template "
2014 "property group to find a property "
2015 "type.\n"));
2016
2017 goto out;
2018 }
2019
2020 if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
2021 scf_tmpl_pg_destroy(t_pg);
2022 t_pg = NULL;
2023 } else {
2024 goto do_tmpl;
2025 }
2026 }
2027 }
2028
2029 if (issvc == 0) {
2030 scf_instance_t *i;
2031 scf_service_t *s;
2032
2033 issvc = 1;
2034 if (lcb->sc_flags == 1) {
2035 entity_t *e = pg->sc_parent->sc_parent;
2036
2037 fmri = e->sc_fmri;
2038 goto retry_pg;
2039 }
2040
2041 /*
2042 * because lcb->sc_flags was not set then this means
2043 * the pg was not used and can be used here.
2044 */
2045 if ((pg = internal_pgroup_new()) == NULL) {
2046 warn(gettext("Could not create internal property group "
2047 "to find a missing type."));
2048
2049 goto out;
2050 }
2051
2052 pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1);
2053 if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name,
2054 max_scf_name_len + 1) < 0)
2055 goto out;
2056
2057 i = scf_instance_create(g_hndl);
2058 s = scf_service_create(g_hndl);
2059 if (i == NULL || s == NULL ||
2060 scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) {
2061 warn(gettext("Could not get a service for the instance "
2062 "to find a missing type."));
2063
2064 goto out;
2065 }
2066
2067 /*
2068 * Check to see truly at the instance level.
2069 */
2070 lfmri = safe_malloc(max_scf_fmri_len + 1);
2071 if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
2072 scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0)
2073 goto out;
2074 else
2075 fmri = (const char *)lfmri;
2076
2077 goto retry_pg;
2078 }
2079
2080 out :
2081 if (sc_pg != lcb->sc_parent) {
2082 scf_pg_destroy(sc_pg);
2083 }
2084
2085 /*
2086 * If this is true then the pg was allocated
2087 * here, and the name was set so need to free
2088 * the name and the pg.
2089 */
2090 if (pg != NULL && pg != lcb->sc_parent) {
2091 free((char *)pg->sc_pgroup_name);
2092 internal_pgroup_free(pg);
2093 }
2094
2095 if (cur_selection) {
2096 lscf_select(cur_selection);
2097 free(cur_selection);
2098 }
2099
2100 scf_tmpl_pg_destroy(t_pg);
2101 scf_tmpl_prop_destroy(t_prop);
2102 scf_property_destroy(sc_prop);
2103
2104 if (r != UU_WALK_NEXT)
2105 warn(gettext("Could not find property type for \"%s\" "
2106 "from \"%s\"\n"), prop->sc_property_name,
2107 fmri != NULL ? fmri : lcb->sc_source_fmri);
2108
2109 free(lfmri);
2110
2111 return (r);
2112 }
2113
2114 /*
2115 * Take a property group that does not have a type and check to see if a type
2116 * exists or can be gleened from the current data. Set the type.
2117 *
2118 * Check the current level (instance) and then check the higher level
2119 * (service). This could be the case for adding a new property to
2120 * the instance that's going to "override" a service level property.
2121 *
2122 * For a property group
2123 * 1. Take the type from an existing property group
2124 * 2. Take the type from a template entry
2125 *
2126 * If the type can not be found, then leave the type as is, and let the import
2127 * report the problem of the missing type.
2128 */
2129 static int
2130 find_current_pg_type(void *p, void *sori)
2131 {
2132 entity_t *si = sori;
2133 pgroup_t *pg = p;
2134
2135 const char *ofmri, *fmri;
2136 char *cur_selection = NULL;
2137 char *pg_type = NULL;
2138
2139 scf_propertygroup_t *sc_pg = NULL;
2140 scf_pg_tmpl_t *t_pg = NULL;
2141
2142 int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2143 int r = UU_WALK_ERROR;
2144
2145 ofmri = fmri = si->sc_fmri;
2146 if (pg->sc_pgroup_type != NULL) {
2147 r = UU_WALK_NEXT;
2148
2149 goto out;
2150 }
2151
2152 sc_pg = scf_pg_create(g_hndl);
2153 if (sc_pg == NULL) {
2154 warn(gettext("Unable to create property group to attempt "
2155 "and find a missing type.\n"));
2156
2157 return (UU_WALK_ERROR);
2158 }
2159
2160 /*
2161 * Using get_pg() requires that the cur_svc/cur_inst be
2162 * via lscf_select. Need to preserve the current selection
2163 * if going to use lscf_select() to set up the cur_svc/cur_inst
2164 */
2165 if (cur_svc) {
2166 cur_selection = safe_malloc(max_scf_fmri_len + 1);
2167 lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1);
2168 }
2169
2170 /*
2171 * If the property group exists get the type, and set
2172 * the pgroup_t type of that type.
2173 *
2174 * If not the check for a template pg_pattern entry
2175 * and take the type from that.
2176 */
2177 retry_svc:
2178 lscf_select(fmri);
2179
2180 if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) {
2181 pg_type = safe_malloc(max_scf_pg_type_len + 1);
2182 if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type,
2183 max_scf_pg_type_len + 1) != -1) {
2184 pg->sc_pgroup_type = pg_type;
2185
2186 r = UU_WALK_NEXT;
2187 goto out;
2188 } else {
2189 free(pg_type);
2190 }
2191 } else {
2192 if ((t_pg == NULL) &&
2193 (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
2194 goto out;
2195
2196 if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name,
2197 NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS &&
2198 scf_tmpl_pg_type(t_pg, &pg_type) != -1) {
2199 pg->sc_pgroup_type = pg_type;
2200
2201 r = UU_WALK_NEXT;
2202 goto out;
2203 }
2204 }
2205
2206 /*
2207 * If type is not found at the instance level then attempt to
2208 * find the type at the service level.
2209 */
2210 if (!issvc) {
2211 si = si->sc_parent;
2212 fmri = si->sc_fmri;
2213 issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2214 goto retry_svc;
2215 }
2216
2217 out :
2218 if (cur_selection) {
2219 lscf_select(cur_selection);
2220 free(cur_selection);
2221 }
2222
2223 /*
2224 * Now walk the properties of the property group to make sure that
2225 * all properties have the correct type and values are valid for
2226 * those types.
2227 */
2228 if (r == UU_WALK_NEXT) {
2229 scf_callback_t cb;
2230
2231 cb.sc_service = issvc;
2232 cb.sc_source_fmri = ofmri;
2233 if (sc_pg != NULL) {
2234 cb.sc_parent = sc_pg;
2235 cb.sc_flags = 0;
2236 } else {
2237 cb.sc_parent = pg;
2238 cb.sc_flags = 1;
2239 }
2240
2241 if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type,
2242 &cb, UU_DEFAULT) != 0) {
2243 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2244 bad_error("uu_list_walk", uu_error());
2245
2246 r = UU_WALK_ERROR;
2247 }
2248 } else {
2249 warn(gettext("Could not find property group type for "
2250 "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri);
2251 }
2252
2253 scf_tmpl_pg_destroy(t_pg);
2254 scf_pg_destroy(sc_pg);
2255
2256 return (r);
2257 }
2258
2259 /*
2260 * Import. These functions import a bundle into the repository.
2261 */
2262
2263 /*
2264 * Add a transaction entry to lcbdata->sc_trans for this property_t. Uses
2265 * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata. On success,
2266 * returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
2267 * lcbdata->sc_err to
2268 * ENOMEM - out of memory
2269 * ECONNABORTED - repository connection broken
2270 * ECANCELED - sc_trans's property group was deleted
2271 * EINVAL - p's name is invalid (error printed)
2272 * - p has an invalid value (error printed)
2273 */
2274 static int
2275 lscf_property_import(void *v, void *pvt)
2276 {
2277 property_t *p = v;
2278 scf_callback_t *lcbdata = pvt;
2279 value_t *vp;
2280 scf_transaction_t *trans = lcbdata->sc_trans;
2281 scf_transaction_entry_t *entr;
2282 scf_value_t *val;
2283 scf_type_t tp;
2284
2285 if ((lcbdata->sc_flags & SCI_NOENABLED ||
2286 lcbdata->sc_flags & SCI_DELAYENABLE) &&
2287 strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
2288 lcbdata->sc_enable = p;
2289 return (UU_WALK_NEXT);
2290 }
2291
2292 entr = scf_entry_create(lcbdata->sc_handle);
2293 if (entr == NULL) {
2294 switch (scf_error()) {
2295 case SCF_ERROR_NO_MEMORY:
2296 return (stash_scferror(lcbdata));
2297
2298 case SCF_ERROR_INVALID_ARGUMENT:
2299 default:
2300 bad_error("scf_entry_create", scf_error());
2301 }
2302 }
2303
2304 tp = p->sc_value_type;
2305
2306 if (scf_transaction_property_new(trans, entr,
2307 p->sc_property_name, tp) != 0) {
2308 switch (scf_error()) {
2309 case SCF_ERROR_INVALID_ARGUMENT:
2310 semerr(emsg_invalid_prop_name, p->sc_property_name);
2311 scf_entry_destroy(entr);
2312 return (stash_scferror(lcbdata));
2313
2314 case SCF_ERROR_EXISTS:
2315 break;
2316
2317 case SCF_ERROR_DELETED:
2318 case SCF_ERROR_CONNECTION_BROKEN:
2319 scf_entry_destroy(entr);
2320 return (stash_scferror(lcbdata));
2321
2322 case SCF_ERROR_NOT_BOUND:
2323 case SCF_ERROR_HANDLE_MISMATCH:
2324 case SCF_ERROR_NOT_SET:
2325 default:
2326 bad_error("scf_transaction_property_new", scf_error());
2327 }
2328
2329 if (scf_transaction_property_change_type(trans, entr,
2330 p->sc_property_name, tp) != 0) {
2331 switch (scf_error()) {
2332 case SCF_ERROR_DELETED:
2333 case SCF_ERROR_CONNECTION_BROKEN:
2334 scf_entry_destroy(entr);
2335 return (stash_scferror(lcbdata));
2336
2337 case SCF_ERROR_INVALID_ARGUMENT:
2338 semerr(emsg_invalid_prop_name,
2339 p->sc_property_name);
2340 scf_entry_destroy(entr);
2341 return (stash_scferror(lcbdata));
2342
2343 case SCF_ERROR_NOT_FOUND:
2344 case SCF_ERROR_NOT_SET:
2345 case SCF_ERROR_HANDLE_MISMATCH:
2346 case SCF_ERROR_NOT_BOUND:
2347 default:
2348 bad_error(
2349 "scf_transaction_property_change_type",
2350 scf_error());
2351 }
2352 }
2353 }
2354
2355 for (vp = uu_list_first(p->sc_property_values);
2356 vp != NULL;
2357 vp = uu_list_next(p->sc_property_values, vp)) {
2358 val = scf_value_create(g_hndl);
2359 if (val == NULL) {
2360 switch (scf_error()) {
2361 case SCF_ERROR_NO_MEMORY:
2362 return (stash_scferror(lcbdata));
2363
2364 case SCF_ERROR_INVALID_ARGUMENT:
2365 default:
2366 bad_error("scf_value_create", scf_error());
2367 }
2368 }
2369
2370 switch (tp) {
2371 case SCF_TYPE_BOOLEAN:
2372 scf_value_set_boolean(val, vp->sc_u.sc_count);
2373 break;
2374 case SCF_TYPE_COUNT:
2375 scf_value_set_count(val, vp->sc_u.sc_count);
2376 break;
2377 case SCF_TYPE_INTEGER:
2378 scf_value_set_integer(val, vp->sc_u.sc_integer);
2379 break;
2380 default:
2381 assert(vp->sc_u.sc_string != NULL);
2382 if (scf_value_set_from_string(val, tp,
2383 vp->sc_u.sc_string) != 0) {
2384 if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
2385 bad_error("scf_value_set_from_string",
2386 scf_error());
2387
2388 warn(gettext("Value \"%s\" is not a valid "
2389 "%s.\n"), vp->sc_u.sc_string,
2390 scf_type_to_string(tp));
2391 scf_value_destroy(val);
2392 return (stash_scferror(lcbdata));
2393 }
2394 break;
2395 }
2396
2397 if (scf_entry_add_value(entr, val) != 0)
2398 bad_error("scf_entry_add_value", scf_error());
2399 }
2400
2401 return (UU_WALK_NEXT);
2402 }
2403
2404 /*
2405 * Import a pgroup_t into the repository. Uses sc_handle, sc_parent,
2406 * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2407 * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2408 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
2409 * lcbdata->sc_err to
2410 * ECONNABORTED - repository connection broken
2411 * ENOMEM - out of memory
2412 * ENOSPC - svc.configd is out of resources
2413 * ECANCELED - sc_parent was deleted
2414 * EPERM - could not create property group (permission denied) (error printed)
2415 * - could not modify property group (permission denied) (error printed)
2416 * - could not delete property group (permission denied) (error printed)
2417 * EROFS - could not create property group (repository is read-only)
2418 * - could not delete property group (repository is read-only)
2419 * EACCES - could not create property group (backend access denied)
2420 * - could not delete property group (backend access denied)
2421 * EEXIST - could not create property group (already exists)
2422 * EINVAL - invalid property group name (error printed)
2423 * - invalid property name (error printed)
2424 * - invalid value (error printed)
2425 * EBUSY - new property group deleted (error printed)
2426 * - new property group changed (error printed)
2427 * - property group added (error printed)
2428 * - property group deleted (error printed)
2429 */
2430 static int
2431 entity_pgroup_import(void *v, void *pvt)
2432 {
2433 pgroup_t *p = v;
2434 scf_callback_t cbdata;
2435 scf_callback_t *lcbdata = pvt;
2436 void *ent = lcbdata->sc_parent;
2437 int issvc = lcbdata->sc_service;
2438 int r;
2439
2440 const char * const pg_changed = gettext("%s changed unexpectedly "
2441 "(new property group \"%s\" changed).\n");
2442
2443 /* Never import deleted property groups. */
2444 if (p->sc_pgroup_delete) {
2445 if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY &&
2446 entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) {
2447 goto delete_pg;
2448 }
2449 return (UU_WALK_NEXT);
2450 }
2451
2452 if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
2453 strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
2454 lcbdata->sc_general = p;
2455 return (UU_WALK_NEXT);
2456 }
2457
2458 add_pg:
2459 if (issvc)
2460 r = scf_service_add_pg(ent, p->sc_pgroup_name,
2461 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2462 else
2463 r = scf_instance_add_pg(ent, p->sc_pgroup_name,
2464 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2465 if (r != 0) {
2466 switch (scf_error()) {
2467 case SCF_ERROR_DELETED:
2468 case SCF_ERROR_CONNECTION_BROKEN:
2469 case SCF_ERROR_BACKEND_READONLY:
2470 case SCF_ERROR_BACKEND_ACCESS:
2471 case SCF_ERROR_NO_RESOURCES:
2472 return (stash_scferror(lcbdata));
2473
2474 case SCF_ERROR_EXISTS:
2475 if (lcbdata->sc_flags & SCI_FORCE)
2476 break;
2477 return (stash_scferror(lcbdata));
2478
2479 case SCF_ERROR_INVALID_ARGUMENT:
2480 warn(emsg_fmri_invalid_pg_name_type,
2481 lcbdata->sc_source_fmri,
2482 p->sc_pgroup_name, p->sc_pgroup_type);
2483 return (stash_scferror(lcbdata));
2484
2485 case SCF_ERROR_PERMISSION_DENIED:
2486 warn(emsg_pg_add_perm, p->sc_pgroup_name,
2487 lcbdata->sc_target_fmri);
2488 return (stash_scferror(lcbdata));
2489
2490 case SCF_ERROR_NOT_BOUND:
2491 case SCF_ERROR_HANDLE_MISMATCH:
2492 case SCF_ERROR_NOT_SET:
2493 default:
2494 bad_error("scf_service_add_pg", scf_error());
2495 }
2496
2497 if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2498 switch (scf_error()) {
2499 case SCF_ERROR_CONNECTION_BROKEN:
2500 case SCF_ERROR_DELETED:
2501 return (stash_scferror(lcbdata));
2502
2503 case SCF_ERROR_INVALID_ARGUMENT:
2504 warn(emsg_fmri_invalid_pg_name,
2505 lcbdata->sc_source_fmri,
2506 p->sc_pgroup_name);
2507 return (stash_scferror(lcbdata));
2508
2509 case SCF_ERROR_NOT_FOUND:
2510 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2511 p->sc_pgroup_name);
2512 lcbdata->sc_err = EBUSY;
2513 return (UU_WALK_ERROR);
2514
2515 case SCF_ERROR_NOT_BOUND:
2516 case SCF_ERROR_HANDLE_MISMATCH:
2517 case SCF_ERROR_NOT_SET:
2518 default:
2519 bad_error("entity_get_pg", scf_error());
2520 }
2521 }
2522
2523 if (lcbdata->sc_flags & SCI_KEEP)
2524 goto props;
2525
2526 delete_pg:
2527 if (scf_pg_delete(imp_pg) != 0) {
2528 switch (scf_error()) {
2529 case SCF_ERROR_DELETED:
2530 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2531 p->sc_pgroup_name);
2532 lcbdata->sc_err = EBUSY;
2533 return (UU_WALK_ERROR);
2534
2535 case SCF_ERROR_PERMISSION_DENIED:
2536 warn(emsg_pg_del_perm, p->sc_pgroup_name,
2537 lcbdata->sc_target_fmri);
2538 return (stash_scferror(lcbdata));
2539
2540 case SCF_ERROR_BACKEND_READONLY:
2541 case SCF_ERROR_BACKEND_ACCESS:
2542 case SCF_ERROR_CONNECTION_BROKEN:
2543 return (stash_scferror(lcbdata));
2544
2545 case SCF_ERROR_NOT_SET:
2546 default:
2547 bad_error("scf_pg_delete", scf_error());
2548 }
2549 }
2550
2551 if (p->sc_pgroup_delete)
2552 return (UU_WALK_NEXT);
2553
2554 goto add_pg;
2555 }
2556
2557 props:
2558
2559 /*
2560 * Add properties to property group, if any.
2561 */
2562 cbdata.sc_handle = lcbdata->sc_handle;
2563 cbdata.sc_parent = imp_pg;
2564 cbdata.sc_flags = lcbdata->sc_flags;
2565 cbdata.sc_trans = imp_tx;
2566 cbdata.sc_enable = NULL;
2567
2568 if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2569 switch (scf_error()) {
2570 case SCF_ERROR_BACKEND_ACCESS:
2571 case SCF_ERROR_BACKEND_READONLY:
2572 case SCF_ERROR_CONNECTION_BROKEN:
2573 return (stash_scferror(lcbdata));
2574
2575 case SCF_ERROR_DELETED:
2576 warn(pg_changed, lcbdata->sc_target_fmri,
2577 p->sc_pgroup_name);
2578 lcbdata->sc_err = EBUSY;
2579 return (UU_WALK_ERROR);
2580
2581 case SCF_ERROR_PERMISSION_DENIED:
2582 warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2583 lcbdata->sc_target_fmri);
2584 return (stash_scferror(lcbdata));
2585
2586 case SCF_ERROR_NOT_BOUND:
2587 case SCF_ERROR_NOT_SET:
2588 case SCF_ERROR_IN_USE:
2589 case SCF_ERROR_HANDLE_MISMATCH:
2590 default:
2591 bad_error("scf_transaction_start", scf_error());
2592 }
2593 }
2594
2595 if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2596 UU_DEFAULT) != 0) {
2597 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2598 bad_error("uu_list_walk", uu_error());
2599 scf_transaction_reset(imp_tx);
2600
2601 lcbdata->sc_err = cbdata.sc_err;
2602 if (cbdata.sc_err == ECANCELED) {
2603 warn(pg_changed, lcbdata->sc_target_fmri,
2604 p->sc_pgroup_name);
2605 lcbdata->sc_err = EBUSY;
2606 }
2607 return (UU_WALK_ERROR);
2608 }
2609
2610 if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2611 cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2612
2613 /*
2614 * take the snapshot running snapshot then
2615 * import the stored general/enable property
2616 */
2617 r = take_snap(ent, snap_running, imp_rsnap);
2618 switch (r) {
2619 case 0:
2620 break;
2621
2622 case ECONNABORTED:
2623 warn(gettext("Could not take %s snapshot on import "
2624 "(repository connection broken).\n"),
2625 snap_running);
2626 lcbdata->sc_err = r;
2627 return (UU_WALK_ERROR);
2628 case ECANCELED:
2629 warn(emsg_deleted);
2630 lcbdata->sc_err = r;
2631 return (UU_WALK_ERROR);
2632
2633 case EPERM:
2634 warn(gettext("Could not take %s snapshot "
2635 "(permission denied).\n"), snap_running);
2636 lcbdata->sc_err = r;
2637 return (UU_WALK_ERROR);
2638
2639 case ENOSPC:
2640 warn(gettext("Could not take %s snapshot"
2641 "(repository server out of resources).\n"),
2642 snap_running);
2643 lcbdata->sc_err = r;
2644 return (UU_WALK_ERROR);
2645
2646 default:
2647 bad_error("take_snap", r);
2648 }
2649
2650 r = lscf_property_import(cbdata.sc_enable, &cbdata);
2651 if (r != UU_WALK_NEXT) {
2652 if (r != UU_WALK_ERROR)
2653 bad_error("lscf_property_import", r);
2654 return (EINVAL);
2655 }
2656 }
2657
2658 r = scf_transaction_commit(imp_tx);
2659 switch (r) {
2660 case 1:
2661 r = UU_WALK_NEXT;
2662 break;
2663
2664 case 0:
2665 warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2666 lcbdata->sc_err = EBUSY;
2667 r = UU_WALK_ERROR;
2668 break;
2669
2670 case -1:
2671 switch (scf_error()) {
2672 case SCF_ERROR_BACKEND_READONLY:
2673 case SCF_ERROR_BACKEND_ACCESS:
2674 case SCF_ERROR_CONNECTION_BROKEN:
2675 case SCF_ERROR_NO_RESOURCES:
2676 r = stash_scferror(lcbdata);
2677 break;
2678
2679 case SCF_ERROR_DELETED:
2680 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2681 p->sc_pgroup_name);
2682 lcbdata->sc_err = EBUSY;
2683 r = UU_WALK_ERROR;
2684 break;
2685
2686 case SCF_ERROR_PERMISSION_DENIED:
2687 warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2688 lcbdata->sc_target_fmri);
2689 r = stash_scferror(lcbdata);
2690 break;
2691
2692 case SCF_ERROR_NOT_SET:
2693 case SCF_ERROR_INVALID_ARGUMENT:
2694 case SCF_ERROR_NOT_BOUND:
2695 default:
2696 bad_error("scf_transaction_commit", scf_error());
2697 }
2698 break;
2699
2700 default:
2701 bad_error("scf_transaction_commit", r);
2702 }
2703
2704 scf_transaction_destroy_children(imp_tx);
2705
2706 return (r);
2707 }
2708
2709 /*
2710 * Returns
2711 * 0 - success
2712 * ECONNABORTED - repository connection broken
2713 * ENOMEM - out of memory
2714 * ENOSPC - svc.configd is out of resources
2715 * ECANCELED - inst was deleted
2716 * EPERM - could not create property group (permission denied) (error printed)
2717 * - could not modify property group (permission denied) (error printed)
2718 * EROFS - could not create property group (repository is read-only)
2719 * EACCES - could not create property group (backend access denied)
2720 * EEXIST - could not create property group (already exists)
2721 * EINVAL - invalid property group name (error printed)
2722 * - invalid property name (error printed)
2723 * - invalid value (error printed)
2724 * EBUSY - new property group changed (error printed)
2725 */
2726 static int
2727 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2728 const entity_t *isvc, int flags)
2729 {
2730 scf_callback_t cbdata;
2731
2732 cbdata.sc_handle = scf_service_handle(svc);
2733 cbdata.sc_parent = svc;
2734 cbdata.sc_service = 1;
2735 cbdata.sc_general = 0;
2736 cbdata.sc_enable = 0;
2737 cbdata.sc_flags = flags;
2738 cbdata.sc_source_fmri = isvc->sc_fmri;
2739 cbdata.sc_target_fmri = target_fmri;
2740
2741 /*
2742 * If the op is set, then add the flag to the callback
2743 * flags for later use.
2744 */
2745 if (isvc->sc_op != SVCCFG_OP_NONE) {
2746 switch (isvc->sc_op) {
2747 case SVCCFG_OP_IMPORT :
2748 cbdata.sc_flags |= SCI_OP_IMPORT;
2749 break;
2750 case SVCCFG_OP_APPLY :
2751 cbdata.sc_flags |= SCI_OP_APPLY;
2752 break;
2753 case SVCCFG_OP_RESTORE :
2754 cbdata.sc_flags |= SCI_OP_RESTORE;
2755 break;
2756 default :
2757 uu_die(gettext("lscf_import_service_pgs : "
2758 "Unknown op stored in the service entity\n"));
2759
2760 }
2761 }
2762
2763 if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2764 UU_DEFAULT) != 0) {
2765 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2766 bad_error("uu_list_walk", uu_error());
2767
2768 return (cbdata.sc_err);
2769 }
2770
2771 return (0);
2772 }
2773
2774 /*
2775 * Returns
2776 * 0 - success
2777 * ECONNABORTED - repository connection broken
2778 * ENOMEM - out of memory
2779 * ENOSPC - svc.configd is out of resources
2780 * ECANCELED - inst was deleted
2781 * EPERM - could not create property group (permission denied) (error printed)
2782 * - could not modify property group (permission denied) (error printed)
2783 * EROFS - could not create property group (repository is read-only)
2784 * EACCES - could not create property group (backend access denied)
2785 * EEXIST - could not create property group (already exists)
2786 * EINVAL - invalid property group name (error printed)
2787 * - invalid property name (error printed)
2788 * - invalid value (error printed)
2789 * EBUSY - new property group changed (error printed)
2790 */
2791 static int
2792 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2793 const entity_t *iinst, int flags)
2794 {
2795 scf_callback_t cbdata;
2796
2797 cbdata.sc_handle = scf_instance_handle(inst);
2798 cbdata.sc_parent = inst;
2799 cbdata.sc_service = 0;
2800 cbdata.sc_general = NULL;
2801 cbdata.sc_enable = NULL;
2802 cbdata.sc_flags = flags;
2803 cbdata.sc_source_fmri = iinst->sc_fmri;
2804 cbdata.sc_target_fmri = target_fmri;
2805
2806 /*
2807 * If the op is set, then add the flag to the callback
2808 * flags for later use.
2809 */
2810 if (iinst->sc_op != SVCCFG_OP_NONE) {
2811 switch (iinst->sc_op) {
2812 case SVCCFG_OP_IMPORT :
2813 cbdata.sc_flags |= SCI_OP_IMPORT;
2814 break;
2815 case SVCCFG_OP_APPLY :
2816 cbdata.sc_flags |= SCI_OP_APPLY;
2817 break;
2818 case SVCCFG_OP_RESTORE :
2819 cbdata.sc_flags |= SCI_OP_RESTORE;
2820 break;
2821 default :
2822 uu_die(gettext("lscf_import_instance_pgs : "
2823 "Unknown op stored in the instance entity\n"));
2824 }
2825 }
2826
2827 if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2828 UU_DEFAULT) != 0) {
2829 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2830 bad_error("uu_list_walk", uu_error());
2831
2832 return (cbdata.sc_err);
2833 }
2834
2835 if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2836 cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2837 /*
2838 * If importing with the SCI_NOENABLED flag then
2839 * skip the delay, but if not then add the delay
2840 * of the enable property.
2841 */
2842 if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2843 cbdata.sc_flags |= SCI_DELAYENABLE;
2844 }
2845
2846 if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2847 != UU_WALK_NEXT)
2848 return (cbdata.sc_err);
2849 }
2850
2851 return (0);
2852 }
2853
2854 /*
2855 * Report the reasons why we can't upgrade pg2 to pg1.
2856 */
2857 static void
2858 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2859 int new)
2860 {
2861 property_t *p1, *p2;
2862
2863 assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2864
2865 if (!pg_attrs_equal(pg1, pg2, fmri, new))
2866 return;
2867
2868 for (p1 = uu_list_first(pg1->sc_pgroup_props);
2869 p1 != NULL;
2870 p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2871 p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2872 if (p2 != NULL) {
2873 (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2874 new);
2875 continue;
2876 }
2877
2878 if (new)
2879 warn(gettext("Conflict upgrading %s (new property "
2880 "group \"%s\" is missing property \"%s\").\n"),
2881 fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2882 else
2883 warn(gettext("Conflict upgrading %s (property "
2884 "\"%s/%s\" is missing).\n"), fmri,
2885 pg1->sc_pgroup_name, p1->sc_property_name);
2886 }
2887
2888 /*
2889 * Since pg1 should be from the manifest, any properties in pg2 which
2890 * aren't in pg1 shouldn't be reported as conflicts.
2891 */
2892 }
2893
2894 /*
2895 * Add transaction entries to tx which will upgrade cur's pg according to old
2896 * & new.
2897 *
2898 * Returns
2899 * 0 - success
2900 * EINVAL - new has a property with an invalid name or value (message emitted)
2901 * ENOMEM - out of memory
2902 */
2903 static int
2904 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2905 pgroup_t *cur, int speak, const char *fmri)
2906 {
2907 property_t *p, *new_p, *cur_p;
2908 scf_transaction_entry_t *e;
2909 int r;
2910 int is_general;
2911 int is_protected;
2912
2913 if (uu_list_walk(new->sc_pgroup_props, clear_int,
2914 (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2915 bad_error("uu_list_walk", uu_error());
2916
2917 is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2918
2919 for (p = uu_list_first(old->sc_pgroup_props);
2920 p != NULL;
2921 p = uu_list_next(old->sc_pgroup_props, p)) {
2922 /* p is a property in the old property group. */
2923
2924 /* Protect live properties. */
2925 is_protected = 0;
2926 if (is_general) {
2927 if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2928 0 ||
2929 strcmp(p->sc_property_name,
2930 SCF_PROPERTY_RESTARTER) == 0)
2931 is_protected = 1;
2932 }
2933
2934 /* Look for the same property in the new properties. */
2935 new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2936 if (new_p != NULL) {
2937 new_p->sc_seen = 1;
2938
2939 /*
2940 * If the new property is the same as the old, don't do
2941 * anything (leave any user customizations).
2942 */
2943 if (prop_equal(p, new_p, NULL, NULL, 0))
2944 continue;
2945
2946 if (new_p->sc_property_override)
2947 goto upgrade;
2948 }
2949
2950 cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2951 if (cur_p == NULL) {
2952 /*
2953 * p has been deleted from the repository. If we were
2954 * going to delete it anyway, do nothing. Otherwise
2955 * report a conflict.
2956 */
2957 if (new_p == NULL)
2958 continue;
2959
2960 if (is_protected)
2961 continue;
2962
2963 warn(gettext("Conflict upgrading %s "
2964 "(property \"%s/%s\" is missing).\n"), fmri,
2965 old->sc_pgroup_name, p->sc_property_name);
2966 continue;
2967 }
2968
2969 if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2970 /*
2971 * Conflict. Don't warn if the property is already the
2972 * way we want it, though.
2973 */
2974 if (is_protected)
2975 continue;
2976
2977 if (new_p == NULL)
2978 (void) prop_equal(p, cur_p, fmri,
2979 old->sc_pgroup_name, 0);
2980 else
2981 (void) prop_equal(cur_p, new_p, fmri,
2982 old->sc_pgroup_name, 0);
2983 continue;
2984 }
2985
2986 if (is_protected) {
2987 if (speak)
2988 warn(gettext("%s: Refusing to upgrade "
2989 "\"%s/%s\" (live property).\n"), fmri,
2990 old->sc_pgroup_name, p->sc_property_name);
2991 continue;
2992 }
2993
2994 upgrade:
2995 /* p hasn't been customized in the repository. Upgrade it. */
2996 if (new_p == NULL) {
2997 /* p was deleted. Delete from cur if unchanged. */
2998 if (speak)
2999 warn(gettext(
3000 "%s: Deleting property \"%s/%s\".\n"),
3001 fmri, old->sc_pgroup_name,
3002 p->sc_property_name);
3003
3004 e = scf_entry_create(g_hndl);
3005 if (e == NULL)
3006 return (ENOMEM);
3007
3008 if (scf_transaction_property_delete(tx, e,
3009 p->sc_property_name) != 0) {
3010 switch (scf_error()) {
3011 case SCF_ERROR_DELETED:
3012 scf_entry_destroy(e);
3013 return (ECANCELED);
3014
3015 case SCF_ERROR_CONNECTION_BROKEN:
3016 scf_entry_destroy(e);
3017 return (ECONNABORTED);
3018
3019 case SCF_ERROR_NOT_FOUND:
3020 /*
3021 * This can happen if cur is from the
3022 * running snapshot (and it differs
3023 * from the live properties).
3024 */
3025 scf_entry_destroy(e);
3026 break;
3027
3028 case SCF_ERROR_HANDLE_MISMATCH:
3029 case SCF_ERROR_NOT_BOUND:
3030 case SCF_ERROR_NOT_SET:
3031 case SCF_ERROR_INVALID_ARGUMENT:
3032 default:
3033 bad_error(
3034 "scf_transaction_property_delete",
3035 scf_error());
3036 }
3037 }
3038 } else {
3039 scf_callback_t ctx;
3040
3041 if (speak)
3042 warn(gettext(
3043 "%s: Upgrading property \"%s/%s\".\n"),
3044 fmri, old->sc_pgroup_name,
3045 p->sc_property_name);
3046
3047 ctx.sc_handle = g_hndl;
3048 ctx.sc_trans = tx;
3049 ctx.sc_flags = 0;
3050
3051 r = lscf_property_import(new_p, &ctx);
3052 if (r != UU_WALK_NEXT) {
3053 if (r != UU_WALK_ERROR)
3054 bad_error("lscf_property_import", r);
3055 return (EINVAL);
3056 }
3057 }
3058 }
3059
3060 /* Go over the properties which were added. */
3061 for (new_p = uu_list_first(new->sc_pgroup_props);
3062 new_p != NULL;
3063 new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
3064 if (new_p->sc_seen)
3065 continue;
3066
3067 /* This is a new property. */
3068 cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
3069 if (cur_p == NULL) {
3070 scf_callback_t ctx;
3071
3072 ctx.sc_handle = g_hndl;
3073 ctx.sc_trans = tx;
3074 ctx.sc_flags = 0;
3075
3076 r = lscf_property_import(new_p, &ctx);
3077 if (r != UU_WALK_NEXT) {
3078 if (r != UU_WALK_ERROR)
3079 bad_error("lscf_property_import", r);
3080 return (EINVAL);
3081 }
3082 continue;
3083 }
3084
3085 /*
3086 * Report a conflict if the new property differs from the
3087 * current one. Unless it's general/enabled, since that's
3088 * never in the last-import snapshot.
3089 */
3090 if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
3091 0 &&
3092 strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
3093 continue;
3094
3095 (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
3096 }
3097
3098 return (0);
3099 }
3100
3101 /*
3102 * Upgrade pg according to old & new.
3103 *
3104 * Returns
3105 * 0 - success
3106 * ECONNABORTED - repository connection broken
3107 * ENOMEM - out of memory
3108 * ENOSPC - svc.configd is out of resources
3109 * ECANCELED - pg was deleted
3110 * EPERM - couldn't modify pg (permission denied)
3111 * EROFS - couldn't modify pg (backend read-only)
3112 * EACCES - couldn't modify pg (backend access denied)
3113 * EINVAL - new has a property with invalid name or value (error printed)
3114 * EBUSY - pg changed unexpectedly
3115 */
3116 static int
3117 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
3118 pgroup_t *new, int speak, const char *fmri)
3119 {
3120 int r;
3121
3122 if (scf_transaction_start(imp_tx, pg) != 0) {
3123 switch (scf_error()) {
3124 case SCF_ERROR_CONNECTION_BROKEN:
3125 case SCF_ERROR_DELETED:
3126 case SCF_ERROR_PERMISSION_DENIED:
3127 case SCF_ERROR_BACKEND_READONLY:
3128 case SCF_ERROR_BACKEND_ACCESS:
3129 return (scferror2errno(scf_error()));
3130
3131 case SCF_ERROR_HANDLE_MISMATCH:
3132 case SCF_ERROR_IN_USE:
3133 case SCF_ERROR_NOT_BOUND:
3134 case SCF_ERROR_NOT_SET:
3135 default:
3136 bad_error("scf_transaction_start", scf_error());
3137 }
3138 }
3139
3140 r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
3141 switch (r) {
3142 case 0:
3143 break;
3144
3145 case EINVAL:
3146 case ENOMEM:
3147 scf_transaction_destroy_children(imp_tx);
3148 return (r);
3149
3150 default:
3151 bad_error("add_upgrade_entries", r);
3152 }
3153
3154 r = scf_transaction_commit(imp_tx);
3155
3156 scf_transaction_destroy_children(imp_tx);
3157
3158 switch (r) {
3159 case 1:
3160 break;
3161
3162 case 0:
3163 return (EBUSY);
3164
3165 case -1:
3166 switch (scf_error()) {
3167 case SCF_ERROR_CONNECTION_BROKEN:
3168 case SCF_ERROR_NO_RESOURCES:
3169 case SCF_ERROR_PERMISSION_DENIED:
3170 case SCF_ERROR_BACKEND_READONLY:
3171 case SCF_ERROR_BACKEND_ACCESS:
3172 case SCF_ERROR_DELETED:
3173 return (scferror2errno(scf_error()));
3174
3175 case SCF_ERROR_NOT_BOUND:
3176 case SCF_ERROR_INVALID_ARGUMENT:
3177 case SCF_ERROR_NOT_SET:
3178 default:
3179 bad_error("scf_transaction_commit", scf_error());
3180 }
3181
3182 default:
3183 bad_error("scf_transaction_commit", r);
3184 }
3185
3186 return (0);
3187 }
3188
3189 /*
3190 * Compares two entity FMRIs. Returns
3191 *
3192 * 1 - equal
3193 * 0 - not equal
3194 * -1 - f1 is invalid or not an entity
3195 * -2 - f2 is invalid or not an entity
3196 */
3197 static int
3198 fmri_equal(const char *f1, const char *f2)
3199 {
3200 int r;
3201 const char *s1, *i1, *pg1;
3202 const char *s2, *i2, *pg2;
3203
3204 if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3205 return (-1);
3206 if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
3207 return (-1);
3208
3209 if (s1 == NULL || pg1 != NULL)
3210 return (-1);
3211
3212 if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3213 return (-2);
3214 if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
3215 return (-2);
3216
3217 if (s2 == NULL || pg2 != NULL)
3218 return (-2);
3219
3220 r = strcmp(s1, s2);
3221 if (r != 0)
3222 return (0);
3223
3224 if (i1 == NULL && i2 == NULL)
3225 return (1);
3226
3227 if (i1 == NULL || i2 == NULL)
3228 return (0);
3229
3230 return (strcmp(i1, i2) == 0);
3231 }
3232
3233 /*
3234 * Import a dependent by creating a dependency property group in the dependent
3235 * entity. If lcbdata->sc_trans is set, assume it's been started on the
3236 * dependents pg, and add an entry to create a new property for this
3237 * dependent. Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3238 *
3239 * On success, returns UU_WALK_NEXT. On error, returns UU_WALK_ERROR and sets
3240 * lcbdata->sc_err to
3241 * ECONNABORTED - repository connection broken
3242 * ENOMEM - out of memory
3243 * ENOSPC - configd is out of resources
3244 * EINVAL - target is invalid (error printed)
3245 * - target is not an entity (error printed)
3246 * - dependent has invalid name (error printed)
3247 * - invalid property name (error printed)
3248 * - invalid value (error printed)
3249 * - scope of target does not exist (error printed)
3250 * EPERM - couldn't create target (permission denied) (error printed)
3251 * - couldn't create dependency pg (permission denied) (error printed)
3252 * - couldn't modify dependency pg (permission denied) (error printed)
3253 * EROFS - couldn't create target (repository read-only)
3254 * - couldn't create dependency pg (repository read-only)
3255 * EACCES - couldn't create target (backend access denied)
3256 * - couldn't create dependency pg (backend access denied)
3257 * ECANCELED - sc_trans's pg was deleted
3258 * EALREADY - property for dependent already exists in sc_trans's pg
3259 * EEXIST - dependency pg already exists in target (error printed)
3260 * EBUSY - target deleted (error printed)
3261 * - property group changed during import (error printed)
3262 */
3263 static int
3264 lscf_dependent_import(void *a1, void *pvt)
3265 {
3266 pgroup_t *pgrp = a1;
3267 scf_callback_t *lcbdata = pvt;
3268
3269 int isservice;
3270 int ret;
3271 scf_transaction_entry_t *e;
3272 scf_value_t *val;
3273 scf_callback_t dependent_cbdata;
3274 scf_error_t scfe;
3275
3276 /*
3277 * Decode the FMRI into dependent_cbdata->sc_parent. Do it here so if
3278 * it's invalid, we fail before modifying the repository.
3279 */
3280 scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3281 &dependent_cbdata.sc_parent, &isservice);
3282 switch (scfe) {
3283 case SCF_ERROR_NONE:
3284 break;
3285
3286 case SCF_ERROR_NO_MEMORY:
3287 return (stash_scferror_err(lcbdata, scfe));
3288
3289 case SCF_ERROR_INVALID_ARGUMENT:
3290 semerr(gettext("The FMRI for the \"%s\" dependent is "
3291 "invalid.\n"), pgrp->sc_pgroup_name);
3292 return (stash_scferror_err(lcbdata, scfe));
3293
3294 case SCF_ERROR_CONSTRAINT_VIOLATED:
3295 semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3296 "specifies neither a service nor an instance.\n"),
3297 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3298 return (stash_scferror_err(lcbdata, scfe));
3299
3300 case SCF_ERROR_NOT_FOUND:
3301 scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3302 &dependent_cbdata.sc_parent, &isservice);
3303 switch (scfe) {
3304 case SCF_ERROR_NONE:
3305 break;
3306
3307 case SCF_ERROR_NO_MEMORY:
3308 case SCF_ERROR_BACKEND_READONLY:
3309 case SCF_ERROR_BACKEND_ACCESS:
3310 return (stash_scferror_err(lcbdata, scfe));
3311
3312 case SCF_ERROR_NOT_FOUND:
3313 semerr(gettext("The scope in FMRI \"%s\" for the "
3314 "\"%s\" dependent does not exist.\n"),
3315 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3316 lcbdata->sc_err = EINVAL;
3317 return (UU_WALK_ERROR);
3318
3319 case SCF_ERROR_PERMISSION_DENIED:
3320 warn(gettext(
3321 "Could not create %s (permission denied).\n"),
3322 pgrp->sc_pgroup_fmri);
3323 return (stash_scferror_err(lcbdata, scfe));
3324
3325 case SCF_ERROR_INVALID_ARGUMENT:
3326 case SCF_ERROR_CONSTRAINT_VIOLATED:
3327 default:
3328 bad_error("create_entity", scfe);
3329 }
3330 break;
3331
3332 default:
3333 bad_error("fmri_to_entity", scfe);
3334 }
3335
3336 if (lcbdata->sc_trans != NULL) {
3337 e = scf_entry_create(lcbdata->sc_handle);
3338 if (e == NULL) {
3339 if (scf_error() != SCF_ERROR_NO_MEMORY)
3340 bad_error("scf_entry_create", scf_error());
3341
3342 entity_destroy(dependent_cbdata.sc_parent, isservice);
3343 return (stash_scferror(lcbdata));
3344 }
3345
3346 if (scf_transaction_property_new(lcbdata->sc_trans, e,
3347 pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
3348 switch (scf_error()) {
3349 case SCF_ERROR_INVALID_ARGUMENT:
3350 warn(gettext("Dependent of %s has invalid name "
3351 "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
3352 pgrp->sc_pgroup_name);
3353 /* FALLTHROUGH */
3354
3355 case SCF_ERROR_DELETED:
3356 case SCF_ERROR_CONNECTION_BROKEN:
3357 scf_entry_destroy(e);
3358 entity_destroy(dependent_cbdata.sc_parent,
3359 isservice);
3360 return (stash_scferror(lcbdata));
3361
3362 case SCF_ERROR_EXISTS:
3363 scf_entry_destroy(e);
3364 entity_destroy(dependent_cbdata.sc_parent,
3365 isservice);
3366 lcbdata->sc_err = EALREADY;
3367 return (UU_WALK_ERROR);
3368
3369 case SCF_ERROR_NOT_BOUND:
3370 case SCF_ERROR_HANDLE_MISMATCH:
3371 case SCF_ERROR_NOT_SET:
3372 default:
3373 bad_error("scf_transaction_property_new",
3374 scf_error());
3375 }
3376 }
3377
3378 val = scf_value_create(lcbdata->sc_handle);
3379 if (val == NULL) {
3380 if (scf_error() != SCF_ERROR_NO_MEMORY)
3381 bad_error("scf_value_create", scf_error());
3382
3383 entity_destroy(dependent_cbdata.sc_parent, isservice);
3384 return (stash_scferror(lcbdata));
3385 }
3386
3387 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
3388 pgrp->sc_pgroup_fmri) != 0)
3389 /* invalid should have been caught above */
3390 bad_error("scf_value_set_from_string", scf_error());
3391
3392 if (scf_entry_add_value(e, val) != 0)
3393 bad_error("scf_entry_add_value", scf_error());
3394 }
3395
3396 /* Add the property group to the target entity. */
3397
3398 dependent_cbdata.sc_handle = lcbdata->sc_handle;
3399 dependent_cbdata.sc_flags = lcbdata->sc_flags;
3400 dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
3401 dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
3402
3403 ret = entity_pgroup_import(pgrp, &dependent_cbdata);
3404
3405 entity_destroy(dependent_cbdata.sc_parent, isservice);
3406
3407 if (ret == UU_WALK_NEXT)
3408 return (ret);
3409
3410 if (ret != UU_WALK_ERROR)
3411 bad_error("entity_pgroup_import", ret);
3412
3413 switch (dependent_cbdata.sc_err) {
3414 case ECANCELED:
3415 warn(gettext("%s deleted unexpectedly.\n"),
3416 pgrp->sc_pgroup_fmri);
3417 lcbdata->sc_err = EBUSY;
3418 break;
3419
3420 case EEXIST:
3421 warn(gettext("Could not create \"%s\" dependency in %s "
3422 "(already exists).\n"), pgrp->sc_pgroup_name,
3423 pgrp->sc_pgroup_fmri);
3424 /* FALLTHROUGH */
3425
3426 default:
3427 lcbdata->sc_err = dependent_cbdata.sc_err;
3428 }
3429
3430 return (UU_WALK_ERROR);
3431 }
3432
3433 static int upgrade_dependent(const scf_property_t *, const entity_t *,
3434 const scf_snaplevel_t *, scf_transaction_t *);
3435 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
3436 const pgroup_t *);
3437
3438 /*
3439 * Upgrade uncustomized dependents of ent to those specified in ient. Read
3440 * the current dependent targets from running (the snaplevel of a running
3441 * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3442 * scf_instance_t * according to ient, otherwise). Draw the ancestral
3443 * dependent targets and dependency properties from li_dpts_pg (the
3444 * "dependents" property group in snpl) and snpl (the snaplevel which
3445 * corresponds to ent in a last-import snapshot). If li_dpts_pg is NULL, then
3446 * snpl doesn't have a "dependents" property group, and any dependents in ient
3447 * are new.
3448 *
3449 * Returns
3450 * 0 - success
3451 * ECONNABORTED - repository connection broken
3452 * ENOMEM - out of memory
3453 * ENOSPC - configd is out of resources
3454 * ECANCELED - ent was deleted
3455 * ENODEV - the entity containing li_dpts_pg was deleted
3456 * EPERM - could not modify dependents pg (permission denied) (error printed)
3457 * - couldn't upgrade dependent (permission denied) (error printed)
3458 * - couldn't create dependent (permission denied) (error printed)
3459 * EROFS - could not modify dependents pg (repository read-only)
3460 * - couldn't upgrade dependent (repository read-only)
3461 * - couldn't create dependent (repository read-only)
3462 * EACCES - could not modify dependents pg (backend access denied)
3463 * - could not upgrade dependent (backend access denied)
3464 * - could not create dependent (backend access denied)
3465 * EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3466 * - dependent target deleted (error printed)
3467 * - dependent pg changed (error printed)
3468 * EINVAL - new dependent is invalid (error printed)
3469 * EBADF - snpl is corrupt (error printed)
3470 * - snpl has corrupt pg (error printed)
3471 * - dependency pg in target is corrupt (error printed)
3472 * - target has corrupt snapshot (error printed)
3473 * EEXIST - dependency pg already existed in target service (error printed)
3474 */
3475 static int
3476 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
3477 const scf_snaplevel_t *snpl, const entity_t *ient,
3478 const scf_snaplevel_t *running, void *ent)
3479 {
3480 pgroup_t *new_dpt_pgroup;
3481 scf_callback_t cbdata;
3482 int r, unseen, tx_started = 0;
3483 int have_cur_depts;
3484
3485 const char * const dependents = "dependents";
3486
3487 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3488
3489 if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
3490 /* Nothing to do. */
3491 return (0);
3492
3493 /* Fetch the current version of the "dependents" property group. */
3494 have_cur_depts = 1;
3495 if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
3496 switch (scf_error()) {
3497 case SCF_ERROR_NOT_FOUND:
3498 break;
3499
3500 case SCF_ERROR_DELETED:
3501 case SCF_ERROR_CONNECTION_BROKEN:
3502 return (scferror2errno(scf_error()));
3503
3504 case SCF_ERROR_NOT_SET:
3505 case SCF_ERROR_INVALID_ARGUMENT:
3506 case SCF_ERROR_HANDLE_MISMATCH:
3507 case SCF_ERROR_NOT_BOUND:
3508 default:
3509 bad_error("entity_get_pg", scf_error());
3510 }
3511
3512 have_cur_depts = 0;
3513 }
3514
3515 /* Fetch the running version of the "dependents" property group. */
3516 ud_run_dpts_pg_set = 0;
3517 if (running != NULL)
3518 r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
3519 else
3520 r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
3521 if (r == 0) {
3522 ud_run_dpts_pg_set = 1;
3523 } else {
3524 switch (scf_error()) {
3525 case SCF_ERROR_NOT_FOUND:
3526 break;
3527
3528 case SCF_ERROR_DELETED:
3529 case SCF_ERROR_CONNECTION_BROKEN:
3530 return (scferror2errno(scf_error()));
3531
3532 case SCF_ERROR_NOT_SET:
3533 case SCF_ERROR_INVALID_ARGUMENT:
3534 case SCF_ERROR_HANDLE_MISMATCH:
3535 case SCF_ERROR_NOT_BOUND:
3536 default:
3537 bad_error(running ? "scf_snaplevel_get_pg" :
3538 "entity_get_pg", scf_error());
3539 }
3540 }
3541
3542 /*
3543 * Clear the seen fields of the dependents, so we can tell which ones
3544 * are new.
3545 */
3546 if (uu_list_walk(ient->sc_dependents, clear_int,
3547 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3548 bad_error("uu_list_walk", uu_error());
3549
3550 if (li_dpts_pg != NULL) {
3551 /*
3552 * Each property in li_dpts_pg represents a dependent tag in
3553 * the old manifest. For each, call upgrade_dependent(),
3554 * which will change ud_cur_depts_pg or dependencies in other
3555 * services as appropriate. Note (a) that changes to
3556 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3557 * made en masse, and (b) it's ok if the entity doesn't have
3558 * a current version of the "dependents" property group,
3559 * because we'll just consider all dependents as customized
3560 * (by being deleted).
3561 */
3562
3563 if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3564 switch (scf_error()) {
3565 case SCF_ERROR_DELETED:
3566 return (ENODEV);
3567
3568 case SCF_ERROR_CONNECTION_BROKEN:
3569 return (ECONNABORTED);
3570
3571 case SCF_ERROR_HANDLE_MISMATCH:
3572 case SCF_ERROR_NOT_BOUND:
3573 case SCF_ERROR_NOT_SET:
3574 default:
3575 bad_error("scf_iter_pg_properties",
3576 scf_error());
3577 }
3578 }
3579
3580 if (have_cur_depts &&
3581 scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3582 switch (scf_error()) {
3583 case SCF_ERROR_BACKEND_ACCESS:
3584 case SCF_ERROR_BACKEND_READONLY:
3585 case SCF_ERROR_CONNECTION_BROKEN:
3586 return (scferror2errno(scf_error()));
3587
3588 case SCF_ERROR_DELETED:
3589 warn(emsg_pg_deleted, ient->sc_fmri,
3590 dependents);
3591 return (EBUSY);
3592
3593 case SCF_ERROR_PERMISSION_DENIED:
3594 warn(emsg_pg_mod_perm, dependents,
3595 ient->sc_fmri);
3596 return (scferror2errno(scf_error()));
3597
3598 case SCF_ERROR_HANDLE_MISMATCH:
3599 case SCF_ERROR_IN_USE:
3600 case SCF_ERROR_NOT_BOUND:
3601 case SCF_ERROR_NOT_SET:
3602 default:
3603 bad_error("scf_transaction_start", scf_error());
3604 }
3605 }
3606 tx_started = have_cur_depts;
3607
3608 for (;;) {
3609 r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3610 if (r == 0)
3611 break;
3612 if (r == 1) {
3613 r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3614 tx_started ? ud_tx : NULL);
3615 switch (r) {
3616 case 0:
3617 continue;
3618
3619 case ECONNABORTED:
3620 case ENOMEM:
3621 case ENOSPC:
3622 case EBADF:
3623 case EBUSY:
3624 case EINVAL:
3625 case EPERM:
3626 case EROFS:
3627 case EACCES:
3628 case EEXIST:
3629 break;
3630
3631 case ECANCELED:
3632 r = ENODEV;
3633 break;
3634
3635 default:
3636 bad_error("upgrade_dependent", r);
3637 }
3638
3639 if (tx_started)
3640 scf_transaction_destroy_children(ud_tx);
3641 return (r);
3642 }
3643 if (r != -1)
3644 bad_error("scf_iter_next_property", r);
3645
3646 switch (scf_error()) {
3647 case SCF_ERROR_DELETED:
3648 r = ENODEV;
3649 break;
3650
3651 case SCF_ERROR_CONNECTION_BROKEN:
3652 r = ECONNABORTED;
3653 break;
3654
3655 case SCF_ERROR_NOT_SET:
3656 case SCF_ERROR_INVALID_ARGUMENT:
3657 case SCF_ERROR_NOT_BOUND:
3658 case SCF_ERROR_HANDLE_MISMATCH:
3659 default:
3660 bad_error("scf_iter_next_property",
3661 scf_error());
3662 }
3663
3664 if (tx_started)
3665 scf_transaction_destroy_children(ud_tx);
3666 return (r);
3667 }
3668 }
3669
3670 /* import unseen dependents */
3671 unseen = 0;
3672 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3673 new_dpt_pgroup != NULL;
3674 new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3675 new_dpt_pgroup)) {
3676 if (!new_dpt_pgroup->sc_pgroup_seen) {
3677 unseen = 1;
3678 break;
3679 }
3680 }
3681
3682 /* If there are none, exit early. */
3683 if (unseen == 0)
3684 goto commit;
3685
3686 /* Set up for lscf_dependent_import() */
3687 cbdata.sc_handle = g_hndl;
3688 cbdata.sc_parent = ent;
3689 cbdata.sc_service = issvc;
3690 cbdata.sc_flags = 0;
3691
3692 if (!have_cur_depts) {
3693 /*
3694 * We have new dependents to import, so we need a "dependents"
3695 * property group.
3696 */
3697 if (issvc)
3698 r = scf_service_add_pg(ent, dependents,
3699 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3700 else
3701 r = scf_instance_add_pg(ent, dependents,
3702 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3703 if (r != 0) {
3704 switch (scf_error()) {
3705 case SCF_ERROR_DELETED:
3706 case SCF_ERROR_CONNECTION_BROKEN:
3707 case SCF_ERROR_BACKEND_READONLY:
3708 case SCF_ERROR_BACKEND_ACCESS:
3709 case SCF_ERROR_NO_RESOURCES:
3710 return (scferror2errno(scf_error()));
3711
3712 case SCF_ERROR_EXISTS:
3713 warn(emsg_pg_added, ient->sc_fmri, dependents);
3714 return (EBUSY);
3715
3716 case SCF_ERROR_PERMISSION_DENIED:
3717 warn(emsg_pg_add_perm, dependents,
3718 ient->sc_fmri);
3719 return (scferror2errno(scf_error()));
3720
3721 case SCF_ERROR_NOT_BOUND:
3722 case SCF_ERROR_HANDLE_MISMATCH:
3723 case SCF_ERROR_INVALID_ARGUMENT:
3724 case SCF_ERROR_NOT_SET:
3725 default:
3726 bad_error("scf_service_add_pg", scf_error());
3727 }
3728 }
3729 }
3730
3731 cbdata.sc_trans = ud_tx;
3732
3733 if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3734 switch (scf_error()) {
3735 case SCF_ERROR_CONNECTION_BROKEN:
3736 case SCF_ERROR_BACKEND_ACCESS:
3737 case SCF_ERROR_BACKEND_READONLY:
3738 return (scferror2errno(scf_error()));
3739
3740 case SCF_ERROR_DELETED:
3741 warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3742 return (EBUSY);
3743
3744 case SCF_ERROR_PERMISSION_DENIED:
3745 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3746 return (scferror2errno(scf_error()));
3747
3748 case SCF_ERROR_HANDLE_MISMATCH:
3749 case SCF_ERROR_IN_USE:
3750 case SCF_ERROR_NOT_BOUND:
3751 case SCF_ERROR_NOT_SET:
3752 default:
3753 bad_error("scf_transaction_start", scf_error());
3754 }
3755 }
3756 tx_started = 1;
3757
3758 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3759 new_dpt_pgroup != NULL;
3760 new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3761 new_dpt_pgroup)) {
3762 if (new_dpt_pgroup->sc_pgroup_seen)
3763 continue;
3764
3765 if (ud_run_dpts_pg_set) {
3766 /*
3767 * If the dependent is already there, then we have
3768 * a conflict.
3769 */
3770 if (scf_pg_get_property(ud_run_dpts_pg,
3771 new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3772 r = handle_dependent_conflict(ient, ud_prop,
3773 new_dpt_pgroup);
3774 switch (r) {
3775 case 0:
3776 continue;
3777
3778 case ECONNABORTED:
3779 case ENOMEM:
3780 case EBUSY:
3781 case EBADF:
3782 case EINVAL:
3783 scf_transaction_destroy_children(ud_tx);
3784 return (r);
3785
3786 default:
3787 bad_error("handle_dependent_conflict",
3788 r);
3789 }
3790 } else {
3791 switch (scf_error()) {
3792 case SCF_ERROR_NOT_FOUND:
3793 break;
3794
3795 case SCF_ERROR_INVALID_ARGUMENT:
3796 warn(emsg_fmri_invalid_pg_name,
3797 ient->sc_fmri,
3798 new_dpt_pgroup->sc_pgroup_name);
3799 scf_transaction_destroy_children(ud_tx);
3800 return (EINVAL);
3801
3802 case SCF_ERROR_DELETED:
3803 warn(emsg_pg_deleted, ient->sc_fmri,
3804 new_dpt_pgroup->sc_pgroup_name);
3805 scf_transaction_destroy_children(ud_tx);
3806 return (EBUSY);
3807
3808 case SCF_ERROR_CONNECTION_BROKEN:
3809 scf_transaction_destroy_children(ud_tx);
3810 return (ECONNABORTED);
3811
3812 case SCF_ERROR_NOT_BOUND:
3813 case SCF_ERROR_HANDLE_MISMATCH:
3814 case SCF_ERROR_NOT_SET:
3815 default:
3816 bad_error("scf_pg_get_property",
3817 scf_error());
3818 }
3819 }
3820 }
3821
3822 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3823 if (r != UU_WALK_NEXT) {
3824 if (r != UU_WALK_ERROR)
3825 bad_error("lscf_dependent_import", r);
3826
3827 if (cbdata.sc_err == EALREADY) {
3828 /* Collisions were handled preemptively. */
3829 bad_error("lscf_dependent_import",
3830 cbdata.sc_err);
3831 }
3832
3833 scf_transaction_destroy_children(ud_tx);
3834 return (cbdata.sc_err);
3835 }
3836 }
3837
3838 commit:
3839 if (!tx_started)
3840 return (0);
3841
3842 r = scf_transaction_commit(ud_tx);
3843
3844 scf_transaction_destroy_children(ud_tx);
3845
3846 switch (r) {
3847 case 1:
3848 return (0);
3849
3850 case 0:
3851 warn(emsg_pg_changed, ient->sc_fmri, dependents);
3852 return (EBUSY);
3853
3854 case -1:
3855 break;
3856
3857 default:
3858 bad_error("scf_transaction_commit", r);
3859 }
3860
3861 switch (scf_error()) {
3862 case SCF_ERROR_CONNECTION_BROKEN:
3863 case SCF_ERROR_BACKEND_READONLY:
3864 case SCF_ERROR_BACKEND_ACCESS:
3865 case SCF_ERROR_NO_RESOURCES:
3866 return (scferror2errno(scf_error()));
3867
3868 case SCF_ERROR_DELETED:
3869 warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3870 return (EBUSY);
3871
3872 case SCF_ERROR_PERMISSION_DENIED:
3873 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3874 return (scferror2errno(scf_error()));
3875
3876 case SCF_ERROR_NOT_BOUND:
3877 case SCF_ERROR_INVALID_ARGUMENT:
3878 case SCF_ERROR_NOT_SET:
3879 default:
3880 bad_error("scf_transaction_destroy", scf_error());
3881 /* NOTREACHED */
3882 }
3883 }
3884
3885 /*
3886 * Used to add the manifests to the list of currently supported manifests.
3887 * We can modify the existing manifest list removing entries if the files
3888 * don't exist.
3889 *
3890 * Get the old list and the new file name
3891 * If the new file name is in the list return
3892 * If not then add the file to the list.
3893 * As we process the list check to see if the files in the old list exist
3894 * if not then remove the file from the list.
3895 * Commit the list of manifest file names.
3896 *
3897 */
3898 static int
3899 upgrade_manifestfiles(pgroup_t *pg, entity_t *ient,
3900 const scf_snaplevel_t *running, void *ent)
3901 {
3902 scf_propertygroup_t *ud_mfsts_pg = NULL;
3903 scf_property_t *ud_prop = NULL;
3904 scf_iter_t *ud_prop_iter;
3905 scf_value_t *fname_value;
3906 scf_callback_t cbdata;
3907 pgroup_t *mfst_pgroup;
3908 property_t *mfst_prop;
3909 property_t *old_prop;
3910 char *pname;
3911 char *fval;
3912 char *old_pname;
3913 char *old_fval;
3914 int no_upgrade_pg;
3915 int mfst_seen;
3916 int r;
3917
3918 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3919
3920 /*
3921 * This should always be the service base on the code
3922 * path, and the fact that the manifests pg is a service
3923 * level property group only.
3924 */
3925 ud_mfsts_pg = scf_pg_create(g_hndl);
3926 ud_prop = scf_property_create(g_hndl);
3927 ud_prop_iter = scf_iter_create(g_hndl);
3928 fname_value = scf_value_create(g_hndl);
3929
3930 /* Fetch the "manifests" property group */
3931 no_upgrade_pg = 0;
3932 r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3933 ud_mfsts_pg);
3934 if (r != 0) {
3935 switch (scf_error()) {
3936 case SCF_ERROR_NOT_FOUND:
3937 no_upgrade_pg = 1;
3938 break;
3939
3940 case SCF_ERROR_DELETED:
3941 case SCF_ERROR_CONNECTION_BROKEN:
3942 return (scferror2errno(scf_error()));
3943
3944 case SCF_ERROR_NOT_SET:
3945 case SCF_ERROR_INVALID_ARGUMENT:
3946 case SCF_ERROR_HANDLE_MISMATCH:
3947 case SCF_ERROR_NOT_BOUND:
3948 default:
3949 bad_error(running ? "scf_snaplevel_get_pg" :
3950 "entity_get_pg", scf_error());
3951 }
3952 }
3953
3954 if (no_upgrade_pg) {
3955 cbdata.sc_handle = g_hndl;
3956 cbdata.sc_parent = ent;
3957 cbdata.sc_service = issvc;
3958 cbdata.sc_flags = SCI_FORCE;
3959 cbdata.sc_source_fmri = ient->sc_fmri;
3960 cbdata.sc_target_fmri = ient->sc_fmri;
3961
3962 if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3963 return (cbdata.sc_err);
3964
3965 return (0);
3966 }
3967
3968 /* Fetch the new manifests property group */
3969 mfst_pgroup = internal_pgroup_find_or_create(ient,
3970 SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
3971 assert(mfst_pgroup != NULL);
3972
3973 if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3974 SCF_SUCCESS)
3975 return (-1);
3976
3977 if ((pname = malloc(MAXPATHLEN)) == NULL)
3978 return (ENOMEM);
3979 if ((fval = malloc(MAXPATHLEN)) == NULL) {
3980 free(pname);
3981 return (ENOMEM);
3982 }
3983
3984 while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
3985 mfst_seen = 0;
3986 if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
3987 continue;
3988
3989 for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
3990 mfst_prop != NULL;
3991 mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
3992 mfst_prop)) {
3993 if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
3994 mfst_seen = 1;
3995 }
3996 }
3997
3998 /*
3999 * If the manifest is not seen then add it to the new mfst
4000 * property list to get proccessed into the repo.
4001 */
4002 if (mfst_seen == 0) {
4003 /*
4004 * If we cannot get the value then there is no
4005 * reason to attempt to attach the value to
4006 * the property group
4007 */
4008 if (prop_get_val(ud_prop, fname_value) == 0 &&
4009 scf_value_get_astring(fname_value, fval,
4010 MAXPATHLEN) != -1) {
4011 old_pname = safe_strdup(pname);
4012 old_fval = safe_strdup(fval);
4013 old_prop = internal_property_create(old_pname,
4014 SCF_TYPE_ASTRING, 1, old_fval);
4015
4016 /*
4017 * Already checked to see if the property exists
4018 * in the group, and it does not.
4019 */
4020 (void) internal_attach_property(mfst_pgroup,
4021 old_prop);
4022 }
4023 }
4024 }
4025 free(pname);
4026 free(fval);
4027
4028 cbdata.sc_handle = g_hndl;
4029 cbdata.sc_parent = ent;
4030 cbdata.sc_service = issvc;
4031 cbdata.sc_flags = SCI_FORCE;
4032 cbdata.sc_source_fmri = ient->sc_fmri;
4033 cbdata.sc_target_fmri = ient->sc_fmri;
4034
4035 if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
4036 return (cbdata.sc_err);
4037
4038 return (r);
4039 }
4040
4041 /*
4042 * prop is taken to be a property in the "dependents" property group of snpl,
4043 * which is taken to be the snaplevel of a last-import snapshot corresponding
4044 * to ient. If prop is a valid dependents property, upgrade the dependent it
4045 * represents according to the repository & ient. If ud_run_dpts_pg_set is
4046 * true, then ud_run_dpts_pg is taken to be the "dependents" property group
4047 * of the entity ient represents (possibly in the running snapshot). If it
4048 * needs to be changed, an entry will be added to tx, if not NULL.
4049 *
4050 * Returns
4051 * 0 - success
4052 * ECONNABORTED - repository connection broken
4053 * ENOMEM - out of memory
4054 * ENOSPC - configd was out of resources
4055 * ECANCELED - snpl's entity was deleted
4056 * EINVAL - dependent target is invalid (error printed)
4057 * - dependent is invalid (error printed)
4058 * EBADF - snpl is corrupt (error printed)
4059 * - snpl has corrupt pg (error printed)
4060 * - dependency pg in target is corrupt (error printed)
4061 * - running snapshot in dependent is missing snaplevel (error printed)
4062 * EPERM - couldn't delete dependency pg (permission denied) (error printed)
4063 * - couldn't create dependent (permission denied) (error printed)
4064 * - couldn't modify dependent pg (permission denied) (error printed)
4065 * EROFS - couldn't delete dependency pg (repository read-only)
4066 * - couldn't create dependent (repository read-only)
4067 * EACCES - couldn't delete dependency pg (backend access denied)
4068 * - couldn't create dependent (backend access denied)
4069 * EBUSY - ud_run_dpts_pg was deleted (error printed)
4070 * - tx's pg was deleted (error printed)
4071 * - dependent pg was changed or deleted (error printed)
4072 * EEXIST - dependency pg already exists in new target (error printed)
4073 */
4074 static int
4075 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
4076 const scf_snaplevel_t *snpl, scf_transaction_t *tx)
4077 {
4078 pgroup_t pgrp;
4079 scf_type_t ty;
4080 pgroup_t *new_dpt_pgroup;
4081 pgroup_t *old_dpt_pgroup = NULL;
4082 pgroup_t *current_pg;
4083 pgroup_t *dpt;
4084 scf_callback_t cbdata;
4085 int tissvc;
4086 void *target_ent;
4087 scf_error_t serr;
4088 int r;
4089 scf_transaction_entry_t *ent;
4090
4091 const char * const cf_inval = gettext("Conflict upgrading %s "
4092 "(dependent \"%s\" has invalid dependents property).\n");
4093 const char * const cf_missing = gettext("Conflict upgrading %s "
4094 "(dependent \"%s\" is missing).\n");
4095 const char * const cf_newdpg = gettext("Conflict upgrading %s "
4096 "(dependent \"%s\" has new dependency property group).\n");
4097 const char * const cf_newtarg = gettext("Conflict upgrading %s "
4098 "(dependent \"%s\" has new target).\n");
4099 const char * const li_corrupt =
4100 gettext("%s: \"last-import\" snapshot is corrupt.\n");
4101 const char * const upgrading =
4102 gettext("%s: Upgrading dependent \"%s\".\n");
4103 const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
4104 "corrupt (missing snaplevel).\n");
4105
4106 if (scf_property_type(prop, &ty) != 0) {
4107 switch (scf_error()) {
4108 case SCF_ERROR_DELETED:
4109 case SCF_ERROR_CONNECTION_BROKEN:
4110 return (scferror2errno(scf_error()));
4111
4112 case SCF_ERROR_NOT_BOUND:
4113 case SCF_ERROR_NOT_SET:
4114 default:
4115 bad_error("scf_property_type", scf_error());
4116 }
4117 }
4118
4119 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4120 warn(li_corrupt, ient->sc_fmri);
4121 return (EBADF);
4122 }
4123
4124 /*
4125 * prop represents a dependent in the old manifest. It is named after
4126 * the dependent.
4127 */
4128 if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
4129 switch (scf_error()) {
4130 case SCF_ERROR_DELETED:
4131 case SCF_ERROR_CONNECTION_BROKEN:
4132 return (scferror2errno(scf_error()));
4133
4134 case SCF_ERROR_NOT_BOUND:
4135 case SCF_ERROR_NOT_SET:
4136 default:
4137 bad_error("scf_property_get_name", scf_error());
4138 }
4139 }
4140
4141 /* See if it's in the new manifest. */
4142 pgrp.sc_pgroup_name = ud_name;
4143 new_dpt_pgroup =
4144 uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
4145
4146 /* If it's not, delete it... if it hasn't been customized. */
4147 if (new_dpt_pgroup == NULL) {
4148 if (!ud_run_dpts_pg_set)
4149 return (0);
4150
4151 if (scf_property_get_value(prop, ud_val) != 0) {
4152 switch (scf_error()) {
4153 case SCF_ERROR_NOT_FOUND:
4154 case SCF_ERROR_CONSTRAINT_VIOLATED:
4155 warn(li_corrupt, ient->sc_fmri);
4156 return (EBADF);
4157
4158 case SCF_ERROR_DELETED:
4159 case SCF_ERROR_CONNECTION_BROKEN:
4160 return (scferror2errno(scf_error()));
4161
4162 case SCF_ERROR_HANDLE_MISMATCH:
4163 case SCF_ERROR_NOT_BOUND:
4164 case SCF_ERROR_NOT_SET:
4165 case SCF_ERROR_PERMISSION_DENIED:
4166 default:
4167 bad_error("scf_property_get_value",
4168 scf_error());
4169 }
4170 }
4171
4172 if (scf_value_get_as_string(ud_val, ud_oldtarg,
4173 max_scf_value_len + 1) < 0)
4174 bad_error("scf_value_get_as_string", scf_error());
4175
4176 if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
4177 0) {
4178 switch (scf_error()) {
4179 case SCF_ERROR_NOT_FOUND:
4180 return (0);
4181
4182 case SCF_ERROR_CONNECTION_BROKEN:
4183 return (scferror2errno(scf_error()));
4184
4185 case SCF_ERROR_DELETED:
4186 warn(emsg_pg_deleted, ient->sc_fmri,
4187 "dependents");
4188 return (EBUSY);
4189
4190 case SCF_ERROR_INVALID_ARGUMENT:
4191 case SCF_ERROR_NOT_BOUND:
4192 case SCF_ERROR_HANDLE_MISMATCH:
4193 case SCF_ERROR_NOT_SET:
4194 default:
4195 bad_error("scf_pg_get_property", scf_error());
4196 }
4197 }
4198 if (scf_property_get_value(ud_prop, ud_val) != 0) {
4199 switch (scf_error()) {
4200 case SCF_ERROR_NOT_FOUND:
4201 case SCF_ERROR_CONSTRAINT_VIOLATED:
4202 warn(cf_inval, ient->sc_fmri, ud_name);
4203 return (0);
4204
4205 case SCF_ERROR_DELETED:
4206 case SCF_ERROR_CONNECTION_BROKEN:
4207 return (scferror2errno(scf_error()));
4208
4209 case SCF_ERROR_HANDLE_MISMATCH:
4210 case SCF_ERROR_NOT_BOUND:
4211 case SCF_ERROR_NOT_SET:
4212 case SCF_ERROR_PERMISSION_DENIED:
4213 default:
4214 bad_error("scf_property_get_value",
4215 scf_error());
4216 }
4217 }
4218
4219 ty = scf_value_type(ud_val);
4220 assert(ty != SCF_TYPE_INVALID);
4221 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4222 warn(cf_inval, ient->sc_fmri, ud_name);
4223 return (0);
4224 }
4225
4226 if (scf_value_get_as_string(ud_val, ud_ctarg,
4227 max_scf_value_len + 1) < 0)
4228 bad_error("scf_value_get_as_string", scf_error());
4229
4230 r = fmri_equal(ud_ctarg, ud_oldtarg);
4231 switch (r) {
4232 case 1:
4233 break;
4234
4235 case 0:
4236 case -1: /* warn? */
4237 warn(cf_newtarg, ient->sc_fmri, ud_name);
4238 return (0);
4239
4240 case -2:
4241 warn(li_corrupt, ient->sc_fmri);
4242 return (EBADF);
4243
4244 default:
4245 bad_error("fmri_equal", r);
4246 }
4247
4248 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4249 switch (scf_error()) {
4250 case SCF_ERROR_NOT_FOUND:
4251 warn(li_corrupt, ient->sc_fmri);
4252 return (EBADF);
4253
4254 case SCF_ERROR_DELETED:
4255 case SCF_ERROR_CONNECTION_BROKEN:
4256 return (scferror2errno(scf_error()));
4257
4258 case SCF_ERROR_NOT_BOUND:
4259 case SCF_ERROR_HANDLE_MISMATCH:
4260 case SCF_ERROR_INVALID_ARGUMENT:
4261 case SCF_ERROR_NOT_SET:
4262 default:
4263 bad_error("scf_snaplevel_get_pg", scf_error());
4264 }
4265 }
4266
4267 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4268 snap_lastimport);
4269 switch (r) {
4270 case 0:
4271 break;
4272
4273 case ECANCELED:
4274 case ECONNABORTED:
4275 case ENOMEM:
4276 case EBADF:
4277 return (r);
4278
4279 case EACCES:
4280 default:
4281 bad_error("load_pg", r);
4282 }
4283
4284 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4285 switch (serr) {
4286 case SCF_ERROR_NONE:
4287 break;
4288
4289 case SCF_ERROR_NO_MEMORY:
4290 internal_pgroup_free(old_dpt_pgroup);
4291 return (ENOMEM);
4292
4293 case SCF_ERROR_NOT_FOUND:
4294 internal_pgroup_free(old_dpt_pgroup);
4295 goto delprop;
4296
4297 case SCF_ERROR_CONSTRAINT_VIOLATED: /* caught above */
4298 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
4299 default:
4300 bad_error("fmri_to_entity", serr);
4301 }
4302
4303 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4304 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4305 switch (r) {
4306 case 0:
4307 break;
4308
4309 case ECONNABORTED:
4310 internal_pgroup_free(old_dpt_pgroup);
4311 return (r);
4312
4313 case ECANCELED:
4314 case ENOENT:
4315 internal_pgroup_free(old_dpt_pgroup);
4316 goto delprop;
4317
4318 case EBADF:
4319 warn(r_no_lvl, ud_ctarg);
4320 internal_pgroup_free(old_dpt_pgroup);
4321 return (r);
4322
4323 case EINVAL:
4324 default:
4325 bad_error("entity_get_running_pg", r);
4326 }
4327
4328 /* load it */
4329 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4330 switch (r) {
4331 case 0:
4332 break;
4333
4334 case ECANCELED:
4335 internal_pgroup_free(old_dpt_pgroup);
4336 goto delprop;
4337
4338 case ECONNABORTED:
4339 case ENOMEM:
4340 case EBADF:
4341 internal_pgroup_free(old_dpt_pgroup);
4342 return (r);
4343
4344 case EACCES:
4345 default:
4346 bad_error("load_pg", r);
4347 }
4348
4349 /* compare property groups */
4350 if (!pg_equal(old_dpt_pgroup, current_pg)) {
4351 warn(cf_newdpg, ient->sc_fmri, ud_name);
4352 internal_pgroup_free(old_dpt_pgroup);
4353 internal_pgroup_free(current_pg);
4354 return (0);
4355 }
4356
4357 internal_pgroup_free(old_dpt_pgroup);
4358 internal_pgroup_free(current_pg);
4359
4360 if (g_verbose)
4361 warn(gettext("%s: Deleting dependent \"%s\".\n"),
4362 ient->sc_fmri, ud_name);
4363
4364 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4365 switch (scf_error()) {
4366 case SCF_ERROR_NOT_FOUND:
4367 case SCF_ERROR_DELETED:
4368 internal_pgroup_free(old_dpt_pgroup);
4369 goto delprop;
4370
4371 case SCF_ERROR_CONNECTION_BROKEN:
4372 internal_pgroup_free(old_dpt_pgroup);
4373 return (ECONNABORTED);
4374
4375 case SCF_ERROR_NOT_SET:
4376 case SCF_ERROR_INVALID_ARGUMENT:
4377 case SCF_ERROR_HANDLE_MISMATCH:
4378 case SCF_ERROR_NOT_BOUND:
4379 default:
4380 bad_error("entity_get_pg", scf_error());
4381 }
4382 }
4383
4384 if (scf_pg_delete(ud_pg) != 0) {
4385 switch (scf_error()) {
4386 case SCF_ERROR_DELETED:
4387 break;
4388
4389 case SCF_ERROR_CONNECTION_BROKEN:
4390 case SCF_ERROR_BACKEND_READONLY:
4391 case SCF_ERROR_BACKEND_ACCESS:
4392 return (scferror2errno(scf_error()));
4393
4394 case SCF_ERROR_PERMISSION_DENIED:
4395 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4396 return (scferror2errno(scf_error()));
4397
4398 case SCF_ERROR_NOT_SET:
4399 default:
4400 bad_error("scf_pg_delete", scf_error());
4401 }
4402 }
4403
4404 /*
4405 * This service was changed, so it must be refreshed. But
4406 * since it's not mentioned in the new manifest, we have to
4407 * record its FMRI here for use later. We record the name
4408 * & the entity (via sc_parent) in case we need to print error
4409 * messages during the refresh.
4410 */
4411 dpt = internal_pgroup_new();
4412 if (dpt == NULL)
4413 return (ENOMEM);
4414 dpt->sc_pgroup_name = strdup(ud_name);
4415 dpt->sc_pgroup_fmri = strdup(ud_ctarg);
4416 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4417 return (ENOMEM);
4418 dpt->sc_parent = (entity_t *)ient;
4419 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4420 uu_die(gettext("libuutil error: %s\n"),
4421 uu_strerror(uu_error()));
4422
4423 delprop:
4424 if (tx == NULL)
4425 return (0);
4426
4427 ent = scf_entry_create(g_hndl);
4428 if (ent == NULL)
4429 return (ENOMEM);
4430
4431 if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
4432 scf_entry_destroy(ent);
4433 switch (scf_error()) {
4434 case SCF_ERROR_DELETED:
4435 warn(emsg_pg_deleted, ient->sc_fmri,
4436 "dependents");
4437 return (EBUSY);
4438
4439 case SCF_ERROR_CONNECTION_BROKEN:
4440 return (scferror2errno(scf_error()));
4441
4442 case SCF_ERROR_NOT_FOUND:
4443 break;
4444
4445 case SCF_ERROR_HANDLE_MISMATCH:
4446 case SCF_ERROR_NOT_BOUND:
4447 case SCF_ERROR_INVALID_ARGUMENT:
4448 case SCF_ERROR_NOT_SET:
4449 default:
4450 bad_error("scf_transaction_property_delete",
4451 scf_error());
4452 }
4453 }
4454
4455 return (0);
4456 }
4457
4458 new_dpt_pgroup->sc_pgroup_seen = 1;
4459
4460 /*
4461 * Decide whether the dependent has changed in the manifest.
4462 */
4463 /* Compare the target. */
4464 if (scf_property_get_value(prop, ud_val) != 0) {
4465 switch (scf_error()) {
4466 case SCF_ERROR_NOT_FOUND:
4467 case SCF_ERROR_CONSTRAINT_VIOLATED:
4468 warn(li_corrupt, ient->sc_fmri);
4469 return (EBADF);
4470
4471 case SCF_ERROR_DELETED:
4472 case SCF_ERROR_CONNECTION_BROKEN:
4473 return (scferror2errno(scf_error()));
4474
4475 case SCF_ERROR_HANDLE_MISMATCH:
4476 case SCF_ERROR_NOT_BOUND:
4477 case SCF_ERROR_NOT_SET:
4478 case SCF_ERROR_PERMISSION_DENIED:
4479 default:
4480 bad_error("scf_property_get_value", scf_error());
4481 }
4482 }
4483
4484 if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
4485 0)
4486 bad_error("scf_value_get_as_string", scf_error());
4487
4488 /*
4489 * If the fmri's are not equal then the old fmri will need to
4490 * be refreshed to ensure that the changes are properly updated
4491 * in that service.
4492 */
4493 r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
4494 switch (r) {
4495 case 0:
4496 dpt = internal_pgroup_new();
4497 if (dpt == NULL)
4498 return (ENOMEM);
4499 dpt->sc_pgroup_name = strdup(ud_name);
4500 dpt->sc_pgroup_fmri = strdup(ud_oldtarg);
4501 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4502 return (ENOMEM);
4503 dpt->sc_parent = (entity_t *)ient;
4504 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4505 uu_die(gettext("libuutil error: %s\n"),
4506 uu_strerror(uu_error()));
4507 break;
4508
4509 case 1:
4510 /* Compare the dependency pgs. */
4511 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4512 switch (scf_error()) {
4513 case SCF_ERROR_NOT_FOUND:
4514 warn(li_corrupt, ient->sc_fmri);
4515 return (EBADF);
4516
4517 case SCF_ERROR_DELETED:
4518 case SCF_ERROR_CONNECTION_BROKEN:
4519 return (scferror2errno(scf_error()));
4520
4521 case SCF_ERROR_NOT_BOUND:
4522 case SCF_ERROR_HANDLE_MISMATCH:
4523 case SCF_ERROR_INVALID_ARGUMENT:
4524 case SCF_ERROR_NOT_SET:
4525 default:
4526 bad_error("scf_snaplevel_get_pg", scf_error());
4527 }
4528 }
4529
4530 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4531 snap_lastimport);
4532 switch (r) {
4533 case 0:
4534 break;
4535
4536 case ECANCELED:
4537 case ECONNABORTED:
4538 case ENOMEM:
4539 case EBADF:
4540 return (r);
4541
4542 case EACCES:
4543 default:
4544 bad_error("load_pg", r);
4545 }
4546
4547 if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4548 /* no change, leave customizations */
4549 internal_pgroup_free(old_dpt_pgroup);
4550 return (0);
4551 }
4552 break;
4553
4554 case -1:
4555 warn(li_corrupt, ient->sc_fmri);
4556 return (EBADF);
4557
4558 case -2:
4559 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4560 ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4561 return (EINVAL);
4562
4563 default:
4564 bad_error("fmri_equal", r);
4565 }
4566
4567 /*
4568 * The dependent has changed in the manifest. Upgrade the current
4569 * properties if they haven't been customized.
4570 */
4571
4572 /*
4573 * If new_dpt_pgroup->sc_override, then act as though the property
4574 * group hasn't been customized.
4575 */
4576 if (new_dpt_pgroup->sc_pgroup_override) {
4577 (void) strcpy(ud_ctarg, ud_oldtarg);
4578 goto nocust;
4579 }
4580
4581 if (!ud_run_dpts_pg_set) {
4582 warn(cf_missing, ient->sc_fmri, ud_name);
4583 r = 0;
4584 goto out;
4585 } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4586 switch (scf_error()) {
4587 case SCF_ERROR_NOT_FOUND:
4588 warn(cf_missing, ient->sc_fmri, ud_name);
4589 r = 0;
4590 goto out;
4591
4592 case SCF_ERROR_CONNECTION_BROKEN:
4593 r = scferror2errno(scf_error());
4594 goto out;
4595
4596 case SCF_ERROR_DELETED:
4597 warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4598 r = EBUSY;
4599 goto out;
4600
4601 case SCF_ERROR_INVALID_ARGUMENT:
4602 case SCF_ERROR_NOT_BOUND:
4603 case SCF_ERROR_HANDLE_MISMATCH:
4604 case SCF_ERROR_NOT_SET:
4605 default:
4606 bad_error("scf_pg_get_property", scf_error());
4607 }
4608 }
4609
4610 if (scf_property_get_value(ud_prop, ud_val) != 0) {
4611 switch (scf_error()) {
4612 case SCF_ERROR_NOT_FOUND:
4613 case SCF_ERROR_CONSTRAINT_VIOLATED:
4614 warn(cf_inval, ient->sc_fmri, ud_name);
4615 r = 0;
4616 goto out;
4617
4618 case SCF_ERROR_DELETED:
4619 case SCF_ERROR_CONNECTION_BROKEN:
4620 r = scferror2errno(scf_error());
4621 goto out;
4622
4623 case SCF_ERROR_HANDLE_MISMATCH:
4624 case SCF_ERROR_NOT_BOUND:
4625 case SCF_ERROR_NOT_SET:
4626 case SCF_ERROR_PERMISSION_DENIED:
4627 default:
4628 bad_error("scf_property_get_value", scf_error());
4629 }
4630 }
4631
4632 ty = scf_value_type(ud_val);
4633 assert(ty != SCF_TYPE_INVALID);
4634 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4635 warn(cf_inval, ient->sc_fmri, ud_name);
4636 r = 0;
4637 goto out;
4638 }
4639 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4640 0)
4641 bad_error("scf_value_get_as_string", scf_error());
4642
4643 r = fmri_equal(ud_ctarg, ud_oldtarg);
4644 if (r == -1) {
4645 warn(cf_inval, ient->sc_fmri, ud_name);
4646 r = 0;
4647 goto out;
4648 } else if (r == -2) {
4649 warn(li_corrupt, ient->sc_fmri);
4650 r = EBADF;
4651 goto out;
4652 } else if (r == 0) {
4653 /*
4654 * Target has been changed. Only abort now if it's been
4655 * changed to something other than what's in the manifest.
4656 */
4657 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4658 if (r == -1) {
4659 warn(cf_inval, ient->sc_fmri, ud_name);
4660 r = 0;
4661 goto out;
4662 } else if (r == 0) {
4663 warn(cf_newtarg, ient->sc_fmri, ud_name);
4664 r = 0;
4665 goto out;
4666 } else if (r != 1) {
4667 /* invalid sc_pgroup_fmri caught above */
4668 bad_error("fmri_equal", r);
4669 }
4670
4671 /*
4672 * Fetch the current dependency pg. If it's what the manifest
4673 * says, then no problem.
4674 */
4675 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4676 switch (serr) {
4677 case SCF_ERROR_NONE:
4678 break;
4679
4680 case SCF_ERROR_NOT_FOUND:
4681 warn(cf_missing, ient->sc_fmri, ud_name);
4682 r = 0;
4683 goto out;
4684
4685 case SCF_ERROR_NO_MEMORY:
4686 r = ENOMEM;
4687 goto out;
4688
4689 case SCF_ERROR_CONSTRAINT_VIOLATED:
4690 case SCF_ERROR_INVALID_ARGUMENT:
4691 default:
4692 bad_error("fmri_to_entity", serr);
4693 }
4694
4695 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4696 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4697 switch (r) {
4698 case 0:
4699 break;
4700
4701 case ECONNABORTED:
4702 goto out;
4703
4704 case ECANCELED:
4705 case ENOENT:
4706 warn(cf_missing, ient->sc_fmri, ud_name);
4707 r = 0;
4708 goto out;
4709
4710 case EBADF:
4711 warn(r_no_lvl, ud_ctarg);
4712 goto out;
4713
4714 case EINVAL:
4715 default:
4716 bad_error("entity_get_running_pg", r);
4717 }
4718
4719 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4720 switch (r) {
4721 case 0:
4722 break;
4723
4724 case ECANCELED:
4725 warn(cf_missing, ient->sc_fmri, ud_name);
4726 r = 0;
4727 goto out;
4728
4729 case ECONNABORTED:
4730 case ENOMEM:
4731 case EBADF:
4732 goto out;
4733
4734 case EACCES:
4735 default:
4736 bad_error("load_pg", r);
4737 }
4738
4739 if (!pg_equal(current_pg, new_dpt_pgroup))
4740 warn(cf_newdpg, ient->sc_fmri, ud_name);
4741 internal_pgroup_free(current_pg);
4742 r = 0;
4743 goto out;
4744 } else if (r != 1) {
4745 bad_error("fmri_equal", r);
4746 }
4747
4748 nocust:
4749 /*
4750 * Target has not been customized. Check the dependency property
4751 * group.
4752 */
4753
4754 if (old_dpt_pgroup == NULL) {
4755 if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4756 ud_pg) != 0) {
4757 switch (scf_error()) {
4758 case SCF_ERROR_NOT_FOUND:
4759 warn(li_corrupt, ient->sc_fmri);
4760 return (EBADF);
4761
4762 case SCF_ERROR_DELETED:
4763 case SCF_ERROR_CONNECTION_BROKEN:
4764 return (scferror2errno(scf_error()));
4765
4766 case SCF_ERROR_NOT_BOUND:
4767 case SCF_ERROR_HANDLE_MISMATCH:
4768 case SCF_ERROR_INVALID_ARGUMENT:
4769 case SCF_ERROR_NOT_SET:
4770 default:
4771 bad_error("scf_snaplevel_get_pg", scf_error());
4772 }
4773 }
4774
4775 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4776 snap_lastimport);
4777 switch (r) {
4778 case 0:
4779 break;
4780
4781 case ECANCELED:
4782 case ECONNABORTED:
4783 case ENOMEM:
4784 case EBADF:
4785 return (r);
4786
4787 case EACCES:
4788 default:
4789 bad_error("load_pg", r);
4790 }
4791 }
4792 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4793 switch (serr) {
4794 case SCF_ERROR_NONE:
4795 break;
4796
4797 case SCF_ERROR_NOT_FOUND:
4798 warn(cf_missing, ient->sc_fmri, ud_name);
4799 r = 0;
4800 goto out;
4801
4802 case SCF_ERROR_NO_MEMORY:
4803 r = ENOMEM;
4804 goto out;
4805
4806 case SCF_ERROR_CONSTRAINT_VIOLATED:
4807 case SCF_ERROR_INVALID_ARGUMENT:
4808 default:
4809 bad_error("fmri_to_entity", serr);
4810 }
4811
4812 r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4813 ud_iter2, ud_inst, imp_snap, ud_snpl);
4814 switch (r) {
4815 case 0:
4816 break;
4817
4818 case ECONNABORTED:
4819 goto out;
4820
4821 case ECANCELED:
4822 case ENOENT:
4823 warn(cf_missing, ient->sc_fmri, ud_name);
4824 r = 0;
4825 goto out;
4826
4827 case EBADF:
4828 warn(r_no_lvl, ud_ctarg);
4829 goto out;
4830
4831 case EINVAL:
4832 default:
4833 bad_error("entity_get_running_pg", r);
4834 }
4835
4836 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4837 switch (r) {
4838 case 0:
4839 break;
4840
4841 case ECANCELED:
4842 warn(cf_missing, ient->sc_fmri, ud_name);
4843 goto out;
4844
4845 case ECONNABORTED:
4846 case ENOMEM:
4847 case EBADF:
4848 goto out;
4849
4850 case EACCES:
4851 default:
4852 bad_error("load_pg", r);
4853 }
4854
4855 if (!pg_equal(current_pg, old_dpt_pgroup)) {
4856 if (!pg_equal(current_pg, new_dpt_pgroup))
4857 warn(cf_newdpg, ient->sc_fmri, ud_name);
4858 internal_pgroup_free(current_pg);
4859 r = 0;
4860 goto out;
4861 }
4862
4863 /* Uncustomized. Upgrade. */
4864
4865 r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4866 switch (r) {
4867 case 1:
4868 if (pg_equal(current_pg, new_dpt_pgroup)) {
4869 /* Already upgraded. */
4870 internal_pgroup_free(current_pg);
4871 r = 0;
4872 goto out;
4873 }
4874
4875 internal_pgroup_free(current_pg);
4876
4877 /* upgrade current_pg */
4878 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4879 switch (scf_error()) {
4880 case SCF_ERROR_CONNECTION_BROKEN:
4881 r = scferror2errno(scf_error());
4882 goto out;
4883
4884 case SCF_ERROR_DELETED:
4885 warn(cf_missing, ient->sc_fmri, ud_name);
4886 r = 0;
4887 goto out;
4888
4889 case SCF_ERROR_NOT_FOUND:
4890 break;
4891
4892 case SCF_ERROR_INVALID_ARGUMENT:
4893 case SCF_ERROR_NOT_BOUND:
4894 case SCF_ERROR_NOT_SET:
4895 case SCF_ERROR_HANDLE_MISMATCH:
4896 default:
4897 bad_error("entity_get_pg", scf_error());
4898 }
4899
4900 if (tissvc)
4901 r = scf_service_add_pg(target_ent, ud_name,
4902 SCF_GROUP_DEPENDENCY, 0, ud_pg);
4903 else
4904 r = scf_instance_add_pg(target_ent, ud_name,
4905 SCF_GROUP_DEPENDENCY, 0, ud_pg);
4906 if (r != 0) {
4907 switch (scf_error()) {
4908 case SCF_ERROR_CONNECTION_BROKEN:
4909 case SCF_ERROR_NO_RESOURCES:
4910 case SCF_ERROR_BACKEND_READONLY:
4911 case SCF_ERROR_BACKEND_ACCESS:
4912 r = scferror2errno(scf_error());
4913 goto out;
4914
4915 case SCF_ERROR_DELETED:
4916 warn(cf_missing, ient->sc_fmri,
4917 ud_name);
4918 r = 0;
4919 goto out;
4920
4921 case SCF_ERROR_PERMISSION_DENIED:
4922 warn(emsg_pg_deleted, ud_ctarg,
4923 ud_name);
4924 r = EPERM;
4925 goto out;
4926
4927 case SCF_ERROR_EXISTS:
4928 warn(emsg_pg_added, ud_ctarg, ud_name);
4929 r = EBUSY;
4930 goto out;
4931
4932 case SCF_ERROR_NOT_BOUND:
4933 case SCF_ERROR_HANDLE_MISMATCH:
4934 case SCF_ERROR_INVALID_ARGUMENT:
4935 case SCF_ERROR_NOT_SET:
4936 default:
4937 bad_error("entity_add_pg", scf_error());
4938 }
4939 }
4940 }
4941
4942 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4943 switch (r) {
4944 case 0:
4945 break;
4946
4947 case ECANCELED:
4948 warn(cf_missing, ient->sc_fmri, ud_name);
4949 goto out;
4950
4951 case ECONNABORTED:
4952 case ENOMEM:
4953 case EBADF:
4954 goto out;
4955
4956 case EACCES:
4957 default:
4958 bad_error("load_pg", r);
4959 }
4960
4961 if (g_verbose)
4962 warn(upgrading, ient->sc_fmri, ud_name);
4963
4964 r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4965 new_dpt_pgroup, 0, ient->sc_fmri);
4966 switch (r) {
4967 case 0:
4968 break;
4969
4970 case ECANCELED:
4971 warn(emsg_pg_deleted, ud_ctarg, ud_name);
4972 r = EBUSY;
4973 goto out;
4974
4975 case EPERM:
4976 warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4977 goto out;
4978
4979 case EBUSY:
4980 warn(emsg_pg_changed, ud_ctarg, ud_name);
4981 goto out;
4982
4983 case ECONNABORTED:
4984 case ENOMEM:
4985 case ENOSPC:
4986 case EROFS:
4987 case EACCES:
4988 case EINVAL:
4989 goto out;
4990
4991 default:
4992 bad_error("upgrade_pg", r);
4993 }
4994 break;
4995
4996 case 0: {
4997 scf_transaction_entry_t *ent;
4998 scf_value_t *val;
4999
5000 internal_pgroup_free(current_pg);
5001
5002 /* delete old pg */
5003 if (g_verbose)
5004 warn(upgrading, ient->sc_fmri, ud_name);
5005
5006 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
5007 switch (scf_error()) {
5008 case SCF_ERROR_CONNECTION_BROKEN:
5009 r = scferror2errno(scf_error());
5010 goto out;
5011
5012 case SCF_ERROR_DELETED:
5013 warn(cf_missing, ient->sc_fmri, ud_name);
5014 r = 0;
5015 goto out;
5016
5017 case SCF_ERROR_NOT_FOUND:
5018 break;
5019
5020 case SCF_ERROR_INVALID_ARGUMENT:
5021 case SCF_ERROR_NOT_BOUND:
5022 case SCF_ERROR_NOT_SET:
5023 case SCF_ERROR_HANDLE_MISMATCH:
5024 default:
5025 bad_error("entity_get_pg", scf_error());
5026 }
5027 } else if (scf_pg_delete(ud_pg) != 0) {
5028 switch (scf_error()) {
5029 case SCF_ERROR_DELETED:
5030 break;
5031
5032 case SCF_ERROR_CONNECTION_BROKEN:
5033 case SCF_ERROR_BACKEND_READONLY:
5034 case SCF_ERROR_BACKEND_ACCESS:
5035 r = scferror2errno(scf_error());
5036 goto out;
5037
5038 case SCF_ERROR_PERMISSION_DENIED:
5039 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
5040 r = scferror2errno(scf_error());
5041 goto out;
5042
5043 case SCF_ERROR_NOT_SET:
5044 default:
5045 bad_error("scf_pg_delete", scf_error());
5046 }
5047 }
5048
5049 /* import new one */
5050 cbdata.sc_handle = g_hndl;
5051 cbdata.sc_trans = NULL; /* handled below */
5052 cbdata.sc_flags = 0;
5053
5054 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
5055 if (r != UU_WALK_NEXT) {
5056 if (r != UU_WALK_ERROR)
5057 bad_error("lscf_dependent_import", r);
5058
5059 r = cbdata.sc_err;
5060 goto out;
5061 }
5062
5063 if (tx == NULL)
5064 break;
5065
5066 if ((ent = scf_entry_create(g_hndl)) == NULL ||
5067 (val = scf_value_create(g_hndl)) == NULL) {
5068 if (scf_error() == SCF_ERROR_NO_MEMORY)
5069 return (ENOMEM);
5070
5071 bad_error("scf_entry_create", scf_error());
5072 }
5073
5074 if (scf_transaction_property_change_type(tx, ent, ud_name,
5075 SCF_TYPE_FMRI) != 0) {
5076 switch (scf_error()) {
5077 case SCF_ERROR_CONNECTION_BROKEN:
5078 r = scferror2errno(scf_error());
5079 goto out;
5080
5081 case SCF_ERROR_DELETED:
5082 warn(emsg_pg_deleted, ient->sc_fmri,
5083 "dependents");
5084 r = EBUSY;
5085 goto out;
5086
5087 case SCF_ERROR_NOT_FOUND:
5088 break;
5089
5090 case SCF_ERROR_NOT_BOUND:
5091 case SCF_ERROR_HANDLE_MISMATCH:
5092 case SCF_ERROR_INVALID_ARGUMENT:
5093 case SCF_ERROR_NOT_SET:
5094 default:
5095 bad_error("scf_transaction_property_"
5096 "change_type", scf_error());
5097 }
5098
5099 if (scf_transaction_property_new(tx, ent, ud_name,
5100 SCF_TYPE_FMRI) != 0) {
5101 switch (scf_error()) {
5102 case SCF_ERROR_CONNECTION_BROKEN:
5103 r = scferror2errno(scf_error());
5104 goto out;
5105
5106 case SCF_ERROR_DELETED:
5107 warn(emsg_pg_deleted, ient->sc_fmri,
5108 "dependents");
5109 r = EBUSY;
5110 goto out;
5111
5112 case SCF_ERROR_EXISTS:
5113 warn(emsg_pg_changed, ient->sc_fmri,
5114 "dependents");
5115 r = EBUSY;
5116 goto out;
5117
5118 case SCF_ERROR_INVALID_ARGUMENT:
5119 case SCF_ERROR_HANDLE_MISMATCH:
5120 case SCF_ERROR_NOT_BOUND:
5121 case SCF_ERROR_NOT_SET:
5122 default:
5123 bad_error("scf_transaction_property_"
5124 "new", scf_error());
5125 }
5126 }
5127 }
5128
5129 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
5130 new_dpt_pgroup->sc_pgroup_fmri) != 0)
5131 /* invalid sc_pgroup_fmri caught above */
5132 bad_error("scf_value_set_from_string",
5133 scf_error());
5134
5135 if (scf_entry_add_value(ent, val) != 0)
5136 bad_error("scf_entry_add_value", scf_error());
5137 break;
5138 }
5139
5140 case -2:
5141 warn(li_corrupt, ient->sc_fmri);
5142 internal_pgroup_free(current_pg);
5143 r = EBADF;
5144 goto out;
5145
5146 case -1:
5147 default:
5148 /* invalid sc_pgroup_fmri caught above */
5149 bad_error("fmri_equal", r);
5150 }
5151
5152 r = 0;
5153
5154 out:
5155 if (old_dpt_pgroup != NULL)
5156 internal_pgroup_free(old_dpt_pgroup);
5157
5158 return (r);
5159 }
5160
5161 /*
5162 * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
5163 * would import it, except it seems to exist in the service anyway. Compare
5164 * the existent dependent with the one we would import, and report any
5165 * differences (if there are none, be silent). prop is the property which
5166 * represents the existent dependent (in the dependents property group) in the
5167 * entity corresponding to ient.
5168 *
5169 * Returns
5170 * 0 - success (Sort of. At least, we can continue importing.)
5171 * ECONNABORTED - repository connection broken
5172 * EBUSY - ancestor of prop was deleted (error printed)
5173 * ENOMEM - out of memory
5174 * EBADF - corrupt property group (error printed)
5175 * EINVAL - new_dpt_pgroup has invalid target (error printed)
5176 */
5177 static int
5178 handle_dependent_conflict(const entity_t * const ient,
5179 const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
5180 {
5181 int r;
5182 scf_type_t ty;
5183 scf_error_t scfe;
5184 void *tptr;
5185 int tissvc;
5186 pgroup_t *pgroup;
5187
5188 if (scf_property_get_value(prop, ud_val) != 0) {
5189 switch (scf_error()) {
5190 case SCF_ERROR_CONNECTION_BROKEN:
5191 return (scferror2errno(scf_error()));
5192
5193 case SCF_ERROR_DELETED:
5194 warn(emsg_pg_deleted, ient->sc_fmri,
5195 new_dpt_pgroup->sc_pgroup_name);
5196 return (EBUSY);
5197
5198 case SCF_ERROR_CONSTRAINT_VIOLATED:
5199 case SCF_ERROR_NOT_FOUND:
5200 warn(gettext("Conflict upgrading %s (not importing "
5201 "dependent \"%s\" because it already exists.) "
5202 "Warning: The \"%s/%2$s\" property has more or "
5203 "fewer than one value)).\n"), ient->sc_fmri,
5204 new_dpt_pgroup->sc_pgroup_name, "dependents");
5205 return (0);
5206
5207 case SCF_ERROR_HANDLE_MISMATCH:
5208 case SCF_ERROR_NOT_BOUND:
5209 case SCF_ERROR_NOT_SET:
5210 case SCF_ERROR_PERMISSION_DENIED:
5211 default:
5212 bad_error("scf_property_get_value",
5213 scf_error());
5214 }
5215 }
5216
5217 ty = scf_value_type(ud_val);
5218 assert(ty != SCF_TYPE_INVALID);
5219 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
5220 warn(gettext("Conflict upgrading %s (not importing dependent "
5221 "\"%s\" because it already exists). Warning: The "
5222 "\"%s/%s\" property has unexpected type \"%s\")).\n"),
5223 ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
5224 scf_type_to_string(ty), "dependents");
5225 return (0);
5226 }
5227
5228 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
5229 0)
5230 bad_error("scf_value_get_as_string", scf_error());
5231
5232 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
5233 switch (r) {
5234 case 0:
5235 warn(gettext("Conflict upgrading %s (not importing dependent "
5236 "\"%s\" (target \"%s\") because it already exists with "
5237 "target \"%s\").\n"), ient->sc_fmri,
5238 new_dpt_pgroup->sc_pgroup_name,
5239 new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
5240 return (0);
5241
5242 case 1:
5243 break;
5244
5245 case -1:
5246 warn(gettext("Conflict upgrading %s (not importing dependent "
5247 "\"%s\" because it already exists). Warning: The current "
5248 "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
5249 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5250 return (0);
5251
5252 case -2:
5253 warn(gettext("Dependent \"%s\" of %s has invalid target "
5254 "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
5255 new_dpt_pgroup->sc_pgroup_fmri);
5256 return (EINVAL);
5257
5258 default:
5259 bad_error("fmri_equal", r);
5260 }
5261
5262 /* compare dependency pgs in target */
5263 scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
5264 switch (scfe) {
5265 case SCF_ERROR_NONE:
5266 break;
5267
5268 case SCF_ERROR_NO_MEMORY:
5269 return (ENOMEM);
5270
5271 case SCF_ERROR_NOT_FOUND:
5272 warn(emsg_dpt_dangling, ient->sc_fmri,
5273 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5274 return (0);
5275
5276 case SCF_ERROR_CONSTRAINT_VIOLATED:
5277 case SCF_ERROR_INVALID_ARGUMENT:
5278 default:
5279 bad_error("fmri_to_entity", scfe);
5280 }
5281
5282 r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
5283 ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
5284 switch (r) {
5285 case 0:
5286 break;
5287
5288 case ECONNABORTED:
5289 return (r);
5290
5291 case ECANCELED:
5292 warn(emsg_dpt_dangling, ient->sc_fmri,
5293 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5294 return (0);
5295
5296 case EBADF:
5297 if (tissvc)
5298 warn(gettext("%s has an instance with a \"%s\" "
5299 "snapshot which is missing a snaplevel.\n"),
5300 ud_ctarg, "running");
5301 else
5302 warn(gettext("%s has a \"%s\" snapshot which is "
5303 "missing a snaplevel.\n"), ud_ctarg, "running");
5304 /* FALLTHROUGH */
5305
5306 case ENOENT:
5307 warn(emsg_dpt_no_dep, ient->sc_fmri,
5308 new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5309 new_dpt_pgroup->sc_pgroup_name);
5310 return (0);
5311
5312 case EINVAL:
5313 default:
5314 bad_error("entity_get_running_pg", r);
5315 }
5316
5317 pgroup = internal_pgroup_new();
5318 if (pgroup == NULL)
5319 return (ENOMEM);
5320
5321 r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
5322 switch (r) {
5323 case 0:
5324 break;
5325
5326 case ECONNABORTED:
5327 case EBADF:
5328 case ENOMEM:
5329 internal_pgroup_free(pgroup);
5330 return (r);
5331
5332 case ECANCELED:
5333 warn(emsg_dpt_no_dep, ient->sc_fmri,
5334 new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5335 new_dpt_pgroup->sc_pgroup_name);
5336 internal_pgroup_free(pgroup);
5337 return (0);
5338
5339 case EACCES:
5340 default:
5341 bad_error("load_pg", r);
5342 }
5343
5344 /* report differences */
5345 report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
5346 internal_pgroup_free(pgroup);
5347 return (0);
5348 }
5349
5350 /*
5351 * lipg is a property group in the last-import snapshot of ent, which is an
5352 * scf_service_t or an scf_instance_t (according to ient). If lipg is not in
5353 * ient's pgroups, delete it from ent if it hasn't been customized. If it is
5354 * in ents's property groups, compare and upgrade ent appropriately.
5355 *
5356 * Returns
5357 * 0 - success
5358 * ECONNABORTED - repository connection broken
5359 * ENOMEM - out of memory
5360 * ENOSPC - configd is out of resources
5361 * EINVAL - ient has invalid dependent (error printed)
5362 * - ient has invalid pgroup_t (error printed)
5363 * ECANCELED - ent has been deleted
5364 * ENODEV - entity containing lipg has been deleted
5365 * - entity containing running has been deleted
5366 * EPERM - could not delete pg (permission denied) (error printed)
5367 * - couldn't upgrade dependents (permission denied) (error printed)
5368 * - couldn't import pg (permission denied) (error printed)
5369 * - couldn't upgrade pg (permission denied) (error printed)
5370 * EROFS - could not delete pg (repository read-only)
5371 * - couldn't upgrade dependents (repository read-only)
5372 * - couldn't import pg (repository read-only)
5373 * - couldn't upgrade pg (repository read-only)
5374 * EACCES - could not delete pg (backend access denied)
5375 * - couldn't upgrade dependents (backend access denied)
5376 * - couldn't import pg (backend access denied)
5377 * - couldn't upgrade pg (backend access denied)
5378 * - couldn't read property (backend access denied)
5379 * EBUSY - property group was added (error printed)
5380 * - property group was deleted (error printed)
5381 * - property group changed (error printed)
5382 * - "dependents" pg was added, changed, or deleted (error printed)
5383 * - dependent target deleted (error printed)
5384 * - dependent pg changed (error printed)
5385 * EBADF - imp_snpl is corrupt (error printed)
5386 * - ent has bad pg (error printed)
5387 * EEXIST - dependent collision in target service (error printed)
5388 */
5389 static int
5390 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
5391 const scf_snaplevel_t *running)
5392 {
5393 int r;
5394 pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
5395 scf_callback_t cbdata;
5396
5397 const char * const cf_pg_missing =
5398 gettext("Conflict upgrading %s (property group %s is missing)\n");
5399 const char * const deleting =
5400 gettext("%s: Deleting property group \"%s\".\n");
5401
5402 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5403
5404 /* Skip dependent property groups. */
5405 if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
5406 switch (scf_error()) {
5407 case SCF_ERROR_DELETED:
5408 return (ENODEV);
5409
5410 case SCF_ERROR_CONNECTION_BROKEN:
5411 return (ECONNABORTED);
5412
5413 case SCF_ERROR_NOT_SET:
5414 case SCF_ERROR_NOT_BOUND:
5415 default:
5416 bad_error("scf_pg_get_type", scf_error());
5417 }
5418 }
5419
5420 if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
5421 if (scf_pg_get_property(lipg, "external", NULL) == 0)
5422 return (0);
5423
5424 switch (scf_error()) {
5425 case SCF_ERROR_NOT_FOUND:
5426 break;
5427
5428 case SCF_ERROR_CONNECTION_BROKEN:
5429 return (ECONNABORTED);
5430
5431 case SCF_ERROR_DELETED:
5432 return (ENODEV);
5433
5434 case SCF_ERROR_INVALID_ARGUMENT:
5435 case SCF_ERROR_NOT_BOUND:
5436 case SCF_ERROR_HANDLE_MISMATCH:
5437 case SCF_ERROR_NOT_SET:
5438 default:
5439 bad_error("scf_pg_get_property", scf_error());
5440 }
5441 }
5442
5443 /* lookup pg in new properties */
5444 if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
5445 switch (scf_error()) {
5446 case SCF_ERROR_DELETED:
5447 return (ENODEV);
5448
5449 case SCF_ERROR_CONNECTION_BROKEN:
5450 return (ECONNABORTED);
5451
5452 case SCF_ERROR_NOT_SET:
5453 case SCF_ERROR_NOT_BOUND:
5454 default:
5455 bad_error("scf_pg_get_name", scf_error());
5456 }
5457 }
5458
5459 pgrp.sc_pgroup_name = imp_str;
5460 mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
5461
5462 if (mpg != NULL)
5463 mpg->sc_pgroup_seen = 1;
5464
5465 /* Special handling for dependents */
5466 if (strcmp(imp_str, "dependents") == 0)
5467 return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
5468
5469 if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
5470 return (upgrade_manifestfiles(NULL, ient, running, ent));
5471
5472 if (mpg == NULL || mpg->sc_pgroup_delete) {
5473 /* property group was deleted from manifest */
5474 if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5475 switch (scf_error()) {
5476 case SCF_ERROR_NOT_FOUND:
5477 return (0);
5478
5479 case SCF_ERROR_DELETED:
5480 case SCF_ERROR_CONNECTION_BROKEN:
5481 return (scferror2errno(scf_error()));
5482
5483 case SCF_ERROR_INVALID_ARGUMENT:
5484 case SCF_ERROR_HANDLE_MISMATCH:
5485 case SCF_ERROR_NOT_BOUND:
5486 case SCF_ERROR_NOT_SET:
5487 default:
5488 bad_error("entity_get_pg", scf_error());
5489 }
5490 }
5491
5492 if (mpg != NULL && mpg->sc_pgroup_delete) {
5493 if (g_verbose)
5494 warn(deleting, ient->sc_fmri, imp_str);
5495 if (scf_pg_delete(imp_pg2) == 0)
5496 return (0);
5497
5498 switch (scf_error()) {
5499 case SCF_ERROR_DELETED:
5500 return (0);
5501
5502 case SCF_ERROR_CONNECTION_BROKEN:
5503 case SCF_ERROR_BACKEND_READONLY:
5504 case SCF_ERROR_BACKEND_ACCESS:
5505 return (scferror2errno(scf_error()));
5506
5507 case SCF_ERROR_PERMISSION_DENIED:
5508 warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
5509 return (scferror2errno(scf_error()));
5510
5511 case SCF_ERROR_NOT_SET:
5512 default:
5513 bad_error("scf_pg_delete", scf_error());
5514 }
5515 }
5516
5517 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5518 switch (r) {
5519 case 0:
5520 break;
5521
5522 case ECANCELED:
5523 return (ENODEV);
5524
5525 case ECONNABORTED:
5526 case ENOMEM:
5527 case EBADF:
5528 case EACCES:
5529 return (r);
5530
5531 default:
5532 bad_error("load_pg", r);
5533 }
5534
5535 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5536 switch (r) {
5537 case 0:
5538 break;
5539
5540 case ECANCELED:
5541 case ECONNABORTED:
5542 case ENOMEM:
5543 case EBADF:
5544 case EACCES:
5545 internal_pgroup_free(lipg_i);
5546 return (r);
5547
5548 default:
5549 bad_error("load_pg", r);
5550 }
5551
5552 if (pg_equal(lipg_i, curpg_i)) {
5553 if (g_verbose)
5554 warn(deleting, ient->sc_fmri, imp_str);
5555 if (scf_pg_delete(imp_pg2) != 0) {
5556 switch (scf_error()) {
5557 case SCF_ERROR_DELETED:
5558 break;
5559
5560 case SCF_ERROR_CONNECTION_BROKEN:
5561 internal_pgroup_free(lipg_i);
5562 internal_pgroup_free(curpg_i);
5563 return (ECONNABORTED);
5564
5565 case SCF_ERROR_NOT_SET:
5566 case SCF_ERROR_NOT_BOUND:
5567 default:
5568 bad_error("scf_pg_delete", scf_error());
5569 }
5570 }
5571 } else {
5572 report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5573 }
5574
5575 internal_pgroup_free(lipg_i);
5576 internal_pgroup_free(curpg_i);
5577
5578 return (0);
5579 }
5580
5581 /*
5582 * Only dependent pgs can have override set, and we skipped those
5583 * above.
5584 */
5585 assert(!mpg->sc_pgroup_override);
5586
5587 /* compare */
5588 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5589 switch (r) {
5590 case 0:
5591 break;
5592
5593 case ECANCELED:
5594 return (ENODEV);
5595
5596 case ECONNABORTED:
5597 case EBADF:
5598 case ENOMEM:
5599 case EACCES:
5600 return (r);
5601
5602 default:
5603 bad_error("load_pg", r);
5604 }
5605
5606 if (pg_equal(mpg, lipg_i)) {
5607 /* The manifest pg has not changed. Move on. */
5608 r = 0;
5609 goto out;
5610 }
5611
5612 /* upgrade current properties according to lipg & mpg */
5613 if (running != NULL)
5614 r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5615 else
5616 r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5617 if (r != 0) {
5618 switch (scf_error()) {
5619 case SCF_ERROR_CONNECTION_BROKEN:
5620 r = scferror2errno(scf_error());
5621 goto out;
5622
5623 case SCF_ERROR_DELETED:
5624 if (running != NULL)
5625 r = ENODEV;
5626 else
5627 r = ECANCELED;
5628 goto out;
5629
5630 case SCF_ERROR_NOT_FOUND:
5631 break;
5632
5633 case SCF_ERROR_INVALID_ARGUMENT:
5634 case SCF_ERROR_HANDLE_MISMATCH:
5635 case SCF_ERROR_NOT_BOUND:
5636 case SCF_ERROR_NOT_SET:
5637 default:
5638 bad_error("entity_get_pg", scf_error());
5639 }
5640
5641 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5642
5643 r = 0;
5644 goto out;
5645 }
5646
5647 r = load_pg_attrs(imp_pg2, &curpg_i);
5648 switch (r) {
5649 case 0:
5650 break;
5651
5652 case ECANCELED:
5653 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5654 r = 0;
5655 goto out;
5656
5657 case ECONNABORTED:
5658 case ENOMEM:
5659 goto out;
5660
5661 default:
5662 bad_error("load_pg_attrs", r);
5663 }
5664
5665 if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5666 (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5667 internal_pgroup_free(curpg_i);
5668 r = 0;
5669 goto out;
5670 }
5671
5672 internal_pgroup_free(curpg_i);
5673
5674 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5675 switch (r) {
5676 case 0:
5677 break;
5678
5679 case ECANCELED:
5680 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5681 r = 0;
5682 goto out;
5683
5684 case ECONNABORTED:
5685 case EBADF:
5686 case ENOMEM:
5687 case EACCES:
5688 goto out;
5689
5690 default:
5691 bad_error("load_pg", r);
5692 }
5693
5694 if (pg_equal(lipg_i, curpg_i) &&
5695 !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5696 int do_delete = 1;
5697
5698 if (g_verbose)
5699 warn(gettext("%s: Upgrading property group \"%s\".\n"),
5700 ient->sc_fmri, mpg->sc_pgroup_name);
5701
5702 internal_pgroup_free(curpg_i);
5703
5704 if (running != NULL &&
5705 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5706 switch (scf_error()) {
5707 case SCF_ERROR_DELETED:
5708 r = ECANCELED;
5709 goto out;
5710
5711 case SCF_ERROR_NOT_FOUND:
5712 do_delete = 0;
5713 break;
5714
5715 case SCF_ERROR_CONNECTION_BROKEN:
5716 r = scferror2errno(scf_error());
5717 goto out;
5718
5719 case SCF_ERROR_HANDLE_MISMATCH:
5720 case SCF_ERROR_INVALID_ARGUMENT:
5721 case SCF_ERROR_NOT_SET:
5722 case SCF_ERROR_NOT_BOUND:
5723 default:
5724 bad_error("entity_get_pg", scf_error());
5725 }
5726 }
5727
5728 if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5729 switch (scf_error()) {
5730 case SCF_ERROR_DELETED:
5731 break;
5732
5733 case SCF_ERROR_CONNECTION_BROKEN:
5734 case SCF_ERROR_BACKEND_READONLY:
5735 case SCF_ERROR_BACKEND_ACCESS:
5736 r = scferror2errno(scf_error());
5737 goto out;
5738
5739 case SCF_ERROR_PERMISSION_DENIED:
5740 warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5741 ient->sc_fmri);
5742 r = scferror2errno(scf_error());
5743 goto out;
5744
5745 case SCF_ERROR_NOT_SET:
5746 case SCF_ERROR_NOT_BOUND:
5747 default:
5748 bad_error("scf_pg_delete", scf_error());
5749 }
5750 }
5751
5752 cbdata.sc_handle = g_hndl;
5753 cbdata.sc_parent = ent;
5754 cbdata.sc_service = issvc;
5755 cbdata.sc_flags = 0;
5756 cbdata.sc_source_fmri = ient->sc_fmri;
5757 cbdata.sc_target_fmri = ient->sc_fmri;
5758
5759 r = entity_pgroup_import(mpg, &cbdata);
5760 switch (r) {
5761 case UU_WALK_NEXT:
5762 r = 0;
5763 goto out;
5764
5765 case UU_WALK_ERROR:
5766 if (cbdata.sc_err == EEXIST) {
5767 warn(emsg_pg_added, ient->sc_fmri,
5768 mpg->sc_pgroup_name);
5769 r = EBUSY;
5770 } else {
5771 r = cbdata.sc_err;
5772 }
5773 goto out;
5774
5775 default:
5776 bad_error("entity_pgroup_import", r);
5777 }
5778 }
5779
5780 if (running != NULL &&
5781 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5782 switch (scf_error()) {
5783 case SCF_ERROR_CONNECTION_BROKEN:
5784 case SCF_ERROR_DELETED:
5785 r = scferror2errno(scf_error());
5786 goto out;
5787
5788 case SCF_ERROR_NOT_FOUND:
5789 break;
5790
5791 case SCF_ERROR_HANDLE_MISMATCH:
5792 case SCF_ERROR_INVALID_ARGUMENT:
5793 case SCF_ERROR_NOT_SET:
5794 case SCF_ERROR_NOT_BOUND:
5795 default:
5796 bad_error("entity_get_pg", scf_error());
5797 }
5798
5799 cbdata.sc_handle = g_hndl;
5800 cbdata.sc_parent = ent;
5801 cbdata.sc_service = issvc;
5802 cbdata.sc_flags = SCI_FORCE;
5803 cbdata.sc_source_fmri = ient->sc_fmri;
5804 cbdata.sc_target_fmri = ient->sc_fmri;
5805
5806 r = entity_pgroup_import(mpg, &cbdata);
5807 switch (r) {
5808 case UU_WALK_NEXT:
5809 r = 0;
5810 goto out;
5811
5812 case UU_WALK_ERROR:
5813 if (cbdata.sc_err == EEXIST) {
5814 warn(emsg_pg_added, ient->sc_fmri,
5815 mpg->sc_pgroup_name);
5816 r = EBUSY;
5817 } else {
5818 r = cbdata.sc_err;
5819 }
5820 goto out;
5821
5822 default:
5823 bad_error("entity_pgroup_import", r);
5824 }
5825 }
5826
5827 r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5828 internal_pgroup_free(curpg_i);
5829 switch (r) {
5830 case 0:
5831 ient->sc_import_state = IMPORT_PROP_BEGUN;
5832 break;
5833
5834 case ECANCELED:
5835 warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5836 r = EBUSY;
5837 break;
5838
5839 case EPERM:
5840 warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5841 break;
5842
5843 case EBUSY:
5844 warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5845 break;
5846
5847 case ECONNABORTED:
5848 case ENOMEM:
5849 case ENOSPC:
5850 case EROFS:
5851 case EACCES:
5852 case EINVAL:
5853 break;
5854
5855 default:
5856 bad_error("upgrade_pg", r);
5857 }
5858
5859 out:
5860 internal_pgroup_free(lipg_i);
5861 return (r);
5862 }
5863
5864 /*
5865 * Upgrade the properties of ent according to snpl & ient.
5866 *
5867 * Returns
5868 * 0 - success
5869 * ECONNABORTED - repository connection broken
5870 * ENOMEM - out of memory
5871 * ENOSPC - configd is out of resources
5872 * ECANCELED - ent was deleted
5873 * ENODEV - entity containing snpl was deleted
5874 * - entity containing running was deleted
5875 * EBADF - imp_snpl is corrupt (error printed)
5876 * - ent has corrupt pg (error printed)
5877 * - dependent has corrupt pg (error printed)
5878 * - dependent target has a corrupt snapshot (error printed)
5879 * EBUSY - pg was added, changed, or deleted (error printed)
5880 * - dependent target was deleted (error printed)
5881 * - dependent pg changed (error printed)
5882 * EINVAL - invalid property group name (error printed)
5883 * - invalid property name (error printed)
5884 * - invalid value (error printed)
5885 * - ient has invalid pgroup or dependent (error printed)
5886 * EPERM - could not create property group (permission denied) (error printed)
5887 * - could not modify property group (permission denied) (error printed)
5888 * - couldn't delete, upgrade, or import pg or dependent (error printed)
5889 * EROFS - could not create property group (repository read-only)
5890 * - couldn't delete, upgrade, or import pg or dependent
5891 * EACCES - could not create property group (backend access denied)
5892 * - couldn't delete, upgrade, or import pg or dependent
5893 * EEXIST - dependent collision in target service (error printed)
5894 */
5895 static int
5896 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5897 entity_t *ient)
5898 {
5899 pgroup_t *pg, *rpg;
5900 int r;
5901 uu_list_t *pgs = ient->sc_pgroups;
5902
5903 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5904
5905 /* clear sc_sceen for pgs */
5906 if (uu_list_walk(pgs, clear_int,
5907 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5908 bad_error("uu_list_walk", uu_error());
5909
5910 if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5911 switch (scf_error()) {
5912 case SCF_ERROR_DELETED:
5913 return (ENODEV);
5914
5915 case SCF_ERROR_CONNECTION_BROKEN:
5916 return (ECONNABORTED);
5917
5918 case SCF_ERROR_NOT_SET:
5919 case SCF_ERROR_NOT_BOUND:
5920 case SCF_ERROR_HANDLE_MISMATCH:
5921 default:
5922 bad_error("scf_iter_snaplevel_pgs", scf_error());
5923 }
5924 }
5925
5926 for (;;) {
5927 r = scf_iter_next_pg(imp_up_iter, imp_pg);
5928 if (r == 0)
5929 break;
5930 if (r == 1) {
5931 r = process_old_pg(imp_pg, ient, ent, running);
5932 switch (r) {
5933 case 0:
5934 break;
5935
5936 case ECONNABORTED:
5937 case ENOMEM:
5938 case ENOSPC:
5939 case ECANCELED:
5940 case ENODEV:
5941 case EPERM:
5942 case EROFS:
5943 case EACCES:
5944 case EBADF:
5945 case EBUSY:
5946 case EINVAL:
5947 case EEXIST:
5948 return (r);
5949
5950 default:
5951 bad_error("process_old_pg", r);
5952 }
5953 continue;
5954 }
5955 if (r != -1)
5956 bad_error("scf_iter_next_pg", r);
5957
5958 switch (scf_error()) {
5959 case SCF_ERROR_DELETED:
5960 return (ENODEV);
5961
5962 case SCF_ERROR_CONNECTION_BROKEN:
5963 return (ECONNABORTED);
5964
5965 case SCF_ERROR_HANDLE_MISMATCH:
5966 case SCF_ERROR_NOT_BOUND:
5967 case SCF_ERROR_NOT_SET:
5968 case SCF_ERROR_INVALID_ARGUMENT:
5969 default:
5970 bad_error("scf_iter_next_pg", scf_error());
5971 }
5972 }
5973
5974 for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5975 if (pg->sc_pgroup_seen)
5976 continue;
5977
5978 /* pg is new */
5979
5980 if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5981 r = upgrade_dependents(NULL, imp_snpl, ient, running,
5982 ent);
5983 switch (r) {
5984 case 0:
5985 break;
5986
5987 case ECONNABORTED:
5988 case ENOMEM:
5989 case ENOSPC:
5990 case ECANCELED:
5991 case ENODEV:
5992 case EBADF:
5993 case EBUSY:
5994 case EINVAL:
5995 case EPERM:
5996 case EROFS:
5997 case EACCES:
5998 case EEXIST:
5999 return (r);
6000
6001 default:
6002 bad_error("upgrade_dependents", r);
6003 }
6004 continue;
6005 }
6006
6007 if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
6008 r = upgrade_manifestfiles(pg, ient, running, ent);
6009 switch (r) {
6010 case 0:
6011 break;
6012
6013 case ECONNABORTED:
6014 case ENOMEM:
6015 case ENOSPC:
6016 case ECANCELED:
6017 case ENODEV:
6018 case EBADF:
6019 case EBUSY:
6020 case EINVAL:
6021 case EPERM:
6022 case EROFS:
6023 case EACCES:
6024 case EEXIST:
6025 return (r);
6026
6027 default:
6028 bad_error("upgrade_manifestfiles", r);
6029 }
6030 continue;
6031 }
6032
6033 if (running != NULL) {
6034 r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
6035 imp_pg);
6036 } else {
6037 r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
6038 imp_pg);
6039 }
6040 if (r != 0) {
6041 scf_callback_t cbdata;
6042
6043 switch (scf_error()) {
6044 case SCF_ERROR_NOT_FOUND:
6045 break;
6046
6047 case SCF_ERROR_CONNECTION_BROKEN:
6048 return (scferror2errno(scf_error()));
6049
6050 case SCF_ERROR_DELETED:
6051 if (running != NULL)
6052 return (ENODEV);
6053 else
6054 return (scferror2errno(scf_error()));
6055
6056 case SCF_ERROR_INVALID_ARGUMENT:
6057 warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
6058 pg->sc_pgroup_name);
6059 return (EINVAL);
6060
6061 case SCF_ERROR_NOT_SET:
6062 case SCF_ERROR_HANDLE_MISMATCH:
6063 case SCF_ERROR_NOT_BOUND:
6064 default:
6065 bad_error("entity_get_pg", scf_error());
6066 }
6067
6068 /* User doesn't have pg, so import it. */
6069
6070 cbdata.sc_handle = g_hndl;
6071 cbdata.sc_parent = ent;
6072 cbdata.sc_service = issvc;
6073 cbdata.sc_flags = SCI_FORCE;
6074 cbdata.sc_source_fmri = ient->sc_fmri;
6075 cbdata.sc_target_fmri = ient->sc_fmri;
6076
6077 r = entity_pgroup_import(pg, &cbdata);
6078 switch (r) {
6079 case UU_WALK_NEXT:
6080 ient->sc_import_state = IMPORT_PROP_BEGUN;
6081 continue;
6082
6083 case UU_WALK_ERROR:
6084 if (cbdata.sc_err == EEXIST) {
6085 warn(emsg_pg_added, ient->sc_fmri,
6086 pg->sc_pgroup_name);
6087 return (EBUSY);
6088 }
6089 return (cbdata.sc_err);
6090
6091 default:
6092 bad_error("entity_pgroup_import", r);
6093 }
6094 }
6095
6096 /* report differences between pg & current */
6097 r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
6098 switch (r) {
6099 case 0:
6100 break;
6101
6102 case ECANCELED:
6103 warn(emsg_pg_deleted, ient->sc_fmri,
6104 pg->sc_pgroup_name);
6105 return (EBUSY);
6106
6107 case ECONNABORTED:
6108 case EBADF:
6109 case ENOMEM:
6110 case EACCES:
6111 return (r);
6112
6113 default:
6114 bad_error("load_pg", r);
6115 }
6116 report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
6117 internal_pgroup_free(rpg);
6118 rpg = NULL;
6119 }
6120
6121 return (0);
6122 }
6123
6124 /*
6125 * Import an instance. If it doesn't exist, create it. If it has
6126 * a last-import snapshot, upgrade its properties. Finish by updating its
6127 * last-import snapshot. If it doesn't have a last-import snapshot then it
6128 * could have been created for a dependent tag in another manifest. Import the
6129 * new properties. If there's a conflict, don't override, like now?
6130 *
6131 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
6132 * lcbdata->sc_err to
6133 * ECONNABORTED - repository connection broken
6134 * ENOMEM - out of memory
6135 * ENOSPC - svc.configd is out of resources
6136 * EEXIST - dependency collision in dependent service (error printed)
6137 * EPERM - couldn't create temporary instance (permission denied)
6138 * - couldn't import into temporary instance (permission denied)
6139 * - couldn't take snapshot (permission denied)
6140 * - couldn't upgrade properties (permission denied)
6141 * - couldn't import properties (permission denied)
6142 * - couldn't import dependents (permission denied)
6143 * EROFS - couldn't create temporary instance (repository read-only)
6144 * - couldn't import into temporary instance (repository read-only)
6145 * - couldn't upgrade properties (repository read-only)
6146 * - couldn't import properties (repository read-only)
6147 * - couldn't import dependents (repository read-only)
6148 * EACCES - couldn't create temporary instance (backend access denied)
6149 * - couldn't import into temporary instance (backend access denied)
6150 * - couldn't upgrade properties (backend access denied)
6151 * - couldn't import properties (backend access denied)
6152 * - couldn't import dependents (backend access denied)
6153 * EINVAL - invalid instance name (error printed)
6154 * - invalid pgroup_t's (error printed)
6155 * - invalid dependents (error printed)
6156 * EBUSY - temporary service deleted (error printed)
6157 * - temporary instance deleted (error printed)
6158 * - temporary instance changed (error printed)
6159 * - temporary instance already exists (error printed)
6160 * - instance deleted (error printed)
6161 * EBADF - instance has corrupt last-import snapshot (error printed)
6162 * - instance is corrupt (error printed)
6163 * - dependent has corrupt pg (error printed)
6164 * - dependent target has a corrupt snapshot (error printed)
6165 * -1 - unknown libscf error (error printed)
6166 */
6167 static int
6168 lscf_instance_import(void *v, void *pvt)
6169 {
6170 entity_t *inst = v;
6171 scf_callback_t ctx;
6172 scf_callback_t *lcbdata = pvt;
6173 scf_service_t *rsvc = lcbdata->sc_parent;
6174 int r;
6175 scf_snaplevel_t *running;
6176 int flags = lcbdata->sc_flags;
6177
6178 const char * const emsg_tdel =
6179 gettext("Temporary instance svc:/%s:%s was deleted.\n");
6180 const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
6181 "changed unexpectedly.\n");
6182 const char * const emsg_del = gettext("%s changed unexpectedly "
6183 "(instance \"%s\" was deleted.)\n");
6184 const char * const emsg_badsnap = gettext(
6185 "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
6186
6187 /*
6188 * prepare last-import snapshot:
6189 * create temporary instance (service was precreated)
6190 * populate with properties from bundle
6191 * take snapshot
6192 */
6193 if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
6194 switch (scf_error()) {
6195 case SCF_ERROR_CONNECTION_BROKEN:
6196 case SCF_ERROR_NO_RESOURCES:
6197 case SCF_ERROR_BACKEND_READONLY:
6198 case SCF_ERROR_BACKEND_ACCESS:
6199 return (stash_scferror(lcbdata));
6200
6201 case SCF_ERROR_EXISTS:
6202 warn(gettext("Temporary service svc:/%s "
6203 "changed unexpectedly (instance \"%s\" added).\n"),
6204 imp_tsname, inst->sc_name);
6205 lcbdata->sc_err = EBUSY;
6206 return (UU_WALK_ERROR);
6207
6208 case SCF_ERROR_DELETED:
6209 warn(gettext("Temporary service svc:/%s "
6210 "was deleted unexpectedly.\n"), imp_tsname);
6211 lcbdata->sc_err = EBUSY;
6212 return (UU_WALK_ERROR);
6213
6214 case SCF_ERROR_INVALID_ARGUMENT:
6215 warn(gettext("Invalid instance name \"%s\".\n"),
6216 inst->sc_name);
6217 return (stash_scferror(lcbdata));
6218
6219 case SCF_ERROR_PERMISSION_DENIED:
6220 warn(gettext("Could not create temporary instance "
6221 "\"%s\" in svc:/%s (permission denied).\n"),
6222 inst->sc_name, imp_tsname);
6223 return (stash_scferror(lcbdata));
6224
6225 case SCF_ERROR_HANDLE_MISMATCH:
6226 case SCF_ERROR_NOT_BOUND:
6227 case SCF_ERROR_NOT_SET:
6228 default:
6229 bad_error("scf_service_add_instance", scf_error());
6230 }
6231 }
6232
6233 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6234 inst->sc_name);
6235 if (r < 0)
6236 bad_error("snprintf", errno);
6237
6238 r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
6239 lcbdata->sc_flags | SCI_NOENABLED);
6240 switch (r) {
6241 case 0:
6242 break;
6243
6244 case ECANCELED:
6245 warn(emsg_tdel, imp_tsname, inst->sc_name);
6246 lcbdata->sc_err = EBUSY;
6247 r = UU_WALK_ERROR;
6248 goto deltemp;
6249
6250 case EEXIST:
6251 warn(emsg_tchg, imp_tsname, inst->sc_name);
6252 lcbdata->sc_err = EBUSY;
6253 r = UU_WALK_ERROR;
6254 goto deltemp;
6255
6256 case ECONNABORTED:
6257 goto connaborted;
6258
6259 case ENOMEM:
6260 case ENOSPC:
6261 case EPERM:
6262 case EROFS:
6263 case EACCES:
6264 case EINVAL:
6265 case EBUSY:
6266 lcbdata->sc_err = r;
6267 r = UU_WALK_ERROR;
6268 goto deltemp;
6269
6270 default:
6271 bad_error("lscf_import_instance_pgs", r);
6272 }
6273
6274 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6275 inst->sc_name);
6276 if (r < 0)
6277 bad_error("snprintf", errno);
6278
6279 ctx.sc_handle = lcbdata->sc_handle;
6280 ctx.sc_parent = imp_tinst;
6281 ctx.sc_service = 0;
6282 ctx.sc_source_fmri = inst->sc_fmri;
6283 ctx.sc_target_fmri = imp_str;
6284 if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
6285 UU_DEFAULT) != 0) {
6286 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6287 bad_error("uu_list_walk", uu_error());
6288
6289 switch (ctx.sc_err) {
6290 case ECONNABORTED:
6291 goto connaborted;
6292
6293 case ECANCELED:
6294 warn(emsg_tdel, imp_tsname, inst->sc_name);
6295 lcbdata->sc_err = EBUSY;
6296 break;
6297
6298 case EEXIST:
6299 warn(emsg_tchg, imp_tsname, inst->sc_name);
6300 lcbdata->sc_err = EBUSY;
6301 break;
6302
6303 default:
6304 lcbdata->sc_err = ctx.sc_err;
6305 }
6306 r = UU_WALK_ERROR;
6307 goto deltemp;
6308 }
6309
6310 if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
6311 inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
6312 switch (scf_error()) {
6313 case SCF_ERROR_CONNECTION_BROKEN:
6314 goto connaborted;
6315
6316 case SCF_ERROR_NO_RESOURCES:
6317 r = stash_scferror(lcbdata);
6318 goto deltemp;
6319
6320 case SCF_ERROR_EXISTS:
6321 warn(emsg_tchg, imp_tsname, inst->sc_name);
6322 lcbdata->sc_err = EBUSY;
6323 r = UU_WALK_ERROR;
6324 goto deltemp;
6325
6326 case SCF_ERROR_PERMISSION_DENIED:
6327 warn(gettext("Could not take \"%s\" snapshot of %s "
6328 "(permission denied).\n"), snap_lastimport,
6329 imp_str);
6330 r = stash_scferror(lcbdata);
6331 goto deltemp;
6332
6333 default:
6334 scfwarn();
6335 lcbdata->sc_err = -1;
6336 r = UU_WALK_ERROR;
6337 goto deltemp;
6338
6339 case SCF_ERROR_HANDLE_MISMATCH:
6340 case SCF_ERROR_INVALID_ARGUMENT:
6341 case SCF_ERROR_NOT_SET:
6342 bad_error("_scf_snapshot_take_new_named", scf_error());
6343 }
6344 }
6345
6346 if (lcbdata->sc_flags & SCI_FRESH)
6347 goto fresh;
6348
6349 if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
6350 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6351 imp_lisnap) != 0) {
6352 switch (scf_error()) {
6353 case SCF_ERROR_DELETED:
6354 warn(emsg_del, inst->sc_parent->sc_fmri,
6355 inst->sc_name);
6356 lcbdata->sc_err = EBUSY;
6357 r = UU_WALK_ERROR;
6358 goto deltemp;
6359
6360 case SCF_ERROR_NOT_FOUND:
6361 flags |= SCI_FORCE;
6362 goto nosnap;
6363
6364 case SCF_ERROR_CONNECTION_BROKEN:
6365 goto connaborted;
6366
6367 case SCF_ERROR_INVALID_ARGUMENT:
6368 case SCF_ERROR_HANDLE_MISMATCH:
6369 case SCF_ERROR_NOT_BOUND:
6370 case SCF_ERROR_NOT_SET:
6371 default:
6372 bad_error("scf_instance_get_snapshot",
6373 scf_error());
6374 }
6375 }
6376
6377 /* upgrade */
6378
6379 /*
6380 * compare new properties with last-import properties
6381 * upgrade current properties
6382 */
6383 /* clear sc_sceen for pgs */
6384 if (uu_list_walk(inst->sc_pgroups, clear_int,
6385 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
6386 0)
6387 bad_error("uu_list_walk", uu_error());
6388
6389 r = get_snaplevel(imp_lisnap, 0, imp_snpl);
6390 switch (r) {
6391 case 0:
6392 break;
6393
6394 case ECONNABORTED:
6395 goto connaborted;
6396
6397 case ECANCELED:
6398 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6399 lcbdata->sc_err = EBUSY;
6400 r = UU_WALK_ERROR;
6401 goto deltemp;
6402
6403 case ENOENT:
6404 warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
6405 lcbdata->sc_err = EBADF;
6406 r = UU_WALK_ERROR;
6407 goto deltemp;
6408
6409 default:
6410 bad_error("get_snaplevel", r);
6411 }
6412
6413 if (scf_instance_get_snapshot(imp_inst, snap_running,
6414 imp_rsnap) != 0) {
6415 switch (scf_error()) {
6416 case SCF_ERROR_DELETED:
6417 warn(emsg_del, inst->sc_parent->sc_fmri,
6418 inst->sc_name);
6419 lcbdata->sc_err = EBUSY;
6420 r = UU_WALK_ERROR;
6421 goto deltemp;
6422
6423 case SCF_ERROR_NOT_FOUND:
6424 break;
6425
6426 case SCF_ERROR_CONNECTION_BROKEN:
6427 goto connaborted;
6428
6429 case SCF_ERROR_INVALID_ARGUMENT:
6430 case SCF_ERROR_HANDLE_MISMATCH:
6431 case SCF_ERROR_NOT_BOUND:
6432 case SCF_ERROR_NOT_SET:
6433 default:
6434 bad_error("scf_instance_get_snapshot",
6435 scf_error());
6436 }
6437
6438 running = NULL;
6439 } else {
6440 r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
6441 switch (r) {
6442 case 0:
6443 running = imp_rsnpl;
6444 break;
6445
6446 case ECONNABORTED:
6447 goto connaborted;
6448
6449 case ECANCELED:
6450 warn(emsg_del, inst->sc_parent->sc_fmri,
6451 inst->sc_name);
6452 lcbdata->sc_err = EBUSY;
6453 r = UU_WALK_ERROR;
6454 goto deltemp;
6455
6456 case ENOENT:
6457 warn(emsg_badsnap, snap_running, inst->sc_fmri);
6458 lcbdata->sc_err = EBADF;
6459 r = UU_WALK_ERROR;
6460 goto deltemp;
6461
6462 default:
6463 bad_error("get_snaplevel", r);
6464 }
6465 }
6466
6467 r = upgrade_props(imp_inst, running, imp_snpl, inst);
6468 switch (r) {
6469 case 0:
6470 break;
6471
6472 case ECANCELED:
6473 case ENODEV:
6474 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6475 lcbdata->sc_err = EBUSY;
6476 r = UU_WALK_ERROR;
6477 goto deltemp;
6478
6479 case ECONNABORTED:
6480 goto connaborted;
6481
6482 case ENOMEM:
6483 case ENOSPC:
6484 case EBADF:
6485 case EBUSY:
6486 case EINVAL:
6487 case EPERM:
6488 case EROFS:
6489 case EACCES:
6490 case EEXIST:
6491 lcbdata->sc_err = r;
6492 r = UU_WALK_ERROR;
6493 goto deltemp;
6494
6495 default:
6496 bad_error("upgrade_props", r);
6497 }
6498
6499 inst->sc_import_state = IMPORT_PROP_DONE;
6500 } else {
6501 switch (scf_error()) {
6502 case SCF_ERROR_CONNECTION_BROKEN:
6503 goto connaborted;
6504
6505 case SCF_ERROR_NOT_FOUND:
6506 break;
6507
6508 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
6509 case SCF_ERROR_HANDLE_MISMATCH:
6510 case SCF_ERROR_NOT_BOUND:
6511 case SCF_ERROR_NOT_SET:
6512 default:
6513 bad_error("scf_service_get_instance", scf_error());
6514 }
6515
6516 fresh:
6517 /* create instance */
6518 if (scf_service_add_instance(rsvc, inst->sc_name,
6519 imp_inst) != 0) {
6520 switch (scf_error()) {
6521 case SCF_ERROR_CONNECTION_BROKEN:
6522 goto connaborted;
6523
6524 case SCF_ERROR_NO_RESOURCES:
6525 case SCF_ERROR_BACKEND_READONLY:
6526 case SCF_ERROR_BACKEND_ACCESS:
6527 r = stash_scferror(lcbdata);
6528 goto deltemp;
6529
6530 case SCF_ERROR_EXISTS:
6531 warn(gettext("%s changed unexpectedly "
6532 "(instance \"%s\" added).\n"),
6533 inst->sc_parent->sc_fmri, inst->sc_name);
6534 lcbdata->sc_err = EBUSY;
6535 r = UU_WALK_ERROR;
6536 goto deltemp;
6537
6538 case SCF_ERROR_PERMISSION_DENIED:
6539 warn(gettext("Could not create \"%s\" instance "
6540 "in %s (permission denied).\n"),
6541 inst->sc_name, inst->sc_parent->sc_fmri);
6542 r = stash_scferror(lcbdata);
6543 goto deltemp;
6544
6545 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
6546 case SCF_ERROR_HANDLE_MISMATCH:
6547 case SCF_ERROR_NOT_BOUND:
6548 case SCF_ERROR_NOT_SET:
6549 default:
6550 bad_error("scf_service_add_instance",
6551 scf_error());
6552 }
6553 }
6554
6555 nosnap:
6556 /*
6557 * Create a last-import snapshot to serve as an attachment
6558 * point for the real one from the temporary instance. Since
6559 * the contents is irrelevant, take it now, while the instance
6560 * is empty, to minimize svc.configd's work.
6561 */
6562 if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6563 imp_lisnap) != 0) {
6564 switch (scf_error()) {
6565 case SCF_ERROR_CONNECTION_BROKEN:
6566 goto connaborted;
6567
6568 case SCF_ERROR_NO_RESOURCES:
6569 r = stash_scferror(lcbdata);
6570 goto deltemp;
6571
6572 case SCF_ERROR_EXISTS:
6573 warn(gettext("%s changed unexpectedly "
6574 "(snapshot \"%s\" added).\n"),
6575 inst->sc_fmri, snap_lastimport);
6576 lcbdata->sc_err = EBUSY;
6577 r = UU_WALK_ERROR;
6578 goto deltemp;
6579
6580 case SCF_ERROR_PERMISSION_DENIED:
6581 warn(gettext("Could not take \"%s\" snapshot "
6582 "of %s (permission denied).\n"),
6583 snap_lastimport, inst->sc_fmri);
6584 r = stash_scferror(lcbdata);
6585 goto deltemp;
6586
6587 default:
6588 scfwarn();
6589 lcbdata->sc_err = -1;
6590 r = UU_WALK_ERROR;
6591 goto deltemp;
6592
6593 case SCF_ERROR_NOT_SET:
6594 case SCF_ERROR_INTERNAL:
6595 case SCF_ERROR_INVALID_ARGUMENT:
6596 case SCF_ERROR_HANDLE_MISMATCH:
6597 bad_error("_scf_snapshot_take_new",
6598 scf_error());
6599 }
6600 }
6601
6602 if (li_only)
6603 goto lionly;
6604
6605 inst->sc_import_state = IMPORT_PROP_BEGUN;
6606
6607 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6608 flags);
6609 switch (r) {
6610 case 0:
6611 break;
6612
6613 case ECONNABORTED:
6614 goto connaborted;
6615
6616 case ECANCELED:
6617 warn(gettext("%s changed unexpectedly "
6618 "(instance \"%s\" deleted).\n"),
6619 inst->sc_parent->sc_fmri, inst->sc_name);
6620 lcbdata->sc_err = EBUSY;
6621 r = UU_WALK_ERROR;
6622 goto deltemp;
6623
6624 case EEXIST:
6625 warn(gettext("%s changed unexpectedly "
6626 "(property group added).\n"), inst->sc_fmri);
6627 lcbdata->sc_err = EBUSY;
6628 r = UU_WALK_ERROR;
6629 goto deltemp;
6630
6631 default:
6632 lcbdata->sc_err = r;
6633 r = UU_WALK_ERROR;
6634 goto deltemp;
6635
6636 case EINVAL: /* caught above */
6637 bad_error("lscf_import_instance_pgs", r);
6638 }
6639
6640 ctx.sc_parent = imp_inst;
6641 ctx.sc_service = 0;
6642 ctx.sc_trans = NULL;
6643 ctx.sc_flags = 0;
6644 if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6645 &ctx, UU_DEFAULT) != 0) {
6646 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6647 bad_error("uu_list_walk", uu_error());
6648
6649 if (ctx.sc_err == ECONNABORTED)
6650 goto connaborted;
6651 lcbdata->sc_err = ctx.sc_err;
6652 r = UU_WALK_ERROR;
6653 goto deltemp;
6654 }
6655
6656 inst->sc_import_state = IMPORT_PROP_DONE;
6657
6658 if (g_verbose)
6659 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6660 snap_initial, inst->sc_fmri);
6661 r = take_snap(imp_inst, snap_initial, imp_snap);
6662 switch (r) {
6663 case 0:
6664 break;
6665
6666 case ECONNABORTED:
6667 goto connaborted;
6668
6669 case ENOSPC:
6670 case -1:
6671 lcbdata->sc_err = r;
6672 r = UU_WALK_ERROR;
6673 goto deltemp;
6674
6675 case ECANCELED:
6676 warn(gettext("%s changed unexpectedly "
6677 "(instance %s deleted).\n"),
6678 inst->sc_parent->sc_fmri, inst->sc_name);
6679 lcbdata->sc_err = r;
6680 r = UU_WALK_ERROR;
6681 goto deltemp;
6682
6683 case EPERM:
6684 warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6685 lcbdata->sc_err = r;
6686 r = UU_WALK_ERROR;
6687 goto deltemp;
6688
6689 default:
6690 bad_error("take_snap", r);
6691 }
6692 }
6693
6694 lionly:
6695 if (lcbdata->sc_flags & SCI_NOSNAP)
6696 goto deltemp;
6697
6698 /* transfer snapshot from temporary instance */
6699 if (g_verbose)
6700 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6701 snap_lastimport, inst->sc_fmri);
6702 if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6703 switch (scf_error()) {
6704 case SCF_ERROR_CONNECTION_BROKEN:
6705 goto connaborted;
6706
6707 case SCF_ERROR_NO_RESOURCES:
6708 r = stash_scferror(lcbdata);
6709 goto deltemp;
6710
6711 case SCF_ERROR_PERMISSION_DENIED:
6712 warn(gettext("Could not take \"%s\" snapshot for %s "
6713 "(permission denied).\n"), snap_lastimport,
6714 inst->sc_fmri);
6715 r = stash_scferror(lcbdata);
6716 goto deltemp;
6717
6718 case SCF_ERROR_NOT_SET:
6719 case SCF_ERROR_HANDLE_MISMATCH:
6720 default:
6721 bad_error("_scf_snapshot_attach", scf_error());
6722 }
6723 }
6724
6725 inst->sc_import_state = IMPORT_COMPLETE;
6726
6727 r = UU_WALK_NEXT;
6728
6729 deltemp:
6730 /* delete temporary instance */
6731 if (scf_instance_delete(imp_tinst) != 0) {
6732 switch (scf_error()) {
6733 case SCF_ERROR_DELETED:
6734 break;
6735
6736 case SCF_ERROR_CONNECTION_BROKEN:
6737 goto connaborted;
6738
6739 case SCF_ERROR_NOT_SET:
6740 case SCF_ERROR_NOT_BOUND:
6741 default:
6742 bad_error("scf_instance_delete", scf_error());
6743 }
6744 }
6745
6746 return (r);
6747
6748 connaborted:
6749 warn(gettext("Could not delete svc:/%s:%s "
6750 "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6751 lcbdata->sc_err = ECONNABORTED;
6752 return (UU_WALK_ERROR);
6753 }
6754
6755 /*
6756 * When an instance is imported we end up telling configd about it. Once we tell
6757 * configd about these changes, startd eventually notices. If this is a new
6758 * instance, the manifest may not specify the SCF_PG_RESTARTER (restarter)
6759 * property group. However, many of the other tools expect that this property
6760 * group exists and has certain values.
6761 *
6762 * These values are added asynchronously by startd. We should not return from
6763 * this routine until we can verify that the property group we need is there.
6764 *
6765 * Before we go ahead and verify this, we have to ask ourselves an important
6766 * question: Is the early manifest service currently running? Because if it is
6767 * running and it has invoked us, then the service will never get a restarter
6768 * property because svc.startd is blocked on EMI finishing before it lets itself
6769 * fully connect to svc.configd. Of course, this means that this race condition
6770 * is in fact impossible to 100% eliminate.
6771 *
6772 * svc.startd makes sure that EMI only runs once and has succeeded by checking
6773 * the state of the EMI instance. If it is online it bails out and makes sure
6774 * that it doesn't run again. In this case, we're going to do something similar,
6775 * only if the state is online, then we're going to actually verify. EMI always
6776 * has to be present, but it can be explicitly disabled to reduce the amount of
6777 * damage it can cause. If EMI has been disabled then we no longer have to worry
6778 * about the implicit race condition and can go ahead and check things. If EMI
6779 * is in some state that isn't online or disabled and isn't runinng, then we
6780 * assume that things are rather bad and we're not going to get in your way,
6781 * even if the rest of SMF does.
6782 *
6783 * Returns 0 on success or returns an errno.
6784 */
6785 #ifndef NATIVE_BUILD
6786 static int
6787 lscf_instance_verify(scf_scope_t *scope, entity_t *svc, entity_t *inst)
6788 {
6789 int ret, err;
6790 struct timespec ts;
6791 char *emi_state;
6792
6793 /*
6794 * smf_get_state does not distinguish between its different failure
6795 * modes: memory allocation failures, SMF internal failures, and a lack
6796 * of EMI entirely because it's been removed. In these cases, we're
6797 * going to be conservative and opt to say that if we don't know, better
6798 * to not block import or falsely warn to the user.
6799 */
6800 if ((emi_state = smf_get_state(SCF_INSTANCE_EMI)) == NULL) {
6801 return (0);
6802 }
6803
6804 /*
6805 * As per the block comment for this function check the state of EMI
6806 */
6807 if (strcmp(emi_state, SCF_STATE_STRING_ONLINE) != 0 &&
6808 strcmp(emi_state, SCF_STATE_STRING_DISABLED) != 0) {
6809 warn(gettext("Not validating instance %s:%s because EMI's "
6810 "state is %s\n"), svc->sc_name, inst->sc_name, emi_state);
6811 free(emi_state);
6812 return (0);
6813 }
6814
6815 free(emi_state);
6816
6817 /*
6818 * First we have to get the property.
6819 */
6820 if ((ret = scf_scope_get_service(scope, svc->sc_name, imp_svc)) != 0) {
6821 ret = scf_error();
6822 warn(gettext("Failed to look up service: %s\n"), svc->sc_name);
6823 return (ret);
6824 }
6825
6826 /*
6827 * We should always be able to get the instance. It should already
6828 * exist because we just created it or got it. There probably is a
6829 * slim chance that someone may have come in and deleted it though from
6830 * under us.
6831 */
6832 if ((ret = scf_service_get_instance(imp_svc, inst->sc_name, imp_inst))
6833 != 0) {
6834 ret = scf_error();
6835 warn(gettext("Failed to verify instance: %s\n"), inst->sc_name);
6836 switch (ret) {
6837 case SCF_ERROR_DELETED:
6838 err = ENODEV;
6839 break;
6840 case SCF_ERROR_CONNECTION_BROKEN:
6841 warn(gettext("Lost repository connection\n"));
6842 err = ECONNABORTED;
6843 break;
6844 case SCF_ERROR_NOT_FOUND:
6845 warn(gettext("Instance \"%s\" disappeared out from "
6846 "under us.\n"), inst->sc_name);
6847 err = ENOENT;
6848 break;
6849 default:
6850 bad_error("scf_service_get_instance", ret);
6851 }
6852
6853 return (err);
6854 }
6855
6856 /*
6857 * An astute observer may want to use _scf_wait_pg which would notify us
6858 * of a property group change, unfortunately that does not work if the
6859 * property group in question does not exist. So instead we have to
6860 * manually poll and ask smf the best way to get to it.
6861 */
6862 while ((ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg))
6863 != SCF_SUCCESS) {
6864 ret = scf_error();
6865 if (ret != SCF_ERROR_NOT_FOUND) {
6866 warn(gettext("Failed to get restarter property "
6867 "group for instance: %s\n"), inst->sc_name);
6868 switch (ret) {
6869 case SCF_ERROR_DELETED:
6870 err = ENODEV;
6871 break;
6872 case SCF_ERROR_CONNECTION_BROKEN:
6873 warn(gettext("Lost repository connection\n"));
6874 err = ECONNABORTED;
6875 break;
6876 default:
6877 bad_error("scf_service_get_instance", ret);
6878 }
6879
6880 return (err);
6881 }
6882
6883 ts.tv_sec = pg_timeout / NANOSEC;
6884 ts.tv_nsec = pg_timeout % NANOSEC;
6885
6886 (void) nanosleep(&ts, NULL);
6887 }
6888
6889 /*
6890 * svcadm also expects that the SCF_PROPERTY_STATE property is present.
6891 * So in addition to the property group being present, we need to wait
6892 * for the property to be there in some form.
6893 *
6894 * Note that a property group is a frozen snapshot in time. To properly
6895 * get beyond this, you have to refresh the property group each time.
6896 */
6897 while ((ret = scf_pg_get_property(imp_pg, SCF_PROPERTY_STATE,
6898 imp_prop)) != 0) {
6899
6900 ret = scf_error();
6901 if (ret != SCF_ERROR_NOT_FOUND) {
6902 warn(gettext("Failed to get property %s from the "
6903 "restarter property group of instance %s\n"),
6904 SCF_PROPERTY_STATE, inst->sc_name);
6905 switch (ret) {
6906 case SCF_ERROR_CONNECTION_BROKEN:
6907 warn(gettext("Lost repository connection\n"));
6908 err = ECONNABORTED;
6909 break;
6910 case SCF_ERROR_DELETED:
6911 err = ENODEV;
6912 break;
6913 default:
6914 bad_error("scf_pg_get_property", ret);
6915 }
6916
6917 return (err);
6918 }
6919
6920 ts.tv_sec = pg_timeout / NANOSEC;
6921 ts.tv_nsec = pg_timeout % NANOSEC;
6922
6923 (void) nanosleep(&ts, NULL);
6924
6925 ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg);
6926 if (ret != SCF_SUCCESS) {
6927 warn(gettext("Failed to get restarter property "
6928 "group for instance: %s\n"), inst->sc_name);
6929 switch (ret) {
6930 case SCF_ERROR_DELETED:
6931 err = ENODEV;
6932 break;
6933 case SCF_ERROR_CONNECTION_BROKEN:
6934 warn(gettext("Lost repository connection\n"));
6935 err = ECONNABORTED;
6936 break;
6937 default:
6938 bad_error("scf_service_get_instance", ret);
6939 }
6940
6941 return (err);
6942 }
6943 }
6944
6945 /*
6946 * We don't have to free the property groups or other values that we got
6947 * because we stored them in global variables that are allocated and
6948 * freed by the routines that call into these functions. Unless of
6949 * course the rest of the code here that we are basing this on is
6950 * mistaken.
6951 */
6952 return (0);
6953 }
6954 #endif
6955
6956 /*
6957 * If the service is missing, create it, import its properties, and import the
6958 * instances. Since the service is brand new, it should be empty, and if we
6959 * run into any existing entities (SCF_ERROR_EXISTS), abort.
6960 *
6961 * If the service exists, we want to upgrade its properties and import the
6962 * instances. Upgrade requires a last-import snapshot, though, which are
6963 * children of instances, so first we'll have to go through the instances
6964 * looking for a last-import snapshot. If we don't find one then we'll just
6965 * override-import the service properties (but don't delete existing
6966 * properties: another service might have declared us as a dependent). Before
6967 * we change anything, though, we want to take the previous snapshots. We
6968 * also give lscf_instance_import() a leg up on taking last-import snapshots
6969 * by importing the manifest's service properties into a temporary service.
6970 *
6971 * On success, returns UU_WALK_NEXT. On failure, returns UU_WALK_ERROR and
6972 * sets lcbdata->sc_err to
6973 * ECONNABORTED - repository connection broken
6974 * ENOMEM - out of memory
6975 * ENOSPC - svc.configd is out of resources
6976 * EPERM - couldn't create temporary service (error printed)
6977 * - couldn't import into temp service (error printed)
6978 * - couldn't create service (error printed)
6979 * - couldn't import dependent (error printed)
6980 * - couldn't take snapshot (error printed)
6981 * - couldn't create instance (error printed)
6982 * - couldn't create, modify, or delete pg (error printed)
6983 * - couldn't create, modify, or delete dependent (error printed)
6984 * - couldn't import instance (error printed)
6985 * EROFS - couldn't create temporary service (repository read-only)
6986 * - couldn't import into temporary service (repository read-only)
6987 * - couldn't create service (repository read-only)
6988 * - couldn't import dependent (repository read-only)
6989 * - couldn't create instance (repository read-only)
6990 * - couldn't create, modify, or delete pg or dependent
6991 * - couldn't import instance (repository read-only)
6992 * EACCES - couldn't create temporary service (backend access denied)
6993 * - couldn't import into temporary service (backend access denied)
6994 * - couldn't create service (backend access denied)
6995 * - couldn't import dependent (backend access denied)
6996 * - couldn't create instance (backend access denied)
6997 * - couldn't create, modify, or delete pg or dependent
6998 * - couldn't import instance (backend access denied)
6999 * EINVAL - service name is invalid (error printed)
7000 * - service name is too long (error printed)
7001 * - s has invalid pgroup (error printed)
7002 * - s has invalid dependent (error printed)
7003 * - instance name is invalid (error printed)
7004 * - instance entity_t is invalid (error printed)
7005 * EEXIST - couldn't create temporary service (already exists) (error printed)
7006 * - couldn't import dependent (dependency pg already exists) (printed)
7007 * - dependency collision in dependent service (error printed)
7008 * EBUSY - temporary service deleted (error printed)
7009 * - property group added to temporary service (error printed)
7010 * - new property group changed or was deleted (error printed)
7011 * - service was added unexpectedly (error printed)
7012 * - service was deleted unexpectedly (error printed)
7013 * - property group added to new service (error printed)
7014 * - instance added unexpectedly (error printed)
7015 * - instance deleted unexpectedly (error printed)
7016 * - dependent service deleted unexpectedly (error printed)
7017 * - pg was added, changed, or deleted (error printed)
7018 * - dependent pg changed (error printed)
7019 * - temporary instance added, changed, or deleted (error printed)
7020 * EBADF - a last-import snapshot is corrupt (error printed)
7021 * - the service is corrupt (error printed)
7022 * - a dependent is corrupt (error printed)
7023 * - an instance is corrupt (error printed)
7024 * - an instance has a corrupt last-import snapshot (error printed)
7025 * - dependent target has a corrupt snapshot (error printed)
7026 * -1 - unknown libscf error (error printed)
7027 */
7028 static int
7029 lscf_service_import(void *v, void *pvt)
7030 {
7031 entity_t *s = v;
7032 scf_callback_t cbdata;
7033 scf_callback_t *lcbdata = pvt;
7034 scf_scope_t *scope = lcbdata->sc_parent;
7035 entity_t *inst, linst;
7036 int r;
7037 int fresh = 0;
7038 scf_snaplevel_t *running;
7039 int have_ge = 0;
7040 boolean_t retried = B_FALSE;
7041
7042 const char * const ts_deleted = gettext("Temporary service svc:/%s "
7043 "was deleted unexpectedly.\n");
7044 const char * const ts_pg_added = gettext("Temporary service svc:/%s "
7045 "changed unexpectedly (property group added).\n");
7046 const char * const s_deleted =
7047 gettext("%s was deleted unexpectedly.\n");
7048 const char * const i_deleted =
7049 gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
7050 const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
7051 "is corrupt (missing service snaplevel).\n");
7052 const char * const s_mfile_upd =
7053 gettext("Unable to update the manifest file connection "
7054 "for %s\n");
7055
7056 li_only = 0;
7057 /* Validate the service name */
7058 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7059 switch (scf_error()) {
7060 case SCF_ERROR_CONNECTION_BROKEN:
7061 return (stash_scferror(lcbdata));
7062
7063 case SCF_ERROR_INVALID_ARGUMENT:
7064 warn(gettext("\"%s\" is an invalid service name. "
7065 "Cannot import.\n"), s->sc_name);
7066 return (stash_scferror(lcbdata));
7067
7068 case SCF_ERROR_NOT_FOUND:
7069 break;
7070
7071 case SCF_ERROR_HANDLE_MISMATCH:
7072 case SCF_ERROR_NOT_BOUND:
7073 case SCF_ERROR_NOT_SET:
7074 default:
7075 bad_error("scf_scope_get_service", scf_error());
7076 }
7077 }
7078
7079 /* create temporary service */
7080 /*
7081 * the size of the buffer was reduced to max_scf_name_len to prevent
7082 * hitting bug 6681151. After the bug fix, the size of the buffer
7083 * should be restored to its original value (max_scf_name_len +1)
7084 */
7085 r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
7086 if (r < 0)
7087 bad_error("snprintf", errno);
7088 if (r > max_scf_name_len) {
7089 warn(gettext(
7090 "Service name \"%s\" is too long. Cannot import.\n"),
7091 s->sc_name);
7092 lcbdata->sc_err = EINVAL;
7093 return (UU_WALK_ERROR);
7094 }
7095
7096 retry:
7097 if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
7098 switch (scf_error()) {
7099 case SCF_ERROR_CONNECTION_BROKEN:
7100 case SCF_ERROR_NO_RESOURCES:
7101 case SCF_ERROR_BACKEND_READONLY:
7102 case SCF_ERROR_BACKEND_ACCESS:
7103 return (stash_scferror(lcbdata));
7104
7105 case SCF_ERROR_EXISTS:
7106 if (!retried) {
7107 lscf_delete(imp_tsname, 0);
7108 retried = B_TRUE;
7109 goto retry;
7110 }
7111 warn(gettext(
7112 "Temporary service \"%s\" must be deleted before "
7113 "this manifest can be imported.\n"), imp_tsname);
7114 return (stash_scferror(lcbdata));
7115
7116 case SCF_ERROR_PERMISSION_DENIED:
7117 warn(gettext("Could not create temporary service "
7118 "\"%s\" (permission denied).\n"), imp_tsname);
7119 return (stash_scferror(lcbdata));
7120
7121 case SCF_ERROR_INVALID_ARGUMENT:
7122 case SCF_ERROR_HANDLE_MISMATCH:
7123 case SCF_ERROR_NOT_BOUND:
7124 case SCF_ERROR_NOT_SET:
7125 default:
7126 bad_error("scf_scope_add_service", scf_error());
7127 }
7128 }
7129
7130 r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
7131 if (r < 0)
7132 bad_error("snprintf", errno);
7133
7134 cbdata.sc_handle = lcbdata->sc_handle;
7135 cbdata.sc_parent = imp_tsvc;
7136 cbdata.sc_service = 1;
7137 cbdata.sc_source_fmri = s->sc_fmri;
7138 cbdata.sc_target_fmri = imp_str;
7139 cbdata.sc_flags = 0;
7140
7141 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
7142 UU_DEFAULT) != 0) {
7143 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7144 bad_error("uu_list_walk", uu_error());
7145
7146 lcbdata->sc_err = cbdata.sc_err;
7147 switch (cbdata.sc_err) {
7148 case ECONNABORTED:
7149 goto connaborted;
7150
7151 case ECANCELED:
7152 warn(ts_deleted, imp_tsname);
7153 lcbdata->sc_err = EBUSY;
7154 return (UU_WALK_ERROR);
7155
7156 case EEXIST:
7157 warn(ts_pg_added, imp_tsname);
7158 lcbdata->sc_err = EBUSY;
7159 return (UU_WALK_ERROR);
7160 }
7161
7162 r = UU_WALK_ERROR;
7163 goto deltemp;
7164 }
7165
7166 if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
7167 UU_DEFAULT) != 0) {
7168 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7169 bad_error("uu_list_walk", uu_error());
7170
7171 lcbdata->sc_err = cbdata.sc_err;
7172 switch (cbdata.sc_err) {
7173 case ECONNABORTED:
7174 goto connaborted;
7175
7176 case ECANCELED:
7177 warn(ts_deleted, imp_tsname);
7178 lcbdata->sc_err = EBUSY;
7179 return (UU_WALK_ERROR);
7180
7181 case EEXIST:
7182 warn(ts_pg_added, imp_tsname);
7183 lcbdata->sc_err = EBUSY;
7184 return (UU_WALK_ERROR);
7185 }
7186
7187 r = UU_WALK_ERROR;
7188 goto deltemp;
7189 }
7190
7191 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7192 switch (scf_error()) {
7193 case SCF_ERROR_NOT_FOUND:
7194 break;
7195
7196 case SCF_ERROR_CONNECTION_BROKEN:
7197 goto connaborted;
7198
7199 case SCF_ERROR_INVALID_ARGUMENT:
7200 case SCF_ERROR_HANDLE_MISMATCH:
7201 case SCF_ERROR_NOT_BOUND:
7202 case SCF_ERROR_NOT_SET:
7203 default:
7204 bad_error("scf_scope_get_service", scf_error());
7205 }
7206
7207 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
7208 switch (scf_error()) {
7209 case SCF_ERROR_CONNECTION_BROKEN:
7210 goto connaborted;
7211
7212 case SCF_ERROR_NO_RESOURCES:
7213 case SCF_ERROR_BACKEND_READONLY:
7214 case SCF_ERROR_BACKEND_ACCESS:
7215 r = stash_scferror(lcbdata);
7216 goto deltemp;
7217
7218 case SCF_ERROR_EXISTS:
7219 warn(gettext("Scope \"%s\" changed unexpectedly"
7220 " (service \"%s\" added).\n"),
7221 SCF_SCOPE_LOCAL, s->sc_name);
7222 lcbdata->sc_err = EBUSY;
7223 goto deltemp;
7224
7225 case SCF_ERROR_PERMISSION_DENIED:
7226 warn(gettext("Could not create service \"%s\" "
7227 "(permission denied).\n"), s->sc_name);
7228 goto deltemp;
7229
7230 case SCF_ERROR_INVALID_ARGUMENT:
7231 case SCF_ERROR_HANDLE_MISMATCH:
7232 case SCF_ERROR_NOT_BOUND:
7233 case SCF_ERROR_NOT_SET:
7234 default:
7235 bad_error("scf_scope_add_service", scf_error());
7236 }
7237 }
7238
7239 s->sc_import_state = IMPORT_PROP_BEGUN;
7240
7241 /* import service properties */
7242 cbdata.sc_handle = lcbdata->sc_handle;
7243 cbdata.sc_parent = imp_svc;
7244 cbdata.sc_service = 1;
7245 cbdata.sc_flags = lcbdata->sc_flags;
7246 cbdata.sc_source_fmri = s->sc_fmri;
7247 cbdata.sc_target_fmri = s->sc_fmri;
7248
7249 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7250 &cbdata, UU_DEFAULT) != 0) {
7251 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7252 bad_error("uu_list_walk", uu_error());
7253
7254 lcbdata->sc_err = cbdata.sc_err;
7255 switch (cbdata.sc_err) {
7256 case ECONNABORTED:
7257 goto connaborted;
7258
7259 case ECANCELED:
7260 warn(s_deleted, s->sc_fmri);
7261 lcbdata->sc_err = EBUSY;
7262 return (UU_WALK_ERROR);
7263
7264 case EEXIST:
7265 warn(gettext("%s changed unexpectedly "
7266 "(property group added).\n"), s->sc_fmri);
7267 lcbdata->sc_err = EBUSY;
7268 return (UU_WALK_ERROR);
7269
7270 case EINVAL:
7271 /* caught above */
7272 bad_error("entity_pgroup_import",
7273 cbdata.sc_err);
7274 }
7275
7276 r = UU_WALK_ERROR;
7277 goto deltemp;
7278 }
7279
7280 cbdata.sc_trans = NULL;
7281 cbdata.sc_flags = 0;
7282 if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
7283 &cbdata, UU_DEFAULT) != 0) {
7284 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7285 bad_error("uu_list_walk", uu_error());
7286
7287 lcbdata->sc_err = cbdata.sc_err;
7288 if (cbdata.sc_err == ECONNABORTED)
7289 goto connaborted;
7290 r = UU_WALK_ERROR;
7291 goto deltemp;
7292 }
7293
7294 s->sc_import_state = IMPORT_PROP_DONE;
7295
7296 /*
7297 * This is a new service, so we can't take previous snapshots
7298 * or upgrade service properties.
7299 */
7300 fresh = 1;
7301 goto instances;
7302 }
7303
7304 /* Clear sc_seen for the instances. */
7305 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
7306 (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
7307 bad_error("uu_list_walk", uu_error());
7308
7309 /*
7310 * Take previous snapshots for all instances. Even for ones not
7311 * mentioned in the bundle, since we might change their service
7312 * properties.
7313 */
7314 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7315 switch (scf_error()) {
7316 case SCF_ERROR_CONNECTION_BROKEN:
7317 goto connaborted;
7318
7319 case SCF_ERROR_DELETED:
7320 warn(s_deleted, s->sc_fmri);
7321 lcbdata->sc_err = EBUSY;
7322 r = UU_WALK_ERROR;
7323 goto deltemp;
7324
7325 case SCF_ERROR_HANDLE_MISMATCH:
7326 case SCF_ERROR_NOT_BOUND:
7327 case SCF_ERROR_NOT_SET:
7328 default:
7329 bad_error("scf_iter_service_instances", scf_error());
7330 }
7331 }
7332
7333 for (;;) {
7334 r = scf_iter_next_instance(imp_iter, imp_inst);
7335 if (r == 0)
7336 break;
7337 if (r != 1) {
7338 switch (scf_error()) {
7339 case SCF_ERROR_DELETED:
7340 warn(s_deleted, s->sc_fmri);
7341 lcbdata->sc_err = EBUSY;
7342 r = UU_WALK_ERROR;
7343 goto deltemp;
7344
7345 case SCF_ERROR_CONNECTION_BROKEN:
7346 goto connaborted;
7347
7348 case SCF_ERROR_NOT_BOUND:
7349 case SCF_ERROR_HANDLE_MISMATCH:
7350 case SCF_ERROR_INVALID_ARGUMENT:
7351 case SCF_ERROR_NOT_SET:
7352 default:
7353 bad_error("scf_iter_next_instance",
7354 scf_error());
7355 }
7356 }
7357
7358 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
7359 switch (scf_error()) {
7360 case SCF_ERROR_DELETED:
7361 continue;
7362
7363 case SCF_ERROR_CONNECTION_BROKEN:
7364 goto connaborted;
7365
7366 case SCF_ERROR_NOT_SET:
7367 case SCF_ERROR_NOT_BOUND:
7368 default:
7369 bad_error("scf_instance_get_name", scf_error());
7370 }
7371 }
7372
7373 if (g_verbose)
7374 warn(gettext(
7375 "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
7376 snap_previous, s->sc_name, imp_str);
7377
7378 r = take_snap(imp_inst, snap_previous, imp_snap);
7379 switch (r) {
7380 case 0:
7381 break;
7382
7383 case ECANCELED:
7384 continue;
7385
7386 case ECONNABORTED:
7387 goto connaborted;
7388
7389 case EPERM:
7390 warn(gettext("Could not take \"%s\" snapshot of "
7391 "svc:/%s:%s (permission denied).\n"),
7392 snap_previous, s->sc_name, imp_str);
7393 lcbdata->sc_err = r;
7394 return (UU_WALK_ERROR);
7395
7396 case ENOSPC:
7397 case -1:
7398 lcbdata->sc_err = r;
7399 r = UU_WALK_ERROR;
7400 goto deltemp;
7401
7402 default:
7403 bad_error("take_snap", r);
7404 }
7405
7406 linst.sc_name = imp_str;
7407 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
7408 &linst, NULL, NULL);
7409 if (inst != NULL) {
7410 inst->sc_import_state = IMPORT_PREVIOUS;
7411 inst->sc_seen = 1;
7412 }
7413 }
7414
7415 /*
7416 * Create the new instances and take previous snapshots of
7417 * them. This is not necessary, but it maximizes data preservation.
7418 */
7419 for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
7420 inst != NULL;
7421 inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
7422 inst)) {
7423 if (inst->sc_seen)
7424 continue;
7425
7426 if (scf_service_add_instance(imp_svc, inst->sc_name,
7427 imp_inst) != 0) {
7428 switch (scf_error()) {
7429 case SCF_ERROR_CONNECTION_BROKEN:
7430 goto connaborted;
7431
7432 case SCF_ERROR_BACKEND_READONLY:
7433 case SCF_ERROR_BACKEND_ACCESS:
7434 case SCF_ERROR_NO_RESOURCES:
7435 r = stash_scferror(lcbdata);
7436 goto deltemp;
7437
7438 case SCF_ERROR_EXISTS:
7439 warn(gettext("%s changed unexpectedly "
7440 "(instance \"%s\" added).\n"), s->sc_fmri,
7441 inst->sc_name);
7442 lcbdata->sc_err = EBUSY;
7443 r = UU_WALK_ERROR;
7444 goto deltemp;
7445
7446 case SCF_ERROR_INVALID_ARGUMENT:
7447 warn(gettext("Service \"%s\" has instance with "
7448 "invalid name \"%s\".\n"), s->sc_name,
7449 inst->sc_name);
7450 r = stash_scferror(lcbdata);
7451 goto deltemp;
7452
7453 case SCF_ERROR_PERMISSION_DENIED:
7454 warn(gettext("Could not create instance \"%s\" "
7455 "in %s (permission denied).\n"),
7456 inst->sc_name, s->sc_fmri);
7457 r = stash_scferror(lcbdata);
7458 goto deltemp;
7459
7460 case SCF_ERROR_HANDLE_MISMATCH:
7461 case SCF_ERROR_NOT_BOUND:
7462 case SCF_ERROR_NOT_SET:
7463 default:
7464 bad_error("scf_service_add_instance",
7465 scf_error());
7466 }
7467 }
7468
7469 if (g_verbose)
7470 warn(gettext("Taking \"%s\" snapshot for "
7471 "new service %s.\n"), snap_previous, inst->sc_fmri);
7472 r = take_snap(imp_inst, snap_previous, imp_snap);
7473 switch (r) {
7474 case 0:
7475 break;
7476
7477 case ECANCELED:
7478 warn(i_deleted, s->sc_fmri, inst->sc_name);
7479 lcbdata->sc_err = EBUSY;
7480 r = UU_WALK_ERROR;
7481 goto deltemp;
7482
7483 case ECONNABORTED:
7484 goto connaborted;
7485
7486 case EPERM:
7487 warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
7488 lcbdata->sc_err = r;
7489 r = UU_WALK_ERROR;
7490 goto deltemp;
7491
7492 case ENOSPC:
7493 case -1:
7494 r = UU_WALK_ERROR;
7495 goto deltemp;
7496
7497 default:
7498 bad_error("take_snap", r);
7499 }
7500 }
7501
7502 s->sc_import_state = IMPORT_PREVIOUS;
7503
7504 /*
7505 * Upgrade service properties, if we can find a last-import snapshot.
7506 * Any will do because we don't support different service properties
7507 * in different manifests, so all snaplevels of the service in all of
7508 * the last-import snapshots of the instances should be the same.
7509 */
7510 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7511 switch (scf_error()) {
7512 case SCF_ERROR_CONNECTION_BROKEN:
7513 goto connaborted;
7514
7515 case SCF_ERROR_DELETED:
7516 warn(s_deleted, s->sc_fmri);
7517 lcbdata->sc_err = EBUSY;
7518 r = UU_WALK_ERROR;
7519 goto deltemp;
7520
7521 case SCF_ERROR_HANDLE_MISMATCH:
7522 case SCF_ERROR_NOT_BOUND:
7523 case SCF_ERROR_NOT_SET:
7524 default:
7525 bad_error("scf_iter_service_instances", scf_error());
7526 }
7527 }
7528
7529 for (;;) {
7530 r = scf_iter_next_instance(imp_iter, imp_inst);
7531 if (r == -1) {
7532 switch (scf_error()) {
7533 case SCF_ERROR_DELETED:
7534 warn(s_deleted, s->sc_fmri);
7535 lcbdata->sc_err = EBUSY;
7536 r = UU_WALK_ERROR;
7537 goto deltemp;
7538
7539 case SCF_ERROR_CONNECTION_BROKEN:
7540 goto connaborted;
7541
7542 case SCF_ERROR_NOT_BOUND:
7543 case SCF_ERROR_HANDLE_MISMATCH:
7544 case SCF_ERROR_INVALID_ARGUMENT:
7545 case SCF_ERROR_NOT_SET:
7546 default:
7547 bad_error("scf_iter_next_instance",
7548 scf_error());
7549 }
7550 }
7551
7552 if (r == 0) {
7553 /*
7554 * Didn't find any last-import snapshots. Override-
7555 * import the properties. Unless one of the instances
7556 * has a general/enabled property, in which case we're
7557 * probably running a last-import-capable svccfg for
7558 * the first time, and we should only take the
7559 * last-import snapshot.
7560 */
7561 if (have_ge) {
7562 pgroup_t *mfpg;
7563 scf_callback_t mfcbdata;
7564
7565 li_only = 1;
7566 no_refresh = 1;
7567 /*
7568 * Need to go ahead and import the manifestfiles
7569 * pg if it exists. If the last-import snapshot
7570 * upgrade code is ever removed this code can
7571 * be removed as well.
7572 */
7573 mfpg = internal_pgroup_find(s,
7574 SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
7575
7576 if (mfpg) {
7577 mfcbdata.sc_handle = g_hndl;
7578 mfcbdata.sc_parent = imp_svc;
7579 mfcbdata.sc_service = 1;
7580 mfcbdata.sc_flags = SCI_FORCE;
7581 mfcbdata.sc_source_fmri = s->sc_fmri;
7582 mfcbdata.sc_target_fmri = s->sc_fmri;
7583 if (entity_pgroup_import(mfpg,
7584 &mfcbdata) != UU_WALK_NEXT) {
7585 warn(s_mfile_upd, s->sc_fmri);
7586 r = UU_WALK_ERROR;
7587 goto deltemp;
7588 }
7589 }
7590 break;
7591 }
7592
7593 s->sc_import_state = IMPORT_PROP_BEGUN;
7594
7595 cbdata.sc_handle = g_hndl;
7596 cbdata.sc_parent = imp_svc;
7597 cbdata.sc_service = 1;
7598 cbdata.sc_flags = SCI_FORCE;
7599 cbdata.sc_source_fmri = s->sc_fmri;
7600 cbdata.sc_target_fmri = s->sc_fmri;
7601 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7602 &cbdata, UU_DEFAULT) != 0) {
7603 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7604 bad_error("uu_list_walk", uu_error());
7605 lcbdata->sc_err = cbdata.sc_err;
7606 switch (cbdata.sc_err) {
7607 case ECONNABORTED:
7608 goto connaborted;
7609
7610 case ECANCELED:
7611 warn(s_deleted, s->sc_fmri);
7612 lcbdata->sc_err = EBUSY;
7613 break;
7614
7615 case EINVAL: /* caught above */
7616 case EEXIST:
7617 bad_error("entity_pgroup_import",
7618 cbdata.sc_err);
7619 }
7620
7621 r = UU_WALK_ERROR;
7622 goto deltemp;
7623 }
7624
7625 cbdata.sc_trans = NULL;
7626 cbdata.sc_flags = 0;
7627 if (uu_list_walk(s->sc_dependents,
7628 lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
7629 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7630 bad_error("uu_list_walk", uu_error());
7631 lcbdata->sc_err = cbdata.sc_err;
7632 if (cbdata.sc_err == ECONNABORTED)
7633 goto connaborted;
7634 r = UU_WALK_ERROR;
7635 goto deltemp;
7636 }
7637 break;
7638 }
7639
7640 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
7641 imp_snap) != 0) {
7642 switch (scf_error()) {
7643 case SCF_ERROR_DELETED:
7644 continue;
7645
7646 case SCF_ERROR_NOT_FOUND:
7647 break;
7648
7649 case SCF_ERROR_CONNECTION_BROKEN:
7650 goto connaborted;
7651
7652 case SCF_ERROR_HANDLE_MISMATCH:
7653 case SCF_ERROR_NOT_BOUND:
7654 case SCF_ERROR_INVALID_ARGUMENT:
7655 case SCF_ERROR_NOT_SET:
7656 default:
7657 bad_error("scf_instance_get_snapshot",
7658 scf_error());
7659 }
7660
7661 if (have_ge)
7662 continue;
7663
7664 /*
7665 * Check for a general/enabled property. This is how
7666 * we tell whether to import if there turn out to be
7667 * no last-import snapshots.
7668 */
7669 if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
7670 imp_pg) == 0) {
7671 if (scf_pg_get_property(imp_pg,
7672 SCF_PROPERTY_ENABLED, imp_prop) == 0) {
7673 have_ge = 1;
7674 } else {
7675 switch (scf_error()) {
7676 case SCF_ERROR_DELETED:
7677 case SCF_ERROR_NOT_FOUND:
7678 continue;
7679
7680 case SCF_ERROR_INVALID_ARGUMENT:
7681 case SCF_ERROR_HANDLE_MISMATCH:
7682 case SCF_ERROR_CONNECTION_BROKEN:
7683 case SCF_ERROR_NOT_BOUND:
7684 case SCF_ERROR_NOT_SET:
7685 default:
7686 bad_error("scf_pg_get_property",
7687 scf_error());
7688 }
7689 }
7690 } else {
7691 switch (scf_error()) {
7692 case SCF_ERROR_DELETED:
7693 case SCF_ERROR_NOT_FOUND:
7694 continue;
7695
7696 case SCF_ERROR_CONNECTION_BROKEN:
7697 goto connaborted;
7698
7699 case SCF_ERROR_NOT_BOUND:
7700 case SCF_ERROR_NOT_SET:
7701 case SCF_ERROR_INVALID_ARGUMENT:
7702 case SCF_ERROR_HANDLE_MISMATCH:
7703 default:
7704 bad_error("scf_instance_get_pg",
7705 scf_error());
7706 }
7707 }
7708 continue;
7709 }
7710
7711 /* find service snaplevel */
7712 r = get_snaplevel(imp_snap, 1, imp_snpl);
7713 switch (r) {
7714 case 0:
7715 break;
7716
7717 case ECONNABORTED:
7718 goto connaborted;
7719
7720 case ECANCELED:
7721 continue;
7722
7723 case ENOENT:
7724 if (scf_instance_get_name(imp_inst, imp_str,
7725 imp_str_sz) < 0)
7726 (void) strcpy(imp_str, "?");
7727 warn(badsnap, snap_lastimport, s->sc_name, imp_str);
7728 lcbdata->sc_err = EBADF;
7729 r = UU_WALK_ERROR;
7730 goto deltemp;
7731
7732 default:
7733 bad_error("get_snaplevel", r);
7734 }
7735
7736 if (scf_instance_get_snapshot(imp_inst, snap_running,
7737 imp_rsnap) != 0) {
7738 switch (scf_error()) {
7739 case SCF_ERROR_DELETED:
7740 continue;
7741
7742 case SCF_ERROR_NOT_FOUND:
7743 break;
7744
7745 case SCF_ERROR_CONNECTION_BROKEN:
7746 goto connaborted;
7747
7748 case SCF_ERROR_INVALID_ARGUMENT:
7749 case SCF_ERROR_HANDLE_MISMATCH:
7750 case SCF_ERROR_NOT_BOUND:
7751 case SCF_ERROR_NOT_SET:
7752 default:
7753 bad_error("scf_instance_get_snapshot",
7754 scf_error());
7755 }
7756 running = NULL;
7757 } else {
7758 r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
7759 switch (r) {
7760 case 0:
7761 running = imp_rsnpl;
7762 break;
7763
7764 case ECONNABORTED:
7765 goto connaborted;
7766
7767 case ECANCELED:
7768 continue;
7769
7770 case ENOENT:
7771 if (scf_instance_get_name(imp_inst, imp_str,
7772 imp_str_sz) < 0)
7773 (void) strcpy(imp_str, "?");
7774 warn(badsnap, snap_running, s->sc_name,
7775 imp_str);
7776 lcbdata->sc_err = EBADF;
7777 r = UU_WALK_ERROR;
7778 goto deltemp;
7779
7780 default:
7781 bad_error("get_snaplevel", r);
7782 }
7783 }
7784
7785 if (g_verbose) {
7786 if (scf_instance_get_name(imp_inst, imp_str,
7787 imp_str_sz) < 0)
7788 (void) strcpy(imp_str, "?");
7789 warn(gettext("Upgrading properties of %s according to "
7790 "instance \"%s\".\n"), s->sc_fmri, imp_str);
7791 }
7792
7793 /* upgrade service properties */
7794 r = upgrade_props(imp_svc, running, imp_snpl, s);
7795 if (r == 0)
7796 break;
7797
7798 switch (r) {
7799 case ECONNABORTED:
7800 goto connaborted;
7801
7802 case ECANCELED:
7803 warn(s_deleted, s->sc_fmri);
7804 lcbdata->sc_err = EBUSY;
7805 break;
7806
7807 case ENODEV:
7808 if (scf_instance_get_name(imp_inst, imp_str,
7809 imp_str_sz) < 0)
7810 (void) strcpy(imp_str, "?");
7811 warn(i_deleted, s->sc_fmri, imp_str);
7812 lcbdata->sc_err = EBUSY;
7813 break;
7814
7815 default:
7816 lcbdata->sc_err = r;
7817 }
7818
7819 r = UU_WALK_ERROR;
7820 goto deltemp;
7821 }
7822
7823 s->sc_import_state = IMPORT_PROP_DONE;
7824
7825 instances:
7826 /* import instances */
7827 cbdata.sc_handle = lcbdata->sc_handle;
7828 cbdata.sc_parent = imp_svc;
7829 cbdata.sc_service = 1;
7830 cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7831 cbdata.sc_general = NULL;
7832
7833 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7834 lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7835 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7836 bad_error("uu_list_walk", uu_error());
7837
7838 lcbdata->sc_err = cbdata.sc_err;
7839 if (cbdata.sc_err == ECONNABORTED)
7840 goto connaborted;
7841 r = UU_WALK_ERROR;
7842 goto deltemp;
7843 }
7844
7845 s->sc_import_state = IMPORT_COMPLETE;
7846 r = UU_WALK_NEXT;
7847
7848 deltemp:
7849 /* delete temporary service */
7850 if (scf_service_delete(imp_tsvc) != 0) {
7851 switch (scf_error()) {
7852 case SCF_ERROR_DELETED:
7853 break;
7854
7855 case SCF_ERROR_CONNECTION_BROKEN:
7856 goto connaborted;
7857
7858 case SCF_ERROR_EXISTS:
7859 warn(gettext(
7860 "Could not delete svc:/%s (instances exist).\n"),
7861 imp_tsname);
7862 break;
7863
7864 case SCF_ERROR_NOT_SET:
7865 case SCF_ERROR_NOT_BOUND:
7866 default:
7867 bad_error("scf_service_delete", scf_error());
7868 }
7869 }
7870
7871 return (r);
7872
7873 connaborted:
7874 warn(gettext("Could not delete svc:/%s "
7875 "(repository connection broken).\n"), imp_tsname);
7876 lcbdata->sc_err = ECONNABORTED;
7877 return (UU_WALK_ERROR);
7878 }
7879
7880 static const char *
7881 import_progress(int st)
7882 {
7883 switch (st) {
7884 case 0:
7885 return (gettext("not reached."));
7886
7887 case IMPORT_PREVIOUS:
7888 return (gettext("previous snapshot taken."));
7889
7890 case IMPORT_PROP_BEGUN:
7891 return (gettext("some properties imported."));
7892
7893 case IMPORT_PROP_DONE:
7894 return (gettext("properties imported."));
7895
7896 case IMPORT_COMPLETE:
7897 return (gettext("imported."));
7898
7899 case IMPORT_REFRESHED:
7900 return (gettext("refresh requested."));
7901
7902 default:
7903 #ifndef NDEBUG
7904 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7905 __FILE__, __LINE__, st);
7906 #endif
7907 abort();
7908 /* NOTREACHED */
7909 }
7910 }
7911
7912 /*
7913 * Returns
7914 * 0 - success
7915 * - fmri wasn't found (error printed)
7916 * - entity was deleted (error printed)
7917 * - backend denied access (error printed)
7918 * ENOMEM - out of memory (error printed)
7919 * ECONNABORTED - repository connection broken (error printed)
7920 * EPERM - permission denied (error printed)
7921 * -1 - unknown libscf error (error printed)
7922 */
7923 static int
7924 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7925 {
7926 scf_error_t serr;
7927 void *ent;
7928 int issvc;
7929 int r;
7930
7931 const char *deleted = gettext("Could not refresh %s (deleted).\n");
7932 const char *dpt_deleted = gettext("Could not refresh %s "
7933 "(dependent \"%s\" of %s) (deleted).\n");
7934
7935 serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7936 switch (serr) {
7937 case SCF_ERROR_NONE:
7938 break;
7939
7940 case SCF_ERROR_NO_MEMORY:
7941 if (name == NULL)
7942 warn(gettext("Could not refresh %s (out of memory).\n"),
7943 fmri);
7944 else
7945 warn(gettext("Could not refresh %s "
7946 "(dependent \"%s\" of %s) (out of memory).\n"),
7947 fmri, name, d_fmri);
7948 return (ENOMEM);
7949
7950 case SCF_ERROR_NOT_FOUND:
7951 if (name == NULL)
7952 warn(deleted, fmri);
7953 else
7954 warn(dpt_deleted, fmri, name, d_fmri);
7955 return (0);
7956
7957 case SCF_ERROR_INVALID_ARGUMENT:
7958 case SCF_ERROR_CONSTRAINT_VIOLATED:
7959 default:
7960 bad_error("fmri_to_entity", serr);
7961 }
7962
7963 r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7964 switch (r) {
7965 case 0:
7966 break;
7967
7968 case ECONNABORTED:
7969 if (name != NULL)
7970 warn(gettext("Could not refresh %s "
7971 "(dependent \"%s\" of %s) "
7972 "(repository connection broken).\n"), fmri, name,
7973 d_fmri);
7974 return (r);
7975
7976 case ECANCELED:
7977 if (name == NULL)
7978 warn(deleted, fmri);
7979 else
7980 warn(dpt_deleted, fmri, name, d_fmri);
7981 return (0);
7982
7983 case EACCES:
7984 if (!g_verbose)
7985 return (0);
7986 if (name == NULL)
7987 warn(gettext("Could not refresh %s "
7988 "(backend access denied).\n"), fmri);
7989 else
7990 warn(gettext("Could not refresh %s "
7991 "(dependent \"%s\" of %s) "
7992 "(backend access denied).\n"), fmri, name, d_fmri);
7993 return (0);
7994
7995 case EPERM:
7996 if (name == NULL)
7997 warn(gettext("Could not refresh %s "
7998 "(permission denied).\n"), fmri);
7999 else
8000 warn(gettext("Could not refresh %s "
8001 "(dependent \"%s\" of %s) "
8002 "(permission denied).\n"), fmri, name, d_fmri);
8003 return (r);
8004
8005 case ENOSPC:
8006 if (name == NULL)
8007 warn(gettext("Could not refresh %s "
8008 "(repository server out of resources).\n"),
8009 fmri);
8010 else
8011 warn(gettext("Could not refresh %s "
8012 "(dependent \"%s\" of %s) "
8013 "(repository server out of resources).\n"),
8014 fmri, name, d_fmri);
8015 return (r);
8016
8017 case -1:
8018 scfwarn();
8019 return (r);
8020
8021 default:
8022 bad_error("refresh_entity", r);
8023 }
8024
8025 if (issvc)
8026 scf_service_destroy(ent);
8027 else
8028 scf_instance_destroy(ent);
8029
8030 return (0);
8031 }
8032
8033 static int
8034 alloc_imp_globals()
8035 {
8036 int r;
8037
8038 const char * const emsg_nomem = gettext("Out of memory.\n");
8039 const char * const emsg_nores =
8040 gettext("svc.configd is out of resources.\n");
8041
8042 imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
8043 max_scf_name_len : max_scf_fmri_len) + 1;
8044
8045 if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
8046 (imp_svc = scf_service_create(g_hndl)) == NULL ||
8047 (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
8048 (imp_inst = scf_instance_create(g_hndl)) == NULL ||
8049 (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
8050 (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
8051 (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
8052 (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
8053 (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
8054 (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8055 (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
8056 (imp_pg = scf_pg_create(g_hndl)) == NULL ||
8057 (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
8058 (imp_prop = scf_property_create(g_hndl)) == NULL ||
8059 (imp_iter = scf_iter_create(g_hndl)) == NULL ||
8060 (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
8061 (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
8062 (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
8063 (imp_str = malloc(imp_str_sz)) == NULL ||
8064 (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
8065 (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
8066 (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
8067 (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
8068 (ud_inst = scf_instance_create(g_hndl)) == NULL ||
8069 (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8070 (ud_pg = scf_pg_create(g_hndl)) == NULL ||
8071 (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
8072 (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
8073 (ud_prop = scf_property_create(g_hndl)) == NULL ||
8074 (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
8075 (ud_val = scf_value_create(g_hndl)) == NULL ||
8076 (ud_iter = scf_iter_create(g_hndl)) == NULL ||
8077 (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
8078 (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
8079 (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
8080 (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
8081 (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
8082 if (scf_error() == SCF_ERROR_NO_RESOURCES)
8083 warn(emsg_nores);
8084 else
8085 warn(emsg_nomem);
8086
8087 return (-1);
8088 }
8089
8090 r = load_init();
8091 switch (r) {
8092 case 0:
8093 break;
8094
8095 case ENOMEM:
8096 warn(emsg_nomem);
8097 return (-1);
8098
8099 default:
8100 bad_error("load_init", r);
8101 }
8102
8103 return (0);
8104 }
8105
8106 static void
8107 free_imp_globals()
8108 {
8109 pgroup_t *old_dpt;
8110 void *cookie;
8111
8112 load_fini();
8113
8114 free(ud_ctarg);
8115 free(ud_oldtarg);
8116 free(ud_name);
8117 ud_ctarg = ud_oldtarg = ud_name = NULL;
8118
8119 scf_transaction_destroy(ud_tx);
8120 ud_tx = NULL;
8121 scf_iter_destroy(ud_iter);
8122 scf_iter_destroy(ud_iter2);
8123 ud_iter = ud_iter2 = NULL;
8124 scf_value_destroy(ud_val);
8125 ud_val = NULL;
8126 scf_property_destroy(ud_prop);
8127 scf_property_destroy(ud_dpt_prop);
8128 ud_prop = ud_dpt_prop = NULL;
8129 scf_pg_destroy(ud_pg);
8130 scf_pg_destroy(ud_cur_depts_pg);
8131 scf_pg_destroy(ud_run_dpts_pg);
8132 ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
8133 scf_snaplevel_destroy(ud_snpl);
8134 ud_snpl = NULL;
8135 scf_instance_destroy(ud_inst);
8136 ud_inst = NULL;
8137
8138 free(imp_str);
8139 free(imp_tsname);
8140 free(imp_fe1);
8141 free(imp_fe2);
8142 imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
8143
8144 cookie = NULL;
8145 while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
8146 NULL) {
8147 free((char *)old_dpt->sc_pgroup_name);
8148 free((char *)old_dpt->sc_pgroup_fmri);
8149 internal_pgroup_free(old_dpt);
8150 }
8151 uu_list_destroy(imp_deleted_dpts);
8152
8153 scf_transaction_destroy(imp_tx);
8154 imp_tx = NULL;
8155 scf_iter_destroy(imp_iter);
8156 scf_iter_destroy(imp_rpg_iter);
8157 scf_iter_destroy(imp_up_iter);
8158 imp_iter = imp_rpg_iter = imp_up_iter = NULL;
8159 scf_property_destroy(imp_prop);
8160 imp_prop = NULL;
8161 scf_pg_destroy(imp_pg);
8162 scf_pg_destroy(imp_pg2);
8163 imp_pg = imp_pg2 = NULL;
8164 scf_snaplevel_destroy(imp_snpl);
8165 scf_snaplevel_destroy(imp_rsnpl);
8166 imp_snpl = imp_rsnpl = NULL;
8167 scf_snapshot_destroy(imp_snap);
8168 scf_snapshot_destroy(imp_lisnap);
8169 scf_snapshot_destroy(imp_tlisnap);
8170 scf_snapshot_destroy(imp_rsnap);
8171 imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
8172 scf_instance_destroy(imp_inst);
8173 scf_instance_destroy(imp_tinst);
8174 imp_inst = imp_tinst = NULL;
8175 scf_service_destroy(imp_svc);
8176 scf_service_destroy(imp_tsvc);
8177 imp_svc = imp_tsvc = NULL;
8178 scf_scope_destroy(imp_scope);
8179 imp_scope = NULL;
8180
8181 load_fini();
8182 }
8183
8184 int
8185 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
8186 {
8187 scf_callback_t cbdata;
8188 int result = 0;
8189 entity_t *svc, *inst;
8190 uu_list_t *insts;
8191 int r;
8192 pgroup_t *old_dpt;
8193 int annotation_set = 0;
8194
8195 const char * const emsg_nomem = gettext("Out of memory.\n");
8196 const char * const emsg_nores =
8197 gettext("svc.configd is out of resources.\n");
8198
8199 lscf_prep_hndl();
8200
8201 if (alloc_imp_globals())
8202 goto out;
8203
8204 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
8205 switch (scf_error()) {
8206 case SCF_ERROR_CONNECTION_BROKEN:
8207 warn(gettext("Repository connection broken.\n"));
8208 repository_teardown();
8209 result = -1;
8210 goto out;
8211
8212 case SCF_ERROR_NOT_FOUND:
8213 case SCF_ERROR_INVALID_ARGUMENT:
8214 case SCF_ERROR_NOT_BOUND:
8215 case SCF_ERROR_HANDLE_MISMATCH:
8216 default:
8217 bad_error("scf_handle_get_scope", scf_error());
8218 }
8219 }
8220
8221 /* Set up the auditing annotation. */
8222 if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
8223 annotation_set = 1;
8224 } else {
8225 switch (scf_error()) {
8226 case SCF_ERROR_CONNECTION_BROKEN:
8227 warn(gettext("Repository connection broken.\n"));
8228 repository_teardown();
8229 result = -1;
8230 goto out;
8231
8232 case SCF_ERROR_INVALID_ARGUMENT:
8233 case SCF_ERROR_NOT_BOUND:
8234 case SCF_ERROR_NO_RESOURCES:
8235 case SCF_ERROR_INTERNAL:
8236 bad_error("_scf_set_annotation", scf_error());
8237 /* NOTREACHED */
8238
8239 default:
8240 /*
8241 * Do not terminate import because of inability to
8242 * generate annotation audit event.
8243 */
8244 warn(gettext("_scf_set_annotation() unexpectedly "
8245 "failed with return code of %d\n"), scf_error());
8246 break;
8247 }
8248 }
8249
8250 /*
8251 * Clear the sc_import_state's of all services & instances so we can
8252 * report how far we got if we fail.
8253 */
8254 for (svc = uu_list_first(bndl->sc_bundle_services);
8255 svc != NULL;
8256 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8257 svc->sc_import_state = 0;
8258
8259 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
8260 clear_int, (void *)offsetof(entity_t, sc_import_state),
8261 UU_DEFAULT) != 0)
8262 bad_error("uu_list_walk", uu_error());
8263 }
8264
8265 cbdata.sc_handle = g_hndl;
8266 cbdata.sc_parent = imp_scope;
8267 cbdata.sc_flags = flags;
8268 cbdata.sc_general = NULL;
8269
8270 if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
8271 &cbdata, UU_DEFAULT) == 0) {
8272 char *eptr;
8273 /* Success. Refresh everything. */
8274
8275 if (flags & SCI_NOREFRESH || no_refresh) {
8276 no_refresh = 0;
8277 result = 0;
8278 goto out;
8279 }
8280
8281 for (svc = uu_list_first(bndl->sc_bundle_services);
8282 svc != NULL;
8283 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8284 pgroup_t *dpt;
8285
8286 insts = svc->sc_u.sc_service.sc_service_instances;
8287
8288 for (inst = uu_list_first(insts);
8289 inst != NULL;
8290 inst = uu_list_next(insts, inst)) {
8291 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
8292 switch (r) {
8293 case 0:
8294 break;
8295
8296 case ENOMEM:
8297 case ECONNABORTED:
8298 case EPERM:
8299 case -1:
8300 goto progress;
8301
8302 default:
8303 bad_error("imp_refresh_fmri", r);
8304 }
8305
8306 inst->sc_import_state = IMPORT_REFRESHED;
8307
8308 for (dpt = uu_list_first(inst->sc_dependents);
8309 dpt != NULL;
8310 dpt = uu_list_next(inst->sc_dependents,
8311 dpt))
8312 if (imp_refresh_fmri(
8313 dpt->sc_pgroup_fmri,
8314 dpt->sc_pgroup_name,
8315 inst->sc_fmri) != 0)
8316 goto progress;
8317 }
8318
8319 for (dpt = uu_list_first(svc->sc_dependents);
8320 dpt != NULL;
8321 dpt = uu_list_next(svc->sc_dependents, dpt))
8322 if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
8323 dpt->sc_pgroup_name, svc->sc_fmri) != 0)
8324 goto progress;
8325 }
8326
8327 for (old_dpt = uu_list_first(imp_deleted_dpts);
8328 old_dpt != NULL;
8329 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
8330 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8331 old_dpt->sc_pgroup_name,
8332 old_dpt->sc_parent->sc_fmri) != 0)
8333 goto progress;
8334
8335 result = 0;
8336
8337 /*
8338 * This snippet of code assumes that we are running svccfg as we
8339 * normally do -- witih svc.startd running. Of course, that is
8340 * not actually the case all the time because we also use a
8341 * varient of svc.configd and svccfg which are only meant to
8342 * run during the build process. During this time we have no
8343 * svc.startd, so this check would hang the build process.
8344 *
8345 * However, we've also given other consolidations, a bit of a
8346 * means to tie themselves into a knot. They're not properly
8347 * using the native build equivalents, but they've been getting
8348 * away with it anyways. Therefore, if we've found that
8349 * SVCCFG_REPOSITORY is set indicating that a separate configd
8350 * should be spun up, then we have to assume it's not using a
8351 * startd and we should not do this check.
8352 */
8353 #ifndef NATIVE_BUILD
8354 /*
8355 * Verify that the restarter group is preset
8356 */
8357 eptr = getenv("SVCCFG_REPOSITORY");
8358 for (svc = uu_list_first(bndl->sc_bundle_services);
8359 svc != NULL && eptr == NULL;
8360 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8361
8362 insts = svc->sc_u.sc_service.sc_service_instances;
8363
8364 for (inst = uu_list_first(insts);
8365 inst != NULL;
8366 inst = uu_list_next(insts, inst)) {
8367 if (lscf_instance_verify(imp_scope, svc,
8368 inst) != 0)
8369 goto progress;
8370 }
8371 }
8372 #endif
8373 goto out;
8374
8375 }
8376
8377 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8378 bad_error("uu_list_walk", uu_error());
8379
8380 printerr:
8381 /* If the error hasn't been printed yet, do so here. */
8382 switch (cbdata.sc_err) {
8383 case ECONNABORTED:
8384 warn(gettext("Repository connection broken.\n"));
8385 break;
8386
8387 case ENOMEM:
8388 warn(emsg_nomem);
8389 break;
8390
8391 case ENOSPC:
8392 warn(emsg_nores);
8393 break;
8394
8395 case EROFS:
8396 warn(gettext("Repository is read-only.\n"));
8397 break;
8398
8399 case EACCES:
8400 warn(gettext("Repository backend denied access.\n"));
8401 break;
8402
8403 case EPERM:
8404 case EINVAL:
8405 case EEXIST:
8406 case EBUSY:
8407 case EBADF:
8408 case -1:
8409 break;
8410
8411 default:
8412 bad_error("lscf_service_import", cbdata.sc_err);
8413 }
8414
8415 progress:
8416 warn(gettext("Import of %s failed. Progress:\n"), filename);
8417
8418 for (svc = uu_list_first(bndl->sc_bundle_services);
8419 svc != NULL;
8420 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8421 insts = svc->sc_u.sc_service.sc_service_instances;
8422
8423 warn(gettext(" Service \"%s\": %s\n"), svc->sc_name,
8424 import_progress(svc->sc_import_state));
8425
8426 for (inst = uu_list_first(insts);
8427 inst != NULL;
8428 inst = uu_list_next(insts, inst))
8429 warn(gettext(" Instance \"%s\": %s\n"),
8430 inst->sc_name,
8431 import_progress(inst->sc_import_state));
8432 }
8433
8434 if (cbdata.sc_err == ECONNABORTED)
8435 repository_teardown();
8436
8437
8438 result = -1;
8439
8440 out:
8441 if (annotation_set != 0) {
8442 /* Turn off annotation. It is no longer needed. */
8443 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8444 }
8445
8446 free_imp_globals();
8447
8448 return (result);
8449 }
8450
8451 /*
8452 * _lscf_import_err() summarize the error handling returned by
8453 * lscf_import_{instance | service}_pgs
8454 * Return values are:
8455 * IMPORT_NEXT
8456 * IMPORT_OUT
8457 * IMPORT_BAD
8458 */
8459
8460 #define IMPORT_BAD -1
8461 #define IMPORT_NEXT 0
8462 #define IMPORT_OUT 1
8463
8464 static int
8465 _lscf_import_err(int err, const char *fmri)
8466 {
8467 switch (err) {
8468 case 0:
8469 if (g_verbose)
8470 warn(gettext("%s updated.\n"), fmri);
8471 return (IMPORT_NEXT);
8472
8473 case ECONNABORTED:
8474 warn(gettext("Could not update %s "
8475 "(repository connection broken).\n"), fmri);
8476 return (IMPORT_OUT);
8477
8478 case ENOMEM:
8479 warn(gettext("Could not update %s (out of memory).\n"), fmri);
8480 return (IMPORT_OUT);
8481
8482 case ENOSPC:
8483 warn(gettext("Could not update %s "
8484 "(repository server out of resources).\n"), fmri);
8485 return (IMPORT_OUT);
8486
8487 case ECANCELED:
8488 warn(gettext(
8489 "Could not update %s (deleted).\n"), fmri);
8490 return (IMPORT_NEXT);
8491
8492 case EPERM:
8493 case EINVAL:
8494 case EBUSY:
8495 return (IMPORT_NEXT);
8496
8497 case EROFS:
8498 warn(gettext("Could not update %s (repository read-only).\n"),
8499 fmri);
8500 return (IMPORT_OUT);
8501
8502 case EACCES:
8503 warn(gettext("Could not update %s "
8504 "(backend access denied).\n"), fmri);
8505 return (IMPORT_NEXT);
8506
8507 case EEXIST:
8508 default:
8509 return (IMPORT_BAD);
8510 }
8511
8512 /*NOTREACHED*/
8513 }
8514
8515 /*
8516 * The global imp_svc and imp_inst should be set by the caller in the
8517 * check to make sure the service and instance exist that the apply is
8518 * working on.
8519 */
8520 static int
8521 lscf_dependent_apply(void *dpg, void *e)
8522 {
8523 scf_callback_t cb;
8524 pgroup_t *dpt_pgroup = dpg;
8525 pgroup_t *deldpt;
8526 entity_t *ent = e;
8527 int tissvc;
8528 void *sc_ent, *tent;
8529 scf_error_t serr;
8530 int r;
8531
8532 const char * const dependents = "dependents";
8533 const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT);
8534
8535 if (issvc)
8536 sc_ent = imp_svc;
8537 else
8538 sc_ent = imp_inst;
8539
8540 if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg,
8541 imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 ||
8542 scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name,
8543 imp_prop) != 0) {
8544 switch (scf_error()) {
8545 case SCF_ERROR_NOT_FOUND:
8546 case SCF_ERROR_DELETED:
8547 break;
8548
8549 case SCF_ERROR_CONNECTION_BROKEN:
8550 case SCF_ERROR_NOT_SET:
8551 case SCF_ERROR_INVALID_ARGUMENT:
8552 case SCF_ERROR_HANDLE_MISMATCH:
8553 case SCF_ERROR_NOT_BOUND:
8554 default:
8555 bad_error("entity_get_pg", scf_error());
8556 }
8557 } else {
8558 /*
8559 * Found the dependents/<wip dep> so check to
8560 * see if the service is different. If so
8561 * store the service for later refresh, and
8562 * delete the wip dependency from the service
8563 */
8564 if (scf_property_get_value(imp_prop, ud_val) != 0) {
8565 switch (scf_error()) {
8566 case SCF_ERROR_DELETED:
8567 break;
8568
8569 case SCF_ERROR_CONNECTION_BROKEN:
8570 case SCF_ERROR_NOT_SET:
8571 case SCF_ERROR_INVALID_ARGUMENT:
8572 case SCF_ERROR_HANDLE_MISMATCH:
8573 case SCF_ERROR_NOT_BOUND:
8574 default:
8575 bad_error("scf_property_get_value",
8576 scf_error());
8577 }
8578 }
8579
8580 if (scf_value_get_as_string(ud_val, ud_oldtarg,
8581 max_scf_value_len + 1) < 0)
8582 bad_error("scf_value_get_as_string", scf_error());
8583
8584 r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
8585 switch (r) {
8586 case 1:
8587 break;
8588 case 0:
8589 if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent,
8590 &tissvc)) != SCF_ERROR_NONE) {
8591 if (serr == SCF_ERROR_NOT_FOUND) {
8592 break;
8593 } else {
8594 bad_error("fmri_to_entity", serr);
8595 }
8596 }
8597
8598 if (entity_get_pg(tent, tissvc,
8599 dpt_pgroup->sc_pgroup_name, imp_pg) != 0) {
8600 serr = scf_error();
8601 if (serr == SCF_ERROR_NOT_FOUND ||
8602 serr == SCF_ERROR_DELETED) {
8603 break;
8604 } else {
8605 bad_error("entity_get_pg", scf_error());
8606 }
8607 }
8608
8609 if (scf_pg_delete(imp_pg) != 0) {
8610 serr = scf_error();
8611 if (serr == SCF_ERROR_NOT_FOUND ||
8612 serr == SCF_ERROR_DELETED) {
8613 break;
8614 } else {
8615 bad_error("scf_pg_delete", scf_error());
8616 }
8617 }
8618
8619 deldpt = internal_pgroup_new();
8620 if (deldpt == NULL)
8621 return (ENOMEM);
8622 deldpt->sc_pgroup_name =
8623 strdup(dpt_pgroup->sc_pgroup_name);
8624 deldpt->sc_pgroup_fmri = strdup(ud_oldtarg);
8625 if (deldpt->sc_pgroup_name == NULL ||
8626 deldpt->sc_pgroup_fmri == NULL)
8627 return (ENOMEM);
8628 deldpt->sc_parent = (entity_t *)ent;
8629 if (uu_list_insert_after(imp_deleted_dpts, NULL,
8630 deldpt) != 0)
8631 uu_die(gettext("libuutil error: %s\n"),
8632 uu_strerror(uu_error()));
8633
8634 break;
8635 default:
8636 bad_error("fmri_equal", r);
8637 }
8638 }
8639
8640 cb.sc_handle = g_hndl;
8641 cb.sc_parent = ent;
8642 cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT;
8643 cb.sc_source_fmri = ent->sc_fmri;
8644 cb.sc_target_fmri = ent->sc_fmri;
8645 cb.sc_trans = NULL;
8646 cb.sc_flags = SCI_FORCE;
8647
8648 if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT)
8649 return (UU_WALK_ERROR);
8650
8651 r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL);
8652 switch (r) {
8653 case 0:
8654 break;
8655
8656 case ENOMEM:
8657 case ECONNABORTED:
8658 case EPERM:
8659 case -1:
8660 warn(gettext("Unable to refresh \"%s\"\n"),
8661 dpt_pgroup->sc_pgroup_fmri);
8662 return (UU_WALK_ERROR);
8663
8664 default:
8665 bad_error("imp_refresh_fmri", r);
8666 }
8667
8668 return (UU_WALK_NEXT);
8669 }
8670
8671 /*
8672 * Returns
8673 * 0 - success
8674 * -1 - lscf_import_instance_pgs() failed.
8675 */
8676 int
8677 lscf_bundle_apply(bundle_t *bndl, const char *file)
8678 {
8679 pgroup_t *old_dpt;
8680 entity_t *svc, *inst;
8681 int annotation_set = 0;
8682 int ret = 0;
8683 int r = 0;
8684
8685 lscf_prep_hndl();
8686
8687 if ((ret = alloc_imp_globals()))
8688 goto out;
8689
8690 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0)
8691 scfdie();
8692
8693 /*
8694 * Set the strings to be used for the security audit annotation
8695 * event.
8696 */
8697 if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
8698 annotation_set = 1;
8699 } else {
8700 switch (scf_error()) {
8701 case SCF_ERROR_CONNECTION_BROKEN:
8702 warn(gettext("Repository connection broken.\n"));
8703 goto out;
8704
8705 case SCF_ERROR_INVALID_ARGUMENT:
8706 case SCF_ERROR_NOT_BOUND:
8707 case SCF_ERROR_NO_RESOURCES:
8708 case SCF_ERROR_INTERNAL:
8709 bad_error("_scf_set_annotation", scf_error());
8710 /* NOTREACHED */
8711
8712 default:
8713 /*
8714 * Do not abort apply operation because of
8715 * inability to create annotation audit event.
8716 */
8717 warn(gettext("_scf_set_annotation() unexpectedly "
8718 "failed with return code of %d\n"), scf_error());
8719 break;
8720 }
8721 }
8722
8723 for (svc = uu_list_first(bndl->sc_bundle_services);
8724 svc != NULL;
8725 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8726 int refresh = 0;
8727
8728 if (scf_scope_get_service(imp_scope, svc->sc_name,
8729 imp_svc) != 0) {
8730 switch (scf_error()) {
8731 case SCF_ERROR_NOT_FOUND:
8732 if (g_verbose)
8733 warn(gettext("Ignoring nonexistent "
8734 "service %s.\n"), svc->sc_name);
8735 continue;
8736
8737 default:
8738 scfdie();
8739 }
8740 }
8741
8742 /*
8743 * If there were missing types in the profile, then need to
8744 * attempt to find the types.
8745 */
8746 if (svc->sc_miss_type) {
8747 if (uu_list_numnodes(svc->sc_pgroups) &&
8748 uu_list_walk(svc->sc_pgroups, find_current_pg_type,
8749 svc, UU_DEFAULT) != 0) {
8750 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8751 bad_error("uu_list_walk", uu_error());
8752
8753 ret = -1;
8754 continue;
8755 }
8756
8757 for (inst = uu_list_first(
8758 svc->sc_u.sc_service.sc_service_instances);
8759 inst != NULL;
8760 inst = uu_list_next(
8761 svc->sc_u.sc_service.sc_service_instances, inst)) {
8762 /*
8763 * If the instance doesn't exist just
8764 * skip to the next instance and let the
8765 * import note the missing instance.
8766 */
8767 if (scf_service_get_instance(imp_svc,
8768 inst->sc_name, imp_inst) != 0)
8769 continue;
8770
8771 if (uu_list_walk(inst->sc_pgroups,
8772 find_current_pg_type, inst,
8773 UU_DEFAULT) != 0) {
8774 if (uu_error() !=
8775 UU_ERROR_CALLBACK_FAILED)
8776 bad_error("uu_list_walk",
8777 uu_error());
8778
8779 ret = -1;
8780 inst->sc_miss_type = B_TRUE;
8781 }
8782 }
8783 }
8784
8785 /*
8786 * if we have pgs in the profile, we need to refresh ALL
8787 * instances of the service
8788 */
8789 if (uu_list_numnodes(svc->sc_pgroups) != 0) {
8790 refresh = 1;
8791 r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc,
8792 SCI_FORCE | SCI_KEEP);
8793 switch (_lscf_import_err(r, svc->sc_fmri)) {
8794 case IMPORT_NEXT:
8795 break;
8796
8797 case IMPORT_OUT:
8798 goto out;
8799
8800 case IMPORT_BAD:
8801 default:
8802 bad_error("lscf_import_service_pgs", r);
8803 }
8804 }
8805
8806 if (uu_list_numnodes(svc->sc_dependents) != 0) {
8807 uu_list_walk(svc->sc_dependents,
8808 lscf_dependent_apply, svc, UU_DEFAULT);
8809 }
8810
8811 for (inst = uu_list_first(
8812 svc->sc_u.sc_service.sc_service_instances);
8813 inst != NULL;
8814 inst = uu_list_next(
8815 svc->sc_u.sc_service.sc_service_instances, inst)) {
8816 /*
8817 * This instance still has missing types
8818 * so skip it.
8819 */
8820 if (inst->sc_miss_type) {
8821 if (g_verbose)
8822 warn(gettext("Ignoring instance "
8823 "%s:%s with missing types\n"),
8824 inst->sc_parent->sc_name,
8825 inst->sc_name);
8826
8827 continue;
8828 }
8829
8830 if (scf_service_get_instance(imp_svc, inst->sc_name,
8831 imp_inst) != 0) {
8832 switch (scf_error()) {
8833 case SCF_ERROR_NOT_FOUND:
8834 if (g_verbose)
8835 warn(gettext("Ignoring "
8836 "nonexistant instance "
8837 "%s:%s.\n"),
8838 inst->sc_parent->sc_name,
8839 inst->sc_name);
8840 continue;
8841
8842 default:
8843 scfdie();
8844 }
8845 }
8846
8847 /*
8848 * If the instance does not have a general/enabled
8849 * property and no last-import snapshot then the
8850 * instance is not a fully installed instance and
8851 * should not have a profile applied to it.
8852 *
8853 * This could happen if a service/instance declares
8854 * a dependent on behalf of another service/instance.
8855 *
8856 */
8857 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
8858 imp_snap) != 0) {
8859 if (scf_instance_get_pg(imp_inst,
8860 SCF_PG_GENERAL, imp_pg) != 0 ||
8861 scf_pg_get_property(imp_pg,
8862 SCF_PROPERTY_ENABLED, imp_prop) != 0) {
8863 if (g_verbose)
8864 warn(gettext("Ignoreing "
8865 "partial instance "
8866 "%s:%s.\n"),
8867 inst->sc_parent->sc_name,
8868 inst->sc_name);
8869 continue;
8870 }
8871 }
8872
8873 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri,
8874 inst, SCI_FORCE | SCI_KEEP);
8875 switch (_lscf_import_err(r, inst->sc_fmri)) {
8876 case IMPORT_NEXT:
8877 break;
8878
8879 case IMPORT_OUT:
8880 goto out;
8881
8882 case IMPORT_BAD:
8883 default:
8884 bad_error("lscf_import_instance_pgs", r);
8885 }
8886
8887 if (uu_list_numnodes(inst->sc_dependents) != 0) {
8888 uu_list_walk(inst->sc_dependents,
8889 lscf_dependent_apply, inst, UU_DEFAULT);
8890 }
8891
8892 /* refresh only if there is no pgs in the service */
8893 if (refresh == 0)
8894 (void) refresh_entity(0, imp_inst,
8895 inst->sc_fmri, NULL, NULL, NULL);
8896 }
8897
8898 if (refresh == 1) {
8899 char *name_buf = safe_malloc(max_scf_name_len + 1);
8900
8901 (void) refresh_entity(1, imp_svc, svc->sc_name,
8902 imp_inst, imp_iter, name_buf);
8903 free(name_buf);
8904 }
8905
8906 for (old_dpt = uu_list_first(imp_deleted_dpts);
8907 old_dpt != NULL;
8908 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) {
8909 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8910 old_dpt->sc_pgroup_name,
8911 old_dpt->sc_parent->sc_fmri) != 0) {
8912 warn(gettext("Unable to refresh \"%s\"\n"),
8913 old_dpt->sc_pgroup_fmri);
8914 }
8915 }
8916 }
8917
8918 out:
8919 if (annotation_set) {
8920 /* Remove security audit annotation strings. */
8921 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8922 }
8923
8924 free_imp_globals();
8925 return (ret);
8926 }
8927
8928
8929 /*
8930 * Export. These functions create and output an XML tree of a service
8931 * description from the repository. This is largely the inverse of
8932 * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
8933 *
8934 * - We must include any properties which are not represented specifically by
8935 * a service manifest, e.g., properties created by an admin post-import. To
8936 * do so we'll iterate through all properties and deal with each
8937 * apropriately.
8938 *
8939 * - Children of services and instances must must be in the order set by the
8940 * DTD, but we iterate over the properties in undefined order. The elements
8941 * are not easily (or efficiently) sortable by name. Since there's a fixed
8942 * number of classes of them, however, we'll keep the classes separate and
8943 * assemble them in order.
8944 */
8945
8946 /*
8947 * Convenience function to handle xmlSetProp errors (and type casting).
8948 */
8949 static void
8950 safe_setprop(xmlNodePtr n, const char *name, const char *val)
8951 {
8952 if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
8953 uu_die(gettext("Could not set XML property.\n"));
8954 }
8955
8956 /*
8957 * Convenience function to set an XML attribute to the single value of an
8958 * astring property. If the value happens to be the default, don't set the
8959 * attribute. "dval" should be the default value supplied by the DTD, or
8960 * NULL for no default.
8961 */
8962 static int
8963 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
8964 const char *name, const char *dval)
8965 {
8966 scf_value_t *val;
8967 ssize_t len;
8968 char *str;
8969
8970 val = scf_value_create(g_hndl);
8971 if (val == NULL)
8972 scfdie();
8973
8974 if (prop_get_val(prop, val) != 0) {
8975 scf_value_destroy(val);
8976 return (-1);
8977 }
8978
8979 len = scf_value_get_as_string(val, NULL, 0);
8980 if (len < 0)
8981 scfdie();
8982
8983 str = safe_malloc(len + 1);
8984
8985 if (scf_value_get_as_string(val, str, len + 1) < 0)
8986 scfdie();
8987
8988 scf_value_destroy(val);
8989
8990 if (dval == NULL || strcmp(str, dval) != 0)
8991 safe_setprop(n, name, str);
8992
8993 free(str);
8994
8995 return (0);
8996 }
8997
8998 /*
8999 * As above, but the attribute is always set.
9000 */
9001 static int
9002 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
9003 {
9004 return (set_attr_from_prop_default(prop, n, name, NULL));
9005 }
9006
9007 /*
9008 * Dump the given document onto f, with "'s replaced by ''s.
9009 */
9010 static int
9011 write_service_bundle(xmlDocPtr doc, FILE *f)
9012 {
9013 xmlChar *mem;
9014 int sz, i;
9015
9016 mem = NULL;
9017 xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
9018
9019 if (mem == NULL) {
9020 semerr(gettext("Could not dump XML tree.\n"));
9021 return (-1);
9022 }
9023
9024 /*
9025 * Fortunately libxml produces " instead of ", so we can blindly
9026 * replace all " with '. Cursed libxml2! Why must you #ifdef out the
9027 * ' code?!
9028 */
9029 for (i = 0; i < sz; ++i) {
9030 char c = (char)mem[i];
9031
9032 if (c == '"')
9033 (void) fputc('\'', f);
9034 else if (c == '\'')
9035 (void) fwrite("'", sizeof ("'") - 1, 1, f);
9036 else
9037 (void) fputc(c, f);
9038 }
9039
9040 return (0);
9041 }
9042
9043 /*
9044 * Create the DOM elements in elts necessary to (generically) represent prop
9045 * (i.e., a property or propval element). If the name of the property is
9046 * known, it should be passed as name_arg. Otherwise, pass NULL.
9047 */
9048 static void
9049 export_property(scf_property_t *prop, const char *name_arg,
9050 struct pg_elts *elts, int flags)
9051 {
9052 const char *type;
9053 scf_error_t err = 0;
9054 xmlNodePtr pnode, lnode;
9055 char *lnname;
9056 int ret;
9057
9058 /* name */
9059 if (name_arg != NULL) {
9060 (void) strcpy(exp_str, name_arg);
9061 } else {
9062 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
9063 scfdie();
9064 }
9065
9066 /* type */
9067 type = prop_to_typestr(prop);
9068 if (type == NULL)
9069 uu_die(gettext("Can't export property %s: unknown type.\n"),
9070 exp_str);
9071
9072 /* If we're exporting values, and there's just one, export it here. */
9073 if (!(flags & SCE_ALL_VALUES))
9074 goto empty;
9075
9076 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
9077 xmlNodePtr n;
9078
9079 /* Single value, so use propval */
9080 n = xmlNewNode(NULL, (xmlChar *)"propval");
9081 if (n == NULL)
9082 uu_die(emsg_create_xml);
9083
9084 safe_setprop(n, name_attr, exp_str);
9085 safe_setprop(n, type_attr, type);
9086
9087 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9088 scfdie();
9089 safe_setprop(n, value_attr, exp_str);
9090
9091 if (elts->propvals == NULL)
9092 elts->propvals = n;
9093 else
9094 (void) xmlAddSibling(elts->propvals, n);
9095
9096 return;
9097 }
9098
9099 err = scf_error();
9100
9101 if (err == SCF_ERROR_PERMISSION_DENIED) {
9102 semerr(emsg_permission_denied);
9103 return;
9104 }
9105
9106 if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
9107 err != SCF_ERROR_NOT_FOUND &&
9108 err != SCF_ERROR_PERMISSION_DENIED)
9109 scfdie();
9110
9111 empty:
9112 /* Multiple (or no) values, so use property */
9113 pnode = xmlNewNode(NULL, (xmlChar *)"property");
9114 if (pnode == NULL)
9115 uu_die(emsg_create_xml);
9116
9117 safe_setprop(pnode, name_attr, exp_str);
9118 safe_setprop(pnode, type_attr, type);
9119
9120 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
9121 lnname = uu_msprintf("%s_list", type);
9122 if (lnname == NULL)
9123 uu_die(gettext("Could not create string"));
9124
9125 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
9126 if (lnode == NULL)
9127 uu_die(emsg_create_xml);
9128
9129 uu_free(lnname);
9130
9131 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
9132 scfdie();
9133
9134 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
9135 1) {
9136 xmlNodePtr vn;
9137
9138 vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
9139 NULL);
9140 if (vn == NULL)
9141 uu_die(emsg_create_xml);
9142
9143 if (scf_value_get_as_string(exp_val, exp_str,
9144 exp_str_sz) < 0)
9145 scfdie();
9146 safe_setprop(vn, value_attr, exp_str);
9147 }
9148 if (ret != 0)
9149 scfdie();
9150 }
9151
9152 if (elts->properties == NULL)
9153 elts->properties = pnode;
9154 else
9155 (void) xmlAddSibling(elts->properties, pnode);
9156 }
9157
9158 /*
9159 * Add a property_group element for this property group to elts.
9160 */
9161 static void
9162 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
9163 {
9164 xmlNodePtr n;
9165 struct pg_elts elts;
9166 int ret;
9167 boolean_t read_protected;
9168
9169 n = xmlNewNode(NULL, (xmlChar *)"property_group");
9170
9171 /* name */
9172 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9173 scfdie();
9174 safe_setprop(n, name_attr, exp_str);
9175
9176 /* type */
9177 if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
9178 scfdie();
9179 safe_setprop(n, type_attr, exp_str);
9180
9181 /* properties */
9182 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9183 scfdie();
9184
9185 (void) memset(&elts, 0, sizeof (elts));
9186
9187 /*
9188 * If this property group is not read protected, we always want to
9189 * output all the values. Otherwise, we only output the values if the
9190 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
9191 */
9192 if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
9193 scfdie();
9194
9195 if (!read_protected)
9196 flags |= SCE_ALL_VALUES;
9197
9198 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9199 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9200 scfdie();
9201
9202 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9203 xmlNodePtr m;
9204
9205 m = xmlNewNode(NULL, (xmlChar *)"stability");
9206 if (m == NULL)
9207 uu_die(emsg_create_xml);
9208
9209 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9210 elts.stability = m;
9211 continue;
9212 }
9213
9214 xmlFreeNode(m);
9215 }
9216
9217 export_property(exp_prop, NULL, &elts, flags);
9218 }
9219 if (ret == -1)
9220 scfdie();
9221
9222 (void) xmlAddChild(n, elts.stability);
9223 (void) xmlAddChildList(n, elts.propvals);
9224 (void) xmlAddChildList(n, elts.properties);
9225
9226 if (eelts->property_groups == NULL)
9227 eelts->property_groups = n;
9228 else
9229 (void) xmlAddSibling(eelts->property_groups, n);
9230 }
9231
9232 /*
9233 * Create an XML node representing the dependency described by the given
9234 * property group and put it in eelts. Unless the dependency is not valid, in
9235 * which case create a generic property_group element which represents it and
9236 * put it in eelts.
9237 */
9238 static void
9239 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
9240 {
9241 xmlNodePtr n;
9242 int err = 0, ret;
9243 struct pg_elts elts;
9244
9245 n = xmlNewNode(NULL, (xmlChar *)"dependency");
9246 if (n == NULL)
9247 uu_die(emsg_create_xml);
9248
9249 /*
9250 * If the external flag is present, skip this dependency because it
9251 * should have been created by another manifest.
9252 */
9253 if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
9254 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9255 prop_get_val(exp_prop, exp_val) == 0) {
9256 uint8_t b;
9257
9258 if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
9259 scfdie();
9260
9261 if (b)
9262 return;
9263 }
9264 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
9265 scfdie();
9266
9267 /* Get the required attributes. */
9268
9269 /* name */
9270 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9271 scfdie();
9272 safe_setprop(n, name_attr, exp_str);
9273
9274 /* grouping */
9275 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9276 set_attr_from_prop(exp_prop, n, "grouping") != 0)
9277 err = 1;
9278
9279 /* restart_on */
9280 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9281 set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9282 err = 1;
9283
9284 /* type */
9285 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9286 set_attr_from_prop(exp_prop, n, type_attr) != 0)
9287 err = 1;
9288
9289 /*
9290 * entities: Not required, but if we create no children, it will be
9291 * created as empty on import, so fail if it's missing.
9292 */
9293 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9294 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
9295 scf_iter_t *eiter;
9296 int ret2;
9297
9298 eiter = scf_iter_create(g_hndl);
9299 if (eiter == NULL)
9300 scfdie();
9301
9302 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
9303 scfdie();
9304
9305 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
9306 xmlNodePtr ch;
9307
9308 if (scf_value_get_astring(exp_val, exp_str,
9309 exp_str_sz) < 0)
9310 scfdie();
9311
9312 /*
9313 * service_fmri's must be first, so we can add them
9314 * here.
9315 */
9316 ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
9317 NULL);
9318 if (ch == NULL)
9319 uu_die(emsg_create_xml);
9320
9321 safe_setprop(ch, value_attr, exp_str);
9322 }
9323 if (ret2 == -1)
9324 scfdie();
9325
9326 scf_iter_destroy(eiter);
9327 } else
9328 err = 1;
9329
9330 if (err) {
9331 xmlFreeNode(n);
9332
9333 export_pg(pg, eelts, SCE_ALL_VALUES);
9334
9335 return;
9336 }
9337
9338 /* Iterate through the properties & handle each. */
9339 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9340 scfdie();
9341
9342 (void) memset(&elts, 0, sizeof (elts));
9343
9344 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9345 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9346 scfdie();
9347
9348 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9349 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9350 strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9351 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9352 continue;
9353 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9354 xmlNodePtr m;
9355
9356 m = xmlNewNode(NULL, (xmlChar *)"stability");
9357 if (m == NULL)
9358 uu_die(emsg_create_xml);
9359
9360 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9361 elts.stability = m;
9362 continue;
9363 }
9364
9365 xmlFreeNode(m);
9366 }
9367
9368 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9369 }
9370 if (ret == -1)
9371 scfdie();
9372
9373 (void) xmlAddChild(n, elts.stability);
9374 (void) xmlAddChildList(n, elts.propvals);
9375 (void) xmlAddChildList(n, elts.properties);
9376
9377 if (eelts->dependencies == NULL)
9378 eelts->dependencies = n;
9379 else
9380 (void) xmlAddSibling(eelts->dependencies, n);
9381 }
9382
9383 static xmlNodePtr
9384 export_method_environment(scf_propertygroup_t *pg)
9385 {
9386 xmlNodePtr env;
9387 int ret;
9388 int children = 0;
9389
9390 if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
9391 return (NULL);
9392
9393 env = xmlNewNode(NULL, (xmlChar *)"method_environment");
9394 if (env == NULL)
9395 uu_die(emsg_create_xml);
9396
9397 if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
9398 scfdie();
9399
9400 if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
9401 scfdie();
9402
9403 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
9404 xmlNodePtr ev;
9405 char *cp;
9406
9407 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9408 scfdie();
9409
9410 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
9411 warn(gettext("Invalid environment variable \"%s\".\n"),
9412 exp_str);
9413 continue;
9414 } else if (strncmp(exp_str, "SMF_", 4) == 0) {
9415 warn(gettext("Invalid environment variable \"%s\"; "
9416 "\"SMF_\" prefix is reserved.\n"), exp_str);
9417 continue;
9418 }
9419
9420 *cp = '\0';
9421 cp++;
9422
9423 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
9424 if (ev == NULL)
9425 uu_die(emsg_create_xml);
9426
9427 safe_setprop(ev, name_attr, exp_str);
9428 safe_setprop(ev, value_attr, cp);
9429 children++;
9430 }
9431
9432 if (ret != 0)
9433 scfdie();
9434
9435 if (children == 0) {
9436 xmlFreeNode(env);
9437 return (NULL);
9438 }
9439
9440 return (env);
9441 }
9442
9443 /*
9444 * As above, but for a method property group.
9445 */
9446 static void
9447 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
9448 {
9449 xmlNodePtr n, env;
9450 char *str;
9451 int err = 0, nonenv, ret;
9452 uint8_t use_profile;
9453 struct pg_elts elts;
9454 xmlNodePtr ctxt = NULL;
9455
9456 n = xmlNewNode(NULL, (xmlChar *)"exec_method");
9457
9458 /* Get the required attributes. */
9459
9460 /* name */
9461 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9462 scfdie();
9463 safe_setprop(n, name_attr, exp_str);
9464
9465 /* type */
9466 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9467 set_attr_from_prop(exp_prop, n, type_attr) != 0)
9468 err = 1;
9469
9470 /* exec */
9471 if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
9472 set_attr_from_prop(exp_prop, n, "exec") != 0)
9473 err = 1;
9474
9475 /* timeout */
9476 if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
9477 prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
9478 prop_get_val(exp_prop, exp_val) == 0) {
9479 uint64_t c;
9480
9481 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
9482 scfdie();
9483
9484 str = uu_msprintf("%llu", c);
9485 if (str == NULL)
9486 uu_die(gettext("Could not create string"));
9487
9488 safe_setprop(n, "timeout_seconds", str);
9489 free(str);
9490 } else
9491 err = 1;
9492
9493 if (err) {
9494 xmlFreeNode(n);
9495
9496 export_pg(pg, eelts, SCE_ALL_VALUES);
9497
9498 return;
9499 }
9500
9501
9502 /*
9503 * If we're going to have a method_context child, we need to know
9504 * before we iterate through the properties. Since method_context's
9505 * are optional, we don't want to complain about any properties
9506 * missing if none of them are there. Thus we can't use the
9507 * convenience functions.
9508 */
9509 nonenv =
9510 scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
9511 SCF_SUCCESS ||
9512 scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
9513 SCF_SUCCESS ||
9514 scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
9515 SCF_SUCCESS ||
9516 scf_pg_get_property(pg, SCF_PROPERTY_SECFLAGS, NULL) ==
9517 SCF_SUCCESS ||
9518 scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
9519 SCF_SUCCESS;
9520
9521 if (nonenv) {
9522 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9523 if (ctxt == NULL)
9524 uu_die(emsg_create_xml);
9525
9526 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
9527 0 &&
9528 set_attr_from_prop_default(exp_prop, ctxt,
9529 "working_directory", ":default") != 0)
9530 err = 1;
9531
9532 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
9533 set_attr_from_prop_default(exp_prop, ctxt, "project",
9534 ":default") != 0)
9535 err = 1;
9536
9537 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
9538 0 &&
9539 set_attr_from_prop_default(exp_prop, ctxt,
9540 "resource_pool", ":default") != 0)
9541 err = 1;
9542
9543 if (pg_get_prop(pg, SCF_PROPERTY_SECFLAGS, exp_prop) == 0 &&
9544 set_attr_from_prop_default(exp_prop, ctxt,
9545 "security_flags", ":default") != 0)
9546 err = 1;
9547
9548 /*
9549 * We only want to complain about profile or credential
9550 * properties if we will use them. To determine that we must
9551 * examine USE_PROFILE.
9552 */
9553 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9554 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9555 prop_get_val(exp_prop, exp_val) == 0) {
9556 if (scf_value_get_boolean(exp_val, &use_profile) !=
9557 SCF_SUCCESS) {
9558 scfdie();
9559 }
9560
9561 if (use_profile) {
9562 xmlNodePtr prof;
9563
9564 prof = xmlNewChild(ctxt, NULL,
9565 (xmlChar *)"method_profile", NULL);
9566 if (prof == NULL)
9567 uu_die(emsg_create_xml);
9568
9569 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
9570 exp_prop) != 0 ||
9571 set_attr_from_prop(exp_prop, prof,
9572 name_attr) != 0)
9573 err = 1;
9574 } else {
9575 xmlNodePtr cred;
9576
9577 cred = xmlNewChild(ctxt, NULL,
9578 (xmlChar *)"method_credential", NULL);
9579 if (cred == NULL)
9580 uu_die(emsg_create_xml);
9581
9582 if (pg_get_prop(pg, SCF_PROPERTY_USER,
9583 exp_prop) != 0 ||
9584 set_attr_from_prop(exp_prop, cred,
9585 "user") != 0) {
9586 err = 1;
9587 }
9588
9589 if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
9590 exp_prop) == 0 &&
9591 set_attr_from_prop_default(exp_prop, cred,
9592 "group", ":default") != 0)
9593 err = 1;
9594
9595 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
9596 exp_prop) == 0 &&
9597 set_attr_from_prop_default(exp_prop, cred,
9598 "supp_groups", ":default") != 0)
9599 err = 1;
9600
9601 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
9602 exp_prop) == 0 &&
9603 set_attr_from_prop_default(exp_prop, cred,
9604 "privileges", ":default") != 0)
9605 err = 1;
9606
9607 if (pg_get_prop(pg,
9608 SCF_PROPERTY_LIMIT_PRIVILEGES,
9609 exp_prop) == 0 &&
9610 set_attr_from_prop_default(exp_prop, cred,
9611 "limit_privileges", ":default") != 0)
9612 err = 1;
9613 }
9614 }
9615 }
9616
9617 if ((env = export_method_environment(pg)) != NULL) {
9618 if (ctxt == NULL) {
9619 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9620 if (ctxt == NULL)
9621 uu_die(emsg_create_xml);
9622 }
9623 (void) xmlAddChild(ctxt, env);
9624 }
9625
9626 if (env != NULL || (nonenv && err == 0))
9627 (void) xmlAddChild(n, ctxt);
9628 else
9629 xmlFreeNode(ctxt);
9630
9631 nonenv = (err == 0);
9632
9633 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9634 scfdie();
9635
9636 (void) memset(&elts, 0, sizeof (elts));
9637
9638 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9639 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9640 scfdie();
9641
9642 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9643 strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
9644 strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
9645 continue;
9646 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9647 xmlNodePtr m;
9648
9649 m = xmlNewNode(NULL, (xmlChar *)"stability");
9650 if (m == NULL)
9651 uu_die(emsg_create_xml);
9652
9653 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9654 elts.stability = m;
9655 continue;
9656 }
9657
9658 xmlFreeNode(m);
9659 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
9660 0 ||
9661 strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
9662 strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
9663 strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9664 if (nonenv)
9665 continue;
9666 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
9667 strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
9668 strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
9669 strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
9670 strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0 ||
9671 strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9672 if (nonenv && !use_profile)
9673 continue;
9674 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9675 if (nonenv && use_profile)
9676 continue;
9677 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
9678 if (env != NULL)
9679 continue;
9680 }
9681
9682 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9683 }
9684 if (ret == -1)
9685 scfdie();
9686
9687 (void) xmlAddChild(n, elts.stability);
9688 (void) xmlAddChildList(n, elts.propvals);
9689 (void) xmlAddChildList(n, elts.properties);
9690
9691 if (eelts->exec_methods == NULL)
9692 eelts->exec_methods = n;
9693 else
9694 (void) xmlAddSibling(eelts->exec_methods, n);
9695 }
9696
9697 static void
9698 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
9699 struct entity_elts *eelts)
9700 {
9701 xmlNodePtr pgnode;
9702
9703 pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
9704 if (pgnode == NULL)
9705 uu_die(emsg_create_xml);
9706
9707 safe_setprop(pgnode, name_attr, name);
9708 safe_setprop(pgnode, type_attr, type);
9709
9710 (void) xmlAddChildList(pgnode, elts->propvals);
9711 (void) xmlAddChildList(pgnode, elts->properties);
9712
9713 if (eelts->property_groups == NULL)
9714 eelts->property_groups = pgnode;
9715 else
9716 (void) xmlAddSibling(eelts->property_groups, pgnode);
9717 }
9718
9719 /*
9720 * Process the general property group for a service. This is the one with the
9721 * goodies.
9722 */
9723 static void
9724 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
9725 {
9726 struct pg_elts elts;
9727 int ret;
9728
9729 /*
9730 * In case there are properties which don't correspond to child
9731 * entities of the service entity, we'll set up a pg_elts structure to
9732 * put them in.
9733 */
9734 (void) memset(&elts, 0, sizeof (elts));
9735
9736 /* Walk the properties, looking for special ones. */
9737 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9738 scfdie();
9739
9740 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9741 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9742 scfdie();
9743
9744 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
9745 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9746 prop_get_val(exp_prop, exp_val) == 0) {
9747 uint8_t b;
9748
9749 if (scf_value_get_boolean(exp_val, &b) !=
9750 SCF_SUCCESS)
9751 scfdie();
9752
9753 if (b) {
9754 selts->single_instance =
9755 xmlNewNode(NULL,
9756 (xmlChar *)"single_instance");
9757 if (selts->single_instance == NULL)
9758 uu_die(emsg_create_xml);
9759 }
9760
9761 continue;
9762 }
9763 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9764 xmlNodePtr rnode, sfnode;
9765
9766 rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9767 if (rnode == NULL)
9768 uu_die(emsg_create_xml);
9769
9770 sfnode = xmlNewChild(rnode, NULL,
9771 (xmlChar *)"service_fmri", NULL);
9772 if (sfnode == NULL)
9773 uu_die(emsg_create_xml);
9774
9775 if (set_attr_from_prop(exp_prop, sfnode,
9776 value_attr) == 0) {
9777 selts->restarter = rnode;
9778 continue;
9779 }
9780
9781 xmlFreeNode(rnode);
9782 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
9783 0) {
9784 xmlNodePtr s;
9785
9786 s = xmlNewNode(NULL, (xmlChar *)"stability");
9787 if (s == NULL)
9788 uu_die(emsg_create_xml);
9789
9790 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9791 selts->stability = s;
9792 continue;
9793 }
9794
9795 xmlFreeNode(s);
9796 }
9797
9798 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9799 }
9800 if (ret == -1)
9801 scfdie();
9802
9803 if (elts.propvals != NULL || elts.properties != NULL)
9804 export_pg_elts(&elts, scf_pg_general, scf_group_framework,
9805 selts);
9806 }
9807
9808 static void
9809 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
9810 {
9811 xmlNodePtr n, prof, cred, env;
9812 uint8_t use_profile;
9813 int ret, err = 0;
9814
9815 n = xmlNewNode(NULL, (xmlChar *)"method_context");
9816
9817 env = export_method_environment(pg);
9818
9819 /* Need to know whether we'll use a profile or not. */
9820 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9821 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9822 prop_get_val(exp_prop, exp_val) == 0) {
9823 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
9824 scfdie();
9825
9826 if (use_profile)
9827 prof =
9828 xmlNewChild(n, NULL, (xmlChar *)"method_profile",
9829 NULL);
9830 else
9831 cred =
9832 xmlNewChild(n, NULL, (xmlChar *)"method_credential",
9833 NULL);
9834 }
9835
9836 if (env != NULL)
9837 (void) xmlAddChild(n, env);
9838
9839 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9840 scfdie();
9841
9842 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9843 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9844 scfdie();
9845
9846 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
9847 if (set_attr_from_prop(exp_prop, n,
9848 "working_directory") != 0)
9849 err = 1;
9850 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
9851 if (set_attr_from_prop(exp_prop, n, "project") != 0)
9852 err = 1;
9853 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
9854 if (set_attr_from_prop(exp_prop, n,
9855 "resource_pool") != 0)
9856 err = 1;
9857 } else if (strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9858 if (set_attr_from_prop(exp_prop, n,
9859 "security_flags") != 0)
9860 err = 1;
9861 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9862 /* EMPTY */
9863 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
9864 if (use_profile ||
9865 set_attr_from_prop(exp_prop, cred, "user") != 0)
9866 err = 1;
9867 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
9868 if (use_profile ||
9869 set_attr_from_prop(exp_prop, cred, "group") != 0)
9870 err = 1;
9871 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
9872 if (use_profile || set_attr_from_prop(exp_prop, cred,
9873 "supp_groups") != 0)
9874 err = 1;
9875 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
9876 if (use_profile || set_attr_from_prop(exp_prop, cred,
9877 "privileges") != 0)
9878 err = 1;
9879 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
9880 0) {
9881 if (use_profile || set_attr_from_prop(exp_prop, cred,
9882 "limit_privileges") != 0)
9883 err = 1;
9884 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9885 if (!use_profile || set_attr_from_prop(exp_prop,
9886 prof, name_attr) != 0)
9887 err = 1;
9888 } else {
9889 /* Can't have generic properties in method_context's */
9890 err = 1;
9891 }
9892 }
9893 if (ret == -1)
9894 scfdie();
9895
9896 if (err && env == NULL) {
9897 xmlFreeNode(n);
9898 export_pg(pg, elts, SCE_ALL_VALUES);
9899 return;
9900 }
9901
9902 elts->method_context = n;
9903 }
9904
9905 /*
9906 * Given a dependency property group in the tfmri entity (target fmri), return
9907 * a dependent element which represents it.
9908 */
9909 static xmlNodePtr
9910 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
9911 {
9912 uint8_t b;
9913 xmlNodePtr n, sf;
9914 int err = 0, ret;
9915 struct pg_elts pgelts;
9916
9917 /*
9918 * If external isn't set to true then exporting the service will
9919 * export this as a normal dependency, so we should stop to avoid
9920 * duplication.
9921 */
9922 if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
9923 scf_property_get_value(exp_prop, exp_val) != 0 ||
9924 scf_value_get_boolean(exp_val, &b) != 0 || !b) {
9925 if (g_verbose) {
9926 warn(gettext("Dependent \"%s\" cannot be exported "
9927 "properly because the \"%s\" property of the "
9928 "\"%s\" dependency of %s is not set to true.\n"),
9929 name, scf_property_external, name, tfmri);
9930 }
9931
9932 return (NULL);
9933 }
9934
9935 n = xmlNewNode(NULL, (xmlChar *)"dependent");
9936 if (n == NULL)
9937 uu_die(emsg_create_xml);
9938
9939 safe_setprop(n, name_attr, name);
9940
9941 /* Get the required attributes */
9942 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9943 set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9944 err = 1;
9945
9946 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9947 set_attr_from_prop(exp_prop, n, "grouping") != 0)
9948 err = 1;
9949
9950 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9951 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
9952 prop_get_val(exp_prop, exp_val) == 0) {
9953 /* EMPTY */
9954 } else
9955 err = 1;
9956
9957 if (err) {
9958 xmlFreeNode(n);
9959 return (NULL);
9960 }
9961
9962 sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
9963 if (sf == NULL)
9964 uu_die(emsg_create_xml);
9965
9966 safe_setprop(sf, value_attr, tfmri);
9967
9968 /*
9969 * Now add elements for the other properties.
9970 */
9971 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9972 scfdie();
9973
9974 (void) memset(&pgelts, 0, sizeof (pgelts));
9975
9976 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9977 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9978 scfdie();
9979
9980 if (strcmp(exp_str, scf_property_external) == 0 ||
9981 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9982 strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9983 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9984 continue;
9985 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
9986 if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
9987 prop_get_val(exp_prop, exp_val) == 0) {
9988 char type[sizeof ("service") + 1];
9989
9990 if (scf_value_get_astring(exp_val, type,
9991 sizeof (type)) < 0)
9992 scfdie();
9993
9994 if (strcmp(type, "service") == 0)
9995 continue;
9996 }
9997 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9998 xmlNodePtr s;
9999
10000 s = xmlNewNode(NULL, (xmlChar *)"stability");
10001 if (s == NULL)
10002 uu_die(emsg_create_xml);
10003
10004 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
10005 pgelts.stability = s;
10006 continue;
10007 }
10008
10009 xmlFreeNode(s);
10010 }
10011
10012 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10013 }
10014 if (ret == -1)
10015 scfdie();
10016
10017 (void) xmlAddChild(n, pgelts.stability);
10018 (void) xmlAddChildList(n, pgelts.propvals);
10019 (void) xmlAddChildList(n, pgelts.properties);
10020
10021 return (n);
10022 }
10023
10024 static void
10025 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
10026 {
10027 scf_propertygroup_t *opg;
10028 scf_iter_t *iter;
10029 char *type, *fmri;
10030 int ret;
10031 struct pg_elts pgelts;
10032 xmlNodePtr n;
10033 scf_error_t serr;
10034
10035 if ((opg = scf_pg_create(g_hndl)) == NULL ||
10036 (iter = scf_iter_create(g_hndl)) == NULL)
10037 scfdie();
10038
10039 /* Can't use exp_prop_iter due to export_dependent(). */
10040 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
10041 scfdie();
10042
10043 type = safe_malloc(max_scf_pg_type_len + 1);
10044
10045 /* Get an extra byte so we can tell if values are too long. */
10046 fmri = safe_malloc(max_scf_fmri_len + 2);
10047
10048 (void) memset(&pgelts, 0, sizeof (pgelts));
10049
10050 while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
10051 void *entity;
10052 int isservice;
10053 scf_type_t ty;
10054
10055 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
10056 scfdie();
10057
10058 if ((ty != SCF_TYPE_ASTRING &&
10059 prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
10060 prop_get_val(exp_prop, exp_val) != 0) {
10061 export_property(exp_prop, NULL, &pgelts,
10062 SCE_ALL_VALUES);
10063 continue;
10064 }
10065
10066 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10067 scfdie();
10068
10069 if (scf_value_get_astring(exp_val, fmri,
10070 max_scf_fmri_len + 2) < 0)
10071 scfdie();
10072
10073 /* Look for a dependency group in the target fmri. */
10074 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
10075 switch (serr) {
10076 case SCF_ERROR_NONE:
10077 break;
10078
10079 case SCF_ERROR_NO_MEMORY:
10080 uu_die(gettext("Out of memory.\n"));
10081 /* NOTREACHED */
10082
10083 case SCF_ERROR_INVALID_ARGUMENT:
10084 if (g_verbose) {
10085 if (scf_property_to_fmri(exp_prop, fmri,
10086 max_scf_fmri_len + 2) < 0)
10087 scfdie();
10088
10089 warn(gettext("The value of %s is not a valid "
10090 "FMRI.\n"), fmri);
10091 }
10092
10093 export_property(exp_prop, exp_str, &pgelts,
10094 SCE_ALL_VALUES);
10095 continue;
10096
10097 case SCF_ERROR_CONSTRAINT_VIOLATED:
10098 if (g_verbose) {
10099 if (scf_property_to_fmri(exp_prop, fmri,
10100 max_scf_fmri_len + 2) < 0)
10101 scfdie();
10102
10103 warn(gettext("The value of %s does not specify "
10104 "a service or an instance.\n"), fmri);
10105 }
10106
10107 export_property(exp_prop, exp_str, &pgelts,
10108 SCE_ALL_VALUES);
10109 continue;
10110
10111 case SCF_ERROR_NOT_FOUND:
10112 if (g_verbose) {
10113 if (scf_property_to_fmri(exp_prop, fmri,
10114 max_scf_fmri_len + 2) < 0)
10115 scfdie();
10116
10117 warn(gettext("The entity specified by %s does "
10118 "not exist.\n"), fmri);
10119 }
10120
10121 export_property(exp_prop, exp_str, &pgelts,
10122 SCE_ALL_VALUES);
10123 continue;
10124
10125 default:
10126 #ifndef NDEBUG
10127 (void) fprintf(stderr, "%s:%d: %s() failed with "
10128 "unexpected error %d.\n", __FILE__, __LINE__,
10129 "fmri_to_entity", serr);
10130 #endif
10131 abort();
10132 }
10133
10134 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
10135 if (scf_error() != SCF_ERROR_NOT_FOUND)
10136 scfdie();
10137
10138 warn(gettext("Entity %s is missing dependency property "
10139 "group %s.\n"), fmri, exp_str);
10140
10141 export_property(exp_prop, NULL, &pgelts,
10142 SCE_ALL_VALUES);
10143 continue;
10144 }
10145
10146 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
10147 scfdie();
10148
10149 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
10150 if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
10151 scfdie();
10152
10153 warn(gettext("Property group %s is not of "
10154 "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
10155
10156 export_property(exp_prop, NULL, &pgelts,
10157 SCE_ALL_VALUES);
10158 continue;
10159 }
10160
10161 n = export_dependent(opg, exp_str, fmri);
10162 if (n == NULL) {
10163 export_property(exp_prop, exp_str, &pgelts,
10164 SCE_ALL_VALUES);
10165 } else {
10166 if (eelts->dependents == NULL)
10167 eelts->dependents = n;
10168 else
10169 (void) xmlAddSibling(eelts->dependents,
10170 n);
10171 }
10172 }
10173 if (ret == -1)
10174 scfdie();
10175
10176 free(fmri);
10177 free(type);
10178
10179 scf_iter_destroy(iter);
10180 scf_pg_destroy(opg);
10181
10182 if (pgelts.propvals != NULL || pgelts.properties != NULL)
10183 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
10184 eelts);
10185 }
10186
10187 static void
10188 make_node(xmlNodePtr *nodep, const char *name)
10189 {
10190 if (*nodep == NULL) {
10191 *nodep = xmlNewNode(NULL, (xmlChar *)name);
10192 if (*nodep == NULL)
10193 uu_die(emsg_create_xml);
10194 }
10195 }
10196
10197 static xmlNodePtr
10198 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
10199 {
10200 int ret;
10201 xmlNodePtr parent = NULL;
10202 xmlNodePtr loctext = NULL;
10203
10204 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10205 scfdie();
10206
10207 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10208 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
10209 prop_get_val(exp_prop, exp_val) != 0)
10210 continue;
10211
10212 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
10213 scfdie();
10214
10215 make_node(&parent, parname);
10216 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
10217 (xmlChar *)exp_str);
10218 if (loctext == NULL)
10219 uu_die(emsg_create_xml);
10220
10221 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10222 scfdie();
10223
10224 safe_setprop(loctext, "xml:lang", exp_str);
10225 }
10226
10227 if (ret == -1)
10228 scfdie();
10229
10230 return (parent);
10231 }
10232
10233 static xmlNodePtr
10234 export_tm_manpage(scf_propertygroup_t *pg)
10235 {
10236 xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
10237 if (manpage == NULL)
10238 uu_die(emsg_create_xml);
10239
10240 if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
10241 set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
10242 pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
10243 set_attr_from_prop(exp_prop, manpage, "section") != 0) {
10244 xmlFreeNode(manpage);
10245 return (NULL);
10246 }
10247
10248 if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
10249 (void) set_attr_from_prop_default(exp_prop,
10250 manpage, "manpath", ":default");
10251
10252 return (manpage);
10253 }
10254
10255 static xmlNodePtr
10256 export_tm_doc_link(scf_propertygroup_t *pg)
10257 {
10258 xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
10259 if (doc_link == NULL)
10260 uu_die(emsg_create_xml);
10261
10262 if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
10263 set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
10264 pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
10265 set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
10266 xmlFreeNode(doc_link);
10267 return (NULL);
10268 }
10269 return (doc_link);
10270 }
10271
10272 /*
10273 * Process template information for a service or instances.
10274 */
10275 static void
10276 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
10277 struct template_elts *telts)
10278 {
10279 size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
10280 size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
10281 xmlNodePtr child = NULL;
10282
10283 if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
10284 scfdie();
10285
10286 if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
10287 telts->common_name = export_tm_loctext(pg, "common_name");
10288 if (telts->common_name == NULL)
10289 export_pg(pg, elts, SCE_ALL_VALUES);
10290 return;
10291 } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
10292 telts->description = export_tm_loctext(pg, "description");
10293 if (telts->description == NULL)
10294 export_pg(pg, elts, SCE_ALL_VALUES);
10295 return;
10296 }
10297
10298 if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
10299 child = export_tm_manpage(pg);
10300 } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
10301 child = export_tm_doc_link(pg);
10302 }
10303
10304 if (child != NULL) {
10305 make_node(&telts->documentation, "documentation");
10306 (void) xmlAddChild(telts->documentation, child);
10307 } else {
10308 export_pg(pg, elts, SCE_ALL_VALUES);
10309 }
10310 }
10311
10312 /*
10313 * Process parameter and paramval elements
10314 */
10315 static void
10316 export_parameter(scf_property_t *prop, const char *name,
10317 struct params_elts *elts)
10318 {
10319 xmlNodePtr param;
10320 scf_error_t err = 0;
10321 int ret;
10322
10323 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
10324 if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL)
10325 uu_die(emsg_create_xml);
10326
10327 safe_setprop(param, name_attr, name);
10328
10329 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
10330 scfdie();
10331 safe_setprop(param, value_attr, exp_str);
10332
10333 if (elts->paramval == NULL)
10334 elts->paramval = param;
10335 else
10336 (void) xmlAddSibling(elts->paramval, param);
10337
10338 return;
10339 }
10340
10341 err = scf_error();
10342
10343 if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
10344 err != SCF_ERROR_NOT_FOUND)
10345 scfdie();
10346
10347 if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL)
10348 uu_die(emsg_create_xml);
10349
10350 safe_setprop(param, name_attr, name);
10351
10352 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
10353 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
10354 scfdie();
10355
10356 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
10357 1) {
10358 xmlNodePtr vn;
10359
10360 if ((vn = xmlNewChild(param, NULL,
10361 (xmlChar *)"value_node", NULL)) == NULL)
10362 uu_die(emsg_create_xml);
10363
10364 if (scf_value_get_as_string(exp_val, exp_str,
10365 exp_str_sz) < 0)
10366 scfdie();
10367
10368 safe_setprop(vn, value_attr, exp_str);
10369 }
10370 if (ret != 0)
10371 scfdie();
10372 }
10373
10374 if (elts->parameter == NULL)
10375 elts->parameter = param;
10376 else
10377 (void) xmlAddSibling(elts->parameter, param);
10378 }
10379
10380 /*
10381 * Process notification parameters for a service or instance
10382 */
10383 static void
10384 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts)
10385 {
10386 xmlNodePtr n, event, *type;
10387 struct params_elts *eelts;
10388 int ret, err, i;
10389
10390 n = xmlNewNode(NULL, (xmlChar *)"notification_parameters");
10391 event = xmlNewNode(NULL, (xmlChar *)"event");
10392 if (n == NULL || event == NULL)
10393 uu_die(emsg_create_xml);
10394
10395 /* event value */
10396 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
10397 scfdie();
10398 safe_setprop(event, value_attr, exp_str);
10399
10400 (void) xmlAddChild(n, event);
10401
10402 if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL ||
10403 (eelts = calloc(URI_SCHEME_NUM,
10404 sizeof (struct params_elts))) == NULL)
10405 uu_die(gettext("Out of memory.\n"));
10406
10407 err = 0;
10408
10409 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10410 scfdie();
10411
10412 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10413 char *t, *p;
10414
10415 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10416 scfdie();
10417
10418 if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) {
10419 /*
10420 * this is not a well formed notification parameters
10421 * element, we should export as regular pg
10422 */
10423 err = 1;
10424 break;
10425 }
10426
10427 if ((i = check_uri_protocol(t)) < 0) {
10428 err = 1;
10429 break;
10430 }
10431
10432 if (type[i] == NULL) {
10433 if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) ==
10434 NULL)
10435 uu_die(emsg_create_xml);
10436
10437 safe_setprop(type[i], name_attr, t);
10438 }
10439 if (strcmp(p, active_attr) == 0) {
10440 if (set_attr_from_prop(exp_prop, type[i],
10441 active_attr) != 0) {
10442 err = 1;
10443 break;
10444 }
10445 continue;
10446 }
10447 /*
10448 * We export the parameter
10449 */
10450 export_parameter(exp_prop, p, &eelts[i]);
10451 }
10452
10453 if (ret == -1)
10454 scfdie();
10455
10456 if (err == 1) {
10457 for (i = 0; i < URI_SCHEME_NUM; ++i)
10458 xmlFree(type[i]);
10459 free(type);
10460
10461 export_pg(pg, elts, SCE_ALL_VALUES);
10462
10463 return;
10464 } else {
10465 for (i = 0; i < URI_SCHEME_NUM; ++i)
10466 if (type[i] != NULL) {
10467 (void) xmlAddChildList(type[i],
10468 eelts[i].paramval);
10469 (void) xmlAddChildList(type[i],
10470 eelts[i].parameter);
10471 (void) xmlAddSibling(event, type[i]);
10472 }
10473 }
10474 free(type);
10475
10476 if (elts->notify_params == NULL)
10477 elts->notify_params = n;
10478 else
10479 (void) xmlAddSibling(elts->notify_params, n);
10480 }
10481
10482 /*
10483 * Process the general property group for an instance.
10484 */
10485 static void
10486 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
10487 struct entity_elts *elts)
10488 {
10489 uint8_t enabled;
10490 struct pg_elts pgelts;
10491 int ret;
10492
10493 /* enabled */
10494 if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
10495 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
10496 prop_get_val(exp_prop, exp_val) == 0) {
10497 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
10498 scfdie();
10499 } else {
10500 enabled = 0;
10501 }
10502
10503 safe_setprop(inode, enabled_attr, enabled ? true : false);
10504
10505 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10506 scfdie();
10507
10508 (void) memset(&pgelts, 0, sizeof (pgelts));
10509
10510 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10511 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10512 scfdie();
10513
10514 if (strcmp(exp_str, scf_property_enabled) == 0) {
10515 continue;
10516 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
10517 xmlNodePtr rnode, sfnode;
10518
10519 rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10520 if (rnode == NULL)
10521 uu_die(emsg_create_xml);
10522
10523 sfnode = xmlNewChild(rnode, NULL,
10524 (xmlChar *)"service_fmri", NULL);
10525 if (sfnode == NULL)
10526 uu_die(emsg_create_xml);
10527
10528 if (set_attr_from_prop(exp_prop, sfnode,
10529 value_attr) == 0) {
10530 elts->restarter = rnode;
10531 continue;
10532 }
10533
10534 xmlFreeNode(rnode);
10535 }
10536
10537 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10538 }
10539 if (ret == -1)
10540 scfdie();
10541
10542 if (pgelts.propvals != NULL || pgelts.properties != NULL)
10543 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10544 elts);
10545 }
10546
10547 /*
10548 * Put an instance element for the given instance into selts.
10549 */
10550 static void
10551 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10552 {
10553 xmlNodePtr n;
10554 boolean_t isdefault;
10555 struct entity_elts elts;
10556 struct template_elts template_elts;
10557 int ret;
10558
10559 n = xmlNewNode(NULL, (xmlChar *)"instance");
10560 if (n == NULL)
10561 uu_die(emsg_create_xml);
10562
10563 /* name */
10564 if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10565 scfdie();
10566 safe_setprop(n, name_attr, exp_str);
10567 isdefault = strcmp(exp_str, "default") == 0;
10568
10569 /* check existance of general pg (since general/enabled is required) */
10570 if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
10571 if (scf_error() != SCF_ERROR_NOT_FOUND)
10572 scfdie();
10573
10574 if (g_verbose) {
10575 if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10576 scfdie();
10577
10578 warn(gettext("Instance %s has no general property "
10579 "group; it will be marked disabled.\n"), exp_str);
10580 }
10581
10582 safe_setprop(n, enabled_attr, false);
10583 } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
10584 strcmp(exp_str, scf_group_framework) != 0) {
10585 if (g_verbose) {
10586 if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10587 scfdie();
10588
10589 warn(gettext("Property group %s is not of type "
10590 "framework; the instance will be marked "
10591 "disabled.\n"), exp_str);
10592 }
10593
10594 safe_setprop(n, enabled_attr, false);
10595 }
10596
10597 /* property groups */
10598 if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
10599 scfdie();
10600
10601 (void) memset(&elts, 0, sizeof (elts));
10602 (void) memset(&template_elts, 0, sizeof (template_elts));
10603
10604 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10605 uint32_t pgflags;
10606
10607 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10608 scfdie();
10609
10610 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10611 continue;
10612
10613 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10614 scfdie();
10615
10616 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10617 export_dependency(exp_pg, &elts);
10618 continue;
10619 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10620 export_method(exp_pg, &elts);
10621 continue;
10622 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10623 if (scf_pg_get_name(exp_pg, exp_str,
10624 max_scf_name_len + 1) < 0)
10625 scfdie();
10626
10627 if (strcmp(exp_str, scf_pg_general) == 0) {
10628 export_inst_general(exp_pg, n, &elts);
10629 continue;
10630 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10631 0) {
10632 export_method_context(exp_pg, &elts);
10633 continue;
10634 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10635 export_dependents(exp_pg, &elts);
10636 continue;
10637 }
10638 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10639 export_template(exp_pg, &elts, &template_elts);
10640 continue;
10641 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10642 export_notify_params(exp_pg, &elts);
10643 continue;
10644 }
10645
10646 /* Ordinary pg. */
10647 export_pg(exp_pg, &elts, flags);
10648 }
10649 if (ret == -1)
10650 scfdie();
10651
10652 if (template_elts.common_name != NULL) {
10653 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10654 (void) xmlAddChild(elts.template, template_elts.common_name);
10655 (void) xmlAddChild(elts.template, template_elts.description);
10656 (void) xmlAddChild(elts.template, template_elts.documentation);
10657 } else {
10658 xmlFreeNode(template_elts.description);
10659 xmlFreeNode(template_elts.documentation);
10660 }
10661
10662 if (isdefault && elts.restarter == NULL &&
10663 elts.dependencies == NULL && elts.method_context == NULL &&
10664 elts.exec_methods == NULL && elts.notify_params == NULL &&
10665 elts.property_groups == NULL && elts.template == NULL) {
10666 xmlChar *eval;
10667
10668 /* This is a default instance */
10669 eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10670
10671 xmlFreeNode(n);
10672
10673 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10674 if (n == NULL)
10675 uu_die(emsg_create_xml);
10676
10677 safe_setprop(n, enabled_attr, (char *)eval);
10678 xmlFree(eval);
10679
10680 selts->create_default_instance = n;
10681 } else {
10682 /* Assemble the children in order. */
10683 (void) xmlAddChild(n, elts.restarter);
10684 (void) xmlAddChildList(n, elts.dependencies);
10685 (void) xmlAddChildList(n, elts.dependents);
10686 (void) xmlAddChild(n, elts.method_context);
10687 (void) xmlAddChildList(n, elts.exec_methods);
10688 (void) xmlAddChildList(n, elts.notify_params);
10689 (void) xmlAddChildList(n, elts.property_groups);
10690 (void) xmlAddChild(n, elts.template);
10691
10692 if (selts->instances == NULL)
10693 selts->instances = n;
10694 else
10695 (void) xmlAddSibling(selts->instances, n);
10696 }
10697 }
10698
10699 /*
10700 * Return a service element for the given service.
10701 */
10702 static xmlNodePtr
10703 export_service(scf_service_t *svc, int flags)
10704 {
10705 xmlNodePtr snode;
10706 struct entity_elts elts;
10707 struct template_elts template_elts;
10708 int ret;
10709
10710 snode = xmlNewNode(NULL, (xmlChar *)"service");
10711 if (snode == NULL)
10712 uu_die(emsg_create_xml);
10713
10714 /* Get & set name attribute */
10715 if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
10716 scfdie();
10717 safe_setprop(snode, name_attr, exp_str);
10718
10719 safe_setprop(snode, type_attr, "service");
10720 safe_setprop(snode, "version", "0");
10721
10722 /* Acquire child elements. */
10723 if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
10724 scfdie();
10725
10726 (void) memset(&elts, 0, sizeof (elts));
10727 (void) memset(&template_elts, 0, sizeof (template_elts));
10728
10729 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10730 uint32_t pgflags;
10731
10732 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10733 scfdie();
10734
10735 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10736 continue;
10737
10738 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10739 scfdie();
10740
10741 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10742 export_dependency(exp_pg, &elts);
10743 continue;
10744 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10745 export_method(exp_pg, &elts);
10746 continue;
10747 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10748 if (scf_pg_get_name(exp_pg, exp_str,
10749 max_scf_name_len + 1) < 0)
10750 scfdie();
10751
10752 if (strcmp(exp_str, scf_pg_general) == 0) {
10753 export_svc_general(exp_pg, &elts);
10754 continue;
10755 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10756 0) {
10757 export_method_context(exp_pg, &elts);
10758 continue;
10759 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10760 export_dependents(exp_pg, &elts);
10761 continue;
10762 } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10763 continue;
10764 }
10765 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10766 export_template(exp_pg, &elts, &template_elts);
10767 continue;
10768 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10769 export_notify_params(exp_pg, &elts);
10770 continue;
10771 }
10772
10773 export_pg(exp_pg, &elts, flags);
10774 }
10775 if (ret == -1)
10776 scfdie();
10777
10778 if (template_elts.common_name != NULL) {
10779 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10780 (void) xmlAddChild(elts.template, template_elts.common_name);
10781 (void) xmlAddChild(elts.template, template_elts.description);
10782 (void) xmlAddChild(elts.template, template_elts.documentation);
10783 } else {
10784 xmlFreeNode(template_elts.description);
10785 xmlFreeNode(template_elts.documentation);
10786 }
10787
10788 /* Iterate instances */
10789 if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
10790 scfdie();
10791
10792 while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10793 export_instance(exp_inst, &elts, flags);
10794 if (ret == -1)
10795 scfdie();
10796
10797 /* Now add all of the accumulated elements in order. */
10798 (void) xmlAddChild(snode, elts.create_default_instance);
10799 (void) xmlAddChild(snode, elts.single_instance);
10800 (void) xmlAddChild(snode, elts.restarter);
10801 (void) xmlAddChildList(snode, elts.dependencies);
10802 (void) xmlAddChildList(snode, elts.dependents);
10803 (void) xmlAddChild(snode, elts.method_context);
10804 (void) xmlAddChildList(snode, elts.exec_methods);
10805 (void) xmlAddChildList(snode, elts.notify_params);
10806 (void) xmlAddChildList(snode, elts.property_groups);
10807 (void) xmlAddChildList(snode, elts.instances);
10808 (void) xmlAddChild(snode, elts.stability);
10809 (void) xmlAddChild(snode, elts.template);
10810
10811 return (snode);
10812 }
10813
10814 static int
10815 export_callback(void *data, scf_walkinfo_t *wip)
10816 {
10817 FILE *f;
10818 xmlDocPtr doc;
10819 xmlNodePtr sb;
10820 int result;
10821 struct export_args *argsp = (struct export_args *)data;
10822
10823 if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
10824 (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10825 (exp_prop = scf_property_create(g_hndl)) == NULL ||
10826 (exp_val = scf_value_create(g_hndl)) == NULL ||
10827 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10828 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10829 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10830 (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10831 scfdie();
10832
10833 exp_str_sz = max_scf_len + 1;
10834 exp_str = safe_malloc(exp_str_sz);
10835
10836 if (argsp->filename != NULL) {
10837 errno = 0;
10838 f = fopen(argsp->filename, "wb");
10839 if (f == NULL) {
10840 if (errno == 0)
10841 uu_die(gettext("Could not open \"%s\": no free "
10842 "stdio streams.\n"), argsp->filename);
10843 else
10844 uu_die(gettext("Could not open \"%s\""),
10845 argsp->filename);
10846 }
10847 } else
10848 f = stdout;
10849
10850 doc = xmlNewDoc((xmlChar *)"1.0");
10851 if (doc == NULL)
10852 uu_die(gettext("Could not create XML document.\n"));
10853
10854 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10855 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10856 uu_die(emsg_create_xml);
10857
10858 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10859 if (sb == NULL)
10860 uu_die(emsg_create_xml);
10861 safe_setprop(sb, type_attr, "manifest");
10862 safe_setprop(sb, name_attr, "export");
10863 (void) xmlAddSibling(doc->children, sb);
10864
10865 (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
10866
10867 result = write_service_bundle(doc, f);
10868
10869 free(exp_str);
10870 scf_iter_destroy(exp_val_iter);
10871 scf_iter_destroy(exp_prop_iter);
10872 scf_iter_destroy(exp_pg_iter);
10873 scf_iter_destroy(exp_inst_iter);
10874 scf_value_destroy(exp_val);
10875 scf_property_destroy(exp_prop);
10876 scf_pg_destroy(exp_pg);
10877 scf_instance_destroy(exp_inst);
10878
10879 xmlFreeDoc(doc);
10880
10881 if (f != stdout)
10882 (void) fclose(f);
10883
10884 return (result);
10885 }
10886
10887 /*
10888 * Get the service named by fmri, build an XML tree which represents it, and
10889 * dump it into filename (or stdout if filename is NULL).
10890 */
10891 int
10892 lscf_service_export(char *fmri, const char *filename, int flags)
10893 {
10894 struct export_args args;
10895 char *fmridup;
10896 const char *scope, *svc, *inst;
10897 size_t cblen = 3 * max_scf_name_len;
10898 char *canonbuf = alloca(cblen);
10899 int ret, err;
10900
10901 lscf_prep_hndl();
10902
10903 bzero(&args, sizeof (args));
10904 args.filename = filename;
10905 args.flags = flags;
10906
10907 /*
10908 * If some poor user has passed an exact instance FMRI, of the sort
10909 * one might cut and paste from svcs(1) or an error message, warn
10910 * and chop off the instance instead of failing.
10911 */
10912 fmridup = alloca(strlen(fmri) + 1);
10913 (void) strcpy(fmridup, fmri);
10914 if (strncmp(fmridup, SCF_FMRI_SVC_PREFIX,
10915 sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 &&
10916 scf_parse_svc_fmri(fmridup, &scope, &svc, &inst, NULL, NULL) == 0 &&
10917 inst != NULL) {
10918 (void) strlcpy(canonbuf, "svc:/", cblen);
10919 if (strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
10920 (void) strlcat(canonbuf, "/", cblen);
10921 (void) strlcat(canonbuf, scope, cblen);
10922 }
10923 (void) strlcat(canonbuf, svc, cblen);
10924 fmri = canonbuf;
10925
10926 warn(gettext("Only services may be exported; ignoring "
10927 "instance portion of argument.\n"));
10928 }
10929
10930 err = 0;
10931 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10932 SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10933 &args, &err, semerr)) != 0) {
10934 if (ret != -1)
10935 semerr(gettext("Failed to walk instances: %s\n"),
10936 scf_strerror(ret));
10937 return (-1);
10938 }
10939
10940 /*
10941 * Error message has already been printed.
10942 */
10943 if (err != 0)
10944 return (-1);
10945
10946 return (0);
10947 }
10948
10949
10950 /*
10951 * Archive
10952 */
10953
10954 static xmlNodePtr
10955 make_archive(int flags)
10956 {
10957 xmlNodePtr sb;
10958 scf_scope_t *scope;
10959 scf_service_t *svc;
10960 scf_iter_t *iter;
10961 int r;
10962
10963 if ((scope = scf_scope_create(g_hndl)) == NULL ||
10964 (svc = scf_service_create(g_hndl)) == NULL ||
10965 (iter = scf_iter_create(g_hndl)) == NULL ||
10966 (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10967 (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10968 (exp_prop = scf_property_create(g_hndl)) == NULL ||
10969 (exp_val = scf_value_create(g_hndl)) == NULL ||
10970 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10971 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10972 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10973 (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10974 scfdie();
10975
10976 exp_str_sz = max_scf_len + 1;
10977 exp_str = safe_malloc(exp_str_sz);
10978
10979 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10980 if (sb == NULL)
10981 uu_die(emsg_create_xml);
10982 safe_setprop(sb, type_attr, "archive");
10983 safe_setprop(sb, name_attr, "none");
10984
10985 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
10986 scfdie();
10987 if (scf_iter_scope_services(iter, scope) != 0)
10988 scfdie();
10989
10990 for (;;) {
10991 r = scf_iter_next_service(iter, svc);
10992 if (r == 0)
10993 break;
10994 if (r != 1)
10995 scfdie();
10996
10997 if (scf_service_get_name(svc, exp_str,
10998 max_scf_name_len + 1) < 0)
10999 scfdie();
11000
11001 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
11002 continue;
11003
11004 (void) xmlAddChild(sb, export_service(svc, flags));
11005 }
11006
11007 free(exp_str);
11008
11009 scf_iter_destroy(exp_val_iter);
11010 scf_iter_destroy(exp_prop_iter);
11011 scf_iter_destroy(exp_pg_iter);
11012 scf_iter_destroy(exp_inst_iter);
11013 scf_value_destroy(exp_val);
11014 scf_property_destroy(exp_prop);
11015 scf_pg_destroy(exp_pg);
11016 scf_instance_destroy(exp_inst);
11017 scf_iter_destroy(iter);
11018 scf_service_destroy(svc);
11019 scf_scope_destroy(scope);
11020
11021 return (sb);
11022 }
11023
11024 int
11025 lscf_archive(const char *filename, int flags)
11026 {
11027 FILE *f;
11028 xmlDocPtr doc;
11029 int result;
11030
11031 lscf_prep_hndl();
11032
11033 if (filename != NULL) {
11034 errno = 0;
11035 f = fopen(filename, "wb");
11036 if (f == NULL) {
11037 if (errno == 0)
11038 uu_die(gettext("Could not open \"%s\": no free "
11039 "stdio streams.\n"), filename);
11040 else
11041 uu_die(gettext("Could not open \"%s\""),
11042 filename);
11043 }
11044 } else
11045 f = stdout;
11046
11047 doc = xmlNewDoc((xmlChar *)"1.0");
11048 if (doc == NULL)
11049 uu_die(gettext("Could not create XML document.\n"));
11050
11051 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11052 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11053 uu_die(emsg_create_xml);
11054
11055 (void) xmlAddSibling(doc->children, make_archive(flags));
11056
11057 result = write_service_bundle(doc, f);
11058
11059 xmlFreeDoc(doc);
11060
11061 if (f != stdout)
11062 (void) fclose(f);
11063
11064 return (result);
11065 }
11066
11067
11068 /*
11069 * "Extract" a profile.
11070 */
11071 int
11072 lscf_profile_extract(const char *filename)
11073 {
11074 FILE *f;
11075 xmlDocPtr doc;
11076 xmlNodePtr sb, snode, inode;
11077 scf_scope_t *scope;
11078 scf_service_t *svc;
11079 scf_instance_t *inst;
11080 scf_propertygroup_t *pg;
11081 scf_property_t *prop;
11082 scf_value_t *val;
11083 scf_iter_t *siter, *iiter;
11084 int r, s;
11085 char *namebuf;
11086 uint8_t b;
11087 int result;
11088
11089 lscf_prep_hndl();
11090
11091 if (filename != NULL) {
11092 errno = 0;
11093 f = fopen(filename, "wb");
11094 if (f == NULL) {
11095 if (errno == 0)
11096 uu_die(gettext("Could not open \"%s\": no "
11097 "free stdio streams.\n"), filename);
11098 else
11099 uu_die(gettext("Could not open \"%s\""),
11100 filename);
11101 }
11102 } else
11103 f = stdout;
11104
11105 doc = xmlNewDoc((xmlChar *)"1.0");
11106 if (doc == NULL)
11107 uu_die(gettext("Could not create XML document.\n"));
11108
11109 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11110 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11111 uu_die(emsg_create_xml);
11112
11113 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
11114 if (sb == NULL)
11115 uu_die(emsg_create_xml);
11116 safe_setprop(sb, type_attr, "profile");
11117 safe_setprop(sb, name_attr, "extract");
11118 (void) xmlAddSibling(doc->children, sb);
11119
11120 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11121 (svc = scf_service_create(g_hndl)) == NULL ||
11122 (inst = scf_instance_create(g_hndl)) == NULL ||
11123 (pg = scf_pg_create(g_hndl)) == NULL ||
11124 (prop = scf_property_create(g_hndl)) == NULL ||
11125 (val = scf_value_create(g_hndl)) == NULL ||
11126 (siter = scf_iter_create(g_hndl)) == NULL ||
11127 (iiter = scf_iter_create(g_hndl)) == NULL)
11128 scfdie();
11129
11130 if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
11131 scfdie();
11132
11133 if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
11134 scfdie();
11135
11136 namebuf = safe_malloc(max_scf_name_len + 1);
11137
11138 while ((r = scf_iter_next_service(siter, svc)) == 1) {
11139 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
11140 scfdie();
11141
11142 snode = xmlNewNode(NULL, (xmlChar *)"service");
11143 if (snode == NULL)
11144 uu_die(emsg_create_xml);
11145
11146 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
11147 0)
11148 scfdie();
11149
11150 safe_setprop(snode, name_attr, namebuf);
11151
11152 safe_setprop(snode, type_attr, "service");
11153 safe_setprop(snode, "version", "0");
11154
11155 while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
11156 if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
11157 SCF_SUCCESS) {
11158 if (scf_error() != SCF_ERROR_NOT_FOUND)
11159 scfdie();
11160
11161 if (g_verbose) {
11162 ssize_t len;
11163 char *fmri;
11164
11165 len =
11166 scf_instance_to_fmri(inst, NULL, 0);
11167 if (len < 0)
11168 scfdie();
11169
11170 fmri = safe_malloc(len + 1);
11171
11172 if (scf_instance_to_fmri(inst, fmri,
11173 len + 1) < 0)
11174 scfdie();
11175
11176 warn("Instance %s has no \"%s\" "
11177 "property group.\n", fmri,
11178 scf_pg_general);
11179
11180 free(fmri);
11181 }
11182
11183 continue;
11184 }
11185
11186 if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
11187 prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
11188 prop_get_val(prop, val) != 0)
11189 continue;
11190
11191 inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
11192 NULL);
11193 if (inode == NULL)
11194 uu_die(emsg_create_xml);
11195
11196 if (scf_instance_get_name(inst, namebuf,
11197 max_scf_name_len + 1) < 0)
11198 scfdie();
11199
11200 safe_setprop(inode, name_attr, namebuf);
11201
11202 if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
11203 scfdie();
11204
11205 safe_setprop(inode, enabled_attr, b ? true : false);
11206 }
11207 if (s < 0)
11208 scfdie();
11209
11210 if (snode->children != NULL)
11211 (void) xmlAddChild(sb, snode);
11212 else
11213 xmlFreeNode(snode);
11214 }
11215 if (r < 0)
11216 scfdie();
11217
11218 free(namebuf);
11219
11220 result = write_service_bundle(doc, f);
11221
11222 xmlFreeDoc(doc);
11223
11224 if (f != stdout)
11225 (void) fclose(f);
11226
11227 return (result);
11228 }
11229
11230
11231 /*
11232 * Entity manipulation commands
11233 */
11234
11235 /*
11236 * Entity selection. If no entity is selected, then the current scope is in
11237 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected,
11238 * only cur_inst is NULL, and when an instance is selected, none are NULL.
11239 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
11240 * cur_inst will be non-NULL.
11241 */
11242
11243 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
11244 static int
11245 select_inst(const char *name)
11246 {
11247 scf_instance_t *inst;
11248 scf_error_t err;
11249
11250 assert(cur_svc != NULL);
11251
11252 inst = scf_instance_create(g_hndl);
11253 if (inst == NULL)
11254 scfdie();
11255
11256 if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
11257 cur_inst = inst;
11258 return (0);
11259 }
11260
11261 err = scf_error();
11262 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11263 scfdie();
11264
11265 scf_instance_destroy(inst);
11266 return (1);
11267 }
11268
11269 /* Returns as above. */
11270 static int
11271 select_svc(const char *name)
11272 {
11273 scf_service_t *svc;
11274 scf_error_t err;
11275
11276 assert(cur_scope != NULL);
11277
11278 svc = scf_service_create(g_hndl);
11279 if (svc == NULL)
11280 scfdie();
11281
11282 if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
11283 cur_svc = svc;
11284 return (0);
11285 }
11286
11287 err = scf_error();
11288 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11289 scfdie();
11290
11291 scf_service_destroy(svc);
11292 return (1);
11293 }
11294
11295 /* ARGSUSED */
11296 static int
11297 select_callback(void *unused, scf_walkinfo_t *wip)
11298 {
11299 scf_instance_t *inst;
11300 scf_service_t *svc;
11301 scf_scope_t *scope;
11302
11303 if (wip->inst != NULL) {
11304 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11305 (svc = scf_service_create(g_hndl)) == NULL ||
11306 (inst = scf_instance_create(g_hndl)) == NULL)
11307 scfdie();
11308
11309 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11310 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11311 scfdie();
11312 } else {
11313 assert(wip->svc != NULL);
11314
11315 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11316 (svc = scf_service_create(g_hndl)) == NULL)
11317 scfdie();
11318
11319 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11320 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11321 scfdie();
11322
11323 inst = NULL;
11324 }
11325
11326 /* Clear out the current selection */
11327 assert(cur_scope != NULL);
11328 scf_scope_destroy(cur_scope);
11329 scf_service_destroy(cur_svc);
11330 scf_instance_destroy(cur_inst);
11331
11332 cur_scope = scope;
11333 cur_svc = svc;
11334 cur_inst = inst;
11335
11336 return (0);
11337 }
11338
11339 static int
11340 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
11341 {
11342 char **fmri = fmri_p;
11343
11344 *fmri = strdup(wip->fmri);
11345 if (*fmri == NULL)
11346 uu_die(gettext("Out of memory.\n"));
11347
11348 return (0);
11349 }
11350
11351 /*
11352 * validate [fmri]
11353 * Perform the validation of an FMRI instance.
11354 */
11355 void
11356 lscf_validate_fmri(const char *fmri)
11357 {
11358 int ret = 0;
11359 size_t inst_sz;
11360 char *inst_fmri = NULL;
11361 scf_tmpl_errors_t *errs = NULL;
11362 char *snapbuf = NULL;
11363
11364 lscf_prep_hndl();
11365
11366 if (fmri == NULL) {
11367 inst_sz = max_scf_fmri_len + 1;
11368 inst_fmri = safe_malloc(inst_sz);
11369
11370 if (cur_snap != NULL) {
11371 snapbuf = safe_malloc(max_scf_name_len + 1);
11372 if (scf_snapshot_get_name(cur_snap, snapbuf,
11373 max_scf_name_len + 1) < 0)
11374 scfdie();
11375 }
11376 if (cur_inst == NULL) {
11377 semerr(gettext("No instance selected\n"));
11378 goto cleanup;
11379 } else if (scf_instance_to_fmri(cur_inst, inst_fmri,
11380 inst_sz) >= inst_sz) {
11381 /* sanity check. Should never get here */
11382 uu_die(gettext("Unexpected error! file %s, line %d\n"),
11383 __FILE__, __LINE__);
11384 }
11385 } else {
11386 scf_error_t scf_err;
11387 int err = 0;
11388
11389 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
11390 validate_callback, &inst_fmri, &err, semerr)) != 0) {
11391 uu_warn("Failed to walk instances: %s\n",
11392 scf_strerror(scf_err));
11393 goto cleanup;
11394 }
11395 if (err != 0) {
11396 /* error message displayed by scf_walk_fmri */
11397 goto cleanup;
11398 }
11399 }
11400
11401 ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
11402 SCF_TMPL_VALIDATE_FLAG_CURRENT);
11403 if (ret == -1) {
11404 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
11405 warn(gettext("Template data for %s is invalid. "
11406 "Consider reverting to a previous snapshot or "
11407 "restoring original configuration.\n"), inst_fmri);
11408 } else {
11409 uu_warn("%s: %s\n",
11410 gettext("Error validating the instance"),
11411 scf_strerror(scf_error()));
11412 }
11413 } else if (ret == 1 && errs != NULL) {
11414 scf_tmpl_error_t *err = NULL;
11415 char *msg;
11416 size_t len = 256; /* initial error buffer size */
11417 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
11418 SCF_TMPL_STRERROR_HUMAN : 0;
11419
11420 msg = safe_malloc(len);
11421
11422 while ((err = scf_tmpl_next_error(errs)) != NULL) {
11423 int ret;
11424
11425 if ((ret = scf_tmpl_strerror(err, msg, len,
11426 flag)) >= len) {
11427 len = ret + 1;
11428 msg = realloc(msg, len);
11429 if (msg == NULL)
11430 uu_die(gettext(
11431 "Out of memory.\n"));
11432 (void) scf_tmpl_strerror(err, msg, len,
11433 flag);
11434 }
11435 (void) fprintf(stderr, "%s\n", msg);
11436 }
11437 if (msg != NULL)
11438 free(msg);
11439 }
11440 if (errs != NULL)
11441 scf_tmpl_errors_destroy(errs);
11442
11443 cleanup:
11444 free(inst_fmri);
11445 free(snapbuf);
11446 }
11447
11448 static void
11449 lscf_validate_file(const char *filename)
11450 {
11451 tmpl_errors_t *errs;
11452
11453 bundle_t *b = internal_bundle_new();
11454 if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
11455 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
11456 tmpl_errors_print(stderr, errs, "");
11457 semerr(gettext("Validation failed.\n"));
11458 }
11459 tmpl_errors_destroy(errs);
11460 }
11461 (void) internal_bundle_free(b);
11462 }
11463
11464 /*
11465 * validate [fmri|file]
11466 */
11467 void
11468 lscf_validate(const char *arg)
11469 {
11470 const char *str;
11471
11472 if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
11473 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
11474 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
11475 lscf_validate_file(str);
11476 } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
11477 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
11478 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
11479 lscf_validate_fmri(str);
11480 } else if (access(arg, R_OK | F_OK) == 0) {
11481 lscf_validate_file(arg);
11482 } else {
11483 lscf_validate_fmri(arg);
11484 }
11485 }
11486
11487 void
11488 lscf_select(const char *fmri)
11489 {
11490 int ret, err;
11491
11492 lscf_prep_hndl();
11493
11494 if (cur_snap != NULL) {
11495 struct snaplevel *elt;
11496 char *buf;
11497
11498 /* Error unless name is that of the next level. */
11499 elt = uu_list_next(cur_levels, cur_elt);
11500 if (elt == NULL) {
11501 semerr(gettext("No children.\n"));
11502 return;
11503 }
11504
11505 buf = safe_malloc(max_scf_name_len + 1);
11506
11507 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11508 max_scf_name_len + 1) < 0)
11509 scfdie();
11510
11511 if (strcmp(buf, fmri) != 0) {
11512 semerr(gettext("No such child.\n"));
11513 free(buf);
11514 return;
11515 }
11516
11517 free(buf);
11518
11519 cur_elt = elt;
11520 cur_level = elt->sl;
11521 return;
11522 }
11523
11524 /*
11525 * Special case for 'svc:', which takes the user to the scope level.
11526 */
11527 if (strcmp(fmri, "svc:") == 0) {
11528 scf_instance_destroy(cur_inst);
11529 scf_service_destroy(cur_svc);
11530 cur_inst = NULL;
11531 cur_svc = NULL;
11532 return;
11533 }
11534
11535 /*
11536 * Special case for ':properties'. This appears as part of 'list' but
11537 * can't be selected. Give a more helpful error message in this case.
11538 */
11539 if (strcmp(fmri, ":properties") == 0) {
11540 semerr(gettext(":properties is not an entity. Try 'listprop' "
11541 "to list properties.\n"));
11542 return;
11543 }
11544
11545 /*
11546 * First try the argument as relative to the current selection.
11547 */
11548 if (cur_inst != NULL) {
11549 /* EMPTY */;
11550 } else if (cur_svc != NULL) {
11551 if (select_inst(fmri) != 1)
11552 return;
11553 } else {
11554 if (select_svc(fmri) != 1)
11555 return;
11556 }
11557
11558 err = 0;
11559 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11560 select_callback, NULL, &err, semerr)) != 0) {
11561 semerr(gettext("Failed to walk instances: %s\n"),
11562 scf_strerror(ret));
11563 }
11564 }
11565
11566 void
11567 lscf_unselect(void)
11568 {
11569 lscf_prep_hndl();
11570
11571 if (cur_snap != NULL) {
11572 struct snaplevel *elt;
11573
11574 elt = uu_list_prev(cur_levels, cur_elt);
11575 if (elt == NULL) {
11576 semerr(gettext("No parent levels.\n"));
11577 } else {
11578 cur_elt = elt;
11579 cur_level = elt->sl;
11580 }
11581 } else if (cur_inst != NULL) {
11582 scf_instance_destroy(cur_inst);
11583 cur_inst = NULL;
11584 } else if (cur_svc != NULL) {
11585 scf_service_destroy(cur_svc);
11586 cur_svc = NULL;
11587 } else {
11588 semerr(gettext("Cannot unselect at scope level.\n"));
11589 }
11590 }
11591
11592 /*
11593 * Return the FMRI of the current selection, for the prompt.
11594 */
11595 void
11596 lscf_get_selection_str(char *buf, size_t bufsz)
11597 {
11598 char *cp;
11599 ssize_t fmrilen, szret;
11600 boolean_t deleted = B_FALSE;
11601
11602 if (g_hndl == NULL) {
11603 (void) strlcpy(buf, "svc:", bufsz);
11604 return;
11605 }
11606
11607 if (cur_level != NULL) {
11608 assert(cur_snap != NULL);
11609
11610 /* [ snapshot ] FMRI [: instance ] */
11611 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11612 + 2 + max_scf_name_len + 1 + 1);
11613
11614 buf[0] = '[';
11615
11616 szret = scf_snapshot_get_name(cur_snap, buf + 1,
11617 max_scf_name_len + 1);
11618 if (szret < 0) {
11619 if (scf_error() != SCF_ERROR_DELETED)
11620 scfdie();
11621
11622 goto snap_deleted;
11623 }
11624
11625 (void) strcat(buf, "]svc:/");
11626
11627 cp = strchr(buf, '\0');
11628
11629 szret = scf_snaplevel_get_service_name(cur_level, cp,
11630 max_scf_name_len + 1);
11631 if (szret < 0) {
11632 if (scf_error() != SCF_ERROR_DELETED)
11633 scfdie();
11634
11635 goto snap_deleted;
11636 }
11637
11638 cp = strchr(cp, '\0');
11639
11640 if (snaplevel_is_instance(cur_level)) {
11641 *cp++ = ':';
11642
11643 if (scf_snaplevel_get_instance_name(cur_level, cp,
11644 max_scf_name_len + 1) < 0) {
11645 if (scf_error() != SCF_ERROR_DELETED)
11646 scfdie();
11647
11648 goto snap_deleted;
11649 }
11650 } else {
11651 *cp++ = '[';
11652 *cp++ = ':';
11653
11654 if (scf_instance_get_name(cur_inst, cp,
11655 max_scf_name_len + 1) < 0) {
11656 if (scf_error() != SCF_ERROR_DELETED)
11657 scfdie();
11658
11659 goto snap_deleted;
11660 }
11661
11662 (void) strcat(buf, "]");
11663 }
11664
11665 return;
11666
11667 snap_deleted:
11668 deleted = B_TRUE;
11669 free(buf);
11670 unselect_cursnap();
11671 }
11672
11673 assert(cur_snap == NULL);
11674
11675 if (cur_inst != NULL) {
11676 assert(cur_svc != NULL);
11677 assert(cur_scope != NULL);
11678
11679 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11680 if (fmrilen >= 0) {
11681 assert(fmrilen < bufsz);
11682 if (deleted)
11683 warn(emsg_deleted);
11684 return;
11685 }
11686
11687 if (scf_error() != SCF_ERROR_DELETED)
11688 scfdie();
11689
11690 deleted = B_TRUE;
11691
11692 scf_instance_destroy(cur_inst);
11693 cur_inst = NULL;
11694 }
11695
11696 if (cur_svc != NULL) {
11697 assert(cur_scope != NULL);
11698
11699 szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11700 if (szret >= 0) {
11701 assert(szret < bufsz);
11702 if (deleted)
11703 warn(emsg_deleted);
11704 return;
11705 }
11706
11707 if (scf_error() != SCF_ERROR_DELETED)
11708 scfdie();
11709
11710 deleted = B_TRUE;
11711 scf_service_destroy(cur_svc);
11712 cur_svc = NULL;
11713 }
11714
11715 assert(cur_scope != NULL);
11716 fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11717
11718 if (fmrilen < 0)
11719 scfdie();
11720
11721 assert(fmrilen < bufsz);
11722 if (deleted)
11723 warn(emsg_deleted);
11724 }
11725
11726 /*
11727 * Entity listing. Entities and colon namespaces (e.g., :properties and
11728 * :statistics) are listed for the current selection.
11729 */
11730 void
11731 lscf_list(const char *pattern)
11732 {
11733 scf_iter_t *iter;
11734 char *buf;
11735 int ret;
11736
11737 lscf_prep_hndl();
11738
11739 if (cur_level != NULL) {
11740 struct snaplevel *elt;
11741
11742 (void) fputs(COLON_NAMESPACES, stdout);
11743
11744 elt = uu_list_next(cur_levels, cur_elt);
11745 if (elt == NULL)
11746 return;
11747
11748 /*
11749 * For now, we know that the next level is an instance. But
11750 * if we ever have multiple scopes, this could be complicated.
11751 */
11752 buf = safe_malloc(max_scf_name_len + 1);
11753 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11754 max_scf_name_len + 1) >= 0) {
11755 (void) puts(buf);
11756 } else {
11757 if (scf_error() != SCF_ERROR_DELETED)
11758 scfdie();
11759 }
11760
11761 free(buf);
11762
11763 return;
11764 }
11765
11766 if (cur_inst != NULL) {
11767 (void) fputs(COLON_NAMESPACES, stdout);
11768 return;
11769 }
11770
11771 iter = scf_iter_create(g_hndl);
11772 if (iter == NULL)
11773 scfdie();
11774
11775 buf = safe_malloc(max_scf_name_len + 1);
11776
11777 if (cur_svc != NULL) {
11778 /* List the instances in this service. */
11779 scf_instance_t *inst;
11780
11781 inst = scf_instance_create(g_hndl);
11782 if (inst == NULL)
11783 scfdie();
11784
11785 if (scf_iter_service_instances(iter, cur_svc) == 0) {
11786 safe_printf(COLON_NAMESPACES);
11787
11788 for (;;) {
11789 ret = scf_iter_next_instance(iter, inst);
11790 if (ret == 0)
11791 break;
11792 if (ret != 1) {
11793 if (scf_error() != SCF_ERROR_DELETED)
11794 scfdie();
11795
11796 break;
11797 }
11798
11799 if (scf_instance_get_name(inst, buf,
11800 max_scf_name_len + 1) >= 0) {
11801 if (pattern == NULL ||
11802 fnmatch(pattern, buf, 0) == 0)
11803 (void) puts(buf);
11804 } else {
11805 if (scf_error() != SCF_ERROR_DELETED)
11806 scfdie();
11807 }
11808 }
11809 } else {
11810 if (scf_error() != SCF_ERROR_DELETED)
11811 scfdie();
11812 }
11813
11814 scf_instance_destroy(inst);
11815 } else {
11816 /* List the services in this scope. */
11817 scf_service_t *svc;
11818
11819 assert(cur_scope != NULL);
11820
11821 svc = scf_service_create(g_hndl);
11822 if (svc == NULL)
11823 scfdie();
11824
11825 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11826 scfdie();
11827
11828 for (;;) {
11829 ret = scf_iter_next_service(iter, svc);
11830 if (ret == 0)
11831 break;
11832 if (ret != 1)
11833 scfdie();
11834
11835 if (scf_service_get_name(svc, buf,
11836 max_scf_name_len + 1) >= 0) {
11837 if (pattern == NULL ||
11838 fnmatch(pattern, buf, 0) == 0)
11839 safe_printf("%s\n", buf);
11840 } else {
11841 if (scf_error() != SCF_ERROR_DELETED)
11842 scfdie();
11843 }
11844 }
11845
11846 scf_service_destroy(svc);
11847 }
11848
11849 free(buf);
11850 scf_iter_destroy(iter);
11851 }
11852
11853 /*
11854 * Entity addition. Creates an empty entity in the current selection.
11855 */
11856 void
11857 lscf_add(const char *name)
11858 {
11859 lscf_prep_hndl();
11860
11861 if (cur_snap != NULL) {
11862 semerr(emsg_cant_modify_snapshots);
11863 } else if (cur_inst != NULL) {
11864 semerr(gettext("Cannot add entities to an instance.\n"));
11865 } else if (cur_svc != NULL) {
11866
11867 if (scf_service_add_instance(cur_svc, name, NULL) !=
11868 SCF_SUCCESS) {
11869 switch (scf_error()) {
11870 case SCF_ERROR_INVALID_ARGUMENT:
11871 semerr(gettext("Invalid name.\n"));
11872 break;
11873
11874 case SCF_ERROR_EXISTS:
11875 semerr(gettext("Instance already exists.\n"));
11876 break;
11877
11878 case SCF_ERROR_PERMISSION_DENIED:
11879 semerr(emsg_permission_denied);
11880 break;
11881
11882 default:
11883 scfdie();
11884 }
11885 }
11886 } else {
11887 assert(cur_scope != NULL);
11888
11889 if (scf_scope_add_service(cur_scope, name, NULL) !=
11890 SCF_SUCCESS) {
11891 switch (scf_error()) {
11892 case SCF_ERROR_INVALID_ARGUMENT:
11893 semerr(gettext("Invalid name.\n"));
11894 break;
11895
11896 case SCF_ERROR_EXISTS:
11897 semerr(gettext("Service already exists.\n"));
11898 break;
11899
11900 case SCF_ERROR_PERMISSION_DENIED:
11901 semerr(emsg_permission_denied);
11902 break;
11903
11904 case SCF_ERROR_BACKEND_READONLY:
11905 semerr(emsg_read_only);
11906 break;
11907
11908 default:
11909 scfdie();
11910 }
11911 }
11912 }
11913 }
11914
11915 /* return 1 if the entity has no persistent pgs, else return 0 */
11916 static int
11917 entity_has_no_pgs(void *ent, int isservice)
11918 {
11919 scf_iter_t *iter = NULL;
11920 scf_propertygroup_t *pg = NULL;
11921 uint32_t flags;
11922 int err;
11923 int ret = 1;
11924
11925 if ((iter = scf_iter_create(g_hndl)) == NULL ||
11926 (pg = scf_pg_create(g_hndl)) == NULL)
11927 scfdie();
11928
11929 if (isservice) {
11930 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11931 scfdie();
11932 } else {
11933 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11934 scfdie();
11935 }
11936
11937 while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11938 if (scf_pg_get_flags(pg, &flags) != 0)
11939 scfdie();
11940
11941 /* skip nonpersistent pgs */
11942 if (flags & SCF_PG_FLAG_NONPERSISTENT)
11943 continue;
11944
11945 ret = 0;
11946 break;
11947 }
11948
11949 if (err == -1)
11950 scfdie();
11951
11952 scf_pg_destroy(pg);
11953 scf_iter_destroy(iter);
11954
11955 return (ret);
11956 }
11957
11958 /* return 1 if the service has no instances, else return 0 */
11959 static int
11960 svc_has_no_insts(scf_service_t *svc)
11961 {
11962 scf_instance_t *inst;
11963 scf_iter_t *iter;
11964 int r;
11965 int ret = 1;
11966
11967 if ((inst = scf_instance_create(g_hndl)) == NULL ||
11968 (iter = scf_iter_create(g_hndl)) == NULL)
11969 scfdie();
11970
11971 if (scf_iter_service_instances(iter, svc) != 0)
11972 scfdie();
11973
11974 r = scf_iter_next_instance(iter, inst);
11975 if (r == 1) {
11976 ret = 0;
11977 } else if (r == 0) {
11978 ret = 1;
11979 } else if (r == -1) {
11980 scfdie();
11981 } else {
11982 bad_error("scf_iter_next_instance", r);
11983 }
11984
11985 scf_iter_destroy(iter);
11986 scf_instance_destroy(inst);
11987
11988 return (ret);
11989 }
11990
11991 /*
11992 * Entity deletion.
11993 */
11994
11995 /*
11996 * Delete the property group <fmri>/:properties/<name>. Returns
11997 * SCF_ERROR_NONE on success (or if the entity is not found),
11998 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
11999 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
12000 * denied.
12001 */
12002 static scf_error_t
12003 delete_dependency_pg(const char *fmri, const char *name)
12004 {
12005 void *entity = NULL;
12006 int isservice;
12007 scf_propertygroup_t *pg = NULL;
12008 scf_error_t result;
12009 char *pgty;
12010 scf_service_t *svc = NULL;
12011 scf_instance_t *inst = NULL;
12012 scf_iter_t *iter = NULL;
12013 char *name_buf = NULL;
12014
12015 result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
12016 switch (result) {
12017 case SCF_ERROR_NONE:
12018 break;
12019
12020 case SCF_ERROR_NO_MEMORY:
12021 uu_die(gettext("Out of memory.\n"));
12022 /* NOTREACHED */
12023
12024 case SCF_ERROR_INVALID_ARGUMENT:
12025 case SCF_ERROR_CONSTRAINT_VIOLATED:
12026 return (SCF_ERROR_INVALID_ARGUMENT);
12027
12028 case SCF_ERROR_NOT_FOUND:
12029 result = SCF_ERROR_NONE;
12030 goto out;
12031
12032 default:
12033 bad_error("fmri_to_entity", result);
12034 }
12035
12036 pg = scf_pg_create(g_hndl);
12037 if (pg == NULL)
12038 scfdie();
12039
12040 if (entity_get_pg(entity, isservice, name, pg) != 0) {
12041 if (scf_error() != SCF_ERROR_NOT_FOUND)
12042 scfdie();
12043
12044 result = SCF_ERROR_NONE;
12045 goto out;
12046 }
12047
12048 pgty = safe_malloc(max_scf_pg_type_len + 1);
12049
12050 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12051 scfdie();
12052
12053 if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
12054 result = SCF_ERROR_TYPE_MISMATCH;
12055 free(pgty);
12056 goto out;
12057 }
12058
12059 free(pgty);
12060
12061 if (scf_pg_delete(pg) != 0) {
12062 result = scf_error();
12063 if (result != SCF_ERROR_PERMISSION_DENIED)
12064 scfdie();
12065 goto out;
12066 }
12067
12068 /*
12069 * We have to handle the case where we've just deleted the last
12070 * property group of a "dummy" entity (instance or service).
12071 * A "dummy" entity is an entity only present to hold an
12072 * external dependency.
12073 * So, in the case we deleted the last property group then we
12074 * can also delete the entity. If the entity is an instance then
12075 * we must verify if this was the last instance for the service
12076 * and if it is, we can also delete the service if it doesn't
12077 * have any property group either.
12078 */
12079
12080 result = SCF_ERROR_NONE;
12081
12082 if (isservice) {
12083 svc = (scf_service_t *)entity;
12084
12085 if ((inst = scf_instance_create(g_hndl)) == NULL ||
12086 (iter = scf_iter_create(g_hndl)) == NULL)
12087 scfdie();
12088
12089 name_buf = safe_malloc(max_scf_name_len + 1);
12090 } else {
12091 inst = (scf_instance_t *)entity;
12092 }
12093
12094 /*
12095 * If the entity is an instance and we've just deleted its last
12096 * property group then we should delete it.
12097 */
12098 if (!isservice && entity_has_no_pgs(entity, isservice)) {
12099 /* find the service before deleting the inst. - needed later */
12100 if ((svc = scf_service_create(g_hndl)) == NULL)
12101 scfdie();
12102
12103 if (scf_instance_get_parent(inst, svc) != 0)
12104 scfdie();
12105
12106 /* delete the instance */
12107 if (scf_instance_delete(inst) != 0) {
12108 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12109 scfdie();
12110
12111 result = SCF_ERROR_PERMISSION_DENIED;
12112 goto out;
12113 }
12114 /* no need to refresh the instance */
12115 inst = NULL;
12116 }
12117
12118 /*
12119 * If the service has no more instances and pgs or we just deleted the
12120 * last instance and the service doesn't have anymore propery groups
12121 * then the service should be deleted.
12122 */
12123 if (svc != NULL &&
12124 svc_has_no_insts(svc) &&
12125 entity_has_no_pgs((void *)svc, 1)) {
12126 if (scf_service_delete(svc) == 0) {
12127 if (isservice) {
12128 /* no need to refresh the service */
12129 svc = NULL;
12130 }
12131
12132 goto out;
12133 }
12134
12135 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12136 scfdie();
12137
12138 result = SCF_ERROR_PERMISSION_DENIED;
12139 }
12140
12141 /* if the entity has not been deleted, refresh it */
12142 if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
12143 (void) refresh_entity(isservice, entity, fmri, inst, iter,
12144 name_buf);
12145 }
12146
12147 out:
12148 if (isservice && (inst != NULL && iter != NULL)) {
12149 free(name_buf);
12150 scf_iter_destroy(iter);
12151 scf_instance_destroy(inst);
12152 }
12153
12154 if (!isservice && svc != NULL) {
12155 scf_service_destroy(svc);
12156 }
12157
12158 scf_pg_destroy(pg);
12159 if (entity != NULL)
12160 entity_destroy(entity, isservice);
12161
12162 return (result);
12163 }
12164
12165 static int
12166 delete_dependents(scf_propertygroup_t *pg)
12167 {
12168 char *pgty, *name, *fmri;
12169 scf_property_t *prop;
12170 scf_value_t *val;
12171 scf_iter_t *iter;
12172 int r;
12173 scf_error_t err;
12174
12175 /* Verify that the pg has the correct type. */
12176 pgty = safe_malloc(max_scf_pg_type_len + 1);
12177 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12178 scfdie();
12179
12180 if (strcmp(pgty, scf_group_framework) != 0) {
12181 if (g_verbose) {
12182 fmri = safe_malloc(max_scf_fmri_len + 1);
12183 if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
12184 scfdie();
12185
12186 warn(gettext("Property group %s is not of expected "
12187 "type %s.\n"), fmri, scf_group_framework);
12188
12189 free(fmri);
12190 }
12191
12192 free(pgty);
12193 return (-1);
12194 }
12195
12196 free(pgty);
12197
12198 /* map delete_dependency_pg onto the properties. */
12199 if ((prop = scf_property_create(g_hndl)) == NULL ||
12200 (val = scf_value_create(g_hndl)) == NULL ||
12201 (iter = scf_iter_create(g_hndl)) == NULL)
12202 scfdie();
12203
12204 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
12205 scfdie();
12206
12207 name = safe_malloc(max_scf_name_len + 1);
12208 fmri = safe_malloc(max_scf_fmri_len + 2);
12209
12210 while ((r = scf_iter_next_property(iter, prop)) == 1) {
12211 scf_type_t ty;
12212
12213 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
12214 scfdie();
12215
12216 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
12217 scfdie();
12218
12219 if ((ty != SCF_TYPE_ASTRING &&
12220 prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
12221 prop_get_val(prop, val) != 0)
12222 continue;
12223
12224 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
12225 scfdie();
12226
12227 err = delete_dependency_pg(fmri, name);
12228 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
12229 if (scf_property_to_fmri(prop, fmri,
12230 max_scf_fmri_len + 2) < 0)
12231 scfdie();
12232
12233 warn(gettext("Value of %s is not a valid FMRI.\n"),
12234 fmri);
12235 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
12236 warn(gettext("Property group \"%s\" of entity \"%s\" "
12237 "does not have dependency type.\n"), name, fmri);
12238 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
12239 warn(gettext("Could not delete property group \"%s\" "
12240 "of entity \"%s\" (permission denied).\n"), name,
12241 fmri);
12242 }
12243 }
12244 if (r == -1)
12245 scfdie();
12246
12247 scf_value_destroy(val);
12248 scf_property_destroy(prop);
12249
12250 return (0);
12251 }
12252
12253 /*
12254 * Returns 1 if the instance may be running, and 0 otherwise.
12255 */
12256 static int
12257 inst_is_running(scf_instance_t *inst)
12258 {
12259 scf_propertygroup_t *pg;
12260 scf_property_t *prop;
12261 scf_value_t *val;
12262 char buf[MAX_SCF_STATE_STRING_SZ];
12263 int ret = 0;
12264 ssize_t szret;
12265
12266 if ((pg = scf_pg_create(g_hndl)) == NULL ||
12267 (prop = scf_property_create(g_hndl)) == NULL ||
12268 (val = scf_value_create(g_hndl)) == NULL)
12269 scfdie();
12270
12271 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
12272 if (scf_error() != SCF_ERROR_NOT_FOUND)
12273 scfdie();
12274 goto out;
12275 }
12276
12277 if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
12278 prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
12279 prop_get_val(prop, val) != 0)
12280 goto out;
12281
12282 szret = scf_value_get_astring(val, buf, sizeof (buf));
12283 assert(szret >= 0);
12284
12285 ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
12286 strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
12287
12288 out:
12289 scf_value_destroy(val);
12290 scf_property_destroy(prop);
12291 scf_pg_destroy(pg);
12292 return (ret);
12293 }
12294
12295 static uint8_t
12296 pg_is_external_dependency(scf_propertygroup_t *pg)
12297 {
12298 char *type;
12299 scf_value_t *val;
12300 scf_property_t *prop;
12301 uint8_t b = B_FALSE;
12302
12303 type = safe_malloc(max_scf_pg_type_len + 1);
12304
12305 if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
12306 scfdie();
12307
12308 if ((prop = scf_property_create(g_hndl)) == NULL ||
12309 (val = scf_value_create(g_hndl)) == NULL)
12310 scfdie();
12311
12312 if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
12313 if (pg_get_prop(pg, scf_property_external, prop) == 0) {
12314 if (scf_property_get_value(prop, val) != 0)
12315 scfdie();
12316 if (scf_value_get_boolean(val, &b) != 0)
12317 scfdie();
12318 }
12319 }
12320
12321 free(type);
12322 (void) scf_value_destroy(val);
12323 (void) scf_property_destroy(prop);
12324
12325 return (b);
12326 }
12327
12328 #define DELETE_FAILURE -1
12329 #define DELETE_SUCCESS_NOEXTDEPS 0
12330 #define DELETE_SUCCESS_EXTDEPS 1
12331
12332 /*
12333 * lscf_instance_delete() deletes an instance. Before calling
12334 * scf_instance_delete(), though, we make sure the instance isn't
12335 * running and delete dependencies in other entities which the instance
12336 * declared as "dependents". If there are dependencies which were
12337 * created for other entities, then instead of deleting the instance we
12338 * make it "empty" by deleting all other property groups and all
12339 * snapshots.
12340 *
12341 * lscf_instance_delete() verifies that there is no external dependency pgs
12342 * before suppressing the instance. If there is, then we must not remove them
12343 * now in case the instance is re-created otherwise the dependencies would be
12344 * lost. The external dependency pgs will be removed if the dependencies are
12345 * removed.
12346 *
12347 * Returns:
12348 * DELETE_FAILURE on failure
12349 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12350 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12351 */
12352 static int
12353 lscf_instance_delete(scf_instance_t *inst, int force)
12354 {
12355 scf_propertygroup_t *pg;
12356 scf_snapshot_t *snap;
12357 scf_iter_t *iter;
12358 int err;
12359 int external = 0;
12360
12361 /* If we're not forcing and the instance is running, refuse. */
12362 if (!force && inst_is_running(inst)) {
12363 char *fmri;
12364
12365 fmri = safe_malloc(max_scf_fmri_len + 1);
12366
12367 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
12368 scfdie();
12369
12370 semerr(gettext("Instance %s may be running. "
12371 "Use delete -f if it is not.\n"), fmri);
12372
12373 free(fmri);
12374 return (DELETE_FAILURE);
12375 }
12376
12377 pg = scf_pg_create(g_hndl);
12378 if (pg == NULL)
12379 scfdie();
12380
12381 if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
12382 (void) delete_dependents(pg);
12383 else if (scf_error() != SCF_ERROR_NOT_FOUND)
12384 scfdie();
12385
12386 scf_pg_destroy(pg);
12387
12388 /*
12389 * If the instance has some external dependencies then we must
12390 * keep them in case the instance is reimported otherwise the
12391 * dependencies would be lost on reimport.
12392 */
12393 if ((iter = scf_iter_create(g_hndl)) == NULL ||
12394 (pg = scf_pg_create(g_hndl)) == NULL)
12395 scfdie();
12396
12397 if (scf_iter_instance_pgs(iter, inst) < 0)
12398 scfdie();
12399
12400 while ((err = scf_iter_next_pg(iter, pg)) == 1) {
12401 if (pg_is_external_dependency(pg)) {
12402 external = 1;
12403 continue;
12404 }
12405
12406 if (scf_pg_delete(pg) != 0) {
12407 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12408 scfdie();
12409 else {
12410 semerr(emsg_permission_denied);
12411
12412 (void) scf_iter_destroy(iter);
12413 (void) scf_pg_destroy(pg);
12414 return (DELETE_FAILURE);
12415 }
12416 }
12417 }
12418
12419 if (err == -1)
12420 scfdie();
12421
12422 (void) scf_iter_destroy(iter);
12423 (void) scf_pg_destroy(pg);
12424
12425 if (external) {
12426 /*
12427 * All the pgs have been deleted for the instance except
12428 * the ones holding the external dependencies.
12429 * For the job to be complete, we must also delete the
12430 * snapshots associated with the instance.
12431 */
12432 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
12433 NULL)
12434 scfdie();
12435 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
12436 scfdie();
12437
12438 if (scf_iter_instance_snapshots(iter, inst) == -1)
12439 scfdie();
12440
12441 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
12442 if (_scf_snapshot_delete(snap) != 0) {
12443 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12444 scfdie();
12445
12446 semerr(emsg_permission_denied);
12447
12448 (void) scf_iter_destroy(iter);
12449 (void) scf_snapshot_destroy(snap);
12450 return (DELETE_FAILURE);
12451 }
12452 }
12453
12454 if (err == -1)
12455 scfdie();
12456
12457 (void) scf_iter_destroy(iter);
12458 (void) scf_snapshot_destroy(snap);
12459 return (DELETE_SUCCESS_EXTDEPS);
12460 }
12461
12462 if (scf_instance_delete(inst) != 0) {
12463 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12464 scfdie();
12465
12466 semerr(emsg_permission_denied);
12467
12468 return (DELETE_FAILURE);
12469 }
12470
12471 return (DELETE_SUCCESS_NOEXTDEPS);
12472 }
12473
12474 /*
12475 * lscf_service_delete() deletes a service. Before calling
12476 * scf_service_delete(), though, we call lscf_instance_delete() for
12477 * each of the instances and delete dependencies in other entities
12478 * which were created as "dependents" of this service. If there are
12479 * dependencies which were created for other entities, then we delete
12480 * all other property groups in the service and leave it as "empty".
12481 *
12482 * lscf_service_delete() verifies that there is no external dependency
12483 * pgs at the instance & service level before suppressing the service.
12484 * If there is, then we must not remove them now in case the service
12485 * is re-imported otherwise the dependencies would be lost. The external
12486 * dependency pgs will be removed if the dependencies are removed.
12487 *
12488 * Returns:
12489 * DELETE_FAILURE on failure
12490 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12491 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12492 */
12493 static int
12494 lscf_service_delete(scf_service_t *svc, int force)
12495 {
12496 int r;
12497 scf_instance_t *inst;
12498 scf_propertygroup_t *pg;
12499 scf_iter_t *iter;
12500 int ret;
12501 int external = 0;
12502
12503 if ((inst = scf_instance_create(g_hndl)) == NULL ||
12504 (pg = scf_pg_create(g_hndl)) == NULL ||
12505 (iter = scf_iter_create(g_hndl)) == NULL)
12506 scfdie();
12507
12508 if (scf_iter_service_instances(iter, svc) != 0)
12509 scfdie();
12510
12511 for (r = scf_iter_next_instance(iter, inst);
12512 r == 1;
12513 r = scf_iter_next_instance(iter, inst)) {
12514
12515 ret = lscf_instance_delete(inst, force);
12516 if (ret == DELETE_FAILURE) {
12517 scf_iter_destroy(iter);
12518 scf_pg_destroy(pg);
12519 scf_instance_destroy(inst);
12520 return (DELETE_FAILURE);
12521 }
12522
12523 /*
12524 * Record the fact that there is some external dependencies
12525 * at the instance level.
12526 */
12527 if (ret == DELETE_SUCCESS_EXTDEPS)
12528 external |= 1;
12529 }
12530
12531 if (r != 0)
12532 scfdie();
12533
12534 /* Delete dependency property groups in dependent services. */
12535 if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12536 (void) delete_dependents(pg);
12537 else if (scf_error() != SCF_ERROR_NOT_FOUND)
12538 scfdie();
12539
12540 scf_iter_destroy(iter);
12541 scf_pg_destroy(pg);
12542 scf_instance_destroy(inst);
12543
12544 /*
12545 * If the service has some external dependencies then we don't
12546 * want to remove them in case the service is re-imported.
12547 */
12548 if ((pg = scf_pg_create(g_hndl)) == NULL ||
12549 (iter = scf_iter_create(g_hndl)) == NULL)
12550 scfdie();
12551
12552 if (scf_iter_service_pgs(iter, svc) < 0)
12553 scfdie();
12554
12555 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12556 if (pg_is_external_dependency(pg)) {
12557 external |= 2;
12558 continue;
12559 }
12560
12561 if (scf_pg_delete(pg) != 0) {
12562 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12563 scfdie();
12564 else {
12565 semerr(emsg_permission_denied);
12566
12567 (void) scf_iter_destroy(iter);
12568 (void) scf_pg_destroy(pg);
12569 return (DELETE_FAILURE);
12570 }
12571 }
12572 }
12573
12574 if (r == -1)
12575 scfdie();
12576
12577 (void) scf_iter_destroy(iter);
12578 (void) scf_pg_destroy(pg);
12579
12580 if (external != 0)
12581 return (DELETE_SUCCESS_EXTDEPS);
12582
12583 if (scf_service_delete(svc) == 0)
12584 return (DELETE_SUCCESS_NOEXTDEPS);
12585
12586 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12587 scfdie();
12588
12589 semerr(emsg_permission_denied);
12590 return (DELETE_FAILURE);
12591 }
12592
12593 static int
12594 delete_callback(void *data, scf_walkinfo_t *wip)
12595 {
12596 int force = (int)data;
12597
12598 if (wip->inst != NULL)
12599 (void) lscf_instance_delete(wip->inst, force);
12600 else
12601 (void) lscf_service_delete(wip->svc, force);
12602
12603 return (0);
12604 }
12605
12606 void
12607 lscf_delete(const char *fmri, int force)
12608 {
12609 scf_service_t *svc;
12610 scf_instance_t *inst;
12611 int ret;
12612
12613 lscf_prep_hndl();
12614
12615 if (cur_snap != NULL) {
12616 if (!snaplevel_is_instance(cur_level)) {
12617 char *buf;
12618
12619 buf = safe_malloc(max_scf_name_len + 1);
12620 if (scf_instance_get_name(cur_inst, buf,
12621 max_scf_name_len + 1) >= 0) {
12622 if (strcmp(buf, fmri) == 0) {
12623 semerr(emsg_cant_modify_snapshots);
12624 free(buf);
12625 return;
12626 }
12627 } else if (scf_error() != SCF_ERROR_DELETED) {
12628 scfdie();
12629 }
12630 free(buf);
12631 }
12632 } else if (cur_inst != NULL) {
12633 /* EMPTY */;
12634 } else if (cur_svc != NULL) {
12635 inst = scf_instance_create(g_hndl);
12636 if (inst == NULL)
12637 scfdie();
12638
12639 if (scf_service_get_instance(cur_svc, fmri, inst) ==
12640 SCF_SUCCESS) {
12641 (void) lscf_instance_delete(inst, force);
12642 scf_instance_destroy(inst);
12643 return;
12644 }
12645
12646 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12647 scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12648 scfdie();
12649
12650 scf_instance_destroy(inst);
12651 } else {
12652 assert(cur_scope != NULL);
12653
12654 svc = scf_service_create(g_hndl);
12655 if (svc == NULL)
12656 scfdie();
12657
12658 if (scf_scope_get_service(cur_scope, fmri, svc) ==
12659 SCF_SUCCESS) {
12660 (void) lscf_service_delete(svc, force);
12661 scf_service_destroy(svc);
12662 return;
12663 }
12664
12665 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12666 scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12667 scfdie();
12668
12669 scf_service_destroy(svc);
12670 }
12671
12672 /*
12673 * Match FMRI to entity.
12674 */
12675 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12676 delete_callback, (void *)force, NULL, semerr)) != 0) {
12677 semerr(gettext("Failed to walk instances: %s\n"),
12678 scf_strerror(ret));
12679 }
12680 }
12681
12682
12683
12684 /*
12685 * :properties commands. These all end with "pg" or "prop" and generally
12686 * operate on the currently selected entity.
12687 */
12688
12689 /*
12690 * Property listing. List the property groups, properties, their types and
12691 * their values for the currently selected entity.
12692 */
12693 static void
12694 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12695 {
12696 char *buf;
12697 uint32_t flags;
12698
12699 buf = safe_malloc(max_scf_pg_type_len + 1);
12700
12701 if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12702 scfdie();
12703
12704 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12705 scfdie();
12706
12707 safe_printf("%-*s %s", namewidth, name, buf);
12708
12709 if (flags & SCF_PG_FLAG_NONPERSISTENT)
12710 safe_printf("\tNONPERSISTENT");
12711
12712 safe_printf("\n");
12713
12714 free(buf);
12715 }
12716
12717 static boolean_t
12718 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12719 {
12720 if (scf_property_get_value(prop, val) == 0) {
12721 return (B_FALSE);
12722 } else {
12723 switch (scf_error()) {
12724 case SCF_ERROR_NOT_FOUND:
12725 return (B_FALSE);
12726 case SCF_ERROR_PERMISSION_DENIED:
12727 case SCF_ERROR_CONSTRAINT_VIOLATED:
12728 return (B_TRUE);
12729 default:
12730 scfdie();
12731 /*NOTREACHED*/
12732 }
12733 }
12734 }
12735
12736 static void
12737 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12738 {
12739 scf_iter_t *iter;
12740 scf_value_t *val;
12741 const char *type;
12742 int multiple_strings = 0;
12743 int ret;
12744
12745 if ((iter = scf_iter_create(g_hndl)) == NULL ||
12746 (val = scf_value_create(g_hndl)) == NULL)
12747 scfdie();
12748
12749 type = prop_to_typestr(prop);
12750 assert(type != NULL);
12751
12752 safe_printf("%-*s %-7s ", len, name, type);
12753
12754 if (prop_has_multiple_values(prop, val) &&
12755 (scf_value_type(val) == SCF_TYPE_ASTRING ||
12756 scf_value_type(val) == SCF_TYPE_USTRING))
12757 multiple_strings = 1;
12758
12759 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12760 scfdie();
12761
12762 while ((ret = scf_iter_next_value(iter, val)) == 1) {
12763 char *buf;
12764 ssize_t vlen, szret;
12765
12766 vlen = scf_value_get_as_string(val, NULL, 0);
12767 if (vlen < 0)
12768 scfdie();
12769
12770 buf = safe_malloc(vlen + 1);
12771
12772 szret = scf_value_get_as_string(val, buf, vlen + 1);
12773 if (szret < 0)
12774 scfdie();
12775 assert(szret <= vlen);
12776
12777 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12778 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12779 safe_printf(" \"");
12780 (void) quote_and_print(buf, stdout, 0);
12781 (void) putchar('"');
12782 if (ferror(stdout)) {
12783 (void) putchar('\n');
12784 uu_die(gettext("Error writing to stdout.\n"));
12785 }
12786 } else {
12787 safe_printf(" %s", buf);
12788 }
12789
12790 free(buf);
12791 }
12792 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12793 scfdie();
12794
12795 if (putchar('\n') != '\n')
12796 uu_die(gettext("Could not output newline"));
12797 }
12798
12799 /*
12800 * Outputs template property group info for the describe subcommand.
12801 * If 'templates' == 2, verbose output is printed in the format expected
12802 * for describe -v, which includes all templates fields. If pg is
12803 * not NULL, we're describing the template data, not an existing property
12804 * group, and formatting should be appropriate for describe -t.
12805 */
12806 static void
12807 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12808 {
12809 char *buf;
12810 uint8_t required;
12811 scf_property_t *stability_prop;
12812 scf_value_t *stability_val;
12813
12814 if (templates == 0)
12815 return;
12816
12817 if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12818 (stability_val = scf_value_create(g_hndl)) == NULL)
12819 scfdie();
12820
12821 if (templates == 2 && pg != NULL) {
12822 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12823 stability_prop) == 0) {
12824 if (prop_check_type(stability_prop,
12825 SCF_TYPE_ASTRING) == 0 &&
12826 prop_get_val(stability_prop, stability_val) == 0) {
12827 char *stability;
12828
12829 stability = safe_malloc(max_scf_value_len + 1);
12830
12831 if (scf_value_get_astring(stability_val,
12832 stability, max_scf_value_len + 1) == -1 &&
12833 scf_error() != SCF_ERROR_NOT_FOUND)
12834 scfdie();
12835
12836 safe_printf("%s%s: %s\n", TMPL_INDENT,
12837 gettext("stability"), stability);
12838
12839 free(stability);
12840 }
12841 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
12842 scfdie();
12843 }
12844
12845 scf_property_destroy(stability_prop);
12846 scf_value_destroy(stability_val);
12847
12848 if (pgt == NULL)
12849 return;
12850
12851 if (pg == NULL || templates == 2) {
12852 /* print type info only if scf_tmpl_pg_name succeeds */
12853 if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12854 if (pg != NULL)
12855 safe_printf("%s", TMPL_INDENT);
12856 safe_printf("%s: ", gettext("name"));
12857 safe_printf("%s\n", buf);
12858 free(buf);
12859 }
12860
12861 /* print type info only if scf_tmpl_pg_type succeeds */
12862 if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12863 if (pg != NULL)
12864 safe_printf("%s", TMPL_INDENT);
12865 safe_printf("%s: ", gettext("type"));
12866 safe_printf("%s\n", buf);
12867 free(buf);
12868 }
12869 }
12870
12871 if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12872 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12873 required ? "true" : "false");
12874
12875 if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12876 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12877 buf);
12878 free(buf);
12879 }
12880
12881 if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12882 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12883 buf);
12884 free(buf);
12885 }
12886
12887 if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12888 if (templates == 2)
12889 safe_printf("%s%s: %s\n", TMPL_INDENT,
12890 gettext("description"), buf);
12891 else
12892 safe_printf("%s%s\n", TMPL_INDENT, buf);
12893 free(buf);
12894 }
12895
12896 }
12897
12898 /*
12899 * With as_value set to true, indent as appropriate for the value level.
12900 * If false, indent to appropriate level for inclusion in constraint
12901 * or choice printout.
12902 */
12903 static void
12904 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12905 int as_value)
12906 {
12907 char *buf;
12908
12909 if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12910 if (as_value == 0)
12911 safe_printf("%s", TMPL_CHOICE_INDENT);
12912 else
12913 safe_printf("%s", TMPL_INDENT);
12914 safe_printf("%s: %s\n", gettext("value common name"), buf);
12915 free(buf);
12916 }
12917
12918 if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12919 if (as_value == 0)
12920 safe_printf("%s", TMPL_CHOICE_INDENT);
12921 else
12922 safe_printf("%s", TMPL_INDENT);
12923 safe_printf("%s: %s\n", gettext("value description"), buf);
12924 free(buf);
12925 }
12926 }
12927
12928 static void
12929 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12930 {
12931 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12932 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12933 safe_printf("%s\n", val_buf);
12934
12935 print_template_value_details(prt, val_buf, 1);
12936 }
12937
12938 static void
12939 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12940 {
12941 int i, printed = 0;
12942 scf_values_t values;
12943 scf_count_ranges_t c_ranges;
12944 scf_int_ranges_t i_ranges;
12945
12946 printed = 0;
12947 i = 0;
12948 if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12949 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12950 gettext("value constraints"));
12951 printed++;
12952 for (i = 0; i < values.value_count; ++i) {
12953 safe_printf("%s%s: %s\n", TMPL_INDENT,
12954 gettext("value name"), values.values_as_strings[i]);
12955 if (verbose == 1)
12956 print_template_value_details(prt,
12957 values.values_as_strings[i], 0);
12958 }
12959
12960 scf_values_destroy(&values);
12961 }
12962
12963 if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12964 if (printed++ == 0)
12965 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12966 gettext("value constraints"));
12967 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12968 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12969 gettext("range"), c_ranges.scr_min[i],
12970 c_ranges.scr_max[i]);
12971 }
12972 scf_count_ranges_destroy(&c_ranges);
12973 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12974 scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
12975 if (printed++ == 0)
12976 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12977 gettext("value constraints"));
12978 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12979 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12980 gettext("range"), i_ranges.sir_min[i],
12981 i_ranges.sir_max[i]);
12982 }
12983 scf_int_ranges_destroy(&i_ranges);
12984 }
12985 }
12986
12987 static void
12988 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
12989 {
12990 int i = 0, printed = 0;
12991 scf_values_t values;
12992 scf_count_ranges_t c_ranges;
12993 scf_int_ranges_t i_ranges;
12994
12995 printed = 0;
12996 if (scf_tmpl_value_name_choices(prt, &values) == 0) {
12997 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12998 gettext("value constraints"));
12999 printed++;
13000 for (i = 0; i < values.value_count; i++) {
13001 safe_printf("%s%s: %s\n", TMPL_INDENT,
13002 gettext("value name"), values.values_as_strings[i]);
13003 if (verbose == 1)
13004 print_template_value_details(prt,
13005 values.values_as_strings[i], 0);
13006 }
13007
13008 scf_values_destroy(&values);
13009 }
13010
13011 if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
13012 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
13013 if (printed++ == 0)
13014 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13015 gettext("value choices"));
13016 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
13017 gettext("range"), c_ranges.scr_min[i],
13018 c_ranges.scr_max[i]);
13019 }
13020 scf_count_ranges_destroy(&c_ranges);
13021 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
13022 scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
13023 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
13024 if (printed++ == 0)
13025 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13026 gettext("value choices"));
13027 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
13028 gettext("range"), i_ranges.sir_min[i],
13029 i_ranges.sir_max[i]);
13030 }
13031 scf_int_ranges_destroy(&i_ranges);
13032 }
13033 }
13034
13035 static void
13036 list_values_by_template(scf_prop_tmpl_t *prt)
13037 {
13038 print_template_constraints(prt, 1);
13039 print_template_choices(prt, 1);
13040 }
13041
13042 static void
13043 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
13044 {
13045 char *val_buf;
13046 scf_iter_t *iter;
13047 scf_value_t *val;
13048 int ret;
13049
13050 if ((iter = scf_iter_create(g_hndl)) == NULL ||
13051 (val = scf_value_create(g_hndl)) == NULL)
13052 scfdie();
13053
13054 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
13055 scfdie();
13056
13057 val_buf = safe_malloc(max_scf_value_len + 1);
13058
13059 while ((ret = scf_iter_next_value(iter, val)) == 1) {
13060 if (scf_value_get_as_string(val, val_buf,
13061 max_scf_value_len + 1) < 0)
13062 scfdie();
13063
13064 print_template_value(prt, val_buf);
13065 }
13066 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
13067 scfdie();
13068 free(val_buf);
13069
13070 print_template_constraints(prt, 0);
13071 print_template_choices(prt, 0);
13072
13073 }
13074
13075 /*
13076 * Outputs property info for the describe subcommand
13077 * Verbose output if templates == 2, -v option of svccfg describe
13078 * Displays template data if prop is not NULL, -t option of svccfg describe
13079 */
13080 static void
13081 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
13082 {
13083 char *buf;
13084 uint8_t u_buf;
13085 int i;
13086 uint64_t min, max;
13087 scf_values_t values;
13088
13089 if (prt == NULL || templates == 0)
13090 return;
13091
13092 if (prop == NULL) {
13093 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
13094 if (scf_tmpl_prop_name(prt, &buf) > 0) {
13095 safe_printf("%s\n", buf);
13096 free(buf);
13097 } else
13098 safe_printf("(%s)\n", gettext("any"));
13099 }
13100
13101 if (prop == NULL || templates == 2) {
13102 if (prop != NULL)
13103 safe_printf("%s", TMPL_INDENT);
13104 else
13105 safe_printf("%s", TMPL_VALUE_INDENT);
13106 safe_printf("%s: ", gettext("type"));
13107 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
13108 safe_printf("%s\n", buf);
13109 free(buf);
13110 } else
13111 safe_printf("(%s)\n", gettext("any"));
13112 }
13113
13114 if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
13115 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
13116 u_buf ? "true" : "false");
13117
13118 if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
13119 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
13120 buf);
13121 free(buf);
13122 }
13123
13124 if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
13125 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
13126 buf);
13127 free(buf);
13128 }
13129
13130 if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
13131 safe_printf("%s%s\n", TMPL_INDENT, buf);
13132 free(buf);
13133 }
13134
13135 if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
13136 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
13137 scf_tmpl_visibility_to_string(u_buf));
13138
13139 if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
13140 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13141 gettext("minimum number of values"), min);
13142 if (max == ULLONG_MAX) {
13143 safe_printf("%s%s: %s\n", TMPL_INDENT,
13144 gettext("maximum number of values"),
13145 gettext("unlimited"));
13146 } else {
13147 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13148 gettext("maximum number of values"), max);
13149 }
13150 }
13151
13152 if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
13153 for (i = 0; i < values.value_count; i++) {
13154 if (i == 0) {
13155 safe_printf("%s%s:", TMPL_INDENT,
13156 gettext("internal separators"));
13157 }
13158 safe_printf(" \"%s\"", values.values_as_strings[i]);
13159 }
13160 safe_printf("\n");
13161 }
13162
13163 if (templates != 2)
13164 return;
13165
13166 if (prop != NULL)
13167 list_values_tmpl(prt, prop);
13168 else
13169 list_values_by_template(prt);
13170 }
13171
13172 static char *
13173 read_astring(scf_propertygroup_t *pg, const char *prop_name)
13174 {
13175 char *rv;
13176
13177 rv = _scf_read_single_astring_from_pg(pg, prop_name);
13178 if (rv == NULL) {
13179 switch (scf_error()) {
13180 case SCF_ERROR_NOT_FOUND:
13181 break;
13182 default:
13183 scfdie();
13184 }
13185 }
13186 return (rv);
13187 }
13188
13189 static void
13190 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
13191 {
13192 size_t doc_len;
13193 size_t man_len;
13194 char *pg_name;
13195 char *text = NULL;
13196 int rv;
13197
13198 doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
13199 man_len = strlen(SCF_PG_TM_MAN_PREFIX);
13200 pg_name = safe_malloc(max_scf_name_len + 1);
13201 while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
13202 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
13203 scfdie();
13204 }
13205 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
13206 /* Display doc_link and and uri */
13207 safe_printf("%s%s:\n", TMPL_INDENT,
13208 gettext("doc_link"));
13209 text = read_astring(pg, SCF_PROPERTY_TM_NAME);
13210 if (text != NULL) {
13211 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13212 TMPL_INDENT, gettext("name"), text);
13213 uu_free(text);
13214 }
13215 text = read_astring(pg, SCF_PROPERTY_TM_URI);
13216 if (text != NULL) {
13217 safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
13218 gettext("uri"), text);
13219 uu_free(text);
13220 }
13221 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
13222 man_len) == 0) {
13223 /* Display manpage title, section and path */
13224 safe_printf("%s%s:\n", TMPL_INDENT,
13225 gettext("manpage"));
13226 text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
13227 if (text != NULL) {
13228 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13229 TMPL_INDENT, gettext("title"), text);
13230 uu_free(text);
13231 }
13232 text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
13233 if (text != NULL) {
13234 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13235 TMPL_INDENT, gettext("section"), text);
13236 uu_free(text);
13237 }
13238 text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
13239 if (text != NULL) {
13240 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13241 TMPL_INDENT, gettext("manpath"), text);
13242 uu_free(text);
13243 }
13244 }
13245 }
13246 if (rv == -1)
13247 scfdie();
13248
13249 done:
13250 free(pg_name);
13251 }
13252
13253 static void
13254 list_entity_tmpl(int templates)
13255 {
13256 char *common_name = NULL;
13257 char *description = NULL;
13258 char *locale = NULL;
13259 scf_iter_t *iter;
13260 scf_propertygroup_t *pg;
13261 scf_property_t *prop;
13262 int r;
13263 scf_value_t *val;
13264
13265 if ((pg = scf_pg_create(g_hndl)) == NULL ||
13266 (prop = scf_property_create(g_hndl)) == NULL ||
13267 (val = scf_value_create(g_hndl)) == NULL ||
13268 (iter = scf_iter_create(g_hndl)) == NULL)
13269 scfdie();
13270
13271 locale = setlocale(LC_MESSAGES, NULL);
13272
13273 if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
13274 common_name = safe_malloc(max_scf_value_len + 1);
13275
13276 /* Try both the current locale and the "C" locale. */
13277 if (scf_pg_get_property(pg, locale, prop) == 0 ||
13278 (scf_error() == SCF_ERROR_NOT_FOUND &&
13279 scf_pg_get_property(pg, "C", prop) == 0)) {
13280 if (prop_get_val(prop, val) == 0 &&
13281 scf_value_get_ustring(val, common_name,
13282 max_scf_value_len + 1) != -1) {
13283 safe_printf("%s%s: %s\n", TMPL_INDENT,
13284 gettext("common name"), common_name);
13285 }
13286 }
13287 }
13288
13289 /*
13290 * Do description, manpages, and doc links if templates == 2.
13291 */
13292 if (templates == 2) {
13293 /* Get the description. */
13294 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
13295 description = safe_malloc(max_scf_value_len + 1);
13296
13297 /* Try both the current locale and the "C" locale. */
13298 if (scf_pg_get_property(pg, locale, prop) == 0 ||
13299 (scf_error() == SCF_ERROR_NOT_FOUND &&
13300 scf_pg_get_property(pg, "C", prop) == 0)) {
13301 if (prop_get_val(prop, val) == 0 &&
13302 scf_value_get_ustring(val, description,
13303 max_scf_value_len + 1) != -1) {
13304 safe_printf("%s%s: %s\n", TMPL_INDENT,
13305 gettext("description"),
13306 description);
13307 }
13308 }
13309 }
13310
13311 /* Process doc_link & manpage elements. */
13312 if (cur_level != NULL) {
13313 r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
13314 SCF_GROUP_TEMPLATE);
13315 } else if (cur_inst != NULL) {
13316 r = scf_iter_instance_pgs_typed(iter, cur_inst,
13317 SCF_GROUP_TEMPLATE);
13318 } else {
13319 r = scf_iter_service_pgs_typed(iter, cur_svc,
13320 SCF_GROUP_TEMPLATE);
13321 }
13322 if (r == 0) {
13323 display_documentation(iter, pg);
13324 }
13325 }
13326
13327 free(common_name);
13328 free(description);
13329 scf_pg_destroy(pg);
13330 scf_property_destroy(prop);
13331 scf_value_destroy(val);
13332 scf_iter_destroy(iter);
13333 }
13334
13335 static void
13336 listtmpl(const char *pattern, int templates)
13337 {
13338 scf_pg_tmpl_t *pgt;
13339 scf_prop_tmpl_t *prt;
13340 char *snapbuf = NULL;
13341 char *fmribuf;
13342 char *pg_name = NULL, *prop_name = NULL;
13343 ssize_t prop_name_size;
13344 char *qual_prop_name;
13345 char *search_name;
13346 int listed = 0;
13347
13348 if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13349 (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
13350 scfdie();
13351
13352 fmribuf = safe_malloc(max_scf_name_len + 1);
13353 qual_prop_name = safe_malloc(max_scf_name_len + 1);
13354
13355 if (cur_snap != NULL) {
13356 snapbuf = safe_malloc(max_scf_name_len + 1);
13357 if (scf_snapshot_get_name(cur_snap, snapbuf,
13358 max_scf_name_len + 1) < 0)
13359 scfdie();
13360 }
13361
13362 if (cur_inst != NULL) {
13363 if (scf_instance_to_fmri(cur_inst, fmribuf,
13364 max_scf_name_len + 1) < 0)
13365 scfdie();
13366 } else if (cur_svc != NULL) {
13367 if (scf_service_to_fmri(cur_svc, fmribuf,
13368 max_scf_name_len + 1) < 0)
13369 scfdie();
13370 } else
13371 abort();
13372
13373 /* If pattern is specified, we want to list only those items. */
13374 while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) {
13375 listed = 0;
13376 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
13377 fnmatch(pattern, pg_name, 0) == 0)) {
13378 list_pg_tmpl(pgt, NULL, templates);
13379 listed++;
13380 }
13381
13382 scf_tmpl_prop_reset(prt);
13383
13384 while (scf_tmpl_iter_props(pgt, prt, 0) == 0) {
13385 search_name = NULL;
13386 prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
13387 if ((prop_name_size > 0) && (pg_name != NULL)) {
13388 if (snprintf(qual_prop_name,
13389 max_scf_name_len + 1, "%s/%s",
13390 pg_name, prop_name) >=
13391 max_scf_name_len + 1) {
13392 prop_name_size = -1;
13393 } else {
13394 search_name = qual_prop_name;
13395 }
13396 }
13397 if (listed > 0 || pattern == NULL ||
13398 (prop_name_size > 0 &&
13399 fnmatch(pattern, search_name,
13400 FNM_PATHNAME) == 0))
13401 list_prop_tmpl(prt, NULL, templates);
13402 if (prop_name != NULL) {
13403 free(prop_name);
13404 prop_name = NULL;
13405 }
13406 }
13407 if (pg_name != NULL) {
13408 free(pg_name);
13409 pg_name = NULL;
13410 }
13411 }
13412
13413 scf_tmpl_prop_destroy(prt);
13414 scf_tmpl_pg_destroy(pgt);
13415 free(snapbuf);
13416 free(fmribuf);
13417 free(qual_prop_name);
13418 }
13419
13420 static void
13421 listprop(const char *pattern, int only_pgs, int templates)
13422 {
13423 scf_propertygroup_t *pg;
13424 scf_property_t *prop;
13425 scf_iter_t *iter, *piter;
13426 char *pgnbuf, *prnbuf, *ppnbuf;
13427 scf_pg_tmpl_t *pgt, *pgtp;
13428 scf_prop_tmpl_t *prt;
13429
13430 void **objects;
13431 char **names;
13432 void **tmpls;
13433 int allocd, i;
13434
13435 int ret;
13436 ssize_t pgnlen, prnlen, szret;
13437 size_t max_len = 0;
13438
13439 if (cur_svc == NULL && cur_inst == NULL) {
13440 semerr(emsg_entity_not_selected);
13441 return;
13442 }
13443
13444 if ((pg = scf_pg_create(g_hndl)) == NULL ||
13445 (prop = scf_property_create(g_hndl)) == NULL ||
13446 (iter = scf_iter_create(g_hndl)) == NULL ||
13447 (piter = scf_iter_create(g_hndl)) == NULL ||
13448 (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13449 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
13450 scfdie();
13451
13452 prnbuf = safe_malloc(max_scf_name_len + 1);
13453
13454 if (cur_level != NULL)
13455 ret = scf_iter_snaplevel_pgs(iter, cur_level);
13456 else if (cur_inst != NULL)
13457 ret = scf_iter_instance_pgs(iter, cur_inst);
13458 else
13459 ret = scf_iter_service_pgs(iter, cur_svc);
13460 if (ret != 0) {
13461 return;
13462 }
13463
13464 /*
13465 * We want to only list items which match pattern, and we want the
13466 * second column to line up, so during the first pass we'll save
13467 * matching items, their names, and their templates in objects,
13468 * names, and tmpls, computing the maximum name length as we go,
13469 * and then we'll print them out.
13470 *
13471 * Note: We always keep an extra slot available so the array can be
13472 * NULL-terminated.
13473 */
13474 i = 0;
13475 allocd = 1;
13476 objects = safe_malloc(sizeof (*objects));
13477 names = safe_malloc(sizeof (*names));
13478 tmpls = safe_malloc(sizeof (*tmpls));
13479
13480 while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13481 int new_pg = 0;
13482 int print_props = 0;
13483 pgtp = NULL;
13484
13485 pgnlen = scf_pg_get_name(pg, NULL, 0);
13486 if (pgnlen < 0)
13487 scfdie();
13488
13489 pgnbuf = safe_malloc(pgnlen + 1);
13490
13491 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
13492 if (szret < 0)
13493 scfdie();
13494 assert(szret <= pgnlen);
13495
13496 if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) {
13497 if (scf_error() != SCF_ERROR_NOT_FOUND)
13498 scfdie();
13499 pgtp = NULL;
13500 } else {
13501 pgtp = pgt;
13502 }
13503
13504 if (pattern == NULL ||
13505 fnmatch(pattern, pgnbuf, 0) == 0) {
13506 if (i+1 >= allocd) {
13507 allocd *= 2;
13508 objects = realloc(objects,
13509 sizeof (*objects) * allocd);
13510 names =
13511 realloc(names, sizeof (*names) * allocd);
13512 tmpls = realloc(tmpls,
13513 sizeof (*tmpls) * allocd);
13514 if (objects == NULL || names == NULL ||
13515 tmpls == NULL)
13516 uu_die(gettext("Out of memory"));
13517 }
13518 objects[i] = pg;
13519 names[i] = pgnbuf;
13520
13521 if (pgtp == NULL)
13522 tmpls[i] = NULL;
13523 else
13524 tmpls[i] = pgt;
13525
13526 ++i;
13527
13528 if (pgnlen > max_len)
13529 max_len = pgnlen;
13530
13531 new_pg = 1;
13532 print_props = 1;
13533 }
13534
13535 if (only_pgs) {
13536 if (new_pg) {
13537 pg = scf_pg_create(g_hndl);
13538 if (pg == NULL)
13539 scfdie();
13540 pgt = scf_tmpl_pg_create(g_hndl);
13541 if (pgt == NULL)
13542 scfdie();
13543 } else
13544 free(pgnbuf);
13545
13546 continue;
13547 }
13548
13549 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13550 scfdie();
13551
13552 while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13553 prnlen = scf_property_get_name(prop, prnbuf,
13554 max_scf_name_len + 1);
13555 if (prnlen < 0)
13556 scfdie();
13557
13558 /* Will prepend the property group name and a slash. */
13559 prnlen += pgnlen + 1;
13560
13561 ppnbuf = safe_malloc(prnlen + 1);
13562
13563 if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13564 prnbuf) < 0)
13565 uu_die("snprintf");
13566
13567 if (pattern == NULL || print_props == 1 ||
13568 fnmatch(pattern, ppnbuf, 0) == 0) {
13569 if (i+1 >= allocd) {
13570 allocd *= 2;
13571 objects = realloc(objects,
13572 sizeof (*objects) * allocd);
13573 names = realloc(names,
13574 sizeof (*names) * allocd);
13575 tmpls = realloc(tmpls,
13576 sizeof (*tmpls) * allocd);
13577 if (objects == NULL || names == NULL ||
13578 tmpls == NULL)
13579 uu_die(gettext(
13580 "Out of memory"));
13581 }
13582
13583 objects[i] = prop;
13584 names[i] = ppnbuf;
13585
13586 if (pgtp != NULL) {
13587 if (scf_tmpl_get_by_prop(pgt, prnbuf,
13588 prt, 0) < 0) {
13589 if (scf_error() !=
13590 SCF_ERROR_NOT_FOUND)
13591 scfdie();
13592 tmpls[i] = NULL;
13593 } else {
13594 tmpls[i] = prt;
13595 }
13596 } else {
13597 tmpls[i] = NULL;
13598 }
13599
13600 ++i;
13601
13602 if (prnlen > max_len)
13603 max_len = prnlen;
13604
13605 prop = scf_property_create(g_hndl);
13606 prt = scf_tmpl_prop_create(g_hndl);
13607 } else {
13608 free(ppnbuf);
13609 }
13610 }
13611
13612 if (new_pg) {
13613 pg = scf_pg_create(g_hndl);
13614 if (pg == NULL)
13615 scfdie();
13616 pgt = scf_tmpl_pg_create(g_hndl);
13617 if (pgt == NULL)
13618 scfdie();
13619 } else
13620 free(pgnbuf);
13621 }
13622 if (ret != 0)
13623 scfdie();
13624
13625 objects[i] = NULL;
13626
13627 scf_pg_destroy(pg);
13628 scf_tmpl_pg_destroy(pgt);
13629 scf_property_destroy(prop);
13630 scf_tmpl_prop_destroy(prt);
13631
13632 for (i = 0; objects[i] != NULL; ++i) {
13633 if (strchr(names[i], '/') == NULL) {
13634 /* property group */
13635 pg = (scf_propertygroup_t *)objects[i];
13636 pgt = (scf_pg_tmpl_t *)tmpls[i];
13637 list_pg_info(pg, names[i], max_len);
13638 list_pg_tmpl(pgt, pg, templates);
13639 free(names[i]);
13640 scf_pg_destroy(pg);
13641 if (pgt != NULL)
13642 scf_tmpl_pg_destroy(pgt);
13643 } else {
13644 /* property */
13645 prop = (scf_property_t *)objects[i];
13646 prt = (scf_prop_tmpl_t *)tmpls[i];
13647 list_prop_info(prop, names[i], max_len);
13648 list_prop_tmpl(prt, prop, templates);
13649 free(names[i]);
13650 scf_property_destroy(prop);
13651 if (prt != NULL)
13652 scf_tmpl_prop_destroy(prt);
13653 }
13654 }
13655
13656 free(names);
13657 free(objects);
13658 free(tmpls);
13659 }
13660
13661 void
13662 lscf_listpg(const char *pattern)
13663 {
13664 lscf_prep_hndl();
13665
13666 listprop(pattern, 1, 0);
13667 }
13668
13669 /*
13670 * Property group and property creation, setting, and deletion. setprop (and
13671 * its alias, addprop) can either create a property group of a given type, or
13672 * it can create or set a property to a given type and list of values.
13673 */
13674 void
13675 lscf_addpg(const char *name, const char *type, const char *flags)
13676 {
13677 scf_propertygroup_t *pg;
13678 int ret;
13679 uint32_t flgs = 0;
13680 const char *cp;
13681
13682
13683 lscf_prep_hndl();
13684
13685 if (cur_snap != NULL) {
13686 semerr(emsg_cant_modify_snapshots);
13687 return;
13688 }
13689
13690 if (cur_inst == NULL && cur_svc == NULL) {
13691 semerr(emsg_entity_not_selected);
13692 return;
13693 }
13694
13695 if (flags != NULL) {
13696 for (cp = flags; *cp != '\0'; ++cp) {
13697 switch (*cp) {
13698 case 'P':
13699 flgs |= SCF_PG_FLAG_NONPERSISTENT;
13700 break;
13701
13702 case 'p':
13703 flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13704 break;
13705
13706 default:
13707 semerr(gettext("Invalid property group flag "
13708 "%c."), *cp);
13709 return;
13710 }
13711 }
13712 }
13713
13714 pg = scf_pg_create(g_hndl);
13715 if (pg == NULL)
13716 scfdie();
13717
13718 if (cur_inst != NULL)
13719 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13720 else
13721 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13722
13723 if (ret != SCF_SUCCESS) {
13724 switch (scf_error()) {
13725 case SCF_ERROR_INVALID_ARGUMENT:
13726 semerr(gettext("Name, type, or flags are invalid.\n"));
13727 break;
13728
13729 case SCF_ERROR_EXISTS:
13730 semerr(gettext("Property group already exists.\n"));
13731 break;
13732
13733 case SCF_ERROR_PERMISSION_DENIED:
13734 semerr(emsg_permission_denied);
13735 break;
13736
13737 case SCF_ERROR_BACKEND_ACCESS:
13738 semerr(gettext("Backend refused access.\n"));
13739 break;
13740
13741 default:
13742 scfdie();
13743 }
13744 }
13745
13746 scf_pg_destroy(pg);
13747
13748 private_refresh();
13749 }
13750
13751 void
13752 lscf_delpg(char *name)
13753 {
13754 lscf_prep_hndl();
13755
13756 if (cur_snap != NULL) {
13757 semerr(emsg_cant_modify_snapshots);
13758 return;
13759 }
13760
13761 if (cur_inst == NULL && cur_svc == NULL) {
13762 semerr(emsg_entity_not_selected);
13763 return;
13764 }
13765
13766 if (strchr(name, '/') != NULL) {
13767 semerr(emsg_invalid_pg_name, name);
13768 return;
13769 }
13770
13771 lscf_delprop(name);
13772 }
13773
13774 /*
13775 * scf_delhash() is used to remove the property group related to the
13776 * hash entry for a specific manifest in the repository. pgname will be
13777 * constructed from the location of the manifest file. If deathrow isn't 0,
13778 * manifest file doesn't need to exist (manifest string will be used as
13779 * an absolute path).
13780 */
13781 void
13782 lscf_delhash(char *manifest, int deathrow)
13783 {
13784 char *pgname;
13785
13786 if (cur_snap != NULL ||
13787 cur_inst != NULL || cur_svc != NULL) {
13788 warn(gettext("error, an entity is selected\n"));
13789 return;
13790 }
13791
13792 /* select smf/manifest */
13793 lscf_select(HASH_SVC);
13794 /*
13795 * Translate the manifest file name to property name. In the deathrow
13796 * case, the manifest file does not need to exist.
13797 */
13798 pgname = mhash_filename_to_propname(manifest,
13799 deathrow ? B_TRUE : B_FALSE);
13800 if (pgname == NULL) {
13801 warn(gettext("cannot resolve pathname for %s\n"), manifest);
13802 return;
13803 }
13804 /* delete the hash property name */
13805 lscf_delpg(pgname);
13806 }
13807
13808 void
13809 lscf_listprop(const char *pattern)
13810 {
13811 lscf_prep_hndl();
13812
13813 listprop(pattern, 0, 0);
13814 }
13815
13816 int
13817 lscf_setprop(const char *pgname, const char *type, const char *value,
13818 const uu_list_t *values)
13819 {
13820 scf_type_t ty, current_ty;
13821 scf_service_t *svc;
13822 scf_propertygroup_t *pg, *parent_pg;
13823 scf_property_t *prop, *parent_prop;
13824 scf_pg_tmpl_t *pgt;
13825 scf_prop_tmpl_t *prt;
13826 int ret, result = 0;
13827 scf_transaction_t *tx;
13828 scf_transaction_entry_t *e;
13829 scf_value_t *v;
13830 uu_list_walk_t *walk;
13831 string_list_t *sp;
13832 char *propname;
13833 int req_quotes = 0;
13834
13835 lscf_prep_hndl();
13836
13837 if ((e = scf_entry_create(g_hndl)) == NULL ||
13838 (svc = scf_service_create(g_hndl)) == NULL ||
13839 (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13840 (pg = scf_pg_create(g_hndl)) == NULL ||
13841 (parent_prop = scf_property_create(g_hndl)) == NULL ||
13842 (prop = scf_property_create(g_hndl)) == NULL ||
13843 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13844 (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13845 (tx = scf_transaction_create(g_hndl)) == NULL)
13846 scfdie();
13847
13848 if (cur_snap != NULL) {
13849 semerr(emsg_cant_modify_snapshots);
13850 goto fail;
13851 }
13852
13853 if (cur_inst == NULL && cur_svc == NULL) {
13854 semerr(emsg_entity_not_selected);
13855 goto fail;
13856 }
13857
13858 propname = strchr(pgname, '/');
13859 if (propname == NULL) {
13860 semerr(gettext("Property names must contain a `/'.\n"));
13861 goto fail;
13862 }
13863
13864 *propname = '\0';
13865 ++propname;
13866
13867 if (type != NULL) {
13868 ty = string_to_type(type);
13869 if (ty == SCF_TYPE_INVALID) {
13870 semerr(gettext("Unknown type \"%s\".\n"), type);
13871 goto fail;
13872 }
13873 }
13874
13875 if (cur_inst != NULL)
13876 ret = scf_instance_get_pg(cur_inst, pgname, pg);
13877 else
13878 ret = scf_service_get_pg(cur_svc, pgname, pg);
13879 if (ret != SCF_SUCCESS) {
13880 switch (scf_error()) {
13881 case SCF_ERROR_NOT_FOUND:
13882 semerr(emsg_no_such_pg, pgname);
13883 goto fail;
13884
13885 case SCF_ERROR_INVALID_ARGUMENT:
13886 semerr(emsg_invalid_pg_name, pgname);
13887 goto fail;
13888
13889 default:
13890 scfdie();
13891 break;
13892 }
13893 }
13894
13895 do {
13896 if (scf_pg_update(pg) == -1)
13897 scfdie();
13898 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13899 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13900 scfdie();
13901
13902 semerr(emsg_permission_denied);
13903 goto fail;
13904 }
13905
13906 ret = scf_pg_get_property(pg, propname, prop);
13907 if (ret == SCF_SUCCESS) {
13908 if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS)
13909 scfdie();
13910
13911 if (type == NULL)
13912 ty = current_ty;
13913 if (scf_transaction_property_change_type(tx, e,
13914 propname, ty) == -1)
13915 scfdie();
13916
13917 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13918 /* Infer the type, if possible. */
13919 if (type == NULL) {
13920 /*
13921 * First check if we're an instance and the
13922 * property is set on the service.
13923 */
13924 if (cur_inst != NULL &&
13925 scf_instance_get_parent(cur_inst,
13926 svc) == 0 &&
13927 scf_service_get_pg(cur_svc, pgname,
13928 parent_pg) == 0 &&
13929 scf_pg_get_property(parent_pg, propname,
13930 parent_prop) == 0 &&
13931 scf_property_type(parent_prop,
13932 ¤t_ty) == 0) {
13933 ty = current_ty;
13934
13935 /* Then check for a type set in a template. */
13936 } else if (scf_tmpl_get_by_pg(pg, pgt,
13937 0) == 0 &&
13938 scf_tmpl_get_by_prop(pgt, propname, prt,
13939 0) == 0 &&
13940 scf_tmpl_prop_type(prt, ¤t_ty) == 0) {
13941 ty = current_ty;
13942
13943 /* If type can't be inferred, fail. */
13944 } else {
13945 semerr(gettext("Type required for new "
13946 "properties.\n"));
13947 goto fail;
13948 }
13949 }
13950 if (scf_transaction_property_new(tx, e, propname,
13951 ty) == -1)
13952 scfdie();
13953 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13954 semerr(emsg_invalid_prop_name, propname);
13955 goto fail;
13956 } else {
13957 scfdie();
13958 }
13959
13960 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13961 req_quotes = 1;
13962
13963 if (value != NULL) {
13964 v = string_to_value(value, ty, 0);
13965
13966 if (v == NULL)
13967 goto fail;
13968
13969 ret = scf_entry_add_value(e, v);
13970 assert(ret == SCF_SUCCESS);
13971 } else {
13972 assert(values != NULL);
13973
13974 walk = uu_list_walk_start((uu_list_t *)values,
13975 UU_DEFAULT);
13976 if (walk == NULL)
13977 uu_die(gettext("Could not walk list"));
13978
13979 for (sp = uu_list_walk_next(walk); sp != NULL;
13980 sp = uu_list_walk_next(walk)) {
13981 v = string_to_value(sp->str, ty, req_quotes);
13982
13983 if (v == NULL) {
13984 scf_entry_destroy_children(e);
13985 goto fail;
13986 }
13987
13988 ret = scf_entry_add_value(e, v);
13989 assert(ret == SCF_SUCCESS);
13990 }
13991 uu_list_walk_end(walk);
13992 }
13993 result = scf_transaction_commit(tx);
13994
13995 scf_transaction_reset(tx);
13996 scf_entry_destroy_children(e);
13997 } while (result == 0);
13998
13999 if (result < 0) {
14000 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14001 scfdie();
14002
14003 semerr(emsg_permission_denied);
14004 goto fail;
14005 }
14006
14007 ret = 0;
14008
14009 private_refresh();
14010
14011 goto cleanup;
14012
14013 fail:
14014 ret = -1;
14015
14016 cleanup:
14017 scf_transaction_destroy(tx);
14018 scf_entry_destroy(e);
14019 scf_service_destroy(svc);
14020 scf_pg_destroy(parent_pg);
14021 scf_pg_destroy(pg);
14022 scf_property_destroy(parent_prop);
14023 scf_property_destroy(prop);
14024 scf_tmpl_pg_destroy(pgt);
14025 scf_tmpl_prop_destroy(prt);
14026
14027 return (ret);
14028 }
14029
14030 void
14031 lscf_delprop(char *pgn)
14032 {
14033 char *slash, *pn;
14034 scf_propertygroup_t *pg;
14035 scf_transaction_t *tx;
14036 scf_transaction_entry_t *e;
14037 int ret;
14038
14039
14040 lscf_prep_hndl();
14041
14042 if (cur_snap != NULL) {
14043 semerr(emsg_cant_modify_snapshots);
14044 return;
14045 }
14046
14047 if (cur_inst == NULL && cur_svc == NULL) {
14048 semerr(emsg_entity_not_selected);
14049 return;
14050 }
14051
14052 pg = scf_pg_create(g_hndl);
14053 if (pg == NULL)
14054 scfdie();
14055
14056 slash = strchr(pgn, '/');
14057 if (slash == NULL) {
14058 pn = NULL;
14059 } else {
14060 *slash = '\0';
14061 pn = slash + 1;
14062 }
14063
14064 if (cur_inst != NULL)
14065 ret = scf_instance_get_pg(cur_inst, pgn, pg);
14066 else
14067 ret = scf_service_get_pg(cur_svc, pgn, pg);
14068 if (ret != SCF_SUCCESS) {
14069 switch (scf_error()) {
14070 case SCF_ERROR_NOT_FOUND:
14071 semerr(emsg_no_such_pg, pgn);
14072 break;
14073
14074 case SCF_ERROR_INVALID_ARGUMENT:
14075 semerr(emsg_invalid_pg_name, pgn);
14076 break;
14077
14078 default:
14079 scfdie();
14080 }
14081
14082 scf_pg_destroy(pg);
14083
14084 return;
14085 }
14086
14087 if (pn == NULL) {
14088 /* Try to delete the property group. */
14089 if (scf_pg_delete(pg) != SCF_SUCCESS) {
14090 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14091 scfdie();
14092
14093 semerr(emsg_permission_denied);
14094 } else {
14095 private_refresh();
14096 }
14097
14098 scf_pg_destroy(pg);
14099 return;
14100 }
14101
14102 e = scf_entry_create(g_hndl);
14103 tx = scf_transaction_create(g_hndl);
14104
14105 do {
14106 if (scf_pg_update(pg) == -1)
14107 scfdie();
14108 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
14109 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14110 scfdie();
14111
14112 semerr(emsg_permission_denied);
14113 break;
14114 }
14115
14116 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
14117 if (scf_error() == SCF_ERROR_NOT_FOUND) {
14118 semerr(gettext("No such property %s/%s.\n"),
14119 pgn, pn);
14120 break;
14121 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14122 semerr(emsg_invalid_prop_name, pn);
14123 break;
14124 } else {
14125 scfdie();
14126 }
14127 }
14128
14129 ret = scf_transaction_commit(tx);
14130
14131 if (ret == 0)
14132 scf_transaction_reset(tx);
14133 } while (ret == 0);
14134
14135 if (ret < 0) {
14136 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14137 scfdie();
14138
14139 semerr(emsg_permission_denied);
14140 } else {
14141 private_refresh();
14142 }
14143
14144 scf_transaction_destroy(tx);
14145 scf_entry_destroy(e);
14146 scf_pg_destroy(pg);
14147 }
14148
14149 /*
14150 * Property editing.
14151 */
14152
14153 static int
14154 write_edit_script(FILE *strm)
14155 {
14156 char *fmribuf;
14157 ssize_t fmrilen;
14158
14159 scf_propertygroup_t *pg;
14160 scf_property_t *prop;
14161 scf_value_t *val;
14162 scf_type_t ty;
14163 int ret, result = 0;
14164 scf_iter_t *iter, *piter, *viter;
14165 char *buf, *tybuf, *pname;
14166 const char *emsg_write_error;
14167
14168
14169 emsg_write_error = gettext("Error writing temoprary file: %s.\n");
14170
14171
14172 /* select fmri */
14173 if (cur_inst != NULL) {
14174 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
14175 if (fmrilen < 0)
14176 scfdie();
14177 fmribuf = safe_malloc(fmrilen + 1);
14178 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
14179 scfdie();
14180 } else {
14181 assert(cur_svc != NULL);
14182 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
14183 if (fmrilen < 0)
14184 scfdie();
14185 fmribuf = safe_malloc(fmrilen + 1);
14186 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
14187 scfdie();
14188 }
14189
14190 if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
14191 warn(emsg_write_error, strerror(errno));
14192 free(fmribuf);
14193 return (-1);
14194 }
14195
14196 free(fmribuf);
14197
14198
14199 if ((pg = scf_pg_create(g_hndl)) == NULL ||
14200 (prop = scf_property_create(g_hndl)) == NULL ||
14201 (val = scf_value_create(g_hndl)) == NULL ||
14202 (iter = scf_iter_create(g_hndl)) == NULL ||
14203 (piter = scf_iter_create(g_hndl)) == NULL ||
14204 (viter = scf_iter_create(g_hndl)) == NULL)
14205 scfdie();
14206
14207 buf = safe_malloc(max_scf_name_len + 1);
14208 tybuf = safe_malloc(max_scf_pg_type_len + 1);
14209 pname = safe_malloc(max_scf_name_len + 1);
14210
14211 if (cur_inst != NULL)
14212 ret = scf_iter_instance_pgs(iter, cur_inst);
14213 else
14214 ret = scf_iter_service_pgs(iter, cur_svc);
14215 if (ret != SCF_SUCCESS)
14216 scfdie();
14217
14218 while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
14219 int ret2;
14220
14221 /*
14222 * # delprop pg
14223 * # addpg pg type
14224 */
14225 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
14226 scfdie();
14227
14228 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
14229 scfdie();
14230
14231 if (fprintf(strm, "# Property group \"%s\"\n"
14232 "# delprop %s\n"
14233 "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
14234 warn(emsg_write_error, strerror(errno));
14235 result = -1;
14236 goto out;
14237 }
14238
14239 /* # setprop pg/prop = (values) */
14240
14241 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
14242 scfdie();
14243
14244 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
14245 int first = 1;
14246 int ret3;
14247 int multiple;
14248 int is_str;
14249 scf_type_t bty;
14250
14251 if (scf_property_get_name(prop, pname,
14252 max_scf_name_len + 1) < 0)
14253 scfdie();
14254
14255 if (scf_property_type(prop, &ty) != 0)
14256 scfdie();
14257
14258 multiple = prop_has_multiple_values(prop, val);
14259
14260 if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
14261 pname, scf_type_to_string(ty), multiple ? "(" : "")
14262 < 0) {
14263 warn(emsg_write_error, strerror(errno));
14264 result = -1;
14265 goto out;
14266 }
14267
14268 (void) scf_type_base_type(ty, &bty);
14269 is_str = (bty == SCF_TYPE_ASTRING);
14270
14271 if (scf_iter_property_values(viter, prop) !=
14272 SCF_SUCCESS)
14273 scfdie();
14274
14275 while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
14276 char *buf;
14277 ssize_t buflen;
14278
14279 buflen = scf_value_get_as_string(val, NULL, 0);
14280 if (buflen < 0)
14281 scfdie();
14282
14283 buf = safe_malloc(buflen + 1);
14284
14285 if (scf_value_get_as_string(val, buf,
14286 buflen + 1) < 0)
14287 scfdie();
14288
14289 if (first)
14290 first = 0;
14291 else {
14292 if (putc(' ', strm) != ' ') {
14293 warn(emsg_write_error,
14294 strerror(errno));
14295 result = -1;
14296 goto out;
14297 }
14298 }
14299
14300 if ((is_str && multiple) ||
14301 strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
14302 (void) putc('"', strm);
14303 (void) quote_and_print(buf, strm, 1);
14304 (void) putc('"', strm);
14305
14306 if (ferror(strm)) {
14307 warn(emsg_write_error,
14308 strerror(errno));
14309 result = -1;
14310 goto out;
14311 }
14312 } else {
14313 if (fprintf(strm, "%s", buf) < 0) {
14314 warn(emsg_write_error,
14315 strerror(errno));
14316 result = -1;
14317 goto out;
14318 }
14319 }
14320
14321 free(buf);
14322 }
14323 if (ret3 < 0 &&
14324 scf_error() != SCF_ERROR_PERMISSION_DENIED)
14325 scfdie();
14326
14327 /* Write closing paren if mult-value property */
14328 if ((multiple && putc(')', strm) == EOF) ||
14329
14330 /* Write final newline */
14331 fputc('\n', strm) == EOF) {
14332 warn(emsg_write_error, strerror(errno));
14333 result = -1;
14334 goto out;
14335 }
14336 }
14337 if (ret2 < 0)
14338 scfdie();
14339
14340 if (fputc('\n', strm) == EOF) {
14341 warn(emsg_write_error, strerror(errno));
14342 result = -1;
14343 goto out;
14344 }
14345 }
14346 if (ret < 0)
14347 scfdie();
14348
14349 out:
14350 free(pname);
14351 free(tybuf);
14352 free(buf);
14353 scf_iter_destroy(viter);
14354 scf_iter_destroy(piter);
14355 scf_iter_destroy(iter);
14356 scf_value_destroy(val);
14357 scf_property_destroy(prop);
14358 scf_pg_destroy(pg);
14359
14360 if (result == 0) {
14361 if (fflush(strm) != 0) {
14362 warn(emsg_write_error, strerror(errno));
14363 return (-1);
14364 }
14365 }
14366
14367 return (result);
14368 }
14369
14370 int
14371 lscf_editprop()
14372 {
14373 char *buf, *editor;
14374 size_t bufsz;
14375 int tmpfd;
14376 char tempname[] = TEMP_FILE_PATTERN;
14377
14378 lscf_prep_hndl();
14379
14380 if (cur_snap != NULL) {
14381 semerr(emsg_cant_modify_snapshots);
14382 return (-1);
14383 }
14384
14385 if (cur_svc == NULL && cur_inst == NULL) {
14386 semerr(emsg_entity_not_selected);
14387 return (-1);
14388 }
14389
14390 tmpfd = mkstemp(tempname);
14391 if (tmpfd == -1) {
14392 semerr(gettext("Could not create temporary file.\n"));
14393 return (-1);
14394 }
14395
14396 (void) strcpy(tempfilename, tempname);
14397
14398 tempfile = fdopen(tmpfd, "r+");
14399 if (tempfile == NULL) {
14400 warn(gettext("Could not create temporary file.\n"));
14401 if (close(tmpfd) == -1)
14402 warn(gettext("Could not close temporary file: %s.\n"),
14403 strerror(errno));
14404
14405 remove_tempfile();
14406
14407 return (-1);
14408 }
14409
14410 if (write_edit_script(tempfile) == -1) {
14411 remove_tempfile();
14412 return (-1);
14413 }
14414
14415 editor = getenv("EDITOR");
14416 if (editor == NULL)
14417 editor = "vi";
14418
14419 bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
14420 buf = safe_malloc(bufsz);
14421
14422 if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
14423 uu_die(gettext("Error creating editor command"));
14424
14425 if (system(buf) == -1) {
14426 semerr(gettext("Could not launch editor %s: %s\n"), editor,
14427 strerror(errno));
14428 free(buf);
14429 remove_tempfile();
14430 return (-1);
14431 }
14432
14433 free(buf);
14434
14435 (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
14436
14437 remove_tempfile();
14438
14439 return (0);
14440 }
14441
14442 static void
14443 add_string(uu_list_t *strlist, const char *str)
14444 {
14445 string_list_t *elem;
14446 elem = safe_malloc(sizeof (*elem));
14447 uu_list_node_init(elem, &elem->node, string_pool);
14448 elem->str = safe_strdup(str);
14449 if (uu_list_append(strlist, elem) != 0)
14450 uu_die(gettext("libuutil error: %s\n"),
14451 uu_strerror(uu_error()));
14452 }
14453
14454 static int
14455 remove_string(uu_list_t *strlist, const char *str)
14456 {
14457 uu_list_walk_t *elems;
14458 string_list_t *sp;
14459
14460 /*
14461 * Find the element that needs to be removed.
14462 */
14463 elems = uu_list_walk_start(strlist, UU_DEFAULT);
14464 while ((sp = uu_list_walk_next(elems)) != NULL) {
14465 if (strcmp(sp->str, str) == 0)
14466 break;
14467 }
14468 uu_list_walk_end(elems);
14469
14470 /*
14471 * Returning 1 here as the value was not found, this
14472 * might not be an error. Leave it to the caller to
14473 * decide.
14474 */
14475 if (sp == NULL) {
14476 return (1);
14477 }
14478
14479 uu_list_remove(strlist, sp);
14480
14481 free(sp->str);
14482 free(sp);
14483
14484 return (0);
14485 }
14486
14487 /*
14488 * Get all property values that don't match the given glob pattern,
14489 * if a pattern is specified.
14490 */
14491 static void
14492 get_prop_values(scf_property_t *prop, uu_list_t *values,
14493 const char *pattern)
14494 {
14495 scf_iter_t *iter;
14496 scf_value_t *val;
14497 int ret;
14498
14499 if ((iter = scf_iter_create(g_hndl)) == NULL ||
14500 (val = scf_value_create(g_hndl)) == NULL)
14501 scfdie();
14502
14503 if (scf_iter_property_values(iter, prop) != 0)
14504 scfdie();
14505
14506 while ((ret = scf_iter_next_value(iter, val)) == 1) {
14507 char *buf;
14508 ssize_t vlen, szret;
14509
14510 vlen = scf_value_get_as_string(val, NULL, 0);
14511 if (vlen < 0)
14512 scfdie();
14513
14514 buf = safe_malloc(vlen + 1);
14515
14516 szret = scf_value_get_as_string(val, buf, vlen + 1);
14517 if (szret < 0)
14518 scfdie();
14519 assert(szret <= vlen);
14520
14521 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14522 add_string(values, buf);
14523
14524 free(buf);
14525 }
14526
14527 if (ret == -1)
14528 scfdie();
14529
14530 scf_value_destroy(val);
14531 scf_iter_destroy(iter);
14532 }
14533
14534 static int
14535 lscf_setpropvalue(const char *pgname, const char *type,
14536 const char *arg, int isadd, int isnotfoundok)
14537 {
14538 scf_type_t ty;
14539 scf_propertygroup_t *pg;
14540 scf_property_t *prop;
14541 int ret, result = 0;
14542 scf_transaction_t *tx;
14543 scf_transaction_entry_t *e;
14544 scf_value_t *v;
14545 string_list_t *sp;
14546 char *propname;
14547 uu_list_t *values;
14548 uu_list_walk_t *walk;
14549 void *cookie = NULL;
14550 char *pattern = NULL;
14551
14552 lscf_prep_hndl();
14553
14554 if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14555 uu_die(gettext("Could not create property list: %s\n"),
14556 uu_strerror(uu_error()));
14557
14558 if (!isadd)
14559 pattern = safe_strdup(arg);
14560
14561 if ((e = scf_entry_create(g_hndl)) == NULL ||
14562 (pg = scf_pg_create(g_hndl)) == NULL ||
14563 (prop = scf_property_create(g_hndl)) == NULL ||
14564 (tx = scf_transaction_create(g_hndl)) == NULL)
14565 scfdie();
14566
14567 if (cur_snap != NULL) {
14568 semerr(emsg_cant_modify_snapshots);
14569 goto fail;
14570 }
14571
14572 if (cur_inst == NULL && cur_svc == NULL) {
14573 semerr(emsg_entity_not_selected);
14574 goto fail;
14575 }
14576
14577 propname = strchr(pgname, '/');
14578 if (propname == NULL) {
14579 semerr(gettext("Property names must contain a `/'.\n"));
14580 goto fail;
14581 }
14582
14583 *propname = '\0';
14584 ++propname;
14585
14586 if (type != NULL) {
14587 ty = string_to_type(type);
14588 if (ty == SCF_TYPE_INVALID) {
14589 semerr(gettext("Unknown type \"%s\".\n"), type);
14590 goto fail;
14591 }
14592 }
14593
14594 if (cur_inst != NULL)
14595 ret = scf_instance_get_pg(cur_inst, pgname, pg);
14596 else
14597 ret = scf_service_get_pg(cur_svc, pgname, pg);
14598 if (ret != 0) {
14599 switch (scf_error()) {
14600 case SCF_ERROR_NOT_FOUND:
14601 if (isnotfoundok) {
14602 result = 0;
14603 } else {
14604 semerr(emsg_no_such_pg, pgname);
14605 result = -1;
14606 }
14607 goto out;
14608
14609 case SCF_ERROR_INVALID_ARGUMENT:
14610 semerr(emsg_invalid_pg_name, pgname);
14611 goto fail;
14612
14613 default:
14614 scfdie();
14615 }
14616 }
14617
14618 do {
14619 if (scf_pg_update(pg) == -1)
14620 scfdie();
14621 if (scf_transaction_start(tx, pg) != 0) {
14622 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14623 scfdie();
14624
14625 semerr(emsg_permission_denied);
14626 goto fail;
14627 }
14628
14629 ret = scf_pg_get_property(pg, propname, prop);
14630 if (ret == 0) {
14631 scf_type_t ptype;
14632 char *pat = pattern;
14633
14634 if (scf_property_type(prop, &ptype) != 0)
14635 scfdie();
14636
14637 if (isadd) {
14638 if (type != NULL && ptype != ty) {
14639 semerr(gettext("Property \"%s\" is not "
14640 "of type \"%s\".\n"), propname,
14641 type);
14642 goto fail;
14643 }
14644
14645 pat = NULL;
14646 } else {
14647 size_t len = strlen(pat);
14648 if (len > 0 && pat[len - 1] == '\"')
14649 pat[len - 1] = '\0';
14650 if (len > 0 && pat[0] == '\"')
14651 pat++;
14652 }
14653
14654 ty = ptype;
14655
14656 get_prop_values(prop, values, pat);
14657
14658 if (isadd)
14659 add_string(values, arg);
14660
14661 if (scf_transaction_property_change(tx, e,
14662 propname, ty) == -1)
14663 scfdie();
14664 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14665 if (isadd) {
14666 if (type == NULL) {
14667 semerr(gettext("Type required "
14668 "for new properties.\n"));
14669 goto fail;
14670 }
14671
14672 add_string(values, arg);
14673
14674 if (scf_transaction_property_new(tx, e,
14675 propname, ty) == -1)
14676 scfdie();
14677 } else if (isnotfoundok) {
14678 result = 0;
14679 goto out;
14680 } else {
14681 semerr(gettext("No such property %s/%s.\n"),
14682 pgname, propname);
14683 result = -1;
14684 goto out;
14685 }
14686 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14687 semerr(emsg_invalid_prop_name, propname);
14688 goto fail;
14689 } else {
14690 scfdie();
14691 }
14692
14693 walk = uu_list_walk_start(values, UU_DEFAULT);
14694 if (walk == NULL)
14695 uu_die(gettext("Could not walk property list.\n"));
14696
14697 for (sp = uu_list_walk_next(walk); sp != NULL;
14698 sp = uu_list_walk_next(walk)) {
14699 v = string_to_value(sp->str, ty, 0);
14700
14701 if (v == NULL) {
14702 scf_entry_destroy_children(e);
14703 goto fail;
14704 }
14705 ret = scf_entry_add_value(e, v);
14706 assert(ret == 0);
14707 }
14708 uu_list_walk_end(walk);
14709
14710 result = scf_transaction_commit(tx);
14711
14712 scf_transaction_reset(tx);
14713 scf_entry_destroy_children(e);
14714 } while (result == 0);
14715
14716 if (result < 0) {
14717 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14718 scfdie();
14719
14720 semerr(emsg_permission_denied);
14721 goto fail;
14722 }
14723
14724 result = 0;
14725
14726 private_refresh();
14727
14728 out:
14729 scf_transaction_destroy(tx);
14730 scf_entry_destroy(e);
14731 scf_pg_destroy(pg);
14732 scf_property_destroy(prop);
14733 free(pattern);
14734
14735 while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14736 free(sp->str);
14737 free(sp);
14738 }
14739
14740 uu_list_destroy(values);
14741
14742 return (result);
14743
14744 fail:
14745 result = -1;
14746 goto out;
14747 }
14748
14749 int
14750 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14751 {
14752 return (lscf_setpropvalue(pgname, type, value, 1, 0));
14753 }
14754
14755 int
14756 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14757 {
14758 return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14759 }
14760
14761 /*
14762 * Look for a standard start method, first in the instance (if any),
14763 * then the service.
14764 */
14765 static const char *
14766 start_method_name(int *in_instance)
14767 {
14768 scf_propertygroup_t *pg;
14769 char **p;
14770 int ret;
14771 scf_instance_t *inst = cur_inst;
14772
14773 if ((pg = scf_pg_create(g_hndl)) == NULL)
14774 scfdie();
14775
14776 again:
14777 for (p = start_method_names; *p != NULL; p++) {
14778 if (inst != NULL)
14779 ret = scf_instance_get_pg(inst, *p, pg);
14780 else
14781 ret = scf_service_get_pg(cur_svc, *p, pg);
14782
14783 if (ret == 0) {
14784 size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14785 char *buf = safe_malloc(bufsz);
14786
14787 if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14788 free(buf);
14789 continue;
14790 }
14791 if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14792 free(buf);
14793 continue;
14794 }
14795
14796 free(buf);
14797 *in_instance = (inst != NULL);
14798 scf_pg_destroy(pg);
14799 return (*p);
14800 }
14801
14802 if (scf_error() == SCF_ERROR_NOT_FOUND)
14803 continue;
14804
14805 scfdie();
14806 }
14807
14808 if (inst != NULL) {
14809 inst = NULL;
14810 goto again;
14811 }
14812
14813 scf_pg_destroy(pg);
14814 return (NULL);
14815 }
14816
14817 static int
14818 addpg(const char *name, const char *type)
14819 {
14820 scf_propertygroup_t *pg;
14821 int ret;
14822
14823 pg = scf_pg_create(g_hndl);
14824 if (pg == NULL)
14825 scfdie();
14826
14827 if (cur_inst != NULL)
14828 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14829 else
14830 ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14831
14832 if (ret != 0) {
14833 switch (scf_error()) {
14834 case SCF_ERROR_EXISTS:
14835 ret = 0;
14836 break;
14837
14838 case SCF_ERROR_PERMISSION_DENIED:
14839 semerr(emsg_permission_denied);
14840 break;
14841
14842 default:
14843 scfdie();
14844 }
14845 }
14846
14847 scf_pg_destroy(pg);
14848 return (ret);
14849 }
14850
14851 int
14852 lscf_setenv(uu_list_t *args, int isunset)
14853 {
14854 int ret = 0;
14855 size_t i;
14856 int argc;
14857 char **argv = NULL;
14858 string_list_t *slp;
14859 char *pattern;
14860 char *prop;
14861 int do_service = 0;
14862 int do_instance = 0;
14863 const char *method = NULL;
14864 const char *name = NULL;
14865 const char *value = NULL;
14866 scf_instance_t *saved_cur_inst = cur_inst;
14867
14868 lscf_prep_hndl();
14869
14870 argc = uu_list_numnodes(args);
14871 if (argc < 1)
14872 goto usage;
14873
14874 argv = calloc(argc + 1, sizeof (char *));
14875 if (argv == NULL)
14876 uu_die(gettext("Out of memory.\n"));
14877
14878 for (slp = uu_list_first(args), i = 0;
14879 slp != NULL;
14880 slp = uu_list_next(args, slp), ++i)
14881 argv[i] = slp->str;
14882
14883 argv[i] = NULL;
14884
14885 opterr = 0;
14886 optind = 0;
14887 for (;;) {
14888 ret = getopt(argc, argv, "sim:");
14889 if (ret == -1)
14890 break;
14891
14892 switch (ret) {
14893 case 's':
14894 do_service = 1;
14895 cur_inst = NULL;
14896 break;
14897
14898 case 'i':
14899 do_instance = 1;
14900 break;
14901
14902 case 'm':
14903 method = optarg;
14904 break;
14905
14906 case '?':
14907 goto usage;
14908
14909 default:
14910 bad_error("getopt", ret);
14911 }
14912 }
14913
14914 argc -= optind;
14915 if ((do_service && do_instance) ||
14916 (isunset && argc != 1) ||
14917 (!isunset && argc != 2))
14918 goto usage;
14919
14920 name = argv[optind];
14921 if (!isunset)
14922 value = argv[optind + 1];
14923
14924 if (cur_snap != NULL) {
14925 semerr(emsg_cant_modify_snapshots);
14926 ret = -1;
14927 goto out;
14928 }
14929
14930 if (cur_inst == NULL && cur_svc == NULL) {
14931 semerr(emsg_entity_not_selected);
14932 ret = -1;
14933 goto out;
14934 }
14935
14936 if (do_instance && cur_inst == NULL) {
14937 semerr(gettext("No instance is selected.\n"));
14938 ret = -1;
14939 goto out;
14940 }
14941
14942 if (do_service && cur_svc == NULL) {
14943 semerr(gettext("No service is selected.\n"));
14944 ret = -1;
14945 goto out;
14946 }
14947
14948 if (method == NULL) {
14949 if (do_instance || do_service) {
14950 method = "method_context";
14951 if (!isunset) {
14952 ret = addpg("method_context",
14953 SCF_GROUP_FRAMEWORK);
14954 if (ret != 0)
14955 goto out;
14956 }
14957 } else {
14958 int in_instance;
14959 method = start_method_name(&in_instance);
14960 if (method == NULL) {
14961 semerr(gettext(
14962 "Couldn't find start method; please "
14963 "specify a method with '-m'.\n"));
14964 ret = -1;
14965 goto out;
14966 }
14967 if (!in_instance)
14968 cur_inst = NULL;
14969 }
14970 } else {
14971 scf_propertygroup_t *pg;
14972 size_t bufsz;
14973 char *buf;
14974 int ret;
14975
14976 if ((pg = scf_pg_create(g_hndl)) == NULL)
14977 scfdie();
14978
14979 if (cur_inst != NULL)
14980 ret = scf_instance_get_pg(cur_inst, method, pg);
14981 else
14982 ret = scf_service_get_pg(cur_svc, method, pg);
14983
14984 if (ret != 0) {
14985 scf_pg_destroy(pg);
14986 switch (scf_error()) {
14987 case SCF_ERROR_NOT_FOUND:
14988 semerr(gettext("Couldn't find the method "
14989 "\"%s\".\n"), method);
14990 goto out;
14991
14992 case SCF_ERROR_INVALID_ARGUMENT:
14993 semerr(gettext("Invalid method name \"%s\".\n"),
14994 method);
14995 goto out;
14996
14997 default:
14998 scfdie();
14999 }
15000 }
15001
15002 bufsz = strlen(SCF_GROUP_METHOD) + 1;
15003 buf = safe_malloc(bufsz);
15004
15005 if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
15006 strcmp(buf, SCF_GROUP_METHOD) != 0) {
15007 semerr(gettext("Property group \"%s\" is not of type "
15008 "\"method\".\n"), method);
15009 ret = -1;
15010 free(buf);
15011 scf_pg_destroy(pg);
15012 goto out;
15013 }
15014
15015 free(buf);
15016 scf_pg_destroy(pg);
15017 }
15018
15019 prop = uu_msprintf("%s/environment", method);
15020 pattern = uu_msprintf("%s=*", name);
15021
15022 if (prop == NULL || pattern == NULL)
15023 uu_die(gettext("Out of memory.\n"));
15024
15025 ret = lscf_delpropvalue(prop, pattern, !isunset);
15026
15027 if (ret == 0 && !isunset) {
15028 uu_free(pattern);
15029 uu_free(prop);
15030 prop = uu_msprintf("%s/environment", method);
15031 pattern = uu_msprintf("%s=%s", name, value);
15032 if (prop == NULL || pattern == NULL)
15033 uu_die(gettext("Out of memory.\n"));
15034 ret = lscf_addpropvalue(prop, "astring:", pattern);
15035 }
15036 uu_free(pattern);
15037 uu_free(prop);
15038
15039 out:
15040 cur_inst = saved_cur_inst;
15041
15042 free(argv);
15043 return (ret);
15044 usage:
15045 ret = -2;
15046 goto out;
15047 }
15048
15049 /*
15050 * Snapshot commands
15051 */
15052
15053 void
15054 lscf_listsnap()
15055 {
15056 scf_snapshot_t *snap;
15057 scf_iter_t *iter;
15058 char *nb;
15059 int r;
15060
15061 lscf_prep_hndl();
15062
15063 if (cur_inst == NULL) {
15064 semerr(gettext("Instance not selected.\n"));
15065 return;
15066 }
15067
15068 if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15069 (iter = scf_iter_create(g_hndl)) == NULL)
15070 scfdie();
15071
15072 if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
15073 scfdie();
15074
15075 nb = safe_malloc(max_scf_name_len + 1);
15076
15077 while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
15078 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
15079 scfdie();
15080
15081 (void) puts(nb);
15082 }
15083 if (r < 0)
15084 scfdie();
15085
15086 free(nb);
15087 scf_iter_destroy(iter);
15088 scf_snapshot_destroy(snap);
15089 }
15090
15091 void
15092 lscf_selectsnap(const char *name)
15093 {
15094 scf_snapshot_t *snap;
15095 scf_snaplevel_t *level;
15096
15097 lscf_prep_hndl();
15098
15099 if (cur_inst == NULL) {
15100 semerr(gettext("Instance not selected.\n"));
15101 return;
15102 }
15103
15104 if (cur_snap != NULL) {
15105 if (name != NULL) {
15106 char *cur_snap_name;
15107 boolean_t nochange;
15108
15109 cur_snap_name = safe_malloc(max_scf_name_len + 1);
15110
15111 if (scf_snapshot_get_name(cur_snap, cur_snap_name,
15112 max_scf_name_len + 1) < 0)
15113 scfdie();
15114
15115 nochange = strcmp(name, cur_snap_name) == 0;
15116
15117 free(cur_snap_name);
15118
15119 if (nochange)
15120 return;
15121 }
15122
15123 unselect_cursnap();
15124 }
15125
15126 if (name == NULL)
15127 return;
15128
15129 if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15130 (level = scf_snaplevel_create(g_hndl)) == NULL)
15131 scfdie();
15132
15133 if (scf_instance_get_snapshot(cur_inst, name, snap) !=
15134 SCF_SUCCESS) {
15135 switch (scf_error()) {
15136 case SCF_ERROR_INVALID_ARGUMENT:
15137 semerr(gettext("Invalid name \"%s\".\n"), name);
15138 break;
15139
15140 case SCF_ERROR_NOT_FOUND:
15141 semerr(gettext("No such snapshot \"%s\".\n"), name);
15142 break;
15143
15144 default:
15145 scfdie();
15146 }
15147
15148 scf_snaplevel_destroy(level);
15149 scf_snapshot_destroy(snap);
15150 return;
15151 }
15152
15153 /* Load the snaplevels into our list. */
15154 cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
15155 if (cur_levels == NULL)
15156 uu_die(gettext("Could not create list: %s\n"),
15157 uu_strerror(uu_error()));
15158
15159 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15160 if (scf_error() != SCF_ERROR_NOT_FOUND)
15161 scfdie();
15162
15163 semerr(gettext("Snapshot has no snaplevels.\n"));
15164
15165 scf_snaplevel_destroy(level);
15166 scf_snapshot_destroy(snap);
15167 return;
15168 }
15169
15170 cur_snap = snap;
15171
15172 for (;;) {
15173 cur_elt = safe_malloc(sizeof (*cur_elt));
15174 uu_list_node_init(cur_elt, &cur_elt->list_node,
15175 snaplevel_pool);
15176 cur_elt->sl = level;
15177 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
15178 uu_die(gettext("libuutil error: %s\n"),
15179 uu_strerror(uu_error()));
15180
15181 level = scf_snaplevel_create(g_hndl);
15182 if (level == NULL)
15183 scfdie();
15184
15185 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
15186 level) != SCF_SUCCESS) {
15187 if (scf_error() != SCF_ERROR_NOT_FOUND)
15188 scfdie();
15189
15190 scf_snaplevel_destroy(level);
15191 break;
15192 }
15193 }
15194
15195 cur_elt = uu_list_last(cur_levels);
15196 cur_level = cur_elt->sl;
15197 }
15198
15199 /*
15200 * Copies the properties & values in src to dst. Assumes src won't change.
15201 * Returns -1 if permission is denied, -2 if another transaction interrupts,
15202 * and 0 on success.
15203 *
15204 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
15205 * property, if it is copied and has type boolean. (See comment in
15206 * lscf_revert()).
15207 */
15208 static int
15209 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
15210 uint8_t enabled)
15211 {
15212 scf_transaction_t *tx;
15213 scf_iter_t *iter, *viter;
15214 scf_property_t *prop;
15215 scf_value_t *v;
15216 char *nbuf;
15217 int r;
15218
15219 tx = scf_transaction_create(g_hndl);
15220 if (tx == NULL)
15221 scfdie();
15222
15223 if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
15224 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15225 scfdie();
15226
15227 scf_transaction_destroy(tx);
15228
15229 return (-1);
15230 }
15231
15232 if ((iter = scf_iter_create(g_hndl)) == NULL ||
15233 (prop = scf_property_create(g_hndl)) == NULL ||
15234 (viter = scf_iter_create(g_hndl)) == NULL)
15235 scfdie();
15236
15237 nbuf = safe_malloc(max_scf_name_len + 1);
15238
15239 if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
15240 scfdie();
15241
15242 for (;;) {
15243 scf_transaction_entry_t *e;
15244 scf_type_t ty;
15245
15246 r = scf_iter_next_property(iter, prop);
15247 if (r == -1)
15248 scfdie();
15249 if (r == 0)
15250 break;
15251
15252 e = scf_entry_create(g_hndl);
15253 if (e == NULL)
15254 scfdie();
15255
15256 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
15257 scfdie();
15258
15259 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
15260 scfdie();
15261
15262 if (scf_transaction_property_new(tx, e, nbuf,
15263 ty) != SCF_SUCCESS)
15264 scfdie();
15265
15266 if ((enabled == 0 || enabled == 1) &&
15267 strcmp(nbuf, scf_property_enabled) == 0 &&
15268 ty == SCF_TYPE_BOOLEAN) {
15269 v = scf_value_create(g_hndl);
15270 if (v == NULL)
15271 scfdie();
15272
15273 scf_value_set_boolean(v, enabled);
15274
15275 if (scf_entry_add_value(e, v) != 0)
15276 scfdie();
15277 } else {
15278 if (scf_iter_property_values(viter, prop) != 0)
15279 scfdie();
15280
15281 for (;;) {
15282 v = scf_value_create(g_hndl);
15283 if (v == NULL)
15284 scfdie();
15285
15286 r = scf_iter_next_value(viter, v);
15287 if (r == -1)
15288 scfdie();
15289 if (r == 0) {
15290 scf_value_destroy(v);
15291 break;
15292 }
15293
15294 if (scf_entry_add_value(e, v) != SCF_SUCCESS)
15295 scfdie();
15296 }
15297 }
15298 }
15299
15300 free(nbuf);
15301 scf_iter_destroy(viter);
15302 scf_property_destroy(prop);
15303 scf_iter_destroy(iter);
15304
15305 r = scf_transaction_commit(tx);
15306 if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
15307 scfdie();
15308
15309 scf_transaction_destroy_children(tx);
15310 scf_transaction_destroy(tx);
15311
15312 switch (r) {
15313 case 1: return (0);
15314 case 0: return (-2);
15315 case -1: return (-1);
15316
15317 default:
15318 abort();
15319 }
15320
15321 /* NOTREACHED */
15322 }
15323
15324 void
15325 lscf_revert(const char *snapname)
15326 {
15327 scf_snapshot_t *snap, *prev;
15328 scf_snaplevel_t *level, *nlevel;
15329 scf_iter_t *iter;
15330 scf_propertygroup_t *pg, *npg;
15331 scf_property_t *prop;
15332 scf_value_t *val;
15333 char *nbuf, *tbuf;
15334 uint8_t enabled;
15335
15336 lscf_prep_hndl();
15337
15338 if (cur_inst == NULL) {
15339 semerr(gettext("Instance not selected.\n"));
15340 return;
15341 }
15342
15343 if (snapname != NULL) {
15344 snap = scf_snapshot_create(g_hndl);
15345 if (snap == NULL)
15346 scfdie();
15347
15348 if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
15349 SCF_SUCCESS) {
15350 switch (scf_error()) {
15351 case SCF_ERROR_INVALID_ARGUMENT:
15352 semerr(gettext("Invalid snapshot name "
15353 "\"%s\".\n"), snapname);
15354 break;
15355
15356 case SCF_ERROR_NOT_FOUND:
15357 semerr(gettext("No such snapshot.\n"));
15358 break;
15359
15360 default:
15361 scfdie();
15362 }
15363
15364 scf_snapshot_destroy(snap);
15365 return;
15366 }
15367 } else {
15368 if (cur_snap != NULL) {
15369 snap = cur_snap;
15370 } else {
15371 semerr(gettext("No snapshot selected.\n"));
15372 return;
15373 }
15374 }
15375
15376 if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
15377 (level = scf_snaplevel_create(g_hndl)) == NULL ||
15378 (iter = scf_iter_create(g_hndl)) == NULL ||
15379 (pg = scf_pg_create(g_hndl)) == NULL ||
15380 (npg = scf_pg_create(g_hndl)) == NULL ||
15381 (prop = scf_property_create(g_hndl)) == NULL ||
15382 (val = scf_value_create(g_hndl)) == NULL)
15383 scfdie();
15384
15385 nbuf = safe_malloc(max_scf_name_len + 1);
15386 tbuf = safe_malloc(max_scf_pg_type_len + 1);
15387
15388 /* Take the "previous" snapshot before we blow away the properties. */
15389 if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
15390 if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
15391 scfdie();
15392 } else {
15393 if (scf_error() != SCF_ERROR_NOT_FOUND)
15394 scfdie();
15395
15396 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
15397 scfdie();
15398 }
15399
15400 /* Save general/enabled, since we're probably going to replace it. */
15401 enabled = 2;
15402 if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
15403 scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
15404 scf_property_get_value(prop, val) == 0)
15405 (void) scf_value_get_boolean(val, &enabled);
15406
15407 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15408 if (scf_error() != SCF_ERROR_NOT_FOUND)
15409 scfdie();
15410
15411 goto out;
15412 }
15413
15414 for (;;) {
15415 boolean_t isinst;
15416 uint32_t flags;
15417 int r;
15418
15419 /* Clear the properties from the corresponding entity. */
15420 isinst = snaplevel_is_instance(level);
15421
15422 if (!isinst)
15423 r = scf_iter_service_pgs(iter, cur_svc);
15424 else
15425 r = scf_iter_instance_pgs(iter, cur_inst);
15426 if (r != SCF_SUCCESS)
15427 scfdie();
15428
15429 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15430 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15431 scfdie();
15432
15433 /* Skip nonpersistent pgs. */
15434 if (flags & SCF_PG_FLAG_NONPERSISTENT)
15435 continue;
15436
15437 if (scf_pg_delete(pg) != SCF_SUCCESS) {
15438 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15439 scfdie();
15440
15441 semerr(emsg_permission_denied);
15442 goto out;
15443 }
15444 }
15445 if (r == -1)
15446 scfdie();
15447
15448 /* Copy the properties to the corresponding entity. */
15449 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
15450 scfdie();
15451
15452 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15453 if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
15454 scfdie();
15455
15456 if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
15457 0)
15458 scfdie();
15459
15460 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15461 scfdie();
15462
15463 if (!isinst)
15464 r = scf_service_add_pg(cur_svc, nbuf, tbuf,
15465 flags, npg);
15466 else
15467 r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
15468 flags, npg);
15469 if (r != SCF_SUCCESS) {
15470 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15471 scfdie();
15472
15473 semerr(emsg_permission_denied);
15474 goto out;
15475 }
15476
15477 if ((enabled == 0 || enabled == 1) &&
15478 strcmp(nbuf, scf_pg_general) == 0)
15479 r = pg_copy(pg, npg, enabled);
15480 else
15481 r = pg_copy(pg, npg, 2);
15482
15483 switch (r) {
15484 case 0:
15485 break;
15486
15487 case -1:
15488 semerr(emsg_permission_denied);
15489 goto out;
15490
15491 case -2:
15492 semerr(gettext(
15493 "Interrupted by another change.\n"));
15494 goto out;
15495
15496 default:
15497 abort();
15498 }
15499 }
15500 if (r == -1)
15501 scfdie();
15502
15503 /* Get next level. */
15504 nlevel = scf_snaplevel_create(g_hndl);
15505 if (nlevel == NULL)
15506 scfdie();
15507
15508 if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
15509 SCF_SUCCESS) {
15510 if (scf_error() != SCF_ERROR_NOT_FOUND)
15511 scfdie();
15512
15513 scf_snaplevel_destroy(nlevel);
15514 break;
15515 }
15516
15517 scf_snaplevel_destroy(level);
15518 level = nlevel;
15519 }
15520
15521 if (snapname == NULL) {
15522 lscf_selectsnap(NULL);
15523 snap = NULL; /* cur_snap has been destroyed */
15524 }
15525
15526 out:
15527 free(tbuf);
15528 free(nbuf);
15529 scf_value_destroy(val);
15530 scf_property_destroy(prop);
15531 scf_pg_destroy(npg);
15532 scf_pg_destroy(pg);
15533 scf_iter_destroy(iter);
15534 scf_snaplevel_destroy(level);
15535 scf_snapshot_destroy(prev);
15536 if (snap != cur_snap)
15537 scf_snapshot_destroy(snap);
15538 }
15539
15540 void
15541 lscf_refresh(void)
15542 {
15543 ssize_t fmrilen;
15544 size_t bufsz;
15545 char *fmribuf;
15546 int r;
15547
15548 lscf_prep_hndl();
15549
15550 if (cur_inst == NULL) {
15551 semerr(gettext("Instance not selected.\n"));
15552 return;
15553 }
15554
15555 bufsz = max_scf_fmri_len + 1;
15556 fmribuf = safe_malloc(bufsz);
15557 fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15558 if (fmrilen < 0) {
15559 free(fmribuf);
15560 if (scf_error() != SCF_ERROR_DELETED)
15561 scfdie();
15562 scf_instance_destroy(cur_inst);
15563 cur_inst = NULL;
15564 warn(emsg_deleted);
15565 return;
15566 }
15567 assert(fmrilen < bufsz);
15568
15569 r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15570 switch (r) {
15571 case 0:
15572 break;
15573
15574 case ECONNABORTED:
15575 warn(gettext("Could not refresh %s "
15576 "(repository connection broken).\n"), fmribuf);
15577 break;
15578
15579 case ECANCELED:
15580 warn(emsg_deleted);
15581 break;
15582
15583 case EPERM:
15584 warn(gettext("Could not refresh %s "
15585 "(permission denied).\n"), fmribuf);
15586 break;
15587
15588 case ENOSPC:
15589 warn(gettext("Could not refresh %s "
15590 "(repository server out of resources).\n"),
15591 fmribuf);
15592 break;
15593
15594 case EACCES:
15595 default:
15596 bad_error("refresh_entity", scf_error());
15597 }
15598
15599 free(fmribuf);
15600 }
15601
15602 /*
15603 * describe [-v] [-t] [pg/prop]
15604 */
15605 int
15606 lscf_describe(uu_list_t *args, int hasargs)
15607 {
15608 int ret = 0;
15609 size_t i;
15610 int argc;
15611 char **argv = NULL;
15612 string_list_t *slp;
15613 int do_verbose = 0;
15614 int do_templates = 0;
15615 char *pattern = NULL;
15616
15617 lscf_prep_hndl();
15618
15619 if (hasargs != 0) {
15620 argc = uu_list_numnodes(args);
15621 if (argc < 1)
15622 goto usage;
15623
15624 argv = calloc(argc + 1, sizeof (char *));
15625 if (argv == NULL)
15626 uu_die(gettext("Out of memory.\n"));
15627
15628 for (slp = uu_list_first(args), i = 0;
15629 slp != NULL;
15630 slp = uu_list_next(args, slp), ++i)
15631 argv[i] = slp->str;
15632
15633 argv[i] = NULL;
15634
15635 /*
15636 * We start optind = 0 because our list of arguments
15637 * starts at argv[0]
15638 */
15639 optind = 0;
15640 opterr = 0;
15641 for (;;) {
15642 ret = getopt(argc, argv, "vt");
15643 if (ret == -1)
15644 break;
15645
15646 switch (ret) {
15647 case 'v':
15648 do_verbose = 1;
15649 break;
15650
15651 case 't':
15652 do_templates = 1;
15653 break;
15654
15655 case '?':
15656 goto usage;
15657
15658 default:
15659 bad_error("getopt", ret);
15660 }
15661 }
15662
15663 pattern = argv[optind];
15664 }
15665
15666 if (cur_inst == NULL && cur_svc == NULL) {
15667 semerr(emsg_entity_not_selected);
15668 ret = -1;
15669 goto out;
15670 }
15671
15672 /*
15673 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15674 * output if their last parameter is set to 2. Less information is
15675 * produced if the parameter is set to 1.
15676 */
15677 if (pattern == NULL) {
15678 if (do_verbose == 1)
15679 list_entity_tmpl(2);
15680 else
15681 list_entity_tmpl(1);
15682 }
15683
15684 if (do_templates == 0) {
15685 if (do_verbose == 1)
15686 listprop(pattern, 0, 2);
15687 else
15688 listprop(pattern, 0, 1);
15689 } else {
15690 if (do_verbose == 1)
15691 listtmpl(pattern, 2);
15692 else
15693 listtmpl(pattern, 1);
15694 }
15695
15696 ret = 0;
15697 out:
15698 if (argv != NULL)
15699 free(argv);
15700 return (ret);
15701 usage:
15702 ret = -2;
15703 goto out;
15704 }
15705
15706 #define PARAM_ACTIVE ((const char *) "active")
15707 #define PARAM_INACTIVE ((const char *) "inactive")
15708 #define PARAM_SMTP_TO ((const char *) "to")
15709
15710 /*
15711 * tokenize()
15712 * Breaks down the string according to the tokens passed.
15713 * Caller is responsible for freeing array of pointers returned.
15714 * Returns NULL on failure
15715 */
15716 char **
15717 tokenize(char *str, const char *sep)
15718 {
15719 char *token, *lasts;
15720 char **buf;
15721 int n = 0; /* number of elements */
15722 int size = 8; /* size of the array (initial) */
15723
15724 buf = safe_malloc(size * sizeof (char *));
15725
15726 for (token = strtok_r(str, sep, &lasts); token != NULL;
15727 token = strtok_r(NULL, sep, &lasts), ++n) {
15728 if (n + 1 >= size) {
15729 size *= 2;
15730 if ((buf = realloc(buf, size * sizeof (char *))) ==
15731 NULL) {
15732 uu_die(gettext("Out of memory"));
15733 }
15734 }
15735 buf[n] = token;
15736 }
15737 /* NULL terminate the pointer array */
15738 buf[n] = NULL;
15739
15740 return (buf);
15741 }
15742
15743 int32_t
15744 check_tokens(char **p)
15745 {
15746 int32_t smf = 0;
15747 int32_t fma = 0;
15748
15749 while (*p) {
15750 int32_t t = string_to_tset(*p);
15751
15752 if (t == 0) {
15753 if (is_fma_token(*p) == 0)
15754 return (INVALID_TOKENS);
15755 fma = 1; /* this token is an fma event */
15756 } else {
15757 smf |= t;
15758 }
15759
15760 if (smf != 0 && fma == 1)
15761 return (MIXED_TOKENS);
15762 ++p;
15763 }
15764
15765 if (smf > 0)
15766 return (smf);
15767 else if (fma == 1)
15768 return (FMA_TOKENS);
15769
15770 return (INVALID_TOKENS);
15771 }
15772
15773 static int
15774 get_selection_str(char *fmri, size_t sz)
15775 {
15776 if (g_hndl == NULL) {
15777 semerr(emsg_entity_not_selected);
15778 return (-1);
15779 } else if (cur_level != NULL) {
15780 semerr(emsg_invalid_for_snapshot);
15781 return (-1);
15782 } else {
15783 lscf_get_selection_str(fmri, sz);
15784 }
15785
15786 return (0);
15787 }
15788
15789 void
15790 lscf_delnotify(const char *set, int global)
15791 {
15792 char *str = strdup(set);
15793 char **pgs;
15794 char **p;
15795 int32_t tset;
15796 char *fmri = NULL;
15797
15798 if (str == NULL)
15799 uu_die(gettext("Out of memory.\n"));
15800
15801 pgs = tokenize(str, ",");
15802
15803 if ((tset = check_tokens(pgs)) > 0) {
15804 size_t sz = max_scf_fmri_len + 1;
15805
15806 fmri = safe_malloc(sz);
15807 if (global) {
15808 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15809 } else if (get_selection_str(fmri, sz) != 0) {
15810 goto out;
15811 }
15812
15813 if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri,
15814 tset) != SCF_SUCCESS) {
15815 uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15816 scf_strerror(scf_error()));
15817 }
15818 } else if (tset == FMA_TOKENS) {
15819 if (global) {
15820 semerr(gettext("Can't use option '-g' with FMA event "
15821 "definitions\n"));
15822 goto out;
15823 }
15824
15825 for (p = pgs; *p; ++p) {
15826 if (smf_notify_del_params(de_tag(*p), NULL, 0) !=
15827 SCF_SUCCESS) {
15828 uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
15829 scf_strerror(scf_error()));
15830 goto out;
15831 }
15832 }
15833 } else if (tset == MIXED_TOKENS) {
15834 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15835 goto out;
15836 } else {
15837 uu_die(gettext("Invalid input.\n"));
15838 }
15839
15840 out:
15841 free(fmri);
15842 free(pgs);
15843 free(str);
15844 }
15845
15846 void
15847 lscf_listnotify(const char *set, int global)
15848 {
15849 char *str = safe_strdup(set);
15850 char **pgs;
15851 char **p;
15852 int32_t tset;
15853 nvlist_t *nvl;
15854 char *fmri = NULL;
15855
15856 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
15857 uu_die(gettext("Out of memory.\n"));
15858
15859 pgs = tokenize(str, ",");
15860
15861 if ((tset = check_tokens(pgs)) > 0) {
15862 size_t sz = max_scf_fmri_len + 1;
15863
15864 fmri = safe_malloc(sz);
15865 if (global) {
15866 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15867 } else if (get_selection_str(fmri, sz) != 0) {
15868 goto out;
15869 }
15870
15871 if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
15872 SCF_SUCCESS) {
15873 if (scf_error() != SCF_ERROR_NOT_FOUND &&
15874 scf_error() != SCF_ERROR_DELETED)
15875 uu_warn(gettext(
15876 "Failed listnotify: %s\n"),
15877 scf_strerror(scf_error()));
15878 goto out;
15879 }
15880
15881 listnotify_print(nvl, NULL);
15882 } else if (tset == FMA_TOKENS) {
15883 if (global) {
15884 semerr(gettext("Can't use option '-g' with FMA event "
15885 "definitions\n"));
15886 goto out;
15887 }
15888
15889 for (p = pgs; *p; ++p) {
15890 if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
15891 SCF_SUCCESS) {
15892 /*
15893 * if the preferences have just been deleted
15894 * or does not exist, just skip.
15895 */
15896 if (scf_error() == SCF_ERROR_NOT_FOUND ||
15897 scf_error() == SCF_ERROR_DELETED)
15898 continue;
15899 uu_warn(gettext(
15900 "Failed listnotify: %s\n"),
15901 scf_strerror(scf_error()));
15902 goto out;
15903 }
15904 listnotify_print(nvl, re_tag(*p));
15905 }
15906 } else if (tset == MIXED_TOKENS) {
15907 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15908 goto out;
15909 } else {
15910 semerr(gettext("Invalid input.\n"));
15911 }
15912
15913 out:
15914 nvlist_free(nvl);
15915 free(fmri);
15916 free(pgs);
15917 free(str);
15918 }
15919
15920 static char *
15921 strip_quotes_and_blanks(char *s)
15922 {
15923 char *start = s;
15924 char *end = strrchr(s, '\"');
15925
15926 if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
15927 start = s + 1;
15928 while (isblank(*start))
15929 start++;
15930 while (isblank(*(end - 1)) && end > start) {
15931 end--;
15932 }
15933 *end = '\0';
15934 }
15935
15936 return (start);
15937 }
15938
15939 static int
15940 set_active(nvlist_t *mech, const char *hier_part)
15941 {
15942 boolean_t b;
15943
15944 if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
15945 b = B_TRUE;
15946 } else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
15947 b = B_FALSE;
15948 } else {
15949 return (-1);
15950 }
15951
15952 if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
15953 uu_die(gettext("Out of memory.\n"));
15954
15955 return (0);
15956 }
15957
15958 static int
15959 add_snmp_params(nvlist_t *mech, char *hier_part)
15960 {
15961 return (set_active(mech, hier_part));
15962 }
15963
15964 static int
15965 add_syslog_params(nvlist_t *mech, char *hier_part)
15966 {
15967 return (set_active(mech, hier_part));
15968 }
15969
15970 /*
15971 * add_mailto_paramas()
15972 * parse the hier_part of mailto URI
15973 * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
15974 * or mailto:{[active]|inactive}
15975 */
15976 static int
15977 add_mailto_params(nvlist_t *mech, char *hier_part)
15978 {
15979 const char *tok = "?&";
15980 char *p;
15981 char *lasts;
15982 char *param;
15983 char *val;
15984
15985 /*
15986 * If the notification parametes are in the form of
15987 *
15988 * malito:{[active]|inactive}
15989 *
15990 * we set the property accordingly and return.
15991 * Otherwise, we make the notification type active and
15992 * process the hier_part.
15993 */
15994 if (set_active(mech, hier_part) == 0)
15995 return (0);
15996 else if (set_active(mech, PARAM_ACTIVE) != 0)
15997 return (-1);
15998
15999 if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) {
16000 /*
16001 * sanity check: we only get here if hier_part = "", but
16002 * that's handled by set_active
16003 */
16004 uu_die("strtok_r");
16005 }
16006
16007 if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0)
16008 uu_die(gettext("Out of memory.\n"));
16009
16010 while ((p = strtok_r(NULL, tok, &lasts)) != NULL)
16011 if ((param = strtok_r(p, "=", &val)) != NULL)
16012 if (nvlist_add_string(mech, param, val) != 0)
16013 uu_die(gettext("Out of memory.\n"));
16014
16015 return (0);
16016 }
16017
16018 static int
16019 uri_split(char *uri, char **scheme, char **hier_part)
16020 {
16021 int r = -1;
16022
16023 if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
16024 *hier_part == NULL) {
16025 semerr(gettext("'%s' is not an URI\n"), uri);
16026 return (r);
16027 }
16028
16029 if ((r = check_uri_scheme(*scheme)) < 0) {
16030 semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
16031 return (r);
16032 }
16033
16034 return (r);
16035 }
16036
16037 static int
16038 process_uri(nvlist_t *params, char *uri)
16039 {
16040 char *scheme;
16041 char *hier_part;
16042 nvlist_t *mech;
16043 int index;
16044 int r;
16045
16046 if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
16047 return (-1);
16048
16049 if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
16050 uu_die(gettext("Out of memory.\n"));
16051
16052 switch (index) {
16053 case 0:
16054 /* error messages displayed by called function */
16055 r = add_mailto_params(mech, hier_part);
16056 break;
16057
16058 case 1:
16059 if ((r = add_snmp_params(mech, hier_part)) != 0)
16060 semerr(gettext("Not valid parameters: '%s'\n"),
16061 hier_part);
16062 break;
16063
16064 case 2:
16065 if ((r = add_syslog_params(mech, hier_part)) != 0)
16066 semerr(gettext("Not valid parameters: '%s'\n"),
16067 hier_part);
16068 break;
16069
16070 default:
16071 r = -1;
16072 }
16073
16074 if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
16075 mech) != 0)
16076 uu_die(gettext("Out of memory.\n"));
16077
16078 nvlist_free(mech);
16079 return (r);
16080 }
16081
16082 static int
16083 set_params(nvlist_t *params, char **p)
16084 {
16085 char *uri;
16086
16087 if (p == NULL)
16088 /* sanity check */
16089 uu_die("set_params");
16090
16091 while (*p) {
16092 uri = strip_quotes_and_blanks(*p);
16093 if (process_uri(params, uri) != 0)
16094 return (-1);
16095
16096 ++p;
16097 }
16098
16099 return (0);
16100 }
16101
16102 static int
16103 setnotify(const char *e, char **p, int global)
16104 {
16105 char *str = safe_strdup(e);
16106 char **events;
16107 int32_t tset;
16108 int r = -1;
16109 nvlist_t *nvl, *params;
16110 char *fmri = NULL;
16111
16112 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
16113 nvlist_alloc(¶ms, NV_UNIQUE_NAME, 0) != 0 ||
16114 nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
16115 SCF_NOTIFY_PARAMS_VERSION) != 0)
16116 uu_die(gettext("Out of memory.\n"));
16117
16118 events = tokenize(str, ",");
16119
16120 if ((tset = check_tokens(events)) > 0) {
16121 /* SMF state transitions parameters */
16122 size_t sz = max_scf_fmri_len + 1;
16123
16124 fmri = safe_malloc(sz);
16125 if (global) {
16126 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
16127 } else if (get_selection_str(fmri, sz) != 0) {
16128 goto out;
16129 }
16130
16131 if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 ||
16132 nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0)
16133 uu_die(gettext("Out of memory.\n"));
16134
16135 if ((r = set_params(params, p)) == 0) {
16136 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS,
16137 params) != 0)
16138 uu_die(gettext("Out of memory.\n"));
16139
16140 if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
16141 nvl) != SCF_SUCCESS) {
16142 r = -1;
16143 uu_warn(gettext(
16144 "Failed smf_notify_set_params(3SCF): %s\n"),
16145 scf_strerror(scf_error()));
16146 }
16147 }
16148 } else if (tset == FMA_TOKENS) {
16149 /* FMA event parameters */
16150 if (global) {
16151 semerr(gettext("Can't use option '-g' with FMA event "
16152 "definitions\n"));
16153 goto out;
16154 }
16155
16156 if ((r = set_params(params, p)) != 0)
16157 goto out;
16158
16159 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
16160 uu_die(gettext("Out of memory.\n"));
16161
16162 while (*events) {
16163 if (smf_notify_set_params(de_tag(*events), nvl) !=
16164 SCF_SUCCESS)
16165 uu_warn(gettext(
16166 "Failed smf_notify_set_params(3SCF) for "
16167 "event %s: %s\n"), *events,
16168 scf_strerror(scf_error()));
16169 events++;
16170 }
16171 } else if (tset == MIXED_TOKENS) {
16172 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
16173 } else {
16174 /* Sanity check */
16175 uu_die(gettext("Invalid input.\n"));
16176 }
16177
16178 out:
16179 nvlist_free(nvl);
16180 nvlist_free(params);
16181 free(fmri);
16182 free(str);
16183
16184 return (r);
16185 }
16186
16187 int
16188 lscf_setnotify(uu_list_t *args)
16189 {
16190 int argc;
16191 char **argv = NULL;
16192 string_list_t *slp;
16193 int global;
16194 char *events;
16195 char **p;
16196 int i;
16197 int ret;
16198
16199 if ((argc = uu_list_numnodes(args)) < 2)
16200 goto usage;
16201
16202 argv = calloc(argc + 1, sizeof (char *));
16203 if (argv == NULL)
16204 uu_die(gettext("Out of memory.\n"));
16205
16206 for (slp = uu_list_first(args), i = 0;
16207 slp != NULL;
16208 slp = uu_list_next(args, slp), ++i)
16209 argv[i] = slp->str;
16210
16211 argv[i] = NULL;
16212
16213 if (strcmp(argv[0], "-g") == 0) {
16214 global = 1;
16215 events = argv[1];
16216 p = argv + 2;
16217 } else {
16218 global = 0;
16219 events = argv[0];
16220 p = argv + 1;
16221 }
16222
16223 ret = setnotify(events, p, global);
16224
16225 out:
16226 free(argv);
16227 return (ret);
16228
16229 usage:
16230 ret = -2;
16231 goto out;
16232 }
16233
16234 /*
16235 * Creates a list of instance name strings associated with a service. If
16236 * wohandcrafted flag is set, get only instances that have a last-import
16237 * snapshot, instances that were imported via svccfg.
16238 */
16239 static uu_list_t *
16240 create_instance_list(scf_service_t *svc, int wohandcrafted)
16241 {
16242 scf_snapshot_t *snap = NULL;
16243 scf_instance_t *inst;
16244 scf_iter_t *inst_iter;
16245 uu_list_t *instances;
16246 char *instname;
16247 int r;
16248
16249 inst_iter = scf_iter_create(g_hndl);
16250 inst = scf_instance_create(g_hndl);
16251 if (inst_iter == NULL || inst == NULL) {
16252 uu_warn(gettext("Could not create instance or iterator\n"));
16253 scfdie();
16254 }
16255
16256 if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
16257 return (instances);
16258
16259 if (scf_iter_service_instances(inst_iter, svc) != 0) {
16260 switch (scf_error()) {
16261 case SCF_ERROR_CONNECTION_BROKEN:
16262 case SCF_ERROR_DELETED:
16263 uu_list_destroy(instances);
16264 instances = NULL;
16265 goto out;
16266
16267 case SCF_ERROR_HANDLE_MISMATCH:
16268 case SCF_ERROR_NOT_BOUND:
16269 case SCF_ERROR_NOT_SET:
16270 default:
16271 bad_error("scf_iter_service_instances", scf_error());
16272 }
16273 }
16274
16275 instname = safe_malloc(max_scf_name_len + 1);
16276 while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
16277 if (r == -1) {
16278 (void) uu_warn(gettext("Unable to iterate through "
16279 "instances to create instance list : %s\n"),
16280 scf_strerror(scf_error()));
16281
16282 uu_list_destroy(instances);
16283 instances = NULL;
16284 goto out;
16285 }
16286
16287 /*
16288 * If the instance does not have a last-import snapshot
16289 * then do not add it to the list as it is a hand-crafted
16290 * instance that should not be managed.
16291 */
16292 if (wohandcrafted) {
16293 if (snap == NULL &&
16294 (snap = scf_snapshot_create(g_hndl)) == NULL) {
16295 uu_warn(gettext("Unable to create snapshot "
16296 "entity\n"));
16297 scfdie();
16298 }
16299
16300 if (scf_instance_get_snapshot(inst,
16301 snap_lastimport, snap) != 0) {
16302 switch (scf_error()) {
16303 case SCF_ERROR_NOT_FOUND :
16304 case SCF_ERROR_DELETED:
16305 continue;
16306
16307 case SCF_ERROR_CONNECTION_BROKEN:
16308 uu_list_destroy(instances);
16309 instances = NULL;
16310 goto out;
16311
16312 case SCF_ERROR_HANDLE_MISMATCH:
16313 case SCF_ERROR_NOT_BOUND:
16314 case SCF_ERROR_NOT_SET:
16315 default:
16316 bad_error("scf_iter_service_instances",
16317 scf_error());
16318 }
16319 }
16320 }
16321
16322 if (scf_instance_get_name(inst, instname,
16323 max_scf_name_len + 1) < 0) {
16324 switch (scf_error()) {
16325 case SCF_ERROR_NOT_FOUND :
16326 continue;
16327
16328 case SCF_ERROR_CONNECTION_BROKEN:
16329 case SCF_ERROR_DELETED:
16330 uu_list_destroy(instances);
16331 instances = NULL;
16332 goto out;
16333
16334 case SCF_ERROR_HANDLE_MISMATCH:
16335 case SCF_ERROR_NOT_BOUND:
16336 case SCF_ERROR_NOT_SET:
16337 default:
16338 bad_error("scf_iter_service_instances",
16339 scf_error());
16340 }
16341 }
16342
16343 add_string(instances, instname);
16344 }
16345
16346 out:
16347 if (snap)
16348 scf_snapshot_destroy(snap);
16349
16350 scf_instance_destroy(inst);
16351 scf_iter_destroy(inst_iter);
16352 free(instname);
16353 return (instances);
16354 }
16355
16356 /*
16357 * disable an instance but wait for the instance to
16358 * move out of the running state.
16359 *
16360 * Returns 0 : if the instance did not disable
16361 * Returns non-zero : if the instance disabled.
16362 *
16363 */
16364 static int
16365 disable_instance(scf_instance_t *instance)
16366 {
16367 char *fmribuf;
16368 int enabled = 10000;
16369
16370 if (inst_is_running(instance)) {
16371 fmribuf = safe_malloc(max_scf_name_len + 1);
16372 if (scf_instance_to_fmri(instance, fmribuf,
16373 max_scf_name_len + 1) < 0) {
16374 free(fmribuf);
16375 return (0);
16376 }
16377
16378 /*
16379 * If the instance cannot be disabled then return
16380 * failure to disable and let the caller decide
16381 * if that is of importance.
16382 */
16383 if (smf_disable_instance(fmribuf, 0) != 0) {
16384 free(fmribuf);
16385 return (0);
16386 }
16387
16388 while (enabled) {
16389 if (!inst_is_running(instance))
16390 break;
16391
16392 (void) poll(NULL, 0, 5);
16393 enabled = enabled - 5;
16394 }
16395
16396 free(fmribuf);
16397 }
16398
16399 return (enabled);
16400 }
16401
16402 /*
16403 * Function to compare two service_manifest structures.
16404 */
16405 /* ARGSUSED2 */
16406 static int
16407 service_manifest_compare(const void *left, const void *right, void *unused)
16408 {
16409 service_manifest_t *l = (service_manifest_t *)left;
16410 service_manifest_t *r = (service_manifest_t *)right;
16411 int rc;
16412
16413 rc = strcmp(l->servicename, r->servicename);
16414
16415 return (rc);
16416 }
16417
16418 /*
16419 * Look for the provided service in the service to manifest
16420 * tree. If the service exists, and a manifest was provided
16421 * then add the manifest to that service. If the service
16422 * does not exist, then add the service and manifest to the
16423 * list.
16424 *
16425 * If the manifest is NULL, return the element if found. If
16426 * the service is not found return NULL.
16427 */
16428 service_manifest_t *
16429 find_add_svc_mfst(const char *svnbuf, const char *mfst)
16430 {
16431 service_manifest_t elem;
16432 service_manifest_t *fnelem;
16433 uu_avl_index_t marker;
16434
16435 elem.servicename = svnbuf;
16436 fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
16437
16438 if (mfst) {
16439 if (fnelem) {
16440 add_string(fnelem->mfstlist, strdup(mfst));
16441 } else {
16442 fnelem = safe_malloc(sizeof (*fnelem));
16443 fnelem->servicename = safe_strdup(svnbuf);
16444 if ((fnelem->mfstlist =
16445 uu_list_create(string_pool, NULL, 0)) == NULL)
16446 uu_die(gettext("Could not create property "
16447 "list: %s\n"), uu_strerror(uu_error()));
16448
16449 add_string(fnelem->mfstlist, safe_strdup(mfst));
16450
16451 uu_avl_insert(service_manifest_tree, fnelem, marker);
16452 }
16453 }
16454
16455 return (fnelem);
16456 }
16457
16458 /*
16459 * Create the service to manifest avl tree.
16460 *
16461 * Walk each of the manifests currently installed in the supported
16462 * directories, /lib/svc/manifests and /var/svc/manifests. For
16463 * each of the manifests, inventory the services and add them to
16464 * the tree.
16465 *
16466 * Code that calls this function should make sure fileystem/minimal is online,
16467 * /var is available, since this function walks the /var/svc/manifest directory.
16468 */
16469 static void
16470 create_manifest_tree(void)
16471 {
16472 manifest_info_t **entry;
16473 manifest_info_t **manifests;
16474 uu_list_walk_t *svcs;
16475 bundle_t *b;
16476 entity_t *mfsvc;
16477 char *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
16478 int c, status;
16479
16480 if (service_manifest_pool)
16481 return;
16482
16483 /*
16484 * Create the list pool for the service manifest list
16485 */
16486 service_manifest_pool = uu_avl_pool_create("service_manifest",
16487 sizeof (service_manifest_t),
16488 offsetof(service_manifest_t, svcmfst_node),
16489 service_manifest_compare, UU_DEFAULT);
16490 if (service_manifest_pool == NULL)
16491 uu_die(gettext("service_manifest pool creation failed: %s\n"),
16492 uu_strerror(uu_error()));
16493
16494 /*
16495 * Create the list
16496 */
16497 service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
16498 UU_DEFAULT);
16499 if (service_manifest_tree == NULL)
16500 uu_die(gettext("service_manifest tree creation failed: %s\n"),
16501 uu_strerror(uu_error()));
16502
16503 /*
16504 * Walk the manifests adding the service(s) from each manifest.
16505 *
16506 * If a service already exists add the manifest to the manifest
16507 * list for that service. This covers the case of a service that
16508 * is supported by multiple manifest files.
16509 */
16510 for (c = 0; dirs[c]; c++) {
16511 status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT);
16512 if (status < 0) {
16513 uu_warn(gettext("file tree walk of %s encountered "
16514 "error %s\n"), dirs[c], strerror(errno));
16515
16516 uu_avl_destroy(service_manifest_tree);
16517 service_manifest_tree = NULL;
16518 return;
16519 }
16520
16521 /*
16522 * If a manifest that was in the list is not found
16523 * then skip and go to the next manifest file.
16524 */
16525 if (manifests != NULL) {
16526 for (entry = manifests; *entry != NULL; entry++) {
16527 b = internal_bundle_new();
16528 if (lxml_get_bundle_file(b, (*entry)->mi_path,
16529 SVCCFG_OP_IMPORT) != 0) {
16530 internal_bundle_free(b);
16531 continue;
16532 }
16533
16534 svcs = uu_list_walk_start(b->sc_bundle_services,
16535 0);
16536 if (svcs == NULL) {
16537 internal_bundle_free(b);
16538 continue;
16539 }
16540
16541 while ((mfsvc = uu_list_walk_next(svcs)) !=
16542 NULL) {
16543 /* Add manifest to service */
16544 (void) find_add_svc_mfst(mfsvc->sc_name,
16545 (*entry)->mi_path);
16546 }
16547
16548 uu_list_walk_end(svcs);
16549 internal_bundle_free(b);
16550 }
16551
16552 free_manifest_array(manifests);
16553 }
16554 }
16555 }
16556
16557 /*
16558 * Check the manifest history file to see
16559 * if the service was ever installed from
16560 * one of the supported directories.
16561 *
16562 * Return Values :
16563 * -1 - if there's error reading manifest history file
16564 * 1 - if the service is not found
16565 * 0 - if the service is found
16566 */
16567 static int
16568 check_mfst_history(const char *svcname)
16569 {
16570 struct stat st;
16571 caddr_t mfsthist_start;
16572 char *svnbuf;
16573 int fd;
16574 int r = 1;
16575
16576 fd = open(MFSTHISTFILE, O_RDONLY);
16577 if (fd == -1) {
16578 uu_warn(gettext("Unable to open the history file\n"));
16579 return (-1);
16580 }
16581
16582 if (fstat(fd, &st) == -1) {
16583 uu_warn(gettext("Unable to stat the history file\n"));
16584 return (-1);
16585 }
16586
16587 mfsthist_start = mmap(0, st.st_size, PROT_READ,
16588 MAP_PRIVATE, fd, 0);
16589
16590 (void) close(fd);
16591 if (mfsthist_start == MAP_FAILED ||
16592 *(mfsthist_start + st.st_size) != '\0') {
16593 (void) munmap(mfsthist_start, st.st_size);
16594 return (-1);
16595 }
16596
16597 /*
16598 * The manifest history file is a space delimited list
16599 * of service and instance to manifest linkage. Adding
16600 * a space to the end of the service name so to get only
16601 * the service that is being searched for.
16602 */
16603 svnbuf = uu_msprintf("%s ", svcname);
16604 if (svnbuf == NULL)
16605 uu_die(gettext("Out of memory"));
16606
16607 if (strstr(mfsthist_start, svnbuf) != NULL)
16608 r = 0;
16609
16610 (void) munmap(mfsthist_start, st.st_size);
16611 uu_free(svnbuf);
16612 return (r);
16613 }
16614
16615 /*
16616 * Take down each of the instances in the service
16617 * and remove them, then delete the service.
16618 */
16619 static void
16620 teardown_service(scf_service_t *svc, const char *svnbuf)
16621 {
16622 scf_instance_t *instance;
16623 scf_iter_t *iter;
16624 int r;
16625
16626 safe_printf(gettext("Delete service %s as there are no "
16627 "supporting manifests\n"), svnbuf);
16628
16629 instance = scf_instance_create(g_hndl);
16630 iter = scf_iter_create(g_hndl);
16631 if (iter == NULL || instance == NULL) {
16632 uu_warn(gettext("Unable to create supporting entities to "
16633 "teardown the service\n"));
16634 uu_warn(gettext("scf error is : %s\n"),
16635 scf_strerror(scf_error()));
16636 scfdie();
16637 }
16638
16639 if (scf_iter_service_instances(iter, svc) != 0) {
16640 switch (scf_error()) {
16641 case SCF_ERROR_CONNECTION_BROKEN:
16642 case SCF_ERROR_DELETED:
16643 goto out;
16644
16645 case SCF_ERROR_HANDLE_MISMATCH:
16646 case SCF_ERROR_NOT_BOUND:
16647 case SCF_ERROR_NOT_SET:
16648 default:
16649 bad_error("scf_iter_service_instances",
16650 scf_error());
16651 }
16652 }
16653
16654 while ((r = scf_iter_next_instance(iter, instance)) != 0) {
16655 if (r == -1) {
16656 uu_warn(gettext("Error - %s\n"),
16657 scf_strerror(scf_error()));
16658 goto out;
16659 }
16660
16661 (void) disable_instance(instance);
16662 }
16663
16664 /*
16665 * Delete the service... forcing the deletion in case
16666 * any of the instances did not disable.
16667 */
16668 (void) lscf_service_delete(svc, 1);
16669 out:
16670 scf_instance_destroy(instance);
16671 scf_iter_destroy(iter);
16672 }
16673
16674 /*
16675 * Get the list of instances supported by the manifest
16676 * file.
16677 *
16678 * Return 0 if there are no instances.
16679 *
16680 * Return -1 if there are errors attempting to collect instances.
16681 *
16682 * Return the count of instances found if there are no errors.
16683 *
16684 */
16685 static int
16686 check_instance_support(char *mfstfile, const char *svcname,
16687 uu_list_t *instances)
16688 {
16689 uu_list_walk_t *svcs, *insts;
16690 uu_list_t *ilist;
16691 bundle_t *b;
16692 entity_t *mfsvc, *mfinst;
16693 const char *svcn;
16694 int rminstcnt = 0;
16695
16696
16697 b = internal_bundle_new();
16698
16699 if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
16700 /*
16701 * Unable to process the manifest file for
16702 * instance support, so just return as
16703 * don't want to remove instances that could
16704 * not be accounted for that might exist here.
16705 */
16706 internal_bundle_free(b);
16707 return (0);
16708 }
16709
16710 svcs = uu_list_walk_start(b->sc_bundle_services, 0);
16711 if (svcs == NULL) {
16712 internal_bundle_free(b);
16713 return (0);
16714 }
16715
16716 svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
16717 (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
16718
16719 while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
16720 if (strcmp(mfsvc->sc_name, svcn) == 0)
16721 break;
16722 }
16723 uu_list_walk_end(svcs);
16724
16725 if (mfsvc == NULL) {
16726 internal_bundle_free(b);
16727 return (-1);
16728 }
16729
16730 ilist = mfsvc->sc_u.sc_service.sc_service_instances;
16731 if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
16732 internal_bundle_free(b);
16733 return (0);
16734 }
16735
16736 while ((mfinst = uu_list_walk_next(insts)) != NULL) {
16737 /*
16738 * Remove the instance from the instances list.
16739 * The unaccounted for instances will be removed
16740 * from the service once all manifests are
16741 * processed.
16742 */
16743 (void) remove_string(instances,
16744 mfinst->sc_name);
16745 rminstcnt++;
16746 }
16747
16748 uu_list_walk_end(insts);
16749 internal_bundle_free(b);
16750
16751 return (rminstcnt);
16752 }
16753
16754 /*
16755 * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16756 * 'false' to indicate there's no manifest file(s) found for the service.
16757 */
16758 static void
16759 svc_add_no_support(scf_service_t *svc)
16760 {
16761 char *pname;
16762
16763 /* Add no support */
16764 cur_svc = svc;
16765 if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
16766 return;
16767
16768 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
16769 if (pname == NULL)
16770 uu_die(gettext("Out of memory.\n"));
16771
16772 (void) lscf_addpropvalue(pname, "boolean:", "0");
16773
16774 uu_free(pname);
16775 cur_svc = NULL;
16776 }
16777
16778 /*
16779 * This function handles all upgrade scenarios for a service that doesn't have
16780 * SCF_PG_MANIFESTFILES pg. The function creates and populates
16781 * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16782 * manifest(s) mapping. Manifests under supported directories are inventoried
16783 * and a property is added for each file that delivers configuration to the
16784 * service. A service that has no corresponding manifest files (deleted) are
16785 * removed from repository.
16786 *
16787 * Unsupported services:
16788 *
16789 * A service is considered unsupported if there is no corresponding manifest
16790 * in the supported directories for that service and the service isn't in the
16791 * history file list. The history file, MFSTHISTFILE, contains a list of all
16792 * services and instances that were delivered by Solaris before the introduction
16793 * of the SCF_PG_MANIFESTFILES property group. The history file also contains
16794 * the path to the manifest file that defined the service or instance.
16795 *
16796 * Another type of unsupported services is 'handcrafted' services,
16797 * programmatically created services or services created by dependent entries
16798 * in other manifests. A handcrafted service is identified by its lack of any
16799 * instance containing last-import snapshot which is created during svccfg
16800 * import.
16801 *
16802 * This function sets a flag for unsupported services by setting services'
16803 * SCF_PG_MANIFESTFILES/support property to false.
16804 */
16805 static void
16806 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
16807 {
16808 service_manifest_t *elem;
16809 uu_list_walk_t *mfwalk;
16810 string_list_t *mfile;
16811 uu_list_t *instances;
16812 const char *sname;
16813 char *pname;
16814 int r;
16815
16816 /*
16817 * Since there's no guarantee manifests under /var are available during
16818 * early import, don't perform any upgrade during early import.
16819 */
16820 if (IGNORE_VAR)
16821 return;
16822
16823 if (service_manifest_tree == NULL) {
16824 create_manifest_tree();
16825 }
16826
16827 /*
16828 * Find service's supporting manifest(s) after
16829 * stripping off the svc:/ prefix that is part
16830 * of the fmri that is not used in the service
16831 * manifest bundle list.
16832 */
16833 sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
16834 strlen(SCF_FMRI_SERVICE_PREFIX);
16835 elem = find_add_svc_mfst(sname, NULL);
16836 if (elem == NULL) {
16837
16838 /*
16839 * A handcrafted service, one that has no instance containing
16840 * last-import snapshot, should get unsupported flag.
16841 */
16842 instances = create_instance_list(svc, 1);
16843 if (instances == NULL) {
16844 uu_warn(gettext("Unable to create instance list %s\n"),
16845 svcname);
16846 return;
16847 }
16848
16849 if (uu_list_numnodes(instances) == 0) {
16850 svc_add_no_support(svc);
16851 return;
16852 }
16853
16854 /*
16855 * If the service is in the history file, and its supporting
16856 * manifests are not found, we can safely delete the service
16857 * because its manifests are removed from the system.
16858 *
16859 * Services not found in the history file are not delivered by
16860 * Solaris and/or delivered outside supported directories, set
16861 * unsupported flag for these services.
16862 */
16863 r = check_mfst_history(svcname);
16864 if (r == -1)
16865 return;
16866
16867 if (r) {
16868 /* Set unsupported flag for service */
16869 svc_add_no_support(svc);
16870 } else {
16871 /* Delete the service */
16872 teardown_service(svc, svcname);
16873 }
16874
16875 return;
16876 }
16877
16878 /*
16879 * Walk through the list of manifests and add them
16880 * to the service.
16881 *
16882 * Create a manifestfiles pg and add the property.
16883 */
16884 mfwalk = uu_list_walk_start(elem->mfstlist, 0);
16885 if (mfwalk == NULL)
16886 return;
16887
16888 cur_svc = svc;
16889 r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
16890 if (r != 0) {
16891 cur_svc = NULL;
16892 return;
16893 }
16894
16895 while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
16896 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16897 mhash_filename_to_propname(mfile->str, 0));
16898 if (pname == NULL)
16899 uu_die(gettext("Out of memory.\n"));
16900
16901 (void) lscf_addpropvalue(pname, "astring:", mfile->str);
16902 uu_free(pname);
16903 }
16904 uu_list_walk_end(mfwalk);
16905
16906 cur_svc = NULL;
16907 }
16908
16909 /*
16910 * Take a service and process the manifest file entires to see if
16911 * there is continued support for the service and instances. If
16912 * not cleanup as appropriate.
16913 *
16914 * If a service does not have a manifest files entry flag it for
16915 * upgrade and return.
16916 *
16917 * For each manifestfiles property check if the manifest file is
16918 * under the supported /lib/svc/manifest or /var/svc/manifest path
16919 * and if not then return immediately as this service is not supported
16920 * by the cleanup mechanism and should be ignored.
16921 *
16922 * For each manifest file that is supported, check to see if the
16923 * file exists. If not then remove the manifest file property
16924 * from the service and the smf/manifest hash table. If the manifest
16925 * file exists then verify that it supports the instances that are
16926 * part of the service.
16927 *
16928 * Once all manifest files have been accounted for remove any instances
16929 * that are no longer supported in the service.
16930 *
16931 * Return values :
16932 * 0 - Successfully processed the service
16933 * non-zero - failed to process the service
16934 *
16935 * On most errors, will just return to wait and get the next service,
16936 * unless in case of unable to create the needed structures which is
16937 * most likely a fatal error that is not going to be recoverable.
16938 */
16939 int
16940 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
16941 {
16942 struct mpg_mfile *mpntov;
16943 struct mpg_mfile **mpvarry = NULL;
16944 scf_service_t *svc;
16945 scf_propertygroup_t *mpg;
16946 scf_property_t *mp;
16947 scf_value_t *mv;
16948 scf_iter_t *mi;
16949 scf_instance_t *instance;
16950 uu_list_walk_t *insts;
16951 uu_list_t *instances = NULL;
16952 boolean_t activity = (boolean_t)act;
16953 char *mpnbuf;
16954 char *mpvbuf;
16955 char *pgpropbuf;
16956 int mfstcnt, rminstct, instct, mfstmax;
16957 int index;
16958 int r = 0;
16959
16960 assert(g_hndl != NULL);
16961 assert(wip->svc != NULL);
16962 assert(wip->fmri != NULL);
16963
16964 svc = wip->svc;
16965
16966 mpg = scf_pg_create(g_hndl);
16967 mp = scf_property_create(g_hndl);
16968 mi = scf_iter_create(g_hndl);
16969 mv = scf_value_create(g_hndl);
16970 instance = scf_instance_create(g_hndl);
16971
16972 if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
16973 instance == NULL) {
16974 uu_warn(gettext("Unable to create the supporting entities\n"));
16975 uu_warn(gettext("scf error is : %s\n"),
16976 scf_strerror(scf_error()));
16977 scfdie();
16978 }
16979
16980 /*
16981 * Get the manifestfiles property group to be parsed for
16982 * files existence.
16983 */
16984 if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
16985 switch (scf_error()) {
16986 case SCF_ERROR_NOT_FOUND:
16987 upgrade_svc_mfst_connection(svc, wip->fmri);
16988 break;
16989 case SCF_ERROR_DELETED:
16990 case SCF_ERROR_CONNECTION_BROKEN:
16991 goto out;
16992
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());
16999 }
17000
17001 goto out;
17002 }
17003
17004 /*
17005 * Iterate through each of the manifestfiles properties
17006 * to determine what manifestfiles are available.
17007 *
17008 * If a manifest file is supported then increment the
17009 * count and therefore the service is safe.
17010 */
17011 if (scf_iter_pg_properties(mi, mpg) != 0) {
17012 switch (scf_error()) {
17013 case SCF_ERROR_DELETED:
17014 case SCF_ERROR_CONNECTION_BROKEN:
17015 goto out;
17016
17017 case SCF_ERROR_HANDLE_MISMATCH:
17018 case SCF_ERROR_NOT_BOUND:
17019 case SCF_ERROR_NOT_SET:
17020 default:
17021 bad_error("scf_iter_pg_properties",
17022 scf_error());
17023 }
17024 }
17025
17026 mfstcnt = 0;
17027 mfstmax = MFSTFILE_MAX;
17028 mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
17029 while ((r = scf_iter_next_property(mi, mp)) != 0) {
17030 if (r == -1)
17031 bad_error(gettext("Unable to iterate through "
17032 "manifestfiles properties : %s"),
17033 scf_error());
17034
17035 mpntov = safe_malloc(sizeof (struct mpg_mfile));
17036 mpnbuf = safe_malloc(max_scf_name_len + 1);
17037 mpvbuf = safe_malloc(max_scf_value_len + 1);
17038 mpntov->mpg = mpnbuf;
17039 mpntov->mfile = mpvbuf;
17040 mpntov->access = 1;
17041 if (scf_property_get_name(mp, mpnbuf,
17042 max_scf_name_len + 1) < 0) {
17043 uu_warn(gettext("Unable to get manifest file "
17044 "property : %s\n"),
17045 scf_strerror(scf_error()));
17046
17047 switch (scf_error()) {
17048 case SCF_ERROR_DELETED:
17049 case SCF_ERROR_CONNECTION_BROKEN:
17050 r = scferror2errno(scf_error());
17051 goto out_free;
17052
17053 case SCF_ERROR_HANDLE_MISMATCH:
17054 case SCF_ERROR_NOT_BOUND:
17055 case SCF_ERROR_NOT_SET:
17056 default:
17057 bad_error("scf_iter_pg_properties",
17058 scf_error());
17059 }
17060 }
17061
17062 /*
17063 * The support property is a boolean value that indicates
17064 * if the service is supported for manifest file deletion.
17065 * Currently at this time there is no code that sets this
17066 * value to true. So while we could just let this be caught
17067 * by the support check below, in the future this by be set
17068 * to true and require processing. So for that, go ahead
17069 * and check here, and just return if false. Otherwise,
17070 * fall through expecting that other support checks will
17071 * handle the entries.
17072 */
17073 if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
17074 uint8_t support;
17075
17076 if (scf_property_get_value(mp, mv) != 0 ||
17077 scf_value_get_boolean(mv, &support) != 0) {
17078 uu_warn(gettext("Unable to get the manifest "
17079 "support value: %s\n"),
17080 scf_strerror(scf_error()));
17081
17082 switch (scf_error()) {
17083 case SCF_ERROR_DELETED:
17084 case SCF_ERROR_CONNECTION_BROKEN:
17085 r = scferror2errno(scf_error());
17086 goto out_free;
17087
17088 case SCF_ERROR_HANDLE_MISMATCH:
17089 case SCF_ERROR_NOT_BOUND:
17090 case SCF_ERROR_NOT_SET:
17091 default:
17092 bad_error("scf_iter_pg_properties",
17093 scf_error());
17094 }
17095 }
17096
17097 if (support == B_FALSE)
17098 goto out_free;
17099 }
17100
17101 /*
17102 * Anything with a manifest outside of the supported
17103 * directories, immediately bail out because that makes
17104 * this service non-supported. We don't even want
17105 * to do instance processing in this case because the
17106 * instances could be part of the non-supported manifest.
17107 */
17108 if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
17109 /*
17110 * Manifest is not in /lib/svc, so we need to
17111 * consider the /var/svc case.
17112 */
17113 if (strncmp(mpnbuf, VARSVC_PR,
17114 strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
17115 /*
17116 * Either the manifest is not in /var/svc or
17117 * /var is not yet mounted. We ignore the
17118 * manifest either because it is not in a
17119 * standard location or because we cannot
17120 * currently access the manifest.
17121 */
17122 goto out_free;
17123 }
17124 }
17125
17126 /*
17127 * Get the value to of the manifest file for this entry
17128 * for access verification and instance support
17129 * verification if it still exists.
17130 *
17131 * During Early Manifest Import if the manifest is in
17132 * /var/svc then it may not yet be available for checking
17133 * so we must determine if /var/svc is available. If not
17134 * then defer until Late Manifest Import to cleanup.
17135 */
17136 if (scf_property_get_value(mp, mv) != 0) {
17137 uu_warn(gettext("Unable to get the manifest file "
17138 "value: %s\n"),
17139 scf_strerror(scf_error()));
17140
17141 switch (scf_error()) {
17142 case SCF_ERROR_DELETED:
17143 case SCF_ERROR_CONNECTION_BROKEN:
17144 r = scferror2errno(scf_error());
17145 goto out_free;
17146
17147 case SCF_ERROR_HANDLE_MISMATCH:
17148 case SCF_ERROR_NOT_BOUND:
17149 case SCF_ERROR_NOT_SET:
17150 default:
17151 bad_error("scf_property_get_value",
17152 scf_error());
17153 }
17154 }
17155
17156 if (scf_value_get_astring(mv, mpvbuf,
17157 max_scf_value_len + 1) < 0) {
17158 uu_warn(gettext("Unable to get the manifest "
17159 "file : %s\n"),
17160 scf_strerror(scf_error()));
17161
17162 switch (scf_error()) {
17163 case SCF_ERROR_DELETED:
17164 case SCF_ERROR_CONNECTION_BROKEN:
17165 r = scferror2errno(scf_error());
17166 goto out_free;
17167
17168 case SCF_ERROR_HANDLE_MISMATCH:
17169 case SCF_ERROR_NOT_BOUND:
17170 case SCF_ERROR_NOT_SET:
17171 default:
17172 bad_error("scf_value_get_astring",
17173 scf_error());
17174 }
17175 }
17176
17177 mpvarry[mfstcnt] = mpntov;
17178 mfstcnt++;
17179
17180 /*
17181 * Check for the need to reallocate array
17182 */
17183 if (mfstcnt >= (mfstmax - 1)) {
17184 struct mpg_mfile **newmpvarry;
17185
17186 mfstmax = mfstmax * 2;
17187 newmpvarry = realloc(mpvarry,
17188 sizeof (struct mpg_mfile *) * mfstmax);
17189
17190 if (newmpvarry == NULL)
17191 goto out_free;
17192
17193 mpvarry = newmpvarry;
17194 }
17195
17196 mpvarry[mfstcnt] = NULL;
17197 }
17198
17199 for (index = 0; mpvarry[index]; index++) {
17200 mpntov = mpvarry[index];
17201
17202 /*
17203 * Check to see if the manifestfile is accessable, if so hand
17204 * this service and manifestfile off to be processed for
17205 * instance support.
17206 */
17207 mpnbuf = mpntov->mpg;
17208 mpvbuf = mpntov->mfile;
17209 if (access(mpvbuf, F_OK) != 0) {
17210 mpntov->access = 0;
17211 activity++;
17212 mfstcnt--;
17213 /* Remove the entry from the service */
17214 cur_svc = svc;
17215 pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
17216 mpnbuf);
17217 if (pgpropbuf == NULL)
17218 uu_die(gettext("Out of memory.\n"));
17219
17220 lscf_delprop(pgpropbuf);
17221 cur_svc = NULL;
17222
17223 uu_free(pgpropbuf);
17224 }
17225 }
17226
17227 /*
17228 * If mfstcnt is 0, none of the manifests that supported the service
17229 * existed so remove the service.
17230 */
17231 if (mfstcnt == 0) {
17232 teardown_service(svc, wip->fmri);
17233
17234 goto out_free;
17235 }
17236
17237 if (activity) {
17238 int nosvcsupport = 0;
17239
17240 /*
17241 * If the list of service instances is NULL then
17242 * create the list.
17243 */
17244 instances = create_instance_list(svc, 1);
17245 if (instances == NULL) {
17246 uu_warn(gettext("Unable to create instance list %s\n"),
17247 wip->fmri);
17248 goto out_free;
17249 }
17250
17251 rminstct = uu_list_numnodes(instances);
17252 instct = rminstct;
17253
17254 for (index = 0; mpvarry[index]; index++) {
17255 mpntov = mpvarry[index];
17256 if (mpntov->access == 0)
17257 continue;
17258
17259 mpnbuf = mpntov->mpg;
17260 mpvbuf = mpntov->mfile;
17261 r = check_instance_support(mpvbuf, wip->fmri,
17262 instances);
17263 if (r == -1) {
17264 nosvcsupport++;
17265 } else {
17266 rminstct -= r;
17267 }
17268 }
17269
17270 if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
17271 teardown_service(svc, wip->fmri);
17272
17273 goto out_free;
17274 }
17275 }
17276
17277 /*
17278 * If there are instances left on the instance list, then
17279 * we must remove them.
17280 */
17281 if (instances != NULL && uu_list_numnodes(instances)) {
17282 string_list_t *sp;
17283
17284 insts = uu_list_walk_start(instances, 0);
17285 while ((sp = uu_list_walk_next(insts)) != NULL) {
17286 /*
17287 * Remove the instance from the instances list.
17288 */
17289 safe_printf(gettext("Delete instance %s from "
17290 "service %s\n"), sp->str, wip->fmri);
17291 if (scf_service_get_instance(svc, sp->str,
17292 instance) != SCF_SUCCESS) {
17293 (void) uu_warn("scf_error - %s\n",
17294 scf_strerror(scf_error()));
17295
17296 continue;
17297 }
17298
17299 (void) disable_instance(instance);
17300
17301 (void) lscf_instance_delete(instance, 1);
17302 }
17303 scf_instance_destroy(instance);
17304 uu_list_walk_end(insts);
17305 }
17306
17307 out_free:
17308 if (mpvarry) {
17309 struct mpg_mfile *fmpntov;
17310
17311 for (index = 0; mpvarry[index]; index++) {
17312 fmpntov = mpvarry[index];
17313 if (fmpntov->mpg == mpnbuf)
17314 mpnbuf = NULL;
17315 free(fmpntov->mpg);
17316
17317 if (fmpntov->mfile == mpvbuf)
17318 mpvbuf = NULL;
17319 free(fmpntov->mfile);
17320
17321 if (fmpntov == mpntov)
17322 mpntov = NULL;
17323 free(fmpntov);
17324 }
17325 if (mpnbuf)
17326 free(mpnbuf);
17327 if (mpvbuf)
17328 free(mpvbuf);
17329 if (mpntov)
17330 free(mpntov);
17331
17332 free(mpvarry);
17333 }
17334 out:
17335 scf_pg_destroy(mpg);
17336 scf_property_destroy(mp);
17337 scf_iter_destroy(mi);
17338 scf_value_destroy(mv);
17339
17340 return (0);
17341 }
17342
17343 /*
17344 * Take the service and search for the manifestfiles property
17345 * in each of the property groups. If the manifest file
17346 * associated with the property does not exist then remove
17347 * the property group.
17348 */
17349 int
17350 lscf_hash_cleanup()
17351 {
17352 scf_service_t *svc;
17353 scf_scope_t *scope;
17354 scf_propertygroup_t *pg;
17355 scf_property_t *prop;
17356 scf_value_t *val;
17357 scf_iter_t *iter;
17358 char *pgname = NULL;
17359 char *mfile = NULL;
17360 int r;
17361
17362 svc = scf_service_create(g_hndl);
17363 scope = scf_scope_create(g_hndl);
17364 pg = scf_pg_create(g_hndl);
17365 prop = scf_property_create(g_hndl);
17366 val = scf_value_create(g_hndl);
17367 iter = scf_iter_create(g_hndl);
17368 if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
17369 svc == NULL || scope == NULL) {
17370 uu_warn(gettext("Unable to create a property group, or "
17371 "property\n"));
17372 uu_warn("%s\n", pg == NULL ? "pg is NULL" :
17373 "pg is not NULL");
17374 uu_warn("%s\n", prop == NULL ? "prop is NULL" :
17375 "prop is not NULL");
17376 uu_warn("%s\n", val == NULL ? "val is NULL" :
17377 "val is not NULL");
17378 uu_warn("%s\n", iter == NULL ? "iter is NULL" :
17379 "iter is not NULL");
17380 uu_warn("%s\n", svc == NULL ? "svc is NULL" :
17381 "svc is not NULL");
17382 uu_warn("%s\n", scope == NULL ? "scope is NULL" :
17383 "scope is not NULL");
17384 uu_warn(gettext("scf error is : %s\n"),
17385 scf_strerror(scf_error()));
17386 scfdie();
17387 }
17388
17389 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
17390 switch (scf_error()) {
17391 case SCF_ERROR_CONNECTION_BROKEN:
17392 case SCF_ERROR_NOT_FOUND:
17393 goto out;
17394
17395 case SCF_ERROR_HANDLE_MISMATCH:
17396 case SCF_ERROR_NOT_BOUND:
17397 case SCF_ERROR_INVALID_ARGUMENT:
17398 default:
17399 bad_error("scf_handle_get_scope", scf_error());
17400 }
17401 }
17402
17403 if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
17404 uu_warn(gettext("Unable to process the hash service, %s\n"),
17405 HASH_SVC);
17406 goto out;
17407 }
17408
17409 pgname = safe_malloc(max_scf_name_len + 1);
17410 mfile = safe_malloc(max_scf_value_len + 1);
17411
17412 if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
17413 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17414 scf_strerror(scf_error()));
17415 goto out;
17416 }
17417
17418 while ((r = scf_iter_next_pg(iter, pg)) != 0) {
17419 if (r == -1)
17420 goto out;
17421
17422 if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
17423 switch (scf_error()) {
17424 case SCF_ERROR_DELETED:
17425 return (ENODEV);
17426
17427 case SCF_ERROR_CONNECTION_BROKEN:
17428 return (ECONNABORTED);
17429
17430 case SCF_ERROR_NOT_SET:
17431 case SCF_ERROR_NOT_BOUND:
17432 default:
17433 bad_error("scf_pg_get_name", scf_error());
17434 }
17435 }
17436 if (IGNORE_VAR) {
17437 if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
17438 continue;
17439 }
17440
17441 /*
17442 * If unable to get the property continue as this is an
17443 * entry that has no location to check against.
17444 */
17445 if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
17446 continue;
17447 }
17448
17449 if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
17450 uu_warn(gettext("Unable to get value from %s\n"),
17451 pgname);
17452
17453 switch (scf_error()) {
17454 case SCF_ERROR_DELETED:
17455 case SCF_ERROR_CONSTRAINT_VIOLATED:
17456 case SCF_ERROR_NOT_FOUND:
17457 case SCF_ERROR_NOT_SET:
17458 continue;
17459
17460 case SCF_ERROR_CONNECTION_BROKEN:
17461 r = scferror2errno(scf_error());
17462 goto out;
17463
17464 case SCF_ERROR_HANDLE_MISMATCH:
17465 case SCF_ERROR_NOT_BOUND:
17466 default:
17467 bad_error("scf_property_get_value",
17468 scf_error());
17469 }
17470 }
17471
17472 if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
17473 == -1) {
17474 uu_warn(gettext("Unable to get astring from %s : %s\n"),
17475 pgname, scf_strerror(scf_error()));
17476
17477 switch (scf_error()) {
17478 case SCF_ERROR_NOT_SET:
17479 case SCF_ERROR_TYPE_MISMATCH:
17480 continue;
17481
17482 default:
17483 bad_error("scf_value_get_astring", scf_error());
17484 }
17485 }
17486
17487 if (access(mfile, F_OK) == 0)
17488 continue;
17489
17490 (void) scf_pg_delete(pg);
17491 }
17492
17493 out:
17494 scf_scope_destroy(scope);
17495 scf_service_destroy(svc);
17496 scf_pg_destroy(pg);
17497 scf_property_destroy(prop);
17498 scf_value_destroy(val);
17499 scf_iter_destroy(iter);
17500 free(pgname);
17501 free(mfile);
17502
17503 return (0);
17504 }
17505
17506 #ifndef NATIVE_BUILD
17507 /* ARGSUSED */
17508 CPL_MATCH_FN(complete_select)
17509 {
17510 const char *arg0, *arg1, *arg1end;
17511 int word_start, err = 0, r;
17512 size_t len;
17513 char *buf;
17514
17515 lscf_prep_hndl();
17516
17517 arg0 = line + strspn(line, " \t");
17518 assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
17519
17520 arg1 = arg0 + sizeof ("select") - 1;
17521 arg1 += strspn(arg1, " \t");
17522 word_start = arg1 - line;
17523
17524 arg1end = arg1 + strcspn(arg1, " \t");
17525 if (arg1end < line + word_end)
17526 return (0);
17527
17528 len = line + word_end - arg1;
17529
17530 buf = safe_malloc(max_scf_name_len + 1);
17531
17532 if (cur_snap != NULL) {
17533 return (0);
17534 } else if (cur_inst != NULL) {
17535 return (0);
17536 } else if (cur_svc != NULL) {
17537 scf_instance_t *inst;
17538 scf_iter_t *iter;
17539
17540 if ((inst = scf_instance_create(g_hndl)) == NULL ||
17541 (iter = scf_iter_create(g_hndl)) == NULL)
17542 scfdie();
17543
17544 if (scf_iter_service_instances(iter, cur_svc) != 0)
17545 scfdie();
17546
17547 for (;;) {
17548 r = scf_iter_next_instance(iter, inst);
17549 if (r == 0)
17550 break;
17551 if (r != 1)
17552 scfdie();
17553
17554 if (scf_instance_get_name(inst, buf,
17555 max_scf_name_len + 1) < 0)
17556 scfdie();
17557
17558 if (strncmp(buf, arg1, len) == 0) {
17559 err = cpl_add_completion(cpl, line, word_start,
17560 word_end, buf + len, "", " ");
17561 if (err != 0)
17562 break;
17563 }
17564 }
17565
17566 scf_iter_destroy(iter);
17567 scf_instance_destroy(inst);
17568
17569 return (err);
17570 } else {
17571 scf_service_t *svc;
17572 scf_iter_t *iter;
17573
17574 assert(cur_scope != NULL);
17575
17576 if ((svc = scf_service_create(g_hndl)) == NULL ||
17577 (iter = scf_iter_create(g_hndl)) == NULL)
17578 scfdie();
17579
17580 if (scf_iter_scope_services(iter, cur_scope) != 0)
17581 scfdie();
17582
17583 for (;;) {
17584 r = scf_iter_next_service(iter, svc);
17585 if (r == 0)
17586 break;
17587 if (r != 1)
17588 scfdie();
17589
17590 if (scf_service_get_name(svc, buf,
17591 max_scf_name_len + 1) < 0)
17592 scfdie();
17593
17594 if (strncmp(buf, arg1, len) == 0) {
17595 err = cpl_add_completion(cpl, line, word_start,
17596 word_end, buf + len, "", " ");
17597 if (err != 0)
17598 break;
17599 }
17600 }
17601
17602 scf_iter_destroy(iter);
17603 scf_service_destroy(svc);
17604
17605 return (err);
17606 }
17607 }
17608
17609 /* ARGSUSED */
17610 CPL_MATCH_FN(complete_command)
17611 {
17612 uint32_t scope = 0;
17613
17614 if (cur_snap != NULL)
17615 scope = CS_SNAP;
17616 else if (cur_inst != NULL)
17617 scope = CS_INST;
17618 else if (cur_svc != NULL)
17619 scope = CS_SVC;
17620 else
17621 scope = CS_SCOPE;
17622
17623 return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
17624 }
17625 #endif /* NATIVE_BUILD */