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