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 */
25
26
27 #include <alloca.h>
28 #include <assert.h>
29 #include <ctype.h>
30 #include <door.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <fnmatch.h>
34 #include <inttypes.h>
35 #include <libintl.h>
36 #include <libnvpair.h>
37 #include <libscf.h>
38 #include <libscf_priv.h>
39 #include <libtecla.h>
40 #include <libuutil.h>
41 #include <limits.h>
42 #include <locale.h>
43 #include <stdarg.h>
44 #include <string.h>
45 #include <strings.h>
46 #include <unistd.h>
47 #include <wait.h>
48 #include <poll.h>
49
50 #include <libxml/tree.h>
51
52 #include <sys/param.h>
53
54 #include <sys/stat.h>
55 #include <sys/mman.h>
56
57 #include "svccfg.h"
58 #include "notify_params.h"
59 #include "manifest_hash.h"
60 #include "manifest_find.h"
61
62 /* The colon namespaces in each entity (each followed by a newline). */
63 #define COLON_NAMESPACES ":properties\n"
64
65 #define TEMP_FILE_PATTERN "/tmp/svccfg-XXXXXX"
66
67 /* These are characters which the lexer requires to be in double-quotes. */
68 #define CHARS_TO_QUOTE " \t\n\\>=\"()"
69
70 #define HASH_SIZE 16
71 #define HASH_PG_TYPE "framework"
72 #define HASH_PG_FLAGS 0
73 #define HASH_PROP "md5sum"
74
75 /*
76 * Indentation used in the output of the describe subcommand.
77 */
78 #define TMPL_VALUE_INDENT " "
79 #define TMPL_INDENT " "
80 #define TMPL_INDENT_2X " "
81 #define TMPL_CHOICE_INDENT " "
82
83 /*
84 * Directory locations for manifests
85 */
86 #define VARSVC_DIR "/var/svc/manifest"
87 #define LIBSVC_DIR "/lib/svc/manifest"
88 #define VARSVC_PR "var_svc_manifest"
89 #define LIBSVC_PR "lib_svc_manifest"
90 #define MFSTFILEPR "manifestfile"
91
92 #define SUPPORTPROP "support"
93
94 #define MFSTHISTFILE "/lib/svc/share/mfsthistory"
95
96 #define MFSTFILE_MAX 16
97
98 /*
99 * These are the classes of elements which may appear as children of service
100 * or instance elements in XML manifests.
101 */
102 struct entity_elts {
103 xmlNodePtr create_default_instance;
104 xmlNodePtr single_instance;
105 xmlNodePtr restarter;
106 xmlNodePtr dependencies;
107 xmlNodePtr dependents;
108 xmlNodePtr method_context;
109 xmlNodePtr exec_methods;
110 xmlNodePtr notify_params;
111 xmlNodePtr property_groups;
112 xmlNodePtr instances;
113 xmlNodePtr stability;
114 xmlNodePtr template;
115 };
116
117 /*
118 * Likewise for property_group elements.
119 */
120 struct pg_elts {
121 xmlNodePtr stability;
122 xmlNodePtr propvals;
123 xmlNodePtr properties;
124 };
125
126 /*
127 * Likewise for template elements.
128 */
129 struct template_elts {
130 xmlNodePtr common_name;
131 xmlNodePtr description;
132 xmlNodePtr documentation;
133 };
134
135 /*
136 * Likewise for type (for notification parameters) elements.
137 */
138 struct params_elts {
139 xmlNodePtr paramval;
140 xmlNodePtr parameter;
141 };
142
143 /*
144 * This structure is for snaplevel lists. They are convenient because libscf
145 * only allows traversing snaplevels in one direction.
146 */
147 struct snaplevel {
148 uu_list_node_t list_node;
149 scf_snaplevel_t *sl;
150 };
151
152 /*
153 * This is used for communication between lscf_service_export and
154 * export_callback.
155 */
156 struct export_args {
157 const char *filename;
158 int flags;
159 };
160
161 /*
162 * The service_manifest structure is used by the upgrade process
163 * to create a list of service to manifest linkages from the manifests
164 * in a set of given directories.
165 */
166 typedef struct service_manifest {
167 const char *servicename;
168 uu_list_t *mfstlist;
169 size_t mfstlist_sz;
170
171 uu_avl_node_t svcmfst_node;
172 } service_manifest_t;
173
174 /*
175 * Structure to track the manifest file property group
176 * and the manifest file associated with that property
177 * group. Also, a flag to keep the access once it has
178 * been checked.
179 */
180 struct mpg_mfile {
181 char *mpg;
182 char *mfile;
183 int access;
184 };
185
186 const char * const scf_pg_general = SCF_PG_GENERAL;
187 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
188 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
189 const char * const scf_property_external = "external";
190
191 const char * const snap_initial = "initial";
192 const char * const snap_lastimport = "last-import";
193 const char * const snap_previous = "previous";
194 const char * const snap_running = "running";
195
196 scf_handle_t *g_hndl = NULL; /* only valid after lscf_prep_hndl() */
197
198 ssize_t max_scf_fmri_len;
199 ssize_t max_scf_name_len;
200 ssize_t max_scf_pg_type_len;
201 ssize_t max_scf_value_len;
202 static size_t max_scf_len;
203
204 static scf_scope_t *cur_scope;
205 static scf_service_t *cur_svc = NULL;
206 static scf_instance_t *cur_inst = NULL;
207 static scf_snapshot_t *cur_snap = NULL;
208 static scf_snaplevel_t *cur_level = NULL;
209
210 static uu_list_pool_t *snaplevel_pool;
211 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
212 static uu_list_t *cur_levels;
213 static struct snaplevel *cur_elt; /* cur_elt->sl == cur_level */
214
215 static FILE *tempfile = NULL;
216 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
217
218 static const char *emsg_entity_not_selected;
219 static const char *emsg_permission_denied;
220 static const char *emsg_create_xml;
221 static const char *emsg_cant_modify_snapshots;
222 static const char *emsg_invalid_for_snapshot;
223 static const char *emsg_read_only;
224 static const char *emsg_deleted;
225 static const char *emsg_invalid_pg_name;
226 static const char *emsg_invalid_prop_name;
227 static const char *emsg_no_such_pg;
228 static const char *emsg_fmri_invalid_pg_name;
229 static const char *emsg_fmri_invalid_pg_name_type;
230 static const char *emsg_pg_added;
231 static const char *emsg_pg_changed;
232 static const char *emsg_pg_deleted;
233 static const char *emsg_pg_mod_perm;
234 static const char *emsg_pg_add_perm;
235 static const char *emsg_pg_del_perm;
236 static const char *emsg_snap_perm;
237 static const char *emsg_dpt_dangling;
238 static const char *emsg_dpt_no_dep;
239
240 static int li_only = 0;
241 static int no_refresh = 0;
242
243 /* import globals, to minimize allocations */
244 static scf_scope_t *imp_scope = NULL;
245 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
246 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
247 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
248 static scf_snapshot_t *imp_rsnap = NULL;
249 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
250 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
251 static scf_property_t *imp_prop = NULL;
252 static scf_iter_t *imp_iter = NULL;
253 static scf_iter_t *imp_rpg_iter = NULL;
254 static scf_iter_t *imp_up_iter = NULL;
255 static scf_transaction_t *imp_tx = NULL; /* always reset this */
256 static char *imp_str = NULL;
257 static size_t imp_str_sz;
258 static char *imp_tsname = NULL;
259 static char *imp_fe1 = NULL; /* for fmri_equal() */
260 static char *imp_fe2 = NULL;
261 static uu_list_t *imp_deleted_dpts = NULL; /* pgroup_t's to refresh */
262
263 /* upgrade_dependents() globals */
264 static scf_instance_t *ud_inst = NULL;
265 static scf_snaplevel_t *ud_snpl = NULL;
266 static scf_propertygroup_t *ud_pg = NULL;
267 static scf_propertygroup_t *ud_cur_depts_pg = NULL;
268 static scf_propertygroup_t *ud_run_dpts_pg = NULL;
269 static int ud_run_dpts_pg_set = 0;
270 static scf_property_t *ud_prop = NULL;
271 static scf_property_t *ud_dpt_prop = NULL;
272 static scf_value_t *ud_val = NULL;
273 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
274 static scf_transaction_t *ud_tx = NULL;
275 static char *ud_ctarg = NULL;
276 static char *ud_oldtarg = NULL;
277 static char *ud_name = NULL;
278
279 /* export globals */
280 static scf_instance_t *exp_inst;
281 static scf_propertygroup_t *exp_pg;
282 static scf_property_t *exp_prop;
283 static scf_value_t *exp_val;
284 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
285 static char *exp_str;
286 static size_t exp_str_sz;
287
288 /* cleanup globals */
289 static uu_avl_pool_t *service_manifest_pool = NULL;
290 static uu_avl_t *service_manifest_tree = NULL;
291
292 static void scfdie_lineno(int lineno) __NORETURN;
293
294 static char *start_method_names[] = {
295 "start",
296 "inetd_start",
297 NULL
298 };
299
300 static struct uri_scheme {
301 const char *scheme;
302 const char *protocol;
303 } uri_scheme[] = {
304 { "mailto", "smtp" },
305 { "snmp", "snmp" },
306 { "syslog", "syslog" },
307 { NULL, NULL }
308 };
309 #define URI_SCHEME_NUM ((sizeof (uri_scheme) / \
310 sizeof (struct uri_scheme)) - 1)
311
312 static int
check_uri_scheme(const char * scheme)313 check_uri_scheme(const char *scheme)
314 {
315 int i;
316
317 for (i = 0; uri_scheme[i].scheme != NULL; ++i) {
318 if (strcmp(scheme, uri_scheme[i].scheme) == 0)
319 return (i);
320 }
321
322 return (-1);
323 }
324
325 static int
check_uri_protocol(const char * p)326 check_uri_protocol(const char *p)
327 {
328 int i;
329
330 for (i = 0; uri_scheme[i].protocol != NULL; ++i) {
331 if (strcmp(p, uri_scheme[i].protocol) == 0)
332 return (i);
333 }
334
335 return (-1);
336 }
337
338 /*
339 * For unexpected libscf errors.
340 */
341 #ifdef NDEBUG
342
343 static void scfdie(void) __NORETURN;
344
345 static void
scfdie(void)346 scfdie(void)
347 {
348 scf_error_t err = scf_error();
349
350 if (err == SCF_ERROR_CONNECTION_BROKEN)
351 uu_die(gettext("Repository connection broken. Exiting.\n"));
352
353 uu_die(gettext("Unexpected fatal libscf error: %s. Exiting.\n"),
354 scf_strerror(err));
355 }
356
357 #else
358
359 #define scfdie() scfdie_lineno(__LINE__)
360
361 static void
scfdie_lineno(int lineno)362 scfdie_lineno(int lineno)
363 {
364 scf_error_t err = scf_error();
365
366 if (err == SCF_ERROR_CONNECTION_BROKEN)
367 uu_die(gettext("Repository connection broken. Exiting.\n"));
368
369 uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
370 ": %s.\n"), lineno, scf_strerror(err));
371 }
372
373 #endif
374
375 static void
scfwarn(void)376 scfwarn(void)
377 {
378 warn(gettext("Unexpected libscf error: %s.\n"),
379 scf_strerror(scf_error()));
380 }
381
382 /*
383 * Clear a field of a structure.
384 */
385 static int
clear_int(void * a,void * b)386 clear_int(void *a, void *b)
387 {
388 /* LINTED */
389 *(int *)((char *)a + (size_t)b) = 0;
390
391 return (UU_WALK_NEXT);
392 }
393
394 static int
scferror2errno(scf_error_t err)395 scferror2errno(scf_error_t err)
396 {
397 switch (err) {
398 case SCF_ERROR_BACKEND_ACCESS:
399 return (EACCES);
400
401 case SCF_ERROR_BACKEND_READONLY:
402 return (EROFS);
403
404 case SCF_ERROR_CONNECTION_BROKEN:
405 return (ECONNABORTED);
406
407 case SCF_ERROR_CONSTRAINT_VIOLATED:
408 case SCF_ERROR_INVALID_ARGUMENT:
409 return (EINVAL);
410
411 case SCF_ERROR_DELETED:
412 return (ECANCELED);
413
414 case SCF_ERROR_EXISTS:
415 return (EEXIST);
416
417 case SCF_ERROR_NO_MEMORY:
418 return (ENOMEM);
419
420 case SCF_ERROR_NO_RESOURCES:
421 return (ENOSPC);
422
423 case SCF_ERROR_NOT_FOUND:
424 return (ENOENT);
425
426 case SCF_ERROR_PERMISSION_DENIED:
427 return (EPERM);
428
429 default:
430 #ifndef NDEBUG
431 (void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
432 __FILE__, __LINE__, err);
433 #else
434 (void) fprintf(stderr, "Unknown libscf error %d.\n", err);
435 #endif
436 abort();
437 /* NOTREACHED */
438 }
439 }
440
441 static int
entity_get_pg(void * ent,int issvc,const char * name,scf_propertygroup_t * pg)442 entity_get_pg(void *ent, int issvc, const char *name,
443 scf_propertygroup_t *pg)
444 {
445 if (issvc)
446 return (scf_service_get_pg(ent, name, pg));
447 else
448 return (scf_instance_get_pg(ent, name, pg));
449 }
450
451 static void
entity_destroy(void * ent,int issvc)452 entity_destroy(void *ent, int issvc)
453 {
454 if (issvc)
455 scf_service_destroy(ent);
456 else
457 scf_instance_destroy(ent);
458 }
459
460 static int
get_pg(const char * pg_name,scf_propertygroup_t * pg)461 get_pg(const char *pg_name, scf_propertygroup_t *pg)
462 {
463 int ret;
464
465 if (cur_level != NULL)
466 ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
467 else if (cur_inst != NULL)
468 ret = scf_instance_get_pg(cur_inst, pg_name, pg);
469 else
470 ret = scf_service_get_pg(cur_svc, pg_name, pg);
471
472 return (ret);
473 }
474
475 /*
476 * Find a snaplevel in a snapshot. If get_svc is true, find the service
477 * snaplevel. Otherwise find the instance snaplevel.
478 *
479 * Returns
480 * 0 - success
481 * ECONNABORTED - repository connection broken
482 * ECANCELED - instance containing snap was deleted
483 * ENOENT - snap has no snaplevels
484 * - requested snaplevel not found
485 */
486 static int
get_snaplevel(scf_snapshot_t * snap,int get_svc,scf_snaplevel_t * snpl)487 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
488 {
489 if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
490 switch (scf_error()) {
491 case SCF_ERROR_CONNECTION_BROKEN:
492 case SCF_ERROR_DELETED:
493 case SCF_ERROR_NOT_FOUND:
494 return (scferror2errno(scf_error()));
495
496 case SCF_ERROR_HANDLE_MISMATCH:
497 case SCF_ERROR_NOT_BOUND:
498 case SCF_ERROR_NOT_SET:
499 default:
500 bad_error("scf_snapshot_get_base_snaplevel",
501 scf_error());
502 }
503 }
504
505 for (;;) {
506 ssize_t ssz;
507
508 ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
509 if (ssz >= 0) {
510 if (!get_svc)
511 return (0);
512 } else {
513 switch (scf_error()) {
514 case SCF_ERROR_CONSTRAINT_VIOLATED:
515 if (get_svc)
516 return (0);
517 break;
518
519 case SCF_ERROR_DELETED:
520 case SCF_ERROR_CONNECTION_BROKEN:
521 return (scferror2errno(scf_error()));
522
523 case SCF_ERROR_NOT_SET:
524 case SCF_ERROR_NOT_BOUND:
525 default:
526 bad_error("scf_snaplevel_get_instance_name",
527 scf_error());
528 }
529 }
530
531 if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
532 switch (scf_error()) {
533 case SCF_ERROR_NOT_FOUND:
534 case SCF_ERROR_CONNECTION_BROKEN:
535 case SCF_ERROR_DELETED:
536 return (scferror2errno(scf_error()));
537
538 case SCF_ERROR_HANDLE_MISMATCH:
539 case SCF_ERROR_NOT_BOUND:
540 case SCF_ERROR_NOT_SET:
541 case SCF_ERROR_INVALID_ARGUMENT:
542 default:
543 bad_error("scf_snaplevel_get_next_snaplevel",
544 scf_error());
545 }
546 }
547 }
548 }
549
550 /*
551 * If issvc is 0, take ent to be a pointer to an scf_instance_t. If it has
552 * a running snapshot, and that snapshot has an instance snaplevel, set pg to
553 * the property group named name in it. If it doesn't have a running
554 * snapshot, set pg to the instance's current property group named name.
555 *
556 * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
557 * its instances. If one has a running snapshot with a service snaplevel, set
558 * pg to the property group named name in it. If no such snaplevel could be
559 * found, set pg to the service's current property group named name.
560 *
561 * iter, inst, snap, and snpl are required scratch objects.
562 *
563 * Returns
564 * 0 - success
565 * ECONNABORTED - repository connection broken
566 * ECANCELED - ent was deleted
567 * ENOENT - no such property group
568 * EINVAL - name is an invalid property group name
569 * EBADF - found running snapshot is missing a snaplevel
570 */
571 static int
entity_get_running_pg(void * ent,int issvc,const char * name,scf_propertygroup_t * pg,scf_iter_t * iter,scf_instance_t * inst,scf_snapshot_t * snap,scf_snaplevel_t * snpl)572 entity_get_running_pg(void *ent, int issvc, const char *name,
573 scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
574 scf_snapshot_t *snap, scf_snaplevel_t *snpl)
575 {
576 int r;
577
578 if (issvc) {
579 /* Search for an instance with a running snapshot. */
580 if (scf_iter_service_instances(iter, ent) != 0) {
581 switch (scf_error()) {
582 case SCF_ERROR_DELETED:
583 case SCF_ERROR_CONNECTION_BROKEN:
584 return (scferror2errno(scf_error()));
585
586 case SCF_ERROR_NOT_SET:
587 case SCF_ERROR_NOT_BOUND:
588 case SCF_ERROR_HANDLE_MISMATCH:
589 default:
590 bad_error("scf_iter_service_instances",
591 scf_error());
592 }
593 }
594
595 for (;;) {
596 r = scf_iter_next_instance(iter, inst);
597 if (r == 0) {
598 if (scf_service_get_pg(ent, name, pg) == 0)
599 return (0);
600
601 switch (scf_error()) {
602 case SCF_ERROR_DELETED:
603 case SCF_ERROR_NOT_FOUND:
604 case SCF_ERROR_INVALID_ARGUMENT:
605 case SCF_ERROR_CONNECTION_BROKEN:
606 return (scferror2errno(scf_error()));
607
608 case SCF_ERROR_NOT_BOUND:
609 case SCF_ERROR_HANDLE_MISMATCH:
610 case SCF_ERROR_NOT_SET:
611 default:
612 bad_error("scf_service_get_pg",
613 scf_error());
614 }
615 }
616 if (r != 1) {
617 switch (scf_error()) {
618 case SCF_ERROR_DELETED:
619 case SCF_ERROR_CONNECTION_BROKEN:
620 return (scferror2errno(scf_error()));
621
622 case SCF_ERROR_INVALID_ARGUMENT:
623 case SCF_ERROR_NOT_SET:
624 case SCF_ERROR_NOT_BOUND:
625 case SCF_ERROR_HANDLE_MISMATCH:
626 default:
627 bad_error("scf_iter_next_instance",
628 scf_error());
629 }
630 }
631
632 if (scf_instance_get_snapshot(inst, snap_running,
633 snap) == 0)
634 break;
635
636 switch (scf_error()) {
637 case SCF_ERROR_NOT_FOUND:
638 case SCF_ERROR_DELETED:
639 continue;
640
641 case SCF_ERROR_CONNECTION_BROKEN:
642 return (ECONNABORTED);
643
644 case SCF_ERROR_HANDLE_MISMATCH:
645 case SCF_ERROR_INVALID_ARGUMENT:
646 case SCF_ERROR_NOT_SET:
647 case SCF_ERROR_NOT_BOUND:
648 default:
649 bad_error("scf_instance_get_snapshot",
650 scf_error());
651 }
652 }
653 } else {
654 if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
655 switch (scf_error()) {
656 case SCF_ERROR_NOT_FOUND:
657 break;
658
659 case SCF_ERROR_DELETED:
660 case SCF_ERROR_CONNECTION_BROKEN:
661 return (scferror2errno(scf_error()));
662
663 case SCF_ERROR_NOT_BOUND:
664 case SCF_ERROR_HANDLE_MISMATCH:
665 case SCF_ERROR_INVALID_ARGUMENT:
666 case SCF_ERROR_NOT_SET:
667 default:
668 bad_error("scf_instance_get_snapshot",
669 scf_error());
670 }
671
672 if (scf_instance_get_pg(ent, name, pg) == 0)
673 return (0);
674
675 switch (scf_error()) {
676 case SCF_ERROR_DELETED:
677 case SCF_ERROR_NOT_FOUND:
678 case SCF_ERROR_INVALID_ARGUMENT:
679 case SCF_ERROR_CONNECTION_BROKEN:
680 return (scferror2errno(scf_error()));
681
682 case SCF_ERROR_NOT_BOUND:
683 case SCF_ERROR_HANDLE_MISMATCH:
684 case SCF_ERROR_NOT_SET:
685 default:
686 bad_error("scf_instance_get_pg", scf_error());
687 }
688 }
689 }
690
691 r = get_snaplevel(snap, issvc, snpl);
692 switch (r) {
693 case 0:
694 break;
695
696 case ECONNABORTED:
697 case ECANCELED:
698 return (r);
699
700 case ENOENT:
701 return (EBADF);
702
703 default:
704 bad_error("get_snaplevel", r);
705 }
706
707 if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
708 return (0);
709
710 switch (scf_error()) {
711 case SCF_ERROR_DELETED:
712 case SCF_ERROR_INVALID_ARGUMENT:
713 case SCF_ERROR_CONNECTION_BROKEN:
714 case SCF_ERROR_NOT_FOUND:
715 return (scferror2errno(scf_error()));
716
717 case SCF_ERROR_NOT_BOUND:
718 case SCF_ERROR_HANDLE_MISMATCH:
719 case SCF_ERROR_NOT_SET:
720 default:
721 bad_error("scf_snaplevel_get_pg", scf_error());
722 /* NOTREACHED */
723 }
724 }
725
726 /*
727 * To be registered with atexit().
728 */
729 static void
remove_tempfile(void)730 remove_tempfile(void)
731 {
732 int ret;
733
734 if (tempfile != NULL) {
735 if (fclose(tempfile) == EOF)
736 (void) warn(gettext("Could not close temporary file"));
737 tempfile = NULL;
738 }
739
740 if (tempfilename[0] != '\0') {
741 do {
742 ret = remove(tempfilename);
743 } while (ret == -1 && errno == EINTR);
744 if (ret == -1)
745 warn(gettext("Could not remove temporary file"));
746 tempfilename[0] = '\0';
747 }
748 }
749
750 /*
751 * Launch private svc.configd(1M) for manipulating alternate repositories.
752 */
753 static void
start_private_repository(engine_state_t * est)754 start_private_repository(engine_state_t *est)
755 {
756 int fd, stat;
757 struct door_info info;
758 pid_t pid;
759
760 /*
761 * 1. Create a temporary file for the door.
762 */
763 if (est->sc_repo_doorname != NULL)
764 free((void *)est->sc_repo_doorname);
765
766 est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
767 if (est->sc_repo_doorname == NULL)
768 uu_die(gettext("Could not acquire temporary filename"));
769
770 fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
771 if (fd < 0)
772 uu_die(gettext("Could not create temporary file for "
773 "repository server"));
774
775 (void) close(fd);
776
777 /*
778 * 2. Launch a configd with that door, using the specified
779 * repository.
780 */
781 if ((est->sc_repo_pid = fork()) == 0) {
782 (void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
783 "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
784 NULL);
785 uu_die(gettext("Could not execute %s"), est->sc_repo_server);
786 } else if (est->sc_repo_pid == -1)
787 uu_die(gettext("Attempt to fork failed"));
788
789 do {
790 pid = waitpid(est->sc_repo_pid, &stat, 0);
791 } while (pid == -1 && errno == EINTR);
792
793 if (pid == -1)
794 uu_die(gettext("Could not waitpid() for repository server"));
795
796 if (!WIFEXITED(stat)) {
797 uu_die(gettext("Repository server failed (status %d).\n"),
798 stat);
799 } else if (WEXITSTATUS(stat) != 0) {
800 uu_die(gettext("Repository server failed (exit %d).\n"),
801 WEXITSTATUS(stat));
802 }
803
804 /*
805 * See if it was successful by checking if the door is a door.
806 */
807
808 fd = open(est->sc_repo_doorname, O_RDWR);
809 if (fd < 0)
810 uu_die(gettext("Could not open door \"%s\""),
811 est->sc_repo_doorname);
812
813 if (door_info(fd, &info) < 0)
814 uu_die(gettext("Unexpected door_info() error"));
815
816 if (close(fd) == -1)
817 warn(gettext("Could not close repository door"),
818 strerror(errno));
819
820 est->sc_repo_pid = info.di_target;
821 }
822
823 void
lscf_cleanup(void)824 lscf_cleanup(void)
825 {
826 /*
827 * In the case where we've launched a private svc.configd(1M)
828 * instance, we must terminate our child and remove the temporary
829 * rendezvous point.
830 */
831 if (est->sc_repo_pid > 0) {
832 (void) kill(est->sc_repo_pid, SIGTERM);
833 (void) waitpid(est->sc_repo_pid, NULL, 0);
834 (void) unlink(est->sc_repo_doorname);
835
836 est->sc_repo_pid = 0;
837 }
838 }
839
840 void
unselect_cursnap(void)841 unselect_cursnap(void)
842 {
843 void *cookie;
844
845 cur_level = NULL;
846
847 cookie = NULL;
848 while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
849 scf_snaplevel_destroy(cur_elt->sl);
850 free(cur_elt);
851 }
852
853 scf_snapshot_destroy(cur_snap);
854 cur_snap = NULL;
855 }
856
857 void
lscf_prep_hndl(void)858 lscf_prep_hndl(void)
859 {
860 if (g_hndl != NULL)
861 return;
862
863 g_hndl = scf_handle_create(SCF_VERSION);
864 if (g_hndl == NULL)
865 scfdie();
866
867 if (est->sc_repo_filename != NULL)
868 start_private_repository(est);
869
870 if (est->sc_repo_doorname != NULL) {
871 scf_value_t *repo_value;
872 int ret;
873
874 repo_value = scf_value_create(g_hndl);
875 if (repo_value == NULL)
876 scfdie();
877
878 ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
879 assert(ret == SCF_SUCCESS);
880
881 if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
882 SCF_SUCCESS)
883 scfdie();
884
885 scf_value_destroy(repo_value);
886 }
887
888 if (scf_handle_bind(g_hndl) != 0)
889 uu_die(gettext("Could not connect to repository server: %s.\n"),
890 scf_strerror(scf_error()));
891
892 cur_scope = scf_scope_create(g_hndl);
893 if (cur_scope == NULL)
894 scfdie();
895
896 if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
897 scfdie();
898 }
899
900 static void
repository_teardown(void)901 repository_teardown(void)
902 {
903 if (g_hndl != NULL) {
904 if (cur_snap != NULL)
905 unselect_cursnap();
906 scf_instance_destroy(cur_inst);
907 scf_service_destroy(cur_svc);
908 scf_scope_destroy(cur_scope);
909 scf_handle_destroy(g_hndl);
910 cur_inst = NULL;
911 cur_svc = NULL;
912 cur_scope = NULL;
913 g_hndl = NULL;
914 lscf_cleanup();
915 }
916 }
917
918 void
lscf_set_repository(const char * repfile,int force)919 lscf_set_repository(const char *repfile, int force)
920 {
921 repository_teardown();
922
923 if (est->sc_repo_filename != NULL) {
924 free((void *)est->sc_repo_filename);
925 est->sc_repo_filename = NULL;
926 }
927
928 if ((force == 0) && (access(repfile, R_OK) != 0)) {
929 /*
930 * Repository file does not exist
931 * or has no read permission.
932 */
933 warn(gettext("Cannot access \"%s\": %s\n"),
934 repfile, strerror(errno));
935 } else {
936 est->sc_repo_filename = safe_strdup(repfile);
937 }
938
939 lscf_prep_hndl();
940 }
941
942 void
lscf_init()943 lscf_init()
944 {
945 if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
946 (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
947 (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
948 0 ||
949 (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
950 scfdie();
951
952 max_scf_len = max_scf_fmri_len;
953 if (max_scf_name_len > max_scf_len)
954 max_scf_len = max_scf_name_len;
955 if (max_scf_pg_type_len > max_scf_len)
956 max_scf_len = max_scf_pg_type_len;
957 /*
958 * When a value of type opaque is represented as a string, the
959 * string contains 2 characters for every byte of data. That is
960 * because the string contains the hex representation of the opaque
961 * value.
962 */
963 if (2 * max_scf_value_len > max_scf_len)
964 max_scf_len = 2 * max_scf_value_len;
965
966 if (atexit(remove_tempfile) != 0)
967 uu_die(gettext("Could not register atexit() function"));
968
969 emsg_entity_not_selected = gettext("An entity is not selected.\n");
970 emsg_permission_denied = gettext("Permission denied.\n");
971 emsg_create_xml = gettext("Could not create XML node.\n");
972 emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
973 emsg_invalid_for_snapshot =
974 gettext("Invalid operation on a snapshot.\n");
975 emsg_read_only = gettext("Backend read-only.\n");
976 emsg_deleted = gettext("Current selection has been deleted.\n");
977 emsg_invalid_pg_name =
978 gettext("Invalid property group name \"%s\".\n");
979 emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
980 emsg_no_such_pg = gettext("No such property group \"%s\".\n");
981 emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
982 "with invalid name \"%s\".\n");
983 emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
984 "group with invalid name \"%s\" or type \"%s\".\n");
985 emsg_pg_added = gettext("%s changed unexpectedly "
986 "(property group \"%s\" added).\n");
987 emsg_pg_changed = gettext("%s changed unexpectedly "
988 "(property group \"%s\" changed).\n");
989 emsg_pg_deleted = gettext("%s changed unexpectedly "
990 "(property group \"%s\" or an ancestor was deleted).\n");
991 emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
992 "in %s (permission denied).\n");
993 emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
994 "in %s (permission denied).\n");
995 emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
996 "in %s (permission denied).\n");
997 emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
998 "(permission denied).\n");
999 emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
1000 "new dependent \"%s\" because it already exists). Warning: The "
1001 "current dependent's target (%s) does not exist.\n");
1002 emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
1003 "dependent \"%s\" because it already exists). Warning: The "
1004 "current dependent's target (%s) does not have a dependency named "
1005 "\"%s\" as expected.\n");
1006
1007 string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
1008 offsetof(string_list_t, node), NULL, 0);
1009 snaplevel_pool = uu_list_pool_create("snaplevels",
1010 sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
1011 NULL, 0);
1012 }
1013
1014
1015 static const char *
prop_to_typestr(const scf_property_t * prop)1016 prop_to_typestr(const scf_property_t *prop)
1017 {
1018 scf_type_t ty;
1019
1020 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
1021 scfdie();
1022
1023 return (scf_type_to_string(ty));
1024 }
1025
1026 static scf_type_t
string_to_type(const char * type)1027 string_to_type(const char *type)
1028 {
1029 size_t len = strlen(type);
1030 char *buf;
1031
1032 if (len == 0 || type[len - 1] != ':')
1033 return (SCF_TYPE_INVALID);
1034
1035 buf = (char *)alloca(len + 1);
1036 (void) strlcpy(buf, type, len + 1);
1037 buf[len - 1] = 0;
1038
1039 return (scf_string_to_type(buf));
1040 }
1041
1042 static scf_value_t *
string_to_value(const char * str,scf_type_t ty,boolean_t require_quotes)1043 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
1044 {
1045 scf_value_t *v;
1046 char *dup, *nstr;
1047 size_t len;
1048
1049 v = scf_value_create(g_hndl);
1050 if (v == NULL)
1051 scfdie();
1052
1053 len = strlen(str);
1054 if (require_quotes &&
1055 (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
1056 semerr(gettext("Multiple string values or string values "
1057 "with spaces must be quoted with '\"'.\n"));
1058 scf_value_destroy(v);
1059 return (NULL);
1060 }
1061
1062 nstr = dup = safe_strdup(str);
1063 if (dup[0] == '\"') {
1064 /*
1065 * Strip out the first and the last quote.
1066 */
1067 dup[len - 1] = '\0';
1068 nstr = dup + 1;
1069 }
1070
1071 if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
1072 assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1073 semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1074 scf_type_to_string(ty), nstr);
1075 scf_value_destroy(v);
1076 v = NULL;
1077 }
1078 free(dup);
1079 return (v);
1080 }
1081
1082 /*
1083 * Print str to strm, quoting double-quotes and backslashes with backslashes.
1084 * Optionally append a comment prefix ('#') to newlines ('\n').
1085 */
1086 static int
quote_and_print(const char * str,FILE * strm,int commentnl)1087 quote_and_print(const char *str, FILE *strm, int commentnl)
1088 {
1089 const char *cp;
1090
1091 for (cp = str; *cp != '\0'; ++cp) {
1092 if (*cp == '"' || *cp == '\\')
1093 (void) putc('\\', strm);
1094
1095 (void) putc(*cp, strm);
1096
1097 if (commentnl && *cp == '\n') {
1098 (void) putc('#', strm);
1099 }
1100 }
1101
1102 return (ferror(strm));
1103 }
1104
1105 /*
1106 * These wrappers around lowlevel functions provide consistent error checking
1107 * and warnings.
1108 */
1109 static int
pg_get_prop(scf_propertygroup_t * pg,const char * propname,scf_property_t * prop)1110 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1111 {
1112 if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1113 return (0);
1114
1115 if (scf_error() != SCF_ERROR_NOT_FOUND)
1116 scfdie();
1117
1118 if (g_verbose) {
1119 ssize_t len;
1120 char *fmri;
1121
1122 len = scf_pg_to_fmri(pg, NULL, 0);
1123 if (len < 0)
1124 scfdie();
1125
1126 fmri = safe_malloc(len + 1);
1127
1128 if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1129 scfdie();
1130
1131 warn(gettext("Expected property %s of property group %s is "
1132 "missing.\n"), propname, fmri);
1133
1134 free(fmri);
1135 }
1136
1137 return (-1);
1138 }
1139
1140 static int
prop_check_type(scf_property_t * prop,scf_type_t ty)1141 prop_check_type(scf_property_t *prop, scf_type_t ty)
1142 {
1143 scf_type_t pty;
1144
1145 if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1146 scfdie();
1147
1148 if (ty == pty)
1149 return (0);
1150
1151 if (g_verbose) {
1152 ssize_t len;
1153 char *fmri;
1154 const char *tystr;
1155
1156 len = scf_property_to_fmri(prop, NULL, 0);
1157 if (len < 0)
1158 scfdie();
1159
1160 fmri = safe_malloc(len + 1);
1161
1162 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1163 scfdie();
1164
1165 tystr = scf_type_to_string(ty);
1166 if (tystr == NULL)
1167 tystr = "?";
1168
1169 warn(gettext("Property %s is not of expected type %s.\n"),
1170 fmri, tystr);
1171
1172 free(fmri);
1173 }
1174
1175 return (-1);
1176 }
1177
1178 static int
prop_get_val(scf_property_t * prop,scf_value_t * val)1179 prop_get_val(scf_property_t *prop, scf_value_t *val)
1180 {
1181 scf_error_t err;
1182
1183 if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1184 return (0);
1185
1186 err = scf_error();
1187
1188 if (err != SCF_ERROR_NOT_FOUND &&
1189 err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1190 err != SCF_ERROR_PERMISSION_DENIED)
1191 scfdie();
1192
1193 if (g_verbose) {
1194 ssize_t len;
1195 char *fmri, *emsg;
1196
1197 len = scf_property_to_fmri(prop, NULL, 0);
1198 if (len < 0)
1199 scfdie();
1200
1201 fmri = safe_malloc(len + 1);
1202
1203 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1204 scfdie();
1205
1206 if (err == SCF_ERROR_NOT_FOUND)
1207 emsg = gettext("Property %s has no values; expected "
1208 "one.\n");
1209 else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1210 emsg = gettext("Property %s has multiple values; "
1211 "expected one.\n");
1212 else
1213 emsg = gettext("No permission to read property %s.\n");
1214
1215 warn(emsg, fmri);
1216
1217 free(fmri);
1218 }
1219
1220 return (-1);
1221 }
1222
1223
1224 static boolean_t
snaplevel_is_instance(const scf_snaplevel_t * level)1225 snaplevel_is_instance(const scf_snaplevel_t *level)
1226 {
1227 if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1228 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1229 scfdie();
1230 return (0);
1231 } else {
1232 return (1);
1233 }
1234 }
1235
1236 /*
1237 * Decode FMRI into a service or instance, and put the result in *ep. If
1238 * memory cannot be allocated, return SCF_ERROR_NO_MEMORY. If the FMRI is
1239 * invalid, return SCF_ERROR_INVALID_ARGUMENT. If the FMRI does not specify
1240 * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED. If the entity cannot be
1241 * found, return SCF_ERROR_NOT_FOUND. Otherwise return SCF_ERROR_NONE, point
1242 * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1243 * whether *ep is a service.
1244 */
1245 static scf_error_t
fmri_to_entity(scf_handle_t * h,const char * fmri,void ** ep,int * isservice)1246 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1247 {
1248 char *fmri_copy;
1249 const char *sstr, *istr, *pgstr;
1250 scf_service_t *svc;
1251 scf_instance_t *inst;
1252
1253 fmri_copy = strdup(fmri);
1254 if (fmri_copy == NULL)
1255 return (SCF_ERROR_NO_MEMORY);
1256
1257 if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1258 SCF_SUCCESS) {
1259 free(fmri_copy);
1260 return (SCF_ERROR_INVALID_ARGUMENT);
1261 }
1262
1263 free(fmri_copy);
1264
1265 if (sstr == NULL || pgstr != NULL)
1266 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1267
1268 if (istr == NULL) {
1269 svc = scf_service_create(h);
1270 if (svc == NULL)
1271 return (SCF_ERROR_NO_MEMORY);
1272
1273 if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1274 SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1275 if (scf_error() != SCF_ERROR_NOT_FOUND)
1276 scfdie();
1277
1278 return (SCF_ERROR_NOT_FOUND);
1279 }
1280
1281 *ep = svc;
1282 *isservice = 1;
1283 } else {
1284 inst = scf_instance_create(h);
1285 if (inst == NULL)
1286 return (SCF_ERROR_NO_MEMORY);
1287
1288 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1289 NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1290 if (scf_error() != SCF_ERROR_NOT_FOUND)
1291 scfdie();
1292
1293 return (SCF_ERROR_NOT_FOUND);
1294 }
1295
1296 *ep = inst;
1297 *isservice = 0;
1298 }
1299
1300 return (SCF_ERROR_NONE);
1301 }
1302
1303 /*
1304 * Create the entity named by fmri. Place a pointer to its libscf handle in
1305 * *ep, and set or clear *isservicep if it is a service or an instance.
1306 * Returns
1307 * SCF_ERROR_NONE - success
1308 * SCF_ERROR_NO_MEMORY - scf_*_create() failed
1309 * SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1310 * SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1311 * SCF_ERROR_NOT_FOUND - no such scope
1312 * SCF_ERROR_PERMISSION_DENIED
1313 * SCF_ERROR_BACKEND_READONLY
1314 * SCF_ERROR_BACKEND_ACCESS
1315 */
1316 static scf_error_t
create_entity(scf_handle_t * h,const char * fmri,void ** ep,int * isservicep)1317 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1318 {
1319 char *fmri_copy;
1320 const char *scstr, *sstr, *istr, *pgstr;
1321 scf_scope_t *scope = NULL;
1322 scf_service_t *svc = NULL;
1323 scf_instance_t *inst = NULL;
1324 scf_error_t scfe;
1325
1326 fmri_copy = safe_strdup(fmri);
1327
1328 if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1329 0) {
1330 free(fmri_copy);
1331 return (SCF_ERROR_INVALID_ARGUMENT);
1332 }
1333
1334 if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1335 free(fmri_copy);
1336 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1337 }
1338
1339 *ep = NULL;
1340
1341 if ((scope = scf_scope_create(h)) == NULL ||
1342 (svc = scf_service_create(h)) == NULL ||
1343 (inst = scf_instance_create(h)) == NULL) {
1344 scfe = SCF_ERROR_NO_MEMORY;
1345 goto out;
1346 }
1347
1348 get_scope:
1349 if (scf_handle_get_scope(h, scstr, scope) != 0) {
1350 switch (scf_error()) {
1351 case SCF_ERROR_CONNECTION_BROKEN:
1352 scfdie();
1353 /* NOTREACHED */
1354
1355 case SCF_ERROR_NOT_FOUND:
1356 scfe = SCF_ERROR_NOT_FOUND;
1357 goto out;
1358
1359 case SCF_ERROR_HANDLE_MISMATCH:
1360 case SCF_ERROR_NOT_BOUND:
1361 case SCF_ERROR_INVALID_ARGUMENT:
1362 default:
1363 bad_error("scf_handle_get_scope", scf_error());
1364 }
1365 }
1366
1367 get_svc:
1368 if (scf_scope_get_service(scope, sstr, svc) != 0) {
1369 switch (scf_error()) {
1370 case SCF_ERROR_CONNECTION_BROKEN:
1371 scfdie();
1372 /* NOTREACHED */
1373
1374 case SCF_ERROR_DELETED:
1375 goto get_scope;
1376
1377 case SCF_ERROR_NOT_FOUND:
1378 break;
1379
1380 case SCF_ERROR_HANDLE_MISMATCH:
1381 case SCF_ERROR_INVALID_ARGUMENT:
1382 case SCF_ERROR_NOT_BOUND:
1383 case SCF_ERROR_NOT_SET:
1384 default:
1385 bad_error("scf_scope_get_service", scf_error());
1386 }
1387
1388 if (scf_scope_add_service(scope, sstr, svc) != 0) {
1389 switch (scf_error()) {
1390 case SCF_ERROR_CONNECTION_BROKEN:
1391 scfdie();
1392 /* NOTREACHED */
1393
1394 case SCF_ERROR_DELETED:
1395 goto get_scope;
1396
1397 case SCF_ERROR_PERMISSION_DENIED:
1398 case SCF_ERROR_BACKEND_READONLY:
1399 case SCF_ERROR_BACKEND_ACCESS:
1400 scfe = scf_error();
1401 goto out;
1402
1403 case SCF_ERROR_HANDLE_MISMATCH:
1404 case SCF_ERROR_INVALID_ARGUMENT:
1405 case SCF_ERROR_NOT_BOUND:
1406 case SCF_ERROR_NOT_SET:
1407 default:
1408 bad_error("scf_scope_get_service", scf_error());
1409 }
1410 }
1411 }
1412
1413 if (istr == NULL) {
1414 scfe = SCF_ERROR_NONE;
1415 *ep = svc;
1416 *isservicep = 1;
1417 goto out;
1418 }
1419
1420 get_inst:
1421 if (scf_service_get_instance(svc, istr, inst) != 0) {
1422 switch (scf_error()) {
1423 case SCF_ERROR_CONNECTION_BROKEN:
1424 scfdie();
1425 /* NOTREACHED */
1426
1427 case SCF_ERROR_DELETED:
1428 goto get_svc;
1429
1430 case SCF_ERROR_NOT_FOUND:
1431 break;
1432
1433 case SCF_ERROR_HANDLE_MISMATCH:
1434 case SCF_ERROR_INVALID_ARGUMENT:
1435 case SCF_ERROR_NOT_BOUND:
1436 case SCF_ERROR_NOT_SET:
1437 default:
1438 bad_error("scf_service_get_instance", scf_error());
1439 }
1440
1441 if (scf_service_add_instance(svc, istr, inst) != 0) {
1442 switch (scf_error()) {
1443 case SCF_ERROR_CONNECTION_BROKEN:
1444 scfdie();
1445 /* NOTREACHED */
1446
1447 case SCF_ERROR_DELETED:
1448 goto get_svc;
1449
1450 case SCF_ERROR_PERMISSION_DENIED:
1451 case SCF_ERROR_BACKEND_READONLY:
1452 case SCF_ERROR_BACKEND_ACCESS:
1453 scfe = scf_error();
1454 goto out;
1455
1456 case SCF_ERROR_HANDLE_MISMATCH:
1457 case SCF_ERROR_INVALID_ARGUMENT:
1458 case SCF_ERROR_NOT_BOUND:
1459 case SCF_ERROR_NOT_SET:
1460 default:
1461 bad_error("scf_service_add_instance",
1462 scf_error());
1463 }
1464 }
1465 }
1466
1467 scfe = SCF_ERROR_NONE;
1468 *ep = inst;
1469 *isservicep = 0;
1470
1471 out:
1472 if (*ep != inst)
1473 scf_instance_destroy(inst);
1474 if (*ep != svc)
1475 scf_service_destroy(svc);
1476 scf_scope_destroy(scope);
1477 free(fmri_copy);
1478 return (scfe);
1479 }
1480
1481 /*
1482 * Create or update a snapshot of inst. snap is a required scratch object.
1483 *
1484 * Returns
1485 * 0 - success
1486 * ECONNABORTED - repository connection broken
1487 * EPERM - permission denied
1488 * ENOSPC - configd is out of resources
1489 * ECANCELED - inst was deleted
1490 * -1 - unknown libscf error (message printed)
1491 */
1492 static int
take_snap(scf_instance_t * inst,const char * name,scf_snapshot_t * snap)1493 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1494 {
1495 again:
1496 if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1497 if (_scf_snapshot_take_attach(inst, snap) != 0) {
1498 switch (scf_error()) {
1499 case SCF_ERROR_CONNECTION_BROKEN:
1500 case SCF_ERROR_PERMISSION_DENIED:
1501 case SCF_ERROR_NO_RESOURCES:
1502 return (scferror2errno(scf_error()));
1503
1504 case SCF_ERROR_NOT_SET:
1505 case SCF_ERROR_INVALID_ARGUMENT:
1506 default:
1507 bad_error("_scf_snapshot_take_attach",
1508 scf_error());
1509 }
1510 }
1511 } else {
1512 switch (scf_error()) {
1513 case SCF_ERROR_NOT_FOUND:
1514 break;
1515
1516 case SCF_ERROR_DELETED:
1517 case SCF_ERROR_CONNECTION_BROKEN:
1518 return (scferror2errno(scf_error()));
1519
1520 case SCF_ERROR_HANDLE_MISMATCH:
1521 case SCF_ERROR_NOT_BOUND:
1522 case SCF_ERROR_INVALID_ARGUMENT:
1523 case SCF_ERROR_NOT_SET:
1524 default:
1525 bad_error("scf_instance_get_snapshot", scf_error());
1526 }
1527
1528 if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1529 switch (scf_error()) {
1530 case SCF_ERROR_EXISTS:
1531 goto again;
1532
1533 case SCF_ERROR_CONNECTION_BROKEN:
1534 case SCF_ERROR_NO_RESOURCES:
1535 case SCF_ERROR_PERMISSION_DENIED:
1536 return (scferror2errno(scf_error()));
1537
1538 default:
1539 scfwarn();
1540 return (-1);
1541
1542 case SCF_ERROR_NOT_SET:
1543 case SCF_ERROR_INTERNAL:
1544 case SCF_ERROR_INVALID_ARGUMENT:
1545 case SCF_ERROR_HANDLE_MISMATCH:
1546 bad_error("_scf_snapshot_take_new",
1547 scf_error());
1548 }
1549 }
1550 }
1551
1552 return (0);
1553 }
1554
1555 static int
refresh_running_snapshot(void * entity)1556 refresh_running_snapshot(void *entity)
1557 {
1558 scf_snapshot_t *snap;
1559 int r;
1560
1561 if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1562 scfdie();
1563 r = take_snap(entity, snap_running, snap);
1564 scf_snapshot_destroy(snap);
1565
1566 return (r);
1567 }
1568
1569 /*
1570 * Refresh entity. If isservice is zero, take entity to be an scf_instance_t *.
1571 * Otherwise take entity to be an scf_service_t * and refresh all of its child
1572 * instances. fmri is used for messages. inst, iter, and name_buf are used
1573 * for scratch space. Returns
1574 * 0 - success
1575 * ECONNABORTED - repository connection broken
1576 * ECANCELED - entity was deleted
1577 * EACCES - backend denied access
1578 * EPERM - permission denied
1579 * ENOSPC - repository server out of resources
1580 * -1 - _smf_refresh_instance_i() failed. scf_error() should be set.
1581 */
1582 static int
refresh_entity(int isservice,void * entity,const char * fmri,scf_instance_t * inst,scf_iter_t * iter,char * name_buf)1583 refresh_entity(int isservice, void *entity, const char *fmri,
1584 scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1585 {
1586 scf_error_t scfe;
1587 int r;
1588
1589 if (!isservice) {
1590 /*
1591 * Let restarter handles refreshing and making new running
1592 * snapshot only if operating on a live repository and not
1593 * running in early import.
1594 */
1595 if (est->sc_repo_filename == NULL &&
1596 est->sc_repo_doorname == NULL &&
1597 est->sc_in_emi == 0) {
1598 if (_smf_refresh_instance_i(entity) == 0) {
1599 if (g_verbose)
1600 warn(gettext("Refreshed %s.\n"), fmri);
1601 return (0);
1602 }
1603
1604 switch (scf_error()) {
1605 case SCF_ERROR_BACKEND_ACCESS:
1606 return (EACCES);
1607
1608 case SCF_ERROR_PERMISSION_DENIED:
1609 return (EPERM);
1610
1611 default:
1612 return (-1);
1613 }
1614 } else {
1615 r = refresh_running_snapshot(entity);
1616 switch (r) {
1617 case 0:
1618 break;
1619
1620 case ECONNABORTED:
1621 case ECANCELED:
1622 case EPERM:
1623 case ENOSPC:
1624 break;
1625
1626 default:
1627 bad_error("refresh_running_snapshot",
1628 scf_error());
1629 }
1630
1631 return (r);
1632 }
1633 }
1634
1635 if (scf_iter_service_instances(iter, entity) != 0) {
1636 switch (scf_error()) {
1637 case SCF_ERROR_CONNECTION_BROKEN:
1638 return (ECONNABORTED);
1639
1640 case SCF_ERROR_DELETED:
1641 return (ECANCELED);
1642
1643 case SCF_ERROR_HANDLE_MISMATCH:
1644 case SCF_ERROR_NOT_BOUND:
1645 case SCF_ERROR_NOT_SET:
1646 default:
1647 bad_error("scf_iter_service_instances", scf_error());
1648 }
1649 }
1650
1651 for (;;) {
1652 r = scf_iter_next_instance(iter, inst);
1653 if (r == 0)
1654 break;
1655 if (r != 1) {
1656 switch (scf_error()) {
1657 case SCF_ERROR_CONNECTION_BROKEN:
1658 return (ECONNABORTED);
1659
1660 case SCF_ERROR_DELETED:
1661 return (ECANCELED);
1662
1663 case SCF_ERROR_HANDLE_MISMATCH:
1664 case SCF_ERROR_NOT_BOUND:
1665 case SCF_ERROR_NOT_SET:
1666 case SCF_ERROR_INVALID_ARGUMENT:
1667 default:
1668 bad_error("scf_iter_next_instance",
1669 scf_error());
1670 }
1671 }
1672
1673 /*
1674 * Similarly, just take a new running snapshot if operating on
1675 * a non-live repository or running during early import.
1676 */
1677 if (est->sc_repo_filename != NULL ||
1678 est->sc_repo_doorname != NULL ||
1679 est->sc_in_emi == 1) {
1680 r = refresh_running_snapshot(inst);
1681 switch (r) {
1682 case 0:
1683 continue;
1684
1685 case ECONNABORTED:
1686 case ECANCELED:
1687 case EPERM:
1688 case ENOSPC:
1689 break;
1690 default:
1691 bad_error("refresh_running_snapshot",
1692 scf_error());
1693 }
1694
1695 return (r);
1696
1697 }
1698
1699 if (_smf_refresh_instance_i(inst) == 0) {
1700 if (g_verbose) {
1701 if (scf_instance_get_name(inst, name_buf,
1702 max_scf_name_len + 1) < 0)
1703 (void) strcpy(name_buf, "?");
1704
1705 warn(gettext("Refreshed %s:%s.\n"),
1706 fmri, name_buf);
1707 }
1708 } else {
1709 if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1710 g_verbose) {
1711 scfe = scf_error();
1712
1713 if (scf_instance_to_fmri(inst, name_buf,
1714 max_scf_name_len + 1) < 0)
1715 (void) strcpy(name_buf, "?");
1716
1717 warn(gettext(
1718 "Refresh of %s:%s failed: %s.\n"), fmri,
1719 name_buf, scf_strerror(scfe));
1720 }
1721 }
1722 }
1723
1724 return (0);
1725 }
1726
1727 static void
private_refresh(void)1728 private_refresh(void)
1729 {
1730 scf_instance_t *pinst = NULL;
1731 scf_iter_t *piter = NULL;
1732 ssize_t fmrilen;
1733 size_t bufsz;
1734 char *fmribuf;
1735 void *ent;
1736 int issvc;
1737 int r;
1738
1739 if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1740 return;
1741
1742 assert(cur_svc != NULL);
1743
1744 bufsz = max_scf_fmri_len + 1;
1745 fmribuf = safe_malloc(bufsz);
1746 if (cur_inst) {
1747 issvc = 0;
1748 ent = cur_inst;
1749 fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1750 } else {
1751 issvc = 1;
1752 ent = cur_svc;
1753 fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1754 if ((pinst = scf_instance_create(g_hndl)) == NULL)
1755 scfdie();
1756
1757 if ((piter = scf_iter_create(g_hndl)) == NULL)
1758 scfdie();
1759 }
1760 if (fmrilen < 0) {
1761 free(fmribuf);
1762 if (scf_error() != SCF_ERROR_DELETED)
1763 scfdie();
1764
1765 warn(emsg_deleted);
1766 return;
1767 }
1768 assert(fmrilen < bufsz);
1769
1770 r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1771 switch (r) {
1772 case 0:
1773 break;
1774
1775 case ECONNABORTED:
1776 warn(gettext("Could not refresh %s "
1777 "(repository connection broken).\n"), fmribuf);
1778 break;
1779
1780 case ECANCELED:
1781 warn(emsg_deleted);
1782 break;
1783
1784 case EPERM:
1785 warn(gettext("Could not refresh %s "
1786 "(permission denied).\n"), fmribuf);
1787 break;
1788
1789 case ENOSPC:
1790 warn(gettext("Could not refresh %s "
1791 "(repository server out of resources).\n"),
1792 fmribuf);
1793 break;
1794
1795 case EACCES:
1796 default:
1797 bad_error("refresh_entity", scf_error());
1798 }
1799
1800 if (issvc) {
1801 scf_instance_destroy(pinst);
1802 scf_iter_destroy(piter);
1803 }
1804
1805 free(fmribuf);
1806 }
1807
1808
1809 static int
stash_scferror_err(scf_callback_t * cbp,scf_error_t err)1810 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1811 {
1812 cbp->sc_err = scferror2errno(err);
1813 return (UU_WALK_ERROR);
1814 }
1815
1816 static int
stash_scferror(scf_callback_t * cbp)1817 stash_scferror(scf_callback_t *cbp)
1818 {
1819 return (stash_scferror_err(cbp, scf_error()));
1820 }
1821
1822 static int select_inst(const char *);
1823 static int select_svc(const char *);
1824
1825 /*
1826 * Take a property that does not have a type and check to see if a type
1827 * exists or can be gleened from the current data. Set the type.
1828 *
1829 * Check the current level (instance) and then check the higher level
1830 * (service). This could be the case for adding a new property to
1831 * the instance that's going to "override" a service level property.
1832 *
1833 * For a property :
1834 * 1. Take the type from an existing property
1835 * 2. Take the type from a template entry
1836 *
1837 * If the type can not be found, then leave the type as is, and let the import
1838 * report the problem of the missing type.
1839 */
1840 static int
find_current_prop_type(void * p,void * g)1841 find_current_prop_type(void *p, void *g)
1842 {
1843 property_t *prop = p;
1844 scf_callback_t *lcb = g;
1845 pgroup_t *pg = NULL;
1846
1847 const char *fmri = NULL;
1848 char *lfmri = NULL;
1849 char *cur_selection = NULL;
1850
1851 scf_propertygroup_t *sc_pg = NULL;
1852 scf_property_t *sc_prop = NULL;
1853 scf_pg_tmpl_t *t_pg = NULL;
1854 scf_prop_tmpl_t *t_prop = NULL;
1855 scf_type_t prop_type;
1856
1857 value_t *vp;
1858 int issvc = lcb->sc_service;
1859 int r = UU_WALK_ERROR;
1860
1861 if (prop->sc_value_type != SCF_TYPE_INVALID)
1862 return (UU_WALK_NEXT);
1863
1864 t_prop = scf_tmpl_prop_create(g_hndl);
1865 sc_prop = scf_property_create(g_hndl);
1866 if (sc_prop == NULL || t_prop == NULL) {
1867 warn(gettext("Unable to create the property to attempt and "
1868 "find a missing type.\n"));
1869
1870 scf_property_destroy(sc_prop);
1871 scf_tmpl_prop_destroy(t_prop);
1872
1873 return (UU_WALK_ERROR);
1874 }
1875
1876 if (lcb->sc_flags == 1) {
1877 pg = lcb->sc_parent;
1878 issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT);
1879 fmri = pg->sc_parent->sc_fmri;
1880 retry_pg:
1881 if (cur_svc && cur_selection == NULL) {
1882 cur_selection = safe_malloc(max_scf_fmri_len + 1);
1883 lscf_get_selection_str(cur_selection,
1884 max_scf_fmri_len + 1);
1885
1886 if (strcmp(cur_selection, fmri) != 0) {
1887 lscf_select(fmri);
1888 } else {
1889 free(cur_selection);
1890 cur_selection = NULL;
1891 }
1892 } else {
1893 lscf_select(fmri);
1894 }
1895
1896 if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) {
1897 warn(gettext("Unable to create property group to "
1898 "find a missing property type.\n"));
1899
1900 goto out;
1901 }
1902
1903 if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) {
1904 /*
1905 * If this is the sc_pg from the parent
1906 * let the caller clean up the sc_pg,
1907 * and just throw it away in this case.
1908 */
1909 if (sc_pg != lcb->sc_parent)
1910 scf_pg_destroy(sc_pg);
1911
1912 sc_pg = NULL;
1913 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1914 warn(gettext("Unable to create template "
1915 "property group to find a property "
1916 "type.\n"));
1917
1918 goto out;
1919 }
1920
1921 if (scf_tmpl_get_by_pg_name(fmri, NULL,
1922 pg->sc_pgroup_name, NULL, t_pg,
1923 SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) {
1924 /*
1925 * if instance get service and jump back
1926 */
1927 scf_tmpl_pg_destroy(t_pg);
1928 t_pg = NULL;
1929 if (issvc == 0) {
1930 entity_t *e = pg->sc_parent->sc_parent;
1931
1932 fmri = e->sc_fmri;
1933 issvc = 1;
1934 goto retry_pg;
1935 } else {
1936 goto out;
1937 }
1938 }
1939 }
1940 } else {
1941 sc_pg = lcb->sc_parent;
1942 }
1943
1944 /*
1945 * Attempt to get the type from an existing property. If the property
1946 * cannot be found then attempt to get the type from a template entry
1947 * for the property.
1948 *
1949 * Finally, if at the instance level look at the service level.
1950 */
1951 if (sc_pg != NULL &&
1952 pg_get_prop(sc_pg, prop->sc_property_name,
1953 sc_prop) == SCF_SUCCESS &&
1954 scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) {
1955 prop->sc_value_type = prop_type;
1956
1957 /*
1958 * Found a type, update the value types and validate
1959 * the actual value against this type.
1960 */
1961 for (vp = uu_list_first(prop->sc_property_values);
1962 vp != NULL;
1963 vp = uu_list_next(prop->sc_property_values, vp)) {
1964 vp->sc_type = prop->sc_value_type;
1965 lxml_store_value(vp, 0, NULL);
1966 }
1967
1968 r = UU_WALK_NEXT;
1969 goto out;
1970 }
1971
1972 /*
1973 * If we get here with t_pg set to NULL then we had to have
1974 * gotten an sc_pg but that sc_pg did not have the property
1975 * we are looking for. So if the t_pg is not null look up
1976 * the template entry for the property.
1977 *
1978 * If the t_pg is null then need to attempt to get a matching
1979 * template entry for the sc_pg, and see if there is a property
1980 * entry for that template entry.
1981 */
1982 do_tmpl :
1983 if (t_pg != NULL &&
1984 scf_tmpl_get_by_prop(t_pg, prop->sc_property_name,
1985 t_prop, 0) == SCF_SUCCESS) {
1986 if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) {
1987 prop->sc_value_type = prop_type;
1988
1989 /*
1990 * Found a type, update the value types and validate
1991 * the actual value against this type.
1992 */
1993 for (vp = uu_list_first(prop->sc_property_values);
1994 vp != NULL;
1995 vp = uu_list_next(prop->sc_property_values, vp)) {
1996 vp->sc_type = prop->sc_value_type;
1997 lxml_store_value(vp, 0, NULL);
1998 }
1999
2000 r = UU_WALK_NEXT;
2001 goto out;
2002 }
2003 } else {
2004 if (t_pg == NULL && sc_pg) {
2005 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
2006 warn(gettext("Unable to create template "
2007 "property group to find a property "
2008 "type.\n"));
2009
2010 goto out;
2011 }
2012
2013 if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
2014 scf_tmpl_pg_destroy(t_pg);
2015 t_pg = NULL;
2016 } else {
2017 goto do_tmpl;
2018 }
2019 }
2020 }
2021
2022 if (issvc == 0) {
2023 scf_instance_t *i;
2024 scf_service_t *s;
2025
2026 issvc = 1;
2027 if (lcb->sc_flags == 1) {
2028 entity_t *e = pg->sc_parent->sc_parent;
2029
2030 fmri = e->sc_fmri;
2031 goto retry_pg;
2032 }
2033
2034 /*
2035 * because lcb->sc_flags was not set then this means
2036 * the pg was not used and can be used here.
2037 */
2038 if ((pg = internal_pgroup_new()) == NULL) {
2039 warn(gettext("Could not create internal property group "
2040 "to find a missing type."));
2041
2042 goto out;
2043 }
2044
2045 pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1);
2046 if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name,
2047 max_scf_name_len + 1) < 0)
2048 goto out;
2049
2050 i = scf_instance_create(g_hndl);
2051 s = scf_service_create(g_hndl);
2052 if (i == NULL || s == NULL ||
2053 scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) {
2054 warn(gettext("Could not get a service for the instance "
2055 "to find a missing type."));
2056
2057 goto out;
2058 }
2059
2060 /*
2061 * Check to see truly at the instance level.
2062 */
2063 lfmri = safe_malloc(max_scf_fmri_len + 1);
2064 if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
2065 scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0)
2066 goto out;
2067 else
2068 fmri = (const char *)lfmri;
2069
2070 goto retry_pg;
2071 }
2072
2073 out :
2074 if (sc_pg != lcb->sc_parent) {
2075 scf_pg_destroy(sc_pg);
2076 }
2077
2078 /*
2079 * If this is true then the pg was allocated
2080 * here, and the name was set so need to free
2081 * the name and the pg.
2082 */
2083 if (pg != NULL && pg != lcb->sc_parent) {
2084 free((char *)pg->sc_pgroup_name);
2085 internal_pgroup_free(pg);
2086 }
2087
2088 if (cur_selection) {
2089 lscf_select(cur_selection);
2090 free(cur_selection);
2091 }
2092
2093 scf_tmpl_pg_destroy(t_pg);
2094 scf_tmpl_prop_destroy(t_prop);
2095 scf_property_destroy(sc_prop);
2096
2097 if (r != UU_WALK_NEXT)
2098 warn(gettext("Could not find property type for \"%s\" "
2099 "from \"%s\"\n"), prop->sc_property_name,
2100 fmri != NULL ? fmri : lcb->sc_source_fmri);
2101
2102 free(lfmri);
2103
2104 return (r);
2105 }
2106
2107 /*
2108 * Take a property group that does not have a type and check to see if a type
2109 * exists or can be gleened from the current data. Set the type.
2110 *
2111 * Check the current level (instance) and then check the higher level
2112 * (service). This could be the case for adding a new property to
2113 * the instance that's going to "override" a service level property.
2114 *
2115 * For a property group
2116 * 1. Take the type from an existing property group
2117 * 2. Take the type from a template entry
2118 *
2119 * If the type can not be found, then leave the type as is, and let the import
2120 * report the problem of the missing type.
2121 */
2122 static int
find_current_pg_type(void * p,void * sori)2123 find_current_pg_type(void *p, void *sori)
2124 {
2125 entity_t *si = sori;
2126 pgroup_t *pg = p;
2127
2128 const char *ofmri, *fmri;
2129 char *cur_selection = NULL;
2130 char *pg_type = NULL;
2131
2132 scf_propertygroup_t *sc_pg = NULL;
2133 scf_pg_tmpl_t *t_pg = NULL;
2134
2135 int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2136 int r = UU_WALK_ERROR;
2137
2138 ofmri = fmri = si->sc_fmri;
2139 if (pg->sc_pgroup_type != NULL) {
2140 r = UU_WALK_NEXT;
2141
2142 goto out;
2143 }
2144
2145 sc_pg = scf_pg_create(g_hndl);
2146 if (sc_pg == NULL) {
2147 warn(gettext("Unable to create property group to attempt "
2148 "and find a missing type.\n"));
2149
2150 return (UU_WALK_ERROR);
2151 }
2152
2153 /*
2154 * Using get_pg() requires that the cur_svc/cur_inst be
2155 * via lscf_select. Need to preserve the current selection
2156 * if going to use lscf_select() to set up the cur_svc/cur_inst
2157 */
2158 if (cur_svc) {
2159 cur_selection = safe_malloc(max_scf_fmri_len + 1);
2160 lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1);
2161 }
2162
2163 /*
2164 * If the property group exists get the type, and set
2165 * the pgroup_t type of that type.
2166 *
2167 * If not the check for a template pg_pattern entry
2168 * and take the type from that.
2169 */
2170 retry_svc:
2171 lscf_select(fmri);
2172
2173 if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) {
2174 pg_type = safe_malloc(max_scf_pg_type_len + 1);
2175 if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type,
2176 max_scf_pg_type_len + 1) != -1) {
2177 pg->sc_pgroup_type = pg_type;
2178
2179 r = UU_WALK_NEXT;
2180 goto out;
2181 } else {
2182 free(pg_type);
2183 }
2184 } else {
2185 if ((t_pg == NULL) &&
2186 (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
2187 goto out;
2188
2189 if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name,
2190 NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS &&
2191 scf_tmpl_pg_type(t_pg, &pg_type) != -1) {
2192 pg->sc_pgroup_type = pg_type;
2193
2194 r = UU_WALK_NEXT;
2195 goto out;
2196 }
2197 }
2198
2199 /*
2200 * If type is not found at the instance level then attempt to
2201 * find the type at the service level.
2202 */
2203 if (!issvc) {
2204 si = si->sc_parent;
2205 fmri = si->sc_fmri;
2206 issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2207 goto retry_svc;
2208 }
2209
2210 out :
2211 if (cur_selection) {
2212 lscf_select(cur_selection);
2213 free(cur_selection);
2214 }
2215
2216 /*
2217 * Now walk the properties of the property group to make sure that
2218 * all properties have the correct type and values are valid for
2219 * those types.
2220 */
2221 if (r == UU_WALK_NEXT) {
2222 scf_callback_t cb;
2223
2224 cb.sc_service = issvc;
2225 cb.sc_source_fmri = ofmri;
2226 if (sc_pg != NULL) {
2227 cb.sc_parent = sc_pg;
2228 cb.sc_flags = 0;
2229 } else {
2230 cb.sc_parent = pg;
2231 cb.sc_flags = 1;
2232 }
2233
2234 if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type,
2235 &cb, UU_DEFAULT) != 0) {
2236 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2237 bad_error("uu_list_walk", uu_error());
2238
2239 r = UU_WALK_ERROR;
2240 }
2241 } else {
2242 warn(gettext("Could not find property group type for "
2243 "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri);
2244 }
2245
2246 scf_tmpl_pg_destroy(t_pg);
2247 scf_pg_destroy(sc_pg);
2248
2249 return (r);
2250 }
2251
2252 /*
2253 * Import. These functions import a bundle into the repository.
2254 */
2255
2256 /*
2257 * Add a transaction entry to lcbdata->sc_trans for this property_t. Uses
2258 * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata. On success,
2259 * returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
2260 * lcbdata->sc_err to
2261 * ENOMEM - out of memory
2262 * ECONNABORTED - repository connection broken
2263 * ECANCELED - sc_trans's property group was deleted
2264 * EINVAL - p's name is invalid (error printed)
2265 * - p has an invalid value (error printed)
2266 */
2267 static int
lscf_property_import(void * v,void * pvt)2268 lscf_property_import(void *v, void *pvt)
2269 {
2270 property_t *p = v;
2271 scf_callback_t *lcbdata = pvt;
2272 value_t *vp;
2273 scf_transaction_t *trans = lcbdata->sc_trans;
2274 scf_transaction_entry_t *entr;
2275 scf_value_t *val;
2276 scf_type_t tp;
2277
2278 if ((lcbdata->sc_flags & SCI_NOENABLED ||
2279 lcbdata->sc_flags & SCI_DELAYENABLE) &&
2280 strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
2281 lcbdata->sc_enable = p;
2282 return (UU_WALK_NEXT);
2283 }
2284
2285 entr = scf_entry_create(lcbdata->sc_handle);
2286 if (entr == NULL) {
2287 switch (scf_error()) {
2288 case SCF_ERROR_NO_MEMORY:
2289 return (stash_scferror(lcbdata));
2290
2291 case SCF_ERROR_INVALID_ARGUMENT:
2292 default:
2293 bad_error("scf_entry_create", scf_error());
2294 }
2295 }
2296
2297 tp = p->sc_value_type;
2298
2299 if (scf_transaction_property_new(trans, entr,
2300 p->sc_property_name, tp) != 0) {
2301 switch (scf_error()) {
2302 case SCF_ERROR_INVALID_ARGUMENT:
2303 semerr(emsg_invalid_prop_name, p->sc_property_name);
2304 scf_entry_destroy(entr);
2305 return (stash_scferror(lcbdata));
2306
2307 case SCF_ERROR_EXISTS:
2308 break;
2309
2310 case SCF_ERROR_DELETED:
2311 case SCF_ERROR_CONNECTION_BROKEN:
2312 scf_entry_destroy(entr);
2313 return (stash_scferror(lcbdata));
2314
2315 case SCF_ERROR_NOT_BOUND:
2316 case SCF_ERROR_HANDLE_MISMATCH:
2317 case SCF_ERROR_NOT_SET:
2318 default:
2319 bad_error("scf_transaction_property_new", scf_error());
2320 }
2321
2322 if (scf_transaction_property_change_type(trans, entr,
2323 p->sc_property_name, tp) != 0) {
2324 switch (scf_error()) {
2325 case SCF_ERROR_DELETED:
2326 case SCF_ERROR_CONNECTION_BROKEN:
2327 scf_entry_destroy(entr);
2328 return (stash_scferror(lcbdata));
2329
2330 case SCF_ERROR_INVALID_ARGUMENT:
2331 semerr(emsg_invalid_prop_name,
2332 p->sc_property_name);
2333 scf_entry_destroy(entr);
2334 return (stash_scferror(lcbdata));
2335
2336 case SCF_ERROR_NOT_FOUND:
2337 case SCF_ERROR_NOT_SET:
2338 case SCF_ERROR_HANDLE_MISMATCH:
2339 case SCF_ERROR_NOT_BOUND:
2340 default:
2341 bad_error(
2342 "scf_transaction_property_change_type",
2343 scf_error());
2344 }
2345 }
2346 }
2347
2348 for (vp = uu_list_first(p->sc_property_values);
2349 vp != NULL;
2350 vp = uu_list_next(p->sc_property_values, vp)) {
2351 val = scf_value_create(g_hndl);
2352 if (val == NULL) {
2353 switch (scf_error()) {
2354 case SCF_ERROR_NO_MEMORY:
2355 return (stash_scferror(lcbdata));
2356
2357 case SCF_ERROR_INVALID_ARGUMENT:
2358 default:
2359 bad_error("scf_value_create", scf_error());
2360 }
2361 }
2362
2363 switch (tp) {
2364 case SCF_TYPE_BOOLEAN:
2365 scf_value_set_boolean(val, vp->sc_u.sc_count);
2366 break;
2367 case SCF_TYPE_COUNT:
2368 scf_value_set_count(val, vp->sc_u.sc_count);
2369 break;
2370 case SCF_TYPE_INTEGER:
2371 scf_value_set_integer(val, vp->sc_u.sc_integer);
2372 break;
2373 default:
2374 assert(vp->sc_u.sc_string != NULL);
2375 if (scf_value_set_from_string(val, tp,
2376 vp->sc_u.sc_string) != 0) {
2377 if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
2378 bad_error("scf_value_set_from_string",
2379 scf_error());
2380
2381 warn(gettext("Value \"%s\" is not a valid "
2382 "%s.\n"), vp->sc_u.sc_string,
2383 scf_type_to_string(tp));
2384 scf_value_destroy(val);
2385 return (stash_scferror(lcbdata));
2386 }
2387 break;
2388 }
2389
2390 if (scf_entry_add_value(entr, val) != 0)
2391 bad_error("scf_entry_add_value", scf_error());
2392 }
2393
2394 return (UU_WALK_NEXT);
2395 }
2396
2397 /*
2398 * Import a pgroup_t into the repository. Uses sc_handle, sc_parent,
2399 * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2400 * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2401 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
2402 * lcbdata->sc_err to
2403 * ECONNABORTED - repository connection broken
2404 * ENOMEM - out of memory
2405 * ENOSPC - svc.configd is out of resources
2406 * ECANCELED - sc_parent was deleted
2407 * EPERM - could not create property group (permission denied) (error printed)
2408 * - could not modify property group (permission denied) (error printed)
2409 * - could not delete property group (permission denied) (error printed)
2410 * EROFS - could not create property group (repository is read-only)
2411 * - could not delete property group (repository is read-only)
2412 * EACCES - could not create property group (backend access denied)
2413 * - could not delete property group (backend access denied)
2414 * EEXIST - could not create property group (already exists)
2415 * EINVAL - invalid property group name (error printed)
2416 * - invalid property name (error printed)
2417 * - invalid value (error printed)
2418 * EBUSY - new property group deleted (error printed)
2419 * - new property group changed (error printed)
2420 * - property group added (error printed)
2421 * - property group deleted (error printed)
2422 */
2423 static int
entity_pgroup_import(void * v,void * pvt)2424 entity_pgroup_import(void *v, void *pvt)
2425 {
2426 pgroup_t *p = v;
2427 scf_callback_t cbdata;
2428 scf_callback_t *lcbdata = pvt;
2429 void *ent = lcbdata->sc_parent;
2430 int issvc = lcbdata->sc_service;
2431 int r;
2432
2433 const char * const pg_changed = gettext("%s changed unexpectedly "
2434 "(new property group \"%s\" changed).\n");
2435
2436 /* Never import deleted property groups. */
2437 if (p->sc_pgroup_delete) {
2438 if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY &&
2439 entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) {
2440 goto delete_pg;
2441 }
2442 return (UU_WALK_NEXT);
2443 }
2444
2445 if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
2446 strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
2447 lcbdata->sc_general = p;
2448 return (UU_WALK_NEXT);
2449 }
2450
2451 add_pg:
2452 if (issvc)
2453 r = scf_service_add_pg(ent, p->sc_pgroup_name,
2454 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2455 else
2456 r = scf_instance_add_pg(ent, p->sc_pgroup_name,
2457 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2458 if (r != 0) {
2459 switch (scf_error()) {
2460 case SCF_ERROR_DELETED:
2461 case SCF_ERROR_CONNECTION_BROKEN:
2462 case SCF_ERROR_BACKEND_READONLY:
2463 case SCF_ERROR_BACKEND_ACCESS:
2464 case SCF_ERROR_NO_RESOURCES:
2465 return (stash_scferror(lcbdata));
2466
2467 case SCF_ERROR_EXISTS:
2468 if (lcbdata->sc_flags & SCI_FORCE)
2469 break;
2470 return (stash_scferror(lcbdata));
2471
2472 case SCF_ERROR_INVALID_ARGUMENT:
2473 warn(emsg_fmri_invalid_pg_name_type,
2474 lcbdata->sc_source_fmri,
2475 p->sc_pgroup_name, p->sc_pgroup_type);
2476 return (stash_scferror(lcbdata));
2477
2478 case SCF_ERROR_PERMISSION_DENIED:
2479 warn(emsg_pg_add_perm, p->sc_pgroup_name,
2480 lcbdata->sc_target_fmri);
2481 return (stash_scferror(lcbdata));
2482
2483 case SCF_ERROR_NOT_BOUND:
2484 case SCF_ERROR_HANDLE_MISMATCH:
2485 case SCF_ERROR_NOT_SET:
2486 default:
2487 bad_error("scf_service_add_pg", scf_error());
2488 }
2489
2490 if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2491 switch (scf_error()) {
2492 case SCF_ERROR_CONNECTION_BROKEN:
2493 case SCF_ERROR_DELETED:
2494 return (stash_scferror(lcbdata));
2495
2496 case SCF_ERROR_INVALID_ARGUMENT:
2497 warn(emsg_fmri_invalid_pg_name,
2498 lcbdata->sc_source_fmri,
2499 p->sc_pgroup_name);
2500 return (stash_scferror(lcbdata));
2501
2502 case SCF_ERROR_NOT_FOUND:
2503 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2504 p->sc_pgroup_name);
2505 lcbdata->sc_err = EBUSY;
2506 return (UU_WALK_ERROR);
2507
2508 case SCF_ERROR_NOT_BOUND:
2509 case SCF_ERROR_HANDLE_MISMATCH:
2510 case SCF_ERROR_NOT_SET:
2511 default:
2512 bad_error("entity_get_pg", scf_error());
2513 }
2514 }
2515
2516 if (lcbdata->sc_flags & SCI_KEEP)
2517 goto props;
2518
2519 delete_pg:
2520 if (scf_pg_delete(imp_pg) != 0) {
2521 switch (scf_error()) {
2522 case SCF_ERROR_DELETED:
2523 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2524 p->sc_pgroup_name);
2525 lcbdata->sc_err = EBUSY;
2526 return (UU_WALK_ERROR);
2527
2528 case SCF_ERROR_PERMISSION_DENIED:
2529 warn(emsg_pg_del_perm, p->sc_pgroup_name,
2530 lcbdata->sc_target_fmri);
2531 return (stash_scferror(lcbdata));
2532
2533 case SCF_ERROR_BACKEND_READONLY:
2534 case SCF_ERROR_BACKEND_ACCESS:
2535 case SCF_ERROR_CONNECTION_BROKEN:
2536 return (stash_scferror(lcbdata));
2537
2538 case SCF_ERROR_NOT_SET:
2539 default:
2540 bad_error("scf_pg_delete", scf_error());
2541 }
2542 }
2543
2544 if (p->sc_pgroup_delete)
2545 return (UU_WALK_NEXT);
2546
2547 goto add_pg;
2548 }
2549
2550 props:
2551
2552 /*
2553 * Add properties to property group, if any.
2554 */
2555 cbdata.sc_handle = lcbdata->sc_handle;
2556 cbdata.sc_parent = imp_pg;
2557 cbdata.sc_flags = lcbdata->sc_flags;
2558 cbdata.sc_trans = imp_tx;
2559 cbdata.sc_enable = NULL;
2560
2561 if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2562 switch (scf_error()) {
2563 case SCF_ERROR_BACKEND_ACCESS:
2564 case SCF_ERROR_BACKEND_READONLY:
2565 case SCF_ERROR_CONNECTION_BROKEN:
2566 return (stash_scferror(lcbdata));
2567
2568 case SCF_ERROR_DELETED:
2569 warn(pg_changed, lcbdata->sc_target_fmri,
2570 p->sc_pgroup_name);
2571 lcbdata->sc_err = EBUSY;
2572 return (UU_WALK_ERROR);
2573
2574 case SCF_ERROR_PERMISSION_DENIED:
2575 warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2576 lcbdata->sc_target_fmri);
2577 return (stash_scferror(lcbdata));
2578
2579 case SCF_ERROR_NOT_BOUND:
2580 case SCF_ERROR_NOT_SET:
2581 case SCF_ERROR_IN_USE:
2582 case SCF_ERROR_HANDLE_MISMATCH:
2583 default:
2584 bad_error("scf_transaction_start", scf_error());
2585 }
2586 }
2587
2588 if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2589 UU_DEFAULT) != 0) {
2590 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2591 bad_error("uu_list_walk", uu_error());
2592 scf_transaction_reset(imp_tx);
2593
2594 lcbdata->sc_err = cbdata.sc_err;
2595 if (cbdata.sc_err == ECANCELED) {
2596 warn(pg_changed, lcbdata->sc_target_fmri,
2597 p->sc_pgroup_name);
2598 lcbdata->sc_err = EBUSY;
2599 }
2600 return (UU_WALK_ERROR);
2601 }
2602
2603 if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2604 cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2605
2606 /*
2607 * take the snapshot running snapshot then
2608 * import the stored general/enable property
2609 */
2610 r = take_snap(ent, snap_running, imp_rsnap);
2611 switch (r) {
2612 case 0:
2613 break;
2614
2615 case ECONNABORTED:
2616 warn(gettext("Could not take %s snapshot on import "
2617 "(repository connection broken).\n"),
2618 snap_running);
2619 lcbdata->sc_err = r;
2620 return (UU_WALK_ERROR);
2621 case ECANCELED:
2622 warn(emsg_deleted);
2623 lcbdata->sc_err = r;
2624 return (UU_WALK_ERROR);
2625
2626 case EPERM:
2627 warn(gettext("Could not take %s snapshot "
2628 "(permission denied).\n"), snap_running);
2629 lcbdata->sc_err = r;
2630 return (UU_WALK_ERROR);
2631
2632 case ENOSPC:
2633 warn(gettext("Could not take %s snapshot"
2634 "(repository server out of resources).\n"),
2635 snap_running);
2636 lcbdata->sc_err = r;
2637 return (UU_WALK_ERROR);
2638
2639 default:
2640 bad_error("take_snap", r);
2641 }
2642
2643 r = lscf_property_import(cbdata.sc_enable, &cbdata);
2644 if (r != UU_WALK_NEXT) {
2645 if (r != UU_WALK_ERROR)
2646 bad_error("lscf_property_import", r);
2647 return (EINVAL);
2648 }
2649 }
2650
2651 r = scf_transaction_commit(imp_tx);
2652 switch (r) {
2653 case 1:
2654 r = UU_WALK_NEXT;
2655 break;
2656
2657 case 0:
2658 warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2659 lcbdata->sc_err = EBUSY;
2660 r = UU_WALK_ERROR;
2661 break;
2662
2663 case -1:
2664 switch (scf_error()) {
2665 case SCF_ERROR_BACKEND_READONLY:
2666 case SCF_ERROR_BACKEND_ACCESS:
2667 case SCF_ERROR_CONNECTION_BROKEN:
2668 case SCF_ERROR_NO_RESOURCES:
2669 r = stash_scferror(lcbdata);
2670 break;
2671
2672 case SCF_ERROR_DELETED:
2673 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2674 p->sc_pgroup_name);
2675 lcbdata->sc_err = EBUSY;
2676 r = UU_WALK_ERROR;
2677 break;
2678
2679 case SCF_ERROR_PERMISSION_DENIED:
2680 warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2681 lcbdata->sc_target_fmri);
2682 r = stash_scferror(lcbdata);
2683 break;
2684
2685 case SCF_ERROR_NOT_SET:
2686 case SCF_ERROR_INVALID_ARGUMENT:
2687 case SCF_ERROR_NOT_BOUND:
2688 default:
2689 bad_error("scf_transaction_commit", scf_error());
2690 }
2691 break;
2692
2693 default:
2694 bad_error("scf_transaction_commit", r);
2695 }
2696
2697 scf_transaction_destroy_children(imp_tx);
2698
2699 return (r);
2700 }
2701
2702 /*
2703 * Returns
2704 * 0 - success
2705 * ECONNABORTED - repository connection broken
2706 * ENOMEM - out of memory
2707 * ENOSPC - svc.configd is out of resources
2708 * ECANCELED - inst was deleted
2709 * EPERM - could not create property group (permission denied) (error printed)
2710 * - could not modify property group (permission denied) (error printed)
2711 * EROFS - could not create property group (repository is read-only)
2712 * EACCES - could not create property group (backend access denied)
2713 * EEXIST - could not create property group (already exists)
2714 * EINVAL - invalid property group name (error printed)
2715 * - invalid property name (error printed)
2716 * - invalid value (error printed)
2717 * EBUSY - new property group changed (error printed)
2718 */
2719 static int
lscf_import_service_pgs(scf_service_t * svc,const char * target_fmri,const entity_t * isvc,int flags)2720 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2721 const entity_t *isvc, int flags)
2722 {
2723 scf_callback_t cbdata;
2724
2725 cbdata.sc_handle = scf_service_handle(svc);
2726 cbdata.sc_parent = svc;
2727 cbdata.sc_service = 1;
2728 cbdata.sc_general = 0;
2729 cbdata.sc_enable = 0;
2730 cbdata.sc_flags = flags;
2731 cbdata.sc_source_fmri = isvc->sc_fmri;
2732 cbdata.sc_target_fmri = target_fmri;
2733
2734 /*
2735 * If the op is set, then add the flag to the callback
2736 * flags for later use.
2737 */
2738 if (isvc->sc_op != SVCCFG_OP_NONE) {
2739 switch (isvc->sc_op) {
2740 case SVCCFG_OP_IMPORT :
2741 cbdata.sc_flags |= SCI_OP_IMPORT;
2742 break;
2743 case SVCCFG_OP_APPLY :
2744 cbdata.sc_flags |= SCI_OP_APPLY;
2745 break;
2746 case SVCCFG_OP_RESTORE :
2747 cbdata.sc_flags |= SCI_OP_RESTORE;
2748 break;
2749 default :
2750 uu_die(gettext("lscf_import_service_pgs : "
2751 "Unknown op stored in the service entity\n"));
2752
2753 }
2754 }
2755
2756 if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2757 UU_DEFAULT) != 0) {
2758 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2759 bad_error("uu_list_walk", uu_error());
2760
2761 return (cbdata.sc_err);
2762 }
2763
2764 return (0);
2765 }
2766
2767 /*
2768 * Returns
2769 * 0 - success
2770 * ECONNABORTED - repository connection broken
2771 * ENOMEM - out of memory
2772 * ENOSPC - svc.configd is out of resources
2773 * ECANCELED - inst was deleted
2774 * EPERM - could not create property group (permission denied) (error printed)
2775 * - could not modify property group (permission denied) (error printed)
2776 * EROFS - could not create property group (repository is read-only)
2777 * EACCES - could not create property group (backend access denied)
2778 * EEXIST - could not create property group (already exists)
2779 * EINVAL - invalid property group name (error printed)
2780 * - invalid property name (error printed)
2781 * - invalid value (error printed)
2782 * EBUSY - new property group changed (error printed)
2783 */
2784 static int
lscf_import_instance_pgs(scf_instance_t * inst,const char * target_fmri,const entity_t * iinst,int flags)2785 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2786 const entity_t *iinst, int flags)
2787 {
2788 scf_callback_t cbdata;
2789
2790 cbdata.sc_handle = scf_instance_handle(inst);
2791 cbdata.sc_parent = inst;
2792 cbdata.sc_service = 0;
2793 cbdata.sc_general = NULL;
2794 cbdata.sc_enable = NULL;
2795 cbdata.sc_flags = flags;
2796 cbdata.sc_source_fmri = iinst->sc_fmri;
2797 cbdata.sc_target_fmri = target_fmri;
2798
2799 /*
2800 * If the op is set, then add the flag to the callback
2801 * flags for later use.
2802 */
2803 if (iinst->sc_op != SVCCFG_OP_NONE) {
2804 switch (iinst->sc_op) {
2805 case SVCCFG_OP_IMPORT :
2806 cbdata.sc_flags |= SCI_OP_IMPORT;
2807 break;
2808 case SVCCFG_OP_APPLY :
2809 cbdata.sc_flags |= SCI_OP_APPLY;
2810 break;
2811 case SVCCFG_OP_RESTORE :
2812 cbdata.sc_flags |= SCI_OP_RESTORE;
2813 break;
2814 default :
2815 uu_die(gettext("lscf_import_instance_pgs : "
2816 "Unknown op stored in the instance entity\n"));
2817 }
2818 }
2819
2820 if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2821 UU_DEFAULT) != 0) {
2822 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2823 bad_error("uu_list_walk", uu_error());
2824
2825 return (cbdata.sc_err);
2826 }
2827
2828 if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2829 cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2830 /*
2831 * If importing with the SCI_NOENABLED flag then
2832 * skip the delay, but if not then add the delay
2833 * of the enable property.
2834 */
2835 if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2836 cbdata.sc_flags |= SCI_DELAYENABLE;
2837 }
2838
2839 if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2840 != UU_WALK_NEXT)
2841 return (cbdata.sc_err);
2842 }
2843
2844 return (0);
2845 }
2846
2847 /*
2848 * Report the reasons why we can't upgrade pg2 to pg1.
2849 */
2850 static void
report_pg_diffs(const pgroup_t * pg1,const pgroup_t * pg2,const char * fmri,int new)2851 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2852 int new)
2853 {
2854 property_t *p1, *p2;
2855
2856 assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2857
2858 if (!pg_attrs_equal(pg1, pg2, fmri, new))
2859 return;
2860
2861 for (p1 = uu_list_first(pg1->sc_pgroup_props);
2862 p1 != NULL;
2863 p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2864 p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2865 if (p2 != NULL) {
2866 (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2867 new);
2868 continue;
2869 }
2870
2871 if (new)
2872 warn(gettext("Conflict upgrading %s (new property "
2873 "group \"%s\" is missing property \"%s\").\n"),
2874 fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2875 else
2876 warn(gettext("Conflict upgrading %s (property "
2877 "\"%s/%s\" is missing).\n"), fmri,
2878 pg1->sc_pgroup_name, p1->sc_property_name);
2879 }
2880
2881 /*
2882 * Since pg1 should be from the manifest, any properties in pg2 which
2883 * aren't in pg1 shouldn't be reported as conflicts.
2884 */
2885 }
2886
2887 /*
2888 * Add transaction entries to tx which will upgrade cur's pg according to old
2889 * & new.
2890 *
2891 * Returns
2892 * 0 - success
2893 * EINVAL - new has a property with an invalid name or value (message emitted)
2894 * ENOMEM - out of memory
2895 */
2896 static int
add_upgrade_entries(scf_transaction_t * tx,pgroup_t * old,pgroup_t * new,pgroup_t * cur,int speak,const char * fmri)2897 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2898 pgroup_t *cur, int speak, const char *fmri)
2899 {
2900 property_t *p, *new_p, *cur_p;
2901 scf_transaction_entry_t *e;
2902 int r;
2903 int is_general;
2904 int is_protected;
2905
2906 if (uu_list_walk(new->sc_pgroup_props, clear_int,
2907 (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2908 bad_error("uu_list_walk", uu_error());
2909
2910 is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2911
2912 for (p = uu_list_first(old->sc_pgroup_props);
2913 p != NULL;
2914 p = uu_list_next(old->sc_pgroup_props, p)) {
2915 /* p is a property in the old property group. */
2916
2917 /* Protect live properties. */
2918 is_protected = 0;
2919 if (is_general) {
2920 if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2921 0 ||
2922 strcmp(p->sc_property_name,
2923 SCF_PROPERTY_RESTARTER) == 0)
2924 is_protected = 1;
2925 }
2926
2927 /* Look for the same property in the new properties. */
2928 new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2929 if (new_p != NULL) {
2930 new_p->sc_seen = 1;
2931
2932 /*
2933 * If the new property is the same as the old, don't do
2934 * anything (leave any user customizations).
2935 */
2936 if (prop_equal(p, new_p, NULL, NULL, 0))
2937 continue;
2938
2939 if (new_p->sc_property_override)
2940 goto upgrade;
2941 }
2942
2943 cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2944 if (cur_p == NULL) {
2945 /*
2946 * p has been deleted from the repository. If we were
2947 * going to delete it anyway, do nothing. Otherwise
2948 * report a conflict.
2949 */
2950 if (new_p == NULL)
2951 continue;
2952
2953 if (is_protected)
2954 continue;
2955
2956 warn(gettext("Conflict upgrading %s "
2957 "(property \"%s/%s\" is missing).\n"), fmri,
2958 old->sc_pgroup_name, p->sc_property_name);
2959 continue;
2960 }
2961
2962 if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2963 /*
2964 * Conflict. Don't warn if the property is already the
2965 * way we want it, though.
2966 */
2967 if (is_protected)
2968 continue;
2969
2970 if (new_p == NULL)
2971 (void) prop_equal(p, cur_p, fmri,
2972 old->sc_pgroup_name, 0);
2973 else
2974 (void) prop_equal(cur_p, new_p, fmri,
2975 old->sc_pgroup_name, 0);
2976 continue;
2977 }
2978
2979 if (is_protected) {
2980 if (speak)
2981 warn(gettext("%s: Refusing to upgrade "
2982 "\"%s/%s\" (live property).\n"), fmri,
2983 old->sc_pgroup_name, p->sc_property_name);
2984 continue;
2985 }
2986
2987 upgrade:
2988 /* p hasn't been customized in the repository. Upgrade it. */
2989 if (new_p == NULL) {
2990 /* p was deleted. Delete from cur if unchanged. */
2991 if (speak)
2992 warn(gettext(
2993 "%s: Deleting property \"%s/%s\".\n"),
2994 fmri, old->sc_pgroup_name,
2995 p->sc_property_name);
2996
2997 e = scf_entry_create(g_hndl);
2998 if (e == NULL)
2999 return (ENOMEM);
3000
3001 if (scf_transaction_property_delete(tx, e,
3002 p->sc_property_name) != 0) {
3003 switch (scf_error()) {
3004 case SCF_ERROR_DELETED:
3005 scf_entry_destroy(e);
3006 return (ECANCELED);
3007
3008 case SCF_ERROR_CONNECTION_BROKEN:
3009 scf_entry_destroy(e);
3010 return (ECONNABORTED);
3011
3012 case SCF_ERROR_NOT_FOUND:
3013 /*
3014 * This can happen if cur is from the
3015 * running snapshot (and it differs
3016 * from the live properties).
3017 */
3018 scf_entry_destroy(e);
3019 break;
3020
3021 case SCF_ERROR_HANDLE_MISMATCH:
3022 case SCF_ERROR_NOT_BOUND:
3023 case SCF_ERROR_NOT_SET:
3024 case SCF_ERROR_INVALID_ARGUMENT:
3025 default:
3026 bad_error(
3027 "scf_transaction_property_delete",
3028 scf_error());
3029 }
3030 }
3031 } else {
3032 scf_callback_t ctx;
3033
3034 if (speak)
3035 warn(gettext(
3036 "%s: Upgrading property \"%s/%s\".\n"),
3037 fmri, old->sc_pgroup_name,
3038 p->sc_property_name);
3039
3040 ctx.sc_handle = g_hndl;
3041 ctx.sc_trans = tx;
3042 ctx.sc_flags = 0;
3043
3044 r = lscf_property_import(new_p, &ctx);
3045 if (r != UU_WALK_NEXT) {
3046 if (r != UU_WALK_ERROR)
3047 bad_error("lscf_property_import", r);
3048 return (EINVAL);
3049 }
3050 }
3051 }
3052
3053 /* Go over the properties which were added. */
3054 for (new_p = uu_list_first(new->sc_pgroup_props);
3055 new_p != NULL;
3056 new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
3057 if (new_p->sc_seen)
3058 continue;
3059
3060 /* This is a new property. */
3061 cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
3062 if (cur_p == NULL) {
3063 scf_callback_t ctx;
3064
3065 ctx.sc_handle = g_hndl;
3066 ctx.sc_trans = tx;
3067 ctx.sc_flags = 0;
3068
3069 r = lscf_property_import(new_p, &ctx);
3070 if (r != UU_WALK_NEXT) {
3071 if (r != UU_WALK_ERROR)
3072 bad_error("lscf_property_import", r);
3073 return (EINVAL);
3074 }
3075 continue;
3076 }
3077
3078 /*
3079 * Report a conflict if the new property differs from the
3080 * current one. Unless it's general/enabled, since that's
3081 * never in the last-import snapshot.
3082 */
3083 if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
3084 0 &&
3085 strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
3086 continue;
3087
3088 (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
3089 }
3090
3091 return (0);
3092 }
3093
3094 /*
3095 * Upgrade pg according to old & new.
3096 *
3097 * Returns
3098 * 0 - success
3099 * ECONNABORTED - repository connection broken
3100 * ENOMEM - out of memory
3101 * ENOSPC - svc.configd is out of resources
3102 * ECANCELED - pg was deleted
3103 * EPERM - couldn't modify pg (permission denied)
3104 * EROFS - couldn't modify pg (backend read-only)
3105 * EACCES - couldn't modify pg (backend access denied)
3106 * EINVAL - new has a property with invalid name or value (error printed)
3107 * EBUSY - pg changed unexpectedly
3108 */
3109 static int
upgrade_pg(scf_propertygroup_t * pg,pgroup_t * cur,pgroup_t * old,pgroup_t * new,int speak,const char * fmri)3110 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
3111 pgroup_t *new, int speak, const char *fmri)
3112 {
3113 int r;
3114
3115 if (scf_transaction_start(imp_tx, pg) != 0) {
3116 switch (scf_error()) {
3117 case SCF_ERROR_CONNECTION_BROKEN:
3118 case SCF_ERROR_DELETED:
3119 case SCF_ERROR_PERMISSION_DENIED:
3120 case SCF_ERROR_BACKEND_READONLY:
3121 case SCF_ERROR_BACKEND_ACCESS:
3122 return (scferror2errno(scf_error()));
3123
3124 case SCF_ERROR_HANDLE_MISMATCH:
3125 case SCF_ERROR_IN_USE:
3126 case SCF_ERROR_NOT_BOUND:
3127 case SCF_ERROR_NOT_SET:
3128 default:
3129 bad_error("scf_transaction_start", scf_error());
3130 }
3131 }
3132
3133 r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
3134 switch (r) {
3135 case 0:
3136 break;
3137
3138 case EINVAL:
3139 case ENOMEM:
3140 scf_transaction_destroy_children(imp_tx);
3141 return (r);
3142
3143 default:
3144 bad_error("add_upgrade_entries", r);
3145 }
3146
3147 r = scf_transaction_commit(imp_tx);
3148
3149 scf_transaction_destroy_children(imp_tx);
3150
3151 switch (r) {
3152 case 1:
3153 break;
3154
3155 case 0:
3156 return (EBUSY);
3157
3158 case -1:
3159 switch (scf_error()) {
3160 case SCF_ERROR_CONNECTION_BROKEN:
3161 case SCF_ERROR_NO_RESOURCES:
3162 case SCF_ERROR_PERMISSION_DENIED:
3163 case SCF_ERROR_BACKEND_READONLY:
3164 case SCF_ERROR_BACKEND_ACCESS:
3165 case SCF_ERROR_DELETED:
3166 return (scferror2errno(scf_error()));
3167
3168 case SCF_ERROR_NOT_BOUND:
3169 case SCF_ERROR_INVALID_ARGUMENT:
3170 case SCF_ERROR_NOT_SET:
3171 default:
3172 bad_error("scf_transaction_commit", scf_error());
3173 }
3174
3175 default:
3176 bad_error("scf_transaction_commit", r);
3177 }
3178
3179 return (0);
3180 }
3181
3182 /*
3183 * Compares two entity FMRIs. Returns
3184 *
3185 * 1 - equal
3186 * 0 - not equal
3187 * -1 - f1 is invalid or not an entity
3188 * -2 - f2 is invalid or not an entity
3189 */
3190 static int
fmri_equal(const char * f1,const char * f2)3191 fmri_equal(const char *f1, const char *f2)
3192 {
3193 int r;
3194 const char *s1, *i1, *pg1;
3195 const char *s2, *i2, *pg2;
3196
3197 if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3198 return (-1);
3199 if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
3200 return (-1);
3201
3202 if (s1 == NULL || pg1 != NULL)
3203 return (-1);
3204
3205 if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3206 return (-2);
3207 if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
3208 return (-2);
3209
3210 if (s2 == NULL || pg2 != NULL)
3211 return (-2);
3212
3213 r = strcmp(s1, s2);
3214 if (r != 0)
3215 return (0);
3216
3217 if (i1 == NULL && i2 == NULL)
3218 return (1);
3219
3220 if (i1 == NULL || i2 == NULL)
3221 return (0);
3222
3223 return (strcmp(i1, i2) == 0);
3224 }
3225
3226 /*
3227 * Import a dependent by creating a dependency property group in the dependent
3228 * entity. If lcbdata->sc_trans is set, assume it's been started on the
3229 * dependents pg, and add an entry to create a new property for this
3230 * dependent. Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3231 *
3232 * On success, returns UU_WALK_NEXT. On error, returns UU_WALK_ERROR and sets
3233 * lcbdata->sc_err to
3234 * ECONNABORTED - repository connection broken
3235 * ENOMEM - out of memory
3236 * ENOSPC - configd is out of resources
3237 * EINVAL - target is invalid (error printed)
3238 * - target is not an entity (error printed)
3239 * - dependent has invalid name (error printed)
3240 * - invalid property name (error printed)
3241 * - invalid value (error printed)
3242 * - scope of target does not exist (error printed)
3243 * EPERM - couldn't create target (permission denied) (error printed)
3244 * - couldn't create dependency pg (permission denied) (error printed)
3245 * - couldn't modify dependency pg (permission denied) (error printed)
3246 * EROFS - couldn't create target (repository read-only)
3247 * - couldn't create dependency pg (repository read-only)
3248 * EACCES - couldn't create target (backend access denied)
3249 * - couldn't create dependency pg (backend access denied)
3250 * ECANCELED - sc_trans's pg was deleted
3251 * EALREADY - property for dependent already exists in sc_trans's pg
3252 * EEXIST - dependency pg already exists in target (error printed)
3253 * EBUSY - target deleted (error printed)
3254 * - property group changed during import (error printed)
3255 */
3256 static int
lscf_dependent_import(void * a1,void * pvt)3257 lscf_dependent_import(void *a1, void *pvt)
3258 {
3259 pgroup_t *pgrp = a1;
3260 scf_callback_t *lcbdata = pvt;
3261
3262 int isservice;
3263 int ret;
3264 scf_transaction_entry_t *e;
3265 scf_value_t *val;
3266 scf_callback_t dependent_cbdata;
3267 scf_error_t scfe;
3268
3269 /*
3270 * Decode the FMRI into dependent_cbdata->sc_parent. Do it here so if
3271 * it's invalid, we fail before modifying the repository.
3272 */
3273 scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3274 &dependent_cbdata.sc_parent, &isservice);
3275 switch (scfe) {
3276 case SCF_ERROR_NONE:
3277 break;
3278
3279 case SCF_ERROR_NO_MEMORY:
3280 return (stash_scferror_err(lcbdata, scfe));
3281
3282 case SCF_ERROR_INVALID_ARGUMENT:
3283 semerr(gettext("The FMRI for the \"%s\" dependent is "
3284 "invalid.\n"), pgrp->sc_pgroup_name);
3285 return (stash_scferror_err(lcbdata, scfe));
3286
3287 case SCF_ERROR_CONSTRAINT_VIOLATED:
3288 semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3289 "specifies neither a service nor an instance.\n"),
3290 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3291 return (stash_scferror_err(lcbdata, scfe));
3292
3293 case SCF_ERROR_NOT_FOUND:
3294 scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3295 &dependent_cbdata.sc_parent, &isservice);
3296 switch (scfe) {
3297 case SCF_ERROR_NONE:
3298 break;
3299
3300 case SCF_ERROR_NO_MEMORY:
3301 case SCF_ERROR_BACKEND_READONLY:
3302 case SCF_ERROR_BACKEND_ACCESS:
3303 return (stash_scferror_err(lcbdata, scfe));
3304
3305 case SCF_ERROR_NOT_FOUND:
3306 semerr(gettext("The scope in FMRI \"%s\" for the "
3307 "\"%s\" dependent does not exist.\n"),
3308 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3309 lcbdata->sc_err = EINVAL;
3310 return (UU_WALK_ERROR);
3311
3312 case SCF_ERROR_PERMISSION_DENIED:
3313 warn(gettext(
3314 "Could not create %s (permission denied).\n"),
3315 pgrp->sc_pgroup_fmri);
3316 return (stash_scferror_err(lcbdata, scfe));
3317
3318 case SCF_ERROR_INVALID_ARGUMENT:
3319 case SCF_ERROR_CONSTRAINT_VIOLATED:
3320 default:
3321 bad_error("create_entity", scfe);
3322 }
3323 break;
3324
3325 default:
3326 bad_error("fmri_to_entity", scfe);
3327 }
3328
3329 if (lcbdata->sc_trans != NULL) {
3330 e = scf_entry_create(lcbdata->sc_handle);
3331 if (e == NULL) {
3332 if (scf_error() != SCF_ERROR_NO_MEMORY)
3333 bad_error("scf_entry_create", scf_error());
3334
3335 entity_destroy(dependent_cbdata.sc_parent, isservice);
3336 return (stash_scferror(lcbdata));
3337 }
3338
3339 if (scf_transaction_property_new(lcbdata->sc_trans, e,
3340 pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
3341 switch (scf_error()) {
3342 case SCF_ERROR_INVALID_ARGUMENT:
3343 warn(gettext("Dependent of %s has invalid name "
3344 "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
3345 pgrp->sc_pgroup_name);
3346 /* FALLTHROUGH */
3347
3348 case SCF_ERROR_DELETED:
3349 case SCF_ERROR_CONNECTION_BROKEN:
3350 scf_entry_destroy(e);
3351 entity_destroy(dependent_cbdata.sc_parent,
3352 isservice);
3353 return (stash_scferror(lcbdata));
3354
3355 case SCF_ERROR_EXISTS:
3356 scf_entry_destroy(e);
3357 entity_destroy(dependent_cbdata.sc_parent,
3358 isservice);
3359 lcbdata->sc_err = EALREADY;
3360 return (UU_WALK_ERROR);
3361
3362 case SCF_ERROR_NOT_BOUND:
3363 case SCF_ERROR_HANDLE_MISMATCH:
3364 case SCF_ERROR_NOT_SET:
3365 default:
3366 bad_error("scf_transaction_property_new",
3367 scf_error());
3368 }
3369 }
3370
3371 val = scf_value_create(lcbdata->sc_handle);
3372 if (val == NULL) {
3373 if (scf_error() != SCF_ERROR_NO_MEMORY)
3374 bad_error("scf_value_create", scf_error());
3375
3376 entity_destroy(dependent_cbdata.sc_parent, isservice);
3377 return (stash_scferror(lcbdata));
3378 }
3379
3380 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
3381 pgrp->sc_pgroup_fmri) != 0)
3382 /* invalid should have been caught above */
3383 bad_error("scf_value_set_from_string", scf_error());
3384
3385 if (scf_entry_add_value(e, val) != 0)
3386 bad_error("scf_entry_add_value", scf_error());
3387 }
3388
3389 /* Add the property group to the target entity. */
3390
3391 dependent_cbdata.sc_handle = lcbdata->sc_handle;
3392 dependent_cbdata.sc_flags = lcbdata->sc_flags;
3393 dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
3394 dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
3395
3396 ret = entity_pgroup_import(pgrp, &dependent_cbdata);
3397
3398 entity_destroy(dependent_cbdata.sc_parent, isservice);
3399
3400 if (ret == UU_WALK_NEXT)
3401 return (ret);
3402
3403 if (ret != UU_WALK_ERROR)
3404 bad_error("entity_pgroup_import", ret);
3405
3406 switch (dependent_cbdata.sc_err) {
3407 case ECANCELED:
3408 warn(gettext("%s deleted unexpectedly.\n"),
3409 pgrp->sc_pgroup_fmri);
3410 lcbdata->sc_err = EBUSY;
3411 break;
3412
3413 case EEXIST:
3414 warn(gettext("Could not create \"%s\" dependency in %s "
3415 "(already exists).\n"), pgrp->sc_pgroup_name,
3416 pgrp->sc_pgroup_fmri);
3417 /* FALLTHROUGH */
3418
3419 default:
3420 lcbdata->sc_err = dependent_cbdata.sc_err;
3421 }
3422
3423 return (UU_WALK_ERROR);
3424 }
3425
3426 static int upgrade_dependent(const scf_property_t *, const entity_t *,
3427 const scf_snaplevel_t *, scf_transaction_t *);
3428 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
3429 const pgroup_t *);
3430
3431 /*
3432 * Upgrade uncustomized dependents of ent to those specified in ient. Read
3433 * the current dependent targets from running (the snaplevel of a running
3434 * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3435 * scf_instance_t * according to ient, otherwise). Draw the ancestral
3436 * dependent targets and dependency properties from li_dpts_pg (the
3437 * "dependents" property group in snpl) and snpl (the snaplevel which
3438 * corresponds to ent in a last-import snapshot). If li_dpts_pg is NULL, then
3439 * snpl doesn't have a "dependents" property group, and any dependents in ient
3440 * are new.
3441 *
3442 * Returns
3443 * 0 - success
3444 * ECONNABORTED - repository connection broken
3445 * ENOMEM - out of memory
3446 * ENOSPC - configd is out of resources
3447 * ECANCELED - ent was deleted
3448 * ENODEV - the entity containing li_dpts_pg was deleted
3449 * EPERM - could not modify dependents pg (permission denied) (error printed)
3450 * - couldn't upgrade dependent (permission denied) (error printed)
3451 * - couldn't create dependent (permission denied) (error printed)
3452 * EROFS - could not modify dependents pg (repository read-only)
3453 * - couldn't upgrade dependent (repository read-only)
3454 * - couldn't create dependent (repository read-only)
3455 * EACCES - could not modify dependents pg (backend access denied)
3456 * - could not upgrade dependent (backend access denied)
3457 * - could not create dependent (backend access denied)
3458 * EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3459 * - dependent target deleted (error printed)
3460 * - dependent pg changed (error printed)
3461 * EINVAL - new dependent is invalid (error printed)
3462 * EBADF - snpl is corrupt (error printed)
3463 * - snpl has corrupt pg (error printed)
3464 * - dependency pg in target is corrupt (error printed)
3465 * - target has corrupt snapshot (error printed)
3466 * EEXIST - dependency pg already existed in target service (error printed)
3467 */
3468 static int
upgrade_dependents(const scf_propertygroup_t * li_dpts_pg,const scf_snaplevel_t * snpl,const entity_t * ient,const scf_snaplevel_t * running,void * ent)3469 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
3470 const scf_snaplevel_t *snpl, const entity_t *ient,
3471 const scf_snaplevel_t *running, void *ent)
3472 {
3473 pgroup_t *new_dpt_pgroup;
3474 scf_callback_t cbdata;
3475 int r, unseen, tx_started = 0;
3476 int have_cur_depts;
3477
3478 const char * const dependents = "dependents";
3479
3480 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3481
3482 if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
3483 /* Nothing to do. */
3484 return (0);
3485
3486 /* Fetch the current version of the "dependents" property group. */
3487 have_cur_depts = 1;
3488 if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
3489 switch (scf_error()) {
3490 case SCF_ERROR_NOT_FOUND:
3491 break;
3492
3493 case SCF_ERROR_DELETED:
3494 case SCF_ERROR_CONNECTION_BROKEN:
3495 return (scferror2errno(scf_error()));
3496
3497 case SCF_ERROR_NOT_SET:
3498 case SCF_ERROR_INVALID_ARGUMENT:
3499 case SCF_ERROR_HANDLE_MISMATCH:
3500 case SCF_ERROR_NOT_BOUND:
3501 default:
3502 bad_error("entity_get_pg", scf_error());
3503 }
3504
3505 have_cur_depts = 0;
3506 }
3507
3508 /* Fetch the running version of the "dependents" property group. */
3509 ud_run_dpts_pg_set = 0;
3510 if (running != NULL)
3511 r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
3512 else
3513 r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
3514 if (r == 0) {
3515 ud_run_dpts_pg_set = 1;
3516 } else {
3517 switch (scf_error()) {
3518 case SCF_ERROR_NOT_FOUND:
3519 break;
3520
3521 case SCF_ERROR_DELETED:
3522 case SCF_ERROR_CONNECTION_BROKEN:
3523 return (scferror2errno(scf_error()));
3524
3525 case SCF_ERROR_NOT_SET:
3526 case SCF_ERROR_INVALID_ARGUMENT:
3527 case SCF_ERROR_HANDLE_MISMATCH:
3528 case SCF_ERROR_NOT_BOUND:
3529 default:
3530 bad_error(running ? "scf_snaplevel_get_pg" :
3531 "entity_get_pg", scf_error());
3532 }
3533 }
3534
3535 /*
3536 * Clear the seen fields of the dependents, so we can tell which ones
3537 * are new.
3538 */
3539 if (uu_list_walk(ient->sc_dependents, clear_int,
3540 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3541 bad_error("uu_list_walk", uu_error());
3542
3543 if (li_dpts_pg != NULL) {
3544 /*
3545 * Each property in li_dpts_pg represents a dependent tag in
3546 * the old manifest. For each, call upgrade_dependent(),
3547 * which will change ud_cur_depts_pg or dependencies in other
3548 * services as appropriate. Note (a) that changes to
3549 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3550 * made en masse, and (b) it's ok if the entity doesn't have
3551 * a current version of the "dependents" property group,
3552 * because we'll just consider all dependents as customized
3553 * (by being deleted).
3554 */
3555
3556 if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3557 switch (scf_error()) {
3558 case SCF_ERROR_DELETED:
3559 return (ENODEV);
3560
3561 case SCF_ERROR_CONNECTION_BROKEN:
3562 return (ECONNABORTED);
3563
3564 case SCF_ERROR_HANDLE_MISMATCH:
3565 case SCF_ERROR_NOT_BOUND:
3566 case SCF_ERROR_NOT_SET:
3567 default:
3568 bad_error("scf_iter_pg_properties",
3569 scf_error());
3570 }
3571 }
3572
3573 if (have_cur_depts &&
3574 scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3575 switch (scf_error()) {
3576 case SCF_ERROR_BACKEND_ACCESS:
3577 case SCF_ERROR_BACKEND_READONLY:
3578 case SCF_ERROR_CONNECTION_BROKEN:
3579 return (scferror2errno(scf_error()));
3580
3581 case SCF_ERROR_DELETED:
3582 warn(emsg_pg_deleted, ient->sc_fmri,
3583 dependents);
3584 return (EBUSY);
3585
3586 case SCF_ERROR_PERMISSION_DENIED:
3587 warn(emsg_pg_mod_perm, dependents,
3588 ient->sc_fmri);
3589 return (scferror2errno(scf_error()));
3590
3591 case SCF_ERROR_HANDLE_MISMATCH:
3592 case SCF_ERROR_IN_USE:
3593 case SCF_ERROR_NOT_BOUND:
3594 case SCF_ERROR_NOT_SET:
3595 default:
3596 bad_error("scf_transaction_start", scf_error());
3597 }
3598 }
3599 tx_started = have_cur_depts;
3600
3601 for (;;) {
3602 r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3603 if (r == 0)
3604 break;
3605 if (r == 1) {
3606 r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3607 tx_started ? ud_tx : NULL);
3608 switch (r) {
3609 case 0:
3610 continue;
3611
3612 case ECONNABORTED:
3613 case ENOMEM:
3614 case ENOSPC:
3615 case EBADF:
3616 case EBUSY:
3617 case EINVAL:
3618 case EPERM:
3619 case EROFS:
3620 case EACCES:
3621 case EEXIST:
3622 break;
3623
3624 case ECANCELED:
3625 r = ENODEV;
3626 break;
3627
3628 default:
3629 bad_error("upgrade_dependent", r);
3630 }
3631
3632 if (tx_started)
3633 scf_transaction_destroy_children(ud_tx);
3634 return (r);
3635 }
3636 if (r != -1)
3637 bad_error("scf_iter_next_property", r);
3638
3639 switch (scf_error()) {
3640 case SCF_ERROR_DELETED:
3641 r = ENODEV;
3642 break;
3643
3644 case SCF_ERROR_CONNECTION_BROKEN:
3645 r = ECONNABORTED;
3646 break;
3647
3648 case SCF_ERROR_NOT_SET:
3649 case SCF_ERROR_INVALID_ARGUMENT:
3650 case SCF_ERROR_NOT_BOUND:
3651 case SCF_ERROR_HANDLE_MISMATCH:
3652 default:
3653 bad_error("scf_iter_next_property",
3654 scf_error());
3655 }
3656
3657 if (tx_started)
3658 scf_transaction_destroy_children(ud_tx);
3659 return (r);
3660 }
3661 }
3662
3663 /* import unseen dependents */
3664 unseen = 0;
3665 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3666 new_dpt_pgroup != NULL;
3667 new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3668 new_dpt_pgroup)) {
3669 if (!new_dpt_pgroup->sc_pgroup_seen) {
3670 unseen = 1;
3671 break;
3672 }
3673 }
3674
3675 /* If there are none, exit early. */
3676 if (unseen == 0)
3677 goto commit;
3678
3679 /* Set up for lscf_dependent_import() */
3680 cbdata.sc_handle = g_hndl;
3681 cbdata.sc_parent = ent;
3682 cbdata.sc_service = issvc;
3683 cbdata.sc_flags = 0;
3684
3685 if (!have_cur_depts) {
3686 /*
3687 * We have new dependents to import, so we need a "dependents"
3688 * property group.
3689 */
3690 if (issvc)
3691 r = scf_service_add_pg(ent, dependents,
3692 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3693 else
3694 r = scf_instance_add_pg(ent, dependents,
3695 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3696 if (r != 0) {
3697 switch (scf_error()) {
3698 case SCF_ERROR_DELETED:
3699 case SCF_ERROR_CONNECTION_BROKEN:
3700 case SCF_ERROR_BACKEND_READONLY:
3701 case SCF_ERROR_BACKEND_ACCESS:
3702 case SCF_ERROR_NO_RESOURCES:
3703 return (scferror2errno(scf_error()));
3704
3705 case SCF_ERROR_EXISTS:
3706 warn(emsg_pg_added, ient->sc_fmri, dependents);
3707 return (EBUSY);
3708
3709 case SCF_ERROR_PERMISSION_DENIED:
3710 warn(emsg_pg_add_perm, dependents,
3711 ient->sc_fmri);
3712 return (scferror2errno(scf_error()));
3713
3714 case SCF_ERROR_NOT_BOUND:
3715 case SCF_ERROR_HANDLE_MISMATCH:
3716 case SCF_ERROR_INVALID_ARGUMENT:
3717 case SCF_ERROR_NOT_SET:
3718 default:
3719 bad_error("scf_service_add_pg", scf_error());
3720 }
3721 }
3722 }
3723
3724 cbdata.sc_trans = ud_tx;
3725
3726 if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3727 switch (scf_error()) {
3728 case SCF_ERROR_CONNECTION_BROKEN:
3729 case SCF_ERROR_BACKEND_ACCESS:
3730 case SCF_ERROR_BACKEND_READONLY:
3731 return (scferror2errno(scf_error()));
3732
3733 case SCF_ERROR_DELETED:
3734 warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3735 return (EBUSY);
3736
3737 case SCF_ERROR_PERMISSION_DENIED:
3738 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3739 return (scferror2errno(scf_error()));
3740
3741 case SCF_ERROR_HANDLE_MISMATCH:
3742 case SCF_ERROR_IN_USE:
3743 case SCF_ERROR_NOT_BOUND:
3744 case SCF_ERROR_NOT_SET:
3745 default:
3746 bad_error("scf_transaction_start", scf_error());
3747 }
3748 }
3749 tx_started = 1;
3750
3751 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3752 new_dpt_pgroup != NULL;
3753 new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3754 new_dpt_pgroup)) {
3755 if (new_dpt_pgroup->sc_pgroup_seen)
3756 continue;
3757
3758 if (ud_run_dpts_pg_set) {
3759 /*
3760 * If the dependent is already there, then we have
3761 * a conflict.
3762 */
3763 if (scf_pg_get_property(ud_run_dpts_pg,
3764 new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3765 r = handle_dependent_conflict(ient, ud_prop,
3766 new_dpt_pgroup);
3767 switch (r) {
3768 case 0:
3769 continue;
3770
3771 case ECONNABORTED:
3772 case ENOMEM:
3773 case EBUSY:
3774 case EBADF:
3775 case EINVAL:
3776 scf_transaction_destroy_children(ud_tx);
3777 return (r);
3778
3779 default:
3780 bad_error("handle_dependent_conflict",
3781 r);
3782 }
3783 } else {
3784 switch (scf_error()) {
3785 case SCF_ERROR_NOT_FOUND:
3786 break;
3787
3788 case SCF_ERROR_INVALID_ARGUMENT:
3789 warn(emsg_fmri_invalid_pg_name,
3790 ient->sc_fmri,
3791 new_dpt_pgroup->sc_pgroup_name);
3792 scf_transaction_destroy_children(ud_tx);
3793 return (EINVAL);
3794
3795 case SCF_ERROR_DELETED:
3796 warn(emsg_pg_deleted, ient->sc_fmri,
3797 new_dpt_pgroup->sc_pgroup_name);
3798 scf_transaction_destroy_children(ud_tx);
3799 return (EBUSY);
3800
3801 case SCF_ERROR_CONNECTION_BROKEN:
3802 scf_transaction_destroy_children(ud_tx);
3803 return (ECONNABORTED);
3804
3805 case SCF_ERROR_NOT_BOUND:
3806 case SCF_ERROR_HANDLE_MISMATCH:
3807 case SCF_ERROR_NOT_SET:
3808 default:
3809 bad_error("scf_pg_get_property",
3810 scf_error());
3811 }
3812 }
3813 }
3814
3815 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3816 if (r != UU_WALK_NEXT) {
3817 if (r != UU_WALK_ERROR)
3818 bad_error("lscf_dependent_import", r);
3819
3820 if (cbdata.sc_err == EALREADY) {
3821 /* Collisions were handled preemptively. */
3822 bad_error("lscf_dependent_import",
3823 cbdata.sc_err);
3824 }
3825
3826 scf_transaction_destroy_children(ud_tx);
3827 return (cbdata.sc_err);
3828 }
3829 }
3830
3831 commit:
3832 if (!tx_started)
3833 return (0);
3834
3835 r = scf_transaction_commit(ud_tx);
3836
3837 scf_transaction_destroy_children(ud_tx);
3838
3839 switch (r) {
3840 case 1:
3841 return (0);
3842
3843 case 0:
3844 warn(emsg_pg_changed, ient->sc_fmri, dependents);
3845 return (EBUSY);
3846
3847 case -1:
3848 break;
3849
3850 default:
3851 bad_error("scf_transaction_commit", r);
3852 }
3853
3854 switch (scf_error()) {
3855 case SCF_ERROR_CONNECTION_BROKEN:
3856 case SCF_ERROR_BACKEND_READONLY:
3857 case SCF_ERROR_BACKEND_ACCESS:
3858 case SCF_ERROR_NO_RESOURCES:
3859 return (scferror2errno(scf_error()));
3860
3861 case SCF_ERROR_DELETED:
3862 warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3863 return (EBUSY);
3864
3865 case SCF_ERROR_PERMISSION_DENIED:
3866 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3867 return (scferror2errno(scf_error()));
3868
3869 case SCF_ERROR_NOT_BOUND:
3870 case SCF_ERROR_INVALID_ARGUMENT:
3871 case SCF_ERROR_NOT_SET:
3872 default:
3873 bad_error("scf_transaction_destroy", scf_error());
3874 /* NOTREACHED */
3875 }
3876 }
3877
3878 /*
3879 * Used to add the manifests to the list of currently supported manifests.
3880 * We can modify the existing manifest list removing entries if the files
3881 * don't exist.
3882 *
3883 * Get the old list and the new file name
3884 * If the new file name is in the list return
3885 * If not then add the file to the list.
3886 * As we process the list check to see if the files in the old list exist
3887 * if not then remove the file from the list.
3888 * Commit the list of manifest file names.
3889 *
3890 */
3891 static int
upgrade_manifestfiles(pgroup_t * pg,const entity_t * ient,const scf_snaplevel_t * running,void * ent)3892 upgrade_manifestfiles(pgroup_t *pg, const entity_t *ient,
3893 const scf_snaplevel_t *running, void *ent)
3894 {
3895 scf_propertygroup_t *ud_mfsts_pg = NULL;
3896 scf_property_t *ud_prop = NULL;
3897 scf_iter_t *ud_prop_iter;
3898 scf_value_t *fname_value;
3899 scf_callback_t cbdata;
3900 pgroup_t *mfst_pgroup;
3901 property_t *mfst_prop;
3902 property_t *old_prop;
3903 char *pname = malloc(MAXPATHLEN);
3904 char *fval = NULL;
3905 char *old_pname;
3906 char *old_fval;
3907 int no_upgrade_pg;
3908 int mfst_seen;
3909 int r;
3910
3911 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3912
3913 /*
3914 * This should always be the service base on the code
3915 * path, and the fact that the manifests pg is a service
3916 * level property group only.
3917 */
3918 ud_mfsts_pg = scf_pg_create(g_hndl);
3919 ud_prop = scf_property_create(g_hndl);
3920 ud_prop_iter = scf_iter_create(g_hndl);
3921 fname_value = scf_value_create(g_hndl);
3922
3923 /* Fetch the "manifests" property group */
3924 no_upgrade_pg = 0;
3925 r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3926 ud_mfsts_pg);
3927 if (r != 0) {
3928 switch (scf_error()) {
3929 case SCF_ERROR_NOT_FOUND:
3930 no_upgrade_pg = 1;
3931 break;
3932
3933 case SCF_ERROR_DELETED:
3934 case SCF_ERROR_CONNECTION_BROKEN:
3935 return (scferror2errno(scf_error()));
3936
3937 case SCF_ERROR_NOT_SET:
3938 case SCF_ERROR_INVALID_ARGUMENT:
3939 case SCF_ERROR_HANDLE_MISMATCH:
3940 case SCF_ERROR_NOT_BOUND:
3941 default:
3942 bad_error(running ? "scf_snaplevel_get_pg" :
3943 "entity_get_pg", scf_error());
3944 }
3945 }
3946
3947 if (no_upgrade_pg) {
3948 cbdata.sc_handle = g_hndl;
3949 cbdata.sc_parent = ent;
3950 cbdata.sc_service = issvc;
3951 cbdata.sc_flags = SCI_FORCE;
3952 cbdata.sc_source_fmri = ient->sc_fmri;
3953 cbdata.sc_target_fmri = ient->sc_fmri;
3954
3955 if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3956 return (cbdata.sc_err);
3957
3958 return (0);
3959 }
3960
3961 /* Fetch the new manifests property group */
3962 for (mfst_pgroup = uu_list_first(ient->sc_pgroups);
3963 mfst_pgroup != NULL;
3964 mfst_pgroup = uu_list_next(ient->sc_pgroups, mfst_pgroup)) {
3965 if (strcmp(mfst_pgroup->sc_pgroup_name,
3966 SCF_PG_MANIFESTFILES) == 0)
3967 break;
3968 }
3969
3970 if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3971 SCF_SUCCESS)
3972 return (-1);
3973
3974 while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
3975 mfst_seen = 0;
3976 if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
3977 continue;
3978
3979 for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
3980 mfst_prop != NULL;
3981 mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
3982 mfst_prop)) {
3983 if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
3984 mfst_seen = 1;
3985 }
3986 }
3987
3988 /*
3989 * If the manifest is not seen then add it to the new mfst
3990 * property list to get proccessed into the repo.
3991 */
3992 if (mfst_seen == 0) {
3993 if (fval == NULL)
3994 fval = malloc(MAXPATHLEN);
3995
3996 /*
3997 * If we cannot get the value then there is no
3998 * reason to attempt to attach the value to
3999 * the property group
4000 */
4001 if (fval != NULL &&
4002 prop_get_val(ud_prop, fname_value) == 0 &&
4003 scf_value_get_astring(fname_value, fval,
4004 MAXPATHLEN) != -1) {
4005 old_pname = safe_strdup(pname);
4006 old_fval = safe_strdup(fval);
4007 old_prop = internal_property_create(old_pname,
4008 SCF_TYPE_ASTRING, 1, old_fval);
4009
4010 /*
4011 * Already checked to see if the property exists
4012 * in the group, and it does not.
4013 */
4014 (void) internal_attach_property(mfst_pgroup,
4015 old_prop);
4016 }
4017 }
4018 }
4019 free(fval);
4020
4021 cbdata.sc_handle = g_hndl;
4022 cbdata.sc_parent = ent;
4023 cbdata.sc_service = issvc;
4024 cbdata.sc_flags = SCI_FORCE;
4025 cbdata.sc_source_fmri = ient->sc_fmri;
4026 cbdata.sc_target_fmri = ient->sc_fmri;
4027
4028 if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
4029 return (cbdata.sc_err);
4030
4031 return (r);
4032 }
4033
4034 /*
4035 * prop is taken to be a property in the "dependents" property group of snpl,
4036 * which is taken to be the snaplevel of a last-import snapshot corresponding
4037 * to ient. If prop is a valid dependents property, upgrade the dependent it
4038 * represents according to the repository & ient. If ud_run_dpts_pg_set is
4039 * true, then ud_run_dpts_pg is taken to be the "dependents" property group
4040 * of the entity ient represents (possibly in the running snapshot). If it
4041 * needs to be changed, an entry will be added to tx, if not NULL.
4042 *
4043 * Returns
4044 * 0 - success
4045 * ECONNABORTED - repository connection broken
4046 * ENOMEM - out of memory
4047 * ENOSPC - configd was out of resources
4048 * ECANCELED - snpl's entity was deleted
4049 * EINVAL - dependent target is invalid (error printed)
4050 * - dependent is invalid (error printed)
4051 * EBADF - snpl is corrupt (error printed)
4052 * - snpl has corrupt pg (error printed)
4053 * - dependency pg in target is corrupt (error printed)
4054 * - running snapshot in dependent is missing snaplevel (error printed)
4055 * EPERM - couldn't delete dependency pg (permission denied) (error printed)
4056 * - couldn't create dependent (permission denied) (error printed)
4057 * - couldn't modify dependent pg (permission denied) (error printed)
4058 * EROFS - couldn't delete dependency pg (repository read-only)
4059 * - couldn't create dependent (repository read-only)
4060 * EACCES - couldn't delete dependency pg (backend access denied)
4061 * - couldn't create dependent (backend access denied)
4062 * EBUSY - ud_run_dpts_pg was deleted (error printed)
4063 * - tx's pg was deleted (error printed)
4064 * - dependent pg was changed or deleted (error printed)
4065 * EEXIST - dependency pg already exists in new target (error printed)
4066 */
4067 static int
upgrade_dependent(const scf_property_t * prop,const entity_t * ient,const scf_snaplevel_t * snpl,scf_transaction_t * tx)4068 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
4069 const scf_snaplevel_t *snpl, scf_transaction_t *tx)
4070 {
4071 pgroup_t pgrp;
4072 scf_type_t ty;
4073 pgroup_t *new_dpt_pgroup;
4074 pgroup_t *old_dpt_pgroup = NULL;
4075 pgroup_t *current_pg;
4076 pgroup_t *dpt;
4077 scf_callback_t cbdata;
4078 int tissvc;
4079 void *target_ent;
4080 scf_error_t serr;
4081 int r;
4082 scf_transaction_entry_t *ent;
4083
4084 const char * const cf_inval = gettext("Conflict upgrading %s "
4085 "(dependent \"%s\" has invalid dependents property).\n");
4086 const char * const cf_missing = gettext("Conflict upgrading %s "
4087 "(dependent \"%s\" is missing).\n");
4088 const char * const cf_newdpg = gettext("Conflict upgrading %s "
4089 "(dependent \"%s\" has new dependency property group).\n");
4090 const char * const cf_newtarg = gettext("Conflict upgrading %s "
4091 "(dependent \"%s\" has new target).\n");
4092 const char * const li_corrupt =
4093 gettext("%s: \"last-import\" snapshot is corrupt.\n");
4094 const char * const upgrading =
4095 gettext("%s: Upgrading dependent \"%s\".\n");
4096 const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
4097 "corrupt (missing snaplevel).\n");
4098
4099 if (scf_property_type(prop, &ty) != 0) {
4100 switch (scf_error()) {
4101 case SCF_ERROR_DELETED:
4102 case SCF_ERROR_CONNECTION_BROKEN:
4103 return (scferror2errno(scf_error()));
4104
4105 case SCF_ERROR_NOT_BOUND:
4106 case SCF_ERROR_NOT_SET:
4107 default:
4108 bad_error("scf_property_type", scf_error());
4109 }
4110 }
4111
4112 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4113 warn(li_corrupt, ient->sc_fmri);
4114 return (EBADF);
4115 }
4116
4117 /*
4118 * prop represents a dependent in the old manifest. It is named after
4119 * the dependent.
4120 */
4121 if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
4122 switch (scf_error()) {
4123 case SCF_ERROR_DELETED:
4124 case SCF_ERROR_CONNECTION_BROKEN:
4125 return (scferror2errno(scf_error()));
4126
4127 case SCF_ERROR_NOT_BOUND:
4128 case SCF_ERROR_NOT_SET:
4129 default:
4130 bad_error("scf_property_get_name", scf_error());
4131 }
4132 }
4133
4134 /* See if it's in the new manifest. */
4135 pgrp.sc_pgroup_name = ud_name;
4136 new_dpt_pgroup =
4137 uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
4138
4139 /* If it's not, delete it... if it hasn't been customized. */
4140 if (new_dpt_pgroup == NULL) {
4141 if (!ud_run_dpts_pg_set)
4142 return (0);
4143
4144 if (scf_property_get_value(prop, ud_val) != 0) {
4145 switch (scf_error()) {
4146 case SCF_ERROR_NOT_FOUND:
4147 case SCF_ERROR_CONSTRAINT_VIOLATED:
4148 warn(li_corrupt, ient->sc_fmri);
4149 return (EBADF);
4150
4151 case SCF_ERROR_DELETED:
4152 case SCF_ERROR_CONNECTION_BROKEN:
4153 return (scferror2errno(scf_error()));
4154
4155 case SCF_ERROR_HANDLE_MISMATCH:
4156 case SCF_ERROR_NOT_BOUND:
4157 case SCF_ERROR_NOT_SET:
4158 case SCF_ERROR_PERMISSION_DENIED:
4159 default:
4160 bad_error("scf_property_get_value",
4161 scf_error());
4162 }
4163 }
4164
4165 if (scf_value_get_as_string(ud_val, ud_oldtarg,
4166 max_scf_value_len + 1) < 0)
4167 bad_error("scf_value_get_as_string", scf_error());
4168
4169 if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
4170 0) {
4171 switch (scf_error()) {
4172 case SCF_ERROR_NOT_FOUND:
4173 return (0);
4174
4175 case SCF_ERROR_CONNECTION_BROKEN:
4176 return (scferror2errno(scf_error()));
4177
4178 case SCF_ERROR_DELETED:
4179 warn(emsg_pg_deleted, ient->sc_fmri,
4180 "dependents");
4181 return (EBUSY);
4182
4183 case SCF_ERROR_INVALID_ARGUMENT:
4184 case SCF_ERROR_NOT_BOUND:
4185 case SCF_ERROR_HANDLE_MISMATCH:
4186 case SCF_ERROR_NOT_SET:
4187 default:
4188 bad_error("scf_pg_get_property", scf_error());
4189 }
4190 }
4191 if (scf_property_get_value(ud_prop, ud_val) != 0) {
4192 switch (scf_error()) {
4193 case SCF_ERROR_NOT_FOUND:
4194 case SCF_ERROR_CONSTRAINT_VIOLATED:
4195 warn(cf_inval, ient->sc_fmri, ud_name);
4196 return (0);
4197
4198 case SCF_ERROR_DELETED:
4199 case SCF_ERROR_CONNECTION_BROKEN:
4200 return (scferror2errno(scf_error()));
4201
4202 case SCF_ERROR_HANDLE_MISMATCH:
4203 case SCF_ERROR_NOT_BOUND:
4204 case SCF_ERROR_NOT_SET:
4205 case SCF_ERROR_PERMISSION_DENIED:
4206 default:
4207 bad_error("scf_property_get_value",
4208 scf_error());
4209 }
4210 }
4211
4212 ty = scf_value_type(ud_val);
4213 assert(ty != SCF_TYPE_INVALID);
4214 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4215 warn(cf_inval, ient->sc_fmri, ud_name);
4216 return (0);
4217 }
4218
4219 if (scf_value_get_as_string(ud_val, ud_ctarg,
4220 max_scf_value_len + 1) < 0)
4221 bad_error("scf_value_get_as_string", scf_error());
4222
4223 r = fmri_equal(ud_ctarg, ud_oldtarg);
4224 switch (r) {
4225 case 1:
4226 break;
4227
4228 case 0:
4229 case -1: /* warn? */
4230 warn(cf_newtarg, ient->sc_fmri, ud_name);
4231 return (0);
4232
4233 case -2:
4234 warn(li_corrupt, ient->sc_fmri);
4235 return (EBADF);
4236
4237 default:
4238 bad_error("fmri_equal", r);
4239 }
4240
4241 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4242 switch (scf_error()) {
4243 case SCF_ERROR_NOT_FOUND:
4244 warn(li_corrupt, ient->sc_fmri);
4245 return (EBADF);
4246
4247 case SCF_ERROR_DELETED:
4248 case SCF_ERROR_CONNECTION_BROKEN:
4249 return (scferror2errno(scf_error()));
4250
4251 case SCF_ERROR_NOT_BOUND:
4252 case SCF_ERROR_HANDLE_MISMATCH:
4253 case SCF_ERROR_INVALID_ARGUMENT:
4254 case SCF_ERROR_NOT_SET:
4255 default:
4256 bad_error("scf_snaplevel_get_pg", scf_error());
4257 }
4258 }
4259
4260 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4261 snap_lastimport);
4262 switch (r) {
4263 case 0:
4264 break;
4265
4266 case ECANCELED:
4267 case ECONNABORTED:
4268 case ENOMEM:
4269 case EBADF:
4270 return (r);
4271
4272 case EACCES:
4273 default:
4274 bad_error("load_pg", r);
4275 }
4276
4277 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4278 switch (serr) {
4279 case SCF_ERROR_NONE:
4280 break;
4281
4282 case SCF_ERROR_NO_MEMORY:
4283 internal_pgroup_free(old_dpt_pgroup);
4284 return (ENOMEM);
4285
4286 case SCF_ERROR_NOT_FOUND:
4287 internal_pgroup_free(old_dpt_pgroup);
4288 goto delprop;
4289
4290 case SCF_ERROR_CONSTRAINT_VIOLATED: /* caught above */
4291 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
4292 default:
4293 bad_error("fmri_to_entity", serr);
4294 }
4295
4296 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4297 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4298 switch (r) {
4299 case 0:
4300 break;
4301
4302 case ECONNABORTED:
4303 internal_pgroup_free(old_dpt_pgroup);
4304 return (r);
4305
4306 case ECANCELED:
4307 case ENOENT:
4308 internal_pgroup_free(old_dpt_pgroup);
4309 goto delprop;
4310
4311 case EBADF:
4312 warn(r_no_lvl, ud_ctarg);
4313 internal_pgroup_free(old_dpt_pgroup);
4314 return (r);
4315
4316 case EINVAL:
4317 default:
4318 bad_error("entity_get_running_pg", r);
4319 }
4320
4321 /* load it */
4322 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4323 switch (r) {
4324 case 0:
4325 break;
4326
4327 case ECANCELED:
4328 internal_pgroup_free(old_dpt_pgroup);
4329 goto delprop;
4330
4331 case ECONNABORTED:
4332 case ENOMEM:
4333 case EBADF:
4334 internal_pgroup_free(old_dpt_pgroup);
4335 return (r);
4336
4337 case EACCES:
4338 default:
4339 bad_error("load_pg", r);
4340 }
4341
4342 /* compare property groups */
4343 if (!pg_equal(old_dpt_pgroup, current_pg)) {
4344 warn(cf_newdpg, ient->sc_fmri, ud_name);
4345 internal_pgroup_free(old_dpt_pgroup);
4346 internal_pgroup_free(current_pg);
4347 return (0);
4348 }
4349
4350 internal_pgroup_free(old_dpt_pgroup);
4351 internal_pgroup_free(current_pg);
4352
4353 if (g_verbose)
4354 warn(gettext("%s: Deleting dependent \"%s\".\n"),
4355 ient->sc_fmri, ud_name);
4356
4357 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4358 switch (scf_error()) {
4359 case SCF_ERROR_NOT_FOUND:
4360 case SCF_ERROR_DELETED:
4361 internal_pgroup_free(old_dpt_pgroup);
4362 goto delprop;
4363
4364 case SCF_ERROR_CONNECTION_BROKEN:
4365 internal_pgroup_free(old_dpt_pgroup);
4366 return (ECONNABORTED);
4367
4368 case SCF_ERROR_NOT_SET:
4369 case SCF_ERROR_INVALID_ARGUMENT:
4370 case SCF_ERROR_HANDLE_MISMATCH:
4371 case SCF_ERROR_NOT_BOUND:
4372 default:
4373 bad_error("entity_get_pg", scf_error());
4374 }
4375 }
4376
4377 if (scf_pg_delete(ud_pg) != 0) {
4378 switch (scf_error()) {
4379 case SCF_ERROR_DELETED:
4380 break;
4381
4382 case SCF_ERROR_CONNECTION_BROKEN:
4383 case SCF_ERROR_BACKEND_READONLY:
4384 case SCF_ERROR_BACKEND_ACCESS:
4385 return (scferror2errno(scf_error()));
4386
4387 case SCF_ERROR_PERMISSION_DENIED:
4388 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4389 return (scferror2errno(scf_error()));
4390
4391 case SCF_ERROR_NOT_SET:
4392 default:
4393 bad_error("scf_pg_delete", scf_error());
4394 }
4395 }
4396
4397 /*
4398 * This service was changed, so it must be refreshed. But
4399 * since it's not mentioned in the new manifest, we have to
4400 * record its FMRI here for use later. We record the name
4401 * & the entity (via sc_parent) in case we need to print error
4402 * messages during the refresh.
4403 */
4404 dpt = internal_pgroup_new();
4405 if (dpt == NULL)
4406 return (ENOMEM);
4407 dpt->sc_pgroup_name = strdup(ud_name);
4408 dpt->sc_pgroup_fmri = strdup(ud_ctarg);
4409 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4410 return (ENOMEM);
4411 dpt->sc_parent = (entity_t *)ient;
4412 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4413 uu_die(gettext("libuutil error: %s\n"),
4414 uu_strerror(uu_error()));
4415
4416 delprop:
4417 if (tx == NULL)
4418 return (0);
4419
4420 ent = scf_entry_create(g_hndl);
4421 if (ent == NULL)
4422 return (ENOMEM);
4423
4424 if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
4425 scf_entry_destroy(ent);
4426 switch (scf_error()) {
4427 case SCF_ERROR_DELETED:
4428 warn(emsg_pg_deleted, ient->sc_fmri,
4429 "dependents");
4430 return (EBUSY);
4431
4432 case SCF_ERROR_CONNECTION_BROKEN:
4433 return (scferror2errno(scf_error()));
4434
4435 case SCF_ERROR_NOT_FOUND:
4436 break;
4437
4438 case SCF_ERROR_HANDLE_MISMATCH:
4439 case SCF_ERROR_NOT_BOUND:
4440 case SCF_ERROR_INVALID_ARGUMENT:
4441 case SCF_ERROR_NOT_SET:
4442 default:
4443 bad_error("scf_transaction_property_delete",
4444 scf_error());
4445 }
4446 }
4447
4448 return (0);
4449 }
4450
4451 new_dpt_pgroup->sc_pgroup_seen = 1;
4452
4453 /*
4454 * Decide whether the dependent has changed in the manifest.
4455 */
4456 /* Compare the target. */
4457 if (scf_property_get_value(prop, ud_val) != 0) {
4458 switch (scf_error()) {
4459 case SCF_ERROR_NOT_FOUND:
4460 case SCF_ERROR_CONSTRAINT_VIOLATED:
4461 warn(li_corrupt, ient->sc_fmri);
4462 return (EBADF);
4463
4464 case SCF_ERROR_DELETED:
4465 case SCF_ERROR_CONNECTION_BROKEN:
4466 return (scferror2errno(scf_error()));
4467
4468 case SCF_ERROR_HANDLE_MISMATCH:
4469 case SCF_ERROR_NOT_BOUND:
4470 case SCF_ERROR_NOT_SET:
4471 case SCF_ERROR_PERMISSION_DENIED:
4472 default:
4473 bad_error("scf_property_get_value", scf_error());
4474 }
4475 }
4476
4477 if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
4478 0)
4479 bad_error("scf_value_get_as_string", scf_error());
4480
4481 /*
4482 * If the fmri's are not equal then the old fmri will need to
4483 * be refreshed to ensure that the changes are properly updated
4484 * in that service.
4485 */
4486 r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
4487 switch (r) {
4488 case 0:
4489 dpt = internal_pgroup_new();
4490 if (dpt == NULL)
4491 return (ENOMEM);
4492 dpt->sc_pgroup_name = strdup(ud_name);
4493 dpt->sc_pgroup_fmri = strdup(ud_oldtarg);
4494 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4495 return (ENOMEM);
4496 dpt->sc_parent = (entity_t *)ient;
4497 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4498 uu_die(gettext("libuutil error: %s\n"),
4499 uu_strerror(uu_error()));
4500 break;
4501
4502 case 1:
4503 /* Compare the dependency pgs. */
4504 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4505 switch (scf_error()) {
4506 case SCF_ERROR_NOT_FOUND:
4507 warn(li_corrupt, ient->sc_fmri);
4508 return (EBADF);
4509
4510 case SCF_ERROR_DELETED:
4511 case SCF_ERROR_CONNECTION_BROKEN:
4512 return (scferror2errno(scf_error()));
4513
4514 case SCF_ERROR_NOT_BOUND:
4515 case SCF_ERROR_HANDLE_MISMATCH:
4516 case SCF_ERROR_INVALID_ARGUMENT:
4517 case SCF_ERROR_NOT_SET:
4518 default:
4519 bad_error("scf_snaplevel_get_pg", scf_error());
4520 }
4521 }
4522
4523 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4524 snap_lastimport);
4525 switch (r) {
4526 case 0:
4527 break;
4528
4529 case ECANCELED:
4530 case ECONNABORTED:
4531 case ENOMEM:
4532 case EBADF:
4533 return (r);
4534
4535 case EACCES:
4536 default:
4537 bad_error("load_pg", r);
4538 }
4539
4540 if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4541 /* no change, leave customizations */
4542 internal_pgroup_free(old_dpt_pgroup);
4543 return (0);
4544 }
4545 break;
4546
4547 case -1:
4548 warn(li_corrupt, ient->sc_fmri);
4549 return (EBADF);
4550
4551 case -2:
4552 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4553 ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4554 return (EINVAL);
4555
4556 default:
4557 bad_error("fmri_equal", r);
4558 }
4559
4560 /*
4561 * The dependent has changed in the manifest. Upgrade the current
4562 * properties if they haven't been customized.
4563 */
4564
4565 /*
4566 * If new_dpt_pgroup->sc_override, then act as though the property
4567 * group hasn't been customized.
4568 */
4569 if (new_dpt_pgroup->sc_pgroup_override) {
4570 (void) strcpy(ud_ctarg, ud_oldtarg);
4571 goto nocust;
4572 }
4573
4574 if (!ud_run_dpts_pg_set) {
4575 warn(cf_missing, ient->sc_fmri, ud_name);
4576 r = 0;
4577 goto out;
4578 } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4579 switch (scf_error()) {
4580 case SCF_ERROR_NOT_FOUND:
4581 warn(cf_missing, ient->sc_fmri, ud_name);
4582 r = 0;
4583 goto out;
4584
4585 case SCF_ERROR_CONNECTION_BROKEN:
4586 r = scferror2errno(scf_error());
4587 goto out;
4588
4589 case SCF_ERROR_DELETED:
4590 warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4591 r = EBUSY;
4592 goto out;
4593
4594 case SCF_ERROR_INVALID_ARGUMENT:
4595 case SCF_ERROR_NOT_BOUND:
4596 case SCF_ERROR_HANDLE_MISMATCH:
4597 case SCF_ERROR_NOT_SET:
4598 default:
4599 bad_error("scf_pg_get_property", scf_error());
4600 }
4601 }
4602
4603 if (scf_property_get_value(ud_prop, ud_val) != 0) {
4604 switch (scf_error()) {
4605 case SCF_ERROR_NOT_FOUND:
4606 case SCF_ERROR_CONSTRAINT_VIOLATED:
4607 warn(cf_inval, ient->sc_fmri, ud_name);
4608 r = 0;
4609 goto out;
4610
4611 case SCF_ERROR_DELETED:
4612 case SCF_ERROR_CONNECTION_BROKEN:
4613 r = scferror2errno(scf_error());
4614 goto out;
4615
4616 case SCF_ERROR_HANDLE_MISMATCH:
4617 case SCF_ERROR_NOT_BOUND:
4618 case SCF_ERROR_NOT_SET:
4619 case SCF_ERROR_PERMISSION_DENIED:
4620 default:
4621 bad_error("scf_property_get_value", scf_error());
4622 }
4623 }
4624
4625 ty = scf_value_type(ud_val);
4626 assert(ty != SCF_TYPE_INVALID);
4627 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4628 warn(cf_inval, ient->sc_fmri, ud_name);
4629 r = 0;
4630 goto out;
4631 }
4632 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4633 0)
4634 bad_error("scf_value_get_as_string", scf_error());
4635
4636 r = fmri_equal(ud_ctarg, ud_oldtarg);
4637 if (r == -1) {
4638 warn(cf_inval, ient->sc_fmri, ud_name);
4639 r = 0;
4640 goto out;
4641 } else if (r == -2) {
4642 warn(li_corrupt, ient->sc_fmri);
4643 r = EBADF;
4644 goto out;
4645 } else if (r == 0) {
4646 /*
4647 * Target has been changed. Only abort now if it's been
4648 * changed to something other than what's in the manifest.
4649 */
4650 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4651 if (r == -1) {
4652 warn(cf_inval, ient->sc_fmri, ud_name);
4653 r = 0;
4654 goto out;
4655 } else if (r == 0) {
4656 warn(cf_newtarg, ient->sc_fmri, ud_name);
4657 r = 0;
4658 goto out;
4659 } else if (r != 1) {
4660 /* invalid sc_pgroup_fmri caught above */
4661 bad_error("fmri_equal", r);
4662 }
4663
4664 /*
4665 * Fetch the current dependency pg. If it's what the manifest
4666 * says, then no problem.
4667 */
4668 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4669 switch (serr) {
4670 case SCF_ERROR_NONE:
4671 break;
4672
4673 case SCF_ERROR_NOT_FOUND:
4674 warn(cf_missing, ient->sc_fmri, ud_name);
4675 r = 0;
4676 goto out;
4677
4678 case SCF_ERROR_NO_MEMORY:
4679 r = ENOMEM;
4680 goto out;
4681
4682 case SCF_ERROR_CONSTRAINT_VIOLATED:
4683 case SCF_ERROR_INVALID_ARGUMENT:
4684 default:
4685 bad_error("fmri_to_entity", serr);
4686 }
4687
4688 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4689 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4690 switch (r) {
4691 case 0:
4692 break;
4693
4694 case ECONNABORTED:
4695 goto out;
4696
4697 case ECANCELED:
4698 case ENOENT:
4699 warn(cf_missing, ient->sc_fmri, ud_name);
4700 r = 0;
4701 goto out;
4702
4703 case EBADF:
4704 warn(r_no_lvl, ud_ctarg);
4705 goto out;
4706
4707 case EINVAL:
4708 default:
4709 bad_error("entity_get_running_pg", r);
4710 }
4711
4712 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4713 switch (r) {
4714 case 0:
4715 break;
4716
4717 case ECANCELED:
4718 warn(cf_missing, ient->sc_fmri, ud_name);
4719 r = 0;
4720 goto out;
4721
4722 case ECONNABORTED:
4723 case ENOMEM:
4724 case EBADF:
4725 goto out;
4726
4727 case EACCES:
4728 default:
4729 bad_error("load_pg", r);
4730 }
4731
4732 if (!pg_equal(current_pg, new_dpt_pgroup))
4733 warn(cf_newdpg, ient->sc_fmri, ud_name);
4734 internal_pgroup_free(current_pg);
4735 r = 0;
4736 goto out;
4737 } else if (r != 1) {
4738 bad_error("fmri_equal", r);
4739 }
4740
4741 nocust:
4742 /*
4743 * Target has not been customized. Check the dependency property
4744 * group.
4745 */
4746
4747 if (old_dpt_pgroup == NULL) {
4748 if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4749 ud_pg) != 0) {
4750 switch (scf_error()) {
4751 case SCF_ERROR_NOT_FOUND:
4752 warn(li_corrupt, ient->sc_fmri);
4753 return (EBADF);
4754
4755 case SCF_ERROR_DELETED:
4756 case SCF_ERROR_CONNECTION_BROKEN:
4757 return (scferror2errno(scf_error()));
4758
4759 case SCF_ERROR_NOT_BOUND:
4760 case SCF_ERROR_HANDLE_MISMATCH:
4761 case SCF_ERROR_INVALID_ARGUMENT:
4762 case SCF_ERROR_NOT_SET:
4763 default:
4764 bad_error("scf_snaplevel_get_pg", scf_error());
4765 }
4766 }
4767
4768 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4769 snap_lastimport);
4770 switch (r) {
4771 case 0:
4772 break;
4773
4774 case ECANCELED:
4775 case ECONNABORTED:
4776 case ENOMEM:
4777 case EBADF:
4778 return (r);
4779
4780 case EACCES:
4781 default:
4782 bad_error("load_pg", r);
4783 }
4784 }
4785 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4786 switch (serr) {
4787 case SCF_ERROR_NONE:
4788 break;
4789
4790 case SCF_ERROR_NOT_FOUND:
4791 warn(cf_missing, ient->sc_fmri, ud_name);
4792 r = 0;
4793 goto out;
4794
4795 case SCF_ERROR_NO_MEMORY:
4796 r = ENOMEM;
4797 goto out;
4798
4799 case SCF_ERROR_CONSTRAINT_VIOLATED:
4800 case SCF_ERROR_INVALID_ARGUMENT:
4801 default:
4802 bad_error("fmri_to_entity", serr);
4803 }
4804
4805 r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4806 ud_iter2, ud_inst, imp_snap, ud_snpl);
4807 switch (r) {
4808 case 0:
4809 break;
4810
4811 case ECONNABORTED:
4812 goto out;
4813
4814 case ECANCELED:
4815 case ENOENT:
4816 warn(cf_missing, ient->sc_fmri, ud_name);
4817 r = 0;
4818 goto out;
4819
4820 case EBADF:
4821 warn(r_no_lvl, ud_ctarg);
4822 goto out;
4823
4824 case EINVAL:
4825 default:
4826 bad_error("entity_get_running_pg", r);
4827 }
4828
4829 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4830 switch (r) {
4831 case 0:
4832 break;
4833
4834 case ECANCELED:
4835 warn(cf_missing, ient->sc_fmri, ud_name);
4836 goto out;
4837
4838 case ECONNABORTED:
4839 case ENOMEM:
4840 case EBADF:
4841 goto out;
4842
4843 case EACCES:
4844 default:
4845 bad_error("load_pg", r);
4846 }
4847
4848 if (!pg_equal(current_pg, old_dpt_pgroup)) {
4849 if (!pg_equal(current_pg, new_dpt_pgroup))
4850 warn(cf_newdpg, ient->sc_fmri, ud_name);
4851 internal_pgroup_free(current_pg);
4852 r = 0;
4853 goto out;
4854 }
4855
4856 /* Uncustomized. Upgrade. */
4857
4858 r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4859 switch (r) {
4860 case 1:
4861 if (pg_equal(current_pg, new_dpt_pgroup)) {
4862 /* Already upgraded. */
4863 internal_pgroup_free(current_pg);
4864 r = 0;
4865 goto out;
4866 }
4867
4868 internal_pgroup_free(current_pg);
4869
4870 /* upgrade current_pg */
4871 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4872 switch (scf_error()) {
4873 case SCF_ERROR_CONNECTION_BROKEN:
4874 r = scferror2errno(scf_error());
4875 goto out;
4876
4877 case SCF_ERROR_DELETED:
4878 warn(cf_missing, ient->sc_fmri, ud_name);
4879 r = 0;
4880 goto out;
4881
4882 case SCF_ERROR_NOT_FOUND:
4883 break;
4884
4885 case SCF_ERROR_INVALID_ARGUMENT:
4886 case SCF_ERROR_NOT_BOUND:
4887 case SCF_ERROR_NOT_SET:
4888 case SCF_ERROR_HANDLE_MISMATCH:
4889 default:
4890 bad_error("entity_get_pg", scf_error());
4891 }
4892
4893 if (tissvc)
4894 r = scf_service_add_pg(target_ent, ud_name,
4895 SCF_GROUP_DEPENDENCY, 0, ud_pg);
4896 else
4897 r = scf_instance_add_pg(target_ent, ud_name,
4898 SCF_GROUP_DEPENDENCY, 0, ud_pg);
4899 if (r != 0) {
4900 switch (scf_error()) {
4901 case SCF_ERROR_CONNECTION_BROKEN:
4902 case SCF_ERROR_NO_RESOURCES:
4903 case SCF_ERROR_BACKEND_READONLY:
4904 case SCF_ERROR_BACKEND_ACCESS:
4905 r = scferror2errno(scf_error());
4906 goto out;
4907
4908 case SCF_ERROR_DELETED:
4909 warn(cf_missing, ient->sc_fmri,
4910 ud_name);
4911 r = 0;
4912 goto out;
4913
4914 case SCF_ERROR_PERMISSION_DENIED:
4915 warn(emsg_pg_deleted, ud_ctarg,
4916 ud_name);
4917 r = EPERM;
4918 goto out;
4919
4920 case SCF_ERROR_EXISTS:
4921 warn(emsg_pg_added, ud_ctarg, ud_name);
4922 r = EBUSY;
4923 goto out;
4924
4925 case SCF_ERROR_NOT_BOUND:
4926 case SCF_ERROR_HANDLE_MISMATCH:
4927 case SCF_ERROR_INVALID_ARGUMENT:
4928 case SCF_ERROR_NOT_SET:
4929 default:
4930 bad_error("entity_add_pg", scf_error());
4931 }
4932 }
4933 }
4934
4935 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4936 switch (r) {
4937 case 0:
4938 break;
4939
4940 case ECANCELED:
4941 warn(cf_missing, ient->sc_fmri, ud_name);
4942 goto out;
4943
4944 case ECONNABORTED:
4945 case ENOMEM:
4946 case EBADF:
4947 goto out;
4948
4949 case EACCES:
4950 default:
4951 bad_error("load_pg", r);
4952 }
4953
4954 if (g_verbose)
4955 warn(upgrading, ient->sc_fmri, ud_name);
4956
4957 r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4958 new_dpt_pgroup, 0, ient->sc_fmri);
4959 switch (r) {
4960 case 0:
4961 break;
4962
4963 case ECANCELED:
4964 warn(emsg_pg_deleted, ud_ctarg, ud_name);
4965 r = EBUSY;
4966 goto out;
4967
4968 case EPERM:
4969 warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4970 goto out;
4971
4972 case EBUSY:
4973 warn(emsg_pg_changed, ud_ctarg, ud_name);
4974 goto out;
4975
4976 case ECONNABORTED:
4977 case ENOMEM:
4978 case ENOSPC:
4979 case EROFS:
4980 case EACCES:
4981 case EINVAL:
4982 goto out;
4983
4984 default:
4985 bad_error("upgrade_pg", r);
4986 }
4987 break;
4988
4989 case 0: {
4990 scf_transaction_entry_t *ent;
4991 scf_value_t *val;
4992
4993 internal_pgroup_free(current_pg);
4994
4995 /* delete old pg */
4996 if (g_verbose)
4997 warn(upgrading, ient->sc_fmri, ud_name);
4998
4999 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
5000 switch (scf_error()) {
5001 case SCF_ERROR_CONNECTION_BROKEN:
5002 r = scferror2errno(scf_error());
5003 goto out;
5004
5005 case SCF_ERROR_DELETED:
5006 warn(cf_missing, ient->sc_fmri, ud_name);
5007 r = 0;
5008 goto out;
5009
5010 case SCF_ERROR_NOT_FOUND:
5011 break;
5012
5013 case SCF_ERROR_INVALID_ARGUMENT:
5014 case SCF_ERROR_NOT_BOUND:
5015 case SCF_ERROR_NOT_SET:
5016 case SCF_ERROR_HANDLE_MISMATCH:
5017 default:
5018 bad_error("entity_get_pg", scf_error());
5019 }
5020 } else if (scf_pg_delete(ud_pg) != 0) {
5021 switch (scf_error()) {
5022 case SCF_ERROR_DELETED:
5023 break;
5024
5025 case SCF_ERROR_CONNECTION_BROKEN:
5026 case SCF_ERROR_BACKEND_READONLY:
5027 case SCF_ERROR_BACKEND_ACCESS:
5028 r = scferror2errno(scf_error());
5029 goto out;
5030
5031 case SCF_ERROR_PERMISSION_DENIED:
5032 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
5033 r = scferror2errno(scf_error());
5034 goto out;
5035
5036 case SCF_ERROR_NOT_SET:
5037 default:
5038 bad_error("scf_pg_delete", scf_error());
5039 }
5040 }
5041
5042 /* import new one */
5043 cbdata.sc_handle = g_hndl;
5044 cbdata.sc_trans = NULL; /* handled below */
5045 cbdata.sc_flags = 0;
5046
5047 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
5048 if (r != UU_WALK_NEXT) {
5049 if (r != UU_WALK_ERROR)
5050 bad_error("lscf_dependent_import", r);
5051
5052 r = cbdata.sc_err;
5053 goto out;
5054 }
5055
5056 if (tx == NULL)
5057 break;
5058
5059 if ((ent = scf_entry_create(g_hndl)) == NULL ||
5060 (val = scf_value_create(g_hndl)) == NULL) {
5061 if (scf_error() == SCF_ERROR_NO_MEMORY)
5062 return (ENOMEM);
5063
5064 bad_error("scf_entry_create", scf_error());
5065 }
5066
5067 if (scf_transaction_property_change_type(tx, ent, ud_name,
5068 SCF_TYPE_FMRI) != 0) {
5069 switch (scf_error()) {
5070 case SCF_ERROR_CONNECTION_BROKEN:
5071 r = scferror2errno(scf_error());
5072 goto out;
5073
5074 case SCF_ERROR_DELETED:
5075 warn(emsg_pg_deleted, ient->sc_fmri,
5076 "dependents");
5077 r = EBUSY;
5078 goto out;
5079
5080 case SCF_ERROR_NOT_FOUND:
5081 break;
5082
5083 case SCF_ERROR_NOT_BOUND:
5084 case SCF_ERROR_HANDLE_MISMATCH:
5085 case SCF_ERROR_INVALID_ARGUMENT:
5086 case SCF_ERROR_NOT_SET:
5087 default:
5088 bad_error("scf_transaction_property_"
5089 "change_type", scf_error());
5090 }
5091
5092 if (scf_transaction_property_new(tx, ent, ud_name,
5093 SCF_TYPE_FMRI) != 0) {
5094 switch (scf_error()) {
5095 case SCF_ERROR_CONNECTION_BROKEN:
5096 r = scferror2errno(scf_error());
5097 goto out;
5098
5099 case SCF_ERROR_DELETED:
5100 warn(emsg_pg_deleted, ient->sc_fmri,
5101 "dependents");
5102 r = EBUSY;
5103 goto out;
5104
5105 case SCF_ERROR_EXISTS:
5106 warn(emsg_pg_changed, ient->sc_fmri,
5107 "dependents");
5108 r = EBUSY;
5109 goto out;
5110
5111 case SCF_ERROR_INVALID_ARGUMENT:
5112 case SCF_ERROR_HANDLE_MISMATCH:
5113 case SCF_ERROR_NOT_BOUND:
5114 case SCF_ERROR_NOT_SET:
5115 default:
5116 bad_error("scf_transaction_property_"
5117 "new", scf_error());
5118 }
5119 }
5120 }
5121
5122 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
5123 new_dpt_pgroup->sc_pgroup_fmri) != 0)
5124 /* invalid sc_pgroup_fmri caught above */
5125 bad_error("scf_value_set_from_string",
5126 scf_error());
5127
5128 if (scf_entry_add_value(ent, val) != 0)
5129 bad_error("scf_entry_add_value", scf_error());
5130 break;
5131 }
5132
5133 case -2:
5134 warn(li_corrupt, ient->sc_fmri);
5135 internal_pgroup_free(current_pg);
5136 r = EBADF;
5137 goto out;
5138
5139 case -1:
5140 default:
5141 /* invalid sc_pgroup_fmri caught above */
5142 bad_error("fmri_equal", r);
5143 }
5144
5145 r = 0;
5146
5147 out:
5148 if (old_dpt_pgroup != NULL)
5149 internal_pgroup_free(old_dpt_pgroup);
5150
5151 return (r);
5152 }
5153
5154 /*
5155 * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
5156 * would import it, except it seems to exist in the service anyway. Compare
5157 * the existent dependent with the one we would import, and report any
5158 * differences (if there are none, be silent). prop is the property which
5159 * represents the existent dependent (in the dependents property group) in the
5160 * entity corresponding to ient.
5161 *
5162 * Returns
5163 * 0 - success (Sort of. At least, we can continue importing.)
5164 * ECONNABORTED - repository connection broken
5165 * EBUSY - ancestor of prop was deleted (error printed)
5166 * ENOMEM - out of memory
5167 * EBADF - corrupt property group (error printed)
5168 * EINVAL - new_dpt_pgroup has invalid target (error printed)
5169 */
5170 static int
handle_dependent_conflict(const entity_t * const ient,const scf_property_t * const prop,const pgroup_t * const new_dpt_pgroup)5171 handle_dependent_conflict(const entity_t * const ient,
5172 const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
5173 {
5174 int r;
5175 scf_type_t ty;
5176 scf_error_t scfe;
5177 void *tptr;
5178 int tissvc;
5179 pgroup_t *pgroup;
5180
5181 if (scf_property_get_value(prop, ud_val) != 0) {
5182 switch (scf_error()) {
5183 case SCF_ERROR_CONNECTION_BROKEN:
5184 return (scferror2errno(scf_error()));
5185
5186 case SCF_ERROR_DELETED:
5187 warn(emsg_pg_deleted, ient->sc_fmri,
5188 new_dpt_pgroup->sc_pgroup_name);
5189 return (EBUSY);
5190
5191 case SCF_ERROR_CONSTRAINT_VIOLATED:
5192 case SCF_ERROR_NOT_FOUND:
5193 warn(gettext("Conflict upgrading %s (not importing "
5194 "dependent \"%s\" because it already exists.) "
5195 "Warning: The \"%s/%2$s\" property has more or "
5196 "fewer than one value)).\n"), ient->sc_fmri,
5197 new_dpt_pgroup->sc_pgroup_name, "dependents");
5198 return (0);
5199
5200 case SCF_ERROR_HANDLE_MISMATCH:
5201 case SCF_ERROR_NOT_BOUND:
5202 case SCF_ERROR_NOT_SET:
5203 case SCF_ERROR_PERMISSION_DENIED:
5204 default:
5205 bad_error("scf_property_get_value",
5206 scf_error());
5207 }
5208 }
5209
5210 ty = scf_value_type(ud_val);
5211 assert(ty != SCF_TYPE_INVALID);
5212 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
5213 warn(gettext("Conflict upgrading %s (not importing dependent "
5214 "\"%s\" because it already exists). Warning: The "
5215 "\"%s/%s\" property has unexpected type \"%s\")).\n"),
5216 ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
5217 scf_type_to_string(ty), "dependents");
5218 return (0);
5219 }
5220
5221 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
5222 0)
5223 bad_error("scf_value_get_as_string", scf_error());
5224
5225 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
5226 switch (r) {
5227 case 0:
5228 warn(gettext("Conflict upgrading %s (not importing dependent "
5229 "\"%s\" (target \"%s\") because it already exists with "
5230 "target \"%s\").\n"), ient->sc_fmri,
5231 new_dpt_pgroup->sc_pgroup_name,
5232 new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
5233 return (0);
5234
5235 case 1:
5236 break;
5237
5238 case -1:
5239 warn(gettext("Conflict upgrading %s (not importing dependent "
5240 "\"%s\" because it already exists). Warning: The current "
5241 "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
5242 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5243 return (0);
5244
5245 case -2:
5246 warn(gettext("Dependent \"%s\" of %s has invalid target "
5247 "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
5248 new_dpt_pgroup->sc_pgroup_fmri);
5249 return (EINVAL);
5250
5251 default:
5252 bad_error("fmri_equal", r);
5253 }
5254
5255 /* compare dependency pgs in target */
5256 scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
5257 switch (scfe) {
5258 case SCF_ERROR_NONE:
5259 break;
5260
5261 case SCF_ERROR_NO_MEMORY:
5262 return (ENOMEM);
5263
5264 case SCF_ERROR_NOT_FOUND:
5265 warn(emsg_dpt_dangling, ient->sc_fmri,
5266 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5267 return (0);
5268
5269 case SCF_ERROR_CONSTRAINT_VIOLATED:
5270 case SCF_ERROR_INVALID_ARGUMENT:
5271 default:
5272 bad_error("fmri_to_entity", scfe);
5273 }
5274
5275 r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
5276 ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
5277 switch (r) {
5278 case 0:
5279 break;
5280
5281 case ECONNABORTED:
5282 return (r);
5283
5284 case ECANCELED:
5285 warn(emsg_dpt_dangling, ient->sc_fmri,
5286 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5287 return (0);
5288
5289 case EBADF:
5290 if (tissvc)
5291 warn(gettext("%s has an instance with a \"%s\" "
5292 "snapshot which is missing a snaplevel.\n"),
5293 ud_ctarg, "running");
5294 else
5295 warn(gettext("%s has a \"%s\" snapshot which is "
5296 "missing a snaplevel.\n"), ud_ctarg, "running");
5297 /* FALLTHROUGH */
5298
5299 case ENOENT:
5300 warn(emsg_dpt_no_dep, ient->sc_fmri,
5301 new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5302 new_dpt_pgroup->sc_pgroup_name);
5303 return (0);
5304
5305 case EINVAL:
5306 default:
5307 bad_error("entity_get_running_pg", r);
5308 }
5309
5310 pgroup = internal_pgroup_new();
5311 if (pgroup == NULL)
5312 return (ENOMEM);
5313
5314 r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
5315 switch (r) {
5316 case 0:
5317 break;
5318
5319 case ECONNABORTED:
5320 case EBADF:
5321 case ENOMEM:
5322 internal_pgroup_free(pgroup);
5323 return (r);
5324
5325 case ECANCELED:
5326 warn(emsg_dpt_no_dep, ient->sc_fmri,
5327 new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5328 new_dpt_pgroup->sc_pgroup_name);
5329 internal_pgroup_free(pgroup);
5330 return (0);
5331
5332 case EACCES:
5333 default:
5334 bad_error("load_pg", r);
5335 }
5336
5337 /* report differences */
5338 report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
5339 internal_pgroup_free(pgroup);
5340 return (0);
5341 }
5342
5343 /*
5344 * lipg is a property group in the last-import snapshot of ent, which is an
5345 * scf_service_t or an scf_instance_t (according to ient). If lipg is not in
5346 * ient's pgroups, delete it from ent if it hasn't been customized. If it is
5347 * in ents's property groups, compare and upgrade ent appropriately.
5348 *
5349 * Returns
5350 * 0 - success
5351 * ECONNABORTED - repository connection broken
5352 * ENOMEM - out of memory
5353 * ENOSPC - configd is out of resources
5354 * EINVAL - ient has invalid dependent (error printed)
5355 * - ient has invalid pgroup_t (error printed)
5356 * ECANCELED - ent has been deleted
5357 * ENODEV - entity containing lipg has been deleted
5358 * - entity containing running has been deleted
5359 * EPERM - could not delete pg (permission denied) (error printed)
5360 * - couldn't upgrade dependents (permission denied) (error printed)
5361 * - couldn't import pg (permission denied) (error printed)
5362 * - couldn't upgrade pg (permission denied) (error printed)
5363 * EROFS - could not delete pg (repository read-only)
5364 * - couldn't upgrade dependents (repository read-only)
5365 * - couldn't import pg (repository read-only)
5366 * - couldn't upgrade pg (repository read-only)
5367 * EACCES - could not delete pg (backend access denied)
5368 * - couldn't upgrade dependents (backend access denied)
5369 * - couldn't import pg (backend access denied)
5370 * - couldn't upgrade pg (backend access denied)
5371 * - couldn't read property (backend access denied)
5372 * EBUSY - property group was added (error printed)
5373 * - property group was deleted (error printed)
5374 * - property group changed (error printed)
5375 * - "dependents" pg was added, changed, or deleted (error printed)
5376 * - dependent target deleted (error printed)
5377 * - dependent pg changed (error printed)
5378 * EBADF - imp_snpl is corrupt (error printed)
5379 * - ent has bad pg (error printed)
5380 * EEXIST - dependent collision in target service (error printed)
5381 */
5382 static int
process_old_pg(const scf_propertygroup_t * lipg,entity_t * ient,void * ent,const scf_snaplevel_t * running)5383 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
5384 const scf_snaplevel_t *running)
5385 {
5386 int r;
5387 pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
5388 scf_callback_t cbdata;
5389
5390 const char * const cf_pg_missing =
5391 gettext("Conflict upgrading %s (property group %s is missing)\n");
5392 const char * const deleting =
5393 gettext("%s: Deleting property group \"%s\".\n");
5394
5395 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5396
5397 /* Skip dependent property groups. */
5398 if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
5399 switch (scf_error()) {
5400 case SCF_ERROR_DELETED:
5401 return (ENODEV);
5402
5403 case SCF_ERROR_CONNECTION_BROKEN:
5404 return (ECONNABORTED);
5405
5406 case SCF_ERROR_NOT_SET:
5407 case SCF_ERROR_NOT_BOUND:
5408 default:
5409 bad_error("scf_pg_get_type", scf_error());
5410 }
5411 }
5412
5413 if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
5414 if (scf_pg_get_property(lipg, "external", NULL) == 0)
5415 return (0);
5416
5417 switch (scf_error()) {
5418 case SCF_ERROR_NOT_FOUND:
5419 break;
5420
5421 case SCF_ERROR_CONNECTION_BROKEN:
5422 return (ECONNABORTED);
5423
5424 case SCF_ERROR_DELETED:
5425 return (ENODEV);
5426
5427 case SCF_ERROR_INVALID_ARGUMENT:
5428 case SCF_ERROR_NOT_BOUND:
5429 case SCF_ERROR_HANDLE_MISMATCH:
5430 case SCF_ERROR_NOT_SET:
5431 default:
5432 bad_error("scf_pg_get_property", scf_error());
5433 }
5434 }
5435
5436 /* lookup pg in new properties */
5437 if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
5438 switch (scf_error()) {
5439 case SCF_ERROR_DELETED:
5440 return (ENODEV);
5441
5442 case SCF_ERROR_CONNECTION_BROKEN:
5443 return (ECONNABORTED);
5444
5445 case SCF_ERROR_NOT_SET:
5446 case SCF_ERROR_NOT_BOUND:
5447 default:
5448 bad_error("scf_pg_get_name", scf_error());
5449 }
5450 }
5451
5452 pgrp.sc_pgroup_name = imp_str;
5453 mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
5454
5455 if (mpg != NULL)
5456 mpg->sc_pgroup_seen = 1;
5457
5458 /* Special handling for dependents */
5459 if (strcmp(imp_str, "dependents") == 0)
5460 return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
5461
5462 if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
5463 return (upgrade_manifestfiles(NULL, ient, running, ent));
5464
5465 if (mpg == NULL || mpg->sc_pgroup_delete) {
5466 /* property group was deleted from manifest */
5467 if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5468 switch (scf_error()) {
5469 case SCF_ERROR_NOT_FOUND:
5470 return (0);
5471
5472 case SCF_ERROR_DELETED:
5473 case SCF_ERROR_CONNECTION_BROKEN:
5474 return (scferror2errno(scf_error()));
5475
5476 case SCF_ERROR_INVALID_ARGUMENT:
5477 case SCF_ERROR_HANDLE_MISMATCH:
5478 case SCF_ERROR_NOT_BOUND:
5479 case SCF_ERROR_NOT_SET:
5480 default:
5481 bad_error("entity_get_pg", scf_error());
5482 }
5483 }
5484
5485 if (mpg != NULL && mpg->sc_pgroup_delete) {
5486 if (g_verbose)
5487 warn(deleting, ient->sc_fmri, imp_str);
5488 if (scf_pg_delete(imp_pg2) == 0)
5489 return (0);
5490
5491 switch (scf_error()) {
5492 case SCF_ERROR_DELETED:
5493 return (0);
5494
5495 case SCF_ERROR_CONNECTION_BROKEN:
5496 case SCF_ERROR_BACKEND_READONLY:
5497 case SCF_ERROR_BACKEND_ACCESS:
5498 return (scferror2errno(scf_error()));
5499
5500 case SCF_ERROR_PERMISSION_DENIED:
5501 warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
5502 return (scferror2errno(scf_error()));
5503
5504 case SCF_ERROR_NOT_SET:
5505 default:
5506 bad_error("scf_pg_delete", scf_error());
5507 }
5508 }
5509
5510 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5511 switch (r) {
5512 case 0:
5513 break;
5514
5515 case ECANCELED:
5516 return (ENODEV);
5517
5518 case ECONNABORTED:
5519 case ENOMEM:
5520 case EBADF:
5521 case EACCES:
5522 return (r);
5523
5524 default:
5525 bad_error("load_pg", r);
5526 }
5527
5528 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5529 switch (r) {
5530 case 0:
5531 break;
5532
5533 case ECANCELED:
5534 case ECONNABORTED:
5535 case ENOMEM:
5536 case EBADF:
5537 case EACCES:
5538 internal_pgroup_free(lipg_i);
5539 return (r);
5540
5541 default:
5542 bad_error("load_pg", r);
5543 }
5544
5545 if (pg_equal(lipg_i, curpg_i)) {
5546 if (g_verbose)
5547 warn(deleting, ient->sc_fmri, imp_str);
5548 if (scf_pg_delete(imp_pg2) != 0) {
5549 switch (scf_error()) {
5550 case SCF_ERROR_DELETED:
5551 break;
5552
5553 case SCF_ERROR_CONNECTION_BROKEN:
5554 internal_pgroup_free(lipg_i);
5555 internal_pgroup_free(curpg_i);
5556 return (ECONNABORTED);
5557
5558 case SCF_ERROR_NOT_SET:
5559 case SCF_ERROR_NOT_BOUND:
5560 default:
5561 bad_error("scf_pg_delete", scf_error());
5562 }
5563 }
5564 } else {
5565 report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5566 }
5567
5568 internal_pgroup_free(lipg_i);
5569 internal_pgroup_free(curpg_i);
5570
5571 return (0);
5572 }
5573
5574 /*
5575 * Only dependent pgs can have override set, and we skipped those
5576 * above.
5577 */
5578 assert(!mpg->sc_pgroup_override);
5579
5580 /* compare */
5581 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5582 switch (r) {
5583 case 0:
5584 break;
5585
5586 case ECANCELED:
5587 return (ENODEV);
5588
5589 case ECONNABORTED:
5590 case EBADF:
5591 case ENOMEM:
5592 case EACCES:
5593 return (r);
5594
5595 default:
5596 bad_error("load_pg", r);
5597 }
5598
5599 if (pg_equal(mpg, lipg_i)) {
5600 /* The manifest pg has not changed. Move on. */
5601 r = 0;
5602 goto out;
5603 }
5604
5605 /* upgrade current properties according to lipg & mpg */
5606 if (running != NULL)
5607 r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5608 else
5609 r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5610 if (r != 0) {
5611 switch (scf_error()) {
5612 case SCF_ERROR_CONNECTION_BROKEN:
5613 r = scferror2errno(scf_error());
5614 goto out;
5615
5616 case SCF_ERROR_DELETED:
5617 if (running != NULL)
5618 r = ENODEV;
5619 else
5620 r = ECANCELED;
5621 goto out;
5622
5623 case SCF_ERROR_NOT_FOUND:
5624 break;
5625
5626 case SCF_ERROR_INVALID_ARGUMENT:
5627 case SCF_ERROR_HANDLE_MISMATCH:
5628 case SCF_ERROR_NOT_BOUND:
5629 case SCF_ERROR_NOT_SET:
5630 default:
5631 bad_error("entity_get_pg", scf_error());
5632 }
5633
5634 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5635
5636 r = 0;
5637 goto out;
5638 }
5639
5640 r = load_pg_attrs(imp_pg2, &curpg_i);
5641 switch (r) {
5642 case 0:
5643 break;
5644
5645 case ECANCELED:
5646 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5647 r = 0;
5648 goto out;
5649
5650 case ECONNABORTED:
5651 case ENOMEM:
5652 goto out;
5653
5654 default:
5655 bad_error("load_pg_attrs", r);
5656 }
5657
5658 if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5659 (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5660 internal_pgroup_free(curpg_i);
5661 r = 0;
5662 goto out;
5663 }
5664
5665 internal_pgroup_free(curpg_i);
5666
5667 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5668 switch (r) {
5669 case 0:
5670 break;
5671
5672 case ECANCELED:
5673 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5674 r = 0;
5675 goto out;
5676
5677 case ECONNABORTED:
5678 case EBADF:
5679 case ENOMEM:
5680 case EACCES:
5681 goto out;
5682
5683 default:
5684 bad_error("load_pg", r);
5685 }
5686
5687 if (pg_equal(lipg_i, curpg_i) &&
5688 !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5689 int do_delete = 1;
5690
5691 if (g_verbose)
5692 warn(gettext("%s: Upgrading property group \"%s\".\n"),
5693 ient->sc_fmri, mpg->sc_pgroup_name);
5694
5695 internal_pgroup_free(curpg_i);
5696
5697 if (running != NULL &&
5698 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5699 switch (scf_error()) {
5700 case SCF_ERROR_DELETED:
5701 r = ECANCELED;
5702 goto out;
5703
5704 case SCF_ERROR_NOT_FOUND:
5705 do_delete = 0;
5706 break;
5707
5708 case SCF_ERROR_CONNECTION_BROKEN:
5709 r = scferror2errno(scf_error());
5710 goto out;
5711
5712 case SCF_ERROR_HANDLE_MISMATCH:
5713 case SCF_ERROR_INVALID_ARGUMENT:
5714 case SCF_ERROR_NOT_SET:
5715 case SCF_ERROR_NOT_BOUND:
5716 default:
5717 bad_error("entity_get_pg", scf_error());
5718 }
5719 }
5720
5721 if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5722 switch (scf_error()) {
5723 case SCF_ERROR_DELETED:
5724 break;
5725
5726 case SCF_ERROR_CONNECTION_BROKEN:
5727 case SCF_ERROR_BACKEND_READONLY:
5728 case SCF_ERROR_BACKEND_ACCESS:
5729 r = scferror2errno(scf_error());
5730 goto out;
5731
5732 case SCF_ERROR_PERMISSION_DENIED:
5733 warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5734 ient->sc_fmri);
5735 r = scferror2errno(scf_error());
5736 goto out;
5737
5738 case SCF_ERROR_NOT_SET:
5739 case SCF_ERROR_NOT_BOUND:
5740 default:
5741 bad_error("scf_pg_delete", scf_error());
5742 }
5743 }
5744
5745 cbdata.sc_handle = g_hndl;
5746 cbdata.sc_parent = ent;
5747 cbdata.sc_service = issvc;
5748 cbdata.sc_flags = 0;
5749 cbdata.sc_source_fmri = ient->sc_fmri;
5750 cbdata.sc_target_fmri = ient->sc_fmri;
5751
5752 r = entity_pgroup_import(mpg, &cbdata);
5753 switch (r) {
5754 case UU_WALK_NEXT:
5755 r = 0;
5756 goto out;
5757
5758 case UU_WALK_ERROR:
5759 if (cbdata.sc_err == EEXIST) {
5760 warn(emsg_pg_added, ient->sc_fmri,
5761 mpg->sc_pgroup_name);
5762 r = EBUSY;
5763 } else {
5764 r = cbdata.sc_err;
5765 }
5766 goto out;
5767
5768 default:
5769 bad_error("entity_pgroup_import", r);
5770 }
5771 }
5772
5773 if (running != NULL &&
5774 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5775 switch (scf_error()) {
5776 case SCF_ERROR_CONNECTION_BROKEN:
5777 case SCF_ERROR_DELETED:
5778 r = scferror2errno(scf_error());
5779 goto out;
5780
5781 case SCF_ERROR_NOT_FOUND:
5782 break;
5783
5784 case SCF_ERROR_HANDLE_MISMATCH:
5785 case SCF_ERROR_INVALID_ARGUMENT:
5786 case SCF_ERROR_NOT_SET:
5787 case SCF_ERROR_NOT_BOUND:
5788 default:
5789 bad_error("entity_get_pg", scf_error());
5790 }
5791
5792 cbdata.sc_handle = g_hndl;
5793 cbdata.sc_parent = ent;
5794 cbdata.sc_service = issvc;
5795 cbdata.sc_flags = SCI_FORCE;
5796 cbdata.sc_source_fmri = ient->sc_fmri;
5797 cbdata.sc_target_fmri = ient->sc_fmri;
5798
5799 r = entity_pgroup_import(mpg, &cbdata);
5800 switch (r) {
5801 case UU_WALK_NEXT:
5802 r = 0;
5803 goto out;
5804
5805 case UU_WALK_ERROR:
5806 if (cbdata.sc_err == EEXIST) {
5807 warn(emsg_pg_added, ient->sc_fmri,
5808 mpg->sc_pgroup_name);
5809 r = EBUSY;
5810 } else {
5811 r = cbdata.sc_err;
5812 }
5813 goto out;
5814
5815 default:
5816 bad_error("entity_pgroup_import", r);
5817 }
5818 }
5819
5820 r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5821 internal_pgroup_free(curpg_i);
5822 switch (r) {
5823 case 0:
5824 ient->sc_import_state = IMPORT_PROP_BEGUN;
5825 break;
5826
5827 case ECANCELED:
5828 warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5829 r = EBUSY;
5830 break;
5831
5832 case EPERM:
5833 warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5834 break;
5835
5836 case EBUSY:
5837 warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5838 break;
5839
5840 case ECONNABORTED:
5841 case ENOMEM:
5842 case ENOSPC:
5843 case EROFS:
5844 case EACCES:
5845 case EINVAL:
5846 break;
5847
5848 default:
5849 bad_error("upgrade_pg", r);
5850 }
5851
5852 out:
5853 internal_pgroup_free(lipg_i);
5854 return (r);
5855 }
5856
5857 /*
5858 * Upgrade the properties of ent according to snpl & ient.
5859 *
5860 * Returns
5861 * 0 - success
5862 * ECONNABORTED - repository connection broken
5863 * ENOMEM - out of memory
5864 * ENOSPC - configd is out of resources
5865 * ECANCELED - ent was deleted
5866 * ENODEV - entity containing snpl was deleted
5867 * - entity containing running was deleted
5868 * EBADF - imp_snpl is corrupt (error printed)
5869 * - ent has corrupt pg (error printed)
5870 * - dependent has corrupt pg (error printed)
5871 * - dependent target has a corrupt snapshot (error printed)
5872 * EBUSY - pg was added, changed, or deleted (error printed)
5873 * - dependent target was deleted (error printed)
5874 * - dependent pg changed (error printed)
5875 * EINVAL - invalid property group name (error printed)
5876 * - invalid property name (error printed)
5877 * - invalid value (error printed)
5878 * - ient has invalid pgroup or dependent (error printed)
5879 * EPERM - could not create property group (permission denied) (error printed)
5880 * - could not modify property group (permission denied) (error printed)
5881 * - couldn't delete, upgrade, or import pg or dependent (error printed)
5882 * EROFS - could not create property group (repository read-only)
5883 * - couldn't delete, upgrade, or import pg or dependent
5884 * EACCES - could not create property group (backend access denied)
5885 * - couldn't delete, upgrade, or import pg or dependent
5886 * EEXIST - dependent collision in target service (error printed)
5887 */
5888 static int
upgrade_props(void * ent,scf_snaplevel_t * running,scf_snaplevel_t * snpl,entity_t * ient)5889 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5890 entity_t *ient)
5891 {
5892 pgroup_t *pg, *rpg;
5893 int r;
5894 uu_list_t *pgs = ient->sc_pgroups;
5895
5896 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5897
5898 /* clear sc_sceen for pgs */
5899 if (uu_list_walk(pgs, clear_int,
5900 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5901 bad_error("uu_list_walk", uu_error());
5902
5903 if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5904 switch (scf_error()) {
5905 case SCF_ERROR_DELETED:
5906 return (ENODEV);
5907
5908 case SCF_ERROR_CONNECTION_BROKEN:
5909 return (ECONNABORTED);
5910
5911 case SCF_ERROR_NOT_SET:
5912 case SCF_ERROR_NOT_BOUND:
5913 case SCF_ERROR_HANDLE_MISMATCH:
5914 default:
5915 bad_error("scf_iter_snaplevel_pgs", scf_error());
5916 }
5917 }
5918
5919 for (;;) {
5920 r = scf_iter_next_pg(imp_up_iter, imp_pg);
5921 if (r == 0)
5922 break;
5923 if (r == 1) {
5924 r = process_old_pg(imp_pg, ient, ent, running);
5925 switch (r) {
5926 case 0:
5927 break;
5928
5929 case ECONNABORTED:
5930 case ENOMEM:
5931 case ENOSPC:
5932 case ECANCELED:
5933 case ENODEV:
5934 case EPERM:
5935 case EROFS:
5936 case EACCES:
5937 case EBADF:
5938 case EBUSY:
5939 case EINVAL:
5940 case EEXIST:
5941 return (r);
5942
5943 default:
5944 bad_error("process_old_pg", r);
5945 }
5946 continue;
5947 }
5948 if (r != -1)
5949 bad_error("scf_iter_next_pg", r);
5950
5951 switch (scf_error()) {
5952 case SCF_ERROR_DELETED:
5953 return (ENODEV);
5954
5955 case SCF_ERROR_CONNECTION_BROKEN:
5956 return (ECONNABORTED);
5957
5958 case SCF_ERROR_HANDLE_MISMATCH:
5959 case SCF_ERROR_NOT_BOUND:
5960 case SCF_ERROR_NOT_SET:
5961 case SCF_ERROR_INVALID_ARGUMENT:
5962 default:
5963 bad_error("scf_iter_next_pg", scf_error());
5964 }
5965 }
5966
5967 for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5968 if (pg->sc_pgroup_seen)
5969 continue;
5970
5971 /* pg is new */
5972
5973 if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5974 r = upgrade_dependents(NULL, imp_snpl, ient, running,
5975 ent);
5976 switch (r) {
5977 case 0:
5978 break;
5979
5980 case ECONNABORTED:
5981 case ENOMEM:
5982 case ENOSPC:
5983 case ECANCELED:
5984 case ENODEV:
5985 case EBADF:
5986 case EBUSY:
5987 case EINVAL:
5988 case EPERM:
5989 case EROFS:
5990 case EACCES:
5991 case EEXIST:
5992 return (r);
5993
5994 default:
5995 bad_error("upgrade_dependents", r);
5996 }
5997 continue;
5998 }
5999
6000 if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
6001 r = upgrade_manifestfiles(pg, ient, running, ent);
6002 switch (r) {
6003 case 0:
6004 break;
6005
6006 case ECONNABORTED:
6007 case ENOMEM:
6008 case ENOSPC:
6009 case ECANCELED:
6010 case ENODEV:
6011 case EBADF:
6012 case EBUSY:
6013 case EINVAL:
6014 case EPERM:
6015 case EROFS:
6016 case EACCES:
6017 case EEXIST:
6018 return (r);
6019
6020 default:
6021 bad_error("upgrade_manifestfiles", r);
6022 }
6023 continue;
6024 }
6025
6026 if (running != NULL) {
6027 r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
6028 imp_pg);
6029 } else {
6030 r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
6031 imp_pg);
6032 }
6033 if (r != 0) {
6034 scf_callback_t cbdata;
6035
6036 switch (scf_error()) {
6037 case SCF_ERROR_NOT_FOUND:
6038 break;
6039
6040 case SCF_ERROR_CONNECTION_BROKEN:
6041 return (scferror2errno(scf_error()));
6042
6043 case SCF_ERROR_DELETED:
6044 if (running != NULL)
6045 return (ENODEV);
6046 else
6047 return (scferror2errno(scf_error()));
6048
6049 case SCF_ERROR_INVALID_ARGUMENT:
6050 warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
6051 pg->sc_pgroup_name);
6052 return (EINVAL);
6053
6054 case SCF_ERROR_NOT_SET:
6055 case SCF_ERROR_HANDLE_MISMATCH:
6056 case SCF_ERROR_NOT_BOUND:
6057 default:
6058 bad_error("entity_get_pg", scf_error());
6059 }
6060
6061 /* User doesn't have pg, so import it. */
6062
6063 cbdata.sc_handle = g_hndl;
6064 cbdata.sc_parent = ent;
6065 cbdata.sc_service = issvc;
6066 cbdata.sc_flags = SCI_FORCE;
6067 cbdata.sc_source_fmri = ient->sc_fmri;
6068 cbdata.sc_target_fmri = ient->sc_fmri;
6069
6070 r = entity_pgroup_import(pg, &cbdata);
6071 switch (r) {
6072 case UU_WALK_NEXT:
6073 ient->sc_import_state = IMPORT_PROP_BEGUN;
6074 continue;
6075
6076 case UU_WALK_ERROR:
6077 if (cbdata.sc_err == EEXIST) {
6078 warn(emsg_pg_added, ient->sc_fmri,
6079 pg->sc_pgroup_name);
6080 return (EBUSY);
6081 }
6082 return (cbdata.sc_err);
6083
6084 default:
6085 bad_error("entity_pgroup_import", r);
6086 }
6087 }
6088
6089 /* report differences between pg & current */
6090 r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
6091 switch (r) {
6092 case 0:
6093 break;
6094
6095 case ECANCELED:
6096 warn(emsg_pg_deleted, ient->sc_fmri,
6097 pg->sc_pgroup_name);
6098 return (EBUSY);
6099
6100 case ECONNABORTED:
6101 case EBADF:
6102 case ENOMEM:
6103 case EACCES:
6104 return (r);
6105
6106 default:
6107 bad_error("load_pg", r);
6108 }
6109 report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
6110 internal_pgroup_free(rpg);
6111 rpg = NULL;
6112 }
6113
6114 return (0);
6115 }
6116
6117 /*
6118 * Import an instance. If it doesn't exist, create it. If it has
6119 * a last-import snapshot, upgrade its properties. Finish by updating its
6120 * last-import snapshot. If it doesn't have a last-import snapshot then it
6121 * could have been created for a dependent tag in another manifest. Import the
6122 * new properties. If there's a conflict, don't override, like now?
6123 *
6124 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
6125 * lcbdata->sc_err to
6126 * ECONNABORTED - repository connection broken
6127 * ENOMEM - out of memory
6128 * ENOSPC - svc.configd is out of resources
6129 * EEXIST - dependency collision in dependent service (error printed)
6130 * EPERM - couldn't create temporary instance (permission denied)
6131 * - couldn't import into temporary instance (permission denied)
6132 * - couldn't take snapshot (permission denied)
6133 * - couldn't upgrade properties (permission denied)
6134 * - couldn't import properties (permission denied)
6135 * - couldn't import dependents (permission denied)
6136 * EROFS - couldn't create temporary instance (repository read-only)
6137 * - couldn't import into temporary instance (repository read-only)
6138 * - couldn't upgrade properties (repository read-only)
6139 * - couldn't import properties (repository read-only)
6140 * - couldn't import dependents (repository read-only)
6141 * EACCES - couldn't create temporary instance (backend access denied)
6142 * - couldn't import into temporary instance (backend access denied)
6143 * - couldn't upgrade properties (backend access denied)
6144 * - couldn't import properties (backend access denied)
6145 * - couldn't import dependents (backend access denied)
6146 * EINVAL - invalid instance name (error printed)
6147 * - invalid pgroup_t's (error printed)
6148 * - invalid dependents (error printed)
6149 * EBUSY - temporary service deleted (error printed)
6150 * - temporary instance deleted (error printed)
6151 * - temporary instance changed (error printed)
6152 * - temporary instance already exists (error printed)
6153 * - instance deleted (error printed)
6154 * EBADF - instance has corrupt last-import snapshot (error printed)
6155 * - instance is corrupt (error printed)
6156 * - dependent has corrupt pg (error printed)
6157 * - dependent target has a corrupt snapshot (error printed)
6158 * -1 - unknown libscf error (error printed)
6159 */
6160 static int
lscf_instance_import(void * v,void * pvt)6161 lscf_instance_import(void *v, void *pvt)
6162 {
6163 entity_t *inst = v;
6164 scf_callback_t ctx;
6165 scf_callback_t *lcbdata = pvt;
6166 scf_service_t *rsvc = lcbdata->sc_parent;
6167 int r;
6168 scf_snaplevel_t *running;
6169 int flags = lcbdata->sc_flags;
6170
6171 const char * const emsg_tdel =
6172 gettext("Temporary instance svc:/%s:%s was deleted.\n");
6173 const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
6174 "changed unexpectedly.\n");
6175 const char * const emsg_del = gettext("%s changed unexpectedly "
6176 "(instance \"%s\" was deleted.)\n");
6177 const char * const emsg_badsnap = gettext(
6178 "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
6179
6180 /*
6181 * prepare last-import snapshot:
6182 * create temporary instance (service was precreated)
6183 * populate with properties from bundle
6184 * take snapshot
6185 */
6186 if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
6187 switch (scf_error()) {
6188 case SCF_ERROR_CONNECTION_BROKEN:
6189 case SCF_ERROR_NO_RESOURCES:
6190 case SCF_ERROR_BACKEND_READONLY:
6191 case SCF_ERROR_BACKEND_ACCESS:
6192 return (stash_scferror(lcbdata));
6193
6194 case SCF_ERROR_EXISTS:
6195 warn(gettext("Temporary service svc:/%s "
6196 "changed unexpectedly (instance \"%s\" added).\n"),
6197 imp_tsname, inst->sc_name);
6198 lcbdata->sc_err = EBUSY;
6199 return (UU_WALK_ERROR);
6200
6201 case SCF_ERROR_DELETED:
6202 warn(gettext("Temporary service svc:/%s "
6203 "was deleted unexpectedly.\n"), imp_tsname);
6204 lcbdata->sc_err = EBUSY;
6205 return (UU_WALK_ERROR);
6206
6207 case SCF_ERROR_INVALID_ARGUMENT:
6208 warn(gettext("Invalid instance name \"%s\".\n"),
6209 inst->sc_name);
6210 return (stash_scferror(lcbdata));
6211
6212 case SCF_ERROR_PERMISSION_DENIED:
6213 warn(gettext("Could not create temporary instance "
6214 "\"%s\" in svc:/%s (permission denied).\n"),
6215 inst->sc_name, imp_tsname);
6216 return (stash_scferror(lcbdata));
6217
6218 case SCF_ERROR_HANDLE_MISMATCH:
6219 case SCF_ERROR_NOT_BOUND:
6220 case SCF_ERROR_NOT_SET:
6221 default:
6222 bad_error("scf_service_add_instance", scf_error());
6223 }
6224 }
6225
6226 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6227 inst->sc_name);
6228 if (r < 0)
6229 bad_error("snprintf", errno);
6230
6231 r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
6232 lcbdata->sc_flags | SCI_NOENABLED);
6233 switch (r) {
6234 case 0:
6235 break;
6236
6237 case ECANCELED:
6238 warn(emsg_tdel, imp_tsname, inst->sc_name);
6239 lcbdata->sc_err = EBUSY;
6240 r = UU_WALK_ERROR;
6241 goto deltemp;
6242
6243 case EEXIST:
6244 warn(emsg_tchg, imp_tsname, inst->sc_name);
6245 lcbdata->sc_err = EBUSY;
6246 r = UU_WALK_ERROR;
6247 goto deltemp;
6248
6249 case ECONNABORTED:
6250 goto connaborted;
6251
6252 case ENOMEM:
6253 case ENOSPC:
6254 case EPERM:
6255 case EROFS:
6256 case EACCES:
6257 case EINVAL:
6258 case EBUSY:
6259 lcbdata->sc_err = r;
6260 r = UU_WALK_ERROR;
6261 goto deltemp;
6262
6263 default:
6264 bad_error("lscf_import_instance_pgs", r);
6265 }
6266
6267 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6268 inst->sc_name);
6269 if (r < 0)
6270 bad_error("snprintf", errno);
6271
6272 ctx.sc_handle = lcbdata->sc_handle;
6273 ctx.sc_parent = imp_tinst;
6274 ctx.sc_service = 0;
6275 ctx.sc_source_fmri = inst->sc_fmri;
6276 ctx.sc_target_fmri = imp_str;
6277 if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
6278 UU_DEFAULT) != 0) {
6279 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6280 bad_error("uu_list_walk", uu_error());
6281
6282 switch (ctx.sc_err) {
6283 case ECONNABORTED:
6284 goto connaborted;
6285
6286 case ECANCELED:
6287 warn(emsg_tdel, imp_tsname, inst->sc_name);
6288 lcbdata->sc_err = EBUSY;
6289 break;
6290
6291 case EEXIST:
6292 warn(emsg_tchg, imp_tsname, inst->sc_name);
6293 lcbdata->sc_err = EBUSY;
6294 break;
6295
6296 default:
6297 lcbdata->sc_err = ctx.sc_err;
6298 }
6299 r = UU_WALK_ERROR;
6300 goto deltemp;
6301 }
6302
6303 if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
6304 inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
6305 switch (scf_error()) {
6306 case SCF_ERROR_CONNECTION_BROKEN:
6307 goto connaborted;
6308
6309 case SCF_ERROR_NO_RESOURCES:
6310 r = stash_scferror(lcbdata);
6311 goto deltemp;
6312
6313 case SCF_ERROR_EXISTS:
6314 warn(emsg_tchg, imp_tsname, inst->sc_name);
6315 lcbdata->sc_err = EBUSY;
6316 r = UU_WALK_ERROR;
6317 goto deltemp;
6318
6319 case SCF_ERROR_PERMISSION_DENIED:
6320 warn(gettext("Could not take \"%s\" snapshot of %s "
6321 "(permission denied).\n"), snap_lastimport,
6322 imp_str);
6323 r = stash_scferror(lcbdata);
6324 goto deltemp;
6325
6326 default:
6327 scfwarn();
6328 lcbdata->sc_err = -1;
6329 r = UU_WALK_ERROR;
6330 goto deltemp;
6331
6332 case SCF_ERROR_HANDLE_MISMATCH:
6333 case SCF_ERROR_INVALID_ARGUMENT:
6334 case SCF_ERROR_NOT_SET:
6335 bad_error("_scf_snapshot_take_new_named", scf_error());
6336 }
6337 }
6338
6339 if (lcbdata->sc_flags & SCI_FRESH)
6340 goto fresh;
6341
6342 if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
6343 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6344 imp_lisnap) != 0) {
6345 switch (scf_error()) {
6346 case SCF_ERROR_DELETED:
6347 warn(emsg_del, inst->sc_parent->sc_fmri,
6348 inst->sc_name);
6349 lcbdata->sc_err = EBUSY;
6350 r = UU_WALK_ERROR;
6351 goto deltemp;
6352
6353 case SCF_ERROR_NOT_FOUND:
6354 flags |= SCI_FORCE;
6355 goto nosnap;
6356
6357 case SCF_ERROR_CONNECTION_BROKEN:
6358 goto connaborted;
6359
6360 case SCF_ERROR_INVALID_ARGUMENT:
6361 case SCF_ERROR_HANDLE_MISMATCH:
6362 case SCF_ERROR_NOT_BOUND:
6363 case SCF_ERROR_NOT_SET:
6364 default:
6365 bad_error("scf_instance_get_snapshot",
6366 scf_error());
6367 }
6368 }
6369
6370 /* upgrade */
6371
6372 /*
6373 * compare new properties with last-import properties
6374 * upgrade current properties
6375 */
6376 /* clear sc_sceen for pgs */
6377 if (uu_list_walk(inst->sc_pgroups, clear_int,
6378 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
6379 0)
6380 bad_error("uu_list_walk", uu_error());
6381
6382 r = get_snaplevel(imp_lisnap, 0, imp_snpl);
6383 switch (r) {
6384 case 0:
6385 break;
6386
6387 case ECONNABORTED:
6388 goto connaborted;
6389
6390 case ECANCELED:
6391 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6392 lcbdata->sc_err = EBUSY;
6393 r = UU_WALK_ERROR;
6394 goto deltemp;
6395
6396 case ENOENT:
6397 warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
6398 lcbdata->sc_err = EBADF;
6399 r = UU_WALK_ERROR;
6400 goto deltemp;
6401
6402 default:
6403 bad_error("get_snaplevel", r);
6404 }
6405
6406 if (scf_instance_get_snapshot(imp_inst, snap_running,
6407 imp_rsnap) != 0) {
6408 switch (scf_error()) {
6409 case SCF_ERROR_DELETED:
6410 warn(emsg_del, inst->sc_parent->sc_fmri,
6411 inst->sc_name);
6412 lcbdata->sc_err = EBUSY;
6413 r = UU_WALK_ERROR;
6414 goto deltemp;
6415
6416 case SCF_ERROR_NOT_FOUND:
6417 break;
6418
6419 case SCF_ERROR_CONNECTION_BROKEN:
6420 goto connaborted;
6421
6422 case SCF_ERROR_INVALID_ARGUMENT:
6423 case SCF_ERROR_HANDLE_MISMATCH:
6424 case SCF_ERROR_NOT_BOUND:
6425 case SCF_ERROR_NOT_SET:
6426 default:
6427 bad_error("scf_instance_get_snapshot",
6428 scf_error());
6429 }
6430
6431 running = NULL;
6432 } else {
6433 r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
6434 switch (r) {
6435 case 0:
6436 running = imp_rsnpl;
6437 break;
6438
6439 case ECONNABORTED:
6440 goto connaborted;
6441
6442 case ECANCELED:
6443 warn(emsg_del, inst->sc_parent->sc_fmri,
6444 inst->sc_name);
6445 lcbdata->sc_err = EBUSY;
6446 r = UU_WALK_ERROR;
6447 goto deltemp;
6448
6449 case ENOENT:
6450 warn(emsg_badsnap, snap_running, inst->sc_fmri);
6451 lcbdata->sc_err = EBADF;
6452 r = UU_WALK_ERROR;
6453 goto deltemp;
6454
6455 default:
6456 bad_error("get_snaplevel", r);
6457 }
6458 }
6459
6460 r = upgrade_props(imp_inst, running, imp_snpl, inst);
6461 switch (r) {
6462 case 0:
6463 break;
6464
6465 case ECANCELED:
6466 case ENODEV:
6467 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6468 lcbdata->sc_err = EBUSY;
6469 r = UU_WALK_ERROR;
6470 goto deltemp;
6471
6472 case ECONNABORTED:
6473 goto connaborted;
6474
6475 case ENOMEM:
6476 case ENOSPC:
6477 case EBADF:
6478 case EBUSY:
6479 case EINVAL:
6480 case EPERM:
6481 case EROFS:
6482 case EACCES:
6483 case EEXIST:
6484 lcbdata->sc_err = r;
6485 r = UU_WALK_ERROR;
6486 goto deltemp;
6487
6488 default:
6489 bad_error("upgrade_props", r);
6490 }
6491
6492 inst->sc_import_state = IMPORT_PROP_DONE;
6493 } else {
6494 switch (scf_error()) {
6495 case SCF_ERROR_CONNECTION_BROKEN:
6496 goto connaborted;
6497
6498 case SCF_ERROR_NOT_FOUND:
6499 break;
6500
6501 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
6502 case SCF_ERROR_HANDLE_MISMATCH:
6503 case SCF_ERROR_NOT_BOUND:
6504 case SCF_ERROR_NOT_SET:
6505 default:
6506 bad_error("scf_service_get_instance", scf_error());
6507 }
6508
6509 fresh:
6510 /* create instance */
6511 if (scf_service_add_instance(rsvc, inst->sc_name,
6512 imp_inst) != 0) {
6513 switch (scf_error()) {
6514 case SCF_ERROR_CONNECTION_BROKEN:
6515 goto connaborted;
6516
6517 case SCF_ERROR_NO_RESOURCES:
6518 case SCF_ERROR_BACKEND_READONLY:
6519 case SCF_ERROR_BACKEND_ACCESS:
6520 r = stash_scferror(lcbdata);
6521 goto deltemp;
6522
6523 case SCF_ERROR_EXISTS:
6524 warn(gettext("%s changed unexpectedly "
6525 "(instance \"%s\" added).\n"),
6526 inst->sc_parent->sc_fmri, inst->sc_name);
6527 lcbdata->sc_err = EBUSY;
6528 r = UU_WALK_ERROR;
6529 goto deltemp;
6530
6531 case SCF_ERROR_PERMISSION_DENIED:
6532 warn(gettext("Could not create \"%s\" instance "
6533 "in %s (permission denied).\n"),
6534 inst->sc_name, inst->sc_parent->sc_fmri);
6535 r = stash_scferror(lcbdata);
6536 goto deltemp;
6537
6538 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
6539 case SCF_ERROR_HANDLE_MISMATCH:
6540 case SCF_ERROR_NOT_BOUND:
6541 case SCF_ERROR_NOT_SET:
6542 default:
6543 bad_error("scf_service_add_instance",
6544 scf_error());
6545 }
6546 }
6547
6548 nosnap:
6549 /*
6550 * Create a last-import snapshot to serve as an attachment
6551 * point for the real one from the temporary instance. Since
6552 * the contents is irrelevant, take it now, while the instance
6553 * is empty, to minimize svc.configd's work.
6554 */
6555 if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6556 imp_lisnap) != 0) {
6557 switch (scf_error()) {
6558 case SCF_ERROR_CONNECTION_BROKEN:
6559 goto connaborted;
6560
6561 case SCF_ERROR_NO_RESOURCES:
6562 r = stash_scferror(lcbdata);
6563 goto deltemp;
6564
6565 case SCF_ERROR_EXISTS:
6566 warn(gettext("%s changed unexpectedly "
6567 "(snapshot \"%s\" added).\n"),
6568 inst->sc_fmri, snap_lastimport);
6569 lcbdata->sc_err = EBUSY;
6570 r = UU_WALK_ERROR;
6571 goto deltemp;
6572
6573 case SCF_ERROR_PERMISSION_DENIED:
6574 warn(gettext("Could not take \"%s\" snapshot "
6575 "of %s (permission denied).\n"),
6576 snap_lastimport, inst->sc_fmri);
6577 r = stash_scferror(lcbdata);
6578 goto deltemp;
6579
6580 default:
6581 scfwarn();
6582 lcbdata->sc_err = -1;
6583 r = UU_WALK_ERROR;
6584 goto deltemp;
6585
6586 case SCF_ERROR_NOT_SET:
6587 case SCF_ERROR_INTERNAL:
6588 case SCF_ERROR_INVALID_ARGUMENT:
6589 case SCF_ERROR_HANDLE_MISMATCH:
6590 bad_error("_scf_snapshot_take_new",
6591 scf_error());
6592 }
6593 }
6594
6595 if (li_only)
6596 goto lionly;
6597
6598 inst->sc_import_state = IMPORT_PROP_BEGUN;
6599
6600 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6601 flags);
6602 switch (r) {
6603 case 0:
6604 break;
6605
6606 case ECONNABORTED:
6607 goto connaborted;
6608
6609 case ECANCELED:
6610 warn(gettext("%s changed unexpectedly "
6611 "(instance \"%s\" deleted).\n"),
6612 inst->sc_parent->sc_fmri, inst->sc_name);
6613 lcbdata->sc_err = EBUSY;
6614 r = UU_WALK_ERROR;
6615 goto deltemp;
6616
6617 case EEXIST:
6618 warn(gettext("%s changed unexpectedly "
6619 "(property group added).\n"), inst->sc_fmri);
6620 lcbdata->sc_err = EBUSY;
6621 r = UU_WALK_ERROR;
6622 goto deltemp;
6623
6624 default:
6625 lcbdata->sc_err = r;
6626 r = UU_WALK_ERROR;
6627 goto deltemp;
6628
6629 case EINVAL: /* caught above */
6630 bad_error("lscf_import_instance_pgs", r);
6631 }
6632
6633 ctx.sc_parent = imp_inst;
6634 ctx.sc_service = 0;
6635 ctx.sc_trans = NULL;
6636 ctx.sc_flags = 0;
6637 if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6638 &ctx, UU_DEFAULT) != 0) {
6639 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6640 bad_error("uu_list_walk", uu_error());
6641
6642 if (ctx.sc_err == ECONNABORTED)
6643 goto connaborted;
6644 lcbdata->sc_err = ctx.sc_err;
6645 r = UU_WALK_ERROR;
6646 goto deltemp;
6647 }
6648
6649 inst->sc_import_state = IMPORT_PROP_DONE;
6650
6651 if (g_verbose)
6652 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6653 snap_initial, inst->sc_fmri);
6654 r = take_snap(imp_inst, snap_initial, imp_snap);
6655 switch (r) {
6656 case 0:
6657 break;
6658
6659 case ECONNABORTED:
6660 goto connaborted;
6661
6662 case ENOSPC:
6663 case -1:
6664 lcbdata->sc_err = r;
6665 r = UU_WALK_ERROR;
6666 goto deltemp;
6667
6668 case ECANCELED:
6669 warn(gettext("%s changed unexpectedly "
6670 "(instance %s deleted).\n"),
6671 inst->sc_parent->sc_fmri, inst->sc_name);
6672 lcbdata->sc_err = r;
6673 r = UU_WALK_ERROR;
6674 goto deltemp;
6675
6676 case EPERM:
6677 warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6678 lcbdata->sc_err = r;
6679 r = UU_WALK_ERROR;
6680 goto deltemp;
6681
6682 default:
6683 bad_error("take_snap", r);
6684 }
6685 }
6686
6687 lionly:
6688 if (lcbdata->sc_flags & SCI_NOSNAP)
6689 goto deltemp;
6690
6691 /* transfer snapshot from temporary instance */
6692 if (g_verbose)
6693 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6694 snap_lastimport, inst->sc_fmri);
6695 if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6696 switch (scf_error()) {
6697 case SCF_ERROR_CONNECTION_BROKEN:
6698 goto connaborted;
6699
6700 case SCF_ERROR_NO_RESOURCES:
6701 r = stash_scferror(lcbdata);
6702 goto deltemp;
6703
6704 case SCF_ERROR_PERMISSION_DENIED:
6705 warn(gettext("Could not take \"%s\" snapshot for %s "
6706 "(permission denied).\n"), snap_lastimport,
6707 inst->sc_fmri);
6708 r = stash_scferror(lcbdata);
6709 goto deltemp;
6710
6711 case SCF_ERROR_NOT_SET:
6712 case SCF_ERROR_HANDLE_MISMATCH:
6713 default:
6714 bad_error("_scf_snapshot_attach", scf_error());
6715 }
6716 }
6717
6718 inst->sc_import_state = IMPORT_COMPLETE;
6719
6720 r = UU_WALK_NEXT;
6721
6722 deltemp:
6723 /* delete temporary instance */
6724 if (scf_instance_delete(imp_tinst) != 0) {
6725 switch (scf_error()) {
6726 case SCF_ERROR_DELETED:
6727 break;
6728
6729 case SCF_ERROR_CONNECTION_BROKEN:
6730 goto connaborted;
6731
6732 case SCF_ERROR_NOT_SET:
6733 case SCF_ERROR_NOT_BOUND:
6734 default:
6735 bad_error("scf_instance_delete", scf_error());
6736 }
6737 }
6738
6739 return (r);
6740
6741 connaborted:
6742 warn(gettext("Could not delete svc:/%s:%s "
6743 "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6744 lcbdata->sc_err = ECONNABORTED;
6745 return (UU_WALK_ERROR);
6746 }
6747
6748 /*
6749 * If the service is missing, create it, import its properties, and import the
6750 * instances. Since the service is brand new, it should be empty, and if we
6751 * run into any existing entities (SCF_ERROR_EXISTS), abort.
6752 *
6753 * If the service exists, we want to upgrade its properties and import the
6754 * instances. Upgrade requires a last-import snapshot, though, which are
6755 * children of instances, so first we'll have to go through the instances
6756 * looking for a last-import snapshot. If we don't find one then we'll just
6757 * override-import the service properties (but don't delete existing
6758 * properties: another service might have declared us as a dependent). Before
6759 * we change anything, though, we want to take the previous snapshots. We
6760 * also give lscf_instance_import() a leg up on taking last-import snapshots
6761 * by importing the manifest's service properties into a temporary service.
6762 *
6763 * On success, returns UU_WALK_NEXT. On failure, returns UU_WALK_ERROR and
6764 * sets lcbdata->sc_err to
6765 * ECONNABORTED - repository connection broken
6766 * ENOMEM - out of memory
6767 * ENOSPC - svc.configd is out of resources
6768 * EPERM - couldn't create temporary service (error printed)
6769 * - couldn't import into temp service (error printed)
6770 * - couldn't create service (error printed)
6771 * - couldn't import dependent (error printed)
6772 * - couldn't take snapshot (error printed)
6773 * - couldn't create instance (error printed)
6774 * - couldn't create, modify, or delete pg (error printed)
6775 * - couldn't create, modify, or delete dependent (error printed)
6776 * - couldn't import instance (error printed)
6777 * EROFS - couldn't create temporary service (repository read-only)
6778 * - couldn't import into temporary service (repository read-only)
6779 * - couldn't create service (repository read-only)
6780 * - couldn't import dependent (repository read-only)
6781 * - couldn't create instance (repository read-only)
6782 * - couldn't create, modify, or delete pg or dependent
6783 * - couldn't import instance (repository read-only)
6784 * EACCES - couldn't create temporary service (backend access denied)
6785 * - couldn't import into temporary service (backend access denied)
6786 * - couldn't create service (backend access denied)
6787 * - couldn't import dependent (backend access denied)
6788 * - couldn't create instance (backend access denied)
6789 * - couldn't create, modify, or delete pg or dependent
6790 * - couldn't import instance (backend access denied)
6791 * EINVAL - service name is invalid (error printed)
6792 * - service name is too long (error printed)
6793 * - s has invalid pgroup (error printed)
6794 * - s has invalid dependent (error printed)
6795 * - instance name is invalid (error printed)
6796 * - instance entity_t is invalid (error printed)
6797 * EEXIST - couldn't create temporary service (already exists) (error printed)
6798 * - couldn't import dependent (dependency pg already exists) (printed)
6799 * - dependency collision in dependent service (error printed)
6800 * EBUSY - temporary service deleted (error printed)
6801 * - property group added to temporary service (error printed)
6802 * - new property group changed or was deleted (error printed)
6803 * - service was added unexpectedly (error printed)
6804 * - service was deleted unexpectedly (error printed)
6805 * - property group added to new service (error printed)
6806 * - instance added unexpectedly (error printed)
6807 * - instance deleted unexpectedly (error printed)
6808 * - dependent service deleted unexpectedly (error printed)
6809 * - pg was added, changed, or deleted (error printed)
6810 * - dependent pg changed (error printed)
6811 * - temporary instance added, changed, or deleted (error printed)
6812 * EBADF - a last-import snapshot is corrupt (error printed)
6813 * - the service is corrupt (error printed)
6814 * - a dependent is corrupt (error printed)
6815 * - an instance is corrupt (error printed)
6816 * - an instance has a corrupt last-import snapshot (error printed)
6817 * - dependent target has a corrupt snapshot (error printed)
6818 * -1 - unknown libscf error (error printed)
6819 */
6820 static int
lscf_service_import(void * v,void * pvt)6821 lscf_service_import(void *v, void *pvt)
6822 {
6823 entity_t *s = v;
6824 scf_callback_t cbdata;
6825 scf_callback_t *lcbdata = pvt;
6826 scf_scope_t *scope = lcbdata->sc_parent;
6827 entity_t *inst, linst;
6828 int r;
6829 int fresh = 0;
6830 scf_snaplevel_t *running;
6831 int have_ge = 0;
6832
6833 const char * const ts_deleted = gettext("Temporary service svc:/%s "
6834 "was deleted unexpectedly.\n");
6835 const char * const ts_pg_added = gettext("Temporary service svc:/%s "
6836 "changed unexpectedly (property group added).\n");
6837 const char * const s_deleted =
6838 gettext("%s was deleted unexpectedly.\n");
6839 const char * const i_deleted =
6840 gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
6841 const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
6842 "is corrupt (missing service snaplevel).\n");
6843 const char * const s_mfile_upd =
6844 gettext("Unable to update the manifest file connection "
6845 "for %s\n");
6846
6847 li_only = 0;
6848 /* Validate the service name */
6849 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
6850 switch (scf_error()) {
6851 case SCF_ERROR_CONNECTION_BROKEN:
6852 return (stash_scferror(lcbdata));
6853
6854 case SCF_ERROR_INVALID_ARGUMENT:
6855 warn(gettext("\"%s\" is an invalid service name. "
6856 "Cannot import.\n"), s->sc_name);
6857 return (stash_scferror(lcbdata));
6858
6859 case SCF_ERROR_NOT_FOUND:
6860 break;
6861
6862 case SCF_ERROR_HANDLE_MISMATCH:
6863 case SCF_ERROR_NOT_BOUND:
6864 case SCF_ERROR_NOT_SET:
6865 default:
6866 bad_error("scf_scope_get_service", scf_error());
6867 }
6868 }
6869
6870 /* create temporary service */
6871 /*
6872 * the size of the buffer was reduced to max_scf_name_len to prevent
6873 * hitting bug 6681151. After the bug fix, the size of the buffer
6874 * should be restored to its original value (max_scf_name_len +1)
6875 */
6876 r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
6877 if (r < 0)
6878 bad_error("snprintf", errno);
6879 if (r > max_scf_name_len) {
6880 warn(gettext(
6881 "Service name \"%s\" is too long. Cannot import.\n"),
6882 s->sc_name);
6883 lcbdata->sc_err = EINVAL;
6884 return (UU_WALK_ERROR);
6885 }
6886
6887 if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
6888 switch (scf_error()) {
6889 case SCF_ERROR_CONNECTION_BROKEN:
6890 case SCF_ERROR_NO_RESOURCES:
6891 case SCF_ERROR_BACKEND_READONLY:
6892 case SCF_ERROR_BACKEND_ACCESS:
6893 return (stash_scferror(lcbdata));
6894
6895 case SCF_ERROR_EXISTS:
6896 warn(gettext(
6897 "Temporary service \"%s\" must be deleted before "
6898 "this manifest can be imported.\n"), imp_tsname);
6899 return (stash_scferror(lcbdata));
6900
6901 case SCF_ERROR_PERMISSION_DENIED:
6902 warn(gettext("Could not create temporary service "
6903 "\"%s\" (permission denied).\n"), imp_tsname);
6904 return (stash_scferror(lcbdata));
6905
6906 case SCF_ERROR_INVALID_ARGUMENT:
6907 case SCF_ERROR_HANDLE_MISMATCH:
6908 case SCF_ERROR_NOT_BOUND:
6909 case SCF_ERROR_NOT_SET:
6910 default:
6911 bad_error("scf_scope_add_service", scf_error());
6912 }
6913 }
6914
6915 r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
6916 if (r < 0)
6917 bad_error("snprintf", errno);
6918
6919 cbdata.sc_handle = lcbdata->sc_handle;
6920 cbdata.sc_parent = imp_tsvc;
6921 cbdata.sc_service = 1;
6922 cbdata.sc_source_fmri = s->sc_fmri;
6923 cbdata.sc_target_fmri = imp_str;
6924 cbdata.sc_flags = 0;
6925
6926 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
6927 UU_DEFAULT) != 0) {
6928 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6929 bad_error("uu_list_walk", uu_error());
6930
6931 lcbdata->sc_err = cbdata.sc_err;
6932 switch (cbdata.sc_err) {
6933 case ECONNABORTED:
6934 goto connaborted;
6935
6936 case ECANCELED:
6937 warn(ts_deleted, imp_tsname);
6938 lcbdata->sc_err = EBUSY;
6939 return (UU_WALK_ERROR);
6940
6941 case EEXIST:
6942 warn(ts_pg_added, imp_tsname);
6943 lcbdata->sc_err = EBUSY;
6944 return (UU_WALK_ERROR);
6945 }
6946
6947 r = UU_WALK_ERROR;
6948 goto deltemp;
6949 }
6950
6951 if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
6952 UU_DEFAULT) != 0) {
6953 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6954 bad_error("uu_list_walk", uu_error());
6955
6956 lcbdata->sc_err = cbdata.sc_err;
6957 switch (cbdata.sc_err) {
6958 case ECONNABORTED:
6959 goto connaborted;
6960
6961 case ECANCELED:
6962 warn(ts_deleted, imp_tsname);
6963 lcbdata->sc_err = EBUSY;
6964 return (UU_WALK_ERROR);
6965
6966 case EEXIST:
6967 warn(ts_pg_added, imp_tsname);
6968 lcbdata->sc_err = EBUSY;
6969 return (UU_WALK_ERROR);
6970 }
6971
6972 r = UU_WALK_ERROR;
6973 goto deltemp;
6974 }
6975
6976 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
6977 switch (scf_error()) {
6978 case SCF_ERROR_NOT_FOUND:
6979 break;
6980
6981 case SCF_ERROR_CONNECTION_BROKEN:
6982 goto connaborted;
6983
6984 case SCF_ERROR_INVALID_ARGUMENT:
6985 case SCF_ERROR_HANDLE_MISMATCH:
6986 case SCF_ERROR_NOT_BOUND:
6987 case SCF_ERROR_NOT_SET:
6988 default:
6989 bad_error("scf_scope_get_service", scf_error());
6990 }
6991
6992 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
6993 switch (scf_error()) {
6994 case SCF_ERROR_CONNECTION_BROKEN:
6995 goto connaborted;
6996
6997 case SCF_ERROR_NO_RESOURCES:
6998 case SCF_ERROR_BACKEND_READONLY:
6999 case SCF_ERROR_BACKEND_ACCESS:
7000 r = stash_scferror(lcbdata);
7001 goto deltemp;
7002
7003 case SCF_ERROR_EXISTS:
7004 warn(gettext("Scope \"%s\" changed unexpectedly"
7005 " (service \"%s\" added).\n"),
7006 SCF_SCOPE_LOCAL, s->sc_name);
7007 lcbdata->sc_err = EBUSY;
7008 goto deltemp;
7009
7010 case SCF_ERROR_PERMISSION_DENIED:
7011 warn(gettext("Could not create service \"%s\" "
7012 "(permission denied).\n"), s->sc_name);
7013 goto deltemp;
7014
7015 case SCF_ERROR_INVALID_ARGUMENT:
7016 case SCF_ERROR_HANDLE_MISMATCH:
7017 case SCF_ERROR_NOT_BOUND:
7018 case SCF_ERROR_NOT_SET:
7019 default:
7020 bad_error("scf_scope_add_service", scf_error());
7021 }
7022 }
7023
7024 s->sc_import_state = IMPORT_PROP_BEGUN;
7025
7026 /* import service properties */
7027 cbdata.sc_handle = lcbdata->sc_handle;
7028 cbdata.sc_parent = imp_svc;
7029 cbdata.sc_service = 1;
7030 cbdata.sc_flags = lcbdata->sc_flags;
7031 cbdata.sc_source_fmri = s->sc_fmri;
7032 cbdata.sc_target_fmri = s->sc_fmri;
7033
7034 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7035 &cbdata, UU_DEFAULT) != 0) {
7036 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7037 bad_error("uu_list_walk", uu_error());
7038
7039 lcbdata->sc_err = cbdata.sc_err;
7040 switch (cbdata.sc_err) {
7041 case ECONNABORTED:
7042 goto connaborted;
7043
7044 case ECANCELED:
7045 warn(s_deleted, s->sc_fmri);
7046 lcbdata->sc_err = EBUSY;
7047 return (UU_WALK_ERROR);
7048
7049 case EEXIST:
7050 warn(gettext("%s changed unexpectedly "
7051 "(property group added).\n"), s->sc_fmri);
7052 lcbdata->sc_err = EBUSY;
7053 return (UU_WALK_ERROR);
7054
7055 case EINVAL:
7056 /* caught above */
7057 bad_error("entity_pgroup_import",
7058 cbdata.sc_err);
7059 }
7060
7061 r = UU_WALK_ERROR;
7062 goto deltemp;
7063 }
7064
7065 cbdata.sc_trans = NULL;
7066 cbdata.sc_flags = 0;
7067 if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
7068 &cbdata, UU_DEFAULT) != 0) {
7069 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7070 bad_error("uu_list_walk", uu_error());
7071
7072 lcbdata->sc_err = cbdata.sc_err;
7073 if (cbdata.sc_err == ECONNABORTED)
7074 goto connaborted;
7075 r = UU_WALK_ERROR;
7076 goto deltemp;
7077 }
7078
7079 s->sc_import_state = IMPORT_PROP_DONE;
7080
7081 /*
7082 * This is a new service, so we can't take previous snapshots
7083 * or upgrade service properties.
7084 */
7085 fresh = 1;
7086 goto instances;
7087 }
7088
7089 /* Clear sc_seen for the instances. */
7090 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
7091 (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
7092 bad_error("uu_list_walk", uu_error());
7093
7094 /*
7095 * Take previous snapshots for all instances. Even for ones not
7096 * mentioned in the bundle, since we might change their service
7097 * properties.
7098 */
7099 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7100 switch (scf_error()) {
7101 case SCF_ERROR_CONNECTION_BROKEN:
7102 goto connaborted;
7103
7104 case SCF_ERROR_DELETED:
7105 warn(s_deleted, s->sc_fmri);
7106 lcbdata->sc_err = EBUSY;
7107 r = UU_WALK_ERROR;
7108 goto deltemp;
7109
7110 case SCF_ERROR_HANDLE_MISMATCH:
7111 case SCF_ERROR_NOT_BOUND:
7112 case SCF_ERROR_NOT_SET:
7113 default:
7114 bad_error("scf_iter_service_instances", scf_error());
7115 }
7116 }
7117
7118 for (;;) {
7119 r = scf_iter_next_instance(imp_iter, imp_inst);
7120 if (r == 0)
7121 break;
7122 if (r != 1) {
7123 switch (scf_error()) {
7124 case SCF_ERROR_DELETED:
7125 warn(s_deleted, s->sc_fmri);
7126 lcbdata->sc_err = EBUSY;
7127 r = UU_WALK_ERROR;
7128 goto deltemp;
7129
7130 case SCF_ERROR_CONNECTION_BROKEN:
7131 goto connaborted;
7132
7133 case SCF_ERROR_NOT_BOUND:
7134 case SCF_ERROR_HANDLE_MISMATCH:
7135 case SCF_ERROR_INVALID_ARGUMENT:
7136 case SCF_ERROR_NOT_SET:
7137 default:
7138 bad_error("scf_iter_next_instance",
7139 scf_error());
7140 }
7141 }
7142
7143 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
7144 switch (scf_error()) {
7145 case SCF_ERROR_DELETED:
7146 continue;
7147
7148 case SCF_ERROR_CONNECTION_BROKEN:
7149 goto connaborted;
7150
7151 case SCF_ERROR_NOT_SET:
7152 case SCF_ERROR_NOT_BOUND:
7153 default:
7154 bad_error("scf_instance_get_name", scf_error());
7155 }
7156 }
7157
7158 if (g_verbose)
7159 warn(gettext(
7160 "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
7161 snap_previous, s->sc_name, imp_str);
7162
7163 r = take_snap(imp_inst, snap_previous, imp_snap);
7164 switch (r) {
7165 case 0:
7166 break;
7167
7168 case ECANCELED:
7169 continue;
7170
7171 case ECONNABORTED:
7172 goto connaborted;
7173
7174 case EPERM:
7175 warn(gettext("Could not take \"%s\" snapshot of "
7176 "svc:/%s:%s (permission denied).\n"),
7177 snap_previous, s->sc_name, imp_str);
7178 lcbdata->sc_err = r;
7179 return (UU_WALK_ERROR);
7180
7181 case ENOSPC:
7182 case -1:
7183 lcbdata->sc_err = r;
7184 r = UU_WALK_ERROR;
7185 goto deltemp;
7186
7187 default:
7188 bad_error("take_snap", r);
7189 }
7190
7191 linst.sc_name = imp_str;
7192 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
7193 &linst, NULL, NULL);
7194 if (inst != NULL) {
7195 inst->sc_import_state = IMPORT_PREVIOUS;
7196 inst->sc_seen = 1;
7197 }
7198 }
7199
7200 /*
7201 * Create the new instances and take previous snapshots of
7202 * them. This is not necessary, but it maximizes data preservation.
7203 */
7204 for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
7205 inst != NULL;
7206 inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
7207 inst)) {
7208 if (inst->sc_seen)
7209 continue;
7210
7211 if (scf_service_add_instance(imp_svc, inst->sc_name,
7212 imp_inst) != 0) {
7213 switch (scf_error()) {
7214 case SCF_ERROR_CONNECTION_BROKEN:
7215 goto connaborted;
7216
7217 case SCF_ERROR_BACKEND_READONLY:
7218 case SCF_ERROR_BACKEND_ACCESS:
7219 case SCF_ERROR_NO_RESOURCES:
7220 r = stash_scferror(lcbdata);
7221 goto deltemp;
7222
7223 case SCF_ERROR_EXISTS:
7224 warn(gettext("%s changed unexpectedly "
7225 "(instance \"%s\" added).\n"), s->sc_fmri,
7226 inst->sc_name);
7227 lcbdata->sc_err = EBUSY;
7228 r = UU_WALK_ERROR;
7229 goto deltemp;
7230
7231 case SCF_ERROR_INVALID_ARGUMENT:
7232 warn(gettext("Service \"%s\" has instance with "
7233 "invalid name \"%s\".\n"), s->sc_name,
7234 inst->sc_name);
7235 r = stash_scferror(lcbdata);
7236 goto deltemp;
7237
7238 case SCF_ERROR_PERMISSION_DENIED:
7239 warn(gettext("Could not create instance \"%s\" "
7240 "in %s (permission denied).\n"),
7241 inst->sc_name, s->sc_fmri);
7242 r = stash_scferror(lcbdata);
7243 goto deltemp;
7244
7245 case SCF_ERROR_HANDLE_MISMATCH:
7246 case SCF_ERROR_NOT_BOUND:
7247 case SCF_ERROR_NOT_SET:
7248 default:
7249 bad_error("scf_service_add_instance",
7250 scf_error());
7251 }
7252 }
7253
7254 if (g_verbose)
7255 warn(gettext("Taking \"%s\" snapshot for "
7256 "new service %s.\n"), snap_previous, inst->sc_fmri);
7257 r = take_snap(imp_inst, snap_previous, imp_snap);
7258 switch (r) {
7259 case 0:
7260 break;
7261
7262 case ECANCELED:
7263 warn(i_deleted, s->sc_fmri, inst->sc_name);
7264 lcbdata->sc_err = EBUSY;
7265 r = UU_WALK_ERROR;
7266 goto deltemp;
7267
7268 case ECONNABORTED:
7269 goto connaborted;
7270
7271 case EPERM:
7272 warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
7273 lcbdata->sc_err = r;
7274 r = UU_WALK_ERROR;
7275 goto deltemp;
7276
7277 case ENOSPC:
7278 case -1:
7279 r = UU_WALK_ERROR;
7280 goto deltemp;
7281
7282 default:
7283 bad_error("take_snap", r);
7284 }
7285 }
7286
7287 s->sc_import_state = IMPORT_PREVIOUS;
7288
7289 /*
7290 * Upgrade service properties, if we can find a last-import snapshot.
7291 * Any will do because we don't support different service properties
7292 * in different manifests, so all snaplevels of the service in all of
7293 * the last-import snapshots of the instances should be the same.
7294 */
7295 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7296 switch (scf_error()) {
7297 case SCF_ERROR_CONNECTION_BROKEN:
7298 goto connaborted;
7299
7300 case SCF_ERROR_DELETED:
7301 warn(s_deleted, s->sc_fmri);
7302 lcbdata->sc_err = EBUSY;
7303 r = UU_WALK_ERROR;
7304 goto deltemp;
7305
7306 case SCF_ERROR_HANDLE_MISMATCH:
7307 case SCF_ERROR_NOT_BOUND:
7308 case SCF_ERROR_NOT_SET:
7309 default:
7310 bad_error("scf_iter_service_instances", scf_error());
7311 }
7312 }
7313
7314 for (;;) {
7315 r = scf_iter_next_instance(imp_iter, imp_inst);
7316 if (r == -1) {
7317 switch (scf_error()) {
7318 case SCF_ERROR_DELETED:
7319 warn(s_deleted, s->sc_fmri);
7320 lcbdata->sc_err = EBUSY;
7321 r = UU_WALK_ERROR;
7322 goto deltemp;
7323
7324 case SCF_ERROR_CONNECTION_BROKEN:
7325 goto connaborted;
7326
7327 case SCF_ERROR_NOT_BOUND:
7328 case SCF_ERROR_HANDLE_MISMATCH:
7329 case SCF_ERROR_INVALID_ARGUMENT:
7330 case SCF_ERROR_NOT_SET:
7331 default:
7332 bad_error("scf_iter_next_instance",
7333 scf_error());
7334 }
7335 }
7336
7337 if (r == 0) {
7338 /*
7339 * Didn't find any last-import snapshots. Override-
7340 * import the properties. Unless one of the instances
7341 * has a general/enabled property, in which case we're
7342 * probably running a last-import-capable svccfg for
7343 * the first time, and we should only take the
7344 * last-import snapshot.
7345 */
7346 if (have_ge) {
7347 pgroup_t *mfpg;
7348 scf_callback_t mfcbdata;
7349
7350 li_only = 1;
7351 no_refresh = 1;
7352 /*
7353 * Need to go ahead and import the manifestfiles
7354 * pg if it exists. If the last-import snapshot
7355 * upgrade code is ever removed this code can
7356 * be removed as well.
7357 */
7358 mfpg = internal_pgroup_find(s,
7359 SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
7360
7361 if (mfpg) {
7362 mfcbdata.sc_handle = g_hndl;
7363 mfcbdata.sc_parent = imp_svc;
7364 mfcbdata.sc_service = 1;
7365 mfcbdata.sc_flags = SCI_FORCE;
7366 mfcbdata.sc_source_fmri = s->sc_fmri;
7367 mfcbdata.sc_target_fmri = s->sc_fmri;
7368 if (entity_pgroup_import(mfpg,
7369 &mfcbdata) != UU_WALK_NEXT) {
7370 warn(s_mfile_upd, s->sc_fmri);
7371 r = UU_WALK_ERROR;
7372 goto deltemp;
7373 }
7374 }
7375 break;
7376 }
7377
7378 s->sc_import_state = IMPORT_PROP_BEGUN;
7379
7380 cbdata.sc_handle = g_hndl;
7381 cbdata.sc_parent = imp_svc;
7382 cbdata.sc_service = 1;
7383 cbdata.sc_flags = SCI_FORCE;
7384 cbdata.sc_source_fmri = s->sc_fmri;
7385 cbdata.sc_target_fmri = s->sc_fmri;
7386 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7387 &cbdata, UU_DEFAULT) != 0) {
7388 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7389 bad_error("uu_list_walk", uu_error());
7390 lcbdata->sc_err = cbdata.sc_err;
7391 switch (cbdata.sc_err) {
7392 case ECONNABORTED:
7393 goto connaborted;
7394
7395 case ECANCELED:
7396 warn(s_deleted, s->sc_fmri);
7397 lcbdata->sc_err = EBUSY;
7398 break;
7399
7400 case EINVAL: /* caught above */
7401 case EEXIST:
7402 bad_error("entity_pgroup_import",
7403 cbdata.sc_err);
7404 }
7405
7406 r = UU_WALK_ERROR;
7407 goto deltemp;
7408 }
7409
7410 cbdata.sc_trans = NULL;
7411 cbdata.sc_flags = 0;
7412 if (uu_list_walk(s->sc_dependents,
7413 lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
7414 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7415 bad_error("uu_list_walk", uu_error());
7416 lcbdata->sc_err = cbdata.sc_err;
7417 if (cbdata.sc_err == ECONNABORTED)
7418 goto connaborted;
7419 r = UU_WALK_ERROR;
7420 goto deltemp;
7421 }
7422 break;
7423 }
7424
7425 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
7426 imp_snap) != 0) {
7427 switch (scf_error()) {
7428 case SCF_ERROR_DELETED:
7429 continue;
7430
7431 case SCF_ERROR_NOT_FOUND:
7432 break;
7433
7434 case SCF_ERROR_CONNECTION_BROKEN:
7435 goto connaborted;
7436
7437 case SCF_ERROR_HANDLE_MISMATCH:
7438 case SCF_ERROR_NOT_BOUND:
7439 case SCF_ERROR_INVALID_ARGUMENT:
7440 case SCF_ERROR_NOT_SET:
7441 default:
7442 bad_error("scf_instance_get_snapshot",
7443 scf_error());
7444 }
7445
7446 if (have_ge)
7447 continue;
7448
7449 /*
7450 * Check for a general/enabled property. This is how
7451 * we tell whether to import if there turn out to be
7452 * no last-import snapshots.
7453 */
7454 if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
7455 imp_pg) == 0) {
7456 if (scf_pg_get_property(imp_pg,
7457 SCF_PROPERTY_ENABLED, imp_prop) == 0) {
7458 have_ge = 1;
7459 } else {
7460 switch (scf_error()) {
7461 case SCF_ERROR_DELETED:
7462 case SCF_ERROR_NOT_FOUND:
7463 continue;
7464
7465 case SCF_ERROR_INVALID_ARGUMENT:
7466 case SCF_ERROR_HANDLE_MISMATCH:
7467 case SCF_ERROR_CONNECTION_BROKEN:
7468 case SCF_ERROR_NOT_BOUND:
7469 case SCF_ERROR_NOT_SET:
7470 default:
7471 bad_error("scf_pg_get_property",
7472 scf_error());
7473 }
7474 }
7475 } else {
7476 switch (scf_error()) {
7477 case SCF_ERROR_DELETED:
7478 case SCF_ERROR_NOT_FOUND:
7479 continue;
7480
7481 case SCF_ERROR_CONNECTION_BROKEN:
7482 goto connaborted;
7483
7484 case SCF_ERROR_NOT_BOUND:
7485 case SCF_ERROR_NOT_SET:
7486 case SCF_ERROR_INVALID_ARGUMENT:
7487 case SCF_ERROR_HANDLE_MISMATCH:
7488 default:
7489 bad_error("scf_instance_get_pg",
7490 scf_error());
7491 }
7492 }
7493 continue;
7494 }
7495
7496 /* find service snaplevel */
7497 r = get_snaplevel(imp_snap, 1, imp_snpl);
7498 switch (r) {
7499 case 0:
7500 break;
7501
7502 case ECONNABORTED:
7503 goto connaborted;
7504
7505 case ECANCELED:
7506 continue;
7507
7508 case ENOENT:
7509 if (scf_instance_get_name(imp_inst, imp_str,
7510 imp_str_sz) < 0)
7511 (void) strcpy(imp_str, "?");
7512 warn(badsnap, snap_lastimport, s->sc_name, imp_str);
7513 lcbdata->sc_err = EBADF;
7514 r = UU_WALK_ERROR;
7515 goto deltemp;
7516
7517 default:
7518 bad_error("get_snaplevel", r);
7519 }
7520
7521 if (scf_instance_get_snapshot(imp_inst, snap_running,
7522 imp_rsnap) != 0) {
7523 switch (scf_error()) {
7524 case SCF_ERROR_DELETED:
7525 continue;
7526
7527 case SCF_ERROR_NOT_FOUND:
7528 break;
7529
7530 case SCF_ERROR_CONNECTION_BROKEN:
7531 goto connaborted;
7532
7533 case SCF_ERROR_INVALID_ARGUMENT:
7534 case SCF_ERROR_HANDLE_MISMATCH:
7535 case SCF_ERROR_NOT_BOUND:
7536 case SCF_ERROR_NOT_SET:
7537 default:
7538 bad_error("scf_instance_get_snapshot",
7539 scf_error());
7540 }
7541 running = NULL;
7542 } else {
7543 r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
7544 switch (r) {
7545 case 0:
7546 running = imp_rsnpl;
7547 break;
7548
7549 case ECONNABORTED:
7550 goto connaborted;
7551
7552 case ECANCELED:
7553 continue;
7554
7555 case ENOENT:
7556 if (scf_instance_get_name(imp_inst, imp_str,
7557 imp_str_sz) < 0)
7558 (void) strcpy(imp_str, "?");
7559 warn(badsnap, snap_running, s->sc_name,
7560 imp_str);
7561 lcbdata->sc_err = EBADF;
7562 r = UU_WALK_ERROR;
7563 goto deltemp;
7564
7565 default:
7566 bad_error("get_snaplevel", r);
7567 }
7568 }
7569
7570 if (g_verbose) {
7571 if (scf_instance_get_name(imp_inst, imp_str,
7572 imp_str_sz) < 0)
7573 (void) strcpy(imp_str, "?");
7574 warn(gettext("Upgrading properties of %s according to "
7575 "instance \"%s\".\n"), s->sc_fmri, imp_str);
7576 }
7577
7578 /* upgrade service properties */
7579 r = upgrade_props(imp_svc, running, imp_snpl, s);
7580 if (r == 0)
7581 break;
7582
7583 switch (r) {
7584 case ECONNABORTED:
7585 goto connaborted;
7586
7587 case ECANCELED:
7588 warn(s_deleted, s->sc_fmri);
7589 lcbdata->sc_err = EBUSY;
7590 break;
7591
7592 case ENODEV:
7593 if (scf_instance_get_name(imp_inst, imp_str,
7594 imp_str_sz) < 0)
7595 (void) strcpy(imp_str, "?");
7596 warn(i_deleted, s->sc_fmri, imp_str);
7597 lcbdata->sc_err = EBUSY;
7598 break;
7599
7600 default:
7601 lcbdata->sc_err = r;
7602 }
7603
7604 r = UU_WALK_ERROR;
7605 goto deltemp;
7606 }
7607
7608 s->sc_import_state = IMPORT_PROP_DONE;
7609
7610 instances:
7611 /* import instances */
7612 cbdata.sc_handle = lcbdata->sc_handle;
7613 cbdata.sc_parent = imp_svc;
7614 cbdata.sc_service = 1;
7615 cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7616 cbdata.sc_general = NULL;
7617
7618 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7619 lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7620 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7621 bad_error("uu_list_walk", uu_error());
7622
7623 lcbdata->sc_err = cbdata.sc_err;
7624 if (cbdata.sc_err == ECONNABORTED)
7625 goto connaborted;
7626 r = UU_WALK_ERROR;
7627 goto deltemp;
7628 }
7629
7630 s->sc_import_state = IMPORT_COMPLETE;
7631 r = UU_WALK_NEXT;
7632
7633 deltemp:
7634 /* delete temporary service */
7635 if (scf_service_delete(imp_tsvc) != 0) {
7636 switch (scf_error()) {
7637 case SCF_ERROR_DELETED:
7638 break;
7639
7640 case SCF_ERROR_CONNECTION_BROKEN:
7641 goto connaborted;
7642
7643 case SCF_ERROR_EXISTS:
7644 warn(gettext(
7645 "Could not delete svc:/%s (instances exist).\n"),
7646 imp_tsname);
7647 break;
7648
7649 case SCF_ERROR_NOT_SET:
7650 case SCF_ERROR_NOT_BOUND:
7651 default:
7652 bad_error("scf_service_delete", scf_error());
7653 }
7654 }
7655
7656 return (r);
7657
7658 connaborted:
7659 warn(gettext("Could not delete svc:/%s "
7660 "(repository connection broken).\n"), imp_tsname);
7661 lcbdata->sc_err = ECONNABORTED;
7662 return (UU_WALK_ERROR);
7663 }
7664
7665 static const char *
import_progress(int st)7666 import_progress(int st)
7667 {
7668 switch (st) {
7669 case 0:
7670 return (gettext("not reached."));
7671
7672 case IMPORT_PREVIOUS:
7673 return (gettext("previous snapshot taken."));
7674
7675 case IMPORT_PROP_BEGUN:
7676 return (gettext("some properties imported."));
7677
7678 case IMPORT_PROP_DONE:
7679 return (gettext("properties imported."));
7680
7681 case IMPORT_COMPLETE:
7682 return (gettext("imported."));
7683
7684 case IMPORT_REFRESHED:
7685 return (gettext("refresh requested."));
7686
7687 default:
7688 #ifndef NDEBUG
7689 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7690 __FILE__, __LINE__, st);
7691 #endif
7692 abort();
7693 /* NOTREACHED */
7694 }
7695 }
7696
7697 /*
7698 * Returns
7699 * 0 - success
7700 * - fmri wasn't found (error printed)
7701 * - entity was deleted (error printed)
7702 * - backend denied access (error printed)
7703 * ENOMEM - out of memory (error printed)
7704 * ECONNABORTED - repository connection broken (error printed)
7705 * EPERM - permission denied (error printed)
7706 * -1 - unknown libscf error (error printed)
7707 */
7708 static int
imp_refresh_fmri(const char * fmri,const char * name,const char * d_fmri)7709 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7710 {
7711 scf_error_t serr;
7712 void *ent;
7713 int issvc;
7714 int r;
7715
7716 const char *deleted = gettext("Could not refresh %s (deleted).\n");
7717 const char *dpt_deleted = gettext("Could not refresh %s "
7718 "(dependent \"%s\" of %s) (deleted).\n");
7719
7720 serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7721 switch (serr) {
7722 case SCF_ERROR_NONE:
7723 break;
7724
7725 case SCF_ERROR_NO_MEMORY:
7726 if (name == NULL)
7727 warn(gettext("Could not refresh %s (out of memory).\n"),
7728 fmri);
7729 else
7730 warn(gettext("Could not refresh %s "
7731 "(dependent \"%s\" of %s) (out of memory).\n"),
7732 fmri, name, d_fmri);
7733 return (ENOMEM);
7734
7735 case SCF_ERROR_NOT_FOUND:
7736 if (name == NULL)
7737 warn(deleted, fmri);
7738 else
7739 warn(dpt_deleted, fmri, name, d_fmri);
7740 return (0);
7741
7742 case SCF_ERROR_INVALID_ARGUMENT:
7743 case SCF_ERROR_CONSTRAINT_VIOLATED:
7744 default:
7745 bad_error("fmri_to_entity", serr);
7746 }
7747
7748 r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7749 switch (r) {
7750 case 0:
7751 break;
7752
7753 case ECONNABORTED:
7754 if (name != NULL)
7755 warn(gettext("Could not refresh %s "
7756 "(dependent \"%s\" of %s) "
7757 "(repository connection broken).\n"), fmri, name,
7758 d_fmri);
7759 return (r);
7760
7761 case ECANCELED:
7762 if (name == NULL)
7763 warn(deleted, fmri);
7764 else
7765 warn(dpt_deleted, fmri, name, d_fmri);
7766 return (0);
7767
7768 case EACCES:
7769 if (!g_verbose)
7770 return (0);
7771 if (name == NULL)
7772 warn(gettext("Could not refresh %s "
7773 "(backend access denied).\n"), fmri);
7774 else
7775 warn(gettext("Could not refresh %s "
7776 "(dependent \"%s\" of %s) "
7777 "(backend access denied).\n"), fmri, name, d_fmri);
7778 return (0);
7779
7780 case EPERM:
7781 if (name == NULL)
7782 warn(gettext("Could not refresh %s "
7783 "(permission denied).\n"), fmri);
7784 else
7785 warn(gettext("Could not refresh %s "
7786 "(dependent \"%s\" of %s) "
7787 "(permission denied).\n"), fmri, name, d_fmri);
7788 return (r);
7789
7790 case ENOSPC:
7791 if (name == NULL)
7792 warn(gettext("Could not refresh %s "
7793 "(repository server out of resources).\n"),
7794 fmri);
7795 else
7796 warn(gettext("Could not refresh %s "
7797 "(dependent \"%s\" of %s) "
7798 "(repository server out of resources).\n"),
7799 fmri, name, d_fmri);
7800 return (r);
7801
7802 case -1:
7803 scfwarn();
7804 return (r);
7805
7806 default:
7807 bad_error("refresh_entity", r);
7808 }
7809
7810 if (issvc)
7811 scf_service_destroy(ent);
7812 else
7813 scf_instance_destroy(ent);
7814
7815 return (0);
7816 }
7817
7818 static int
alloc_imp_globals()7819 alloc_imp_globals()
7820 {
7821 int r;
7822
7823 const char * const emsg_nomem = gettext("Out of memory.\n");
7824 const char * const emsg_nores =
7825 gettext("svc.configd is out of resources.\n");
7826
7827 imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
7828 max_scf_name_len : max_scf_fmri_len) + 1;
7829
7830 if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
7831 (imp_svc = scf_service_create(g_hndl)) == NULL ||
7832 (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
7833 (imp_inst = scf_instance_create(g_hndl)) == NULL ||
7834 (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
7835 (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
7836 (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
7837 (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
7838 (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
7839 (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
7840 (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
7841 (imp_pg = scf_pg_create(g_hndl)) == NULL ||
7842 (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
7843 (imp_prop = scf_property_create(g_hndl)) == NULL ||
7844 (imp_iter = scf_iter_create(g_hndl)) == NULL ||
7845 (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
7846 (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
7847 (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
7848 (imp_str = malloc(imp_str_sz)) == NULL ||
7849 (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
7850 (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
7851 (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
7852 (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
7853 (ud_inst = scf_instance_create(g_hndl)) == NULL ||
7854 (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
7855 (ud_pg = scf_pg_create(g_hndl)) == NULL ||
7856 (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
7857 (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
7858 (ud_prop = scf_property_create(g_hndl)) == NULL ||
7859 (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
7860 (ud_val = scf_value_create(g_hndl)) == NULL ||
7861 (ud_iter = scf_iter_create(g_hndl)) == NULL ||
7862 (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
7863 (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
7864 (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
7865 (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
7866 (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
7867 if (scf_error() == SCF_ERROR_NO_RESOURCES)
7868 warn(emsg_nores);
7869 else
7870 warn(emsg_nomem);
7871
7872 return (-1);
7873 }
7874
7875 r = load_init();
7876 switch (r) {
7877 case 0:
7878 break;
7879
7880 case ENOMEM:
7881 warn(emsg_nomem);
7882 return (-1);
7883
7884 default:
7885 bad_error("load_init", r);
7886 }
7887
7888 return (0);
7889 }
7890
7891 static void
free_imp_globals()7892 free_imp_globals()
7893 {
7894 pgroup_t *old_dpt;
7895 void *cookie;
7896
7897 load_fini();
7898
7899 free(ud_ctarg);
7900 free(ud_oldtarg);
7901 free(ud_name);
7902 ud_ctarg = ud_oldtarg = ud_name = NULL;
7903
7904 scf_transaction_destroy(ud_tx);
7905 ud_tx = NULL;
7906 scf_iter_destroy(ud_iter);
7907 scf_iter_destroy(ud_iter2);
7908 ud_iter = ud_iter2 = NULL;
7909 scf_value_destroy(ud_val);
7910 ud_val = NULL;
7911 scf_property_destroy(ud_prop);
7912 scf_property_destroy(ud_dpt_prop);
7913 ud_prop = ud_dpt_prop = NULL;
7914 scf_pg_destroy(ud_pg);
7915 scf_pg_destroy(ud_cur_depts_pg);
7916 scf_pg_destroy(ud_run_dpts_pg);
7917 ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
7918 scf_snaplevel_destroy(ud_snpl);
7919 ud_snpl = NULL;
7920 scf_instance_destroy(ud_inst);
7921 ud_inst = NULL;
7922
7923 free(imp_str);
7924 free(imp_tsname);
7925 free(imp_fe1);
7926 free(imp_fe2);
7927 imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
7928
7929 cookie = NULL;
7930 while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
7931 NULL) {
7932 free((char *)old_dpt->sc_pgroup_name);
7933 free((char *)old_dpt->sc_pgroup_fmri);
7934 internal_pgroup_free(old_dpt);
7935 }
7936 uu_list_destroy(imp_deleted_dpts);
7937
7938 scf_transaction_destroy(imp_tx);
7939 imp_tx = NULL;
7940 scf_iter_destroy(imp_iter);
7941 scf_iter_destroy(imp_rpg_iter);
7942 scf_iter_destroy(imp_up_iter);
7943 imp_iter = imp_rpg_iter = imp_up_iter = NULL;
7944 scf_property_destroy(imp_prop);
7945 imp_prop = NULL;
7946 scf_pg_destroy(imp_pg);
7947 scf_pg_destroy(imp_pg2);
7948 imp_pg = imp_pg2 = NULL;
7949 scf_snaplevel_destroy(imp_snpl);
7950 scf_snaplevel_destroy(imp_rsnpl);
7951 imp_snpl = imp_rsnpl = NULL;
7952 scf_snapshot_destroy(imp_snap);
7953 scf_snapshot_destroy(imp_lisnap);
7954 scf_snapshot_destroy(imp_tlisnap);
7955 scf_snapshot_destroy(imp_rsnap);
7956 imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
7957 scf_instance_destroy(imp_inst);
7958 scf_instance_destroy(imp_tinst);
7959 imp_inst = imp_tinst = NULL;
7960 scf_service_destroy(imp_svc);
7961 scf_service_destroy(imp_tsvc);
7962 imp_svc = imp_tsvc = NULL;
7963 scf_scope_destroy(imp_scope);
7964 imp_scope = NULL;
7965
7966 load_fini();
7967 }
7968
7969 int
lscf_bundle_import(bundle_t * bndl,const char * filename,uint_t flags)7970 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
7971 {
7972 scf_callback_t cbdata;
7973 int result = 0;
7974 entity_t *svc, *inst;
7975 uu_list_t *insts;
7976 int r;
7977 pgroup_t *old_dpt;
7978 int annotation_set = 0;
7979
7980 const char * const emsg_nomem = gettext("Out of memory.\n");
7981 const char * const emsg_nores =
7982 gettext("svc.configd is out of resources.\n");
7983
7984 lscf_prep_hndl();
7985
7986 if (alloc_imp_globals())
7987 goto out;
7988
7989 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
7990 switch (scf_error()) {
7991 case SCF_ERROR_CONNECTION_BROKEN:
7992 warn(gettext("Repository connection broken.\n"));
7993 repository_teardown();
7994 result = -1;
7995 goto out;
7996
7997 case SCF_ERROR_NOT_FOUND:
7998 case SCF_ERROR_INVALID_ARGUMENT:
7999 case SCF_ERROR_NOT_BOUND:
8000 case SCF_ERROR_HANDLE_MISMATCH:
8001 default:
8002 bad_error("scf_handle_get_scope", scf_error());
8003 }
8004 }
8005
8006 /* Set up the auditing annotation. */
8007 if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
8008 annotation_set = 1;
8009 } else {
8010 switch (scf_error()) {
8011 case SCF_ERROR_CONNECTION_BROKEN:
8012 warn(gettext("Repository connection broken.\n"));
8013 repository_teardown();
8014 result = -1;
8015 goto out;
8016
8017 case SCF_ERROR_INVALID_ARGUMENT:
8018 case SCF_ERROR_NOT_BOUND:
8019 case SCF_ERROR_NO_RESOURCES:
8020 case SCF_ERROR_INTERNAL:
8021 bad_error("_scf_set_annotation", scf_error());
8022 /* NOTREACHED */
8023
8024 default:
8025 /*
8026 * Do not terminate import because of inability to
8027 * generate annotation audit event.
8028 */
8029 warn(gettext("_scf_set_annotation() unexpectedly "
8030 "failed with return code of %d\n"), scf_error());
8031 break;
8032 }
8033 }
8034
8035 /*
8036 * Clear the sc_import_state's of all services & instances so we can
8037 * report how far we got if we fail.
8038 */
8039 for (svc = uu_list_first(bndl->sc_bundle_services);
8040 svc != NULL;
8041 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8042 svc->sc_import_state = 0;
8043
8044 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
8045 clear_int, (void *)offsetof(entity_t, sc_import_state),
8046 UU_DEFAULT) != 0)
8047 bad_error("uu_list_walk", uu_error());
8048 }
8049
8050 cbdata.sc_handle = g_hndl;
8051 cbdata.sc_parent = imp_scope;
8052 cbdata.sc_flags = flags;
8053 cbdata.sc_general = NULL;
8054
8055 if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
8056 &cbdata, UU_DEFAULT) == 0) {
8057 /* Success. Refresh everything. */
8058
8059 if (flags & SCI_NOREFRESH || no_refresh) {
8060 no_refresh = 0;
8061 result = 0;
8062 goto out;
8063 }
8064
8065 for (svc = uu_list_first(bndl->sc_bundle_services);
8066 svc != NULL;
8067 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8068 pgroup_t *dpt;
8069
8070 insts = svc->sc_u.sc_service.sc_service_instances;
8071
8072 for (inst = uu_list_first(insts);
8073 inst != NULL;
8074 inst = uu_list_next(insts, inst)) {
8075 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
8076 switch (r) {
8077 case 0:
8078 break;
8079
8080 case ENOMEM:
8081 case ECONNABORTED:
8082 case EPERM:
8083 case -1:
8084 goto progress;
8085
8086 default:
8087 bad_error("imp_refresh_fmri", r);
8088 }
8089
8090 inst->sc_import_state = IMPORT_REFRESHED;
8091
8092 for (dpt = uu_list_first(inst->sc_dependents);
8093 dpt != NULL;
8094 dpt = uu_list_next(inst->sc_dependents,
8095 dpt))
8096 if (imp_refresh_fmri(
8097 dpt->sc_pgroup_fmri,
8098 dpt->sc_pgroup_name,
8099 inst->sc_fmri) != 0)
8100 goto progress;
8101 }
8102
8103 for (dpt = uu_list_first(svc->sc_dependents);
8104 dpt != NULL;
8105 dpt = uu_list_next(svc->sc_dependents, dpt))
8106 if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
8107 dpt->sc_pgroup_name, svc->sc_fmri) != 0)
8108 goto progress;
8109 }
8110
8111 for (old_dpt = uu_list_first(imp_deleted_dpts);
8112 old_dpt != NULL;
8113 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
8114 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8115 old_dpt->sc_pgroup_name,
8116 old_dpt->sc_parent->sc_fmri) != 0)
8117 goto progress;
8118
8119 result = 0;
8120 goto out;
8121 }
8122
8123 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8124 bad_error("uu_list_walk", uu_error());
8125
8126 printerr:
8127 /* If the error hasn't been printed yet, do so here. */
8128 switch (cbdata.sc_err) {
8129 case ECONNABORTED:
8130 warn(gettext("Repository connection broken.\n"));
8131 break;
8132
8133 case ENOMEM:
8134 warn(emsg_nomem);
8135 break;
8136
8137 case ENOSPC:
8138 warn(emsg_nores);
8139 break;
8140
8141 case EROFS:
8142 warn(gettext("Repository is read-only.\n"));
8143 break;
8144
8145 case EACCES:
8146 warn(gettext("Repository backend denied access.\n"));
8147 break;
8148
8149 case EPERM:
8150 case EINVAL:
8151 case EEXIST:
8152 case EBUSY:
8153 case EBADF:
8154 case -1:
8155 break;
8156
8157 default:
8158 bad_error("lscf_service_import", cbdata.sc_err);
8159 }
8160
8161 progress:
8162 warn(gettext("Import of %s failed. Progress:\n"), filename);
8163
8164 for (svc = uu_list_first(bndl->sc_bundle_services);
8165 svc != NULL;
8166 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8167 insts = svc->sc_u.sc_service.sc_service_instances;
8168
8169 warn(gettext(" Service \"%s\": %s\n"), svc->sc_name,
8170 import_progress(svc->sc_import_state));
8171
8172 for (inst = uu_list_first(insts);
8173 inst != NULL;
8174 inst = uu_list_next(insts, inst))
8175 warn(gettext(" Instance \"%s\": %s\n"),
8176 inst->sc_name,
8177 import_progress(inst->sc_import_state));
8178 }
8179
8180 if (cbdata.sc_err == ECONNABORTED)
8181 repository_teardown();
8182
8183
8184 result = -1;
8185
8186 out:
8187 if (annotation_set != 0) {
8188 /* Turn off annotation. It is no longer needed. */
8189 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8190 }
8191
8192 free_imp_globals();
8193
8194 return (result);
8195 }
8196
8197 /*
8198 * _lscf_import_err() summarize the error handling returned by
8199 * lscf_import_{instance | service}_pgs
8200 * Return values are:
8201 * IMPORT_NEXT
8202 * IMPORT_OUT
8203 * IMPORT_BAD
8204 */
8205
8206 #define IMPORT_BAD -1
8207 #define IMPORT_NEXT 0
8208 #define IMPORT_OUT 1
8209
8210 static int
_lscf_import_err(int err,const char * fmri)8211 _lscf_import_err(int err, const char *fmri)
8212 {
8213 switch (err) {
8214 case 0:
8215 if (g_verbose)
8216 warn(gettext("%s updated.\n"), fmri);
8217 return (IMPORT_NEXT);
8218
8219 case ECONNABORTED:
8220 warn(gettext("Could not update %s "
8221 "(repository connection broken).\n"), fmri);
8222 return (IMPORT_OUT);
8223
8224 case ENOMEM:
8225 warn(gettext("Could not update %s (out of memory).\n"), fmri);
8226 return (IMPORT_OUT);
8227
8228 case ENOSPC:
8229 warn(gettext("Could not update %s "
8230 "(repository server out of resources).\n"), fmri);
8231 return (IMPORT_OUT);
8232
8233 case ECANCELED:
8234 warn(gettext(
8235 "Could not update %s (deleted).\n"), fmri);
8236 return (IMPORT_NEXT);
8237
8238 case EPERM:
8239 case EINVAL:
8240 case EBUSY:
8241 return (IMPORT_NEXT);
8242
8243 case EROFS:
8244 warn(gettext("Could not update %s (repository read-only).\n"),
8245 fmri);
8246 return (IMPORT_OUT);
8247
8248 case EACCES:
8249 warn(gettext("Could not update %s "
8250 "(backend access denied).\n"), fmri);
8251 return (IMPORT_NEXT);
8252
8253 case EEXIST:
8254 default:
8255 return (IMPORT_BAD);
8256 }
8257
8258 /*NOTREACHED*/
8259 }
8260
8261 /*
8262 * The global imp_svc and imp_inst should be set by the caller in the
8263 * check to make sure the service and instance exist that the apply is
8264 * working on.
8265 */
8266 static int
lscf_dependent_apply(void * dpg,void * e)8267 lscf_dependent_apply(void *dpg, void *e)
8268 {
8269 scf_callback_t cb;
8270 pgroup_t *dpt_pgroup = dpg;
8271 pgroup_t *deldpt;
8272 entity_t *ent = e;
8273 int tissvc;
8274 void *sc_ent, *tent;
8275 scf_error_t serr;
8276 int r;
8277
8278 const char * const dependents = "dependents";
8279 const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT);
8280
8281 if (issvc)
8282 sc_ent = imp_svc;
8283 else
8284 sc_ent = imp_inst;
8285
8286 if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg,
8287 imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 ||
8288 scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name,
8289 imp_prop) != 0) {
8290 switch (scf_error()) {
8291 case SCF_ERROR_NOT_FOUND:
8292 case SCF_ERROR_DELETED:
8293 break;
8294
8295 case SCF_ERROR_CONNECTION_BROKEN:
8296 case SCF_ERROR_NOT_SET:
8297 case SCF_ERROR_INVALID_ARGUMENT:
8298 case SCF_ERROR_HANDLE_MISMATCH:
8299 case SCF_ERROR_NOT_BOUND:
8300 default:
8301 bad_error("entity_get_pg", scf_error());
8302 }
8303 } else {
8304 /*
8305 * Found the dependents/<wip dep> so check to
8306 * see if the service is different. If so
8307 * store the service for later refresh, and
8308 * delete the wip dependency from the service
8309 */
8310 if (scf_property_get_value(imp_prop, ud_val) != 0) {
8311 switch (scf_error()) {
8312 case SCF_ERROR_DELETED:
8313 break;
8314
8315 case SCF_ERROR_CONNECTION_BROKEN:
8316 case SCF_ERROR_NOT_SET:
8317 case SCF_ERROR_INVALID_ARGUMENT:
8318 case SCF_ERROR_HANDLE_MISMATCH:
8319 case SCF_ERROR_NOT_BOUND:
8320 default:
8321 bad_error("scf_property_get_value",
8322 scf_error());
8323 }
8324 }
8325
8326 if (scf_value_get_as_string(ud_val, ud_oldtarg,
8327 max_scf_value_len + 1) < 0)
8328 bad_error("scf_value_get_as_string", scf_error());
8329
8330 r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
8331 switch (r) {
8332 case 1:
8333 break;
8334 case 0:
8335 if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent,
8336 &tissvc)) != SCF_ERROR_NONE) {
8337 if (serr == SCF_ERROR_NOT_FOUND) {
8338 break;
8339 } else {
8340 bad_error("fmri_to_entity", serr);
8341 }
8342 }
8343
8344 if (entity_get_pg(tent, tissvc,
8345 dpt_pgroup->sc_pgroup_name, imp_pg) != 0) {
8346 serr = scf_error();
8347 if (serr == SCF_ERROR_NOT_FOUND ||
8348 serr == SCF_ERROR_DELETED) {
8349 break;
8350 } else {
8351 bad_error("entity_get_pg", scf_error());
8352 }
8353 }
8354
8355 if (scf_pg_delete(imp_pg) != 0) {
8356 serr = scf_error();
8357 if (serr == SCF_ERROR_NOT_FOUND ||
8358 serr == SCF_ERROR_DELETED) {
8359 break;
8360 } else {
8361 bad_error("scf_pg_delete", scf_error());
8362 }
8363 }
8364
8365 deldpt = internal_pgroup_new();
8366 if (deldpt == NULL)
8367 return (ENOMEM);
8368 deldpt->sc_pgroup_name =
8369 strdup(dpt_pgroup->sc_pgroup_name);
8370 deldpt->sc_pgroup_fmri = strdup(ud_oldtarg);
8371 if (deldpt->sc_pgroup_name == NULL ||
8372 deldpt->sc_pgroup_fmri == NULL)
8373 return (ENOMEM);
8374 deldpt->sc_parent = (entity_t *)ent;
8375 if (uu_list_insert_after(imp_deleted_dpts, NULL,
8376 deldpt) != 0)
8377 uu_die(gettext("libuutil error: %s\n"),
8378 uu_strerror(uu_error()));
8379
8380 break;
8381 default:
8382 bad_error("fmri_equal", r);
8383 }
8384 }
8385
8386 cb.sc_handle = g_hndl;
8387 cb.sc_parent = ent;
8388 cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT;
8389 cb.sc_source_fmri = ent->sc_fmri;
8390 cb.sc_target_fmri = ent->sc_fmri;
8391 cb.sc_trans = NULL;
8392 cb.sc_flags = SCI_FORCE;
8393
8394 if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT)
8395 return (UU_WALK_ERROR);
8396
8397 r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL);
8398 switch (r) {
8399 case 0:
8400 break;
8401
8402 case ENOMEM:
8403 case ECONNABORTED:
8404 case EPERM:
8405 case -1:
8406 warn(gettext("Unable to refresh \"%s\"\n"),
8407 dpt_pgroup->sc_pgroup_fmri);
8408 return (UU_WALK_ERROR);
8409
8410 default:
8411 bad_error("imp_refresh_fmri", r);
8412 }
8413
8414 return (UU_WALK_NEXT);
8415 }
8416
8417 /*
8418 * Returns
8419 * 0 - success
8420 * -1 - lscf_import_instance_pgs() failed.
8421 */
8422 int
lscf_bundle_apply(bundle_t * bndl,const char * file)8423 lscf_bundle_apply(bundle_t *bndl, const char *file)
8424 {
8425 pgroup_t *old_dpt;
8426 entity_t *svc, *inst;
8427 int annotation_set = 0;
8428 int ret = 0;
8429 int r = 0;
8430
8431 lscf_prep_hndl();
8432
8433 if ((ret = alloc_imp_globals()))
8434 goto out;
8435
8436 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0)
8437 scfdie();
8438
8439 /*
8440 * Set the strings to be used for the security audit annotation
8441 * event.
8442 */
8443 if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
8444 annotation_set = 1;
8445 } else {
8446 switch (scf_error()) {
8447 case SCF_ERROR_CONNECTION_BROKEN:
8448 warn(gettext("Repository connection broken.\n"));
8449 goto out;
8450
8451 case SCF_ERROR_INVALID_ARGUMENT:
8452 case SCF_ERROR_NOT_BOUND:
8453 case SCF_ERROR_NO_RESOURCES:
8454 case SCF_ERROR_INTERNAL:
8455 bad_error("_scf_set_annotation", scf_error());
8456 /* NOTREACHED */
8457
8458 default:
8459 /*
8460 * Do not abort apply operation because of
8461 * inability to create annotation audit event.
8462 */
8463 warn(gettext("_scf_set_annotation() unexpectedly "
8464 "failed with return code of %d\n"), scf_error());
8465 break;
8466 }
8467 }
8468
8469 for (svc = uu_list_first(bndl->sc_bundle_services);
8470 svc != NULL;
8471 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8472 int refresh = 0;
8473
8474 if (scf_scope_get_service(imp_scope, svc->sc_name,
8475 imp_svc) != 0) {
8476 switch (scf_error()) {
8477 case SCF_ERROR_NOT_FOUND:
8478 if (g_verbose)
8479 warn(gettext("Ignoring nonexistent "
8480 "service %s.\n"), svc->sc_name);
8481 continue;
8482
8483 default:
8484 scfdie();
8485 }
8486 }
8487
8488 /*
8489 * If there were missing types in the profile, then need to
8490 * attempt to find the types.
8491 */
8492 if (svc->sc_miss_type) {
8493 if (uu_list_numnodes(svc->sc_pgroups) &&
8494 uu_list_walk(svc->sc_pgroups, find_current_pg_type,
8495 svc, UU_DEFAULT) != 0) {
8496 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8497 bad_error("uu_list_walk", uu_error());
8498
8499 ret = -1;
8500 continue;
8501 }
8502
8503 for (inst = uu_list_first(
8504 svc->sc_u.sc_service.sc_service_instances);
8505 inst != NULL;
8506 inst = uu_list_next(
8507 svc->sc_u.sc_service.sc_service_instances, inst)) {
8508 /*
8509 * If the instance doesn't exist just
8510 * skip to the next instance and let the
8511 * import note the missing instance.
8512 */
8513 if (scf_service_get_instance(imp_svc,
8514 inst->sc_name, imp_inst) != 0)
8515 continue;
8516
8517 if (uu_list_walk(inst->sc_pgroups,
8518 find_current_pg_type, inst,
8519 UU_DEFAULT) != 0) {
8520 if (uu_error() !=
8521 UU_ERROR_CALLBACK_FAILED)
8522 bad_error("uu_list_walk",
8523 uu_error());
8524
8525 ret = -1;
8526 inst->sc_miss_type = B_TRUE;
8527 }
8528 }
8529 }
8530
8531 /*
8532 * if we have pgs in the profile, we need to refresh ALL
8533 * instances of the service
8534 */
8535 if (uu_list_numnodes(svc->sc_pgroups) != 0) {
8536 refresh = 1;
8537 r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc,
8538 SCI_FORCE | SCI_KEEP);
8539 switch (_lscf_import_err(r, svc->sc_fmri)) {
8540 case IMPORT_NEXT:
8541 break;
8542
8543 case IMPORT_OUT:
8544 goto out;
8545
8546 case IMPORT_BAD:
8547 default:
8548 bad_error("lscf_import_service_pgs", r);
8549 }
8550 }
8551
8552 if (uu_list_numnodes(svc->sc_dependents) != 0) {
8553 uu_list_walk(svc->sc_dependents,
8554 lscf_dependent_apply, svc, UU_DEFAULT);
8555 }
8556
8557 for (inst = uu_list_first(
8558 svc->sc_u.sc_service.sc_service_instances);
8559 inst != NULL;
8560 inst = uu_list_next(
8561 svc->sc_u.sc_service.sc_service_instances, inst)) {
8562 /*
8563 * This instance still has missing types
8564 * so skip it.
8565 */
8566 if (inst->sc_miss_type) {
8567 if (g_verbose)
8568 warn(gettext("Ignoring instance "
8569 "%s:%s with missing types\n"),
8570 inst->sc_parent->sc_name,
8571 inst->sc_name);
8572
8573 continue;
8574 }
8575
8576 if (scf_service_get_instance(imp_svc, inst->sc_name,
8577 imp_inst) != 0) {
8578 switch (scf_error()) {
8579 case SCF_ERROR_NOT_FOUND:
8580 if (g_verbose)
8581 warn(gettext("Ignoring "
8582 "nonexistant instance "
8583 "%s:%s.\n"),
8584 inst->sc_parent->sc_name,
8585 inst->sc_name);
8586 continue;
8587
8588 default:
8589 scfdie();
8590 }
8591 }
8592
8593 /*
8594 * If the instance does not have a general/enabled
8595 * property and no last-import snapshot then the
8596 * instance is not a fully installed instance and
8597 * should not have a profile applied to it.
8598 *
8599 * This could happen if a service/instance declares
8600 * a dependent on behalf of another service/instance.
8601 *
8602 */
8603 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
8604 imp_snap) != 0) {
8605 if (scf_instance_get_pg(imp_inst,
8606 SCF_PG_GENERAL, imp_pg) != 0 ||
8607 scf_pg_get_property(imp_pg,
8608 SCF_PROPERTY_ENABLED, imp_prop) != 0) {
8609 if (g_verbose)
8610 warn(gettext("Ignoreing "
8611 "partial instance "
8612 "%s:%s.\n"),
8613 inst->sc_parent->sc_name,
8614 inst->sc_name);
8615 continue;
8616 }
8617 }
8618
8619 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri,
8620 inst, SCI_FORCE | SCI_KEEP);
8621 switch (_lscf_import_err(r, inst->sc_fmri)) {
8622 case IMPORT_NEXT:
8623 break;
8624
8625 case IMPORT_OUT:
8626 goto out;
8627
8628 case IMPORT_BAD:
8629 default:
8630 bad_error("lscf_import_instance_pgs", r);
8631 }
8632
8633 if (uu_list_numnodes(inst->sc_dependents) != 0) {
8634 uu_list_walk(inst->sc_dependents,
8635 lscf_dependent_apply, inst, UU_DEFAULT);
8636 }
8637
8638 /* refresh only if there is no pgs in the service */
8639 if (refresh == 0)
8640 (void) refresh_entity(0, imp_inst,
8641 inst->sc_fmri, NULL, NULL, NULL);
8642 }
8643
8644 if (refresh == 1) {
8645 char *name_buf = safe_malloc(max_scf_name_len + 1);
8646
8647 (void) refresh_entity(1, imp_svc, svc->sc_name,
8648 imp_inst, imp_iter, name_buf);
8649 free(name_buf);
8650 }
8651
8652 for (old_dpt = uu_list_first(imp_deleted_dpts);
8653 old_dpt != NULL;
8654 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) {
8655 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8656 old_dpt->sc_pgroup_name,
8657 old_dpt->sc_parent->sc_fmri) != 0) {
8658 warn(gettext("Unable to refresh \"%s\"\n"),
8659 old_dpt->sc_pgroup_fmri);
8660 }
8661 }
8662 }
8663
8664 out:
8665 if (annotation_set) {
8666 /* Remove security audit annotation strings. */
8667 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8668 }
8669
8670 free_imp_globals();
8671 return (ret);
8672 }
8673
8674
8675 /*
8676 * Export. These functions create and output an XML tree of a service
8677 * description from the repository. This is largely the inverse of
8678 * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
8679 *
8680 * - We must include any properties which are not represented specifically by
8681 * a service manifest, e.g., properties created by an admin post-import. To
8682 * do so we'll iterate through all properties and deal with each
8683 * apropriately.
8684 *
8685 * - Children of services and instances must must be in the order set by the
8686 * DTD, but we iterate over the properties in undefined order. The elements
8687 * are not easily (or efficiently) sortable by name. Since there's a fixed
8688 * number of classes of them, however, we'll keep the classes separate and
8689 * assemble them in order.
8690 */
8691
8692 /*
8693 * Convenience function to handle xmlSetProp errors (and type casting).
8694 */
8695 static void
safe_setprop(xmlNodePtr n,const char * name,const char * val)8696 safe_setprop(xmlNodePtr n, const char *name, const char *val)
8697 {
8698 if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
8699 uu_die(gettext("Could not set XML property.\n"));
8700 }
8701
8702 /*
8703 * Convenience function to set an XML attribute to the single value of an
8704 * astring property. If the value happens to be the default, don't set the
8705 * attribute. "dval" should be the default value supplied by the DTD, or
8706 * NULL for no default.
8707 */
8708 static int
set_attr_from_prop_default(scf_property_t * prop,xmlNodePtr n,const char * name,const char * dval)8709 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
8710 const char *name, const char *dval)
8711 {
8712 scf_value_t *val;
8713 ssize_t len;
8714 char *str;
8715
8716 val = scf_value_create(g_hndl);
8717 if (val == NULL)
8718 scfdie();
8719
8720 if (prop_get_val(prop, val) != 0) {
8721 scf_value_destroy(val);
8722 return (-1);
8723 }
8724
8725 len = scf_value_get_as_string(val, NULL, 0);
8726 if (len < 0)
8727 scfdie();
8728
8729 str = safe_malloc(len + 1);
8730
8731 if (scf_value_get_as_string(val, str, len + 1) < 0)
8732 scfdie();
8733
8734 scf_value_destroy(val);
8735
8736 if (dval == NULL || strcmp(str, dval) != 0)
8737 safe_setprop(n, name, str);
8738
8739 free(str);
8740
8741 return (0);
8742 }
8743
8744 /*
8745 * As above, but the attribute is always set.
8746 */
8747 static int
set_attr_from_prop(scf_property_t * prop,xmlNodePtr n,const char * name)8748 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
8749 {
8750 return (set_attr_from_prop_default(prop, n, name, NULL));
8751 }
8752
8753 /*
8754 * Dump the given document onto f, with "'s replaced by ''s.
8755 */
8756 static int
write_service_bundle(xmlDocPtr doc,FILE * f)8757 write_service_bundle(xmlDocPtr doc, FILE *f)
8758 {
8759 xmlChar *mem;
8760 int sz, i;
8761
8762 mem = NULL;
8763 xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
8764
8765 if (mem == NULL) {
8766 semerr(gettext("Could not dump XML tree.\n"));
8767 return (-1);
8768 }
8769
8770 /*
8771 * Fortunately libxml produces " instead of ", so we can blindly
8772 * replace all " with '. Cursed libxml2! Why must you #ifdef out the
8773 * ' code?!
8774 */
8775 for (i = 0; i < sz; ++i) {
8776 char c = (char)mem[i];
8777
8778 if (c == '"')
8779 (void) fputc('\'', f);
8780 else if (c == '\'')
8781 (void) fwrite("'", sizeof ("'") - 1, 1, f);
8782 else
8783 (void) fputc(c, f);
8784 }
8785
8786 return (0);
8787 }
8788
8789 /*
8790 * Create the DOM elements in elts necessary to (generically) represent prop
8791 * (i.e., a property or propval element). If the name of the property is
8792 * known, it should be passed as name_arg. Otherwise, pass NULL.
8793 */
8794 static void
export_property(scf_property_t * prop,const char * name_arg,struct pg_elts * elts,int flags)8795 export_property(scf_property_t *prop, const char *name_arg,
8796 struct pg_elts *elts, int flags)
8797 {
8798 const char *type;
8799 scf_error_t err = 0;
8800 xmlNodePtr pnode, lnode;
8801 char *lnname;
8802 int ret;
8803
8804 /* name */
8805 if (name_arg != NULL) {
8806 (void) strcpy(exp_str, name_arg);
8807 } else {
8808 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
8809 scfdie();
8810 }
8811
8812 /* type */
8813 type = prop_to_typestr(prop);
8814 if (type == NULL)
8815 uu_die(gettext("Can't export property %s: unknown type.\n"),
8816 exp_str);
8817
8818 /* If we're exporting values, and there's just one, export it here. */
8819 if (!(flags & SCE_ALL_VALUES))
8820 goto empty;
8821
8822 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
8823 xmlNodePtr n;
8824
8825 /* Single value, so use propval */
8826 n = xmlNewNode(NULL, (xmlChar *)"propval");
8827 if (n == NULL)
8828 uu_die(emsg_create_xml);
8829
8830 safe_setprop(n, name_attr, exp_str);
8831 safe_setprop(n, type_attr, type);
8832
8833 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
8834 scfdie();
8835 safe_setprop(n, value_attr, exp_str);
8836
8837 if (elts->propvals == NULL)
8838 elts->propvals = n;
8839 else
8840 (void) xmlAddSibling(elts->propvals, n);
8841
8842 return;
8843 }
8844
8845 err = scf_error();
8846
8847 if (err == SCF_ERROR_PERMISSION_DENIED) {
8848 semerr(emsg_permission_denied);
8849 return;
8850 }
8851
8852 if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
8853 err != SCF_ERROR_NOT_FOUND &&
8854 err != SCF_ERROR_PERMISSION_DENIED)
8855 scfdie();
8856
8857 empty:
8858 /* Multiple (or no) values, so use property */
8859 pnode = xmlNewNode(NULL, (xmlChar *)"property");
8860 if (pnode == NULL)
8861 uu_die(emsg_create_xml);
8862
8863 safe_setprop(pnode, name_attr, exp_str);
8864 safe_setprop(pnode, type_attr, type);
8865
8866 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
8867 lnname = uu_msprintf("%s_list", type);
8868 if (lnname == NULL)
8869 uu_die(gettext("Could not create string"));
8870
8871 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
8872 if (lnode == NULL)
8873 uu_die(emsg_create_xml);
8874
8875 uu_free(lnname);
8876
8877 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
8878 scfdie();
8879
8880 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
8881 1) {
8882 xmlNodePtr vn;
8883
8884 vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
8885 NULL);
8886 if (vn == NULL)
8887 uu_die(emsg_create_xml);
8888
8889 if (scf_value_get_as_string(exp_val, exp_str,
8890 exp_str_sz) < 0)
8891 scfdie();
8892 safe_setprop(vn, value_attr, exp_str);
8893 }
8894 if (ret != 0)
8895 scfdie();
8896 }
8897
8898 if (elts->properties == NULL)
8899 elts->properties = pnode;
8900 else
8901 (void) xmlAddSibling(elts->properties, pnode);
8902 }
8903
8904 /*
8905 * Add a property_group element for this property group to elts.
8906 */
8907 static void
export_pg(scf_propertygroup_t * pg,struct entity_elts * eelts,int flags)8908 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
8909 {
8910 xmlNodePtr n;
8911 struct pg_elts elts;
8912 int ret;
8913 boolean_t read_protected;
8914
8915 n = xmlNewNode(NULL, (xmlChar *)"property_group");
8916
8917 /* name */
8918 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
8919 scfdie();
8920 safe_setprop(n, name_attr, exp_str);
8921
8922 /* type */
8923 if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
8924 scfdie();
8925 safe_setprop(n, type_attr, exp_str);
8926
8927 /* properties */
8928 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8929 scfdie();
8930
8931 (void) memset(&elts, 0, sizeof (elts));
8932
8933 /*
8934 * If this property group is not read protected, we always want to
8935 * output all the values. Otherwise, we only output the values if the
8936 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
8937 */
8938 if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
8939 scfdie();
8940
8941 if (!read_protected)
8942 flags |= SCE_ALL_VALUES;
8943
8944 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8945 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8946 scfdie();
8947
8948 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8949 xmlNodePtr m;
8950
8951 m = xmlNewNode(NULL, (xmlChar *)"stability");
8952 if (m == NULL)
8953 uu_die(emsg_create_xml);
8954
8955 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
8956 elts.stability = m;
8957 continue;
8958 }
8959
8960 xmlFreeNode(m);
8961 }
8962
8963 export_property(exp_prop, NULL, &elts, flags);
8964 }
8965 if (ret == -1)
8966 scfdie();
8967
8968 (void) xmlAddChild(n, elts.stability);
8969 (void) xmlAddChildList(n, elts.propvals);
8970 (void) xmlAddChildList(n, elts.properties);
8971
8972 if (eelts->property_groups == NULL)
8973 eelts->property_groups = n;
8974 else
8975 (void) xmlAddSibling(eelts->property_groups, n);
8976 }
8977
8978 /*
8979 * Create an XML node representing the dependency described by the given
8980 * property group and put it in eelts. Unless the dependency is not valid, in
8981 * which case create a generic property_group element which represents it and
8982 * put it in eelts.
8983 */
8984 static void
export_dependency(scf_propertygroup_t * pg,struct entity_elts * eelts)8985 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
8986 {
8987 xmlNodePtr n;
8988 int err = 0, ret;
8989 struct pg_elts elts;
8990
8991 n = xmlNewNode(NULL, (xmlChar *)"dependency");
8992 if (n == NULL)
8993 uu_die(emsg_create_xml);
8994
8995 /*
8996 * If the external flag is present, skip this dependency because it
8997 * should have been created by another manifest.
8998 */
8999 if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
9000 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9001 prop_get_val(exp_prop, exp_val) == 0) {
9002 uint8_t b;
9003
9004 if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
9005 scfdie();
9006
9007 if (b)
9008 return;
9009 }
9010 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
9011 scfdie();
9012
9013 /* Get the required attributes. */
9014
9015 /* name */
9016 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9017 scfdie();
9018 safe_setprop(n, name_attr, exp_str);
9019
9020 /* grouping */
9021 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9022 set_attr_from_prop(exp_prop, n, "grouping") != 0)
9023 err = 1;
9024
9025 /* restart_on */
9026 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9027 set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9028 err = 1;
9029
9030 /* type */
9031 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9032 set_attr_from_prop(exp_prop, n, type_attr) != 0)
9033 err = 1;
9034
9035 /*
9036 * entities: Not required, but if we create no children, it will be
9037 * created as empty on import, so fail if it's missing.
9038 */
9039 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9040 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
9041 scf_iter_t *eiter;
9042 int ret2;
9043
9044 eiter = scf_iter_create(g_hndl);
9045 if (eiter == NULL)
9046 scfdie();
9047
9048 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
9049 scfdie();
9050
9051 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
9052 xmlNodePtr ch;
9053
9054 if (scf_value_get_astring(exp_val, exp_str,
9055 exp_str_sz) < 0)
9056 scfdie();
9057
9058 /*
9059 * service_fmri's must be first, so we can add them
9060 * here.
9061 */
9062 ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
9063 NULL);
9064 if (ch == NULL)
9065 uu_die(emsg_create_xml);
9066
9067 safe_setprop(ch, value_attr, exp_str);
9068 }
9069 if (ret2 == -1)
9070 scfdie();
9071
9072 scf_iter_destroy(eiter);
9073 } else
9074 err = 1;
9075
9076 if (err) {
9077 xmlFreeNode(n);
9078
9079 export_pg(pg, eelts, 0);
9080
9081 return;
9082 }
9083
9084 /* Iterate through the properties & handle each. */
9085 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9086 scfdie();
9087
9088 (void) memset(&elts, 0, sizeof (elts));
9089
9090 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9091 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9092 scfdie();
9093
9094 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9095 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9096 strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9097 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9098 continue;
9099 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9100 xmlNodePtr m;
9101
9102 m = xmlNewNode(NULL, (xmlChar *)"stability");
9103 if (m == NULL)
9104 uu_die(emsg_create_xml);
9105
9106 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9107 elts.stability = m;
9108 continue;
9109 }
9110
9111 xmlFreeNode(m);
9112 }
9113
9114 export_property(exp_prop, exp_str, &elts, 0);
9115 }
9116 if (ret == -1)
9117 scfdie();
9118
9119 (void) xmlAddChild(n, elts.stability);
9120 (void) xmlAddChildList(n, elts.propvals);
9121 (void) xmlAddChildList(n, elts.properties);
9122
9123 if (eelts->dependencies == NULL)
9124 eelts->dependencies = n;
9125 else
9126 (void) xmlAddSibling(eelts->dependencies, n);
9127 }
9128
9129 static xmlNodePtr
export_method_environment(scf_propertygroup_t * pg)9130 export_method_environment(scf_propertygroup_t *pg)
9131 {
9132 xmlNodePtr env;
9133 int ret;
9134 int children = 0;
9135
9136 if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
9137 return (NULL);
9138
9139 env = xmlNewNode(NULL, (xmlChar *)"method_environment");
9140 if (env == NULL)
9141 uu_die(emsg_create_xml);
9142
9143 if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
9144 scfdie();
9145
9146 if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
9147 scfdie();
9148
9149 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
9150 xmlNodePtr ev;
9151 char *cp;
9152
9153 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9154 scfdie();
9155
9156 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
9157 warn(gettext("Invalid environment variable \"%s\".\n"),
9158 exp_str);
9159 continue;
9160 } else if (strncmp(exp_str, "SMF_", 4) == 0) {
9161 warn(gettext("Invalid environment variable \"%s\"; "
9162 "\"SMF_\" prefix is reserved.\n"), exp_str);
9163 continue;
9164 }
9165
9166 *cp = '\0';
9167 cp++;
9168
9169 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
9170 if (ev == NULL)
9171 uu_die(emsg_create_xml);
9172
9173 safe_setprop(ev, name_attr, exp_str);
9174 safe_setprop(ev, value_attr, cp);
9175 children++;
9176 }
9177
9178 if (ret != 0)
9179 scfdie();
9180
9181 if (children == 0) {
9182 xmlFreeNode(env);
9183 return (NULL);
9184 }
9185
9186 return (env);
9187 }
9188
9189 /*
9190 * As above, but for a method property group.
9191 */
9192 static void
export_method(scf_propertygroup_t * pg,struct entity_elts * eelts)9193 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
9194 {
9195 xmlNodePtr n, env;
9196 char *str;
9197 int err = 0, nonenv, ret;
9198 uint8_t use_profile;
9199 struct pg_elts elts;
9200 xmlNodePtr ctxt = NULL;
9201
9202 n = xmlNewNode(NULL, (xmlChar *)"exec_method");
9203
9204 /* Get the required attributes. */
9205
9206 /* name */
9207 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9208 scfdie();
9209 safe_setprop(n, name_attr, exp_str);
9210
9211 /* type */
9212 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9213 set_attr_from_prop(exp_prop, n, type_attr) != 0)
9214 err = 1;
9215
9216 /* exec */
9217 if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
9218 set_attr_from_prop(exp_prop, n, "exec") != 0)
9219 err = 1;
9220
9221 /* timeout */
9222 if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
9223 prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
9224 prop_get_val(exp_prop, exp_val) == 0) {
9225 uint64_t c;
9226
9227 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
9228 scfdie();
9229
9230 str = uu_msprintf("%llu", c);
9231 if (str == NULL)
9232 uu_die(gettext("Could not create string"));
9233
9234 safe_setprop(n, "timeout_seconds", str);
9235 free(str);
9236 } else
9237 err = 1;
9238
9239 if (err) {
9240 xmlFreeNode(n);
9241
9242 export_pg(pg, eelts, 0);
9243
9244 return;
9245 }
9246
9247
9248 /*
9249 * If we're going to have a method_context child, we need to know
9250 * before we iterate through the properties. Since method_context's
9251 * are optional, we don't want to complain about any properties
9252 * missing if none of them are there. Thus we can't use the
9253 * convenience functions.
9254 */
9255 nonenv =
9256 scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
9257 SCF_SUCCESS ||
9258 scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
9259 SCF_SUCCESS ||
9260 scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
9261 SCF_SUCCESS ||
9262 scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
9263 SCF_SUCCESS;
9264
9265 if (nonenv) {
9266 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9267 if (ctxt == NULL)
9268 uu_die(emsg_create_xml);
9269
9270 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
9271 0 &&
9272 set_attr_from_prop_default(exp_prop, ctxt,
9273 "working_directory", ":default") != 0)
9274 err = 1;
9275
9276 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
9277 set_attr_from_prop_default(exp_prop, ctxt, "project",
9278 ":default") != 0)
9279 err = 1;
9280
9281 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
9282 0 &&
9283 set_attr_from_prop_default(exp_prop, ctxt,
9284 "resource_pool", ":default") != 0)
9285 err = 1;
9286 /*
9287 * We only want to complain about profile or credential
9288 * properties if we will use them. To determine that we must
9289 * examine USE_PROFILE.
9290 */
9291 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9292 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9293 prop_get_val(exp_prop, exp_val) == 0) {
9294 if (scf_value_get_boolean(exp_val, &use_profile) !=
9295 SCF_SUCCESS) {
9296 scfdie();
9297 }
9298
9299 if (use_profile) {
9300 xmlNodePtr prof;
9301
9302 prof = xmlNewChild(ctxt, NULL,
9303 (xmlChar *)"method_profile", NULL);
9304 if (prof == NULL)
9305 uu_die(emsg_create_xml);
9306
9307 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
9308 exp_prop) != 0 ||
9309 set_attr_from_prop(exp_prop, prof,
9310 name_attr) != 0)
9311 err = 1;
9312 } else {
9313 xmlNodePtr cred;
9314
9315 cred = xmlNewChild(ctxt, NULL,
9316 (xmlChar *)"method_credential", NULL);
9317 if (cred == NULL)
9318 uu_die(emsg_create_xml);
9319
9320 if (pg_get_prop(pg, SCF_PROPERTY_USER,
9321 exp_prop) != 0 ||
9322 set_attr_from_prop(exp_prop, cred,
9323 "user") != 0) {
9324 err = 1;
9325 }
9326
9327 if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
9328 exp_prop) == 0 &&
9329 set_attr_from_prop_default(exp_prop, cred,
9330 "group", ":default") != 0)
9331 err = 1;
9332
9333 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
9334 exp_prop) == 0 &&
9335 set_attr_from_prop_default(exp_prop, cred,
9336 "supp_groups", ":default") != 0)
9337 err = 1;
9338
9339 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
9340 exp_prop) == 0 &&
9341 set_attr_from_prop_default(exp_prop, cred,
9342 "privileges", ":default") != 0)
9343 err = 1;
9344
9345 if (pg_get_prop(pg,
9346 SCF_PROPERTY_LIMIT_PRIVILEGES,
9347 exp_prop) == 0 &&
9348 set_attr_from_prop_default(exp_prop, cred,
9349 "limit_privileges", ":default") != 0)
9350 err = 1;
9351 }
9352 }
9353 }
9354
9355 if ((env = export_method_environment(pg)) != NULL) {
9356 if (ctxt == NULL) {
9357 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9358 if (ctxt == NULL)
9359 uu_die(emsg_create_xml);
9360 }
9361 (void) xmlAddChild(ctxt, env);
9362 }
9363
9364 if (env != NULL || (nonenv && err == 0))
9365 (void) xmlAddChild(n, ctxt);
9366 else
9367 xmlFreeNode(ctxt);
9368
9369 nonenv = (err == 0);
9370
9371 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9372 scfdie();
9373
9374 (void) memset(&elts, 0, sizeof (elts));
9375
9376 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9377 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9378 scfdie();
9379
9380 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9381 strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
9382 strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
9383 continue;
9384 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9385 xmlNodePtr m;
9386
9387 m = xmlNewNode(NULL, (xmlChar *)"stability");
9388 if (m == NULL)
9389 uu_die(emsg_create_xml);
9390
9391 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9392 elts.stability = m;
9393 continue;
9394 }
9395
9396 xmlFreeNode(m);
9397 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
9398 0 ||
9399 strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
9400 strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
9401 strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9402 if (nonenv)
9403 continue;
9404 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
9405 strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
9406 strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
9407 strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
9408 strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) {
9409 if (nonenv && !use_profile)
9410 continue;
9411 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9412 if (nonenv && use_profile)
9413 continue;
9414 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
9415 if (env != NULL)
9416 continue;
9417 }
9418
9419 export_property(exp_prop, exp_str, &elts, 0);
9420 }
9421 if (ret == -1)
9422 scfdie();
9423
9424 (void) xmlAddChild(n, elts.stability);
9425 (void) xmlAddChildList(n, elts.propvals);
9426 (void) xmlAddChildList(n, elts.properties);
9427
9428 if (eelts->exec_methods == NULL)
9429 eelts->exec_methods = n;
9430 else
9431 (void) xmlAddSibling(eelts->exec_methods, n);
9432 }
9433
9434 static void
export_pg_elts(struct pg_elts * elts,const char * name,const char * type,struct entity_elts * eelts)9435 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
9436 struct entity_elts *eelts)
9437 {
9438 xmlNodePtr pgnode;
9439
9440 pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
9441 if (pgnode == NULL)
9442 uu_die(emsg_create_xml);
9443
9444 safe_setprop(pgnode, name_attr, name);
9445 safe_setprop(pgnode, type_attr, type);
9446
9447 (void) xmlAddChildList(pgnode, elts->propvals);
9448 (void) xmlAddChildList(pgnode, elts->properties);
9449
9450 if (eelts->property_groups == NULL)
9451 eelts->property_groups = pgnode;
9452 else
9453 (void) xmlAddSibling(eelts->property_groups, pgnode);
9454 }
9455
9456 /*
9457 * Process the general property group for a service. This is the one with the
9458 * goodies.
9459 */
9460 static void
export_svc_general(scf_propertygroup_t * pg,struct entity_elts * selts)9461 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
9462 {
9463 struct pg_elts elts;
9464 int ret;
9465
9466 /*
9467 * In case there are properties which don't correspond to child
9468 * entities of the service entity, we'll set up a pg_elts structure to
9469 * put them in.
9470 */
9471 (void) memset(&elts, 0, sizeof (elts));
9472
9473 /* Walk the properties, looking for special ones. */
9474 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9475 scfdie();
9476
9477 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9478 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9479 scfdie();
9480
9481 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
9482 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9483 prop_get_val(exp_prop, exp_val) == 0) {
9484 uint8_t b;
9485
9486 if (scf_value_get_boolean(exp_val, &b) !=
9487 SCF_SUCCESS)
9488 scfdie();
9489
9490 if (b) {
9491 selts->single_instance =
9492 xmlNewNode(NULL,
9493 (xmlChar *)"single_instance");
9494 if (selts->single_instance == NULL)
9495 uu_die(emsg_create_xml);
9496 }
9497
9498 continue;
9499 }
9500 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9501 xmlNodePtr rnode, sfnode;
9502
9503 rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9504 if (rnode == NULL)
9505 uu_die(emsg_create_xml);
9506
9507 sfnode = xmlNewChild(rnode, NULL,
9508 (xmlChar *)"service_fmri", NULL);
9509 if (sfnode == NULL)
9510 uu_die(emsg_create_xml);
9511
9512 if (set_attr_from_prop(exp_prop, sfnode,
9513 value_attr) == 0) {
9514 selts->restarter = rnode;
9515 continue;
9516 }
9517
9518 xmlFreeNode(rnode);
9519 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
9520 0) {
9521 xmlNodePtr s;
9522
9523 s = xmlNewNode(NULL, (xmlChar *)"stability");
9524 if (s == NULL)
9525 uu_die(emsg_create_xml);
9526
9527 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9528 selts->stability = s;
9529 continue;
9530 }
9531
9532 xmlFreeNode(s);
9533 }
9534
9535 export_property(exp_prop, exp_str, &elts, 0);
9536 }
9537 if (ret == -1)
9538 scfdie();
9539
9540 if (elts.propvals != NULL || elts.properties != NULL)
9541 export_pg_elts(&elts, scf_pg_general, scf_group_framework,
9542 selts);
9543 }
9544
9545 static void
export_method_context(scf_propertygroup_t * pg,struct entity_elts * elts)9546 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
9547 {
9548 xmlNodePtr n, prof, cred, env;
9549 uint8_t use_profile;
9550 int ret, err = 0;
9551
9552 n = xmlNewNode(NULL, (xmlChar *)"method_context");
9553
9554 env = export_method_environment(pg);
9555
9556 /* Need to know whether we'll use a profile or not. */
9557 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9558 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9559 prop_get_val(exp_prop, exp_val) == 0) {
9560 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
9561 scfdie();
9562
9563 if (use_profile)
9564 prof =
9565 xmlNewChild(n, NULL, (xmlChar *)"method_profile",
9566 NULL);
9567 else
9568 cred =
9569 xmlNewChild(n, NULL, (xmlChar *)"method_credential",
9570 NULL);
9571 }
9572
9573 if (env != NULL)
9574 (void) xmlAddChild(n, env);
9575
9576 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9577 scfdie();
9578
9579 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9580 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9581 scfdie();
9582
9583 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
9584 if (set_attr_from_prop(exp_prop, n,
9585 "working_directory") != 0)
9586 err = 1;
9587 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
9588 if (set_attr_from_prop(exp_prop, n, "project") != 0)
9589 err = 1;
9590 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
9591 if (set_attr_from_prop(exp_prop, n,
9592 "resource_pool") != 0)
9593 err = 1;
9594 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9595 /* EMPTY */
9596 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
9597 if (use_profile ||
9598 set_attr_from_prop(exp_prop, cred, "user") != 0)
9599 err = 1;
9600 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
9601 if (use_profile ||
9602 set_attr_from_prop(exp_prop, cred, "group") != 0)
9603 err = 1;
9604 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
9605 if (use_profile || set_attr_from_prop(exp_prop, cred,
9606 "supp_groups") != 0)
9607 err = 1;
9608 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
9609 if (use_profile || set_attr_from_prop(exp_prop, cred,
9610 "privileges") != 0)
9611 err = 1;
9612 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
9613 0) {
9614 if (use_profile || set_attr_from_prop(exp_prop, cred,
9615 "limit_privileges") != 0)
9616 err = 1;
9617 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9618 if (!use_profile || set_attr_from_prop(exp_prop,
9619 prof, name_attr) != 0)
9620 err = 1;
9621 } else {
9622 /* Can't have generic properties in method_context's */
9623 err = 1;
9624 }
9625 }
9626 if (ret == -1)
9627 scfdie();
9628
9629 if (err && env == NULL) {
9630 xmlFreeNode(n);
9631 export_pg(pg, elts, 0);
9632 return;
9633 }
9634
9635 elts->method_context = n;
9636 }
9637
9638 /*
9639 * Given a dependency property group in the tfmri entity (target fmri), return
9640 * a dependent element which represents it.
9641 */
9642 static xmlNodePtr
export_dependent(scf_propertygroup_t * pg,const char * name,const char * tfmri)9643 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
9644 {
9645 uint8_t b;
9646 xmlNodePtr n, sf;
9647 int err = 0, ret;
9648 struct pg_elts pgelts;
9649
9650 /*
9651 * If external isn't set to true then exporting the service will
9652 * export this as a normal dependency, so we should stop to avoid
9653 * duplication.
9654 */
9655 if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
9656 scf_property_get_value(exp_prop, exp_val) != 0 ||
9657 scf_value_get_boolean(exp_val, &b) != 0 || !b) {
9658 if (g_verbose) {
9659 warn(gettext("Dependent \"%s\" cannot be exported "
9660 "properly because the \"%s\" property of the "
9661 "\"%s\" dependency of %s is not set to true.\n"),
9662 name, scf_property_external, name, tfmri);
9663 }
9664
9665 return (NULL);
9666 }
9667
9668 n = xmlNewNode(NULL, (xmlChar *)"dependent");
9669 if (n == NULL)
9670 uu_die(emsg_create_xml);
9671
9672 safe_setprop(n, name_attr, name);
9673
9674 /* Get the required attributes */
9675 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9676 set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9677 err = 1;
9678
9679 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9680 set_attr_from_prop(exp_prop, n, "grouping") != 0)
9681 err = 1;
9682
9683 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9684 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
9685 prop_get_val(exp_prop, exp_val) == 0) {
9686 /* EMPTY */
9687 } else
9688 err = 1;
9689
9690 if (err) {
9691 xmlFreeNode(n);
9692 return (NULL);
9693 }
9694
9695 sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
9696 if (sf == NULL)
9697 uu_die(emsg_create_xml);
9698
9699 safe_setprop(sf, value_attr, tfmri);
9700
9701 /*
9702 * Now add elements for the other properties.
9703 */
9704 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9705 scfdie();
9706
9707 (void) memset(&pgelts, 0, sizeof (pgelts));
9708
9709 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9710 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9711 scfdie();
9712
9713 if (strcmp(exp_str, scf_property_external) == 0 ||
9714 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9715 strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9716 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9717 continue;
9718 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
9719 if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
9720 prop_get_val(exp_prop, exp_val) == 0) {
9721 char type[sizeof ("service") + 1];
9722
9723 if (scf_value_get_astring(exp_val, type,
9724 sizeof (type)) < 0)
9725 scfdie();
9726
9727 if (strcmp(type, "service") == 0)
9728 continue;
9729 }
9730 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9731 xmlNodePtr s;
9732
9733 s = xmlNewNode(NULL, (xmlChar *)"stability");
9734 if (s == NULL)
9735 uu_die(emsg_create_xml);
9736
9737 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9738 pgelts.stability = s;
9739 continue;
9740 }
9741
9742 xmlFreeNode(s);
9743 }
9744
9745 export_property(exp_prop, exp_str, &pgelts, 0);
9746 }
9747 if (ret == -1)
9748 scfdie();
9749
9750 (void) xmlAddChild(n, pgelts.stability);
9751 (void) xmlAddChildList(n, pgelts.propvals);
9752 (void) xmlAddChildList(n, pgelts.properties);
9753
9754 return (n);
9755 }
9756
9757 static void
export_dependents(scf_propertygroup_t * pg,struct entity_elts * eelts)9758 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
9759 {
9760 scf_propertygroup_t *opg;
9761 scf_iter_t *iter;
9762 char *type, *fmri;
9763 int ret;
9764 struct pg_elts pgelts;
9765 xmlNodePtr n;
9766 scf_error_t serr;
9767
9768 if ((opg = scf_pg_create(g_hndl)) == NULL ||
9769 (iter = scf_iter_create(g_hndl)) == NULL)
9770 scfdie();
9771
9772 /* Can't use exp_prop_iter due to export_dependent(). */
9773 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
9774 scfdie();
9775
9776 type = safe_malloc(max_scf_pg_type_len + 1);
9777
9778 /* Get an extra byte so we can tell if values are too long. */
9779 fmri = safe_malloc(max_scf_fmri_len + 2);
9780
9781 (void) memset(&pgelts, 0, sizeof (pgelts));
9782
9783 while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
9784 void *entity;
9785 int isservice;
9786 scf_type_t ty;
9787
9788 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
9789 scfdie();
9790
9791 if ((ty != SCF_TYPE_ASTRING &&
9792 prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
9793 prop_get_val(exp_prop, exp_val) != 0) {
9794 export_property(exp_prop, NULL, &pgelts, 0);
9795 continue;
9796 }
9797
9798 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9799 scfdie();
9800
9801 if (scf_value_get_astring(exp_val, fmri,
9802 max_scf_fmri_len + 2) < 0)
9803 scfdie();
9804
9805 /* Look for a dependency group in the target fmri. */
9806 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
9807 switch (serr) {
9808 case SCF_ERROR_NONE:
9809 break;
9810
9811 case SCF_ERROR_NO_MEMORY:
9812 uu_die(gettext("Out of memory.\n"));
9813 /* NOTREACHED */
9814
9815 case SCF_ERROR_INVALID_ARGUMENT:
9816 if (g_verbose) {
9817 if (scf_property_to_fmri(exp_prop, fmri,
9818 max_scf_fmri_len + 2) < 0)
9819 scfdie();
9820
9821 warn(gettext("The value of %s is not a valid "
9822 "FMRI.\n"), fmri);
9823 }
9824
9825 export_property(exp_prop, exp_str, &pgelts, 0);
9826 continue;
9827
9828 case SCF_ERROR_CONSTRAINT_VIOLATED:
9829 if (g_verbose) {
9830 if (scf_property_to_fmri(exp_prop, fmri,
9831 max_scf_fmri_len + 2) < 0)
9832 scfdie();
9833
9834 warn(gettext("The value of %s does not specify "
9835 "a service or an instance.\n"), fmri);
9836 }
9837
9838 export_property(exp_prop, exp_str, &pgelts, 0);
9839 continue;
9840
9841 case SCF_ERROR_NOT_FOUND:
9842 if (g_verbose) {
9843 if (scf_property_to_fmri(exp_prop, fmri,
9844 max_scf_fmri_len + 2) < 0)
9845 scfdie();
9846
9847 warn(gettext("The entity specified by %s does "
9848 "not exist.\n"), fmri);
9849 }
9850
9851 export_property(exp_prop, exp_str, &pgelts, 0);
9852 continue;
9853
9854 default:
9855 #ifndef NDEBUG
9856 (void) fprintf(stderr, "%s:%d: %s() failed with "
9857 "unexpected error %d.\n", __FILE__, __LINE__,
9858 "fmri_to_entity", serr);
9859 #endif
9860 abort();
9861 }
9862
9863 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
9864 if (scf_error() != SCF_ERROR_NOT_FOUND)
9865 scfdie();
9866
9867 warn(gettext("Entity %s is missing dependency property "
9868 "group %s.\n"), fmri, exp_str);
9869
9870 export_property(exp_prop, NULL, &pgelts, 0);
9871 continue;
9872 }
9873
9874 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
9875 scfdie();
9876
9877 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
9878 if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
9879 scfdie();
9880
9881 warn(gettext("Property group %s is not of "
9882 "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
9883
9884 export_property(exp_prop, NULL, &pgelts, 0);
9885 continue;
9886 }
9887
9888 n = export_dependent(opg, exp_str, fmri);
9889 if (n == NULL)
9890 export_property(exp_prop, exp_str, &pgelts, 0);
9891 else {
9892 if (eelts->dependents == NULL)
9893 eelts->dependents = n;
9894 else
9895 (void) xmlAddSibling(eelts->dependents,
9896 n);
9897 }
9898 }
9899 if (ret == -1)
9900 scfdie();
9901
9902 free(fmri);
9903 free(type);
9904
9905 scf_iter_destroy(iter);
9906 scf_pg_destroy(opg);
9907
9908 if (pgelts.propvals != NULL || pgelts.properties != NULL)
9909 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
9910 eelts);
9911 }
9912
9913 static void
make_node(xmlNodePtr * nodep,const char * name)9914 make_node(xmlNodePtr *nodep, const char *name)
9915 {
9916 if (*nodep == NULL) {
9917 *nodep = xmlNewNode(NULL, (xmlChar *)name);
9918 if (*nodep == NULL)
9919 uu_die(emsg_create_xml);
9920 }
9921 }
9922
9923 static xmlNodePtr
export_tm_loctext(scf_propertygroup_t * pg,const char * parname)9924 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
9925 {
9926 int ret;
9927 xmlNodePtr parent = NULL;
9928 xmlNodePtr loctext = NULL;
9929
9930 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9931 scfdie();
9932
9933 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9934 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
9935 prop_get_val(exp_prop, exp_val) != 0)
9936 continue;
9937
9938 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
9939 scfdie();
9940
9941 make_node(&parent, parname);
9942 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
9943 (xmlChar *)exp_str);
9944 if (loctext == NULL)
9945 uu_die(emsg_create_xml);
9946
9947 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9948 scfdie();
9949
9950 safe_setprop(loctext, "xml:lang", exp_str);
9951 }
9952
9953 if (ret == -1)
9954 scfdie();
9955
9956 return (parent);
9957 }
9958
9959 static xmlNodePtr
export_tm_manpage(scf_propertygroup_t * pg)9960 export_tm_manpage(scf_propertygroup_t *pg)
9961 {
9962 xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
9963 if (manpage == NULL)
9964 uu_die(emsg_create_xml);
9965
9966 if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
9967 set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
9968 pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
9969 set_attr_from_prop(exp_prop, manpage, "section") != 0) {
9970 xmlFreeNode(manpage);
9971 return (NULL);
9972 }
9973
9974 if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
9975 (void) set_attr_from_prop_default(exp_prop,
9976 manpage, "manpath", ":default");
9977
9978 return (manpage);
9979 }
9980
9981 static xmlNodePtr
export_tm_doc_link(scf_propertygroup_t * pg)9982 export_tm_doc_link(scf_propertygroup_t *pg)
9983 {
9984 xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
9985 if (doc_link == NULL)
9986 uu_die(emsg_create_xml);
9987
9988 if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
9989 set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
9990 pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
9991 set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
9992 xmlFreeNode(doc_link);
9993 return (NULL);
9994 }
9995 return (doc_link);
9996 }
9997
9998 /*
9999 * Process template information for a service or instances.
10000 */
10001 static void
export_template(scf_propertygroup_t * pg,struct entity_elts * elts,struct template_elts * telts)10002 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
10003 struct template_elts *telts)
10004 {
10005 size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
10006 size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
10007 xmlNodePtr child = NULL;
10008
10009 if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
10010 scfdie();
10011
10012 if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
10013 telts->common_name = export_tm_loctext(pg, "common_name");
10014 if (telts->common_name == NULL)
10015 export_pg(pg, elts, 0);
10016 return;
10017 } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
10018 telts->description = export_tm_loctext(pg, "description");
10019 if (telts->description == NULL)
10020 export_pg(pg, elts, 0);
10021 return;
10022 }
10023
10024 if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
10025 child = export_tm_manpage(pg);
10026 } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
10027 child = export_tm_doc_link(pg);
10028 }
10029
10030 if (child != NULL) {
10031 make_node(&telts->documentation, "documentation");
10032 (void) xmlAddChild(telts->documentation, child);
10033 } else {
10034 export_pg(pg, elts, 0);
10035 }
10036 }
10037
10038 /*
10039 * Process parameter and paramval elements
10040 */
10041 static void
export_parameter(scf_property_t * prop,const char * name,struct params_elts * elts)10042 export_parameter(scf_property_t *prop, const char *name,
10043 struct params_elts *elts)
10044 {
10045 xmlNodePtr param;
10046 scf_error_t err = 0;
10047 int ret;
10048
10049 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
10050 if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL)
10051 uu_die(emsg_create_xml);
10052
10053 safe_setprop(param, name_attr, name);
10054
10055 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
10056 scfdie();
10057 safe_setprop(param, value_attr, exp_str);
10058
10059 if (elts->paramval == NULL)
10060 elts->paramval = param;
10061 else
10062 (void) xmlAddSibling(elts->paramval, param);
10063
10064 return;
10065 }
10066
10067 err = scf_error();
10068
10069 if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
10070 err != SCF_ERROR_NOT_FOUND)
10071 scfdie();
10072
10073 if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL)
10074 uu_die(emsg_create_xml);
10075
10076 safe_setprop(param, name_attr, name);
10077
10078 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
10079 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
10080 scfdie();
10081
10082 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
10083 1) {
10084 xmlNodePtr vn;
10085
10086 if ((vn = xmlNewChild(param, NULL,
10087 (xmlChar *)"value_node", NULL)) == NULL)
10088 uu_die(emsg_create_xml);
10089
10090 if (scf_value_get_as_string(exp_val, exp_str,
10091 exp_str_sz) < 0)
10092 scfdie();
10093
10094 safe_setprop(vn, value_attr, exp_str);
10095 }
10096 if (ret != 0)
10097 scfdie();
10098 }
10099
10100 if (elts->parameter == NULL)
10101 elts->parameter = param;
10102 else
10103 (void) xmlAddSibling(elts->parameter, param);
10104 }
10105
10106 /*
10107 * Process notification parameters for a service or instance
10108 */
10109 static void
export_notify_params(scf_propertygroup_t * pg,struct entity_elts * elts)10110 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts)
10111 {
10112 xmlNodePtr n, event, *type;
10113 struct params_elts *eelts;
10114 int ret, err, i;
10115
10116 n = xmlNewNode(NULL, (xmlChar *)"notification_parameters");
10117 event = xmlNewNode(NULL, (xmlChar *)"event");
10118 if (n == NULL || event == NULL)
10119 uu_die(emsg_create_xml);
10120
10121 /* event value */
10122 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
10123 scfdie();
10124 safe_setprop(event, value_attr, exp_str);
10125
10126 (void) xmlAddChild(n, event);
10127
10128 if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL ||
10129 (eelts = calloc(URI_SCHEME_NUM,
10130 sizeof (struct params_elts))) == NULL)
10131 uu_die(gettext("Out of memory.\n"));
10132
10133 err = 0;
10134
10135 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10136 scfdie();
10137
10138 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10139 char *t, *p;
10140
10141 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10142 scfdie();
10143
10144 if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) {
10145 /*
10146 * this is not a well formed notification parameters
10147 * element, we should export as regular pg
10148 */
10149 err = 1;
10150 break;
10151 }
10152
10153 if ((i = check_uri_protocol(t)) < 0) {
10154 err = 1;
10155 break;
10156 }
10157
10158 if (type[i] == NULL) {
10159 if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) ==
10160 NULL)
10161 uu_die(emsg_create_xml);
10162
10163 safe_setprop(type[i], name_attr, t);
10164 }
10165 if (strcmp(p, active_attr) == 0) {
10166 if (set_attr_from_prop(exp_prop, type[i],
10167 active_attr) != 0) {
10168 err = 1;
10169 break;
10170 }
10171 continue;
10172 }
10173 /*
10174 * We export the parameter
10175 */
10176 export_parameter(exp_prop, p, &eelts[i]);
10177 }
10178
10179 if (ret == -1)
10180 scfdie();
10181
10182 if (err == 1) {
10183 for (i = 0; i < URI_SCHEME_NUM; ++i)
10184 xmlFree(type[i]);
10185 free(type);
10186
10187 export_pg(pg, elts, 0);
10188
10189 return;
10190 } else {
10191 for (i = 0; i < URI_SCHEME_NUM; ++i)
10192 if (type[i] != NULL) {
10193 (void) xmlAddChildList(type[i],
10194 eelts[i].paramval);
10195 (void) xmlAddChildList(type[i],
10196 eelts[i].parameter);
10197 (void) xmlAddSibling(event, type[i]);
10198 }
10199 }
10200 free(type);
10201
10202 if (elts->notify_params == NULL)
10203 elts->notify_params = n;
10204 else
10205 (void) xmlAddSibling(elts->notify_params, n);
10206 }
10207
10208 /*
10209 * Process the general property group for an instance.
10210 */
10211 static void
export_inst_general(scf_propertygroup_t * pg,xmlNodePtr inode,struct entity_elts * elts)10212 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
10213 struct entity_elts *elts)
10214 {
10215 uint8_t enabled;
10216 struct pg_elts pgelts;
10217 int ret;
10218
10219 /* enabled */
10220 if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
10221 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
10222 prop_get_val(exp_prop, exp_val) == 0) {
10223 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
10224 scfdie();
10225 } else {
10226 enabled = 0;
10227 }
10228
10229 safe_setprop(inode, enabled_attr, enabled ? true : false);
10230
10231 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10232 scfdie();
10233
10234 (void) memset(&pgelts, 0, sizeof (pgelts));
10235
10236 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10237 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10238 scfdie();
10239
10240 if (strcmp(exp_str, scf_property_enabled) == 0) {
10241 continue;
10242 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
10243 xmlNodePtr rnode, sfnode;
10244
10245 rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10246 if (rnode == NULL)
10247 uu_die(emsg_create_xml);
10248
10249 sfnode = xmlNewChild(rnode, NULL,
10250 (xmlChar *)"service_fmri", NULL);
10251 if (sfnode == NULL)
10252 uu_die(emsg_create_xml);
10253
10254 if (set_attr_from_prop(exp_prop, sfnode,
10255 value_attr) == 0) {
10256 elts->restarter = rnode;
10257 continue;
10258 }
10259
10260 xmlFreeNode(rnode);
10261 }
10262
10263 export_property(exp_prop, exp_str, &pgelts, 0);
10264 }
10265 if (ret == -1)
10266 scfdie();
10267
10268 if (pgelts.propvals != NULL || pgelts.properties != NULL)
10269 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10270 elts);
10271 }
10272
10273 /*
10274 * Put an instance element for the given instance into selts.
10275 */
10276 static void
export_instance(scf_instance_t * inst,struct entity_elts * selts,int flags)10277 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10278 {
10279 xmlNodePtr n;
10280 boolean_t isdefault;
10281 struct entity_elts elts;
10282 struct template_elts template_elts;
10283 int ret;
10284
10285 n = xmlNewNode(NULL, (xmlChar *)"instance");
10286 if (n == NULL)
10287 uu_die(emsg_create_xml);
10288
10289 /* name */
10290 if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10291 scfdie();
10292 safe_setprop(n, name_attr, exp_str);
10293 isdefault = strcmp(exp_str, "default") == 0;
10294
10295 /* check existance of general pg (since general/enabled is required) */
10296 if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
10297 if (scf_error() != SCF_ERROR_NOT_FOUND)
10298 scfdie();
10299
10300 if (g_verbose) {
10301 if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10302 scfdie();
10303
10304 warn(gettext("Instance %s has no general property "
10305 "group; it will be marked disabled.\n"), exp_str);
10306 }
10307
10308 safe_setprop(n, enabled_attr, false);
10309 } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
10310 strcmp(exp_str, scf_group_framework) != 0) {
10311 if (g_verbose) {
10312 if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10313 scfdie();
10314
10315 warn(gettext("Property group %s is not of type "
10316 "framework; the instance will be marked "
10317 "disabled.\n"), exp_str);
10318 }
10319
10320 safe_setprop(n, enabled_attr, false);
10321 }
10322
10323 /* property groups */
10324 if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
10325 scfdie();
10326
10327 (void) memset(&elts, 0, sizeof (elts));
10328 (void) memset(&template_elts, 0, sizeof (template_elts));
10329
10330 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10331 uint32_t pgflags;
10332
10333 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10334 scfdie();
10335
10336 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10337 continue;
10338
10339 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10340 scfdie();
10341
10342 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10343 export_dependency(exp_pg, &elts);
10344 continue;
10345 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10346 export_method(exp_pg, &elts);
10347 continue;
10348 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10349 if (scf_pg_get_name(exp_pg, exp_str,
10350 max_scf_name_len + 1) < 0)
10351 scfdie();
10352
10353 if (strcmp(exp_str, scf_pg_general) == 0) {
10354 export_inst_general(exp_pg, n, &elts);
10355 continue;
10356 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10357 0) {
10358 export_method_context(exp_pg, &elts);
10359 continue;
10360 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10361 export_dependents(exp_pg, &elts);
10362 continue;
10363 }
10364 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10365 export_template(exp_pg, &elts, &template_elts);
10366 continue;
10367 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10368 export_notify_params(exp_pg, &elts);
10369 continue;
10370 }
10371
10372 /* Ordinary pg. */
10373 export_pg(exp_pg, &elts, flags);
10374 }
10375 if (ret == -1)
10376 scfdie();
10377
10378 if (template_elts.common_name != NULL) {
10379 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10380 (void) xmlAddChild(elts.template, template_elts.common_name);
10381 (void) xmlAddChild(elts.template, template_elts.description);
10382 (void) xmlAddChild(elts.template, template_elts.documentation);
10383 } else {
10384 xmlFreeNode(template_elts.description);
10385 xmlFreeNode(template_elts.documentation);
10386 }
10387
10388 if (isdefault && elts.restarter == NULL &&
10389 elts.dependencies == NULL && elts.method_context == NULL &&
10390 elts.exec_methods == NULL && elts.notify_params == NULL &&
10391 elts.property_groups == NULL && elts.template == NULL) {
10392 xmlChar *eval;
10393
10394 /* This is a default instance */
10395 eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10396
10397 xmlFreeNode(n);
10398
10399 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10400 if (n == NULL)
10401 uu_die(emsg_create_xml);
10402
10403 safe_setprop(n, enabled_attr, (char *)eval);
10404 xmlFree(eval);
10405
10406 selts->create_default_instance = n;
10407 } else {
10408 /* Assemble the children in order. */
10409 (void) xmlAddChild(n, elts.restarter);
10410 (void) xmlAddChildList(n, elts.dependencies);
10411 (void) xmlAddChildList(n, elts.dependents);
10412 (void) xmlAddChild(n, elts.method_context);
10413 (void) xmlAddChildList(n, elts.exec_methods);
10414 (void) xmlAddChildList(n, elts.notify_params);
10415 (void) xmlAddChildList(n, elts.property_groups);
10416 (void) xmlAddChild(n, elts.template);
10417
10418 if (selts->instances == NULL)
10419 selts->instances = n;
10420 else
10421 (void) xmlAddSibling(selts->instances, n);
10422 }
10423 }
10424
10425 /*
10426 * Return a service element for the given service.
10427 */
10428 static xmlNodePtr
export_service(scf_service_t * svc,int flags)10429 export_service(scf_service_t *svc, int flags)
10430 {
10431 xmlNodePtr snode;
10432 struct entity_elts elts;
10433 struct template_elts template_elts;
10434 int ret;
10435
10436 snode = xmlNewNode(NULL, (xmlChar *)"service");
10437 if (snode == NULL)
10438 uu_die(emsg_create_xml);
10439
10440 /* Get & set name attribute */
10441 if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
10442 scfdie();
10443 safe_setprop(snode, name_attr, exp_str);
10444
10445 safe_setprop(snode, type_attr, "service");
10446 safe_setprop(snode, "version", "0");
10447
10448 /* Acquire child elements. */
10449 if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
10450 scfdie();
10451
10452 (void) memset(&elts, 0, sizeof (elts));
10453 (void) memset(&template_elts, 0, sizeof (template_elts));
10454
10455 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10456 uint32_t pgflags;
10457
10458 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10459 scfdie();
10460
10461 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10462 continue;
10463
10464 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10465 scfdie();
10466
10467 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10468 export_dependency(exp_pg, &elts);
10469 continue;
10470 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10471 export_method(exp_pg, &elts);
10472 continue;
10473 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10474 if (scf_pg_get_name(exp_pg, exp_str,
10475 max_scf_name_len + 1) < 0)
10476 scfdie();
10477
10478 if (strcmp(exp_str, scf_pg_general) == 0) {
10479 export_svc_general(exp_pg, &elts);
10480 continue;
10481 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10482 0) {
10483 export_method_context(exp_pg, &elts);
10484 continue;
10485 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10486 export_dependents(exp_pg, &elts);
10487 continue;
10488 } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10489 continue;
10490 }
10491 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10492 export_template(exp_pg, &elts, &template_elts);
10493 continue;
10494 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10495 export_notify_params(exp_pg, &elts);
10496 continue;
10497 }
10498
10499 export_pg(exp_pg, &elts, flags);
10500 }
10501 if (ret == -1)
10502 scfdie();
10503
10504 if (template_elts.common_name != NULL) {
10505 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10506 (void) xmlAddChild(elts.template, template_elts.common_name);
10507 (void) xmlAddChild(elts.template, template_elts.description);
10508 (void) xmlAddChild(elts.template, template_elts.documentation);
10509 } else {
10510 xmlFreeNode(template_elts.description);
10511 xmlFreeNode(template_elts.documentation);
10512 }
10513
10514 /* Iterate instances */
10515 if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
10516 scfdie();
10517
10518 while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10519 export_instance(exp_inst, &elts, flags);
10520 if (ret == -1)
10521 scfdie();
10522
10523 /* Now add all of the accumulated elements in order. */
10524 (void) xmlAddChild(snode, elts.create_default_instance);
10525 (void) xmlAddChild(snode, elts.single_instance);
10526 (void) xmlAddChild(snode, elts.restarter);
10527 (void) xmlAddChildList(snode, elts.dependencies);
10528 (void) xmlAddChildList(snode, elts.dependents);
10529 (void) xmlAddChild(snode, elts.method_context);
10530 (void) xmlAddChildList(snode, elts.exec_methods);
10531 (void) xmlAddChildList(snode, elts.notify_params);
10532 (void) xmlAddChildList(snode, elts.property_groups);
10533 (void) xmlAddChildList(snode, elts.instances);
10534 (void) xmlAddChild(snode, elts.stability);
10535 (void) xmlAddChild(snode, elts.template);
10536
10537 return (snode);
10538 }
10539
10540 static int
export_callback(void * data,scf_walkinfo_t * wip)10541 export_callback(void *data, scf_walkinfo_t *wip)
10542 {
10543 FILE *f;
10544 xmlDocPtr doc;
10545 xmlNodePtr sb;
10546 int result;
10547 struct export_args *argsp = (struct export_args *)data;
10548
10549 if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
10550 (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10551 (exp_prop = scf_property_create(g_hndl)) == NULL ||
10552 (exp_val = scf_value_create(g_hndl)) == NULL ||
10553 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10554 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10555 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10556 (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10557 scfdie();
10558
10559 exp_str_sz = max_scf_len + 1;
10560 exp_str = safe_malloc(exp_str_sz);
10561
10562 if (argsp->filename != NULL) {
10563 errno = 0;
10564 f = fopen(argsp->filename, "wb");
10565 if (f == NULL) {
10566 if (errno == 0)
10567 uu_die(gettext("Could not open \"%s\": no free "
10568 "stdio streams.\n"), argsp->filename);
10569 else
10570 uu_die(gettext("Could not open \"%s\""),
10571 argsp->filename);
10572 }
10573 } else
10574 f = stdout;
10575
10576 doc = xmlNewDoc((xmlChar *)"1.0");
10577 if (doc == NULL)
10578 uu_die(gettext("Could not create XML document.\n"));
10579
10580 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10581 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10582 uu_die(emsg_create_xml);
10583
10584 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10585 if (sb == NULL)
10586 uu_die(emsg_create_xml);
10587 safe_setprop(sb, type_attr, "manifest");
10588 safe_setprop(sb, name_attr, "export");
10589 (void) xmlAddSibling(doc->children, sb);
10590
10591 (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
10592
10593 result = write_service_bundle(doc, f);
10594
10595 free(exp_str);
10596 scf_iter_destroy(exp_val_iter);
10597 scf_iter_destroy(exp_prop_iter);
10598 scf_iter_destroy(exp_pg_iter);
10599 scf_iter_destroy(exp_inst_iter);
10600 scf_value_destroy(exp_val);
10601 scf_property_destroy(exp_prop);
10602 scf_pg_destroy(exp_pg);
10603 scf_instance_destroy(exp_inst);
10604
10605 xmlFreeDoc(doc);
10606
10607 if (f != stdout)
10608 (void) fclose(f);
10609
10610 return (result);
10611 }
10612
10613 /*
10614 * Get the service named by fmri, build an XML tree which represents it, and
10615 * dump it into filename (or stdout if filename is NULL).
10616 */
10617 int
lscf_service_export(char * fmri,const char * filename,int flags)10618 lscf_service_export(char *fmri, const char *filename, int flags)
10619 {
10620 struct export_args args;
10621 int ret, err;
10622
10623 lscf_prep_hndl();
10624
10625 bzero(&args, sizeof (args));
10626 args.filename = filename;
10627 args.flags = flags;
10628
10629 err = 0;
10630 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10631 SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10632 &args, &err, semerr)) != 0) {
10633 if (ret != -1)
10634 semerr(gettext("Failed to walk instances: %s\n"),
10635 scf_strerror(ret));
10636 return (-1);
10637 }
10638
10639 /*
10640 * Error message has already been printed.
10641 */
10642 if (err != 0)
10643 return (-1);
10644
10645 return (0);
10646 }
10647
10648
10649 /*
10650 * Archive
10651 */
10652
10653 static xmlNodePtr
make_archive(int flags)10654 make_archive(int flags)
10655 {
10656 xmlNodePtr sb;
10657 scf_scope_t *scope;
10658 scf_service_t *svc;
10659 scf_iter_t *iter;
10660 int r;
10661
10662 if ((scope = scf_scope_create(g_hndl)) == NULL ||
10663 (svc = scf_service_create(g_hndl)) == NULL ||
10664 (iter = scf_iter_create(g_hndl)) == NULL ||
10665 (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10666 (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10667 (exp_prop = scf_property_create(g_hndl)) == NULL ||
10668 (exp_val = scf_value_create(g_hndl)) == NULL ||
10669 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10670 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10671 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10672 (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10673 scfdie();
10674
10675 exp_str_sz = max_scf_len + 1;
10676 exp_str = safe_malloc(exp_str_sz);
10677
10678 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10679 if (sb == NULL)
10680 uu_die(emsg_create_xml);
10681 safe_setprop(sb, type_attr, "archive");
10682 safe_setprop(sb, name_attr, "none");
10683
10684 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
10685 scfdie();
10686 if (scf_iter_scope_services(iter, scope) != 0)
10687 scfdie();
10688
10689 for (;;) {
10690 r = scf_iter_next_service(iter, svc);
10691 if (r == 0)
10692 break;
10693 if (r != 1)
10694 scfdie();
10695
10696 if (scf_service_get_name(svc, exp_str,
10697 max_scf_name_len + 1) < 0)
10698 scfdie();
10699
10700 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
10701 continue;
10702
10703 (void) xmlAddChild(sb, export_service(svc, flags));
10704 }
10705
10706 free(exp_str);
10707
10708 scf_iter_destroy(exp_val_iter);
10709 scf_iter_destroy(exp_prop_iter);
10710 scf_iter_destroy(exp_pg_iter);
10711 scf_iter_destroy(exp_inst_iter);
10712 scf_value_destroy(exp_val);
10713 scf_property_destroy(exp_prop);
10714 scf_pg_destroy(exp_pg);
10715 scf_instance_destroy(exp_inst);
10716 scf_iter_destroy(iter);
10717 scf_service_destroy(svc);
10718 scf_scope_destroy(scope);
10719
10720 return (sb);
10721 }
10722
10723 int
lscf_archive(const char * filename,int flags)10724 lscf_archive(const char *filename, int flags)
10725 {
10726 FILE *f;
10727 xmlDocPtr doc;
10728 int result;
10729
10730 lscf_prep_hndl();
10731
10732 if (filename != NULL) {
10733 errno = 0;
10734 f = fopen(filename, "wb");
10735 if (f == NULL) {
10736 if (errno == 0)
10737 uu_die(gettext("Could not open \"%s\": no free "
10738 "stdio streams.\n"), filename);
10739 else
10740 uu_die(gettext("Could not open \"%s\""),
10741 filename);
10742 }
10743 } else
10744 f = stdout;
10745
10746 doc = xmlNewDoc((xmlChar *)"1.0");
10747 if (doc == NULL)
10748 uu_die(gettext("Could not create XML document.\n"));
10749
10750 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10751 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10752 uu_die(emsg_create_xml);
10753
10754 (void) xmlAddSibling(doc->children, make_archive(flags));
10755
10756 result = write_service_bundle(doc, f);
10757
10758 xmlFreeDoc(doc);
10759
10760 if (f != stdout)
10761 (void) fclose(f);
10762
10763 return (result);
10764 }
10765
10766
10767 /*
10768 * "Extract" a profile.
10769 */
10770 int
lscf_profile_extract(const char * filename)10771 lscf_profile_extract(const char *filename)
10772 {
10773 FILE *f;
10774 xmlDocPtr doc;
10775 xmlNodePtr sb, snode, inode;
10776 scf_scope_t *scope;
10777 scf_service_t *svc;
10778 scf_instance_t *inst;
10779 scf_propertygroup_t *pg;
10780 scf_property_t *prop;
10781 scf_value_t *val;
10782 scf_iter_t *siter, *iiter;
10783 int r, s;
10784 char *namebuf;
10785 uint8_t b;
10786 int result;
10787
10788 lscf_prep_hndl();
10789
10790 if (filename != NULL) {
10791 errno = 0;
10792 f = fopen(filename, "wb");
10793 if (f == NULL) {
10794 if (errno == 0)
10795 uu_die(gettext("Could not open \"%s\": no "
10796 "free stdio streams.\n"), filename);
10797 else
10798 uu_die(gettext("Could not open \"%s\""),
10799 filename);
10800 }
10801 } else
10802 f = stdout;
10803
10804 doc = xmlNewDoc((xmlChar *)"1.0");
10805 if (doc == NULL)
10806 uu_die(gettext("Could not create XML document.\n"));
10807
10808 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10809 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10810 uu_die(emsg_create_xml);
10811
10812 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10813 if (sb == NULL)
10814 uu_die(emsg_create_xml);
10815 safe_setprop(sb, type_attr, "profile");
10816 safe_setprop(sb, name_attr, "extract");
10817 (void) xmlAddSibling(doc->children, sb);
10818
10819 if ((scope = scf_scope_create(g_hndl)) == NULL ||
10820 (svc = scf_service_create(g_hndl)) == NULL ||
10821 (inst = scf_instance_create(g_hndl)) == NULL ||
10822 (pg = scf_pg_create(g_hndl)) == NULL ||
10823 (prop = scf_property_create(g_hndl)) == NULL ||
10824 (val = scf_value_create(g_hndl)) == NULL ||
10825 (siter = scf_iter_create(g_hndl)) == NULL ||
10826 (iiter = scf_iter_create(g_hndl)) == NULL)
10827 scfdie();
10828
10829 if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
10830 scfdie();
10831
10832 if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
10833 scfdie();
10834
10835 namebuf = safe_malloc(max_scf_name_len + 1);
10836
10837 while ((r = scf_iter_next_service(siter, svc)) == 1) {
10838 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
10839 scfdie();
10840
10841 snode = xmlNewNode(NULL, (xmlChar *)"service");
10842 if (snode == NULL)
10843 uu_die(emsg_create_xml);
10844
10845 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
10846 0)
10847 scfdie();
10848
10849 safe_setprop(snode, name_attr, namebuf);
10850
10851 safe_setprop(snode, type_attr, "service");
10852 safe_setprop(snode, "version", "0");
10853
10854 while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
10855 if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
10856 SCF_SUCCESS) {
10857 if (scf_error() != SCF_ERROR_NOT_FOUND)
10858 scfdie();
10859
10860 if (g_verbose) {
10861 ssize_t len;
10862 char *fmri;
10863
10864 len =
10865 scf_instance_to_fmri(inst, NULL, 0);
10866 if (len < 0)
10867 scfdie();
10868
10869 fmri = safe_malloc(len + 1);
10870
10871 if (scf_instance_to_fmri(inst, fmri,
10872 len + 1) < 0)
10873 scfdie();
10874
10875 warn("Instance %s has no \"%s\" "
10876 "property group.\n", fmri,
10877 scf_pg_general);
10878
10879 free(fmri);
10880 }
10881
10882 continue;
10883 }
10884
10885 if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
10886 prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
10887 prop_get_val(prop, val) != 0)
10888 continue;
10889
10890 inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
10891 NULL);
10892 if (inode == NULL)
10893 uu_die(emsg_create_xml);
10894
10895 if (scf_instance_get_name(inst, namebuf,
10896 max_scf_name_len + 1) < 0)
10897 scfdie();
10898
10899 safe_setprop(inode, name_attr, namebuf);
10900
10901 if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
10902 scfdie();
10903
10904 safe_setprop(inode, enabled_attr, b ? true : false);
10905 }
10906 if (s < 0)
10907 scfdie();
10908
10909 if (snode->children != NULL)
10910 (void) xmlAddChild(sb, snode);
10911 else
10912 xmlFreeNode(snode);
10913 }
10914 if (r < 0)
10915 scfdie();
10916
10917 free(namebuf);
10918
10919 result = write_service_bundle(doc, f);
10920
10921 xmlFreeDoc(doc);
10922
10923 if (f != stdout)
10924 (void) fclose(f);
10925
10926 return (result);
10927 }
10928
10929
10930 /*
10931 * Entity manipulation commands
10932 */
10933
10934 /*
10935 * Entity selection. If no entity is selected, then the current scope is in
10936 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected,
10937 * only cur_inst is NULL, and when an instance is selected, none are NULL.
10938 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
10939 * cur_inst will be non-NULL.
10940 */
10941
10942 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
10943 static int
select_inst(const char * name)10944 select_inst(const char *name)
10945 {
10946 scf_instance_t *inst;
10947 scf_error_t err;
10948
10949 assert(cur_svc != NULL);
10950
10951 inst = scf_instance_create(g_hndl);
10952 if (inst == NULL)
10953 scfdie();
10954
10955 if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
10956 cur_inst = inst;
10957 return (0);
10958 }
10959
10960 err = scf_error();
10961 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
10962 scfdie();
10963
10964 scf_instance_destroy(inst);
10965 return (1);
10966 }
10967
10968 /* Returns as above. */
10969 static int
select_svc(const char * name)10970 select_svc(const char *name)
10971 {
10972 scf_service_t *svc;
10973 scf_error_t err;
10974
10975 assert(cur_scope != NULL);
10976
10977 svc = scf_service_create(g_hndl);
10978 if (svc == NULL)
10979 scfdie();
10980
10981 if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
10982 cur_svc = svc;
10983 return (0);
10984 }
10985
10986 err = scf_error();
10987 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
10988 scfdie();
10989
10990 scf_service_destroy(svc);
10991 return (1);
10992 }
10993
10994 /* ARGSUSED */
10995 static int
select_callback(void * unused,scf_walkinfo_t * wip)10996 select_callback(void *unused, scf_walkinfo_t *wip)
10997 {
10998 scf_instance_t *inst;
10999 scf_service_t *svc;
11000 scf_scope_t *scope;
11001
11002 if (wip->inst != NULL) {
11003 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11004 (svc = scf_service_create(g_hndl)) == NULL ||
11005 (inst = scf_instance_create(g_hndl)) == NULL)
11006 scfdie();
11007
11008 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11009 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11010 scfdie();
11011 } else {
11012 assert(wip->svc != NULL);
11013
11014 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11015 (svc = scf_service_create(g_hndl)) == NULL)
11016 scfdie();
11017
11018 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11019 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11020 scfdie();
11021
11022 inst = NULL;
11023 }
11024
11025 /* Clear out the current selection */
11026 assert(cur_scope != NULL);
11027 scf_scope_destroy(cur_scope);
11028 scf_service_destroy(cur_svc);
11029 scf_instance_destroy(cur_inst);
11030
11031 cur_scope = scope;
11032 cur_svc = svc;
11033 cur_inst = inst;
11034
11035 return (0);
11036 }
11037
11038 static int
validate_callback(void * fmri_p,scf_walkinfo_t * wip)11039 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
11040 {
11041 char **fmri = fmri_p;
11042
11043 *fmri = strdup(wip->fmri);
11044 if (*fmri == NULL)
11045 uu_die(gettext("Out of memory.\n"));
11046
11047 return (0);
11048 }
11049
11050 /*
11051 * validate [fmri]
11052 * Perform the validation of an FMRI instance.
11053 */
11054 void
lscf_validate_fmri(const char * fmri)11055 lscf_validate_fmri(const char *fmri)
11056 {
11057 int ret = 0;
11058 size_t inst_sz;
11059 char *inst_fmri = NULL;
11060 scf_tmpl_errors_t *errs = NULL;
11061 char *snapbuf = NULL;
11062
11063 lscf_prep_hndl();
11064
11065 if (fmri == NULL) {
11066 inst_sz = max_scf_fmri_len + 1;
11067 inst_fmri = safe_malloc(inst_sz);
11068
11069 if (cur_snap != NULL) {
11070 snapbuf = safe_malloc(max_scf_name_len + 1);
11071 if (scf_snapshot_get_name(cur_snap, snapbuf,
11072 max_scf_name_len + 1) < 0)
11073 scfdie();
11074 }
11075 if (cur_inst == NULL) {
11076 semerr(gettext("No instance selected\n"));
11077 goto cleanup;
11078 } else if (scf_instance_to_fmri(cur_inst, inst_fmri,
11079 inst_sz) >= inst_sz) {
11080 /* sanity check. Should never get here */
11081 uu_die(gettext("Unexpected error! file %s, line %d\n"),
11082 __FILE__, __LINE__);
11083 }
11084 } else {
11085 scf_error_t scf_err;
11086 int err = 0;
11087
11088 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
11089 validate_callback, &inst_fmri, &err, semerr)) != 0) {
11090 uu_warn("Failed to walk instances: %s\n",
11091 scf_strerror(scf_err));
11092 goto cleanup;
11093 }
11094 if (err != 0) {
11095 /* error message displayed by scf_walk_fmri */
11096 goto cleanup;
11097 }
11098 }
11099
11100 ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
11101 SCF_TMPL_VALIDATE_FLAG_CURRENT);
11102 if (ret == -1) {
11103 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
11104 warn(gettext("Template data for %s is invalid. "
11105 "Consider reverting to a previous snapshot or "
11106 "restoring original configuration.\n"), inst_fmri);
11107 } else {
11108 uu_warn("%s: %s\n",
11109 gettext("Error validating the instance"),
11110 scf_strerror(scf_error()));
11111 }
11112 } else if (ret == 1 && errs != NULL) {
11113 scf_tmpl_error_t *err = NULL;
11114 char *msg;
11115 size_t len = 256; /* initial error buffer size */
11116 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
11117 SCF_TMPL_STRERROR_HUMAN : 0;
11118
11119 msg = safe_malloc(len);
11120
11121 while ((err = scf_tmpl_next_error(errs)) != NULL) {
11122 int ret;
11123
11124 if ((ret = scf_tmpl_strerror(err, msg, len,
11125 flag)) >= len) {
11126 len = ret + 1;
11127 msg = realloc(msg, len);
11128 if (msg == NULL)
11129 uu_die(gettext(
11130 "Out of memory.\n"));
11131 (void) scf_tmpl_strerror(err, msg, len,
11132 flag);
11133 }
11134 (void) fprintf(stderr, "%s\n", msg);
11135 }
11136 if (msg != NULL)
11137 free(msg);
11138 }
11139 if (errs != NULL)
11140 scf_tmpl_errors_destroy(errs);
11141
11142 cleanup:
11143 free(inst_fmri);
11144 free(snapbuf);
11145 }
11146
11147 static void
lscf_validate_file(const char * filename)11148 lscf_validate_file(const char *filename)
11149 {
11150 tmpl_errors_t *errs;
11151
11152 bundle_t *b = internal_bundle_new();
11153 if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
11154 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
11155 tmpl_errors_print(stderr, errs, "");
11156 semerr(gettext("Validation failed.\n"));
11157 }
11158 tmpl_errors_destroy(errs);
11159 }
11160 (void) internal_bundle_free(b);
11161 }
11162
11163 /*
11164 * validate [fmri|file]
11165 */
11166 void
lscf_validate(const char * arg)11167 lscf_validate(const char *arg)
11168 {
11169 const char *str;
11170
11171 if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
11172 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
11173 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
11174 lscf_validate_file(str);
11175 } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
11176 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
11177 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
11178 lscf_validate_fmri(str);
11179 } else if (access(arg, R_OK | F_OK) == 0) {
11180 lscf_validate_file(arg);
11181 } else {
11182 lscf_validate_fmri(arg);
11183 }
11184 }
11185
11186 void
lscf_select(const char * fmri)11187 lscf_select(const char *fmri)
11188 {
11189 int ret, err;
11190
11191 lscf_prep_hndl();
11192
11193 if (cur_snap != NULL) {
11194 struct snaplevel *elt;
11195 char *buf;
11196
11197 /* Error unless name is that of the next level. */
11198 elt = uu_list_next(cur_levels, cur_elt);
11199 if (elt == NULL) {
11200 semerr(gettext("No children.\n"));
11201 return;
11202 }
11203
11204 buf = safe_malloc(max_scf_name_len + 1);
11205
11206 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11207 max_scf_name_len + 1) < 0)
11208 scfdie();
11209
11210 if (strcmp(buf, fmri) != 0) {
11211 semerr(gettext("No such child.\n"));
11212 free(buf);
11213 return;
11214 }
11215
11216 free(buf);
11217
11218 cur_elt = elt;
11219 cur_level = elt->sl;
11220 return;
11221 }
11222
11223 /*
11224 * Special case for 'svc:', which takes the user to the scope level.
11225 */
11226 if (strcmp(fmri, "svc:") == 0) {
11227 scf_instance_destroy(cur_inst);
11228 scf_service_destroy(cur_svc);
11229 cur_inst = NULL;
11230 cur_svc = NULL;
11231 return;
11232 }
11233
11234 /*
11235 * Special case for ':properties'. This appears as part of 'list' but
11236 * can't be selected. Give a more helpful error message in this case.
11237 */
11238 if (strcmp(fmri, ":properties") == 0) {
11239 semerr(gettext(":properties is not an entity. Try 'listprop' "
11240 "to list properties.\n"));
11241 return;
11242 }
11243
11244 /*
11245 * First try the argument as relative to the current selection.
11246 */
11247 if (cur_inst != NULL) {
11248 /* EMPTY */;
11249 } else if (cur_svc != NULL) {
11250 if (select_inst(fmri) != 1)
11251 return;
11252 } else {
11253 if (select_svc(fmri) != 1)
11254 return;
11255 }
11256
11257 err = 0;
11258 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11259 select_callback, NULL, &err, semerr)) != 0) {
11260 semerr(gettext("Failed to walk instances: %s\n"),
11261 scf_strerror(ret));
11262 }
11263 }
11264
11265 void
lscf_unselect(void)11266 lscf_unselect(void)
11267 {
11268 lscf_prep_hndl();
11269
11270 if (cur_snap != NULL) {
11271 struct snaplevel *elt;
11272
11273 elt = uu_list_prev(cur_levels, cur_elt);
11274 if (elt == NULL) {
11275 semerr(gettext("No parent levels.\n"));
11276 } else {
11277 cur_elt = elt;
11278 cur_level = elt->sl;
11279 }
11280 } else if (cur_inst != NULL) {
11281 scf_instance_destroy(cur_inst);
11282 cur_inst = NULL;
11283 } else if (cur_svc != NULL) {
11284 scf_service_destroy(cur_svc);
11285 cur_svc = NULL;
11286 } else {
11287 semerr(gettext("Cannot unselect at scope level.\n"));
11288 }
11289 }
11290
11291 /*
11292 * Return the FMRI of the current selection, for the prompt.
11293 */
11294 void
lscf_get_selection_str(char * buf,size_t bufsz)11295 lscf_get_selection_str(char *buf, size_t bufsz)
11296 {
11297 char *cp;
11298 ssize_t fmrilen, szret;
11299 boolean_t deleted = B_FALSE;
11300
11301 if (g_hndl == NULL) {
11302 (void) strlcpy(buf, "svc:", bufsz);
11303 return;
11304 }
11305
11306 if (cur_level != NULL) {
11307 assert(cur_snap != NULL);
11308
11309 /* [ snapshot ] FMRI [: instance ] */
11310 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11311 + 2 + max_scf_name_len + 1 + 1);
11312
11313 buf[0] = '[';
11314
11315 szret = scf_snapshot_get_name(cur_snap, buf + 1,
11316 max_scf_name_len + 1);
11317 if (szret < 0) {
11318 if (scf_error() != SCF_ERROR_DELETED)
11319 scfdie();
11320
11321 goto snap_deleted;
11322 }
11323
11324 (void) strcat(buf, "]svc:/");
11325
11326 cp = strchr(buf, '\0');
11327
11328 szret = scf_snaplevel_get_service_name(cur_level, cp,
11329 max_scf_name_len + 1);
11330 if (szret < 0) {
11331 if (scf_error() != SCF_ERROR_DELETED)
11332 scfdie();
11333
11334 goto snap_deleted;
11335 }
11336
11337 cp = strchr(cp, '\0');
11338
11339 if (snaplevel_is_instance(cur_level)) {
11340 *cp++ = ':';
11341
11342 if (scf_snaplevel_get_instance_name(cur_level, cp,
11343 max_scf_name_len + 1) < 0) {
11344 if (scf_error() != SCF_ERROR_DELETED)
11345 scfdie();
11346
11347 goto snap_deleted;
11348 }
11349 } else {
11350 *cp++ = '[';
11351 *cp++ = ':';
11352
11353 if (scf_instance_get_name(cur_inst, cp,
11354 max_scf_name_len + 1) < 0) {
11355 if (scf_error() != SCF_ERROR_DELETED)
11356 scfdie();
11357
11358 goto snap_deleted;
11359 }
11360
11361 (void) strcat(buf, "]");
11362 }
11363
11364 return;
11365
11366 snap_deleted:
11367 deleted = B_TRUE;
11368 free(buf);
11369 unselect_cursnap();
11370 }
11371
11372 assert(cur_snap == NULL);
11373
11374 if (cur_inst != NULL) {
11375 assert(cur_svc != NULL);
11376 assert(cur_scope != NULL);
11377
11378 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11379 if (fmrilen >= 0) {
11380 assert(fmrilen < bufsz);
11381 if (deleted)
11382 warn(emsg_deleted);
11383 return;
11384 }
11385
11386 if (scf_error() != SCF_ERROR_DELETED)
11387 scfdie();
11388
11389 deleted = B_TRUE;
11390
11391 scf_instance_destroy(cur_inst);
11392 cur_inst = NULL;
11393 }
11394
11395 if (cur_svc != NULL) {
11396 assert(cur_scope != NULL);
11397
11398 szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11399 if (szret >= 0) {
11400 assert(szret < bufsz);
11401 if (deleted)
11402 warn(emsg_deleted);
11403 return;
11404 }
11405
11406 if (scf_error() != SCF_ERROR_DELETED)
11407 scfdie();
11408
11409 deleted = B_TRUE;
11410 scf_service_destroy(cur_svc);
11411 cur_svc = NULL;
11412 }
11413
11414 assert(cur_scope != NULL);
11415 fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11416
11417 if (fmrilen < 0)
11418 scfdie();
11419
11420 assert(fmrilen < bufsz);
11421 if (deleted)
11422 warn(emsg_deleted);
11423 }
11424
11425 /*
11426 * Entity listing. Entities and colon namespaces (e.g., :properties and
11427 * :statistics) are listed for the current selection.
11428 */
11429 void
lscf_list(const char * pattern)11430 lscf_list(const char *pattern)
11431 {
11432 scf_iter_t *iter;
11433 char *buf;
11434 int ret;
11435
11436 lscf_prep_hndl();
11437
11438 if (cur_level != NULL) {
11439 struct snaplevel *elt;
11440
11441 (void) fputs(COLON_NAMESPACES, stdout);
11442
11443 elt = uu_list_next(cur_levels, cur_elt);
11444 if (elt == NULL)
11445 return;
11446
11447 /*
11448 * For now, we know that the next level is an instance. But
11449 * if we ever have multiple scopes, this could be complicated.
11450 */
11451 buf = safe_malloc(max_scf_name_len + 1);
11452 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11453 max_scf_name_len + 1) >= 0) {
11454 (void) puts(buf);
11455 } else {
11456 if (scf_error() != SCF_ERROR_DELETED)
11457 scfdie();
11458 }
11459
11460 free(buf);
11461
11462 return;
11463 }
11464
11465 if (cur_inst != NULL) {
11466 (void) fputs(COLON_NAMESPACES, stdout);
11467 return;
11468 }
11469
11470 iter = scf_iter_create(g_hndl);
11471 if (iter == NULL)
11472 scfdie();
11473
11474 buf = safe_malloc(max_scf_name_len + 1);
11475
11476 if (cur_svc != NULL) {
11477 /* List the instances in this service. */
11478 scf_instance_t *inst;
11479
11480 inst = scf_instance_create(g_hndl);
11481 if (inst == NULL)
11482 scfdie();
11483
11484 if (scf_iter_service_instances(iter, cur_svc) == 0) {
11485 safe_printf(COLON_NAMESPACES);
11486
11487 for (;;) {
11488 ret = scf_iter_next_instance(iter, inst);
11489 if (ret == 0)
11490 break;
11491 if (ret != 1) {
11492 if (scf_error() != SCF_ERROR_DELETED)
11493 scfdie();
11494
11495 break;
11496 }
11497
11498 if (scf_instance_get_name(inst, buf,
11499 max_scf_name_len + 1) >= 0) {
11500 if (pattern == NULL ||
11501 fnmatch(pattern, buf, 0) == 0)
11502 (void) puts(buf);
11503 } else {
11504 if (scf_error() != SCF_ERROR_DELETED)
11505 scfdie();
11506 }
11507 }
11508 } else {
11509 if (scf_error() != SCF_ERROR_DELETED)
11510 scfdie();
11511 }
11512
11513 scf_instance_destroy(inst);
11514 } else {
11515 /* List the services in this scope. */
11516 scf_service_t *svc;
11517
11518 assert(cur_scope != NULL);
11519
11520 svc = scf_service_create(g_hndl);
11521 if (svc == NULL)
11522 scfdie();
11523
11524 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11525 scfdie();
11526
11527 for (;;) {
11528 ret = scf_iter_next_service(iter, svc);
11529 if (ret == 0)
11530 break;
11531 if (ret != 1)
11532 scfdie();
11533
11534 if (scf_service_get_name(svc, buf,
11535 max_scf_name_len + 1) >= 0) {
11536 if (pattern == NULL ||
11537 fnmatch(pattern, buf, 0) == 0)
11538 safe_printf("%s\n", buf);
11539 } else {
11540 if (scf_error() != SCF_ERROR_DELETED)
11541 scfdie();
11542 }
11543 }
11544
11545 scf_service_destroy(svc);
11546 }
11547
11548 free(buf);
11549 scf_iter_destroy(iter);
11550 }
11551
11552 /*
11553 * Entity addition. Creates an empty entity in the current selection.
11554 */
11555 void
lscf_add(const char * name)11556 lscf_add(const char *name)
11557 {
11558 lscf_prep_hndl();
11559
11560 if (cur_snap != NULL) {
11561 semerr(emsg_cant_modify_snapshots);
11562 } else if (cur_inst != NULL) {
11563 semerr(gettext("Cannot add entities to an instance.\n"));
11564 } else if (cur_svc != NULL) {
11565
11566 if (scf_service_add_instance(cur_svc, name, NULL) !=
11567 SCF_SUCCESS) {
11568 switch (scf_error()) {
11569 case SCF_ERROR_INVALID_ARGUMENT:
11570 semerr(gettext("Invalid name.\n"));
11571 break;
11572
11573 case SCF_ERROR_EXISTS:
11574 semerr(gettext("Instance already exists.\n"));
11575 break;
11576
11577 case SCF_ERROR_PERMISSION_DENIED:
11578 semerr(emsg_permission_denied);
11579 break;
11580
11581 default:
11582 scfdie();
11583 }
11584 }
11585 } else {
11586 assert(cur_scope != NULL);
11587
11588 if (scf_scope_add_service(cur_scope, name, NULL) !=
11589 SCF_SUCCESS) {
11590 switch (scf_error()) {
11591 case SCF_ERROR_INVALID_ARGUMENT:
11592 semerr(gettext("Invalid name.\n"));
11593 break;
11594
11595 case SCF_ERROR_EXISTS:
11596 semerr(gettext("Service already exists.\n"));
11597 break;
11598
11599 case SCF_ERROR_PERMISSION_DENIED:
11600 semerr(emsg_permission_denied);
11601 break;
11602
11603 case SCF_ERROR_BACKEND_READONLY:
11604 semerr(emsg_read_only);
11605 break;
11606
11607 default:
11608 scfdie();
11609 }
11610 }
11611 }
11612 }
11613
11614 /* return 1 if the entity has no persistent pgs, else return 0 */
11615 static int
entity_has_no_pgs(void * ent,int isservice)11616 entity_has_no_pgs(void *ent, int isservice)
11617 {
11618 scf_iter_t *iter = NULL;
11619 scf_propertygroup_t *pg = NULL;
11620 uint32_t flags;
11621 int err;
11622 int ret = 1;
11623
11624 if ((iter = scf_iter_create(g_hndl)) == NULL ||
11625 (pg = scf_pg_create(g_hndl)) == NULL)
11626 scfdie();
11627
11628 if (isservice) {
11629 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11630 scfdie();
11631 } else {
11632 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11633 scfdie();
11634 }
11635
11636 while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11637 if (scf_pg_get_flags(pg, &flags) != 0)
11638 scfdie();
11639
11640 /* skip nonpersistent pgs */
11641 if (flags & SCF_PG_FLAG_NONPERSISTENT)
11642 continue;
11643
11644 ret = 0;
11645 break;
11646 }
11647
11648 if (err == -1)
11649 scfdie();
11650
11651 scf_pg_destroy(pg);
11652 scf_iter_destroy(iter);
11653
11654 return (ret);
11655 }
11656
11657 /* return 1 if the service has no instances, else return 0 */
11658 static int
svc_has_no_insts(scf_service_t * svc)11659 svc_has_no_insts(scf_service_t *svc)
11660 {
11661 scf_instance_t *inst;
11662 scf_iter_t *iter;
11663 int r;
11664 int ret = 1;
11665
11666 if ((inst = scf_instance_create(g_hndl)) == NULL ||
11667 (iter = scf_iter_create(g_hndl)) == NULL)
11668 scfdie();
11669
11670 if (scf_iter_service_instances(iter, svc) != 0)
11671 scfdie();
11672
11673 r = scf_iter_next_instance(iter, inst);
11674 if (r == 1) {
11675 ret = 0;
11676 } else if (r == 0) {
11677 ret = 1;
11678 } else if (r == -1) {
11679 scfdie();
11680 } else {
11681 bad_error("scf_iter_next_instance", r);
11682 }
11683
11684 scf_iter_destroy(iter);
11685 scf_instance_destroy(inst);
11686
11687 return (ret);
11688 }
11689
11690 /*
11691 * Entity deletion.
11692 */
11693
11694 /*
11695 * Delete the property group <fmri>/:properties/<name>. Returns
11696 * SCF_ERROR_NONE on success (or if the entity is not found),
11697 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
11698 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
11699 * denied.
11700 */
11701 static scf_error_t
delete_dependency_pg(const char * fmri,const char * name)11702 delete_dependency_pg(const char *fmri, const char *name)
11703 {
11704 void *entity = NULL;
11705 int isservice;
11706 scf_propertygroup_t *pg = NULL;
11707 scf_error_t result;
11708 char *pgty;
11709 scf_service_t *svc = NULL;
11710 scf_instance_t *inst = NULL;
11711 scf_iter_t *iter = NULL;
11712 char *name_buf = NULL;
11713
11714 result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
11715 switch (result) {
11716 case SCF_ERROR_NONE:
11717 break;
11718
11719 case SCF_ERROR_NO_MEMORY:
11720 uu_die(gettext("Out of memory.\n"));
11721 /* NOTREACHED */
11722
11723 case SCF_ERROR_INVALID_ARGUMENT:
11724 case SCF_ERROR_CONSTRAINT_VIOLATED:
11725 return (SCF_ERROR_INVALID_ARGUMENT);
11726
11727 case SCF_ERROR_NOT_FOUND:
11728 result = SCF_ERROR_NONE;
11729 goto out;
11730
11731 default:
11732 bad_error("fmri_to_entity", result);
11733 }
11734
11735 pg = scf_pg_create(g_hndl);
11736 if (pg == NULL)
11737 scfdie();
11738
11739 if (entity_get_pg(entity, isservice, name, pg) != 0) {
11740 if (scf_error() != SCF_ERROR_NOT_FOUND)
11741 scfdie();
11742
11743 result = SCF_ERROR_NONE;
11744 goto out;
11745 }
11746
11747 pgty = safe_malloc(max_scf_pg_type_len + 1);
11748
11749 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
11750 scfdie();
11751
11752 if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
11753 result = SCF_ERROR_TYPE_MISMATCH;
11754 free(pgty);
11755 goto out;
11756 }
11757
11758 free(pgty);
11759
11760 if (scf_pg_delete(pg) != 0) {
11761 result = scf_error();
11762 if (result != SCF_ERROR_PERMISSION_DENIED)
11763 scfdie();
11764 goto out;
11765 }
11766
11767 /*
11768 * We have to handle the case where we've just deleted the last
11769 * property group of a "dummy" entity (instance or service).
11770 * A "dummy" entity is an entity only present to hold an
11771 * external dependency.
11772 * So, in the case we deleted the last property group then we
11773 * can also delete the entity. If the entity is an instance then
11774 * we must verify if this was the last instance for the service
11775 * and if it is, we can also delete the service if it doesn't
11776 * have any property group either.
11777 */
11778
11779 result = SCF_ERROR_NONE;
11780
11781 if (isservice) {
11782 svc = (scf_service_t *)entity;
11783
11784 if ((inst = scf_instance_create(g_hndl)) == NULL ||
11785 (iter = scf_iter_create(g_hndl)) == NULL)
11786 scfdie();
11787
11788 name_buf = safe_malloc(max_scf_name_len + 1);
11789 } else {
11790 inst = (scf_instance_t *)entity;
11791 }
11792
11793 /*
11794 * If the entity is an instance and we've just deleted its last
11795 * property group then we should delete it.
11796 */
11797 if (!isservice && entity_has_no_pgs(entity, isservice)) {
11798 /* find the service before deleting the inst. - needed later */
11799 if ((svc = scf_service_create(g_hndl)) == NULL)
11800 scfdie();
11801
11802 if (scf_instance_get_parent(inst, svc) != 0)
11803 scfdie();
11804
11805 /* delete the instance */
11806 if (scf_instance_delete(inst) != 0) {
11807 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11808 scfdie();
11809
11810 result = SCF_ERROR_PERMISSION_DENIED;
11811 goto out;
11812 }
11813 /* no need to refresh the instance */
11814 inst = NULL;
11815 }
11816
11817 /*
11818 * If the service has no more instances and pgs or we just deleted the
11819 * last instance and the service doesn't have anymore propery groups
11820 * then the service should be deleted.
11821 */
11822 if (svc != NULL &&
11823 svc_has_no_insts(svc) &&
11824 entity_has_no_pgs((void *)svc, 1)) {
11825 if (scf_service_delete(svc) == 0) {
11826 if (isservice) {
11827 /* no need to refresh the service */
11828 svc = NULL;
11829 }
11830
11831 goto out;
11832 }
11833
11834 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11835 scfdie();
11836
11837 result = SCF_ERROR_PERMISSION_DENIED;
11838 }
11839
11840 /* if the entity has not been deleted, refresh it */
11841 if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
11842 (void) refresh_entity(isservice, entity, fmri, inst, iter,
11843 name_buf);
11844 }
11845
11846 out:
11847 if (isservice && (inst != NULL && iter != NULL)) {
11848 free(name_buf);
11849 scf_iter_destroy(iter);
11850 scf_instance_destroy(inst);
11851 }
11852
11853 if (!isservice && svc != NULL) {
11854 scf_service_destroy(svc);
11855 }
11856
11857 scf_pg_destroy(pg);
11858 if (entity != NULL)
11859 entity_destroy(entity, isservice);
11860
11861 return (result);
11862 }
11863
11864 static int
delete_dependents(scf_propertygroup_t * pg)11865 delete_dependents(scf_propertygroup_t *pg)
11866 {
11867 char *pgty, *name, *fmri;
11868 scf_property_t *prop;
11869 scf_value_t *val;
11870 scf_iter_t *iter;
11871 int r;
11872 scf_error_t err;
11873
11874 /* Verify that the pg has the correct type. */
11875 pgty = safe_malloc(max_scf_pg_type_len + 1);
11876 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
11877 scfdie();
11878
11879 if (strcmp(pgty, scf_group_framework) != 0) {
11880 if (g_verbose) {
11881 fmri = safe_malloc(max_scf_fmri_len + 1);
11882 if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
11883 scfdie();
11884
11885 warn(gettext("Property group %s is not of expected "
11886 "type %s.\n"), fmri, scf_group_framework);
11887
11888 free(fmri);
11889 }
11890
11891 free(pgty);
11892 return (-1);
11893 }
11894
11895 free(pgty);
11896
11897 /* map delete_dependency_pg onto the properties. */
11898 if ((prop = scf_property_create(g_hndl)) == NULL ||
11899 (val = scf_value_create(g_hndl)) == NULL ||
11900 (iter = scf_iter_create(g_hndl)) == NULL)
11901 scfdie();
11902
11903 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
11904 scfdie();
11905
11906 name = safe_malloc(max_scf_name_len + 1);
11907 fmri = safe_malloc(max_scf_fmri_len + 2);
11908
11909 while ((r = scf_iter_next_property(iter, prop)) == 1) {
11910 scf_type_t ty;
11911
11912 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
11913 scfdie();
11914
11915 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
11916 scfdie();
11917
11918 if ((ty != SCF_TYPE_ASTRING &&
11919 prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
11920 prop_get_val(prop, val) != 0)
11921 continue;
11922
11923 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
11924 scfdie();
11925
11926 err = delete_dependency_pg(fmri, name);
11927 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
11928 if (scf_property_to_fmri(prop, fmri,
11929 max_scf_fmri_len + 2) < 0)
11930 scfdie();
11931
11932 warn(gettext("Value of %s is not a valid FMRI.\n"),
11933 fmri);
11934 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
11935 warn(gettext("Property group \"%s\" of entity \"%s\" "
11936 "does not have dependency type.\n"), name, fmri);
11937 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
11938 warn(gettext("Could not delete property group \"%s\" "
11939 "of entity \"%s\" (permission denied).\n"), name,
11940 fmri);
11941 }
11942 }
11943 if (r == -1)
11944 scfdie();
11945
11946 scf_value_destroy(val);
11947 scf_property_destroy(prop);
11948
11949 return (0);
11950 }
11951
11952 /*
11953 * Returns 1 if the instance may be running, and 0 otherwise.
11954 */
11955 static int
inst_is_running(scf_instance_t * inst)11956 inst_is_running(scf_instance_t *inst)
11957 {
11958 scf_propertygroup_t *pg;
11959 scf_property_t *prop;
11960 scf_value_t *val;
11961 char buf[MAX_SCF_STATE_STRING_SZ];
11962 int ret = 0;
11963 ssize_t szret;
11964
11965 if ((pg = scf_pg_create(g_hndl)) == NULL ||
11966 (prop = scf_property_create(g_hndl)) == NULL ||
11967 (val = scf_value_create(g_hndl)) == NULL)
11968 scfdie();
11969
11970 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
11971 if (scf_error() != SCF_ERROR_NOT_FOUND)
11972 scfdie();
11973 goto out;
11974 }
11975
11976 if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
11977 prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
11978 prop_get_val(prop, val) != 0)
11979 goto out;
11980
11981 szret = scf_value_get_astring(val, buf, sizeof (buf));
11982 assert(szret >= 0);
11983
11984 ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
11985 strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
11986
11987 out:
11988 scf_value_destroy(val);
11989 scf_property_destroy(prop);
11990 scf_pg_destroy(pg);
11991 return (ret);
11992 }
11993
11994 static uint8_t
pg_is_external_dependency(scf_propertygroup_t * pg)11995 pg_is_external_dependency(scf_propertygroup_t *pg)
11996 {
11997 char *type;
11998 scf_value_t *val;
11999 scf_property_t *prop;
12000 uint8_t b = B_FALSE;
12001
12002 type = safe_malloc(max_scf_pg_type_len + 1);
12003
12004 if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
12005 scfdie();
12006
12007 if ((prop = scf_property_create(g_hndl)) == NULL ||
12008 (val = scf_value_create(g_hndl)) == NULL)
12009 scfdie();
12010
12011 if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
12012 if (pg_get_prop(pg, scf_property_external, prop) == 0) {
12013 if (scf_property_get_value(prop, val) != 0)
12014 scfdie();
12015 if (scf_value_get_boolean(val, &b) != 0)
12016 scfdie();
12017 }
12018 }
12019
12020 free(type);
12021 (void) scf_value_destroy(val);
12022 (void) scf_property_destroy(prop);
12023
12024 return (b);
12025 }
12026
12027 #define DELETE_FAILURE -1
12028 #define DELETE_SUCCESS_NOEXTDEPS 0
12029 #define DELETE_SUCCESS_EXTDEPS 1
12030
12031 /*
12032 * lscf_instance_delete() deletes an instance. Before calling
12033 * scf_instance_delete(), though, we make sure the instance isn't
12034 * running and delete dependencies in other entities which the instance
12035 * declared as "dependents". If there are dependencies which were
12036 * created for other entities, then instead of deleting the instance we
12037 * make it "empty" by deleting all other property groups and all
12038 * snapshots.
12039 *
12040 * lscf_instance_delete() verifies that there is no external dependency pgs
12041 * before suppressing the instance. If there is, then we must not remove them
12042 * now in case the instance is re-created otherwise the dependencies would be
12043 * lost. The external dependency pgs will be removed if the dependencies are
12044 * removed.
12045 *
12046 * Returns:
12047 * DELETE_FAILURE on failure
12048 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12049 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12050 */
12051 static int
lscf_instance_delete(scf_instance_t * inst,int force)12052 lscf_instance_delete(scf_instance_t *inst, int force)
12053 {
12054 scf_propertygroup_t *pg;
12055 scf_snapshot_t *snap;
12056 scf_iter_t *iter;
12057 int err;
12058 int external = 0;
12059
12060 /* If we're not forcing and the instance is running, refuse. */
12061 if (!force && inst_is_running(inst)) {
12062 char *fmri;
12063
12064 fmri = safe_malloc(max_scf_fmri_len + 1);
12065
12066 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
12067 scfdie();
12068
12069 semerr(gettext("Instance %s may be running. "
12070 "Use delete -f if it is not.\n"), fmri);
12071
12072 free(fmri);
12073 return (DELETE_FAILURE);
12074 }
12075
12076 pg = scf_pg_create(g_hndl);
12077 if (pg == NULL)
12078 scfdie();
12079
12080 if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
12081 (void) delete_dependents(pg);
12082 else if (scf_error() != SCF_ERROR_NOT_FOUND)
12083 scfdie();
12084
12085 scf_pg_destroy(pg);
12086
12087 /*
12088 * If the instance has some external dependencies then we must
12089 * keep them in case the instance is reimported otherwise the
12090 * dependencies would be lost on reimport.
12091 */
12092 if ((iter = scf_iter_create(g_hndl)) == NULL ||
12093 (pg = scf_pg_create(g_hndl)) == NULL)
12094 scfdie();
12095
12096 if (scf_iter_instance_pgs(iter, inst) < 0)
12097 scfdie();
12098
12099 while ((err = scf_iter_next_pg(iter, pg)) == 1) {
12100 if (pg_is_external_dependency(pg)) {
12101 external = 1;
12102 continue;
12103 }
12104
12105 if (scf_pg_delete(pg) != 0) {
12106 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12107 scfdie();
12108 else {
12109 semerr(emsg_permission_denied);
12110
12111 (void) scf_iter_destroy(iter);
12112 (void) scf_pg_destroy(pg);
12113 return (DELETE_FAILURE);
12114 }
12115 }
12116 }
12117
12118 if (err == -1)
12119 scfdie();
12120
12121 (void) scf_iter_destroy(iter);
12122 (void) scf_pg_destroy(pg);
12123
12124 if (external) {
12125 /*
12126 * All the pgs have been deleted for the instance except
12127 * the ones holding the external dependencies.
12128 * For the job to be complete, we must also delete the
12129 * snapshots associated with the instance.
12130 */
12131 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
12132 NULL)
12133 scfdie();
12134 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
12135 scfdie();
12136
12137 if (scf_iter_instance_snapshots(iter, inst) == -1)
12138 scfdie();
12139
12140 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
12141 if (_scf_snapshot_delete(snap) != 0) {
12142 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12143 scfdie();
12144
12145 semerr(emsg_permission_denied);
12146
12147 (void) scf_iter_destroy(iter);
12148 (void) scf_snapshot_destroy(snap);
12149 return (DELETE_FAILURE);
12150 }
12151 }
12152
12153 if (err == -1)
12154 scfdie();
12155
12156 (void) scf_iter_destroy(iter);
12157 (void) scf_snapshot_destroy(snap);
12158 return (DELETE_SUCCESS_EXTDEPS);
12159 }
12160
12161 if (scf_instance_delete(inst) != 0) {
12162 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12163 scfdie();
12164
12165 semerr(emsg_permission_denied);
12166
12167 return (DELETE_FAILURE);
12168 }
12169
12170 return (DELETE_SUCCESS_NOEXTDEPS);
12171 }
12172
12173 /*
12174 * lscf_service_delete() deletes a service. Before calling
12175 * scf_service_delete(), though, we call lscf_instance_delete() for
12176 * each of the instances and delete dependencies in other entities
12177 * which were created as "dependents" of this service. If there are
12178 * dependencies which were created for other entities, then we delete
12179 * all other property groups in the service and leave it as "empty".
12180 *
12181 * lscf_service_delete() verifies that there is no external dependency
12182 * pgs at the instance & service level before suppressing the service.
12183 * If there is, then we must not remove them now in case the service
12184 * is re-imported otherwise the dependencies would be lost. The external
12185 * dependency pgs will be removed if the dependencies are removed.
12186 *
12187 * Returns:
12188 * DELETE_FAILURE on failure
12189 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12190 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12191 */
12192 static int
lscf_service_delete(scf_service_t * svc,int force)12193 lscf_service_delete(scf_service_t *svc, int force)
12194 {
12195 int r;
12196 scf_instance_t *inst;
12197 scf_propertygroup_t *pg;
12198 scf_iter_t *iter;
12199 int ret;
12200 int external = 0;
12201
12202 if ((inst = scf_instance_create(g_hndl)) == NULL ||
12203 (pg = scf_pg_create(g_hndl)) == NULL ||
12204 (iter = scf_iter_create(g_hndl)) == NULL)
12205 scfdie();
12206
12207 if (scf_iter_service_instances(iter, svc) != 0)
12208 scfdie();
12209
12210 for (r = scf_iter_next_instance(iter, inst);
12211 r == 1;
12212 r = scf_iter_next_instance(iter, inst)) {
12213
12214 ret = lscf_instance_delete(inst, force);
12215 if (ret == DELETE_FAILURE) {
12216 scf_iter_destroy(iter);
12217 scf_pg_destroy(pg);
12218 scf_instance_destroy(inst);
12219 return (DELETE_FAILURE);
12220 }
12221
12222 /*
12223 * Record the fact that there is some external dependencies
12224 * at the instance level.
12225 */
12226 if (ret == DELETE_SUCCESS_EXTDEPS)
12227 external |= 1;
12228 }
12229
12230 if (r != 0)
12231 scfdie();
12232
12233 /* Delete dependency property groups in dependent services. */
12234 if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12235 (void) delete_dependents(pg);
12236 else if (scf_error() != SCF_ERROR_NOT_FOUND)
12237 scfdie();
12238
12239 scf_iter_destroy(iter);
12240 scf_pg_destroy(pg);
12241 scf_instance_destroy(inst);
12242
12243 /*
12244 * If the service has some external dependencies then we don't
12245 * want to remove them in case the service is re-imported.
12246 */
12247 if ((pg = scf_pg_create(g_hndl)) == NULL ||
12248 (iter = scf_iter_create(g_hndl)) == NULL)
12249 scfdie();
12250
12251 if (scf_iter_service_pgs(iter, svc) < 0)
12252 scfdie();
12253
12254 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12255 if (pg_is_external_dependency(pg)) {
12256 external |= 2;
12257 continue;
12258 }
12259
12260 if (scf_pg_delete(pg) != 0) {
12261 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12262 scfdie();
12263 else {
12264 semerr(emsg_permission_denied);
12265
12266 (void) scf_iter_destroy(iter);
12267 (void) scf_pg_destroy(pg);
12268 return (DELETE_FAILURE);
12269 }
12270 }
12271 }
12272
12273 if (r == -1)
12274 scfdie();
12275
12276 (void) scf_iter_destroy(iter);
12277 (void) scf_pg_destroy(pg);
12278
12279 if (external != 0)
12280 return (DELETE_SUCCESS_EXTDEPS);
12281
12282 if (scf_service_delete(svc) == 0)
12283 return (DELETE_SUCCESS_NOEXTDEPS);
12284
12285 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12286 scfdie();
12287
12288 semerr(emsg_permission_denied);
12289 return (DELETE_FAILURE);
12290 }
12291
12292 static int
delete_callback(void * data,scf_walkinfo_t * wip)12293 delete_callback(void *data, scf_walkinfo_t *wip)
12294 {
12295 int force = (int)data;
12296
12297 if (wip->inst != NULL)
12298 (void) lscf_instance_delete(wip->inst, force);
12299 else
12300 (void) lscf_service_delete(wip->svc, force);
12301
12302 return (0);
12303 }
12304
12305 void
lscf_delete(const char * fmri,int force)12306 lscf_delete(const char *fmri, int force)
12307 {
12308 scf_service_t *svc;
12309 scf_instance_t *inst;
12310 int ret;
12311
12312 lscf_prep_hndl();
12313
12314 if (cur_snap != NULL) {
12315 if (!snaplevel_is_instance(cur_level)) {
12316 char *buf;
12317
12318 buf = safe_malloc(max_scf_name_len + 1);
12319 if (scf_instance_get_name(cur_inst, buf,
12320 max_scf_name_len + 1) >= 0) {
12321 if (strcmp(buf, fmri) == 0) {
12322 semerr(emsg_cant_modify_snapshots);
12323 free(buf);
12324 return;
12325 }
12326 } else if (scf_error() != SCF_ERROR_DELETED) {
12327 scfdie();
12328 }
12329 free(buf);
12330 }
12331 } else if (cur_inst != NULL) {
12332 /* EMPTY */;
12333 } else if (cur_svc != NULL) {
12334 inst = scf_instance_create(g_hndl);
12335 if (inst == NULL)
12336 scfdie();
12337
12338 if (scf_service_get_instance(cur_svc, fmri, inst) ==
12339 SCF_SUCCESS) {
12340 (void) lscf_instance_delete(inst, force);
12341 scf_instance_destroy(inst);
12342 return;
12343 }
12344
12345 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12346 scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12347 scfdie();
12348
12349 scf_instance_destroy(inst);
12350 } else {
12351 assert(cur_scope != NULL);
12352
12353 svc = scf_service_create(g_hndl);
12354 if (svc == NULL)
12355 scfdie();
12356
12357 if (scf_scope_get_service(cur_scope, fmri, svc) ==
12358 SCF_SUCCESS) {
12359 (void) lscf_service_delete(svc, force);
12360 scf_service_destroy(svc);
12361 return;
12362 }
12363
12364 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12365 scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12366 scfdie();
12367
12368 scf_service_destroy(svc);
12369 }
12370
12371 /*
12372 * Match FMRI to entity.
12373 */
12374 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12375 delete_callback, (void *)force, NULL, semerr)) != 0) {
12376 semerr(gettext("Failed to walk instances: %s\n"),
12377 scf_strerror(ret));
12378 }
12379 }
12380
12381
12382
12383 /*
12384 * :properties commands. These all end with "pg" or "prop" and generally
12385 * operate on the currently selected entity.
12386 */
12387
12388 /*
12389 * Property listing. List the property groups, properties, their types and
12390 * their values for the currently selected entity.
12391 */
12392 static void
list_pg_info(const scf_propertygroup_t * pg,const char * name,size_t namewidth)12393 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12394 {
12395 char *buf;
12396 uint32_t flags;
12397
12398 buf = safe_malloc(max_scf_pg_type_len + 1);
12399
12400 if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12401 scfdie();
12402
12403 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12404 scfdie();
12405
12406 safe_printf("%-*s %s", namewidth, name, buf);
12407
12408 if (flags & SCF_PG_FLAG_NONPERSISTENT)
12409 safe_printf("\tNONPERSISTENT");
12410
12411 safe_printf("\n");
12412
12413 free(buf);
12414 }
12415
12416 static boolean_t
prop_has_multiple_values(const scf_property_t * prop,scf_value_t * val)12417 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12418 {
12419 if (scf_property_get_value(prop, val) == 0) {
12420 return (B_FALSE);
12421 } else {
12422 switch (scf_error()) {
12423 case SCF_ERROR_NOT_FOUND:
12424 return (B_FALSE);
12425 case SCF_ERROR_PERMISSION_DENIED:
12426 case SCF_ERROR_CONSTRAINT_VIOLATED:
12427 return (B_TRUE);
12428 default:
12429 scfdie();
12430 /*NOTREACHED*/
12431 }
12432 }
12433 }
12434
12435 static void
list_prop_info(const scf_property_t * prop,const char * name,size_t len)12436 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12437 {
12438 scf_iter_t *iter;
12439 scf_value_t *val;
12440 const char *type;
12441 int multiple_strings = 0;
12442 int ret;
12443
12444 if ((iter = scf_iter_create(g_hndl)) == NULL ||
12445 (val = scf_value_create(g_hndl)) == NULL)
12446 scfdie();
12447
12448 type = prop_to_typestr(prop);
12449 assert(type != NULL);
12450
12451 safe_printf("%-*s %-7s ", len, name, type);
12452
12453 if (prop_has_multiple_values(prop, val) &&
12454 (scf_value_type(val) == SCF_TYPE_ASTRING ||
12455 scf_value_type(val) == SCF_TYPE_USTRING))
12456 multiple_strings = 1;
12457
12458 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12459 scfdie();
12460
12461 while ((ret = scf_iter_next_value(iter, val)) == 1) {
12462 char *buf;
12463 ssize_t vlen, szret;
12464
12465 vlen = scf_value_get_as_string(val, NULL, 0);
12466 if (vlen < 0)
12467 scfdie();
12468
12469 buf = safe_malloc(vlen + 1);
12470
12471 szret = scf_value_get_as_string(val, buf, vlen + 1);
12472 if (szret < 0)
12473 scfdie();
12474 assert(szret <= vlen);
12475
12476 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12477 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12478 safe_printf(" \"");
12479 (void) quote_and_print(buf, stdout, 0);
12480 (void) putchar('"');
12481 if (ferror(stdout)) {
12482 (void) putchar('\n');
12483 uu_die(gettext("Error writing to stdout.\n"));
12484 }
12485 } else {
12486 safe_printf(" %s", buf);
12487 }
12488
12489 free(buf);
12490 }
12491 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12492 scfdie();
12493
12494 if (putchar('\n') != '\n')
12495 uu_die(gettext("Could not output newline"));
12496 }
12497
12498 /*
12499 * Outputs template property group info for the describe subcommand.
12500 * If 'templates' == 2, verbose output is printed in the format expected
12501 * for describe -v, which includes all templates fields. If pg is
12502 * not NULL, we're describing the template data, not an existing property
12503 * group, and formatting should be appropriate for describe -t.
12504 */
12505 static void
list_pg_tmpl(scf_pg_tmpl_t * pgt,scf_propertygroup_t * pg,int templates)12506 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12507 {
12508 char *buf;
12509 uint8_t required;
12510 scf_property_t *stability_prop;
12511 scf_value_t *stability_val;
12512
12513 if (templates == 0)
12514 return;
12515
12516 if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12517 (stability_val = scf_value_create(g_hndl)) == NULL)
12518 scfdie();
12519
12520 if (templates == 2 && pg != NULL) {
12521 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12522 stability_prop) == 0) {
12523 if (prop_check_type(stability_prop,
12524 SCF_TYPE_ASTRING) == 0 &&
12525 prop_get_val(stability_prop, stability_val) == 0) {
12526 char *stability;
12527
12528 stability = safe_malloc(max_scf_value_len + 1);
12529
12530 if (scf_value_get_astring(stability_val,
12531 stability, max_scf_value_len + 1) == -1 &&
12532 scf_error() != SCF_ERROR_NOT_FOUND)
12533 scfdie();
12534
12535 safe_printf("%s%s: %s\n", TMPL_INDENT,
12536 gettext("stability"), stability);
12537
12538 free(stability);
12539 }
12540 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
12541 scfdie();
12542 }
12543
12544 scf_property_destroy(stability_prop);
12545 scf_value_destroy(stability_val);
12546
12547 if (pgt == NULL)
12548 return;
12549
12550 if (pg == NULL || templates == 2) {
12551 /* print type info only if scf_tmpl_pg_name succeeds */
12552 if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12553 if (pg != NULL)
12554 safe_printf("%s", TMPL_INDENT);
12555 safe_printf("%s: ", gettext("name"));
12556 safe_printf("%s\n", buf);
12557 free(buf);
12558 }
12559
12560 /* print type info only if scf_tmpl_pg_type succeeds */
12561 if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12562 if (pg != NULL)
12563 safe_printf("%s", TMPL_INDENT);
12564 safe_printf("%s: ", gettext("type"));
12565 safe_printf("%s\n", buf);
12566 free(buf);
12567 }
12568 }
12569
12570 if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12571 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12572 required ? "true" : "false");
12573
12574 if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12575 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12576 buf);
12577 free(buf);
12578 }
12579
12580 if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12581 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12582 buf);
12583 free(buf);
12584 }
12585
12586 if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12587 if (templates == 2)
12588 safe_printf("%s%s: %s\n", TMPL_INDENT,
12589 gettext("description"), buf);
12590 else
12591 safe_printf("%s%s\n", TMPL_INDENT, buf);
12592 free(buf);
12593 }
12594
12595 }
12596
12597 /*
12598 * With as_value set to true, indent as appropriate for the value level.
12599 * If false, indent to appropriate level for inclusion in constraint
12600 * or choice printout.
12601 */
12602 static void
print_template_value_details(scf_prop_tmpl_t * prt,const char * val_buf,int as_value)12603 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12604 int as_value)
12605 {
12606 char *buf;
12607
12608 if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12609 if (as_value == 0)
12610 safe_printf("%s", TMPL_CHOICE_INDENT);
12611 else
12612 safe_printf("%s", TMPL_INDENT);
12613 safe_printf("%s: %s\n", gettext("value common name"), buf);
12614 free(buf);
12615 }
12616
12617 if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12618 if (as_value == 0)
12619 safe_printf("%s", TMPL_CHOICE_INDENT);
12620 else
12621 safe_printf("%s", TMPL_INDENT);
12622 safe_printf("%s: %s\n", gettext("value description"), buf);
12623 free(buf);
12624 }
12625 }
12626
12627 static void
print_template_value(scf_prop_tmpl_t * prt,const char * val_buf)12628 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12629 {
12630 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12631 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12632 safe_printf("%s\n", val_buf);
12633
12634 print_template_value_details(prt, val_buf, 1);
12635 }
12636
12637 static void
print_template_constraints(scf_prop_tmpl_t * prt,int verbose)12638 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12639 {
12640 int i, printed = 0;
12641 scf_values_t values;
12642 scf_count_ranges_t c_ranges;
12643 scf_int_ranges_t i_ranges;
12644
12645 printed = 0;
12646 i = 0;
12647 if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12648 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12649 gettext("value constraints"));
12650 printed++;
12651 for (i = 0; i < values.value_count; ++i) {
12652 safe_printf("%s%s: %s\n", TMPL_INDENT,
12653 gettext("value name"), values.values_as_strings[i]);
12654 if (verbose == 1)
12655 print_template_value_details(prt,
12656 values.values_as_strings[i], 0);
12657 }
12658
12659 scf_values_destroy(&values);
12660 }
12661
12662 if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12663 if (printed++ == 0)
12664 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12665 gettext("value constraints"));
12666 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12667 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12668 gettext("range"), c_ranges.scr_min[i],
12669 c_ranges.scr_max[i]);
12670 }
12671 scf_count_ranges_destroy(&c_ranges);
12672 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12673 scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
12674 if (printed++ == 0)
12675 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12676 gettext("value constraints"));
12677 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12678 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12679 gettext("range"), i_ranges.sir_min[i],
12680 i_ranges.sir_max[i]);
12681 }
12682 scf_int_ranges_destroy(&i_ranges);
12683 }
12684 }
12685
12686 static void
print_template_choices(scf_prop_tmpl_t * prt,int verbose)12687 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
12688 {
12689 int i = 0, printed = 0;
12690 scf_values_t values;
12691 scf_count_ranges_t c_ranges;
12692 scf_int_ranges_t i_ranges;
12693
12694 printed = 0;
12695 if (scf_tmpl_value_name_choices(prt, &values) == 0) {
12696 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12697 gettext("value constraints"));
12698 printed++;
12699 for (i = 0; i < values.value_count; i++) {
12700 safe_printf("%s%s: %s\n", TMPL_INDENT,
12701 gettext("value name"), values.values_as_strings[i]);
12702 if (verbose == 1)
12703 print_template_value_details(prt,
12704 values.values_as_strings[i], 0);
12705 }
12706
12707 scf_values_destroy(&values);
12708 }
12709
12710 if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
12711 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12712 if (printed++ == 0)
12713 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12714 gettext("value choices"));
12715 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12716 gettext("range"), c_ranges.scr_min[i],
12717 c_ranges.scr_max[i]);
12718 }
12719 scf_count_ranges_destroy(&c_ranges);
12720 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12721 scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
12722 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12723 if (printed++ == 0)
12724 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12725 gettext("value choices"));
12726 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12727 gettext("range"), i_ranges.sir_min[i],
12728 i_ranges.sir_max[i]);
12729 }
12730 scf_int_ranges_destroy(&i_ranges);
12731 }
12732 }
12733
12734 static void
list_values_by_template(scf_prop_tmpl_t * prt)12735 list_values_by_template(scf_prop_tmpl_t *prt)
12736 {
12737 print_template_constraints(prt, 1);
12738 print_template_choices(prt, 1);
12739 }
12740
12741 static void
list_values_tmpl(scf_prop_tmpl_t * prt,scf_property_t * prop)12742 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
12743 {
12744 char *val_buf;
12745 scf_iter_t *iter;
12746 scf_value_t *val;
12747 int ret;
12748
12749 if ((iter = scf_iter_create(g_hndl)) == NULL ||
12750 (val = scf_value_create(g_hndl)) == NULL)
12751 scfdie();
12752
12753 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12754 scfdie();
12755
12756 val_buf = safe_malloc(max_scf_value_len + 1);
12757
12758 while ((ret = scf_iter_next_value(iter, val)) == 1) {
12759 if (scf_value_get_as_string(val, val_buf,
12760 max_scf_value_len + 1) < 0)
12761 scfdie();
12762
12763 print_template_value(prt, val_buf);
12764 }
12765 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12766 scfdie();
12767 free(val_buf);
12768
12769 print_template_constraints(prt, 0);
12770 print_template_choices(prt, 0);
12771
12772 }
12773
12774 /*
12775 * Outputs property info for the describe subcommand
12776 * Verbose output if templates == 2, -v option of svccfg describe
12777 * Displays template data if prop is not NULL, -t option of svccfg describe
12778 */
12779 static void
list_prop_tmpl(scf_prop_tmpl_t * prt,scf_property_t * prop,int templates)12780 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
12781 {
12782 char *buf;
12783 uint8_t u_buf;
12784 int i;
12785 uint64_t min, max;
12786 scf_values_t values;
12787
12788 if (prt == NULL || templates == 0)
12789 return;
12790
12791 if (prop == NULL) {
12792 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
12793 if (scf_tmpl_prop_name(prt, &buf) > 0) {
12794 safe_printf("%s\n", buf);
12795 free(buf);
12796 } else
12797 safe_printf("(%s)\n", gettext("any"));
12798 }
12799
12800 if (prop == NULL || templates == 2) {
12801 if (prop != NULL)
12802 safe_printf("%s", TMPL_INDENT);
12803 else
12804 safe_printf("%s", TMPL_VALUE_INDENT);
12805 safe_printf("%s: ", gettext("type"));
12806 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
12807 safe_printf("%s\n", buf);
12808 free(buf);
12809 } else
12810 safe_printf("(%s)\n", gettext("any"));
12811 }
12812
12813 if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
12814 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12815 u_buf ? "true" : "false");
12816
12817 if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
12818 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12819 buf);
12820 free(buf);
12821 }
12822
12823 if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
12824 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
12825 buf);
12826 free(buf);
12827 }
12828
12829 if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
12830 safe_printf("%s%s\n", TMPL_INDENT, buf);
12831 free(buf);
12832 }
12833
12834 if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
12835 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
12836 scf_tmpl_visibility_to_string(u_buf));
12837
12838 if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
12839 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
12840 gettext("minimum number of values"), min);
12841 if (max == ULLONG_MAX) {
12842 safe_printf("%s%s: %s\n", TMPL_INDENT,
12843 gettext("maximum number of values"),
12844 gettext("unlimited"));
12845 } else {
12846 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
12847 gettext("maximum number of values"), max);
12848 }
12849 }
12850
12851 if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
12852 for (i = 0; i < values.value_count; i++) {
12853 if (i == 0) {
12854 safe_printf("%s%s:", TMPL_INDENT,
12855 gettext("internal separators"));
12856 }
12857 safe_printf(" \"%s\"", values.values_as_strings[i]);
12858 }
12859 safe_printf("\n");
12860 }
12861
12862 if (templates != 2)
12863 return;
12864
12865 if (prop != NULL)
12866 list_values_tmpl(prt, prop);
12867 else
12868 list_values_by_template(prt);
12869 }
12870
12871 static char *
read_astring(scf_propertygroup_t * pg,const char * prop_name)12872 read_astring(scf_propertygroup_t *pg, const char *prop_name)
12873 {
12874 char *rv;
12875
12876 rv = _scf_read_single_astring_from_pg(pg, prop_name);
12877 if (rv == NULL) {
12878 switch (scf_error()) {
12879 case SCF_ERROR_NOT_FOUND:
12880 break;
12881 default:
12882 scfdie();
12883 }
12884 }
12885 return (rv);
12886 }
12887
12888 static void
display_documentation(scf_iter_t * iter,scf_propertygroup_t * pg)12889 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
12890 {
12891 size_t doc_len;
12892 size_t man_len;
12893 char *pg_name;
12894 char *text = NULL;
12895 int rv;
12896
12897 doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
12898 man_len = strlen(SCF_PG_TM_MAN_PREFIX);
12899 pg_name = safe_malloc(max_scf_name_len + 1);
12900 while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
12901 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
12902 scfdie();
12903 }
12904 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
12905 /* Display doc_link and and uri */
12906 safe_printf("%s%s:\n", TMPL_INDENT,
12907 gettext("doc_link"));
12908 text = read_astring(pg, SCF_PROPERTY_TM_NAME);
12909 if (text != NULL) {
12910 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12911 TMPL_INDENT, gettext("name"), text);
12912 uu_free(text);
12913 }
12914 text = read_astring(pg, SCF_PROPERTY_TM_URI);
12915 if (text != NULL) {
12916 safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
12917 gettext("uri"), text);
12918 uu_free(text);
12919 }
12920 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
12921 man_len) == 0) {
12922 /* Display manpage title, section and path */
12923 safe_printf("%s%s:\n", TMPL_INDENT,
12924 gettext("manpage"));
12925 text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
12926 if (text != NULL) {
12927 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12928 TMPL_INDENT, gettext("title"), text);
12929 uu_free(text);
12930 }
12931 text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
12932 if (text != NULL) {
12933 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12934 TMPL_INDENT, gettext("section"), text);
12935 uu_free(text);
12936 }
12937 text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
12938 if (text != NULL) {
12939 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12940 TMPL_INDENT, gettext("manpath"), text);
12941 uu_free(text);
12942 }
12943 }
12944 }
12945 if (rv == -1)
12946 scfdie();
12947
12948 done:
12949 free(pg_name);
12950 }
12951
12952 static void
list_entity_tmpl(int templates)12953 list_entity_tmpl(int templates)
12954 {
12955 char *common_name = NULL;
12956 char *description = NULL;
12957 char *locale = NULL;
12958 scf_iter_t *iter;
12959 scf_propertygroup_t *pg;
12960 scf_property_t *prop;
12961 int r;
12962 scf_value_t *val;
12963
12964 if ((pg = scf_pg_create(g_hndl)) == NULL ||
12965 (prop = scf_property_create(g_hndl)) == NULL ||
12966 (val = scf_value_create(g_hndl)) == NULL ||
12967 (iter = scf_iter_create(g_hndl)) == NULL)
12968 scfdie();
12969
12970 locale = setlocale(LC_MESSAGES, NULL);
12971
12972 if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
12973 common_name = safe_malloc(max_scf_value_len + 1);
12974
12975 /* Try both the current locale and the "C" locale. */
12976 if (scf_pg_get_property(pg, locale, prop) == 0 ||
12977 (scf_error() == SCF_ERROR_NOT_FOUND &&
12978 scf_pg_get_property(pg, "C", prop) == 0)) {
12979 if (prop_get_val(prop, val) == 0 &&
12980 scf_value_get_ustring(val, common_name,
12981 max_scf_value_len + 1) != -1) {
12982 safe_printf("%s%s: %s\n", TMPL_INDENT,
12983 gettext("common name"), common_name);
12984 }
12985 }
12986 }
12987
12988 /*
12989 * Do description, manpages, and doc links if templates == 2.
12990 */
12991 if (templates == 2) {
12992 /* Get the description. */
12993 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
12994 description = safe_malloc(max_scf_value_len + 1);
12995
12996 /* Try both the current locale and the "C" locale. */
12997 if (scf_pg_get_property(pg, locale, prop) == 0 ||
12998 (scf_error() == SCF_ERROR_NOT_FOUND &&
12999 scf_pg_get_property(pg, "C", prop) == 0)) {
13000 if (prop_get_val(prop, val) == 0 &&
13001 scf_value_get_ustring(val, description,
13002 max_scf_value_len + 1) != -1) {
13003 safe_printf("%s%s: %s\n", TMPL_INDENT,
13004 gettext("description"),
13005 description);
13006 }
13007 }
13008 }
13009
13010 /* Process doc_link & manpage elements. */
13011 if (cur_level != NULL) {
13012 r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
13013 SCF_GROUP_TEMPLATE);
13014 } else if (cur_inst != NULL) {
13015 r = scf_iter_instance_pgs_typed(iter, cur_inst,
13016 SCF_GROUP_TEMPLATE);
13017 } else {
13018 r = scf_iter_service_pgs_typed(iter, cur_svc,
13019 SCF_GROUP_TEMPLATE);
13020 }
13021 if (r == 0) {
13022 display_documentation(iter, pg);
13023 }
13024 }
13025
13026 free(common_name);
13027 free(description);
13028 scf_pg_destroy(pg);
13029 scf_property_destroy(prop);
13030 scf_value_destroy(val);
13031 scf_iter_destroy(iter);
13032 }
13033
13034 static void
listtmpl(const char * pattern,int templates)13035 listtmpl(const char *pattern, int templates)
13036 {
13037 scf_pg_tmpl_t *pgt;
13038 scf_prop_tmpl_t *prt;
13039 char *snapbuf = NULL;
13040 char *fmribuf;
13041 char *pg_name = NULL, *prop_name = NULL;
13042 ssize_t prop_name_size;
13043 char *qual_prop_name;
13044 char *search_name;
13045 int listed = 0;
13046
13047 if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13048 (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
13049 scfdie();
13050
13051 fmribuf = safe_malloc(max_scf_name_len + 1);
13052 qual_prop_name = safe_malloc(max_scf_name_len + 1);
13053
13054 if (cur_snap != NULL) {
13055 snapbuf = safe_malloc(max_scf_name_len + 1);
13056 if (scf_snapshot_get_name(cur_snap, snapbuf,
13057 max_scf_name_len + 1) < 0)
13058 scfdie();
13059 }
13060
13061 if (cur_inst != NULL) {
13062 if (scf_instance_to_fmri(cur_inst, fmribuf,
13063 max_scf_name_len + 1) < 0)
13064 scfdie();
13065 } else if (cur_svc != NULL) {
13066 if (scf_service_to_fmri(cur_svc, fmribuf,
13067 max_scf_name_len + 1) < 0)
13068 scfdie();
13069 } else
13070 abort();
13071
13072 /* If pattern is specified, we want to list only those items. */
13073 while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, NULL) == 1) {
13074 listed = 0;
13075 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
13076 fnmatch(pattern, pg_name, 0) == 0)) {
13077 list_pg_tmpl(pgt, NULL, templates);
13078 listed++;
13079 }
13080
13081 scf_tmpl_prop_reset(prt);
13082
13083 while (scf_tmpl_iter_props(pgt, prt, NULL) == 0) {
13084 search_name = NULL;
13085 prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
13086 if ((prop_name_size > 0) && (pg_name != NULL)) {
13087 if (snprintf(qual_prop_name,
13088 max_scf_name_len + 1, "%s/%s",
13089 pg_name, prop_name) >=
13090 max_scf_name_len + 1) {
13091 prop_name_size = -1;
13092 } else {
13093 search_name = qual_prop_name;
13094 }
13095 }
13096 if (listed > 0 || pattern == NULL ||
13097 (prop_name_size > 0 &&
13098 fnmatch(pattern, search_name,
13099 FNM_PATHNAME) == 0))
13100 list_prop_tmpl(prt, NULL, templates);
13101 if (prop_name != NULL) {
13102 free(prop_name);
13103 prop_name = NULL;
13104 }
13105 }
13106 if (pg_name != NULL) {
13107 free(pg_name);
13108 pg_name = NULL;
13109 }
13110 }
13111
13112 scf_tmpl_prop_destroy(prt);
13113 scf_tmpl_pg_destroy(pgt);
13114 free(snapbuf);
13115 free(fmribuf);
13116 free(qual_prop_name);
13117 }
13118
13119 static void
listprop(const char * pattern,int only_pgs,int templates)13120 listprop(const char *pattern, int only_pgs, int templates)
13121 {
13122 scf_propertygroup_t *pg;
13123 scf_property_t *prop;
13124 scf_iter_t *iter, *piter;
13125 char *pgnbuf, *prnbuf, *ppnbuf;
13126 scf_pg_tmpl_t *pgt, *pgtp;
13127 scf_prop_tmpl_t *prt;
13128
13129 void **objects;
13130 char **names;
13131 void **tmpls;
13132 int allocd, i;
13133
13134 int ret;
13135 ssize_t pgnlen, prnlen, szret;
13136 size_t max_len = 0;
13137
13138 if (cur_svc == NULL && cur_inst == NULL) {
13139 semerr(emsg_entity_not_selected);
13140 return;
13141 }
13142
13143 if ((pg = scf_pg_create(g_hndl)) == NULL ||
13144 (prop = scf_property_create(g_hndl)) == NULL ||
13145 (iter = scf_iter_create(g_hndl)) == NULL ||
13146 (piter = scf_iter_create(g_hndl)) == NULL ||
13147 (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13148 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
13149 scfdie();
13150
13151 prnbuf = safe_malloc(max_scf_name_len + 1);
13152
13153 if (cur_level != NULL)
13154 ret = scf_iter_snaplevel_pgs(iter, cur_level);
13155 else if (cur_inst != NULL)
13156 ret = scf_iter_instance_pgs(iter, cur_inst);
13157 else
13158 ret = scf_iter_service_pgs(iter, cur_svc);
13159 if (ret != 0) {
13160 return;
13161 }
13162
13163 /*
13164 * We want to only list items which match pattern, and we want the
13165 * second column to line up, so during the first pass we'll save
13166 * matching items, their names, and their templates in objects,
13167 * names, and tmpls, computing the maximum name length as we go,
13168 * and then we'll print them out.
13169 *
13170 * Note: We always keep an extra slot available so the array can be
13171 * NULL-terminated.
13172 */
13173 i = 0;
13174 allocd = 1;
13175 objects = safe_malloc(sizeof (*objects));
13176 names = safe_malloc(sizeof (*names));
13177 tmpls = safe_malloc(sizeof (*tmpls));
13178
13179 while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13180 int new_pg = 0;
13181 int print_props = 0;
13182 pgtp = NULL;
13183
13184 pgnlen = scf_pg_get_name(pg, NULL, 0);
13185 if (pgnlen < 0)
13186 scfdie();
13187
13188 pgnbuf = safe_malloc(pgnlen + 1);
13189
13190 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
13191 if (szret < 0)
13192 scfdie();
13193 assert(szret <= pgnlen);
13194
13195 if (scf_tmpl_get_by_pg(pg, pgt, NULL) == -1) {
13196 if (scf_error() != SCF_ERROR_NOT_FOUND)
13197 scfdie();
13198 pgtp = NULL;
13199 } else {
13200 pgtp = pgt;
13201 }
13202
13203 if (pattern == NULL ||
13204 fnmatch(pattern, pgnbuf, 0) == 0) {
13205 if (i+1 >= allocd) {
13206 allocd *= 2;
13207 objects = realloc(objects,
13208 sizeof (*objects) * allocd);
13209 names =
13210 realloc(names, sizeof (*names) * allocd);
13211 tmpls = realloc(tmpls,
13212 sizeof (*tmpls) * allocd);
13213 if (objects == NULL || names == NULL ||
13214 tmpls == NULL)
13215 uu_die(gettext("Out of memory"));
13216 }
13217 objects[i] = pg;
13218 names[i] = pgnbuf;
13219
13220 if (pgtp == NULL)
13221 tmpls[i] = NULL;
13222 else
13223 tmpls[i] = pgt;
13224
13225 ++i;
13226
13227 if (pgnlen > max_len)
13228 max_len = pgnlen;
13229
13230 new_pg = 1;
13231 print_props = 1;
13232 }
13233
13234 if (only_pgs) {
13235 if (new_pg) {
13236 pg = scf_pg_create(g_hndl);
13237 if (pg == NULL)
13238 scfdie();
13239 pgt = scf_tmpl_pg_create(g_hndl);
13240 if (pgt == NULL)
13241 scfdie();
13242 } else
13243 free(pgnbuf);
13244
13245 continue;
13246 }
13247
13248 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13249 scfdie();
13250
13251 while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13252 prnlen = scf_property_get_name(prop, prnbuf,
13253 max_scf_name_len + 1);
13254 if (prnlen < 0)
13255 scfdie();
13256
13257 /* Will prepend the property group name and a slash. */
13258 prnlen += pgnlen + 1;
13259
13260 ppnbuf = safe_malloc(prnlen + 1);
13261
13262 if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13263 prnbuf) < 0)
13264 uu_die("snprintf");
13265
13266 if (pattern == NULL || print_props == 1 ||
13267 fnmatch(pattern, ppnbuf, 0) == 0) {
13268 if (i+1 >= allocd) {
13269 allocd *= 2;
13270 objects = realloc(objects,
13271 sizeof (*objects) * allocd);
13272 names = realloc(names,
13273 sizeof (*names) * allocd);
13274 tmpls = realloc(tmpls,
13275 sizeof (*tmpls) * allocd);
13276 if (objects == NULL || names == NULL ||
13277 tmpls == NULL)
13278 uu_die(gettext(
13279 "Out of memory"));
13280 }
13281
13282 objects[i] = prop;
13283 names[i] = ppnbuf;
13284
13285 if (pgtp != NULL) {
13286 if (scf_tmpl_get_by_prop(pgt, prnbuf,
13287 prt, NULL) < 0) {
13288 if (scf_error() !=
13289 SCF_ERROR_NOT_FOUND)
13290 scfdie();
13291 tmpls[i] = NULL;
13292 } else {
13293 tmpls[i] = prt;
13294 }
13295 } else {
13296 tmpls[i] = NULL;
13297 }
13298
13299 ++i;
13300
13301 if (prnlen > max_len)
13302 max_len = prnlen;
13303
13304 prop = scf_property_create(g_hndl);
13305 prt = scf_tmpl_prop_create(g_hndl);
13306 } else {
13307 free(ppnbuf);
13308 }
13309 }
13310
13311 if (new_pg) {
13312 pg = scf_pg_create(g_hndl);
13313 if (pg == NULL)
13314 scfdie();
13315 pgt = scf_tmpl_pg_create(g_hndl);
13316 if (pgt == NULL)
13317 scfdie();
13318 } else
13319 free(pgnbuf);
13320 }
13321 if (ret != 0)
13322 scfdie();
13323
13324 objects[i] = NULL;
13325
13326 scf_pg_destroy(pg);
13327 scf_tmpl_pg_destroy(pgt);
13328 scf_property_destroy(prop);
13329 scf_tmpl_prop_destroy(prt);
13330
13331 for (i = 0; objects[i] != NULL; ++i) {
13332 if (strchr(names[i], '/') == NULL) {
13333 /* property group */
13334 pg = (scf_propertygroup_t *)objects[i];
13335 pgt = (scf_pg_tmpl_t *)tmpls[i];
13336 list_pg_info(pg, names[i], max_len);
13337 list_pg_tmpl(pgt, pg, templates);
13338 free(names[i]);
13339 scf_pg_destroy(pg);
13340 if (pgt != NULL)
13341 scf_tmpl_pg_destroy(pgt);
13342 } else {
13343 /* property */
13344 prop = (scf_property_t *)objects[i];
13345 prt = (scf_prop_tmpl_t *)tmpls[i];
13346 list_prop_info(prop, names[i], max_len);
13347 list_prop_tmpl(prt, prop, templates);
13348 free(names[i]);
13349 scf_property_destroy(prop);
13350 if (prt != NULL)
13351 scf_tmpl_prop_destroy(prt);
13352 }
13353 }
13354
13355 free(names);
13356 free(objects);
13357 free(tmpls);
13358 }
13359
13360 void
lscf_listpg(const char * pattern)13361 lscf_listpg(const char *pattern)
13362 {
13363 lscf_prep_hndl();
13364
13365 listprop(pattern, 1, 0);
13366 }
13367
13368 /*
13369 * Property group and property creation, setting, and deletion. setprop (and
13370 * its alias, addprop) can either create a property group of a given type, or
13371 * it can create or set a property to a given type and list of values.
13372 */
13373 void
lscf_addpg(const char * name,const char * type,const char * flags)13374 lscf_addpg(const char *name, const char *type, const char *flags)
13375 {
13376 scf_propertygroup_t *pg;
13377 int ret;
13378 uint32_t flgs = 0;
13379 const char *cp;
13380
13381
13382 lscf_prep_hndl();
13383
13384 if (cur_snap != NULL) {
13385 semerr(emsg_cant_modify_snapshots);
13386 return;
13387 }
13388
13389 if (cur_inst == NULL && cur_svc == NULL) {
13390 semerr(emsg_entity_not_selected);
13391 return;
13392 }
13393
13394 if (flags != NULL) {
13395 for (cp = flags; *cp != '\0'; ++cp) {
13396 switch (*cp) {
13397 case 'P':
13398 flgs |= SCF_PG_FLAG_NONPERSISTENT;
13399 break;
13400
13401 case 'p':
13402 flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13403 break;
13404
13405 default:
13406 semerr(gettext("Invalid property group flag "
13407 "%c."), *cp);
13408 return;
13409 }
13410 }
13411 }
13412
13413 pg = scf_pg_create(g_hndl);
13414 if (pg == NULL)
13415 scfdie();
13416
13417 if (cur_inst != NULL)
13418 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13419 else
13420 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13421
13422 if (ret != SCF_SUCCESS) {
13423 switch (scf_error()) {
13424 case SCF_ERROR_INVALID_ARGUMENT:
13425 semerr(gettext("Name, type, or flags are invalid.\n"));
13426 break;
13427
13428 case SCF_ERROR_EXISTS:
13429 semerr(gettext("Property group already exists.\n"));
13430 break;
13431
13432 case SCF_ERROR_PERMISSION_DENIED:
13433 semerr(emsg_permission_denied);
13434 break;
13435
13436 case SCF_ERROR_BACKEND_ACCESS:
13437 semerr(gettext("Backend refused access.\n"));
13438 break;
13439
13440 default:
13441 scfdie();
13442 }
13443 }
13444
13445 scf_pg_destroy(pg);
13446
13447 private_refresh();
13448 }
13449
13450 void
lscf_delpg(char * name)13451 lscf_delpg(char *name)
13452 {
13453 lscf_prep_hndl();
13454
13455 if (cur_snap != NULL) {
13456 semerr(emsg_cant_modify_snapshots);
13457 return;
13458 }
13459
13460 if (cur_inst == NULL && cur_svc == NULL) {
13461 semerr(emsg_entity_not_selected);
13462 return;
13463 }
13464
13465 if (strchr(name, '/') != NULL) {
13466 semerr(emsg_invalid_pg_name, name);
13467 return;
13468 }
13469
13470 lscf_delprop(name);
13471 }
13472
13473 /*
13474 * scf_delhash() is used to remove the property group related to the
13475 * hash entry for a specific manifest in the repository. pgname will be
13476 * constructed from the location of the manifest file. If deathrow isn't 0,
13477 * manifest file doesn't need to exist (manifest string will be used as
13478 * an absolute path).
13479 */
13480 void
lscf_delhash(char * manifest,int deathrow)13481 lscf_delhash(char *manifest, int deathrow)
13482 {
13483 char *pgname;
13484
13485 if (cur_snap != NULL ||
13486 cur_inst != NULL || cur_svc != NULL) {
13487 warn(gettext("error, an entity is selected\n"));
13488 return;
13489 }
13490
13491 /* select smf/manifest */
13492 lscf_select(HASH_SVC);
13493 /*
13494 * Translate the manifest file name to property name. In the deathrow
13495 * case, the manifest file does not need to exist.
13496 */
13497 pgname = mhash_filename_to_propname(manifest,
13498 deathrow ? B_TRUE : B_FALSE);
13499 if (pgname == NULL) {
13500 warn(gettext("cannot resolve pathname for %s\n"), manifest);
13501 return;
13502 }
13503 /* delete the hash property name */
13504 lscf_delpg(pgname);
13505 }
13506
13507 void
lscf_listprop(const char * pattern)13508 lscf_listprop(const char *pattern)
13509 {
13510 lscf_prep_hndl();
13511
13512 listprop(pattern, 0, 0);
13513 }
13514
13515 int
lscf_setprop(const char * pgname,const char * type,const char * value,const uu_list_t * values)13516 lscf_setprop(const char *pgname, const char *type, const char *value,
13517 const uu_list_t *values)
13518 {
13519 scf_type_t ty, current_ty;
13520 scf_service_t *svc;
13521 scf_propertygroup_t *pg, *parent_pg;
13522 scf_property_t *prop, *parent_prop;
13523 scf_pg_tmpl_t *pgt;
13524 scf_prop_tmpl_t *prt;
13525 int ret, result = 0;
13526 scf_transaction_t *tx;
13527 scf_transaction_entry_t *e;
13528 scf_value_t *v;
13529 uu_list_walk_t *walk;
13530 string_list_t *sp;
13531 char *propname;
13532 int req_quotes = 0;
13533
13534 lscf_prep_hndl();
13535
13536 if ((e = scf_entry_create(g_hndl)) == NULL ||
13537 (svc = scf_service_create(g_hndl)) == NULL ||
13538 (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13539 (pg = scf_pg_create(g_hndl)) == NULL ||
13540 (parent_prop = scf_property_create(g_hndl)) == NULL ||
13541 (prop = scf_property_create(g_hndl)) == NULL ||
13542 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13543 (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13544 (tx = scf_transaction_create(g_hndl)) == NULL)
13545 scfdie();
13546
13547 if (cur_snap != NULL) {
13548 semerr(emsg_cant_modify_snapshots);
13549 goto fail;
13550 }
13551
13552 if (cur_inst == NULL && cur_svc == NULL) {
13553 semerr(emsg_entity_not_selected);
13554 goto fail;
13555 }
13556
13557 propname = strchr(pgname, '/');
13558 if (propname == NULL) {
13559 semerr(gettext("Property names must contain a `/'.\n"));
13560 goto fail;
13561 }
13562
13563 *propname = '\0';
13564 ++propname;
13565
13566 if (type != NULL) {
13567 ty = string_to_type(type);
13568 if (ty == SCF_TYPE_INVALID) {
13569 semerr(gettext("Unknown type \"%s\".\n"), type);
13570 goto fail;
13571 }
13572 }
13573
13574 if (cur_inst != NULL)
13575 ret = scf_instance_get_pg(cur_inst, pgname, pg);
13576 else
13577 ret = scf_service_get_pg(cur_svc, pgname, pg);
13578 if (ret != SCF_SUCCESS) {
13579 switch (scf_error()) {
13580 case SCF_ERROR_NOT_FOUND:
13581 semerr(emsg_no_such_pg, pgname);
13582 goto fail;
13583
13584 case SCF_ERROR_INVALID_ARGUMENT:
13585 semerr(emsg_invalid_pg_name, pgname);
13586 goto fail;
13587
13588 default:
13589 scfdie();
13590 break;
13591 }
13592 }
13593
13594 do {
13595 if (scf_pg_update(pg) == -1)
13596 scfdie();
13597 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13598 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13599 scfdie();
13600
13601 semerr(emsg_permission_denied);
13602 goto fail;
13603 }
13604
13605 ret = scf_pg_get_property(pg, propname, prop);
13606 if (ret == SCF_SUCCESS) {
13607 if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS)
13608 scfdie();
13609
13610 if (type == NULL)
13611 ty = current_ty;
13612 if (scf_transaction_property_change_type(tx, e,
13613 propname, ty) == -1)
13614 scfdie();
13615
13616 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13617 /* Infer the type, if possible. */
13618 if (type == NULL) {
13619 /*
13620 * First check if we're an instance and the
13621 * property is set on the service.
13622 */
13623 if (cur_inst != NULL &&
13624 scf_instance_get_parent(cur_inst,
13625 svc) == 0 &&
13626 scf_service_get_pg(cur_svc, pgname,
13627 parent_pg) == 0 &&
13628 scf_pg_get_property(parent_pg, propname,
13629 parent_prop) == 0 &&
13630 scf_property_type(parent_prop,
13631 ¤t_ty) == 0) {
13632 ty = current_ty;
13633
13634 /* Then check for a type set in a template. */
13635 } else if (scf_tmpl_get_by_pg(pg, pgt,
13636 NULL) == 0 &&
13637 scf_tmpl_get_by_prop(pgt, propname, prt,
13638 NULL) == 0 &&
13639 scf_tmpl_prop_type(prt, ¤t_ty) == 0) {
13640 ty = current_ty;
13641
13642 /* If type can't be inferred, fail. */
13643 } else {
13644 semerr(gettext("Type required for new "
13645 "properties.\n"));
13646 goto fail;
13647 }
13648 }
13649 if (scf_transaction_property_new(tx, e, propname,
13650 ty) == -1)
13651 scfdie();
13652 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13653 semerr(emsg_invalid_prop_name, propname);
13654 goto fail;
13655 } else {
13656 scfdie();
13657 }
13658
13659 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13660 req_quotes = 1;
13661
13662 if (value != NULL) {
13663 v = string_to_value(value, ty, 0);
13664
13665 if (v == NULL)
13666 goto fail;
13667
13668 ret = scf_entry_add_value(e, v);
13669 assert(ret == SCF_SUCCESS);
13670 } else {
13671 assert(values != NULL);
13672
13673 walk = uu_list_walk_start((uu_list_t *)values,
13674 UU_DEFAULT);
13675 if (walk == NULL)
13676 uu_die(gettext("Could not walk list"));
13677
13678 for (sp = uu_list_walk_next(walk); sp != NULL;
13679 sp = uu_list_walk_next(walk)) {
13680 v = string_to_value(sp->str, ty, req_quotes);
13681
13682 if (v == NULL) {
13683 scf_entry_destroy_children(e);
13684 goto fail;
13685 }
13686
13687 ret = scf_entry_add_value(e, v);
13688 assert(ret == SCF_SUCCESS);
13689 }
13690 uu_list_walk_end(walk);
13691 }
13692 result = scf_transaction_commit(tx);
13693
13694 scf_transaction_reset(tx);
13695 scf_entry_destroy_children(e);
13696 } while (result == 0);
13697
13698 if (result < 0) {
13699 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13700 scfdie();
13701
13702 semerr(emsg_permission_denied);
13703 goto fail;
13704 }
13705
13706 ret = 0;
13707
13708 private_refresh();
13709
13710 goto cleanup;
13711
13712 fail:
13713 ret = -1;
13714
13715 cleanup:
13716 scf_transaction_destroy(tx);
13717 scf_entry_destroy(e);
13718 scf_service_destroy(svc);
13719 scf_pg_destroy(parent_pg);
13720 scf_pg_destroy(pg);
13721 scf_property_destroy(parent_prop);
13722 scf_property_destroy(prop);
13723 scf_tmpl_pg_destroy(pgt);
13724 scf_tmpl_prop_destroy(prt);
13725
13726 return (ret);
13727 }
13728
13729 void
lscf_delprop(char * pgn)13730 lscf_delprop(char *pgn)
13731 {
13732 char *slash, *pn;
13733 scf_propertygroup_t *pg;
13734 scf_transaction_t *tx;
13735 scf_transaction_entry_t *e;
13736 int ret;
13737
13738
13739 lscf_prep_hndl();
13740
13741 if (cur_snap != NULL) {
13742 semerr(emsg_cant_modify_snapshots);
13743 return;
13744 }
13745
13746 if (cur_inst == NULL && cur_svc == NULL) {
13747 semerr(emsg_entity_not_selected);
13748 return;
13749 }
13750
13751 pg = scf_pg_create(g_hndl);
13752 if (pg == NULL)
13753 scfdie();
13754
13755 slash = strchr(pgn, '/');
13756 if (slash == NULL) {
13757 pn = NULL;
13758 } else {
13759 *slash = '\0';
13760 pn = slash + 1;
13761 }
13762
13763 if (cur_inst != NULL)
13764 ret = scf_instance_get_pg(cur_inst, pgn, pg);
13765 else
13766 ret = scf_service_get_pg(cur_svc, pgn, pg);
13767 if (ret != SCF_SUCCESS) {
13768 switch (scf_error()) {
13769 case SCF_ERROR_NOT_FOUND:
13770 semerr(emsg_no_such_pg, pgn);
13771 break;
13772
13773 case SCF_ERROR_INVALID_ARGUMENT:
13774 semerr(emsg_invalid_pg_name, pgn);
13775 break;
13776
13777 default:
13778 scfdie();
13779 }
13780
13781 scf_pg_destroy(pg);
13782
13783 return;
13784 }
13785
13786 if (pn == NULL) {
13787 /* Try to delete the property group. */
13788 if (scf_pg_delete(pg) != SCF_SUCCESS) {
13789 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13790 scfdie();
13791
13792 semerr(emsg_permission_denied);
13793 } else {
13794 private_refresh();
13795 }
13796
13797 scf_pg_destroy(pg);
13798 return;
13799 }
13800
13801 e = scf_entry_create(g_hndl);
13802 tx = scf_transaction_create(g_hndl);
13803
13804 do {
13805 if (scf_pg_update(pg) == -1)
13806 scfdie();
13807 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13808 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13809 scfdie();
13810
13811 semerr(emsg_permission_denied);
13812 break;
13813 }
13814
13815 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
13816 if (scf_error() == SCF_ERROR_NOT_FOUND) {
13817 semerr(gettext("No such property %s/%s.\n"),
13818 pgn, pn);
13819 break;
13820 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13821 semerr(emsg_invalid_prop_name, pn);
13822 break;
13823 } else {
13824 scfdie();
13825 }
13826 }
13827
13828 ret = scf_transaction_commit(tx);
13829
13830 if (ret == 0)
13831 scf_transaction_reset(tx);
13832 } while (ret == 0);
13833
13834 if (ret < 0) {
13835 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13836 scfdie();
13837
13838 semerr(emsg_permission_denied);
13839 } else {
13840 private_refresh();
13841 }
13842
13843 scf_transaction_destroy(tx);
13844 scf_entry_destroy(e);
13845 scf_pg_destroy(pg);
13846 }
13847
13848 /*
13849 * Property editing.
13850 */
13851
13852 static int
write_edit_script(FILE * strm)13853 write_edit_script(FILE *strm)
13854 {
13855 char *fmribuf;
13856 ssize_t fmrilen;
13857
13858 scf_propertygroup_t *pg;
13859 scf_property_t *prop;
13860 scf_value_t *val;
13861 scf_type_t ty;
13862 int ret, result = 0;
13863 scf_iter_t *iter, *piter, *viter;
13864 char *buf, *tybuf, *pname;
13865 const char *emsg_write_error;
13866
13867
13868 emsg_write_error = gettext("Error writing temoprary file: %s.\n");
13869
13870
13871 /* select fmri */
13872 if (cur_inst != NULL) {
13873 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
13874 if (fmrilen < 0)
13875 scfdie();
13876 fmribuf = safe_malloc(fmrilen + 1);
13877 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
13878 scfdie();
13879 } else {
13880 assert(cur_svc != NULL);
13881 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
13882 if (fmrilen < 0)
13883 scfdie();
13884 fmribuf = safe_malloc(fmrilen + 1);
13885 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
13886 scfdie();
13887 }
13888
13889 if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
13890 warn(emsg_write_error, strerror(errno));
13891 free(fmribuf);
13892 return (-1);
13893 }
13894
13895 free(fmribuf);
13896
13897
13898 if ((pg = scf_pg_create(g_hndl)) == NULL ||
13899 (prop = scf_property_create(g_hndl)) == NULL ||
13900 (val = scf_value_create(g_hndl)) == NULL ||
13901 (iter = scf_iter_create(g_hndl)) == NULL ||
13902 (piter = scf_iter_create(g_hndl)) == NULL ||
13903 (viter = scf_iter_create(g_hndl)) == NULL)
13904 scfdie();
13905
13906 buf = safe_malloc(max_scf_name_len + 1);
13907 tybuf = safe_malloc(max_scf_pg_type_len + 1);
13908 pname = safe_malloc(max_scf_name_len + 1);
13909
13910 if (cur_inst != NULL)
13911 ret = scf_iter_instance_pgs(iter, cur_inst);
13912 else
13913 ret = scf_iter_service_pgs(iter, cur_svc);
13914 if (ret != SCF_SUCCESS)
13915 scfdie();
13916
13917 while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13918 int ret2;
13919
13920 /*
13921 * # delprop pg
13922 * # addpg pg type
13923 */
13924 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
13925 scfdie();
13926
13927 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
13928 scfdie();
13929
13930 if (fprintf(strm, "# Property group \"%s\"\n"
13931 "# delprop %s\n"
13932 "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
13933 warn(emsg_write_error, strerror(errno));
13934 result = -1;
13935 goto out;
13936 }
13937
13938 /* # setprop pg/prop = (values) */
13939
13940 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13941 scfdie();
13942
13943 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
13944 int first = 1;
13945 int ret3;
13946 int multiple;
13947 int is_str;
13948 scf_type_t bty;
13949
13950 if (scf_property_get_name(prop, pname,
13951 max_scf_name_len + 1) < 0)
13952 scfdie();
13953
13954 if (scf_property_type(prop, &ty) != 0)
13955 scfdie();
13956
13957 multiple = prop_has_multiple_values(prop, val);
13958
13959 if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
13960 pname, scf_type_to_string(ty), multiple ? "(" : "")
13961 < 0) {
13962 warn(emsg_write_error, strerror(errno));
13963 result = -1;
13964 goto out;
13965 }
13966
13967 (void) scf_type_base_type(ty, &bty);
13968 is_str = (bty == SCF_TYPE_ASTRING);
13969
13970 if (scf_iter_property_values(viter, prop) !=
13971 SCF_SUCCESS)
13972 scfdie();
13973
13974 while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
13975 char *buf;
13976 ssize_t buflen;
13977
13978 buflen = scf_value_get_as_string(val, NULL, 0);
13979 if (buflen < 0)
13980 scfdie();
13981
13982 buf = safe_malloc(buflen + 1);
13983
13984 if (scf_value_get_as_string(val, buf,
13985 buflen + 1) < 0)
13986 scfdie();
13987
13988 if (first)
13989 first = 0;
13990 else {
13991 if (putc(' ', strm) != ' ') {
13992 warn(emsg_write_error,
13993 strerror(errno));
13994 result = -1;
13995 goto out;
13996 }
13997 }
13998
13999 if ((is_str && multiple) ||
14000 strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
14001 (void) putc('"', strm);
14002 (void) quote_and_print(buf, strm, 1);
14003 (void) putc('"', strm);
14004
14005 if (ferror(strm)) {
14006 warn(emsg_write_error,
14007 strerror(errno));
14008 result = -1;
14009 goto out;
14010 }
14011 } else {
14012 if (fprintf(strm, "%s", buf) < 0) {
14013 warn(emsg_write_error,
14014 strerror(errno));
14015 result = -1;
14016 goto out;
14017 }
14018 }
14019
14020 free(buf);
14021 }
14022 if (ret3 < 0 &&
14023 scf_error() != SCF_ERROR_PERMISSION_DENIED)
14024 scfdie();
14025
14026 /* Write closing paren if mult-value property */
14027 if ((multiple && putc(')', strm) == EOF) ||
14028
14029 /* Write final newline */
14030 fputc('\n', strm) == EOF) {
14031 warn(emsg_write_error, strerror(errno));
14032 result = -1;
14033 goto out;
14034 }
14035 }
14036 if (ret2 < 0)
14037 scfdie();
14038
14039 if (fputc('\n', strm) == EOF) {
14040 warn(emsg_write_error, strerror(errno));
14041 result = -1;
14042 goto out;
14043 }
14044 }
14045 if (ret < 0)
14046 scfdie();
14047
14048 out:
14049 free(pname);
14050 free(tybuf);
14051 free(buf);
14052 scf_iter_destroy(viter);
14053 scf_iter_destroy(piter);
14054 scf_iter_destroy(iter);
14055 scf_value_destroy(val);
14056 scf_property_destroy(prop);
14057 scf_pg_destroy(pg);
14058
14059 if (result == 0) {
14060 if (fflush(strm) != 0) {
14061 warn(emsg_write_error, strerror(errno));
14062 return (-1);
14063 }
14064 }
14065
14066 return (result);
14067 }
14068
14069 int
lscf_editprop()14070 lscf_editprop()
14071 {
14072 char *buf, *editor;
14073 size_t bufsz;
14074 int tmpfd;
14075 char tempname[] = TEMP_FILE_PATTERN;
14076
14077 lscf_prep_hndl();
14078
14079 if (cur_snap != NULL) {
14080 semerr(emsg_cant_modify_snapshots);
14081 return (-1);
14082 }
14083
14084 if (cur_svc == NULL && cur_inst == NULL) {
14085 semerr(emsg_entity_not_selected);
14086 return (-1);
14087 }
14088
14089 tmpfd = mkstemp(tempname);
14090 if (tmpfd == -1) {
14091 semerr(gettext("Could not create temporary file.\n"));
14092 return (-1);
14093 }
14094
14095 (void) strcpy(tempfilename, tempname);
14096
14097 tempfile = fdopen(tmpfd, "r+");
14098 if (tempfile == NULL) {
14099 warn(gettext("Could not create temporary file.\n"));
14100 if (close(tmpfd) == -1)
14101 warn(gettext("Could not close temporary file: %s.\n"),
14102 strerror(errno));
14103
14104 remove_tempfile();
14105
14106 return (-1);
14107 }
14108
14109 if (write_edit_script(tempfile) == -1) {
14110 remove_tempfile();
14111 return (-1);
14112 }
14113
14114 editor = getenv("EDITOR");
14115 if (editor == NULL)
14116 editor = "vi";
14117
14118 bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
14119 buf = safe_malloc(bufsz);
14120
14121 if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
14122 uu_die(gettext("Error creating editor command"));
14123
14124 if (system(buf) == -1) {
14125 semerr(gettext("Could not launch editor %s: %s\n"), editor,
14126 strerror(errno));
14127 free(buf);
14128 remove_tempfile();
14129 return (-1);
14130 }
14131
14132 free(buf);
14133
14134 (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
14135
14136 remove_tempfile();
14137
14138 return (0);
14139 }
14140
14141 static void
add_string(uu_list_t * strlist,const char * str)14142 add_string(uu_list_t *strlist, const char *str)
14143 {
14144 string_list_t *elem;
14145 elem = safe_malloc(sizeof (*elem));
14146 uu_list_node_init(elem, &elem->node, string_pool);
14147 elem->str = safe_strdup(str);
14148 if (uu_list_append(strlist, elem) != 0)
14149 uu_die(gettext("libuutil error: %s\n"),
14150 uu_strerror(uu_error()));
14151 }
14152
14153 static int
remove_string(uu_list_t * strlist,const char * str)14154 remove_string(uu_list_t *strlist, const char *str)
14155 {
14156 uu_list_walk_t *elems;
14157 string_list_t *sp;
14158
14159 /*
14160 * Find the element that needs to be removed.
14161 */
14162 elems = uu_list_walk_start(strlist, UU_DEFAULT);
14163 while ((sp = uu_list_walk_next(elems)) != NULL) {
14164 if (strcmp(sp->str, str) == 0)
14165 break;
14166 }
14167 uu_list_walk_end(elems);
14168
14169 /*
14170 * Returning 1 here as the value was not found, this
14171 * might not be an error. Leave it to the caller to
14172 * decide.
14173 */
14174 if (sp == NULL) {
14175 return (1);
14176 }
14177
14178 uu_list_remove(strlist, sp);
14179
14180 free(sp->str);
14181 free(sp);
14182
14183 return (0);
14184 }
14185
14186 /*
14187 * Get all property values that don't match the given glob pattern,
14188 * if a pattern is specified.
14189 */
14190 static void
get_prop_values(scf_property_t * prop,uu_list_t * values,const char * pattern)14191 get_prop_values(scf_property_t *prop, uu_list_t *values,
14192 const char *pattern)
14193 {
14194 scf_iter_t *iter;
14195 scf_value_t *val;
14196 int ret;
14197
14198 if ((iter = scf_iter_create(g_hndl)) == NULL ||
14199 (val = scf_value_create(g_hndl)) == NULL)
14200 scfdie();
14201
14202 if (scf_iter_property_values(iter, prop) != 0)
14203 scfdie();
14204
14205 while ((ret = scf_iter_next_value(iter, val)) == 1) {
14206 char *buf;
14207 ssize_t vlen, szret;
14208
14209 vlen = scf_value_get_as_string(val, NULL, 0);
14210 if (vlen < 0)
14211 scfdie();
14212
14213 buf = safe_malloc(vlen + 1);
14214
14215 szret = scf_value_get_as_string(val, buf, vlen + 1);
14216 if (szret < 0)
14217 scfdie();
14218 assert(szret <= vlen);
14219
14220 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14221 add_string(values, buf);
14222
14223 free(buf);
14224 }
14225
14226 if (ret == -1)
14227 scfdie();
14228
14229 scf_value_destroy(val);
14230 scf_iter_destroy(iter);
14231 }
14232
14233 static int
lscf_setpropvalue(const char * pgname,const char * type,const char * arg,int isadd,int isnotfoundok)14234 lscf_setpropvalue(const char *pgname, const char *type,
14235 const char *arg, int isadd, int isnotfoundok)
14236 {
14237 scf_type_t ty;
14238 scf_propertygroup_t *pg;
14239 scf_property_t *prop;
14240 int ret, result = 0;
14241 scf_transaction_t *tx;
14242 scf_transaction_entry_t *e;
14243 scf_value_t *v;
14244 string_list_t *sp;
14245 char *propname;
14246 uu_list_t *values;
14247 uu_list_walk_t *walk;
14248 void *cookie = NULL;
14249 char *pattern = NULL;
14250
14251 lscf_prep_hndl();
14252
14253 if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14254 uu_die(gettext("Could not create property list: %s\n"),
14255 uu_strerror(uu_error()));
14256
14257 if (!isadd)
14258 pattern = safe_strdup(arg);
14259
14260 if ((e = scf_entry_create(g_hndl)) == NULL ||
14261 (pg = scf_pg_create(g_hndl)) == NULL ||
14262 (prop = scf_property_create(g_hndl)) == NULL ||
14263 (tx = scf_transaction_create(g_hndl)) == NULL)
14264 scfdie();
14265
14266 if (cur_snap != NULL) {
14267 semerr(emsg_cant_modify_snapshots);
14268 goto fail;
14269 }
14270
14271 if (cur_inst == NULL && cur_svc == NULL) {
14272 semerr(emsg_entity_not_selected);
14273 goto fail;
14274 }
14275
14276 propname = strchr(pgname, '/');
14277 if (propname == NULL) {
14278 semerr(gettext("Property names must contain a `/'.\n"));
14279 goto fail;
14280 }
14281
14282 *propname = '\0';
14283 ++propname;
14284
14285 if (type != NULL) {
14286 ty = string_to_type(type);
14287 if (ty == SCF_TYPE_INVALID) {
14288 semerr(gettext("Unknown type \"%s\".\n"), type);
14289 goto fail;
14290 }
14291 }
14292
14293 if (cur_inst != NULL)
14294 ret = scf_instance_get_pg(cur_inst, pgname, pg);
14295 else
14296 ret = scf_service_get_pg(cur_svc, pgname, pg);
14297 if (ret != 0) {
14298 switch (scf_error()) {
14299 case SCF_ERROR_NOT_FOUND:
14300 if (isnotfoundok) {
14301 result = 0;
14302 } else {
14303 semerr(emsg_no_such_pg, pgname);
14304 result = -1;
14305 }
14306 goto out;
14307
14308 case SCF_ERROR_INVALID_ARGUMENT:
14309 semerr(emsg_invalid_pg_name, pgname);
14310 goto fail;
14311
14312 default:
14313 scfdie();
14314 }
14315 }
14316
14317 do {
14318 if (scf_pg_update(pg) == -1)
14319 scfdie();
14320 if (scf_transaction_start(tx, pg) != 0) {
14321 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14322 scfdie();
14323
14324 semerr(emsg_permission_denied);
14325 goto fail;
14326 }
14327
14328 ret = scf_pg_get_property(pg, propname, prop);
14329 if (ret == 0) {
14330 scf_type_t ptype;
14331 char *pat = pattern;
14332
14333 if (scf_property_type(prop, &ptype) != 0)
14334 scfdie();
14335
14336 if (isadd) {
14337 if (type != NULL && ptype != ty) {
14338 semerr(gettext("Property \"%s\" is not "
14339 "of type \"%s\".\n"), propname,
14340 type);
14341 goto fail;
14342 }
14343
14344 pat = NULL;
14345 } else {
14346 size_t len = strlen(pat);
14347 if (len > 0 && pat[len - 1] == '\"')
14348 pat[len - 1] = '\0';
14349 if (len > 0 && pat[0] == '\"')
14350 pat++;
14351 }
14352
14353 ty = ptype;
14354
14355 get_prop_values(prop, values, pat);
14356
14357 if (isadd)
14358 add_string(values, arg);
14359
14360 if (scf_transaction_property_change(tx, e,
14361 propname, ty) == -1)
14362 scfdie();
14363 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14364 if (isadd) {
14365 if (type == NULL) {
14366 semerr(gettext("Type required "
14367 "for new properties.\n"));
14368 goto fail;
14369 }
14370
14371 add_string(values, arg);
14372
14373 if (scf_transaction_property_new(tx, e,
14374 propname, ty) == -1)
14375 scfdie();
14376 } else if (isnotfoundok) {
14377 result = 0;
14378 goto out;
14379 } else {
14380 semerr(gettext("No such property %s/%s.\n"),
14381 pgname, propname);
14382 result = -1;
14383 goto out;
14384 }
14385 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14386 semerr(emsg_invalid_prop_name, propname);
14387 goto fail;
14388 } else {
14389 scfdie();
14390 }
14391
14392 walk = uu_list_walk_start(values, UU_DEFAULT);
14393 if (walk == NULL)
14394 uu_die(gettext("Could not walk property list.\n"));
14395
14396 for (sp = uu_list_walk_next(walk); sp != NULL;
14397 sp = uu_list_walk_next(walk)) {
14398 v = string_to_value(sp->str, ty, 0);
14399
14400 if (v == NULL) {
14401 scf_entry_destroy_children(e);
14402 goto fail;
14403 }
14404 ret = scf_entry_add_value(e, v);
14405 assert(ret == 0);
14406 }
14407 uu_list_walk_end(walk);
14408
14409 result = scf_transaction_commit(tx);
14410
14411 scf_transaction_reset(tx);
14412 scf_entry_destroy_children(e);
14413 } while (result == 0);
14414
14415 if (result < 0) {
14416 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14417 scfdie();
14418
14419 semerr(emsg_permission_denied);
14420 goto fail;
14421 }
14422
14423 result = 0;
14424
14425 private_refresh();
14426
14427 out:
14428 scf_transaction_destroy(tx);
14429 scf_entry_destroy(e);
14430 scf_pg_destroy(pg);
14431 scf_property_destroy(prop);
14432 free(pattern);
14433
14434 while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14435 free(sp->str);
14436 free(sp);
14437 }
14438
14439 uu_list_destroy(values);
14440
14441 return (result);
14442
14443 fail:
14444 result = -1;
14445 goto out;
14446 }
14447
14448 int
lscf_addpropvalue(const char * pgname,const char * type,const char * value)14449 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14450 {
14451 return (lscf_setpropvalue(pgname, type, value, 1, 0));
14452 }
14453
14454 int
lscf_delpropvalue(const char * pgname,const char * pattern,int isnotfoundok)14455 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14456 {
14457 return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14458 }
14459
14460 /*
14461 * Look for a standard start method, first in the instance (if any),
14462 * then the service.
14463 */
14464 static const char *
start_method_name(int * in_instance)14465 start_method_name(int *in_instance)
14466 {
14467 scf_propertygroup_t *pg;
14468 char **p;
14469 int ret;
14470 scf_instance_t *inst = cur_inst;
14471
14472 if ((pg = scf_pg_create(g_hndl)) == NULL)
14473 scfdie();
14474
14475 again:
14476 for (p = start_method_names; *p != NULL; p++) {
14477 if (inst != NULL)
14478 ret = scf_instance_get_pg(inst, *p, pg);
14479 else
14480 ret = scf_service_get_pg(cur_svc, *p, pg);
14481
14482 if (ret == 0) {
14483 size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14484 char *buf = safe_malloc(bufsz);
14485
14486 if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14487 free(buf);
14488 continue;
14489 }
14490 if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14491 free(buf);
14492 continue;
14493 }
14494
14495 free(buf);
14496 *in_instance = (inst != NULL);
14497 scf_pg_destroy(pg);
14498 return (*p);
14499 }
14500
14501 if (scf_error() == SCF_ERROR_NOT_FOUND)
14502 continue;
14503
14504 scfdie();
14505 }
14506
14507 if (inst != NULL) {
14508 inst = NULL;
14509 goto again;
14510 }
14511
14512 scf_pg_destroy(pg);
14513 return (NULL);
14514 }
14515
14516 static int
addpg(const char * name,const char * type)14517 addpg(const char *name, const char *type)
14518 {
14519 scf_propertygroup_t *pg;
14520 int ret;
14521
14522 pg = scf_pg_create(g_hndl);
14523 if (pg == NULL)
14524 scfdie();
14525
14526 if (cur_inst != NULL)
14527 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14528 else
14529 ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14530
14531 if (ret != 0) {
14532 switch (scf_error()) {
14533 case SCF_ERROR_EXISTS:
14534 ret = 0;
14535 break;
14536
14537 case SCF_ERROR_PERMISSION_DENIED:
14538 semerr(emsg_permission_denied);
14539 break;
14540
14541 default:
14542 scfdie();
14543 }
14544 }
14545
14546 scf_pg_destroy(pg);
14547 return (ret);
14548 }
14549
14550 int
lscf_setenv(uu_list_t * args,int isunset)14551 lscf_setenv(uu_list_t *args, int isunset)
14552 {
14553 int ret = 0;
14554 size_t i;
14555 int argc;
14556 char **argv = NULL;
14557 string_list_t *slp;
14558 char *pattern;
14559 char *prop;
14560 int do_service = 0;
14561 int do_instance = 0;
14562 const char *method = NULL;
14563 const char *name = NULL;
14564 const char *value = NULL;
14565 scf_instance_t *saved_cur_inst = cur_inst;
14566
14567 lscf_prep_hndl();
14568
14569 argc = uu_list_numnodes(args);
14570 if (argc < 1)
14571 goto usage;
14572
14573 argv = calloc(argc + 1, sizeof (char *));
14574 if (argv == NULL)
14575 uu_die(gettext("Out of memory.\n"));
14576
14577 for (slp = uu_list_first(args), i = 0;
14578 slp != NULL;
14579 slp = uu_list_next(args, slp), ++i)
14580 argv[i] = slp->str;
14581
14582 argv[i] = NULL;
14583
14584 opterr = 0;
14585 optind = 0;
14586 for (;;) {
14587 ret = getopt(argc, argv, "sim:");
14588 if (ret == -1)
14589 break;
14590
14591 switch (ret) {
14592 case 's':
14593 do_service = 1;
14594 cur_inst = NULL;
14595 break;
14596
14597 case 'i':
14598 do_instance = 1;
14599 break;
14600
14601 case 'm':
14602 method = optarg;
14603 break;
14604
14605 case '?':
14606 goto usage;
14607
14608 default:
14609 bad_error("getopt", ret);
14610 }
14611 }
14612
14613 argc -= optind;
14614 if ((do_service && do_instance) ||
14615 (isunset && argc != 1) ||
14616 (!isunset && argc != 2))
14617 goto usage;
14618
14619 name = argv[optind];
14620 if (!isunset)
14621 value = argv[optind + 1];
14622
14623 if (cur_snap != NULL) {
14624 semerr(emsg_cant_modify_snapshots);
14625 ret = -1;
14626 goto out;
14627 }
14628
14629 if (cur_inst == NULL && cur_svc == NULL) {
14630 semerr(emsg_entity_not_selected);
14631 ret = -1;
14632 goto out;
14633 }
14634
14635 if (do_instance && cur_inst == NULL) {
14636 semerr(gettext("No instance is selected.\n"));
14637 ret = -1;
14638 goto out;
14639 }
14640
14641 if (do_service && cur_svc == NULL) {
14642 semerr(gettext("No service is selected.\n"));
14643 ret = -1;
14644 goto out;
14645 }
14646
14647 if (method == NULL) {
14648 if (do_instance || do_service) {
14649 method = "method_context";
14650 if (!isunset) {
14651 ret = addpg("method_context",
14652 SCF_GROUP_FRAMEWORK);
14653 if (ret != 0)
14654 goto out;
14655 }
14656 } else {
14657 int in_instance;
14658 method = start_method_name(&in_instance);
14659 if (method == NULL) {
14660 semerr(gettext(
14661 "Couldn't find start method; please "
14662 "specify a method with '-m'.\n"));
14663 ret = -1;
14664 goto out;
14665 }
14666 if (!in_instance)
14667 cur_inst = NULL;
14668 }
14669 } else {
14670 scf_propertygroup_t *pg;
14671 size_t bufsz;
14672 char *buf;
14673 int ret;
14674
14675 if ((pg = scf_pg_create(g_hndl)) == NULL)
14676 scfdie();
14677
14678 if (cur_inst != NULL)
14679 ret = scf_instance_get_pg(cur_inst, method, pg);
14680 else
14681 ret = scf_service_get_pg(cur_svc, method, pg);
14682
14683 if (ret != 0) {
14684 scf_pg_destroy(pg);
14685 switch (scf_error()) {
14686 case SCF_ERROR_NOT_FOUND:
14687 semerr(gettext("Couldn't find the method "
14688 "\"%s\".\n"), method);
14689 goto out;
14690
14691 case SCF_ERROR_INVALID_ARGUMENT:
14692 semerr(gettext("Invalid method name \"%s\".\n"),
14693 method);
14694 goto out;
14695
14696 default:
14697 scfdie();
14698 }
14699 }
14700
14701 bufsz = strlen(SCF_GROUP_METHOD) + 1;
14702 buf = safe_malloc(bufsz);
14703
14704 if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
14705 strcmp(buf, SCF_GROUP_METHOD) != 0) {
14706 semerr(gettext("Property group \"%s\" is not of type "
14707 "\"method\".\n"), method);
14708 ret = -1;
14709 free(buf);
14710 scf_pg_destroy(pg);
14711 goto out;
14712 }
14713
14714 free(buf);
14715 scf_pg_destroy(pg);
14716 }
14717
14718 prop = uu_msprintf("%s/environment", method);
14719 pattern = uu_msprintf("%s=*", name);
14720
14721 if (prop == NULL || pattern == NULL)
14722 uu_die(gettext("Out of memory.\n"));
14723
14724 ret = lscf_delpropvalue(prop, pattern, !isunset);
14725
14726 if (ret == 0 && !isunset) {
14727 uu_free(pattern);
14728 uu_free(prop);
14729 prop = uu_msprintf("%s/environment", method);
14730 pattern = uu_msprintf("%s=%s", name, value);
14731 if (prop == NULL || pattern == NULL)
14732 uu_die(gettext("Out of memory.\n"));
14733 ret = lscf_addpropvalue(prop, "astring:", pattern);
14734 }
14735 uu_free(pattern);
14736 uu_free(prop);
14737
14738 out:
14739 cur_inst = saved_cur_inst;
14740
14741 free(argv);
14742 return (ret);
14743 usage:
14744 ret = -2;
14745 goto out;
14746 }
14747
14748 /*
14749 * Snapshot commands
14750 */
14751
14752 void
lscf_listsnap()14753 lscf_listsnap()
14754 {
14755 scf_snapshot_t *snap;
14756 scf_iter_t *iter;
14757 char *nb;
14758 int r;
14759
14760 lscf_prep_hndl();
14761
14762 if (cur_inst == NULL) {
14763 semerr(gettext("Instance not selected.\n"));
14764 return;
14765 }
14766
14767 if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
14768 (iter = scf_iter_create(g_hndl)) == NULL)
14769 scfdie();
14770
14771 if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
14772 scfdie();
14773
14774 nb = safe_malloc(max_scf_name_len + 1);
14775
14776 while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
14777 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
14778 scfdie();
14779
14780 (void) puts(nb);
14781 }
14782 if (r < 0)
14783 scfdie();
14784
14785 free(nb);
14786 scf_iter_destroy(iter);
14787 scf_snapshot_destroy(snap);
14788 }
14789
14790 void
lscf_selectsnap(const char * name)14791 lscf_selectsnap(const char *name)
14792 {
14793 scf_snapshot_t *snap;
14794 scf_snaplevel_t *level;
14795
14796 lscf_prep_hndl();
14797
14798 if (cur_inst == NULL) {
14799 semerr(gettext("Instance not selected.\n"));
14800 return;
14801 }
14802
14803 if (cur_snap != NULL) {
14804 if (name != NULL) {
14805 char *cur_snap_name;
14806 boolean_t nochange;
14807
14808 cur_snap_name = safe_malloc(max_scf_name_len + 1);
14809
14810 if (scf_snapshot_get_name(cur_snap, cur_snap_name,
14811 max_scf_name_len + 1) < 0)
14812 scfdie();
14813
14814 nochange = strcmp(name, cur_snap_name) == 0;
14815
14816 free(cur_snap_name);
14817
14818 if (nochange)
14819 return;
14820 }
14821
14822 unselect_cursnap();
14823 }
14824
14825 if (name == NULL)
14826 return;
14827
14828 if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
14829 (level = scf_snaplevel_create(g_hndl)) == NULL)
14830 scfdie();
14831
14832 if (scf_instance_get_snapshot(cur_inst, name, snap) !=
14833 SCF_SUCCESS) {
14834 switch (scf_error()) {
14835 case SCF_ERROR_INVALID_ARGUMENT:
14836 semerr(gettext("Invalid name \"%s\".\n"), name);
14837 break;
14838
14839 case SCF_ERROR_NOT_FOUND:
14840 semerr(gettext("No such snapshot \"%s\".\n"), name);
14841 break;
14842
14843 default:
14844 scfdie();
14845 }
14846
14847 scf_snaplevel_destroy(level);
14848 scf_snapshot_destroy(snap);
14849 return;
14850 }
14851
14852 /* Load the snaplevels into our list. */
14853 cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
14854 if (cur_levels == NULL)
14855 uu_die(gettext("Could not create list: %s\n"),
14856 uu_strerror(uu_error()));
14857
14858 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
14859 if (scf_error() != SCF_ERROR_NOT_FOUND)
14860 scfdie();
14861
14862 semerr(gettext("Snapshot has no snaplevels.\n"));
14863
14864 scf_snaplevel_destroy(level);
14865 scf_snapshot_destroy(snap);
14866 return;
14867 }
14868
14869 cur_snap = snap;
14870
14871 for (;;) {
14872 cur_elt = safe_malloc(sizeof (*cur_elt));
14873 uu_list_node_init(cur_elt, &cur_elt->list_node,
14874 snaplevel_pool);
14875 cur_elt->sl = level;
14876 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
14877 uu_die(gettext("libuutil error: %s\n"),
14878 uu_strerror(uu_error()));
14879
14880 level = scf_snaplevel_create(g_hndl);
14881 if (level == NULL)
14882 scfdie();
14883
14884 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
14885 level) != SCF_SUCCESS) {
14886 if (scf_error() != SCF_ERROR_NOT_FOUND)
14887 scfdie();
14888
14889 scf_snaplevel_destroy(level);
14890 break;
14891 }
14892 }
14893
14894 cur_elt = uu_list_last(cur_levels);
14895 cur_level = cur_elt->sl;
14896 }
14897
14898 /*
14899 * Copies the properties & values in src to dst. Assumes src won't change.
14900 * Returns -1 if permission is denied, -2 if another transaction interrupts,
14901 * and 0 on success.
14902 *
14903 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
14904 * property, if it is copied and has type boolean. (See comment in
14905 * lscf_revert()).
14906 */
14907 static int
pg_copy(const scf_propertygroup_t * src,scf_propertygroup_t * dst,uint8_t enabled)14908 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
14909 uint8_t enabled)
14910 {
14911 scf_transaction_t *tx;
14912 scf_iter_t *iter, *viter;
14913 scf_property_t *prop;
14914 scf_value_t *v;
14915 char *nbuf;
14916 int r;
14917
14918 tx = scf_transaction_create(g_hndl);
14919 if (tx == NULL)
14920 scfdie();
14921
14922 if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
14923 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14924 scfdie();
14925
14926 scf_transaction_destroy(tx);
14927
14928 return (-1);
14929 }
14930
14931 if ((iter = scf_iter_create(g_hndl)) == NULL ||
14932 (prop = scf_property_create(g_hndl)) == NULL ||
14933 (viter = scf_iter_create(g_hndl)) == NULL)
14934 scfdie();
14935
14936 nbuf = safe_malloc(max_scf_name_len + 1);
14937
14938 if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
14939 scfdie();
14940
14941 for (;;) {
14942 scf_transaction_entry_t *e;
14943 scf_type_t ty;
14944
14945 r = scf_iter_next_property(iter, prop);
14946 if (r == -1)
14947 scfdie();
14948 if (r == 0)
14949 break;
14950
14951 e = scf_entry_create(g_hndl);
14952 if (e == NULL)
14953 scfdie();
14954
14955 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
14956 scfdie();
14957
14958 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
14959 scfdie();
14960
14961 if (scf_transaction_property_new(tx, e, nbuf,
14962 ty) != SCF_SUCCESS)
14963 scfdie();
14964
14965 if ((enabled == 0 || enabled == 1) &&
14966 strcmp(nbuf, scf_property_enabled) == 0 &&
14967 ty == SCF_TYPE_BOOLEAN) {
14968 v = scf_value_create(g_hndl);
14969 if (v == NULL)
14970 scfdie();
14971
14972 scf_value_set_boolean(v, enabled);
14973
14974 if (scf_entry_add_value(e, v) != 0)
14975 scfdie();
14976 } else {
14977 if (scf_iter_property_values(viter, prop) != 0)
14978 scfdie();
14979
14980 for (;;) {
14981 v = scf_value_create(g_hndl);
14982 if (v == NULL)
14983 scfdie();
14984
14985 r = scf_iter_next_value(viter, v);
14986 if (r == -1)
14987 scfdie();
14988 if (r == 0) {
14989 scf_value_destroy(v);
14990 break;
14991 }
14992
14993 if (scf_entry_add_value(e, v) != SCF_SUCCESS)
14994 scfdie();
14995 }
14996 }
14997 }
14998
14999 free(nbuf);
15000 scf_iter_destroy(viter);
15001 scf_property_destroy(prop);
15002 scf_iter_destroy(iter);
15003
15004 r = scf_transaction_commit(tx);
15005 if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
15006 scfdie();
15007
15008 scf_transaction_destroy_children(tx);
15009 scf_transaction_destroy(tx);
15010
15011 switch (r) {
15012 case 1: return (0);
15013 case 0: return (-2);
15014 case -1: return (-1);
15015
15016 default:
15017 abort();
15018 }
15019
15020 /* NOTREACHED */
15021 }
15022
15023 void
lscf_revert(const char * snapname)15024 lscf_revert(const char *snapname)
15025 {
15026 scf_snapshot_t *snap, *prev;
15027 scf_snaplevel_t *level, *nlevel;
15028 scf_iter_t *iter;
15029 scf_propertygroup_t *pg, *npg;
15030 scf_property_t *prop;
15031 scf_value_t *val;
15032 char *nbuf, *tbuf;
15033 uint8_t enabled;
15034
15035 lscf_prep_hndl();
15036
15037 if (cur_inst == NULL) {
15038 semerr(gettext("Instance not selected.\n"));
15039 return;
15040 }
15041
15042 if (snapname != NULL) {
15043 snap = scf_snapshot_create(g_hndl);
15044 if (snap == NULL)
15045 scfdie();
15046
15047 if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
15048 SCF_SUCCESS) {
15049 switch (scf_error()) {
15050 case SCF_ERROR_INVALID_ARGUMENT:
15051 semerr(gettext("Invalid snapshot name "
15052 "\"%s\".\n"), snapname);
15053 break;
15054
15055 case SCF_ERROR_NOT_FOUND:
15056 semerr(gettext("No such snapshot.\n"));
15057 break;
15058
15059 default:
15060 scfdie();
15061 }
15062
15063 scf_snapshot_destroy(snap);
15064 return;
15065 }
15066 } else {
15067 if (cur_snap != NULL) {
15068 snap = cur_snap;
15069 } else {
15070 semerr(gettext("No snapshot selected.\n"));
15071 return;
15072 }
15073 }
15074
15075 if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
15076 (level = scf_snaplevel_create(g_hndl)) == NULL ||
15077 (iter = scf_iter_create(g_hndl)) == NULL ||
15078 (pg = scf_pg_create(g_hndl)) == NULL ||
15079 (npg = scf_pg_create(g_hndl)) == NULL ||
15080 (prop = scf_property_create(g_hndl)) == NULL ||
15081 (val = scf_value_create(g_hndl)) == NULL)
15082 scfdie();
15083
15084 nbuf = safe_malloc(max_scf_name_len + 1);
15085 tbuf = safe_malloc(max_scf_pg_type_len + 1);
15086
15087 /* Take the "previous" snapshot before we blow away the properties. */
15088 if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
15089 if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
15090 scfdie();
15091 } else {
15092 if (scf_error() != SCF_ERROR_NOT_FOUND)
15093 scfdie();
15094
15095 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
15096 scfdie();
15097 }
15098
15099 /* Save general/enabled, since we're probably going to replace it. */
15100 enabled = 2;
15101 if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
15102 scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
15103 scf_property_get_value(prop, val) == 0)
15104 (void) scf_value_get_boolean(val, &enabled);
15105
15106 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15107 if (scf_error() != SCF_ERROR_NOT_FOUND)
15108 scfdie();
15109
15110 goto out;
15111 }
15112
15113 for (;;) {
15114 boolean_t isinst;
15115 uint32_t flags;
15116 int r;
15117
15118 /* Clear the properties from the corresponding entity. */
15119 isinst = snaplevel_is_instance(level);
15120
15121 if (!isinst)
15122 r = scf_iter_service_pgs(iter, cur_svc);
15123 else
15124 r = scf_iter_instance_pgs(iter, cur_inst);
15125 if (r != SCF_SUCCESS)
15126 scfdie();
15127
15128 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15129 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15130 scfdie();
15131
15132 /* Skip nonpersistent pgs. */
15133 if (flags & SCF_PG_FLAG_NONPERSISTENT)
15134 continue;
15135
15136 if (scf_pg_delete(pg) != SCF_SUCCESS) {
15137 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15138 scfdie();
15139
15140 semerr(emsg_permission_denied);
15141 goto out;
15142 }
15143 }
15144 if (r == -1)
15145 scfdie();
15146
15147 /* Copy the properties to the corresponding entity. */
15148 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
15149 scfdie();
15150
15151 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15152 if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
15153 scfdie();
15154
15155 if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
15156 0)
15157 scfdie();
15158
15159 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15160 scfdie();
15161
15162 if (!isinst)
15163 r = scf_service_add_pg(cur_svc, nbuf, tbuf,
15164 flags, npg);
15165 else
15166 r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
15167 flags, npg);
15168 if (r != SCF_SUCCESS) {
15169 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15170 scfdie();
15171
15172 semerr(emsg_permission_denied);
15173 goto out;
15174 }
15175
15176 if ((enabled == 0 || enabled == 1) &&
15177 strcmp(nbuf, scf_pg_general) == 0)
15178 r = pg_copy(pg, npg, enabled);
15179 else
15180 r = pg_copy(pg, npg, 2);
15181
15182 switch (r) {
15183 case 0:
15184 break;
15185
15186 case -1:
15187 semerr(emsg_permission_denied);
15188 goto out;
15189
15190 case -2:
15191 semerr(gettext(
15192 "Interrupted by another change.\n"));
15193 goto out;
15194
15195 default:
15196 abort();
15197 }
15198 }
15199 if (r == -1)
15200 scfdie();
15201
15202 /* Get next level. */
15203 nlevel = scf_snaplevel_create(g_hndl);
15204 if (nlevel == NULL)
15205 scfdie();
15206
15207 if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
15208 SCF_SUCCESS) {
15209 if (scf_error() != SCF_ERROR_NOT_FOUND)
15210 scfdie();
15211
15212 scf_snaplevel_destroy(nlevel);
15213 break;
15214 }
15215
15216 scf_snaplevel_destroy(level);
15217 level = nlevel;
15218 }
15219
15220 if (snapname == NULL) {
15221 lscf_selectsnap(NULL);
15222 snap = NULL; /* cur_snap has been destroyed */
15223 }
15224
15225 out:
15226 free(tbuf);
15227 free(nbuf);
15228 scf_value_destroy(val);
15229 scf_property_destroy(prop);
15230 scf_pg_destroy(npg);
15231 scf_pg_destroy(pg);
15232 scf_iter_destroy(iter);
15233 scf_snaplevel_destroy(level);
15234 scf_snapshot_destroy(prev);
15235 if (snap != cur_snap)
15236 scf_snapshot_destroy(snap);
15237 }
15238
15239 void
lscf_refresh(void)15240 lscf_refresh(void)
15241 {
15242 ssize_t fmrilen;
15243 size_t bufsz;
15244 char *fmribuf;
15245 int r;
15246
15247 lscf_prep_hndl();
15248
15249 if (cur_inst == NULL) {
15250 semerr(gettext("Instance not selected.\n"));
15251 return;
15252 }
15253
15254 bufsz = max_scf_fmri_len + 1;
15255 fmribuf = safe_malloc(bufsz);
15256 fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15257 if (fmrilen < 0) {
15258 free(fmribuf);
15259 if (scf_error() != SCF_ERROR_DELETED)
15260 scfdie();
15261 scf_instance_destroy(cur_inst);
15262 cur_inst = NULL;
15263 warn(emsg_deleted);
15264 return;
15265 }
15266 assert(fmrilen < bufsz);
15267
15268 r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15269 switch (r) {
15270 case 0:
15271 break;
15272
15273 case ECONNABORTED:
15274 warn(gettext("Could not refresh %s "
15275 "(repository connection broken).\n"), fmribuf);
15276 break;
15277
15278 case ECANCELED:
15279 warn(emsg_deleted);
15280 break;
15281
15282 case EPERM:
15283 warn(gettext("Could not refresh %s "
15284 "(permission denied).\n"), fmribuf);
15285 break;
15286
15287 case ENOSPC:
15288 warn(gettext("Could not refresh %s "
15289 "(repository server out of resources).\n"),
15290 fmribuf);
15291 break;
15292
15293 case EACCES:
15294 default:
15295 bad_error("refresh_entity", scf_error());
15296 }
15297
15298 free(fmribuf);
15299 }
15300
15301 /*
15302 * describe [-v] [-t] [pg/prop]
15303 */
15304 int
lscf_describe(uu_list_t * args,int hasargs)15305 lscf_describe(uu_list_t *args, int hasargs)
15306 {
15307 int ret = 0;
15308 size_t i;
15309 int argc;
15310 char **argv = NULL;
15311 string_list_t *slp;
15312 int do_verbose = 0;
15313 int do_templates = 0;
15314 char *pattern = NULL;
15315
15316 lscf_prep_hndl();
15317
15318 if (hasargs != 0) {
15319 argc = uu_list_numnodes(args);
15320 if (argc < 1)
15321 goto usage;
15322
15323 argv = calloc(argc + 1, sizeof (char *));
15324 if (argv == NULL)
15325 uu_die(gettext("Out of memory.\n"));
15326
15327 for (slp = uu_list_first(args), i = 0;
15328 slp != NULL;
15329 slp = uu_list_next(args, slp), ++i)
15330 argv[i] = slp->str;
15331
15332 argv[i] = NULL;
15333
15334 /*
15335 * We start optind = 0 because our list of arguments
15336 * starts at argv[0]
15337 */
15338 optind = 0;
15339 opterr = 0;
15340 for (;;) {
15341 ret = getopt(argc, argv, "vt");
15342 if (ret == -1)
15343 break;
15344
15345 switch (ret) {
15346 case 'v':
15347 do_verbose = 1;
15348 break;
15349
15350 case 't':
15351 do_templates = 1;
15352 break;
15353
15354 case '?':
15355 goto usage;
15356
15357 default:
15358 bad_error("getopt", ret);
15359 }
15360 }
15361
15362 pattern = argv[optind];
15363 }
15364
15365 if (cur_inst == NULL && cur_svc == NULL) {
15366 semerr(emsg_entity_not_selected);
15367 ret = -1;
15368 goto out;
15369 }
15370
15371 /*
15372 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15373 * output if their last parameter is set to 2. Less information is
15374 * produced if the parameter is set to 1.
15375 */
15376 if (pattern == NULL) {
15377 if (do_verbose == 1)
15378 list_entity_tmpl(2);
15379 else
15380 list_entity_tmpl(1);
15381 }
15382
15383 if (do_templates == 0) {
15384 if (do_verbose == 1)
15385 listprop(pattern, 0, 2);
15386 else
15387 listprop(pattern, 0, 1);
15388 } else {
15389 if (do_verbose == 1)
15390 listtmpl(pattern, 2);
15391 else
15392 listtmpl(pattern, 1);
15393 }
15394
15395 ret = 0;
15396 out:
15397 if (argv != NULL)
15398 free(argv);
15399 return (ret);
15400 usage:
15401 ret = -2;
15402 goto out;
15403 }
15404
15405 #define PARAM_ACTIVE ((const char *) "active")
15406 #define PARAM_INACTIVE ((const char *) "inactive")
15407 #define PARAM_SMTP_TO ((const char *) "to")
15408
15409 /*
15410 * tokenize()
15411 * Breaks down the string according to the tokens passed.
15412 * Caller is responsible for freeing array of pointers returned.
15413 * Returns NULL on failure
15414 */
15415 char **
tokenize(char * str,const char * sep)15416 tokenize(char *str, const char *sep)
15417 {
15418 char *token, *lasts;
15419 char **buf;
15420 int n = 0; /* number of elements */
15421 int size = 8; /* size of the array (initial) */
15422
15423 buf = safe_malloc(size * sizeof (char *));
15424
15425 for (token = strtok_r(str, sep, &lasts); token != NULL;
15426 token = strtok_r(NULL, sep, &lasts), ++n) {
15427 if (n + 1 >= size) {
15428 size *= 2;
15429 if ((buf = realloc(buf, size * sizeof (char *))) ==
15430 NULL) {
15431 uu_die(gettext("Out of memory"));
15432 }
15433 }
15434 buf[n] = token;
15435 }
15436 /* NULL terminate the pointer array */
15437 buf[n] = NULL;
15438
15439 return (buf);
15440 }
15441
15442 int32_t
check_tokens(char ** p)15443 check_tokens(char **p)
15444 {
15445 int32_t smf = 0;
15446 int32_t fma = 0;
15447
15448 while (*p) {
15449 int32_t t = string_to_tset(*p);
15450
15451 if (t == 0) {
15452 if (is_fma_token(*p) == 0)
15453 return (INVALID_TOKENS);
15454 fma = 1; /* this token is an fma event */
15455 } else {
15456 smf |= t;
15457 }
15458
15459 if (smf != 0 && fma == 1)
15460 return (MIXED_TOKENS);
15461 ++p;
15462 }
15463
15464 if (smf > 0)
15465 return (smf);
15466 else if (fma == 1)
15467 return (FMA_TOKENS);
15468
15469 return (INVALID_TOKENS);
15470 }
15471
15472 static int
get_selection_str(char * fmri,size_t sz)15473 get_selection_str(char *fmri, size_t sz)
15474 {
15475 if (g_hndl == NULL) {
15476 semerr(emsg_entity_not_selected);
15477 return (-1);
15478 } else if (cur_level != NULL) {
15479 semerr(emsg_invalid_for_snapshot);
15480 return (-1);
15481 } else {
15482 lscf_get_selection_str(fmri, sz);
15483 }
15484
15485 return (0);
15486 }
15487
15488 void
lscf_delnotify(const char * set,int global)15489 lscf_delnotify(const char *set, int global)
15490 {
15491 char *str = strdup(set);
15492 char **pgs;
15493 char **p;
15494 int32_t tset;
15495 char *fmri = NULL;
15496
15497 if (str == NULL)
15498 uu_die(gettext("Out of memory.\n"));
15499
15500 pgs = tokenize(str, ",");
15501
15502 if ((tset = check_tokens(pgs)) > 0) {
15503 size_t sz = max_scf_fmri_len + 1;
15504
15505 fmri = safe_malloc(sz);
15506 if (global) {
15507 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15508 } else if (get_selection_str(fmri, sz) != 0) {
15509 goto out;
15510 }
15511
15512 if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri,
15513 tset) != SCF_SUCCESS) {
15514 uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15515 scf_strerror(scf_error()));
15516 }
15517 } else if (tset == FMA_TOKENS) {
15518 if (global) {
15519 semerr(gettext("Can't use option '-g' with FMA event "
15520 "definitions\n"));
15521 goto out;
15522 }
15523
15524 for (p = pgs; *p; ++p) {
15525 if (smf_notify_del_params(de_tag(*p), NULL, NULL) !=
15526 SCF_SUCCESS) {
15527 uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
15528 scf_strerror(scf_error()));
15529 goto out;
15530 }
15531 }
15532 } else if (tset == MIXED_TOKENS) {
15533 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15534 goto out;
15535 } else {
15536 uu_die(gettext("Invalid input.\n"));
15537 }
15538
15539 out:
15540 free(fmri);
15541 free(pgs);
15542 free(str);
15543 }
15544
15545 void
lscf_listnotify(const char * set,int global)15546 lscf_listnotify(const char *set, int global)
15547 {
15548 char *str = safe_strdup(set);
15549 char **pgs;
15550 char **p;
15551 int32_t tset;
15552 nvlist_t *nvl;
15553 char *fmri = NULL;
15554
15555 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
15556 uu_die(gettext("Out of memory.\n"));
15557
15558 pgs = tokenize(str, ",");
15559
15560 if ((tset = check_tokens(pgs)) > 0) {
15561 size_t sz = max_scf_fmri_len + 1;
15562
15563 fmri = safe_malloc(sz);
15564 if (global) {
15565 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15566 } else if (get_selection_str(fmri, sz) != 0) {
15567 goto out;
15568 }
15569
15570 if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
15571 SCF_SUCCESS) {
15572 if (scf_error() != SCF_ERROR_NOT_FOUND &&
15573 scf_error() != SCF_ERROR_DELETED)
15574 uu_warn(gettext(
15575 "Failed listnotify: %s\n"),
15576 scf_strerror(scf_error()));
15577 goto out;
15578 }
15579
15580 listnotify_print(nvl, NULL);
15581 } else if (tset == FMA_TOKENS) {
15582 if (global) {
15583 semerr(gettext("Can't use option '-g' with FMA event "
15584 "definitions\n"));
15585 goto out;
15586 }
15587
15588 for (p = pgs; *p; ++p) {
15589 if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
15590 SCF_SUCCESS) {
15591 /*
15592 * if the preferences have just been deleted
15593 * or does not exist, just skip.
15594 */
15595 if (scf_error() == SCF_ERROR_NOT_FOUND ||
15596 scf_error() == SCF_ERROR_DELETED)
15597 continue;
15598 uu_warn(gettext(
15599 "Failed listnotify: %s\n"),
15600 scf_strerror(scf_error()));
15601 goto out;
15602 }
15603 listnotify_print(nvl, re_tag(*p));
15604 }
15605 } else if (tset == MIXED_TOKENS) {
15606 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15607 goto out;
15608 } else {
15609 semerr(gettext("Invalid input.\n"));
15610 }
15611
15612 out:
15613 nvlist_free(nvl);
15614 free(fmri);
15615 free(pgs);
15616 free(str);
15617 }
15618
15619 static char *
strip_quotes_and_blanks(char * s)15620 strip_quotes_and_blanks(char *s)
15621 {
15622 char *start = s;
15623 char *end = strrchr(s, '\"');
15624
15625 if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
15626 start = s + 1;
15627 while (isblank(*start))
15628 start++;
15629 while (isblank(*(end - 1)) && end > start) {
15630 end--;
15631 }
15632 *end = '\0';
15633 }
15634
15635 return (start);
15636 }
15637
15638 static int
set_active(nvlist_t * mech,const char * hier_part)15639 set_active(nvlist_t *mech, const char *hier_part)
15640 {
15641 boolean_t b;
15642
15643 if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
15644 b = B_TRUE;
15645 } else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
15646 b = B_FALSE;
15647 } else {
15648 return (-1);
15649 }
15650
15651 if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
15652 uu_die(gettext("Out of memory.\n"));
15653
15654 return (0);
15655 }
15656
15657 static int
add_snmp_params(nvlist_t * mech,char * hier_part)15658 add_snmp_params(nvlist_t *mech, char *hier_part)
15659 {
15660 return (set_active(mech, hier_part));
15661 }
15662
15663 static int
add_syslog_params(nvlist_t * mech,char * hier_part)15664 add_syslog_params(nvlist_t *mech, char *hier_part)
15665 {
15666 return (set_active(mech, hier_part));
15667 }
15668
15669 /*
15670 * add_mailto_paramas()
15671 * parse the hier_part of mailto URI
15672 * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
15673 * or mailto:{[active]|inactive}
15674 */
15675 static int
add_mailto_params(nvlist_t * mech,char * hier_part)15676 add_mailto_params(nvlist_t *mech, char *hier_part)
15677 {
15678 const char *tok = "?&";
15679 char *p;
15680 char *lasts;
15681 char *param;
15682 char *val;
15683
15684 /*
15685 * If the notification parametes are in the form of
15686 *
15687 * malito:{[active]|inactive}
15688 *
15689 * we set the property accordingly and return.
15690 * Otherwise, we make the notification type active and
15691 * process the hier_part.
15692 */
15693 if (set_active(mech, hier_part) == 0)
15694 return (0);
15695 else if (set_active(mech, PARAM_ACTIVE) != 0)
15696 return (-1);
15697
15698 if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) {
15699 /*
15700 * sanity check: we only get here if hier_part = "", but
15701 * that's handled by set_active
15702 */
15703 uu_die("strtok_r");
15704 }
15705
15706 if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0)
15707 uu_die(gettext("Out of memory.\n"));
15708
15709 while ((p = strtok_r(NULL, tok, &lasts)) != NULL)
15710 if ((param = strtok_r(p, "=", &val)) != NULL)
15711 if (nvlist_add_string(mech, param, val) != 0)
15712 uu_die(gettext("Out of memory.\n"));
15713
15714 return (0);
15715 }
15716
15717 static int
uri_split(char * uri,char ** scheme,char ** hier_part)15718 uri_split(char *uri, char **scheme, char **hier_part)
15719 {
15720 int r = -1;
15721
15722 if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
15723 *hier_part == NULL) {
15724 semerr(gettext("'%s' is not an URI\n"), uri);
15725 return (r);
15726 }
15727
15728 if ((r = check_uri_scheme(*scheme)) < 0) {
15729 semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
15730 return (r);
15731 }
15732
15733 return (r);
15734 }
15735
15736 static int
process_uri(nvlist_t * params,char * uri)15737 process_uri(nvlist_t *params, char *uri)
15738 {
15739 char *scheme;
15740 char *hier_part;
15741 nvlist_t *mech;
15742 int index;
15743 int r;
15744
15745 if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
15746 return (-1);
15747
15748 if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
15749 uu_die(gettext("Out of memory.\n"));
15750
15751 switch (index) {
15752 case 0:
15753 /* error messages displayed by called function */
15754 r = add_mailto_params(mech, hier_part);
15755 break;
15756
15757 case 1:
15758 if ((r = add_snmp_params(mech, hier_part)) != 0)
15759 semerr(gettext("Not valid parameters: '%s'\n"),
15760 hier_part);
15761 break;
15762
15763 case 2:
15764 if ((r = add_syslog_params(mech, hier_part)) != 0)
15765 semerr(gettext("Not valid parameters: '%s'\n"),
15766 hier_part);
15767 break;
15768
15769 default:
15770 r = -1;
15771 }
15772
15773 if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
15774 mech) != 0)
15775 uu_die(gettext("Out of memory.\n"));
15776
15777 nvlist_free(mech);
15778 return (r);
15779 }
15780
15781 static int
set_params(nvlist_t * params,char ** p)15782 set_params(nvlist_t *params, char **p)
15783 {
15784 char *uri;
15785
15786 if (p == NULL)
15787 /* sanity check */
15788 uu_die("set_params");
15789
15790 while (*p) {
15791 uri = strip_quotes_and_blanks(*p);
15792 if (process_uri(params, uri) != 0)
15793 return (-1);
15794
15795 ++p;
15796 }
15797
15798 return (0);
15799 }
15800
15801 static int
setnotify(const char * e,char ** p,int global)15802 setnotify(const char *e, char **p, int global)
15803 {
15804 char *str = safe_strdup(e);
15805 char **events;
15806 int32_t tset;
15807 int r = -1;
15808 nvlist_t *nvl, *params;
15809 char *fmri = NULL;
15810
15811 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
15812 nvlist_alloc(¶ms, NV_UNIQUE_NAME, 0) != 0 ||
15813 nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
15814 SCF_NOTIFY_PARAMS_VERSION) != 0)
15815 uu_die(gettext("Out of memory.\n"));
15816
15817 events = tokenize(str, ",");
15818
15819 if ((tset = check_tokens(events)) > 0) {
15820 /* SMF state transitions parameters */
15821 size_t sz = max_scf_fmri_len + 1;
15822
15823 fmri = safe_malloc(sz);
15824 if (global) {
15825 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15826 } else if (get_selection_str(fmri, sz) != 0) {
15827 goto out;
15828 }
15829
15830 if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 ||
15831 nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0)
15832 uu_die(gettext("Out of memory.\n"));
15833
15834 if ((r = set_params(params, p)) == 0) {
15835 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS,
15836 params) != 0)
15837 uu_die(gettext("Out of memory.\n"));
15838
15839 if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
15840 nvl) != SCF_SUCCESS) {
15841 r = -1;
15842 uu_warn(gettext(
15843 "Failed smf_notify_set_params(3SCF): %s\n"),
15844 scf_strerror(scf_error()));
15845 }
15846 }
15847 } else if (tset == FMA_TOKENS) {
15848 /* FMA event parameters */
15849 if (global) {
15850 semerr(gettext("Can't use option '-g' with FMA event "
15851 "definitions\n"));
15852 goto out;
15853 }
15854
15855 if ((r = set_params(params, p)) != 0)
15856 goto out;
15857
15858 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
15859 uu_die(gettext("Out of memory.\n"));
15860
15861 while (*events) {
15862 if (smf_notify_set_params(de_tag(*events), nvl) !=
15863 SCF_SUCCESS)
15864 uu_warn(gettext(
15865 "Failed smf_notify_set_params(3SCF) for "
15866 "event %s: %s\n"), *events,
15867 scf_strerror(scf_error()));
15868 events++;
15869 }
15870 } else if (tset == MIXED_TOKENS) {
15871 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15872 } else {
15873 /* Sanity check */
15874 uu_die(gettext("Invalid input.\n"));
15875 }
15876
15877 out:
15878 nvlist_free(nvl);
15879 nvlist_free(params);
15880 free(fmri);
15881 free(str);
15882
15883 return (r);
15884 }
15885
15886 int
lscf_setnotify(uu_list_t * args)15887 lscf_setnotify(uu_list_t *args)
15888 {
15889 int argc;
15890 char **argv = NULL;
15891 string_list_t *slp;
15892 int global;
15893 char *events;
15894 char **p;
15895 int i;
15896 int ret;
15897
15898 if ((argc = uu_list_numnodes(args)) < 2)
15899 goto usage;
15900
15901 argv = calloc(argc + 1, sizeof (char *));
15902 if (argv == NULL)
15903 uu_die(gettext("Out of memory.\n"));
15904
15905 for (slp = uu_list_first(args), i = 0;
15906 slp != NULL;
15907 slp = uu_list_next(args, slp), ++i)
15908 argv[i] = slp->str;
15909
15910 argv[i] = NULL;
15911
15912 if (strcmp(argv[0], "-g") == 0) {
15913 global = 1;
15914 events = argv[1];
15915 p = argv + 2;
15916 } else {
15917 global = 0;
15918 events = argv[0];
15919 p = argv + 1;
15920 }
15921
15922 ret = setnotify(events, p, global);
15923
15924 out:
15925 free(argv);
15926 return (ret);
15927
15928 usage:
15929 ret = -2;
15930 goto out;
15931 }
15932
15933 /*
15934 * Creates a list of instance name strings associated with a service. If
15935 * wohandcrafted flag is set, get only instances that have a last-import
15936 * snapshot, instances that were imported via svccfg.
15937 */
15938 static uu_list_t *
create_instance_list(scf_service_t * svc,int wohandcrafted)15939 create_instance_list(scf_service_t *svc, int wohandcrafted)
15940 {
15941 scf_snapshot_t *snap = NULL;
15942 scf_instance_t *inst;
15943 scf_iter_t *inst_iter;
15944 uu_list_t *instances;
15945 char *instname;
15946 int r;
15947
15948 inst_iter = scf_iter_create(g_hndl);
15949 inst = scf_instance_create(g_hndl);
15950 if (inst_iter == NULL || inst == NULL) {
15951 uu_warn(gettext("Could not create instance or iterator\n"));
15952 scfdie();
15953 }
15954
15955 if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
15956 return (instances);
15957
15958 if (scf_iter_service_instances(inst_iter, svc) != 0) {
15959 switch (scf_error()) {
15960 case SCF_ERROR_CONNECTION_BROKEN:
15961 case SCF_ERROR_DELETED:
15962 uu_list_destroy(instances);
15963 instances = NULL;
15964 goto out;
15965
15966 case SCF_ERROR_HANDLE_MISMATCH:
15967 case SCF_ERROR_NOT_BOUND:
15968 case SCF_ERROR_NOT_SET:
15969 default:
15970 bad_error("scf_iter_service_instances", scf_error());
15971 }
15972 }
15973
15974 instname = safe_malloc(max_scf_name_len + 1);
15975 while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
15976 if (r == -1) {
15977 (void) uu_warn(gettext("Unable to iterate through "
15978 "instances to create instance list : %s\n"),
15979 scf_strerror(scf_error()));
15980
15981 uu_list_destroy(instances);
15982 instances = NULL;
15983 goto out;
15984 }
15985
15986 /*
15987 * If the instance does not have a last-import snapshot
15988 * then do not add it to the list as it is a hand-crafted
15989 * instance that should not be managed.
15990 */
15991 if (wohandcrafted) {
15992 if (snap == NULL &&
15993 (snap = scf_snapshot_create(g_hndl)) == NULL) {
15994 uu_warn(gettext("Unable to create snapshot "
15995 "entity\n"));
15996 scfdie();
15997 }
15998
15999 if (scf_instance_get_snapshot(inst,
16000 snap_lastimport, snap) != 0) {
16001 switch (scf_error()) {
16002 case SCF_ERROR_NOT_FOUND :
16003 case SCF_ERROR_DELETED:
16004 continue;
16005
16006 case SCF_ERROR_CONNECTION_BROKEN:
16007 uu_list_destroy(instances);
16008 instances = NULL;
16009 goto out;
16010
16011 case SCF_ERROR_HANDLE_MISMATCH:
16012 case SCF_ERROR_NOT_BOUND:
16013 case SCF_ERROR_NOT_SET:
16014 default:
16015 bad_error("scf_iter_service_instances",
16016 scf_error());
16017 }
16018 }
16019 }
16020
16021 if (scf_instance_get_name(inst, instname,
16022 max_scf_name_len + 1) < 0) {
16023 switch (scf_error()) {
16024 case SCF_ERROR_NOT_FOUND :
16025 continue;
16026
16027 case SCF_ERROR_CONNECTION_BROKEN:
16028 case SCF_ERROR_DELETED:
16029 uu_list_destroy(instances);
16030 instances = NULL;
16031 goto out;
16032
16033 case SCF_ERROR_HANDLE_MISMATCH:
16034 case SCF_ERROR_NOT_BOUND:
16035 case SCF_ERROR_NOT_SET:
16036 default:
16037 bad_error("scf_iter_service_instances",
16038 scf_error());
16039 }
16040 }
16041
16042 add_string(instances, instname);
16043 }
16044
16045 out:
16046 if (snap)
16047 scf_snapshot_destroy(snap);
16048
16049 scf_instance_destroy(inst);
16050 scf_iter_destroy(inst_iter);
16051 free(instname);
16052 return (instances);
16053 }
16054
16055 /*
16056 * disable an instance but wait for the instance to
16057 * move out of the running state.
16058 *
16059 * Returns 0 : if the instance did not disable
16060 * Returns non-zero : if the instance disabled.
16061 *
16062 */
16063 static int
disable_instance(scf_instance_t * instance)16064 disable_instance(scf_instance_t *instance)
16065 {
16066 char *fmribuf;
16067 int enabled = 10000;
16068
16069 if (inst_is_running(instance)) {
16070 fmribuf = safe_malloc(max_scf_name_len + 1);
16071 if (scf_instance_to_fmri(instance, fmribuf,
16072 max_scf_name_len + 1) < 0) {
16073 free(fmribuf);
16074 return (0);
16075 }
16076
16077 /*
16078 * If the instance cannot be disabled then return
16079 * failure to disable and let the caller decide
16080 * if that is of importance.
16081 */
16082 if (smf_disable_instance(fmribuf, 0) != 0) {
16083 free(fmribuf);
16084 return (0);
16085 }
16086
16087 while (enabled) {
16088 if (!inst_is_running(instance))
16089 break;
16090
16091 (void) poll(NULL, 0, 5);
16092 enabled = enabled - 5;
16093 }
16094
16095 free(fmribuf);
16096 }
16097
16098 return (enabled);
16099 }
16100
16101 /*
16102 * Function to compare two service_manifest structures.
16103 */
16104 /* ARGSUSED2 */
16105 static int
service_manifest_compare(const void * left,const void * right,void * unused)16106 service_manifest_compare(const void *left, const void *right, void *unused)
16107 {
16108 service_manifest_t *l = (service_manifest_t *)left;
16109 service_manifest_t *r = (service_manifest_t *)right;
16110 int rc;
16111
16112 rc = strcmp(l->servicename, r->servicename);
16113
16114 return (rc);
16115 }
16116
16117 /*
16118 * Look for the provided service in the service to manifest
16119 * tree. If the service exists, and a manifest was provided
16120 * then add the manifest to that service. If the service
16121 * does not exist, then add the service and manifest to the
16122 * list.
16123 *
16124 * If the manifest is NULL, return the element if found. If
16125 * the service is not found return NULL.
16126 */
16127 service_manifest_t *
find_add_svc_mfst(const char * svnbuf,const char * mfst)16128 find_add_svc_mfst(const char *svnbuf, const char *mfst)
16129 {
16130 service_manifest_t elem;
16131 service_manifest_t *fnelem;
16132 uu_avl_index_t marker;
16133
16134 elem.servicename = svnbuf;
16135 fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
16136
16137 if (mfst) {
16138 if (fnelem) {
16139 add_string(fnelem->mfstlist, strdup(mfst));
16140 } else {
16141 fnelem = safe_malloc(sizeof (*fnelem));
16142 fnelem->servicename = safe_strdup(svnbuf);
16143 if ((fnelem->mfstlist =
16144 uu_list_create(string_pool, NULL, 0)) == NULL)
16145 uu_die(gettext("Could not create property "
16146 "list: %s\n"), uu_strerror(uu_error()));
16147
16148 add_string(fnelem->mfstlist, safe_strdup(mfst));
16149
16150 uu_avl_insert(service_manifest_tree, fnelem, marker);
16151 }
16152 }
16153
16154 return (fnelem);
16155 }
16156
16157 /*
16158 * Create the service to manifest avl tree.
16159 *
16160 * Walk each of the manifests currently installed in the supported
16161 * directories, /lib/svc/manifests and /var/svc/manifests. For
16162 * each of the manifests, inventory the services and add them to
16163 * the tree.
16164 *
16165 * Code that calls this function should make sure fileystem/minimal is online,
16166 * /var is available, since this function walks the /var/svc/manifest directory.
16167 */
16168 static void
create_manifest_tree(void)16169 create_manifest_tree(void)
16170 {
16171 manifest_info_t **entry;
16172 manifest_info_t **manifests;
16173 uu_list_walk_t *svcs;
16174 bundle_t *b;
16175 entity_t *mfsvc;
16176 char *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
16177 int c, status;
16178
16179 if (service_manifest_pool)
16180 return;
16181
16182 /*
16183 * Create the list pool for the service manifest list
16184 */
16185 service_manifest_pool = uu_avl_pool_create("service_manifest",
16186 sizeof (service_manifest_t),
16187 offsetof(service_manifest_t, svcmfst_node),
16188 service_manifest_compare, UU_DEFAULT);
16189 if (service_manifest_pool == NULL)
16190 uu_die(gettext("service_manifest pool creation failed: %s\n"),
16191 uu_strerror(uu_error()));
16192
16193 /*
16194 * Create the list
16195 */
16196 service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
16197 UU_DEFAULT);
16198 if (service_manifest_tree == NULL)
16199 uu_die(gettext("service_manifest tree creation failed: %s\n"),
16200 uu_strerror(uu_error()));
16201
16202 /*
16203 * Walk the manifests adding the service(s) from each manifest.
16204 *
16205 * If a service already exists add the manifest to the manifest
16206 * list for that service. This covers the case of a service that
16207 * is supported by multiple manifest files.
16208 */
16209 for (c = 0; dirs[c]; c++) {
16210 status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT);
16211 if (status < 0) {
16212 uu_warn(gettext("file tree walk of %s encountered "
16213 "error %s\n"), dirs[c], strerror(errno));
16214
16215 uu_avl_destroy(service_manifest_tree);
16216 service_manifest_tree = NULL;
16217 return;
16218 }
16219
16220 /*
16221 * If a manifest that was in the list is not found
16222 * then skip and go to the next manifest file.
16223 */
16224 if (manifests != NULL) {
16225 for (entry = manifests; *entry != NULL; entry++) {
16226 b = internal_bundle_new();
16227 if (lxml_get_bundle_file(b, (*entry)->mi_path,
16228 SVCCFG_OP_IMPORT) != 0) {
16229 internal_bundle_free(b);
16230 continue;
16231 }
16232
16233 svcs = uu_list_walk_start(b->sc_bundle_services,
16234 0);
16235 if (svcs == NULL) {
16236 internal_bundle_free(b);
16237 continue;
16238 }
16239
16240 while ((mfsvc = uu_list_walk_next(svcs)) !=
16241 NULL) {
16242 /* Add manifest to service */
16243 (void) find_add_svc_mfst(mfsvc->sc_name,
16244 (*entry)->mi_path);
16245 }
16246
16247 uu_list_walk_end(svcs);
16248 internal_bundle_free(b);
16249 }
16250
16251 free_manifest_array(manifests);
16252 }
16253 }
16254 }
16255
16256 /*
16257 * Check the manifest history file to see
16258 * if the service was ever installed from
16259 * one of the supported directories.
16260 *
16261 * Return Values :
16262 * -1 - if there's error reading manifest history file
16263 * 1 - if the service is not found
16264 * 0 - if the service is found
16265 */
16266 static int
check_mfst_history(const char * svcname)16267 check_mfst_history(const char *svcname)
16268 {
16269 struct stat st;
16270 caddr_t mfsthist_start;
16271 char *svnbuf;
16272 int fd;
16273 int r = 1;
16274
16275 fd = open(MFSTHISTFILE, O_RDONLY);
16276 if (fd == -1) {
16277 uu_warn(gettext("Unable to open the history file\n"));
16278 return (-1);
16279 }
16280
16281 if (fstat(fd, &st) == -1) {
16282 uu_warn(gettext("Unable to stat the history file\n"));
16283 return (-1);
16284 }
16285
16286 mfsthist_start = mmap(0, st.st_size, PROT_READ,
16287 MAP_PRIVATE, fd, 0);
16288
16289 (void) close(fd);
16290 if (mfsthist_start == MAP_FAILED ||
16291 *(mfsthist_start + st.st_size) != '\0') {
16292 (void) munmap(mfsthist_start, st.st_size);
16293 return (-1);
16294 }
16295
16296 /*
16297 * The manifest history file is a space delimited list
16298 * of service and instance to manifest linkage. Adding
16299 * a space to the end of the service name so to get only
16300 * the service that is being searched for.
16301 */
16302 svnbuf = uu_msprintf("%s ", svcname);
16303 if (svnbuf == NULL)
16304 uu_die(gettext("Out of memory"));
16305
16306 if (strstr(mfsthist_start, svnbuf) != NULL)
16307 r = 0;
16308
16309 (void) munmap(mfsthist_start, st.st_size);
16310 uu_free(svnbuf);
16311 return (r);
16312 }
16313
16314 /*
16315 * Take down each of the instances in the service
16316 * and remove them, then delete the service.
16317 */
16318 static void
teardown_service(scf_service_t * svc,const char * svnbuf)16319 teardown_service(scf_service_t *svc, const char *svnbuf)
16320 {
16321 scf_instance_t *instance;
16322 scf_iter_t *iter;
16323 int r;
16324
16325 safe_printf(gettext("Delete service %s as there are no "
16326 "supporting manifests\n"), svnbuf);
16327
16328 instance = scf_instance_create(g_hndl);
16329 iter = scf_iter_create(g_hndl);
16330 if (iter == NULL || instance == NULL) {
16331 uu_warn(gettext("Unable to create supporting entities to "
16332 "teardown the service\n"));
16333 uu_warn(gettext("scf error is : %s\n"),
16334 scf_strerror(scf_error()));
16335 scfdie();
16336 }
16337
16338 if (scf_iter_service_instances(iter, svc) != 0) {
16339 switch (scf_error()) {
16340 case SCF_ERROR_CONNECTION_BROKEN:
16341 case SCF_ERROR_DELETED:
16342 goto out;
16343
16344 case SCF_ERROR_HANDLE_MISMATCH:
16345 case SCF_ERROR_NOT_BOUND:
16346 case SCF_ERROR_NOT_SET:
16347 default:
16348 bad_error("scf_iter_service_instances",
16349 scf_error());
16350 }
16351 }
16352
16353 while ((r = scf_iter_next_instance(iter, instance)) != 0) {
16354 if (r == -1) {
16355 uu_warn(gettext("Error - %s\n"),
16356 scf_strerror(scf_error()));
16357 goto out;
16358 }
16359
16360 (void) disable_instance(instance);
16361 }
16362
16363 /*
16364 * Delete the service... forcing the deletion in case
16365 * any of the instances did not disable.
16366 */
16367 (void) lscf_service_delete(svc, 1);
16368 out:
16369 scf_instance_destroy(instance);
16370 scf_iter_destroy(iter);
16371 }
16372
16373 /*
16374 * Get the list of instances supported by the manifest
16375 * file.
16376 *
16377 * Return 0 if there are no instances.
16378 *
16379 * Return -1 if there are errors attempting to collect instances.
16380 *
16381 * Return the count of instances found if there are no errors.
16382 *
16383 */
16384 static int
check_instance_support(char * mfstfile,const char * svcname,uu_list_t * instances)16385 check_instance_support(char *mfstfile, const char *svcname,
16386 uu_list_t *instances)
16387 {
16388 uu_list_walk_t *svcs, *insts;
16389 uu_list_t *ilist;
16390 bundle_t *b;
16391 entity_t *mfsvc, *mfinst;
16392 const char *svcn;
16393 int rminstcnt = 0;
16394
16395
16396 b = internal_bundle_new();
16397
16398 if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
16399 /*
16400 * Unable to process the manifest file for
16401 * instance support, so just return as
16402 * don't want to remove instances that could
16403 * not be accounted for that might exist here.
16404 */
16405 internal_bundle_free(b);
16406 return (0);
16407 }
16408
16409 svcs = uu_list_walk_start(b->sc_bundle_services, 0);
16410 if (svcs == NULL) {
16411 internal_bundle_free(b);
16412 return (0);
16413 }
16414
16415 svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
16416 (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
16417
16418 while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
16419 if (strcmp(mfsvc->sc_name, svcn) == 0)
16420 break;
16421 }
16422 uu_list_walk_end(svcs);
16423
16424 if (mfsvc == NULL) {
16425 internal_bundle_free(b);
16426 return (-1);
16427 }
16428
16429 ilist = mfsvc->sc_u.sc_service.sc_service_instances;
16430 if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
16431 internal_bundle_free(b);
16432 return (0);
16433 }
16434
16435 while ((mfinst = uu_list_walk_next(insts)) != NULL) {
16436 /*
16437 * Remove the instance from the instances list.
16438 * The unaccounted for instances will be removed
16439 * from the service once all manifests are
16440 * processed.
16441 */
16442 (void) remove_string(instances,
16443 mfinst->sc_name);
16444 rminstcnt++;
16445 }
16446
16447 uu_list_walk_end(insts);
16448 internal_bundle_free(b);
16449
16450 return (rminstcnt);
16451 }
16452
16453 /*
16454 * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16455 * 'false' to indicate there's no manifest file(s) found for the service.
16456 */
16457 static void
svc_add_no_support(scf_service_t * svc)16458 svc_add_no_support(scf_service_t *svc)
16459 {
16460 char *pname;
16461
16462 /* Add no support */
16463 cur_svc = svc;
16464 if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
16465 return;
16466
16467 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
16468 if (pname == NULL)
16469 uu_die(gettext("Out of memory.\n"));
16470
16471 (void) lscf_addpropvalue(pname, "boolean:", "0");
16472
16473 uu_free(pname);
16474 cur_svc = NULL;
16475 }
16476
16477 /*
16478 * This function handles all upgrade scenarios for a service that doesn't have
16479 * SCF_PG_MANIFESTFILES pg. The function creates and populates
16480 * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16481 * manifest(s) mapping. Manifests under supported directories are inventoried
16482 * and a property is added for each file that delivers configuration to the
16483 * service. A service that has no corresponding manifest files (deleted) are
16484 * removed from repository.
16485 *
16486 * Unsupported services:
16487 *
16488 * A service is considered unsupported if there is no corresponding manifest
16489 * in the supported directories for that service and the service isn't in the
16490 * history file list. The history file, MFSTHISTFILE, contains a list of all
16491 * services and instances that were delivered by Solaris before the introduction
16492 * of the SCF_PG_MANIFESTFILES property group. The history file also contains
16493 * the path to the manifest file that defined the service or instance.
16494 *
16495 * Another type of unsupported services is 'handcrafted' services,
16496 * programmatically created services or services created by dependent entries
16497 * in other manifests. A handcrafted service is identified by its lack of any
16498 * instance containing last-import snapshot which is created during svccfg
16499 * import.
16500 *
16501 * This function sets a flag for unsupported services by setting services'
16502 * SCF_PG_MANIFESTFILES/support property to false.
16503 */
16504 static void
upgrade_svc_mfst_connection(scf_service_t * svc,const char * svcname)16505 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
16506 {
16507 service_manifest_t *elem;
16508 uu_list_walk_t *mfwalk;
16509 string_list_t *mfile;
16510 uu_list_t *instances;
16511 const char *sname;
16512 char *pname;
16513 int r;
16514
16515 /*
16516 * Since there's no guarantee manifests under /var are available during
16517 * early import, don't perform any upgrade during early import.
16518 */
16519 if (IGNORE_VAR)
16520 return;
16521
16522 if (service_manifest_tree == NULL) {
16523 create_manifest_tree();
16524 }
16525
16526 /*
16527 * Find service's supporting manifest(s) after
16528 * stripping off the svc:/ prefix that is part
16529 * of the fmri that is not used in the service
16530 * manifest bundle list.
16531 */
16532 sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
16533 strlen(SCF_FMRI_SERVICE_PREFIX);
16534 elem = find_add_svc_mfst(sname, NULL);
16535 if (elem == NULL) {
16536
16537 /*
16538 * A handcrafted service, one that has no instance containing
16539 * last-import snapshot, should get unsupported flag.
16540 */
16541 instances = create_instance_list(svc, 1);
16542 if (instances == NULL) {
16543 uu_warn(gettext("Unable to create instance list %s\n"),
16544 svcname);
16545 return;
16546 }
16547
16548 if (uu_list_numnodes(instances) == 0) {
16549 svc_add_no_support(svc);
16550 return;
16551 }
16552
16553 /*
16554 * If the service is in the history file, and its supporting
16555 * manifests are not found, we can safely delete the service
16556 * because its manifests are removed from the system.
16557 *
16558 * Services not found in the history file are not delivered by
16559 * Solaris and/or delivered outside supported directories, set
16560 * unsupported flag for these services.
16561 */
16562 r = check_mfst_history(svcname);
16563 if (r == -1)
16564 return;
16565
16566 if (r) {
16567 /* Set unsupported flag for service */
16568 svc_add_no_support(svc);
16569 } else {
16570 /* Delete the service */
16571 teardown_service(svc, svcname);
16572 }
16573
16574 return;
16575 }
16576
16577 /*
16578 * Walk through the list of manifests and add them
16579 * to the service.
16580 *
16581 * Create a manifestfiles pg and add the property.
16582 */
16583 mfwalk = uu_list_walk_start(elem->mfstlist, 0);
16584 if (mfwalk == NULL)
16585 return;
16586
16587 cur_svc = svc;
16588 r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
16589 if (r != 0) {
16590 cur_svc = NULL;
16591 return;
16592 }
16593
16594 while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
16595 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16596 mhash_filename_to_propname(mfile->str, 0));
16597 if (pname == NULL)
16598 uu_die(gettext("Out of memory.\n"));
16599
16600 (void) lscf_addpropvalue(pname, "astring:", mfile->str);
16601 uu_free(pname);
16602 }
16603 uu_list_walk_end(mfwalk);
16604
16605 cur_svc = NULL;
16606 }
16607
16608 /*
16609 * Take a service and process the manifest file entires to see if
16610 * there is continued support for the service and instances. If
16611 * not cleanup as appropriate.
16612 *
16613 * If a service does not have a manifest files entry flag it for
16614 * upgrade and return.
16615 *
16616 * For each manifestfiles property check if the manifest file is
16617 * under the supported /lib/svc/manifest or /var/svc/manifest path
16618 * and if not then return immediately as this service is not supported
16619 * by the cleanup mechanism and should be ignored.
16620 *
16621 * For each manifest file that is supported, check to see if the
16622 * file exists. If not then remove the manifest file property
16623 * from the service and the smf/manifest hash table. If the manifest
16624 * file exists then verify that it supports the instances that are
16625 * part of the service.
16626 *
16627 * Once all manifest files have been accounted for remove any instances
16628 * that are no longer supported in the service.
16629 *
16630 * Return values :
16631 * 0 - Successfully processed the service
16632 * non-zero - failed to process the service
16633 *
16634 * On most errors, will just return to wait and get the next service,
16635 * unless in case of unable to create the needed structures which is
16636 * most likely a fatal error that is not going to be recoverable.
16637 */
16638 int
lscf_service_cleanup(void * act,scf_walkinfo_t * wip)16639 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
16640 {
16641 struct mpg_mfile *mpntov;
16642 struct mpg_mfile **mpvarry = NULL;
16643 scf_service_t *svc;
16644 scf_propertygroup_t *mpg;
16645 scf_property_t *mp;
16646 scf_value_t *mv;
16647 scf_iter_t *mi;
16648 scf_instance_t *instance;
16649 uu_list_walk_t *insts;
16650 uu_list_t *instances = NULL;
16651 boolean_t activity = (boolean_t)act;
16652 char *mpnbuf;
16653 char *mpvbuf;
16654 char *pgpropbuf;
16655 int mfstcnt, rminstct, instct, mfstmax;
16656 int index;
16657 int r = 0;
16658
16659 assert(g_hndl != NULL);
16660 assert(wip->svc != NULL);
16661 assert(wip->fmri != NULL);
16662
16663 svc = wip->svc;
16664
16665 mpg = scf_pg_create(g_hndl);
16666 mp = scf_property_create(g_hndl);
16667 mi = scf_iter_create(g_hndl);
16668 mv = scf_value_create(g_hndl);
16669 instance = scf_instance_create(g_hndl);
16670
16671 if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
16672 instance == NULL) {
16673 uu_warn(gettext("Unable to create the supporting entities\n"));
16674 uu_warn(gettext("scf error is : %s\n"),
16675 scf_strerror(scf_error()));
16676 scfdie();
16677 }
16678
16679 /*
16680 * Get the manifestfiles property group to be parsed for
16681 * files existence.
16682 */
16683 if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
16684 switch (scf_error()) {
16685 case SCF_ERROR_NOT_FOUND:
16686 upgrade_svc_mfst_connection(svc, wip->fmri);
16687 break;
16688 case SCF_ERROR_DELETED:
16689 case SCF_ERROR_CONNECTION_BROKEN:
16690 goto out;
16691
16692 case SCF_ERROR_HANDLE_MISMATCH:
16693 case SCF_ERROR_NOT_BOUND:
16694 case SCF_ERROR_NOT_SET:
16695 default:
16696 bad_error("scf_iter_pg_properties",
16697 scf_error());
16698 }
16699
16700 goto out;
16701 }
16702
16703 /*
16704 * Iterate through each of the manifestfiles properties
16705 * to determine what manifestfiles are available.
16706 *
16707 * If a manifest file is supported then increment the
16708 * count and therefore the service is safe.
16709 */
16710 if (scf_iter_pg_properties(mi, mpg) != 0) {
16711 switch (scf_error()) {
16712 case SCF_ERROR_DELETED:
16713 case SCF_ERROR_CONNECTION_BROKEN:
16714 goto out;
16715
16716 case SCF_ERROR_HANDLE_MISMATCH:
16717 case SCF_ERROR_NOT_BOUND:
16718 case SCF_ERROR_NOT_SET:
16719 default:
16720 bad_error("scf_iter_pg_properties",
16721 scf_error());
16722 }
16723 }
16724
16725 mfstcnt = 0;
16726 mfstmax = MFSTFILE_MAX;
16727 mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
16728 while ((r = scf_iter_next_property(mi, mp)) != 0) {
16729 if (r == -1)
16730 bad_error(gettext("Unable to iterate through "
16731 "manifestfiles properties : %s"),
16732 scf_error());
16733
16734 mpntov = safe_malloc(sizeof (struct mpg_mfile));
16735 mpnbuf = safe_malloc(max_scf_name_len + 1);
16736 mpvbuf = safe_malloc(max_scf_value_len + 1);
16737 mpntov->mpg = mpnbuf;
16738 mpntov->mfile = mpvbuf;
16739 mpntov->access = 1;
16740 if (scf_property_get_name(mp, mpnbuf,
16741 max_scf_name_len + 1) < 0) {
16742 uu_warn(gettext("Unable to get manifest file "
16743 "property : %s\n"),
16744 scf_strerror(scf_error()));
16745
16746 switch (scf_error()) {
16747 case SCF_ERROR_DELETED:
16748 case SCF_ERROR_CONNECTION_BROKEN:
16749 r = scferror2errno(scf_error());
16750 goto out_free;
16751
16752 case SCF_ERROR_HANDLE_MISMATCH:
16753 case SCF_ERROR_NOT_BOUND:
16754 case SCF_ERROR_NOT_SET:
16755 default:
16756 bad_error("scf_iter_pg_properties",
16757 scf_error());
16758 }
16759 }
16760
16761 /*
16762 * The support property is a boolean value that indicates
16763 * if the service is supported for manifest file deletion.
16764 * Currently at this time there is no code that sets this
16765 * value to true. So while we could just let this be caught
16766 * by the support check below, in the future this by be set
16767 * to true and require processing. So for that, go ahead
16768 * and check here, and just return if false. Otherwise,
16769 * fall through expecting that other support checks will
16770 * handle the entries.
16771 */
16772 if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
16773 uint8_t support;
16774
16775 if (scf_property_get_value(mp, mv) != 0 ||
16776 scf_value_get_boolean(mv, &support) != 0) {
16777 uu_warn(gettext("Unable to get the manifest "
16778 "support value: %s\n"),
16779 scf_strerror(scf_error()));
16780
16781 switch (scf_error()) {
16782 case SCF_ERROR_DELETED:
16783 case SCF_ERROR_CONNECTION_BROKEN:
16784 r = scferror2errno(scf_error());
16785 goto out_free;
16786
16787 case SCF_ERROR_HANDLE_MISMATCH:
16788 case SCF_ERROR_NOT_BOUND:
16789 case SCF_ERROR_NOT_SET:
16790 default:
16791 bad_error("scf_iter_pg_properties",
16792 scf_error());
16793 }
16794 }
16795
16796 if (support == B_FALSE)
16797 goto out_free;
16798 }
16799
16800 /*
16801 * Anything with a manifest outside of the supported
16802 * directories, immediately bail out because that makes
16803 * this service non-supported. We don't even want
16804 * to do instance processing in this case because the
16805 * instances could be part of the non-supported manifest.
16806 */
16807 if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
16808 /*
16809 * Manifest is not in /lib/svc, so we need to
16810 * consider the /var/svc case.
16811 */
16812 if (strncmp(mpnbuf, VARSVC_PR,
16813 strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
16814 /*
16815 * Either the manifest is not in /var/svc or
16816 * /var is not yet mounted. We ignore the
16817 * manifest either because it is not in a
16818 * standard location or because we cannot
16819 * currently access the manifest.
16820 */
16821 goto out_free;
16822 }
16823 }
16824
16825 /*
16826 * Get the value to of the manifest file for this entry
16827 * for access verification and instance support
16828 * verification if it still exists.
16829 *
16830 * During Early Manifest Import if the manifest is in
16831 * /var/svc then it may not yet be available for checking
16832 * so we must determine if /var/svc is available. If not
16833 * then defer until Late Manifest Import to cleanup.
16834 */
16835 if (scf_property_get_value(mp, mv) != 0) {
16836 uu_warn(gettext("Unable to get the manifest file "
16837 "value: %s\n"),
16838 scf_strerror(scf_error()));
16839
16840 switch (scf_error()) {
16841 case SCF_ERROR_DELETED:
16842 case SCF_ERROR_CONNECTION_BROKEN:
16843 r = scferror2errno(scf_error());
16844 goto out_free;
16845
16846 case SCF_ERROR_HANDLE_MISMATCH:
16847 case SCF_ERROR_NOT_BOUND:
16848 case SCF_ERROR_NOT_SET:
16849 default:
16850 bad_error("scf_property_get_value",
16851 scf_error());
16852 }
16853 }
16854
16855 if (scf_value_get_astring(mv, mpvbuf,
16856 max_scf_value_len + 1) < 0) {
16857 uu_warn(gettext("Unable to get the manifest "
16858 "file : %s\n"),
16859 scf_strerror(scf_error()));
16860
16861 switch (scf_error()) {
16862 case SCF_ERROR_DELETED:
16863 case SCF_ERROR_CONNECTION_BROKEN:
16864 r = scferror2errno(scf_error());
16865 goto out_free;
16866
16867 case SCF_ERROR_HANDLE_MISMATCH:
16868 case SCF_ERROR_NOT_BOUND:
16869 case SCF_ERROR_NOT_SET:
16870 default:
16871 bad_error("scf_value_get_astring",
16872 scf_error());
16873 }
16874 }
16875
16876 mpvarry[mfstcnt] = mpntov;
16877 mfstcnt++;
16878
16879 /*
16880 * Check for the need to reallocate array
16881 */
16882 if (mfstcnt >= (mfstmax - 1)) {
16883 struct mpg_mfile **newmpvarry;
16884
16885 mfstmax = mfstmax * 2;
16886 newmpvarry = realloc(mpvarry,
16887 sizeof (struct mpg_mfile *) * mfstmax);
16888
16889 if (newmpvarry == NULL)
16890 goto out_free;
16891
16892 mpvarry = newmpvarry;
16893 }
16894
16895 mpvarry[mfstcnt] = NULL;
16896 }
16897
16898 for (index = 0; mpvarry[index]; index++) {
16899 mpntov = mpvarry[index];
16900
16901 /*
16902 * Check to see if the manifestfile is accessable, if so hand
16903 * this service and manifestfile off to be processed for
16904 * instance support.
16905 */
16906 mpnbuf = mpntov->mpg;
16907 mpvbuf = mpntov->mfile;
16908 if (access(mpvbuf, F_OK) != 0) {
16909 mpntov->access = 0;
16910 activity++;
16911 mfstcnt--;
16912 /* Remove the entry from the service */
16913 cur_svc = svc;
16914 pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16915 mpnbuf);
16916 if (pgpropbuf == NULL)
16917 uu_die(gettext("Out of memory.\n"));
16918
16919 lscf_delprop(pgpropbuf);
16920 cur_svc = NULL;
16921
16922 uu_free(pgpropbuf);
16923 }
16924 }
16925
16926 /*
16927 * If mfstcnt is 0, none of the manifests that supported the service
16928 * existed so remove the service.
16929 */
16930 if (mfstcnt == 0) {
16931 teardown_service(svc, wip->fmri);
16932
16933 goto out_free;
16934 }
16935
16936 if (activity) {
16937 int nosvcsupport = 0;
16938
16939 /*
16940 * If the list of service instances is NULL then
16941 * create the list.
16942 */
16943 instances = create_instance_list(svc, 1);
16944 if (instances == NULL) {
16945 uu_warn(gettext("Unable to create instance list %s\n"),
16946 wip->fmri);
16947 goto out_free;
16948 }
16949
16950 rminstct = uu_list_numnodes(instances);
16951 instct = rminstct;
16952
16953 for (index = 0; mpvarry[index]; index++) {
16954 mpntov = mpvarry[index];
16955 if (mpntov->access == 0)
16956 continue;
16957
16958 mpnbuf = mpntov->mpg;
16959 mpvbuf = mpntov->mfile;
16960 r = check_instance_support(mpvbuf, wip->fmri,
16961 instances);
16962 if (r == -1) {
16963 nosvcsupport++;
16964 } else {
16965 rminstct -= r;
16966 }
16967 }
16968
16969 if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
16970 teardown_service(svc, wip->fmri);
16971
16972 goto out_free;
16973 }
16974 }
16975
16976 /*
16977 * If there are instances left on the instance list, then
16978 * we must remove them.
16979 */
16980 if (instances != NULL && uu_list_numnodes(instances)) {
16981 string_list_t *sp;
16982
16983 insts = uu_list_walk_start(instances, 0);
16984 while ((sp = uu_list_walk_next(insts)) != NULL) {
16985 /*
16986 * Remove the instance from the instances list.
16987 */
16988 safe_printf(gettext("Delete instance %s from "
16989 "service %s\n"), sp->str, wip->fmri);
16990 if (scf_service_get_instance(svc, sp->str,
16991 instance) != SCF_SUCCESS) {
16992 (void) uu_warn("scf_error - %s\n",
16993 scf_strerror(scf_error()));
16994
16995 continue;
16996 }
16997
16998 (void) disable_instance(instance);
16999
17000 (void) lscf_instance_delete(instance, 1);
17001 }
17002 scf_instance_destroy(instance);
17003 uu_list_walk_end(insts);
17004 }
17005
17006 out_free:
17007 if (mpvarry) {
17008 struct mpg_mfile *fmpntov;
17009
17010 for (index = 0; mpvarry[index]; index++) {
17011 fmpntov = mpvarry[index];
17012 if (fmpntov->mpg == mpnbuf)
17013 mpnbuf = NULL;
17014 free(fmpntov->mpg);
17015
17016 if (fmpntov->mfile == mpvbuf)
17017 mpvbuf = NULL;
17018 free(fmpntov->mfile);
17019
17020 if (fmpntov == mpntov)
17021 mpntov = NULL;
17022 free(fmpntov);
17023 }
17024 if (mpnbuf)
17025 free(mpnbuf);
17026 if (mpvbuf)
17027 free(mpvbuf);
17028 if (mpntov)
17029 free(mpntov);
17030
17031 free(mpvarry);
17032 }
17033 out:
17034 scf_pg_destroy(mpg);
17035 scf_property_destroy(mp);
17036 scf_iter_destroy(mi);
17037 scf_value_destroy(mv);
17038
17039 return (0);
17040 }
17041
17042 /*
17043 * Take the service and search for the manifestfiles property
17044 * in each of the property groups. If the manifest file
17045 * associated with the property does not exist then remove
17046 * the property group.
17047 */
17048 int
lscf_hash_cleanup()17049 lscf_hash_cleanup()
17050 {
17051 scf_service_t *svc;
17052 scf_scope_t *scope;
17053 scf_propertygroup_t *pg;
17054 scf_property_t *prop;
17055 scf_value_t *val;
17056 scf_iter_t *iter;
17057 char *pgname = NULL;
17058 char *mfile = NULL;
17059 int r;
17060
17061 svc = scf_service_create(g_hndl);
17062 scope = scf_scope_create(g_hndl);
17063 pg = scf_pg_create(g_hndl);
17064 prop = scf_property_create(g_hndl);
17065 val = scf_value_create(g_hndl);
17066 iter = scf_iter_create(g_hndl);
17067 if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
17068 svc == NULL || scope == NULL) {
17069 uu_warn(gettext("Unable to create a property group, or "
17070 "property\n"));
17071 uu_warn("%s\n", pg == NULL ? "pg is NULL" :
17072 "pg is not NULL");
17073 uu_warn("%s\n", prop == NULL ? "prop is NULL" :
17074 "prop is not NULL");
17075 uu_warn("%s\n", val == NULL ? "val is NULL" :
17076 "val is not NULL");
17077 uu_warn("%s\n", iter == NULL ? "iter is NULL" :
17078 "iter is not NULL");
17079 uu_warn("%s\n", svc == NULL ? "svc is NULL" :
17080 "svc is not NULL");
17081 uu_warn("%s\n", scope == NULL ? "scope is NULL" :
17082 "scope is not NULL");
17083 uu_warn(gettext("scf error is : %s\n"),
17084 scf_strerror(scf_error()));
17085 scfdie();
17086 }
17087
17088 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
17089 switch (scf_error()) {
17090 case SCF_ERROR_CONNECTION_BROKEN:
17091 case SCF_ERROR_NOT_FOUND:
17092 goto out;
17093
17094 case SCF_ERROR_HANDLE_MISMATCH:
17095 case SCF_ERROR_NOT_BOUND:
17096 case SCF_ERROR_INVALID_ARGUMENT:
17097 default:
17098 bad_error("scf_handle_get_scope", scf_error());
17099 }
17100 }
17101
17102 if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
17103 uu_warn(gettext("Unable to process the hash service, %s\n"),
17104 HASH_SVC);
17105 goto out;
17106 }
17107
17108 pgname = safe_malloc(max_scf_name_len + 1);
17109 mfile = safe_malloc(max_scf_value_len + 1);
17110
17111 if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
17112 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17113 scf_strerror(scf_error()));
17114 goto out;
17115 }
17116
17117 while ((r = scf_iter_next_pg(iter, pg)) != 0) {
17118 if (r == -1)
17119 goto out;
17120
17121 if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
17122 switch (scf_error()) {
17123 case SCF_ERROR_DELETED:
17124 return (ENODEV);
17125
17126 case SCF_ERROR_CONNECTION_BROKEN:
17127 return (ECONNABORTED);
17128
17129 case SCF_ERROR_NOT_SET:
17130 case SCF_ERROR_NOT_BOUND:
17131 default:
17132 bad_error("scf_pg_get_name", scf_error());
17133 }
17134 }
17135 if (IGNORE_VAR) {
17136 if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
17137 continue;
17138 }
17139
17140 /*
17141 * If unable to get the property continue as this is an
17142 * entry that has no location to check against.
17143 */
17144 if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
17145 continue;
17146 }
17147
17148 if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
17149 uu_warn(gettext("Unable to get value from %s\n"),
17150 pgname);
17151
17152 switch (scf_error()) {
17153 case SCF_ERROR_DELETED:
17154 case SCF_ERROR_CONSTRAINT_VIOLATED:
17155 case SCF_ERROR_NOT_FOUND:
17156 case SCF_ERROR_NOT_SET:
17157 continue;
17158
17159 case SCF_ERROR_CONNECTION_BROKEN:
17160 r = scferror2errno(scf_error());
17161 goto out;
17162
17163 case SCF_ERROR_HANDLE_MISMATCH:
17164 case SCF_ERROR_NOT_BOUND:
17165 default:
17166 bad_error("scf_property_get_value",
17167 scf_error());
17168 }
17169 }
17170
17171 if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
17172 == -1) {
17173 uu_warn(gettext("Unable to get astring from %s : %s\n"),
17174 pgname, scf_strerror(scf_error()));
17175
17176 switch (scf_error()) {
17177 case SCF_ERROR_NOT_SET:
17178 case SCF_ERROR_TYPE_MISMATCH:
17179 continue;
17180
17181 default:
17182 bad_error("scf_value_get_astring", scf_error());
17183 }
17184 }
17185
17186 if (access(mfile, F_OK) == 0)
17187 continue;
17188
17189 (void) scf_pg_delete(pg);
17190 }
17191
17192 out:
17193 scf_scope_destroy(scope);
17194 scf_service_destroy(svc);
17195 scf_pg_destroy(pg);
17196 scf_property_destroy(prop);
17197 scf_value_destroy(val);
17198 scf_iter_destroy(iter);
17199 free(pgname);
17200 free(mfile);
17201
17202 return (0);
17203 }
17204
17205 #ifndef NATIVE_BUILD
17206 /* ARGSUSED */
CPL_MATCH_FN(complete_select)17207 CPL_MATCH_FN(complete_select)
17208 {
17209 const char *arg0, *arg1, *arg1end;
17210 int word_start, err = 0, r;
17211 size_t len;
17212 char *buf;
17213
17214 lscf_prep_hndl();
17215
17216 arg0 = line + strspn(line, " \t");
17217 assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
17218
17219 arg1 = arg0 + sizeof ("select") - 1;
17220 arg1 += strspn(arg1, " \t");
17221 word_start = arg1 - line;
17222
17223 arg1end = arg1 + strcspn(arg1, " \t");
17224 if (arg1end < line + word_end)
17225 return (0);
17226
17227 len = line + word_end - arg1;
17228
17229 buf = safe_malloc(max_scf_name_len + 1);
17230
17231 if (cur_snap != NULL) {
17232 return (0);
17233 } else if (cur_inst != NULL) {
17234 return (0);
17235 } else if (cur_svc != NULL) {
17236 scf_instance_t *inst;
17237 scf_iter_t *iter;
17238
17239 if ((inst = scf_instance_create(g_hndl)) == NULL ||
17240 (iter = scf_iter_create(g_hndl)) == NULL)
17241 scfdie();
17242
17243 if (scf_iter_service_instances(iter, cur_svc) != 0)
17244 scfdie();
17245
17246 for (;;) {
17247 r = scf_iter_next_instance(iter, inst);
17248 if (r == 0)
17249 break;
17250 if (r != 1)
17251 scfdie();
17252
17253 if (scf_instance_get_name(inst, buf,
17254 max_scf_name_len + 1) < 0)
17255 scfdie();
17256
17257 if (strncmp(buf, arg1, len) == 0) {
17258 err = cpl_add_completion(cpl, line, word_start,
17259 word_end, buf + len, "", " ");
17260 if (err != 0)
17261 break;
17262 }
17263 }
17264
17265 scf_iter_destroy(iter);
17266 scf_instance_destroy(inst);
17267
17268 return (err);
17269 } else {
17270 scf_service_t *svc;
17271 scf_iter_t *iter;
17272
17273 assert(cur_scope != NULL);
17274
17275 if ((svc = scf_service_create(g_hndl)) == NULL ||
17276 (iter = scf_iter_create(g_hndl)) == NULL)
17277 scfdie();
17278
17279 if (scf_iter_scope_services(iter, cur_scope) != 0)
17280 scfdie();
17281
17282 for (;;) {
17283 r = scf_iter_next_service(iter, svc);
17284 if (r == 0)
17285 break;
17286 if (r != 1)
17287 scfdie();
17288
17289 if (scf_service_get_name(svc, buf,
17290 max_scf_name_len + 1) < 0)
17291 scfdie();
17292
17293 if (strncmp(buf, arg1, len) == 0) {
17294 err = cpl_add_completion(cpl, line, word_start,
17295 word_end, buf + len, "", " ");
17296 if (err != 0)
17297 break;
17298 }
17299 }
17300
17301 scf_iter_destroy(iter);
17302 scf_service_destroy(svc);
17303
17304 return (err);
17305 }
17306 }
17307
17308 /* ARGSUSED */
CPL_MATCH_FN(complete_command)17309 CPL_MATCH_FN(complete_command)
17310 {
17311 uint32_t scope = 0;
17312
17313 if (cur_snap != NULL)
17314 scope = CS_SNAP;
17315 else if (cur_inst != NULL)
17316 scope = CS_INST;
17317 else if (cur_svc != NULL)
17318 scope = CS_SVC;
17319 else
17320 scope = CS_SCOPE;
17321
17322 return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
17323 }
17324 #endif /* NATIVE_BUILD */
17325