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 if (scf_service_get_instance(svc, istr, inst) != 0) {
1445 switch (scf_error()) {
1446 case SCF_ERROR_CONNECTION_BROKEN:
1447 scfdie();
1448 /* NOTREACHED */
1449
1450 case SCF_ERROR_DELETED:
1451 goto get_svc;
1452
1453 case SCF_ERROR_NOT_FOUND:
1454 break;
1455
1456 case SCF_ERROR_HANDLE_MISMATCH:
1457 case SCF_ERROR_INVALID_ARGUMENT:
1458 case SCF_ERROR_NOT_BOUND:
1459 case SCF_ERROR_NOT_SET:
1460 default:
1461 bad_error("scf_service_get_instance", scf_error());
1462 }
1463
1464 if (scf_service_add_instance(svc, istr, inst) != 0) {
1465 switch (scf_error()) {
1466 case SCF_ERROR_CONNECTION_BROKEN:
1467 scfdie();
1468 /* NOTREACHED */
1469
1470 case SCF_ERROR_DELETED:
1471 goto get_svc;
1472
1473 case SCF_ERROR_PERMISSION_DENIED:
1474 case SCF_ERROR_BACKEND_READONLY:
1475 case SCF_ERROR_BACKEND_ACCESS:
1476 scfe = scf_error();
1477 goto out;
1478
1479 case SCF_ERROR_HANDLE_MISMATCH:
1480 case SCF_ERROR_INVALID_ARGUMENT:
1481 case SCF_ERROR_NOT_BOUND:
1482 case SCF_ERROR_NOT_SET:
1483 default:
1484 bad_error("scf_service_add_instance",
1485 scf_error());
1486 }
1487 }
1488 }
1489
1490 scfe = SCF_ERROR_NONE;
1491 *ep = inst;
1492 *isservicep = 0;
1493
1494 out:
1495 if (*ep != inst)
1496 scf_instance_destroy(inst);
1497 if (*ep != svc)
1498 scf_service_destroy(svc);
1499 scf_scope_destroy(scope);
1500 free(fmri_copy);
1501 return (scfe);
1502 }
1503
1504 /*
1505 * Create or update a snapshot of inst. snap is a required scratch object.
1506 *
1507 * Returns
1508 * 0 - success
1509 * ECONNABORTED - repository connection broken
1510 * EPERM - permission denied
1511 * ENOSPC - configd is out of resources
1512 * ECANCELED - inst was deleted
1513 * -1 - unknown libscf error (message printed)
1514 */
1515 static int
take_snap(scf_instance_t * inst,const char * name,scf_snapshot_t * snap)1516 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1517 {
1518 again:
1519 if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1520 if (_scf_snapshot_take_attach(inst, snap) != 0) {
1521 switch (scf_error()) {
1522 case SCF_ERROR_CONNECTION_BROKEN:
1523 case SCF_ERROR_PERMISSION_DENIED:
1524 case SCF_ERROR_NO_RESOURCES:
1525 return (scferror2errno(scf_error()));
1526
1527 case SCF_ERROR_NOT_SET:
1528 case SCF_ERROR_INVALID_ARGUMENT:
1529 default:
1530 bad_error("_scf_snapshot_take_attach",
1531 scf_error());
1532 }
1533 }
1534 } else {
1535 switch (scf_error()) {
1536 case SCF_ERROR_NOT_FOUND:
1537 break;
1538
1539 case SCF_ERROR_DELETED:
1540 case SCF_ERROR_CONNECTION_BROKEN:
1541 return (scferror2errno(scf_error()));
1542
1543 case SCF_ERROR_HANDLE_MISMATCH:
1544 case SCF_ERROR_NOT_BOUND:
1545 case SCF_ERROR_INVALID_ARGUMENT:
1546 case SCF_ERROR_NOT_SET:
1547 default:
1548 bad_error("scf_instance_get_snapshot", scf_error());
1549 }
1550
1551 if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1552 switch (scf_error()) {
1553 case SCF_ERROR_EXISTS:
1554 goto again;
1555
1556 case SCF_ERROR_CONNECTION_BROKEN:
1557 case SCF_ERROR_NO_RESOURCES:
1558 case SCF_ERROR_PERMISSION_DENIED:
1559 return (scferror2errno(scf_error()));
1560
1561 default:
1562 scfwarn();
1563 return (-1);
1564
1565 case SCF_ERROR_NOT_SET:
1566 case SCF_ERROR_INTERNAL:
1567 case SCF_ERROR_INVALID_ARGUMENT:
1568 case SCF_ERROR_HANDLE_MISMATCH:
1569 bad_error("_scf_snapshot_take_new",
1570 scf_error());
1571 }
1572 }
1573 }
1574
1575 return (0);
1576 }
1577
1578 static int
refresh_running_snapshot(void * entity)1579 refresh_running_snapshot(void *entity)
1580 {
1581 scf_snapshot_t *snap;
1582 int r;
1583
1584 if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1585 scfdie();
1586 r = take_snap(entity, snap_running, snap);
1587 scf_snapshot_destroy(snap);
1588
1589 return (r);
1590 }
1591
1592 /*
1593 * Refresh entity. If isservice is zero, take entity to be an scf_instance_t *.
1594 * Otherwise take entity to be an scf_service_t * and refresh all of its child
1595 * instances. fmri is used for messages. inst, iter, and name_buf are used
1596 * for scratch space. Returns
1597 * 0 - success
1598 * ECONNABORTED - repository connection broken
1599 * ECANCELED - entity was deleted
1600 * EACCES - backend denied access
1601 * EPERM - permission denied
1602 * ENOSPC - repository server out of resources
1603 * -1 - _smf_refresh_instance_i() failed. scf_error() should be set.
1604 */
1605 static int
refresh_entity(int isservice,void * entity,const char * fmri,scf_instance_t * inst,scf_iter_t * iter,char * name_buf)1606 refresh_entity(int isservice, void *entity, const char *fmri,
1607 scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1608 {
1609 scf_error_t scfe;
1610 int r;
1611
1612 if (!isservice) {
1613 /*
1614 * Let restarter handles refreshing and making new running
1615 * snapshot only if operating on a live repository and not
1616 * running in early import.
1617 */
1618 if (est->sc_repo_filename == NULL &&
1619 est->sc_repo_doorname == NULL &&
1620 est->sc_in_emi == 0) {
1621 if (_smf_refresh_instance_i(entity) == 0) {
1622 if (g_verbose)
1623 warn(gettext("Refreshed %s.\n"), fmri);
1624 return (0);
1625 }
1626
1627 switch (scf_error()) {
1628 case SCF_ERROR_BACKEND_ACCESS:
1629 return (EACCES);
1630
1631 case SCF_ERROR_PERMISSION_DENIED:
1632 return (EPERM);
1633
1634 default:
1635 return (-1);
1636 }
1637 } else {
1638 r = refresh_running_snapshot(entity);
1639 switch (r) {
1640 case 0:
1641 break;
1642
1643 case ECONNABORTED:
1644 case ECANCELED:
1645 case EPERM:
1646 case ENOSPC:
1647 break;
1648
1649 default:
1650 bad_error("refresh_running_snapshot",
1651 scf_error());
1652 }
1653
1654 return (r);
1655 }
1656 }
1657
1658 if (scf_iter_service_instances(iter, entity) != 0) {
1659 switch (scf_error()) {
1660 case SCF_ERROR_CONNECTION_BROKEN:
1661 return (ECONNABORTED);
1662
1663 case SCF_ERROR_DELETED:
1664 return (ECANCELED);
1665
1666 case SCF_ERROR_HANDLE_MISMATCH:
1667 case SCF_ERROR_NOT_BOUND:
1668 case SCF_ERROR_NOT_SET:
1669 default:
1670 bad_error("scf_iter_service_instances", scf_error());
1671 }
1672 }
1673
1674 for (;;) {
1675 r = scf_iter_next_instance(iter, inst);
1676 if (r == 0)
1677 break;
1678 if (r != 1) {
1679 switch (scf_error()) {
1680 case SCF_ERROR_CONNECTION_BROKEN:
1681 return (ECONNABORTED);
1682
1683 case SCF_ERROR_DELETED:
1684 return (ECANCELED);
1685
1686 case SCF_ERROR_HANDLE_MISMATCH:
1687 case SCF_ERROR_NOT_BOUND:
1688 case SCF_ERROR_NOT_SET:
1689 case SCF_ERROR_INVALID_ARGUMENT:
1690 default:
1691 bad_error("scf_iter_next_instance",
1692 scf_error());
1693 }
1694 }
1695
1696 /*
1697 * Similarly, just take a new running snapshot if operating on
1698 * a non-live repository or running during early import.
1699 */
1700 if (est->sc_repo_filename != NULL ||
1701 est->sc_repo_doorname != NULL ||
1702 est->sc_in_emi == 1) {
1703 r = refresh_running_snapshot(inst);
1704 switch (r) {
1705 case 0:
1706 continue;
1707
1708 case ECONNABORTED:
1709 case ECANCELED:
1710 case EPERM:
1711 case ENOSPC:
1712 break;
1713 default:
1714 bad_error("refresh_running_snapshot",
1715 scf_error());
1716 }
1717
1718 return (r);
1719
1720 }
1721
1722 if (_smf_refresh_instance_i(inst) == 0) {
1723 if (g_verbose) {
1724 if (scf_instance_get_name(inst, name_buf,
1725 max_scf_name_len + 1) < 0)
1726 (void) strcpy(name_buf, "?");
1727
1728 warn(gettext("Refreshed %s:%s.\n"),
1729 fmri, name_buf);
1730 }
1731 } else {
1732 if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1733 g_verbose) {
1734 scfe = scf_error();
1735
1736 if (scf_instance_to_fmri(inst, name_buf,
1737 max_scf_name_len + 1) < 0)
1738 (void) strcpy(name_buf, "?");
1739
1740 warn(gettext(
1741 "Refresh of %s:%s failed: %s.\n"), fmri,
1742 name_buf, scf_strerror(scfe));
1743 }
1744 }
1745 }
1746
1747 return (0);
1748 }
1749
1750 static void
private_refresh(void)1751 private_refresh(void)
1752 {
1753 scf_instance_t *pinst = NULL;
1754 scf_iter_t *piter = NULL;
1755 ssize_t fmrilen;
1756 size_t bufsz;
1757 char *fmribuf;
1758 void *ent;
1759 int issvc;
1760 int r;
1761
1762 if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1763 return;
1764
1765 assert(cur_svc != NULL);
1766
1767 bufsz = max_scf_fmri_len + 1;
1768 fmribuf = safe_malloc(bufsz);
1769 if (cur_inst) {
1770 issvc = 0;
1771 ent = cur_inst;
1772 fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1773 } else {
1774 issvc = 1;
1775 ent = cur_svc;
1776 fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1777 if ((pinst = scf_instance_create(g_hndl)) == NULL)
1778 scfdie();
1779
1780 if ((piter = scf_iter_create(g_hndl)) == NULL)
1781 scfdie();
1782 }
1783 if (fmrilen < 0) {
1784 free(fmribuf);
1785 if (scf_error() != SCF_ERROR_DELETED)
1786 scfdie();
1787
1788 warn(emsg_deleted);
1789 return;
1790 }
1791 assert(fmrilen < bufsz);
1792
1793 r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1794 switch (r) {
1795 case 0:
1796 break;
1797
1798 case ECONNABORTED:
1799 warn(gettext("Could not refresh %s "
1800 "(repository connection broken).\n"), fmribuf);
1801 break;
1802
1803 case ECANCELED:
1804 warn(emsg_deleted);
1805 break;
1806
1807 case EPERM:
1808 warn(gettext("Could not refresh %s "
1809 "(permission denied).\n"), fmribuf);
1810 break;
1811
1812 case ENOSPC:
1813 warn(gettext("Could not refresh %s "
1814 "(repository server out of resources).\n"),
1815 fmribuf);
1816 break;
1817
1818 case EACCES:
1819 default:
1820 bad_error("refresh_entity", scf_error());
1821 }
1822
1823 if (issvc) {
1824 scf_instance_destroy(pinst);
1825 scf_iter_destroy(piter);
1826 }
1827
1828 free(fmribuf);
1829 }
1830
1831
1832 static int
stash_scferror_err(scf_callback_t * cbp,scf_error_t err)1833 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1834 {
1835 cbp->sc_err = scferror2errno(err);
1836 return (UU_WALK_ERROR);
1837 }
1838
1839 static int
stash_scferror(scf_callback_t * cbp)1840 stash_scferror(scf_callback_t *cbp)
1841 {
1842 return (stash_scferror_err(cbp, scf_error()));
1843 }
1844
1845 static int select_inst(const char *);
1846 static int select_svc(const char *);
1847
1848 /*
1849 * Take a property that does not have a type and check to see if a type
1850 * exists or can be gleened from the current data. Set the type.
1851 *
1852 * Check the current level (instance) and then check the higher level
1853 * (service). This could be the case for adding a new property to
1854 * the instance that's going to "override" a service level property.
1855 *
1856 * For a property :
1857 * 1. Take the type from an existing property
1858 * 2. Take the type from a template entry
1859 *
1860 * If the type can not be found, then leave the type as is, and let the import
1861 * report the problem of the missing type.
1862 */
1863 static int
find_current_prop_type(void * p,void * g)1864 find_current_prop_type(void *p, void *g)
1865 {
1866 property_t *prop = p;
1867 scf_callback_t *lcb = g;
1868 pgroup_t *pg = NULL;
1869
1870 const char *fmri = NULL;
1871 char *lfmri = NULL;
1872 char *cur_selection = NULL;
1873
1874 scf_propertygroup_t *sc_pg = NULL;
1875 scf_property_t *sc_prop = NULL;
1876 scf_pg_tmpl_t *t_pg = NULL;
1877 scf_prop_tmpl_t *t_prop = NULL;
1878 scf_type_t prop_type;
1879
1880 value_t *vp;
1881 int issvc = lcb->sc_service;
1882 int r = UU_WALK_ERROR;
1883
1884 if (prop->sc_value_type != SCF_TYPE_INVALID)
1885 return (UU_WALK_NEXT);
1886
1887 t_prop = scf_tmpl_prop_create(g_hndl);
1888 sc_prop = scf_property_create(g_hndl);
1889 if (sc_prop == NULL || t_prop == NULL) {
1890 warn(gettext("Unable to create the property to attempt and "
1891 "find a missing type.\n"));
1892
1893 scf_property_destroy(sc_prop);
1894 scf_tmpl_prop_destroy(t_prop);
1895
1896 return (UU_WALK_ERROR);
1897 }
1898
1899 if (lcb->sc_flags == 1) {
1900 pg = lcb->sc_parent;
1901 issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT);
1902 fmri = pg->sc_parent->sc_fmri;
1903 retry_pg:
1904 if (cur_svc && cur_selection == NULL) {
1905 cur_selection = safe_malloc(max_scf_fmri_len + 1);
1906 lscf_get_selection_str(cur_selection,
1907 max_scf_fmri_len + 1);
1908
1909 if (strcmp(cur_selection, fmri) != 0) {
1910 lscf_select(fmri);
1911 } else {
1912 free(cur_selection);
1913 cur_selection = NULL;
1914 }
1915 } else {
1916 lscf_select(fmri);
1917 }
1918
1919 if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) {
1920 warn(gettext("Unable to create property group to "
1921 "find a missing property type.\n"));
1922
1923 goto out;
1924 }
1925
1926 if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) {
1927 /*
1928 * If this is the sc_pg from the parent
1929 * let the caller clean up the sc_pg,
1930 * and just throw it away in this case.
1931 */
1932 if (sc_pg != lcb->sc_parent)
1933 scf_pg_destroy(sc_pg);
1934
1935 sc_pg = NULL;
1936 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1937 warn(gettext("Unable to create template "
1938 "property group to find a property "
1939 "type.\n"));
1940
1941 goto out;
1942 }
1943
1944 if (scf_tmpl_get_by_pg_name(fmri, NULL,
1945 pg->sc_pgroup_name, NULL, t_pg,
1946 SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) {
1947 /*
1948 * if instance get service and jump back
1949 */
1950 scf_tmpl_pg_destroy(t_pg);
1951 t_pg = NULL;
1952 if (issvc == 0) {
1953 entity_t *e = pg->sc_parent->sc_parent;
1954
1955 fmri = e->sc_fmri;
1956 issvc = 1;
1957 goto retry_pg;
1958 } else {
1959 goto out;
1960 }
1961 }
1962 }
1963 } else {
1964 sc_pg = lcb->sc_parent;
1965 }
1966
1967 /*
1968 * Attempt to get the type from an existing property. If the property
1969 * cannot be found then attempt to get the type from a template entry
1970 * for the property.
1971 *
1972 * Finally, if at the instance level look at the service level.
1973 */
1974 if (sc_pg != NULL &&
1975 pg_get_prop(sc_pg, prop->sc_property_name,
1976 sc_prop) == SCF_SUCCESS &&
1977 scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) {
1978 prop->sc_value_type = prop_type;
1979
1980 /*
1981 * Found a type, update the value types and validate
1982 * the actual value against this type.
1983 */
1984 for (vp = uu_list_first(prop->sc_property_values);
1985 vp != NULL;
1986 vp = uu_list_next(prop->sc_property_values, vp)) {
1987 vp->sc_type = prop->sc_value_type;
1988 lxml_store_value(vp, 0, NULL);
1989 }
1990
1991 r = UU_WALK_NEXT;
1992 goto out;
1993 }
1994
1995 /*
1996 * If we get here with t_pg set to NULL then we had to have
1997 * gotten an sc_pg but that sc_pg did not have the property
1998 * we are looking for. So if the t_pg is not null look up
1999 * the template entry for the property.
2000 *
2001 * If the t_pg is null then need to attempt to get a matching
2002 * template entry for the sc_pg, and see if there is a property
2003 * entry for that template entry.
2004 */
2005 do_tmpl :
2006 if (t_pg != NULL &&
2007 scf_tmpl_get_by_prop(t_pg, prop->sc_property_name,
2008 t_prop, 0) == SCF_SUCCESS) {
2009 if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) {
2010 prop->sc_value_type = prop_type;
2011
2012 /*
2013 * Found a type, update the value types and validate
2014 * the actual value against this type.
2015 */
2016 for (vp = uu_list_first(prop->sc_property_values);
2017 vp != NULL;
2018 vp = uu_list_next(prop->sc_property_values, vp)) {
2019 vp->sc_type = prop->sc_value_type;
2020 lxml_store_value(vp, 0, NULL);
2021 }
2022
2023 r = UU_WALK_NEXT;
2024 goto out;
2025 }
2026 } else {
2027 if (t_pg == NULL && sc_pg) {
2028 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
2029 warn(gettext("Unable to create template "
2030 "property group to find a property "
2031 "type.\n"));
2032
2033 goto out;
2034 }
2035
2036 if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
2037 scf_tmpl_pg_destroy(t_pg);
2038 t_pg = NULL;
2039 } else {
2040 goto do_tmpl;
2041 }
2042 }
2043 }
2044
2045 if (issvc == 0) {
2046 scf_instance_t *i;
2047 scf_service_t *s;
2048
2049 issvc = 1;
2050 if (lcb->sc_flags == 1) {
2051 entity_t *e = pg->sc_parent->sc_parent;
2052
2053 fmri = e->sc_fmri;
2054 goto retry_pg;
2055 }
2056
2057 /*
2058 * because lcb->sc_flags was not set then this means
2059 * the pg was not used and can be used here.
2060 */
2061 if ((pg = internal_pgroup_new()) == NULL) {
2062 warn(gettext("Could not create internal property group "
2063 "to find a missing type."));
2064
2065 goto out;
2066 }
2067
2068 pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1);
2069 if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name,
2070 max_scf_name_len + 1) < 0)
2071 goto out;
2072
2073 i = scf_instance_create(g_hndl);
2074 s = scf_service_create(g_hndl);
2075 if (i == NULL || s == NULL ||
2076 scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) {
2077 warn(gettext("Could not get a service for the instance "
2078 "to find a missing type."));
2079
2080 goto out;
2081 }
2082
2083 /*
2084 * Check to see truly at the instance level.
2085 */
2086 lfmri = safe_malloc(max_scf_fmri_len + 1);
2087 if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
2088 scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0)
2089 goto out;
2090 else
2091 fmri = (const char *)lfmri;
2092
2093 goto retry_pg;
2094 }
2095
2096 out :
2097 if (sc_pg != lcb->sc_parent) {
2098 scf_pg_destroy(sc_pg);
2099 }
2100
2101 /*
2102 * If this is true then the pg was allocated
2103 * here, and the name was set so need to free
2104 * the name and the pg.
2105 */
2106 if (pg != NULL && pg != lcb->sc_parent) {
2107 free((char *)pg->sc_pgroup_name);
2108 internal_pgroup_free(pg);
2109 }
2110
2111 if (cur_selection) {
2112 lscf_select(cur_selection);
2113 free(cur_selection);
2114 }
2115
2116 scf_tmpl_pg_destroy(t_pg);
2117 scf_tmpl_prop_destroy(t_prop);
2118 scf_property_destroy(sc_prop);
2119
2120 if (r != UU_WALK_NEXT)
2121 warn(gettext("Could not find property type for \"%s\" "
2122 "from \"%s\"\n"), prop->sc_property_name,
2123 fmri != NULL ? fmri : lcb->sc_source_fmri);
2124
2125 free(lfmri);
2126
2127 return (r);
2128 }
2129
2130 /*
2131 * Take a property group that does not have a type and check to see if a type
2132 * exists or can be gleened from the current data. Set the type.
2133 *
2134 * Check the current level (instance) and then check the higher level
2135 * (service). This could be the case for adding a new property to
2136 * the instance that's going to "override" a service level property.
2137 *
2138 * For a property group
2139 * 1. Take the type from an existing property group
2140 * 2. Take the type from a template entry
2141 *
2142 * If the type can not be found, then leave the type as is, and let the import
2143 * report the problem of the missing type.
2144 */
2145 static int
find_current_pg_type(void * p,void * sori)2146 find_current_pg_type(void *p, void *sori)
2147 {
2148 entity_t *si = sori;
2149 pgroup_t *pg = p;
2150
2151 const char *ofmri, *fmri;
2152 char *cur_selection = NULL;
2153 char *pg_type = NULL;
2154
2155 scf_propertygroup_t *sc_pg = NULL;
2156 scf_pg_tmpl_t *t_pg = NULL;
2157
2158 int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2159 int r = UU_WALK_ERROR;
2160
2161 ofmri = fmri = si->sc_fmri;
2162 if (pg->sc_pgroup_type != NULL) {
2163 r = UU_WALK_NEXT;
2164
2165 goto out;
2166 }
2167
2168 sc_pg = scf_pg_create(g_hndl);
2169 if (sc_pg == NULL) {
2170 warn(gettext("Unable to create property group to attempt "
2171 "and find a missing type.\n"));
2172
2173 return (UU_WALK_ERROR);
2174 }
2175
2176 /*
2177 * Using get_pg() requires that the cur_svc/cur_inst be
2178 * via lscf_select. Need to preserve the current selection
2179 * if going to use lscf_select() to set up the cur_svc/cur_inst
2180 */
2181 if (cur_svc) {
2182 cur_selection = safe_malloc(max_scf_fmri_len + 1);
2183 lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1);
2184 }
2185
2186 /*
2187 * If the property group exists get the type, and set
2188 * the pgroup_t type of that type.
2189 *
2190 * If not the check for a template pg_pattern entry
2191 * and take the type from that.
2192 */
2193 retry_svc:
2194 lscf_select(fmri);
2195
2196 if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) {
2197 pg_type = safe_malloc(max_scf_pg_type_len + 1);
2198 if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type,
2199 max_scf_pg_type_len + 1) != -1) {
2200 pg->sc_pgroup_type = pg_type;
2201
2202 r = UU_WALK_NEXT;
2203 goto out;
2204 } else {
2205 free(pg_type);
2206 }
2207 } else {
2208 if ((t_pg == NULL) &&
2209 (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
2210 goto out;
2211
2212 if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name,
2213 NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS &&
2214 scf_tmpl_pg_type(t_pg, &pg_type) != -1) {
2215 pg->sc_pgroup_type = pg_type;
2216
2217 r = UU_WALK_NEXT;
2218 goto out;
2219 }
2220 }
2221
2222 /*
2223 * If type is not found at the instance level then attempt to
2224 * find the type at the service level.
2225 */
2226 if (!issvc) {
2227 si = si->sc_parent;
2228 fmri = si->sc_fmri;
2229 issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2230 goto retry_svc;
2231 }
2232
2233 out :
2234 if (cur_selection) {
2235 lscf_select(cur_selection);
2236 free(cur_selection);
2237 }
2238
2239 /*
2240 * Now walk the properties of the property group to make sure that
2241 * all properties have the correct type and values are valid for
2242 * those types.
2243 */
2244 if (r == UU_WALK_NEXT) {
2245 scf_callback_t cb;
2246
2247 cb.sc_service = issvc;
2248 cb.sc_source_fmri = ofmri;
2249 if (sc_pg != NULL) {
2250 cb.sc_parent = sc_pg;
2251 cb.sc_flags = 0;
2252 } else {
2253 cb.sc_parent = pg;
2254 cb.sc_flags = 1;
2255 }
2256
2257 if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type,
2258 &cb, UU_DEFAULT) != 0) {
2259 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2260 bad_error("uu_list_walk", uu_error());
2261
2262 r = UU_WALK_ERROR;
2263 }
2264 } else {
2265 warn(gettext("Could not find property group type for "
2266 "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri);
2267 }
2268
2269 scf_tmpl_pg_destroy(t_pg);
2270 scf_pg_destroy(sc_pg);
2271
2272 return (r);
2273 }
2274
2275 /*
2276 * Import. These functions import a bundle into the repository.
2277 */
2278
2279 /*
2280 * Add a transaction entry to lcbdata->sc_trans for this property_t. Uses
2281 * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata. On success,
2282 * returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
2283 * lcbdata->sc_err to
2284 * ENOMEM - out of memory
2285 * ECONNABORTED - repository connection broken
2286 * ECANCELED - sc_trans's property group was deleted
2287 * EINVAL - p's name is invalid (error printed)
2288 * - p has an invalid value (error printed)
2289 */
2290 static int
lscf_property_import(void * v,void * pvt)2291 lscf_property_import(void *v, void *pvt)
2292 {
2293 property_t *p = v;
2294 scf_callback_t *lcbdata = pvt;
2295 value_t *vp;
2296 scf_transaction_t *trans = lcbdata->sc_trans;
2297 scf_transaction_entry_t *entr;
2298 scf_value_t *val;
2299 scf_type_t tp;
2300
2301 if ((lcbdata->sc_flags & SCI_NOENABLED ||
2302 lcbdata->sc_flags & SCI_DELAYENABLE) &&
2303 strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
2304 lcbdata->sc_enable = p;
2305 return (UU_WALK_NEXT);
2306 }
2307
2308 entr = scf_entry_create(lcbdata->sc_handle);
2309 if (entr == NULL) {
2310 switch (scf_error()) {
2311 case SCF_ERROR_NO_MEMORY:
2312 return (stash_scferror(lcbdata));
2313
2314 case SCF_ERROR_INVALID_ARGUMENT:
2315 default:
2316 bad_error("scf_entry_create", scf_error());
2317 }
2318 }
2319
2320 tp = p->sc_value_type;
2321
2322 if (scf_transaction_property_new(trans, entr,
2323 p->sc_property_name, tp) != 0) {
2324 switch (scf_error()) {
2325 case SCF_ERROR_INVALID_ARGUMENT:
2326 semerr(emsg_invalid_prop_name, p->sc_property_name);
2327 scf_entry_destroy(entr);
2328 return (stash_scferror(lcbdata));
2329
2330 case SCF_ERROR_EXISTS:
2331 break;
2332
2333 case SCF_ERROR_DELETED:
2334 case SCF_ERROR_CONNECTION_BROKEN:
2335 scf_entry_destroy(entr);
2336 return (stash_scferror(lcbdata));
2337
2338 case SCF_ERROR_NOT_BOUND:
2339 case SCF_ERROR_HANDLE_MISMATCH:
2340 case SCF_ERROR_NOT_SET:
2341 default:
2342 bad_error("scf_transaction_property_new", scf_error());
2343 }
2344
2345 if (scf_transaction_property_change_type(trans, entr,
2346 p->sc_property_name, tp) != 0) {
2347 switch (scf_error()) {
2348 case SCF_ERROR_DELETED:
2349 case SCF_ERROR_CONNECTION_BROKEN:
2350 scf_entry_destroy(entr);
2351 return (stash_scferror(lcbdata));
2352
2353 case SCF_ERROR_INVALID_ARGUMENT:
2354 semerr(emsg_invalid_prop_name,
2355 p->sc_property_name);
2356 scf_entry_destroy(entr);
2357 return (stash_scferror(lcbdata));
2358
2359 case SCF_ERROR_NOT_FOUND:
2360 case SCF_ERROR_NOT_SET:
2361 case SCF_ERROR_HANDLE_MISMATCH:
2362 case SCF_ERROR_NOT_BOUND:
2363 default:
2364 bad_error(
2365 "scf_transaction_property_change_type",
2366 scf_error());
2367 }
2368 }
2369 }
2370
2371 for (vp = uu_list_first(p->sc_property_values);
2372 vp != NULL;
2373 vp = uu_list_next(p->sc_property_values, vp)) {
2374 val = scf_value_create(g_hndl);
2375 if (val == NULL) {
2376 switch (scf_error()) {
2377 case SCF_ERROR_NO_MEMORY:
2378 return (stash_scferror(lcbdata));
2379
2380 case SCF_ERROR_INVALID_ARGUMENT:
2381 default:
2382 bad_error("scf_value_create", scf_error());
2383 }
2384 }
2385
2386 switch (tp) {
2387 case SCF_TYPE_BOOLEAN:
2388 scf_value_set_boolean(val, vp->sc_u.sc_count);
2389 break;
2390 case SCF_TYPE_COUNT:
2391 scf_value_set_count(val, vp->sc_u.sc_count);
2392 break;
2393 case SCF_TYPE_INTEGER:
2394 scf_value_set_integer(val, vp->sc_u.sc_integer);
2395 break;
2396 default:
2397 assert(vp->sc_u.sc_string != NULL);
2398 if (scf_value_set_from_string(val, tp,
2399 vp->sc_u.sc_string) != 0) {
2400 if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
2401 bad_error("scf_value_set_from_string",
2402 scf_error());
2403
2404 warn(gettext("Value \"%s\" is not a valid "
2405 "%s.\n"), vp->sc_u.sc_string,
2406 scf_type_to_string(tp));
2407 scf_value_destroy(val);
2408 return (stash_scferror(lcbdata));
2409 }
2410 break;
2411 }
2412
2413 if (scf_entry_add_value(entr, val) != 0)
2414 bad_error("scf_entry_add_value", scf_error());
2415 }
2416
2417 return (UU_WALK_NEXT);
2418 }
2419
2420 /*
2421 * Import a pgroup_t into the repository. Uses sc_handle, sc_parent,
2422 * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2423 * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2424 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
2425 * lcbdata->sc_err to
2426 * ECONNABORTED - repository connection broken
2427 * ENOMEM - out of memory
2428 * ENOSPC - svc.configd is out of resources
2429 * ECANCELED - sc_parent was deleted
2430 * EPERM - could not create property group (permission denied) (error printed)
2431 * - could not modify property group (permission denied) (error printed)
2432 * - could not delete property group (permission denied) (error printed)
2433 * EROFS - could not create property group (repository is read-only)
2434 * - could not delete property group (repository is read-only)
2435 * EACCES - could not create property group (backend access denied)
2436 * - could not delete property group (backend access denied)
2437 * EEXIST - could not create property group (already exists)
2438 * EINVAL - invalid property group name (error printed)
2439 * - invalid property name (error printed)
2440 * - invalid value (error printed)
2441 * EBUSY - new property group deleted (error printed)
2442 * - new property group changed (error printed)
2443 * - property group added (error printed)
2444 * - property group deleted (error printed)
2445 */
2446 static int
entity_pgroup_import(void * v,void * pvt)2447 entity_pgroup_import(void *v, void *pvt)
2448 {
2449 pgroup_t *p = v;
2450 scf_callback_t cbdata;
2451 scf_callback_t *lcbdata = pvt;
2452 void *ent = lcbdata->sc_parent;
2453 int issvc = lcbdata->sc_service;
2454 int r;
2455
2456 const char * const pg_changed = gettext("%s changed unexpectedly "
2457 "(new property group \"%s\" changed).\n");
2458
2459 /* Never import deleted property groups. */
2460 if (p->sc_pgroup_delete) {
2461 if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY &&
2462 entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) {
2463 goto delete_pg;
2464 }
2465 return (UU_WALK_NEXT);
2466 }
2467
2468 if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
2469 strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
2470 lcbdata->sc_general = p;
2471 return (UU_WALK_NEXT);
2472 }
2473
2474 add_pg:
2475 if (issvc)
2476 r = scf_service_add_pg(ent, p->sc_pgroup_name,
2477 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2478 else
2479 r = scf_instance_add_pg(ent, p->sc_pgroup_name,
2480 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2481 if (r != 0) {
2482 switch (scf_error()) {
2483 case SCF_ERROR_DELETED:
2484 case SCF_ERROR_CONNECTION_BROKEN:
2485 case SCF_ERROR_BACKEND_READONLY:
2486 case SCF_ERROR_BACKEND_ACCESS:
2487 case SCF_ERROR_NO_RESOURCES:
2488 return (stash_scferror(lcbdata));
2489
2490 case SCF_ERROR_EXISTS:
2491 if (lcbdata->sc_flags & SCI_FORCE)
2492 break;
2493 return (stash_scferror(lcbdata));
2494
2495 case SCF_ERROR_INVALID_ARGUMENT:
2496 warn(emsg_fmri_invalid_pg_name_type,
2497 lcbdata->sc_source_fmri,
2498 p->sc_pgroup_name, p->sc_pgroup_type);
2499 return (stash_scferror(lcbdata));
2500
2501 case SCF_ERROR_PERMISSION_DENIED:
2502 warn(emsg_pg_add_perm, p->sc_pgroup_name,
2503 lcbdata->sc_target_fmri);
2504 return (stash_scferror(lcbdata));
2505
2506 case SCF_ERROR_NOT_BOUND:
2507 case SCF_ERROR_HANDLE_MISMATCH:
2508 case SCF_ERROR_NOT_SET:
2509 default:
2510 bad_error("scf_service_add_pg", scf_error());
2511 }
2512
2513 if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2514 switch (scf_error()) {
2515 case SCF_ERROR_CONNECTION_BROKEN:
2516 case SCF_ERROR_DELETED:
2517 return (stash_scferror(lcbdata));
2518
2519 case SCF_ERROR_INVALID_ARGUMENT:
2520 warn(emsg_fmri_invalid_pg_name,
2521 lcbdata->sc_source_fmri,
2522 p->sc_pgroup_name);
2523 return (stash_scferror(lcbdata));
2524
2525 case SCF_ERROR_NOT_FOUND:
2526 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2527 p->sc_pgroup_name);
2528 lcbdata->sc_err = EBUSY;
2529 return (UU_WALK_ERROR);
2530
2531 case SCF_ERROR_NOT_BOUND:
2532 case SCF_ERROR_HANDLE_MISMATCH:
2533 case SCF_ERROR_NOT_SET:
2534 default:
2535 bad_error("entity_get_pg", scf_error());
2536 }
2537 }
2538
2539 if (lcbdata->sc_flags & SCI_KEEP)
2540 goto props;
2541
2542 delete_pg:
2543 if (scf_pg_delete(imp_pg) != 0) {
2544 switch (scf_error()) {
2545 case SCF_ERROR_DELETED:
2546 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2547 p->sc_pgroup_name);
2548 lcbdata->sc_err = EBUSY;
2549 return (UU_WALK_ERROR);
2550
2551 case SCF_ERROR_PERMISSION_DENIED:
2552 warn(emsg_pg_del_perm, p->sc_pgroup_name,
2553 lcbdata->sc_target_fmri);
2554 return (stash_scferror(lcbdata));
2555
2556 case SCF_ERROR_BACKEND_READONLY:
2557 case SCF_ERROR_BACKEND_ACCESS:
2558 case SCF_ERROR_CONNECTION_BROKEN:
2559 return (stash_scferror(lcbdata));
2560
2561 case SCF_ERROR_NOT_SET:
2562 default:
2563 bad_error("scf_pg_delete", scf_error());
2564 }
2565 }
2566
2567 if (p->sc_pgroup_delete)
2568 return (UU_WALK_NEXT);
2569
2570 goto add_pg;
2571 }
2572
2573 props:
2574
2575 /*
2576 * Add properties to property group, if any.
2577 */
2578 cbdata.sc_handle = lcbdata->sc_handle;
2579 cbdata.sc_parent = imp_pg;
2580 cbdata.sc_flags = lcbdata->sc_flags;
2581 cbdata.sc_trans = imp_tx;
2582 cbdata.sc_enable = NULL;
2583
2584 if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2585 switch (scf_error()) {
2586 case SCF_ERROR_BACKEND_ACCESS:
2587 case SCF_ERROR_BACKEND_READONLY:
2588 case SCF_ERROR_CONNECTION_BROKEN:
2589 return (stash_scferror(lcbdata));
2590
2591 case SCF_ERROR_DELETED:
2592 warn(pg_changed, lcbdata->sc_target_fmri,
2593 p->sc_pgroup_name);
2594 lcbdata->sc_err = EBUSY;
2595 return (UU_WALK_ERROR);
2596
2597 case SCF_ERROR_PERMISSION_DENIED:
2598 warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2599 lcbdata->sc_target_fmri);
2600 return (stash_scferror(lcbdata));
2601
2602 case SCF_ERROR_NOT_BOUND:
2603 case SCF_ERROR_NOT_SET:
2604 case SCF_ERROR_IN_USE:
2605 case SCF_ERROR_HANDLE_MISMATCH:
2606 default:
2607 bad_error("scf_transaction_start", scf_error());
2608 }
2609 }
2610
2611 if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2612 UU_DEFAULT) != 0) {
2613 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2614 bad_error("uu_list_walk", uu_error());
2615 scf_transaction_reset(imp_tx);
2616
2617 lcbdata->sc_err = cbdata.sc_err;
2618 if (cbdata.sc_err == ECANCELED) {
2619 warn(pg_changed, lcbdata->sc_target_fmri,
2620 p->sc_pgroup_name);
2621 lcbdata->sc_err = EBUSY;
2622 }
2623 return (UU_WALK_ERROR);
2624 }
2625
2626 if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2627 cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2628
2629 /*
2630 * take the snapshot running snapshot then
2631 * import the stored general/enable property
2632 */
2633 r = take_snap(ent, snap_running, imp_rsnap);
2634 switch (r) {
2635 case 0:
2636 break;
2637
2638 case ECONNABORTED:
2639 warn(gettext("Could not take %s snapshot on import "
2640 "(repository connection broken).\n"),
2641 snap_running);
2642 lcbdata->sc_err = r;
2643 return (UU_WALK_ERROR);
2644 case ECANCELED:
2645 warn(emsg_deleted);
2646 lcbdata->sc_err = r;
2647 return (UU_WALK_ERROR);
2648
2649 case EPERM:
2650 warn(gettext("Could not take %s snapshot "
2651 "(permission denied).\n"), snap_running);
2652 lcbdata->sc_err = r;
2653 return (UU_WALK_ERROR);
2654
2655 case ENOSPC:
2656 warn(gettext("Could not take %s snapshot"
2657 "(repository server out of resources).\n"),
2658 snap_running);
2659 lcbdata->sc_err = r;
2660 return (UU_WALK_ERROR);
2661
2662 default:
2663 bad_error("take_snap", r);
2664 }
2665
2666 r = lscf_property_import(cbdata.sc_enable, &cbdata);
2667 if (r != UU_WALK_NEXT) {
2668 if (r != UU_WALK_ERROR)
2669 bad_error("lscf_property_import", r);
2670 return (EINVAL);
2671 }
2672 }
2673
2674 r = scf_transaction_commit(imp_tx);
2675 switch (r) {
2676 case 1:
2677 r = UU_WALK_NEXT;
2678 break;
2679
2680 case 0:
2681 warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2682 lcbdata->sc_err = EBUSY;
2683 r = UU_WALK_ERROR;
2684 break;
2685
2686 case -1:
2687 switch (scf_error()) {
2688 case SCF_ERROR_BACKEND_READONLY:
2689 case SCF_ERROR_BACKEND_ACCESS:
2690 case SCF_ERROR_CONNECTION_BROKEN:
2691 case SCF_ERROR_NO_RESOURCES:
2692 r = stash_scferror(lcbdata);
2693 break;
2694
2695 case SCF_ERROR_DELETED:
2696 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2697 p->sc_pgroup_name);
2698 lcbdata->sc_err = EBUSY;
2699 r = UU_WALK_ERROR;
2700 break;
2701
2702 case SCF_ERROR_PERMISSION_DENIED:
2703 warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2704 lcbdata->sc_target_fmri);
2705 r = stash_scferror(lcbdata);
2706 break;
2707
2708 case SCF_ERROR_NOT_SET:
2709 case SCF_ERROR_INVALID_ARGUMENT:
2710 case SCF_ERROR_NOT_BOUND:
2711 default:
2712 bad_error("scf_transaction_commit", scf_error());
2713 }
2714 break;
2715
2716 default:
2717 bad_error("scf_transaction_commit", r);
2718 }
2719
2720 scf_transaction_destroy_children(imp_tx);
2721
2722 return (r);
2723 }
2724
2725 /*
2726 * Returns
2727 * 0 - success
2728 * ECONNABORTED - repository connection broken
2729 * ENOMEM - out of memory
2730 * ENOSPC - svc.configd is out of resources
2731 * ECANCELED - inst was deleted
2732 * EPERM - could not create property group (permission denied) (error printed)
2733 * - could not modify property group (permission denied) (error printed)
2734 * EROFS - could not create property group (repository is read-only)
2735 * EACCES - could not create property group (backend access denied)
2736 * EEXIST - could not create property group (already exists)
2737 * EINVAL - invalid property group name (error printed)
2738 * - invalid property name (error printed)
2739 * - invalid value (error printed)
2740 * EBUSY - new property group changed (error printed)
2741 */
2742 static int
lscf_import_service_pgs(scf_service_t * svc,const char * target_fmri,const entity_t * isvc,int flags)2743 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2744 const entity_t *isvc, int flags)
2745 {
2746 scf_callback_t cbdata;
2747
2748 cbdata.sc_handle = scf_service_handle(svc);
2749 cbdata.sc_parent = svc;
2750 cbdata.sc_service = 1;
2751 cbdata.sc_general = 0;
2752 cbdata.sc_enable = 0;
2753 cbdata.sc_flags = flags;
2754 cbdata.sc_source_fmri = isvc->sc_fmri;
2755 cbdata.sc_target_fmri = target_fmri;
2756
2757 /*
2758 * If the op is set, then add the flag to the callback
2759 * flags for later use.
2760 */
2761 if (isvc->sc_op != SVCCFG_OP_NONE) {
2762 switch (isvc->sc_op) {
2763 case SVCCFG_OP_IMPORT :
2764 cbdata.sc_flags |= SCI_OP_IMPORT;
2765 break;
2766 case SVCCFG_OP_APPLY :
2767 cbdata.sc_flags |= SCI_OP_APPLY;
2768 break;
2769 case SVCCFG_OP_RESTORE :
2770 cbdata.sc_flags |= SCI_OP_RESTORE;
2771 break;
2772 default :
2773 uu_die(gettext("lscf_import_service_pgs : "
2774 "Unknown op stored in the service entity\n"));
2775
2776 }
2777 }
2778
2779 if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2780 UU_DEFAULT) != 0) {
2781 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2782 bad_error("uu_list_walk", uu_error());
2783
2784 return (cbdata.sc_err);
2785 }
2786
2787 return (0);
2788 }
2789
2790 /*
2791 * Returns
2792 * 0 - success
2793 * ECONNABORTED - repository connection broken
2794 * ENOMEM - out of memory
2795 * ENOSPC - svc.configd is out of resources
2796 * ECANCELED - inst was deleted
2797 * EPERM - could not create property group (permission denied) (error printed)
2798 * - could not modify property group (permission denied) (error printed)
2799 * EROFS - could not create property group (repository is read-only)
2800 * EACCES - could not create property group (backend access denied)
2801 * EEXIST - could not create property group (already exists)
2802 * EINVAL - invalid property group name (error printed)
2803 * - invalid property name (error printed)
2804 * - invalid value (error printed)
2805 * EBUSY - new property group changed (error printed)
2806 */
2807 static int
lscf_import_instance_pgs(scf_instance_t * inst,const char * target_fmri,const entity_t * iinst,int flags)2808 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2809 const entity_t *iinst, int flags)
2810 {
2811 scf_callback_t cbdata;
2812
2813 cbdata.sc_handle = scf_instance_handle(inst);
2814 cbdata.sc_parent = inst;
2815 cbdata.sc_service = 0;
2816 cbdata.sc_general = NULL;
2817 cbdata.sc_enable = NULL;
2818 cbdata.sc_flags = flags;
2819 cbdata.sc_source_fmri = iinst->sc_fmri;
2820 cbdata.sc_target_fmri = target_fmri;
2821
2822 /*
2823 * If the op is set, then add the flag to the callback
2824 * flags for later use.
2825 */
2826 if (iinst->sc_op != SVCCFG_OP_NONE) {
2827 switch (iinst->sc_op) {
2828 case SVCCFG_OP_IMPORT :
2829 cbdata.sc_flags |= SCI_OP_IMPORT;
2830 break;
2831 case SVCCFG_OP_APPLY :
2832 cbdata.sc_flags |= SCI_OP_APPLY;
2833 break;
2834 case SVCCFG_OP_RESTORE :
2835 cbdata.sc_flags |= SCI_OP_RESTORE;
2836 break;
2837 default :
2838 uu_die(gettext("lscf_import_instance_pgs : "
2839 "Unknown op stored in the instance entity\n"));
2840 }
2841 }
2842
2843 if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2844 UU_DEFAULT) != 0) {
2845 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2846 bad_error("uu_list_walk", uu_error());
2847
2848 return (cbdata.sc_err);
2849 }
2850
2851 if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2852 cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2853 /*
2854 * If importing with the SCI_NOENABLED flag then
2855 * skip the delay, but if not then add the delay
2856 * of the enable property.
2857 */
2858 if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2859 cbdata.sc_flags |= SCI_DELAYENABLE;
2860 }
2861
2862 if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2863 != UU_WALK_NEXT)
2864 return (cbdata.sc_err);
2865 }
2866
2867 return (0);
2868 }
2869
2870 /*
2871 * Report the reasons why we can't upgrade pg2 to pg1.
2872 */
2873 static void
report_pg_diffs(const pgroup_t * pg1,const pgroup_t * pg2,const char * fmri,int new)2874 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2875 int new)
2876 {
2877 property_t *p1, *p2;
2878
2879 assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2880
2881 if (!pg_attrs_equal(pg1, pg2, fmri, new))
2882 return;
2883
2884 for (p1 = uu_list_first(pg1->sc_pgroup_props);
2885 p1 != NULL;
2886 p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2887 p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2888 if (p2 != NULL) {
2889 (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2890 new);
2891 continue;
2892 }
2893
2894 if (new)
2895 warn(gettext("Conflict upgrading %s (new property "
2896 "group \"%s\" is missing property \"%s\").\n"),
2897 fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2898 else
2899 warn(gettext("Conflict upgrading %s (property "
2900 "\"%s/%s\" is missing).\n"), fmri,
2901 pg1->sc_pgroup_name, p1->sc_property_name);
2902 }
2903
2904 /*
2905 * Since pg1 should be from the manifest, any properties in pg2 which
2906 * aren't in pg1 shouldn't be reported as conflicts.
2907 */
2908 }
2909
2910 /*
2911 * Add transaction entries to tx which will upgrade cur's pg according to old
2912 * & new.
2913 *
2914 * Returns
2915 * 0 - success
2916 * EINVAL - new has a property with an invalid name or value (message emitted)
2917 * ENOMEM - out of memory
2918 */
2919 static int
add_upgrade_entries(scf_transaction_t * tx,pgroup_t * old,pgroup_t * new,pgroup_t * cur,int speak,const char * fmri)2920 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2921 pgroup_t *cur, int speak, const char *fmri)
2922 {
2923 property_t *p, *new_p, *cur_p;
2924 scf_transaction_entry_t *e;
2925 int r;
2926 int is_general;
2927 int is_protected;
2928
2929 if (uu_list_walk(new->sc_pgroup_props, clear_int,
2930 (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2931 bad_error("uu_list_walk", uu_error());
2932
2933 is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2934
2935 for (p = uu_list_first(old->sc_pgroup_props);
2936 p != NULL;
2937 p = uu_list_next(old->sc_pgroup_props, p)) {
2938 /* p is a property in the old property group. */
2939
2940 /* Protect live properties. */
2941 is_protected = 0;
2942 if (is_general) {
2943 if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2944 0 ||
2945 strcmp(p->sc_property_name,
2946 SCF_PROPERTY_RESTARTER) == 0)
2947 is_protected = 1;
2948 }
2949
2950 /* Look for the same property in the new properties. */
2951 new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2952 if (new_p != NULL) {
2953 new_p->sc_seen = 1;
2954
2955 /*
2956 * If the new property is the same as the old, don't do
2957 * anything (leave any user customizations).
2958 */
2959 if (prop_equal(p, new_p, NULL, NULL, 0))
2960 continue;
2961
2962 if (new_p->sc_property_override)
2963 goto upgrade;
2964 }
2965
2966 cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2967 if (cur_p == NULL) {
2968 /*
2969 * p has been deleted from the repository. If we were
2970 * going to delete it anyway, do nothing. Otherwise
2971 * report a conflict.
2972 */
2973 if (new_p == NULL)
2974 continue;
2975
2976 if (is_protected)
2977 continue;
2978
2979 warn(gettext("Conflict upgrading %s "
2980 "(property \"%s/%s\" is missing).\n"), fmri,
2981 old->sc_pgroup_name, p->sc_property_name);
2982 continue;
2983 }
2984
2985 if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2986 /*
2987 * Conflict. Don't warn if the property is already the
2988 * way we want it, though.
2989 */
2990 if (is_protected)
2991 continue;
2992
2993 if (new_p == NULL)
2994 (void) prop_equal(p, cur_p, fmri,
2995 old->sc_pgroup_name, 0);
2996 else
2997 (void) prop_equal(cur_p, new_p, fmri,
2998 old->sc_pgroup_name, 0);
2999 continue;
3000 }
3001
3002 if (is_protected) {
3003 if (speak)
3004 warn(gettext("%s: Refusing to upgrade "
3005 "\"%s/%s\" (live property).\n"), fmri,
3006 old->sc_pgroup_name, p->sc_property_name);
3007 continue;
3008 }
3009
3010 upgrade:
3011 /* p hasn't been customized in the repository. Upgrade it. */
3012 if (new_p == NULL) {
3013 /* p was deleted. Delete from cur if unchanged. */
3014 if (speak)
3015 warn(gettext(
3016 "%s: Deleting property \"%s/%s\".\n"),
3017 fmri, old->sc_pgroup_name,
3018 p->sc_property_name);
3019
3020 e = scf_entry_create(g_hndl);
3021 if (e == NULL)
3022 return (ENOMEM);
3023
3024 if (scf_transaction_property_delete(tx, e,
3025 p->sc_property_name) != 0) {
3026 switch (scf_error()) {
3027 case SCF_ERROR_DELETED:
3028 scf_entry_destroy(e);
3029 return (ECANCELED);
3030
3031 case SCF_ERROR_CONNECTION_BROKEN:
3032 scf_entry_destroy(e);
3033 return (ECONNABORTED);
3034
3035 case SCF_ERROR_NOT_FOUND:
3036 /*
3037 * This can happen if cur is from the
3038 * running snapshot (and it differs
3039 * from the live properties).
3040 */
3041 scf_entry_destroy(e);
3042 break;
3043
3044 case SCF_ERROR_HANDLE_MISMATCH:
3045 case SCF_ERROR_NOT_BOUND:
3046 case SCF_ERROR_NOT_SET:
3047 case SCF_ERROR_INVALID_ARGUMENT:
3048 default:
3049 bad_error(
3050 "scf_transaction_property_delete",
3051 scf_error());
3052 }
3053 }
3054 } else {
3055 scf_callback_t ctx;
3056
3057 if (speak)
3058 warn(gettext(
3059 "%s: Upgrading property \"%s/%s\".\n"),
3060 fmri, old->sc_pgroup_name,
3061 p->sc_property_name);
3062
3063 ctx.sc_handle = g_hndl;
3064 ctx.sc_trans = tx;
3065 ctx.sc_flags = 0;
3066
3067 r = lscf_property_import(new_p, &ctx);
3068 if (r != UU_WALK_NEXT) {
3069 if (r != UU_WALK_ERROR)
3070 bad_error("lscf_property_import", r);
3071 return (EINVAL);
3072 }
3073 }
3074 }
3075
3076 /* Go over the properties which were added. */
3077 for (new_p = uu_list_first(new->sc_pgroup_props);
3078 new_p != NULL;
3079 new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
3080 if (new_p->sc_seen)
3081 continue;
3082
3083 /* This is a new property. */
3084 cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
3085 if (cur_p == NULL) {
3086 scf_callback_t ctx;
3087
3088 ctx.sc_handle = g_hndl;
3089 ctx.sc_trans = tx;
3090 ctx.sc_flags = 0;
3091
3092 r = lscf_property_import(new_p, &ctx);
3093 if (r != UU_WALK_NEXT) {
3094 if (r != UU_WALK_ERROR)
3095 bad_error("lscf_property_import", r);
3096 return (EINVAL);
3097 }
3098 continue;
3099 }
3100
3101 /*
3102 * Report a conflict if the new property differs from the
3103 * current one. Unless it's general/enabled, since that's
3104 * never in the last-import snapshot.
3105 */
3106 if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
3107 0 &&
3108 strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
3109 continue;
3110
3111 (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
3112 }
3113
3114 return (0);
3115 }
3116
3117 /*
3118 * Upgrade pg according to old & new.
3119 *
3120 * Returns
3121 * 0 - success
3122 * ECONNABORTED - repository connection broken
3123 * ENOMEM - out of memory
3124 * ENOSPC - svc.configd is out of resources
3125 * ECANCELED - pg was deleted
3126 * EPERM - couldn't modify pg (permission denied)
3127 * EROFS - couldn't modify pg (backend read-only)
3128 * EACCES - couldn't modify pg (backend access denied)
3129 * EINVAL - new has a property with invalid name or value (error printed)
3130 * EBUSY - pg changed unexpectedly
3131 */
3132 static int
upgrade_pg(scf_propertygroup_t * pg,pgroup_t * cur,pgroup_t * old,pgroup_t * new,int speak,const char * fmri)3133 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
3134 pgroup_t *new, int speak, const char *fmri)
3135 {
3136 int r;
3137
3138 if (scf_transaction_start(imp_tx, pg) != 0) {
3139 switch (scf_error()) {
3140 case SCF_ERROR_CONNECTION_BROKEN:
3141 case SCF_ERROR_DELETED:
3142 case SCF_ERROR_PERMISSION_DENIED:
3143 case SCF_ERROR_BACKEND_READONLY:
3144 case SCF_ERROR_BACKEND_ACCESS:
3145 return (scferror2errno(scf_error()));
3146
3147 case SCF_ERROR_HANDLE_MISMATCH:
3148 case SCF_ERROR_IN_USE:
3149 case SCF_ERROR_NOT_BOUND:
3150 case SCF_ERROR_NOT_SET:
3151 default:
3152 bad_error("scf_transaction_start", scf_error());
3153 }
3154 }
3155
3156 r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
3157 switch (r) {
3158 case 0:
3159 break;
3160
3161 case EINVAL:
3162 case ENOMEM:
3163 scf_transaction_destroy_children(imp_tx);
3164 return (r);
3165
3166 default:
3167 bad_error("add_upgrade_entries", r);
3168 }
3169
3170 r = scf_transaction_commit(imp_tx);
3171
3172 scf_transaction_destroy_children(imp_tx);
3173
3174 switch (r) {
3175 case 1:
3176 break;
3177
3178 case 0:
3179 return (EBUSY);
3180
3181 case -1:
3182 switch (scf_error()) {
3183 case SCF_ERROR_CONNECTION_BROKEN:
3184 case SCF_ERROR_NO_RESOURCES:
3185 case SCF_ERROR_PERMISSION_DENIED:
3186 case SCF_ERROR_BACKEND_READONLY:
3187 case SCF_ERROR_BACKEND_ACCESS:
3188 case SCF_ERROR_DELETED:
3189 return (scferror2errno(scf_error()));
3190
3191 case SCF_ERROR_NOT_BOUND:
3192 case SCF_ERROR_INVALID_ARGUMENT:
3193 case SCF_ERROR_NOT_SET:
3194 default:
3195 bad_error("scf_transaction_commit", scf_error());
3196 }
3197
3198 default:
3199 bad_error("scf_transaction_commit", r);
3200 }
3201
3202 return (0);
3203 }
3204
3205 /*
3206 * Compares two entity FMRIs. Returns
3207 *
3208 * 1 - equal
3209 * 0 - not equal
3210 * -1 - f1 is invalid or not an entity
3211 * -2 - f2 is invalid or not an entity
3212 */
3213 static int
fmri_equal(const char * f1,const char * f2)3214 fmri_equal(const char *f1, const char *f2)
3215 {
3216 int r;
3217 const char *s1, *i1, *pg1;
3218 const char *s2, *i2, *pg2;
3219
3220 if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3221 return (-1);
3222 if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
3223 return (-1);
3224
3225 if (s1 == NULL || pg1 != NULL)
3226 return (-1);
3227
3228 if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3229 return (-2);
3230 if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
3231 return (-2);
3232
3233 if (s2 == NULL || pg2 != NULL)
3234 return (-2);
3235
3236 r = strcmp(s1, s2);
3237 if (r != 0)
3238 return (0);
3239
3240 if (i1 == NULL && i2 == NULL)
3241 return (1);
3242
3243 if (i1 == NULL || i2 == NULL)
3244 return (0);
3245
3246 return (strcmp(i1, i2) == 0);
3247 }
3248
3249 /*
3250 * Import a dependent by creating a dependency property group in the dependent
3251 * entity. If lcbdata->sc_trans is set, assume it's been started on the
3252 * dependents pg, and add an entry to create a new property for this
3253 * dependent. Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3254 *
3255 * On success, returns UU_WALK_NEXT. On error, returns UU_WALK_ERROR and sets
3256 * lcbdata->sc_err to
3257 * ECONNABORTED - repository connection broken
3258 * ENOMEM - out of memory
3259 * ENOSPC - configd is out of resources
3260 * EINVAL - target is invalid (error printed)
3261 * - target is not an entity (error printed)
3262 * - dependent has invalid name (error printed)
3263 * - invalid property name (error printed)
3264 * - invalid value (error printed)
3265 * - scope of target does not exist (error printed)
3266 * EPERM - couldn't create target (permission denied) (error printed)
3267 * - couldn't create dependency pg (permission denied) (error printed)
3268 * - couldn't modify dependency pg (permission denied) (error printed)
3269 * EROFS - couldn't create target (repository read-only)
3270 * - couldn't create dependency pg (repository read-only)
3271 * EACCES - couldn't create target (backend access denied)
3272 * - couldn't create dependency pg (backend access denied)
3273 * ECANCELED - sc_trans's pg was deleted
3274 * EALREADY - property for dependent already exists in sc_trans's pg
3275 * EEXIST - dependency pg already exists in target (error printed)
3276 * EBUSY - target deleted (error printed)
3277 * - property group changed during import (error printed)
3278 */
3279 static int
lscf_dependent_import(void * a1,void * pvt)3280 lscf_dependent_import(void *a1, void *pvt)
3281 {
3282 pgroup_t *pgrp = a1;
3283 scf_callback_t *lcbdata = pvt;
3284
3285 int isservice;
3286 int ret;
3287 scf_transaction_entry_t *e;
3288 scf_value_t *val;
3289 scf_callback_t dependent_cbdata;
3290 scf_error_t scfe;
3291
3292 /*
3293 * Decode the FMRI into dependent_cbdata->sc_parent. Do it here so if
3294 * it's invalid, we fail before modifying the repository.
3295 */
3296 scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3297 &dependent_cbdata.sc_parent, &isservice);
3298 switch (scfe) {
3299 case SCF_ERROR_NONE:
3300 break;
3301
3302 case SCF_ERROR_NO_MEMORY:
3303 return (stash_scferror_err(lcbdata, scfe));
3304
3305 case SCF_ERROR_INVALID_ARGUMENT:
3306 semerr(gettext("The FMRI for the \"%s\" dependent is "
3307 "invalid.\n"), pgrp->sc_pgroup_name);
3308 return (stash_scferror_err(lcbdata, scfe));
3309
3310 case SCF_ERROR_CONSTRAINT_VIOLATED:
3311 semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3312 "specifies neither a service nor an instance.\n"),
3313 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3314 return (stash_scferror_err(lcbdata, scfe));
3315
3316 case SCF_ERROR_NOT_FOUND:
3317 scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3318 &dependent_cbdata.sc_parent, &isservice);
3319 switch (scfe) {
3320 case SCF_ERROR_NONE:
3321 break;
3322
3323 case SCF_ERROR_NO_MEMORY:
3324 case SCF_ERROR_BACKEND_READONLY:
3325 case SCF_ERROR_BACKEND_ACCESS:
3326 return (stash_scferror_err(lcbdata, scfe));
3327
3328 case SCF_ERROR_NOT_FOUND:
3329 semerr(gettext("The scope in FMRI \"%s\" for the "
3330 "\"%s\" dependent does not exist.\n"),
3331 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3332 lcbdata->sc_err = EINVAL;
3333 return (UU_WALK_ERROR);
3334
3335 case SCF_ERROR_PERMISSION_DENIED:
3336 warn(gettext(
3337 "Could not create %s (permission denied).\n"),
3338 pgrp->sc_pgroup_fmri);
3339 return (stash_scferror_err(lcbdata, scfe));
3340
3341 case SCF_ERROR_INVALID_ARGUMENT:
3342 case SCF_ERROR_CONSTRAINT_VIOLATED:
3343 default:
3344 bad_error("create_entity", scfe);
3345 }
3346 break;
3347
3348 default:
3349 bad_error("fmri_to_entity", scfe);
3350 }
3351
3352 if (lcbdata->sc_trans != NULL) {
3353 e = scf_entry_create(lcbdata->sc_handle);
3354 if (e == NULL) {
3355 if (scf_error() != SCF_ERROR_NO_MEMORY)
3356 bad_error("scf_entry_create", scf_error());
3357
3358 entity_destroy(dependent_cbdata.sc_parent, isservice);
3359 return (stash_scferror(lcbdata));
3360 }
3361
3362 if (scf_transaction_property_new(lcbdata->sc_trans, e,
3363 pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
3364 switch (scf_error()) {
3365 case SCF_ERROR_INVALID_ARGUMENT:
3366 warn(gettext("Dependent of %s has invalid name "
3367 "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
3368 pgrp->sc_pgroup_name);
3369 /* FALLTHROUGH */
3370
3371 case SCF_ERROR_DELETED:
3372 case SCF_ERROR_CONNECTION_BROKEN:
3373 scf_entry_destroy(e);
3374 entity_destroy(dependent_cbdata.sc_parent,
3375 isservice);
3376 return (stash_scferror(lcbdata));
3377
3378 case SCF_ERROR_EXISTS:
3379 scf_entry_destroy(e);
3380 entity_destroy(dependent_cbdata.sc_parent,
3381 isservice);
3382 lcbdata->sc_err = EALREADY;
3383 return (UU_WALK_ERROR);
3384
3385 case SCF_ERROR_NOT_BOUND:
3386 case SCF_ERROR_HANDLE_MISMATCH:
3387 case SCF_ERROR_NOT_SET:
3388 default:
3389 bad_error("scf_transaction_property_new",
3390 scf_error());
3391 }
3392 }
3393
3394 val = scf_value_create(lcbdata->sc_handle);
3395 if (val == NULL) {
3396 if (scf_error() != SCF_ERROR_NO_MEMORY)
3397 bad_error("scf_value_create", scf_error());
3398
3399 entity_destroy(dependent_cbdata.sc_parent, isservice);
3400 return (stash_scferror(lcbdata));
3401 }
3402
3403 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
3404 pgrp->sc_pgroup_fmri) != 0)
3405 /* invalid should have been caught above */
3406 bad_error("scf_value_set_from_string", scf_error());
3407
3408 if (scf_entry_add_value(e, val) != 0)
3409 bad_error("scf_entry_add_value", scf_error());
3410 }
3411
3412 /* Add the property group to the target entity. */
3413
3414 dependent_cbdata.sc_handle = lcbdata->sc_handle;
3415 dependent_cbdata.sc_flags = lcbdata->sc_flags;
3416 dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
3417 dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
3418
3419 ret = entity_pgroup_import(pgrp, &dependent_cbdata);
3420
3421 entity_destroy(dependent_cbdata.sc_parent, isservice);
3422
3423 if (ret == UU_WALK_NEXT)
3424 return (ret);
3425
3426 if (ret != UU_WALK_ERROR)
3427 bad_error("entity_pgroup_import", ret);
3428
3429 switch (dependent_cbdata.sc_err) {
3430 case ECANCELED:
3431 warn(gettext("%s deleted unexpectedly.\n"),
3432 pgrp->sc_pgroup_fmri);
3433 lcbdata->sc_err = EBUSY;
3434 break;
3435
3436 case EEXIST:
3437 warn(gettext("Could not create \"%s\" dependency in %s "
3438 "(already exists).\n"), pgrp->sc_pgroup_name,
3439 pgrp->sc_pgroup_fmri);
3440 /* FALLTHROUGH */
3441
3442 default:
3443 lcbdata->sc_err = dependent_cbdata.sc_err;
3444 }
3445
3446 return (UU_WALK_ERROR);
3447 }
3448
3449 static int upgrade_dependent(const scf_property_t *, const entity_t *,
3450 const scf_snaplevel_t *, scf_transaction_t *);
3451 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
3452 const pgroup_t *);
3453
3454 /*
3455 * Upgrade uncustomized dependents of ent to those specified in ient. Read
3456 * the current dependent targets from running (the snaplevel of a running
3457 * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3458 * scf_instance_t * according to ient, otherwise). Draw the ancestral
3459 * dependent targets and dependency properties from li_dpts_pg (the
3460 * "dependents" property group in snpl) and snpl (the snaplevel which
3461 * corresponds to ent in a last-import snapshot). If li_dpts_pg is NULL, then
3462 * snpl doesn't have a "dependents" property group, and any dependents in ient
3463 * are new.
3464 *
3465 * Returns
3466 * 0 - success
3467 * ECONNABORTED - repository connection broken
3468 * ENOMEM - out of memory
3469 * ENOSPC - configd is out of resources
3470 * ECANCELED - ent was deleted
3471 * ENODEV - the entity containing li_dpts_pg was deleted
3472 * EPERM - could not modify dependents pg (permission denied) (error printed)
3473 * - couldn't upgrade dependent (permission denied) (error printed)
3474 * - couldn't create dependent (permission denied) (error printed)
3475 * EROFS - could not modify dependents pg (repository read-only)
3476 * - couldn't upgrade dependent (repository read-only)
3477 * - couldn't create dependent (repository read-only)
3478 * EACCES - could not modify dependents pg (backend access denied)
3479 * - could not upgrade dependent (backend access denied)
3480 * - could not create dependent (backend access denied)
3481 * EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3482 * - dependent target deleted (error printed)
3483 * - dependent pg changed (error printed)
3484 * EINVAL - new dependent is invalid (error printed)
3485 * EBADF - snpl is corrupt (error printed)
3486 * - snpl has corrupt pg (error printed)
3487 * - dependency pg in target is corrupt (error printed)
3488 * - target has corrupt snapshot (error printed)
3489 * EEXIST - dependency pg already existed in target service (error printed)
3490 */
3491 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)3492 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
3493 const scf_snaplevel_t *snpl, const entity_t *ient,
3494 const scf_snaplevel_t *running, void *ent)
3495 {
3496 pgroup_t *new_dpt_pgroup;
3497 scf_callback_t cbdata;
3498 int r, unseen, tx_started = 0;
3499 int have_cur_depts;
3500
3501 const char * const dependents = "dependents";
3502
3503 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3504
3505 if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
3506 /* Nothing to do. */
3507 return (0);
3508
3509 /* Fetch the current version of the "dependents" property group. */
3510 have_cur_depts = 1;
3511 if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
3512 switch (scf_error()) {
3513 case SCF_ERROR_NOT_FOUND:
3514 break;
3515
3516 case SCF_ERROR_DELETED:
3517 case SCF_ERROR_CONNECTION_BROKEN:
3518 return (scferror2errno(scf_error()));
3519
3520 case SCF_ERROR_NOT_SET:
3521 case SCF_ERROR_INVALID_ARGUMENT:
3522 case SCF_ERROR_HANDLE_MISMATCH:
3523 case SCF_ERROR_NOT_BOUND:
3524 default:
3525 bad_error("entity_get_pg", scf_error());
3526 }
3527
3528 have_cur_depts = 0;
3529 }
3530
3531 /* Fetch the running version of the "dependents" property group. */
3532 ud_run_dpts_pg_set = 0;
3533 if (running != NULL)
3534 r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
3535 else
3536 r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
3537 if (r == 0) {
3538 ud_run_dpts_pg_set = 1;
3539 } else {
3540 switch (scf_error()) {
3541 case SCF_ERROR_NOT_FOUND:
3542 break;
3543
3544 case SCF_ERROR_DELETED:
3545 case SCF_ERROR_CONNECTION_BROKEN:
3546 return (scferror2errno(scf_error()));
3547
3548 case SCF_ERROR_NOT_SET:
3549 case SCF_ERROR_INVALID_ARGUMENT:
3550 case SCF_ERROR_HANDLE_MISMATCH:
3551 case SCF_ERROR_NOT_BOUND:
3552 default:
3553 bad_error(running ? "scf_snaplevel_get_pg" :
3554 "entity_get_pg", scf_error());
3555 }
3556 }
3557
3558 /*
3559 * Clear the seen fields of the dependents, so we can tell which ones
3560 * are new.
3561 */
3562 if (uu_list_walk(ient->sc_dependents, clear_int,
3563 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3564 bad_error("uu_list_walk", uu_error());
3565
3566 if (li_dpts_pg != NULL) {
3567 /*
3568 * Each property in li_dpts_pg represents a dependent tag in
3569 * the old manifest. For each, call upgrade_dependent(),
3570 * which will change ud_cur_depts_pg or dependencies in other
3571 * services as appropriate. Note (a) that changes to
3572 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3573 * made en masse, and (b) it's ok if the entity doesn't have
3574 * a current version of the "dependents" property group,
3575 * because we'll just consider all dependents as customized
3576 * (by being deleted).
3577 */
3578
3579 if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3580 switch (scf_error()) {
3581 case SCF_ERROR_DELETED:
3582 return (ENODEV);
3583
3584 case SCF_ERROR_CONNECTION_BROKEN:
3585 return (ECONNABORTED);
3586
3587 case SCF_ERROR_HANDLE_MISMATCH:
3588 case SCF_ERROR_NOT_BOUND:
3589 case SCF_ERROR_NOT_SET:
3590 default:
3591 bad_error("scf_iter_pg_properties",
3592 scf_error());
3593 }
3594 }
3595
3596 if (have_cur_depts &&
3597 scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3598 switch (scf_error()) {
3599 case SCF_ERROR_BACKEND_ACCESS:
3600 case SCF_ERROR_BACKEND_READONLY:
3601 case SCF_ERROR_CONNECTION_BROKEN:
3602 return (scferror2errno(scf_error()));
3603
3604 case SCF_ERROR_DELETED:
3605 warn(emsg_pg_deleted, ient->sc_fmri,
3606 dependents);
3607 return (EBUSY);
3608
3609 case SCF_ERROR_PERMISSION_DENIED:
3610 warn(emsg_pg_mod_perm, dependents,
3611 ient->sc_fmri);
3612 return (scferror2errno(scf_error()));
3613
3614 case SCF_ERROR_HANDLE_MISMATCH:
3615 case SCF_ERROR_IN_USE:
3616 case SCF_ERROR_NOT_BOUND:
3617 case SCF_ERROR_NOT_SET:
3618 default:
3619 bad_error("scf_transaction_start", scf_error());
3620 }
3621 }
3622 tx_started = have_cur_depts;
3623
3624 for (;;) {
3625 r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3626 if (r == 0)
3627 break;
3628 if (r == 1) {
3629 r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3630 tx_started ? ud_tx : NULL);
3631 switch (r) {
3632 case 0:
3633 continue;
3634
3635 case ECONNABORTED:
3636 case ENOMEM:
3637 case ENOSPC:
3638 case EBADF:
3639 case EBUSY:
3640 case EINVAL:
3641 case EPERM:
3642 case EROFS:
3643 case EACCES:
3644 case EEXIST:
3645 break;
3646
3647 case ECANCELED:
3648 r = ENODEV;
3649 break;
3650
3651 default:
3652 bad_error("upgrade_dependent", r);
3653 }
3654
3655 if (tx_started)
3656 scf_transaction_destroy_children(ud_tx);
3657 return (r);
3658 }
3659 if (r != -1)
3660 bad_error("scf_iter_next_property", r);
3661
3662 switch (scf_error()) {
3663 case SCF_ERROR_DELETED:
3664 r = ENODEV;
3665 break;
3666
3667 case SCF_ERROR_CONNECTION_BROKEN:
3668 r = ECONNABORTED;
3669 break;
3670
3671 case SCF_ERROR_NOT_SET:
3672 case SCF_ERROR_INVALID_ARGUMENT:
3673 case SCF_ERROR_NOT_BOUND:
3674 case SCF_ERROR_HANDLE_MISMATCH:
3675 default:
3676 bad_error("scf_iter_next_property",
3677 scf_error());
3678 }
3679
3680 if (tx_started)
3681 scf_transaction_destroy_children(ud_tx);
3682 return (r);
3683 }
3684 }
3685
3686 /* import unseen dependents */
3687 unseen = 0;
3688 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3689 new_dpt_pgroup != NULL;
3690 new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3691 new_dpt_pgroup)) {
3692 if (!new_dpt_pgroup->sc_pgroup_seen) {
3693 unseen = 1;
3694 break;
3695 }
3696 }
3697
3698 /* If there are none, exit early. */
3699 if (unseen == 0)
3700 goto commit;
3701
3702 /* Set up for lscf_dependent_import() */
3703 cbdata.sc_handle = g_hndl;
3704 cbdata.sc_parent = ent;
3705 cbdata.sc_service = issvc;
3706 cbdata.sc_flags = 0;
3707
3708 if (!have_cur_depts) {
3709 /*
3710 * We have new dependents to import, so we need a "dependents"
3711 * property group.
3712 */
3713 if (issvc)
3714 r = scf_service_add_pg(ent, dependents,
3715 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3716 else
3717 r = scf_instance_add_pg(ent, dependents,
3718 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3719 if (r != 0) {
3720 switch (scf_error()) {
3721 case SCF_ERROR_DELETED:
3722 case SCF_ERROR_CONNECTION_BROKEN:
3723 case SCF_ERROR_BACKEND_READONLY:
3724 case SCF_ERROR_BACKEND_ACCESS:
3725 case SCF_ERROR_NO_RESOURCES:
3726 return (scferror2errno(scf_error()));
3727
3728 case SCF_ERROR_EXISTS:
3729 warn(emsg_pg_added, ient->sc_fmri, dependents);
3730 return (EBUSY);
3731
3732 case SCF_ERROR_PERMISSION_DENIED:
3733 warn(emsg_pg_add_perm, dependents,
3734 ient->sc_fmri);
3735 return (scferror2errno(scf_error()));
3736
3737 case SCF_ERROR_NOT_BOUND:
3738 case SCF_ERROR_HANDLE_MISMATCH:
3739 case SCF_ERROR_INVALID_ARGUMENT:
3740 case SCF_ERROR_NOT_SET:
3741 default:
3742 bad_error("scf_service_add_pg", scf_error());
3743 }
3744 }
3745 }
3746
3747 cbdata.sc_trans = ud_tx;
3748
3749 if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3750 switch (scf_error()) {
3751 case SCF_ERROR_CONNECTION_BROKEN:
3752 case SCF_ERROR_BACKEND_ACCESS:
3753 case SCF_ERROR_BACKEND_READONLY:
3754 return (scferror2errno(scf_error()));
3755
3756 case SCF_ERROR_DELETED:
3757 warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3758 return (EBUSY);
3759
3760 case SCF_ERROR_PERMISSION_DENIED:
3761 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3762 return (scferror2errno(scf_error()));
3763
3764 case SCF_ERROR_HANDLE_MISMATCH:
3765 case SCF_ERROR_IN_USE:
3766 case SCF_ERROR_NOT_BOUND:
3767 case SCF_ERROR_NOT_SET:
3768 default:
3769 bad_error("scf_transaction_start", scf_error());
3770 }
3771 }
3772 tx_started = 1;
3773
3774 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3775 new_dpt_pgroup != NULL;
3776 new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3777 new_dpt_pgroup)) {
3778 if (new_dpt_pgroup->sc_pgroup_seen)
3779 continue;
3780
3781 if (ud_run_dpts_pg_set) {
3782 /*
3783 * If the dependent is already there, then we have
3784 * a conflict.
3785 */
3786 if (scf_pg_get_property(ud_run_dpts_pg,
3787 new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3788 r = handle_dependent_conflict(ient, ud_prop,
3789 new_dpt_pgroup);
3790 switch (r) {
3791 case 0:
3792 continue;
3793
3794 case ECONNABORTED:
3795 case ENOMEM:
3796 case EBUSY:
3797 case EBADF:
3798 case EINVAL:
3799 scf_transaction_destroy_children(ud_tx);
3800 return (r);
3801
3802 default:
3803 bad_error("handle_dependent_conflict",
3804 r);
3805 }
3806 } else {
3807 switch (scf_error()) {
3808 case SCF_ERROR_NOT_FOUND:
3809 break;
3810
3811 case SCF_ERROR_INVALID_ARGUMENT:
3812 warn(emsg_fmri_invalid_pg_name,
3813 ient->sc_fmri,
3814 new_dpt_pgroup->sc_pgroup_name);
3815 scf_transaction_destroy_children(ud_tx);
3816 return (EINVAL);
3817
3818 case SCF_ERROR_DELETED:
3819 warn(emsg_pg_deleted, ient->sc_fmri,
3820 new_dpt_pgroup->sc_pgroup_name);
3821 scf_transaction_destroy_children(ud_tx);
3822 return (EBUSY);
3823
3824 case SCF_ERROR_CONNECTION_BROKEN:
3825 scf_transaction_destroy_children(ud_tx);
3826 return (ECONNABORTED);
3827
3828 case SCF_ERROR_NOT_BOUND:
3829 case SCF_ERROR_HANDLE_MISMATCH:
3830 case SCF_ERROR_NOT_SET:
3831 default:
3832 bad_error("scf_pg_get_property",
3833 scf_error());
3834 }
3835 }
3836 }
3837
3838 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3839 if (r != UU_WALK_NEXT) {
3840 if (r != UU_WALK_ERROR)
3841 bad_error("lscf_dependent_import", r);
3842
3843 if (cbdata.sc_err == EALREADY) {
3844 /* Collisions were handled preemptively. */
3845 bad_error("lscf_dependent_import",
3846 cbdata.sc_err);
3847 }
3848
3849 scf_transaction_destroy_children(ud_tx);
3850 return (cbdata.sc_err);
3851 }
3852 }
3853
3854 commit:
3855 if (!tx_started)
3856 return (0);
3857
3858 r = scf_transaction_commit(ud_tx);
3859
3860 scf_transaction_destroy_children(ud_tx);
3861
3862 switch (r) {
3863 case 1:
3864 return (0);
3865
3866 case 0:
3867 warn(emsg_pg_changed, ient->sc_fmri, dependents);
3868 return (EBUSY);
3869
3870 case -1:
3871 break;
3872
3873 default:
3874 bad_error("scf_transaction_commit", r);
3875 }
3876
3877 switch (scf_error()) {
3878 case SCF_ERROR_CONNECTION_BROKEN:
3879 case SCF_ERROR_BACKEND_READONLY:
3880 case SCF_ERROR_BACKEND_ACCESS:
3881 case SCF_ERROR_NO_RESOURCES:
3882 return (scferror2errno(scf_error()));
3883
3884 case SCF_ERROR_DELETED:
3885 warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3886 return (EBUSY);
3887
3888 case SCF_ERROR_PERMISSION_DENIED:
3889 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3890 return (scferror2errno(scf_error()));
3891
3892 case SCF_ERROR_NOT_BOUND:
3893 case SCF_ERROR_INVALID_ARGUMENT:
3894 case SCF_ERROR_NOT_SET:
3895 default:
3896 bad_error("scf_transaction_destroy", scf_error());
3897 /* NOTREACHED */
3898 }
3899 }
3900
3901 /*
3902 * Used to add the manifests to the list of currently supported manifests.
3903 * We can modify the existing manifest list removing entries if the files
3904 * don't exist.
3905 *
3906 * Get the old list and the new file name
3907 * If the new file name is in the list return
3908 * If not then add the file to the list.
3909 * As we process the list check to see if the files in the old list exist
3910 * if not then remove the file from the list.
3911 * Commit the list of manifest file names.
3912 *
3913 */
3914 static int
upgrade_manifestfiles(pgroup_t * pg,entity_t * ient,const scf_snaplevel_t * running,void * ent)3915 upgrade_manifestfiles(pgroup_t *pg, entity_t *ient,
3916 const scf_snaplevel_t *running, void *ent)
3917 {
3918 scf_propertygroup_t *ud_mfsts_pg = NULL;
3919 scf_property_t *ud_prop = NULL;
3920 scf_iter_t *ud_prop_iter;
3921 scf_value_t *fname_value;
3922 scf_callback_t cbdata;
3923 pgroup_t *mfst_pgroup;
3924 property_t *mfst_prop;
3925 property_t *old_prop;
3926 char *pname;
3927 char *fval;
3928 char *old_pname;
3929 char *old_fval;
3930 int no_upgrade_pg;
3931 int mfst_seen;
3932 int r;
3933
3934 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3935
3936 /*
3937 * This should always be the service base on the code
3938 * path, and the fact that the manifests pg is a service
3939 * level property group only.
3940 */
3941 ud_mfsts_pg = scf_pg_create(g_hndl);
3942 ud_prop = scf_property_create(g_hndl);
3943 ud_prop_iter = scf_iter_create(g_hndl);
3944 fname_value = scf_value_create(g_hndl);
3945
3946 /* Fetch the "manifests" property group */
3947 no_upgrade_pg = 0;
3948 r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3949 ud_mfsts_pg);
3950 if (r != 0) {
3951 switch (scf_error()) {
3952 case SCF_ERROR_NOT_FOUND:
3953 no_upgrade_pg = 1;
3954 break;
3955
3956 case SCF_ERROR_DELETED:
3957 case SCF_ERROR_CONNECTION_BROKEN:
3958 return (scferror2errno(scf_error()));
3959
3960 case SCF_ERROR_NOT_SET:
3961 case SCF_ERROR_INVALID_ARGUMENT:
3962 case SCF_ERROR_HANDLE_MISMATCH:
3963 case SCF_ERROR_NOT_BOUND:
3964 default:
3965 bad_error(running ? "scf_snaplevel_get_pg" :
3966 "entity_get_pg", scf_error());
3967 }
3968 }
3969
3970 if (no_upgrade_pg) {
3971 cbdata.sc_handle = g_hndl;
3972 cbdata.sc_parent = ent;
3973 cbdata.sc_service = issvc;
3974 cbdata.sc_flags = SCI_FORCE;
3975 cbdata.sc_source_fmri = ient->sc_fmri;
3976 cbdata.sc_target_fmri = ient->sc_fmri;
3977
3978 if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3979 return (cbdata.sc_err);
3980
3981 return (0);
3982 }
3983
3984 /* Fetch the new manifests property group */
3985 mfst_pgroup = internal_pgroup_find_or_create(ient,
3986 SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
3987 assert(mfst_pgroup != NULL);
3988
3989 if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3990 SCF_SUCCESS)
3991 return (-1);
3992
3993 if ((pname = malloc(MAXPATHLEN)) == NULL)
3994 return (ENOMEM);
3995 if ((fval = malloc(MAXPATHLEN)) == NULL) {
3996 free(pname);
3997 return (ENOMEM);
3998 }
3999
4000 while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
4001 mfst_seen = 0;
4002 if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
4003 continue;
4004
4005 for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
4006 mfst_prop != NULL;
4007 mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
4008 mfst_prop)) {
4009 if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
4010 mfst_seen = 1;
4011 }
4012 }
4013
4014 /*
4015 * If the manifest is not seen then add it to the new mfst
4016 * property list to get proccessed into the repo.
4017 */
4018 if (mfst_seen == 0) {
4019 /*
4020 * If we cannot get the value then there is no
4021 * reason to attempt to attach the value to
4022 * the property group
4023 */
4024 if (prop_get_val(ud_prop, fname_value) == 0 &&
4025 scf_value_get_astring(fname_value, fval,
4026 MAXPATHLEN) != -1) {
4027 old_pname = safe_strdup(pname);
4028 old_fval = safe_strdup(fval);
4029 old_prop = internal_property_create(old_pname,
4030 SCF_TYPE_ASTRING, 1, old_fval);
4031
4032 /*
4033 * Already checked to see if the property exists
4034 * in the group, and it does not.
4035 */
4036 (void) internal_attach_property(mfst_pgroup,
4037 old_prop);
4038 }
4039 }
4040 }
4041 free(pname);
4042 free(fval);
4043
4044 cbdata.sc_handle = g_hndl;
4045 cbdata.sc_parent = ent;
4046 cbdata.sc_service = issvc;
4047 cbdata.sc_flags = SCI_FORCE;
4048 cbdata.sc_source_fmri = ient->sc_fmri;
4049 cbdata.sc_target_fmri = ient->sc_fmri;
4050
4051 if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
4052 return (cbdata.sc_err);
4053
4054 return (r);
4055 }
4056
4057 /*
4058 * prop is taken to be a property in the "dependents" property group of snpl,
4059 * which is taken to be the snaplevel of a last-import snapshot corresponding
4060 * to ient. If prop is a valid dependents property, upgrade the dependent it
4061 * represents according to the repository & ient. If ud_run_dpts_pg_set is
4062 * true, then ud_run_dpts_pg is taken to be the "dependents" property group
4063 * of the entity ient represents (possibly in the running snapshot). If it
4064 * needs to be changed, an entry will be added to tx, if not NULL.
4065 *
4066 * Returns
4067 * 0 - success
4068 * ECONNABORTED - repository connection broken
4069 * ENOMEM - out of memory
4070 * ENOSPC - configd was out of resources
4071 * ECANCELED - snpl's entity was deleted
4072 * EINVAL - dependent target is invalid (error printed)
4073 * - dependent is invalid (error printed)
4074 * EBADF - snpl is corrupt (error printed)
4075 * - snpl has corrupt pg (error printed)
4076 * - dependency pg in target is corrupt (error printed)
4077 * - running snapshot in dependent is missing snaplevel (error printed)
4078 * EPERM - couldn't delete dependency pg (permission denied) (error printed)
4079 * - couldn't create dependent (permission denied) (error printed)
4080 * - couldn't modify dependent pg (permission denied) (error printed)
4081 * EROFS - couldn't delete dependency pg (repository read-only)
4082 * - couldn't create dependent (repository read-only)
4083 * EACCES - couldn't delete dependency pg (backend access denied)
4084 * - couldn't create dependent (backend access denied)
4085 * EBUSY - ud_run_dpts_pg was deleted (error printed)
4086 * - tx's pg was deleted (error printed)
4087 * - dependent pg was changed or deleted (error printed)
4088 * EEXIST - dependency pg already exists in new target (error printed)
4089 */
4090 static int
upgrade_dependent(const scf_property_t * prop,const entity_t * ient,const scf_snaplevel_t * snpl,scf_transaction_t * tx)4091 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
4092 const scf_snaplevel_t *snpl, scf_transaction_t *tx)
4093 {
4094 pgroup_t pgrp;
4095 scf_type_t ty;
4096 pgroup_t *new_dpt_pgroup;
4097 pgroup_t *old_dpt_pgroup = NULL;
4098 pgroup_t *current_pg;
4099 pgroup_t *dpt;
4100 scf_callback_t cbdata;
4101 int tissvc;
4102 void *target_ent;
4103 scf_error_t serr;
4104 int r;
4105 scf_transaction_entry_t *ent;
4106
4107 const char * const cf_inval = gettext("Conflict upgrading %s "
4108 "(dependent \"%s\" has invalid dependents property).\n");
4109 const char * const cf_missing = gettext("Conflict upgrading %s "
4110 "(dependent \"%s\" is missing).\n");
4111 const char * const cf_newdpg = gettext("Conflict upgrading %s "
4112 "(dependent \"%s\" has new dependency property group).\n");
4113 const char * const cf_newtarg = gettext("Conflict upgrading %s "
4114 "(dependent \"%s\" has new target).\n");
4115 const char * const li_corrupt =
4116 gettext("%s: \"last-import\" snapshot is corrupt.\n");
4117 const char * const upgrading =
4118 gettext("%s: Upgrading dependent \"%s\".\n");
4119 const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
4120 "corrupt (missing snaplevel).\n");
4121
4122 if (scf_property_type(prop, &ty) != 0) {
4123 switch (scf_error()) {
4124 case SCF_ERROR_DELETED:
4125 case SCF_ERROR_CONNECTION_BROKEN:
4126 return (scferror2errno(scf_error()));
4127
4128 case SCF_ERROR_NOT_BOUND:
4129 case SCF_ERROR_NOT_SET:
4130 default:
4131 bad_error("scf_property_type", scf_error());
4132 }
4133 }
4134
4135 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4136 warn(li_corrupt, ient->sc_fmri);
4137 return (EBADF);
4138 }
4139
4140 /*
4141 * prop represents a dependent in the old manifest. It is named after
4142 * the dependent.
4143 */
4144 if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
4145 switch (scf_error()) {
4146 case SCF_ERROR_DELETED:
4147 case SCF_ERROR_CONNECTION_BROKEN:
4148 return (scferror2errno(scf_error()));
4149
4150 case SCF_ERROR_NOT_BOUND:
4151 case SCF_ERROR_NOT_SET:
4152 default:
4153 bad_error("scf_property_get_name", scf_error());
4154 }
4155 }
4156
4157 /* See if it's in the new manifest. */
4158 pgrp.sc_pgroup_name = ud_name;
4159 new_dpt_pgroup =
4160 uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
4161
4162 /* If it's not, delete it... if it hasn't been customized. */
4163 if (new_dpt_pgroup == NULL) {
4164 if (!ud_run_dpts_pg_set)
4165 return (0);
4166
4167 if (scf_property_get_value(prop, ud_val) != 0) {
4168 switch (scf_error()) {
4169 case SCF_ERROR_NOT_FOUND:
4170 case SCF_ERROR_CONSTRAINT_VIOLATED:
4171 warn(li_corrupt, ient->sc_fmri);
4172 return (EBADF);
4173
4174 case SCF_ERROR_DELETED:
4175 case SCF_ERROR_CONNECTION_BROKEN:
4176 return (scferror2errno(scf_error()));
4177
4178 case SCF_ERROR_HANDLE_MISMATCH:
4179 case SCF_ERROR_NOT_BOUND:
4180 case SCF_ERROR_NOT_SET:
4181 case SCF_ERROR_PERMISSION_DENIED:
4182 default:
4183 bad_error("scf_property_get_value",
4184 scf_error());
4185 }
4186 }
4187
4188 if (scf_value_get_as_string(ud_val, ud_oldtarg,
4189 max_scf_value_len + 1) < 0)
4190 bad_error("scf_value_get_as_string", scf_error());
4191
4192 if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
4193 0) {
4194 switch (scf_error()) {
4195 case SCF_ERROR_NOT_FOUND:
4196 return (0);
4197
4198 case SCF_ERROR_CONNECTION_BROKEN:
4199 return (scferror2errno(scf_error()));
4200
4201 case SCF_ERROR_DELETED:
4202 warn(emsg_pg_deleted, ient->sc_fmri,
4203 "dependents");
4204 return (EBUSY);
4205
4206 case SCF_ERROR_INVALID_ARGUMENT:
4207 case SCF_ERROR_NOT_BOUND:
4208 case SCF_ERROR_HANDLE_MISMATCH:
4209 case SCF_ERROR_NOT_SET:
4210 default:
4211 bad_error("scf_pg_get_property", scf_error());
4212 }
4213 }
4214 if (scf_property_get_value(ud_prop, ud_val) != 0) {
4215 switch (scf_error()) {
4216 case SCF_ERROR_NOT_FOUND:
4217 case SCF_ERROR_CONSTRAINT_VIOLATED:
4218 warn(cf_inval, ient->sc_fmri, ud_name);
4219 return (0);
4220
4221 case SCF_ERROR_DELETED:
4222 case SCF_ERROR_CONNECTION_BROKEN:
4223 return (scferror2errno(scf_error()));
4224
4225 case SCF_ERROR_HANDLE_MISMATCH:
4226 case SCF_ERROR_NOT_BOUND:
4227 case SCF_ERROR_NOT_SET:
4228 case SCF_ERROR_PERMISSION_DENIED:
4229 default:
4230 bad_error("scf_property_get_value",
4231 scf_error());
4232 }
4233 }
4234
4235 ty = scf_value_type(ud_val);
4236 assert(ty != SCF_TYPE_INVALID);
4237 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4238 warn(cf_inval, ient->sc_fmri, ud_name);
4239 return (0);
4240 }
4241
4242 if (scf_value_get_as_string(ud_val, ud_ctarg,
4243 max_scf_value_len + 1) < 0)
4244 bad_error("scf_value_get_as_string", scf_error());
4245
4246 r = fmri_equal(ud_ctarg, ud_oldtarg);
4247 switch (r) {
4248 case 1:
4249 break;
4250
4251 case 0:
4252 case -1: /* warn? */
4253 warn(cf_newtarg, ient->sc_fmri, ud_name);
4254 return (0);
4255
4256 case -2:
4257 warn(li_corrupt, ient->sc_fmri);
4258 return (EBADF);
4259
4260 default:
4261 bad_error("fmri_equal", r);
4262 }
4263
4264 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4265 switch (scf_error()) {
4266 case SCF_ERROR_NOT_FOUND:
4267 warn(li_corrupt, ient->sc_fmri);
4268 return (EBADF);
4269
4270 case SCF_ERROR_DELETED:
4271 case SCF_ERROR_CONNECTION_BROKEN:
4272 return (scferror2errno(scf_error()));
4273
4274 case SCF_ERROR_NOT_BOUND:
4275 case SCF_ERROR_HANDLE_MISMATCH:
4276 case SCF_ERROR_INVALID_ARGUMENT:
4277 case SCF_ERROR_NOT_SET:
4278 default:
4279 bad_error("scf_snaplevel_get_pg", scf_error());
4280 }
4281 }
4282
4283 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4284 snap_lastimport);
4285 switch (r) {
4286 case 0:
4287 break;
4288
4289 case ECANCELED:
4290 case ECONNABORTED:
4291 case ENOMEM:
4292 case EBADF:
4293 return (r);
4294
4295 case EACCES:
4296 default:
4297 bad_error("load_pg", r);
4298 }
4299
4300 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4301 switch (serr) {
4302 case SCF_ERROR_NONE:
4303 break;
4304
4305 case SCF_ERROR_NO_MEMORY:
4306 internal_pgroup_free(old_dpt_pgroup);
4307 return (ENOMEM);
4308
4309 case SCF_ERROR_NOT_FOUND:
4310 internal_pgroup_free(old_dpt_pgroup);
4311 goto delprop;
4312
4313 case SCF_ERROR_CONSTRAINT_VIOLATED: /* caught above */
4314 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
4315 default:
4316 bad_error("fmri_to_entity", serr);
4317 }
4318
4319 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4320 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4321 switch (r) {
4322 case 0:
4323 break;
4324
4325 case ECONNABORTED:
4326 internal_pgroup_free(old_dpt_pgroup);
4327 return (r);
4328
4329 case ECANCELED:
4330 case ENOENT:
4331 internal_pgroup_free(old_dpt_pgroup);
4332 goto delprop;
4333
4334 case EBADF:
4335 warn(r_no_lvl, ud_ctarg);
4336 internal_pgroup_free(old_dpt_pgroup);
4337 return (r);
4338
4339 case EINVAL:
4340 default:
4341 bad_error("entity_get_running_pg", r);
4342 }
4343
4344 /* load it */
4345 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4346 switch (r) {
4347 case 0:
4348 break;
4349
4350 case ECANCELED:
4351 internal_pgroup_free(old_dpt_pgroup);
4352 goto delprop;
4353
4354 case ECONNABORTED:
4355 case ENOMEM:
4356 case EBADF:
4357 internal_pgroup_free(old_dpt_pgroup);
4358 return (r);
4359
4360 case EACCES:
4361 default:
4362 bad_error("load_pg", r);
4363 }
4364
4365 /* compare property groups */
4366 if (!pg_equal(old_dpt_pgroup, current_pg)) {
4367 warn(cf_newdpg, ient->sc_fmri, ud_name);
4368 internal_pgroup_free(old_dpt_pgroup);
4369 internal_pgroup_free(current_pg);
4370 return (0);
4371 }
4372
4373 internal_pgroup_free(old_dpt_pgroup);
4374 internal_pgroup_free(current_pg);
4375
4376 if (g_verbose)
4377 warn(gettext("%s: Deleting dependent \"%s\".\n"),
4378 ient->sc_fmri, ud_name);
4379
4380 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4381 switch (scf_error()) {
4382 case SCF_ERROR_NOT_FOUND:
4383 case SCF_ERROR_DELETED:
4384 internal_pgroup_free(old_dpt_pgroup);
4385 goto delprop;
4386
4387 case SCF_ERROR_CONNECTION_BROKEN:
4388 internal_pgroup_free(old_dpt_pgroup);
4389 return (ECONNABORTED);
4390
4391 case SCF_ERROR_NOT_SET:
4392 case SCF_ERROR_INVALID_ARGUMENT:
4393 case SCF_ERROR_HANDLE_MISMATCH:
4394 case SCF_ERROR_NOT_BOUND:
4395 default:
4396 bad_error("entity_get_pg", scf_error());
4397 }
4398 }
4399
4400 if (scf_pg_delete(ud_pg) != 0) {
4401 switch (scf_error()) {
4402 case SCF_ERROR_DELETED:
4403 break;
4404
4405 case SCF_ERROR_CONNECTION_BROKEN:
4406 case SCF_ERROR_BACKEND_READONLY:
4407 case SCF_ERROR_BACKEND_ACCESS:
4408 return (scferror2errno(scf_error()));
4409
4410 case SCF_ERROR_PERMISSION_DENIED:
4411 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4412 return (scferror2errno(scf_error()));
4413
4414 case SCF_ERROR_NOT_SET:
4415 default:
4416 bad_error("scf_pg_delete", scf_error());
4417 }
4418 }
4419
4420 /*
4421 * This service was changed, so it must be refreshed. But
4422 * since it's not mentioned in the new manifest, we have to
4423 * record its FMRI here for use later. We record the name
4424 * & the entity (via sc_parent) in case we need to print error
4425 * messages during the refresh.
4426 */
4427 dpt = internal_pgroup_new();
4428 if (dpt == NULL)
4429 return (ENOMEM);
4430 dpt->sc_pgroup_name = strdup(ud_name);
4431 dpt->sc_pgroup_fmri = strdup(ud_ctarg);
4432 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4433 return (ENOMEM);
4434 dpt->sc_parent = (entity_t *)ient;
4435 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4436 uu_die(gettext("libuutil error: %s\n"),
4437 uu_strerror(uu_error()));
4438
4439 delprop:
4440 if (tx == NULL)
4441 return (0);
4442
4443 ent = scf_entry_create(g_hndl);
4444 if (ent == NULL)
4445 return (ENOMEM);
4446
4447 if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
4448 scf_entry_destroy(ent);
4449 switch (scf_error()) {
4450 case SCF_ERROR_DELETED:
4451 warn(emsg_pg_deleted, ient->sc_fmri,
4452 "dependents");
4453 return (EBUSY);
4454
4455 case SCF_ERROR_CONNECTION_BROKEN:
4456 return (scferror2errno(scf_error()));
4457
4458 case SCF_ERROR_NOT_FOUND:
4459 break;
4460
4461 case SCF_ERROR_HANDLE_MISMATCH:
4462 case SCF_ERROR_NOT_BOUND:
4463 case SCF_ERROR_INVALID_ARGUMENT:
4464 case SCF_ERROR_NOT_SET:
4465 default:
4466 bad_error("scf_transaction_property_delete",
4467 scf_error());
4468 }
4469 }
4470
4471 return (0);
4472 }
4473
4474 new_dpt_pgroup->sc_pgroup_seen = 1;
4475
4476 /*
4477 * Decide whether the dependent has changed in the manifest.
4478 */
4479 /* Compare the target. */
4480 if (scf_property_get_value(prop, ud_val) != 0) {
4481 switch (scf_error()) {
4482 case SCF_ERROR_NOT_FOUND:
4483 case SCF_ERROR_CONSTRAINT_VIOLATED:
4484 warn(li_corrupt, ient->sc_fmri);
4485 return (EBADF);
4486
4487 case SCF_ERROR_DELETED:
4488 case SCF_ERROR_CONNECTION_BROKEN:
4489 return (scferror2errno(scf_error()));
4490
4491 case SCF_ERROR_HANDLE_MISMATCH:
4492 case SCF_ERROR_NOT_BOUND:
4493 case SCF_ERROR_NOT_SET:
4494 case SCF_ERROR_PERMISSION_DENIED:
4495 default:
4496 bad_error("scf_property_get_value", scf_error());
4497 }
4498 }
4499
4500 if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
4501 0)
4502 bad_error("scf_value_get_as_string", scf_error());
4503
4504 /*
4505 * If the fmri's are not equal then the old fmri will need to
4506 * be refreshed to ensure that the changes are properly updated
4507 * in that service.
4508 */
4509 r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
4510 switch (r) {
4511 case 0:
4512 dpt = internal_pgroup_new();
4513 if (dpt == NULL)
4514 return (ENOMEM);
4515 dpt->sc_pgroup_name = strdup(ud_name);
4516 dpt->sc_pgroup_fmri = strdup(ud_oldtarg);
4517 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4518 return (ENOMEM);
4519 dpt->sc_parent = (entity_t *)ient;
4520 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4521 uu_die(gettext("libuutil error: %s\n"),
4522 uu_strerror(uu_error()));
4523 break;
4524
4525 case 1:
4526 /* Compare the dependency pgs. */
4527 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4528 switch (scf_error()) {
4529 case SCF_ERROR_NOT_FOUND:
4530 warn(li_corrupt, ient->sc_fmri);
4531 return (EBADF);
4532
4533 case SCF_ERROR_DELETED:
4534 case SCF_ERROR_CONNECTION_BROKEN:
4535 return (scferror2errno(scf_error()));
4536
4537 case SCF_ERROR_NOT_BOUND:
4538 case SCF_ERROR_HANDLE_MISMATCH:
4539 case SCF_ERROR_INVALID_ARGUMENT:
4540 case SCF_ERROR_NOT_SET:
4541 default:
4542 bad_error("scf_snaplevel_get_pg", scf_error());
4543 }
4544 }
4545
4546 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4547 snap_lastimport);
4548 switch (r) {
4549 case 0:
4550 break;
4551
4552 case ECANCELED:
4553 case ECONNABORTED:
4554 case ENOMEM:
4555 case EBADF:
4556 return (r);
4557
4558 case EACCES:
4559 default:
4560 bad_error("load_pg", r);
4561 }
4562
4563 if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4564 /* no change, leave customizations */
4565 internal_pgroup_free(old_dpt_pgroup);
4566 return (0);
4567 }
4568 break;
4569
4570 case -1:
4571 warn(li_corrupt, ient->sc_fmri);
4572 return (EBADF);
4573
4574 case -2:
4575 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4576 ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4577 return (EINVAL);
4578
4579 default:
4580 bad_error("fmri_equal", r);
4581 }
4582
4583 /*
4584 * The dependent has changed in the manifest. Upgrade the current
4585 * properties if they haven't been customized.
4586 */
4587
4588 /*
4589 * If new_dpt_pgroup->sc_override, then act as though the property
4590 * group hasn't been customized.
4591 */
4592 if (new_dpt_pgroup->sc_pgroup_override) {
4593 (void) strcpy(ud_ctarg, ud_oldtarg);
4594 goto nocust;
4595 }
4596
4597 if (!ud_run_dpts_pg_set) {
4598 warn(cf_missing, ient->sc_fmri, ud_name);
4599 r = 0;
4600 goto out;
4601 } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4602 switch (scf_error()) {
4603 case SCF_ERROR_NOT_FOUND:
4604 warn(cf_missing, ient->sc_fmri, ud_name);
4605 r = 0;
4606 goto out;
4607
4608 case SCF_ERROR_CONNECTION_BROKEN:
4609 r = scferror2errno(scf_error());
4610 goto out;
4611
4612 case SCF_ERROR_DELETED:
4613 warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4614 r = EBUSY;
4615 goto out;
4616
4617 case SCF_ERROR_INVALID_ARGUMENT:
4618 case SCF_ERROR_NOT_BOUND:
4619 case SCF_ERROR_HANDLE_MISMATCH:
4620 case SCF_ERROR_NOT_SET:
4621 default:
4622 bad_error("scf_pg_get_property", scf_error());
4623 }
4624 }
4625
4626 if (scf_property_get_value(ud_prop, ud_val) != 0) {
4627 switch (scf_error()) {
4628 case SCF_ERROR_NOT_FOUND:
4629 case SCF_ERROR_CONSTRAINT_VIOLATED:
4630 warn(cf_inval, ient->sc_fmri, ud_name);
4631 r = 0;
4632 goto out;
4633
4634 case SCF_ERROR_DELETED:
4635 case SCF_ERROR_CONNECTION_BROKEN:
4636 r = scferror2errno(scf_error());
4637 goto out;
4638
4639 case SCF_ERROR_HANDLE_MISMATCH:
4640 case SCF_ERROR_NOT_BOUND:
4641 case SCF_ERROR_NOT_SET:
4642 case SCF_ERROR_PERMISSION_DENIED:
4643 default:
4644 bad_error("scf_property_get_value", scf_error());
4645 }
4646 }
4647
4648 ty = scf_value_type(ud_val);
4649 assert(ty != SCF_TYPE_INVALID);
4650 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4651 warn(cf_inval, ient->sc_fmri, ud_name);
4652 r = 0;
4653 goto out;
4654 }
4655 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4656 0)
4657 bad_error("scf_value_get_as_string", scf_error());
4658
4659 r = fmri_equal(ud_ctarg, ud_oldtarg);
4660 if (r == -1) {
4661 warn(cf_inval, ient->sc_fmri, ud_name);
4662 r = 0;
4663 goto out;
4664 } else if (r == -2) {
4665 warn(li_corrupt, ient->sc_fmri);
4666 r = EBADF;
4667 goto out;
4668 } else if (r == 0) {
4669 /*
4670 * Target has been changed. Only abort now if it's been
4671 * changed to something other than what's in the manifest.
4672 */
4673 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4674 if (r == -1) {
4675 warn(cf_inval, ient->sc_fmri, ud_name);
4676 r = 0;
4677 goto out;
4678 } else if (r == 0) {
4679 warn(cf_newtarg, ient->sc_fmri, ud_name);
4680 r = 0;
4681 goto out;
4682 } else if (r != 1) {
4683 /* invalid sc_pgroup_fmri caught above */
4684 bad_error("fmri_equal", r);
4685 }
4686
4687 /*
4688 * Fetch the current dependency pg. If it's what the manifest
4689 * says, then no problem.
4690 */
4691 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4692 switch (serr) {
4693 case SCF_ERROR_NONE:
4694 break;
4695
4696 case SCF_ERROR_NOT_FOUND:
4697 warn(cf_missing, ient->sc_fmri, ud_name);
4698 r = 0;
4699 goto out;
4700
4701 case SCF_ERROR_NO_MEMORY:
4702 r = ENOMEM;
4703 goto out;
4704
4705 case SCF_ERROR_CONSTRAINT_VIOLATED:
4706 case SCF_ERROR_INVALID_ARGUMENT:
4707 default:
4708 bad_error("fmri_to_entity", serr);
4709 }
4710
4711 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4712 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4713 switch (r) {
4714 case 0:
4715 break;
4716
4717 case ECONNABORTED:
4718 goto out;
4719
4720 case ECANCELED:
4721 case ENOENT:
4722 warn(cf_missing, ient->sc_fmri, ud_name);
4723 r = 0;
4724 goto out;
4725
4726 case EBADF:
4727 warn(r_no_lvl, ud_ctarg);
4728 goto out;
4729
4730 case EINVAL:
4731 default:
4732 bad_error("entity_get_running_pg", r);
4733 }
4734
4735 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4736 switch (r) {
4737 case 0:
4738 break;
4739
4740 case ECANCELED:
4741 warn(cf_missing, ient->sc_fmri, ud_name);
4742 r = 0;
4743 goto out;
4744
4745 case ECONNABORTED:
4746 case ENOMEM:
4747 case EBADF:
4748 goto out;
4749
4750 case EACCES:
4751 default:
4752 bad_error("load_pg", r);
4753 }
4754
4755 if (!pg_equal(current_pg, new_dpt_pgroup))
4756 warn(cf_newdpg, ient->sc_fmri, ud_name);
4757 internal_pgroup_free(current_pg);
4758 r = 0;
4759 goto out;
4760 } else if (r != 1) {
4761 bad_error("fmri_equal", r);
4762 }
4763
4764 nocust:
4765 /*
4766 * Target has not been customized. Check the dependency property
4767 * group.
4768 */
4769
4770 if (old_dpt_pgroup == NULL) {
4771 if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4772 ud_pg) != 0) {
4773 switch (scf_error()) {
4774 case SCF_ERROR_NOT_FOUND:
4775 warn(li_corrupt, ient->sc_fmri);
4776 return (EBADF);
4777
4778 case SCF_ERROR_DELETED:
4779 case SCF_ERROR_CONNECTION_BROKEN:
4780 return (scferror2errno(scf_error()));
4781
4782 case SCF_ERROR_NOT_BOUND:
4783 case SCF_ERROR_HANDLE_MISMATCH:
4784 case SCF_ERROR_INVALID_ARGUMENT:
4785 case SCF_ERROR_NOT_SET:
4786 default:
4787 bad_error("scf_snaplevel_get_pg", scf_error());
4788 }
4789 }
4790
4791 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4792 snap_lastimport);
4793 switch (r) {
4794 case 0:
4795 break;
4796
4797 case ECANCELED:
4798 case ECONNABORTED:
4799 case ENOMEM:
4800 case EBADF:
4801 return (r);
4802
4803 case EACCES:
4804 default:
4805 bad_error("load_pg", r);
4806 }
4807 }
4808 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4809 switch (serr) {
4810 case SCF_ERROR_NONE:
4811 break;
4812
4813 case SCF_ERROR_NOT_FOUND:
4814 warn(cf_missing, ient->sc_fmri, ud_name);
4815 r = 0;
4816 goto out;
4817
4818 case SCF_ERROR_NO_MEMORY:
4819 r = ENOMEM;
4820 goto out;
4821
4822 case SCF_ERROR_CONSTRAINT_VIOLATED:
4823 case SCF_ERROR_INVALID_ARGUMENT:
4824 default:
4825 bad_error("fmri_to_entity", serr);
4826 }
4827
4828 r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4829 ud_iter2, ud_inst, imp_snap, ud_snpl);
4830 switch (r) {
4831 case 0:
4832 break;
4833
4834 case ECONNABORTED:
4835 goto out;
4836
4837 case ECANCELED:
4838 case ENOENT:
4839 warn(cf_missing, ient->sc_fmri, ud_name);
4840 r = 0;
4841 goto out;
4842
4843 case EBADF:
4844 warn(r_no_lvl, ud_ctarg);
4845 goto out;
4846
4847 case EINVAL:
4848 default:
4849 bad_error("entity_get_running_pg", r);
4850 }
4851
4852 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4853 switch (r) {
4854 case 0:
4855 break;
4856
4857 case ECANCELED:
4858 warn(cf_missing, ient->sc_fmri, ud_name);
4859 goto out;
4860
4861 case ECONNABORTED:
4862 case ENOMEM:
4863 case EBADF:
4864 goto out;
4865
4866 case EACCES:
4867 default:
4868 bad_error("load_pg", r);
4869 }
4870
4871 if (!pg_equal(current_pg, old_dpt_pgroup)) {
4872 if (!pg_equal(current_pg, new_dpt_pgroup))
4873 warn(cf_newdpg, ient->sc_fmri, ud_name);
4874 internal_pgroup_free(current_pg);
4875 r = 0;
4876 goto out;
4877 }
4878
4879 /* Uncustomized. Upgrade. */
4880
4881 r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4882 switch (r) {
4883 case 1:
4884 if (pg_equal(current_pg, new_dpt_pgroup)) {
4885 /* Already upgraded. */
4886 internal_pgroup_free(current_pg);
4887 r = 0;
4888 goto out;
4889 }
4890
4891 internal_pgroup_free(current_pg);
4892
4893 /* upgrade current_pg */
4894 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4895 switch (scf_error()) {
4896 case SCF_ERROR_CONNECTION_BROKEN:
4897 r = scferror2errno(scf_error());
4898 goto out;
4899
4900 case SCF_ERROR_DELETED:
4901 warn(cf_missing, ient->sc_fmri, ud_name);
4902 r = 0;
4903 goto out;
4904
4905 case SCF_ERROR_NOT_FOUND:
4906 break;
4907
4908 case SCF_ERROR_INVALID_ARGUMENT:
4909 case SCF_ERROR_NOT_BOUND:
4910 case SCF_ERROR_NOT_SET:
4911 case SCF_ERROR_HANDLE_MISMATCH:
4912 default:
4913 bad_error("entity_get_pg", scf_error());
4914 }
4915
4916 if (tissvc)
4917 r = scf_service_add_pg(target_ent, ud_name,
4918 SCF_GROUP_DEPENDENCY, 0, ud_pg);
4919 else
4920 r = scf_instance_add_pg(target_ent, ud_name,
4921 SCF_GROUP_DEPENDENCY, 0, ud_pg);
4922 if (r != 0) {
4923 switch (scf_error()) {
4924 case SCF_ERROR_CONNECTION_BROKEN:
4925 case SCF_ERROR_NO_RESOURCES:
4926 case SCF_ERROR_BACKEND_READONLY:
4927 case SCF_ERROR_BACKEND_ACCESS:
4928 r = scferror2errno(scf_error());
4929 goto out;
4930
4931 case SCF_ERROR_DELETED:
4932 warn(cf_missing, ient->sc_fmri,
4933 ud_name);
4934 r = 0;
4935 goto out;
4936
4937 case SCF_ERROR_PERMISSION_DENIED:
4938 warn(emsg_pg_deleted, ud_ctarg,
4939 ud_name);
4940 r = EPERM;
4941 goto out;
4942
4943 case SCF_ERROR_EXISTS:
4944 warn(emsg_pg_added, ud_ctarg, ud_name);
4945 r = EBUSY;
4946 goto out;
4947
4948 case SCF_ERROR_NOT_BOUND:
4949 case SCF_ERROR_HANDLE_MISMATCH:
4950 case SCF_ERROR_INVALID_ARGUMENT:
4951 case SCF_ERROR_NOT_SET:
4952 default:
4953 bad_error("entity_add_pg", scf_error());
4954 }
4955 }
4956 }
4957
4958 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4959 switch (r) {
4960 case 0:
4961 break;
4962
4963 case ECANCELED:
4964 warn(cf_missing, ient->sc_fmri, ud_name);
4965 goto out;
4966
4967 case ECONNABORTED:
4968 case ENOMEM:
4969 case EBADF:
4970 goto out;
4971
4972 case EACCES:
4973 default:
4974 bad_error("load_pg", r);
4975 }
4976
4977 if (g_verbose)
4978 warn(upgrading, ient->sc_fmri, ud_name);
4979
4980 r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4981 new_dpt_pgroup, 0, ient->sc_fmri);
4982 switch (r) {
4983 case 0:
4984 break;
4985
4986 case ECANCELED:
4987 warn(emsg_pg_deleted, ud_ctarg, ud_name);
4988 r = EBUSY;
4989 goto out;
4990
4991 case EPERM:
4992 warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4993 goto out;
4994
4995 case EBUSY:
4996 warn(emsg_pg_changed, ud_ctarg, ud_name);
4997 goto out;
4998
4999 case ECONNABORTED:
5000 case ENOMEM:
5001 case ENOSPC:
5002 case EROFS:
5003 case EACCES:
5004 case EINVAL:
5005 goto out;
5006
5007 default:
5008 bad_error("upgrade_pg", r);
5009 }
5010 break;
5011
5012 case 0: {
5013 scf_transaction_entry_t *ent;
5014 scf_value_t *val;
5015
5016 internal_pgroup_free(current_pg);
5017
5018 /* delete old pg */
5019 if (g_verbose)
5020 warn(upgrading, ient->sc_fmri, ud_name);
5021
5022 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
5023 switch (scf_error()) {
5024 case SCF_ERROR_CONNECTION_BROKEN:
5025 r = scferror2errno(scf_error());
5026 goto out;
5027
5028 case SCF_ERROR_DELETED:
5029 warn(cf_missing, ient->sc_fmri, ud_name);
5030 r = 0;
5031 goto out;
5032
5033 case SCF_ERROR_NOT_FOUND:
5034 break;
5035
5036 case SCF_ERROR_INVALID_ARGUMENT:
5037 case SCF_ERROR_NOT_BOUND:
5038 case SCF_ERROR_NOT_SET:
5039 case SCF_ERROR_HANDLE_MISMATCH:
5040 default:
5041 bad_error("entity_get_pg", scf_error());
5042 }
5043 } else if (scf_pg_delete(ud_pg) != 0) {
5044 switch (scf_error()) {
5045 case SCF_ERROR_DELETED:
5046 break;
5047
5048 case SCF_ERROR_CONNECTION_BROKEN:
5049 case SCF_ERROR_BACKEND_READONLY:
5050 case SCF_ERROR_BACKEND_ACCESS:
5051 r = scferror2errno(scf_error());
5052 goto out;
5053
5054 case SCF_ERROR_PERMISSION_DENIED:
5055 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
5056 r = scferror2errno(scf_error());
5057 goto out;
5058
5059 case SCF_ERROR_NOT_SET:
5060 default:
5061 bad_error("scf_pg_delete", scf_error());
5062 }
5063 }
5064
5065 /* import new one */
5066 cbdata.sc_handle = g_hndl;
5067 cbdata.sc_trans = NULL; /* handled below */
5068 cbdata.sc_flags = 0;
5069
5070 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
5071 if (r != UU_WALK_NEXT) {
5072 if (r != UU_WALK_ERROR)
5073 bad_error("lscf_dependent_import", r);
5074
5075 r = cbdata.sc_err;
5076 goto out;
5077 }
5078
5079 if (tx == NULL)
5080 break;
5081
5082 if ((ent = scf_entry_create(g_hndl)) == NULL ||
5083 (val = scf_value_create(g_hndl)) == NULL) {
5084 if (scf_error() == SCF_ERROR_NO_MEMORY)
5085 return (ENOMEM);
5086
5087 bad_error("scf_entry_create", scf_error());
5088 }
5089
5090 if (scf_transaction_property_change_type(tx, ent, ud_name,
5091 SCF_TYPE_FMRI) != 0) {
5092 switch (scf_error()) {
5093 case SCF_ERROR_CONNECTION_BROKEN:
5094 r = scferror2errno(scf_error());
5095 goto out;
5096
5097 case SCF_ERROR_DELETED:
5098 warn(emsg_pg_deleted, ient->sc_fmri,
5099 "dependents");
5100 r = EBUSY;
5101 goto out;
5102
5103 case SCF_ERROR_NOT_FOUND:
5104 break;
5105
5106 case SCF_ERROR_NOT_BOUND:
5107 case SCF_ERROR_HANDLE_MISMATCH:
5108 case SCF_ERROR_INVALID_ARGUMENT:
5109 case SCF_ERROR_NOT_SET:
5110 default:
5111 bad_error("scf_transaction_property_"
5112 "change_type", scf_error());
5113 }
5114
5115 if (scf_transaction_property_new(tx, ent, ud_name,
5116 SCF_TYPE_FMRI) != 0) {
5117 switch (scf_error()) {
5118 case SCF_ERROR_CONNECTION_BROKEN:
5119 r = scferror2errno(scf_error());
5120 goto out;
5121
5122 case SCF_ERROR_DELETED:
5123 warn(emsg_pg_deleted, ient->sc_fmri,
5124 "dependents");
5125 r = EBUSY;
5126 goto out;
5127
5128 case SCF_ERROR_EXISTS:
5129 warn(emsg_pg_changed, ient->sc_fmri,
5130 "dependents");
5131 r = EBUSY;
5132 goto out;
5133
5134 case SCF_ERROR_INVALID_ARGUMENT:
5135 case SCF_ERROR_HANDLE_MISMATCH:
5136 case SCF_ERROR_NOT_BOUND:
5137 case SCF_ERROR_NOT_SET:
5138 default:
5139 bad_error("scf_transaction_property_"
5140 "new", scf_error());
5141 }
5142 }
5143 }
5144
5145 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
5146 new_dpt_pgroup->sc_pgroup_fmri) != 0)
5147 /* invalid sc_pgroup_fmri caught above */
5148 bad_error("scf_value_set_from_string",
5149 scf_error());
5150
5151 if (scf_entry_add_value(ent, val) != 0)
5152 bad_error("scf_entry_add_value", scf_error());
5153 break;
5154 }
5155
5156 case -2:
5157 warn(li_corrupt, ient->sc_fmri);
5158 internal_pgroup_free(current_pg);
5159 r = EBADF;
5160 goto out;
5161
5162 case -1:
5163 default:
5164 /* invalid sc_pgroup_fmri caught above */
5165 bad_error("fmri_equal", r);
5166 }
5167
5168 r = 0;
5169
5170 out:
5171 if (old_dpt_pgroup != NULL)
5172 internal_pgroup_free(old_dpt_pgroup);
5173
5174 return (r);
5175 }
5176
5177 /*
5178 * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
5179 * would import it, except it seems to exist in the service anyway. Compare
5180 * the existent dependent with the one we would import, and report any
5181 * differences (if there are none, be silent). prop is the property which
5182 * represents the existent dependent (in the dependents property group) in the
5183 * entity corresponding to ient.
5184 *
5185 * Returns
5186 * 0 - success (Sort of. At least, we can continue importing.)
5187 * ECONNABORTED - repository connection broken
5188 * EBUSY - ancestor of prop was deleted (error printed)
5189 * ENOMEM - out of memory
5190 * EBADF - corrupt property group (error printed)
5191 * EINVAL - new_dpt_pgroup has invalid target (error printed)
5192 */
5193 static int
handle_dependent_conflict(const entity_t * const ient,const scf_property_t * const prop,const pgroup_t * const new_dpt_pgroup)5194 handle_dependent_conflict(const entity_t * const ient,
5195 const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
5196 {
5197 int r;
5198 scf_type_t ty;
5199 scf_error_t scfe;
5200 void *tptr;
5201 int tissvc;
5202 pgroup_t *pgroup;
5203
5204 if (scf_property_get_value(prop, ud_val) != 0) {
5205 switch (scf_error()) {
5206 case SCF_ERROR_CONNECTION_BROKEN:
5207 return (scferror2errno(scf_error()));
5208
5209 case SCF_ERROR_DELETED:
5210 warn(emsg_pg_deleted, ient->sc_fmri,
5211 new_dpt_pgroup->sc_pgroup_name);
5212 return (EBUSY);
5213
5214 case SCF_ERROR_CONSTRAINT_VIOLATED:
5215 case SCF_ERROR_NOT_FOUND:
5216 warn(gettext("Conflict upgrading %s (not importing "
5217 "dependent \"%s\" because it already exists.) "
5218 "Warning: The \"%s/%2$s\" property has more or "
5219 "fewer than one value)).\n"), ient->sc_fmri,
5220 new_dpt_pgroup->sc_pgroup_name, "dependents");
5221 return (0);
5222
5223 case SCF_ERROR_HANDLE_MISMATCH:
5224 case SCF_ERROR_NOT_BOUND:
5225 case SCF_ERROR_NOT_SET:
5226 case SCF_ERROR_PERMISSION_DENIED:
5227 default:
5228 bad_error("scf_property_get_value",
5229 scf_error());
5230 }
5231 }
5232
5233 ty = scf_value_type(ud_val);
5234 assert(ty != SCF_TYPE_INVALID);
5235 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
5236 warn(gettext("Conflict upgrading %s (not importing dependent "
5237 "\"%s\" because it already exists). Warning: The "
5238 "\"%s/%s\" property has unexpected type \"%s\")).\n"),
5239 ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
5240 scf_type_to_string(ty), "dependents");
5241 return (0);
5242 }
5243
5244 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
5245 0)
5246 bad_error("scf_value_get_as_string", scf_error());
5247
5248 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
5249 switch (r) {
5250 case 0:
5251 warn(gettext("Conflict upgrading %s (not importing dependent "
5252 "\"%s\" (target \"%s\") because it already exists with "
5253 "target \"%s\").\n"), ient->sc_fmri,
5254 new_dpt_pgroup->sc_pgroup_name,
5255 new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
5256 return (0);
5257
5258 case 1:
5259 break;
5260
5261 case -1:
5262 warn(gettext("Conflict upgrading %s (not importing dependent "
5263 "\"%s\" because it already exists). Warning: The current "
5264 "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
5265 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5266 return (0);
5267
5268 case -2:
5269 warn(gettext("Dependent \"%s\" of %s has invalid target "
5270 "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
5271 new_dpt_pgroup->sc_pgroup_fmri);
5272 return (EINVAL);
5273
5274 default:
5275 bad_error("fmri_equal", r);
5276 }
5277
5278 /* compare dependency pgs in target */
5279 scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
5280 switch (scfe) {
5281 case SCF_ERROR_NONE:
5282 break;
5283
5284 case SCF_ERROR_NO_MEMORY:
5285 return (ENOMEM);
5286
5287 case SCF_ERROR_NOT_FOUND:
5288 warn(emsg_dpt_dangling, ient->sc_fmri,
5289 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5290 return (0);
5291
5292 case SCF_ERROR_CONSTRAINT_VIOLATED:
5293 case SCF_ERROR_INVALID_ARGUMENT:
5294 default:
5295 bad_error("fmri_to_entity", scfe);
5296 }
5297
5298 r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
5299 ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
5300 switch (r) {
5301 case 0:
5302 break;
5303
5304 case ECONNABORTED:
5305 return (r);
5306
5307 case ECANCELED:
5308 warn(emsg_dpt_dangling, ient->sc_fmri,
5309 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5310 return (0);
5311
5312 case EBADF:
5313 if (tissvc)
5314 warn(gettext("%s has an instance with a \"%s\" "
5315 "snapshot which is missing a snaplevel.\n"),
5316 ud_ctarg, "running");
5317 else
5318 warn(gettext("%s has a \"%s\" snapshot which is "
5319 "missing a snaplevel.\n"), ud_ctarg, "running");
5320 /* FALLTHROUGH */
5321
5322 case ENOENT:
5323 warn(emsg_dpt_no_dep, ient->sc_fmri,
5324 new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5325 new_dpt_pgroup->sc_pgroup_name);
5326 return (0);
5327
5328 case EINVAL:
5329 default:
5330 bad_error("entity_get_running_pg", r);
5331 }
5332
5333 pgroup = internal_pgroup_new();
5334 if (pgroup == NULL)
5335 return (ENOMEM);
5336
5337 r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
5338 switch (r) {
5339 case 0:
5340 break;
5341
5342 case ECONNABORTED:
5343 case EBADF:
5344 case ENOMEM:
5345 internal_pgroup_free(pgroup);
5346 return (r);
5347
5348 case ECANCELED:
5349 warn(emsg_dpt_no_dep, ient->sc_fmri,
5350 new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5351 new_dpt_pgroup->sc_pgroup_name);
5352 internal_pgroup_free(pgroup);
5353 return (0);
5354
5355 case EACCES:
5356 default:
5357 bad_error("load_pg", r);
5358 }
5359
5360 /* report differences */
5361 report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
5362 internal_pgroup_free(pgroup);
5363 return (0);
5364 }
5365
5366 /*
5367 * lipg is a property group in the last-import snapshot of ent, which is an
5368 * scf_service_t or an scf_instance_t (according to ient). If lipg is not in
5369 * ient's pgroups, delete it from ent if it hasn't been customized. If it is
5370 * in ents's property groups, compare and upgrade ent appropriately.
5371 *
5372 * Returns
5373 * 0 - success
5374 * ECONNABORTED - repository connection broken
5375 * ENOMEM - out of memory
5376 * ENOSPC - configd is out of resources
5377 * EINVAL - ient has invalid dependent (error printed)
5378 * - ient has invalid pgroup_t (error printed)
5379 * ECANCELED - ent has been deleted
5380 * ENODEV - entity containing lipg has been deleted
5381 * - entity containing running has been deleted
5382 * EPERM - could not delete pg (permission denied) (error printed)
5383 * - couldn't upgrade dependents (permission denied) (error printed)
5384 * - couldn't import pg (permission denied) (error printed)
5385 * - couldn't upgrade pg (permission denied) (error printed)
5386 * EROFS - could not delete pg (repository read-only)
5387 * - couldn't upgrade dependents (repository read-only)
5388 * - couldn't import pg (repository read-only)
5389 * - couldn't upgrade pg (repository read-only)
5390 * EACCES - could not delete pg (backend access denied)
5391 * - couldn't upgrade dependents (backend access denied)
5392 * - couldn't import pg (backend access denied)
5393 * - couldn't upgrade pg (backend access denied)
5394 * - couldn't read property (backend access denied)
5395 * EBUSY - property group was added (error printed)
5396 * - property group was deleted (error printed)
5397 * - property group changed (error printed)
5398 * - "dependents" pg was added, changed, or deleted (error printed)
5399 * - dependent target deleted (error printed)
5400 * - dependent pg changed (error printed)
5401 * EBADF - imp_snpl is corrupt (error printed)
5402 * - ent has bad pg (error printed)
5403 * EEXIST - dependent collision in target service (error printed)
5404 */
5405 static int
process_old_pg(const scf_propertygroup_t * lipg,entity_t * ient,void * ent,const scf_snaplevel_t * running)5406 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
5407 const scf_snaplevel_t *running)
5408 {
5409 int r;
5410 pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
5411 scf_callback_t cbdata;
5412
5413 const char * const cf_pg_missing =
5414 gettext("Conflict upgrading %s (property group %s is missing)\n");
5415 const char * const deleting =
5416 gettext("%s: Deleting property group \"%s\".\n");
5417
5418 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5419
5420 /* Skip dependent property groups. */
5421 if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
5422 switch (scf_error()) {
5423 case SCF_ERROR_DELETED:
5424 return (ENODEV);
5425
5426 case SCF_ERROR_CONNECTION_BROKEN:
5427 return (ECONNABORTED);
5428
5429 case SCF_ERROR_NOT_SET:
5430 case SCF_ERROR_NOT_BOUND:
5431 default:
5432 bad_error("scf_pg_get_type", scf_error());
5433 }
5434 }
5435
5436 if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
5437 if (scf_pg_get_property(lipg, "external", NULL) == 0)
5438 return (0);
5439
5440 switch (scf_error()) {
5441 case SCF_ERROR_NOT_FOUND:
5442 break;
5443
5444 case SCF_ERROR_CONNECTION_BROKEN:
5445 return (ECONNABORTED);
5446
5447 case SCF_ERROR_DELETED:
5448 return (ENODEV);
5449
5450 case SCF_ERROR_INVALID_ARGUMENT:
5451 case SCF_ERROR_NOT_BOUND:
5452 case SCF_ERROR_HANDLE_MISMATCH:
5453 case SCF_ERROR_NOT_SET:
5454 default:
5455 bad_error("scf_pg_get_property", scf_error());
5456 }
5457 }
5458
5459 /* lookup pg in new properties */
5460 if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
5461 switch (scf_error()) {
5462 case SCF_ERROR_DELETED:
5463 return (ENODEV);
5464
5465 case SCF_ERROR_CONNECTION_BROKEN:
5466 return (ECONNABORTED);
5467
5468 case SCF_ERROR_NOT_SET:
5469 case SCF_ERROR_NOT_BOUND:
5470 default:
5471 bad_error("scf_pg_get_name", scf_error());
5472 }
5473 }
5474
5475 pgrp.sc_pgroup_name = imp_str;
5476 mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
5477
5478 if (mpg != NULL)
5479 mpg->sc_pgroup_seen = 1;
5480
5481 /* Special handling for dependents */
5482 if (strcmp(imp_str, "dependents") == 0)
5483 return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
5484
5485 if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
5486 return (upgrade_manifestfiles(NULL, ient, running, ent));
5487
5488 if (mpg == NULL || mpg->sc_pgroup_delete) {
5489 /* property group was deleted from manifest */
5490 if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5491 switch (scf_error()) {
5492 case SCF_ERROR_NOT_FOUND:
5493 return (0);
5494
5495 case SCF_ERROR_DELETED:
5496 case SCF_ERROR_CONNECTION_BROKEN:
5497 return (scferror2errno(scf_error()));
5498
5499 case SCF_ERROR_INVALID_ARGUMENT:
5500 case SCF_ERROR_HANDLE_MISMATCH:
5501 case SCF_ERROR_NOT_BOUND:
5502 case SCF_ERROR_NOT_SET:
5503 default:
5504 bad_error("entity_get_pg", scf_error());
5505 }
5506 }
5507
5508 if (mpg != NULL && mpg->sc_pgroup_delete) {
5509 if (g_verbose)
5510 warn(deleting, ient->sc_fmri, imp_str);
5511 if (scf_pg_delete(imp_pg2) == 0)
5512 return (0);
5513
5514 switch (scf_error()) {
5515 case SCF_ERROR_DELETED:
5516 return (0);
5517
5518 case SCF_ERROR_CONNECTION_BROKEN:
5519 case SCF_ERROR_BACKEND_READONLY:
5520 case SCF_ERROR_BACKEND_ACCESS:
5521 return (scferror2errno(scf_error()));
5522
5523 case SCF_ERROR_PERMISSION_DENIED:
5524 warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
5525 return (scferror2errno(scf_error()));
5526
5527 case SCF_ERROR_NOT_SET:
5528 default:
5529 bad_error("scf_pg_delete", scf_error());
5530 }
5531 }
5532
5533 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5534 switch (r) {
5535 case 0:
5536 break;
5537
5538 case ECANCELED:
5539 return (ENODEV);
5540
5541 case ECONNABORTED:
5542 case ENOMEM:
5543 case EBADF:
5544 case EACCES:
5545 return (r);
5546
5547 default:
5548 bad_error("load_pg", r);
5549 }
5550
5551 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5552 switch (r) {
5553 case 0:
5554 break;
5555
5556 case ECANCELED:
5557 case ECONNABORTED:
5558 case ENOMEM:
5559 case EBADF:
5560 case EACCES:
5561 internal_pgroup_free(lipg_i);
5562 return (r);
5563
5564 default:
5565 bad_error("load_pg", r);
5566 }
5567
5568 if (pg_equal(lipg_i, curpg_i)) {
5569 if (g_verbose)
5570 warn(deleting, ient->sc_fmri, imp_str);
5571 if (scf_pg_delete(imp_pg2) != 0) {
5572 switch (scf_error()) {
5573 case SCF_ERROR_DELETED:
5574 break;
5575
5576 case SCF_ERROR_CONNECTION_BROKEN:
5577 internal_pgroup_free(lipg_i);
5578 internal_pgroup_free(curpg_i);
5579 return (ECONNABORTED);
5580
5581 case SCF_ERROR_NOT_SET:
5582 case SCF_ERROR_NOT_BOUND:
5583 default:
5584 bad_error("scf_pg_delete", scf_error());
5585 }
5586 }
5587 } else {
5588 report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5589 }
5590
5591 internal_pgroup_free(lipg_i);
5592 internal_pgroup_free(curpg_i);
5593
5594 return (0);
5595 }
5596
5597 /*
5598 * Only dependent pgs can have override set, and we skipped those
5599 * above.
5600 */
5601 assert(!mpg->sc_pgroup_override);
5602
5603 /* compare */
5604 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5605 switch (r) {
5606 case 0:
5607 break;
5608
5609 case ECANCELED:
5610 return (ENODEV);
5611
5612 case ECONNABORTED:
5613 case EBADF:
5614 case ENOMEM:
5615 case EACCES:
5616 return (r);
5617
5618 default:
5619 bad_error("load_pg", r);
5620 }
5621
5622 if (pg_equal(mpg, lipg_i)) {
5623 /* The manifest pg has not changed. Move on. */
5624 r = 0;
5625 goto out;
5626 }
5627
5628 /* upgrade current properties according to lipg & mpg */
5629 if (running != NULL)
5630 r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5631 else
5632 r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5633 if (r != 0) {
5634 switch (scf_error()) {
5635 case SCF_ERROR_CONNECTION_BROKEN:
5636 r = scferror2errno(scf_error());
5637 goto out;
5638
5639 case SCF_ERROR_DELETED:
5640 if (running != NULL)
5641 r = ENODEV;
5642 else
5643 r = ECANCELED;
5644 goto out;
5645
5646 case SCF_ERROR_NOT_FOUND:
5647 break;
5648
5649 case SCF_ERROR_INVALID_ARGUMENT:
5650 case SCF_ERROR_HANDLE_MISMATCH:
5651 case SCF_ERROR_NOT_BOUND:
5652 case SCF_ERROR_NOT_SET:
5653 default:
5654 bad_error("entity_get_pg", scf_error());
5655 }
5656
5657 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5658
5659 r = 0;
5660 goto out;
5661 }
5662
5663 r = load_pg_attrs(imp_pg2, &curpg_i);
5664 switch (r) {
5665 case 0:
5666 break;
5667
5668 case ECANCELED:
5669 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5670 r = 0;
5671 goto out;
5672
5673 case ECONNABORTED:
5674 case ENOMEM:
5675 goto out;
5676
5677 default:
5678 bad_error("load_pg_attrs", r);
5679 }
5680
5681 if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5682 (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5683 internal_pgroup_free(curpg_i);
5684 r = 0;
5685 goto out;
5686 }
5687
5688 internal_pgroup_free(curpg_i);
5689
5690 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5691 switch (r) {
5692 case 0:
5693 break;
5694
5695 case ECANCELED:
5696 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5697 r = 0;
5698 goto out;
5699
5700 case ECONNABORTED:
5701 case EBADF:
5702 case ENOMEM:
5703 case EACCES:
5704 goto out;
5705
5706 default:
5707 bad_error("load_pg", r);
5708 }
5709
5710 if (pg_equal(lipg_i, curpg_i) &&
5711 !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5712 int do_delete = 1;
5713
5714 if (g_verbose)
5715 warn(gettext("%s: Upgrading property group \"%s\".\n"),
5716 ient->sc_fmri, mpg->sc_pgroup_name);
5717
5718 internal_pgroup_free(curpg_i);
5719
5720 if (running != NULL &&
5721 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5722 switch (scf_error()) {
5723 case SCF_ERROR_DELETED:
5724 r = ECANCELED;
5725 goto out;
5726
5727 case SCF_ERROR_NOT_FOUND:
5728 do_delete = 0;
5729 break;
5730
5731 case SCF_ERROR_CONNECTION_BROKEN:
5732 r = scferror2errno(scf_error());
5733 goto out;
5734
5735 case SCF_ERROR_HANDLE_MISMATCH:
5736 case SCF_ERROR_INVALID_ARGUMENT:
5737 case SCF_ERROR_NOT_SET:
5738 case SCF_ERROR_NOT_BOUND:
5739 default:
5740 bad_error("entity_get_pg", scf_error());
5741 }
5742 }
5743
5744 if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5745 switch (scf_error()) {
5746 case SCF_ERROR_DELETED:
5747 break;
5748
5749 case SCF_ERROR_CONNECTION_BROKEN:
5750 case SCF_ERROR_BACKEND_READONLY:
5751 case SCF_ERROR_BACKEND_ACCESS:
5752 r = scferror2errno(scf_error());
5753 goto out;
5754
5755 case SCF_ERROR_PERMISSION_DENIED:
5756 warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5757 ient->sc_fmri);
5758 r = scferror2errno(scf_error());
5759 goto out;
5760
5761 case SCF_ERROR_NOT_SET:
5762 case SCF_ERROR_NOT_BOUND:
5763 default:
5764 bad_error("scf_pg_delete", scf_error());
5765 }
5766 }
5767
5768 cbdata.sc_handle = g_hndl;
5769 cbdata.sc_parent = ent;
5770 cbdata.sc_service = issvc;
5771 cbdata.sc_flags = 0;
5772 cbdata.sc_source_fmri = ient->sc_fmri;
5773 cbdata.sc_target_fmri = ient->sc_fmri;
5774
5775 r = entity_pgroup_import(mpg, &cbdata);
5776 switch (r) {
5777 case UU_WALK_NEXT:
5778 r = 0;
5779 goto out;
5780
5781 case UU_WALK_ERROR:
5782 if (cbdata.sc_err == EEXIST) {
5783 warn(emsg_pg_added, ient->sc_fmri,
5784 mpg->sc_pgroup_name);
5785 r = EBUSY;
5786 } else {
5787 r = cbdata.sc_err;
5788 }
5789 goto out;
5790
5791 default:
5792 bad_error("entity_pgroup_import", r);
5793 }
5794 }
5795
5796 if (running != NULL &&
5797 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5798 switch (scf_error()) {
5799 case SCF_ERROR_CONNECTION_BROKEN:
5800 case SCF_ERROR_DELETED:
5801 r = scferror2errno(scf_error());
5802 goto out;
5803
5804 case SCF_ERROR_NOT_FOUND:
5805 break;
5806
5807 case SCF_ERROR_HANDLE_MISMATCH:
5808 case SCF_ERROR_INVALID_ARGUMENT:
5809 case SCF_ERROR_NOT_SET:
5810 case SCF_ERROR_NOT_BOUND:
5811 default:
5812 bad_error("entity_get_pg", scf_error());
5813 }
5814
5815 cbdata.sc_handle = g_hndl;
5816 cbdata.sc_parent = ent;
5817 cbdata.sc_service = issvc;
5818 cbdata.sc_flags = SCI_FORCE;
5819 cbdata.sc_source_fmri = ient->sc_fmri;
5820 cbdata.sc_target_fmri = ient->sc_fmri;
5821
5822 r = entity_pgroup_import(mpg, &cbdata);
5823 switch (r) {
5824 case UU_WALK_NEXT:
5825 r = 0;
5826 goto out;
5827
5828 case UU_WALK_ERROR:
5829 if (cbdata.sc_err == EEXIST) {
5830 warn(emsg_pg_added, ient->sc_fmri,
5831 mpg->sc_pgroup_name);
5832 r = EBUSY;
5833 } else {
5834 r = cbdata.sc_err;
5835 }
5836 goto out;
5837
5838 default:
5839 bad_error("entity_pgroup_import", r);
5840 }
5841 }
5842
5843 r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5844 internal_pgroup_free(curpg_i);
5845 switch (r) {
5846 case 0:
5847 ient->sc_import_state = IMPORT_PROP_BEGUN;
5848 break;
5849
5850 case ECANCELED:
5851 warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5852 r = EBUSY;
5853 break;
5854
5855 case EPERM:
5856 warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5857 break;
5858
5859 case EBUSY:
5860 warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5861 break;
5862
5863 case ECONNABORTED:
5864 case ENOMEM:
5865 case ENOSPC:
5866 case EROFS:
5867 case EACCES:
5868 case EINVAL:
5869 break;
5870
5871 default:
5872 bad_error("upgrade_pg", r);
5873 }
5874
5875 out:
5876 internal_pgroup_free(lipg_i);
5877 return (r);
5878 }
5879
5880 /*
5881 * Upgrade the properties of ent according to snpl & ient.
5882 *
5883 * Returns
5884 * 0 - success
5885 * ECONNABORTED - repository connection broken
5886 * ENOMEM - out of memory
5887 * ENOSPC - configd is out of resources
5888 * ECANCELED - ent was deleted
5889 * ENODEV - entity containing snpl was deleted
5890 * - entity containing running was deleted
5891 * EBADF - imp_snpl is corrupt (error printed)
5892 * - ent has corrupt pg (error printed)
5893 * - dependent has corrupt pg (error printed)
5894 * - dependent target has a corrupt snapshot (error printed)
5895 * EBUSY - pg was added, changed, or deleted (error printed)
5896 * - dependent target was deleted (error printed)
5897 * - dependent pg changed (error printed)
5898 * EINVAL - invalid property group name (error printed)
5899 * - invalid property name (error printed)
5900 * - invalid value (error printed)
5901 * - ient has invalid pgroup or dependent (error printed)
5902 * EPERM - could not create property group (permission denied) (error printed)
5903 * - could not modify property group (permission denied) (error printed)
5904 * - couldn't delete, upgrade, or import pg or dependent (error printed)
5905 * EROFS - could not create property group (repository read-only)
5906 * - couldn't delete, upgrade, or import pg or dependent
5907 * EACCES - could not create property group (backend access denied)
5908 * - couldn't delete, upgrade, or import pg or dependent
5909 * EEXIST - dependent collision in target service (error printed)
5910 */
5911 static int
upgrade_props(void * ent,scf_snaplevel_t * running,scf_snaplevel_t * snpl,entity_t * ient)5912 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5913 entity_t *ient)
5914 {
5915 pgroup_t *pg, *rpg;
5916 int r;
5917 uu_list_t *pgs = ient->sc_pgroups;
5918
5919 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5920
5921 /* clear sc_sceen for pgs */
5922 if (uu_list_walk(pgs, clear_int,
5923 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5924 bad_error("uu_list_walk", uu_error());
5925
5926 if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5927 switch (scf_error()) {
5928 case SCF_ERROR_DELETED:
5929 return (ENODEV);
5930
5931 case SCF_ERROR_CONNECTION_BROKEN:
5932 return (ECONNABORTED);
5933
5934 case SCF_ERROR_NOT_SET:
5935 case SCF_ERROR_NOT_BOUND:
5936 case SCF_ERROR_HANDLE_MISMATCH:
5937 default:
5938 bad_error("scf_iter_snaplevel_pgs", scf_error());
5939 }
5940 }
5941
5942 for (;;) {
5943 r = scf_iter_next_pg(imp_up_iter, imp_pg);
5944 if (r == 0)
5945 break;
5946 if (r == 1) {
5947 r = process_old_pg(imp_pg, ient, ent, running);
5948 switch (r) {
5949 case 0:
5950 break;
5951
5952 case ECONNABORTED:
5953 case ENOMEM:
5954 case ENOSPC:
5955 case ECANCELED:
5956 case ENODEV:
5957 case EPERM:
5958 case EROFS:
5959 case EACCES:
5960 case EBADF:
5961 case EBUSY:
5962 case EINVAL:
5963 case EEXIST:
5964 return (r);
5965
5966 default:
5967 bad_error("process_old_pg", r);
5968 }
5969 continue;
5970 }
5971 if (r != -1)
5972 bad_error("scf_iter_next_pg", r);
5973
5974 switch (scf_error()) {
5975 case SCF_ERROR_DELETED:
5976 return (ENODEV);
5977
5978 case SCF_ERROR_CONNECTION_BROKEN:
5979 return (ECONNABORTED);
5980
5981 case SCF_ERROR_HANDLE_MISMATCH:
5982 case SCF_ERROR_NOT_BOUND:
5983 case SCF_ERROR_NOT_SET:
5984 case SCF_ERROR_INVALID_ARGUMENT:
5985 default:
5986 bad_error("scf_iter_next_pg", scf_error());
5987 }
5988 }
5989
5990 for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5991 if (pg->sc_pgroup_seen)
5992 continue;
5993
5994 /* pg is new */
5995
5996 if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5997 r = upgrade_dependents(NULL, imp_snpl, ient, running,
5998 ent);
5999 switch (r) {
6000 case 0:
6001 break;
6002
6003 case ECONNABORTED:
6004 case ENOMEM:
6005 case ENOSPC:
6006 case ECANCELED:
6007 case ENODEV:
6008 case EBADF:
6009 case EBUSY:
6010 case EINVAL:
6011 case EPERM:
6012 case EROFS:
6013 case EACCES:
6014 case EEXIST:
6015 return (r);
6016
6017 default:
6018 bad_error("upgrade_dependents", r);
6019 }
6020 continue;
6021 }
6022
6023 if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
6024 r = upgrade_manifestfiles(pg, ient, running, ent);
6025 switch (r) {
6026 case 0:
6027 break;
6028
6029 case ECONNABORTED:
6030 case ENOMEM:
6031 case ENOSPC:
6032 case ECANCELED:
6033 case ENODEV:
6034 case EBADF:
6035 case EBUSY:
6036 case EINVAL:
6037 case EPERM:
6038 case EROFS:
6039 case EACCES:
6040 case EEXIST:
6041 return (r);
6042
6043 default:
6044 bad_error("upgrade_manifestfiles", r);
6045 }
6046 continue;
6047 }
6048
6049 if (running != NULL) {
6050 r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
6051 imp_pg);
6052 } else {
6053 r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
6054 imp_pg);
6055 }
6056 if (r != 0) {
6057 scf_callback_t cbdata;
6058
6059 switch (scf_error()) {
6060 case SCF_ERROR_NOT_FOUND:
6061 break;
6062
6063 case SCF_ERROR_CONNECTION_BROKEN:
6064 return (scferror2errno(scf_error()));
6065
6066 case SCF_ERROR_DELETED:
6067 if (running != NULL)
6068 return (ENODEV);
6069 else
6070 return (scferror2errno(scf_error()));
6071
6072 case SCF_ERROR_INVALID_ARGUMENT:
6073 warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
6074 pg->sc_pgroup_name);
6075 return (EINVAL);
6076
6077 case SCF_ERROR_NOT_SET:
6078 case SCF_ERROR_HANDLE_MISMATCH:
6079 case SCF_ERROR_NOT_BOUND:
6080 default:
6081 bad_error("entity_get_pg", scf_error());
6082 }
6083
6084 /* User doesn't have pg, so import it. */
6085
6086 cbdata.sc_handle = g_hndl;
6087 cbdata.sc_parent = ent;
6088 cbdata.sc_service = issvc;
6089 cbdata.sc_flags = SCI_FORCE;
6090 cbdata.sc_source_fmri = ient->sc_fmri;
6091 cbdata.sc_target_fmri = ient->sc_fmri;
6092
6093 r = entity_pgroup_import(pg, &cbdata);
6094 switch (r) {
6095 case UU_WALK_NEXT:
6096 ient->sc_import_state = IMPORT_PROP_BEGUN;
6097 continue;
6098
6099 case UU_WALK_ERROR:
6100 if (cbdata.sc_err == EEXIST) {
6101 warn(emsg_pg_added, ient->sc_fmri,
6102 pg->sc_pgroup_name);
6103 return (EBUSY);
6104 }
6105 return (cbdata.sc_err);
6106
6107 default:
6108 bad_error("entity_pgroup_import", r);
6109 }
6110 }
6111
6112 /* report differences between pg & current */
6113 r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
6114 switch (r) {
6115 case 0:
6116 break;
6117
6118 case ECANCELED:
6119 warn(emsg_pg_deleted, ient->sc_fmri,
6120 pg->sc_pgroup_name);
6121 return (EBUSY);
6122
6123 case ECONNABORTED:
6124 case EBADF:
6125 case ENOMEM:
6126 case EACCES:
6127 return (r);
6128
6129 default:
6130 bad_error("load_pg", r);
6131 }
6132 report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
6133 internal_pgroup_free(rpg);
6134 rpg = NULL;
6135 }
6136
6137 return (0);
6138 }
6139
6140 /*
6141 * Import an instance. If it doesn't exist, create it. If it has
6142 * a last-import snapshot, upgrade its properties. Finish by updating its
6143 * last-import snapshot. If it doesn't have a last-import snapshot then it
6144 * could have been created for a dependent tag in another manifest. Import the
6145 * new properties. If there's a conflict, don't override, like now?
6146 *
6147 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
6148 * lcbdata->sc_err to
6149 * ECONNABORTED - repository connection broken
6150 * ENOMEM - out of memory
6151 * ENOSPC - svc.configd is out of resources
6152 * EEXIST - dependency collision in dependent service (error printed)
6153 * EPERM - couldn't create temporary instance (permission denied)
6154 * - couldn't import into temporary instance (permission denied)
6155 * - couldn't take snapshot (permission denied)
6156 * - couldn't upgrade properties (permission denied)
6157 * - couldn't import properties (permission denied)
6158 * - couldn't import dependents (permission denied)
6159 * EROFS - couldn't create temporary instance (repository read-only)
6160 * - couldn't import into temporary instance (repository read-only)
6161 * - couldn't upgrade properties (repository read-only)
6162 * - couldn't import properties (repository read-only)
6163 * - couldn't import dependents (repository read-only)
6164 * EACCES - couldn't create temporary instance (backend access denied)
6165 * - couldn't import into temporary instance (backend access denied)
6166 * - couldn't upgrade properties (backend access denied)
6167 * - couldn't import properties (backend access denied)
6168 * - couldn't import dependents (backend access denied)
6169 * EINVAL - invalid instance name (error printed)
6170 * - invalid pgroup_t's (error printed)
6171 * - invalid dependents (error printed)
6172 * EBUSY - temporary service deleted (error printed)
6173 * - temporary instance deleted (error printed)
6174 * - temporary instance changed (error printed)
6175 * - temporary instance already exists (error printed)
6176 * - instance deleted (error printed)
6177 * EBADF - instance has corrupt last-import snapshot (error printed)
6178 * - instance is corrupt (error printed)
6179 * - dependent has corrupt pg (error printed)
6180 * - dependent target has a corrupt snapshot (error printed)
6181 * -1 - unknown libscf error (error printed)
6182 */
6183 static int
lscf_instance_import(void * v,void * pvt)6184 lscf_instance_import(void *v, void *pvt)
6185 {
6186 entity_t *inst = v;
6187 scf_callback_t ctx;
6188 scf_callback_t *lcbdata = pvt;
6189 scf_service_t *rsvc = lcbdata->sc_parent;
6190 int r;
6191 scf_snaplevel_t *running;
6192 int flags = lcbdata->sc_flags;
6193
6194 const char * const emsg_tdel =
6195 gettext("Temporary instance svc:/%s:%s was deleted.\n");
6196 const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
6197 "changed unexpectedly.\n");
6198 const char * const emsg_del = gettext("%s changed unexpectedly "
6199 "(instance \"%s\" was deleted.)\n");
6200 const char * const emsg_badsnap = gettext(
6201 "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
6202
6203 /*
6204 * prepare last-import snapshot:
6205 * create temporary instance (service was precreated)
6206 * populate with properties from bundle
6207 * take snapshot
6208 */
6209 if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
6210 switch (scf_error()) {
6211 case SCF_ERROR_CONNECTION_BROKEN:
6212 case SCF_ERROR_NO_RESOURCES:
6213 case SCF_ERROR_BACKEND_READONLY:
6214 case SCF_ERROR_BACKEND_ACCESS:
6215 return (stash_scferror(lcbdata));
6216
6217 case SCF_ERROR_EXISTS:
6218 warn(gettext("Temporary service svc:/%s "
6219 "changed unexpectedly (instance \"%s\" added).\n"),
6220 imp_tsname, inst->sc_name);
6221 lcbdata->sc_err = EBUSY;
6222 return (UU_WALK_ERROR);
6223
6224 case SCF_ERROR_DELETED:
6225 warn(gettext("Temporary service svc:/%s "
6226 "was deleted unexpectedly.\n"), imp_tsname);
6227 lcbdata->sc_err = EBUSY;
6228 return (UU_WALK_ERROR);
6229
6230 case SCF_ERROR_INVALID_ARGUMENT:
6231 warn(gettext("Invalid instance name \"%s\".\n"),
6232 inst->sc_name);
6233 return (stash_scferror(lcbdata));
6234
6235 case SCF_ERROR_PERMISSION_DENIED:
6236 warn(gettext("Could not create temporary instance "
6237 "\"%s\" in svc:/%s (permission denied).\n"),
6238 inst->sc_name, imp_tsname);
6239 return (stash_scferror(lcbdata));
6240
6241 case SCF_ERROR_HANDLE_MISMATCH:
6242 case SCF_ERROR_NOT_BOUND:
6243 case SCF_ERROR_NOT_SET:
6244 default:
6245 bad_error("scf_service_add_instance", scf_error());
6246 }
6247 }
6248
6249 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6250 inst->sc_name);
6251 if (r < 0)
6252 bad_error("snprintf", errno);
6253
6254 r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
6255 lcbdata->sc_flags | SCI_NOENABLED);
6256 switch (r) {
6257 case 0:
6258 break;
6259
6260 case ECANCELED:
6261 warn(emsg_tdel, imp_tsname, inst->sc_name);
6262 lcbdata->sc_err = EBUSY;
6263 r = UU_WALK_ERROR;
6264 goto deltemp;
6265
6266 case EEXIST:
6267 warn(emsg_tchg, imp_tsname, inst->sc_name);
6268 lcbdata->sc_err = EBUSY;
6269 r = UU_WALK_ERROR;
6270 goto deltemp;
6271
6272 case ECONNABORTED:
6273 goto connaborted;
6274
6275 case ENOMEM:
6276 case ENOSPC:
6277 case EPERM:
6278 case EROFS:
6279 case EACCES:
6280 case EINVAL:
6281 case EBUSY:
6282 lcbdata->sc_err = r;
6283 r = UU_WALK_ERROR;
6284 goto deltemp;
6285
6286 default:
6287 bad_error("lscf_import_instance_pgs", r);
6288 }
6289
6290 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6291 inst->sc_name);
6292 if (r < 0)
6293 bad_error("snprintf", errno);
6294
6295 ctx.sc_handle = lcbdata->sc_handle;
6296 ctx.sc_parent = imp_tinst;
6297 ctx.sc_service = 0;
6298 ctx.sc_source_fmri = inst->sc_fmri;
6299 ctx.sc_target_fmri = imp_str;
6300 if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
6301 UU_DEFAULT) != 0) {
6302 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6303 bad_error("uu_list_walk", uu_error());
6304
6305 switch (ctx.sc_err) {
6306 case ECONNABORTED:
6307 goto connaborted;
6308
6309 case ECANCELED:
6310 warn(emsg_tdel, imp_tsname, inst->sc_name);
6311 lcbdata->sc_err = EBUSY;
6312 break;
6313
6314 case EEXIST:
6315 warn(emsg_tchg, imp_tsname, inst->sc_name);
6316 lcbdata->sc_err = EBUSY;
6317 break;
6318
6319 default:
6320 lcbdata->sc_err = ctx.sc_err;
6321 }
6322 r = UU_WALK_ERROR;
6323 goto deltemp;
6324 }
6325
6326 if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
6327 inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
6328 switch (scf_error()) {
6329 case SCF_ERROR_CONNECTION_BROKEN:
6330 goto connaborted;
6331
6332 case SCF_ERROR_NO_RESOURCES:
6333 r = stash_scferror(lcbdata);
6334 goto deltemp;
6335
6336 case SCF_ERROR_EXISTS:
6337 warn(emsg_tchg, imp_tsname, inst->sc_name);
6338 lcbdata->sc_err = EBUSY;
6339 r = UU_WALK_ERROR;
6340 goto deltemp;
6341
6342 case SCF_ERROR_PERMISSION_DENIED:
6343 warn(gettext("Could not take \"%s\" snapshot of %s "
6344 "(permission denied).\n"), snap_lastimport,
6345 imp_str);
6346 r = stash_scferror(lcbdata);
6347 goto deltemp;
6348
6349 default:
6350 scfwarn();
6351 lcbdata->sc_err = -1;
6352 r = UU_WALK_ERROR;
6353 goto deltemp;
6354
6355 case SCF_ERROR_HANDLE_MISMATCH:
6356 case SCF_ERROR_INVALID_ARGUMENT:
6357 case SCF_ERROR_NOT_SET:
6358 bad_error("_scf_snapshot_take_new_named", scf_error());
6359 }
6360 }
6361
6362 if (lcbdata->sc_flags & SCI_FRESH)
6363 goto fresh;
6364
6365 if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
6366 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6367 imp_lisnap) != 0) {
6368 switch (scf_error()) {
6369 case SCF_ERROR_DELETED:
6370 warn(emsg_del, inst->sc_parent->sc_fmri,
6371 inst->sc_name);
6372 lcbdata->sc_err = EBUSY;
6373 r = UU_WALK_ERROR;
6374 goto deltemp;
6375
6376 case SCF_ERROR_NOT_FOUND:
6377 flags |= SCI_FORCE;
6378 goto nosnap;
6379
6380 case SCF_ERROR_CONNECTION_BROKEN:
6381 goto connaborted;
6382
6383 case SCF_ERROR_INVALID_ARGUMENT:
6384 case SCF_ERROR_HANDLE_MISMATCH:
6385 case SCF_ERROR_NOT_BOUND:
6386 case SCF_ERROR_NOT_SET:
6387 default:
6388 bad_error("scf_instance_get_snapshot",
6389 scf_error());
6390 }
6391 }
6392
6393 /* upgrade */
6394
6395 /*
6396 * compare new properties with last-import properties
6397 * upgrade current properties
6398 */
6399 /* clear sc_sceen for pgs */
6400 if (uu_list_walk(inst->sc_pgroups, clear_int,
6401 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
6402 0)
6403 bad_error("uu_list_walk", uu_error());
6404
6405 r = get_snaplevel(imp_lisnap, 0, imp_snpl);
6406 switch (r) {
6407 case 0:
6408 break;
6409
6410 case ECONNABORTED:
6411 goto connaborted;
6412
6413 case ECANCELED:
6414 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6415 lcbdata->sc_err = EBUSY;
6416 r = UU_WALK_ERROR;
6417 goto deltemp;
6418
6419 case ENOENT:
6420 warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
6421 lcbdata->sc_err = EBADF;
6422 r = UU_WALK_ERROR;
6423 goto deltemp;
6424
6425 default:
6426 bad_error("get_snaplevel", r);
6427 }
6428
6429 if (scf_instance_get_snapshot(imp_inst, snap_running,
6430 imp_rsnap) != 0) {
6431 switch (scf_error()) {
6432 case SCF_ERROR_DELETED:
6433 warn(emsg_del, inst->sc_parent->sc_fmri,
6434 inst->sc_name);
6435 lcbdata->sc_err = EBUSY;
6436 r = UU_WALK_ERROR;
6437 goto deltemp;
6438
6439 case SCF_ERROR_NOT_FOUND:
6440 break;
6441
6442 case SCF_ERROR_CONNECTION_BROKEN:
6443 goto connaborted;
6444
6445 case SCF_ERROR_INVALID_ARGUMENT:
6446 case SCF_ERROR_HANDLE_MISMATCH:
6447 case SCF_ERROR_NOT_BOUND:
6448 case SCF_ERROR_NOT_SET:
6449 default:
6450 bad_error("scf_instance_get_snapshot",
6451 scf_error());
6452 }
6453
6454 running = NULL;
6455 } else {
6456 r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
6457 switch (r) {
6458 case 0:
6459 running = imp_rsnpl;
6460 break;
6461
6462 case ECONNABORTED:
6463 goto connaborted;
6464
6465 case ECANCELED:
6466 warn(emsg_del, inst->sc_parent->sc_fmri,
6467 inst->sc_name);
6468 lcbdata->sc_err = EBUSY;
6469 r = UU_WALK_ERROR;
6470 goto deltemp;
6471
6472 case ENOENT:
6473 warn(emsg_badsnap, snap_running, inst->sc_fmri);
6474 lcbdata->sc_err = EBADF;
6475 r = UU_WALK_ERROR;
6476 goto deltemp;
6477
6478 default:
6479 bad_error("get_snaplevel", r);
6480 }
6481 }
6482
6483 r = upgrade_props(imp_inst, running, imp_snpl, inst);
6484 switch (r) {
6485 case 0:
6486 break;
6487
6488 case ECANCELED:
6489 case ENODEV:
6490 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6491 lcbdata->sc_err = EBUSY;
6492 r = UU_WALK_ERROR;
6493 goto deltemp;
6494
6495 case ECONNABORTED:
6496 goto connaborted;
6497
6498 case ENOMEM:
6499 case ENOSPC:
6500 case EBADF:
6501 case EBUSY:
6502 case EINVAL:
6503 case EPERM:
6504 case EROFS:
6505 case EACCES:
6506 case EEXIST:
6507 lcbdata->sc_err = r;
6508 r = UU_WALK_ERROR;
6509 goto deltemp;
6510
6511 default:
6512 bad_error("upgrade_props", r);
6513 }
6514
6515 inst->sc_import_state = IMPORT_PROP_DONE;
6516 } else {
6517 switch (scf_error()) {
6518 case SCF_ERROR_CONNECTION_BROKEN:
6519 goto connaborted;
6520
6521 case SCF_ERROR_NOT_FOUND:
6522 break;
6523
6524 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
6525 case SCF_ERROR_HANDLE_MISMATCH:
6526 case SCF_ERROR_NOT_BOUND:
6527 case SCF_ERROR_NOT_SET:
6528 default:
6529 bad_error("scf_service_get_instance", scf_error());
6530 }
6531
6532 fresh:
6533 /* create instance */
6534 if (scf_service_add_instance(rsvc, inst->sc_name,
6535 imp_inst) != 0) {
6536 switch (scf_error()) {
6537 case SCF_ERROR_CONNECTION_BROKEN:
6538 goto connaborted;
6539
6540 case SCF_ERROR_NO_RESOURCES:
6541 case SCF_ERROR_BACKEND_READONLY:
6542 case SCF_ERROR_BACKEND_ACCESS:
6543 r = stash_scferror(lcbdata);
6544 goto deltemp;
6545
6546 case SCF_ERROR_EXISTS:
6547 warn(gettext("%s changed unexpectedly "
6548 "(instance \"%s\" added).\n"),
6549 inst->sc_parent->sc_fmri, inst->sc_name);
6550 lcbdata->sc_err = EBUSY;
6551 r = UU_WALK_ERROR;
6552 goto deltemp;
6553
6554 case SCF_ERROR_PERMISSION_DENIED:
6555 warn(gettext("Could not create \"%s\" instance "
6556 "in %s (permission denied).\n"),
6557 inst->sc_name, inst->sc_parent->sc_fmri);
6558 r = stash_scferror(lcbdata);
6559 goto deltemp;
6560
6561 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
6562 case SCF_ERROR_HANDLE_MISMATCH:
6563 case SCF_ERROR_NOT_BOUND:
6564 case SCF_ERROR_NOT_SET:
6565 default:
6566 bad_error("scf_service_add_instance",
6567 scf_error());
6568 }
6569 }
6570
6571 nosnap:
6572 /*
6573 * Create a last-import snapshot to serve as an attachment
6574 * point for the real one from the temporary instance. Since
6575 * the contents is irrelevant, take it now, while the instance
6576 * is empty, to minimize svc.configd's work.
6577 */
6578 if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6579 imp_lisnap) != 0) {
6580 switch (scf_error()) {
6581 case SCF_ERROR_CONNECTION_BROKEN:
6582 goto connaborted;
6583
6584 case SCF_ERROR_NO_RESOURCES:
6585 r = stash_scferror(lcbdata);
6586 goto deltemp;
6587
6588 case SCF_ERROR_EXISTS:
6589 warn(gettext("%s changed unexpectedly "
6590 "(snapshot \"%s\" added).\n"),
6591 inst->sc_fmri, snap_lastimport);
6592 lcbdata->sc_err = EBUSY;
6593 r = UU_WALK_ERROR;
6594 goto deltemp;
6595
6596 case SCF_ERROR_PERMISSION_DENIED:
6597 warn(gettext("Could not take \"%s\" snapshot "
6598 "of %s (permission denied).\n"),
6599 snap_lastimport, inst->sc_fmri);
6600 r = stash_scferror(lcbdata);
6601 goto deltemp;
6602
6603 default:
6604 scfwarn();
6605 lcbdata->sc_err = -1;
6606 r = UU_WALK_ERROR;
6607 goto deltemp;
6608
6609 case SCF_ERROR_NOT_SET:
6610 case SCF_ERROR_INTERNAL:
6611 case SCF_ERROR_INVALID_ARGUMENT:
6612 case SCF_ERROR_HANDLE_MISMATCH:
6613 bad_error("_scf_snapshot_take_new",
6614 scf_error());
6615 }
6616 }
6617
6618 if (li_only)
6619 goto lionly;
6620
6621 inst->sc_import_state = IMPORT_PROP_BEGUN;
6622
6623 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6624 flags);
6625 switch (r) {
6626 case 0:
6627 break;
6628
6629 case ECONNABORTED:
6630 goto connaborted;
6631
6632 case ECANCELED:
6633 warn(gettext("%s changed unexpectedly "
6634 "(instance \"%s\" deleted).\n"),
6635 inst->sc_parent->sc_fmri, inst->sc_name);
6636 lcbdata->sc_err = EBUSY;
6637 r = UU_WALK_ERROR;
6638 goto deltemp;
6639
6640 case EEXIST:
6641 warn(gettext("%s changed unexpectedly "
6642 "(property group added).\n"), inst->sc_fmri);
6643 lcbdata->sc_err = EBUSY;
6644 r = UU_WALK_ERROR;
6645 goto deltemp;
6646
6647 default:
6648 lcbdata->sc_err = r;
6649 r = UU_WALK_ERROR;
6650 goto deltemp;
6651
6652 case EINVAL: /* caught above */
6653 bad_error("lscf_import_instance_pgs", r);
6654 }
6655
6656 ctx.sc_parent = imp_inst;
6657 ctx.sc_service = 0;
6658 ctx.sc_trans = NULL;
6659 ctx.sc_flags = 0;
6660 if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6661 &ctx, UU_DEFAULT) != 0) {
6662 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6663 bad_error("uu_list_walk", uu_error());
6664
6665 if (ctx.sc_err == ECONNABORTED)
6666 goto connaborted;
6667 lcbdata->sc_err = ctx.sc_err;
6668 r = UU_WALK_ERROR;
6669 goto deltemp;
6670 }
6671
6672 inst->sc_import_state = IMPORT_PROP_DONE;
6673
6674 if (g_verbose)
6675 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6676 snap_initial, inst->sc_fmri);
6677 r = take_snap(imp_inst, snap_initial, imp_snap);
6678 switch (r) {
6679 case 0:
6680 break;
6681
6682 case ECONNABORTED:
6683 goto connaborted;
6684
6685 case ENOSPC:
6686 case -1:
6687 lcbdata->sc_err = r;
6688 r = UU_WALK_ERROR;
6689 goto deltemp;
6690
6691 case ECANCELED:
6692 warn(gettext("%s changed unexpectedly "
6693 "(instance %s deleted).\n"),
6694 inst->sc_parent->sc_fmri, inst->sc_name);
6695 lcbdata->sc_err = r;
6696 r = UU_WALK_ERROR;
6697 goto deltemp;
6698
6699 case EPERM:
6700 warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6701 lcbdata->sc_err = r;
6702 r = UU_WALK_ERROR;
6703 goto deltemp;
6704
6705 default:
6706 bad_error("take_snap", r);
6707 }
6708 }
6709
6710 lionly:
6711 if (lcbdata->sc_flags & SCI_NOSNAP)
6712 goto deltemp;
6713
6714 /* transfer snapshot from temporary instance */
6715 if (g_verbose)
6716 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6717 snap_lastimport, inst->sc_fmri);
6718 if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6719 switch (scf_error()) {
6720 case SCF_ERROR_CONNECTION_BROKEN:
6721 goto connaborted;
6722
6723 case SCF_ERROR_NO_RESOURCES:
6724 r = stash_scferror(lcbdata);
6725 goto deltemp;
6726
6727 case SCF_ERROR_PERMISSION_DENIED:
6728 warn(gettext("Could not take \"%s\" snapshot for %s "
6729 "(permission denied).\n"), snap_lastimport,
6730 inst->sc_fmri);
6731 r = stash_scferror(lcbdata);
6732 goto deltemp;
6733
6734 case SCF_ERROR_NOT_SET:
6735 case SCF_ERROR_HANDLE_MISMATCH:
6736 default:
6737 bad_error("_scf_snapshot_attach", scf_error());
6738 }
6739 }
6740
6741 inst->sc_import_state = IMPORT_COMPLETE;
6742
6743 r = UU_WALK_NEXT;
6744
6745 deltemp:
6746 /* delete temporary instance */
6747 if (scf_instance_delete(imp_tinst) != 0) {
6748 switch (scf_error()) {
6749 case SCF_ERROR_DELETED:
6750 break;
6751
6752 case SCF_ERROR_CONNECTION_BROKEN:
6753 goto connaborted;
6754
6755 case SCF_ERROR_NOT_SET:
6756 case SCF_ERROR_NOT_BOUND:
6757 default:
6758 bad_error("scf_instance_delete", scf_error());
6759 }
6760 }
6761
6762 return (r);
6763
6764 connaborted:
6765 warn(gettext("Could not delete svc:/%s:%s "
6766 "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6767 lcbdata->sc_err = ECONNABORTED;
6768 return (UU_WALK_ERROR);
6769 }
6770
6771 /*
6772 * When an instance is imported we end up telling configd about it. Once we tell
6773 * configd about these changes, startd eventually notices. If this is a new
6774 * instance, the manifest may not specify the SCF_PG_RESTARTER (restarter)
6775 * property group. However, many of the other tools expect that this property
6776 * group exists and has certain values.
6777 *
6778 * These values are added asynchronously by startd. We should not return from
6779 * this routine until we can verify that the property group we need is there.
6780 *
6781 * Before we go ahead and verify this, we have to ask ourselves an important
6782 * question: Is the early manifest service currently running? Because if it is
6783 * running and it has invoked us, then the service will never get a restarter
6784 * property because svc.startd is blocked on EMI finishing before it lets itself
6785 * fully connect to svc.configd. Of course, this means that this race condition
6786 * is in fact impossible to 100% eliminate.
6787 *
6788 * svc.startd makes sure that EMI only runs once and has succeeded by checking
6789 * the state of the EMI instance. If it is online it bails out and makes sure
6790 * that it doesn't run again. In this case, we're going to do something similar,
6791 * only if the state is online, then we're going to actually verify. EMI always
6792 * has to be present, but it can be explicitly disabled to reduce the amount of
6793 * damage it can cause. If EMI has been disabled then we no longer have to worry
6794 * about the implicit race condition and can go ahead and check things. If EMI
6795 * is in some state that isn't online or disabled and isn't runinng, then we
6796 * assume that things are rather bad and we're not going to get in your way,
6797 * even if the rest of SMF does.
6798 *
6799 * Returns 0 on success or returns an errno.
6800 */
6801 #ifndef NATIVE_BUILD
6802 static int
lscf_instance_verify(scf_scope_t * scope,entity_t * svc,entity_t * inst)6803 lscf_instance_verify(scf_scope_t *scope, entity_t *svc, entity_t *inst)
6804 {
6805 int ret, err;
6806 struct timespec ts;
6807 char *emi_state;
6808
6809 /*
6810 * smf_get_state does not distinguish between its different failure
6811 * modes: memory allocation failures, SMF internal failures, and a lack
6812 * of EMI entirely because it's been removed. In these cases, we're
6813 * going to be conservative and opt to say that if we don't know, better
6814 * to not block import or falsely warn to the user.
6815 */
6816 if ((emi_state = smf_get_state(SCF_INSTANCE_EMI)) == NULL) {
6817 return (0);
6818 }
6819
6820 /*
6821 * As per the block comment for this function check the state of EMI
6822 */
6823 if (strcmp(emi_state, SCF_STATE_STRING_ONLINE) != 0 &&
6824 strcmp(emi_state, SCF_STATE_STRING_DISABLED) != 0) {
6825 warn(gettext("Not validating instance %s:%s because EMI's "
6826 "state is %s\n"), svc->sc_name, inst->sc_name, emi_state);
6827 free(emi_state);
6828 return (0);
6829 }
6830
6831 free(emi_state);
6832
6833 /*
6834 * First we have to get the property.
6835 */
6836 if ((ret = scf_scope_get_service(scope, svc->sc_name, imp_svc)) != 0) {
6837 ret = scf_error();
6838 warn(gettext("Failed to look up service: %s\n"), svc->sc_name);
6839 return (ret);
6840 }
6841
6842 /*
6843 * We should always be able to get the instance. It should already
6844 * exist because we just created it or got it. There probably is a
6845 * slim chance that someone may have come in and deleted it though from
6846 * under us.
6847 */
6848 if ((ret = scf_service_get_instance(imp_svc, inst->sc_name, imp_inst))
6849 != 0) {
6850 ret = scf_error();
6851 warn(gettext("Failed to verify instance: %s\n"), inst->sc_name);
6852 switch (ret) {
6853 case SCF_ERROR_DELETED:
6854 err = ENODEV;
6855 break;
6856 case SCF_ERROR_CONNECTION_BROKEN:
6857 warn(gettext("Lost repository connection\n"));
6858 err = ECONNABORTED;
6859 break;
6860 case SCF_ERROR_NOT_FOUND:
6861 warn(gettext("Instance \"%s\" disappeared out from "
6862 "under us.\n"), inst->sc_name);
6863 err = ENOENT;
6864 break;
6865 default:
6866 bad_error("scf_service_get_instance", ret);
6867 }
6868
6869 return (err);
6870 }
6871
6872 /*
6873 * An astute observer may want to use _scf_wait_pg which would notify us
6874 * of a property group change, unfortunately that does not work if the
6875 * property group in question does not exist. So instead we have to
6876 * manually poll and ask smf the best way to get to it.
6877 */
6878 while ((ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg))
6879 != SCF_SUCCESS) {
6880 ret = scf_error();
6881 if (ret != SCF_ERROR_NOT_FOUND) {
6882 warn(gettext("Failed to get restarter property "
6883 "group for instance: %s\n"), inst->sc_name);
6884 switch (ret) {
6885 case SCF_ERROR_DELETED:
6886 err = ENODEV;
6887 break;
6888 case SCF_ERROR_CONNECTION_BROKEN:
6889 warn(gettext("Lost repository connection\n"));
6890 err = ECONNABORTED;
6891 break;
6892 default:
6893 bad_error("scf_service_get_instance", ret);
6894 }
6895
6896 return (err);
6897 }
6898
6899 ts.tv_sec = pg_timeout / NANOSEC;
6900 ts.tv_nsec = pg_timeout % NANOSEC;
6901
6902 (void) nanosleep(&ts, NULL);
6903 }
6904
6905 /*
6906 * svcadm also expects that the SCF_PROPERTY_STATE property is present.
6907 * So in addition to the property group being present, we need to wait
6908 * for the property to be there in some form.
6909 *
6910 * Note that a property group is a frozen snapshot in time. To properly
6911 * get beyond this, you have to refresh the property group each time.
6912 */
6913 while ((ret = scf_pg_get_property(imp_pg, SCF_PROPERTY_STATE,
6914 imp_prop)) != 0) {
6915
6916 ret = scf_error();
6917 if (ret != SCF_ERROR_NOT_FOUND) {
6918 warn(gettext("Failed to get property %s from the "
6919 "restarter property group of instance %s\n"),
6920 SCF_PROPERTY_STATE, inst->sc_name);
6921 switch (ret) {
6922 case SCF_ERROR_CONNECTION_BROKEN:
6923 warn(gettext("Lost repository connection\n"));
6924 err = ECONNABORTED;
6925 break;
6926 case SCF_ERROR_DELETED:
6927 err = ENODEV;
6928 break;
6929 default:
6930 bad_error("scf_pg_get_property", ret);
6931 }
6932
6933 return (err);
6934 }
6935
6936 ts.tv_sec = pg_timeout / NANOSEC;
6937 ts.tv_nsec = pg_timeout % NANOSEC;
6938
6939 (void) nanosleep(&ts, NULL);
6940
6941 ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg);
6942 if (ret != SCF_SUCCESS) {
6943 warn(gettext("Failed to get restarter property "
6944 "group for instance: %s\n"), inst->sc_name);
6945 switch (ret) {
6946 case SCF_ERROR_DELETED:
6947 err = ENODEV;
6948 break;
6949 case SCF_ERROR_CONNECTION_BROKEN:
6950 warn(gettext("Lost repository connection\n"));
6951 err = ECONNABORTED;
6952 break;
6953 default:
6954 bad_error("scf_service_get_instance", ret);
6955 }
6956
6957 return (err);
6958 }
6959 }
6960
6961 /*
6962 * We don't have to free the property groups or other values that we got
6963 * because we stored them in global variables that are allocated and
6964 * freed by the routines that call into these functions. Unless of
6965 * course the rest of the code here that we are basing this on is
6966 * mistaken.
6967 */
6968 return (0);
6969 }
6970 #endif
6971
6972 /*
6973 * If the service is missing, create it, import its properties, and import the
6974 * instances. Since the service is brand new, it should be empty, and if we
6975 * run into any existing entities (SCF_ERROR_EXISTS), abort.
6976 *
6977 * If the service exists, we want to upgrade its properties and import the
6978 * instances. Upgrade requires a last-import snapshot, though, which are
6979 * children of instances, so first we'll have to go through the instances
6980 * looking for a last-import snapshot. If we don't find one then we'll just
6981 * override-import the service properties (but don't delete existing
6982 * properties: another service might have declared us as a dependent). Before
6983 * we change anything, though, we want to take the previous snapshots. We
6984 * also give lscf_instance_import() a leg up on taking last-import snapshots
6985 * by importing the manifest's service properties into a temporary service.
6986 *
6987 * On success, returns UU_WALK_NEXT. On failure, returns UU_WALK_ERROR and
6988 * sets lcbdata->sc_err to
6989 * ECONNABORTED - repository connection broken
6990 * ENOMEM - out of memory
6991 * ENOSPC - svc.configd is out of resources
6992 * EPERM - couldn't create temporary service (error printed)
6993 * - couldn't import into temp service (error printed)
6994 * - couldn't create service (error printed)
6995 * - couldn't import dependent (error printed)
6996 * - couldn't take snapshot (error printed)
6997 * - couldn't create instance (error printed)
6998 * - couldn't create, modify, or delete pg (error printed)
6999 * - couldn't create, modify, or delete dependent (error printed)
7000 * - couldn't import instance (error printed)
7001 * EROFS - couldn't create temporary service (repository read-only)
7002 * - couldn't import into temporary service (repository read-only)
7003 * - couldn't create service (repository read-only)
7004 * - couldn't import dependent (repository read-only)
7005 * - couldn't create instance (repository read-only)
7006 * - couldn't create, modify, or delete pg or dependent
7007 * - couldn't import instance (repository read-only)
7008 * EACCES - couldn't create temporary service (backend access denied)
7009 * - couldn't import into temporary service (backend access denied)
7010 * - couldn't create service (backend access denied)
7011 * - couldn't import dependent (backend access denied)
7012 * - couldn't create instance (backend access denied)
7013 * - couldn't create, modify, or delete pg or dependent
7014 * - couldn't import instance (backend access denied)
7015 * EINVAL - service name is invalid (error printed)
7016 * - service name is too long (error printed)
7017 * - s has invalid pgroup (error printed)
7018 * - s has invalid dependent (error printed)
7019 * - instance name is invalid (error printed)
7020 * - instance entity_t is invalid (error printed)
7021 * EEXIST - couldn't create temporary service (already exists) (error printed)
7022 * - couldn't import dependent (dependency pg already exists) (printed)
7023 * - dependency collision in dependent service (error printed)
7024 * EBUSY - temporary service deleted (error printed)
7025 * - property group added to temporary service (error printed)
7026 * - new property group changed or was deleted (error printed)
7027 * - service was added unexpectedly (error printed)
7028 * - service was deleted unexpectedly (error printed)
7029 * - property group added to new service (error printed)
7030 * - instance added unexpectedly (error printed)
7031 * - instance deleted unexpectedly (error printed)
7032 * - dependent service deleted unexpectedly (error printed)
7033 * - pg was added, changed, or deleted (error printed)
7034 * - dependent pg changed (error printed)
7035 * - temporary instance added, changed, or deleted (error printed)
7036 * EBADF - a last-import snapshot is corrupt (error printed)
7037 * - the service is corrupt (error printed)
7038 * - a dependent is corrupt (error printed)
7039 * - an instance is corrupt (error printed)
7040 * - an instance has a corrupt last-import snapshot (error printed)
7041 * - dependent target has a corrupt snapshot (error printed)
7042 * -1 - unknown libscf error (error printed)
7043 */
7044 static int
lscf_service_import(void * v,void * pvt)7045 lscf_service_import(void *v, void *pvt)
7046 {
7047 entity_t *s = v;
7048 scf_callback_t cbdata;
7049 scf_callback_t *lcbdata = pvt;
7050 scf_scope_t *scope = lcbdata->sc_parent;
7051 entity_t *inst, linst;
7052 int r;
7053 int fresh = 0;
7054 scf_snaplevel_t *running;
7055 int have_ge = 0;
7056 boolean_t retried = B_FALSE;
7057
7058 const char * const ts_deleted = gettext("Temporary service svc:/%s "
7059 "was deleted unexpectedly.\n");
7060 const char * const ts_pg_added = gettext("Temporary service svc:/%s "
7061 "changed unexpectedly (property group added).\n");
7062 const char * const s_deleted =
7063 gettext("%s was deleted unexpectedly.\n");
7064 const char * const i_deleted =
7065 gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
7066 const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
7067 "is corrupt (missing service snaplevel).\n");
7068 const char * const s_mfile_upd =
7069 gettext("Unable to update the manifest file connection "
7070 "for %s\n");
7071
7072 li_only = 0;
7073 /* Validate the service name */
7074 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7075 switch (scf_error()) {
7076 case SCF_ERROR_CONNECTION_BROKEN:
7077 return (stash_scferror(lcbdata));
7078
7079 case SCF_ERROR_INVALID_ARGUMENT:
7080 warn(gettext("\"%s\" is an invalid service name. "
7081 "Cannot import.\n"), s->sc_name);
7082 return (stash_scferror(lcbdata));
7083
7084 case SCF_ERROR_NOT_FOUND:
7085 break;
7086
7087 case SCF_ERROR_HANDLE_MISMATCH:
7088 case SCF_ERROR_NOT_BOUND:
7089 case SCF_ERROR_NOT_SET:
7090 default:
7091 bad_error("scf_scope_get_service", scf_error());
7092 }
7093 }
7094
7095 /* create temporary service */
7096 /*
7097 * the size of the buffer was reduced to max_scf_name_len to prevent
7098 * hitting bug 6681151. After the bug fix, the size of the buffer
7099 * should be restored to its original value (max_scf_name_len +1)
7100 */
7101 r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
7102 if (r < 0)
7103 bad_error("snprintf", errno);
7104 if (r > max_scf_name_len) {
7105 warn(gettext(
7106 "Service name \"%s\" is too long. Cannot import.\n"),
7107 s->sc_name);
7108 lcbdata->sc_err = EINVAL;
7109 return (UU_WALK_ERROR);
7110 }
7111
7112 retry:
7113 if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
7114 switch (scf_error()) {
7115 case SCF_ERROR_CONNECTION_BROKEN:
7116 case SCF_ERROR_NO_RESOURCES:
7117 case SCF_ERROR_BACKEND_READONLY:
7118 case SCF_ERROR_BACKEND_ACCESS:
7119 return (stash_scferror(lcbdata));
7120
7121 case SCF_ERROR_EXISTS:
7122 if (!retried) {
7123 lscf_delete(imp_tsname, 0);
7124 retried = B_TRUE;
7125 goto retry;
7126 }
7127 warn(gettext(
7128 "Temporary service \"%s\" must be deleted before "
7129 "this manifest can be imported.\n"), imp_tsname);
7130 return (stash_scferror(lcbdata));
7131
7132 case SCF_ERROR_PERMISSION_DENIED:
7133 warn(gettext("Could not create temporary service "
7134 "\"%s\" (permission denied).\n"), imp_tsname);
7135 return (stash_scferror(lcbdata));
7136
7137 case SCF_ERROR_INVALID_ARGUMENT:
7138 case SCF_ERROR_HANDLE_MISMATCH:
7139 case SCF_ERROR_NOT_BOUND:
7140 case SCF_ERROR_NOT_SET:
7141 default:
7142 bad_error("scf_scope_add_service", scf_error());
7143 }
7144 }
7145
7146 r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
7147 if (r < 0)
7148 bad_error("snprintf", errno);
7149
7150 cbdata.sc_handle = lcbdata->sc_handle;
7151 cbdata.sc_parent = imp_tsvc;
7152 cbdata.sc_service = 1;
7153 cbdata.sc_source_fmri = s->sc_fmri;
7154 cbdata.sc_target_fmri = imp_str;
7155 cbdata.sc_flags = 0;
7156
7157 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
7158 UU_DEFAULT) != 0) {
7159 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7160 bad_error("uu_list_walk", uu_error());
7161
7162 lcbdata->sc_err = cbdata.sc_err;
7163 switch (cbdata.sc_err) {
7164 case ECONNABORTED:
7165 goto connaborted;
7166
7167 case ECANCELED:
7168 warn(ts_deleted, imp_tsname);
7169 lcbdata->sc_err = EBUSY;
7170 return (UU_WALK_ERROR);
7171
7172 case EEXIST:
7173 warn(ts_pg_added, imp_tsname);
7174 lcbdata->sc_err = EBUSY;
7175 return (UU_WALK_ERROR);
7176 }
7177
7178 r = UU_WALK_ERROR;
7179 goto deltemp;
7180 }
7181
7182 if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
7183 UU_DEFAULT) != 0) {
7184 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7185 bad_error("uu_list_walk", uu_error());
7186
7187 lcbdata->sc_err = cbdata.sc_err;
7188 switch (cbdata.sc_err) {
7189 case ECONNABORTED:
7190 goto connaborted;
7191
7192 case ECANCELED:
7193 warn(ts_deleted, imp_tsname);
7194 lcbdata->sc_err = EBUSY;
7195 return (UU_WALK_ERROR);
7196
7197 case EEXIST:
7198 warn(ts_pg_added, imp_tsname);
7199 lcbdata->sc_err = EBUSY;
7200 return (UU_WALK_ERROR);
7201 }
7202
7203 r = UU_WALK_ERROR;
7204 goto deltemp;
7205 }
7206
7207 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7208 switch (scf_error()) {
7209 case SCF_ERROR_NOT_FOUND:
7210 break;
7211
7212 case SCF_ERROR_CONNECTION_BROKEN:
7213 goto connaborted;
7214
7215 case SCF_ERROR_INVALID_ARGUMENT:
7216 case SCF_ERROR_HANDLE_MISMATCH:
7217 case SCF_ERROR_NOT_BOUND:
7218 case SCF_ERROR_NOT_SET:
7219 default:
7220 bad_error("scf_scope_get_service", scf_error());
7221 }
7222
7223 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
7224 switch (scf_error()) {
7225 case SCF_ERROR_CONNECTION_BROKEN:
7226 goto connaborted;
7227
7228 case SCF_ERROR_NO_RESOURCES:
7229 case SCF_ERROR_BACKEND_READONLY:
7230 case SCF_ERROR_BACKEND_ACCESS:
7231 r = stash_scferror(lcbdata);
7232 goto deltemp;
7233
7234 case SCF_ERROR_EXISTS:
7235 warn(gettext("Scope \"%s\" changed unexpectedly"
7236 " (service \"%s\" added).\n"),
7237 SCF_SCOPE_LOCAL, s->sc_name);
7238 lcbdata->sc_err = EBUSY;
7239 goto deltemp;
7240
7241 case SCF_ERROR_PERMISSION_DENIED:
7242 warn(gettext("Could not create service \"%s\" "
7243 "(permission denied).\n"), s->sc_name);
7244 goto deltemp;
7245
7246 case SCF_ERROR_INVALID_ARGUMENT:
7247 case SCF_ERROR_HANDLE_MISMATCH:
7248 case SCF_ERROR_NOT_BOUND:
7249 case SCF_ERROR_NOT_SET:
7250 default:
7251 bad_error("scf_scope_add_service", scf_error());
7252 }
7253 }
7254
7255 s->sc_import_state = IMPORT_PROP_BEGUN;
7256
7257 /* import service properties */
7258 cbdata.sc_handle = lcbdata->sc_handle;
7259 cbdata.sc_parent = imp_svc;
7260 cbdata.sc_service = 1;
7261 cbdata.sc_flags = lcbdata->sc_flags;
7262 cbdata.sc_source_fmri = s->sc_fmri;
7263 cbdata.sc_target_fmri = s->sc_fmri;
7264
7265 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7266 &cbdata, UU_DEFAULT) != 0) {
7267 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7268 bad_error("uu_list_walk", uu_error());
7269
7270 lcbdata->sc_err = cbdata.sc_err;
7271 switch (cbdata.sc_err) {
7272 case ECONNABORTED:
7273 goto connaborted;
7274
7275 case ECANCELED:
7276 warn(s_deleted, s->sc_fmri);
7277 lcbdata->sc_err = EBUSY;
7278 return (UU_WALK_ERROR);
7279
7280 case EEXIST:
7281 warn(gettext("%s changed unexpectedly "
7282 "(property group added).\n"), s->sc_fmri);
7283 lcbdata->sc_err = EBUSY;
7284 return (UU_WALK_ERROR);
7285
7286 case EINVAL:
7287 /* caught above */
7288 bad_error("entity_pgroup_import",
7289 cbdata.sc_err);
7290 }
7291
7292 r = UU_WALK_ERROR;
7293 goto deltemp;
7294 }
7295
7296 cbdata.sc_trans = NULL;
7297 cbdata.sc_flags = 0;
7298 if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
7299 &cbdata, UU_DEFAULT) != 0) {
7300 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7301 bad_error("uu_list_walk", uu_error());
7302
7303 lcbdata->sc_err = cbdata.sc_err;
7304 if (cbdata.sc_err == ECONNABORTED)
7305 goto connaborted;
7306 r = UU_WALK_ERROR;
7307 goto deltemp;
7308 }
7309
7310 s->sc_import_state = IMPORT_PROP_DONE;
7311
7312 /*
7313 * This is a new service, so we can't take previous snapshots
7314 * or upgrade service properties.
7315 */
7316 fresh = 1;
7317 goto instances;
7318 }
7319
7320 /* Clear sc_seen for the instances. */
7321 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
7322 (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
7323 bad_error("uu_list_walk", uu_error());
7324
7325 /*
7326 * Take previous snapshots for all instances. Even for ones not
7327 * mentioned in the bundle, since we might change their service
7328 * properties.
7329 */
7330 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7331 switch (scf_error()) {
7332 case SCF_ERROR_CONNECTION_BROKEN:
7333 goto connaborted;
7334
7335 case SCF_ERROR_DELETED:
7336 warn(s_deleted, s->sc_fmri);
7337 lcbdata->sc_err = EBUSY;
7338 r = UU_WALK_ERROR;
7339 goto deltemp;
7340
7341 case SCF_ERROR_HANDLE_MISMATCH:
7342 case SCF_ERROR_NOT_BOUND:
7343 case SCF_ERROR_NOT_SET:
7344 default:
7345 bad_error("scf_iter_service_instances", scf_error());
7346 }
7347 }
7348
7349 for (;;) {
7350 r = scf_iter_next_instance(imp_iter, imp_inst);
7351 if (r == 0)
7352 break;
7353 if (r != 1) {
7354 switch (scf_error()) {
7355 case SCF_ERROR_DELETED:
7356 warn(s_deleted, s->sc_fmri);
7357 lcbdata->sc_err = EBUSY;
7358 r = UU_WALK_ERROR;
7359 goto deltemp;
7360
7361 case SCF_ERROR_CONNECTION_BROKEN:
7362 goto connaborted;
7363
7364 case SCF_ERROR_NOT_BOUND:
7365 case SCF_ERROR_HANDLE_MISMATCH:
7366 case SCF_ERROR_INVALID_ARGUMENT:
7367 case SCF_ERROR_NOT_SET:
7368 default:
7369 bad_error("scf_iter_next_instance",
7370 scf_error());
7371 }
7372 }
7373
7374 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
7375 switch (scf_error()) {
7376 case SCF_ERROR_DELETED:
7377 continue;
7378
7379 case SCF_ERROR_CONNECTION_BROKEN:
7380 goto connaborted;
7381
7382 case SCF_ERROR_NOT_SET:
7383 case SCF_ERROR_NOT_BOUND:
7384 default:
7385 bad_error("scf_instance_get_name", scf_error());
7386 }
7387 }
7388
7389 if (g_verbose)
7390 warn(gettext(
7391 "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
7392 snap_previous, s->sc_name, imp_str);
7393
7394 r = take_snap(imp_inst, snap_previous, imp_snap);
7395 switch (r) {
7396 case 0:
7397 break;
7398
7399 case ECANCELED:
7400 continue;
7401
7402 case ECONNABORTED:
7403 goto connaborted;
7404
7405 case EPERM:
7406 warn(gettext("Could not take \"%s\" snapshot of "
7407 "svc:/%s:%s (permission denied).\n"),
7408 snap_previous, s->sc_name, imp_str);
7409 lcbdata->sc_err = r;
7410 return (UU_WALK_ERROR);
7411
7412 case ENOSPC:
7413 case -1:
7414 lcbdata->sc_err = r;
7415 r = UU_WALK_ERROR;
7416 goto deltemp;
7417
7418 default:
7419 bad_error("take_snap", r);
7420 }
7421
7422 linst.sc_name = imp_str;
7423 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
7424 &linst, NULL, NULL);
7425 if (inst != NULL) {
7426 inst->sc_import_state = IMPORT_PREVIOUS;
7427 inst->sc_seen = 1;
7428 }
7429 }
7430
7431 /*
7432 * Create the new instances and take previous snapshots of
7433 * them. This is not necessary, but it maximizes data preservation.
7434 */
7435 for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
7436 inst != NULL;
7437 inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
7438 inst)) {
7439 if (inst->sc_seen)
7440 continue;
7441
7442 if (scf_service_add_instance(imp_svc, inst->sc_name,
7443 imp_inst) != 0) {
7444 switch (scf_error()) {
7445 case SCF_ERROR_CONNECTION_BROKEN:
7446 goto connaborted;
7447
7448 case SCF_ERROR_BACKEND_READONLY:
7449 case SCF_ERROR_BACKEND_ACCESS:
7450 case SCF_ERROR_NO_RESOURCES:
7451 r = stash_scferror(lcbdata);
7452 goto deltemp;
7453
7454 case SCF_ERROR_EXISTS:
7455 warn(gettext("%s changed unexpectedly "
7456 "(instance \"%s\" added).\n"), s->sc_fmri,
7457 inst->sc_name);
7458 lcbdata->sc_err = EBUSY;
7459 r = UU_WALK_ERROR;
7460 goto deltemp;
7461
7462 case SCF_ERROR_INVALID_ARGUMENT:
7463 warn(gettext("Service \"%s\" has instance with "
7464 "invalid name \"%s\".\n"), s->sc_name,
7465 inst->sc_name);
7466 r = stash_scferror(lcbdata);
7467 goto deltemp;
7468
7469 case SCF_ERROR_PERMISSION_DENIED:
7470 warn(gettext("Could not create instance \"%s\" "
7471 "in %s (permission denied).\n"),
7472 inst->sc_name, s->sc_fmri);
7473 r = stash_scferror(lcbdata);
7474 goto deltemp;
7475
7476 case SCF_ERROR_HANDLE_MISMATCH:
7477 case SCF_ERROR_NOT_BOUND:
7478 case SCF_ERROR_NOT_SET:
7479 default:
7480 bad_error("scf_service_add_instance",
7481 scf_error());
7482 }
7483 }
7484
7485 if (g_verbose)
7486 warn(gettext("Taking \"%s\" snapshot for "
7487 "new service %s.\n"), snap_previous, inst->sc_fmri);
7488 r = take_snap(imp_inst, snap_previous, imp_snap);
7489 switch (r) {
7490 case 0:
7491 break;
7492
7493 case ECANCELED:
7494 warn(i_deleted, s->sc_fmri, inst->sc_name);
7495 lcbdata->sc_err = EBUSY;
7496 r = UU_WALK_ERROR;
7497 goto deltemp;
7498
7499 case ECONNABORTED:
7500 goto connaborted;
7501
7502 case EPERM:
7503 warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
7504 lcbdata->sc_err = r;
7505 r = UU_WALK_ERROR;
7506 goto deltemp;
7507
7508 case ENOSPC:
7509 case -1:
7510 r = UU_WALK_ERROR;
7511 goto deltemp;
7512
7513 default:
7514 bad_error("take_snap", r);
7515 }
7516 }
7517
7518 s->sc_import_state = IMPORT_PREVIOUS;
7519
7520 /*
7521 * Upgrade service properties, if we can find a last-import snapshot.
7522 * Any will do because we don't support different service properties
7523 * in different manifests, so all snaplevels of the service in all of
7524 * the last-import snapshots of the instances should be the same.
7525 */
7526 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7527 switch (scf_error()) {
7528 case SCF_ERROR_CONNECTION_BROKEN:
7529 goto connaborted;
7530
7531 case SCF_ERROR_DELETED:
7532 warn(s_deleted, s->sc_fmri);
7533 lcbdata->sc_err = EBUSY;
7534 r = UU_WALK_ERROR;
7535 goto deltemp;
7536
7537 case SCF_ERROR_HANDLE_MISMATCH:
7538 case SCF_ERROR_NOT_BOUND:
7539 case SCF_ERROR_NOT_SET:
7540 default:
7541 bad_error("scf_iter_service_instances", scf_error());
7542 }
7543 }
7544
7545 for (;;) {
7546 r = scf_iter_next_instance(imp_iter, imp_inst);
7547 if (r == -1) {
7548 switch (scf_error()) {
7549 case SCF_ERROR_DELETED:
7550 warn(s_deleted, s->sc_fmri);
7551 lcbdata->sc_err = EBUSY;
7552 r = UU_WALK_ERROR;
7553 goto deltemp;
7554
7555 case SCF_ERROR_CONNECTION_BROKEN:
7556 goto connaborted;
7557
7558 case SCF_ERROR_NOT_BOUND:
7559 case SCF_ERROR_HANDLE_MISMATCH:
7560 case SCF_ERROR_INVALID_ARGUMENT:
7561 case SCF_ERROR_NOT_SET:
7562 default:
7563 bad_error("scf_iter_next_instance",
7564 scf_error());
7565 }
7566 }
7567
7568 if (r == 0) {
7569 /*
7570 * Didn't find any last-import snapshots. Override-
7571 * import the properties. Unless one of the instances
7572 * has a general/enabled property, in which case we're
7573 * probably running a last-import-capable svccfg for
7574 * the first time, and we should only take the
7575 * last-import snapshot.
7576 */
7577 if (have_ge) {
7578 pgroup_t *mfpg;
7579 scf_callback_t mfcbdata;
7580
7581 li_only = 1;
7582 no_refresh = 1;
7583 /*
7584 * Need to go ahead and import the manifestfiles
7585 * pg if it exists. If the last-import snapshot
7586 * upgrade code is ever removed this code can
7587 * be removed as well.
7588 */
7589 mfpg = internal_pgroup_find(s,
7590 SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
7591
7592 if (mfpg) {
7593 mfcbdata.sc_handle = g_hndl;
7594 mfcbdata.sc_parent = imp_svc;
7595 mfcbdata.sc_service = 1;
7596 mfcbdata.sc_flags = SCI_FORCE;
7597 mfcbdata.sc_source_fmri = s->sc_fmri;
7598 mfcbdata.sc_target_fmri = s->sc_fmri;
7599 if (entity_pgroup_import(mfpg,
7600 &mfcbdata) != UU_WALK_NEXT) {
7601 warn(s_mfile_upd, s->sc_fmri);
7602 r = UU_WALK_ERROR;
7603 goto deltemp;
7604 }
7605 }
7606 break;
7607 }
7608
7609 s->sc_import_state = IMPORT_PROP_BEGUN;
7610
7611 cbdata.sc_handle = g_hndl;
7612 cbdata.sc_parent = imp_svc;
7613 cbdata.sc_service = 1;
7614 cbdata.sc_flags = SCI_FORCE;
7615 cbdata.sc_source_fmri = s->sc_fmri;
7616 cbdata.sc_target_fmri = s->sc_fmri;
7617 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7618 &cbdata, UU_DEFAULT) != 0) {
7619 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7620 bad_error("uu_list_walk", uu_error());
7621 lcbdata->sc_err = cbdata.sc_err;
7622 switch (cbdata.sc_err) {
7623 case ECONNABORTED:
7624 goto connaborted;
7625
7626 case ECANCELED:
7627 warn(s_deleted, s->sc_fmri);
7628 lcbdata->sc_err = EBUSY;
7629 break;
7630
7631 case EINVAL: /* caught above */
7632 case EEXIST:
7633 bad_error("entity_pgroup_import",
7634 cbdata.sc_err);
7635 }
7636
7637 r = UU_WALK_ERROR;
7638 goto deltemp;
7639 }
7640
7641 cbdata.sc_trans = NULL;
7642 cbdata.sc_flags = 0;
7643 if (uu_list_walk(s->sc_dependents,
7644 lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
7645 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7646 bad_error("uu_list_walk", uu_error());
7647 lcbdata->sc_err = cbdata.sc_err;
7648 if (cbdata.sc_err == ECONNABORTED)
7649 goto connaborted;
7650 r = UU_WALK_ERROR;
7651 goto deltemp;
7652 }
7653 break;
7654 }
7655
7656 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
7657 imp_snap) != 0) {
7658 switch (scf_error()) {
7659 case SCF_ERROR_DELETED:
7660 continue;
7661
7662 case SCF_ERROR_NOT_FOUND:
7663 break;
7664
7665 case SCF_ERROR_CONNECTION_BROKEN:
7666 goto connaborted;
7667
7668 case SCF_ERROR_HANDLE_MISMATCH:
7669 case SCF_ERROR_NOT_BOUND:
7670 case SCF_ERROR_INVALID_ARGUMENT:
7671 case SCF_ERROR_NOT_SET:
7672 default:
7673 bad_error("scf_instance_get_snapshot",
7674 scf_error());
7675 }
7676
7677 if (have_ge)
7678 continue;
7679
7680 /*
7681 * Check for a general/enabled property. This is how
7682 * we tell whether to import if there turn out to be
7683 * no last-import snapshots.
7684 */
7685 if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
7686 imp_pg) == 0) {
7687 if (scf_pg_get_property(imp_pg,
7688 SCF_PROPERTY_ENABLED, imp_prop) == 0) {
7689 have_ge = 1;
7690 } else {
7691 switch (scf_error()) {
7692 case SCF_ERROR_DELETED:
7693 case SCF_ERROR_NOT_FOUND:
7694 continue;
7695
7696 case SCF_ERROR_INVALID_ARGUMENT:
7697 case SCF_ERROR_HANDLE_MISMATCH:
7698 case SCF_ERROR_CONNECTION_BROKEN:
7699 case SCF_ERROR_NOT_BOUND:
7700 case SCF_ERROR_NOT_SET:
7701 default:
7702 bad_error("scf_pg_get_property",
7703 scf_error());
7704 }
7705 }
7706 } else {
7707 switch (scf_error()) {
7708 case SCF_ERROR_DELETED:
7709 case SCF_ERROR_NOT_FOUND:
7710 continue;
7711
7712 case SCF_ERROR_CONNECTION_BROKEN:
7713 goto connaborted;
7714
7715 case SCF_ERROR_NOT_BOUND:
7716 case SCF_ERROR_NOT_SET:
7717 case SCF_ERROR_INVALID_ARGUMENT:
7718 case SCF_ERROR_HANDLE_MISMATCH:
7719 default:
7720 bad_error("scf_instance_get_pg",
7721 scf_error());
7722 }
7723 }
7724 continue;
7725 }
7726
7727 /* find service snaplevel */
7728 r = get_snaplevel(imp_snap, 1, imp_snpl);
7729 switch (r) {
7730 case 0:
7731 break;
7732
7733 case ECONNABORTED:
7734 goto connaborted;
7735
7736 case ECANCELED:
7737 continue;
7738
7739 case ENOENT:
7740 if (scf_instance_get_name(imp_inst, imp_str,
7741 imp_str_sz) < 0)
7742 (void) strcpy(imp_str, "?");
7743 warn(badsnap, snap_lastimport, s->sc_name, imp_str);
7744 lcbdata->sc_err = EBADF;
7745 r = UU_WALK_ERROR;
7746 goto deltemp;
7747
7748 default:
7749 bad_error("get_snaplevel", r);
7750 }
7751
7752 if (scf_instance_get_snapshot(imp_inst, snap_running,
7753 imp_rsnap) != 0) {
7754 switch (scf_error()) {
7755 case SCF_ERROR_DELETED:
7756 continue;
7757
7758 case SCF_ERROR_NOT_FOUND:
7759 break;
7760
7761 case SCF_ERROR_CONNECTION_BROKEN:
7762 goto connaborted;
7763
7764 case SCF_ERROR_INVALID_ARGUMENT:
7765 case SCF_ERROR_HANDLE_MISMATCH:
7766 case SCF_ERROR_NOT_BOUND:
7767 case SCF_ERROR_NOT_SET:
7768 default:
7769 bad_error("scf_instance_get_snapshot",
7770 scf_error());
7771 }
7772 running = NULL;
7773 } else {
7774 r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
7775 switch (r) {
7776 case 0:
7777 running = imp_rsnpl;
7778 break;
7779
7780 case ECONNABORTED:
7781 goto connaborted;
7782
7783 case ECANCELED:
7784 continue;
7785
7786 case ENOENT:
7787 if (scf_instance_get_name(imp_inst, imp_str,
7788 imp_str_sz) < 0)
7789 (void) strcpy(imp_str, "?");
7790 warn(badsnap, snap_running, s->sc_name,
7791 imp_str);
7792 lcbdata->sc_err = EBADF;
7793 r = UU_WALK_ERROR;
7794 goto deltemp;
7795
7796 default:
7797 bad_error("get_snaplevel", r);
7798 }
7799 }
7800
7801 if (g_verbose) {
7802 if (scf_instance_get_name(imp_inst, imp_str,
7803 imp_str_sz) < 0)
7804 (void) strcpy(imp_str, "?");
7805 warn(gettext("Upgrading properties of %s according to "
7806 "instance \"%s\".\n"), s->sc_fmri, imp_str);
7807 }
7808
7809 /* upgrade service properties */
7810 r = upgrade_props(imp_svc, running, imp_snpl, s);
7811 if (r == 0)
7812 break;
7813
7814 switch (r) {
7815 case ECONNABORTED:
7816 goto connaborted;
7817
7818 case ECANCELED:
7819 warn(s_deleted, s->sc_fmri);
7820 lcbdata->sc_err = EBUSY;
7821 break;
7822
7823 case ENODEV:
7824 if (scf_instance_get_name(imp_inst, imp_str,
7825 imp_str_sz) < 0)
7826 (void) strcpy(imp_str, "?");
7827 warn(i_deleted, s->sc_fmri, imp_str);
7828 lcbdata->sc_err = EBUSY;
7829 break;
7830
7831 default:
7832 lcbdata->sc_err = r;
7833 }
7834
7835 r = UU_WALK_ERROR;
7836 goto deltemp;
7837 }
7838
7839 s->sc_import_state = IMPORT_PROP_DONE;
7840
7841 instances:
7842 /* import instances */
7843 cbdata.sc_handle = lcbdata->sc_handle;
7844 cbdata.sc_parent = imp_svc;
7845 cbdata.sc_service = 1;
7846 cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7847 cbdata.sc_general = NULL;
7848
7849 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7850 lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7851 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7852 bad_error("uu_list_walk", uu_error());
7853
7854 lcbdata->sc_err = cbdata.sc_err;
7855 if (cbdata.sc_err == ECONNABORTED)
7856 goto connaborted;
7857 r = UU_WALK_ERROR;
7858 goto deltemp;
7859 }
7860
7861 s->sc_import_state = IMPORT_COMPLETE;
7862 r = UU_WALK_NEXT;
7863
7864 deltemp:
7865 /* delete temporary service */
7866 if (scf_service_delete(imp_tsvc) != 0) {
7867 switch (scf_error()) {
7868 case SCF_ERROR_DELETED:
7869 break;
7870
7871 case SCF_ERROR_CONNECTION_BROKEN:
7872 goto connaborted;
7873
7874 case SCF_ERROR_EXISTS:
7875 warn(gettext(
7876 "Could not delete svc:/%s (instances exist).\n"),
7877 imp_tsname);
7878 break;
7879
7880 case SCF_ERROR_NOT_SET:
7881 case SCF_ERROR_NOT_BOUND:
7882 default:
7883 bad_error("scf_service_delete", scf_error());
7884 }
7885 }
7886
7887 return (r);
7888
7889 connaborted:
7890 warn(gettext("Could not delete svc:/%s "
7891 "(repository connection broken).\n"), imp_tsname);
7892 lcbdata->sc_err = ECONNABORTED;
7893 return (UU_WALK_ERROR);
7894 }
7895
7896 static const char *
import_progress(int st)7897 import_progress(int st)
7898 {
7899 switch (st) {
7900 case 0:
7901 return (gettext("not reached."));
7902
7903 case IMPORT_PREVIOUS:
7904 return (gettext("previous snapshot taken."));
7905
7906 case IMPORT_PROP_BEGUN:
7907 return (gettext("some properties imported."));
7908
7909 case IMPORT_PROP_DONE:
7910 return (gettext("properties imported."));
7911
7912 case IMPORT_COMPLETE:
7913 return (gettext("imported."));
7914
7915 case IMPORT_REFRESHED:
7916 return (gettext("refresh requested."));
7917
7918 default:
7919 #ifndef NDEBUG
7920 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7921 __FILE__, __LINE__, st);
7922 #endif
7923 abort();
7924 /* NOTREACHED */
7925 }
7926 }
7927
7928 /*
7929 * Returns
7930 * 0 - success
7931 * - fmri wasn't found (error printed)
7932 * - entity was deleted (error printed)
7933 * - backend denied access (error printed)
7934 * ENOMEM - out of memory (error printed)
7935 * ECONNABORTED - repository connection broken (error printed)
7936 * EPERM - permission denied (error printed)
7937 * -1 - unknown libscf error (error printed)
7938 */
7939 static int
imp_refresh_fmri(const char * fmri,const char * name,const char * d_fmri)7940 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7941 {
7942 scf_error_t serr;
7943 void *ent;
7944 int issvc;
7945 int r;
7946
7947 const char *deleted = gettext("Could not refresh %s (deleted).\n");
7948 const char *dpt_deleted = gettext("Could not refresh %s "
7949 "(dependent \"%s\" of %s) (deleted).\n");
7950
7951 serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7952 switch (serr) {
7953 case SCF_ERROR_NONE:
7954 break;
7955
7956 case SCF_ERROR_NO_MEMORY:
7957 if (name == NULL)
7958 warn(gettext("Could not refresh %s (out of memory).\n"),
7959 fmri);
7960 else
7961 warn(gettext("Could not refresh %s "
7962 "(dependent \"%s\" of %s) (out of memory).\n"),
7963 fmri, name, d_fmri);
7964 return (ENOMEM);
7965
7966 case SCF_ERROR_NOT_FOUND:
7967 if (name == NULL)
7968 warn(deleted, fmri);
7969 else
7970 warn(dpt_deleted, fmri, name, d_fmri);
7971 return (0);
7972
7973 case SCF_ERROR_INVALID_ARGUMENT:
7974 case SCF_ERROR_CONSTRAINT_VIOLATED:
7975 default:
7976 bad_error("fmri_to_entity", serr);
7977 }
7978
7979 r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7980 switch (r) {
7981 case 0:
7982 break;
7983
7984 case ECONNABORTED:
7985 if (name != NULL)
7986 warn(gettext("Could not refresh %s "
7987 "(dependent \"%s\" of %s) "
7988 "(repository connection broken).\n"), fmri, name,
7989 d_fmri);
7990 return (r);
7991
7992 case ECANCELED:
7993 if (name == NULL)
7994 warn(deleted, fmri);
7995 else
7996 warn(dpt_deleted, fmri, name, d_fmri);
7997 return (0);
7998
7999 case EACCES:
8000 if (!g_verbose)
8001 return (0);
8002 if (name == NULL)
8003 warn(gettext("Could not refresh %s "
8004 "(backend access denied).\n"), fmri);
8005 else
8006 warn(gettext("Could not refresh %s "
8007 "(dependent \"%s\" of %s) "
8008 "(backend access denied).\n"), fmri, name, d_fmri);
8009 return (0);
8010
8011 case EPERM:
8012 if (name == NULL)
8013 warn(gettext("Could not refresh %s "
8014 "(permission denied).\n"), fmri);
8015 else
8016 warn(gettext("Could not refresh %s "
8017 "(dependent \"%s\" of %s) "
8018 "(permission denied).\n"), fmri, name, d_fmri);
8019 return (r);
8020
8021 case ENOSPC:
8022 if (name == NULL)
8023 warn(gettext("Could not refresh %s "
8024 "(repository server out of resources).\n"),
8025 fmri);
8026 else
8027 warn(gettext("Could not refresh %s "
8028 "(dependent \"%s\" of %s) "
8029 "(repository server out of resources).\n"),
8030 fmri, name, d_fmri);
8031 return (r);
8032
8033 case -1:
8034 scfwarn();
8035 return (r);
8036
8037 default:
8038 bad_error("refresh_entity", r);
8039 }
8040
8041 if (issvc)
8042 scf_service_destroy(ent);
8043 else
8044 scf_instance_destroy(ent);
8045
8046 return (0);
8047 }
8048
8049 static int
alloc_imp_globals()8050 alloc_imp_globals()
8051 {
8052 int r;
8053
8054 const char * const emsg_nomem = gettext("Out of memory.\n");
8055 const char * const emsg_nores =
8056 gettext("svc.configd is out of resources.\n");
8057
8058 imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
8059 max_scf_name_len : max_scf_fmri_len) + 1;
8060
8061 if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
8062 (imp_svc = scf_service_create(g_hndl)) == NULL ||
8063 (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
8064 (imp_inst = scf_instance_create(g_hndl)) == NULL ||
8065 (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
8066 (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
8067 (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
8068 (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
8069 (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
8070 (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8071 (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
8072 (imp_pg = scf_pg_create(g_hndl)) == NULL ||
8073 (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
8074 (imp_prop = scf_property_create(g_hndl)) == NULL ||
8075 (imp_iter = scf_iter_create(g_hndl)) == NULL ||
8076 (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
8077 (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
8078 (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
8079 (imp_str = malloc(imp_str_sz)) == NULL ||
8080 (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
8081 (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
8082 (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
8083 (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
8084 (ud_inst = scf_instance_create(g_hndl)) == NULL ||
8085 (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8086 (ud_pg = scf_pg_create(g_hndl)) == NULL ||
8087 (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
8088 (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
8089 (ud_prop = scf_property_create(g_hndl)) == NULL ||
8090 (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
8091 (ud_val = scf_value_create(g_hndl)) == NULL ||
8092 (ud_iter = scf_iter_create(g_hndl)) == NULL ||
8093 (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
8094 (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
8095 (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
8096 (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
8097 (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
8098 if (scf_error() == SCF_ERROR_NO_RESOURCES)
8099 warn(emsg_nores);
8100 else
8101 warn(emsg_nomem);
8102
8103 return (-1);
8104 }
8105
8106 r = load_init();
8107 switch (r) {
8108 case 0:
8109 break;
8110
8111 case ENOMEM:
8112 warn(emsg_nomem);
8113 return (-1);
8114
8115 default:
8116 bad_error("load_init", r);
8117 }
8118
8119 return (0);
8120 }
8121
8122 static void
free_imp_globals()8123 free_imp_globals()
8124 {
8125 pgroup_t *old_dpt;
8126 void *cookie;
8127
8128 load_fini();
8129
8130 free(ud_ctarg);
8131 free(ud_oldtarg);
8132 free(ud_name);
8133 ud_ctarg = ud_oldtarg = ud_name = NULL;
8134
8135 scf_transaction_destroy(ud_tx);
8136 ud_tx = NULL;
8137 scf_iter_destroy(ud_iter);
8138 scf_iter_destroy(ud_iter2);
8139 ud_iter = ud_iter2 = NULL;
8140 scf_value_destroy(ud_val);
8141 ud_val = NULL;
8142 scf_property_destroy(ud_prop);
8143 scf_property_destroy(ud_dpt_prop);
8144 ud_prop = ud_dpt_prop = NULL;
8145 scf_pg_destroy(ud_pg);
8146 scf_pg_destroy(ud_cur_depts_pg);
8147 scf_pg_destroy(ud_run_dpts_pg);
8148 ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
8149 scf_snaplevel_destroy(ud_snpl);
8150 ud_snpl = NULL;
8151 scf_instance_destroy(ud_inst);
8152 ud_inst = NULL;
8153
8154 free(imp_str);
8155 free(imp_tsname);
8156 free(imp_fe1);
8157 free(imp_fe2);
8158 imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
8159
8160 cookie = NULL;
8161 while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
8162 NULL) {
8163 free((char *)old_dpt->sc_pgroup_name);
8164 free((char *)old_dpt->sc_pgroup_fmri);
8165 internal_pgroup_free(old_dpt);
8166 }
8167 uu_list_destroy(imp_deleted_dpts);
8168
8169 scf_transaction_destroy(imp_tx);
8170 imp_tx = NULL;
8171 scf_iter_destroy(imp_iter);
8172 scf_iter_destroy(imp_rpg_iter);
8173 scf_iter_destroy(imp_up_iter);
8174 imp_iter = imp_rpg_iter = imp_up_iter = NULL;
8175 scf_property_destroy(imp_prop);
8176 imp_prop = NULL;
8177 scf_pg_destroy(imp_pg);
8178 scf_pg_destroy(imp_pg2);
8179 imp_pg = imp_pg2 = NULL;
8180 scf_snaplevel_destroy(imp_snpl);
8181 scf_snaplevel_destroy(imp_rsnpl);
8182 imp_snpl = imp_rsnpl = NULL;
8183 scf_snapshot_destroy(imp_snap);
8184 scf_snapshot_destroy(imp_lisnap);
8185 scf_snapshot_destroy(imp_tlisnap);
8186 scf_snapshot_destroy(imp_rsnap);
8187 imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
8188 scf_instance_destroy(imp_inst);
8189 scf_instance_destroy(imp_tinst);
8190 imp_inst = imp_tinst = NULL;
8191 scf_service_destroy(imp_svc);
8192 scf_service_destroy(imp_tsvc);
8193 imp_svc = imp_tsvc = NULL;
8194 scf_scope_destroy(imp_scope);
8195 imp_scope = NULL;
8196
8197 load_fini();
8198 }
8199
8200 int
lscf_bundle_import(bundle_t * bndl,const char * filename,uint_t flags)8201 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
8202 {
8203 scf_callback_t cbdata;
8204 int result = 0;
8205 entity_t *svc, *inst;
8206 uu_list_t *insts;
8207 int r;
8208 pgroup_t *old_dpt;
8209 int annotation_set = 0;
8210
8211 const char * const emsg_nomem = gettext("Out of memory.\n");
8212 const char * const emsg_nores =
8213 gettext("svc.configd is out of resources.\n");
8214
8215 lscf_prep_hndl();
8216
8217 if (alloc_imp_globals())
8218 goto out;
8219
8220 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
8221 switch (scf_error()) {
8222 case SCF_ERROR_CONNECTION_BROKEN:
8223 warn(gettext("Repository connection broken.\n"));
8224 repository_teardown();
8225 result = -1;
8226 goto out;
8227
8228 case SCF_ERROR_NOT_FOUND:
8229 case SCF_ERROR_INVALID_ARGUMENT:
8230 case SCF_ERROR_NOT_BOUND:
8231 case SCF_ERROR_HANDLE_MISMATCH:
8232 default:
8233 bad_error("scf_handle_get_scope", scf_error());
8234 }
8235 }
8236
8237 /* Set up the auditing annotation. */
8238 if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
8239 annotation_set = 1;
8240 } else {
8241 switch (scf_error()) {
8242 case SCF_ERROR_CONNECTION_BROKEN:
8243 warn(gettext("Repository connection broken.\n"));
8244 repository_teardown();
8245 result = -1;
8246 goto out;
8247
8248 case SCF_ERROR_INVALID_ARGUMENT:
8249 case SCF_ERROR_NOT_BOUND:
8250 case SCF_ERROR_NO_RESOURCES:
8251 case SCF_ERROR_INTERNAL:
8252 bad_error("_scf_set_annotation", scf_error());
8253 /* NOTREACHED */
8254
8255 default:
8256 /*
8257 * Do not terminate import because of inability to
8258 * generate annotation audit event.
8259 */
8260 warn(gettext("_scf_set_annotation() unexpectedly "
8261 "failed with return code of %d\n"), scf_error());
8262 break;
8263 }
8264 }
8265
8266 /*
8267 * Clear the sc_import_state's of all services & instances so we can
8268 * report how far we got if we fail.
8269 */
8270 for (svc = uu_list_first(bndl->sc_bundle_services);
8271 svc != NULL;
8272 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8273 svc->sc_import_state = 0;
8274
8275 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
8276 clear_int, (void *)offsetof(entity_t, sc_import_state),
8277 UU_DEFAULT) != 0)
8278 bad_error("uu_list_walk", uu_error());
8279 }
8280
8281 cbdata.sc_handle = g_hndl;
8282 cbdata.sc_parent = imp_scope;
8283 cbdata.sc_flags = flags;
8284 cbdata.sc_general = NULL;
8285
8286 if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
8287 &cbdata, UU_DEFAULT) == 0) {
8288 char *eptr;
8289 /* Success. Refresh everything. */
8290
8291 if (flags & SCI_NOREFRESH || no_refresh) {
8292 no_refresh = 0;
8293 result = 0;
8294 goto out;
8295 }
8296
8297 for (svc = uu_list_first(bndl->sc_bundle_services);
8298 svc != NULL;
8299 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8300 pgroup_t *dpt;
8301
8302 insts = svc->sc_u.sc_service.sc_service_instances;
8303
8304 for (inst = uu_list_first(insts);
8305 inst != NULL;
8306 inst = uu_list_next(insts, inst)) {
8307 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
8308 switch (r) {
8309 case 0:
8310 break;
8311
8312 case ENOMEM:
8313 case ECONNABORTED:
8314 case EPERM:
8315 case -1:
8316 goto progress;
8317
8318 default:
8319 bad_error("imp_refresh_fmri", r);
8320 }
8321
8322 inst->sc_import_state = IMPORT_REFRESHED;
8323
8324 for (dpt = uu_list_first(inst->sc_dependents);
8325 dpt != NULL;
8326 dpt = uu_list_next(inst->sc_dependents,
8327 dpt))
8328 if (imp_refresh_fmri(
8329 dpt->sc_pgroup_fmri,
8330 dpt->sc_pgroup_name,
8331 inst->sc_fmri) != 0)
8332 goto progress;
8333 }
8334
8335 for (dpt = uu_list_first(svc->sc_dependents);
8336 dpt != NULL;
8337 dpt = uu_list_next(svc->sc_dependents, dpt))
8338 if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
8339 dpt->sc_pgroup_name, svc->sc_fmri) != 0)
8340 goto progress;
8341 }
8342
8343 for (old_dpt = uu_list_first(imp_deleted_dpts);
8344 old_dpt != NULL;
8345 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
8346 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8347 old_dpt->sc_pgroup_name,
8348 old_dpt->sc_parent->sc_fmri) != 0)
8349 goto progress;
8350
8351 result = 0;
8352
8353 /*
8354 * This snippet of code assumes that we are running svccfg as we
8355 * normally do -- witih svc.startd running. Of course, that is
8356 * not actually the case all the time because we also use a
8357 * varient of svc.configd and svccfg which are only meant to
8358 * run during the build process. During this time we have no
8359 * svc.startd, so this check would hang the build process.
8360 *
8361 * However, we've also given other consolidations, a bit of a
8362 * means to tie themselves into a knot. They're not properly
8363 * using the native build equivalents, but they've been getting
8364 * away with it anyways. Therefore, if we've found that
8365 * SVCCFG_REPOSITORY is set indicating that a separate configd
8366 * should be spun up, then we have to assume it's not using a
8367 * startd and we should not do this check.
8368 */
8369 #ifndef NATIVE_BUILD
8370 /*
8371 * Verify that the restarter group is preset
8372 */
8373 eptr = getenv("SVCCFG_REPOSITORY");
8374 for (svc = uu_list_first(bndl->sc_bundle_services);
8375 svc != NULL && eptr == NULL;
8376 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8377
8378 insts = svc->sc_u.sc_service.sc_service_instances;
8379
8380 for (inst = uu_list_first(insts);
8381 inst != NULL;
8382 inst = uu_list_next(insts, inst)) {
8383 if (lscf_instance_verify(imp_scope, svc,
8384 inst) != 0)
8385 goto progress;
8386 }
8387 }
8388 #endif
8389 goto out;
8390
8391 }
8392
8393 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8394 bad_error("uu_list_walk", uu_error());
8395
8396 /* If the error hasn't been printed yet, do so here. */
8397 switch (cbdata.sc_err) {
8398 case ECONNABORTED:
8399 warn(gettext("Repository connection broken.\n"));
8400 break;
8401
8402 case ENOMEM:
8403 warn(emsg_nomem);
8404 break;
8405
8406 case ENOSPC:
8407 warn(emsg_nores);
8408 break;
8409
8410 case EROFS:
8411 warn(gettext("Repository is read-only.\n"));
8412 break;
8413
8414 case EACCES:
8415 warn(gettext("Repository backend denied access.\n"));
8416 break;
8417
8418 case EPERM:
8419 case EINVAL:
8420 case EEXIST:
8421 case EBUSY:
8422 case EBADF:
8423 case -1:
8424 break;
8425
8426 default:
8427 bad_error("lscf_service_import", cbdata.sc_err);
8428 }
8429
8430 progress:
8431 warn(gettext("Import of %s failed. Progress:\n"), filename);
8432
8433 for (svc = uu_list_first(bndl->sc_bundle_services);
8434 svc != NULL;
8435 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8436 insts = svc->sc_u.sc_service.sc_service_instances;
8437
8438 warn(gettext(" Service \"%s\": %s\n"), svc->sc_name,
8439 import_progress(svc->sc_import_state));
8440
8441 for (inst = uu_list_first(insts);
8442 inst != NULL;
8443 inst = uu_list_next(insts, inst))
8444 warn(gettext(" Instance \"%s\": %s\n"),
8445 inst->sc_name,
8446 import_progress(inst->sc_import_state));
8447 }
8448
8449 if (cbdata.sc_err == ECONNABORTED)
8450 repository_teardown();
8451
8452
8453 result = -1;
8454
8455 out:
8456 if (annotation_set != 0) {
8457 /* Turn off annotation. It is no longer needed. */
8458 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8459 }
8460
8461 free_imp_globals();
8462
8463 return (result);
8464 }
8465
8466 /*
8467 * _lscf_import_err() summarize the error handling returned by
8468 * lscf_import_{instance | service}_pgs
8469 * Return values are:
8470 * IMPORT_NEXT
8471 * IMPORT_OUT
8472 * IMPORT_BAD
8473 */
8474
8475 #define IMPORT_BAD -1
8476 #define IMPORT_NEXT 0
8477 #define IMPORT_OUT 1
8478
8479 static int
_lscf_import_err(int err,const char * fmri)8480 _lscf_import_err(int err, const char *fmri)
8481 {
8482 switch (err) {
8483 case 0:
8484 if (g_verbose)
8485 warn(gettext("%s updated.\n"), fmri);
8486 return (IMPORT_NEXT);
8487
8488 case ECONNABORTED:
8489 warn(gettext("Could not update %s "
8490 "(repository connection broken).\n"), fmri);
8491 return (IMPORT_OUT);
8492
8493 case ENOMEM:
8494 warn(gettext("Could not update %s (out of memory).\n"), fmri);
8495 return (IMPORT_OUT);
8496
8497 case ENOSPC:
8498 warn(gettext("Could not update %s "
8499 "(repository server out of resources).\n"), fmri);
8500 return (IMPORT_OUT);
8501
8502 case ECANCELED:
8503 warn(gettext(
8504 "Could not update %s (deleted).\n"), fmri);
8505 return (IMPORT_NEXT);
8506
8507 case EPERM:
8508 case EINVAL:
8509 case EBUSY:
8510 return (IMPORT_NEXT);
8511
8512 case EROFS:
8513 warn(gettext("Could not update %s (repository read-only).\n"),
8514 fmri);
8515 return (IMPORT_OUT);
8516
8517 case EACCES:
8518 warn(gettext("Could not update %s "
8519 "(backend access denied).\n"), fmri);
8520 return (IMPORT_NEXT);
8521
8522 case EEXIST:
8523 default:
8524 return (IMPORT_BAD);
8525 }
8526
8527 /*NOTREACHED*/
8528 }
8529
8530 /*
8531 * The global imp_svc and imp_inst should be set by the caller in the
8532 * check to make sure the service and instance exist that the apply is
8533 * working on.
8534 */
8535 static int
lscf_dependent_apply(void * dpg,void * e)8536 lscf_dependent_apply(void *dpg, void *e)
8537 {
8538 scf_callback_t cb;
8539 pgroup_t *dpt_pgroup = dpg;
8540 pgroup_t *deldpt;
8541 entity_t *ent = e;
8542 int tissvc;
8543 void *sc_ent, *tent;
8544 scf_error_t serr;
8545 int r;
8546
8547 const char * const dependents = "dependents";
8548 const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT);
8549
8550 if (issvc)
8551 sc_ent = imp_svc;
8552 else
8553 sc_ent = imp_inst;
8554
8555 if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg,
8556 imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 ||
8557 scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name,
8558 imp_prop) != 0) {
8559 switch (scf_error()) {
8560 case SCF_ERROR_NOT_FOUND:
8561 case SCF_ERROR_DELETED:
8562 break;
8563
8564 case SCF_ERROR_CONNECTION_BROKEN:
8565 case SCF_ERROR_NOT_SET:
8566 case SCF_ERROR_INVALID_ARGUMENT:
8567 case SCF_ERROR_HANDLE_MISMATCH:
8568 case SCF_ERROR_NOT_BOUND:
8569 default:
8570 bad_error("entity_get_pg", scf_error());
8571 }
8572 } else {
8573 /*
8574 * Found the dependents/<wip dep> so check to
8575 * see if the service is different. If so
8576 * store the service for later refresh, and
8577 * delete the wip dependency from the service
8578 */
8579 if (scf_property_get_value(imp_prop, ud_val) != 0) {
8580 switch (scf_error()) {
8581 case SCF_ERROR_DELETED:
8582 break;
8583
8584 case SCF_ERROR_CONNECTION_BROKEN:
8585 case SCF_ERROR_NOT_SET:
8586 case SCF_ERROR_INVALID_ARGUMENT:
8587 case SCF_ERROR_HANDLE_MISMATCH:
8588 case SCF_ERROR_NOT_BOUND:
8589 default:
8590 bad_error("scf_property_get_value",
8591 scf_error());
8592 }
8593 }
8594
8595 if (scf_value_get_as_string(ud_val, ud_oldtarg,
8596 max_scf_value_len + 1) < 0)
8597 bad_error("scf_value_get_as_string", scf_error());
8598
8599 r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
8600 switch (r) {
8601 case 1:
8602 break;
8603 case 0:
8604 if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent,
8605 &tissvc)) != SCF_ERROR_NONE) {
8606 if (serr == SCF_ERROR_NOT_FOUND) {
8607 break;
8608 } else {
8609 bad_error("fmri_to_entity", serr);
8610 }
8611 }
8612
8613 if (entity_get_pg(tent, tissvc,
8614 dpt_pgroup->sc_pgroup_name, imp_pg) != 0) {
8615 serr = scf_error();
8616 if (serr == SCF_ERROR_NOT_FOUND ||
8617 serr == SCF_ERROR_DELETED) {
8618 break;
8619 } else {
8620 bad_error("entity_get_pg", scf_error());
8621 }
8622 }
8623
8624 if (scf_pg_delete(imp_pg) != 0) {
8625 serr = scf_error();
8626 if (serr == SCF_ERROR_NOT_FOUND ||
8627 serr == SCF_ERROR_DELETED) {
8628 break;
8629 } else {
8630 bad_error("scf_pg_delete", scf_error());
8631 }
8632 }
8633
8634 deldpt = internal_pgroup_new();
8635 if (deldpt == NULL)
8636 return (ENOMEM);
8637 deldpt->sc_pgroup_name =
8638 strdup(dpt_pgroup->sc_pgroup_name);
8639 deldpt->sc_pgroup_fmri = strdup(ud_oldtarg);
8640 if (deldpt->sc_pgroup_name == NULL ||
8641 deldpt->sc_pgroup_fmri == NULL)
8642 return (ENOMEM);
8643 deldpt->sc_parent = (entity_t *)ent;
8644 if (uu_list_insert_after(imp_deleted_dpts, NULL,
8645 deldpt) != 0)
8646 uu_die(gettext("libuutil error: %s\n"),
8647 uu_strerror(uu_error()));
8648
8649 break;
8650 default:
8651 bad_error("fmri_equal", r);
8652 }
8653 }
8654
8655 cb.sc_handle = g_hndl;
8656 cb.sc_parent = ent;
8657 cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT;
8658 cb.sc_source_fmri = ent->sc_fmri;
8659 cb.sc_target_fmri = ent->sc_fmri;
8660 cb.sc_trans = NULL;
8661 cb.sc_flags = SCI_FORCE;
8662
8663 if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT)
8664 return (UU_WALK_ERROR);
8665
8666 r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL);
8667 switch (r) {
8668 case 0:
8669 break;
8670
8671 case ENOMEM:
8672 case ECONNABORTED:
8673 case EPERM:
8674 case -1:
8675 warn(gettext("Unable to refresh \"%s\"\n"),
8676 dpt_pgroup->sc_pgroup_fmri);
8677 return (UU_WALK_ERROR);
8678
8679 default:
8680 bad_error("imp_refresh_fmri", r);
8681 }
8682
8683 return (UU_WALK_NEXT);
8684 }
8685
8686 /*
8687 * Returns
8688 * 0 - success
8689 * -1 - lscf_import_instance_pgs() failed.
8690 */
8691 int
lscf_bundle_apply(bundle_t * bndl,const char * file)8692 lscf_bundle_apply(bundle_t *bndl, const char *file)
8693 {
8694 pgroup_t *old_dpt;
8695 entity_t *svc, *inst;
8696 int annotation_set = 0;
8697 int ret = 0;
8698 int r = 0;
8699
8700 lscf_prep_hndl();
8701
8702 if ((ret = alloc_imp_globals()))
8703 goto out;
8704
8705 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0)
8706 scfdie();
8707
8708 /*
8709 * Set the strings to be used for the security audit annotation
8710 * event.
8711 */
8712 if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
8713 annotation_set = 1;
8714 } else {
8715 switch (scf_error()) {
8716 case SCF_ERROR_CONNECTION_BROKEN:
8717 warn(gettext("Repository connection broken.\n"));
8718 goto out;
8719
8720 case SCF_ERROR_INVALID_ARGUMENT:
8721 case SCF_ERROR_NOT_BOUND:
8722 case SCF_ERROR_NO_RESOURCES:
8723 case SCF_ERROR_INTERNAL:
8724 bad_error("_scf_set_annotation", scf_error());
8725 /* NOTREACHED */
8726
8727 default:
8728 /*
8729 * Do not abort apply operation because of
8730 * inability to create annotation audit event.
8731 */
8732 warn(gettext("_scf_set_annotation() unexpectedly "
8733 "failed with return code of %d\n"), scf_error());
8734 break;
8735 }
8736 }
8737
8738 for (svc = uu_list_first(bndl->sc_bundle_services);
8739 svc != NULL;
8740 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8741 int refresh = 0;
8742
8743 if (scf_scope_get_service(imp_scope, svc->sc_name,
8744 imp_svc) != 0) {
8745 switch (scf_error()) {
8746 case SCF_ERROR_NOT_FOUND:
8747 if (g_verbose)
8748 warn(gettext("Ignoring nonexistent "
8749 "service %s.\n"), svc->sc_name);
8750 continue;
8751
8752 default:
8753 scfdie();
8754 }
8755 }
8756
8757 /*
8758 * If there were missing types in the profile, then need to
8759 * attempt to find the types.
8760 */
8761 if (svc->sc_miss_type) {
8762 if (uu_list_numnodes(svc->sc_pgroups) &&
8763 uu_list_walk(svc->sc_pgroups, find_current_pg_type,
8764 svc, UU_DEFAULT) != 0) {
8765 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8766 bad_error("uu_list_walk", uu_error());
8767
8768 ret = -1;
8769 continue;
8770 }
8771
8772 for (inst = uu_list_first(
8773 svc->sc_u.sc_service.sc_service_instances);
8774 inst != NULL;
8775 inst = uu_list_next(
8776 svc->sc_u.sc_service.sc_service_instances, inst)) {
8777 /*
8778 * If the instance doesn't exist just
8779 * skip to the next instance and let the
8780 * import note the missing instance.
8781 */
8782 if (scf_service_get_instance(imp_svc,
8783 inst->sc_name, imp_inst) != 0)
8784 continue;
8785
8786 if (uu_list_walk(inst->sc_pgroups,
8787 find_current_pg_type, inst,
8788 UU_DEFAULT) != 0) {
8789 if (uu_error() !=
8790 UU_ERROR_CALLBACK_FAILED)
8791 bad_error("uu_list_walk",
8792 uu_error());
8793
8794 ret = -1;
8795 inst->sc_miss_type = B_TRUE;
8796 }
8797 }
8798 }
8799
8800 /*
8801 * if we have pgs in the profile, we need to refresh ALL
8802 * instances of the service
8803 */
8804 if (uu_list_numnodes(svc->sc_pgroups) != 0) {
8805 refresh = 1;
8806 r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc,
8807 SCI_FORCE | SCI_KEEP);
8808 switch (_lscf_import_err(r, svc->sc_fmri)) {
8809 case IMPORT_NEXT:
8810 break;
8811
8812 case IMPORT_OUT:
8813 goto out;
8814
8815 case IMPORT_BAD:
8816 default:
8817 bad_error("lscf_import_service_pgs", r);
8818 }
8819 }
8820
8821 if (uu_list_numnodes(svc->sc_dependents) != 0) {
8822 uu_list_walk(svc->sc_dependents,
8823 lscf_dependent_apply, svc, UU_DEFAULT);
8824 }
8825
8826 for (inst = uu_list_first(
8827 svc->sc_u.sc_service.sc_service_instances);
8828 inst != NULL;
8829 inst = uu_list_next(
8830 svc->sc_u.sc_service.sc_service_instances, inst)) {
8831 /*
8832 * This instance still has missing types
8833 * so skip it.
8834 */
8835 if (inst->sc_miss_type) {
8836 if (g_verbose)
8837 warn(gettext("Ignoring instance "
8838 "%s:%s with missing types\n"),
8839 inst->sc_parent->sc_name,
8840 inst->sc_name);
8841
8842 continue;
8843 }
8844
8845 if (scf_service_get_instance(imp_svc, inst->sc_name,
8846 imp_inst) != 0) {
8847 switch (scf_error()) {
8848 case SCF_ERROR_NOT_FOUND:
8849 if (g_verbose)
8850 warn(gettext("Ignoring "
8851 "nonexistant instance "
8852 "%s:%s.\n"),
8853 inst->sc_parent->sc_name,
8854 inst->sc_name);
8855 continue;
8856
8857 default:
8858 scfdie();
8859 }
8860 }
8861
8862 /*
8863 * If the instance does not have a general/enabled
8864 * property and no last-import snapshot then the
8865 * instance is not a fully installed instance and
8866 * should not have a profile applied to it.
8867 *
8868 * This could happen if a service/instance declares
8869 * a dependent on behalf of another service/instance.
8870 *
8871 */
8872 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
8873 imp_snap) != 0) {
8874 if (scf_instance_get_pg(imp_inst,
8875 SCF_PG_GENERAL, imp_pg) != 0 ||
8876 scf_pg_get_property(imp_pg,
8877 SCF_PROPERTY_ENABLED, imp_prop) != 0) {
8878 if (g_verbose)
8879 warn(gettext("Ignoreing "
8880 "partial instance "
8881 "%s:%s.\n"),
8882 inst->sc_parent->sc_name,
8883 inst->sc_name);
8884 continue;
8885 }
8886 }
8887
8888 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri,
8889 inst, SCI_FORCE | SCI_KEEP);
8890 switch (_lscf_import_err(r, inst->sc_fmri)) {
8891 case IMPORT_NEXT:
8892 break;
8893
8894 case IMPORT_OUT:
8895 goto out;
8896
8897 case IMPORT_BAD:
8898 default:
8899 bad_error("lscf_import_instance_pgs", r);
8900 }
8901
8902 if (uu_list_numnodes(inst->sc_dependents) != 0) {
8903 uu_list_walk(inst->sc_dependents,
8904 lscf_dependent_apply, inst, UU_DEFAULT);
8905 }
8906
8907 /* refresh only if there is no pgs in the service */
8908 if (refresh == 0)
8909 (void) refresh_entity(0, imp_inst,
8910 inst->sc_fmri, NULL, NULL, NULL);
8911 }
8912
8913 if (refresh == 1) {
8914 char *name_buf = safe_malloc(max_scf_name_len + 1);
8915
8916 (void) refresh_entity(1, imp_svc, svc->sc_name,
8917 imp_inst, imp_iter, name_buf);
8918 free(name_buf);
8919 }
8920
8921 for (old_dpt = uu_list_first(imp_deleted_dpts);
8922 old_dpt != NULL;
8923 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) {
8924 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8925 old_dpt->sc_pgroup_name,
8926 old_dpt->sc_parent->sc_fmri) != 0) {
8927 warn(gettext("Unable to refresh \"%s\"\n"),
8928 old_dpt->sc_pgroup_fmri);
8929 }
8930 }
8931 }
8932
8933 out:
8934 if (annotation_set) {
8935 /* Remove security audit annotation strings. */
8936 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8937 }
8938
8939 free_imp_globals();
8940 return (ret);
8941 }
8942
8943
8944 /*
8945 * Export. These functions create and output an XML tree of a service
8946 * description from the repository. This is largely the inverse of
8947 * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
8948 *
8949 * - We must include any properties which are not represented specifically by
8950 * a service manifest, e.g., properties created by an admin post-import. To
8951 * do so we'll iterate through all properties and deal with each
8952 * apropriately.
8953 *
8954 * - Children of services and instances must must be in the order set by the
8955 * DTD, but we iterate over the properties in undefined order. The elements
8956 * are not easily (or efficiently) sortable by name. Since there's a fixed
8957 * number of classes of them, however, we'll keep the classes separate and
8958 * assemble them in order.
8959 */
8960
8961 /*
8962 * Convenience function to handle xmlSetProp errors (and type casting).
8963 */
8964 static void
safe_setprop(xmlNodePtr n,const char * name,const char * val)8965 safe_setprop(xmlNodePtr n, const char *name, const char *val)
8966 {
8967 if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
8968 uu_die(gettext("Could not set XML property.\n"));
8969 }
8970
8971 /*
8972 * Convenience function to set an XML attribute to the single value of an
8973 * astring property. If the value happens to be the default, don't set the
8974 * attribute. "dval" should be the default value supplied by the DTD, or
8975 * NULL for no default.
8976 */
8977 static int
set_attr_from_prop_default(scf_property_t * prop,xmlNodePtr n,const char * name,const char * dval)8978 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
8979 const char *name, const char *dval)
8980 {
8981 scf_value_t *val;
8982 ssize_t len;
8983 char *str;
8984
8985 val = scf_value_create(g_hndl);
8986 if (val == NULL)
8987 scfdie();
8988
8989 if (prop_get_val(prop, val) != 0) {
8990 scf_value_destroy(val);
8991 return (-1);
8992 }
8993
8994 len = scf_value_get_as_string(val, NULL, 0);
8995 if (len < 0)
8996 scfdie();
8997
8998 str = safe_malloc(len + 1);
8999
9000 if (scf_value_get_as_string(val, str, len + 1) < 0)
9001 scfdie();
9002
9003 scf_value_destroy(val);
9004
9005 if (dval == NULL || strcmp(str, dval) != 0)
9006 safe_setprop(n, name, str);
9007
9008 free(str);
9009
9010 return (0);
9011 }
9012
9013 /*
9014 * As above, but the attribute is always set.
9015 */
9016 static int
set_attr_from_prop(scf_property_t * prop,xmlNodePtr n,const char * name)9017 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
9018 {
9019 return (set_attr_from_prop_default(prop, n, name, NULL));
9020 }
9021
9022 /*
9023 * Dump the given document onto f, with "'s replaced by ''s.
9024 */
9025 static int
write_service_bundle(xmlDocPtr doc,FILE * f)9026 write_service_bundle(xmlDocPtr doc, FILE *f)
9027 {
9028 xmlChar *mem;
9029 int sz, i;
9030
9031 mem = NULL;
9032 xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
9033
9034 if (mem == NULL) {
9035 semerr(gettext("Could not dump XML tree.\n"));
9036 return (-1);
9037 }
9038
9039 /*
9040 * Fortunately libxml produces " instead of ", so we can blindly
9041 * replace all " with '. Cursed libxml2! Why must you #ifdef out the
9042 * ' code?!
9043 */
9044 for (i = 0; i < sz; ++i) {
9045 char c = (char)mem[i];
9046
9047 if (c == '"')
9048 (void) fputc('\'', f);
9049 else if (c == '\'')
9050 (void) fwrite("'", sizeof ("'") - 1, 1, f);
9051 else
9052 (void) fputc(c, f);
9053 }
9054
9055 return (0);
9056 }
9057
9058 /*
9059 * Create the DOM elements in elts necessary to (generically) represent prop
9060 * (i.e., a property or propval element). If the name of the property is
9061 * known, it should be passed as name_arg. Otherwise, pass NULL.
9062 */
9063 static void
export_property(scf_property_t * prop,const char * name_arg,struct pg_elts * elts,int flags)9064 export_property(scf_property_t *prop, const char *name_arg,
9065 struct pg_elts *elts, int flags)
9066 {
9067 const char *type;
9068 scf_error_t err = 0;
9069 xmlNodePtr pnode, lnode;
9070 char *lnname;
9071 int ret;
9072
9073 /* name */
9074 if (name_arg != NULL) {
9075 (void) strcpy(exp_str, name_arg);
9076 } else {
9077 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
9078 scfdie();
9079 }
9080
9081 /* type */
9082 type = prop_to_typestr(prop);
9083 if (type == NULL)
9084 uu_die(gettext("Can't export property %s: unknown type.\n"),
9085 exp_str);
9086
9087 /* If we're exporting values, and there's just one, export it here. */
9088 if (!(flags & SCE_ALL_VALUES))
9089 goto empty;
9090
9091 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
9092 xmlNodePtr n;
9093
9094 /* Single value, so use propval */
9095 n = xmlNewNode(NULL, (xmlChar *)"propval");
9096 if (n == NULL)
9097 uu_die(emsg_create_xml);
9098
9099 safe_setprop(n, name_attr, exp_str);
9100 safe_setprop(n, type_attr, type);
9101
9102 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9103 scfdie();
9104 safe_setprop(n, value_attr, exp_str);
9105
9106 if (elts->propvals == NULL)
9107 elts->propvals = n;
9108 else
9109 (void) xmlAddSibling(elts->propvals, n);
9110
9111 return;
9112 }
9113
9114 err = scf_error();
9115
9116 if (err == SCF_ERROR_PERMISSION_DENIED) {
9117 semerr(emsg_permission_denied);
9118 return;
9119 }
9120
9121 if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
9122 err != SCF_ERROR_NOT_FOUND &&
9123 err != SCF_ERROR_PERMISSION_DENIED)
9124 scfdie();
9125
9126 empty:
9127 /* Multiple (or no) values, so use property */
9128 pnode = xmlNewNode(NULL, (xmlChar *)"property");
9129 if (pnode == NULL)
9130 uu_die(emsg_create_xml);
9131
9132 safe_setprop(pnode, name_attr, exp_str);
9133 safe_setprop(pnode, type_attr, type);
9134
9135 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
9136 lnname = uu_msprintf("%s_list", type);
9137 if (lnname == NULL)
9138 uu_die(gettext("Could not create string"));
9139
9140 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
9141 if (lnode == NULL)
9142 uu_die(emsg_create_xml);
9143
9144 uu_free(lnname);
9145
9146 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
9147 scfdie();
9148
9149 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
9150 1) {
9151 xmlNodePtr vn;
9152
9153 vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
9154 NULL);
9155 if (vn == NULL)
9156 uu_die(emsg_create_xml);
9157
9158 if (scf_value_get_as_string(exp_val, exp_str,
9159 exp_str_sz) < 0)
9160 scfdie();
9161 safe_setprop(vn, value_attr, exp_str);
9162 }
9163 if (ret != 0)
9164 scfdie();
9165 }
9166
9167 if (elts->properties == NULL)
9168 elts->properties = pnode;
9169 else
9170 (void) xmlAddSibling(elts->properties, pnode);
9171 }
9172
9173 /*
9174 * Add a property_group element for this property group to elts.
9175 */
9176 static void
export_pg(scf_propertygroup_t * pg,struct entity_elts * eelts,int flags)9177 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
9178 {
9179 xmlNodePtr n;
9180 struct pg_elts elts;
9181 int ret;
9182 boolean_t read_protected;
9183
9184 n = xmlNewNode(NULL, (xmlChar *)"property_group");
9185
9186 /* name */
9187 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9188 scfdie();
9189 safe_setprop(n, name_attr, exp_str);
9190
9191 /* type */
9192 if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
9193 scfdie();
9194 safe_setprop(n, type_attr, exp_str);
9195
9196 /* properties */
9197 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9198 scfdie();
9199
9200 (void) memset(&elts, 0, sizeof (elts));
9201
9202 /*
9203 * If this property group is not read protected, we always want to
9204 * output all the values. Otherwise, we only output the values if the
9205 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
9206 */
9207 if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
9208 scfdie();
9209
9210 if (!read_protected)
9211 flags |= SCE_ALL_VALUES;
9212
9213 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9214 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9215 scfdie();
9216
9217 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9218 xmlNodePtr m;
9219
9220 m = xmlNewNode(NULL, (xmlChar *)"stability");
9221 if (m == NULL)
9222 uu_die(emsg_create_xml);
9223
9224 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9225 elts.stability = m;
9226 continue;
9227 }
9228
9229 xmlFreeNode(m);
9230 }
9231
9232 export_property(exp_prop, NULL, &elts, flags);
9233 }
9234 if (ret == -1)
9235 scfdie();
9236
9237 (void) xmlAddChild(n, elts.stability);
9238 (void) xmlAddChildList(n, elts.propvals);
9239 (void) xmlAddChildList(n, elts.properties);
9240
9241 if (eelts->property_groups == NULL)
9242 eelts->property_groups = n;
9243 else
9244 (void) xmlAddSibling(eelts->property_groups, n);
9245 }
9246
9247 /*
9248 * Create an XML node representing the dependency described by the given
9249 * property group and put it in eelts. Unless the dependency is not valid, in
9250 * which case create a generic property_group element which represents it and
9251 * put it in eelts.
9252 */
9253 static void
export_dependency(scf_propertygroup_t * pg,struct entity_elts * eelts)9254 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
9255 {
9256 xmlNodePtr n;
9257 int err = 0, ret;
9258 struct pg_elts elts;
9259
9260 n = xmlNewNode(NULL, (xmlChar *)"dependency");
9261 if (n == NULL)
9262 uu_die(emsg_create_xml);
9263
9264 /*
9265 * If the external flag is present, skip this dependency because it
9266 * should have been created by another manifest.
9267 */
9268 if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
9269 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9270 prop_get_val(exp_prop, exp_val) == 0) {
9271 uint8_t b;
9272
9273 if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
9274 scfdie();
9275
9276 if (b)
9277 return;
9278 }
9279 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
9280 scfdie();
9281
9282 /* Get the required attributes. */
9283
9284 /* name */
9285 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9286 scfdie();
9287 safe_setprop(n, name_attr, exp_str);
9288
9289 /* grouping */
9290 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9291 set_attr_from_prop(exp_prop, n, "grouping") != 0)
9292 err = 1;
9293
9294 /* restart_on */
9295 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9296 set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9297 err = 1;
9298
9299 /* type */
9300 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9301 set_attr_from_prop(exp_prop, n, type_attr) != 0)
9302 err = 1;
9303
9304 /*
9305 * entities: Not required, but if we create no children, it will be
9306 * created as empty on import, so fail if it's missing.
9307 */
9308 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9309 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
9310 scf_iter_t *eiter;
9311 int ret2;
9312
9313 eiter = scf_iter_create(g_hndl);
9314 if (eiter == NULL)
9315 scfdie();
9316
9317 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
9318 scfdie();
9319
9320 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
9321 xmlNodePtr ch;
9322
9323 if (scf_value_get_astring(exp_val, exp_str,
9324 exp_str_sz) < 0)
9325 scfdie();
9326
9327 /*
9328 * service_fmri's must be first, so we can add them
9329 * here.
9330 */
9331 ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
9332 NULL);
9333 if (ch == NULL)
9334 uu_die(emsg_create_xml);
9335
9336 safe_setprop(ch, value_attr, exp_str);
9337 }
9338 if (ret2 == -1)
9339 scfdie();
9340
9341 scf_iter_destroy(eiter);
9342 } else
9343 err = 1;
9344
9345 if (err) {
9346 xmlFreeNode(n);
9347
9348 export_pg(pg, eelts, SCE_ALL_VALUES);
9349
9350 return;
9351 }
9352
9353 /* Iterate through the properties & handle each. */
9354 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9355 scfdie();
9356
9357 (void) memset(&elts, 0, sizeof (elts));
9358
9359 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9360 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9361 scfdie();
9362
9363 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9364 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9365 strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9366 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9367 continue;
9368 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9369 xmlNodePtr m;
9370
9371 m = xmlNewNode(NULL, (xmlChar *)"stability");
9372 if (m == NULL)
9373 uu_die(emsg_create_xml);
9374
9375 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9376 elts.stability = m;
9377 continue;
9378 }
9379
9380 xmlFreeNode(m);
9381 }
9382
9383 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9384 }
9385 if (ret == -1)
9386 scfdie();
9387
9388 (void) xmlAddChild(n, elts.stability);
9389 (void) xmlAddChildList(n, elts.propvals);
9390 (void) xmlAddChildList(n, elts.properties);
9391
9392 if (eelts->dependencies == NULL)
9393 eelts->dependencies = n;
9394 else
9395 (void) xmlAddSibling(eelts->dependencies, n);
9396 }
9397
9398 static xmlNodePtr
export_method_environment(scf_propertygroup_t * pg)9399 export_method_environment(scf_propertygroup_t *pg)
9400 {
9401 xmlNodePtr env;
9402 int ret;
9403 int children = 0;
9404
9405 if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
9406 return (NULL);
9407
9408 env = xmlNewNode(NULL, (xmlChar *)"method_environment");
9409 if (env == NULL)
9410 uu_die(emsg_create_xml);
9411
9412 if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
9413 scfdie();
9414
9415 if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
9416 scfdie();
9417
9418 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
9419 xmlNodePtr ev;
9420 char *cp;
9421
9422 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9423 scfdie();
9424
9425 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
9426 warn(gettext("Invalid environment variable \"%s\".\n"),
9427 exp_str);
9428 continue;
9429 } else if (strncmp(exp_str, "SMF_", 4) == 0) {
9430 warn(gettext("Invalid environment variable \"%s\"; "
9431 "\"SMF_\" prefix is reserved.\n"), exp_str);
9432 continue;
9433 }
9434
9435 *cp = '\0';
9436 cp++;
9437
9438 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
9439 if (ev == NULL)
9440 uu_die(emsg_create_xml);
9441
9442 safe_setprop(ev, name_attr, exp_str);
9443 safe_setprop(ev, value_attr, cp);
9444 children++;
9445 }
9446
9447 if (ret != 0)
9448 scfdie();
9449
9450 if (children == 0) {
9451 xmlFreeNode(env);
9452 return (NULL);
9453 }
9454
9455 return (env);
9456 }
9457
9458 /*
9459 * As above, but for a method property group.
9460 */
9461 static void
export_method(scf_propertygroup_t * pg,struct entity_elts * eelts)9462 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
9463 {
9464 xmlNodePtr n, env;
9465 char *str;
9466 int err = 0, nonenv, ret;
9467 uint8_t use_profile;
9468 struct pg_elts elts;
9469 xmlNodePtr ctxt = NULL;
9470
9471 n = xmlNewNode(NULL, (xmlChar *)"exec_method");
9472
9473 /* Get the required attributes. */
9474
9475 /* name */
9476 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9477 scfdie();
9478 safe_setprop(n, name_attr, exp_str);
9479
9480 /* type */
9481 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9482 set_attr_from_prop(exp_prop, n, type_attr) != 0)
9483 err = 1;
9484
9485 /* exec */
9486 if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
9487 set_attr_from_prop(exp_prop, n, "exec") != 0)
9488 err = 1;
9489
9490 /* timeout */
9491 if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
9492 prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
9493 prop_get_val(exp_prop, exp_val) == 0) {
9494 uint64_t c;
9495
9496 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
9497 scfdie();
9498
9499 str = uu_msprintf("%llu", c);
9500 if (str == NULL)
9501 uu_die(gettext("Could not create string"));
9502
9503 safe_setprop(n, "timeout_seconds", str);
9504 free(str);
9505 } else
9506 err = 1;
9507
9508 if (err) {
9509 xmlFreeNode(n);
9510
9511 export_pg(pg, eelts, SCE_ALL_VALUES);
9512
9513 return;
9514 }
9515
9516
9517 /*
9518 * If we're going to have a method_context child, we need to know
9519 * before we iterate through the properties. Since method_context's
9520 * are optional, we don't want to complain about any properties
9521 * missing if none of them are there. Thus we can't use the
9522 * convenience functions.
9523 */
9524 nonenv =
9525 scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
9526 SCF_SUCCESS ||
9527 scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
9528 SCF_SUCCESS ||
9529 scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
9530 SCF_SUCCESS ||
9531 scf_pg_get_property(pg, SCF_PROPERTY_SECFLAGS, NULL) ==
9532 SCF_SUCCESS ||
9533 scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
9534 SCF_SUCCESS;
9535
9536 if (nonenv) {
9537 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9538 if (ctxt == NULL)
9539 uu_die(emsg_create_xml);
9540
9541 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
9542 0 &&
9543 set_attr_from_prop_default(exp_prop, ctxt,
9544 "working_directory", ":default") != 0)
9545 err = 1;
9546
9547 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
9548 set_attr_from_prop_default(exp_prop, ctxt, "project",
9549 ":default") != 0)
9550 err = 1;
9551
9552 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
9553 0 &&
9554 set_attr_from_prop_default(exp_prop, ctxt,
9555 "resource_pool", ":default") != 0)
9556 err = 1;
9557
9558 if (pg_get_prop(pg, SCF_PROPERTY_SECFLAGS, exp_prop) == 0 &&
9559 set_attr_from_prop_default(exp_prop, ctxt,
9560 "security_flags", ":default") != 0)
9561 err = 1;
9562
9563 /*
9564 * We only want to complain about profile or credential
9565 * properties if we will use them. To determine that we must
9566 * examine USE_PROFILE.
9567 */
9568 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9569 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9570 prop_get_val(exp_prop, exp_val) == 0) {
9571 if (scf_value_get_boolean(exp_val, &use_profile) !=
9572 SCF_SUCCESS) {
9573 scfdie();
9574 }
9575
9576 if (use_profile) {
9577 xmlNodePtr prof;
9578
9579 prof = xmlNewChild(ctxt, NULL,
9580 (xmlChar *)"method_profile", NULL);
9581 if (prof == NULL)
9582 uu_die(emsg_create_xml);
9583
9584 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
9585 exp_prop) != 0 ||
9586 set_attr_from_prop(exp_prop, prof,
9587 name_attr) != 0)
9588 err = 1;
9589 } else {
9590 xmlNodePtr cred;
9591
9592 cred = xmlNewChild(ctxt, NULL,
9593 (xmlChar *)"method_credential", NULL);
9594 if (cred == NULL)
9595 uu_die(emsg_create_xml);
9596
9597 if (pg_get_prop(pg, SCF_PROPERTY_USER,
9598 exp_prop) != 0 ||
9599 set_attr_from_prop(exp_prop, cred,
9600 "user") != 0) {
9601 err = 1;
9602 }
9603
9604 if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
9605 exp_prop) == 0 &&
9606 set_attr_from_prop_default(exp_prop, cred,
9607 "group", ":default") != 0)
9608 err = 1;
9609
9610 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
9611 exp_prop) == 0 &&
9612 set_attr_from_prop_default(exp_prop, cred,
9613 "supp_groups", ":default") != 0)
9614 err = 1;
9615
9616 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
9617 exp_prop) == 0 &&
9618 set_attr_from_prop_default(exp_prop, cred,
9619 "privileges", ":default") != 0)
9620 err = 1;
9621
9622 if (pg_get_prop(pg,
9623 SCF_PROPERTY_LIMIT_PRIVILEGES,
9624 exp_prop) == 0 &&
9625 set_attr_from_prop_default(exp_prop, cred,
9626 "limit_privileges", ":default") != 0)
9627 err = 1;
9628 }
9629 }
9630 }
9631
9632 if ((env = export_method_environment(pg)) != NULL) {
9633 if (ctxt == NULL) {
9634 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9635 if (ctxt == NULL)
9636 uu_die(emsg_create_xml);
9637 }
9638 (void) xmlAddChild(ctxt, env);
9639 }
9640
9641 if (env != NULL || (nonenv && err == 0))
9642 (void) xmlAddChild(n, ctxt);
9643 else
9644 xmlFreeNode(ctxt);
9645
9646 nonenv = (err == 0);
9647
9648 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9649 scfdie();
9650
9651 (void) memset(&elts, 0, sizeof (elts));
9652
9653 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9654 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9655 scfdie();
9656
9657 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9658 strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
9659 strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
9660 continue;
9661 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9662 xmlNodePtr m;
9663
9664 m = xmlNewNode(NULL, (xmlChar *)"stability");
9665 if (m == NULL)
9666 uu_die(emsg_create_xml);
9667
9668 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9669 elts.stability = m;
9670 continue;
9671 }
9672
9673 xmlFreeNode(m);
9674 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
9675 0 ||
9676 strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
9677 strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
9678 strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9679 if (nonenv)
9680 continue;
9681 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
9682 strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
9683 strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
9684 strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
9685 strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0 ||
9686 strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9687 if (nonenv && !use_profile)
9688 continue;
9689 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9690 if (nonenv && use_profile)
9691 continue;
9692 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
9693 if (env != NULL)
9694 continue;
9695 }
9696
9697 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9698 }
9699 if (ret == -1)
9700 scfdie();
9701
9702 (void) xmlAddChild(n, elts.stability);
9703 (void) xmlAddChildList(n, elts.propvals);
9704 (void) xmlAddChildList(n, elts.properties);
9705
9706 if (eelts->exec_methods == NULL)
9707 eelts->exec_methods = n;
9708 else
9709 (void) xmlAddSibling(eelts->exec_methods, n);
9710 }
9711
9712 static void
export_pg_elts(struct pg_elts * elts,const char * name,const char * type,struct entity_elts * eelts)9713 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
9714 struct entity_elts *eelts)
9715 {
9716 xmlNodePtr pgnode;
9717
9718 pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
9719 if (pgnode == NULL)
9720 uu_die(emsg_create_xml);
9721
9722 safe_setprop(pgnode, name_attr, name);
9723 safe_setprop(pgnode, type_attr, type);
9724
9725 (void) xmlAddChildList(pgnode, elts->propvals);
9726 (void) xmlAddChildList(pgnode, elts->properties);
9727
9728 if (eelts->property_groups == NULL)
9729 eelts->property_groups = pgnode;
9730 else
9731 (void) xmlAddSibling(eelts->property_groups, pgnode);
9732 }
9733
9734 /*
9735 * Process the general property group for a service. This is the one with the
9736 * goodies.
9737 */
9738 static void
export_svc_general(scf_propertygroup_t * pg,struct entity_elts * selts)9739 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
9740 {
9741 struct pg_elts elts;
9742 int ret;
9743
9744 /*
9745 * In case there are properties which don't correspond to child
9746 * entities of the service entity, we'll set up a pg_elts structure to
9747 * put them in.
9748 */
9749 (void) memset(&elts, 0, sizeof (elts));
9750
9751 /* Walk the properties, looking for special ones. */
9752 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9753 scfdie();
9754
9755 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9756 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9757 scfdie();
9758
9759 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
9760 /*
9761 * Unimplemented and obsolete, but we still process it
9762 * for compatibility purposes.
9763 */
9764 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9765 prop_get_val(exp_prop, exp_val) == 0) {
9766 uint8_t b;
9767
9768 if (scf_value_get_boolean(exp_val, &b) !=
9769 SCF_SUCCESS)
9770 scfdie();
9771
9772 if (b) {
9773 selts->single_instance =
9774 xmlNewNode(NULL,
9775 (xmlChar *)"single_instance");
9776 if (selts->single_instance == NULL)
9777 uu_die(emsg_create_xml);
9778 }
9779
9780 continue;
9781 }
9782 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9783 xmlNodePtr rnode, sfnode;
9784
9785 rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9786 if (rnode == NULL)
9787 uu_die(emsg_create_xml);
9788
9789 sfnode = xmlNewChild(rnode, NULL,
9790 (xmlChar *)"service_fmri", NULL);
9791 if (sfnode == NULL)
9792 uu_die(emsg_create_xml);
9793
9794 if (set_attr_from_prop(exp_prop, sfnode,
9795 value_attr) == 0) {
9796 selts->restarter = rnode;
9797 continue;
9798 }
9799
9800 xmlFreeNode(rnode);
9801 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
9802 0) {
9803 xmlNodePtr s;
9804
9805 s = xmlNewNode(NULL, (xmlChar *)"stability");
9806 if (s == NULL)
9807 uu_die(emsg_create_xml);
9808
9809 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9810 selts->stability = s;
9811 continue;
9812 }
9813
9814 xmlFreeNode(s);
9815 }
9816
9817 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9818 }
9819 if (ret == -1)
9820 scfdie();
9821
9822 if (elts.propvals != NULL || elts.properties != NULL)
9823 export_pg_elts(&elts, scf_pg_general, scf_group_framework,
9824 selts);
9825 }
9826
9827 static void
export_method_context(scf_propertygroup_t * pg,struct entity_elts * elts)9828 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
9829 {
9830 xmlNodePtr n, prof, cred, env;
9831 uint8_t use_profile;
9832 int ret, err = 0;
9833
9834 n = xmlNewNode(NULL, (xmlChar *)"method_context");
9835
9836 env = export_method_environment(pg);
9837
9838 /* Need to know whether we'll use a profile or not. */
9839 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9840 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9841 prop_get_val(exp_prop, exp_val) == 0) {
9842 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
9843 scfdie();
9844
9845 if (use_profile)
9846 prof =
9847 xmlNewChild(n, NULL, (xmlChar *)"method_profile",
9848 NULL);
9849 else
9850 cred =
9851 xmlNewChild(n, NULL, (xmlChar *)"method_credential",
9852 NULL);
9853 }
9854
9855 if (env != NULL)
9856 (void) xmlAddChild(n, env);
9857
9858 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9859 scfdie();
9860
9861 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9862 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9863 scfdie();
9864
9865 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
9866 if (set_attr_from_prop(exp_prop, n,
9867 "working_directory") != 0)
9868 err = 1;
9869 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
9870 if (set_attr_from_prop(exp_prop, n, "project") != 0)
9871 err = 1;
9872 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
9873 if (set_attr_from_prop(exp_prop, n,
9874 "resource_pool") != 0)
9875 err = 1;
9876 } else if (strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9877 if (set_attr_from_prop(exp_prop, n,
9878 "security_flags") != 0)
9879 err = 1;
9880 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9881 /* EMPTY */
9882 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
9883 if (use_profile ||
9884 set_attr_from_prop(exp_prop, cred, "user") != 0)
9885 err = 1;
9886 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
9887 if (use_profile ||
9888 set_attr_from_prop(exp_prop, cred, "group") != 0)
9889 err = 1;
9890 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
9891 if (use_profile || set_attr_from_prop(exp_prop, cred,
9892 "supp_groups") != 0)
9893 err = 1;
9894 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
9895 if (use_profile || set_attr_from_prop(exp_prop, cred,
9896 "privileges") != 0)
9897 err = 1;
9898 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
9899 0) {
9900 if (use_profile || set_attr_from_prop(exp_prop, cred,
9901 "limit_privileges") != 0)
9902 err = 1;
9903 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9904 if (!use_profile || set_attr_from_prop(exp_prop,
9905 prof, name_attr) != 0)
9906 err = 1;
9907 } else {
9908 /* Can't have generic properties in method_context's */
9909 err = 1;
9910 }
9911 }
9912 if (ret == -1)
9913 scfdie();
9914
9915 if (err && env == NULL) {
9916 xmlFreeNode(n);
9917 export_pg(pg, elts, SCE_ALL_VALUES);
9918 return;
9919 }
9920
9921 elts->method_context = n;
9922 }
9923
9924 /*
9925 * Given a dependency property group in the tfmri entity (target fmri), return
9926 * a dependent element which represents it.
9927 */
9928 static xmlNodePtr
export_dependent(scf_propertygroup_t * pg,const char * name,const char * tfmri)9929 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
9930 {
9931 uint8_t b;
9932 xmlNodePtr n, sf;
9933 int err = 0, ret;
9934 struct pg_elts pgelts;
9935
9936 /*
9937 * If external isn't set to true then exporting the service will
9938 * export this as a normal dependency, so we should stop to avoid
9939 * duplication.
9940 */
9941 if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
9942 scf_property_get_value(exp_prop, exp_val) != 0 ||
9943 scf_value_get_boolean(exp_val, &b) != 0 || !b) {
9944 if (g_verbose) {
9945 warn(gettext("Dependent \"%s\" cannot be exported "
9946 "properly because the \"%s\" property of the "
9947 "\"%s\" dependency of %s is not set to true.\n"),
9948 name, scf_property_external, name, tfmri);
9949 }
9950
9951 return (NULL);
9952 }
9953
9954 n = xmlNewNode(NULL, (xmlChar *)"dependent");
9955 if (n == NULL)
9956 uu_die(emsg_create_xml);
9957
9958 safe_setprop(n, name_attr, name);
9959
9960 /* Get the required attributes */
9961 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9962 set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9963 err = 1;
9964
9965 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9966 set_attr_from_prop(exp_prop, n, "grouping") != 0)
9967 err = 1;
9968
9969 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9970 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
9971 prop_get_val(exp_prop, exp_val) == 0) {
9972 /* EMPTY */
9973 } else
9974 err = 1;
9975
9976 if (err) {
9977 xmlFreeNode(n);
9978 return (NULL);
9979 }
9980
9981 sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
9982 if (sf == NULL)
9983 uu_die(emsg_create_xml);
9984
9985 safe_setprop(sf, value_attr, tfmri);
9986
9987 /*
9988 * Now add elements for the other properties.
9989 */
9990 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9991 scfdie();
9992
9993 (void) memset(&pgelts, 0, sizeof (pgelts));
9994
9995 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9996 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9997 scfdie();
9998
9999 if (strcmp(exp_str, scf_property_external) == 0 ||
10000 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
10001 strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
10002 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
10003 continue;
10004 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
10005 if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
10006 prop_get_val(exp_prop, exp_val) == 0) {
10007 char type[sizeof ("service") + 1];
10008
10009 if (scf_value_get_astring(exp_val, type,
10010 sizeof (type)) < 0)
10011 scfdie();
10012
10013 if (strcmp(type, "service") == 0)
10014 continue;
10015 }
10016 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
10017 xmlNodePtr s;
10018
10019 s = xmlNewNode(NULL, (xmlChar *)"stability");
10020 if (s == NULL)
10021 uu_die(emsg_create_xml);
10022
10023 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
10024 pgelts.stability = s;
10025 continue;
10026 }
10027
10028 xmlFreeNode(s);
10029 }
10030
10031 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10032 }
10033 if (ret == -1)
10034 scfdie();
10035
10036 (void) xmlAddChild(n, pgelts.stability);
10037 (void) xmlAddChildList(n, pgelts.propvals);
10038 (void) xmlAddChildList(n, pgelts.properties);
10039
10040 return (n);
10041 }
10042
10043 static void
export_dependents(scf_propertygroup_t * pg,struct entity_elts * eelts)10044 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
10045 {
10046 scf_propertygroup_t *opg;
10047 scf_iter_t *iter;
10048 char *type, *fmri;
10049 int ret;
10050 struct pg_elts pgelts;
10051 xmlNodePtr n;
10052 scf_error_t serr;
10053
10054 if ((opg = scf_pg_create(g_hndl)) == NULL ||
10055 (iter = scf_iter_create(g_hndl)) == NULL)
10056 scfdie();
10057
10058 /* Can't use exp_prop_iter due to export_dependent(). */
10059 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
10060 scfdie();
10061
10062 type = safe_malloc(max_scf_pg_type_len + 1);
10063
10064 /* Get an extra byte so we can tell if values are too long. */
10065 fmri = safe_malloc(max_scf_fmri_len + 2);
10066
10067 (void) memset(&pgelts, 0, sizeof (pgelts));
10068
10069 while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
10070 void *entity;
10071 int isservice;
10072 scf_type_t ty;
10073
10074 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
10075 scfdie();
10076
10077 if ((ty != SCF_TYPE_ASTRING &&
10078 prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
10079 prop_get_val(exp_prop, exp_val) != 0) {
10080 export_property(exp_prop, NULL, &pgelts,
10081 SCE_ALL_VALUES);
10082 continue;
10083 }
10084
10085 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10086 scfdie();
10087
10088 if (scf_value_get_astring(exp_val, fmri,
10089 max_scf_fmri_len + 2) < 0)
10090 scfdie();
10091
10092 /* Look for a dependency group in the target fmri. */
10093 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
10094 switch (serr) {
10095 case SCF_ERROR_NONE:
10096 break;
10097
10098 case SCF_ERROR_NO_MEMORY:
10099 uu_die(gettext("Out of memory.\n"));
10100 /* NOTREACHED */
10101
10102 case SCF_ERROR_INVALID_ARGUMENT:
10103 if (g_verbose) {
10104 if (scf_property_to_fmri(exp_prop, fmri,
10105 max_scf_fmri_len + 2) < 0)
10106 scfdie();
10107
10108 warn(gettext("The value of %s is not a valid "
10109 "FMRI.\n"), fmri);
10110 }
10111
10112 export_property(exp_prop, exp_str, &pgelts,
10113 SCE_ALL_VALUES);
10114 continue;
10115
10116 case SCF_ERROR_CONSTRAINT_VIOLATED:
10117 if (g_verbose) {
10118 if (scf_property_to_fmri(exp_prop, fmri,
10119 max_scf_fmri_len + 2) < 0)
10120 scfdie();
10121
10122 warn(gettext("The value of %s does not specify "
10123 "a service or an instance.\n"), fmri);
10124 }
10125
10126 export_property(exp_prop, exp_str, &pgelts,
10127 SCE_ALL_VALUES);
10128 continue;
10129
10130 case SCF_ERROR_NOT_FOUND:
10131 if (g_verbose) {
10132 if (scf_property_to_fmri(exp_prop, fmri,
10133 max_scf_fmri_len + 2) < 0)
10134 scfdie();
10135
10136 warn(gettext("The entity specified by %s does "
10137 "not exist.\n"), fmri);
10138 }
10139
10140 export_property(exp_prop, exp_str, &pgelts,
10141 SCE_ALL_VALUES);
10142 continue;
10143
10144 default:
10145 #ifndef NDEBUG
10146 (void) fprintf(stderr, "%s:%d: %s() failed with "
10147 "unexpected error %d.\n", __FILE__, __LINE__,
10148 "fmri_to_entity", serr);
10149 #endif
10150 abort();
10151 }
10152
10153 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
10154 if (scf_error() != SCF_ERROR_NOT_FOUND)
10155 scfdie();
10156
10157 warn(gettext("Entity %s is missing dependency property "
10158 "group %s.\n"), fmri, exp_str);
10159
10160 export_property(exp_prop, NULL, &pgelts,
10161 SCE_ALL_VALUES);
10162 continue;
10163 }
10164
10165 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
10166 scfdie();
10167
10168 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
10169 if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
10170 scfdie();
10171
10172 warn(gettext("Property group %s is not of "
10173 "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
10174
10175 export_property(exp_prop, NULL, &pgelts,
10176 SCE_ALL_VALUES);
10177 continue;
10178 }
10179
10180 n = export_dependent(opg, exp_str, fmri);
10181 if (n == NULL) {
10182 export_property(exp_prop, exp_str, &pgelts,
10183 SCE_ALL_VALUES);
10184 } else {
10185 if (eelts->dependents == NULL)
10186 eelts->dependents = n;
10187 else
10188 (void) xmlAddSibling(eelts->dependents,
10189 n);
10190 }
10191 }
10192 if (ret == -1)
10193 scfdie();
10194
10195 free(fmri);
10196 free(type);
10197
10198 scf_iter_destroy(iter);
10199 scf_pg_destroy(opg);
10200
10201 if (pgelts.propvals != NULL || pgelts.properties != NULL)
10202 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
10203 eelts);
10204 }
10205
10206 static void
make_node(xmlNodePtr * nodep,const char * name)10207 make_node(xmlNodePtr *nodep, const char *name)
10208 {
10209 if (*nodep == NULL) {
10210 *nodep = xmlNewNode(NULL, (xmlChar *)name);
10211 if (*nodep == NULL)
10212 uu_die(emsg_create_xml);
10213 }
10214 }
10215
10216 static xmlNodePtr
export_tm_loctext(scf_propertygroup_t * pg,const char * parname)10217 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
10218 {
10219 int ret;
10220 xmlNodePtr parent = NULL;
10221 xmlNodePtr loctext = NULL;
10222
10223 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10224 scfdie();
10225
10226 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10227 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
10228 prop_get_val(exp_prop, exp_val) != 0)
10229 continue;
10230
10231 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
10232 scfdie();
10233
10234 make_node(&parent, parname);
10235 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
10236 (xmlChar *)exp_str);
10237 if (loctext == NULL)
10238 uu_die(emsg_create_xml);
10239
10240 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10241 scfdie();
10242
10243 safe_setprop(loctext, "xml:lang", exp_str);
10244 }
10245
10246 if (ret == -1)
10247 scfdie();
10248
10249 return (parent);
10250 }
10251
10252 static xmlNodePtr
export_tm_manpage(scf_propertygroup_t * pg)10253 export_tm_manpage(scf_propertygroup_t *pg)
10254 {
10255 xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
10256 if (manpage == NULL)
10257 uu_die(emsg_create_xml);
10258
10259 if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
10260 set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
10261 pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
10262 set_attr_from_prop(exp_prop, manpage, "section") != 0) {
10263 xmlFreeNode(manpage);
10264 return (NULL);
10265 }
10266
10267 if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
10268 (void) set_attr_from_prop_default(exp_prop,
10269 manpage, "manpath", ":default");
10270
10271 return (manpage);
10272 }
10273
10274 static xmlNodePtr
export_tm_doc_link(scf_propertygroup_t * pg)10275 export_tm_doc_link(scf_propertygroup_t *pg)
10276 {
10277 xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
10278 if (doc_link == NULL)
10279 uu_die(emsg_create_xml);
10280
10281 if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
10282 set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
10283 pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
10284 set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
10285 xmlFreeNode(doc_link);
10286 return (NULL);
10287 }
10288 return (doc_link);
10289 }
10290
10291 /*
10292 * Process template information for a service or instances.
10293 */
10294 static void
export_template(scf_propertygroup_t * pg,struct entity_elts * elts,struct template_elts * telts)10295 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
10296 struct template_elts *telts)
10297 {
10298 size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
10299 size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
10300 xmlNodePtr child = NULL;
10301
10302 if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
10303 scfdie();
10304
10305 if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
10306 telts->common_name = export_tm_loctext(pg, "common_name");
10307 if (telts->common_name == NULL)
10308 export_pg(pg, elts, SCE_ALL_VALUES);
10309 return;
10310 } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
10311 telts->description = export_tm_loctext(pg, "description");
10312 if (telts->description == NULL)
10313 export_pg(pg, elts, SCE_ALL_VALUES);
10314 return;
10315 }
10316
10317 if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
10318 child = export_tm_manpage(pg);
10319 } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
10320 child = export_tm_doc_link(pg);
10321 }
10322
10323 if (child != NULL) {
10324 make_node(&telts->documentation, "documentation");
10325 (void) xmlAddChild(telts->documentation, child);
10326 } else {
10327 export_pg(pg, elts, SCE_ALL_VALUES);
10328 }
10329 }
10330
10331 /*
10332 * Process parameter and paramval elements
10333 */
10334 static void
export_parameter(scf_property_t * prop,const char * name,struct params_elts * elts)10335 export_parameter(scf_property_t *prop, const char *name,
10336 struct params_elts *elts)
10337 {
10338 xmlNodePtr param;
10339 scf_error_t err = 0;
10340 int ret;
10341
10342 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
10343 if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL)
10344 uu_die(emsg_create_xml);
10345
10346 safe_setprop(param, name_attr, name);
10347
10348 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
10349 scfdie();
10350 safe_setprop(param, value_attr, exp_str);
10351
10352 if (elts->paramval == NULL)
10353 elts->paramval = param;
10354 else
10355 (void) xmlAddSibling(elts->paramval, param);
10356
10357 return;
10358 }
10359
10360 err = scf_error();
10361
10362 if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
10363 err != SCF_ERROR_NOT_FOUND)
10364 scfdie();
10365
10366 if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL)
10367 uu_die(emsg_create_xml);
10368
10369 safe_setprop(param, name_attr, name);
10370
10371 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
10372 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
10373 scfdie();
10374
10375 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
10376 1) {
10377 xmlNodePtr vn;
10378
10379 if ((vn = xmlNewChild(param, NULL,
10380 (xmlChar *)"value_node", NULL)) == NULL)
10381 uu_die(emsg_create_xml);
10382
10383 if (scf_value_get_as_string(exp_val, exp_str,
10384 exp_str_sz) < 0)
10385 scfdie();
10386
10387 safe_setprop(vn, value_attr, exp_str);
10388 }
10389 if (ret != 0)
10390 scfdie();
10391 }
10392
10393 if (elts->parameter == NULL)
10394 elts->parameter = param;
10395 else
10396 (void) xmlAddSibling(elts->parameter, param);
10397 }
10398
10399 /*
10400 * Process notification parameters for a service or instance
10401 */
10402 static void
export_notify_params(scf_propertygroup_t * pg,struct entity_elts * elts)10403 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts)
10404 {
10405 xmlNodePtr n, event, *type;
10406 struct params_elts *eelts;
10407 int ret, err, i;
10408 char *s;
10409
10410 n = xmlNewNode(NULL, (xmlChar *)"notification_parameters");
10411 event = xmlNewNode(NULL, (xmlChar *)"event");
10412 if (n == NULL || event == NULL)
10413 uu_die(emsg_create_xml);
10414
10415 /* event value */
10416 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
10417 scfdie();
10418 /* trim SCF_NOTIFY_PG_POSTFIX appended to name on import */
10419 if ((s = strchr(exp_str, ',')) != NULL)
10420 *s = '\0';
10421 safe_setprop(event, value_attr, exp_str);
10422
10423 (void) xmlAddChild(n, event);
10424
10425 if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL ||
10426 (eelts = calloc(URI_SCHEME_NUM,
10427 sizeof (struct params_elts))) == NULL)
10428 uu_die(gettext("Out of memory.\n"));
10429
10430 err = 0;
10431
10432 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10433 scfdie();
10434
10435 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10436 char *t, *p;
10437
10438 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10439 scfdie();
10440
10441 if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) {
10442 /*
10443 * this is not a well formed notification parameters
10444 * element, we should export as regular pg
10445 */
10446 err = 1;
10447 break;
10448 }
10449
10450 if ((i = check_uri_protocol(t)) < 0) {
10451 err = 1;
10452 break;
10453 }
10454
10455 if (type[i] == NULL) {
10456 if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) ==
10457 NULL)
10458 uu_die(emsg_create_xml);
10459
10460 safe_setprop(type[i], name_attr, t);
10461 }
10462 if (strcmp(p, active_attr) == 0) {
10463 if (set_attr_from_prop(exp_prop, type[i],
10464 active_attr) != 0) {
10465 err = 1;
10466 break;
10467 }
10468 continue;
10469 }
10470 /*
10471 * We export the parameter
10472 */
10473 export_parameter(exp_prop, p, &eelts[i]);
10474 }
10475
10476 if (ret == -1)
10477 scfdie();
10478
10479 if (err == 1) {
10480 for (i = 0; i < URI_SCHEME_NUM; ++i)
10481 xmlFree(type[i]);
10482 free(type);
10483
10484 export_pg(pg, elts, SCE_ALL_VALUES);
10485
10486 return;
10487 } else {
10488 for (i = 0; i < URI_SCHEME_NUM; ++i)
10489 if (type[i] != NULL) {
10490 (void) xmlAddChildList(type[i],
10491 eelts[i].paramval);
10492 (void) xmlAddChildList(type[i],
10493 eelts[i].parameter);
10494 (void) xmlAddSibling(event, type[i]);
10495 }
10496 }
10497 free(type);
10498
10499 if (elts->notify_params == NULL)
10500 elts->notify_params = n;
10501 else
10502 (void) xmlAddSibling(elts->notify_params, n);
10503 }
10504
10505 /*
10506 * Process the general property group for an instance.
10507 */
10508 static void
export_inst_general(scf_propertygroup_t * pg,xmlNodePtr inode,struct entity_elts * elts)10509 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
10510 struct entity_elts *elts)
10511 {
10512 uint8_t enabled;
10513 struct pg_elts pgelts;
10514 int ret;
10515
10516 /* enabled */
10517 if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
10518 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
10519 prop_get_val(exp_prop, exp_val) == 0) {
10520 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
10521 scfdie();
10522 } else {
10523 enabled = 0;
10524 }
10525
10526 safe_setprop(inode, enabled_attr, enabled ? true : false);
10527
10528 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10529 scfdie();
10530
10531 (void) memset(&pgelts, 0, sizeof (pgelts));
10532
10533 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10534 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10535 scfdie();
10536
10537 if (strcmp(exp_str, scf_property_enabled) == 0) {
10538 continue;
10539 } else if (strcmp(exp_str, SCF_PROPERTY_COMMENT) == 0) {
10540 continue;
10541 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
10542 xmlNodePtr rnode, sfnode;
10543
10544 rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10545 if (rnode == NULL)
10546 uu_die(emsg_create_xml);
10547
10548 sfnode = xmlNewChild(rnode, NULL,
10549 (xmlChar *)"service_fmri", NULL);
10550 if (sfnode == NULL)
10551 uu_die(emsg_create_xml);
10552
10553 if (set_attr_from_prop(exp_prop, sfnode,
10554 value_attr) == 0) {
10555 elts->restarter = rnode;
10556 continue;
10557 }
10558
10559 xmlFreeNode(rnode);
10560 }
10561
10562 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10563 }
10564 if (ret == -1)
10565 scfdie();
10566
10567 if (pgelts.propvals != NULL || pgelts.properties != NULL)
10568 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10569 elts);
10570 }
10571
10572 /*
10573 * Put an instance element for the given instance into selts.
10574 */
10575 static void
export_instance(scf_instance_t * inst,struct entity_elts * selts,int flags)10576 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10577 {
10578 xmlNodePtr n;
10579 boolean_t isdefault;
10580 struct entity_elts elts;
10581 struct template_elts template_elts;
10582 int ret;
10583
10584 n = xmlNewNode(NULL, (xmlChar *)"instance");
10585 if (n == NULL)
10586 uu_die(emsg_create_xml);
10587
10588 /* name */
10589 if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10590 scfdie();
10591 safe_setprop(n, name_attr, exp_str);
10592 isdefault = strcmp(exp_str, "default") == 0;
10593
10594 /* check existance of general pg (since general/enabled is required) */
10595 if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
10596 if (scf_error() != SCF_ERROR_NOT_FOUND)
10597 scfdie();
10598
10599 if (g_verbose) {
10600 if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10601 scfdie();
10602
10603 warn(gettext("Instance %s has no general property "
10604 "group; it will be marked disabled.\n"), exp_str);
10605 }
10606
10607 safe_setprop(n, enabled_attr, false);
10608 } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
10609 strcmp(exp_str, scf_group_framework) != 0) {
10610 if (g_verbose) {
10611 if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10612 scfdie();
10613
10614 warn(gettext("Property group %s is not of type "
10615 "framework; the instance will be marked "
10616 "disabled.\n"), exp_str);
10617 }
10618
10619 safe_setprop(n, enabled_attr, false);
10620 }
10621
10622 /* property groups */
10623 if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
10624 scfdie();
10625
10626 (void) memset(&elts, 0, sizeof (elts));
10627 (void) memset(&template_elts, 0, sizeof (template_elts));
10628
10629 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10630 uint32_t pgflags;
10631
10632 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10633 scfdie();
10634
10635 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10636 continue;
10637
10638 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10639 scfdie();
10640
10641 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10642 export_dependency(exp_pg, &elts);
10643 continue;
10644 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10645 export_method(exp_pg, &elts);
10646 continue;
10647 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10648 if (scf_pg_get_name(exp_pg, exp_str,
10649 max_scf_name_len + 1) < 0)
10650 scfdie();
10651
10652 if (strcmp(exp_str, scf_pg_general) == 0) {
10653 export_inst_general(exp_pg, n, &elts);
10654 continue;
10655 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10656 0) {
10657 export_method_context(exp_pg, &elts);
10658 continue;
10659 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10660 export_dependents(exp_pg, &elts);
10661 continue;
10662 }
10663 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10664 export_template(exp_pg, &elts, &template_elts);
10665 continue;
10666 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10667 export_notify_params(exp_pg, &elts);
10668 continue;
10669 }
10670
10671 /* Ordinary pg. */
10672 export_pg(exp_pg, &elts, flags);
10673 }
10674 if (ret == -1)
10675 scfdie();
10676
10677 if (template_elts.common_name != NULL) {
10678 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10679 (void) xmlAddChild(elts.template, template_elts.common_name);
10680 (void) xmlAddChild(elts.template, template_elts.description);
10681 (void) xmlAddChild(elts.template, template_elts.documentation);
10682 } else {
10683 xmlFreeNode(template_elts.description);
10684 xmlFreeNode(template_elts.documentation);
10685 }
10686
10687 if (isdefault && elts.restarter == NULL &&
10688 elts.dependencies == NULL && elts.method_context == NULL &&
10689 elts.exec_methods == NULL && elts.notify_params == NULL &&
10690 elts.property_groups == NULL && elts.template == NULL) {
10691 xmlChar *eval;
10692
10693 /* This is a default instance */
10694 eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10695
10696 xmlFreeNode(n);
10697
10698 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10699 if (n == NULL)
10700 uu_die(emsg_create_xml);
10701
10702 safe_setprop(n, enabled_attr, (char *)eval);
10703 xmlFree(eval);
10704
10705 selts->create_default_instance = n;
10706 } else {
10707 /* Assemble the children in order. */
10708 (void) xmlAddChild(n, elts.restarter);
10709 (void) xmlAddChildList(n, elts.dependencies);
10710 (void) xmlAddChildList(n, elts.dependents);
10711 (void) xmlAddChild(n, elts.method_context);
10712 (void) xmlAddChildList(n, elts.exec_methods);
10713 (void) xmlAddChildList(n, elts.notify_params);
10714 (void) xmlAddChildList(n, elts.property_groups);
10715 (void) xmlAddChild(n, elts.template);
10716
10717 if (selts->instances == NULL)
10718 selts->instances = n;
10719 else
10720 (void) xmlAddSibling(selts->instances, n);
10721 }
10722 }
10723
10724 /*
10725 * Return a service element for the given service.
10726 */
10727 static xmlNodePtr
export_service(scf_service_t * svc,int flags)10728 export_service(scf_service_t *svc, int flags)
10729 {
10730 xmlNodePtr snode;
10731 struct entity_elts elts;
10732 struct template_elts template_elts;
10733 int ret;
10734
10735 snode = xmlNewNode(NULL, (xmlChar *)"service");
10736 if (snode == NULL)
10737 uu_die(emsg_create_xml);
10738
10739 /* Get & set name attribute */
10740 if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
10741 scfdie();
10742 safe_setprop(snode, name_attr, exp_str);
10743
10744 safe_setprop(snode, type_attr, "service");
10745 safe_setprop(snode, "version", "0");
10746
10747 /* Acquire child elements. */
10748 if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
10749 scfdie();
10750
10751 (void) memset(&elts, 0, sizeof (elts));
10752 (void) memset(&template_elts, 0, sizeof (template_elts));
10753
10754 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10755 uint32_t pgflags;
10756
10757 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10758 scfdie();
10759
10760 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10761 continue;
10762
10763 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10764 scfdie();
10765
10766 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10767 export_dependency(exp_pg, &elts);
10768 continue;
10769 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10770 export_method(exp_pg, &elts);
10771 continue;
10772 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10773 if (scf_pg_get_name(exp_pg, exp_str,
10774 max_scf_name_len + 1) < 0)
10775 scfdie();
10776
10777 if (strcmp(exp_str, scf_pg_general) == 0) {
10778 export_svc_general(exp_pg, &elts);
10779 continue;
10780 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10781 0) {
10782 export_method_context(exp_pg, &elts);
10783 continue;
10784 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10785 export_dependents(exp_pg, &elts);
10786 continue;
10787 } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10788 continue;
10789 }
10790 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10791 export_template(exp_pg, &elts, &template_elts);
10792 continue;
10793 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10794 export_notify_params(exp_pg, &elts);
10795 continue;
10796 }
10797
10798 export_pg(exp_pg, &elts, flags);
10799 }
10800 if (ret == -1)
10801 scfdie();
10802
10803 if (template_elts.common_name != NULL) {
10804 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10805 (void) xmlAddChild(elts.template, template_elts.common_name);
10806 (void) xmlAddChild(elts.template, template_elts.description);
10807 (void) xmlAddChild(elts.template, template_elts.documentation);
10808 } else {
10809 xmlFreeNode(template_elts.description);
10810 xmlFreeNode(template_elts.documentation);
10811 }
10812
10813 /* Iterate instances */
10814 if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
10815 scfdie();
10816
10817 while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10818 export_instance(exp_inst, &elts, flags);
10819 if (ret == -1)
10820 scfdie();
10821
10822 /* Now add all of the accumulated elements in order. */
10823 (void) xmlAddChild(snode, elts.create_default_instance);
10824 (void) xmlAddChild(snode, elts.single_instance);
10825 (void) xmlAddChild(snode, elts.restarter);
10826 (void) xmlAddChildList(snode, elts.dependencies);
10827 (void) xmlAddChildList(snode, elts.dependents);
10828 (void) xmlAddChild(snode, elts.method_context);
10829 (void) xmlAddChildList(snode, elts.exec_methods);
10830 (void) xmlAddChildList(snode, elts.notify_params);
10831 (void) xmlAddChildList(snode, elts.property_groups);
10832 (void) xmlAddChildList(snode, elts.instances);
10833 (void) xmlAddChild(snode, elts.stability);
10834 (void) xmlAddChild(snode, elts.template);
10835
10836 return (snode);
10837 }
10838
10839 static int
export_callback(void * data,scf_walkinfo_t * wip)10840 export_callback(void *data, scf_walkinfo_t *wip)
10841 {
10842 FILE *f;
10843 xmlDocPtr doc;
10844 xmlNodePtr sb;
10845 int result;
10846 struct export_args *argsp = (struct export_args *)data;
10847
10848 if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
10849 (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10850 (exp_prop = scf_property_create(g_hndl)) == NULL ||
10851 (exp_val = scf_value_create(g_hndl)) == NULL ||
10852 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10853 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10854 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10855 (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10856 scfdie();
10857
10858 exp_str_sz = max_scf_len + 1;
10859 exp_str = safe_malloc(exp_str_sz);
10860
10861 if (argsp->filename != NULL) {
10862 errno = 0;
10863 f = fopen(argsp->filename, "wb");
10864 if (f == NULL) {
10865 if (errno == 0)
10866 uu_die(gettext("Could not open \"%s\": no free "
10867 "stdio streams.\n"), argsp->filename);
10868 else
10869 uu_die(gettext("Could not open \"%s\""),
10870 argsp->filename);
10871 }
10872 } else
10873 f = stdout;
10874
10875 doc = xmlNewDoc((xmlChar *)"1.0");
10876 if (doc == NULL)
10877 uu_die(gettext("Could not create XML document.\n"));
10878
10879 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10880 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10881 uu_die(emsg_create_xml);
10882
10883 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10884 if (sb == NULL)
10885 uu_die(emsg_create_xml);
10886 safe_setprop(sb, type_attr, "manifest");
10887 safe_setprop(sb, name_attr, "export");
10888 (void) xmlAddSibling(doc->children, sb);
10889
10890 (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
10891
10892 result = write_service_bundle(doc, f);
10893
10894 free(exp_str);
10895 scf_iter_destroy(exp_val_iter);
10896 scf_iter_destroy(exp_prop_iter);
10897 scf_iter_destroy(exp_pg_iter);
10898 scf_iter_destroy(exp_inst_iter);
10899 scf_value_destroy(exp_val);
10900 scf_property_destroy(exp_prop);
10901 scf_pg_destroy(exp_pg);
10902 scf_instance_destroy(exp_inst);
10903
10904 xmlFreeDoc(doc);
10905
10906 if (f != stdout)
10907 (void) fclose(f);
10908
10909 return (result);
10910 }
10911
10912 /*
10913 * Get the service named by fmri, build an XML tree which represents it, and
10914 * dump it into filename (or stdout if filename is NULL).
10915 */
10916 int
lscf_service_export(char * fmri,const char * filename,int flags)10917 lscf_service_export(char *fmri, const char *filename, int flags)
10918 {
10919 struct export_args args;
10920 char *fmridup;
10921 const char *scope, *svc, *inst;
10922 size_t cblen = 3 * max_scf_name_len;
10923 char *canonbuf = alloca(cblen);
10924 int ret, err;
10925
10926 lscf_prep_hndl();
10927
10928 bzero(&args, sizeof (args));
10929 args.filename = filename;
10930 args.flags = flags;
10931
10932 /*
10933 * If some poor user has passed an exact instance FMRI, of the sort
10934 * one might cut and paste from svcs(1) or an error message, warn
10935 * and chop off the instance instead of failing.
10936 */
10937 fmridup = alloca(strlen(fmri) + 1);
10938 (void) strcpy(fmridup, fmri);
10939 if (strncmp(fmridup, SCF_FMRI_SVC_PREFIX,
10940 sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 &&
10941 scf_parse_svc_fmri(fmridup, &scope, &svc, &inst, NULL, NULL) == 0 &&
10942 inst != NULL) {
10943 (void) strlcpy(canonbuf, "svc:/", cblen);
10944 if (strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
10945 (void) strlcat(canonbuf, "/", cblen);
10946 (void) strlcat(canonbuf, scope, cblen);
10947 }
10948 (void) strlcat(canonbuf, svc, cblen);
10949 fmri = canonbuf;
10950
10951 warn(gettext("Only services may be exported; ignoring "
10952 "instance portion of argument.\n"));
10953 }
10954
10955 err = 0;
10956 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10957 SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10958 &args, &err, semerr)) != 0) {
10959 if (ret != -1)
10960 semerr(gettext("Failed to walk instances: %s\n"),
10961 scf_strerror(ret));
10962 return (-1);
10963 }
10964
10965 /*
10966 * Error message has already been printed.
10967 */
10968 if (err != 0)
10969 return (-1);
10970
10971 return (0);
10972 }
10973
10974
10975 /*
10976 * Archive
10977 */
10978
10979 static xmlNodePtr
make_archive(int flags)10980 make_archive(int flags)
10981 {
10982 xmlNodePtr sb;
10983 scf_scope_t *scope;
10984 scf_service_t *svc;
10985 scf_iter_t *iter;
10986 int r;
10987
10988 if ((scope = scf_scope_create(g_hndl)) == NULL ||
10989 (svc = scf_service_create(g_hndl)) == NULL ||
10990 (iter = scf_iter_create(g_hndl)) == NULL ||
10991 (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10992 (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10993 (exp_prop = scf_property_create(g_hndl)) == NULL ||
10994 (exp_val = scf_value_create(g_hndl)) == NULL ||
10995 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10996 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10997 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10998 (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10999 scfdie();
11000
11001 exp_str_sz = max_scf_len + 1;
11002 exp_str = safe_malloc(exp_str_sz);
11003
11004 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
11005 if (sb == NULL)
11006 uu_die(emsg_create_xml);
11007 safe_setprop(sb, type_attr, "archive");
11008 safe_setprop(sb, name_attr, "none");
11009
11010 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
11011 scfdie();
11012 if (scf_iter_scope_services(iter, scope) != 0)
11013 scfdie();
11014
11015 for (;;) {
11016 r = scf_iter_next_service(iter, svc);
11017 if (r == 0)
11018 break;
11019 if (r != 1)
11020 scfdie();
11021
11022 if (scf_service_get_name(svc, exp_str,
11023 max_scf_name_len + 1) < 0)
11024 scfdie();
11025
11026 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
11027 continue;
11028
11029 (void) xmlAddChild(sb, export_service(svc, flags));
11030 }
11031
11032 free(exp_str);
11033
11034 scf_iter_destroy(exp_val_iter);
11035 scf_iter_destroy(exp_prop_iter);
11036 scf_iter_destroy(exp_pg_iter);
11037 scf_iter_destroy(exp_inst_iter);
11038 scf_value_destroy(exp_val);
11039 scf_property_destroy(exp_prop);
11040 scf_pg_destroy(exp_pg);
11041 scf_instance_destroy(exp_inst);
11042 scf_iter_destroy(iter);
11043 scf_service_destroy(svc);
11044 scf_scope_destroy(scope);
11045
11046 return (sb);
11047 }
11048
11049 int
lscf_archive(const char * filename,int flags)11050 lscf_archive(const char *filename, int flags)
11051 {
11052 FILE *f;
11053 xmlDocPtr doc;
11054 int result;
11055
11056 lscf_prep_hndl();
11057
11058 if (filename != NULL) {
11059 errno = 0;
11060 f = fopen(filename, "wb");
11061 if (f == NULL) {
11062 if (errno == 0)
11063 uu_die(gettext("Could not open \"%s\": no free "
11064 "stdio streams.\n"), filename);
11065 else
11066 uu_die(gettext("Could not open \"%s\""),
11067 filename);
11068 }
11069 } else
11070 f = stdout;
11071
11072 doc = xmlNewDoc((xmlChar *)"1.0");
11073 if (doc == NULL)
11074 uu_die(gettext("Could not create XML document.\n"));
11075
11076 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11077 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11078 uu_die(emsg_create_xml);
11079
11080 (void) xmlAddSibling(doc->children, make_archive(flags));
11081
11082 result = write_service_bundle(doc, f);
11083
11084 xmlFreeDoc(doc);
11085
11086 if (f != stdout)
11087 (void) fclose(f);
11088
11089 return (result);
11090 }
11091
11092
11093 /*
11094 * "Extract" a profile.
11095 */
11096 int
lscf_profile_extract(const char * filename)11097 lscf_profile_extract(const char *filename)
11098 {
11099 FILE *f;
11100 xmlDocPtr doc;
11101 xmlNodePtr sb, snode, inode;
11102 scf_scope_t *scope;
11103 scf_service_t *svc;
11104 scf_instance_t *inst;
11105 scf_propertygroup_t *pg;
11106 scf_property_t *prop;
11107 scf_value_t *val;
11108 scf_iter_t *siter, *iiter;
11109 int r, s;
11110 char *namebuf;
11111 uint8_t b;
11112 int result;
11113
11114 lscf_prep_hndl();
11115
11116 if (filename != NULL) {
11117 errno = 0;
11118 f = fopen(filename, "wb");
11119 if (f == NULL) {
11120 if (errno == 0)
11121 uu_die(gettext("Could not open \"%s\": no "
11122 "free stdio streams.\n"), filename);
11123 else
11124 uu_die(gettext("Could not open \"%s\""),
11125 filename);
11126 }
11127 } else
11128 f = stdout;
11129
11130 doc = xmlNewDoc((xmlChar *)"1.0");
11131 if (doc == NULL)
11132 uu_die(gettext("Could not create XML document.\n"));
11133
11134 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11135 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11136 uu_die(emsg_create_xml);
11137
11138 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
11139 if (sb == NULL)
11140 uu_die(emsg_create_xml);
11141 safe_setprop(sb, type_attr, "profile");
11142 safe_setprop(sb, name_attr, "extract");
11143 (void) xmlAddSibling(doc->children, sb);
11144
11145 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11146 (svc = scf_service_create(g_hndl)) == NULL ||
11147 (inst = scf_instance_create(g_hndl)) == NULL ||
11148 (pg = scf_pg_create(g_hndl)) == NULL ||
11149 (prop = scf_property_create(g_hndl)) == NULL ||
11150 (val = scf_value_create(g_hndl)) == NULL ||
11151 (siter = scf_iter_create(g_hndl)) == NULL ||
11152 (iiter = scf_iter_create(g_hndl)) == NULL)
11153 scfdie();
11154
11155 if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
11156 scfdie();
11157
11158 if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
11159 scfdie();
11160
11161 namebuf = safe_malloc(max_scf_name_len + 1);
11162
11163 while ((r = scf_iter_next_service(siter, svc)) == 1) {
11164 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
11165 scfdie();
11166
11167 snode = xmlNewNode(NULL, (xmlChar *)"service");
11168 if (snode == NULL)
11169 uu_die(emsg_create_xml);
11170
11171 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
11172 0)
11173 scfdie();
11174
11175 safe_setprop(snode, name_attr, namebuf);
11176
11177 safe_setprop(snode, type_attr, "service");
11178 safe_setprop(snode, "version", "0");
11179
11180 while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
11181 if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
11182 SCF_SUCCESS) {
11183 if (scf_error() != SCF_ERROR_NOT_FOUND)
11184 scfdie();
11185
11186 if (g_verbose) {
11187 ssize_t len;
11188 char *fmri;
11189
11190 len =
11191 scf_instance_to_fmri(inst, NULL, 0);
11192 if (len < 0)
11193 scfdie();
11194
11195 fmri = safe_malloc(len + 1);
11196
11197 if (scf_instance_to_fmri(inst, fmri,
11198 len + 1) < 0)
11199 scfdie();
11200
11201 warn("Instance %s has no \"%s\" "
11202 "property group.\n", fmri,
11203 scf_pg_general);
11204
11205 free(fmri);
11206 }
11207
11208 continue;
11209 }
11210
11211 if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
11212 prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
11213 prop_get_val(prop, val) != 0)
11214 continue;
11215
11216 inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
11217 NULL);
11218 if (inode == NULL)
11219 uu_die(emsg_create_xml);
11220
11221 if (scf_instance_get_name(inst, namebuf,
11222 max_scf_name_len + 1) < 0)
11223 scfdie();
11224
11225 safe_setprop(inode, name_attr, namebuf);
11226
11227 if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
11228 scfdie();
11229
11230 safe_setprop(inode, enabled_attr, b ? true : false);
11231 }
11232 if (s < 0)
11233 scfdie();
11234
11235 if (snode->children != NULL)
11236 (void) xmlAddChild(sb, snode);
11237 else
11238 xmlFreeNode(snode);
11239 }
11240 if (r < 0)
11241 scfdie();
11242
11243 free(namebuf);
11244
11245 result = write_service_bundle(doc, f);
11246
11247 xmlFreeDoc(doc);
11248
11249 if (f != stdout)
11250 (void) fclose(f);
11251
11252 return (result);
11253 }
11254
11255
11256 /*
11257 * Entity manipulation commands
11258 */
11259
11260 /*
11261 * Entity selection. If no entity is selected, then the current scope is in
11262 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected,
11263 * only cur_inst is NULL, and when an instance is selected, none are NULL.
11264 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
11265 * cur_inst will be non-NULL.
11266 */
11267
11268 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
11269 static int
select_inst(const char * name)11270 select_inst(const char *name)
11271 {
11272 scf_instance_t *inst;
11273 scf_error_t err;
11274
11275 assert(cur_svc != NULL);
11276
11277 inst = scf_instance_create(g_hndl);
11278 if (inst == NULL)
11279 scfdie();
11280
11281 if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
11282 cur_inst = inst;
11283 return (0);
11284 }
11285
11286 err = scf_error();
11287 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11288 scfdie();
11289
11290 scf_instance_destroy(inst);
11291 return (1);
11292 }
11293
11294 /* Returns as above. */
11295 static int
select_svc(const char * name)11296 select_svc(const char *name)
11297 {
11298 scf_service_t *svc;
11299 scf_error_t err;
11300
11301 assert(cur_scope != NULL);
11302
11303 svc = scf_service_create(g_hndl);
11304 if (svc == NULL)
11305 scfdie();
11306
11307 if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
11308 cur_svc = svc;
11309 return (0);
11310 }
11311
11312 err = scf_error();
11313 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11314 scfdie();
11315
11316 scf_service_destroy(svc);
11317 return (1);
11318 }
11319
11320 /* ARGSUSED */
11321 static int
select_callback(void * unused,scf_walkinfo_t * wip)11322 select_callback(void *unused, scf_walkinfo_t *wip)
11323 {
11324 scf_instance_t *inst;
11325 scf_service_t *svc;
11326 scf_scope_t *scope;
11327
11328 if (wip->inst != NULL) {
11329 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11330 (svc = scf_service_create(g_hndl)) == NULL ||
11331 (inst = scf_instance_create(g_hndl)) == NULL)
11332 scfdie();
11333
11334 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11335 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11336 scfdie();
11337 } else {
11338 assert(wip->svc != NULL);
11339
11340 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11341 (svc = scf_service_create(g_hndl)) == NULL)
11342 scfdie();
11343
11344 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11345 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11346 scfdie();
11347
11348 inst = NULL;
11349 }
11350
11351 /* Clear out the current selection */
11352 assert(cur_scope != NULL);
11353 scf_scope_destroy(cur_scope);
11354 scf_service_destroy(cur_svc);
11355 scf_instance_destroy(cur_inst);
11356
11357 cur_scope = scope;
11358 cur_svc = svc;
11359 cur_inst = inst;
11360
11361 return (0);
11362 }
11363
11364 static int
validate_callback(void * fmri_p,scf_walkinfo_t * wip)11365 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
11366 {
11367 char **fmri = fmri_p;
11368
11369 *fmri = strdup(wip->fmri);
11370 if (*fmri == NULL)
11371 uu_die(gettext("Out of memory.\n"));
11372
11373 return (0);
11374 }
11375
11376 /*
11377 * validate [fmri]
11378 * Perform the validation of an FMRI instance.
11379 */
11380 void
lscf_validate_fmri(const char * fmri)11381 lscf_validate_fmri(const char *fmri)
11382 {
11383 int ret = 0;
11384 size_t inst_sz;
11385 char *inst_fmri = NULL;
11386 scf_tmpl_errors_t *errs = NULL;
11387 char *snapbuf = NULL;
11388
11389 lscf_prep_hndl();
11390
11391 if (fmri == NULL) {
11392 inst_sz = max_scf_fmri_len + 1;
11393 inst_fmri = safe_malloc(inst_sz);
11394
11395 if (cur_snap != NULL) {
11396 snapbuf = safe_malloc(max_scf_name_len + 1);
11397 if (scf_snapshot_get_name(cur_snap, snapbuf,
11398 max_scf_name_len + 1) < 0)
11399 scfdie();
11400 }
11401 if (cur_inst == NULL) {
11402 semerr(gettext("No instance selected\n"));
11403 goto cleanup;
11404 } else if (scf_instance_to_fmri(cur_inst, inst_fmri,
11405 inst_sz) >= inst_sz) {
11406 /* sanity check. Should never get here */
11407 uu_die(gettext("Unexpected error! file %s, line %d\n"),
11408 __FILE__, __LINE__);
11409 }
11410 } else {
11411 scf_error_t scf_err;
11412 int err = 0;
11413
11414 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
11415 validate_callback, &inst_fmri, &err, semerr)) != 0) {
11416 uu_warn("Failed to walk instances: %s\n",
11417 scf_strerror(scf_err));
11418 goto cleanup;
11419 }
11420 if (err != 0) {
11421 /* error message displayed by scf_walk_fmri */
11422 goto cleanup;
11423 }
11424 }
11425
11426 ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
11427 SCF_TMPL_VALIDATE_FLAG_CURRENT);
11428 if (ret == -1) {
11429 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
11430 warn(gettext("Template data for %s is invalid. "
11431 "Consider reverting to a previous snapshot or "
11432 "restoring original configuration.\n"), inst_fmri);
11433 } else {
11434 uu_warn("%s: %s\n",
11435 gettext("Error validating the instance"),
11436 scf_strerror(scf_error()));
11437 }
11438 } else if (ret == 1 && errs != NULL) {
11439 scf_tmpl_error_t *err = NULL;
11440 char *msg;
11441 size_t len = 256; /* initial error buffer size */
11442 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
11443 SCF_TMPL_STRERROR_HUMAN : 0;
11444
11445 msg = safe_malloc(len);
11446
11447 while ((err = scf_tmpl_next_error(errs)) != NULL) {
11448 int ret;
11449
11450 if ((ret = scf_tmpl_strerror(err, msg, len,
11451 flag)) >= len) {
11452 len = ret + 1;
11453 msg = realloc(msg, len);
11454 if (msg == NULL)
11455 uu_die(gettext(
11456 "Out of memory.\n"));
11457 (void) scf_tmpl_strerror(err, msg, len,
11458 flag);
11459 }
11460 (void) fprintf(stderr, "%s\n", msg);
11461 }
11462 if (msg != NULL)
11463 free(msg);
11464 }
11465 if (errs != NULL)
11466 scf_tmpl_errors_destroy(errs);
11467
11468 cleanup:
11469 free(inst_fmri);
11470 free(snapbuf);
11471 }
11472
11473 static void
lscf_validate_file(const char * filename)11474 lscf_validate_file(const char *filename)
11475 {
11476 tmpl_errors_t *errs;
11477
11478 bundle_t *b = internal_bundle_new();
11479 if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
11480 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
11481 tmpl_errors_print(stderr, errs, "");
11482 semerr(gettext("Validation failed.\n"));
11483 }
11484 tmpl_errors_destroy(errs);
11485 }
11486 (void) internal_bundle_free(b);
11487 }
11488
11489 /*
11490 * validate [fmri|file]
11491 */
11492 void
lscf_validate(const char * arg)11493 lscf_validate(const char *arg)
11494 {
11495 const char *str;
11496
11497 if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
11498 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
11499 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
11500 lscf_validate_file(str);
11501 } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
11502 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
11503 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
11504 lscf_validate_fmri(str);
11505 } else if (access(arg, R_OK | F_OK) == 0) {
11506 lscf_validate_file(arg);
11507 } else {
11508 lscf_validate_fmri(arg);
11509 }
11510 }
11511
11512 void
lscf_select(const char * fmri)11513 lscf_select(const char *fmri)
11514 {
11515 int ret, err;
11516
11517 lscf_prep_hndl();
11518
11519 if (cur_snap != NULL) {
11520 struct snaplevel *elt;
11521 char *buf;
11522
11523 /* Error unless name is that of the next level. */
11524 elt = uu_list_next(cur_levels, cur_elt);
11525 if (elt == NULL) {
11526 semerr(gettext("No children.\n"));
11527 return;
11528 }
11529
11530 buf = safe_malloc(max_scf_name_len + 1);
11531
11532 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11533 max_scf_name_len + 1) < 0)
11534 scfdie();
11535
11536 if (strcmp(buf, fmri) != 0) {
11537 semerr(gettext("No such child.\n"));
11538 free(buf);
11539 return;
11540 }
11541
11542 free(buf);
11543
11544 cur_elt = elt;
11545 cur_level = elt->sl;
11546 return;
11547 }
11548
11549 /*
11550 * Special case for 'svc:', which takes the user to the scope level.
11551 */
11552 if (strcmp(fmri, "svc:") == 0) {
11553 scf_instance_destroy(cur_inst);
11554 scf_service_destroy(cur_svc);
11555 cur_inst = NULL;
11556 cur_svc = NULL;
11557 return;
11558 }
11559
11560 /*
11561 * Special case for ':properties'. This appears as part of 'list' but
11562 * can't be selected. Give a more helpful error message in this case.
11563 */
11564 if (strcmp(fmri, ":properties") == 0) {
11565 semerr(gettext(":properties is not an entity. Try 'listprop' "
11566 "to list properties.\n"));
11567 return;
11568 }
11569
11570 /*
11571 * First try the argument as relative to the current selection.
11572 */
11573 if (cur_inst != NULL) {
11574 /* EMPTY */;
11575 } else if (cur_svc != NULL) {
11576 if (select_inst(fmri) != 1)
11577 return;
11578 } else {
11579 if (select_svc(fmri) != 1)
11580 return;
11581 }
11582
11583 err = 0;
11584 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11585 select_callback, NULL, &err, semerr)) != 0) {
11586 semerr(gettext("Failed to walk instances: %s\n"),
11587 scf_strerror(ret));
11588 }
11589 }
11590
11591 void
lscf_unselect(void)11592 lscf_unselect(void)
11593 {
11594 lscf_prep_hndl();
11595
11596 if (cur_snap != NULL) {
11597 struct snaplevel *elt;
11598
11599 elt = uu_list_prev(cur_levels, cur_elt);
11600 if (elt == NULL) {
11601 semerr(gettext("No parent levels.\n"));
11602 } else {
11603 cur_elt = elt;
11604 cur_level = elt->sl;
11605 }
11606 } else if (cur_inst != NULL) {
11607 scf_instance_destroy(cur_inst);
11608 cur_inst = NULL;
11609 } else if (cur_svc != NULL) {
11610 scf_service_destroy(cur_svc);
11611 cur_svc = NULL;
11612 } else {
11613 semerr(gettext("Cannot unselect at scope level.\n"));
11614 }
11615 }
11616
11617 /*
11618 * Return the FMRI of the current selection, for the prompt.
11619 */
11620 void
lscf_get_selection_str(char * buf,size_t bufsz)11621 lscf_get_selection_str(char *buf, size_t bufsz)
11622 {
11623 char *cp;
11624 ssize_t fmrilen, szret;
11625 boolean_t deleted = B_FALSE;
11626
11627 if (g_hndl == NULL) {
11628 (void) strlcpy(buf, "svc:", bufsz);
11629 return;
11630 }
11631
11632 if (cur_level != NULL) {
11633 assert(cur_snap != NULL);
11634
11635 /* [ snapshot ] FMRI [: instance ] */
11636 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11637 + 2 + max_scf_name_len + 1 + 1);
11638
11639 buf[0] = '[';
11640
11641 szret = scf_snapshot_get_name(cur_snap, buf + 1,
11642 max_scf_name_len + 1);
11643 if (szret < 0) {
11644 if (scf_error() != SCF_ERROR_DELETED)
11645 scfdie();
11646
11647 goto snap_deleted;
11648 }
11649
11650 (void) strcat(buf, "]svc:/");
11651
11652 cp = strchr(buf, '\0');
11653
11654 szret = scf_snaplevel_get_service_name(cur_level, cp,
11655 max_scf_name_len + 1);
11656 if (szret < 0) {
11657 if (scf_error() != SCF_ERROR_DELETED)
11658 scfdie();
11659
11660 goto snap_deleted;
11661 }
11662
11663 cp = strchr(cp, '\0');
11664
11665 if (snaplevel_is_instance(cur_level)) {
11666 *cp++ = ':';
11667
11668 if (scf_snaplevel_get_instance_name(cur_level, cp,
11669 max_scf_name_len + 1) < 0) {
11670 if (scf_error() != SCF_ERROR_DELETED)
11671 scfdie();
11672
11673 goto snap_deleted;
11674 }
11675 } else {
11676 *cp++ = '[';
11677 *cp++ = ':';
11678
11679 if (scf_instance_get_name(cur_inst, cp,
11680 max_scf_name_len + 1) < 0) {
11681 if (scf_error() != SCF_ERROR_DELETED)
11682 scfdie();
11683
11684 goto snap_deleted;
11685 }
11686
11687 (void) strcat(buf, "]");
11688 }
11689
11690 return;
11691
11692 snap_deleted:
11693 deleted = B_TRUE;
11694 free(buf);
11695 unselect_cursnap();
11696 }
11697
11698 assert(cur_snap == NULL);
11699
11700 if (cur_inst != NULL) {
11701 assert(cur_svc != NULL);
11702 assert(cur_scope != NULL);
11703
11704 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11705 if (fmrilen >= 0) {
11706 assert(fmrilen < bufsz);
11707 if (deleted)
11708 warn(emsg_deleted);
11709 return;
11710 }
11711
11712 if (scf_error() != SCF_ERROR_DELETED)
11713 scfdie();
11714
11715 deleted = B_TRUE;
11716
11717 scf_instance_destroy(cur_inst);
11718 cur_inst = NULL;
11719 }
11720
11721 if (cur_svc != NULL) {
11722 assert(cur_scope != NULL);
11723
11724 szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11725 if (szret >= 0) {
11726 assert(szret < bufsz);
11727 if (deleted)
11728 warn(emsg_deleted);
11729 return;
11730 }
11731
11732 if (scf_error() != SCF_ERROR_DELETED)
11733 scfdie();
11734
11735 deleted = B_TRUE;
11736 scf_service_destroy(cur_svc);
11737 cur_svc = NULL;
11738 }
11739
11740 assert(cur_scope != NULL);
11741 fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11742
11743 if (fmrilen < 0)
11744 scfdie();
11745
11746 assert(fmrilen < bufsz);
11747 if (deleted)
11748 warn(emsg_deleted);
11749 }
11750
11751 /*
11752 * Entity listing. Entities and colon namespaces (e.g., :properties and
11753 * :statistics) are listed for the current selection.
11754 */
11755 void
lscf_list(const char * pattern)11756 lscf_list(const char *pattern)
11757 {
11758 scf_iter_t *iter;
11759 char *buf;
11760 int ret;
11761
11762 lscf_prep_hndl();
11763
11764 if (cur_level != NULL) {
11765 struct snaplevel *elt;
11766
11767 (void) fputs(COLON_NAMESPACES, stdout);
11768
11769 elt = uu_list_next(cur_levels, cur_elt);
11770 if (elt == NULL)
11771 return;
11772
11773 /*
11774 * For now, we know that the next level is an instance. But
11775 * if we ever have multiple scopes, this could be complicated.
11776 */
11777 buf = safe_malloc(max_scf_name_len + 1);
11778 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11779 max_scf_name_len + 1) >= 0) {
11780 (void) puts(buf);
11781 } else {
11782 if (scf_error() != SCF_ERROR_DELETED)
11783 scfdie();
11784 }
11785
11786 free(buf);
11787
11788 return;
11789 }
11790
11791 if (cur_inst != NULL) {
11792 (void) fputs(COLON_NAMESPACES, stdout);
11793 return;
11794 }
11795
11796 iter = scf_iter_create(g_hndl);
11797 if (iter == NULL)
11798 scfdie();
11799
11800 buf = safe_malloc(max_scf_name_len + 1);
11801
11802 if (cur_svc != NULL) {
11803 /* List the instances in this service. */
11804 scf_instance_t *inst;
11805
11806 inst = scf_instance_create(g_hndl);
11807 if (inst == NULL)
11808 scfdie();
11809
11810 if (scf_iter_service_instances(iter, cur_svc) == 0) {
11811 safe_printf(COLON_NAMESPACES);
11812
11813 for (;;) {
11814 ret = scf_iter_next_instance(iter, inst);
11815 if (ret == 0)
11816 break;
11817 if (ret != 1) {
11818 if (scf_error() != SCF_ERROR_DELETED)
11819 scfdie();
11820
11821 break;
11822 }
11823
11824 if (scf_instance_get_name(inst, buf,
11825 max_scf_name_len + 1) >= 0) {
11826 if (pattern == NULL ||
11827 fnmatch(pattern, buf, 0) == 0)
11828 (void) puts(buf);
11829 } else {
11830 if (scf_error() != SCF_ERROR_DELETED)
11831 scfdie();
11832 }
11833 }
11834 } else {
11835 if (scf_error() != SCF_ERROR_DELETED)
11836 scfdie();
11837 }
11838
11839 scf_instance_destroy(inst);
11840 } else {
11841 /* List the services in this scope. */
11842 scf_service_t *svc;
11843
11844 assert(cur_scope != NULL);
11845
11846 svc = scf_service_create(g_hndl);
11847 if (svc == NULL)
11848 scfdie();
11849
11850 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11851 scfdie();
11852
11853 for (;;) {
11854 ret = scf_iter_next_service(iter, svc);
11855 if (ret == 0)
11856 break;
11857 if (ret != 1)
11858 scfdie();
11859
11860 if (scf_service_get_name(svc, buf,
11861 max_scf_name_len + 1) >= 0) {
11862 if (pattern == NULL ||
11863 fnmatch(pattern, buf, 0) == 0)
11864 safe_printf("%s\n", buf);
11865 } else {
11866 if (scf_error() != SCF_ERROR_DELETED)
11867 scfdie();
11868 }
11869 }
11870
11871 scf_service_destroy(svc);
11872 }
11873
11874 free(buf);
11875 scf_iter_destroy(iter);
11876 }
11877
11878 /*
11879 * Entity addition. Creates an empty entity in the current selection.
11880 */
11881 void
lscf_add(const char * name)11882 lscf_add(const char *name)
11883 {
11884 lscf_prep_hndl();
11885
11886 if (cur_snap != NULL) {
11887 semerr(emsg_cant_modify_snapshots);
11888 } else if (cur_inst != NULL) {
11889 semerr(gettext("Cannot add entities to an instance.\n"));
11890 } else if (cur_svc != NULL) {
11891
11892 if (scf_service_add_instance(cur_svc, name, NULL) !=
11893 SCF_SUCCESS) {
11894 switch (scf_error()) {
11895 case SCF_ERROR_INVALID_ARGUMENT:
11896 semerr(gettext("Invalid name.\n"));
11897 break;
11898
11899 case SCF_ERROR_EXISTS:
11900 semerr(gettext("Instance already exists.\n"));
11901 break;
11902
11903 case SCF_ERROR_PERMISSION_DENIED:
11904 semerr(emsg_permission_denied);
11905 break;
11906
11907 default:
11908 scfdie();
11909 }
11910 }
11911 } else {
11912 assert(cur_scope != NULL);
11913
11914 if (scf_scope_add_service(cur_scope, name, NULL) !=
11915 SCF_SUCCESS) {
11916 switch (scf_error()) {
11917 case SCF_ERROR_INVALID_ARGUMENT:
11918 semerr(gettext("Invalid name.\n"));
11919 break;
11920
11921 case SCF_ERROR_EXISTS:
11922 semerr(gettext("Service already exists.\n"));
11923 break;
11924
11925 case SCF_ERROR_PERMISSION_DENIED:
11926 semerr(emsg_permission_denied);
11927 break;
11928
11929 case SCF_ERROR_BACKEND_READONLY:
11930 semerr(emsg_read_only);
11931 break;
11932
11933 default:
11934 scfdie();
11935 }
11936 }
11937 }
11938 }
11939
11940 /* return 1 if the entity has no persistent pgs, else return 0 */
11941 static int
entity_has_no_pgs(void * ent,int isservice)11942 entity_has_no_pgs(void *ent, int isservice)
11943 {
11944 scf_iter_t *iter = NULL;
11945 scf_propertygroup_t *pg = NULL;
11946 uint32_t flags;
11947 int err;
11948 int ret = 1;
11949
11950 if ((iter = scf_iter_create(g_hndl)) == NULL ||
11951 (pg = scf_pg_create(g_hndl)) == NULL)
11952 scfdie();
11953
11954 if (isservice) {
11955 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11956 scfdie();
11957 } else {
11958 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11959 scfdie();
11960 }
11961
11962 while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11963 if (scf_pg_get_flags(pg, &flags) != 0)
11964 scfdie();
11965
11966 /* skip nonpersistent pgs */
11967 if (flags & SCF_PG_FLAG_NONPERSISTENT)
11968 continue;
11969
11970 ret = 0;
11971 break;
11972 }
11973
11974 if (err == -1)
11975 scfdie();
11976
11977 scf_pg_destroy(pg);
11978 scf_iter_destroy(iter);
11979
11980 return (ret);
11981 }
11982
11983 /* return 1 if the service has no instances, else return 0 */
11984 static int
svc_has_no_insts(scf_service_t * svc)11985 svc_has_no_insts(scf_service_t *svc)
11986 {
11987 scf_instance_t *inst;
11988 scf_iter_t *iter;
11989 int r;
11990 int ret = 1;
11991
11992 if ((inst = scf_instance_create(g_hndl)) == NULL ||
11993 (iter = scf_iter_create(g_hndl)) == NULL)
11994 scfdie();
11995
11996 if (scf_iter_service_instances(iter, svc) != 0)
11997 scfdie();
11998
11999 r = scf_iter_next_instance(iter, inst);
12000 if (r == 1) {
12001 ret = 0;
12002 } else if (r == 0) {
12003 ret = 1;
12004 } else if (r == -1) {
12005 scfdie();
12006 } else {
12007 bad_error("scf_iter_next_instance", r);
12008 }
12009
12010 scf_iter_destroy(iter);
12011 scf_instance_destroy(inst);
12012
12013 return (ret);
12014 }
12015
12016 /*
12017 * Entity deletion.
12018 */
12019
12020 /*
12021 * Delete the property group <fmri>/:properties/<name>. Returns
12022 * SCF_ERROR_NONE on success (or if the entity is not found),
12023 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
12024 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
12025 * denied.
12026 */
12027 static scf_error_t
delete_dependency_pg(const char * fmri,const char * name)12028 delete_dependency_pg(const char *fmri, const char *name)
12029 {
12030 void *entity = NULL;
12031 int isservice;
12032 scf_propertygroup_t *pg = NULL;
12033 scf_error_t result;
12034 char *pgty;
12035 scf_service_t *svc = NULL;
12036 scf_instance_t *inst = NULL;
12037 scf_iter_t *iter = NULL;
12038 char *name_buf = NULL;
12039
12040 result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
12041 switch (result) {
12042 case SCF_ERROR_NONE:
12043 break;
12044
12045 case SCF_ERROR_NO_MEMORY:
12046 uu_die(gettext("Out of memory.\n"));
12047 /* NOTREACHED */
12048
12049 case SCF_ERROR_INVALID_ARGUMENT:
12050 case SCF_ERROR_CONSTRAINT_VIOLATED:
12051 return (SCF_ERROR_INVALID_ARGUMENT);
12052
12053 case SCF_ERROR_NOT_FOUND:
12054 result = SCF_ERROR_NONE;
12055 goto out;
12056
12057 default:
12058 bad_error("fmri_to_entity", result);
12059 }
12060
12061 pg = scf_pg_create(g_hndl);
12062 if (pg == NULL)
12063 scfdie();
12064
12065 if (entity_get_pg(entity, isservice, name, pg) != 0) {
12066 if (scf_error() != SCF_ERROR_NOT_FOUND)
12067 scfdie();
12068
12069 result = SCF_ERROR_NONE;
12070 goto out;
12071 }
12072
12073 pgty = safe_malloc(max_scf_pg_type_len + 1);
12074
12075 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12076 scfdie();
12077
12078 if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
12079 result = SCF_ERROR_TYPE_MISMATCH;
12080 free(pgty);
12081 goto out;
12082 }
12083
12084 free(pgty);
12085
12086 if (scf_pg_delete(pg) != 0) {
12087 result = scf_error();
12088 if (result != SCF_ERROR_PERMISSION_DENIED)
12089 scfdie();
12090 goto out;
12091 }
12092
12093 /*
12094 * We have to handle the case where we've just deleted the last
12095 * property group of a "dummy" entity (instance or service).
12096 * A "dummy" entity is an entity only present to hold an
12097 * external dependency.
12098 * So, in the case we deleted the last property group then we
12099 * can also delete the entity. If the entity is an instance then
12100 * we must verify if this was the last instance for the service
12101 * and if it is, we can also delete the service if it doesn't
12102 * have any property group either.
12103 */
12104
12105 result = SCF_ERROR_NONE;
12106
12107 if (isservice) {
12108 svc = (scf_service_t *)entity;
12109
12110 if ((inst = scf_instance_create(g_hndl)) == NULL ||
12111 (iter = scf_iter_create(g_hndl)) == NULL)
12112 scfdie();
12113
12114 name_buf = safe_malloc(max_scf_name_len + 1);
12115 } else {
12116 inst = (scf_instance_t *)entity;
12117 }
12118
12119 /*
12120 * If the entity is an instance and we've just deleted its last
12121 * property group then we should delete it.
12122 */
12123 if (!isservice && entity_has_no_pgs(entity, isservice)) {
12124 /* find the service before deleting the inst. - needed later */
12125 if ((svc = scf_service_create(g_hndl)) == NULL)
12126 scfdie();
12127
12128 if (scf_instance_get_parent(inst, svc) != 0)
12129 scfdie();
12130
12131 /* delete the instance */
12132 if (scf_instance_delete(inst) != 0) {
12133 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12134 scfdie();
12135
12136 result = SCF_ERROR_PERMISSION_DENIED;
12137 goto out;
12138 }
12139 /* no need to refresh the instance */
12140 inst = NULL;
12141 }
12142
12143 /*
12144 * If the service has no more instances and pgs or we just deleted the
12145 * last instance and the service doesn't have anymore propery groups
12146 * then the service should be deleted.
12147 */
12148 if (svc != NULL &&
12149 svc_has_no_insts(svc) &&
12150 entity_has_no_pgs((void *)svc, 1)) {
12151 if (scf_service_delete(svc) == 0) {
12152 if (isservice) {
12153 /* no need to refresh the service */
12154 svc = NULL;
12155 }
12156
12157 goto out;
12158 }
12159
12160 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12161 scfdie();
12162
12163 result = SCF_ERROR_PERMISSION_DENIED;
12164 }
12165
12166 /* if the entity has not been deleted, refresh it */
12167 if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
12168 (void) refresh_entity(isservice, entity, fmri, inst, iter,
12169 name_buf);
12170 }
12171
12172 out:
12173 if (isservice && (inst != NULL && iter != NULL)) {
12174 free(name_buf);
12175 scf_iter_destroy(iter);
12176 scf_instance_destroy(inst);
12177 }
12178
12179 if (!isservice && svc != NULL) {
12180 scf_service_destroy(svc);
12181 }
12182
12183 scf_pg_destroy(pg);
12184 if (entity != NULL)
12185 entity_destroy(entity, isservice);
12186
12187 return (result);
12188 }
12189
12190 static int
delete_dependents(scf_propertygroup_t * pg)12191 delete_dependents(scf_propertygroup_t *pg)
12192 {
12193 char *pgty, *name, *fmri;
12194 scf_property_t *prop;
12195 scf_value_t *val;
12196 scf_iter_t *iter;
12197 int r;
12198 scf_error_t err;
12199
12200 /* Verify that the pg has the correct type. */
12201 pgty = safe_malloc(max_scf_pg_type_len + 1);
12202 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12203 scfdie();
12204
12205 if (strcmp(pgty, scf_group_framework) != 0) {
12206 if (g_verbose) {
12207 fmri = safe_malloc(max_scf_fmri_len + 1);
12208 if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
12209 scfdie();
12210
12211 warn(gettext("Property group %s is not of expected "
12212 "type %s.\n"), fmri, scf_group_framework);
12213
12214 free(fmri);
12215 }
12216
12217 free(pgty);
12218 return (-1);
12219 }
12220
12221 free(pgty);
12222
12223 /* map delete_dependency_pg onto the properties. */
12224 if ((prop = scf_property_create(g_hndl)) == NULL ||
12225 (val = scf_value_create(g_hndl)) == NULL ||
12226 (iter = scf_iter_create(g_hndl)) == NULL)
12227 scfdie();
12228
12229 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
12230 scfdie();
12231
12232 name = safe_malloc(max_scf_name_len + 1);
12233 fmri = safe_malloc(max_scf_fmri_len + 2);
12234
12235 while ((r = scf_iter_next_property(iter, prop)) == 1) {
12236 scf_type_t ty;
12237
12238 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
12239 scfdie();
12240
12241 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
12242 scfdie();
12243
12244 if ((ty != SCF_TYPE_ASTRING &&
12245 prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
12246 prop_get_val(prop, val) != 0)
12247 continue;
12248
12249 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
12250 scfdie();
12251
12252 err = delete_dependency_pg(fmri, name);
12253 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
12254 if (scf_property_to_fmri(prop, fmri,
12255 max_scf_fmri_len + 2) < 0)
12256 scfdie();
12257
12258 warn(gettext("Value of %s is not a valid FMRI.\n"),
12259 fmri);
12260 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
12261 warn(gettext("Property group \"%s\" of entity \"%s\" "
12262 "does not have dependency type.\n"), name, fmri);
12263 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
12264 warn(gettext("Could not delete property group \"%s\" "
12265 "of entity \"%s\" (permission denied).\n"), name,
12266 fmri);
12267 }
12268 }
12269 if (r == -1)
12270 scfdie();
12271
12272 scf_value_destroy(val);
12273 scf_property_destroy(prop);
12274
12275 return (0);
12276 }
12277
12278 /*
12279 * Returns 1 if the instance may be running, and 0 otherwise.
12280 */
12281 static int
inst_is_running(scf_instance_t * inst)12282 inst_is_running(scf_instance_t *inst)
12283 {
12284 scf_propertygroup_t *pg;
12285 scf_property_t *prop;
12286 scf_value_t *val;
12287 char buf[MAX_SCF_STATE_STRING_SZ];
12288 int ret = 0;
12289 ssize_t szret;
12290
12291 if ((pg = scf_pg_create(g_hndl)) == NULL ||
12292 (prop = scf_property_create(g_hndl)) == NULL ||
12293 (val = scf_value_create(g_hndl)) == NULL)
12294 scfdie();
12295
12296 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
12297 if (scf_error() != SCF_ERROR_NOT_FOUND)
12298 scfdie();
12299 goto out;
12300 }
12301
12302 if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
12303 prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
12304 prop_get_val(prop, val) != 0)
12305 goto out;
12306
12307 szret = scf_value_get_astring(val, buf, sizeof (buf));
12308 assert(szret >= 0);
12309
12310 ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
12311 strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
12312
12313 out:
12314 scf_value_destroy(val);
12315 scf_property_destroy(prop);
12316 scf_pg_destroy(pg);
12317 return (ret);
12318 }
12319
12320 static uint8_t
pg_is_external_dependency(scf_propertygroup_t * pg)12321 pg_is_external_dependency(scf_propertygroup_t *pg)
12322 {
12323 char *type;
12324 scf_value_t *val;
12325 scf_property_t *prop;
12326 uint8_t b = B_FALSE;
12327
12328 type = safe_malloc(max_scf_pg_type_len + 1);
12329
12330 if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
12331 scfdie();
12332
12333 if ((prop = scf_property_create(g_hndl)) == NULL ||
12334 (val = scf_value_create(g_hndl)) == NULL)
12335 scfdie();
12336
12337 if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
12338 if (pg_get_prop(pg, scf_property_external, prop) == 0) {
12339 if (scf_property_get_value(prop, val) != 0)
12340 scfdie();
12341 if (scf_value_get_boolean(val, &b) != 0)
12342 scfdie();
12343 }
12344 }
12345
12346 free(type);
12347 (void) scf_value_destroy(val);
12348 (void) scf_property_destroy(prop);
12349
12350 return (b);
12351 }
12352
12353 #define DELETE_FAILURE -1
12354 #define DELETE_SUCCESS_NOEXTDEPS 0
12355 #define DELETE_SUCCESS_EXTDEPS 1
12356
12357 /*
12358 * lscf_instance_delete() deletes an instance. Before calling
12359 * scf_instance_delete(), though, we make sure the instance isn't
12360 * running and delete dependencies in other entities which the instance
12361 * declared as "dependents". If there are dependencies which were
12362 * created for other entities, then instead of deleting the instance we
12363 * make it "empty" by deleting all other property groups and all
12364 * snapshots.
12365 *
12366 * lscf_instance_delete() verifies that there is no external dependency pgs
12367 * before suppressing the instance. If there is, then we must not remove them
12368 * now in case the instance is re-created otherwise the dependencies would be
12369 * lost. The external dependency pgs will be removed if the dependencies are
12370 * removed.
12371 *
12372 * Returns:
12373 * DELETE_FAILURE on failure
12374 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12375 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12376 */
12377 static int
lscf_instance_delete(scf_instance_t * inst,int force)12378 lscf_instance_delete(scf_instance_t *inst, int force)
12379 {
12380 scf_propertygroup_t *pg;
12381 scf_snapshot_t *snap;
12382 scf_iter_t *iter;
12383 int err;
12384 int external = 0;
12385
12386 /* If we're not forcing and the instance is running, refuse. */
12387 if (!force && inst_is_running(inst)) {
12388 char *fmri;
12389
12390 fmri = safe_malloc(max_scf_fmri_len + 1);
12391
12392 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
12393 scfdie();
12394
12395 semerr(gettext("Instance %s may be running. "
12396 "Use delete -f if it is not.\n"), fmri);
12397
12398 free(fmri);
12399 return (DELETE_FAILURE);
12400 }
12401
12402 pg = scf_pg_create(g_hndl);
12403 if (pg == NULL)
12404 scfdie();
12405
12406 if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
12407 (void) delete_dependents(pg);
12408 else if (scf_error() != SCF_ERROR_NOT_FOUND)
12409 scfdie();
12410
12411 scf_pg_destroy(pg);
12412
12413 /*
12414 * If the instance has some external dependencies then we must
12415 * keep them in case the instance is reimported otherwise the
12416 * dependencies would be lost on reimport.
12417 */
12418 if ((iter = scf_iter_create(g_hndl)) == NULL ||
12419 (pg = scf_pg_create(g_hndl)) == NULL)
12420 scfdie();
12421
12422 if (scf_iter_instance_pgs(iter, inst) < 0)
12423 scfdie();
12424
12425 while ((err = scf_iter_next_pg(iter, pg)) == 1) {
12426 if (pg_is_external_dependency(pg)) {
12427 external = 1;
12428 continue;
12429 }
12430
12431 if (scf_pg_delete(pg) != 0) {
12432 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12433 scfdie();
12434 else {
12435 semerr(emsg_permission_denied);
12436
12437 (void) scf_iter_destroy(iter);
12438 (void) scf_pg_destroy(pg);
12439 return (DELETE_FAILURE);
12440 }
12441 }
12442 }
12443
12444 if (err == -1)
12445 scfdie();
12446
12447 (void) scf_iter_destroy(iter);
12448 (void) scf_pg_destroy(pg);
12449
12450 if (external) {
12451 /*
12452 * All the pgs have been deleted for the instance except
12453 * the ones holding the external dependencies.
12454 * For the job to be complete, we must also delete the
12455 * snapshots associated with the instance.
12456 */
12457 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
12458 NULL)
12459 scfdie();
12460 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
12461 scfdie();
12462
12463 if (scf_iter_instance_snapshots(iter, inst) == -1)
12464 scfdie();
12465
12466 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
12467 if (_scf_snapshot_delete(snap) != 0) {
12468 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12469 scfdie();
12470
12471 semerr(emsg_permission_denied);
12472
12473 (void) scf_iter_destroy(iter);
12474 (void) scf_snapshot_destroy(snap);
12475 return (DELETE_FAILURE);
12476 }
12477 }
12478
12479 if (err == -1)
12480 scfdie();
12481
12482 (void) scf_iter_destroy(iter);
12483 (void) scf_snapshot_destroy(snap);
12484 return (DELETE_SUCCESS_EXTDEPS);
12485 }
12486
12487 if (scf_instance_delete(inst) != 0) {
12488 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12489 scfdie();
12490
12491 semerr(emsg_permission_denied);
12492
12493 return (DELETE_FAILURE);
12494 }
12495
12496 return (DELETE_SUCCESS_NOEXTDEPS);
12497 }
12498
12499 /*
12500 * lscf_service_delete() deletes a service. Before calling
12501 * scf_service_delete(), though, we call lscf_instance_delete() for
12502 * each of the instances and delete dependencies in other entities
12503 * which were created as "dependents" of this service. If there are
12504 * dependencies which were created for other entities, then we delete
12505 * all other property groups in the service and leave it as "empty".
12506 *
12507 * lscf_service_delete() verifies that there is no external dependency
12508 * pgs at the instance & service level before suppressing the service.
12509 * If there is, then we must not remove them now in case the service
12510 * is re-imported otherwise the dependencies would be lost. The external
12511 * dependency pgs will be removed if the dependencies are removed.
12512 *
12513 * Returns:
12514 * DELETE_FAILURE on failure
12515 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12516 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12517 */
12518 static int
lscf_service_delete(scf_service_t * svc,int force)12519 lscf_service_delete(scf_service_t *svc, int force)
12520 {
12521 int r;
12522 scf_instance_t *inst;
12523 scf_propertygroup_t *pg;
12524 scf_iter_t *iter;
12525 int ret;
12526 int external = 0;
12527
12528 if ((inst = scf_instance_create(g_hndl)) == NULL ||
12529 (pg = scf_pg_create(g_hndl)) == NULL ||
12530 (iter = scf_iter_create(g_hndl)) == NULL)
12531 scfdie();
12532
12533 if (scf_iter_service_instances(iter, svc) != 0)
12534 scfdie();
12535
12536 for (r = scf_iter_next_instance(iter, inst);
12537 r == 1;
12538 r = scf_iter_next_instance(iter, inst)) {
12539
12540 ret = lscf_instance_delete(inst, force);
12541 if (ret == DELETE_FAILURE) {
12542 scf_iter_destroy(iter);
12543 scf_pg_destroy(pg);
12544 scf_instance_destroy(inst);
12545 return (DELETE_FAILURE);
12546 }
12547
12548 /*
12549 * Record the fact that there is some external dependencies
12550 * at the instance level.
12551 */
12552 if (ret == DELETE_SUCCESS_EXTDEPS)
12553 external |= 1;
12554 }
12555
12556 if (r != 0)
12557 scfdie();
12558
12559 /* Delete dependency property groups in dependent services. */
12560 if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12561 (void) delete_dependents(pg);
12562 else if (scf_error() != SCF_ERROR_NOT_FOUND)
12563 scfdie();
12564
12565 scf_iter_destroy(iter);
12566 scf_pg_destroy(pg);
12567 scf_instance_destroy(inst);
12568
12569 /*
12570 * If the service has some external dependencies then we don't
12571 * want to remove them in case the service is re-imported.
12572 */
12573 if ((pg = scf_pg_create(g_hndl)) == NULL ||
12574 (iter = scf_iter_create(g_hndl)) == NULL)
12575 scfdie();
12576
12577 if (scf_iter_service_pgs(iter, svc) < 0)
12578 scfdie();
12579
12580 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12581 if (pg_is_external_dependency(pg)) {
12582 external |= 2;
12583 continue;
12584 }
12585
12586 if (scf_pg_delete(pg) != 0) {
12587 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12588 scfdie();
12589 else {
12590 semerr(emsg_permission_denied);
12591
12592 (void) scf_iter_destroy(iter);
12593 (void) scf_pg_destroy(pg);
12594 return (DELETE_FAILURE);
12595 }
12596 }
12597 }
12598
12599 if (r == -1)
12600 scfdie();
12601
12602 (void) scf_iter_destroy(iter);
12603 (void) scf_pg_destroy(pg);
12604
12605 if (external != 0)
12606 return (DELETE_SUCCESS_EXTDEPS);
12607
12608 if (scf_service_delete(svc) == 0)
12609 return (DELETE_SUCCESS_NOEXTDEPS);
12610
12611 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12612 scfdie();
12613
12614 semerr(emsg_permission_denied);
12615 return (DELETE_FAILURE);
12616 }
12617
12618 static int
delete_callback(void * data,scf_walkinfo_t * wip)12619 delete_callback(void *data, scf_walkinfo_t *wip)
12620 {
12621 int force = (int)data;
12622
12623 if (wip->inst != NULL)
12624 (void) lscf_instance_delete(wip->inst, force);
12625 else
12626 (void) lscf_service_delete(wip->svc, force);
12627
12628 return (0);
12629 }
12630
12631 void
lscf_delete(const char * fmri,int force)12632 lscf_delete(const char *fmri, int force)
12633 {
12634 scf_service_t *svc;
12635 scf_instance_t *inst;
12636 int ret;
12637
12638 lscf_prep_hndl();
12639
12640 if (cur_snap != NULL) {
12641 if (!snaplevel_is_instance(cur_level)) {
12642 char *buf;
12643
12644 buf = safe_malloc(max_scf_name_len + 1);
12645 if (scf_instance_get_name(cur_inst, buf,
12646 max_scf_name_len + 1) >= 0) {
12647 if (strcmp(buf, fmri) == 0) {
12648 semerr(emsg_cant_modify_snapshots);
12649 free(buf);
12650 return;
12651 }
12652 } else if (scf_error() != SCF_ERROR_DELETED) {
12653 scfdie();
12654 }
12655 free(buf);
12656 }
12657 } else if (cur_inst != NULL) {
12658 /* EMPTY */;
12659 } else if (cur_svc != NULL) {
12660 inst = scf_instance_create(g_hndl);
12661 if (inst == NULL)
12662 scfdie();
12663
12664 if (scf_service_get_instance(cur_svc, fmri, inst) ==
12665 SCF_SUCCESS) {
12666 (void) lscf_instance_delete(inst, force);
12667 scf_instance_destroy(inst);
12668 return;
12669 }
12670
12671 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12672 scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12673 scfdie();
12674
12675 scf_instance_destroy(inst);
12676 } else {
12677 assert(cur_scope != NULL);
12678
12679 svc = scf_service_create(g_hndl);
12680 if (svc == NULL)
12681 scfdie();
12682
12683 if (scf_scope_get_service(cur_scope, fmri, svc) ==
12684 SCF_SUCCESS) {
12685 (void) lscf_service_delete(svc, force);
12686 scf_service_destroy(svc);
12687 return;
12688 }
12689
12690 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12691 scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12692 scfdie();
12693
12694 scf_service_destroy(svc);
12695 }
12696
12697 /*
12698 * Match FMRI to entity.
12699 */
12700 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12701 delete_callback, (void *)force, NULL, semerr)) != 0) {
12702 semerr(gettext("Failed to walk instances: %s\n"),
12703 scf_strerror(ret));
12704 }
12705 }
12706
12707
12708
12709 /*
12710 * :properties commands. These all end with "pg" or "prop" and generally
12711 * operate on the currently selected entity.
12712 */
12713
12714 /*
12715 * Property listing. List the property groups, properties, their types and
12716 * their values for the currently selected entity.
12717 */
12718 static void
list_pg_info(const scf_propertygroup_t * pg,const char * name,size_t namewidth)12719 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12720 {
12721 char *buf;
12722 uint32_t flags;
12723
12724 buf = safe_malloc(max_scf_pg_type_len + 1);
12725
12726 if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12727 scfdie();
12728
12729 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12730 scfdie();
12731
12732 safe_printf("%-*s %s", namewidth, name, buf);
12733
12734 if (flags & SCF_PG_FLAG_NONPERSISTENT)
12735 safe_printf("\tNONPERSISTENT");
12736
12737 safe_printf("\n");
12738
12739 free(buf);
12740 }
12741
12742 static boolean_t
prop_has_multiple_values(const scf_property_t * prop,scf_value_t * val)12743 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12744 {
12745 if (scf_property_get_value(prop, val) == 0) {
12746 return (B_FALSE);
12747 } else {
12748 switch (scf_error()) {
12749 case SCF_ERROR_NOT_FOUND:
12750 return (B_FALSE);
12751 case SCF_ERROR_PERMISSION_DENIED:
12752 case SCF_ERROR_CONSTRAINT_VIOLATED:
12753 return (B_TRUE);
12754 default:
12755 scfdie();
12756 /*NOTREACHED*/
12757 }
12758 }
12759 }
12760
12761 static void
list_prop_info(const scf_property_t * prop,const char * name,size_t len)12762 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12763 {
12764 scf_iter_t *iter;
12765 scf_value_t *val;
12766 const char *type;
12767 int multiple_strings = 0;
12768 int ret;
12769
12770 if ((iter = scf_iter_create(g_hndl)) == NULL ||
12771 (val = scf_value_create(g_hndl)) == NULL)
12772 scfdie();
12773
12774 type = prop_to_typestr(prop);
12775 assert(type != NULL);
12776
12777 safe_printf("%-*s %-7s ", len, name, type);
12778
12779 if (prop_has_multiple_values(prop, val) &&
12780 (scf_value_type(val) == SCF_TYPE_ASTRING ||
12781 scf_value_type(val) == SCF_TYPE_USTRING))
12782 multiple_strings = 1;
12783
12784 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12785 scfdie();
12786
12787 while ((ret = scf_iter_next_value(iter, val)) == 1) {
12788 char *buf;
12789 ssize_t vlen, szret;
12790
12791 vlen = scf_value_get_as_string(val, NULL, 0);
12792 if (vlen < 0)
12793 scfdie();
12794
12795 buf = safe_malloc(vlen + 1);
12796
12797 szret = scf_value_get_as_string(val, buf, vlen + 1);
12798 if (szret < 0)
12799 scfdie();
12800 assert(szret <= vlen);
12801
12802 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12803 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12804 safe_printf(" \"");
12805 (void) quote_and_print(buf, stdout, 0);
12806 (void) putchar('"');
12807 if (ferror(stdout)) {
12808 (void) putchar('\n');
12809 uu_die(gettext("Error writing to stdout.\n"));
12810 }
12811 } else {
12812 safe_printf(" %s", buf);
12813 }
12814
12815 free(buf);
12816 }
12817 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12818 scfdie();
12819
12820 if (putchar('\n') != '\n')
12821 uu_die(gettext("Could not output newline"));
12822 }
12823
12824 /*
12825 * Outputs template property group info for the describe subcommand.
12826 * If 'templates' == 2, verbose output is printed in the format expected
12827 * for describe -v, which includes all templates fields. If pg is
12828 * not NULL, we're describing the template data, not an existing property
12829 * group, and formatting should be appropriate for describe -t.
12830 */
12831 static void
list_pg_tmpl(scf_pg_tmpl_t * pgt,scf_propertygroup_t * pg,int templates)12832 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12833 {
12834 char *buf;
12835 uint8_t required;
12836 scf_property_t *stability_prop;
12837 scf_value_t *stability_val;
12838
12839 if (templates == 0)
12840 return;
12841
12842 if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12843 (stability_val = scf_value_create(g_hndl)) == NULL)
12844 scfdie();
12845
12846 if (templates == 2 && pg != NULL) {
12847 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12848 stability_prop) == 0) {
12849 if (prop_check_type(stability_prop,
12850 SCF_TYPE_ASTRING) == 0 &&
12851 prop_get_val(stability_prop, stability_val) == 0) {
12852 char *stability;
12853
12854 stability = safe_malloc(max_scf_value_len + 1);
12855
12856 if (scf_value_get_astring(stability_val,
12857 stability, max_scf_value_len + 1) == -1 &&
12858 scf_error() != SCF_ERROR_NOT_FOUND)
12859 scfdie();
12860
12861 safe_printf("%s%s: %s\n", TMPL_INDENT,
12862 gettext("stability"), stability);
12863
12864 free(stability);
12865 }
12866 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
12867 scfdie();
12868 }
12869
12870 scf_property_destroy(stability_prop);
12871 scf_value_destroy(stability_val);
12872
12873 if (pgt == NULL)
12874 return;
12875
12876 if (pg == NULL || templates == 2) {
12877 /* print type info only if scf_tmpl_pg_name succeeds */
12878 if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12879 if (pg != NULL)
12880 safe_printf("%s", TMPL_INDENT);
12881 safe_printf("%s: ", gettext("name"));
12882 safe_printf("%s\n", buf);
12883 free(buf);
12884 }
12885
12886 /* print type info only if scf_tmpl_pg_type succeeds */
12887 if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12888 if (pg != NULL)
12889 safe_printf("%s", TMPL_INDENT);
12890 safe_printf("%s: ", gettext("type"));
12891 safe_printf("%s\n", buf);
12892 free(buf);
12893 }
12894 }
12895
12896 if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12897 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12898 required ? "true" : "false");
12899
12900 if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12901 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12902 buf);
12903 free(buf);
12904 }
12905
12906 if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12907 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12908 buf);
12909 free(buf);
12910 }
12911
12912 if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12913 if (templates == 2)
12914 safe_printf("%s%s: %s\n", TMPL_INDENT,
12915 gettext("description"), buf);
12916 else
12917 safe_printf("%s%s\n", TMPL_INDENT, buf);
12918 free(buf);
12919 }
12920
12921 }
12922
12923 /*
12924 * With as_value set to true, indent as appropriate for the value level.
12925 * If false, indent to appropriate level for inclusion in constraint
12926 * or choice printout.
12927 */
12928 static void
print_template_value_details(scf_prop_tmpl_t * prt,const char * val_buf,int as_value)12929 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12930 int as_value)
12931 {
12932 char *buf;
12933
12934 if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12935 if (as_value == 0)
12936 safe_printf("%s", TMPL_CHOICE_INDENT);
12937 else
12938 safe_printf("%s", TMPL_INDENT);
12939 safe_printf("%s: %s\n", gettext("value common name"), buf);
12940 free(buf);
12941 }
12942
12943 if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12944 if (as_value == 0)
12945 safe_printf("%s", TMPL_CHOICE_INDENT);
12946 else
12947 safe_printf("%s", TMPL_INDENT);
12948 safe_printf("%s: %s\n", gettext("value description"), buf);
12949 free(buf);
12950 }
12951 }
12952
12953 static void
print_template_value(scf_prop_tmpl_t * prt,const char * val_buf)12954 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12955 {
12956 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12957 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12958 safe_printf("%s\n", val_buf);
12959
12960 print_template_value_details(prt, val_buf, 1);
12961 }
12962
12963 static void
print_template_constraints(scf_prop_tmpl_t * prt,int verbose)12964 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12965 {
12966 int i, printed = 0;
12967 scf_values_t values;
12968 scf_count_ranges_t c_ranges;
12969 scf_int_ranges_t i_ranges;
12970
12971 printed = 0;
12972 i = 0;
12973 if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12974 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12975 gettext("value constraints"));
12976 printed++;
12977 for (i = 0; i < values.value_count; ++i) {
12978 safe_printf("%s%s: %s\n", TMPL_INDENT,
12979 gettext("value name"), values.values_as_strings[i]);
12980 if (verbose == 1)
12981 print_template_value_details(prt,
12982 values.values_as_strings[i], 0);
12983 }
12984
12985 scf_values_destroy(&values);
12986 }
12987
12988 if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12989 if (printed++ == 0)
12990 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12991 gettext("value constraints"));
12992 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12993 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12994 gettext("range"), c_ranges.scr_min[i],
12995 c_ranges.scr_max[i]);
12996 }
12997 scf_count_ranges_destroy(&c_ranges);
12998 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12999 scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
13000 if (printed++ == 0)
13001 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13002 gettext("value constraints"));
13003 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
13004 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
13005 gettext("range"), i_ranges.sir_min[i],
13006 i_ranges.sir_max[i]);
13007 }
13008 scf_int_ranges_destroy(&i_ranges);
13009 }
13010 }
13011
13012 static void
print_template_choices(scf_prop_tmpl_t * prt,int verbose)13013 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
13014 {
13015 int i = 0, printed = 0;
13016 scf_values_t values;
13017 scf_count_ranges_t c_ranges;
13018 scf_int_ranges_t i_ranges;
13019
13020 printed = 0;
13021 if (scf_tmpl_value_name_choices(prt, &values) == 0) {
13022 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13023 gettext("value constraints"));
13024 printed++;
13025 for (i = 0; i < values.value_count; i++) {
13026 safe_printf("%s%s: %s\n", TMPL_INDENT,
13027 gettext("value name"), values.values_as_strings[i]);
13028 if (verbose == 1)
13029 print_template_value_details(prt,
13030 values.values_as_strings[i], 0);
13031 }
13032
13033 scf_values_destroy(&values);
13034 }
13035
13036 if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
13037 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
13038 if (printed++ == 0)
13039 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13040 gettext("value choices"));
13041 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
13042 gettext("range"), c_ranges.scr_min[i],
13043 c_ranges.scr_max[i]);
13044 }
13045 scf_count_ranges_destroy(&c_ranges);
13046 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
13047 scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
13048 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
13049 if (printed++ == 0)
13050 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13051 gettext("value choices"));
13052 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
13053 gettext("range"), i_ranges.sir_min[i],
13054 i_ranges.sir_max[i]);
13055 }
13056 scf_int_ranges_destroy(&i_ranges);
13057 }
13058 }
13059
13060 static void
list_values_by_template(scf_prop_tmpl_t * prt)13061 list_values_by_template(scf_prop_tmpl_t *prt)
13062 {
13063 print_template_constraints(prt, 1);
13064 print_template_choices(prt, 1);
13065 }
13066
13067 static void
list_values_tmpl(scf_prop_tmpl_t * prt,scf_property_t * prop)13068 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
13069 {
13070 char *val_buf;
13071 scf_iter_t *iter;
13072 scf_value_t *val;
13073 int ret;
13074
13075 if ((iter = scf_iter_create(g_hndl)) == NULL ||
13076 (val = scf_value_create(g_hndl)) == NULL)
13077 scfdie();
13078
13079 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
13080 scfdie();
13081
13082 val_buf = safe_malloc(max_scf_value_len + 1);
13083
13084 while ((ret = scf_iter_next_value(iter, val)) == 1) {
13085 if (scf_value_get_as_string(val, val_buf,
13086 max_scf_value_len + 1) < 0)
13087 scfdie();
13088
13089 print_template_value(prt, val_buf);
13090 }
13091 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
13092 scfdie();
13093 free(val_buf);
13094
13095 print_template_constraints(prt, 0);
13096 print_template_choices(prt, 0);
13097
13098 }
13099
13100 /*
13101 * Outputs property info for the describe subcommand
13102 * Verbose output if templates == 2, -v option of svccfg describe
13103 * Displays template data if prop is not NULL, -t option of svccfg describe
13104 */
13105 static void
list_prop_tmpl(scf_prop_tmpl_t * prt,scf_property_t * prop,int templates)13106 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
13107 {
13108 char *buf;
13109 uint8_t u_buf;
13110 int i;
13111 uint64_t min, max;
13112 scf_values_t values;
13113
13114 if (prt == NULL || templates == 0)
13115 return;
13116
13117 if (prop == NULL) {
13118 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
13119 if (scf_tmpl_prop_name(prt, &buf) > 0) {
13120 safe_printf("%s\n", buf);
13121 free(buf);
13122 } else
13123 safe_printf("(%s)\n", gettext("any"));
13124 }
13125
13126 if (prop == NULL || templates == 2) {
13127 if (prop != NULL)
13128 safe_printf("%s", TMPL_INDENT);
13129 else
13130 safe_printf("%s", TMPL_VALUE_INDENT);
13131 safe_printf("%s: ", gettext("type"));
13132 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
13133 safe_printf("%s\n", buf);
13134 free(buf);
13135 } else
13136 safe_printf("(%s)\n", gettext("any"));
13137 }
13138
13139 if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
13140 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
13141 u_buf ? "true" : "false");
13142
13143 if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
13144 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
13145 buf);
13146 free(buf);
13147 }
13148
13149 if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
13150 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
13151 buf);
13152 free(buf);
13153 }
13154
13155 if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
13156 safe_printf("%s%s\n", TMPL_INDENT, buf);
13157 free(buf);
13158 }
13159
13160 if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
13161 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
13162 scf_tmpl_visibility_to_string(u_buf));
13163
13164 if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
13165 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13166 gettext("minimum number of values"), min);
13167 if (max == ULLONG_MAX) {
13168 safe_printf("%s%s: %s\n", TMPL_INDENT,
13169 gettext("maximum number of values"),
13170 gettext("unlimited"));
13171 } else {
13172 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13173 gettext("maximum number of values"), max);
13174 }
13175 }
13176
13177 if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
13178 for (i = 0; i < values.value_count; i++) {
13179 if (i == 0) {
13180 safe_printf("%s%s:", TMPL_INDENT,
13181 gettext("internal separators"));
13182 }
13183 safe_printf(" \"%s\"", values.values_as_strings[i]);
13184 }
13185 safe_printf("\n");
13186 }
13187
13188 if (templates != 2)
13189 return;
13190
13191 if (prop != NULL)
13192 list_values_tmpl(prt, prop);
13193 else
13194 list_values_by_template(prt);
13195 }
13196
13197 static char *
read_astring(scf_propertygroup_t * pg,const char * prop_name)13198 read_astring(scf_propertygroup_t *pg, const char *prop_name)
13199 {
13200 char *rv;
13201
13202 rv = _scf_read_single_astring_from_pg(pg, prop_name);
13203 if (rv == NULL) {
13204 switch (scf_error()) {
13205 case SCF_ERROR_NOT_FOUND:
13206 break;
13207 default:
13208 scfdie();
13209 }
13210 }
13211 return (rv);
13212 }
13213
13214 static void
display_documentation(scf_iter_t * iter,scf_propertygroup_t * pg)13215 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
13216 {
13217 size_t doc_len;
13218 size_t man_len;
13219 char *pg_name;
13220 char *text = NULL;
13221 int rv;
13222
13223 doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
13224 man_len = strlen(SCF_PG_TM_MAN_PREFIX);
13225 pg_name = safe_malloc(max_scf_name_len + 1);
13226 while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
13227 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
13228 scfdie();
13229 }
13230 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
13231 /* Display doc_link and and uri */
13232 safe_printf("%s%s:\n", TMPL_INDENT,
13233 gettext("doc_link"));
13234 text = read_astring(pg, SCF_PROPERTY_TM_NAME);
13235 if (text != NULL) {
13236 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13237 TMPL_INDENT, gettext("name"), text);
13238 uu_free(text);
13239 }
13240 text = read_astring(pg, SCF_PROPERTY_TM_URI);
13241 if (text != NULL) {
13242 safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
13243 gettext("uri"), text);
13244 uu_free(text);
13245 }
13246 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
13247 man_len) == 0) {
13248 /* Display manpage title, section and path */
13249 safe_printf("%s%s:\n", TMPL_INDENT,
13250 gettext("manpage"));
13251 text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
13252 if (text != NULL) {
13253 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13254 TMPL_INDENT, gettext("title"), text);
13255 uu_free(text);
13256 }
13257 text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
13258 if (text != NULL) {
13259 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13260 TMPL_INDENT, gettext("section"), text);
13261 uu_free(text);
13262 }
13263 text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
13264 if (text != NULL) {
13265 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13266 TMPL_INDENT, gettext("manpath"), text);
13267 uu_free(text);
13268 }
13269 }
13270 }
13271 if (rv == -1)
13272 scfdie();
13273
13274 free(pg_name);
13275 }
13276
13277 static void
list_entity_tmpl(int templates)13278 list_entity_tmpl(int templates)
13279 {
13280 char *common_name = NULL;
13281 char *description = NULL;
13282 char *locale = NULL;
13283 scf_iter_t *iter;
13284 scf_propertygroup_t *pg;
13285 scf_property_t *prop;
13286 int r;
13287 scf_value_t *val;
13288
13289 if ((pg = scf_pg_create(g_hndl)) == NULL ||
13290 (prop = scf_property_create(g_hndl)) == NULL ||
13291 (val = scf_value_create(g_hndl)) == NULL ||
13292 (iter = scf_iter_create(g_hndl)) == NULL)
13293 scfdie();
13294
13295 locale = setlocale(LC_MESSAGES, NULL);
13296
13297 if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
13298 common_name = safe_malloc(max_scf_value_len + 1);
13299
13300 /* Try both the current locale and the "C" locale. */
13301 if (scf_pg_get_property(pg, locale, prop) == 0 ||
13302 (scf_error() == SCF_ERROR_NOT_FOUND &&
13303 scf_pg_get_property(pg, "C", prop) == 0)) {
13304 if (prop_get_val(prop, val) == 0 &&
13305 scf_value_get_ustring(val, common_name,
13306 max_scf_value_len + 1) != -1) {
13307 safe_printf("%s%s: %s\n", TMPL_INDENT,
13308 gettext("common name"), common_name);
13309 }
13310 }
13311 }
13312
13313 /*
13314 * Do description, manpages, and doc links if templates == 2.
13315 */
13316 if (templates == 2) {
13317 /* Get the description. */
13318 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
13319 description = safe_malloc(max_scf_value_len + 1);
13320
13321 /* Try both the current locale and the "C" locale. */
13322 if (scf_pg_get_property(pg, locale, prop) == 0 ||
13323 (scf_error() == SCF_ERROR_NOT_FOUND &&
13324 scf_pg_get_property(pg, "C", prop) == 0)) {
13325 if (prop_get_val(prop, val) == 0 &&
13326 scf_value_get_ustring(val, description,
13327 max_scf_value_len + 1) != -1) {
13328 safe_printf("%s%s: %s\n", TMPL_INDENT,
13329 gettext("description"),
13330 description);
13331 }
13332 }
13333 }
13334
13335 /* Process doc_link & manpage elements. */
13336 if (cur_level != NULL) {
13337 r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
13338 SCF_GROUP_TEMPLATE);
13339 } else if (cur_inst != NULL) {
13340 r = scf_iter_instance_pgs_typed(iter, cur_inst,
13341 SCF_GROUP_TEMPLATE);
13342 } else {
13343 r = scf_iter_service_pgs_typed(iter, cur_svc,
13344 SCF_GROUP_TEMPLATE);
13345 }
13346 if (r == 0) {
13347 display_documentation(iter, pg);
13348 }
13349 }
13350
13351 free(common_name);
13352 free(description);
13353 scf_pg_destroy(pg);
13354 scf_property_destroy(prop);
13355 scf_value_destroy(val);
13356 scf_iter_destroy(iter);
13357 }
13358
13359 static void
listtmpl(const char * pattern,int templates)13360 listtmpl(const char *pattern, int templates)
13361 {
13362 scf_pg_tmpl_t *pgt;
13363 scf_prop_tmpl_t *prt;
13364 char *snapbuf = NULL;
13365 char *fmribuf;
13366 char *pg_name = NULL, *prop_name = NULL;
13367 ssize_t prop_name_size;
13368 char *qual_prop_name;
13369 char *search_name;
13370 int listed = 0;
13371
13372 if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13373 (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
13374 scfdie();
13375
13376 fmribuf = safe_malloc(max_scf_name_len + 1);
13377 qual_prop_name = safe_malloc(max_scf_name_len + 1);
13378
13379 if (cur_snap != NULL) {
13380 snapbuf = safe_malloc(max_scf_name_len + 1);
13381 if (scf_snapshot_get_name(cur_snap, snapbuf,
13382 max_scf_name_len + 1) < 0)
13383 scfdie();
13384 }
13385
13386 if (cur_inst != NULL) {
13387 if (scf_instance_to_fmri(cur_inst, fmribuf,
13388 max_scf_name_len + 1) < 0)
13389 scfdie();
13390 } else if (cur_svc != NULL) {
13391 if (scf_service_to_fmri(cur_svc, fmribuf,
13392 max_scf_name_len + 1) < 0)
13393 scfdie();
13394 } else
13395 abort();
13396
13397 /* If pattern is specified, we want to list only those items. */
13398 while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) {
13399 listed = 0;
13400 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
13401 fnmatch(pattern, pg_name, 0) == 0)) {
13402 list_pg_tmpl(pgt, NULL, templates);
13403 listed++;
13404 }
13405
13406 scf_tmpl_prop_reset(prt);
13407
13408 while (scf_tmpl_iter_props(pgt, prt, 0) == 0) {
13409 search_name = NULL;
13410 prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
13411 if ((prop_name_size > 0) && (pg_name != NULL)) {
13412 if (snprintf(qual_prop_name,
13413 max_scf_name_len + 1, "%s/%s",
13414 pg_name, prop_name) >=
13415 max_scf_name_len + 1) {
13416 prop_name_size = -1;
13417 } else {
13418 search_name = qual_prop_name;
13419 }
13420 }
13421 if (listed > 0 || pattern == NULL ||
13422 (prop_name_size > 0 &&
13423 fnmatch(pattern, search_name,
13424 FNM_PATHNAME) == 0))
13425 list_prop_tmpl(prt, NULL, templates);
13426 if (prop_name != NULL) {
13427 free(prop_name);
13428 prop_name = NULL;
13429 }
13430 }
13431 if (pg_name != NULL) {
13432 free(pg_name);
13433 pg_name = NULL;
13434 }
13435 }
13436
13437 scf_tmpl_prop_destroy(prt);
13438 scf_tmpl_pg_destroy(pgt);
13439 free(snapbuf);
13440 free(fmribuf);
13441 free(qual_prop_name);
13442 }
13443
13444 static void
listprop(const char * pattern,int only_pgs,int templates)13445 listprop(const char *pattern, int only_pgs, int templates)
13446 {
13447 scf_propertygroup_t *pg;
13448 scf_property_t *prop;
13449 scf_iter_t *iter, *piter;
13450 char *pgnbuf, *prnbuf, *ppnbuf;
13451 scf_pg_tmpl_t *pgt, *pgtp;
13452 scf_prop_tmpl_t *prt;
13453
13454 void **objects;
13455 char **names;
13456 void **tmpls;
13457 int allocd, i;
13458
13459 int ret;
13460 ssize_t pgnlen, prnlen, szret;
13461 size_t max_len = 0;
13462
13463 if (cur_svc == NULL && cur_inst == NULL) {
13464 semerr(emsg_entity_not_selected);
13465 return;
13466 }
13467
13468 if ((pg = scf_pg_create(g_hndl)) == NULL ||
13469 (prop = scf_property_create(g_hndl)) == NULL ||
13470 (iter = scf_iter_create(g_hndl)) == NULL ||
13471 (piter = scf_iter_create(g_hndl)) == NULL ||
13472 (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13473 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
13474 scfdie();
13475
13476 prnbuf = safe_malloc(max_scf_name_len + 1);
13477
13478 if (cur_level != NULL)
13479 ret = scf_iter_snaplevel_pgs(iter, cur_level);
13480 else if (cur_inst != NULL)
13481 ret = scf_iter_instance_pgs(iter, cur_inst);
13482 else
13483 ret = scf_iter_service_pgs(iter, cur_svc);
13484 if (ret != 0) {
13485 return;
13486 }
13487
13488 /*
13489 * We want to only list items which match pattern, and we want the
13490 * second column to line up, so during the first pass we'll save
13491 * matching items, their names, and their templates in objects,
13492 * names, and tmpls, computing the maximum name length as we go,
13493 * and then we'll print them out.
13494 *
13495 * Note: We always keep an extra slot available so the array can be
13496 * NULL-terminated.
13497 */
13498 i = 0;
13499 allocd = 1;
13500 objects = safe_malloc(sizeof (*objects));
13501 names = safe_malloc(sizeof (*names));
13502 tmpls = safe_malloc(sizeof (*tmpls));
13503
13504 while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13505 int new_pg = 0;
13506 int print_props = 0;
13507 pgtp = NULL;
13508
13509 pgnlen = scf_pg_get_name(pg, NULL, 0);
13510 if (pgnlen < 0)
13511 scfdie();
13512
13513 pgnbuf = safe_malloc(pgnlen + 1);
13514
13515 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
13516 if (szret < 0)
13517 scfdie();
13518 assert(szret <= pgnlen);
13519
13520 if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) {
13521 if (scf_error() != SCF_ERROR_NOT_FOUND)
13522 scfdie();
13523 pgtp = NULL;
13524 } else {
13525 pgtp = pgt;
13526 }
13527
13528 if (pattern == NULL ||
13529 fnmatch(pattern, pgnbuf, 0) == 0) {
13530 if (i+1 >= allocd) {
13531 allocd *= 2;
13532 objects = realloc(objects,
13533 sizeof (*objects) * allocd);
13534 names =
13535 realloc(names, sizeof (*names) * allocd);
13536 tmpls = realloc(tmpls,
13537 sizeof (*tmpls) * allocd);
13538 if (objects == NULL || names == NULL ||
13539 tmpls == NULL)
13540 uu_die(gettext("Out of memory"));
13541 }
13542 objects[i] = pg;
13543 names[i] = pgnbuf;
13544
13545 if (pgtp == NULL)
13546 tmpls[i] = NULL;
13547 else
13548 tmpls[i] = pgt;
13549
13550 ++i;
13551
13552 if (pgnlen > max_len)
13553 max_len = pgnlen;
13554
13555 new_pg = 1;
13556 print_props = 1;
13557 }
13558
13559 if (only_pgs) {
13560 if (new_pg) {
13561 pg = scf_pg_create(g_hndl);
13562 if (pg == NULL)
13563 scfdie();
13564 pgt = scf_tmpl_pg_create(g_hndl);
13565 if (pgt == NULL)
13566 scfdie();
13567 } else
13568 free(pgnbuf);
13569
13570 continue;
13571 }
13572
13573 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13574 scfdie();
13575
13576 while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13577 prnlen = scf_property_get_name(prop, prnbuf,
13578 max_scf_name_len + 1);
13579 if (prnlen < 0)
13580 scfdie();
13581
13582 /* Will prepend the property group name and a slash. */
13583 prnlen += pgnlen + 1;
13584
13585 ppnbuf = safe_malloc(prnlen + 1);
13586
13587 if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13588 prnbuf) < 0)
13589 uu_die("snprintf");
13590
13591 if (pattern == NULL || print_props == 1 ||
13592 fnmatch(pattern, ppnbuf, 0) == 0) {
13593 if (i+1 >= allocd) {
13594 allocd *= 2;
13595 objects = realloc(objects,
13596 sizeof (*objects) * allocd);
13597 names = realloc(names,
13598 sizeof (*names) * allocd);
13599 tmpls = realloc(tmpls,
13600 sizeof (*tmpls) * allocd);
13601 if (objects == NULL || names == NULL ||
13602 tmpls == NULL)
13603 uu_die(gettext(
13604 "Out of memory"));
13605 }
13606
13607 objects[i] = prop;
13608 names[i] = ppnbuf;
13609
13610 if (pgtp != NULL) {
13611 if (scf_tmpl_get_by_prop(pgt, prnbuf,
13612 prt, 0) < 0) {
13613 if (scf_error() !=
13614 SCF_ERROR_NOT_FOUND)
13615 scfdie();
13616 tmpls[i] = NULL;
13617 } else {
13618 tmpls[i] = prt;
13619 }
13620 } else {
13621 tmpls[i] = NULL;
13622 }
13623
13624 ++i;
13625
13626 if (prnlen > max_len)
13627 max_len = prnlen;
13628
13629 prop = scf_property_create(g_hndl);
13630 prt = scf_tmpl_prop_create(g_hndl);
13631 } else {
13632 free(ppnbuf);
13633 }
13634 }
13635
13636 if (new_pg) {
13637 pg = scf_pg_create(g_hndl);
13638 if (pg == NULL)
13639 scfdie();
13640 pgt = scf_tmpl_pg_create(g_hndl);
13641 if (pgt == NULL)
13642 scfdie();
13643 } else
13644 free(pgnbuf);
13645 }
13646 if (ret != 0)
13647 scfdie();
13648
13649 objects[i] = NULL;
13650
13651 scf_pg_destroy(pg);
13652 scf_tmpl_pg_destroy(pgt);
13653 scf_property_destroy(prop);
13654 scf_tmpl_prop_destroy(prt);
13655
13656 for (i = 0; objects[i] != NULL; ++i) {
13657 if (strchr(names[i], '/') == NULL) {
13658 /* property group */
13659 pg = (scf_propertygroup_t *)objects[i];
13660 pgt = (scf_pg_tmpl_t *)tmpls[i];
13661 list_pg_info(pg, names[i], max_len);
13662 list_pg_tmpl(pgt, pg, templates);
13663 free(names[i]);
13664 scf_pg_destroy(pg);
13665 if (pgt != NULL)
13666 scf_tmpl_pg_destroy(pgt);
13667 } else {
13668 /* property */
13669 prop = (scf_property_t *)objects[i];
13670 prt = (scf_prop_tmpl_t *)tmpls[i];
13671 list_prop_info(prop, names[i], max_len);
13672 list_prop_tmpl(prt, prop, templates);
13673 free(names[i]);
13674 scf_property_destroy(prop);
13675 if (prt != NULL)
13676 scf_tmpl_prop_destroy(prt);
13677 }
13678 }
13679
13680 free(names);
13681 free(objects);
13682 free(tmpls);
13683 }
13684
13685 void
lscf_listpg(const char * pattern)13686 lscf_listpg(const char *pattern)
13687 {
13688 lscf_prep_hndl();
13689
13690 listprop(pattern, 1, 0);
13691 }
13692
13693 /*
13694 * Property group and property creation, setting, and deletion. setprop (and
13695 * its alias, addprop) can either create a property group of a given type, or
13696 * it can create or set a property to a given type and list of values.
13697 */
13698 void
lscf_addpg(const char * name,const char * type,const char * flags)13699 lscf_addpg(const char *name, const char *type, const char *flags)
13700 {
13701 scf_propertygroup_t *pg;
13702 int ret;
13703 uint32_t flgs = 0;
13704 const char *cp;
13705
13706
13707 lscf_prep_hndl();
13708
13709 if (cur_snap != NULL) {
13710 semerr(emsg_cant_modify_snapshots);
13711 return;
13712 }
13713
13714 if (cur_inst == NULL && cur_svc == NULL) {
13715 semerr(emsg_entity_not_selected);
13716 return;
13717 }
13718
13719 if (flags != NULL) {
13720 for (cp = flags; *cp != '\0'; ++cp) {
13721 switch (*cp) {
13722 case 'P':
13723 flgs |= SCF_PG_FLAG_NONPERSISTENT;
13724 break;
13725
13726 case 'p':
13727 flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13728 break;
13729
13730 default:
13731 semerr(gettext("Invalid property group flag "
13732 "%c."), *cp);
13733 return;
13734 }
13735 }
13736 }
13737
13738 pg = scf_pg_create(g_hndl);
13739 if (pg == NULL)
13740 scfdie();
13741
13742 if (cur_inst != NULL)
13743 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13744 else
13745 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13746
13747 if (ret != SCF_SUCCESS) {
13748 switch (scf_error()) {
13749 case SCF_ERROR_INVALID_ARGUMENT:
13750 semerr(gettext("Name, type, or flags are invalid.\n"));
13751 break;
13752
13753 case SCF_ERROR_EXISTS:
13754 semerr(gettext("Property group already exists.\n"));
13755 break;
13756
13757 case SCF_ERROR_PERMISSION_DENIED:
13758 semerr(emsg_permission_denied);
13759 break;
13760
13761 case SCF_ERROR_BACKEND_ACCESS:
13762 semerr(gettext("Backend refused access.\n"));
13763 break;
13764
13765 default:
13766 scfdie();
13767 }
13768 }
13769
13770 scf_pg_destroy(pg);
13771
13772 private_refresh();
13773 }
13774
13775 void
lscf_delpg(char * name)13776 lscf_delpg(char *name)
13777 {
13778 lscf_prep_hndl();
13779
13780 if (cur_snap != NULL) {
13781 semerr(emsg_cant_modify_snapshots);
13782 return;
13783 }
13784
13785 if (cur_inst == NULL && cur_svc == NULL) {
13786 semerr(emsg_entity_not_selected);
13787 return;
13788 }
13789
13790 if (strchr(name, '/') != NULL) {
13791 semerr(emsg_invalid_pg_name, name);
13792 return;
13793 }
13794
13795 lscf_delprop(name);
13796 }
13797
13798 /*
13799 * scf_delhash() is used to remove the property group related to the
13800 * hash entry for a specific manifest in the repository. pgname will be
13801 * constructed from the location of the manifest file. If deathrow isn't 0,
13802 * manifest file doesn't need to exist (manifest string will be used as
13803 * an absolute path).
13804 */
13805 void
lscf_delhash(char * manifest,int deathrow)13806 lscf_delhash(char *manifest, int deathrow)
13807 {
13808 char *pgname;
13809
13810 if (cur_snap != NULL ||
13811 cur_inst != NULL || cur_svc != NULL) {
13812 warn(gettext("error, an entity is selected\n"));
13813 return;
13814 }
13815
13816 /* select smf/manifest */
13817 lscf_select(HASH_SVC);
13818 /*
13819 * Translate the manifest file name to property name. In the deathrow
13820 * case, the manifest file does not need to exist.
13821 */
13822 pgname = mhash_filename_to_propname(manifest,
13823 deathrow ? B_TRUE : B_FALSE);
13824 if (pgname == NULL) {
13825 warn(gettext("cannot resolve pathname for %s\n"), manifest);
13826 return;
13827 }
13828 /* delete the hash property name */
13829 lscf_delpg(pgname);
13830 }
13831
13832 void
lscf_listprop(const char * pattern)13833 lscf_listprop(const char *pattern)
13834 {
13835 lscf_prep_hndl();
13836
13837 listprop(pattern, 0, 0);
13838 }
13839
13840 int
lscf_setprop(const char * pgname,const char * type,const char * value,const uu_list_t * values)13841 lscf_setprop(const char *pgname, const char *type, const char *value,
13842 const uu_list_t *values)
13843 {
13844 scf_type_t ty, current_ty;
13845 scf_service_t *svc;
13846 scf_propertygroup_t *pg, *parent_pg;
13847 scf_property_t *prop, *parent_prop;
13848 scf_pg_tmpl_t *pgt;
13849 scf_prop_tmpl_t *prt;
13850 int ret, result = 0;
13851 scf_transaction_t *tx;
13852 scf_transaction_entry_t *e;
13853 scf_value_t *v;
13854 uu_list_walk_t *walk;
13855 string_list_t *sp;
13856 char *propname;
13857 int req_quotes = 0;
13858
13859 lscf_prep_hndl();
13860
13861 if ((e = scf_entry_create(g_hndl)) == NULL ||
13862 (svc = scf_service_create(g_hndl)) == NULL ||
13863 (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13864 (pg = scf_pg_create(g_hndl)) == NULL ||
13865 (parent_prop = scf_property_create(g_hndl)) == NULL ||
13866 (prop = scf_property_create(g_hndl)) == NULL ||
13867 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13868 (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13869 (tx = scf_transaction_create(g_hndl)) == NULL)
13870 scfdie();
13871
13872 if (cur_snap != NULL) {
13873 semerr(emsg_cant_modify_snapshots);
13874 goto fail;
13875 }
13876
13877 if (cur_inst == NULL && cur_svc == NULL) {
13878 semerr(emsg_entity_not_selected);
13879 goto fail;
13880 }
13881
13882 propname = strchr(pgname, '/');
13883 if (propname == NULL) {
13884 semerr(gettext("Property names must contain a `/'.\n"));
13885 goto fail;
13886 }
13887
13888 *propname = '\0';
13889 ++propname;
13890
13891 if (type != NULL) {
13892 ty = string_to_type(type);
13893 if (ty == SCF_TYPE_INVALID) {
13894 semerr(gettext("Unknown type \"%s\".\n"), type);
13895 goto fail;
13896 }
13897 }
13898
13899 if (cur_inst != NULL)
13900 ret = scf_instance_get_pg(cur_inst, pgname, pg);
13901 else
13902 ret = scf_service_get_pg(cur_svc, pgname, pg);
13903 if (ret != SCF_SUCCESS) {
13904 switch (scf_error()) {
13905 case SCF_ERROR_NOT_FOUND:
13906 semerr(emsg_no_such_pg, pgname);
13907 goto fail;
13908
13909 case SCF_ERROR_INVALID_ARGUMENT:
13910 semerr(emsg_invalid_pg_name, pgname);
13911 goto fail;
13912
13913 default:
13914 scfdie();
13915 break;
13916 }
13917 }
13918
13919 do {
13920 if (scf_pg_update(pg) == -1)
13921 scfdie();
13922 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13923 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13924 scfdie();
13925
13926 semerr(emsg_permission_denied);
13927 goto fail;
13928 }
13929
13930 ret = scf_pg_get_property(pg, propname, prop);
13931 if (ret == SCF_SUCCESS) {
13932 if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS)
13933 scfdie();
13934
13935 if (type == NULL)
13936 ty = current_ty;
13937 if (scf_transaction_property_change_type(tx, e,
13938 propname, ty) == -1)
13939 scfdie();
13940
13941 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13942 /* Infer the type, if possible. */
13943 if (type == NULL) {
13944 /*
13945 * First check if we're an instance and the
13946 * property is set on the service.
13947 */
13948 if (cur_inst != NULL &&
13949 scf_instance_get_parent(cur_inst,
13950 svc) == 0 &&
13951 scf_service_get_pg(cur_svc, pgname,
13952 parent_pg) == 0 &&
13953 scf_pg_get_property(parent_pg, propname,
13954 parent_prop) == 0 &&
13955 scf_property_type(parent_prop,
13956 ¤t_ty) == 0) {
13957 ty = current_ty;
13958
13959 /* Then check for a type set in a template. */
13960 } else if (scf_tmpl_get_by_pg(pg, pgt,
13961 0) == 0 &&
13962 scf_tmpl_get_by_prop(pgt, propname, prt,
13963 0) == 0 &&
13964 scf_tmpl_prop_type(prt, ¤t_ty) == 0) {
13965 ty = current_ty;
13966
13967 /* If type can't be inferred, fail. */
13968 } else {
13969 semerr(gettext("Type required for new "
13970 "properties.\n"));
13971 goto fail;
13972 }
13973 }
13974 if (scf_transaction_property_new(tx, e, propname,
13975 ty) == -1)
13976 scfdie();
13977 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13978 semerr(emsg_invalid_prop_name, propname);
13979 goto fail;
13980 } else {
13981 scfdie();
13982 }
13983
13984 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13985 req_quotes = 1;
13986
13987 if (value != NULL) {
13988 v = string_to_value(value, ty, 0);
13989
13990 if (v == NULL)
13991 goto fail;
13992
13993 ret = scf_entry_add_value(e, v);
13994 assert(ret == SCF_SUCCESS);
13995 } else {
13996 assert(values != NULL);
13997
13998 walk = uu_list_walk_start((uu_list_t *)values,
13999 UU_DEFAULT);
14000 if (walk == NULL)
14001 uu_die(gettext("Could not walk list"));
14002
14003 for (sp = uu_list_walk_next(walk); sp != NULL;
14004 sp = uu_list_walk_next(walk)) {
14005 v = string_to_value(sp->str, ty, req_quotes);
14006
14007 if (v == NULL) {
14008 scf_entry_destroy_children(e);
14009 goto fail;
14010 }
14011
14012 ret = scf_entry_add_value(e, v);
14013 assert(ret == SCF_SUCCESS);
14014 }
14015 uu_list_walk_end(walk);
14016 }
14017 result = scf_transaction_commit(tx);
14018
14019 scf_transaction_reset(tx);
14020 scf_entry_destroy_children(e);
14021 } while (result == 0);
14022
14023 if (result < 0) {
14024 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14025 scfdie();
14026
14027 semerr(emsg_permission_denied);
14028 goto fail;
14029 }
14030
14031 ret = 0;
14032
14033 private_refresh();
14034
14035 goto cleanup;
14036
14037 fail:
14038 ret = -1;
14039
14040 cleanup:
14041 scf_transaction_destroy(tx);
14042 scf_entry_destroy(e);
14043 scf_service_destroy(svc);
14044 scf_pg_destroy(parent_pg);
14045 scf_pg_destroy(pg);
14046 scf_property_destroy(parent_prop);
14047 scf_property_destroy(prop);
14048 scf_tmpl_pg_destroy(pgt);
14049 scf_tmpl_prop_destroy(prt);
14050
14051 return (ret);
14052 }
14053
14054 void
lscf_delprop(char * pgn)14055 lscf_delprop(char *pgn)
14056 {
14057 char *slash, *pn;
14058 scf_propertygroup_t *pg;
14059 scf_transaction_t *tx;
14060 scf_transaction_entry_t *e;
14061 int ret;
14062
14063
14064 lscf_prep_hndl();
14065
14066 if (cur_snap != NULL) {
14067 semerr(emsg_cant_modify_snapshots);
14068 return;
14069 }
14070
14071 if (cur_inst == NULL && cur_svc == NULL) {
14072 semerr(emsg_entity_not_selected);
14073 return;
14074 }
14075
14076 pg = scf_pg_create(g_hndl);
14077 if (pg == NULL)
14078 scfdie();
14079
14080 slash = strchr(pgn, '/');
14081 if (slash == NULL) {
14082 pn = NULL;
14083 } else {
14084 *slash = '\0';
14085 pn = slash + 1;
14086 }
14087
14088 if (cur_inst != NULL)
14089 ret = scf_instance_get_pg(cur_inst, pgn, pg);
14090 else
14091 ret = scf_service_get_pg(cur_svc, pgn, pg);
14092 if (ret != SCF_SUCCESS) {
14093 switch (scf_error()) {
14094 case SCF_ERROR_NOT_FOUND:
14095 semerr(emsg_no_such_pg, pgn);
14096 break;
14097
14098 case SCF_ERROR_INVALID_ARGUMENT:
14099 semerr(emsg_invalid_pg_name, pgn);
14100 break;
14101
14102 default:
14103 scfdie();
14104 }
14105
14106 scf_pg_destroy(pg);
14107
14108 return;
14109 }
14110
14111 if (pn == NULL) {
14112 /* Try to delete the property group. */
14113 if (scf_pg_delete(pg) != SCF_SUCCESS) {
14114 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14115 scfdie();
14116
14117 semerr(emsg_permission_denied);
14118 } else {
14119 private_refresh();
14120 }
14121
14122 scf_pg_destroy(pg);
14123 return;
14124 }
14125
14126 e = scf_entry_create(g_hndl);
14127 tx = scf_transaction_create(g_hndl);
14128
14129 do {
14130 if (scf_pg_update(pg) == -1)
14131 scfdie();
14132 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
14133 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14134 scfdie();
14135
14136 semerr(emsg_permission_denied);
14137 break;
14138 }
14139
14140 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
14141 if (scf_error() == SCF_ERROR_NOT_FOUND) {
14142 semerr(gettext("No such property %s/%s.\n"),
14143 pgn, pn);
14144 break;
14145 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14146 semerr(emsg_invalid_prop_name, pn);
14147 break;
14148 } else {
14149 scfdie();
14150 }
14151 }
14152
14153 ret = scf_transaction_commit(tx);
14154
14155 if (ret == 0)
14156 scf_transaction_reset(tx);
14157 } while (ret == 0);
14158
14159 if (ret < 0) {
14160 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14161 scfdie();
14162
14163 semerr(emsg_permission_denied);
14164 } else {
14165 private_refresh();
14166 }
14167
14168 scf_transaction_destroy(tx);
14169 scf_entry_destroy(e);
14170 scf_pg_destroy(pg);
14171 }
14172
14173 /*
14174 * Property editing.
14175 */
14176
14177 static int
write_edit_script(FILE * strm)14178 write_edit_script(FILE *strm)
14179 {
14180 char *fmribuf;
14181 ssize_t fmrilen;
14182
14183 scf_propertygroup_t *pg;
14184 scf_property_t *prop;
14185 scf_value_t *val;
14186 scf_type_t ty;
14187 int ret, result = 0;
14188 scf_iter_t *iter, *piter, *viter;
14189 char *buf, *tybuf, *pname;
14190 const char *emsg_write_error;
14191
14192
14193 emsg_write_error = gettext("Error writing temoprary file: %s.\n");
14194
14195
14196 /* select fmri */
14197 if (cur_inst != NULL) {
14198 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
14199 if (fmrilen < 0)
14200 scfdie();
14201 fmribuf = safe_malloc(fmrilen + 1);
14202 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
14203 scfdie();
14204 } else {
14205 assert(cur_svc != NULL);
14206 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
14207 if (fmrilen < 0)
14208 scfdie();
14209 fmribuf = safe_malloc(fmrilen + 1);
14210 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
14211 scfdie();
14212 }
14213
14214 if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
14215 warn(emsg_write_error, strerror(errno));
14216 free(fmribuf);
14217 return (-1);
14218 }
14219
14220 free(fmribuf);
14221
14222
14223 if ((pg = scf_pg_create(g_hndl)) == NULL ||
14224 (prop = scf_property_create(g_hndl)) == NULL ||
14225 (val = scf_value_create(g_hndl)) == NULL ||
14226 (iter = scf_iter_create(g_hndl)) == NULL ||
14227 (piter = scf_iter_create(g_hndl)) == NULL ||
14228 (viter = scf_iter_create(g_hndl)) == NULL)
14229 scfdie();
14230
14231 buf = safe_malloc(max_scf_name_len + 1);
14232 tybuf = safe_malloc(max_scf_pg_type_len + 1);
14233 pname = safe_malloc(max_scf_name_len + 1);
14234
14235 if (cur_inst != NULL)
14236 ret = scf_iter_instance_pgs(iter, cur_inst);
14237 else
14238 ret = scf_iter_service_pgs(iter, cur_svc);
14239 if (ret != SCF_SUCCESS)
14240 scfdie();
14241
14242 while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
14243 int ret2;
14244
14245 /*
14246 * # delprop pg
14247 * # addpg pg type
14248 */
14249 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
14250 scfdie();
14251
14252 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
14253 scfdie();
14254
14255 if (fprintf(strm, "# Property group \"%s\"\n"
14256 "# delprop %s\n"
14257 "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
14258 warn(emsg_write_error, strerror(errno));
14259 result = -1;
14260 goto out;
14261 }
14262
14263 /* # setprop pg/prop = (values) */
14264
14265 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
14266 scfdie();
14267
14268 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
14269 int first = 1;
14270 int ret3;
14271 int multiple;
14272 int is_str;
14273 scf_type_t bty;
14274
14275 if (scf_property_get_name(prop, pname,
14276 max_scf_name_len + 1) < 0)
14277 scfdie();
14278
14279 if (scf_property_type(prop, &ty) != 0)
14280 scfdie();
14281
14282 multiple = prop_has_multiple_values(prop, val);
14283
14284 if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
14285 pname, scf_type_to_string(ty), multiple ? "(" : "")
14286 < 0) {
14287 warn(emsg_write_error, strerror(errno));
14288 result = -1;
14289 goto out;
14290 }
14291
14292 (void) scf_type_base_type(ty, &bty);
14293 is_str = (bty == SCF_TYPE_ASTRING);
14294
14295 if (scf_iter_property_values(viter, prop) !=
14296 SCF_SUCCESS)
14297 scfdie();
14298
14299 while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
14300 char *buf;
14301 ssize_t buflen;
14302
14303 buflen = scf_value_get_as_string(val, NULL, 0);
14304 if (buflen < 0)
14305 scfdie();
14306
14307 buf = safe_malloc(buflen + 1);
14308
14309 if (scf_value_get_as_string(val, buf,
14310 buflen + 1) < 0)
14311 scfdie();
14312
14313 if (first)
14314 first = 0;
14315 else {
14316 if (putc(' ', strm) != ' ') {
14317 warn(emsg_write_error,
14318 strerror(errno));
14319 result = -1;
14320 goto out;
14321 }
14322 }
14323
14324 if ((is_str && multiple) ||
14325 strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
14326 (void) putc('"', strm);
14327 (void) quote_and_print(buf, strm, 1);
14328 (void) putc('"', strm);
14329
14330 if (ferror(strm)) {
14331 warn(emsg_write_error,
14332 strerror(errno));
14333 result = -1;
14334 goto out;
14335 }
14336 } else {
14337 if (fprintf(strm, "%s", buf) < 0) {
14338 warn(emsg_write_error,
14339 strerror(errno));
14340 result = -1;
14341 goto out;
14342 }
14343 }
14344
14345 free(buf);
14346 }
14347 if (ret3 < 0 &&
14348 scf_error() != SCF_ERROR_PERMISSION_DENIED)
14349 scfdie();
14350
14351 /* Write closing paren if mult-value property */
14352 if ((multiple && putc(')', strm) == EOF) ||
14353
14354 /* Write final newline */
14355 fputc('\n', strm) == EOF) {
14356 warn(emsg_write_error, strerror(errno));
14357 result = -1;
14358 goto out;
14359 }
14360 }
14361 if (ret2 < 0)
14362 scfdie();
14363
14364 if (fputc('\n', strm) == EOF) {
14365 warn(emsg_write_error, strerror(errno));
14366 result = -1;
14367 goto out;
14368 }
14369 }
14370 if (ret < 0)
14371 scfdie();
14372
14373 out:
14374 free(pname);
14375 free(tybuf);
14376 free(buf);
14377 scf_iter_destroy(viter);
14378 scf_iter_destroy(piter);
14379 scf_iter_destroy(iter);
14380 scf_value_destroy(val);
14381 scf_property_destroy(prop);
14382 scf_pg_destroy(pg);
14383
14384 if (result == 0) {
14385 if (fflush(strm) != 0) {
14386 warn(emsg_write_error, strerror(errno));
14387 return (-1);
14388 }
14389 }
14390
14391 return (result);
14392 }
14393
14394 int
lscf_editprop(void)14395 lscf_editprop(void)
14396 {
14397 char *buf, *editor;
14398 size_t bufsz;
14399 int tmpfd;
14400 char tempname[] = TEMP_FILE_PATTERN;
14401
14402 lscf_prep_hndl();
14403
14404 if (cur_snap != NULL) {
14405 semerr(emsg_cant_modify_snapshots);
14406 return (-1);
14407 }
14408
14409 if (cur_svc == NULL && cur_inst == NULL) {
14410 semerr(emsg_entity_not_selected);
14411 return (-1);
14412 }
14413
14414 tmpfd = mkstemp(tempname);
14415 if (tmpfd == -1) {
14416 semerr(gettext("Could not create temporary file.\n"));
14417 return (-1);
14418 }
14419
14420 (void) strcpy(tempfilename, tempname);
14421
14422 tempfile = fdopen(tmpfd, "r+");
14423 if (tempfile == NULL) {
14424 warn(gettext("Could not create temporary file.\n"));
14425 if (close(tmpfd) == -1)
14426 warn(gettext("Could not close temporary file: %s.\n"),
14427 strerror(errno));
14428
14429 remove_tempfile();
14430
14431 return (-1);
14432 }
14433
14434 if (write_edit_script(tempfile) == -1) {
14435 remove_tempfile();
14436 return (-1);
14437 }
14438
14439 editor = getenv("EDITOR");
14440 if (editor == NULL)
14441 editor = "vi";
14442
14443 bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
14444 buf = safe_malloc(bufsz);
14445
14446 if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
14447 uu_die(gettext("Error creating editor command"));
14448
14449 if (system(buf) == -1) {
14450 semerr(gettext("Could not launch editor %s: %s\n"), editor,
14451 strerror(errno));
14452 free(buf);
14453 remove_tempfile();
14454 return (-1);
14455 }
14456
14457 free(buf);
14458
14459 (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
14460
14461 remove_tempfile();
14462
14463 return (0);
14464 }
14465
14466 static void
add_string(uu_list_t * strlist,const char * str)14467 add_string(uu_list_t *strlist, const char *str)
14468 {
14469 string_list_t *elem;
14470 elem = safe_malloc(sizeof (*elem));
14471 uu_list_node_init(elem, &elem->node, string_pool);
14472 elem->str = safe_strdup(str);
14473 if (uu_list_append(strlist, elem) != 0)
14474 uu_die(gettext("libuutil error: %s\n"),
14475 uu_strerror(uu_error()));
14476 }
14477
14478 static int
remove_string(uu_list_t * strlist,const char * str)14479 remove_string(uu_list_t *strlist, const char *str)
14480 {
14481 uu_list_walk_t *elems;
14482 string_list_t *sp;
14483
14484 /*
14485 * Find the element that needs to be removed.
14486 */
14487 elems = uu_list_walk_start(strlist, UU_DEFAULT);
14488 while ((sp = uu_list_walk_next(elems)) != NULL) {
14489 if (strcmp(sp->str, str) == 0)
14490 break;
14491 }
14492 uu_list_walk_end(elems);
14493
14494 /*
14495 * Returning 1 here as the value was not found, this
14496 * might not be an error. Leave it to the caller to
14497 * decide.
14498 */
14499 if (sp == NULL) {
14500 return (1);
14501 }
14502
14503 uu_list_remove(strlist, sp);
14504
14505 free(sp->str);
14506 free(sp);
14507
14508 return (0);
14509 }
14510
14511 /*
14512 * Get all property values that don't match the given glob pattern,
14513 * if a pattern is specified.
14514 */
14515 static void
get_prop_values(scf_property_t * prop,uu_list_t * values,const char * pattern)14516 get_prop_values(scf_property_t *prop, uu_list_t *values,
14517 const char *pattern)
14518 {
14519 scf_iter_t *iter;
14520 scf_value_t *val;
14521 int ret;
14522
14523 if ((iter = scf_iter_create(g_hndl)) == NULL ||
14524 (val = scf_value_create(g_hndl)) == NULL)
14525 scfdie();
14526
14527 if (scf_iter_property_values(iter, prop) != 0)
14528 scfdie();
14529
14530 while ((ret = scf_iter_next_value(iter, val)) == 1) {
14531 char *buf;
14532 ssize_t vlen, szret;
14533
14534 vlen = scf_value_get_as_string(val, NULL, 0);
14535 if (vlen < 0)
14536 scfdie();
14537
14538 buf = safe_malloc(vlen + 1);
14539
14540 szret = scf_value_get_as_string(val, buf, vlen + 1);
14541 if (szret < 0)
14542 scfdie();
14543 assert(szret <= vlen);
14544
14545 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14546 add_string(values, buf);
14547
14548 free(buf);
14549 }
14550
14551 if (ret == -1)
14552 scfdie();
14553
14554 scf_value_destroy(val);
14555 scf_iter_destroy(iter);
14556 }
14557
14558 static int
lscf_setpropvalue(const char * pgname,const char * type,const char * arg,int isadd,int isnotfoundok)14559 lscf_setpropvalue(const char *pgname, const char *type,
14560 const char *arg, int isadd, int isnotfoundok)
14561 {
14562 scf_type_t ty;
14563 scf_propertygroup_t *pg;
14564 scf_property_t *prop;
14565 int ret, result = 0;
14566 scf_transaction_t *tx;
14567 scf_transaction_entry_t *e;
14568 scf_value_t *v;
14569 string_list_t *sp;
14570 char *propname;
14571 uu_list_t *values;
14572 uu_list_walk_t *walk;
14573 void *cookie = NULL;
14574 char *pattern = NULL;
14575
14576 lscf_prep_hndl();
14577
14578 if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14579 uu_die(gettext("Could not create property list: %s\n"),
14580 uu_strerror(uu_error()));
14581
14582 if (!isadd)
14583 pattern = safe_strdup(arg);
14584
14585 if ((e = scf_entry_create(g_hndl)) == NULL ||
14586 (pg = scf_pg_create(g_hndl)) == NULL ||
14587 (prop = scf_property_create(g_hndl)) == NULL ||
14588 (tx = scf_transaction_create(g_hndl)) == NULL)
14589 scfdie();
14590
14591 if (cur_snap != NULL) {
14592 semerr(emsg_cant_modify_snapshots);
14593 goto fail;
14594 }
14595
14596 if (cur_inst == NULL && cur_svc == NULL) {
14597 semerr(emsg_entity_not_selected);
14598 goto fail;
14599 }
14600
14601 propname = strchr(pgname, '/');
14602 if (propname == NULL) {
14603 semerr(gettext("Property names must contain a `/'.\n"));
14604 goto fail;
14605 }
14606
14607 *propname = '\0';
14608 ++propname;
14609
14610 if (type != NULL) {
14611 ty = string_to_type(type);
14612 if (ty == SCF_TYPE_INVALID) {
14613 semerr(gettext("Unknown type \"%s\".\n"), type);
14614 goto fail;
14615 }
14616 }
14617
14618 if (cur_inst != NULL)
14619 ret = scf_instance_get_pg(cur_inst, pgname, pg);
14620 else
14621 ret = scf_service_get_pg(cur_svc, pgname, pg);
14622 if (ret != 0) {
14623 switch (scf_error()) {
14624 case SCF_ERROR_NOT_FOUND:
14625 if (isnotfoundok) {
14626 result = 0;
14627 } else {
14628 semerr(emsg_no_such_pg, pgname);
14629 result = -1;
14630 }
14631 goto out;
14632
14633 case SCF_ERROR_INVALID_ARGUMENT:
14634 semerr(emsg_invalid_pg_name, pgname);
14635 goto fail;
14636
14637 default:
14638 scfdie();
14639 }
14640 }
14641
14642 do {
14643 if (scf_pg_update(pg) == -1)
14644 scfdie();
14645 if (scf_transaction_start(tx, pg) != 0) {
14646 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14647 scfdie();
14648
14649 semerr(emsg_permission_denied);
14650 goto fail;
14651 }
14652
14653 ret = scf_pg_get_property(pg, propname, prop);
14654 if (ret == 0) {
14655 scf_type_t ptype;
14656 char *pat = pattern;
14657
14658 if (scf_property_type(prop, &ptype) != 0)
14659 scfdie();
14660
14661 if (isadd) {
14662 if (type != NULL && ptype != ty) {
14663 semerr(gettext("Property \"%s\" is not "
14664 "of type \"%s\".\n"), propname,
14665 type);
14666 goto fail;
14667 }
14668
14669 pat = NULL;
14670 } else {
14671 size_t len = strlen(pat);
14672 if (len > 0 && pat[len - 1] == '\"')
14673 pat[len - 1] = '\0';
14674 if (len > 0 && pat[0] == '\"')
14675 pat++;
14676 }
14677
14678 ty = ptype;
14679
14680 get_prop_values(prop, values, pat);
14681
14682 if (isadd)
14683 add_string(values, arg);
14684
14685 if (scf_transaction_property_change(tx, e,
14686 propname, ty) == -1)
14687 scfdie();
14688 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14689 if (isadd) {
14690 if (type == NULL) {
14691 semerr(gettext("Type required "
14692 "for new properties.\n"));
14693 goto fail;
14694 }
14695
14696 add_string(values, arg);
14697
14698 if (scf_transaction_property_new(tx, e,
14699 propname, ty) == -1)
14700 scfdie();
14701 } else if (isnotfoundok) {
14702 result = 0;
14703 goto out;
14704 } else {
14705 semerr(gettext("No such property %s/%s.\n"),
14706 pgname, propname);
14707 result = -1;
14708 goto out;
14709 }
14710 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14711 semerr(emsg_invalid_prop_name, propname);
14712 goto fail;
14713 } else {
14714 scfdie();
14715 }
14716
14717 walk = uu_list_walk_start(values, UU_DEFAULT);
14718 if (walk == NULL)
14719 uu_die(gettext("Could not walk property list.\n"));
14720
14721 for (sp = uu_list_walk_next(walk); sp != NULL;
14722 sp = uu_list_walk_next(walk)) {
14723 v = string_to_value(sp->str, ty, 0);
14724
14725 if (v == NULL) {
14726 scf_entry_destroy_children(e);
14727 goto fail;
14728 }
14729 ret = scf_entry_add_value(e, v);
14730 assert(ret == 0);
14731 }
14732 uu_list_walk_end(walk);
14733
14734 result = scf_transaction_commit(tx);
14735
14736 scf_transaction_reset(tx);
14737 scf_entry_destroy_children(e);
14738 } while (result == 0);
14739
14740 if (result < 0) {
14741 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14742 scfdie();
14743
14744 semerr(emsg_permission_denied);
14745 goto fail;
14746 }
14747
14748 result = 0;
14749
14750 private_refresh();
14751
14752 out:
14753 scf_transaction_destroy(tx);
14754 scf_entry_destroy(e);
14755 scf_pg_destroy(pg);
14756 scf_property_destroy(prop);
14757 free(pattern);
14758
14759 while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14760 free(sp->str);
14761 free(sp);
14762 }
14763
14764 uu_list_destroy(values);
14765
14766 return (result);
14767
14768 fail:
14769 result = -1;
14770 goto out;
14771 }
14772
14773 int
lscf_addpropvalue(const char * pgname,const char * type,const char * value)14774 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14775 {
14776 return (lscf_setpropvalue(pgname, type, value, 1, 0));
14777 }
14778
14779 int
lscf_delpropvalue(const char * pgname,const char * pattern,int isnotfoundok)14780 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14781 {
14782 return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14783 }
14784
14785 /*
14786 * Look for a standard start method, first in the instance (if any),
14787 * then the service.
14788 */
14789 static const char *
start_method_name(int * in_instance)14790 start_method_name(int *in_instance)
14791 {
14792 scf_propertygroup_t *pg;
14793 char **p;
14794 int ret;
14795 scf_instance_t *inst = cur_inst;
14796
14797 if ((pg = scf_pg_create(g_hndl)) == NULL)
14798 scfdie();
14799
14800 again:
14801 for (p = start_method_names; *p != NULL; p++) {
14802 if (inst != NULL)
14803 ret = scf_instance_get_pg(inst, *p, pg);
14804 else
14805 ret = scf_service_get_pg(cur_svc, *p, pg);
14806
14807 if (ret == 0) {
14808 size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14809 char *buf = safe_malloc(bufsz);
14810
14811 if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14812 free(buf);
14813 continue;
14814 }
14815 if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14816 free(buf);
14817 continue;
14818 }
14819
14820 free(buf);
14821 *in_instance = (inst != NULL);
14822 scf_pg_destroy(pg);
14823 return (*p);
14824 }
14825
14826 if (scf_error() == SCF_ERROR_NOT_FOUND)
14827 continue;
14828
14829 scfdie();
14830 }
14831
14832 if (inst != NULL) {
14833 inst = NULL;
14834 goto again;
14835 }
14836
14837 scf_pg_destroy(pg);
14838 return (NULL);
14839 }
14840
14841 static int
addpg(const char * name,const char * type)14842 addpg(const char *name, const char *type)
14843 {
14844 scf_propertygroup_t *pg;
14845 int ret;
14846
14847 pg = scf_pg_create(g_hndl);
14848 if (pg == NULL)
14849 scfdie();
14850
14851 if (cur_inst != NULL)
14852 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14853 else
14854 ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14855
14856 if (ret != 0) {
14857 switch (scf_error()) {
14858 case SCF_ERROR_EXISTS:
14859 ret = 0;
14860 break;
14861
14862 case SCF_ERROR_PERMISSION_DENIED:
14863 semerr(emsg_permission_denied);
14864 break;
14865
14866 default:
14867 scfdie();
14868 }
14869 }
14870
14871 scf_pg_destroy(pg);
14872 return (ret);
14873 }
14874
14875 int
lscf_setenv(uu_list_t * args,int isunset)14876 lscf_setenv(uu_list_t *args, int isunset)
14877 {
14878 int ret = 0;
14879 size_t i;
14880 int argc;
14881 char **argv = NULL;
14882 string_list_t *slp;
14883 char *pattern;
14884 char *prop;
14885 int do_service = 0;
14886 int do_instance = 0;
14887 const char *method = NULL;
14888 const char *name = NULL;
14889 const char *value = NULL;
14890 scf_instance_t *saved_cur_inst = cur_inst;
14891
14892 lscf_prep_hndl();
14893
14894 argc = uu_list_numnodes(args);
14895 if (argc < 1)
14896 goto usage;
14897
14898 argv = calloc(argc + 1, sizeof (char *));
14899 if (argv == NULL)
14900 uu_die(gettext("Out of memory.\n"));
14901
14902 for (slp = uu_list_first(args), i = 0;
14903 slp != NULL;
14904 slp = uu_list_next(args, slp), ++i)
14905 argv[i] = slp->str;
14906
14907 argv[i] = NULL;
14908
14909 opterr = 0;
14910 optind = 0;
14911 for (;;) {
14912 ret = getopt(argc, argv, "sim:");
14913 if (ret == -1)
14914 break;
14915
14916 switch (ret) {
14917 case 's':
14918 do_service = 1;
14919 cur_inst = NULL;
14920 break;
14921
14922 case 'i':
14923 do_instance = 1;
14924 break;
14925
14926 case 'm':
14927 method = optarg;
14928 break;
14929
14930 case '?':
14931 goto usage;
14932
14933 default:
14934 bad_error("getopt", ret);
14935 }
14936 }
14937
14938 argc -= optind;
14939 if ((do_service && do_instance) ||
14940 (isunset && argc != 1) ||
14941 (!isunset && argc != 2))
14942 goto usage;
14943
14944 name = argv[optind];
14945 if (!isunset)
14946 value = argv[optind + 1];
14947
14948 if (cur_snap != NULL) {
14949 semerr(emsg_cant_modify_snapshots);
14950 ret = -1;
14951 goto out;
14952 }
14953
14954 if (cur_inst == NULL && cur_svc == NULL) {
14955 semerr(emsg_entity_not_selected);
14956 ret = -1;
14957 goto out;
14958 }
14959
14960 if (do_instance && cur_inst == NULL) {
14961 semerr(gettext("No instance is selected.\n"));
14962 ret = -1;
14963 goto out;
14964 }
14965
14966 if (do_service && cur_svc == NULL) {
14967 semerr(gettext("No service is selected.\n"));
14968 ret = -1;
14969 goto out;
14970 }
14971
14972 if (method == NULL) {
14973 if (do_instance || do_service) {
14974 method = "method_context";
14975 if (!isunset) {
14976 ret = addpg("method_context",
14977 SCF_GROUP_FRAMEWORK);
14978 if (ret != 0)
14979 goto out;
14980 }
14981 } else {
14982 int in_instance;
14983 method = start_method_name(&in_instance);
14984 if (method == NULL) {
14985 semerr(gettext(
14986 "Couldn't find start method; please "
14987 "specify a method with '-m'.\n"));
14988 ret = -1;
14989 goto out;
14990 }
14991 if (!in_instance)
14992 cur_inst = NULL;
14993 }
14994 } else {
14995 scf_propertygroup_t *pg;
14996 size_t bufsz;
14997 char *buf;
14998 int ret;
14999
15000 if ((pg = scf_pg_create(g_hndl)) == NULL)
15001 scfdie();
15002
15003 if (cur_inst != NULL)
15004 ret = scf_instance_get_pg(cur_inst, method, pg);
15005 else
15006 ret = scf_service_get_pg(cur_svc, method, pg);
15007
15008 if (ret != 0) {
15009 scf_pg_destroy(pg);
15010 switch (scf_error()) {
15011 case SCF_ERROR_NOT_FOUND:
15012 semerr(gettext("Couldn't find the method "
15013 "\"%s\".\n"), method);
15014 goto out;
15015
15016 case SCF_ERROR_INVALID_ARGUMENT:
15017 semerr(gettext("Invalid method name \"%s\".\n"),
15018 method);
15019 goto out;
15020
15021 default:
15022 scfdie();
15023 }
15024 }
15025
15026 bufsz = strlen(SCF_GROUP_METHOD) + 1;
15027 buf = safe_malloc(bufsz);
15028
15029 if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
15030 strcmp(buf, SCF_GROUP_METHOD) != 0) {
15031 semerr(gettext("Property group \"%s\" is not of type "
15032 "\"method\".\n"), method);
15033 ret = -1;
15034 free(buf);
15035 scf_pg_destroy(pg);
15036 goto out;
15037 }
15038
15039 free(buf);
15040 scf_pg_destroy(pg);
15041 }
15042
15043 prop = uu_msprintf("%s/environment", method);
15044 pattern = uu_msprintf("%s=*", name);
15045
15046 if (prop == NULL || pattern == NULL)
15047 uu_die(gettext("Out of memory.\n"));
15048
15049 ret = lscf_delpropvalue(prop, pattern, !isunset);
15050
15051 if (ret == 0 && !isunset) {
15052 uu_free(pattern);
15053 uu_free(prop);
15054 prop = uu_msprintf("%s/environment", method);
15055 pattern = uu_msprintf("%s=%s", name, value);
15056 if (prop == NULL || pattern == NULL)
15057 uu_die(gettext("Out of memory.\n"));
15058 ret = lscf_addpropvalue(prop, "astring:", pattern);
15059 }
15060 uu_free(pattern);
15061 uu_free(prop);
15062
15063 out:
15064 cur_inst = saved_cur_inst;
15065
15066 free(argv);
15067 return (ret);
15068 usage:
15069 ret = -2;
15070 goto out;
15071 }
15072
15073 /*
15074 * Snapshot commands
15075 */
15076
15077 void
lscf_listsnap()15078 lscf_listsnap()
15079 {
15080 scf_snapshot_t *snap;
15081 scf_iter_t *iter;
15082 char *nb;
15083 int r;
15084
15085 lscf_prep_hndl();
15086
15087 if (cur_inst == NULL) {
15088 semerr(gettext("Instance not selected.\n"));
15089 return;
15090 }
15091
15092 if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15093 (iter = scf_iter_create(g_hndl)) == NULL)
15094 scfdie();
15095
15096 if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
15097 scfdie();
15098
15099 nb = safe_malloc(max_scf_name_len + 1);
15100
15101 while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
15102 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
15103 scfdie();
15104
15105 (void) puts(nb);
15106 }
15107 if (r < 0)
15108 scfdie();
15109
15110 free(nb);
15111 scf_iter_destroy(iter);
15112 scf_snapshot_destroy(snap);
15113 }
15114
15115 void
lscf_selectsnap(const char * name)15116 lscf_selectsnap(const char *name)
15117 {
15118 scf_snapshot_t *snap;
15119 scf_snaplevel_t *level;
15120
15121 lscf_prep_hndl();
15122
15123 if (cur_inst == NULL) {
15124 semerr(gettext("Instance not selected.\n"));
15125 return;
15126 }
15127
15128 if (cur_snap != NULL) {
15129 if (name != NULL) {
15130 char *cur_snap_name;
15131 boolean_t nochange;
15132
15133 cur_snap_name = safe_malloc(max_scf_name_len + 1);
15134
15135 if (scf_snapshot_get_name(cur_snap, cur_snap_name,
15136 max_scf_name_len + 1) < 0)
15137 scfdie();
15138
15139 nochange = strcmp(name, cur_snap_name) == 0;
15140
15141 free(cur_snap_name);
15142
15143 if (nochange)
15144 return;
15145 }
15146
15147 unselect_cursnap();
15148 }
15149
15150 if (name == NULL)
15151 return;
15152
15153 if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15154 (level = scf_snaplevel_create(g_hndl)) == NULL)
15155 scfdie();
15156
15157 if (scf_instance_get_snapshot(cur_inst, name, snap) !=
15158 SCF_SUCCESS) {
15159 switch (scf_error()) {
15160 case SCF_ERROR_INVALID_ARGUMENT:
15161 semerr(gettext("Invalid name \"%s\".\n"), name);
15162 break;
15163
15164 case SCF_ERROR_NOT_FOUND:
15165 semerr(gettext("No such snapshot \"%s\".\n"), name);
15166 break;
15167
15168 default:
15169 scfdie();
15170 }
15171
15172 scf_snaplevel_destroy(level);
15173 scf_snapshot_destroy(snap);
15174 return;
15175 }
15176
15177 /* Load the snaplevels into our list. */
15178 cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
15179 if (cur_levels == NULL)
15180 uu_die(gettext("Could not create list: %s\n"),
15181 uu_strerror(uu_error()));
15182
15183 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15184 if (scf_error() != SCF_ERROR_NOT_FOUND)
15185 scfdie();
15186
15187 semerr(gettext("Snapshot has no snaplevels.\n"));
15188
15189 scf_snaplevel_destroy(level);
15190 scf_snapshot_destroy(snap);
15191 return;
15192 }
15193
15194 cur_snap = snap;
15195
15196 for (;;) {
15197 cur_elt = safe_malloc(sizeof (*cur_elt));
15198 uu_list_node_init(cur_elt, &cur_elt->list_node,
15199 snaplevel_pool);
15200 cur_elt->sl = level;
15201 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
15202 uu_die(gettext("libuutil error: %s\n"),
15203 uu_strerror(uu_error()));
15204
15205 level = scf_snaplevel_create(g_hndl);
15206 if (level == NULL)
15207 scfdie();
15208
15209 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
15210 level) != SCF_SUCCESS) {
15211 if (scf_error() != SCF_ERROR_NOT_FOUND)
15212 scfdie();
15213
15214 scf_snaplevel_destroy(level);
15215 break;
15216 }
15217 }
15218
15219 cur_elt = uu_list_last(cur_levels);
15220 cur_level = cur_elt->sl;
15221 }
15222
15223 /*
15224 * Copies the properties & values in src to dst. Assumes src won't change.
15225 * Returns -1 if permission is denied, -2 if another transaction interrupts,
15226 * and 0 on success.
15227 *
15228 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
15229 * property, if it is copied and has type boolean. (See comment in
15230 * lscf_revert()).
15231 */
15232 static int
pg_copy(const scf_propertygroup_t * src,scf_propertygroup_t * dst,uint8_t enabled)15233 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
15234 uint8_t enabled)
15235 {
15236 scf_transaction_t *tx;
15237 scf_iter_t *iter, *viter;
15238 scf_property_t *prop;
15239 scf_value_t *v;
15240 char *nbuf;
15241 int r;
15242
15243 tx = scf_transaction_create(g_hndl);
15244 if (tx == NULL)
15245 scfdie();
15246
15247 if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
15248 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15249 scfdie();
15250
15251 scf_transaction_destroy(tx);
15252
15253 return (-1);
15254 }
15255
15256 if ((iter = scf_iter_create(g_hndl)) == NULL ||
15257 (prop = scf_property_create(g_hndl)) == NULL ||
15258 (viter = scf_iter_create(g_hndl)) == NULL)
15259 scfdie();
15260
15261 nbuf = safe_malloc(max_scf_name_len + 1);
15262
15263 if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
15264 scfdie();
15265
15266 for (;;) {
15267 scf_transaction_entry_t *e;
15268 scf_type_t ty;
15269
15270 r = scf_iter_next_property(iter, prop);
15271 if (r == -1)
15272 scfdie();
15273 if (r == 0)
15274 break;
15275
15276 e = scf_entry_create(g_hndl);
15277 if (e == NULL)
15278 scfdie();
15279
15280 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
15281 scfdie();
15282
15283 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
15284 scfdie();
15285
15286 if (scf_transaction_property_new(tx, e, nbuf,
15287 ty) != SCF_SUCCESS)
15288 scfdie();
15289
15290 if ((enabled == 0 || enabled == 1) &&
15291 strcmp(nbuf, scf_property_enabled) == 0 &&
15292 ty == SCF_TYPE_BOOLEAN) {
15293 v = scf_value_create(g_hndl);
15294 if (v == NULL)
15295 scfdie();
15296
15297 scf_value_set_boolean(v, enabled);
15298
15299 if (scf_entry_add_value(e, v) != 0)
15300 scfdie();
15301 } else {
15302 if (scf_iter_property_values(viter, prop) != 0)
15303 scfdie();
15304
15305 for (;;) {
15306 v = scf_value_create(g_hndl);
15307 if (v == NULL)
15308 scfdie();
15309
15310 r = scf_iter_next_value(viter, v);
15311 if (r == -1)
15312 scfdie();
15313 if (r == 0) {
15314 scf_value_destroy(v);
15315 break;
15316 }
15317
15318 if (scf_entry_add_value(e, v) != SCF_SUCCESS)
15319 scfdie();
15320 }
15321 }
15322 }
15323
15324 free(nbuf);
15325 scf_iter_destroy(viter);
15326 scf_property_destroy(prop);
15327 scf_iter_destroy(iter);
15328
15329 r = scf_transaction_commit(tx);
15330 if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
15331 scfdie();
15332
15333 scf_transaction_destroy_children(tx);
15334 scf_transaction_destroy(tx);
15335
15336 switch (r) {
15337 case 1: return (0);
15338 case 0: return (-2);
15339 case -1: return (-1);
15340
15341 default:
15342 abort();
15343 }
15344
15345 /* NOTREACHED */
15346 }
15347
15348 void
lscf_revert(const char * snapname)15349 lscf_revert(const char *snapname)
15350 {
15351 scf_snapshot_t *snap, *prev;
15352 scf_snaplevel_t *level, *nlevel;
15353 scf_iter_t *iter;
15354 scf_propertygroup_t *pg, *npg;
15355 scf_property_t *prop;
15356 scf_value_t *val;
15357 char *nbuf, *tbuf;
15358 uint8_t enabled;
15359
15360 lscf_prep_hndl();
15361
15362 if (cur_inst == NULL) {
15363 semerr(gettext("Instance not selected.\n"));
15364 return;
15365 }
15366
15367 if (snapname != NULL) {
15368 snap = scf_snapshot_create(g_hndl);
15369 if (snap == NULL)
15370 scfdie();
15371
15372 if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
15373 SCF_SUCCESS) {
15374 switch (scf_error()) {
15375 case SCF_ERROR_INVALID_ARGUMENT:
15376 semerr(gettext("Invalid snapshot name "
15377 "\"%s\".\n"), snapname);
15378 break;
15379
15380 case SCF_ERROR_NOT_FOUND:
15381 semerr(gettext("No such snapshot.\n"));
15382 break;
15383
15384 default:
15385 scfdie();
15386 }
15387
15388 scf_snapshot_destroy(snap);
15389 return;
15390 }
15391 } else {
15392 if (cur_snap != NULL) {
15393 snap = cur_snap;
15394 } else {
15395 semerr(gettext("No snapshot selected.\n"));
15396 return;
15397 }
15398 }
15399
15400 if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
15401 (level = scf_snaplevel_create(g_hndl)) == NULL ||
15402 (iter = scf_iter_create(g_hndl)) == NULL ||
15403 (pg = scf_pg_create(g_hndl)) == NULL ||
15404 (npg = scf_pg_create(g_hndl)) == NULL ||
15405 (prop = scf_property_create(g_hndl)) == NULL ||
15406 (val = scf_value_create(g_hndl)) == NULL)
15407 scfdie();
15408
15409 nbuf = safe_malloc(max_scf_name_len + 1);
15410 tbuf = safe_malloc(max_scf_pg_type_len + 1);
15411
15412 /* Take the "previous" snapshot before we blow away the properties. */
15413 if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
15414 if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
15415 scfdie();
15416 } else {
15417 if (scf_error() != SCF_ERROR_NOT_FOUND)
15418 scfdie();
15419
15420 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
15421 scfdie();
15422 }
15423
15424 /* Save general/enabled, since we're probably going to replace it. */
15425 enabled = 2;
15426 if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
15427 scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
15428 scf_property_get_value(prop, val) == 0)
15429 (void) scf_value_get_boolean(val, &enabled);
15430
15431 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15432 if (scf_error() != SCF_ERROR_NOT_FOUND)
15433 scfdie();
15434
15435 goto out;
15436 }
15437
15438 for (;;) {
15439 boolean_t isinst;
15440 uint32_t flags;
15441 int r;
15442
15443 /* Clear the properties from the corresponding entity. */
15444 isinst = snaplevel_is_instance(level);
15445
15446 if (!isinst)
15447 r = scf_iter_service_pgs(iter, cur_svc);
15448 else
15449 r = scf_iter_instance_pgs(iter, cur_inst);
15450 if (r != SCF_SUCCESS)
15451 scfdie();
15452
15453 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15454 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15455 scfdie();
15456
15457 /* Skip nonpersistent pgs. */
15458 if (flags & SCF_PG_FLAG_NONPERSISTENT)
15459 continue;
15460
15461 if (scf_pg_delete(pg) != SCF_SUCCESS) {
15462 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15463 scfdie();
15464
15465 semerr(emsg_permission_denied);
15466 goto out;
15467 }
15468 }
15469 if (r == -1)
15470 scfdie();
15471
15472 /* Copy the properties to the corresponding entity. */
15473 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
15474 scfdie();
15475
15476 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15477 if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
15478 scfdie();
15479
15480 if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
15481 0)
15482 scfdie();
15483
15484 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15485 scfdie();
15486
15487 if (!isinst)
15488 r = scf_service_add_pg(cur_svc, nbuf, tbuf,
15489 flags, npg);
15490 else
15491 r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
15492 flags, npg);
15493 if (r != SCF_SUCCESS) {
15494 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15495 scfdie();
15496
15497 semerr(emsg_permission_denied);
15498 goto out;
15499 }
15500
15501 if ((enabled == 0 || enabled == 1) &&
15502 strcmp(nbuf, scf_pg_general) == 0)
15503 r = pg_copy(pg, npg, enabled);
15504 else
15505 r = pg_copy(pg, npg, 2);
15506
15507 switch (r) {
15508 case 0:
15509 break;
15510
15511 case -1:
15512 semerr(emsg_permission_denied);
15513 goto out;
15514
15515 case -2:
15516 semerr(gettext(
15517 "Interrupted by another change.\n"));
15518 goto out;
15519
15520 default:
15521 abort();
15522 }
15523 }
15524 if (r == -1)
15525 scfdie();
15526
15527 /* Get next level. */
15528 nlevel = scf_snaplevel_create(g_hndl);
15529 if (nlevel == NULL)
15530 scfdie();
15531
15532 if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
15533 SCF_SUCCESS) {
15534 if (scf_error() != SCF_ERROR_NOT_FOUND)
15535 scfdie();
15536
15537 scf_snaplevel_destroy(nlevel);
15538 break;
15539 }
15540
15541 scf_snaplevel_destroy(level);
15542 level = nlevel;
15543 }
15544
15545 if (snapname == NULL) {
15546 lscf_selectsnap(NULL);
15547 snap = NULL; /* cur_snap has been destroyed */
15548 }
15549
15550 out:
15551 free(tbuf);
15552 free(nbuf);
15553 scf_value_destroy(val);
15554 scf_property_destroy(prop);
15555 scf_pg_destroy(npg);
15556 scf_pg_destroy(pg);
15557 scf_iter_destroy(iter);
15558 scf_snaplevel_destroy(level);
15559 scf_snapshot_destroy(prev);
15560 if (snap != cur_snap)
15561 scf_snapshot_destroy(snap);
15562 }
15563
15564 void
lscf_refresh(void)15565 lscf_refresh(void)
15566 {
15567 ssize_t fmrilen;
15568 size_t bufsz;
15569 char *fmribuf;
15570 int r;
15571
15572 lscf_prep_hndl();
15573
15574 if (cur_inst == NULL) {
15575 semerr(gettext("Instance not selected.\n"));
15576 return;
15577 }
15578
15579 bufsz = max_scf_fmri_len + 1;
15580 fmribuf = safe_malloc(bufsz);
15581 fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15582 if (fmrilen < 0) {
15583 free(fmribuf);
15584 if (scf_error() != SCF_ERROR_DELETED)
15585 scfdie();
15586 scf_instance_destroy(cur_inst);
15587 cur_inst = NULL;
15588 warn(emsg_deleted);
15589 return;
15590 }
15591 assert(fmrilen < bufsz);
15592
15593 r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15594 switch (r) {
15595 case 0:
15596 break;
15597
15598 case ECONNABORTED:
15599 warn(gettext("Could not refresh %s "
15600 "(repository connection broken).\n"), fmribuf);
15601 break;
15602
15603 case ECANCELED:
15604 warn(emsg_deleted);
15605 break;
15606
15607 case EPERM:
15608 warn(gettext("Could not refresh %s "
15609 "(permission denied).\n"), fmribuf);
15610 break;
15611
15612 case ENOSPC:
15613 warn(gettext("Could not refresh %s "
15614 "(repository server out of resources).\n"),
15615 fmribuf);
15616 break;
15617
15618 case EACCES:
15619 default:
15620 bad_error("refresh_entity", scf_error());
15621 }
15622
15623 free(fmribuf);
15624 }
15625
15626 /*
15627 * describe [-v] [-t] [pg/prop]
15628 */
15629 int
lscf_describe(uu_list_t * args,int hasargs)15630 lscf_describe(uu_list_t *args, int hasargs)
15631 {
15632 int ret = 0;
15633 size_t i;
15634 int argc;
15635 char **argv = NULL;
15636 string_list_t *slp;
15637 int do_verbose = 0;
15638 int do_templates = 0;
15639 char *pattern = NULL;
15640
15641 lscf_prep_hndl();
15642
15643 if (hasargs != 0) {
15644 argc = uu_list_numnodes(args);
15645 if (argc < 1)
15646 goto usage;
15647
15648 argv = calloc(argc + 1, sizeof (char *));
15649 if (argv == NULL)
15650 uu_die(gettext("Out of memory.\n"));
15651
15652 for (slp = uu_list_first(args), i = 0;
15653 slp != NULL;
15654 slp = uu_list_next(args, slp), ++i)
15655 argv[i] = slp->str;
15656
15657 argv[i] = NULL;
15658
15659 /*
15660 * We start optind = 0 because our list of arguments
15661 * starts at argv[0]
15662 */
15663 optind = 0;
15664 opterr = 0;
15665 for (;;) {
15666 ret = getopt(argc, argv, "vt");
15667 if (ret == -1)
15668 break;
15669
15670 switch (ret) {
15671 case 'v':
15672 do_verbose = 1;
15673 break;
15674
15675 case 't':
15676 do_templates = 1;
15677 break;
15678
15679 case '?':
15680 goto usage;
15681
15682 default:
15683 bad_error("getopt", ret);
15684 }
15685 }
15686
15687 pattern = argv[optind];
15688 }
15689
15690 if (cur_inst == NULL && cur_svc == NULL) {
15691 semerr(emsg_entity_not_selected);
15692 ret = -1;
15693 goto out;
15694 }
15695
15696 /*
15697 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15698 * output if their last parameter is set to 2. Less information is
15699 * produced if the parameter is set to 1.
15700 */
15701 if (pattern == NULL) {
15702 if (do_verbose == 1)
15703 list_entity_tmpl(2);
15704 else
15705 list_entity_tmpl(1);
15706 }
15707
15708 if (do_templates == 0) {
15709 if (do_verbose == 1)
15710 listprop(pattern, 0, 2);
15711 else
15712 listprop(pattern, 0, 1);
15713 } else {
15714 if (do_verbose == 1)
15715 listtmpl(pattern, 2);
15716 else
15717 listtmpl(pattern, 1);
15718 }
15719
15720 ret = 0;
15721 out:
15722 if (argv != NULL)
15723 free(argv);
15724 return (ret);
15725 usage:
15726 ret = -2;
15727 goto out;
15728 }
15729
15730 #define PARAM_ACTIVE ((const char *) "active")
15731 #define PARAM_INACTIVE ((const char *) "inactive")
15732 #define PARAM_SMTP_TO ((const char *) "to")
15733
15734 /*
15735 * tokenize()
15736 * Breaks down the string according to the tokens passed.
15737 * Caller is responsible for freeing array of pointers returned.
15738 * Returns NULL on failure
15739 */
15740 char **
tokenize(char * str,const char * sep)15741 tokenize(char *str, const char *sep)
15742 {
15743 char *token, *lasts;
15744 char **buf;
15745 int n = 0; /* number of elements */
15746 int size = 8; /* size of the array (initial) */
15747
15748 buf = safe_malloc(size * sizeof (char *));
15749
15750 for (token = strtok_r(str, sep, &lasts); token != NULL;
15751 token = strtok_r(NULL, sep, &lasts), ++n) {
15752 if (n + 1 >= size) {
15753 size *= 2;
15754 if ((buf = realloc(buf, size * sizeof (char *))) ==
15755 NULL) {
15756 uu_die(gettext("Out of memory"));
15757 }
15758 }
15759 buf[n] = token;
15760 }
15761 /* NULL terminate the pointer array */
15762 buf[n] = NULL;
15763
15764 return (buf);
15765 }
15766
15767 int32_t
check_tokens(char ** p)15768 check_tokens(char **p)
15769 {
15770 int32_t smf = 0;
15771 int32_t fma = 0;
15772
15773 while (*p) {
15774 int32_t t = string_to_tset(*p);
15775
15776 if (t == 0) {
15777 if (is_fma_token(*p) == 0)
15778 return (INVALID_TOKENS);
15779 fma = 1; /* this token is an fma event */
15780 } else {
15781 smf |= t;
15782 }
15783
15784 if (smf != 0 && fma == 1)
15785 return (MIXED_TOKENS);
15786 ++p;
15787 }
15788
15789 if (smf > 0)
15790 return (smf);
15791 else if (fma == 1)
15792 return (FMA_TOKENS);
15793
15794 return (INVALID_TOKENS);
15795 }
15796
15797 static int
get_selection_str(char * fmri,size_t sz)15798 get_selection_str(char *fmri, size_t sz)
15799 {
15800 if (g_hndl == NULL) {
15801 semerr(emsg_entity_not_selected);
15802 return (-1);
15803 } else if (cur_level != NULL) {
15804 semerr(emsg_invalid_for_snapshot);
15805 return (-1);
15806 } else {
15807 lscf_get_selection_str(fmri, sz);
15808 }
15809
15810 return (0);
15811 }
15812
15813 void
lscf_delnotify(const char * set,int global)15814 lscf_delnotify(const char *set, int global)
15815 {
15816 char *str = strdup(set);
15817 char **pgs;
15818 char **p;
15819 int32_t tset;
15820 char *fmri = NULL;
15821
15822 if (str == NULL)
15823 uu_die(gettext("Out of memory.\n"));
15824
15825 pgs = tokenize(str, ",");
15826
15827 if ((tset = check_tokens(pgs)) > 0) {
15828 size_t sz = max_scf_fmri_len + 1;
15829
15830 fmri = safe_malloc(sz);
15831 if (global) {
15832 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15833 } else if (get_selection_str(fmri, sz) != 0) {
15834 goto out;
15835 }
15836
15837 if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri,
15838 tset) != SCF_SUCCESS) {
15839 uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15840 scf_strerror(scf_error()));
15841 }
15842 } else if (tset == FMA_TOKENS) {
15843 if (global) {
15844 semerr(gettext("Can't use option '-g' with FMA event "
15845 "definitions\n"));
15846 goto out;
15847 }
15848
15849 for (p = pgs; *p; ++p) {
15850 if (smf_notify_del_params(de_tag(*p), NULL, 0) !=
15851 SCF_SUCCESS) {
15852 uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
15853 scf_strerror(scf_error()));
15854 goto out;
15855 }
15856 }
15857 } else if (tset == MIXED_TOKENS) {
15858 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15859 goto out;
15860 } else {
15861 uu_die(gettext("Invalid input.\n"));
15862 }
15863
15864 out:
15865 free(fmri);
15866 free(pgs);
15867 free(str);
15868 }
15869
15870 void
lscf_listnotify(const char * set,int global)15871 lscf_listnotify(const char *set, int global)
15872 {
15873 char *str = safe_strdup(set);
15874 char **pgs;
15875 char **p;
15876 int32_t tset;
15877 nvlist_t *nvl;
15878 char *fmri = NULL;
15879
15880 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
15881 uu_die(gettext("Out of memory.\n"));
15882
15883 pgs = tokenize(str, ",");
15884
15885 if ((tset = check_tokens(pgs)) > 0) {
15886 size_t sz = max_scf_fmri_len + 1;
15887
15888 fmri = safe_malloc(sz);
15889 if (global) {
15890 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15891 } else if (get_selection_str(fmri, sz) != 0) {
15892 goto out;
15893 }
15894
15895 if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
15896 SCF_SUCCESS) {
15897 if (scf_error() != SCF_ERROR_NOT_FOUND &&
15898 scf_error() != SCF_ERROR_DELETED)
15899 uu_warn(gettext(
15900 "Failed listnotify: %s\n"),
15901 scf_strerror(scf_error()));
15902 goto out;
15903 }
15904
15905 listnotify_print(nvl, NULL);
15906 } else if (tset == FMA_TOKENS) {
15907 if (global) {
15908 semerr(gettext("Can't use option '-g' with FMA event "
15909 "definitions\n"));
15910 goto out;
15911 }
15912
15913 for (p = pgs; *p; ++p) {
15914 if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
15915 SCF_SUCCESS) {
15916 /*
15917 * if the preferences have just been deleted
15918 * or does not exist, just skip.
15919 */
15920 if (scf_error() == SCF_ERROR_NOT_FOUND ||
15921 scf_error() == SCF_ERROR_DELETED)
15922 continue;
15923 uu_warn(gettext(
15924 "Failed listnotify: %s\n"),
15925 scf_strerror(scf_error()));
15926 goto out;
15927 }
15928 listnotify_print(nvl, re_tag(*p));
15929 }
15930 } else if (tset == MIXED_TOKENS) {
15931 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15932 goto out;
15933 } else {
15934 semerr(gettext("Invalid input.\n"));
15935 }
15936
15937 out:
15938 nvlist_free(nvl);
15939 free(fmri);
15940 free(pgs);
15941 free(str);
15942 }
15943
15944 static char *
strip_quotes_and_blanks(char * s)15945 strip_quotes_and_blanks(char *s)
15946 {
15947 char *start = s;
15948 char *end = strrchr(s, '\"');
15949
15950 if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
15951 start = s + 1;
15952 while (isblank(*start))
15953 start++;
15954 while (isblank(*(end - 1)) && end > start) {
15955 end--;
15956 }
15957 *end = '\0';
15958 }
15959
15960 return (start);
15961 }
15962
15963 static int
set_active(nvlist_t * mech,const char * hier_part)15964 set_active(nvlist_t *mech, const char *hier_part)
15965 {
15966 boolean_t b;
15967
15968 if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
15969 b = B_TRUE;
15970 } else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
15971 b = B_FALSE;
15972 } else {
15973 return (-1);
15974 }
15975
15976 if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
15977 uu_die(gettext("Out of memory.\n"));
15978
15979 return (0);
15980 }
15981
15982 static int
add_snmp_params(nvlist_t * mech,char * hier_part)15983 add_snmp_params(nvlist_t *mech, char *hier_part)
15984 {
15985 return (set_active(mech, hier_part));
15986 }
15987
15988 static int
add_syslog_params(nvlist_t * mech,char * hier_part)15989 add_syslog_params(nvlist_t *mech, char *hier_part)
15990 {
15991 return (set_active(mech, hier_part));
15992 }
15993
15994 /*
15995 * add_mailto_paramas()
15996 * parse the hier_part of mailto URI
15997 * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
15998 * or mailto:{[active]|inactive}
15999 */
16000 static int
add_mailto_params(nvlist_t * mech,char * hier_part)16001 add_mailto_params(nvlist_t *mech, char *hier_part)
16002 {
16003 const char *tok = "?&";
16004 char *p;
16005 char *lasts;
16006 char *param;
16007 char *val;
16008
16009 /*
16010 * If the notification parametes are in the form of
16011 *
16012 * malito:{[active]|inactive}
16013 *
16014 * we set the property accordingly and return.
16015 * Otherwise, we make the notification type active and
16016 * process the hier_part.
16017 */
16018 if (set_active(mech, hier_part) == 0)
16019 return (0);
16020 else if (set_active(mech, PARAM_ACTIVE) != 0)
16021 return (-1);
16022
16023 if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) {
16024 /*
16025 * sanity check: we only get here if hier_part = "", but
16026 * that's handled by set_active
16027 */
16028 uu_die("strtok_r");
16029 }
16030
16031 if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0)
16032 uu_die(gettext("Out of memory.\n"));
16033
16034 while ((p = strtok_r(NULL, tok, &lasts)) != NULL)
16035 if ((param = strtok_r(p, "=", &val)) != NULL)
16036 if (nvlist_add_string(mech, param, val) != 0)
16037 uu_die(gettext("Out of memory.\n"));
16038
16039 return (0);
16040 }
16041
16042 static int
uri_split(char * uri,char ** scheme,char ** hier_part)16043 uri_split(char *uri, char **scheme, char **hier_part)
16044 {
16045 int r = -1;
16046
16047 if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
16048 *hier_part == NULL) {
16049 semerr(gettext("'%s' is not an URI\n"), uri);
16050 return (r);
16051 }
16052
16053 if ((r = check_uri_scheme(*scheme)) < 0) {
16054 semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
16055 return (r);
16056 }
16057
16058 return (r);
16059 }
16060
16061 static int
process_uri(nvlist_t * params,char * uri)16062 process_uri(nvlist_t *params, char *uri)
16063 {
16064 char *scheme;
16065 char *hier_part;
16066 nvlist_t *mech;
16067 int index;
16068 int r;
16069
16070 if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
16071 return (-1);
16072
16073 if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
16074 uu_die(gettext("Out of memory.\n"));
16075
16076 switch (index) {
16077 case 0:
16078 /* error messages displayed by called function */
16079 r = add_mailto_params(mech, hier_part);
16080 break;
16081
16082 case 1:
16083 if ((r = add_snmp_params(mech, hier_part)) != 0)
16084 semerr(gettext("Not valid parameters: '%s'\n"),
16085 hier_part);
16086 break;
16087
16088 case 2:
16089 if ((r = add_syslog_params(mech, hier_part)) != 0)
16090 semerr(gettext("Not valid parameters: '%s'\n"),
16091 hier_part);
16092 break;
16093
16094 default:
16095 r = -1;
16096 }
16097
16098 if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
16099 mech) != 0)
16100 uu_die(gettext("Out of memory.\n"));
16101
16102 nvlist_free(mech);
16103 return (r);
16104 }
16105
16106 static int
set_params(nvlist_t * params,char ** p)16107 set_params(nvlist_t *params, char **p)
16108 {
16109 char *uri;
16110
16111 if (p == NULL)
16112 /* sanity check */
16113 uu_die("set_params");
16114
16115 while (*p) {
16116 uri = strip_quotes_and_blanks(*p);
16117 if (process_uri(params, uri) != 0)
16118 return (-1);
16119
16120 ++p;
16121 }
16122
16123 return (0);
16124 }
16125
16126 static int
setnotify(const char * e,char ** p,int global)16127 setnotify(const char *e, char **p, int global)
16128 {
16129 char *str = safe_strdup(e);
16130 char **events;
16131 int32_t tset;
16132 int r = -1;
16133 nvlist_t *nvl, *params;
16134 char *fmri = NULL;
16135
16136 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
16137 nvlist_alloc(¶ms, NV_UNIQUE_NAME, 0) != 0 ||
16138 nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
16139 SCF_NOTIFY_PARAMS_VERSION) != 0)
16140 uu_die(gettext("Out of memory.\n"));
16141
16142 events = tokenize(str, ",");
16143
16144 if ((tset = check_tokens(events)) > 0) {
16145 /* SMF state transitions parameters */
16146 size_t sz = max_scf_fmri_len + 1;
16147
16148 fmri = safe_malloc(sz);
16149 if (global) {
16150 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
16151 } else if (get_selection_str(fmri, sz) != 0) {
16152 goto out;
16153 }
16154
16155 if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 ||
16156 nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0)
16157 uu_die(gettext("Out of memory.\n"));
16158
16159 if ((r = set_params(params, p)) == 0) {
16160 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS,
16161 params) != 0)
16162 uu_die(gettext("Out of memory.\n"));
16163
16164 if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
16165 nvl) != SCF_SUCCESS) {
16166 r = -1;
16167 uu_warn(gettext(
16168 "Failed smf_notify_set_params(3SCF): %s\n"),
16169 scf_strerror(scf_error()));
16170 }
16171 }
16172 } else if (tset == FMA_TOKENS) {
16173 /* FMA event parameters */
16174 if (global) {
16175 semerr(gettext("Can't use option '-g' with FMA event "
16176 "definitions\n"));
16177 goto out;
16178 }
16179
16180 if ((r = set_params(params, p)) != 0)
16181 goto out;
16182
16183 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
16184 uu_die(gettext("Out of memory.\n"));
16185
16186 while (*events) {
16187 if (smf_notify_set_params(de_tag(*events), nvl) !=
16188 SCF_SUCCESS)
16189 uu_warn(gettext(
16190 "Failed smf_notify_set_params(3SCF) for "
16191 "event %s: %s\n"), *events,
16192 scf_strerror(scf_error()));
16193 events++;
16194 }
16195 } else if (tset == MIXED_TOKENS) {
16196 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
16197 } else {
16198 /* Sanity check */
16199 uu_die(gettext("Invalid input.\n"));
16200 }
16201
16202 out:
16203 nvlist_free(nvl);
16204 nvlist_free(params);
16205 free(fmri);
16206 free(str);
16207
16208 return (r);
16209 }
16210
16211 int
lscf_setnotify(uu_list_t * args)16212 lscf_setnotify(uu_list_t *args)
16213 {
16214 int argc;
16215 char **argv = NULL;
16216 string_list_t *slp;
16217 int global;
16218 char *events;
16219 char **p;
16220 int i;
16221 int ret;
16222
16223 if ((argc = uu_list_numnodes(args)) < 2)
16224 goto usage;
16225
16226 argv = calloc(argc + 1, sizeof (char *));
16227 if (argv == NULL)
16228 uu_die(gettext("Out of memory.\n"));
16229
16230 for (slp = uu_list_first(args), i = 0;
16231 slp != NULL;
16232 slp = uu_list_next(args, slp), ++i)
16233 argv[i] = slp->str;
16234
16235 argv[i] = NULL;
16236
16237 if (strcmp(argv[0], "-g") == 0) {
16238 global = 1;
16239 events = argv[1];
16240 p = argv + 2;
16241 } else {
16242 global = 0;
16243 events = argv[0];
16244 p = argv + 1;
16245 }
16246
16247 ret = setnotify(events, p, global);
16248
16249 out:
16250 free(argv);
16251 return (ret);
16252
16253 usage:
16254 ret = -2;
16255 goto out;
16256 }
16257
16258 /*
16259 * Creates a list of instance name strings associated with a service. If
16260 * wohandcrafted flag is set, get only instances that have a last-import
16261 * snapshot, instances that were imported via svccfg.
16262 */
16263 static uu_list_t *
create_instance_list(scf_service_t * svc,int wohandcrafted)16264 create_instance_list(scf_service_t *svc, int wohandcrafted)
16265 {
16266 scf_snapshot_t *snap = NULL;
16267 scf_instance_t *inst;
16268 scf_iter_t *inst_iter;
16269 uu_list_t *instances;
16270 char *instname = NULL;
16271 int r;
16272
16273 inst_iter = scf_iter_create(g_hndl);
16274 inst = scf_instance_create(g_hndl);
16275 if (inst_iter == NULL || inst == NULL) {
16276 uu_warn(gettext("Could not create instance or iterator\n"));
16277 scfdie();
16278 }
16279
16280 if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
16281 return (instances);
16282
16283 if (scf_iter_service_instances(inst_iter, svc) != 0) {
16284 switch (scf_error()) {
16285 case SCF_ERROR_CONNECTION_BROKEN:
16286 case SCF_ERROR_DELETED:
16287 uu_list_destroy(instances);
16288 instances = NULL;
16289 goto out;
16290
16291 case SCF_ERROR_HANDLE_MISMATCH:
16292 case SCF_ERROR_NOT_BOUND:
16293 case SCF_ERROR_NOT_SET:
16294 default:
16295 bad_error("scf_iter_service_instances", scf_error());
16296 }
16297 }
16298
16299 instname = safe_malloc(max_scf_name_len + 1);
16300 while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
16301 if (r == -1) {
16302 (void) uu_warn(gettext("Unable to iterate through "
16303 "instances to create instance list : %s\n"),
16304 scf_strerror(scf_error()));
16305
16306 uu_list_destroy(instances);
16307 instances = NULL;
16308 goto out;
16309 }
16310
16311 /*
16312 * If the instance does not have a last-import snapshot
16313 * then do not add it to the list as it is a hand-crafted
16314 * instance that should not be managed.
16315 */
16316 if (wohandcrafted) {
16317 if (snap == NULL &&
16318 (snap = scf_snapshot_create(g_hndl)) == NULL) {
16319 uu_warn(gettext("Unable to create snapshot "
16320 "entity\n"));
16321 scfdie();
16322 }
16323
16324 if (scf_instance_get_snapshot(inst,
16325 snap_lastimport, snap) != 0) {
16326 switch (scf_error()) {
16327 case SCF_ERROR_NOT_FOUND :
16328 case SCF_ERROR_DELETED:
16329 continue;
16330
16331 case SCF_ERROR_CONNECTION_BROKEN:
16332 uu_list_destroy(instances);
16333 instances = NULL;
16334 goto out;
16335
16336 case SCF_ERROR_HANDLE_MISMATCH:
16337 case SCF_ERROR_NOT_BOUND:
16338 case SCF_ERROR_NOT_SET:
16339 default:
16340 bad_error("scf_iter_service_instances",
16341 scf_error());
16342 }
16343 }
16344 }
16345
16346 if (scf_instance_get_name(inst, instname,
16347 max_scf_name_len + 1) < 0) {
16348 switch (scf_error()) {
16349 case SCF_ERROR_NOT_FOUND :
16350 continue;
16351
16352 case SCF_ERROR_CONNECTION_BROKEN:
16353 case SCF_ERROR_DELETED:
16354 uu_list_destroy(instances);
16355 instances = NULL;
16356 goto out;
16357
16358 case SCF_ERROR_HANDLE_MISMATCH:
16359 case SCF_ERROR_NOT_BOUND:
16360 case SCF_ERROR_NOT_SET:
16361 default:
16362 bad_error("scf_iter_service_instances",
16363 scf_error());
16364 }
16365 }
16366
16367 add_string(instances, instname);
16368 }
16369
16370 out:
16371 if (snap)
16372 scf_snapshot_destroy(snap);
16373
16374 scf_instance_destroy(inst);
16375 scf_iter_destroy(inst_iter);
16376 free(instname);
16377 return (instances);
16378 }
16379
16380 /*
16381 * disable an instance but wait for the instance to
16382 * move out of the running state.
16383 *
16384 * Returns 0 : if the instance did not disable
16385 * Returns non-zero : if the instance disabled.
16386 *
16387 */
16388 static int
disable_instance(scf_instance_t * instance)16389 disable_instance(scf_instance_t *instance)
16390 {
16391 char *fmribuf;
16392 int enabled = 10000;
16393
16394 if (inst_is_running(instance)) {
16395 fmribuf = safe_malloc(max_scf_name_len + 1);
16396 if (scf_instance_to_fmri(instance, fmribuf,
16397 max_scf_name_len + 1) < 0) {
16398 free(fmribuf);
16399 return (0);
16400 }
16401
16402 /*
16403 * If the instance cannot be disabled then return
16404 * failure to disable and let the caller decide
16405 * if that is of importance.
16406 */
16407 if (smf_disable_instance(fmribuf, 0) != 0) {
16408 free(fmribuf);
16409 return (0);
16410 }
16411
16412 while (enabled) {
16413 if (!inst_is_running(instance))
16414 break;
16415
16416 (void) poll(NULL, 0, 5);
16417 enabled = enabled - 5;
16418 }
16419
16420 free(fmribuf);
16421 }
16422
16423 return (enabled);
16424 }
16425
16426 /*
16427 * Function to compare two service_manifest structures.
16428 */
16429 /* ARGSUSED2 */
16430 static int
service_manifest_compare(const void * left,const void * right,void * unused)16431 service_manifest_compare(const void *left, const void *right, void *unused)
16432 {
16433 service_manifest_t *l = (service_manifest_t *)left;
16434 service_manifest_t *r = (service_manifest_t *)right;
16435 int rc;
16436
16437 rc = strcmp(l->servicename, r->servicename);
16438
16439 return (rc);
16440 }
16441
16442 /*
16443 * Look for the provided service in the service to manifest
16444 * tree. If the service exists, and a manifest was provided
16445 * then add the manifest to that service. If the service
16446 * does not exist, then add the service and manifest to the
16447 * list.
16448 *
16449 * If the manifest is NULL, return the element if found. If
16450 * the service is not found return NULL.
16451 */
16452 service_manifest_t *
find_add_svc_mfst(const char * svnbuf,const char * mfst)16453 find_add_svc_mfst(const char *svnbuf, const char *mfst)
16454 {
16455 service_manifest_t elem;
16456 service_manifest_t *fnelem;
16457 uu_avl_index_t marker;
16458
16459 elem.servicename = svnbuf;
16460 fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
16461
16462 if (mfst) {
16463 if (fnelem) {
16464 add_string(fnelem->mfstlist, strdup(mfst));
16465 } else {
16466 fnelem = safe_malloc(sizeof (*fnelem));
16467 fnelem->servicename = safe_strdup(svnbuf);
16468 if ((fnelem->mfstlist =
16469 uu_list_create(string_pool, NULL, 0)) == NULL)
16470 uu_die(gettext("Could not create property "
16471 "list: %s\n"), uu_strerror(uu_error()));
16472
16473 add_string(fnelem->mfstlist, safe_strdup(mfst));
16474
16475 uu_avl_insert(service_manifest_tree, fnelem, marker);
16476 }
16477 }
16478
16479 return (fnelem);
16480 }
16481
16482 /*
16483 * Create the service to manifest avl tree.
16484 *
16485 * Walk each of the manifests currently installed in the supported
16486 * directories, /lib/svc/manifest and /var/svc/manifest. For
16487 * each of the manifests, inventory the services and add them to
16488 * the tree.
16489 *
16490 * Code that calls this function should make sure fileystem/minimal is online,
16491 * /var is available, since this function walks the /var/svc/manifest directory.
16492 */
16493 static void
create_manifest_tree(void)16494 create_manifest_tree(void)
16495 {
16496 manifest_info_t **entry;
16497 manifest_info_t **manifests;
16498 uu_list_walk_t *svcs;
16499 bundle_t *b;
16500 entity_t *mfsvc;
16501 char *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
16502 int c, status;
16503
16504 if (service_manifest_pool)
16505 return;
16506
16507 /*
16508 * Create the list pool for the service manifest list
16509 */
16510 service_manifest_pool = uu_avl_pool_create("service_manifest",
16511 sizeof (service_manifest_t),
16512 offsetof(service_manifest_t, svcmfst_node),
16513 service_manifest_compare, UU_DEFAULT);
16514 if (service_manifest_pool == NULL)
16515 uu_die(gettext("service_manifest pool creation failed: %s\n"),
16516 uu_strerror(uu_error()));
16517
16518 /*
16519 * Create the list
16520 */
16521 service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
16522 UU_DEFAULT);
16523 if (service_manifest_tree == NULL)
16524 uu_die(gettext("service_manifest tree creation failed: %s\n"),
16525 uu_strerror(uu_error()));
16526
16527 /*
16528 * Walk the manifests adding the service(s) from each manifest.
16529 *
16530 * If a service already exists add the manifest to the manifest
16531 * list for that service. This covers the case of a service that
16532 * is supported by multiple manifest files.
16533 */
16534 for (c = 0; dirs[c]; c++) {
16535 status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT);
16536 if (status < 0) {
16537 uu_warn(gettext("file tree walk of %s encountered "
16538 "error %s\n"), dirs[c], strerror(errno));
16539
16540 uu_avl_destroy(service_manifest_tree);
16541 service_manifest_tree = NULL;
16542 return;
16543 }
16544
16545 /*
16546 * If a manifest that was in the list is not found
16547 * then skip and go to the next manifest file.
16548 */
16549 if (manifests != NULL) {
16550 for (entry = manifests; *entry != NULL; entry++) {
16551 b = internal_bundle_new();
16552 if (lxml_get_bundle_file(b, (*entry)->mi_path,
16553 SVCCFG_OP_IMPORT) != 0) {
16554 internal_bundle_free(b);
16555 continue;
16556 }
16557
16558 svcs = uu_list_walk_start(b->sc_bundle_services,
16559 0);
16560 if (svcs == NULL) {
16561 internal_bundle_free(b);
16562 continue;
16563 }
16564
16565 while ((mfsvc = uu_list_walk_next(svcs)) !=
16566 NULL) {
16567 /* Add manifest to service */
16568 (void) find_add_svc_mfst(mfsvc->sc_name,
16569 (*entry)->mi_path);
16570 }
16571
16572 uu_list_walk_end(svcs);
16573 internal_bundle_free(b);
16574 }
16575
16576 free_manifest_array(manifests);
16577 }
16578 }
16579 }
16580
16581 /*
16582 * Check the manifest history file to see
16583 * if the service was ever installed from
16584 * one of the supported directories.
16585 *
16586 * Return Values :
16587 * -1 - if there's error reading manifest history file
16588 * 1 - if the service is not found
16589 * 0 - if the service is found
16590 */
16591 static int
check_mfst_history(const char * svcname)16592 check_mfst_history(const char *svcname)
16593 {
16594 struct stat st;
16595 caddr_t mfsthist_start;
16596 char *svnbuf;
16597 int fd;
16598 int r = 1;
16599
16600 fd = open(MFSTHISTFILE, O_RDONLY);
16601 if (fd == -1) {
16602 uu_warn(gettext("Unable to open the history file\n"));
16603 return (-1);
16604 }
16605
16606 if (fstat(fd, &st) == -1) {
16607 uu_warn(gettext("Unable to stat the history file\n"));
16608 return (-1);
16609 }
16610
16611 mfsthist_start = mmap(0, st.st_size, PROT_READ,
16612 MAP_PRIVATE, fd, 0);
16613
16614 (void) close(fd);
16615 if (mfsthist_start == MAP_FAILED ||
16616 *(mfsthist_start + st.st_size) != '\0') {
16617 (void) munmap(mfsthist_start, st.st_size);
16618 return (-1);
16619 }
16620
16621 /*
16622 * The manifest history file is a space delimited list
16623 * of service and instance to manifest linkage. Adding
16624 * a space to the end of the service name so to get only
16625 * the service that is being searched for.
16626 */
16627 svnbuf = uu_msprintf("%s ", svcname);
16628 if (svnbuf == NULL)
16629 uu_die(gettext("Out of memory"));
16630
16631 if (strstr(mfsthist_start, svnbuf) != NULL)
16632 r = 0;
16633
16634 (void) munmap(mfsthist_start, st.st_size);
16635 uu_free(svnbuf);
16636 return (r);
16637 }
16638
16639 /*
16640 * Take down each of the instances in the service
16641 * and remove them, then delete the service.
16642 */
16643 static void
teardown_service(scf_service_t * svc,const char * svnbuf)16644 teardown_service(scf_service_t *svc, const char *svnbuf)
16645 {
16646 scf_instance_t *instance;
16647 scf_iter_t *iter;
16648 int r;
16649
16650 safe_printf(gettext("Delete service %s as there are no "
16651 "supporting manifests\n"), svnbuf);
16652
16653 instance = scf_instance_create(g_hndl);
16654 iter = scf_iter_create(g_hndl);
16655 if (iter == NULL || instance == NULL) {
16656 uu_warn(gettext("Unable to create supporting entities to "
16657 "teardown the service\n"));
16658 uu_warn(gettext("scf error is : %s\n"),
16659 scf_strerror(scf_error()));
16660 scfdie();
16661 }
16662
16663 if (scf_iter_service_instances(iter, svc) != 0) {
16664 switch (scf_error()) {
16665 case SCF_ERROR_CONNECTION_BROKEN:
16666 case SCF_ERROR_DELETED:
16667 goto out;
16668
16669 case SCF_ERROR_HANDLE_MISMATCH:
16670 case SCF_ERROR_NOT_BOUND:
16671 case SCF_ERROR_NOT_SET:
16672 default:
16673 bad_error("scf_iter_service_instances",
16674 scf_error());
16675 }
16676 }
16677
16678 while ((r = scf_iter_next_instance(iter, instance)) != 0) {
16679 if (r == -1) {
16680 uu_warn(gettext("Error - %s\n"),
16681 scf_strerror(scf_error()));
16682 goto out;
16683 }
16684
16685 (void) disable_instance(instance);
16686 }
16687
16688 /*
16689 * Delete the service... forcing the deletion in case
16690 * any of the instances did not disable.
16691 */
16692 (void) lscf_service_delete(svc, 1);
16693 out:
16694 scf_instance_destroy(instance);
16695 scf_iter_destroy(iter);
16696 }
16697
16698 /*
16699 * Get the list of instances supported by the manifest
16700 * file.
16701 *
16702 * Return 0 if there are no instances.
16703 *
16704 * Return -1 if there are errors attempting to collect instances.
16705 *
16706 * Return the count of instances found if there are no errors.
16707 *
16708 */
16709 static int
check_instance_support(char * mfstfile,const char * svcname,uu_list_t * instances)16710 check_instance_support(char *mfstfile, const char *svcname,
16711 uu_list_t *instances)
16712 {
16713 uu_list_walk_t *svcs, *insts;
16714 uu_list_t *ilist;
16715 bundle_t *b;
16716 entity_t *mfsvc, *mfinst;
16717 const char *svcn;
16718 int rminstcnt = 0;
16719
16720
16721 b = internal_bundle_new();
16722
16723 if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
16724 /*
16725 * Unable to process the manifest file for
16726 * instance support, so just return as
16727 * don't want to remove instances that could
16728 * not be accounted for that might exist here.
16729 */
16730 internal_bundle_free(b);
16731 return (0);
16732 }
16733
16734 svcs = uu_list_walk_start(b->sc_bundle_services, 0);
16735 if (svcs == NULL) {
16736 internal_bundle_free(b);
16737 return (0);
16738 }
16739
16740 svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
16741 (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
16742
16743 while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
16744 if (strcmp(mfsvc->sc_name, svcn) == 0)
16745 break;
16746 }
16747 uu_list_walk_end(svcs);
16748
16749 if (mfsvc == NULL) {
16750 internal_bundle_free(b);
16751 return (-1);
16752 }
16753
16754 ilist = mfsvc->sc_u.sc_service.sc_service_instances;
16755 if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
16756 internal_bundle_free(b);
16757 return (0);
16758 }
16759
16760 while ((mfinst = uu_list_walk_next(insts)) != NULL) {
16761 /*
16762 * Remove the instance from the instances list.
16763 * The unaccounted for instances will be removed
16764 * from the service once all manifests are
16765 * processed.
16766 */
16767 (void) remove_string(instances,
16768 mfinst->sc_name);
16769 rminstcnt++;
16770 }
16771
16772 uu_list_walk_end(insts);
16773 internal_bundle_free(b);
16774
16775 return (rminstcnt);
16776 }
16777
16778 /*
16779 * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16780 * 'false' to indicate there's no manifest file(s) found for the service.
16781 */
16782 static void
svc_add_no_support(scf_service_t * svc)16783 svc_add_no_support(scf_service_t *svc)
16784 {
16785 char *pname;
16786
16787 /* Add no support */
16788 cur_svc = svc;
16789 if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
16790 return;
16791
16792 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
16793 if (pname == NULL)
16794 uu_die(gettext("Out of memory.\n"));
16795
16796 (void) lscf_addpropvalue(pname, "boolean:", "0");
16797
16798 uu_free(pname);
16799 cur_svc = NULL;
16800 }
16801
16802 /*
16803 * This function handles all upgrade scenarios for a service that doesn't have
16804 * SCF_PG_MANIFESTFILES pg. The function creates and populates
16805 * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16806 * manifest(s) mapping. Manifests under supported directories are inventoried
16807 * and a property is added for each file that delivers configuration to the
16808 * service. A service that has no corresponding manifest files (deleted) are
16809 * removed from repository.
16810 *
16811 * Unsupported services:
16812 *
16813 * A service is considered unsupported if there is no corresponding manifest
16814 * in the supported directories for that service and the service isn't in the
16815 * history file list. The history file, MFSTHISTFILE, contains a list of all
16816 * services and instances that were delivered by Solaris before the introduction
16817 * of the SCF_PG_MANIFESTFILES property group. The history file also contains
16818 * the path to the manifest file that defined the service or instance.
16819 *
16820 * Another type of unsupported services is 'handcrafted' services,
16821 * programmatically created services or services created by dependent entries
16822 * in other manifests. A handcrafted service is identified by its lack of any
16823 * instance containing last-import snapshot which is created during svccfg
16824 * import.
16825 *
16826 * This function sets a flag for unsupported services by setting services'
16827 * SCF_PG_MANIFESTFILES/support property to false.
16828 */
16829 static void
upgrade_svc_mfst_connection(scf_service_t * svc,const char * svcname)16830 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
16831 {
16832 service_manifest_t *elem;
16833 uu_list_walk_t *mfwalk;
16834 string_list_t *mfile;
16835 uu_list_t *instances;
16836 const char *sname;
16837 char *pname;
16838 int r;
16839
16840 /*
16841 * Since there's no guarantee manifests under /var are available during
16842 * early import, don't perform any upgrade during early import.
16843 */
16844 if (IGNORE_VAR)
16845 return;
16846
16847 if (service_manifest_tree == NULL) {
16848 create_manifest_tree();
16849 }
16850
16851 /*
16852 * Find service's supporting manifest(s) after
16853 * stripping off the svc:/ prefix that is part
16854 * of the fmri that is not used in the service
16855 * manifest bundle list.
16856 */
16857 sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
16858 strlen(SCF_FMRI_SERVICE_PREFIX);
16859 elem = find_add_svc_mfst(sname, NULL);
16860 if (elem == NULL) {
16861
16862 /*
16863 * A handcrafted service, one that has no instance containing
16864 * last-import snapshot, should get unsupported flag.
16865 */
16866 instances = create_instance_list(svc, 1);
16867 if (instances == NULL) {
16868 uu_warn(gettext("Unable to create instance list %s\n"),
16869 svcname);
16870 return;
16871 }
16872
16873 if (uu_list_numnodes(instances) == 0) {
16874 svc_add_no_support(svc);
16875 return;
16876 }
16877
16878 /*
16879 * If the service is in the history file, and its supporting
16880 * manifests are not found, we can safely delete the service
16881 * because its manifests are removed from the system.
16882 *
16883 * Services not found in the history file are not delivered by
16884 * Solaris and/or delivered outside supported directories, set
16885 * unsupported flag for these services.
16886 */
16887 r = check_mfst_history(svcname);
16888 if (r == -1)
16889 return;
16890
16891 if (r) {
16892 /* Set unsupported flag for service */
16893 svc_add_no_support(svc);
16894 } else {
16895 /* Delete the service */
16896 teardown_service(svc, svcname);
16897 }
16898
16899 return;
16900 }
16901
16902 /*
16903 * Walk through the list of manifests and add them
16904 * to the service.
16905 *
16906 * Create a manifestfiles pg and add the property.
16907 */
16908 mfwalk = uu_list_walk_start(elem->mfstlist, 0);
16909 if (mfwalk == NULL)
16910 return;
16911
16912 cur_svc = svc;
16913 r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
16914 if (r != 0) {
16915 cur_svc = NULL;
16916 return;
16917 }
16918
16919 while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
16920 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16921 mhash_filename_to_propname(mfile->str, 0));
16922 if (pname == NULL)
16923 uu_die(gettext("Out of memory.\n"));
16924
16925 (void) lscf_addpropvalue(pname, "astring:", mfile->str);
16926 uu_free(pname);
16927 }
16928 uu_list_walk_end(mfwalk);
16929
16930 cur_svc = NULL;
16931 }
16932
16933 /*
16934 * Take a service and process the manifest file entires to see if
16935 * there is continued support for the service and instances. If
16936 * not cleanup as appropriate.
16937 *
16938 * If a service does not have a manifest files entry flag it for
16939 * upgrade and return.
16940 *
16941 * For each manifestfiles property check if the manifest file is
16942 * under the supported /lib/svc/manifest or /var/svc/manifest path
16943 * and if not then return immediately as this service is not supported
16944 * by the cleanup mechanism and should be ignored.
16945 *
16946 * For each manifest file that is supported, check to see if the
16947 * file exists. If not then remove the manifest file property
16948 * from the service and the smf/manifest hash table. If the manifest
16949 * file exists then verify that it supports the instances that are
16950 * part of the service.
16951 *
16952 * Once all manifest files have been accounted for remove any instances
16953 * that are no longer supported in the service.
16954 *
16955 * Return values :
16956 * 0 - Successfully processed the service
16957 * non-zero - failed to process the service
16958 *
16959 * On most errors, will just return to wait and get the next service,
16960 * unless in case of unable to create the needed structures which is
16961 * most likely a fatal error that is not going to be recoverable.
16962 */
16963 int
lscf_service_cleanup(void * act,scf_walkinfo_t * wip)16964 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
16965 {
16966 struct mpg_mfile *mpntov = NULL;
16967 struct mpg_mfile **mpvarry = NULL;
16968 scf_service_t *svc;
16969 scf_propertygroup_t *mpg;
16970 scf_property_t *mp;
16971 scf_value_t *mv;
16972 scf_iter_t *mi;
16973 scf_instance_t *instance;
16974 uu_list_walk_t *insts;
16975 uu_list_t *instances = NULL;
16976 boolean_t activity = (boolean_t)act;
16977 char *mpnbuf = NULL;
16978 char *mpvbuf = NULL;
16979 char *pgpropbuf;
16980 int mfstcnt, rminstct, instct, mfstmax;
16981 int index;
16982 int r = 0;
16983
16984 assert(g_hndl != NULL);
16985 assert(wip->svc != NULL);
16986 assert(wip->fmri != NULL);
16987
16988 svc = wip->svc;
16989
16990 mpg = scf_pg_create(g_hndl);
16991 mp = scf_property_create(g_hndl);
16992 mi = scf_iter_create(g_hndl);
16993 mv = scf_value_create(g_hndl);
16994 instance = scf_instance_create(g_hndl);
16995
16996 if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
16997 instance == NULL) {
16998 uu_warn(gettext("Unable to create the supporting entities\n"));
16999 uu_warn(gettext("scf error is : %s\n"),
17000 scf_strerror(scf_error()));
17001 scfdie();
17002 }
17003
17004 /*
17005 * Get the manifestfiles property group to be parsed for
17006 * files existence.
17007 */
17008 if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
17009 switch (scf_error()) {
17010 case SCF_ERROR_NOT_FOUND:
17011 upgrade_svc_mfst_connection(svc, wip->fmri);
17012 break;
17013 case SCF_ERROR_DELETED:
17014 case SCF_ERROR_CONNECTION_BROKEN:
17015 goto out;
17016
17017 case SCF_ERROR_HANDLE_MISMATCH:
17018 case SCF_ERROR_NOT_BOUND:
17019 case SCF_ERROR_NOT_SET:
17020 default:
17021 bad_error("scf_iter_pg_properties",
17022 scf_error());
17023 }
17024
17025 goto out;
17026 }
17027
17028 /*
17029 * Iterate through each of the manifestfiles properties
17030 * to determine what manifestfiles are available.
17031 *
17032 * If a manifest file is supported then increment the
17033 * count and therefore the service is safe.
17034 */
17035 if (scf_iter_pg_properties(mi, mpg) != 0) {
17036 switch (scf_error()) {
17037 case SCF_ERROR_DELETED:
17038 case SCF_ERROR_CONNECTION_BROKEN:
17039 goto out;
17040
17041 case SCF_ERROR_HANDLE_MISMATCH:
17042 case SCF_ERROR_NOT_BOUND:
17043 case SCF_ERROR_NOT_SET:
17044 default:
17045 bad_error("scf_iter_pg_properties",
17046 scf_error());
17047 }
17048 }
17049
17050 mfstcnt = 0;
17051 mfstmax = MFSTFILE_MAX;
17052 mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
17053 while ((r = scf_iter_next_property(mi, mp)) != 0) {
17054 if (r == -1)
17055 bad_error(gettext("Unable to iterate through "
17056 "manifestfiles properties : %s"),
17057 scf_error());
17058
17059 mpntov = safe_malloc(sizeof (struct mpg_mfile));
17060 mpnbuf = safe_malloc(max_scf_name_len + 1);
17061 mpvbuf = safe_malloc(max_scf_value_len + 1);
17062 mpntov->mpg = mpnbuf;
17063 mpntov->mfile = mpvbuf;
17064 mpntov->access = 1;
17065 if (scf_property_get_name(mp, mpnbuf,
17066 max_scf_name_len + 1) < 0) {
17067 uu_warn(gettext("Unable to get manifest file "
17068 "property : %s\n"),
17069 scf_strerror(scf_error()));
17070
17071 switch (scf_error()) {
17072 case SCF_ERROR_DELETED:
17073 case SCF_ERROR_CONNECTION_BROKEN:
17074 r = scferror2errno(scf_error());
17075 goto out_free;
17076
17077 case SCF_ERROR_HANDLE_MISMATCH:
17078 case SCF_ERROR_NOT_BOUND:
17079 case SCF_ERROR_NOT_SET:
17080 default:
17081 bad_error("scf_iter_pg_properties",
17082 scf_error());
17083 }
17084 }
17085
17086 /*
17087 * The support property is a boolean value that indicates
17088 * if the service is supported for manifest file deletion.
17089 * Currently at this time there is no code that sets this
17090 * value to true. So while we could just let this be caught
17091 * by the support check below, in the future this by be set
17092 * to true and require processing. So for that, go ahead
17093 * and check here, and just return if false. Otherwise,
17094 * fall through expecting that other support checks will
17095 * handle the entries.
17096 */
17097 if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
17098 uint8_t support;
17099
17100 if (scf_property_get_value(mp, mv) != 0 ||
17101 scf_value_get_boolean(mv, &support) != 0) {
17102 uu_warn(gettext("Unable to get the manifest "
17103 "support value: %s\n"),
17104 scf_strerror(scf_error()));
17105
17106 switch (scf_error()) {
17107 case SCF_ERROR_DELETED:
17108 case SCF_ERROR_CONNECTION_BROKEN:
17109 r = scferror2errno(scf_error());
17110 goto out_free;
17111
17112 case SCF_ERROR_HANDLE_MISMATCH:
17113 case SCF_ERROR_NOT_BOUND:
17114 case SCF_ERROR_NOT_SET:
17115 default:
17116 bad_error("scf_iter_pg_properties",
17117 scf_error());
17118 }
17119 }
17120
17121 if (support == B_FALSE)
17122 goto out_free;
17123 }
17124
17125 /*
17126 * Anything with a manifest outside of the supported
17127 * directories, immediately bail out because that makes
17128 * this service non-supported. We don't even want
17129 * to do instance processing in this case because the
17130 * instances could be part of the non-supported manifest.
17131 */
17132 if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
17133 /*
17134 * Manifest is not in /lib/svc, so we need to
17135 * consider the /var/svc case.
17136 */
17137 if (strncmp(mpnbuf, VARSVC_PR,
17138 strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
17139 /*
17140 * Either the manifest is not in /var/svc or
17141 * /var is not yet mounted. We ignore the
17142 * manifest either because it is not in a
17143 * standard location or because we cannot
17144 * currently access the manifest.
17145 */
17146 goto out_free;
17147 }
17148 }
17149
17150 /*
17151 * Get the value to of the manifest file for this entry
17152 * for access verification and instance support
17153 * verification if it still exists.
17154 *
17155 * During Early Manifest Import if the manifest is in
17156 * /var/svc then it may not yet be available for checking
17157 * so we must determine if /var/svc is available. If not
17158 * then defer until Late Manifest Import to cleanup.
17159 */
17160 if (scf_property_get_value(mp, mv) != 0) {
17161 uu_warn(gettext("Unable to get the manifest file "
17162 "value: %s\n"),
17163 scf_strerror(scf_error()));
17164
17165 switch (scf_error()) {
17166 case SCF_ERROR_DELETED:
17167 case SCF_ERROR_CONNECTION_BROKEN:
17168 r = scferror2errno(scf_error());
17169 goto out_free;
17170
17171 case SCF_ERROR_HANDLE_MISMATCH:
17172 case SCF_ERROR_NOT_BOUND:
17173 case SCF_ERROR_NOT_SET:
17174 default:
17175 bad_error("scf_property_get_value",
17176 scf_error());
17177 }
17178 }
17179
17180 if (scf_value_get_astring(mv, mpvbuf,
17181 max_scf_value_len + 1) < 0) {
17182 uu_warn(gettext("Unable to get the manifest "
17183 "file : %s\n"),
17184 scf_strerror(scf_error()));
17185
17186 switch (scf_error()) {
17187 case SCF_ERROR_DELETED:
17188 case SCF_ERROR_CONNECTION_BROKEN:
17189 r = scferror2errno(scf_error());
17190 goto out_free;
17191
17192 case SCF_ERROR_HANDLE_MISMATCH:
17193 case SCF_ERROR_NOT_BOUND:
17194 case SCF_ERROR_NOT_SET:
17195 default:
17196 bad_error("scf_value_get_astring",
17197 scf_error());
17198 }
17199 }
17200
17201 mpvarry[mfstcnt] = mpntov;
17202 mfstcnt++;
17203
17204 /*
17205 * Check for the need to reallocate array
17206 */
17207 if (mfstcnt >= (mfstmax - 1)) {
17208 struct mpg_mfile **newmpvarry;
17209
17210 mfstmax = mfstmax * 2;
17211 newmpvarry = realloc(mpvarry,
17212 sizeof (struct mpg_mfile *) * mfstmax);
17213
17214 if (newmpvarry == NULL)
17215 goto out_free;
17216
17217 mpvarry = newmpvarry;
17218 }
17219
17220 mpvarry[mfstcnt] = NULL;
17221 }
17222
17223 for (index = 0; mpvarry[index]; index++) {
17224 mpntov = mpvarry[index];
17225
17226 /*
17227 * Check to see if the manifestfile is accessable, if so hand
17228 * this service and manifestfile off to be processed for
17229 * instance support.
17230 */
17231 mpnbuf = mpntov->mpg;
17232 mpvbuf = mpntov->mfile;
17233 if (access(mpvbuf, F_OK) != 0) {
17234 mpntov->access = 0;
17235 activity++;
17236 mfstcnt--;
17237 /* Remove the entry from the service */
17238 cur_svc = svc;
17239 pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
17240 mpnbuf);
17241 if (pgpropbuf == NULL)
17242 uu_die(gettext("Out of memory.\n"));
17243
17244 lscf_delprop(pgpropbuf);
17245 cur_svc = NULL;
17246
17247 uu_free(pgpropbuf);
17248 }
17249 }
17250
17251 /*
17252 * If mfstcnt is 0, none of the manifests that supported the service
17253 * existed so remove the service.
17254 */
17255 if (mfstcnt == 0) {
17256 teardown_service(svc, wip->fmri);
17257
17258 goto out_free;
17259 }
17260
17261 if (activity) {
17262 int nosvcsupport = 0;
17263
17264 /*
17265 * If the list of service instances is NULL then
17266 * create the list.
17267 */
17268 instances = create_instance_list(svc, 1);
17269 if (instances == NULL) {
17270 uu_warn(gettext("Unable to create instance list %s\n"),
17271 wip->fmri);
17272 goto out_free;
17273 }
17274
17275 rminstct = uu_list_numnodes(instances);
17276 instct = rminstct;
17277
17278 for (index = 0; mpvarry[index]; index++) {
17279 mpntov = mpvarry[index];
17280 if (mpntov->access == 0)
17281 continue;
17282
17283 mpnbuf = mpntov->mpg;
17284 mpvbuf = mpntov->mfile;
17285 r = check_instance_support(mpvbuf, wip->fmri,
17286 instances);
17287 if (r == -1) {
17288 nosvcsupport++;
17289 } else {
17290 rminstct -= r;
17291 }
17292 }
17293
17294 if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
17295 teardown_service(svc, wip->fmri);
17296
17297 goto out_free;
17298 }
17299 }
17300
17301 /*
17302 * If there are instances left on the instance list, then
17303 * we must remove them.
17304 */
17305 if (instances != NULL && uu_list_numnodes(instances)) {
17306 string_list_t *sp;
17307
17308 insts = uu_list_walk_start(instances, 0);
17309 while ((sp = uu_list_walk_next(insts)) != NULL) {
17310 /*
17311 * Remove the instance from the instances list.
17312 */
17313 safe_printf(gettext("Delete instance %s from "
17314 "service %s\n"), sp->str, wip->fmri);
17315 if (scf_service_get_instance(svc, sp->str,
17316 instance) != SCF_SUCCESS) {
17317 (void) uu_warn("scf_error - %s\n",
17318 scf_strerror(scf_error()));
17319
17320 continue;
17321 }
17322
17323 (void) disable_instance(instance);
17324
17325 (void) lscf_instance_delete(instance, 1);
17326 }
17327 scf_instance_destroy(instance);
17328 uu_list_walk_end(insts);
17329 }
17330
17331 out_free:
17332 if (mpvarry) {
17333 struct mpg_mfile *fmpntov;
17334
17335 for (index = 0; mpvarry[index]; index++) {
17336 fmpntov = mpvarry[index];
17337 if (fmpntov->mpg == mpnbuf)
17338 mpnbuf = NULL;
17339 free(fmpntov->mpg);
17340
17341 if (fmpntov->mfile == mpvbuf)
17342 mpvbuf = NULL;
17343 free(fmpntov->mfile);
17344
17345 if (fmpntov == mpntov)
17346 mpntov = NULL;
17347 free(fmpntov);
17348 }
17349 if (mpnbuf)
17350 free(mpnbuf);
17351 if (mpvbuf)
17352 free(mpvbuf);
17353 if (mpntov)
17354 free(mpntov);
17355
17356 free(mpvarry);
17357 }
17358 out:
17359 scf_pg_destroy(mpg);
17360 scf_property_destroy(mp);
17361 scf_iter_destroy(mi);
17362 scf_value_destroy(mv);
17363
17364 return (0);
17365 }
17366
17367 /*
17368 * Take the service and search for the manifestfiles property
17369 * in each of the property groups. If the manifest file
17370 * associated with the property does not exist then remove
17371 * the property group.
17372 */
17373 int
lscf_hash_cleanup()17374 lscf_hash_cleanup()
17375 {
17376 scf_service_t *svc;
17377 scf_scope_t *scope;
17378 scf_propertygroup_t *pg;
17379 scf_property_t *prop;
17380 scf_value_t *val;
17381 scf_iter_t *iter;
17382 char *pgname = NULL;
17383 char *mfile = NULL;
17384 int r;
17385
17386 svc = scf_service_create(g_hndl);
17387 scope = scf_scope_create(g_hndl);
17388 pg = scf_pg_create(g_hndl);
17389 prop = scf_property_create(g_hndl);
17390 val = scf_value_create(g_hndl);
17391 iter = scf_iter_create(g_hndl);
17392 if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
17393 svc == NULL || scope == NULL) {
17394 uu_warn(gettext("Unable to create a property group, or "
17395 "property\n"));
17396 uu_warn("%s\n", pg == NULL ? "pg is NULL" :
17397 "pg is not NULL");
17398 uu_warn("%s\n", prop == NULL ? "prop is NULL" :
17399 "prop is not NULL");
17400 uu_warn("%s\n", val == NULL ? "val is NULL" :
17401 "val is not NULL");
17402 uu_warn("%s\n", iter == NULL ? "iter is NULL" :
17403 "iter is not NULL");
17404 uu_warn("%s\n", svc == NULL ? "svc is NULL" :
17405 "svc is not NULL");
17406 uu_warn("%s\n", scope == NULL ? "scope is NULL" :
17407 "scope is not NULL");
17408 uu_warn(gettext("scf error is : %s\n"),
17409 scf_strerror(scf_error()));
17410 scfdie();
17411 }
17412
17413 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
17414 switch (scf_error()) {
17415 case SCF_ERROR_CONNECTION_BROKEN:
17416 case SCF_ERROR_NOT_FOUND:
17417 goto out;
17418
17419 case SCF_ERROR_HANDLE_MISMATCH:
17420 case SCF_ERROR_NOT_BOUND:
17421 case SCF_ERROR_INVALID_ARGUMENT:
17422 default:
17423 bad_error("scf_handle_get_scope", scf_error());
17424 }
17425 }
17426
17427 if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
17428 uu_warn(gettext("Unable to process the hash service, %s\n"),
17429 HASH_SVC);
17430 goto out;
17431 }
17432
17433 pgname = safe_malloc(max_scf_name_len + 1);
17434 mfile = safe_malloc(max_scf_value_len + 1);
17435
17436 if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
17437 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17438 scf_strerror(scf_error()));
17439 goto out;
17440 }
17441
17442 while ((r = scf_iter_next_pg(iter, pg)) != 0) {
17443 if (r == -1)
17444 goto out;
17445
17446 if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
17447 switch (scf_error()) {
17448 case SCF_ERROR_DELETED:
17449 return (ENODEV);
17450
17451 case SCF_ERROR_CONNECTION_BROKEN:
17452 return (ECONNABORTED);
17453
17454 case SCF_ERROR_NOT_SET:
17455 case SCF_ERROR_NOT_BOUND:
17456 default:
17457 bad_error("scf_pg_get_name", scf_error());
17458 }
17459 }
17460 if (IGNORE_VAR) {
17461 if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
17462 continue;
17463 }
17464
17465 /*
17466 * If unable to get the property continue as this is an
17467 * entry that has no location to check against.
17468 */
17469 if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
17470 continue;
17471 }
17472
17473 if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
17474 uu_warn(gettext("Unable to get value from %s\n"),
17475 pgname);
17476
17477 switch (scf_error()) {
17478 case SCF_ERROR_DELETED:
17479 case SCF_ERROR_CONSTRAINT_VIOLATED:
17480 case SCF_ERROR_NOT_FOUND:
17481 case SCF_ERROR_NOT_SET:
17482 continue;
17483
17484 case SCF_ERROR_CONNECTION_BROKEN:
17485 r = scferror2errno(scf_error());
17486 goto out;
17487
17488 case SCF_ERROR_HANDLE_MISMATCH:
17489 case SCF_ERROR_NOT_BOUND:
17490 default:
17491 bad_error("scf_property_get_value",
17492 scf_error());
17493 }
17494 }
17495
17496 if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
17497 == -1) {
17498 uu_warn(gettext("Unable to get astring from %s : %s\n"),
17499 pgname, scf_strerror(scf_error()));
17500
17501 switch (scf_error()) {
17502 case SCF_ERROR_NOT_SET:
17503 case SCF_ERROR_TYPE_MISMATCH:
17504 continue;
17505
17506 default:
17507 bad_error("scf_value_get_astring", scf_error());
17508 }
17509 }
17510
17511 if (access(mfile, F_OK) == 0)
17512 continue;
17513
17514 (void) scf_pg_delete(pg);
17515 }
17516
17517 out:
17518 scf_scope_destroy(scope);
17519 scf_service_destroy(svc);
17520 scf_pg_destroy(pg);
17521 scf_property_destroy(prop);
17522 scf_value_destroy(val);
17523 scf_iter_destroy(iter);
17524 free(pgname);
17525 free(mfile);
17526
17527 return (0);
17528 }
17529
17530 #ifndef NATIVE_BUILD
17531 /* ARGSUSED */
CPL_MATCH_FN(complete_select)17532 CPL_MATCH_FN(complete_select)
17533 {
17534 const char *arg0, *arg1, *arg1end;
17535 int word_start, err = 0, r;
17536 size_t len;
17537 char *buf;
17538
17539 lscf_prep_hndl();
17540
17541 arg0 = line + strspn(line, " \t");
17542 assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
17543
17544 arg1 = arg0 + sizeof ("select") - 1;
17545 arg1 += strspn(arg1, " \t");
17546 word_start = arg1 - line;
17547
17548 arg1end = arg1 + strcspn(arg1, " \t");
17549 if (arg1end < line + word_end)
17550 return (0);
17551
17552 len = line + word_end - arg1;
17553
17554 buf = safe_malloc(max_scf_name_len + 1);
17555
17556 if (cur_snap != NULL) {
17557 return (0);
17558 } else if (cur_inst != NULL) {
17559 return (0);
17560 } else if (cur_svc != NULL) {
17561 scf_instance_t *inst;
17562 scf_iter_t *iter;
17563
17564 if ((inst = scf_instance_create(g_hndl)) == NULL ||
17565 (iter = scf_iter_create(g_hndl)) == NULL)
17566 scfdie();
17567
17568 if (scf_iter_service_instances(iter, cur_svc) != 0)
17569 scfdie();
17570
17571 for (;;) {
17572 r = scf_iter_next_instance(iter, inst);
17573 if (r == 0)
17574 break;
17575 if (r != 1)
17576 scfdie();
17577
17578 if (scf_instance_get_name(inst, buf,
17579 max_scf_name_len + 1) < 0)
17580 scfdie();
17581
17582 if (strncmp(buf, arg1, len) == 0) {
17583 err = cpl_add_completion(cpl, line, word_start,
17584 word_end, buf + len, "", " ");
17585 if (err != 0)
17586 break;
17587 }
17588 }
17589
17590 scf_iter_destroy(iter);
17591 scf_instance_destroy(inst);
17592
17593 return (err);
17594 } else {
17595 scf_service_t *svc;
17596 scf_iter_t *iter;
17597
17598 assert(cur_scope != NULL);
17599
17600 if ((svc = scf_service_create(g_hndl)) == NULL ||
17601 (iter = scf_iter_create(g_hndl)) == NULL)
17602 scfdie();
17603
17604 if (scf_iter_scope_services(iter, cur_scope) != 0)
17605 scfdie();
17606
17607 for (;;) {
17608 r = scf_iter_next_service(iter, svc);
17609 if (r == 0)
17610 break;
17611 if (r != 1)
17612 scfdie();
17613
17614 if (scf_service_get_name(svc, buf,
17615 max_scf_name_len + 1) < 0)
17616 scfdie();
17617
17618 if (strncmp(buf, arg1, len) == 0) {
17619 err = cpl_add_completion(cpl, line, word_start,
17620 word_end, buf + len, "", " ");
17621 if (err != 0)
17622 break;
17623 }
17624 }
17625
17626 scf_iter_destroy(iter);
17627 scf_service_destroy(svc);
17628
17629 return (err);
17630 }
17631 }
17632
17633 /* ARGSUSED */
CPL_MATCH_FN(complete_command)17634 CPL_MATCH_FN(complete_command)
17635 {
17636 uint32_t scope = 0;
17637
17638 if (cur_snap != NULL)
17639 scope = CS_SNAP;
17640 else if (cur_inst != NULL)
17641 scope = CS_INST;
17642 else if (cur_svc != NULL)
17643 scope = CS_SVC;
17644 else
17645 scope = CS_SCOPE;
17646
17647 return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
17648 }
17649 #endif /* NATIVE_BUILD */
17650