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 char *s;
10390
10391 n = xmlNewNode(NULL, (xmlChar *)"notification_parameters");
10392 event = xmlNewNode(NULL, (xmlChar *)"event");
10393 if (n == NULL || event == NULL)
10394 uu_die(emsg_create_xml);
10395
10396 /* event value */
10397 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
10398 scfdie();
10399 /* trim SCF_NOTIFY_PG_POSTFIX appended to name on import */
10400 if ((s = strchr(exp_str, ',')) != NULL)
10401 *s = '\0';
10402 safe_setprop(event, value_attr, exp_str);
10403
10404 (void) xmlAddChild(n, event);
10405
10406 if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL ||
10407 (eelts = calloc(URI_SCHEME_NUM,
10408 sizeof (struct params_elts))) == NULL)
10409 uu_die(gettext("Out of memory.\n"));
10410
10411 err = 0;
10412
10413 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10414 scfdie();
10415
10416 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10417 char *t, *p;
10418
10419 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10420 scfdie();
10421
10422 if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) {
10423 /*
10424 * this is not a well formed notification parameters
10425 * element, we should export as regular pg
10426 */
10427 err = 1;
10428 break;
10429 }
10430
10431 if ((i = check_uri_protocol(t)) < 0) {
10432 err = 1;
10433 break;
10434 }
10435
10436 if (type[i] == NULL) {
10437 if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) ==
10438 NULL)
10439 uu_die(emsg_create_xml);
10440
10441 safe_setprop(type[i], name_attr, t);
10442 }
10443 if (strcmp(p, active_attr) == 0) {
10444 if (set_attr_from_prop(exp_prop, type[i],
10445 active_attr) != 0) {
10446 err = 1;
10447 break;
10448 }
10449 continue;
10450 }
10451 /*
10452 * We export the parameter
10453 */
10454 export_parameter(exp_prop, p, &eelts[i]);
10455 }
10456
10457 if (ret == -1)
10458 scfdie();
10459
10460 if (err == 1) {
10461 for (i = 0; i < URI_SCHEME_NUM; ++i)
10462 xmlFree(type[i]);
10463 free(type);
10464
10465 export_pg(pg, elts, SCE_ALL_VALUES);
10466
10467 return;
10468 } else {
10469 for (i = 0; i < URI_SCHEME_NUM; ++i)
10470 if (type[i] != NULL) {
10471 (void) xmlAddChildList(type[i],
10472 eelts[i].paramval);
10473 (void) xmlAddChildList(type[i],
10474 eelts[i].parameter);
10475 (void) xmlAddSibling(event, type[i]);
10476 }
10477 }
10478 free(type);
10479
10480 if (elts->notify_params == NULL)
10481 elts->notify_params = n;
10482 else
10483 (void) xmlAddSibling(elts->notify_params, n);
10484 }
10485
10486 /*
10487 * Process the general property group for an instance.
10488 */
10489 static void
10490 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
10491 struct entity_elts *elts)
10492 {
10493 uint8_t enabled;
10494 struct pg_elts pgelts;
10495 int ret;
10496
10497 /* enabled */
10498 if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
10499 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
10500 prop_get_val(exp_prop, exp_val) == 0) {
10501 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
10502 scfdie();
10503 } else {
10504 enabled = 0;
10505 }
10506
10507 safe_setprop(inode, enabled_attr, enabled ? true : false);
10508
10509 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10510 scfdie();
10511
10512 (void) memset(&pgelts, 0, sizeof (pgelts));
10513
10514 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10515 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10516 scfdie();
10517
10518 if (strcmp(exp_str, scf_property_enabled) == 0) {
10519 continue;
10520 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
10521 xmlNodePtr rnode, sfnode;
10522
10523 rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10524 if (rnode == NULL)
10525 uu_die(emsg_create_xml);
10526
10527 sfnode = xmlNewChild(rnode, NULL,
10528 (xmlChar *)"service_fmri", NULL);
10529 if (sfnode == NULL)
10530 uu_die(emsg_create_xml);
10531
10532 if (set_attr_from_prop(exp_prop, sfnode,
10533 value_attr) == 0) {
10534 elts->restarter = rnode;
10535 continue;
10536 }
10537
10538 xmlFreeNode(rnode);
10539 }
10540
10541 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10542 }
10543 if (ret == -1)
10544 scfdie();
10545
10546 if (pgelts.propvals != NULL || pgelts.properties != NULL)
10547 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10548 elts);
10549 }
10550
10551 /*
10552 * Put an instance element for the given instance into selts.
10553 */
10554 static void
10555 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10556 {
10557 xmlNodePtr n;
10558 boolean_t isdefault;
10559 struct entity_elts elts;
10560 struct template_elts template_elts;
10561 int ret;
10562
10563 n = xmlNewNode(NULL, (xmlChar *)"instance");
10564 if (n == NULL)
10565 uu_die(emsg_create_xml);
10566
10567 /* name */
10568 if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10569 scfdie();
10570 safe_setprop(n, name_attr, exp_str);
10571 isdefault = strcmp(exp_str, "default") == 0;
10572
10573 /* check existance of general pg (since general/enabled is required) */
10574 if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
10575 if (scf_error() != SCF_ERROR_NOT_FOUND)
10576 scfdie();
10577
10578 if (g_verbose) {
10579 if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10580 scfdie();
10581
10582 warn(gettext("Instance %s has no general property "
10583 "group; it will be marked disabled.\n"), exp_str);
10584 }
10585
10586 safe_setprop(n, enabled_attr, false);
10587 } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
10588 strcmp(exp_str, scf_group_framework) != 0) {
10589 if (g_verbose) {
10590 if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10591 scfdie();
10592
10593 warn(gettext("Property group %s is not of type "
10594 "framework; the instance will be marked "
10595 "disabled.\n"), exp_str);
10596 }
10597
10598 safe_setprop(n, enabled_attr, false);
10599 }
10600
10601 /* property groups */
10602 if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
10603 scfdie();
10604
10605 (void) memset(&elts, 0, sizeof (elts));
10606 (void) memset(&template_elts, 0, sizeof (template_elts));
10607
10608 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10609 uint32_t pgflags;
10610
10611 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10612 scfdie();
10613
10614 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10615 continue;
10616
10617 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10618 scfdie();
10619
10620 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10621 export_dependency(exp_pg, &elts);
10622 continue;
10623 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10624 export_method(exp_pg, &elts);
10625 continue;
10626 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10627 if (scf_pg_get_name(exp_pg, exp_str,
10628 max_scf_name_len + 1) < 0)
10629 scfdie();
10630
10631 if (strcmp(exp_str, scf_pg_general) == 0) {
10632 export_inst_general(exp_pg, n, &elts);
10633 continue;
10634 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10635 0) {
10636 export_method_context(exp_pg, &elts);
10637 continue;
10638 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10639 export_dependents(exp_pg, &elts);
10640 continue;
10641 }
10642 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10643 export_template(exp_pg, &elts, &template_elts);
10644 continue;
10645 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10646 export_notify_params(exp_pg, &elts);
10647 continue;
10648 }
10649
10650 /* Ordinary pg. */
10651 export_pg(exp_pg, &elts, flags);
10652 }
10653 if (ret == -1)
10654 scfdie();
10655
10656 if (template_elts.common_name != NULL) {
10657 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10658 (void) xmlAddChild(elts.template, template_elts.common_name);
10659 (void) xmlAddChild(elts.template, template_elts.description);
10660 (void) xmlAddChild(elts.template, template_elts.documentation);
10661 } else {
10662 xmlFreeNode(template_elts.description);
10663 xmlFreeNode(template_elts.documentation);
10664 }
10665
10666 if (isdefault && elts.restarter == NULL &&
10667 elts.dependencies == NULL && elts.method_context == NULL &&
10668 elts.exec_methods == NULL && elts.notify_params == NULL &&
10669 elts.property_groups == NULL && elts.template == NULL) {
10670 xmlChar *eval;
10671
10672 /* This is a default instance */
10673 eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10674
10675 xmlFreeNode(n);
10676
10677 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10678 if (n == NULL)
10679 uu_die(emsg_create_xml);
10680
10681 safe_setprop(n, enabled_attr, (char *)eval);
10682 xmlFree(eval);
10683
10684 selts->create_default_instance = n;
10685 } else {
10686 /* Assemble the children in order. */
10687 (void) xmlAddChild(n, elts.restarter);
10688 (void) xmlAddChildList(n, elts.dependencies);
10689 (void) xmlAddChildList(n, elts.dependents);
10690 (void) xmlAddChild(n, elts.method_context);
10691 (void) xmlAddChildList(n, elts.exec_methods);
10692 (void) xmlAddChildList(n, elts.notify_params);
10693 (void) xmlAddChildList(n, elts.property_groups);
10694 (void) xmlAddChild(n, elts.template);
10695
10696 if (selts->instances == NULL)
10697 selts->instances = n;
10698 else
10699 (void) xmlAddSibling(selts->instances, n);
10700 }
10701 }
10702
10703 /*
10704 * Return a service element for the given service.
10705 */
10706 static xmlNodePtr
10707 export_service(scf_service_t *svc, int flags)
10708 {
10709 xmlNodePtr snode;
10710 struct entity_elts elts;
10711 struct template_elts template_elts;
10712 int ret;
10713
10714 snode = xmlNewNode(NULL, (xmlChar *)"service");
10715 if (snode == NULL)
10716 uu_die(emsg_create_xml);
10717
10718 /* Get & set name attribute */
10719 if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
10720 scfdie();
10721 safe_setprop(snode, name_attr, exp_str);
10722
10723 safe_setprop(snode, type_attr, "service");
10724 safe_setprop(snode, "version", "0");
10725
10726 /* Acquire child elements. */
10727 if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
10728 scfdie();
10729
10730 (void) memset(&elts, 0, sizeof (elts));
10731 (void) memset(&template_elts, 0, sizeof (template_elts));
10732
10733 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10734 uint32_t pgflags;
10735
10736 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10737 scfdie();
10738
10739 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10740 continue;
10741
10742 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10743 scfdie();
10744
10745 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10746 export_dependency(exp_pg, &elts);
10747 continue;
10748 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10749 export_method(exp_pg, &elts);
10750 continue;
10751 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10752 if (scf_pg_get_name(exp_pg, exp_str,
10753 max_scf_name_len + 1) < 0)
10754 scfdie();
10755
10756 if (strcmp(exp_str, scf_pg_general) == 0) {
10757 export_svc_general(exp_pg, &elts);
10758 continue;
10759 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10760 0) {
10761 export_method_context(exp_pg, &elts);
10762 continue;
10763 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10764 export_dependents(exp_pg, &elts);
10765 continue;
10766 } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10767 continue;
10768 }
10769 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10770 export_template(exp_pg, &elts, &template_elts);
10771 continue;
10772 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10773 export_notify_params(exp_pg, &elts);
10774 continue;
10775 }
10776
10777 export_pg(exp_pg, &elts, flags);
10778 }
10779 if (ret == -1)
10780 scfdie();
10781
10782 if (template_elts.common_name != NULL) {
10783 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10784 (void) xmlAddChild(elts.template, template_elts.common_name);
10785 (void) xmlAddChild(elts.template, template_elts.description);
10786 (void) xmlAddChild(elts.template, template_elts.documentation);
10787 } else {
10788 xmlFreeNode(template_elts.description);
10789 xmlFreeNode(template_elts.documentation);
10790 }
10791
10792 /* Iterate instances */
10793 if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
10794 scfdie();
10795
10796 while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10797 export_instance(exp_inst, &elts, flags);
10798 if (ret == -1)
10799 scfdie();
10800
10801 /* Now add all of the accumulated elements in order. */
10802 (void) xmlAddChild(snode, elts.create_default_instance);
10803 (void) xmlAddChild(snode, elts.single_instance);
10804 (void) xmlAddChild(snode, elts.restarter);
10805 (void) xmlAddChildList(snode, elts.dependencies);
10806 (void) xmlAddChildList(snode, elts.dependents);
10807 (void) xmlAddChild(snode, elts.method_context);
10808 (void) xmlAddChildList(snode, elts.exec_methods);
10809 (void) xmlAddChildList(snode, elts.notify_params);
10810 (void) xmlAddChildList(snode, elts.property_groups);
10811 (void) xmlAddChildList(snode, elts.instances);
10812 (void) xmlAddChild(snode, elts.stability);
10813 (void) xmlAddChild(snode, elts.template);
10814
10815 return (snode);
10816 }
10817
10818 static int
10819 export_callback(void *data, scf_walkinfo_t *wip)
10820 {
10821 FILE *f;
10822 xmlDocPtr doc;
10823 xmlNodePtr sb;
10824 int result;
10825 struct export_args *argsp = (struct export_args *)data;
10826
10827 if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
10828 (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10829 (exp_prop = scf_property_create(g_hndl)) == NULL ||
10830 (exp_val = scf_value_create(g_hndl)) == NULL ||
10831 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10832 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10833 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10834 (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10835 scfdie();
10836
10837 exp_str_sz = max_scf_len + 1;
10838 exp_str = safe_malloc(exp_str_sz);
10839
10840 if (argsp->filename != NULL) {
10841 errno = 0;
10842 f = fopen(argsp->filename, "wb");
10843 if (f == NULL) {
10844 if (errno == 0)
10845 uu_die(gettext("Could not open \"%s\": no free "
10846 "stdio streams.\n"), argsp->filename);
10847 else
10848 uu_die(gettext("Could not open \"%s\""),
10849 argsp->filename);
10850 }
10851 } else
10852 f = stdout;
10853
10854 doc = xmlNewDoc((xmlChar *)"1.0");
10855 if (doc == NULL)
10856 uu_die(gettext("Could not create XML document.\n"));
10857
10858 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10859 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10860 uu_die(emsg_create_xml);
10861
10862 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10863 if (sb == NULL)
10864 uu_die(emsg_create_xml);
10865 safe_setprop(sb, type_attr, "manifest");
10866 safe_setprop(sb, name_attr, "export");
10867 (void) xmlAddSibling(doc->children, sb);
10868
10869 (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
10870
10871 result = write_service_bundle(doc, f);
10872
10873 free(exp_str);
10874 scf_iter_destroy(exp_val_iter);
10875 scf_iter_destroy(exp_prop_iter);
10876 scf_iter_destroy(exp_pg_iter);
10877 scf_iter_destroy(exp_inst_iter);
10878 scf_value_destroy(exp_val);
10879 scf_property_destroy(exp_prop);
10880 scf_pg_destroy(exp_pg);
10881 scf_instance_destroy(exp_inst);
10882
10883 xmlFreeDoc(doc);
10884
10885 if (f != stdout)
10886 (void) fclose(f);
10887
10888 return (result);
10889 }
10890
10891 /*
10892 * Get the service named by fmri, build an XML tree which represents it, and
10893 * dump it into filename (or stdout if filename is NULL).
10894 */
10895 int
10896 lscf_service_export(char *fmri, const char *filename, int flags)
10897 {
10898 struct export_args args;
10899 char *fmridup;
10900 const char *scope, *svc, *inst;
10901 size_t cblen = 3 * max_scf_name_len;
10902 char *canonbuf = alloca(cblen);
10903 int ret, err;
10904
10905 lscf_prep_hndl();
10906
10907 bzero(&args, sizeof (args));
10908 args.filename = filename;
10909 args.flags = flags;
10910
10911 /*
10912 * If some poor user has passed an exact instance FMRI, of the sort
10913 * one might cut and paste from svcs(1) or an error message, warn
10914 * and chop off the instance instead of failing.
10915 */
10916 fmridup = alloca(strlen(fmri) + 1);
10917 (void) strcpy(fmridup, fmri);
10918 if (strncmp(fmridup, SCF_FMRI_SVC_PREFIX,
10919 sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 &&
10920 scf_parse_svc_fmri(fmridup, &scope, &svc, &inst, NULL, NULL) == 0 &&
10921 inst != NULL) {
10922 (void) strlcpy(canonbuf, "svc:/", cblen);
10923 if (strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
10924 (void) strlcat(canonbuf, "/", cblen);
10925 (void) strlcat(canonbuf, scope, cblen);
10926 }
10927 (void) strlcat(canonbuf, svc, cblen);
10928 fmri = canonbuf;
10929
10930 warn(gettext("Only services may be exported; ignoring "
10931 "instance portion of argument.\n"));
10932 }
10933
10934 err = 0;
10935 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10936 SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10937 &args, &err, semerr)) != 0) {
10938 if (ret != -1)
10939 semerr(gettext("Failed to walk instances: %s\n"),
10940 scf_strerror(ret));
10941 return (-1);
10942 }
10943
10944 /*
10945 * Error message has already been printed.
10946 */
10947 if (err != 0)
10948 return (-1);
10949
10950 return (0);
10951 }
10952
10953
10954 /*
10955 * Archive
10956 */
10957
10958 static xmlNodePtr
10959 make_archive(int flags)
10960 {
10961 xmlNodePtr sb;
10962 scf_scope_t *scope;
10963 scf_service_t *svc;
10964 scf_iter_t *iter;
10965 int r;
10966
10967 if ((scope = scf_scope_create(g_hndl)) == NULL ||
10968 (svc = scf_service_create(g_hndl)) == NULL ||
10969 (iter = scf_iter_create(g_hndl)) == NULL ||
10970 (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10971 (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10972 (exp_prop = scf_property_create(g_hndl)) == NULL ||
10973 (exp_val = scf_value_create(g_hndl)) == NULL ||
10974 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10975 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10976 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10977 (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10978 scfdie();
10979
10980 exp_str_sz = max_scf_len + 1;
10981 exp_str = safe_malloc(exp_str_sz);
10982
10983 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10984 if (sb == NULL)
10985 uu_die(emsg_create_xml);
10986 safe_setprop(sb, type_attr, "archive");
10987 safe_setprop(sb, name_attr, "none");
10988
10989 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
10990 scfdie();
10991 if (scf_iter_scope_services(iter, scope) != 0)
10992 scfdie();
10993
10994 for (;;) {
10995 r = scf_iter_next_service(iter, svc);
10996 if (r == 0)
10997 break;
10998 if (r != 1)
10999 scfdie();
11000
11001 if (scf_service_get_name(svc, exp_str,
11002 max_scf_name_len + 1) < 0)
11003 scfdie();
11004
11005 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
11006 continue;
11007
11008 (void) xmlAddChild(sb, export_service(svc, flags));
11009 }
11010
11011 free(exp_str);
11012
11013 scf_iter_destroy(exp_val_iter);
11014 scf_iter_destroy(exp_prop_iter);
11015 scf_iter_destroy(exp_pg_iter);
11016 scf_iter_destroy(exp_inst_iter);
11017 scf_value_destroy(exp_val);
11018 scf_property_destroy(exp_prop);
11019 scf_pg_destroy(exp_pg);
11020 scf_instance_destroy(exp_inst);
11021 scf_iter_destroy(iter);
11022 scf_service_destroy(svc);
11023 scf_scope_destroy(scope);
11024
11025 return (sb);
11026 }
11027
11028 int
11029 lscf_archive(const char *filename, int flags)
11030 {
11031 FILE *f;
11032 xmlDocPtr doc;
11033 int result;
11034
11035 lscf_prep_hndl();
11036
11037 if (filename != NULL) {
11038 errno = 0;
11039 f = fopen(filename, "wb");
11040 if (f == NULL) {
11041 if (errno == 0)
11042 uu_die(gettext("Could not open \"%s\": no free "
11043 "stdio streams.\n"), filename);
11044 else
11045 uu_die(gettext("Could not open \"%s\""),
11046 filename);
11047 }
11048 } else
11049 f = stdout;
11050
11051 doc = xmlNewDoc((xmlChar *)"1.0");
11052 if (doc == NULL)
11053 uu_die(gettext("Could not create XML document.\n"));
11054
11055 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11056 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11057 uu_die(emsg_create_xml);
11058
11059 (void) xmlAddSibling(doc->children, make_archive(flags));
11060
11061 result = write_service_bundle(doc, f);
11062
11063 xmlFreeDoc(doc);
11064
11065 if (f != stdout)
11066 (void) fclose(f);
11067
11068 return (result);
11069 }
11070
11071
11072 /*
11073 * "Extract" a profile.
11074 */
11075 int
11076 lscf_profile_extract(const char *filename)
11077 {
11078 FILE *f;
11079 xmlDocPtr doc;
11080 xmlNodePtr sb, snode, inode;
11081 scf_scope_t *scope;
11082 scf_service_t *svc;
11083 scf_instance_t *inst;
11084 scf_propertygroup_t *pg;
11085 scf_property_t *prop;
11086 scf_value_t *val;
11087 scf_iter_t *siter, *iiter;
11088 int r, s;
11089 char *namebuf;
11090 uint8_t b;
11091 int result;
11092
11093 lscf_prep_hndl();
11094
11095 if (filename != NULL) {
11096 errno = 0;
11097 f = fopen(filename, "wb");
11098 if (f == NULL) {
11099 if (errno == 0)
11100 uu_die(gettext("Could not open \"%s\": no "
11101 "free stdio streams.\n"), filename);
11102 else
11103 uu_die(gettext("Could not open \"%s\""),
11104 filename);
11105 }
11106 } else
11107 f = stdout;
11108
11109 doc = xmlNewDoc((xmlChar *)"1.0");
11110 if (doc == NULL)
11111 uu_die(gettext("Could not create XML document.\n"));
11112
11113 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11114 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11115 uu_die(emsg_create_xml);
11116
11117 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
11118 if (sb == NULL)
11119 uu_die(emsg_create_xml);
11120 safe_setprop(sb, type_attr, "profile");
11121 safe_setprop(sb, name_attr, "extract");
11122 (void) xmlAddSibling(doc->children, sb);
11123
11124 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11125 (svc = scf_service_create(g_hndl)) == NULL ||
11126 (inst = scf_instance_create(g_hndl)) == NULL ||
11127 (pg = scf_pg_create(g_hndl)) == NULL ||
11128 (prop = scf_property_create(g_hndl)) == NULL ||
11129 (val = scf_value_create(g_hndl)) == NULL ||
11130 (siter = scf_iter_create(g_hndl)) == NULL ||
11131 (iiter = scf_iter_create(g_hndl)) == NULL)
11132 scfdie();
11133
11134 if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
11135 scfdie();
11136
11137 if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
11138 scfdie();
11139
11140 namebuf = safe_malloc(max_scf_name_len + 1);
11141
11142 while ((r = scf_iter_next_service(siter, svc)) == 1) {
11143 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
11144 scfdie();
11145
11146 snode = xmlNewNode(NULL, (xmlChar *)"service");
11147 if (snode == NULL)
11148 uu_die(emsg_create_xml);
11149
11150 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
11151 0)
11152 scfdie();
11153
11154 safe_setprop(snode, name_attr, namebuf);
11155
11156 safe_setprop(snode, type_attr, "service");
11157 safe_setprop(snode, "version", "0");
11158
11159 while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
11160 if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
11161 SCF_SUCCESS) {
11162 if (scf_error() != SCF_ERROR_NOT_FOUND)
11163 scfdie();
11164
11165 if (g_verbose) {
11166 ssize_t len;
11167 char *fmri;
11168
11169 len =
11170 scf_instance_to_fmri(inst, NULL, 0);
11171 if (len < 0)
11172 scfdie();
11173
11174 fmri = safe_malloc(len + 1);
11175
11176 if (scf_instance_to_fmri(inst, fmri,
11177 len + 1) < 0)
11178 scfdie();
11179
11180 warn("Instance %s has no \"%s\" "
11181 "property group.\n", fmri,
11182 scf_pg_general);
11183
11184 free(fmri);
11185 }
11186
11187 continue;
11188 }
11189
11190 if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
11191 prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
11192 prop_get_val(prop, val) != 0)
11193 continue;
11194
11195 inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
11196 NULL);
11197 if (inode == NULL)
11198 uu_die(emsg_create_xml);
11199
11200 if (scf_instance_get_name(inst, namebuf,
11201 max_scf_name_len + 1) < 0)
11202 scfdie();
11203
11204 safe_setprop(inode, name_attr, namebuf);
11205
11206 if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
11207 scfdie();
11208
11209 safe_setprop(inode, enabled_attr, b ? true : false);
11210 }
11211 if (s < 0)
11212 scfdie();
11213
11214 if (snode->children != NULL)
11215 (void) xmlAddChild(sb, snode);
11216 else
11217 xmlFreeNode(snode);
11218 }
11219 if (r < 0)
11220 scfdie();
11221
11222 free(namebuf);
11223
11224 result = write_service_bundle(doc, f);
11225
11226 xmlFreeDoc(doc);
11227
11228 if (f != stdout)
11229 (void) fclose(f);
11230
11231 return (result);
11232 }
11233
11234
11235 /*
11236 * Entity manipulation commands
11237 */
11238
11239 /*
11240 * Entity selection. If no entity is selected, then the current scope is in
11241 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected,
11242 * only cur_inst is NULL, and when an instance is selected, none are NULL.
11243 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
11244 * cur_inst will be non-NULL.
11245 */
11246
11247 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
11248 static int
11249 select_inst(const char *name)
11250 {
11251 scf_instance_t *inst;
11252 scf_error_t err;
11253
11254 assert(cur_svc != NULL);
11255
11256 inst = scf_instance_create(g_hndl);
11257 if (inst == NULL)
11258 scfdie();
11259
11260 if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
11261 cur_inst = inst;
11262 return (0);
11263 }
11264
11265 err = scf_error();
11266 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11267 scfdie();
11268
11269 scf_instance_destroy(inst);
11270 return (1);
11271 }
11272
11273 /* Returns as above. */
11274 static int
11275 select_svc(const char *name)
11276 {
11277 scf_service_t *svc;
11278 scf_error_t err;
11279
11280 assert(cur_scope != NULL);
11281
11282 svc = scf_service_create(g_hndl);
11283 if (svc == NULL)
11284 scfdie();
11285
11286 if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
11287 cur_svc = svc;
11288 return (0);
11289 }
11290
11291 err = scf_error();
11292 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11293 scfdie();
11294
11295 scf_service_destroy(svc);
11296 return (1);
11297 }
11298
11299 /* ARGSUSED */
11300 static int
11301 select_callback(void *unused, scf_walkinfo_t *wip)
11302 {
11303 scf_instance_t *inst;
11304 scf_service_t *svc;
11305 scf_scope_t *scope;
11306
11307 if (wip->inst != NULL) {
11308 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11309 (svc = scf_service_create(g_hndl)) == NULL ||
11310 (inst = scf_instance_create(g_hndl)) == NULL)
11311 scfdie();
11312
11313 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11314 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11315 scfdie();
11316 } else {
11317 assert(wip->svc != NULL);
11318
11319 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11320 (svc = scf_service_create(g_hndl)) == NULL)
11321 scfdie();
11322
11323 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11324 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11325 scfdie();
11326
11327 inst = NULL;
11328 }
11329
11330 /* Clear out the current selection */
11331 assert(cur_scope != NULL);
11332 scf_scope_destroy(cur_scope);
11333 scf_service_destroy(cur_svc);
11334 scf_instance_destroy(cur_inst);
11335
11336 cur_scope = scope;
11337 cur_svc = svc;
11338 cur_inst = inst;
11339
11340 return (0);
11341 }
11342
11343 static int
11344 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
11345 {
11346 char **fmri = fmri_p;
11347
11348 *fmri = strdup(wip->fmri);
11349 if (*fmri == NULL)
11350 uu_die(gettext("Out of memory.\n"));
11351
11352 return (0);
11353 }
11354
11355 /*
11356 * validate [fmri]
11357 * Perform the validation of an FMRI instance.
11358 */
11359 void
11360 lscf_validate_fmri(const char *fmri)
11361 {
11362 int ret = 0;
11363 size_t inst_sz;
11364 char *inst_fmri = NULL;
11365 scf_tmpl_errors_t *errs = NULL;
11366 char *snapbuf = NULL;
11367
11368 lscf_prep_hndl();
11369
11370 if (fmri == NULL) {
11371 inst_sz = max_scf_fmri_len + 1;
11372 inst_fmri = safe_malloc(inst_sz);
11373
11374 if (cur_snap != NULL) {
11375 snapbuf = safe_malloc(max_scf_name_len + 1);
11376 if (scf_snapshot_get_name(cur_snap, snapbuf,
11377 max_scf_name_len + 1) < 0)
11378 scfdie();
11379 }
11380 if (cur_inst == NULL) {
11381 semerr(gettext("No instance selected\n"));
11382 goto cleanup;
11383 } else if (scf_instance_to_fmri(cur_inst, inst_fmri,
11384 inst_sz) >= inst_sz) {
11385 /* sanity check. Should never get here */
11386 uu_die(gettext("Unexpected error! file %s, line %d\n"),
11387 __FILE__, __LINE__);
11388 }
11389 } else {
11390 scf_error_t scf_err;
11391 int err = 0;
11392
11393 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
11394 validate_callback, &inst_fmri, &err, semerr)) != 0) {
11395 uu_warn("Failed to walk instances: %s\n",
11396 scf_strerror(scf_err));
11397 goto cleanup;
11398 }
11399 if (err != 0) {
11400 /* error message displayed by scf_walk_fmri */
11401 goto cleanup;
11402 }
11403 }
11404
11405 ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
11406 SCF_TMPL_VALIDATE_FLAG_CURRENT);
11407 if (ret == -1) {
11408 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
11409 warn(gettext("Template data for %s is invalid. "
11410 "Consider reverting to a previous snapshot or "
11411 "restoring original configuration.\n"), inst_fmri);
11412 } else {
11413 uu_warn("%s: %s\n",
11414 gettext("Error validating the instance"),
11415 scf_strerror(scf_error()));
11416 }
11417 } else if (ret == 1 && errs != NULL) {
11418 scf_tmpl_error_t *err = NULL;
11419 char *msg;
11420 size_t len = 256; /* initial error buffer size */
11421 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
11422 SCF_TMPL_STRERROR_HUMAN : 0;
11423
11424 msg = safe_malloc(len);
11425
11426 while ((err = scf_tmpl_next_error(errs)) != NULL) {
11427 int ret;
11428
11429 if ((ret = scf_tmpl_strerror(err, msg, len,
11430 flag)) >= len) {
11431 len = ret + 1;
11432 msg = realloc(msg, len);
11433 if (msg == NULL)
11434 uu_die(gettext(
11435 "Out of memory.\n"));
11436 (void) scf_tmpl_strerror(err, msg, len,
11437 flag);
11438 }
11439 (void) fprintf(stderr, "%s\n", msg);
11440 }
11441 if (msg != NULL)
11442 free(msg);
11443 }
11444 if (errs != NULL)
11445 scf_tmpl_errors_destroy(errs);
11446
11447 cleanup:
11448 free(inst_fmri);
11449 free(snapbuf);
11450 }
11451
11452 static void
11453 lscf_validate_file(const char *filename)
11454 {
11455 tmpl_errors_t *errs;
11456
11457 bundle_t *b = internal_bundle_new();
11458 if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
11459 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
11460 tmpl_errors_print(stderr, errs, "");
11461 semerr(gettext("Validation failed.\n"));
11462 }
11463 tmpl_errors_destroy(errs);
11464 }
11465 (void) internal_bundle_free(b);
11466 }
11467
11468 /*
11469 * validate [fmri|file]
11470 */
11471 void
11472 lscf_validate(const char *arg)
11473 {
11474 const char *str;
11475
11476 if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
11477 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
11478 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
11479 lscf_validate_file(str);
11480 } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
11481 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
11482 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
11483 lscf_validate_fmri(str);
11484 } else if (access(arg, R_OK | F_OK) == 0) {
11485 lscf_validate_file(arg);
11486 } else {
11487 lscf_validate_fmri(arg);
11488 }
11489 }
11490
11491 void
11492 lscf_select(const char *fmri)
11493 {
11494 int ret, err;
11495
11496 lscf_prep_hndl();
11497
11498 if (cur_snap != NULL) {
11499 struct snaplevel *elt;
11500 char *buf;
11501
11502 /* Error unless name is that of the next level. */
11503 elt = uu_list_next(cur_levels, cur_elt);
11504 if (elt == NULL) {
11505 semerr(gettext("No children.\n"));
11506 return;
11507 }
11508
11509 buf = safe_malloc(max_scf_name_len + 1);
11510
11511 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11512 max_scf_name_len + 1) < 0)
11513 scfdie();
11514
11515 if (strcmp(buf, fmri) != 0) {
11516 semerr(gettext("No such child.\n"));
11517 free(buf);
11518 return;
11519 }
11520
11521 free(buf);
11522
11523 cur_elt = elt;
11524 cur_level = elt->sl;
11525 return;
11526 }
11527
11528 /*
11529 * Special case for 'svc:', which takes the user to the scope level.
11530 */
11531 if (strcmp(fmri, "svc:") == 0) {
11532 scf_instance_destroy(cur_inst);
11533 scf_service_destroy(cur_svc);
11534 cur_inst = NULL;
11535 cur_svc = NULL;
11536 return;
11537 }
11538
11539 /*
11540 * Special case for ':properties'. This appears as part of 'list' but
11541 * can't be selected. Give a more helpful error message in this case.
11542 */
11543 if (strcmp(fmri, ":properties") == 0) {
11544 semerr(gettext(":properties is not an entity. Try 'listprop' "
11545 "to list properties.\n"));
11546 return;
11547 }
11548
11549 /*
11550 * First try the argument as relative to the current selection.
11551 */
11552 if (cur_inst != NULL) {
11553 /* EMPTY */;
11554 } else if (cur_svc != NULL) {
11555 if (select_inst(fmri) != 1)
11556 return;
11557 } else {
11558 if (select_svc(fmri) != 1)
11559 return;
11560 }
11561
11562 err = 0;
11563 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11564 select_callback, NULL, &err, semerr)) != 0) {
11565 semerr(gettext("Failed to walk instances: %s\n"),
11566 scf_strerror(ret));
11567 }
11568 }
11569
11570 void
11571 lscf_unselect(void)
11572 {
11573 lscf_prep_hndl();
11574
11575 if (cur_snap != NULL) {
11576 struct snaplevel *elt;
11577
11578 elt = uu_list_prev(cur_levels, cur_elt);
11579 if (elt == NULL) {
11580 semerr(gettext("No parent levels.\n"));
11581 } else {
11582 cur_elt = elt;
11583 cur_level = elt->sl;
11584 }
11585 } else if (cur_inst != NULL) {
11586 scf_instance_destroy(cur_inst);
11587 cur_inst = NULL;
11588 } else if (cur_svc != NULL) {
11589 scf_service_destroy(cur_svc);
11590 cur_svc = NULL;
11591 } else {
11592 semerr(gettext("Cannot unselect at scope level.\n"));
11593 }
11594 }
11595
11596 /*
11597 * Return the FMRI of the current selection, for the prompt.
11598 */
11599 void
11600 lscf_get_selection_str(char *buf, size_t bufsz)
11601 {
11602 char *cp;
11603 ssize_t fmrilen, szret;
11604 boolean_t deleted = B_FALSE;
11605
11606 if (g_hndl == NULL) {
11607 (void) strlcpy(buf, "svc:", bufsz);
11608 return;
11609 }
11610
11611 if (cur_level != NULL) {
11612 assert(cur_snap != NULL);
11613
11614 /* [ snapshot ] FMRI [: instance ] */
11615 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11616 + 2 + max_scf_name_len + 1 + 1);
11617
11618 buf[0] = '[';
11619
11620 szret = scf_snapshot_get_name(cur_snap, buf + 1,
11621 max_scf_name_len + 1);
11622 if (szret < 0) {
11623 if (scf_error() != SCF_ERROR_DELETED)
11624 scfdie();
11625
11626 goto snap_deleted;
11627 }
11628
11629 (void) strcat(buf, "]svc:/");
11630
11631 cp = strchr(buf, '\0');
11632
11633 szret = scf_snaplevel_get_service_name(cur_level, cp,
11634 max_scf_name_len + 1);
11635 if (szret < 0) {
11636 if (scf_error() != SCF_ERROR_DELETED)
11637 scfdie();
11638
11639 goto snap_deleted;
11640 }
11641
11642 cp = strchr(cp, '\0');
11643
11644 if (snaplevel_is_instance(cur_level)) {
11645 *cp++ = ':';
11646
11647 if (scf_snaplevel_get_instance_name(cur_level, cp,
11648 max_scf_name_len + 1) < 0) {
11649 if (scf_error() != SCF_ERROR_DELETED)
11650 scfdie();
11651
11652 goto snap_deleted;
11653 }
11654 } else {
11655 *cp++ = '[';
11656 *cp++ = ':';
11657
11658 if (scf_instance_get_name(cur_inst, cp,
11659 max_scf_name_len + 1) < 0) {
11660 if (scf_error() != SCF_ERROR_DELETED)
11661 scfdie();
11662
11663 goto snap_deleted;
11664 }
11665
11666 (void) strcat(buf, "]");
11667 }
11668
11669 return;
11670
11671 snap_deleted:
11672 deleted = B_TRUE;
11673 free(buf);
11674 unselect_cursnap();
11675 }
11676
11677 assert(cur_snap == NULL);
11678
11679 if (cur_inst != NULL) {
11680 assert(cur_svc != NULL);
11681 assert(cur_scope != NULL);
11682
11683 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11684 if (fmrilen >= 0) {
11685 assert(fmrilen < bufsz);
11686 if (deleted)
11687 warn(emsg_deleted);
11688 return;
11689 }
11690
11691 if (scf_error() != SCF_ERROR_DELETED)
11692 scfdie();
11693
11694 deleted = B_TRUE;
11695
11696 scf_instance_destroy(cur_inst);
11697 cur_inst = NULL;
11698 }
11699
11700 if (cur_svc != NULL) {
11701 assert(cur_scope != NULL);
11702
11703 szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11704 if (szret >= 0) {
11705 assert(szret < bufsz);
11706 if (deleted)
11707 warn(emsg_deleted);
11708 return;
11709 }
11710
11711 if (scf_error() != SCF_ERROR_DELETED)
11712 scfdie();
11713
11714 deleted = B_TRUE;
11715 scf_service_destroy(cur_svc);
11716 cur_svc = NULL;
11717 }
11718
11719 assert(cur_scope != NULL);
11720 fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11721
11722 if (fmrilen < 0)
11723 scfdie();
11724
11725 assert(fmrilen < bufsz);
11726 if (deleted)
11727 warn(emsg_deleted);
11728 }
11729
11730 /*
11731 * Entity listing. Entities and colon namespaces (e.g., :properties and
11732 * :statistics) are listed for the current selection.
11733 */
11734 void
11735 lscf_list(const char *pattern)
11736 {
11737 scf_iter_t *iter;
11738 char *buf;
11739 int ret;
11740
11741 lscf_prep_hndl();
11742
11743 if (cur_level != NULL) {
11744 struct snaplevel *elt;
11745
11746 (void) fputs(COLON_NAMESPACES, stdout);
11747
11748 elt = uu_list_next(cur_levels, cur_elt);
11749 if (elt == NULL)
11750 return;
11751
11752 /*
11753 * For now, we know that the next level is an instance. But
11754 * if we ever have multiple scopes, this could be complicated.
11755 */
11756 buf = safe_malloc(max_scf_name_len + 1);
11757 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11758 max_scf_name_len + 1) >= 0) {
11759 (void) puts(buf);
11760 } else {
11761 if (scf_error() != SCF_ERROR_DELETED)
11762 scfdie();
11763 }
11764
11765 free(buf);
11766
11767 return;
11768 }
11769
11770 if (cur_inst != NULL) {
11771 (void) fputs(COLON_NAMESPACES, stdout);
11772 return;
11773 }
11774
11775 iter = scf_iter_create(g_hndl);
11776 if (iter == NULL)
11777 scfdie();
11778
11779 buf = safe_malloc(max_scf_name_len + 1);
11780
11781 if (cur_svc != NULL) {
11782 /* List the instances in this service. */
11783 scf_instance_t *inst;
11784
11785 inst = scf_instance_create(g_hndl);
11786 if (inst == NULL)
11787 scfdie();
11788
11789 if (scf_iter_service_instances(iter, cur_svc) == 0) {
11790 safe_printf(COLON_NAMESPACES);
11791
11792 for (;;) {
11793 ret = scf_iter_next_instance(iter, inst);
11794 if (ret == 0)
11795 break;
11796 if (ret != 1) {
11797 if (scf_error() != SCF_ERROR_DELETED)
11798 scfdie();
11799
11800 break;
11801 }
11802
11803 if (scf_instance_get_name(inst, buf,
11804 max_scf_name_len + 1) >= 0) {
11805 if (pattern == NULL ||
11806 fnmatch(pattern, buf, 0) == 0)
11807 (void) puts(buf);
11808 } else {
11809 if (scf_error() != SCF_ERROR_DELETED)
11810 scfdie();
11811 }
11812 }
11813 } else {
11814 if (scf_error() != SCF_ERROR_DELETED)
11815 scfdie();
11816 }
11817
11818 scf_instance_destroy(inst);
11819 } else {
11820 /* List the services in this scope. */
11821 scf_service_t *svc;
11822
11823 assert(cur_scope != NULL);
11824
11825 svc = scf_service_create(g_hndl);
11826 if (svc == NULL)
11827 scfdie();
11828
11829 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11830 scfdie();
11831
11832 for (;;) {
11833 ret = scf_iter_next_service(iter, svc);
11834 if (ret == 0)
11835 break;
11836 if (ret != 1)
11837 scfdie();
11838
11839 if (scf_service_get_name(svc, buf,
11840 max_scf_name_len + 1) >= 0) {
11841 if (pattern == NULL ||
11842 fnmatch(pattern, buf, 0) == 0)
11843 safe_printf("%s\n", buf);
11844 } else {
11845 if (scf_error() != SCF_ERROR_DELETED)
11846 scfdie();
11847 }
11848 }
11849
11850 scf_service_destroy(svc);
11851 }
11852
11853 free(buf);
11854 scf_iter_destroy(iter);
11855 }
11856
11857 /*
11858 * Entity addition. Creates an empty entity in the current selection.
11859 */
11860 void
11861 lscf_add(const char *name)
11862 {
11863 lscf_prep_hndl();
11864
11865 if (cur_snap != NULL) {
11866 semerr(emsg_cant_modify_snapshots);
11867 } else if (cur_inst != NULL) {
11868 semerr(gettext("Cannot add entities to an instance.\n"));
11869 } else if (cur_svc != NULL) {
11870
11871 if (scf_service_add_instance(cur_svc, name, NULL) !=
11872 SCF_SUCCESS) {
11873 switch (scf_error()) {
11874 case SCF_ERROR_INVALID_ARGUMENT:
11875 semerr(gettext("Invalid name.\n"));
11876 break;
11877
11878 case SCF_ERROR_EXISTS:
11879 semerr(gettext("Instance already exists.\n"));
11880 break;
11881
11882 case SCF_ERROR_PERMISSION_DENIED:
11883 semerr(emsg_permission_denied);
11884 break;
11885
11886 default:
11887 scfdie();
11888 }
11889 }
11890 } else {
11891 assert(cur_scope != NULL);
11892
11893 if (scf_scope_add_service(cur_scope, name, NULL) !=
11894 SCF_SUCCESS) {
11895 switch (scf_error()) {
11896 case SCF_ERROR_INVALID_ARGUMENT:
11897 semerr(gettext("Invalid name.\n"));
11898 break;
11899
11900 case SCF_ERROR_EXISTS:
11901 semerr(gettext("Service already exists.\n"));
11902 break;
11903
11904 case SCF_ERROR_PERMISSION_DENIED:
11905 semerr(emsg_permission_denied);
11906 break;
11907
11908 case SCF_ERROR_BACKEND_READONLY:
11909 semerr(emsg_read_only);
11910 break;
11911
11912 default:
11913 scfdie();
11914 }
11915 }
11916 }
11917 }
11918
11919 /* return 1 if the entity has no persistent pgs, else return 0 */
11920 static int
11921 entity_has_no_pgs(void *ent, int isservice)
11922 {
11923 scf_iter_t *iter = NULL;
11924 scf_propertygroup_t *pg = NULL;
11925 uint32_t flags;
11926 int err;
11927 int ret = 1;
11928
11929 if ((iter = scf_iter_create(g_hndl)) == NULL ||
11930 (pg = scf_pg_create(g_hndl)) == NULL)
11931 scfdie();
11932
11933 if (isservice) {
11934 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11935 scfdie();
11936 } else {
11937 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11938 scfdie();
11939 }
11940
11941 while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11942 if (scf_pg_get_flags(pg, &flags) != 0)
11943 scfdie();
11944
11945 /* skip nonpersistent pgs */
11946 if (flags & SCF_PG_FLAG_NONPERSISTENT)
11947 continue;
11948
11949 ret = 0;
11950 break;
11951 }
11952
11953 if (err == -1)
11954 scfdie();
11955
11956 scf_pg_destroy(pg);
11957 scf_iter_destroy(iter);
11958
11959 return (ret);
11960 }
11961
11962 /* return 1 if the service has no instances, else return 0 */
11963 static int
11964 svc_has_no_insts(scf_service_t *svc)
11965 {
11966 scf_instance_t *inst;
11967 scf_iter_t *iter;
11968 int r;
11969 int ret = 1;
11970
11971 if ((inst = scf_instance_create(g_hndl)) == NULL ||
11972 (iter = scf_iter_create(g_hndl)) == NULL)
11973 scfdie();
11974
11975 if (scf_iter_service_instances(iter, svc) != 0)
11976 scfdie();
11977
11978 r = scf_iter_next_instance(iter, inst);
11979 if (r == 1) {
11980 ret = 0;
11981 } else if (r == 0) {
11982 ret = 1;
11983 } else if (r == -1) {
11984 scfdie();
11985 } else {
11986 bad_error("scf_iter_next_instance", r);
11987 }
11988
11989 scf_iter_destroy(iter);
11990 scf_instance_destroy(inst);
11991
11992 return (ret);
11993 }
11994
11995 /*
11996 * Entity deletion.
11997 */
11998
11999 /*
12000 * Delete the property group <fmri>/:properties/<name>. Returns
12001 * SCF_ERROR_NONE on success (or if the entity is not found),
12002 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
12003 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
12004 * denied.
12005 */
12006 static scf_error_t
12007 delete_dependency_pg(const char *fmri, const char *name)
12008 {
12009 void *entity = NULL;
12010 int isservice;
12011 scf_propertygroup_t *pg = NULL;
12012 scf_error_t result;
12013 char *pgty;
12014 scf_service_t *svc = NULL;
12015 scf_instance_t *inst = NULL;
12016 scf_iter_t *iter = NULL;
12017 char *name_buf = NULL;
12018
12019 result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
12020 switch (result) {
12021 case SCF_ERROR_NONE:
12022 break;
12023
12024 case SCF_ERROR_NO_MEMORY:
12025 uu_die(gettext("Out of memory.\n"));
12026 /* NOTREACHED */
12027
12028 case SCF_ERROR_INVALID_ARGUMENT:
12029 case SCF_ERROR_CONSTRAINT_VIOLATED:
12030 return (SCF_ERROR_INVALID_ARGUMENT);
12031
12032 case SCF_ERROR_NOT_FOUND:
12033 result = SCF_ERROR_NONE;
12034 goto out;
12035
12036 default:
12037 bad_error("fmri_to_entity", result);
12038 }
12039
12040 pg = scf_pg_create(g_hndl);
12041 if (pg == NULL)
12042 scfdie();
12043
12044 if (entity_get_pg(entity, isservice, name, pg) != 0) {
12045 if (scf_error() != SCF_ERROR_NOT_FOUND)
12046 scfdie();
12047
12048 result = SCF_ERROR_NONE;
12049 goto out;
12050 }
12051
12052 pgty = safe_malloc(max_scf_pg_type_len + 1);
12053
12054 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12055 scfdie();
12056
12057 if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
12058 result = SCF_ERROR_TYPE_MISMATCH;
12059 free(pgty);
12060 goto out;
12061 }
12062
12063 free(pgty);
12064
12065 if (scf_pg_delete(pg) != 0) {
12066 result = scf_error();
12067 if (result != SCF_ERROR_PERMISSION_DENIED)
12068 scfdie();
12069 goto out;
12070 }
12071
12072 /*
12073 * We have to handle the case where we've just deleted the last
12074 * property group of a "dummy" entity (instance or service).
12075 * A "dummy" entity is an entity only present to hold an
12076 * external dependency.
12077 * So, in the case we deleted the last property group then we
12078 * can also delete the entity. If the entity is an instance then
12079 * we must verify if this was the last instance for the service
12080 * and if it is, we can also delete the service if it doesn't
12081 * have any property group either.
12082 */
12083
12084 result = SCF_ERROR_NONE;
12085
12086 if (isservice) {
12087 svc = (scf_service_t *)entity;
12088
12089 if ((inst = scf_instance_create(g_hndl)) == NULL ||
12090 (iter = scf_iter_create(g_hndl)) == NULL)
12091 scfdie();
12092
12093 name_buf = safe_malloc(max_scf_name_len + 1);
12094 } else {
12095 inst = (scf_instance_t *)entity;
12096 }
12097
12098 /*
12099 * If the entity is an instance and we've just deleted its last
12100 * property group then we should delete it.
12101 */
12102 if (!isservice && entity_has_no_pgs(entity, isservice)) {
12103 /* find the service before deleting the inst. - needed later */
12104 if ((svc = scf_service_create(g_hndl)) == NULL)
12105 scfdie();
12106
12107 if (scf_instance_get_parent(inst, svc) != 0)
12108 scfdie();
12109
12110 /* delete the instance */
12111 if (scf_instance_delete(inst) != 0) {
12112 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12113 scfdie();
12114
12115 result = SCF_ERROR_PERMISSION_DENIED;
12116 goto out;
12117 }
12118 /* no need to refresh the instance */
12119 inst = NULL;
12120 }
12121
12122 /*
12123 * If the service has no more instances and pgs or we just deleted the
12124 * last instance and the service doesn't have anymore propery groups
12125 * then the service should be deleted.
12126 */
12127 if (svc != NULL &&
12128 svc_has_no_insts(svc) &&
12129 entity_has_no_pgs((void *)svc, 1)) {
12130 if (scf_service_delete(svc) == 0) {
12131 if (isservice) {
12132 /* no need to refresh the service */
12133 svc = NULL;
12134 }
12135
12136 goto out;
12137 }
12138
12139 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12140 scfdie();
12141
12142 result = SCF_ERROR_PERMISSION_DENIED;
12143 }
12144
12145 /* if the entity has not been deleted, refresh it */
12146 if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
12147 (void) refresh_entity(isservice, entity, fmri, inst, iter,
12148 name_buf);
12149 }
12150
12151 out:
12152 if (isservice && (inst != NULL && iter != NULL)) {
12153 free(name_buf);
12154 scf_iter_destroy(iter);
12155 scf_instance_destroy(inst);
12156 }
12157
12158 if (!isservice && svc != NULL) {
12159 scf_service_destroy(svc);
12160 }
12161
12162 scf_pg_destroy(pg);
12163 if (entity != NULL)
12164 entity_destroy(entity, isservice);
12165
12166 return (result);
12167 }
12168
12169 static int
12170 delete_dependents(scf_propertygroup_t *pg)
12171 {
12172 char *pgty, *name, *fmri;
12173 scf_property_t *prop;
12174 scf_value_t *val;
12175 scf_iter_t *iter;
12176 int r;
12177 scf_error_t err;
12178
12179 /* Verify that the pg has the correct type. */
12180 pgty = safe_malloc(max_scf_pg_type_len + 1);
12181 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12182 scfdie();
12183
12184 if (strcmp(pgty, scf_group_framework) != 0) {
12185 if (g_verbose) {
12186 fmri = safe_malloc(max_scf_fmri_len + 1);
12187 if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
12188 scfdie();
12189
12190 warn(gettext("Property group %s is not of expected "
12191 "type %s.\n"), fmri, scf_group_framework);
12192
12193 free(fmri);
12194 }
12195
12196 free(pgty);
12197 return (-1);
12198 }
12199
12200 free(pgty);
12201
12202 /* map delete_dependency_pg onto the properties. */
12203 if ((prop = scf_property_create(g_hndl)) == NULL ||
12204 (val = scf_value_create(g_hndl)) == NULL ||
12205 (iter = scf_iter_create(g_hndl)) == NULL)
12206 scfdie();
12207
12208 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
12209 scfdie();
12210
12211 name = safe_malloc(max_scf_name_len + 1);
12212 fmri = safe_malloc(max_scf_fmri_len + 2);
12213
12214 while ((r = scf_iter_next_property(iter, prop)) == 1) {
12215 scf_type_t ty;
12216
12217 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
12218 scfdie();
12219
12220 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
12221 scfdie();
12222
12223 if ((ty != SCF_TYPE_ASTRING &&
12224 prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
12225 prop_get_val(prop, val) != 0)
12226 continue;
12227
12228 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
12229 scfdie();
12230
12231 err = delete_dependency_pg(fmri, name);
12232 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
12233 if (scf_property_to_fmri(prop, fmri,
12234 max_scf_fmri_len + 2) < 0)
12235 scfdie();
12236
12237 warn(gettext("Value of %s is not a valid FMRI.\n"),
12238 fmri);
12239 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
12240 warn(gettext("Property group \"%s\" of entity \"%s\" "
12241 "does not have dependency type.\n"), name, fmri);
12242 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
12243 warn(gettext("Could not delete property group \"%s\" "
12244 "of entity \"%s\" (permission denied).\n"), name,
12245 fmri);
12246 }
12247 }
12248 if (r == -1)
12249 scfdie();
12250
12251 scf_value_destroy(val);
12252 scf_property_destroy(prop);
12253
12254 return (0);
12255 }
12256
12257 /*
12258 * Returns 1 if the instance may be running, and 0 otherwise.
12259 */
12260 static int
12261 inst_is_running(scf_instance_t *inst)
12262 {
12263 scf_propertygroup_t *pg;
12264 scf_property_t *prop;
12265 scf_value_t *val;
12266 char buf[MAX_SCF_STATE_STRING_SZ];
12267 int ret = 0;
12268 ssize_t szret;
12269
12270 if ((pg = scf_pg_create(g_hndl)) == NULL ||
12271 (prop = scf_property_create(g_hndl)) == NULL ||
12272 (val = scf_value_create(g_hndl)) == NULL)
12273 scfdie();
12274
12275 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
12276 if (scf_error() != SCF_ERROR_NOT_FOUND)
12277 scfdie();
12278 goto out;
12279 }
12280
12281 if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
12282 prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
12283 prop_get_val(prop, val) != 0)
12284 goto out;
12285
12286 szret = scf_value_get_astring(val, buf, sizeof (buf));
12287 assert(szret >= 0);
12288
12289 ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
12290 strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
12291
12292 out:
12293 scf_value_destroy(val);
12294 scf_property_destroy(prop);
12295 scf_pg_destroy(pg);
12296 return (ret);
12297 }
12298
12299 static uint8_t
12300 pg_is_external_dependency(scf_propertygroup_t *pg)
12301 {
12302 char *type;
12303 scf_value_t *val;
12304 scf_property_t *prop;
12305 uint8_t b = B_FALSE;
12306
12307 type = safe_malloc(max_scf_pg_type_len + 1);
12308
12309 if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
12310 scfdie();
12311
12312 if ((prop = scf_property_create(g_hndl)) == NULL ||
12313 (val = scf_value_create(g_hndl)) == NULL)
12314 scfdie();
12315
12316 if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
12317 if (pg_get_prop(pg, scf_property_external, prop) == 0) {
12318 if (scf_property_get_value(prop, val) != 0)
12319 scfdie();
12320 if (scf_value_get_boolean(val, &b) != 0)
12321 scfdie();
12322 }
12323 }
12324
12325 free(type);
12326 (void) scf_value_destroy(val);
12327 (void) scf_property_destroy(prop);
12328
12329 return (b);
12330 }
12331
12332 #define DELETE_FAILURE -1
12333 #define DELETE_SUCCESS_NOEXTDEPS 0
12334 #define DELETE_SUCCESS_EXTDEPS 1
12335
12336 /*
12337 * lscf_instance_delete() deletes an instance. Before calling
12338 * scf_instance_delete(), though, we make sure the instance isn't
12339 * running and delete dependencies in other entities which the instance
12340 * declared as "dependents". If there are dependencies which were
12341 * created for other entities, then instead of deleting the instance we
12342 * make it "empty" by deleting all other property groups and all
12343 * snapshots.
12344 *
12345 * lscf_instance_delete() verifies that there is no external dependency pgs
12346 * before suppressing the instance. If there is, then we must not remove them
12347 * now in case the instance is re-created otherwise the dependencies would be
12348 * lost. The external dependency pgs will be removed if the dependencies are
12349 * removed.
12350 *
12351 * Returns:
12352 * DELETE_FAILURE on failure
12353 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12354 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12355 */
12356 static int
12357 lscf_instance_delete(scf_instance_t *inst, int force)
12358 {
12359 scf_propertygroup_t *pg;
12360 scf_snapshot_t *snap;
12361 scf_iter_t *iter;
12362 int err;
12363 int external = 0;
12364
12365 /* If we're not forcing and the instance is running, refuse. */
12366 if (!force && inst_is_running(inst)) {
12367 char *fmri;
12368
12369 fmri = safe_malloc(max_scf_fmri_len + 1);
12370
12371 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
12372 scfdie();
12373
12374 semerr(gettext("Instance %s may be running. "
12375 "Use delete -f if it is not.\n"), fmri);
12376
12377 free(fmri);
12378 return (DELETE_FAILURE);
12379 }
12380
12381 pg = scf_pg_create(g_hndl);
12382 if (pg == NULL)
12383 scfdie();
12384
12385 if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
12386 (void) delete_dependents(pg);
12387 else if (scf_error() != SCF_ERROR_NOT_FOUND)
12388 scfdie();
12389
12390 scf_pg_destroy(pg);
12391
12392 /*
12393 * If the instance has some external dependencies then we must
12394 * keep them in case the instance is reimported otherwise the
12395 * dependencies would be lost on reimport.
12396 */
12397 if ((iter = scf_iter_create(g_hndl)) == NULL ||
12398 (pg = scf_pg_create(g_hndl)) == NULL)
12399 scfdie();
12400
12401 if (scf_iter_instance_pgs(iter, inst) < 0)
12402 scfdie();
12403
12404 while ((err = scf_iter_next_pg(iter, pg)) == 1) {
12405 if (pg_is_external_dependency(pg)) {
12406 external = 1;
12407 continue;
12408 }
12409
12410 if (scf_pg_delete(pg) != 0) {
12411 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12412 scfdie();
12413 else {
12414 semerr(emsg_permission_denied);
12415
12416 (void) scf_iter_destroy(iter);
12417 (void) scf_pg_destroy(pg);
12418 return (DELETE_FAILURE);
12419 }
12420 }
12421 }
12422
12423 if (err == -1)
12424 scfdie();
12425
12426 (void) scf_iter_destroy(iter);
12427 (void) scf_pg_destroy(pg);
12428
12429 if (external) {
12430 /*
12431 * All the pgs have been deleted for the instance except
12432 * the ones holding the external dependencies.
12433 * For the job to be complete, we must also delete the
12434 * snapshots associated with the instance.
12435 */
12436 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
12437 NULL)
12438 scfdie();
12439 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
12440 scfdie();
12441
12442 if (scf_iter_instance_snapshots(iter, inst) == -1)
12443 scfdie();
12444
12445 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
12446 if (_scf_snapshot_delete(snap) != 0) {
12447 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12448 scfdie();
12449
12450 semerr(emsg_permission_denied);
12451
12452 (void) scf_iter_destroy(iter);
12453 (void) scf_snapshot_destroy(snap);
12454 return (DELETE_FAILURE);
12455 }
12456 }
12457
12458 if (err == -1)
12459 scfdie();
12460
12461 (void) scf_iter_destroy(iter);
12462 (void) scf_snapshot_destroy(snap);
12463 return (DELETE_SUCCESS_EXTDEPS);
12464 }
12465
12466 if (scf_instance_delete(inst) != 0) {
12467 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12468 scfdie();
12469
12470 semerr(emsg_permission_denied);
12471
12472 return (DELETE_FAILURE);
12473 }
12474
12475 return (DELETE_SUCCESS_NOEXTDEPS);
12476 }
12477
12478 /*
12479 * lscf_service_delete() deletes a service. Before calling
12480 * scf_service_delete(), though, we call lscf_instance_delete() for
12481 * each of the instances and delete dependencies in other entities
12482 * which were created as "dependents" of this service. If there are
12483 * dependencies which were created for other entities, then we delete
12484 * all other property groups in the service and leave it as "empty".
12485 *
12486 * lscf_service_delete() verifies that there is no external dependency
12487 * pgs at the instance & service level before suppressing the service.
12488 * If there is, then we must not remove them now in case the service
12489 * is re-imported otherwise the dependencies would be lost. The external
12490 * dependency pgs will be removed if the dependencies are removed.
12491 *
12492 * Returns:
12493 * DELETE_FAILURE on failure
12494 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12495 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12496 */
12497 static int
12498 lscf_service_delete(scf_service_t *svc, int force)
12499 {
12500 int r;
12501 scf_instance_t *inst;
12502 scf_propertygroup_t *pg;
12503 scf_iter_t *iter;
12504 int ret;
12505 int external = 0;
12506
12507 if ((inst = scf_instance_create(g_hndl)) == NULL ||
12508 (pg = scf_pg_create(g_hndl)) == NULL ||
12509 (iter = scf_iter_create(g_hndl)) == NULL)
12510 scfdie();
12511
12512 if (scf_iter_service_instances(iter, svc) != 0)
12513 scfdie();
12514
12515 for (r = scf_iter_next_instance(iter, inst);
12516 r == 1;
12517 r = scf_iter_next_instance(iter, inst)) {
12518
12519 ret = lscf_instance_delete(inst, force);
12520 if (ret == DELETE_FAILURE) {
12521 scf_iter_destroy(iter);
12522 scf_pg_destroy(pg);
12523 scf_instance_destroy(inst);
12524 return (DELETE_FAILURE);
12525 }
12526
12527 /*
12528 * Record the fact that there is some external dependencies
12529 * at the instance level.
12530 */
12531 if (ret == DELETE_SUCCESS_EXTDEPS)
12532 external |= 1;
12533 }
12534
12535 if (r != 0)
12536 scfdie();
12537
12538 /* Delete dependency property groups in dependent services. */
12539 if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12540 (void) delete_dependents(pg);
12541 else if (scf_error() != SCF_ERROR_NOT_FOUND)
12542 scfdie();
12543
12544 scf_iter_destroy(iter);
12545 scf_pg_destroy(pg);
12546 scf_instance_destroy(inst);
12547
12548 /*
12549 * If the service has some external dependencies then we don't
12550 * want to remove them in case the service is re-imported.
12551 */
12552 if ((pg = scf_pg_create(g_hndl)) == NULL ||
12553 (iter = scf_iter_create(g_hndl)) == NULL)
12554 scfdie();
12555
12556 if (scf_iter_service_pgs(iter, svc) < 0)
12557 scfdie();
12558
12559 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12560 if (pg_is_external_dependency(pg)) {
12561 external |= 2;
12562 continue;
12563 }
12564
12565 if (scf_pg_delete(pg) != 0) {
12566 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12567 scfdie();
12568 else {
12569 semerr(emsg_permission_denied);
12570
12571 (void) scf_iter_destroy(iter);
12572 (void) scf_pg_destroy(pg);
12573 return (DELETE_FAILURE);
12574 }
12575 }
12576 }
12577
12578 if (r == -1)
12579 scfdie();
12580
12581 (void) scf_iter_destroy(iter);
12582 (void) scf_pg_destroy(pg);
12583
12584 if (external != 0)
12585 return (DELETE_SUCCESS_EXTDEPS);
12586
12587 if (scf_service_delete(svc) == 0)
12588 return (DELETE_SUCCESS_NOEXTDEPS);
12589
12590 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12591 scfdie();
12592
12593 semerr(emsg_permission_denied);
12594 return (DELETE_FAILURE);
12595 }
12596
12597 static int
12598 delete_callback(void *data, scf_walkinfo_t *wip)
12599 {
12600 int force = (int)data;
12601
12602 if (wip->inst != NULL)
12603 (void) lscf_instance_delete(wip->inst, force);
12604 else
12605 (void) lscf_service_delete(wip->svc, force);
12606
12607 return (0);
12608 }
12609
12610 void
12611 lscf_delete(const char *fmri, int force)
12612 {
12613 scf_service_t *svc;
12614 scf_instance_t *inst;
12615 int ret;
12616
12617 lscf_prep_hndl();
12618
12619 if (cur_snap != NULL) {
12620 if (!snaplevel_is_instance(cur_level)) {
12621 char *buf;
12622
12623 buf = safe_malloc(max_scf_name_len + 1);
12624 if (scf_instance_get_name(cur_inst, buf,
12625 max_scf_name_len + 1) >= 0) {
12626 if (strcmp(buf, fmri) == 0) {
12627 semerr(emsg_cant_modify_snapshots);
12628 free(buf);
12629 return;
12630 }
12631 } else if (scf_error() != SCF_ERROR_DELETED) {
12632 scfdie();
12633 }
12634 free(buf);
12635 }
12636 } else if (cur_inst != NULL) {
12637 /* EMPTY */;
12638 } else if (cur_svc != NULL) {
12639 inst = scf_instance_create(g_hndl);
12640 if (inst == NULL)
12641 scfdie();
12642
12643 if (scf_service_get_instance(cur_svc, fmri, inst) ==
12644 SCF_SUCCESS) {
12645 (void) lscf_instance_delete(inst, force);
12646 scf_instance_destroy(inst);
12647 return;
12648 }
12649
12650 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12651 scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12652 scfdie();
12653
12654 scf_instance_destroy(inst);
12655 } else {
12656 assert(cur_scope != NULL);
12657
12658 svc = scf_service_create(g_hndl);
12659 if (svc == NULL)
12660 scfdie();
12661
12662 if (scf_scope_get_service(cur_scope, fmri, svc) ==
12663 SCF_SUCCESS) {
12664 (void) lscf_service_delete(svc, force);
12665 scf_service_destroy(svc);
12666 return;
12667 }
12668
12669 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12670 scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12671 scfdie();
12672
12673 scf_service_destroy(svc);
12674 }
12675
12676 /*
12677 * Match FMRI to entity.
12678 */
12679 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12680 delete_callback, (void *)force, NULL, semerr)) != 0) {
12681 semerr(gettext("Failed to walk instances: %s\n"),
12682 scf_strerror(ret));
12683 }
12684 }
12685
12686
12687
12688 /*
12689 * :properties commands. These all end with "pg" or "prop" and generally
12690 * operate on the currently selected entity.
12691 */
12692
12693 /*
12694 * Property listing. List the property groups, properties, their types and
12695 * their values for the currently selected entity.
12696 */
12697 static void
12698 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12699 {
12700 char *buf;
12701 uint32_t flags;
12702
12703 buf = safe_malloc(max_scf_pg_type_len + 1);
12704
12705 if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12706 scfdie();
12707
12708 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12709 scfdie();
12710
12711 safe_printf("%-*s %s", namewidth, name, buf);
12712
12713 if (flags & SCF_PG_FLAG_NONPERSISTENT)
12714 safe_printf("\tNONPERSISTENT");
12715
12716 safe_printf("\n");
12717
12718 free(buf);
12719 }
12720
12721 static boolean_t
12722 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12723 {
12724 if (scf_property_get_value(prop, val) == 0) {
12725 return (B_FALSE);
12726 } else {
12727 switch (scf_error()) {
12728 case SCF_ERROR_NOT_FOUND:
12729 return (B_FALSE);
12730 case SCF_ERROR_PERMISSION_DENIED:
12731 case SCF_ERROR_CONSTRAINT_VIOLATED:
12732 return (B_TRUE);
12733 default:
12734 scfdie();
12735 /*NOTREACHED*/
12736 }
12737 }
12738 }
12739
12740 static void
12741 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12742 {
12743 scf_iter_t *iter;
12744 scf_value_t *val;
12745 const char *type;
12746 int multiple_strings = 0;
12747 int ret;
12748
12749 if ((iter = scf_iter_create(g_hndl)) == NULL ||
12750 (val = scf_value_create(g_hndl)) == NULL)
12751 scfdie();
12752
12753 type = prop_to_typestr(prop);
12754 assert(type != NULL);
12755
12756 safe_printf("%-*s %-7s ", len, name, type);
12757
12758 if (prop_has_multiple_values(prop, val) &&
12759 (scf_value_type(val) == SCF_TYPE_ASTRING ||
12760 scf_value_type(val) == SCF_TYPE_USTRING))
12761 multiple_strings = 1;
12762
12763 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12764 scfdie();
12765
12766 while ((ret = scf_iter_next_value(iter, val)) == 1) {
12767 char *buf;
12768 ssize_t vlen, szret;
12769
12770 vlen = scf_value_get_as_string(val, NULL, 0);
12771 if (vlen < 0)
12772 scfdie();
12773
12774 buf = safe_malloc(vlen + 1);
12775
12776 szret = scf_value_get_as_string(val, buf, vlen + 1);
12777 if (szret < 0)
12778 scfdie();
12779 assert(szret <= vlen);
12780
12781 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12782 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12783 safe_printf(" \"");
12784 (void) quote_and_print(buf, stdout, 0);
12785 (void) putchar('"');
12786 if (ferror(stdout)) {
12787 (void) putchar('\n');
12788 uu_die(gettext("Error writing to stdout.\n"));
12789 }
12790 } else {
12791 safe_printf(" %s", buf);
12792 }
12793
12794 free(buf);
12795 }
12796 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12797 scfdie();
12798
12799 if (putchar('\n') != '\n')
12800 uu_die(gettext("Could not output newline"));
12801 }
12802
12803 /*
12804 * Outputs template property group info for the describe subcommand.
12805 * If 'templates' == 2, verbose output is printed in the format expected
12806 * for describe -v, which includes all templates fields. If pg is
12807 * not NULL, we're describing the template data, not an existing property
12808 * group, and formatting should be appropriate for describe -t.
12809 */
12810 static void
12811 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12812 {
12813 char *buf;
12814 uint8_t required;
12815 scf_property_t *stability_prop;
12816 scf_value_t *stability_val;
12817
12818 if (templates == 0)
12819 return;
12820
12821 if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12822 (stability_val = scf_value_create(g_hndl)) == NULL)
12823 scfdie();
12824
12825 if (templates == 2 && pg != NULL) {
12826 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12827 stability_prop) == 0) {
12828 if (prop_check_type(stability_prop,
12829 SCF_TYPE_ASTRING) == 0 &&
12830 prop_get_val(stability_prop, stability_val) == 0) {
12831 char *stability;
12832
12833 stability = safe_malloc(max_scf_value_len + 1);
12834
12835 if (scf_value_get_astring(stability_val,
12836 stability, max_scf_value_len + 1) == -1 &&
12837 scf_error() != SCF_ERROR_NOT_FOUND)
12838 scfdie();
12839
12840 safe_printf("%s%s: %s\n", TMPL_INDENT,
12841 gettext("stability"), stability);
12842
12843 free(stability);
12844 }
12845 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
12846 scfdie();
12847 }
12848
12849 scf_property_destroy(stability_prop);
12850 scf_value_destroy(stability_val);
12851
12852 if (pgt == NULL)
12853 return;
12854
12855 if (pg == NULL || templates == 2) {
12856 /* print type info only if scf_tmpl_pg_name succeeds */
12857 if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12858 if (pg != NULL)
12859 safe_printf("%s", TMPL_INDENT);
12860 safe_printf("%s: ", gettext("name"));
12861 safe_printf("%s\n", buf);
12862 free(buf);
12863 }
12864
12865 /* print type info only if scf_tmpl_pg_type succeeds */
12866 if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12867 if (pg != NULL)
12868 safe_printf("%s", TMPL_INDENT);
12869 safe_printf("%s: ", gettext("type"));
12870 safe_printf("%s\n", buf);
12871 free(buf);
12872 }
12873 }
12874
12875 if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12876 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12877 required ? "true" : "false");
12878
12879 if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12880 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12881 buf);
12882 free(buf);
12883 }
12884
12885 if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12886 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12887 buf);
12888 free(buf);
12889 }
12890
12891 if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12892 if (templates == 2)
12893 safe_printf("%s%s: %s\n", TMPL_INDENT,
12894 gettext("description"), buf);
12895 else
12896 safe_printf("%s%s\n", TMPL_INDENT, buf);
12897 free(buf);
12898 }
12899
12900 }
12901
12902 /*
12903 * With as_value set to true, indent as appropriate for the value level.
12904 * If false, indent to appropriate level for inclusion in constraint
12905 * or choice printout.
12906 */
12907 static void
12908 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12909 int as_value)
12910 {
12911 char *buf;
12912
12913 if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12914 if (as_value == 0)
12915 safe_printf("%s", TMPL_CHOICE_INDENT);
12916 else
12917 safe_printf("%s", TMPL_INDENT);
12918 safe_printf("%s: %s\n", gettext("value common name"), buf);
12919 free(buf);
12920 }
12921
12922 if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12923 if (as_value == 0)
12924 safe_printf("%s", TMPL_CHOICE_INDENT);
12925 else
12926 safe_printf("%s", TMPL_INDENT);
12927 safe_printf("%s: %s\n", gettext("value description"), buf);
12928 free(buf);
12929 }
12930 }
12931
12932 static void
12933 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12934 {
12935 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12936 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12937 safe_printf("%s\n", val_buf);
12938
12939 print_template_value_details(prt, val_buf, 1);
12940 }
12941
12942 static void
12943 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12944 {
12945 int i, printed = 0;
12946 scf_values_t values;
12947 scf_count_ranges_t c_ranges;
12948 scf_int_ranges_t i_ranges;
12949
12950 printed = 0;
12951 i = 0;
12952 if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12953 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12954 gettext("value constraints"));
12955 printed++;
12956 for (i = 0; i < values.value_count; ++i) {
12957 safe_printf("%s%s: %s\n", TMPL_INDENT,
12958 gettext("value name"), values.values_as_strings[i]);
12959 if (verbose == 1)
12960 print_template_value_details(prt,
12961 values.values_as_strings[i], 0);
12962 }
12963
12964 scf_values_destroy(&values);
12965 }
12966
12967 if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12968 if (printed++ == 0)
12969 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12970 gettext("value constraints"));
12971 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12972 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12973 gettext("range"), c_ranges.scr_min[i],
12974 c_ranges.scr_max[i]);
12975 }
12976 scf_count_ranges_destroy(&c_ranges);
12977 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12978 scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
12979 if (printed++ == 0)
12980 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12981 gettext("value constraints"));
12982 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12983 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12984 gettext("range"), i_ranges.sir_min[i],
12985 i_ranges.sir_max[i]);
12986 }
12987 scf_int_ranges_destroy(&i_ranges);
12988 }
12989 }
12990
12991 static void
12992 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
12993 {
12994 int i = 0, printed = 0;
12995 scf_values_t values;
12996 scf_count_ranges_t c_ranges;
12997 scf_int_ranges_t i_ranges;
12998
12999 printed = 0;
13000 if (scf_tmpl_value_name_choices(prt, &values) == 0) {
13001 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13002 gettext("value constraints"));
13003 printed++;
13004 for (i = 0; i < values.value_count; i++) {
13005 safe_printf("%s%s: %s\n", TMPL_INDENT,
13006 gettext("value name"), values.values_as_strings[i]);
13007 if (verbose == 1)
13008 print_template_value_details(prt,
13009 values.values_as_strings[i], 0);
13010 }
13011
13012 scf_values_destroy(&values);
13013 }
13014
13015 if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
13016 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
13017 if (printed++ == 0)
13018 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13019 gettext("value choices"));
13020 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
13021 gettext("range"), c_ranges.scr_min[i],
13022 c_ranges.scr_max[i]);
13023 }
13024 scf_count_ranges_destroy(&c_ranges);
13025 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
13026 scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
13027 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
13028 if (printed++ == 0)
13029 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13030 gettext("value choices"));
13031 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
13032 gettext("range"), i_ranges.sir_min[i],
13033 i_ranges.sir_max[i]);
13034 }
13035 scf_int_ranges_destroy(&i_ranges);
13036 }
13037 }
13038
13039 static void
13040 list_values_by_template(scf_prop_tmpl_t *prt)
13041 {
13042 print_template_constraints(prt, 1);
13043 print_template_choices(prt, 1);
13044 }
13045
13046 static void
13047 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
13048 {
13049 char *val_buf;
13050 scf_iter_t *iter;
13051 scf_value_t *val;
13052 int ret;
13053
13054 if ((iter = scf_iter_create(g_hndl)) == NULL ||
13055 (val = scf_value_create(g_hndl)) == NULL)
13056 scfdie();
13057
13058 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
13059 scfdie();
13060
13061 val_buf = safe_malloc(max_scf_value_len + 1);
13062
13063 while ((ret = scf_iter_next_value(iter, val)) == 1) {
13064 if (scf_value_get_as_string(val, val_buf,
13065 max_scf_value_len + 1) < 0)
13066 scfdie();
13067
13068 print_template_value(prt, val_buf);
13069 }
13070 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
13071 scfdie();
13072 free(val_buf);
13073
13074 print_template_constraints(prt, 0);
13075 print_template_choices(prt, 0);
13076
13077 }
13078
13079 /*
13080 * Outputs property info for the describe subcommand
13081 * Verbose output if templates == 2, -v option of svccfg describe
13082 * Displays template data if prop is not NULL, -t option of svccfg describe
13083 */
13084 static void
13085 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
13086 {
13087 char *buf;
13088 uint8_t u_buf;
13089 int i;
13090 uint64_t min, max;
13091 scf_values_t values;
13092
13093 if (prt == NULL || templates == 0)
13094 return;
13095
13096 if (prop == NULL) {
13097 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
13098 if (scf_tmpl_prop_name(prt, &buf) > 0) {
13099 safe_printf("%s\n", buf);
13100 free(buf);
13101 } else
13102 safe_printf("(%s)\n", gettext("any"));
13103 }
13104
13105 if (prop == NULL || templates == 2) {
13106 if (prop != NULL)
13107 safe_printf("%s", TMPL_INDENT);
13108 else
13109 safe_printf("%s", TMPL_VALUE_INDENT);
13110 safe_printf("%s: ", gettext("type"));
13111 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
13112 safe_printf("%s\n", buf);
13113 free(buf);
13114 } else
13115 safe_printf("(%s)\n", gettext("any"));
13116 }
13117
13118 if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
13119 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
13120 u_buf ? "true" : "false");
13121
13122 if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
13123 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
13124 buf);
13125 free(buf);
13126 }
13127
13128 if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
13129 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
13130 buf);
13131 free(buf);
13132 }
13133
13134 if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
13135 safe_printf("%s%s\n", TMPL_INDENT, buf);
13136 free(buf);
13137 }
13138
13139 if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
13140 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
13141 scf_tmpl_visibility_to_string(u_buf));
13142
13143 if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
13144 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13145 gettext("minimum number of values"), min);
13146 if (max == ULLONG_MAX) {
13147 safe_printf("%s%s: %s\n", TMPL_INDENT,
13148 gettext("maximum number of values"),
13149 gettext("unlimited"));
13150 } else {
13151 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13152 gettext("maximum number of values"), max);
13153 }
13154 }
13155
13156 if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
13157 for (i = 0; i < values.value_count; i++) {
13158 if (i == 0) {
13159 safe_printf("%s%s:", TMPL_INDENT,
13160 gettext("internal separators"));
13161 }
13162 safe_printf(" \"%s\"", values.values_as_strings[i]);
13163 }
13164 safe_printf("\n");
13165 }
13166
13167 if (templates != 2)
13168 return;
13169
13170 if (prop != NULL)
13171 list_values_tmpl(prt, prop);
13172 else
13173 list_values_by_template(prt);
13174 }
13175
13176 static char *
13177 read_astring(scf_propertygroup_t *pg, const char *prop_name)
13178 {
13179 char *rv;
13180
13181 rv = _scf_read_single_astring_from_pg(pg, prop_name);
13182 if (rv == NULL) {
13183 switch (scf_error()) {
13184 case SCF_ERROR_NOT_FOUND:
13185 break;
13186 default:
13187 scfdie();
13188 }
13189 }
13190 return (rv);
13191 }
13192
13193 static void
13194 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
13195 {
13196 size_t doc_len;
13197 size_t man_len;
13198 char *pg_name;
13199 char *text = NULL;
13200 int rv;
13201
13202 doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
13203 man_len = strlen(SCF_PG_TM_MAN_PREFIX);
13204 pg_name = safe_malloc(max_scf_name_len + 1);
13205 while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
13206 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
13207 scfdie();
13208 }
13209 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
13210 /* Display doc_link and and uri */
13211 safe_printf("%s%s:\n", TMPL_INDENT,
13212 gettext("doc_link"));
13213 text = read_astring(pg, SCF_PROPERTY_TM_NAME);
13214 if (text != NULL) {
13215 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13216 TMPL_INDENT, gettext("name"), text);
13217 uu_free(text);
13218 }
13219 text = read_astring(pg, SCF_PROPERTY_TM_URI);
13220 if (text != NULL) {
13221 safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
13222 gettext("uri"), text);
13223 uu_free(text);
13224 }
13225 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
13226 man_len) == 0) {
13227 /* Display manpage title, section and path */
13228 safe_printf("%s%s:\n", TMPL_INDENT,
13229 gettext("manpage"));
13230 text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
13231 if (text != NULL) {
13232 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13233 TMPL_INDENT, gettext("title"), text);
13234 uu_free(text);
13235 }
13236 text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
13237 if (text != NULL) {
13238 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13239 TMPL_INDENT, gettext("section"), text);
13240 uu_free(text);
13241 }
13242 text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
13243 if (text != NULL) {
13244 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13245 TMPL_INDENT, gettext("manpath"), text);
13246 uu_free(text);
13247 }
13248 }
13249 }
13250 if (rv == -1)
13251 scfdie();
13252
13253 done:
13254 free(pg_name);
13255 }
13256
13257 static void
13258 list_entity_tmpl(int templates)
13259 {
13260 char *common_name = NULL;
13261 char *description = NULL;
13262 char *locale = NULL;
13263 scf_iter_t *iter;
13264 scf_propertygroup_t *pg;
13265 scf_property_t *prop;
13266 int r;
13267 scf_value_t *val;
13268
13269 if ((pg = scf_pg_create(g_hndl)) == NULL ||
13270 (prop = scf_property_create(g_hndl)) == NULL ||
13271 (val = scf_value_create(g_hndl)) == NULL ||
13272 (iter = scf_iter_create(g_hndl)) == NULL)
13273 scfdie();
13274
13275 locale = setlocale(LC_MESSAGES, NULL);
13276
13277 if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
13278 common_name = safe_malloc(max_scf_value_len + 1);
13279
13280 /* Try both the current locale and the "C" locale. */
13281 if (scf_pg_get_property(pg, locale, prop) == 0 ||
13282 (scf_error() == SCF_ERROR_NOT_FOUND &&
13283 scf_pg_get_property(pg, "C", prop) == 0)) {
13284 if (prop_get_val(prop, val) == 0 &&
13285 scf_value_get_ustring(val, common_name,
13286 max_scf_value_len + 1) != -1) {
13287 safe_printf("%s%s: %s\n", TMPL_INDENT,
13288 gettext("common name"), common_name);
13289 }
13290 }
13291 }
13292
13293 /*
13294 * Do description, manpages, and doc links if templates == 2.
13295 */
13296 if (templates == 2) {
13297 /* Get the description. */
13298 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
13299 description = safe_malloc(max_scf_value_len + 1);
13300
13301 /* Try both the current locale and the "C" locale. */
13302 if (scf_pg_get_property(pg, locale, prop) == 0 ||
13303 (scf_error() == SCF_ERROR_NOT_FOUND &&
13304 scf_pg_get_property(pg, "C", prop) == 0)) {
13305 if (prop_get_val(prop, val) == 0 &&
13306 scf_value_get_ustring(val, description,
13307 max_scf_value_len + 1) != -1) {
13308 safe_printf("%s%s: %s\n", TMPL_INDENT,
13309 gettext("description"),
13310 description);
13311 }
13312 }
13313 }
13314
13315 /* Process doc_link & manpage elements. */
13316 if (cur_level != NULL) {
13317 r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
13318 SCF_GROUP_TEMPLATE);
13319 } else if (cur_inst != NULL) {
13320 r = scf_iter_instance_pgs_typed(iter, cur_inst,
13321 SCF_GROUP_TEMPLATE);
13322 } else {
13323 r = scf_iter_service_pgs_typed(iter, cur_svc,
13324 SCF_GROUP_TEMPLATE);
13325 }
13326 if (r == 0) {
13327 display_documentation(iter, pg);
13328 }
13329 }
13330
13331 free(common_name);
13332 free(description);
13333 scf_pg_destroy(pg);
13334 scf_property_destroy(prop);
13335 scf_value_destroy(val);
13336 scf_iter_destroy(iter);
13337 }
13338
13339 static void
13340 listtmpl(const char *pattern, int templates)
13341 {
13342 scf_pg_tmpl_t *pgt;
13343 scf_prop_tmpl_t *prt;
13344 char *snapbuf = NULL;
13345 char *fmribuf;
13346 char *pg_name = NULL, *prop_name = NULL;
13347 ssize_t prop_name_size;
13348 char *qual_prop_name;
13349 char *search_name;
13350 int listed = 0;
13351
13352 if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13353 (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
13354 scfdie();
13355
13356 fmribuf = safe_malloc(max_scf_name_len + 1);
13357 qual_prop_name = safe_malloc(max_scf_name_len + 1);
13358
13359 if (cur_snap != NULL) {
13360 snapbuf = safe_malloc(max_scf_name_len + 1);
13361 if (scf_snapshot_get_name(cur_snap, snapbuf,
13362 max_scf_name_len + 1) < 0)
13363 scfdie();
13364 }
13365
13366 if (cur_inst != NULL) {
13367 if (scf_instance_to_fmri(cur_inst, fmribuf,
13368 max_scf_name_len + 1) < 0)
13369 scfdie();
13370 } else if (cur_svc != NULL) {
13371 if (scf_service_to_fmri(cur_svc, fmribuf,
13372 max_scf_name_len + 1) < 0)
13373 scfdie();
13374 } else
13375 abort();
13376
13377 /* If pattern is specified, we want to list only those items. */
13378 while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) {
13379 listed = 0;
13380 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
13381 fnmatch(pattern, pg_name, 0) == 0)) {
13382 list_pg_tmpl(pgt, NULL, templates);
13383 listed++;
13384 }
13385
13386 scf_tmpl_prop_reset(prt);
13387
13388 while (scf_tmpl_iter_props(pgt, prt, 0) == 0) {
13389 search_name = NULL;
13390 prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
13391 if ((prop_name_size > 0) && (pg_name != NULL)) {
13392 if (snprintf(qual_prop_name,
13393 max_scf_name_len + 1, "%s/%s",
13394 pg_name, prop_name) >=
13395 max_scf_name_len + 1) {
13396 prop_name_size = -1;
13397 } else {
13398 search_name = qual_prop_name;
13399 }
13400 }
13401 if (listed > 0 || pattern == NULL ||
13402 (prop_name_size > 0 &&
13403 fnmatch(pattern, search_name,
13404 FNM_PATHNAME) == 0))
13405 list_prop_tmpl(prt, NULL, templates);
13406 if (prop_name != NULL) {
13407 free(prop_name);
13408 prop_name = NULL;
13409 }
13410 }
13411 if (pg_name != NULL) {
13412 free(pg_name);
13413 pg_name = NULL;
13414 }
13415 }
13416
13417 scf_tmpl_prop_destroy(prt);
13418 scf_tmpl_pg_destroy(pgt);
13419 free(snapbuf);
13420 free(fmribuf);
13421 free(qual_prop_name);
13422 }
13423
13424 static void
13425 listprop(const char *pattern, int only_pgs, int templates)
13426 {
13427 scf_propertygroup_t *pg;
13428 scf_property_t *prop;
13429 scf_iter_t *iter, *piter;
13430 char *pgnbuf, *prnbuf, *ppnbuf;
13431 scf_pg_tmpl_t *pgt, *pgtp;
13432 scf_prop_tmpl_t *prt;
13433
13434 void **objects;
13435 char **names;
13436 void **tmpls;
13437 int allocd, i;
13438
13439 int ret;
13440 ssize_t pgnlen, prnlen, szret;
13441 size_t max_len = 0;
13442
13443 if (cur_svc == NULL && cur_inst == NULL) {
13444 semerr(emsg_entity_not_selected);
13445 return;
13446 }
13447
13448 if ((pg = scf_pg_create(g_hndl)) == NULL ||
13449 (prop = scf_property_create(g_hndl)) == NULL ||
13450 (iter = scf_iter_create(g_hndl)) == NULL ||
13451 (piter = scf_iter_create(g_hndl)) == NULL ||
13452 (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13453 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
13454 scfdie();
13455
13456 prnbuf = safe_malloc(max_scf_name_len + 1);
13457
13458 if (cur_level != NULL)
13459 ret = scf_iter_snaplevel_pgs(iter, cur_level);
13460 else if (cur_inst != NULL)
13461 ret = scf_iter_instance_pgs(iter, cur_inst);
13462 else
13463 ret = scf_iter_service_pgs(iter, cur_svc);
13464 if (ret != 0) {
13465 return;
13466 }
13467
13468 /*
13469 * We want to only list items which match pattern, and we want the
13470 * second column to line up, so during the first pass we'll save
13471 * matching items, their names, and their templates in objects,
13472 * names, and tmpls, computing the maximum name length as we go,
13473 * and then we'll print them out.
13474 *
13475 * Note: We always keep an extra slot available so the array can be
13476 * NULL-terminated.
13477 */
13478 i = 0;
13479 allocd = 1;
13480 objects = safe_malloc(sizeof (*objects));
13481 names = safe_malloc(sizeof (*names));
13482 tmpls = safe_malloc(sizeof (*tmpls));
13483
13484 while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13485 int new_pg = 0;
13486 int print_props = 0;
13487 pgtp = NULL;
13488
13489 pgnlen = scf_pg_get_name(pg, NULL, 0);
13490 if (pgnlen < 0)
13491 scfdie();
13492
13493 pgnbuf = safe_malloc(pgnlen + 1);
13494
13495 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
13496 if (szret < 0)
13497 scfdie();
13498 assert(szret <= pgnlen);
13499
13500 if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) {
13501 if (scf_error() != SCF_ERROR_NOT_FOUND)
13502 scfdie();
13503 pgtp = NULL;
13504 } else {
13505 pgtp = pgt;
13506 }
13507
13508 if (pattern == NULL ||
13509 fnmatch(pattern, pgnbuf, 0) == 0) {
13510 if (i+1 >= allocd) {
13511 allocd *= 2;
13512 objects = realloc(objects,
13513 sizeof (*objects) * allocd);
13514 names =
13515 realloc(names, sizeof (*names) * allocd);
13516 tmpls = realloc(tmpls,
13517 sizeof (*tmpls) * allocd);
13518 if (objects == NULL || names == NULL ||
13519 tmpls == NULL)
13520 uu_die(gettext("Out of memory"));
13521 }
13522 objects[i] = pg;
13523 names[i] = pgnbuf;
13524
13525 if (pgtp == NULL)
13526 tmpls[i] = NULL;
13527 else
13528 tmpls[i] = pgt;
13529
13530 ++i;
13531
13532 if (pgnlen > max_len)
13533 max_len = pgnlen;
13534
13535 new_pg = 1;
13536 print_props = 1;
13537 }
13538
13539 if (only_pgs) {
13540 if (new_pg) {
13541 pg = scf_pg_create(g_hndl);
13542 if (pg == NULL)
13543 scfdie();
13544 pgt = scf_tmpl_pg_create(g_hndl);
13545 if (pgt == NULL)
13546 scfdie();
13547 } else
13548 free(pgnbuf);
13549
13550 continue;
13551 }
13552
13553 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13554 scfdie();
13555
13556 while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13557 prnlen = scf_property_get_name(prop, prnbuf,
13558 max_scf_name_len + 1);
13559 if (prnlen < 0)
13560 scfdie();
13561
13562 /* Will prepend the property group name and a slash. */
13563 prnlen += pgnlen + 1;
13564
13565 ppnbuf = safe_malloc(prnlen + 1);
13566
13567 if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13568 prnbuf) < 0)
13569 uu_die("snprintf");
13570
13571 if (pattern == NULL || print_props == 1 ||
13572 fnmatch(pattern, ppnbuf, 0) == 0) {
13573 if (i+1 >= allocd) {
13574 allocd *= 2;
13575 objects = realloc(objects,
13576 sizeof (*objects) * allocd);
13577 names = realloc(names,
13578 sizeof (*names) * allocd);
13579 tmpls = realloc(tmpls,
13580 sizeof (*tmpls) * allocd);
13581 if (objects == NULL || names == NULL ||
13582 tmpls == NULL)
13583 uu_die(gettext(
13584 "Out of memory"));
13585 }
13586
13587 objects[i] = prop;
13588 names[i] = ppnbuf;
13589
13590 if (pgtp != NULL) {
13591 if (scf_tmpl_get_by_prop(pgt, prnbuf,
13592 prt, 0) < 0) {
13593 if (scf_error() !=
13594 SCF_ERROR_NOT_FOUND)
13595 scfdie();
13596 tmpls[i] = NULL;
13597 } else {
13598 tmpls[i] = prt;
13599 }
13600 } else {
13601 tmpls[i] = NULL;
13602 }
13603
13604 ++i;
13605
13606 if (prnlen > max_len)
13607 max_len = prnlen;
13608
13609 prop = scf_property_create(g_hndl);
13610 prt = scf_tmpl_prop_create(g_hndl);
13611 } else {
13612 free(ppnbuf);
13613 }
13614 }
13615
13616 if (new_pg) {
13617 pg = scf_pg_create(g_hndl);
13618 if (pg == NULL)
13619 scfdie();
13620 pgt = scf_tmpl_pg_create(g_hndl);
13621 if (pgt == NULL)
13622 scfdie();
13623 } else
13624 free(pgnbuf);
13625 }
13626 if (ret != 0)
13627 scfdie();
13628
13629 objects[i] = NULL;
13630
13631 scf_pg_destroy(pg);
13632 scf_tmpl_pg_destroy(pgt);
13633 scf_property_destroy(prop);
13634 scf_tmpl_prop_destroy(prt);
13635
13636 for (i = 0; objects[i] != NULL; ++i) {
13637 if (strchr(names[i], '/') == NULL) {
13638 /* property group */
13639 pg = (scf_propertygroup_t *)objects[i];
13640 pgt = (scf_pg_tmpl_t *)tmpls[i];
13641 list_pg_info(pg, names[i], max_len);
13642 list_pg_tmpl(pgt, pg, templates);
13643 free(names[i]);
13644 scf_pg_destroy(pg);
13645 if (pgt != NULL)
13646 scf_tmpl_pg_destroy(pgt);
13647 } else {
13648 /* property */
13649 prop = (scf_property_t *)objects[i];
13650 prt = (scf_prop_tmpl_t *)tmpls[i];
13651 list_prop_info(prop, names[i], max_len);
13652 list_prop_tmpl(prt, prop, templates);
13653 free(names[i]);
13654 scf_property_destroy(prop);
13655 if (prt != NULL)
13656 scf_tmpl_prop_destroy(prt);
13657 }
13658 }
13659
13660 free(names);
13661 free(objects);
13662 free(tmpls);
13663 }
13664
13665 void
13666 lscf_listpg(const char *pattern)
13667 {
13668 lscf_prep_hndl();
13669
13670 listprop(pattern, 1, 0);
13671 }
13672
13673 /*
13674 * Property group and property creation, setting, and deletion. setprop (and
13675 * its alias, addprop) can either create a property group of a given type, or
13676 * it can create or set a property to a given type and list of values.
13677 */
13678 void
13679 lscf_addpg(const char *name, const char *type, const char *flags)
13680 {
13681 scf_propertygroup_t *pg;
13682 int ret;
13683 uint32_t flgs = 0;
13684 const char *cp;
13685
13686
13687 lscf_prep_hndl();
13688
13689 if (cur_snap != NULL) {
13690 semerr(emsg_cant_modify_snapshots);
13691 return;
13692 }
13693
13694 if (cur_inst == NULL && cur_svc == NULL) {
13695 semerr(emsg_entity_not_selected);
13696 return;
13697 }
13698
13699 if (flags != NULL) {
13700 for (cp = flags; *cp != '\0'; ++cp) {
13701 switch (*cp) {
13702 case 'P':
13703 flgs |= SCF_PG_FLAG_NONPERSISTENT;
13704 break;
13705
13706 case 'p':
13707 flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13708 break;
13709
13710 default:
13711 semerr(gettext("Invalid property group flag "
13712 "%c."), *cp);
13713 return;
13714 }
13715 }
13716 }
13717
13718 pg = scf_pg_create(g_hndl);
13719 if (pg == NULL)
13720 scfdie();
13721
13722 if (cur_inst != NULL)
13723 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13724 else
13725 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13726
13727 if (ret != SCF_SUCCESS) {
13728 switch (scf_error()) {
13729 case SCF_ERROR_INVALID_ARGUMENT:
13730 semerr(gettext("Name, type, or flags are invalid.\n"));
13731 break;
13732
13733 case SCF_ERROR_EXISTS:
13734 semerr(gettext("Property group already exists.\n"));
13735 break;
13736
13737 case SCF_ERROR_PERMISSION_DENIED:
13738 semerr(emsg_permission_denied);
13739 break;
13740
13741 case SCF_ERROR_BACKEND_ACCESS:
13742 semerr(gettext("Backend refused access.\n"));
13743 break;
13744
13745 default:
13746 scfdie();
13747 }
13748 }
13749
13750 scf_pg_destroy(pg);
13751
13752 private_refresh();
13753 }
13754
13755 void
13756 lscf_delpg(char *name)
13757 {
13758 lscf_prep_hndl();
13759
13760 if (cur_snap != NULL) {
13761 semerr(emsg_cant_modify_snapshots);
13762 return;
13763 }
13764
13765 if (cur_inst == NULL && cur_svc == NULL) {
13766 semerr(emsg_entity_not_selected);
13767 return;
13768 }
13769
13770 if (strchr(name, '/') != NULL) {
13771 semerr(emsg_invalid_pg_name, name);
13772 return;
13773 }
13774
13775 lscf_delprop(name);
13776 }
13777
13778 /*
13779 * scf_delhash() is used to remove the property group related to the
13780 * hash entry for a specific manifest in the repository. pgname will be
13781 * constructed from the location of the manifest file. If deathrow isn't 0,
13782 * manifest file doesn't need to exist (manifest string will be used as
13783 * an absolute path).
13784 */
13785 void
13786 lscf_delhash(char *manifest, int deathrow)
13787 {
13788 char *pgname;
13789
13790 if (cur_snap != NULL ||
13791 cur_inst != NULL || cur_svc != NULL) {
13792 warn(gettext("error, an entity is selected\n"));
13793 return;
13794 }
13795
13796 /* select smf/manifest */
13797 lscf_select(HASH_SVC);
13798 /*
13799 * Translate the manifest file name to property name. In the deathrow
13800 * case, the manifest file does not need to exist.
13801 */
13802 pgname = mhash_filename_to_propname(manifest,
13803 deathrow ? B_TRUE : B_FALSE);
13804 if (pgname == NULL) {
13805 warn(gettext("cannot resolve pathname for %s\n"), manifest);
13806 return;
13807 }
13808 /* delete the hash property name */
13809 lscf_delpg(pgname);
13810 }
13811
13812 void
13813 lscf_listprop(const char *pattern)
13814 {
13815 lscf_prep_hndl();
13816
13817 listprop(pattern, 0, 0);
13818 }
13819
13820 int
13821 lscf_setprop(const char *pgname, const char *type, const char *value,
13822 const uu_list_t *values)
13823 {
13824 scf_type_t ty, current_ty;
13825 scf_service_t *svc;
13826 scf_propertygroup_t *pg, *parent_pg;
13827 scf_property_t *prop, *parent_prop;
13828 scf_pg_tmpl_t *pgt;
13829 scf_prop_tmpl_t *prt;
13830 int ret, result = 0;
13831 scf_transaction_t *tx;
13832 scf_transaction_entry_t *e;
13833 scf_value_t *v;
13834 uu_list_walk_t *walk;
13835 string_list_t *sp;
13836 char *propname;
13837 int req_quotes = 0;
13838
13839 lscf_prep_hndl();
13840
13841 if ((e = scf_entry_create(g_hndl)) == NULL ||
13842 (svc = scf_service_create(g_hndl)) == NULL ||
13843 (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13844 (pg = scf_pg_create(g_hndl)) == NULL ||
13845 (parent_prop = scf_property_create(g_hndl)) == NULL ||
13846 (prop = scf_property_create(g_hndl)) == NULL ||
13847 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13848 (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13849 (tx = scf_transaction_create(g_hndl)) == NULL)
13850 scfdie();
13851
13852 if (cur_snap != NULL) {
13853 semerr(emsg_cant_modify_snapshots);
13854 goto fail;
13855 }
13856
13857 if (cur_inst == NULL && cur_svc == NULL) {
13858 semerr(emsg_entity_not_selected);
13859 goto fail;
13860 }
13861
13862 propname = strchr(pgname, '/');
13863 if (propname == NULL) {
13864 semerr(gettext("Property names must contain a `/'.\n"));
13865 goto fail;
13866 }
13867
13868 *propname = '\0';
13869 ++propname;
13870
13871 if (type != NULL) {
13872 ty = string_to_type(type);
13873 if (ty == SCF_TYPE_INVALID) {
13874 semerr(gettext("Unknown type \"%s\".\n"), type);
13875 goto fail;
13876 }
13877 }
13878
13879 if (cur_inst != NULL)
13880 ret = scf_instance_get_pg(cur_inst, pgname, pg);
13881 else
13882 ret = scf_service_get_pg(cur_svc, pgname, pg);
13883 if (ret != SCF_SUCCESS) {
13884 switch (scf_error()) {
13885 case SCF_ERROR_NOT_FOUND:
13886 semerr(emsg_no_such_pg, pgname);
13887 goto fail;
13888
13889 case SCF_ERROR_INVALID_ARGUMENT:
13890 semerr(emsg_invalid_pg_name, pgname);
13891 goto fail;
13892
13893 default:
13894 scfdie();
13895 break;
13896 }
13897 }
13898
13899 do {
13900 if (scf_pg_update(pg) == -1)
13901 scfdie();
13902 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13903 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13904 scfdie();
13905
13906 semerr(emsg_permission_denied);
13907 goto fail;
13908 }
13909
13910 ret = scf_pg_get_property(pg, propname, prop);
13911 if (ret == SCF_SUCCESS) {
13912 if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS)
13913 scfdie();
13914
13915 if (type == NULL)
13916 ty = current_ty;
13917 if (scf_transaction_property_change_type(tx, e,
13918 propname, ty) == -1)
13919 scfdie();
13920
13921 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13922 /* Infer the type, if possible. */
13923 if (type == NULL) {
13924 /*
13925 * First check if we're an instance and the
13926 * property is set on the service.
13927 */
13928 if (cur_inst != NULL &&
13929 scf_instance_get_parent(cur_inst,
13930 svc) == 0 &&
13931 scf_service_get_pg(cur_svc, pgname,
13932 parent_pg) == 0 &&
13933 scf_pg_get_property(parent_pg, propname,
13934 parent_prop) == 0 &&
13935 scf_property_type(parent_prop,
13936 ¤t_ty) == 0) {
13937 ty = current_ty;
13938
13939 /* Then check for a type set in a template. */
13940 } else if (scf_tmpl_get_by_pg(pg, pgt,
13941 0) == 0 &&
13942 scf_tmpl_get_by_prop(pgt, propname, prt,
13943 0) == 0 &&
13944 scf_tmpl_prop_type(prt, ¤t_ty) == 0) {
13945 ty = current_ty;
13946
13947 /* If type can't be inferred, fail. */
13948 } else {
13949 semerr(gettext("Type required for new "
13950 "properties.\n"));
13951 goto fail;
13952 }
13953 }
13954 if (scf_transaction_property_new(tx, e, propname,
13955 ty) == -1)
13956 scfdie();
13957 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13958 semerr(emsg_invalid_prop_name, propname);
13959 goto fail;
13960 } else {
13961 scfdie();
13962 }
13963
13964 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13965 req_quotes = 1;
13966
13967 if (value != NULL) {
13968 v = string_to_value(value, ty, 0);
13969
13970 if (v == NULL)
13971 goto fail;
13972
13973 ret = scf_entry_add_value(e, v);
13974 assert(ret == SCF_SUCCESS);
13975 } else {
13976 assert(values != NULL);
13977
13978 walk = uu_list_walk_start((uu_list_t *)values,
13979 UU_DEFAULT);
13980 if (walk == NULL)
13981 uu_die(gettext("Could not walk list"));
13982
13983 for (sp = uu_list_walk_next(walk); sp != NULL;
13984 sp = uu_list_walk_next(walk)) {
13985 v = string_to_value(sp->str, ty, req_quotes);
13986
13987 if (v == NULL) {
13988 scf_entry_destroy_children(e);
13989 goto fail;
13990 }
13991
13992 ret = scf_entry_add_value(e, v);
13993 assert(ret == SCF_SUCCESS);
13994 }
13995 uu_list_walk_end(walk);
13996 }
13997 result = scf_transaction_commit(tx);
13998
13999 scf_transaction_reset(tx);
14000 scf_entry_destroy_children(e);
14001 } while (result == 0);
14002
14003 if (result < 0) {
14004 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14005 scfdie();
14006
14007 semerr(emsg_permission_denied);
14008 goto fail;
14009 }
14010
14011 ret = 0;
14012
14013 private_refresh();
14014
14015 goto cleanup;
14016
14017 fail:
14018 ret = -1;
14019
14020 cleanup:
14021 scf_transaction_destroy(tx);
14022 scf_entry_destroy(e);
14023 scf_service_destroy(svc);
14024 scf_pg_destroy(parent_pg);
14025 scf_pg_destroy(pg);
14026 scf_property_destroy(parent_prop);
14027 scf_property_destroy(prop);
14028 scf_tmpl_pg_destroy(pgt);
14029 scf_tmpl_prop_destroy(prt);
14030
14031 return (ret);
14032 }
14033
14034 void
14035 lscf_delprop(char *pgn)
14036 {
14037 char *slash, *pn;
14038 scf_propertygroup_t *pg;
14039 scf_transaction_t *tx;
14040 scf_transaction_entry_t *e;
14041 int ret;
14042
14043
14044 lscf_prep_hndl();
14045
14046 if (cur_snap != NULL) {
14047 semerr(emsg_cant_modify_snapshots);
14048 return;
14049 }
14050
14051 if (cur_inst == NULL && cur_svc == NULL) {
14052 semerr(emsg_entity_not_selected);
14053 return;
14054 }
14055
14056 pg = scf_pg_create(g_hndl);
14057 if (pg == NULL)
14058 scfdie();
14059
14060 slash = strchr(pgn, '/');
14061 if (slash == NULL) {
14062 pn = NULL;
14063 } else {
14064 *slash = '\0';
14065 pn = slash + 1;
14066 }
14067
14068 if (cur_inst != NULL)
14069 ret = scf_instance_get_pg(cur_inst, pgn, pg);
14070 else
14071 ret = scf_service_get_pg(cur_svc, pgn, pg);
14072 if (ret != SCF_SUCCESS) {
14073 switch (scf_error()) {
14074 case SCF_ERROR_NOT_FOUND:
14075 semerr(emsg_no_such_pg, pgn);
14076 break;
14077
14078 case SCF_ERROR_INVALID_ARGUMENT:
14079 semerr(emsg_invalid_pg_name, pgn);
14080 break;
14081
14082 default:
14083 scfdie();
14084 }
14085
14086 scf_pg_destroy(pg);
14087
14088 return;
14089 }
14090
14091 if (pn == NULL) {
14092 /* Try to delete the property group. */
14093 if (scf_pg_delete(pg) != SCF_SUCCESS) {
14094 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14095 scfdie();
14096
14097 semerr(emsg_permission_denied);
14098 } else {
14099 private_refresh();
14100 }
14101
14102 scf_pg_destroy(pg);
14103 return;
14104 }
14105
14106 e = scf_entry_create(g_hndl);
14107 tx = scf_transaction_create(g_hndl);
14108
14109 do {
14110 if (scf_pg_update(pg) == -1)
14111 scfdie();
14112 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
14113 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14114 scfdie();
14115
14116 semerr(emsg_permission_denied);
14117 break;
14118 }
14119
14120 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
14121 if (scf_error() == SCF_ERROR_NOT_FOUND) {
14122 semerr(gettext("No such property %s/%s.\n"),
14123 pgn, pn);
14124 break;
14125 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14126 semerr(emsg_invalid_prop_name, pn);
14127 break;
14128 } else {
14129 scfdie();
14130 }
14131 }
14132
14133 ret = scf_transaction_commit(tx);
14134
14135 if (ret == 0)
14136 scf_transaction_reset(tx);
14137 } while (ret == 0);
14138
14139 if (ret < 0) {
14140 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14141 scfdie();
14142
14143 semerr(emsg_permission_denied);
14144 } else {
14145 private_refresh();
14146 }
14147
14148 scf_transaction_destroy(tx);
14149 scf_entry_destroy(e);
14150 scf_pg_destroy(pg);
14151 }
14152
14153 /*
14154 * Property editing.
14155 */
14156
14157 static int
14158 write_edit_script(FILE *strm)
14159 {
14160 char *fmribuf;
14161 ssize_t fmrilen;
14162
14163 scf_propertygroup_t *pg;
14164 scf_property_t *prop;
14165 scf_value_t *val;
14166 scf_type_t ty;
14167 int ret, result = 0;
14168 scf_iter_t *iter, *piter, *viter;
14169 char *buf, *tybuf, *pname;
14170 const char *emsg_write_error;
14171
14172
14173 emsg_write_error = gettext("Error writing temoprary file: %s.\n");
14174
14175
14176 /* select fmri */
14177 if (cur_inst != NULL) {
14178 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
14179 if (fmrilen < 0)
14180 scfdie();
14181 fmribuf = safe_malloc(fmrilen + 1);
14182 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
14183 scfdie();
14184 } else {
14185 assert(cur_svc != NULL);
14186 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
14187 if (fmrilen < 0)
14188 scfdie();
14189 fmribuf = safe_malloc(fmrilen + 1);
14190 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
14191 scfdie();
14192 }
14193
14194 if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
14195 warn(emsg_write_error, strerror(errno));
14196 free(fmribuf);
14197 return (-1);
14198 }
14199
14200 free(fmribuf);
14201
14202
14203 if ((pg = scf_pg_create(g_hndl)) == NULL ||
14204 (prop = scf_property_create(g_hndl)) == NULL ||
14205 (val = scf_value_create(g_hndl)) == NULL ||
14206 (iter = scf_iter_create(g_hndl)) == NULL ||
14207 (piter = scf_iter_create(g_hndl)) == NULL ||
14208 (viter = scf_iter_create(g_hndl)) == NULL)
14209 scfdie();
14210
14211 buf = safe_malloc(max_scf_name_len + 1);
14212 tybuf = safe_malloc(max_scf_pg_type_len + 1);
14213 pname = safe_malloc(max_scf_name_len + 1);
14214
14215 if (cur_inst != NULL)
14216 ret = scf_iter_instance_pgs(iter, cur_inst);
14217 else
14218 ret = scf_iter_service_pgs(iter, cur_svc);
14219 if (ret != SCF_SUCCESS)
14220 scfdie();
14221
14222 while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
14223 int ret2;
14224
14225 /*
14226 * # delprop pg
14227 * # addpg pg type
14228 */
14229 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
14230 scfdie();
14231
14232 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
14233 scfdie();
14234
14235 if (fprintf(strm, "# Property group \"%s\"\n"
14236 "# delprop %s\n"
14237 "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
14238 warn(emsg_write_error, strerror(errno));
14239 result = -1;
14240 goto out;
14241 }
14242
14243 /* # setprop pg/prop = (values) */
14244
14245 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
14246 scfdie();
14247
14248 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
14249 int first = 1;
14250 int ret3;
14251 int multiple;
14252 int is_str;
14253 scf_type_t bty;
14254
14255 if (scf_property_get_name(prop, pname,
14256 max_scf_name_len + 1) < 0)
14257 scfdie();
14258
14259 if (scf_property_type(prop, &ty) != 0)
14260 scfdie();
14261
14262 multiple = prop_has_multiple_values(prop, val);
14263
14264 if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
14265 pname, scf_type_to_string(ty), multiple ? "(" : "")
14266 < 0) {
14267 warn(emsg_write_error, strerror(errno));
14268 result = -1;
14269 goto out;
14270 }
14271
14272 (void) scf_type_base_type(ty, &bty);
14273 is_str = (bty == SCF_TYPE_ASTRING);
14274
14275 if (scf_iter_property_values(viter, prop) !=
14276 SCF_SUCCESS)
14277 scfdie();
14278
14279 while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
14280 char *buf;
14281 ssize_t buflen;
14282
14283 buflen = scf_value_get_as_string(val, NULL, 0);
14284 if (buflen < 0)
14285 scfdie();
14286
14287 buf = safe_malloc(buflen + 1);
14288
14289 if (scf_value_get_as_string(val, buf,
14290 buflen + 1) < 0)
14291 scfdie();
14292
14293 if (first)
14294 first = 0;
14295 else {
14296 if (putc(' ', strm) != ' ') {
14297 warn(emsg_write_error,
14298 strerror(errno));
14299 result = -1;
14300 goto out;
14301 }
14302 }
14303
14304 if ((is_str && multiple) ||
14305 strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
14306 (void) putc('"', strm);
14307 (void) quote_and_print(buf, strm, 1);
14308 (void) putc('"', strm);
14309
14310 if (ferror(strm)) {
14311 warn(emsg_write_error,
14312 strerror(errno));
14313 result = -1;
14314 goto out;
14315 }
14316 } else {
14317 if (fprintf(strm, "%s", buf) < 0) {
14318 warn(emsg_write_error,
14319 strerror(errno));
14320 result = -1;
14321 goto out;
14322 }
14323 }
14324
14325 free(buf);
14326 }
14327 if (ret3 < 0 &&
14328 scf_error() != SCF_ERROR_PERMISSION_DENIED)
14329 scfdie();
14330
14331 /* Write closing paren if mult-value property */
14332 if ((multiple && putc(')', strm) == EOF) ||
14333
14334 /* Write final newline */
14335 fputc('\n', strm) == EOF) {
14336 warn(emsg_write_error, strerror(errno));
14337 result = -1;
14338 goto out;
14339 }
14340 }
14341 if (ret2 < 0)
14342 scfdie();
14343
14344 if (fputc('\n', strm) == EOF) {
14345 warn(emsg_write_error, strerror(errno));
14346 result = -1;
14347 goto out;
14348 }
14349 }
14350 if (ret < 0)
14351 scfdie();
14352
14353 out:
14354 free(pname);
14355 free(tybuf);
14356 free(buf);
14357 scf_iter_destroy(viter);
14358 scf_iter_destroy(piter);
14359 scf_iter_destroy(iter);
14360 scf_value_destroy(val);
14361 scf_property_destroy(prop);
14362 scf_pg_destroy(pg);
14363
14364 if (result == 0) {
14365 if (fflush(strm) != 0) {
14366 warn(emsg_write_error, strerror(errno));
14367 return (-1);
14368 }
14369 }
14370
14371 return (result);
14372 }
14373
14374 int
14375 lscf_editprop()
14376 {
14377 char *buf, *editor;
14378 size_t bufsz;
14379 int tmpfd;
14380 char tempname[] = TEMP_FILE_PATTERN;
14381
14382 lscf_prep_hndl();
14383
14384 if (cur_snap != NULL) {
14385 semerr(emsg_cant_modify_snapshots);
14386 return (-1);
14387 }
14388
14389 if (cur_svc == NULL && cur_inst == NULL) {
14390 semerr(emsg_entity_not_selected);
14391 return (-1);
14392 }
14393
14394 tmpfd = mkstemp(tempname);
14395 if (tmpfd == -1) {
14396 semerr(gettext("Could not create temporary file.\n"));
14397 return (-1);
14398 }
14399
14400 (void) strcpy(tempfilename, tempname);
14401
14402 tempfile = fdopen(tmpfd, "r+");
14403 if (tempfile == NULL) {
14404 warn(gettext("Could not create temporary file.\n"));
14405 if (close(tmpfd) == -1)
14406 warn(gettext("Could not close temporary file: %s.\n"),
14407 strerror(errno));
14408
14409 remove_tempfile();
14410
14411 return (-1);
14412 }
14413
14414 if (write_edit_script(tempfile) == -1) {
14415 remove_tempfile();
14416 return (-1);
14417 }
14418
14419 editor = getenv("EDITOR");
14420 if (editor == NULL)
14421 editor = "vi";
14422
14423 bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
14424 buf = safe_malloc(bufsz);
14425
14426 if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
14427 uu_die(gettext("Error creating editor command"));
14428
14429 if (system(buf) == -1) {
14430 semerr(gettext("Could not launch editor %s: %s\n"), editor,
14431 strerror(errno));
14432 free(buf);
14433 remove_tempfile();
14434 return (-1);
14435 }
14436
14437 free(buf);
14438
14439 (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
14440
14441 remove_tempfile();
14442
14443 return (0);
14444 }
14445
14446 static void
14447 add_string(uu_list_t *strlist, const char *str)
14448 {
14449 string_list_t *elem;
14450 elem = safe_malloc(sizeof (*elem));
14451 uu_list_node_init(elem, &elem->node, string_pool);
14452 elem->str = safe_strdup(str);
14453 if (uu_list_append(strlist, elem) != 0)
14454 uu_die(gettext("libuutil error: %s\n"),
14455 uu_strerror(uu_error()));
14456 }
14457
14458 static int
14459 remove_string(uu_list_t *strlist, const char *str)
14460 {
14461 uu_list_walk_t *elems;
14462 string_list_t *sp;
14463
14464 /*
14465 * Find the element that needs to be removed.
14466 */
14467 elems = uu_list_walk_start(strlist, UU_DEFAULT);
14468 while ((sp = uu_list_walk_next(elems)) != NULL) {
14469 if (strcmp(sp->str, str) == 0)
14470 break;
14471 }
14472 uu_list_walk_end(elems);
14473
14474 /*
14475 * Returning 1 here as the value was not found, this
14476 * might not be an error. Leave it to the caller to
14477 * decide.
14478 */
14479 if (sp == NULL) {
14480 return (1);
14481 }
14482
14483 uu_list_remove(strlist, sp);
14484
14485 free(sp->str);
14486 free(sp);
14487
14488 return (0);
14489 }
14490
14491 /*
14492 * Get all property values that don't match the given glob pattern,
14493 * if a pattern is specified.
14494 */
14495 static void
14496 get_prop_values(scf_property_t *prop, uu_list_t *values,
14497 const char *pattern)
14498 {
14499 scf_iter_t *iter;
14500 scf_value_t *val;
14501 int ret;
14502
14503 if ((iter = scf_iter_create(g_hndl)) == NULL ||
14504 (val = scf_value_create(g_hndl)) == NULL)
14505 scfdie();
14506
14507 if (scf_iter_property_values(iter, prop) != 0)
14508 scfdie();
14509
14510 while ((ret = scf_iter_next_value(iter, val)) == 1) {
14511 char *buf;
14512 ssize_t vlen, szret;
14513
14514 vlen = scf_value_get_as_string(val, NULL, 0);
14515 if (vlen < 0)
14516 scfdie();
14517
14518 buf = safe_malloc(vlen + 1);
14519
14520 szret = scf_value_get_as_string(val, buf, vlen + 1);
14521 if (szret < 0)
14522 scfdie();
14523 assert(szret <= vlen);
14524
14525 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14526 add_string(values, buf);
14527
14528 free(buf);
14529 }
14530
14531 if (ret == -1)
14532 scfdie();
14533
14534 scf_value_destroy(val);
14535 scf_iter_destroy(iter);
14536 }
14537
14538 static int
14539 lscf_setpropvalue(const char *pgname, const char *type,
14540 const char *arg, int isadd, int isnotfoundok)
14541 {
14542 scf_type_t ty;
14543 scf_propertygroup_t *pg;
14544 scf_property_t *prop;
14545 int ret, result = 0;
14546 scf_transaction_t *tx;
14547 scf_transaction_entry_t *e;
14548 scf_value_t *v;
14549 string_list_t *sp;
14550 char *propname;
14551 uu_list_t *values;
14552 uu_list_walk_t *walk;
14553 void *cookie = NULL;
14554 char *pattern = NULL;
14555
14556 lscf_prep_hndl();
14557
14558 if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14559 uu_die(gettext("Could not create property list: %s\n"),
14560 uu_strerror(uu_error()));
14561
14562 if (!isadd)
14563 pattern = safe_strdup(arg);
14564
14565 if ((e = scf_entry_create(g_hndl)) == NULL ||
14566 (pg = scf_pg_create(g_hndl)) == NULL ||
14567 (prop = scf_property_create(g_hndl)) == NULL ||
14568 (tx = scf_transaction_create(g_hndl)) == NULL)
14569 scfdie();
14570
14571 if (cur_snap != NULL) {
14572 semerr(emsg_cant_modify_snapshots);
14573 goto fail;
14574 }
14575
14576 if (cur_inst == NULL && cur_svc == NULL) {
14577 semerr(emsg_entity_not_selected);
14578 goto fail;
14579 }
14580
14581 propname = strchr(pgname, '/');
14582 if (propname == NULL) {
14583 semerr(gettext("Property names must contain a `/'.\n"));
14584 goto fail;
14585 }
14586
14587 *propname = '\0';
14588 ++propname;
14589
14590 if (type != NULL) {
14591 ty = string_to_type(type);
14592 if (ty == SCF_TYPE_INVALID) {
14593 semerr(gettext("Unknown type \"%s\".\n"), type);
14594 goto fail;
14595 }
14596 }
14597
14598 if (cur_inst != NULL)
14599 ret = scf_instance_get_pg(cur_inst, pgname, pg);
14600 else
14601 ret = scf_service_get_pg(cur_svc, pgname, pg);
14602 if (ret != 0) {
14603 switch (scf_error()) {
14604 case SCF_ERROR_NOT_FOUND:
14605 if (isnotfoundok) {
14606 result = 0;
14607 } else {
14608 semerr(emsg_no_such_pg, pgname);
14609 result = -1;
14610 }
14611 goto out;
14612
14613 case SCF_ERROR_INVALID_ARGUMENT:
14614 semerr(emsg_invalid_pg_name, pgname);
14615 goto fail;
14616
14617 default:
14618 scfdie();
14619 }
14620 }
14621
14622 do {
14623 if (scf_pg_update(pg) == -1)
14624 scfdie();
14625 if (scf_transaction_start(tx, pg) != 0) {
14626 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14627 scfdie();
14628
14629 semerr(emsg_permission_denied);
14630 goto fail;
14631 }
14632
14633 ret = scf_pg_get_property(pg, propname, prop);
14634 if (ret == 0) {
14635 scf_type_t ptype;
14636 char *pat = pattern;
14637
14638 if (scf_property_type(prop, &ptype) != 0)
14639 scfdie();
14640
14641 if (isadd) {
14642 if (type != NULL && ptype != ty) {
14643 semerr(gettext("Property \"%s\" is not "
14644 "of type \"%s\".\n"), propname,
14645 type);
14646 goto fail;
14647 }
14648
14649 pat = NULL;
14650 } else {
14651 size_t len = strlen(pat);
14652 if (len > 0 && pat[len - 1] == '\"')
14653 pat[len - 1] = '\0';
14654 if (len > 0 && pat[0] == '\"')
14655 pat++;
14656 }
14657
14658 ty = ptype;
14659
14660 get_prop_values(prop, values, pat);
14661
14662 if (isadd)
14663 add_string(values, arg);
14664
14665 if (scf_transaction_property_change(tx, e,
14666 propname, ty) == -1)
14667 scfdie();
14668 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14669 if (isadd) {
14670 if (type == NULL) {
14671 semerr(gettext("Type required "
14672 "for new properties.\n"));
14673 goto fail;
14674 }
14675
14676 add_string(values, arg);
14677
14678 if (scf_transaction_property_new(tx, e,
14679 propname, ty) == -1)
14680 scfdie();
14681 } else if (isnotfoundok) {
14682 result = 0;
14683 goto out;
14684 } else {
14685 semerr(gettext("No such property %s/%s.\n"),
14686 pgname, propname);
14687 result = -1;
14688 goto out;
14689 }
14690 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14691 semerr(emsg_invalid_prop_name, propname);
14692 goto fail;
14693 } else {
14694 scfdie();
14695 }
14696
14697 walk = uu_list_walk_start(values, UU_DEFAULT);
14698 if (walk == NULL)
14699 uu_die(gettext("Could not walk property list.\n"));
14700
14701 for (sp = uu_list_walk_next(walk); sp != NULL;
14702 sp = uu_list_walk_next(walk)) {
14703 v = string_to_value(sp->str, ty, 0);
14704
14705 if (v == NULL) {
14706 scf_entry_destroy_children(e);
14707 goto fail;
14708 }
14709 ret = scf_entry_add_value(e, v);
14710 assert(ret == 0);
14711 }
14712 uu_list_walk_end(walk);
14713
14714 result = scf_transaction_commit(tx);
14715
14716 scf_transaction_reset(tx);
14717 scf_entry_destroy_children(e);
14718 } while (result == 0);
14719
14720 if (result < 0) {
14721 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14722 scfdie();
14723
14724 semerr(emsg_permission_denied);
14725 goto fail;
14726 }
14727
14728 result = 0;
14729
14730 private_refresh();
14731
14732 out:
14733 scf_transaction_destroy(tx);
14734 scf_entry_destroy(e);
14735 scf_pg_destroy(pg);
14736 scf_property_destroy(prop);
14737 free(pattern);
14738
14739 while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14740 free(sp->str);
14741 free(sp);
14742 }
14743
14744 uu_list_destroy(values);
14745
14746 return (result);
14747
14748 fail:
14749 result = -1;
14750 goto out;
14751 }
14752
14753 int
14754 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14755 {
14756 return (lscf_setpropvalue(pgname, type, value, 1, 0));
14757 }
14758
14759 int
14760 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14761 {
14762 return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14763 }
14764
14765 /*
14766 * Look for a standard start method, first in the instance (if any),
14767 * then the service.
14768 */
14769 static const char *
14770 start_method_name(int *in_instance)
14771 {
14772 scf_propertygroup_t *pg;
14773 char **p;
14774 int ret;
14775 scf_instance_t *inst = cur_inst;
14776
14777 if ((pg = scf_pg_create(g_hndl)) == NULL)
14778 scfdie();
14779
14780 again:
14781 for (p = start_method_names; *p != NULL; p++) {
14782 if (inst != NULL)
14783 ret = scf_instance_get_pg(inst, *p, pg);
14784 else
14785 ret = scf_service_get_pg(cur_svc, *p, pg);
14786
14787 if (ret == 0) {
14788 size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14789 char *buf = safe_malloc(bufsz);
14790
14791 if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14792 free(buf);
14793 continue;
14794 }
14795 if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14796 free(buf);
14797 continue;
14798 }
14799
14800 free(buf);
14801 *in_instance = (inst != NULL);
14802 scf_pg_destroy(pg);
14803 return (*p);
14804 }
14805
14806 if (scf_error() == SCF_ERROR_NOT_FOUND)
14807 continue;
14808
14809 scfdie();
14810 }
14811
14812 if (inst != NULL) {
14813 inst = NULL;
14814 goto again;
14815 }
14816
14817 scf_pg_destroy(pg);
14818 return (NULL);
14819 }
14820
14821 static int
14822 addpg(const char *name, const char *type)
14823 {
14824 scf_propertygroup_t *pg;
14825 int ret;
14826
14827 pg = scf_pg_create(g_hndl);
14828 if (pg == NULL)
14829 scfdie();
14830
14831 if (cur_inst != NULL)
14832 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14833 else
14834 ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14835
14836 if (ret != 0) {
14837 switch (scf_error()) {
14838 case SCF_ERROR_EXISTS:
14839 ret = 0;
14840 break;
14841
14842 case SCF_ERROR_PERMISSION_DENIED:
14843 semerr(emsg_permission_denied);
14844 break;
14845
14846 default:
14847 scfdie();
14848 }
14849 }
14850
14851 scf_pg_destroy(pg);
14852 return (ret);
14853 }
14854
14855 int
14856 lscf_setenv(uu_list_t *args, int isunset)
14857 {
14858 int ret = 0;
14859 size_t i;
14860 int argc;
14861 char **argv = NULL;
14862 string_list_t *slp;
14863 char *pattern;
14864 char *prop;
14865 int do_service = 0;
14866 int do_instance = 0;
14867 const char *method = NULL;
14868 const char *name = NULL;
14869 const char *value = NULL;
14870 scf_instance_t *saved_cur_inst = cur_inst;
14871
14872 lscf_prep_hndl();
14873
14874 argc = uu_list_numnodes(args);
14875 if (argc < 1)
14876 goto usage;
14877
14878 argv = calloc(argc + 1, sizeof (char *));
14879 if (argv == NULL)
14880 uu_die(gettext("Out of memory.\n"));
14881
14882 for (slp = uu_list_first(args), i = 0;
14883 slp != NULL;
14884 slp = uu_list_next(args, slp), ++i)
14885 argv[i] = slp->str;
14886
14887 argv[i] = NULL;
14888
14889 opterr = 0;
14890 optind = 0;
14891 for (;;) {
14892 ret = getopt(argc, argv, "sim:");
14893 if (ret == -1)
14894 break;
14895
14896 switch (ret) {
14897 case 's':
14898 do_service = 1;
14899 cur_inst = NULL;
14900 break;
14901
14902 case 'i':
14903 do_instance = 1;
14904 break;
14905
14906 case 'm':
14907 method = optarg;
14908 break;
14909
14910 case '?':
14911 goto usage;
14912
14913 default:
14914 bad_error("getopt", ret);
14915 }
14916 }
14917
14918 argc -= optind;
14919 if ((do_service && do_instance) ||
14920 (isunset && argc != 1) ||
14921 (!isunset && argc != 2))
14922 goto usage;
14923
14924 name = argv[optind];
14925 if (!isunset)
14926 value = argv[optind + 1];
14927
14928 if (cur_snap != NULL) {
14929 semerr(emsg_cant_modify_snapshots);
14930 ret = -1;
14931 goto out;
14932 }
14933
14934 if (cur_inst == NULL && cur_svc == NULL) {
14935 semerr(emsg_entity_not_selected);
14936 ret = -1;
14937 goto out;
14938 }
14939
14940 if (do_instance && cur_inst == NULL) {
14941 semerr(gettext("No instance is selected.\n"));
14942 ret = -1;
14943 goto out;
14944 }
14945
14946 if (do_service && cur_svc == NULL) {
14947 semerr(gettext("No service is selected.\n"));
14948 ret = -1;
14949 goto out;
14950 }
14951
14952 if (method == NULL) {
14953 if (do_instance || do_service) {
14954 method = "method_context";
14955 if (!isunset) {
14956 ret = addpg("method_context",
14957 SCF_GROUP_FRAMEWORK);
14958 if (ret != 0)
14959 goto out;
14960 }
14961 } else {
14962 int in_instance;
14963 method = start_method_name(&in_instance);
14964 if (method == NULL) {
14965 semerr(gettext(
14966 "Couldn't find start method; please "
14967 "specify a method with '-m'.\n"));
14968 ret = -1;
14969 goto out;
14970 }
14971 if (!in_instance)
14972 cur_inst = NULL;
14973 }
14974 } else {
14975 scf_propertygroup_t *pg;
14976 size_t bufsz;
14977 char *buf;
14978 int ret;
14979
14980 if ((pg = scf_pg_create(g_hndl)) == NULL)
14981 scfdie();
14982
14983 if (cur_inst != NULL)
14984 ret = scf_instance_get_pg(cur_inst, method, pg);
14985 else
14986 ret = scf_service_get_pg(cur_svc, method, pg);
14987
14988 if (ret != 0) {
14989 scf_pg_destroy(pg);
14990 switch (scf_error()) {
14991 case SCF_ERROR_NOT_FOUND:
14992 semerr(gettext("Couldn't find the method "
14993 "\"%s\".\n"), method);
14994 goto out;
14995
14996 case SCF_ERROR_INVALID_ARGUMENT:
14997 semerr(gettext("Invalid method name \"%s\".\n"),
14998 method);
14999 goto out;
15000
15001 default:
15002 scfdie();
15003 }
15004 }
15005
15006 bufsz = strlen(SCF_GROUP_METHOD) + 1;
15007 buf = safe_malloc(bufsz);
15008
15009 if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
15010 strcmp(buf, SCF_GROUP_METHOD) != 0) {
15011 semerr(gettext("Property group \"%s\" is not of type "
15012 "\"method\".\n"), method);
15013 ret = -1;
15014 free(buf);
15015 scf_pg_destroy(pg);
15016 goto out;
15017 }
15018
15019 free(buf);
15020 scf_pg_destroy(pg);
15021 }
15022
15023 prop = uu_msprintf("%s/environment", method);
15024 pattern = uu_msprintf("%s=*", name);
15025
15026 if (prop == NULL || pattern == NULL)
15027 uu_die(gettext("Out of memory.\n"));
15028
15029 ret = lscf_delpropvalue(prop, pattern, !isunset);
15030
15031 if (ret == 0 && !isunset) {
15032 uu_free(pattern);
15033 uu_free(prop);
15034 prop = uu_msprintf("%s/environment", method);
15035 pattern = uu_msprintf("%s=%s", name, value);
15036 if (prop == NULL || pattern == NULL)
15037 uu_die(gettext("Out of memory.\n"));
15038 ret = lscf_addpropvalue(prop, "astring:", pattern);
15039 }
15040 uu_free(pattern);
15041 uu_free(prop);
15042
15043 out:
15044 cur_inst = saved_cur_inst;
15045
15046 free(argv);
15047 return (ret);
15048 usage:
15049 ret = -2;
15050 goto out;
15051 }
15052
15053 /*
15054 * Snapshot commands
15055 */
15056
15057 void
15058 lscf_listsnap()
15059 {
15060 scf_snapshot_t *snap;
15061 scf_iter_t *iter;
15062 char *nb;
15063 int r;
15064
15065 lscf_prep_hndl();
15066
15067 if (cur_inst == NULL) {
15068 semerr(gettext("Instance not selected.\n"));
15069 return;
15070 }
15071
15072 if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15073 (iter = scf_iter_create(g_hndl)) == NULL)
15074 scfdie();
15075
15076 if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
15077 scfdie();
15078
15079 nb = safe_malloc(max_scf_name_len + 1);
15080
15081 while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
15082 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
15083 scfdie();
15084
15085 (void) puts(nb);
15086 }
15087 if (r < 0)
15088 scfdie();
15089
15090 free(nb);
15091 scf_iter_destroy(iter);
15092 scf_snapshot_destroy(snap);
15093 }
15094
15095 void
15096 lscf_selectsnap(const char *name)
15097 {
15098 scf_snapshot_t *snap;
15099 scf_snaplevel_t *level;
15100
15101 lscf_prep_hndl();
15102
15103 if (cur_inst == NULL) {
15104 semerr(gettext("Instance not selected.\n"));
15105 return;
15106 }
15107
15108 if (cur_snap != NULL) {
15109 if (name != NULL) {
15110 char *cur_snap_name;
15111 boolean_t nochange;
15112
15113 cur_snap_name = safe_malloc(max_scf_name_len + 1);
15114
15115 if (scf_snapshot_get_name(cur_snap, cur_snap_name,
15116 max_scf_name_len + 1) < 0)
15117 scfdie();
15118
15119 nochange = strcmp(name, cur_snap_name) == 0;
15120
15121 free(cur_snap_name);
15122
15123 if (nochange)
15124 return;
15125 }
15126
15127 unselect_cursnap();
15128 }
15129
15130 if (name == NULL)
15131 return;
15132
15133 if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15134 (level = scf_snaplevel_create(g_hndl)) == NULL)
15135 scfdie();
15136
15137 if (scf_instance_get_snapshot(cur_inst, name, snap) !=
15138 SCF_SUCCESS) {
15139 switch (scf_error()) {
15140 case SCF_ERROR_INVALID_ARGUMENT:
15141 semerr(gettext("Invalid name \"%s\".\n"), name);
15142 break;
15143
15144 case SCF_ERROR_NOT_FOUND:
15145 semerr(gettext("No such snapshot \"%s\".\n"), name);
15146 break;
15147
15148 default:
15149 scfdie();
15150 }
15151
15152 scf_snaplevel_destroy(level);
15153 scf_snapshot_destroy(snap);
15154 return;
15155 }
15156
15157 /* Load the snaplevels into our list. */
15158 cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
15159 if (cur_levels == NULL)
15160 uu_die(gettext("Could not create list: %s\n"),
15161 uu_strerror(uu_error()));
15162
15163 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15164 if (scf_error() != SCF_ERROR_NOT_FOUND)
15165 scfdie();
15166
15167 semerr(gettext("Snapshot has no snaplevels.\n"));
15168
15169 scf_snaplevel_destroy(level);
15170 scf_snapshot_destroy(snap);
15171 return;
15172 }
15173
15174 cur_snap = snap;
15175
15176 for (;;) {
15177 cur_elt = safe_malloc(sizeof (*cur_elt));
15178 uu_list_node_init(cur_elt, &cur_elt->list_node,
15179 snaplevel_pool);
15180 cur_elt->sl = level;
15181 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
15182 uu_die(gettext("libuutil error: %s\n"),
15183 uu_strerror(uu_error()));
15184
15185 level = scf_snaplevel_create(g_hndl);
15186 if (level == NULL)
15187 scfdie();
15188
15189 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
15190 level) != SCF_SUCCESS) {
15191 if (scf_error() != SCF_ERROR_NOT_FOUND)
15192 scfdie();
15193
15194 scf_snaplevel_destroy(level);
15195 break;
15196 }
15197 }
15198
15199 cur_elt = uu_list_last(cur_levels);
15200 cur_level = cur_elt->sl;
15201 }
15202
15203 /*
15204 * Copies the properties & values in src to dst. Assumes src won't change.
15205 * Returns -1 if permission is denied, -2 if another transaction interrupts,
15206 * and 0 on success.
15207 *
15208 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
15209 * property, if it is copied and has type boolean. (See comment in
15210 * lscf_revert()).
15211 */
15212 static int
15213 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
15214 uint8_t enabled)
15215 {
15216 scf_transaction_t *tx;
15217 scf_iter_t *iter, *viter;
15218 scf_property_t *prop;
15219 scf_value_t *v;
15220 char *nbuf;
15221 int r;
15222
15223 tx = scf_transaction_create(g_hndl);
15224 if (tx == NULL)
15225 scfdie();
15226
15227 if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
15228 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15229 scfdie();
15230
15231 scf_transaction_destroy(tx);
15232
15233 return (-1);
15234 }
15235
15236 if ((iter = scf_iter_create(g_hndl)) == NULL ||
15237 (prop = scf_property_create(g_hndl)) == NULL ||
15238 (viter = scf_iter_create(g_hndl)) == NULL)
15239 scfdie();
15240
15241 nbuf = safe_malloc(max_scf_name_len + 1);
15242
15243 if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
15244 scfdie();
15245
15246 for (;;) {
15247 scf_transaction_entry_t *e;
15248 scf_type_t ty;
15249
15250 r = scf_iter_next_property(iter, prop);
15251 if (r == -1)
15252 scfdie();
15253 if (r == 0)
15254 break;
15255
15256 e = scf_entry_create(g_hndl);
15257 if (e == NULL)
15258 scfdie();
15259
15260 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
15261 scfdie();
15262
15263 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
15264 scfdie();
15265
15266 if (scf_transaction_property_new(tx, e, nbuf,
15267 ty) != SCF_SUCCESS)
15268 scfdie();
15269
15270 if ((enabled == 0 || enabled == 1) &&
15271 strcmp(nbuf, scf_property_enabled) == 0 &&
15272 ty == SCF_TYPE_BOOLEAN) {
15273 v = scf_value_create(g_hndl);
15274 if (v == NULL)
15275 scfdie();
15276
15277 scf_value_set_boolean(v, enabled);
15278
15279 if (scf_entry_add_value(e, v) != 0)
15280 scfdie();
15281 } else {
15282 if (scf_iter_property_values(viter, prop) != 0)
15283 scfdie();
15284
15285 for (;;) {
15286 v = scf_value_create(g_hndl);
15287 if (v == NULL)
15288 scfdie();
15289
15290 r = scf_iter_next_value(viter, v);
15291 if (r == -1)
15292 scfdie();
15293 if (r == 0) {
15294 scf_value_destroy(v);
15295 break;
15296 }
15297
15298 if (scf_entry_add_value(e, v) != SCF_SUCCESS)
15299 scfdie();
15300 }
15301 }
15302 }
15303
15304 free(nbuf);
15305 scf_iter_destroy(viter);
15306 scf_property_destroy(prop);
15307 scf_iter_destroy(iter);
15308
15309 r = scf_transaction_commit(tx);
15310 if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
15311 scfdie();
15312
15313 scf_transaction_destroy_children(tx);
15314 scf_transaction_destroy(tx);
15315
15316 switch (r) {
15317 case 1: return (0);
15318 case 0: return (-2);
15319 case -1: return (-1);
15320
15321 default:
15322 abort();
15323 }
15324
15325 /* NOTREACHED */
15326 }
15327
15328 void
15329 lscf_revert(const char *snapname)
15330 {
15331 scf_snapshot_t *snap, *prev;
15332 scf_snaplevel_t *level, *nlevel;
15333 scf_iter_t *iter;
15334 scf_propertygroup_t *pg, *npg;
15335 scf_property_t *prop;
15336 scf_value_t *val;
15337 char *nbuf, *tbuf;
15338 uint8_t enabled;
15339
15340 lscf_prep_hndl();
15341
15342 if (cur_inst == NULL) {
15343 semerr(gettext("Instance not selected.\n"));
15344 return;
15345 }
15346
15347 if (snapname != NULL) {
15348 snap = scf_snapshot_create(g_hndl);
15349 if (snap == NULL)
15350 scfdie();
15351
15352 if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
15353 SCF_SUCCESS) {
15354 switch (scf_error()) {
15355 case SCF_ERROR_INVALID_ARGUMENT:
15356 semerr(gettext("Invalid snapshot name "
15357 "\"%s\".\n"), snapname);
15358 break;
15359
15360 case SCF_ERROR_NOT_FOUND:
15361 semerr(gettext("No such snapshot.\n"));
15362 break;
15363
15364 default:
15365 scfdie();
15366 }
15367
15368 scf_snapshot_destroy(snap);
15369 return;
15370 }
15371 } else {
15372 if (cur_snap != NULL) {
15373 snap = cur_snap;
15374 } else {
15375 semerr(gettext("No snapshot selected.\n"));
15376 return;
15377 }
15378 }
15379
15380 if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
15381 (level = scf_snaplevel_create(g_hndl)) == NULL ||
15382 (iter = scf_iter_create(g_hndl)) == NULL ||
15383 (pg = scf_pg_create(g_hndl)) == NULL ||
15384 (npg = scf_pg_create(g_hndl)) == NULL ||
15385 (prop = scf_property_create(g_hndl)) == NULL ||
15386 (val = scf_value_create(g_hndl)) == NULL)
15387 scfdie();
15388
15389 nbuf = safe_malloc(max_scf_name_len + 1);
15390 tbuf = safe_malloc(max_scf_pg_type_len + 1);
15391
15392 /* Take the "previous" snapshot before we blow away the properties. */
15393 if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
15394 if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
15395 scfdie();
15396 } else {
15397 if (scf_error() != SCF_ERROR_NOT_FOUND)
15398 scfdie();
15399
15400 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
15401 scfdie();
15402 }
15403
15404 /* Save general/enabled, since we're probably going to replace it. */
15405 enabled = 2;
15406 if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
15407 scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
15408 scf_property_get_value(prop, val) == 0)
15409 (void) scf_value_get_boolean(val, &enabled);
15410
15411 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15412 if (scf_error() != SCF_ERROR_NOT_FOUND)
15413 scfdie();
15414
15415 goto out;
15416 }
15417
15418 for (;;) {
15419 boolean_t isinst;
15420 uint32_t flags;
15421 int r;
15422
15423 /* Clear the properties from the corresponding entity. */
15424 isinst = snaplevel_is_instance(level);
15425
15426 if (!isinst)
15427 r = scf_iter_service_pgs(iter, cur_svc);
15428 else
15429 r = scf_iter_instance_pgs(iter, cur_inst);
15430 if (r != SCF_SUCCESS)
15431 scfdie();
15432
15433 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15434 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15435 scfdie();
15436
15437 /* Skip nonpersistent pgs. */
15438 if (flags & SCF_PG_FLAG_NONPERSISTENT)
15439 continue;
15440
15441 if (scf_pg_delete(pg) != SCF_SUCCESS) {
15442 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15443 scfdie();
15444
15445 semerr(emsg_permission_denied);
15446 goto out;
15447 }
15448 }
15449 if (r == -1)
15450 scfdie();
15451
15452 /* Copy the properties to the corresponding entity. */
15453 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
15454 scfdie();
15455
15456 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15457 if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
15458 scfdie();
15459
15460 if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
15461 0)
15462 scfdie();
15463
15464 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15465 scfdie();
15466
15467 if (!isinst)
15468 r = scf_service_add_pg(cur_svc, nbuf, tbuf,
15469 flags, npg);
15470 else
15471 r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
15472 flags, npg);
15473 if (r != SCF_SUCCESS) {
15474 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15475 scfdie();
15476
15477 semerr(emsg_permission_denied);
15478 goto out;
15479 }
15480
15481 if ((enabled == 0 || enabled == 1) &&
15482 strcmp(nbuf, scf_pg_general) == 0)
15483 r = pg_copy(pg, npg, enabled);
15484 else
15485 r = pg_copy(pg, npg, 2);
15486
15487 switch (r) {
15488 case 0:
15489 break;
15490
15491 case -1:
15492 semerr(emsg_permission_denied);
15493 goto out;
15494
15495 case -2:
15496 semerr(gettext(
15497 "Interrupted by another change.\n"));
15498 goto out;
15499
15500 default:
15501 abort();
15502 }
15503 }
15504 if (r == -1)
15505 scfdie();
15506
15507 /* Get next level. */
15508 nlevel = scf_snaplevel_create(g_hndl);
15509 if (nlevel == NULL)
15510 scfdie();
15511
15512 if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
15513 SCF_SUCCESS) {
15514 if (scf_error() != SCF_ERROR_NOT_FOUND)
15515 scfdie();
15516
15517 scf_snaplevel_destroy(nlevel);
15518 break;
15519 }
15520
15521 scf_snaplevel_destroy(level);
15522 level = nlevel;
15523 }
15524
15525 if (snapname == NULL) {
15526 lscf_selectsnap(NULL);
15527 snap = NULL; /* cur_snap has been destroyed */
15528 }
15529
15530 out:
15531 free(tbuf);
15532 free(nbuf);
15533 scf_value_destroy(val);
15534 scf_property_destroy(prop);
15535 scf_pg_destroy(npg);
15536 scf_pg_destroy(pg);
15537 scf_iter_destroy(iter);
15538 scf_snaplevel_destroy(level);
15539 scf_snapshot_destroy(prev);
15540 if (snap != cur_snap)
15541 scf_snapshot_destroy(snap);
15542 }
15543
15544 void
15545 lscf_refresh(void)
15546 {
15547 ssize_t fmrilen;
15548 size_t bufsz;
15549 char *fmribuf;
15550 int r;
15551
15552 lscf_prep_hndl();
15553
15554 if (cur_inst == NULL) {
15555 semerr(gettext("Instance not selected.\n"));
15556 return;
15557 }
15558
15559 bufsz = max_scf_fmri_len + 1;
15560 fmribuf = safe_malloc(bufsz);
15561 fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15562 if (fmrilen < 0) {
15563 free(fmribuf);
15564 if (scf_error() != SCF_ERROR_DELETED)
15565 scfdie();
15566 scf_instance_destroy(cur_inst);
15567 cur_inst = NULL;
15568 warn(emsg_deleted);
15569 return;
15570 }
15571 assert(fmrilen < bufsz);
15572
15573 r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15574 switch (r) {
15575 case 0:
15576 break;
15577
15578 case ECONNABORTED:
15579 warn(gettext("Could not refresh %s "
15580 "(repository connection broken).\n"), fmribuf);
15581 break;
15582
15583 case ECANCELED:
15584 warn(emsg_deleted);
15585 break;
15586
15587 case EPERM:
15588 warn(gettext("Could not refresh %s "
15589 "(permission denied).\n"), fmribuf);
15590 break;
15591
15592 case ENOSPC:
15593 warn(gettext("Could not refresh %s "
15594 "(repository server out of resources).\n"),
15595 fmribuf);
15596 break;
15597
15598 case EACCES:
15599 default:
15600 bad_error("refresh_entity", scf_error());
15601 }
15602
15603 free(fmribuf);
15604 }
15605
15606 /*
15607 * describe [-v] [-t] [pg/prop]
15608 */
15609 int
15610 lscf_describe(uu_list_t *args, int hasargs)
15611 {
15612 int ret = 0;
15613 size_t i;
15614 int argc;
15615 char **argv = NULL;
15616 string_list_t *slp;
15617 int do_verbose = 0;
15618 int do_templates = 0;
15619 char *pattern = NULL;
15620
15621 lscf_prep_hndl();
15622
15623 if (hasargs != 0) {
15624 argc = uu_list_numnodes(args);
15625 if (argc < 1)
15626 goto usage;
15627
15628 argv = calloc(argc + 1, sizeof (char *));
15629 if (argv == NULL)
15630 uu_die(gettext("Out of memory.\n"));
15631
15632 for (slp = uu_list_first(args), i = 0;
15633 slp != NULL;
15634 slp = uu_list_next(args, slp), ++i)
15635 argv[i] = slp->str;
15636
15637 argv[i] = NULL;
15638
15639 /*
15640 * We start optind = 0 because our list of arguments
15641 * starts at argv[0]
15642 */
15643 optind = 0;
15644 opterr = 0;
15645 for (;;) {
15646 ret = getopt(argc, argv, "vt");
15647 if (ret == -1)
15648 break;
15649
15650 switch (ret) {
15651 case 'v':
15652 do_verbose = 1;
15653 break;
15654
15655 case 't':
15656 do_templates = 1;
15657 break;
15658
15659 case '?':
15660 goto usage;
15661
15662 default:
15663 bad_error("getopt", ret);
15664 }
15665 }
15666
15667 pattern = argv[optind];
15668 }
15669
15670 if (cur_inst == NULL && cur_svc == NULL) {
15671 semerr(emsg_entity_not_selected);
15672 ret = -1;
15673 goto out;
15674 }
15675
15676 /*
15677 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15678 * output if their last parameter is set to 2. Less information is
15679 * produced if the parameter is set to 1.
15680 */
15681 if (pattern == NULL) {
15682 if (do_verbose == 1)
15683 list_entity_tmpl(2);
15684 else
15685 list_entity_tmpl(1);
15686 }
15687
15688 if (do_templates == 0) {
15689 if (do_verbose == 1)
15690 listprop(pattern, 0, 2);
15691 else
15692 listprop(pattern, 0, 1);
15693 } else {
15694 if (do_verbose == 1)
15695 listtmpl(pattern, 2);
15696 else
15697 listtmpl(pattern, 1);
15698 }
15699
15700 ret = 0;
15701 out:
15702 if (argv != NULL)
15703 free(argv);
15704 return (ret);
15705 usage:
15706 ret = -2;
15707 goto out;
15708 }
15709
15710 #define PARAM_ACTIVE ((const char *) "active")
15711 #define PARAM_INACTIVE ((const char *) "inactive")
15712 #define PARAM_SMTP_TO ((const char *) "to")
15713
15714 /*
15715 * tokenize()
15716 * Breaks down the string according to the tokens passed.
15717 * Caller is responsible for freeing array of pointers returned.
15718 * Returns NULL on failure
15719 */
15720 char **
15721 tokenize(char *str, const char *sep)
15722 {
15723 char *token, *lasts;
15724 char **buf;
15725 int n = 0; /* number of elements */
15726 int size = 8; /* size of the array (initial) */
15727
15728 buf = safe_malloc(size * sizeof (char *));
15729
15730 for (token = strtok_r(str, sep, &lasts); token != NULL;
15731 token = strtok_r(NULL, sep, &lasts), ++n) {
15732 if (n + 1 >= size) {
15733 size *= 2;
15734 if ((buf = realloc(buf, size * sizeof (char *))) ==
15735 NULL) {
15736 uu_die(gettext("Out of memory"));
15737 }
15738 }
15739 buf[n] = token;
15740 }
15741 /* NULL terminate the pointer array */
15742 buf[n] = NULL;
15743
15744 return (buf);
15745 }
15746
15747 int32_t
15748 check_tokens(char **p)
15749 {
15750 int32_t smf = 0;
15751 int32_t fma = 0;
15752
15753 while (*p) {
15754 int32_t t = string_to_tset(*p);
15755
15756 if (t == 0) {
15757 if (is_fma_token(*p) == 0)
15758 return (INVALID_TOKENS);
15759 fma = 1; /* this token is an fma event */
15760 } else {
15761 smf |= t;
15762 }
15763
15764 if (smf != 0 && fma == 1)
15765 return (MIXED_TOKENS);
15766 ++p;
15767 }
15768
15769 if (smf > 0)
15770 return (smf);
15771 else if (fma == 1)
15772 return (FMA_TOKENS);
15773
15774 return (INVALID_TOKENS);
15775 }
15776
15777 static int
15778 get_selection_str(char *fmri, size_t sz)
15779 {
15780 if (g_hndl == NULL) {
15781 semerr(emsg_entity_not_selected);
15782 return (-1);
15783 } else if (cur_level != NULL) {
15784 semerr(emsg_invalid_for_snapshot);
15785 return (-1);
15786 } else {
15787 lscf_get_selection_str(fmri, sz);
15788 }
15789
15790 return (0);
15791 }
15792
15793 void
15794 lscf_delnotify(const char *set, int global)
15795 {
15796 char *str = strdup(set);
15797 char **pgs;
15798 char **p;
15799 int32_t tset;
15800 char *fmri = NULL;
15801
15802 if (str == NULL)
15803 uu_die(gettext("Out of memory.\n"));
15804
15805 pgs = tokenize(str, ",");
15806
15807 if ((tset = check_tokens(pgs)) > 0) {
15808 size_t sz = max_scf_fmri_len + 1;
15809
15810 fmri = safe_malloc(sz);
15811 if (global) {
15812 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15813 } else if (get_selection_str(fmri, sz) != 0) {
15814 goto out;
15815 }
15816
15817 if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri,
15818 tset) != SCF_SUCCESS) {
15819 uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15820 scf_strerror(scf_error()));
15821 }
15822 } else if (tset == FMA_TOKENS) {
15823 if (global) {
15824 semerr(gettext("Can't use option '-g' with FMA event "
15825 "definitions\n"));
15826 goto out;
15827 }
15828
15829 for (p = pgs; *p; ++p) {
15830 if (smf_notify_del_params(de_tag(*p), NULL, 0) !=
15831 SCF_SUCCESS) {
15832 uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
15833 scf_strerror(scf_error()));
15834 goto out;
15835 }
15836 }
15837 } else if (tset == MIXED_TOKENS) {
15838 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15839 goto out;
15840 } else {
15841 uu_die(gettext("Invalid input.\n"));
15842 }
15843
15844 out:
15845 free(fmri);
15846 free(pgs);
15847 free(str);
15848 }
15849
15850 void
15851 lscf_listnotify(const char *set, int global)
15852 {
15853 char *str = safe_strdup(set);
15854 char **pgs;
15855 char **p;
15856 int32_t tset;
15857 nvlist_t *nvl;
15858 char *fmri = NULL;
15859
15860 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
15861 uu_die(gettext("Out of memory.\n"));
15862
15863 pgs = tokenize(str, ",");
15864
15865 if ((tset = check_tokens(pgs)) > 0) {
15866 size_t sz = max_scf_fmri_len + 1;
15867
15868 fmri = safe_malloc(sz);
15869 if (global) {
15870 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15871 } else if (get_selection_str(fmri, sz) != 0) {
15872 goto out;
15873 }
15874
15875 if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
15876 SCF_SUCCESS) {
15877 if (scf_error() != SCF_ERROR_NOT_FOUND &&
15878 scf_error() != SCF_ERROR_DELETED)
15879 uu_warn(gettext(
15880 "Failed listnotify: %s\n"),
15881 scf_strerror(scf_error()));
15882 goto out;
15883 }
15884
15885 listnotify_print(nvl, NULL);
15886 } else if (tset == FMA_TOKENS) {
15887 if (global) {
15888 semerr(gettext("Can't use option '-g' with FMA event "
15889 "definitions\n"));
15890 goto out;
15891 }
15892
15893 for (p = pgs; *p; ++p) {
15894 if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
15895 SCF_SUCCESS) {
15896 /*
15897 * if the preferences have just been deleted
15898 * or does not exist, just skip.
15899 */
15900 if (scf_error() == SCF_ERROR_NOT_FOUND ||
15901 scf_error() == SCF_ERROR_DELETED)
15902 continue;
15903 uu_warn(gettext(
15904 "Failed listnotify: %s\n"),
15905 scf_strerror(scf_error()));
15906 goto out;
15907 }
15908 listnotify_print(nvl, re_tag(*p));
15909 }
15910 } else if (tset == MIXED_TOKENS) {
15911 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15912 goto out;
15913 } else {
15914 semerr(gettext("Invalid input.\n"));
15915 }
15916
15917 out:
15918 nvlist_free(nvl);
15919 free(fmri);
15920 free(pgs);
15921 free(str);
15922 }
15923
15924 static char *
15925 strip_quotes_and_blanks(char *s)
15926 {
15927 char *start = s;
15928 char *end = strrchr(s, '\"');
15929
15930 if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
15931 start = s + 1;
15932 while (isblank(*start))
15933 start++;
15934 while (isblank(*(end - 1)) && end > start) {
15935 end--;
15936 }
15937 *end = '\0';
15938 }
15939
15940 return (start);
15941 }
15942
15943 static int
15944 set_active(nvlist_t *mech, const char *hier_part)
15945 {
15946 boolean_t b;
15947
15948 if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
15949 b = B_TRUE;
15950 } else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
15951 b = B_FALSE;
15952 } else {
15953 return (-1);
15954 }
15955
15956 if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
15957 uu_die(gettext("Out of memory.\n"));
15958
15959 return (0);
15960 }
15961
15962 static int
15963 add_snmp_params(nvlist_t *mech, char *hier_part)
15964 {
15965 return (set_active(mech, hier_part));
15966 }
15967
15968 static int
15969 add_syslog_params(nvlist_t *mech, char *hier_part)
15970 {
15971 return (set_active(mech, hier_part));
15972 }
15973
15974 /*
15975 * add_mailto_paramas()
15976 * parse the hier_part of mailto URI
15977 * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
15978 * or mailto:{[active]|inactive}
15979 */
15980 static int
15981 add_mailto_params(nvlist_t *mech, char *hier_part)
15982 {
15983 const char *tok = "?&";
15984 char *p;
15985 char *lasts;
15986 char *param;
15987 char *val;
15988
15989 /*
15990 * If the notification parametes are in the form of
15991 *
15992 * malito:{[active]|inactive}
15993 *
15994 * we set the property accordingly and return.
15995 * Otherwise, we make the notification type active and
15996 * process the hier_part.
15997 */
15998 if (set_active(mech, hier_part) == 0)
15999 return (0);
16000 else if (set_active(mech, PARAM_ACTIVE) != 0)
16001 return (-1);
16002
16003 if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) {
16004 /*
16005 * sanity check: we only get here if hier_part = "", but
16006 * that's handled by set_active
16007 */
16008 uu_die("strtok_r");
16009 }
16010
16011 if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0)
16012 uu_die(gettext("Out of memory.\n"));
16013
16014 while ((p = strtok_r(NULL, tok, &lasts)) != NULL)
16015 if ((param = strtok_r(p, "=", &val)) != NULL)
16016 if (nvlist_add_string(mech, param, val) != 0)
16017 uu_die(gettext("Out of memory.\n"));
16018
16019 return (0);
16020 }
16021
16022 static int
16023 uri_split(char *uri, char **scheme, char **hier_part)
16024 {
16025 int r = -1;
16026
16027 if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
16028 *hier_part == NULL) {
16029 semerr(gettext("'%s' is not an URI\n"), uri);
16030 return (r);
16031 }
16032
16033 if ((r = check_uri_scheme(*scheme)) < 0) {
16034 semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
16035 return (r);
16036 }
16037
16038 return (r);
16039 }
16040
16041 static int
16042 process_uri(nvlist_t *params, char *uri)
16043 {
16044 char *scheme;
16045 char *hier_part;
16046 nvlist_t *mech;
16047 int index;
16048 int r;
16049
16050 if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
16051 return (-1);
16052
16053 if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
16054 uu_die(gettext("Out of memory.\n"));
16055
16056 switch (index) {
16057 case 0:
16058 /* error messages displayed by called function */
16059 r = add_mailto_params(mech, hier_part);
16060 break;
16061
16062 case 1:
16063 if ((r = add_snmp_params(mech, hier_part)) != 0)
16064 semerr(gettext("Not valid parameters: '%s'\n"),
16065 hier_part);
16066 break;
16067
16068 case 2:
16069 if ((r = add_syslog_params(mech, hier_part)) != 0)
16070 semerr(gettext("Not valid parameters: '%s'\n"),
16071 hier_part);
16072 break;
16073
16074 default:
16075 r = -1;
16076 }
16077
16078 if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
16079 mech) != 0)
16080 uu_die(gettext("Out of memory.\n"));
16081
16082 nvlist_free(mech);
16083 return (r);
16084 }
16085
16086 static int
16087 set_params(nvlist_t *params, char **p)
16088 {
16089 char *uri;
16090
16091 if (p == NULL)
16092 /* sanity check */
16093 uu_die("set_params");
16094
16095 while (*p) {
16096 uri = strip_quotes_and_blanks(*p);
16097 if (process_uri(params, uri) != 0)
16098 return (-1);
16099
16100 ++p;
16101 }
16102
16103 return (0);
16104 }
16105
16106 static int
16107 setnotify(const char *e, char **p, int global)
16108 {
16109 char *str = safe_strdup(e);
16110 char **events;
16111 int32_t tset;
16112 int r = -1;
16113 nvlist_t *nvl, *params;
16114 char *fmri = NULL;
16115
16116 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
16117 nvlist_alloc(¶ms, NV_UNIQUE_NAME, 0) != 0 ||
16118 nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
16119 SCF_NOTIFY_PARAMS_VERSION) != 0)
16120 uu_die(gettext("Out of memory.\n"));
16121
16122 events = tokenize(str, ",");
16123
16124 if ((tset = check_tokens(events)) > 0) {
16125 /* SMF state transitions parameters */
16126 size_t sz = max_scf_fmri_len + 1;
16127
16128 fmri = safe_malloc(sz);
16129 if (global) {
16130 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
16131 } else if (get_selection_str(fmri, sz) != 0) {
16132 goto out;
16133 }
16134
16135 if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 ||
16136 nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0)
16137 uu_die(gettext("Out of memory.\n"));
16138
16139 if ((r = set_params(params, p)) == 0) {
16140 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS,
16141 params) != 0)
16142 uu_die(gettext("Out of memory.\n"));
16143
16144 if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
16145 nvl) != SCF_SUCCESS) {
16146 r = -1;
16147 uu_warn(gettext(
16148 "Failed smf_notify_set_params(3SCF): %s\n"),
16149 scf_strerror(scf_error()));
16150 }
16151 }
16152 } else if (tset == FMA_TOKENS) {
16153 /* FMA event parameters */
16154 if (global) {
16155 semerr(gettext("Can't use option '-g' with FMA event "
16156 "definitions\n"));
16157 goto out;
16158 }
16159
16160 if ((r = set_params(params, p)) != 0)
16161 goto out;
16162
16163 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
16164 uu_die(gettext("Out of memory.\n"));
16165
16166 while (*events) {
16167 if (smf_notify_set_params(de_tag(*events), nvl) !=
16168 SCF_SUCCESS)
16169 uu_warn(gettext(
16170 "Failed smf_notify_set_params(3SCF) for "
16171 "event %s: %s\n"), *events,
16172 scf_strerror(scf_error()));
16173 events++;
16174 }
16175 } else if (tset == MIXED_TOKENS) {
16176 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
16177 } else {
16178 /* Sanity check */
16179 uu_die(gettext("Invalid input.\n"));
16180 }
16181
16182 out:
16183 nvlist_free(nvl);
16184 nvlist_free(params);
16185 free(fmri);
16186 free(str);
16187
16188 return (r);
16189 }
16190
16191 int
16192 lscf_setnotify(uu_list_t *args)
16193 {
16194 int argc;
16195 char **argv = NULL;
16196 string_list_t *slp;
16197 int global;
16198 char *events;
16199 char **p;
16200 int i;
16201 int ret;
16202
16203 if ((argc = uu_list_numnodes(args)) < 2)
16204 goto usage;
16205
16206 argv = calloc(argc + 1, sizeof (char *));
16207 if (argv == NULL)
16208 uu_die(gettext("Out of memory.\n"));
16209
16210 for (slp = uu_list_first(args), i = 0;
16211 slp != NULL;
16212 slp = uu_list_next(args, slp), ++i)
16213 argv[i] = slp->str;
16214
16215 argv[i] = NULL;
16216
16217 if (strcmp(argv[0], "-g") == 0) {
16218 global = 1;
16219 events = argv[1];
16220 p = argv + 2;
16221 } else {
16222 global = 0;
16223 events = argv[0];
16224 p = argv + 1;
16225 }
16226
16227 ret = setnotify(events, p, global);
16228
16229 out:
16230 free(argv);
16231 return (ret);
16232
16233 usage:
16234 ret = -2;
16235 goto out;
16236 }
16237
16238 /*
16239 * Creates a list of instance name strings associated with a service. If
16240 * wohandcrafted flag is set, get only instances that have a last-import
16241 * snapshot, instances that were imported via svccfg.
16242 */
16243 static uu_list_t *
16244 create_instance_list(scf_service_t *svc, int wohandcrafted)
16245 {
16246 scf_snapshot_t *snap = NULL;
16247 scf_instance_t *inst;
16248 scf_iter_t *inst_iter;
16249 uu_list_t *instances;
16250 char *instname;
16251 int r;
16252
16253 inst_iter = scf_iter_create(g_hndl);
16254 inst = scf_instance_create(g_hndl);
16255 if (inst_iter == NULL || inst == NULL) {
16256 uu_warn(gettext("Could not create instance or iterator\n"));
16257 scfdie();
16258 }
16259
16260 if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
16261 return (instances);
16262
16263 if (scf_iter_service_instances(inst_iter, svc) != 0) {
16264 switch (scf_error()) {
16265 case SCF_ERROR_CONNECTION_BROKEN:
16266 case SCF_ERROR_DELETED:
16267 uu_list_destroy(instances);
16268 instances = NULL;
16269 goto out;
16270
16271 case SCF_ERROR_HANDLE_MISMATCH:
16272 case SCF_ERROR_NOT_BOUND:
16273 case SCF_ERROR_NOT_SET:
16274 default:
16275 bad_error("scf_iter_service_instances", scf_error());
16276 }
16277 }
16278
16279 instname = safe_malloc(max_scf_name_len + 1);
16280 while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
16281 if (r == -1) {
16282 (void) uu_warn(gettext("Unable to iterate through "
16283 "instances to create instance list : %s\n"),
16284 scf_strerror(scf_error()));
16285
16286 uu_list_destroy(instances);
16287 instances = NULL;
16288 goto out;
16289 }
16290
16291 /*
16292 * If the instance does not have a last-import snapshot
16293 * then do not add it to the list as it is a hand-crafted
16294 * instance that should not be managed.
16295 */
16296 if (wohandcrafted) {
16297 if (snap == NULL &&
16298 (snap = scf_snapshot_create(g_hndl)) == NULL) {
16299 uu_warn(gettext("Unable to create snapshot "
16300 "entity\n"));
16301 scfdie();
16302 }
16303
16304 if (scf_instance_get_snapshot(inst,
16305 snap_lastimport, snap) != 0) {
16306 switch (scf_error()) {
16307 case SCF_ERROR_NOT_FOUND :
16308 case SCF_ERROR_DELETED:
16309 continue;
16310
16311 case SCF_ERROR_CONNECTION_BROKEN:
16312 uu_list_destroy(instances);
16313 instances = NULL;
16314 goto out;
16315
16316 case SCF_ERROR_HANDLE_MISMATCH:
16317 case SCF_ERROR_NOT_BOUND:
16318 case SCF_ERROR_NOT_SET:
16319 default:
16320 bad_error("scf_iter_service_instances",
16321 scf_error());
16322 }
16323 }
16324 }
16325
16326 if (scf_instance_get_name(inst, instname,
16327 max_scf_name_len + 1) < 0) {
16328 switch (scf_error()) {
16329 case SCF_ERROR_NOT_FOUND :
16330 continue;
16331
16332 case SCF_ERROR_CONNECTION_BROKEN:
16333 case SCF_ERROR_DELETED:
16334 uu_list_destroy(instances);
16335 instances = NULL;
16336 goto out;
16337
16338 case SCF_ERROR_HANDLE_MISMATCH:
16339 case SCF_ERROR_NOT_BOUND:
16340 case SCF_ERROR_NOT_SET:
16341 default:
16342 bad_error("scf_iter_service_instances",
16343 scf_error());
16344 }
16345 }
16346
16347 add_string(instances, instname);
16348 }
16349
16350 out:
16351 if (snap)
16352 scf_snapshot_destroy(snap);
16353
16354 scf_instance_destroy(inst);
16355 scf_iter_destroy(inst_iter);
16356 free(instname);
16357 return (instances);
16358 }
16359
16360 /*
16361 * disable an instance but wait for the instance to
16362 * move out of the running state.
16363 *
16364 * Returns 0 : if the instance did not disable
16365 * Returns non-zero : if the instance disabled.
16366 *
16367 */
16368 static int
16369 disable_instance(scf_instance_t *instance)
16370 {
16371 char *fmribuf;
16372 int enabled = 10000;
16373
16374 if (inst_is_running(instance)) {
16375 fmribuf = safe_malloc(max_scf_name_len + 1);
16376 if (scf_instance_to_fmri(instance, fmribuf,
16377 max_scf_name_len + 1) < 0) {
16378 free(fmribuf);
16379 return (0);
16380 }
16381
16382 /*
16383 * If the instance cannot be disabled then return
16384 * failure to disable and let the caller decide
16385 * if that is of importance.
16386 */
16387 if (smf_disable_instance(fmribuf, 0) != 0) {
16388 free(fmribuf);
16389 return (0);
16390 }
16391
16392 while (enabled) {
16393 if (!inst_is_running(instance))
16394 break;
16395
16396 (void) poll(NULL, 0, 5);
16397 enabled = enabled - 5;
16398 }
16399
16400 free(fmribuf);
16401 }
16402
16403 return (enabled);
16404 }
16405
16406 /*
16407 * Function to compare two service_manifest structures.
16408 */
16409 /* ARGSUSED2 */
16410 static int
16411 service_manifest_compare(const void *left, const void *right, void *unused)
16412 {
16413 service_manifest_t *l = (service_manifest_t *)left;
16414 service_manifest_t *r = (service_manifest_t *)right;
16415 int rc;
16416
16417 rc = strcmp(l->servicename, r->servicename);
16418
16419 return (rc);
16420 }
16421
16422 /*
16423 * Look for the provided service in the service to manifest
16424 * tree. If the service exists, and a manifest was provided
16425 * then add the manifest to that service. If the service
16426 * does not exist, then add the service and manifest to the
16427 * list.
16428 *
16429 * If the manifest is NULL, return the element if found. If
16430 * the service is not found return NULL.
16431 */
16432 service_manifest_t *
16433 find_add_svc_mfst(const char *svnbuf, const char *mfst)
16434 {
16435 service_manifest_t elem;
16436 service_manifest_t *fnelem;
16437 uu_avl_index_t marker;
16438
16439 elem.servicename = svnbuf;
16440 fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
16441
16442 if (mfst) {
16443 if (fnelem) {
16444 add_string(fnelem->mfstlist, strdup(mfst));
16445 } else {
16446 fnelem = safe_malloc(sizeof (*fnelem));
16447 fnelem->servicename = safe_strdup(svnbuf);
16448 if ((fnelem->mfstlist =
16449 uu_list_create(string_pool, NULL, 0)) == NULL)
16450 uu_die(gettext("Could not create property "
16451 "list: %s\n"), uu_strerror(uu_error()));
16452
16453 add_string(fnelem->mfstlist, safe_strdup(mfst));
16454
16455 uu_avl_insert(service_manifest_tree, fnelem, marker);
16456 }
16457 }
16458
16459 return (fnelem);
16460 }
16461
16462 /*
16463 * Create the service to manifest avl tree.
16464 *
16465 * Walk each of the manifests currently installed in the supported
16466 * directories, /lib/svc/manifests and /var/svc/manifests. For
16467 * each of the manifests, inventory the services and add them to
16468 * the tree.
16469 *
16470 * Code that calls this function should make sure fileystem/minimal is online,
16471 * /var is available, since this function walks the /var/svc/manifest directory.
16472 */
16473 static void
16474 create_manifest_tree(void)
16475 {
16476 manifest_info_t **entry;
16477 manifest_info_t **manifests;
16478 uu_list_walk_t *svcs;
16479 bundle_t *b;
16480 entity_t *mfsvc;
16481 char *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
16482 int c, status;
16483
16484 if (service_manifest_pool)
16485 return;
16486
16487 /*
16488 * Create the list pool for the service manifest list
16489 */
16490 service_manifest_pool = uu_avl_pool_create("service_manifest",
16491 sizeof (service_manifest_t),
16492 offsetof(service_manifest_t, svcmfst_node),
16493 service_manifest_compare, UU_DEFAULT);
16494 if (service_manifest_pool == NULL)
16495 uu_die(gettext("service_manifest pool creation failed: %s\n"),
16496 uu_strerror(uu_error()));
16497
16498 /*
16499 * Create the list
16500 */
16501 service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
16502 UU_DEFAULT);
16503 if (service_manifest_tree == NULL)
16504 uu_die(gettext("service_manifest tree creation failed: %s\n"),
16505 uu_strerror(uu_error()));
16506
16507 /*
16508 * Walk the manifests adding the service(s) from each manifest.
16509 *
16510 * If a service already exists add the manifest to the manifest
16511 * list for that service. This covers the case of a service that
16512 * is supported by multiple manifest files.
16513 */
16514 for (c = 0; dirs[c]; c++) {
16515 status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT);
16516 if (status < 0) {
16517 uu_warn(gettext("file tree walk of %s encountered "
16518 "error %s\n"), dirs[c], strerror(errno));
16519
16520 uu_avl_destroy(service_manifest_tree);
16521 service_manifest_tree = NULL;
16522 return;
16523 }
16524
16525 /*
16526 * If a manifest that was in the list is not found
16527 * then skip and go to the next manifest file.
16528 */
16529 if (manifests != NULL) {
16530 for (entry = manifests; *entry != NULL; entry++) {
16531 b = internal_bundle_new();
16532 if (lxml_get_bundle_file(b, (*entry)->mi_path,
16533 SVCCFG_OP_IMPORT) != 0) {
16534 internal_bundle_free(b);
16535 continue;
16536 }
16537
16538 svcs = uu_list_walk_start(b->sc_bundle_services,
16539 0);
16540 if (svcs == NULL) {
16541 internal_bundle_free(b);
16542 continue;
16543 }
16544
16545 while ((mfsvc = uu_list_walk_next(svcs)) !=
16546 NULL) {
16547 /* Add manifest to service */
16548 (void) find_add_svc_mfst(mfsvc->sc_name,
16549 (*entry)->mi_path);
16550 }
16551
16552 uu_list_walk_end(svcs);
16553 internal_bundle_free(b);
16554 }
16555
16556 free_manifest_array(manifests);
16557 }
16558 }
16559 }
16560
16561 /*
16562 * Check the manifest history file to see
16563 * if the service was ever installed from
16564 * one of the supported directories.
16565 *
16566 * Return Values :
16567 * -1 - if there's error reading manifest history file
16568 * 1 - if the service is not found
16569 * 0 - if the service is found
16570 */
16571 static int
16572 check_mfst_history(const char *svcname)
16573 {
16574 struct stat st;
16575 caddr_t mfsthist_start;
16576 char *svnbuf;
16577 int fd;
16578 int r = 1;
16579
16580 fd = open(MFSTHISTFILE, O_RDONLY);
16581 if (fd == -1) {
16582 uu_warn(gettext("Unable to open the history file\n"));
16583 return (-1);
16584 }
16585
16586 if (fstat(fd, &st) == -1) {
16587 uu_warn(gettext("Unable to stat the history file\n"));
16588 return (-1);
16589 }
16590
16591 mfsthist_start = mmap(0, st.st_size, PROT_READ,
16592 MAP_PRIVATE, fd, 0);
16593
16594 (void) close(fd);
16595 if (mfsthist_start == MAP_FAILED ||
16596 *(mfsthist_start + st.st_size) != '\0') {
16597 (void) munmap(mfsthist_start, st.st_size);
16598 return (-1);
16599 }
16600
16601 /*
16602 * The manifest history file is a space delimited list
16603 * of service and instance to manifest linkage. Adding
16604 * a space to the end of the service name so to get only
16605 * the service that is being searched for.
16606 */
16607 svnbuf = uu_msprintf("%s ", svcname);
16608 if (svnbuf == NULL)
16609 uu_die(gettext("Out of memory"));
16610
16611 if (strstr(mfsthist_start, svnbuf) != NULL)
16612 r = 0;
16613
16614 (void) munmap(mfsthist_start, st.st_size);
16615 uu_free(svnbuf);
16616 return (r);
16617 }
16618
16619 /*
16620 * Take down each of the instances in the service
16621 * and remove them, then delete the service.
16622 */
16623 static void
16624 teardown_service(scf_service_t *svc, const char *svnbuf)
16625 {
16626 scf_instance_t *instance;
16627 scf_iter_t *iter;
16628 int r;
16629
16630 safe_printf(gettext("Delete service %s as there are no "
16631 "supporting manifests\n"), svnbuf);
16632
16633 instance = scf_instance_create(g_hndl);
16634 iter = scf_iter_create(g_hndl);
16635 if (iter == NULL || instance == NULL) {
16636 uu_warn(gettext("Unable to create supporting entities to "
16637 "teardown the service\n"));
16638 uu_warn(gettext("scf error is : %s\n"),
16639 scf_strerror(scf_error()));
16640 scfdie();
16641 }
16642
16643 if (scf_iter_service_instances(iter, svc) != 0) {
16644 switch (scf_error()) {
16645 case SCF_ERROR_CONNECTION_BROKEN:
16646 case SCF_ERROR_DELETED:
16647 goto out;
16648
16649 case SCF_ERROR_HANDLE_MISMATCH:
16650 case SCF_ERROR_NOT_BOUND:
16651 case SCF_ERROR_NOT_SET:
16652 default:
16653 bad_error("scf_iter_service_instances",
16654 scf_error());
16655 }
16656 }
16657
16658 while ((r = scf_iter_next_instance(iter, instance)) != 0) {
16659 if (r == -1) {
16660 uu_warn(gettext("Error - %s\n"),
16661 scf_strerror(scf_error()));
16662 goto out;
16663 }
16664
16665 (void) disable_instance(instance);
16666 }
16667
16668 /*
16669 * Delete the service... forcing the deletion in case
16670 * any of the instances did not disable.
16671 */
16672 (void) lscf_service_delete(svc, 1);
16673 out:
16674 scf_instance_destroy(instance);
16675 scf_iter_destroy(iter);
16676 }
16677
16678 /*
16679 * Get the list of instances supported by the manifest
16680 * file.
16681 *
16682 * Return 0 if there are no instances.
16683 *
16684 * Return -1 if there are errors attempting to collect instances.
16685 *
16686 * Return the count of instances found if there are no errors.
16687 *
16688 */
16689 static int
16690 check_instance_support(char *mfstfile, const char *svcname,
16691 uu_list_t *instances)
16692 {
16693 uu_list_walk_t *svcs, *insts;
16694 uu_list_t *ilist;
16695 bundle_t *b;
16696 entity_t *mfsvc, *mfinst;
16697 const char *svcn;
16698 int rminstcnt = 0;
16699
16700
16701 b = internal_bundle_new();
16702
16703 if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
16704 /*
16705 * Unable to process the manifest file for
16706 * instance support, so just return as
16707 * don't want to remove instances that could
16708 * not be accounted for that might exist here.
16709 */
16710 internal_bundle_free(b);
16711 return (0);
16712 }
16713
16714 svcs = uu_list_walk_start(b->sc_bundle_services, 0);
16715 if (svcs == NULL) {
16716 internal_bundle_free(b);
16717 return (0);
16718 }
16719
16720 svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
16721 (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
16722
16723 while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
16724 if (strcmp(mfsvc->sc_name, svcn) == 0)
16725 break;
16726 }
16727 uu_list_walk_end(svcs);
16728
16729 if (mfsvc == NULL) {
16730 internal_bundle_free(b);
16731 return (-1);
16732 }
16733
16734 ilist = mfsvc->sc_u.sc_service.sc_service_instances;
16735 if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
16736 internal_bundle_free(b);
16737 return (0);
16738 }
16739
16740 while ((mfinst = uu_list_walk_next(insts)) != NULL) {
16741 /*
16742 * Remove the instance from the instances list.
16743 * The unaccounted for instances will be removed
16744 * from the service once all manifests are
16745 * processed.
16746 */
16747 (void) remove_string(instances,
16748 mfinst->sc_name);
16749 rminstcnt++;
16750 }
16751
16752 uu_list_walk_end(insts);
16753 internal_bundle_free(b);
16754
16755 return (rminstcnt);
16756 }
16757
16758 /*
16759 * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16760 * 'false' to indicate there's no manifest file(s) found for the service.
16761 */
16762 static void
16763 svc_add_no_support(scf_service_t *svc)
16764 {
16765 char *pname;
16766
16767 /* Add no support */
16768 cur_svc = svc;
16769 if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
16770 return;
16771
16772 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
16773 if (pname == NULL)
16774 uu_die(gettext("Out of memory.\n"));
16775
16776 (void) lscf_addpropvalue(pname, "boolean:", "0");
16777
16778 uu_free(pname);
16779 cur_svc = NULL;
16780 }
16781
16782 /*
16783 * This function handles all upgrade scenarios for a service that doesn't have
16784 * SCF_PG_MANIFESTFILES pg. The function creates and populates
16785 * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16786 * manifest(s) mapping. Manifests under supported directories are inventoried
16787 * and a property is added for each file that delivers configuration to the
16788 * service. A service that has no corresponding manifest files (deleted) are
16789 * removed from repository.
16790 *
16791 * Unsupported services:
16792 *
16793 * A service is considered unsupported if there is no corresponding manifest
16794 * in the supported directories for that service and the service isn't in the
16795 * history file list. The history file, MFSTHISTFILE, contains a list of all
16796 * services and instances that were delivered by Solaris before the introduction
16797 * of the SCF_PG_MANIFESTFILES property group. The history file also contains
16798 * the path to the manifest file that defined the service or instance.
16799 *
16800 * Another type of unsupported services is 'handcrafted' services,
16801 * programmatically created services or services created by dependent entries
16802 * in other manifests. A handcrafted service is identified by its lack of any
16803 * instance containing last-import snapshot which is created during svccfg
16804 * import.
16805 *
16806 * This function sets a flag for unsupported services by setting services'
16807 * SCF_PG_MANIFESTFILES/support property to false.
16808 */
16809 static void
16810 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
16811 {
16812 service_manifest_t *elem;
16813 uu_list_walk_t *mfwalk;
16814 string_list_t *mfile;
16815 uu_list_t *instances;
16816 const char *sname;
16817 char *pname;
16818 int r;
16819
16820 /*
16821 * Since there's no guarantee manifests under /var are available during
16822 * early import, don't perform any upgrade during early import.
16823 */
16824 if (IGNORE_VAR)
16825 return;
16826
16827 if (service_manifest_tree == NULL) {
16828 create_manifest_tree();
16829 }
16830
16831 /*
16832 * Find service's supporting manifest(s) after
16833 * stripping off the svc:/ prefix that is part
16834 * of the fmri that is not used in the service
16835 * manifest bundle list.
16836 */
16837 sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
16838 strlen(SCF_FMRI_SERVICE_PREFIX);
16839 elem = find_add_svc_mfst(sname, NULL);
16840 if (elem == NULL) {
16841
16842 /*
16843 * A handcrafted service, one that has no instance containing
16844 * last-import snapshot, should get unsupported flag.
16845 */
16846 instances = create_instance_list(svc, 1);
16847 if (instances == NULL) {
16848 uu_warn(gettext("Unable to create instance list %s\n"),
16849 svcname);
16850 return;
16851 }
16852
16853 if (uu_list_numnodes(instances) == 0) {
16854 svc_add_no_support(svc);
16855 return;
16856 }
16857
16858 /*
16859 * If the service is in the history file, and its supporting
16860 * manifests are not found, we can safely delete the service
16861 * because its manifests are removed from the system.
16862 *
16863 * Services not found in the history file are not delivered by
16864 * Solaris and/or delivered outside supported directories, set
16865 * unsupported flag for these services.
16866 */
16867 r = check_mfst_history(svcname);
16868 if (r == -1)
16869 return;
16870
16871 if (r) {
16872 /* Set unsupported flag for service */
16873 svc_add_no_support(svc);
16874 } else {
16875 /* Delete the service */
16876 teardown_service(svc, svcname);
16877 }
16878
16879 return;
16880 }
16881
16882 /*
16883 * Walk through the list of manifests and add them
16884 * to the service.
16885 *
16886 * Create a manifestfiles pg and add the property.
16887 */
16888 mfwalk = uu_list_walk_start(elem->mfstlist, 0);
16889 if (mfwalk == NULL)
16890 return;
16891
16892 cur_svc = svc;
16893 r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
16894 if (r != 0) {
16895 cur_svc = NULL;
16896 return;
16897 }
16898
16899 while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
16900 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16901 mhash_filename_to_propname(mfile->str, 0));
16902 if (pname == NULL)
16903 uu_die(gettext("Out of memory.\n"));
16904
16905 (void) lscf_addpropvalue(pname, "astring:", mfile->str);
16906 uu_free(pname);
16907 }
16908 uu_list_walk_end(mfwalk);
16909
16910 cur_svc = NULL;
16911 }
16912
16913 /*
16914 * Take a service and process the manifest file entires to see if
16915 * there is continued support for the service and instances. If
16916 * not cleanup as appropriate.
16917 *
16918 * If a service does not have a manifest files entry flag it for
16919 * upgrade and return.
16920 *
16921 * For each manifestfiles property check if the manifest file is
16922 * under the supported /lib/svc/manifest or /var/svc/manifest path
16923 * and if not then return immediately as this service is not supported
16924 * by the cleanup mechanism and should be ignored.
16925 *
16926 * For each manifest file that is supported, check to see if the
16927 * file exists. If not then remove the manifest file property
16928 * from the service and the smf/manifest hash table. If the manifest
16929 * file exists then verify that it supports the instances that are
16930 * part of the service.
16931 *
16932 * Once all manifest files have been accounted for remove any instances
16933 * that are no longer supported in the service.
16934 *
16935 * Return values :
16936 * 0 - Successfully processed the service
16937 * non-zero - failed to process the service
16938 *
16939 * On most errors, will just return to wait and get the next service,
16940 * unless in case of unable to create the needed structures which is
16941 * most likely a fatal error that is not going to be recoverable.
16942 */
16943 int
16944 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
16945 {
16946 struct mpg_mfile *mpntov;
16947 struct mpg_mfile **mpvarry = NULL;
16948 scf_service_t *svc;
16949 scf_propertygroup_t *mpg;
16950 scf_property_t *mp;
16951 scf_value_t *mv;
16952 scf_iter_t *mi;
16953 scf_instance_t *instance;
16954 uu_list_walk_t *insts;
16955 uu_list_t *instances = NULL;
16956 boolean_t activity = (boolean_t)act;
16957 char *mpnbuf;
16958 char *mpvbuf;
16959 char *pgpropbuf;
16960 int mfstcnt, rminstct, instct, mfstmax;
16961 int index;
16962 int r = 0;
16963
16964 assert(g_hndl != NULL);
16965 assert(wip->svc != NULL);
16966 assert(wip->fmri != NULL);
16967
16968 svc = wip->svc;
16969
16970 mpg = scf_pg_create(g_hndl);
16971 mp = scf_property_create(g_hndl);
16972 mi = scf_iter_create(g_hndl);
16973 mv = scf_value_create(g_hndl);
16974 instance = scf_instance_create(g_hndl);
16975
16976 if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
16977 instance == NULL) {
16978 uu_warn(gettext("Unable to create the supporting entities\n"));
16979 uu_warn(gettext("scf error is : %s\n"),
16980 scf_strerror(scf_error()));
16981 scfdie();
16982 }
16983
16984 /*
16985 * Get the manifestfiles property group to be parsed for
16986 * files existence.
16987 */
16988 if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
16989 switch (scf_error()) {
16990 case SCF_ERROR_NOT_FOUND:
16991 upgrade_svc_mfst_connection(svc, wip->fmri);
16992 break;
16993 case SCF_ERROR_DELETED:
16994 case SCF_ERROR_CONNECTION_BROKEN:
16995 goto out;
16996
16997 case SCF_ERROR_HANDLE_MISMATCH:
16998 case SCF_ERROR_NOT_BOUND:
16999 case SCF_ERROR_NOT_SET:
17000 default:
17001 bad_error("scf_iter_pg_properties",
17002 scf_error());
17003 }
17004
17005 goto out;
17006 }
17007
17008 /*
17009 * Iterate through each of the manifestfiles properties
17010 * to determine what manifestfiles are available.
17011 *
17012 * If a manifest file is supported then increment the
17013 * count and therefore the service is safe.
17014 */
17015 if (scf_iter_pg_properties(mi, mpg) != 0) {
17016 switch (scf_error()) {
17017 case SCF_ERROR_DELETED:
17018 case SCF_ERROR_CONNECTION_BROKEN:
17019 goto out;
17020
17021 case SCF_ERROR_HANDLE_MISMATCH:
17022 case SCF_ERROR_NOT_BOUND:
17023 case SCF_ERROR_NOT_SET:
17024 default:
17025 bad_error("scf_iter_pg_properties",
17026 scf_error());
17027 }
17028 }
17029
17030 mfstcnt = 0;
17031 mfstmax = MFSTFILE_MAX;
17032 mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
17033 while ((r = scf_iter_next_property(mi, mp)) != 0) {
17034 if (r == -1)
17035 bad_error(gettext("Unable to iterate through "
17036 "manifestfiles properties : %s"),
17037 scf_error());
17038
17039 mpntov = safe_malloc(sizeof (struct mpg_mfile));
17040 mpnbuf = safe_malloc(max_scf_name_len + 1);
17041 mpvbuf = safe_malloc(max_scf_value_len + 1);
17042 mpntov->mpg = mpnbuf;
17043 mpntov->mfile = mpvbuf;
17044 mpntov->access = 1;
17045 if (scf_property_get_name(mp, mpnbuf,
17046 max_scf_name_len + 1) < 0) {
17047 uu_warn(gettext("Unable to get manifest file "
17048 "property : %s\n"),
17049 scf_strerror(scf_error()));
17050
17051 switch (scf_error()) {
17052 case SCF_ERROR_DELETED:
17053 case SCF_ERROR_CONNECTION_BROKEN:
17054 r = scferror2errno(scf_error());
17055 goto out_free;
17056
17057 case SCF_ERROR_HANDLE_MISMATCH:
17058 case SCF_ERROR_NOT_BOUND:
17059 case SCF_ERROR_NOT_SET:
17060 default:
17061 bad_error("scf_iter_pg_properties",
17062 scf_error());
17063 }
17064 }
17065
17066 /*
17067 * The support property is a boolean value that indicates
17068 * if the service is supported for manifest file deletion.
17069 * Currently at this time there is no code that sets this
17070 * value to true. So while we could just let this be caught
17071 * by the support check below, in the future this by be set
17072 * to true and require processing. So for that, go ahead
17073 * and check here, and just return if false. Otherwise,
17074 * fall through expecting that other support checks will
17075 * handle the entries.
17076 */
17077 if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
17078 uint8_t support;
17079
17080 if (scf_property_get_value(mp, mv) != 0 ||
17081 scf_value_get_boolean(mv, &support) != 0) {
17082 uu_warn(gettext("Unable to get the manifest "
17083 "support value: %s\n"),
17084 scf_strerror(scf_error()));
17085
17086 switch (scf_error()) {
17087 case SCF_ERROR_DELETED:
17088 case SCF_ERROR_CONNECTION_BROKEN:
17089 r = scferror2errno(scf_error());
17090 goto out_free;
17091
17092 case SCF_ERROR_HANDLE_MISMATCH:
17093 case SCF_ERROR_NOT_BOUND:
17094 case SCF_ERROR_NOT_SET:
17095 default:
17096 bad_error("scf_iter_pg_properties",
17097 scf_error());
17098 }
17099 }
17100
17101 if (support == B_FALSE)
17102 goto out_free;
17103 }
17104
17105 /*
17106 * Anything with a manifest outside of the supported
17107 * directories, immediately bail out because that makes
17108 * this service non-supported. We don't even want
17109 * to do instance processing in this case because the
17110 * instances could be part of the non-supported manifest.
17111 */
17112 if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
17113 /*
17114 * Manifest is not in /lib/svc, so we need to
17115 * consider the /var/svc case.
17116 */
17117 if (strncmp(mpnbuf, VARSVC_PR,
17118 strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
17119 /*
17120 * Either the manifest is not in /var/svc or
17121 * /var is not yet mounted. We ignore the
17122 * manifest either because it is not in a
17123 * standard location or because we cannot
17124 * currently access the manifest.
17125 */
17126 goto out_free;
17127 }
17128 }
17129
17130 /*
17131 * Get the value to of the manifest file for this entry
17132 * for access verification and instance support
17133 * verification if it still exists.
17134 *
17135 * During Early Manifest Import if the manifest is in
17136 * /var/svc then it may not yet be available for checking
17137 * so we must determine if /var/svc is available. If not
17138 * then defer until Late Manifest Import to cleanup.
17139 */
17140 if (scf_property_get_value(mp, mv) != 0) {
17141 uu_warn(gettext("Unable to get the manifest file "
17142 "value: %s\n"),
17143 scf_strerror(scf_error()));
17144
17145 switch (scf_error()) {
17146 case SCF_ERROR_DELETED:
17147 case SCF_ERROR_CONNECTION_BROKEN:
17148 r = scferror2errno(scf_error());
17149 goto out_free;
17150
17151 case SCF_ERROR_HANDLE_MISMATCH:
17152 case SCF_ERROR_NOT_BOUND:
17153 case SCF_ERROR_NOT_SET:
17154 default:
17155 bad_error("scf_property_get_value",
17156 scf_error());
17157 }
17158 }
17159
17160 if (scf_value_get_astring(mv, mpvbuf,
17161 max_scf_value_len + 1) < 0) {
17162 uu_warn(gettext("Unable to get the manifest "
17163 "file : %s\n"),
17164 scf_strerror(scf_error()));
17165
17166 switch (scf_error()) {
17167 case SCF_ERROR_DELETED:
17168 case SCF_ERROR_CONNECTION_BROKEN:
17169 r = scferror2errno(scf_error());
17170 goto out_free;
17171
17172 case SCF_ERROR_HANDLE_MISMATCH:
17173 case SCF_ERROR_NOT_BOUND:
17174 case SCF_ERROR_NOT_SET:
17175 default:
17176 bad_error("scf_value_get_astring",
17177 scf_error());
17178 }
17179 }
17180
17181 mpvarry[mfstcnt] = mpntov;
17182 mfstcnt++;
17183
17184 /*
17185 * Check for the need to reallocate array
17186 */
17187 if (mfstcnt >= (mfstmax - 1)) {
17188 struct mpg_mfile **newmpvarry;
17189
17190 mfstmax = mfstmax * 2;
17191 newmpvarry = realloc(mpvarry,
17192 sizeof (struct mpg_mfile *) * mfstmax);
17193
17194 if (newmpvarry == NULL)
17195 goto out_free;
17196
17197 mpvarry = newmpvarry;
17198 }
17199
17200 mpvarry[mfstcnt] = NULL;
17201 }
17202
17203 for (index = 0; mpvarry[index]; index++) {
17204 mpntov = mpvarry[index];
17205
17206 /*
17207 * Check to see if the manifestfile is accessable, if so hand
17208 * this service and manifestfile off to be processed for
17209 * instance support.
17210 */
17211 mpnbuf = mpntov->mpg;
17212 mpvbuf = mpntov->mfile;
17213 if (access(mpvbuf, F_OK) != 0) {
17214 mpntov->access = 0;
17215 activity++;
17216 mfstcnt--;
17217 /* Remove the entry from the service */
17218 cur_svc = svc;
17219 pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
17220 mpnbuf);
17221 if (pgpropbuf == NULL)
17222 uu_die(gettext("Out of memory.\n"));
17223
17224 lscf_delprop(pgpropbuf);
17225 cur_svc = NULL;
17226
17227 uu_free(pgpropbuf);
17228 }
17229 }
17230
17231 /*
17232 * If mfstcnt is 0, none of the manifests that supported the service
17233 * existed so remove the service.
17234 */
17235 if (mfstcnt == 0) {
17236 teardown_service(svc, wip->fmri);
17237
17238 goto out_free;
17239 }
17240
17241 if (activity) {
17242 int nosvcsupport = 0;
17243
17244 /*
17245 * If the list of service instances is NULL then
17246 * create the list.
17247 */
17248 instances = create_instance_list(svc, 1);
17249 if (instances == NULL) {
17250 uu_warn(gettext("Unable to create instance list %s\n"),
17251 wip->fmri);
17252 goto out_free;
17253 }
17254
17255 rminstct = uu_list_numnodes(instances);
17256 instct = rminstct;
17257
17258 for (index = 0; mpvarry[index]; index++) {
17259 mpntov = mpvarry[index];
17260 if (mpntov->access == 0)
17261 continue;
17262
17263 mpnbuf = mpntov->mpg;
17264 mpvbuf = mpntov->mfile;
17265 r = check_instance_support(mpvbuf, wip->fmri,
17266 instances);
17267 if (r == -1) {
17268 nosvcsupport++;
17269 } else {
17270 rminstct -= r;
17271 }
17272 }
17273
17274 if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
17275 teardown_service(svc, wip->fmri);
17276
17277 goto out_free;
17278 }
17279 }
17280
17281 /*
17282 * If there are instances left on the instance list, then
17283 * we must remove them.
17284 */
17285 if (instances != NULL && uu_list_numnodes(instances)) {
17286 string_list_t *sp;
17287
17288 insts = uu_list_walk_start(instances, 0);
17289 while ((sp = uu_list_walk_next(insts)) != NULL) {
17290 /*
17291 * Remove the instance from the instances list.
17292 */
17293 safe_printf(gettext("Delete instance %s from "
17294 "service %s\n"), sp->str, wip->fmri);
17295 if (scf_service_get_instance(svc, sp->str,
17296 instance) != SCF_SUCCESS) {
17297 (void) uu_warn("scf_error - %s\n",
17298 scf_strerror(scf_error()));
17299
17300 continue;
17301 }
17302
17303 (void) disable_instance(instance);
17304
17305 (void) lscf_instance_delete(instance, 1);
17306 }
17307 scf_instance_destroy(instance);
17308 uu_list_walk_end(insts);
17309 }
17310
17311 out_free:
17312 if (mpvarry) {
17313 struct mpg_mfile *fmpntov;
17314
17315 for (index = 0; mpvarry[index]; index++) {
17316 fmpntov = mpvarry[index];
17317 if (fmpntov->mpg == mpnbuf)
17318 mpnbuf = NULL;
17319 free(fmpntov->mpg);
17320
17321 if (fmpntov->mfile == mpvbuf)
17322 mpvbuf = NULL;
17323 free(fmpntov->mfile);
17324
17325 if (fmpntov == mpntov)
17326 mpntov = NULL;
17327 free(fmpntov);
17328 }
17329 if (mpnbuf)
17330 free(mpnbuf);
17331 if (mpvbuf)
17332 free(mpvbuf);
17333 if (mpntov)
17334 free(mpntov);
17335
17336 free(mpvarry);
17337 }
17338 out:
17339 scf_pg_destroy(mpg);
17340 scf_property_destroy(mp);
17341 scf_iter_destroy(mi);
17342 scf_value_destroy(mv);
17343
17344 return (0);
17345 }
17346
17347 /*
17348 * Take the service and search for the manifestfiles property
17349 * in each of the property groups. If the manifest file
17350 * associated with the property does not exist then remove
17351 * the property group.
17352 */
17353 int
17354 lscf_hash_cleanup()
17355 {
17356 scf_service_t *svc;
17357 scf_scope_t *scope;
17358 scf_propertygroup_t *pg;
17359 scf_property_t *prop;
17360 scf_value_t *val;
17361 scf_iter_t *iter;
17362 char *pgname = NULL;
17363 char *mfile = NULL;
17364 int r;
17365
17366 svc = scf_service_create(g_hndl);
17367 scope = scf_scope_create(g_hndl);
17368 pg = scf_pg_create(g_hndl);
17369 prop = scf_property_create(g_hndl);
17370 val = scf_value_create(g_hndl);
17371 iter = scf_iter_create(g_hndl);
17372 if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
17373 svc == NULL || scope == NULL) {
17374 uu_warn(gettext("Unable to create a property group, or "
17375 "property\n"));
17376 uu_warn("%s\n", pg == NULL ? "pg is NULL" :
17377 "pg is not NULL");
17378 uu_warn("%s\n", prop == NULL ? "prop is NULL" :
17379 "prop is not NULL");
17380 uu_warn("%s\n", val == NULL ? "val is NULL" :
17381 "val is not NULL");
17382 uu_warn("%s\n", iter == NULL ? "iter is NULL" :
17383 "iter is not NULL");
17384 uu_warn("%s\n", svc == NULL ? "svc is NULL" :
17385 "svc is not NULL");
17386 uu_warn("%s\n", scope == NULL ? "scope is NULL" :
17387 "scope is not NULL");
17388 uu_warn(gettext("scf error is : %s\n"),
17389 scf_strerror(scf_error()));
17390 scfdie();
17391 }
17392
17393 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
17394 switch (scf_error()) {
17395 case SCF_ERROR_CONNECTION_BROKEN:
17396 case SCF_ERROR_NOT_FOUND:
17397 goto out;
17398
17399 case SCF_ERROR_HANDLE_MISMATCH:
17400 case SCF_ERROR_NOT_BOUND:
17401 case SCF_ERROR_INVALID_ARGUMENT:
17402 default:
17403 bad_error("scf_handle_get_scope", scf_error());
17404 }
17405 }
17406
17407 if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
17408 uu_warn(gettext("Unable to process the hash service, %s\n"),
17409 HASH_SVC);
17410 goto out;
17411 }
17412
17413 pgname = safe_malloc(max_scf_name_len + 1);
17414 mfile = safe_malloc(max_scf_value_len + 1);
17415
17416 if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
17417 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17418 scf_strerror(scf_error()));
17419 goto out;
17420 }
17421
17422 while ((r = scf_iter_next_pg(iter, pg)) != 0) {
17423 if (r == -1)
17424 goto out;
17425
17426 if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
17427 switch (scf_error()) {
17428 case SCF_ERROR_DELETED:
17429 return (ENODEV);
17430
17431 case SCF_ERROR_CONNECTION_BROKEN:
17432 return (ECONNABORTED);
17433
17434 case SCF_ERROR_NOT_SET:
17435 case SCF_ERROR_NOT_BOUND:
17436 default:
17437 bad_error("scf_pg_get_name", scf_error());
17438 }
17439 }
17440 if (IGNORE_VAR) {
17441 if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
17442 continue;
17443 }
17444
17445 /*
17446 * If unable to get the property continue as this is an
17447 * entry that has no location to check against.
17448 */
17449 if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
17450 continue;
17451 }
17452
17453 if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
17454 uu_warn(gettext("Unable to get value from %s\n"),
17455 pgname);
17456
17457 switch (scf_error()) {
17458 case SCF_ERROR_DELETED:
17459 case SCF_ERROR_CONSTRAINT_VIOLATED:
17460 case SCF_ERROR_NOT_FOUND:
17461 case SCF_ERROR_NOT_SET:
17462 continue;
17463
17464 case SCF_ERROR_CONNECTION_BROKEN:
17465 r = scferror2errno(scf_error());
17466 goto out;
17467
17468 case SCF_ERROR_HANDLE_MISMATCH:
17469 case SCF_ERROR_NOT_BOUND:
17470 default:
17471 bad_error("scf_property_get_value",
17472 scf_error());
17473 }
17474 }
17475
17476 if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
17477 == -1) {
17478 uu_warn(gettext("Unable to get astring from %s : %s\n"),
17479 pgname, scf_strerror(scf_error()));
17480
17481 switch (scf_error()) {
17482 case SCF_ERROR_NOT_SET:
17483 case SCF_ERROR_TYPE_MISMATCH:
17484 continue;
17485
17486 default:
17487 bad_error("scf_value_get_astring", scf_error());
17488 }
17489 }
17490
17491 if (access(mfile, F_OK) == 0)
17492 continue;
17493
17494 (void) scf_pg_delete(pg);
17495 }
17496
17497 out:
17498 scf_scope_destroy(scope);
17499 scf_service_destroy(svc);
17500 scf_pg_destroy(pg);
17501 scf_property_destroy(prop);
17502 scf_value_destroy(val);
17503 scf_iter_destroy(iter);
17504 free(pgname);
17505 free(mfile);
17506
17507 return (0);
17508 }
17509
17510 #ifndef NATIVE_BUILD
17511 /* ARGSUSED */
17512 CPL_MATCH_FN(complete_select)
17513 {
17514 const char *arg0, *arg1, *arg1end;
17515 int word_start, err = 0, r;
17516 size_t len;
17517 char *buf;
17518
17519 lscf_prep_hndl();
17520
17521 arg0 = line + strspn(line, " \t");
17522 assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
17523
17524 arg1 = arg0 + sizeof ("select") - 1;
17525 arg1 += strspn(arg1, " \t");
17526 word_start = arg1 - line;
17527
17528 arg1end = arg1 + strcspn(arg1, " \t");
17529 if (arg1end < line + word_end)
17530 return (0);
17531
17532 len = line + word_end - arg1;
17533
17534 buf = safe_malloc(max_scf_name_len + 1);
17535
17536 if (cur_snap != NULL) {
17537 return (0);
17538 } else if (cur_inst != NULL) {
17539 return (0);
17540 } else if (cur_svc != NULL) {
17541 scf_instance_t *inst;
17542 scf_iter_t *iter;
17543
17544 if ((inst = scf_instance_create(g_hndl)) == NULL ||
17545 (iter = scf_iter_create(g_hndl)) == NULL)
17546 scfdie();
17547
17548 if (scf_iter_service_instances(iter, cur_svc) != 0)
17549 scfdie();
17550
17551 for (;;) {
17552 r = scf_iter_next_instance(iter, inst);
17553 if (r == 0)
17554 break;
17555 if (r != 1)
17556 scfdie();
17557
17558 if (scf_instance_get_name(inst, buf,
17559 max_scf_name_len + 1) < 0)
17560 scfdie();
17561
17562 if (strncmp(buf, arg1, len) == 0) {
17563 err = cpl_add_completion(cpl, line, word_start,
17564 word_end, buf + len, "", " ");
17565 if (err != 0)
17566 break;
17567 }
17568 }
17569
17570 scf_iter_destroy(iter);
17571 scf_instance_destroy(inst);
17572
17573 return (err);
17574 } else {
17575 scf_service_t *svc;
17576 scf_iter_t *iter;
17577
17578 assert(cur_scope != NULL);
17579
17580 if ((svc = scf_service_create(g_hndl)) == NULL ||
17581 (iter = scf_iter_create(g_hndl)) == NULL)
17582 scfdie();
17583
17584 if (scf_iter_scope_services(iter, cur_scope) != 0)
17585 scfdie();
17586
17587 for (;;) {
17588 r = scf_iter_next_service(iter, svc);
17589 if (r == 0)
17590 break;
17591 if (r != 1)
17592 scfdie();
17593
17594 if (scf_service_get_name(svc, buf,
17595 max_scf_name_len + 1) < 0)
17596 scfdie();
17597
17598 if (strncmp(buf, arg1, len) == 0) {
17599 err = cpl_add_completion(cpl, line, word_start,
17600 word_end, buf + len, "", " ");
17601 if (err != 0)
17602 break;
17603 }
17604 }
17605
17606 scf_iter_destroy(iter);
17607 scf_service_destroy(svc);
17608
17609 return (err);
17610 }
17611 }
17612
17613 /* ARGSUSED */
17614 CPL_MATCH_FN(complete_command)
17615 {
17616 uint32_t scope = 0;
17617
17618 if (cur_snap != NULL)
17619 scope = CS_SNAP;
17620 else if (cur_inst != NULL)
17621 scope = CS_INST;
17622 else if (cur_svc != NULL)
17623 scope = CS_SVC;
17624 else
17625 scope = CS_SCOPE;
17626
17627 return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
17628 }
17629 #endif /* NATIVE_BUILD */