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 2012 Milan Jurik. All rights reserved.
25 */
26
27
28 #include <alloca.h>
29 #include <assert.h>
30 #include <ctype.h>
31 #include <door.h>
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <fnmatch.h>
35 #include <inttypes.h>
36 #include <libintl.h>
37 #include <libnvpair.h>
38 #include <libscf.h>
39 #include <libscf_priv.h>
40 #include <libtecla.h>
41 #include <libuutil.h>
42 #include <limits.h>
43 #include <locale.h>
44 #include <stdarg.h>
45 #include <string.h>
46 #include <strings.h>
47 #include <unistd.h>
48 #include <wait.h>
49 #include <poll.h>
50
51 #include <libxml/tree.h>
52
53 #include <sys/param.h>
54
55 #include <sys/stat.h>
56 #include <sys/mman.h>
57
58 #include "svccfg.h"
59 #include "notify_params.h"
60 #include "manifest_hash.h"
61 #include "manifest_find.h"
62
63 /* The colon namespaces in each entity (each followed by a newline). */
64 #define COLON_NAMESPACES ":properties\n"
65
66 #define TEMP_FILE_PATTERN "/tmp/svccfg-XXXXXX"
67
68 /* These are characters which the lexer requires to be in double-quotes. */
69 #define CHARS_TO_QUOTE " \t\n\\>=\"()"
70
71 #define HASH_SIZE 16
72 #define HASH_PG_TYPE "framework"
73 #define HASH_PG_FLAGS 0
74 #define HASH_PROP "md5sum"
75
76 /*
77 * Indentation used in the output of the describe subcommand.
78 */
79 #define TMPL_VALUE_INDENT " "
80 #define TMPL_INDENT " "
81 #define TMPL_INDENT_2X " "
82 #define TMPL_CHOICE_INDENT " "
83
84 /*
85 * Directory locations for manifests
86 */
87 #define VARSVC_DIR "/var/svc/manifest"
88 #define LIBSVC_DIR "/lib/svc/manifest"
89 #define VARSVC_PR "var_svc_manifest"
90 #define LIBSVC_PR "lib_svc_manifest"
91 #define MFSTFILEPR "manifestfile"
92
93 #define SUPPORTPROP "support"
94
95 #define MFSTHISTFILE "/lib/svc/share/mfsthistory"
96
97 #define MFSTFILE_MAX 16
98
99 /*
100 * These are the classes of elements which may appear as children of service
101 * or instance elements in XML manifests.
102 */
103 struct entity_elts {
104 xmlNodePtr create_default_instance;
105 xmlNodePtr single_instance;
106 xmlNodePtr restarter;
107 xmlNodePtr dependencies;
108 xmlNodePtr dependents;
109 xmlNodePtr method_context;
110 xmlNodePtr exec_methods;
111 xmlNodePtr notify_params;
112 xmlNodePtr property_groups;
113 xmlNodePtr instances;
114 xmlNodePtr stability;
115 xmlNodePtr template;
116 };
117
118 /*
119 * Likewise for property_group elements.
120 */
121 struct pg_elts {
122 xmlNodePtr stability;
123 xmlNodePtr propvals;
124 xmlNodePtr properties;
125 };
126
127 /*
128 * Likewise for template elements.
129 */
130 struct template_elts {
131 xmlNodePtr common_name;
132 xmlNodePtr description;
133 xmlNodePtr documentation;
134 };
135
136 /*
137 * Likewise for type (for notification parameters) elements.
138 */
139 struct params_elts {
140 xmlNodePtr paramval;
141 xmlNodePtr parameter;
142 };
143
144 /*
145 * This structure is for snaplevel lists. They are convenient because libscf
146 * only allows traversing snaplevels in one direction.
147 */
148 struct snaplevel {
149 uu_list_node_t list_node;
150 scf_snaplevel_t *sl;
151 };
152
153 /*
154 * This is used for communication between lscf_service_export and
155 * export_callback.
156 */
157 struct export_args {
158 const char *filename;
159 int flags;
160 };
161
162 /*
163 * The service_manifest structure is used by the upgrade process
164 * to create a list of service to manifest linkages from the manifests
165 * in a set of given directories.
166 */
167 typedef struct service_manifest {
168 const char *servicename;
169 uu_list_t *mfstlist;
170 size_t mfstlist_sz;
171
172 uu_avl_node_t svcmfst_node;
173 } service_manifest_t;
174
175 /*
176 * Structure to track the manifest file property group
177 * and the manifest file associated with that property
178 * group. Also, a flag to keep the access once it has
179 * been checked.
180 */
181 struct mpg_mfile {
182 char *mpg;
183 char *mfile;
184 int access;
185 };
186
187 const char * const scf_pg_general = SCF_PG_GENERAL;
188 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
189 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
190 const char * const scf_property_external = "external";
191
192 const char * const snap_initial = "initial";
193 const char * const snap_lastimport = "last-import";
194 const char * const snap_previous = "previous";
195 const char * const snap_running = "running";
196
197 scf_handle_t *g_hndl = NULL; /* only valid after lscf_prep_hndl() */
198
199 ssize_t max_scf_fmri_len;
200 ssize_t max_scf_name_len;
201 ssize_t max_scf_pg_type_len;
202 ssize_t max_scf_value_len;
203 static size_t max_scf_len;
204
205 static scf_scope_t *cur_scope;
206 static scf_service_t *cur_svc = NULL;
207 static scf_instance_t *cur_inst = NULL;
208 static scf_snapshot_t *cur_snap = NULL;
209 static scf_snaplevel_t *cur_level = NULL;
210
211 static uu_list_pool_t *snaplevel_pool;
212 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
213 static uu_list_t *cur_levels;
214 static struct snaplevel *cur_elt; /* cur_elt->sl == cur_level */
215
216 static FILE *tempfile = NULL;
217 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
218
219 static const char *emsg_entity_not_selected;
220 static const char *emsg_permission_denied;
221 static const char *emsg_create_xml;
222 static const char *emsg_cant_modify_snapshots;
223 static const char *emsg_invalid_for_snapshot;
224 static const char *emsg_read_only;
225 static const char *emsg_deleted;
226 static const char *emsg_invalid_pg_name;
227 static const char *emsg_invalid_prop_name;
228 static const char *emsg_no_such_pg;
229 static const char *emsg_fmri_invalid_pg_name;
230 static const char *emsg_fmri_invalid_pg_name_type;
231 static const char *emsg_pg_added;
232 static const char *emsg_pg_changed;
233 static const char *emsg_pg_deleted;
234 static const char *emsg_pg_mod_perm;
235 static const char *emsg_pg_add_perm;
236 static const char *emsg_pg_del_perm;
237 static const char *emsg_snap_perm;
238 static const char *emsg_dpt_dangling;
239 static const char *emsg_dpt_no_dep;
240
241 static int li_only = 0;
242 static int no_refresh = 0;
243
244 /* import globals, to minimize allocations */
245 static scf_scope_t *imp_scope = NULL;
246 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
247 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
248 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
249 static scf_snapshot_t *imp_rsnap = NULL;
250 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
251 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
252 static scf_property_t *imp_prop = NULL;
253 static scf_iter_t *imp_iter = NULL;
254 static scf_iter_t *imp_rpg_iter = NULL;
255 static scf_iter_t *imp_up_iter = NULL;
256 static scf_transaction_t *imp_tx = NULL; /* always reset this */
257 static char *imp_str = NULL;
258 static size_t imp_str_sz;
259 static char *imp_tsname = NULL;
260 static char *imp_fe1 = NULL; /* for fmri_equal() */
261 static char *imp_fe2 = NULL;
262 static uu_list_t *imp_deleted_dpts = NULL; /* pgroup_t's to refresh */
263
264 /* upgrade_dependents() globals */
265 static scf_instance_t *ud_inst = NULL;
266 static scf_snaplevel_t *ud_snpl = NULL;
267 static scf_propertygroup_t *ud_pg = NULL;
268 static scf_propertygroup_t *ud_cur_depts_pg = NULL;
269 static scf_propertygroup_t *ud_run_dpts_pg = NULL;
270 static int ud_run_dpts_pg_set = 0;
271 static scf_property_t *ud_prop = NULL;
272 static scf_property_t *ud_dpt_prop = NULL;
273 static scf_value_t *ud_val = NULL;
274 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
275 static scf_transaction_t *ud_tx = NULL;
276 static char *ud_ctarg = NULL;
277 static char *ud_oldtarg = NULL;
278 static char *ud_name = NULL;
279
280 /* export globals */
281 static scf_instance_t *exp_inst;
282 static scf_propertygroup_t *exp_pg;
283 static scf_property_t *exp_prop;
284 static scf_value_t *exp_val;
285 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
286 static char *exp_str;
287 static size_t exp_str_sz;
288
289 /* cleanup globals */
290 static uu_avl_pool_t *service_manifest_pool = NULL;
291 static uu_avl_t *service_manifest_tree = NULL;
292
293 static void scfdie_lineno(int lineno) __NORETURN;
294
295 static char *start_method_names[] = {
296 "start",
297 "inetd_start",
298 NULL
299 };
300
301 static struct uri_scheme {
302 const char *scheme;
303 const char *protocol;
304 } uri_scheme[] = {
305 { "mailto", "smtp" },
306 { "snmp", "snmp" },
307 { "syslog", "syslog" },
308 { NULL, NULL }
309 };
310 #define URI_SCHEME_NUM ((sizeof (uri_scheme) / \
311 sizeof (struct uri_scheme)) - 1)
312
313 static int
314 check_uri_scheme(const char *scheme)
315 {
316 int i;
317
318 for (i = 0; uri_scheme[i].scheme != NULL; ++i) {
319 if (strcmp(scheme, uri_scheme[i].scheme) == 0)
320 return (i);
321 }
322
323 return (-1);
324 }
325
326 static int
327 check_uri_protocol(const char *p)
328 {
329 int i;
330
331 for (i = 0; uri_scheme[i].protocol != NULL; ++i) {
332 if (strcmp(p, uri_scheme[i].protocol) == 0)
333 return (i);
334 }
335
336 return (-1);
337 }
338
339 /*
340 * For unexpected libscf errors.
341 */
342 #ifdef NDEBUG
343
344 static void scfdie(void) __NORETURN;
345
346 static void
347 scfdie(void)
348 {
349 scf_error_t err = scf_error();
350
351 if (err == SCF_ERROR_CONNECTION_BROKEN)
352 uu_die(gettext("Repository connection broken. Exiting.\n"));
353
354 uu_die(gettext("Unexpected fatal libscf error: %s. Exiting.\n"),
355 scf_strerror(err));
356 }
357
358 #else
359
360 #define scfdie() scfdie_lineno(__LINE__)
361
362 static void
363 scfdie_lineno(int lineno)
364 {
365 scf_error_t err = scf_error();
366
367 if (err == SCF_ERROR_CONNECTION_BROKEN)
368 uu_die(gettext("Repository connection broken. Exiting.\n"));
369
370 uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
371 ": %s.\n"), lineno, scf_strerror(err));
372 }
373
374 #endif
375
376 static void
377 scfwarn(void)
378 {
379 warn(gettext("Unexpected libscf error: %s.\n"),
380 scf_strerror(scf_error()));
381 }
382
383 /*
384 * Clear a field of a structure.
385 */
386 static int
387 clear_int(void *a, void *b)
388 {
389 /* LINTED */
390 *(int *)((char *)a + (size_t)b) = 0;
391
392 return (UU_WALK_NEXT);
393 }
394
395 static int
396 scferror2errno(scf_error_t err)
397 {
398 switch (err) {
399 case SCF_ERROR_BACKEND_ACCESS:
400 return (EACCES);
401
402 case SCF_ERROR_BACKEND_READONLY:
403 return (EROFS);
404
405 case SCF_ERROR_CONNECTION_BROKEN:
406 return (ECONNABORTED);
407
408 case SCF_ERROR_CONSTRAINT_VIOLATED:
409 case SCF_ERROR_INVALID_ARGUMENT:
410 return (EINVAL);
411
412 case SCF_ERROR_DELETED:
413 return (ECANCELED);
414
415 case SCF_ERROR_EXISTS:
416 return (EEXIST);
417
418 case SCF_ERROR_NO_MEMORY:
419 return (ENOMEM);
420
421 case SCF_ERROR_NO_RESOURCES:
422 return (ENOSPC);
423
424 case SCF_ERROR_NOT_FOUND:
425 return (ENOENT);
426
427 case SCF_ERROR_PERMISSION_DENIED:
428 return (EPERM);
429
430 default:
431 #ifndef NDEBUG
432 (void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
433 __FILE__, __LINE__, err);
434 #else
435 (void) fprintf(stderr, "Unknown libscf error %d.\n", err);
436 #endif
437 abort();
438 /* NOTREACHED */
439 }
440 }
441
442 static int
443 entity_get_pg(void *ent, int issvc, const char *name,
444 scf_propertygroup_t *pg)
445 {
446 if (issvc)
447 return (scf_service_get_pg(ent, name, pg));
448 else
449 return (scf_instance_get_pg(ent, name, pg));
450 }
451
452 static void
453 entity_destroy(void *ent, int issvc)
454 {
455 if (issvc)
456 scf_service_destroy(ent);
457 else
458 scf_instance_destroy(ent);
459 }
460
461 static int
462 get_pg(const char *pg_name, scf_propertygroup_t *pg)
463 {
464 int ret;
465
466 if (cur_level != NULL)
467 ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
468 else if (cur_inst != NULL)
469 ret = scf_instance_get_pg(cur_inst, pg_name, pg);
470 else
471 ret = scf_service_get_pg(cur_svc, pg_name, pg);
472
473 return (ret);
474 }
475
476 /*
477 * Find a snaplevel in a snapshot. If get_svc is true, find the service
478 * snaplevel. Otherwise find the instance snaplevel.
479 *
480 * Returns
481 * 0 - success
482 * ECONNABORTED - repository connection broken
483 * ECANCELED - instance containing snap was deleted
484 * ENOENT - snap has no snaplevels
485 * - requested snaplevel not found
486 */
487 static int
488 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
489 {
490 if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
491 switch (scf_error()) {
492 case SCF_ERROR_CONNECTION_BROKEN:
493 case SCF_ERROR_DELETED:
494 case SCF_ERROR_NOT_FOUND:
495 return (scferror2errno(scf_error()));
496
497 case SCF_ERROR_HANDLE_MISMATCH:
498 case SCF_ERROR_NOT_BOUND:
499 case SCF_ERROR_NOT_SET:
500 default:
501 bad_error("scf_snapshot_get_base_snaplevel",
502 scf_error());
503 }
504 }
505
506 for (;;) {
507 ssize_t ssz;
508
509 ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
510 if (ssz >= 0) {
511 if (!get_svc)
512 return (0);
513 } else {
514 switch (scf_error()) {
515 case SCF_ERROR_CONSTRAINT_VIOLATED:
516 if (get_svc)
517 return (0);
518 break;
519
520 case SCF_ERROR_DELETED:
521 case SCF_ERROR_CONNECTION_BROKEN:
522 return (scferror2errno(scf_error()));
523
524 case SCF_ERROR_NOT_SET:
525 case SCF_ERROR_NOT_BOUND:
526 default:
527 bad_error("scf_snaplevel_get_instance_name",
528 scf_error());
529 }
530 }
531
532 if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
533 switch (scf_error()) {
534 case SCF_ERROR_NOT_FOUND:
535 case SCF_ERROR_CONNECTION_BROKEN:
536 case SCF_ERROR_DELETED:
537 return (scferror2errno(scf_error()));
538
539 case SCF_ERROR_HANDLE_MISMATCH:
540 case SCF_ERROR_NOT_BOUND:
541 case SCF_ERROR_NOT_SET:
542 case SCF_ERROR_INVALID_ARGUMENT:
543 default:
544 bad_error("scf_snaplevel_get_next_snaplevel",
545 scf_error());
546 }
547 }
548 }
549 }
550
551 /*
552 * If issvc is 0, take ent to be a pointer to an scf_instance_t. If it has
553 * a running snapshot, and that snapshot has an instance snaplevel, set pg to
554 * the property group named name in it. If it doesn't have a running
555 * snapshot, set pg to the instance's current property group named name.
556 *
557 * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
558 * its instances. If one has a running snapshot with a service snaplevel, set
559 * pg to the property group named name in it. If no such snaplevel could be
560 * found, set pg to the service's current property group named name.
561 *
562 * iter, inst, snap, and snpl are required scratch objects.
563 *
564 * Returns
565 * 0 - success
566 * ECONNABORTED - repository connection broken
567 * ECANCELED - ent was deleted
568 * ENOENT - no such property group
569 * EINVAL - name is an invalid property group name
570 * EBADF - found running snapshot is missing a snaplevel
571 */
572 static int
573 entity_get_running_pg(void *ent, int issvc, const char *name,
574 scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
575 scf_snapshot_t *snap, scf_snaplevel_t *snpl)
576 {
577 int r;
578
579 if (issvc) {
580 /* Search for an instance with a running snapshot. */
581 if (scf_iter_service_instances(iter, ent) != 0) {
582 switch (scf_error()) {
583 case SCF_ERROR_DELETED:
584 case SCF_ERROR_CONNECTION_BROKEN:
585 return (scferror2errno(scf_error()));
586
587 case SCF_ERROR_NOT_SET:
588 case SCF_ERROR_NOT_BOUND:
589 case SCF_ERROR_HANDLE_MISMATCH:
590 default:
591 bad_error("scf_iter_service_instances",
592 scf_error());
593 }
594 }
595
596 for (;;) {
597 r = scf_iter_next_instance(iter, inst);
598 if (r == 0) {
599 if (scf_service_get_pg(ent, name, pg) == 0)
600 return (0);
601
602 switch (scf_error()) {
603 case SCF_ERROR_DELETED:
604 case SCF_ERROR_NOT_FOUND:
605 case SCF_ERROR_INVALID_ARGUMENT:
606 case SCF_ERROR_CONNECTION_BROKEN:
607 return (scferror2errno(scf_error()));
608
609 case SCF_ERROR_NOT_BOUND:
610 case SCF_ERROR_HANDLE_MISMATCH:
611 case SCF_ERROR_NOT_SET:
612 default:
613 bad_error("scf_service_get_pg",
614 scf_error());
615 }
616 }
617 if (r != 1) {
618 switch (scf_error()) {
619 case SCF_ERROR_DELETED:
620 case SCF_ERROR_CONNECTION_BROKEN:
621 return (scferror2errno(scf_error()));
622
623 case SCF_ERROR_INVALID_ARGUMENT:
624 case SCF_ERROR_NOT_SET:
625 case SCF_ERROR_NOT_BOUND:
626 case SCF_ERROR_HANDLE_MISMATCH:
627 default:
628 bad_error("scf_iter_next_instance",
629 scf_error());
630 }
631 }
632
633 if (scf_instance_get_snapshot(inst, snap_running,
634 snap) == 0)
635 break;
636
637 switch (scf_error()) {
638 case SCF_ERROR_NOT_FOUND:
639 case SCF_ERROR_DELETED:
640 continue;
641
642 case SCF_ERROR_CONNECTION_BROKEN:
643 return (ECONNABORTED);
644
645 case SCF_ERROR_HANDLE_MISMATCH:
646 case SCF_ERROR_INVALID_ARGUMENT:
647 case SCF_ERROR_NOT_SET:
648 case SCF_ERROR_NOT_BOUND:
649 default:
650 bad_error("scf_instance_get_snapshot",
651 scf_error());
652 }
653 }
654 } else {
655 if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
656 switch (scf_error()) {
657 case SCF_ERROR_NOT_FOUND:
658 break;
659
660 case SCF_ERROR_DELETED:
661 case SCF_ERROR_CONNECTION_BROKEN:
662 return (scferror2errno(scf_error()));
663
664 case SCF_ERROR_NOT_BOUND:
665 case SCF_ERROR_HANDLE_MISMATCH:
666 case SCF_ERROR_INVALID_ARGUMENT:
667 case SCF_ERROR_NOT_SET:
668 default:
669 bad_error("scf_instance_get_snapshot",
670 scf_error());
671 }
672
673 if (scf_instance_get_pg(ent, name, pg) == 0)
674 return (0);
675
676 switch (scf_error()) {
677 case SCF_ERROR_DELETED:
678 case SCF_ERROR_NOT_FOUND:
679 case SCF_ERROR_INVALID_ARGUMENT:
680 case SCF_ERROR_CONNECTION_BROKEN:
681 return (scferror2errno(scf_error()));
682
683 case SCF_ERROR_NOT_BOUND:
684 case SCF_ERROR_HANDLE_MISMATCH:
685 case SCF_ERROR_NOT_SET:
686 default:
687 bad_error("scf_instance_get_pg", scf_error());
688 }
689 }
690 }
691
692 r = get_snaplevel(snap, issvc, snpl);
693 switch (r) {
694 case 0:
695 break;
696
697 case ECONNABORTED:
698 case ECANCELED:
699 return (r);
700
701 case ENOENT:
702 return (EBADF);
703
704 default:
705 bad_error("get_snaplevel", r);
706 }
707
708 if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
709 return (0);
710
711 switch (scf_error()) {
712 case SCF_ERROR_DELETED:
713 case SCF_ERROR_INVALID_ARGUMENT:
714 case SCF_ERROR_CONNECTION_BROKEN:
715 case SCF_ERROR_NOT_FOUND:
716 return (scferror2errno(scf_error()));
717
718 case SCF_ERROR_NOT_BOUND:
719 case SCF_ERROR_HANDLE_MISMATCH:
720 case SCF_ERROR_NOT_SET:
721 default:
722 bad_error("scf_snaplevel_get_pg", scf_error());
723 /* NOTREACHED */
724 }
725 }
726
727 /*
728 * To be registered with atexit().
729 */
730 static void
731 remove_tempfile(void)
732 {
733 int ret;
734
735 if (tempfile != NULL) {
736 if (fclose(tempfile) == EOF)
737 (void) warn(gettext("Could not close temporary file"));
738 tempfile = NULL;
739 }
740
741 if (tempfilename[0] != '\0') {
742 do {
743 ret = remove(tempfilename);
744 } while (ret == -1 && errno == EINTR);
745 if (ret == -1)
746 warn(gettext("Could not remove temporary file"));
747 tempfilename[0] = '\0';
748 }
749 }
750
751 /*
752 * Launch private svc.configd(1M) for manipulating alternate repositories.
753 */
754 static void
755 start_private_repository(engine_state_t *est)
756 {
757 int fd, stat;
758 struct door_info info;
759 pid_t pid;
760
761 /*
762 * 1. Create a temporary file for the door.
763 */
764 if (est->sc_repo_doorname != NULL)
765 free((void *)est->sc_repo_doorname);
766
767 est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
768 if (est->sc_repo_doorname == NULL)
769 uu_die(gettext("Could not acquire temporary filename"));
770
771 fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
772 if (fd < 0)
773 uu_die(gettext("Could not create temporary file for "
774 "repository server"));
775
776 (void) close(fd);
777
778 /*
779 * 2. Launch a configd with that door, using the specified
780 * repository.
781 */
782 if ((est->sc_repo_pid = fork()) == 0) {
783 (void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
784 "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
785 NULL);
786 uu_die(gettext("Could not execute %s"), est->sc_repo_server);
787 } else if (est->sc_repo_pid == -1)
788 uu_die(gettext("Attempt to fork failed"));
789
790 do {
791 pid = waitpid(est->sc_repo_pid, &stat, 0);
792 } while (pid == -1 && errno == EINTR);
793
794 if (pid == -1)
795 uu_die(gettext("Could not waitpid() for repository server"));
796
797 if (!WIFEXITED(stat)) {
798 uu_die(gettext("Repository server failed (status %d).\n"),
799 stat);
800 } else if (WEXITSTATUS(stat) != 0) {
801 uu_die(gettext("Repository server failed (exit %d).\n"),
802 WEXITSTATUS(stat));
803 }
804
805 /*
806 * See if it was successful by checking if the door is a door.
807 */
808
809 fd = open(est->sc_repo_doorname, O_RDWR);
810 if (fd < 0)
811 uu_die(gettext("Could not open door \"%s\""),
812 est->sc_repo_doorname);
813
814 if (door_info(fd, &info) < 0)
815 uu_die(gettext("Unexpected door_info() error"));
816
817 if (close(fd) == -1)
818 warn(gettext("Could not close repository door"),
819 strerror(errno));
820
821 est->sc_repo_pid = info.di_target;
822 }
823
824 void
825 lscf_cleanup(void)
826 {
827 /*
828 * In the case where we've launched a private svc.configd(1M)
829 * instance, we must terminate our child and remove the temporary
830 * rendezvous point.
831 */
832 if (est->sc_repo_pid > 0) {
833 (void) kill(est->sc_repo_pid, SIGTERM);
834 (void) waitpid(est->sc_repo_pid, NULL, 0);
835 (void) unlink(est->sc_repo_doorname);
836
837 est->sc_repo_pid = 0;
838 }
839 }
840
841 void
842 unselect_cursnap(void)
843 {
844 void *cookie;
845
846 cur_level = NULL;
847
848 cookie = NULL;
849 while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
850 scf_snaplevel_destroy(cur_elt->sl);
851 free(cur_elt);
852 }
853
854 scf_snapshot_destroy(cur_snap);
855 cur_snap = NULL;
856 }
857
858 void
859 lscf_prep_hndl(void)
860 {
861 if (g_hndl != NULL)
862 return;
863
864 g_hndl = scf_handle_create(SCF_VERSION);
865 if (g_hndl == NULL)
866 scfdie();
867
868 if (est->sc_repo_filename != NULL)
869 start_private_repository(est);
870
871 if (est->sc_repo_doorname != NULL) {
872 scf_value_t *repo_value;
873 int ret;
874
875 repo_value = scf_value_create(g_hndl);
876 if (repo_value == NULL)
877 scfdie();
878
879 ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
880 assert(ret == SCF_SUCCESS);
881
882 if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
883 SCF_SUCCESS)
884 scfdie();
885
886 scf_value_destroy(repo_value);
887 }
888
889 if (scf_handle_bind(g_hndl) != 0)
890 uu_die(gettext("Could not connect to repository server: %s.\n"),
891 scf_strerror(scf_error()));
892
893 cur_scope = scf_scope_create(g_hndl);
894 if (cur_scope == NULL)
895 scfdie();
896
897 if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
898 scfdie();
899 }
900
901 static void
902 repository_teardown(void)
903 {
904 if (g_hndl != NULL) {
905 if (cur_snap != NULL)
906 unselect_cursnap();
907 scf_instance_destroy(cur_inst);
908 scf_service_destroy(cur_svc);
909 scf_scope_destroy(cur_scope);
910 scf_handle_destroy(g_hndl);
911 cur_inst = NULL;
912 cur_svc = NULL;
913 cur_scope = NULL;
914 g_hndl = NULL;
915 lscf_cleanup();
916 }
917 }
918
919 void
920 lscf_set_repository(const char *repfile, int force)
921 {
922 repository_teardown();
923
924 if (est->sc_repo_filename != NULL) {
925 free((void *)est->sc_repo_filename);
926 est->sc_repo_filename = NULL;
927 }
928
929 if ((force == 0) && (access(repfile, R_OK) != 0)) {
930 /*
931 * Repository file does not exist
932 * or has no read permission.
933 */
934 warn(gettext("Cannot access \"%s\": %s\n"),
935 repfile, strerror(errno));
936 } else {
937 est->sc_repo_filename = safe_strdup(repfile);
938 }
939
940 lscf_prep_hndl();
941 }
942
943 void
944 lscf_init()
945 {
946 if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
947 (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
948 (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
949 0 ||
950 (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
951 scfdie();
952
953 max_scf_len = max_scf_fmri_len;
954 if (max_scf_name_len > max_scf_len)
955 max_scf_len = max_scf_name_len;
956 if (max_scf_pg_type_len > max_scf_len)
957 max_scf_len = max_scf_pg_type_len;
958 /*
959 * When a value of type opaque is represented as a string, the
960 * string contains 2 characters for every byte of data. That is
961 * because the string contains the hex representation of the opaque
962 * value.
963 */
964 if (2 * max_scf_value_len > max_scf_len)
965 max_scf_len = 2 * max_scf_value_len;
966
967 if (atexit(remove_tempfile) != 0)
968 uu_die(gettext("Could not register atexit() function"));
969
970 emsg_entity_not_selected = gettext("An entity is not selected.\n");
971 emsg_permission_denied = gettext("Permission denied.\n");
972 emsg_create_xml = gettext("Could not create XML node.\n");
973 emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
974 emsg_invalid_for_snapshot =
975 gettext("Invalid operation on a snapshot.\n");
976 emsg_read_only = gettext("Backend read-only.\n");
977 emsg_deleted = gettext("Current selection has been deleted.\n");
978 emsg_invalid_pg_name =
979 gettext("Invalid property group name \"%s\".\n");
980 emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
981 emsg_no_such_pg = gettext("No such property group \"%s\".\n");
982 emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
983 "with invalid name \"%s\".\n");
984 emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
985 "group with invalid name \"%s\" or type \"%s\".\n");
986 emsg_pg_added = gettext("%s changed unexpectedly "
987 "(property group \"%s\" added).\n");
988 emsg_pg_changed = gettext("%s changed unexpectedly "
989 "(property group \"%s\" changed).\n");
990 emsg_pg_deleted = gettext("%s changed unexpectedly "
991 "(property group \"%s\" or an ancestor was deleted).\n");
992 emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
993 "in %s (permission denied).\n");
994 emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
995 "in %s (permission denied).\n");
996 emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
997 "in %s (permission denied).\n");
998 emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
999 "(permission denied).\n");
1000 emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
1001 "new dependent \"%s\" because it already exists). Warning: The "
1002 "current dependent's target (%s) does not exist.\n");
1003 emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
1004 "dependent \"%s\" because it already exists). Warning: The "
1005 "current dependent's target (%s) does not have a dependency named "
1006 "\"%s\" as expected.\n");
1007
1008 string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
1009 offsetof(string_list_t, node), NULL, 0);
1010 snaplevel_pool = uu_list_pool_create("snaplevels",
1011 sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
1012 NULL, 0);
1013 }
1014
1015
1016 static const char *
1017 prop_to_typestr(const scf_property_t *prop)
1018 {
1019 scf_type_t ty;
1020
1021 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
1022 scfdie();
1023
1024 return (scf_type_to_string(ty));
1025 }
1026
1027 static scf_type_t
1028 string_to_type(const char *type)
1029 {
1030 size_t len = strlen(type);
1031 char *buf;
1032
1033 if (len == 0 || type[len - 1] != ':')
1034 return (SCF_TYPE_INVALID);
1035
1036 buf = (char *)alloca(len + 1);
1037 (void) strlcpy(buf, type, len + 1);
1038 buf[len - 1] = 0;
1039
1040 return (scf_string_to_type(buf));
1041 }
1042
1043 static scf_value_t *
1044 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
1045 {
1046 scf_value_t *v;
1047 char *dup, *nstr;
1048 size_t len;
1049
1050 v = scf_value_create(g_hndl);
1051 if (v == NULL)
1052 scfdie();
1053
1054 len = strlen(str);
1055 if (require_quotes &&
1056 (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
1057 semerr(gettext("Multiple string values or string values "
1058 "with spaces must be quoted with '\"'.\n"));
1059 scf_value_destroy(v);
1060 return (NULL);
1061 }
1062
1063 nstr = dup = safe_strdup(str);
1064 if (dup[0] == '\"') {
1065 /*
1066 * Strip out the first and the last quote.
1067 */
1068 dup[len - 1] = '\0';
1069 nstr = dup + 1;
1070 }
1071
1072 if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
1073 assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1074 semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1075 scf_type_to_string(ty), nstr);
1076 scf_value_destroy(v);
1077 v = NULL;
1078 }
1079 free(dup);
1080 return (v);
1081 }
1082
1083 /*
1084 * Print str to strm, quoting double-quotes and backslashes with backslashes.
1085 * Optionally append a comment prefix ('#') to newlines ('\n').
1086 */
1087 static int
1088 quote_and_print(const char *str, FILE *strm, int commentnl)
1089 {
1090 const char *cp;
1091
1092 for (cp = str; *cp != '\0'; ++cp) {
1093 if (*cp == '"' || *cp == '\\')
1094 (void) putc('\\', strm);
1095
1096 (void) putc(*cp, strm);
1097
1098 if (commentnl && *cp == '\n') {
1099 (void) putc('#', strm);
1100 }
1101 }
1102
1103 return (ferror(strm));
1104 }
1105
1106 /*
1107 * These wrappers around lowlevel functions provide consistent error checking
1108 * and warnings.
1109 */
1110 static int
1111 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1112 {
1113 if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1114 return (0);
1115
1116 if (scf_error() != SCF_ERROR_NOT_FOUND)
1117 scfdie();
1118
1119 if (g_verbose) {
1120 ssize_t len;
1121 char *fmri;
1122
1123 len = scf_pg_to_fmri(pg, NULL, 0);
1124 if (len < 0)
1125 scfdie();
1126
1127 fmri = safe_malloc(len + 1);
1128
1129 if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1130 scfdie();
1131
1132 warn(gettext("Expected property %s of property group %s is "
1133 "missing.\n"), propname, fmri);
1134
1135 free(fmri);
1136 }
1137
1138 return (-1);
1139 }
1140
1141 static int
1142 prop_check_type(scf_property_t *prop, scf_type_t ty)
1143 {
1144 scf_type_t pty;
1145
1146 if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1147 scfdie();
1148
1149 if (ty == pty)
1150 return (0);
1151
1152 if (g_verbose) {
1153 ssize_t len;
1154 char *fmri;
1155 const char *tystr;
1156
1157 len = scf_property_to_fmri(prop, NULL, 0);
1158 if (len < 0)
1159 scfdie();
1160
1161 fmri = safe_malloc(len + 1);
1162
1163 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1164 scfdie();
1165
1166 tystr = scf_type_to_string(ty);
1167 if (tystr == NULL)
1168 tystr = "?";
1169
1170 warn(gettext("Property %s is not of expected type %s.\n"),
1171 fmri, tystr);
1172
1173 free(fmri);
1174 }
1175
1176 return (-1);
1177 }
1178
1179 static int
1180 prop_get_val(scf_property_t *prop, scf_value_t *val)
1181 {
1182 scf_error_t err;
1183
1184 if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1185 return (0);
1186
1187 err = scf_error();
1188
1189 if (err != SCF_ERROR_NOT_FOUND &&
1190 err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1191 err != SCF_ERROR_PERMISSION_DENIED)
1192 scfdie();
1193
1194 if (g_verbose) {
1195 ssize_t len;
1196 char *fmri, *emsg;
1197
1198 len = scf_property_to_fmri(prop, NULL, 0);
1199 if (len < 0)
1200 scfdie();
1201
1202 fmri = safe_malloc(len + 1);
1203
1204 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1205 scfdie();
1206
1207 if (err == SCF_ERROR_NOT_FOUND)
1208 emsg = gettext("Property %s has no values; expected "
1209 "one.\n");
1210 else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1211 emsg = gettext("Property %s has multiple values; "
1212 "expected one.\n");
1213 else
1214 emsg = gettext("No permission to read property %s.\n");
1215
1216 warn(emsg, fmri);
1217
1218 free(fmri);
1219 }
1220
1221 return (-1);
1222 }
1223
1224
1225 static boolean_t
1226 snaplevel_is_instance(const scf_snaplevel_t *level)
1227 {
1228 if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1229 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1230 scfdie();
1231 return (0);
1232 } else {
1233 return (1);
1234 }
1235 }
1236
1237 /*
1238 * Decode FMRI into a service or instance, and put the result in *ep. If
1239 * memory cannot be allocated, return SCF_ERROR_NO_MEMORY. If the FMRI is
1240 * invalid, return SCF_ERROR_INVALID_ARGUMENT. If the FMRI does not specify
1241 * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED. If the entity cannot be
1242 * found, return SCF_ERROR_NOT_FOUND. Otherwise return SCF_ERROR_NONE, point
1243 * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1244 * whether *ep is a service.
1245 */
1246 static scf_error_t
1247 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1248 {
1249 char *fmri_copy;
1250 const char *sstr, *istr, *pgstr;
1251 scf_service_t *svc;
1252 scf_instance_t *inst;
1253
1254 fmri_copy = strdup(fmri);
1255 if (fmri_copy == NULL)
1256 return (SCF_ERROR_NO_MEMORY);
1257
1258 if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1259 SCF_SUCCESS) {
1260 free(fmri_copy);
1261 return (SCF_ERROR_INVALID_ARGUMENT);
1262 }
1263
1264 free(fmri_copy);
1265
1266 if (sstr == NULL || pgstr != NULL)
1267 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1268
1269 if (istr == NULL) {
1270 svc = scf_service_create(h);
1271 if (svc == NULL)
1272 return (SCF_ERROR_NO_MEMORY);
1273
1274 if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1275 SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1276 if (scf_error() != SCF_ERROR_NOT_FOUND)
1277 scfdie();
1278
1279 return (SCF_ERROR_NOT_FOUND);
1280 }
1281
1282 *ep = svc;
1283 *isservice = 1;
1284 } else {
1285 inst = scf_instance_create(h);
1286 if (inst == NULL)
1287 return (SCF_ERROR_NO_MEMORY);
1288
1289 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1290 NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1291 if (scf_error() != SCF_ERROR_NOT_FOUND)
1292 scfdie();
1293
1294 return (SCF_ERROR_NOT_FOUND);
1295 }
1296
1297 *ep = inst;
1298 *isservice = 0;
1299 }
1300
1301 return (SCF_ERROR_NONE);
1302 }
1303
1304 /*
1305 * Create the entity named by fmri. Place a pointer to its libscf handle in
1306 * *ep, and set or clear *isservicep if it is a service or an instance.
1307 * Returns
1308 * SCF_ERROR_NONE - success
1309 * SCF_ERROR_NO_MEMORY - scf_*_create() failed
1310 * SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1311 * SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1312 * SCF_ERROR_NOT_FOUND - no such scope
1313 * SCF_ERROR_PERMISSION_DENIED
1314 * SCF_ERROR_BACKEND_READONLY
1315 * SCF_ERROR_BACKEND_ACCESS
1316 */
1317 static scf_error_t
1318 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1319 {
1320 char *fmri_copy;
1321 const char *scstr, *sstr, *istr, *pgstr;
1322 scf_scope_t *scope = NULL;
1323 scf_service_t *svc = NULL;
1324 scf_instance_t *inst = NULL;
1325 scf_error_t scfe;
1326
1327 fmri_copy = safe_strdup(fmri);
1328
1329 if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1330 0) {
1331 free(fmri_copy);
1332 return (SCF_ERROR_INVALID_ARGUMENT);
1333 }
1334
1335 if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1336 free(fmri_copy);
1337 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1338 }
1339
1340 *ep = NULL;
1341
1342 if ((scope = scf_scope_create(h)) == NULL ||
1343 (svc = scf_service_create(h)) == NULL ||
1344 (inst = scf_instance_create(h)) == NULL) {
1345 scfe = SCF_ERROR_NO_MEMORY;
1346 goto out;
1347 }
1348
1349 get_scope:
1350 if (scf_handle_get_scope(h, scstr, scope) != 0) {
1351 switch (scf_error()) {
1352 case SCF_ERROR_CONNECTION_BROKEN:
1353 scfdie();
1354 /* NOTREACHED */
1355
1356 case SCF_ERROR_NOT_FOUND:
1357 scfe = SCF_ERROR_NOT_FOUND;
1358 goto out;
1359
1360 case SCF_ERROR_HANDLE_MISMATCH:
1361 case SCF_ERROR_NOT_BOUND:
1362 case SCF_ERROR_INVALID_ARGUMENT:
1363 default:
1364 bad_error("scf_handle_get_scope", scf_error());
1365 }
1366 }
1367
1368 get_svc:
1369 if (scf_scope_get_service(scope, sstr, svc) != 0) {
1370 switch (scf_error()) {
1371 case SCF_ERROR_CONNECTION_BROKEN:
1372 scfdie();
1373 /* NOTREACHED */
1374
1375 case SCF_ERROR_DELETED:
1376 goto get_scope;
1377
1378 case SCF_ERROR_NOT_FOUND:
1379 break;
1380
1381 case SCF_ERROR_HANDLE_MISMATCH:
1382 case SCF_ERROR_INVALID_ARGUMENT:
1383 case SCF_ERROR_NOT_BOUND:
1384 case SCF_ERROR_NOT_SET:
1385 default:
1386 bad_error("scf_scope_get_service", scf_error());
1387 }
1388
1389 if (scf_scope_add_service(scope, sstr, svc) != 0) {
1390 switch (scf_error()) {
1391 case SCF_ERROR_CONNECTION_BROKEN:
1392 scfdie();
1393 /* NOTREACHED */
1394
1395 case SCF_ERROR_DELETED:
1396 goto get_scope;
1397
1398 case SCF_ERROR_PERMISSION_DENIED:
1399 case SCF_ERROR_BACKEND_READONLY:
1400 case SCF_ERROR_BACKEND_ACCESS:
1401 scfe = scf_error();
1402 goto out;
1403
1404 case SCF_ERROR_HANDLE_MISMATCH:
1405 case SCF_ERROR_INVALID_ARGUMENT:
1406 case SCF_ERROR_NOT_BOUND:
1407 case SCF_ERROR_NOT_SET:
1408 default:
1409 bad_error("scf_scope_get_service", scf_error());
1410 }
1411 }
1412 }
1413
1414 if (istr == NULL) {
1415 scfe = SCF_ERROR_NONE;
1416 *ep = svc;
1417 *isservicep = 1;
1418 goto out;
1419 }
1420
1421 get_inst:
1422 if (scf_service_get_instance(svc, istr, inst) != 0) {
1423 switch (scf_error()) {
1424 case SCF_ERROR_CONNECTION_BROKEN:
1425 scfdie();
1426 /* NOTREACHED */
1427
1428 case SCF_ERROR_DELETED:
1429 goto get_svc;
1430
1431 case SCF_ERROR_NOT_FOUND:
1432 break;
1433
1434 case SCF_ERROR_HANDLE_MISMATCH:
1435 case SCF_ERROR_INVALID_ARGUMENT:
1436 case SCF_ERROR_NOT_BOUND:
1437 case SCF_ERROR_NOT_SET:
1438 default:
1439 bad_error("scf_service_get_instance", scf_error());
1440 }
1441
1442 if (scf_service_add_instance(svc, istr, inst) != 0) {
1443 switch (scf_error()) {
1444 case SCF_ERROR_CONNECTION_BROKEN:
1445 scfdie();
1446 /* NOTREACHED */
1447
1448 case SCF_ERROR_DELETED:
1449 goto get_svc;
1450
1451 case SCF_ERROR_PERMISSION_DENIED:
1452 case SCF_ERROR_BACKEND_READONLY:
1453 case SCF_ERROR_BACKEND_ACCESS:
1454 scfe = scf_error();
1455 goto out;
1456
1457 case SCF_ERROR_HANDLE_MISMATCH:
1458 case SCF_ERROR_INVALID_ARGUMENT:
1459 case SCF_ERROR_NOT_BOUND:
1460 case SCF_ERROR_NOT_SET:
1461 default:
1462 bad_error("scf_service_add_instance",
1463 scf_error());
1464 }
1465 }
1466 }
1467
1468 scfe = SCF_ERROR_NONE;
1469 *ep = inst;
1470 *isservicep = 0;
1471
1472 out:
1473 if (*ep != inst)
1474 scf_instance_destroy(inst);
1475 if (*ep != svc)
1476 scf_service_destroy(svc);
1477 scf_scope_destroy(scope);
1478 free(fmri_copy);
1479 return (scfe);
1480 }
1481
1482 /*
1483 * Create or update a snapshot of inst. snap is a required scratch object.
1484 *
1485 * Returns
1486 * 0 - success
1487 * ECONNABORTED - repository connection broken
1488 * EPERM - permission denied
1489 * ENOSPC - configd is out of resources
1490 * ECANCELED - inst was deleted
1491 * -1 - unknown libscf error (message printed)
1492 */
1493 static int
1494 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1495 {
1496 again:
1497 if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1498 if (_scf_snapshot_take_attach(inst, snap) != 0) {
1499 switch (scf_error()) {
1500 case SCF_ERROR_CONNECTION_BROKEN:
1501 case SCF_ERROR_PERMISSION_DENIED:
1502 case SCF_ERROR_NO_RESOURCES:
1503 return (scferror2errno(scf_error()));
1504
1505 case SCF_ERROR_NOT_SET:
1506 case SCF_ERROR_INVALID_ARGUMENT:
1507 default:
1508 bad_error("_scf_snapshot_take_attach",
1509 scf_error());
1510 }
1511 }
1512 } else {
1513 switch (scf_error()) {
1514 case SCF_ERROR_NOT_FOUND:
1515 break;
1516
1517 case SCF_ERROR_DELETED:
1518 case SCF_ERROR_CONNECTION_BROKEN:
1519 return (scferror2errno(scf_error()));
1520
1521 case SCF_ERROR_HANDLE_MISMATCH:
1522 case SCF_ERROR_NOT_BOUND:
1523 case SCF_ERROR_INVALID_ARGUMENT:
1524 case SCF_ERROR_NOT_SET:
1525 default:
1526 bad_error("scf_instance_get_snapshot", scf_error());
1527 }
1528
1529 if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1530 switch (scf_error()) {
1531 case SCF_ERROR_EXISTS:
1532 goto again;
1533
1534 case SCF_ERROR_CONNECTION_BROKEN:
1535 case SCF_ERROR_NO_RESOURCES:
1536 case SCF_ERROR_PERMISSION_DENIED:
1537 return (scferror2errno(scf_error()));
1538
1539 default:
1540 scfwarn();
1541 return (-1);
1542
1543 case SCF_ERROR_NOT_SET:
1544 case SCF_ERROR_INTERNAL:
1545 case SCF_ERROR_INVALID_ARGUMENT:
1546 case SCF_ERROR_HANDLE_MISMATCH:
1547 bad_error("_scf_snapshot_take_new",
1548 scf_error());
1549 }
1550 }
1551 }
1552
1553 return (0);
1554 }
1555
1556 static int
1557 refresh_running_snapshot(void *entity)
1558 {
1559 scf_snapshot_t *snap;
1560 int r;
1561
1562 if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1563 scfdie();
1564 r = take_snap(entity, snap_running, snap);
1565 scf_snapshot_destroy(snap);
1566
1567 return (r);
1568 }
1569
1570 /*
1571 * Refresh entity. If isservice is zero, take entity to be an scf_instance_t *.
1572 * Otherwise take entity to be an scf_service_t * and refresh all of its child
1573 * instances. fmri is used for messages. inst, iter, and name_buf are used
1574 * for scratch space. Returns
1575 * 0 - success
1576 * ECONNABORTED - repository connection broken
1577 * ECANCELED - entity was deleted
1578 * EACCES - backend denied access
1579 * EPERM - permission denied
1580 * ENOSPC - repository server out of resources
1581 * -1 - _smf_refresh_instance_i() failed. scf_error() should be set.
1582 */
1583 static int
1584 refresh_entity(int isservice, void *entity, const char *fmri,
1585 scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1586 {
1587 scf_error_t scfe;
1588 int r;
1589
1590 if (!isservice) {
1591 /*
1592 * Let restarter handles refreshing and making new running
1593 * snapshot only if operating on a live repository and not
1594 * running in early import.
1595 */
1596 if (est->sc_repo_filename == NULL &&
1597 est->sc_repo_doorname == NULL &&
1598 est->sc_in_emi == 0) {
1599 if (_smf_refresh_instance_i(entity) == 0) {
1600 if (g_verbose)
1601 warn(gettext("Refreshed %s.\n"), fmri);
1602 return (0);
1603 }
1604
1605 switch (scf_error()) {
1606 case SCF_ERROR_BACKEND_ACCESS:
1607 return (EACCES);
1608
1609 case SCF_ERROR_PERMISSION_DENIED:
1610 return (EPERM);
1611
1612 default:
1613 return (-1);
1614 }
1615 } else {
1616 r = refresh_running_snapshot(entity);
1617 switch (r) {
1618 case 0:
1619 break;
1620
1621 case ECONNABORTED:
1622 case ECANCELED:
1623 case EPERM:
1624 case ENOSPC:
1625 break;
1626
1627 default:
1628 bad_error("refresh_running_snapshot",
1629 scf_error());
1630 }
1631
1632 return (r);
1633 }
1634 }
1635
1636 if (scf_iter_service_instances(iter, entity) != 0) {
1637 switch (scf_error()) {
1638 case SCF_ERROR_CONNECTION_BROKEN:
1639 return (ECONNABORTED);
1640
1641 case SCF_ERROR_DELETED:
1642 return (ECANCELED);
1643
1644 case SCF_ERROR_HANDLE_MISMATCH:
1645 case SCF_ERROR_NOT_BOUND:
1646 case SCF_ERROR_NOT_SET:
1647 default:
1648 bad_error("scf_iter_service_instances", scf_error());
1649 }
1650 }
1651
1652 for (;;) {
1653 r = scf_iter_next_instance(iter, inst);
1654 if (r == 0)
1655 break;
1656 if (r != 1) {
1657 switch (scf_error()) {
1658 case SCF_ERROR_CONNECTION_BROKEN:
1659 return (ECONNABORTED);
1660
1661 case SCF_ERROR_DELETED:
1662 return (ECANCELED);
1663
1664 case SCF_ERROR_HANDLE_MISMATCH:
1665 case SCF_ERROR_NOT_BOUND:
1666 case SCF_ERROR_NOT_SET:
1667 case SCF_ERROR_INVALID_ARGUMENT:
1668 default:
1669 bad_error("scf_iter_next_instance",
1670 scf_error());
1671 }
1672 }
1673
1674 /*
1675 * Similarly, just take a new running snapshot if operating on
1676 * a non-live repository or running during early import.
1677 */
1678 if (est->sc_repo_filename != NULL ||
1679 est->sc_repo_doorname != NULL ||
1680 est->sc_in_emi == 1) {
1681 r = refresh_running_snapshot(inst);
1682 switch (r) {
1683 case 0:
1684 continue;
1685
1686 case ECONNABORTED:
1687 case ECANCELED:
1688 case EPERM:
1689 case ENOSPC:
1690 break;
1691 default:
1692 bad_error("refresh_running_snapshot",
1693 scf_error());
1694 }
1695
1696 return (r);
1697
1698 }
1699
1700 if (_smf_refresh_instance_i(inst) == 0) {
1701 if (g_verbose) {
1702 if (scf_instance_get_name(inst, name_buf,
1703 max_scf_name_len + 1) < 0)
1704 (void) strcpy(name_buf, "?");
1705
1706 warn(gettext("Refreshed %s:%s.\n"),
1707 fmri, name_buf);
1708 }
1709 } else {
1710 if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1711 g_verbose) {
1712 scfe = scf_error();
1713
1714 if (scf_instance_to_fmri(inst, name_buf,
1715 max_scf_name_len + 1) < 0)
1716 (void) strcpy(name_buf, "?");
1717
1718 warn(gettext(
1719 "Refresh of %s:%s failed: %s.\n"), fmri,
1720 name_buf, scf_strerror(scfe));
1721 }
1722 }
1723 }
1724
1725 return (0);
1726 }
1727
1728 static void
1729 private_refresh(void)
1730 {
1731 scf_instance_t *pinst = NULL;
1732 scf_iter_t *piter = NULL;
1733 ssize_t fmrilen;
1734 size_t bufsz;
1735 char *fmribuf;
1736 void *ent;
1737 int issvc;
1738 int r;
1739
1740 if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1741 return;
1742
1743 assert(cur_svc != NULL);
1744
1745 bufsz = max_scf_fmri_len + 1;
1746 fmribuf = safe_malloc(bufsz);
1747 if (cur_inst) {
1748 issvc = 0;
1749 ent = cur_inst;
1750 fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1751 } else {
1752 issvc = 1;
1753 ent = cur_svc;
1754 fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1755 if ((pinst = scf_instance_create(g_hndl)) == NULL)
1756 scfdie();
1757
1758 if ((piter = scf_iter_create(g_hndl)) == NULL)
1759 scfdie();
1760 }
1761 if (fmrilen < 0) {
1762 free(fmribuf);
1763 if (scf_error() != SCF_ERROR_DELETED)
1764 scfdie();
1765
1766 warn(emsg_deleted);
1767 return;
1768 }
1769 assert(fmrilen < bufsz);
1770
1771 r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1772 switch (r) {
1773 case 0:
1774 break;
1775
1776 case ECONNABORTED:
1777 warn(gettext("Could not refresh %s "
1778 "(repository connection broken).\n"), fmribuf);
1779 break;
1780
1781 case ECANCELED:
1782 warn(emsg_deleted);
1783 break;
1784
1785 case EPERM:
1786 warn(gettext("Could not refresh %s "
1787 "(permission denied).\n"), fmribuf);
1788 break;
1789
1790 case ENOSPC:
1791 warn(gettext("Could not refresh %s "
1792 "(repository server out of resources).\n"),
1793 fmribuf);
1794 break;
1795
1796 case EACCES:
1797 default:
1798 bad_error("refresh_entity", scf_error());
1799 }
1800
1801 if (issvc) {
1802 scf_instance_destroy(pinst);
1803 scf_iter_destroy(piter);
1804 }
1805
1806 free(fmribuf);
1807 }
1808
1809
1810 static int
1811 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1812 {
1813 cbp->sc_err = scferror2errno(err);
1814 return (UU_WALK_ERROR);
1815 }
1816
1817 static int
1818 stash_scferror(scf_callback_t *cbp)
1819 {
1820 return (stash_scferror_err(cbp, scf_error()));
1821 }
1822
1823 static int select_inst(const char *);
1824 static int select_svc(const char *);
1825
1826 /*
1827 * Take a property that does not have a type and check to see if a type
1828 * exists or can be gleened from the current data. Set the type.
1829 *
1830 * Check the current level (instance) and then check the higher level
1831 * (service). This could be the case for adding a new property to
1832 * the instance that's going to "override" a service level property.
1833 *
1834 * For a property :
1835 * 1. Take the type from an existing property
1836 * 2. Take the type from a template entry
1837 *
1838 * If the type can not be found, then leave the type as is, and let the import
1839 * report the problem of the missing type.
1840 */
1841 static int
1842 find_current_prop_type(void *p, void *g)
1843 {
1844 property_t *prop = p;
1845 scf_callback_t *lcb = g;
1846 pgroup_t *pg = NULL;
1847
1848 const char *fmri = NULL;
1849 char *lfmri = NULL;
1850 char *cur_selection = NULL;
1851
1852 scf_propertygroup_t *sc_pg = NULL;
1853 scf_property_t *sc_prop = NULL;
1854 scf_pg_tmpl_t *t_pg = NULL;
1855 scf_prop_tmpl_t *t_prop = NULL;
1856 scf_type_t prop_type;
1857
1858 value_t *vp;
1859 int issvc = lcb->sc_service;
1860 int r = UU_WALK_ERROR;
1861
1862 if (prop->sc_value_type != SCF_TYPE_INVALID)
1863 return (UU_WALK_NEXT);
1864
1865 t_prop = scf_tmpl_prop_create(g_hndl);
1866 sc_prop = scf_property_create(g_hndl);
1867 if (sc_prop == NULL || t_prop == NULL) {
1868 warn(gettext("Unable to create the property to attempt and "
1869 "find a missing type.\n"));
1870
1871 scf_property_destroy(sc_prop);
1872 scf_tmpl_prop_destroy(t_prop);
1873
1874 return (UU_WALK_ERROR);
1875 }
1876
1877 if (lcb->sc_flags == 1) {
1878 pg = lcb->sc_parent;
1879 issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT);
1880 fmri = pg->sc_parent->sc_fmri;
1881 retry_pg:
1882 if (cur_svc && cur_selection == NULL) {
1883 cur_selection = safe_malloc(max_scf_fmri_len + 1);
1884 lscf_get_selection_str(cur_selection,
1885 max_scf_fmri_len + 1);
1886
1887 if (strcmp(cur_selection, fmri) != 0) {
1888 lscf_select(fmri);
1889 } else {
1890 free(cur_selection);
1891 cur_selection = NULL;
1892 }
1893 } else {
1894 lscf_select(fmri);
1895 }
1896
1897 if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) {
1898 warn(gettext("Unable to create property group to "
1899 "find a missing property type.\n"));
1900
1901 goto out;
1902 }
1903
1904 if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) {
1905 /*
1906 * If this is the sc_pg from the parent
1907 * let the caller clean up the sc_pg,
1908 * and just throw it away in this case.
1909 */
1910 if (sc_pg != lcb->sc_parent)
1911 scf_pg_destroy(sc_pg);
1912
1913 sc_pg = NULL;
1914 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1915 warn(gettext("Unable to create template "
1916 "property group to find a property "
1917 "type.\n"));
1918
1919 goto out;
1920 }
1921
1922 if (scf_tmpl_get_by_pg_name(fmri, NULL,
1923 pg->sc_pgroup_name, NULL, t_pg,
1924 SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) {
1925 /*
1926 * if instance get service and jump back
1927 */
1928 scf_tmpl_pg_destroy(t_pg);
1929 t_pg = NULL;
1930 if (issvc == 0) {
1931 entity_t *e = pg->sc_parent->sc_parent;
1932
1933 fmri = e->sc_fmri;
1934 issvc = 1;
1935 goto retry_pg;
1936 } else {
1937 goto out;
1938 }
1939 }
1940 }
1941 } else {
1942 sc_pg = lcb->sc_parent;
1943 }
1944
1945 /*
1946 * Attempt to get the type from an existing property. If the property
1947 * cannot be found then attempt to get the type from a template entry
1948 * for the property.
1949 *
1950 * Finally, if at the instance level look at the service level.
1951 */
1952 if (sc_pg != NULL &&
1953 pg_get_prop(sc_pg, prop->sc_property_name,
1954 sc_prop) == SCF_SUCCESS &&
1955 scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) {
1956 prop->sc_value_type = prop_type;
1957
1958 /*
1959 * Found a type, update the value types and validate
1960 * the actual value against this type.
1961 */
1962 for (vp = uu_list_first(prop->sc_property_values);
1963 vp != NULL;
1964 vp = uu_list_next(prop->sc_property_values, vp)) {
1965 vp->sc_type = prop->sc_value_type;
1966 lxml_store_value(vp, 0, NULL);
1967 }
1968
1969 r = UU_WALK_NEXT;
1970 goto out;
1971 }
1972
1973 /*
1974 * If we get here with t_pg set to NULL then we had to have
1975 * gotten an sc_pg but that sc_pg did not have the property
1976 * we are looking for. So if the t_pg is not null look up
1977 * the template entry for the property.
1978 *
1979 * If the t_pg is null then need to attempt to get a matching
1980 * template entry for the sc_pg, and see if there is a property
1981 * entry for that template entry.
1982 */
1983 do_tmpl :
1984 if (t_pg != NULL &&
1985 scf_tmpl_get_by_prop(t_pg, prop->sc_property_name,
1986 t_prop, 0) == SCF_SUCCESS) {
1987 if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) {
1988 prop->sc_value_type = prop_type;
1989
1990 /*
1991 * Found a type, update the value types and validate
1992 * the actual value against this type.
1993 */
1994 for (vp = uu_list_first(prop->sc_property_values);
1995 vp != NULL;
1996 vp = uu_list_next(prop->sc_property_values, vp)) {
1997 vp->sc_type = prop->sc_value_type;
1998 lxml_store_value(vp, 0, NULL);
1999 }
2000
2001 r = UU_WALK_NEXT;
2002 goto out;
2003 }
2004 } else {
2005 if (t_pg == NULL && sc_pg) {
2006 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
2007 warn(gettext("Unable to create template "
2008 "property group to find a property "
2009 "type.\n"));
2010
2011 goto out;
2012 }
2013
2014 if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
2015 scf_tmpl_pg_destroy(t_pg);
2016 t_pg = NULL;
2017 } else {
2018 goto do_tmpl;
2019 }
2020 }
2021 }
2022
2023 if (issvc == 0) {
2024 scf_instance_t *i;
2025 scf_service_t *s;
2026
2027 issvc = 1;
2028 if (lcb->sc_flags == 1) {
2029 entity_t *e = pg->sc_parent->sc_parent;
2030
2031 fmri = e->sc_fmri;
2032 goto retry_pg;
2033 }
2034
2035 /*
2036 * because lcb->sc_flags was not set then this means
2037 * the pg was not used and can be used here.
2038 */
2039 if ((pg = internal_pgroup_new()) == NULL) {
2040 warn(gettext("Could not create internal property group "
2041 "to find a missing type."));
2042
2043 goto out;
2044 }
2045
2046 pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1);
2047 if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name,
2048 max_scf_name_len + 1) < 0)
2049 goto out;
2050
2051 i = scf_instance_create(g_hndl);
2052 s = scf_service_create(g_hndl);
2053 if (i == NULL || s == NULL ||
2054 scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) {
2055 warn(gettext("Could not get a service for the instance "
2056 "to find a missing type."));
2057
2058 goto out;
2059 }
2060
2061 /*
2062 * Check to see truly at the instance level.
2063 */
2064 lfmri = safe_malloc(max_scf_fmri_len + 1);
2065 if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
2066 scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0)
2067 goto out;
2068 else
2069 fmri = (const char *)lfmri;
2070
2071 goto retry_pg;
2072 }
2073
2074 out :
2075 if (sc_pg != lcb->sc_parent) {
2076 scf_pg_destroy(sc_pg);
2077 }
2078
2079 /*
2080 * If this is true then the pg was allocated
2081 * here, and the name was set so need to free
2082 * the name and the pg.
2083 */
2084 if (pg != NULL && pg != lcb->sc_parent) {
2085 free((char *)pg->sc_pgroup_name);
2086 internal_pgroup_free(pg);
2087 }
2088
2089 if (cur_selection) {
2090 lscf_select(cur_selection);
2091 free(cur_selection);
2092 }
2093
2094 scf_tmpl_pg_destroy(t_pg);
2095 scf_tmpl_prop_destroy(t_prop);
2096 scf_property_destroy(sc_prop);
2097
2098 if (r != UU_WALK_NEXT)
2099 warn(gettext("Could not find property type for \"%s\" "
2100 "from \"%s\"\n"), prop->sc_property_name,
2101 fmri != NULL ? fmri : lcb->sc_source_fmri);
2102
2103 free(lfmri);
2104
2105 return (r);
2106 }
2107
2108 /*
2109 * Take a property group that does not have a type and check to see if a type
2110 * exists or can be gleened from the current data. Set the type.
2111 *
2112 * Check the current level (instance) and then check the higher level
2113 * (service). This could be the case for adding a new property to
2114 * the instance that's going to "override" a service level property.
2115 *
2116 * For a property group
2117 * 1. Take the type from an existing property group
2118 * 2. Take the type from a template entry
2119 *
2120 * If the type can not be found, then leave the type as is, and let the import
2121 * report the problem of the missing type.
2122 */
2123 static int
2124 find_current_pg_type(void *p, void *sori)
2125 {
2126 entity_t *si = sori;
2127 pgroup_t *pg = p;
2128
2129 const char *ofmri, *fmri;
2130 char *cur_selection = NULL;
2131 char *pg_type = NULL;
2132
2133 scf_propertygroup_t *sc_pg = NULL;
2134 scf_pg_tmpl_t *t_pg = NULL;
2135
2136 int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2137 int r = UU_WALK_ERROR;
2138
2139 ofmri = fmri = si->sc_fmri;
2140 if (pg->sc_pgroup_type != NULL) {
2141 r = UU_WALK_NEXT;
2142
2143 goto out;
2144 }
2145
2146 sc_pg = scf_pg_create(g_hndl);
2147 if (sc_pg == NULL) {
2148 warn(gettext("Unable to create property group to attempt "
2149 "and find a missing type.\n"));
2150
2151 return (UU_WALK_ERROR);
2152 }
2153
2154 /*
2155 * Using get_pg() requires that the cur_svc/cur_inst be
2156 * via lscf_select. Need to preserve the current selection
2157 * if going to use lscf_select() to set up the cur_svc/cur_inst
2158 */
2159 if (cur_svc) {
2160 cur_selection = safe_malloc(max_scf_fmri_len + 1);
2161 lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1);
2162 }
2163
2164 /*
2165 * If the property group exists get the type, and set
2166 * the pgroup_t type of that type.
2167 *
2168 * If not the check for a template pg_pattern entry
2169 * and take the type from that.
2170 */
2171 retry_svc:
2172 lscf_select(fmri);
2173
2174 if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) {
2175 pg_type = safe_malloc(max_scf_pg_type_len + 1);
2176 if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type,
2177 max_scf_pg_type_len + 1) != -1) {
2178 pg->sc_pgroup_type = pg_type;
2179
2180 r = UU_WALK_NEXT;
2181 goto out;
2182 } else {
2183 free(pg_type);
2184 }
2185 } else {
2186 if ((t_pg == NULL) &&
2187 (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
2188 goto out;
2189
2190 if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name,
2191 NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS &&
2192 scf_tmpl_pg_type(t_pg, &pg_type) != -1) {
2193 pg->sc_pgroup_type = pg_type;
2194
2195 r = UU_WALK_NEXT;
2196 goto out;
2197 }
2198 }
2199
2200 /*
2201 * If type is not found at the instance level then attempt to
2202 * find the type at the service level.
2203 */
2204 if (!issvc) {
2205 si = si->sc_parent;
2206 fmri = si->sc_fmri;
2207 issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2208 goto retry_svc;
2209 }
2210
2211 out :
2212 if (cur_selection) {
2213 lscf_select(cur_selection);
2214 free(cur_selection);
2215 }
2216
2217 /*
2218 * Now walk the properties of the property group to make sure that
2219 * all properties have the correct type and values are valid for
2220 * those types.
2221 */
2222 if (r == UU_WALK_NEXT) {
2223 scf_callback_t cb;
2224
2225 cb.sc_service = issvc;
2226 cb.sc_source_fmri = ofmri;
2227 if (sc_pg != NULL) {
2228 cb.sc_parent = sc_pg;
2229 cb.sc_flags = 0;
2230 } else {
2231 cb.sc_parent = pg;
2232 cb.sc_flags = 1;
2233 }
2234
2235 if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type,
2236 &cb, UU_DEFAULT) != 0) {
2237 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2238 bad_error("uu_list_walk", uu_error());
2239
2240 r = UU_WALK_ERROR;
2241 }
2242 } else {
2243 warn(gettext("Could not find property group type for "
2244 "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri);
2245 }
2246
2247 scf_tmpl_pg_destroy(t_pg);
2248 scf_pg_destroy(sc_pg);
2249
2250 return (r);
2251 }
2252
2253 /*
2254 * Import. These functions import a bundle into the repository.
2255 */
2256
2257 /*
2258 * Add a transaction entry to lcbdata->sc_trans for this property_t. Uses
2259 * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata. On success,
2260 * returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
2261 * lcbdata->sc_err to
2262 * ENOMEM - out of memory
2263 * ECONNABORTED - repository connection broken
2264 * ECANCELED - sc_trans's property group was deleted
2265 * EINVAL - p's name is invalid (error printed)
2266 * - p has an invalid value (error printed)
2267 */
2268 static int
2269 lscf_property_import(void *v, void *pvt)
2270 {
2271 property_t *p = v;
2272 scf_callback_t *lcbdata = pvt;
2273 value_t *vp;
2274 scf_transaction_t *trans = lcbdata->sc_trans;
2275 scf_transaction_entry_t *entr;
2276 scf_value_t *val;
2277 scf_type_t tp;
2278
2279 if ((lcbdata->sc_flags & SCI_NOENABLED ||
2280 lcbdata->sc_flags & SCI_DELAYENABLE) &&
2281 strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
2282 lcbdata->sc_enable = p;
2283 return (UU_WALK_NEXT);
2284 }
2285
2286 entr = scf_entry_create(lcbdata->sc_handle);
2287 if (entr == NULL) {
2288 switch (scf_error()) {
2289 case SCF_ERROR_NO_MEMORY:
2290 return (stash_scferror(lcbdata));
2291
2292 case SCF_ERROR_INVALID_ARGUMENT:
2293 default:
2294 bad_error("scf_entry_create", scf_error());
2295 }
2296 }
2297
2298 tp = p->sc_value_type;
2299
2300 if (scf_transaction_property_new(trans, entr,
2301 p->sc_property_name, tp) != 0) {
2302 switch (scf_error()) {
2303 case SCF_ERROR_INVALID_ARGUMENT:
2304 semerr(emsg_invalid_prop_name, p->sc_property_name);
2305 scf_entry_destroy(entr);
2306 return (stash_scferror(lcbdata));
2307
2308 case SCF_ERROR_EXISTS:
2309 break;
2310
2311 case SCF_ERROR_DELETED:
2312 case SCF_ERROR_CONNECTION_BROKEN:
2313 scf_entry_destroy(entr);
2314 return (stash_scferror(lcbdata));
2315
2316 case SCF_ERROR_NOT_BOUND:
2317 case SCF_ERROR_HANDLE_MISMATCH:
2318 case SCF_ERROR_NOT_SET:
2319 default:
2320 bad_error("scf_transaction_property_new", scf_error());
2321 }
2322
2323 if (scf_transaction_property_change_type(trans, entr,
2324 p->sc_property_name, tp) != 0) {
2325 switch (scf_error()) {
2326 case SCF_ERROR_DELETED:
2327 case SCF_ERROR_CONNECTION_BROKEN:
2328 scf_entry_destroy(entr);
2329 return (stash_scferror(lcbdata));
2330
2331 case SCF_ERROR_INVALID_ARGUMENT:
2332 semerr(emsg_invalid_prop_name,
2333 p->sc_property_name);
2334 scf_entry_destroy(entr);
2335 return (stash_scferror(lcbdata));
2336
2337 case SCF_ERROR_NOT_FOUND:
2338 case SCF_ERROR_NOT_SET:
2339 case SCF_ERROR_HANDLE_MISMATCH:
2340 case SCF_ERROR_NOT_BOUND:
2341 default:
2342 bad_error(
2343 "scf_transaction_property_change_type",
2344 scf_error());
2345 }
2346 }
2347 }
2348
2349 for (vp = uu_list_first(p->sc_property_values);
2350 vp != NULL;
2351 vp = uu_list_next(p->sc_property_values, vp)) {
2352 val = scf_value_create(g_hndl);
2353 if (val == NULL) {
2354 switch (scf_error()) {
2355 case SCF_ERROR_NO_MEMORY:
2356 return (stash_scferror(lcbdata));
2357
2358 case SCF_ERROR_INVALID_ARGUMENT:
2359 default:
2360 bad_error("scf_value_create", scf_error());
2361 }
2362 }
2363
2364 switch (tp) {
2365 case SCF_TYPE_BOOLEAN:
2366 scf_value_set_boolean(val, vp->sc_u.sc_count);
2367 break;
2368 case SCF_TYPE_COUNT:
2369 scf_value_set_count(val, vp->sc_u.sc_count);
2370 break;
2371 case SCF_TYPE_INTEGER:
2372 scf_value_set_integer(val, vp->sc_u.sc_integer);
2373 break;
2374 default:
2375 assert(vp->sc_u.sc_string != NULL);
2376 if (scf_value_set_from_string(val, tp,
2377 vp->sc_u.sc_string) != 0) {
2378 if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
2379 bad_error("scf_value_set_from_string",
2380 scf_error());
2381
2382 warn(gettext("Value \"%s\" is not a valid "
2383 "%s.\n"), vp->sc_u.sc_string,
2384 scf_type_to_string(tp));
2385 scf_value_destroy(val);
2386 return (stash_scferror(lcbdata));
2387 }
2388 break;
2389 }
2390
2391 if (scf_entry_add_value(entr, val) != 0)
2392 bad_error("scf_entry_add_value", scf_error());
2393 }
2394
2395 return (UU_WALK_NEXT);
2396 }
2397
2398 /*
2399 * Import a pgroup_t into the repository. Uses sc_handle, sc_parent,
2400 * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2401 * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2402 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
2403 * lcbdata->sc_err to
2404 * ECONNABORTED - repository connection broken
2405 * ENOMEM - out of memory
2406 * ENOSPC - svc.configd is out of resources
2407 * ECANCELED - sc_parent was deleted
2408 * EPERM - could not create property group (permission denied) (error printed)
2409 * - could not modify property group (permission denied) (error printed)
2410 * - could not delete property group (permission denied) (error printed)
2411 * EROFS - could not create property group (repository is read-only)
2412 * - could not delete property group (repository is read-only)
2413 * EACCES - could not create property group (backend access denied)
2414 * - could not delete property group (backend access denied)
2415 * EEXIST - could not create property group (already exists)
2416 * EINVAL - invalid property group name (error printed)
2417 * - invalid property name (error printed)
2418 * - invalid value (error printed)
2419 * EBUSY - new property group deleted (error printed)
2420 * - new property group changed (error printed)
2421 * - property group added (error printed)
2422 * - property group deleted (error printed)
2423 */
2424 static int
2425 entity_pgroup_import(void *v, void *pvt)
2426 {
2427 pgroup_t *p = v;
2428 scf_callback_t cbdata;
2429 scf_callback_t *lcbdata = pvt;
2430 void *ent = lcbdata->sc_parent;
2431 int issvc = lcbdata->sc_service;
2432 int r;
2433
2434 const char * const pg_changed = gettext("%s changed unexpectedly "
2435 "(new property group \"%s\" changed).\n");
2436
2437 /* Never import deleted property groups. */
2438 if (p->sc_pgroup_delete) {
2439 if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY &&
2440 entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) {
2441 goto delete_pg;
2442 }
2443 return (UU_WALK_NEXT);
2444 }
2445
2446 if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
2447 strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
2448 lcbdata->sc_general = p;
2449 return (UU_WALK_NEXT);
2450 }
2451
2452 add_pg:
2453 if (issvc)
2454 r = scf_service_add_pg(ent, p->sc_pgroup_name,
2455 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2456 else
2457 r = scf_instance_add_pg(ent, p->sc_pgroup_name,
2458 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2459 if (r != 0) {
2460 switch (scf_error()) {
2461 case SCF_ERROR_DELETED:
2462 case SCF_ERROR_CONNECTION_BROKEN:
2463 case SCF_ERROR_BACKEND_READONLY:
2464 case SCF_ERROR_BACKEND_ACCESS:
2465 case SCF_ERROR_NO_RESOURCES:
2466 return (stash_scferror(lcbdata));
2467
2468 case SCF_ERROR_EXISTS:
2469 if (lcbdata->sc_flags & SCI_FORCE)
2470 break;
2471 return (stash_scferror(lcbdata));
2472
2473 case SCF_ERROR_INVALID_ARGUMENT:
2474 warn(emsg_fmri_invalid_pg_name_type,
2475 lcbdata->sc_source_fmri,
2476 p->sc_pgroup_name, p->sc_pgroup_type);
2477 return (stash_scferror(lcbdata));
2478
2479 case SCF_ERROR_PERMISSION_DENIED:
2480 warn(emsg_pg_add_perm, p->sc_pgroup_name,
2481 lcbdata->sc_target_fmri);
2482 return (stash_scferror(lcbdata));
2483
2484 case SCF_ERROR_NOT_BOUND:
2485 case SCF_ERROR_HANDLE_MISMATCH:
2486 case SCF_ERROR_NOT_SET:
2487 default:
2488 bad_error("scf_service_add_pg", scf_error());
2489 }
2490
2491 if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2492 switch (scf_error()) {
2493 case SCF_ERROR_CONNECTION_BROKEN:
2494 case SCF_ERROR_DELETED:
2495 return (stash_scferror(lcbdata));
2496
2497 case SCF_ERROR_INVALID_ARGUMENT:
2498 warn(emsg_fmri_invalid_pg_name,
2499 lcbdata->sc_source_fmri,
2500 p->sc_pgroup_name);
2501 return (stash_scferror(lcbdata));
2502
2503 case SCF_ERROR_NOT_FOUND:
2504 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2505 p->sc_pgroup_name);
2506 lcbdata->sc_err = EBUSY;
2507 return (UU_WALK_ERROR);
2508
2509 case SCF_ERROR_NOT_BOUND:
2510 case SCF_ERROR_HANDLE_MISMATCH:
2511 case SCF_ERROR_NOT_SET:
2512 default:
2513 bad_error("entity_get_pg", scf_error());
2514 }
2515 }
2516
2517 if (lcbdata->sc_flags & SCI_KEEP)
2518 goto props;
2519
2520 delete_pg:
2521 if (scf_pg_delete(imp_pg) != 0) {
2522 switch (scf_error()) {
2523 case SCF_ERROR_DELETED:
2524 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2525 p->sc_pgroup_name);
2526 lcbdata->sc_err = EBUSY;
2527 return (UU_WALK_ERROR);
2528
2529 case SCF_ERROR_PERMISSION_DENIED:
2530 warn(emsg_pg_del_perm, p->sc_pgroup_name,
2531 lcbdata->sc_target_fmri);
2532 return (stash_scferror(lcbdata));
2533
2534 case SCF_ERROR_BACKEND_READONLY:
2535 case SCF_ERROR_BACKEND_ACCESS:
2536 case SCF_ERROR_CONNECTION_BROKEN:
2537 return (stash_scferror(lcbdata));
2538
2539 case SCF_ERROR_NOT_SET:
2540 default:
2541 bad_error("scf_pg_delete", scf_error());
2542 }
2543 }
2544
2545 if (p->sc_pgroup_delete)
2546 return (UU_WALK_NEXT);
2547
2548 goto add_pg;
2549 }
2550
2551 props:
2552
2553 /*
2554 * Add properties to property group, if any.
2555 */
2556 cbdata.sc_handle = lcbdata->sc_handle;
2557 cbdata.sc_parent = imp_pg;
2558 cbdata.sc_flags = lcbdata->sc_flags;
2559 cbdata.sc_trans = imp_tx;
2560 cbdata.sc_enable = NULL;
2561
2562 if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2563 switch (scf_error()) {
2564 case SCF_ERROR_BACKEND_ACCESS:
2565 case SCF_ERROR_BACKEND_READONLY:
2566 case SCF_ERROR_CONNECTION_BROKEN:
2567 return (stash_scferror(lcbdata));
2568
2569 case SCF_ERROR_DELETED:
2570 warn(pg_changed, lcbdata->sc_target_fmri,
2571 p->sc_pgroup_name);
2572 lcbdata->sc_err = EBUSY;
2573 return (UU_WALK_ERROR);
2574
2575 case SCF_ERROR_PERMISSION_DENIED:
2576 warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2577 lcbdata->sc_target_fmri);
2578 return (stash_scferror(lcbdata));
2579
2580 case SCF_ERROR_NOT_BOUND:
2581 case SCF_ERROR_NOT_SET:
2582 case SCF_ERROR_IN_USE:
2583 case SCF_ERROR_HANDLE_MISMATCH:
2584 default:
2585 bad_error("scf_transaction_start", scf_error());
2586 }
2587 }
2588
2589 if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2590 UU_DEFAULT) != 0) {
2591 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2592 bad_error("uu_list_walk", uu_error());
2593 scf_transaction_reset(imp_tx);
2594
2595 lcbdata->sc_err = cbdata.sc_err;
2596 if (cbdata.sc_err == ECANCELED) {
2597 warn(pg_changed, lcbdata->sc_target_fmri,
2598 p->sc_pgroup_name);
2599 lcbdata->sc_err = EBUSY;
2600 }
2601 return (UU_WALK_ERROR);
2602 }
2603
2604 if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2605 cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2606
2607 /*
2608 * take the snapshot running snapshot then
2609 * import the stored general/enable property
2610 */
2611 r = take_snap(ent, snap_running, imp_rsnap);
2612 switch (r) {
2613 case 0:
2614 break;
2615
2616 case ECONNABORTED:
2617 warn(gettext("Could not take %s snapshot on import "
2618 "(repository connection broken).\n"),
2619 snap_running);
2620 lcbdata->sc_err = r;
2621 return (UU_WALK_ERROR);
2622 case ECANCELED:
2623 warn(emsg_deleted);
2624 lcbdata->sc_err = r;
2625 return (UU_WALK_ERROR);
2626
2627 case EPERM:
2628 warn(gettext("Could not take %s snapshot "
2629 "(permission denied).\n"), snap_running);
2630 lcbdata->sc_err = r;
2631 return (UU_WALK_ERROR);
2632
2633 case ENOSPC:
2634 warn(gettext("Could not take %s snapshot"
2635 "(repository server out of resources).\n"),
2636 snap_running);
2637 lcbdata->sc_err = r;
2638 return (UU_WALK_ERROR);
2639
2640 default:
2641 bad_error("take_snap", r);
2642 }
2643
2644 r = lscf_property_import(cbdata.sc_enable, &cbdata);
2645 if (r != UU_WALK_NEXT) {
2646 if (r != UU_WALK_ERROR)
2647 bad_error("lscf_property_import", r);
2648 return (EINVAL);
2649 }
2650 }
2651
2652 r = scf_transaction_commit(imp_tx);
2653 switch (r) {
2654 case 1:
2655 r = UU_WALK_NEXT;
2656 break;
2657
2658 case 0:
2659 warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2660 lcbdata->sc_err = EBUSY;
2661 r = UU_WALK_ERROR;
2662 break;
2663
2664 case -1:
2665 switch (scf_error()) {
2666 case SCF_ERROR_BACKEND_READONLY:
2667 case SCF_ERROR_BACKEND_ACCESS:
2668 case SCF_ERROR_CONNECTION_BROKEN:
2669 case SCF_ERROR_NO_RESOURCES:
2670 r = stash_scferror(lcbdata);
2671 break;
2672
2673 case SCF_ERROR_DELETED:
2674 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2675 p->sc_pgroup_name);
2676 lcbdata->sc_err = EBUSY;
2677 r = UU_WALK_ERROR;
2678 break;
2679
2680 case SCF_ERROR_PERMISSION_DENIED:
2681 warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2682 lcbdata->sc_target_fmri);
2683 r = stash_scferror(lcbdata);
2684 break;
2685
2686 case SCF_ERROR_NOT_SET:
2687 case SCF_ERROR_INVALID_ARGUMENT:
2688 case SCF_ERROR_NOT_BOUND:
2689 default:
2690 bad_error("scf_transaction_commit", scf_error());
2691 }
2692 break;
2693
2694 default:
2695 bad_error("scf_transaction_commit", r);
2696 }
2697
2698 scf_transaction_destroy_children(imp_tx);
2699
2700 return (r);
2701 }
2702
2703 /*
2704 * Returns
2705 * 0 - success
2706 * ECONNABORTED - repository connection broken
2707 * ENOMEM - out of memory
2708 * ENOSPC - svc.configd is out of resources
2709 * ECANCELED - inst was deleted
2710 * EPERM - could not create property group (permission denied) (error printed)
2711 * - could not modify property group (permission denied) (error printed)
2712 * EROFS - could not create property group (repository is read-only)
2713 * EACCES - could not create property group (backend access denied)
2714 * EEXIST - could not create property group (already exists)
2715 * EINVAL - invalid property group name (error printed)
2716 * - invalid property name (error printed)
2717 * - invalid value (error printed)
2718 * EBUSY - new property group changed (error printed)
2719 */
2720 static int
2721 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2722 const entity_t *isvc, int flags)
2723 {
2724 scf_callback_t cbdata;
2725
2726 cbdata.sc_handle = scf_service_handle(svc);
2727 cbdata.sc_parent = svc;
2728 cbdata.sc_service = 1;
2729 cbdata.sc_general = 0;
2730 cbdata.sc_enable = 0;
2731 cbdata.sc_flags = flags;
2732 cbdata.sc_source_fmri = isvc->sc_fmri;
2733 cbdata.sc_target_fmri = target_fmri;
2734
2735 /*
2736 * If the op is set, then add the flag to the callback
2737 * flags for later use.
2738 */
2739 if (isvc->sc_op != SVCCFG_OP_NONE) {
2740 switch (isvc->sc_op) {
2741 case SVCCFG_OP_IMPORT :
2742 cbdata.sc_flags |= SCI_OP_IMPORT;
2743 break;
2744 case SVCCFG_OP_APPLY :
2745 cbdata.sc_flags |= SCI_OP_APPLY;
2746 break;
2747 case SVCCFG_OP_RESTORE :
2748 cbdata.sc_flags |= SCI_OP_RESTORE;
2749 break;
2750 default :
2751 uu_die(gettext("lscf_import_service_pgs : "
2752 "Unknown op stored in the service entity\n"));
2753
2754 }
2755 }
2756
2757 if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2758 UU_DEFAULT) != 0) {
2759 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2760 bad_error("uu_list_walk", uu_error());
2761
2762 return (cbdata.sc_err);
2763 }
2764
2765 return (0);
2766 }
2767
2768 /*
2769 * Returns
2770 * 0 - success
2771 * ECONNABORTED - repository connection broken
2772 * ENOMEM - out of memory
2773 * ENOSPC - svc.configd is out of resources
2774 * ECANCELED - inst was deleted
2775 * EPERM - could not create property group (permission denied) (error printed)
2776 * - could not modify property group (permission denied) (error printed)
2777 * EROFS - could not create property group (repository is read-only)
2778 * EACCES - could not create property group (backend access denied)
2779 * EEXIST - could not create property group (already exists)
2780 * EINVAL - invalid property group name (error printed)
2781 * - invalid property name (error printed)
2782 * - invalid value (error printed)
2783 * EBUSY - new property group changed (error printed)
2784 */
2785 static int
2786 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2787 const entity_t *iinst, int flags)
2788 {
2789 scf_callback_t cbdata;
2790
2791 cbdata.sc_handle = scf_instance_handle(inst);
2792 cbdata.sc_parent = inst;
2793 cbdata.sc_service = 0;
2794 cbdata.sc_general = NULL;
2795 cbdata.sc_enable = NULL;
2796 cbdata.sc_flags = flags;
2797 cbdata.sc_source_fmri = iinst->sc_fmri;
2798 cbdata.sc_target_fmri = target_fmri;
2799
2800 /*
2801 * If the op is set, then add the flag to the callback
2802 * flags for later use.
2803 */
2804 if (iinst->sc_op != SVCCFG_OP_NONE) {
2805 switch (iinst->sc_op) {
2806 case SVCCFG_OP_IMPORT :
2807 cbdata.sc_flags |= SCI_OP_IMPORT;
2808 break;
2809 case SVCCFG_OP_APPLY :
2810 cbdata.sc_flags |= SCI_OP_APPLY;
2811 break;
2812 case SVCCFG_OP_RESTORE :
2813 cbdata.sc_flags |= SCI_OP_RESTORE;
2814 break;
2815 default :
2816 uu_die(gettext("lscf_import_instance_pgs : "
2817 "Unknown op stored in the instance entity\n"));
2818 }
2819 }
2820
2821 if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2822 UU_DEFAULT) != 0) {
2823 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2824 bad_error("uu_list_walk", uu_error());
2825
2826 return (cbdata.sc_err);
2827 }
2828
2829 if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2830 cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2831 /*
2832 * If importing with the SCI_NOENABLED flag then
2833 * skip the delay, but if not then add the delay
2834 * of the enable property.
2835 */
2836 if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2837 cbdata.sc_flags |= SCI_DELAYENABLE;
2838 }
2839
2840 if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2841 != UU_WALK_NEXT)
2842 return (cbdata.sc_err);
2843 }
2844
2845 return (0);
2846 }
2847
2848 /*
2849 * Report the reasons why we can't upgrade pg2 to pg1.
2850 */
2851 static void
2852 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2853 int new)
2854 {
2855 property_t *p1, *p2;
2856
2857 assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2858
2859 if (!pg_attrs_equal(pg1, pg2, fmri, new))
2860 return;
2861
2862 for (p1 = uu_list_first(pg1->sc_pgroup_props);
2863 p1 != NULL;
2864 p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2865 p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2866 if (p2 != NULL) {
2867 (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2868 new);
2869 continue;
2870 }
2871
2872 if (new)
2873 warn(gettext("Conflict upgrading %s (new property "
2874 "group \"%s\" is missing property \"%s\").\n"),
2875 fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2876 else
2877 warn(gettext("Conflict upgrading %s (property "
2878 "\"%s/%s\" is missing).\n"), fmri,
2879 pg1->sc_pgroup_name, p1->sc_property_name);
2880 }
2881
2882 /*
2883 * Since pg1 should be from the manifest, any properties in pg2 which
2884 * aren't in pg1 shouldn't be reported as conflicts.
2885 */
2886 }
2887
2888 /*
2889 * Add transaction entries to tx which will upgrade cur's pg according to old
2890 * & new.
2891 *
2892 * Returns
2893 * 0 - success
2894 * EINVAL - new has a property with an invalid name or value (message emitted)
2895 * ENOMEM - out of memory
2896 */
2897 static int
2898 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2899 pgroup_t *cur, int speak, const char *fmri)
2900 {
2901 property_t *p, *new_p, *cur_p;
2902 scf_transaction_entry_t *e;
2903 int r;
2904 int is_general;
2905 int is_protected;
2906
2907 if (uu_list_walk(new->sc_pgroup_props, clear_int,
2908 (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2909 bad_error("uu_list_walk", uu_error());
2910
2911 is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2912
2913 for (p = uu_list_first(old->sc_pgroup_props);
2914 p != NULL;
2915 p = uu_list_next(old->sc_pgroup_props, p)) {
2916 /* p is a property in the old property group. */
2917
2918 /* Protect live properties. */
2919 is_protected = 0;
2920 if (is_general) {
2921 if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2922 0 ||
2923 strcmp(p->sc_property_name,
2924 SCF_PROPERTY_RESTARTER) == 0)
2925 is_protected = 1;
2926 }
2927
2928 /* Look for the same property in the new properties. */
2929 new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2930 if (new_p != NULL) {
2931 new_p->sc_seen = 1;
2932
2933 /*
2934 * If the new property is the same as the old, don't do
2935 * anything (leave any user customizations).
2936 */
2937 if (prop_equal(p, new_p, NULL, NULL, 0))
2938 continue;
2939
2940 if (new_p->sc_property_override)
2941 goto upgrade;
2942 }
2943
2944 cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2945 if (cur_p == NULL) {
2946 /*
2947 * p has been deleted from the repository. If we were
2948 * going to delete it anyway, do nothing. Otherwise
2949 * report a conflict.
2950 */
2951 if (new_p == NULL)
2952 continue;
2953
2954 if (is_protected)
2955 continue;
2956
2957 warn(gettext("Conflict upgrading %s "
2958 "(property \"%s/%s\" is missing).\n"), fmri,
2959 old->sc_pgroup_name, p->sc_property_name);
2960 continue;
2961 }
2962
2963 if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2964 /*
2965 * Conflict. Don't warn if the property is already the
2966 * way we want it, though.
2967 */
2968 if (is_protected)
2969 continue;
2970
2971 if (new_p == NULL)
2972 (void) prop_equal(p, cur_p, fmri,
2973 old->sc_pgroup_name, 0);
2974 else
2975 (void) prop_equal(cur_p, new_p, fmri,
2976 old->sc_pgroup_name, 0);
2977 continue;
2978 }
2979
2980 if (is_protected) {
2981 if (speak)
2982 warn(gettext("%s: Refusing to upgrade "
2983 "\"%s/%s\" (live property).\n"), fmri,
2984 old->sc_pgroup_name, p->sc_property_name);
2985 continue;
2986 }
2987
2988 upgrade:
2989 /* p hasn't been customized in the repository. Upgrade it. */
2990 if (new_p == NULL) {
2991 /* p was deleted. Delete from cur if unchanged. */
2992 if (speak)
2993 warn(gettext(
2994 "%s: Deleting property \"%s/%s\".\n"),
2995 fmri, old->sc_pgroup_name,
2996 p->sc_property_name);
2997
2998 e = scf_entry_create(g_hndl);
2999 if (e == NULL)
3000 return (ENOMEM);
3001
3002 if (scf_transaction_property_delete(tx, e,
3003 p->sc_property_name) != 0) {
3004 switch (scf_error()) {
3005 case SCF_ERROR_DELETED:
3006 scf_entry_destroy(e);
3007 return (ECANCELED);
3008
3009 case SCF_ERROR_CONNECTION_BROKEN:
3010 scf_entry_destroy(e);
3011 return (ECONNABORTED);
3012
3013 case SCF_ERROR_NOT_FOUND:
3014 /*
3015 * This can happen if cur is from the
3016 * running snapshot (and it differs
3017 * from the live properties).
3018 */
3019 scf_entry_destroy(e);
3020 break;
3021
3022 case SCF_ERROR_HANDLE_MISMATCH:
3023 case SCF_ERROR_NOT_BOUND:
3024 case SCF_ERROR_NOT_SET:
3025 case SCF_ERROR_INVALID_ARGUMENT:
3026 default:
3027 bad_error(
3028 "scf_transaction_property_delete",
3029 scf_error());
3030 }
3031 }
3032 } else {
3033 scf_callback_t ctx;
3034
3035 if (speak)
3036 warn(gettext(
3037 "%s: Upgrading property \"%s/%s\".\n"),
3038 fmri, old->sc_pgroup_name,
3039 p->sc_property_name);
3040
3041 ctx.sc_handle = g_hndl;
3042 ctx.sc_trans = tx;
3043 ctx.sc_flags = 0;
3044
3045 r = lscf_property_import(new_p, &ctx);
3046 if (r != UU_WALK_NEXT) {
3047 if (r != UU_WALK_ERROR)
3048 bad_error("lscf_property_import", r);
3049 return (EINVAL);
3050 }
3051 }
3052 }
3053
3054 /* Go over the properties which were added. */
3055 for (new_p = uu_list_first(new->sc_pgroup_props);
3056 new_p != NULL;
3057 new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
3058 if (new_p->sc_seen)
3059 continue;
3060
3061 /* This is a new property. */
3062 cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
3063 if (cur_p == NULL) {
3064 scf_callback_t ctx;
3065
3066 ctx.sc_handle = g_hndl;
3067 ctx.sc_trans = tx;
3068 ctx.sc_flags = 0;
3069
3070 r = lscf_property_import(new_p, &ctx);
3071 if (r != UU_WALK_NEXT) {
3072 if (r != UU_WALK_ERROR)
3073 bad_error("lscf_property_import", r);
3074 return (EINVAL);
3075 }
3076 continue;
3077 }
3078
3079 /*
3080 * Report a conflict if the new property differs from the
3081 * current one. Unless it's general/enabled, since that's
3082 * never in the last-import snapshot.
3083 */
3084 if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
3085 0 &&
3086 strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
3087 continue;
3088
3089 (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
3090 }
3091
3092 return (0);
3093 }
3094
3095 /*
3096 * Upgrade pg according to old & new.
3097 *
3098 * Returns
3099 * 0 - success
3100 * ECONNABORTED - repository connection broken
3101 * ENOMEM - out of memory
3102 * ENOSPC - svc.configd is out of resources
3103 * ECANCELED - pg was deleted
3104 * EPERM - couldn't modify pg (permission denied)
3105 * EROFS - couldn't modify pg (backend read-only)
3106 * EACCES - couldn't modify pg (backend access denied)
3107 * EINVAL - new has a property with invalid name or value (error printed)
3108 * EBUSY - pg changed unexpectedly
3109 */
3110 static int
3111 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
3112 pgroup_t *new, int speak, const char *fmri)
3113 {
3114 int r;
3115
3116 if (scf_transaction_start(imp_tx, pg) != 0) {
3117 switch (scf_error()) {
3118 case SCF_ERROR_CONNECTION_BROKEN:
3119 case SCF_ERROR_DELETED:
3120 case SCF_ERROR_PERMISSION_DENIED:
3121 case SCF_ERROR_BACKEND_READONLY:
3122 case SCF_ERROR_BACKEND_ACCESS:
3123 return (scferror2errno(scf_error()));
3124
3125 case SCF_ERROR_HANDLE_MISMATCH:
3126 case SCF_ERROR_IN_USE:
3127 case SCF_ERROR_NOT_BOUND:
3128 case SCF_ERROR_NOT_SET:
3129 default:
3130 bad_error("scf_transaction_start", scf_error());
3131 }
3132 }
3133
3134 r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
3135 switch (r) {
3136 case 0:
3137 break;
3138
3139 case EINVAL:
3140 case ENOMEM:
3141 scf_transaction_destroy_children(imp_tx);
3142 return (r);
3143
3144 default:
3145 bad_error("add_upgrade_entries", r);
3146 }
3147
3148 r = scf_transaction_commit(imp_tx);
3149
3150 scf_transaction_destroy_children(imp_tx);
3151
3152 switch (r) {
3153 case 1:
3154 break;
3155
3156 case 0:
3157 return (EBUSY);
3158
3159 case -1:
3160 switch (scf_error()) {
3161 case SCF_ERROR_CONNECTION_BROKEN:
3162 case SCF_ERROR_NO_RESOURCES:
3163 case SCF_ERROR_PERMISSION_DENIED:
3164 case SCF_ERROR_BACKEND_READONLY:
3165 case SCF_ERROR_BACKEND_ACCESS:
3166 case SCF_ERROR_DELETED:
3167 return (scferror2errno(scf_error()));
3168
3169 case SCF_ERROR_NOT_BOUND:
3170 case SCF_ERROR_INVALID_ARGUMENT:
3171 case SCF_ERROR_NOT_SET:
3172 default:
3173 bad_error("scf_transaction_commit", scf_error());
3174 }
3175
3176 default:
3177 bad_error("scf_transaction_commit", r);
3178 }
3179
3180 return (0);
3181 }
3182
3183 /*
3184 * Compares two entity FMRIs. Returns
3185 *
3186 * 1 - equal
3187 * 0 - not equal
3188 * -1 - f1 is invalid or not an entity
3189 * -2 - f2 is invalid or not an entity
3190 */
3191 static int
3192 fmri_equal(const char *f1, const char *f2)
3193 {
3194 int r;
3195 const char *s1, *i1, *pg1;
3196 const char *s2, *i2, *pg2;
3197
3198 if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3199 return (-1);
3200 if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
3201 return (-1);
3202
3203 if (s1 == NULL || pg1 != NULL)
3204 return (-1);
3205
3206 if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3207 return (-2);
3208 if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
3209 return (-2);
3210
3211 if (s2 == NULL || pg2 != NULL)
3212 return (-2);
3213
3214 r = strcmp(s1, s2);
3215 if (r != 0)
3216 return (0);
3217
3218 if (i1 == NULL && i2 == NULL)
3219 return (1);
3220
3221 if (i1 == NULL || i2 == NULL)
3222 return (0);
3223
3224 return (strcmp(i1, i2) == 0);
3225 }
3226
3227 /*
3228 * Import a dependent by creating a dependency property group in the dependent
3229 * entity. If lcbdata->sc_trans is set, assume it's been started on the
3230 * dependents pg, and add an entry to create a new property for this
3231 * dependent. Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3232 *
3233 * On success, returns UU_WALK_NEXT. On error, returns UU_WALK_ERROR and sets
3234 * lcbdata->sc_err to
3235 * ECONNABORTED - repository connection broken
3236 * ENOMEM - out of memory
3237 * ENOSPC - configd is out of resources
3238 * EINVAL - target is invalid (error printed)
3239 * - target is not an entity (error printed)
3240 * - dependent has invalid name (error printed)
3241 * - invalid property name (error printed)
3242 * - invalid value (error printed)
3243 * - scope of target does not exist (error printed)
3244 * EPERM - couldn't create target (permission denied) (error printed)
3245 * - couldn't create dependency pg (permission denied) (error printed)
3246 * - couldn't modify dependency pg (permission denied) (error printed)
3247 * EROFS - couldn't create target (repository read-only)
3248 * - couldn't create dependency pg (repository read-only)
3249 * EACCES - couldn't create target (backend access denied)
3250 * - couldn't create dependency pg (backend access denied)
3251 * ECANCELED - sc_trans's pg was deleted
3252 * EALREADY - property for dependent already exists in sc_trans's pg
3253 * EEXIST - dependency pg already exists in target (error printed)
3254 * EBUSY - target deleted (error printed)
3255 * - property group changed during import (error printed)
3256 */
3257 static int
3258 lscf_dependent_import(void *a1, void *pvt)
3259 {
3260 pgroup_t *pgrp = a1;
3261 scf_callback_t *lcbdata = pvt;
3262
3263 int isservice;
3264 int ret;
3265 scf_transaction_entry_t *e;
3266 scf_value_t *val;
3267 scf_callback_t dependent_cbdata;
3268 scf_error_t scfe;
3269
3270 /*
3271 * Decode the FMRI into dependent_cbdata->sc_parent. Do it here so if
3272 * it's invalid, we fail before modifying the repository.
3273 */
3274 scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3275 &dependent_cbdata.sc_parent, &isservice);
3276 switch (scfe) {
3277 case SCF_ERROR_NONE:
3278 break;
3279
3280 case SCF_ERROR_NO_MEMORY:
3281 return (stash_scferror_err(lcbdata, scfe));
3282
3283 case SCF_ERROR_INVALID_ARGUMENT:
3284 semerr(gettext("The FMRI for the \"%s\" dependent is "
3285 "invalid.\n"), pgrp->sc_pgroup_name);
3286 return (stash_scferror_err(lcbdata, scfe));
3287
3288 case SCF_ERROR_CONSTRAINT_VIOLATED:
3289 semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3290 "specifies neither a service nor an instance.\n"),
3291 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3292 return (stash_scferror_err(lcbdata, scfe));
3293
3294 case SCF_ERROR_NOT_FOUND:
3295 scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3296 &dependent_cbdata.sc_parent, &isservice);
3297 switch (scfe) {
3298 case SCF_ERROR_NONE:
3299 break;
3300
3301 case SCF_ERROR_NO_MEMORY:
3302 case SCF_ERROR_BACKEND_READONLY:
3303 case SCF_ERROR_BACKEND_ACCESS:
3304 return (stash_scferror_err(lcbdata, scfe));
3305
3306 case SCF_ERROR_NOT_FOUND:
3307 semerr(gettext("The scope in FMRI \"%s\" for the "
3308 "\"%s\" dependent does not exist.\n"),
3309 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3310 lcbdata->sc_err = EINVAL;
3311 return (UU_WALK_ERROR);
3312
3313 case SCF_ERROR_PERMISSION_DENIED:
3314 warn(gettext(
3315 "Could not create %s (permission denied).\n"),
3316 pgrp->sc_pgroup_fmri);
3317 return (stash_scferror_err(lcbdata, scfe));
3318
3319 case SCF_ERROR_INVALID_ARGUMENT:
3320 case SCF_ERROR_CONSTRAINT_VIOLATED:
3321 default:
3322 bad_error("create_entity", scfe);
3323 }
3324 break;
3325
3326 default:
3327 bad_error("fmri_to_entity", scfe);
3328 }
3329
3330 if (lcbdata->sc_trans != NULL) {
3331 e = scf_entry_create(lcbdata->sc_handle);
3332 if (e == NULL) {
3333 if (scf_error() != SCF_ERROR_NO_MEMORY)
3334 bad_error("scf_entry_create", scf_error());
3335
3336 entity_destroy(dependent_cbdata.sc_parent, isservice);
3337 return (stash_scferror(lcbdata));
3338 }
3339
3340 if (scf_transaction_property_new(lcbdata->sc_trans, e,
3341 pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
3342 switch (scf_error()) {
3343 case SCF_ERROR_INVALID_ARGUMENT:
3344 warn(gettext("Dependent of %s has invalid name "
3345 "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
3346 pgrp->sc_pgroup_name);
3347 /* FALLTHROUGH */
3348
3349 case SCF_ERROR_DELETED:
3350 case SCF_ERROR_CONNECTION_BROKEN:
3351 scf_entry_destroy(e);
3352 entity_destroy(dependent_cbdata.sc_parent,
3353 isservice);
3354 return (stash_scferror(lcbdata));
3355
3356 case SCF_ERROR_EXISTS:
3357 scf_entry_destroy(e);
3358 entity_destroy(dependent_cbdata.sc_parent,
3359 isservice);
3360 lcbdata->sc_err = EALREADY;
3361 return (UU_WALK_ERROR);
3362
3363 case SCF_ERROR_NOT_BOUND:
3364 case SCF_ERROR_HANDLE_MISMATCH:
3365 case SCF_ERROR_NOT_SET:
3366 default:
3367 bad_error("scf_transaction_property_new",
3368 scf_error());
3369 }
3370 }
3371
3372 val = scf_value_create(lcbdata->sc_handle);
3373 if (val == NULL) {
3374 if (scf_error() != SCF_ERROR_NO_MEMORY)
3375 bad_error("scf_value_create", scf_error());
3376
3377 entity_destroy(dependent_cbdata.sc_parent, isservice);
3378 return (stash_scferror(lcbdata));
3379 }
3380
3381 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
3382 pgrp->sc_pgroup_fmri) != 0)
3383 /* invalid should have been caught above */
3384 bad_error("scf_value_set_from_string", scf_error());
3385
3386 if (scf_entry_add_value(e, val) != 0)
3387 bad_error("scf_entry_add_value", scf_error());
3388 }
3389
3390 /* Add the property group to the target entity. */
3391
3392 dependent_cbdata.sc_handle = lcbdata->sc_handle;
3393 dependent_cbdata.sc_flags = lcbdata->sc_flags;
3394 dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
3395 dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
3396
3397 ret = entity_pgroup_import(pgrp, &dependent_cbdata);
3398
3399 entity_destroy(dependent_cbdata.sc_parent, isservice);
3400
3401 if (ret == UU_WALK_NEXT)
3402 return (ret);
3403
3404 if (ret != UU_WALK_ERROR)
3405 bad_error("entity_pgroup_import", ret);
3406
3407 switch (dependent_cbdata.sc_err) {
3408 case ECANCELED:
3409 warn(gettext("%s deleted unexpectedly.\n"),
3410 pgrp->sc_pgroup_fmri);
3411 lcbdata->sc_err = EBUSY;
3412 break;
3413
3414 case EEXIST:
3415 warn(gettext("Could not create \"%s\" dependency in %s "
3416 "(already exists).\n"), pgrp->sc_pgroup_name,
3417 pgrp->sc_pgroup_fmri);
3418 /* FALLTHROUGH */
3419
3420 default:
3421 lcbdata->sc_err = dependent_cbdata.sc_err;
3422 }
3423
3424 return (UU_WALK_ERROR);
3425 }
3426
3427 static int upgrade_dependent(const scf_property_t *, const entity_t *,
3428 const scf_snaplevel_t *, scf_transaction_t *);
3429 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
3430 const pgroup_t *);
3431
3432 /*
3433 * Upgrade uncustomized dependents of ent to those specified in ient. Read
3434 * the current dependent targets from running (the snaplevel of a running
3435 * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3436 * scf_instance_t * according to ient, otherwise). Draw the ancestral
3437 * dependent targets and dependency properties from li_dpts_pg (the
3438 * "dependents" property group in snpl) and snpl (the snaplevel which
3439 * corresponds to ent in a last-import snapshot). If li_dpts_pg is NULL, then
3440 * snpl doesn't have a "dependents" property group, and any dependents in ient
3441 * are new.
3442 *
3443 * Returns
3444 * 0 - success
3445 * ECONNABORTED - repository connection broken
3446 * ENOMEM - out of memory
3447 * ENOSPC - configd is out of resources
3448 * ECANCELED - ent was deleted
3449 * ENODEV - the entity containing li_dpts_pg was deleted
3450 * EPERM - could not modify dependents pg (permission denied) (error printed)
3451 * - couldn't upgrade dependent (permission denied) (error printed)
3452 * - couldn't create dependent (permission denied) (error printed)
3453 * EROFS - could not modify dependents pg (repository read-only)
3454 * - couldn't upgrade dependent (repository read-only)
3455 * - couldn't create dependent (repository read-only)
3456 * EACCES - could not modify dependents pg (backend access denied)
3457 * - could not upgrade dependent (backend access denied)
3458 * - could not create dependent (backend access denied)
3459 * EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3460 * - dependent target deleted (error printed)
3461 * - dependent pg changed (error printed)
3462 * EINVAL - new dependent is invalid (error printed)
3463 * EBADF - snpl is corrupt (error printed)
3464 * - snpl has corrupt pg (error printed)
3465 * - dependency pg in target is corrupt (error printed)
3466 * - target has corrupt snapshot (error printed)
3467 * EEXIST - dependency pg already existed in target service (error printed)
3468 */
3469 static int
3470 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
3471 const scf_snaplevel_t *snpl, const entity_t *ient,
3472 const scf_snaplevel_t *running, void *ent)
3473 {
3474 pgroup_t *new_dpt_pgroup;
3475 scf_callback_t cbdata;
3476 int r, unseen, tx_started = 0;
3477 int have_cur_depts;
3478
3479 const char * const dependents = "dependents";
3480
3481 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3482
3483 if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
3484 /* Nothing to do. */
3485 return (0);
3486
3487 /* Fetch the current version of the "dependents" property group. */
3488 have_cur_depts = 1;
3489 if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
3490 switch (scf_error()) {
3491 case SCF_ERROR_NOT_FOUND:
3492 break;
3493
3494 case SCF_ERROR_DELETED:
3495 case SCF_ERROR_CONNECTION_BROKEN:
3496 return (scferror2errno(scf_error()));
3497
3498 case SCF_ERROR_NOT_SET:
3499 case SCF_ERROR_INVALID_ARGUMENT:
3500 case SCF_ERROR_HANDLE_MISMATCH:
3501 case SCF_ERROR_NOT_BOUND:
3502 default:
3503 bad_error("entity_get_pg", scf_error());
3504 }
3505
3506 have_cur_depts = 0;
3507 }
3508
3509 /* Fetch the running version of the "dependents" property group. */
3510 ud_run_dpts_pg_set = 0;
3511 if (running != NULL)
3512 r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
3513 else
3514 r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
3515 if (r == 0) {
3516 ud_run_dpts_pg_set = 1;
3517 } else {
3518 switch (scf_error()) {
3519 case SCF_ERROR_NOT_FOUND:
3520 break;
3521
3522 case SCF_ERROR_DELETED:
3523 case SCF_ERROR_CONNECTION_BROKEN:
3524 return (scferror2errno(scf_error()));
3525
3526 case SCF_ERROR_NOT_SET:
3527 case SCF_ERROR_INVALID_ARGUMENT:
3528 case SCF_ERROR_HANDLE_MISMATCH:
3529 case SCF_ERROR_NOT_BOUND:
3530 default:
3531 bad_error(running ? "scf_snaplevel_get_pg" :
3532 "entity_get_pg", scf_error());
3533 }
3534 }
3535
3536 /*
3537 * Clear the seen fields of the dependents, so we can tell which ones
3538 * are new.
3539 */
3540 if (uu_list_walk(ient->sc_dependents, clear_int,
3541 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3542 bad_error("uu_list_walk", uu_error());
3543
3544 if (li_dpts_pg != NULL) {
3545 /*
3546 * Each property in li_dpts_pg represents a dependent tag in
3547 * the old manifest. For each, call upgrade_dependent(),
3548 * which will change ud_cur_depts_pg or dependencies in other
3549 * services as appropriate. Note (a) that changes to
3550 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3551 * made en masse, and (b) it's ok if the entity doesn't have
3552 * a current version of the "dependents" property group,
3553 * because we'll just consider all dependents as customized
3554 * (by being deleted).
3555 */
3556
3557 if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3558 switch (scf_error()) {
3559 case SCF_ERROR_DELETED:
3560 return (ENODEV);
3561
3562 case SCF_ERROR_CONNECTION_BROKEN:
3563 return (ECONNABORTED);
3564
3565 case SCF_ERROR_HANDLE_MISMATCH:
3566 case SCF_ERROR_NOT_BOUND:
3567 case SCF_ERROR_NOT_SET:
3568 default:
3569 bad_error("scf_iter_pg_properties",
3570 scf_error());
3571 }
3572 }
3573
3574 if (have_cur_depts &&
3575 scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3576 switch (scf_error()) {
3577 case SCF_ERROR_BACKEND_ACCESS:
3578 case SCF_ERROR_BACKEND_READONLY:
3579 case SCF_ERROR_CONNECTION_BROKEN:
3580 return (scferror2errno(scf_error()));
3581
3582 case SCF_ERROR_DELETED:
3583 warn(emsg_pg_deleted, ient->sc_fmri,
3584 dependents);
3585 return (EBUSY);
3586
3587 case SCF_ERROR_PERMISSION_DENIED:
3588 warn(emsg_pg_mod_perm, dependents,
3589 ient->sc_fmri);
3590 return (scferror2errno(scf_error()));
3591
3592 case SCF_ERROR_HANDLE_MISMATCH:
3593 case SCF_ERROR_IN_USE:
3594 case SCF_ERROR_NOT_BOUND:
3595 case SCF_ERROR_NOT_SET:
3596 default:
3597 bad_error("scf_transaction_start", scf_error());
3598 }
3599 }
3600 tx_started = have_cur_depts;
3601
3602 for (;;) {
3603 r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3604 if (r == 0)
3605 break;
3606 if (r == 1) {
3607 r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3608 tx_started ? ud_tx : NULL);
3609 switch (r) {
3610 case 0:
3611 continue;
3612
3613 case ECONNABORTED:
3614 case ENOMEM:
3615 case ENOSPC:
3616 case EBADF:
3617 case EBUSY:
3618 case EINVAL:
3619 case EPERM:
3620 case EROFS:
3621 case EACCES:
3622 case EEXIST:
3623 break;
3624
3625 case ECANCELED:
3626 r = ENODEV;
3627 break;
3628
3629 default:
3630 bad_error("upgrade_dependent", r);
3631 }
3632
3633 if (tx_started)
3634 scf_transaction_destroy_children(ud_tx);
3635 return (r);
3636 }
3637 if (r != -1)
3638 bad_error("scf_iter_next_property", r);
3639
3640 switch (scf_error()) {
3641 case SCF_ERROR_DELETED:
3642 r = ENODEV;
3643 break;
3644
3645 case SCF_ERROR_CONNECTION_BROKEN:
3646 r = ECONNABORTED;
3647 break;
3648
3649 case SCF_ERROR_NOT_SET:
3650 case SCF_ERROR_INVALID_ARGUMENT:
3651 case SCF_ERROR_NOT_BOUND:
3652 case SCF_ERROR_HANDLE_MISMATCH:
3653 default:
3654 bad_error("scf_iter_next_property",
3655 scf_error());
3656 }
3657
3658 if (tx_started)
3659 scf_transaction_destroy_children(ud_tx);
3660 return (r);
3661 }
3662 }
3663
3664 /* import unseen dependents */
3665 unseen = 0;
3666 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3667 new_dpt_pgroup != NULL;
3668 new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3669 new_dpt_pgroup)) {
3670 if (!new_dpt_pgroup->sc_pgroup_seen) {
3671 unseen = 1;
3672 break;
3673 }
3674 }
3675
3676 /* If there are none, exit early. */
3677 if (unseen == 0)
3678 goto commit;
3679
3680 /* Set up for lscf_dependent_import() */
3681 cbdata.sc_handle = g_hndl;
3682 cbdata.sc_parent = ent;
3683 cbdata.sc_service = issvc;
3684 cbdata.sc_flags = 0;
3685
3686 if (!have_cur_depts) {
3687 /*
3688 * We have new dependents to import, so we need a "dependents"
3689 * property group.
3690 */
3691 if (issvc)
3692 r = scf_service_add_pg(ent, dependents,
3693 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3694 else
3695 r = scf_instance_add_pg(ent, dependents,
3696 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3697 if (r != 0) {
3698 switch (scf_error()) {
3699 case SCF_ERROR_DELETED:
3700 case SCF_ERROR_CONNECTION_BROKEN:
3701 case SCF_ERROR_BACKEND_READONLY:
3702 case SCF_ERROR_BACKEND_ACCESS:
3703 case SCF_ERROR_NO_RESOURCES:
3704 return (scferror2errno(scf_error()));
3705
3706 case SCF_ERROR_EXISTS:
3707 warn(emsg_pg_added, ient->sc_fmri, dependents);
3708 return (EBUSY);
3709
3710 case SCF_ERROR_PERMISSION_DENIED:
3711 warn(emsg_pg_add_perm, dependents,
3712 ient->sc_fmri);
3713 return (scferror2errno(scf_error()));
3714
3715 case SCF_ERROR_NOT_BOUND:
3716 case SCF_ERROR_HANDLE_MISMATCH:
3717 case SCF_ERROR_INVALID_ARGUMENT:
3718 case SCF_ERROR_NOT_SET:
3719 default:
3720 bad_error("scf_service_add_pg", scf_error());
3721 }
3722 }
3723 }
3724
3725 cbdata.sc_trans = ud_tx;
3726
3727 if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3728 switch (scf_error()) {
3729 case SCF_ERROR_CONNECTION_BROKEN:
3730 case SCF_ERROR_BACKEND_ACCESS:
3731 case SCF_ERROR_BACKEND_READONLY:
3732 return (scferror2errno(scf_error()));
3733
3734 case SCF_ERROR_DELETED:
3735 warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3736 return (EBUSY);
3737
3738 case SCF_ERROR_PERMISSION_DENIED:
3739 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3740 return (scferror2errno(scf_error()));
3741
3742 case SCF_ERROR_HANDLE_MISMATCH:
3743 case SCF_ERROR_IN_USE:
3744 case SCF_ERROR_NOT_BOUND:
3745 case SCF_ERROR_NOT_SET:
3746 default:
3747 bad_error("scf_transaction_start", scf_error());
3748 }
3749 }
3750 tx_started = 1;
3751
3752 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3753 new_dpt_pgroup != NULL;
3754 new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3755 new_dpt_pgroup)) {
3756 if (new_dpt_pgroup->sc_pgroup_seen)
3757 continue;
3758
3759 if (ud_run_dpts_pg_set) {
3760 /*
3761 * If the dependent is already there, then we have
3762 * a conflict.
3763 */
3764 if (scf_pg_get_property(ud_run_dpts_pg,
3765 new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3766 r = handle_dependent_conflict(ient, ud_prop,
3767 new_dpt_pgroup);
3768 switch (r) {
3769 case 0:
3770 continue;
3771
3772 case ECONNABORTED:
3773 case ENOMEM:
3774 case EBUSY:
3775 case EBADF:
3776 case EINVAL:
3777 scf_transaction_destroy_children(ud_tx);
3778 return (r);
3779
3780 default:
3781 bad_error("handle_dependent_conflict",
3782 r);
3783 }
3784 } else {
3785 switch (scf_error()) {
3786 case SCF_ERROR_NOT_FOUND:
3787 break;
3788
3789 case SCF_ERROR_INVALID_ARGUMENT:
3790 warn(emsg_fmri_invalid_pg_name,
3791 ient->sc_fmri,
3792 new_dpt_pgroup->sc_pgroup_name);
3793 scf_transaction_destroy_children(ud_tx);
3794 return (EINVAL);
3795
3796 case SCF_ERROR_DELETED:
3797 warn(emsg_pg_deleted, ient->sc_fmri,
3798 new_dpt_pgroup->sc_pgroup_name);
3799 scf_transaction_destroy_children(ud_tx);
3800 return (EBUSY);
3801
3802 case SCF_ERROR_CONNECTION_BROKEN:
3803 scf_transaction_destroy_children(ud_tx);
3804 return (ECONNABORTED);
3805
3806 case SCF_ERROR_NOT_BOUND:
3807 case SCF_ERROR_HANDLE_MISMATCH:
3808 case SCF_ERROR_NOT_SET:
3809 default:
3810 bad_error("scf_pg_get_property",
3811 scf_error());
3812 }
3813 }
3814 }
3815
3816 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3817 if (r != UU_WALK_NEXT) {
3818 if (r != UU_WALK_ERROR)
3819 bad_error("lscf_dependent_import", r);
3820
3821 if (cbdata.sc_err == EALREADY) {
3822 /* Collisions were handled preemptively. */
3823 bad_error("lscf_dependent_import",
3824 cbdata.sc_err);
3825 }
3826
3827 scf_transaction_destroy_children(ud_tx);
3828 return (cbdata.sc_err);
3829 }
3830 }
3831
3832 commit:
3833 if (!tx_started)
3834 return (0);
3835
3836 r = scf_transaction_commit(ud_tx);
3837
3838 scf_transaction_destroy_children(ud_tx);
3839
3840 switch (r) {
3841 case 1:
3842 return (0);
3843
3844 case 0:
3845 warn(emsg_pg_changed, ient->sc_fmri, dependents);
3846 return (EBUSY);
3847
3848 case -1:
3849 break;
3850
3851 default:
3852 bad_error("scf_transaction_commit", r);
3853 }
3854
3855 switch (scf_error()) {
3856 case SCF_ERROR_CONNECTION_BROKEN:
3857 case SCF_ERROR_BACKEND_READONLY:
3858 case SCF_ERROR_BACKEND_ACCESS:
3859 case SCF_ERROR_NO_RESOURCES:
3860 return (scferror2errno(scf_error()));
3861
3862 case SCF_ERROR_DELETED:
3863 warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3864 return (EBUSY);
3865
3866 case SCF_ERROR_PERMISSION_DENIED:
3867 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3868 return (scferror2errno(scf_error()));
3869
3870 case SCF_ERROR_NOT_BOUND:
3871 case SCF_ERROR_INVALID_ARGUMENT:
3872 case SCF_ERROR_NOT_SET:
3873 default:
3874 bad_error("scf_transaction_destroy", scf_error());
3875 /* NOTREACHED */
3876 }
3877 }
3878
3879 /*
3880 * Used to add the manifests to the list of currently supported manifests.
3881 * We can modify the existing manifest list removing entries if the files
3882 * don't exist.
3883 *
3884 * Get the old list and the new file name
3885 * If the new file name is in the list return
3886 * If not then add the file to the list.
3887 * As we process the list check to see if the files in the old list exist
3888 * if not then remove the file from the list.
3889 * Commit the list of manifest file names.
3890 *
3891 */
3892 static int
3893 upgrade_manifestfiles(pgroup_t *pg, const entity_t *ient,
3894 const scf_snaplevel_t *running, void *ent)
3895 {
3896 scf_propertygroup_t *ud_mfsts_pg = NULL;
3897 scf_property_t *ud_prop = NULL;
3898 scf_iter_t *ud_prop_iter;
3899 scf_value_t *fname_value;
3900 scf_callback_t cbdata;
3901 pgroup_t *mfst_pgroup;
3902 property_t *mfst_prop;
3903 property_t *old_prop;
3904 char *pname;
3905 char *fval;
3906 char *old_pname;
3907 char *old_fval;
3908 int no_upgrade_pg;
3909 int mfst_seen;
3910 int r;
3911
3912 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3913
3914 /*
3915 * This should always be the service base on the code
3916 * path, and the fact that the manifests pg is a service
3917 * level property group only.
3918 */
3919 ud_mfsts_pg = scf_pg_create(g_hndl);
3920 ud_prop = scf_property_create(g_hndl);
3921 ud_prop_iter = scf_iter_create(g_hndl);
3922 fname_value = scf_value_create(g_hndl);
3923
3924 /* Fetch the "manifests" property group */
3925 no_upgrade_pg = 0;
3926 r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3927 ud_mfsts_pg);
3928 if (r != 0) {
3929 switch (scf_error()) {
3930 case SCF_ERROR_NOT_FOUND:
3931 no_upgrade_pg = 1;
3932 break;
3933
3934 case SCF_ERROR_DELETED:
3935 case SCF_ERROR_CONNECTION_BROKEN:
3936 return (scferror2errno(scf_error()));
3937
3938 case SCF_ERROR_NOT_SET:
3939 case SCF_ERROR_INVALID_ARGUMENT:
3940 case SCF_ERROR_HANDLE_MISMATCH:
3941 case SCF_ERROR_NOT_BOUND:
3942 default:
3943 bad_error(running ? "scf_snaplevel_get_pg" :
3944 "entity_get_pg", scf_error());
3945 }
3946 }
3947
3948 if (no_upgrade_pg) {
3949 cbdata.sc_handle = g_hndl;
3950 cbdata.sc_parent = ent;
3951 cbdata.sc_service = issvc;
3952 cbdata.sc_flags = SCI_FORCE;
3953 cbdata.sc_source_fmri = ient->sc_fmri;
3954 cbdata.sc_target_fmri = ient->sc_fmri;
3955
3956 if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3957 return (cbdata.sc_err);
3958
3959 return (0);
3960 }
3961
3962 /* Fetch the new manifests property group */
3963 for (mfst_pgroup = uu_list_first(ient->sc_pgroups);
3964 mfst_pgroup != NULL;
3965 mfst_pgroup = uu_list_next(ient->sc_pgroups, mfst_pgroup)) {
3966 if (strcmp(mfst_pgroup->sc_pgroup_name,
3967 SCF_PG_MANIFESTFILES) == 0)
3968 break;
3969 }
3970
3971 if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3972 SCF_SUCCESS)
3973 return (-1);
3974
3975 if ((pname = malloc(MAXPATHLEN)) == NULL)
3976 return (ENOMEM);
3977 if ((fval = malloc(MAXPATHLEN)) == NULL) {
3978 free(pname);
3979 return (ENOMEM);
3980 }
3981
3982 while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
3983 mfst_seen = 0;
3984 if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
3985 continue;
3986
3987 for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
3988 mfst_prop != NULL;
3989 mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
3990 mfst_prop)) {
3991 if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
3992 mfst_seen = 1;
3993 }
3994 }
3995
3996 /*
3997 * If the manifest is not seen then add it to the new mfst
3998 * property list to get proccessed into the repo.
3999 */
4000 if (mfst_seen == 0) {
4001 /*
4002 * If we cannot get the value then there is no
4003 * reason to attempt to attach the value to
4004 * the property group
4005 */
4006 if (prop_get_val(ud_prop, fname_value) == 0 &&
4007 scf_value_get_astring(fname_value, fval,
4008 MAXPATHLEN) != -1) {
4009 old_pname = safe_strdup(pname);
4010 old_fval = safe_strdup(fval);
4011 old_prop = internal_property_create(old_pname,
4012 SCF_TYPE_ASTRING, 1, old_fval);
4013
4014 /*
4015 * Already checked to see if the property exists
4016 * in the group, and it does not.
4017 */
4018 (void) internal_attach_property(mfst_pgroup,
4019 old_prop);
4020 }
4021 }
4022 }
4023 free(pname);
4024 free(fval);
4025
4026 cbdata.sc_handle = g_hndl;
4027 cbdata.sc_parent = ent;
4028 cbdata.sc_service = issvc;
4029 cbdata.sc_flags = SCI_FORCE;
4030 cbdata.sc_source_fmri = ient->sc_fmri;
4031 cbdata.sc_target_fmri = ient->sc_fmri;
4032
4033 if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
4034 return (cbdata.sc_err);
4035
4036 return (r);
4037 }
4038
4039 /*
4040 * prop is taken to be a property in the "dependents" property group of snpl,
4041 * which is taken to be the snaplevel of a last-import snapshot corresponding
4042 * to ient. If prop is a valid dependents property, upgrade the dependent it
4043 * represents according to the repository & ient. If ud_run_dpts_pg_set is
4044 * true, then ud_run_dpts_pg is taken to be the "dependents" property group
4045 * of the entity ient represents (possibly in the running snapshot). If it
4046 * needs to be changed, an entry will be added to tx, if not NULL.
4047 *
4048 * Returns
4049 * 0 - success
4050 * ECONNABORTED - repository connection broken
4051 * ENOMEM - out of memory
4052 * ENOSPC - configd was out of resources
4053 * ECANCELED - snpl's entity was deleted
4054 * EINVAL - dependent target is invalid (error printed)
4055 * - dependent is invalid (error printed)
4056 * EBADF - snpl is corrupt (error printed)
4057 * - snpl has corrupt pg (error printed)
4058 * - dependency pg in target is corrupt (error printed)
4059 * - running snapshot in dependent is missing snaplevel (error printed)
4060 * EPERM - couldn't delete dependency pg (permission denied) (error printed)
4061 * - couldn't create dependent (permission denied) (error printed)
4062 * - couldn't modify dependent pg (permission denied) (error printed)
4063 * EROFS - couldn't delete dependency pg (repository read-only)
4064 * - couldn't create dependent (repository read-only)
4065 * EACCES - couldn't delete dependency pg (backend access denied)
4066 * - couldn't create dependent (backend access denied)
4067 * EBUSY - ud_run_dpts_pg was deleted (error printed)
4068 * - tx's pg was deleted (error printed)
4069 * - dependent pg was changed or deleted (error printed)
4070 * EEXIST - dependency pg already exists in new target (error printed)
4071 */
4072 static int
4073 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
4074 const scf_snaplevel_t *snpl, scf_transaction_t *tx)
4075 {
4076 pgroup_t pgrp;
4077 scf_type_t ty;
4078 pgroup_t *new_dpt_pgroup;
4079 pgroup_t *old_dpt_pgroup = NULL;
4080 pgroup_t *current_pg;
4081 pgroup_t *dpt;
4082 scf_callback_t cbdata;
4083 int tissvc;
4084 void *target_ent;
4085 scf_error_t serr;
4086 int r;
4087 scf_transaction_entry_t *ent;
4088
4089 const char * const cf_inval = gettext("Conflict upgrading %s "
4090 "(dependent \"%s\" has invalid dependents property).\n");
4091 const char * const cf_missing = gettext("Conflict upgrading %s "
4092 "(dependent \"%s\" is missing).\n");
4093 const char * const cf_newdpg = gettext("Conflict upgrading %s "
4094 "(dependent \"%s\" has new dependency property group).\n");
4095 const char * const cf_newtarg = gettext("Conflict upgrading %s "
4096 "(dependent \"%s\" has new target).\n");
4097 const char * const li_corrupt =
4098 gettext("%s: \"last-import\" snapshot is corrupt.\n");
4099 const char * const upgrading =
4100 gettext("%s: Upgrading dependent \"%s\".\n");
4101 const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
4102 "corrupt (missing snaplevel).\n");
4103
4104 if (scf_property_type(prop, &ty) != 0) {
4105 switch (scf_error()) {
4106 case SCF_ERROR_DELETED:
4107 case SCF_ERROR_CONNECTION_BROKEN:
4108 return (scferror2errno(scf_error()));
4109
4110 case SCF_ERROR_NOT_BOUND:
4111 case SCF_ERROR_NOT_SET:
4112 default:
4113 bad_error("scf_property_type", scf_error());
4114 }
4115 }
4116
4117 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4118 warn(li_corrupt, ient->sc_fmri);
4119 return (EBADF);
4120 }
4121
4122 /*
4123 * prop represents a dependent in the old manifest. It is named after
4124 * the dependent.
4125 */
4126 if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
4127 switch (scf_error()) {
4128 case SCF_ERROR_DELETED:
4129 case SCF_ERROR_CONNECTION_BROKEN:
4130 return (scferror2errno(scf_error()));
4131
4132 case SCF_ERROR_NOT_BOUND:
4133 case SCF_ERROR_NOT_SET:
4134 default:
4135 bad_error("scf_property_get_name", scf_error());
4136 }
4137 }
4138
4139 /* See if it's in the new manifest. */
4140 pgrp.sc_pgroup_name = ud_name;
4141 new_dpt_pgroup =
4142 uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
4143
4144 /* If it's not, delete it... if it hasn't been customized. */
4145 if (new_dpt_pgroup == NULL) {
4146 if (!ud_run_dpts_pg_set)
4147 return (0);
4148
4149 if (scf_property_get_value(prop, ud_val) != 0) {
4150 switch (scf_error()) {
4151 case SCF_ERROR_NOT_FOUND:
4152 case SCF_ERROR_CONSTRAINT_VIOLATED:
4153 warn(li_corrupt, ient->sc_fmri);
4154 return (EBADF);
4155
4156 case SCF_ERROR_DELETED:
4157 case SCF_ERROR_CONNECTION_BROKEN:
4158 return (scferror2errno(scf_error()));
4159
4160 case SCF_ERROR_HANDLE_MISMATCH:
4161 case SCF_ERROR_NOT_BOUND:
4162 case SCF_ERROR_NOT_SET:
4163 case SCF_ERROR_PERMISSION_DENIED:
4164 default:
4165 bad_error("scf_property_get_value",
4166 scf_error());
4167 }
4168 }
4169
4170 if (scf_value_get_as_string(ud_val, ud_oldtarg,
4171 max_scf_value_len + 1) < 0)
4172 bad_error("scf_value_get_as_string", scf_error());
4173
4174 if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
4175 0) {
4176 switch (scf_error()) {
4177 case SCF_ERROR_NOT_FOUND:
4178 return (0);
4179
4180 case SCF_ERROR_CONNECTION_BROKEN:
4181 return (scferror2errno(scf_error()));
4182
4183 case SCF_ERROR_DELETED:
4184 warn(emsg_pg_deleted, ient->sc_fmri,
4185 "dependents");
4186 return (EBUSY);
4187
4188 case SCF_ERROR_INVALID_ARGUMENT:
4189 case SCF_ERROR_NOT_BOUND:
4190 case SCF_ERROR_HANDLE_MISMATCH:
4191 case SCF_ERROR_NOT_SET:
4192 default:
4193 bad_error("scf_pg_get_property", scf_error());
4194 }
4195 }
4196 if (scf_property_get_value(ud_prop, ud_val) != 0) {
4197 switch (scf_error()) {
4198 case SCF_ERROR_NOT_FOUND:
4199 case SCF_ERROR_CONSTRAINT_VIOLATED:
4200 warn(cf_inval, ient->sc_fmri, ud_name);
4201 return (0);
4202
4203 case SCF_ERROR_DELETED:
4204 case SCF_ERROR_CONNECTION_BROKEN:
4205 return (scferror2errno(scf_error()));
4206
4207 case SCF_ERROR_HANDLE_MISMATCH:
4208 case SCF_ERROR_NOT_BOUND:
4209 case SCF_ERROR_NOT_SET:
4210 case SCF_ERROR_PERMISSION_DENIED:
4211 default:
4212 bad_error("scf_property_get_value",
4213 scf_error());
4214 }
4215 }
4216
4217 ty = scf_value_type(ud_val);
4218 assert(ty != SCF_TYPE_INVALID);
4219 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4220 warn(cf_inval, ient->sc_fmri, ud_name);
4221 return (0);
4222 }
4223
4224 if (scf_value_get_as_string(ud_val, ud_ctarg,
4225 max_scf_value_len + 1) < 0)
4226 bad_error("scf_value_get_as_string", scf_error());
4227
4228 r = fmri_equal(ud_ctarg, ud_oldtarg);
4229 switch (r) {
4230 case 1:
4231 break;
4232
4233 case 0:
4234 case -1: /* warn? */
4235 warn(cf_newtarg, ient->sc_fmri, ud_name);
4236 return (0);
4237
4238 case -2:
4239 warn(li_corrupt, ient->sc_fmri);
4240 return (EBADF);
4241
4242 default:
4243 bad_error("fmri_equal", r);
4244 }
4245
4246 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4247 switch (scf_error()) {
4248 case SCF_ERROR_NOT_FOUND:
4249 warn(li_corrupt, ient->sc_fmri);
4250 return (EBADF);
4251
4252 case SCF_ERROR_DELETED:
4253 case SCF_ERROR_CONNECTION_BROKEN:
4254 return (scferror2errno(scf_error()));
4255
4256 case SCF_ERROR_NOT_BOUND:
4257 case SCF_ERROR_HANDLE_MISMATCH:
4258 case SCF_ERROR_INVALID_ARGUMENT:
4259 case SCF_ERROR_NOT_SET:
4260 default:
4261 bad_error("scf_snaplevel_get_pg", scf_error());
4262 }
4263 }
4264
4265 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4266 snap_lastimport);
4267 switch (r) {
4268 case 0:
4269 break;
4270
4271 case ECANCELED:
4272 case ECONNABORTED:
4273 case ENOMEM:
4274 case EBADF:
4275 return (r);
4276
4277 case EACCES:
4278 default:
4279 bad_error("load_pg", r);
4280 }
4281
4282 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4283 switch (serr) {
4284 case SCF_ERROR_NONE:
4285 break;
4286
4287 case SCF_ERROR_NO_MEMORY:
4288 internal_pgroup_free(old_dpt_pgroup);
4289 return (ENOMEM);
4290
4291 case SCF_ERROR_NOT_FOUND:
4292 internal_pgroup_free(old_dpt_pgroup);
4293 goto delprop;
4294
4295 case SCF_ERROR_CONSTRAINT_VIOLATED: /* caught above */
4296 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
4297 default:
4298 bad_error("fmri_to_entity", serr);
4299 }
4300
4301 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4302 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4303 switch (r) {
4304 case 0:
4305 break;
4306
4307 case ECONNABORTED:
4308 internal_pgroup_free(old_dpt_pgroup);
4309 return (r);
4310
4311 case ECANCELED:
4312 case ENOENT:
4313 internal_pgroup_free(old_dpt_pgroup);
4314 goto delprop;
4315
4316 case EBADF:
4317 warn(r_no_lvl, ud_ctarg);
4318 internal_pgroup_free(old_dpt_pgroup);
4319 return (r);
4320
4321 case EINVAL:
4322 default:
4323 bad_error("entity_get_running_pg", r);
4324 }
4325
4326 /* load it */
4327 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4328 switch (r) {
4329 case 0:
4330 break;
4331
4332 case ECANCELED:
4333 internal_pgroup_free(old_dpt_pgroup);
4334 goto delprop;
4335
4336 case ECONNABORTED:
4337 case ENOMEM:
4338 case EBADF:
4339 internal_pgroup_free(old_dpt_pgroup);
4340 return (r);
4341
4342 case EACCES:
4343 default:
4344 bad_error("load_pg", r);
4345 }
4346
4347 /* compare property groups */
4348 if (!pg_equal(old_dpt_pgroup, current_pg)) {
4349 warn(cf_newdpg, ient->sc_fmri, ud_name);
4350 internal_pgroup_free(old_dpt_pgroup);
4351 internal_pgroup_free(current_pg);
4352 return (0);
4353 }
4354
4355 internal_pgroup_free(old_dpt_pgroup);
4356 internal_pgroup_free(current_pg);
4357
4358 if (g_verbose)
4359 warn(gettext("%s: Deleting dependent \"%s\".\n"),
4360 ient->sc_fmri, ud_name);
4361
4362 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4363 switch (scf_error()) {
4364 case SCF_ERROR_NOT_FOUND:
4365 case SCF_ERROR_DELETED:
4366 internal_pgroup_free(old_dpt_pgroup);
4367 goto delprop;
4368
4369 case SCF_ERROR_CONNECTION_BROKEN:
4370 internal_pgroup_free(old_dpt_pgroup);
4371 return (ECONNABORTED);
4372
4373 case SCF_ERROR_NOT_SET:
4374 case SCF_ERROR_INVALID_ARGUMENT:
4375 case SCF_ERROR_HANDLE_MISMATCH:
4376 case SCF_ERROR_NOT_BOUND:
4377 default:
4378 bad_error("entity_get_pg", scf_error());
4379 }
4380 }
4381
4382 if (scf_pg_delete(ud_pg) != 0) {
4383 switch (scf_error()) {
4384 case SCF_ERROR_DELETED:
4385 break;
4386
4387 case SCF_ERROR_CONNECTION_BROKEN:
4388 case SCF_ERROR_BACKEND_READONLY:
4389 case SCF_ERROR_BACKEND_ACCESS:
4390 return (scferror2errno(scf_error()));
4391
4392 case SCF_ERROR_PERMISSION_DENIED:
4393 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4394 return (scferror2errno(scf_error()));
4395
4396 case SCF_ERROR_NOT_SET:
4397 default:
4398 bad_error("scf_pg_delete", scf_error());
4399 }
4400 }
4401
4402 /*
4403 * This service was changed, so it must be refreshed. But
4404 * since it's not mentioned in the new manifest, we have to
4405 * record its FMRI here for use later. We record the name
4406 * & the entity (via sc_parent) in case we need to print error
4407 * messages during the refresh.
4408 */
4409 dpt = internal_pgroup_new();
4410 if (dpt == NULL)
4411 return (ENOMEM);
4412 dpt->sc_pgroup_name = strdup(ud_name);
4413 dpt->sc_pgroup_fmri = strdup(ud_ctarg);
4414 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4415 return (ENOMEM);
4416 dpt->sc_parent = (entity_t *)ient;
4417 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4418 uu_die(gettext("libuutil error: %s\n"),
4419 uu_strerror(uu_error()));
4420
4421 delprop:
4422 if (tx == NULL)
4423 return (0);
4424
4425 ent = scf_entry_create(g_hndl);
4426 if (ent == NULL)
4427 return (ENOMEM);
4428
4429 if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
4430 scf_entry_destroy(ent);
4431 switch (scf_error()) {
4432 case SCF_ERROR_DELETED:
4433 warn(emsg_pg_deleted, ient->sc_fmri,
4434 "dependents");
4435 return (EBUSY);
4436
4437 case SCF_ERROR_CONNECTION_BROKEN:
4438 return (scferror2errno(scf_error()));
4439
4440 case SCF_ERROR_NOT_FOUND:
4441 break;
4442
4443 case SCF_ERROR_HANDLE_MISMATCH:
4444 case SCF_ERROR_NOT_BOUND:
4445 case SCF_ERROR_INVALID_ARGUMENT:
4446 case SCF_ERROR_NOT_SET:
4447 default:
4448 bad_error("scf_transaction_property_delete",
4449 scf_error());
4450 }
4451 }
4452
4453 return (0);
4454 }
4455
4456 new_dpt_pgroup->sc_pgroup_seen = 1;
4457
4458 /*
4459 * Decide whether the dependent has changed in the manifest.
4460 */
4461 /* Compare the target. */
4462 if (scf_property_get_value(prop, ud_val) != 0) {
4463 switch (scf_error()) {
4464 case SCF_ERROR_NOT_FOUND:
4465 case SCF_ERROR_CONSTRAINT_VIOLATED:
4466 warn(li_corrupt, ient->sc_fmri);
4467 return (EBADF);
4468
4469 case SCF_ERROR_DELETED:
4470 case SCF_ERROR_CONNECTION_BROKEN:
4471 return (scferror2errno(scf_error()));
4472
4473 case SCF_ERROR_HANDLE_MISMATCH:
4474 case SCF_ERROR_NOT_BOUND:
4475 case SCF_ERROR_NOT_SET:
4476 case SCF_ERROR_PERMISSION_DENIED:
4477 default:
4478 bad_error("scf_property_get_value", scf_error());
4479 }
4480 }
4481
4482 if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
4483 0)
4484 bad_error("scf_value_get_as_string", scf_error());
4485
4486 /*
4487 * If the fmri's are not equal then the old fmri will need to
4488 * be refreshed to ensure that the changes are properly updated
4489 * in that service.
4490 */
4491 r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
4492 switch (r) {
4493 case 0:
4494 dpt = internal_pgroup_new();
4495 if (dpt == NULL)
4496 return (ENOMEM);
4497 dpt->sc_pgroup_name = strdup(ud_name);
4498 dpt->sc_pgroup_fmri = strdup(ud_oldtarg);
4499 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4500 return (ENOMEM);
4501 dpt->sc_parent = (entity_t *)ient;
4502 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4503 uu_die(gettext("libuutil error: %s\n"),
4504 uu_strerror(uu_error()));
4505 break;
4506
4507 case 1:
4508 /* Compare the dependency pgs. */
4509 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4510 switch (scf_error()) {
4511 case SCF_ERROR_NOT_FOUND:
4512 warn(li_corrupt, ient->sc_fmri);
4513 return (EBADF);
4514
4515 case SCF_ERROR_DELETED:
4516 case SCF_ERROR_CONNECTION_BROKEN:
4517 return (scferror2errno(scf_error()));
4518
4519 case SCF_ERROR_NOT_BOUND:
4520 case SCF_ERROR_HANDLE_MISMATCH:
4521 case SCF_ERROR_INVALID_ARGUMENT:
4522 case SCF_ERROR_NOT_SET:
4523 default:
4524 bad_error("scf_snaplevel_get_pg", scf_error());
4525 }
4526 }
4527
4528 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4529 snap_lastimport);
4530 switch (r) {
4531 case 0:
4532 break;
4533
4534 case ECANCELED:
4535 case ECONNABORTED:
4536 case ENOMEM:
4537 case EBADF:
4538 return (r);
4539
4540 case EACCES:
4541 default:
4542 bad_error("load_pg", r);
4543 }
4544
4545 if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4546 /* no change, leave customizations */
4547 internal_pgroup_free(old_dpt_pgroup);
4548 return (0);
4549 }
4550 break;
4551
4552 case -1:
4553 warn(li_corrupt, ient->sc_fmri);
4554 return (EBADF);
4555
4556 case -2:
4557 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4558 ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4559 return (EINVAL);
4560
4561 default:
4562 bad_error("fmri_equal", r);
4563 }
4564
4565 /*
4566 * The dependent has changed in the manifest. Upgrade the current
4567 * properties if they haven't been customized.
4568 */
4569
4570 /*
4571 * If new_dpt_pgroup->sc_override, then act as though the property
4572 * group hasn't been customized.
4573 */
4574 if (new_dpt_pgroup->sc_pgroup_override) {
4575 (void) strcpy(ud_ctarg, ud_oldtarg);
4576 goto nocust;
4577 }
4578
4579 if (!ud_run_dpts_pg_set) {
4580 warn(cf_missing, ient->sc_fmri, ud_name);
4581 r = 0;
4582 goto out;
4583 } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4584 switch (scf_error()) {
4585 case SCF_ERROR_NOT_FOUND:
4586 warn(cf_missing, ient->sc_fmri, ud_name);
4587 r = 0;
4588 goto out;
4589
4590 case SCF_ERROR_CONNECTION_BROKEN:
4591 r = scferror2errno(scf_error());
4592 goto out;
4593
4594 case SCF_ERROR_DELETED:
4595 warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4596 r = EBUSY;
4597 goto out;
4598
4599 case SCF_ERROR_INVALID_ARGUMENT:
4600 case SCF_ERROR_NOT_BOUND:
4601 case SCF_ERROR_HANDLE_MISMATCH:
4602 case SCF_ERROR_NOT_SET:
4603 default:
4604 bad_error("scf_pg_get_property", scf_error());
4605 }
4606 }
4607
4608 if (scf_property_get_value(ud_prop, ud_val) != 0) {
4609 switch (scf_error()) {
4610 case SCF_ERROR_NOT_FOUND:
4611 case SCF_ERROR_CONSTRAINT_VIOLATED:
4612 warn(cf_inval, ient->sc_fmri, ud_name);
4613 r = 0;
4614 goto out;
4615
4616 case SCF_ERROR_DELETED:
4617 case SCF_ERROR_CONNECTION_BROKEN:
4618 r = scferror2errno(scf_error());
4619 goto out;
4620
4621 case SCF_ERROR_HANDLE_MISMATCH:
4622 case SCF_ERROR_NOT_BOUND:
4623 case SCF_ERROR_NOT_SET:
4624 case SCF_ERROR_PERMISSION_DENIED:
4625 default:
4626 bad_error("scf_property_get_value", scf_error());
4627 }
4628 }
4629
4630 ty = scf_value_type(ud_val);
4631 assert(ty != SCF_TYPE_INVALID);
4632 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4633 warn(cf_inval, ient->sc_fmri, ud_name);
4634 r = 0;
4635 goto out;
4636 }
4637 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4638 0)
4639 bad_error("scf_value_get_as_string", scf_error());
4640
4641 r = fmri_equal(ud_ctarg, ud_oldtarg);
4642 if (r == -1) {
4643 warn(cf_inval, ient->sc_fmri, ud_name);
4644 r = 0;
4645 goto out;
4646 } else if (r == -2) {
4647 warn(li_corrupt, ient->sc_fmri);
4648 r = EBADF;
4649 goto out;
4650 } else if (r == 0) {
4651 /*
4652 * Target has been changed. Only abort now if it's been
4653 * changed to something other than what's in the manifest.
4654 */
4655 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4656 if (r == -1) {
4657 warn(cf_inval, ient->sc_fmri, ud_name);
4658 r = 0;
4659 goto out;
4660 } else if (r == 0) {
4661 warn(cf_newtarg, ient->sc_fmri, ud_name);
4662 r = 0;
4663 goto out;
4664 } else if (r != 1) {
4665 /* invalid sc_pgroup_fmri caught above */
4666 bad_error("fmri_equal", r);
4667 }
4668
4669 /*
4670 * Fetch the current dependency pg. If it's what the manifest
4671 * says, then no problem.
4672 */
4673 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4674 switch (serr) {
4675 case SCF_ERROR_NONE:
4676 break;
4677
4678 case SCF_ERROR_NOT_FOUND:
4679 warn(cf_missing, ient->sc_fmri, ud_name);
4680 r = 0;
4681 goto out;
4682
4683 case SCF_ERROR_NO_MEMORY:
4684 r = ENOMEM;
4685 goto out;
4686
4687 case SCF_ERROR_CONSTRAINT_VIOLATED:
4688 case SCF_ERROR_INVALID_ARGUMENT:
4689 default:
4690 bad_error("fmri_to_entity", serr);
4691 }
4692
4693 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4694 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4695 switch (r) {
4696 case 0:
4697 break;
4698
4699 case ECONNABORTED:
4700 goto out;
4701
4702 case ECANCELED:
4703 case ENOENT:
4704 warn(cf_missing, ient->sc_fmri, ud_name);
4705 r = 0;
4706 goto out;
4707
4708 case EBADF:
4709 warn(r_no_lvl, ud_ctarg);
4710 goto out;
4711
4712 case EINVAL:
4713 default:
4714 bad_error("entity_get_running_pg", r);
4715 }
4716
4717 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4718 switch (r) {
4719 case 0:
4720 break;
4721
4722 case ECANCELED:
4723 warn(cf_missing, ient->sc_fmri, ud_name);
4724 r = 0;
4725 goto out;
4726
4727 case ECONNABORTED:
4728 case ENOMEM:
4729 case EBADF:
4730 goto out;
4731
4732 case EACCES:
4733 default:
4734 bad_error("load_pg", r);
4735 }
4736
4737 if (!pg_equal(current_pg, new_dpt_pgroup))
4738 warn(cf_newdpg, ient->sc_fmri, ud_name);
4739 internal_pgroup_free(current_pg);
4740 r = 0;
4741 goto out;
4742 } else if (r != 1) {
4743 bad_error("fmri_equal", r);
4744 }
4745
4746 nocust:
4747 /*
4748 * Target has not been customized. Check the dependency property
4749 * group.
4750 */
4751
4752 if (old_dpt_pgroup == NULL) {
4753 if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4754 ud_pg) != 0) {
4755 switch (scf_error()) {
4756 case SCF_ERROR_NOT_FOUND:
4757 warn(li_corrupt, ient->sc_fmri);
4758 return (EBADF);
4759
4760 case SCF_ERROR_DELETED:
4761 case SCF_ERROR_CONNECTION_BROKEN:
4762 return (scferror2errno(scf_error()));
4763
4764 case SCF_ERROR_NOT_BOUND:
4765 case SCF_ERROR_HANDLE_MISMATCH:
4766 case SCF_ERROR_INVALID_ARGUMENT:
4767 case SCF_ERROR_NOT_SET:
4768 default:
4769 bad_error("scf_snaplevel_get_pg", scf_error());
4770 }
4771 }
4772
4773 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4774 snap_lastimport);
4775 switch (r) {
4776 case 0:
4777 break;
4778
4779 case ECANCELED:
4780 case ECONNABORTED:
4781 case ENOMEM:
4782 case EBADF:
4783 return (r);
4784
4785 case EACCES:
4786 default:
4787 bad_error("load_pg", r);
4788 }
4789 }
4790 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4791 switch (serr) {
4792 case SCF_ERROR_NONE:
4793 break;
4794
4795 case SCF_ERROR_NOT_FOUND:
4796 warn(cf_missing, ient->sc_fmri, ud_name);
4797 r = 0;
4798 goto out;
4799
4800 case SCF_ERROR_NO_MEMORY:
4801 r = ENOMEM;
4802 goto out;
4803
4804 case SCF_ERROR_CONSTRAINT_VIOLATED:
4805 case SCF_ERROR_INVALID_ARGUMENT:
4806 default:
4807 bad_error("fmri_to_entity", serr);
4808 }
4809
4810 r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4811 ud_iter2, ud_inst, imp_snap, ud_snpl);
4812 switch (r) {
4813 case 0:
4814 break;
4815
4816 case ECONNABORTED:
4817 goto out;
4818
4819 case ECANCELED:
4820 case ENOENT:
4821 warn(cf_missing, ient->sc_fmri, ud_name);
4822 r = 0;
4823 goto out;
4824
4825 case EBADF:
4826 warn(r_no_lvl, ud_ctarg);
4827 goto out;
4828
4829 case EINVAL:
4830 default:
4831 bad_error("entity_get_running_pg", r);
4832 }
4833
4834 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4835 switch (r) {
4836 case 0:
4837 break;
4838
4839 case ECANCELED:
4840 warn(cf_missing, ient->sc_fmri, ud_name);
4841 goto out;
4842
4843 case ECONNABORTED:
4844 case ENOMEM:
4845 case EBADF:
4846 goto out;
4847
4848 case EACCES:
4849 default:
4850 bad_error("load_pg", r);
4851 }
4852
4853 if (!pg_equal(current_pg, old_dpt_pgroup)) {
4854 if (!pg_equal(current_pg, new_dpt_pgroup))
4855 warn(cf_newdpg, ient->sc_fmri, ud_name);
4856 internal_pgroup_free(current_pg);
4857 r = 0;
4858 goto out;
4859 }
4860
4861 /* Uncustomized. Upgrade. */
4862
4863 r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4864 switch (r) {
4865 case 1:
4866 if (pg_equal(current_pg, new_dpt_pgroup)) {
4867 /* Already upgraded. */
4868 internal_pgroup_free(current_pg);
4869 r = 0;
4870 goto out;
4871 }
4872
4873 internal_pgroup_free(current_pg);
4874
4875 /* upgrade current_pg */
4876 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4877 switch (scf_error()) {
4878 case SCF_ERROR_CONNECTION_BROKEN:
4879 r = scferror2errno(scf_error());
4880 goto out;
4881
4882 case SCF_ERROR_DELETED:
4883 warn(cf_missing, ient->sc_fmri, ud_name);
4884 r = 0;
4885 goto out;
4886
4887 case SCF_ERROR_NOT_FOUND:
4888 break;
4889
4890 case SCF_ERROR_INVALID_ARGUMENT:
4891 case SCF_ERROR_NOT_BOUND:
4892 case SCF_ERROR_NOT_SET:
4893 case SCF_ERROR_HANDLE_MISMATCH:
4894 default:
4895 bad_error("entity_get_pg", scf_error());
4896 }
4897
4898 if (tissvc)
4899 r = scf_service_add_pg(target_ent, ud_name,
4900 SCF_GROUP_DEPENDENCY, 0, ud_pg);
4901 else
4902 r = scf_instance_add_pg(target_ent, ud_name,
4903 SCF_GROUP_DEPENDENCY, 0, ud_pg);
4904 if (r != 0) {
4905 switch (scf_error()) {
4906 case SCF_ERROR_CONNECTION_BROKEN:
4907 case SCF_ERROR_NO_RESOURCES:
4908 case SCF_ERROR_BACKEND_READONLY:
4909 case SCF_ERROR_BACKEND_ACCESS:
4910 r = scferror2errno(scf_error());
4911 goto out;
4912
4913 case SCF_ERROR_DELETED:
4914 warn(cf_missing, ient->sc_fmri,
4915 ud_name);
4916 r = 0;
4917 goto out;
4918
4919 case SCF_ERROR_PERMISSION_DENIED:
4920 warn(emsg_pg_deleted, ud_ctarg,
4921 ud_name);
4922 r = EPERM;
4923 goto out;
4924
4925 case SCF_ERROR_EXISTS:
4926 warn(emsg_pg_added, ud_ctarg, ud_name);
4927 r = EBUSY;
4928 goto out;
4929
4930 case SCF_ERROR_NOT_BOUND:
4931 case SCF_ERROR_HANDLE_MISMATCH:
4932 case SCF_ERROR_INVALID_ARGUMENT:
4933 case SCF_ERROR_NOT_SET:
4934 default:
4935 bad_error("entity_add_pg", scf_error());
4936 }
4937 }
4938 }
4939
4940 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4941 switch (r) {
4942 case 0:
4943 break;
4944
4945 case ECANCELED:
4946 warn(cf_missing, ient->sc_fmri, ud_name);
4947 goto out;
4948
4949 case ECONNABORTED:
4950 case ENOMEM:
4951 case EBADF:
4952 goto out;
4953
4954 case EACCES:
4955 default:
4956 bad_error("load_pg", r);
4957 }
4958
4959 if (g_verbose)
4960 warn(upgrading, ient->sc_fmri, ud_name);
4961
4962 r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4963 new_dpt_pgroup, 0, ient->sc_fmri);
4964 switch (r) {
4965 case 0:
4966 break;
4967
4968 case ECANCELED:
4969 warn(emsg_pg_deleted, ud_ctarg, ud_name);
4970 r = EBUSY;
4971 goto out;
4972
4973 case EPERM:
4974 warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4975 goto out;
4976
4977 case EBUSY:
4978 warn(emsg_pg_changed, ud_ctarg, ud_name);
4979 goto out;
4980
4981 case ECONNABORTED:
4982 case ENOMEM:
4983 case ENOSPC:
4984 case EROFS:
4985 case EACCES:
4986 case EINVAL:
4987 goto out;
4988
4989 default:
4990 bad_error("upgrade_pg", r);
4991 }
4992 break;
4993
4994 case 0: {
4995 scf_transaction_entry_t *ent;
4996 scf_value_t *val;
4997
4998 internal_pgroup_free(current_pg);
4999
5000 /* delete old pg */
5001 if (g_verbose)
5002 warn(upgrading, ient->sc_fmri, ud_name);
5003
5004 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
5005 switch (scf_error()) {
5006 case SCF_ERROR_CONNECTION_BROKEN:
5007 r = scferror2errno(scf_error());
5008 goto out;
5009
5010 case SCF_ERROR_DELETED:
5011 warn(cf_missing, ient->sc_fmri, ud_name);
5012 r = 0;
5013 goto out;
5014
5015 case SCF_ERROR_NOT_FOUND:
5016 break;
5017
5018 case SCF_ERROR_INVALID_ARGUMENT:
5019 case SCF_ERROR_NOT_BOUND:
5020 case SCF_ERROR_NOT_SET:
5021 case SCF_ERROR_HANDLE_MISMATCH:
5022 default:
5023 bad_error("entity_get_pg", scf_error());
5024 }
5025 } else if (scf_pg_delete(ud_pg) != 0) {
5026 switch (scf_error()) {
5027 case SCF_ERROR_DELETED:
5028 break;
5029
5030 case SCF_ERROR_CONNECTION_BROKEN:
5031 case SCF_ERROR_BACKEND_READONLY:
5032 case SCF_ERROR_BACKEND_ACCESS:
5033 r = scferror2errno(scf_error());
5034 goto out;
5035
5036 case SCF_ERROR_PERMISSION_DENIED:
5037 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
5038 r = scferror2errno(scf_error());
5039 goto out;
5040
5041 case SCF_ERROR_NOT_SET:
5042 default:
5043 bad_error("scf_pg_delete", scf_error());
5044 }
5045 }
5046
5047 /* import new one */
5048 cbdata.sc_handle = g_hndl;
5049 cbdata.sc_trans = NULL; /* handled below */
5050 cbdata.sc_flags = 0;
5051
5052 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
5053 if (r != UU_WALK_NEXT) {
5054 if (r != UU_WALK_ERROR)
5055 bad_error("lscf_dependent_import", r);
5056
5057 r = cbdata.sc_err;
5058 goto out;
5059 }
5060
5061 if (tx == NULL)
5062 break;
5063
5064 if ((ent = scf_entry_create(g_hndl)) == NULL ||
5065 (val = scf_value_create(g_hndl)) == NULL) {
5066 if (scf_error() == SCF_ERROR_NO_MEMORY)
5067 return (ENOMEM);
5068
5069 bad_error("scf_entry_create", scf_error());
5070 }
5071
5072 if (scf_transaction_property_change_type(tx, ent, ud_name,
5073 SCF_TYPE_FMRI) != 0) {
5074 switch (scf_error()) {
5075 case SCF_ERROR_CONNECTION_BROKEN:
5076 r = scferror2errno(scf_error());
5077 goto out;
5078
5079 case SCF_ERROR_DELETED:
5080 warn(emsg_pg_deleted, ient->sc_fmri,
5081 "dependents");
5082 r = EBUSY;
5083 goto out;
5084
5085 case SCF_ERROR_NOT_FOUND:
5086 break;
5087
5088 case SCF_ERROR_NOT_BOUND:
5089 case SCF_ERROR_HANDLE_MISMATCH:
5090 case SCF_ERROR_INVALID_ARGUMENT:
5091 case SCF_ERROR_NOT_SET:
5092 default:
5093 bad_error("scf_transaction_property_"
5094 "change_type", scf_error());
5095 }
5096
5097 if (scf_transaction_property_new(tx, ent, ud_name,
5098 SCF_TYPE_FMRI) != 0) {
5099 switch (scf_error()) {
5100 case SCF_ERROR_CONNECTION_BROKEN:
5101 r = scferror2errno(scf_error());
5102 goto out;
5103
5104 case SCF_ERROR_DELETED:
5105 warn(emsg_pg_deleted, ient->sc_fmri,
5106 "dependents");
5107 r = EBUSY;
5108 goto out;
5109
5110 case SCF_ERROR_EXISTS:
5111 warn(emsg_pg_changed, ient->sc_fmri,
5112 "dependents");
5113 r = EBUSY;
5114 goto out;
5115
5116 case SCF_ERROR_INVALID_ARGUMENT:
5117 case SCF_ERROR_HANDLE_MISMATCH:
5118 case SCF_ERROR_NOT_BOUND:
5119 case SCF_ERROR_NOT_SET:
5120 default:
5121 bad_error("scf_transaction_property_"
5122 "new", scf_error());
5123 }
5124 }
5125 }
5126
5127 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
5128 new_dpt_pgroup->sc_pgroup_fmri) != 0)
5129 /* invalid sc_pgroup_fmri caught above */
5130 bad_error("scf_value_set_from_string",
5131 scf_error());
5132
5133 if (scf_entry_add_value(ent, val) != 0)
5134 bad_error("scf_entry_add_value", scf_error());
5135 break;
5136 }
5137
5138 case -2:
5139 warn(li_corrupt, ient->sc_fmri);
5140 internal_pgroup_free(current_pg);
5141 r = EBADF;
5142 goto out;
5143
5144 case -1:
5145 default:
5146 /* invalid sc_pgroup_fmri caught above */
5147 bad_error("fmri_equal", r);
5148 }
5149
5150 r = 0;
5151
5152 out:
5153 if (old_dpt_pgroup != NULL)
5154 internal_pgroup_free(old_dpt_pgroup);
5155
5156 return (r);
5157 }
5158
5159 /*
5160 * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
5161 * would import it, except it seems to exist in the service anyway. Compare
5162 * the existent dependent with the one we would import, and report any
5163 * differences (if there are none, be silent). prop is the property which
5164 * represents the existent dependent (in the dependents property group) in the
5165 * entity corresponding to ient.
5166 *
5167 * Returns
5168 * 0 - success (Sort of. At least, we can continue importing.)
5169 * ECONNABORTED - repository connection broken
5170 * EBUSY - ancestor of prop was deleted (error printed)
5171 * ENOMEM - out of memory
5172 * EBADF - corrupt property group (error printed)
5173 * EINVAL - new_dpt_pgroup has invalid target (error printed)
5174 */
5175 static int
5176 handle_dependent_conflict(const entity_t * const ient,
5177 const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
5178 {
5179 int r;
5180 scf_type_t ty;
5181 scf_error_t scfe;
5182 void *tptr;
5183 int tissvc;
5184 pgroup_t *pgroup;
5185
5186 if (scf_property_get_value(prop, ud_val) != 0) {
5187 switch (scf_error()) {
5188 case SCF_ERROR_CONNECTION_BROKEN:
5189 return (scferror2errno(scf_error()));
5190
5191 case SCF_ERROR_DELETED:
5192 warn(emsg_pg_deleted, ient->sc_fmri,
5193 new_dpt_pgroup->sc_pgroup_name);
5194 return (EBUSY);
5195
5196 case SCF_ERROR_CONSTRAINT_VIOLATED:
5197 case SCF_ERROR_NOT_FOUND:
5198 warn(gettext("Conflict upgrading %s (not importing "
5199 "dependent \"%s\" because it already exists.) "
5200 "Warning: The \"%s/%2$s\" property has more or "
5201 "fewer than one value)).\n"), ient->sc_fmri,
5202 new_dpt_pgroup->sc_pgroup_name, "dependents");
5203 return (0);
5204
5205 case SCF_ERROR_HANDLE_MISMATCH:
5206 case SCF_ERROR_NOT_BOUND:
5207 case SCF_ERROR_NOT_SET:
5208 case SCF_ERROR_PERMISSION_DENIED:
5209 default:
5210 bad_error("scf_property_get_value",
5211 scf_error());
5212 }
5213 }
5214
5215 ty = scf_value_type(ud_val);
5216 assert(ty != SCF_TYPE_INVALID);
5217 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
5218 warn(gettext("Conflict upgrading %s (not importing dependent "
5219 "\"%s\" because it already exists). Warning: The "
5220 "\"%s/%s\" property has unexpected type \"%s\")).\n"),
5221 ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
5222 scf_type_to_string(ty), "dependents");
5223 return (0);
5224 }
5225
5226 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
5227 0)
5228 bad_error("scf_value_get_as_string", scf_error());
5229
5230 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
5231 switch (r) {
5232 case 0:
5233 warn(gettext("Conflict upgrading %s (not importing dependent "
5234 "\"%s\" (target \"%s\") because it already exists with "
5235 "target \"%s\").\n"), ient->sc_fmri,
5236 new_dpt_pgroup->sc_pgroup_name,
5237 new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
5238 return (0);
5239
5240 case 1:
5241 break;
5242
5243 case -1:
5244 warn(gettext("Conflict upgrading %s (not importing dependent "
5245 "\"%s\" because it already exists). Warning: The current "
5246 "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
5247 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5248 return (0);
5249
5250 case -2:
5251 warn(gettext("Dependent \"%s\" of %s has invalid target "
5252 "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
5253 new_dpt_pgroup->sc_pgroup_fmri);
5254 return (EINVAL);
5255
5256 default:
5257 bad_error("fmri_equal", r);
5258 }
5259
5260 /* compare dependency pgs in target */
5261 scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
5262 switch (scfe) {
5263 case SCF_ERROR_NONE:
5264 break;
5265
5266 case SCF_ERROR_NO_MEMORY:
5267 return (ENOMEM);
5268
5269 case SCF_ERROR_NOT_FOUND:
5270 warn(emsg_dpt_dangling, ient->sc_fmri,
5271 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5272 return (0);
5273
5274 case SCF_ERROR_CONSTRAINT_VIOLATED:
5275 case SCF_ERROR_INVALID_ARGUMENT:
5276 default:
5277 bad_error("fmri_to_entity", scfe);
5278 }
5279
5280 r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
5281 ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
5282 switch (r) {
5283 case 0:
5284 break;
5285
5286 case ECONNABORTED:
5287 return (r);
5288
5289 case ECANCELED:
5290 warn(emsg_dpt_dangling, ient->sc_fmri,
5291 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5292 return (0);
5293
5294 case EBADF:
5295 if (tissvc)
5296 warn(gettext("%s has an instance with a \"%s\" "
5297 "snapshot which is missing a snaplevel.\n"),
5298 ud_ctarg, "running");
5299 else
5300 warn(gettext("%s has a \"%s\" snapshot which is "
5301 "missing a snaplevel.\n"), ud_ctarg, "running");
5302 /* FALLTHROUGH */
5303
5304 case ENOENT:
5305 warn(emsg_dpt_no_dep, ient->sc_fmri,
5306 new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5307 new_dpt_pgroup->sc_pgroup_name);
5308 return (0);
5309
5310 case EINVAL:
5311 default:
5312 bad_error("entity_get_running_pg", r);
5313 }
5314
5315 pgroup = internal_pgroup_new();
5316 if (pgroup == NULL)
5317 return (ENOMEM);
5318
5319 r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
5320 switch (r) {
5321 case 0:
5322 break;
5323
5324 case ECONNABORTED:
5325 case EBADF:
5326 case ENOMEM:
5327 internal_pgroup_free(pgroup);
5328 return (r);
5329
5330 case ECANCELED:
5331 warn(emsg_dpt_no_dep, ient->sc_fmri,
5332 new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5333 new_dpt_pgroup->sc_pgroup_name);
5334 internal_pgroup_free(pgroup);
5335 return (0);
5336
5337 case EACCES:
5338 default:
5339 bad_error("load_pg", r);
5340 }
5341
5342 /* report differences */
5343 report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
5344 internal_pgroup_free(pgroup);
5345 return (0);
5346 }
5347
5348 /*
5349 * lipg is a property group in the last-import snapshot of ent, which is an
5350 * scf_service_t or an scf_instance_t (according to ient). If lipg is not in
5351 * ient's pgroups, delete it from ent if it hasn't been customized. If it is
5352 * in ents's property groups, compare and upgrade ent appropriately.
5353 *
5354 * Returns
5355 * 0 - success
5356 * ECONNABORTED - repository connection broken
5357 * ENOMEM - out of memory
5358 * ENOSPC - configd is out of resources
5359 * EINVAL - ient has invalid dependent (error printed)
5360 * - ient has invalid pgroup_t (error printed)
5361 * ECANCELED - ent has been deleted
5362 * ENODEV - entity containing lipg has been deleted
5363 * - entity containing running has been deleted
5364 * EPERM - could not delete pg (permission denied) (error printed)
5365 * - couldn't upgrade dependents (permission denied) (error printed)
5366 * - couldn't import pg (permission denied) (error printed)
5367 * - couldn't upgrade pg (permission denied) (error printed)
5368 * EROFS - could not delete pg (repository read-only)
5369 * - couldn't upgrade dependents (repository read-only)
5370 * - couldn't import pg (repository read-only)
5371 * - couldn't upgrade pg (repository read-only)
5372 * EACCES - could not delete pg (backend access denied)
5373 * - couldn't upgrade dependents (backend access denied)
5374 * - couldn't import pg (backend access denied)
5375 * - couldn't upgrade pg (backend access denied)
5376 * - couldn't read property (backend access denied)
5377 * EBUSY - property group was added (error printed)
5378 * - property group was deleted (error printed)
5379 * - property group changed (error printed)
5380 * - "dependents" pg was added, changed, or deleted (error printed)
5381 * - dependent target deleted (error printed)
5382 * - dependent pg changed (error printed)
5383 * EBADF - imp_snpl is corrupt (error printed)
5384 * - ent has bad pg (error printed)
5385 * EEXIST - dependent collision in target service (error printed)
5386 */
5387 static int
5388 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
5389 const scf_snaplevel_t *running)
5390 {
5391 int r;
5392 pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
5393 scf_callback_t cbdata;
5394
5395 const char * const cf_pg_missing =
5396 gettext("Conflict upgrading %s (property group %s is missing)\n");
5397 const char * const deleting =
5398 gettext("%s: Deleting property group \"%s\".\n");
5399
5400 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5401
5402 /* Skip dependent property groups. */
5403 if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
5404 switch (scf_error()) {
5405 case SCF_ERROR_DELETED:
5406 return (ENODEV);
5407
5408 case SCF_ERROR_CONNECTION_BROKEN:
5409 return (ECONNABORTED);
5410
5411 case SCF_ERROR_NOT_SET:
5412 case SCF_ERROR_NOT_BOUND:
5413 default:
5414 bad_error("scf_pg_get_type", scf_error());
5415 }
5416 }
5417
5418 if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
5419 if (scf_pg_get_property(lipg, "external", NULL) == 0)
5420 return (0);
5421
5422 switch (scf_error()) {
5423 case SCF_ERROR_NOT_FOUND:
5424 break;
5425
5426 case SCF_ERROR_CONNECTION_BROKEN:
5427 return (ECONNABORTED);
5428
5429 case SCF_ERROR_DELETED:
5430 return (ENODEV);
5431
5432 case SCF_ERROR_INVALID_ARGUMENT:
5433 case SCF_ERROR_NOT_BOUND:
5434 case SCF_ERROR_HANDLE_MISMATCH:
5435 case SCF_ERROR_NOT_SET:
5436 default:
5437 bad_error("scf_pg_get_property", scf_error());
5438 }
5439 }
5440
5441 /* lookup pg in new properties */
5442 if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
5443 switch (scf_error()) {
5444 case SCF_ERROR_DELETED:
5445 return (ENODEV);
5446
5447 case SCF_ERROR_CONNECTION_BROKEN:
5448 return (ECONNABORTED);
5449
5450 case SCF_ERROR_NOT_SET:
5451 case SCF_ERROR_NOT_BOUND:
5452 default:
5453 bad_error("scf_pg_get_name", scf_error());
5454 }
5455 }
5456
5457 pgrp.sc_pgroup_name = imp_str;
5458 mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
5459
5460 if (mpg != NULL)
5461 mpg->sc_pgroup_seen = 1;
5462
5463 /* Special handling for dependents */
5464 if (strcmp(imp_str, "dependents") == 0)
5465 return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
5466
5467 if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
5468 return (upgrade_manifestfiles(NULL, ient, running, ent));
5469
5470 if (mpg == NULL || mpg->sc_pgroup_delete) {
5471 /* property group was deleted from manifest */
5472 if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5473 switch (scf_error()) {
5474 case SCF_ERROR_NOT_FOUND:
5475 return (0);
5476
5477 case SCF_ERROR_DELETED:
5478 case SCF_ERROR_CONNECTION_BROKEN:
5479 return (scferror2errno(scf_error()));
5480
5481 case SCF_ERROR_INVALID_ARGUMENT:
5482 case SCF_ERROR_HANDLE_MISMATCH:
5483 case SCF_ERROR_NOT_BOUND:
5484 case SCF_ERROR_NOT_SET:
5485 default:
5486 bad_error("entity_get_pg", scf_error());
5487 }
5488 }
5489
5490 if (mpg != NULL && mpg->sc_pgroup_delete) {
5491 if (g_verbose)
5492 warn(deleting, ient->sc_fmri, imp_str);
5493 if (scf_pg_delete(imp_pg2) == 0)
5494 return (0);
5495
5496 switch (scf_error()) {
5497 case SCF_ERROR_DELETED:
5498 return (0);
5499
5500 case SCF_ERROR_CONNECTION_BROKEN:
5501 case SCF_ERROR_BACKEND_READONLY:
5502 case SCF_ERROR_BACKEND_ACCESS:
5503 return (scferror2errno(scf_error()));
5504
5505 case SCF_ERROR_PERMISSION_DENIED:
5506 warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
5507 return (scferror2errno(scf_error()));
5508
5509 case SCF_ERROR_NOT_SET:
5510 default:
5511 bad_error("scf_pg_delete", scf_error());
5512 }
5513 }
5514
5515 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5516 switch (r) {
5517 case 0:
5518 break;
5519
5520 case ECANCELED:
5521 return (ENODEV);
5522
5523 case ECONNABORTED:
5524 case ENOMEM:
5525 case EBADF:
5526 case EACCES:
5527 return (r);
5528
5529 default:
5530 bad_error("load_pg", r);
5531 }
5532
5533 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5534 switch (r) {
5535 case 0:
5536 break;
5537
5538 case ECANCELED:
5539 case ECONNABORTED:
5540 case ENOMEM:
5541 case EBADF:
5542 case EACCES:
5543 internal_pgroup_free(lipg_i);
5544 return (r);
5545
5546 default:
5547 bad_error("load_pg", r);
5548 }
5549
5550 if (pg_equal(lipg_i, curpg_i)) {
5551 if (g_verbose)
5552 warn(deleting, ient->sc_fmri, imp_str);
5553 if (scf_pg_delete(imp_pg2) != 0) {
5554 switch (scf_error()) {
5555 case SCF_ERROR_DELETED:
5556 break;
5557
5558 case SCF_ERROR_CONNECTION_BROKEN:
5559 internal_pgroup_free(lipg_i);
5560 internal_pgroup_free(curpg_i);
5561 return (ECONNABORTED);
5562
5563 case SCF_ERROR_NOT_SET:
5564 case SCF_ERROR_NOT_BOUND:
5565 default:
5566 bad_error("scf_pg_delete", scf_error());
5567 }
5568 }
5569 } else {
5570 report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5571 }
5572
5573 internal_pgroup_free(lipg_i);
5574 internal_pgroup_free(curpg_i);
5575
5576 return (0);
5577 }
5578
5579 /*
5580 * Only dependent pgs can have override set, and we skipped those
5581 * above.
5582 */
5583 assert(!mpg->sc_pgroup_override);
5584
5585 /* compare */
5586 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5587 switch (r) {
5588 case 0:
5589 break;
5590
5591 case ECANCELED:
5592 return (ENODEV);
5593
5594 case ECONNABORTED:
5595 case EBADF:
5596 case ENOMEM:
5597 case EACCES:
5598 return (r);
5599
5600 default:
5601 bad_error("load_pg", r);
5602 }
5603
5604 if (pg_equal(mpg, lipg_i)) {
5605 /* The manifest pg has not changed. Move on. */
5606 r = 0;
5607 goto out;
5608 }
5609
5610 /* upgrade current properties according to lipg & mpg */
5611 if (running != NULL)
5612 r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5613 else
5614 r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5615 if (r != 0) {
5616 switch (scf_error()) {
5617 case SCF_ERROR_CONNECTION_BROKEN:
5618 r = scferror2errno(scf_error());
5619 goto out;
5620
5621 case SCF_ERROR_DELETED:
5622 if (running != NULL)
5623 r = ENODEV;
5624 else
5625 r = ECANCELED;
5626 goto out;
5627
5628 case SCF_ERROR_NOT_FOUND:
5629 break;
5630
5631 case SCF_ERROR_INVALID_ARGUMENT:
5632 case SCF_ERROR_HANDLE_MISMATCH:
5633 case SCF_ERROR_NOT_BOUND:
5634 case SCF_ERROR_NOT_SET:
5635 default:
5636 bad_error("entity_get_pg", scf_error());
5637 }
5638
5639 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5640
5641 r = 0;
5642 goto out;
5643 }
5644
5645 r = load_pg_attrs(imp_pg2, &curpg_i);
5646 switch (r) {
5647 case 0:
5648 break;
5649
5650 case ECANCELED:
5651 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5652 r = 0;
5653 goto out;
5654
5655 case ECONNABORTED:
5656 case ENOMEM:
5657 goto out;
5658
5659 default:
5660 bad_error("load_pg_attrs", r);
5661 }
5662
5663 if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5664 (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5665 internal_pgroup_free(curpg_i);
5666 r = 0;
5667 goto out;
5668 }
5669
5670 internal_pgroup_free(curpg_i);
5671
5672 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5673 switch (r) {
5674 case 0:
5675 break;
5676
5677 case ECANCELED:
5678 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5679 r = 0;
5680 goto out;
5681
5682 case ECONNABORTED:
5683 case EBADF:
5684 case ENOMEM:
5685 case EACCES:
5686 goto out;
5687
5688 default:
5689 bad_error("load_pg", r);
5690 }
5691
5692 if (pg_equal(lipg_i, curpg_i) &&
5693 !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5694 int do_delete = 1;
5695
5696 if (g_verbose)
5697 warn(gettext("%s: Upgrading property group \"%s\".\n"),
5698 ient->sc_fmri, mpg->sc_pgroup_name);
5699
5700 internal_pgroup_free(curpg_i);
5701
5702 if (running != NULL &&
5703 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5704 switch (scf_error()) {
5705 case SCF_ERROR_DELETED:
5706 r = ECANCELED;
5707 goto out;
5708
5709 case SCF_ERROR_NOT_FOUND:
5710 do_delete = 0;
5711 break;
5712
5713 case SCF_ERROR_CONNECTION_BROKEN:
5714 r = scferror2errno(scf_error());
5715 goto out;
5716
5717 case SCF_ERROR_HANDLE_MISMATCH:
5718 case SCF_ERROR_INVALID_ARGUMENT:
5719 case SCF_ERROR_NOT_SET:
5720 case SCF_ERROR_NOT_BOUND:
5721 default:
5722 bad_error("entity_get_pg", scf_error());
5723 }
5724 }
5725
5726 if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5727 switch (scf_error()) {
5728 case SCF_ERROR_DELETED:
5729 break;
5730
5731 case SCF_ERROR_CONNECTION_BROKEN:
5732 case SCF_ERROR_BACKEND_READONLY:
5733 case SCF_ERROR_BACKEND_ACCESS:
5734 r = scferror2errno(scf_error());
5735 goto out;
5736
5737 case SCF_ERROR_PERMISSION_DENIED:
5738 warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5739 ient->sc_fmri);
5740 r = scferror2errno(scf_error());
5741 goto out;
5742
5743 case SCF_ERROR_NOT_SET:
5744 case SCF_ERROR_NOT_BOUND:
5745 default:
5746 bad_error("scf_pg_delete", scf_error());
5747 }
5748 }
5749
5750 cbdata.sc_handle = g_hndl;
5751 cbdata.sc_parent = ent;
5752 cbdata.sc_service = issvc;
5753 cbdata.sc_flags = 0;
5754 cbdata.sc_source_fmri = ient->sc_fmri;
5755 cbdata.sc_target_fmri = ient->sc_fmri;
5756
5757 r = entity_pgroup_import(mpg, &cbdata);
5758 switch (r) {
5759 case UU_WALK_NEXT:
5760 r = 0;
5761 goto out;
5762
5763 case UU_WALK_ERROR:
5764 if (cbdata.sc_err == EEXIST) {
5765 warn(emsg_pg_added, ient->sc_fmri,
5766 mpg->sc_pgroup_name);
5767 r = EBUSY;
5768 } else {
5769 r = cbdata.sc_err;
5770 }
5771 goto out;
5772
5773 default:
5774 bad_error("entity_pgroup_import", r);
5775 }
5776 }
5777
5778 if (running != NULL &&
5779 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5780 switch (scf_error()) {
5781 case SCF_ERROR_CONNECTION_BROKEN:
5782 case SCF_ERROR_DELETED:
5783 r = scferror2errno(scf_error());
5784 goto out;
5785
5786 case SCF_ERROR_NOT_FOUND:
5787 break;
5788
5789 case SCF_ERROR_HANDLE_MISMATCH:
5790 case SCF_ERROR_INVALID_ARGUMENT:
5791 case SCF_ERROR_NOT_SET:
5792 case SCF_ERROR_NOT_BOUND:
5793 default:
5794 bad_error("entity_get_pg", scf_error());
5795 }
5796
5797 cbdata.sc_handle = g_hndl;
5798 cbdata.sc_parent = ent;
5799 cbdata.sc_service = issvc;
5800 cbdata.sc_flags = SCI_FORCE;
5801 cbdata.sc_source_fmri = ient->sc_fmri;
5802 cbdata.sc_target_fmri = ient->sc_fmri;
5803
5804 r = entity_pgroup_import(mpg, &cbdata);
5805 switch (r) {
5806 case UU_WALK_NEXT:
5807 r = 0;
5808 goto out;
5809
5810 case UU_WALK_ERROR:
5811 if (cbdata.sc_err == EEXIST) {
5812 warn(emsg_pg_added, ient->sc_fmri,
5813 mpg->sc_pgroup_name);
5814 r = EBUSY;
5815 } else {
5816 r = cbdata.sc_err;
5817 }
5818 goto out;
5819
5820 default:
5821 bad_error("entity_pgroup_import", r);
5822 }
5823 }
5824
5825 r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5826 internal_pgroup_free(curpg_i);
5827 switch (r) {
5828 case 0:
5829 ient->sc_import_state = IMPORT_PROP_BEGUN;
5830 break;
5831
5832 case ECANCELED:
5833 warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5834 r = EBUSY;
5835 break;
5836
5837 case EPERM:
5838 warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5839 break;
5840
5841 case EBUSY:
5842 warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5843 break;
5844
5845 case ECONNABORTED:
5846 case ENOMEM:
5847 case ENOSPC:
5848 case EROFS:
5849 case EACCES:
5850 case EINVAL:
5851 break;
5852
5853 default:
5854 bad_error("upgrade_pg", r);
5855 }
5856
5857 out:
5858 internal_pgroup_free(lipg_i);
5859 return (r);
5860 }
5861
5862 /*
5863 * Upgrade the properties of ent according to snpl & ient.
5864 *
5865 * Returns
5866 * 0 - success
5867 * ECONNABORTED - repository connection broken
5868 * ENOMEM - out of memory
5869 * ENOSPC - configd is out of resources
5870 * ECANCELED - ent was deleted
5871 * ENODEV - entity containing snpl was deleted
5872 * - entity containing running was deleted
5873 * EBADF - imp_snpl is corrupt (error printed)
5874 * - ent has corrupt pg (error printed)
5875 * - dependent has corrupt pg (error printed)
5876 * - dependent target has a corrupt snapshot (error printed)
5877 * EBUSY - pg was added, changed, or deleted (error printed)
5878 * - dependent target was deleted (error printed)
5879 * - dependent pg changed (error printed)
5880 * EINVAL - invalid property group name (error printed)
5881 * - invalid property name (error printed)
5882 * - invalid value (error printed)
5883 * - ient has invalid pgroup or dependent (error printed)
5884 * EPERM - could not create property group (permission denied) (error printed)
5885 * - could not modify property group (permission denied) (error printed)
5886 * - couldn't delete, upgrade, or import pg or dependent (error printed)
5887 * EROFS - could not create property group (repository read-only)
5888 * - couldn't delete, upgrade, or import pg or dependent
5889 * EACCES - could not create property group (backend access denied)
5890 * - couldn't delete, upgrade, or import pg or dependent
5891 * EEXIST - dependent collision in target service (error printed)
5892 */
5893 static int
5894 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5895 entity_t *ient)
5896 {
5897 pgroup_t *pg, *rpg;
5898 int r;
5899 uu_list_t *pgs = ient->sc_pgroups;
5900
5901 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5902
5903 /* clear sc_sceen for pgs */
5904 if (uu_list_walk(pgs, clear_int,
5905 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5906 bad_error("uu_list_walk", uu_error());
5907
5908 if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5909 switch (scf_error()) {
5910 case SCF_ERROR_DELETED:
5911 return (ENODEV);
5912
5913 case SCF_ERROR_CONNECTION_BROKEN:
5914 return (ECONNABORTED);
5915
5916 case SCF_ERROR_NOT_SET:
5917 case SCF_ERROR_NOT_BOUND:
5918 case SCF_ERROR_HANDLE_MISMATCH:
5919 default:
5920 bad_error("scf_iter_snaplevel_pgs", scf_error());
5921 }
5922 }
5923
5924 for (;;) {
5925 r = scf_iter_next_pg(imp_up_iter, imp_pg);
5926 if (r == 0)
5927 break;
5928 if (r == 1) {
5929 r = process_old_pg(imp_pg, ient, ent, running);
5930 switch (r) {
5931 case 0:
5932 break;
5933
5934 case ECONNABORTED:
5935 case ENOMEM:
5936 case ENOSPC:
5937 case ECANCELED:
5938 case ENODEV:
5939 case EPERM:
5940 case EROFS:
5941 case EACCES:
5942 case EBADF:
5943 case EBUSY:
5944 case EINVAL:
5945 case EEXIST:
5946 return (r);
5947
5948 default:
5949 bad_error("process_old_pg", r);
5950 }
5951 continue;
5952 }
5953 if (r != -1)
5954 bad_error("scf_iter_next_pg", r);
5955
5956 switch (scf_error()) {
5957 case SCF_ERROR_DELETED:
5958 return (ENODEV);
5959
5960 case SCF_ERROR_CONNECTION_BROKEN:
5961 return (ECONNABORTED);
5962
5963 case SCF_ERROR_HANDLE_MISMATCH:
5964 case SCF_ERROR_NOT_BOUND:
5965 case SCF_ERROR_NOT_SET:
5966 case SCF_ERROR_INVALID_ARGUMENT:
5967 default:
5968 bad_error("scf_iter_next_pg", scf_error());
5969 }
5970 }
5971
5972 for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5973 if (pg->sc_pgroup_seen)
5974 continue;
5975
5976 /* pg is new */
5977
5978 if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5979 r = upgrade_dependents(NULL, imp_snpl, ient, running,
5980 ent);
5981 switch (r) {
5982 case 0:
5983 break;
5984
5985 case ECONNABORTED:
5986 case ENOMEM:
5987 case ENOSPC:
5988 case ECANCELED:
5989 case ENODEV:
5990 case EBADF:
5991 case EBUSY:
5992 case EINVAL:
5993 case EPERM:
5994 case EROFS:
5995 case EACCES:
5996 case EEXIST:
5997 return (r);
5998
5999 default:
6000 bad_error("upgrade_dependents", r);
6001 }
6002 continue;
6003 }
6004
6005 if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
6006 r = upgrade_manifestfiles(pg, ient, running, ent);
6007 switch (r) {
6008 case 0:
6009 break;
6010
6011 case ECONNABORTED:
6012 case ENOMEM:
6013 case ENOSPC:
6014 case ECANCELED:
6015 case ENODEV:
6016 case EBADF:
6017 case EBUSY:
6018 case EINVAL:
6019 case EPERM:
6020 case EROFS:
6021 case EACCES:
6022 case EEXIST:
6023 return (r);
6024
6025 default:
6026 bad_error("upgrade_manifestfiles", r);
6027 }
6028 continue;
6029 }
6030
6031 if (running != NULL) {
6032 r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
6033 imp_pg);
6034 } else {
6035 r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
6036 imp_pg);
6037 }
6038 if (r != 0) {
6039 scf_callback_t cbdata;
6040
6041 switch (scf_error()) {
6042 case SCF_ERROR_NOT_FOUND:
6043 break;
6044
6045 case SCF_ERROR_CONNECTION_BROKEN:
6046 return (scferror2errno(scf_error()));
6047
6048 case SCF_ERROR_DELETED:
6049 if (running != NULL)
6050 return (ENODEV);
6051 else
6052 return (scferror2errno(scf_error()));
6053
6054 case SCF_ERROR_INVALID_ARGUMENT:
6055 warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
6056 pg->sc_pgroup_name);
6057 return (EINVAL);
6058
6059 case SCF_ERROR_NOT_SET:
6060 case SCF_ERROR_HANDLE_MISMATCH:
6061 case SCF_ERROR_NOT_BOUND:
6062 default:
6063 bad_error("entity_get_pg", scf_error());
6064 }
6065
6066 /* User doesn't have pg, so import it. */
6067
6068 cbdata.sc_handle = g_hndl;
6069 cbdata.sc_parent = ent;
6070 cbdata.sc_service = issvc;
6071 cbdata.sc_flags = SCI_FORCE;
6072 cbdata.sc_source_fmri = ient->sc_fmri;
6073 cbdata.sc_target_fmri = ient->sc_fmri;
6074
6075 r = entity_pgroup_import(pg, &cbdata);
6076 switch (r) {
6077 case UU_WALK_NEXT:
6078 ient->sc_import_state = IMPORT_PROP_BEGUN;
6079 continue;
6080
6081 case UU_WALK_ERROR:
6082 if (cbdata.sc_err == EEXIST) {
6083 warn(emsg_pg_added, ient->sc_fmri,
6084 pg->sc_pgroup_name);
6085 return (EBUSY);
6086 }
6087 return (cbdata.sc_err);
6088
6089 default:
6090 bad_error("entity_pgroup_import", r);
6091 }
6092 }
6093
6094 /* report differences between pg & current */
6095 r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
6096 switch (r) {
6097 case 0:
6098 break;
6099
6100 case ECANCELED:
6101 warn(emsg_pg_deleted, ient->sc_fmri,
6102 pg->sc_pgroup_name);
6103 return (EBUSY);
6104
6105 case ECONNABORTED:
6106 case EBADF:
6107 case ENOMEM:
6108 case EACCES:
6109 return (r);
6110
6111 default:
6112 bad_error("load_pg", r);
6113 }
6114 report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
6115 internal_pgroup_free(rpg);
6116 rpg = NULL;
6117 }
6118
6119 return (0);
6120 }
6121
6122 /*
6123 * Import an instance. If it doesn't exist, create it. If it has
6124 * a last-import snapshot, upgrade its properties. Finish by updating its
6125 * last-import snapshot. If it doesn't have a last-import snapshot then it
6126 * could have been created for a dependent tag in another manifest. Import the
6127 * new properties. If there's a conflict, don't override, like now?
6128 *
6129 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
6130 * lcbdata->sc_err to
6131 * ECONNABORTED - repository connection broken
6132 * ENOMEM - out of memory
6133 * ENOSPC - svc.configd is out of resources
6134 * EEXIST - dependency collision in dependent service (error printed)
6135 * EPERM - couldn't create temporary instance (permission denied)
6136 * - couldn't import into temporary instance (permission denied)
6137 * - couldn't take snapshot (permission denied)
6138 * - couldn't upgrade properties (permission denied)
6139 * - couldn't import properties (permission denied)
6140 * - couldn't import dependents (permission denied)
6141 * EROFS - couldn't create temporary instance (repository read-only)
6142 * - couldn't import into temporary instance (repository read-only)
6143 * - couldn't upgrade properties (repository read-only)
6144 * - couldn't import properties (repository read-only)
6145 * - couldn't import dependents (repository read-only)
6146 * EACCES - couldn't create temporary instance (backend access denied)
6147 * - couldn't import into temporary instance (backend access denied)
6148 * - couldn't upgrade properties (backend access denied)
6149 * - couldn't import properties (backend access denied)
6150 * - couldn't import dependents (backend access denied)
6151 * EINVAL - invalid instance name (error printed)
6152 * - invalid pgroup_t's (error printed)
6153 * - invalid dependents (error printed)
6154 * EBUSY - temporary service deleted (error printed)
6155 * - temporary instance deleted (error printed)
6156 * - temporary instance changed (error printed)
6157 * - temporary instance already exists (error printed)
6158 * - instance deleted (error printed)
6159 * EBADF - instance has corrupt last-import snapshot (error printed)
6160 * - instance is corrupt (error printed)
6161 * - dependent has corrupt pg (error printed)
6162 * - dependent target has a corrupt snapshot (error printed)
6163 * -1 - unknown libscf error (error printed)
6164 */
6165 static int
6166 lscf_instance_import(void *v, void *pvt)
6167 {
6168 entity_t *inst = v;
6169 scf_callback_t ctx;
6170 scf_callback_t *lcbdata = pvt;
6171 scf_service_t *rsvc = lcbdata->sc_parent;
6172 int r;
6173 scf_snaplevel_t *running;
6174 int flags = lcbdata->sc_flags;
6175
6176 const char * const emsg_tdel =
6177 gettext("Temporary instance svc:/%s:%s was deleted.\n");
6178 const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
6179 "changed unexpectedly.\n");
6180 const char * const emsg_del = gettext("%s changed unexpectedly "
6181 "(instance \"%s\" was deleted.)\n");
6182 const char * const emsg_badsnap = gettext(
6183 "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
6184
6185 /*
6186 * prepare last-import snapshot:
6187 * create temporary instance (service was precreated)
6188 * populate with properties from bundle
6189 * take snapshot
6190 */
6191 if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
6192 switch (scf_error()) {
6193 case SCF_ERROR_CONNECTION_BROKEN:
6194 case SCF_ERROR_NO_RESOURCES:
6195 case SCF_ERROR_BACKEND_READONLY:
6196 case SCF_ERROR_BACKEND_ACCESS:
6197 return (stash_scferror(lcbdata));
6198
6199 case SCF_ERROR_EXISTS:
6200 warn(gettext("Temporary service svc:/%s "
6201 "changed unexpectedly (instance \"%s\" added).\n"),
6202 imp_tsname, inst->sc_name);
6203 lcbdata->sc_err = EBUSY;
6204 return (UU_WALK_ERROR);
6205
6206 case SCF_ERROR_DELETED:
6207 warn(gettext("Temporary service svc:/%s "
6208 "was deleted unexpectedly.\n"), imp_tsname);
6209 lcbdata->sc_err = EBUSY;
6210 return (UU_WALK_ERROR);
6211
6212 case SCF_ERROR_INVALID_ARGUMENT:
6213 warn(gettext("Invalid instance name \"%s\".\n"),
6214 inst->sc_name);
6215 return (stash_scferror(lcbdata));
6216
6217 case SCF_ERROR_PERMISSION_DENIED:
6218 warn(gettext("Could not create temporary instance "
6219 "\"%s\" in svc:/%s (permission denied).\n"),
6220 inst->sc_name, imp_tsname);
6221 return (stash_scferror(lcbdata));
6222
6223 case SCF_ERROR_HANDLE_MISMATCH:
6224 case SCF_ERROR_NOT_BOUND:
6225 case SCF_ERROR_NOT_SET:
6226 default:
6227 bad_error("scf_service_add_instance", scf_error());
6228 }
6229 }
6230
6231 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6232 inst->sc_name);
6233 if (r < 0)
6234 bad_error("snprintf", errno);
6235
6236 r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
6237 lcbdata->sc_flags | SCI_NOENABLED);
6238 switch (r) {
6239 case 0:
6240 break;
6241
6242 case ECANCELED:
6243 warn(emsg_tdel, imp_tsname, inst->sc_name);
6244 lcbdata->sc_err = EBUSY;
6245 r = UU_WALK_ERROR;
6246 goto deltemp;
6247
6248 case EEXIST:
6249 warn(emsg_tchg, imp_tsname, inst->sc_name);
6250 lcbdata->sc_err = EBUSY;
6251 r = UU_WALK_ERROR;
6252 goto deltemp;
6253
6254 case ECONNABORTED:
6255 goto connaborted;
6256
6257 case ENOMEM:
6258 case ENOSPC:
6259 case EPERM:
6260 case EROFS:
6261 case EACCES:
6262 case EINVAL:
6263 case EBUSY:
6264 lcbdata->sc_err = r;
6265 r = UU_WALK_ERROR;
6266 goto deltemp;
6267
6268 default:
6269 bad_error("lscf_import_instance_pgs", r);
6270 }
6271
6272 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6273 inst->sc_name);
6274 if (r < 0)
6275 bad_error("snprintf", errno);
6276
6277 ctx.sc_handle = lcbdata->sc_handle;
6278 ctx.sc_parent = imp_tinst;
6279 ctx.sc_service = 0;
6280 ctx.sc_source_fmri = inst->sc_fmri;
6281 ctx.sc_target_fmri = imp_str;
6282 if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
6283 UU_DEFAULT) != 0) {
6284 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6285 bad_error("uu_list_walk", uu_error());
6286
6287 switch (ctx.sc_err) {
6288 case ECONNABORTED:
6289 goto connaborted;
6290
6291 case ECANCELED:
6292 warn(emsg_tdel, imp_tsname, inst->sc_name);
6293 lcbdata->sc_err = EBUSY;
6294 break;
6295
6296 case EEXIST:
6297 warn(emsg_tchg, imp_tsname, inst->sc_name);
6298 lcbdata->sc_err = EBUSY;
6299 break;
6300
6301 default:
6302 lcbdata->sc_err = ctx.sc_err;
6303 }
6304 r = UU_WALK_ERROR;
6305 goto deltemp;
6306 }
6307
6308 if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
6309 inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
6310 switch (scf_error()) {
6311 case SCF_ERROR_CONNECTION_BROKEN:
6312 goto connaborted;
6313
6314 case SCF_ERROR_NO_RESOURCES:
6315 r = stash_scferror(lcbdata);
6316 goto deltemp;
6317
6318 case SCF_ERROR_EXISTS:
6319 warn(emsg_tchg, imp_tsname, inst->sc_name);
6320 lcbdata->sc_err = EBUSY;
6321 r = UU_WALK_ERROR;
6322 goto deltemp;
6323
6324 case SCF_ERROR_PERMISSION_DENIED:
6325 warn(gettext("Could not take \"%s\" snapshot of %s "
6326 "(permission denied).\n"), snap_lastimport,
6327 imp_str);
6328 r = stash_scferror(lcbdata);
6329 goto deltemp;
6330
6331 default:
6332 scfwarn();
6333 lcbdata->sc_err = -1;
6334 r = UU_WALK_ERROR;
6335 goto deltemp;
6336
6337 case SCF_ERROR_HANDLE_MISMATCH:
6338 case SCF_ERROR_INVALID_ARGUMENT:
6339 case SCF_ERROR_NOT_SET:
6340 bad_error("_scf_snapshot_take_new_named", scf_error());
6341 }
6342 }
6343
6344 if (lcbdata->sc_flags & SCI_FRESH)
6345 goto fresh;
6346
6347 if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
6348 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6349 imp_lisnap) != 0) {
6350 switch (scf_error()) {
6351 case SCF_ERROR_DELETED:
6352 warn(emsg_del, inst->sc_parent->sc_fmri,
6353 inst->sc_name);
6354 lcbdata->sc_err = EBUSY;
6355 r = UU_WALK_ERROR;
6356 goto deltemp;
6357
6358 case SCF_ERROR_NOT_FOUND:
6359 flags |= SCI_FORCE;
6360 goto nosnap;
6361
6362 case SCF_ERROR_CONNECTION_BROKEN:
6363 goto connaborted;
6364
6365 case SCF_ERROR_INVALID_ARGUMENT:
6366 case SCF_ERROR_HANDLE_MISMATCH:
6367 case SCF_ERROR_NOT_BOUND:
6368 case SCF_ERROR_NOT_SET:
6369 default:
6370 bad_error("scf_instance_get_snapshot",
6371 scf_error());
6372 }
6373 }
6374
6375 /* upgrade */
6376
6377 /*
6378 * compare new properties with last-import properties
6379 * upgrade current properties
6380 */
6381 /* clear sc_sceen for pgs */
6382 if (uu_list_walk(inst->sc_pgroups, clear_int,
6383 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
6384 0)
6385 bad_error("uu_list_walk", uu_error());
6386
6387 r = get_snaplevel(imp_lisnap, 0, imp_snpl);
6388 switch (r) {
6389 case 0:
6390 break;
6391
6392 case ECONNABORTED:
6393 goto connaborted;
6394
6395 case ECANCELED:
6396 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6397 lcbdata->sc_err = EBUSY;
6398 r = UU_WALK_ERROR;
6399 goto deltemp;
6400
6401 case ENOENT:
6402 warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
6403 lcbdata->sc_err = EBADF;
6404 r = UU_WALK_ERROR;
6405 goto deltemp;
6406
6407 default:
6408 bad_error("get_snaplevel", r);
6409 }
6410
6411 if (scf_instance_get_snapshot(imp_inst, snap_running,
6412 imp_rsnap) != 0) {
6413 switch (scf_error()) {
6414 case SCF_ERROR_DELETED:
6415 warn(emsg_del, inst->sc_parent->sc_fmri,
6416 inst->sc_name);
6417 lcbdata->sc_err = EBUSY;
6418 r = UU_WALK_ERROR;
6419 goto deltemp;
6420
6421 case SCF_ERROR_NOT_FOUND:
6422 break;
6423
6424 case SCF_ERROR_CONNECTION_BROKEN:
6425 goto connaborted;
6426
6427 case SCF_ERROR_INVALID_ARGUMENT:
6428 case SCF_ERROR_HANDLE_MISMATCH:
6429 case SCF_ERROR_NOT_BOUND:
6430 case SCF_ERROR_NOT_SET:
6431 default:
6432 bad_error("scf_instance_get_snapshot",
6433 scf_error());
6434 }
6435
6436 running = NULL;
6437 } else {
6438 r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
6439 switch (r) {
6440 case 0:
6441 running = imp_rsnpl;
6442 break;
6443
6444 case ECONNABORTED:
6445 goto connaborted;
6446
6447 case ECANCELED:
6448 warn(emsg_del, inst->sc_parent->sc_fmri,
6449 inst->sc_name);
6450 lcbdata->sc_err = EBUSY;
6451 r = UU_WALK_ERROR;
6452 goto deltemp;
6453
6454 case ENOENT:
6455 warn(emsg_badsnap, snap_running, inst->sc_fmri);
6456 lcbdata->sc_err = EBADF;
6457 r = UU_WALK_ERROR;
6458 goto deltemp;
6459
6460 default:
6461 bad_error("get_snaplevel", r);
6462 }
6463 }
6464
6465 r = upgrade_props(imp_inst, running, imp_snpl, inst);
6466 switch (r) {
6467 case 0:
6468 break;
6469
6470 case ECANCELED:
6471 case ENODEV:
6472 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6473 lcbdata->sc_err = EBUSY;
6474 r = UU_WALK_ERROR;
6475 goto deltemp;
6476
6477 case ECONNABORTED:
6478 goto connaborted;
6479
6480 case ENOMEM:
6481 case ENOSPC:
6482 case EBADF:
6483 case EBUSY:
6484 case EINVAL:
6485 case EPERM:
6486 case EROFS:
6487 case EACCES:
6488 case EEXIST:
6489 lcbdata->sc_err = r;
6490 r = UU_WALK_ERROR;
6491 goto deltemp;
6492
6493 default:
6494 bad_error("upgrade_props", r);
6495 }
6496
6497 inst->sc_import_state = IMPORT_PROP_DONE;
6498 } else {
6499 switch (scf_error()) {
6500 case SCF_ERROR_CONNECTION_BROKEN:
6501 goto connaborted;
6502
6503 case SCF_ERROR_NOT_FOUND:
6504 break;
6505
6506 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
6507 case SCF_ERROR_HANDLE_MISMATCH:
6508 case SCF_ERROR_NOT_BOUND:
6509 case SCF_ERROR_NOT_SET:
6510 default:
6511 bad_error("scf_service_get_instance", scf_error());
6512 }
6513
6514 fresh:
6515 /* create instance */
6516 if (scf_service_add_instance(rsvc, inst->sc_name,
6517 imp_inst) != 0) {
6518 switch (scf_error()) {
6519 case SCF_ERROR_CONNECTION_BROKEN:
6520 goto connaborted;
6521
6522 case SCF_ERROR_NO_RESOURCES:
6523 case SCF_ERROR_BACKEND_READONLY:
6524 case SCF_ERROR_BACKEND_ACCESS:
6525 r = stash_scferror(lcbdata);
6526 goto deltemp;
6527
6528 case SCF_ERROR_EXISTS:
6529 warn(gettext("%s changed unexpectedly "
6530 "(instance \"%s\" added).\n"),
6531 inst->sc_parent->sc_fmri, inst->sc_name);
6532 lcbdata->sc_err = EBUSY;
6533 r = UU_WALK_ERROR;
6534 goto deltemp;
6535
6536 case SCF_ERROR_PERMISSION_DENIED:
6537 warn(gettext("Could not create \"%s\" instance "
6538 "in %s (permission denied).\n"),
6539 inst->sc_name, inst->sc_parent->sc_fmri);
6540 r = stash_scferror(lcbdata);
6541 goto deltemp;
6542
6543 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
6544 case SCF_ERROR_HANDLE_MISMATCH:
6545 case SCF_ERROR_NOT_BOUND:
6546 case SCF_ERROR_NOT_SET:
6547 default:
6548 bad_error("scf_service_add_instance",
6549 scf_error());
6550 }
6551 }
6552
6553 nosnap:
6554 /*
6555 * Create a last-import snapshot to serve as an attachment
6556 * point for the real one from the temporary instance. Since
6557 * the contents is irrelevant, take it now, while the instance
6558 * is empty, to minimize svc.configd's work.
6559 */
6560 if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6561 imp_lisnap) != 0) {
6562 switch (scf_error()) {
6563 case SCF_ERROR_CONNECTION_BROKEN:
6564 goto connaborted;
6565
6566 case SCF_ERROR_NO_RESOURCES:
6567 r = stash_scferror(lcbdata);
6568 goto deltemp;
6569
6570 case SCF_ERROR_EXISTS:
6571 warn(gettext("%s changed unexpectedly "
6572 "(snapshot \"%s\" added).\n"),
6573 inst->sc_fmri, snap_lastimport);
6574 lcbdata->sc_err = EBUSY;
6575 r = UU_WALK_ERROR;
6576 goto deltemp;
6577
6578 case SCF_ERROR_PERMISSION_DENIED:
6579 warn(gettext("Could not take \"%s\" snapshot "
6580 "of %s (permission denied).\n"),
6581 snap_lastimport, inst->sc_fmri);
6582 r = stash_scferror(lcbdata);
6583 goto deltemp;
6584
6585 default:
6586 scfwarn();
6587 lcbdata->sc_err = -1;
6588 r = UU_WALK_ERROR;
6589 goto deltemp;
6590
6591 case SCF_ERROR_NOT_SET:
6592 case SCF_ERROR_INTERNAL:
6593 case SCF_ERROR_INVALID_ARGUMENT:
6594 case SCF_ERROR_HANDLE_MISMATCH:
6595 bad_error("_scf_snapshot_take_new",
6596 scf_error());
6597 }
6598 }
6599
6600 if (li_only)
6601 goto lionly;
6602
6603 inst->sc_import_state = IMPORT_PROP_BEGUN;
6604
6605 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6606 flags);
6607 switch (r) {
6608 case 0:
6609 break;
6610
6611 case ECONNABORTED:
6612 goto connaborted;
6613
6614 case ECANCELED:
6615 warn(gettext("%s changed unexpectedly "
6616 "(instance \"%s\" deleted).\n"),
6617 inst->sc_parent->sc_fmri, inst->sc_name);
6618 lcbdata->sc_err = EBUSY;
6619 r = UU_WALK_ERROR;
6620 goto deltemp;
6621
6622 case EEXIST:
6623 warn(gettext("%s changed unexpectedly "
6624 "(property group added).\n"), inst->sc_fmri);
6625 lcbdata->sc_err = EBUSY;
6626 r = UU_WALK_ERROR;
6627 goto deltemp;
6628
6629 default:
6630 lcbdata->sc_err = r;
6631 r = UU_WALK_ERROR;
6632 goto deltemp;
6633
6634 case EINVAL: /* caught above */
6635 bad_error("lscf_import_instance_pgs", r);
6636 }
6637
6638 ctx.sc_parent = imp_inst;
6639 ctx.sc_service = 0;
6640 ctx.sc_trans = NULL;
6641 ctx.sc_flags = 0;
6642 if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6643 &ctx, UU_DEFAULT) != 0) {
6644 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6645 bad_error("uu_list_walk", uu_error());
6646
6647 if (ctx.sc_err == ECONNABORTED)
6648 goto connaborted;
6649 lcbdata->sc_err = ctx.sc_err;
6650 r = UU_WALK_ERROR;
6651 goto deltemp;
6652 }
6653
6654 inst->sc_import_state = IMPORT_PROP_DONE;
6655
6656 if (g_verbose)
6657 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6658 snap_initial, inst->sc_fmri);
6659 r = take_snap(imp_inst, snap_initial, imp_snap);
6660 switch (r) {
6661 case 0:
6662 break;
6663
6664 case ECONNABORTED:
6665 goto connaborted;
6666
6667 case ENOSPC:
6668 case -1:
6669 lcbdata->sc_err = r;
6670 r = UU_WALK_ERROR;
6671 goto deltemp;
6672
6673 case ECANCELED:
6674 warn(gettext("%s changed unexpectedly "
6675 "(instance %s deleted).\n"),
6676 inst->sc_parent->sc_fmri, inst->sc_name);
6677 lcbdata->sc_err = r;
6678 r = UU_WALK_ERROR;
6679 goto deltemp;
6680
6681 case EPERM:
6682 warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6683 lcbdata->sc_err = r;
6684 r = UU_WALK_ERROR;
6685 goto deltemp;
6686
6687 default:
6688 bad_error("take_snap", r);
6689 }
6690 }
6691
6692 lionly:
6693 if (lcbdata->sc_flags & SCI_NOSNAP)
6694 goto deltemp;
6695
6696 /* transfer snapshot from temporary instance */
6697 if (g_verbose)
6698 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6699 snap_lastimport, inst->sc_fmri);
6700 if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6701 switch (scf_error()) {
6702 case SCF_ERROR_CONNECTION_BROKEN:
6703 goto connaborted;
6704
6705 case SCF_ERROR_NO_RESOURCES:
6706 r = stash_scferror(lcbdata);
6707 goto deltemp;
6708
6709 case SCF_ERROR_PERMISSION_DENIED:
6710 warn(gettext("Could not take \"%s\" snapshot for %s "
6711 "(permission denied).\n"), snap_lastimport,
6712 inst->sc_fmri);
6713 r = stash_scferror(lcbdata);
6714 goto deltemp;
6715
6716 case SCF_ERROR_NOT_SET:
6717 case SCF_ERROR_HANDLE_MISMATCH:
6718 default:
6719 bad_error("_scf_snapshot_attach", scf_error());
6720 }
6721 }
6722
6723 inst->sc_import_state = IMPORT_COMPLETE;
6724
6725 r = UU_WALK_NEXT;
6726
6727 deltemp:
6728 /* delete temporary instance */
6729 if (scf_instance_delete(imp_tinst) != 0) {
6730 switch (scf_error()) {
6731 case SCF_ERROR_DELETED:
6732 break;
6733
6734 case SCF_ERROR_CONNECTION_BROKEN:
6735 goto connaborted;
6736
6737 case SCF_ERROR_NOT_SET:
6738 case SCF_ERROR_NOT_BOUND:
6739 default:
6740 bad_error("scf_instance_delete", scf_error());
6741 }
6742 }
6743
6744 return (r);
6745
6746 connaborted:
6747 warn(gettext("Could not delete svc:/%s:%s "
6748 "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6749 lcbdata->sc_err = ECONNABORTED;
6750 return (UU_WALK_ERROR);
6751 }
6752
6753 /*
6754 * If the service is missing, create it, import its properties, and import the
6755 * instances. Since the service is brand new, it should be empty, and if we
6756 * run into any existing entities (SCF_ERROR_EXISTS), abort.
6757 *
6758 * If the service exists, we want to upgrade its properties and import the
6759 * instances. Upgrade requires a last-import snapshot, though, which are
6760 * children of instances, so first we'll have to go through the instances
6761 * looking for a last-import snapshot. If we don't find one then we'll just
6762 * override-import the service properties (but don't delete existing
6763 * properties: another service might have declared us as a dependent). Before
6764 * we change anything, though, we want to take the previous snapshots. We
6765 * also give lscf_instance_import() a leg up on taking last-import snapshots
6766 * by importing the manifest's service properties into a temporary service.
6767 *
6768 * On success, returns UU_WALK_NEXT. On failure, returns UU_WALK_ERROR and
6769 * sets lcbdata->sc_err to
6770 * ECONNABORTED - repository connection broken
6771 * ENOMEM - out of memory
6772 * ENOSPC - svc.configd is out of resources
6773 * EPERM - couldn't create temporary service (error printed)
6774 * - couldn't import into temp service (error printed)
6775 * - couldn't create service (error printed)
6776 * - couldn't import dependent (error printed)
6777 * - couldn't take snapshot (error printed)
6778 * - couldn't create instance (error printed)
6779 * - couldn't create, modify, or delete pg (error printed)
6780 * - couldn't create, modify, or delete dependent (error printed)
6781 * - couldn't import instance (error printed)
6782 * EROFS - couldn't create temporary service (repository read-only)
6783 * - couldn't import into temporary service (repository read-only)
6784 * - couldn't create service (repository read-only)
6785 * - couldn't import dependent (repository read-only)
6786 * - couldn't create instance (repository read-only)
6787 * - couldn't create, modify, or delete pg or dependent
6788 * - couldn't import instance (repository read-only)
6789 * EACCES - couldn't create temporary service (backend access denied)
6790 * - couldn't import into temporary service (backend access denied)
6791 * - couldn't create service (backend access denied)
6792 * - couldn't import dependent (backend access denied)
6793 * - couldn't create instance (backend access denied)
6794 * - couldn't create, modify, or delete pg or dependent
6795 * - couldn't import instance (backend access denied)
6796 * EINVAL - service name is invalid (error printed)
6797 * - service name is too long (error printed)
6798 * - s has invalid pgroup (error printed)
6799 * - s has invalid dependent (error printed)
6800 * - instance name is invalid (error printed)
6801 * - instance entity_t is invalid (error printed)
6802 * EEXIST - couldn't create temporary service (already exists) (error printed)
6803 * - couldn't import dependent (dependency pg already exists) (printed)
6804 * - dependency collision in dependent service (error printed)
6805 * EBUSY - temporary service deleted (error printed)
6806 * - property group added to temporary service (error printed)
6807 * - new property group changed or was deleted (error printed)
6808 * - service was added unexpectedly (error printed)
6809 * - service was deleted unexpectedly (error printed)
6810 * - property group added to new service (error printed)
6811 * - instance added unexpectedly (error printed)
6812 * - instance deleted unexpectedly (error printed)
6813 * - dependent service deleted unexpectedly (error printed)
6814 * - pg was added, changed, or deleted (error printed)
6815 * - dependent pg changed (error printed)
6816 * - temporary instance added, changed, or deleted (error printed)
6817 * EBADF - a last-import snapshot is corrupt (error printed)
6818 * - the service is corrupt (error printed)
6819 * - a dependent is corrupt (error printed)
6820 * - an instance is corrupt (error printed)
6821 * - an instance has a corrupt last-import snapshot (error printed)
6822 * - dependent target has a corrupt snapshot (error printed)
6823 * -1 - unknown libscf error (error printed)
6824 */
6825 static int
6826 lscf_service_import(void *v, void *pvt)
6827 {
6828 entity_t *s = v;
6829 scf_callback_t cbdata;
6830 scf_callback_t *lcbdata = pvt;
6831 scf_scope_t *scope = lcbdata->sc_parent;
6832 entity_t *inst, linst;
6833 int r;
6834 int fresh = 0;
6835 scf_snaplevel_t *running;
6836 int have_ge = 0;
6837
6838 const char * const ts_deleted = gettext("Temporary service svc:/%s "
6839 "was deleted unexpectedly.\n");
6840 const char * const ts_pg_added = gettext("Temporary service svc:/%s "
6841 "changed unexpectedly (property group added).\n");
6842 const char * const s_deleted =
6843 gettext("%s was deleted unexpectedly.\n");
6844 const char * const i_deleted =
6845 gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
6846 const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
6847 "is corrupt (missing service snaplevel).\n");
6848 const char * const s_mfile_upd =
6849 gettext("Unable to update the manifest file connection "
6850 "for %s\n");
6851
6852 li_only = 0;
6853 /* Validate the service name */
6854 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
6855 switch (scf_error()) {
6856 case SCF_ERROR_CONNECTION_BROKEN:
6857 return (stash_scferror(lcbdata));
6858
6859 case SCF_ERROR_INVALID_ARGUMENT:
6860 warn(gettext("\"%s\" is an invalid service name. "
6861 "Cannot import.\n"), s->sc_name);
6862 return (stash_scferror(lcbdata));
6863
6864 case SCF_ERROR_NOT_FOUND:
6865 break;
6866
6867 case SCF_ERROR_HANDLE_MISMATCH:
6868 case SCF_ERROR_NOT_BOUND:
6869 case SCF_ERROR_NOT_SET:
6870 default:
6871 bad_error("scf_scope_get_service", scf_error());
6872 }
6873 }
6874
6875 /* create temporary service */
6876 /*
6877 * the size of the buffer was reduced to max_scf_name_len to prevent
6878 * hitting bug 6681151. After the bug fix, the size of the buffer
6879 * should be restored to its original value (max_scf_name_len +1)
6880 */
6881 r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
6882 if (r < 0)
6883 bad_error("snprintf", errno);
6884 if (r > max_scf_name_len) {
6885 warn(gettext(
6886 "Service name \"%s\" is too long. Cannot import.\n"),
6887 s->sc_name);
6888 lcbdata->sc_err = EINVAL;
6889 return (UU_WALK_ERROR);
6890 }
6891
6892 if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
6893 switch (scf_error()) {
6894 case SCF_ERROR_CONNECTION_BROKEN:
6895 case SCF_ERROR_NO_RESOURCES:
6896 case SCF_ERROR_BACKEND_READONLY:
6897 case SCF_ERROR_BACKEND_ACCESS:
6898 return (stash_scferror(lcbdata));
6899
6900 case SCF_ERROR_EXISTS:
6901 warn(gettext(
6902 "Temporary service \"%s\" must be deleted before "
6903 "this manifest can be imported.\n"), imp_tsname);
6904 return (stash_scferror(lcbdata));
6905
6906 case SCF_ERROR_PERMISSION_DENIED:
6907 warn(gettext("Could not create temporary service "
6908 "\"%s\" (permission denied).\n"), imp_tsname);
6909 return (stash_scferror(lcbdata));
6910
6911 case SCF_ERROR_INVALID_ARGUMENT:
6912 case SCF_ERROR_HANDLE_MISMATCH:
6913 case SCF_ERROR_NOT_BOUND:
6914 case SCF_ERROR_NOT_SET:
6915 default:
6916 bad_error("scf_scope_add_service", scf_error());
6917 }
6918 }
6919
6920 r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
6921 if (r < 0)
6922 bad_error("snprintf", errno);
6923
6924 cbdata.sc_handle = lcbdata->sc_handle;
6925 cbdata.sc_parent = imp_tsvc;
6926 cbdata.sc_service = 1;
6927 cbdata.sc_source_fmri = s->sc_fmri;
6928 cbdata.sc_target_fmri = imp_str;
6929 cbdata.sc_flags = 0;
6930
6931 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
6932 UU_DEFAULT) != 0) {
6933 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6934 bad_error("uu_list_walk", uu_error());
6935
6936 lcbdata->sc_err = cbdata.sc_err;
6937 switch (cbdata.sc_err) {
6938 case ECONNABORTED:
6939 goto connaborted;
6940
6941 case ECANCELED:
6942 warn(ts_deleted, imp_tsname);
6943 lcbdata->sc_err = EBUSY;
6944 return (UU_WALK_ERROR);
6945
6946 case EEXIST:
6947 warn(ts_pg_added, imp_tsname);
6948 lcbdata->sc_err = EBUSY;
6949 return (UU_WALK_ERROR);
6950 }
6951
6952 r = UU_WALK_ERROR;
6953 goto deltemp;
6954 }
6955
6956 if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
6957 UU_DEFAULT) != 0) {
6958 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6959 bad_error("uu_list_walk", uu_error());
6960
6961 lcbdata->sc_err = cbdata.sc_err;
6962 switch (cbdata.sc_err) {
6963 case ECONNABORTED:
6964 goto connaborted;
6965
6966 case ECANCELED:
6967 warn(ts_deleted, imp_tsname);
6968 lcbdata->sc_err = EBUSY;
6969 return (UU_WALK_ERROR);
6970
6971 case EEXIST:
6972 warn(ts_pg_added, imp_tsname);
6973 lcbdata->sc_err = EBUSY;
6974 return (UU_WALK_ERROR);
6975 }
6976
6977 r = UU_WALK_ERROR;
6978 goto deltemp;
6979 }
6980
6981 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
6982 switch (scf_error()) {
6983 case SCF_ERROR_NOT_FOUND:
6984 break;
6985
6986 case SCF_ERROR_CONNECTION_BROKEN:
6987 goto connaborted;
6988
6989 case SCF_ERROR_INVALID_ARGUMENT:
6990 case SCF_ERROR_HANDLE_MISMATCH:
6991 case SCF_ERROR_NOT_BOUND:
6992 case SCF_ERROR_NOT_SET:
6993 default:
6994 bad_error("scf_scope_get_service", scf_error());
6995 }
6996
6997 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
6998 switch (scf_error()) {
6999 case SCF_ERROR_CONNECTION_BROKEN:
7000 goto connaborted;
7001
7002 case SCF_ERROR_NO_RESOURCES:
7003 case SCF_ERROR_BACKEND_READONLY:
7004 case SCF_ERROR_BACKEND_ACCESS:
7005 r = stash_scferror(lcbdata);
7006 goto deltemp;
7007
7008 case SCF_ERROR_EXISTS:
7009 warn(gettext("Scope \"%s\" changed unexpectedly"
7010 " (service \"%s\" added).\n"),
7011 SCF_SCOPE_LOCAL, s->sc_name);
7012 lcbdata->sc_err = EBUSY;
7013 goto deltemp;
7014
7015 case SCF_ERROR_PERMISSION_DENIED:
7016 warn(gettext("Could not create service \"%s\" "
7017 "(permission denied).\n"), s->sc_name);
7018 goto deltemp;
7019
7020 case SCF_ERROR_INVALID_ARGUMENT:
7021 case SCF_ERROR_HANDLE_MISMATCH:
7022 case SCF_ERROR_NOT_BOUND:
7023 case SCF_ERROR_NOT_SET:
7024 default:
7025 bad_error("scf_scope_add_service", scf_error());
7026 }
7027 }
7028
7029 s->sc_import_state = IMPORT_PROP_BEGUN;
7030
7031 /* import service properties */
7032 cbdata.sc_handle = lcbdata->sc_handle;
7033 cbdata.sc_parent = imp_svc;
7034 cbdata.sc_service = 1;
7035 cbdata.sc_flags = lcbdata->sc_flags;
7036 cbdata.sc_source_fmri = s->sc_fmri;
7037 cbdata.sc_target_fmri = s->sc_fmri;
7038
7039 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7040 &cbdata, UU_DEFAULT) != 0) {
7041 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7042 bad_error("uu_list_walk", uu_error());
7043
7044 lcbdata->sc_err = cbdata.sc_err;
7045 switch (cbdata.sc_err) {
7046 case ECONNABORTED:
7047 goto connaborted;
7048
7049 case ECANCELED:
7050 warn(s_deleted, s->sc_fmri);
7051 lcbdata->sc_err = EBUSY;
7052 return (UU_WALK_ERROR);
7053
7054 case EEXIST:
7055 warn(gettext("%s changed unexpectedly "
7056 "(property group added).\n"), s->sc_fmri);
7057 lcbdata->sc_err = EBUSY;
7058 return (UU_WALK_ERROR);
7059
7060 case EINVAL:
7061 /* caught above */
7062 bad_error("entity_pgroup_import",
7063 cbdata.sc_err);
7064 }
7065
7066 r = UU_WALK_ERROR;
7067 goto deltemp;
7068 }
7069
7070 cbdata.sc_trans = NULL;
7071 cbdata.sc_flags = 0;
7072 if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
7073 &cbdata, UU_DEFAULT) != 0) {
7074 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7075 bad_error("uu_list_walk", uu_error());
7076
7077 lcbdata->sc_err = cbdata.sc_err;
7078 if (cbdata.sc_err == ECONNABORTED)
7079 goto connaborted;
7080 r = UU_WALK_ERROR;
7081 goto deltemp;
7082 }
7083
7084 s->sc_import_state = IMPORT_PROP_DONE;
7085
7086 /*
7087 * This is a new service, so we can't take previous snapshots
7088 * or upgrade service properties.
7089 */
7090 fresh = 1;
7091 goto instances;
7092 }
7093
7094 /* Clear sc_seen for the instances. */
7095 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
7096 (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
7097 bad_error("uu_list_walk", uu_error());
7098
7099 /*
7100 * Take previous snapshots for all instances. Even for ones not
7101 * mentioned in the bundle, since we might change their service
7102 * properties.
7103 */
7104 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7105 switch (scf_error()) {
7106 case SCF_ERROR_CONNECTION_BROKEN:
7107 goto connaborted;
7108
7109 case SCF_ERROR_DELETED:
7110 warn(s_deleted, s->sc_fmri);
7111 lcbdata->sc_err = EBUSY;
7112 r = UU_WALK_ERROR;
7113 goto deltemp;
7114
7115 case SCF_ERROR_HANDLE_MISMATCH:
7116 case SCF_ERROR_NOT_BOUND:
7117 case SCF_ERROR_NOT_SET:
7118 default:
7119 bad_error("scf_iter_service_instances", scf_error());
7120 }
7121 }
7122
7123 for (;;) {
7124 r = scf_iter_next_instance(imp_iter, imp_inst);
7125 if (r == 0)
7126 break;
7127 if (r != 1) {
7128 switch (scf_error()) {
7129 case SCF_ERROR_DELETED:
7130 warn(s_deleted, s->sc_fmri);
7131 lcbdata->sc_err = EBUSY;
7132 r = UU_WALK_ERROR;
7133 goto deltemp;
7134
7135 case SCF_ERROR_CONNECTION_BROKEN:
7136 goto connaborted;
7137
7138 case SCF_ERROR_NOT_BOUND:
7139 case SCF_ERROR_HANDLE_MISMATCH:
7140 case SCF_ERROR_INVALID_ARGUMENT:
7141 case SCF_ERROR_NOT_SET:
7142 default:
7143 bad_error("scf_iter_next_instance",
7144 scf_error());
7145 }
7146 }
7147
7148 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
7149 switch (scf_error()) {
7150 case SCF_ERROR_DELETED:
7151 continue;
7152
7153 case SCF_ERROR_CONNECTION_BROKEN:
7154 goto connaborted;
7155
7156 case SCF_ERROR_NOT_SET:
7157 case SCF_ERROR_NOT_BOUND:
7158 default:
7159 bad_error("scf_instance_get_name", scf_error());
7160 }
7161 }
7162
7163 if (g_verbose)
7164 warn(gettext(
7165 "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
7166 snap_previous, s->sc_name, imp_str);
7167
7168 r = take_snap(imp_inst, snap_previous, imp_snap);
7169 switch (r) {
7170 case 0:
7171 break;
7172
7173 case ECANCELED:
7174 continue;
7175
7176 case ECONNABORTED:
7177 goto connaborted;
7178
7179 case EPERM:
7180 warn(gettext("Could not take \"%s\" snapshot of "
7181 "svc:/%s:%s (permission denied).\n"),
7182 snap_previous, s->sc_name, imp_str);
7183 lcbdata->sc_err = r;
7184 return (UU_WALK_ERROR);
7185
7186 case ENOSPC:
7187 case -1:
7188 lcbdata->sc_err = r;
7189 r = UU_WALK_ERROR;
7190 goto deltemp;
7191
7192 default:
7193 bad_error("take_snap", r);
7194 }
7195
7196 linst.sc_name = imp_str;
7197 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
7198 &linst, NULL, NULL);
7199 if (inst != NULL) {
7200 inst->sc_import_state = IMPORT_PREVIOUS;
7201 inst->sc_seen = 1;
7202 }
7203 }
7204
7205 /*
7206 * Create the new instances and take previous snapshots of
7207 * them. This is not necessary, but it maximizes data preservation.
7208 */
7209 for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
7210 inst != NULL;
7211 inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
7212 inst)) {
7213 if (inst->sc_seen)
7214 continue;
7215
7216 if (scf_service_add_instance(imp_svc, inst->sc_name,
7217 imp_inst) != 0) {
7218 switch (scf_error()) {
7219 case SCF_ERROR_CONNECTION_BROKEN:
7220 goto connaborted;
7221
7222 case SCF_ERROR_BACKEND_READONLY:
7223 case SCF_ERROR_BACKEND_ACCESS:
7224 case SCF_ERROR_NO_RESOURCES:
7225 r = stash_scferror(lcbdata);
7226 goto deltemp;
7227
7228 case SCF_ERROR_EXISTS:
7229 warn(gettext("%s changed unexpectedly "
7230 "(instance \"%s\" added).\n"), s->sc_fmri,
7231 inst->sc_name);
7232 lcbdata->sc_err = EBUSY;
7233 r = UU_WALK_ERROR;
7234 goto deltemp;
7235
7236 case SCF_ERROR_INVALID_ARGUMENT:
7237 warn(gettext("Service \"%s\" has instance with "
7238 "invalid name \"%s\".\n"), s->sc_name,
7239 inst->sc_name);
7240 r = stash_scferror(lcbdata);
7241 goto deltemp;
7242
7243 case SCF_ERROR_PERMISSION_DENIED:
7244 warn(gettext("Could not create instance \"%s\" "
7245 "in %s (permission denied).\n"),
7246 inst->sc_name, s->sc_fmri);
7247 r = stash_scferror(lcbdata);
7248 goto deltemp;
7249
7250 case SCF_ERROR_HANDLE_MISMATCH:
7251 case SCF_ERROR_NOT_BOUND:
7252 case SCF_ERROR_NOT_SET:
7253 default:
7254 bad_error("scf_service_add_instance",
7255 scf_error());
7256 }
7257 }
7258
7259 if (g_verbose)
7260 warn(gettext("Taking \"%s\" snapshot for "
7261 "new service %s.\n"), snap_previous, inst->sc_fmri);
7262 r = take_snap(imp_inst, snap_previous, imp_snap);
7263 switch (r) {
7264 case 0:
7265 break;
7266
7267 case ECANCELED:
7268 warn(i_deleted, s->sc_fmri, inst->sc_name);
7269 lcbdata->sc_err = EBUSY;
7270 r = UU_WALK_ERROR;
7271 goto deltemp;
7272
7273 case ECONNABORTED:
7274 goto connaborted;
7275
7276 case EPERM:
7277 warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
7278 lcbdata->sc_err = r;
7279 r = UU_WALK_ERROR;
7280 goto deltemp;
7281
7282 case ENOSPC:
7283 case -1:
7284 r = UU_WALK_ERROR;
7285 goto deltemp;
7286
7287 default:
7288 bad_error("take_snap", r);
7289 }
7290 }
7291
7292 s->sc_import_state = IMPORT_PREVIOUS;
7293
7294 /*
7295 * Upgrade service properties, if we can find a last-import snapshot.
7296 * Any will do because we don't support different service properties
7297 * in different manifests, so all snaplevels of the service in all of
7298 * the last-import snapshots of the instances should be the same.
7299 */
7300 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7301 switch (scf_error()) {
7302 case SCF_ERROR_CONNECTION_BROKEN:
7303 goto connaborted;
7304
7305 case SCF_ERROR_DELETED:
7306 warn(s_deleted, s->sc_fmri);
7307 lcbdata->sc_err = EBUSY;
7308 r = UU_WALK_ERROR;
7309 goto deltemp;
7310
7311 case SCF_ERROR_HANDLE_MISMATCH:
7312 case SCF_ERROR_NOT_BOUND:
7313 case SCF_ERROR_NOT_SET:
7314 default:
7315 bad_error("scf_iter_service_instances", scf_error());
7316 }
7317 }
7318
7319 for (;;) {
7320 r = scf_iter_next_instance(imp_iter, imp_inst);
7321 if (r == -1) {
7322 switch (scf_error()) {
7323 case SCF_ERROR_DELETED:
7324 warn(s_deleted, s->sc_fmri);
7325 lcbdata->sc_err = EBUSY;
7326 r = UU_WALK_ERROR;
7327 goto deltemp;
7328
7329 case SCF_ERROR_CONNECTION_BROKEN:
7330 goto connaborted;
7331
7332 case SCF_ERROR_NOT_BOUND:
7333 case SCF_ERROR_HANDLE_MISMATCH:
7334 case SCF_ERROR_INVALID_ARGUMENT:
7335 case SCF_ERROR_NOT_SET:
7336 default:
7337 bad_error("scf_iter_next_instance",
7338 scf_error());
7339 }
7340 }
7341
7342 if (r == 0) {
7343 /*
7344 * Didn't find any last-import snapshots. Override-
7345 * import the properties. Unless one of the instances
7346 * has a general/enabled property, in which case we're
7347 * probably running a last-import-capable svccfg for
7348 * the first time, and we should only take the
7349 * last-import snapshot.
7350 */
7351 if (have_ge) {
7352 pgroup_t *mfpg;
7353 scf_callback_t mfcbdata;
7354
7355 li_only = 1;
7356 no_refresh = 1;
7357 /*
7358 * Need to go ahead and import the manifestfiles
7359 * pg if it exists. If the last-import snapshot
7360 * upgrade code is ever removed this code can
7361 * be removed as well.
7362 */
7363 mfpg = internal_pgroup_find(s,
7364 SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
7365
7366 if (mfpg) {
7367 mfcbdata.sc_handle = g_hndl;
7368 mfcbdata.sc_parent = imp_svc;
7369 mfcbdata.sc_service = 1;
7370 mfcbdata.sc_flags = SCI_FORCE;
7371 mfcbdata.sc_source_fmri = s->sc_fmri;
7372 mfcbdata.sc_target_fmri = s->sc_fmri;
7373 if (entity_pgroup_import(mfpg,
7374 &mfcbdata) != UU_WALK_NEXT) {
7375 warn(s_mfile_upd, s->sc_fmri);
7376 r = UU_WALK_ERROR;
7377 goto deltemp;
7378 }
7379 }
7380 break;
7381 }
7382
7383 s->sc_import_state = IMPORT_PROP_BEGUN;
7384
7385 cbdata.sc_handle = g_hndl;
7386 cbdata.sc_parent = imp_svc;
7387 cbdata.sc_service = 1;
7388 cbdata.sc_flags = SCI_FORCE;
7389 cbdata.sc_source_fmri = s->sc_fmri;
7390 cbdata.sc_target_fmri = s->sc_fmri;
7391 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7392 &cbdata, UU_DEFAULT) != 0) {
7393 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7394 bad_error("uu_list_walk", uu_error());
7395 lcbdata->sc_err = cbdata.sc_err;
7396 switch (cbdata.sc_err) {
7397 case ECONNABORTED:
7398 goto connaborted;
7399
7400 case ECANCELED:
7401 warn(s_deleted, s->sc_fmri);
7402 lcbdata->sc_err = EBUSY;
7403 break;
7404
7405 case EINVAL: /* caught above */
7406 case EEXIST:
7407 bad_error("entity_pgroup_import",
7408 cbdata.sc_err);
7409 }
7410
7411 r = UU_WALK_ERROR;
7412 goto deltemp;
7413 }
7414
7415 cbdata.sc_trans = NULL;
7416 cbdata.sc_flags = 0;
7417 if (uu_list_walk(s->sc_dependents,
7418 lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
7419 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7420 bad_error("uu_list_walk", uu_error());
7421 lcbdata->sc_err = cbdata.sc_err;
7422 if (cbdata.sc_err == ECONNABORTED)
7423 goto connaborted;
7424 r = UU_WALK_ERROR;
7425 goto deltemp;
7426 }
7427 break;
7428 }
7429
7430 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
7431 imp_snap) != 0) {
7432 switch (scf_error()) {
7433 case SCF_ERROR_DELETED:
7434 continue;
7435
7436 case SCF_ERROR_NOT_FOUND:
7437 break;
7438
7439 case SCF_ERROR_CONNECTION_BROKEN:
7440 goto connaborted;
7441
7442 case SCF_ERROR_HANDLE_MISMATCH:
7443 case SCF_ERROR_NOT_BOUND:
7444 case SCF_ERROR_INVALID_ARGUMENT:
7445 case SCF_ERROR_NOT_SET:
7446 default:
7447 bad_error("scf_instance_get_snapshot",
7448 scf_error());
7449 }
7450
7451 if (have_ge)
7452 continue;
7453
7454 /*
7455 * Check for a general/enabled property. This is how
7456 * we tell whether to import if there turn out to be
7457 * no last-import snapshots.
7458 */
7459 if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
7460 imp_pg) == 0) {
7461 if (scf_pg_get_property(imp_pg,
7462 SCF_PROPERTY_ENABLED, imp_prop) == 0) {
7463 have_ge = 1;
7464 } else {
7465 switch (scf_error()) {
7466 case SCF_ERROR_DELETED:
7467 case SCF_ERROR_NOT_FOUND:
7468 continue;
7469
7470 case SCF_ERROR_INVALID_ARGUMENT:
7471 case SCF_ERROR_HANDLE_MISMATCH:
7472 case SCF_ERROR_CONNECTION_BROKEN:
7473 case SCF_ERROR_NOT_BOUND:
7474 case SCF_ERROR_NOT_SET:
7475 default:
7476 bad_error("scf_pg_get_property",
7477 scf_error());
7478 }
7479 }
7480 } else {
7481 switch (scf_error()) {
7482 case SCF_ERROR_DELETED:
7483 case SCF_ERROR_NOT_FOUND:
7484 continue;
7485
7486 case SCF_ERROR_CONNECTION_BROKEN:
7487 goto connaborted;
7488
7489 case SCF_ERROR_NOT_BOUND:
7490 case SCF_ERROR_NOT_SET:
7491 case SCF_ERROR_INVALID_ARGUMENT:
7492 case SCF_ERROR_HANDLE_MISMATCH:
7493 default:
7494 bad_error("scf_instance_get_pg",
7495 scf_error());
7496 }
7497 }
7498 continue;
7499 }
7500
7501 /* find service snaplevel */
7502 r = get_snaplevel(imp_snap, 1, imp_snpl);
7503 switch (r) {
7504 case 0:
7505 break;
7506
7507 case ECONNABORTED:
7508 goto connaborted;
7509
7510 case ECANCELED:
7511 continue;
7512
7513 case ENOENT:
7514 if (scf_instance_get_name(imp_inst, imp_str,
7515 imp_str_sz) < 0)
7516 (void) strcpy(imp_str, "?");
7517 warn(badsnap, snap_lastimport, s->sc_name, imp_str);
7518 lcbdata->sc_err = EBADF;
7519 r = UU_WALK_ERROR;
7520 goto deltemp;
7521
7522 default:
7523 bad_error("get_snaplevel", r);
7524 }
7525
7526 if (scf_instance_get_snapshot(imp_inst, snap_running,
7527 imp_rsnap) != 0) {
7528 switch (scf_error()) {
7529 case SCF_ERROR_DELETED:
7530 continue;
7531
7532 case SCF_ERROR_NOT_FOUND:
7533 break;
7534
7535 case SCF_ERROR_CONNECTION_BROKEN:
7536 goto connaborted;
7537
7538 case SCF_ERROR_INVALID_ARGUMENT:
7539 case SCF_ERROR_HANDLE_MISMATCH:
7540 case SCF_ERROR_NOT_BOUND:
7541 case SCF_ERROR_NOT_SET:
7542 default:
7543 bad_error("scf_instance_get_snapshot",
7544 scf_error());
7545 }
7546 running = NULL;
7547 } else {
7548 r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
7549 switch (r) {
7550 case 0:
7551 running = imp_rsnpl;
7552 break;
7553
7554 case ECONNABORTED:
7555 goto connaborted;
7556
7557 case ECANCELED:
7558 continue;
7559
7560 case ENOENT:
7561 if (scf_instance_get_name(imp_inst, imp_str,
7562 imp_str_sz) < 0)
7563 (void) strcpy(imp_str, "?");
7564 warn(badsnap, snap_running, s->sc_name,
7565 imp_str);
7566 lcbdata->sc_err = EBADF;
7567 r = UU_WALK_ERROR;
7568 goto deltemp;
7569
7570 default:
7571 bad_error("get_snaplevel", r);
7572 }
7573 }
7574
7575 if (g_verbose) {
7576 if (scf_instance_get_name(imp_inst, imp_str,
7577 imp_str_sz) < 0)
7578 (void) strcpy(imp_str, "?");
7579 warn(gettext("Upgrading properties of %s according to "
7580 "instance \"%s\".\n"), s->sc_fmri, imp_str);
7581 }
7582
7583 /* upgrade service properties */
7584 r = upgrade_props(imp_svc, running, imp_snpl, s);
7585 if (r == 0)
7586 break;
7587
7588 switch (r) {
7589 case ECONNABORTED:
7590 goto connaborted;
7591
7592 case ECANCELED:
7593 warn(s_deleted, s->sc_fmri);
7594 lcbdata->sc_err = EBUSY;
7595 break;
7596
7597 case ENODEV:
7598 if (scf_instance_get_name(imp_inst, imp_str,
7599 imp_str_sz) < 0)
7600 (void) strcpy(imp_str, "?");
7601 warn(i_deleted, s->sc_fmri, imp_str);
7602 lcbdata->sc_err = EBUSY;
7603 break;
7604
7605 default:
7606 lcbdata->sc_err = r;
7607 }
7608
7609 r = UU_WALK_ERROR;
7610 goto deltemp;
7611 }
7612
7613 s->sc_import_state = IMPORT_PROP_DONE;
7614
7615 instances:
7616 /* import instances */
7617 cbdata.sc_handle = lcbdata->sc_handle;
7618 cbdata.sc_parent = imp_svc;
7619 cbdata.sc_service = 1;
7620 cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7621 cbdata.sc_general = NULL;
7622
7623 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7624 lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7625 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7626 bad_error("uu_list_walk", uu_error());
7627
7628 lcbdata->sc_err = cbdata.sc_err;
7629 if (cbdata.sc_err == ECONNABORTED)
7630 goto connaborted;
7631 r = UU_WALK_ERROR;
7632 goto deltemp;
7633 }
7634
7635 s->sc_import_state = IMPORT_COMPLETE;
7636 r = UU_WALK_NEXT;
7637
7638 deltemp:
7639 /* delete temporary service */
7640 if (scf_service_delete(imp_tsvc) != 0) {
7641 switch (scf_error()) {
7642 case SCF_ERROR_DELETED:
7643 break;
7644
7645 case SCF_ERROR_CONNECTION_BROKEN:
7646 goto connaborted;
7647
7648 case SCF_ERROR_EXISTS:
7649 warn(gettext(
7650 "Could not delete svc:/%s (instances exist).\n"),
7651 imp_tsname);
7652 break;
7653
7654 case SCF_ERROR_NOT_SET:
7655 case SCF_ERROR_NOT_BOUND:
7656 default:
7657 bad_error("scf_service_delete", scf_error());
7658 }
7659 }
7660
7661 return (r);
7662
7663 connaborted:
7664 warn(gettext("Could not delete svc:/%s "
7665 "(repository connection broken).\n"), imp_tsname);
7666 lcbdata->sc_err = ECONNABORTED;
7667 return (UU_WALK_ERROR);
7668 }
7669
7670 static const char *
7671 import_progress(int st)
7672 {
7673 switch (st) {
7674 case 0:
7675 return (gettext("not reached."));
7676
7677 case IMPORT_PREVIOUS:
7678 return (gettext("previous snapshot taken."));
7679
7680 case IMPORT_PROP_BEGUN:
7681 return (gettext("some properties imported."));
7682
7683 case IMPORT_PROP_DONE:
7684 return (gettext("properties imported."));
7685
7686 case IMPORT_COMPLETE:
7687 return (gettext("imported."));
7688
7689 case IMPORT_REFRESHED:
7690 return (gettext("refresh requested."));
7691
7692 default:
7693 #ifndef NDEBUG
7694 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7695 __FILE__, __LINE__, st);
7696 #endif
7697 abort();
7698 /* NOTREACHED */
7699 }
7700 }
7701
7702 /*
7703 * Returns
7704 * 0 - success
7705 * - fmri wasn't found (error printed)
7706 * - entity was deleted (error printed)
7707 * - backend denied access (error printed)
7708 * ENOMEM - out of memory (error printed)
7709 * ECONNABORTED - repository connection broken (error printed)
7710 * EPERM - permission denied (error printed)
7711 * -1 - unknown libscf error (error printed)
7712 */
7713 static int
7714 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7715 {
7716 scf_error_t serr;
7717 void *ent;
7718 int issvc;
7719 int r;
7720
7721 const char *deleted = gettext("Could not refresh %s (deleted).\n");
7722 const char *dpt_deleted = gettext("Could not refresh %s "
7723 "(dependent \"%s\" of %s) (deleted).\n");
7724
7725 serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7726 switch (serr) {
7727 case SCF_ERROR_NONE:
7728 break;
7729
7730 case SCF_ERROR_NO_MEMORY:
7731 if (name == NULL)
7732 warn(gettext("Could not refresh %s (out of memory).\n"),
7733 fmri);
7734 else
7735 warn(gettext("Could not refresh %s "
7736 "(dependent \"%s\" of %s) (out of memory).\n"),
7737 fmri, name, d_fmri);
7738 return (ENOMEM);
7739
7740 case SCF_ERROR_NOT_FOUND:
7741 if (name == NULL)
7742 warn(deleted, fmri);
7743 else
7744 warn(dpt_deleted, fmri, name, d_fmri);
7745 return (0);
7746
7747 case SCF_ERROR_INVALID_ARGUMENT:
7748 case SCF_ERROR_CONSTRAINT_VIOLATED:
7749 default:
7750 bad_error("fmri_to_entity", serr);
7751 }
7752
7753 r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7754 switch (r) {
7755 case 0:
7756 break;
7757
7758 case ECONNABORTED:
7759 if (name != NULL)
7760 warn(gettext("Could not refresh %s "
7761 "(dependent \"%s\" of %s) "
7762 "(repository connection broken).\n"), fmri, name,
7763 d_fmri);
7764 return (r);
7765
7766 case ECANCELED:
7767 if (name == NULL)
7768 warn(deleted, fmri);
7769 else
7770 warn(dpt_deleted, fmri, name, d_fmri);
7771 return (0);
7772
7773 case EACCES:
7774 if (!g_verbose)
7775 return (0);
7776 if (name == NULL)
7777 warn(gettext("Could not refresh %s "
7778 "(backend access denied).\n"), fmri);
7779 else
7780 warn(gettext("Could not refresh %s "
7781 "(dependent \"%s\" of %s) "
7782 "(backend access denied).\n"), fmri, name, d_fmri);
7783 return (0);
7784
7785 case EPERM:
7786 if (name == NULL)
7787 warn(gettext("Could not refresh %s "
7788 "(permission denied).\n"), fmri);
7789 else
7790 warn(gettext("Could not refresh %s "
7791 "(dependent \"%s\" of %s) "
7792 "(permission denied).\n"), fmri, name, d_fmri);
7793 return (r);
7794
7795 case ENOSPC:
7796 if (name == NULL)
7797 warn(gettext("Could not refresh %s "
7798 "(repository server out of resources).\n"),
7799 fmri);
7800 else
7801 warn(gettext("Could not refresh %s "
7802 "(dependent \"%s\" of %s) "
7803 "(repository server out of resources).\n"),
7804 fmri, name, d_fmri);
7805 return (r);
7806
7807 case -1:
7808 scfwarn();
7809 return (r);
7810
7811 default:
7812 bad_error("refresh_entity", r);
7813 }
7814
7815 if (issvc)
7816 scf_service_destroy(ent);
7817 else
7818 scf_instance_destroy(ent);
7819
7820 return (0);
7821 }
7822
7823 static int
7824 alloc_imp_globals()
7825 {
7826 int r;
7827
7828 const char * const emsg_nomem = gettext("Out of memory.\n");
7829 const char * const emsg_nores =
7830 gettext("svc.configd is out of resources.\n");
7831
7832 imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
7833 max_scf_name_len : max_scf_fmri_len) + 1;
7834
7835 if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
7836 (imp_svc = scf_service_create(g_hndl)) == NULL ||
7837 (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
7838 (imp_inst = scf_instance_create(g_hndl)) == NULL ||
7839 (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
7840 (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
7841 (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
7842 (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
7843 (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
7844 (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
7845 (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
7846 (imp_pg = scf_pg_create(g_hndl)) == NULL ||
7847 (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
7848 (imp_prop = scf_property_create(g_hndl)) == NULL ||
7849 (imp_iter = scf_iter_create(g_hndl)) == NULL ||
7850 (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
7851 (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
7852 (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
7853 (imp_str = malloc(imp_str_sz)) == NULL ||
7854 (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
7855 (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
7856 (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
7857 (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
7858 (ud_inst = scf_instance_create(g_hndl)) == NULL ||
7859 (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
7860 (ud_pg = scf_pg_create(g_hndl)) == NULL ||
7861 (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
7862 (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
7863 (ud_prop = scf_property_create(g_hndl)) == NULL ||
7864 (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
7865 (ud_val = scf_value_create(g_hndl)) == NULL ||
7866 (ud_iter = scf_iter_create(g_hndl)) == NULL ||
7867 (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
7868 (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
7869 (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
7870 (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
7871 (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
7872 if (scf_error() == SCF_ERROR_NO_RESOURCES)
7873 warn(emsg_nores);
7874 else
7875 warn(emsg_nomem);
7876
7877 return (-1);
7878 }
7879
7880 r = load_init();
7881 switch (r) {
7882 case 0:
7883 break;
7884
7885 case ENOMEM:
7886 warn(emsg_nomem);
7887 return (-1);
7888
7889 default:
7890 bad_error("load_init", r);
7891 }
7892
7893 return (0);
7894 }
7895
7896 static void
7897 free_imp_globals()
7898 {
7899 pgroup_t *old_dpt;
7900 void *cookie;
7901
7902 load_fini();
7903
7904 free(ud_ctarg);
7905 free(ud_oldtarg);
7906 free(ud_name);
7907 ud_ctarg = ud_oldtarg = ud_name = NULL;
7908
7909 scf_transaction_destroy(ud_tx);
7910 ud_tx = NULL;
7911 scf_iter_destroy(ud_iter);
7912 scf_iter_destroy(ud_iter2);
7913 ud_iter = ud_iter2 = NULL;
7914 scf_value_destroy(ud_val);
7915 ud_val = NULL;
7916 scf_property_destroy(ud_prop);
7917 scf_property_destroy(ud_dpt_prop);
7918 ud_prop = ud_dpt_prop = NULL;
7919 scf_pg_destroy(ud_pg);
7920 scf_pg_destroy(ud_cur_depts_pg);
7921 scf_pg_destroy(ud_run_dpts_pg);
7922 ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
7923 scf_snaplevel_destroy(ud_snpl);
7924 ud_snpl = NULL;
7925 scf_instance_destroy(ud_inst);
7926 ud_inst = NULL;
7927
7928 free(imp_str);
7929 free(imp_tsname);
7930 free(imp_fe1);
7931 free(imp_fe2);
7932 imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
7933
7934 cookie = NULL;
7935 while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
7936 NULL) {
7937 free((char *)old_dpt->sc_pgroup_name);
7938 free((char *)old_dpt->sc_pgroup_fmri);
7939 internal_pgroup_free(old_dpt);
7940 }
7941 uu_list_destroy(imp_deleted_dpts);
7942
7943 scf_transaction_destroy(imp_tx);
7944 imp_tx = NULL;
7945 scf_iter_destroy(imp_iter);
7946 scf_iter_destroy(imp_rpg_iter);
7947 scf_iter_destroy(imp_up_iter);
7948 imp_iter = imp_rpg_iter = imp_up_iter = NULL;
7949 scf_property_destroy(imp_prop);
7950 imp_prop = NULL;
7951 scf_pg_destroy(imp_pg);
7952 scf_pg_destroy(imp_pg2);
7953 imp_pg = imp_pg2 = NULL;
7954 scf_snaplevel_destroy(imp_snpl);
7955 scf_snaplevel_destroy(imp_rsnpl);
7956 imp_snpl = imp_rsnpl = NULL;
7957 scf_snapshot_destroy(imp_snap);
7958 scf_snapshot_destroy(imp_lisnap);
7959 scf_snapshot_destroy(imp_tlisnap);
7960 scf_snapshot_destroy(imp_rsnap);
7961 imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
7962 scf_instance_destroy(imp_inst);
7963 scf_instance_destroy(imp_tinst);
7964 imp_inst = imp_tinst = NULL;
7965 scf_service_destroy(imp_svc);
7966 scf_service_destroy(imp_tsvc);
7967 imp_svc = imp_tsvc = NULL;
7968 scf_scope_destroy(imp_scope);
7969 imp_scope = NULL;
7970
7971 load_fini();
7972 }
7973
7974 int
7975 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
7976 {
7977 scf_callback_t cbdata;
7978 int result = 0;
7979 entity_t *svc, *inst;
7980 uu_list_t *insts;
7981 int r;
7982 pgroup_t *old_dpt;
7983 int annotation_set = 0;
7984
7985 const char * const emsg_nomem = gettext("Out of memory.\n");
7986 const char * const emsg_nores =
7987 gettext("svc.configd is out of resources.\n");
7988
7989 lscf_prep_hndl();
7990
7991 if (alloc_imp_globals())
7992 goto out;
7993
7994 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
7995 switch (scf_error()) {
7996 case SCF_ERROR_CONNECTION_BROKEN:
7997 warn(gettext("Repository connection broken.\n"));
7998 repository_teardown();
7999 result = -1;
8000 goto out;
8001
8002 case SCF_ERROR_NOT_FOUND:
8003 case SCF_ERROR_INVALID_ARGUMENT:
8004 case SCF_ERROR_NOT_BOUND:
8005 case SCF_ERROR_HANDLE_MISMATCH:
8006 default:
8007 bad_error("scf_handle_get_scope", scf_error());
8008 }
8009 }
8010
8011 /* Set up the auditing annotation. */
8012 if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
8013 annotation_set = 1;
8014 } else {
8015 switch (scf_error()) {
8016 case SCF_ERROR_CONNECTION_BROKEN:
8017 warn(gettext("Repository connection broken.\n"));
8018 repository_teardown();
8019 result = -1;
8020 goto out;
8021
8022 case SCF_ERROR_INVALID_ARGUMENT:
8023 case SCF_ERROR_NOT_BOUND:
8024 case SCF_ERROR_NO_RESOURCES:
8025 case SCF_ERROR_INTERNAL:
8026 bad_error("_scf_set_annotation", scf_error());
8027 /* NOTREACHED */
8028
8029 default:
8030 /*
8031 * Do not terminate import because of inability to
8032 * generate annotation audit event.
8033 */
8034 warn(gettext("_scf_set_annotation() unexpectedly "
8035 "failed with return code of %d\n"), scf_error());
8036 break;
8037 }
8038 }
8039
8040 /*
8041 * Clear the sc_import_state's of all services & instances so we can
8042 * report how far we got if we fail.
8043 */
8044 for (svc = uu_list_first(bndl->sc_bundle_services);
8045 svc != NULL;
8046 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8047 svc->sc_import_state = 0;
8048
8049 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
8050 clear_int, (void *)offsetof(entity_t, sc_import_state),
8051 UU_DEFAULT) != 0)
8052 bad_error("uu_list_walk", uu_error());
8053 }
8054
8055 cbdata.sc_handle = g_hndl;
8056 cbdata.sc_parent = imp_scope;
8057 cbdata.sc_flags = flags;
8058 cbdata.sc_general = NULL;
8059
8060 if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
8061 &cbdata, UU_DEFAULT) == 0) {
8062 /* Success. Refresh everything. */
8063
8064 if (flags & SCI_NOREFRESH || no_refresh) {
8065 no_refresh = 0;
8066 result = 0;
8067 goto out;
8068 }
8069
8070 for (svc = uu_list_first(bndl->sc_bundle_services);
8071 svc != NULL;
8072 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8073 pgroup_t *dpt;
8074
8075 insts = svc->sc_u.sc_service.sc_service_instances;
8076
8077 for (inst = uu_list_first(insts);
8078 inst != NULL;
8079 inst = uu_list_next(insts, inst)) {
8080 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
8081 switch (r) {
8082 case 0:
8083 break;
8084
8085 case ENOMEM:
8086 case ECONNABORTED:
8087 case EPERM:
8088 case -1:
8089 goto progress;
8090
8091 default:
8092 bad_error("imp_refresh_fmri", r);
8093 }
8094
8095 inst->sc_import_state = IMPORT_REFRESHED;
8096
8097 for (dpt = uu_list_first(inst->sc_dependents);
8098 dpt != NULL;
8099 dpt = uu_list_next(inst->sc_dependents,
8100 dpt))
8101 if (imp_refresh_fmri(
8102 dpt->sc_pgroup_fmri,
8103 dpt->sc_pgroup_name,
8104 inst->sc_fmri) != 0)
8105 goto progress;
8106 }
8107
8108 for (dpt = uu_list_first(svc->sc_dependents);
8109 dpt != NULL;
8110 dpt = uu_list_next(svc->sc_dependents, dpt))
8111 if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
8112 dpt->sc_pgroup_name, svc->sc_fmri) != 0)
8113 goto progress;
8114 }
8115
8116 for (old_dpt = uu_list_first(imp_deleted_dpts);
8117 old_dpt != NULL;
8118 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
8119 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8120 old_dpt->sc_pgroup_name,
8121 old_dpt->sc_parent->sc_fmri) != 0)
8122 goto progress;
8123
8124 result = 0;
8125 goto out;
8126 }
8127
8128 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8129 bad_error("uu_list_walk", uu_error());
8130
8131 printerr:
8132 /* If the error hasn't been printed yet, do so here. */
8133 switch (cbdata.sc_err) {
8134 case ECONNABORTED:
8135 warn(gettext("Repository connection broken.\n"));
8136 break;
8137
8138 case ENOMEM:
8139 warn(emsg_nomem);
8140 break;
8141
8142 case ENOSPC:
8143 warn(emsg_nores);
8144 break;
8145
8146 case EROFS:
8147 warn(gettext("Repository is read-only.\n"));
8148 break;
8149
8150 case EACCES:
8151 warn(gettext("Repository backend denied access.\n"));
8152 break;
8153
8154 case EPERM:
8155 case EINVAL:
8156 case EEXIST:
8157 case EBUSY:
8158 case EBADF:
8159 case -1:
8160 break;
8161
8162 default:
8163 bad_error("lscf_service_import", cbdata.sc_err);
8164 }
8165
8166 progress:
8167 warn(gettext("Import of %s failed. Progress:\n"), filename);
8168
8169 for (svc = uu_list_first(bndl->sc_bundle_services);
8170 svc != NULL;
8171 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8172 insts = svc->sc_u.sc_service.sc_service_instances;
8173
8174 warn(gettext(" Service \"%s\": %s\n"), svc->sc_name,
8175 import_progress(svc->sc_import_state));
8176
8177 for (inst = uu_list_first(insts);
8178 inst != NULL;
8179 inst = uu_list_next(insts, inst))
8180 warn(gettext(" Instance \"%s\": %s\n"),
8181 inst->sc_name,
8182 import_progress(inst->sc_import_state));
8183 }
8184
8185 if (cbdata.sc_err == ECONNABORTED)
8186 repository_teardown();
8187
8188
8189 result = -1;
8190
8191 out:
8192 if (annotation_set != 0) {
8193 /* Turn off annotation. It is no longer needed. */
8194 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8195 }
8196
8197 free_imp_globals();
8198
8199 return (result);
8200 }
8201
8202 /*
8203 * _lscf_import_err() summarize the error handling returned by
8204 * lscf_import_{instance | service}_pgs
8205 * Return values are:
8206 * IMPORT_NEXT
8207 * IMPORT_OUT
8208 * IMPORT_BAD
8209 */
8210
8211 #define IMPORT_BAD -1
8212 #define IMPORT_NEXT 0
8213 #define IMPORT_OUT 1
8214
8215 static int
8216 _lscf_import_err(int err, const char *fmri)
8217 {
8218 switch (err) {
8219 case 0:
8220 if (g_verbose)
8221 warn(gettext("%s updated.\n"), fmri);
8222 return (IMPORT_NEXT);
8223
8224 case ECONNABORTED:
8225 warn(gettext("Could not update %s "
8226 "(repository connection broken).\n"), fmri);
8227 return (IMPORT_OUT);
8228
8229 case ENOMEM:
8230 warn(gettext("Could not update %s (out of memory).\n"), fmri);
8231 return (IMPORT_OUT);
8232
8233 case ENOSPC:
8234 warn(gettext("Could not update %s "
8235 "(repository server out of resources).\n"), fmri);
8236 return (IMPORT_OUT);
8237
8238 case ECANCELED:
8239 warn(gettext(
8240 "Could not update %s (deleted).\n"), fmri);
8241 return (IMPORT_NEXT);
8242
8243 case EPERM:
8244 case EINVAL:
8245 case EBUSY:
8246 return (IMPORT_NEXT);
8247
8248 case EROFS:
8249 warn(gettext("Could not update %s (repository read-only).\n"),
8250 fmri);
8251 return (IMPORT_OUT);
8252
8253 case EACCES:
8254 warn(gettext("Could not update %s "
8255 "(backend access denied).\n"), fmri);
8256 return (IMPORT_NEXT);
8257
8258 case EEXIST:
8259 default:
8260 return (IMPORT_BAD);
8261 }
8262
8263 /*NOTREACHED*/
8264 }
8265
8266 /*
8267 * The global imp_svc and imp_inst should be set by the caller in the
8268 * check to make sure the service and instance exist that the apply is
8269 * working on.
8270 */
8271 static int
8272 lscf_dependent_apply(void *dpg, void *e)
8273 {
8274 scf_callback_t cb;
8275 pgroup_t *dpt_pgroup = dpg;
8276 pgroup_t *deldpt;
8277 entity_t *ent = e;
8278 int tissvc;
8279 void *sc_ent, *tent;
8280 scf_error_t serr;
8281 int r;
8282
8283 const char * const dependents = "dependents";
8284 const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT);
8285
8286 if (issvc)
8287 sc_ent = imp_svc;
8288 else
8289 sc_ent = imp_inst;
8290
8291 if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg,
8292 imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 ||
8293 scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name,
8294 imp_prop) != 0) {
8295 switch (scf_error()) {
8296 case SCF_ERROR_NOT_FOUND:
8297 case SCF_ERROR_DELETED:
8298 break;
8299
8300 case SCF_ERROR_CONNECTION_BROKEN:
8301 case SCF_ERROR_NOT_SET:
8302 case SCF_ERROR_INVALID_ARGUMENT:
8303 case SCF_ERROR_HANDLE_MISMATCH:
8304 case SCF_ERROR_NOT_BOUND:
8305 default:
8306 bad_error("entity_get_pg", scf_error());
8307 }
8308 } else {
8309 /*
8310 * Found the dependents/<wip dep> so check to
8311 * see if the service is different. If so
8312 * store the service for later refresh, and
8313 * delete the wip dependency from the service
8314 */
8315 if (scf_property_get_value(imp_prop, ud_val) != 0) {
8316 switch (scf_error()) {
8317 case SCF_ERROR_DELETED:
8318 break;
8319
8320 case SCF_ERROR_CONNECTION_BROKEN:
8321 case SCF_ERROR_NOT_SET:
8322 case SCF_ERROR_INVALID_ARGUMENT:
8323 case SCF_ERROR_HANDLE_MISMATCH:
8324 case SCF_ERROR_NOT_BOUND:
8325 default:
8326 bad_error("scf_property_get_value",
8327 scf_error());
8328 }
8329 }
8330
8331 if (scf_value_get_as_string(ud_val, ud_oldtarg,
8332 max_scf_value_len + 1) < 0)
8333 bad_error("scf_value_get_as_string", scf_error());
8334
8335 r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
8336 switch (r) {
8337 case 1:
8338 break;
8339 case 0:
8340 if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent,
8341 &tissvc)) != SCF_ERROR_NONE) {
8342 if (serr == SCF_ERROR_NOT_FOUND) {
8343 break;
8344 } else {
8345 bad_error("fmri_to_entity", serr);
8346 }
8347 }
8348
8349 if (entity_get_pg(tent, tissvc,
8350 dpt_pgroup->sc_pgroup_name, imp_pg) != 0) {
8351 serr = scf_error();
8352 if (serr == SCF_ERROR_NOT_FOUND ||
8353 serr == SCF_ERROR_DELETED) {
8354 break;
8355 } else {
8356 bad_error("entity_get_pg", scf_error());
8357 }
8358 }
8359
8360 if (scf_pg_delete(imp_pg) != 0) {
8361 serr = scf_error();
8362 if (serr == SCF_ERROR_NOT_FOUND ||
8363 serr == SCF_ERROR_DELETED) {
8364 break;
8365 } else {
8366 bad_error("scf_pg_delete", scf_error());
8367 }
8368 }
8369
8370 deldpt = internal_pgroup_new();
8371 if (deldpt == NULL)
8372 return (ENOMEM);
8373 deldpt->sc_pgroup_name =
8374 strdup(dpt_pgroup->sc_pgroup_name);
8375 deldpt->sc_pgroup_fmri = strdup(ud_oldtarg);
8376 if (deldpt->sc_pgroup_name == NULL ||
8377 deldpt->sc_pgroup_fmri == NULL)
8378 return (ENOMEM);
8379 deldpt->sc_parent = (entity_t *)ent;
8380 if (uu_list_insert_after(imp_deleted_dpts, NULL,
8381 deldpt) != 0)
8382 uu_die(gettext("libuutil error: %s\n"),
8383 uu_strerror(uu_error()));
8384
8385 break;
8386 default:
8387 bad_error("fmri_equal", r);
8388 }
8389 }
8390
8391 cb.sc_handle = g_hndl;
8392 cb.sc_parent = ent;
8393 cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT;
8394 cb.sc_source_fmri = ent->sc_fmri;
8395 cb.sc_target_fmri = ent->sc_fmri;
8396 cb.sc_trans = NULL;
8397 cb.sc_flags = SCI_FORCE;
8398
8399 if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT)
8400 return (UU_WALK_ERROR);
8401
8402 r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL);
8403 switch (r) {
8404 case 0:
8405 break;
8406
8407 case ENOMEM:
8408 case ECONNABORTED:
8409 case EPERM:
8410 case -1:
8411 warn(gettext("Unable to refresh \"%s\"\n"),
8412 dpt_pgroup->sc_pgroup_fmri);
8413 return (UU_WALK_ERROR);
8414
8415 default:
8416 bad_error("imp_refresh_fmri", r);
8417 }
8418
8419 return (UU_WALK_NEXT);
8420 }
8421
8422 /*
8423 * Returns
8424 * 0 - success
8425 * -1 - lscf_import_instance_pgs() failed.
8426 */
8427 int
8428 lscf_bundle_apply(bundle_t *bndl, const char *file)
8429 {
8430 pgroup_t *old_dpt;
8431 entity_t *svc, *inst;
8432 int annotation_set = 0;
8433 int ret = 0;
8434 int r = 0;
8435
8436 lscf_prep_hndl();
8437
8438 if ((ret = alloc_imp_globals()))
8439 goto out;
8440
8441 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0)
8442 scfdie();
8443
8444 /*
8445 * Set the strings to be used for the security audit annotation
8446 * event.
8447 */
8448 if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
8449 annotation_set = 1;
8450 } else {
8451 switch (scf_error()) {
8452 case SCF_ERROR_CONNECTION_BROKEN:
8453 warn(gettext("Repository connection broken.\n"));
8454 goto out;
8455
8456 case SCF_ERROR_INVALID_ARGUMENT:
8457 case SCF_ERROR_NOT_BOUND:
8458 case SCF_ERROR_NO_RESOURCES:
8459 case SCF_ERROR_INTERNAL:
8460 bad_error("_scf_set_annotation", scf_error());
8461 /* NOTREACHED */
8462
8463 default:
8464 /*
8465 * Do not abort apply operation because of
8466 * inability to create annotation audit event.
8467 */
8468 warn(gettext("_scf_set_annotation() unexpectedly "
8469 "failed with return code of %d\n"), scf_error());
8470 break;
8471 }
8472 }
8473
8474 for (svc = uu_list_first(bndl->sc_bundle_services);
8475 svc != NULL;
8476 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8477 int refresh = 0;
8478
8479 if (scf_scope_get_service(imp_scope, svc->sc_name,
8480 imp_svc) != 0) {
8481 switch (scf_error()) {
8482 case SCF_ERROR_NOT_FOUND:
8483 if (g_verbose)
8484 warn(gettext("Ignoring nonexistent "
8485 "service %s.\n"), svc->sc_name);
8486 continue;
8487
8488 default:
8489 scfdie();
8490 }
8491 }
8492
8493 /*
8494 * If there were missing types in the profile, then need to
8495 * attempt to find the types.
8496 */
8497 if (svc->sc_miss_type) {
8498 if (uu_list_numnodes(svc->sc_pgroups) &&
8499 uu_list_walk(svc->sc_pgroups, find_current_pg_type,
8500 svc, UU_DEFAULT) != 0) {
8501 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8502 bad_error("uu_list_walk", uu_error());
8503
8504 ret = -1;
8505 continue;
8506 }
8507
8508 for (inst = uu_list_first(
8509 svc->sc_u.sc_service.sc_service_instances);
8510 inst != NULL;
8511 inst = uu_list_next(
8512 svc->sc_u.sc_service.sc_service_instances, inst)) {
8513 /*
8514 * If the instance doesn't exist just
8515 * skip to the next instance and let the
8516 * import note the missing instance.
8517 */
8518 if (scf_service_get_instance(imp_svc,
8519 inst->sc_name, imp_inst) != 0)
8520 continue;
8521
8522 if (uu_list_walk(inst->sc_pgroups,
8523 find_current_pg_type, inst,
8524 UU_DEFAULT) != 0) {
8525 if (uu_error() !=
8526 UU_ERROR_CALLBACK_FAILED)
8527 bad_error("uu_list_walk",
8528 uu_error());
8529
8530 ret = -1;
8531 inst->sc_miss_type = B_TRUE;
8532 }
8533 }
8534 }
8535
8536 /*
8537 * if we have pgs in the profile, we need to refresh ALL
8538 * instances of the service
8539 */
8540 if (uu_list_numnodes(svc->sc_pgroups) != 0) {
8541 refresh = 1;
8542 r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc,
8543 SCI_FORCE | SCI_KEEP);
8544 switch (_lscf_import_err(r, svc->sc_fmri)) {
8545 case IMPORT_NEXT:
8546 break;
8547
8548 case IMPORT_OUT:
8549 goto out;
8550
8551 case IMPORT_BAD:
8552 default:
8553 bad_error("lscf_import_service_pgs", r);
8554 }
8555 }
8556
8557 if (uu_list_numnodes(svc->sc_dependents) != 0) {
8558 uu_list_walk(svc->sc_dependents,
8559 lscf_dependent_apply, svc, UU_DEFAULT);
8560 }
8561
8562 for (inst = uu_list_first(
8563 svc->sc_u.sc_service.sc_service_instances);
8564 inst != NULL;
8565 inst = uu_list_next(
8566 svc->sc_u.sc_service.sc_service_instances, inst)) {
8567 /*
8568 * This instance still has missing types
8569 * so skip it.
8570 */
8571 if (inst->sc_miss_type) {
8572 if (g_verbose)
8573 warn(gettext("Ignoring instance "
8574 "%s:%s with missing types\n"),
8575 inst->sc_parent->sc_name,
8576 inst->sc_name);
8577
8578 continue;
8579 }
8580
8581 if (scf_service_get_instance(imp_svc, inst->sc_name,
8582 imp_inst) != 0) {
8583 switch (scf_error()) {
8584 case SCF_ERROR_NOT_FOUND:
8585 if (g_verbose)
8586 warn(gettext("Ignoring "
8587 "nonexistant instance "
8588 "%s:%s.\n"),
8589 inst->sc_parent->sc_name,
8590 inst->sc_name);
8591 continue;
8592
8593 default:
8594 scfdie();
8595 }
8596 }
8597
8598 /*
8599 * If the instance does not have a general/enabled
8600 * property and no last-import snapshot then the
8601 * instance is not a fully installed instance and
8602 * should not have a profile applied to it.
8603 *
8604 * This could happen if a service/instance declares
8605 * a dependent on behalf of another service/instance.
8606 *
8607 */
8608 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
8609 imp_snap) != 0) {
8610 if (scf_instance_get_pg(imp_inst,
8611 SCF_PG_GENERAL, imp_pg) != 0 ||
8612 scf_pg_get_property(imp_pg,
8613 SCF_PROPERTY_ENABLED, imp_prop) != 0) {
8614 if (g_verbose)
8615 warn(gettext("Ignoreing "
8616 "partial instance "
8617 "%s:%s.\n"),
8618 inst->sc_parent->sc_name,
8619 inst->sc_name);
8620 continue;
8621 }
8622 }
8623
8624 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri,
8625 inst, SCI_FORCE | SCI_KEEP);
8626 switch (_lscf_import_err(r, inst->sc_fmri)) {
8627 case IMPORT_NEXT:
8628 break;
8629
8630 case IMPORT_OUT:
8631 goto out;
8632
8633 case IMPORT_BAD:
8634 default:
8635 bad_error("lscf_import_instance_pgs", r);
8636 }
8637
8638 if (uu_list_numnodes(inst->sc_dependents) != 0) {
8639 uu_list_walk(inst->sc_dependents,
8640 lscf_dependent_apply, inst, UU_DEFAULT);
8641 }
8642
8643 /* refresh only if there is no pgs in the service */
8644 if (refresh == 0)
8645 (void) refresh_entity(0, imp_inst,
8646 inst->sc_fmri, NULL, NULL, NULL);
8647 }
8648
8649 if (refresh == 1) {
8650 char *name_buf = safe_malloc(max_scf_name_len + 1);
8651
8652 (void) refresh_entity(1, imp_svc, svc->sc_name,
8653 imp_inst, imp_iter, name_buf);
8654 free(name_buf);
8655 }
8656
8657 for (old_dpt = uu_list_first(imp_deleted_dpts);
8658 old_dpt != NULL;
8659 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) {
8660 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8661 old_dpt->sc_pgroup_name,
8662 old_dpt->sc_parent->sc_fmri) != 0) {
8663 warn(gettext("Unable to refresh \"%s\"\n"),
8664 old_dpt->sc_pgroup_fmri);
8665 }
8666 }
8667 }
8668
8669 out:
8670 if (annotation_set) {
8671 /* Remove security audit annotation strings. */
8672 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8673 }
8674
8675 free_imp_globals();
8676 return (ret);
8677 }
8678
8679
8680 /*
8681 * Export. These functions create and output an XML tree of a service
8682 * description from the repository. This is largely the inverse of
8683 * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
8684 *
8685 * - We must include any properties which are not represented specifically by
8686 * a service manifest, e.g., properties created by an admin post-import. To
8687 * do so we'll iterate through all properties and deal with each
8688 * apropriately.
8689 *
8690 * - Children of services and instances must must be in the order set by the
8691 * DTD, but we iterate over the properties in undefined order. The elements
8692 * are not easily (or efficiently) sortable by name. Since there's a fixed
8693 * number of classes of them, however, we'll keep the classes separate and
8694 * assemble them in order.
8695 */
8696
8697 /*
8698 * Convenience function to handle xmlSetProp errors (and type casting).
8699 */
8700 static void
8701 safe_setprop(xmlNodePtr n, const char *name, const char *val)
8702 {
8703 if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
8704 uu_die(gettext("Could not set XML property.\n"));
8705 }
8706
8707 /*
8708 * Convenience function to set an XML attribute to the single value of an
8709 * astring property. If the value happens to be the default, don't set the
8710 * attribute. "dval" should be the default value supplied by the DTD, or
8711 * NULL for no default.
8712 */
8713 static int
8714 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
8715 const char *name, const char *dval)
8716 {
8717 scf_value_t *val;
8718 ssize_t len;
8719 char *str;
8720
8721 val = scf_value_create(g_hndl);
8722 if (val == NULL)
8723 scfdie();
8724
8725 if (prop_get_val(prop, val) != 0) {
8726 scf_value_destroy(val);
8727 return (-1);
8728 }
8729
8730 len = scf_value_get_as_string(val, NULL, 0);
8731 if (len < 0)
8732 scfdie();
8733
8734 str = safe_malloc(len + 1);
8735
8736 if (scf_value_get_as_string(val, str, len + 1) < 0)
8737 scfdie();
8738
8739 scf_value_destroy(val);
8740
8741 if (dval == NULL || strcmp(str, dval) != 0)
8742 safe_setprop(n, name, str);
8743
8744 free(str);
8745
8746 return (0);
8747 }
8748
8749 /*
8750 * As above, but the attribute is always set.
8751 */
8752 static int
8753 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
8754 {
8755 return (set_attr_from_prop_default(prop, n, name, NULL));
8756 }
8757
8758 /*
8759 * Dump the given document onto f, with "'s replaced by ''s.
8760 */
8761 static int
8762 write_service_bundle(xmlDocPtr doc, FILE *f)
8763 {
8764 xmlChar *mem;
8765 int sz, i;
8766
8767 mem = NULL;
8768 xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
8769
8770 if (mem == NULL) {
8771 semerr(gettext("Could not dump XML tree.\n"));
8772 return (-1);
8773 }
8774
8775 /*
8776 * Fortunately libxml produces " instead of ", so we can blindly
8777 * replace all " with '. Cursed libxml2! Why must you #ifdef out the
8778 * ' code?!
8779 */
8780 for (i = 0; i < sz; ++i) {
8781 char c = (char)mem[i];
8782
8783 if (c == '"')
8784 (void) fputc('\'', f);
8785 else if (c == '\'')
8786 (void) fwrite("'", sizeof ("'") - 1, 1, f);
8787 else
8788 (void) fputc(c, f);
8789 }
8790
8791 return (0);
8792 }
8793
8794 /*
8795 * Create the DOM elements in elts necessary to (generically) represent prop
8796 * (i.e., a property or propval element). If the name of the property is
8797 * known, it should be passed as name_arg. Otherwise, pass NULL.
8798 */
8799 static void
8800 export_property(scf_property_t *prop, const char *name_arg,
8801 struct pg_elts *elts, int flags)
8802 {
8803 const char *type;
8804 scf_error_t err = 0;
8805 xmlNodePtr pnode, lnode;
8806 char *lnname;
8807 int ret;
8808
8809 /* name */
8810 if (name_arg != NULL) {
8811 (void) strcpy(exp_str, name_arg);
8812 } else {
8813 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
8814 scfdie();
8815 }
8816
8817 /* type */
8818 type = prop_to_typestr(prop);
8819 if (type == NULL)
8820 uu_die(gettext("Can't export property %s: unknown type.\n"),
8821 exp_str);
8822
8823 /* If we're exporting values, and there's just one, export it here. */
8824 if (!(flags & SCE_ALL_VALUES))
8825 goto empty;
8826
8827 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
8828 xmlNodePtr n;
8829
8830 /* Single value, so use propval */
8831 n = xmlNewNode(NULL, (xmlChar *)"propval");
8832 if (n == NULL)
8833 uu_die(emsg_create_xml);
8834
8835 safe_setprop(n, name_attr, exp_str);
8836 safe_setprop(n, type_attr, type);
8837
8838 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
8839 scfdie();
8840 safe_setprop(n, value_attr, exp_str);
8841
8842 if (elts->propvals == NULL)
8843 elts->propvals = n;
8844 else
8845 (void) xmlAddSibling(elts->propvals, n);
8846
8847 return;
8848 }
8849
8850 err = scf_error();
8851
8852 if (err == SCF_ERROR_PERMISSION_DENIED) {
8853 semerr(emsg_permission_denied);
8854 return;
8855 }
8856
8857 if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
8858 err != SCF_ERROR_NOT_FOUND &&
8859 err != SCF_ERROR_PERMISSION_DENIED)
8860 scfdie();
8861
8862 empty:
8863 /* Multiple (or no) values, so use property */
8864 pnode = xmlNewNode(NULL, (xmlChar *)"property");
8865 if (pnode == NULL)
8866 uu_die(emsg_create_xml);
8867
8868 safe_setprop(pnode, name_attr, exp_str);
8869 safe_setprop(pnode, type_attr, type);
8870
8871 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
8872 lnname = uu_msprintf("%s_list", type);
8873 if (lnname == NULL)
8874 uu_die(gettext("Could not create string"));
8875
8876 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
8877 if (lnode == NULL)
8878 uu_die(emsg_create_xml);
8879
8880 uu_free(lnname);
8881
8882 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
8883 scfdie();
8884
8885 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
8886 1) {
8887 xmlNodePtr vn;
8888
8889 vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
8890 NULL);
8891 if (vn == NULL)
8892 uu_die(emsg_create_xml);
8893
8894 if (scf_value_get_as_string(exp_val, exp_str,
8895 exp_str_sz) < 0)
8896 scfdie();
8897 safe_setprop(vn, value_attr, exp_str);
8898 }
8899 if (ret != 0)
8900 scfdie();
8901 }
8902
8903 if (elts->properties == NULL)
8904 elts->properties = pnode;
8905 else
8906 (void) xmlAddSibling(elts->properties, pnode);
8907 }
8908
8909 /*
8910 * Add a property_group element for this property group to elts.
8911 */
8912 static void
8913 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
8914 {
8915 xmlNodePtr n;
8916 struct pg_elts elts;
8917 int ret;
8918 boolean_t read_protected;
8919
8920 n = xmlNewNode(NULL, (xmlChar *)"property_group");
8921
8922 /* name */
8923 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
8924 scfdie();
8925 safe_setprop(n, name_attr, exp_str);
8926
8927 /* type */
8928 if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
8929 scfdie();
8930 safe_setprop(n, type_attr, exp_str);
8931
8932 /* properties */
8933 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8934 scfdie();
8935
8936 (void) memset(&elts, 0, sizeof (elts));
8937
8938 /*
8939 * If this property group is not read protected, we always want to
8940 * output all the values. Otherwise, we only output the values if the
8941 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
8942 */
8943 if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
8944 scfdie();
8945
8946 if (!read_protected)
8947 flags |= SCE_ALL_VALUES;
8948
8949 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8950 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8951 scfdie();
8952
8953 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8954 xmlNodePtr m;
8955
8956 m = xmlNewNode(NULL, (xmlChar *)"stability");
8957 if (m == NULL)
8958 uu_die(emsg_create_xml);
8959
8960 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
8961 elts.stability = m;
8962 continue;
8963 }
8964
8965 xmlFreeNode(m);
8966 }
8967
8968 export_property(exp_prop, NULL, &elts, flags);
8969 }
8970 if (ret == -1)
8971 scfdie();
8972
8973 (void) xmlAddChild(n, elts.stability);
8974 (void) xmlAddChildList(n, elts.propvals);
8975 (void) xmlAddChildList(n, elts.properties);
8976
8977 if (eelts->property_groups == NULL)
8978 eelts->property_groups = n;
8979 else
8980 (void) xmlAddSibling(eelts->property_groups, n);
8981 }
8982
8983 /*
8984 * Create an XML node representing the dependency described by the given
8985 * property group and put it in eelts. Unless the dependency is not valid, in
8986 * which case create a generic property_group element which represents it and
8987 * put it in eelts.
8988 */
8989 static void
8990 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
8991 {
8992 xmlNodePtr n;
8993 int err = 0, ret;
8994 struct pg_elts elts;
8995
8996 n = xmlNewNode(NULL, (xmlChar *)"dependency");
8997 if (n == NULL)
8998 uu_die(emsg_create_xml);
8999
9000 /*
9001 * If the external flag is present, skip this dependency because it
9002 * should have been created by another manifest.
9003 */
9004 if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
9005 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9006 prop_get_val(exp_prop, exp_val) == 0) {
9007 uint8_t b;
9008
9009 if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
9010 scfdie();
9011
9012 if (b)
9013 return;
9014 }
9015 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
9016 scfdie();
9017
9018 /* Get the required attributes. */
9019
9020 /* name */
9021 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9022 scfdie();
9023 safe_setprop(n, name_attr, exp_str);
9024
9025 /* grouping */
9026 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9027 set_attr_from_prop(exp_prop, n, "grouping") != 0)
9028 err = 1;
9029
9030 /* restart_on */
9031 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9032 set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9033 err = 1;
9034
9035 /* type */
9036 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9037 set_attr_from_prop(exp_prop, n, type_attr) != 0)
9038 err = 1;
9039
9040 /*
9041 * entities: Not required, but if we create no children, it will be
9042 * created as empty on import, so fail if it's missing.
9043 */
9044 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9045 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
9046 scf_iter_t *eiter;
9047 int ret2;
9048
9049 eiter = scf_iter_create(g_hndl);
9050 if (eiter == NULL)
9051 scfdie();
9052
9053 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
9054 scfdie();
9055
9056 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
9057 xmlNodePtr ch;
9058
9059 if (scf_value_get_astring(exp_val, exp_str,
9060 exp_str_sz) < 0)
9061 scfdie();
9062
9063 /*
9064 * service_fmri's must be first, so we can add them
9065 * here.
9066 */
9067 ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
9068 NULL);
9069 if (ch == NULL)
9070 uu_die(emsg_create_xml);
9071
9072 safe_setprop(ch, value_attr, exp_str);
9073 }
9074 if (ret2 == -1)
9075 scfdie();
9076
9077 scf_iter_destroy(eiter);
9078 } else
9079 err = 1;
9080
9081 if (err) {
9082 xmlFreeNode(n);
9083
9084 export_pg(pg, eelts, 0);
9085
9086 return;
9087 }
9088
9089 /* Iterate through the properties & handle each. */
9090 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9091 scfdie();
9092
9093 (void) memset(&elts, 0, sizeof (elts));
9094
9095 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9096 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9097 scfdie();
9098
9099 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9100 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9101 strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9102 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9103 continue;
9104 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9105 xmlNodePtr m;
9106
9107 m = xmlNewNode(NULL, (xmlChar *)"stability");
9108 if (m == NULL)
9109 uu_die(emsg_create_xml);
9110
9111 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9112 elts.stability = m;
9113 continue;
9114 }
9115
9116 xmlFreeNode(m);
9117 }
9118
9119 export_property(exp_prop, exp_str, &elts, 0);
9120 }
9121 if (ret == -1)
9122 scfdie();
9123
9124 (void) xmlAddChild(n, elts.stability);
9125 (void) xmlAddChildList(n, elts.propvals);
9126 (void) xmlAddChildList(n, elts.properties);
9127
9128 if (eelts->dependencies == NULL)
9129 eelts->dependencies = n;
9130 else
9131 (void) xmlAddSibling(eelts->dependencies, n);
9132 }
9133
9134 static xmlNodePtr
9135 export_method_environment(scf_propertygroup_t *pg)
9136 {
9137 xmlNodePtr env;
9138 int ret;
9139 int children = 0;
9140
9141 if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
9142 return (NULL);
9143
9144 env = xmlNewNode(NULL, (xmlChar *)"method_environment");
9145 if (env == NULL)
9146 uu_die(emsg_create_xml);
9147
9148 if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
9149 scfdie();
9150
9151 if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
9152 scfdie();
9153
9154 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
9155 xmlNodePtr ev;
9156 char *cp;
9157
9158 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9159 scfdie();
9160
9161 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
9162 warn(gettext("Invalid environment variable \"%s\".\n"),
9163 exp_str);
9164 continue;
9165 } else if (strncmp(exp_str, "SMF_", 4) == 0) {
9166 warn(gettext("Invalid environment variable \"%s\"; "
9167 "\"SMF_\" prefix is reserved.\n"), exp_str);
9168 continue;
9169 }
9170
9171 *cp = '\0';
9172 cp++;
9173
9174 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
9175 if (ev == NULL)
9176 uu_die(emsg_create_xml);
9177
9178 safe_setprop(ev, name_attr, exp_str);
9179 safe_setprop(ev, value_attr, cp);
9180 children++;
9181 }
9182
9183 if (ret != 0)
9184 scfdie();
9185
9186 if (children == 0) {
9187 xmlFreeNode(env);
9188 return (NULL);
9189 }
9190
9191 return (env);
9192 }
9193
9194 /*
9195 * As above, but for a method property group.
9196 */
9197 static void
9198 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
9199 {
9200 xmlNodePtr n, env;
9201 char *str;
9202 int err = 0, nonenv, ret;
9203 uint8_t use_profile;
9204 struct pg_elts elts;
9205 xmlNodePtr ctxt = NULL;
9206
9207 n = xmlNewNode(NULL, (xmlChar *)"exec_method");
9208
9209 /* Get the required attributes. */
9210
9211 /* name */
9212 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9213 scfdie();
9214 safe_setprop(n, name_attr, exp_str);
9215
9216 /* type */
9217 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9218 set_attr_from_prop(exp_prop, n, type_attr) != 0)
9219 err = 1;
9220
9221 /* exec */
9222 if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
9223 set_attr_from_prop(exp_prop, n, "exec") != 0)
9224 err = 1;
9225
9226 /* timeout */
9227 if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
9228 prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
9229 prop_get_val(exp_prop, exp_val) == 0) {
9230 uint64_t c;
9231
9232 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
9233 scfdie();
9234
9235 str = uu_msprintf("%llu", c);
9236 if (str == NULL)
9237 uu_die(gettext("Could not create string"));
9238
9239 safe_setprop(n, "timeout_seconds", str);
9240 free(str);
9241 } else
9242 err = 1;
9243
9244 if (err) {
9245 xmlFreeNode(n);
9246
9247 export_pg(pg, eelts, 0);
9248
9249 return;
9250 }
9251
9252
9253 /*
9254 * If we're going to have a method_context child, we need to know
9255 * before we iterate through the properties. Since method_context's
9256 * are optional, we don't want to complain about any properties
9257 * missing if none of them are there. Thus we can't use the
9258 * convenience functions.
9259 */
9260 nonenv =
9261 scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
9262 SCF_SUCCESS ||
9263 scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
9264 SCF_SUCCESS ||
9265 scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
9266 SCF_SUCCESS ||
9267 scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
9268 SCF_SUCCESS;
9269
9270 if (nonenv) {
9271 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9272 if (ctxt == NULL)
9273 uu_die(emsg_create_xml);
9274
9275 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
9276 0 &&
9277 set_attr_from_prop_default(exp_prop, ctxt,
9278 "working_directory", ":default") != 0)
9279 err = 1;
9280
9281 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
9282 set_attr_from_prop_default(exp_prop, ctxt, "project",
9283 ":default") != 0)
9284 err = 1;
9285
9286 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
9287 0 &&
9288 set_attr_from_prop_default(exp_prop, ctxt,
9289 "resource_pool", ":default") != 0)
9290 err = 1;
9291 /*
9292 * We only want to complain about profile or credential
9293 * properties if we will use them. To determine that we must
9294 * examine USE_PROFILE.
9295 */
9296 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9297 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9298 prop_get_val(exp_prop, exp_val) == 0) {
9299 if (scf_value_get_boolean(exp_val, &use_profile) !=
9300 SCF_SUCCESS) {
9301 scfdie();
9302 }
9303
9304 if (use_profile) {
9305 xmlNodePtr prof;
9306
9307 prof = xmlNewChild(ctxt, NULL,
9308 (xmlChar *)"method_profile", NULL);
9309 if (prof == NULL)
9310 uu_die(emsg_create_xml);
9311
9312 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
9313 exp_prop) != 0 ||
9314 set_attr_from_prop(exp_prop, prof,
9315 name_attr) != 0)
9316 err = 1;
9317 } else {
9318 xmlNodePtr cred;
9319
9320 cred = xmlNewChild(ctxt, NULL,
9321 (xmlChar *)"method_credential", NULL);
9322 if (cred == NULL)
9323 uu_die(emsg_create_xml);
9324
9325 if (pg_get_prop(pg, SCF_PROPERTY_USER,
9326 exp_prop) != 0 ||
9327 set_attr_from_prop(exp_prop, cred,
9328 "user") != 0) {
9329 err = 1;
9330 }
9331
9332 if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
9333 exp_prop) == 0 &&
9334 set_attr_from_prop_default(exp_prop, cred,
9335 "group", ":default") != 0)
9336 err = 1;
9337
9338 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
9339 exp_prop) == 0 &&
9340 set_attr_from_prop_default(exp_prop, cred,
9341 "supp_groups", ":default") != 0)
9342 err = 1;
9343
9344 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
9345 exp_prop) == 0 &&
9346 set_attr_from_prop_default(exp_prop, cred,
9347 "privileges", ":default") != 0)
9348 err = 1;
9349
9350 if (pg_get_prop(pg,
9351 SCF_PROPERTY_LIMIT_PRIVILEGES,
9352 exp_prop) == 0 &&
9353 set_attr_from_prop_default(exp_prop, cred,
9354 "limit_privileges", ":default") != 0)
9355 err = 1;
9356 }
9357 }
9358 }
9359
9360 if ((env = export_method_environment(pg)) != NULL) {
9361 if (ctxt == NULL) {
9362 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9363 if (ctxt == NULL)
9364 uu_die(emsg_create_xml);
9365 }
9366 (void) xmlAddChild(ctxt, env);
9367 }
9368
9369 if (env != NULL || (nonenv && err == 0))
9370 (void) xmlAddChild(n, ctxt);
9371 else
9372 xmlFreeNode(ctxt);
9373
9374 nonenv = (err == 0);
9375
9376 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9377 scfdie();
9378
9379 (void) memset(&elts, 0, sizeof (elts));
9380
9381 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9382 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9383 scfdie();
9384
9385 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9386 strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
9387 strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
9388 continue;
9389 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9390 xmlNodePtr m;
9391
9392 m = xmlNewNode(NULL, (xmlChar *)"stability");
9393 if (m == NULL)
9394 uu_die(emsg_create_xml);
9395
9396 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9397 elts.stability = m;
9398 continue;
9399 }
9400
9401 xmlFreeNode(m);
9402 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
9403 0 ||
9404 strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
9405 strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
9406 strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9407 if (nonenv)
9408 continue;
9409 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
9410 strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
9411 strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
9412 strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
9413 strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) {
9414 if (nonenv && !use_profile)
9415 continue;
9416 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9417 if (nonenv && use_profile)
9418 continue;
9419 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
9420 if (env != NULL)
9421 continue;
9422 }
9423
9424 export_property(exp_prop, exp_str, &elts, 0);
9425 }
9426 if (ret == -1)
9427 scfdie();
9428
9429 (void) xmlAddChild(n, elts.stability);
9430 (void) xmlAddChildList(n, elts.propvals);
9431 (void) xmlAddChildList(n, elts.properties);
9432
9433 if (eelts->exec_methods == NULL)
9434 eelts->exec_methods = n;
9435 else
9436 (void) xmlAddSibling(eelts->exec_methods, n);
9437 }
9438
9439 static void
9440 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
9441 struct entity_elts *eelts)
9442 {
9443 xmlNodePtr pgnode;
9444
9445 pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
9446 if (pgnode == NULL)
9447 uu_die(emsg_create_xml);
9448
9449 safe_setprop(pgnode, name_attr, name);
9450 safe_setprop(pgnode, type_attr, type);
9451
9452 (void) xmlAddChildList(pgnode, elts->propvals);
9453 (void) xmlAddChildList(pgnode, elts->properties);
9454
9455 if (eelts->property_groups == NULL)
9456 eelts->property_groups = pgnode;
9457 else
9458 (void) xmlAddSibling(eelts->property_groups, pgnode);
9459 }
9460
9461 /*
9462 * Process the general property group for a service. This is the one with the
9463 * goodies.
9464 */
9465 static void
9466 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
9467 {
9468 struct pg_elts elts;
9469 int ret;
9470
9471 /*
9472 * In case there are properties which don't correspond to child
9473 * entities of the service entity, we'll set up a pg_elts structure to
9474 * put them in.
9475 */
9476 (void) memset(&elts, 0, sizeof (elts));
9477
9478 /* Walk the properties, looking for special ones. */
9479 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9480 scfdie();
9481
9482 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9483 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9484 scfdie();
9485
9486 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
9487 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9488 prop_get_val(exp_prop, exp_val) == 0) {
9489 uint8_t b;
9490
9491 if (scf_value_get_boolean(exp_val, &b) !=
9492 SCF_SUCCESS)
9493 scfdie();
9494
9495 if (b) {
9496 selts->single_instance =
9497 xmlNewNode(NULL,
9498 (xmlChar *)"single_instance");
9499 if (selts->single_instance == NULL)
9500 uu_die(emsg_create_xml);
9501 }
9502
9503 continue;
9504 }
9505 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9506 xmlNodePtr rnode, sfnode;
9507
9508 rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9509 if (rnode == NULL)
9510 uu_die(emsg_create_xml);
9511
9512 sfnode = xmlNewChild(rnode, NULL,
9513 (xmlChar *)"service_fmri", NULL);
9514 if (sfnode == NULL)
9515 uu_die(emsg_create_xml);
9516
9517 if (set_attr_from_prop(exp_prop, sfnode,
9518 value_attr) == 0) {
9519 selts->restarter = rnode;
9520 continue;
9521 }
9522
9523 xmlFreeNode(rnode);
9524 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
9525 0) {
9526 xmlNodePtr s;
9527
9528 s = xmlNewNode(NULL, (xmlChar *)"stability");
9529 if (s == NULL)
9530 uu_die(emsg_create_xml);
9531
9532 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9533 selts->stability = s;
9534 continue;
9535 }
9536
9537 xmlFreeNode(s);
9538 }
9539
9540 export_property(exp_prop, exp_str, &elts, 0);
9541 }
9542 if (ret == -1)
9543 scfdie();
9544
9545 if (elts.propvals != NULL || elts.properties != NULL)
9546 export_pg_elts(&elts, scf_pg_general, scf_group_framework,
9547 selts);
9548 }
9549
9550 static void
9551 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
9552 {
9553 xmlNodePtr n, prof, cred, env;
9554 uint8_t use_profile;
9555 int ret, err = 0;
9556
9557 n = xmlNewNode(NULL, (xmlChar *)"method_context");
9558
9559 env = export_method_environment(pg);
9560
9561 /* Need to know whether we'll use a profile or not. */
9562 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9563 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9564 prop_get_val(exp_prop, exp_val) == 0) {
9565 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
9566 scfdie();
9567
9568 if (use_profile)
9569 prof =
9570 xmlNewChild(n, NULL, (xmlChar *)"method_profile",
9571 NULL);
9572 else
9573 cred =
9574 xmlNewChild(n, NULL, (xmlChar *)"method_credential",
9575 NULL);
9576 }
9577
9578 if (env != NULL)
9579 (void) xmlAddChild(n, env);
9580
9581 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9582 scfdie();
9583
9584 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9585 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9586 scfdie();
9587
9588 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
9589 if (set_attr_from_prop(exp_prop, n,
9590 "working_directory") != 0)
9591 err = 1;
9592 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
9593 if (set_attr_from_prop(exp_prop, n, "project") != 0)
9594 err = 1;
9595 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
9596 if (set_attr_from_prop(exp_prop, n,
9597 "resource_pool") != 0)
9598 err = 1;
9599 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9600 /* EMPTY */
9601 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
9602 if (use_profile ||
9603 set_attr_from_prop(exp_prop, cred, "user") != 0)
9604 err = 1;
9605 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
9606 if (use_profile ||
9607 set_attr_from_prop(exp_prop, cred, "group") != 0)
9608 err = 1;
9609 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
9610 if (use_profile || set_attr_from_prop(exp_prop, cred,
9611 "supp_groups") != 0)
9612 err = 1;
9613 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
9614 if (use_profile || set_attr_from_prop(exp_prop, cred,
9615 "privileges") != 0)
9616 err = 1;
9617 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
9618 0) {
9619 if (use_profile || set_attr_from_prop(exp_prop, cred,
9620 "limit_privileges") != 0)
9621 err = 1;
9622 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9623 if (!use_profile || set_attr_from_prop(exp_prop,
9624 prof, name_attr) != 0)
9625 err = 1;
9626 } else {
9627 /* Can't have generic properties in method_context's */
9628 err = 1;
9629 }
9630 }
9631 if (ret == -1)
9632 scfdie();
9633
9634 if (err && env == NULL) {
9635 xmlFreeNode(n);
9636 export_pg(pg, elts, 0);
9637 return;
9638 }
9639
9640 elts->method_context = n;
9641 }
9642
9643 /*
9644 * Given a dependency property group in the tfmri entity (target fmri), return
9645 * a dependent element which represents it.
9646 */
9647 static xmlNodePtr
9648 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
9649 {
9650 uint8_t b;
9651 xmlNodePtr n, sf;
9652 int err = 0, ret;
9653 struct pg_elts pgelts;
9654
9655 /*
9656 * If external isn't set to true then exporting the service will
9657 * export this as a normal dependency, so we should stop to avoid
9658 * duplication.
9659 */
9660 if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
9661 scf_property_get_value(exp_prop, exp_val) != 0 ||
9662 scf_value_get_boolean(exp_val, &b) != 0 || !b) {
9663 if (g_verbose) {
9664 warn(gettext("Dependent \"%s\" cannot be exported "
9665 "properly because the \"%s\" property of the "
9666 "\"%s\" dependency of %s is not set to true.\n"),
9667 name, scf_property_external, name, tfmri);
9668 }
9669
9670 return (NULL);
9671 }
9672
9673 n = xmlNewNode(NULL, (xmlChar *)"dependent");
9674 if (n == NULL)
9675 uu_die(emsg_create_xml);
9676
9677 safe_setprop(n, name_attr, name);
9678
9679 /* Get the required attributes */
9680 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9681 set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9682 err = 1;
9683
9684 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9685 set_attr_from_prop(exp_prop, n, "grouping") != 0)
9686 err = 1;
9687
9688 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9689 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
9690 prop_get_val(exp_prop, exp_val) == 0) {
9691 /* EMPTY */
9692 } else
9693 err = 1;
9694
9695 if (err) {
9696 xmlFreeNode(n);
9697 return (NULL);
9698 }
9699
9700 sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
9701 if (sf == NULL)
9702 uu_die(emsg_create_xml);
9703
9704 safe_setprop(sf, value_attr, tfmri);
9705
9706 /*
9707 * Now add elements for the other properties.
9708 */
9709 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9710 scfdie();
9711
9712 (void) memset(&pgelts, 0, sizeof (pgelts));
9713
9714 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9715 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9716 scfdie();
9717
9718 if (strcmp(exp_str, scf_property_external) == 0 ||
9719 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9720 strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9721 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9722 continue;
9723 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
9724 if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
9725 prop_get_val(exp_prop, exp_val) == 0) {
9726 char type[sizeof ("service") + 1];
9727
9728 if (scf_value_get_astring(exp_val, type,
9729 sizeof (type)) < 0)
9730 scfdie();
9731
9732 if (strcmp(type, "service") == 0)
9733 continue;
9734 }
9735 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9736 xmlNodePtr s;
9737
9738 s = xmlNewNode(NULL, (xmlChar *)"stability");
9739 if (s == NULL)
9740 uu_die(emsg_create_xml);
9741
9742 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9743 pgelts.stability = s;
9744 continue;
9745 }
9746
9747 xmlFreeNode(s);
9748 }
9749
9750 export_property(exp_prop, exp_str, &pgelts, 0);
9751 }
9752 if (ret == -1)
9753 scfdie();
9754
9755 (void) xmlAddChild(n, pgelts.stability);
9756 (void) xmlAddChildList(n, pgelts.propvals);
9757 (void) xmlAddChildList(n, pgelts.properties);
9758
9759 return (n);
9760 }
9761
9762 static void
9763 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
9764 {
9765 scf_propertygroup_t *opg;
9766 scf_iter_t *iter;
9767 char *type, *fmri;
9768 int ret;
9769 struct pg_elts pgelts;
9770 xmlNodePtr n;
9771 scf_error_t serr;
9772
9773 if ((opg = scf_pg_create(g_hndl)) == NULL ||
9774 (iter = scf_iter_create(g_hndl)) == NULL)
9775 scfdie();
9776
9777 /* Can't use exp_prop_iter due to export_dependent(). */
9778 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
9779 scfdie();
9780
9781 type = safe_malloc(max_scf_pg_type_len + 1);
9782
9783 /* Get an extra byte so we can tell if values are too long. */
9784 fmri = safe_malloc(max_scf_fmri_len + 2);
9785
9786 (void) memset(&pgelts, 0, sizeof (pgelts));
9787
9788 while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
9789 void *entity;
9790 int isservice;
9791 scf_type_t ty;
9792
9793 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
9794 scfdie();
9795
9796 if ((ty != SCF_TYPE_ASTRING &&
9797 prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
9798 prop_get_val(exp_prop, exp_val) != 0) {
9799 export_property(exp_prop, NULL, &pgelts, 0);
9800 continue;
9801 }
9802
9803 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9804 scfdie();
9805
9806 if (scf_value_get_astring(exp_val, fmri,
9807 max_scf_fmri_len + 2) < 0)
9808 scfdie();
9809
9810 /* Look for a dependency group in the target fmri. */
9811 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
9812 switch (serr) {
9813 case SCF_ERROR_NONE:
9814 break;
9815
9816 case SCF_ERROR_NO_MEMORY:
9817 uu_die(gettext("Out of memory.\n"));
9818 /* NOTREACHED */
9819
9820 case SCF_ERROR_INVALID_ARGUMENT:
9821 if (g_verbose) {
9822 if (scf_property_to_fmri(exp_prop, fmri,
9823 max_scf_fmri_len + 2) < 0)
9824 scfdie();
9825
9826 warn(gettext("The value of %s is not a valid "
9827 "FMRI.\n"), fmri);
9828 }
9829
9830 export_property(exp_prop, exp_str, &pgelts, 0);
9831 continue;
9832
9833 case SCF_ERROR_CONSTRAINT_VIOLATED:
9834 if (g_verbose) {
9835 if (scf_property_to_fmri(exp_prop, fmri,
9836 max_scf_fmri_len + 2) < 0)
9837 scfdie();
9838
9839 warn(gettext("The value of %s does not specify "
9840 "a service or an instance.\n"), fmri);
9841 }
9842
9843 export_property(exp_prop, exp_str, &pgelts, 0);
9844 continue;
9845
9846 case SCF_ERROR_NOT_FOUND:
9847 if (g_verbose) {
9848 if (scf_property_to_fmri(exp_prop, fmri,
9849 max_scf_fmri_len + 2) < 0)
9850 scfdie();
9851
9852 warn(gettext("The entity specified by %s does "
9853 "not exist.\n"), fmri);
9854 }
9855
9856 export_property(exp_prop, exp_str, &pgelts, 0);
9857 continue;
9858
9859 default:
9860 #ifndef NDEBUG
9861 (void) fprintf(stderr, "%s:%d: %s() failed with "
9862 "unexpected error %d.\n", __FILE__, __LINE__,
9863 "fmri_to_entity", serr);
9864 #endif
9865 abort();
9866 }
9867
9868 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
9869 if (scf_error() != SCF_ERROR_NOT_FOUND)
9870 scfdie();
9871
9872 warn(gettext("Entity %s is missing dependency property "
9873 "group %s.\n"), fmri, exp_str);
9874
9875 export_property(exp_prop, NULL, &pgelts, 0);
9876 continue;
9877 }
9878
9879 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
9880 scfdie();
9881
9882 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
9883 if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
9884 scfdie();
9885
9886 warn(gettext("Property group %s is not of "
9887 "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
9888
9889 export_property(exp_prop, NULL, &pgelts, 0);
9890 continue;
9891 }
9892
9893 n = export_dependent(opg, exp_str, fmri);
9894 if (n == NULL)
9895 export_property(exp_prop, exp_str, &pgelts, 0);
9896 else {
9897 if (eelts->dependents == NULL)
9898 eelts->dependents = n;
9899 else
9900 (void) xmlAddSibling(eelts->dependents,
9901 n);
9902 }
9903 }
9904 if (ret == -1)
9905 scfdie();
9906
9907 free(fmri);
9908 free(type);
9909
9910 scf_iter_destroy(iter);
9911 scf_pg_destroy(opg);
9912
9913 if (pgelts.propvals != NULL || pgelts.properties != NULL)
9914 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
9915 eelts);
9916 }
9917
9918 static void
9919 make_node(xmlNodePtr *nodep, const char *name)
9920 {
9921 if (*nodep == NULL) {
9922 *nodep = xmlNewNode(NULL, (xmlChar *)name);
9923 if (*nodep == NULL)
9924 uu_die(emsg_create_xml);
9925 }
9926 }
9927
9928 static xmlNodePtr
9929 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
9930 {
9931 int ret;
9932 xmlNodePtr parent = NULL;
9933 xmlNodePtr loctext = NULL;
9934
9935 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9936 scfdie();
9937
9938 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9939 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
9940 prop_get_val(exp_prop, exp_val) != 0)
9941 continue;
9942
9943 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
9944 scfdie();
9945
9946 make_node(&parent, parname);
9947 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
9948 (xmlChar *)exp_str);
9949 if (loctext == NULL)
9950 uu_die(emsg_create_xml);
9951
9952 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9953 scfdie();
9954
9955 safe_setprop(loctext, "xml:lang", exp_str);
9956 }
9957
9958 if (ret == -1)
9959 scfdie();
9960
9961 return (parent);
9962 }
9963
9964 static xmlNodePtr
9965 export_tm_manpage(scf_propertygroup_t *pg)
9966 {
9967 xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
9968 if (manpage == NULL)
9969 uu_die(emsg_create_xml);
9970
9971 if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
9972 set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
9973 pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
9974 set_attr_from_prop(exp_prop, manpage, "section") != 0) {
9975 xmlFreeNode(manpage);
9976 return (NULL);
9977 }
9978
9979 if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
9980 (void) set_attr_from_prop_default(exp_prop,
9981 manpage, "manpath", ":default");
9982
9983 return (manpage);
9984 }
9985
9986 static xmlNodePtr
9987 export_tm_doc_link(scf_propertygroup_t *pg)
9988 {
9989 xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
9990 if (doc_link == NULL)
9991 uu_die(emsg_create_xml);
9992
9993 if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
9994 set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
9995 pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
9996 set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
9997 xmlFreeNode(doc_link);
9998 return (NULL);
9999 }
10000 return (doc_link);
10001 }
10002
10003 /*
10004 * Process template information for a service or instances.
10005 */
10006 static void
10007 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
10008 struct template_elts *telts)
10009 {
10010 size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
10011 size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
10012 xmlNodePtr child = NULL;
10013
10014 if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
10015 scfdie();
10016
10017 if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
10018 telts->common_name = export_tm_loctext(pg, "common_name");
10019 if (telts->common_name == NULL)
10020 export_pg(pg, elts, 0);
10021 return;
10022 } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
10023 telts->description = export_tm_loctext(pg, "description");
10024 if (telts->description == NULL)
10025 export_pg(pg, elts, 0);
10026 return;
10027 }
10028
10029 if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
10030 child = export_tm_manpage(pg);
10031 } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
10032 child = export_tm_doc_link(pg);
10033 }
10034
10035 if (child != NULL) {
10036 make_node(&telts->documentation, "documentation");
10037 (void) xmlAddChild(telts->documentation, child);
10038 } else {
10039 export_pg(pg, elts, 0);
10040 }
10041 }
10042
10043 /*
10044 * Process parameter and paramval elements
10045 */
10046 static void
10047 export_parameter(scf_property_t *prop, const char *name,
10048 struct params_elts *elts)
10049 {
10050 xmlNodePtr param;
10051 scf_error_t err = 0;
10052 int ret;
10053
10054 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
10055 if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL)
10056 uu_die(emsg_create_xml);
10057
10058 safe_setprop(param, name_attr, name);
10059
10060 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
10061 scfdie();
10062 safe_setprop(param, value_attr, exp_str);
10063
10064 if (elts->paramval == NULL)
10065 elts->paramval = param;
10066 else
10067 (void) xmlAddSibling(elts->paramval, param);
10068
10069 return;
10070 }
10071
10072 err = scf_error();
10073
10074 if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
10075 err != SCF_ERROR_NOT_FOUND)
10076 scfdie();
10077
10078 if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL)
10079 uu_die(emsg_create_xml);
10080
10081 safe_setprop(param, name_attr, name);
10082
10083 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
10084 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
10085 scfdie();
10086
10087 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
10088 1) {
10089 xmlNodePtr vn;
10090
10091 if ((vn = xmlNewChild(param, NULL,
10092 (xmlChar *)"value_node", NULL)) == NULL)
10093 uu_die(emsg_create_xml);
10094
10095 if (scf_value_get_as_string(exp_val, exp_str,
10096 exp_str_sz) < 0)
10097 scfdie();
10098
10099 safe_setprop(vn, value_attr, exp_str);
10100 }
10101 if (ret != 0)
10102 scfdie();
10103 }
10104
10105 if (elts->parameter == NULL)
10106 elts->parameter = param;
10107 else
10108 (void) xmlAddSibling(elts->parameter, param);
10109 }
10110
10111 /*
10112 * Process notification parameters for a service or instance
10113 */
10114 static void
10115 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts)
10116 {
10117 xmlNodePtr n, event, *type;
10118 struct params_elts *eelts;
10119 int ret, err, i;
10120
10121 n = xmlNewNode(NULL, (xmlChar *)"notification_parameters");
10122 event = xmlNewNode(NULL, (xmlChar *)"event");
10123 if (n == NULL || event == NULL)
10124 uu_die(emsg_create_xml);
10125
10126 /* event value */
10127 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
10128 scfdie();
10129 safe_setprop(event, value_attr, exp_str);
10130
10131 (void) xmlAddChild(n, event);
10132
10133 if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL ||
10134 (eelts = calloc(URI_SCHEME_NUM,
10135 sizeof (struct params_elts))) == NULL)
10136 uu_die(gettext("Out of memory.\n"));
10137
10138 err = 0;
10139
10140 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10141 scfdie();
10142
10143 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10144 char *t, *p;
10145
10146 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10147 scfdie();
10148
10149 if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) {
10150 /*
10151 * this is not a well formed notification parameters
10152 * element, we should export as regular pg
10153 */
10154 err = 1;
10155 break;
10156 }
10157
10158 if ((i = check_uri_protocol(t)) < 0) {
10159 err = 1;
10160 break;
10161 }
10162
10163 if (type[i] == NULL) {
10164 if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) ==
10165 NULL)
10166 uu_die(emsg_create_xml);
10167
10168 safe_setprop(type[i], name_attr, t);
10169 }
10170 if (strcmp(p, active_attr) == 0) {
10171 if (set_attr_from_prop(exp_prop, type[i],
10172 active_attr) != 0) {
10173 err = 1;
10174 break;
10175 }
10176 continue;
10177 }
10178 /*
10179 * We export the parameter
10180 */
10181 export_parameter(exp_prop, p, &eelts[i]);
10182 }
10183
10184 if (ret == -1)
10185 scfdie();
10186
10187 if (err == 1) {
10188 for (i = 0; i < URI_SCHEME_NUM; ++i)
10189 xmlFree(type[i]);
10190 free(type);
10191
10192 export_pg(pg, elts, 0);
10193
10194 return;
10195 } else {
10196 for (i = 0; i < URI_SCHEME_NUM; ++i)
10197 if (type[i] != NULL) {
10198 (void) xmlAddChildList(type[i],
10199 eelts[i].paramval);
10200 (void) xmlAddChildList(type[i],
10201 eelts[i].parameter);
10202 (void) xmlAddSibling(event, type[i]);
10203 }
10204 }
10205 free(type);
10206
10207 if (elts->notify_params == NULL)
10208 elts->notify_params = n;
10209 else
10210 (void) xmlAddSibling(elts->notify_params, n);
10211 }
10212
10213 /*
10214 * Process the general property group for an instance.
10215 */
10216 static void
10217 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
10218 struct entity_elts *elts)
10219 {
10220 uint8_t enabled;
10221 struct pg_elts pgelts;
10222 int ret;
10223
10224 /* enabled */
10225 if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
10226 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
10227 prop_get_val(exp_prop, exp_val) == 0) {
10228 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
10229 scfdie();
10230 } else {
10231 enabled = 0;
10232 }
10233
10234 safe_setprop(inode, enabled_attr, enabled ? true : false);
10235
10236 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10237 scfdie();
10238
10239 (void) memset(&pgelts, 0, sizeof (pgelts));
10240
10241 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10242 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10243 scfdie();
10244
10245 if (strcmp(exp_str, scf_property_enabled) == 0) {
10246 continue;
10247 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
10248 xmlNodePtr rnode, sfnode;
10249
10250 rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10251 if (rnode == NULL)
10252 uu_die(emsg_create_xml);
10253
10254 sfnode = xmlNewChild(rnode, NULL,
10255 (xmlChar *)"service_fmri", NULL);
10256 if (sfnode == NULL)
10257 uu_die(emsg_create_xml);
10258
10259 if (set_attr_from_prop(exp_prop, sfnode,
10260 value_attr) == 0) {
10261 elts->restarter = rnode;
10262 continue;
10263 }
10264
10265 xmlFreeNode(rnode);
10266 }
10267
10268 export_property(exp_prop, exp_str, &pgelts, 0);
10269 }
10270 if (ret == -1)
10271 scfdie();
10272
10273 if (pgelts.propvals != NULL || pgelts.properties != NULL)
10274 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10275 elts);
10276 }
10277
10278 /*
10279 * Put an instance element for the given instance into selts.
10280 */
10281 static void
10282 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10283 {
10284 xmlNodePtr n;
10285 boolean_t isdefault;
10286 struct entity_elts elts;
10287 struct template_elts template_elts;
10288 int ret;
10289
10290 n = xmlNewNode(NULL, (xmlChar *)"instance");
10291 if (n == NULL)
10292 uu_die(emsg_create_xml);
10293
10294 /* name */
10295 if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10296 scfdie();
10297 safe_setprop(n, name_attr, exp_str);
10298 isdefault = strcmp(exp_str, "default") == 0;
10299
10300 /* check existance of general pg (since general/enabled is required) */
10301 if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
10302 if (scf_error() != SCF_ERROR_NOT_FOUND)
10303 scfdie();
10304
10305 if (g_verbose) {
10306 if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10307 scfdie();
10308
10309 warn(gettext("Instance %s has no general property "
10310 "group; it will be marked disabled.\n"), exp_str);
10311 }
10312
10313 safe_setprop(n, enabled_attr, false);
10314 } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
10315 strcmp(exp_str, scf_group_framework) != 0) {
10316 if (g_verbose) {
10317 if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10318 scfdie();
10319
10320 warn(gettext("Property group %s is not of type "
10321 "framework; the instance will be marked "
10322 "disabled.\n"), exp_str);
10323 }
10324
10325 safe_setprop(n, enabled_attr, false);
10326 }
10327
10328 /* property groups */
10329 if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
10330 scfdie();
10331
10332 (void) memset(&elts, 0, sizeof (elts));
10333 (void) memset(&template_elts, 0, sizeof (template_elts));
10334
10335 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10336 uint32_t pgflags;
10337
10338 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10339 scfdie();
10340
10341 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10342 continue;
10343
10344 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10345 scfdie();
10346
10347 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10348 export_dependency(exp_pg, &elts);
10349 continue;
10350 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10351 export_method(exp_pg, &elts);
10352 continue;
10353 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10354 if (scf_pg_get_name(exp_pg, exp_str,
10355 max_scf_name_len + 1) < 0)
10356 scfdie();
10357
10358 if (strcmp(exp_str, scf_pg_general) == 0) {
10359 export_inst_general(exp_pg, n, &elts);
10360 continue;
10361 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10362 0) {
10363 export_method_context(exp_pg, &elts);
10364 continue;
10365 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10366 export_dependents(exp_pg, &elts);
10367 continue;
10368 }
10369 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10370 export_template(exp_pg, &elts, &template_elts);
10371 continue;
10372 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10373 export_notify_params(exp_pg, &elts);
10374 continue;
10375 }
10376
10377 /* Ordinary pg. */
10378 export_pg(exp_pg, &elts, flags);
10379 }
10380 if (ret == -1)
10381 scfdie();
10382
10383 if (template_elts.common_name != NULL) {
10384 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10385 (void) xmlAddChild(elts.template, template_elts.common_name);
10386 (void) xmlAddChild(elts.template, template_elts.description);
10387 (void) xmlAddChild(elts.template, template_elts.documentation);
10388 } else {
10389 xmlFreeNode(template_elts.description);
10390 xmlFreeNode(template_elts.documentation);
10391 }
10392
10393 if (isdefault && elts.restarter == NULL &&
10394 elts.dependencies == NULL && elts.method_context == NULL &&
10395 elts.exec_methods == NULL && elts.notify_params == NULL &&
10396 elts.property_groups == NULL && elts.template == NULL) {
10397 xmlChar *eval;
10398
10399 /* This is a default instance */
10400 eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10401
10402 xmlFreeNode(n);
10403
10404 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10405 if (n == NULL)
10406 uu_die(emsg_create_xml);
10407
10408 safe_setprop(n, enabled_attr, (char *)eval);
10409 xmlFree(eval);
10410
10411 selts->create_default_instance = n;
10412 } else {
10413 /* Assemble the children in order. */
10414 (void) xmlAddChild(n, elts.restarter);
10415 (void) xmlAddChildList(n, elts.dependencies);
10416 (void) xmlAddChildList(n, elts.dependents);
10417 (void) xmlAddChild(n, elts.method_context);
10418 (void) xmlAddChildList(n, elts.exec_methods);
10419 (void) xmlAddChildList(n, elts.notify_params);
10420 (void) xmlAddChildList(n, elts.property_groups);
10421 (void) xmlAddChild(n, elts.template);
10422
10423 if (selts->instances == NULL)
10424 selts->instances = n;
10425 else
10426 (void) xmlAddSibling(selts->instances, n);
10427 }
10428 }
10429
10430 /*
10431 * Return a service element for the given service.
10432 */
10433 static xmlNodePtr
10434 export_service(scf_service_t *svc, int flags)
10435 {
10436 xmlNodePtr snode;
10437 struct entity_elts elts;
10438 struct template_elts template_elts;
10439 int ret;
10440
10441 snode = xmlNewNode(NULL, (xmlChar *)"service");
10442 if (snode == NULL)
10443 uu_die(emsg_create_xml);
10444
10445 /* Get & set name attribute */
10446 if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
10447 scfdie();
10448 safe_setprop(snode, name_attr, exp_str);
10449
10450 safe_setprop(snode, type_attr, "service");
10451 safe_setprop(snode, "version", "0");
10452
10453 /* Acquire child elements. */
10454 if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
10455 scfdie();
10456
10457 (void) memset(&elts, 0, sizeof (elts));
10458 (void) memset(&template_elts, 0, sizeof (template_elts));
10459
10460 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10461 uint32_t pgflags;
10462
10463 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10464 scfdie();
10465
10466 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10467 continue;
10468
10469 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10470 scfdie();
10471
10472 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10473 export_dependency(exp_pg, &elts);
10474 continue;
10475 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10476 export_method(exp_pg, &elts);
10477 continue;
10478 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10479 if (scf_pg_get_name(exp_pg, exp_str,
10480 max_scf_name_len + 1) < 0)
10481 scfdie();
10482
10483 if (strcmp(exp_str, scf_pg_general) == 0) {
10484 export_svc_general(exp_pg, &elts);
10485 continue;
10486 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10487 0) {
10488 export_method_context(exp_pg, &elts);
10489 continue;
10490 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10491 export_dependents(exp_pg, &elts);
10492 continue;
10493 } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10494 continue;
10495 }
10496 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10497 export_template(exp_pg, &elts, &template_elts);
10498 continue;
10499 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10500 export_notify_params(exp_pg, &elts);
10501 continue;
10502 }
10503
10504 export_pg(exp_pg, &elts, flags);
10505 }
10506 if (ret == -1)
10507 scfdie();
10508
10509 if (template_elts.common_name != NULL) {
10510 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10511 (void) xmlAddChild(elts.template, template_elts.common_name);
10512 (void) xmlAddChild(elts.template, template_elts.description);
10513 (void) xmlAddChild(elts.template, template_elts.documentation);
10514 } else {
10515 xmlFreeNode(template_elts.description);
10516 xmlFreeNode(template_elts.documentation);
10517 }
10518
10519 /* Iterate instances */
10520 if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
10521 scfdie();
10522
10523 while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10524 export_instance(exp_inst, &elts, flags);
10525 if (ret == -1)
10526 scfdie();
10527
10528 /* Now add all of the accumulated elements in order. */
10529 (void) xmlAddChild(snode, elts.create_default_instance);
10530 (void) xmlAddChild(snode, elts.single_instance);
10531 (void) xmlAddChild(snode, elts.restarter);
10532 (void) xmlAddChildList(snode, elts.dependencies);
10533 (void) xmlAddChildList(snode, elts.dependents);
10534 (void) xmlAddChild(snode, elts.method_context);
10535 (void) xmlAddChildList(snode, elts.exec_methods);
10536 (void) xmlAddChildList(snode, elts.notify_params);
10537 (void) xmlAddChildList(snode, elts.property_groups);
10538 (void) xmlAddChildList(snode, elts.instances);
10539 (void) xmlAddChild(snode, elts.stability);
10540 (void) xmlAddChild(snode, elts.template);
10541
10542 return (snode);
10543 }
10544
10545 static int
10546 export_callback(void *data, scf_walkinfo_t *wip)
10547 {
10548 FILE *f;
10549 xmlDocPtr doc;
10550 xmlNodePtr sb;
10551 int result;
10552 struct export_args *argsp = (struct export_args *)data;
10553
10554 if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
10555 (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10556 (exp_prop = scf_property_create(g_hndl)) == NULL ||
10557 (exp_val = scf_value_create(g_hndl)) == NULL ||
10558 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10559 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10560 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10561 (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10562 scfdie();
10563
10564 exp_str_sz = max_scf_len + 1;
10565 exp_str = safe_malloc(exp_str_sz);
10566
10567 if (argsp->filename != NULL) {
10568 errno = 0;
10569 f = fopen(argsp->filename, "wb");
10570 if (f == NULL) {
10571 if (errno == 0)
10572 uu_die(gettext("Could not open \"%s\": no free "
10573 "stdio streams.\n"), argsp->filename);
10574 else
10575 uu_die(gettext("Could not open \"%s\""),
10576 argsp->filename);
10577 }
10578 } else
10579 f = stdout;
10580
10581 doc = xmlNewDoc((xmlChar *)"1.0");
10582 if (doc == NULL)
10583 uu_die(gettext("Could not create XML document.\n"));
10584
10585 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10586 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10587 uu_die(emsg_create_xml);
10588
10589 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10590 if (sb == NULL)
10591 uu_die(emsg_create_xml);
10592 safe_setprop(sb, type_attr, "manifest");
10593 safe_setprop(sb, name_attr, "export");
10594 (void) xmlAddSibling(doc->children, sb);
10595
10596 (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
10597
10598 result = write_service_bundle(doc, f);
10599
10600 free(exp_str);
10601 scf_iter_destroy(exp_val_iter);
10602 scf_iter_destroy(exp_prop_iter);
10603 scf_iter_destroy(exp_pg_iter);
10604 scf_iter_destroy(exp_inst_iter);
10605 scf_value_destroy(exp_val);
10606 scf_property_destroy(exp_prop);
10607 scf_pg_destroy(exp_pg);
10608 scf_instance_destroy(exp_inst);
10609
10610 xmlFreeDoc(doc);
10611
10612 if (f != stdout)
10613 (void) fclose(f);
10614
10615 return (result);
10616 }
10617
10618 /*
10619 * Get the service named by fmri, build an XML tree which represents it, and
10620 * dump it into filename (or stdout if filename is NULL).
10621 */
10622 int
10623 lscf_service_export(char *fmri, const char *filename, int flags)
10624 {
10625 struct export_args args;
10626 int ret, err;
10627
10628 lscf_prep_hndl();
10629
10630 bzero(&args, sizeof (args));
10631 args.filename = filename;
10632 args.flags = flags;
10633
10634 err = 0;
10635 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10636 SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10637 &args, &err, semerr)) != 0) {
10638 if (ret != -1)
10639 semerr(gettext("Failed to walk instances: %s\n"),
10640 scf_strerror(ret));
10641 return (-1);
10642 }
10643
10644 /*
10645 * Error message has already been printed.
10646 */
10647 if (err != 0)
10648 return (-1);
10649
10650 return (0);
10651 }
10652
10653
10654 /*
10655 * Archive
10656 */
10657
10658 static xmlNodePtr
10659 make_archive(int flags)
10660 {
10661 xmlNodePtr sb;
10662 scf_scope_t *scope;
10663 scf_service_t *svc;
10664 scf_iter_t *iter;
10665 int r;
10666
10667 if ((scope = scf_scope_create(g_hndl)) == NULL ||
10668 (svc = scf_service_create(g_hndl)) == NULL ||
10669 (iter = scf_iter_create(g_hndl)) == NULL ||
10670 (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10671 (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10672 (exp_prop = scf_property_create(g_hndl)) == NULL ||
10673 (exp_val = scf_value_create(g_hndl)) == NULL ||
10674 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10675 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10676 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10677 (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10678 scfdie();
10679
10680 exp_str_sz = max_scf_len + 1;
10681 exp_str = safe_malloc(exp_str_sz);
10682
10683 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10684 if (sb == NULL)
10685 uu_die(emsg_create_xml);
10686 safe_setprop(sb, type_attr, "archive");
10687 safe_setprop(sb, name_attr, "none");
10688
10689 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
10690 scfdie();
10691 if (scf_iter_scope_services(iter, scope) != 0)
10692 scfdie();
10693
10694 for (;;) {
10695 r = scf_iter_next_service(iter, svc);
10696 if (r == 0)
10697 break;
10698 if (r != 1)
10699 scfdie();
10700
10701 if (scf_service_get_name(svc, exp_str,
10702 max_scf_name_len + 1) < 0)
10703 scfdie();
10704
10705 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
10706 continue;
10707
10708 (void) xmlAddChild(sb, export_service(svc, flags));
10709 }
10710
10711 free(exp_str);
10712
10713 scf_iter_destroy(exp_val_iter);
10714 scf_iter_destroy(exp_prop_iter);
10715 scf_iter_destroy(exp_pg_iter);
10716 scf_iter_destroy(exp_inst_iter);
10717 scf_value_destroy(exp_val);
10718 scf_property_destroy(exp_prop);
10719 scf_pg_destroy(exp_pg);
10720 scf_instance_destroy(exp_inst);
10721 scf_iter_destroy(iter);
10722 scf_service_destroy(svc);
10723 scf_scope_destroy(scope);
10724
10725 return (sb);
10726 }
10727
10728 int
10729 lscf_archive(const char *filename, int flags)
10730 {
10731 FILE *f;
10732 xmlDocPtr doc;
10733 int result;
10734
10735 lscf_prep_hndl();
10736
10737 if (filename != NULL) {
10738 errno = 0;
10739 f = fopen(filename, "wb");
10740 if (f == NULL) {
10741 if (errno == 0)
10742 uu_die(gettext("Could not open \"%s\": no free "
10743 "stdio streams.\n"), filename);
10744 else
10745 uu_die(gettext("Could not open \"%s\""),
10746 filename);
10747 }
10748 } else
10749 f = stdout;
10750
10751 doc = xmlNewDoc((xmlChar *)"1.0");
10752 if (doc == NULL)
10753 uu_die(gettext("Could not create XML document.\n"));
10754
10755 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10756 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10757 uu_die(emsg_create_xml);
10758
10759 (void) xmlAddSibling(doc->children, make_archive(flags));
10760
10761 result = write_service_bundle(doc, f);
10762
10763 xmlFreeDoc(doc);
10764
10765 if (f != stdout)
10766 (void) fclose(f);
10767
10768 return (result);
10769 }
10770
10771
10772 /*
10773 * "Extract" a profile.
10774 */
10775 int
10776 lscf_profile_extract(const char *filename)
10777 {
10778 FILE *f;
10779 xmlDocPtr doc;
10780 xmlNodePtr sb, snode, inode;
10781 scf_scope_t *scope;
10782 scf_service_t *svc;
10783 scf_instance_t *inst;
10784 scf_propertygroup_t *pg;
10785 scf_property_t *prop;
10786 scf_value_t *val;
10787 scf_iter_t *siter, *iiter;
10788 int r, s;
10789 char *namebuf;
10790 uint8_t b;
10791 int result;
10792
10793 lscf_prep_hndl();
10794
10795 if (filename != NULL) {
10796 errno = 0;
10797 f = fopen(filename, "wb");
10798 if (f == NULL) {
10799 if (errno == 0)
10800 uu_die(gettext("Could not open \"%s\": no "
10801 "free stdio streams.\n"), filename);
10802 else
10803 uu_die(gettext("Could not open \"%s\""),
10804 filename);
10805 }
10806 } else
10807 f = stdout;
10808
10809 doc = xmlNewDoc((xmlChar *)"1.0");
10810 if (doc == NULL)
10811 uu_die(gettext("Could not create XML document.\n"));
10812
10813 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10814 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10815 uu_die(emsg_create_xml);
10816
10817 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10818 if (sb == NULL)
10819 uu_die(emsg_create_xml);
10820 safe_setprop(sb, type_attr, "profile");
10821 safe_setprop(sb, name_attr, "extract");
10822 (void) xmlAddSibling(doc->children, sb);
10823
10824 if ((scope = scf_scope_create(g_hndl)) == NULL ||
10825 (svc = scf_service_create(g_hndl)) == NULL ||
10826 (inst = scf_instance_create(g_hndl)) == NULL ||
10827 (pg = scf_pg_create(g_hndl)) == NULL ||
10828 (prop = scf_property_create(g_hndl)) == NULL ||
10829 (val = scf_value_create(g_hndl)) == NULL ||
10830 (siter = scf_iter_create(g_hndl)) == NULL ||
10831 (iiter = scf_iter_create(g_hndl)) == NULL)
10832 scfdie();
10833
10834 if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
10835 scfdie();
10836
10837 if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
10838 scfdie();
10839
10840 namebuf = safe_malloc(max_scf_name_len + 1);
10841
10842 while ((r = scf_iter_next_service(siter, svc)) == 1) {
10843 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
10844 scfdie();
10845
10846 snode = xmlNewNode(NULL, (xmlChar *)"service");
10847 if (snode == NULL)
10848 uu_die(emsg_create_xml);
10849
10850 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
10851 0)
10852 scfdie();
10853
10854 safe_setprop(snode, name_attr, namebuf);
10855
10856 safe_setprop(snode, type_attr, "service");
10857 safe_setprop(snode, "version", "0");
10858
10859 while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
10860 if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
10861 SCF_SUCCESS) {
10862 if (scf_error() != SCF_ERROR_NOT_FOUND)
10863 scfdie();
10864
10865 if (g_verbose) {
10866 ssize_t len;
10867 char *fmri;
10868
10869 len =
10870 scf_instance_to_fmri(inst, NULL, 0);
10871 if (len < 0)
10872 scfdie();
10873
10874 fmri = safe_malloc(len + 1);
10875
10876 if (scf_instance_to_fmri(inst, fmri,
10877 len + 1) < 0)
10878 scfdie();
10879
10880 warn("Instance %s has no \"%s\" "
10881 "property group.\n", fmri,
10882 scf_pg_general);
10883
10884 free(fmri);
10885 }
10886
10887 continue;
10888 }
10889
10890 if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
10891 prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
10892 prop_get_val(prop, val) != 0)
10893 continue;
10894
10895 inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
10896 NULL);
10897 if (inode == NULL)
10898 uu_die(emsg_create_xml);
10899
10900 if (scf_instance_get_name(inst, namebuf,
10901 max_scf_name_len + 1) < 0)
10902 scfdie();
10903
10904 safe_setprop(inode, name_attr, namebuf);
10905
10906 if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
10907 scfdie();
10908
10909 safe_setprop(inode, enabled_attr, b ? true : false);
10910 }
10911 if (s < 0)
10912 scfdie();
10913
10914 if (snode->children != NULL)
10915 (void) xmlAddChild(sb, snode);
10916 else
10917 xmlFreeNode(snode);
10918 }
10919 if (r < 0)
10920 scfdie();
10921
10922 free(namebuf);
10923
10924 result = write_service_bundle(doc, f);
10925
10926 xmlFreeDoc(doc);
10927
10928 if (f != stdout)
10929 (void) fclose(f);
10930
10931 return (result);
10932 }
10933
10934
10935 /*
10936 * Entity manipulation commands
10937 */
10938
10939 /*
10940 * Entity selection. If no entity is selected, then the current scope is in
10941 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected,
10942 * only cur_inst is NULL, and when an instance is selected, none are NULL.
10943 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
10944 * cur_inst will be non-NULL.
10945 */
10946
10947 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
10948 static int
10949 select_inst(const char *name)
10950 {
10951 scf_instance_t *inst;
10952 scf_error_t err;
10953
10954 assert(cur_svc != NULL);
10955
10956 inst = scf_instance_create(g_hndl);
10957 if (inst == NULL)
10958 scfdie();
10959
10960 if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
10961 cur_inst = inst;
10962 return (0);
10963 }
10964
10965 err = scf_error();
10966 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
10967 scfdie();
10968
10969 scf_instance_destroy(inst);
10970 return (1);
10971 }
10972
10973 /* Returns as above. */
10974 static int
10975 select_svc(const char *name)
10976 {
10977 scf_service_t *svc;
10978 scf_error_t err;
10979
10980 assert(cur_scope != NULL);
10981
10982 svc = scf_service_create(g_hndl);
10983 if (svc == NULL)
10984 scfdie();
10985
10986 if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
10987 cur_svc = svc;
10988 return (0);
10989 }
10990
10991 err = scf_error();
10992 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
10993 scfdie();
10994
10995 scf_service_destroy(svc);
10996 return (1);
10997 }
10998
10999 /* ARGSUSED */
11000 static int
11001 select_callback(void *unused, scf_walkinfo_t *wip)
11002 {
11003 scf_instance_t *inst;
11004 scf_service_t *svc;
11005 scf_scope_t *scope;
11006
11007 if (wip->inst != NULL) {
11008 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11009 (svc = scf_service_create(g_hndl)) == NULL ||
11010 (inst = scf_instance_create(g_hndl)) == NULL)
11011 scfdie();
11012
11013 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11014 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11015 scfdie();
11016 } else {
11017 assert(wip->svc != NULL);
11018
11019 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11020 (svc = scf_service_create(g_hndl)) == NULL)
11021 scfdie();
11022
11023 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11024 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11025 scfdie();
11026
11027 inst = NULL;
11028 }
11029
11030 /* Clear out the current selection */
11031 assert(cur_scope != NULL);
11032 scf_scope_destroy(cur_scope);
11033 scf_service_destroy(cur_svc);
11034 scf_instance_destroy(cur_inst);
11035
11036 cur_scope = scope;
11037 cur_svc = svc;
11038 cur_inst = inst;
11039
11040 return (0);
11041 }
11042
11043 static int
11044 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
11045 {
11046 char **fmri = fmri_p;
11047
11048 *fmri = strdup(wip->fmri);
11049 if (*fmri == NULL)
11050 uu_die(gettext("Out of memory.\n"));
11051
11052 return (0);
11053 }
11054
11055 /*
11056 * validate [fmri]
11057 * Perform the validation of an FMRI instance.
11058 */
11059 void
11060 lscf_validate_fmri(const char *fmri)
11061 {
11062 int ret = 0;
11063 size_t inst_sz;
11064 char *inst_fmri = NULL;
11065 scf_tmpl_errors_t *errs = NULL;
11066 char *snapbuf = NULL;
11067
11068 lscf_prep_hndl();
11069
11070 if (fmri == NULL) {
11071 inst_sz = max_scf_fmri_len + 1;
11072 inst_fmri = safe_malloc(inst_sz);
11073
11074 if (cur_snap != NULL) {
11075 snapbuf = safe_malloc(max_scf_name_len + 1);
11076 if (scf_snapshot_get_name(cur_snap, snapbuf,
11077 max_scf_name_len + 1) < 0)
11078 scfdie();
11079 }
11080 if (cur_inst == NULL) {
11081 semerr(gettext("No instance selected\n"));
11082 goto cleanup;
11083 } else if (scf_instance_to_fmri(cur_inst, inst_fmri,
11084 inst_sz) >= inst_sz) {
11085 /* sanity check. Should never get here */
11086 uu_die(gettext("Unexpected error! file %s, line %d\n"),
11087 __FILE__, __LINE__);
11088 }
11089 } else {
11090 scf_error_t scf_err;
11091 int err = 0;
11092
11093 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
11094 validate_callback, &inst_fmri, &err, semerr)) != 0) {
11095 uu_warn("Failed to walk instances: %s\n",
11096 scf_strerror(scf_err));
11097 goto cleanup;
11098 }
11099 if (err != 0) {
11100 /* error message displayed by scf_walk_fmri */
11101 goto cleanup;
11102 }
11103 }
11104
11105 ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
11106 SCF_TMPL_VALIDATE_FLAG_CURRENT);
11107 if (ret == -1) {
11108 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
11109 warn(gettext("Template data for %s is invalid. "
11110 "Consider reverting to a previous snapshot or "
11111 "restoring original configuration.\n"), inst_fmri);
11112 } else {
11113 uu_warn("%s: %s\n",
11114 gettext("Error validating the instance"),
11115 scf_strerror(scf_error()));
11116 }
11117 } else if (ret == 1 && errs != NULL) {
11118 scf_tmpl_error_t *err = NULL;
11119 char *msg;
11120 size_t len = 256; /* initial error buffer size */
11121 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
11122 SCF_TMPL_STRERROR_HUMAN : 0;
11123
11124 msg = safe_malloc(len);
11125
11126 while ((err = scf_tmpl_next_error(errs)) != NULL) {
11127 int ret;
11128
11129 if ((ret = scf_tmpl_strerror(err, msg, len,
11130 flag)) >= len) {
11131 len = ret + 1;
11132 msg = realloc(msg, len);
11133 if (msg == NULL)
11134 uu_die(gettext(
11135 "Out of memory.\n"));
11136 (void) scf_tmpl_strerror(err, msg, len,
11137 flag);
11138 }
11139 (void) fprintf(stderr, "%s\n", msg);
11140 }
11141 if (msg != NULL)
11142 free(msg);
11143 }
11144 if (errs != NULL)
11145 scf_tmpl_errors_destroy(errs);
11146
11147 cleanup:
11148 free(inst_fmri);
11149 free(snapbuf);
11150 }
11151
11152 static void
11153 lscf_validate_file(const char *filename)
11154 {
11155 tmpl_errors_t *errs;
11156
11157 bundle_t *b = internal_bundle_new();
11158 if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
11159 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
11160 tmpl_errors_print(stderr, errs, "");
11161 semerr(gettext("Validation failed.\n"));
11162 }
11163 tmpl_errors_destroy(errs);
11164 }
11165 (void) internal_bundle_free(b);
11166 }
11167
11168 /*
11169 * validate [fmri|file]
11170 */
11171 void
11172 lscf_validate(const char *arg)
11173 {
11174 const char *str;
11175
11176 if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
11177 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
11178 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
11179 lscf_validate_file(str);
11180 } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
11181 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
11182 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
11183 lscf_validate_fmri(str);
11184 } else if (access(arg, R_OK | F_OK) == 0) {
11185 lscf_validate_file(arg);
11186 } else {
11187 lscf_validate_fmri(arg);
11188 }
11189 }
11190
11191 void
11192 lscf_select(const char *fmri)
11193 {
11194 int ret, err;
11195
11196 lscf_prep_hndl();
11197
11198 if (cur_snap != NULL) {
11199 struct snaplevel *elt;
11200 char *buf;
11201
11202 /* Error unless name is that of the next level. */
11203 elt = uu_list_next(cur_levels, cur_elt);
11204 if (elt == NULL) {
11205 semerr(gettext("No children.\n"));
11206 return;
11207 }
11208
11209 buf = safe_malloc(max_scf_name_len + 1);
11210
11211 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11212 max_scf_name_len + 1) < 0)
11213 scfdie();
11214
11215 if (strcmp(buf, fmri) != 0) {
11216 semerr(gettext("No such child.\n"));
11217 free(buf);
11218 return;
11219 }
11220
11221 free(buf);
11222
11223 cur_elt = elt;
11224 cur_level = elt->sl;
11225 return;
11226 }
11227
11228 /*
11229 * Special case for 'svc:', which takes the user to the scope level.
11230 */
11231 if (strcmp(fmri, "svc:") == 0) {
11232 scf_instance_destroy(cur_inst);
11233 scf_service_destroy(cur_svc);
11234 cur_inst = NULL;
11235 cur_svc = NULL;
11236 return;
11237 }
11238
11239 /*
11240 * Special case for ':properties'. This appears as part of 'list' but
11241 * can't be selected. Give a more helpful error message in this case.
11242 */
11243 if (strcmp(fmri, ":properties") == 0) {
11244 semerr(gettext(":properties is not an entity. Try 'listprop' "
11245 "to list properties.\n"));
11246 return;
11247 }
11248
11249 /*
11250 * First try the argument as relative to the current selection.
11251 */
11252 if (cur_inst != NULL) {
11253 /* EMPTY */;
11254 } else if (cur_svc != NULL) {
11255 if (select_inst(fmri) != 1)
11256 return;
11257 } else {
11258 if (select_svc(fmri) != 1)
11259 return;
11260 }
11261
11262 err = 0;
11263 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11264 select_callback, NULL, &err, semerr)) != 0) {
11265 semerr(gettext("Failed to walk instances: %s\n"),
11266 scf_strerror(ret));
11267 }
11268 }
11269
11270 void
11271 lscf_unselect(void)
11272 {
11273 lscf_prep_hndl();
11274
11275 if (cur_snap != NULL) {
11276 struct snaplevel *elt;
11277
11278 elt = uu_list_prev(cur_levels, cur_elt);
11279 if (elt == NULL) {
11280 semerr(gettext("No parent levels.\n"));
11281 } else {
11282 cur_elt = elt;
11283 cur_level = elt->sl;
11284 }
11285 } else if (cur_inst != NULL) {
11286 scf_instance_destroy(cur_inst);
11287 cur_inst = NULL;
11288 } else if (cur_svc != NULL) {
11289 scf_service_destroy(cur_svc);
11290 cur_svc = NULL;
11291 } else {
11292 semerr(gettext("Cannot unselect at scope level.\n"));
11293 }
11294 }
11295
11296 /*
11297 * Return the FMRI of the current selection, for the prompt.
11298 */
11299 void
11300 lscf_get_selection_str(char *buf, size_t bufsz)
11301 {
11302 char *cp;
11303 ssize_t fmrilen, szret;
11304 boolean_t deleted = B_FALSE;
11305
11306 if (g_hndl == NULL) {
11307 (void) strlcpy(buf, "svc:", bufsz);
11308 return;
11309 }
11310
11311 if (cur_level != NULL) {
11312 assert(cur_snap != NULL);
11313
11314 /* [ snapshot ] FMRI [: instance ] */
11315 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11316 + 2 + max_scf_name_len + 1 + 1);
11317
11318 buf[0] = '[';
11319
11320 szret = scf_snapshot_get_name(cur_snap, buf + 1,
11321 max_scf_name_len + 1);
11322 if (szret < 0) {
11323 if (scf_error() != SCF_ERROR_DELETED)
11324 scfdie();
11325
11326 goto snap_deleted;
11327 }
11328
11329 (void) strcat(buf, "]svc:/");
11330
11331 cp = strchr(buf, '\0');
11332
11333 szret = scf_snaplevel_get_service_name(cur_level, cp,
11334 max_scf_name_len + 1);
11335 if (szret < 0) {
11336 if (scf_error() != SCF_ERROR_DELETED)
11337 scfdie();
11338
11339 goto snap_deleted;
11340 }
11341
11342 cp = strchr(cp, '\0');
11343
11344 if (snaplevel_is_instance(cur_level)) {
11345 *cp++ = ':';
11346
11347 if (scf_snaplevel_get_instance_name(cur_level, cp,
11348 max_scf_name_len + 1) < 0) {
11349 if (scf_error() != SCF_ERROR_DELETED)
11350 scfdie();
11351
11352 goto snap_deleted;
11353 }
11354 } else {
11355 *cp++ = '[';
11356 *cp++ = ':';
11357
11358 if (scf_instance_get_name(cur_inst, cp,
11359 max_scf_name_len + 1) < 0) {
11360 if (scf_error() != SCF_ERROR_DELETED)
11361 scfdie();
11362
11363 goto snap_deleted;
11364 }
11365
11366 (void) strcat(buf, "]");
11367 }
11368
11369 return;
11370
11371 snap_deleted:
11372 deleted = B_TRUE;
11373 free(buf);
11374 unselect_cursnap();
11375 }
11376
11377 assert(cur_snap == NULL);
11378
11379 if (cur_inst != NULL) {
11380 assert(cur_svc != NULL);
11381 assert(cur_scope != NULL);
11382
11383 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11384 if (fmrilen >= 0) {
11385 assert(fmrilen < bufsz);
11386 if (deleted)
11387 warn(emsg_deleted);
11388 return;
11389 }
11390
11391 if (scf_error() != SCF_ERROR_DELETED)
11392 scfdie();
11393
11394 deleted = B_TRUE;
11395
11396 scf_instance_destroy(cur_inst);
11397 cur_inst = NULL;
11398 }
11399
11400 if (cur_svc != NULL) {
11401 assert(cur_scope != NULL);
11402
11403 szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11404 if (szret >= 0) {
11405 assert(szret < bufsz);
11406 if (deleted)
11407 warn(emsg_deleted);
11408 return;
11409 }
11410
11411 if (scf_error() != SCF_ERROR_DELETED)
11412 scfdie();
11413
11414 deleted = B_TRUE;
11415 scf_service_destroy(cur_svc);
11416 cur_svc = NULL;
11417 }
11418
11419 assert(cur_scope != NULL);
11420 fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11421
11422 if (fmrilen < 0)
11423 scfdie();
11424
11425 assert(fmrilen < bufsz);
11426 if (deleted)
11427 warn(emsg_deleted);
11428 }
11429
11430 /*
11431 * Entity listing. Entities and colon namespaces (e.g., :properties and
11432 * :statistics) are listed for the current selection.
11433 */
11434 void
11435 lscf_list(const char *pattern)
11436 {
11437 scf_iter_t *iter;
11438 char *buf;
11439 int ret;
11440
11441 lscf_prep_hndl();
11442
11443 if (cur_level != NULL) {
11444 struct snaplevel *elt;
11445
11446 (void) fputs(COLON_NAMESPACES, stdout);
11447
11448 elt = uu_list_next(cur_levels, cur_elt);
11449 if (elt == NULL)
11450 return;
11451
11452 /*
11453 * For now, we know that the next level is an instance. But
11454 * if we ever have multiple scopes, this could be complicated.
11455 */
11456 buf = safe_malloc(max_scf_name_len + 1);
11457 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11458 max_scf_name_len + 1) >= 0) {
11459 (void) puts(buf);
11460 } else {
11461 if (scf_error() != SCF_ERROR_DELETED)
11462 scfdie();
11463 }
11464
11465 free(buf);
11466
11467 return;
11468 }
11469
11470 if (cur_inst != NULL) {
11471 (void) fputs(COLON_NAMESPACES, stdout);
11472 return;
11473 }
11474
11475 iter = scf_iter_create(g_hndl);
11476 if (iter == NULL)
11477 scfdie();
11478
11479 buf = safe_malloc(max_scf_name_len + 1);
11480
11481 if (cur_svc != NULL) {
11482 /* List the instances in this service. */
11483 scf_instance_t *inst;
11484
11485 inst = scf_instance_create(g_hndl);
11486 if (inst == NULL)
11487 scfdie();
11488
11489 if (scf_iter_service_instances(iter, cur_svc) == 0) {
11490 safe_printf(COLON_NAMESPACES);
11491
11492 for (;;) {
11493 ret = scf_iter_next_instance(iter, inst);
11494 if (ret == 0)
11495 break;
11496 if (ret != 1) {
11497 if (scf_error() != SCF_ERROR_DELETED)
11498 scfdie();
11499
11500 break;
11501 }
11502
11503 if (scf_instance_get_name(inst, buf,
11504 max_scf_name_len + 1) >= 0) {
11505 if (pattern == NULL ||
11506 fnmatch(pattern, buf, 0) == 0)
11507 (void) puts(buf);
11508 } else {
11509 if (scf_error() != SCF_ERROR_DELETED)
11510 scfdie();
11511 }
11512 }
11513 } else {
11514 if (scf_error() != SCF_ERROR_DELETED)
11515 scfdie();
11516 }
11517
11518 scf_instance_destroy(inst);
11519 } else {
11520 /* List the services in this scope. */
11521 scf_service_t *svc;
11522
11523 assert(cur_scope != NULL);
11524
11525 svc = scf_service_create(g_hndl);
11526 if (svc == NULL)
11527 scfdie();
11528
11529 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11530 scfdie();
11531
11532 for (;;) {
11533 ret = scf_iter_next_service(iter, svc);
11534 if (ret == 0)
11535 break;
11536 if (ret != 1)
11537 scfdie();
11538
11539 if (scf_service_get_name(svc, buf,
11540 max_scf_name_len + 1) >= 0) {
11541 if (pattern == NULL ||
11542 fnmatch(pattern, buf, 0) == 0)
11543 safe_printf("%s\n", buf);
11544 } else {
11545 if (scf_error() != SCF_ERROR_DELETED)
11546 scfdie();
11547 }
11548 }
11549
11550 scf_service_destroy(svc);
11551 }
11552
11553 free(buf);
11554 scf_iter_destroy(iter);
11555 }
11556
11557 /*
11558 * Entity addition. Creates an empty entity in the current selection.
11559 */
11560 void
11561 lscf_add(const char *name)
11562 {
11563 lscf_prep_hndl();
11564
11565 if (cur_snap != NULL) {
11566 semerr(emsg_cant_modify_snapshots);
11567 } else if (cur_inst != NULL) {
11568 semerr(gettext("Cannot add entities to an instance.\n"));
11569 } else if (cur_svc != NULL) {
11570
11571 if (scf_service_add_instance(cur_svc, name, NULL) !=
11572 SCF_SUCCESS) {
11573 switch (scf_error()) {
11574 case SCF_ERROR_INVALID_ARGUMENT:
11575 semerr(gettext("Invalid name.\n"));
11576 break;
11577
11578 case SCF_ERROR_EXISTS:
11579 semerr(gettext("Instance already exists.\n"));
11580 break;
11581
11582 case SCF_ERROR_PERMISSION_DENIED:
11583 semerr(emsg_permission_denied);
11584 break;
11585
11586 default:
11587 scfdie();
11588 }
11589 }
11590 } else {
11591 assert(cur_scope != NULL);
11592
11593 if (scf_scope_add_service(cur_scope, name, NULL) !=
11594 SCF_SUCCESS) {
11595 switch (scf_error()) {
11596 case SCF_ERROR_INVALID_ARGUMENT:
11597 semerr(gettext("Invalid name.\n"));
11598 break;
11599
11600 case SCF_ERROR_EXISTS:
11601 semerr(gettext("Service already exists.\n"));
11602 break;
11603
11604 case SCF_ERROR_PERMISSION_DENIED:
11605 semerr(emsg_permission_denied);
11606 break;
11607
11608 case SCF_ERROR_BACKEND_READONLY:
11609 semerr(emsg_read_only);
11610 break;
11611
11612 default:
11613 scfdie();
11614 }
11615 }
11616 }
11617 }
11618
11619 /* return 1 if the entity has no persistent pgs, else return 0 */
11620 static int
11621 entity_has_no_pgs(void *ent, int isservice)
11622 {
11623 scf_iter_t *iter = NULL;
11624 scf_propertygroup_t *pg = NULL;
11625 uint32_t flags;
11626 int err;
11627 int ret = 1;
11628
11629 if ((iter = scf_iter_create(g_hndl)) == NULL ||
11630 (pg = scf_pg_create(g_hndl)) == NULL)
11631 scfdie();
11632
11633 if (isservice) {
11634 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11635 scfdie();
11636 } else {
11637 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11638 scfdie();
11639 }
11640
11641 while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11642 if (scf_pg_get_flags(pg, &flags) != 0)
11643 scfdie();
11644
11645 /* skip nonpersistent pgs */
11646 if (flags & SCF_PG_FLAG_NONPERSISTENT)
11647 continue;
11648
11649 ret = 0;
11650 break;
11651 }
11652
11653 if (err == -1)
11654 scfdie();
11655
11656 scf_pg_destroy(pg);
11657 scf_iter_destroy(iter);
11658
11659 return (ret);
11660 }
11661
11662 /* return 1 if the service has no instances, else return 0 */
11663 static int
11664 svc_has_no_insts(scf_service_t *svc)
11665 {
11666 scf_instance_t *inst;
11667 scf_iter_t *iter;
11668 int r;
11669 int ret = 1;
11670
11671 if ((inst = scf_instance_create(g_hndl)) == NULL ||
11672 (iter = scf_iter_create(g_hndl)) == NULL)
11673 scfdie();
11674
11675 if (scf_iter_service_instances(iter, svc) != 0)
11676 scfdie();
11677
11678 r = scf_iter_next_instance(iter, inst);
11679 if (r == 1) {
11680 ret = 0;
11681 } else if (r == 0) {
11682 ret = 1;
11683 } else if (r == -1) {
11684 scfdie();
11685 } else {
11686 bad_error("scf_iter_next_instance", r);
11687 }
11688
11689 scf_iter_destroy(iter);
11690 scf_instance_destroy(inst);
11691
11692 return (ret);
11693 }
11694
11695 /*
11696 * Entity deletion.
11697 */
11698
11699 /*
11700 * Delete the property group <fmri>/:properties/<name>. Returns
11701 * SCF_ERROR_NONE on success (or if the entity is not found),
11702 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
11703 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
11704 * denied.
11705 */
11706 static scf_error_t
11707 delete_dependency_pg(const char *fmri, const char *name)
11708 {
11709 void *entity = NULL;
11710 int isservice;
11711 scf_propertygroup_t *pg = NULL;
11712 scf_error_t result;
11713 char *pgty;
11714 scf_service_t *svc = NULL;
11715 scf_instance_t *inst = NULL;
11716 scf_iter_t *iter = NULL;
11717 char *name_buf = NULL;
11718
11719 result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
11720 switch (result) {
11721 case SCF_ERROR_NONE:
11722 break;
11723
11724 case SCF_ERROR_NO_MEMORY:
11725 uu_die(gettext("Out of memory.\n"));
11726 /* NOTREACHED */
11727
11728 case SCF_ERROR_INVALID_ARGUMENT:
11729 case SCF_ERROR_CONSTRAINT_VIOLATED:
11730 return (SCF_ERROR_INVALID_ARGUMENT);
11731
11732 case SCF_ERROR_NOT_FOUND:
11733 result = SCF_ERROR_NONE;
11734 goto out;
11735
11736 default:
11737 bad_error("fmri_to_entity", result);
11738 }
11739
11740 pg = scf_pg_create(g_hndl);
11741 if (pg == NULL)
11742 scfdie();
11743
11744 if (entity_get_pg(entity, isservice, name, pg) != 0) {
11745 if (scf_error() != SCF_ERROR_NOT_FOUND)
11746 scfdie();
11747
11748 result = SCF_ERROR_NONE;
11749 goto out;
11750 }
11751
11752 pgty = safe_malloc(max_scf_pg_type_len + 1);
11753
11754 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
11755 scfdie();
11756
11757 if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
11758 result = SCF_ERROR_TYPE_MISMATCH;
11759 free(pgty);
11760 goto out;
11761 }
11762
11763 free(pgty);
11764
11765 if (scf_pg_delete(pg) != 0) {
11766 result = scf_error();
11767 if (result != SCF_ERROR_PERMISSION_DENIED)
11768 scfdie();
11769 goto out;
11770 }
11771
11772 /*
11773 * We have to handle the case where we've just deleted the last
11774 * property group of a "dummy" entity (instance or service).
11775 * A "dummy" entity is an entity only present to hold an
11776 * external dependency.
11777 * So, in the case we deleted the last property group then we
11778 * can also delete the entity. If the entity is an instance then
11779 * we must verify if this was the last instance for the service
11780 * and if it is, we can also delete the service if it doesn't
11781 * have any property group either.
11782 */
11783
11784 result = SCF_ERROR_NONE;
11785
11786 if (isservice) {
11787 svc = (scf_service_t *)entity;
11788
11789 if ((inst = scf_instance_create(g_hndl)) == NULL ||
11790 (iter = scf_iter_create(g_hndl)) == NULL)
11791 scfdie();
11792
11793 name_buf = safe_malloc(max_scf_name_len + 1);
11794 } else {
11795 inst = (scf_instance_t *)entity;
11796 }
11797
11798 /*
11799 * If the entity is an instance and we've just deleted its last
11800 * property group then we should delete it.
11801 */
11802 if (!isservice && entity_has_no_pgs(entity, isservice)) {
11803 /* find the service before deleting the inst. - needed later */
11804 if ((svc = scf_service_create(g_hndl)) == NULL)
11805 scfdie();
11806
11807 if (scf_instance_get_parent(inst, svc) != 0)
11808 scfdie();
11809
11810 /* delete the instance */
11811 if (scf_instance_delete(inst) != 0) {
11812 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11813 scfdie();
11814
11815 result = SCF_ERROR_PERMISSION_DENIED;
11816 goto out;
11817 }
11818 /* no need to refresh the instance */
11819 inst = NULL;
11820 }
11821
11822 /*
11823 * If the service has no more instances and pgs or we just deleted the
11824 * last instance and the service doesn't have anymore propery groups
11825 * then the service should be deleted.
11826 */
11827 if (svc != NULL &&
11828 svc_has_no_insts(svc) &&
11829 entity_has_no_pgs((void *)svc, 1)) {
11830 if (scf_service_delete(svc) == 0) {
11831 if (isservice) {
11832 /* no need to refresh the service */
11833 svc = NULL;
11834 }
11835
11836 goto out;
11837 }
11838
11839 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11840 scfdie();
11841
11842 result = SCF_ERROR_PERMISSION_DENIED;
11843 }
11844
11845 /* if the entity has not been deleted, refresh it */
11846 if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
11847 (void) refresh_entity(isservice, entity, fmri, inst, iter,
11848 name_buf);
11849 }
11850
11851 out:
11852 if (isservice && (inst != NULL && iter != NULL)) {
11853 free(name_buf);
11854 scf_iter_destroy(iter);
11855 scf_instance_destroy(inst);
11856 }
11857
11858 if (!isservice && svc != NULL) {
11859 scf_service_destroy(svc);
11860 }
11861
11862 scf_pg_destroy(pg);
11863 if (entity != NULL)
11864 entity_destroy(entity, isservice);
11865
11866 return (result);
11867 }
11868
11869 static int
11870 delete_dependents(scf_propertygroup_t *pg)
11871 {
11872 char *pgty, *name, *fmri;
11873 scf_property_t *prop;
11874 scf_value_t *val;
11875 scf_iter_t *iter;
11876 int r;
11877 scf_error_t err;
11878
11879 /* Verify that the pg has the correct type. */
11880 pgty = safe_malloc(max_scf_pg_type_len + 1);
11881 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
11882 scfdie();
11883
11884 if (strcmp(pgty, scf_group_framework) != 0) {
11885 if (g_verbose) {
11886 fmri = safe_malloc(max_scf_fmri_len + 1);
11887 if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
11888 scfdie();
11889
11890 warn(gettext("Property group %s is not of expected "
11891 "type %s.\n"), fmri, scf_group_framework);
11892
11893 free(fmri);
11894 }
11895
11896 free(pgty);
11897 return (-1);
11898 }
11899
11900 free(pgty);
11901
11902 /* map delete_dependency_pg onto the properties. */
11903 if ((prop = scf_property_create(g_hndl)) == NULL ||
11904 (val = scf_value_create(g_hndl)) == NULL ||
11905 (iter = scf_iter_create(g_hndl)) == NULL)
11906 scfdie();
11907
11908 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
11909 scfdie();
11910
11911 name = safe_malloc(max_scf_name_len + 1);
11912 fmri = safe_malloc(max_scf_fmri_len + 2);
11913
11914 while ((r = scf_iter_next_property(iter, prop)) == 1) {
11915 scf_type_t ty;
11916
11917 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
11918 scfdie();
11919
11920 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
11921 scfdie();
11922
11923 if ((ty != SCF_TYPE_ASTRING &&
11924 prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
11925 prop_get_val(prop, val) != 0)
11926 continue;
11927
11928 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
11929 scfdie();
11930
11931 err = delete_dependency_pg(fmri, name);
11932 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
11933 if (scf_property_to_fmri(prop, fmri,
11934 max_scf_fmri_len + 2) < 0)
11935 scfdie();
11936
11937 warn(gettext("Value of %s is not a valid FMRI.\n"),
11938 fmri);
11939 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
11940 warn(gettext("Property group \"%s\" of entity \"%s\" "
11941 "does not have dependency type.\n"), name, fmri);
11942 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
11943 warn(gettext("Could not delete property group \"%s\" "
11944 "of entity \"%s\" (permission denied).\n"), name,
11945 fmri);
11946 }
11947 }
11948 if (r == -1)
11949 scfdie();
11950
11951 scf_value_destroy(val);
11952 scf_property_destroy(prop);
11953
11954 return (0);
11955 }
11956
11957 /*
11958 * Returns 1 if the instance may be running, and 0 otherwise.
11959 */
11960 static int
11961 inst_is_running(scf_instance_t *inst)
11962 {
11963 scf_propertygroup_t *pg;
11964 scf_property_t *prop;
11965 scf_value_t *val;
11966 char buf[MAX_SCF_STATE_STRING_SZ];
11967 int ret = 0;
11968 ssize_t szret;
11969
11970 if ((pg = scf_pg_create(g_hndl)) == NULL ||
11971 (prop = scf_property_create(g_hndl)) == NULL ||
11972 (val = scf_value_create(g_hndl)) == NULL)
11973 scfdie();
11974
11975 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
11976 if (scf_error() != SCF_ERROR_NOT_FOUND)
11977 scfdie();
11978 goto out;
11979 }
11980
11981 if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
11982 prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
11983 prop_get_val(prop, val) != 0)
11984 goto out;
11985
11986 szret = scf_value_get_astring(val, buf, sizeof (buf));
11987 assert(szret >= 0);
11988
11989 ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
11990 strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
11991
11992 out:
11993 scf_value_destroy(val);
11994 scf_property_destroy(prop);
11995 scf_pg_destroy(pg);
11996 return (ret);
11997 }
11998
11999 static uint8_t
12000 pg_is_external_dependency(scf_propertygroup_t *pg)
12001 {
12002 char *type;
12003 scf_value_t *val;
12004 scf_property_t *prop;
12005 uint8_t b = B_FALSE;
12006
12007 type = safe_malloc(max_scf_pg_type_len + 1);
12008
12009 if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
12010 scfdie();
12011
12012 if ((prop = scf_property_create(g_hndl)) == NULL ||
12013 (val = scf_value_create(g_hndl)) == NULL)
12014 scfdie();
12015
12016 if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
12017 if (pg_get_prop(pg, scf_property_external, prop) == 0) {
12018 if (scf_property_get_value(prop, val) != 0)
12019 scfdie();
12020 if (scf_value_get_boolean(val, &b) != 0)
12021 scfdie();
12022 }
12023 }
12024
12025 free(type);
12026 (void) scf_value_destroy(val);
12027 (void) scf_property_destroy(prop);
12028
12029 return (b);
12030 }
12031
12032 #define DELETE_FAILURE -1
12033 #define DELETE_SUCCESS_NOEXTDEPS 0
12034 #define DELETE_SUCCESS_EXTDEPS 1
12035
12036 /*
12037 * lscf_instance_delete() deletes an instance. Before calling
12038 * scf_instance_delete(), though, we make sure the instance isn't
12039 * running and delete dependencies in other entities which the instance
12040 * declared as "dependents". If there are dependencies which were
12041 * created for other entities, then instead of deleting the instance we
12042 * make it "empty" by deleting all other property groups and all
12043 * snapshots.
12044 *
12045 * lscf_instance_delete() verifies that there is no external dependency pgs
12046 * before suppressing the instance. If there is, then we must not remove them
12047 * now in case the instance is re-created otherwise the dependencies would be
12048 * lost. The external dependency pgs will be removed if the dependencies are
12049 * removed.
12050 *
12051 * Returns:
12052 * DELETE_FAILURE on failure
12053 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12054 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12055 */
12056 static int
12057 lscf_instance_delete(scf_instance_t *inst, int force)
12058 {
12059 scf_propertygroup_t *pg;
12060 scf_snapshot_t *snap;
12061 scf_iter_t *iter;
12062 int err;
12063 int external = 0;
12064
12065 /* If we're not forcing and the instance is running, refuse. */
12066 if (!force && inst_is_running(inst)) {
12067 char *fmri;
12068
12069 fmri = safe_malloc(max_scf_fmri_len + 1);
12070
12071 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
12072 scfdie();
12073
12074 semerr(gettext("Instance %s may be running. "
12075 "Use delete -f if it is not.\n"), fmri);
12076
12077 free(fmri);
12078 return (DELETE_FAILURE);
12079 }
12080
12081 pg = scf_pg_create(g_hndl);
12082 if (pg == NULL)
12083 scfdie();
12084
12085 if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
12086 (void) delete_dependents(pg);
12087 else if (scf_error() != SCF_ERROR_NOT_FOUND)
12088 scfdie();
12089
12090 scf_pg_destroy(pg);
12091
12092 /*
12093 * If the instance has some external dependencies then we must
12094 * keep them in case the instance is reimported otherwise the
12095 * dependencies would be lost on reimport.
12096 */
12097 if ((iter = scf_iter_create(g_hndl)) == NULL ||
12098 (pg = scf_pg_create(g_hndl)) == NULL)
12099 scfdie();
12100
12101 if (scf_iter_instance_pgs(iter, inst) < 0)
12102 scfdie();
12103
12104 while ((err = scf_iter_next_pg(iter, pg)) == 1) {
12105 if (pg_is_external_dependency(pg)) {
12106 external = 1;
12107 continue;
12108 }
12109
12110 if (scf_pg_delete(pg) != 0) {
12111 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12112 scfdie();
12113 else {
12114 semerr(emsg_permission_denied);
12115
12116 (void) scf_iter_destroy(iter);
12117 (void) scf_pg_destroy(pg);
12118 return (DELETE_FAILURE);
12119 }
12120 }
12121 }
12122
12123 if (err == -1)
12124 scfdie();
12125
12126 (void) scf_iter_destroy(iter);
12127 (void) scf_pg_destroy(pg);
12128
12129 if (external) {
12130 /*
12131 * All the pgs have been deleted for the instance except
12132 * the ones holding the external dependencies.
12133 * For the job to be complete, we must also delete the
12134 * snapshots associated with the instance.
12135 */
12136 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
12137 NULL)
12138 scfdie();
12139 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
12140 scfdie();
12141
12142 if (scf_iter_instance_snapshots(iter, inst) == -1)
12143 scfdie();
12144
12145 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
12146 if (_scf_snapshot_delete(snap) != 0) {
12147 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12148 scfdie();
12149
12150 semerr(emsg_permission_denied);
12151
12152 (void) scf_iter_destroy(iter);
12153 (void) scf_snapshot_destroy(snap);
12154 return (DELETE_FAILURE);
12155 }
12156 }
12157
12158 if (err == -1)
12159 scfdie();
12160
12161 (void) scf_iter_destroy(iter);
12162 (void) scf_snapshot_destroy(snap);
12163 return (DELETE_SUCCESS_EXTDEPS);
12164 }
12165
12166 if (scf_instance_delete(inst) != 0) {
12167 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12168 scfdie();
12169
12170 semerr(emsg_permission_denied);
12171
12172 return (DELETE_FAILURE);
12173 }
12174
12175 return (DELETE_SUCCESS_NOEXTDEPS);
12176 }
12177
12178 /*
12179 * lscf_service_delete() deletes a service. Before calling
12180 * scf_service_delete(), though, we call lscf_instance_delete() for
12181 * each of the instances and delete dependencies in other entities
12182 * which were created as "dependents" of this service. If there are
12183 * dependencies which were created for other entities, then we delete
12184 * all other property groups in the service and leave it as "empty".
12185 *
12186 * lscf_service_delete() verifies that there is no external dependency
12187 * pgs at the instance & service level before suppressing the service.
12188 * If there is, then we must not remove them now in case the service
12189 * is re-imported otherwise the dependencies would be lost. The external
12190 * dependency pgs will be removed if the dependencies are removed.
12191 *
12192 * Returns:
12193 * DELETE_FAILURE on failure
12194 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12195 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12196 */
12197 static int
12198 lscf_service_delete(scf_service_t *svc, int force)
12199 {
12200 int r;
12201 scf_instance_t *inst;
12202 scf_propertygroup_t *pg;
12203 scf_iter_t *iter;
12204 int ret;
12205 int external = 0;
12206
12207 if ((inst = scf_instance_create(g_hndl)) == NULL ||
12208 (pg = scf_pg_create(g_hndl)) == NULL ||
12209 (iter = scf_iter_create(g_hndl)) == NULL)
12210 scfdie();
12211
12212 if (scf_iter_service_instances(iter, svc) != 0)
12213 scfdie();
12214
12215 for (r = scf_iter_next_instance(iter, inst);
12216 r == 1;
12217 r = scf_iter_next_instance(iter, inst)) {
12218
12219 ret = lscf_instance_delete(inst, force);
12220 if (ret == DELETE_FAILURE) {
12221 scf_iter_destroy(iter);
12222 scf_pg_destroy(pg);
12223 scf_instance_destroy(inst);
12224 return (DELETE_FAILURE);
12225 }
12226
12227 /*
12228 * Record the fact that there is some external dependencies
12229 * at the instance level.
12230 */
12231 if (ret == DELETE_SUCCESS_EXTDEPS)
12232 external |= 1;
12233 }
12234
12235 if (r != 0)
12236 scfdie();
12237
12238 /* Delete dependency property groups in dependent services. */
12239 if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12240 (void) delete_dependents(pg);
12241 else if (scf_error() != SCF_ERROR_NOT_FOUND)
12242 scfdie();
12243
12244 scf_iter_destroy(iter);
12245 scf_pg_destroy(pg);
12246 scf_instance_destroy(inst);
12247
12248 /*
12249 * If the service has some external dependencies then we don't
12250 * want to remove them in case the service is re-imported.
12251 */
12252 if ((pg = scf_pg_create(g_hndl)) == NULL ||
12253 (iter = scf_iter_create(g_hndl)) == NULL)
12254 scfdie();
12255
12256 if (scf_iter_service_pgs(iter, svc) < 0)
12257 scfdie();
12258
12259 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12260 if (pg_is_external_dependency(pg)) {
12261 external |= 2;
12262 continue;
12263 }
12264
12265 if (scf_pg_delete(pg) != 0) {
12266 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12267 scfdie();
12268 else {
12269 semerr(emsg_permission_denied);
12270
12271 (void) scf_iter_destroy(iter);
12272 (void) scf_pg_destroy(pg);
12273 return (DELETE_FAILURE);
12274 }
12275 }
12276 }
12277
12278 if (r == -1)
12279 scfdie();
12280
12281 (void) scf_iter_destroy(iter);
12282 (void) scf_pg_destroy(pg);
12283
12284 if (external != 0)
12285 return (DELETE_SUCCESS_EXTDEPS);
12286
12287 if (scf_service_delete(svc) == 0)
12288 return (DELETE_SUCCESS_NOEXTDEPS);
12289
12290 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12291 scfdie();
12292
12293 semerr(emsg_permission_denied);
12294 return (DELETE_FAILURE);
12295 }
12296
12297 static int
12298 delete_callback(void *data, scf_walkinfo_t *wip)
12299 {
12300 int force = (int)data;
12301
12302 if (wip->inst != NULL)
12303 (void) lscf_instance_delete(wip->inst, force);
12304 else
12305 (void) lscf_service_delete(wip->svc, force);
12306
12307 return (0);
12308 }
12309
12310 void
12311 lscf_delete(const char *fmri, int force)
12312 {
12313 scf_service_t *svc;
12314 scf_instance_t *inst;
12315 int ret;
12316
12317 lscf_prep_hndl();
12318
12319 if (cur_snap != NULL) {
12320 if (!snaplevel_is_instance(cur_level)) {
12321 char *buf;
12322
12323 buf = safe_malloc(max_scf_name_len + 1);
12324 if (scf_instance_get_name(cur_inst, buf,
12325 max_scf_name_len + 1) >= 0) {
12326 if (strcmp(buf, fmri) == 0) {
12327 semerr(emsg_cant_modify_snapshots);
12328 free(buf);
12329 return;
12330 }
12331 } else if (scf_error() != SCF_ERROR_DELETED) {
12332 scfdie();
12333 }
12334 free(buf);
12335 }
12336 } else if (cur_inst != NULL) {
12337 /* EMPTY */;
12338 } else if (cur_svc != NULL) {
12339 inst = scf_instance_create(g_hndl);
12340 if (inst == NULL)
12341 scfdie();
12342
12343 if (scf_service_get_instance(cur_svc, fmri, inst) ==
12344 SCF_SUCCESS) {
12345 (void) lscf_instance_delete(inst, force);
12346 scf_instance_destroy(inst);
12347 return;
12348 }
12349
12350 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12351 scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12352 scfdie();
12353
12354 scf_instance_destroy(inst);
12355 } else {
12356 assert(cur_scope != NULL);
12357
12358 svc = scf_service_create(g_hndl);
12359 if (svc == NULL)
12360 scfdie();
12361
12362 if (scf_scope_get_service(cur_scope, fmri, svc) ==
12363 SCF_SUCCESS) {
12364 (void) lscf_service_delete(svc, force);
12365 scf_service_destroy(svc);
12366 return;
12367 }
12368
12369 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12370 scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12371 scfdie();
12372
12373 scf_service_destroy(svc);
12374 }
12375
12376 /*
12377 * Match FMRI to entity.
12378 */
12379 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12380 delete_callback, (void *)force, NULL, semerr)) != 0) {
12381 semerr(gettext("Failed to walk instances: %s\n"),
12382 scf_strerror(ret));
12383 }
12384 }
12385
12386
12387
12388 /*
12389 * :properties commands. These all end with "pg" or "prop" and generally
12390 * operate on the currently selected entity.
12391 */
12392
12393 /*
12394 * Property listing. List the property groups, properties, their types and
12395 * their values for the currently selected entity.
12396 */
12397 static void
12398 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12399 {
12400 char *buf;
12401 uint32_t flags;
12402
12403 buf = safe_malloc(max_scf_pg_type_len + 1);
12404
12405 if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12406 scfdie();
12407
12408 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12409 scfdie();
12410
12411 safe_printf("%-*s %s", namewidth, name, buf);
12412
12413 if (flags & SCF_PG_FLAG_NONPERSISTENT)
12414 safe_printf("\tNONPERSISTENT");
12415
12416 safe_printf("\n");
12417
12418 free(buf);
12419 }
12420
12421 static boolean_t
12422 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12423 {
12424 if (scf_property_get_value(prop, val) == 0) {
12425 return (B_FALSE);
12426 } else {
12427 switch (scf_error()) {
12428 case SCF_ERROR_NOT_FOUND:
12429 return (B_FALSE);
12430 case SCF_ERROR_PERMISSION_DENIED:
12431 case SCF_ERROR_CONSTRAINT_VIOLATED:
12432 return (B_TRUE);
12433 default:
12434 scfdie();
12435 /*NOTREACHED*/
12436 }
12437 }
12438 }
12439
12440 static void
12441 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12442 {
12443 scf_iter_t *iter;
12444 scf_value_t *val;
12445 const char *type;
12446 int multiple_strings = 0;
12447 int ret;
12448
12449 if ((iter = scf_iter_create(g_hndl)) == NULL ||
12450 (val = scf_value_create(g_hndl)) == NULL)
12451 scfdie();
12452
12453 type = prop_to_typestr(prop);
12454 assert(type != NULL);
12455
12456 safe_printf("%-*s %-7s ", len, name, type);
12457
12458 if (prop_has_multiple_values(prop, val) &&
12459 (scf_value_type(val) == SCF_TYPE_ASTRING ||
12460 scf_value_type(val) == SCF_TYPE_USTRING))
12461 multiple_strings = 1;
12462
12463 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12464 scfdie();
12465
12466 while ((ret = scf_iter_next_value(iter, val)) == 1) {
12467 char *buf;
12468 ssize_t vlen, szret;
12469
12470 vlen = scf_value_get_as_string(val, NULL, 0);
12471 if (vlen < 0)
12472 scfdie();
12473
12474 buf = safe_malloc(vlen + 1);
12475
12476 szret = scf_value_get_as_string(val, buf, vlen + 1);
12477 if (szret < 0)
12478 scfdie();
12479 assert(szret <= vlen);
12480
12481 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12482 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12483 safe_printf(" \"");
12484 (void) quote_and_print(buf, stdout, 0);
12485 (void) putchar('"');
12486 if (ferror(stdout)) {
12487 (void) putchar('\n');
12488 uu_die(gettext("Error writing to stdout.\n"));
12489 }
12490 } else {
12491 safe_printf(" %s", buf);
12492 }
12493
12494 free(buf);
12495 }
12496 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12497 scfdie();
12498
12499 if (putchar('\n') != '\n')
12500 uu_die(gettext("Could not output newline"));
12501 }
12502
12503 /*
12504 * Outputs template property group info for the describe subcommand.
12505 * If 'templates' == 2, verbose output is printed in the format expected
12506 * for describe -v, which includes all templates fields. If pg is
12507 * not NULL, we're describing the template data, not an existing property
12508 * group, and formatting should be appropriate for describe -t.
12509 */
12510 static void
12511 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12512 {
12513 char *buf;
12514 uint8_t required;
12515 scf_property_t *stability_prop;
12516 scf_value_t *stability_val;
12517
12518 if (templates == 0)
12519 return;
12520
12521 if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12522 (stability_val = scf_value_create(g_hndl)) == NULL)
12523 scfdie();
12524
12525 if (templates == 2 && pg != NULL) {
12526 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12527 stability_prop) == 0) {
12528 if (prop_check_type(stability_prop,
12529 SCF_TYPE_ASTRING) == 0 &&
12530 prop_get_val(stability_prop, stability_val) == 0) {
12531 char *stability;
12532
12533 stability = safe_malloc(max_scf_value_len + 1);
12534
12535 if (scf_value_get_astring(stability_val,
12536 stability, max_scf_value_len + 1) == -1 &&
12537 scf_error() != SCF_ERROR_NOT_FOUND)
12538 scfdie();
12539
12540 safe_printf("%s%s: %s\n", TMPL_INDENT,
12541 gettext("stability"), stability);
12542
12543 free(stability);
12544 }
12545 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
12546 scfdie();
12547 }
12548
12549 scf_property_destroy(stability_prop);
12550 scf_value_destroy(stability_val);
12551
12552 if (pgt == NULL)
12553 return;
12554
12555 if (pg == NULL || templates == 2) {
12556 /* print type info only if scf_tmpl_pg_name succeeds */
12557 if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12558 if (pg != NULL)
12559 safe_printf("%s", TMPL_INDENT);
12560 safe_printf("%s: ", gettext("name"));
12561 safe_printf("%s\n", buf);
12562 free(buf);
12563 }
12564
12565 /* print type info only if scf_tmpl_pg_type succeeds */
12566 if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12567 if (pg != NULL)
12568 safe_printf("%s", TMPL_INDENT);
12569 safe_printf("%s: ", gettext("type"));
12570 safe_printf("%s\n", buf);
12571 free(buf);
12572 }
12573 }
12574
12575 if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12576 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12577 required ? "true" : "false");
12578
12579 if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12580 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12581 buf);
12582 free(buf);
12583 }
12584
12585 if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12586 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12587 buf);
12588 free(buf);
12589 }
12590
12591 if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12592 if (templates == 2)
12593 safe_printf("%s%s: %s\n", TMPL_INDENT,
12594 gettext("description"), buf);
12595 else
12596 safe_printf("%s%s\n", TMPL_INDENT, buf);
12597 free(buf);
12598 }
12599
12600 }
12601
12602 /*
12603 * With as_value set to true, indent as appropriate for the value level.
12604 * If false, indent to appropriate level for inclusion in constraint
12605 * or choice printout.
12606 */
12607 static void
12608 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12609 int as_value)
12610 {
12611 char *buf;
12612
12613 if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12614 if (as_value == 0)
12615 safe_printf("%s", TMPL_CHOICE_INDENT);
12616 else
12617 safe_printf("%s", TMPL_INDENT);
12618 safe_printf("%s: %s\n", gettext("value common name"), buf);
12619 free(buf);
12620 }
12621
12622 if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12623 if (as_value == 0)
12624 safe_printf("%s", TMPL_CHOICE_INDENT);
12625 else
12626 safe_printf("%s", TMPL_INDENT);
12627 safe_printf("%s: %s\n", gettext("value description"), buf);
12628 free(buf);
12629 }
12630 }
12631
12632 static void
12633 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12634 {
12635 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12636 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12637 safe_printf("%s\n", val_buf);
12638
12639 print_template_value_details(prt, val_buf, 1);
12640 }
12641
12642 static void
12643 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12644 {
12645 int i, printed = 0;
12646 scf_values_t values;
12647 scf_count_ranges_t c_ranges;
12648 scf_int_ranges_t i_ranges;
12649
12650 printed = 0;
12651 i = 0;
12652 if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12653 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12654 gettext("value constraints"));
12655 printed++;
12656 for (i = 0; i < values.value_count; ++i) {
12657 safe_printf("%s%s: %s\n", TMPL_INDENT,
12658 gettext("value name"), values.values_as_strings[i]);
12659 if (verbose == 1)
12660 print_template_value_details(prt,
12661 values.values_as_strings[i], 0);
12662 }
12663
12664 scf_values_destroy(&values);
12665 }
12666
12667 if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12668 if (printed++ == 0)
12669 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12670 gettext("value constraints"));
12671 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12672 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12673 gettext("range"), c_ranges.scr_min[i],
12674 c_ranges.scr_max[i]);
12675 }
12676 scf_count_ranges_destroy(&c_ranges);
12677 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12678 scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
12679 if (printed++ == 0)
12680 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12681 gettext("value constraints"));
12682 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12683 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12684 gettext("range"), i_ranges.sir_min[i],
12685 i_ranges.sir_max[i]);
12686 }
12687 scf_int_ranges_destroy(&i_ranges);
12688 }
12689 }
12690
12691 static void
12692 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
12693 {
12694 int i = 0, printed = 0;
12695 scf_values_t values;
12696 scf_count_ranges_t c_ranges;
12697 scf_int_ranges_t i_ranges;
12698
12699 printed = 0;
12700 if (scf_tmpl_value_name_choices(prt, &values) == 0) {
12701 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12702 gettext("value constraints"));
12703 printed++;
12704 for (i = 0; i < values.value_count; i++) {
12705 safe_printf("%s%s: %s\n", TMPL_INDENT,
12706 gettext("value name"), values.values_as_strings[i]);
12707 if (verbose == 1)
12708 print_template_value_details(prt,
12709 values.values_as_strings[i], 0);
12710 }
12711
12712 scf_values_destroy(&values);
12713 }
12714
12715 if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
12716 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12717 if (printed++ == 0)
12718 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12719 gettext("value choices"));
12720 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12721 gettext("range"), c_ranges.scr_min[i],
12722 c_ranges.scr_max[i]);
12723 }
12724 scf_count_ranges_destroy(&c_ranges);
12725 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12726 scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
12727 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12728 if (printed++ == 0)
12729 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12730 gettext("value choices"));
12731 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12732 gettext("range"), i_ranges.sir_min[i],
12733 i_ranges.sir_max[i]);
12734 }
12735 scf_int_ranges_destroy(&i_ranges);
12736 }
12737 }
12738
12739 static void
12740 list_values_by_template(scf_prop_tmpl_t *prt)
12741 {
12742 print_template_constraints(prt, 1);
12743 print_template_choices(prt, 1);
12744 }
12745
12746 static void
12747 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
12748 {
12749 char *val_buf;
12750 scf_iter_t *iter;
12751 scf_value_t *val;
12752 int ret;
12753
12754 if ((iter = scf_iter_create(g_hndl)) == NULL ||
12755 (val = scf_value_create(g_hndl)) == NULL)
12756 scfdie();
12757
12758 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12759 scfdie();
12760
12761 val_buf = safe_malloc(max_scf_value_len + 1);
12762
12763 while ((ret = scf_iter_next_value(iter, val)) == 1) {
12764 if (scf_value_get_as_string(val, val_buf,
12765 max_scf_value_len + 1) < 0)
12766 scfdie();
12767
12768 print_template_value(prt, val_buf);
12769 }
12770 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12771 scfdie();
12772 free(val_buf);
12773
12774 print_template_constraints(prt, 0);
12775 print_template_choices(prt, 0);
12776
12777 }
12778
12779 /*
12780 * Outputs property info for the describe subcommand
12781 * Verbose output if templates == 2, -v option of svccfg describe
12782 * Displays template data if prop is not NULL, -t option of svccfg describe
12783 */
12784 static void
12785 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
12786 {
12787 char *buf;
12788 uint8_t u_buf;
12789 int i;
12790 uint64_t min, max;
12791 scf_values_t values;
12792
12793 if (prt == NULL || templates == 0)
12794 return;
12795
12796 if (prop == NULL) {
12797 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
12798 if (scf_tmpl_prop_name(prt, &buf) > 0) {
12799 safe_printf("%s\n", buf);
12800 free(buf);
12801 } else
12802 safe_printf("(%s)\n", gettext("any"));
12803 }
12804
12805 if (prop == NULL || templates == 2) {
12806 if (prop != NULL)
12807 safe_printf("%s", TMPL_INDENT);
12808 else
12809 safe_printf("%s", TMPL_VALUE_INDENT);
12810 safe_printf("%s: ", gettext("type"));
12811 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
12812 safe_printf("%s\n", buf);
12813 free(buf);
12814 } else
12815 safe_printf("(%s)\n", gettext("any"));
12816 }
12817
12818 if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
12819 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12820 u_buf ? "true" : "false");
12821
12822 if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
12823 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12824 buf);
12825 free(buf);
12826 }
12827
12828 if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
12829 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
12830 buf);
12831 free(buf);
12832 }
12833
12834 if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
12835 safe_printf("%s%s\n", TMPL_INDENT, buf);
12836 free(buf);
12837 }
12838
12839 if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
12840 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
12841 scf_tmpl_visibility_to_string(u_buf));
12842
12843 if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
12844 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
12845 gettext("minimum number of values"), min);
12846 if (max == ULLONG_MAX) {
12847 safe_printf("%s%s: %s\n", TMPL_INDENT,
12848 gettext("maximum number of values"),
12849 gettext("unlimited"));
12850 } else {
12851 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
12852 gettext("maximum number of values"), max);
12853 }
12854 }
12855
12856 if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
12857 for (i = 0; i < values.value_count; i++) {
12858 if (i == 0) {
12859 safe_printf("%s%s:", TMPL_INDENT,
12860 gettext("internal separators"));
12861 }
12862 safe_printf(" \"%s\"", values.values_as_strings[i]);
12863 }
12864 safe_printf("\n");
12865 }
12866
12867 if (templates != 2)
12868 return;
12869
12870 if (prop != NULL)
12871 list_values_tmpl(prt, prop);
12872 else
12873 list_values_by_template(prt);
12874 }
12875
12876 static char *
12877 read_astring(scf_propertygroup_t *pg, const char *prop_name)
12878 {
12879 char *rv;
12880
12881 rv = _scf_read_single_astring_from_pg(pg, prop_name);
12882 if (rv == NULL) {
12883 switch (scf_error()) {
12884 case SCF_ERROR_NOT_FOUND:
12885 break;
12886 default:
12887 scfdie();
12888 }
12889 }
12890 return (rv);
12891 }
12892
12893 static void
12894 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
12895 {
12896 size_t doc_len;
12897 size_t man_len;
12898 char *pg_name;
12899 char *text = NULL;
12900 int rv;
12901
12902 doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
12903 man_len = strlen(SCF_PG_TM_MAN_PREFIX);
12904 pg_name = safe_malloc(max_scf_name_len + 1);
12905 while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
12906 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
12907 scfdie();
12908 }
12909 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
12910 /* Display doc_link and and uri */
12911 safe_printf("%s%s:\n", TMPL_INDENT,
12912 gettext("doc_link"));
12913 text = read_astring(pg, SCF_PROPERTY_TM_NAME);
12914 if (text != NULL) {
12915 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12916 TMPL_INDENT, gettext("name"), text);
12917 uu_free(text);
12918 }
12919 text = read_astring(pg, SCF_PROPERTY_TM_URI);
12920 if (text != NULL) {
12921 safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
12922 gettext("uri"), text);
12923 uu_free(text);
12924 }
12925 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
12926 man_len) == 0) {
12927 /* Display manpage title, section and path */
12928 safe_printf("%s%s:\n", TMPL_INDENT,
12929 gettext("manpage"));
12930 text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
12931 if (text != NULL) {
12932 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12933 TMPL_INDENT, gettext("title"), text);
12934 uu_free(text);
12935 }
12936 text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
12937 if (text != NULL) {
12938 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12939 TMPL_INDENT, gettext("section"), text);
12940 uu_free(text);
12941 }
12942 text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
12943 if (text != NULL) {
12944 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12945 TMPL_INDENT, gettext("manpath"), text);
12946 uu_free(text);
12947 }
12948 }
12949 }
12950 if (rv == -1)
12951 scfdie();
12952
12953 done:
12954 free(pg_name);
12955 }
12956
12957 static void
12958 list_entity_tmpl(int templates)
12959 {
12960 char *common_name = NULL;
12961 char *description = NULL;
12962 char *locale = NULL;
12963 scf_iter_t *iter;
12964 scf_propertygroup_t *pg;
12965 scf_property_t *prop;
12966 int r;
12967 scf_value_t *val;
12968
12969 if ((pg = scf_pg_create(g_hndl)) == NULL ||
12970 (prop = scf_property_create(g_hndl)) == NULL ||
12971 (val = scf_value_create(g_hndl)) == NULL ||
12972 (iter = scf_iter_create(g_hndl)) == NULL)
12973 scfdie();
12974
12975 locale = setlocale(LC_MESSAGES, NULL);
12976
12977 if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
12978 common_name = safe_malloc(max_scf_value_len + 1);
12979
12980 /* Try both the current locale and the "C" locale. */
12981 if (scf_pg_get_property(pg, locale, prop) == 0 ||
12982 (scf_error() == SCF_ERROR_NOT_FOUND &&
12983 scf_pg_get_property(pg, "C", prop) == 0)) {
12984 if (prop_get_val(prop, val) == 0 &&
12985 scf_value_get_ustring(val, common_name,
12986 max_scf_value_len + 1) != -1) {
12987 safe_printf("%s%s: %s\n", TMPL_INDENT,
12988 gettext("common name"), common_name);
12989 }
12990 }
12991 }
12992
12993 /*
12994 * Do description, manpages, and doc links if templates == 2.
12995 */
12996 if (templates == 2) {
12997 /* Get the description. */
12998 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
12999 description = safe_malloc(max_scf_value_len + 1);
13000
13001 /* Try both the current locale and the "C" locale. */
13002 if (scf_pg_get_property(pg, locale, prop) == 0 ||
13003 (scf_error() == SCF_ERROR_NOT_FOUND &&
13004 scf_pg_get_property(pg, "C", prop) == 0)) {
13005 if (prop_get_val(prop, val) == 0 &&
13006 scf_value_get_ustring(val, description,
13007 max_scf_value_len + 1) != -1) {
13008 safe_printf("%s%s: %s\n", TMPL_INDENT,
13009 gettext("description"),
13010 description);
13011 }
13012 }
13013 }
13014
13015 /* Process doc_link & manpage elements. */
13016 if (cur_level != NULL) {
13017 r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
13018 SCF_GROUP_TEMPLATE);
13019 } else if (cur_inst != NULL) {
13020 r = scf_iter_instance_pgs_typed(iter, cur_inst,
13021 SCF_GROUP_TEMPLATE);
13022 } else {
13023 r = scf_iter_service_pgs_typed(iter, cur_svc,
13024 SCF_GROUP_TEMPLATE);
13025 }
13026 if (r == 0) {
13027 display_documentation(iter, pg);
13028 }
13029 }
13030
13031 free(common_name);
13032 free(description);
13033 scf_pg_destroy(pg);
13034 scf_property_destroy(prop);
13035 scf_value_destroy(val);
13036 scf_iter_destroy(iter);
13037 }
13038
13039 static void
13040 listtmpl(const char *pattern, int templates)
13041 {
13042 scf_pg_tmpl_t *pgt;
13043 scf_prop_tmpl_t *prt;
13044 char *snapbuf = NULL;
13045 char *fmribuf;
13046 char *pg_name = NULL, *prop_name = NULL;
13047 ssize_t prop_name_size;
13048 char *qual_prop_name;
13049 char *search_name;
13050 int listed = 0;
13051
13052 if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13053 (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
13054 scfdie();
13055
13056 fmribuf = safe_malloc(max_scf_name_len + 1);
13057 qual_prop_name = safe_malloc(max_scf_name_len + 1);
13058
13059 if (cur_snap != NULL) {
13060 snapbuf = safe_malloc(max_scf_name_len + 1);
13061 if (scf_snapshot_get_name(cur_snap, snapbuf,
13062 max_scf_name_len + 1) < 0)
13063 scfdie();
13064 }
13065
13066 if (cur_inst != NULL) {
13067 if (scf_instance_to_fmri(cur_inst, fmribuf,
13068 max_scf_name_len + 1) < 0)
13069 scfdie();
13070 } else if (cur_svc != NULL) {
13071 if (scf_service_to_fmri(cur_svc, fmribuf,
13072 max_scf_name_len + 1) < 0)
13073 scfdie();
13074 } else
13075 abort();
13076
13077 /* If pattern is specified, we want to list only those items. */
13078 while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) {
13079 listed = 0;
13080 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
13081 fnmatch(pattern, pg_name, 0) == 0)) {
13082 list_pg_tmpl(pgt, NULL, templates);
13083 listed++;
13084 }
13085
13086 scf_tmpl_prop_reset(prt);
13087
13088 while (scf_tmpl_iter_props(pgt, prt, 0) == 0) {
13089 search_name = NULL;
13090 prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
13091 if ((prop_name_size > 0) && (pg_name != NULL)) {
13092 if (snprintf(qual_prop_name,
13093 max_scf_name_len + 1, "%s/%s",
13094 pg_name, prop_name) >=
13095 max_scf_name_len + 1) {
13096 prop_name_size = -1;
13097 } else {
13098 search_name = qual_prop_name;
13099 }
13100 }
13101 if (listed > 0 || pattern == NULL ||
13102 (prop_name_size > 0 &&
13103 fnmatch(pattern, search_name,
13104 FNM_PATHNAME) == 0))
13105 list_prop_tmpl(prt, NULL, templates);
13106 if (prop_name != NULL) {
13107 free(prop_name);
13108 prop_name = NULL;
13109 }
13110 }
13111 if (pg_name != NULL) {
13112 free(pg_name);
13113 pg_name = NULL;
13114 }
13115 }
13116
13117 scf_tmpl_prop_destroy(prt);
13118 scf_tmpl_pg_destroy(pgt);
13119 free(snapbuf);
13120 free(fmribuf);
13121 free(qual_prop_name);
13122 }
13123
13124 static void
13125 listprop(const char *pattern, int only_pgs, int templates)
13126 {
13127 scf_propertygroup_t *pg;
13128 scf_property_t *prop;
13129 scf_iter_t *iter, *piter;
13130 char *pgnbuf, *prnbuf, *ppnbuf;
13131 scf_pg_tmpl_t *pgt, *pgtp;
13132 scf_prop_tmpl_t *prt;
13133
13134 void **objects;
13135 char **names;
13136 void **tmpls;
13137 int allocd, i;
13138
13139 int ret;
13140 ssize_t pgnlen, prnlen, szret;
13141 size_t max_len = 0;
13142
13143 if (cur_svc == NULL && cur_inst == NULL) {
13144 semerr(emsg_entity_not_selected);
13145 return;
13146 }
13147
13148 if ((pg = scf_pg_create(g_hndl)) == NULL ||
13149 (prop = scf_property_create(g_hndl)) == NULL ||
13150 (iter = scf_iter_create(g_hndl)) == NULL ||
13151 (piter = scf_iter_create(g_hndl)) == NULL ||
13152 (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13153 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
13154 scfdie();
13155
13156 prnbuf = safe_malloc(max_scf_name_len + 1);
13157
13158 if (cur_level != NULL)
13159 ret = scf_iter_snaplevel_pgs(iter, cur_level);
13160 else if (cur_inst != NULL)
13161 ret = scf_iter_instance_pgs(iter, cur_inst);
13162 else
13163 ret = scf_iter_service_pgs(iter, cur_svc);
13164 if (ret != 0) {
13165 return;
13166 }
13167
13168 /*
13169 * We want to only list items which match pattern, and we want the
13170 * second column to line up, so during the first pass we'll save
13171 * matching items, their names, and their templates in objects,
13172 * names, and tmpls, computing the maximum name length as we go,
13173 * and then we'll print them out.
13174 *
13175 * Note: We always keep an extra slot available so the array can be
13176 * NULL-terminated.
13177 */
13178 i = 0;
13179 allocd = 1;
13180 objects = safe_malloc(sizeof (*objects));
13181 names = safe_malloc(sizeof (*names));
13182 tmpls = safe_malloc(sizeof (*tmpls));
13183
13184 while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13185 int new_pg = 0;
13186 int print_props = 0;
13187 pgtp = NULL;
13188
13189 pgnlen = scf_pg_get_name(pg, NULL, 0);
13190 if (pgnlen < 0)
13191 scfdie();
13192
13193 pgnbuf = safe_malloc(pgnlen + 1);
13194
13195 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
13196 if (szret < 0)
13197 scfdie();
13198 assert(szret <= pgnlen);
13199
13200 if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) {
13201 if (scf_error() != SCF_ERROR_NOT_FOUND)
13202 scfdie();
13203 pgtp = NULL;
13204 } else {
13205 pgtp = pgt;
13206 }
13207
13208 if (pattern == NULL ||
13209 fnmatch(pattern, pgnbuf, 0) == 0) {
13210 if (i+1 >= allocd) {
13211 allocd *= 2;
13212 objects = realloc(objects,
13213 sizeof (*objects) * allocd);
13214 names =
13215 realloc(names, sizeof (*names) * allocd);
13216 tmpls = realloc(tmpls,
13217 sizeof (*tmpls) * allocd);
13218 if (objects == NULL || names == NULL ||
13219 tmpls == NULL)
13220 uu_die(gettext("Out of memory"));
13221 }
13222 objects[i] = pg;
13223 names[i] = pgnbuf;
13224
13225 if (pgtp == NULL)
13226 tmpls[i] = NULL;
13227 else
13228 tmpls[i] = pgt;
13229
13230 ++i;
13231
13232 if (pgnlen > max_len)
13233 max_len = pgnlen;
13234
13235 new_pg = 1;
13236 print_props = 1;
13237 }
13238
13239 if (only_pgs) {
13240 if (new_pg) {
13241 pg = scf_pg_create(g_hndl);
13242 if (pg == NULL)
13243 scfdie();
13244 pgt = scf_tmpl_pg_create(g_hndl);
13245 if (pgt == NULL)
13246 scfdie();
13247 } else
13248 free(pgnbuf);
13249
13250 continue;
13251 }
13252
13253 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13254 scfdie();
13255
13256 while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13257 prnlen = scf_property_get_name(prop, prnbuf,
13258 max_scf_name_len + 1);
13259 if (prnlen < 0)
13260 scfdie();
13261
13262 /* Will prepend the property group name and a slash. */
13263 prnlen += pgnlen + 1;
13264
13265 ppnbuf = safe_malloc(prnlen + 1);
13266
13267 if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13268 prnbuf) < 0)
13269 uu_die("snprintf");
13270
13271 if (pattern == NULL || print_props == 1 ||
13272 fnmatch(pattern, ppnbuf, 0) == 0) {
13273 if (i+1 >= allocd) {
13274 allocd *= 2;
13275 objects = realloc(objects,
13276 sizeof (*objects) * allocd);
13277 names = realloc(names,
13278 sizeof (*names) * allocd);
13279 tmpls = realloc(tmpls,
13280 sizeof (*tmpls) * allocd);
13281 if (objects == NULL || names == NULL ||
13282 tmpls == NULL)
13283 uu_die(gettext(
13284 "Out of memory"));
13285 }
13286
13287 objects[i] = prop;
13288 names[i] = ppnbuf;
13289
13290 if (pgtp != NULL) {
13291 if (scf_tmpl_get_by_prop(pgt, prnbuf,
13292 prt, 0) < 0) {
13293 if (scf_error() !=
13294 SCF_ERROR_NOT_FOUND)
13295 scfdie();
13296 tmpls[i] = NULL;
13297 } else {
13298 tmpls[i] = prt;
13299 }
13300 } else {
13301 tmpls[i] = NULL;
13302 }
13303
13304 ++i;
13305
13306 if (prnlen > max_len)
13307 max_len = prnlen;
13308
13309 prop = scf_property_create(g_hndl);
13310 prt = scf_tmpl_prop_create(g_hndl);
13311 } else {
13312 free(ppnbuf);
13313 }
13314 }
13315
13316 if (new_pg) {
13317 pg = scf_pg_create(g_hndl);
13318 if (pg == NULL)
13319 scfdie();
13320 pgt = scf_tmpl_pg_create(g_hndl);
13321 if (pgt == NULL)
13322 scfdie();
13323 } else
13324 free(pgnbuf);
13325 }
13326 if (ret != 0)
13327 scfdie();
13328
13329 objects[i] = NULL;
13330
13331 scf_pg_destroy(pg);
13332 scf_tmpl_pg_destroy(pgt);
13333 scf_property_destroy(prop);
13334 scf_tmpl_prop_destroy(prt);
13335
13336 for (i = 0; objects[i] != NULL; ++i) {
13337 if (strchr(names[i], '/') == NULL) {
13338 /* property group */
13339 pg = (scf_propertygroup_t *)objects[i];
13340 pgt = (scf_pg_tmpl_t *)tmpls[i];
13341 list_pg_info(pg, names[i], max_len);
13342 list_pg_tmpl(pgt, pg, templates);
13343 free(names[i]);
13344 scf_pg_destroy(pg);
13345 if (pgt != NULL)
13346 scf_tmpl_pg_destroy(pgt);
13347 } else {
13348 /* property */
13349 prop = (scf_property_t *)objects[i];
13350 prt = (scf_prop_tmpl_t *)tmpls[i];
13351 list_prop_info(prop, names[i], max_len);
13352 list_prop_tmpl(prt, prop, templates);
13353 free(names[i]);
13354 scf_property_destroy(prop);
13355 if (prt != NULL)
13356 scf_tmpl_prop_destroy(prt);
13357 }
13358 }
13359
13360 free(names);
13361 free(objects);
13362 free(tmpls);
13363 }
13364
13365 void
13366 lscf_listpg(const char *pattern)
13367 {
13368 lscf_prep_hndl();
13369
13370 listprop(pattern, 1, 0);
13371 }
13372
13373 /*
13374 * Property group and property creation, setting, and deletion. setprop (and
13375 * its alias, addprop) can either create a property group of a given type, or
13376 * it can create or set a property to a given type and list of values.
13377 */
13378 void
13379 lscf_addpg(const char *name, const char *type, const char *flags)
13380 {
13381 scf_propertygroup_t *pg;
13382 int ret;
13383 uint32_t flgs = 0;
13384 const char *cp;
13385
13386
13387 lscf_prep_hndl();
13388
13389 if (cur_snap != NULL) {
13390 semerr(emsg_cant_modify_snapshots);
13391 return;
13392 }
13393
13394 if (cur_inst == NULL && cur_svc == NULL) {
13395 semerr(emsg_entity_not_selected);
13396 return;
13397 }
13398
13399 if (flags != NULL) {
13400 for (cp = flags; *cp != '\0'; ++cp) {
13401 switch (*cp) {
13402 case 'P':
13403 flgs |= SCF_PG_FLAG_NONPERSISTENT;
13404 break;
13405
13406 case 'p':
13407 flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13408 break;
13409
13410 default:
13411 semerr(gettext("Invalid property group flag "
13412 "%c."), *cp);
13413 return;
13414 }
13415 }
13416 }
13417
13418 pg = scf_pg_create(g_hndl);
13419 if (pg == NULL)
13420 scfdie();
13421
13422 if (cur_inst != NULL)
13423 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13424 else
13425 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13426
13427 if (ret != SCF_SUCCESS) {
13428 switch (scf_error()) {
13429 case SCF_ERROR_INVALID_ARGUMENT:
13430 semerr(gettext("Name, type, or flags are invalid.\n"));
13431 break;
13432
13433 case SCF_ERROR_EXISTS:
13434 semerr(gettext("Property group already exists.\n"));
13435 break;
13436
13437 case SCF_ERROR_PERMISSION_DENIED:
13438 semerr(emsg_permission_denied);
13439 break;
13440
13441 case SCF_ERROR_BACKEND_ACCESS:
13442 semerr(gettext("Backend refused access.\n"));
13443 break;
13444
13445 default:
13446 scfdie();
13447 }
13448 }
13449
13450 scf_pg_destroy(pg);
13451
13452 private_refresh();
13453 }
13454
13455 void
13456 lscf_delpg(char *name)
13457 {
13458 lscf_prep_hndl();
13459
13460 if (cur_snap != NULL) {
13461 semerr(emsg_cant_modify_snapshots);
13462 return;
13463 }
13464
13465 if (cur_inst == NULL && cur_svc == NULL) {
13466 semerr(emsg_entity_not_selected);
13467 return;
13468 }
13469
13470 if (strchr(name, '/') != NULL) {
13471 semerr(emsg_invalid_pg_name, name);
13472 return;
13473 }
13474
13475 lscf_delprop(name);
13476 }
13477
13478 /*
13479 * scf_delhash() is used to remove the property group related to the
13480 * hash entry for a specific manifest in the repository. pgname will be
13481 * constructed from the location of the manifest file. If deathrow isn't 0,
13482 * manifest file doesn't need to exist (manifest string will be used as
13483 * an absolute path).
13484 */
13485 void
13486 lscf_delhash(char *manifest, int deathrow)
13487 {
13488 char *pgname;
13489
13490 if (cur_snap != NULL ||
13491 cur_inst != NULL || cur_svc != NULL) {
13492 warn(gettext("error, an entity is selected\n"));
13493 return;
13494 }
13495
13496 /* select smf/manifest */
13497 lscf_select(HASH_SVC);
13498 /*
13499 * Translate the manifest file name to property name. In the deathrow
13500 * case, the manifest file does not need to exist.
13501 */
13502 pgname = mhash_filename_to_propname(manifest,
13503 deathrow ? B_TRUE : B_FALSE);
13504 if (pgname == NULL) {
13505 warn(gettext("cannot resolve pathname for %s\n"), manifest);
13506 return;
13507 }
13508 /* delete the hash property name */
13509 lscf_delpg(pgname);
13510 }
13511
13512 void
13513 lscf_listprop(const char *pattern)
13514 {
13515 lscf_prep_hndl();
13516
13517 listprop(pattern, 0, 0);
13518 }
13519
13520 int
13521 lscf_setprop(const char *pgname, const char *type, const char *value,
13522 const uu_list_t *values)
13523 {
13524 scf_type_t ty, current_ty;
13525 scf_service_t *svc;
13526 scf_propertygroup_t *pg, *parent_pg;
13527 scf_property_t *prop, *parent_prop;
13528 scf_pg_tmpl_t *pgt;
13529 scf_prop_tmpl_t *prt;
13530 int ret, result = 0;
13531 scf_transaction_t *tx;
13532 scf_transaction_entry_t *e;
13533 scf_value_t *v;
13534 uu_list_walk_t *walk;
13535 string_list_t *sp;
13536 char *propname;
13537 int req_quotes = 0;
13538
13539 lscf_prep_hndl();
13540
13541 if ((e = scf_entry_create(g_hndl)) == NULL ||
13542 (svc = scf_service_create(g_hndl)) == NULL ||
13543 (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13544 (pg = scf_pg_create(g_hndl)) == NULL ||
13545 (parent_prop = scf_property_create(g_hndl)) == NULL ||
13546 (prop = scf_property_create(g_hndl)) == NULL ||
13547 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13548 (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13549 (tx = scf_transaction_create(g_hndl)) == NULL)
13550 scfdie();
13551
13552 if (cur_snap != NULL) {
13553 semerr(emsg_cant_modify_snapshots);
13554 goto fail;
13555 }
13556
13557 if (cur_inst == NULL && cur_svc == NULL) {
13558 semerr(emsg_entity_not_selected);
13559 goto fail;
13560 }
13561
13562 propname = strchr(pgname, '/');
13563 if (propname == NULL) {
13564 semerr(gettext("Property names must contain a `/'.\n"));
13565 goto fail;
13566 }
13567
13568 *propname = '\0';
13569 ++propname;
13570
13571 if (type != NULL) {
13572 ty = string_to_type(type);
13573 if (ty == SCF_TYPE_INVALID) {
13574 semerr(gettext("Unknown type \"%s\".\n"), type);
13575 goto fail;
13576 }
13577 }
13578
13579 if (cur_inst != NULL)
13580 ret = scf_instance_get_pg(cur_inst, pgname, pg);
13581 else
13582 ret = scf_service_get_pg(cur_svc, pgname, pg);
13583 if (ret != SCF_SUCCESS) {
13584 switch (scf_error()) {
13585 case SCF_ERROR_NOT_FOUND:
13586 semerr(emsg_no_such_pg, pgname);
13587 goto fail;
13588
13589 case SCF_ERROR_INVALID_ARGUMENT:
13590 semerr(emsg_invalid_pg_name, pgname);
13591 goto fail;
13592
13593 default:
13594 scfdie();
13595 break;
13596 }
13597 }
13598
13599 do {
13600 if (scf_pg_update(pg) == -1)
13601 scfdie();
13602 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13603 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13604 scfdie();
13605
13606 semerr(emsg_permission_denied);
13607 goto fail;
13608 }
13609
13610 ret = scf_pg_get_property(pg, propname, prop);
13611 if (ret == SCF_SUCCESS) {
13612 if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS)
13613 scfdie();
13614
13615 if (type == NULL)
13616 ty = current_ty;
13617 if (scf_transaction_property_change_type(tx, e,
13618 propname, ty) == -1)
13619 scfdie();
13620
13621 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13622 /* Infer the type, if possible. */
13623 if (type == NULL) {
13624 /*
13625 * First check if we're an instance and the
13626 * property is set on the service.
13627 */
13628 if (cur_inst != NULL &&
13629 scf_instance_get_parent(cur_inst,
13630 svc) == 0 &&
13631 scf_service_get_pg(cur_svc, pgname,
13632 parent_pg) == 0 &&
13633 scf_pg_get_property(parent_pg, propname,
13634 parent_prop) == 0 &&
13635 scf_property_type(parent_prop,
13636 ¤t_ty) == 0) {
13637 ty = current_ty;
13638
13639 /* Then check for a type set in a template. */
13640 } else if (scf_tmpl_get_by_pg(pg, pgt,
13641 0) == 0 &&
13642 scf_tmpl_get_by_prop(pgt, propname, prt,
13643 0) == 0 &&
13644 scf_tmpl_prop_type(prt, ¤t_ty) == 0) {
13645 ty = current_ty;
13646
13647 /* If type can't be inferred, fail. */
13648 } else {
13649 semerr(gettext("Type required for new "
13650 "properties.\n"));
13651 goto fail;
13652 }
13653 }
13654 if (scf_transaction_property_new(tx, e, propname,
13655 ty) == -1)
13656 scfdie();
13657 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13658 semerr(emsg_invalid_prop_name, propname);
13659 goto fail;
13660 } else {
13661 scfdie();
13662 }
13663
13664 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13665 req_quotes = 1;
13666
13667 if (value != NULL) {
13668 v = string_to_value(value, ty, 0);
13669
13670 if (v == NULL)
13671 goto fail;
13672
13673 ret = scf_entry_add_value(e, v);
13674 assert(ret == SCF_SUCCESS);
13675 } else {
13676 assert(values != NULL);
13677
13678 walk = uu_list_walk_start((uu_list_t *)values,
13679 UU_DEFAULT);
13680 if (walk == NULL)
13681 uu_die(gettext("Could not walk list"));
13682
13683 for (sp = uu_list_walk_next(walk); sp != NULL;
13684 sp = uu_list_walk_next(walk)) {
13685 v = string_to_value(sp->str, ty, req_quotes);
13686
13687 if (v == NULL) {
13688 scf_entry_destroy_children(e);
13689 goto fail;
13690 }
13691
13692 ret = scf_entry_add_value(e, v);
13693 assert(ret == SCF_SUCCESS);
13694 }
13695 uu_list_walk_end(walk);
13696 }
13697 result = scf_transaction_commit(tx);
13698
13699 scf_transaction_reset(tx);
13700 scf_entry_destroy_children(e);
13701 } while (result == 0);
13702
13703 if (result < 0) {
13704 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13705 scfdie();
13706
13707 semerr(emsg_permission_denied);
13708 goto fail;
13709 }
13710
13711 ret = 0;
13712
13713 private_refresh();
13714
13715 goto cleanup;
13716
13717 fail:
13718 ret = -1;
13719
13720 cleanup:
13721 scf_transaction_destroy(tx);
13722 scf_entry_destroy(e);
13723 scf_service_destroy(svc);
13724 scf_pg_destroy(parent_pg);
13725 scf_pg_destroy(pg);
13726 scf_property_destroy(parent_prop);
13727 scf_property_destroy(prop);
13728 scf_tmpl_pg_destroy(pgt);
13729 scf_tmpl_prop_destroy(prt);
13730
13731 return (ret);
13732 }
13733
13734 void
13735 lscf_delprop(char *pgn)
13736 {
13737 char *slash, *pn;
13738 scf_propertygroup_t *pg;
13739 scf_transaction_t *tx;
13740 scf_transaction_entry_t *e;
13741 int ret;
13742
13743
13744 lscf_prep_hndl();
13745
13746 if (cur_snap != NULL) {
13747 semerr(emsg_cant_modify_snapshots);
13748 return;
13749 }
13750
13751 if (cur_inst == NULL && cur_svc == NULL) {
13752 semerr(emsg_entity_not_selected);
13753 return;
13754 }
13755
13756 pg = scf_pg_create(g_hndl);
13757 if (pg == NULL)
13758 scfdie();
13759
13760 slash = strchr(pgn, '/');
13761 if (slash == NULL) {
13762 pn = NULL;
13763 } else {
13764 *slash = '\0';
13765 pn = slash + 1;
13766 }
13767
13768 if (cur_inst != NULL)
13769 ret = scf_instance_get_pg(cur_inst, pgn, pg);
13770 else
13771 ret = scf_service_get_pg(cur_svc, pgn, pg);
13772 if (ret != SCF_SUCCESS) {
13773 switch (scf_error()) {
13774 case SCF_ERROR_NOT_FOUND:
13775 semerr(emsg_no_such_pg, pgn);
13776 break;
13777
13778 case SCF_ERROR_INVALID_ARGUMENT:
13779 semerr(emsg_invalid_pg_name, pgn);
13780 break;
13781
13782 default:
13783 scfdie();
13784 }
13785
13786 scf_pg_destroy(pg);
13787
13788 return;
13789 }
13790
13791 if (pn == NULL) {
13792 /* Try to delete the property group. */
13793 if (scf_pg_delete(pg) != SCF_SUCCESS) {
13794 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13795 scfdie();
13796
13797 semerr(emsg_permission_denied);
13798 } else {
13799 private_refresh();
13800 }
13801
13802 scf_pg_destroy(pg);
13803 return;
13804 }
13805
13806 e = scf_entry_create(g_hndl);
13807 tx = scf_transaction_create(g_hndl);
13808
13809 do {
13810 if (scf_pg_update(pg) == -1)
13811 scfdie();
13812 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13813 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13814 scfdie();
13815
13816 semerr(emsg_permission_denied);
13817 break;
13818 }
13819
13820 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
13821 if (scf_error() == SCF_ERROR_NOT_FOUND) {
13822 semerr(gettext("No such property %s/%s.\n"),
13823 pgn, pn);
13824 break;
13825 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13826 semerr(emsg_invalid_prop_name, pn);
13827 break;
13828 } else {
13829 scfdie();
13830 }
13831 }
13832
13833 ret = scf_transaction_commit(tx);
13834
13835 if (ret == 0)
13836 scf_transaction_reset(tx);
13837 } while (ret == 0);
13838
13839 if (ret < 0) {
13840 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13841 scfdie();
13842
13843 semerr(emsg_permission_denied);
13844 } else {
13845 private_refresh();
13846 }
13847
13848 scf_transaction_destroy(tx);
13849 scf_entry_destroy(e);
13850 scf_pg_destroy(pg);
13851 }
13852
13853 /*
13854 * Property editing.
13855 */
13856
13857 static int
13858 write_edit_script(FILE *strm)
13859 {
13860 char *fmribuf;
13861 ssize_t fmrilen;
13862
13863 scf_propertygroup_t *pg;
13864 scf_property_t *prop;
13865 scf_value_t *val;
13866 scf_type_t ty;
13867 int ret, result = 0;
13868 scf_iter_t *iter, *piter, *viter;
13869 char *buf, *tybuf, *pname;
13870 const char *emsg_write_error;
13871
13872
13873 emsg_write_error = gettext("Error writing temoprary file: %s.\n");
13874
13875
13876 /* select fmri */
13877 if (cur_inst != NULL) {
13878 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
13879 if (fmrilen < 0)
13880 scfdie();
13881 fmribuf = safe_malloc(fmrilen + 1);
13882 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
13883 scfdie();
13884 } else {
13885 assert(cur_svc != NULL);
13886 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
13887 if (fmrilen < 0)
13888 scfdie();
13889 fmribuf = safe_malloc(fmrilen + 1);
13890 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
13891 scfdie();
13892 }
13893
13894 if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
13895 warn(emsg_write_error, strerror(errno));
13896 free(fmribuf);
13897 return (-1);
13898 }
13899
13900 free(fmribuf);
13901
13902
13903 if ((pg = scf_pg_create(g_hndl)) == NULL ||
13904 (prop = scf_property_create(g_hndl)) == NULL ||
13905 (val = scf_value_create(g_hndl)) == NULL ||
13906 (iter = scf_iter_create(g_hndl)) == NULL ||
13907 (piter = scf_iter_create(g_hndl)) == NULL ||
13908 (viter = scf_iter_create(g_hndl)) == NULL)
13909 scfdie();
13910
13911 buf = safe_malloc(max_scf_name_len + 1);
13912 tybuf = safe_malloc(max_scf_pg_type_len + 1);
13913 pname = safe_malloc(max_scf_name_len + 1);
13914
13915 if (cur_inst != NULL)
13916 ret = scf_iter_instance_pgs(iter, cur_inst);
13917 else
13918 ret = scf_iter_service_pgs(iter, cur_svc);
13919 if (ret != SCF_SUCCESS)
13920 scfdie();
13921
13922 while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13923 int ret2;
13924
13925 /*
13926 * # delprop pg
13927 * # addpg pg type
13928 */
13929 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
13930 scfdie();
13931
13932 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
13933 scfdie();
13934
13935 if (fprintf(strm, "# Property group \"%s\"\n"
13936 "# delprop %s\n"
13937 "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
13938 warn(emsg_write_error, strerror(errno));
13939 result = -1;
13940 goto out;
13941 }
13942
13943 /* # setprop pg/prop = (values) */
13944
13945 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13946 scfdie();
13947
13948 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
13949 int first = 1;
13950 int ret3;
13951 int multiple;
13952 int is_str;
13953 scf_type_t bty;
13954
13955 if (scf_property_get_name(prop, pname,
13956 max_scf_name_len + 1) < 0)
13957 scfdie();
13958
13959 if (scf_property_type(prop, &ty) != 0)
13960 scfdie();
13961
13962 multiple = prop_has_multiple_values(prop, val);
13963
13964 if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
13965 pname, scf_type_to_string(ty), multiple ? "(" : "")
13966 < 0) {
13967 warn(emsg_write_error, strerror(errno));
13968 result = -1;
13969 goto out;
13970 }
13971
13972 (void) scf_type_base_type(ty, &bty);
13973 is_str = (bty == SCF_TYPE_ASTRING);
13974
13975 if (scf_iter_property_values(viter, prop) !=
13976 SCF_SUCCESS)
13977 scfdie();
13978
13979 while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
13980 char *buf;
13981 ssize_t buflen;
13982
13983 buflen = scf_value_get_as_string(val, NULL, 0);
13984 if (buflen < 0)
13985 scfdie();
13986
13987 buf = safe_malloc(buflen + 1);
13988
13989 if (scf_value_get_as_string(val, buf,
13990 buflen + 1) < 0)
13991 scfdie();
13992
13993 if (first)
13994 first = 0;
13995 else {
13996 if (putc(' ', strm) != ' ') {
13997 warn(emsg_write_error,
13998 strerror(errno));
13999 result = -1;
14000 goto out;
14001 }
14002 }
14003
14004 if ((is_str && multiple) ||
14005 strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
14006 (void) putc('"', strm);
14007 (void) quote_and_print(buf, strm, 1);
14008 (void) putc('"', strm);
14009
14010 if (ferror(strm)) {
14011 warn(emsg_write_error,
14012 strerror(errno));
14013 result = -1;
14014 goto out;
14015 }
14016 } else {
14017 if (fprintf(strm, "%s", buf) < 0) {
14018 warn(emsg_write_error,
14019 strerror(errno));
14020 result = -1;
14021 goto out;
14022 }
14023 }
14024
14025 free(buf);
14026 }
14027 if (ret3 < 0 &&
14028 scf_error() != SCF_ERROR_PERMISSION_DENIED)
14029 scfdie();
14030
14031 /* Write closing paren if mult-value property */
14032 if ((multiple && putc(')', strm) == EOF) ||
14033
14034 /* Write final newline */
14035 fputc('\n', strm) == EOF) {
14036 warn(emsg_write_error, strerror(errno));
14037 result = -1;
14038 goto out;
14039 }
14040 }
14041 if (ret2 < 0)
14042 scfdie();
14043
14044 if (fputc('\n', strm) == EOF) {
14045 warn(emsg_write_error, strerror(errno));
14046 result = -1;
14047 goto out;
14048 }
14049 }
14050 if (ret < 0)
14051 scfdie();
14052
14053 out:
14054 free(pname);
14055 free(tybuf);
14056 free(buf);
14057 scf_iter_destroy(viter);
14058 scf_iter_destroy(piter);
14059 scf_iter_destroy(iter);
14060 scf_value_destroy(val);
14061 scf_property_destroy(prop);
14062 scf_pg_destroy(pg);
14063
14064 if (result == 0) {
14065 if (fflush(strm) != 0) {
14066 warn(emsg_write_error, strerror(errno));
14067 return (-1);
14068 }
14069 }
14070
14071 return (result);
14072 }
14073
14074 int
14075 lscf_editprop()
14076 {
14077 char *buf, *editor;
14078 size_t bufsz;
14079 int tmpfd;
14080 char tempname[] = TEMP_FILE_PATTERN;
14081
14082 lscf_prep_hndl();
14083
14084 if (cur_snap != NULL) {
14085 semerr(emsg_cant_modify_snapshots);
14086 return (-1);
14087 }
14088
14089 if (cur_svc == NULL && cur_inst == NULL) {
14090 semerr(emsg_entity_not_selected);
14091 return (-1);
14092 }
14093
14094 tmpfd = mkstemp(tempname);
14095 if (tmpfd == -1) {
14096 semerr(gettext("Could not create temporary file.\n"));
14097 return (-1);
14098 }
14099
14100 (void) strcpy(tempfilename, tempname);
14101
14102 tempfile = fdopen(tmpfd, "r+");
14103 if (tempfile == NULL) {
14104 warn(gettext("Could not create temporary file.\n"));
14105 if (close(tmpfd) == -1)
14106 warn(gettext("Could not close temporary file: %s.\n"),
14107 strerror(errno));
14108
14109 remove_tempfile();
14110
14111 return (-1);
14112 }
14113
14114 if (write_edit_script(tempfile) == -1) {
14115 remove_tempfile();
14116 return (-1);
14117 }
14118
14119 editor = getenv("EDITOR");
14120 if (editor == NULL)
14121 editor = "vi";
14122
14123 bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
14124 buf = safe_malloc(bufsz);
14125
14126 if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
14127 uu_die(gettext("Error creating editor command"));
14128
14129 if (system(buf) == -1) {
14130 semerr(gettext("Could not launch editor %s: %s\n"), editor,
14131 strerror(errno));
14132 free(buf);
14133 remove_tempfile();
14134 return (-1);
14135 }
14136
14137 free(buf);
14138
14139 (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
14140
14141 remove_tempfile();
14142
14143 return (0);
14144 }
14145
14146 static void
14147 add_string(uu_list_t *strlist, const char *str)
14148 {
14149 string_list_t *elem;
14150 elem = safe_malloc(sizeof (*elem));
14151 uu_list_node_init(elem, &elem->node, string_pool);
14152 elem->str = safe_strdup(str);
14153 if (uu_list_append(strlist, elem) != 0)
14154 uu_die(gettext("libuutil error: %s\n"),
14155 uu_strerror(uu_error()));
14156 }
14157
14158 static int
14159 remove_string(uu_list_t *strlist, const char *str)
14160 {
14161 uu_list_walk_t *elems;
14162 string_list_t *sp;
14163
14164 /*
14165 * Find the element that needs to be removed.
14166 */
14167 elems = uu_list_walk_start(strlist, UU_DEFAULT);
14168 while ((sp = uu_list_walk_next(elems)) != NULL) {
14169 if (strcmp(sp->str, str) == 0)
14170 break;
14171 }
14172 uu_list_walk_end(elems);
14173
14174 /*
14175 * Returning 1 here as the value was not found, this
14176 * might not be an error. Leave it to the caller to
14177 * decide.
14178 */
14179 if (sp == NULL) {
14180 return (1);
14181 }
14182
14183 uu_list_remove(strlist, sp);
14184
14185 free(sp->str);
14186 free(sp);
14187
14188 return (0);
14189 }
14190
14191 /*
14192 * Get all property values that don't match the given glob pattern,
14193 * if a pattern is specified.
14194 */
14195 static void
14196 get_prop_values(scf_property_t *prop, uu_list_t *values,
14197 const char *pattern)
14198 {
14199 scf_iter_t *iter;
14200 scf_value_t *val;
14201 int ret;
14202
14203 if ((iter = scf_iter_create(g_hndl)) == NULL ||
14204 (val = scf_value_create(g_hndl)) == NULL)
14205 scfdie();
14206
14207 if (scf_iter_property_values(iter, prop) != 0)
14208 scfdie();
14209
14210 while ((ret = scf_iter_next_value(iter, val)) == 1) {
14211 char *buf;
14212 ssize_t vlen, szret;
14213
14214 vlen = scf_value_get_as_string(val, NULL, 0);
14215 if (vlen < 0)
14216 scfdie();
14217
14218 buf = safe_malloc(vlen + 1);
14219
14220 szret = scf_value_get_as_string(val, buf, vlen + 1);
14221 if (szret < 0)
14222 scfdie();
14223 assert(szret <= vlen);
14224
14225 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14226 add_string(values, buf);
14227
14228 free(buf);
14229 }
14230
14231 if (ret == -1)
14232 scfdie();
14233
14234 scf_value_destroy(val);
14235 scf_iter_destroy(iter);
14236 }
14237
14238 static int
14239 lscf_setpropvalue(const char *pgname, const char *type,
14240 const char *arg, int isadd, int isnotfoundok)
14241 {
14242 scf_type_t ty;
14243 scf_propertygroup_t *pg;
14244 scf_property_t *prop;
14245 int ret, result = 0;
14246 scf_transaction_t *tx;
14247 scf_transaction_entry_t *e;
14248 scf_value_t *v;
14249 string_list_t *sp;
14250 char *propname;
14251 uu_list_t *values;
14252 uu_list_walk_t *walk;
14253 void *cookie = NULL;
14254 char *pattern = NULL;
14255
14256 lscf_prep_hndl();
14257
14258 if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14259 uu_die(gettext("Could not create property list: %s\n"),
14260 uu_strerror(uu_error()));
14261
14262 if (!isadd)
14263 pattern = safe_strdup(arg);
14264
14265 if ((e = scf_entry_create(g_hndl)) == NULL ||
14266 (pg = scf_pg_create(g_hndl)) == NULL ||
14267 (prop = scf_property_create(g_hndl)) == NULL ||
14268 (tx = scf_transaction_create(g_hndl)) == NULL)
14269 scfdie();
14270
14271 if (cur_snap != NULL) {
14272 semerr(emsg_cant_modify_snapshots);
14273 goto fail;
14274 }
14275
14276 if (cur_inst == NULL && cur_svc == NULL) {
14277 semerr(emsg_entity_not_selected);
14278 goto fail;
14279 }
14280
14281 propname = strchr(pgname, '/');
14282 if (propname == NULL) {
14283 semerr(gettext("Property names must contain a `/'.\n"));
14284 goto fail;
14285 }
14286
14287 *propname = '\0';
14288 ++propname;
14289
14290 if (type != NULL) {
14291 ty = string_to_type(type);
14292 if (ty == SCF_TYPE_INVALID) {
14293 semerr(gettext("Unknown type \"%s\".\n"), type);
14294 goto fail;
14295 }
14296 }
14297
14298 if (cur_inst != NULL)
14299 ret = scf_instance_get_pg(cur_inst, pgname, pg);
14300 else
14301 ret = scf_service_get_pg(cur_svc, pgname, pg);
14302 if (ret != 0) {
14303 switch (scf_error()) {
14304 case SCF_ERROR_NOT_FOUND:
14305 if (isnotfoundok) {
14306 result = 0;
14307 } else {
14308 semerr(emsg_no_such_pg, pgname);
14309 result = -1;
14310 }
14311 goto out;
14312
14313 case SCF_ERROR_INVALID_ARGUMENT:
14314 semerr(emsg_invalid_pg_name, pgname);
14315 goto fail;
14316
14317 default:
14318 scfdie();
14319 }
14320 }
14321
14322 do {
14323 if (scf_pg_update(pg) == -1)
14324 scfdie();
14325 if (scf_transaction_start(tx, pg) != 0) {
14326 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14327 scfdie();
14328
14329 semerr(emsg_permission_denied);
14330 goto fail;
14331 }
14332
14333 ret = scf_pg_get_property(pg, propname, prop);
14334 if (ret == 0) {
14335 scf_type_t ptype;
14336 char *pat = pattern;
14337
14338 if (scf_property_type(prop, &ptype) != 0)
14339 scfdie();
14340
14341 if (isadd) {
14342 if (type != NULL && ptype != ty) {
14343 semerr(gettext("Property \"%s\" is not "
14344 "of type \"%s\".\n"), propname,
14345 type);
14346 goto fail;
14347 }
14348
14349 pat = NULL;
14350 } else {
14351 size_t len = strlen(pat);
14352 if (len > 0 && pat[len - 1] == '\"')
14353 pat[len - 1] = '\0';
14354 if (len > 0 && pat[0] == '\"')
14355 pat++;
14356 }
14357
14358 ty = ptype;
14359
14360 get_prop_values(prop, values, pat);
14361
14362 if (isadd)
14363 add_string(values, arg);
14364
14365 if (scf_transaction_property_change(tx, e,
14366 propname, ty) == -1)
14367 scfdie();
14368 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14369 if (isadd) {
14370 if (type == NULL) {
14371 semerr(gettext("Type required "
14372 "for new properties.\n"));
14373 goto fail;
14374 }
14375
14376 add_string(values, arg);
14377
14378 if (scf_transaction_property_new(tx, e,
14379 propname, ty) == -1)
14380 scfdie();
14381 } else if (isnotfoundok) {
14382 result = 0;
14383 goto out;
14384 } else {
14385 semerr(gettext("No such property %s/%s.\n"),
14386 pgname, propname);
14387 result = -1;
14388 goto out;
14389 }
14390 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14391 semerr(emsg_invalid_prop_name, propname);
14392 goto fail;
14393 } else {
14394 scfdie();
14395 }
14396
14397 walk = uu_list_walk_start(values, UU_DEFAULT);
14398 if (walk == NULL)
14399 uu_die(gettext("Could not walk property list.\n"));
14400
14401 for (sp = uu_list_walk_next(walk); sp != NULL;
14402 sp = uu_list_walk_next(walk)) {
14403 v = string_to_value(sp->str, ty, 0);
14404
14405 if (v == NULL) {
14406 scf_entry_destroy_children(e);
14407 goto fail;
14408 }
14409 ret = scf_entry_add_value(e, v);
14410 assert(ret == 0);
14411 }
14412 uu_list_walk_end(walk);
14413
14414 result = scf_transaction_commit(tx);
14415
14416 scf_transaction_reset(tx);
14417 scf_entry_destroy_children(e);
14418 } while (result == 0);
14419
14420 if (result < 0) {
14421 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14422 scfdie();
14423
14424 semerr(emsg_permission_denied);
14425 goto fail;
14426 }
14427
14428 result = 0;
14429
14430 private_refresh();
14431
14432 out:
14433 scf_transaction_destroy(tx);
14434 scf_entry_destroy(e);
14435 scf_pg_destroy(pg);
14436 scf_property_destroy(prop);
14437 free(pattern);
14438
14439 while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14440 free(sp->str);
14441 free(sp);
14442 }
14443
14444 uu_list_destroy(values);
14445
14446 return (result);
14447
14448 fail:
14449 result = -1;
14450 goto out;
14451 }
14452
14453 int
14454 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14455 {
14456 return (lscf_setpropvalue(pgname, type, value, 1, 0));
14457 }
14458
14459 int
14460 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14461 {
14462 return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14463 }
14464
14465 /*
14466 * Look for a standard start method, first in the instance (if any),
14467 * then the service.
14468 */
14469 static const char *
14470 start_method_name(int *in_instance)
14471 {
14472 scf_propertygroup_t *pg;
14473 char **p;
14474 int ret;
14475 scf_instance_t *inst = cur_inst;
14476
14477 if ((pg = scf_pg_create(g_hndl)) == NULL)
14478 scfdie();
14479
14480 again:
14481 for (p = start_method_names; *p != NULL; p++) {
14482 if (inst != NULL)
14483 ret = scf_instance_get_pg(inst, *p, pg);
14484 else
14485 ret = scf_service_get_pg(cur_svc, *p, pg);
14486
14487 if (ret == 0) {
14488 size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14489 char *buf = safe_malloc(bufsz);
14490
14491 if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14492 free(buf);
14493 continue;
14494 }
14495 if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14496 free(buf);
14497 continue;
14498 }
14499
14500 free(buf);
14501 *in_instance = (inst != NULL);
14502 scf_pg_destroy(pg);
14503 return (*p);
14504 }
14505
14506 if (scf_error() == SCF_ERROR_NOT_FOUND)
14507 continue;
14508
14509 scfdie();
14510 }
14511
14512 if (inst != NULL) {
14513 inst = NULL;
14514 goto again;
14515 }
14516
14517 scf_pg_destroy(pg);
14518 return (NULL);
14519 }
14520
14521 static int
14522 addpg(const char *name, const char *type)
14523 {
14524 scf_propertygroup_t *pg;
14525 int ret;
14526
14527 pg = scf_pg_create(g_hndl);
14528 if (pg == NULL)
14529 scfdie();
14530
14531 if (cur_inst != NULL)
14532 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14533 else
14534 ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14535
14536 if (ret != 0) {
14537 switch (scf_error()) {
14538 case SCF_ERROR_EXISTS:
14539 ret = 0;
14540 break;
14541
14542 case SCF_ERROR_PERMISSION_DENIED:
14543 semerr(emsg_permission_denied);
14544 break;
14545
14546 default:
14547 scfdie();
14548 }
14549 }
14550
14551 scf_pg_destroy(pg);
14552 return (ret);
14553 }
14554
14555 int
14556 lscf_setenv(uu_list_t *args, int isunset)
14557 {
14558 int ret = 0;
14559 size_t i;
14560 int argc;
14561 char **argv = NULL;
14562 string_list_t *slp;
14563 char *pattern;
14564 char *prop;
14565 int do_service = 0;
14566 int do_instance = 0;
14567 const char *method = NULL;
14568 const char *name = NULL;
14569 const char *value = NULL;
14570 scf_instance_t *saved_cur_inst = cur_inst;
14571
14572 lscf_prep_hndl();
14573
14574 argc = uu_list_numnodes(args);
14575 if (argc < 1)
14576 goto usage;
14577
14578 argv = calloc(argc + 1, sizeof (char *));
14579 if (argv == NULL)
14580 uu_die(gettext("Out of memory.\n"));
14581
14582 for (slp = uu_list_first(args), i = 0;
14583 slp != NULL;
14584 slp = uu_list_next(args, slp), ++i)
14585 argv[i] = slp->str;
14586
14587 argv[i] = NULL;
14588
14589 opterr = 0;
14590 optind = 0;
14591 for (;;) {
14592 ret = getopt(argc, argv, "sim:");
14593 if (ret == -1)
14594 break;
14595
14596 switch (ret) {
14597 case 's':
14598 do_service = 1;
14599 cur_inst = NULL;
14600 break;
14601
14602 case 'i':
14603 do_instance = 1;
14604 break;
14605
14606 case 'm':
14607 method = optarg;
14608 break;
14609
14610 case '?':
14611 goto usage;
14612
14613 default:
14614 bad_error("getopt", ret);
14615 }
14616 }
14617
14618 argc -= optind;
14619 if ((do_service && do_instance) ||
14620 (isunset && argc != 1) ||
14621 (!isunset && argc != 2))
14622 goto usage;
14623
14624 name = argv[optind];
14625 if (!isunset)
14626 value = argv[optind + 1];
14627
14628 if (cur_snap != NULL) {
14629 semerr(emsg_cant_modify_snapshots);
14630 ret = -1;
14631 goto out;
14632 }
14633
14634 if (cur_inst == NULL && cur_svc == NULL) {
14635 semerr(emsg_entity_not_selected);
14636 ret = -1;
14637 goto out;
14638 }
14639
14640 if (do_instance && cur_inst == NULL) {
14641 semerr(gettext("No instance is selected.\n"));
14642 ret = -1;
14643 goto out;
14644 }
14645
14646 if (do_service && cur_svc == NULL) {
14647 semerr(gettext("No service is selected.\n"));
14648 ret = -1;
14649 goto out;
14650 }
14651
14652 if (method == NULL) {
14653 if (do_instance || do_service) {
14654 method = "method_context";
14655 if (!isunset) {
14656 ret = addpg("method_context",
14657 SCF_GROUP_FRAMEWORK);
14658 if (ret != 0)
14659 goto out;
14660 }
14661 } else {
14662 int in_instance;
14663 method = start_method_name(&in_instance);
14664 if (method == NULL) {
14665 semerr(gettext(
14666 "Couldn't find start method; please "
14667 "specify a method with '-m'.\n"));
14668 ret = -1;
14669 goto out;
14670 }
14671 if (!in_instance)
14672 cur_inst = NULL;
14673 }
14674 } else {
14675 scf_propertygroup_t *pg;
14676 size_t bufsz;
14677 char *buf;
14678 int ret;
14679
14680 if ((pg = scf_pg_create(g_hndl)) == NULL)
14681 scfdie();
14682
14683 if (cur_inst != NULL)
14684 ret = scf_instance_get_pg(cur_inst, method, pg);
14685 else
14686 ret = scf_service_get_pg(cur_svc, method, pg);
14687
14688 if (ret != 0) {
14689 scf_pg_destroy(pg);
14690 switch (scf_error()) {
14691 case SCF_ERROR_NOT_FOUND:
14692 semerr(gettext("Couldn't find the method "
14693 "\"%s\".\n"), method);
14694 goto out;
14695
14696 case SCF_ERROR_INVALID_ARGUMENT:
14697 semerr(gettext("Invalid method name \"%s\".\n"),
14698 method);
14699 goto out;
14700
14701 default:
14702 scfdie();
14703 }
14704 }
14705
14706 bufsz = strlen(SCF_GROUP_METHOD) + 1;
14707 buf = safe_malloc(bufsz);
14708
14709 if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
14710 strcmp(buf, SCF_GROUP_METHOD) != 0) {
14711 semerr(gettext("Property group \"%s\" is not of type "
14712 "\"method\".\n"), method);
14713 ret = -1;
14714 free(buf);
14715 scf_pg_destroy(pg);
14716 goto out;
14717 }
14718
14719 free(buf);
14720 scf_pg_destroy(pg);
14721 }
14722
14723 prop = uu_msprintf("%s/environment", method);
14724 pattern = uu_msprintf("%s=*", name);
14725
14726 if (prop == NULL || pattern == NULL)
14727 uu_die(gettext("Out of memory.\n"));
14728
14729 ret = lscf_delpropvalue(prop, pattern, !isunset);
14730
14731 if (ret == 0 && !isunset) {
14732 uu_free(pattern);
14733 uu_free(prop);
14734 prop = uu_msprintf("%s/environment", method);
14735 pattern = uu_msprintf("%s=%s", name, value);
14736 if (prop == NULL || pattern == NULL)
14737 uu_die(gettext("Out of memory.\n"));
14738 ret = lscf_addpropvalue(prop, "astring:", pattern);
14739 }
14740 uu_free(pattern);
14741 uu_free(prop);
14742
14743 out:
14744 cur_inst = saved_cur_inst;
14745
14746 free(argv);
14747 return (ret);
14748 usage:
14749 ret = -2;
14750 goto out;
14751 }
14752
14753 /*
14754 * Snapshot commands
14755 */
14756
14757 void
14758 lscf_listsnap()
14759 {
14760 scf_snapshot_t *snap;
14761 scf_iter_t *iter;
14762 char *nb;
14763 int r;
14764
14765 lscf_prep_hndl();
14766
14767 if (cur_inst == NULL) {
14768 semerr(gettext("Instance not selected.\n"));
14769 return;
14770 }
14771
14772 if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
14773 (iter = scf_iter_create(g_hndl)) == NULL)
14774 scfdie();
14775
14776 if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
14777 scfdie();
14778
14779 nb = safe_malloc(max_scf_name_len + 1);
14780
14781 while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
14782 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
14783 scfdie();
14784
14785 (void) puts(nb);
14786 }
14787 if (r < 0)
14788 scfdie();
14789
14790 free(nb);
14791 scf_iter_destroy(iter);
14792 scf_snapshot_destroy(snap);
14793 }
14794
14795 void
14796 lscf_selectsnap(const char *name)
14797 {
14798 scf_snapshot_t *snap;
14799 scf_snaplevel_t *level;
14800
14801 lscf_prep_hndl();
14802
14803 if (cur_inst == NULL) {
14804 semerr(gettext("Instance not selected.\n"));
14805 return;
14806 }
14807
14808 if (cur_snap != NULL) {
14809 if (name != NULL) {
14810 char *cur_snap_name;
14811 boolean_t nochange;
14812
14813 cur_snap_name = safe_malloc(max_scf_name_len + 1);
14814
14815 if (scf_snapshot_get_name(cur_snap, cur_snap_name,
14816 max_scf_name_len + 1) < 0)
14817 scfdie();
14818
14819 nochange = strcmp(name, cur_snap_name) == 0;
14820
14821 free(cur_snap_name);
14822
14823 if (nochange)
14824 return;
14825 }
14826
14827 unselect_cursnap();
14828 }
14829
14830 if (name == NULL)
14831 return;
14832
14833 if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
14834 (level = scf_snaplevel_create(g_hndl)) == NULL)
14835 scfdie();
14836
14837 if (scf_instance_get_snapshot(cur_inst, name, snap) !=
14838 SCF_SUCCESS) {
14839 switch (scf_error()) {
14840 case SCF_ERROR_INVALID_ARGUMENT:
14841 semerr(gettext("Invalid name \"%s\".\n"), name);
14842 break;
14843
14844 case SCF_ERROR_NOT_FOUND:
14845 semerr(gettext("No such snapshot \"%s\".\n"), name);
14846 break;
14847
14848 default:
14849 scfdie();
14850 }
14851
14852 scf_snaplevel_destroy(level);
14853 scf_snapshot_destroy(snap);
14854 return;
14855 }
14856
14857 /* Load the snaplevels into our list. */
14858 cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
14859 if (cur_levels == NULL)
14860 uu_die(gettext("Could not create list: %s\n"),
14861 uu_strerror(uu_error()));
14862
14863 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
14864 if (scf_error() != SCF_ERROR_NOT_FOUND)
14865 scfdie();
14866
14867 semerr(gettext("Snapshot has no snaplevels.\n"));
14868
14869 scf_snaplevel_destroy(level);
14870 scf_snapshot_destroy(snap);
14871 return;
14872 }
14873
14874 cur_snap = snap;
14875
14876 for (;;) {
14877 cur_elt = safe_malloc(sizeof (*cur_elt));
14878 uu_list_node_init(cur_elt, &cur_elt->list_node,
14879 snaplevel_pool);
14880 cur_elt->sl = level;
14881 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
14882 uu_die(gettext("libuutil error: %s\n"),
14883 uu_strerror(uu_error()));
14884
14885 level = scf_snaplevel_create(g_hndl);
14886 if (level == NULL)
14887 scfdie();
14888
14889 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
14890 level) != SCF_SUCCESS) {
14891 if (scf_error() != SCF_ERROR_NOT_FOUND)
14892 scfdie();
14893
14894 scf_snaplevel_destroy(level);
14895 break;
14896 }
14897 }
14898
14899 cur_elt = uu_list_last(cur_levels);
14900 cur_level = cur_elt->sl;
14901 }
14902
14903 /*
14904 * Copies the properties & values in src to dst. Assumes src won't change.
14905 * Returns -1 if permission is denied, -2 if another transaction interrupts,
14906 * and 0 on success.
14907 *
14908 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
14909 * property, if it is copied and has type boolean. (See comment in
14910 * lscf_revert()).
14911 */
14912 static int
14913 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
14914 uint8_t enabled)
14915 {
14916 scf_transaction_t *tx;
14917 scf_iter_t *iter, *viter;
14918 scf_property_t *prop;
14919 scf_value_t *v;
14920 char *nbuf;
14921 int r;
14922
14923 tx = scf_transaction_create(g_hndl);
14924 if (tx == NULL)
14925 scfdie();
14926
14927 if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
14928 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14929 scfdie();
14930
14931 scf_transaction_destroy(tx);
14932
14933 return (-1);
14934 }
14935
14936 if ((iter = scf_iter_create(g_hndl)) == NULL ||
14937 (prop = scf_property_create(g_hndl)) == NULL ||
14938 (viter = scf_iter_create(g_hndl)) == NULL)
14939 scfdie();
14940
14941 nbuf = safe_malloc(max_scf_name_len + 1);
14942
14943 if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
14944 scfdie();
14945
14946 for (;;) {
14947 scf_transaction_entry_t *e;
14948 scf_type_t ty;
14949
14950 r = scf_iter_next_property(iter, prop);
14951 if (r == -1)
14952 scfdie();
14953 if (r == 0)
14954 break;
14955
14956 e = scf_entry_create(g_hndl);
14957 if (e == NULL)
14958 scfdie();
14959
14960 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
14961 scfdie();
14962
14963 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
14964 scfdie();
14965
14966 if (scf_transaction_property_new(tx, e, nbuf,
14967 ty) != SCF_SUCCESS)
14968 scfdie();
14969
14970 if ((enabled == 0 || enabled == 1) &&
14971 strcmp(nbuf, scf_property_enabled) == 0 &&
14972 ty == SCF_TYPE_BOOLEAN) {
14973 v = scf_value_create(g_hndl);
14974 if (v == NULL)
14975 scfdie();
14976
14977 scf_value_set_boolean(v, enabled);
14978
14979 if (scf_entry_add_value(e, v) != 0)
14980 scfdie();
14981 } else {
14982 if (scf_iter_property_values(viter, prop) != 0)
14983 scfdie();
14984
14985 for (;;) {
14986 v = scf_value_create(g_hndl);
14987 if (v == NULL)
14988 scfdie();
14989
14990 r = scf_iter_next_value(viter, v);
14991 if (r == -1)
14992 scfdie();
14993 if (r == 0) {
14994 scf_value_destroy(v);
14995 break;
14996 }
14997
14998 if (scf_entry_add_value(e, v) != SCF_SUCCESS)
14999 scfdie();
15000 }
15001 }
15002 }
15003
15004 free(nbuf);
15005 scf_iter_destroy(viter);
15006 scf_property_destroy(prop);
15007 scf_iter_destroy(iter);
15008
15009 r = scf_transaction_commit(tx);
15010 if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
15011 scfdie();
15012
15013 scf_transaction_destroy_children(tx);
15014 scf_transaction_destroy(tx);
15015
15016 switch (r) {
15017 case 1: return (0);
15018 case 0: return (-2);
15019 case -1: return (-1);
15020
15021 default:
15022 abort();
15023 }
15024
15025 /* NOTREACHED */
15026 }
15027
15028 void
15029 lscf_revert(const char *snapname)
15030 {
15031 scf_snapshot_t *snap, *prev;
15032 scf_snaplevel_t *level, *nlevel;
15033 scf_iter_t *iter;
15034 scf_propertygroup_t *pg, *npg;
15035 scf_property_t *prop;
15036 scf_value_t *val;
15037 char *nbuf, *tbuf;
15038 uint8_t enabled;
15039
15040 lscf_prep_hndl();
15041
15042 if (cur_inst == NULL) {
15043 semerr(gettext("Instance not selected.\n"));
15044 return;
15045 }
15046
15047 if (snapname != NULL) {
15048 snap = scf_snapshot_create(g_hndl);
15049 if (snap == NULL)
15050 scfdie();
15051
15052 if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
15053 SCF_SUCCESS) {
15054 switch (scf_error()) {
15055 case SCF_ERROR_INVALID_ARGUMENT:
15056 semerr(gettext("Invalid snapshot name "
15057 "\"%s\".\n"), snapname);
15058 break;
15059
15060 case SCF_ERROR_NOT_FOUND:
15061 semerr(gettext("No such snapshot.\n"));
15062 break;
15063
15064 default:
15065 scfdie();
15066 }
15067
15068 scf_snapshot_destroy(snap);
15069 return;
15070 }
15071 } else {
15072 if (cur_snap != NULL) {
15073 snap = cur_snap;
15074 } else {
15075 semerr(gettext("No snapshot selected.\n"));
15076 return;
15077 }
15078 }
15079
15080 if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
15081 (level = scf_snaplevel_create(g_hndl)) == NULL ||
15082 (iter = scf_iter_create(g_hndl)) == NULL ||
15083 (pg = scf_pg_create(g_hndl)) == NULL ||
15084 (npg = scf_pg_create(g_hndl)) == NULL ||
15085 (prop = scf_property_create(g_hndl)) == NULL ||
15086 (val = scf_value_create(g_hndl)) == NULL)
15087 scfdie();
15088
15089 nbuf = safe_malloc(max_scf_name_len + 1);
15090 tbuf = safe_malloc(max_scf_pg_type_len + 1);
15091
15092 /* Take the "previous" snapshot before we blow away the properties. */
15093 if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
15094 if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
15095 scfdie();
15096 } else {
15097 if (scf_error() != SCF_ERROR_NOT_FOUND)
15098 scfdie();
15099
15100 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
15101 scfdie();
15102 }
15103
15104 /* Save general/enabled, since we're probably going to replace it. */
15105 enabled = 2;
15106 if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
15107 scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
15108 scf_property_get_value(prop, val) == 0)
15109 (void) scf_value_get_boolean(val, &enabled);
15110
15111 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15112 if (scf_error() != SCF_ERROR_NOT_FOUND)
15113 scfdie();
15114
15115 goto out;
15116 }
15117
15118 for (;;) {
15119 boolean_t isinst;
15120 uint32_t flags;
15121 int r;
15122
15123 /* Clear the properties from the corresponding entity. */
15124 isinst = snaplevel_is_instance(level);
15125
15126 if (!isinst)
15127 r = scf_iter_service_pgs(iter, cur_svc);
15128 else
15129 r = scf_iter_instance_pgs(iter, cur_inst);
15130 if (r != SCF_SUCCESS)
15131 scfdie();
15132
15133 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15134 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15135 scfdie();
15136
15137 /* Skip nonpersistent pgs. */
15138 if (flags & SCF_PG_FLAG_NONPERSISTENT)
15139 continue;
15140
15141 if (scf_pg_delete(pg) != SCF_SUCCESS) {
15142 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15143 scfdie();
15144
15145 semerr(emsg_permission_denied);
15146 goto out;
15147 }
15148 }
15149 if (r == -1)
15150 scfdie();
15151
15152 /* Copy the properties to the corresponding entity. */
15153 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
15154 scfdie();
15155
15156 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15157 if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
15158 scfdie();
15159
15160 if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
15161 0)
15162 scfdie();
15163
15164 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15165 scfdie();
15166
15167 if (!isinst)
15168 r = scf_service_add_pg(cur_svc, nbuf, tbuf,
15169 flags, npg);
15170 else
15171 r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
15172 flags, npg);
15173 if (r != SCF_SUCCESS) {
15174 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15175 scfdie();
15176
15177 semerr(emsg_permission_denied);
15178 goto out;
15179 }
15180
15181 if ((enabled == 0 || enabled == 1) &&
15182 strcmp(nbuf, scf_pg_general) == 0)
15183 r = pg_copy(pg, npg, enabled);
15184 else
15185 r = pg_copy(pg, npg, 2);
15186
15187 switch (r) {
15188 case 0:
15189 break;
15190
15191 case -1:
15192 semerr(emsg_permission_denied);
15193 goto out;
15194
15195 case -2:
15196 semerr(gettext(
15197 "Interrupted by another change.\n"));
15198 goto out;
15199
15200 default:
15201 abort();
15202 }
15203 }
15204 if (r == -1)
15205 scfdie();
15206
15207 /* Get next level. */
15208 nlevel = scf_snaplevel_create(g_hndl);
15209 if (nlevel == NULL)
15210 scfdie();
15211
15212 if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
15213 SCF_SUCCESS) {
15214 if (scf_error() != SCF_ERROR_NOT_FOUND)
15215 scfdie();
15216
15217 scf_snaplevel_destroy(nlevel);
15218 break;
15219 }
15220
15221 scf_snaplevel_destroy(level);
15222 level = nlevel;
15223 }
15224
15225 if (snapname == NULL) {
15226 lscf_selectsnap(NULL);
15227 snap = NULL; /* cur_snap has been destroyed */
15228 }
15229
15230 out:
15231 free(tbuf);
15232 free(nbuf);
15233 scf_value_destroy(val);
15234 scf_property_destroy(prop);
15235 scf_pg_destroy(npg);
15236 scf_pg_destroy(pg);
15237 scf_iter_destroy(iter);
15238 scf_snaplevel_destroy(level);
15239 scf_snapshot_destroy(prev);
15240 if (snap != cur_snap)
15241 scf_snapshot_destroy(snap);
15242 }
15243
15244 void
15245 lscf_refresh(void)
15246 {
15247 ssize_t fmrilen;
15248 size_t bufsz;
15249 char *fmribuf;
15250 int r;
15251
15252 lscf_prep_hndl();
15253
15254 if (cur_inst == NULL) {
15255 semerr(gettext("Instance not selected.\n"));
15256 return;
15257 }
15258
15259 bufsz = max_scf_fmri_len + 1;
15260 fmribuf = safe_malloc(bufsz);
15261 fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15262 if (fmrilen < 0) {
15263 free(fmribuf);
15264 if (scf_error() != SCF_ERROR_DELETED)
15265 scfdie();
15266 scf_instance_destroy(cur_inst);
15267 cur_inst = NULL;
15268 warn(emsg_deleted);
15269 return;
15270 }
15271 assert(fmrilen < bufsz);
15272
15273 r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15274 switch (r) {
15275 case 0:
15276 break;
15277
15278 case ECONNABORTED:
15279 warn(gettext("Could not refresh %s "
15280 "(repository connection broken).\n"), fmribuf);
15281 break;
15282
15283 case ECANCELED:
15284 warn(emsg_deleted);
15285 break;
15286
15287 case EPERM:
15288 warn(gettext("Could not refresh %s "
15289 "(permission denied).\n"), fmribuf);
15290 break;
15291
15292 case ENOSPC:
15293 warn(gettext("Could not refresh %s "
15294 "(repository server out of resources).\n"),
15295 fmribuf);
15296 break;
15297
15298 case EACCES:
15299 default:
15300 bad_error("refresh_entity", scf_error());
15301 }
15302
15303 free(fmribuf);
15304 }
15305
15306 /*
15307 * describe [-v] [-t] [pg/prop]
15308 */
15309 int
15310 lscf_describe(uu_list_t *args, int hasargs)
15311 {
15312 int ret = 0;
15313 size_t i;
15314 int argc;
15315 char **argv = NULL;
15316 string_list_t *slp;
15317 int do_verbose = 0;
15318 int do_templates = 0;
15319 char *pattern = NULL;
15320
15321 lscf_prep_hndl();
15322
15323 if (hasargs != 0) {
15324 argc = uu_list_numnodes(args);
15325 if (argc < 1)
15326 goto usage;
15327
15328 argv = calloc(argc + 1, sizeof (char *));
15329 if (argv == NULL)
15330 uu_die(gettext("Out of memory.\n"));
15331
15332 for (slp = uu_list_first(args), i = 0;
15333 slp != NULL;
15334 slp = uu_list_next(args, slp), ++i)
15335 argv[i] = slp->str;
15336
15337 argv[i] = NULL;
15338
15339 /*
15340 * We start optind = 0 because our list of arguments
15341 * starts at argv[0]
15342 */
15343 optind = 0;
15344 opterr = 0;
15345 for (;;) {
15346 ret = getopt(argc, argv, "vt");
15347 if (ret == -1)
15348 break;
15349
15350 switch (ret) {
15351 case 'v':
15352 do_verbose = 1;
15353 break;
15354
15355 case 't':
15356 do_templates = 1;
15357 break;
15358
15359 case '?':
15360 goto usage;
15361
15362 default:
15363 bad_error("getopt", ret);
15364 }
15365 }
15366
15367 pattern = argv[optind];
15368 }
15369
15370 if (cur_inst == NULL && cur_svc == NULL) {
15371 semerr(emsg_entity_not_selected);
15372 ret = -1;
15373 goto out;
15374 }
15375
15376 /*
15377 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15378 * output if their last parameter is set to 2. Less information is
15379 * produced if the parameter is set to 1.
15380 */
15381 if (pattern == NULL) {
15382 if (do_verbose == 1)
15383 list_entity_tmpl(2);
15384 else
15385 list_entity_tmpl(1);
15386 }
15387
15388 if (do_templates == 0) {
15389 if (do_verbose == 1)
15390 listprop(pattern, 0, 2);
15391 else
15392 listprop(pattern, 0, 1);
15393 } else {
15394 if (do_verbose == 1)
15395 listtmpl(pattern, 2);
15396 else
15397 listtmpl(pattern, 1);
15398 }
15399
15400 ret = 0;
15401 out:
15402 if (argv != NULL)
15403 free(argv);
15404 return (ret);
15405 usage:
15406 ret = -2;
15407 goto out;
15408 }
15409
15410 #define PARAM_ACTIVE ((const char *) "active")
15411 #define PARAM_INACTIVE ((const char *) "inactive")
15412 #define PARAM_SMTP_TO ((const char *) "to")
15413
15414 /*
15415 * tokenize()
15416 * Breaks down the string according to the tokens passed.
15417 * Caller is responsible for freeing array of pointers returned.
15418 * Returns NULL on failure
15419 */
15420 char **
15421 tokenize(char *str, const char *sep)
15422 {
15423 char *token, *lasts;
15424 char **buf;
15425 int n = 0; /* number of elements */
15426 int size = 8; /* size of the array (initial) */
15427
15428 buf = safe_malloc(size * sizeof (char *));
15429
15430 for (token = strtok_r(str, sep, &lasts); token != NULL;
15431 token = strtok_r(NULL, sep, &lasts), ++n) {
15432 if (n + 1 >= size) {
15433 size *= 2;
15434 if ((buf = realloc(buf, size * sizeof (char *))) ==
15435 NULL) {
15436 uu_die(gettext("Out of memory"));
15437 }
15438 }
15439 buf[n] = token;
15440 }
15441 /* NULL terminate the pointer array */
15442 buf[n] = NULL;
15443
15444 return (buf);
15445 }
15446
15447 int32_t
15448 check_tokens(char **p)
15449 {
15450 int32_t smf = 0;
15451 int32_t fma = 0;
15452
15453 while (*p) {
15454 int32_t t = string_to_tset(*p);
15455
15456 if (t == 0) {
15457 if (is_fma_token(*p) == 0)
15458 return (INVALID_TOKENS);
15459 fma = 1; /* this token is an fma event */
15460 } else {
15461 smf |= t;
15462 }
15463
15464 if (smf != 0 && fma == 1)
15465 return (MIXED_TOKENS);
15466 ++p;
15467 }
15468
15469 if (smf > 0)
15470 return (smf);
15471 else if (fma == 1)
15472 return (FMA_TOKENS);
15473
15474 return (INVALID_TOKENS);
15475 }
15476
15477 static int
15478 get_selection_str(char *fmri, size_t sz)
15479 {
15480 if (g_hndl == NULL) {
15481 semerr(emsg_entity_not_selected);
15482 return (-1);
15483 } else if (cur_level != NULL) {
15484 semerr(emsg_invalid_for_snapshot);
15485 return (-1);
15486 } else {
15487 lscf_get_selection_str(fmri, sz);
15488 }
15489
15490 return (0);
15491 }
15492
15493 void
15494 lscf_delnotify(const char *set, int global)
15495 {
15496 char *str = strdup(set);
15497 char **pgs;
15498 char **p;
15499 int32_t tset;
15500 char *fmri = NULL;
15501
15502 if (str == NULL)
15503 uu_die(gettext("Out of memory.\n"));
15504
15505 pgs = tokenize(str, ",");
15506
15507 if ((tset = check_tokens(pgs)) > 0) {
15508 size_t sz = max_scf_fmri_len + 1;
15509
15510 fmri = safe_malloc(sz);
15511 if (global) {
15512 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15513 } else if (get_selection_str(fmri, sz) != 0) {
15514 goto out;
15515 }
15516
15517 if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri,
15518 tset) != SCF_SUCCESS) {
15519 uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15520 scf_strerror(scf_error()));
15521 }
15522 } else if (tset == FMA_TOKENS) {
15523 if (global) {
15524 semerr(gettext("Can't use option '-g' with FMA event "
15525 "definitions\n"));
15526 goto out;
15527 }
15528
15529 for (p = pgs; *p; ++p) {
15530 if (smf_notify_del_params(de_tag(*p), NULL, 0) !=
15531 SCF_SUCCESS) {
15532 uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
15533 scf_strerror(scf_error()));
15534 goto out;
15535 }
15536 }
15537 } else if (tset == MIXED_TOKENS) {
15538 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15539 goto out;
15540 } else {
15541 uu_die(gettext("Invalid input.\n"));
15542 }
15543
15544 out:
15545 free(fmri);
15546 free(pgs);
15547 free(str);
15548 }
15549
15550 void
15551 lscf_listnotify(const char *set, int global)
15552 {
15553 char *str = safe_strdup(set);
15554 char **pgs;
15555 char **p;
15556 int32_t tset;
15557 nvlist_t *nvl;
15558 char *fmri = NULL;
15559
15560 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
15561 uu_die(gettext("Out of memory.\n"));
15562
15563 pgs = tokenize(str, ",");
15564
15565 if ((tset = check_tokens(pgs)) > 0) {
15566 size_t sz = max_scf_fmri_len + 1;
15567
15568 fmri = safe_malloc(sz);
15569 if (global) {
15570 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15571 } else if (get_selection_str(fmri, sz) != 0) {
15572 goto out;
15573 }
15574
15575 if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
15576 SCF_SUCCESS) {
15577 if (scf_error() != SCF_ERROR_NOT_FOUND &&
15578 scf_error() != SCF_ERROR_DELETED)
15579 uu_warn(gettext(
15580 "Failed listnotify: %s\n"),
15581 scf_strerror(scf_error()));
15582 goto out;
15583 }
15584
15585 listnotify_print(nvl, NULL);
15586 } else if (tset == FMA_TOKENS) {
15587 if (global) {
15588 semerr(gettext("Can't use option '-g' with FMA event "
15589 "definitions\n"));
15590 goto out;
15591 }
15592
15593 for (p = pgs; *p; ++p) {
15594 if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
15595 SCF_SUCCESS) {
15596 /*
15597 * if the preferences have just been deleted
15598 * or does not exist, just skip.
15599 */
15600 if (scf_error() == SCF_ERROR_NOT_FOUND ||
15601 scf_error() == SCF_ERROR_DELETED)
15602 continue;
15603 uu_warn(gettext(
15604 "Failed listnotify: %s\n"),
15605 scf_strerror(scf_error()));
15606 goto out;
15607 }
15608 listnotify_print(nvl, re_tag(*p));
15609 }
15610 } else if (tset == MIXED_TOKENS) {
15611 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15612 goto out;
15613 } else {
15614 semerr(gettext("Invalid input.\n"));
15615 }
15616
15617 out:
15618 nvlist_free(nvl);
15619 free(fmri);
15620 free(pgs);
15621 free(str);
15622 }
15623
15624 static char *
15625 strip_quotes_and_blanks(char *s)
15626 {
15627 char *start = s;
15628 char *end = strrchr(s, '\"');
15629
15630 if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
15631 start = s + 1;
15632 while (isblank(*start))
15633 start++;
15634 while (isblank(*(end - 1)) && end > start) {
15635 end--;
15636 }
15637 *end = '\0';
15638 }
15639
15640 return (start);
15641 }
15642
15643 static int
15644 set_active(nvlist_t *mech, const char *hier_part)
15645 {
15646 boolean_t b;
15647
15648 if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
15649 b = B_TRUE;
15650 } else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
15651 b = B_FALSE;
15652 } else {
15653 return (-1);
15654 }
15655
15656 if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
15657 uu_die(gettext("Out of memory.\n"));
15658
15659 return (0);
15660 }
15661
15662 static int
15663 add_snmp_params(nvlist_t *mech, char *hier_part)
15664 {
15665 return (set_active(mech, hier_part));
15666 }
15667
15668 static int
15669 add_syslog_params(nvlist_t *mech, char *hier_part)
15670 {
15671 return (set_active(mech, hier_part));
15672 }
15673
15674 /*
15675 * add_mailto_paramas()
15676 * parse the hier_part of mailto URI
15677 * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
15678 * or mailto:{[active]|inactive}
15679 */
15680 static int
15681 add_mailto_params(nvlist_t *mech, char *hier_part)
15682 {
15683 const char *tok = "?&";
15684 char *p;
15685 char *lasts;
15686 char *param;
15687 char *val;
15688
15689 /*
15690 * If the notification parametes are in the form of
15691 *
15692 * malito:{[active]|inactive}
15693 *
15694 * we set the property accordingly and return.
15695 * Otherwise, we make the notification type active and
15696 * process the hier_part.
15697 */
15698 if (set_active(mech, hier_part) == 0)
15699 return (0);
15700 else if (set_active(mech, PARAM_ACTIVE) != 0)
15701 return (-1);
15702
15703 if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) {
15704 /*
15705 * sanity check: we only get here if hier_part = "", but
15706 * that's handled by set_active
15707 */
15708 uu_die("strtok_r");
15709 }
15710
15711 if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0)
15712 uu_die(gettext("Out of memory.\n"));
15713
15714 while ((p = strtok_r(NULL, tok, &lasts)) != NULL)
15715 if ((param = strtok_r(p, "=", &val)) != NULL)
15716 if (nvlist_add_string(mech, param, val) != 0)
15717 uu_die(gettext("Out of memory.\n"));
15718
15719 return (0);
15720 }
15721
15722 static int
15723 uri_split(char *uri, char **scheme, char **hier_part)
15724 {
15725 int r = -1;
15726
15727 if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
15728 *hier_part == NULL) {
15729 semerr(gettext("'%s' is not an URI\n"), uri);
15730 return (r);
15731 }
15732
15733 if ((r = check_uri_scheme(*scheme)) < 0) {
15734 semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
15735 return (r);
15736 }
15737
15738 return (r);
15739 }
15740
15741 static int
15742 process_uri(nvlist_t *params, char *uri)
15743 {
15744 char *scheme;
15745 char *hier_part;
15746 nvlist_t *mech;
15747 int index;
15748 int r;
15749
15750 if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
15751 return (-1);
15752
15753 if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
15754 uu_die(gettext("Out of memory.\n"));
15755
15756 switch (index) {
15757 case 0:
15758 /* error messages displayed by called function */
15759 r = add_mailto_params(mech, hier_part);
15760 break;
15761
15762 case 1:
15763 if ((r = add_snmp_params(mech, hier_part)) != 0)
15764 semerr(gettext("Not valid parameters: '%s'\n"),
15765 hier_part);
15766 break;
15767
15768 case 2:
15769 if ((r = add_syslog_params(mech, hier_part)) != 0)
15770 semerr(gettext("Not valid parameters: '%s'\n"),
15771 hier_part);
15772 break;
15773
15774 default:
15775 r = -1;
15776 }
15777
15778 if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
15779 mech) != 0)
15780 uu_die(gettext("Out of memory.\n"));
15781
15782 nvlist_free(mech);
15783 return (r);
15784 }
15785
15786 static int
15787 set_params(nvlist_t *params, char **p)
15788 {
15789 char *uri;
15790
15791 if (p == NULL)
15792 /* sanity check */
15793 uu_die("set_params");
15794
15795 while (*p) {
15796 uri = strip_quotes_and_blanks(*p);
15797 if (process_uri(params, uri) != 0)
15798 return (-1);
15799
15800 ++p;
15801 }
15802
15803 return (0);
15804 }
15805
15806 static int
15807 setnotify(const char *e, char **p, int global)
15808 {
15809 char *str = safe_strdup(e);
15810 char **events;
15811 int32_t tset;
15812 int r = -1;
15813 nvlist_t *nvl, *params;
15814 char *fmri = NULL;
15815
15816 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
15817 nvlist_alloc(¶ms, NV_UNIQUE_NAME, 0) != 0 ||
15818 nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
15819 SCF_NOTIFY_PARAMS_VERSION) != 0)
15820 uu_die(gettext("Out of memory.\n"));
15821
15822 events = tokenize(str, ",");
15823
15824 if ((tset = check_tokens(events)) > 0) {
15825 /* SMF state transitions parameters */
15826 size_t sz = max_scf_fmri_len + 1;
15827
15828 fmri = safe_malloc(sz);
15829 if (global) {
15830 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15831 } else if (get_selection_str(fmri, sz) != 0) {
15832 goto out;
15833 }
15834
15835 if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 ||
15836 nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0)
15837 uu_die(gettext("Out of memory.\n"));
15838
15839 if ((r = set_params(params, p)) == 0) {
15840 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS,
15841 params) != 0)
15842 uu_die(gettext("Out of memory.\n"));
15843
15844 if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
15845 nvl) != SCF_SUCCESS) {
15846 r = -1;
15847 uu_warn(gettext(
15848 "Failed smf_notify_set_params(3SCF): %s\n"),
15849 scf_strerror(scf_error()));
15850 }
15851 }
15852 } else if (tset == FMA_TOKENS) {
15853 /* FMA event parameters */
15854 if (global) {
15855 semerr(gettext("Can't use option '-g' with FMA event "
15856 "definitions\n"));
15857 goto out;
15858 }
15859
15860 if ((r = set_params(params, p)) != 0)
15861 goto out;
15862
15863 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
15864 uu_die(gettext("Out of memory.\n"));
15865
15866 while (*events) {
15867 if (smf_notify_set_params(de_tag(*events), nvl) !=
15868 SCF_SUCCESS)
15869 uu_warn(gettext(
15870 "Failed smf_notify_set_params(3SCF) for "
15871 "event %s: %s\n"), *events,
15872 scf_strerror(scf_error()));
15873 events++;
15874 }
15875 } else if (tset == MIXED_TOKENS) {
15876 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15877 } else {
15878 /* Sanity check */
15879 uu_die(gettext("Invalid input.\n"));
15880 }
15881
15882 out:
15883 nvlist_free(nvl);
15884 nvlist_free(params);
15885 free(fmri);
15886 free(str);
15887
15888 return (r);
15889 }
15890
15891 int
15892 lscf_setnotify(uu_list_t *args)
15893 {
15894 int argc;
15895 char **argv = NULL;
15896 string_list_t *slp;
15897 int global;
15898 char *events;
15899 char **p;
15900 int i;
15901 int ret;
15902
15903 if ((argc = uu_list_numnodes(args)) < 2)
15904 goto usage;
15905
15906 argv = calloc(argc + 1, sizeof (char *));
15907 if (argv == NULL)
15908 uu_die(gettext("Out of memory.\n"));
15909
15910 for (slp = uu_list_first(args), i = 0;
15911 slp != NULL;
15912 slp = uu_list_next(args, slp), ++i)
15913 argv[i] = slp->str;
15914
15915 argv[i] = NULL;
15916
15917 if (strcmp(argv[0], "-g") == 0) {
15918 global = 1;
15919 events = argv[1];
15920 p = argv + 2;
15921 } else {
15922 global = 0;
15923 events = argv[0];
15924 p = argv + 1;
15925 }
15926
15927 ret = setnotify(events, p, global);
15928
15929 out:
15930 free(argv);
15931 return (ret);
15932
15933 usage:
15934 ret = -2;
15935 goto out;
15936 }
15937
15938 /*
15939 * Creates a list of instance name strings associated with a service. If
15940 * wohandcrafted flag is set, get only instances that have a last-import
15941 * snapshot, instances that were imported via svccfg.
15942 */
15943 static uu_list_t *
15944 create_instance_list(scf_service_t *svc, int wohandcrafted)
15945 {
15946 scf_snapshot_t *snap = NULL;
15947 scf_instance_t *inst;
15948 scf_iter_t *inst_iter;
15949 uu_list_t *instances;
15950 char *instname;
15951 int r;
15952
15953 inst_iter = scf_iter_create(g_hndl);
15954 inst = scf_instance_create(g_hndl);
15955 if (inst_iter == NULL || inst == NULL) {
15956 uu_warn(gettext("Could not create instance or iterator\n"));
15957 scfdie();
15958 }
15959
15960 if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
15961 return (instances);
15962
15963 if (scf_iter_service_instances(inst_iter, svc) != 0) {
15964 switch (scf_error()) {
15965 case SCF_ERROR_CONNECTION_BROKEN:
15966 case SCF_ERROR_DELETED:
15967 uu_list_destroy(instances);
15968 instances = NULL;
15969 goto out;
15970
15971 case SCF_ERROR_HANDLE_MISMATCH:
15972 case SCF_ERROR_NOT_BOUND:
15973 case SCF_ERROR_NOT_SET:
15974 default:
15975 bad_error("scf_iter_service_instances", scf_error());
15976 }
15977 }
15978
15979 instname = safe_malloc(max_scf_name_len + 1);
15980 while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
15981 if (r == -1) {
15982 (void) uu_warn(gettext("Unable to iterate through "
15983 "instances to create instance list : %s\n"),
15984 scf_strerror(scf_error()));
15985
15986 uu_list_destroy(instances);
15987 instances = NULL;
15988 goto out;
15989 }
15990
15991 /*
15992 * If the instance does not have a last-import snapshot
15993 * then do not add it to the list as it is a hand-crafted
15994 * instance that should not be managed.
15995 */
15996 if (wohandcrafted) {
15997 if (snap == NULL &&
15998 (snap = scf_snapshot_create(g_hndl)) == NULL) {
15999 uu_warn(gettext("Unable to create snapshot "
16000 "entity\n"));
16001 scfdie();
16002 }
16003
16004 if (scf_instance_get_snapshot(inst,
16005 snap_lastimport, snap) != 0) {
16006 switch (scf_error()) {
16007 case SCF_ERROR_NOT_FOUND :
16008 case SCF_ERROR_DELETED:
16009 continue;
16010
16011 case SCF_ERROR_CONNECTION_BROKEN:
16012 uu_list_destroy(instances);
16013 instances = NULL;
16014 goto out;
16015
16016 case SCF_ERROR_HANDLE_MISMATCH:
16017 case SCF_ERROR_NOT_BOUND:
16018 case SCF_ERROR_NOT_SET:
16019 default:
16020 bad_error("scf_iter_service_instances",
16021 scf_error());
16022 }
16023 }
16024 }
16025
16026 if (scf_instance_get_name(inst, instname,
16027 max_scf_name_len + 1) < 0) {
16028 switch (scf_error()) {
16029 case SCF_ERROR_NOT_FOUND :
16030 continue;
16031
16032 case SCF_ERROR_CONNECTION_BROKEN:
16033 case SCF_ERROR_DELETED:
16034 uu_list_destroy(instances);
16035 instances = NULL;
16036 goto out;
16037
16038 case SCF_ERROR_HANDLE_MISMATCH:
16039 case SCF_ERROR_NOT_BOUND:
16040 case SCF_ERROR_NOT_SET:
16041 default:
16042 bad_error("scf_iter_service_instances",
16043 scf_error());
16044 }
16045 }
16046
16047 add_string(instances, instname);
16048 }
16049
16050 out:
16051 if (snap)
16052 scf_snapshot_destroy(snap);
16053
16054 scf_instance_destroy(inst);
16055 scf_iter_destroy(inst_iter);
16056 free(instname);
16057 return (instances);
16058 }
16059
16060 /*
16061 * disable an instance but wait for the instance to
16062 * move out of the running state.
16063 *
16064 * Returns 0 : if the instance did not disable
16065 * Returns non-zero : if the instance disabled.
16066 *
16067 */
16068 static int
16069 disable_instance(scf_instance_t *instance)
16070 {
16071 char *fmribuf;
16072 int enabled = 10000;
16073
16074 if (inst_is_running(instance)) {
16075 fmribuf = safe_malloc(max_scf_name_len + 1);
16076 if (scf_instance_to_fmri(instance, fmribuf,
16077 max_scf_name_len + 1) < 0) {
16078 free(fmribuf);
16079 return (0);
16080 }
16081
16082 /*
16083 * If the instance cannot be disabled then return
16084 * failure to disable and let the caller decide
16085 * if that is of importance.
16086 */
16087 if (smf_disable_instance(fmribuf, 0) != 0) {
16088 free(fmribuf);
16089 return (0);
16090 }
16091
16092 while (enabled) {
16093 if (!inst_is_running(instance))
16094 break;
16095
16096 (void) poll(NULL, 0, 5);
16097 enabled = enabled - 5;
16098 }
16099
16100 free(fmribuf);
16101 }
16102
16103 return (enabled);
16104 }
16105
16106 /*
16107 * Function to compare two service_manifest structures.
16108 */
16109 /* ARGSUSED2 */
16110 static int
16111 service_manifest_compare(const void *left, const void *right, void *unused)
16112 {
16113 service_manifest_t *l = (service_manifest_t *)left;
16114 service_manifest_t *r = (service_manifest_t *)right;
16115 int rc;
16116
16117 rc = strcmp(l->servicename, r->servicename);
16118
16119 return (rc);
16120 }
16121
16122 /*
16123 * Look for the provided service in the service to manifest
16124 * tree. If the service exists, and a manifest was provided
16125 * then add the manifest to that service. If the service
16126 * does not exist, then add the service and manifest to the
16127 * list.
16128 *
16129 * If the manifest is NULL, return the element if found. If
16130 * the service is not found return NULL.
16131 */
16132 service_manifest_t *
16133 find_add_svc_mfst(const char *svnbuf, const char *mfst)
16134 {
16135 service_manifest_t elem;
16136 service_manifest_t *fnelem;
16137 uu_avl_index_t marker;
16138
16139 elem.servicename = svnbuf;
16140 fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
16141
16142 if (mfst) {
16143 if (fnelem) {
16144 add_string(fnelem->mfstlist, strdup(mfst));
16145 } else {
16146 fnelem = safe_malloc(sizeof (*fnelem));
16147 fnelem->servicename = safe_strdup(svnbuf);
16148 if ((fnelem->mfstlist =
16149 uu_list_create(string_pool, NULL, 0)) == NULL)
16150 uu_die(gettext("Could not create property "
16151 "list: %s\n"), uu_strerror(uu_error()));
16152
16153 add_string(fnelem->mfstlist, safe_strdup(mfst));
16154
16155 uu_avl_insert(service_manifest_tree, fnelem, marker);
16156 }
16157 }
16158
16159 return (fnelem);
16160 }
16161
16162 /*
16163 * Create the service to manifest avl tree.
16164 *
16165 * Walk each of the manifests currently installed in the supported
16166 * directories, /lib/svc/manifests and /var/svc/manifests. For
16167 * each of the manifests, inventory the services and add them to
16168 * the tree.
16169 *
16170 * Code that calls this function should make sure fileystem/minimal is online,
16171 * /var is available, since this function walks the /var/svc/manifest directory.
16172 */
16173 static void
16174 create_manifest_tree(void)
16175 {
16176 manifest_info_t **entry;
16177 manifest_info_t **manifests;
16178 uu_list_walk_t *svcs;
16179 bundle_t *b;
16180 entity_t *mfsvc;
16181 char *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
16182 int c, status;
16183
16184 if (service_manifest_pool)
16185 return;
16186
16187 /*
16188 * Create the list pool for the service manifest list
16189 */
16190 service_manifest_pool = uu_avl_pool_create("service_manifest",
16191 sizeof (service_manifest_t),
16192 offsetof(service_manifest_t, svcmfst_node),
16193 service_manifest_compare, UU_DEFAULT);
16194 if (service_manifest_pool == NULL)
16195 uu_die(gettext("service_manifest pool creation failed: %s\n"),
16196 uu_strerror(uu_error()));
16197
16198 /*
16199 * Create the list
16200 */
16201 service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
16202 UU_DEFAULT);
16203 if (service_manifest_tree == NULL)
16204 uu_die(gettext("service_manifest tree creation failed: %s\n"),
16205 uu_strerror(uu_error()));
16206
16207 /*
16208 * Walk the manifests adding the service(s) from each manifest.
16209 *
16210 * If a service already exists add the manifest to the manifest
16211 * list for that service. This covers the case of a service that
16212 * is supported by multiple manifest files.
16213 */
16214 for (c = 0; dirs[c]; c++) {
16215 status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT);
16216 if (status < 0) {
16217 uu_warn(gettext("file tree walk of %s encountered "
16218 "error %s\n"), dirs[c], strerror(errno));
16219
16220 uu_avl_destroy(service_manifest_tree);
16221 service_manifest_tree = NULL;
16222 return;
16223 }
16224
16225 /*
16226 * If a manifest that was in the list is not found
16227 * then skip and go to the next manifest file.
16228 */
16229 if (manifests != NULL) {
16230 for (entry = manifests; *entry != NULL; entry++) {
16231 b = internal_bundle_new();
16232 if (lxml_get_bundle_file(b, (*entry)->mi_path,
16233 SVCCFG_OP_IMPORT) != 0) {
16234 internal_bundle_free(b);
16235 continue;
16236 }
16237
16238 svcs = uu_list_walk_start(b->sc_bundle_services,
16239 0);
16240 if (svcs == NULL) {
16241 internal_bundle_free(b);
16242 continue;
16243 }
16244
16245 while ((mfsvc = uu_list_walk_next(svcs)) !=
16246 NULL) {
16247 /* Add manifest to service */
16248 (void) find_add_svc_mfst(mfsvc->sc_name,
16249 (*entry)->mi_path);
16250 }
16251
16252 uu_list_walk_end(svcs);
16253 internal_bundle_free(b);
16254 }
16255
16256 free_manifest_array(manifests);
16257 }
16258 }
16259 }
16260
16261 /*
16262 * Check the manifest history file to see
16263 * if the service was ever installed from
16264 * one of the supported directories.
16265 *
16266 * Return Values :
16267 * -1 - if there's error reading manifest history file
16268 * 1 - if the service is not found
16269 * 0 - if the service is found
16270 */
16271 static int
16272 check_mfst_history(const char *svcname)
16273 {
16274 struct stat st;
16275 caddr_t mfsthist_start;
16276 char *svnbuf;
16277 int fd;
16278 int r = 1;
16279
16280 fd = open(MFSTHISTFILE, O_RDONLY);
16281 if (fd == -1) {
16282 uu_warn(gettext("Unable to open the history file\n"));
16283 return (-1);
16284 }
16285
16286 if (fstat(fd, &st) == -1) {
16287 uu_warn(gettext("Unable to stat the history file\n"));
16288 return (-1);
16289 }
16290
16291 mfsthist_start = mmap(0, st.st_size, PROT_READ,
16292 MAP_PRIVATE, fd, 0);
16293
16294 (void) close(fd);
16295 if (mfsthist_start == MAP_FAILED ||
16296 *(mfsthist_start + st.st_size) != '\0') {
16297 (void) munmap(mfsthist_start, st.st_size);
16298 return (-1);
16299 }
16300
16301 /*
16302 * The manifest history file is a space delimited list
16303 * of service and instance to manifest linkage. Adding
16304 * a space to the end of the service name so to get only
16305 * the service that is being searched for.
16306 */
16307 svnbuf = uu_msprintf("%s ", svcname);
16308 if (svnbuf == NULL)
16309 uu_die(gettext("Out of memory"));
16310
16311 if (strstr(mfsthist_start, svnbuf) != NULL)
16312 r = 0;
16313
16314 (void) munmap(mfsthist_start, st.st_size);
16315 uu_free(svnbuf);
16316 return (r);
16317 }
16318
16319 /*
16320 * Take down each of the instances in the service
16321 * and remove them, then delete the service.
16322 */
16323 static void
16324 teardown_service(scf_service_t *svc, const char *svnbuf)
16325 {
16326 scf_instance_t *instance;
16327 scf_iter_t *iter;
16328 int r;
16329
16330 safe_printf(gettext("Delete service %s as there are no "
16331 "supporting manifests\n"), svnbuf);
16332
16333 instance = scf_instance_create(g_hndl);
16334 iter = scf_iter_create(g_hndl);
16335 if (iter == NULL || instance == NULL) {
16336 uu_warn(gettext("Unable to create supporting entities to "
16337 "teardown the service\n"));
16338 uu_warn(gettext("scf error is : %s\n"),
16339 scf_strerror(scf_error()));
16340 scfdie();
16341 }
16342
16343 if (scf_iter_service_instances(iter, svc) != 0) {
16344 switch (scf_error()) {
16345 case SCF_ERROR_CONNECTION_BROKEN:
16346 case SCF_ERROR_DELETED:
16347 goto out;
16348
16349 case SCF_ERROR_HANDLE_MISMATCH:
16350 case SCF_ERROR_NOT_BOUND:
16351 case SCF_ERROR_NOT_SET:
16352 default:
16353 bad_error("scf_iter_service_instances",
16354 scf_error());
16355 }
16356 }
16357
16358 while ((r = scf_iter_next_instance(iter, instance)) != 0) {
16359 if (r == -1) {
16360 uu_warn(gettext("Error - %s\n"),
16361 scf_strerror(scf_error()));
16362 goto out;
16363 }
16364
16365 (void) disable_instance(instance);
16366 }
16367
16368 /*
16369 * Delete the service... forcing the deletion in case
16370 * any of the instances did not disable.
16371 */
16372 (void) lscf_service_delete(svc, 1);
16373 out:
16374 scf_instance_destroy(instance);
16375 scf_iter_destroy(iter);
16376 }
16377
16378 /*
16379 * Get the list of instances supported by the manifest
16380 * file.
16381 *
16382 * Return 0 if there are no instances.
16383 *
16384 * Return -1 if there are errors attempting to collect instances.
16385 *
16386 * Return the count of instances found if there are no errors.
16387 *
16388 */
16389 static int
16390 check_instance_support(char *mfstfile, const char *svcname,
16391 uu_list_t *instances)
16392 {
16393 uu_list_walk_t *svcs, *insts;
16394 uu_list_t *ilist;
16395 bundle_t *b;
16396 entity_t *mfsvc, *mfinst;
16397 const char *svcn;
16398 int rminstcnt = 0;
16399
16400
16401 b = internal_bundle_new();
16402
16403 if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
16404 /*
16405 * Unable to process the manifest file for
16406 * instance support, so just return as
16407 * don't want to remove instances that could
16408 * not be accounted for that might exist here.
16409 */
16410 internal_bundle_free(b);
16411 return (0);
16412 }
16413
16414 svcs = uu_list_walk_start(b->sc_bundle_services, 0);
16415 if (svcs == NULL) {
16416 internal_bundle_free(b);
16417 return (0);
16418 }
16419
16420 svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
16421 (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
16422
16423 while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
16424 if (strcmp(mfsvc->sc_name, svcn) == 0)
16425 break;
16426 }
16427 uu_list_walk_end(svcs);
16428
16429 if (mfsvc == NULL) {
16430 internal_bundle_free(b);
16431 return (-1);
16432 }
16433
16434 ilist = mfsvc->sc_u.sc_service.sc_service_instances;
16435 if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
16436 internal_bundle_free(b);
16437 return (0);
16438 }
16439
16440 while ((mfinst = uu_list_walk_next(insts)) != NULL) {
16441 /*
16442 * Remove the instance from the instances list.
16443 * The unaccounted for instances will be removed
16444 * from the service once all manifests are
16445 * processed.
16446 */
16447 (void) remove_string(instances,
16448 mfinst->sc_name);
16449 rminstcnt++;
16450 }
16451
16452 uu_list_walk_end(insts);
16453 internal_bundle_free(b);
16454
16455 return (rminstcnt);
16456 }
16457
16458 /*
16459 * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16460 * 'false' to indicate there's no manifest file(s) found for the service.
16461 */
16462 static void
16463 svc_add_no_support(scf_service_t *svc)
16464 {
16465 char *pname;
16466
16467 /* Add no support */
16468 cur_svc = svc;
16469 if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
16470 return;
16471
16472 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
16473 if (pname == NULL)
16474 uu_die(gettext("Out of memory.\n"));
16475
16476 (void) lscf_addpropvalue(pname, "boolean:", "0");
16477
16478 uu_free(pname);
16479 cur_svc = NULL;
16480 }
16481
16482 /*
16483 * This function handles all upgrade scenarios for a service that doesn't have
16484 * SCF_PG_MANIFESTFILES pg. The function creates and populates
16485 * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16486 * manifest(s) mapping. Manifests under supported directories are inventoried
16487 * and a property is added for each file that delivers configuration to the
16488 * service. A service that has no corresponding manifest files (deleted) are
16489 * removed from repository.
16490 *
16491 * Unsupported services:
16492 *
16493 * A service is considered unsupported if there is no corresponding manifest
16494 * in the supported directories for that service and the service isn't in the
16495 * history file list. The history file, MFSTHISTFILE, contains a list of all
16496 * services and instances that were delivered by Solaris before the introduction
16497 * of the SCF_PG_MANIFESTFILES property group. The history file also contains
16498 * the path to the manifest file that defined the service or instance.
16499 *
16500 * Another type of unsupported services is 'handcrafted' services,
16501 * programmatically created services or services created by dependent entries
16502 * in other manifests. A handcrafted service is identified by its lack of any
16503 * instance containing last-import snapshot which is created during svccfg
16504 * import.
16505 *
16506 * This function sets a flag for unsupported services by setting services'
16507 * SCF_PG_MANIFESTFILES/support property to false.
16508 */
16509 static void
16510 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
16511 {
16512 service_manifest_t *elem;
16513 uu_list_walk_t *mfwalk;
16514 string_list_t *mfile;
16515 uu_list_t *instances;
16516 const char *sname;
16517 char *pname;
16518 int r;
16519
16520 /*
16521 * Since there's no guarantee manifests under /var are available during
16522 * early import, don't perform any upgrade during early import.
16523 */
16524 if (IGNORE_VAR)
16525 return;
16526
16527 if (service_manifest_tree == NULL) {
16528 create_manifest_tree();
16529 }
16530
16531 /*
16532 * Find service's supporting manifest(s) after
16533 * stripping off the svc:/ prefix that is part
16534 * of the fmri that is not used in the service
16535 * manifest bundle list.
16536 */
16537 sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
16538 strlen(SCF_FMRI_SERVICE_PREFIX);
16539 elem = find_add_svc_mfst(sname, NULL);
16540 if (elem == NULL) {
16541
16542 /*
16543 * A handcrafted service, one that has no instance containing
16544 * last-import snapshot, should get unsupported flag.
16545 */
16546 instances = create_instance_list(svc, 1);
16547 if (instances == NULL) {
16548 uu_warn(gettext("Unable to create instance list %s\n"),
16549 svcname);
16550 return;
16551 }
16552
16553 if (uu_list_numnodes(instances) == 0) {
16554 svc_add_no_support(svc);
16555 return;
16556 }
16557
16558 /*
16559 * If the service is in the history file, and its supporting
16560 * manifests are not found, we can safely delete the service
16561 * because its manifests are removed from the system.
16562 *
16563 * Services not found in the history file are not delivered by
16564 * Solaris and/or delivered outside supported directories, set
16565 * unsupported flag for these services.
16566 */
16567 r = check_mfst_history(svcname);
16568 if (r == -1)
16569 return;
16570
16571 if (r) {
16572 /* Set unsupported flag for service */
16573 svc_add_no_support(svc);
16574 } else {
16575 /* Delete the service */
16576 teardown_service(svc, svcname);
16577 }
16578
16579 return;
16580 }
16581
16582 /*
16583 * Walk through the list of manifests and add them
16584 * to the service.
16585 *
16586 * Create a manifestfiles pg and add the property.
16587 */
16588 mfwalk = uu_list_walk_start(elem->mfstlist, 0);
16589 if (mfwalk == NULL)
16590 return;
16591
16592 cur_svc = svc;
16593 r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
16594 if (r != 0) {
16595 cur_svc = NULL;
16596 return;
16597 }
16598
16599 while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
16600 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16601 mhash_filename_to_propname(mfile->str, 0));
16602 if (pname == NULL)
16603 uu_die(gettext("Out of memory.\n"));
16604
16605 (void) lscf_addpropvalue(pname, "astring:", mfile->str);
16606 uu_free(pname);
16607 }
16608 uu_list_walk_end(mfwalk);
16609
16610 cur_svc = NULL;
16611 }
16612
16613 /*
16614 * Take a service and process the manifest file entires to see if
16615 * there is continued support for the service and instances. If
16616 * not cleanup as appropriate.
16617 *
16618 * If a service does not have a manifest files entry flag it for
16619 * upgrade and return.
16620 *
16621 * For each manifestfiles property check if the manifest file is
16622 * under the supported /lib/svc/manifest or /var/svc/manifest path
16623 * and if not then return immediately as this service is not supported
16624 * by the cleanup mechanism and should be ignored.
16625 *
16626 * For each manifest file that is supported, check to see if the
16627 * file exists. If not then remove the manifest file property
16628 * from the service and the smf/manifest hash table. If the manifest
16629 * file exists then verify that it supports the instances that are
16630 * part of the service.
16631 *
16632 * Once all manifest files have been accounted for remove any instances
16633 * that are no longer supported in the service.
16634 *
16635 * Return values :
16636 * 0 - Successfully processed the service
16637 * non-zero - failed to process the service
16638 *
16639 * On most errors, will just return to wait and get the next service,
16640 * unless in case of unable to create the needed structures which is
16641 * most likely a fatal error that is not going to be recoverable.
16642 */
16643 int
16644 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
16645 {
16646 struct mpg_mfile *mpntov;
16647 struct mpg_mfile **mpvarry = NULL;
16648 scf_service_t *svc;
16649 scf_propertygroup_t *mpg;
16650 scf_property_t *mp;
16651 scf_value_t *mv;
16652 scf_iter_t *mi;
16653 scf_instance_t *instance;
16654 uu_list_walk_t *insts;
16655 uu_list_t *instances = NULL;
16656 boolean_t activity = (boolean_t)act;
16657 char *mpnbuf;
16658 char *mpvbuf;
16659 char *pgpropbuf;
16660 int mfstcnt, rminstct, instct, mfstmax;
16661 int index;
16662 int r = 0;
16663
16664 assert(g_hndl != NULL);
16665 assert(wip->svc != NULL);
16666 assert(wip->fmri != NULL);
16667
16668 svc = wip->svc;
16669
16670 mpg = scf_pg_create(g_hndl);
16671 mp = scf_property_create(g_hndl);
16672 mi = scf_iter_create(g_hndl);
16673 mv = scf_value_create(g_hndl);
16674 instance = scf_instance_create(g_hndl);
16675
16676 if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
16677 instance == NULL) {
16678 uu_warn(gettext("Unable to create the supporting entities\n"));
16679 uu_warn(gettext("scf error is : %s\n"),
16680 scf_strerror(scf_error()));
16681 scfdie();
16682 }
16683
16684 /*
16685 * Get the manifestfiles property group to be parsed for
16686 * files existence.
16687 */
16688 if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
16689 switch (scf_error()) {
16690 case SCF_ERROR_NOT_FOUND:
16691 upgrade_svc_mfst_connection(svc, wip->fmri);
16692 break;
16693 case SCF_ERROR_DELETED:
16694 case SCF_ERROR_CONNECTION_BROKEN:
16695 goto out;
16696
16697 case SCF_ERROR_HANDLE_MISMATCH:
16698 case SCF_ERROR_NOT_BOUND:
16699 case SCF_ERROR_NOT_SET:
16700 default:
16701 bad_error("scf_iter_pg_properties",
16702 scf_error());
16703 }
16704
16705 goto out;
16706 }
16707
16708 /*
16709 * Iterate through each of the manifestfiles properties
16710 * to determine what manifestfiles are available.
16711 *
16712 * If a manifest file is supported then increment the
16713 * count and therefore the service is safe.
16714 */
16715 if (scf_iter_pg_properties(mi, mpg) != 0) {
16716 switch (scf_error()) {
16717 case SCF_ERROR_DELETED:
16718 case SCF_ERROR_CONNECTION_BROKEN:
16719 goto out;
16720
16721 case SCF_ERROR_HANDLE_MISMATCH:
16722 case SCF_ERROR_NOT_BOUND:
16723 case SCF_ERROR_NOT_SET:
16724 default:
16725 bad_error("scf_iter_pg_properties",
16726 scf_error());
16727 }
16728 }
16729
16730 mfstcnt = 0;
16731 mfstmax = MFSTFILE_MAX;
16732 mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
16733 while ((r = scf_iter_next_property(mi, mp)) != 0) {
16734 if (r == -1)
16735 bad_error(gettext("Unable to iterate through "
16736 "manifestfiles properties : %s"),
16737 scf_error());
16738
16739 mpntov = safe_malloc(sizeof (struct mpg_mfile));
16740 mpnbuf = safe_malloc(max_scf_name_len + 1);
16741 mpvbuf = safe_malloc(max_scf_value_len + 1);
16742 mpntov->mpg = mpnbuf;
16743 mpntov->mfile = mpvbuf;
16744 mpntov->access = 1;
16745 if (scf_property_get_name(mp, mpnbuf,
16746 max_scf_name_len + 1) < 0) {
16747 uu_warn(gettext("Unable to get manifest file "
16748 "property : %s\n"),
16749 scf_strerror(scf_error()));
16750
16751 switch (scf_error()) {
16752 case SCF_ERROR_DELETED:
16753 case SCF_ERROR_CONNECTION_BROKEN:
16754 r = scferror2errno(scf_error());
16755 goto out_free;
16756
16757 case SCF_ERROR_HANDLE_MISMATCH:
16758 case SCF_ERROR_NOT_BOUND:
16759 case SCF_ERROR_NOT_SET:
16760 default:
16761 bad_error("scf_iter_pg_properties",
16762 scf_error());
16763 }
16764 }
16765
16766 /*
16767 * The support property is a boolean value that indicates
16768 * if the service is supported for manifest file deletion.
16769 * Currently at this time there is no code that sets this
16770 * value to true. So while we could just let this be caught
16771 * by the support check below, in the future this by be set
16772 * to true and require processing. So for that, go ahead
16773 * and check here, and just return if false. Otherwise,
16774 * fall through expecting that other support checks will
16775 * handle the entries.
16776 */
16777 if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
16778 uint8_t support;
16779
16780 if (scf_property_get_value(mp, mv) != 0 ||
16781 scf_value_get_boolean(mv, &support) != 0) {
16782 uu_warn(gettext("Unable to get the manifest "
16783 "support value: %s\n"),
16784 scf_strerror(scf_error()));
16785
16786 switch (scf_error()) {
16787 case SCF_ERROR_DELETED:
16788 case SCF_ERROR_CONNECTION_BROKEN:
16789 r = scferror2errno(scf_error());
16790 goto out_free;
16791
16792 case SCF_ERROR_HANDLE_MISMATCH:
16793 case SCF_ERROR_NOT_BOUND:
16794 case SCF_ERROR_NOT_SET:
16795 default:
16796 bad_error("scf_iter_pg_properties",
16797 scf_error());
16798 }
16799 }
16800
16801 if (support == B_FALSE)
16802 goto out_free;
16803 }
16804
16805 /*
16806 * Anything with a manifest outside of the supported
16807 * directories, immediately bail out because that makes
16808 * this service non-supported. We don't even want
16809 * to do instance processing in this case because the
16810 * instances could be part of the non-supported manifest.
16811 */
16812 if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
16813 /*
16814 * Manifest is not in /lib/svc, so we need to
16815 * consider the /var/svc case.
16816 */
16817 if (strncmp(mpnbuf, VARSVC_PR,
16818 strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
16819 /*
16820 * Either the manifest is not in /var/svc or
16821 * /var is not yet mounted. We ignore the
16822 * manifest either because it is not in a
16823 * standard location or because we cannot
16824 * currently access the manifest.
16825 */
16826 goto out_free;
16827 }
16828 }
16829
16830 /*
16831 * Get the value to of the manifest file for this entry
16832 * for access verification and instance support
16833 * verification if it still exists.
16834 *
16835 * During Early Manifest Import if the manifest is in
16836 * /var/svc then it may not yet be available for checking
16837 * so we must determine if /var/svc is available. If not
16838 * then defer until Late Manifest Import to cleanup.
16839 */
16840 if (scf_property_get_value(mp, mv) != 0) {
16841 uu_warn(gettext("Unable to get the manifest file "
16842 "value: %s\n"),
16843 scf_strerror(scf_error()));
16844
16845 switch (scf_error()) {
16846 case SCF_ERROR_DELETED:
16847 case SCF_ERROR_CONNECTION_BROKEN:
16848 r = scferror2errno(scf_error());
16849 goto out_free;
16850
16851 case SCF_ERROR_HANDLE_MISMATCH:
16852 case SCF_ERROR_NOT_BOUND:
16853 case SCF_ERROR_NOT_SET:
16854 default:
16855 bad_error("scf_property_get_value",
16856 scf_error());
16857 }
16858 }
16859
16860 if (scf_value_get_astring(mv, mpvbuf,
16861 max_scf_value_len + 1) < 0) {
16862 uu_warn(gettext("Unable to get the manifest "
16863 "file : %s\n"),
16864 scf_strerror(scf_error()));
16865
16866 switch (scf_error()) {
16867 case SCF_ERROR_DELETED:
16868 case SCF_ERROR_CONNECTION_BROKEN:
16869 r = scferror2errno(scf_error());
16870 goto out_free;
16871
16872 case SCF_ERROR_HANDLE_MISMATCH:
16873 case SCF_ERROR_NOT_BOUND:
16874 case SCF_ERROR_NOT_SET:
16875 default:
16876 bad_error("scf_value_get_astring",
16877 scf_error());
16878 }
16879 }
16880
16881 mpvarry[mfstcnt] = mpntov;
16882 mfstcnt++;
16883
16884 /*
16885 * Check for the need to reallocate array
16886 */
16887 if (mfstcnt >= (mfstmax - 1)) {
16888 struct mpg_mfile **newmpvarry;
16889
16890 mfstmax = mfstmax * 2;
16891 newmpvarry = realloc(mpvarry,
16892 sizeof (struct mpg_mfile *) * mfstmax);
16893
16894 if (newmpvarry == NULL)
16895 goto out_free;
16896
16897 mpvarry = newmpvarry;
16898 }
16899
16900 mpvarry[mfstcnt] = NULL;
16901 }
16902
16903 for (index = 0; mpvarry[index]; index++) {
16904 mpntov = mpvarry[index];
16905
16906 /*
16907 * Check to see if the manifestfile is accessable, if so hand
16908 * this service and manifestfile off to be processed for
16909 * instance support.
16910 */
16911 mpnbuf = mpntov->mpg;
16912 mpvbuf = mpntov->mfile;
16913 if (access(mpvbuf, F_OK) != 0) {
16914 mpntov->access = 0;
16915 activity++;
16916 mfstcnt--;
16917 /* Remove the entry from the service */
16918 cur_svc = svc;
16919 pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16920 mpnbuf);
16921 if (pgpropbuf == NULL)
16922 uu_die(gettext("Out of memory.\n"));
16923
16924 lscf_delprop(pgpropbuf);
16925 cur_svc = NULL;
16926
16927 uu_free(pgpropbuf);
16928 }
16929 }
16930
16931 /*
16932 * If mfstcnt is 0, none of the manifests that supported the service
16933 * existed so remove the service.
16934 */
16935 if (mfstcnt == 0) {
16936 teardown_service(svc, wip->fmri);
16937
16938 goto out_free;
16939 }
16940
16941 if (activity) {
16942 int nosvcsupport = 0;
16943
16944 /*
16945 * If the list of service instances is NULL then
16946 * create the list.
16947 */
16948 instances = create_instance_list(svc, 1);
16949 if (instances == NULL) {
16950 uu_warn(gettext("Unable to create instance list %s\n"),
16951 wip->fmri);
16952 goto out_free;
16953 }
16954
16955 rminstct = uu_list_numnodes(instances);
16956 instct = rminstct;
16957
16958 for (index = 0; mpvarry[index]; index++) {
16959 mpntov = mpvarry[index];
16960 if (mpntov->access == 0)
16961 continue;
16962
16963 mpnbuf = mpntov->mpg;
16964 mpvbuf = mpntov->mfile;
16965 r = check_instance_support(mpvbuf, wip->fmri,
16966 instances);
16967 if (r == -1) {
16968 nosvcsupport++;
16969 } else {
16970 rminstct -= r;
16971 }
16972 }
16973
16974 if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
16975 teardown_service(svc, wip->fmri);
16976
16977 goto out_free;
16978 }
16979 }
16980
16981 /*
16982 * If there are instances left on the instance list, then
16983 * we must remove them.
16984 */
16985 if (instances != NULL && uu_list_numnodes(instances)) {
16986 string_list_t *sp;
16987
16988 insts = uu_list_walk_start(instances, 0);
16989 while ((sp = uu_list_walk_next(insts)) != NULL) {
16990 /*
16991 * Remove the instance from the instances list.
16992 */
16993 safe_printf(gettext("Delete instance %s from "
16994 "service %s\n"), sp->str, wip->fmri);
16995 if (scf_service_get_instance(svc, sp->str,
16996 instance) != SCF_SUCCESS) {
16997 (void) uu_warn("scf_error - %s\n",
16998 scf_strerror(scf_error()));
16999
17000 continue;
17001 }
17002
17003 (void) disable_instance(instance);
17004
17005 (void) lscf_instance_delete(instance, 1);
17006 }
17007 scf_instance_destroy(instance);
17008 uu_list_walk_end(insts);
17009 }
17010
17011 out_free:
17012 if (mpvarry) {
17013 struct mpg_mfile *fmpntov;
17014
17015 for (index = 0; mpvarry[index]; index++) {
17016 fmpntov = mpvarry[index];
17017 if (fmpntov->mpg == mpnbuf)
17018 mpnbuf = NULL;
17019 free(fmpntov->mpg);
17020
17021 if (fmpntov->mfile == mpvbuf)
17022 mpvbuf = NULL;
17023 free(fmpntov->mfile);
17024
17025 if (fmpntov == mpntov)
17026 mpntov = NULL;
17027 free(fmpntov);
17028 }
17029 if (mpnbuf)
17030 free(mpnbuf);
17031 if (mpvbuf)
17032 free(mpvbuf);
17033 if (mpntov)
17034 free(mpntov);
17035
17036 free(mpvarry);
17037 }
17038 out:
17039 scf_pg_destroy(mpg);
17040 scf_property_destroy(mp);
17041 scf_iter_destroy(mi);
17042 scf_value_destroy(mv);
17043
17044 return (0);
17045 }
17046
17047 /*
17048 * Take the service and search for the manifestfiles property
17049 * in each of the property groups. If the manifest file
17050 * associated with the property does not exist then remove
17051 * the property group.
17052 */
17053 int
17054 lscf_hash_cleanup()
17055 {
17056 scf_service_t *svc;
17057 scf_scope_t *scope;
17058 scf_propertygroup_t *pg;
17059 scf_property_t *prop;
17060 scf_value_t *val;
17061 scf_iter_t *iter;
17062 char *pgname = NULL;
17063 char *mfile = NULL;
17064 int r;
17065
17066 svc = scf_service_create(g_hndl);
17067 scope = scf_scope_create(g_hndl);
17068 pg = scf_pg_create(g_hndl);
17069 prop = scf_property_create(g_hndl);
17070 val = scf_value_create(g_hndl);
17071 iter = scf_iter_create(g_hndl);
17072 if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
17073 svc == NULL || scope == NULL) {
17074 uu_warn(gettext("Unable to create a property group, or "
17075 "property\n"));
17076 uu_warn("%s\n", pg == NULL ? "pg is NULL" :
17077 "pg is not NULL");
17078 uu_warn("%s\n", prop == NULL ? "prop is NULL" :
17079 "prop is not NULL");
17080 uu_warn("%s\n", val == NULL ? "val is NULL" :
17081 "val is not NULL");
17082 uu_warn("%s\n", iter == NULL ? "iter is NULL" :
17083 "iter is not NULL");
17084 uu_warn("%s\n", svc == NULL ? "svc is NULL" :
17085 "svc is not NULL");
17086 uu_warn("%s\n", scope == NULL ? "scope is NULL" :
17087 "scope is not NULL");
17088 uu_warn(gettext("scf error is : %s\n"),
17089 scf_strerror(scf_error()));
17090 scfdie();
17091 }
17092
17093 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
17094 switch (scf_error()) {
17095 case SCF_ERROR_CONNECTION_BROKEN:
17096 case SCF_ERROR_NOT_FOUND:
17097 goto out;
17098
17099 case SCF_ERROR_HANDLE_MISMATCH:
17100 case SCF_ERROR_NOT_BOUND:
17101 case SCF_ERROR_INVALID_ARGUMENT:
17102 default:
17103 bad_error("scf_handle_get_scope", scf_error());
17104 }
17105 }
17106
17107 if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
17108 uu_warn(gettext("Unable to process the hash service, %s\n"),
17109 HASH_SVC);
17110 goto out;
17111 }
17112
17113 pgname = safe_malloc(max_scf_name_len + 1);
17114 mfile = safe_malloc(max_scf_value_len + 1);
17115
17116 if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
17117 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17118 scf_strerror(scf_error()));
17119 goto out;
17120 }
17121
17122 while ((r = scf_iter_next_pg(iter, pg)) != 0) {
17123 if (r == -1)
17124 goto out;
17125
17126 if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
17127 switch (scf_error()) {
17128 case SCF_ERROR_DELETED:
17129 return (ENODEV);
17130
17131 case SCF_ERROR_CONNECTION_BROKEN:
17132 return (ECONNABORTED);
17133
17134 case SCF_ERROR_NOT_SET:
17135 case SCF_ERROR_NOT_BOUND:
17136 default:
17137 bad_error("scf_pg_get_name", scf_error());
17138 }
17139 }
17140 if (IGNORE_VAR) {
17141 if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
17142 continue;
17143 }
17144
17145 /*
17146 * If unable to get the property continue as this is an
17147 * entry that has no location to check against.
17148 */
17149 if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
17150 continue;
17151 }
17152
17153 if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
17154 uu_warn(gettext("Unable to get value from %s\n"),
17155 pgname);
17156
17157 switch (scf_error()) {
17158 case SCF_ERROR_DELETED:
17159 case SCF_ERROR_CONSTRAINT_VIOLATED:
17160 case SCF_ERROR_NOT_FOUND:
17161 case SCF_ERROR_NOT_SET:
17162 continue;
17163
17164 case SCF_ERROR_CONNECTION_BROKEN:
17165 r = scferror2errno(scf_error());
17166 goto out;
17167
17168 case SCF_ERROR_HANDLE_MISMATCH:
17169 case SCF_ERROR_NOT_BOUND:
17170 default:
17171 bad_error("scf_property_get_value",
17172 scf_error());
17173 }
17174 }
17175
17176 if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
17177 == -1) {
17178 uu_warn(gettext("Unable to get astring from %s : %s\n"),
17179 pgname, scf_strerror(scf_error()));
17180
17181 switch (scf_error()) {
17182 case SCF_ERROR_NOT_SET:
17183 case SCF_ERROR_TYPE_MISMATCH:
17184 continue;
17185
17186 default:
17187 bad_error("scf_value_get_astring", scf_error());
17188 }
17189 }
17190
17191 if (access(mfile, F_OK) == 0)
17192 continue;
17193
17194 (void) scf_pg_delete(pg);
17195 }
17196
17197 out:
17198 scf_scope_destroy(scope);
17199 scf_service_destroy(svc);
17200 scf_pg_destroy(pg);
17201 scf_property_destroy(prop);
17202 scf_value_destroy(val);
17203 scf_iter_destroy(iter);
17204 free(pgname);
17205 free(mfile);
17206
17207 return (0);
17208 }
17209
17210 #ifndef NATIVE_BUILD
17211 /* ARGSUSED */
17212 CPL_MATCH_FN(complete_select)
17213 {
17214 const char *arg0, *arg1, *arg1end;
17215 int word_start, err = 0, r;
17216 size_t len;
17217 char *buf;
17218
17219 lscf_prep_hndl();
17220
17221 arg0 = line + strspn(line, " \t");
17222 assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
17223
17224 arg1 = arg0 + sizeof ("select") - 1;
17225 arg1 += strspn(arg1, " \t");
17226 word_start = arg1 - line;
17227
17228 arg1end = arg1 + strcspn(arg1, " \t");
17229 if (arg1end < line + word_end)
17230 return (0);
17231
17232 len = line + word_end - arg1;
17233
17234 buf = safe_malloc(max_scf_name_len + 1);
17235
17236 if (cur_snap != NULL) {
17237 return (0);
17238 } else if (cur_inst != NULL) {
17239 return (0);
17240 } else if (cur_svc != NULL) {
17241 scf_instance_t *inst;
17242 scf_iter_t *iter;
17243
17244 if ((inst = scf_instance_create(g_hndl)) == NULL ||
17245 (iter = scf_iter_create(g_hndl)) == NULL)
17246 scfdie();
17247
17248 if (scf_iter_service_instances(iter, cur_svc) != 0)
17249 scfdie();
17250
17251 for (;;) {
17252 r = scf_iter_next_instance(iter, inst);
17253 if (r == 0)
17254 break;
17255 if (r != 1)
17256 scfdie();
17257
17258 if (scf_instance_get_name(inst, buf,
17259 max_scf_name_len + 1) < 0)
17260 scfdie();
17261
17262 if (strncmp(buf, arg1, len) == 0) {
17263 err = cpl_add_completion(cpl, line, word_start,
17264 word_end, buf + len, "", " ");
17265 if (err != 0)
17266 break;
17267 }
17268 }
17269
17270 scf_iter_destroy(iter);
17271 scf_instance_destroy(inst);
17272
17273 return (err);
17274 } else {
17275 scf_service_t *svc;
17276 scf_iter_t *iter;
17277
17278 assert(cur_scope != NULL);
17279
17280 if ((svc = scf_service_create(g_hndl)) == NULL ||
17281 (iter = scf_iter_create(g_hndl)) == NULL)
17282 scfdie();
17283
17284 if (scf_iter_scope_services(iter, cur_scope) != 0)
17285 scfdie();
17286
17287 for (;;) {
17288 r = scf_iter_next_service(iter, svc);
17289 if (r == 0)
17290 break;
17291 if (r != 1)
17292 scfdie();
17293
17294 if (scf_service_get_name(svc, buf,
17295 max_scf_name_len + 1) < 0)
17296 scfdie();
17297
17298 if (strncmp(buf, arg1, len) == 0) {
17299 err = cpl_add_completion(cpl, line, word_start,
17300 word_end, buf + len, "", " ");
17301 if (err != 0)
17302 break;
17303 }
17304 }
17305
17306 scf_iter_destroy(iter);
17307 scf_service_destroy(svc);
17308
17309 return (err);
17310 }
17311 }
17312
17313 /* ARGSUSED */
17314 CPL_MATCH_FN(complete_command)
17315 {
17316 uint32_t scope = 0;
17317
17318 if (cur_snap != NULL)
17319 scope = CS_SNAP;
17320 else if (cur_inst != NULL)
17321 scope = CS_INST;
17322 else if (cur_svc != NULL)
17323 scope = CS_SVC;
17324 else
17325 scope = CS_SCOPE;
17326
17327 return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
17328 }
17329 #endif /* NATIVE_BUILD */