1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2020 Joyent, Inc.
25 * Copyright 2012 Milan Jurik. All rights reserved.
26 * Copyright 2017 RackTop Systems.
27 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
28 * Copyright 2023 Oxide Computer Company
29 */
30
31
32 #include <alloca.h>
33 #include <assert.h>
34 #include <ctype.h>
35 #include <door.h>
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <fnmatch.h>
39 #include <inttypes.h>
40 #include <libintl.h>
41 #include <libnvpair.h>
42 #include <libscf.h>
43 #include <libscf_priv.h>
44 #include <libtecla.h>
45 #include <libuutil.h>
46 #include <limits.h>
47 #include <locale.h>
48 #include <stdarg.h>
49 #include <string.h>
50 #include <strings.h>
51 #include <time.h>
52 #include <unistd.h>
53 #include <wait.h>
54 #include <poll.h>
55
56 #include <libxml/tree.h>
57
58 #include <sys/param.h>
59
60 #include <sys/stat.h>
61 #include <sys/mman.h>
62
63 #include "svccfg.h"
64 #include "notify_params.h"
65 #include "manifest_hash.h"
66 #include "manifest_find.h"
67
68 /* The colon namespaces in each entity (each followed by a newline). */
69 #define COLON_NAMESPACES ":properties\n"
70
71 #define TEMP_FILE_PATTERN "/tmp/svccfg-XXXXXX"
72
73 /* These are characters which the lexer requires to be in double-quotes. */
74 #define CHARS_TO_QUOTE " \t\n\\>=\"()"
75
76 #define HASH_SIZE 16
77 #define HASH_PG_TYPE "framework"
78 #define HASH_PG_FLAGS 0
79 #define HASH_PROP "md5sum"
80
81 /*
82 * Indentation used in the output of the describe subcommand.
83 */
84 #define TMPL_VALUE_INDENT " "
85 #define TMPL_INDENT " "
86 #define TMPL_INDENT_2X " "
87 #define TMPL_CHOICE_INDENT " "
88
89 /*
90 * Directory locations for manifests
91 */
92 #define VARSVC_DIR "/var/svc/manifest"
93 #define LIBSVC_DIR "/lib/svc/manifest"
94 #define VARSVC_PR "var_svc_manifest"
95 #define LIBSVC_PR "lib_svc_manifest"
96 #define MFSTFILEPR "manifestfile"
97
98 #define SUPPORTPROP "support"
99
100 #define MFSTHISTFILE "/lib/svc/share/mfsthistory"
101
102 #define MFSTFILE_MAX 16
103
104 /*
105 * These are the classes of elements which may appear as children of service
106 * or instance elements in XML manifests.
107 */
108 struct entity_elts {
109 xmlNodePtr create_default_instance;
110 xmlNodePtr single_instance;
111 xmlNodePtr restarter;
112 xmlNodePtr dependencies;
113 xmlNodePtr dependents;
114 xmlNodePtr method_context;
115 xmlNodePtr exec_methods;
116 xmlNodePtr notify_params;
117 xmlNodePtr property_groups;
118 xmlNodePtr instances;
119 xmlNodePtr stability;
120 xmlNodePtr template;
121 };
122
123 /*
124 * Likewise for property_group elements.
125 */
126 struct pg_elts {
127 xmlNodePtr stability;
128 xmlNodePtr propvals;
129 xmlNodePtr properties;
130 };
131
132 /*
133 * Likewise for template elements.
134 */
135 struct template_elts {
136 xmlNodePtr common_name;
137 xmlNodePtr description;
138 xmlNodePtr documentation;
139 };
140
141 /*
142 * Likewise for type (for notification parameters) elements.
143 */
144 struct params_elts {
145 xmlNodePtr paramval;
146 xmlNodePtr parameter;
147 };
148
149 /*
150 * This structure is for snaplevel lists. They are convenient because libscf
151 * only allows traversing snaplevels in one direction.
152 */
153 struct snaplevel {
154 uu_list_node_t list_node;
155 scf_snaplevel_t *sl;
156 };
157
158 /*
159 * This is used for communication between lscf_service_export and
160 * export_callback.
161 */
162 struct export_args {
163 const char *filename;
164 int flags;
165 };
166
167 /*
168 * The service_manifest structure is used by the upgrade process
169 * to create a list of service to manifest linkages from the manifests
170 * in a set of given directories.
171 */
172 typedef struct service_manifest {
173 const char *servicename;
174 uu_list_t *mfstlist;
175 size_t mfstlist_sz;
176
177 uu_avl_node_t svcmfst_node;
178 } service_manifest_t;
179
180 /*
181 * Structure to track the manifest file property group
182 * and the manifest file associated with that property
183 * group. Also, a flag to keep the access once it has
184 * been checked.
185 */
186 struct mpg_mfile {
187 char *mpg;
188 char *mfile;
189 int access;
190 };
191
192 const char * const scf_pg_general = SCF_PG_GENERAL;
193 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
194 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
195 const char * const scf_property_external = "external";
196
197 const char * const snap_initial = "initial";
198 const char * const snap_lastimport = "last-import";
199 const char * const snap_previous = "previous";
200 const char * const snap_running = "running";
201
202 scf_handle_t *g_hndl = NULL; /* only valid after lscf_prep_hndl() */
203
204 ssize_t max_scf_fmri_len;
205 ssize_t max_scf_name_len;
206 ssize_t max_scf_pg_type_len;
207 ssize_t max_scf_value_len;
208 static size_t max_scf_len;
209
210 static scf_scope_t *cur_scope;
211 static scf_service_t *cur_svc = NULL;
212 static scf_instance_t *cur_inst = NULL;
213 static scf_snapshot_t *cur_snap = NULL;
214 static scf_snaplevel_t *cur_level = NULL;
215
216 static uu_list_pool_t *snaplevel_pool;
217 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
218 static uu_list_t *cur_levels;
219 static struct snaplevel *cur_elt; /* cur_elt->sl == cur_level */
220
221 static FILE *tempfile = NULL;
222 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
223
224 static const char *emsg_entity_not_selected;
225 static const char *emsg_permission_denied;
226 static const char *emsg_create_xml;
227 static const char *emsg_cant_modify_snapshots;
228 static const char *emsg_invalid_for_snapshot;
229 static const char *emsg_read_only;
230 static const char *emsg_deleted;
231 static const char *emsg_invalid_pg_name;
232 static const char *emsg_invalid_prop_name;
233 static const char *emsg_no_such_pg;
234 static const char *emsg_fmri_invalid_pg_name;
235 static const char *emsg_fmri_invalid_pg_name_type;
236 static const char *emsg_pg_added;
237 static const char *emsg_pg_changed;
238 static const char *emsg_pg_deleted;
239 static const char *emsg_pg_mod_perm;
240 static const char *emsg_pg_add_perm;
241 static const char *emsg_pg_del_perm;
242 static const char *emsg_snap_perm;
243 static const char *emsg_dpt_dangling;
244 static const char *emsg_dpt_no_dep;
245
246 static int li_only = 0;
247 static int no_refresh = 0;
248
249 /* how long in ns we should wait between checks for a pg */
250 static uint64_t pg_timeout = 100 * (NANOSEC / MILLISEC);
251
252 /* import globals, to minimize allocations */
253 static scf_scope_t *imp_scope = NULL;
254 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
255 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
256 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
257 static scf_snapshot_t *imp_rsnap = NULL;
258 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
259 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
260 static scf_property_t *imp_prop = NULL;
261 static scf_iter_t *imp_iter = NULL;
262 static scf_iter_t *imp_rpg_iter = NULL;
263 static scf_iter_t *imp_up_iter = NULL;
264 static scf_transaction_t *imp_tx = NULL; /* always reset this */
265 static char *imp_str = NULL;
266 static size_t imp_str_sz;
267 static char *imp_tsname = NULL;
268 static char *imp_fe1 = NULL; /* for fmri_equal() */
269 static char *imp_fe2 = NULL;
270 static uu_list_t *imp_deleted_dpts = NULL; /* pgroup_t's to refresh */
271
272 /* upgrade_dependents() globals */
273 static scf_instance_t *ud_inst = NULL;
274 static scf_snaplevel_t *ud_snpl = NULL;
275 static scf_propertygroup_t *ud_pg = NULL;
276 static scf_propertygroup_t *ud_cur_depts_pg = NULL;
277 static scf_propertygroup_t *ud_run_dpts_pg = NULL;
278 static int ud_run_dpts_pg_set = 0;
279 static scf_property_t *ud_prop = NULL;
280 static scf_property_t *ud_dpt_prop = NULL;
281 static scf_value_t *ud_val = NULL;
282 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
283 static scf_transaction_t *ud_tx = NULL;
284 static char *ud_ctarg = NULL;
285 static char *ud_oldtarg = NULL;
286 static char *ud_name = NULL;
287
288 /* export globals */
289 static scf_instance_t *exp_inst;
290 static scf_propertygroup_t *exp_pg;
291 static scf_property_t *exp_prop;
292 static scf_value_t *exp_val;
293 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
294 static char *exp_str;
295 static size_t exp_str_sz;
296
297 /* cleanup globals */
298 static uu_avl_pool_t *service_manifest_pool = NULL;
299 static uu_avl_t *service_manifest_tree = NULL;
300
301 static void scfdie_lineno(int lineno) __NORETURN;
302
303 static char *start_method_names[] = {
304 "start",
305 "inetd_start",
306 NULL
307 };
308
309 static struct uri_scheme {
310 const char *scheme;
311 const char *protocol;
312 } uri_scheme[] = {
313 { "mailto", "smtp" },
314 { "snmp", "snmp" },
315 { "syslog", "syslog" },
316 { NULL, NULL }
317 };
318 #define URI_SCHEME_NUM ((sizeof (uri_scheme) / \
319 sizeof (struct uri_scheme)) - 1)
320
321 static int
check_uri_scheme(const char * scheme)322 check_uri_scheme(const char *scheme)
323 {
324 int i;
325
326 for (i = 0; uri_scheme[i].scheme != NULL; ++i) {
327 if (strcmp(scheme, uri_scheme[i].scheme) == 0)
328 return (i);
329 }
330
331 return (-1);
332 }
333
334 static int
check_uri_protocol(const char * p)335 check_uri_protocol(const char *p)
336 {
337 int i;
338
339 for (i = 0; uri_scheme[i].protocol != NULL; ++i) {
340 if (strcmp(p, uri_scheme[i].protocol) == 0)
341 return (i);
342 }
343
344 return (-1);
345 }
346
347 /*
348 * For unexpected libscf errors.
349 */
350 #ifdef NDEBUG
351
352 static void scfdie(void) __NORETURN;
353
354 static void
scfdie(void)355 scfdie(void)
356 {
357 scf_error_t err = scf_error();
358
359 if (err == SCF_ERROR_CONNECTION_BROKEN)
360 uu_die(gettext("Repository connection broken. Exiting.\n"));
361
362 uu_die(gettext("Unexpected fatal libscf error: %s. Exiting.\n"),
363 scf_strerror(err));
364 }
365
366 #else
367
368 #define scfdie() scfdie_lineno(__LINE__)
369
370 static void
scfdie_lineno(int lineno)371 scfdie_lineno(int lineno)
372 {
373 scf_error_t err = scf_error();
374
375 if (err == SCF_ERROR_CONNECTION_BROKEN)
376 uu_die(gettext("Repository connection broken. Exiting.\n"));
377
378 uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
379 ": %s.\n"), lineno, scf_strerror(err));
380 }
381
382 #endif
383
384 static void
scfwarn(void)385 scfwarn(void)
386 {
387 warn(gettext("Unexpected libscf error: %s.\n"),
388 scf_strerror(scf_error()));
389 }
390
391 /*
392 * Clear a field of a structure.
393 */
394 static int
clear_int(void * a,void * b)395 clear_int(void *a, void *b)
396 {
397 /* LINTED */
398 *(int *)((char *)a + (size_t)b) = 0;
399
400 return (UU_WALK_NEXT);
401 }
402
403 static int
scferror2errno(scf_error_t err)404 scferror2errno(scf_error_t err)
405 {
406 switch (err) {
407 case SCF_ERROR_BACKEND_ACCESS:
408 return (EACCES);
409
410 case SCF_ERROR_BACKEND_READONLY:
411 return (EROFS);
412
413 case SCF_ERROR_CONNECTION_BROKEN:
414 return (ECONNABORTED);
415
416 case SCF_ERROR_CONSTRAINT_VIOLATED:
417 case SCF_ERROR_INVALID_ARGUMENT:
418 return (EINVAL);
419
420 case SCF_ERROR_DELETED:
421 return (ECANCELED);
422
423 case SCF_ERROR_EXISTS:
424 return (EEXIST);
425
426 case SCF_ERROR_NO_MEMORY:
427 return (ENOMEM);
428
429 case SCF_ERROR_NO_RESOURCES:
430 return (ENOSPC);
431
432 case SCF_ERROR_NOT_FOUND:
433 return (ENOENT);
434
435 case SCF_ERROR_PERMISSION_DENIED:
436 return (EPERM);
437
438 default:
439 #ifndef NDEBUG
440 (void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
441 __FILE__, __LINE__, err);
442 #else
443 (void) fprintf(stderr, "Unknown libscf error %d.\n", err);
444 #endif
445 abort();
446 /* NOTREACHED */
447 }
448 }
449
450 static int
entity_get_pg(void * ent,int issvc,const char * name,scf_propertygroup_t * pg)451 entity_get_pg(void *ent, int issvc, const char *name,
452 scf_propertygroup_t *pg)
453 {
454 if (issvc)
455 return (scf_service_get_pg(ent, name, pg));
456 else
457 return (scf_instance_get_pg(ent, name, pg));
458 }
459
460 static void
entity_destroy(void * ent,int issvc)461 entity_destroy(void *ent, int issvc)
462 {
463 if (issvc)
464 scf_service_destroy(ent);
465 else
466 scf_instance_destroy(ent);
467 }
468
469 static int
get_pg(const char * pg_name,scf_propertygroup_t * pg)470 get_pg(const char *pg_name, scf_propertygroup_t *pg)
471 {
472 int ret;
473
474 if (cur_level != NULL)
475 ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
476 else if (cur_inst != NULL)
477 ret = scf_instance_get_pg(cur_inst, pg_name, pg);
478 else
479 ret = scf_service_get_pg(cur_svc, pg_name, pg);
480
481 return (ret);
482 }
483
484 /*
485 * Find a snaplevel in a snapshot. If get_svc is true, find the service
486 * snaplevel. Otherwise find the instance snaplevel.
487 *
488 * Returns
489 * 0 - success
490 * ECONNABORTED - repository connection broken
491 * ECANCELED - instance containing snap was deleted
492 * ENOENT - snap has no snaplevels
493 * - requested snaplevel not found
494 */
495 static int
get_snaplevel(scf_snapshot_t * snap,int get_svc,scf_snaplevel_t * snpl)496 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
497 {
498 if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
499 switch (scf_error()) {
500 case SCF_ERROR_CONNECTION_BROKEN:
501 case SCF_ERROR_DELETED:
502 case SCF_ERROR_NOT_FOUND:
503 return (scferror2errno(scf_error()));
504
505 case SCF_ERROR_HANDLE_MISMATCH:
506 case SCF_ERROR_NOT_BOUND:
507 case SCF_ERROR_NOT_SET:
508 default:
509 bad_error("scf_snapshot_get_base_snaplevel",
510 scf_error());
511 }
512 }
513
514 for (;;) {
515 ssize_t ssz;
516
517 ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
518 if (ssz >= 0) {
519 if (!get_svc)
520 return (0);
521 } else {
522 switch (scf_error()) {
523 case SCF_ERROR_CONSTRAINT_VIOLATED:
524 if (get_svc)
525 return (0);
526 break;
527
528 case SCF_ERROR_DELETED:
529 case SCF_ERROR_CONNECTION_BROKEN:
530 return (scferror2errno(scf_error()));
531
532 case SCF_ERROR_NOT_SET:
533 case SCF_ERROR_NOT_BOUND:
534 default:
535 bad_error("scf_snaplevel_get_instance_name",
536 scf_error());
537 }
538 }
539
540 if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
541 switch (scf_error()) {
542 case SCF_ERROR_NOT_FOUND:
543 case SCF_ERROR_CONNECTION_BROKEN:
544 case SCF_ERROR_DELETED:
545 return (scferror2errno(scf_error()));
546
547 case SCF_ERROR_HANDLE_MISMATCH:
548 case SCF_ERROR_NOT_BOUND:
549 case SCF_ERROR_NOT_SET:
550 case SCF_ERROR_INVALID_ARGUMENT:
551 default:
552 bad_error("scf_snaplevel_get_next_snaplevel",
553 scf_error());
554 }
555 }
556 }
557 }
558
559 /*
560 * If issvc is 0, take ent to be a pointer to an scf_instance_t. If it has
561 * a running snapshot, and that snapshot has an instance snaplevel, set pg to
562 * the property group named name in it. If it doesn't have a running
563 * snapshot, set pg to the instance's current property group named name.
564 *
565 * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
566 * its instances. If one has a running snapshot with a service snaplevel, set
567 * pg to the property group named name in it. If no such snaplevel could be
568 * found, set pg to the service's current property group named name.
569 *
570 * iter, inst, snap, and snpl are required scratch objects.
571 *
572 * Returns
573 * 0 - success
574 * ECONNABORTED - repository connection broken
575 * ECANCELED - ent was deleted
576 * ENOENT - no such property group
577 * EINVAL - name is an invalid property group name
578 * EBADF - found running snapshot is missing a snaplevel
579 */
580 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)581 entity_get_running_pg(void *ent, int issvc, const char *name,
582 scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
583 scf_snapshot_t *snap, scf_snaplevel_t *snpl)
584 {
585 int r;
586
587 if (issvc) {
588 /* Search for an instance with a running snapshot. */
589 if (scf_iter_service_instances(iter, ent) != 0) {
590 switch (scf_error()) {
591 case SCF_ERROR_DELETED:
592 case SCF_ERROR_CONNECTION_BROKEN:
593 return (scferror2errno(scf_error()));
594
595 case SCF_ERROR_NOT_SET:
596 case SCF_ERROR_NOT_BOUND:
597 case SCF_ERROR_HANDLE_MISMATCH:
598 default:
599 bad_error("scf_iter_service_instances",
600 scf_error());
601 }
602 }
603
604 for (;;) {
605 r = scf_iter_next_instance(iter, inst);
606 if (r == 0) {
607 if (scf_service_get_pg(ent, name, pg) == 0)
608 return (0);
609
610 switch (scf_error()) {
611 case SCF_ERROR_DELETED:
612 case SCF_ERROR_NOT_FOUND:
613 case SCF_ERROR_INVALID_ARGUMENT:
614 case SCF_ERROR_CONNECTION_BROKEN:
615 return (scferror2errno(scf_error()));
616
617 case SCF_ERROR_NOT_BOUND:
618 case SCF_ERROR_HANDLE_MISMATCH:
619 case SCF_ERROR_NOT_SET:
620 default:
621 bad_error("scf_service_get_pg",
622 scf_error());
623 }
624 }
625 if (r != 1) {
626 switch (scf_error()) {
627 case SCF_ERROR_DELETED:
628 case SCF_ERROR_CONNECTION_BROKEN:
629 return (scferror2errno(scf_error()));
630
631 case SCF_ERROR_INVALID_ARGUMENT:
632 case SCF_ERROR_NOT_SET:
633 case SCF_ERROR_NOT_BOUND:
634 case SCF_ERROR_HANDLE_MISMATCH:
635 default:
636 bad_error("scf_iter_next_instance",
637 scf_error());
638 }
639 }
640
641 if (scf_instance_get_snapshot(inst, snap_running,
642 snap) == 0)
643 break;
644
645 switch (scf_error()) {
646 case SCF_ERROR_NOT_FOUND:
647 case SCF_ERROR_DELETED:
648 continue;
649
650 case SCF_ERROR_CONNECTION_BROKEN:
651 return (ECONNABORTED);
652
653 case SCF_ERROR_HANDLE_MISMATCH:
654 case SCF_ERROR_INVALID_ARGUMENT:
655 case SCF_ERROR_NOT_SET:
656 case SCF_ERROR_NOT_BOUND:
657 default:
658 bad_error("scf_instance_get_snapshot",
659 scf_error());
660 }
661 }
662 } else {
663 if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
664 switch (scf_error()) {
665 case SCF_ERROR_NOT_FOUND:
666 break;
667
668 case SCF_ERROR_DELETED:
669 case SCF_ERROR_CONNECTION_BROKEN:
670 return (scferror2errno(scf_error()));
671
672 case SCF_ERROR_NOT_BOUND:
673 case SCF_ERROR_HANDLE_MISMATCH:
674 case SCF_ERROR_INVALID_ARGUMENT:
675 case SCF_ERROR_NOT_SET:
676 default:
677 bad_error("scf_instance_get_snapshot",
678 scf_error());
679 }
680
681 if (scf_instance_get_pg(ent, name, pg) == 0)
682 return (0);
683
684 switch (scf_error()) {
685 case SCF_ERROR_DELETED:
686 case SCF_ERROR_NOT_FOUND:
687 case SCF_ERROR_INVALID_ARGUMENT:
688 case SCF_ERROR_CONNECTION_BROKEN:
689 return (scferror2errno(scf_error()));
690
691 case SCF_ERROR_NOT_BOUND:
692 case SCF_ERROR_HANDLE_MISMATCH:
693 case SCF_ERROR_NOT_SET:
694 default:
695 bad_error("scf_instance_get_pg", scf_error());
696 }
697 }
698 }
699
700 r = get_snaplevel(snap, issvc, snpl);
701 switch (r) {
702 case 0:
703 break;
704
705 case ECONNABORTED:
706 case ECANCELED:
707 return (r);
708
709 case ENOENT:
710 return (EBADF);
711
712 default:
713 bad_error("get_snaplevel", r);
714 }
715
716 if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
717 return (0);
718
719 switch (scf_error()) {
720 case SCF_ERROR_DELETED:
721 case SCF_ERROR_INVALID_ARGUMENT:
722 case SCF_ERROR_CONNECTION_BROKEN:
723 case SCF_ERROR_NOT_FOUND:
724 return (scferror2errno(scf_error()));
725
726 case SCF_ERROR_NOT_BOUND:
727 case SCF_ERROR_HANDLE_MISMATCH:
728 case SCF_ERROR_NOT_SET:
729 default:
730 bad_error("scf_snaplevel_get_pg", scf_error());
731 /* NOTREACHED */
732 }
733 }
734
735 /*
736 * To be registered with atexit().
737 */
738 static void
remove_tempfile(void)739 remove_tempfile(void)
740 {
741 int ret;
742
743 if (tempfile != NULL) {
744 if (fclose(tempfile) == EOF)
745 (void) warn(gettext("Could not close temporary file"));
746 tempfile = NULL;
747 }
748
749 if (tempfilename[0] != '\0') {
750 do {
751 ret = remove(tempfilename);
752 } while (ret == -1 && errno == EINTR);
753 if (ret == -1)
754 warn(gettext("Could not remove temporary file"));
755 tempfilename[0] = '\0';
756 }
757 }
758
759 /*
760 * Launch private svc.configd(8) for manipulating alternate repositories.
761 */
762 static void
start_private_repository(engine_state_t * est)763 start_private_repository(engine_state_t *est)
764 {
765 int fd, stat;
766 struct door_info info;
767 pid_t pid;
768
769 /*
770 * 1. Create a temporary file for the door.
771 */
772 if (est->sc_repo_doorname != NULL)
773 free((void *)est->sc_repo_doorname);
774
775 est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
776 if (est->sc_repo_doorname == NULL)
777 uu_die(gettext("Could not acquire temporary filename"));
778
779 fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
780 if (fd < 0)
781 uu_die(gettext("Could not create temporary file for "
782 "repository server"));
783
784 (void) close(fd);
785
786 /*
787 * 2. Launch a configd with that door, using the specified
788 * repository.
789 */
790 if ((est->sc_repo_pid = fork()) == 0) {
791 (void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
792 "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
793 NULL);
794 uu_die(gettext("Could not execute %s"), est->sc_repo_server);
795 } else if (est->sc_repo_pid == -1)
796 uu_die(gettext("Attempt to fork failed"));
797
798 do {
799 pid = waitpid(est->sc_repo_pid, &stat, 0);
800 } while (pid == -1 && errno == EINTR);
801
802 if (pid == -1)
803 uu_die(gettext("Could not waitpid() for repository server"));
804
805 if (!WIFEXITED(stat)) {
806 uu_die(gettext("Repository server failed (status %d).\n"),
807 stat);
808 } else if (WEXITSTATUS(stat) != 0) {
809 uu_die(gettext("Repository server failed (exit %d).\n"),
810 WEXITSTATUS(stat));
811 }
812
813 /*
814 * See if it was successful by checking if the door is a door.
815 */
816
817 fd = open(est->sc_repo_doorname, O_RDWR);
818 if (fd < 0)
819 uu_die(gettext("Could not open door \"%s\""),
820 est->sc_repo_doorname);
821
822 if (door_info(fd, &info) < 0)
823 uu_die(gettext("Unexpected door_info() error"));
824
825 if (close(fd) == -1)
826 warn(gettext("Could not close repository door"),
827 strerror(errno));
828
829 est->sc_repo_pid = info.di_target;
830 }
831
832 void
lscf_cleanup(void)833 lscf_cleanup(void)
834 {
835 /*
836 * In the case where we've launched a private svc.configd(8)
837 * instance, we must terminate our child and remove the temporary
838 * rendezvous point.
839 */
840 if (est->sc_repo_pid > 0) {
841 (void) kill(est->sc_repo_pid, SIGTERM);
842 (void) waitpid(est->sc_repo_pid, NULL, 0);
843 (void) unlink(est->sc_repo_doorname);
844
845 est->sc_repo_pid = 0;
846 }
847 }
848
849 void
unselect_cursnap(void)850 unselect_cursnap(void)
851 {
852 void *cookie;
853
854 cur_level = NULL;
855
856 cookie = NULL;
857 while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
858 scf_snaplevel_destroy(cur_elt->sl);
859 free(cur_elt);
860 }
861
862 scf_snapshot_destroy(cur_snap);
863 cur_snap = NULL;
864 }
865
866 void
lscf_prep_hndl(void)867 lscf_prep_hndl(void)
868 {
869 if (g_hndl != NULL)
870 return;
871
872 g_hndl = scf_handle_create(SCF_VERSION);
873 if (g_hndl == NULL)
874 scfdie();
875
876 if (est->sc_repo_filename != NULL)
877 start_private_repository(est);
878
879 if (est->sc_repo_doorname != NULL) {
880 scf_value_t *repo_value;
881 int ret;
882
883 repo_value = scf_value_create(g_hndl);
884 if (repo_value == NULL)
885 scfdie();
886
887 ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
888 assert(ret == SCF_SUCCESS);
889
890 if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
891 SCF_SUCCESS)
892 scfdie();
893
894 scf_value_destroy(repo_value);
895 } else if (g_do_zone != 0) {
896 scf_value_t *zone;
897
898 if ((zone = scf_value_create(g_hndl)) == NULL)
899 scfdie();
900
901 if (scf_value_set_astring(zone, g_zonename) != SCF_SUCCESS)
902 scfdie();
903
904 if (scf_handle_decorate(g_hndl, "zone", zone) != SCF_SUCCESS) {
905 uu_die(gettext("zone '%s': %s\n"),
906 g_zonename, scf_strerror(scf_error()));
907 }
908
909 scf_value_destroy(zone);
910 }
911
912 if (scf_handle_bind(g_hndl) != 0)
913 uu_die(gettext("Could not connect to repository server: %s.\n"),
914 scf_strerror(scf_error()));
915
916 cur_scope = scf_scope_create(g_hndl);
917 if (cur_scope == NULL)
918 scfdie();
919
920 if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
921 scfdie();
922 }
923
924 static void
repository_teardown(void)925 repository_teardown(void)
926 {
927 if (g_hndl != NULL) {
928 if (cur_snap != NULL)
929 unselect_cursnap();
930 scf_instance_destroy(cur_inst);
931 scf_service_destroy(cur_svc);
932 scf_scope_destroy(cur_scope);
933 scf_handle_destroy(g_hndl);
934 cur_inst = NULL;
935 cur_svc = NULL;
936 cur_scope = NULL;
937 g_hndl = NULL;
938 lscf_cleanup();
939 }
940 }
941
942 void
lscf_set_repository(const char * repfile,int force)943 lscf_set_repository(const char *repfile, int force)
944 {
945 repository_teardown();
946
947 if (est->sc_repo_filename != NULL) {
948 free((void *)est->sc_repo_filename);
949 est->sc_repo_filename = NULL;
950 }
951
952 if ((force == 0) && (access(repfile, R_OK) != 0)) {
953 /*
954 * Repository file does not exist
955 * or has no read permission.
956 */
957 warn(gettext("Cannot access \"%s\": %s\n"),
958 repfile, strerror(errno));
959 } else {
960 est->sc_repo_filename = safe_strdup(repfile);
961 }
962
963 lscf_prep_hndl();
964 }
965
966 void
lscf_init()967 lscf_init()
968 {
969 if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
970 (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
971 (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
972 0 ||
973 (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
974 scfdie();
975
976 max_scf_len = max_scf_fmri_len;
977 if (max_scf_name_len > max_scf_len)
978 max_scf_len = max_scf_name_len;
979 if (max_scf_pg_type_len > max_scf_len)
980 max_scf_len = max_scf_pg_type_len;
981 /*
982 * When a value of type opaque is represented as a string, the
983 * string contains 2 characters for every byte of data. That is
984 * because the string contains the hex representation of the opaque
985 * value.
986 */
987 if (2 * max_scf_value_len > max_scf_len)
988 max_scf_len = 2 * max_scf_value_len;
989
990 if (atexit(remove_tempfile) != 0)
991 uu_die(gettext("Could not register atexit() function"));
992
993 emsg_entity_not_selected = gettext("An entity is not selected.\n");
994 emsg_permission_denied = gettext("Permission denied.\n");
995 emsg_create_xml = gettext("Could not create XML node.\n");
996 emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
997 emsg_invalid_for_snapshot =
998 gettext("Invalid operation on a snapshot.\n");
999 emsg_read_only = gettext("Backend read-only.\n");
1000 emsg_deleted = gettext("Current selection has been deleted.\n");
1001 emsg_invalid_pg_name =
1002 gettext("Invalid property group name \"%s\".\n");
1003 emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
1004 emsg_no_such_pg = gettext("No such property group \"%s\".\n");
1005 emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
1006 "with invalid name \"%s\".\n");
1007 emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
1008 "group with invalid name \"%s\" or type \"%s\".\n");
1009 emsg_pg_added = gettext("%s changed unexpectedly "
1010 "(property group \"%s\" added).\n");
1011 emsg_pg_changed = gettext("%s changed unexpectedly "
1012 "(property group \"%s\" changed).\n");
1013 emsg_pg_deleted = gettext("%s changed unexpectedly "
1014 "(property group \"%s\" or an ancestor was deleted).\n");
1015 emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
1016 "in %s (permission denied).\n");
1017 emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
1018 "in %s (permission denied).\n");
1019 emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
1020 "in %s (permission denied).\n");
1021 emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
1022 "(permission denied).\n");
1023 emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
1024 "new dependent \"%s\" because it already exists). Warning: The "
1025 "current dependent's target (%s) does not exist.\n");
1026 emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
1027 "dependent \"%s\" because it already exists). Warning: The "
1028 "current dependent's target (%s) does not have a dependency named "
1029 "\"%s\" as expected.\n");
1030
1031 string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
1032 offsetof(string_list_t, node), NULL, 0);
1033 snaplevel_pool = uu_list_pool_create("snaplevels",
1034 sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
1035 NULL, 0);
1036 }
1037
1038
1039 static const char *
prop_to_typestr(const scf_property_t * prop)1040 prop_to_typestr(const scf_property_t *prop)
1041 {
1042 scf_type_t ty;
1043
1044 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
1045 scfdie();
1046
1047 return (scf_type_to_string(ty));
1048 }
1049
1050 static scf_type_t
string_to_type(const char * type)1051 string_to_type(const char *type)
1052 {
1053 size_t len = strlen(type);
1054 char *buf;
1055
1056 if (len == 0 || type[len - 1] != ':')
1057 return (SCF_TYPE_INVALID);
1058
1059 buf = (char *)alloca(len + 1);
1060 (void) strlcpy(buf, type, len + 1);
1061 buf[len - 1] = 0;
1062
1063 return (scf_string_to_type(buf));
1064 }
1065
1066 static scf_value_t *
string_to_value(const char * str,scf_type_t ty,boolean_t require_quotes)1067 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
1068 {
1069 scf_value_t *v;
1070 char *dup, *nstr;
1071 size_t len;
1072
1073 v = scf_value_create(g_hndl);
1074 if (v == NULL)
1075 scfdie();
1076
1077 len = strlen(str);
1078 if (require_quotes &&
1079 (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
1080 semerr(gettext("Multiple string values or string values "
1081 "with spaces must be quoted with '\"'.\n"));
1082 scf_value_destroy(v);
1083 return (NULL);
1084 }
1085
1086 nstr = dup = safe_strdup(str);
1087 if (dup[0] == '\"') {
1088 /*
1089 * Strip out the first and the last quote.
1090 */
1091 dup[len - 1] = '\0';
1092 nstr = dup + 1;
1093 }
1094
1095 if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
1096 assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1097 semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1098 scf_type_to_string(ty), nstr);
1099 scf_value_destroy(v);
1100 v = NULL;
1101 }
1102 free(dup);
1103 return (v);
1104 }
1105
1106 /*
1107 * Print str to strm, quoting double-quotes and backslashes with backslashes.
1108 * Optionally append a comment prefix ('#') to newlines ('\n').
1109 */
1110 static int
quote_and_print(const char * str,FILE * strm,int commentnl)1111 quote_and_print(const char *str, FILE *strm, int commentnl)
1112 {
1113 const char *cp;
1114
1115 for (cp = str; *cp != '\0'; ++cp) {
1116 if (*cp == '"' || *cp == '\\')
1117 (void) putc('\\', strm);
1118
1119 (void) putc(*cp, strm);
1120
1121 if (commentnl && *cp == '\n') {
1122 (void) putc('#', strm);
1123 }
1124 }
1125
1126 return (ferror(strm));
1127 }
1128
1129 /*
1130 * These wrappers around lowlevel functions provide consistent error checking
1131 * and warnings.
1132 */
1133 static int
pg_get_prop(scf_propertygroup_t * pg,const char * propname,scf_property_t * prop)1134 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1135 {
1136 if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1137 return (0);
1138
1139 if (scf_error() != SCF_ERROR_NOT_FOUND)
1140 scfdie();
1141
1142 if (g_verbose) {
1143 ssize_t len;
1144 char *fmri;
1145
1146 len = scf_pg_to_fmri(pg, NULL, 0);
1147 if (len < 0)
1148 scfdie();
1149
1150 fmri = safe_malloc(len + 1);
1151
1152 if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1153 scfdie();
1154
1155 warn(gettext("Expected property %s of property group %s is "
1156 "missing.\n"), propname, fmri);
1157
1158 free(fmri);
1159 }
1160
1161 return (-1);
1162 }
1163
1164 static int
prop_check_type(scf_property_t * prop,scf_type_t ty)1165 prop_check_type(scf_property_t *prop, scf_type_t ty)
1166 {
1167 scf_type_t pty;
1168
1169 if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1170 scfdie();
1171
1172 if (ty == pty)
1173 return (0);
1174
1175 if (g_verbose) {
1176 ssize_t len;
1177 char *fmri;
1178 const char *tystr;
1179
1180 len = scf_property_to_fmri(prop, NULL, 0);
1181 if (len < 0)
1182 scfdie();
1183
1184 fmri = safe_malloc(len + 1);
1185
1186 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1187 scfdie();
1188
1189 tystr = scf_type_to_string(ty);
1190 if (tystr == NULL)
1191 tystr = "?";
1192
1193 warn(gettext("Property %s is not of expected type %s.\n"),
1194 fmri, tystr);
1195
1196 free(fmri);
1197 }
1198
1199 return (-1);
1200 }
1201
1202 static int
prop_get_val(scf_property_t * prop,scf_value_t * val)1203 prop_get_val(scf_property_t *prop, scf_value_t *val)
1204 {
1205 scf_error_t err;
1206
1207 if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1208 return (0);
1209
1210 err = scf_error();
1211
1212 if (err != SCF_ERROR_NOT_FOUND &&
1213 err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1214 err != SCF_ERROR_PERMISSION_DENIED)
1215 scfdie();
1216
1217 if (g_verbose) {
1218 ssize_t len;
1219 char *fmri, *emsg;
1220
1221 len = scf_property_to_fmri(prop, NULL, 0);
1222 if (len < 0)
1223 scfdie();
1224
1225 fmri = safe_malloc(len + 1);
1226
1227 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1228 scfdie();
1229
1230 if (err == SCF_ERROR_NOT_FOUND)
1231 emsg = gettext("Property %s has no values; expected "
1232 "one.\n");
1233 else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1234 emsg = gettext("Property %s has multiple values; "
1235 "expected one.\n");
1236 else
1237 emsg = gettext("No permission to read property %s.\n");
1238
1239 warn(emsg, fmri);
1240
1241 free(fmri);
1242 }
1243
1244 return (-1);
1245 }
1246
1247
1248 static boolean_t
snaplevel_is_instance(const scf_snaplevel_t * level)1249 snaplevel_is_instance(const scf_snaplevel_t *level)
1250 {
1251 if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1252 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1253 scfdie();
1254 return (0);
1255 } else {
1256 return (1);
1257 }
1258 }
1259
1260 /*
1261 * Decode FMRI into a service or instance, and put the result in *ep. If
1262 * memory cannot be allocated, return SCF_ERROR_NO_MEMORY. If the FMRI is
1263 * invalid, return SCF_ERROR_INVALID_ARGUMENT. If the FMRI does not specify
1264 * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED. If the entity cannot be
1265 * found, return SCF_ERROR_NOT_FOUND. Otherwise return SCF_ERROR_NONE, point
1266 * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1267 * whether *ep is a service.
1268 */
1269 static scf_error_t
fmri_to_entity(scf_handle_t * h,const char * fmri,void ** ep,int * isservice)1270 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1271 {
1272 char *fmri_copy;
1273 const char *sstr, *istr, *pgstr;
1274 scf_service_t *svc;
1275 scf_instance_t *inst;
1276
1277 fmri_copy = strdup(fmri);
1278 if (fmri_copy == NULL)
1279 return (SCF_ERROR_NO_MEMORY);
1280
1281 if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1282 SCF_SUCCESS) {
1283 free(fmri_copy);
1284 return (SCF_ERROR_INVALID_ARGUMENT);
1285 }
1286
1287 free(fmri_copy);
1288
1289 if (sstr == NULL || pgstr != NULL)
1290 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1291
1292 if (istr == NULL) {
1293 svc = scf_service_create(h);
1294 if (svc == NULL)
1295 return (SCF_ERROR_NO_MEMORY);
1296
1297 if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1298 SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1299 if (scf_error() != SCF_ERROR_NOT_FOUND)
1300 scfdie();
1301
1302 return (SCF_ERROR_NOT_FOUND);
1303 }
1304
1305 *ep = svc;
1306 *isservice = 1;
1307 } else {
1308 inst = scf_instance_create(h);
1309 if (inst == NULL)
1310 return (SCF_ERROR_NO_MEMORY);
1311
1312 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1313 NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1314 if (scf_error() != SCF_ERROR_NOT_FOUND)
1315 scfdie();
1316
1317 return (SCF_ERROR_NOT_FOUND);
1318 }
1319
1320 *ep = inst;
1321 *isservice = 0;
1322 }
1323
1324 return (SCF_ERROR_NONE);
1325 }
1326
1327 /*
1328 * Create the entity named by fmri. Place a pointer to its libscf handle in
1329 * *ep, and set or clear *isservicep if it is a service or an instance.
1330 * Returns
1331 * SCF_ERROR_NONE - success
1332 * SCF_ERROR_NO_MEMORY - scf_*_create() failed
1333 * SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1334 * SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1335 * SCF_ERROR_NOT_FOUND - no such scope
1336 * SCF_ERROR_PERMISSION_DENIED
1337 * SCF_ERROR_BACKEND_READONLY
1338 * SCF_ERROR_BACKEND_ACCESS
1339 */
1340 static scf_error_t
create_entity(scf_handle_t * h,const char * fmri,void ** ep,int * isservicep)1341 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1342 {
1343 char *fmri_copy;
1344 const char *scstr, *sstr, *istr, *pgstr;
1345 scf_scope_t *scope = NULL;
1346 scf_service_t *svc = NULL;
1347 scf_instance_t *inst = NULL;
1348 scf_error_t scfe;
1349
1350 fmri_copy = safe_strdup(fmri);
1351
1352 if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1353 0) {
1354 free(fmri_copy);
1355 return (SCF_ERROR_INVALID_ARGUMENT);
1356 }
1357
1358 if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1359 free(fmri_copy);
1360 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1361 }
1362
1363 *ep = NULL;
1364
1365 if ((scope = scf_scope_create(h)) == NULL ||
1366 (svc = scf_service_create(h)) == NULL ||
1367 (inst = scf_instance_create(h)) == NULL) {
1368 scfe = SCF_ERROR_NO_MEMORY;
1369 goto out;
1370 }
1371
1372 get_scope:
1373 if (scf_handle_get_scope(h, scstr, scope) != 0) {
1374 switch (scf_error()) {
1375 case SCF_ERROR_CONNECTION_BROKEN:
1376 scfdie();
1377 /* NOTREACHED */
1378
1379 case SCF_ERROR_NOT_FOUND:
1380 scfe = SCF_ERROR_NOT_FOUND;
1381 goto out;
1382
1383 case SCF_ERROR_HANDLE_MISMATCH:
1384 case SCF_ERROR_NOT_BOUND:
1385 case SCF_ERROR_INVALID_ARGUMENT:
1386 default:
1387 bad_error("scf_handle_get_scope", scf_error());
1388 }
1389 }
1390
1391 get_svc:
1392 if (scf_scope_get_service(scope, sstr, svc) != 0) {
1393 switch (scf_error()) {
1394 case SCF_ERROR_CONNECTION_BROKEN:
1395 scfdie();
1396 /* NOTREACHED */
1397
1398 case SCF_ERROR_DELETED:
1399 goto get_scope;
1400
1401 case SCF_ERROR_NOT_FOUND:
1402 break;
1403
1404 case SCF_ERROR_HANDLE_MISMATCH:
1405 case SCF_ERROR_INVALID_ARGUMENT:
1406 case SCF_ERROR_NOT_BOUND:
1407 case SCF_ERROR_NOT_SET:
1408 default:
1409 bad_error("scf_scope_get_service", scf_error());
1410 }
1411
1412 if (scf_scope_add_service(scope, sstr, svc) != 0) {
1413 switch (scf_error()) {
1414 case SCF_ERROR_CONNECTION_BROKEN:
1415 scfdie();
1416 /* NOTREACHED */
1417
1418 case SCF_ERROR_DELETED:
1419 goto get_scope;
1420
1421 case SCF_ERROR_PERMISSION_DENIED:
1422 case SCF_ERROR_BACKEND_READONLY:
1423 case SCF_ERROR_BACKEND_ACCESS:
1424 scfe = scf_error();
1425 goto out;
1426
1427 case SCF_ERROR_HANDLE_MISMATCH:
1428 case SCF_ERROR_INVALID_ARGUMENT:
1429 case SCF_ERROR_NOT_BOUND:
1430 case SCF_ERROR_NOT_SET:
1431 default:
1432 bad_error("scf_scope_get_service", scf_error());
1433 }
1434 }
1435 }
1436
1437 if (istr == NULL) {
1438 scfe = SCF_ERROR_NONE;
1439 *ep = svc;
1440 *isservicep = 1;
1441 goto out;
1442 }
1443
1444 get_inst:
1445 if (scf_service_get_instance(svc, istr, inst) != 0) {
1446 switch (scf_error()) {
1447 case SCF_ERROR_CONNECTION_BROKEN:
1448 scfdie();
1449 /* NOTREACHED */
1450
1451 case SCF_ERROR_DELETED:
1452 goto get_svc;
1453
1454 case SCF_ERROR_NOT_FOUND:
1455 break;
1456
1457 case SCF_ERROR_HANDLE_MISMATCH:
1458 case SCF_ERROR_INVALID_ARGUMENT:
1459 case SCF_ERROR_NOT_BOUND:
1460 case SCF_ERROR_NOT_SET:
1461 default:
1462 bad_error("scf_service_get_instance", scf_error());
1463 }
1464
1465 if (scf_service_add_instance(svc, istr, inst) != 0) {
1466 switch (scf_error()) {
1467 case SCF_ERROR_CONNECTION_BROKEN:
1468 scfdie();
1469 /* NOTREACHED */
1470
1471 case SCF_ERROR_DELETED:
1472 goto get_svc;
1473
1474 case SCF_ERROR_PERMISSION_DENIED:
1475 case SCF_ERROR_BACKEND_READONLY:
1476 case SCF_ERROR_BACKEND_ACCESS:
1477 scfe = scf_error();
1478 goto out;
1479
1480 case SCF_ERROR_HANDLE_MISMATCH:
1481 case SCF_ERROR_INVALID_ARGUMENT:
1482 case SCF_ERROR_NOT_BOUND:
1483 case SCF_ERROR_NOT_SET:
1484 default:
1485 bad_error("scf_service_add_instance",
1486 scf_error());
1487 }
1488 }
1489 }
1490
1491 scfe = SCF_ERROR_NONE;
1492 *ep = inst;
1493 *isservicep = 0;
1494
1495 out:
1496 if (*ep != inst)
1497 scf_instance_destroy(inst);
1498 if (*ep != svc)
1499 scf_service_destroy(svc);
1500 scf_scope_destroy(scope);
1501 free(fmri_copy);
1502 return (scfe);
1503 }
1504
1505 /*
1506 * Create or update a snapshot of inst. snap is a required scratch object.
1507 *
1508 * Returns
1509 * 0 - success
1510 * ECONNABORTED - repository connection broken
1511 * EPERM - permission denied
1512 * ENOSPC - configd is out of resources
1513 * ECANCELED - inst was deleted
1514 * -1 - unknown libscf error (message printed)
1515 */
1516 static int
take_snap(scf_instance_t * inst,const char * name,scf_snapshot_t * snap)1517 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1518 {
1519 again:
1520 if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1521 if (_scf_snapshot_take_attach(inst, snap) != 0) {
1522 switch (scf_error()) {
1523 case SCF_ERROR_CONNECTION_BROKEN:
1524 case SCF_ERROR_PERMISSION_DENIED:
1525 case SCF_ERROR_NO_RESOURCES:
1526 return (scferror2errno(scf_error()));
1527
1528 case SCF_ERROR_NOT_SET:
1529 case SCF_ERROR_INVALID_ARGUMENT:
1530 default:
1531 bad_error("_scf_snapshot_take_attach",
1532 scf_error());
1533 }
1534 }
1535 } else {
1536 switch (scf_error()) {
1537 case SCF_ERROR_NOT_FOUND:
1538 break;
1539
1540 case SCF_ERROR_DELETED:
1541 case SCF_ERROR_CONNECTION_BROKEN:
1542 return (scferror2errno(scf_error()));
1543
1544 case SCF_ERROR_HANDLE_MISMATCH:
1545 case SCF_ERROR_NOT_BOUND:
1546 case SCF_ERROR_INVALID_ARGUMENT:
1547 case SCF_ERROR_NOT_SET:
1548 default:
1549 bad_error("scf_instance_get_snapshot", scf_error());
1550 }
1551
1552 if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1553 switch (scf_error()) {
1554 case SCF_ERROR_EXISTS:
1555 goto again;
1556
1557 case SCF_ERROR_CONNECTION_BROKEN:
1558 case SCF_ERROR_NO_RESOURCES:
1559 case SCF_ERROR_PERMISSION_DENIED:
1560 return (scferror2errno(scf_error()));
1561
1562 default:
1563 scfwarn();
1564 return (-1);
1565
1566 case SCF_ERROR_NOT_SET:
1567 case SCF_ERROR_INTERNAL:
1568 case SCF_ERROR_INVALID_ARGUMENT:
1569 case SCF_ERROR_HANDLE_MISMATCH:
1570 bad_error("_scf_snapshot_take_new",
1571 scf_error());
1572 }
1573 }
1574 }
1575
1576 return (0);
1577 }
1578
1579 static int
refresh_running_snapshot(void * entity)1580 refresh_running_snapshot(void *entity)
1581 {
1582 scf_snapshot_t *snap;
1583 int r;
1584
1585 if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1586 scfdie();
1587 r = take_snap(entity, snap_running, snap);
1588 scf_snapshot_destroy(snap);
1589
1590 return (r);
1591 }
1592
1593 /*
1594 * Refresh entity. If isservice is zero, take entity to be an scf_instance_t *.
1595 * Otherwise take entity to be an scf_service_t * and refresh all of its child
1596 * instances. fmri is used for messages. inst, iter, and name_buf are used
1597 * for scratch space. Returns
1598 * 0 - success
1599 * ECONNABORTED - repository connection broken
1600 * ECANCELED - entity was deleted
1601 * EACCES - backend denied access
1602 * EPERM - permission denied
1603 * ENOSPC - repository server out of resources
1604 * -1 - _smf_refresh_instance_i() failed. scf_error() should be set.
1605 */
1606 static int
refresh_entity(int isservice,void * entity,const char * fmri,scf_instance_t * inst,scf_iter_t * iter,char * name_buf)1607 refresh_entity(int isservice, void *entity, const char *fmri,
1608 scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1609 {
1610 scf_error_t scfe;
1611 int r;
1612
1613 if (!isservice) {
1614 /*
1615 * Let restarter handles refreshing and making new running
1616 * snapshot only if operating on a live repository and not
1617 * running in early import.
1618 */
1619 if (est->sc_repo_filename == NULL &&
1620 est->sc_repo_doorname == NULL &&
1621 est->sc_in_emi == 0) {
1622 if (_smf_refresh_instance_i(entity) == 0) {
1623 if (g_verbose)
1624 warn(gettext("Refreshed %s.\n"), fmri);
1625 return (0);
1626 }
1627
1628 switch (scf_error()) {
1629 case SCF_ERROR_BACKEND_ACCESS:
1630 return (EACCES);
1631
1632 case SCF_ERROR_PERMISSION_DENIED:
1633 return (EPERM);
1634
1635 default:
1636 return (-1);
1637 }
1638 } else {
1639 r = refresh_running_snapshot(entity);
1640 switch (r) {
1641 case 0:
1642 break;
1643
1644 case ECONNABORTED:
1645 case ECANCELED:
1646 case EPERM:
1647 case ENOSPC:
1648 break;
1649
1650 default:
1651 bad_error("refresh_running_snapshot",
1652 scf_error());
1653 }
1654
1655 return (r);
1656 }
1657 }
1658
1659 if (scf_iter_service_instances(iter, entity) != 0) {
1660 switch (scf_error()) {
1661 case SCF_ERROR_CONNECTION_BROKEN:
1662 return (ECONNABORTED);
1663
1664 case SCF_ERROR_DELETED:
1665 return (ECANCELED);
1666
1667 case SCF_ERROR_HANDLE_MISMATCH:
1668 case SCF_ERROR_NOT_BOUND:
1669 case SCF_ERROR_NOT_SET:
1670 default:
1671 bad_error("scf_iter_service_instances", scf_error());
1672 }
1673 }
1674
1675 for (;;) {
1676 r = scf_iter_next_instance(iter, inst);
1677 if (r == 0)
1678 break;
1679 if (r != 1) {
1680 switch (scf_error()) {
1681 case SCF_ERROR_CONNECTION_BROKEN:
1682 return (ECONNABORTED);
1683
1684 case SCF_ERROR_DELETED:
1685 return (ECANCELED);
1686
1687 case SCF_ERROR_HANDLE_MISMATCH:
1688 case SCF_ERROR_NOT_BOUND:
1689 case SCF_ERROR_NOT_SET:
1690 case SCF_ERROR_INVALID_ARGUMENT:
1691 default:
1692 bad_error("scf_iter_next_instance",
1693 scf_error());
1694 }
1695 }
1696
1697 /*
1698 * Similarly, just take a new running snapshot if operating on
1699 * a non-live repository or running during early import.
1700 */
1701 if (est->sc_repo_filename != NULL ||
1702 est->sc_repo_doorname != NULL ||
1703 est->sc_in_emi == 1) {
1704 r = refresh_running_snapshot(inst);
1705 switch (r) {
1706 case 0:
1707 continue;
1708
1709 case ECONNABORTED:
1710 case ECANCELED:
1711 case EPERM:
1712 case ENOSPC:
1713 break;
1714 default:
1715 bad_error("refresh_running_snapshot",
1716 scf_error());
1717 }
1718
1719 return (r);
1720
1721 }
1722
1723 if (_smf_refresh_instance_i(inst) == 0) {
1724 if (g_verbose) {
1725 if (scf_instance_get_name(inst, name_buf,
1726 max_scf_name_len + 1) < 0)
1727 (void) strcpy(name_buf, "?");
1728
1729 warn(gettext("Refreshed %s:%s.\n"),
1730 fmri, name_buf);
1731 }
1732 } else {
1733 if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1734 g_verbose) {
1735 scfe = scf_error();
1736
1737 if (scf_instance_to_fmri(inst, name_buf,
1738 max_scf_name_len + 1) < 0)
1739 (void) strcpy(name_buf, "?");
1740
1741 warn(gettext(
1742 "Refresh of %s:%s failed: %s.\n"), fmri,
1743 name_buf, scf_strerror(scfe));
1744 }
1745 }
1746 }
1747
1748 return (0);
1749 }
1750
1751 static void
private_refresh(void)1752 private_refresh(void)
1753 {
1754 scf_instance_t *pinst = NULL;
1755 scf_iter_t *piter = NULL;
1756 ssize_t fmrilen;
1757 size_t bufsz;
1758 char *fmribuf;
1759 void *ent;
1760 int issvc;
1761 int r;
1762
1763 if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1764 return;
1765
1766 assert(cur_svc != NULL);
1767
1768 bufsz = max_scf_fmri_len + 1;
1769 fmribuf = safe_malloc(bufsz);
1770 if (cur_inst) {
1771 issvc = 0;
1772 ent = cur_inst;
1773 fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1774 } else {
1775 issvc = 1;
1776 ent = cur_svc;
1777 fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1778 if ((pinst = scf_instance_create(g_hndl)) == NULL)
1779 scfdie();
1780
1781 if ((piter = scf_iter_create(g_hndl)) == NULL)
1782 scfdie();
1783 }
1784 if (fmrilen < 0) {
1785 free(fmribuf);
1786 if (scf_error() != SCF_ERROR_DELETED)
1787 scfdie();
1788
1789 warn(emsg_deleted);
1790 return;
1791 }
1792 assert(fmrilen < bufsz);
1793
1794 r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1795 switch (r) {
1796 case 0:
1797 break;
1798
1799 case ECONNABORTED:
1800 warn(gettext("Could not refresh %s "
1801 "(repository connection broken).\n"), fmribuf);
1802 break;
1803
1804 case ECANCELED:
1805 warn(emsg_deleted);
1806 break;
1807
1808 case EPERM:
1809 warn(gettext("Could not refresh %s "
1810 "(permission denied).\n"), fmribuf);
1811 break;
1812
1813 case ENOSPC:
1814 warn(gettext("Could not refresh %s "
1815 "(repository server out of resources).\n"),
1816 fmribuf);
1817 break;
1818
1819 case EACCES:
1820 default:
1821 bad_error("refresh_entity", scf_error());
1822 }
1823
1824 if (issvc) {
1825 scf_instance_destroy(pinst);
1826 scf_iter_destroy(piter);
1827 }
1828
1829 free(fmribuf);
1830 }
1831
1832
1833 static int
stash_scferror_err(scf_callback_t * cbp,scf_error_t err)1834 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1835 {
1836 cbp->sc_err = scferror2errno(err);
1837 return (UU_WALK_ERROR);
1838 }
1839
1840 static int
stash_scferror(scf_callback_t * cbp)1841 stash_scferror(scf_callback_t *cbp)
1842 {
1843 return (stash_scferror_err(cbp, scf_error()));
1844 }
1845
1846 static int select_inst(const char *);
1847 static int select_svc(const char *);
1848
1849 /*
1850 * Take a property that does not have a type and check to see if a type
1851 * exists or can be gleened from the current data. Set the type.
1852 *
1853 * Check the current level (instance) and then check the higher level
1854 * (service). This could be the case for adding a new property to
1855 * the instance that's going to "override" a service level property.
1856 *
1857 * For a property :
1858 * 1. Take the type from an existing property
1859 * 2. Take the type from a template entry
1860 *
1861 * If the type can not be found, then leave the type as is, and let the import
1862 * report the problem of the missing type.
1863 */
1864 static int
find_current_prop_type(void * p,void * g)1865 find_current_prop_type(void *p, void *g)
1866 {
1867 property_t *prop = p;
1868 scf_callback_t *lcb = g;
1869 pgroup_t *pg = NULL;
1870
1871 const char *fmri = NULL;
1872 char *lfmri = NULL;
1873 char *cur_selection = NULL;
1874
1875 scf_propertygroup_t *sc_pg = NULL;
1876 scf_property_t *sc_prop = NULL;
1877 scf_pg_tmpl_t *t_pg = NULL;
1878 scf_prop_tmpl_t *t_prop = NULL;
1879 scf_type_t prop_type;
1880
1881 value_t *vp;
1882 int issvc = lcb->sc_service;
1883 int r = UU_WALK_ERROR;
1884
1885 if (prop->sc_value_type != SCF_TYPE_INVALID)
1886 return (UU_WALK_NEXT);
1887
1888 t_prop = scf_tmpl_prop_create(g_hndl);
1889 sc_prop = scf_property_create(g_hndl);
1890 if (sc_prop == NULL || t_prop == NULL) {
1891 warn(gettext("Unable to create the property to attempt and "
1892 "find a missing type.\n"));
1893
1894 scf_property_destroy(sc_prop);
1895 scf_tmpl_prop_destroy(t_prop);
1896
1897 return (UU_WALK_ERROR);
1898 }
1899
1900 if (lcb->sc_flags == 1) {
1901 pg = lcb->sc_parent;
1902 issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT);
1903 fmri = pg->sc_parent->sc_fmri;
1904 retry_pg:
1905 if (cur_svc && cur_selection == NULL) {
1906 cur_selection = safe_malloc(max_scf_fmri_len + 1);
1907 lscf_get_selection_str(cur_selection,
1908 max_scf_fmri_len + 1);
1909
1910 if (strcmp(cur_selection, fmri) != 0) {
1911 lscf_select(fmri);
1912 } else {
1913 free(cur_selection);
1914 cur_selection = NULL;
1915 }
1916 } else {
1917 lscf_select(fmri);
1918 }
1919
1920 if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) {
1921 warn(gettext("Unable to create property group to "
1922 "find a missing property type.\n"));
1923
1924 goto out;
1925 }
1926
1927 if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) {
1928 /*
1929 * If this is the sc_pg from the parent
1930 * let the caller clean up the sc_pg,
1931 * and just throw it away in this case.
1932 */
1933 if (sc_pg != lcb->sc_parent)
1934 scf_pg_destroy(sc_pg);
1935
1936 sc_pg = NULL;
1937 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1938 warn(gettext("Unable to create template "
1939 "property group to find a property "
1940 "type.\n"));
1941
1942 goto out;
1943 }
1944
1945 if (scf_tmpl_get_by_pg_name(fmri, NULL,
1946 pg->sc_pgroup_name, NULL, t_pg,
1947 SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) {
1948 /*
1949 * if instance get service and jump back
1950 */
1951 scf_tmpl_pg_destroy(t_pg);
1952 t_pg = NULL;
1953 if (issvc == 0) {
1954 entity_t *e = pg->sc_parent->sc_parent;
1955
1956 fmri = e->sc_fmri;
1957 issvc = 1;
1958 goto retry_pg;
1959 } else {
1960 goto out;
1961 }
1962 }
1963 }
1964 } else {
1965 sc_pg = lcb->sc_parent;
1966 }
1967
1968 /*
1969 * Attempt to get the type from an existing property. If the property
1970 * cannot be found then attempt to get the type from a template entry
1971 * for the property.
1972 *
1973 * Finally, if at the instance level look at the service level.
1974 */
1975 if (sc_pg != NULL &&
1976 pg_get_prop(sc_pg, prop->sc_property_name,
1977 sc_prop) == SCF_SUCCESS &&
1978 scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) {
1979 prop->sc_value_type = prop_type;
1980
1981 /*
1982 * Found a type, update the value types and validate
1983 * the actual value against this type.
1984 */
1985 for (vp = uu_list_first(prop->sc_property_values);
1986 vp != NULL;
1987 vp = uu_list_next(prop->sc_property_values, vp)) {
1988 vp->sc_type = prop->sc_value_type;
1989 lxml_store_value(vp, 0, NULL);
1990 }
1991
1992 r = UU_WALK_NEXT;
1993 goto out;
1994 }
1995
1996 /*
1997 * If we get here with t_pg set to NULL then we had to have
1998 * gotten an sc_pg but that sc_pg did not have the property
1999 * we are looking for. So if the t_pg is not null look up
2000 * the template entry for the property.
2001 *
2002 * If the t_pg is null then need to attempt to get a matching
2003 * template entry for the sc_pg, and see if there is a property
2004 * entry for that template entry.
2005 */
2006 do_tmpl :
2007 if (t_pg != NULL &&
2008 scf_tmpl_get_by_prop(t_pg, prop->sc_property_name,
2009 t_prop, 0) == SCF_SUCCESS) {
2010 if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) {
2011 prop->sc_value_type = prop_type;
2012
2013 /*
2014 * Found a type, update the value types and validate
2015 * the actual value against this type.
2016 */
2017 for (vp = uu_list_first(prop->sc_property_values);
2018 vp != NULL;
2019 vp = uu_list_next(prop->sc_property_values, vp)) {
2020 vp->sc_type = prop->sc_value_type;
2021 lxml_store_value(vp, 0, NULL);
2022 }
2023
2024 r = UU_WALK_NEXT;
2025 goto out;
2026 }
2027 } else {
2028 if (t_pg == NULL && sc_pg) {
2029 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
2030 warn(gettext("Unable to create template "
2031 "property group to find a property "
2032 "type.\n"));
2033
2034 goto out;
2035 }
2036
2037 if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
2038 scf_tmpl_pg_destroy(t_pg);
2039 t_pg = NULL;
2040 } else {
2041 goto do_tmpl;
2042 }
2043 }
2044 }
2045
2046 if (issvc == 0) {
2047 scf_instance_t *i;
2048 scf_service_t *s;
2049
2050 issvc = 1;
2051 if (lcb->sc_flags == 1) {
2052 entity_t *e = pg->sc_parent->sc_parent;
2053
2054 fmri = e->sc_fmri;
2055 goto retry_pg;
2056 }
2057
2058 /*
2059 * because lcb->sc_flags was not set then this means
2060 * the pg was not used and can be used here.
2061 */
2062 if ((pg = internal_pgroup_new()) == NULL) {
2063 warn(gettext("Could not create internal property group "
2064 "to find a missing type."));
2065
2066 goto out;
2067 }
2068
2069 pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1);
2070 if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name,
2071 max_scf_name_len + 1) < 0)
2072 goto out;
2073
2074 i = scf_instance_create(g_hndl);
2075 s = scf_service_create(g_hndl);
2076 if (i == NULL || s == NULL ||
2077 scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) {
2078 warn(gettext("Could not get a service for the instance "
2079 "to find a missing type."));
2080
2081 goto out;
2082 }
2083
2084 /*
2085 * Check to see truly at the instance level.
2086 */
2087 lfmri = safe_malloc(max_scf_fmri_len + 1);
2088 if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
2089 scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0)
2090 goto out;
2091 else
2092 fmri = (const char *)lfmri;
2093
2094 goto retry_pg;
2095 }
2096
2097 out :
2098 if (sc_pg != lcb->sc_parent) {
2099 scf_pg_destroy(sc_pg);
2100 }
2101
2102 /*
2103 * If this is true then the pg was allocated
2104 * here, and the name was set so need to free
2105 * the name and the pg.
2106 */
2107 if (pg != NULL && pg != lcb->sc_parent) {
2108 free((char *)pg->sc_pgroup_name);
2109 internal_pgroup_free(pg);
2110 }
2111
2112 if (cur_selection) {
2113 lscf_select(cur_selection);
2114 free(cur_selection);
2115 }
2116
2117 scf_tmpl_pg_destroy(t_pg);
2118 scf_tmpl_prop_destroy(t_prop);
2119 scf_property_destroy(sc_prop);
2120
2121 if (r != UU_WALK_NEXT)
2122 warn(gettext("Could not find property type for \"%s\" "
2123 "from \"%s\"\n"), prop->sc_property_name,
2124 fmri != NULL ? fmri : lcb->sc_source_fmri);
2125
2126 free(lfmri);
2127
2128 return (r);
2129 }
2130
2131 /*
2132 * Take a property group that does not have a type and check to see if a type
2133 * exists or can be gleened from the current data. Set the type.
2134 *
2135 * Check the current level (instance) and then check the higher level
2136 * (service). This could be the case for adding a new property to
2137 * the instance that's going to "override" a service level property.
2138 *
2139 * For a property group
2140 * 1. Take the type from an existing property group
2141 * 2. Take the type from a template entry
2142 *
2143 * If the type can not be found, then leave the type as is, and let the import
2144 * report the problem of the missing type.
2145 */
2146 static int
find_current_pg_type(void * p,void * sori)2147 find_current_pg_type(void *p, void *sori)
2148 {
2149 entity_t *si = sori;
2150 pgroup_t *pg = p;
2151
2152 const char *ofmri, *fmri;
2153 char *cur_selection = NULL;
2154 char *pg_type = NULL;
2155
2156 scf_propertygroup_t *sc_pg = NULL;
2157 scf_pg_tmpl_t *t_pg = NULL;
2158
2159 int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2160 int r = UU_WALK_ERROR;
2161
2162 ofmri = fmri = si->sc_fmri;
2163 if (pg->sc_pgroup_type != NULL) {
2164 r = UU_WALK_NEXT;
2165
2166 goto out;
2167 }
2168
2169 sc_pg = scf_pg_create(g_hndl);
2170 if (sc_pg == NULL) {
2171 warn(gettext("Unable to create property group to attempt "
2172 "and find a missing type.\n"));
2173
2174 return (UU_WALK_ERROR);
2175 }
2176
2177 /*
2178 * Using get_pg() requires that the cur_svc/cur_inst be
2179 * via lscf_select. Need to preserve the current selection
2180 * if going to use lscf_select() to set up the cur_svc/cur_inst
2181 */
2182 if (cur_svc) {
2183 cur_selection = safe_malloc(max_scf_fmri_len + 1);
2184 lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1);
2185 }
2186
2187 /*
2188 * If the property group exists get the type, and set
2189 * the pgroup_t type of that type.
2190 *
2191 * If not the check for a template pg_pattern entry
2192 * and take the type from that.
2193 */
2194 retry_svc:
2195 lscf_select(fmri);
2196
2197 if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) {
2198 pg_type = safe_malloc(max_scf_pg_type_len + 1);
2199 if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type,
2200 max_scf_pg_type_len + 1) != -1) {
2201 pg->sc_pgroup_type = pg_type;
2202
2203 r = UU_WALK_NEXT;
2204 goto out;
2205 } else {
2206 free(pg_type);
2207 }
2208 } else {
2209 if ((t_pg == NULL) &&
2210 (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
2211 goto out;
2212
2213 if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name,
2214 NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS &&
2215 scf_tmpl_pg_type(t_pg, &pg_type) != -1) {
2216 pg->sc_pgroup_type = pg_type;
2217
2218 r = UU_WALK_NEXT;
2219 goto out;
2220 }
2221 }
2222
2223 /*
2224 * If type is not found at the instance level then attempt to
2225 * find the type at the service level.
2226 */
2227 if (!issvc) {
2228 si = si->sc_parent;
2229 fmri = si->sc_fmri;
2230 issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2231 goto retry_svc;
2232 }
2233
2234 out :
2235 if (cur_selection) {
2236 lscf_select(cur_selection);
2237 free(cur_selection);
2238 }
2239
2240 /*
2241 * Now walk the properties of the property group to make sure that
2242 * all properties have the correct type and values are valid for
2243 * those types.
2244 */
2245 if (r == UU_WALK_NEXT) {
2246 scf_callback_t cb;
2247
2248 cb.sc_service = issvc;
2249 cb.sc_source_fmri = ofmri;
2250 if (sc_pg != NULL) {
2251 cb.sc_parent = sc_pg;
2252 cb.sc_flags = 0;
2253 } else {
2254 cb.sc_parent = pg;
2255 cb.sc_flags = 1;
2256 }
2257
2258 if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type,
2259 &cb, UU_DEFAULT) != 0) {
2260 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2261 bad_error("uu_list_walk", uu_error());
2262
2263 r = UU_WALK_ERROR;
2264 }
2265 } else {
2266 warn(gettext("Could not find property group type for "
2267 "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri);
2268 }
2269
2270 scf_tmpl_pg_destroy(t_pg);
2271 scf_pg_destroy(sc_pg);
2272
2273 return (r);
2274 }
2275
2276 /*
2277 * Import. These functions import a bundle into the repository.
2278 */
2279
2280 /*
2281 * Add a transaction entry to lcbdata->sc_trans for this property_t. Uses
2282 * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata. On success,
2283 * returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
2284 * lcbdata->sc_err to
2285 * ENOMEM - out of memory
2286 * ECONNABORTED - repository connection broken
2287 * ECANCELED - sc_trans's property group was deleted
2288 * EINVAL - p's name is invalid (error printed)
2289 * - p has an invalid value (error printed)
2290 */
2291 static int
lscf_property_import(void * v,void * pvt)2292 lscf_property_import(void *v, void *pvt)
2293 {
2294 property_t *p = v;
2295 scf_callback_t *lcbdata = pvt;
2296 value_t *vp;
2297 scf_transaction_t *trans = lcbdata->sc_trans;
2298 scf_transaction_entry_t *entr;
2299 scf_value_t *val;
2300 scf_type_t tp;
2301
2302 if ((lcbdata->sc_flags & SCI_NOENABLED ||
2303 lcbdata->sc_flags & SCI_DELAYENABLE) &&
2304 strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
2305 lcbdata->sc_enable = p;
2306 return (UU_WALK_NEXT);
2307 }
2308
2309 entr = scf_entry_create(lcbdata->sc_handle);
2310 if (entr == NULL) {
2311 switch (scf_error()) {
2312 case SCF_ERROR_NO_MEMORY:
2313 return (stash_scferror(lcbdata));
2314
2315 case SCF_ERROR_INVALID_ARGUMENT:
2316 default:
2317 bad_error("scf_entry_create", scf_error());
2318 }
2319 }
2320
2321 tp = p->sc_value_type;
2322
2323 if (scf_transaction_property_new(trans, entr,
2324 p->sc_property_name, tp) != 0) {
2325 switch (scf_error()) {
2326 case SCF_ERROR_INVALID_ARGUMENT:
2327 semerr(emsg_invalid_prop_name, p->sc_property_name);
2328 scf_entry_destroy(entr);
2329 return (stash_scferror(lcbdata));
2330
2331 case SCF_ERROR_EXISTS:
2332 break;
2333
2334 case SCF_ERROR_DELETED:
2335 case SCF_ERROR_CONNECTION_BROKEN:
2336 scf_entry_destroy(entr);
2337 return (stash_scferror(lcbdata));
2338
2339 case SCF_ERROR_NOT_BOUND:
2340 case SCF_ERROR_HANDLE_MISMATCH:
2341 case SCF_ERROR_NOT_SET:
2342 default:
2343 bad_error("scf_transaction_property_new", scf_error());
2344 }
2345
2346 if (scf_transaction_property_change_type(trans, entr,
2347 p->sc_property_name, tp) != 0) {
2348 switch (scf_error()) {
2349 case SCF_ERROR_DELETED:
2350 case SCF_ERROR_CONNECTION_BROKEN:
2351 scf_entry_destroy(entr);
2352 return (stash_scferror(lcbdata));
2353
2354 case SCF_ERROR_INVALID_ARGUMENT:
2355 semerr(emsg_invalid_prop_name,
2356 p->sc_property_name);
2357 scf_entry_destroy(entr);
2358 return (stash_scferror(lcbdata));
2359
2360 case SCF_ERROR_NOT_FOUND:
2361 case SCF_ERROR_NOT_SET:
2362 case SCF_ERROR_HANDLE_MISMATCH:
2363 case SCF_ERROR_NOT_BOUND:
2364 default:
2365 bad_error(
2366 "scf_transaction_property_change_type",
2367 scf_error());
2368 }
2369 }
2370 }
2371
2372 for (vp = uu_list_first(p->sc_property_values);
2373 vp != NULL;
2374 vp = uu_list_next(p->sc_property_values, vp)) {
2375 val = scf_value_create(g_hndl);
2376 if (val == NULL) {
2377 switch (scf_error()) {
2378 case SCF_ERROR_NO_MEMORY:
2379 return (stash_scferror(lcbdata));
2380
2381 case SCF_ERROR_INVALID_ARGUMENT:
2382 default:
2383 bad_error("scf_value_create", scf_error());
2384 }
2385 }
2386
2387 switch (tp) {
2388 case SCF_TYPE_BOOLEAN:
2389 scf_value_set_boolean(val, vp->sc_u.sc_count);
2390 break;
2391 case SCF_TYPE_COUNT:
2392 scf_value_set_count(val, vp->sc_u.sc_count);
2393 break;
2394 case SCF_TYPE_INTEGER:
2395 scf_value_set_integer(val, vp->sc_u.sc_integer);
2396 break;
2397 default:
2398 assert(vp->sc_u.sc_string != NULL);
2399 if (scf_value_set_from_string(val, tp,
2400 vp->sc_u.sc_string) != 0) {
2401 if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
2402 bad_error("scf_value_set_from_string",
2403 scf_error());
2404
2405 warn(gettext("Value \"%s\" is not a valid "
2406 "%s.\n"), vp->sc_u.sc_string,
2407 scf_type_to_string(tp));
2408 scf_value_destroy(val);
2409 return (stash_scferror(lcbdata));
2410 }
2411 break;
2412 }
2413
2414 if (scf_entry_add_value(entr, val) != 0)
2415 bad_error("scf_entry_add_value", scf_error());
2416 }
2417
2418 return (UU_WALK_NEXT);
2419 }
2420
2421 /*
2422 * Import a pgroup_t into the repository. Uses sc_handle, sc_parent,
2423 * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2424 * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2425 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
2426 * lcbdata->sc_err to
2427 * ECONNABORTED - repository connection broken
2428 * ENOMEM - out of memory
2429 * ENOSPC - svc.configd is out of resources
2430 * ECANCELED - sc_parent was deleted
2431 * EPERM - could not create property group (permission denied) (error printed)
2432 * - could not modify property group (permission denied) (error printed)
2433 * - could not delete property group (permission denied) (error printed)
2434 * EROFS - could not create property group (repository is read-only)
2435 * - could not delete property group (repository is read-only)
2436 * EACCES - could not create property group (backend access denied)
2437 * - could not delete property group (backend access denied)
2438 * EEXIST - could not create property group (already exists)
2439 * EINVAL - invalid property group name (error printed)
2440 * - invalid property name (error printed)
2441 * - invalid value (error printed)
2442 * EBUSY - new property group deleted (error printed)
2443 * - new property group changed (error printed)
2444 * - property group added (error printed)
2445 * - property group deleted (error printed)
2446 */
2447 static int
entity_pgroup_import(void * v,void * pvt)2448 entity_pgroup_import(void *v, void *pvt)
2449 {
2450 pgroup_t *p = v;
2451 scf_callback_t cbdata;
2452 scf_callback_t *lcbdata = pvt;
2453 void *ent = lcbdata->sc_parent;
2454 int issvc = lcbdata->sc_service;
2455 int r;
2456
2457 const char * const pg_changed = gettext("%s changed unexpectedly "
2458 "(new property group \"%s\" changed).\n");
2459
2460 /* Never import deleted property groups. */
2461 if (p->sc_pgroup_delete) {
2462 if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY &&
2463 entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) {
2464 goto delete_pg;
2465 }
2466 return (UU_WALK_NEXT);
2467 }
2468
2469 if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
2470 strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
2471 lcbdata->sc_general = p;
2472 return (UU_WALK_NEXT);
2473 }
2474
2475 add_pg:
2476 if (issvc)
2477 r = scf_service_add_pg(ent, p->sc_pgroup_name,
2478 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2479 else
2480 r = scf_instance_add_pg(ent, p->sc_pgroup_name,
2481 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2482 if (r != 0) {
2483 switch (scf_error()) {
2484 case SCF_ERROR_DELETED:
2485 case SCF_ERROR_CONNECTION_BROKEN:
2486 case SCF_ERROR_BACKEND_READONLY:
2487 case SCF_ERROR_BACKEND_ACCESS:
2488 case SCF_ERROR_NO_RESOURCES:
2489 return (stash_scferror(lcbdata));
2490
2491 case SCF_ERROR_EXISTS:
2492 if (lcbdata->sc_flags & SCI_FORCE)
2493 break;
2494 return (stash_scferror(lcbdata));
2495
2496 case SCF_ERROR_INVALID_ARGUMENT:
2497 warn(emsg_fmri_invalid_pg_name_type,
2498 lcbdata->sc_source_fmri,
2499 p->sc_pgroup_name, p->sc_pgroup_type);
2500 return (stash_scferror(lcbdata));
2501
2502 case SCF_ERROR_PERMISSION_DENIED:
2503 warn(emsg_pg_add_perm, p->sc_pgroup_name,
2504 lcbdata->sc_target_fmri);
2505 return (stash_scferror(lcbdata));
2506
2507 case SCF_ERROR_NOT_BOUND:
2508 case SCF_ERROR_HANDLE_MISMATCH:
2509 case SCF_ERROR_NOT_SET:
2510 default:
2511 bad_error("scf_service_add_pg", scf_error());
2512 }
2513
2514 if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2515 switch (scf_error()) {
2516 case SCF_ERROR_CONNECTION_BROKEN:
2517 case SCF_ERROR_DELETED:
2518 return (stash_scferror(lcbdata));
2519
2520 case SCF_ERROR_INVALID_ARGUMENT:
2521 warn(emsg_fmri_invalid_pg_name,
2522 lcbdata->sc_source_fmri,
2523 p->sc_pgroup_name);
2524 return (stash_scferror(lcbdata));
2525
2526 case SCF_ERROR_NOT_FOUND:
2527 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2528 p->sc_pgroup_name);
2529 lcbdata->sc_err = EBUSY;
2530 return (UU_WALK_ERROR);
2531
2532 case SCF_ERROR_NOT_BOUND:
2533 case SCF_ERROR_HANDLE_MISMATCH:
2534 case SCF_ERROR_NOT_SET:
2535 default:
2536 bad_error("entity_get_pg", scf_error());
2537 }
2538 }
2539
2540 if (lcbdata->sc_flags & SCI_KEEP)
2541 goto props;
2542
2543 delete_pg:
2544 if (scf_pg_delete(imp_pg) != 0) {
2545 switch (scf_error()) {
2546 case SCF_ERROR_DELETED:
2547 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2548 p->sc_pgroup_name);
2549 lcbdata->sc_err = EBUSY;
2550 return (UU_WALK_ERROR);
2551
2552 case SCF_ERROR_PERMISSION_DENIED:
2553 warn(emsg_pg_del_perm, p->sc_pgroup_name,
2554 lcbdata->sc_target_fmri);
2555 return (stash_scferror(lcbdata));
2556
2557 case SCF_ERROR_BACKEND_READONLY:
2558 case SCF_ERROR_BACKEND_ACCESS:
2559 case SCF_ERROR_CONNECTION_BROKEN:
2560 return (stash_scferror(lcbdata));
2561
2562 case SCF_ERROR_NOT_SET:
2563 default:
2564 bad_error("scf_pg_delete", scf_error());
2565 }
2566 }
2567
2568 if (p->sc_pgroup_delete)
2569 return (UU_WALK_NEXT);
2570
2571 goto add_pg;
2572 }
2573
2574 props:
2575
2576 /*
2577 * Add properties to property group, if any.
2578 */
2579 cbdata.sc_handle = lcbdata->sc_handle;
2580 cbdata.sc_parent = imp_pg;
2581 cbdata.sc_flags = lcbdata->sc_flags;
2582 cbdata.sc_trans = imp_tx;
2583 cbdata.sc_enable = NULL;
2584
2585 if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2586 switch (scf_error()) {
2587 case SCF_ERROR_BACKEND_ACCESS:
2588 case SCF_ERROR_BACKEND_READONLY:
2589 case SCF_ERROR_CONNECTION_BROKEN:
2590 return (stash_scferror(lcbdata));
2591
2592 case SCF_ERROR_DELETED:
2593 warn(pg_changed, lcbdata->sc_target_fmri,
2594 p->sc_pgroup_name);
2595 lcbdata->sc_err = EBUSY;
2596 return (UU_WALK_ERROR);
2597
2598 case SCF_ERROR_PERMISSION_DENIED:
2599 warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2600 lcbdata->sc_target_fmri);
2601 return (stash_scferror(lcbdata));
2602
2603 case SCF_ERROR_NOT_BOUND:
2604 case SCF_ERROR_NOT_SET:
2605 case SCF_ERROR_IN_USE:
2606 case SCF_ERROR_HANDLE_MISMATCH:
2607 default:
2608 bad_error("scf_transaction_start", scf_error());
2609 }
2610 }
2611
2612 if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2613 UU_DEFAULT) != 0) {
2614 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2615 bad_error("uu_list_walk", uu_error());
2616 scf_transaction_reset(imp_tx);
2617
2618 lcbdata->sc_err = cbdata.sc_err;
2619 if (cbdata.sc_err == ECANCELED) {
2620 warn(pg_changed, lcbdata->sc_target_fmri,
2621 p->sc_pgroup_name);
2622 lcbdata->sc_err = EBUSY;
2623 }
2624 return (UU_WALK_ERROR);
2625 }
2626
2627 if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2628 cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2629
2630 /*
2631 * take the snapshot running snapshot then
2632 * import the stored general/enable property
2633 */
2634 r = take_snap(ent, snap_running, imp_rsnap);
2635 switch (r) {
2636 case 0:
2637 break;
2638
2639 case ECONNABORTED:
2640 warn(gettext("Could not take %s snapshot on import "
2641 "(repository connection broken).\n"),
2642 snap_running);
2643 lcbdata->sc_err = r;
2644 return (UU_WALK_ERROR);
2645 case ECANCELED:
2646 warn(emsg_deleted);
2647 lcbdata->sc_err = r;
2648 return (UU_WALK_ERROR);
2649
2650 case EPERM:
2651 warn(gettext("Could not take %s snapshot "
2652 "(permission denied).\n"), snap_running);
2653 lcbdata->sc_err = r;
2654 return (UU_WALK_ERROR);
2655
2656 case ENOSPC:
2657 warn(gettext("Could not take %s snapshot"
2658 "(repository server out of resources).\n"),
2659 snap_running);
2660 lcbdata->sc_err = r;
2661 return (UU_WALK_ERROR);
2662
2663 default:
2664 bad_error("take_snap", r);
2665 }
2666
2667 r = lscf_property_import(cbdata.sc_enable, &cbdata);
2668 if (r != UU_WALK_NEXT) {
2669 if (r != UU_WALK_ERROR)
2670 bad_error("lscf_property_import", r);
2671 return (EINVAL);
2672 }
2673 }
2674
2675 r = scf_transaction_commit(imp_tx);
2676 switch (r) {
2677 case 1:
2678 r = UU_WALK_NEXT;
2679 break;
2680
2681 case 0:
2682 warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2683 lcbdata->sc_err = EBUSY;
2684 r = UU_WALK_ERROR;
2685 break;
2686
2687 case -1:
2688 switch (scf_error()) {
2689 case SCF_ERROR_BACKEND_READONLY:
2690 case SCF_ERROR_BACKEND_ACCESS:
2691 case SCF_ERROR_CONNECTION_BROKEN:
2692 case SCF_ERROR_NO_RESOURCES:
2693 r = stash_scferror(lcbdata);
2694 break;
2695
2696 case SCF_ERROR_DELETED:
2697 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2698 p->sc_pgroup_name);
2699 lcbdata->sc_err = EBUSY;
2700 r = UU_WALK_ERROR;
2701 break;
2702
2703 case SCF_ERROR_PERMISSION_DENIED:
2704 warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2705 lcbdata->sc_target_fmri);
2706 r = stash_scferror(lcbdata);
2707 break;
2708
2709 case SCF_ERROR_NOT_SET:
2710 case SCF_ERROR_INVALID_ARGUMENT:
2711 case SCF_ERROR_NOT_BOUND:
2712 default:
2713 bad_error("scf_transaction_commit", scf_error());
2714 }
2715 break;
2716
2717 default:
2718 bad_error("scf_transaction_commit", r);
2719 }
2720
2721 scf_transaction_destroy_children(imp_tx);
2722
2723 return (r);
2724 }
2725
2726 /*
2727 * Returns
2728 * 0 - success
2729 * ECONNABORTED - repository connection broken
2730 * ENOMEM - out of memory
2731 * ENOSPC - svc.configd is out of resources
2732 * ECANCELED - inst was deleted
2733 * EPERM - could not create property group (permission denied) (error printed)
2734 * - could not modify property group (permission denied) (error printed)
2735 * EROFS - could not create property group (repository is read-only)
2736 * EACCES - could not create property group (backend access denied)
2737 * EEXIST - could not create property group (already exists)
2738 * EINVAL - invalid property group name (error printed)
2739 * - invalid property name (error printed)
2740 * - invalid value (error printed)
2741 * EBUSY - new property group changed (error printed)
2742 */
2743 static int
lscf_import_service_pgs(scf_service_t * svc,const char * target_fmri,const entity_t * isvc,int flags)2744 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2745 const entity_t *isvc, int flags)
2746 {
2747 scf_callback_t cbdata;
2748
2749 cbdata.sc_handle = scf_service_handle(svc);
2750 cbdata.sc_parent = svc;
2751 cbdata.sc_service = 1;
2752 cbdata.sc_general = 0;
2753 cbdata.sc_enable = 0;
2754 cbdata.sc_flags = flags;
2755 cbdata.sc_source_fmri = isvc->sc_fmri;
2756 cbdata.sc_target_fmri = target_fmri;
2757
2758 /*
2759 * If the op is set, then add the flag to the callback
2760 * flags for later use.
2761 */
2762 if (isvc->sc_op != SVCCFG_OP_NONE) {
2763 switch (isvc->sc_op) {
2764 case SVCCFG_OP_IMPORT :
2765 cbdata.sc_flags |= SCI_OP_IMPORT;
2766 break;
2767 case SVCCFG_OP_APPLY :
2768 cbdata.sc_flags |= SCI_OP_APPLY;
2769 break;
2770 case SVCCFG_OP_RESTORE :
2771 cbdata.sc_flags |= SCI_OP_RESTORE;
2772 break;
2773 default :
2774 uu_die(gettext("lscf_import_service_pgs : "
2775 "Unknown op stored in the service entity\n"));
2776
2777 }
2778 }
2779
2780 if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2781 UU_DEFAULT) != 0) {
2782 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2783 bad_error("uu_list_walk", uu_error());
2784
2785 return (cbdata.sc_err);
2786 }
2787
2788 return (0);
2789 }
2790
2791 /*
2792 * Returns
2793 * 0 - success
2794 * ECONNABORTED - repository connection broken
2795 * ENOMEM - out of memory
2796 * ENOSPC - svc.configd is out of resources
2797 * ECANCELED - inst was deleted
2798 * EPERM - could not create property group (permission denied) (error printed)
2799 * - could not modify property group (permission denied) (error printed)
2800 * EROFS - could not create property group (repository is read-only)
2801 * EACCES - could not create property group (backend access denied)
2802 * EEXIST - could not create property group (already exists)
2803 * EINVAL - invalid property group name (error printed)
2804 * - invalid property name (error printed)
2805 * - invalid value (error printed)
2806 * EBUSY - new property group changed (error printed)
2807 */
2808 static int
lscf_import_instance_pgs(scf_instance_t * inst,const char * target_fmri,const entity_t * iinst,int flags)2809 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2810 const entity_t *iinst, int flags)
2811 {
2812 scf_callback_t cbdata;
2813
2814 cbdata.sc_handle = scf_instance_handle(inst);
2815 cbdata.sc_parent = inst;
2816 cbdata.sc_service = 0;
2817 cbdata.sc_general = NULL;
2818 cbdata.sc_enable = NULL;
2819 cbdata.sc_flags = flags;
2820 cbdata.sc_source_fmri = iinst->sc_fmri;
2821 cbdata.sc_target_fmri = target_fmri;
2822
2823 /*
2824 * If the op is set, then add the flag to the callback
2825 * flags for later use.
2826 */
2827 if (iinst->sc_op != SVCCFG_OP_NONE) {
2828 switch (iinst->sc_op) {
2829 case SVCCFG_OP_IMPORT :
2830 cbdata.sc_flags |= SCI_OP_IMPORT;
2831 break;
2832 case SVCCFG_OP_APPLY :
2833 cbdata.sc_flags |= SCI_OP_APPLY;
2834 break;
2835 case SVCCFG_OP_RESTORE :
2836 cbdata.sc_flags |= SCI_OP_RESTORE;
2837 break;
2838 default :
2839 uu_die(gettext("lscf_import_instance_pgs : "
2840 "Unknown op stored in the instance entity\n"));
2841 }
2842 }
2843
2844 if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2845 UU_DEFAULT) != 0) {
2846 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2847 bad_error("uu_list_walk", uu_error());
2848
2849 return (cbdata.sc_err);
2850 }
2851
2852 if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2853 cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2854 /*
2855 * If importing with the SCI_NOENABLED flag then
2856 * skip the delay, but if not then add the delay
2857 * of the enable property.
2858 */
2859 if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2860 cbdata.sc_flags |= SCI_DELAYENABLE;
2861 }
2862
2863 if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2864 != UU_WALK_NEXT)
2865 return (cbdata.sc_err);
2866 }
2867
2868 return (0);
2869 }
2870
2871 /*
2872 * Report the reasons why we can't upgrade pg2 to pg1.
2873 */
2874 static void
report_pg_diffs(const pgroup_t * pg1,const pgroup_t * pg2,const char * fmri,int new)2875 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2876 int new)
2877 {
2878 property_t *p1, *p2;
2879
2880 assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2881
2882 if (!pg_attrs_equal(pg1, pg2, fmri, new))
2883 return;
2884
2885 for (p1 = uu_list_first(pg1->sc_pgroup_props);
2886 p1 != NULL;
2887 p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2888 p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2889 if (p2 != NULL) {
2890 (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2891 new);
2892 continue;
2893 }
2894
2895 if (new)
2896 warn(gettext("Conflict upgrading %s (new property "
2897 "group \"%s\" is missing property \"%s\").\n"),
2898 fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2899 else
2900 warn(gettext("Conflict upgrading %s (property "
2901 "\"%s/%s\" is missing).\n"), fmri,
2902 pg1->sc_pgroup_name, p1->sc_property_name);
2903 }
2904
2905 /*
2906 * Since pg1 should be from the manifest, any properties in pg2 which
2907 * aren't in pg1 shouldn't be reported as conflicts.
2908 */
2909 }
2910
2911 /*
2912 * Add transaction entries to tx which will upgrade cur's pg according to old
2913 * & new.
2914 *
2915 * Returns
2916 * 0 - success
2917 * EINVAL - new has a property with an invalid name or value (message emitted)
2918 * ENOMEM - out of memory
2919 */
2920 static int
add_upgrade_entries(scf_transaction_t * tx,pgroup_t * old,pgroup_t * new,pgroup_t * cur,int speak,const char * fmri)2921 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2922 pgroup_t *cur, int speak, const char *fmri)
2923 {
2924 property_t *p, *new_p, *cur_p;
2925 scf_transaction_entry_t *e;
2926 int r;
2927 int is_general;
2928 int is_protected;
2929
2930 if (uu_list_walk(new->sc_pgroup_props, clear_int,
2931 (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2932 bad_error("uu_list_walk", uu_error());
2933
2934 is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2935
2936 for (p = uu_list_first(old->sc_pgroup_props);
2937 p != NULL;
2938 p = uu_list_next(old->sc_pgroup_props, p)) {
2939 /* p is a property in the old property group. */
2940
2941 /* Protect live properties. */
2942 is_protected = 0;
2943 if (is_general) {
2944 if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2945 0 ||
2946 strcmp(p->sc_property_name,
2947 SCF_PROPERTY_RESTARTER) == 0)
2948 is_protected = 1;
2949 }
2950
2951 /* Look for the same property in the new properties. */
2952 new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2953 if (new_p != NULL) {
2954 new_p->sc_seen = 1;
2955
2956 /*
2957 * If the new property is the same as the old, don't do
2958 * anything (leave any user customizations).
2959 */
2960 if (prop_equal(p, new_p, NULL, NULL, 0))
2961 continue;
2962
2963 if (new_p->sc_property_override)
2964 goto upgrade;
2965 }
2966
2967 cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2968 if (cur_p == NULL) {
2969 /*
2970 * p has been deleted from the repository. If we were
2971 * going to delete it anyway, do nothing. Otherwise
2972 * report a conflict.
2973 */
2974 if (new_p == NULL)
2975 continue;
2976
2977 if (is_protected)
2978 continue;
2979
2980 warn(gettext("Conflict upgrading %s "
2981 "(property \"%s/%s\" is missing).\n"), fmri,
2982 old->sc_pgroup_name, p->sc_property_name);
2983 continue;
2984 }
2985
2986 if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2987 /*
2988 * Conflict. Don't warn if the property is already the
2989 * way we want it, though.
2990 */
2991 if (is_protected)
2992 continue;
2993
2994 if (new_p == NULL)
2995 (void) prop_equal(p, cur_p, fmri,
2996 old->sc_pgroup_name, 0);
2997 else
2998 (void) prop_equal(cur_p, new_p, fmri,
2999 old->sc_pgroup_name, 0);
3000 continue;
3001 }
3002
3003 if (is_protected) {
3004 if (speak)
3005 warn(gettext("%s: Refusing to upgrade "
3006 "\"%s/%s\" (live property).\n"), fmri,
3007 old->sc_pgroup_name, p->sc_property_name);
3008 continue;
3009 }
3010
3011 upgrade:
3012 /* p hasn't been customized in the repository. Upgrade it. */
3013 if (new_p == NULL) {
3014 /* p was deleted. Delete from cur if unchanged. */
3015 if (speak)
3016 warn(gettext(
3017 "%s: Deleting property \"%s/%s\".\n"),
3018 fmri, old->sc_pgroup_name,
3019 p->sc_property_name);
3020
3021 e = scf_entry_create(g_hndl);
3022 if (e == NULL)
3023 return (ENOMEM);
3024
3025 if (scf_transaction_property_delete(tx, e,
3026 p->sc_property_name) != 0) {
3027 switch (scf_error()) {
3028 case SCF_ERROR_DELETED:
3029 scf_entry_destroy(e);
3030 return (ECANCELED);
3031
3032 case SCF_ERROR_CONNECTION_BROKEN:
3033 scf_entry_destroy(e);
3034 return (ECONNABORTED);
3035
3036 case SCF_ERROR_NOT_FOUND:
3037 /*
3038 * This can happen if cur is from the
3039 * running snapshot (and it differs
3040 * from the live properties).
3041 */
3042 scf_entry_destroy(e);
3043 break;
3044
3045 case SCF_ERROR_HANDLE_MISMATCH:
3046 case SCF_ERROR_NOT_BOUND:
3047 case SCF_ERROR_NOT_SET:
3048 case SCF_ERROR_INVALID_ARGUMENT:
3049 default:
3050 bad_error(
3051 "scf_transaction_property_delete",
3052 scf_error());
3053 }
3054 }
3055 } else {
3056 scf_callback_t ctx;
3057
3058 if (speak)
3059 warn(gettext(
3060 "%s: Upgrading property \"%s/%s\".\n"),
3061 fmri, old->sc_pgroup_name,
3062 p->sc_property_name);
3063
3064 ctx.sc_handle = g_hndl;
3065 ctx.sc_trans = tx;
3066 ctx.sc_flags = 0;
3067
3068 r = lscf_property_import(new_p, &ctx);
3069 if (r != UU_WALK_NEXT) {
3070 if (r != UU_WALK_ERROR)
3071 bad_error("lscf_property_import", r);
3072 return (EINVAL);
3073 }
3074 }
3075 }
3076
3077 /* Go over the properties which were added. */
3078 for (new_p = uu_list_first(new->sc_pgroup_props);
3079 new_p != NULL;
3080 new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
3081 if (new_p->sc_seen)
3082 continue;
3083
3084 /* This is a new property. */
3085 cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
3086 if (cur_p == NULL) {
3087 scf_callback_t ctx;
3088
3089 ctx.sc_handle = g_hndl;
3090 ctx.sc_trans = tx;
3091 ctx.sc_flags = 0;
3092
3093 r = lscf_property_import(new_p, &ctx);
3094 if (r != UU_WALK_NEXT) {
3095 if (r != UU_WALK_ERROR)
3096 bad_error("lscf_property_import", r);
3097 return (EINVAL);
3098 }
3099 continue;
3100 }
3101
3102 /*
3103 * Report a conflict if the new property differs from the
3104 * current one. Unless it's general/enabled, since that's
3105 * never in the last-import snapshot.
3106 */
3107 if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
3108 0 &&
3109 strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
3110 continue;
3111
3112 (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
3113 }
3114
3115 return (0);
3116 }
3117
3118 /*
3119 * Upgrade pg according to old & new.
3120 *
3121 * Returns
3122 * 0 - success
3123 * ECONNABORTED - repository connection broken
3124 * ENOMEM - out of memory
3125 * ENOSPC - svc.configd is out of resources
3126 * ECANCELED - pg was deleted
3127 * EPERM - couldn't modify pg (permission denied)
3128 * EROFS - couldn't modify pg (backend read-only)
3129 * EACCES - couldn't modify pg (backend access denied)
3130 * EINVAL - new has a property with invalid name or value (error printed)
3131 * EBUSY - pg changed unexpectedly
3132 */
3133 static int
upgrade_pg(scf_propertygroup_t * pg,pgroup_t * cur,pgroup_t * old,pgroup_t * new,int speak,const char * fmri)3134 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
3135 pgroup_t *new, int speak, const char *fmri)
3136 {
3137 int r;
3138
3139 if (scf_transaction_start(imp_tx, pg) != 0) {
3140 switch (scf_error()) {
3141 case SCF_ERROR_CONNECTION_BROKEN:
3142 case SCF_ERROR_DELETED:
3143 case SCF_ERROR_PERMISSION_DENIED:
3144 case SCF_ERROR_BACKEND_READONLY:
3145 case SCF_ERROR_BACKEND_ACCESS:
3146 return (scferror2errno(scf_error()));
3147
3148 case SCF_ERROR_HANDLE_MISMATCH:
3149 case SCF_ERROR_IN_USE:
3150 case SCF_ERROR_NOT_BOUND:
3151 case SCF_ERROR_NOT_SET:
3152 default:
3153 bad_error("scf_transaction_start", scf_error());
3154 }
3155 }
3156
3157 r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
3158 switch (r) {
3159 case 0:
3160 break;
3161
3162 case EINVAL:
3163 case ENOMEM:
3164 scf_transaction_destroy_children(imp_tx);
3165 return (r);
3166
3167 default:
3168 bad_error("add_upgrade_entries", r);
3169 }
3170
3171 r = scf_transaction_commit(imp_tx);
3172
3173 scf_transaction_destroy_children(imp_tx);
3174
3175 switch (r) {
3176 case 1:
3177 break;
3178
3179 case 0:
3180 return (EBUSY);
3181
3182 case -1:
3183 switch (scf_error()) {
3184 case SCF_ERROR_CONNECTION_BROKEN:
3185 case SCF_ERROR_NO_RESOURCES:
3186 case SCF_ERROR_PERMISSION_DENIED:
3187 case SCF_ERROR_BACKEND_READONLY:
3188 case SCF_ERROR_BACKEND_ACCESS:
3189 case SCF_ERROR_DELETED:
3190 return (scferror2errno(scf_error()));
3191
3192 case SCF_ERROR_NOT_BOUND:
3193 case SCF_ERROR_INVALID_ARGUMENT:
3194 case SCF_ERROR_NOT_SET:
3195 default:
3196 bad_error("scf_transaction_commit", scf_error());
3197 }
3198
3199 default:
3200 bad_error("scf_transaction_commit", r);
3201 }
3202
3203 return (0);
3204 }
3205
3206 /*
3207 * Compares two entity FMRIs. Returns
3208 *
3209 * 1 - equal
3210 * 0 - not equal
3211 * -1 - f1 is invalid or not an entity
3212 * -2 - f2 is invalid or not an entity
3213 */
3214 static int
fmri_equal(const char * f1,const char * f2)3215 fmri_equal(const char *f1, const char *f2)
3216 {
3217 int r;
3218 const char *s1, *i1, *pg1;
3219 const char *s2, *i2, *pg2;
3220
3221 if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3222 return (-1);
3223 if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
3224 return (-1);
3225
3226 if (s1 == NULL || pg1 != NULL)
3227 return (-1);
3228
3229 if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3230 return (-2);
3231 if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
3232 return (-2);
3233
3234 if (s2 == NULL || pg2 != NULL)
3235 return (-2);
3236
3237 r = strcmp(s1, s2);
3238 if (r != 0)
3239 return (0);
3240
3241 if (i1 == NULL && i2 == NULL)
3242 return (1);
3243
3244 if (i1 == NULL || i2 == NULL)
3245 return (0);
3246
3247 return (strcmp(i1, i2) == 0);
3248 }
3249
3250 /*
3251 * Import a dependent by creating a dependency property group in the dependent
3252 * entity. If lcbdata->sc_trans is set, assume it's been started on the
3253 * dependents pg, and add an entry to create a new property for this
3254 * dependent. Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3255 *
3256 * On success, returns UU_WALK_NEXT. On error, returns UU_WALK_ERROR and sets
3257 * lcbdata->sc_err to
3258 * ECONNABORTED - repository connection broken
3259 * ENOMEM - out of memory
3260 * ENOSPC - configd is out of resources
3261 * EINVAL - target is invalid (error printed)
3262 * - target is not an entity (error printed)
3263 * - dependent has invalid name (error printed)
3264 * - invalid property name (error printed)
3265 * - invalid value (error printed)
3266 * - scope of target does not exist (error printed)
3267 * EPERM - couldn't create target (permission denied) (error printed)
3268 * - couldn't create dependency pg (permission denied) (error printed)
3269 * - couldn't modify dependency pg (permission denied) (error printed)
3270 * EROFS - couldn't create target (repository read-only)
3271 * - couldn't create dependency pg (repository read-only)
3272 * EACCES - couldn't create target (backend access denied)
3273 * - couldn't create dependency pg (backend access denied)
3274 * ECANCELED - sc_trans's pg was deleted
3275 * EALREADY - property for dependent already exists in sc_trans's pg
3276 * EEXIST - dependency pg already exists in target (error printed)
3277 * EBUSY - target deleted (error printed)
3278 * - property group changed during import (error printed)
3279 */
3280 static int
lscf_dependent_import(void * a1,void * pvt)3281 lscf_dependent_import(void *a1, void *pvt)
3282 {
3283 pgroup_t *pgrp = a1;
3284 scf_callback_t *lcbdata = pvt;
3285
3286 int isservice;
3287 int ret;
3288 scf_transaction_entry_t *e;
3289 scf_value_t *val;
3290 scf_callback_t dependent_cbdata;
3291 scf_error_t scfe;
3292
3293 /*
3294 * Decode the FMRI into dependent_cbdata->sc_parent. Do it here so if
3295 * it's invalid, we fail before modifying the repository.
3296 */
3297 scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3298 &dependent_cbdata.sc_parent, &isservice);
3299 switch (scfe) {
3300 case SCF_ERROR_NONE:
3301 break;
3302
3303 case SCF_ERROR_NO_MEMORY:
3304 return (stash_scferror_err(lcbdata, scfe));
3305
3306 case SCF_ERROR_INVALID_ARGUMENT:
3307 semerr(gettext("The FMRI for the \"%s\" dependent is "
3308 "invalid.\n"), pgrp->sc_pgroup_name);
3309 return (stash_scferror_err(lcbdata, scfe));
3310
3311 case SCF_ERROR_CONSTRAINT_VIOLATED:
3312 semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3313 "specifies neither a service nor an instance.\n"),
3314 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3315 return (stash_scferror_err(lcbdata, scfe));
3316
3317 case SCF_ERROR_NOT_FOUND:
3318 scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3319 &dependent_cbdata.sc_parent, &isservice);
3320 switch (scfe) {
3321 case SCF_ERROR_NONE:
3322 break;
3323
3324 case SCF_ERROR_NO_MEMORY:
3325 case SCF_ERROR_BACKEND_READONLY:
3326 case SCF_ERROR_BACKEND_ACCESS:
3327 return (stash_scferror_err(lcbdata, scfe));
3328
3329 case SCF_ERROR_NOT_FOUND:
3330 semerr(gettext("The scope in FMRI \"%s\" for the "
3331 "\"%s\" dependent does not exist.\n"),
3332 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3333 lcbdata->sc_err = EINVAL;
3334 return (UU_WALK_ERROR);
3335
3336 case SCF_ERROR_PERMISSION_DENIED:
3337 warn(gettext(
3338 "Could not create %s (permission denied).\n"),
3339 pgrp->sc_pgroup_fmri);
3340 return (stash_scferror_err(lcbdata, scfe));
3341
3342 case SCF_ERROR_INVALID_ARGUMENT:
3343 case SCF_ERROR_CONSTRAINT_VIOLATED:
3344 default:
3345 bad_error("create_entity", scfe);
3346 }
3347 break;
3348
3349 default:
3350 bad_error("fmri_to_entity", scfe);
3351 }
3352
3353 if (lcbdata->sc_trans != NULL) {
3354 e = scf_entry_create(lcbdata->sc_handle);
3355 if (e == NULL) {
3356 if (scf_error() != SCF_ERROR_NO_MEMORY)
3357 bad_error("scf_entry_create", scf_error());
3358
3359 entity_destroy(dependent_cbdata.sc_parent, isservice);
3360 return (stash_scferror(lcbdata));
3361 }
3362
3363 if (scf_transaction_property_new(lcbdata->sc_trans, e,
3364 pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
3365 switch (scf_error()) {
3366 case SCF_ERROR_INVALID_ARGUMENT:
3367 warn(gettext("Dependent of %s has invalid name "
3368 "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
3369 pgrp->sc_pgroup_name);
3370 /* FALLTHROUGH */
3371
3372 case SCF_ERROR_DELETED:
3373 case SCF_ERROR_CONNECTION_BROKEN:
3374 scf_entry_destroy(e);
3375 entity_destroy(dependent_cbdata.sc_parent,
3376 isservice);
3377 return (stash_scferror(lcbdata));
3378
3379 case SCF_ERROR_EXISTS:
3380 scf_entry_destroy(e);
3381 entity_destroy(dependent_cbdata.sc_parent,
3382 isservice);
3383 lcbdata->sc_err = EALREADY;
3384 return (UU_WALK_ERROR);
3385
3386 case SCF_ERROR_NOT_BOUND:
3387 case SCF_ERROR_HANDLE_MISMATCH:
3388 case SCF_ERROR_NOT_SET:
3389 default:
3390 bad_error("scf_transaction_property_new",
3391 scf_error());
3392 }
3393 }
3394
3395 val = scf_value_create(lcbdata->sc_handle);
3396 if (val == NULL) {
3397 if (scf_error() != SCF_ERROR_NO_MEMORY)
3398 bad_error("scf_value_create", scf_error());
3399
3400 entity_destroy(dependent_cbdata.sc_parent, isservice);
3401 return (stash_scferror(lcbdata));
3402 }
3403
3404 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
3405 pgrp->sc_pgroup_fmri) != 0)
3406 /* invalid should have been caught above */
3407 bad_error("scf_value_set_from_string", scf_error());
3408
3409 if (scf_entry_add_value(e, val) != 0)
3410 bad_error("scf_entry_add_value", scf_error());
3411 }
3412
3413 /* Add the property group to the target entity. */
3414
3415 dependent_cbdata.sc_handle = lcbdata->sc_handle;
3416 dependent_cbdata.sc_flags = lcbdata->sc_flags;
3417 dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
3418 dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
3419
3420 ret = entity_pgroup_import(pgrp, &dependent_cbdata);
3421
3422 entity_destroy(dependent_cbdata.sc_parent, isservice);
3423
3424 if (ret == UU_WALK_NEXT)
3425 return (ret);
3426
3427 if (ret != UU_WALK_ERROR)
3428 bad_error("entity_pgroup_import", ret);
3429
3430 switch (dependent_cbdata.sc_err) {
3431 case ECANCELED:
3432 warn(gettext("%s deleted unexpectedly.\n"),
3433 pgrp->sc_pgroup_fmri);
3434 lcbdata->sc_err = EBUSY;
3435 break;
3436
3437 case EEXIST:
3438 warn(gettext("Could not create \"%s\" dependency in %s "
3439 "(already exists).\n"), pgrp->sc_pgroup_name,
3440 pgrp->sc_pgroup_fmri);
3441 /* FALLTHROUGH */
3442
3443 default:
3444 lcbdata->sc_err = dependent_cbdata.sc_err;
3445 }
3446
3447 return (UU_WALK_ERROR);
3448 }
3449
3450 static int upgrade_dependent(const scf_property_t *, const entity_t *,
3451 const scf_snaplevel_t *, scf_transaction_t *);
3452 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
3453 const pgroup_t *);
3454
3455 /*
3456 * Upgrade uncustomized dependents of ent to those specified in ient. Read
3457 * the current dependent targets from running (the snaplevel of a running
3458 * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3459 * scf_instance_t * according to ient, otherwise). Draw the ancestral
3460 * dependent targets and dependency properties from li_dpts_pg (the
3461 * "dependents" property group in snpl) and snpl (the snaplevel which
3462 * corresponds to ent in a last-import snapshot). If li_dpts_pg is NULL, then
3463 * snpl doesn't have a "dependents" property group, and any dependents in ient
3464 * are new.
3465 *
3466 * Returns
3467 * 0 - success
3468 * ECONNABORTED - repository connection broken
3469 * ENOMEM - out of memory
3470 * ENOSPC - configd is out of resources
3471 * ECANCELED - ent was deleted
3472 * ENODEV - the entity containing li_dpts_pg was deleted
3473 * EPERM - could not modify dependents pg (permission denied) (error printed)
3474 * - couldn't upgrade dependent (permission denied) (error printed)
3475 * - couldn't create dependent (permission denied) (error printed)
3476 * EROFS - could not modify dependents pg (repository read-only)
3477 * - couldn't upgrade dependent (repository read-only)
3478 * - couldn't create dependent (repository read-only)
3479 * EACCES - could not modify dependents pg (backend access denied)
3480 * - could not upgrade dependent (backend access denied)
3481 * - could not create dependent (backend access denied)
3482 * EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3483 * - dependent target deleted (error printed)
3484 * - dependent pg changed (error printed)
3485 * EINVAL - new dependent is invalid (error printed)
3486 * EBADF - snpl is corrupt (error printed)
3487 * - snpl has corrupt pg (error printed)
3488 * - dependency pg in target is corrupt (error printed)
3489 * - target has corrupt snapshot (error printed)
3490 * EEXIST - dependency pg already existed in target service (error printed)
3491 */
3492 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)3493 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
3494 const scf_snaplevel_t *snpl, const entity_t *ient,
3495 const scf_snaplevel_t *running, void *ent)
3496 {
3497 pgroup_t *new_dpt_pgroup;
3498 scf_callback_t cbdata;
3499 int r, unseen, tx_started = 0;
3500 int have_cur_depts;
3501
3502 const char * const dependents = "dependents";
3503
3504 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3505
3506 if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
3507 /* Nothing to do. */
3508 return (0);
3509
3510 /* Fetch the current version of the "dependents" property group. */
3511 have_cur_depts = 1;
3512 if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
3513 switch (scf_error()) {
3514 case SCF_ERROR_NOT_FOUND:
3515 break;
3516
3517 case SCF_ERROR_DELETED:
3518 case SCF_ERROR_CONNECTION_BROKEN:
3519 return (scferror2errno(scf_error()));
3520
3521 case SCF_ERROR_NOT_SET:
3522 case SCF_ERROR_INVALID_ARGUMENT:
3523 case SCF_ERROR_HANDLE_MISMATCH:
3524 case SCF_ERROR_NOT_BOUND:
3525 default:
3526 bad_error("entity_get_pg", scf_error());
3527 }
3528
3529 have_cur_depts = 0;
3530 }
3531
3532 /* Fetch the running version of the "dependents" property group. */
3533 ud_run_dpts_pg_set = 0;
3534 if (running != NULL)
3535 r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
3536 else
3537 r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
3538 if (r == 0) {
3539 ud_run_dpts_pg_set = 1;
3540 } else {
3541 switch (scf_error()) {
3542 case SCF_ERROR_NOT_FOUND:
3543 break;
3544
3545 case SCF_ERROR_DELETED:
3546 case SCF_ERROR_CONNECTION_BROKEN:
3547 return (scferror2errno(scf_error()));
3548
3549 case SCF_ERROR_NOT_SET:
3550 case SCF_ERROR_INVALID_ARGUMENT:
3551 case SCF_ERROR_HANDLE_MISMATCH:
3552 case SCF_ERROR_NOT_BOUND:
3553 default:
3554 bad_error(running ? "scf_snaplevel_get_pg" :
3555 "entity_get_pg", scf_error());
3556 }
3557 }
3558
3559 /*
3560 * Clear the seen fields of the dependents, so we can tell which ones
3561 * are new.
3562 */
3563 if (uu_list_walk(ient->sc_dependents, clear_int,
3564 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3565 bad_error("uu_list_walk", uu_error());
3566
3567 if (li_dpts_pg != NULL) {
3568 /*
3569 * Each property in li_dpts_pg represents a dependent tag in
3570 * the old manifest. For each, call upgrade_dependent(),
3571 * which will change ud_cur_depts_pg or dependencies in other
3572 * services as appropriate. Note (a) that changes to
3573 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3574 * made en masse, and (b) it's ok if the entity doesn't have
3575 * a current version of the "dependents" property group,
3576 * because we'll just consider all dependents as customized
3577 * (by being deleted).
3578 */
3579
3580 if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3581 switch (scf_error()) {
3582 case SCF_ERROR_DELETED:
3583 return (ENODEV);
3584
3585 case SCF_ERROR_CONNECTION_BROKEN:
3586 return (ECONNABORTED);
3587
3588 case SCF_ERROR_HANDLE_MISMATCH:
3589 case SCF_ERROR_NOT_BOUND:
3590 case SCF_ERROR_NOT_SET:
3591 default:
3592 bad_error("scf_iter_pg_properties",
3593 scf_error());
3594 }
3595 }
3596
3597 if (have_cur_depts &&
3598 scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3599 switch (scf_error()) {
3600 case SCF_ERROR_BACKEND_ACCESS:
3601 case SCF_ERROR_BACKEND_READONLY:
3602 case SCF_ERROR_CONNECTION_BROKEN:
3603 return (scferror2errno(scf_error()));
3604
3605 case SCF_ERROR_DELETED:
3606 warn(emsg_pg_deleted, ient->sc_fmri,
3607 dependents);
3608 return (EBUSY);
3609
3610 case SCF_ERROR_PERMISSION_DENIED:
3611 warn(emsg_pg_mod_perm, dependents,
3612 ient->sc_fmri);
3613 return (scferror2errno(scf_error()));
3614
3615 case SCF_ERROR_HANDLE_MISMATCH:
3616 case SCF_ERROR_IN_USE:
3617 case SCF_ERROR_NOT_BOUND:
3618 case SCF_ERROR_NOT_SET:
3619 default:
3620 bad_error("scf_transaction_start", scf_error());
3621 }
3622 }
3623 tx_started = have_cur_depts;
3624
3625 for (;;) {
3626 r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3627 if (r == 0)
3628 break;
3629 if (r == 1) {
3630 r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3631 tx_started ? ud_tx : NULL);
3632 switch (r) {
3633 case 0:
3634 continue;
3635
3636 case ECONNABORTED:
3637 case ENOMEM:
3638 case ENOSPC:
3639 case EBADF:
3640 case EBUSY:
3641 case EINVAL:
3642 case EPERM:
3643 case EROFS:
3644 case EACCES:
3645 case EEXIST:
3646 break;
3647
3648 case ECANCELED:
3649 r = ENODEV;
3650 break;
3651
3652 default:
3653 bad_error("upgrade_dependent", r);
3654 }
3655
3656 if (tx_started)
3657 scf_transaction_destroy_children(ud_tx);
3658 return (r);
3659 }
3660 if (r != -1)
3661 bad_error("scf_iter_next_property", r);
3662
3663 switch (scf_error()) {
3664 case SCF_ERROR_DELETED:
3665 r = ENODEV;
3666 break;
3667
3668 case SCF_ERROR_CONNECTION_BROKEN:
3669 r = ECONNABORTED;
3670 break;
3671
3672 case SCF_ERROR_NOT_SET:
3673 case SCF_ERROR_INVALID_ARGUMENT:
3674 case SCF_ERROR_NOT_BOUND:
3675 case SCF_ERROR_HANDLE_MISMATCH:
3676 default:
3677 bad_error("scf_iter_next_property",
3678 scf_error());
3679 }
3680
3681 if (tx_started)
3682 scf_transaction_destroy_children(ud_tx);
3683 return (r);
3684 }
3685 }
3686
3687 /* import unseen dependents */
3688 unseen = 0;
3689 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3690 new_dpt_pgroup != NULL;
3691 new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3692 new_dpt_pgroup)) {
3693 if (!new_dpt_pgroup->sc_pgroup_seen) {
3694 unseen = 1;
3695 break;
3696 }
3697 }
3698
3699 /* If there are none, exit early. */
3700 if (unseen == 0)
3701 goto commit;
3702
3703 /* Set up for lscf_dependent_import() */
3704 cbdata.sc_handle = g_hndl;
3705 cbdata.sc_parent = ent;
3706 cbdata.sc_service = issvc;
3707 cbdata.sc_flags = 0;
3708
3709 if (!have_cur_depts) {
3710 /*
3711 * We have new dependents to import, so we need a "dependents"
3712 * property group.
3713 */
3714 if (issvc)
3715 r = scf_service_add_pg(ent, dependents,
3716 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3717 else
3718 r = scf_instance_add_pg(ent, dependents,
3719 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3720 if (r != 0) {
3721 switch (scf_error()) {
3722 case SCF_ERROR_DELETED:
3723 case SCF_ERROR_CONNECTION_BROKEN:
3724 case SCF_ERROR_BACKEND_READONLY:
3725 case SCF_ERROR_BACKEND_ACCESS:
3726 case SCF_ERROR_NO_RESOURCES:
3727 return (scferror2errno(scf_error()));
3728
3729 case SCF_ERROR_EXISTS:
3730 warn(emsg_pg_added, ient->sc_fmri, dependents);
3731 return (EBUSY);
3732
3733 case SCF_ERROR_PERMISSION_DENIED:
3734 warn(emsg_pg_add_perm, dependents,
3735 ient->sc_fmri);
3736 return (scferror2errno(scf_error()));
3737
3738 case SCF_ERROR_NOT_BOUND:
3739 case SCF_ERROR_HANDLE_MISMATCH:
3740 case SCF_ERROR_INVALID_ARGUMENT:
3741 case SCF_ERROR_NOT_SET:
3742 default:
3743 bad_error("scf_service_add_pg", scf_error());
3744 }
3745 }
3746 }
3747
3748 cbdata.sc_trans = ud_tx;
3749
3750 if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3751 switch (scf_error()) {
3752 case SCF_ERROR_CONNECTION_BROKEN:
3753 case SCF_ERROR_BACKEND_ACCESS:
3754 case SCF_ERROR_BACKEND_READONLY:
3755 return (scferror2errno(scf_error()));
3756
3757 case SCF_ERROR_DELETED:
3758 warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3759 return (EBUSY);
3760
3761 case SCF_ERROR_PERMISSION_DENIED:
3762 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3763 return (scferror2errno(scf_error()));
3764
3765 case SCF_ERROR_HANDLE_MISMATCH:
3766 case SCF_ERROR_IN_USE:
3767 case SCF_ERROR_NOT_BOUND:
3768 case SCF_ERROR_NOT_SET:
3769 default:
3770 bad_error("scf_transaction_start", scf_error());
3771 }
3772 }
3773 tx_started = 1;
3774
3775 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3776 new_dpt_pgroup != NULL;
3777 new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3778 new_dpt_pgroup)) {
3779 if (new_dpt_pgroup->sc_pgroup_seen)
3780 continue;
3781
3782 if (ud_run_dpts_pg_set) {
3783 /*
3784 * If the dependent is already there, then we have
3785 * a conflict.
3786 */
3787 if (scf_pg_get_property(ud_run_dpts_pg,
3788 new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3789 r = handle_dependent_conflict(ient, ud_prop,
3790 new_dpt_pgroup);
3791 switch (r) {
3792 case 0:
3793 continue;
3794
3795 case ECONNABORTED:
3796 case ENOMEM:
3797 case EBUSY:
3798 case EBADF:
3799 case EINVAL:
3800 scf_transaction_destroy_children(ud_tx);
3801 return (r);
3802
3803 default:
3804 bad_error("handle_dependent_conflict",
3805 r);
3806 }
3807 } else {
3808 switch (scf_error()) {
3809 case SCF_ERROR_NOT_FOUND:
3810 break;
3811
3812 case SCF_ERROR_INVALID_ARGUMENT:
3813 warn(emsg_fmri_invalid_pg_name,
3814 ient->sc_fmri,
3815 new_dpt_pgroup->sc_pgroup_name);
3816 scf_transaction_destroy_children(ud_tx);
3817 return (EINVAL);
3818
3819 case SCF_ERROR_DELETED:
3820 warn(emsg_pg_deleted, ient->sc_fmri,
3821 new_dpt_pgroup->sc_pgroup_name);
3822 scf_transaction_destroy_children(ud_tx);
3823 return (EBUSY);
3824
3825 case SCF_ERROR_CONNECTION_BROKEN:
3826 scf_transaction_destroy_children(ud_tx);
3827 return (ECONNABORTED);
3828
3829 case SCF_ERROR_NOT_BOUND:
3830 case SCF_ERROR_HANDLE_MISMATCH:
3831 case SCF_ERROR_NOT_SET:
3832 default:
3833 bad_error("scf_pg_get_property",
3834 scf_error());
3835 }
3836 }
3837 }
3838
3839 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3840 if (r != UU_WALK_NEXT) {
3841 if (r != UU_WALK_ERROR)
3842 bad_error("lscf_dependent_import", r);
3843
3844 if (cbdata.sc_err == EALREADY) {
3845 /* Collisions were handled preemptively. */
3846 bad_error("lscf_dependent_import",
3847 cbdata.sc_err);
3848 }
3849
3850 scf_transaction_destroy_children(ud_tx);
3851 return (cbdata.sc_err);
3852 }
3853 }
3854
3855 commit:
3856 if (!tx_started)
3857 return (0);
3858
3859 r = scf_transaction_commit(ud_tx);
3860
3861 scf_transaction_destroy_children(ud_tx);
3862
3863 switch (r) {
3864 case 1:
3865 return (0);
3866
3867 case 0:
3868 warn(emsg_pg_changed, ient->sc_fmri, dependents);
3869 return (EBUSY);
3870
3871 case -1:
3872 break;
3873
3874 default:
3875 bad_error("scf_transaction_commit", r);
3876 }
3877
3878 switch (scf_error()) {
3879 case SCF_ERROR_CONNECTION_BROKEN:
3880 case SCF_ERROR_BACKEND_READONLY:
3881 case SCF_ERROR_BACKEND_ACCESS:
3882 case SCF_ERROR_NO_RESOURCES:
3883 return (scferror2errno(scf_error()));
3884
3885 case SCF_ERROR_DELETED:
3886 warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3887 return (EBUSY);
3888
3889 case SCF_ERROR_PERMISSION_DENIED:
3890 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3891 return (scferror2errno(scf_error()));
3892
3893 case SCF_ERROR_NOT_BOUND:
3894 case SCF_ERROR_INVALID_ARGUMENT:
3895 case SCF_ERROR_NOT_SET:
3896 default:
3897 bad_error("scf_transaction_destroy", scf_error());
3898 /* NOTREACHED */
3899 }
3900 }
3901
3902 /*
3903 * Used to add the manifests to the list of currently supported manifests.
3904 * We can modify the existing manifest list removing entries if the files
3905 * don't exist.
3906 *
3907 * Get the old list and the new file name
3908 * If the new file name is in the list return
3909 * If not then add the file to the list.
3910 * As we process the list check to see if the files in the old list exist
3911 * if not then remove the file from the list.
3912 * Commit the list of manifest file names.
3913 *
3914 */
3915 static int
upgrade_manifestfiles(pgroup_t * pg,entity_t * ient,const scf_snaplevel_t * running,void * ent)3916 upgrade_manifestfiles(pgroup_t *pg, entity_t *ient,
3917 const scf_snaplevel_t *running, void *ent)
3918 {
3919 scf_propertygroup_t *ud_mfsts_pg = NULL;
3920 scf_property_t *ud_prop = NULL;
3921 scf_iter_t *ud_prop_iter;
3922 scf_value_t *fname_value;
3923 scf_callback_t cbdata;
3924 pgroup_t *mfst_pgroup;
3925 property_t *mfst_prop;
3926 property_t *old_prop;
3927 char *pname;
3928 char *fval;
3929 char *old_pname;
3930 char *old_fval;
3931 int no_upgrade_pg;
3932 int mfst_seen;
3933 int r;
3934
3935 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3936
3937 /*
3938 * This should always be the service base on the code
3939 * path, and the fact that the manifests pg is a service
3940 * level property group only.
3941 */
3942 ud_mfsts_pg = scf_pg_create(g_hndl);
3943 ud_prop = scf_property_create(g_hndl);
3944 ud_prop_iter = scf_iter_create(g_hndl);
3945 fname_value = scf_value_create(g_hndl);
3946
3947 /* Fetch the "manifests" property group */
3948 no_upgrade_pg = 0;
3949 r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3950 ud_mfsts_pg);
3951 if (r != 0) {
3952 switch (scf_error()) {
3953 case SCF_ERROR_NOT_FOUND:
3954 no_upgrade_pg = 1;
3955 break;
3956
3957 case SCF_ERROR_DELETED:
3958 case SCF_ERROR_CONNECTION_BROKEN:
3959 return (scferror2errno(scf_error()));
3960
3961 case SCF_ERROR_NOT_SET:
3962 case SCF_ERROR_INVALID_ARGUMENT:
3963 case SCF_ERROR_HANDLE_MISMATCH:
3964 case SCF_ERROR_NOT_BOUND:
3965 default:
3966 bad_error(running ? "scf_snaplevel_get_pg" :
3967 "entity_get_pg", scf_error());
3968 }
3969 }
3970
3971 if (no_upgrade_pg) {
3972 cbdata.sc_handle = g_hndl;
3973 cbdata.sc_parent = ent;
3974 cbdata.sc_service = issvc;
3975 cbdata.sc_flags = SCI_FORCE;
3976 cbdata.sc_source_fmri = ient->sc_fmri;
3977 cbdata.sc_target_fmri = ient->sc_fmri;
3978
3979 if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3980 return (cbdata.sc_err);
3981
3982 return (0);
3983 }
3984
3985 /* Fetch the new manifests property group */
3986 mfst_pgroup = internal_pgroup_find_or_create(ient,
3987 SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
3988 assert(mfst_pgroup != NULL);
3989
3990 if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3991 SCF_SUCCESS)
3992 return (-1);
3993
3994 if ((pname = malloc(MAXPATHLEN)) == NULL)
3995 return (ENOMEM);
3996 if ((fval = malloc(MAXPATHLEN)) == NULL) {
3997 free(pname);
3998 return (ENOMEM);
3999 }
4000
4001 while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
4002 mfst_seen = 0;
4003 if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
4004 continue;
4005
4006 for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
4007 mfst_prop != NULL;
4008 mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
4009 mfst_prop)) {
4010 if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
4011 mfst_seen = 1;
4012 }
4013 }
4014
4015 /*
4016 * If the manifest is not seen then add it to the new mfst
4017 * property list to get proccessed into the repo.
4018 */
4019 if (mfst_seen == 0) {
4020 /*
4021 * If we cannot get the value then there is no
4022 * reason to attempt to attach the value to
4023 * the property group
4024 */
4025 if (prop_get_val(ud_prop, fname_value) == 0 &&
4026 scf_value_get_astring(fname_value, fval,
4027 MAXPATHLEN) != -1) {
4028 old_pname = safe_strdup(pname);
4029 old_fval = safe_strdup(fval);
4030 old_prop = internal_property_create(old_pname,
4031 SCF_TYPE_ASTRING, 1, old_fval);
4032
4033 /*
4034 * Already checked to see if the property exists
4035 * in the group, and it does not.
4036 */
4037 (void) internal_attach_property(mfst_pgroup,
4038 old_prop);
4039 }
4040 }
4041 }
4042 free(pname);
4043 free(fval);
4044
4045 cbdata.sc_handle = g_hndl;
4046 cbdata.sc_parent = ent;
4047 cbdata.sc_service = issvc;
4048 cbdata.sc_flags = SCI_FORCE;
4049 cbdata.sc_source_fmri = ient->sc_fmri;
4050 cbdata.sc_target_fmri = ient->sc_fmri;
4051
4052 if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
4053 return (cbdata.sc_err);
4054
4055 return (r);
4056 }
4057
4058 /*
4059 * prop is taken to be a property in the "dependents" property group of snpl,
4060 * which is taken to be the snaplevel of a last-import snapshot corresponding
4061 * to ient. If prop is a valid dependents property, upgrade the dependent it
4062 * represents according to the repository & ient. If ud_run_dpts_pg_set is
4063 * true, then ud_run_dpts_pg is taken to be the "dependents" property group
4064 * of the entity ient represents (possibly in the running snapshot). If it
4065 * needs to be changed, an entry will be added to tx, if not NULL.
4066 *
4067 * Returns
4068 * 0 - success
4069 * ECONNABORTED - repository connection broken
4070 * ENOMEM - out of memory
4071 * ENOSPC - configd was out of resources
4072 * ECANCELED - snpl's entity was deleted
4073 * EINVAL - dependent target is invalid (error printed)
4074 * - dependent is invalid (error printed)
4075 * EBADF - snpl is corrupt (error printed)
4076 * - snpl has corrupt pg (error printed)
4077 * - dependency pg in target is corrupt (error printed)
4078 * - running snapshot in dependent is missing snaplevel (error printed)
4079 * EPERM - couldn't delete dependency pg (permission denied) (error printed)
4080 * - couldn't create dependent (permission denied) (error printed)
4081 * - couldn't modify dependent pg (permission denied) (error printed)
4082 * EROFS - couldn't delete dependency pg (repository read-only)
4083 * - couldn't create dependent (repository read-only)
4084 * EACCES - couldn't delete dependency pg (backend access denied)
4085 * - couldn't create dependent (backend access denied)
4086 * EBUSY - ud_run_dpts_pg was deleted (error printed)
4087 * - tx's pg was deleted (error printed)
4088 * - dependent pg was changed or deleted (error printed)
4089 * EEXIST - dependency pg already exists in new target (error printed)
4090 */
4091 static int
upgrade_dependent(const scf_property_t * prop,const entity_t * ient,const scf_snaplevel_t * snpl,scf_transaction_t * tx)4092 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
4093 const scf_snaplevel_t *snpl, scf_transaction_t *tx)
4094 {
4095 pgroup_t pgrp;
4096 scf_type_t ty;
4097 pgroup_t *new_dpt_pgroup;
4098 pgroup_t *old_dpt_pgroup = NULL;
4099 pgroup_t *current_pg;
4100 pgroup_t *dpt;
4101 scf_callback_t cbdata;
4102 int tissvc;
4103 void *target_ent;
4104 scf_error_t serr;
4105 int r;
4106 scf_transaction_entry_t *ent;
4107
4108 const char * const cf_inval = gettext("Conflict upgrading %s "
4109 "(dependent \"%s\" has invalid dependents property).\n");
4110 const char * const cf_missing = gettext("Conflict upgrading %s "
4111 "(dependent \"%s\" is missing).\n");
4112 const char * const cf_newdpg = gettext("Conflict upgrading %s "
4113 "(dependent \"%s\" has new dependency property group).\n");
4114 const char * const cf_newtarg = gettext("Conflict upgrading %s "
4115 "(dependent \"%s\" has new target).\n");
4116 const char * const li_corrupt =
4117 gettext("%s: \"last-import\" snapshot is corrupt.\n");
4118 const char * const upgrading =
4119 gettext("%s: Upgrading dependent \"%s\".\n");
4120 const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
4121 "corrupt (missing snaplevel).\n");
4122
4123 if (scf_property_type(prop, &ty) != 0) {
4124 switch (scf_error()) {
4125 case SCF_ERROR_DELETED:
4126 case SCF_ERROR_CONNECTION_BROKEN:
4127 return (scferror2errno(scf_error()));
4128
4129 case SCF_ERROR_NOT_BOUND:
4130 case SCF_ERROR_NOT_SET:
4131 default:
4132 bad_error("scf_property_type", scf_error());
4133 }
4134 }
4135
4136 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4137 warn(li_corrupt, ient->sc_fmri);
4138 return (EBADF);
4139 }
4140
4141 /*
4142 * prop represents a dependent in the old manifest. It is named after
4143 * the dependent.
4144 */
4145 if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
4146 switch (scf_error()) {
4147 case SCF_ERROR_DELETED:
4148 case SCF_ERROR_CONNECTION_BROKEN:
4149 return (scferror2errno(scf_error()));
4150
4151 case SCF_ERROR_NOT_BOUND:
4152 case SCF_ERROR_NOT_SET:
4153 default:
4154 bad_error("scf_property_get_name", scf_error());
4155 }
4156 }
4157
4158 /* See if it's in the new manifest. */
4159 pgrp.sc_pgroup_name = ud_name;
4160 new_dpt_pgroup =
4161 uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
4162
4163 /* If it's not, delete it... if it hasn't been customized. */
4164 if (new_dpt_pgroup == NULL) {
4165 if (!ud_run_dpts_pg_set)
4166 return (0);
4167
4168 if (scf_property_get_value(prop, ud_val) != 0) {
4169 switch (scf_error()) {
4170 case SCF_ERROR_NOT_FOUND:
4171 case SCF_ERROR_CONSTRAINT_VIOLATED:
4172 warn(li_corrupt, ient->sc_fmri);
4173 return (EBADF);
4174
4175 case SCF_ERROR_DELETED:
4176 case SCF_ERROR_CONNECTION_BROKEN:
4177 return (scferror2errno(scf_error()));
4178
4179 case SCF_ERROR_HANDLE_MISMATCH:
4180 case SCF_ERROR_NOT_BOUND:
4181 case SCF_ERROR_NOT_SET:
4182 case SCF_ERROR_PERMISSION_DENIED:
4183 default:
4184 bad_error("scf_property_get_value",
4185 scf_error());
4186 }
4187 }
4188
4189 if (scf_value_get_as_string(ud_val, ud_oldtarg,
4190 max_scf_value_len + 1) < 0)
4191 bad_error("scf_value_get_as_string", scf_error());
4192
4193 if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
4194 0) {
4195 switch (scf_error()) {
4196 case SCF_ERROR_NOT_FOUND:
4197 return (0);
4198
4199 case SCF_ERROR_CONNECTION_BROKEN:
4200 return (scferror2errno(scf_error()));
4201
4202 case SCF_ERROR_DELETED:
4203 warn(emsg_pg_deleted, ient->sc_fmri,
4204 "dependents");
4205 return (EBUSY);
4206
4207 case SCF_ERROR_INVALID_ARGUMENT:
4208 case SCF_ERROR_NOT_BOUND:
4209 case SCF_ERROR_HANDLE_MISMATCH:
4210 case SCF_ERROR_NOT_SET:
4211 default:
4212 bad_error("scf_pg_get_property", scf_error());
4213 }
4214 }
4215 if (scf_property_get_value(ud_prop, ud_val) != 0) {
4216 switch (scf_error()) {
4217 case SCF_ERROR_NOT_FOUND:
4218 case SCF_ERROR_CONSTRAINT_VIOLATED:
4219 warn(cf_inval, ient->sc_fmri, ud_name);
4220 return (0);
4221
4222 case SCF_ERROR_DELETED:
4223 case SCF_ERROR_CONNECTION_BROKEN:
4224 return (scferror2errno(scf_error()));
4225
4226 case SCF_ERROR_HANDLE_MISMATCH:
4227 case SCF_ERROR_NOT_BOUND:
4228 case SCF_ERROR_NOT_SET:
4229 case SCF_ERROR_PERMISSION_DENIED:
4230 default:
4231 bad_error("scf_property_get_value",
4232 scf_error());
4233 }
4234 }
4235
4236 ty = scf_value_type(ud_val);
4237 assert(ty != SCF_TYPE_INVALID);
4238 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4239 warn(cf_inval, ient->sc_fmri, ud_name);
4240 return (0);
4241 }
4242
4243 if (scf_value_get_as_string(ud_val, ud_ctarg,
4244 max_scf_value_len + 1) < 0)
4245 bad_error("scf_value_get_as_string", scf_error());
4246
4247 r = fmri_equal(ud_ctarg, ud_oldtarg);
4248 switch (r) {
4249 case 1:
4250 break;
4251
4252 case 0:
4253 case -1: /* warn? */
4254 warn(cf_newtarg, ient->sc_fmri, ud_name);
4255 return (0);
4256
4257 case -2:
4258 warn(li_corrupt, ient->sc_fmri);
4259 return (EBADF);
4260
4261 default:
4262 bad_error("fmri_equal", r);
4263 }
4264
4265 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4266 switch (scf_error()) {
4267 case SCF_ERROR_NOT_FOUND:
4268 warn(li_corrupt, ient->sc_fmri);
4269 return (EBADF);
4270
4271 case SCF_ERROR_DELETED:
4272 case SCF_ERROR_CONNECTION_BROKEN:
4273 return (scferror2errno(scf_error()));
4274
4275 case SCF_ERROR_NOT_BOUND:
4276 case SCF_ERROR_HANDLE_MISMATCH:
4277 case SCF_ERROR_INVALID_ARGUMENT:
4278 case SCF_ERROR_NOT_SET:
4279 default:
4280 bad_error("scf_snaplevel_get_pg", scf_error());
4281 }
4282 }
4283
4284 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4285 snap_lastimport);
4286 switch (r) {
4287 case 0:
4288 break;
4289
4290 case ECANCELED:
4291 case ECONNABORTED:
4292 case ENOMEM:
4293 case EBADF:
4294 return (r);
4295
4296 case EACCES:
4297 default:
4298 bad_error("load_pg", r);
4299 }
4300
4301 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4302 switch (serr) {
4303 case SCF_ERROR_NONE:
4304 break;
4305
4306 case SCF_ERROR_NO_MEMORY:
4307 internal_pgroup_free(old_dpt_pgroup);
4308 return (ENOMEM);
4309
4310 case SCF_ERROR_NOT_FOUND:
4311 internal_pgroup_free(old_dpt_pgroup);
4312 goto delprop;
4313
4314 case SCF_ERROR_CONSTRAINT_VIOLATED: /* caught above */
4315 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
4316 default:
4317 bad_error("fmri_to_entity", serr);
4318 }
4319
4320 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4321 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4322 switch (r) {
4323 case 0:
4324 break;
4325
4326 case ECONNABORTED:
4327 internal_pgroup_free(old_dpt_pgroup);
4328 return (r);
4329
4330 case ECANCELED:
4331 case ENOENT:
4332 internal_pgroup_free(old_dpt_pgroup);
4333 goto delprop;
4334
4335 case EBADF:
4336 warn(r_no_lvl, ud_ctarg);
4337 internal_pgroup_free(old_dpt_pgroup);
4338 return (r);
4339
4340 case EINVAL:
4341 default:
4342 bad_error("entity_get_running_pg", r);
4343 }
4344
4345 /* load it */
4346 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4347 switch (r) {
4348 case 0:
4349 break;
4350
4351 case ECANCELED:
4352 internal_pgroup_free(old_dpt_pgroup);
4353 goto delprop;
4354
4355 case ECONNABORTED:
4356 case ENOMEM:
4357 case EBADF:
4358 internal_pgroup_free(old_dpt_pgroup);
4359 return (r);
4360
4361 case EACCES:
4362 default:
4363 bad_error("load_pg", r);
4364 }
4365
4366 /* compare property groups */
4367 if (!pg_equal(old_dpt_pgroup, current_pg)) {
4368 warn(cf_newdpg, ient->sc_fmri, ud_name);
4369 internal_pgroup_free(old_dpt_pgroup);
4370 internal_pgroup_free(current_pg);
4371 return (0);
4372 }
4373
4374 internal_pgroup_free(old_dpt_pgroup);
4375 internal_pgroup_free(current_pg);
4376
4377 if (g_verbose)
4378 warn(gettext("%s: Deleting dependent \"%s\".\n"),
4379 ient->sc_fmri, ud_name);
4380
4381 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4382 switch (scf_error()) {
4383 case SCF_ERROR_NOT_FOUND:
4384 case SCF_ERROR_DELETED:
4385 internal_pgroup_free(old_dpt_pgroup);
4386 goto delprop;
4387
4388 case SCF_ERROR_CONNECTION_BROKEN:
4389 internal_pgroup_free(old_dpt_pgroup);
4390 return (ECONNABORTED);
4391
4392 case SCF_ERROR_NOT_SET:
4393 case SCF_ERROR_INVALID_ARGUMENT:
4394 case SCF_ERROR_HANDLE_MISMATCH:
4395 case SCF_ERROR_NOT_BOUND:
4396 default:
4397 bad_error("entity_get_pg", scf_error());
4398 }
4399 }
4400
4401 if (scf_pg_delete(ud_pg) != 0) {
4402 switch (scf_error()) {
4403 case SCF_ERROR_DELETED:
4404 break;
4405
4406 case SCF_ERROR_CONNECTION_BROKEN:
4407 case SCF_ERROR_BACKEND_READONLY:
4408 case SCF_ERROR_BACKEND_ACCESS:
4409 return (scferror2errno(scf_error()));
4410
4411 case SCF_ERROR_PERMISSION_DENIED:
4412 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4413 return (scferror2errno(scf_error()));
4414
4415 case SCF_ERROR_NOT_SET:
4416 default:
4417 bad_error("scf_pg_delete", scf_error());
4418 }
4419 }
4420
4421 /*
4422 * This service was changed, so it must be refreshed. But
4423 * since it's not mentioned in the new manifest, we have to
4424 * record its FMRI here for use later. We record the name
4425 * & the entity (via sc_parent) in case we need to print error
4426 * messages during the refresh.
4427 */
4428 dpt = internal_pgroup_new();
4429 if (dpt == NULL)
4430 return (ENOMEM);
4431 dpt->sc_pgroup_name = strdup(ud_name);
4432 dpt->sc_pgroup_fmri = strdup(ud_ctarg);
4433 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4434 return (ENOMEM);
4435 dpt->sc_parent = (entity_t *)ient;
4436 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4437 uu_die(gettext("libuutil error: %s\n"),
4438 uu_strerror(uu_error()));
4439
4440 delprop:
4441 if (tx == NULL)
4442 return (0);
4443
4444 ent = scf_entry_create(g_hndl);
4445 if (ent == NULL)
4446 return (ENOMEM);
4447
4448 if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
4449 scf_entry_destroy(ent);
4450 switch (scf_error()) {
4451 case SCF_ERROR_DELETED:
4452 warn(emsg_pg_deleted, ient->sc_fmri,
4453 "dependents");
4454 return (EBUSY);
4455
4456 case SCF_ERROR_CONNECTION_BROKEN:
4457 return (scferror2errno(scf_error()));
4458
4459 case SCF_ERROR_NOT_FOUND:
4460 break;
4461
4462 case SCF_ERROR_HANDLE_MISMATCH:
4463 case SCF_ERROR_NOT_BOUND:
4464 case SCF_ERROR_INVALID_ARGUMENT:
4465 case SCF_ERROR_NOT_SET:
4466 default:
4467 bad_error("scf_transaction_property_delete",
4468 scf_error());
4469 }
4470 }
4471
4472 return (0);
4473 }
4474
4475 new_dpt_pgroup->sc_pgroup_seen = 1;
4476
4477 /*
4478 * Decide whether the dependent has changed in the manifest.
4479 */
4480 /* Compare the target. */
4481 if (scf_property_get_value(prop, ud_val) != 0) {
4482 switch (scf_error()) {
4483 case SCF_ERROR_NOT_FOUND:
4484 case SCF_ERROR_CONSTRAINT_VIOLATED:
4485 warn(li_corrupt, ient->sc_fmri);
4486 return (EBADF);
4487
4488 case SCF_ERROR_DELETED:
4489 case SCF_ERROR_CONNECTION_BROKEN:
4490 return (scferror2errno(scf_error()));
4491
4492 case SCF_ERROR_HANDLE_MISMATCH:
4493 case SCF_ERROR_NOT_BOUND:
4494 case SCF_ERROR_NOT_SET:
4495 case SCF_ERROR_PERMISSION_DENIED:
4496 default:
4497 bad_error("scf_property_get_value", scf_error());
4498 }
4499 }
4500
4501 if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
4502 0)
4503 bad_error("scf_value_get_as_string", scf_error());
4504
4505 /*
4506 * If the fmri's are not equal then the old fmri will need to
4507 * be refreshed to ensure that the changes are properly updated
4508 * in that service.
4509 */
4510 r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
4511 switch (r) {
4512 case 0:
4513 dpt = internal_pgroup_new();
4514 if (dpt == NULL)
4515 return (ENOMEM);
4516 dpt->sc_pgroup_name = strdup(ud_name);
4517 dpt->sc_pgroup_fmri = strdup(ud_oldtarg);
4518 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4519 return (ENOMEM);
4520 dpt->sc_parent = (entity_t *)ient;
4521 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4522 uu_die(gettext("libuutil error: %s\n"),
4523 uu_strerror(uu_error()));
4524 break;
4525
4526 case 1:
4527 /* Compare the dependency pgs. */
4528 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4529 switch (scf_error()) {
4530 case SCF_ERROR_NOT_FOUND:
4531 warn(li_corrupt, ient->sc_fmri);
4532 return (EBADF);
4533
4534 case SCF_ERROR_DELETED:
4535 case SCF_ERROR_CONNECTION_BROKEN:
4536 return (scferror2errno(scf_error()));
4537
4538 case SCF_ERROR_NOT_BOUND:
4539 case SCF_ERROR_HANDLE_MISMATCH:
4540 case SCF_ERROR_INVALID_ARGUMENT:
4541 case SCF_ERROR_NOT_SET:
4542 default:
4543 bad_error("scf_snaplevel_get_pg", scf_error());
4544 }
4545 }
4546
4547 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4548 snap_lastimport);
4549 switch (r) {
4550 case 0:
4551 break;
4552
4553 case ECANCELED:
4554 case ECONNABORTED:
4555 case ENOMEM:
4556 case EBADF:
4557 return (r);
4558
4559 case EACCES:
4560 default:
4561 bad_error("load_pg", r);
4562 }
4563
4564 if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4565 /* no change, leave customizations */
4566 internal_pgroup_free(old_dpt_pgroup);
4567 return (0);
4568 }
4569 break;
4570
4571 case -1:
4572 warn(li_corrupt, ient->sc_fmri);
4573 return (EBADF);
4574
4575 case -2:
4576 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4577 ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4578 return (EINVAL);
4579
4580 default:
4581 bad_error("fmri_equal", r);
4582 }
4583
4584 /*
4585 * The dependent has changed in the manifest. Upgrade the current
4586 * properties if they haven't been customized.
4587 */
4588
4589 /*
4590 * If new_dpt_pgroup->sc_override, then act as though the property
4591 * group hasn't been customized.
4592 */
4593 if (new_dpt_pgroup->sc_pgroup_override) {
4594 (void) strcpy(ud_ctarg, ud_oldtarg);
4595 goto nocust;
4596 }
4597
4598 if (!ud_run_dpts_pg_set) {
4599 warn(cf_missing, ient->sc_fmri, ud_name);
4600 r = 0;
4601 goto out;
4602 } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4603 switch (scf_error()) {
4604 case SCF_ERROR_NOT_FOUND:
4605 warn(cf_missing, ient->sc_fmri, ud_name);
4606 r = 0;
4607 goto out;
4608
4609 case SCF_ERROR_CONNECTION_BROKEN:
4610 r = scferror2errno(scf_error());
4611 goto out;
4612
4613 case SCF_ERROR_DELETED:
4614 warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4615 r = EBUSY;
4616 goto out;
4617
4618 case SCF_ERROR_INVALID_ARGUMENT:
4619 case SCF_ERROR_NOT_BOUND:
4620 case SCF_ERROR_HANDLE_MISMATCH:
4621 case SCF_ERROR_NOT_SET:
4622 default:
4623 bad_error("scf_pg_get_property", scf_error());
4624 }
4625 }
4626
4627 if (scf_property_get_value(ud_prop, ud_val) != 0) {
4628 switch (scf_error()) {
4629 case SCF_ERROR_NOT_FOUND:
4630 case SCF_ERROR_CONSTRAINT_VIOLATED:
4631 warn(cf_inval, ient->sc_fmri, ud_name);
4632 r = 0;
4633 goto out;
4634
4635 case SCF_ERROR_DELETED:
4636 case SCF_ERROR_CONNECTION_BROKEN:
4637 r = scferror2errno(scf_error());
4638 goto out;
4639
4640 case SCF_ERROR_HANDLE_MISMATCH:
4641 case SCF_ERROR_NOT_BOUND:
4642 case SCF_ERROR_NOT_SET:
4643 case SCF_ERROR_PERMISSION_DENIED:
4644 default:
4645 bad_error("scf_property_get_value", scf_error());
4646 }
4647 }
4648
4649 ty = scf_value_type(ud_val);
4650 assert(ty != SCF_TYPE_INVALID);
4651 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4652 warn(cf_inval, ient->sc_fmri, ud_name);
4653 r = 0;
4654 goto out;
4655 }
4656 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4657 0)
4658 bad_error("scf_value_get_as_string", scf_error());
4659
4660 r = fmri_equal(ud_ctarg, ud_oldtarg);
4661 if (r == -1) {
4662 warn(cf_inval, ient->sc_fmri, ud_name);
4663 r = 0;
4664 goto out;
4665 } else if (r == -2) {
4666 warn(li_corrupt, ient->sc_fmri);
4667 r = EBADF;
4668 goto out;
4669 } else if (r == 0) {
4670 /*
4671 * Target has been changed. Only abort now if it's been
4672 * changed to something other than what's in the manifest.
4673 */
4674 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4675 if (r == -1) {
4676 warn(cf_inval, ient->sc_fmri, ud_name);
4677 r = 0;
4678 goto out;
4679 } else if (r == 0) {
4680 warn(cf_newtarg, ient->sc_fmri, ud_name);
4681 r = 0;
4682 goto out;
4683 } else if (r != 1) {
4684 /* invalid sc_pgroup_fmri caught above */
4685 bad_error("fmri_equal", r);
4686 }
4687
4688 /*
4689 * Fetch the current dependency pg. If it's what the manifest
4690 * says, then no problem.
4691 */
4692 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4693 switch (serr) {
4694 case SCF_ERROR_NONE:
4695 break;
4696
4697 case SCF_ERROR_NOT_FOUND:
4698 warn(cf_missing, ient->sc_fmri, ud_name);
4699 r = 0;
4700 goto out;
4701
4702 case SCF_ERROR_NO_MEMORY:
4703 r = ENOMEM;
4704 goto out;
4705
4706 case SCF_ERROR_CONSTRAINT_VIOLATED:
4707 case SCF_ERROR_INVALID_ARGUMENT:
4708 default:
4709 bad_error("fmri_to_entity", serr);
4710 }
4711
4712 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4713 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4714 switch (r) {
4715 case 0:
4716 break;
4717
4718 case ECONNABORTED:
4719 goto out;
4720
4721 case ECANCELED:
4722 case ENOENT:
4723 warn(cf_missing, ient->sc_fmri, ud_name);
4724 r = 0;
4725 goto out;
4726
4727 case EBADF:
4728 warn(r_no_lvl, ud_ctarg);
4729 goto out;
4730
4731 case EINVAL:
4732 default:
4733 bad_error("entity_get_running_pg", r);
4734 }
4735
4736 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4737 switch (r) {
4738 case 0:
4739 break;
4740
4741 case ECANCELED:
4742 warn(cf_missing, ient->sc_fmri, ud_name);
4743 r = 0;
4744 goto out;
4745
4746 case ECONNABORTED:
4747 case ENOMEM:
4748 case EBADF:
4749 goto out;
4750
4751 case EACCES:
4752 default:
4753 bad_error("load_pg", r);
4754 }
4755
4756 if (!pg_equal(current_pg, new_dpt_pgroup))
4757 warn(cf_newdpg, ient->sc_fmri, ud_name);
4758 internal_pgroup_free(current_pg);
4759 r = 0;
4760 goto out;
4761 } else if (r != 1) {
4762 bad_error("fmri_equal", r);
4763 }
4764
4765 nocust:
4766 /*
4767 * Target has not been customized. Check the dependency property
4768 * group.
4769 */
4770
4771 if (old_dpt_pgroup == NULL) {
4772 if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4773 ud_pg) != 0) {
4774 switch (scf_error()) {
4775 case SCF_ERROR_NOT_FOUND:
4776 warn(li_corrupt, ient->sc_fmri);
4777 return (EBADF);
4778
4779 case SCF_ERROR_DELETED:
4780 case SCF_ERROR_CONNECTION_BROKEN:
4781 return (scferror2errno(scf_error()));
4782
4783 case SCF_ERROR_NOT_BOUND:
4784 case SCF_ERROR_HANDLE_MISMATCH:
4785 case SCF_ERROR_INVALID_ARGUMENT:
4786 case SCF_ERROR_NOT_SET:
4787 default:
4788 bad_error("scf_snaplevel_get_pg", scf_error());
4789 }
4790 }
4791
4792 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4793 snap_lastimport);
4794 switch (r) {
4795 case 0:
4796 break;
4797
4798 case ECANCELED:
4799 case ECONNABORTED:
4800 case ENOMEM:
4801 case EBADF:
4802 return (r);
4803
4804 case EACCES:
4805 default:
4806 bad_error("load_pg", r);
4807 }
4808 }
4809 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4810 switch (serr) {
4811 case SCF_ERROR_NONE:
4812 break;
4813
4814 case SCF_ERROR_NOT_FOUND:
4815 warn(cf_missing, ient->sc_fmri, ud_name);
4816 r = 0;
4817 goto out;
4818
4819 case SCF_ERROR_NO_MEMORY:
4820 r = ENOMEM;
4821 goto out;
4822
4823 case SCF_ERROR_CONSTRAINT_VIOLATED:
4824 case SCF_ERROR_INVALID_ARGUMENT:
4825 default:
4826 bad_error("fmri_to_entity", serr);
4827 }
4828
4829 r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4830 ud_iter2, ud_inst, imp_snap, ud_snpl);
4831 switch (r) {
4832 case 0:
4833 break;
4834
4835 case ECONNABORTED:
4836 goto out;
4837
4838 case ECANCELED:
4839 case ENOENT:
4840 warn(cf_missing, ient->sc_fmri, ud_name);
4841 r = 0;
4842 goto out;
4843
4844 case EBADF:
4845 warn(r_no_lvl, ud_ctarg);
4846 goto out;
4847
4848 case EINVAL:
4849 default:
4850 bad_error("entity_get_running_pg", r);
4851 }
4852
4853 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4854 switch (r) {
4855 case 0:
4856 break;
4857
4858 case ECANCELED:
4859 warn(cf_missing, ient->sc_fmri, ud_name);
4860 goto out;
4861
4862 case ECONNABORTED:
4863 case ENOMEM:
4864 case EBADF:
4865 goto out;
4866
4867 case EACCES:
4868 default:
4869 bad_error("load_pg", r);
4870 }
4871
4872 if (!pg_equal(current_pg, old_dpt_pgroup)) {
4873 if (!pg_equal(current_pg, new_dpt_pgroup))
4874 warn(cf_newdpg, ient->sc_fmri, ud_name);
4875 internal_pgroup_free(current_pg);
4876 r = 0;
4877 goto out;
4878 }
4879
4880 /* Uncustomized. Upgrade. */
4881
4882 r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4883 switch (r) {
4884 case 1:
4885 if (pg_equal(current_pg, new_dpt_pgroup)) {
4886 /* Already upgraded. */
4887 internal_pgroup_free(current_pg);
4888 r = 0;
4889 goto out;
4890 }
4891
4892 internal_pgroup_free(current_pg);
4893
4894 /* upgrade current_pg */
4895 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4896 switch (scf_error()) {
4897 case SCF_ERROR_CONNECTION_BROKEN:
4898 r = scferror2errno(scf_error());
4899 goto out;
4900
4901 case SCF_ERROR_DELETED:
4902 warn(cf_missing, ient->sc_fmri, ud_name);
4903 r = 0;
4904 goto out;
4905
4906 case SCF_ERROR_NOT_FOUND:
4907 break;
4908
4909 case SCF_ERROR_INVALID_ARGUMENT:
4910 case SCF_ERROR_NOT_BOUND:
4911 case SCF_ERROR_NOT_SET:
4912 case SCF_ERROR_HANDLE_MISMATCH:
4913 default:
4914 bad_error("entity_get_pg", scf_error());
4915 }
4916
4917 if (tissvc)
4918 r = scf_service_add_pg(target_ent, ud_name,
4919 SCF_GROUP_DEPENDENCY, 0, ud_pg);
4920 else
4921 r = scf_instance_add_pg(target_ent, ud_name,
4922 SCF_GROUP_DEPENDENCY, 0, ud_pg);
4923 if (r != 0) {
4924 switch (scf_error()) {
4925 case SCF_ERROR_CONNECTION_BROKEN:
4926 case SCF_ERROR_NO_RESOURCES:
4927 case SCF_ERROR_BACKEND_READONLY:
4928 case SCF_ERROR_BACKEND_ACCESS:
4929 r = scferror2errno(scf_error());
4930 goto out;
4931
4932 case SCF_ERROR_DELETED:
4933 warn(cf_missing, ient->sc_fmri,
4934 ud_name);
4935 r = 0;
4936 goto out;
4937
4938 case SCF_ERROR_PERMISSION_DENIED:
4939 warn(emsg_pg_deleted, ud_ctarg,
4940 ud_name);
4941 r = EPERM;
4942 goto out;
4943
4944 case SCF_ERROR_EXISTS:
4945 warn(emsg_pg_added, ud_ctarg, ud_name);
4946 r = EBUSY;
4947 goto out;
4948
4949 case SCF_ERROR_NOT_BOUND:
4950 case SCF_ERROR_HANDLE_MISMATCH:
4951 case SCF_ERROR_INVALID_ARGUMENT:
4952 case SCF_ERROR_NOT_SET:
4953 default:
4954 bad_error("entity_add_pg", scf_error());
4955 }
4956 }
4957 }
4958
4959 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4960 switch (r) {
4961 case 0:
4962 break;
4963
4964 case ECANCELED:
4965 warn(cf_missing, ient->sc_fmri, ud_name);
4966 goto out;
4967
4968 case ECONNABORTED:
4969 case ENOMEM:
4970 case EBADF:
4971 goto out;
4972
4973 case EACCES:
4974 default:
4975 bad_error("load_pg", r);
4976 }
4977
4978 if (g_verbose)
4979 warn(upgrading, ient->sc_fmri, ud_name);
4980
4981 r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4982 new_dpt_pgroup, 0, ient->sc_fmri);
4983 switch (r) {
4984 case 0:
4985 break;
4986
4987 case ECANCELED:
4988 warn(emsg_pg_deleted, ud_ctarg, ud_name);
4989 r = EBUSY;
4990 goto out;
4991
4992 case EPERM:
4993 warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4994 goto out;
4995
4996 case EBUSY:
4997 warn(emsg_pg_changed, ud_ctarg, ud_name);
4998 goto out;
4999
5000 case ECONNABORTED:
5001 case ENOMEM:
5002 case ENOSPC:
5003 case EROFS:
5004 case EACCES:
5005 case EINVAL:
5006 goto out;
5007
5008 default:
5009 bad_error("upgrade_pg", r);
5010 }
5011 break;
5012
5013 case 0: {
5014 scf_transaction_entry_t *ent;
5015 scf_value_t *val;
5016
5017 internal_pgroup_free(current_pg);
5018
5019 /* delete old pg */
5020 if (g_verbose)
5021 warn(upgrading, ient->sc_fmri, ud_name);
5022
5023 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
5024 switch (scf_error()) {
5025 case SCF_ERROR_CONNECTION_BROKEN:
5026 r = scferror2errno(scf_error());
5027 goto out;
5028
5029 case SCF_ERROR_DELETED:
5030 warn(cf_missing, ient->sc_fmri, ud_name);
5031 r = 0;
5032 goto out;
5033
5034 case SCF_ERROR_NOT_FOUND:
5035 break;
5036
5037 case SCF_ERROR_INVALID_ARGUMENT:
5038 case SCF_ERROR_NOT_BOUND:
5039 case SCF_ERROR_NOT_SET:
5040 case SCF_ERROR_HANDLE_MISMATCH:
5041 default:
5042 bad_error("entity_get_pg", scf_error());
5043 }
5044 } else if (scf_pg_delete(ud_pg) != 0) {
5045 switch (scf_error()) {
5046 case SCF_ERROR_DELETED:
5047 break;
5048
5049 case SCF_ERROR_CONNECTION_BROKEN:
5050 case SCF_ERROR_BACKEND_READONLY:
5051 case SCF_ERROR_BACKEND_ACCESS:
5052 r = scferror2errno(scf_error());
5053 goto out;
5054
5055 case SCF_ERROR_PERMISSION_DENIED:
5056 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
5057 r = scferror2errno(scf_error());
5058 goto out;
5059
5060 case SCF_ERROR_NOT_SET:
5061 default:
5062 bad_error("scf_pg_delete", scf_error());
5063 }
5064 }
5065
5066 /* import new one */
5067 cbdata.sc_handle = g_hndl;
5068 cbdata.sc_trans = NULL; /* handled below */
5069 cbdata.sc_flags = 0;
5070
5071 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
5072 if (r != UU_WALK_NEXT) {
5073 if (r != UU_WALK_ERROR)
5074 bad_error("lscf_dependent_import", r);
5075
5076 r = cbdata.sc_err;
5077 goto out;
5078 }
5079
5080 if (tx == NULL)
5081 break;
5082
5083 if ((ent = scf_entry_create(g_hndl)) == NULL ||
5084 (val = scf_value_create(g_hndl)) == NULL) {
5085 if (scf_error() == SCF_ERROR_NO_MEMORY)
5086 return (ENOMEM);
5087
5088 bad_error("scf_entry_create", scf_error());
5089 }
5090
5091 if (scf_transaction_property_change_type(tx, ent, ud_name,
5092 SCF_TYPE_FMRI) != 0) {
5093 switch (scf_error()) {
5094 case SCF_ERROR_CONNECTION_BROKEN:
5095 r = scferror2errno(scf_error());
5096 goto out;
5097
5098 case SCF_ERROR_DELETED:
5099 warn(emsg_pg_deleted, ient->sc_fmri,
5100 "dependents");
5101 r = EBUSY;
5102 goto out;
5103
5104 case SCF_ERROR_NOT_FOUND:
5105 break;
5106
5107 case SCF_ERROR_NOT_BOUND:
5108 case SCF_ERROR_HANDLE_MISMATCH:
5109 case SCF_ERROR_INVALID_ARGUMENT:
5110 case SCF_ERROR_NOT_SET:
5111 default:
5112 bad_error("scf_transaction_property_"
5113 "change_type", scf_error());
5114 }
5115
5116 if (scf_transaction_property_new(tx, ent, ud_name,
5117 SCF_TYPE_FMRI) != 0) {
5118 switch (scf_error()) {
5119 case SCF_ERROR_CONNECTION_BROKEN:
5120 r = scferror2errno(scf_error());
5121 goto out;
5122
5123 case SCF_ERROR_DELETED:
5124 warn(emsg_pg_deleted, ient->sc_fmri,
5125 "dependents");
5126 r = EBUSY;
5127 goto out;
5128
5129 case SCF_ERROR_EXISTS:
5130 warn(emsg_pg_changed, ient->sc_fmri,
5131 "dependents");
5132 r = EBUSY;
5133 goto out;
5134
5135 case SCF_ERROR_INVALID_ARGUMENT:
5136 case SCF_ERROR_HANDLE_MISMATCH:
5137 case SCF_ERROR_NOT_BOUND:
5138 case SCF_ERROR_NOT_SET:
5139 default:
5140 bad_error("scf_transaction_property_"
5141 "new", scf_error());
5142 }
5143 }
5144 }
5145
5146 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
5147 new_dpt_pgroup->sc_pgroup_fmri) != 0)
5148 /* invalid sc_pgroup_fmri caught above */
5149 bad_error("scf_value_set_from_string",
5150 scf_error());
5151
5152 if (scf_entry_add_value(ent, val) != 0)
5153 bad_error("scf_entry_add_value", scf_error());
5154 break;
5155 }
5156
5157 case -2:
5158 warn(li_corrupt, ient->sc_fmri);
5159 internal_pgroup_free(current_pg);
5160 r = EBADF;
5161 goto out;
5162
5163 case -1:
5164 default:
5165 /* invalid sc_pgroup_fmri caught above */
5166 bad_error("fmri_equal", r);
5167 }
5168
5169 r = 0;
5170
5171 out:
5172 if (old_dpt_pgroup != NULL)
5173 internal_pgroup_free(old_dpt_pgroup);
5174
5175 return (r);
5176 }
5177
5178 /*
5179 * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
5180 * would import it, except it seems to exist in the service anyway. Compare
5181 * the existent dependent with the one we would import, and report any
5182 * differences (if there are none, be silent). prop is the property which
5183 * represents the existent dependent (in the dependents property group) in the
5184 * entity corresponding to ient.
5185 *
5186 * Returns
5187 * 0 - success (Sort of. At least, we can continue importing.)
5188 * ECONNABORTED - repository connection broken
5189 * EBUSY - ancestor of prop was deleted (error printed)
5190 * ENOMEM - out of memory
5191 * EBADF - corrupt property group (error printed)
5192 * EINVAL - new_dpt_pgroup has invalid target (error printed)
5193 */
5194 static int
handle_dependent_conflict(const entity_t * const ient,const scf_property_t * const prop,const pgroup_t * const new_dpt_pgroup)5195 handle_dependent_conflict(const entity_t * const ient,
5196 const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
5197 {
5198 int r;
5199 scf_type_t ty;
5200 scf_error_t scfe;
5201 void *tptr;
5202 int tissvc;
5203 pgroup_t *pgroup;
5204
5205 if (scf_property_get_value(prop, ud_val) != 0) {
5206 switch (scf_error()) {
5207 case SCF_ERROR_CONNECTION_BROKEN:
5208 return (scferror2errno(scf_error()));
5209
5210 case SCF_ERROR_DELETED:
5211 warn(emsg_pg_deleted, ient->sc_fmri,
5212 new_dpt_pgroup->sc_pgroup_name);
5213 return (EBUSY);
5214
5215 case SCF_ERROR_CONSTRAINT_VIOLATED:
5216 case SCF_ERROR_NOT_FOUND:
5217 warn(gettext("Conflict upgrading %s (not importing "
5218 "dependent \"%s\" because it already exists.) "
5219 "Warning: The \"%s/%2$s\" property has more or "
5220 "fewer than one value)).\n"), ient->sc_fmri,
5221 new_dpt_pgroup->sc_pgroup_name, "dependents");
5222 return (0);
5223
5224 case SCF_ERROR_HANDLE_MISMATCH:
5225 case SCF_ERROR_NOT_BOUND:
5226 case SCF_ERROR_NOT_SET:
5227 case SCF_ERROR_PERMISSION_DENIED:
5228 default:
5229 bad_error("scf_property_get_value",
5230 scf_error());
5231 }
5232 }
5233
5234 ty = scf_value_type(ud_val);
5235 assert(ty != SCF_TYPE_INVALID);
5236 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
5237 warn(gettext("Conflict upgrading %s (not importing dependent "
5238 "\"%s\" because it already exists). Warning: The "
5239 "\"%s/%s\" property has unexpected type \"%s\")).\n"),
5240 ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
5241 scf_type_to_string(ty), "dependents");
5242 return (0);
5243 }
5244
5245 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
5246 0)
5247 bad_error("scf_value_get_as_string", scf_error());
5248
5249 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
5250 switch (r) {
5251 case 0:
5252 warn(gettext("Conflict upgrading %s (not importing dependent "
5253 "\"%s\" (target \"%s\") because it already exists with "
5254 "target \"%s\").\n"), ient->sc_fmri,
5255 new_dpt_pgroup->sc_pgroup_name,
5256 new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
5257 return (0);
5258
5259 case 1:
5260 break;
5261
5262 case -1:
5263 warn(gettext("Conflict upgrading %s (not importing dependent "
5264 "\"%s\" because it already exists). Warning: The current "
5265 "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
5266 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5267 return (0);
5268
5269 case -2:
5270 warn(gettext("Dependent \"%s\" of %s has invalid target "
5271 "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
5272 new_dpt_pgroup->sc_pgroup_fmri);
5273 return (EINVAL);
5274
5275 default:
5276 bad_error("fmri_equal", r);
5277 }
5278
5279 /* compare dependency pgs in target */
5280 scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
5281 switch (scfe) {
5282 case SCF_ERROR_NONE:
5283 break;
5284
5285 case SCF_ERROR_NO_MEMORY:
5286 return (ENOMEM);
5287
5288 case SCF_ERROR_NOT_FOUND:
5289 warn(emsg_dpt_dangling, ient->sc_fmri,
5290 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5291 return (0);
5292
5293 case SCF_ERROR_CONSTRAINT_VIOLATED:
5294 case SCF_ERROR_INVALID_ARGUMENT:
5295 default:
5296 bad_error("fmri_to_entity", scfe);
5297 }
5298
5299 r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
5300 ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
5301 switch (r) {
5302 case 0:
5303 break;
5304
5305 case ECONNABORTED:
5306 return (r);
5307
5308 case ECANCELED:
5309 warn(emsg_dpt_dangling, ient->sc_fmri,
5310 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5311 return (0);
5312
5313 case EBADF:
5314 if (tissvc)
5315 warn(gettext("%s has an instance with a \"%s\" "
5316 "snapshot which is missing a snaplevel.\n"),
5317 ud_ctarg, "running");
5318 else
5319 warn(gettext("%s has a \"%s\" snapshot which is "
5320 "missing a snaplevel.\n"), ud_ctarg, "running");
5321 /* FALLTHROUGH */
5322
5323 case ENOENT:
5324 warn(emsg_dpt_no_dep, ient->sc_fmri,
5325 new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5326 new_dpt_pgroup->sc_pgroup_name);
5327 return (0);
5328
5329 case EINVAL:
5330 default:
5331 bad_error("entity_get_running_pg", r);
5332 }
5333
5334 pgroup = internal_pgroup_new();
5335 if (pgroup == NULL)
5336 return (ENOMEM);
5337
5338 r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
5339 switch (r) {
5340 case 0:
5341 break;
5342
5343 case ECONNABORTED:
5344 case EBADF:
5345 case ENOMEM:
5346 internal_pgroup_free(pgroup);
5347 return (r);
5348
5349 case ECANCELED:
5350 warn(emsg_dpt_no_dep, ient->sc_fmri,
5351 new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5352 new_dpt_pgroup->sc_pgroup_name);
5353 internal_pgroup_free(pgroup);
5354 return (0);
5355
5356 case EACCES:
5357 default:
5358 bad_error("load_pg", r);
5359 }
5360
5361 /* report differences */
5362 report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
5363 internal_pgroup_free(pgroup);
5364 return (0);
5365 }
5366
5367 /*
5368 * lipg is a property group in the last-import snapshot of ent, which is an
5369 * scf_service_t or an scf_instance_t (according to ient). If lipg is not in
5370 * ient's pgroups, delete it from ent if it hasn't been customized. If it is
5371 * in ents's property groups, compare and upgrade ent appropriately.
5372 *
5373 * Returns
5374 * 0 - success
5375 * ECONNABORTED - repository connection broken
5376 * ENOMEM - out of memory
5377 * ENOSPC - configd is out of resources
5378 * EINVAL - ient has invalid dependent (error printed)
5379 * - ient has invalid pgroup_t (error printed)
5380 * ECANCELED - ent has been deleted
5381 * ENODEV - entity containing lipg has been deleted
5382 * - entity containing running has been deleted
5383 * EPERM - could not delete pg (permission denied) (error printed)
5384 * - couldn't upgrade dependents (permission denied) (error printed)
5385 * - couldn't import pg (permission denied) (error printed)
5386 * - couldn't upgrade pg (permission denied) (error printed)
5387 * EROFS - could not delete pg (repository read-only)
5388 * - couldn't upgrade dependents (repository read-only)
5389 * - couldn't import pg (repository read-only)
5390 * - couldn't upgrade pg (repository read-only)
5391 * EACCES - could not delete pg (backend access denied)
5392 * - couldn't upgrade dependents (backend access denied)
5393 * - couldn't import pg (backend access denied)
5394 * - couldn't upgrade pg (backend access denied)
5395 * - couldn't read property (backend access denied)
5396 * EBUSY - property group was added (error printed)
5397 * - property group was deleted (error printed)
5398 * - property group changed (error printed)
5399 * - "dependents" pg was added, changed, or deleted (error printed)
5400 * - dependent target deleted (error printed)
5401 * - dependent pg changed (error printed)
5402 * EBADF - imp_snpl is corrupt (error printed)
5403 * - ent has bad pg (error printed)
5404 * EEXIST - dependent collision in target service (error printed)
5405 */
5406 static int
process_old_pg(const scf_propertygroup_t * lipg,entity_t * ient,void * ent,const scf_snaplevel_t * running)5407 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
5408 const scf_snaplevel_t *running)
5409 {
5410 int r;
5411 pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
5412 scf_callback_t cbdata;
5413
5414 const char * const cf_pg_missing =
5415 gettext("Conflict upgrading %s (property group %s is missing)\n");
5416 const char * const deleting =
5417 gettext("%s: Deleting property group \"%s\".\n");
5418
5419 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5420
5421 /* Skip dependent property groups. */
5422 if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
5423 switch (scf_error()) {
5424 case SCF_ERROR_DELETED:
5425 return (ENODEV);
5426
5427 case SCF_ERROR_CONNECTION_BROKEN:
5428 return (ECONNABORTED);
5429
5430 case SCF_ERROR_NOT_SET:
5431 case SCF_ERROR_NOT_BOUND:
5432 default:
5433 bad_error("scf_pg_get_type", scf_error());
5434 }
5435 }
5436
5437 if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
5438 if (scf_pg_get_property(lipg, "external", NULL) == 0)
5439 return (0);
5440
5441 switch (scf_error()) {
5442 case SCF_ERROR_NOT_FOUND:
5443 break;
5444
5445 case SCF_ERROR_CONNECTION_BROKEN:
5446 return (ECONNABORTED);
5447
5448 case SCF_ERROR_DELETED:
5449 return (ENODEV);
5450
5451 case SCF_ERROR_INVALID_ARGUMENT:
5452 case SCF_ERROR_NOT_BOUND:
5453 case SCF_ERROR_HANDLE_MISMATCH:
5454 case SCF_ERROR_NOT_SET:
5455 default:
5456 bad_error("scf_pg_get_property", scf_error());
5457 }
5458 }
5459
5460 /* lookup pg in new properties */
5461 if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
5462 switch (scf_error()) {
5463 case SCF_ERROR_DELETED:
5464 return (ENODEV);
5465
5466 case SCF_ERROR_CONNECTION_BROKEN:
5467 return (ECONNABORTED);
5468
5469 case SCF_ERROR_NOT_SET:
5470 case SCF_ERROR_NOT_BOUND:
5471 default:
5472 bad_error("scf_pg_get_name", scf_error());
5473 }
5474 }
5475
5476 pgrp.sc_pgroup_name = imp_str;
5477 mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
5478
5479 if (mpg != NULL)
5480 mpg->sc_pgroup_seen = 1;
5481
5482 /* Special handling for dependents */
5483 if (strcmp(imp_str, "dependents") == 0)
5484 return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
5485
5486 if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
5487 return (upgrade_manifestfiles(NULL, ient, running, ent));
5488
5489 if (mpg == NULL || mpg->sc_pgroup_delete) {
5490 /* property group was deleted from manifest */
5491 if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5492 switch (scf_error()) {
5493 case SCF_ERROR_NOT_FOUND:
5494 return (0);
5495
5496 case SCF_ERROR_DELETED:
5497 case SCF_ERROR_CONNECTION_BROKEN:
5498 return (scferror2errno(scf_error()));
5499
5500 case SCF_ERROR_INVALID_ARGUMENT:
5501 case SCF_ERROR_HANDLE_MISMATCH:
5502 case SCF_ERROR_NOT_BOUND:
5503 case SCF_ERROR_NOT_SET:
5504 default:
5505 bad_error("entity_get_pg", scf_error());
5506 }
5507 }
5508
5509 if (mpg != NULL && mpg->sc_pgroup_delete) {
5510 if (g_verbose)
5511 warn(deleting, ient->sc_fmri, imp_str);
5512 if (scf_pg_delete(imp_pg2) == 0)
5513 return (0);
5514
5515 switch (scf_error()) {
5516 case SCF_ERROR_DELETED:
5517 return (0);
5518
5519 case SCF_ERROR_CONNECTION_BROKEN:
5520 case SCF_ERROR_BACKEND_READONLY:
5521 case SCF_ERROR_BACKEND_ACCESS:
5522 return (scferror2errno(scf_error()));
5523
5524 case SCF_ERROR_PERMISSION_DENIED:
5525 warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
5526 return (scferror2errno(scf_error()));
5527
5528 case SCF_ERROR_NOT_SET:
5529 default:
5530 bad_error("scf_pg_delete", scf_error());
5531 }
5532 }
5533
5534 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5535 switch (r) {
5536 case 0:
5537 break;
5538
5539 case ECANCELED:
5540 return (ENODEV);
5541
5542 case ECONNABORTED:
5543 case ENOMEM:
5544 case EBADF:
5545 case EACCES:
5546 return (r);
5547
5548 default:
5549 bad_error("load_pg", r);
5550 }
5551
5552 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5553 switch (r) {
5554 case 0:
5555 break;
5556
5557 case ECANCELED:
5558 case ECONNABORTED:
5559 case ENOMEM:
5560 case EBADF:
5561 case EACCES:
5562 internal_pgroup_free(lipg_i);
5563 return (r);
5564
5565 default:
5566 bad_error("load_pg", r);
5567 }
5568
5569 if (pg_equal(lipg_i, curpg_i)) {
5570 if (g_verbose)
5571 warn(deleting, ient->sc_fmri, imp_str);
5572 if (scf_pg_delete(imp_pg2) != 0) {
5573 switch (scf_error()) {
5574 case SCF_ERROR_DELETED:
5575 break;
5576
5577 case SCF_ERROR_CONNECTION_BROKEN:
5578 internal_pgroup_free(lipg_i);
5579 internal_pgroup_free(curpg_i);
5580 return (ECONNABORTED);
5581
5582 case SCF_ERROR_NOT_SET:
5583 case SCF_ERROR_NOT_BOUND:
5584 default:
5585 bad_error("scf_pg_delete", scf_error());
5586 }
5587 }
5588 } else {
5589 report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5590 }
5591
5592 internal_pgroup_free(lipg_i);
5593 internal_pgroup_free(curpg_i);
5594
5595 return (0);
5596 }
5597
5598 /*
5599 * Only dependent pgs can have override set, and we skipped those
5600 * above.
5601 */
5602 assert(!mpg->sc_pgroup_override);
5603
5604 /* compare */
5605 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5606 switch (r) {
5607 case 0:
5608 break;
5609
5610 case ECANCELED:
5611 return (ENODEV);
5612
5613 case ECONNABORTED:
5614 case EBADF:
5615 case ENOMEM:
5616 case EACCES:
5617 return (r);
5618
5619 default:
5620 bad_error("load_pg", r);
5621 }
5622
5623 if (pg_equal(mpg, lipg_i)) {
5624 /* The manifest pg has not changed. Move on. */
5625 r = 0;
5626 goto out;
5627 }
5628
5629 /* upgrade current properties according to lipg & mpg */
5630 if (running != NULL)
5631 r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5632 else
5633 r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5634 if (r != 0) {
5635 switch (scf_error()) {
5636 case SCF_ERROR_CONNECTION_BROKEN:
5637 r = scferror2errno(scf_error());
5638 goto out;
5639
5640 case SCF_ERROR_DELETED:
5641 if (running != NULL)
5642 r = ENODEV;
5643 else
5644 r = ECANCELED;
5645 goto out;
5646
5647 case SCF_ERROR_NOT_FOUND:
5648 break;
5649
5650 case SCF_ERROR_INVALID_ARGUMENT:
5651 case SCF_ERROR_HANDLE_MISMATCH:
5652 case SCF_ERROR_NOT_BOUND:
5653 case SCF_ERROR_NOT_SET:
5654 default:
5655 bad_error("entity_get_pg", scf_error());
5656 }
5657
5658 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5659
5660 r = 0;
5661 goto out;
5662 }
5663
5664 r = load_pg_attrs(imp_pg2, &curpg_i);
5665 switch (r) {
5666 case 0:
5667 break;
5668
5669 case ECANCELED:
5670 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5671 r = 0;
5672 goto out;
5673
5674 case ECONNABORTED:
5675 case ENOMEM:
5676 goto out;
5677
5678 default:
5679 bad_error("load_pg_attrs", r);
5680 }
5681
5682 if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5683 (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5684 internal_pgroup_free(curpg_i);
5685 r = 0;
5686 goto out;
5687 }
5688
5689 internal_pgroup_free(curpg_i);
5690
5691 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5692 switch (r) {
5693 case 0:
5694 break;
5695
5696 case ECANCELED:
5697 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5698 r = 0;
5699 goto out;
5700
5701 case ECONNABORTED:
5702 case EBADF:
5703 case ENOMEM:
5704 case EACCES:
5705 goto out;
5706
5707 default:
5708 bad_error("load_pg", r);
5709 }
5710
5711 if (pg_equal(lipg_i, curpg_i) &&
5712 !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5713 int do_delete = 1;
5714
5715 if (g_verbose)
5716 warn(gettext("%s: Upgrading property group \"%s\".\n"),
5717 ient->sc_fmri, mpg->sc_pgroup_name);
5718
5719 internal_pgroup_free(curpg_i);
5720
5721 if (running != NULL &&
5722 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5723 switch (scf_error()) {
5724 case SCF_ERROR_DELETED:
5725 r = ECANCELED;
5726 goto out;
5727
5728 case SCF_ERROR_NOT_FOUND:
5729 do_delete = 0;
5730 break;
5731
5732 case SCF_ERROR_CONNECTION_BROKEN:
5733 r = scferror2errno(scf_error());
5734 goto out;
5735
5736 case SCF_ERROR_HANDLE_MISMATCH:
5737 case SCF_ERROR_INVALID_ARGUMENT:
5738 case SCF_ERROR_NOT_SET:
5739 case SCF_ERROR_NOT_BOUND:
5740 default:
5741 bad_error("entity_get_pg", scf_error());
5742 }
5743 }
5744
5745 if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5746 switch (scf_error()) {
5747 case SCF_ERROR_DELETED:
5748 break;
5749
5750 case SCF_ERROR_CONNECTION_BROKEN:
5751 case SCF_ERROR_BACKEND_READONLY:
5752 case SCF_ERROR_BACKEND_ACCESS:
5753 r = scferror2errno(scf_error());
5754 goto out;
5755
5756 case SCF_ERROR_PERMISSION_DENIED:
5757 warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5758 ient->sc_fmri);
5759 r = scferror2errno(scf_error());
5760 goto out;
5761
5762 case SCF_ERROR_NOT_SET:
5763 case SCF_ERROR_NOT_BOUND:
5764 default:
5765 bad_error("scf_pg_delete", scf_error());
5766 }
5767 }
5768
5769 cbdata.sc_handle = g_hndl;
5770 cbdata.sc_parent = ent;
5771 cbdata.sc_service = issvc;
5772 cbdata.sc_flags = 0;
5773 cbdata.sc_source_fmri = ient->sc_fmri;
5774 cbdata.sc_target_fmri = ient->sc_fmri;
5775
5776 r = entity_pgroup_import(mpg, &cbdata);
5777 switch (r) {
5778 case UU_WALK_NEXT:
5779 r = 0;
5780 goto out;
5781
5782 case UU_WALK_ERROR:
5783 if (cbdata.sc_err == EEXIST) {
5784 warn(emsg_pg_added, ient->sc_fmri,
5785 mpg->sc_pgroup_name);
5786 r = EBUSY;
5787 } else {
5788 r = cbdata.sc_err;
5789 }
5790 goto out;
5791
5792 default:
5793 bad_error("entity_pgroup_import", r);
5794 }
5795 }
5796
5797 if (running != NULL &&
5798 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5799 switch (scf_error()) {
5800 case SCF_ERROR_CONNECTION_BROKEN:
5801 case SCF_ERROR_DELETED:
5802 r = scferror2errno(scf_error());
5803 goto out;
5804
5805 case SCF_ERROR_NOT_FOUND:
5806 break;
5807
5808 case SCF_ERROR_HANDLE_MISMATCH:
5809 case SCF_ERROR_INVALID_ARGUMENT:
5810 case SCF_ERROR_NOT_SET:
5811 case SCF_ERROR_NOT_BOUND:
5812 default:
5813 bad_error("entity_get_pg", scf_error());
5814 }
5815
5816 cbdata.sc_handle = g_hndl;
5817 cbdata.sc_parent = ent;
5818 cbdata.sc_service = issvc;
5819 cbdata.sc_flags = SCI_FORCE;
5820 cbdata.sc_source_fmri = ient->sc_fmri;
5821 cbdata.sc_target_fmri = ient->sc_fmri;
5822
5823 r = entity_pgroup_import(mpg, &cbdata);
5824 switch (r) {
5825 case UU_WALK_NEXT:
5826 r = 0;
5827 goto out;
5828
5829 case UU_WALK_ERROR:
5830 if (cbdata.sc_err == EEXIST) {
5831 warn(emsg_pg_added, ient->sc_fmri,
5832 mpg->sc_pgroup_name);
5833 r = EBUSY;
5834 } else {
5835 r = cbdata.sc_err;
5836 }
5837 goto out;
5838
5839 default:
5840 bad_error("entity_pgroup_import", r);
5841 }
5842 }
5843
5844 r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5845 internal_pgroup_free(curpg_i);
5846 switch (r) {
5847 case 0:
5848 ient->sc_import_state = IMPORT_PROP_BEGUN;
5849 break;
5850
5851 case ECANCELED:
5852 warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5853 r = EBUSY;
5854 break;
5855
5856 case EPERM:
5857 warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5858 break;
5859
5860 case EBUSY:
5861 warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5862 break;
5863
5864 case ECONNABORTED:
5865 case ENOMEM:
5866 case ENOSPC:
5867 case EROFS:
5868 case EACCES:
5869 case EINVAL:
5870 break;
5871
5872 default:
5873 bad_error("upgrade_pg", r);
5874 }
5875
5876 out:
5877 internal_pgroup_free(lipg_i);
5878 return (r);
5879 }
5880
5881 /*
5882 * Upgrade the properties of ent according to snpl & ient.
5883 *
5884 * Returns
5885 * 0 - success
5886 * ECONNABORTED - repository connection broken
5887 * ENOMEM - out of memory
5888 * ENOSPC - configd is out of resources
5889 * ECANCELED - ent was deleted
5890 * ENODEV - entity containing snpl was deleted
5891 * - entity containing running was deleted
5892 * EBADF - imp_snpl is corrupt (error printed)
5893 * - ent has corrupt pg (error printed)
5894 * - dependent has corrupt pg (error printed)
5895 * - dependent target has a corrupt snapshot (error printed)
5896 * EBUSY - pg was added, changed, or deleted (error printed)
5897 * - dependent target was deleted (error printed)
5898 * - dependent pg changed (error printed)
5899 * EINVAL - invalid property group name (error printed)
5900 * - invalid property name (error printed)
5901 * - invalid value (error printed)
5902 * - ient has invalid pgroup or dependent (error printed)
5903 * EPERM - could not create property group (permission denied) (error printed)
5904 * - could not modify property group (permission denied) (error printed)
5905 * - couldn't delete, upgrade, or import pg or dependent (error printed)
5906 * EROFS - could not create property group (repository read-only)
5907 * - couldn't delete, upgrade, or import pg or dependent
5908 * EACCES - could not create property group (backend access denied)
5909 * - couldn't delete, upgrade, or import pg or dependent
5910 * EEXIST - dependent collision in target service (error printed)
5911 */
5912 static int
upgrade_props(void * ent,scf_snaplevel_t * running,scf_snaplevel_t * snpl,entity_t * ient)5913 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5914 entity_t *ient)
5915 {
5916 pgroup_t *pg, *rpg;
5917 int r;
5918 uu_list_t *pgs = ient->sc_pgroups;
5919
5920 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5921
5922 /* clear sc_sceen for pgs */
5923 if (uu_list_walk(pgs, clear_int,
5924 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5925 bad_error("uu_list_walk", uu_error());
5926
5927 if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5928 switch (scf_error()) {
5929 case SCF_ERROR_DELETED:
5930 return (ENODEV);
5931
5932 case SCF_ERROR_CONNECTION_BROKEN:
5933 return (ECONNABORTED);
5934
5935 case SCF_ERROR_NOT_SET:
5936 case SCF_ERROR_NOT_BOUND:
5937 case SCF_ERROR_HANDLE_MISMATCH:
5938 default:
5939 bad_error("scf_iter_snaplevel_pgs", scf_error());
5940 }
5941 }
5942
5943 for (;;) {
5944 r = scf_iter_next_pg(imp_up_iter, imp_pg);
5945 if (r == 0)
5946 break;
5947 if (r == 1) {
5948 r = process_old_pg(imp_pg, ient, ent, running);
5949 switch (r) {
5950 case 0:
5951 break;
5952
5953 case ECONNABORTED:
5954 case ENOMEM:
5955 case ENOSPC:
5956 case ECANCELED:
5957 case ENODEV:
5958 case EPERM:
5959 case EROFS:
5960 case EACCES:
5961 case EBADF:
5962 case EBUSY:
5963 case EINVAL:
5964 case EEXIST:
5965 return (r);
5966
5967 default:
5968 bad_error("process_old_pg", r);
5969 }
5970 continue;
5971 }
5972 if (r != -1)
5973 bad_error("scf_iter_next_pg", r);
5974
5975 switch (scf_error()) {
5976 case SCF_ERROR_DELETED:
5977 return (ENODEV);
5978
5979 case SCF_ERROR_CONNECTION_BROKEN:
5980 return (ECONNABORTED);
5981
5982 case SCF_ERROR_HANDLE_MISMATCH:
5983 case SCF_ERROR_NOT_BOUND:
5984 case SCF_ERROR_NOT_SET:
5985 case SCF_ERROR_INVALID_ARGUMENT:
5986 default:
5987 bad_error("scf_iter_next_pg", scf_error());
5988 }
5989 }
5990
5991 for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5992 if (pg->sc_pgroup_seen)
5993 continue;
5994
5995 /* pg is new */
5996
5997 if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5998 r = upgrade_dependents(NULL, imp_snpl, ient, running,
5999 ent);
6000 switch (r) {
6001 case 0:
6002 break;
6003
6004 case ECONNABORTED:
6005 case ENOMEM:
6006 case ENOSPC:
6007 case ECANCELED:
6008 case ENODEV:
6009 case EBADF:
6010 case EBUSY:
6011 case EINVAL:
6012 case EPERM:
6013 case EROFS:
6014 case EACCES:
6015 case EEXIST:
6016 return (r);
6017
6018 default:
6019 bad_error("upgrade_dependents", r);
6020 }
6021 continue;
6022 }
6023
6024 if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
6025 r = upgrade_manifestfiles(pg, ient, running, ent);
6026 switch (r) {
6027 case 0:
6028 break;
6029
6030 case ECONNABORTED:
6031 case ENOMEM:
6032 case ENOSPC:
6033 case ECANCELED:
6034 case ENODEV:
6035 case EBADF:
6036 case EBUSY:
6037 case EINVAL:
6038 case EPERM:
6039 case EROFS:
6040 case EACCES:
6041 case EEXIST:
6042 return (r);
6043
6044 default:
6045 bad_error("upgrade_manifestfiles", r);
6046 }
6047 continue;
6048 }
6049
6050 if (running != NULL) {
6051 r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
6052 imp_pg);
6053 } else {
6054 r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
6055 imp_pg);
6056 }
6057 if (r != 0) {
6058 scf_callback_t cbdata;
6059
6060 switch (scf_error()) {
6061 case SCF_ERROR_NOT_FOUND:
6062 break;
6063
6064 case SCF_ERROR_CONNECTION_BROKEN:
6065 return (scferror2errno(scf_error()));
6066
6067 case SCF_ERROR_DELETED:
6068 if (running != NULL)
6069 return (ENODEV);
6070 else
6071 return (scferror2errno(scf_error()));
6072
6073 case SCF_ERROR_INVALID_ARGUMENT:
6074 warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
6075 pg->sc_pgroup_name);
6076 return (EINVAL);
6077
6078 case SCF_ERROR_NOT_SET:
6079 case SCF_ERROR_HANDLE_MISMATCH:
6080 case SCF_ERROR_NOT_BOUND:
6081 default:
6082 bad_error("entity_get_pg", scf_error());
6083 }
6084
6085 /* User doesn't have pg, so import it. */
6086
6087 cbdata.sc_handle = g_hndl;
6088 cbdata.sc_parent = ent;
6089 cbdata.sc_service = issvc;
6090 cbdata.sc_flags = SCI_FORCE;
6091 cbdata.sc_source_fmri = ient->sc_fmri;
6092 cbdata.sc_target_fmri = ient->sc_fmri;
6093
6094 r = entity_pgroup_import(pg, &cbdata);
6095 switch (r) {
6096 case UU_WALK_NEXT:
6097 ient->sc_import_state = IMPORT_PROP_BEGUN;
6098 continue;
6099
6100 case UU_WALK_ERROR:
6101 if (cbdata.sc_err == EEXIST) {
6102 warn(emsg_pg_added, ient->sc_fmri,
6103 pg->sc_pgroup_name);
6104 return (EBUSY);
6105 }
6106 return (cbdata.sc_err);
6107
6108 default:
6109 bad_error("entity_pgroup_import", r);
6110 }
6111 }
6112
6113 /* report differences between pg & current */
6114 r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
6115 switch (r) {
6116 case 0:
6117 break;
6118
6119 case ECANCELED:
6120 warn(emsg_pg_deleted, ient->sc_fmri,
6121 pg->sc_pgroup_name);
6122 return (EBUSY);
6123
6124 case ECONNABORTED:
6125 case EBADF:
6126 case ENOMEM:
6127 case EACCES:
6128 return (r);
6129
6130 default:
6131 bad_error("load_pg", r);
6132 }
6133 report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
6134 internal_pgroup_free(rpg);
6135 rpg = NULL;
6136 }
6137
6138 return (0);
6139 }
6140
6141 /*
6142 * Import an instance. If it doesn't exist, create it. If it has
6143 * a last-import snapshot, upgrade its properties. Finish by updating its
6144 * last-import snapshot. If it doesn't have a last-import snapshot then it
6145 * could have been created for a dependent tag in another manifest. Import the
6146 * new properties. If there's a conflict, don't override, like now?
6147 *
6148 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
6149 * lcbdata->sc_err to
6150 * ECONNABORTED - repository connection broken
6151 * ENOMEM - out of memory
6152 * ENOSPC - svc.configd is out of resources
6153 * EEXIST - dependency collision in dependent service (error printed)
6154 * EPERM - couldn't create temporary instance (permission denied)
6155 * - couldn't import into temporary instance (permission denied)
6156 * - couldn't take snapshot (permission denied)
6157 * - couldn't upgrade properties (permission denied)
6158 * - couldn't import properties (permission denied)
6159 * - couldn't import dependents (permission denied)
6160 * EROFS - couldn't create temporary instance (repository read-only)
6161 * - couldn't import into temporary instance (repository read-only)
6162 * - couldn't upgrade properties (repository read-only)
6163 * - couldn't import properties (repository read-only)
6164 * - couldn't import dependents (repository read-only)
6165 * EACCES - couldn't create temporary instance (backend access denied)
6166 * - couldn't import into temporary instance (backend access denied)
6167 * - couldn't upgrade properties (backend access denied)
6168 * - couldn't import properties (backend access denied)
6169 * - couldn't import dependents (backend access denied)
6170 * EINVAL - invalid instance name (error printed)
6171 * - invalid pgroup_t's (error printed)
6172 * - invalid dependents (error printed)
6173 * EBUSY - temporary service deleted (error printed)
6174 * - temporary instance deleted (error printed)
6175 * - temporary instance changed (error printed)
6176 * - temporary instance already exists (error printed)
6177 * - instance deleted (error printed)
6178 * EBADF - instance has corrupt last-import snapshot (error printed)
6179 * - instance is corrupt (error printed)
6180 * - dependent has corrupt pg (error printed)
6181 * - dependent target has a corrupt snapshot (error printed)
6182 * -1 - unknown libscf error (error printed)
6183 */
6184 static int
lscf_instance_import(void * v,void * pvt)6185 lscf_instance_import(void *v, void *pvt)
6186 {
6187 entity_t *inst = v;
6188 scf_callback_t ctx;
6189 scf_callback_t *lcbdata = pvt;
6190 scf_service_t *rsvc = lcbdata->sc_parent;
6191 int r;
6192 scf_snaplevel_t *running;
6193 int flags = lcbdata->sc_flags;
6194
6195 const char * const emsg_tdel =
6196 gettext("Temporary instance svc:/%s:%s was deleted.\n");
6197 const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
6198 "changed unexpectedly.\n");
6199 const char * const emsg_del = gettext("%s changed unexpectedly "
6200 "(instance \"%s\" was deleted.)\n");
6201 const char * const emsg_badsnap = gettext(
6202 "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
6203
6204 /*
6205 * prepare last-import snapshot:
6206 * create temporary instance (service was precreated)
6207 * populate with properties from bundle
6208 * take snapshot
6209 */
6210 if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
6211 switch (scf_error()) {
6212 case SCF_ERROR_CONNECTION_BROKEN:
6213 case SCF_ERROR_NO_RESOURCES:
6214 case SCF_ERROR_BACKEND_READONLY:
6215 case SCF_ERROR_BACKEND_ACCESS:
6216 return (stash_scferror(lcbdata));
6217
6218 case SCF_ERROR_EXISTS:
6219 warn(gettext("Temporary service svc:/%s "
6220 "changed unexpectedly (instance \"%s\" added).\n"),
6221 imp_tsname, inst->sc_name);
6222 lcbdata->sc_err = EBUSY;
6223 return (UU_WALK_ERROR);
6224
6225 case SCF_ERROR_DELETED:
6226 warn(gettext("Temporary service svc:/%s "
6227 "was deleted unexpectedly.\n"), imp_tsname);
6228 lcbdata->sc_err = EBUSY;
6229 return (UU_WALK_ERROR);
6230
6231 case SCF_ERROR_INVALID_ARGUMENT:
6232 warn(gettext("Invalid instance name \"%s\".\n"),
6233 inst->sc_name);
6234 return (stash_scferror(lcbdata));
6235
6236 case SCF_ERROR_PERMISSION_DENIED:
6237 warn(gettext("Could not create temporary instance "
6238 "\"%s\" in svc:/%s (permission denied).\n"),
6239 inst->sc_name, imp_tsname);
6240 return (stash_scferror(lcbdata));
6241
6242 case SCF_ERROR_HANDLE_MISMATCH:
6243 case SCF_ERROR_NOT_BOUND:
6244 case SCF_ERROR_NOT_SET:
6245 default:
6246 bad_error("scf_service_add_instance", scf_error());
6247 }
6248 }
6249
6250 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6251 inst->sc_name);
6252 if (r < 0)
6253 bad_error("snprintf", errno);
6254
6255 r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
6256 lcbdata->sc_flags | SCI_NOENABLED);
6257 switch (r) {
6258 case 0:
6259 break;
6260
6261 case ECANCELED:
6262 warn(emsg_tdel, imp_tsname, inst->sc_name);
6263 lcbdata->sc_err = EBUSY;
6264 r = UU_WALK_ERROR;
6265 goto deltemp;
6266
6267 case EEXIST:
6268 warn(emsg_tchg, imp_tsname, inst->sc_name);
6269 lcbdata->sc_err = EBUSY;
6270 r = UU_WALK_ERROR;
6271 goto deltemp;
6272
6273 case ECONNABORTED:
6274 goto connaborted;
6275
6276 case ENOMEM:
6277 case ENOSPC:
6278 case EPERM:
6279 case EROFS:
6280 case EACCES:
6281 case EINVAL:
6282 case EBUSY:
6283 lcbdata->sc_err = r;
6284 r = UU_WALK_ERROR;
6285 goto deltemp;
6286
6287 default:
6288 bad_error("lscf_import_instance_pgs", r);
6289 }
6290
6291 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6292 inst->sc_name);
6293 if (r < 0)
6294 bad_error("snprintf", errno);
6295
6296 ctx.sc_handle = lcbdata->sc_handle;
6297 ctx.sc_parent = imp_tinst;
6298 ctx.sc_service = 0;
6299 ctx.sc_source_fmri = inst->sc_fmri;
6300 ctx.sc_target_fmri = imp_str;
6301 if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
6302 UU_DEFAULT) != 0) {
6303 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6304 bad_error("uu_list_walk", uu_error());
6305
6306 switch (ctx.sc_err) {
6307 case ECONNABORTED:
6308 goto connaborted;
6309
6310 case ECANCELED:
6311 warn(emsg_tdel, imp_tsname, inst->sc_name);
6312 lcbdata->sc_err = EBUSY;
6313 break;
6314
6315 case EEXIST:
6316 warn(emsg_tchg, imp_tsname, inst->sc_name);
6317 lcbdata->sc_err = EBUSY;
6318 break;
6319
6320 default:
6321 lcbdata->sc_err = ctx.sc_err;
6322 }
6323 r = UU_WALK_ERROR;
6324 goto deltemp;
6325 }
6326
6327 if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
6328 inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
6329 switch (scf_error()) {
6330 case SCF_ERROR_CONNECTION_BROKEN:
6331 goto connaborted;
6332
6333 case SCF_ERROR_NO_RESOURCES:
6334 r = stash_scferror(lcbdata);
6335 goto deltemp;
6336
6337 case SCF_ERROR_EXISTS:
6338 warn(emsg_tchg, imp_tsname, inst->sc_name);
6339 lcbdata->sc_err = EBUSY;
6340 r = UU_WALK_ERROR;
6341 goto deltemp;
6342
6343 case SCF_ERROR_PERMISSION_DENIED:
6344 warn(gettext("Could not take \"%s\" snapshot of %s "
6345 "(permission denied).\n"), snap_lastimport,
6346 imp_str);
6347 r = stash_scferror(lcbdata);
6348 goto deltemp;
6349
6350 default:
6351 scfwarn();
6352 lcbdata->sc_err = -1;
6353 r = UU_WALK_ERROR;
6354 goto deltemp;
6355
6356 case SCF_ERROR_HANDLE_MISMATCH:
6357 case SCF_ERROR_INVALID_ARGUMENT:
6358 case SCF_ERROR_NOT_SET:
6359 bad_error("_scf_snapshot_take_new_named", scf_error());
6360 }
6361 }
6362
6363 if (lcbdata->sc_flags & SCI_FRESH)
6364 goto fresh;
6365
6366 if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
6367 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6368 imp_lisnap) != 0) {
6369 switch (scf_error()) {
6370 case SCF_ERROR_DELETED:
6371 warn(emsg_del, inst->sc_parent->sc_fmri,
6372 inst->sc_name);
6373 lcbdata->sc_err = EBUSY;
6374 r = UU_WALK_ERROR;
6375 goto deltemp;
6376
6377 case SCF_ERROR_NOT_FOUND:
6378 flags |= SCI_FORCE;
6379 goto nosnap;
6380
6381 case SCF_ERROR_CONNECTION_BROKEN:
6382 goto connaborted;
6383
6384 case SCF_ERROR_INVALID_ARGUMENT:
6385 case SCF_ERROR_HANDLE_MISMATCH:
6386 case SCF_ERROR_NOT_BOUND:
6387 case SCF_ERROR_NOT_SET:
6388 default:
6389 bad_error("scf_instance_get_snapshot",
6390 scf_error());
6391 }
6392 }
6393
6394 /* upgrade */
6395
6396 /*
6397 * compare new properties with last-import properties
6398 * upgrade current properties
6399 */
6400 /* clear sc_sceen for pgs */
6401 if (uu_list_walk(inst->sc_pgroups, clear_int,
6402 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
6403 0)
6404 bad_error("uu_list_walk", uu_error());
6405
6406 r = get_snaplevel(imp_lisnap, 0, imp_snpl);
6407 switch (r) {
6408 case 0:
6409 break;
6410
6411 case ECONNABORTED:
6412 goto connaborted;
6413
6414 case ECANCELED:
6415 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6416 lcbdata->sc_err = EBUSY;
6417 r = UU_WALK_ERROR;
6418 goto deltemp;
6419
6420 case ENOENT:
6421 warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
6422 lcbdata->sc_err = EBADF;
6423 r = UU_WALK_ERROR;
6424 goto deltemp;
6425
6426 default:
6427 bad_error("get_snaplevel", r);
6428 }
6429
6430 if (scf_instance_get_snapshot(imp_inst, snap_running,
6431 imp_rsnap) != 0) {
6432 switch (scf_error()) {
6433 case SCF_ERROR_DELETED:
6434 warn(emsg_del, inst->sc_parent->sc_fmri,
6435 inst->sc_name);
6436 lcbdata->sc_err = EBUSY;
6437 r = UU_WALK_ERROR;
6438 goto deltemp;
6439
6440 case SCF_ERROR_NOT_FOUND:
6441 break;
6442
6443 case SCF_ERROR_CONNECTION_BROKEN:
6444 goto connaborted;
6445
6446 case SCF_ERROR_INVALID_ARGUMENT:
6447 case SCF_ERROR_HANDLE_MISMATCH:
6448 case SCF_ERROR_NOT_BOUND:
6449 case SCF_ERROR_NOT_SET:
6450 default:
6451 bad_error("scf_instance_get_snapshot",
6452 scf_error());
6453 }
6454
6455 running = NULL;
6456 } else {
6457 r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
6458 switch (r) {
6459 case 0:
6460 running = imp_rsnpl;
6461 break;
6462
6463 case ECONNABORTED:
6464 goto connaborted;
6465
6466 case ECANCELED:
6467 warn(emsg_del, inst->sc_parent->sc_fmri,
6468 inst->sc_name);
6469 lcbdata->sc_err = EBUSY;
6470 r = UU_WALK_ERROR;
6471 goto deltemp;
6472
6473 case ENOENT:
6474 warn(emsg_badsnap, snap_running, inst->sc_fmri);
6475 lcbdata->sc_err = EBADF;
6476 r = UU_WALK_ERROR;
6477 goto deltemp;
6478
6479 default:
6480 bad_error("get_snaplevel", r);
6481 }
6482 }
6483
6484 r = upgrade_props(imp_inst, running, imp_snpl, inst);
6485 switch (r) {
6486 case 0:
6487 break;
6488
6489 case ECANCELED:
6490 case ENODEV:
6491 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6492 lcbdata->sc_err = EBUSY;
6493 r = UU_WALK_ERROR;
6494 goto deltemp;
6495
6496 case ECONNABORTED:
6497 goto connaborted;
6498
6499 case ENOMEM:
6500 case ENOSPC:
6501 case EBADF:
6502 case EBUSY:
6503 case EINVAL:
6504 case EPERM:
6505 case EROFS:
6506 case EACCES:
6507 case EEXIST:
6508 lcbdata->sc_err = r;
6509 r = UU_WALK_ERROR;
6510 goto deltemp;
6511
6512 default:
6513 bad_error("upgrade_props", r);
6514 }
6515
6516 inst->sc_import_state = IMPORT_PROP_DONE;
6517 } else {
6518 switch (scf_error()) {
6519 case SCF_ERROR_CONNECTION_BROKEN:
6520 goto connaborted;
6521
6522 case SCF_ERROR_NOT_FOUND:
6523 break;
6524
6525 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
6526 case SCF_ERROR_HANDLE_MISMATCH:
6527 case SCF_ERROR_NOT_BOUND:
6528 case SCF_ERROR_NOT_SET:
6529 default:
6530 bad_error("scf_service_get_instance", scf_error());
6531 }
6532
6533 fresh:
6534 /* create instance */
6535 if (scf_service_add_instance(rsvc, inst->sc_name,
6536 imp_inst) != 0) {
6537 switch (scf_error()) {
6538 case SCF_ERROR_CONNECTION_BROKEN:
6539 goto connaborted;
6540
6541 case SCF_ERROR_NO_RESOURCES:
6542 case SCF_ERROR_BACKEND_READONLY:
6543 case SCF_ERROR_BACKEND_ACCESS:
6544 r = stash_scferror(lcbdata);
6545 goto deltemp;
6546
6547 case SCF_ERROR_EXISTS:
6548 warn(gettext("%s changed unexpectedly "
6549 "(instance \"%s\" added).\n"),
6550 inst->sc_parent->sc_fmri, inst->sc_name);
6551 lcbdata->sc_err = EBUSY;
6552 r = UU_WALK_ERROR;
6553 goto deltemp;
6554
6555 case SCF_ERROR_PERMISSION_DENIED:
6556 warn(gettext("Could not create \"%s\" instance "
6557 "in %s (permission denied).\n"),
6558 inst->sc_name, inst->sc_parent->sc_fmri);
6559 r = stash_scferror(lcbdata);
6560 goto deltemp;
6561
6562 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
6563 case SCF_ERROR_HANDLE_MISMATCH:
6564 case SCF_ERROR_NOT_BOUND:
6565 case SCF_ERROR_NOT_SET:
6566 default:
6567 bad_error("scf_service_add_instance",
6568 scf_error());
6569 }
6570 }
6571
6572 nosnap:
6573 /*
6574 * Create a last-import snapshot to serve as an attachment
6575 * point for the real one from the temporary instance. Since
6576 * the contents is irrelevant, take it now, while the instance
6577 * is empty, to minimize svc.configd's work.
6578 */
6579 if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6580 imp_lisnap) != 0) {
6581 switch (scf_error()) {
6582 case SCF_ERROR_CONNECTION_BROKEN:
6583 goto connaborted;
6584
6585 case SCF_ERROR_NO_RESOURCES:
6586 r = stash_scferror(lcbdata);
6587 goto deltemp;
6588
6589 case SCF_ERROR_EXISTS:
6590 warn(gettext("%s changed unexpectedly "
6591 "(snapshot \"%s\" added).\n"),
6592 inst->sc_fmri, snap_lastimport);
6593 lcbdata->sc_err = EBUSY;
6594 r = UU_WALK_ERROR;
6595 goto deltemp;
6596
6597 case SCF_ERROR_PERMISSION_DENIED:
6598 warn(gettext("Could not take \"%s\" snapshot "
6599 "of %s (permission denied).\n"),
6600 snap_lastimport, inst->sc_fmri);
6601 r = stash_scferror(lcbdata);
6602 goto deltemp;
6603
6604 default:
6605 scfwarn();
6606 lcbdata->sc_err = -1;
6607 r = UU_WALK_ERROR;
6608 goto deltemp;
6609
6610 case SCF_ERROR_NOT_SET:
6611 case SCF_ERROR_INTERNAL:
6612 case SCF_ERROR_INVALID_ARGUMENT:
6613 case SCF_ERROR_HANDLE_MISMATCH:
6614 bad_error("_scf_snapshot_take_new",
6615 scf_error());
6616 }
6617 }
6618
6619 if (li_only)
6620 goto lionly;
6621
6622 inst->sc_import_state = IMPORT_PROP_BEGUN;
6623
6624 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6625 flags);
6626 switch (r) {
6627 case 0:
6628 break;
6629
6630 case ECONNABORTED:
6631 goto connaborted;
6632
6633 case ECANCELED:
6634 warn(gettext("%s changed unexpectedly "
6635 "(instance \"%s\" deleted).\n"),
6636 inst->sc_parent->sc_fmri, inst->sc_name);
6637 lcbdata->sc_err = EBUSY;
6638 r = UU_WALK_ERROR;
6639 goto deltemp;
6640
6641 case EEXIST:
6642 warn(gettext("%s changed unexpectedly "
6643 "(property group added).\n"), inst->sc_fmri);
6644 lcbdata->sc_err = EBUSY;
6645 r = UU_WALK_ERROR;
6646 goto deltemp;
6647
6648 default:
6649 lcbdata->sc_err = r;
6650 r = UU_WALK_ERROR;
6651 goto deltemp;
6652
6653 case EINVAL: /* caught above */
6654 bad_error("lscf_import_instance_pgs", r);
6655 }
6656
6657 ctx.sc_parent = imp_inst;
6658 ctx.sc_service = 0;
6659 ctx.sc_trans = NULL;
6660 ctx.sc_flags = 0;
6661 if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6662 &ctx, UU_DEFAULT) != 0) {
6663 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6664 bad_error("uu_list_walk", uu_error());
6665
6666 if (ctx.sc_err == ECONNABORTED)
6667 goto connaborted;
6668 lcbdata->sc_err = ctx.sc_err;
6669 r = UU_WALK_ERROR;
6670 goto deltemp;
6671 }
6672
6673 inst->sc_import_state = IMPORT_PROP_DONE;
6674
6675 if (g_verbose)
6676 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6677 snap_initial, inst->sc_fmri);
6678 r = take_snap(imp_inst, snap_initial, imp_snap);
6679 switch (r) {
6680 case 0:
6681 break;
6682
6683 case ECONNABORTED:
6684 goto connaborted;
6685
6686 case ENOSPC:
6687 case -1:
6688 lcbdata->sc_err = r;
6689 r = UU_WALK_ERROR;
6690 goto deltemp;
6691
6692 case ECANCELED:
6693 warn(gettext("%s changed unexpectedly "
6694 "(instance %s deleted).\n"),
6695 inst->sc_parent->sc_fmri, inst->sc_name);
6696 lcbdata->sc_err = r;
6697 r = UU_WALK_ERROR;
6698 goto deltemp;
6699
6700 case EPERM:
6701 warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6702 lcbdata->sc_err = r;
6703 r = UU_WALK_ERROR;
6704 goto deltemp;
6705
6706 default:
6707 bad_error("take_snap", r);
6708 }
6709 }
6710
6711 lionly:
6712 if (lcbdata->sc_flags & SCI_NOSNAP)
6713 goto deltemp;
6714
6715 /* transfer snapshot from temporary instance */
6716 if (g_verbose)
6717 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6718 snap_lastimport, inst->sc_fmri);
6719 if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6720 switch (scf_error()) {
6721 case SCF_ERROR_CONNECTION_BROKEN:
6722 goto connaborted;
6723
6724 case SCF_ERROR_NO_RESOURCES:
6725 r = stash_scferror(lcbdata);
6726 goto deltemp;
6727
6728 case SCF_ERROR_PERMISSION_DENIED:
6729 warn(gettext("Could not take \"%s\" snapshot for %s "
6730 "(permission denied).\n"), snap_lastimport,
6731 inst->sc_fmri);
6732 r = stash_scferror(lcbdata);
6733 goto deltemp;
6734
6735 case SCF_ERROR_NOT_SET:
6736 case SCF_ERROR_HANDLE_MISMATCH:
6737 default:
6738 bad_error("_scf_snapshot_attach", scf_error());
6739 }
6740 }
6741
6742 inst->sc_import_state = IMPORT_COMPLETE;
6743
6744 r = UU_WALK_NEXT;
6745
6746 deltemp:
6747 /* delete temporary instance */
6748 if (scf_instance_delete(imp_tinst) != 0) {
6749 switch (scf_error()) {
6750 case SCF_ERROR_DELETED:
6751 break;
6752
6753 case SCF_ERROR_CONNECTION_BROKEN:
6754 goto connaborted;
6755
6756 case SCF_ERROR_NOT_SET:
6757 case SCF_ERROR_NOT_BOUND:
6758 default:
6759 bad_error("scf_instance_delete", scf_error());
6760 }
6761 }
6762
6763 return (r);
6764
6765 connaborted:
6766 warn(gettext("Could not delete svc:/%s:%s "
6767 "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6768 lcbdata->sc_err = ECONNABORTED;
6769 return (UU_WALK_ERROR);
6770 }
6771
6772 /*
6773 * When an instance is imported we end up telling configd about it. Once we tell
6774 * configd about these changes, startd eventually notices. If this is a new
6775 * instance, the manifest may not specify the SCF_PG_RESTARTER (restarter)
6776 * property group. However, many of the other tools expect that this property
6777 * group exists and has certain values.
6778 *
6779 * These values are added asynchronously by startd. We should not return from
6780 * this routine until we can verify that the property group we need is there.
6781 *
6782 * Before we go ahead and verify this, we have to ask ourselves an important
6783 * question: Is the early manifest service currently running? Because if it is
6784 * running and it has invoked us, then the service will never get a restarter
6785 * property because svc.startd is blocked on EMI finishing before it lets itself
6786 * fully connect to svc.configd. Of course, this means that this race condition
6787 * is in fact impossible to 100% eliminate.
6788 *
6789 * svc.startd makes sure that EMI only runs once and has succeeded by checking
6790 * the state of the EMI instance. If it is online it bails out and makes sure
6791 * that it doesn't run again. In this case, we're going to do something similar,
6792 * only if the state is online, then we're going to actually verify. EMI always
6793 * has to be present, but it can be explicitly disabled to reduce the amount of
6794 * damage it can cause. If EMI has been disabled then we no longer have to worry
6795 * about the implicit race condition and can go ahead and check things. If EMI
6796 * is in some state that isn't online or disabled and isn't runinng, then we
6797 * assume that things are rather bad and we're not going to get in your way,
6798 * even if the rest of SMF does.
6799 *
6800 * Returns 0 on success or returns an errno.
6801 */
6802 #ifndef NATIVE_BUILD
6803 static int
lscf_instance_verify(scf_scope_t * scope,entity_t * svc,entity_t * inst)6804 lscf_instance_verify(scf_scope_t *scope, entity_t *svc, entity_t *inst)
6805 {
6806 int ret, err;
6807 struct timespec ts;
6808 char *emi_state;
6809
6810 /*
6811 * smf_get_state does not distinguish between its different failure
6812 * modes: memory allocation failures, SMF internal failures, and a lack
6813 * of EMI entirely because it's been removed. In these cases, we're
6814 * going to be conservative and opt to say that if we don't know, better
6815 * to not block import or falsely warn to the user.
6816 */
6817 if ((emi_state = smf_get_state(SCF_INSTANCE_EMI)) == NULL) {
6818 return (0);
6819 }
6820
6821 /*
6822 * As per the block comment for this function check the state of EMI
6823 */
6824 if (strcmp(emi_state, SCF_STATE_STRING_ONLINE) != 0 &&
6825 strcmp(emi_state, SCF_STATE_STRING_DISABLED) != 0) {
6826 warn(gettext("Not validating instance %s:%s because EMI's "
6827 "state is %s\n"), svc->sc_name, inst->sc_name, emi_state);
6828 free(emi_state);
6829 return (0);
6830 }
6831
6832 free(emi_state);
6833
6834 /*
6835 * First we have to get the property.
6836 */
6837 if ((ret = scf_scope_get_service(scope, svc->sc_name, imp_svc)) != 0) {
6838 ret = scf_error();
6839 warn(gettext("Failed to look up service: %s\n"), svc->sc_name);
6840 return (ret);
6841 }
6842
6843 /*
6844 * We should always be able to get the instance. It should already
6845 * exist because we just created it or got it. There probably is a
6846 * slim chance that someone may have come in and deleted it though from
6847 * under us.
6848 */
6849 if ((ret = scf_service_get_instance(imp_svc, inst->sc_name, imp_inst))
6850 != 0) {
6851 ret = scf_error();
6852 warn(gettext("Failed to verify instance: %s\n"), inst->sc_name);
6853 switch (ret) {
6854 case SCF_ERROR_DELETED:
6855 err = ENODEV;
6856 break;
6857 case SCF_ERROR_CONNECTION_BROKEN:
6858 warn(gettext("Lost repository connection\n"));
6859 err = ECONNABORTED;
6860 break;
6861 case SCF_ERROR_NOT_FOUND:
6862 warn(gettext("Instance \"%s\" disappeared out from "
6863 "under us.\n"), inst->sc_name);
6864 err = ENOENT;
6865 break;
6866 default:
6867 bad_error("scf_service_get_instance", ret);
6868 }
6869
6870 return (err);
6871 }
6872
6873 /*
6874 * An astute observer may want to use _scf_wait_pg which would notify us
6875 * of a property group change, unfortunately that does not work if the
6876 * property group in question does not exist. So instead we have to
6877 * manually poll and ask smf the best way to get to it.
6878 */
6879 while ((ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg))
6880 != SCF_SUCCESS) {
6881 ret = scf_error();
6882 if (ret != SCF_ERROR_NOT_FOUND) {
6883 warn(gettext("Failed to get restarter property "
6884 "group for instance: %s\n"), inst->sc_name);
6885 switch (ret) {
6886 case SCF_ERROR_DELETED:
6887 err = ENODEV;
6888 break;
6889 case SCF_ERROR_CONNECTION_BROKEN:
6890 warn(gettext("Lost repository connection\n"));
6891 err = ECONNABORTED;
6892 break;
6893 default:
6894 bad_error("scf_service_get_instance", ret);
6895 }
6896
6897 return (err);
6898 }
6899
6900 ts.tv_sec = pg_timeout / NANOSEC;
6901 ts.tv_nsec = pg_timeout % NANOSEC;
6902
6903 (void) nanosleep(&ts, NULL);
6904 }
6905
6906 /*
6907 * svcadm also expects that the SCF_PROPERTY_STATE property is present.
6908 * So in addition to the property group being present, we need to wait
6909 * for the property to be there in some form.
6910 *
6911 * Note that a property group is a frozen snapshot in time. To properly
6912 * get beyond this, you have to refresh the property group each time.
6913 */
6914 while ((ret = scf_pg_get_property(imp_pg, SCF_PROPERTY_STATE,
6915 imp_prop)) != 0) {
6916
6917 ret = scf_error();
6918 if (ret != SCF_ERROR_NOT_FOUND) {
6919 warn(gettext("Failed to get property %s from the "
6920 "restarter property group of instance %s\n"),
6921 SCF_PROPERTY_STATE, inst->sc_name);
6922 switch (ret) {
6923 case SCF_ERROR_CONNECTION_BROKEN:
6924 warn(gettext("Lost repository connection\n"));
6925 err = ECONNABORTED;
6926 break;
6927 case SCF_ERROR_DELETED:
6928 err = ENODEV;
6929 break;
6930 default:
6931 bad_error("scf_pg_get_property", ret);
6932 }
6933
6934 return (err);
6935 }
6936
6937 ts.tv_sec = pg_timeout / NANOSEC;
6938 ts.tv_nsec = pg_timeout % NANOSEC;
6939
6940 (void) nanosleep(&ts, NULL);
6941
6942 ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg);
6943 if (ret != SCF_SUCCESS) {
6944 warn(gettext("Failed to get restarter property "
6945 "group for instance: %s\n"), inst->sc_name);
6946 switch (ret) {
6947 case SCF_ERROR_DELETED:
6948 err = ENODEV;
6949 break;
6950 case SCF_ERROR_CONNECTION_BROKEN:
6951 warn(gettext("Lost repository connection\n"));
6952 err = ECONNABORTED;
6953 break;
6954 default:
6955 bad_error("scf_service_get_instance", ret);
6956 }
6957
6958 return (err);
6959 }
6960 }
6961
6962 /*
6963 * We don't have to free the property groups or other values that we got
6964 * because we stored them in global variables that are allocated and
6965 * freed by the routines that call into these functions. Unless of
6966 * course the rest of the code here that we are basing this on is
6967 * mistaken.
6968 */
6969 return (0);
6970 }
6971 #endif
6972
6973 /*
6974 * If the service is missing, create it, import its properties, and import the
6975 * instances. Since the service is brand new, it should be empty, and if we
6976 * run into any existing entities (SCF_ERROR_EXISTS), abort.
6977 *
6978 * If the service exists, we want to upgrade its properties and import the
6979 * instances. Upgrade requires a last-import snapshot, though, which are
6980 * children of instances, so first we'll have to go through the instances
6981 * looking for a last-import snapshot. If we don't find one then we'll just
6982 * override-import the service properties (but don't delete existing
6983 * properties: another service might have declared us as a dependent). Before
6984 * we change anything, though, we want to take the previous snapshots. We
6985 * also give lscf_instance_import() a leg up on taking last-import snapshots
6986 * by importing the manifest's service properties into a temporary service.
6987 *
6988 * On success, returns UU_WALK_NEXT. On failure, returns UU_WALK_ERROR and
6989 * sets lcbdata->sc_err to
6990 * ECONNABORTED - repository connection broken
6991 * ENOMEM - out of memory
6992 * ENOSPC - svc.configd is out of resources
6993 * EPERM - couldn't create temporary service (error printed)
6994 * - couldn't import into temp service (error printed)
6995 * - couldn't create service (error printed)
6996 * - couldn't import dependent (error printed)
6997 * - couldn't take snapshot (error printed)
6998 * - couldn't create instance (error printed)
6999 * - couldn't create, modify, or delete pg (error printed)
7000 * - couldn't create, modify, or delete dependent (error printed)
7001 * - couldn't import instance (error printed)
7002 * EROFS - couldn't create temporary service (repository read-only)
7003 * - couldn't import into temporary service (repository read-only)
7004 * - couldn't create service (repository read-only)
7005 * - couldn't import dependent (repository read-only)
7006 * - couldn't create instance (repository read-only)
7007 * - couldn't create, modify, or delete pg or dependent
7008 * - couldn't import instance (repository read-only)
7009 * EACCES - couldn't create temporary service (backend access denied)
7010 * - couldn't import into temporary service (backend access denied)
7011 * - couldn't create service (backend access denied)
7012 * - couldn't import dependent (backend access denied)
7013 * - couldn't create instance (backend access denied)
7014 * - couldn't create, modify, or delete pg or dependent
7015 * - couldn't import instance (backend access denied)
7016 * EINVAL - service name is invalid (error printed)
7017 * - service name is too long (error printed)
7018 * - s has invalid pgroup (error printed)
7019 * - s has invalid dependent (error printed)
7020 * - instance name is invalid (error printed)
7021 * - instance entity_t is invalid (error printed)
7022 * EEXIST - couldn't create temporary service (already exists) (error printed)
7023 * - couldn't import dependent (dependency pg already exists) (printed)
7024 * - dependency collision in dependent service (error printed)
7025 * EBUSY - temporary service deleted (error printed)
7026 * - property group added to temporary service (error printed)
7027 * - new property group changed or was deleted (error printed)
7028 * - service was added unexpectedly (error printed)
7029 * - service was deleted unexpectedly (error printed)
7030 * - property group added to new service (error printed)
7031 * - instance added unexpectedly (error printed)
7032 * - instance deleted unexpectedly (error printed)
7033 * - dependent service deleted unexpectedly (error printed)
7034 * - pg was added, changed, or deleted (error printed)
7035 * - dependent pg changed (error printed)
7036 * - temporary instance added, changed, or deleted (error printed)
7037 * EBADF - a last-import snapshot is corrupt (error printed)
7038 * - the service is corrupt (error printed)
7039 * - a dependent is corrupt (error printed)
7040 * - an instance is corrupt (error printed)
7041 * - an instance has a corrupt last-import snapshot (error printed)
7042 * - dependent target has a corrupt snapshot (error printed)
7043 * -1 - unknown libscf error (error printed)
7044 */
7045 static int
lscf_service_import(void * v,void * pvt)7046 lscf_service_import(void *v, void *pvt)
7047 {
7048 entity_t *s = v;
7049 scf_callback_t cbdata;
7050 scf_callback_t *lcbdata = pvt;
7051 scf_scope_t *scope = lcbdata->sc_parent;
7052 entity_t *inst, linst;
7053 int r;
7054 int fresh = 0;
7055 scf_snaplevel_t *running;
7056 int have_ge = 0;
7057 boolean_t retried = B_FALSE;
7058
7059 const char * const ts_deleted = gettext("Temporary service svc:/%s "
7060 "was deleted unexpectedly.\n");
7061 const char * const ts_pg_added = gettext("Temporary service svc:/%s "
7062 "changed unexpectedly (property group added).\n");
7063 const char * const s_deleted =
7064 gettext("%s was deleted unexpectedly.\n");
7065 const char * const i_deleted =
7066 gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
7067 const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
7068 "is corrupt (missing service snaplevel).\n");
7069 const char * const s_mfile_upd =
7070 gettext("Unable to update the manifest file connection "
7071 "for %s\n");
7072
7073 li_only = 0;
7074 /* Validate the service name */
7075 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7076 switch (scf_error()) {
7077 case SCF_ERROR_CONNECTION_BROKEN:
7078 return (stash_scferror(lcbdata));
7079
7080 case SCF_ERROR_INVALID_ARGUMENT:
7081 warn(gettext("\"%s\" is an invalid service name. "
7082 "Cannot import.\n"), s->sc_name);
7083 return (stash_scferror(lcbdata));
7084
7085 case SCF_ERROR_NOT_FOUND:
7086 break;
7087
7088 case SCF_ERROR_HANDLE_MISMATCH:
7089 case SCF_ERROR_NOT_BOUND:
7090 case SCF_ERROR_NOT_SET:
7091 default:
7092 bad_error("scf_scope_get_service", scf_error());
7093 }
7094 }
7095
7096 /* create temporary service */
7097 /*
7098 * the size of the buffer was reduced to max_scf_name_len to prevent
7099 * hitting bug 6681151. After the bug fix, the size of the buffer
7100 * should be restored to its original value (max_scf_name_len +1)
7101 */
7102 r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
7103 if (r < 0)
7104 bad_error("snprintf", errno);
7105 if (r > max_scf_name_len) {
7106 warn(gettext(
7107 "Service name \"%s\" is too long. Cannot import.\n"),
7108 s->sc_name);
7109 lcbdata->sc_err = EINVAL;
7110 return (UU_WALK_ERROR);
7111 }
7112
7113 retry:
7114 if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
7115 switch (scf_error()) {
7116 case SCF_ERROR_CONNECTION_BROKEN:
7117 case SCF_ERROR_NO_RESOURCES:
7118 case SCF_ERROR_BACKEND_READONLY:
7119 case SCF_ERROR_BACKEND_ACCESS:
7120 return (stash_scferror(lcbdata));
7121
7122 case SCF_ERROR_EXISTS:
7123 if (!retried) {
7124 lscf_delete(imp_tsname, 0);
7125 retried = B_TRUE;
7126 goto retry;
7127 }
7128 warn(gettext(
7129 "Temporary service \"%s\" must be deleted before "
7130 "this manifest can be imported.\n"), imp_tsname);
7131 return (stash_scferror(lcbdata));
7132
7133 case SCF_ERROR_PERMISSION_DENIED:
7134 warn(gettext("Could not create temporary service "
7135 "\"%s\" (permission denied).\n"), imp_tsname);
7136 return (stash_scferror(lcbdata));
7137
7138 case SCF_ERROR_INVALID_ARGUMENT:
7139 case SCF_ERROR_HANDLE_MISMATCH:
7140 case SCF_ERROR_NOT_BOUND:
7141 case SCF_ERROR_NOT_SET:
7142 default:
7143 bad_error("scf_scope_add_service", scf_error());
7144 }
7145 }
7146
7147 r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
7148 if (r < 0)
7149 bad_error("snprintf", errno);
7150
7151 cbdata.sc_handle = lcbdata->sc_handle;
7152 cbdata.sc_parent = imp_tsvc;
7153 cbdata.sc_service = 1;
7154 cbdata.sc_source_fmri = s->sc_fmri;
7155 cbdata.sc_target_fmri = imp_str;
7156 cbdata.sc_flags = 0;
7157
7158 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
7159 UU_DEFAULT) != 0) {
7160 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7161 bad_error("uu_list_walk", uu_error());
7162
7163 lcbdata->sc_err = cbdata.sc_err;
7164 switch (cbdata.sc_err) {
7165 case ECONNABORTED:
7166 goto connaborted;
7167
7168 case ECANCELED:
7169 warn(ts_deleted, imp_tsname);
7170 lcbdata->sc_err = EBUSY;
7171 return (UU_WALK_ERROR);
7172
7173 case EEXIST:
7174 warn(ts_pg_added, imp_tsname);
7175 lcbdata->sc_err = EBUSY;
7176 return (UU_WALK_ERROR);
7177 }
7178
7179 r = UU_WALK_ERROR;
7180 goto deltemp;
7181 }
7182
7183 if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
7184 UU_DEFAULT) != 0) {
7185 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7186 bad_error("uu_list_walk", uu_error());
7187
7188 lcbdata->sc_err = cbdata.sc_err;
7189 switch (cbdata.sc_err) {
7190 case ECONNABORTED:
7191 goto connaborted;
7192
7193 case ECANCELED:
7194 warn(ts_deleted, imp_tsname);
7195 lcbdata->sc_err = EBUSY;
7196 return (UU_WALK_ERROR);
7197
7198 case EEXIST:
7199 warn(ts_pg_added, imp_tsname);
7200 lcbdata->sc_err = EBUSY;
7201 return (UU_WALK_ERROR);
7202 }
7203
7204 r = UU_WALK_ERROR;
7205 goto deltemp;
7206 }
7207
7208 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7209 switch (scf_error()) {
7210 case SCF_ERROR_NOT_FOUND:
7211 break;
7212
7213 case SCF_ERROR_CONNECTION_BROKEN:
7214 goto connaborted;
7215
7216 case SCF_ERROR_INVALID_ARGUMENT:
7217 case SCF_ERROR_HANDLE_MISMATCH:
7218 case SCF_ERROR_NOT_BOUND:
7219 case SCF_ERROR_NOT_SET:
7220 default:
7221 bad_error("scf_scope_get_service", scf_error());
7222 }
7223
7224 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
7225 switch (scf_error()) {
7226 case SCF_ERROR_CONNECTION_BROKEN:
7227 goto connaborted;
7228
7229 case SCF_ERROR_NO_RESOURCES:
7230 case SCF_ERROR_BACKEND_READONLY:
7231 case SCF_ERROR_BACKEND_ACCESS:
7232 r = stash_scferror(lcbdata);
7233 goto deltemp;
7234
7235 case SCF_ERROR_EXISTS:
7236 warn(gettext("Scope \"%s\" changed unexpectedly"
7237 " (service \"%s\" added).\n"),
7238 SCF_SCOPE_LOCAL, s->sc_name);
7239 lcbdata->sc_err = EBUSY;
7240 goto deltemp;
7241
7242 case SCF_ERROR_PERMISSION_DENIED:
7243 warn(gettext("Could not create service \"%s\" "
7244 "(permission denied).\n"), s->sc_name);
7245 goto deltemp;
7246
7247 case SCF_ERROR_INVALID_ARGUMENT:
7248 case SCF_ERROR_HANDLE_MISMATCH:
7249 case SCF_ERROR_NOT_BOUND:
7250 case SCF_ERROR_NOT_SET:
7251 default:
7252 bad_error("scf_scope_add_service", scf_error());
7253 }
7254 }
7255
7256 s->sc_import_state = IMPORT_PROP_BEGUN;
7257
7258 /* import service properties */
7259 cbdata.sc_handle = lcbdata->sc_handle;
7260 cbdata.sc_parent = imp_svc;
7261 cbdata.sc_service = 1;
7262 cbdata.sc_flags = lcbdata->sc_flags;
7263 cbdata.sc_source_fmri = s->sc_fmri;
7264 cbdata.sc_target_fmri = s->sc_fmri;
7265
7266 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7267 &cbdata, UU_DEFAULT) != 0) {
7268 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7269 bad_error("uu_list_walk", uu_error());
7270
7271 lcbdata->sc_err = cbdata.sc_err;
7272 switch (cbdata.sc_err) {
7273 case ECONNABORTED:
7274 goto connaborted;
7275
7276 case ECANCELED:
7277 warn(s_deleted, s->sc_fmri);
7278 lcbdata->sc_err = EBUSY;
7279 return (UU_WALK_ERROR);
7280
7281 case EEXIST:
7282 warn(gettext("%s changed unexpectedly "
7283 "(property group added).\n"), s->sc_fmri);
7284 lcbdata->sc_err = EBUSY;
7285 return (UU_WALK_ERROR);
7286
7287 case EINVAL:
7288 /* caught above */
7289 bad_error("entity_pgroup_import",
7290 cbdata.sc_err);
7291 }
7292
7293 r = UU_WALK_ERROR;
7294 goto deltemp;
7295 }
7296
7297 cbdata.sc_trans = NULL;
7298 cbdata.sc_flags = 0;
7299 if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
7300 &cbdata, UU_DEFAULT) != 0) {
7301 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7302 bad_error("uu_list_walk", uu_error());
7303
7304 lcbdata->sc_err = cbdata.sc_err;
7305 if (cbdata.sc_err == ECONNABORTED)
7306 goto connaborted;
7307 r = UU_WALK_ERROR;
7308 goto deltemp;
7309 }
7310
7311 s->sc_import_state = IMPORT_PROP_DONE;
7312
7313 /*
7314 * This is a new service, so we can't take previous snapshots
7315 * or upgrade service properties.
7316 */
7317 fresh = 1;
7318 goto instances;
7319 }
7320
7321 /* Clear sc_seen for the instances. */
7322 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
7323 (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
7324 bad_error("uu_list_walk", uu_error());
7325
7326 /*
7327 * Take previous snapshots for all instances. Even for ones not
7328 * mentioned in the bundle, since we might change their service
7329 * properties.
7330 */
7331 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7332 switch (scf_error()) {
7333 case SCF_ERROR_CONNECTION_BROKEN:
7334 goto connaborted;
7335
7336 case SCF_ERROR_DELETED:
7337 warn(s_deleted, s->sc_fmri);
7338 lcbdata->sc_err = EBUSY;
7339 r = UU_WALK_ERROR;
7340 goto deltemp;
7341
7342 case SCF_ERROR_HANDLE_MISMATCH:
7343 case SCF_ERROR_NOT_BOUND:
7344 case SCF_ERROR_NOT_SET:
7345 default:
7346 bad_error("scf_iter_service_instances", scf_error());
7347 }
7348 }
7349
7350 for (;;) {
7351 r = scf_iter_next_instance(imp_iter, imp_inst);
7352 if (r == 0)
7353 break;
7354 if (r != 1) {
7355 switch (scf_error()) {
7356 case SCF_ERROR_DELETED:
7357 warn(s_deleted, s->sc_fmri);
7358 lcbdata->sc_err = EBUSY;
7359 r = UU_WALK_ERROR;
7360 goto deltemp;
7361
7362 case SCF_ERROR_CONNECTION_BROKEN:
7363 goto connaborted;
7364
7365 case SCF_ERROR_NOT_BOUND:
7366 case SCF_ERROR_HANDLE_MISMATCH:
7367 case SCF_ERROR_INVALID_ARGUMENT:
7368 case SCF_ERROR_NOT_SET:
7369 default:
7370 bad_error("scf_iter_next_instance",
7371 scf_error());
7372 }
7373 }
7374
7375 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
7376 switch (scf_error()) {
7377 case SCF_ERROR_DELETED:
7378 continue;
7379
7380 case SCF_ERROR_CONNECTION_BROKEN:
7381 goto connaborted;
7382
7383 case SCF_ERROR_NOT_SET:
7384 case SCF_ERROR_NOT_BOUND:
7385 default:
7386 bad_error("scf_instance_get_name", scf_error());
7387 }
7388 }
7389
7390 if (g_verbose)
7391 warn(gettext(
7392 "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
7393 snap_previous, s->sc_name, imp_str);
7394
7395 r = take_snap(imp_inst, snap_previous, imp_snap);
7396 switch (r) {
7397 case 0:
7398 break;
7399
7400 case ECANCELED:
7401 continue;
7402
7403 case ECONNABORTED:
7404 goto connaborted;
7405
7406 case EPERM:
7407 warn(gettext("Could not take \"%s\" snapshot of "
7408 "svc:/%s:%s (permission denied).\n"),
7409 snap_previous, s->sc_name, imp_str);
7410 lcbdata->sc_err = r;
7411 return (UU_WALK_ERROR);
7412
7413 case ENOSPC:
7414 case -1:
7415 lcbdata->sc_err = r;
7416 r = UU_WALK_ERROR;
7417 goto deltemp;
7418
7419 default:
7420 bad_error("take_snap", r);
7421 }
7422
7423 linst.sc_name = imp_str;
7424 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
7425 &linst, NULL, NULL);
7426 if (inst != NULL) {
7427 inst->sc_import_state = IMPORT_PREVIOUS;
7428 inst->sc_seen = 1;
7429 }
7430 }
7431
7432 /*
7433 * Create the new instances and take previous snapshots of
7434 * them. This is not necessary, but it maximizes data preservation.
7435 */
7436 for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
7437 inst != NULL;
7438 inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
7439 inst)) {
7440 if (inst->sc_seen)
7441 continue;
7442
7443 if (scf_service_add_instance(imp_svc, inst->sc_name,
7444 imp_inst) != 0) {
7445 switch (scf_error()) {
7446 case SCF_ERROR_CONNECTION_BROKEN:
7447 goto connaborted;
7448
7449 case SCF_ERROR_BACKEND_READONLY:
7450 case SCF_ERROR_BACKEND_ACCESS:
7451 case SCF_ERROR_NO_RESOURCES:
7452 r = stash_scferror(lcbdata);
7453 goto deltemp;
7454
7455 case SCF_ERROR_EXISTS:
7456 warn(gettext("%s changed unexpectedly "
7457 "(instance \"%s\" added).\n"), s->sc_fmri,
7458 inst->sc_name);
7459 lcbdata->sc_err = EBUSY;
7460 r = UU_WALK_ERROR;
7461 goto deltemp;
7462
7463 case SCF_ERROR_INVALID_ARGUMENT:
7464 warn(gettext("Service \"%s\" has instance with "
7465 "invalid name \"%s\".\n"), s->sc_name,
7466 inst->sc_name);
7467 r = stash_scferror(lcbdata);
7468 goto deltemp;
7469
7470 case SCF_ERROR_PERMISSION_DENIED:
7471 warn(gettext("Could not create instance \"%s\" "
7472 "in %s (permission denied).\n"),
7473 inst->sc_name, s->sc_fmri);
7474 r = stash_scferror(lcbdata);
7475 goto deltemp;
7476
7477 case SCF_ERROR_HANDLE_MISMATCH:
7478 case SCF_ERROR_NOT_BOUND:
7479 case SCF_ERROR_NOT_SET:
7480 default:
7481 bad_error("scf_service_add_instance",
7482 scf_error());
7483 }
7484 }
7485
7486 if (g_verbose)
7487 warn(gettext("Taking \"%s\" snapshot for "
7488 "new service %s.\n"), snap_previous, inst->sc_fmri);
7489 r = take_snap(imp_inst, snap_previous, imp_snap);
7490 switch (r) {
7491 case 0:
7492 break;
7493
7494 case ECANCELED:
7495 warn(i_deleted, s->sc_fmri, inst->sc_name);
7496 lcbdata->sc_err = EBUSY;
7497 r = UU_WALK_ERROR;
7498 goto deltemp;
7499
7500 case ECONNABORTED:
7501 goto connaborted;
7502
7503 case EPERM:
7504 warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
7505 lcbdata->sc_err = r;
7506 r = UU_WALK_ERROR;
7507 goto deltemp;
7508
7509 case ENOSPC:
7510 case -1:
7511 r = UU_WALK_ERROR;
7512 goto deltemp;
7513
7514 default:
7515 bad_error("take_snap", r);
7516 }
7517 }
7518
7519 s->sc_import_state = IMPORT_PREVIOUS;
7520
7521 /*
7522 * Upgrade service properties, if we can find a last-import snapshot.
7523 * Any will do because we don't support different service properties
7524 * in different manifests, so all snaplevels of the service in all of
7525 * the last-import snapshots of the instances should be the same.
7526 */
7527 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7528 switch (scf_error()) {
7529 case SCF_ERROR_CONNECTION_BROKEN:
7530 goto connaborted;
7531
7532 case SCF_ERROR_DELETED:
7533 warn(s_deleted, s->sc_fmri);
7534 lcbdata->sc_err = EBUSY;
7535 r = UU_WALK_ERROR;
7536 goto deltemp;
7537
7538 case SCF_ERROR_HANDLE_MISMATCH:
7539 case SCF_ERROR_NOT_BOUND:
7540 case SCF_ERROR_NOT_SET:
7541 default:
7542 bad_error("scf_iter_service_instances", scf_error());
7543 }
7544 }
7545
7546 for (;;) {
7547 r = scf_iter_next_instance(imp_iter, imp_inst);
7548 if (r == -1) {
7549 switch (scf_error()) {
7550 case SCF_ERROR_DELETED:
7551 warn(s_deleted, s->sc_fmri);
7552 lcbdata->sc_err = EBUSY;
7553 r = UU_WALK_ERROR;
7554 goto deltemp;
7555
7556 case SCF_ERROR_CONNECTION_BROKEN:
7557 goto connaborted;
7558
7559 case SCF_ERROR_NOT_BOUND:
7560 case SCF_ERROR_HANDLE_MISMATCH:
7561 case SCF_ERROR_INVALID_ARGUMENT:
7562 case SCF_ERROR_NOT_SET:
7563 default:
7564 bad_error("scf_iter_next_instance",
7565 scf_error());
7566 }
7567 }
7568
7569 if (r == 0) {
7570 /*
7571 * Didn't find any last-import snapshots. Override-
7572 * import the properties. Unless one of the instances
7573 * has a general/enabled property, in which case we're
7574 * probably running a last-import-capable svccfg for
7575 * the first time, and we should only take the
7576 * last-import snapshot.
7577 */
7578 if (have_ge) {
7579 pgroup_t *mfpg;
7580 scf_callback_t mfcbdata;
7581
7582 li_only = 1;
7583 no_refresh = 1;
7584 /*
7585 * Need to go ahead and import the manifestfiles
7586 * pg if it exists. If the last-import snapshot
7587 * upgrade code is ever removed this code can
7588 * be removed as well.
7589 */
7590 mfpg = internal_pgroup_find(s,
7591 SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
7592
7593 if (mfpg) {
7594 mfcbdata.sc_handle = g_hndl;
7595 mfcbdata.sc_parent = imp_svc;
7596 mfcbdata.sc_service = 1;
7597 mfcbdata.sc_flags = SCI_FORCE;
7598 mfcbdata.sc_source_fmri = s->sc_fmri;
7599 mfcbdata.sc_target_fmri = s->sc_fmri;
7600 if (entity_pgroup_import(mfpg,
7601 &mfcbdata) != UU_WALK_NEXT) {
7602 warn(s_mfile_upd, s->sc_fmri);
7603 r = UU_WALK_ERROR;
7604 goto deltemp;
7605 }
7606 }
7607 break;
7608 }
7609
7610 s->sc_import_state = IMPORT_PROP_BEGUN;
7611
7612 cbdata.sc_handle = g_hndl;
7613 cbdata.sc_parent = imp_svc;
7614 cbdata.sc_service = 1;
7615 cbdata.sc_flags = SCI_FORCE;
7616 cbdata.sc_source_fmri = s->sc_fmri;
7617 cbdata.sc_target_fmri = s->sc_fmri;
7618 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7619 &cbdata, UU_DEFAULT) != 0) {
7620 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7621 bad_error("uu_list_walk", uu_error());
7622 lcbdata->sc_err = cbdata.sc_err;
7623 switch (cbdata.sc_err) {
7624 case ECONNABORTED:
7625 goto connaborted;
7626
7627 case ECANCELED:
7628 warn(s_deleted, s->sc_fmri);
7629 lcbdata->sc_err = EBUSY;
7630 break;
7631
7632 case EINVAL: /* caught above */
7633 case EEXIST:
7634 bad_error("entity_pgroup_import",
7635 cbdata.sc_err);
7636 }
7637
7638 r = UU_WALK_ERROR;
7639 goto deltemp;
7640 }
7641
7642 cbdata.sc_trans = NULL;
7643 cbdata.sc_flags = 0;
7644 if (uu_list_walk(s->sc_dependents,
7645 lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
7646 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7647 bad_error("uu_list_walk", uu_error());
7648 lcbdata->sc_err = cbdata.sc_err;
7649 if (cbdata.sc_err == ECONNABORTED)
7650 goto connaborted;
7651 r = UU_WALK_ERROR;
7652 goto deltemp;
7653 }
7654 break;
7655 }
7656
7657 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
7658 imp_snap) != 0) {
7659 switch (scf_error()) {
7660 case SCF_ERROR_DELETED:
7661 continue;
7662
7663 case SCF_ERROR_NOT_FOUND:
7664 break;
7665
7666 case SCF_ERROR_CONNECTION_BROKEN:
7667 goto connaborted;
7668
7669 case SCF_ERROR_HANDLE_MISMATCH:
7670 case SCF_ERROR_NOT_BOUND:
7671 case SCF_ERROR_INVALID_ARGUMENT:
7672 case SCF_ERROR_NOT_SET:
7673 default:
7674 bad_error("scf_instance_get_snapshot",
7675 scf_error());
7676 }
7677
7678 if (have_ge)
7679 continue;
7680
7681 /*
7682 * Check for a general/enabled property. This is how
7683 * we tell whether to import if there turn out to be
7684 * no last-import snapshots.
7685 */
7686 if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
7687 imp_pg) == 0) {
7688 if (scf_pg_get_property(imp_pg,
7689 SCF_PROPERTY_ENABLED, imp_prop) == 0) {
7690 have_ge = 1;
7691 } else {
7692 switch (scf_error()) {
7693 case SCF_ERROR_DELETED:
7694 case SCF_ERROR_NOT_FOUND:
7695 continue;
7696
7697 case SCF_ERROR_INVALID_ARGUMENT:
7698 case SCF_ERROR_HANDLE_MISMATCH:
7699 case SCF_ERROR_CONNECTION_BROKEN:
7700 case SCF_ERROR_NOT_BOUND:
7701 case SCF_ERROR_NOT_SET:
7702 default:
7703 bad_error("scf_pg_get_property",
7704 scf_error());
7705 }
7706 }
7707 } else {
7708 switch (scf_error()) {
7709 case SCF_ERROR_DELETED:
7710 case SCF_ERROR_NOT_FOUND:
7711 continue;
7712
7713 case SCF_ERROR_CONNECTION_BROKEN:
7714 goto connaborted;
7715
7716 case SCF_ERROR_NOT_BOUND:
7717 case SCF_ERROR_NOT_SET:
7718 case SCF_ERROR_INVALID_ARGUMENT:
7719 case SCF_ERROR_HANDLE_MISMATCH:
7720 default:
7721 bad_error("scf_instance_get_pg",
7722 scf_error());
7723 }
7724 }
7725 continue;
7726 }
7727
7728 /* find service snaplevel */
7729 r = get_snaplevel(imp_snap, 1, imp_snpl);
7730 switch (r) {
7731 case 0:
7732 break;
7733
7734 case ECONNABORTED:
7735 goto connaborted;
7736
7737 case ECANCELED:
7738 continue;
7739
7740 case ENOENT:
7741 if (scf_instance_get_name(imp_inst, imp_str,
7742 imp_str_sz) < 0)
7743 (void) strcpy(imp_str, "?");
7744 warn(badsnap, snap_lastimport, s->sc_name, imp_str);
7745 lcbdata->sc_err = EBADF;
7746 r = UU_WALK_ERROR;
7747 goto deltemp;
7748
7749 default:
7750 bad_error("get_snaplevel", r);
7751 }
7752
7753 if (scf_instance_get_snapshot(imp_inst, snap_running,
7754 imp_rsnap) != 0) {
7755 switch (scf_error()) {
7756 case SCF_ERROR_DELETED:
7757 continue;
7758
7759 case SCF_ERROR_NOT_FOUND:
7760 break;
7761
7762 case SCF_ERROR_CONNECTION_BROKEN:
7763 goto connaborted;
7764
7765 case SCF_ERROR_INVALID_ARGUMENT:
7766 case SCF_ERROR_HANDLE_MISMATCH:
7767 case SCF_ERROR_NOT_BOUND:
7768 case SCF_ERROR_NOT_SET:
7769 default:
7770 bad_error("scf_instance_get_snapshot",
7771 scf_error());
7772 }
7773 running = NULL;
7774 } else {
7775 r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
7776 switch (r) {
7777 case 0:
7778 running = imp_rsnpl;
7779 break;
7780
7781 case ECONNABORTED:
7782 goto connaborted;
7783
7784 case ECANCELED:
7785 continue;
7786
7787 case ENOENT:
7788 if (scf_instance_get_name(imp_inst, imp_str,
7789 imp_str_sz) < 0)
7790 (void) strcpy(imp_str, "?");
7791 warn(badsnap, snap_running, s->sc_name,
7792 imp_str);
7793 lcbdata->sc_err = EBADF;
7794 r = UU_WALK_ERROR;
7795 goto deltemp;
7796
7797 default:
7798 bad_error("get_snaplevel", r);
7799 }
7800 }
7801
7802 if (g_verbose) {
7803 if (scf_instance_get_name(imp_inst, imp_str,
7804 imp_str_sz) < 0)
7805 (void) strcpy(imp_str, "?");
7806 warn(gettext("Upgrading properties of %s according to "
7807 "instance \"%s\".\n"), s->sc_fmri, imp_str);
7808 }
7809
7810 /* upgrade service properties */
7811 r = upgrade_props(imp_svc, running, imp_snpl, s);
7812 if (r == 0)
7813 break;
7814
7815 switch (r) {
7816 case ECONNABORTED:
7817 goto connaborted;
7818
7819 case ECANCELED:
7820 warn(s_deleted, s->sc_fmri);
7821 lcbdata->sc_err = EBUSY;
7822 break;
7823
7824 case ENODEV:
7825 if (scf_instance_get_name(imp_inst, imp_str,
7826 imp_str_sz) < 0)
7827 (void) strcpy(imp_str, "?");
7828 warn(i_deleted, s->sc_fmri, imp_str);
7829 lcbdata->sc_err = EBUSY;
7830 break;
7831
7832 default:
7833 lcbdata->sc_err = r;
7834 }
7835
7836 r = UU_WALK_ERROR;
7837 goto deltemp;
7838 }
7839
7840 s->sc_import_state = IMPORT_PROP_DONE;
7841
7842 instances:
7843 /* import instances */
7844 cbdata.sc_handle = lcbdata->sc_handle;
7845 cbdata.sc_parent = imp_svc;
7846 cbdata.sc_service = 1;
7847 cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7848 cbdata.sc_general = NULL;
7849
7850 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7851 lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7852 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7853 bad_error("uu_list_walk", uu_error());
7854
7855 lcbdata->sc_err = cbdata.sc_err;
7856 if (cbdata.sc_err == ECONNABORTED)
7857 goto connaborted;
7858 r = UU_WALK_ERROR;
7859 goto deltemp;
7860 }
7861
7862 s->sc_import_state = IMPORT_COMPLETE;
7863 r = UU_WALK_NEXT;
7864
7865 deltemp:
7866 /* delete temporary service */
7867 if (scf_service_delete(imp_tsvc) != 0) {
7868 switch (scf_error()) {
7869 case SCF_ERROR_DELETED:
7870 break;
7871
7872 case SCF_ERROR_CONNECTION_BROKEN:
7873 goto connaborted;
7874
7875 case SCF_ERROR_EXISTS:
7876 warn(gettext(
7877 "Could not delete svc:/%s (instances exist).\n"),
7878 imp_tsname);
7879 break;
7880
7881 case SCF_ERROR_NOT_SET:
7882 case SCF_ERROR_NOT_BOUND:
7883 default:
7884 bad_error("scf_service_delete", scf_error());
7885 }
7886 }
7887
7888 return (r);
7889
7890 connaborted:
7891 warn(gettext("Could not delete svc:/%s "
7892 "(repository connection broken).\n"), imp_tsname);
7893 lcbdata->sc_err = ECONNABORTED;
7894 return (UU_WALK_ERROR);
7895 }
7896
7897 static const char *
import_progress(int st)7898 import_progress(int st)
7899 {
7900 switch (st) {
7901 case 0:
7902 return (gettext("not reached."));
7903
7904 case IMPORT_PREVIOUS:
7905 return (gettext("previous snapshot taken."));
7906
7907 case IMPORT_PROP_BEGUN:
7908 return (gettext("some properties imported."));
7909
7910 case IMPORT_PROP_DONE:
7911 return (gettext("properties imported."));
7912
7913 case IMPORT_COMPLETE:
7914 return (gettext("imported."));
7915
7916 case IMPORT_REFRESHED:
7917 return (gettext("refresh requested."));
7918
7919 default:
7920 #ifndef NDEBUG
7921 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7922 __FILE__, __LINE__, st);
7923 #endif
7924 abort();
7925 /* NOTREACHED */
7926 }
7927 }
7928
7929 /*
7930 * Returns
7931 * 0 - success
7932 * - fmri wasn't found (error printed)
7933 * - entity was deleted (error printed)
7934 * - backend denied access (error printed)
7935 * ENOMEM - out of memory (error printed)
7936 * ECONNABORTED - repository connection broken (error printed)
7937 * EPERM - permission denied (error printed)
7938 * -1 - unknown libscf error (error printed)
7939 */
7940 static int
imp_refresh_fmri(const char * fmri,const char * name,const char * d_fmri)7941 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7942 {
7943 scf_error_t serr;
7944 void *ent;
7945 int issvc;
7946 int r;
7947
7948 const char *deleted = gettext("Could not refresh %s (deleted).\n");
7949 const char *dpt_deleted = gettext("Could not refresh %s "
7950 "(dependent \"%s\" of %s) (deleted).\n");
7951
7952 serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7953 switch (serr) {
7954 case SCF_ERROR_NONE:
7955 break;
7956
7957 case SCF_ERROR_NO_MEMORY:
7958 if (name == NULL)
7959 warn(gettext("Could not refresh %s (out of memory).\n"),
7960 fmri);
7961 else
7962 warn(gettext("Could not refresh %s "
7963 "(dependent \"%s\" of %s) (out of memory).\n"),
7964 fmri, name, d_fmri);
7965 return (ENOMEM);
7966
7967 case SCF_ERROR_NOT_FOUND:
7968 if (name == NULL)
7969 warn(deleted, fmri);
7970 else
7971 warn(dpt_deleted, fmri, name, d_fmri);
7972 return (0);
7973
7974 case SCF_ERROR_INVALID_ARGUMENT:
7975 case SCF_ERROR_CONSTRAINT_VIOLATED:
7976 default:
7977 bad_error("fmri_to_entity", serr);
7978 }
7979
7980 r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7981 switch (r) {
7982 case 0:
7983 break;
7984
7985 case ECONNABORTED:
7986 if (name != NULL)
7987 warn(gettext("Could not refresh %s "
7988 "(dependent \"%s\" of %s) "
7989 "(repository connection broken).\n"), fmri, name,
7990 d_fmri);
7991 return (r);
7992
7993 case ECANCELED:
7994 if (name == NULL)
7995 warn(deleted, fmri);
7996 else
7997 warn(dpt_deleted, fmri, name, d_fmri);
7998 return (0);
7999
8000 case EACCES:
8001 if (!g_verbose)
8002 return (0);
8003 if (name == NULL)
8004 warn(gettext("Could not refresh %s "
8005 "(backend access denied).\n"), fmri);
8006 else
8007 warn(gettext("Could not refresh %s "
8008 "(dependent \"%s\" of %s) "
8009 "(backend access denied).\n"), fmri, name, d_fmri);
8010 return (0);
8011
8012 case EPERM:
8013 if (name == NULL)
8014 warn(gettext("Could not refresh %s "
8015 "(permission denied).\n"), fmri);
8016 else
8017 warn(gettext("Could not refresh %s "
8018 "(dependent \"%s\" of %s) "
8019 "(permission denied).\n"), fmri, name, d_fmri);
8020 return (r);
8021
8022 case ENOSPC:
8023 if (name == NULL)
8024 warn(gettext("Could not refresh %s "
8025 "(repository server out of resources).\n"),
8026 fmri);
8027 else
8028 warn(gettext("Could not refresh %s "
8029 "(dependent \"%s\" of %s) "
8030 "(repository server out of resources).\n"),
8031 fmri, name, d_fmri);
8032 return (r);
8033
8034 case -1:
8035 scfwarn();
8036 return (r);
8037
8038 default:
8039 bad_error("refresh_entity", r);
8040 }
8041
8042 if (issvc)
8043 scf_service_destroy(ent);
8044 else
8045 scf_instance_destroy(ent);
8046
8047 return (0);
8048 }
8049
8050 static int
alloc_imp_globals()8051 alloc_imp_globals()
8052 {
8053 int r;
8054
8055 const char * const emsg_nomem = gettext("Out of memory.\n");
8056 const char * const emsg_nores =
8057 gettext("svc.configd is out of resources.\n");
8058
8059 imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
8060 max_scf_name_len : max_scf_fmri_len) + 1;
8061
8062 if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
8063 (imp_svc = scf_service_create(g_hndl)) == NULL ||
8064 (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
8065 (imp_inst = scf_instance_create(g_hndl)) == NULL ||
8066 (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
8067 (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
8068 (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
8069 (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
8070 (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
8071 (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8072 (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
8073 (imp_pg = scf_pg_create(g_hndl)) == NULL ||
8074 (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
8075 (imp_prop = scf_property_create(g_hndl)) == NULL ||
8076 (imp_iter = scf_iter_create(g_hndl)) == NULL ||
8077 (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
8078 (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
8079 (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
8080 (imp_str = malloc(imp_str_sz)) == NULL ||
8081 (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
8082 (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
8083 (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
8084 (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
8085 (ud_inst = scf_instance_create(g_hndl)) == NULL ||
8086 (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8087 (ud_pg = scf_pg_create(g_hndl)) == NULL ||
8088 (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
8089 (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
8090 (ud_prop = scf_property_create(g_hndl)) == NULL ||
8091 (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
8092 (ud_val = scf_value_create(g_hndl)) == NULL ||
8093 (ud_iter = scf_iter_create(g_hndl)) == NULL ||
8094 (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
8095 (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
8096 (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
8097 (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
8098 (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
8099 if (scf_error() == SCF_ERROR_NO_RESOURCES)
8100 warn(emsg_nores);
8101 else
8102 warn(emsg_nomem);
8103
8104 return (-1);
8105 }
8106
8107 r = load_init();
8108 switch (r) {
8109 case 0:
8110 break;
8111
8112 case ENOMEM:
8113 warn(emsg_nomem);
8114 return (-1);
8115
8116 default:
8117 bad_error("load_init", r);
8118 }
8119
8120 return (0);
8121 }
8122
8123 static void
free_imp_globals()8124 free_imp_globals()
8125 {
8126 pgroup_t *old_dpt;
8127 void *cookie;
8128
8129 load_fini();
8130
8131 free(ud_ctarg);
8132 free(ud_oldtarg);
8133 free(ud_name);
8134 ud_ctarg = ud_oldtarg = ud_name = NULL;
8135
8136 scf_transaction_destroy(ud_tx);
8137 ud_tx = NULL;
8138 scf_iter_destroy(ud_iter);
8139 scf_iter_destroy(ud_iter2);
8140 ud_iter = ud_iter2 = NULL;
8141 scf_value_destroy(ud_val);
8142 ud_val = NULL;
8143 scf_property_destroy(ud_prop);
8144 scf_property_destroy(ud_dpt_prop);
8145 ud_prop = ud_dpt_prop = NULL;
8146 scf_pg_destroy(ud_pg);
8147 scf_pg_destroy(ud_cur_depts_pg);
8148 scf_pg_destroy(ud_run_dpts_pg);
8149 ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
8150 scf_snaplevel_destroy(ud_snpl);
8151 ud_snpl = NULL;
8152 scf_instance_destroy(ud_inst);
8153 ud_inst = NULL;
8154
8155 free(imp_str);
8156 free(imp_tsname);
8157 free(imp_fe1);
8158 free(imp_fe2);
8159 imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
8160
8161 cookie = NULL;
8162 while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
8163 NULL) {
8164 free((char *)old_dpt->sc_pgroup_name);
8165 free((char *)old_dpt->sc_pgroup_fmri);
8166 internal_pgroup_free(old_dpt);
8167 }
8168 uu_list_destroy(imp_deleted_dpts);
8169
8170 scf_transaction_destroy(imp_tx);
8171 imp_tx = NULL;
8172 scf_iter_destroy(imp_iter);
8173 scf_iter_destroy(imp_rpg_iter);
8174 scf_iter_destroy(imp_up_iter);
8175 imp_iter = imp_rpg_iter = imp_up_iter = NULL;
8176 scf_property_destroy(imp_prop);
8177 imp_prop = NULL;
8178 scf_pg_destroy(imp_pg);
8179 scf_pg_destroy(imp_pg2);
8180 imp_pg = imp_pg2 = NULL;
8181 scf_snaplevel_destroy(imp_snpl);
8182 scf_snaplevel_destroy(imp_rsnpl);
8183 imp_snpl = imp_rsnpl = NULL;
8184 scf_snapshot_destroy(imp_snap);
8185 scf_snapshot_destroy(imp_lisnap);
8186 scf_snapshot_destroy(imp_tlisnap);
8187 scf_snapshot_destroy(imp_rsnap);
8188 imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
8189 scf_instance_destroy(imp_inst);
8190 scf_instance_destroy(imp_tinst);
8191 imp_inst = imp_tinst = NULL;
8192 scf_service_destroy(imp_svc);
8193 scf_service_destroy(imp_tsvc);
8194 imp_svc = imp_tsvc = NULL;
8195 scf_scope_destroy(imp_scope);
8196 imp_scope = NULL;
8197
8198 load_fini();
8199 }
8200
8201 int
lscf_bundle_import(bundle_t * bndl,const char * filename,uint_t flags)8202 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
8203 {
8204 scf_callback_t cbdata;
8205 int result = 0;
8206 entity_t *svc, *inst;
8207 uu_list_t *insts;
8208 int r;
8209 pgroup_t *old_dpt;
8210 int annotation_set = 0;
8211
8212 const char * const emsg_nomem = gettext("Out of memory.\n");
8213 const char * const emsg_nores =
8214 gettext("svc.configd is out of resources.\n");
8215
8216 lscf_prep_hndl();
8217
8218 if (alloc_imp_globals())
8219 goto out;
8220
8221 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
8222 switch (scf_error()) {
8223 case SCF_ERROR_CONNECTION_BROKEN:
8224 warn(gettext("Repository connection broken.\n"));
8225 repository_teardown();
8226 result = -1;
8227 goto out;
8228
8229 case SCF_ERROR_NOT_FOUND:
8230 case SCF_ERROR_INVALID_ARGUMENT:
8231 case SCF_ERROR_NOT_BOUND:
8232 case SCF_ERROR_HANDLE_MISMATCH:
8233 default:
8234 bad_error("scf_handle_get_scope", scf_error());
8235 }
8236 }
8237
8238 /* Set up the auditing annotation. */
8239 if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
8240 annotation_set = 1;
8241 } else {
8242 switch (scf_error()) {
8243 case SCF_ERROR_CONNECTION_BROKEN:
8244 warn(gettext("Repository connection broken.\n"));
8245 repository_teardown();
8246 result = -1;
8247 goto out;
8248
8249 case SCF_ERROR_INVALID_ARGUMENT:
8250 case SCF_ERROR_NOT_BOUND:
8251 case SCF_ERROR_NO_RESOURCES:
8252 case SCF_ERROR_INTERNAL:
8253 bad_error("_scf_set_annotation", scf_error());
8254 /* NOTREACHED */
8255
8256 default:
8257 /*
8258 * Do not terminate import because of inability to
8259 * generate annotation audit event.
8260 */
8261 warn(gettext("_scf_set_annotation() unexpectedly "
8262 "failed with return code of %d\n"), scf_error());
8263 break;
8264 }
8265 }
8266
8267 /*
8268 * Clear the sc_import_state's of all services & instances so we can
8269 * report how far we got if we fail.
8270 */
8271 for (svc = uu_list_first(bndl->sc_bundle_services);
8272 svc != NULL;
8273 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8274 svc->sc_import_state = 0;
8275
8276 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
8277 clear_int, (void *)offsetof(entity_t, sc_import_state),
8278 UU_DEFAULT) != 0)
8279 bad_error("uu_list_walk", uu_error());
8280 }
8281
8282 cbdata.sc_handle = g_hndl;
8283 cbdata.sc_parent = imp_scope;
8284 cbdata.sc_flags = flags;
8285 cbdata.sc_general = NULL;
8286
8287 if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
8288 &cbdata, UU_DEFAULT) == 0) {
8289 char *eptr;
8290 /* Success. Refresh everything. */
8291
8292 if (flags & SCI_NOREFRESH || no_refresh) {
8293 no_refresh = 0;
8294 result = 0;
8295 goto out;
8296 }
8297
8298 for (svc = uu_list_first(bndl->sc_bundle_services);
8299 svc != NULL;
8300 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8301 pgroup_t *dpt;
8302
8303 insts = svc->sc_u.sc_service.sc_service_instances;
8304
8305 for (inst = uu_list_first(insts);
8306 inst != NULL;
8307 inst = uu_list_next(insts, inst)) {
8308 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
8309 switch (r) {
8310 case 0:
8311 break;
8312
8313 case ENOMEM:
8314 case ECONNABORTED:
8315 case EPERM:
8316 case -1:
8317 goto progress;
8318
8319 default:
8320 bad_error("imp_refresh_fmri", r);
8321 }
8322
8323 inst->sc_import_state = IMPORT_REFRESHED;
8324
8325 for (dpt = uu_list_first(inst->sc_dependents);
8326 dpt != NULL;
8327 dpt = uu_list_next(inst->sc_dependents,
8328 dpt))
8329 if (imp_refresh_fmri(
8330 dpt->sc_pgroup_fmri,
8331 dpt->sc_pgroup_name,
8332 inst->sc_fmri) != 0)
8333 goto progress;
8334 }
8335
8336 for (dpt = uu_list_first(svc->sc_dependents);
8337 dpt != NULL;
8338 dpt = uu_list_next(svc->sc_dependents, dpt))
8339 if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
8340 dpt->sc_pgroup_name, svc->sc_fmri) != 0)
8341 goto progress;
8342 }
8343
8344 for (old_dpt = uu_list_first(imp_deleted_dpts);
8345 old_dpt != NULL;
8346 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
8347 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8348 old_dpt->sc_pgroup_name,
8349 old_dpt->sc_parent->sc_fmri) != 0)
8350 goto progress;
8351
8352 result = 0;
8353
8354 /*
8355 * This snippet of code assumes that we are running svccfg as we
8356 * normally do -- witih svc.startd running. Of course, that is
8357 * not actually the case all the time because we also use a
8358 * varient of svc.configd and svccfg which are only meant to
8359 * run during the build process. During this time we have no
8360 * svc.startd, so this check would hang the build process.
8361 *
8362 * However, we've also given other consolidations, a bit of a
8363 * means to tie themselves into a knot. They're not properly
8364 * using the native build equivalents, but they've been getting
8365 * away with it anyways. Therefore, if we've found that
8366 * SVCCFG_REPOSITORY is set indicating that a separate configd
8367 * should be spun up, then we have to assume it's not using a
8368 * startd and we should not do this check.
8369 */
8370 #ifndef NATIVE_BUILD
8371 /*
8372 * Verify that the restarter group is preset
8373 */
8374 eptr = getenv("SVCCFG_REPOSITORY");
8375 for (svc = uu_list_first(bndl->sc_bundle_services);
8376 svc != NULL && eptr == NULL;
8377 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8378
8379 insts = svc->sc_u.sc_service.sc_service_instances;
8380
8381 for (inst = uu_list_first(insts);
8382 inst != NULL;
8383 inst = uu_list_next(insts, inst)) {
8384 if (lscf_instance_verify(imp_scope, svc,
8385 inst) != 0)
8386 goto progress;
8387 }
8388 }
8389 #endif
8390 goto out;
8391
8392 }
8393
8394 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8395 bad_error("uu_list_walk", uu_error());
8396
8397 printerr:
8398 /* If the error hasn't been printed yet, do so here. */
8399 switch (cbdata.sc_err) {
8400 case ECONNABORTED:
8401 warn(gettext("Repository connection broken.\n"));
8402 break;
8403
8404 case ENOMEM:
8405 warn(emsg_nomem);
8406 break;
8407
8408 case ENOSPC:
8409 warn(emsg_nores);
8410 break;
8411
8412 case EROFS:
8413 warn(gettext("Repository is read-only.\n"));
8414 break;
8415
8416 case EACCES:
8417 warn(gettext("Repository backend denied access.\n"));
8418 break;
8419
8420 case EPERM:
8421 case EINVAL:
8422 case EEXIST:
8423 case EBUSY:
8424 case EBADF:
8425 case -1:
8426 break;
8427
8428 default:
8429 bad_error("lscf_service_import", cbdata.sc_err);
8430 }
8431
8432 progress:
8433 warn(gettext("Import of %s failed. Progress:\n"), filename);
8434
8435 for (svc = uu_list_first(bndl->sc_bundle_services);
8436 svc != NULL;
8437 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8438 insts = svc->sc_u.sc_service.sc_service_instances;
8439
8440 warn(gettext(" Service \"%s\": %s\n"), svc->sc_name,
8441 import_progress(svc->sc_import_state));
8442
8443 for (inst = uu_list_first(insts);
8444 inst != NULL;
8445 inst = uu_list_next(insts, inst))
8446 warn(gettext(" Instance \"%s\": %s\n"),
8447 inst->sc_name,
8448 import_progress(inst->sc_import_state));
8449 }
8450
8451 if (cbdata.sc_err == ECONNABORTED)
8452 repository_teardown();
8453
8454
8455 result = -1;
8456
8457 out:
8458 if (annotation_set != 0) {
8459 /* Turn off annotation. It is no longer needed. */
8460 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8461 }
8462
8463 free_imp_globals();
8464
8465 return (result);
8466 }
8467
8468 /*
8469 * _lscf_import_err() summarize the error handling returned by
8470 * lscf_import_{instance | service}_pgs
8471 * Return values are:
8472 * IMPORT_NEXT
8473 * IMPORT_OUT
8474 * IMPORT_BAD
8475 */
8476
8477 #define IMPORT_BAD -1
8478 #define IMPORT_NEXT 0
8479 #define IMPORT_OUT 1
8480
8481 static int
_lscf_import_err(int err,const char * fmri)8482 _lscf_import_err(int err, const char *fmri)
8483 {
8484 switch (err) {
8485 case 0:
8486 if (g_verbose)
8487 warn(gettext("%s updated.\n"), fmri);
8488 return (IMPORT_NEXT);
8489
8490 case ECONNABORTED:
8491 warn(gettext("Could not update %s "
8492 "(repository connection broken).\n"), fmri);
8493 return (IMPORT_OUT);
8494
8495 case ENOMEM:
8496 warn(gettext("Could not update %s (out of memory).\n"), fmri);
8497 return (IMPORT_OUT);
8498
8499 case ENOSPC:
8500 warn(gettext("Could not update %s "
8501 "(repository server out of resources).\n"), fmri);
8502 return (IMPORT_OUT);
8503
8504 case ECANCELED:
8505 warn(gettext(
8506 "Could not update %s (deleted).\n"), fmri);
8507 return (IMPORT_NEXT);
8508
8509 case EPERM:
8510 case EINVAL:
8511 case EBUSY:
8512 return (IMPORT_NEXT);
8513
8514 case EROFS:
8515 warn(gettext("Could not update %s (repository read-only).\n"),
8516 fmri);
8517 return (IMPORT_OUT);
8518
8519 case EACCES:
8520 warn(gettext("Could not update %s "
8521 "(backend access denied).\n"), fmri);
8522 return (IMPORT_NEXT);
8523
8524 case EEXIST:
8525 default:
8526 return (IMPORT_BAD);
8527 }
8528
8529 /*NOTREACHED*/
8530 }
8531
8532 /*
8533 * The global imp_svc and imp_inst should be set by the caller in the
8534 * check to make sure the service and instance exist that the apply is
8535 * working on.
8536 */
8537 static int
lscf_dependent_apply(void * dpg,void * e)8538 lscf_dependent_apply(void *dpg, void *e)
8539 {
8540 scf_callback_t cb;
8541 pgroup_t *dpt_pgroup = dpg;
8542 pgroup_t *deldpt;
8543 entity_t *ent = e;
8544 int tissvc;
8545 void *sc_ent, *tent;
8546 scf_error_t serr;
8547 int r;
8548
8549 const char * const dependents = "dependents";
8550 const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT);
8551
8552 if (issvc)
8553 sc_ent = imp_svc;
8554 else
8555 sc_ent = imp_inst;
8556
8557 if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg,
8558 imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 ||
8559 scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name,
8560 imp_prop) != 0) {
8561 switch (scf_error()) {
8562 case SCF_ERROR_NOT_FOUND:
8563 case SCF_ERROR_DELETED:
8564 break;
8565
8566 case SCF_ERROR_CONNECTION_BROKEN:
8567 case SCF_ERROR_NOT_SET:
8568 case SCF_ERROR_INVALID_ARGUMENT:
8569 case SCF_ERROR_HANDLE_MISMATCH:
8570 case SCF_ERROR_NOT_BOUND:
8571 default:
8572 bad_error("entity_get_pg", scf_error());
8573 }
8574 } else {
8575 /*
8576 * Found the dependents/<wip dep> so check to
8577 * see if the service is different. If so
8578 * store the service for later refresh, and
8579 * delete the wip dependency from the service
8580 */
8581 if (scf_property_get_value(imp_prop, ud_val) != 0) {
8582 switch (scf_error()) {
8583 case SCF_ERROR_DELETED:
8584 break;
8585
8586 case SCF_ERROR_CONNECTION_BROKEN:
8587 case SCF_ERROR_NOT_SET:
8588 case SCF_ERROR_INVALID_ARGUMENT:
8589 case SCF_ERROR_HANDLE_MISMATCH:
8590 case SCF_ERROR_NOT_BOUND:
8591 default:
8592 bad_error("scf_property_get_value",
8593 scf_error());
8594 }
8595 }
8596
8597 if (scf_value_get_as_string(ud_val, ud_oldtarg,
8598 max_scf_value_len + 1) < 0)
8599 bad_error("scf_value_get_as_string", scf_error());
8600
8601 r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
8602 switch (r) {
8603 case 1:
8604 break;
8605 case 0:
8606 if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent,
8607 &tissvc)) != SCF_ERROR_NONE) {
8608 if (serr == SCF_ERROR_NOT_FOUND) {
8609 break;
8610 } else {
8611 bad_error("fmri_to_entity", serr);
8612 }
8613 }
8614
8615 if (entity_get_pg(tent, tissvc,
8616 dpt_pgroup->sc_pgroup_name, imp_pg) != 0) {
8617 serr = scf_error();
8618 if (serr == SCF_ERROR_NOT_FOUND ||
8619 serr == SCF_ERROR_DELETED) {
8620 break;
8621 } else {
8622 bad_error("entity_get_pg", scf_error());
8623 }
8624 }
8625
8626 if (scf_pg_delete(imp_pg) != 0) {
8627 serr = scf_error();
8628 if (serr == SCF_ERROR_NOT_FOUND ||
8629 serr == SCF_ERROR_DELETED) {
8630 break;
8631 } else {
8632 bad_error("scf_pg_delete", scf_error());
8633 }
8634 }
8635
8636 deldpt = internal_pgroup_new();
8637 if (deldpt == NULL)
8638 return (ENOMEM);
8639 deldpt->sc_pgroup_name =
8640 strdup(dpt_pgroup->sc_pgroup_name);
8641 deldpt->sc_pgroup_fmri = strdup(ud_oldtarg);
8642 if (deldpt->sc_pgroup_name == NULL ||
8643 deldpt->sc_pgroup_fmri == NULL)
8644 return (ENOMEM);
8645 deldpt->sc_parent = (entity_t *)ent;
8646 if (uu_list_insert_after(imp_deleted_dpts, NULL,
8647 deldpt) != 0)
8648 uu_die(gettext("libuutil error: %s\n"),
8649 uu_strerror(uu_error()));
8650
8651 break;
8652 default:
8653 bad_error("fmri_equal", r);
8654 }
8655 }
8656
8657 cb.sc_handle = g_hndl;
8658 cb.sc_parent = ent;
8659 cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT;
8660 cb.sc_source_fmri = ent->sc_fmri;
8661 cb.sc_target_fmri = ent->sc_fmri;
8662 cb.sc_trans = NULL;
8663 cb.sc_flags = SCI_FORCE;
8664
8665 if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT)
8666 return (UU_WALK_ERROR);
8667
8668 r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL);
8669 switch (r) {
8670 case 0:
8671 break;
8672
8673 case ENOMEM:
8674 case ECONNABORTED:
8675 case EPERM:
8676 case -1:
8677 warn(gettext("Unable to refresh \"%s\"\n"),
8678 dpt_pgroup->sc_pgroup_fmri);
8679 return (UU_WALK_ERROR);
8680
8681 default:
8682 bad_error("imp_refresh_fmri", r);
8683 }
8684
8685 return (UU_WALK_NEXT);
8686 }
8687
8688 /*
8689 * Returns
8690 * 0 - success
8691 * -1 - lscf_import_instance_pgs() failed.
8692 */
8693 int
lscf_bundle_apply(bundle_t * bndl,const char * file)8694 lscf_bundle_apply(bundle_t *bndl, const char *file)
8695 {
8696 pgroup_t *old_dpt;
8697 entity_t *svc, *inst;
8698 int annotation_set = 0;
8699 int ret = 0;
8700 int r = 0;
8701
8702 lscf_prep_hndl();
8703
8704 if ((ret = alloc_imp_globals()))
8705 goto out;
8706
8707 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0)
8708 scfdie();
8709
8710 /*
8711 * Set the strings to be used for the security audit annotation
8712 * event.
8713 */
8714 if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
8715 annotation_set = 1;
8716 } else {
8717 switch (scf_error()) {
8718 case SCF_ERROR_CONNECTION_BROKEN:
8719 warn(gettext("Repository connection broken.\n"));
8720 goto out;
8721
8722 case SCF_ERROR_INVALID_ARGUMENT:
8723 case SCF_ERROR_NOT_BOUND:
8724 case SCF_ERROR_NO_RESOURCES:
8725 case SCF_ERROR_INTERNAL:
8726 bad_error("_scf_set_annotation", scf_error());
8727 /* NOTREACHED */
8728
8729 default:
8730 /*
8731 * Do not abort apply operation because of
8732 * inability to create annotation audit event.
8733 */
8734 warn(gettext("_scf_set_annotation() unexpectedly "
8735 "failed with return code of %d\n"), scf_error());
8736 break;
8737 }
8738 }
8739
8740 for (svc = uu_list_first(bndl->sc_bundle_services);
8741 svc != NULL;
8742 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8743 int refresh = 0;
8744
8745 if (scf_scope_get_service(imp_scope, svc->sc_name,
8746 imp_svc) != 0) {
8747 switch (scf_error()) {
8748 case SCF_ERROR_NOT_FOUND:
8749 if (g_verbose)
8750 warn(gettext("Ignoring nonexistent "
8751 "service %s.\n"), svc->sc_name);
8752 continue;
8753
8754 default:
8755 scfdie();
8756 }
8757 }
8758
8759 /*
8760 * If there were missing types in the profile, then need to
8761 * attempt to find the types.
8762 */
8763 if (svc->sc_miss_type) {
8764 if (uu_list_numnodes(svc->sc_pgroups) &&
8765 uu_list_walk(svc->sc_pgroups, find_current_pg_type,
8766 svc, UU_DEFAULT) != 0) {
8767 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8768 bad_error("uu_list_walk", uu_error());
8769
8770 ret = -1;
8771 continue;
8772 }
8773
8774 for (inst = uu_list_first(
8775 svc->sc_u.sc_service.sc_service_instances);
8776 inst != NULL;
8777 inst = uu_list_next(
8778 svc->sc_u.sc_service.sc_service_instances, inst)) {
8779 /*
8780 * If the instance doesn't exist just
8781 * skip to the next instance and let the
8782 * import note the missing instance.
8783 */
8784 if (scf_service_get_instance(imp_svc,
8785 inst->sc_name, imp_inst) != 0)
8786 continue;
8787
8788 if (uu_list_walk(inst->sc_pgroups,
8789 find_current_pg_type, inst,
8790 UU_DEFAULT) != 0) {
8791 if (uu_error() !=
8792 UU_ERROR_CALLBACK_FAILED)
8793 bad_error("uu_list_walk",
8794 uu_error());
8795
8796 ret = -1;
8797 inst->sc_miss_type = B_TRUE;
8798 }
8799 }
8800 }
8801
8802 /*
8803 * if we have pgs in the profile, we need to refresh ALL
8804 * instances of the service
8805 */
8806 if (uu_list_numnodes(svc->sc_pgroups) != 0) {
8807 refresh = 1;
8808 r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc,
8809 SCI_FORCE | SCI_KEEP);
8810 switch (_lscf_import_err(r, svc->sc_fmri)) {
8811 case IMPORT_NEXT:
8812 break;
8813
8814 case IMPORT_OUT:
8815 goto out;
8816
8817 case IMPORT_BAD:
8818 default:
8819 bad_error("lscf_import_service_pgs", r);
8820 }
8821 }
8822
8823 if (uu_list_numnodes(svc->sc_dependents) != 0) {
8824 uu_list_walk(svc->sc_dependents,
8825 lscf_dependent_apply, svc, UU_DEFAULT);
8826 }
8827
8828 for (inst = uu_list_first(
8829 svc->sc_u.sc_service.sc_service_instances);
8830 inst != NULL;
8831 inst = uu_list_next(
8832 svc->sc_u.sc_service.sc_service_instances, inst)) {
8833 /*
8834 * This instance still has missing types
8835 * so skip it.
8836 */
8837 if (inst->sc_miss_type) {
8838 if (g_verbose)
8839 warn(gettext("Ignoring instance "
8840 "%s:%s with missing types\n"),
8841 inst->sc_parent->sc_name,
8842 inst->sc_name);
8843
8844 continue;
8845 }
8846
8847 if (scf_service_get_instance(imp_svc, inst->sc_name,
8848 imp_inst) != 0) {
8849 switch (scf_error()) {
8850 case SCF_ERROR_NOT_FOUND:
8851 if (g_verbose)
8852 warn(gettext("Ignoring "
8853 "nonexistant instance "
8854 "%s:%s.\n"),
8855 inst->sc_parent->sc_name,
8856 inst->sc_name);
8857 continue;
8858
8859 default:
8860 scfdie();
8861 }
8862 }
8863
8864 /*
8865 * If the instance does not have a general/enabled
8866 * property and no last-import snapshot then the
8867 * instance is not a fully installed instance and
8868 * should not have a profile applied to it.
8869 *
8870 * This could happen if a service/instance declares
8871 * a dependent on behalf of another service/instance.
8872 *
8873 */
8874 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
8875 imp_snap) != 0) {
8876 if (scf_instance_get_pg(imp_inst,
8877 SCF_PG_GENERAL, imp_pg) != 0 ||
8878 scf_pg_get_property(imp_pg,
8879 SCF_PROPERTY_ENABLED, imp_prop) != 0) {
8880 if (g_verbose)
8881 warn(gettext("Ignoreing "
8882 "partial instance "
8883 "%s:%s.\n"),
8884 inst->sc_parent->sc_name,
8885 inst->sc_name);
8886 continue;
8887 }
8888 }
8889
8890 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri,
8891 inst, SCI_FORCE | SCI_KEEP);
8892 switch (_lscf_import_err(r, inst->sc_fmri)) {
8893 case IMPORT_NEXT:
8894 break;
8895
8896 case IMPORT_OUT:
8897 goto out;
8898
8899 case IMPORT_BAD:
8900 default:
8901 bad_error("lscf_import_instance_pgs", r);
8902 }
8903
8904 if (uu_list_numnodes(inst->sc_dependents) != 0) {
8905 uu_list_walk(inst->sc_dependents,
8906 lscf_dependent_apply, inst, UU_DEFAULT);
8907 }
8908
8909 /* refresh only if there is no pgs in the service */
8910 if (refresh == 0)
8911 (void) refresh_entity(0, imp_inst,
8912 inst->sc_fmri, NULL, NULL, NULL);
8913 }
8914
8915 if (refresh == 1) {
8916 char *name_buf = safe_malloc(max_scf_name_len + 1);
8917
8918 (void) refresh_entity(1, imp_svc, svc->sc_name,
8919 imp_inst, imp_iter, name_buf);
8920 free(name_buf);
8921 }
8922
8923 for (old_dpt = uu_list_first(imp_deleted_dpts);
8924 old_dpt != NULL;
8925 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) {
8926 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8927 old_dpt->sc_pgroup_name,
8928 old_dpt->sc_parent->sc_fmri) != 0) {
8929 warn(gettext("Unable to refresh \"%s\"\n"),
8930 old_dpt->sc_pgroup_fmri);
8931 }
8932 }
8933 }
8934
8935 out:
8936 if (annotation_set) {
8937 /* Remove security audit annotation strings. */
8938 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8939 }
8940
8941 free_imp_globals();
8942 return (ret);
8943 }
8944
8945
8946 /*
8947 * Export. These functions create and output an XML tree of a service
8948 * description from the repository. This is largely the inverse of
8949 * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
8950 *
8951 * - We must include any properties which are not represented specifically by
8952 * a service manifest, e.g., properties created by an admin post-import. To
8953 * do so we'll iterate through all properties and deal with each
8954 * apropriately.
8955 *
8956 * - Children of services and instances must must be in the order set by the
8957 * DTD, but we iterate over the properties in undefined order. The elements
8958 * are not easily (or efficiently) sortable by name. Since there's a fixed
8959 * number of classes of them, however, we'll keep the classes separate and
8960 * assemble them in order.
8961 */
8962
8963 /*
8964 * Convenience function to handle xmlSetProp errors (and type casting).
8965 */
8966 static void
safe_setprop(xmlNodePtr n,const char * name,const char * val)8967 safe_setprop(xmlNodePtr n, const char *name, const char *val)
8968 {
8969 if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
8970 uu_die(gettext("Could not set XML property.\n"));
8971 }
8972
8973 /*
8974 * Convenience function to set an XML attribute to the single value of an
8975 * astring property. If the value happens to be the default, don't set the
8976 * attribute. "dval" should be the default value supplied by the DTD, or
8977 * NULL for no default.
8978 */
8979 static int
set_attr_from_prop_default(scf_property_t * prop,xmlNodePtr n,const char * name,const char * dval)8980 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
8981 const char *name, const char *dval)
8982 {
8983 scf_value_t *val;
8984 ssize_t len;
8985 char *str;
8986
8987 val = scf_value_create(g_hndl);
8988 if (val == NULL)
8989 scfdie();
8990
8991 if (prop_get_val(prop, val) != 0) {
8992 scf_value_destroy(val);
8993 return (-1);
8994 }
8995
8996 len = scf_value_get_as_string(val, NULL, 0);
8997 if (len < 0)
8998 scfdie();
8999
9000 str = safe_malloc(len + 1);
9001
9002 if (scf_value_get_as_string(val, str, len + 1) < 0)
9003 scfdie();
9004
9005 scf_value_destroy(val);
9006
9007 if (dval == NULL || strcmp(str, dval) != 0)
9008 safe_setprop(n, name, str);
9009
9010 free(str);
9011
9012 return (0);
9013 }
9014
9015 /*
9016 * As above, but the attribute is always set.
9017 */
9018 static int
set_attr_from_prop(scf_property_t * prop,xmlNodePtr n,const char * name)9019 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
9020 {
9021 return (set_attr_from_prop_default(prop, n, name, NULL));
9022 }
9023
9024 /*
9025 * Dump the given document onto f, with "'s replaced by ''s.
9026 */
9027 static int
write_service_bundle(xmlDocPtr doc,FILE * f)9028 write_service_bundle(xmlDocPtr doc, FILE *f)
9029 {
9030 xmlChar *mem;
9031 int sz, i;
9032
9033 mem = NULL;
9034 xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
9035
9036 if (mem == NULL) {
9037 semerr(gettext("Could not dump XML tree.\n"));
9038 return (-1);
9039 }
9040
9041 /*
9042 * Fortunately libxml produces " instead of ", so we can blindly
9043 * replace all " with '. Cursed libxml2! Why must you #ifdef out the
9044 * ' code?!
9045 */
9046 for (i = 0; i < sz; ++i) {
9047 char c = (char)mem[i];
9048
9049 if (c == '"')
9050 (void) fputc('\'', f);
9051 else if (c == '\'')
9052 (void) fwrite("'", sizeof ("'") - 1, 1, f);
9053 else
9054 (void) fputc(c, f);
9055 }
9056
9057 return (0);
9058 }
9059
9060 /*
9061 * Create the DOM elements in elts necessary to (generically) represent prop
9062 * (i.e., a property or propval element). If the name of the property is
9063 * known, it should be passed as name_arg. Otherwise, pass NULL.
9064 */
9065 static void
export_property(scf_property_t * prop,const char * name_arg,struct pg_elts * elts,int flags)9066 export_property(scf_property_t *prop, const char *name_arg,
9067 struct pg_elts *elts, int flags)
9068 {
9069 const char *type;
9070 scf_error_t err = 0;
9071 xmlNodePtr pnode, lnode;
9072 char *lnname;
9073 int ret;
9074
9075 /* name */
9076 if (name_arg != NULL) {
9077 (void) strcpy(exp_str, name_arg);
9078 } else {
9079 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
9080 scfdie();
9081 }
9082
9083 /* type */
9084 type = prop_to_typestr(prop);
9085 if (type == NULL)
9086 uu_die(gettext("Can't export property %s: unknown type.\n"),
9087 exp_str);
9088
9089 /* If we're exporting values, and there's just one, export it here. */
9090 if (!(flags & SCE_ALL_VALUES))
9091 goto empty;
9092
9093 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
9094 xmlNodePtr n;
9095
9096 /* Single value, so use propval */
9097 n = xmlNewNode(NULL, (xmlChar *)"propval");
9098 if (n == NULL)
9099 uu_die(emsg_create_xml);
9100
9101 safe_setprop(n, name_attr, exp_str);
9102 safe_setprop(n, type_attr, type);
9103
9104 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9105 scfdie();
9106 safe_setprop(n, value_attr, exp_str);
9107
9108 if (elts->propvals == NULL)
9109 elts->propvals = n;
9110 else
9111 (void) xmlAddSibling(elts->propvals, n);
9112
9113 return;
9114 }
9115
9116 err = scf_error();
9117
9118 if (err == SCF_ERROR_PERMISSION_DENIED) {
9119 semerr(emsg_permission_denied);
9120 return;
9121 }
9122
9123 if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
9124 err != SCF_ERROR_NOT_FOUND &&
9125 err != SCF_ERROR_PERMISSION_DENIED)
9126 scfdie();
9127
9128 empty:
9129 /* Multiple (or no) values, so use property */
9130 pnode = xmlNewNode(NULL, (xmlChar *)"property");
9131 if (pnode == NULL)
9132 uu_die(emsg_create_xml);
9133
9134 safe_setprop(pnode, name_attr, exp_str);
9135 safe_setprop(pnode, type_attr, type);
9136
9137 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
9138 lnname = uu_msprintf("%s_list", type);
9139 if (lnname == NULL)
9140 uu_die(gettext("Could not create string"));
9141
9142 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
9143 if (lnode == NULL)
9144 uu_die(emsg_create_xml);
9145
9146 uu_free(lnname);
9147
9148 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
9149 scfdie();
9150
9151 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
9152 1) {
9153 xmlNodePtr vn;
9154
9155 vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
9156 NULL);
9157 if (vn == NULL)
9158 uu_die(emsg_create_xml);
9159
9160 if (scf_value_get_as_string(exp_val, exp_str,
9161 exp_str_sz) < 0)
9162 scfdie();
9163 safe_setprop(vn, value_attr, exp_str);
9164 }
9165 if (ret != 0)
9166 scfdie();
9167 }
9168
9169 if (elts->properties == NULL)
9170 elts->properties = pnode;
9171 else
9172 (void) xmlAddSibling(elts->properties, pnode);
9173 }
9174
9175 /*
9176 * Add a property_group element for this property group to elts.
9177 */
9178 static void
export_pg(scf_propertygroup_t * pg,struct entity_elts * eelts,int flags)9179 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
9180 {
9181 xmlNodePtr n;
9182 struct pg_elts elts;
9183 int ret;
9184 boolean_t read_protected;
9185
9186 n = xmlNewNode(NULL, (xmlChar *)"property_group");
9187
9188 /* name */
9189 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9190 scfdie();
9191 safe_setprop(n, name_attr, exp_str);
9192
9193 /* type */
9194 if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
9195 scfdie();
9196 safe_setprop(n, type_attr, exp_str);
9197
9198 /* properties */
9199 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9200 scfdie();
9201
9202 (void) memset(&elts, 0, sizeof (elts));
9203
9204 /*
9205 * If this property group is not read protected, we always want to
9206 * output all the values. Otherwise, we only output the values if the
9207 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
9208 */
9209 if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
9210 scfdie();
9211
9212 if (!read_protected)
9213 flags |= SCE_ALL_VALUES;
9214
9215 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9216 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9217 scfdie();
9218
9219 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9220 xmlNodePtr m;
9221
9222 m = xmlNewNode(NULL, (xmlChar *)"stability");
9223 if (m == NULL)
9224 uu_die(emsg_create_xml);
9225
9226 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9227 elts.stability = m;
9228 continue;
9229 }
9230
9231 xmlFreeNode(m);
9232 }
9233
9234 export_property(exp_prop, NULL, &elts, flags);
9235 }
9236 if (ret == -1)
9237 scfdie();
9238
9239 (void) xmlAddChild(n, elts.stability);
9240 (void) xmlAddChildList(n, elts.propvals);
9241 (void) xmlAddChildList(n, elts.properties);
9242
9243 if (eelts->property_groups == NULL)
9244 eelts->property_groups = n;
9245 else
9246 (void) xmlAddSibling(eelts->property_groups, n);
9247 }
9248
9249 /*
9250 * Create an XML node representing the dependency described by the given
9251 * property group and put it in eelts. Unless the dependency is not valid, in
9252 * which case create a generic property_group element which represents it and
9253 * put it in eelts.
9254 */
9255 static void
export_dependency(scf_propertygroup_t * pg,struct entity_elts * eelts)9256 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
9257 {
9258 xmlNodePtr n;
9259 int err = 0, ret;
9260 struct pg_elts elts;
9261
9262 n = xmlNewNode(NULL, (xmlChar *)"dependency");
9263 if (n == NULL)
9264 uu_die(emsg_create_xml);
9265
9266 /*
9267 * If the external flag is present, skip this dependency because it
9268 * should have been created by another manifest.
9269 */
9270 if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
9271 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9272 prop_get_val(exp_prop, exp_val) == 0) {
9273 uint8_t b;
9274
9275 if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
9276 scfdie();
9277
9278 if (b)
9279 return;
9280 }
9281 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
9282 scfdie();
9283
9284 /* Get the required attributes. */
9285
9286 /* name */
9287 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9288 scfdie();
9289 safe_setprop(n, name_attr, exp_str);
9290
9291 /* grouping */
9292 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9293 set_attr_from_prop(exp_prop, n, "grouping") != 0)
9294 err = 1;
9295
9296 /* restart_on */
9297 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9298 set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9299 err = 1;
9300
9301 /* type */
9302 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9303 set_attr_from_prop(exp_prop, n, type_attr) != 0)
9304 err = 1;
9305
9306 /*
9307 * entities: Not required, but if we create no children, it will be
9308 * created as empty on import, so fail if it's missing.
9309 */
9310 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9311 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
9312 scf_iter_t *eiter;
9313 int ret2;
9314
9315 eiter = scf_iter_create(g_hndl);
9316 if (eiter == NULL)
9317 scfdie();
9318
9319 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
9320 scfdie();
9321
9322 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
9323 xmlNodePtr ch;
9324
9325 if (scf_value_get_astring(exp_val, exp_str,
9326 exp_str_sz) < 0)
9327 scfdie();
9328
9329 /*
9330 * service_fmri's must be first, so we can add them
9331 * here.
9332 */
9333 ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
9334 NULL);
9335 if (ch == NULL)
9336 uu_die(emsg_create_xml);
9337
9338 safe_setprop(ch, value_attr, exp_str);
9339 }
9340 if (ret2 == -1)
9341 scfdie();
9342
9343 scf_iter_destroy(eiter);
9344 } else
9345 err = 1;
9346
9347 if (err) {
9348 xmlFreeNode(n);
9349
9350 export_pg(pg, eelts, SCE_ALL_VALUES);
9351
9352 return;
9353 }
9354
9355 /* Iterate through the properties & handle each. */
9356 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9357 scfdie();
9358
9359 (void) memset(&elts, 0, sizeof (elts));
9360
9361 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9362 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9363 scfdie();
9364
9365 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9366 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9367 strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9368 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9369 continue;
9370 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9371 xmlNodePtr m;
9372
9373 m = xmlNewNode(NULL, (xmlChar *)"stability");
9374 if (m == NULL)
9375 uu_die(emsg_create_xml);
9376
9377 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9378 elts.stability = m;
9379 continue;
9380 }
9381
9382 xmlFreeNode(m);
9383 }
9384
9385 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9386 }
9387 if (ret == -1)
9388 scfdie();
9389
9390 (void) xmlAddChild(n, elts.stability);
9391 (void) xmlAddChildList(n, elts.propvals);
9392 (void) xmlAddChildList(n, elts.properties);
9393
9394 if (eelts->dependencies == NULL)
9395 eelts->dependencies = n;
9396 else
9397 (void) xmlAddSibling(eelts->dependencies, n);
9398 }
9399
9400 static xmlNodePtr
export_method_environment(scf_propertygroup_t * pg)9401 export_method_environment(scf_propertygroup_t *pg)
9402 {
9403 xmlNodePtr env;
9404 int ret;
9405 int children = 0;
9406
9407 if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
9408 return (NULL);
9409
9410 env = xmlNewNode(NULL, (xmlChar *)"method_environment");
9411 if (env == NULL)
9412 uu_die(emsg_create_xml);
9413
9414 if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
9415 scfdie();
9416
9417 if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
9418 scfdie();
9419
9420 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
9421 xmlNodePtr ev;
9422 char *cp;
9423
9424 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9425 scfdie();
9426
9427 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
9428 warn(gettext("Invalid environment variable \"%s\".\n"),
9429 exp_str);
9430 continue;
9431 } else if (strncmp(exp_str, "SMF_", 4) == 0) {
9432 warn(gettext("Invalid environment variable \"%s\"; "
9433 "\"SMF_\" prefix is reserved.\n"), exp_str);
9434 continue;
9435 }
9436
9437 *cp = '\0';
9438 cp++;
9439
9440 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
9441 if (ev == NULL)
9442 uu_die(emsg_create_xml);
9443
9444 safe_setprop(ev, name_attr, exp_str);
9445 safe_setprop(ev, value_attr, cp);
9446 children++;
9447 }
9448
9449 if (ret != 0)
9450 scfdie();
9451
9452 if (children == 0) {
9453 xmlFreeNode(env);
9454 return (NULL);
9455 }
9456
9457 return (env);
9458 }
9459
9460 /*
9461 * As above, but for a method property group.
9462 */
9463 static void
export_method(scf_propertygroup_t * pg,struct entity_elts * eelts)9464 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
9465 {
9466 xmlNodePtr n, env;
9467 char *str;
9468 int err = 0, nonenv, ret;
9469 uint8_t use_profile;
9470 struct pg_elts elts;
9471 xmlNodePtr ctxt = NULL;
9472
9473 n = xmlNewNode(NULL, (xmlChar *)"exec_method");
9474
9475 /* Get the required attributes. */
9476
9477 /* name */
9478 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9479 scfdie();
9480 safe_setprop(n, name_attr, exp_str);
9481
9482 /* type */
9483 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9484 set_attr_from_prop(exp_prop, n, type_attr) != 0)
9485 err = 1;
9486
9487 /* exec */
9488 if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
9489 set_attr_from_prop(exp_prop, n, "exec") != 0)
9490 err = 1;
9491
9492 /* timeout */
9493 if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
9494 prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
9495 prop_get_val(exp_prop, exp_val) == 0) {
9496 uint64_t c;
9497
9498 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
9499 scfdie();
9500
9501 str = uu_msprintf("%llu", c);
9502 if (str == NULL)
9503 uu_die(gettext("Could not create string"));
9504
9505 safe_setprop(n, "timeout_seconds", str);
9506 free(str);
9507 } else
9508 err = 1;
9509
9510 if (err) {
9511 xmlFreeNode(n);
9512
9513 export_pg(pg, eelts, SCE_ALL_VALUES);
9514
9515 return;
9516 }
9517
9518
9519 /*
9520 * If we're going to have a method_context child, we need to know
9521 * before we iterate through the properties. Since method_context's
9522 * are optional, we don't want to complain about any properties
9523 * missing if none of them are there. Thus we can't use the
9524 * convenience functions.
9525 */
9526 nonenv =
9527 scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
9528 SCF_SUCCESS ||
9529 scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
9530 SCF_SUCCESS ||
9531 scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
9532 SCF_SUCCESS ||
9533 scf_pg_get_property(pg, SCF_PROPERTY_SECFLAGS, NULL) ==
9534 SCF_SUCCESS ||
9535 scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
9536 SCF_SUCCESS;
9537
9538 if (nonenv) {
9539 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9540 if (ctxt == NULL)
9541 uu_die(emsg_create_xml);
9542
9543 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
9544 0 &&
9545 set_attr_from_prop_default(exp_prop, ctxt,
9546 "working_directory", ":default") != 0)
9547 err = 1;
9548
9549 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
9550 set_attr_from_prop_default(exp_prop, ctxt, "project",
9551 ":default") != 0)
9552 err = 1;
9553
9554 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
9555 0 &&
9556 set_attr_from_prop_default(exp_prop, ctxt,
9557 "resource_pool", ":default") != 0)
9558 err = 1;
9559
9560 if (pg_get_prop(pg, SCF_PROPERTY_SECFLAGS, exp_prop) == 0 &&
9561 set_attr_from_prop_default(exp_prop, ctxt,
9562 "security_flags", ":default") != 0)
9563 err = 1;
9564
9565 /*
9566 * We only want to complain about profile or credential
9567 * properties if we will use them. To determine that we must
9568 * examine USE_PROFILE.
9569 */
9570 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9571 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9572 prop_get_val(exp_prop, exp_val) == 0) {
9573 if (scf_value_get_boolean(exp_val, &use_profile) !=
9574 SCF_SUCCESS) {
9575 scfdie();
9576 }
9577
9578 if (use_profile) {
9579 xmlNodePtr prof;
9580
9581 prof = xmlNewChild(ctxt, NULL,
9582 (xmlChar *)"method_profile", NULL);
9583 if (prof == NULL)
9584 uu_die(emsg_create_xml);
9585
9586 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
9587 exp_prop) != 0 ||
9588 set_attr_from_prop(exp_prop, prof,
9589 name_attr) != 0)
9590 err = 1;
9591 } else {
9592 xmlNodePtr cred;
9593
9594 cred = xmlNewChild(ctxt, NULL,
9595 (xmlChar *)"method_credential", NULL);
9596 if (cred == NULL)
9597 uu_die(emsg_create_xml);
9598
9599 if (pg_get_prop(pg, SCF_PROPERTY_USER,
9600 exp_prop) != 0 ||
9601 set_attr_from_prop(exp_prop, cred,
9602 "user") != 0) {
9603 err = 1;
9604 }
9605
9606 if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
9607 exp_prop) == 0 &&
9608 set_attr_from_prop_default(exp_prop, cred,
9609 "group", ":default") != 0)
9610 err = 1;
9611
9612 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
9613 exp_prop) == 0 &&
9614 set_attr_from_prop_default(exp_prop, cred,
9615 "supp_groups", ":default") != 0)
9616 err = 1;
9617
9618 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
9619 exp_prop) == 0 &&
9620 set_attr_from_prop_default(exp_prop, cred,
9621 "privileges", ":default") != 0)
9622 err = 1;
9623
9624 if (pg_get_prop(pg,
9625 SCF_PROPERTY_LIMIT_PRIVILEGES,
9626 exp_prop) == 0 &&
9627 set_attr_from_prop_default(exp_prop, cred,
9628 "limit_privileges", ":default") != 0)
9629 err = 1;
9630 }
9631 }
9632 }
9633
9634 if ((env = export_method_environment(pg)) != NULL) {
9635 if (ctxt == NULL) {
9636 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9637 if (ctxt == NULL)
9638 uu_die(emsg_create_xml);
9639 }
9640 (void) xmlAddChild(ctxt, env);
9641 }
9642
9643 if (env != NULL || (nonenv && err == 0))
9644 (void) xmlAddChild(n, ctxt);
9645 else
9646 xmlFreeNode(ctxt);
9647
9648 nonenv = (err == 0);
9649
9650 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9651 scfdie();
9652
9653 (void) memset(&elts, 0, sizeof (elts));
9654
9655 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9656 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9657 scfdie();
9658
9659 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9660 strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
9661 strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
9662 continue;
9663 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9664 xmlNodePtr m;
9665
9666 m = xmlNewNode(NULL, (xmlChar *)"stability");
9667 if (m == NULL)
9668 uu_die(emsg_create_xml);
9669
9670 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9671 elts.stability = m;
9672 continue;
9673 }
9674
9675 xmlFreeNode(m);
9676 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
9677 0 ||
9678 strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
9679 strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
9680 strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9681 if (nonenv)
9682 continue;
9683 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
9684 strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
9685 strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
9686 strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
9687 strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0 ||
9688 strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9689 if (nonenv && !use_profile)
9690 continue;
9691 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9692 if (nonenv && use_profile)
9693 continue;
9694 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
9695 if (env != NULL)
9696 continue;
9697 }
9698
9699 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9700 }
9701 if (ret == -1)
9702 scfdie();
9703
9704 (void) xmlAddChild(n, elts.stability);
9705 (void) xmlAddChildList(n, elts.propvals);
9706 (void) xmlAddChildList(n, elts.properties);
9707
9708 if (eelts->exec_methods == NULL)
9709 eelts->exec_methods = n;
9710 else
9711 (void) xmlAddSibling(eelts->exec_methods, n);
9712 }
9713
9714 static void
export_pg_elts(struct pg_elts * elts,const char * name,const char * type,struct entity_elts * eelts)9715 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
9716 struct entity_elts *eelts)
9717 {
9718 xmlNodePtr pgnode;
9719
9720 pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
9721 if (pgnode == NULL)
9722 uu_die(emsg_create_xml);
9723
9724 safe_setprop(pgnode, name_attr, name);
9725 safe_setprop(pgnode, type_attr, type);
9726
9727 (void) xmlAddChildList(pgnode, elts->propvals);
9728 (void) xmlAddChildList(pgnode, elts->properties);
9729
9730 if (eelts->property_groups == NULL)
9731 eelts->property_groups = pgnode;
9732 else
9733 (void) xmlAddSibling(eelts->property_groups, pgnode);
9734 }
9735
9736 /*
9737 * Process the general property group for a service. This is the one with the
9738 * goodies.
9739 */
9740 static void
export_svc_general(scf_propertygroup_t * pg,struct entity_elts * selts)9741 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
9742 {
9743 struct pg_elts elts;
9744 int ret;
9745
9746 /*
9747 * In case there are properties which don't correspond to child
9748 * entities of the service entity, we'll set up a pg_elts structure to
9749 * put them in.
9750 */
9751 (void) memset(&elts, 0, sizeof (elts));
9752
9753 /* Walk the properties, looking for special ones. */
9754 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9755 scfdie();
9756
9757 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9758 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9759 scfdie();
9760
9761 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
9762 /*
9763 * Unimplemented and obsolete, but we still process it
9764 * for compatibility purposes.
9765 */
9766 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9767 prop_get_val(exp_prop, exp_val) == 0) {
9768 uint8_t b;
9769
9770 if (scf_value_get_boolean(exp_val, &b) !=
9771 SCF_SUCCESS)
9772 scfdie();
9773
9774 if (b) {
9775 selts->single_instance =
9776 xmlNewNode(NULL,
9777 (xmlChar *)"single_instance");
9778 if (selts->single_instance == NULL)
9779 uu_die(emsg_create_xml);
9780 }
9781
9782 continue;
9783 }
9784 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9785 xmlNodePtr rnode, sfnode;
9786
9787 rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9788 if (rnode == NULL)
9789 uu_die(emsg_create_xml);
9790
9791 sfnode = xmlNewChild(rnode, NULL,
9792 (xmlChar *)"service_fmri", NULL);
9793 if (sfnode == NULL)
9794 uu_die(emsg_create_xml);
9795
9796 if (set_attr_from_prop(exp_prop, sfnode,
9797 value_attr) == 0) {
9798 selts->restarter = rnode;
9799 continue;
9800 }
9801
9802 xmlFreeNode(rnode);
9803 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
9804 0) {
9805 xmlNodePtr s;
9806
9807 s = xmlNewNode(NULL, (xmlChar *)"stability");
9808 if (s == NULL)
9809 uu_die(emsg_create_xml);
9810
9811 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9812 selts->stability = s;
9813 continue;
9814 }
9815
9816 xmlFreeNode(s);
9817 }
9818
9819 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9820 }
9821 if (ret == -1)
9822 scfdie();
9823
9824 if (elts.propvals != NULL || elts.properties != NULL)
9825 export_pg_elts(&elts, scf_pg_general, scf_group_framework,
9826 selts);
9827 }
9828
9829 static void
export_method_context(scf_propertygroup_t * pg,struct entity_elts * elts)9830 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
9831 {
9832 xmlNodePtr n, prof, cred, env;
9833 uint8_t use_profile;
9834 int ret, err = 0;
9835
9836 n = xmlNewNode(NULL, (xmlChar *)"method_context");
9837
9838 env = export_method_environment(pg);
9839
9840 /* Need to know whether we'll use a profile or not. */
9841 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9842 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9843 prop_get_val(exp_prop, exp_val) == 0) {
9844 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
9845 scfdie();
9846
9847 if (use_profile)
9848 prof =
9849 xmlNewChild(n, NULL, (xmlChar *)"method_profile",
9850 NULL);
9851 else
9852 cred =
9853 xmlNewChild(n, NULL, (xmlChar *)"method_credential",
9854 NULL);
9855 }
9856
9857 if (env != NULL)
9858 (void) xmlAddChild(n, env);
9859
9860 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9861 scfdie();
9862
9863 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9864 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9865 scfdie();
9866
9867 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
9868 if (set_attr_from_prop(exp_prop, n,
9869 "working_directory") != 0)
9870 err = 1;
9871 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
9872 if (set_attr_from_prop(exp_prop, n, "project") != 0)
9873 err = 1;
9874 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
9875 if (set_attr_from_prop(exp_prop, n,
9876 "resource_pool") != 0)
9877 err = 1;
9878 } else if (strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9879 if (set_attr_from_prop(exp_prop, n,
9880 "security_flags") != 0)
9881 err = 1;
9882 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9883 /* EMPTY */
9884 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
9885 if (use_profile ||
9886 set_attr_from_prop(exp_prop, cred, "user") != 0)
9887 err = 1;
9888 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
9889 if (use_profile ||
9890 set_attr_from_prop(exp_prop, cred, "group") != 0)
9891 err = 1;
9892 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
9893 if (use_profile || set_attr_from_prop(exp_prop, cred,
9894 "supp_groups") != 0)
9895 err = 1;
9896 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
9897 if (use_profile || set_attr_from_prop(exp_prop, cred,
9898 "privileges") != 0)
9899 err = 1;
9900 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
9901 0) {
9902 if (use_profile || set_attr_from_prop(exp_prop, cred,
9903 "limit_privileges") != 0)
9904 err = 1;
9905 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9906 if (!use_profile || set_attr_from_prop(exp_prop,
9907 prof, name_attr) != 0)
9908 err = 1;
9909 } else {
9910 /* Can't have generic properties in method_context's */
9911 err = 1;
9912 }
9913 }
9914 if (ret == -1)
9915 scfdie();
9916
9917 if (err && env == NULL) {
9918 xmlFreeNode(n);
9919 export_pg(pg, elts, SCE_ALL_VALUES);
9920 return;
9921 }
9922
9923 elts->method_context = n;
9924 }
9925
9926 /*
9927 * Given a dependency property group in the tfmri entity (target fmri), return
9928 * a dependent element which represents it.
9929 */
9930 static xmlNodePtr
export_dependent(scf_propertygroup_t * pg,const char * name,const char * tfmri)9931 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
9932 {
9933 uint8_t b;
9934 xmlNodePtr n, sf;
9935 int err = 0, ret;
9936 struct pg_elts pgelts;
9937
9938 /*
9939 * If external isn't set to true then exporting the service will
9940 * export this as a normal dependency, so we should stop to avoid
9941 * duplication.
9942 */
9943 if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
9944 scf_property_get_value(exp_prop, exp_val) != 0 ||
9945 scf_value_get_boolean(exp_val, &b) != 0 || !b) {
9946 if (g_verbose) {
9947 warn(gettext("Dependent \"%s\" cannot be exported "
9948 "properly because the \"%s\" property of the "
9949 "\"%s\" dependency of %s is not set to true.\n"),
9950 name, scf_property_external, name, tfmri);
9951 }
9952
9953 return (NULL);
9954 }
9955
9956 n = xmlNewNode(NULL, (xmlChar *)"dependent");
9957 if (n == NULL)
9958 uu_die(emsg_create_xml);
9959
9960 safe_setprop(n, name_attr, name);
9961
9962 /* Get the required attributes */
9963 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9964 set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9965 err = 1;
9966
9967 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9968 set_attr_from_prop(exp_prop, n, "grouping") != 0)
9969 err = 1;
9970
9971 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9972 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
9973 prop_get_val(exp_prop, exp_val) == 0) {
9974 /* EMPTY */
9975 } else
9976 err = 1;
9977
9978 if (err) {
9979 xmlFreeNode(n);
9980 return (NULL);
9981 }
9982
9983 sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
9984 if (sf == NULL)
9985 uu_die(emsg_create_xml);
9986
9987 safe_setprop(sf, value_attr, tfmri);
9988
9989 /*
9990 * Now add elements for the other properties.
9991 */
9992 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9993 scfdie();
9994
9995 (void) memset(&pgelts, 0, sizeof (pgelts));
9996
9997 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9998 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9999 scfdie();
10000
10001 if (strcmp(exp_str, scf_property_external) == 0 ||
10002 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
10003 strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
10004 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
10005 continue;
10006 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
10007 if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
10008 prop_get_val(exp_prop, exp_val) == 0) {
10009 char type[sizeof ("service") + 1];
10010
10011 if (scf_value_get_astring(exp_val, type,
10012 sizeof (type)) < 0)
10013 scfdie();
10014
10015 if (strcmp(type, "service") == 0)
10016 continue;
10017 }
10018 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
10019 xmlNodePtr s;
10020
10021 s = xmlNewNode(NULL, (xmlChar *)"stability");
10022 if (s == NULL)
10023 uu_die(emsg_create_xml);
10024
10025 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
10026 pgelts.stability = s;
10027 continue;
10028 }
10029
10030 xmlFreeNode(s);
10031 }
10032
10033 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10034 }
10035 if (ret == -1)
10036 scfdie();
10037
10038 (void) xmlAddChild(n, pgelts.stability);
10039 (void) xmlAddChildList(n, pgelts.propvals);
10040 (void) xmlAddChildList(n, pgelts.properties);
10041
10042 return (n);
10043 }
10044
10045 static void
export_dependents(scf_propertygroup_t * pg,struct entity_elts * eelts)10046 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
10047 {
10048 scf_propertygroup_t *opg;
10049 scf_iter_t *iter;
10050 char *type, *fmri;
10051 int ret;
10052 struct pg_elts pgelts;
10053 xmlNodePtr n;
10054 scf_error_t serr;
10055
10056 if ((opg = scf_pg_create(g_hndl)) == NULL ||
10057 (iter = scf_iter_create(g_hndl)) == NULL)
10058 scfdie();
10059
10060 /* Can't use exp_prop_iter due to export_dependent(). */
10061 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
10062 scfdie();
10063
10064 type = safe_malloc(max_scf_pg_type_len + 1);
10065
10066 /* Get an extra byte so we can tell if values are too long. */
10067 fmri = safe_malloc(max_scf_fmri_len + 2);
10068
10069 (void) memset(&pgelts, 0, sizeof (pgelts));
10070
10071 while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
10072 void *entity;
10073 int isservice;
10074 scf_type_t ty;
10075
10076 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
10077 scfdie();
10078
10079 if ((ty != SCF_TYPE_ASTRING &&
10080 prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
10081 prop_get_val(exp_prop, exp_val) != 0) {
10082 export_property(exp_prop, NULL, &pgelts,
10083 SCE_ALL_VALUES);
10084 continue;
10085 }
10086
10087 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10088 scfdie();
10089
10090 if (scf_value_get_astring(exp_val, fmri,
10091 max_scf_fmri_len + 2) < 0)
10092 scfdie();
10093
10094 /* Look for a dependency group in the target fmri. */
10095 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
10096 switch (serr) {
10097 case SCF_ERROR_NONE:
10098 break;
10099
10100 case SCF_ERROR_NO_MEMORY:
10101 uu_die(gettext("Out of memory.\n"));
10102 /* NOTREACHED */
10103
10104 case SCF_ERROR_INVALID_ARGUMENT:
10105 if (g_verbose) {
10106 if (scf_property_to_fmri(exp_prop, fmri,
10107 max_scf_fmri_len + 2) < 0)
10108 scfdie();
10109
10110 warn(gettext("The value of %s is not a valid "
10111 "FMRI.\n"), fmri);
10112 }
10113
10114 export_property(exp_prop, exp_str, &pgelts,
10115 SCE_ALL_VALUES);
10116 continue;
10117
10118 case SCF_ERROR_CONSTRAINT_VIOLATED:
10119 if (g_verbose) {
10120 if (scf_property_to_fmri(exp_prop, fmri,
10121 max_scf_fmri_len + 2) < 0)
10122 scfdie();
10123
10124 warn(gettext("The value of %s does not specify "
10125 "a service or an instance.\n"), fmri);
10126 }
10127
10128 export_property(exp_prop, exp_str, &pgelts,
10129 SCE_ALL_VALUES);
10130 continue;
10131
10132 case SCF_ERROR_NOT_FOUND:
10133 if (g_verbose) {
10134 if (scf_property_to_fmri(exp_prop, fmri,
10135 max_scf_fmri_len + 2) < 0)
10136 scfdie();
10137
10138 warn(gettext("The entity specified by %s does "
10139 "not exist.\n"), fmri);
10140 }
10141
10142 export_property(exp_prop, exp_str, &pgelts,
10143 SCE_ALL_VALUES);
10144 continue;
10145
10146 default:
10147 #ifndef NDEBUG
10148 (void) fprintf(stderr, "%s:%d: %s() failed with "
10149 "unexpected error %d.\n", __FILE__, __LINE__,
10150 "fmri_to_entity", serr);
10151 #endif
10152 abort();
10153 }
10154
10155 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
10156 if (scf_error() != SCF_ERROR_NOT_FOUND)
10157 scfdie();
10158
10159 warn(gettext("Entity %s is missing dependency property "
10160 "group %s.\n"), fmri, exp_str);
10161
10162 export_property(exp_prop, NULL, &pgelts,
10163 SCE_ALL_VALUES);
10164 continue;
10165 }
10166
10167 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
10168 scfdie();
10169
10170 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
10171 if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
10172 scfdie();
10173
10174 warn(gettext("Property group %s is not of "
10175 "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
10176
10177 export_property(exp_prop, NULL, &pgelts,
10178 SCE_ALL_VALUES);
10179 continue;
10180 }
10181
10182 n = export_dependent(opg, exp_str, fmri);
10183 if (n == NULL) {
10184 export_property(exp_prop, exp_str, &pgelts,
10185 SCE_ALL_VALUES);
10186 } else {
10187 if (eelts->dependents == NULL)
10188 eelts->dependents = n;
10189 else
10190 (void) xmlAddSibling(eelts->dependents,
10191 n);
10192 }
10193 }
10194 if (ret == -1)
10195 scfdie();
10196
10197 free(fmri);
10198 free(type);
10199
10200 scf_iter_destroy(iter);
10201 scf_pg_destroy(opg);
10202
10203 if (pgelts.propvals != NULL || pgelts.properties != NULL)
10204 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
10205 eelts);
10206 }
10207
10208 static void
make_node(xmlNodePtr * nodep,const char * name)10209 make_node(xmlNodePtr *nodep, const char *name)
10210 {
10211 if (*nodep == NULL) {
10212 *nodep = xmlNewNode(NULL, (xmlChar *)name);
10213 if (*nodep == NULL)
10214 uu_die(emsg_create_xml);
10215 }
10216 }
10217
10218 static xmlNodePtr
export_tm_loctext(scf_propertygroup_t * pg,const char * parname)10219 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
10220 {
10221 int ret;
10222 xmlNodePtr parent = NULL;
10223 xmlNodePtr loctext = NULL;
10224
10225 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10226 scfdie();
10227
10228 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10229 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
10230 prop_get_val(exp_prop, exp_val) != 0)
10231 continue;
10232
10233 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
10234 scfdie();
10235
10236 make_node(&parent, parname);
10237 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
10238 (xmlChar *)exp_str);
10239 if (loctext == NULL)
10240 uu_die(emsg_create_xml);
10241
10242 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10243 scfdie();
10244
10245 safe_setprop(loctext, "xml:lang", exp_str);
10246 }
10247
10248 if (ret == -1)
10249 scfdie();
10250
10251 return (parent);
10252 }
10253
10254 static xmlNodePtr
export_tm_manpage(scf_propertygroup_t * pg)10255 export_tm_manpage(scf_propertygroup_t *pg)
10256 {
10257 xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
10258 if (manpage == NULL)
10259 uu_die(emsg_create_xml);
10260
10261 if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
10262 set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
10263 pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
10264 set_attr_from_prop(exp_prop, manpage, "section") != 0) {
10265 xmlFreeNode(manpage);
10266 return (NULL);
10267 }
10268
10269 if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
10270 (void) set_attr_from_prop_default(exp_prop,
10271 manpage, "manpath", ":default");
10272
10273 return (manpage);
10274 }
10275
10276 static xmlNodePtr
export_tm_doc_link(scf_propertygroup_t * pg)10277 export_tm_doc_link(scf_propertygroup_t *pg)
10278 {
10279 xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
10280 if (doc_link == NULL)
10281 uu_die(emsg_create_xml);
10282
10283 if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
10284 set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
10285 pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
10286 set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
10287 xmlFreeNode(doc_link);
10288 return (NULL);
10289 }
10290 return (doc_link);
10291 }
10292
10293 /*
10294 * Process template information for a service or instances.
10295 */
10296 static void
export_template(scf_propertygroup_t * pg,struct entity_elts * elts,struct template_elts * telts)10297 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
10298 struct template_elts *telts)
10299 {
10300 size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
10301 size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
10302 xmlNodePtr child = NULL;
10303
10304 if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
10305 scfdie();
10306
10307 if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
10308 telts->common_name = export_tm_loctext(pg, "common_name");
10309 if (telts->common_name == NULL)
10310 export_pg(pg, elts, SCE_ALL_VALUES);
10311 return;
10312 } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
10313 telts->description = export_tm_loctext(pg, "description");
10314 if (telts->description == NULL)
10315 export_pg(pg, elts, SCE_ALL_VALUES);
10316 return;
10317 }
10318
10319 if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
10320 child = export_tm_manpage(pg);
10321 } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
10322 child = export_tm_doc_link(pg);
10323 }
10324
10325 if (child != NULL) {
10326 make_node(&telts->documentation, "documentation");
10327 (void) xmlAddChild(telts->documentation, child);
10328 } else {
10329 export_pg(pg, elts, SCE_ALL_VALUES);
10330 }
10331 }
10332
10333 /*
10334 * Process parameter and paramval elements
10335 */
10336 static void
export_parameter(scf_property_t * prop,const char * name,struct params_elts * elts)10337 export_parameter(scf_property_t *prop, const char *name,
10338 struct params_elts *elts)
10339 {
10340 xmlNodePtr param;
10341 scf_error_t err = 0;
10342 int ret;
10343
10344 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
10345 if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL)
10346 uu_die(emsg_create_xml);
10347
10348 safe_setprop(param, name_attr, name);
10349
10350 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
10351 scfdie();
10352 safe_setprop(param, value_attr, exp_str);
10353
10354 if (elts->paramval == NULL)
10355 elts->paramval = param;
10356 else
10357 (void) xmlAddSibling(elts->paramval, param);
10358
10359 return;
10360 }
10361
10362 err = scf_error();
10363
10364 if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
10365 err != SCF_ERROR_NOT_FOUND)
10366 scfdie();
10367
10368 if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL)
10369 uu_die(emsg_create_xml);
10370
10371 safe_setprop(param, name_attr, name);
10372
10373 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
10374 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
10375 scfdie();
10376
10377 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
10378 1) {
10379 xmlNodePtr vn;
10380
10381 if ((vn = xmlNewChild(param, NULL,
10382 (xmlChar *)"value_node", NULL)) == NULL)
10383 uu_die(emsg_create_xml);
10384
10385 if (scf_value_get_as_string(exp_val, exp_str,
10386 exp_str_sz) < 0)
10387 scfdie();
10388
10389 safe_setprop(vn, value_attr, exp_str);
10390 }
10391 if (ret != 0)
10392 scfdie();
10393 }
10394
10395 if (elts->parameter == NULL)
10396 elts->parameter = param;
10397 else
10398 (void) xmlAddSibling(elts->parameter, param);
10399 }
10400
10401 /*
10402 * Process notification parameters for a service or instance
10403 */
10404 static void
export_notify_params(scf_propertygroup_t * pg,struct entity_elts * elts)10405 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts)
10406 {
10407 xmlNodePtr n, event, *type;
10408 struct params_elts *eelts;
10409 int ret, err, i;
10410 char *s;
10411
10412 n = xmlNewNode(NULL, (xmlChar *)"notification_parameters");
10413 event = xmlNewNode(NULL, (xmlChar *)"event");
10414 if (n == NULL || event == NULL)
10415 uu_die(emsg_create_xml);
10416
10417 /* event value */
10418 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
10419 scfdie();
10420 /* trim SCF_NOTIFY_PG_POSTFIX appended to name on import */
10421 if ((s = strchr(exp_str, ',')) != NULL)
10422 *s = '\0';
10423 safe_setprop(event, value_attr, exp_str);
10424
10425 (void) xmlAddChild(n, event);
10426
10427 if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL ||
10428 (eelts = calloc(URI_SCHEME_NUM,
10429 sizeof (struct params_elts))) == NULL)
10430 uu_die(gettext("Out of memory.\n"));
10431
10432 err = 0;
10433
10434 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10435 scfdie();
10436
10437 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10438 char *t, *p;
10439
10440 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10441 scfdie();
10442
10443 if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) {
10444 /*
10445 * this is not a well formed notification parameters
10446 * element, we should export as regular pg
10447 */
10448 err = 1;
10449 break;
10450 }
10451
10452 if ((i = check_uri_protocol(t)) < 0) {
10453 err = 1;
10454 break;
10455 }
10456
10457 if (type[i] == NULL) {
10458 if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) ==
10459 NULL)
10460 uu_die(emsg_create_xml);
10461
10462 safe_setprop(type[i], name_attr, t);
10463 }
10464 if (strcmp(p, active_attr) == 0) {
10465 if (set_attr_from_prop(exp_prop, type[i],
10466 active_attr) != 0) {
10467 err = 1;
10468 break;
10469 }
10470 continue;
10471 }
10472 /*
10473 * We export the parameter
10474 */
10475 export_parameter(exp_prop, p, &eelts[i]);
10476 }
10477
10478 if (ret == -1)
10479 scfdie();
10480
10481 if (err == 1) {
10482 for (i = 0; i < URI_SCHEME_NUM; ++i)
10483 xmlFree(type[i]);
10484 free(type);
10485
10486 export_pg(pg, elts, SCE_ALL_VALUES);
10487
10488 return;
10489 } else {
10490 for (i = 0; i < URI_SCHEME_NUM; ++i)
10491 if (type[i] != NULL) {
10492 (void) xmlAddChildList(type[i],
10493 eelts[i].paramval);
10494 (void) xmlAddChildList(type[i],
10495 eelts[i].parameter);
10496 (void) xmlAddSibling(event, type[i]);
10497 }
10498 }
10499 free(type);
10500
10501 if (elts->notify_params == NULL)
10502 elts->notify_params = n;
10503 else
10504 (void) xmlAddSibling(elts->notify_params, n);
10505 }
10506
10507 /*
10508 * Process the general property group for an instance.
10509 */
10510 static void
export_inst_general(scf_propertygroup_t * pg,xmlNodePtr inode,struct entity_elts * elts)10511 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
10512 struct entity_elts *elts)
10513 {
10514 uint8_t enabled;
10515 struct pg_elts pgelts;
10516 int ret;
10517
10518 /* enabled */
10519 if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
10520 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
10521 prop_get_val(exp_prop, exp_val) == 0) {
10522 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
10523 scfdie();
10524 } else {
10525 enabled = 0;
10526 }
10527
10528 safe_setprop(inode, enabled_attr, enabled ? true : false);
10529
10530 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10531 scfdie();
10532
10533 (void) memset(&pgelts, 0, sizeof (pgelts));
10534
10535 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10536 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10537 scfdie();
10538
10539 if (strcmp(exp_str, scf_property_enabled) == 0) {
10540 continue;
10541 } else if (strcmp(exp_str, SCF_PROPERTY_COMMENT) == 0) {
10542 continue;
10543 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
10544 xmlNodePtr rnode, sfnode;
10545
10546 rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10547 if (rnode == NULL)
10548 uu_die(emsg_create_xml);
10549
10550 sfnode = xmlNewChild(rnode, NULL,
10551 (xmlChar *)"service_fmri", NULL);
10552 if (sfnode == NULL)
10553 uu_die(emsg_create_xml);
10554
10555 if (set_attr_from_prop(exp_prop, sfnode,
10556 value_attr) == 0) {
10557 elts->restarter = rnode;
10558 continue;
10559 }
10560
10561 xmlFreeNode(rnode);
10562 }
10563
10564 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10565 }
10566 if (ret == -1)
10567 scfdie();
10568
10569 if (pgelts.propvals != NULL || pgelts.properties != NULL)
10570 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10571 elts);
10572 }
10573
10574 /*
10575 * Put an instance element for the given instance into selts.
10576 */
10577 static void
export_instance(scf_instance_t * inst,struct entity_elts * selts,int flags)10578 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10579 {
10580 xmlNodePtr n;
10581 boolean_t isdefault;
10582 struct entity_elts elts;
10583 struct template_elts template_elts;
10584 int ret;
10585
10586 n = xmlNewNode(NULL, (xmlChar *)"instance");
10587 if (n == NULL)
10588 uu_die(emsg_create_xml);
10589
10590 /* name */
10591 if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10592 scfdie();
10593 safe_setprop(n, name_attr, exp_str);
10594 isdefault = strcmp(exp_str, "default") == 0;
10595
10596 /* check existance of general pg (since general/enabled is required) */
10597 if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
10598 if (scf_error() != SCF_ERROR_NOT_FOUND)
10599 scfdie();
10600
10601 if (g_verbose) {
10602 if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10603 scfdie();
10604
10605 warn(gettext("Instance %s has no general property "
10606 "group; it will be marked disabled.\n"), exp_str);
10607 }
10608
10609 safe_setprop(n, enabled_attr, false);
10610 } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
10611 strcmp(exp_str, scf_group_framework) != 0) {
10612 if (g_verbose) {
10613 if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10614 scfdie();
10615
10616 warn(gettext("Property group %s is not of type "
10617 "framework; the instance will be marked "
10618 "disabled.\n"), exp_str);
10619 }
10620
10621 safe_setprop(n, enabled_attr, false);
10622 }
10623
10624 /* property groups */
10625 if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
10626 scfdie();
10627
10628 (void) memset(&elts, 0, sizeof (elts));
10629 (void) memset(&template_elts, 0, sizeof (template_elts));
10630
10631 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10632 uint32_t pgflags;
10633
10634 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10635 scfdie();
10636
10637 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10638 continue;
10639
10640 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10641 scfdie();
10642
10643 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10644 export_dependency(exp_pg, &elts);
10645 continue;
10646 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10647 export_method(exp_pg, &elts);
10648 continue;
10649 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10650 if (scf_pg_get_name(exp_pg, exp_str,
10651 max_scf_name_len + 1) < 0)
10652 scfdie();
10653
10654 if (strcmp(exp_str, scf_pg_general) == 0) {
10655 export_inst_general(exp_pg, n, &elts);
10656 continue;
10657 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10658 0) {
10659 export_method_context(exp_pg, &elts);
10660 continue;
10661 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10662 export_dependents(exp_pg, &elts);
10663 continue;
10664 }
10665 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10666 export_template(exp_pg, &elts, &template_elts);
10667 continue;
10668 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10669 export_notify_params(exp_pg, &elts);
10670 continue;
10671 }
10672
10673 /* Ordinary pg. */
10674 export_pg(exp_pg, &elts, flags);
10675 }
10676 if (ret == -1)
10677 scfdie();
10678
10679 if (template_elts.common_name != NULL) {
10680 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10681 (void) xmlAddChild(elts.template, template_elts.common_name);
10682 (void) xmlAddChild(elts.template, template_elts.description);
10683 (void) xmlAddChild(elts.template, template_elts.documentation);
10684 } else {
10685 xmlFreeNode(template_elts.description);
10686 xmlFreeNode(template_elts.documentation);
10687 }
10688
10689 if (isdefault && elts.restarter == NULL &&
10690 elts.dependencies == NULL && elts.method_context == NULL &&
10691 elts.exec_methods == NULL && elts.notify_params == NULL &&
10692 elts.property_groups == NULL && elts.template == NULL) {
10693 xmlChar *eval;
10694
10695 /* This is a default instance */
10696 eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10697
10698 xmlFreeNode(n);
10699
10700 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10701 if (n == NULL)
10702 uu_die(emsg_create_xml);
10703
10704 safe_setprop(n, enabled_attr, (char *)eval);
10705 xmlFree(eval);
10706
10707 selts->create_default_instance = n;
10708 } else {
10709 /* Assemble the children in order. */
10710 (void) xmlAddChild(n, elts.restarter);
10711 (void) xmlAddChildList(n, elts.dependencies);
10712 (void) xmlAddChildList(n, elts.dependents);
10713 (void) xmlAddChild(n, elts.method_context);
10714 (void) xmlAddChildList(n, elts.exec_methods);
10715 (void) xmlAddChildList(n, elts.notify_params);
10716 (void) xmlAddChildList(n, elts.property_groups);
10717 (void) xmlAddChild(n, elts.template);
10718
10719 if (selts->instances == NULL)
10720 selts->instances = n;
10721 else
10722 (void) xmlAddSibling(selts->instances, n);
10723 }
10724 }
10725
10726 /*
10727 * Return a service element for the given service.
10728 */
10729 static xmlNodePtr
export_service(scf_service_t * svc,int flags)10730 export_service(scf_service_t *svc, int flags)
10731 {
10732 xmlNodePtr snode;
10733 struct entity_elts elts;
10734 struct template_elts template_elts;
10735 int ret;
10736
10737 snode = xmlNewNode(NULL, (xmlChar *)"service");
10738 if (snode == NULL)
10739 uu_die(emsg_create_xml);
10740
10741 /* Get & set name attribute */
10742 if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
10743 scfdie();
10744 safe_setprop(snode, name_attr, exp_str);
10745
10746 safe_setprop(snode, type_attr, "service");
10747 safe_setprop(snode, "version", "0");
10748
10749 /* Acquire child elements. */
10750 if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
10751 scfdie();
10752
10753 (void) memset(&elts, 0, sizeof (elts));
10754 (void) memset(&template_elts, 0, sizeof (template_elts));
10755
10756 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10757 uint32_t pgflags;
10758
10759 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10760 scfdie();
10761
10762 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10763 continue;
10764
10765 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10766 scfdie();
10767
10768 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10769 export_dependency(exp_pg, &elts);
10770 continue;
10771 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10772 export_method(exp_pg, &elts);
10773 continue;
10774 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10775 if (scf_pg_get_name(exp_pg, exp_str,
10776 max_scf_name_len + 1) < 0)
10777 scfdie();
10778
10779 if (strcmp(exp_str, scf_pg_general) == 0) {
10780 export_svc_general(exp_pg, &elts);
10781 continue;
10782 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10783 0) {
10784 export_method_context(exp_pg, &elts);
10785 continue;
10786 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10787 export_dependents(exp_pg, &elts);
10788 continue;
10789 } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10790 continue;
10791 }
10792 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10793 export_template(exp_pg, &elts, &template_elts);
10794 continue;
10795 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10796 export_notify_params(exp_pg, &elts);
10797 continue;
10798 }
10799
10800 export_pg(exp_pg, &elts, flags);
10801 }
10802 if (ret == -1)
10803 scfdie();
10804
10805 if (template_elts.common_name != NULL) {
10806 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10807 (void) xmlAddChild(elts.template, template_elts.common_name);
10808 (void) xmlAddChild(elts.template, template_elts.description);
10809 (void) xmlAddChild(elts.template, template_elts.documentation);
10810 } else {
10811 xmlFreeNode(template_elts.description);
10812 xmlFreeNode(template_elts.documentation);
10813 }
10814
10815 /* Iterate instances */
10816 if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
10817 scfdie();
10818
10819 while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10820 export_instance(exp_inst, &elts, flags);
10821 if (ret == -1)
10822 scfdie();
10823
10824 /* Now add all of the accumulated elements in order. */
10825 (void) xmlAddChild(snode, elts.create_default_instance);
10826 (void) xmlAddChild(snode, elts.single_instance);
10827 (void) xmlAddChild(snode, elts.restarter);
10828 (void) xmlAddChildList(snode, elts.dependencies);
10829 (void) xmlAddChildList(snode, elts.dependents);
10830 (void) xmlAddChild(snode, elts.method_context);
10831 (void) xmlAddChildList(snode, elts.exec_methods);
10832 (void) xmlAddChildList(snode, elts.notify_params);
10833 (void) xmlAddChildList(snode, elts.property_groups);
10834 (void) xmlAddChildList(snode, elts.instances);
10835 (void) xmlAddChild(snode, elts.stability);
10836 (void) xmlAddChild(snode, elts.template);
10837
10838 return (snode);
10839 }
10840
10841 static int
export_callback(void * data,scf_walkinfo_t * wip)10842 export_callback(void *data, scf_walkinfo_t *wip)
10843 {
10844 FILE *f;
10845 xmlDocPtr doc;
10846 xmlNodePtr sb;
10847 int result;
10848 struct export_args *argsp = (struct export_args *)data;
10849
10850 if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
10851 (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10852 (exp_prop = scf_property_create(g_hndl)) == NULL ||
10853 (exp_val = scf_value_create(g_hndl)) == NULL ||
10854 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10855 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10856 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10857 (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10858 scfdie();
10859
10860 exp_str_sz = max_scf_len + 1;
10861 exp_str = safe_malloc(exp_str_sz);
10862
10863 if (argsp->filename != NULL) {
10864 errno = 0;
10865 f = fopen(argsp->filename, "wb");
10866 if (f == NULL) {
10867 if (errno == 0)
10868 uu_die(gettext("Could not open \"%s\": no free "
10869 "stdio streams.\n"), argsp->filename);
10870 else
10871 uu_die(gettext("Could not open \"%s\""),
10872 argsp->filename);
10873 }
10874 } else
10875 f = stdout;
10876
10877 doc = xmlNewDoc((xmlChar *)"1.0");
10878 if (doc == NULL)
10879 uu_die(gettext("Could not create XML document.\n"));
10880
10881 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10882 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10883 uu_die(emsg_create_xml);
10884
10885 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10886 if (sb == NULL)
10887 uu_die(emsg_create_xml);
10888 safe_setprop(sb, type_attr, "manifest");
10889 safe_setprop(sb, name_attr, "export");
10890 (void) xmlAddSibling(doc->children, sb);
10891
10892 (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
10893
10894 result = write_service_bundle(doc, f);
10895
10896 free(exp_str);
10897 scf_iter_destroy(exp_val_iter);
10898 scf_iter_destroy(exp_prop_iter);
10899 scf_iter_destroy(exp_pg_iter);
10900 scf_iter_destroy(exp_inst_iter);
10901 scf_value_destroy(exp_val);
10902 scf_property_destroy(exp_prop);
10903 scf_pg_destroy(exp_pg);
10904 scf_instance_destroy(exp_inst);
10905
10906 xmlFreeDoc(doc);
10907
10908 if (f != stdout)
10909 (void) fclose(f);
10910
10911 return (result);
10912 }
10913
10914 /*
10915 * Get the service named by fmri, build an XML tree which represents it, and
10916 * dump it into filename (or stdout if filename is NULL).
10917 */
10918 int
lscf_service_export(char * fmri,const char * filename,int flags)10919 lscf_service_export(char *fmri, const char *filename, int flags)
10920 {
10921 struct export_args args;
10922 char *fmridup;
10923 const char *scope, *svc, *inst;
10924 size_t cblen = 3 * max_scf_name_len;
10925 char *canonbuf = alloca(cblen);
10926 int ret, err;
10927
10928 lscf_prep_hndl();
10929
10930 bzero(&args, sizeof (args));
10931 args.filename = filename;
10932 args.flags = flags;
10933
10934 /*
10935 * If some poor user has passed an exact instance FMRI, of the sort
10936 * one might cut and paste from svcs(1) or an error message, warn
10937 * and chop off the instance instead of failing.
10938 */
10939 fmridup = alloca(strlen(fmri) + 1);
10940 (void) strcpy(fmridup, fmri);
10941 if (strncmp(fmridup, SCF_FMRI_SVC_PREFIX,
10942 sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 &&
10943 scf_parse_svc_fmri(fmridup, &scope, &svc, &inst, NULL, NULL) == 0 &&
10944 inst != NULL) {
10945 (void) strlcpy(canonbuf, "svc:/", cblen);
10946 if (strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
10947 (void) strlcat(canonbuf, "/", cblen);
10948 (void) strlcat(canonbuf, scope, cblen);
10949 }
10950 (void) strlcat(canonbuf, svc, cblen);
10951 fmri = canonbuf;
10952
10953 warn(gettext("Only services may be exported; ignoring "
10954 "instance portion of argument.\n"));
10955 }
10956
10957 err = 0;
10958 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10959 SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10960 &args, &err, semerr)) != 0) {
10961 if (ret != -1)
10962 semerr(gettext("Failed to walk instances: %s\n"),
10963 scf_strerror(ret));
10964 return (-1);
10965 }
10966
10967 /*
10968 * Error message has already been printed.
10969 */
10970 if (err != 0)
10971 return (-1);
10972
10973 return (0);
10974 }
10975
10976
10977 /*
10978 * Archive
10979 */
10980
10981 static xmlNodePtr
make_archive(int flags)10982 make_archive(int flags)
10983 {
10984 xmlNodePtr sb;
10985 scf_scope_t *scope;
10986 scf_service_t *svc;
10987 scf_iter_t *iter;
10988 int r;
10989
10990 if ((scope = scf_scope_create(g_hndl)) == NULL ||
10991 (svc = scf_service_create(g_hndl)) == NULL ||
10992 (iter = scf_iter_create(g_hndl)) == NULL ||
10993 (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10994 (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10995 (exp_prop = scf_property_create(g_hndl)) == NULL ||
10996 (exp_val = scf_value_create(g_hndl)) == NULL ||
10997 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10998 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10999 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
11000 (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
11001 scfdie();
11002
11003 exp_str_sz = max_scf_len + 1;
11004 exp_str = safe_malloc(exp_str_sz);
11005
11006 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
11007 if (sb == NULL)
11008 uu_die(emsg_create_xml);
11009 safe_setprop(sb, type_attr, "archive");
11010 safe_setprop(sb, name_attr, "none");
11011
11012 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
11013 scfdie();
11014 if (scf_iter_scope_services(iter, scope) != 0)
11015 scfdie();
11016
11017 for (;;) {
11018 r = scf_iter_next_service(iter, svc);
11019 if (r == 0)
11020 break;
11021 if (r != 1)
11022 scfdie();
11023
11024 if (scf_service_get_name(svc, exp_str,
11025 max_scf_name_len + 1) < 0)
11026 scfdie();
11027
11028 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
11029 continue;
11030
11031 (void) xmlAddChild(sb, export_service(svc, flags));
11032 }
11033
11034 free(exp_str);
11035
11036 scf_iter_destroy(exp_val_iter);
11037 scf_iter_destroy(exp_prop_iter);
11038 scf_iter_destroy(exp_pg_iter);
11039 scf_iter_destroy(exp_inst_iter);
11040 scf_value_destroy(exp_val);
11041 scf_property_destroy(exp_prop);
11042 scf_pg_destroy(exp_pg);
11043 scf_instance_destroy(exp_inst);
11044 scf_iter_destroy(iter);
11045 scf_service_destroy(svc);
11046 scf_scope_destroy(scope);
11047
11048 return (sb);
11049 }
11050
11051 int
lscf_archive(const char * filename,int flags)11052 lscf_archive(const char *filename, int flags)
11053 {
11054 FILE *f;
11055 xmlDocPtr doc;
11056 int result;
11057
11058 lscf_prep_hndl();
11059
11060 if (filename != NULL) {
11061 errno = 0;
11062 f = fopen(filename, "wb");
11063 if (f == NULL) {
11064 if (errno == 0)
11065 uu_die(gettext("Could not open \"%s\": no free "
11066 "stdio streams.\n"), filename);
11067 else
11068 uu_die(gettext("Could not open \"%s\""),
11069 filename);
11070 }
11071 } else
11072 f = stdout;
11073
11074 doc = xmlNewDoc((xmlChar *)"1.0");
11075 if (doc == NULL)
11076 uu_die(gettext("Could not create XML document.\n"));
11077
11078 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11079 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11080 uu_die(emsg_create_xml);
11081
11082 (void) xmlAddSibling(doc->children, make_archive(flags));
11083
11084 result = write_service_bundle(doc, f);
11085
11086 xmlFreeDoc(doc);
11087
11088 if (f != stdout)
11089 (void) fclose(f);
11090
11091 return (result);
11092 }
11093
11094
11095 /*
11096 * "Extract" a profile.
11097 */
11098 int
lscf_profile_extract(const char * filename)11099 lscf_profile_extract(const char *filename)
11100 {
11101 FILE *f;
11102 xmlDocPtr doc;
11103 xmlNodePtr sb, snode, inode;
11104 scf_scope_t *scope;
11105 scf_service_t *svc;
11106 scf_instance_t *inst;
11107 scf_propertygroup_t *pg;
11108 scf_property_t *prop;
11109 scf_value_t *val;
11110 scf_iter_t *siter, *iiter;
11111 int r, s;
11112 char *namebuf;
11113 uint8_t b;
11114 int result;
11115
11116 lscf_prep_hndl();
11117
11118 if (filename != NULL) {
11119 errno = 0;
11120 f = fopen(filename, "wb");
11121 if (f == NULL) {
11122 if (errno == 0)
11123 uu_die(gettext("Could not open \"%s\": no "
11124 "free stdio streams.\n"), filename);
11125 else
11126 uu_die(gettext("Could not open \"%s\""),
11127 filename);
11128 }
11129 } else
11130 f = stdout;
11131
11132 doc = xmlNewDoc((xmlChar *)"1.0");
11133 if (doc == NULL)
11134 uu_die(gettext("Could not create XML document.\n"));
11135
11136 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11137 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11138 uu_die(emsg_create_xml);
11139
11140 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
11141 if (sb == NULL)
11142 uu_die(emsg_create_xml);
11143 safe_setprop(sb, type_attr, "profile");
11144 safe_setprop(sb, name_attr, "extract");
11145 (void) xmlAddSibling(doc->children, sb);
11146
11147 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11148 (svc = scf_service_create(g_hndl)) == NULL ||
11149 (inst = scf_instance_create(g_hndl)) == NULL ||
11150 (pg = scf_pg_create(g_hndl)) == NULL ||
11151 (prop = scf_property_create(g_hndl)) == NULL ||
11152 (val = scf_value_create(g_hndl)) == NULL ||
11153 (siter = scf_iter_create(g_hndl)) == NULL ||
11154 (iiter = scf_iter_create(g_hndl)) == NULL)
11155 scfdie();
11156
11157 if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
11158 scfdie();
11159
11160 if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
11161 scfdie();
11162
11163 namebuf = safe_malloc(max_scf_name_len + 1);
11164
11165 while ((r = scf_iter_next_service(siter, svc)) == 1) {
11166 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
11167 scfdie();
11168
11169 snode = xmlNewNode(NULL, (xmlChar *)"service");
11170 if (snode == NULL)
11171 uu_die(emsg_create_xml);
11172
11173 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
11174 0)
11175 scfdie();
11176
11177 safe_setprop(snode, name_attr, namebuf);
11178
11179 safe_setprop(snode, type_attr, "service");
11180 safe_setprop(snode, "version", "0");
11181
11182 while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
11183 if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
11184 SCF_SUCCESS) {
11185 if (scf_error() != SCF_ERROR_NOT_FOUND)
11186 scfdie();
11187
11188 if (g_verbose) {
11189 ssize_t len;
11190 char *fmri;
11191
11192 len =
11193 scf_instance_to_fmri(inst, NULL, 0);
11194 if (len < 0)
11195 scfdie();
11196
11197 fmri = safe_malloc(len + 1);
11198
11199 if (scf_instance_to_fmri(inst, fmri,
11200 len + 1) < 0)
11201 scfdie();
11202
11203 warn("Instance %s has no \"%s\" "
11204 "property group.\n", fmri,
11205 scf_pg_general);
11206
11207 free(fmri);
11208 }
11209
11210 continue;
11211 }
11212
11213 if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
11214 prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
11215 prop_get_val(prop, val) != 0)
11216 continue;
11217
11218 inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
11219 NULL);
11220 if (inode == NULL)
11221 uu_die(emsg_create_xml);
11222
11223 if (scf_instance_get_name(inst, namebuf,
11224 max_scf_name_len + 1) < 0)
11225 scfdie();
11226
11227 safe_setprop(inode, name_attr, namebuf);
11228
11229 if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
11230 scfdie();
11231
11232 safe_setprop(inode, enabled_attr, b ? true : false);
11233 }
11234 if (s < 0)
11235 scfdie();
11236
11237 if (snode->children != NULL)
11238 (void) xmlAddChild(sb, snode);
11239 else
11240 xmlFreeNode(snode);
11241 }
11242 if (r < 0)
11243 scfdie();
11244
11245 free(namebuf);
11246
11247 result = write_service_bundle(doc, f);
11248
11249 xmlFreeDoc(doc);
11250
11251 if (f != stdout)
11252 (void) fclose(f);
11253
11254 return (result);
11255 }
11256
11257
11258 /*
11259 * Entity manipulation commands
11260 */
11261
11262 /*
11263 * Entity selection. If no entity is selected, then the current scope is in
11264 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected,
11265 * only cur_inst is NULL, and when an instance is selected, none are NULL.
11266 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
11267 * cur_inst will be non-NULL.
11268 */
11269
11270 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
11271 static int
select_inst(const char * name)11272 select_inst(const char *name)
11273 {
11274 scf_instance_t *inst;
11275 scf_error_t err;
11276
11277 assert(cur_svc != NULL);
11278
11279 inst = scf_instance_create(g_hndl);
11280 if (inst == NULL)
11281 scfdie();
11282
11283 if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
11284 cur_inst = inst;
11285 return (0);
11286 }
11287
11288 err = scf_error();
11289 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11290 scfdie();
11291
11292 scf_instance_destroy(inst);
11293 return (1);
11294 }
11295
11296 /* Returns as above. */
11297 static int
select_svc(const char * name)11298 select_svc(const char *name)
11299 {
11300 scf_service_t *svc;
11301 scf_error_t err;
11302
11303 assert(cur_scope != NULL);
11304
11305 svc = scf_service_create(g_hndl);
11306 if (svc == NULL)
11307 scfdie();
11308
11309 if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
11310 cur_svc = svc;
11311 return (0);
11312 }
11313
11314 err = scf_error();
11315 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11316 scfdie();
11317
11318 scf_service_destroy(svc);
11319 return (1);
11320 }
11321
11322 /* ARGSUSED */
11323 static int
select_callback(void * unused,scf_walkinfo_t * wip)11324 select_callback(void *unused, scf_walkinfo_t *wip)
11325 {
11326 scf_instance_t *inst;
11327 scf_service_t *svc;
11328 scf_scope_t *scope;
11329
11330 if (wip->inst != NULL) {
11331 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11332 (svc = scf_service_create(g_hndl)) == NULL ||
11333 (inst = scf_instance_create(g_hndl)) == NULL)
11334 scfdie();
11335
11336 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11337 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11338 scfdie();
11339 } else {
11340 assert(wip->svc != NULL);
11341
11342 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11343 (svc = scf_service_create(g_hndl)) == NULL)
11344 scfdie();
11345
11346 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11347 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11348 scfdie();
11349
11350 inst = NULL;
11351 }
11352
11353 /* Clear out the current selection */
11354 assert(cur_scope != NULL);
11355 scf_scope_destroy(cur_scope);
11356 scf_service_destroy(cur_svc);
11357 scf_instance_destroy(cur_inst);
11358
11359 cur_scope = scope;
11360 cur_svc = svc;
11361 cur_inst = inst;
11362
11363 return (0);
11364 }
11365
11366 static int
validate_callback(void * fmri_p,scf_walkinfo_t * wip)11367 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
11368 {
11369 char **fmri = fmri_p;
11370
11371 *fmri = strdup(wip->fmri);
11372 if (*fmri == NULL)
11373 uu_die(gettext("Out of memory.\n"));
11374
11375 return (0);
11376 }
11377
11378 /*
11379 * validate [fmri]
11380 * Perform the validation of an FMRI instance.
11381 */
11382 void
lscf_validate_fmri(const char * fmri)11383 lscf_validate_fmri(const char *fmri)
11384 {
11385 int ret = 0;
11386 size_t inst_sz;
11387 char *inst_fmri = NULL;
11388 scf_tmpl_errors_t *errs = NULL;
11389 char *snapbuf = NULL;
11390
11391 lscf_prep_hndl();
11392
11393 if (fmri == NULL) {
11394 inst_sz = max_scf_fmri_len + 1;
11395 inst_fmri = safe_malloc(inst_sz);
11396
11397 if (cur_snap != NULL) {
11398 snapbuf = safe_malloc(max_scf_name_len + 1);
11399 if (scf_snapshot_get_name(cur_snap, snapbuf,
11400 max_scf_name_len + 1) < 0)
11401 scfdie();
11402 }
11403 if (cur_inst == NULL) {
11404 semerr(gettext("No instance selected\n"));
11405 goto cleanup;
11406 } else if (scf_instance_to_fmri(cur_inst, inst_fmri,
11407 inst_sz) >= inst_sz) {
11408 /* sanity check. Should never get here */
11409 uu_die(gettext("Unexpected error! file %s, line %d\n"),
11410 __FILE__, __LINE__);
11411 }
11412 } else {
11413 scf_error_t scf_err;
11414 int err = 0;
11415
11416 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
11417 validate_callback, &inst_fmri, &err, semerr)) != 0) {
11418 uu_warn("Failed to walk instances: %s\n",
11419 scf_strerror(scf_err));
11420 goto cleanup;
11421 }
11422 if (err != 0) {
11423 /* error message displayed by scf_walk_fmri */
11424 goto cleanup;
11425 }
11426 }
11427
11428 ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
11429 SCF_TMPL_VALIDATE_FLAG_CURRENT);
11430 if (ret == -1) {
11431 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
11432 warn(gettext("Template data for %s is invalid. "
11433 "Consider reverting to a previous snapshot or "
11434 "restoring original configuration.\n"), inst_fmri);
11435 } else {
11436 uu_warn("%s: %s\n",
11437 gettext("Error validating the instance"),
11438 scf_strerror(scf_error()));
11439 }
11440 } else if (ret == 1 && errs != NULL) {
11441 scf_tmpl_error_t *err = NULL;
11442 char *msg;
11443 size_t len = 256; /* initial error buffer size */
11444 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
11445 SCF_TMPL_STRERROR_HUMAN : 0;
11446
11447 msg = safe_malloc(len);
11448
11449 while ((err = scf_tmpl_next_error(errs)) != NULL) {
11450 int ret;
11451
11452 if ((ret = scf_tmpl_strerror(err, msg, len,
11453 flag)) >= len) {
11454 len = ret + 1;
11455 msg = realloc(msg, len);
11456 if (msg == NULL)
11457 uu_die(gettext(
11458 "Out of memory.\n"));
11459 (void) scf_tmpl_strerror(err, msg, len,
11460 flag);
11461 }
11462 (void) fprintf(stderr, "%s\n", msg);
11463 }
11464 if (msg != NULL)
11465 free(msg);
11466 }
11467 if (errs != NULL)
11468 scf_tmpl_errors_destroy(errs);
11469
11470 cleanup:
11471 free(inst_fmri);
11472 free(snapbuf);
11473 }
11474
11475 static void
lscf_validate_file(const char * filename)11476 lscf_validate_file(const char *filename)
11477 {
11478 tmpl_errors_t *errs;
11479
11480 bundle_t *b = internal_bundle_new();
11481 if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
11482 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
11483 tmpl_errors_print(stderr, errs, "");
11484 semerr(gettext("Validation failed.\n"));
11485 }
11486 tmpl_errors_destroy(errs);
11487 }
11488 (void) internal_bundle_free(b);
11489 }
11490
11491 /*
11492 * validate [fmri|file]
11493 */
11494 void
lscf_validate(const char * arg)11495 lscf_validate(const char *arg)
11496 {
11497 const char *str;
11498
11499 if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
11500 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
11501 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
11502 lscf_validate_file(str);
11503 } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
11504 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
11505 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
11506 lscf_validate_fmri(str);
11507 } else if (access(arg, R_OK | F_OK) == 0) {
11508 lscf_validate_file(arg);
11509 } else {
11510 lscf_validate_fmri(arg);
11511 }
11512 }
11513
11514 void
lscf_select(const char * fmri)11515 lscf_select(const char *fmri)
11516 {
11517 int ret, err;
11518
11519 lscf_prep_hndl();
11520
11521 if (cur_snap != NULL) {
11522 struct snaplevel *elt;
11523 char *buf;
11524
11525 /* Error unless name is that of the next level. */
11526 elt = uu_list_next(cur_levels, cur_elt);
11527 if (elt == NULL) {
11528 semerr(gettext("No children.\n"));
11529 return;
11530 }
11531
11532 buf = safe_malloc(max_scf_name_len + 1);
11533
11534 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11535 max_scf_name_len + 1) < 0)
11536 scfdie();
11537
11538 if (strcmp(buf, fmri) != 0) {
11539 semerr(gettext("No such child.\n"));
11540 free(buf);
11541 return;
11542 }
11543
11544 free(buf);
11545
11546 cur_elt = elt;
11547 cur_level = elt->sl;
11548 return;
11549 }
11550
11551 /*
11552 * Special case for 'svc:', which takes the user to the scope level.
11553 */
11554 if (strcmp(fmri, "svc:") == 0) {
11555 scf_instance_destroy(cur_inst);
11556 scf_service_destroy(cur_svc);
11557 cur_inst = NULL;
11558 cur_svc = NULL;
11559 return;
11560 }
11561
11562 /*
11563 * Special case for ':properties'. This appears as part of 'list' but
11564 * can't be selected. Give a more helpful error message in this case.
11565 */
11566 if (strcmp(fmri, ":properties") == 0) {
11567 semerr(gettext(":properties is not an entity. Try 'listprop' "
11568 "to list properties.\n"));
11569 return;
11570 }
11571
11572 /*
11573 * First try the argument as relative to the current selection.
11574 */
11575 if (cur_inst != NULL) {
11576 /* EMPTY */;
11577 } else if (cur_svc != NULL) {
11578 if (select_inst(fmri) != 1)
11579 return;
11580 } else {
11581 if (select_svc(fmri) != 1)
11582 return;
11583 }
11584
11585 err = 0;
11586 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11587 select_callback, NULL, &err, semerr)) != 0) {
11588 semerr(gettext("Failed to walk instances: %s\n"),
11589 scf_strerror(ret));
11590 }
11591 }
11592
11593 void
lscf_unselect(void)11594 lscf_unselect(void)
11595 {
11596 lscf_prep_hndl();
11597
11598 if (cur_snap != NULL) {
11599 struct snaplevel *elt;
11600
11601 elt = uu_list_prev(cur_levels, cur_elt);
11602 if (elt == NULL) {
11603 semerr(gettext("No parent levels.\n"));
11604 } else {
11605 cur_elt = elt;
11606 cur_level = elt->sl;
11607 }
11608 } else if (cur_inst != NULL) {
11609 scf_instance_destroy(cur_inst);
11610 cur_inst = NULL;
11611 } else if (cur_svc != NULL) {
11612 scf_service_destroy(cur_svc);
11613 cur_svc = NULL;
11614 } else {
11615 semerr(gettext("Cannot unselect at scope level.\n"));
11616 }
11617 }
11618
11619 /*
11620 * Return the FMRI of the current selection, for the prompt.
11621 */
11622 void
lscf_get_selection_str(char * buf,size_t bufsz)11623 lscf_get_selection_str(char *buf, size_t bufsz)
11624 {
11625 char *cp;
11626 ssize_t fmrilen, szret;
11627 boolean_t deleted = B_FALSE;
11628
11629 if (g_hndl == NULL) {
11630 (void) strlcpy(buf, "svc:", bufsz);
11631 return;
11632 }
11633
11634 if (cur_level != NULL) {
11635 assert(cur_snap != NULL);
11636
11637 /* [ snapshot ] FMRI [: instance ] */
11638 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11639 + 2 + max_scf_name_len + 1 + 1);
11640
11641 buf[0] = '[';
11642
11643 szret = scf_snapshot_get_name(cur_snap, buf + 1,
11644 max_scf_name_len + 1);
11645 if (szret < 0) {
11646 if (scf_error() != SCF_ERROR_DELETED)
11647 scfdie();
11648
11649 goto snap_deleted;
11650 }
11651
11652 (void) strcat(buf, "]svc:/");
11653
11654 cp = strchr(buf, '\0');
11655
11656 szret = scf_snaplevel_get_service_name(cur_level, cp,
11657 max_scf_name_len + 1);
11658 if (szret < 0) {
11659 if (scf_error() != SCF_ERROR_DELETED)
11660 scfdie();
11661
11662 goto snap_deleted;
11663 }
11664
11665 cp = strchr(cp, '\0');
11666
11667 if (snaplevel_is_instance(cur_level)) {
11668 *cp++ = ':';
11669
11670 if (scf_snaplevel_get_instance_name(cur_level, cp,
11671 max_scf_name_len + 1) < 0) {
11672 if (scf_error() != SCF_ERROR_DELETED)
11673 scfdie();
11674
11675 goto snap_deleted;
11676 }
11677 } else {
11678 *cp++ = '[';
11679 *cp++ = ':';
11680
11681 if (scf_instance_get_name(cur_inst, cp,
11682 max_scf_name_len + 1) < 0) {
11683 if (scf_error() != SCF_ERROR_DELETED)
11684 scfdie();
11685
11686 goto snap_deleted;
11687 }
11688
11689 (void) strcat(buf, "]");
11690 }
11691
11692 return;
11693
11694 snap_deleted:
11695 deleted = B_TRUE;
11696 free(buf);
11697 unselect_cursnap();
11698 }
11699
11700 assert(cur_snap == NULL);
11701
11702 if (cur_inst != NULL) {
11703 assert(cur_svc != NULL);
11704 assert(cur_scope != NULL);
11705
11706 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11707 if (fmrilen >= 0) {
11708 assert(fmrilen < bufsz);
11709 if (deleted)
11710 warn(emsg_deleted);
11711 return;
11712 }
11713
11714 if (scf_error() != SCF_ERROR_DELETED)
11715 scfdie();
11716
11717 deleted = B_TRUE;
11718
11719 scf_instance_destroy(cur_inst);
11720 cur_inst = NULL;
11721 }
11722
11723 if (cur_svc != NULL) {
11724 assert(cur_scope != NULL);
11725
11726 szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11727 if (szret >= 0) {
11728 assert(szret < bufsz);
11729 if (deleted)
11730 warn(emsg_deleted);
11731 return;
11732 }
11733
11734 if (scf_error() != SCF_ERROR_DELETED)
11735 scfdie();
11736
11737 deleted = B_TRUE;
11738 scf_service_destroy(cur_svc);
11739 cur_svc = NULL;
11740 }
11741
11742 assert(cur_scope != NULL);
11743 fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11744
11745 if (fmrilen < 0)
11746 scfdie();
11747
11748 assert(fmrilen < bufsz);
11749 if (deleted)
11750 warn(emsg_deleted);
11751 }
11752
11753 /*
11754 * Entity listing. Entities and colon namespaces (e.g., :properties and
11755 * :statistics) are listed for the current selection.
11756 */
11757 void
lscf_list(const char * pattern)11758 lscf_list(const char *pattern)
11759 {
11760 scf_iter_t *iter;
11761 char *buf;
11762 int ret;
11763
11764 lscf_prep_hndl();
11765
11766 if (cur_level != NULL) {
11767 struct snaplevel *elt;
11768
11769 (void) fputs(COLON_NAMESPACES, stdout);
11770
11771 elt = uu_list_next(cur_levels, cur_elt);
11772 if (elt == NULL)
11773 return;
11774
11775 /*
11776 * For now, we know that the next level is an instance. But
11777 * if we ever have multiple scopes, this could be complicated.
11778 */
11779 buf = safe_malloc(max_scf_name_len + 1);
11780 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11781 max_scf_name_len + 1) >= 0) {
11782 (void) puts(buf);
11783 } else {
11784 if (scf_error() != SCF_ERROR_DELETED)
11785 scfdie();
11786 }
11787
11788 free(buf);
11789
11790 return;
11791 }
11792
11793 if (cur_inst != NULL) {
11794 (void) fputs(COLON_NAMESPACES, stdout);
11795 return;
11796 }
11797
11798 iter = scf_iter_create(g_hndl);
11799 if (iter == NULL)
11800 scfdie();
11801
11802 buf = safe_malloc(max_scf_name_len + 1);
11803
11804 if (cur_svc != NULL) {
11805 /* List the instances in this service. */
11806 scf_instance_t *inst;
11807
11808 inst = scf_instance_create(g_hndl);
11809 if (inst == NULL)
11810 scfdie();
11811
11812 if (scf_iter_service_instances(iter, cur_svc) == 0) {
11813 safe_printf(COLON_NAMESPACES);
11814
11815 for (;;) {
11816 ret = scf_iter_next_instance(iter, inst);
11817 if (ret == 0)
11818 break;
11819 if (ret != 1) {
11820 if (scf_error() != SCF_ERROR_DELETED)
11821 scfdie();
11822
11823 break;
11824 }
11825
11826 if (scf_instance_get_name(inst, buf,
11827 max_scf_name_len + 1) >= 0) {
11828 if (pattern == NULL ||
11829 fnmatch(pattern, buf, 0) == 0)
11830 (void) puts(buf);
11831 } else {
11832 if (scf_error() != SCF_ERROR_DELETED)
11833 scfdie();
11834 }
11835 }
11836 } else {
11837 if (scf_error() != SCF_ERROR_DELETED)
11838 scfdie();
11839 }
11840
11841 scf_instance_destroy(inst);
11842 } else {
11843 /* List the services in this scope. */
11844 scf_service_t *svc;
11845
11846 assert(cur_scope != NULL);
11847
11848 svc = scf_service_create(g_hndl);
11849 if (svc == NULL)
11850 scfdie();
11851
11852 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11853 scfdie();
11854
11855 for (;;) {
11856 ret = scf_iter_next_service(iter, svc);
11857 if (ret == 0)
11858 break;
11859 if (ret != 1)
11860 scfdie();
11861
11862 if (scf_service_get_name(svc, buf,
11863 max_scf_name_len + 1) >= 0) {
11864 if (pattern == NULL ||
11865 fnmatch(pattern, buf, 0) == 0)
11866 safe_printf("%s\n", buf);
11867 } else {
11868 if (scf_error() != SCF_ERROR_DELETED)
11869 scfdie();
11870 }
11871 }
11872
11873 scf_service_destroy(svc);
11874 }
11875
11876 free(buf);
11877 scf_iter_destroy(iter);
11878 }
11879
11880 /*
11881 * Entity addition. Creates an empty entity in the current selection.
11882 */
11883 void
lscf_add(const char * name)11884 lscf_add(const char *name)
11885 {
11886 lscf_prep_hndl();
11887
11888 if (cur_snap != NULL) {
11889 semerr(emsg_cant_modify_snapshots);
11890 } else if (cur_inst != NULL) {
11891 semerr(gettext("Cannot add entities to an instance.\n"));
11892 } else if (cur_svc != NULL) {
11893
11894 if (scf_service_add_instance(cur_svc, name, NULL) !=
11895 SCF_SUCCESS) {
11896 switch (scf_error()) {
11897 case SCF_ERROR_INVALID_ARGUMENT:
11898 semerr(gettext("Invalid name.\n"));
11899 break;
11900
11901 case SCF_ERROR_EXISTS:
11902 semerr(gettext("Instance already exists.\n"));
11903 break;
11904
11905 case SCF_ERROR_PERMISSION_DENIED:
11906 semerr(emsg_permission_denied);
11907 break;
11908
11909 default:
11910 scfdie();
11911 }
11912 }
11913 } else {
11914 assert(cur_scope != NULL);
11915
11916 if (scf_scope_add_service(cur_scope, name, NULL) !=
11917 SCF_SUCCESS) {
11918 switch (scf_error()) {
11919 case SCF_ERROR_INVALID_ARGUMENT:
11920 semerr(gettext("Invalid name.\n"));
11921 break;
11922
11923 case SCF_ERROR_EXISTS:
11924 semerr(gettext("Service already exists.\n"));
11925 break;
11926
11927 case SCF_ERROR_PERMISSION_DENIED:
11928 semerr(emsg_permission_denied);
11929 break;
11930
11931 case SCF_ERROR_BACKEND_READONLY:
11932 semerr(emsg_read_only);
11933 break;
11934
11935 default:
11936 scfdie();
11937 }
11938 }
11939 }
11940 }
11941
11942 /* return 1 if the entity has no persistent pgs, else return 0 */
11943 static int
entity_has_no_pgs(void * ent,int isservice)11944 entity_has_no_pgs(void *ent, int isservice)
11945 {
11946 scf_iter_t *iter = NULL;
11947 scf_propertygroup_t *pg = NULL;
11948 uint32_t flags;
11949 int err;
11950 int ret = 1;
11951
11952 if ((iter = scf_iter_create(g_hndl)) == NULL ||
11953 (pg = scf_pg_create(g_hndl)) == NULL)
11954 scfdie();
11955
11956 if (isservice) {
11957 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11958 scfdie();
11959 } else {
11960 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11961 scfdie();
11962 }
11963
11964 while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11965 if (scf_pg_get_flags(pg, &flags) != 0)
11966 scfdie();
11967
11968 /* skip nonpersistent pgs */
11969 if (flags & SCF_PG_FLAG_NONPERSISTENT)
11970 continue;
11971
11972 ret = 0;
11973 break;
11974 }
11975
11976 if (err == -1)
11977 scfdie();
11978
11979 scf_pg_destroy(pg);
11980 scf_iter_destroy(iter);
11981
11982 return (ret);
11983 }
11984
11985 /* return 1 if the service has no instances, else return 0 */
11986 static int
svc_has_no_insts(scf_service_t * svc)11987 svc_has_no_insts(scf_service_t *svc)
11988 {
11989 scf_instance_t *inst;
11990 scf_iter_t *iter;
11991 int r;
11992 int ret = 1;
11993
11994 if ((inst = scf_instance_create(g_hndl)) == NULL ||
11995 (iter = scf_iter_create(g_hndl)) == NULL)
11996 scfdie();
11997
11998 if (scf_iter_service_instances(iter, svc) != 0)
11999 scfdie();
12000
12001 r = scf_iter_next_instance(iter, inst);
12002 if (r == 1) {
12003 ret = 0;
12004 } else if (r == 0) {
12005 ret = 1;
12006 } else if (r == -1) {
12007 scfdie();
12008 } else {
12009 bad_error("scf_iter_next_instance", r);
12010 }
12011
12012 scf_iter_destroy(iter);
12013 scf_instance_destroy(inst);
12014
12015 return (ret);
12016 }
12017
12018 /*
12019 * Entity deletion.
12020 */
12021
12022 /*
12023 * Delete the property group <fmri>/:properties/<name>. Returns
12024 * SCF_ERROR_NONE on success (or if the entity is not found),
12025 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
12026 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
12027 * denied.
12028 */
12029 static scf_error_t
delete_dependency_pg(const char * fmri,const char * name)12030 delete_dependency_pg(const char *fmri, const char *name)
12031 {
12032 void *entity = NULL;
12033 int isservice;
12034 scf_propertygroup_t *pg = NULL;
12035 scf_error_t result;
12036 char *pgty;
12037 scf_service_t *svc = NULL;
12038 scf_instance_t *inst = NULL;
12039 scf_iter_t *iter = NULL;
12040 char *name_buf = NULL;
12041
12042 result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
12043 switch (result) {
12044 case SCF_ERROR_NONE:
12045 break;
12046
12047 case SCF_ERROR_NO_MEMORY:
12048 uu_die(gettext("Out of memory.\n"));
12049 /* NOTREACHED */
12050
12051 case SCF_ERROR_INVALID_ARGUMENT:
12052 case SCF_ERROR_CONSTRAINT_VIOLATED:
12053 return (SCF_ERROR_INVALID_ARGUMENT);
12054
12055 case SCF_ERROR_NOT_FOUND:
12056 result = SCF_ERROR_NONE;
12057 goto out;
12058
12059 default:
12060 bad_error("fmri_to_entity", result);
12061 }
12062
12063 pg = scf_pg_create(g_hndl);
12064 if (pg == NULL)
12065 scfdie();
12066
12067 if (entity_get_pg(entity, isservice, name, pg) != 0) {
12068 if (scf_error() != SCF_ERROR_NOT_FOUND)
12069 scfdie();
12070
12071 result = SCF_ERROR_NONE;
12072 goto out;
12073 }
12074
12075 pgty = safe_malloc(max_scf_pg_type_len + 1);
12076
12077 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12078 scfdie();
12079
12080 if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
12081 result = SCF_ERROR_TYPE_MISMATCH;
12082 free(pgty);
12083 goto out;
12084 }
12085
12086 free(pgty);
12087
12088 if (scf_pg_delete(pg) != 0) {
12089 result = scf_error();
12090 if (result != SCF_ERROR_PERMISSION_DENIED)
12091 scfdie();
12092 goto out;
12093 }
12094
12095 /*
12096 * We have to handle the case where we've just deleted the last
12097 * property group of a "dummy" entity (instance or service).
12098 * A "dummy" entity is an entity only present to hold an
12099 * external dependency.
12100 * So, in the case we deleted the last property group then we
12101 * can also delete the entity. If the entity is an instance then
12102 * we must verify if this was the last instance for the service
12103 * and if it is, we can also delete the service if it doesn't
12104 * have any property group either.
12105 */
12106
12107 result = SCF_ERROR_NONE;
12108
12109 if (isservice) {
12110 svc = (scf_service_t *)entity;
12111
12112 if ((inst = scf_instance_create(g_hndl)) == NULL ||
12113 (iter = scf_iter_create(g_hndl)) == NULL)
12114 scfdie();
12115
12116 name_buf = safe_malloc(max_scf_name_len + 1);
12117 } else {
12118 inst = (scf_instance_t *)entity;
12119 }
12120
12121 /*
12122 * If the entity is an instance and we've just deleted its last
12123 * property group then we should delete it.
12124 */
12125 if (!isservice && entity_has_no_pgs(entity, isservice)) {
12126 /* find the service before deleting the inst. - needed later */
12127 if ((svc = scf_service_create(g_hndl)) == NULL)
12128 scfdie();
12129
12130 if (scf_instance_get_parent(inst, svc) != 0)
12131 scfdie();
12132
12133 /* delete the instance */
12134 if (scf_instance_delete(inst) != 0) {
12135 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12136 scfdie();
12137
12138 result = SCF_ERROR_PERMISSION_DENIED;
12139 goto out;
12140 }
12141 /* no need to refresh the instance */
12142 inst = NULL;
12143 }
12144
12145 /*
12146 * If the service has no more instances and pgs or we just deleted the
12147 * last instance and the service doesn't have anymore propery groups
12148 * then the service should be deleted.
12149 */
12150 if (svc != NULL &&
12151 svc_has_no_insts(svc) &&
12152 entity_has_no_pgs((void *)svc, 1)) {
12153 if (scf_service_delete(svc) == 0) {
12154 if (isservice) {
12155 /* no need to refresh the service */
12156 svc = NULL;
12157 }
12158
12159 goto out;
12160 }
12161
12162 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12163 scfdie();
12164
12165 result = SCF_ERROR_PERMISSION_DENIED;
12166 }
12167
12168 /* if the entity has not been deleted, refresh it */
12169 if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
12170 (void) refresh_entity(isservice, entity, fmri, inst, iter,
12171 name_buf);
12172 }
12173
12174 out:
12175 if (isservice && (inst != NULL && iter != NULL)) {
12176 free(name_buf);
12177 scf_iter_destroy(iter);
12178 scf_instance_destroy(inst);
12179 }
12180
12181 if (!isservice && svc != NULL) {
12182 scf_service_destroy(svc);
12183 }
12184
12185 scf_pg_destroy(pg);
12186 if (entity != NULL)
12187 entity_destroy(entity, isservice);
12188
12189 return (result);
12190 }
12191
12192 static int
delete_dependents(scf_propertygroup_t * pg)12193 delete_dependents(scf_propertygroup_t *pg)
12194 {
12195 char *pgty, *name, *fmri;
12196 scf_property_t *prop;
12197 scf_value_t *val;
12198 scf_iter_t *iter;
12199 int r;
12200 scf_error_t err;
12201
12202 /* Verify that the pg has the correct type. */
12203 pgty = safe_malloc(max_scf_pg_type_len + 1);
12204 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12205 scfdie();
12206
12207 if (strcmp(pgty, scf_group_framework) != 0) {
12208 if (g_verbose) {
12209 fmri = safe_malloc(max_scf_fmri_len + 1);
12210 if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
12211 scfdie();
12212
12213 warn(gettext("Property group %s is not of expected "
12214 "type %s.\n"), fmri, scf_group_framework);
12215
12216 free(fmri);
12217 }
12218
12219 free(pgty);
12220 return (-1);
12221 }
12222
12223 free(pgty);
12224
12225 /* map delete_dependency_pg onto the properties. */
12226 if ((prop = scf_property_create(g_hndl)) == NULL ||
12227 (val = scf_value_create(g_hndl)) == NULL ||
12228 (iter = scf_iter_create(g_hndl)) == NULL)
12229 scfdie();
12230
12231 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
12232 scfdie();
12233
12234 name = safe_malloc(max_scf_name_len + 1);
12235 fmri = safe_malloc(max_scf_fmri_len + 2);
12236
12237 while ((r = scf_iter_next_property(iter, prop)) == 1) {
12238 scf_type_t ty;
12239
12240 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
12241 scfdie();
12242
12243 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
12244 scfdie();
12245
12246 if ((ty != SCF_TYPE_ASTRING &&
12247 prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
12248 prop_get_val(prop, val) != 0)
12249 continue;
12250
12251 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
12252 scfdie();
12253
12254 err = delete_dependency_pg(fmri, name);
12255 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
12256 if (scf_property_to_fmri(prop, fmri,
12257 max_scf_fmri_len + 2) < 0)
12258 scfdie();
12259
12260 warn(gettext("Value of %s is not a valid FMRI.\n"),
12261 fmri);
12262 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
12263 warn(gettext("Property group \"%s\" of entity \"%s\" "
12264 "does not have dependency type.\n"), name, fmri);
12265 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
12266 warn(gettext("Could not delete property group \"%s\" "
12267 "of entity \"%s\" (permission denied).\n"), name,
12268 fmri);
12269 }
12270 }
12271 if (r == -1)
12272 scfdie();
12273
12274 scf_value_destroy(val);
12275 scf_property_destroy(prop);
12276
12277 return (0);
12278 }
12279
12280 /*
12281 * Returns 1 if the instance may be running, and 0 otherwise.
12282 */
12283 static int
inst_is_running(scf_instance_t * inst)12284 inst_is_running(scf_instance_t *inst)
12285 {
12286 scf_propertygroup_t *pg;
12287 scf_property_t *prop;
12288 scf_value_t *val;
12289 char buf[MAX_SCF_STATE_STRING_SZ];
12290 int ret = 0;
12291 ssize_t szret;
12292
12293 if ((pg = scf_pg_create(g_hndl)) == NULL ||
12294 (prop = scf_property_create(g_hndl)) == NULL ||
12295 (val = scf_value_create(g_hndl)) == NULL)
12296 scfdie();
12297
12298 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
12299 if (scf_error() != SCF_ERROR_NOT_FOUND)
12300 scfdie();
12301 goto out;
12302 }
12303
12304 if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
12305 prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
12306 prop_get_val(prop, val) != 0)
12307 goto out;
12308
12309 szret = scf_value_get_astring(val, buf, sizeof (buf));
12310 assert(szret >= 0);
12311
12312 ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
12313 strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
12314
12315 out:
12316 scf_value_destroy(val);
12317 scf_property_destroy(prop);
12318 scf_pg_destroy(pg);
12319 return (ret);
12320 }
12321
12322 static uint8_t
pg_is_external_dependency(scf_propertygroup_t * pg)12323 pg_is_external_dependency(scf_propertygroup_t *pg)
12324 {
12325 char *type;
12326 scf_value_t *val;
12327 scf_property_t *prop;
12328 uint8_t b = B_FALSE;
12329
12330 type = safe_malloc(max_scf_pg_type_len + 1);
12331
12332 if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
12333 scfdie();
12334
12335 if ((prop = scf_property_create(g_hndl)) == NULL ||
12336 (val = scf_value_create(g_hndl)) == NULL)
12337 scfdie();
12338
12339 if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
12340 if (pg_get_prop(pg, scf_property_external, prop) == 0) {
12341 if (scf_property_get_value(prop, val) != 0)
12342 scfdie();
12343 if (scf_value_get_boolean(val, &b) != 0)
12344 scfdie();
12345 }
12346 }
12347
12348 free(type);
12349 (void) scf_value_destroy(val);
12350 (void) scf_property_destroy(prop);
12351
12352 return (b);
12353 }
12354
12355 #define DELETE_FAILURE -1
12356 #define DELETE_SUCCESS_NOEXTDEPS 0
12357 #define DELETE_SUCCESS_EXTDEPS 1
12358
12359 /*
12360 * lscf_instance_delete() deletes an instance. Before calling
12361 * scf_instance_delete(), though, we make sure the instance isn't
12362 * running and delete dependencies in other entities which the instance
12363 * declared as "dependents". If there are dependencies which were
12364 * created for other entities, then instead of deleting the instance we
12365 * make it "empty" by deleting all other property groups and all
12366 * snapshots.
12367 *
12368 * lscf_instance_delete() verifies that there is no external dependency pgs
12369 * before suppressing the instance. If there is, then we must not remove them
12370 * now in case the instance is re-created otherwise the dependencies would be
12371 * lost. The external dependency pgs will be removed if the dependencies are
12372 * removed.
12373 *
12374 * Returns:
12375 * DELETE_FAILURE on failure
12376 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12377 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12378 */
12379 static int
lscf_instance_delete(scf_instance_t * inst,int force)12380 lscf_instance_delete(scf_instance_t *inst, int force)
12381 {
12382 scf_propertygroup_t *pg;
12383 scf_snapshot_t *snap;
12384 scf_iter_t *iter;
12385 int err;
12386 int external = 0;
12387
12388 /* If we're not forcing and the instance is running, refuse. */
12389 if (!force && inst_is_running(inst)) {
12390 char *fmri;
12391
12392 fmri = safe_malloc(max_scf_fmri_len + 1);
12393
12394 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
12395 scfdie();
12396
12397 semerr(gettext("Instance %s may be running. "
12398 "Use delete -f if it is not.\n"), fmri);
12399
12400 free(fmri);
12401 return (DELETE_FAILURE);
12402 }
12403
12404 pg = scf_pg_create(g_hndl);
12405 if (pg == NULL)
12406 scfdie();
12407
12408 if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
12409 (void) delete_dependents(pg);
12410 else if (scf_error() != SCF_ERROR_NOT_FOUND)
12411 scfdie();
12412
12413 scf_pg_destroy(pg);
12414
12415 /*
12416 * If the instance has some external dependencies then we must
12417 * keep them in case the instance is reimported otherwise the
12418 * dependencies would be lost on reimport.
12419 */
12420 if ((iter = scf_iter_create(g_hndl)) == NULL ||
12421 (pg = scf_pg_create(g_hndl)) == NULL)
12422 scfdie();
12423
12424 if (scf_iter_instance_pgs(iter, inst) < 0)
12425 scfdie();
12426
12427 while ((err = scf_iter_next_pg(iter, pg)) == 1) {
12428 if (pg_is_external_dependency(pg)) {
12429 external = 1;
12430 continue;
12431 }
12432
12433 if (scf_pg_delete(pg) != 0) {
12434 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12435 scfdie();
12436 else {
12437 semerr(emsg_permission_denied);
12438
12439 (void) scf_iter_destroy(iter);
12440 (void) scf_pg_destroy(pg);
12441 return (DELETE_FAILURE);
12442 }
12443 }
12444 }
12445
12446 if (err == -1)
12447 scfdie();
12448
12449 (void) scf_iter_destroy(iter);
12450 (void) scf_pg_destroy(pg);
12451
12452 if (external) {
12453 /*
12454 * All the pgs have been deleted for the instance except
12455 * the ones holding the external dependencies.
12456 * For the job to be complete, we must also delete the
12457 * snapshots associated with the instance.
12458 */
12459 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
12460 NULL)
12461 scfdie();
12462 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
12463 scfdie();
12464
12465 if (scf_iter_instance_snapshots(iter, inst) == -1)
12466 scfdie();
12467
12468 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
12469 if (_scf_snapshot_delete(snap) != 0) {
12470 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12471 scfdie();
12472
12473 semerr(emsg_permission_denied);
12474
12475 (void) scf_iter_destroy(iter);
12476 (void) scf_snapshot_destroy(snap);
12477 return (DELETE_FAILURE);
12478 }
12479 }
12480
12481 if (err == -1)
12482 scfdie();
12483
12484 (void) scf_iter_destroy(iter);
12485 (void) scf_snapshot_destroy(snap);
12486 return (DELETE_SUCCESS_EXTDEPS);
12487 }
12488
12489 if (scf_instance_delete(inst) != 0) {
12490 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12491 scfdie();
12492
12493 semerr(emsg_permission_denied);
12494
12495 return (DELETE_FAILURE);
12496 }
12497
12498 return (DELETE_SUCCESS_NOEXTDEPS);
12499 }
12500
12501 /*
12502 * lscf_service_delete() deletes a service. Before calling
12503 * scf_service_delete(), though, we call lscf_instance_delete() for
12504 * each of the instances and delete dependencies in other entities
12505 * which were created as "dependents" of this service. If there are
12506 * dependencies which were created for other entities, then we delete
12507 * all other property groups in the service and leave it as "empty".
12508 *
12509 * lscf_service_delete() verifies that there is no external dependency
12510 * pgs at the instance & service level before suppressing the service.
12511 * If there is, then we must not remove them now in case the service
12512 * is re-imported otherwise the dependencies would be lost. The external
12513 * dependency pgs will be removed if the dependencies are removed.
12514 *
12515 * Returns:
12516 * DELETE_FAILURE on failure
12517 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12518 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12519 */
12520 static int
lscf_service_delete(scf_service_t * svc,int force)12521 lscf_service_delete(scf_service_t *svc, int force)
12522 {
12523 int r;
12524 scf_instance_t *inst;
12525 scf_propertygroup_t *pg;
12526 scf_iter_t *iter;
12527 int ret;
12528 int external = 0;
12529
12530 if ((inst = scf_instance_create(g_hndl)) == NULL ||
12531 (pg = scf_pg_create(g_hndl)) == NULL ||
12532 (iter = scf_iter_create(g_hndl)) == NULL)
12533 scfdie();
12534
12535 if (scf_iter_service_instances(iter, svc) != 0)
12536 scfdie();
12537
12538 for (r = scf_iter_next_instance(iter, inst);
12539 r == 1;
12540 r = scf_iter_next_instance(iter, inst)) {
12541
12542 ret = lscf_instance_delete(inst, force);
12543 if (ret == DELETE_FAILURE) {
12544 scf_iter_destroy(iter);
12545 scf_pg_destroy(pg);
12546 scf_instance_destroy(inst);
12547 return (DELETE_FAILURE);
12548 }
12549
12550 /*
12551 * Record the fact that there is some external dependencies
12552 * at the instance level.
12553 */
12554 if (ret == DELETE_SUCCESS_EXTDEPS)
12555 external |= 1;
12556 }
12557
12558 if (r != 0)
12559 scfdie();
12560
12561 /* Delete dependency property groups in dependent services. */
12562 if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12563 (void) delete_dependents(pg);
12564 else if (scf_error() != SCF_ERROR_NOT_FOUND)
12565 scfdie();
12566
12567 scf_iter_destroy(iter);
12568 scf_pg_destroy(pg);
12569 scf_instance_destroy(inst);
12570
12571 /*
12572 * If the service has some external dependencies then we don't
12573 * want to remove them in case the service is re-imported.
12574 */
12575 if ((pg = scf_pg_create(g_hndl)) == NULL ||
12576 (iter = scf_iter_create(g_hndl)) == NULL)
12577 scfdie();
12578
12579 if (scf_iter_service_pgs(iter, svc) < 0)
12580 scfdie();
12581
12582 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12583 if (pg_is_external_dependency(pg)) {
12584 external |= 2;
12585 continue;
12586 }
12587
12588 if (scf_pg_delete(pg) != 0) {
12589 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12590 scfdie();
12591 else {
12592 semerr(emsg_permission_denied);
12593
12594 (void) scf_iter_destroy(iter);
12595 (void) scf_pg_destroy(pg);
12596 return (DELETE_FAILURE);
12597 }
12598 }
12599 }
12600
12601 if (r == -1)
12602 scfdie();
12603
12604 (void) scf_iter_destroy(iter);
12605 (void) scf_pg_destroy(pg);
12606
12607 if (external != 0)
12608 return (DELETE_SUCCESS_EXTDEPS);
12609
12610 if (scf_service_delete(svc) == 0)
12611 return (DELETE_SUCCESS_NOEXTDEPS);
12612
12613 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12614 scfdie();
12615
12616 semerr(emsg_permission_denied);
12617 return (DELETE_FAILURE);
12618 }
12619
12620 static int
delete_callback(void * data,scf_walkinfo_t * wip)12621 delete_callback(void *data, scf_walkinfo_t *wip)
12622 {
12623 int force = (int)data;
12624
12625 if (wip->inst != NULL)
12626 (void) lscf_instance_delete(wip->inst, force);
12627 else
12628 (void) lscf_service_delete(wip->svc, force);
12629
12630 return (0);
12631 }
12632
12633 void
lscf_delete(const char * fmri,int force)12634 lscf_delete(const char *fmri, int force)
12635 {
12636 scf_service_t *svc;
12637 scf_instance_t *inst;
12638 int ret;
12639
12640 lscf_prep_hndl();
12641
12642 if (cur_snap != NULL) {
12643 if (!snaplevel_is_instance(cur_level)) {
12644 char *buf;
12645
12646 buf = safe_malloc(max_scf_name_len + 1);
12647 if (scf_instance_get_name(cur_inst, buf,
12648 max_scf_name_len + 1) >= 0) {
12649 if (strcmp(buf, fmri) == 0) {
12650 semerr(emsg_cant_modify_snapshots);
12651 free(buf);
12652 return;
12653 }
12654 } else if (scf_error() != SCF_ERROR_DELETED) {
12655 scfdie();
12656 }
12657 free(buf);
12658 }
12659 } else if (cur_inst != NULL) {
12660 /* EMPTY */;
12661 } else if (cur_svc != NULL) {
12662 inst = scf_instance_create(g_hndl);
12663 if (inst == NULL)
12664 scfdie();
12665
12666 if (scf_service_get_instance(cur_svc, fmri, inst) ==
12667 SCF_SUCCESS) {
12668 (void) lscf_instance_delete(inst, force);
12669 scf_instance_destroy(inst);
12670 return;
12671 }
12672
12673 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12674 scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12675 scfdie();
12676
12677 scf_instance_destroy(inst);
12678 } else {
12679 assert(cur_scope != NULL);
12680
12681 svc = scf_service_create(g_hndl);
12682 if (svc == NULL)
12683 scfdie();
12684
12685 if (scf_scope_get_service(cur_scope, fmri, svc) ==
12686 SCF_SUCCESS) {
12687 (void) lscf_service_delete(svc, force);
12688 scf_service_destroy(svc);
12689 return;
12690 }
12691
12692 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12693 scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12694 scfdie();
12695
12696 scf_service_destroy(svc);
12697 }
12698
12699 /*
12700 * Match FMRI to entity.
12701 */
12702 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12703 delete_callback, (void *)force, NULL, semerr)) != 0) {
12704 semerr(gettext("Failed to walk instances: %s\n"),
12705 scf_strerror(ret));
12706 }
12707 }
12708
12709
12710
12711 /*
12712 * :properties commands. These all end with "pg" or "prop" and generally
12713 * operate on the currently selected entity.
12714 */
12715
12716 /*
12717 * Property listing. List the property groups, properties, their types and
12718 * their values for the currently selected entity.
12719 */
12720 static void
list_pg_info(const scf_propertygroup_t * pg,const char * name,size_t namewidth)12721 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12722 {
12723 char *buf;
12724 uint32_t flags;
12725
12726 buf = safe_malloc(max_scf_pg_type_len + 1);
12727
12728 if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12729 scfdie();
12730
12731 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12732 scfdie();
12733
12734 safe_printf("%-*s %s", namewidth, name, buf);
12735
12736 if (flags & SCF_PG_FLAG_NONPERSISTENT)
12737 safe_printf("\tNONPERSISTENT");
12738
12739 safe_printf("\n");
12740
12741 free(buf);
12742 }
12743
12744 static boolean_t
prop_has_multiple_values(const scf_property_t * prop,scf_value_t * val)12745 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12746 {
12747 if (scf_property_get_value(prop, val) == 0) {
12748 return (B_FALSE);
12749 } else {
12750 switch (scf_error()) {
12751 case SCF_ERROR_NOT_FOUND:
12752 return (B_FALSE);
12753 case SCF_ERROR_PERMISSION_DENIED:
12754 case SCF_ERROR_CONSTRAINT_VIOLATED:
12755 return (B_TRUE);
12756 default:
12757 scfdie();
12758 /*NOTREACHED*/
12759 }
12760 }
12761 }
12762
12763 static void
list_prop_info(const scf_property_t * prop,const char * name,size_t len)12764 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12765 {
12766 scf_iter_t *iter;
12767 scf_value_t *val;
12768 const char *type;
12769 int multiple_strings = 0;
12770 int ret;
12771
12772 if ((iter = scf_iter_create(g_hndl)) == NULL ||
12773 (val = scf_value_create(g_hndl)) == NULL)
12774 scfdie();
12775
12776 type = prop_to_typestr(prop);
12777 assert(type != NULL);
12778
12779 safe_printf("%-*s %-7s ", len, name, type);
12780
12781 if (prop_has_multiple_values(prop, val) &&
12782 (scf_value_type(val) == SCF_TYPE_ASTRING ||
12783 scf_value_type(val) == SCF_TYPE_USTRING))
12784 multiple_strings = 1;
12785
12786 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12787 scfdie();
12788
12789 while ((ret = scf_iter_next_value(iter, val)) == 1) {
12790 char *buf;
12791 ssize_t vlen, szret;
12792
12793 vlen = scf_value_get_as_string(val, NULL, 0);
12794 if (vlen < 0)
12795 scfdie();
12796
12797 buf = safe_malloc(vlen + 1);
12798
12799 szret = scf_value_get_as_string(val, buf, vlen + 1);
12800 if (szret < 0)
12801 scfdie();
12802 assert(szret <= vlen);
12803
12804 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12805 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12806 safe_printf(" \"");
12807 (void) quote_and_print(buf, stdout, 0);
12808 (void) putchar('"');
12809 if (ferror(stdout)) {
12810 (void) putchar('\n');
12811 uu_die(gettext("Error writing to stdout.\n"));
12812 }
12813 } else {
12814 safe_printf(" %s", buf);
12815 }
12816
12817 free(buf);
12818 }
12819 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12820 scfdie();
12821
12822 if (putchar('\n') != '\n')
12823 uu_die(gettext("Could not output newline"));
12824 }
12825
12826 /*
12827 * Outputs template property group info for the describe subcommand.
12828 * If 'templates' == 2, verbose output is printed in the format expected
12829 * for describe -v, which includes all templates fields. If pg is
12830 * not NULL, we're describing the template data, not an existing property
12831 * group, and formatting should be appropriate for describe -t.
12832 */
12833 static void
list_pg_tmpl(scf_pg_tmpl_t * pgt,scf_propertygroup_t * pg,int templates)12834 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12835 {
12836 char *buf;
12837 uint8_t required;
12838 scf_property_t *stability_prop;
12839 scf_value_t *stability_val;
12840
12841 if (templates == 0)
12842 return;
12843
12844 if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12845 (stability_val = scf_value_create(g_hndl)) == NULL)
12846 scfdie();
12847
12848 if (templates == 2 && pg != NULL) {
12849 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12850 stability_prop) == 0) {
12851 if (prop_check_type(stability_prop,
12852 SCF_TYPE_ASTRING) == 0 &&
12853 prop_get_val(stability_prop, stability_val) == 0) {
12854 char *stability;
12855
12856 stability = safe_malloc(max_scf_value_len + 1);
12857
12858 if (scf_value_get_astring(stability_val,
12859 stability, max_scf_value_len + 1) == -1 &&
12860 scf_error() != SCF_ERROR_NOT_FOUND)
12861 scfdie();
12862
12863 safe_printf("%s%s: %s\n", TMPL_INDENT,
12864 gettext("stability"), stability);
12865
12866 free(stability);
12867 }
12868 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
12869 scfdie();
12870 }
12871
12872 scf_property_destroy(stability_prop);
12873 scf_value_destroy(stability_val);
12874
12875 if (pgt == NULL)
12876 return;
12877
12878 if (pg == NULL || templates == 2) {
12879 /* print type info only if scf_tmpl_pg_name succeeds */
12880 if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12881 if (pg != NULL)
12882 safe_printf("%s", TMPL_INDENT);
12883 safe_printf("%s: ", gettext("name"));
12884 safe_printf("%s\n", buf);
12885 free(buf);
12886 }
12887
12888 /* print type info only if scf_tmpl_pg_type succeeds */
12889 if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12890 if (pg != NULL)
12891 safe_printf("%s", TMPL_INDENT);
12892 safe_printf("%s: ", gettext("type"));
12893 safe_printf("%s\n", buf);
12894 free(buf);
12895 }
12896 }
12897
12898 if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12899 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12900 required ? "true" : "false");
12901
12902 if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12903 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12904 buf);
12905 free(buf);
12906 }
12907
12908 if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12909 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12910 buf);
12911 free(buf);
12912 }
12913
12914 if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12915 if (templates == 2)
12916 safe_printf("%s%s: %s\n", TMPL_INDENT,
12917 gettext("description"), buf);
12918 else
12919 safe_printf("%s%s\n", TMPL_INDENT, buf);
12920 free(buf);
12921 }
12922
12923 }
12924
12925 /*
12926 * With as_value set to true, indent as appropriate for the value level.
12927 * If false, indent to appropriate level for inclusion in constraint
12928 * or choice printout.
12929 */
12930 static void
print_template_value_details(scf_prop_tmpl_t * prt,const char * val_buf,int as_value)12931 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12932 int as_value)
12933 {
12934 char *buf;
12935
12936 if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12937 if (as_value == 0)
12938 safe_printf("%s", TMPL_CHOICE_INDENT);
12939 else
12940 safe_printf("%s", TMPL_INDENT);
12941 safe_printf("%s: %s\n", gettext("value common name"), buf);
12942 free(buf);
12943 }
12944
12945 if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12946 if (as_value == 0)
12947 safe_printf("%s", TMPL_CHOICE_INDENT);
12948 else
12949 safe_printf("%s", TMPL_INDENT);
12950 safe_printf("%s: %s\n", gettext("value description"), buf);
12951 free(buf);
12952 }
12953 }
12954
12955 static void
print_template_value(scf_prop_tmpl_t * prt,const char * val_buf)12956 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12957 {
12958 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12959 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12960 safe_printf("%s\n", val_buf);
12961
12962 print_template_value_details(prt, val_buf, 1);
12963 }
12964
12965 static void
print_template_constraints(scf_prop_tmpl_t * prt,int verbose)12966 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12967 {
12968 int i, printed = 0;
12969 scf_values_t values;
12970 scf_count_ranges_t c_ranges;
12971 scf_int_ranges_t i_ranges;
12972
12973 printed = 0;
12974 i = 0;
12975 if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12976 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12977 gettext("value constraints"));
12978 printed++;
12979 for (i = 0; i < values.value_count; ++i) {
12980 safe_printf("%s%s: %s\n", TMPL_INDENT,
12981 gettext("value name"), values.values_as_strings[i]);
12982 if (verbose == 1)
12983 print_template_value_details(prt,
12984 values.values_as_strings[i], 0);
12985 }
12986
12987 scf_values_destroy(&values);
12988 }
12989
12990 if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12991 if (printed++ == 0)
12992 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12993 gettext("value constraints"));
12994 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12995 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12996 gettext("range"), c_ranges.scr_min[i],
12997 c_ranges.scr_max[i]);
12998 }
12999 scf_count_ranges_destroy(&c_ranges);
13000 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
13001 scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
13002 if (printed++ == 0)
13003 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13004 gettext("value constraints"));
13005 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
13006 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
13007 gettext("range"), i_ranges.sir_min[i],
13008 i_ranges.sir_max[i]);
13009 }
13010 scf_int_ranges_destroy(&i_ranges);
13011 }
13012 }
13013
13014 static void
print_template_choices(scf_prop_tmpl_t * prt,int verbose)13015 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
13016 {
13017 int i = 0, printed = 0;
13018 scf_values_t values;
13019 scf_count_ranges_t c_ranges;
13020 scf_int_ranges_t i_ranges;
13021
13022 printed = 0;
13023 if (scf_tmpl_value_name_choices(prt, &values) == 0) {
13024 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13025 gettext("value constraints"));
13026 printed++;
13027 for (i = 0; i < values.value_count; i++) {
13028 safe_printf("%s%s: %s\n", TMPL_INDENT,
13029 gettext("value name"), values.values_as_strings[i]);
13030 if (verbose == 1)
13031 print_template_value_details(prt,
13032 values.values_as_strings[i], 0);
13033 }
13034
13035 scf_values_destroy(&values);
13036 }
13037
13038 if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
13039 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
13040 if (printed++ == 0)
13041 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13042 gettext("value choices"));
13043 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
13044 gettext("range"), c_ranges.scr_min[i],
13045 c_ranges.scr_max[i]);
13046 }
13047 scf_count_ranges_destroy(&c_ranges);
13048 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
13049 scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
13050 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
13051 if (printed++ == 0)
13052 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13053 gettext("value choices"));
13054 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
13055 gettext("range"), i_ranges.sir_min[i],
13056 i_ranges.sir_max[i]);
13057 }
13058 scf_int_ranges_destroy(&i_ranges);
13059 }
13060 }
13061
13062 static void
list_values_by_template(scf_prop_tmpl_t * prt)13063 list_values_by_template(scf_prop_tmpl_t *prt)
13064 {
13065 print_template_constraints(prt, 1);
13066 print_template_choices(prt, 1);
13067 }
13068
13069 static void
list_values_tmpl(scf_prop_tmpl_t * prt,scf_property_t * prop)13070 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
13071 {
13072 char *val_buf;
13073 scf_iter_t *iter;
13074 scf_value_t *val;
13075 int ret;
13076
13077 if ((iter = scf_iter_create(g_hndl)) == NULL ||
13078 (val = scf_value_create(g_hndl)) == NULL)
13079 scfdie();
13080
13081 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
13082 scfdie();
13083
13084 val_buf = safe_malloc(max_scf_value_len + 1);
13085
13086 while ((ret = scf_iter_next_value(iter, val)) == 1) {
13087 if (scf_value_get_as_string(val, val_buf,
13088 max_scf_value_len + 1) < 0)
13089 scfdie();
13090
13091 print_template_value(prt, val_buf);
13092 }
13093 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
13094 scfdie();
13095 free(val_buf);
13096
13097 print_template_constraints(prt, 0);
13098 print_template_choices(prt, 0);
13099
13100 }
13101
13102 /*
13103 * Outputs property info for the describe subcommand
13104 * Verbose output if templates == 2, -v option of svccfg describe
13105 * Displays template data if prop is not NULL, -t option of svccfg describe
13106 */
13107 static void
list_prop_tmpl(scf_prop_tmpl_t * prt,scf_property_t * prop,int templates)13108 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
13109 {
13110 char *buf;
13111 uint8_t u_buf;
13112 int i;
13113 uint64_t min, max;
13114 scf_values_t values;
13115
13116 if (prt == NULL || templates == 0)
13117 return;
13118
13119 if (prop == NULL) {
13120 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
13121 if (scf_tmpl_prop_name(prt, &buf) > 0) {
13122 safe_printf("%s\n", buf);
13123 free(buf);
13124 } else
13125 safe_printf("(%s)\n", gettext("any"));
13126 }
13127
13128 if (prop == NULL || templates == 2) {
13129 if (prop != NULL)
13130 safe_printf("%s", TMPL_INDENT);
13131 else
13132 safe_printf("%s", TMPL_VALUE_INDENT);
13133 safe_printf("%s: ", gettext("type"));
13134 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
13135 safe_printf("%s\n", buf);
13136 free(buf);
13137 } else
13138 safe_printf("(%s)\n", gettext("any"));
13139 }
13140
13141 if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
13142 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
13143 u_buf ? "true" : "false");
13144
13145 if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
13146 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
13147 buf);
13148 free(buf);
13149 }
13150
13151 if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
13152 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
13153 buf);
13154 free(buf);
13155 }
13156
13157 if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
13158 safe_printf("%s%s\n", TMPL_INDENT, buf);
13159 free(buf);
13160 }
13161
13162 if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
13163 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
13164 scf_tmpl_visibility_to_string(u_buf));
13165
13166 if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
13167 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13168 gettext("minimum number of values"), min);
13169 if (max == ULLONG_MAX) {
13170 safe_printf("%s%s: %s\n", TMPL_INDENT,
13171 gettext("maximum number of values"),
13172 gettext("unlimited"));
13173 } else {
13174 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13175 gettext("maximum number of values"), max);
13176 }
13177 }
13178
13179 if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
13180 for (i = 0; i < values.value_count; i++) {
13181 if (i == 0) {
13182 safe_printf("%s%s:", TMPL_INDENT,
13183 gettext("internal separators"));
13184 }
13185 safe_printf(" \"%s\"", values.values_as_strings[i]);
13186 }
13187 safe_printf("\n");
13188 }
13189
13190 if (templates != 2)
13191 return;
13192
13193 if (prop != NULL)
13194 list_values_tmpl(prt, prop);
13195 else
13196 list_values_by_template(prt);
13197 }
13198
13199 static char *
read_astring(scf_propertygroup_t * pg,const char * prop_name)13200 read_astring(scf_propertygroup_t *pg, const char *prop_name)
13201 {
13202 char *rv;
13203
13204 rv = _scf_read_single_astring_from_pg(pg, prop_name);
13205 if (rv == NULL) {
13206 switch (scf_error()) {
13207 case SCF_ERROR_NOT_FOUND:
13208 break;
13209 default:
13210 scfdie();
13211 }
13212 }
13213 return (rv);
13214 }
13215
13216 static void
display_documentation(scf_iter_t * iter,scf_propertygroup_t * pg)13217 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
13218 {
13219 size_t doc_len;
13220 size_t man_len;
13221 char *pg_name;
13222 char *text = NULL;
13223 int rv;
13224
13225 doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
13226 man_len = strlen(SCF_PG_TM_MAN_PREFIX);
13227 pg_name = safe_malloc(max_scf_name_len + 1);
13228 while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
13229 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
13230 scfdie();
13231 }
13232 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
13233 /* Display doc_link and and uri */
13234 safe_printf("%s%s:\n", TMPL_INDENT,
13235 gettext("doc_link"));
13236 text = read_astring(pg, SCF_PROPERTY_TM_NAME);
13237 if (text != NULL) {
13238 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13239 TMPL_INDENT, gettext("name"), text);
13240 uu_free(text);
13241 }
13242 text = read_astring(pg, SCF_PROPERTY_TM_URI);
13243 if (text != NULL) {
13244 safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
13245 gettext("uri"), text);
13246 uu_free(text);
13247 }
13248 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
13249 man_len) == 0) {
13250 /* Display manpage title, section and path */
13251 safe_printf("%s%s:\n", TMPL_INDENT,
13252 gettext("manpage"));
13253 text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
13254 if (text != NULL) {
13255 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13256 TMPL_INDENT, gettext("title"), text);
13257 uu_free(text);
13258 }
13259 text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
13260 if (text != NULL) {
13261 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13262 TMPL_INDENT, gettext("section"), text);
13263 uu_free(text);
13264 }
13265 text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
13266 if (text != NULL) {
13267 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13268 TMPL_INDENT, gettext("manpath"), text);
13269 uu_free(text);
13270 }
13271 }
13272 }
13273 if (rv == -1)
13274 scfdie();
13275
13276 done:
13277 free(pg_name);
13278 }
13279
13280 static void
list_entity_tmpl(int templates)13281 list_entity_tmpl(int templates)
13282 {
13283 char *common_name = NULL;
13284 char *description = NULL;
13285 char *locale = NULL;
13286 scf_iter_t *iter;
13287 scf_propertygroup_t *pg;
13288 scf_property_t *prop;
13289 int r;
13290 scf_value_t *val;
13291
13292 if ((pg = scf_pg_create(g_hndl)) == NULL ||
13293 (prop = scf_property_create(g_hndl)) == NULL ||
13294 (val = scf_value_create(g_hndl)) == NULL ||
13295 (iter = scf_iter_create(g_hndl)) == NULL)
13296 scfdie();
13297
13298 locale = setlocale(LC_MESSAGES, NULL);
13299
13300 if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
13301 common_name = safe_malloc(max_scf_value_len + 1);
13302
13303 /* Try both the current locale and the "C" locale. */
13304 if (scf_pg_get_property(pg, locale, prop) == 0 ||
13305 (scf_error() == SCF_ERROR_NOT_FOUND &&
13306 scf_pg_get_property(pg, "C", prop) == 0)) {
13307 if (prop_get_val(prop, val) == 0 &&
13308 scf_value_get_ustring(val, common_name,
13309 max_scf_value_len + 1) != -1) {
13310 safe_printf("%s%s: %s\n", TMPL_INDENT,
13311 gettext("common name"), common_name);
13312 }
13313 }
13314 }
13315
13316 /*
13317 * Do description, manpages, and doc links if templates == 2.
13318 */
13319 if (templates == 2) {
13320 /* Get the description. */
13321 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
13322 description = safe_malloc(max_scf_value_len + 1);
13323
13324 /* Try both the current locale and the "C" locale. */
13325 if (scf_pg_get_property(pg, locale, prop) == 0 ||
13326 (scf_error() == SCF_ERROR_NOT_FOUND &&
13327 scf_pg_get_property(pg, "C", prop) == 0)) {
13328 if (prop_get_val(prop, val) == 0 &&
13329 scf_value_get_ustring(val, description,
13330 max_scf_value_len + 1) != -1) {
13331 safe_printf("%s%s: %s\n", TMPL_INDENT,
13332 gettext("description"),
13333 description);
13334 }
13335 }
13336 }
13337
13338 /* Process doc_link & manpage elements. */
13339 if (cur_level != NULL) {
13340 r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
13341 SCF_GROUP_TEMPLATE);
13342 } else if (cur_inst != NULL) {
13343 r = scf_iter_instance_pgs_typed(iter, cur_inst,
13344 SCF_GROUP_TEMPLATE);
13345 } else {
13346 r = scf_iter_service_pgs_typed(iter, cur_svc,
13347 SCF_GROUP_TEMPLATE);
13348 }
13349 if (r == 0) {
13350 display_documentation(iter, pg);
13351 }
13352 }
13353
13354 free(common_name);
13355 free(description);
13356 scf_pg_destroy(pg);
13357 scf_property_destroy(prop);
13358 scf_value_destroy(val);
13359 scf_iter_destroy(iter);
13360 }
13361
13362 static void
listtmpl(const char * pattern,int templates)13363 listtmpl(const char *pattern, int templates)
13364 {
13365 scf_pg_tmpl_t *pgt;
13366 scf_prop_tmpl_t *prt;
13367 char *snapbuf = NULL;
13368 char *fmribuf;
13369 char *pg_name = NULL, *prop_name = NULL;
13370 ssize_t prop_name_size;
13371 char *qual_prop_name;
13372 char *search_name;
13373 int listed = 0;
13374
13375 if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13376 (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
13377 scfdie();
13378
13379 fmribuf = safe_malloc(max_scf_name_len + 1);
13380 qual_prop_name = safe_malloc(max_scf_name_len + 1);
13381
13382 if (cur_snap != NULL) {
13383 snapbuf = safe_malloc(max_scf_name_len + 1);
13384 if (scf_snapshot_get_name(cur_snap, snapbuf,
13385 max_scf_name_len + 1) < 0)
13386 scfdie();
13387 }
13388
13389 if (cur_inst != NULL) {
13390 if (scf_instance_to_fmri(cur_inst, fmribuf,
13391 max_scf_name_len + 1) < 0)
13392 scfdie();
13393 } else if (cur_svc != NULL) {
13394 if (scf_service_to_fmri(cur_svc, fmribuf,
13395 max_scf_name_len + 1) < 0)
13396 scfdie();
13397 } else
13398 abort();
13399
13400 /* If pattern is specified, we want to list only those items. */
13401 while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) {
13402 listed = 0;
13403 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
13404 fnmatch(pattern, pg_name, 0) == 0)) {
13405 list_pg_tmpl(pgt, NULL, templates);
13406 listed++;
13407 }
13408
13409 scf_tmpl_prop_reset(prt);
13410
13411 while (scf_tmpl_iter_props(pgt, prt, 0) == 0) {
13412 search_name = NULL;
13413 prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
13414 if ((prop_name_size > 0) && (pg_name != NULL)) {
13415 if (snprintf(qual_prop_name,
13416 max_scf_name_len + 1, "%s/%s",
13417 pg_name, prop_name) >=
13418 max_scf_name_len + 1) {
13419 prop_name_size = -1;
13420 } else {
13421 search_name = qual_prop_name;
13422 }
13423 }
13424 if (listed > 0 || pattern == NULL ||
13425 (prop_name_size > 0 &&
13426 fnmatch(pattern, search_name,
13427 FNM_PATHNAME) == 0))
13428 list_prop_tmpl(prt, NULL, templates);
13429 if (prop_name != NULL) {
13430 free(prop_name);
13431 prop_name = NULL;
13432 }
13433 }
13434 if (pg_name != NULL) {
13435 free(pg_name);
13436 pg_name = NULL;
13437 }
13438 }
13439
13440 scf_tmpl_prop_destroy(prt);
13441 scf_tmpl_pg_destroy(pgt);
13442 free(snapbuf);
13443 free(fmribuf);
13444 free(qual_prop_name);
13445 }
13446
13447 static void
listprop(const char * pattern,int only_pgs,int templates)13448 listprop(const char *pattern, int only_pgs, int templates)
13449 {
13450 scf_propertygroup_t *pg;
13451 scf_property_t *prop;
13452 scf_iter_t *iter, *piter;
13453 char *pgnbuf, *prnbuf, *ppnbuf;
13454 scf_pg_tmpl_t *pgt, *pgtp;
13455 scf_prop_tmpl_t *prt;
13456
13457 void **objects;
13458 char **names;
13459 void **tmpls;
13460 int allocd, i;
13461
13462 int ret;
13463 ssize_t pgnlen, prnlen, szret;
13464 size_t max_len = 0;
13465
13466 if (cur_svc == NULL && cur_inst == NULL) {
13467 semerr(emsg_entity_not_selected);
13468 return;
13469 }
13470
13471 if ((pg = scf_pg_create(g_hndl)) == NULL ||
13472 (prop = scf_property_create(g_hndl)) == NULL ||
13473 (iter = scf_iter_create(g_hndl)) == NULL ||
13474 (piter = scf_iter_create(g_hndl)) == NULL ||
13475 (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13476 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
13477 scfdie();
13478
13479 prnbuf = safe_malloc(max_scf_name_len + 1);
13480
13481 if (cur_level != NULL)
13482 ret = scf_iter_snaplevel_pgs(iter, cur_level);
13483 else if (cur_inst != NULL)
13484 ret = scf_iter_instance_pgs(iter, cur_inst);
13485 else
13486 ret = scf_iter_service_pgs(iter, cur_svc);
13487 if (ret != 0) {
13488 return;
13489 }
13490
13491 /*
13492 * We want to only list items which match pattern, and we want the
13493 * second column to line up, so during the first pass we'll save
13494 * matching items, their names, and their templates in objects,
13495 * names, and tmpls, computing the maximum name length as we go,
13496 * and then we'll print them out.
13497 *
13498 * Note: We always keep an extra slot available so the array can be
13499 * NULL-terminated.
13500 */
13501 i = 0;
13502 allocd = 1;
13503 objects = safe_malloc(sizeof (*objects));
13504 names = safe_malloc(sizeof (*names));
13505 tmpls = safe_malloc(sizeof (*tmpls));
13506
13507 while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13508 int new_pg = 0;
13509 int print_props = 0;
13510 pgtp = NULL;
13511
13512 pgnlen = scf_pg_get_name(pg, NULL, 0);
13513 if (pgnlen < 0)
13514 scfdie();
13515
13516 pgnbuf = safe_malloc(pgnlen + 1);
13517
13518 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
13519 if (szret < 0)
13520 scfdie();
13521 assert(szret <= pgnlen);
13522
13523 if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) {
13524 if (scf_error() != SCF_ERROR_NOT_FOUND)
13525 scfdie();
13526 pgtp = NULL;
13527 } else {
13528 pgtp = pgt;
13529 }
13530
13531 if (pattern == NULL ||
13532 fnmatch(pattern, pgnbuf, 0) == 0) {
13533 if (i+1 >= allocd) {
13534 allocd *= 2;
13535 objects = realloc(objects,
13536 sizeof (*objects) * allocd);
13537 names =
13538 realloc(names, sizeof (*names) * allocd);
13539 tmpls = realloc(tmpls,
13540 sizeof (*tmpls) * allocd);
13541 if (objects == NULL || names == NULL ||
13542 tmpls == NULL)
13543 uu_die(gettext("Out of memory"));
13544 }
13545 objects[i] = pg;
13546 names[i] = pgnbuf;
13547
13548 if (pgtp == NULL)
13549 tmpls[i] = NULL;
13550 else
13551 tmpls[i] = pgt;
13552
13553 ++i;
13554
13555 if (pgnlen > max_len)
13556 max_len = pgnlen;
13557
13558 new_pg = 1;
13559 print_props = 1;
13560 }
13561
13562 if (only_pgs) {
13563 if (new_pg) {
13564 pg = scf_pg_create(g_hndl);
13565 if (pg == NULL)
13566 scfdie();
13567 pgt = scf_tmpl_pg_create(g_hndl);
13568 if (pgt == NULL)
13569 scfdie();
13570 } else
13571 free(pgnbuf);
13572
13573 continue;
13574 }
13575
13576 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13577 scfdie();
13578
13579 while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13580 prnlen = scf_property_get_name(prop, prnbuf,
13581 max_scf_name_len + 1);
13582 if (prnlen < 0)
13583 scfdie();
13584
13585 /* Will prepend the property group name and a slash. */
13586 prnlen += pgnlen + 1;
13587
13588 ppnbuf = safe_malloc(prnlen + 1);
13589
13590 if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13591 prnbuf) < 0)
13592 uu_die("snprintf");
13593
13594 if (pattern == NULL || print_props == 1 ||
13595 fnmatch(pattern, ppnbuf, 0) == 0) {
13596 if (i+1 >= allocd) {
13597 allocd *= 2;
13598 objects = realloc(objects,
13599 sizeof (*objects) * allocd);
13600 names = realloc(names,
13601 sizeof (*names) * allocd);
13602 tmpls = realloc(tmpls,
13603 sizeof (*tmpls) * allocd);
13604 if (objects == NULL || names == NULL ||
13605 tmpls == NULL)
13606 uu_die(gettext(
13607 "Out of memory"));
13608 }
13609
13610 objects[i] = prop;
13611 names[i] = ppnbuf;
13612
13613 if (pgtp != NULL) {
13614 if (scf_tmpl_get_by_prop(pgt, prnbuf,
13615 prt, 0) < 0) {
13616 if (scf_error() !=
13617 SCF_ERROR_NOT_FOUND)
13618 scfdie();
13619 tmpls[i] = NULL;
13620 } else {
13621 tmpls[i] = prt;
13622 }
13623 } else {
13624 tmpls[i] = NULL;
13625 }
13626
13627 ++i;
13628
13629 if (prnlen > max_len)
13630 max_len = prnlen;
13631
13632 prop = scf_property_create(g_hndl);
13633 prt = scf_tmpl_prop_create(g_hndl);
13634 } else {
13635 free(ppnbuf);
13636 }
13637 }
13638
13639 if (new_pg) {
13640 pg = scf_pg_create(g_hndl);
13641 if (pg == NULL)
13642 scfdie();
13643 pgt = scf_tmpl_pg_create(g_hndl);
13644 if (pgt == NULL)
13645 scfdie();
13646 } else
13647 free(pgnbuf);
13648 }
13649 if (ret != 0)
13650 scfdie();
13651
13652 objects[i] = NULL;
13653
13654 scf_pg_destroy(pg);
13655 scf_tmpl_pg_destroy(pgt);
13656 scf_property_destroy(prop);
13657 scf_tmpl_prop_destroy(prt);
13658
13659 for (i = 0; objects[i] != NULL; ++i) {
13660 if (strchr(names[i], '/') == NULL) {
13661 /* property group */
13662 pg = (scf_propertygroup_t *)objects[i];
13663 pgt = (scf_pg_tmpl_t *)tmpls[i];
13664 list_pg_info(pg, names[i], max_len);
13665 list_pg_tmpl(pgt, pg, templates);
13666 free(names[i]);
13667 scf_pg_destroy(pg);
13668 if (pgt != NULL)
13669 scf_tmpl_pg_destroy(pgt);
13670 } else {
13671 /* property */
13672 prop = (scf_property_t *)objects[i];
13673 prt = (scf_prop_tmpl_t *)tmpls[i];
13674 list_prop_info(prop, names[i], max_len);
13675 list_prop_tmpl(prt, prop, templates);
13676 free(names[i]);
13677 scf_property_destroy(prop);
13678 if (prt != NULL)
13679 scf_tmpl_prop_destroy(prt);
13680 }
13681 }
13682
13683 free(names);
13684 free(objects);
13685 free(tmpls);
13686 }
13687
13688 void
lscf_listpg(const char * pattern)13689 lscf_listpg(const char *pattern)
13690 {
13691 lscf_prep_hndl();
13692
13693 listprop(pattern, 1, 0);
13694 }
13695
13696 /*
13697 * Property group and property creation, setting, and deletion. setprop (and
13698 * its alias, addprop) can either create a property group of a given type, or
13699 * it can create or set a property to a given type and list of values.
13700 */
13701 void
lscf_addpg(const char * name,const char * type,const char * flags)13702 lscf_addpg(const char *name, const char *type, const char *flags)
13703 {
13704 scf_propertygroup_t *pg;
13705 int ret;
13706 uint32_t flgs = 0;
13707 const char *cp;
13708
13709
13710 lscf_prep_hndl();
13711
13712 if (cur_snap != NULL) {
13713 semerr(emsg_cant_modify_snapshots);
13714 return;
13715 }
13716
13717 if (cur_inst == NULL && cur_svc == NULL) {
13718 semerr(emsg_entity_not_selected);
13719 return;
13720 }
13721
13722 if (flags != NULL) {
13723 for (cp = flags; *cp != '\0'; ++cp) {
13724 switch (*cp) {
13725 case 'P':
13726 flgs |= SCF_PG_FLAG_NONPERSISTENT;
13727 break;
13728
13729 case 'p':
13730 flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13731 break;
13732
13733 default:
13734 semerr(gettext("Invalid property group flag "
13735 "%c."), *cp);
13736 return;
13737 }
13738 }
13739 }
13740
13741 pg = scf_pg_create(g_hndl);
13742 if (pg == NULL)
13743 scfdie();
13744
13745 if (cur_inst != NULL)
13746 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13747 else
13748 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13749
13750 if (ret != SCF_SUCCESS) {
13751 switch (scf_error()) {
13752 case SCF_ERROR_INVALID_ARGUMENT:
13753 semerr(gettext("Name, type, or flags are invalid.\n"));
13754 break;
13755
13756 case SCF_ERROR_EXISTS:
13757 semerr(gettext("Property group already exists.\n"));
13758 break;
13759
13760 case SCF_ERROR_PERMISSION_DENIED:
13761 semerr(emsg_permission_denied);
13762 break;
13763
13764 case SCF_ERROR_BACKEND_ACCESS:
13765 semerr(gettext("Backend refused access.\n"));
13766 break;
13767
13768 default:
13769 scfdie();
13770 }
13771 }
13772
13773 scf_pg_destroy(pg);
13774
13775 private_refresh();
13776 }
13777
13778 void
lscf_delpg(char * name)13779 lscf_delpg(char *name)
13780 {
13781 lscf_prep_hndl();
13782
13783 if (cur_snap != NULL) {
13784 semerr(emsg_cant_modify_snapshots);
13785 return;
13786 }
13787
13788 if (cur_inst == NULL && cur_svc == NULL) {
13789 semerr(emsg_entity_not_selected);
13790 return;
13791 }
13792
13793 if (strchr(name, '/') != NULL) {
13794 semerr(emsg_invalid_pg_name, name);
13795 return;
13796 }
13797
13798 lscf_delprop(name);
13799 }
13800
13801 /*
13802 * scf_delhash() is used to remove the property group related to the
13803 * hash entry for a specific manifest in the repository. pgname will be
13804 * constructed from the location of the manifest file. If deathrow isn't 0,
13805 * manifest file doesn't need to exist (manifest string will be used as
13806 * an absolute path).
13807 */
13808 void
lscf_delhash(char * manifest,int deathrow)13809 lscf_delhash(char *manifest, int deathrow)
13810 {
13811 char *pgname;
13812
13813 if (cur_snap != NULL ||
13814 cur_inst != NULL || cur_svc != NULL) {
13815 warn(gettext("error, an entity is selected\n"));
13816 return;
13817 }
13818
13819 /* select smf/manifest */
13820 lscf_select(HASH_SVC);
13821 /*
13822 * Translate the manifest file name to property name. In the deathrow
13823 * case, the manifest file does not need to exist.
13824 */
13825 pgname = mhash_filename_to_propname(manifest,
13826 deathrow ? B_TRUE : B_FALSE);
13827 if (pgname == NULL) {
13828 warn(gettext("cannot resolve pathname for %s\n"), manifest);
13829 return;
13830 }
13831 /* delete the hash property name */
13832 lscf_delpg(pgname);
13833 }
13834
13835 void
lscf_listprop(const char * pattern)13836 lscf_listprop(const char *pattern)
13837 {
13838 lscf_prep_hndl();
13839
13840 listprop(pattern, 0, 0);
13841 }
13842
13843 int
lscf_setprop(const char * pgname,const char * type,const char * value,const uu_list_t * values)13844 lscf_setprop(const char *pgname, const char *type, const char *value,
13845 const uu_list_t *values)
13846 {
13847 scf_type_t ty, current_ty;
13848 scf_service_t *svc;
13849 scf_propertygroup_t *pg, *parent_pg;
13850 scf_property_t *prop, *parent_prop;
13851 scf_pg_tmpl_t *pgt;
13852 scf_prop_tmpl_t *prt;
13853 int ret, result = 0;
13854 scf_transaction_t *tx;
13855 scf_transaction_entry_t *e;
13856 scf_value_t *v;
13857 uu_list_walk_t *walk;
13858 string_list_t *sp;
13859 char *propname;
13860 int req_quotes = 0;
13861
13862 lscf_prep_hndl();
13863
13864 if ((e = scf_entry_create(g_hndl)) == NULL ||
13865 (svc = scf_service_create(g_hndl)) == NULL ||
13866 (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13867 (pg = scf_pg_create(g_hndl)) == NULL ||
13868 (parent_prop = scf_property_create(g_hndl)) == NULL ||
13869 (prop = scf_property_create(g_hndl)) == NULL ||
13870 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13871 (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13872 (tx = scf_transaction_create(g_hndl)) == NULL)
13873 scfdie();
13874
13875 if (cur_snap != NULL) {
13876 semerr(emsg_cant_modify_snapshots);
13877 goto fail;
13878 }
13879
13880 if (cur_inst == NULL && cur_svc == NULL) {
13881 semerr(emsg_entity_not_selected);
13882 goto fail;
13883 }
13884
13885 propname = strchr(pgname, '/');
13886 if (propname == NULL) {
13887 semerr(gettext("Property names must contain a `/'.\n"));
13888 goto fail;
13889 }
13890
13891 *propname = '\0';
13892 ++propname;
13893
13894 if (type != NULL) {
13895 ty = string_to_type(type);
13896 if (ty == SCF_TYPE_INVALID) {
13897 semerr(gettext("Unknown type \"%s\".\n"), type);
13898 goto fail;
13899 }
13900 }
13901
13902 if (cur_inst != NULL)
13903 ret = scf_instance_get_pg(cur_inst, pgname, pg);
13904 else
13905 ret = scf_service_get_pg(cur_svc, pgname, pg);
13906 if (ret != SCF_SUCCESS) {
13907 switch (scf_error()) {
13908 case SCF_ERROR_NOT_FOUND:
13909 semerr(emsg_no_such_pg, pgname);
13910 goto fail;
13911
13912 case SCF_ERROR_INVALID_ARGUMENT:
13913 semerr(emsg_invalid_pg_name, pgname);
13914 goto fail;
13915
13916 default:
13917 scfdie();
13918 break;
13919 }
13920 }
13921
13922 do {
13923 if (scf_pg_update(pg) == -1)
13924 scfdie();
13925 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13926 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13927 scfdie();
13928
13929 semerr(emsg_permission_denied);
13930 goto fail;
13931 }
13932
13933 ret = scf_pg_get_property(pg, propname, prop);
13934 if (ret == SCF_SUCCESS) {
13935 if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS)
13936 scfdie();
13937
13938 if (type == NULL)
13939 ty = current_ty;
13940 if (scf_transaction_property_change_type(tx, e,
13941 propname, ty) == -1)
13942 scfdie();
13943
13944 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13945 /* Infer the type, if possible. */
13946 if (type == NULL) {
13947 /*
13948 * First check if we're an instance and the
13949 * property is set on the service.
13950 */
13951 if (cur_inst != NULL &&
13952 scf_instance_get_parent(cur_inst,
13953 svc) == 0 &&
13954 scf_service_get_pg(cur_svc, pgname,
13955 parent_pg) == 0 &&
13956 scf_pg_get_property(parent_pg, propname,
13957 parent_prop) == 0 &&
13958 scf_property_type(parent_prop,
13959 ¤t_ty) == 0) {
13960 ty = current_ty;
13961
13962 /* Then check for a type set in a template. */
13963 } else if (scf_tmpl_get_by_pg(pg, pgt,
13964 0) == 0 &&
13965 scf_tmpl_get_by_prop(pgt, propname, prt,
13966 0) == 0 &&
13967 scf_tmpl_prop_type(prt, ¤t_ty) == 0) {
13968 ty = current_ty;
13969
13970 /* If type can't be inferred, fail. */
13971 } else {
13972 semerr(gettext("Type required for new "
13973 "properties.\n"));
13974 goto fail;
13975 }
13976 }
13977 if (scf_transaction_property_new(tx, e, propname,
13978 ty) == -1)
13979 scfdie();
13980 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13981 semerr(emsg_invalid_prop_name, propname);
13982 goto fail;
13983 } else {
13984 scfdie();
13985 }
13986
13987 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13988 req_quotes = 1;
13989
13990 if (value != NULL) {
13991 v = string_to_value(value, ty, 0);
13992
13993 if (v == NULL)
13994 goto fail;
13995
13996 ret = scf_entry_add_value(e, v);
13997 assert(ret == SCF_SUCCESS);
13998 } else {
13999 assert(values != NULL);
14000
14001 walk = uu_list_walk_start((uu_list_t *)values,
14002 UU_DEFAULT);
14003 if (walk == NULL)
14004 uu_die(gettext("Could not walk list"));
14005
14006 for (sp = uu_list_walk_next(walk); sp != NULL;
14007 sp = uu_list_walk_next(walk)) {
14008 v = string_to_value(sp->str, ty, req_quotes);
14009
14010 if (v == NULL) {
14011 scf_entry_destroy_children(e);
14012 goto fail;
14013 }
14014
14015 ret = scf_entry_add_value(e, v);
14016 assert(ret == SCF_SUCCESS);
14017 }
14018 uu_list_walk_end(walk);
14019 }
14020 result = scf_transaction_commit(tx);
14021
14022 scf_transaction_reset(tx);
14023 scf_entry_destroy_children(e);
14024 } while (result == 0);
14025
14026 if (result < 0) {
14027 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14028 scfdie();
14029
14030 semerr(emsg_permission_denied);
14031 goto fail;
14032 }
14033
14034 ret = 0;
14035
14036 private_refresh();
14037
14038 goto cleanup;
14039
14040 fail:
14041 ret = -1;
14042
14043 cleanup:
14044 scf_transaction_destroy(tx);
14045 scf_entry_destroy(e);
14046 scf_service_destroy(svc);
14047 scf_pg_destroy(parent_pg);
14048 scf_pg_destroy(pg);
14049 scf_property_destroy(parent_prop);
14050 scf_property_destroy(prop);
14051 scf_tmpl_pg_destroy(pgt);
14052 scf_tmpl_prop_destroy(prt);
14053
14054 return (ret);
14055 }
14056
14057 void
lscf_delprop(char * pgn)14058 lscf_delprop(char *pgn)
14059 {
14060 char *slash, *pn;
14061 scf_propertygroup_t *pg;
14062 scf_transaction_t *tx;
14063 scf_transaction_entry_t *e;
14064 int ret;
14065
14066
14067 lscf_prep_hndl();
14068
14069 if (cur_snap != NULL) {
14070 semerr(emsg_cant_modify_snapshots);
14071 return;
14072 }
14073
14074 if (cur_inst == NULL && cur_svc == NULL) {
14075 semerr(emsg_entity_not_selected);
14076 return;
14077 }
14078
14079 pg = scf_pg_create(g_hndl);
14080 if (pg == NULL)
14081 scfdie();
14082
14083 slash = strchr(pgn, '/');
14084 if (slash == NULL) {
14085 pn = NULL;
14086 } else {
14087 *slash = '\0';
14088 pn = slash + 1;
14089 }
14090
14091 if (cur_inst != NULL)
14092 ret = scf_instance_get_pg(cur_inst, pgn, pg);
14093 else
14094 ret = scf_service_get_pg(cur_svc, pgn, pg);
14095 if (ret != SCF_SUCCESS) {
14096 switch (scf_error()) {
14097 case SCF_ERROR_NOT_FOUND:
14098 semerr(emsg_no_such_pg, pgn);
14099 break;
14100
14101 case SCF_ERROR_INVALID_ARGUMENT:
14102 semerr(emsg_invalid_pg_name, pgn);
14103 break;
14104
14105 default:
14106 scfdie();
14107 }
14108
14109 scf_pg_destroy(pg);
14110
14111 return;
14112 }
14113
14114 if (pn == NULL) {
14115 /* Try to delete the property group. */
14116 if (scf_pg_delete(pg) != SCF_SUCCESS) {
14117 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14118 scfdie();
14119
14120 semerr(emsg_permission_denied);
14121 } else {
14122 private_refresh();
14123 }
14124
14125 scf_pg_destroy(pg);
14126 return;
14127 }
14128
14129 e = scf_entry_create(g_hndl);
14130 tx = scf_transaction_create(g_hndl);
14131
14132 do {
14133 if (scf_pg_update(pg) == -1)
14134 scfdie();
14135 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
14136 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14137 scfdie();
14138
14139 semerr(emsg_permission_denied);
14140 break;
14141 }
14142
14143 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
14144 if (scf_error() == SCF_ERROR_NOT_FOUND) {
14145 semerr(gettext("No such property %s/%s.\n"),
14146 pgn, pn);
14147 break;
14148 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14149 semerr(emsg_invalid_prop_name, pn);
14150 break;
14151 } else {
14152 scfdie();
14153 }
14154 }
14155
14156 ret = scf_transaction_commit(tx);
14157
14158 if (ret == 0)
14159 scf_transaction_reset(tx);
14160 } while (ret == 0);
14161
14162 if (ret < 0) {
14163 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14164 scfdie();
14165
14166 semerr(emsg_permission_denied);
14167 } else {
14168 private_refresh();
14169 }
14170
14171 scf_transaction_destroy(tx);
14172 scf_entry_destroy(e);
14173 scf_pg_destroy(pg);
14174 }
14175
14176 /*
14177 * Property editing.
14178 */
14179
14180 static int
write_edit_script(FILE * strm)14181 write_edit_script(FILE *strm)
14182 {
14183 char *fmribuf;
14184 ssize_t fmrilen;
14185
14186 scf_propertygroup_t *pg;
14187 scf_property_t *prop;
14188 scf_value_t *val;
14189 scf_type_t ty;
14190 int ret, result = 0;
14191 scf_iter_t *iter, *piter, *viter;
14192 char *buf, *tybuf, *pname;
14193 const char *emsg_write_error;
14194
14195
14196 emsg_write_error = gettext("Error writing temoprary file: %s.\n");
14197
14198
14199 /* select fmri */
14200 if (cur_inst != NULL) {
14201 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
14202 if (fmrilen < 0)
14203 scfdie();
14204 fmribuf = safe_malloc(fmrilen + 1);
14205 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
14206 scfdie();
14207 } else {
14208 assert(cur_svc != NULL);
14209 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
14210 if (fmrilen < 0)
14211 scfdie();
14212 fmribuf = safe_malloc(fmrilen + 1);
14213 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
14214 scfdie();
14215 }
14216
14217 if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
14218 warn(emsg_write_error, strerror(errno));
14219 free(fmribuf);
14220 return (-1);
14221 }
14222
14223 free(fmribuf);
14224
14225
14226 if ((pg = scf_pg_create(g_hndl)) == NULL ||
14227 (prop = scf_property_create(g_hndl)) == NULL ||
14228 (val = scf_value_create(g_hndl)) == NULL ||
14229 (iter = scf_iter_create(g_hndl)) == NULL ||
14230 (piter = scf_iter_create(g_hndl)) == NULL ||
14231 (viter = scf_iter_create(g_hndl)) == NULL)
14232 scfdie();
14233
14234 buf = safe_malloc(max_scf_name_len + 1);
14235 tybuf = safe_malloc(max_scf_pg_type_len + 1);
14236 pname = safe_malloc(max_scf_name_len + 1);
14237
14238 if (cur_inst != NULL)
14239 ret = scf_iter_instance_pgs(iter, cur_inst);
14240 else
14241 ret = scf_iter_service_pgs(iter, cur_svc);
14242 if (ret != SCF_SUCCESS)
14243 scfdie();
14244
14245 while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
14246 int ret2;
14247
14248 /*
14249 * # delprop pg
14250 * # addpg pg type
14251 */
14252 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
14253 scfdie();
14254
14255 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
14256 scfdie();
14257
14258 if (fprintf(strm, "# Property group \"%s\"\n"
14259 "# delprop %s\n"
14260 "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
14261 warn(emsg_write_error, strerror(errno));
14262 result = -1;
14263 goto out;
14264 }
14265
14266 /* # setprop pg/prop = (values) */
14267
14268 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
14269 scfdie();
14270
14271 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
14272 int first = 1;
14273 int ret3;
14274 int multiple;
14275 int is_str;
14276 scf_type_t bty;
14277
14278 if (scf_property_get_name(prop, pname,
14279 max_scf_name_len + 1) < 0)
14280 scfdie();
14281
14282 if (scf_property_type(prop, &ty) != 0)
14283 scfdie();
14284
14285 multiple = prop_has_multiple_values(prop, val);
14286
14287 if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
14288 pname, scf_type_to_string(ty), multiple ? "(" : "")
14289 < 0) {
14290 warn(emsg_write_error, strerror(errno));
14291 result = -1;
14292 goto out;
14293 }
14294
14295 (void) scf_type_base_type(ty, &bty);
14296 is_str = (bty == SCF_TYPE_ASTRING);
14297
14298 if (scf_iter_property_values(viter, prop) !=
14299 SCF_SUCCESS)
14300 scfdie();
14301
14302 while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
14303 char *buf;
14304 ssize_t buflen;
14305
14306 buflen = scf_value_get_as_string(val, NULL, 0);
14307 if (buflen < 0)
14308 scfdie();
14309
14310 buf = safe_malloc(buflen + 1);
14311
14312 if (scf_value_get_as_string(val, buf,
14313 buflen + 1) < 0)
14314 scfdie();
14315
14316 if (first)
14317 first = 0;
14318 else {
14319 if (putc(' ', strm) != ' ') {
14320 warn(emsg_write_error,
14321 strerror(errno));
14322 result = -1;
14323 goto out;
14324 }
14325 }
14326
14327 if ((is_str && multiple) ||
14328 strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
14329 (void) putc('"', strm);
14330 (void) quote_and_print(buf, strm, 1);
14331 (void) putc('"', strm);
14332
14333 if (ferror(strm)) {
14334 warn(emsg_write_error,
14335 strerror(errno));
14336 result = -1;
14337 goto out;
14338 }
14339 } else {
14340 if (fprintf(strm, "%s", buf) < 0) {
14341 warn(emsg_write_error,
14342 strerror(errno));
14343 result = -1;
14344 goto out;
14345 }
14346 }
14347
14348 free(buf);
14349 }
14350 if (ret3 < 0 &&
14351 scf_error() != SCF_ERROR_PERMISSION_DENIED)
14352 scfdie();
14353
14354 /* Write closing paren if mult-value property */
14355 if ((multiple && putc(')', strm) == EOF) ||
14356
14357 /* Write final newline */
14358 fputc('\n', strm) == EOF) {
14359 warn(emsg_write_error, strerror(errno));
14360 result = -1;
14361 goto out;
14362 }
14363 }
14364 if (ret2 < 0)
14365 scfdie();
14366
14367 if (fputc('\n', strm) == EOF) {
14368 warn(emsg_write_error, strerror(errno));
14369 result = -1;
14370 goto out;
14371 }
14372 }
14373 if (ret < 0)
14374 scfdie();
14375
14376 out:
14377 free(pname);
14378 free(tybuf);
14379 free(buf);
14380 scf_iter_destroy(viter);
14381 scf_iter_destroy(piter);
14382 scf_iter_destroy(iter);
14383 scf_value_destroy(val);
14384 scf_property_destroy(prop);
14385 scf_pg_destroy(pg);
14386
14387 if (result == 0) {
14388 if (fflush(strm) != 0) {
14389 warn(emsg_write_error, strerror(errno));
14390 return (-1);
14391 }
14392 }
14393
14394 return (result);
14395 }
14396
14397 int
lscf_editprop(void)14398 lscf_editprop(void)
14399 {
14400 char *buf, *editor;
14401 size_t bufsz;
14402 int tmpfd;
14403 char tempname[] = TEMP_FILE_PATTERN;
14404
14405 lscf_prep_hndl();
14406
14407 if (cur_snap != NULL) {
14408 semerr(emsg_cant_modify_snapshots);
14409 return (-1);
14410 }
14411
14412 if (cur_svc == NULL && cur_inst == NULL) {
14413 semerr(emsg_entity_not_selected);
14414 return (-1);
14415 }
14416
14417 tmpfd = mkstemp(tempname);
14418 if (tmpfd == -1) {
14419 semerr(gettext("Could not create temporary file.\n"));
14420 return (-1);
14421 }
14422
14423 (void) strcpy(tempfilename, tempname);
14424
14425 tempfile = fdopen(tmpfd, "r+");
14426 if (tempfile == NULL) {
14427 warn(gettext("Could not create temporary file.\n"));
14428 if (close(tmpfd) == -1)
14429 warn(gettext("Could not close temporary file: %s.\n"),
14430 strerror(errno));
14431
14432 remove_tempfile();
14433
14434 return (-1);
14435 }
14436
14437 if (write_edit_script(tempfile) == -1) {
14438 remove_tempfile();
14439 return (-1);
14440 }
14441
14442 editor = getenv("EDITOR");
14443 if (editor == NULL)
14444 editor = "vi";
14445
14446 bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
14447 buf = safe_malloc(bufsz);
14448
14449 if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
14450 uu_die(gettext("Error creating editor command"));
14451
14452 if (system(buf) == -1) {
14453 semerr(gettext("Could not launch editor %s: %s\n"), editor,
14454 strerror(errno));
14455 free(buf);
14456 remove_tempfile();
14457 return (-1);
14458 }
14459
14460 free(buf);
14461
14462 (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
14463
14464 remove_tempfile();
14465
14466 return (0);
14467 }
14468
14469 static void
add_string(uu_list_t * strlist,const char * str)14470 add_string(uu_list_t *strlist, const char *str)
14471 {
14472 string_list_t *elem;
14473 elem = safe_malloc(sizeof (*elem));
14474 uu_list_node_init(elem, &elem->node, string_pool);
14475 elem->str = safe_strdup(str);
14476 if (uu_list_append(strlist, elem) != 0)
14477 uu_die(gettext("libuutil error: %s\n"),
14478 uu_strerror(uu_error()));
14479 }
14480
14481 static int
remove_string(uu_list_t * strlist,const char * str)14482 remove_string(uu_list_t *strlist, const char *str)
14483 {
14484 uu_list_walk_t *elems;
14485 string_list_t *sp;
14486
14487 /*
14488 * Find the element that needs to be removed.
14489 */
14490 elems = uu_list_walk_start(strlist, UU_DEFAULT);
14491 while ((sp = uu_list_walk_next(elems)) != NULL) {
14492 if (strcmp(sp->str, str) == 0)
14493 break;
14494 }
14495 uu_list_walk_end(elems);
14496
14497 /*
14498 * Returning 1 here as the value was not found, this
14499 * might not be an error. Leave it to the caller to
14500 * decide.
14501 */
14502 if (sp == NULL) {
14503 return (1);
14504 }
14505
14506 uu_list_remove(strlist, sp);
14507
14508 free(sp->str);
14509 free(sp);
14510
14511 return (0);
14512 }
14513
14514 /*
14515 * Get all property values that don't match the given glob pattern,
14516 * if a pattern is specified.
14517 */
14518 static void
get_prop_values(scf_property_t * prop,uu_list_t * values,const char * pattern)14519 get_prop_values(scf_property_t *prop, uu_list_t *values,
14520 const char *pattern)
14521 {
14522 scf_iter_t *iter;
14523 scf_value_t *val;
14524 int ret;
14525
14526 if ((iter = scf_iter_create(g_hndl)) == NULL ||
14527 (val = scf_value_create(g_hndl)) == NULL)
14528 scfdie();
14529
14530 if (scf_iter_property_values(iter, prop) != 0)
14531 scfdie();
14532
14533 while ((ret = scf_iter_next_value(iter, val)) == 1) {
14534 char *buf;
14535 ssize_t vlen, szret;
14536
14537 vlen = scf_value_get_as_string(val, NULL, 0);
14538 if (vlen < 0)
14539 scfdie();
14540
14541 buf = safe_malloc(vlen + 1);
14542
14543 szret = scf_value_get_as_string(val, buf, vlen + 1);
14544 if (szret < 0)
14545 scfdie();
14546 assert(szret <= vlen);
14547
14548 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14549 add_string(values, buf);
14550
14551 free(buf);
14552 }
14553
14554 if (ret == -1)
14555 scfdie();
14556
14557 scf_value_destroy(val);
14558 scf_iter_destroy(iter);
14559 }
14560
14561 static int
lscf_setpropvalue(const char * pgname,const char * type,const char * arg,int isadd,int isnotfoundok)14562 lscf_setpropvalue(const char *pgname, const char *type,
14563 const char *arg, int isadd, int isnotfoundok)
14564 {
14565 scf_type_t ty;
14566 scf_propertygroup_t *pg;
14567 scf_property_t *prop;
14568 int ret, result = 0;
14569 scf_transaction_t *tx;
14570 scf_transaction_entry_t *e;
14571 scf_value_t *v;
14572 string_list_t *sp;
14573 char *propname;
14574 uu_list_t *values;
14575 uu_list_walk_t *walk;
14576 void *cookie = NULL;
14577 char *pattern = NULL;
14578
14579 lscf_prep_hndl();
14580
14581 if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14582 uu_die(gettext("Could not create property list: %s\n"),
14583 uu_strerror(uu_error()));
14584
14585 if (!isadd)
14586 pattern = safe_strdup(arg);
14587
14588 if ((e = scf_entry_create(g_hndl)) == NULL ||
14589 (pg = scf_pg_create(g_hndl)) == NULL ||
14590 (prop = scf_property_create(g_hndl)) == NULL ||
14591 (tx = scf_transaction_create(g_hndl)) == NULL)
14592 scfdie();
14593
14594 if (cur_snap != NULL) {
14595 semerr(emsg_cant_modify_snapshots);
14596 goto fail;
14597 }
14598
14599 if (cur_inst == NULL && cur_svc == NULL) {
14600 semerr(emsg_entity_not_selected);
14601 goto fail;
14602 }
14603
14604 propname = strchr(pgname, '/');
14605 if (propname == NULL) {
14606 semerr(gettext("Property names must contain a `/'.\n"));
14607 goto fail;
14608 }
14609
14610 *propname = '\0';
14611 ++propname;
14612
14613 if (type != NULL) {
14614 ty = string_to_type(type);
14615 if (ty == SCF_TYPE_INVALID) {
14616 semerr(gettext("Unknown type \"%s\".\n"), type);
14617 goto fail;
14618 }
14619 }
14620
14621 if (cur_inst != NULL)
14622 ret = scf_instance_get_pg(cur_inst, pgname, pg);
14623 else
14624 ret = scf_service_get_pg(cur_svc, pgname, pg);
14625 if (ret != 0) {
14626 switch (scf_error()) {
14627 case SCF_ERROR_NOT_FOUND:
14628 if (isnotfoundok) {
14629 result = 0;
14630 } else {
14631 semerr(emsg_no_such_pg, pgname);
14632 result = -1;
14633 }
14634 goto out;
14635
14636 case SCF_ERROR_INVALID_ARGUMENT:
14637 semerr(emsg_invalid_pg_name, pgname);
14638 goto fail;
14639
14640 default:
14641 scfdie();
14642 }
14643 }
14644
14645 do {
14646 if (scf_pg_update(pg) == -1)
14647 scfdie();
14648 if (scf_transaction_start(tx, pg) != 0) {
14649 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14650 scfdie();
14651
14652 semerr(emsg_permission_denied);
14653 goto fail;
14654 }
14655
14656 ret = scf_pg_get_property(pg, propname, prop);
14657 if (ret == 0) {
14658 scf_type_t ptype;
14659 char *pat = pattern;
14660
14661 if (scf_property_type(prop, &ptype) != 0)
14662 scfdie();
14663
14664 if (isadd) {
14665 if (type != NULL && ptype != ty) {
14666 semerr(gettext("Property \"%s\" is not "
14667 "of type \"%s\".\n"), propname,
14668 type);
14669 goto fail;
14670 }
14671
14672 pat = NULL;
14673 } else {
14674 size_t len = strlen(pat);
14675 if (len > 0 && pat[len - 1] == '\"')
14676 pat[len - 1] = '\0';
14677 if (len > 0 && pat[0] == '\"')
14678 pat++;
14679 }
14680
14681 ty = ptype;
14682
14683 get_prop_values(prop, values, pat);
14684
14685 if (isadd)
14686 add_string(values, arg);
14687
14688 if (scf_transaction_property_change(tx, e,
14689 propname, ty) == -1)
14690 scfdie();
14691 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14692 if (isadd) {
14693 if (type == NULL) {
14694 semerr(gettext("Type required "
14695 "for new properties.\n"));
14696 goto fail;
14697 }
14698
14699 add_string(values, arg);
14700
14701 if (scf_transaction_property_new(tx, e,
14702 propname, ty) == -1)
14703 scfdie();
14704 } else if (isnotfoundok) {
14705 result = 0;
14706 goto out;
14707 } else {
14708 semerr(gettext("No such property %s/%s.\n"),
14709 pgname, propname);
14710 result = -1;
14711 goto out;
14712 }
14713 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14714 semerr(emsg_invalid_prop_name, propname);
14715 goto fail;
14716 } else {
14717 scfdie();
14718 }
14719
14720 walk = uu_list_walk_start(values, UU_DEFAULT);
14721 if (walk == NULL)
14722 uu_die(gettext("Could not walk property list.\n"));
14723
14724 for (sp = uu_list_walk_next(walk); sp != NULL;
14725 sp = uu_list_walk_next(walk)) {
14726 v = string_to_value(sp->str, ty, 0);
14727
14728 if (v == NULL) {
14729 scf_entry_destroy_children(e);
14730 goto fail;
14731 }
14732 ret = scf_entry_add_value(e, v);
14733 assert(ret == 0);
14734 }
14735 uu_list_walk_end(walk);
14736
14737 result = scf_transaction_commit(tx);
14738
14739 scf_transaction_reset(tx);
14740 scf_entry_destroy_children(e);
14741 } while (result == 0);
14742
14743 if (result < 0) {
14744 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14745 scfdie();
14746
14747 semerr(emsg_permission_denied);
14748 goto fail;
14749 }
14750
14751 result = 0;
14752
14753 private_refresh();
14754
14755 out:
14756 scf_transaction_destroy(tx);
14757 scf_entry_destroy(e);
14758 scf_pg_destroy(pg);
14759 scf_property_destroy(prop);
14760 free(pattern);
14761
14762 while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14763 free(sp->str);
14764 free(sp);
14765 }
14766
14767 uu_list_destroy(values);
14768
14769 return (result);
14770
14771 fail:
14772 result = -1;
14773 goto out;
14774 }
14775
14776 int
lscf_addpropvalue(const char * pgname,const char * type,const char * value)14777 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14778 {
14779 return (lscf_setpropvalue(pgname, type, value, 1, 0));
14780 }
14781
14782 int
lscf_delpropvalue(const char * pgname,const char * pattern,int isnotfoundok)14783 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14784 {
14785 return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14786 }
14787
14788 /*
14789 * Look for a standard start method, first in the instance (if any),
14790 * then the service.
14791 */
14792 static const char *
start_method_name(int * in_instance)14793 start_method_name(int *in_instance)
14794 {
14795 scf_propertygroup_t *pg;
14796 char **p;
14797 int ret;
14798 scf_instance_t *inst = cur_inst;
14799
14800 if ((pg = scf_pg_create(g_hndl)) == NULL)
14801 scfdie();
14802
14803 again:
14804 for (p = start_method_names; *p != NULL; p++) {
14805 if (inst != NULL)
14806 ret = scf_instance_get_pg(inst, *p, pg);
14807 else
14808 ret = scf_service_get_pg(cur_svc, *p, pg);
14809
14810 if (ret == 0) {
14811 size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14812 char *buf = safe_malloc(bufsz);
14813
14814 if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14815 free(buf);
14816 continue;
14817 }
14818 if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14819 free(buf);
14820 continue;
14821 }
14822
14823 free(buf);
14824 *in_instance = (inst != NULL);
14825 scf_pg_destroy(pg);
14826 return (*p);
14827 }
14828
14829 if (scf_error() == SCF_ERROR_NOT_FOUND)
14830 continue;
14831
14832 scfdie();
14833 }
14834
14835 if (inst != NULL) {
14836 inst = NULL;
14837 goto again;
14838 }
14839
14840 scf_pg_destroy(pg);
14841 return (NULL);
14842 }
14843
14844 static int
addpg(const char * name,const char * type)14845 addpg(const char *name, const char *type)
14846 {
14847 scf_propertygroup_t *pg;
14848 int ret;
14849
14850 pg = scf_pg_create(g_hndl);
14851 if (pg == NULL)
14852 scfdie();
14853
14854 if (cur_inst != NULL)
14855 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14856 else
14857 ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14858
14859 if (ret != 0) {
14860 switch (scf_error()) {
14861 case SCF_ERROR_EXISTS:
14862 ret = 0;
14863 break;
14864
14865 case SCF_ERROR_PERMISSION_DENIED:
14866 semerr(emsg_permission_denied);
14867 break;
14868
14869 default:
14870 scfdie();
14871 }
14872 }
14873
14874 scf_pg_destroy(pg);
14875 return (ret);
14876 }
14877
14878 int
lscf_setenv(uu_list_t * args,int isunset)14879 lscf_setenv(uu_list_t *args, int isunset)
14880 {
14881 int ret = 0;
14882 size_t i;
14883 int argc;
14884 char **argv = NULL;
14885 string_list_t *slp;
14886 char *pattern;
14887 char *prop;
14888 int do_service = 0;
14889 int do_instance = 0;
14890 const char *method = NULL;
14891 const char *name = NULL;
14892 const char *value = NULL;
14893 scf_instance_t *saved_cur_inst = cur_inst;
14894
14895 lscf_prep_hndl();
14896
14897 argc = uu_list_numnodes(args);
14898 if (argc < 1)
14899 goto usage;
14900
14901 argv = calloc(argc + 1, sizeof (char *));
14902 if (argv == NULL)
14903 uu_die(gettext("Out of memory.\n"));
14904
14905 for (slp = uu_list_first(args), i = 0;
14906 slp != NULL;
14907 slp = uu_list_next(args, slp), ++i)
14908 argv[i] = slp->str;
14909
14910 argv[i] = NULL;
14911
14912 opterr = 0;
14913 optind = 0;
14914 for (;;) {
14915 ret = getopt(argc, argv, "sim:");
14916 if (ret == -1)
14917 break;
14918
14919 switch (ret) {
14920 case 's':
14921 do_service = 1;
14922 cur_inst = NULL;
14923 break;
14924
14925 case 'i':
14926 do_instance = 1;
14927 break;
14928
14929 case 'm':
14930 method = optarg;
14931 break;
14932
14933 case '?':
14934 goto usage;
14935
14936 default:
14937 bad_error("getopt", ret);
14938 }
14939 }
14940
14941 argc -= optind;
14942 if ((do_service && do_instance) ||
14943 (isunset && argc != 1) ||
14944 (!isunset && argc != 2))
14945 goto usage;
14946
14947 name = argv[optind];
14948 if (!isunset)
14949 value = argv[optind + 1];
14950
14951 if (cur_snap != NULL) {
14952 semerr(emsg_cant_modify_snapshots);
14953 ret = -1;
14954 goto out;
14955 }
14956
14957 if (cur_inst == NULL && cur_svc == NULL) {
14958 semerr(emsg_entity_not_selected);
14959 ret = -1;
14960 goto out;
14961 }
14962
14963 if (do_instance && cur_inst == NULL) {
14964 semerr(gettext("No instance is selected.\n"));
14965 ret = -1;
14966 goto out;
14967 }
14968
14969 if (do_service && cur_svc == NULL) {
14970 semerr(gettext("No service is selected.\n"));
14971 ret = -1;
14972 goto out;
14973 }
14974
14975 if (method == NULL) {
14976 if (do_instance || do_service) {
14977 method = "method_context";
14978 if (!isunset) {
14979 ret = addpg("method_context",
14980 SCF_GROUP_FRAMEWORK);
14981 if (ret != 0)
14982 goto out;
14983 }
14984 } else {
14985 int in_instance;
14986 method = start_method_name(&in_instance);
14987 if (method == NULL) {
14988 semerr(gettext(
14989 "Couldn't find start method; please "
14990 "specify a method with '-m'.\n"));
14991 ret = -1;
14992 goto out;
14993 }
14994 if (!in_instance)
14995 cur_inst = NULL;
14996 }
14997 } else {
14998 scf_propertygroup_t *pg;
14999 size_t bufsz;
15000 char *buf;
15001 int ret;
15002
15003 if ((pg = scf_pg_create(g_hndl)) == NULL)
15004 scfdie();
15005
15006 if (cur_inst != NULL)
15007 ret = scf_instance_get_pg(cur_inst, method, pg);
15008 else
15009 ret = scf_service_get_pg(cur_svc, method, pg);
15010
15011 if (ret != 0) {
15012 scf_pg_destroy(pg);
15013 switch (scf_error()) {
15014 case SCF_ERROR_NOT_FOUND:
15015 semerr(gettext("Couldn't find the method "
15016 "\"%s\".\n"), method);
15017 goto out;
15018
15019 case SCF_ERROR_INVALID_ARGUMENT:
15020 semerr(gettext("Invalid method name \"%s\".\n"),
15021 method);
15022 goto out;
15023
15024 default:
15025 scfdie();
15026 }
15027 }
15028
15029 bufsz = strlen(SCF_GROUP_METHOD) + 1;
15030 buf = safe_malloc(bufsz);
15031
15032 if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
15033 strcmp(buf, SCF_GROUP_METHOD) != 0) {
15034 semerr(gettext("Property group \"%s\" is not of type "
15035 "\"method\".\n"), method);
15036 ret = -1;
15037 free(buf);
15038 scf_pg_destroy(pg);
15039 goto out;
15040 }
15041
15042 free(buf);
15043 scf_pg_destroy(pg);
15044 }
15045
15046 prop = uu_msprintf("%s/environment", method);
15047 pattern = uu_msprintf("%s=*", name);
15048
15049 if (prop == NULL || pattern == NULL)
15050 uu_die(gettext("Out of memory.\n"));
15051
15052 ret = lscf_delpropvalue(prop, pattern, !isunset);
15053
15054 if (ret == 0 && !isunset) {
15055 uu_free(pattern);
15056 uu_free(prop);
15057 prop = uu_msprintf("%s/environment", method);
15058 pattern = uu_msprintf("%s=%s", name, value);
15059 if (prop == NULL || pattern == NULL)
15060 uu_die(gettext("Out of memory.\n"));
15061 ret = lscf_addpropvalue(prop, "astring:", pattern);
15062 }
15063 uu_free(pattern);
15064 uu_free(prop);
15065
15066 out:
15067 cur_inst = saved_cur_inst;
15068
15069 free(argv);
15070 return (ret);
15071 usage:
15072 ret = -2;
15073 goto out;
15074 }
15075
15076 /*
15077 * Snapshot commands
15078 */
15079
15080 void
lscf_listsnap()15081 lscf_listsnap()
15082 {
15083 scf_snapshot_t *snap;
15084 scf_iter_t *iter;
15085 char *nb;
15086 int r;
15087
15088 lscf_prep_hndl();
15089
15090 if (cur_inst == NULL) {
15091 semerr(gettext("Instance not selected.\n"));
15092 return;
15093 }
15094
15095 if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15096 (iter = scf_iter_create(g_hndl)) == NULL)
15097 scfdie();
15098
15099 if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
15100 scfdie();
15101
15102 nb = safe_malloc(max_scf_name_len + 1);
15103
15104 while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
15105 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
15106 scfdie();
15107
15108 (void) puts(nb);
15109 }
15110 if (r < 0)
15111 scfdie();
15112
15113 free(nb);
15114 scf_iter_destroy(iter);
15115 scf_snapshot_destroy(snap);
15116 }
15117
15118 void
lscf_selectsnap(const char * name)15119 lscf_selectsnap(const char *name)
15120 {
15121 scf_snapshot_t *snap;
15122 scf_snaplevel_t *level;
15123
15124 lscf_prep_hndl();
15125
15126 if (cur_inst == NULL) {
15127 semerr(gettext("Instance not selected.\n"));
15128 return;
15129 }
15130
15131 if (cur_snap != NULL) {
15132 if (name != NULL) {
15133 char *cur_snap_name;
15134 boolean_t nochange;
15135
15136 cur_snap_name = safe_malloc(max_scf_name_len + 1);
15137
15138 if (scf_snapshot_get_name(cur_snap, cur_snap_name,
15139 max_scf_name_len + 1) < 0)
15140 scfdie();
15141
15142 nochange = strcmp(name, cur_snap_name) == 0;
15143
15144 free(cur_snap_name);
15145
15146 if (nochange)
15147 return;
15148 }
15149
15150 unselect_cursnap();
15151 }
15152
15153 if (name == NULL)
15154 return;
15155
15156 if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15157 (level = scf_snaplevel_create(g_hndl)) == NULL)
15158 scfdie();
15159
15160 if (scf_instance_get_snapshot(cur_inst, name, snap) !=
15161 SCF_SUCCESS) {
15162 switch (scf_error()) {
15163 case SCF_ERROR_INVALID_ARGUMENT:
15164 semerr(gettext("Invalid name \"%s\".\n"), name);
15165 break;
15166
15167 case SCF_ERROR_NOT_FOUND:
15168 semerr(gettext("No such snapshot \"%s\".\n"), name);
15169 break;
15170
15171 default:
15172 scfdie();
15173 }
15174
15175 scf_snaplevel_destroy(level);
15176 scf_snapshot_destroy(snap);
15177 return;
15178 }
15179
15180 /* Load the snaplevels into our list. */
15181 cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
15182 if (cur_levels == NULL)
15183 uu_die(gettext("Could not create list: %s\n"),
15184 uu_strerror(uu_error()));
15185
15186 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15187 if (scf_error() != SCF_ERROR_NOT_FOUND)
15188 scfdie();
15189
15190 semerr(gettext("Snapshot has no snaplevels.\n"));
15191
15192 scf_snaplevel_destroy(level);
15193 scf_snapshot_destroy(snap);
15194 return;
15195 }
15196
15197 cur_snap = snap;
15198
15199 for (;;) {
15200 cur_elt = safe_malloc(sizeof (*cur_elt));
15201 uu_list_node_init(cur_elt, &cur_elt->list_node,
15202 snaplevel_pool);
15203 cur_elt->sl = level;
15204 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
15205 uu_die(gettext("libuutil error: %s\n"),
15206 uu_strerror(uu_error()));
15207
15208 level = scf_snaplevel_create(g_hndl);
15209 if (level == NULL)
15210 scfdie();
15211
15212 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
15213 level) != SCF_SUCCESS) {
15214 if (scf_error() != SCF_ERROR_NOT_FOUND)
15215 scfdie();
15216
15217 scf_snaplevel_destroy(level);
15218 break;
15219 }
15220 }
15221
15222 cur_elt = uu_list_last(cur_levels);
15223 cur_level = cur_elt->sl;
15224 }
15225
15226 /*
15227 * Copies the properties & values in src to dst. Assumes src won't change.
15228 * Returns -1 if permission is denied, -2 if another transaction interrupts,
15229 * and 0 on success.
15230 *
15231 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
15232 * property, if it is copied and has type boolean. (See comment in
15233 * lscf_revert()).
15234 */
15235 static int
pg_copy(const scf_propertygroup_t * src,scf_propertygroup_t * dst,uint8_t enabled)15236 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
15237 uint8_t enabled)
15238 {
15239 scf_transaction_t *tx;
15240 scf_iter_t *iter, *viter;
15241 scf_property_t *prop;
15242 scf_value_t *v;
15243 char *nbuf;
15244 int r;
15245
15246 tx = scf_transaction_create(g_hndl);
15247 if (tx == NULL)
15248 scfdie();
15249
15250 if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
15251 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15252 scfdie();
15253
15254 scf_transaction_destroy(tx);
15255
15256 return (-1);
15257 }
15258
15259 if ((iter = scf_iter_create(g_hndl)) == NULL ||
15260 (prop = scf_property_create(g_hndl)) == NULL ||
15261 (viter = scf_iter_create(g_hndl)) == NULL)
15262 scfdie();
15263
15264 nbuf = safe_malloc(max_scf_name_len + 1);
15265
15266 if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
15267 scfdie();
15268
15269 for (;;) {
15270 scf_transaction_entry_t *e;
15271 scf_type_t ty;
15272
15273 r = scf_iter_next_property(iter, prop);
15274 if (r == -1)
15275 scfdie();
15276 if (r == 0)
15277 break;
15278
15279 e = scf_entry_create(g_hndl);
15280 if (e == NULL)
15281 scfdie();
15282
15283 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
15284 scfdie();
15285
15286 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
15287 scfdie();
15288
15289 if (scf_transaction_property_new(tx, e, nbuf,
15290 ty) != SCF_SUCCESS)
15291 scfdie();
15292
15293 if ((enabled == 0 || enabled == 1) &&
15294 strcmp(nbuf, scf_property_enabled) == 0 &&
15295 ty == SCF_TYPE_BOOLEAN) {
15296 v = scf_value_create(g_hndl);
15297 if (v == NULL)
15298 scfdie();
15299
15300 scf_value_set_boolean(v, enabled);
15301
15302 if (scf_entry_add_value(e, v) != 0)
15303 scfdie();
15304 } else {
15305 if (scf_iter_property_values(viter, prop) != 0)
15306 scfdie();
15307
15308 for (;;) {
15309 v = scf_value_create(g_hndl);
15310 if (v == NULL)
15311 scfdie();
15312
15313 r = scf_iter_next_value(viter, v);
15314 if (r == -1)
15315 scfdie();
15316 if (r == 0) {
15317 scf_value_destroy(v);
15318 break;
15319 }
15320
15321 if (scf_entry_add_value(e, v) != SCF_SUCCESS)
15322 scfdie();
15323 }
15324 }
15325 }
15326
15327 free(nbuf);
15328 scf_iter_destroy(viter);
15329 scf_property_destroy(prop);
15330 scf_iter_destroy(iter);
15331
15332 r = scf_transaction_commit(tx);
15333 if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
15334 scfdie();
15335
15336 scf_transaction_destroy_children(tx);
15337 scf_transaction_destroy(tx);
15338
15339 switch (r) {
15340 case 1: return (0);
15341 case 0: return (-2);
15342 case -1: return (-1);
15343
15344 default:
15345 abort();
15346 }
15347
15348 /* NOTREACHED */
15349 }
15350
15351 void
lscf_revert(const char * snapname)15352 lscf_revert(const char *snapname)
15353 {
15354 scf_snapshot_t *snap, *prev;
15355 scf_snaplevel_t *level, *nlevel;
15356 scf_iter_t *iter;
15357 scf_propertygroup_t *pg, *npg;
15358 scf_property_t *prop;
15359 scf_value_t *val;
15360 char *nbuf, *tbuf;
15361 uint8_t enabled;
15362
15363 lscf_prep_hndl();
15364
15365 if (cur_inst == NULL) {
15366 semerr(gettext("Instance not selected.\n"));
15367 return;
15368 }
15369
15370 if (snapname != NULL) {
15371 snap = scf_snapshot_create(g_hndl);
15372 if (snap == NULL)
15373 scfdie();
15374
15375 if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
15376 SCF_SUCCESS) {
15377 switch (scf_error()) {
15378 case SCF_ERROR_INVALID_ARGUMENT:
15379 semerr(gettext("Invalid snapshot name "
15380 "\"%s\".\n"), snapname);
15381 break;
15382
15383 case SCF_ERROR_NOT_FOUND:
15384 semerr(gettext("No such snapshot.\n"));
15385 break;
15386
15387 default:
15388 scfdie();
15389 }
15390
15391 scf_snapshot_destroy(snap);
15392 return;
15393 }
15394 } else {
15395 if (cur_snap != NULL) {
15396 snap = cur_snap;
15397 } else {
15398 semerr(gettext("No snapshot selected.\n"));
15399 return;
15400 }
15401 }
15402
15403 if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
15404 (level = scf_snaplevel_create(g_hndl)) == NULL ||
15405 (iter = scf_iter_create(g_hndl)) == NULL ||
15406 (pg = scf_pg_create(g_hndl)) == NULL ||
15407 (npg = scf_pg_create(g_hndl)) == NULL ||
15408 (prop = scf_property_create(g_hndl)) == NULL ||
15409 (val = scf_value_create(g_hndl)) == NULL)
15410 scfdie();
15411
15412 nbuf = safe_malloc(max_scf_name_len + 1);
15413 tbuf = safe_malloc(max_scf_pg_type_len + 1);
15414
15415 /* Take the "previous" snapshot before we blow away the properties. */
15416 if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
15417 if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
15418 scfdie();
15419 } else {
15420 if (scf_error() != SCF_ERROR_NOT_FOUND)
15421 scfdie();
15422
15423 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
15424 scfdie();
15425 }
15426
15427 /* Save general/enabled, since we're probably going to replace it. */
15428 enabled = 2;
15429 if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
15430 scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
15431 scf_property_get_value(prop, val) == 0)
15432 (void) scf_value_get_boolean(val, &enabled);
15433
15434 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15435 if (scf_error() != SCF_ERROR_NOT_FOUND)
15436 scfdie();
15437
15438 goto out;
15439 }
15440
15441 for (;;) {
15442 boolean_t isinst;
15443 uint32_t flags;
15444 int r;
15445
15446 /* Clear the properties from the corresponding entity. */
15447 isinst = snaplevel_is_instance(level);
15448
15449 if (!isinst)
15450 r = scf_iter_service_pgs(iter, cur_svc);
15451 else
15452 r = scf_iter_instance_pgs(iter, cur_inst);
15453 if (r != SCF_SUCCESS)
15454 scfdie();
15455
15456 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15457 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15458 scfdie();
15459
15460 /* Skip nonpersistent pgs. */
15461 if (flags & SCF_PG_FLAG_NONPERSISTENT)
15462 continue;
15463
15464 if (scf_pg_delete(pg) != SCF_SUCCESS) {
15465 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15466 scfdie();
15467
15468 semerr(emsg_permission_denied);
15469 goto out;
15470 }
15471 }
15472 if (r == -1)
15473 scfdie();
15474
15475 /* Copy the properties to the corresponding entity. */
15476 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
15477 scfdie();
15478
15479 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15480 if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
15481 scfdie();
15482
15483 if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
15484 0)
15485 scfdie();
15486
15487 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15488 scfdie();
15489
15490 if (!isinst)
15491 r = scf_service_add_pg(cur_svc, nbuf, tbuf,
15492 flags, npg);
15493 else
15494 r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
15495 flags, npg);
15496 if (r != SCF_SUCCESS) {
15497 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15498 scfdie();
15499
15500 semerr(emsg_permission_denied);
15501 goto out;
15502 }
15503
15504 if ((enabled == 0 || enabled == 1) &&
15505 strcmp(nbuf, scf_pg_general) == 0)
15506 r = pg_copy(pg, npg, enabled);
15507 else
15508 r = pg_copy(pg, npg, 2);
15509
15510 switch (r) {
15511 case 0:
15512 break;
15513
15514 case -1:
15515 semerr(emsg_permission_denied);
15516 goto out;
15517
15518 case -2:
15519 semerr(gettext(
15520 "Interrupted by another change.\n"));
15521 goto out;
15522
15523 default:
15524 abort();
15525 }
15526 }
15527 if (r == -1)
15528 scfdie();
15529
15530 /* Get next level. */
15531 nlevel = scf_snaplevel_create(g_hndl);
15532 if (nlevel == NULL)
15533 scfdie();
15534
15535 if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
15536 SCF_SUCCESS) {
15537 if (scf_error() != SCF_ERROR_NOT_FOUND)
15538 scfdie();
15539
15540 scf_snaplevel_destroy(nlevel);
15541 break;
15542 }
15543
15544 scf_snaplevel_destroy(level);
15545 level = nlevel;
15546 }
15547
15548 if (snapname == NULL) {
15549 lscf_selectsnap(NULL);
15550 snap = NULL; /* cur_snap has been destroyed */
15551 }
15552
15553 out:
15554 free(tbuf);
15555 free(nbuf);
15556 scf_value_destroy(val);
15557 scf_property_destroy(prop);
15558 scf_pg_destroy(npg);
15559 scf_pg_destroy(pg);
15560 scf_iter_destroy(iter);
15561 scf_snaplevel_destroy(level);
15562 scf_snapshot_destroy(prev);
15563 if (snap != cur_snap)
15564 scf_snapshot_destroy(snap);
15565 }
15566
15567 void
lscf_refresh(void)15568 lscf_refresh(void)
15569 {
15570 ssize_t fmrilen;
15571 size_t bufsz;
15572 char *fmribuf;
15573 int r;
15574
15575 lscf_prep_hndl();
15576
15577 if (cur_inst == NULL) {
15578 semerr(gettext("Instance not selected.\n"));
15579 return;
15580 }
15581
15582 bufsz = max_scf_fmri_len + 1;
15583 fmribuf = safe_malloc(bufsz);
15584 fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15585 if (fmrilen < 0) {
15586 free(fmribuf);
15587 if (scf_error() != SCF_ERROR_DELETED)
15588 scfdie();
15589 scf_instance_destroy(cur_inst);
15590 cur_inst = NULL;
15591 warn(emsg_deleted);
15592 return;
15593 }
15594 assert(fmrilen < bufsz);
15595
15596 r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15597 switch (r) {
15598 case 0:
15599 break;
15600
15601 case ECONNABORTED:
15602 warn(gettext("Could not refresh %s "
15603 "(repository connection broken).\n"), fmribuf);
15604 break;
15605
15606 case ECANCELED:
15607 warn(emsg_deleted);
15608 break;
15609
15610 case EPERM:
15611 warn(gettext("Could not refresh %s "
15612 "(permission denied).\n"), fmribuf);
15613 break;
15614
15615 case ENOSPC:
15616 warn(gettext("Could not refresh %s "
15617 "(repository server out of resources).\n"),
15618 fmribuf);
15619 break;
15620
15621 case EACCES:
15622 default:
15623 bad_error("refresh_entity", scf_error());
15624 }
15625
15626 free(fmribuf);
15627 }
15628
15629 /*
15630 * describe [-v] [-t] [pg/prop]
15631 */
15632 int
lscf_describe(uu_list_t * args,int hasargs)15633 lscf_describe(uu_list_t *args, int hasargs)
15634 {
15635 int ret = 0;
15636 size_t i;
15637 int argc;
15638 char **argv = NULL;
15639 string_list_t *slp;
15640 int do_verbose = 0;
15641 int do_templates = 0;
15642 char *pattern = NULL;
15643
15644 lscf_prep_hndl();
15645
15646 if (hasargs != 0) {
15647 argc = uu_list_numnodes(args);
15648 if (argc < 1)
15649 goto usage;
15650
15651 argv = calloc(argc + 1, sizeof (char *));
15652 if (argv == NULL)
15653 uu_die(gettext("Out of memory.\n"));
15654
15655 for (slp = uu_list_first(args), i = 0;
15656 slp != NULL;
15657 slp = uu_list_next(args, slp), ++i)
15658 argv[i] = slp->str;
15659
15660 argv[i] = NULL;
15661
15662 /*
15663 * We start optind = 0 because our list of arguments
15664 * starts at argv[0]
15665 */
15666 optind = 0;
15667 opterr = 0;
15668 for (;;) {
15669 ret = getopt(argc, argv, "vt");
15670 if (ret == -1)
15671 break;
15672
15673 switch (ret) {
15674 case 'v':
15675 do_verbose = 1;
15676 break;
15677
15678 case 't':
15679 do_templates = 1;
15680 break;
15681
15682 case '?':
15683 goto usage;
15684
15685 default:
15686 bad_error("getopt", ret);
15687 }
15688 }
15689
15690 pattern = argv[optind];
15691 }
15692
15693 if (cur_inst == NULL && cur_svc == NULL) {
15694 semerr(emsg_entity_not_selected);
15695 ret = -1;
15696 goto out;
15697 }
15698
15699 /*
15700 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15701 * output if their last parameter is set to 2. Less information is
15702 * produced if the parameter is set to 1.
15703 */
15704 if (pattern == NULL) {
15705 if (do_verbose == 1)
15706 list_entity_tmpl(2);
15707 else
15708 list_entity_tmpl(1);
15709 }
15710
15711 if (do_templates == 0) {
15712 if (do_verbose == 1)
15713 listprop(pattern, 0, 2);
15714 else
15715 listprop(pattern, 0, 1);
15716 } else {
15717 if (do_verbose == 1)
15718 listtmpl(pattern, 2);
15719 else
15720 listtmpl(pattern, 1);
15721 }
15722
15723 ret = 0;
15724 out:
15725 if (argv != NULL)
15726 free(argv);
15727 return (ret);
15728 usage:
15729 ret = -2;
15730 goto out;
15731 }
15732
15733 #define PARAM_ACTIVE ((const char *) "active")
15734 #define PARAM_INACTIVE ((const char *) "inactive")
15735 #define PARAM_SMTP_TO ((const char *) "to")
15736
15737 /*
15738 * tokenize()
15739 * Breaks down the string according to the tokens passed.
15740 * Caller is responsible for freeing array of pointers returned.
15741 * Returns NULL on failure
15742 */
15743 char **
tokenize(char * str,const char * sep)15744 tokenize(char *str, const char *sep)
15745 {
15746 char *token, *lasts;
15747 char **buf;
15748 int n = 0; /* number of elements */
15749 int size = 8; /* size of the array (initial) */
15750
15751 buf = safe_malloc(size * sizeof (char *));
15752
15753 for (token = strtok_r(str, sep, &lasts); token != NULL;
15754 token = strtok_r(NULL, sep, &lasts), ++n) {
15755 if (n + 1 >= size) {
15756 size *= 2;
15757 if ((buf = realloc(buf, size * sizeof (char *))) ==
15758 NULL) {
15759 uu_die(gettext("Out of memory"));
15760 }
15761 }
15762 buf[n] = token;
15763 }
15764 /* NULL terminate the pointer array */
15765 buf[n] = NULL;
15766
15767 return (buf);
15768 }
15769
15770 int32_t
check_tokens(char ** p)15771 check_tokens(char **p)
15772 {
15773 int32_t smf = 0;
15774 int32_t fma = 0;
15775
15776 while (*p) {
15777 int32_t t = string_to_tset(*p);
15778
15779 if (t == 0) {
15780 if (is_fma_token(*p) == 0)
15781 return (INVALID_TOKENS);
15782 fma = 1; /* this token is an fma event */
15783 } else {
15784 smf |= t;
15785 }
15786
15787 if (smf != 0 && fma == 1)
15788 return (MIXED_TOKENS);
15789 ++p;
15790 }
15791
15792 if (smf > 0)
15793 return (smf);
15794 else if (fma == 1)
15795 return (FMA_TOKENS);
15796
15797 return (INVALID_TOKENS);
15798 }
15799
15800 static int
get_selection_str(char * fmri,size_t sz)15801 get_selection_str(char *fmri, size_t sz)
15802 {
15803 if (g_hndl == NULL) {
15804 semerr(emsg_entity_not_selected);
15805 return (-1);
15806 } else if (cur_level != NULL) {
15807 semerr(emsg_invalid_for_snapshot);
15808 return (-1);
15809 } else {
15810 lscf_get_selection_str(fmri, sz);
15811 }
15812
15813 return (0);
15814 }
15815
15816 void
lscf_delnotify(const char * set,int global)15817 lscf_delnotify(const char *set, int global)
15818 {
15819 char *str = strdup(set);
15820 char **pgs;
15821 char **p;
15822 int32_t tset;
15823 char *fmri = NULL;
15824
15825 if (str == NULL)
15826 uu_die(gettext("Out of memory.\n"));
15827
15828 pgs = tokenize(str, ",");
15829
15830 if ((tset = check_tokens(pgs)) > 0) {
15831 size_t sz = max_scf_fmri_len + 1;
15832
15833 fmri = safe_malloc(sz);
15834 if (global) {
15835 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15836 } else if (get_selection_str(fmri, sz) != 0) {
15837 goto out;
15838 }
15839
15840 if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri,
15841 tset) != SCF_SUCCESS) {
15842 uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15843 scf_strerror(scf_error()));
15844 }
15845 } else if (tset == FMA_TOKENS) {
15846 if (global) {
15847 semerr(gettext("Can't use option '-g' with FMA event "
15848 "definitions\n"));
15849 goto out;
15850 }
15851
15852 for (p = pgs; *p; ++p) {
15853 if (smf_notify_del_params(de_tag(*p), NULL, 0) !=
15854 SCF_SUCCESS) {
15855 uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
15856 scf_strerror(scf_error()));
15857 goto out;
15858 }
15859 }
15860 } else if (tset == MIXED_TOKENS) {
15861 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15862 goto out;
15863 } else {
15864 uu_die(gettext("Invalid input.\n"));
15865 }
15866
15867 out:
15868 free(fmri);
15869 free(pgs);
15870 free(str);
15871 }
15872
15873 void
lscf_listnotify(const char * set,int global)15874 lscf_listnotify(const char *set, int global)
15875 {
15876 char *str = safe_strdup(set);
15877 char **pgs;
15878 char **p;
15879 int32_t tset;
15880 nvlist_t *nvl;
15881 char *fmri = NULL;
15882
15883 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
15884 uu_die(gettext("Out of memory.\n"));
15885
15886 pgs = tokenize(str, ",");
15887
15888 if ((tset = check_tokens(pgs)) > 0) {
15889 size_t sz = max_scf_fmri_len + 1;
15890
15891 fmri = safe_malloc(sz);
15892 if (global) {
15893 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15894 } else if (get_selection_str(fmri, sz) != 0) {
15895 goto out;
15896 }
15897
15898 if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
15899 SCF_SUCCESS) {
15900 if (scf_error() != SCF_ERROR_NOT_FOUND &&
15901 scf_error() != SCF_ERROR_DELETED)
15902 uu_warn(gettext(
15903 "Failed listnotify: %s\n"),
15904 scf_strerror(scf_error()));
15905 goto out;
15906 }
15907
15908 listnotify_print(nvl, NULL);
15909 } else if (tset == FMA_TOKENS) {
15910 if (global) {
15911 semerr(gettext("Can't use option '-g' with FMA event "
15912 "definitions\n"));
15913 goto out;
15914 }
15915
15916 for (p = pgs; *p; ++p) {
15917 if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
15918 SCF_SUCCESS) {
15919 /*
15920 * if the preferences have just been deleted
15921 * or does not exist, just skip.
15922 */
15923 if (scf_error() == SCF_ERROR_NOT_FOUND ||
15924 scf_error() == SCF_ERROR_DELETED)
15925 continue;
15926 uu_warn(gettext(
15927 "Failed listnotify: %s\n"),
15928 scf_strerror(scf_error()));
15929 goto out;
15930 }
15931 listnotify_print(nvl, re_tag(*p));
15932 }
15933 } else if (tset == MIXED_TOKENS) {
15934 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15935 goto out;
15936 } else {
15937 semerr(gettext("Invalid input.\n"));
15938 }
15939
15940 out:
15941 nvlist_free(nvl);
15942 free(fmri);
15943 free(pgs);
15944 free(str);
15945 }
15946
15947 static char *
strip_quotes_and_blanks(char * s)15948 strip_quotes_and_blanks(char *s)
15949 {
15950 char *start = s;
15951 char *end = strrchr(s, '\"');
15952
15953 if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
15954 start = s + 1;
15955 while (isblank(*start))
15956 start++;
15957 while (isblank(*(end - 1)) && end > start) {
15958 end--;
15959 }
15960 *end = '\0';
15961 }
15962
15963 return (start);
15964 }
15965
15966 static int
set_active(nvlist_t * mech,const char * hier_part)15967 set_active(nvlist_t *mech, const char *hier_part)
15968 {
15969 boolean_t b;
15970
15971 if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
15972 b = B_TRUE;
15973 } else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
15974 b = B_FALSE;
15975 } else {
15976 return (-1);
15977 }
15978
15979 if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
15980 uu_die(gettext("Out of memory.\n"));
15981
15982 return (0);
15983 }
15984
15985 static int
add_snmp_params(nvlist_t * mech,char * hier_part)15986 add_snmp_params(nvlist_t *mech, char *hier_part)
15987 {
15988 return (set_active(mech, hier_part));
15989 }
15990
15991 static int
add_syslog_params(nvlist_t * mech,char * hier_part)15992 add_syslog_params(nvlist_t *mech, char *hier_part)
15993 {
15994 return (set_active(mech, hier_part));
15995 }
15996
15997 /*
15998 * add_mailto_paramas()
15999 * parse the hier_part of mailto URI
16000 * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
16001 * or mailto:{[active]|inactive}
16002 */
16003 static int
add_mailto_params(nvlist_t * mech,char * hier_part)16004 add_mailto_params(nvlist_t *mech, char *hier_part)
16005 {
16006 const char *tok = "?&";
16007 char *p;
16008 char *lasts;
16009 char *param;
16010 char *val;
16011
16012 /*
16013 * If the notification parametes are in the form of
16014 *
16015 * malito:{[active]|inactive}
16016 *
16017 * we set the property accordingly and return.
16018 * Otherwise, we make the notification type active and
16019 * process the hier_part.
16020 */
16021 if (set_active(mech, hier_part) == 0)
16022 return (0);
16023 else if (set_active(mech, PARAM_ACTIVE) != 0)
16024 return (-1);
16025
16026 if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) {
16027 /*
16028 * sanity check: we only get here if hier_part = "", but
16029 * that's handled by set_active
16030 */
16031 uu_die("strtok_r");
16032 }
16033
16034 if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0)
16035 uu_die(gettext("Out of memory.\n"));
16036
16037 while ((p = strtok_r(NULL, tok, &lasts)) != NULL)
16038 if ((param = strtok_r(p, "=", &val)) != NULL)
16039 if (nvlist_add_string(mech, param, val) != 0)
16040 uu_die(gettext("Out of memory.\n"));
16041
16042 return (0);
16043 }
16044
16045 static int
uri_split(char * uri,char ** scheme,char ** hier_part)16046 uri_split(char *uri, char **scheme, char **hier_part)
16047 {
16048 int r = -1;
16049
16050 if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
16051 *hier_part == NULL) {
16052 semerr(gettext("'%s' is not an URI\n"), uri);
16053 return (r);
16054 }
16055
16056 if ((r = check_uri_scheme(*scheme)) < 0) {
16057 semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
16058 return (r);
16059 }
16060
16061 return (r);
16062 }
16063
16064 static int
process_uri(nvlist_t * params,char * uri)16065 process_uri(nvlist_t *params, char *uri)
16066 {
16067 char *scheme;
16068 char *hier_part;
16069 nvlist_t *mech;
16070 int index;
16071 int r;
16072
16073 if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
16074 return (-1);
16075
16076 if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
16077 uu_die(gettext("Out of memory.\n"));
16078
16079 switch (index) {
16080 case 0:
16081 /* error messages displayed by called function */
16082 r = add_mailto_params(mech, hier_part);
16083 break;
16084
16085 case 1:
16086 if ((r = add_snmp_params(mech, hier_part)) != 0)
16087 semerr(gettext("Not valid parameters: '%s'\n"),
16088 hier_part);
16089 break;
16090
16091 case 2:
16092 if ((r = add_syslog_params(mech, hier_part)) != 0)
16093 semerr(gettext("Not valid parameters: '%s'\n"),
16094 hier_part);
16095 break;
16096
16097 default:
16098 r = -1;
16099 }
16100
16101 if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
16102 mech) != 0)
16103 uu_die(gettext("Out of memory.\n"));
16104
16105 nvlist_free(mech);
16106 return (r);
16107 }
16108
16109 static int
set_params(nvlist_t * params,char ** p)16110 set_params(nvlist_t *params, char **p)
16111 {
16112 char *uri;
16113
16114 if (p == NULL)
16115 /* sanity check */
16116 uu_die("set_params");
16117
16118 while (*p) {
16119 uri = strip_quotes_and_blanks(*p);
16120 if (process_uri(params, uri) != 0)
16121 return (-1);
16122
16123 ++p;
16124 }
16125
16126 return (0);
16127 }
16128
16129 static int
setnotify(const char * e,char ** p,int global)16130 setnotify(const char *e, char **p, int global)
16131 {
16132 char *str = safe_strdup(e);
16133 char **events;
16134 int32_t tset;
16135 int r = -1;
16136 nvlist_t *nvl, *params;
16137 char *fmri = NULL;
16138
16139 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
16140 nvlist_alloc(¶ms, NV_UNIQUE_NAME, 0) != 0 ||
16141 nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
16142 SCF_NOTIFY_PARAMS_VERSION) != 0)
16143 uu_die(gettext("Out of memory.\n"));
16144
16145 events = tokenize(str, ",");
16146
16147 if ((tset = check_tokens(events)) > 0) {
16148 /* SMF state transitions parameters */
16149 size_t sz = max_scf_fmri_len + 1;
16150
16151 fmri = safe_malloc(sz);
16152 if (global) {
16153 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
16154 } else if (get_selection_str(fmri, sz) != 0) {
16155 goto out;
16156 }
16157
16158 if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 ||
16159 nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0)
16160 uu_die(gettext("Out of memory.\n"));
16161
16162 if ((r = set_params(params, p)) == 0) {
16163 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS,
16164 params) != 0)
16165 uu_die(gettext("Out of memory.\n"));
16166
16167 if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
16168 nvl) != SCF_SUCCESS) {
16169 r = -1;
16170 uu_warn(gettext(
16171 "Failed smf_notify_set_params(3SCF): %s\n"),
16172 scf_strerror(scf_error()));
16173 }
16174 }
16175 } else if (tset == FMA_TOKENS) {
16176 /* FMA event parameters */
16177 if (global) {
16178 semerr(gettext("Can't use option '-g' with FMA event "
16179 "definitions\n"));
16180 goto out;
16181 }
16182
16183 if ((r = set_params(params, p)) != 0)
16184 goto out;
16185
16186 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
16187 uu_die(gettext("Out of memory.\n"));
16188
16189 while (*events) {
16190 if (smf_notify_set_params(de_tag(*events), nvl) !=
16191 SCF_SUCCESS)
16192 uu_warn(gettext(
16193 "Failed smf_notify_set_params(3SCF) for "
16194 "event %s: %s\n"), *events,
16195 scf_strerror(scf_error()));
16196 events++;
16197 }
16198 } else if (tset == MIXED_TOKENS) {
16199 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
16200 } else {
16201 /* Sanity check */
16202 uu_die(gettext("Invalid input.\n"));
16203 }
16204
16205 out:
16206 nvlist_free(nvl);
16207 nvlist_free(params);
16208 free(fmri);
16209 free(str);
16210
16211 return (r);
16212 }
16213
16214 int
lscf_setnotify(uu_list_t * args)16215 lscf_setnotify(uu_list_t *args)
16216 {
16217 int argc;
16218 char **argv = NULL;
16219 string_list_t *slp;
16220 int global;
16221 char *events;
16222 char **p;
16223 int i;
16224 int ret;
16225
16226 if ((argc = uu_list_numnodes(args)) < 2)
16227 goto usage;
16228
16229 argv = calloc(argc + 1, sizeof (char *));
16230 if (argv == NULL)
16231 uu_die(gettext("Out of memory.\n"));
16232
16233 for (slp = uu_list_first(args), i = 0;
16234 slp != NULL;
16235 slp = uu_list_next(args, slp), ++i)
16236 argv[i] = slp->str;
16237
16238 argv[i] = NULL;
16239
16240 if (strcmp(argv[0], "-g") == 0) {
16241 global = 1;
16242 events = argv[1];
16243 p = argv + 2;
16244 } else {
16245 global = 0;
16246 events = argv[0];
16247 p = argv + 1;
16248 }
16249
16250 ret = setnotify(events, p, global);
16251
16252 out:
16253 free(argv);
16254 return (ret);
16255
16256 usage:
16257 ret = -2;
16258 goto out;
16259 }
16260
16261 /*
16262 * Creates a list of instance name strings associated with a service. If
16263 * wohandcrafted flag is set, get only instances that have a last-import
16264 * snapshot, instances that were imported via svccfg.
16265 */
16266 static uu_list_t *
create_instance_list(scf_service_t * svc,int wohandcrafted)16267 create_instance_list(scf_service_t *svc, int wohandcrafted)
16268 {
16269 scf_snapshot_t *snap = NULL;
16270 scf_instance_t *inst;
16271 scf_iter_t *inst_iter;
16272 uu_list_t *instances;
16273 char *instname = NULL;
16274 int r;
16275
16276 inst_iter = scf_iter_create(g_hndl);
16277 inst = scf_instance_create(g_hndl);
16278 if (inst_iter == NULL || inst == NULL) {
16279 uu_warn(gettext("Could not create instance or iterator\n"));
16280 scfdie();
16281 }
16282
16283 if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
16284 return (instances);
16285
16286 if (scf_iter_service_instances(inst_iter, svc) != 0) {
16287 switch (scf_error()) {
16288 case SCF_ERROR_CONNECTION_BROKEN:
16289 case SCF_ERROR_DELETED:
16290 uu_list_destroy(instances);
16291 instances = NULL;
16292 goto out;
16293
16294 case SCF_ERROR_HANDLE_MISMATCH:
16295 case SCF_ERROR_NOT_BOUND:
16296 case SCF_ERROR_NOT_SET:
16297 default:
16298 bad_error("scf_iter_service_instances", scf_error());
16299 }
16300 }
16301
16302 instname = safe_malloc(max_scf_name_len + 1);
16303 while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
16304 if (r == -1) {
16305 (void) uu_warn(gettext("Unable to iterate through "
16306 "instances to create instance list : %s\n"),
16307 scf_strerror(scf_error()));
16308
16309 uu_list_destroy(instances);
16310 instances = NULL;
16311 goto out;
16312 }
16313
16314 /*
16315 * If the instance does not have a last-import snapshot
16316 * then do not add it to the list as it is a hand-crafted
16317 * instance that should not be managed.
16318 */
16319 if (wohandcrafted) {
16320 if (snap == NULL &&
16321 (snap = scf_snapshot_create(g_hndl)) == NULL) {
16322 uu_warn(gettext("Unable to create snapshot "
16323 "entity\n"));
16324 scfdie();
16325 }
16326
16327 if (scf_instance_get_snapshot(inst,
16328 snap_lastimport, snap) != 0) {
16329 switch (scf_error()) {
16330 case SCF_ERROR_NOT_FOUND :
16331 case SCF_ERROR_DELETED:
16332 continue;
16333
16334 case SCF_ERROR_CONNECTION_BROKEN:
16335 uu_list_destroy(instances);
16336 instances = NULL;
16337 goto out;
16338
16339 case SCF_ERROR_HANDLE_MISMATCH:
16340 case SCF_ERROR_NOT_BOUND:
16341 case SCF_ERROR_NOT_SET:
16342 default:
16343 bad_error("scf_iter_service_instances",
16344 scf_error());
16345 }
16346 }
16347 }
16348
16349 if (scf_instance_get_name(inst, instname,
16350 max_scf_name_len + 1) < 0) {
16351 switch (scf_error()) {
16352 case SCF_ERROR_NOT_FOUND :
16353 continue;
16354
16355 case SCF_ERROR_CONNECTION_BROKEN:
16356 case SCF_ERROR_DELETED:
16357 uu_list_destroy(instances);
16358 instances = NULL;
16359 goto out;
16360
16361 case SCF_ERROR_HANDLE_MISMATCH:
16362 case SCF_ERROR_NOT_BOUND:
16363 case SCF_ERROR_NOT_SET:
16364 default:
16365 bad_error("scf_iter_service_instances",
16366 scf_error());
16367 }
16368 }
16369
16370 add_string(instances, instname);
16371 }
16372
16373 out:
16374 if (snap)
16375 scf_snapshot_destroy(snap);
16376
16377 scf_instance_destroy(inst);
16378 scf_iter_destroy(inst_iter);
16379 free(instname);
16380 return (instances);
16381 }
16382
16383 /*
16384 * disable an instance but wait for the instance to
16385 * move out of the running state.
16386 *
16387 * Returns 0 : if the instance did not disable
16388 * Returns non-zero : if the instance disabled.
16389 *
16390 */
16391 static int
disable_instance(scf_instance_t * instance)16392 disable_instance(scf_instance_t *instance)
16393 {
16394 char *fmribuf;
16395 int enabled = 10000;
16396
16397 if (inst_is_running(instance)) {
16398 fmribuf = safe_malloc(max_scf_name_len + 1);
16399 if (scf_instance_to_fmri(instance, fmribuf,
16400 max_scf_name_len + 1) < 0) {
16401 free(fmribuf);
16402 return (0);
16403 }
16404
16405 /*
16406 * If the instance cannot be disabled then return
16407 * failure to disable and let the caller decide
16408 * if that is of importance.
16409 */
16410 if (smf_disable_instance(fmribuf, 0) != 0) {
16411 free(fmribuf);
16412 return (0);
16413 }
16414
16415 while (enabled) {
16416 if (!inst_is_running(instance))
16417 break;
16418
16419 (void) poll(NULL, 0, 5);
16420 enabled = enabled - 5;
16421 }
16422
16423 free(fmribuf);
16424 }
16425
16426 return (enabled);
16427 }
16428
16429 /*
16430 * Function to compare two service_manifest structures.
16431 */
16432 /* ARGSUSED2 */
16433 static int
service_manifest_compare(const void * left,const void * right,void * unused)16434 service_manifest_compare(const void *left, const void *right, void *unused)
16435 {
16436 service_manifest_t *l = (service_manifest_t *)left;
16437 service_manifest_t *r = (service_manifest_t *)right;
16438 int rc;
16439
16440 rc = strcmp(l->servicename, r->servicename);
16441
16442 return (rc);
16443 }
16444
16445 /*
16446 * Look for the provided service in the service to manifest
16447 * tree. If the service exists, and a manifest was provided
16448 * then add the manifest to that service. If the service
16449 * does not exist, then add the service and manifest to the
16450 * list.
16451 *
16452 * If the manifest is NULL, return the element if found. If
16453 * the service is not found return NULL.
16454 */
16455 service_manifest_t *
find_add_svc_mfst(const char * svnbuf,const char * mfst)16456 find_add_svc_mfst(const char *svnbuf, const char *mfst)
16457 {
16458 service_manifest_t elem;
16459 service_manifest_t *fnelem;
16460 uu_avl_index_t marker;
16461
16462 elem.servicename = svnbuf;
16463 fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
16464
16465 if (mfst) {
16466 if (fnelem) {
16467 add_string(fnelem->mfstlist, strdup(mfst));
16468 } else {
16469 fnelem = safe_malloc(sizeof (*fnelem));
16470 fnelem->servicename = safe_strdup(svnbuf);
16471 if ((fnelem->mfstlist =
16472 uu_list_create(string_pool, NULL, 0)) == NULL)
16473 uu_die(gettext("Could not create property "
16474 "list: %s\n"), uu_strerror(uu_error()));
16475
16476 add_string(fnelem->mfstlist, safe_strdup(mfst));
16477
16478 uu_avl_insert(service_manifest_tree, fnelem, marker);
16479 }
16480 }
16481
16482 return (fnelem);
16483 }
16484
16485 /*
16486 * Create the service to manifest avl tree.
16487 *
16488 * Walk each of the manifests currently installed in the supported
16489 * directories, /lib/svc/manifest and /var/svc/manifest. For
16490 * each of the manifests, inventory the services and add them to
16491 * the tree.
16492 *
16493 * Code that calls this function should make sure fileystem/minimal is online,
16494 * /var is available, since this function walks the /var/svc/manifest directory.
16495 */
16496 static void
create_manifest_tree(void)16497 create_manifest_tree(void)
16498 {
16499 manifest_info_t **entry;
16500 manifest_info_t **manifests;
16501 uu_list_walk_t *svcs;
16502 bundle_t *b;
16503 entity_t *mfsvc;
16504 char *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
16505 int c, status;
16506
16507 if (service_manifest_pool)
16508 return;
16509
16510 /*
16511 * Create the list pool for the service manifest list
16512 */
16513 service_manifest_pool = uu_avl_pool_create("service_manifest",
16514 sizeof (service_manifest_t),
16515 offsetof(service_manifest_t, svcmfst_node),
16516 service_manifest_compare, UU_DEFAULT);
16517 if (service_manifest_pool == NULL)
16518 uu_die(gettext("service_manifest pool creation failed: %s\n"),
16519 uu_strerror(uu_error()));
16520
16521 /*
16522 * Create the list
16523 */
16524 service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
16525 UU_DEFAULT);
16526 if (service_manifest_tree == NULL)
16527 uu_die(gettext("service_manifest tree creation failed: %s\n"),
16528 uu_strerror(uu_error()));
16529
16530 /*
16531 * Walk the manifests adding the service(s) from each manifest.
16532 *
16533 * If a service already exists add the manifest to the manifest
16534 * list for that service. This covers the case of a service that
16535 * is supported by multiple manifest files.
16536 */
16537 for (c = 0; dirs[c]; c++) {
16538 status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT);
16539 if (status < 0) {
16540 uu_warn(gettext("file tree walk of %s encountered "
16541 "error %s\n"), dirs[c], strerror(errno));
16542
16543 uu_avl_destroy(service_manifest_tree);
16544 service_manifest_tree = NULL;
16545 return;
16546 }
16547
16548 /*
16549 * If a manifest that was in the list is not found
16550 * then skip and go to the next manifest file.
16551 */
16552 if (manifests != NULL) {
16553 for (entry = manifests; *entry != NULL; entry++) {
16554 b = internal_bundle_new();
16555 if (lxml_get_bundle_file(b, (*entry)->mi_path,
16556 SVCCFG_OP_IMPORT) != 0) {
16557 internal_bundle_free(b);
16558 continue;
16559 }
16560
16561 svcs = uu_list_walk_start(b->sc_bundle_services,
16562 0);
16563 if (svcs == NULL) {
16564 internal_bundle_free(b);
16565 continue;
16566 }
16567
16568 while ((mfsvc = uu_list_walk_next(svcs)) !=
16569 NULL) {
16570 /* Add manifest to service */
16571 (void) find_add_svc_mfst(mfsvc->sc_name,
16572 (*entry)->mi_path);
16573 }
16574
16575 uu_list_walk_end(svcs);
16576 internal_bundle_free(b);
16577 }
16578
16579 free_manifest_array(manifests);
16580 }
16581 }
16582 }
16583
16584 /*
16585 * Check the manifest history file to see
16586 * if the service was ever installed from
16587 * one of the supported directories.
16588 *
16589 * Return Values :
16590 * -1 - if there's error reading manifest history file
16591 * 1 - if the service is not found
16592 * 0 - if the service is found
16593 */
16594 static int
check_mfst_history(const char * svcname)16595 check_mfst_history(const char *svcname)
16596 {
16597 struct stat st;
16598 caddr_t mfsthist_start;
16599 char *svnbuf;
16600 int fd;
16601 int r = 1;
16602
16603 fd = open(MFSTHISTFILE, O_RDONLY);
16604 if (fd == -1) {
16605 uu_warn(gettext("Unable to open the history file\n"));
16606 return (-1);
16607 }
16608
16609 if (fstat(fd, &st) == -1) {
16610 uu_warn(gettext("Unable to stat the history file\n"));
16611 return (-1);
16612 }
16613
16614 mfsthist_start = mmap(0, st.st_size, PROT_READ,
16615 MAP_PRIVATE, fd, 0);
16616
16617 (void) close(fd);
16618 if (mfsthist_start == MAP_FAILED ||
16619 *(mfsthist_start + st.st_size) != '\0') {
16620 (void) munmap(mfsthist_start, st.st_size);
16621 return (-1);
16622 }
16623
16624 /*
16625 * The manifest history file is a space delimited list
16626 * of service and instance to manifest linkage. Adding
16627 * a space to the end of the service name so to get only
16628 * the service that is being searched for.
16629 */
16630 svnbuf = uu_msprintf("%s ", svcname);
16631 if (svnbuf == NULL)
16632 uu_die(gettext("Out of memory"));
16633
16634 if (strstr(mfsthist_start, svnbuf) != NULL)
16635 r = 0;
16636
16637 (void) munmap(mfsthist_start, st.st_size);
16638 uu_free(svnbuf);
16639 return (r);
16640 }
16641
16642 /*
16643 * Take down each of the instances in the service
16644 * and remove them, then delete the service.
16645 */
16646 static void
teardown_service(scf_service_t * svc,const char * svnbuf)16647 teardown_service(scf_service_t *svc, const char *svnbuf)
16648 {
16649 scf_instance_t *instance;
16650 scf_iter_t *iter;
16651 int r;
16652
16653 safe_printf(gettext("Delete service %s as there are no "
16654 "supporting manifests\n"), svnbuf);
16655
16656 instance = scf_instance_create(g_hndl);
16657 iter = scf_iter_create(g_hndl);
16658 if (iter == NULL || instance == NULL) {
16659 uu_warn(gettext("Unable to create supporting entities to "
16660 "teardown the service\n"));
16661 uu_warn(gettext("scf error is : %s\n"),
16662 scf_strerror(scf_error()));
16663 scfdie();
16664 }
16665
16666 if (scf_iter_service_instances(iter, svc) != 0) {
16667 switch (scf_error()) {
16668 case SCF_ERROR_CONNECTION_BROKEN:
16669 case SCF_ERROR_DELETED:
16670 goto out;
16671
16672 case SCF_ERROR_HANDLE_MISMATCH:
16673 case SCF_ERROR_NOT_BOUND:
16674 case SCF_ERROR_NOT_SET:
16675 default:
16676 bad_error("scf_iter_service_instances",
16677 scf_error());
16678 }
16679 }
16680
16681 while ((r = scf_iter_next_instance(iter, instance)) != 0) {
16682 if (r == -1) {
16683 uu_warn(gettext("Error - %s\n"),
16684 scf_strerror(scf_error()));
16685 goto out;
16686 }
16687
16688 (void) disable_instance(instance);
16689 }
16690
16691 /*
16692 * Delete the service... forcing the deletion in case
16693 * any of the instances did not disable.
16694 */
16695 (void) lscf_service_delete(svc, 1);
16696 out:
16697 scf_instance_destroy(instance);
16698 scf_iter_destroy(iter);
16699 }
16700
16701 /*
16702 * Get the list of instances supported by the manifest
16703 * file.
16704 *
16705 * Return 0 if there are no instances.
16706 *
16707 * Return -1 if there are errors attempting to collect instances.
16708 *
16709 * Return the count of instances found if there are no errors.
16710 *
16711 */
16712 static int
check_instance_support(char * mfstfile,const char * svcname,uu_list_t * instances)16713 check_instance_support(char *mfstfile, const char *svcname,
16714 uu_list_t *instances)
16715 {
16716 uu_list_walk_t *svcs, *insts;
16717 uu_list_t *ilist;
16718 bundle_t *b;
16719 entity_t *mfsvc, *mfinst;
16720 const char *svcn;
16721 int rminstcnt = 0;
16722
16723
16724 b = internal_bundle_new();
16725
16726 if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
16727 /*
16728 * Unable to process the manifest file for
16729 * instance support, so just return as
16730 * don't want to remove instances that could
16731 * not be accounted for that might exist here.
16732 */
16733 internal_bundle_free(b);
16734 return (0);
16735 }
16736
16737 svcs = uu_list_walk_start(b->sc_bundle_services, 0);
16738 if (svcs == NULL) {
16739 internal_bundle_free(b);
16740 return (0);
16741 }
16742
16743 svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
16744 (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
16745
16746 while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
16747 if (strcmp(mfsvc->sc_name, svcn) == 0)
16748 break;
16749 }
16750 uu_list_walk_end(svcs);
16751
16752 if (mfsvc == NULL) {
16753 internal_bundle_free(b);
16754 return (-1);
16755 }
16756
16757 ilist = mfsvc->sc_u.sc_service.sc_service_instances;
16758 if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
16759 internal_bundle_free(b);
16760 return (0);
16761 }
16762
16763 while ((mfinst = uu_list_walk_next(insts)) != NULL) {
16764 /*
16765 * Remove the instance from the instances list.
16766 * The unaccounted for instances will be removed
16767 * from the service once all manifests are
16768 * processed.
16769 */
16770 (void) remove_string(instances,
16771 mfinst->sc_name);
16772 rminstcnt++;
16773 }
16774
16775 uu_list_walk_end(insts);
16776 internal_bundle_free(b);
16777
16778 return (rminstcnt);
16779 }
16780
16781 /*
16782 * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16783 * 'false' to indicate there's no manifest file(s) found for the service.
16784 */
16785 static void
svc_add_no_support(scf_service_t * svc)16786 svc_add_no_support(scf_service_t *svc)
16787 {
16788 char *pname;
16789
16790 /* Add no support */
16791 cur_svc = svc;
16792 if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
16793 return;
16794
16795 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
16796 if (pname == NULL)
16797 uu_die(gettext("Out of memory.\n"));
16798
16799 (void) lscf_addpropvalue(pname, "boolean:", "0");
16800
16801 uu_free(pname);
16802 cur_svc = NULL;
16803 }
16804
16805 /*
16806 * This function handles all upgrade scenarios for a service that doesn't have
16807 * SCF_PG_MANIFESTFILES pg. The function creates and populates
16808 * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16809 * manifest(s) mapping. Manifests under supported directories are inventoried
16810 * and a property is added for each file that delivers configuration to the
16811 * service. A service that has no corresponding manifest files (deleted) are
16812 * removed from repository.
16813 *
16814 * Unsupported services:
16815 *
16816 * A service is considered unsupported if there is no corresponding manifest
16817 * in the supported directories for that service and the service isn't in the
16818 * history file list. The history file, MFSTHISTFILE, contains a list of all
16819 * services and instances that were delivered by Solaris before the introduction
16820 * of the SCF_PG_MANIFESTFILES property group. The history file also contains
16821 * the path to the manifest file that defined the service or instance.
16822 *
16823 * Another type of unsupported services is 'handcrafted' services,
16824 * programmatically created services or services created by dependent entries
16825 * in other manifests. A handcrafted service is identified by its lack of any
16826 * instance containing last-import snapshot which is created during svccfg
16827 * import.
16828 *
16829 * This function sets a flag for unsupported services by setting services'
16830 * SCF_PG_MANIFESTFILES/support property to false.
16831 */
16832 static void
upgrade_svc_mfst_connection(scf_service_t * svc,const char * svcname)16833 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
16834 {
16835 service_manifest_t *elem;
16836 uu_list_walk_t *mfwalk;
16837 string_list_t *mfile;
16838 uu_list_t *instances;
16839 const char *sname;
16840 char *pname;
16841 int r;
16842
16843 /*
16844 * Since there's no guarantee manifests under /var are available during
16845 * early import, don't perform any upgrade during early import.
16846 */
16847 if (IGNORE_VAR)
16848 return;
16849
16850 if (service_manifest_tree == NULL) {
16851 create_manifest_tree();
16852 }
16853
16854 /*
16855 * Find service's supporting manifest(s) after
16856 * stripping off the svc:/ prefix that is part
16857 * of the fmri that is not used in the service
16858 * manifest bundle list.
16859 */
16860 sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
16861 strlen(SCF_FMRI_SERVICE_PREFIX);
16862 elem = find_add_svc_mfst(sname, NULL);
16863 if (elem == NULL) {
16864
16865 /*
16866 * A handcrafted service, one that has no instance containing
16867 * last-import snapshot, should get unsupported flag.
16868 */
16869 instances = create_instance_list(svc, 1);
16870 if (instances == NULL) {
16871 uu_warn(gettext("Unable to create instance list %s\n"),
16872 svcname);
16873 return;
16874 }
16875
16876 if (uu_list_numnodes(instances) == 0) {
16877 svc_add_no_support(svc);
16878 return;
16879 }
16880
16881 /*
16882 * If the service is in the history file, and its supporting
16883 * manifests are not found, we can safely delete the service
16884 * because its manifests are removed from the system.
16885 *
16886 * Services not found in the history file are not delivered by
16887 * Solaris and/or delivered outside supported directories, set
16888 * unsupported flag for these services.
16889 */
16890 r = check_mfst_history(svcname);
16891 if (r == -1)
16892 return;
16893
16894 if (r) {
16895 /* Set unsupported flag for service */
16896 svc_add_no_support(svc);
16897 } else {
16898 /* Delete the service */
16899 teardown_service(svc, svcname);
16900 }
16901
16902 return;
16903 }
16904
16905 /*
16906 * Walk through the list of manifests and add them
16907 * to the service.
16908 *
16909 * Create a manifestfiles pg and add the property.
16910 */
16911 mfwalk = uu_list_walk_start(elem->mfstlist, 0);
16912 if (mfwalk == NULL)
16913 return;
16914
16915 cur_svc = svc;
16916 r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
16917 if (r != 0) {
16918 cur_svc = NULL;
16919 return;
16920 }
16921
16922 while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
16923 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16924 mhash_filename_to_propname(mfile->str, 0));
16925 if (pname == NULL)
16926 uu_die(gettext("Out of memory.\n"));
16927
16928 (void) lscf_addpropvalue(pname, "astring:", mfile->str);
16929 uu_free(pname);
16930 }
16931 uu_list_walk_end(mfwalk);
16932
16933 cur_svc = NULL;
16934 }
16935
16936 /*
16937 * Take a service and process the manifest file entires to see if
16938 * there is continued support for the service and instances. If
16939 * not cleanup as appropriate.
16940 *
16941 * If a service does not have a manifest files entry flag it for
16942 * upgrade and return.
16943 *
16944 * For each manifestfiles property check if the manifest file is
16945 * under the supported /lib/svc/manifest or /var/svc/manifest path
16946 * and if not then return immediately as this service is not supported
16947 * by the cleanup mechanism and should be ignored.
16948 *
16949 * For each manifest file that is supported, check to see if the
16950 * file exists. If not then remove the manifest file property
16951 * from the service and the smf/manifest hash table. If the manifest
16952 * file exists then verify that it supports the instances that are
16953 * part of the service.
16954 *
16955 * Once all manifest files have been accounted for remove any instances
16956 * that are no longer supported in the service.
16957 *
16958 * Return values :
16959 * 0 - Successfully processed the service
16960 * non-zero - failed to process the service
16961 *
16962 * On most errors, will just return to wait and get the next service,
16963 * unless in case of unable to create the needed structures which is
16964 * most likely a fatal error that is not going to be recoverable.
16965 */
16966 int
lscf_service_cleanup(void * act,scf_walkinfo_t * wip)16967 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
16968 {
16969 struct mpg_mfile *mpntov = NULL;
16970 struct mpg_mfile **mpvarry = NULL;
16971 scf_service_t *svc;
16972 scf_propertygroup_t *mpg;
16973 scf_property_t *mp;
16974 scf_value_t *mv;
16975 scf_iter_t *mi;
16976 scf_instance_t *instance;
16977 uu_list_walk_t *insts;
16978 uu_list_t *instances = NULL;
16979 boolean_t activity = (boolean_t)act;
16980 char *mpnbuf = NULL;
16981 char *mpvbuf = NULL;
16982 char *pgpropbuf;
16983 int mfstcnt, rminstct, instct, mfstmax;
16984 int index;
16985 int r = 0;
16986
16987 assert(g_hndl != NULL);
16988 assert(wip->svc != NULL);
16989 assert(wip->fmri != NULL);
16990
16991 svc = wip->svc;
16992
16993 mpg = scf_pg_create(g_hndl);
16994 mp = scf_property_create(g_hndl);
16995 mi = scf_iter_create(g_hndl);
16996 mv = scf_value_create(g_hndl);
16997 instance = scf_instance_create(g_hndl);
16998
16999 if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
17000 instance == NULL) {
17001 uu_warn(gettext("Unable to create the supporting entities\n"));
17002 uu_warn(gettext("scf error is : %s\n"),
17003 scf_strerror(scf_error()));
17004 scfdie();
17005 }
17006
17007 /*
17008 * Get the manifestfiles property group to be parsed for
17009 * files existence.
17010 */
17011 if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
17012 switch (scf_error()) {
17013 case SCF_ERROR_NOT_FOUND:
17014 upgrade_svc_mfst_connection(svc, wip->fmri);
17015 break;
17016 case SCF_ERROR_DELETED:
17017 case SCF_ERROR_CONNECTION_BROKEN:
17018 goto out;
17019
17020 case SCF_ERROR_HANDLE_MISMATCH:
17021 case SCF_ERROR_NOT_BOUND:
17022 case SCF_ERROR_NOT_SET:
17023 default:
17024 bad_error("scf_iter_pg_properties",
17025 scf_error());
17026 }
17027
17028 goto out;
17029 }
17030
17031 /*
17032 * Iterate through each of the manifestfiles properties
17033 * to determine what manifestfiles are available.
17034 *
17035 * If a manifest file is supported then increment the
17036 * count and therefore the service is safe.
17037 */
17038 if (scf_iter_pg_properties(mi, mpg) != 0) {
17039 switch (scf_error()) {
17040 case SCF_ERROR_DELETED:
17041 case SCF_ERROR_CONNECTION_BROKEN:
17042 goto out;
17043
17044 case SCF_ERROR_HANDLE_MISMATCH:
17045 case SCF_ERROR_NOT_BOUND:
17046 case SCF_ERROR_NOT_SET:
17047 default:
17048 bad_error("scf_iter_pg_properties",
17049 scf_error());
17050 }
17051 }
17052
17053 mfstcnt = 0;
17054 mfstmax = MFSTFILE_MAX;
17055 mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
17056 while ((r = scf_iter_next_property(mi, mp)) != 0) {
17057 if (r == -1)
17058 bad_error(gettext("Unable to iterate through "
17059 "manifestfiles properties : %s"),
17060 scf_error());
17061
17062 mpntov = safe_malloc(sizeof (struct mpg_mfile));
17063 mpnbuf = safe_malloc(max_scf_name_len + 1);
17064 mpvbuf = safe_malloc(max_scf_value_len + 1);
17065 mpntov->mpg = mpnbuf;
17066 mpntov->mfile = mpvbuf;
17067 mpntov->access = 1;
17068 if (scf_property_get_name(mp, mpnbuf,
17069 max_scf_name_len + 1) < 0) {
17070 uu_warn(gettext("Unable to get manifest file "
17071 "property : %s\n"),
17072 scf_strerror(scf_error()));
17073
17074 switch (scf_error()) {
17075 case SCF_ERROR_DELETED:
17076 case SCF_ERROR_CONNECTION_BROKEN:
17077 r = scferror2errno(scf_error());
17078 goto out_free;
17079
17080 case SCF_ERROR_HANDLE_MISMATCH:
17081 case SCF_ERROR_NOT_BOUND:
17082 case SCF_ERROR_NOT_SET:
17083 default:
17084 bad_error("scf_iter_pg_properties",
17085 scf_error());
17086 }
17087 }
17088
17089 /*
17090 * The support property is a boolean value that indicates
17091 * if the service is supported for manifest file deletion.
17092 * Currently at this time there is no code that sets this
17093 * value to true. So while we could just let this be caught
17094 * by the support check below, in the future this by be set
17095 * to true and require processing. So for that, go ahead
17096 * and check here, and just return if false. Otherwise,
17097 * fall through expecting that other support checks will
17098 * handle the entries.
17099 */
17100 if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
17101 uint8_t support;
17102
17103 if (scf_property_get_value(mp, mv) != 0 ||
17104 scf_value_get_boolean(mv, &support) != 0) {
17105 uu_warn(gettext("Unable to get the manifest "
17106 "support value: %s\n"),
17107 scf_strerror(scf_error()));
17108
17109 switch (scf_error()) {
17110 case SCF_ERROR_DELETED:
17111 case SCF_ERROR_CONNECTION_BROKEN:
17112 r = scferror2errno(scf_error());
17113 goto out_free;
17114
17115 case SCF_ERROR_HANDLE_MISMATCH:
17116 case SCF_ERROR_NOT_BOUND:
17117 case SCF_ERROR_NOT_SET:
17118 default:
17119 bad_error("scf_iter_pg_properties",
17120 scf_error());
17121 }
17122 }
17123
17124 if (support == B_FALSE)
17125 goto out_free;
17126 }
17127
17128 /*
17129 * Anything with a manifest outside of the supported
17130 * directories, immediately bail out because that makes
17131 * this service non-supported. We don't even want
17132 * to do instance processing in this case because the
17133 * instances could be part of the non-supported manifest.
17134 */
17135 if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
17136 /*
17137 * Manifest is not in /lib/svc, so we need to
17138 * consider the /var/svc case.
17139 */
17140 if (strncmp(mpnbuf, VARSVC_PR,
17141 strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
17142 /*
17143 * Either the manifest is not in /var/svc or
17144 * /var is not yet mounted. We ignore the
17145 * manifest either because it is not in a
17146 * standard location or because we cannot
17147 * currently access the manifest.
17148 */
17149 goto out_free;
17150 }
17151 }
17152
17153 /*
17154 * Get the value to of the manifest file for this entry
17155 * for access verification and instance support
17156 * verification if it still exists.
17157 *
17158 * During Early Manifest Import if the manifest is in
17159 * /var/svc then it may not yet be available for checking
17160 * so we must determine if /var/svc is available. If not
17161 * then defer until Late Manifest Import to cleanup.
17162 */
17163 if (scf_property_get_value(mp, mv) != 0) {
17164 uu_warn(gettext("Unable to get the manifest file "
17165 "value: %s\n"),
17166 scf_strerror(scf_error()));
17167
17168 switch (scf_error()) {
17169 case SCF_ERROR_DELETED:
17170 case SCF_ERROR_CONNECTION_BROKEN:
17171 r = scferror2errno(scf_error());
17172 goto out_free;
17173
17174 case SCF_ERROR_HANDLE_MISMATCH:
17175 case SCF_ERROR_NOT_BOUND:
17176 case SCF_ERROR_NOT_SET:
17177 default:
17178 bad_error("scf_property_get_value",
17179 scf_error());
17180 }
17181 }
17182
17183 if (scf_value_get_astring(mv, mpvbuf,
17184 max_scf_value_len + 1) < 0) {
17185 uu_warn(gettext("Unable to get the manifest "
17186 "file : %s\n"),
17187 scf_strerror(scf_error()));
17188
17189 switch (scf_error()) {
17190 case SCF_ERROR_DELETED:
17191 case SCF_ERROR_CONNECTION_BROKEN:
17192 r = scferror2errno(scf_error());
17193 goto out_free;
17194
17195 case SCF_ERROR_HANDLE_MISMATCH:
17196 case SCF_ERROR_NOT_BOUND:
17197 case SCF_ERROR_NOT_SET:
17198 default:
17199 bad_error("scf_value_get_astring",
17200 scf_error());
17201 }
17202 }
17203
17204 mpvarry[mfstcnt] = mpntov;
17205 mfstcnt++;
17206
17207 /*
17208 * Check for the need to reallocate array
17209 */
17210 if (mfstcnt >= (mfstmax - 1)) {
17211 struct mpg_mfile **newmpvarry;
17212
17213 mfstmax = mfstmax * 2;
17214 newmpvarry = realloc(mpvarry,
17215 sizeof (struct mpg_mfile *) * mfstmax);
17216
17217 if (newmpvarry == NULL)
17218 goto out_free;
17219
17220 mpvarry = newmpvarry;
17221 }
17222
17223 mpvarry[mfstcnt] = NULL;
17224 }
17225
17226 for (index = 0; mpvarry[index]; index++) {
17227 mpntov = mpvarry[index];
17228
17229 /*
17230 * Check to see if the manifestfile is accessable, if so hand
17231 * this service and manifestfile off to be processed for
17232 * instance support.
17233 */
17234 mpnbuf = mpntov->mpg;
17235 mpvbuf = mpntov->mfile;
17236 if (access(mpvbuf, F_OK) != 0) {
17237 mpntov->access = 0;
17238 activity++;
17239 mfstcnt--;
17240 /* Remove the entry from the service */
17241 cur_svc = svc;
17242 pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
17243 mpnbuf);
17244 if (pgpropbuf == NULL)
17245 uu_die(gettext("Out of memory.\n"));
17246
17247 lscf_delprop(pgpropbuf);
17248 cur_svc = NULL;
17249
17250 uu_free(pgpropbuf);
17251 }
17252 }
17253
17254 /*
17255 * If mfstcnt is 0, none of the manifests that supported the service
17256 * existed so remove the service.
17257 */
17258 if (mfstcnt == 0) {
17259 teardown_service(svc, wip->fmri);
17260
17261 goto out_free;
17262 }
17263
17264 if (activity) {
17265 int nosvcsupport = 0;
17266
17267 /*
17268 * If the list of service instances is NULL then
17269 * create the list.
17270 */
17271 instances = create_instance_list(svc, 1);
17272 if (instances == NULL) {
17273 uu_warn(gettext("Unable to create instance list %s\n"),
17274 wip->fmri);
17275 goto out_free;
17276 }
17277
17278 rminstct = uu_list_numnodes(instances);
17279 instct = rminstct;
17280
17281 for (index = 0; mpvarry[index]; index++) {
17282 mpntov = mpvarry[index];
17283 if (mpntov->access == 0)
17284 continue;
17285
17286 mpnbuf = mpntov->mpg;
17287 mpvbuf = mpntov->mfile;
17288 r = check_instance_support(mpvbuf, wip->fmri,
17289 instances);
17290 if (r == -1) {
17291 nosvcsupport++;
17292 } else {
17293 rminstct -= r;
17294 }
17295 }
17296
17297 if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
17298 teardown_service(svc, wip->fmri);
17299
17300 goto out_free;
17301 }
17302 }
17303
17304 /*
17305 * If there are instances left on the instance list, then
17306 * we must remove them.
17307 */
17308 if (instances != NULL && uu_list_numnodes(instances)) {
17309 string_list_t *sp;
17310
17311 insts = uu_list_walk_start(instances, 0);
17312 while ((sp = uu_list_walk_next(insts)) != NULL) {
17313 /*
17314 * Remove the instance from the instances list.
17315 */
17316 safe_printf(gettext("Delete instance %s from "
17317 "service %s\n"), sp->str, wip->fmri);
17318 if (scf_service_get_instance(svc, sp->str,
17319 instance) != SCF_SUCCESS) {
17320 (void) uu_warn("scf_error - %s\n",
17321 scf_strerror(scf_error()));
17322
17323 continue;
17324 }
17325
17326 (void) disable_instance(instance);
17327
17328 (void) lscf_instance_delete(instance, 1);
17329 }
17330 scf_instance_destroy(instance);
17331 uu_list_walk_end(insts);
17332 }
17333
17334 out_free:
17335 if (mpvarry) {
17336 struct mpg_mfile *fmpntov;
17337
17338 for (index = 0; mpvarry[index]; index++) {
17339 fmpntov = mpvarry[index];
17340 if (fmpntov->mpg == mpnbuf)
17341 mpnbuf = NULL;
17342 free(fmpntov->mpg);
17343
17344 if (fmpntov->mfile == mpvbuf)
17345 mpvbuf = NULL;
17346 free(fmpntov->mfile);
17347
17348 if (fmpntov == mpntov)
17349 mpntov = NULL;
17350 free(fmpntov);
17351 }
17352 if (mpnbuf)
17353 free(mpnbuf);
17354 if (mpvbuf)
17355 free(mpvbuf);
17356 if (mpntov)
17357 free(mpntov);
17358
17359 free(mpvarry);
17360 }
17361 out:
17362 scf_pg_destroy(mpg);
17363 scf_property_destroy(mp);
17364 scf_iter_destroy(mi);
17365 scf_value_destroy(mv);
17366
17367 return (0);
17368 }
17369
17370 /*
17371 * Take the service and search for the manifestfiles property
17372 * in each of the property groups. If the manifest file
17373 * associated with the property does not exist then remove
17374 * the property group.
17375 */
17376 int
lscf_hash_cleanup()17377 lscf_hash_cleanup()
17378 {
17379 scf_service_t *svc;
17380 scf_scope_t *scope;
17381 scf_propertygroup_t *pg;
17382 scf_property_t *prop;
17383 scf_value_t *val;
17384 scf_iter_t *iter;
17385 char *pgname = NULL;
17386 char *mfile = NULL;
17387 int r;
17388
17389 svc = scf_service_create(g_hndl);
17390 scope = scf_scope_create(g_hndl);
17391 pg = scf_pg_create(g_hndl);
17392 prop = scf_property_create(g_hndl);
17393 val = scf_value_create(g_hndl);
17394 iter = scf_iter_create(g_hndl);
17395 if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
17396 svc == NULL || scope == NULL) {
17397 uu_warn(gettext("Unable to create a property group, or "
17398 "property\n"));
17399 uu_warn("%s\n", pg == NULL ? "pg is NULL" :
17400 "pg is not NULL");
17401 uu_warn("%s\n", prop == NULL ? "prop is NULL" :
17402 "prop is not NULL");
17403 uu_warn("%s\n", val == NULL ? "val is NULL" :
17404 "val is not NULL");
17405 uu_warn("%s\n", iter == NULL ? "iter is NULL" :
17406 "iter is not NULL");
17407 uu_warn("%s\n", svc == NULL ? "svc is NULL" :
17408 "svc is not NULL");
17409 uu_warn("%s\n", scope == NULL ? "scope is NULL" :
17410 "scope is not NULL");
17411 uu_warn(gettext("scf error is : %s\n"),
17412 scf_strerror(scf_error()));
17413 scfdie();
17414 }
17415
17416 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
17417 switch (scf_error()) {
17418 case SCF_ERROR_CONNECTION_BROKEN:
17419 case SCF_ERROR_NOT_FOUND:
17420 goto out;
17421
17422 case SCF_ERROR_HANDLE_MISMATCH:
17423 case SCF_ERROR_NOT_BOUND:
17424 case SCF_ERROR_INVALID_ARGUMENT:
17425 default:
17426 bad_error("scf_handle_get_scope", scf_error());
17427 }
17428 }
17429
17430 if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
17431 uu_warn(gettext("Unable to process the hash service, %s\n"),
17432 HASH_SVC);
17433 goto out;
17434 }
17435
17436 pgname = safe_malloc(max_scf_name_len + 1);
17437 mfile = safe_malloc(max_scf_value_len + 1);
17438
17439 if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
17440 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17441 scf_strerror(scf_error()));
17442 goto out;
17443 }
17444
17445 while ((r = scf_iter_next_pg(iter, pg)) != 0) {
17446 if (r == -1)
17447 goto out;
17448
17449 if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
17450 switch (scf_error()) {
17451 case SCF_ERROR_DELETED:
17452 return (ENODEV);
17453
17454 case SCF_ERROR_CONNECTION_BROKEN:
17455 return (ECONNABORTED);
17456
17457 case SCF_ERROR_NOT_SET:
17458 case SCF_ERROR_NOT_BOUND:
17459 default:
17460 bad_error("scf_pg_get_name", scf_error());
17461 }
17462 }
17463 if (IGNORE_VAR) {
17464 if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
17465 continue;
17466 }
17467
17468 /*
17469 * If unable to get the property continue as this is an
17470 * entry that has no location to check against.
17471 */
17472 if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
17473 continue;
17474 }
17475
17476 if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
17477 uu_warn(gettext("Unable to get value from %s\n"),
17478 pgname);
17479
17480 switch (scf_error()) {
17481 case SCF_ERROR_DELETED:
17482 case SCF_ERROR_CONSTRAINT_VIOLATED:
17483 case SCF_ERROR_NOT_FOUND:
17484 case SCF_ERROR_NOT_SET:
17485 continue;
17486
17487 case SCF_ERROR_CONNECTION_BROKEN:
17488 r = scferror2errno(scf_error());
17489 goto out;
17490
17491 case SCF_ERROR_HANDLE_MISMATCH:
17492 case SCF_ERROR_NOT_BOUND:
17493 default:
17494 bad_error("scf_property_get_value",
17495 scf_error());
17496 }
17497 }
17498
17499 if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
17500 == -1) {
17501 uu_warn(gettext("Unable to get astring from %s : %s\n"),
17502 pgname, scf_strerror(scf_error()));
17503
17504 switch (scf_error()) {
17505 case SCF_ERROR_NOT_SET:
17506 case SCF_ERROR_TYPE_MISMATCH:
17507 continue;
17508
17509 default:
17510 bad_error("scf_value_get_astring", scf_error());
17511 }
17512 }
17513
17514 if (access(mfile, F_OK) == 0)
17515 continue;
17516
17517 (void) scf_pg_delete(pg);
17518 }
17519
17520 out:
17521 scf_scope_destroy(scope);
17522 scf_service_destroy(svc);
17523 scf_pg_destroy(pg);
17524 scf_property_destroy(prop);
17525 scf_value_destroy(val);
17526 scf_iter_destroy(iter);
17527 free(pgname);
17528 free(mfile);
17529
17530 return (0);
17531 }
17532
17533 #ifndef NATIVE_BUILD
17534 /* ARGSUSED */
CPL_MATCH_FN(complete_select)17535 CPL_MATCH_FN(complete_select)
17536 {
17537 const char *arg0, *arg1, *arg1end;
17538 int word_start, err = 0, r;
17539 size_t len;
17540 char *buf;
17541
17542 lscf_prep_hndl();
17543
17544 arg0 = line + strspn(line, " \t");
17545 assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
17546
17547 arg1 = arg0 + sizeof ("select") - 1;
17548 arg1 += strspn(arg1, " \t");
17549 word_start = arg1 - line;
17550
17551 arg1end = arg1 + strcspn(arg1, " \t");
17552 if (arg1end < line + word_end)
17553 return (0);
17554
17555 len = line + word_end - arg1;
17556
17557 buf = safe_malloc(max_scf_name_len + 1);
17558
17559 if (cur_snap != NULL) {
17560 return (0);
17561 } else if (cur_inst != NULL) {
17562 return (0);
17563 } else if (cur_svc != NULL) {
17564 scf_instance_t *inst;
17565 scf_iter_t *iter;
17566
17567 if ((inst = scf_instance_create(g_hndl)) == NULL ||
17568 (iter = scf_iter_create(g_hndl)) == NULL)
17569 scfdie();
17570
17571 if (scf_iter_service_instances(iter, cur_svc) != 0)
17572 scfdie();
17573
17574 for (;;) {
17575 r = scf_iter_next_instance(iter, inst);
17576 if (r == 0)
17577 break;
17578 if (r != 1)
17579 scfdie();
17580
17581 if (scf_instance_get_name(inst, buf,
17582 max_scf_name_len + 1) < 0)
17583 scfdie();
17584
17585 if (strncmp(buf, arg1, len) == 0) {
17586 err = cpl_add_completion(cpl, line, word_start,
17587 word_end, buf + len, "", " ");
17588 if (err != 0)
17589 break;
17590 }
17591 }
17592
17593 scf_iter_destroy(iter);
17594 scf_instance_destroy(inst);
17595
17596 return (err);
17597 } else {
17598 scf_service_t *svc;
17599 scf_iter_t *iter;
17600
17601 assert(cur_scope != NULL);
17602
17603 if ((svc = scf_service_create(g_hndl)) == NULL ||
17604 (iter = scf_iter_create(g_hndl)) == NULL)
17605 scfdie();
17606
17607 if (scf_iter_scope_services(iter, cur_scope) != 0)
17608 scfdie();
17609
17610 for (;;) {
17611 r = scf_iter_next_service(iter, svc);
17612 if (r == 0)
17613 break;
17614 if (r != 1)
17615 scfdie();
17616
17617 if (scf_service_get_name(svc, buf,
17618 max_scf_name_len + 1) < 0)
17619 scfdie();
17620
17621 if (strncmp(buf, arg1, len) == 0) {
17622 err = cpl_add_completion(cpl, line, word_start,
17623 word_end, buf + len, "", " ");
17624 if (err != 0)
17625 break;
17626 }
17627 }
17628
17629 scf_iter_destroy(iter);
17630 scf_service_destroy(svc);
17631
17632 return (err);
17633 }
17634 }
17635
17636 /* ARGSUSED */
CPL_MATCH_FN(complete_command)17637 CPL_MATCH_FN(complete_command)
17638 {
17639 uint32_t scope = 0;
17640
17641 if (cur_snap != NULL)
17642 scope = CS_SNAP;
17643 else if (cur_inst != NULL)
17644 scope = CS_INST;
17645 else if (cur_svc != NULL)
17646 scope = CS_SVC;
17647 else
17648 scope = CS_SCOPE;
17649
17650 return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
17651 }
17652 #endif /* NATIVE_BUILD */
17653