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 2015 Joyent, Inc.
25 * Copyright 2012 Milan Jurik. All rights reserved.
26 */
27
28
29 #include <alloca.h>
30 #include <assert.h>
31 #include <ctype.h>
32 #include <door.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <fnmatch.h>
36 #include <inttypes.h>
37 #include <libintl.h>
38 #include <libnvpair.h>
39 #include <libscf.h>
40 #include <libscf_priv.h>
41 #include <libtecla.h>
42 #include <libuutil.h>
43 #include <limits.h>
44 #include <locale.h>
45 #include <stdarg.h>
46 #include <string.h>
47 #include <strings.h>
48 #include <time.h>
49 #include <unistd.h>
50 #include <wait.h>
51 #include <poll.h>
52
53 #include <libxml/tree.h>
54
55 #include <sys/param.h>
56
57 #include <sys/stat.h>
58 #include <sys/mman.h>
59
60 #include "svccfg.h"
61 #include "notify_params.h"
62 #include "manifest_hash.h"
63 #include "manifest_find.h"
64
65 /* The colon namespaces in each entity (each followed by a newline). */
66 #define COLON_NAMESPACES ":properties\n"
67
68 #define TEMP_FILE_PATTERN "/tmp/svccfg-XXXXXX"
69
70 /* These are characters which the lexer requires to be in double-quotes. */
71 #define CHARS_TO_QUOTE " \t\n\\>=\"()"
72
73 #define HASH_SIZE 16
74 #define HASH_PG_TYPE "framework"
75 #define HASH_PG_FLAGS 0
76 #define HASH_PROP "md5sum"
77
78 /*
79 * Indentation used in the output of the describe subcommand.
80 */
81 #define TMPL_VALUE_INDENT " "
82 #define TMPL_INDENT " "
83 #define TMPL_INDENT_2X " "
84 #define TMPL_CHOICE_INDENT " "
85
86 /*
87 * Directory locations for manifests
88 */
89 #define VARSVC_DIR "/var/svc/manifest"
90 #define LIBSVC_DIR "/lib/svc/manifest"
91 #define VARSVC_PR "var_svc_manifest"
92 #define LIBSVC_PR "lib_svc_manifest"
93 #define MFSTFILEPR "manifestfile"
94
95 #define SUPPORTPROP "support"
96
97 #define MFSTHISTFILE "/lib/svc/share/mfsthistory"
98
99 #define MFSTFILE_MAX 16
100
101 /*
102 * These are the classes of elements which may appear as children of service
103 * or instance elements in XML manifests.
104 */
105 struct entity_elts {
106 xmlNodePtr create_default_instance;
107 xmlNodePtr single_instance;
108 xmlNodePtr restarter;
109 xmlNodePtr dependencies;
110 xmlNodePtr dependents;
111 xmlNodePtr method_context;
112 xmlNodePtr exec_methods;
113 xmlNodePtr notify_params;
114 xmlNodePtr property_groups;
115 xmlNodePtr instances;
116 xmlNodePtr stability;
117 xmlNodePtr template;
118 };
119
120 /*
121 * Likewise for property_group elements.
122 */
123 struct pg_elts {
124 xmlNodePtr stability;
125 xmlNodePtr propvals;
126 xmlNodePtr properties;
127 };
128
129 /*
130 * Likewise for template elements.
131 */
132 struct template_elts {
133 xmlNodePtr common_name;
134 xmlNodePtr description;
135 xmlNodePtr documentation;
136 };
137
138 /*
139 * Likewise for type (for notification parameters) elements.
140 */
141 struct params_elts {
142 xmlNodePtr paramval;
143 xmlNodePtr parameter;
144 };
145
146 /*
147 * This structure is for snaplevel lists. They are convenient because libscf
148 * only allows traversing snaplevels in one direction.
149 */
150 struct snaplevel {
151 uu_list_node_t list_node;
152 scf_snaplevel_t *sl;
153 };
154
155 /*
156 * This is used for communication between lscf_service_export and
157 * export_callback.
158 */
159 struct export_args {
160 const char *filename;
161 int flags;
162 };
163
164 /*
165 * The service_manifest structure is used by the upgrade process
166 * to create a list of service to manifest linkages from the manifests
167 * in a set of given directories.
168 */
169 typedef struct service_manifest {
170 const char *servicename;
171 uu_list_t *mfstlist;
172 size_t mfstlist_sz;
173
174 uu_avl_node_t svcmfst_node;
175 } service_manifest_t;
176
177 /*
178 * Structure to track the manifest file property group
179 * and the manifest file associated with that property
180 * group. Also, a flag to keep the access once it has
181 * been checked.
182 */
183 struct mpg_mfile {
184 char *mpg;
185 char *mfile;
186 int access;
187 };
188
189 const char * const scf_pg_general = SCF_PG_GENERAL;
190 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
191 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
192 const char * const scf_property_external = "external";
193
194 const char * const snap_initial = "initial";
195 const char * const snap_lastimport = "last-import";
196 const char * const snap_previous = "previous";
197 const char * const snap_running = "running";
198
199 scf_handle_t *g_hndl = NULL; /* only valid after lscf_prep_hndl() */
200
201 ssize_t max_scf_fmri_len;
202 ssize_t max_scf_name_len;
203 ssize_t max_scf_pg_type_len;
204 ssize_t max_scf_value_len;
205 static size_t max_scf_len;
206
207 static scf_scope_t *cur_scope;
208 static scf_service_t *cur_svc = NULL;
209 static scf_instance_t *cur_inst = NULL;
210 static scf_snapshot_t *cur_snap = NULL;
211 static scf_snaplevel_t *cur_level = NULL;
212
213 static uu_list_pool_t *snaplevel_pool;
214 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
215 static uu_list_t *cur_levels;
216 static struct snaplevel *cur_elt; /* cur_elt->sl == cur_level */
217
218 static FILE *tempfile = NULL;
219 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
220
221 static const char *emsg_entity_not_selected;
222 static const char *emsg_permission_denied;
223 static const char *emsg_create_xml;
224 static const char *emsg_cant_modify_snapshots;
225 static const char *emsg_invalid_for_snapshot;
226 static const char *emsg_read_only;
227 static const char *emsg_deleted;
228 static const char *emsg_invalid_pg_name;
229 static const char *emsg_invalid_prop_name;
230 static const char *emsg_no_such_pg;
231 static const char *emsg_fmri_invalid_pg_name;
232 static const char *emsg_fmri_invalid_pg_name_type;
233 static const char *emsg_pg_added;
234 static const char *emsg_pg_changed;
235 static const char *emsg_pg_deleted;
236 static const char *emsg_pg_mod_perm;
237 static const char *emsg_pg_add_perm;
238 static const char *emsg_pg_del_perm;
239 static const char *emsg_snap_perm;
240 static const char *emsg_dpt_dangling;
241 static const char *emsg_dpt_no_dep;
242
243 static int li_only = 0;
244 static int no_refresh = 0;
245
246 /* how long in ns we should wait between checks for a pg */
247 static uint64_t pg_timeout = 100 * (NANOSEC / MILLISEC);
248
249 /* import globals, to minimize allocations */
250 static scf_scope_t *imp_scope = NULL;
251 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
252 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
253 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
254 static scf_snapshot_t *imp_rsnap = NULL;
255 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
256 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
257 static scf_property_t *imp_prop = NULL;
258 static scf_iter_t *imp_iter = NULL;
259 static scf_iter_t *imp_rpg_iter = NULL;
260 static scf_iter_t *imp_up_iter = NULL;
261 static scf_transaction_t *imp_tx = NULL; /* always reset this */
262 static char *imp_str = NULL;
263 static size_t imp_str_sz;
264 static char *imp_tsname = NULL;
265 static char *imp_fe1 = NULL; /* for fmri_equal() */
266 static char *imp_fe2 = NULL;
267 static uu_list_t *imp_deleted_dpts = NULL; /* pgroup_t's to refresh */
268
269 /* upgrade_dependents() globals */
270 static scf_instance_t *ud_inst = NULL;
271 static scf_snaplevel_t *ud_snpl = NULL;
272 static scf_propertygroup_t *ud_pg = NULL;
273 static scf_propertygroup_t *ud_cur_depts_pg = NULL;
274 static scf_propertygroup_t *ud_run_dpts_pg = NULL;
275 static int ud_run_dpts_pg_set = 0;
276 static scf_property_t *ud_prop = NULL;
277 static scf_property_t *ud_dpt_prop = NULL;
278 static scf_value_t *ud_val = NULL;
279 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
280 static scf_transaction_t *ud_tx = NULL;
281 static char *ud_ctarg = NULL;
282 static char *ud_oldtarg = NULL;
283 static char *ud_name = NULL;
284
285 /* export globals */
286 static scf_instance_t *exp_inst;
287 static scf_propertygroup_t *exp_pg;
288 static scf_property_t *exp_prop;
289 static scf_value_t *exp_val;
290 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
291 static char *exp_str;
292 static size_t exp_str_sz;
293
294 /* cleanup globals */
295 static uu_avl_pool_t *service_manifest_pool = NULL;
296 static uu_avl_t *service_manifest_tree = NULL;
297
298 static void scfdie_lineno(int lineno) __NORETURN;
299
300 static char *start_method_names[] = {
301 "start",
302 "inetd_start",
303 NULL
304 };
305
306 static struct uri_scheme {
307 const char *scheme;
308 const char *protocol;
309 } uri_scheme[] = {
310 { "mailto", "smtp" },
311 { "snmp", "snmp" },
312 { "syslog", "syslog" },
313 { NULL, NULL }
314 };
315 #define URI_SCHEME_NUM ((sizeof (uri_scheme) / \
316 sizeof (struct uri_scheme)) - 1)
317
318 static int
check_uri_scheme(const char * scheme)319 check_uri_scheme(const char *scheme)
320 {
321 int i;
322
323 for (i = 0; uri_scheme[i].scheme != NULL; ++i) {
324 if (strcmp(scheme, uri_scheme[i].scheme) == 0)
325 return (i);
326 }
327
328 return (-1);
329 }
330
331 static int
check_uri_protocol(const char * p)332 check_uri_protocol(const char *p)
333 {
334 int i;
335
336 for (i = 0; uri_scheme[i].protocol != NULL; ++i) {
337 if (strcmp(p, uri_scheme[i].protocol) == 0)
338 return (i);
339 }
340
341 return (-1);
342 }
343
344 /*
345 * For unexpected libscf errors.
346 */
347 #ifdef NDEBUG
348
349 static void scfdie(void) __NORETURN;
350
351 static void
scfdie(void)352 scfdie(void)
353 {
354 scf_error_t err = scf_error();
355
356 if (err == SCF_ERROR_CONNECTION_BROKEN)
357 uu_die(gettext("Repository connection broken. Exiting.\n"));
358
359 uu_die(gettext("Unexpected fatal libscf error: %s. Exiting.\n"),
360 scf_strerror(err));
361 }
362
363 #else
364
365 #define scfdie() scfdie_lineno(__LINE__)
366
367 static void
scfdie_lineno(int lineno)368 scfdie_lineno(int lineno)
369 {
370 scf_error_t err = scf_error();
371
372 if (err == SCF_ERROR_CONNECTION_BROKEN)
373 uu_die(gettext("Repository connection broken. Exiting.\n"));
374
375 uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
376 ": %s.\n"), lineno, scf_strerror(err));
377 }
378
379 #endif
380
381 static void
scfwarn(void)382 scfwarn(void)
383 {
384 warn(gettext("Unexpected libscf error: %s.\n"),
385 scf_strerror(scf_error()));
386 }
387
388 /*
389 * Clear a field of a structure.
390 */
391 static int
clear_int(void * a,void * b)392 clear_int(void *a, void *b)
393 {
394 /* LINTED */
395 *(int *)((char *)a + (size_t)b) = 0;
396
397 return (UU_WALK_NEXT);
398 }
399
400 static int
scferror2errno(scf_error_t err)401 scferror2errno(scf_error_t err)
402 {
403 switch (err) {
404 case SCF_ERROR_BACKEND_ACCESS:
405 return (EACCES);
406
407 case SCF_ERROR_BACKEND_READONLY:
408 return (EROFS);
409
410 case SCF_ERROR_CONNECTION_BROKEN:
411 return (ECONNABORTED);
412
413 case SCF_ERROR_CONSTRAINT_VIOLATED:
414 case SCF_ERROR_INVALID_ARGUMENT:
415 return (EINVAL);
416
417 case SCF_ERROR_DELETED:
418 return (ECANCELED);
419
420 case SCF_ERROR_EXISTS:
421 return (EEXIST);
422
423 case SCF_ERROR_NO_MEMORY:
424 return (ENOMEM);
425
426 case SCF_ERROR_NO_RESOURCES:
427 return (ENOSPC);
428
429 case SCF_ERROR_NOT_FOUND:
430 return (ENOENT);
431
432 case SCF_ERROR_PERMISSION_DENIED:
433 return (EPERM);
434
435 default:
436 #ifndef NDEBUG
437 (void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
438 __FILE__, __LINE__, err);
439 #else
440 (void) fprintf(stderr, "Unknown libscf error %d.\n", err);
441 #endif
442 abort();
443 /* NOTREACHED */
444 }
445 }
446
447 static int
entity_get_pg(void * ent,int issvc,const char * name,scf_propertygroup_t * pg)448 entity_get_pg(void *ent, int issvc, const char *name,
449 scf_propertygroup_t *pg)
450 {
451 if (issvc)
452 return (scf_service_get_pg(ent, name, pg));
453 else
454 return (scf_instance_get_pg(ent, name, pg));
455 }
456
457 static void
entity_destroy(void * ent,int issvc)458 entity_destroy(void *ent, int issvc)
459 {
460 if (issvc)
461 scf_service_destroy(ent);
462 else
463 scf_instance_destroy(ent);
464 }
465
466 static int
get_pg(const char * pg_name,scf_propertygroup_t * pg)467 get_pg(const char *pg_name, scf_propertygroup_t *pg)
468 {
469 int ret;
470
471 if (cur_level != NULL)
472 ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
473 else if (cur_inst != NULL)
474 ret = scf_instance_get_pg(cur_inst, pg_name, pg);
475 else
476 ret = scf_service_get_pg(cur_svc, pg_name, pg);
477
478 return (ret);
479 }
480
481 /*
482 * Find a snaplevel in a snapshot. If get_svc is true, find the service
483 * snaplevel. Otherwise find the instance snaplevel.
484 *
485 * Returns
486 * 0 - success
487 * ECONNABORTED - repository connection broken
488 * ECANCELED - instance containing snap was deleted
489 * ENOENT - snap has no snaplevels
490 * - requested snaplevel not found
491 */
492 static int
get_snaplevel(scf_snapshot_t * snap,int get_svc,scf_snaplevel_t * snpl)493 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
494 {
495 if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
496 switch (scf_error()) {
497 case SCF_ERROR_CONNECTION_BROKEN:
498 case SCF_ERROR_DELETED:
499 case SCF_ERROR_NOT_FOUND:
500 return (scferror2errno(scf_error()));
501
502 case SCF_ERROR_HANDLE_MISMATCH:
503 case SCF_ERROR_NOT_BOUND:
504 case SCF_ERROR_NOT_SET:
505 default:
506 bad_error("scf_snapshot_get_base_snaplevel",
507 scf_error());
508 }
509 }
510
511 for (;;) {
512 ssize_t ssz;
513
514 ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
515 if (ssz >= 0) {
516 if (!get_svc)
517 return (0);
518 } else {
519 switch (scf_error()) {
520 case SCF_ERROR_CONSTRAINT_VIOLATED:
521 if (get_svc)
522 return (0);
523 break;
524
525 case SCF_ERROR_DELETED:
526 case SCF_ERROR_CONNECTION_BROKEN:
527 return (scferror2errno(scf_error()));
528
529 case SCF_ERROR_NOT_SET:
530 case SCF_ERROR_NOT_BOUND:
531 default:
532 bad_error("scf_snaplevel_get_instance_name",
533 scf_error());
534 }
535 }
536
537 if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
538 switch (scf_error()) {
539 case SCF_ERROR_NOT_FOUND:
540 case SCF_ERROR_CONNECTION_BROKEN:
541 case SCF_ERROR_DELETED:
542 return (scferror2errno(scf_error()));
543
544 case SCF_ERROR_HANDLE_MISMATCH:
545 case SCF_ERROR_NOT_BOUND:
546 case SCF_ERROR_NOT_SET:
547 case SCF_ERROR_INVALID_ARGUMENT:
548 default:
549 bad_error("scf_snaplevel_get_next_snaplevel",
550 scf_error());
551 }
552 }
553 }
554 }
555
556 /*
557 * If issvc is 0, take ent to be a pointer to an scf_instance_t. If it has
558 * a running snapshot, and that snapshot has an instance snaplevel, set pg to
559 * the property group named name in it. If it doesn't have a running
560 * snapshot, set pg to the instance's current property group named name.
561 *
562 * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
563 * its instances. If one has a running snapshot with a service snaplevel, set
564 * pg to the property group named name in it. If no such snaplevel could be
565 * found, set pg to the service's current property group named name.
566 *
567 * iter, inst, snap, and snpl are required scratch objects.
568 *
569 * Returns
570 * 0 - success
571 * ECONNABORTED - repository connection broken
572 * ECANCELED - ent was deleted
573 * ENOENT - no such property group
574 * EINVAL - name is an invalid property group name
575 * EBADF - found running snapshot is missing a snaplevel
576 */
577 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)578 entity_get_running_pg(void *ent, int issvc, const char *name,
579 scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
580 scf_snapshot_t *snap, scf_snaplevel_t *snpl)
581 {
582 int r;
583
584 if (issvc) {
585 /* Search for an instance with a running snapshot. */
586 if (scf_iter_service_instances(iter, ent) != 0) {
587 switch (scf_error()) {
588 case SCF_ERROR_DELETED:
589 case SCF_ERROR_CONNECTION_BROKEN:
590 return (scferror2errno(scf_error()));
591
592 case SCF_ERROR_NOT_SET:
593 case SCF_ERROR_NOT_BOUND:
594 case SCF_ERROR_HANDLE_MISMATCH:
595 default:
596 bad_error("scf_iter_service_instances",
597 scf_error());
598 }
599 }
600
601 for (;;) {
602 r = scf_iter_next_instance(iter, inst);
603 if (r == 0) {
604 if (scf_service_get_pg(ent, name, pg) == 0)
605 return (0);
606
607 switch (scf_error()) {
608 case SCF_ERROR_DELETED:
609 case SCF_ERROR_NOT_FOUND:
610 case SCF_ERROR_INVALID_ARGUMENT:
611 case SCF_ERROR_CONNECTION_BROKEN:
612 return (scferror2errno(scf_error()));
613
614 case SCF_ERROR_NOT_BOUND:
615 case SCF_ERROR_HANDLE_MISMATCH:
616 case SCF_ERROR_NOT_SET:
617 default:
618 bad_error("scf_service_get_pg",
619 scf_error());
620 }
621 }
622 if (r != 1) {
623 switch (scf_error()) {
624 case SCF_ERROR_DELETED:
625 case SCF_ERROR_CONNECTION_BROKEN:
626 return (scferror2errno(scf_error()));
627
628 case SCF_ERROR_INVALID_ARGUMENT:
629 case SCF_ERROR_NOT_SET:
630 case SCF_ERROR_NOT_BOUND:
631 case SCF_ERROR_HANDLE_MISMATCH:
632 default:
633 bad_error("scf_iter_next_instance",
634 scf_error());
635 }
636 }
637
638 if (scf_instance_get_snapshot(inst, snap_running,
639 snap) == 0)
640 break;
641
642 switch (scf_error()) {
643 case SCF_ERROR_NOT_FOUND:
644 case SCF_ERROR_DELETED:
645 continue;
646
647 case SCF_ERROR_CONNECTION_BROKEN:
648 return (ECONNABORTED);
649
650 case SCF_ERROR_HANDLE_MISMATCH:
651 case SCF_ERROR_INVALID_ARGUMENT:
652 case SCF_ERROR_NOT_SET:
653 case SCF_ERROR_NOT_BOUND:
654 default:
655 bad_error("scf_instance_get_snapshot",
656 scf_error());
657 }
658 }
659 } else {
660 if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
661 switch (scf_error()) {
662 case SCF_ERROR_NOT_FOUND:
663 break;
664
665 case SCF_ERROR_DELETED:
666 case SCF_ERROR_CONNECTION_BROKEN:
667 return (scferror2errno(scf_error()));
668
669 case SCF_ERROR_NOT_BOUND:
670 case SCF_ERROR_HANDLE_MISMATCH:
671 case SCF_ERROR_INVALID_ARGUMENT:
672 case SCF_ERROR_NOT_SET:
673 default:
674 bad_error("scf_instance_get_snapshot",
675 scf_error());
676 }
677
678 if (scf_instance_get_pg(ent, name, pg) == 0)
679 return (0);
680
681 switch (scf_error()) {
682 case SCF_ERROR_DELETED:
683 case SCF_ERROR_NOT_FOUND:
684 case SCF_ERROR_INVALID_ARGUMENT:
685 case SCF_ERROR_CONNECTION_BROKEN:
686 return (scferror2errno(scf_error()));
687
688 case SCF_ERROR_NOT_BOUND:
689 case SCF_ERROR_HANDLE_MISMATCH:
690 case SCF_ERROR_NOT_SET:
691 default:
692 bad_error("scf_instance_get_pg", scf_error());
693 }
694 }
695 }
696
697 r = get_snaplevel(snap, issvc, snpl);
698 switch (r) {
699 case 0:
700 break;
701
702 case ECONNABORTED:
703 case ECANCELED:
704 return (r);
705
706 case ENOENT:
707 return (EBADF);
708
709 default:
710 bad_error("get_snaplevel", r);
711 }
712
713 if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
714 return (0);
715
716 switch (scf_error()) {
717 case SCF_ERROR_DELETED:
718 case SCF_ERROR_INVALID_ARGUMENT:
719 case SCF_ERROR_CONNECTION_BROKEN:
720 case SCF_ERROR_NOT_FOUND:
721 return (scferror2errno(scf_error()));
722
723 case SCF_ERROR_NOT_BOUND:
724 case SCF_ERROR_HANDLE_MISMATCH:
725 case SCF_ERROR_NOT_SET:
726 default:
727 bad_error("scf_snaplevel_get_pg", scf_error());
728 /* NOTREACHED */
729 }
730 }
731
732 /*
733 * To be registered with atexit().
734 */
735 static void
remove_tempfile(void)736 remove_tempfile(void)
737 {
738 int ret;
739
740 if (tempfile != NULL) {
741 if (fclose(tempfile) == EOF)
742 (void) warn(gettext("Could not close temporary file"));
743 tempfile = NULL;
744 }
745
746 if (tempfilename[0] != '\0') {
747 do {
748 ret = remove(tempfilename);
749 } while (ret == -1 && errno == EINTR);
750 if (ret == -1)
751 warn(gettext("Could not remove temporary file"));
752 tempfilename[0] = '\0';
753 }
754 }
755
756 /*
757 * Launch private svc.configd(1M) for manipulating alternate repositories.
758 */
759 static void
start_private_repository(engine_state_t * est)760 start_private_repository(engine_state_t *est)
761 {
762 int fd, stat;
763 struct door_info info;
764 pid_t pid;
765
766 /*
767 * 1. Create a temporary file for the door.
768 */
769 if (est->sc_repo_doorname != NULL)
770 free((void *)est->sc_repo_doorname);
771
772 est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
773 if (est->sc_repo_doorname == NULL)
774 uu_die(gettext("Could not acquire temporary filename"));
775
776 fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
777 if (fd < 0)
778 uu_die(gettext("Could not create temporary file for "
779 "repository server"));
780
781 (void) close(fd);
782
783 /*
784 * 2. Launch a configd with that door, using the specified
785 * repository.
786 */
787 if ((est->sc_repo_pid = fork()) == 0) {
788 (void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
789 "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
790 NULL);
791 uu_die(gettext("Could not execute %s"), est->sc_repo_server);
792 } else if (est->sc_repo_pid == -1)
793 uu_die(gettext("Attempt to fork failed"));
794
795 do {
796 pid = waitpid(est->sc_repo_pid, &stat, 0);
797 } while (pid == -1 && errno == EINTR);
798
799 if (pid == -1)
800 uu_die(gettext("Could not waitpid() for repository server"));
801
802 if (!WIFEXITED(stat)) {
803 uu_die(gettext("Repository server failed (status %d).\n"),
804 stat);
805 } else if (WEXITSTATUS(stat) != 0) {
806 uu_die(gettext("Repository server failed (exit %d).\n"),
807 WEXITSTATUS(stat));
808 }
809
810 /*
811 * See if it was successful by checking if the door is a door.
812 */
813
814 fd = open(est->sc_repo_doorname, O_RDWR);
815 if (fd < 0)
816 uu_die(gettext("Could not open door \"%s\""),
817 est->sc_repo_doorname);
818
819 if (door_info(fd, &info) < 0)
820 uu_die(gettext("Unexpected door_info() error"));
821
822 if (close(fd) == -1)
823 warn(gettext("Could not close repository door"),
824 strerror(errno));
825
826 est->sc_repo_pid = info.di_target;
827 }
828
829 void
lscf_cleanup(void)830 lscf_cleanup(void)
831 {
832 /*
833 * In the case where we've launched a private svc.configd(1M)
834 * instance, we must terminate our child and remove the temporary
835 * rendezvous point.
836 */
837 if (est->sc_repo_pid > 0) {
838 (void) kill(est->sc_repo_pid, SIGTERM);
839 (void) waitpid(est->sc_repo_pid, NULL, 0);
840 (void) unlink(est->sc_repo_doorname);
841
842 est->sc_repo_pid = 0;
843 }
844 }
845
846 void
unselect_cursnap(void)847 unselect_cursnap(void)
848 {
849 void *cookie;
850
851 cur_level = NULL;
852
853 cookie = NULL;
854 while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
855 scf_snaplevel_destroy(cur_elt->sl);
856 free(cur_elt);
857 }
858
859 scf_snapshot_destroy(cur_snap);
860 cur_snap = NULL;
861 }
862
863 void
lscf_prep_hndl(void)864 lscf_prep_hndl(void)
865 {
866 if (g_hndl != NULL)
867 return;
868
869 g_hndl = scf_handle_create(SCF_VERSION);
870 if (g_hndl == NULL)
871 scfdie();
872
873 if (est->sc_repo_filename != NULL)
874 start_private_repository(est);
875
876 if (est->sc_repo_doorname != NULL) {
877 scf_value_t *repo_value;
878 int ret;
879
880 repo_value = scf_value_create(g_hndl);
881 if (repo_value == NULL)
882 scfdie();
883
884 ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
885 assert(ret == SCF_SUCCESS);
886
887 if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
888 SCF_SUCCESS)
889 scfdie();
890
891 scf_value_destroy(repo_value);
892 }
893
894 if (scf_handle_bind(g_hndl) != 0)
895 uu_die(gettext("Could not connect to repository server: %s.\n"),
896 scf_strerror(scf_error()));
897
898 cur_scope = scf_scope_create(g_hndl);
899 if (cur_scope == NULL)
900 scfdie();
901
902 if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
903 scfdie();
904 }
905
906 static void
repository_teardown(void)907 repository_teardown(void)
908 {
909 if (g_hndl != NULL) {
910 if (cur_snap != NULL)
911 unselect_cursnap();
912 scf_instance_destroy(cur_inst);
913 scf_service_destroy(cur_svc);
914 scf_scope_destroy(cur_scope);
915 scf_handle_destroy(g_hndl);
916 cur_inst = NULL;
917 cur_svc = NULL;
918 cur_scope = NULL;
919 g_hndl = NULL;
920 lscf_cleanup();
921 }
922 }
923
924 void
lscf_set_repository(const char * repfile,int force)925 lscf_set_repository(const char *repfile, int force)
926 {
927 repository_teardown();
928
929 if (est->sc_repo_filename != NULL) {
930 free((void *)est->sc_repo_filename);
931 est->sc_repo_filename = NULL;
932 }
933
934 if ((force == 0) && (access(repfile, R_OK) != 0)) {
935 /*
936 * Repository file does not exist
937 * or has no read permission.
938 */
939 warn(gettext("Cannot access \"%s\": %s\n"),
940 repfile, strerror(errno));
941 } else {
942 est->sc_repo_filename = safe_strdup(repfile);
943 }
944
945 lscf_prep_hndl();
946 }
947
948 void
lscf_init()949 lscf_init()
950 {
951 if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
952 (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
953 (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
954 0 ||
955 (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
956 scfdie();
957
958 max_scf_len = max_scf_fmri_len;
959 if (max_scf_name_len > max_scf_len)
960 max_scf_len = max_scf_name_len;
961 if (max_scf_pg_type_len > max_scf_len)
962 max_scf_len = max_scf_pg_type_len;
963 /*
964 * When a value of type opaque is represented as a string, the
965 * string contains 2 characters for every byte of data. That is
966 * because the string contains the hex representation of the opaque
967 * value.
968 */
969 if (2 * max_scf_value_len > max_scf_len)
970 max_scf_len = 2 * max_scf_value_len;
971
972 if (atexit(remove_tempfile) != 0)
973 uu_die(gettext("Could not register atexit() function"));
974
975 emsg_entity_not_selected = gettext("An entity is not selected.\n");
976 emsg_permission_denied = gettext("Permission denied.\n");
977 emsg_create_xml = gettext("Could not create XML node.\n");
978 emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
979 emsg_invalid_for_snapshot =
980 gettext("Invalid operation on a snapshot.\n");
981 emsg_read_only = gettext("Backend read-only.\n");
982 emsg_deleted = gettext("Current selection has been deleted.\n");
983 emsg_invalid_pg_name =
984 gettext("Invalid property group name \"%s\".\n");
985 emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
986 emsg_no_such_pg = gettext("No such property group \"%s\".\n");
987 emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
988 "with invalid name \"%s\".\n");
989 emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
990 "group with invalid name \"%s\" or type \"%s\".\n");
991 emsg_pg_added = gettext("%s changed unexpectedly "
992 "(property group \"%s\" added).\n");
993 emsg_pg_changed = gettext("%s changed unexpectedly "
994 "(property group \"%s\" changed).\n");
995 emsg_pg_deleted = gettext("%s changed unexpectedly "
996 "(property group \"%s\" or an ancestor was deleted).\n");
997 emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
998 "in %s (permission denied).\n");
999 emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
1000 "in %s (permission denied).\n");
1001 emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
1002 "in %s (permission denied).\n");
1003 emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
1004 "(permission denied).\n");
1005 emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
1006 "new dependent \"%s\" because it already exists). Warning: The "
1007 "current dependent's target (%s) does not exist.\n");
1008 emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
1009 "dependent \"%s\" because it already exists). Warning: The "
1010 "current dependent's target (%s) does not have a dependency named "
1011 "\"%s\" as expected.\n");
1012
1013 string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
1014 offsetof(string_list_t, node), NULL, 0);
1015 snaplevel_pool = uu_list_pool_create("snaplevels",
1016 sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
1017 NULL, 0);
1018 }
1019
1020
1021 static const char *
prop_to_typestr(const scf_property_t * prop)1022 prop_to_typestr(const scf_property_t *prop)
1023 {
1024 scf_type_t ty;
1025
1026 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
1027 scfdie();
1028
1029 return (scf_type_to_string(ty));
1030 }
1031
1032 static scf_type_t
string_to_type(const char * type)1033 string_to_type(const char *type)
1034 {
1035 size_t len = strlen(type);
1036 char *buf;
1037
1038 if (len == 0 || type[len - 1] != ':')
1039 return (SCF_TYPE_INVALID);
1040
1041 buf = (char *)alloca(len + 1);
1042 (void) strlcpy(buf, type, len + 1);
1043 buf[len - 1] = 0;
1044
1045 return (scf_string_to_type(buf));
1046 }
1047
1048 static scf_value_t *
string_to_value(const char * str,scf_type_t ty,boolean_t require_quotes)1049 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
1050 {
1051 scf_value_t *v;
1052 char *dup, *nstr;
1053 size_t len;
1054
1055 v = scf_value_create(g_hndl);
1056 if (v == NULL)
1057 scfdie();
1058
1059 len = strlen(str);
1060 if (require_quotes &&
1061 (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
1062 semerr(gettext("Multiple string values or string values "
1063 "with spaces must be quoted with '\"'.\n"));
1064 scf_value_destroy(v);
1065 return (NULL);
1066 }
1067
1068 nstr = dup = safe_strdup(str);
1069 if (dup[0] == '\"') {
1070 /*
1071 * Strip out the first and the last quote.
1072 */
1073 dup[len - 1] = '\0';
1074 nstr = dup + 1;
1075 }
1076
1077 if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
1078 assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1079 semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1080 scf_type_to_string(ty), nstr);
1081 scf_value_destroy(v);
1082 v = NULL;
1083 }
1084 free(dup);
1085 return (v);
1086 }
1087
1088 /*
1089 * Print str to strm, quoting double-quotes and backslashes with backslashes.
1090 * Optionally append a comment prefix ('#') to newlines ('\n').
1091 */
1092 static int
quote_and_print(const char * str,FILE * strm,int commentnl)1093 quote_and_print(const char *str, FILE *strm, int commentnl)
1094 {
1095 const char *cp;
1096
1097 for (cp = str; *cp != '\0'; ++cp) {
1098 if (*cp == '"' || *cp == '\\')
1099 (void) putc('\\', strm);
1100
1101 (void) putc(*cp, strm);
1102
1103 if (commentnl && *cp == '\n') {
1104 (void) putc('#', strm);
1105 }
1106 }
1107
1108 return (ferror(strm));
1109 }
1110
1111 /*
1112 * These wrappers around lowlevel functions provide consistent error checking
1113 * and warnings.
1114 */
1115 static int
pg_get_prop(scf_propertygroup_t * pg,const char * propname,scf_property_t * prop)1116 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1117 {
1118 if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1119 return (0);
1120
1121 if (scf_error() != SCF_ERROR_NOT_FOUND)
1122 scfdie();
1123
1124 if (g_verbose) {
1125 ssize_t len;
1126 char *fmri;
1127
1128 len = scf_pg_to_fmri(pg, NULL, 0);
1129 if (len < 0)
1130 scfdie();
1131
1132 fmri = safe_malloc(len + 1);
1133
1134 if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1135 scfdie();
1136
1137 warn(gettext("Expected property %s of property group %s is "
1138 "missing.\n"), propname, fmri);
1139
1140 free(fmri);
1141 }
1142
1143 return (-1);
1144 }
1145
1146 static int
prop_check_type(scf_property_t * prop,scf_type_t ty)1147 prop_check_type(scf_property_t *prop, scf_type_t ty)
1148 {
1149 scf_type_t pty;
1150
1151 if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1152 scfdie();
1153
1154 if (ty == pty)
1155 return (0);
1156
1157 if (g_verbose) {
1158 ssize_t len;
1159 char *fmri;
1160 const char *tystr;
1161
1162 len = scf_property_to_fmri(prop, NULL, 0);
1163 if (len < 0)
1164 scfdie();
1165
1166 fmri = safe_malloc(len + 1);
1167
1168 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1169 scfdie();
1170
1171 tystr = scf_type_to_string(ty);
1172 if (tystr == NULL)
1173 tystr = "?";
1174
1175 warn(gettext("Property %s is not of expected type %s.\n"),
1176 fmri, tystr);
1177
1178 free(fmri);
1179 }
1180
1181 return (-1);
1182 }
1183
1184 static int
prop_get_val(scf_property_t * prop,scf_value_t * val)1185 prop_get_val(scf_property_t *prop, scf_value_t *val)
1186 {
1187 scf_error_t err;
1188
1189 if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1190 return (0);
1191
1192 err = scf_error();
1193
1194 if (err != SCF_ERROR_NOT_FOUND &&
1195 err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1196 err != SCF_ERROR_PERMISSION_DENIED)
1197 scfdie();
1198
1199 if (g_verbose) {
1200 ssize_t len;
1201 char *fmri, *emsg;
1202
1203 len = scf_property_to_fmri(prop, NULL, 0);
1204 if (len < 0)
1205 scfdie();
1206
1207 fmri = safe_malloc(len + 1);
1208
1209 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1210 scfdie();
1211
1212 if (err == SCF_ERROR_NOT_FOUND)
1213 emsg = gettext("Property %s has no values; expected "
1214 "one.\n");
1215 else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1216 emsg = gettext("Property %s has multiple values; "
1217 "expected one.\n");
1218 else
1219 emsg = gettext("No permission to read property %s.\n");
1220
1221 warn(emsg, fmri);
1222
1223 free(fmri);
1224 }
1225
1226 return (-1);
1227 }
1228
1229
1230 static boolean_t
snaplevel_is_instance(const scf_snaplevel_t * level)1231 snaplevel_is_instance(const scf_snaplevel_t *level)
1232 {
1233 if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1234 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1235 scfdie();
1236 return (0);
1237 } else {
1238 return (1);
1239 }
1240 }
1241
1242 /*
1243 * Decode FMRI into a service or instance, and put the result in *ep. If
1244 * memory cannot be allocated, return SCF_ERROR_NO_MEMORY. If the FMRI is
1245 * invalid, return SCF_ERROR_INVALID_ARGUMENT. If the FMRI does not specify
1246 * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED. If the entity cannot be
1247 * found, return SCF_ERROR_NOT_FOUND. Otherwise return SCF_ERROR_NONE, point
1248 * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1249 * whether *ep is a service.
1250 */
1251 static scf_error_t
fmri_to_entity(scf_handle_t * h,const char * fmri,void ** ep,int * isservice)1252 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1253 {
1254 char *fmri_copy;
1255 const char *sstr, *istr, *pgstr;
1256 scf_service_t *svc;
1257 scf_instance_t *inst;
1258
1259 fmri_copy = strdup(fmri);
1260 if (fmri_copy == NULL)
1261 return (SCF_ERROR_NO_MEMORY);
1262
1263 if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1264 SCF_SUCCESS) {
1265 free(fmri_copy);
1266 return (SCF_ERROR_INVALID_ARGUMENT);
1267 }
1268
1269 free(fmri_copy);
1270
1271 if (sstr == NULL || pgstr != NULL)
1272 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1273
1274 if (istr == NULL) {
1275 svc = scf_service_create(h);
1276 if (svc == NULL)
1277 return (SCF_ERROR_NO_MEMORY);
1278
1279 if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1280 SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1281 if (scf_error() != SCF_ERROR_NOT_FOUND)
1282 scfdie();
1283
1284 return (SCF_ERROR_NOT_FOUND);
1285 }
1286
1287 *ep = svc;
1288 *isservice = 1;
1289 } else {
1290 inst = scf_instance_create(h);
1291 if (inst == NULL)
1292 return (SCF_ERROR_NO_MEMORY);
1293
1294 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1295 NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1296 if (scf_error() != SCF_ERROR_NOT_FOUND)
1297 scfdie();
1298
1299 return (SCF_ERROR_NOT_FOUND);
1300 }
1301
1302 *ep = inst;
1303 *isservice = 0;
1304 }
1305
1306 return (SCF_ERROR_NONE);
1307 }
1308
1309 /*
1310 * Create the entity named by fmri. Place a pointer to its libscf handle in
1311 * *ep, and set or clear *isservicep if it is a service or an instance.
1312 * Returns
1313 * SCF_ERROR_NONE - success
1314 * SCF_ERROR_NO_MEMORY - scf_*_create() failed
1315 * SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1316 * SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1317 * SCF_ERROR_NOT_FOUND - no such scope
1318 * SCF_ERROR_PERMISSION_DENIED
1319 * SCF_ERROR_BACKEND_READONLY
1320 * SCF_ERROR_BACKEND_ACCESS
1321 */
1322 static scf_error_t
create_entity(scf_handle_t * h,const char * fmri,void ** ep,int * isservicep)1323 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1324 {
1325 char *fmri_copy;
1326 const char *scstr, *sstr, *istr, *pgstr;
1327 scf_scope_t *scope = NULL;
1328 scf_service_t *svc = NULL;
1329 scf_instance_t *inst = NULL;
1330 scf_error_t scfe;
1331
1332 fmri_copy = safe_strdup(fmri);
1333
1334 if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1335 0) {
1336 free(fmri_copy);
1337 return (SCF_ERROR_INVALID_ARGUMENT);
1338 }
1339
1340 if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1341 free(fmri_copy);
1342 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1343 }
1344
1345 *ep = NULL;
1346
1347 if ((scope = scf_scope_create(h)) == NULL ||
1348 (svc = scf_service_create(h)) == NULL ||
1349 (inst = scf_instance_create(h)) == NULL) {
1350 scfe = SCF_ERROR_NO_MEMORY;
1351 goto out;
1352 }
1353
1354 get_scope:
1355 if (scf_handle_get_scope(h, scstr, scope) != 0) {
1356 switch (scf_error()) {
1357 case SCF_ERROR_CONNECTION_BROKEN:
1358 scfdie();
1359 /* NOTREACHED */
1360
1361 case SCF_ERROR_NOT_FOUND:
1362 scfe = SCF_ERROR_NOT_FOUND;
1363 goto out;
1364
1365 case SCF_ERROR_HANDLE_MISMATCH:
1366 case SCF_ERROR_NOT_BOUND:
1367 case SCF_ERROR_INVALID_ARGUMENT:
1368 default:
1369 bad_error("scf_handle_get_scope", scf_error());
1370 }
1371 }
1372
1373 get_svc:
1374 if (scf_scope_get_service(scope, sstr, svc) != 0) {
1375 switch (scf_error()) {
1376 case SCF_ERROR_CONNECTION_BROKEN:
1377 scfdie();
1378 /* NOTREACHED */
1379
1380 case SCF_ERROR_DELETED:
1381 goto get_scope;
1382
1383 case SCF_ERROR_NOT_FOUND:
1384 break;
1385
1386 case SCF_ERROR_HANDLE_MISMATCH:
1387 case SCF_ERROR_INVALID_ARGUMENT:
1388 case SCF_ERROR_NOT_BOUND:
1389 case SCF_ERROR_NOT_SET:
1390 default:
1391 bad_error("scf_scope_get_service", scf_error());
1392 }
1393
1394 if (scf_scope_add_service(scope, sstr, svc) != 0) {
1395 switch (scf_error()) {
1396 case SCF_ERROR_CONNECTION_BROKEN:
1397 scfdie();
1398 /* NOTREACHED */
1399
1400 case SCF_ERROR_DELETED:
1401 goto get_scope;
1402
1403 case SCF_ERROR_PERMISSION_DENIED:
1404 case SCF_ERROR_BACKEND_READONLY:
1405 case SCF_ERROR_BACKEND_ACCESS:
1406 scfe = scf_error();
1407 goto out;
1408
1409 case SCF_ERROR_HANDLE_MISMATCH:
1410 case SCF_ERROR_INVALID_ARGUMENT:
1411 case SCF_ERROR_NOT_BOUND:
1412 case SCF_ERROR_NOT_SET:
1413 default:
1414 bad_error("scf_scope_get_service", scf_error());
1415 }
1416 }
1417 }
1418
1419 if (istr == NULL) {
1420 scfe = SCF_ERROR_NONE;
1421 *ep = svc;
1422 *isservicep = 1;
1423 goto out;
1424 }
1425
1426 get_inst:
1427 if (scf_service_get_instance(svc, istr, inst) != 0) {
1428 switch (scf_error()) {
1429 case SCF_ERROR_CONNECTION_BROKEN:
1430 scfdie();
1431 /* NOTREACHED */
1432
1433 case SCF_ERROR_DELETED:
1434 goto get_svc;
1435
1436 case SCF_ERROR_NOT_FOUND:
1437 break;
1438
1439 case SCF_ERROR_HANDLE_MISMATCH:
1440 case SCF_ERROR_INVALID_ARGUMENT:
1441 case SCF_ERROR_NOT_BOUND:
1442 case SCF_ERROR_NOT_SET:
1443 default:
1444 bad_error("scf_service_get_instance", scf_error());
1445 }
1446
1447 if (scf_service_add_instance(svc, istr, inst) != 0) {
1448 switch (scf_error()) {
1449 case SCF_ERROR_CONNECTION_BROKEN:
1450 scfdie();
1451 /* NOTREACHED */
1452
1453 case SCF_ERROR_DELETED:
1454 goto get_svc;
1455
1456 case SCF_ERROR_PERMISSION_DENIED:
1457 case SCF_ERROR_BACKEND_READONLY:
1458 case SCF_ERROR_BACKEND_ACCESS:
1459 scfe = scf_error();
1460 goto out;
1461
1462 case SCF_ERROR_HANDLE_MISMATCH:
1463 case SCF_ERROR_INVALID_ARGUMENT:
1464 case SCF_ERROR_NOT_BOUND:
1465 case SCF_ERROR_NOT_SET:
1466 default:
1467 bad_error("scf_service_add_instance",
1468 scf_error());
1469 }
1470 }
1471 }
1472
1473 scfe = SCF_ERROR_NONE;
1474 *ep = inst;
1475 *isservicep = 0;
1476
1477 out:
1478 if (*ep != inst)
1479 scf_instance_destroy(inst);
1480 if (*ep != svc)
1481 scf_service_destroy(svc);
1482 scf_scope_destroy(scope);
1483 free(fmri_copy);
1484 return (scfe);
1485 }
1486
1487 /*
1488 * Create or update a snapshot of inst. snap is a required scratch object.
1489 *
1490 * Returns
1491 * 0 - success
1492 * ECONNABORTED - repository connection broken
1493 * EPERM - permission denied
1494 * ENOSPC - configd is out of resources
1495 * ECANCELED - inst was deleted
1496 * -1 - unknown libscf error (message printed)
1497 */
1498 static int
take_snap(scf_instance_t * inst,const char * name,scf_snapshot_t * snap)1499 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1500 {
1501 again:
1502 if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1503 if (_scf_snapshot_take_attach(inst, snap) != 0) {
1504 switch (scf_error()) {
1505 case SCF_ERROR_CONNECTION_BROKEN:
1506 case SCF_ERROR_PERMISSION_DENIED:
1507 case SCF_ERROR_NO_RESOURCES:
1508 return (scferror2errno(scf_error()));
1509
1510 case SCF_ERROR_NOT_SET:
1511 case SCF_ERROR_INVALID_ARGUMENT:
1512 default:
1513 bad_error("_scf_snapshot_take_attach",
1514 scf_error());
1515 }
1516 }
1517 } else {
1518 switch (scf_error()) {
1519 case SCF_ERROR_NOT_FOUND:
1520 break;
1521
1522 case SCF_ERROR_DELETED:
1523 case SCF_ERROR_CONNECTION_BROKEN:
1524 return (scferror2errno(scf_error()));
1525
1526 case SCF_ERROR_HANDLE_MISMATCH:
1527 case SCF_ERROR_NOT_BOUND:
1528 case SCF_ERROR_INVALID_ARGUMENT:
1529 case SCF_ERROR_NOT_SET:
1530 default:
1531 bad_error("scf_instance_get_snapshot", scf_error());
1532 }
1533
1534 if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1535 switch (scf_error()) {
1536 case SCF_ERROR_EXISTS:
1537 goto again;
1538
1539 case SCF_ERROR_CONNECTION_BROKEN:
1540 case SCF_ERROR_NO_RESOURCES:
1541 case SCF_ERROR_PERMISSION_DENIED:
1542 return (scferror2errno(scf_error()));
1543
1544 default:
1545 scfwarn();
1546 return (-1);
1547
1548 case SCF_ERROR_NOT_SET:
1549 case SCF_ERROR_INTERNAL:
1550 case SCF_ERROR_INVALID_ARGUMENT:
1551 case SCF_ERROR_HANDLE_MISMATCH:
1552 bad_error("_scf_snapshot_take_new",
1553 scf_error());
1554 }
1555 }
1556 }
1557
1558 return (0);
1559 }
1560
1561 static int
refresh_running_snapshot(void * entity)1562 refresh_running_snapshot(void *entity)
1563 {
1564 scf_snapshot_t *snap;
1565 int r;
1566
1567 if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1568 scfdie();
1569 r = take_snap(entity, snap_running, snap);
1570 scf_snapshot_destroy(snap);
1571
1572 return (r);
1573 }
1574
1575 /*
1576 * Refresh entity. If isservice is zero, take entity to be an scf_instance_t *.
1577 * Otherwise take entity to be an scf_service_t * and refresh all of its child
1578 * instances. fmri is used for messages. inst, iter, and name_buf are used
1579 * for scratch space. Returns
1580 * 0 - success
1581 * ECONNABORTED - repository connection broken
1582 * ECANCELED - entity was deleted
1583 * EACCES - backend denied access
1584 * EPERM - permission denied
1585 * ENOSPC - repository server out of resources
1586 * -1 - _smf_refresh_instance_i() failed. scf_error() should be set.
1587 */
1588 static int
refresh_entity(int isservice,void * entity,const char * fmri,scf_instance_t * inst,scf_iter_t * iter,char * name_buf)1589 refresh_entity(int isservice, void *entity, const char *fmri,
1590 scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1591 {
1592 scf_error_t scfe;
1593 int r;
1594
1595 if (!isservice) {
1596 /*
1597 * Let restarter handles refreshing and making new running
1598 * snapshot only if operating on a live repository and not
1599 * running in early import.
1600 */
1601 if (est->sc_repo_filename == NULL &&
1602 est->sc_repo_doorname == NULL &&
1603 est->sc_in_emi == 0) {
1604 if (_smf_refresh_instance_i(entity) == 0) {
1605 if (g_verbose)
1606 warn(gettext("Refreshed %s.\n"), fmri);
1607 return (0);
1608 }
1609
1610 switch (scf_error()) {
1611 case SCF_ERROR_BACKEND_ACCESS:
1612 return (EACCES);
1613
1614 case SCF_ERROR_PERMISSION_DENIED:
1615 return (EPERM);
1616
1617 default:
1618 return (-1);
1619 }
1620 } else {
1621 r = refresh_running_snapshot(entity);
1622 switch (r) {
1623 case 0:
1624 break;
1625
1626 case ECONNABORTED:
1627 case ECANCELED:
1628 case EPERM:
1629 case ENOSPC:
1630 break;
1631
1632 default:
1633 bad_error("refresh_running_snapshot",
1634 scf_error());
1635 }
1636
1637 return (r);
1638 }
1639 }
1640
1641 if (scf_iter_service_instances(iter, entity) != 0) {
1642 switch (scf_error()) {
1643 case SCF_ERROR_CONNECTION_BROKEN:
1644 return (ECONNABORTED);
1645
1646 case SCF_ERROR_DELETED:
1647 return (ECANCELED);
1648
1649 case SCF_ERROR_HANDLE_MISMATCH:
1650 case SCF_ERROR_NOT_BOUND:
1651 case SCF_ERROR_NOT_SET:
1652 default:
1653 bad_error("scf_iter_service_instances", scf_error());
1654 }
1655 }
1656
1657 for (;;) {
1658 r = scf_iter_next_instance(iter, inst);
1659 if (r == 0)
1660 break;
1661 if (r != 1) {
1662 switch (scf_error()) {
1663 case SCF_ERROR_CONNECTION_BROKEN:
1664 return (ECONNABORTED);
1665
1666 case SCF_ERROR_DELETED:
1667 return (ECANCELED);
1668
1669 case SCF_ERROR_HANDLE_MISMATCH:
1670 case SCF_ERROR_NOT_BOUND:
1671 case SCF_ERROR_NOT_SET:
1672 case SCF_ERROR_INVALID_ARGUMENT:
1673 default:
1674 bad_error("scf_iter_next_instance",
1675 scf_error());
1676 }
1677 }
1678
1679 /*
1680 * Similarly, just take a new running snapshot if operating on
1681 * a non-live repository or running during early import.
1682 */
1683 if (est->sc_repo_filename != NULL ||
1684 est->sc_repo_doorname != NULL ||
1685 est->sc_in_emi == 1) {
1686 r = refresh_running_snapshot(inst);
1687 switch (r) {
1688 case 0:
1689 continue;
1690
1691 case ECONNABORTED:
1692 case ECANCELED:
1693 case EPERM:
1694 case ENOSPC:
1695 break;
1696 default:
1697 bad_error("refresh_running_snapshot",
1698 scf_error());
1699 }
1700
1701 return (r);
1702
1703 }
1704
1705 if (_smf_refresh_instance_i(inst) == 0) {
1706 if (g_verbose) {
1707 if (scf_instance_get_name(inst, name_buf,
1708 max_scf_name_len + 1) < 0)
1709 (void) strcpy(name_buf, "?");
1710
1711 warn(gettext("Refreshed %s:%s.\n"),
1712 fmri, name_buf);
1713 }
1714 } else {
1715 if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1716 g_verbose) {
1717 scfe = scf_error();
1718
1719 if (scf_instance_to_fmri(inst, name_buf,
1720 max_scf_name_len + 1) < 0)
1721 (void) strcpy(name_buf, "?");
1722
1723 warn(gettext(
1724 "Refresh of %s:%s failed: %s.\n"), fmri,
1725 name_buf, scf_strerror(scfe));
1726 }
1727 }
1728 }
1729
1730 return (0);
1731 }
1732
1733 static void
private_refresh(void)1734 private_refresh(void)
1735 {
1736 scf_instance_t *pinst = NULL;
1737 scf_iter_t *piter = NULL;
1738 ssize_t fmrilen;
1739 size_t bufsz;
1740 char *fmribuf;
1741 void *ent;
1742 int issvc;
1743 int r;
1744
1745 if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1746 return;
1747
1748 assert(cur_svc != NULL);
1749
1750 bufsz = max_scf_fmri_len + 1;
1751 fmribuf = safe_malloc(bufsz);
1752 if (cur_inst) {
1753 issvc = 0;
1754 ent = cur_inst;
1755 fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1756 } else {
1757 issvc = 1;
1758 ent = cur_svc;
1759 fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1760 if ((pinst = scf_instance_create(g_hndl)) == NULL)
1761 scfdie();
1762
1763 if ((piter = scf_iter_create(g_hndl)) == NULL)
1764 scfdie();
1765 }
1766 if (fmrilen < 0) {
1767 free(fmribuf);
1768 if (scf_error() != SCF_ERROR_DELETED)
1769 scfdie();
1770
1771 warn(emsg_deleted);
1772 return;
1773 }
1774 assert(fmrilen < bufsz);
1775
1776 r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1777 switch (r) {
1778 case 0:
1779 break;
1780
1781 case ECONNABORTED:
1782 warn(gettext("Could not refresh %s "
1783 "(repository connection broken).\n"), fmribuf);
1784 break;
1785
1786 case ECANCELED:
1787 warn(emsg_deleted);
1788 break;
1789
1790 case EPERM:
1791 warn(gettext("Could not refresh %s "
1792 "(permission denied).\n"), fmribuf);
1793 break;
1794
1795 case ENOSPC:
1796 warn(gettext("Could not refresh %s "
1797 "(repository server out of resources).\n"),
1798 fmribuf);
1799 break;
1800
1801 case EACCES:
1802 default:
1803 bad_error("refresh_entity", scf_error());
1804 }
1805
1806 if (issvc) {
1807 scf_instance_destroy(pinst);
1808 scf_iter_destroy(piter);
1809 }
1810
1811 free(fmribuf);
1812 }
1813
1814
1815 static int
stash_scferror_err(scf_callback_t * cbp,scf_error_t err)1816 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1817 {
1818 cbp->sc_err = scferror2errno(err);
1819 return (UU_WALK_ERROR);
1820 }
1821
1822 static int
stash_scferror(scf_callback_t * cbp)1823 stash_scferror(scf_callback_t *cbp)
1824 {
1825 return (stash_scferror_err(cbp, scf_error()));
1826 }
1827
1828 static int select_inst(const char *);
1829 static int select_svc(const char *);
1830
1831 /*
1832 * Take a property that does not have a type and check to see if a type
1833 * exists or can be gleened from the current data. Set the type.
1834 *
1835 * Check the current level (instance) and then check the higher level
1836 * (service). This could be the case for adding a new property to
1837 * the instance that's going to "override" a service level property.
1838 *
1839 * For a property :
1840 * 1. Take the type from an existing property
1841 * 2. Take the type from a template entry
1842 *
1843 * If the type can not be found, then leave the type as is, and let the import
1844 * report the problem of the missing type.
1845 */
1846 static int
find_current_prop_type(void * p,void * g)1847 find_current_prop_type(void *p, void *g)
1848 {
1849 property_t *prop = p;
1850 scf_callback_t *lcb = g;
1851 pgroup_t *pg = NULL;
1852
1853 const char *fmri = NULL;
1854 char *lfmri = NULL;
1855 char *cur_selection = NULL;
1856
1857 scf_propertygroup_t *sc_pg = NULL;
1858 scf_property_t *sc_prop = NULL;
1859 scf_pg_tmpl_t *t_pg = NULL;
1860 scf_prop_tmpl_t *t_prop = NULL;
1861 scf_type_t prop_type;
1862
1863 value_t *vp;
1864 int issvc = lcb->sc_service;
1865 int r = UU_WALK_ERROR;
1866
1867 if (prop->sc_value_type != SCF_TYPE_INVALID)
1868 return (UU_WALK_NEXT);
1869
1870 t_prop = scf_tmpl_prop_create(g_hndl);
1871 sc_prop = scf_property_create(g_hndl);
1872 if (sc_prop == NULL || t_prop == NULL) {
1873 warn(gettext("Unable to create the property to attempt and "
1874 "find a missing type.\n"));
1875
1876 scf_property_destroy(sc_prop);
1877 scf_tmpl_prop_destroy(t_prop);
1878
1879 return (UU_WALK_ERROR);
1880 }
1881
1882 if (lcb->sc_flags == 1) {
1883 pg = lcb->sc_parent;
1884 issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT);
1885 fmri = pg->sc_parent->sc_fmri;
1886 retry_pg:
1887 if (cur_svc && cur_selection == NULL) {
1888 cur_selection = safe_malloc(max_scf_fmri_len + 1);
1889 lscf_get_selection_str(cur_selection,
1890 max_scf_fmri_len + 1);
1891
1892 if (strcmp(cur_selection, fmri) != 0) {
1893 lscf_select(fmri);
1894 } else {
1895 free(cur_selection);
1896 cur_selection = NULL;
1897 }
1898 } else {
1899 lscf_select(fmri);
1900 }
1901
1902 if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) {
1903 warn(gettext("Unable to create property group to "
1904 "find a missing property type.\n"));
1905
1906 goto out;
1907 }
1908
1909 if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) {
1910 /*
1911 * If this is the sc_pg from the parent
1912 * let the caller clean up the sc_pg,
1913 * and just throw it away in this case.
1914 */
1915 if (sc_pg != lcb->sc_parent)
1916 scf_pg_destroy(sc_pg);
1917
1918 sc_pg = NULL;
1919 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1920 warn(gettext("Unable to create template "
1921 "property group to find a property "
1922 "type.\n"));
1923
1924 goto out;
1925 }
1926
1927 if (scf_tmpl_get_by_pg_name(fmri, NULL,
1928 pg->sc_pgroup_name, NULL, t_pg,
1929 SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) {
1930 /*
1931 * if instance get service and jump back
1932 */
1933 scf_tmpl_pg_destroy(t_pg);
1934 t_pg = NULL;
1935 if (issvc == 0) {
1936 entity_t *e = pg->sc_parent->sc_parent;
1937
1938 fmri = e->sc_fmri;
1939 issvc = 1;
1940 goto retry_pg;
1941 } else {
1942 goto out;
1943 }
1944 }
1945 }
1946 } else {
1947 sc_pg = lcb->sc_parent;
1948 }
1949
1950 /*
1951 * Attempt to get the type from an existing property. If the property
1952 * cannot be found then attempt to get the type from a template entry
1953 * for the property.
1954 *
1955 * Finally, if at the instance level look at the service level.
1956 */
1957 if (sc_pg != NULL &&
1958 pg_get_prop(sc_pg, prop->sc_property_name,
1959 sc_prop) == SCF_SUCCESS &&
1960 scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) {
1961 prop->sc_value_type = prop_type;
1962
1963 /*
1964 * Found a type, update the value types and validate
1965 * the actual value against this type.
1966 */
1967 for (vp = uu_list_first(prop->sc_property_values);
1968 vp != NULL;
1969 vp = uu_list_next(prop->sc_property_values, vp)) {
1970 vp->sc_type = prop->sc_value_type;
1971 lxml_store_value(vp, 0, NULL);
1972 }
1973
1974 r = UU_WALK_NEXT;
1975 goto out;
1976 }
1977
1978 /*
1979 * If we get here with t_pg set to NULL then we had to have
1980 * gotten an sc_pg but that sc_pg did not have the property
1981 * we are looking for. So if the t_pg is not null look up
1982 * the template entry for the property.
1983 *
1984 * If the t_pg is null then need to attempt to get a matching
1985 * template entry for the sc_pg, and see if there is a property
1986 * entry for that template entry.
1987 */
1988 do_tmpl :
1989 if (t_pg != NULL &&
1990 scf_tmpl_get_by_prop(t_pg, prop->sc_property_name,
1991 t_prop, 0) == SCF_SUCCESS) {
1992 if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) {
1993 prop->sc_value_type = prop_type;
1994
1995 /*
1996 * Found a type, update the value types and validate
1997 * the actual value against this type.
1998 */
1999 for (vp = uu_list_first(prop->sc_property_values);
2000 vp != NULL;
2001 vp = uu_list_next(prop->sc_property_values, vp)) {
2002 vp->sc_type = prop->sc_value_type;
2003 lxml_store_value(vp, 0, NULL);
2004 }
2005
2006 r = UU_WALK_NEXT;
2007 goto out;
2008 }
2009 } else {
2010 if (t_pg == NULL && sc_pg) {
2011 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
2012 warn(gettext("Unable to create template "
2013 "property group to find a property "
2014 "type.\n"));
2015
2016 goto out;
2017 }
2018
2019 if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
2020 scf_tmpl_pg_destroy(t_pg);
2021 t_pg = NULL;
2022 } else {
2023 goto do_tmpl;
2024 }
2025 }
2026 }
2027
2028 if (issvc == 0) {
2029 scf_instance_t *i;
2030 scf_service_t *s;
2031
2032 issvc = 1;
2033 if (lcb->sc_flags == 1) {
2034 entity_t *e = pg->sc_parent->sc_parent;
2035
2036 fmri = e->sc_fmri;
2037 goto retry_pg;
2038 }
2039
2040 /*
2041 * because lcb->sc_flags was not set then this means
2042 * the pg was not used and can be used here.
2043 */
2044 if ((pg = internal_pgroup_new()) == NULL) {
2045 warn(gettext("Could not create internal property group "
2046 "to find a missing type."));
2047
2048 goto out;
2049 }
2050
2051 pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1);
2052 if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name,
2053 max_scf_name_len + 1) < 0)
2054 goto out;
2055
2056 i = scf_instance_create(g_hndl);
2057 s = scf_service_create(g_hndl);
2058 if (i == NULL || s == NULL ||
2059 scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) {
2060 warn(gettext("Could not get a service for the instance "
2061 "to find a missing type."));
2062
2063 goto out;
2064 }
2065
2066 /*
2067 * Check to see truly at the instance level.
2068 */
2069 lfmri = safe_malloc(max_scf_fmri_len + 1);
2070 if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
2071 scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0)
2072 goto out;
2073 else
2074 fmri = (const char *)lfmri;
2075
2076 goto retry_pg;
2077 }
2078
2079 out :
2080 if (sc_pg != lcb->sc_parent) {
2081 scf_pg_destroy(sc_pg);
2082 }
2083
2084 /*
2085 * If this is true then the pg was allocated
2086 * here, and the name was set so need to free
2087 * the name and the pg.
2088 */
2089 if (pg != NULL && pg != lcb->sc_parent) {
2090 free((char *)pg->sc_pgroup_name);
2091 internal_pgroup_free(pg);
2092 }
2093
2094 if (cur_selection) {
2095 lscf_select(cur_selection);
2096 free(cur_selection);
2097 }
2098
2099 scf_tmpl_pg_destroy(t_pg);
2100 scf_tmpl_prop_destroy(t_prop);
2101 scf_property_destroy(sc_prop);
2102
2103 if (r != UU_WALK_NEXT)
2104 warn(gettext("Could not find property type for \"%s\" "
2105 "from \"%s\"\n"), prop->sc_property_name,
2106 fmri != NULL ? fmri : lcb->sc_source_fmri);
2107
2108 free(lfmri);
2109
2110 return (r);
2111 }
2112
2113 /*
2114 * Take a property group that does not have a type and check to see if a type
2115 * exists or can be gleened from the current data. Set the type.
2116 *
2117 * Check the current level (instance) and then check the higher level
2118 * (service). This could be the case for adding a new property to
2119 * the instance that's going to "override" a service level property.
2120 *
2121 * For a property group
2122 * 1. Take the type from an existing property group
2123 * 2. Take the type from a template entry
2124 *
2125 * If the type can not be found, then leave the type as is, and let the import
2126 * report the problem of the missing type.
2127 */
2128 static int
find_current_pg_type(void * p,void * sori)2129 find_current_pg_type(void *p, void *sori)
2130 {
2131 entity_t *si = sori;
2132 pgroup_t *pg = p;
2133
2134 const char *ofmri, *fmri;
2135 char *cur_selection = NULL;
2136 char *pg_type = NULL;
2137
2138 scf_propertygroup_t *sc_pg = NULL;
2139 scf_pg_tmpl_t *t_pg = NULL;
2140
2141 int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2142 int r = UU_WALK_ERROR;
2143
2144 ofmri = fmri = si->sc_fmri;
2145 if (pg->sc_pgroup_type != NULL) {
2146 r = UU_WALK_NEXT;
2147
2148 goto out;
2149 }
2150
2151 sc_pg = scf_pg_create(g_hndl);
2152 if (sc_pg == NULL) {
2153 warn(gettext("Unable to create property group to attempt "
2154 "and find a missing type.\n"));
2155
2156 return (UU_WALK_ERROR);
2157 }
2158
2159 /*
2160 * Using get_pg() requires that the cur_svc/cur_inst be
2161 * via lscf_select. Need to preserve the current selection
2162 * if going to use lscf_select() to set up the cur_svc/cur_inst
2163 */
2164 if (cur_svc) {
2165 cur_selection = safe_malloc(max_scf_fmri_len + 1);
2166 lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1);
2167 }
2168
2169 /*
2170 * If the property group exists get the type, and set
2171 * the pgroup_t type of that type.
2172 *
2173 * If not the check for a template pg_pattern entry
2174 * and take the type from that.
2175 */
2176 retry_svc:
2177 lscf_select(fmri);
2178
2179 if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) {
2180 pg_type = safe_malloc(max_scf_pg_type_len + 1);
2181 if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type,
2182 max_scf_pg_type_len + 1) != -1) {
2183 pg->sc_pgroup_type = pg_type;
2184
2185 r = UU_WALK_NEXT;
2186 goto out;
2187 } else {
2188 free(pg_type);
2189 }
2190 } else {
2191 if ((t_pg == NULL) &&
2192 (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
2193 goto out;
2194
2195 if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name,
2196 NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS &&
2197 scf_tmpl_pg_type(t_pg, &pg_type) != -1) {
2198 pg->sc_pgroup_type = pg_type;
2199
2200 r = UU_WALK_NEXT;
2201 goto out;
2202 }
2203 }
2204
2205 /*
2206 * If type is not found at the instance level then attempt to
2207 * find the type at the service level.
2208 */
2209 if (!issvc) {
2210 si = si->sc_parent;
2211 fmri = si->sc_fmri;
2212 issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2213 goto retry_svc;
2214 }
2215
2216 out :
2217 if (cur_selection) {
2218 lscf_select(cur_selection);
2219 free(cur_selection);
2220 }
2221
2222 /*
2223 * Now walk the properties of the property group to make sure that
2224 * all properties have the correct type and values are valid for
2225 * those types.
2226 */
2227 if (r == UU_WALK_NEXT) {
2228 scf_callback_t cb;
2229
2230 cb.sc_service = issvc;
2231 cb.sc_source_fmri = ofmri;
2232 if (sc_pg != NULL) {
2233 cb.sc_parent = sc_pg;
2234 cb.sc_flags = 0;
2235 } else {
2236 cb.sc_parent = pg;
2237 cb.sc_flags = 1;
2238 }
2239
2240 if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type,
2241 &cb, UU_DEFAULT) != 0) {
2242 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2243 bad_error("uu_list_walk", uu_error());
2244
2245 r = UU_WALK_ERROR;
2246 }
2247 } else {
2248 warn(gettext("Could not find property group type for "
2249 "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri);
2250 }
2251
2252 scf_tmpl_pg_destroy(t_pg);
2253 scf_pg_destroy(sc_pg);
2254
2255 return (r);
2256 }
2257
2258 /*
2259 * Import. These functions import a bundle into the repository.
2260 */
2261
2262 /*
2263 * Add a transaction entry to lcbdata->sc_trans for this property_t. Uses
2264 * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata. On success,
2265 * returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
2266 * lcbdata->sc_err to
2267 * ENOMEM - out of memory
2268 * ECONNABORTED - repository connection broken
2269 * ECANCELED - sc_trans's property group was deleted
2270 * EINVAL - p's name is invalid (error printed)
2271 * - p has an invalid value (error printed)
2272 */
2273 static int
lscf_property_import(void * v,void * pvt)2274 lscf_property_import(void *v, void *pvt)
2275 {
2276 property_t *p = v;
2277 scf_callback_t *lcbdata = pvt;
2278 value_t *vp;
2279 scf_transaction_t *trans = lcbdata->sc_trans;
2280 scf_transaction_entry_t *entr;
2281 scf_value_t *val;
2282 scf_type_t tp;
2283
2284 if ((lcbdata->sc_flags & SCI_NOENABLED ||
2285 lcbdata->sc_flags & SCI_DELAYENABLE) &&
2286 strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
2287 lcbdata->sc_enable = p;
2288 return (UU_WALK_NEXT);
2289 }
2290
2291 entr = scf_entry_create(lcbdata->sc_handle);
2292 if (entr == NULL) {
2293 switch (scf_error()) {
2294 case SCF_ERROR_NO_MEMORY:
2295 return (stash_scferror(lcbdata));
2296
2297 case SCF_ERROR_INVALID_ARGUMENT:
2298 default:
2299 bad_error("scf_entry_create", scf_error());
2300 }
2301 }
2302
2303 tp = p->sc_value_type;
2304
2305 if (scf_transaction_property_new(trans, entr,
2306 p->sc_property_name, tp) != 0) {
2307 switch (scf_error()) {
2308 case SCF_ERROR_INVALID_ARGUMENT:
2309 semerr(emsg_invalid_prop_name, p->sc_property_name);
2310 scf_entry_destroy(entr);
2311 return (stash_scferror(lcbdata));
2312
2313 case SCF_ERROR_EXISTS:
2314 break;
2315
2316 case SCF_ERROR_DELETED:
2317 case SCF_ERROR_CONNECTION_BROKEN:
2318 scf_entry_destroy(entr);
2319 return (stash_scferror(lcbdata));
2320
2321 case SCF_ERROR_NOT_BOUND:
2322 case SCF_ERROR_HANDLE_MISMATCH:
2323 case SCF_ERROR_NOT_SET:
2324 default:
2325 bad_error("scf_transaction_property_new", scf_error());
2326 }
2327
2328 if (scf_transaction_property_change_type(trans, entr,
2329 p->sc_property_name, tp) != 0) {
2330 switch (scf_error()) {
2331 case SCF_ERROR_DELETED:
2332 case SCF_ERROR_CONNECTION_BROKEN:
2333 scf_entry_destroy(entr);
2334 return (stash_scferror(lcbdata));
2335
2336 case SCF_ERROR_INVALID_ARGUMENT:
2337 semerr(emsg_invalid_prop_name,
2338 p->sc_property_name);
2339 scf_entry_destroy(entr);
2340 return (stash_scferror(lcbdata));
2341
2342 case SCF_ERROR_NOT_FOUND:
2343 case SCF_ERROR_NOT_SET:
2344 case SCF_ERROR_HANDLE_MISMATCH:
2345 case SCF_ERROR_NOT_BOUND:
2346 default:
2347 bad_error(
2348 "scf_transaction_property_change_type",
2349 scf_error());
2350 }
2351 }
2352 }
2353
2354 for (vp = uu_list_first(p->sc_property_values);
2355 vp != NULL;
2356 vp = uu_list_next(p->sc_property_values, vp)) {
2357 val = scf_value_create(g_hndl);
2358 if (val == NULL) {
2359 switch (scf_error()) {
2360 case SCF_ERROR_NO_MEMORY:
2361 return (stash_scferror(lcbdata));
2362
2363 case SCF_ERROR_INVALID_ARGUMENT:
2364 default:
2365 bad_error("scf_value_create", scf_error());
2366 }
2367 }
2368
2369 switch (tp) {
2370 case SCF_TYPE_BOOLEAN:
2371 scf_value_set_boolean(val, vp->sc_u.sc_count);
2372 break;
2373 case SCF_TYPE_COUNT:
2374 scf_value_set_count(val, vp->sc_u.sc_count);
2375 break;
2376 case SCF_TYPE_INTEGER:
2377 scf_value_set_integer(val, vp->sc_u.sc_integer);
2378 break;
2379 default:
2380 assert(vp->sc_u.sc_string != NULL);
2381 if (scf_value_set_from_string(val, tp,
2382 vp->sc_u.sc_string) != 0) {
2383 if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
2384 bad_error("scf_value_set_from_string",
2385 scf_error());
2386
2387 warn(gettext("Value \"%s\" is not a valid "
2388 "%s.\n"), vp->sc_u.sc_string,
2389 scf_type_to_string(tp));
2390 scf_value_destroy(val);
2391 return (stash_scferror(lcbdata));
2392 }
2393 break;
2394 }
2395
2396 if (scf_entry_add_value(entr, val) != 0)
2397 bad_error("scf_entry_add_value", scf_error());
2398 }
2399
2400 return (UU_WALK_NEXT);
2401 }
2402
2403 /*
2404 * Import a pgroup_t into the repository. Uses sc_handle, sc_parent,
2405 * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2406 * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2407 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
2408 * lcbdata->sc_err to
2409 * ECONNABORTED - repository connection broken
2410 * ENOMEM - out of memory
2411 * ENOSPC - svc.configd is out of resources
2412 * ECANCELED - sc_parent was deleted
2413 * EPERM - could not create property group (permission denied) (error printed)
2414 * - could not modify property group (permission denied) (error printed)
2415 * - could not delete property group (permission denied) (error printed)
2416 * EROFS - could not create property group (repository is read-only)
2417 * - could not delete property group (repository is read-only)
2418 * EACCES - could not create property group (backend access denied)
2419 * - could not delete property group (backend access denied)
2420 * EEXIST - could not create property group (already exists)
2421 * EINVAL - invalid property group name (error printed)
2422 * - invalid property name (error printed)
2423 * - invalid value (error printed)
2424 * EBUSY - new property group deleted (error printed)
2425 * - new property group changed (error printed)
2426 * - property group added (error printed)
2427 * - property group deleted (error printed)
2428 */
2429 static int
entity_pgroup_import(void * v,void * pvt)2430 entity_pgroup_import(void *v, void *pvt)
2431 {
2432 pgroup_t *p = v;
2433 scf_callback_t cbdata;
2434 scf_callback_t *lcbdata = pvt;
2435 void *ent = lcbdata->sc_parent;
2436 int issvc = lcbdata->sc_service;
2437 int r;
2438
2439 const char * const pg_changed = gettext("%s changed unexpectedly "
2440 "(new property group \"%s\" changed).\n");
2441
2442 /* Never import deleted property groups. */
2443 if (p->sc_pgroup_delete) {
2444 if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY &&
2445 entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) {
2446 goto delete_pg;
2447 }
2448 return (UU_WALK_NEXT);
2449 }
2450
2451 if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
2452 strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
2453 lcbdata->sc_general = p;
2454 return (UU_WALK_NEXT);
2455 }
2456
2457 add_pg:
2458 if (issvc)
2459 r = scf_service_add_pg(ent, p->sc_pgroup_name,
2460 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2461 else
2462 r = scf_instance_add_pg(ent, p->sc_pgroup_name,
2463 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2464 if (r != 0) {
2465 switch (scf_error()) {
2466 case SCF_ERROR_DELETED:
2467 case SCF_ERROR_CONNECTION_BROKEN:
2468 case SCF_ERROR_BACKEND_READONLY:
2469 case SCF_ERROR_BACKEND_ACCESS:
2470 case SCF_ERROR_NO_RESOURCES:
2471 return (stash_scferror(lcbdata));
2472
2473 case SCF_ERROR_EXISTS:
2474 if (lcbdata->sc_flags & SCI_FORCE)
2475 break;
2476 return (stash_scferror(lcbdata));
2477
2478 case SCF_ERROR_INVALID_ARGUMENT:
2479 warn(emsg_fmri_invalid_pg_name_type,
2480 lcbdata->sc_source_fmri,
2481 p->sc_pgroup_name, p->sc_pgroup_type);
2482 return (stash_scferror(lcbdata));
2483
2484 case SCF_ERROR_PERMISSION_DENIED:
2485 warn(emsg_pg_add_perm, p->sc_pgroup_name,
2486 lcbdata->sc_target_fmri);
2487 return (stash_scferror(lcbdata));
2488
2489 case SCF_ERROR_NOT_BOUND:
2490 case SCF_ERROR_HANDLE_MISMATCH:
2491 case SCF_ERROR_NOT_SET:
2492 default:
2493 bad_error("scf_service_add_pg", scf_error());
2494 }
2495
2496 if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2497 switch (scf_error()) {
2498 case SCF_ERROR_CONNECTION_BROKEN:
2499 case SCF_ERROR_DELETED:
2500 return (stash_scferror(lcbdata));
2501
2502 case SCF_ERROR_INVALID_ARGUMENT:
2503 warn(emsg_fmri_invalid_pg_name,
2504 lcbdata->sc_source_fmri,
2505 p->sc_pgroup_name);
2506 return (stash_scferror(lcbdata));
2507
2508 case SCF_ERROR_NOT_FOUND:
2509 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2510 p->sc_pgroup_name);
2511 lcbdata->sc_err = EBUSY;
2512 return (UU_WALK_ERROR);
2513
2514 case SCF_ERROR_NOT_BOUND:
2515 case SCF_ERROR_HANDLE_MISMATCH:
2516 case SCF_ERROR_NOT_SET:
2517 default:
2518 bad_error("entity_get_pg", scf_error());
2519 }
2520 }
2521
2522 if (lcbdata->sc_flags & SCI_KEEP)
2523 goto props;
2524
2525 delete_pg:
2526 if (scf_pg_delete(imp_pg) != 0) {
2527 switch (scf_error()) {
2528 case SCF_ERROR_DELETED:
2529 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2530 p->sc_pgroup_name);
2531 lcbdata->sc_err = EBUSY;
2532 return (UU_WALK_ERROR);
2533
2534 case SCF_ERROR_PERMISSION_DENIED:
2535 warn(emsg_pg_del_perm, p->sc_pgroup_name,
2536 lcbdata->sc_target_fmri);
2537 return (stash_scferror(lcbdata));
2538
2539 case SCF_ERROR_BACKEND_READONLY:
2540 case SCF_ERROR_BACKEND_ACCESS:
2541 case SCF_ERROR_CONNECTION_BROKEN:
2542 return (stash_scferror(lcbdata));
2543
2544 case SCF_ERROR_NOT_SET:
2545 default:
2546 bad_error("scf_pg_delete", scf_error());
2547 }
2548 }
2549
2550 if (p->sc_pgroup_delete)
2551 return (UU_WALK_NEXT);
2552
2553 goto add_pg;
2554 }
2555
2556 props:
2557
2558 /*
2559 * Add properties to property group, if any.
2560 */
2561 cbdata.sc_handle = lcbdata->sc_handle;
2562 cbdata.sc_parent = imp_pg;
2563 cbdata.sc_flags = lcbdata->sc_flags;
2564 cbdata.sc_trans = imp_tx;
2565 cbdata.sc_enable = NULL;
2566
2567 if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2568 switch (scf_error()) {
2569 case SCF_ERROR_BACKEND_ACCESS:
2570 case SCF_ERROR_BACKEND_READONLY:
2571 case SCF_ERROR_CONNECTION_BROKEN:
2572 return (stash_scferror(lcbdata));
2573
2574 case SCF_ERROR_DELETED:
2575 warn(pg_changed, lcbdata->sc_target_fmri,
2576 p->sc_pgroup_name);
2577 lcbdata->sc_err = EBUSY;
2578 return (UU_WALK_ERROR);
2579
2580 case SCF_ERROR_PERMISSION_DENIED:
2581 warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2582 lcbdata->sc_target_fmri);
2583 return (stash_scferror(lcbdata));
2584
2585 case SCF_ERROR_NOT_BOUND:
2586 case SCF_ERROR_NOT_SET:
2587 case SCF_ERROR_IN_USE:
2588 case SCF_ERROR_HANDLE_MISMATCH:
2589 default:
2590 bad_error("scf_transaction_start", scf_error());
2591 }
2592 }
2593
2594 if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2595 UU_DEFAULT) != 0) {
2596 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2597 bad_error("uu_list_walk", uu_error());
2598 scf_transaction_reset(imp_tx);
2599
2600 lcbdata->sc_err = cbdata.sc_err;
2601 if (cbdata.sc_err == ECANCELED) {
2602 warn(pg_changed, lcbdata->sc_target_fmri,
2603 p->sc_pgroup_name);
2604 lcbdata->sc_err = EBUSY;
2605 }
2606 return (UU_WALK_ERROR);
2607 }
2608
2609 if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2610 cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2611
2612 /*
2613 * take the snapshot running snapshot then
2614 * import the stored general/enable property
2615 */
2616 r = take_snap(ent, snap_running, imp_rsnap);
2617 switch (r) {
2618 case 0:
2619 break;
2620
2621 case ECONNABORTED:
2622 warn(gettext("Could not take %s snapshot on import "
2623 "(repository connection broken).\n"),
2624 snap_running);
2625 lcbdata->sc_err = r;
2626 return (UU_WALK_ERROR);
2627 case ECANCELED:
2628 warn(emsg_deleted);
2629 lcbdata->sc_err = r;
2630 return (UU_WALK_ERROR);
2631
2632 case EPERM:
2633 warn(gettext("Could not take %s snapshot "
2634 "(permission denied).\n"), snap_running);
2635 lcbdata->sc_err = r;
2636 return (UU_WALK_ERROR);
2637
2638 case ENOSPC:
2639 warn(gettext("Could not take %s snapshot"
2640 "(repository server out of resources).\n"),
2641 snap_running);
2642 lcbdata->sc_err = r;
2643 return (UU_WALK_ERROR);
2644
2645 default:
2646 bad_error("take_snap", r);
2647 }
2648
2649 r = lscf_property_import(cbdata.sc_enable, &cbdata);
2650 if (r != UU_WALK_NEXT) {
2651 if (r != UU_WALK_ERROR)
2652 bad_error("lscf_property_import", r);
2653 return (EINVAL);
2654 }
2655 }
2656
2657 r = scf_transaction_commit(imp_tx);
2658 switch (r) {
2659 case 1:
2660 r = UU_WALK_NEXT;
2661 break;
2662
2663 case 0:
2664 warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2665 lcbdata->sc_err = EBUSY;
2666 r = UU_WALK_ERROR;
2667 break;
2668
2669 case -1:
2670 switch (scf_error()) {
2671 case SCF_ERROR_BACKEND_READONLY:
2672 case SCF_ERROR_BACKEND_ACCESS:
2673 case SCF_ERROR_CONNECTION_BROKEN:
2674 case SCF_ERROR_NO_RESOURCES:
2675 r = stash_scferror(lcbdata);
2676 break;
2677
2678 case SCF_ERROR_DELETED:
2679 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2680 p->sc_pgroup_name);
2681 lcbdata->sc_err = EBUSY;
2682 r = UU_WALK_ERROR;
2683 break;
2684
2685 case SCF_ERROR_PERMISSION_DENIED:
2686 warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2687 lcbdata->sc_target_fmri);
2688 r = stash_scferror(lcbdata);
2689 break;
2690
2691 case SCF_ERROR_NOT_SET:
2692 case SCF_ERROR_INVALID_ARGUMENT:
2693 case SCF_ERROR_NOT_BOUND:
2694 default:
2695 bad_error("scf_transaction_commit", scf_error());
2696 }
2697 break;
2698
2699 default:
2700 bad_error("scf_transaction_commit", r);
2701 }
2702
2703 scf_transaction_destroy_children(imp_tx);
2704
2705 return (r);
2706 }
2707
2708 /*
2709 * Returns
2710 * 0 - success
2711 * ECONNABORTED - repository connection broken
2712 * ENOMEM - out of memory
2713 * ENOSPC - svc.configd is out of resources
2714 * ECANCELED - inst was deleted
2715 * EPERM - could not create property group (permission denied) (error printed)
2716 * - could not modify property group (permission denied) (error printed)
2717 * EROFS - could not create property group (repository is read-only)
2718 * EACCES - could not create property group (backend access denied)
2719 * EEXIST - could not create property group (already exists)
2720 * EINVAL - invalid property group name (error printed)
2721 * - invalid property name (error printed)
2722 * - invalid value (error printed)
2723 * EBUSY - new property group changed (error printed)
2724 */
2725 static int
lscf_import_service_pgs(scf_service_t * svc,const char * target_fmri,const entity_t * isvc,int flags)2726 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2727 const entity_t *isvc, int flags)
2728 {
2729 scf_callback_t cbdata;
2730
2731 cbdata.sc_handle = scf_service_handle(svc);
2732 cbdata.sc_parent = svc;
2733 cbdata.sc_service = 1;
2734 cbdata.sc_general = 0;
2735 cbdata.sc_enable = 0;
2736 cbdata.sc_flags = flags;
2737 cbdata.sc_source_fmri = isvc->sc_fmri;
2738 cbdata.sc_target_fmri = target_fmri;
2739
2740 /*
2741 * If the op is set, then add the flag to the callback
2742 * flags for later use.
2743 */
2744 if (isvc->sc_op != SVCCFG_OP_NONE) {
2745 switch (isvc->sc_op) {
2746 case SVCCFG_OP_IMPORT :
2747 cbdata.sc_flags |= SCI_OP_IMPORT;
2748 break;
2749 case SVCCFG_OP_APPLY :
2750 cbdata.sc_flags |= SCI_OP_APPLY;
2751 break;
2752 case SVCCFG_OP_RESTORE :
2753 cbdata.sc_flags |= SCI_OP_RESTORE;
2754 break;
2755 default :
2756 uu_die(gettext("lscf_import_service_pgs : "
2757 "Unknown op stored in the service entity\n"));
2758
2759 }
2760 }
2761
2762 if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2763 UU_DEFAULT) != 0) {
2764 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2765 bad_error("uu_list_walk", uu_error());
2766
2767 return (cbdata.sc_err);
2768 }
2769
2770 return (0);
2771 }
2772
2773 /*
2774 * Returns
2775 * 0 - success
2776 * ECONNABORTED - repository connection broken
2777 * ENOMEM - out of memory
2778 * ENOSPC - svc.configd is out of resources
2779 * ECANCELED - inst was deleted
2780 * EPERM - could not create property group (permission denied) (error printed)
2781 * - could not modify property group (permission denied) (error printed)
2782 * EROFS - could not create property group (repository is read-only)
2783 * EACCES - could not create property group (backend access denied)
2784 * EEXIST - could not create property group (already exists)
2785 * EINVAL - invalid property group name (error printed)
2786 * - invalid property name (error printed)
2787 * - invalid value (error printed)
2788 * EBUSY - new property group changed (error printed)
2789 */
2790 static int
lscf_import_instance_pgs(scf_instance_t * inst,const char * target_fmri,const entity_t * iinst,int flags)2791 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2792 const entity_t *iinst, int flags)
2793 {
2794 scf_callback_t cbdata;
2795
2796 cbdata.sc_handle = scf_instance_handle(inst);
2797 cbdata.sc_parent = inst;
2798 cbdata.sc_service = 0;
2799 cbdata.sc_general = NULL;
2800 cbdata.sc_enable = NULL;
2801 cbdata.sc_flags = flags;
2802 cbdata.sc_source_fmri = iinst->sc_fmri;
2803 cbdata.sc_target_fmri = target_fmri;
2804
2805 /*
2806 * If the op is set, then add the flag to the callback
2807 * flags for later use.
2808 */
2809 if (iinst->sc_op != SVCCFG_OP_NONE) {
2810 switch (iinst->sc_op) {
2811 case SVCCFG_OP_IMPORT :
2812 cbdata.sc_flags |= SCI_OP_IMPORT;
2813 break;
2814 case SVCCFG_OP_APPLY :
2815 cbdata.sc_flags |= SCI_OP_APPLY;
2816 break;
2817 case SVCCFG_OP_RESTORE :
2818 cbdata.sc_flags |= SCI_OP_RESTORE;
2819 break;
2820 default :
2821 uu_die(gettext("lscf_import_instance_pgs : "
2822 "Unknown op stored in the instance entity\n"));
2823 }
2824 }
2825
2826 if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2827 UU_DEFAULT) != 0) {
2828 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2829 bad_error("uu_list_walk", uu_error());
2830
2831 return (cbdata.sc_err);
2832 }
2833
2834 if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2835 cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2836 /*
2837 * If importing with the SCI_NOENABLED flag then
2838 * skip the delay, but if not then add the delay
2839 * of the enable property.
2840 */
2841 if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2842 cbdata.sc_flags |= SCI_DELAYENABLE;
2843 }
2844
2845 if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2846 != UU_WALK_NEXT)
2847 return (cbdata.sc_err);
2848 }
2849
2850 return (0);
2851 }
2852
2853 /*
2854 * Report the reasons why we can't upgrade pg2 to pg1.
2855 */
2856 static void
report_pg_diffs(const pgroup_t * pg1,const pgroup_t * pg2,const char * fmri,int new)2857 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2858 int new)
2859 {
2860 property_t *p1, *p2;
2861
2862 assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2863
2864 if (!pg_attrs_equal(pg1, pg2, fmri, new))
2865 return;
2866
2867 for (p1 = uu_list_first(pg1->sc_pgroup_props);
2868 p1 != NULL;
2869 p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2870 p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2871 if (p2 != NULL) {
2872 (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2873 new);
2874 continue;
2875 }
2876
2877 if (new)
2878 warn(gettext("Conflict upgrading %s (new property "
2879 "group \"%s\" is missing property \"%s\").\n"),
2880 fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2881 else
2882 warn(gettext("Conflict upgrading %s (property "
2883 "\"%s/%s\" is missing).\n"), fmri,
2884 pg1->sc_pgroup_name, p1->sc_property_name);
2885 }
2886
2887 /*
2888 * Since pg1 should be from the manifest, any properties in pg2 which
2889 * aren't in pg1 shouldn't be reported as conflicts.
2890 */
2891 }
2892
2893 /*
2894 * Add transaction entries to tx which will upgrade cur's pg according to old
2895 * & new.
2896 *
2897 * Returns
2898 * 0 - success
2899 * EINVAL - new has a property with an invalid name or value (message emitted)
2900 * ENOMEM - out of memory
2901 */
2902 static int
add_upgrade_entries(scf_transaction_t * tx,pgroup_t * old,pgroup_t * new,pgroup_t * cur,int speak,const char * fmri)2903 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2904 pgroup_t *cur, int speak, const char *fmri)
2905 {
2906 property_t *p, *new_p, *cur_p;
2907 scf_transaction_entry_t *e;
2908 int r;
2909 int is_general;
2910 int is_protected;
2911
2912 if (uu_list_walk(new->sc_pgroup_props, clear_int,
2913 (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2914 bad_error("uu_list_walk", uu_error());
2915
2916 is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2917
2918 for (p = uu_list_first(old->sc_pgroup_props);
2919 p != NULL;
2920 p = uu_list_next(old->sc_pgroup_props, p)) {
2921 /* p is a property in the old property group. */
2922
2923 /* Protect live properties. */
2924 is_protected = 0;
2925 if (is_general) {
2926 if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2927 0 ||
2928 strcmp(p->sc_property_name,
2929 SCF_PROPERTY_RESTARTER) == 0)
2930 is_protected = 1;
2931 }
2932
2933 /* Look for the same property in the new properties. */
2934 new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2935 if (new_p != NULL) {
2936 new_p->sc_seen = 1;
2937
2938 /*
2939 * If the new property is the same as the old, don't do
2940 * anything (leave any user customizations).
2941 */
2942 if (prop_equal(p, new_p, NULL, NULL, 0))
2943 continue;
2944
2945 if (new_p->sc_property_override)
2946 goto upgrade;
2947 }
2948
2949 cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2950 if (cur_p == NULL) {
2951 /*
2952 * p has been deleted from the repository. If we were
2953 * going to delete it anyway, do nothing. Otherwise
2954 * report a conflict.
2955 */
2956 if (new_p == NULL)
2957 continue;
2958
2959 if (is_protected)
2960 continue;
2961
2962 warn(gettext("Conflict upgrading %s "
2963 "(property \"%s/%s\" is missing).\n"), fmri,
2964 old->sc_pgroup_name, p->sc_property_name);
2965 continue;
2966 }
2967
2968 if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2969 /*
2970 * Conflict. Don't warn if the property is already the
2971 * way we want it, though.
2972 */
2973 if (is_protected)
2974 continue;
2975
2976 if (new_p == NULL)
2977 (void) prop_equal(p, cur_p, fmri,
2978 old->sc_pgroup_name, 0);
2979 else
2980 (void) prop_equal(cur_p, new_p, fmri,
2981 old->sc_pgroup_name, 0);
2982 continue;
2983 }
2984
2985 if (is_protected) {
2986 if (speak)
2987 warn(gettext("%s: Refusing to upgrade "
2988 "\"%s/%s\" (live property).\n"), fmri,
2989 old->sc_pgroup_name, p->sc_property_name);
2990 continue;
2991 }
2992
2993 upgrade:
2994 /* p hasn't been customized in the repository. Upgrade it. */
2995 if (new_p == NULL) {
2996 /* p was deleted. Delete from cur if unchanged. */
2997 if (speak)
2998 warn(gettext(
2999 "%s: Deleting property \"%s/%s\".\n"),
3000 fmri, old->sc_pgroup_name,
3001 p->sc_property_name);
3002
3003 e = scf_entry_create(g_hndl);
3004 if (e == NULL)
3005 return (ENOMEM);
3006
3007 if (scf_transaction_property_delete(tx, e,
3008 p->sc_property_name) != 0) {
3009 switch (scf_error()) {
3010 case SCF_ERROR_DELETED:
3011 scf_entry_destroy(e);
3012 return (ECANCELED);
3013
3014 case SCF_ERROR_CONNECTION_BROKEN:
3015 scf_entry_destroy(e);
3016 return (ECONNABORTED);
3017
3018 case SCF_ERROR_NOT_FOUND:
3019 /*
3020 * This can happen if cur is from the
3021 * running snapshot (and it differs
3022 * from the live properties).
3023 */
3024 scf_entry_destroy(e);
3025 break;
3026
3027 case SCF_ERROR_HANDLE_MISMATCH:
3028 case SCF_ERROR_NOT_BOUND:
3029 case SCF_ERROR_NOT_SET:
3030 case SCF_ERROR_INVALID_ARGUMENT:
3031 default:
3032 bad_error(
3033 "scf_transaction_property_delete",
3034 scf_error());
3035 }
3036 }
3037 } else {
3038 scf_callback_t ctx;
3039
3040 if (speak)
3041 warn(gettext(
3042 "%s: Upgrading property \"%s/%s\".\n"),
3043 fmri, old->sc_pgroup_name,
3044 p->sc_property_name);
3045
3046 ctx.sc_handle = g_hndl;
3047 ctx.sc_trans = tx;
3048 ctx.sc_flags = 0;
3049
3050 r = lscf_property_import(new_p, &ctx);
3051 if (r != UU_WALK_NEXT) {
3052 if (r != UU_WALK_ERROR)
3053 bad_error("lscf_property_import", r);
3054 return (EINVAL);
3055 }
3056 }
3057 }
3058
3059 /* Go over the properties which were added. */
3060 for (new_p = uu_list_first(new->sc_pgroup_props);
3061 new_p != NULL;
3062 new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
3063 if (new_p->sc_seen)
3064 continue;
3065
3066 /* This is a new property. */
3067 cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
3068 if (cur_p == NULL) {
3069 scf_callback_t ctx;
3070
3071 ctx.sc_handle = g_hndl;
3072 ctx.sc_trans = tx;
3073 ctx.sc_flags = 0;
3074
3075 r = lscf_property_import(new_p, &ctx);
3076 if (r != UU_WALK_NEXT) {
3077 if (r != UU_WALK_ERROR)
3078 bad_error("lscf_property_import", r);
3079 return (EINVAL);
3080 }
3081 continue;
3082 }
3083
3084 /*
3085 * Report a conflict if the new property differs from the
3086 * current one. Unless it's general/enabled, since that's
3087 * never in the last-import snapshot.
3088 */
3089 if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
3090 0 &&
3091 strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
3092 continue;
3093
3094 (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
3095 }
3096
3097 return (0);
3098 }
3099
3100 /*
3101 * Upgrade pg according to old & new.
3102 *
3103 * Returns
3104 * 0 - success
3105 * ECONNABORTED - repository connection broken
3106 * ENOMEM - out of memory
3107 * ENOSPC - svc.configd is out of resources
3108 * ECANCELED - pg was deleted
3109 * EPERM - couldn't modify pg (permission denied)
3110 * EROFS - couldn't modify pg (backend read-only)
3111 * EACCES - couldn't modify pg (backend access denied)
3112 * EINVAL - new has a property with invalid name or value (error printed)
3113 * EBUSY - pg changed unexpectedly
3114 */
3115 static int
upgrade_pg(scf_propertygroup_t * pg,pgroup_t * cur,pgroup_t * old,pgroup_t * new,int speak,const char * fmri)3116 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
3117 pgroup_t *new, int speak, const char *fmri)
3118 {
3119 int r;
3120
3121 if (scf_transaction_start(imp_tx, pg) != 0) {
3122 switch (scf_error()) {
3123 case SCF_ERROR_CONNECTION_BROKEN:
3124 case SCF_ERROR_DELETED:
3125 case SCF_ERROR_PERMISSION_DENIED:
3126 case SCF_ERROR_BACKEND_READONLY:
3127 case SCF_ERROR_BACKEND_ACCESS:
3128 return (scferror2errno(scf_error()));
3129
3130 case SCF_ERROR_HANDLE_MISMATCH:
3131 case SCF_ERROR_IN_USE:
3132 case SCF_ERROR_NOT_BOUND:
3133 case SCF_ERROR_NOT_SET:
3134 default:
3135 bad_error("scf_transaction_start", scf_error());
3136 }
3137 }
3138
3139 r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
3140 switch (r) {
3141 case 0:
3142 break;
3143
3144 case EINVAL:
3145 case ENOMEM:
3146 scf_transaction_destroy_children(imp_tx);
3147 return (r);
3148
3149 default:
3150 bad_error("add_upgrade_entries", r);
3151 }
3152
3153 r = scf_transaction_commit(imp_tx);
3154
3155 scf_transaction_destroy_children(imp_tx);
3156
3157 switch (r) {
3158 case 1:
3159 break;
3160
3161 case 0:
3162 return (EBUSY);
3163
3164 case -1:
3165 switch (scf_error()) {
3166 case SCF_ERROR_CONNECTION_BROKEN:
3167 case SCF_ERROR_NO_RESOURCES:
3168 case SCF_ERROR_PERMISSION_DENIED:
3169 case SCF_ERROR_BACKEND_READONLY:
3170 case SCF_ERROR_BACKEND_ACCESS:
3171 case SCF_ERROR_DELETED:
3172 return (scferror2errno(scf_error()));
3173
3174 case SCF_ERROR_NOT_BOUND:
3175 case SCF_ERROR_INVALID_ARGUMENT:
3176 case SCF_ERROR_NOT_SET:
3177 default:
3178 bad_error("scf_transaction_commit", scf_error());
3179 }
3180
3181 default:
3182 bad_error("scf_transaction_commit", r);
3183 }
3184
3185 return (0);
3186 }
3187
3188 /*
3189 * Compares two entity FMRIs. Returns
3190 *
3191 * 1 - equal
3192 * 0 - not equal
3193 * -1 - f1 is invalid or not an entity
3194 * -2 - f2 is invalid or not an entity
3195 */
3196 static int
fmri_equal(const char * f1,const char * f2)3197 fmri_equal(const char *f1, const char *f2)
3198 {
3199 int r;
3200 const char *s1, *i1, *pg1;
3201 const char *s2, *i2, *pg2;
3202
3203 if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3204 return (-1);
3205 if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
3206 return (-1);
3207
3208 if (s1 == NULL || pg1 != NULL)
3209 return (-1);
3210
3211 if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3212 return (-2);
3213 if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
3214 return (-2);
3215
3216 if (s2 == NULL || pg2 != NULL)
3217 return (-2);
3218
3219 r = strcmp(s1, s2);
3220 if (r != 0)
3221 return (0);
3222
3223 if (i1 == NULL && i2 == NULL)
3224 return (1);
3225
3226 if (i1 == NULL || i2 == NULL)
3227 return (0);
3228
3229 return (strcmp(i1, i2) == 0);
3230 }
3231
3232 /*
3233 * Import a dependent by creating a dependency property group in the dependent
3234 * entity. If lcbdata->sc_trans is set, assume it's been started on the
3235 * dependents pg, and add an entry to create a new property for this
3236 * dependent. Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3237 *
3238 * On success, returns UU_WALK_NEXT. On error, returns UU_WALK_ERROR and sets
3239 * lcbdata->sc_err to
3240 * ECONNABORTED - repository connection broken
3241 * ENOMEM - out of memory
3242 * ENOSPC - configd is out of resources
3243 * EINVAL - target is invalid (error printed)
3244 * - target is not an entity (error printed)
3245 * - dependent has invalid name (error printed)
3246 * - invalid property name (error printed)
3247 * - invalid value (error printed)
3248 * - scope of target does not exist (error printed)
3249 * EPERM - couldn't create target (permission denied) (error printed)
3250 * - couldn't create dependency pg (permission denied) (error printed)
3251 * - couldn't modify dependency pg (permission denied) (error printed)
3252 * EROFS - couldn't create target (repository read-only)
3253 * - couldn't create dependency pg (repository read-only)
3254 * EACCES - couldn't create target (backend access denied)
3255 * - couldn't create dependency pg (backend access denied)
3256 * ECANCELED - sc_trans's pg was deleted
3257 * EALREADY - property for dependent already exists in sc_trans's pg
3258 * EEXIST - dependency pg already exists in target (error printed)
3259 * EBUSY - target deleted (error printed)
3260 * - property group changed during import (error printed)
3261 */
3262 static int
lscf_dependent_import(void * a1,void * pvt)3263 lscf_dependent_import(void *a1, void *pvt)
3264 {
3265 pgroup_t *pgrp = a1;
3266 scf_callback_t *lcbdata = pvt;
3267
3268 int isservice;
3269 int ret;
3270 scf_transaction_entry_t *e;
3271 scf_value_t *val;
3272 scf_callback_t dependent_cbdata;
3273 scf_error_t scfe;
3274
3275 /*
3276 * Decode the FMRI into dependent_cbdata->sc_parent. Do it here so if
3277 * it's invalid, we fail before modifying the repository.
3278 */
3279 scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3280 &dependent_cbdata.sc_parent, &isservice);
3281 switch (scfe) {
3282 case SCF_ERROR_NONE:
3283 break;
3284
3285 case SCF_ERROR_NO_MEMORY:
3286 return (stash_scferror_err(lcbdata, scfe));
3287
3288 case SCF_ERROR_INVALID_ARGUMENT:
3289 semerr(gettext("The FMRI for the \"%s\" dependent is "
3290 "invalid.\n"), pgrp->sc_pgroup_name);
3291 return (stash_scferror_err(lcbdata, scfe));
3292
3293 case SCF_ERROR_CONSTRAINT_VIOLATED:
3294 semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3295 "specifies neither a service nor an instance.\n"),
3296 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3297 return (stash_scferror_err(lcbdata, scfe));
3298
3299 case SCF_ERROR_NOT_FOUND:
3300 scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3301 &dependent_cbdata.sc_parent, &isservice);
3302 switch (scfe) {
3303 case SCF_ERROR_NONE:
3304 break;
3305
3306 case SCF_ERROR_NO_MEMORY:
3307 case SCF_ERROR_BACKEND_READONLY:
3308 case SCF_ERROR_BACKEND_ACCESS:
3309 return (stash_scferror_err(lcbdata, scfe));
3310
3311 case SCF_ERROR_NOT_FOUND:
3312 semerr(gettext("The scope in FMRI \"%s\" for the "
3313 "\"%s\" dependent does not exist.\n"),
3314 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3315 lcbdata->sc_err = EINVAL;
3316 return (UU_WALK_ERROR);
3317
3318 case SCF_ERROR_PERMISSION_DENIED:
3319 warn(gettext(
3320 "Could not create %s (permission denied).\n"),
3321 pgrp->sc_pgroup_fmri);
3322 return (stash_scferror_err(lcbdata, scfe));
3323
3324 case SCF_ERROR_INVALID_ARGUMENT:
3325 case SCF_ERROR_CONSTRAINT_VIOLATED:
3326 default:
3327 bad_error("create_entity", scfe);
3328 }
3329 break;
3330
3331 default:
3332 bad_error("fmri_to_entity", scfe);
3333 }
3334
3335 if (lcbdata->sc_trans != NULL) {
3336 e = scf_entry_create(lcbdata->sc_handle);
3337 if (e == NULL) {
3338 if (scf_error() != SCF_ERROR_NO_MEMORY)
3339 bad_error("scf_entry_create", scf_error());
3340
3341 entity_destroy(dependent_cbdata.sc_parent, isservice);
3342 return (stash_scferror(lcbdata));
3343 }
3344
3345 if (scf_transaction_property_new(lcbdata->sc_trans, e,
3346 pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
3347 switch (scf_error()) {
3348 case SCF_ERROR_INVALID_ARGUMENT:
3349 warn(gettext("Dependent of %s has invalid name "
3350 "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
3351 pgrp->sc_pgroup_name);
3352 /* FALLTHROUGH */
3353
3354 case SCF_ERROR_DELETED:
3355 case SCF_ERROR_CONNECTION_BROKEN:
3356 scf_entry_destroy(e);
3357 entity_destroy(dependent_cbdata.sc_parent,
3358 isservice);
3359 return (stash_scferror(lcbdata));
3360
3361 case SCF_ERROR_EXISTS:
3362 scf_entry_destroy(e);
3363 entity_destroy(dependent_cbdata.sc_parent,
3364 isservice);
3365 lcbdata->sc_err = EALREADY;
3366 return (UU_WALK_ERROR);
3367
3368 case SCF_ERROR_NOT_BOUND:
3369 case SCF_ERROR_HANDLE_MISMATCH:
3370 case SCF_ERROR_NOT_SET:
3371 default:
3372 bad_error("scf_transaction_property_new",
3373 scf_error());
3374 }
3375 }
3376
3377 val = scf_value_create(lcbdata->sc_handle);
3378 if (val == NULL) {
3379 if (scf_error() != SCF_ERROR_NO_MEMORY)
3380 bad_error("scf_value_create", scf_error());
3381
3382 entity_destroy(dependent_cbdata.sc_parent, isservice);
3383 return (stash_scferror(lcbdata));
3384 }
3385
3386 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
3387 pgrp->sc_pgroup_fmri) != 0)
3388 /* invalid should have been caught above */
3389 bad_error("scf_value_set_from_string", scf_error());
3390
3391 if (scf_entry_add_value(e, val) != 0)
3392 bad_error("scf_entry_add_value", scf_error());
3393 }
3394
3395 /* Add the property group to the target entity. */
3396
3397 dependent_cbdata.sc_handle = lcbdata->sc_handle;
3398 dependent_cbdata.sc_flags = lcbdata->sc_flags;
3399 dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
3400 dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
3401
3402 ret = entity_pgroup_import(pgrp, &dependent_cbdata);
3403
3404 entity_destroy(dependent_cbdata.sc_parent, isservice);
3405
3406 if (ret == UU_WALK_NEXT)
3407 return (ret);
3408
3409 if (ret != UU_WALK_ERROR)
3410 bad_error("entity_pgroup_import", ret);
3411
3412 switch (dependent_cbdata.sc_err) {
3413 case ECANCELED:
3414 warn(gettext("%s deleted unexpectedly.\n"),
3415 pgrp->sc_pgroup_fmri);
3416 lcbdata->sc_err = EBUSY;
3417 break;
3418
3419 case EEXIST:
3420 warn(gettext("Could not create \"%s\" dependency in %s "
3421 "(already exists).\n"), pgrp->sc_pgroup_name,
3422 pgrp->sc_pgroup_fmri);
3423 /* FALLTHROUGH */
3424
3425 default:
3426 lcbdata->sc_err = dependent_cbdata.sc_err;
3427 }
3428
3429 return (UU_WALK_ERROR);
3430 }
3431
3432 static int upgrade_dependent(const scf_property_t *, const entity_t *,
3433 const scf_snaplevel_t *, scf_transaction_t *);
3434 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
3435 const pgroup_t *);
3436
3437 /*
3438 * Upgrade uncustomized dependents of ent to those specified in ient. Read
3439 * the current dependent targets from running (the snaplevel of a running
3440 * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3441 * scf_instance_t * according to ient, otherwise). Draw the ancestral
3442 * dependent targets and dependency properties from li_dpts_pg (the
3443 * "dependents" property group in snpl) and snpl (the snaplevel which
3444 * corresponds to ent in a last-import snapshot). If li_dpts_pg is NULL, then
3445 * snpl doesn't have a "dependents" property group, and any dependents in ient
3446 * are new.
3447 *
3448 * Returns
3449 * 0 - success
3450 * ECONNABORTED - repository connection broken
3451 * ENOMEM - out of memory
3452 * ENOSPC - configd is out of resources
3453 * ECANCELED - ent was deleted
3454 * ENODEV - the entity containing li_dpts_pg was deleted
3455 * EPERM - could not modify dependents pg (permission denied) (error printed)
3456 * - couldn't upgrade dependent (permission denied) (error printed)
3457 * - couldn't create dependent (permission denied) (error printed)
3458 * EROFS - could not modify dependents pg (repository read-only)
3459 * - couldn't upgrade dependent (repository read-only)
3460 * - couldn't create dependent (repository read-only)
3461 * EACCES - could not modify dependents pg (backend access denied)
3462 * - could not upgrade dependent (backend access denied)
3463 * - could not create dependent (backend access denied)
3464 * EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3465 * - dependent target deleted (error printed)
3466 * - dependent pg changed (error printed)
3467 * EINVAL - new dependent is invalid (error printed)
3468 * EBADF - snpl is corrupt (error printed)
3469 * - snpl has corrupt pg (error printed)
3470 * - dependency pg in target is corrupt (error printed)
3471 * - target has corrupt snapshot (error printed)
3472 * EEXIST - dependency pg already existed in target service (error printed)
3473 */
3474 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)3475 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
3476 const scf_snaplevel_t *snpl, const entity_t *ient,
3477 const scf_snaplevel_t *running, void *ent)
3478 {
3479 pgroup_t *new_dpt_pgroup;
3480 scf_callback_t cbdata;
3481 int r, unseen, tx_started = 0;
3482 int have_cur_depts;
3483
3484 const char * const dependents = "dependents";
3485
3486 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3487
3488 if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
3489 /* Nothing to do. */
3490 return (0);
3491
3492 /* Fetch the current version of the "dependents" property group. */
3493 have_cur_depts = 1;
3494 if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
3495 switch (scf_error()) {
3496 case SCF_ERROR_NOT_FOUND:
3497 break;
3498
3499 case SCF_ERROR_DELETED:
3500 case SCF_ERROR_CONNECTION_BROKEN:
3501 return (scferror2errno(scf_error()));
3502
3503 case SCF_ERROR_NOT_SET:
3504 case SCF_ERROR_INVALID_ARGUMENT:
3505 case SCF_ERROR_HANDLE_MISMATCH:
3506 case SCF_ERROR_NOT_BOUND:
3507 default:
3508 bad_error("entity_get_pg", scf_error());
3509 }
3510
3511 have_cur_depts = 0;
3512 }
3513
3514 /* Fetch the running version of the "dependents" property group. */
3515 ud_run_dpts_pg_set = 0;
3516 if (running != NULL)
3517 r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
3518 else
3519 r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
3520 if (r == 0) {
3521 ud_run_dpts_pg_set = 1;
3522 } else {
3523 switch (scf_error()) {
3524 case SCF_ERROR_NOT_FOUND:
3525 break;
3526
3527 case SCF_ERROR_DELETED:
3528 case SCF_ERROR_CONNECTION_BROKEN:
3529 return (scferror2errno(scf_error()));
3530
3531 case SCF_ERROR_NOT_SET:
3532 case SCF_ERROR_INVALID_ARGUMENT:
3533 case SCF_ERROR_HANDLE_MISMATCH:
3534 case SCF_ERROR_NOT_BOUND:
3535 default:
3536 bad_error(running ? "scf_snaplevel_get_pg" :
3537 "entity_get_pg", scf_error());
3538 }
3539 }
3540
3541 /*
3542 * Clear the seen fields of the dependents, so we can tell which ones
3543 * are new.
3544 */
3545 if (uu_list_walk(ient->sc_dependents, clear_int,
3546 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3547 bad_error("uu_list_walk", uu_error());
3548
3549 if (li_dpts_pg != NULL) {
3550 /*
3551 * Each property in li_dpts_pg represents a dependent tag in
3552 * the old manifest. For each, call upgrade_dependent(),
3553 * which will change ud_cur_depts_pg or dependencies in other
3554 * services as appropriate. Note (a) that changes to
3555 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3556 * made en masse, and (b) it's ok if the entity doesn't have
3557 * a current version of the "dependents" property group,
3558 * because we'll just consider all dependents as customized
3559 * (by being deleted).
3560 */
3561
3562 if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3563 switch (scf_error()) {
3564 case SCF_ERROR_DELETED:
3565 return (ENODEV);
3566
3567 case SCF_ERROR_CONNECTION_BROKEN:
3568 return (ECONNABORTED);
3569
3570 case SCF_ERROR_HANDLE_MISMATCH:
3571 case SCF_ERROR_NOT_BOUND:
3572 case SCF_ERROR_NOT_SET:
3573 default:
3574 bad_error("scf_iter_pg_properties",
3575 scf_error());
3576 }
3577 }
3578
3579 if (have_cur_depts &&
3580 scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3581 switch (scf_error()) {
3582 case SCF_ERROR_BACKEND_ACCESS:
3583 case SCF_ERROR_BACKEND_READONLY:
3584 case SCF_ERROR_CONNECTION_BROKEN:
3585 return (scferror2errno(scf_error()));
3586
3587 case SCF_ERROR_DELETED:
3588 warn(emsg_pg_deleted, ient->sc_fmri,
3589 dependents);
3590 return (EBUSY);
3591
3592 case SCF_ERROR_PERMISSION_DENIED:
3593 warn(emsg_pg_mod_perm, dependents,
3594 ient->sc_fmri);
3595 return (scferror2errno(scf_error()));
3596
3597 case SCF_ERROR_HANDLE_MISMATCH:
3598 case SCF_ERROR_IN_USE:
3599 case SCF_ERROR_NOT_BOUND:
3600 case SCF_ERROR_NOT_SET:
3601 default:
3602 bad_error("scf_transaction_start", scf_error());
3603 }
3604 }
3605 tx_started = have_cur_depts;
3606
3607 for (;;) {
3608 r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3609 if (r == 0)
3610 break;
3611 if (r == 1) {
3612 r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3613 tx_started ? ud_tx : NULL);
3614 switch (r) {
3615 case 0:
3616 continue;
3617
3618 case ECONNABORTED:
3619 case ENOMEM:
3620 case ENOSPC:
3621 case EBADF:
3622 case EBUSY:
3623 case EINVAL:
3624 case EPERM:
3625 case EROFS:
3626 case EACCES:
3627 case EEXIST:
3628 break;
3629
3630 case ECANCELED:
3631 r = ENODEV;
3632 break;
3633
3634 default:
3635 bad_error("upgrade_dependent", r);
3636 }
3637
3638 if (tx_started)
3639 scf_transaction_destroy_children(ud_tx);
3640 return (r);
3641 }
3642 if (r != -1)
3643 bad_error("scf_iter_next_property", r);
3644
3645 switch (scf_error()) {
3646 case SCF_ERROR_DELETED:
3647 r = ENODEV;
3648 break;
3649
3650 case SCF_ERROR_CONNECTION_BROKEN:
3651 r = ECONNABORTED;
3652 break;
3653
3654 case SCF_ERROR_NOT_SET:
3655 case SCF_ERROR_INVALID_ARGUMENT:
3656 case SCF_ERROR_NOT_BOUND:
3657 case SCF_ERROR_HANDLE_MISMATCH:
3658 default:
3659 bad_error("scf_iter_next_property",
3660 scf_error());
3661 }
3662
3663 if (tx_started)
3664 scf_transaction_destroy_children(ud_tx);
3665 return (r);
3666 }
3667 }
3668
3669 /* import unseen dependents */
3670 unseen = 0;
3671 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3672 new_dpt_pgroup != NULL;
3673 new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3674 new_dpt_pgroup)) {
3675 if (!new_dpt_pgroup->sc_pgroup_seen) {
3676 unseen = 1;
3677 break;
3678 }
3679 }
3680
3681 /* If there are none, exit early. */
3682 if (unseen == 0)
3683 goto commit;
3684
3685 /* Set up for lscf_dependent_import() */
3686 cbdata.sc_handle = g_hndl;
3687 cbdata.sc_parent = ent;
3688 cbdata.sc_service = issvc;
3689 cbdata.sc_flags = 0;
3690
3691 if (!have_cur_depts) {
3692 /*
3693 * We have new dependents to import, so we need a "dependents"
3694 * property group.
3695 */
3696 if (issvc)
3697 r = scf_service_add_pg(ent, dependents,
3698 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3699 else
3700 r = scf_instance_add_pg(ent, dependents,
3701 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3702 if (r != 0) {
3703 switch (scf_error()) {
3704 case SCF_ERROR_DELETED:
3705 case SCF_ERROR_CONNECTION_BROKEN:
3706 case SCF_ERROR_BACKEND_READONLY:
3707 case SCF_ERROR_BACKEND_ACCESS:
3708 case SCF_ERROR_NO_RESOURCES:
3709 return (scferror2errno(scf_error()));
3710
3711 case SCF_ERROR_EXISTS:
3712 warn(emsg_pg_added, ient->sc_fmri, dependents);
3713 return (EBUSY);
3714
3715 case SCF_ERROR_PERMISSION_DENIED:
3716 warn(emsg_pg_add_perm, dependents,
3717 ient->sc_fmri);
3718 return (scferror2errno(scf_error()));
3719
3720 case SCF_ERROR_NOT_BOUND:
3721 case SCF_ERROR_HANDLE_MISMATCH:
3722 case SCF_ERROR_INVALID_ARGUMENT:
3723 case SCF_ERROR_NOT_SET:
3724 default:
3725 bad_error("scf_service_add_pg", scf_error());
3726 }
3727 }
3728 }
3729
3730 cbdata.sc_trans = ud_tx;
3731
3732 if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3733 switch (scf_error()) {
3734 case SCF_ERROR_CONNECTION_BROKEN:
3735 case SCF_ERROR_BACKEND_ACCESS:
3736 case SCF_ERROR_BACKEND_READONLY:
3737 return (scferror2errno(scf_error()));
3738
3739 case SCF_ERROR_DELETED:
3740 warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3741 return (EBUSY);
3742
3743 case SCF_ERROR_PERMISSION_DENIED:
3744 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3745 return (scferror2errno(scf_error()));
3746
3747 case SCF_ERROR_HANDLE_MISMATCH:
3748 case SCF_ERROR_IN_USE:
3749 case SCF_ERROR_NOT_BOUND:
3750 case SCF_ERROR_NOT_SET:
3751 default:
3752 bad_error("scf_transaction_start", scf_error());
3753 }
3754 }
3755 tx_started = 1;
3756
3757 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3758 new_dpt_pgroup != NULL;
3759 new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3760 new_dpt_pgroup)) {
3761 if (new_dpt_pgroup->sc_pgroup_seen)
3762 continue;
3763
3764 if (ud_run_dpts_pg_set) {
3765 /*
3766 * If the dependent is already there, then we have
3767 * a conflict.
3768 */
3769 if (scf_pg_get_property(ud_run_dpts_pg,
3770 new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3771 r = handle_dependent_conflict(ient, ud_prop,
3772 new_dpt_pgroup);
3773 switch (r) {
3774 case 0:
3775 continue;
3776
3777 case ECONNABORTED:
3778 case ENOMEM:
3779 case EBUSY:
3780 case EBADF:
3781 case EINVAL:
3782 scf_transaction_destroy_children(ud_tx);
3783 return (r);
3784
3785 default:
3786 bad_error("handle_dependent_conflict",
3787 r);
3788 }
3789 } else {
3790 switch (scf_error()) {
3791 case SCF_ERROR_NOT_FOUND:
3792 break;
3793
3794 case SCF_ERROR_INVALID_ARGUMENT:
3795 warn(emsg_fmri_invalid_pg_name,
3796 ient->sc_fmri,
3797 new_dpt_pgroup->sc_pgroup_name);
3798 scf_transaction_destroy_children(ud_tx);
3799 return (EINVAL);
3800
3801 case SCF_ERROR_DELETED:
3802 warn(emsg_pg_deleted, ient->sc_fmri,
3803 new_dpt_pgroup->sc_pgroup_name);
3804 scf_transaction_destroy_children(ud_tx);
3805 return (EBUSY);
3806
3807 case SCF_ERROR_CONNECTION_BROKEN:
3808 scf_transaction_destroy_children(ud_tx);
3809 return (ECONNABORTED);
3810
3811 case SCF_ERROR_NOT_BOUND:
3812 case SCF_ERROR_HANDLE_MISMATCH:
3813 case SCF_ERROR_NOT_SET:
3814 default:
3815 bad_error("scf_pg_get_property",
3816 scf_error());
3817 }
3818 }
3819 }
3820
3821 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3822 if (r != UU_WALK_NEXT) {
3823 if (r != UU_WALK_ERROR)
3824 bad_error("lscf_dependent_import", r);
3825
3826 if (cbdata.sc_err == EALREADY) {
3827 /* Collisions were handled preemptively. */
3828 bad_error("lscf_dependent_import",
3829 cbdata.sc_err);
3830 }
3831
3832 scf_transaction_destroy_children(ud_tx);
3833 return (cbdata.sc_err);
3834 }
3835 }
3836
3837 commit:
3838 if (!tx_started)
3839 return (0);
3840
3841 r = scf_transaction_commit(ud_tx);
3842
3843 scf_transaction_destroy_children(ud_tx);
3844
3845 switch (r) {
3846 case 1:
3847 return (0);
3848
3849 case 0:
3850 warn(emsg_pg_changed, ient->sc_fmri, dependents);
3851 return (EBUSY);
3852
3853 case -1:
3854 break;
3855
3856 default:
3857 bad_error("scf_transaction_commit", r);
3858 }
3859
3860 switch (scf_error()) {
3861 case SCF_ERROR_CONNECTION_BROKEN:
3862 case SCF_ERROR_BACKEND_READONLY:
3863 case SCF_ERROR_BACKEND_ACCESS:
3864 case SCF_ERROR_NO_RESOURCES:
3865 return (scferror2errno(scf_error()));
3866
3867 case SCF_ERROR_DELETED:
3868 warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3869 return (EBUSY);
3870
3871 case SCF_ERROR_PERMISSION_DENIED:
3872 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3873 return (scferror2errno(scf_error()));
3874
3875 case SCF_ERROR_NOT_BOUND:
3876 case SCF_ERROR_INVALID_ARGUMENT:
3877 case SCF_ERROR_NOT_SET:
3878 default:
3879 bad_error("scf_transaction_destroy", scf_error());
3880 /* NOTREACHED */
3881 }
3882 }
3883
3884 /*
3885 * Used to add the manifests to the list of currently supported manifests.
3886 * We can modify the existing manifest list removing entries if the files
3887 * don't exist.
3888 *
3889 * Get the old list and the new file name
3890 * If the new file name is in the list return
3891 * If not then add the file to the list.
3892 * As we process the list check to see if the files in the old list exist
3893 * if not then remove the file from the list.
3894 * Commit the list of manifest file names.
3895 *
3896 */
3897 static int
upgrade_manifestfiles(pgroup_t * pg,const entity_t * ient,const scf_snaplevel_t * running,void * ent)3898 upgrade_manifestfiles(pgroup_t *pg, const entity_t *ient,
3899 const scf_snaplevel_t *running, void *ent)
3900 {
3901 scf_propertygroup_t *ud_mfsts_pg = NULL;
3902 scf_property_t *ud_prop = NULL;
3903 scf_iter_t *ud_prop_iter;
3904 scf_value_t *fname_value;
3905 scf_callback_t cbdata;
3906 pgroup_t *mfst_pgroup;
3907 property_t *mfst_prop;
3908 property_t *old_prop;
3909 char *pname;
3910 char *fval;
3911 char *old_pname;
3912 char *old_fval;
3913 int no_upgrade_pg;
3914 int mfst_seen;
3915 int r;
3916
3917 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3918
3919 /*
3920 * This should always be the service base on the code
3921 * path, and the fact that the manifests pg is a service
3922 * level property group only.
3923 */
3924 ud_mfsts_pg = scf_pg_create(g_hndl);
3925 ud_prop = scf_property_create(g_hndl);
3926 ud_prop_iter = scf_iter_create(g_hndl);
3927 fname_value = scf_value_create(g_hndl);
3928
3929 /* Fetch the "manifests" property group */
3930 no_upgrade_pg = 0;
3931 r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3932 ud_mfsts_pg);
3933 if (r != 0) {
3934 switch (scf_error()) {
3935 case SCF_ERROR_NOT_FOUND:
3936 no_upgrade_pg = 1;
3937 break;
3938
3939 case SCF_ERROR_DELETED:
3940 case SCF_ERROR_CONNECTION_BROKEN:
3941 return (scferror2errno(scf_error()));
3942
3943 case SCF_ERROR_NOT_SET:
3944 case SCF_ERROR_INVALID_ARGUMENT:
3945 case SCF_ERROR_HANDLE_MISMATCH:
3946 case SCF_ERROR_NOT_BOUND:
3947 default:
3948 bad_error(running ? "scf_snaplevel_get_pg" :
3949 "entity_get_pg", scf_error());
3950 }
3951 }
3952
3953 if (no_upgrade_pg) {
3954 cbdata.sc_handle = g_hndl;
3955 cbdata.sc_parent = ent;
3956 cbdata.sc_service = issvc;
3957 cbdata.sc_flags = SCI_FORCE;
3958 cbdata.sc_source_fmri = ient->sc_fmri;
3959 cbdata.sc_target_fmri = ient->sc_fmri;
3960
3961 if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3962 return (cbdata.sc_err);
3963
3964 return (0);
3965 }
3966
3967 /* Fetch the new manifests property group */
3968 for (mfst_pgroup = uu_list_first(ient->sc_pgroups);
3969 mfst_pgroup != NULL;
3970 mfst_pgroup = uu_list_next(ient->sc_pgroups, mfst_pgroup)) {
3971 if (strcmp(mfst_pgroup->sc_pgroup_name,
3972 SCF_PG_MANIFESTFILES) == 0)
3973 break;
3974 }
3975
3976 if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3977 SCF_SUCCESS)
3978 return (-1);
3979
3980 if ((pname = malloc(MAXPATHLEN)) == NULL)
3981 return (ENOMEM);
3982 if ((fval = malloc(MAXPATHLEN)) == NULL) {
3983 free(pname);
3984 return (ENOMEM);
3985 }
3986
3987 while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
3988 mfst_seen = 0;
3989 if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
3990 continue;
3991
3992 for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
3993 mfst_prop != NULL;
3994 mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
3995 mfst_prop)) {
3996 if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
3997 mfst_seen = 1;
3998 }
3999 }
4000
4001 /*
4002 * If the manifest is not seen then add it to the new mfst
4003 * property list to get proccessed into the repo.
4004 */
4005 if (mfst_seen == 0) {
4006 /*
4007 * If we cannot get the value then there is no
4008 * reason to attempt to attach the value to
4009 * the property group
4010 */
4011 if (prop_get_val(ud_prop, fname_value) == 0 &&
4012 scf_value_get_astring(fname_value, fval,
4013 MAXPATHLEN) != -1) {
4014 old_pname = safe_strdup(pname);
4015 old_fval = safe_strdup(fval);
4016 old_prop = internal_property_create(old_pname,
4017 SCF_TYPE_ASTRING, 1, old_fval);
4018
4019 /*
4020 * Already checked to see if the property exists
4021 * in the group, and it does not.
4022 */
4023 (void) internal_attach_property(mfst_pgroup,
4024 old_prop);
4025 }
4026 }
4027 }
4028 free(pname);
4029 free(fval);
4030
4031 cbdata.sc_handle = g_hndl;
4032 cbdata.sc_parent = ent;
4033 cbdata.sc_service = issvc;
4034 cbdata.sc_flags = SCI_FORCE;
4035 cbdata.sc_source_fmri = ient->sc_fmri;
4036 cbdata.sc_target_fmri = ient->sc_fmri;
4037
4038 if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
4039 return (cbdata.sc_err);
4040
4041 return (r);
4042 }
4043
4044 /*
4045 * prop is taken to be a property in the "dependents" property group of snpl,
4046 * which is taken to be the snaplevel of a last-import snapshot corresponding
4047 * to ient. If prop is a valid dependents property, upgrade the dependent it
4048 * represents according to the repository & ient. If ud_run_dpts_pg_set is
4049 * true, then ud_run_dpts_pg is taken to be the "dependents" property group
4050 * of the entity ient represents (possibly in the running snapshot). If it
4051 * needs to be changed, an entry will be added to tx, if not NULL.
4052 *
4053 * Returns
4054 * 0 - success
4055 * ECONNABORTED - repository connection broken
4056 * ENOMEM - out of memory
4057 * ENOSPC - configd was out of resources
4058 * ECANCELED - snpl's entity was deleted
4059 * EINVAL - dependent target is invalid (error printed)
4060 * - dependent is invalid (error printed)
4061 * EBADF - snpl is corrupt (error printed)
4062 * - snpl has corrupt pg (error printed)
4063 * - dependency pg in target is corrupt (error printed)
4064 * - running snapshot in dependent is missing snaplevel (error printed)
4065 * EPERM - couldn't delete dependency pg (permission denied) (error printed)
4066 * - couldn't create dependent (permission denied) (error printed)
4067 * - couldn't modify dependent pg (permission denied) (error printed)
4068 * EROFS - couldn't delete dependency pg (repository read-only)
4069 * - couldn't create dependent (repository read-only)
4070 * EACCES - couldn't delete dependency pg (backend access denied)
4071 * - couldn't create dependent (backend access denied)
4072 * EBUSY - ud_run_dpts_pg was deleted (error printed)
4073 * - tx's pg was deleted (error printed)
4074 * - dependent pg was changed or deleted (error printed)
4075 * EEXIST - dependency pg already exists in new target (error printed)
4076 */
4077 static int
upgrade_dependent(const scf_property_t * prop,const entity_t * ient,const scf_snaplevel_t * snpl,scf_transaction_t * tx)4078 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
4079 const scf_snaplevel_t *snpl, scf_transaction_t *tx)
4080 {
4081 pgroup_t pgrp;
4082 scf_type_t ty;
4083 pgroup_t *new_dpt_pgroup;
4084 pgroup_t *old_dpt_pgroup = NULL;
4085 pgroup_t *current_pg;
4086 pgroup_t *dpt;
4087 scf_callback_t cbdata;
4088 int tissvc;
4089 void *target_ent;
4090 scf_error_t serr;
4091 int r;
4092 scf_transaction_entry_t *ent;
4093
4094 const char * const cf_inval = gettext("Conflict upgrading %s "
4095 "(dependent \"%s\" has invalid dependents property).\n");
4096 const char * const cf_missing = gettext("Conflict upgrading %s "
4097 "(dependent \"%s\" is missing).\n");
4098 const char * const cf_newdpg = gettext("Conflict upgrading %s "
4099 "(dependent \"%s\" has new dependency property group).\n");
4100 const char * const cf_newtarg = gettext("Conflict upgrading %s "
4101 "(dependent \"%s\" has new target).\n");
4102 const char * const li_corrupt =
4103 gettext("%s: \"last-import\" snapshot is corrupt.\n");
4104 const char * const upgrading =
4105 gettext("%s: Upgrading dependent \"%s\".\n");
4106 const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
4107 "corrupt (missing snaplevel).\n");
4108
4109 if (scf_property_type(prop, &ty) != 0) {
4110 switch (scf_error()) {
4111 case SCF_ERROR_DELETED:
4112 case SCF_ERROR_CONNECTION_BROKEN:
4113 return (scferror2errno(scf_error()));
4114
4115 case SCF_ERROR_NOT_BOUND:
4116 case SCF_ERROR_NOT_SET:
4117 default:
4118 bad_error("scf_property_type", scf_error());
4119 }
4120 }
4121
4122 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4123 warn(li_corrupt, ient->sc_fmri);
4124 return (EBADF);
4125 }
4126
4127 /*
4128 * prop represents a dependent in the old manifest. It is named after
4129 * the dependent.
4130 */
4131 if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
4132 switch (scf_error()) {
4133 case SCF_ERROR_DELETED:
4134 case SCF_ERROR_CONNECTION_BROKEN:
4135 return (scferror2errno(scf_error()));
4136
4137 case SCF_ERROR_NOT_BOUND:
4138 case SCF_ERROR_NOT_SET:
4139 default:
4140 bad_error("scf_property_get_name", scf_error());
4141 }
4142 }
4143
4144 /* See if it's in the new manifest. */
4145 pgrp.sc_pgroup_name = ud_name;
4146 new_dpt_pgroup =
4147 uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
4148
4149 /* If it's not, delete it... if it hasn't been customized. */
4150 if (new_dpt_pgroup == NULL) {
4151 if (!ud_run_dpts_pg_set)
4152 return (0);
4153
4154 if (scf_property_get_value(prop, ud_val) != 0) {
4155 switch (scf_error()) {
4156 case SCF_ERROR_NOT_FOUND:
4157 case SCF_ERROR_CONSTRAINT_VIOLATED:
4158 warn(li_corrupt, ient->sc_fmri);
4159 return (EBADF);
4160
4161 case SCF_ERROR_DELETED:
4162 case SCF_ERROR_CONNECTION_BROKEN:
4163 return (scferror2errno(scf_error()));
4164
4165 case SCF_ERROR_HANDLE_MISMATCH:
4166 case SCF_ERROR_NOT_BOUND:
4167 case SCF_ERROR_NOT_SET:
4168 case SCF_ERROR_PERMISSION_DENIED:
4169 default:
4170 bad_error("scf_property_get_value",
4171 scf_error());
4172 }
4173 }
4174
4175 if (scf_value_get_as_string(ud_val, ud_oldtarg,
4176 max_scf_value_len + 1) < 0)
4177 bad_error("scf_value_get_as_string", scf_error());
4178
4179 if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
4180 0) {
4181 switch (scf_error()) {
4182 case SCF_ERROR_NOT_FOUND:
4183 return (0);
4184
4185 case SCF_ERROR_CONNECTION_BROKEN:
4186 return (scferror2errno(scf_error()));
4187
4188 case SCF_ERROR_DELETED:
4189 warn(emsg_pg_deleted, ient->sc_fmri,
4190 "dependents");
4191 return (EBUSY);
4192
4193 case SCF_ERROR_INVALID_ARGUMENT:
4194 case SCF_ERROR_NOT_BOUND:
4195 case SCF_ERROR_HANDLE_MISMATCH:
4196 case SCF_ERROR_NOT_SET:
4197 default:
4198 bad_error("scf_pg_get_property", scf_error());
4199 }
4200 }
4201 if (scf_property_get_value(ud_prop, ud_val) != 0) {
4202 switch (scf_error()) {
4203 case SCF_ERROR_NOT_FOUND:
4204 case SCF_ERROR_CONSTRAINT_VIOLATED:
4205 warn(cf_inval, ient->sc_fmri, ud_name);
4206 return (0);
4207
4208 case SCF_ERROR_DELETED:
4209 case SCF_ERROR_CONNECTION_BROKEN:
4210 return (scferror2errno(scf_error()));
4211
4212 case SCF_ERROR_HANDLE_MISMATCH:
4213 case SCF_ERROR_NOT_BOUND:
4214 case SCF_ERROR_NOT_SET:
4215 case SCF_ERROR_PERMISSION_DENIED:
4216 default:
4217 bad_error("scf_property_get_value",
4218 scf_error());
4219 }
4220 }
4221
4222 ty = scf_value_type(ud_val);
4223 assert(ty != SCF_TYPE_INVALID);
4224 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4225 warn(cf_inval, ient->sc_fmri, ud_name);
4226 return (0);
4227 }
4228
4229 if (scf_value_get_as_string(ud_val, ud_ctarg,
4230 max_scf_value_len + 1) < 0)
4231 bad_error("scf_value_get_as_string", scf_error());
4232
4233 r = fmri_equal(ud_ctarg, ud_oldtarg);
4234 switch (r) {
4235 case 1:
4236 break;
4237
4238 case 0:
4239 case -1: /* warn? */
4240 warn(cf_newtarg, ient->sc_fmri, ud_name);
4241 return (0);
4242
4243 case -2:
4244 warn(li_corrupt, ient->sc_fmri);
4245 return (EBADF);
4246
4247 default:
4248 bad_error("fmri_equal", r);
4249 }
4250
4251 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4252 switch (scf_error()) {
4253 case SCF_ERROR_NOT_FOUND:
4254 warn(li_corrupt, ient->sc_fmri);
4255 return (EBADF);
4256
4257 case SCF_ERROR_DELETED:
4258 case SCF_ERROR_CONNECTION_BROKEN:
4259 return (scferror2errno(scf_error()));
4260
4261 case SCF_ERROR_NOT_BOUND:
4262 case SCF_ERROR_HANDLE_MISMATCH:
4263 case SCF_ERROR_INVALID_ARGUMENT:
4264 case SCF_ERROR_NOT_SET:
4265 default:
4266 bad_error("scf_snaplevel_get_pg", scf_error());
4267 }
4268 }
4269
4270 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4271 snap_lastimport);
4272 switch (r) {
4273 case 0:
4274 break;
4275
4276 case ECANCELED:
4277 case ECONNABORTED:
4278 case ENOMEM:
4279 case EBADF:
4280 return (r);
4281
4282 case EACCES:
4283 default:
4284 bad_error("load_pg", r);
4285 }
4286
4287 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4288 switch (serr) {
4289 case SCF_ERROR_NONE:
4290 break;
4291
4292 case SCF_ERROR_NO_MEMORY:
4293 internal_pgroup_free(old_dpt_pgroup);
4294 return (ENOMEM);
4295
4296 case SCF_ERROR_NOT_FOUND:
4297 internal_pgroup_free(old_dpt_pgroup);
4298 goto delprop;
4299
4300 case SCF_ERROR_CONSTRAINT_VIOLATED: /* caught above */
4301 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
4302 default:
4303 bad_error("fmri_to_entity", serr);
4304 }
4305
4306 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4307 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4308 switch (r) {
4309 case 0:
4310 break;
4311
4312 case ECONNABORTED:
4313 internal_pgroup_free(old_dpt_pgroup);
4314 return (r);
4315
4316 case ECANCELED:
4317 case ENOENT:
4318 internal_pgroup_free(old_dpt_pgroup);
4319 goto delprop;
4320
4321 case EBADF:
4322 warn(r_no_lvl, ud_ctarg);
4323 internal_pgroup_free(old_dpt_pgroup);
4324 return (r);
4325
4326 case EINVAL:
4327 default:
4328 bad_error("entity_get_running_pg", r);
4329 }
4330
4331 /* load it */
4332 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4333 switch (r) {
4334 case 0:
4335 break;
4336
4337 case ECANCELED:
4338 internal_pgroup_free(old_dpt_pgroup);
4339 goto delprop;
4340
4341 case ECONNABORTED:
4342 case ENOMEM:
4343 case EBADF:
4344 internal_pgroup_free(old_dpt_pgroup);
4345 return (r);
4346
4347 case EACCES:
4348 default:
4349 bad_error("load_pg", r);
4350 }
4351
4352 /* compare property groups */
4353 if (!pg_equal(old_dpt_pgroup, current_pg)) {
4354 warn(cf_newdpg, ient->sc_fmri, ud_name);
4355 internal_pgroup_free(old_dpt_pgroup);
4356 internal_pgroup_free(current_pg);
4357 return (0);
4358 }
4359
4360 internal_pgroup_free(old_dpt_pgroup);
4361 internal_pgroup_free(current_pg);
4362
4363 if (g_verbose)
4364 warn(gettext("%s: Deleting dependent \"%s\".\n"),
4365 ient->sc_fmri, ud_name);
4366
4367 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4368 switch (scf_error()) {
4369 case SCF_ERROR_NOT_FOUND:
4370 case SCF_ERROR_DELETED:
4371 internal_pgroup_free(old_dpt_pgroup);
4372 goto delprop;
4373
4374 case SCF_ERROR_CONNECTION_BROKEN:
4375 internal_pgroup_free(old_dpt_pgroup);
4376 return (ECONNABORTED);
4377
4378 case SCF_ERROR_NOT_SET:
4379 case SCF_ERROR_INVALID_ARGUMENT:
4380 case SCF_ERROR_HANDLE_MISMATCH:
4381 case SCF_ERROR_NOT_BOUND:
4382 default:
4383 bad_error("entity_get_pg", scf_error());
4384 }
4385 }
4386
4387 if (scf_pg_delete(ud_pg) != 0) {
4388 switch (scf_error()) {
4389 case SCF_ERROR_DELETED:
4390 break;
4391
4392 case SCF_ERROR_CONNECTION_BROKEN:
4393 case SCF_ERROR_BACKEND_READONLY:
4394 case SCF_ERROR_BACKEND_ACCESS:
4395 return (scferror2errno(scf_error()));
4396
4397 case SCF_ERROR_PERMISSION_DENIED:
4398 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4399 return (scferror2errno(scf_error()));
4400
4401 case SCF_ERROR_NOT_SET:
4402 default:
4403 bad_error("scf_pg_delete", scf_error());
4404 }
4405 }
4406
4407 /*
4408 * This service was changed, so it must be refreshed. But
4409 * since it's not mentioned in the new manifest, we have to
4410 * record its FMRI here for use later. We record the name
4411 * & the entity (via sc_parent) in case we need to print error
4412 * messages during the refresh.
4413 */
4414 dpt = internal_pgroup_new();
4415 if (dpt == NULL)
4416 return (ENOMEM);
4417 dpt->sc_pgroup_name = strdup(ud_name);
4418 dpt->sc_pgroup_fmri = strdup(ud_ctarg);
4419 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4420 return (ENOMEM);
4421 dpt->sc_parent = (entity_t *)ient;
4422 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4423 uu_die(gettext("libuutil error: %s\n"),
4424 uu_strerror(uu_error()));
4425
4426 delprop:
4427 if (tx == NULL)
4428 return (0);
4429
4430 ent = scf_entry_create(g_hndl);
4431 if (ent == NULL)
4432 return (ENOMEM);
4433
4434 if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
4435 scf_entry_destroy(ent);
4436 switch (scf_error()) {
4437 case SCF_ERROR_DELETED:
4438 warn(emsg_pg_deleted, ient->sc_fmri,
4439 "dependents");
4440 return (EBUSY);
4441
4442 case SCF_ERROR_CONNECTION_BROKEN:
4443 return (scferror2errno(scf_error()));
4444
4445 case SCF_ERROR_NOT_FOUND:
4446 break;
4447
4448 case SCF_ERROR_HANDLE_MISMATCH:
4449 case SCF_ERROR_NOT_BOUND:
4450 case SCF_ERROR_INVALID_ARGUMENT:
4451 case SCF_ERROR_NOT_SET:
4452 default:
4453 bad_error("scf_transaction_property_delete",
4454 scf_error());
4455 }
4456 }
4457
4458 return (0);
4459 }
4460
4461 new_dpt_pgroup->sc_pgroup_seen = 1;
4462
4463 /*
4464 * Decide whether the dependent has changed in the manifest.
4465 */
4466 /* Compare the target. */
4467 if (scf_property_get_value(prop, ud_val) != 0) {
4468 switch (scf_error()) {
4469 case SCF_ERROR_NOT_FOUND:
4470 case SCF_ERROR_CONSTRAINT_VIOLATED:
4471 warn(li_corrupt, ient->sc_fmri);
4472 return (EBADF);
4473
4474 case SCF_ERROR_DELETED:
4475 case SCF_ERROR_CONNECTION_BROKEN:
4476 return (scferror2errno(scf_error()));
4477
4478 case SCF_ERROR_HANDLE_MISMATCH:
4479 case SCF_ERROR_NOT_BOUND:
4480 case SCF_ERROR_NOT_SET:
4481 case SCF_ERROR_PERMISSION_DENIED:
4482 default:
4483 bad_error("scf_property_get_value", scf_error());
4484 }
4485 }
4486
4487 if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
4488 0)
4489 bad_error("scf_value_get_as_string", scf_error());
4490
4491 /*
4492 * If the fmri's are not equal then the old fmri will need to
4493 * be refreshed to ensure that the changes are properly updated
4494 * in that service.
4495 */
4496 r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
4497 switch (r) {
4498 case 0:
4499 dpt = internal_pgroup_new();
4500 if (dpt == NULL)
4501 return (ENOMEM);
4502 dpt->sc_pgroup_name = strdup(ud_name);
4503 dpt->sc_pgroup_fmri = strdup(ud_oldtarg);
4504 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4505 return (ENOMEM);
4506 dpt->sc_parent = (entity_t *)ient;
4507 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4508 uu_die(gettext("libuutil error: %s\n"),
4509 uu_strerror(uu_error()));
4510 break;
4511
4512 case 1:
4513 /* Compare the dependency pgs. */
4514 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4515 switch (scf_error()) {
4516 case SCF_ERROR_NOT_FOUND:
4517 warn(li_corrupt, ient->sc_fmri);
4518 return (EBADF);
4519
4520 case SCF_ERROR_DELETED:
4521 case SCF_ERROR_CONNECTION_BROKEN:
4522 return (scferror2errno(scf_error()));
4523
4524 case SCF_ERROR_NOT_BOUND:
4525 case SCF_ERROR_HANDLE_MISMATCH:
4526 case SCF_ERROR_INVALID_ARGUMENT:
4527 case SCF_ERROR_NOT_SET:
4528 default:
4529 bad_error("scf_snaplevel_get_pg", scf_error());
4530 }
4531 }
4532
4533 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4534 snap_lastimport);
4535 switch (r) {
4536 case 0:
4537 break;
4538
4539 case ECANCELED:
4540 case ECONNABORTED:
4541 case ENOMEM:
4542 case EBADF:
4543 return (r);
4544
4545 case EACCES:
4546 default:
4547 bad_error("load_pg", r);
4548 }
4549
4550 if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4551 /* no change, leave customizations */
4552 internal_pgroup_free(old_dpt_pgroup);
4553 return (0);
4554 }
4555 break;
4556
4557 case -1:
4558 warn(li_corrupt, ient->sc_fmri);
4559 return (EBADF);
4560
4561 case -2:
4562 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4563 ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4564 return (EINVAL);
4565
4566 default:
4567 bad_error("fmri_equal", r);
4568 }
4569
4570 /*
4571 * The dependent has changed in the manifest. Upgrade the current
4572 * properties if they haven't been customized.
4573 */
4574
4575 /*
4576 * If new_dpt_pgroup->sc_override, then act as though the property
4577 * group hasn't been customized.
4578 */
4579 if (new_dpt_pgroup->sc_pgroup_override) {
4580 (void) strcpy(ud_ctarg, ud_oldtarg);
4581 goto nocust;
4582 }
4583
4584 if (!ud_run_dpts_pg_set) {
4585 warn(cf_missing, ient->sc_fmri, ud_name);
4586 r = 0;
4587 goto out;
4588 } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4589 switch (scf_error()) {
4590 case SCF_ERROR_NOT_FOUND:
4591 warn(cf_missing, ient->sc_fmri, ud_name);
4592 r = 0;
4593 goto out;
4594
4595 case SCF_ERROR_CONNECTION_BROKEN:
4596 r = scferror2errno(scf_error());
4597 goto out;
4598
4599 case SCF_ERROR_DELETED:
4600 warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4601 r = EBUSY;
4602 goto out;
4603
4604 case SCF_ERROR_INVALID_ARGUMENT:
4605 case SCF_ERROR_NOT_BOUND:
4606 case SCF_ERROR_HANDLE_MISMATCH:
4607 case SCF_ERROR_NOT_SET:
4608 default:
4609 bad_error("scf_pg_get_property", scf_error());
4610 }
4611 }
4612
4613 if (scf_property_get_value(ud_prop, ud_val) != 0) {
4614 switch (scf_error()) {
4615 case SCF_ERROR_NOT_FOUND:
4616 case SCF_ERROR_CONSTRAINT_VIOLATED:
4617 warn(cf_inval, ient->sc_fmri, ud_name);
4618 r = 0;
4619 goto out;
4620
4621 case SCF_ERROR_DELETED:
4622 case SCF_ERROR_CONNECTION_BROKEN:
4623 r = scferror2errno(scf_error());
4624 goto out;
4625
4626 case SCF_ERROR_HANDLE_MISMATCH:
4627 case SCF_ERROR_NOT_BOUND:
4628 case SCF_ERROR_NOT_SET:
4629 case SCF_ERROR_PERMISSION_DENIED:
4630 default:
4631 bad_error("scf_property_get_value", scf_error());
4632 }
4633 }
4634
4635 ty = scf_value_type(ud_val);
4636 assert(ty != SCF_TYPE_INVALID);
4637 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4638 warn(cf_inval, ient->sc_fmri, ud_name);
4639 r = 0;
4640 goto out;
4641 }
4642 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4643 0)
4644 bad_error("scf_value_get_as_string", scf_error());
4645
4646 r = fmri_equal(ud_ctarg, ud_oldtarg);
4647 if (r == -1) {
4648 warn(cf_inval, ient->sc_fmri, ud_name);
4649 r = 0;
4650 goto out;
4651 } else if (r == -2) {
4652 warn(li_corrupt, ient->sc_fmri);
4653 r = EBADF;
4654 goto out;
4655 } else if (r == 0) {
4656 /*
4657 * Target has been changed. Only abort now if it's been
4658 * changed to something other than what's in the manifest.
4659 */
4660 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4661 if (r == -1) {
4662 warn(cf_inval, ient->sc_fmri, ud_name);
4663 r = 0;
4664 goto out;
4665 } else if (r == 0) {
4666 warn(cf_newtarg, ient->sc_fmri, ud_name);
4667 r = 0;
4668 goto out;
4669 } else if (r != 1) {
4670 /* invalid sc_pgroup_fmri caught above */
4671 bad_error("fmri_equal", r);
4672 }
4673
4674 /*
4675 * Fetch the current dependency pg. If it's what the manifest
4676 * says, then no problem.
4677 */
4678 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4679 switch (serr) {
4680 case SCF_ERROR_NONE:
4681 break;
4682
4683 case SCF_ERROR_NOT_FOUND:
4684 warn(cf_missing, ient->sc_fmri, ud_name);
4685 r = 0;
4686 goto out;
4687
4688 case SCF_ERROR_NO_MEMORY:
4689 r = ENOMEM;
4690 goto out;
4691
4692 case SCF_ERROR_CONSTRAINT_VIOLATED:
4693 case SCF_ERROR_INVALID_ARGUMENT:
4694 default:
4695 bad_error("fmri_to_entity", serr);
4696 }
4697
4698 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4699 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4700 switch (r) {
4701 case 0:
4702 break;
4703
4704 case ECONNABORTED:
4705 goto out;
4706
4707 case ECANCELED:
4708 case ENOENT:
4709 warn(cf_missing, ient->sc_fmri, ud_name);
4710 r = 0;
4711 goto out;
4712
4713 case EBADF:
4714 warn(r_no_lvl, ud_ctarg);
4715 goto out;
4716
4717 case EINVAL:
4718 default:
4719 bad_error("entity_get_running_pg", r);
4720 }
4721
4722 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4723 switch (r) {
4724 case 0:
4725 break;
4726
4727 case ECANCELED:
4728 warn(cf_missing, ient->sc_fmri, ud_name);
4729 r = 0;
4730 goto out;
4731
4732 case ECONNABORTED:
4733 case ENOMEM:
4734 case EBADF:
4735 goto out;
4736
4737 case EACCES:
4738 default:
4739 bad_error("load_pg", r);
4740 }
4741
4742 if (!pg_equal(current_pg, new_dpt_pgroup))
4743 warn(cf_newdpg, ient->sc_fmri, ud_name);
4744 internal_pgroup_free(current_pg);
4745 r = 0;
4746 goto out;
4747 } else if (r != 1) {
4748 bad_error("fmri_equal", r);
4749 }
4750
4751 nocust:
4752 /*
4753 * Target has not been customized. Check the dependency property
4754 * group.
4755 */
4756
4757 if (old_dpt_pgroup == NULL) {
4758 if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4759 ud_pg) != 0) {
4760 switch (scf_error()) {
4761 case SCF_ERROR_NOT_FOUND:
4762 warn(li_corrupt, ient->sc_fmri);
4763 return (EBADF);
4764
4765 case SCF_ERROR_DELETED:
4766 case SCF_ERROR_CONNECTION_BROKEN:
4767 return (scferror2errno(scf_error()));
4768
4769 case SCF_ERROR_NOT_BOUND:
4770 case SCF_ERROR_HANDLE_MISMATCH:
4771 case SCF_ERROR_INVALID_ARGUMENT:
4772 case SCF_ERROR_NOT_SET:
4773 default:
4774 bad_error("scf_snaplevel_get_pg", scf_error());
4775 }
4776 }
4777
4778 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4779 snap_lastimport);
4780 switch (r) {
4781 case 0:
4782 break;
4783
4784 case ECANCELED:
4785 case ECONNABORTED:
4786 case ENOMEM:
4787 case EBADF:
4788 return (r);
4789
4790 case EACCES:
4791 default:
4792 bad_error("load_pg", r);
4793 }
4794 }
4795 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4796 switch (serr) {
4797 case SCF_ERROR_NONE:
4798 break;
4799
4800 case SCF_ERROR_NOT_FOUND:
4801 warn(cf_missing, ient->sc_fmri, ud_name);
4802 r = 0;
4803 goto out;
4804
4805 case SCF_ERROR_NO_MEMORY:
4806 r = ENOMEM;
4807 goto out;
4808
4809 case SCF_ERROR_CONSTRAINT_VIOLATED:
4810 case SCF_ERROR_INVALID_ARGUMENT:
4811 default:
4812 bad_error("fmri_to_entity", serr);
4813 }
4814
4815 r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4816 ud_iter2, ud_inst, imp_snap, ud_snpl);
4817 switch (r) {
4818 case 0:
4819 break;
4820
4821 case ECONNABORTED:
4822 goto out;
4823
4824 case ECANCELED:
4825 case ENOENT:
4826 warn(cf_missing, ient->sc_fmri, ud_name);
4827 r = 0;
4828 goto out;
4829
4830 case EBADF:
4831 warn(r_no_lvl, ud_ctarg);
4832 goto out;
4833
4834 case EINVAL:
4835 default:
4836 bad_error("entity_get_running_pg", r);
4837 }
4838
4839 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4840 switch (r) {
4841 case 0:
4842 break;
4843
4844 case ECANCELED:
4845 warn(cf_missing, ient->sc_fmri, ud_name);
4846 goto out;
4847
4848 case ECONNABORTED:
4849 case ENOMEM:
4850 case EBADF:
4851 goto out;
4852
4853 case EACCES:
4854 default:
4855 bad_error("load_pg", r);
4856 }
4857
4858 if (!pg_equal(current_pg, old_dpt_pgroup)) {
4859 if (!pg_equal(current_pg, new_dpt_pgroup))
4860 warn(cf_newdpg, ient->sc_fmri, ud_name);
4861 internal_pgroup_free(current_pg);
4862 r = 0;
4863 goto out;
4864 }
4865
4866 /* Uncustomized. Upgrade. */
4867
4868 r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4869 switch (r) {
4870 case 1:
4871 if (pg_equal(current_pg, new_dpt_pgroup)) {
4872 /* Already upgraded. */
4873 internal_pgroup_free(current_pg);
4874 r = 0;
4875 goto out;
4876 }
4877
4878 internal_pgroup_free(current_pg);
4879
4880 /* upgrade current_pg */
4881 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4882 switch (scf_error()) {
4883 case SCF_ERROR_CONNECTION_BROKEN:
4884 r = scferror2errno(scf_error());
4885 goto out;
4886
4887 case SCF_ERROR_DELETED:
4888 warn(cf_missing, ient->sc_fmri, ud_name);
4889 r = 0;
4890 goto out;
4891
4892 case SCF_ERROR_NOT_FOUND:
4893 break;
4894
4895 case SCF_ERROR_INVALID_ARGUMENT:
4896 case SCF_ERROR_NOT_BOUND:
4897 case SCF_ERROR_NOT_SET:
4898 case SCF_ERROR_HANDLE_MISMATCH:
4899 default:
4900 bad_error("entity_get_pg", scf_error());
4901 }
4902
4903 if (tissvc)
4904 r = scf_service_add_pg(target_ent, ud_name,
4905 SCF_GROUP_DEPENDENCY, 0, ud_pg);
4906 else
4907 r = scf_instance_add_pg(target_ent, ud_name,
4908 SCF_GROUP_DEPENDENCY, 0, ud_pg);
4909 if (r != 0) {
4910 switch (scf_error()) {
4911 case SCF_ERROR_CONNECTION_BROKEN:
4912 case SCF_ERROR_NO_RESOURCES:
4913 case SCF_ERROR_BACKEND_READONLY:
4914 case SCF_ERROR_BACKEND_ACCESS:
4915 r = scferror2errno(scf_error());
4916 goto out;
4917
4918 case SCF_ERROR_DELETED:
4919 warn(cf_missing, ient->sc_fmri,
4920 ud_name);
4921 r = 0;
4922 goto out;
4923
4924 case SCF_ERROR_PERMISSION_DENIED:
4925 warn(emsg_pg_deleted, ud_ctarg,
4926 ud_name);
4927 r = EPERM;
4928 goto out;
4929
4930 case SCF_ERROR_EXISTS:
4931 warn(emsg_pg_added, ud_ctarg, ud_name);
4932 r = EBUSY;
4933 goto out;
4934
4935 case SCF_ERROR_NOT_BOUND:
4936 case SCF_ERROR_HANDLE_MISMATCH:
4937 case SCF_ERROR_INVALID_ARGUMENT:
4938 case SCF_ERROR_NOT_SET:
4939 default:
4940 bad_error("entity_add_pg", scf_error());
4941 }
4942 }
4943 }
4944
4945 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4946 switch (r) {
4947 case 0:
4948 break;
4949
4950 case ECANCELED:
4951 warn(cf_missing, ient->sc_fmri, ud_name);
4952 goto out;
4953
4954 case ECONNABORTED:
4955 case ENOMEM:
4956 case EBADF:
4957 goto out;
4958
4959 case EACCES:
4960 default:
4961 bad_error("load_pg", r);
4962 }
4963
4964 if (g_verbose)
4965 warn(upgrading, ient->sc_fmri, ud_name);
4966
4967 r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4968 new_dpt_pgroup, 0, ient->sc_fmri);
4969 switch (r) {
4970 case 0:
4971 break;
4972
4973 case ECANCELED:
4974 warn(emsg_pg_deleted, ud_ctarg, ud_name);
4975 r = EBUSY;
4976 goto out;
4977
4978 case EPERM:
4979 warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4980 goto out;
4981
4982 case EBUSY:
4983 warn(emsg_pg_changed, ud_ctarg, ud_name);
4984 goto out;
4985
4986 case ECONNABORTED:
4987 case ENOMEM:
4988 case ENOSPC:
4989 case EROFS:
4990 case EACCES:
4991 case EINVAL:
4992 goto out;
4993
4994 default:
4995 bad_error("upgrade_pg", r);
4996 }
4997 break;
4998
4999 case 0: {
5000 scf_transaction_entry_t *ent;
5001 scf_value_t *val;
5002
5003 internal_pgroup_free(current_pg);
5004
5005 /* delete old pg */
5006 if (g_verbose)
5007 warn(upgrading, ient->sc_fmri, ud_name);
5008
5009 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
5010 switch (scf_error()) {
5011 case SCF_ERROR_CONNECTION_BROKEN:
5012 r = scferror2errno(scf_error());
5013 goto out;
5014
5015 case SCF_ERROR_DELETED:
5016 warn(cf_missing, ient->sc_fmri, ud_name);
5017 r = 0;
5018 goto out;
5019
5020 case SCF_ERROR_NOT_FOUND:
5021 break;
5022
5023 case SCF_ERROR_INVALID_ARGUMENT:
5024 case SCF_ERROR_NOT_BOUND:
5025 case SCF_ERROR_NOT_SET:
5026 case SCF_ERROR_HANDLE_MISMATCH:
5027 default:
5028 bad_error("entity_get_pg", scf_error());
5029 }
5030 } else if (scf_pg_delete(ud_pg) != 0) {
5031 switch (scf_error()) {
5032 case SCF_ERROR_DELETED:
5033 break;
5034
5035 case SCF_ERROR_CONNECTION_BROKEN:
5036 case SCF_ERROR_BACKEND_READONLY:
5037 case SCF_ERROR_BACKEND_ACCESS:
5038 r = scferror2errno(scf_error());
5039 goto out;
5040
5041 case SCF_ERROR_PERMISSION_DENIED:
5042 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
5043 r = scferror2errno(scf_error());
5044 goto out;
5045
5046 case SCF_ERROR_NOT_SET:
5047 default:
5048 bad_error("scf_pg_delete", scf_error());
5049 }
5050 }
5051
5052 /* import new one */
5053 cbdata.sc_handle = g_hndl;
5054 cbdata.sc_trans = NULL; /* handled below */
5055 cbdata.sc_flags = 0;
5056
5057 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
5058 if (r != UU_WALK_NEXT) {
5059 if (r != UU_WALK_ERROR)
5060 bad_error("lscf_dependent_import", r);
5061
5062 r = cbdata.sc_err;
5063 goto out;
5064 }
5065
5066 if (tx == NULL)
5067 break;
5068
5069 if ((ent = scf_entry_create(g_hndl)) == NULL ||
5070 (val = scf_value_create(g_hndl)) == NULL) {
5071 if (scf_error() == SCF_ERROR_NO_MEMORY)
5072 return (ENOMEM);
5073
5074 bad_error("scf_entry_create", scf_error());
5075 }
5076
5077 if (scf_transaction_property_change_type(tx, ent, ud_name,
5078 SCF_TYPE_FMRI) != 0) {
5079 switch (scf_error()) {
5080 case SCF_ERROR_CONNECTION_BROKEN:
5081 r = scferror2errno(scf_error());
5082 goto out;
5083
5084 case SCF_ERROR_DELETED:
5085 warn(emsg_pg_deleted, ient->sc_fmri,
5086 "dependents");
5087 r = EBUSY;
5088 goto out;
5089
5090 case SCF_ERROR_NOT_FOUND:
5091 break;
5092
5093 case SCF_ERROR_NOT_BOUND:
5094 case SCF_ERROR_HANDLE_MISMATCH:
5095 case SCF_ERROR_INVALID_ARGUMENT:
5096 case SCF_ERROR_NOT_SET:
5097 default:
5098 bad_error("scf_transaction_property_"
5099 "change_type", scf_error());
5100 }
5101
5102 if (scf_transaction_property_new(tx, ent, ud_name,
5103 SCF_TYPE_FMRI) != 0) {
5104 switch (scf_error()) {
5105 case SCF_ERROR_CONNECTION_BROKEN:
5106 r = scferror2errno(scf_error());
5107 goto out;
5108
5109 case SCF_ERROR_DELETED:
5110 warn(emsg_pg_deleted, ient->sc_fmri,
5111 "dependents");
5112 r = EBUSY;
5113 goto out;
5114
5115 case SCF_ERROR_EXISTS:
5116 warn(emsg_pg_changed, ient->sc_fmri,
5117 "dependents");
5118 r = EBUSY;
5119 goto out;
5120
5121 case SCF_ERROR_INVALID_ARGUMENT:
5122 case SCF_ERROR_HANDLE_MISMATCH:
5123 case SCF_ERROR_NOT_BOUND:
5124 case SCF_ERROR_NOT_SET:
5125 default:
5126 bad_error("scf_transaction_property_"
5127 "new", scf_error());
5128 }
5129 }
5130 }
5131
5132 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
5133 new_dpt_pgroup->sc_pgroup_fmri) != 0)
5134 /* invalid sc_pgroup_fmri caught above */
5135 bad_error("scf_value_set_from_string",
5136 scf_error());
5137
5138 if (scf_entry_add_value(ent, val) != 0)
5139 bad_error("scf_entry_add_value", scf_error());
5140 break;
5141 }
5142
5143 case -2:
5144 warn(li_corrupt, ient->sc_fmri);
5145 internal_pgroup_free(current_pg);
5146 r = EBADF;
5147 goto out;
5148
5149 case -1:
5150 default:
5151 /* invalid sc_pgroup_fmri caught above */
5152 bad_error("fmri_equal", r);
5153 }
5154
5155 r = 0;
5156
5157 out:
5158 if (old_dpt_pgroup != NULL)
5159 internal_pgroup_free(old_dpt_pgroup);
5160
5161 return (r);
5162 }
5163
5164 /*
5165 * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
5166 * would import it, except it seems to exist in the service anyway. Compare
5167 * the existent dependent with the one we would import, and report any
5168 * differences (if there are none, be silent). prop is the property which
5169 * represents the existent dependent (in the dependents property group) in the
5170 * entity corresponding to ient.
5171 *
5172 * Returns
5173 * 0 - success (Sort of. At least, we can continue importing.)
5174 * ECONNABORTED - repository connection broken
5175 * EBUSY - ancestor of prop was deleted (error printed)
5176 * ENOMEM - out of memory
5177 * EBADF - corrupt property group (error printed)
5178 * EINVAL - new_dpt_pgroup has invalid target (error printed)
5179 */
5180 static int
handle_dependent_conflict(const entity_t * const ient,const scf_property_t * const prop,const pgroup_t * const new_dpt_pgroup)5181 handle_dependent_conflict(const entity_t * const ient,
5182 const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
5183 {
5184 int r;
5185 scf_type_t ty;
5186 scf_error_t scfe;
5187 void *tptr;
5188 int tissvc;
5189 pgroup_t *pgroup;
5190
5191 if (scf_property_get_value(prop, ud_val) != 0) {
5192 switch (scf_error()) {
5193 case SCF_ERROR_CONNECTION_BROKEN:
5194 return (scferror2errno(scf_error()));
5195
5196 case SCF_ERROR_DELETED:
5197 warn(emsg_pg_deleted, ient->sc_fmri,
5198 new_dpt_pgroup->sc_pgroup_name);
5199 return (EBUSY);
5200
5201 case SCF_ERROR_CONSTRAINT_VIOLATED:
5202 case SCF_ERROR_NOT_FOUND:
5203 warn(gettext("Conflict upgrading %s (not importing "
5204 "dependent \"%s\" because it already exists.) "
5205 "Warning: The \"%s/%2$s\" property has more or "
5206 "fewer than one value)).\n"), ient->sc_fmri,
5207 new_dpt_pgroup->sc_pgroup_name, "dependents");
5208 return (0);
5209
5210 case SCF_ERROR_HANDLE_MISMATCH:
5211 case SCF_ERROR_NOT_BOUND:
5212 case SCF_ERROR_NOT_SET:
5213 case SCF_ERROR_PERMISSION_DENIED:
5214 default:
5215 bad_error("scf_property_get_value",
5216 scf_error());
5217 }
5218 }
5219
5220 ty = scf_value_type(ud_val);
5221 assert(ty != SCF_TYPE_INVALID);
5222 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
5223 warn(gettext("Conflict upgrading %s (not importing dependent "
5224 "\"%s\" because it already exists). Warning: The "
5225 "\"%s/%s\" property has unexpected type \"%s\")).\n"),
5226 ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
5227 scf_type_to_string(ty), "dependents");
5228 return (0);
5229 }
5230
5231 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
5232 0)
5233 bad_error("scf_value_get_as_string", scf_error());
5234
5235 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
5236 switch (r) {
5237 case 0:
5238 warn(gettext("Conflict upgrading %s (not importing dependent "
5239 "\"%s\" (target \"%s\") because it already exists with "
5240 "target \"%s\").\n"), ient->sc_fmri,
5241 new_dpt_pgroup->sc_pgroup_name,
5242 new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
5243 return (0);
5244
5245 case 1:
5246 break;
5247
5248 case -1:
5249 warn(gettext("Conflict upgrading %s (not importing dependent "
5250 "\"%s\" because it already exists). Warning: The current "
5251 "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
5252 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5253 return (0);
5254
5255 case -2:
5256 warn(gettext("Dependent \"%s\" of %s has invalid target "
5257 "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
5258 new_dpt_pgroup->sc_pgroup_fmri);
5259 return (EINVAL);
5260
5261 default:
5262 bad_error("fmri_equal", r);
5263 }
5264
5265 /* compare dependency pgs in target */
5266 scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
5267 switch (scfe) {
5268 case SCF_ERROR_NONE:
5269 break;
5270
5271 case SCF_ERROR_NO_MEMORY:
5272 return (ENOMEM);
5273
5274 case SCF_ERROR_NOT_FOUND:
5275 warn(emsg_dpt_dangling, ient->sc_fmri,
5276 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5277 return (0);
5278
5279 case SCF_ERROR_CONSTRAINT_VIOLATED:
5280 case SCF_ERROR_INVALID_ARGUMENT:
5281 default:
5282 bad_error("fmri_to_entity", scfe);
5283 }
5284
5285 r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
5286 ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
5287 switch (r) {
5288 case 0:
5289 break;
5290
5291 case ECONNABORTED:
5292 return (r);
5293
5294 case ECANCELED:
5295 warn(emsg_dpt_dangling, ient->sc_fmri,
5296 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5297 return (0);
5298
5299 case EBADF:
5300 if (tissvc)
5301 warn(gettext("%s has an instance with a \"%s\" "
5302 "snapshot which is missing a snaplevel.\n"),
5303 ud_ctarg, "running");
5304 else
5305 warn(gettext("%s has a \"%s\" snapshot which is "
5306 "missing a snaplevel.\n"), ud_ctarg, "running");
5307 /* FALLTHROUGH */
5308
5309 case ENOENT:
5310 warn(emsg_dpt_no_dep, ient->sc_fmri,
5311 new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5312 new_dpt_pgroup->sc_pgroup_name);
5313 return (0);
5314
5315 case EINVAL:
5316 default:
5317 bad_error("entity_get_running_pg", r);
5318 }
5319
5320 pgroup = internal_pgroup_new();
5321 if (pgroup == NULL)
5322 return (ENOMEM);
5323
5324 r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
5325 switch (r) {
5326 case 0:
5327 break;
5328
5329 case ECONNABORTED:
5330 case EBADF:
5331 case ENOMEM:
5332 internal_pgroup_free(pgroup);
5333 return (r);
5334
5335 case ECANCELED:
5336 warn(emsg_dpt_no_dep, ient->sc_fmri,
5337 new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5338 new_dpt_pgroup->sc_pgroup_name);
5339 internal_pgroup_free(pgroup);
5340 return (0);
5341
5342 case EACCES:
5343 default:
5344 bad_error("load_pg", r);
5345 }
5346
5347 /* report differences */
5348 report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
5349 internal_pgroup_free(pgroup);
5350 return (0);
5351 }
5352
5353 /*
5354 * lipg is a property group in the last-import snapshot of ent, which is an
5355 * scf_service_t or an scf_instance_t (according to ient). If lipg is not in
5356 * ient's pgroups, delete it from ent if it hasn't been customized. If it is
5357 * in ents's property groups, compare and upgrade ent appropriately.
5358 *
5359 * Returns
5360 * 0 - success
5361 * ECONNABORTED - repository connection broken
5362 * ENOMEM - out of memory
5363 * ENOSPC - configd is out of resources
5364 * EINVAL - ient has invalid dependent (error printed)
5365 * - ient has invalid pgroup_t (error printed)
5366 * ECANCELED - ent has been deleted
5367 * ENODEV - entity containing lipg has been deleted
5368 * - entity containing running has been deleted
5369 * EPERM - could not delete pg (permission denied) (error printed)
5370 * - couldn't upgrade dependents (permission denied) (error printed)
5371 * - couldn't import pg (permission denied) (error printed)
5372 * - couldn't upgrade pg (permission denied) (error printed)
5373 * EROFS - could not delete pg (repository read-only)
5374 * - couldn't upgrade dependents (repository read-only)
5375 * - couldn't import pg (repository read-only)
5376 * - couldn't upgrade pg (repository read-only)
5377 * EACCES - could not delete pg (backend access denied)
5378 * - couldn't upgrade dependents (backend access denied)
5379 * - couldn't import pg (backend access denied)
5380 * - couldn't upgrade pg (backend access denied)
5381 * - couldn't read property (backend access denied)
5382 * EBUSY - property group was added (error printed)
5383 * - property group was deleted (error printed)
5384 * - property group changed (error printed)
5385 * - "dependents" pg was added, changed, or deleted (error printed)
5386 * - dependent target deleted (error printed)
5387 * - dependent pg changed (error printed)
5388 * EBADF - imp_snpl is corrupt (error printed)
5389 * - ent has bad pg (error printed)
5390 * EEXIST - dependent collision in target service (error printed)
5391 */
5392 static int
process_old_pg(const scf_propertygroup_t * lipg,entity_t * ient,void * ent,const scf_snaplevel_t * running)5393 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
5394 const scf_snaplevel_t *running)
5395 {
5396 int r;
5397 pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
5398 scf_callback_t cbdata;
5399
5400 const char * const cf_pg_missing =
5401 gettext("Conflict upgrading %s (property group %s is missing)\n");
5402 const char * const deleting =
5403 gettext("%s: Deleting property group \"%s\".\n");
5404
5405 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5406
5407 /* Skip dependent property groups. */
5408 if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
5409 switch (scf_error()) {
5410 case SCF_ERROR_DELETED:
5411 return (ENODEV);
5412
5413 case SCF_ERROR_CONNECTION_BROKEN:
5414 return (ECONNABORTED);
5415
5416 case SCF_ERROR_NOT_SET:
5417 case SCF_ERROR_NOT_BOUND:
5418 default:
5419 bad_error("scf_pg_get_type", scf_error());
5420 }
5421 }
5422
5423 if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
5424 if (scf_pg_get_property(lipg, "external", NULL) == 0)
5425 return (0);
5426
5427 switch (scf_error()) {
5428 case SCF_ERROR_NOT_FOUND:
5429 break;
5430
5431 case SCF_ERROR_CONNECTION_BROKEN:
5432 return (ECONNABORTED);
5433
5434 case SCF_ERROR_DELETED:
5435 return (ENODEV);
5436
5437 case SCF_ERROR_INVALID_ARGUMENT:
5438 case SCF_ERROR_NOT_BOUND:
5439 case SCF_ERROR_HANDLE_MISMATCH:
5440 case SCF_ERROR_NOT_SET:
5441 default:
5442 bad_error("scf_pg_get_property", scf_error());
5443 }
5444 }
5445
5446 /* lookup pg in new properties */
5447 if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
5448 switch (scf_error()) {
5449 case SCF_ERROR_DELETED:
5450 return (ENODEV);
5451
5452 case SCF_ERROR_CONNECTION_BROKEN:
5453 return (ECONNABORTED);
5454
5455 case SCF_ERROR_NOT_SET:
5456 case SCF_ERROR_NOT_BOUND:
5457 default:
5458 bad_error("scf_pg_get_name", scf_error());
5459 }
5460 }
5461
5462 pgrp.sc_pgroup_name = imp_str;
5463 mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
5464
5465 if (mpg != NULL)
5466 mpg->sc_pgroup_seen = 1;
5467
5468 /* Special handling for dependents */
5469 if (strcmp(imp_str, "dependents") == 0)
5470 return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
5471
5472 if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
5473 return (upgrade_manifestfiles(NULL, ient, running, ent));
5474
5475 if (mpg == NULL || mpg->sc_pgroup_delete) {
5476 /* property group was deleted from manifest */
5477 if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5478 switch (scf_error()) {
5479 case SCF_ERROR_NOT_FOUND:
5480 return (0);
5481
5482 case SCF_ERROR_DELETED:
5483 case SCF_ERROR_CONNECTION_BROKEN:
5484 return (scferror2errno(scf_error()));
5485
5486 case SCF_ERROR_INVALID_ARGUMENT:
5487 case SCF_ERROR_HANDLE_MISMATCH:
5488 case SCF_ERROR_NOT_BOUND:
5489 case SCF_ERROR_NOT_SET:
5490 default:
5491 bad_error("entity_get_pg", scf_error());
5492 }
5493 }
5494
5495 if (mpg != NULL && mpg->sc_pgroup_delete) {
5496 if (g_verbose)
5497 warn(deleting, ient->sc_fmri, imp_str);
5498 if (scf_pg_delete(imp_pg2) == 0)
5499 return (0);
5500
5501 switch (scf_error()) {
5502 case SCF_ERROR_DELETED:
5503 return (0);
5504
5505 case SCF_ERROR_CONNECTION_BROKEN:
5506 case SCF_ERROR_BACKEND_READONLY:
5507 case SCF_ERROR_BACKEND_ACCESS:
5508 return (scferror2errno(scf_error()));
5509
5510 case SCF_ERROR_PERMISSION_DENIED:
5511 warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
5512 return (scferror2errno(scf_error()));
5513
5514 case SCF_ERROR_NOT_SET:
5515 default:
5516 bad_error("scf_pg_delete", scf_error());
5517 }
5518 }
5519
5520 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5521 switch (r) {
5522 case 0:
5523 break;
5524
5525 case ECANCELED:
5526 return (ENODEV);
5527
5528 case ECONNABORTED:
5529 case ENOMEM:
5530 case EBADF:
5531 case EACCES:
5532 return (r);
5533
5534 default:
5535 bad_error("load_pg", r);
5536 }
5537
5538 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5539 switch (r) {
5540 case 0:
5541 break;
5542
5543 case ECANCELED:
5544 case ECONNABORTED:
5545 case ENOMEM:
5546 case EBADF:
5547 case EACCES:
5548 internal_pgroup_free(lipg_i);
5549 return (r);
5550
5551 default:
5552 bad_error("load_pg", r);
5553 }
5554
5555 if (pg_equal(lipg_i, curpg_i)) {
5556 if (g_verbose)
5557 warn(deleting, ient->sc_fmri, imp_str);
5558 if (scf_pg_delete(imp_pg2) != 0) {
5559 switch (scf_error()) {
5560 case SCF_ERROR_DELETED:
5561 break;
5562
5563 case SCF_ERROR_CONNECTION_BROKEN:
5564 internal_pgroup_free(lipg_i);
5565 internal_pgroup_free(curpg_i);
5566 return (ECONNABORTED);
5567
5568 case SCF_ERROR_NOT_SET:
5569 case SCF_ERROR_NOT_BOUND:
5570 default:
5571 bad_error("scf_pg_delete", scf_error());
5572 }
5573 }
5574 } else {
5575 report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5576 }
5577
5578 internal_pgroup_free(lipg_i);
5579 internal_pgroup_free(curpg_i);
5580
5581 return (0);
5582 }
5583
5584 /*
5585 * Only dependent pgs can have override set, and we skipped those
5586 * above.
5587 */
5588 assert(!mpg->sc_pgroup_override);
5589
5590 /* compare */
5591 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5592 switch (r) {
5593 case 0:
5594 break;
5595
5596 case ECANCELED:
5597 return (ENODEV);
5598
5599 case ECONNABORTED:
5600 case EBADF:
5601 case ENOMEM:
5602 case EACCES:
5603 return (r);
5604
5605 default:
5606 bad_error("load_pg", r);
5607 }
5608
5609 if (pg_equal(mpg, lipg_i)) {
5610 /* The manifest pg has not changed. Move on. */
5611 r = 0;
5612 goto out;
5613 }
5614
5615 /* upgrade current properties according to lipg & mpg */
5616 if (running != NULL)
5617 r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5618 else
5619 r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5620 if (r != 0) {
5621 switch (scf_error()) {
5622 case SCF_ERROR_CONNECTION_BROKEN:
5623 r = scferror2errno(scf_error());
5624 goto out;
5625
5626 case SCF_ERROR_DELETED:
5627 if (running != NULL)
5628 r = ENODEV;
5629 else
5630 r = ECANCELED;
5631 goto out;
5632
5633 case SCF_ERROR_NOT_FOUND:
5634 break;
5635
5636 case SCF_ERROR_INVALID_ARGUMENT:
5637 case SCF_ERROR_HANDLE_MISMATCH:
5638 case SCF_ERROR_NOT_BOUND:
5639 case SCF_ERROR_NOT_SET:
5640 default:
5641 bad_error("entity_get_pg", scf_error());
5642 }
5643
5644 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5645
5646 r = 0;
5647 goto out;
5648 }
5649
5650 r = load_pg_attrs(imp_pg2, &curpg_i);
5651 switch (r) {
5652 case 0:
5653 break;
5654
5655 case ECANCELED:
5656 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5657 r = 0;
5658 goto out;
5659
5660 case ECONNABORTED:
5661 case ENOMEM:
5662 goto out;
5663
5664 default:
5665 bad_error("load_pg_attrs", r);
5666 }
5667
5668 if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5669 (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5670 internal_pgroup_free(curpg_i);
5671 r = 0;
5672 goto out;
5673 }
5674
5675 internal_pgroup_free(curpg_i);
5676
5677 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5678 switch (r) {
5679 case 0:
5680 break;
5681
5682 case ECANCELED:
5683 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5684 r = 0;
5685 goto out;
5686
5687 case ECONNABORTED:
5688 case EBADF:
5689 case ENOMEM:
5690 case EACCES:
5691 goto out;
5692
5693 default:
5694 bad_error("load_pg", r);
5695 }
5696
5697 if (pg_equal(lipg_i, curpg_i) &&
5698 !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5699 int do_delete = 1;
5700
5701 if (g_verbose)
5702 warn(gettext("%s: Upgrading property group \"%s\".\n"),
5703 ient->sc_fmri, mpg->sc_pgroup_name);
5704
5705 internal_pgroup_free(curpg_i);
5706
5707 if (running != NULL &&
5708 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5709 switch (scf_error()) {
5710 case SCF_ERROR_DELETED:
5711 r = ECANCELED;
5712 goto out;
5713
5714 case SCF_ERROR_NOT_FOUND:
5715 do_delete = 0;
5716 break;
5717
5718 case SCF_ERROR_CONNECTION_BROKEN:
5719 r = scferror2errno(scf_error());
5720 goto out;
5721
5722 case SCF_ERROR_HANDLE_MISMATCH:
5723 case SCF_ERROR_INVALID_ARGUMENT:
5724 case SCF_ERROR_NOT_SET:
5725 case SCF_ERROR_NOT_BOUND:
5726 default:
5727 bad_error("entity_get_pg", scf_error());
5728 }
5729 }
5730
5731 if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5732 switch (scf_error()) {
5733 case SCF_ERROR_DELETED:
5734 break;
5735
5736 case SCF_ERROR_CONNECTION_BROKEN:
5737 case SCF_ERROR_BACKEND_READONLY:
5738 case SCF_ERROR_BACKEND_ACCESS:
5739 r = scferror2errno(scf_error());
5740 goto out;
5741
5742 case SCF_ERROR_PERMISSION_DENIED:
5743 warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5744 ient->sc_fmri);
5745 r = scferror2errno(scf_error());
5746 goto out;
5747
5748 case SCF_ERROR_NOT_SET:
5749 case SCF_ERROR_NOT_BOUND:
5750 default:
5751 bad_error("scf_pg_delete", scf_error());
5752 }
5753 }
5754
5755 cbdata.sc_handle = g_hndl;
5756 cbdata.sc_parent = ent;
5757 cbdata.sc_service = issvc;
5758 cbdata.sc_flags = 0;
5759 cbdata.sc_source_fmri = ient->sc_fmri;
5760 cbdata.sc_target_fmri = ient->sc_fmri;
5761
5762 r = entity_pgroup_import(mpg, &cbdata);
5763 switch (r) {
5764 case UU_WALK_NEXT:
5765 r = 0;
5766 goto out;
5767
5768 case UU_WALK_ERROR:
5769 if (cbdata.sc_err == EEXIST) {
5770 warn(emsg_pg_added, ient->sc_fmri,
5771 mpg->sc_pgroup_name);
5772 r = EBUSY;
5773 } else {
5774 r = cbdata.sc_err;
5775 }
5776 goto out;
5777
5778 default:
5779 bad_error("entity_pgroup_import", r);
5780 }
5781 }
5782
5783 if (running != NULL &&
5784 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5785 switch (scf_error()) {
5786 case SCF_ERROR_CONNECTION_BROKEN:
5787 case SCF_ERROR_DELETED:
5788 r = scferror2errno(scf_error());
5789 goto out;
5790
5791 case SCF_ERROR_NOT_FOUND:
5792 break;
5793
5794 case SCF_ERROR_HANDLE_MISMATCH:
5795 case SCF_ERROR_INVALID_ARGUMENT:
5796 case SCF_ERROR_NOT_SET:
5797 case SCF_ERROR_NOT_BOUND:
5798 default:
5799 bad_error("entity_get_pg", scf_error());
5800 }
5801
5802 cbdata.sc_handle = g_hndl;
5803 cbdata.sc_parent = ent;
5804 cbdata.sc_service = issvc;
5805 cbdata.sc_flags = SCI_FORCE;
5806 cbdata.sc_source_fmri = ient->sc_fmri;
5807 cbdata.sc_target_fmri = ient->sc_fmri;
5808
5809 r = entity_pgroup_import(mpg, &cbdata);
5810 switch (r) {
5811 case UU_WALK_NEXT:
5812 r = 0;
5813 goto out;
5814
5815 case UU_WALK_ERROR:
5816 if (cbdata.sc_err == EEXIST) {
5817 warn(emsg_pg_added, ient->sc_fmri,
5818 mpg->sc_pgroup_name);
5819 r = EBUSY;
5820 } else {
5821 r = cbdata.sc_err;
5822 }
5823 goto out;
5824
5825 default:
5826 bad_error("entity_pgroup_import", r);
5827 }
5828 }
5829
5830 r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5831 internal_pgroup_free(curpg_i);
5832 switch (r) {
5833 case 0:
5834 ient->sc_import_state = IMPORT_PROP_BEGUN;
5835 break;
5836
5837 case ECANCELED:
5838 warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5839 r = EBUSY;
5840 break;
5841
5842 case EPERM:
5843 warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5844 break;
5845
5846 case EBUSY:
5847 warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5848 break;
5849
5850 case ECONNABORTED:
5851 case ENOMEM:
5852 case ENOSPC:
5853 case EROFS:
5854 case EACCES:
5855 case EINVAL:
5856 break;
5857
5858 default:
5859 bad_error("upgrade_pg", r);
5860 }
5861
5862 out:
5863 internal_pgroup_free(lipg_i);
5864 return (r);
5865 }
5866
5867 /*
5868 * Upgrade the properties of ent according to snpl & ient.
5869 *
5870 * Returns
5871 * 0 - success
5872 * ECONNABORTED - repository connection broken
5873 * ENOMEM - out of memory
5874 * ENOSPC - configd is out of resources
5875 * ECANCELED - ent was deleted
5876 * ENODEV - entity containing snpl was deleted
5877 * - entity containing running was deleted
5878 * EBADF - imp_snpl is corrupt (error printed)
5879 * - ent has corrupt pg (error printed)
5880 * - dependent has corrupt pg (error printed)
5881 * - dependent target has a corrupt snapshot (error printed)
5882 * EBUSY - pg was added, changed, or deleted (error printed)
5883 * - dependent target was deleted (error printed)
5884 * - dependent pg changed (error printed)
5885 * EINVAL - invalid property group name (error printed)
5886 * - invalid property name (error printed)
5887 * - invalid value (error printed)
5888 * - ient has invalid pgroup or dependent (error printed)
5889 * EPERM - could not create property group (permission denied) (error printed)
5890 * - could not modify property group (permission denied) (error printed)
5891 * - couldn't delete, upgrade, or import pg or dependent (error printed)
5892 * EROFS - could not create property group (repository read-only)
5893 * - couldn't delete, upgrade, or import pg or dependent
5894 * EACCES - could not create property group (backend access denied)
5895 * - couldn't delete, upgrade, or import pg or dependent
5896 * EEXIST - dependent collision in target service (error printed)
5897 */
5898 static int
upgrade_props(void * ent,scf_snaplevel_t * running,scf_snaplevel_t * snpl,entity_t * ient)5899 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5900 entity_t *ient)
5901 {
5902 pgroup_t *pg, *rpg;
5903 int r;
5904 uu_list_t *pgs = ient->sc_pgroups;
5905
5906 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5907
5908 /* clear sc_sceen for pgs */
5909 if (uu_list_walk(pgs, clear_int,
5910 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5911 bad_error("uu_list_walk", uu_error());
5912
5913 if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5914 switch (scf_error()) {
5915 case SCF_ERROR_DELETED:
5916 return (ENODEV);
5917
5918 case SCF_ERROR_CONNECTION_BROKEN:
5919 return (ECONNABORTED);
5920
5921 case SCF_ERROR_NOT_SET:
5922 case SCF_ERROR_NOT_BOUND:
5923 case SCF_ERROR_HANDLE_MISMATCH:
5924 default:
5925 bad_error("scf_iter_snaplevel_pgs", scf_error());
5926 }
5927 }
5928
5929 for (;;) {
5930 r = scf_iter_next_pg(imp_up_iter, imp_pg);
5931 if (r == 0)
5932 break;
5933 if (r == 1) {
5934 r = process_old_pg(imp_pg, ient, ent, running);
5935 switch (r) {
5936 case 0:
5937 break;
5938
5939 case ECONNABORTED:
5940 case ENOMEM:
5941 case ENOSPC:
5942 case ECANCELED:
5943 case ENODEV:
5944 case EPERM:
5945 case EROFS:
5946 case EACCES:
5947 case EBADF:
5948 case EBUSY:
5949 case EINVAL:
5950 case EEXIST:
5951 return (r);
5952
5953 default:
5954 bad_error("process_old_pg", r);
5955 }
5956 continue;
5957 }
5958 if (r != -1)
5959 bad_error("scf_iter_next_pg", r);
5960
5961 switch (scf_error()) {
5962 case SCF_ERROR_DELETED:
5963 return (ENODEV);
5964
5965 case SCF_ERROR_CONNECTION_BROKEN:
5966 return (ECONNABORTED);
5967
5968 case SCF_ERROR_HANDLE_MISMATCH:
5969 case SCF_ERROR_NOT_BOUND:
5970 case SCF_ERROR_NOT_SET:
5971 case SCF_ERROR_INVALID_ARGUMENT:
5972 default:
5973 bad_error("scf_iter_next_pg", scf_error());
5974 }
5975 }
5976
5977 for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5978 if (pg->sc_pgroup_seen)
5979 continue;
5980
5981 /* pg is new */
5982
5983 if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5984 r = upgrade_dependents(NULL, imp_snpl, ient, running,
5985 ent);
5986 switch (r) {
5987 case 0:
5988 break;
5989
5990 case ECONNABORTED:
5991 case ENOMEM:
5992 case ENOSPC:
5993 case ECANCELED:
5994 case ENODEV:
5995 case EBADF:
5996 case EBUSY:
5997 case EINVAL:
5998 case EPERM:
5999 case EROFS:
6000 case EACCES:
6001 case EEXIST:
6002 return (r);
6003
6004 default:
6005 bad_error("upgrade_dependents", r);
6006 }
6007 continue;
6008 }
6009
6010 if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
6011 r = upgrade_manifestfiles(pg, ient, running, ent);
6012 switch (r) {
6013 case 0:
6014 break;
6015
6016 case ECONNABORTED:
6017 case ENOMEM:
6018 case ENOSPC:
6019 case ECANCELED:
6020 case ENODEV:
6021 case EBADF:
6022 case EBUSY:
6023 case EINVAL:
6024 case EPERM:
6025 case EROFS:
6026 case EACCES:
6027 case EEXIST:
6028 return (r);
6029
6030 default:
6031 bad_error("upgrade_manifestfiles", r);
6032 }
6033 continue;
6034 }
6035
6036 if (running != NULL) {
6037 r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
6038 imp_pg);
6039 } else {
6040 r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
6041 imp_pg);
6042 }
6043 if (r != 0) {
6044 scf_callback_t cbdata;
6045
6046 switch (scf_error()) {
6047 case SCF_ERROR_NOT_FOUND:
6048 break;
6049
6050 case SCF_ERROR_CONNECTION_BROKEN:
6051 return (scferror2errno(scf_error()));
6052
6053 case SCF_ERROR_DELETED:
6054 if (running != NULL)
6055 return (ENODEV);
6056 else
6057 return (scferror2errno(scf_error()));
6058
6059 case SCF_ERROR_INVALID_ARGUMENT:
6060 warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
6061 pg->sc_pgroup_name);
6062 return (EINVAL);
6063
6064 case SCF_ERROR_NOT_SET:
6065 case SCF_ERROR_HANDLE_MISMATCH:
6066 case SCF_ERROR_NOT_BOUND:
6067 default:
6068 bad_error("entity_get_pg", scf_error());
6069 }
6070
6071 /* User doesn't have pg, so import it. */
6072
6073 cbdata.sc_handle = g_hndl;
6074 cbdata.sc_parent = ent;
6075 cbdata.sc_service = issvc;
6076 cbdata.sc_flags = SCI_FORCE;
6077 cbdata.sc_source_fmri = ient->sc_fmri;
6078 cbdata.sc_target_fmri = ient->sc_fmri;
6079
6080 r = entity_pgroup_import(pg, &cbdata);
6081 switch (r) {
6082 case UU_WALK_NEXT:
6083 ient->sc_import_state = IMPORT_PROP_BEGUN;
6084 continue;
6085
6086 case UU_WALK_ERROR:
6087 if (cbdata.sc_err == EEXIST) {
6088 warn(emsg_pg_added, ient->sc_fmri,
6089 pg->sc_pgroup_name);
6090 return (EBUSY);
6091 }
6092 return (cbdata.sc_err);
6093
6094 default:
6095 bad_error("entity_pgroup_import", r);
6096 }
6097 }
6098
6099 /* report differences between pg & current */
6100 r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
6101 switch (r) {
6102 case 0:
6103 break;
6104
6105 case ECANCELED:
6106 warn(emsg_pg_deleted, ient->sc_fmri,
6107 pg->sc_pgroup_name);
6108 return (EBUSY);
6109
6110 case ECONNABORTED:
6111 case EBADF:
6112 case ENOMEM:
6113 case EACCES:
6114 return (r);
6115
6116 default:
6117 bad_error("load_pg", r);
6118 }
6119 report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
6120 internal_pgroup_free(rpg);
6121 rpg = NULL;
6122 }
6123
6124 return (0);
6125 }
6126
6127 /*
6128 * Import an instance. If it doesn't exist, create it. If it has
6129 * a last-import snapshot, upgrade its properties. Finish by updating its
6130 * last-import snapshot. If it doesn't have a last-import snapshot then it
6131 * could have been created for a dependent tag in another manifest. Import the
6132 * new properties. If there's a conflict, don't override, like now?
6133 *
6134 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
6135 * lcbdata->sc_err to
6136 * ECONNABORTED - repository connection broken
6137 * ENOMEM - out of memory
6138 * ENOSPC - svc.configd is out of resources
6139 * EEXIST - dependency collision in dependent service (error printed)
6140 * EPERM - couldn't create temporary instance (permission denied)
6141 * - couldn't import into temporary instance (permission denied)
6142 * - couldn't take snapshot (permission denied)
6143 * - couldn't upgrade properties (permission denied)
6144 * - couldn't import properties (permission denied)
6145 * - couldn't import dependents (permission denied)
6146 * EROFS - couldn't create temporary instance (repository read-only)
6147 * - couldn't import into temporary instance (repository read-only)
6148 * - couldn't upgrade properties (repository read-only)
6149 * - couldn't import properties (repository read-only)
6150 * - couldn't import dependents (repository read-only)
6151 * EACCES - couldn't create temporary instance (backend access denied)
6152 * - couldn't import into temporary instance (backend access denied)
6153 * - couldn't upgrade properties (backend access denied)
6154 * - couldn't import properties (backend access denied)
6155 * - couldn't import dependents (backend access denied)
6156 * EINVAL - invalid instance name (error printed)
6157 * - invalid pgroup_t's (error printed)
6158 * - invalid dependents (error printed)
6159 * EBUSY - temporary service deleted (error printed)
6160 * - temporary instance deleted (error printed)
6161 * - temporary instance changed (error printed)
6162 * - temporary instance already exists (error printed)
6163 * - instance deleted (error printed)
6164 * EBADF - instance has corrupt last-import snapshot (error printed)
6165 * - instance is corrupt (error printed)
6166 * - dependent has corrupt pg (error printed)
6167 * - dependent target has a corrupt snapshot (error printed)
6168 * -1 - unknown libscf error (error printed)
6169 */
6170 static int
lscf_instance_import(void * v,void * pvt)6171 lscf_instance_import(void *v, void *pvt)
6172 {
6173 entity_t *inst = v;
6174 scf_callback_t ctx;
6175 scf_callback_t *lcbdata = pvt;
6176 scf_service_t *rsvc = lcbdata->sc_parent;
6177 int r;
6178 scf_snaplevel_t *running;
6179 int flags = lcbdata->sc_flags;
6180
6181 const char * const emsg_tdel =
6182 gettext("Temporary instance svc:/%s:%s was deleted.\n");
6183 const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
6184 "changed unexpectedly.\n");
6185 const char * const emsg_del = gettext("%s changed unexpectedly "
6186 "(instance \"%s\" was deleted.)\n");
6187 const char * const emsg_badsnap = gettext(
6188 "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
6189
6190 /*
6191 * prepare last-import snapshot:
6192 * create temporary instance (service was precreated)
6193 * populate with properties from bundle
6194 * take snapshot
6195 */
6196 if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
6197 switch (scf_error()) {
6198 case SCF_ERROR_CONNECTION_BROKEN:
6199 case SCF_ERROR_NO_RESOURCES:
6200 case SCF_ERROR_BACKEND_READONLY:
6201 case SCF_ERROR_BACKEND_ACCESS:
6202 return (stash_scferror(lcbdata));
6203
6204 case SCF_ERROR_EXISTS:
6205 warn(gettext("Temporary service svc:/%s "
6206 "changed unexpectedly (instance \"%s\" added).\n"),
6207 imp_tsname, inst->sc_name);
6208 lcbdata->sc_err = EBUSY;
6209 return (UU_WALK_ERROR);
6210
6211 case SCF_ERROR_DELETED:
6212 warn(gettext("Temporary service svc:/%s "
6213 "was deleted unexpectedly.\n"), imp_tsname);
6214 lcbdata->sc_err = EBUSY;
6215 return (UU_WALK_ERROR);
6216
6217 case SCF_ERROR_INVALID_ARGUMENT:
6218 warn(gettext("Invalid instance name \"%s\".\n"),
6219 inst->sc_name);
6220 return (stash_scferror(lcbdata));
6221
6222 case SCF_ERROR_PERMISSION_DENIED:
6223 warn(gettext("Could not create temporary instance "
6224 "\"%s\" in svc:/%s (permission denied).\n"),
6225 inst->sc_name, imp_tsname);
6226 return (stash_scferror(lcbdata));
6227
6228 case SCF_ERROR_HANDLE_MISMATCH:
6229 case SCF_ERROR_NOT_BOUND:
6230 case SCF_ERROR_NOT_SET:
6231 default:
6232 bad_error("scf_service_add_instance", scf_error());
6233 }
6234 }
6235
6236 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6237 inst->sc_name);
6238 if (r < 0)
6239 bad_error("snprintf", errno);
6240
6241 r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
6242 lcbdata->sc_flags | SCI_NOENABLED);
6243 switch (r) {
6244 case 0:
6245 break;
6246
6247 case ECANCELED:
6248 warn(emsg_tdel, imp_tsname, inst->sc_name);
6249 lcbdata->sc_err = EBUSY;
6250 r = UU_WALK_ERROR;
6251 goto deltemp;
6252
6253 case EEXIST:
6254 warn(emsg_tchg, imp_tsname, inst->sc_name);
6255 lcbdata->sc_err = EBUSY;
6256 r = UU_WALK_ERROR;
6257 goto deltemp;
6258
6259 case ECONNABORTED:
6260 goto connaborted;
6261
6262 case ENOMEM:
6263 case ENOSPC:
6264 case EPERM:
6265 case EROFS:
6266 case EACCES:
6267 case EINVAL:
6268 case EBUSY:
6269 lcbdata->sc_err = r;
6270 r = UU_WALK_ERROR;
6271 goto deltemp;
6272
6273 default:
6274 bad_error("lscf_import_instance_pgs", r);
6275 }
6276
6277 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6278 inst->sc_name);
6279 if (r < 0)
6280 bad_error("snprintf", errno);
6281
6282 ctx.sc_handle = lcbdata->sc_handle;
6283 ctx.sc_parent = imp_tinst;
6284 ctx.sc_service = 0;
6285 ctx.sc_source_fmri = inst->sc_fmri;
6286 ctx.sc_target_fmri = imp_str;
6287 if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
6288 UU_DEFAULT) != 0) {
6289 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6290 bad_error("uu_list_walk", uu_error());
6291
6292 switch (ctx.sc_err) {
6293 case ECONNABORTED:
6294 goto connaborted;
6295
6296 case ECANCELED:
6297 warn(emsg_tdel, imp_tsname, inst->sc_name);
6298 lcbdata->sc_err = EBUSY;
6299 break;
6300
6301 case EEXIST:
6302 warn(emsg_tchg, imp_tsname, inst->sc_name);
6303 lcbdata->sc_err = EBUSY;
6304 break;
6305
6306 default:
6307 lcbdata->sc_err = ctx.sc_err;
6308 }
6309 r = UU_WALK_ERROR;
6310 goto deltemp;
6311 }
6312
6313 if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
6314 inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
6315 switch (scf_error()) {
6316 case SCF_ERROR_CONNECTION_BROKEN:
6317 goto connaborted;
6318
6319 case SCF_ERROR_NO_RESOURCES:
6320 r = stash_scferror(lcbdata);
6321 goto deltemp;
6322
6323 case SCF_ERROR_EXISTS:
6324 warn(emsg_tchg, imp_tsname, inst->sc_name);
6325 lcbdata->sc_err = EBUSY;
6326 r = UU_WALK_ERROR;
6327 goto deltemp;
6328
6329 case SCF_ERROR_PERMISSION_DENIED:
6330 warn(gettext("Could not take \"%s\" snapshot of %s "
6331 "(permission denied).\n"), snap_lastimport,
6332 imp_str);
6333 r = stash_scferror(lcbdata);
6334 goto deltemp;
6335
6336 default:
6337 scfwarn();
6338 lcbdata->sc_err = -1;
6339 r = UU_WALK_ERROR;
6340 goto deltemp;
6341
6342 case SCF_ERROR_HANDLE_MISMATCH:
6343 case SCF_ERROR_INVALID_ARGUMENT:
6344 case SCF_ERROR_NOT_SET:
6345 bad_error("_scf_snapshot_take_new_named", scf_error());
6346 }
6347 }
6348
6349 if (lcbdata->sc_flags & SCI_FRESH)
6350 goto fresh;
6351
6352 if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
6353 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6354 imp_lisnap) != 0) {
6355 switch (scf_error()) {
6356 case SCF_ERROR_DELETED:
6357 warn(emsg_del, inst->sc_parent->sc_fmri,
6358 inst->sc_name);
6359 lcbdata->sc_err = EBUSY;
6360 r = UU_WALK_ERROR;
6361 goto deltemp;
6362
6363 case SCF_ERROR_NOT_FOUND:
6364 flags |= SCI_FORCE;
6365 goto nosnap;
6366
6367 case SCF_ERROR_CONNECTION_BROKEN:
6368 goto connaborted;
6369
6370 case SCF_ERROR_INVALID_ARGUMENT:
6371 case SCF_ERROR_HANDLE_MISMATCH:
6372 case SCF_ERROR_NOT_BOUND:
6373 case SCF_ERROR_NOT_SET:
6374 default:
6375 bad_error("scf_instance_get_snapshot",
6376 scf_error());
6377 }
6378 }
6379
6380 /* upgrade */
6381
6382 /*
6383 * compare new properties with last-import properties
6384 * upgrade current properties
6385 */
6386 /* clear sc_sceen for pgs */
6387 if (uu_list_walk(inst->sc_pgroups, clear_int,
6388 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
6389 0)
6390 bad_error("uu_list_walk", uu_error());
6391
6392 r = get_snaplevel(imp_lisnap, 0, imp_snpl);
6393 switch (r) {
6394 case 0:
6395 break;
6396
6397 case ECONNABORTED:
6398 goto connaborted;
6399
6400 case ECANCELED:
6401 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6402 lcbdata->sc_err = EBUSY;
6403 r = UU_WALK_ERROR;
6404 goto deltemp;
6405
6406 case ENOENT:
6407 warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
6408 lcbdata->sc_err = EBADF;
6409 r = UU_WALK_ERROR;
6410 goto deltemp;
6411
6412 default:
6413 bad_error("get_snaplevel", r);
6414 }
6415
6416 if (scf_instance_get_snapshot(imp_inst, snap_running,
6417 imp_rsnap) != 0) {
6418 switch (scf_error()) {
6419 case SCF_ERROR_DELETED:
6420 warn(emsg_del, inst->sc_parent->sc_fmri,
6421 inst->sc_name);
6422 lcbdata->sc_err = EBUSY;
6423 r = UU_WALK_ERROR;
6424 goto deltemp;
6425
6426 case SCF_ERROR_NOT_FOUND:
6427 break;
6428
6429 case SCF_ERROR_CONNECTION_BROKEN:
6430 goto connaborted;
6431
6432 case SCF_ERROR_INVALID_ARGUMENT:
6433 case SCF_ERROR_HANDLE_MISMATCH:
6434 case SCF_ERROR_NOT_BOUND:
6435 case SCF_ERROR_NOT_SET:
6436 default:
6437 bad_error("scf_instance_get_snapshot",
6438 scf_error());
6439 }
6440
6441 running = NULL;
6442 } else {
6443 r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
6444 switch (r) {
6445 case 0:
6446 running = imp_rsnpl;
6447 break;
6448
6449 case ECONNABORTED:
6450 goto connaborted;
6451
6452 case ECANCELED:
6453 warn(emsg_del, inst->sc_parent->sc_fmri,
6454 inst->sc_name);
6455 lcbdata->sc_err = EBUSY;
6456 r = UU_WALK_ERROR;
6457 goto deltemp;
6458
6459 case ENOENT:
6460 warn(emsg_badsnap, snap_running, inst->sc_fmri);
6461 lcbdata->sc_err = EBADF;
6462 r = UU_WALK_ERROR;
6463 goto deltemp;
6464
6465 default:
6466 bad_error("get_snaplevel", r);
6467 }
6468 }
6469
6470 r = upgrade_props(imp_inst, running, imp_snpl, inst);
6471 switch (r) {
6472 case 0:
6473 break;
6474
6475 case ECANCELED:
6476 case ENODEV:
6477 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6478 lcbdata->sc_err = EBUSY;
6479 r = UU_WALK_ERROR;
6480 goto deltemp;
6481
6482 case ECONNABORTED:
6483 goto connaborted;
6484
6485 case ENOMEM:
6486 case ENOSPC:
6487 case EBADF:
6488 case EBUSY:
6489 case EINVAL:
6490 case EPERM:
6491 case EROFS:
6492 case EACCES:
6493 case EEXIST:
6494 lcbdata->sc_err = r;
6495 r = UU_WALK_ERROR;
6496 goto deltemp;
6497
6498 default:
6499 bad_error("upgrade_props", r);
6500 }
6501
6502 inst->sc_import_state = IMPORT_PROP_DONE;
6503 } else {
6504 switch (scf_error()) {
6505 case SCF_ERROR_CONNECTION_BROKEN:
6506 goto connaborted;
6507
6508 case SCF_ERROR_NOT_FOUND:
6509 break;
6510
6511 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
6512 case SCF_ERROR_HANDLE_MISMATCH:
6513 case SCF_ERROR_NOT_BOUND:
6514 case SCF_ERROR_NOT_SET:
6515 default:
6516 bad_error("scf_service_get_instance", scf_error());
6517 }
6518
6519 fresh:
6520 /* create instance */
6521 if (scf_service_add_instance(rsvc, inst->sc_name,
6522 imp_inst) != 0) {
6523 switch (scf_error()) {
6524 case SCF_ERROR_CONNECTION_BROKEN:
6525 goto connaborted;
6526
6527 case SCF_ERROR_NO_RESOURCES:
6528 case SCF_ERROR_BACKEND_READONLY:
6529 case SCF_ERROR_BACKEND_ACCESS:
6530 r = stash_scferror(lcbdata);
6531 goto deltemp;
6532
6533 case SCF_ERROR_EXISTS:
6534 warn(gettext("%s changed unexpectedly "
6535 "(instance \"%s\" added).\n"),
6536 inst->sc_parent->sc_fmri, inst->sc_name);
6537 lcbdata->sc_err = EBUSY;
6538 r = UU_WALK_ERROR;
6539 goto deltemp;
6540
6541 case SCF_ERROR_PERMISSION_DENIED:
6542 warn(gettext("Could not create \"%s\" instance "
6543 "in %s (permission denied).\n"),
6544 inst->sc_name, inst->sc_parent->sc_fmri);
6545 r = stash_scferror(lcbdata);
6546 goto deltemp;
6547
6548 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
6549 case SCF_ERROR_HANDLE_MISMATCH:
6550 case SCF_ERROR_NOT_BOUND:
6551 case SCF_ERROR_NOT_SET:
6552 default:
6553 bad_error("scf_service_add_instance",
6554 scf_error());
6555 }
6556 }
6557
6558 nosnap:
6559 /*
6560 * Create a last-import snapshot to serve as an attachment
6561 * point for the real one from the temporary instance. Since
6562 * the contents is irrelevant, take it now, while the instance
6563 * is empty, to minimize svc.configd's work.
6564 */
6565 if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6566 imp_lisnap) != 0) {
6567 switch (scf_error()) {
6568 case SCF_ERROR_CONNECTION_BROKEN:
6569 goto connaborted;
6570
6571 case SCF_ERROR_NO_RESOURCES:
6572 r = stash_scferror(lcbdata);
6573 goto deltemp;
6574
6575 case SCF_ERROR_EXISTS:
6576 warn(gettext("%s changed unexpectedly "
6577 "(snapshot \"%s\" added).\n"),
6578 inst->sc_fmri, snap_lastimport);
6579 lcbdata->sc_err = EBUSY;
6580 r = UU_WALK_ERROR;
6581 goto deltemp;
6582
6583 case SCF_ERROR_PERMISSION_DENIED:
6584 warn(gettext("Could not take \"%s\" snapshot "
6585 "of %s (permission denied).\n"),
6586 snap_lastimport, inst->sc_fmri);
6587 r = stash_scferror(lcbdata);
6588 goto deltemp;
6589
6590 default:
6591 scfwarn();
6592 lcbdata->sc_err = -1;
6593 r = UU_WALK_ERROR;
6594 goto deltemp;
6595
6596 case SCF_ERROR_NOT_SET:
6597 case SCF_ERROR_INTERNAL:
6598 case SCF_ERROR_INVALID_ARGUMENT:
6599 case SCF_ERROR_HANDLE_MISMATCH:
6600 bad_error("_scf_snapshot_take_new",
6601 scf_error());
6602 }
6603 }
6604
6605 if (li_only)
6606 goto lionly;
6607
6608 inst->sc_import_state = IMPORT_PROP_BEGUN;
6609
6610 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6611 flags);
6612 switch (r) {
6613 case 0:
6614 break;
6615
6616 case ECONNABORTED:
6617 goto connaborted;
6618
6619 case ECANCELED:
6620 warn(gettext("%s changed unexpectedly "
6621 "(instance \"%s\" deleted).\n"),
6622 inst->sc_parent->sc_fmri, inst->sc_name);
6623 lcbdata->sc_err = EBUSY;
6624 r = UU_WALK_ERROR;
6625 goto deltemp;
6626
6627 case EEXIST:
6628 warn(gettext("%s changed unexpectedly "
6629 "(property group added).\n"), inst->sc_fmri);
6630 lcbdata->sc_err = EBUSY;
6631 r = UU_WALK_ERROR;
6632 goto deltemp;
6633
6634 default:
6635 lcbdata->sc_err = r;
6636 r = UU_WALK_ERROR;
6637 goto deltemp;
6638
6639 case EINVAL: /* caught above */
6640 bad_error("lscf_import_instance_pgs", r);
6641 }
6642
6643 ctx.sc_parent = imp_inst;
6644 ctx.sc_service = 0;
6645 ctx.sc_trans = NULL;
6646 ctx.sc_flags = 0;
6647 if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6648 &ctx, UU_DEFAULT) != 0) {
6649 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6650 bad_error("uu_list_walk", uu_error());
6651
6652 if (ctx.sc_err == ECONNABORTED)
6653 goto connaborted;
6654 lcbdata->sc_err = ctx.sc_err;
6655 r = UU_WALK_ERROR;
6656 goto deltemp;
6657 }
6658
6659 inst->sc_import_state = IMPORT_PROP_DONE;
6660
6661 if (g_verbose)
6662 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6663 snap_initial, inst->sc_fmri);
6664 r = take_snap(imp_inst, snap_initial, imp_snap);
6665 switch (r) {
6666 case 0:
6667 break;
6668
6669 case ECONNABORTED:
6670 goto connaborted;
6671
6672 case ENOSPC:
6673 case -1:
6674 lcbdata->sc_err = r;
6675 r = UU_WALK_ERROR;
6676 goto deltemp;
6677
6678 case ECANCELED:
6679 warn(gettext("%s changed unexpectedly "
6680 "(instance %s deleted).\n"),
6681 inst->sc_parent->sc_fmri, inst->sc_name);
6682 lcbdata->sc_err = r;
6683 r = UU_WALK_ERROR;
6684 goto deltemp;
6685
6686 case EPERM:
6687 warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6688 lcbdata->sc_err = r;
6689 r = UU_WALK_ERROR;
6690 goto deltemp;
6691
6692 default:
6693 bad_error("take_snap", r);
6694 }
6695 }
6696
6697 lionly:
6698 if (lcbdata->sc_flags & SCI_NOSNAP)
6699 goto deltemp;
6700
6701 /* transfer snapshot from temporary instance */
6702 if (g_verbose)
6703 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6704 snap_lastimport, inst->sc_fmri);
6705 if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6706 switch (scf_error()) {
6707 case SCF_ERROR_CONNECTION_BROKEN:
6708 goto connaborted;
6709
6710 case SCF_ERROR_NO_RESOURCES:
6711 r = stash_scferror(lcbdata);
6712 goto deltemp;
6713
6714 case SCF_ERROR_PERMISSION_DENIED:
6715 warn(gettext("Could not take \"%s\" snapshot for %s "
6716 "(permission denied).\n"), snap_lastimport,
6717 inst->sc_fmri);
6718 r = stash_scferror(lcbdata);
6719 goto deltemp;
6720
6721 case SCF_ERROR_NOT_SET:
6722 case SCF_ERROR_HANDLE_MISMATCH:
6723 default:
6724 bad_error("_scf_snapshot_attach", scf_error());
6725 }
6726 }
6727
6728 inst->sc_import_state = IMPORT_COMPLETE;
6729
6730 r = UU_WALK_NEXT;
6731
6732 deltemp:
6733 /* delete temporary instance */
6734 if (scf_instance_delete(imp_tinst) != 0) {
6735 switch (scf_error()) {
6736 case SCF_ERROR_DELETED:
6737 break;
6738
6739 case SCF_ERROR_CONNECTION_BROKEN:
6740 goto connaborted;
6741
6742 case SCF_ERROR_NOT_SET:
6743 case SCF_ERROR_NOT_BOUND:
6744 default:
6745 bad_error("scf_instance_delete", scf_error());
6746 }
6747 }
6748
6749 return (r);
6750
6751 connaborted:
6752 warn(gettext("Could not delete svc:/%s:%s "
6753 "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6754 lcbdata->sc_err = ECONNABORTED;
6755 return (UU_WALK_ERROR);
6756 }
6757
6758 /*
6759 * When an instance is imported we end up telling configd about it. Once we tell
6760 * configd about these changes, startd eventually notices. If this is a new
6761 * instance, the manifest may not specify the SCF_PG_RESTARTER (restarter)
6762 * property group. However, many of the other tools expect that this property
6763 * group exists and has certain values.
6764 *
6765 * These values are added asynchronously by startd. We should not return from
6766 * this routine until we can verify that the property group we need is there.
6767 *
6768 * Before we go ahead and verify this, we have to ask ourselves an important
6769 * question: Is the early manifest service currently running? Because if it is
6770 * running and it has invoked us, then the service will never get a restarter
6771 * property because svc.startd is blocked on EMI finishing before it lets itself
6772 * fully connect to svc.configd. Of course, this means that this race condition
6773 * is in fact impossible to 100% eliminate.
6774 *
6775 * svc.startd makes sure that EMI only runs once and has succeeded by checking
6776 * the state of the EMI instance. If it is online it bails out and makes sure
6777 * that it doesn't run again. In this case, we're going to do something similar,
6778 * only if the state is online, then we're going to actually verify. EMI always
6779 * has to be present, but it can be explicitly disabled to reduce the amount of
6780 * damage it can cause. If EMI has been disabled then we no longer have to worry
6781 * about the implicit race condition and can go ahead and check things. If EMI
6782 * is in some state that isn't online or disabled and isn't runinng, then we
6783 * assume that things are rather bad and we're not going to get in your way,
6784 * even if the rest of SMF does.
6785 *
6786 * Returns 0 on success or returns an errno.
6787 */
6788 #ifndef NATIVE_BUILD
6789 static int
lscf_instance_verify(scf_scope_t * scope,entity_t * svc,entity_t * inst)6790 lscf_instance_verify(scf_scope_t *scope, entity_t *svc, entity_t *inst)
6791 {
6792 int ret, err;
6793 struct timespec ts;
6794 char *emi_state;
6795
6796 /*
6797 * smf_get_state does not distinguish between its different failure
6798 * modes: memory allocation failures, SMF internal failures, and a lack
6799 * of EMI entirely because it's been removed. In these cases, we're
6800 * going to be conservative and opt to say that if we don't know, better
6801 * to not block import or falsely warn to the user.
6802 */
6803 if ((emi_state = smf_get_state(SCF_INSTANCE_EMI)) == NULL) {
6804 return (0);
6805 }
6806
6807 /*
6808 * As per the block comment for this function check the state of EMI
6809 */
6810 if (strcmp(emi_state, SCF_STATE_STRING_ONLINE) != 0 &&
6811 strcmp(emi_state, SCF_STATE_STRING_DISABLED) != 0) {
6812 warn(gettext("Not validating instance %s:%s because EMI's "
6813 "state is %s\n"), svc->sc_name, inst->sc_name, emi_state);
6814 free(emi_state);
6815 return (0);
6816 }
6817
6818 free(emi_state);
6819
6820 /*
6821 * First we have to get the property.
6822 */
6823 if ((ret = scf_scope_get_service(scope, svc->sc_name, imp_svc)) != 0) {
6824 ret = scf_error();
6825 warn(gettext("Failed to look up service: %s\n"), svc->sc_name);
6826 return (ret);
6827 }
6828
6829 /*
6830 * We should always be able to get the instance. It should already
6831 * exist because we just created it or got it. There probably is a
6832 * slim chance that someone may have come in and deleted it though from
6833 * under us.
6834 */
6835 if ((ret = scf_service_get_instance(imp_svc, inst->sc_name, imp_inst))
6836 != 0) {
6837 ret = scf_error();
6838 warn(gettext("Failed to verify instance: %s\n"), inst->sc_name);
6839 switch (ret) {
6840 case SCF_ERROR_DELETED:
6841 err = ENODEV;
6842 break;
6843 case SCF_ERROR_CONNECTION_BROKEN:
6844 warn(gettext("Lost repository connection\n"));
6845 err = ECONNABORTED;
6846 break;
6847 case SCF_ERROR_NOT_FOUND:
6848 warn(gettext("Instance \"%s\" disappeared out from "
6849 "under us.\n"), inst->sc_name);
6850 err = ENOENT;
6851 break;
6852 default:
6853 bad_error("scf_service_get_instance", ret);
6854 }
6855
6856 return (err);
6857 }
6858
6859 /*
6860 * An astute observer may want to use _scf_wait_pg which would notify us
6861 * of a property group change, unfortunately that does not work if the
6862 * property group in question does not exist. So instead we have to
6863 * manually poll and ask smf the best way to get to it.
6864 */
6865 while ((ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg))
6866 != SCF_SUCCESS) {
6867 ret = scf_error();
6868 if (ret != SCF_ERROR_NOT_FOUND) {
6869 warn(gettext("Failed to get restarter property "
6870 "group for instance: %s\n"), inst->sc_name);
6871 switch (ret) {
6872 case SCF_ERROR_DELETED:
6873 err = ENODEV;
6874 break;
6875 case SCF_ERROR_CONNECTION_BROKEN:
6876 warn(gettext("Lost repository connection\n"));
6877 err = ECONNABORTED;
6878 break;
6879 default:
6880 bad_error("scf_service_get_instance", ret);
6881 }
6882
6883 return (err);
6884 }
6885
6886 ts.tv_sec = pg_timeout / NANOSEC;
6887 ts.tv_nsec = pg_timeout % NANOSEC;
6888
6889 (void) nanosleep(&ts, NULL);
6890 }
6891
6892 /*
6893 * svcadm also expects that the SCF_PROPERTY_STATE property is present.
6894 * So in addition to the property group being present, we need to wait
6895 * for the property to be there in some form.
6896 *
6897 * Note that a property group is a frozen snapshot in time. To properly
6898 * get beyond this, you have to refresh the property group each time.
6899 */
6900 while ((ret = scf_pg_get_property(imp_pg, SCF_PROPERTY_STATE,
6901 imp_prop)) != 0) {
6902
6903 ret = scf_error();
6904 if (ret != SCF_ERROR_NOT_FOUND) {
6905 warn(gettext("Failed to get property %s from the "
6906 "restarter property group of instance %s\n"),
6907 SCF_PROPERTY_STATE, inst->sc_name);
6908 switch (ret) {
6909 case SCF_ERROR_CONNECTION_BROKEN:
6910 warn(gettext("Lost repository connection\n"));
6911 err = ECONNABORTED;
6912 break;
6913 case SCF_ERROR_DELETED:
6914 err = ENODEV;
6915 break;
6916 default:
6917 bad_error("scf_pg_get_property", ret);
6918 }
6919
6920 return (err);
6921 }
6922
6923 ts.tv_sec = pg_timeout / NANOSEC;
6924 ts.tv_nsec = pg_timeout % NANOSEC;
6925
6926 (void) nanosleep(&ts, NULL);
6927
6928 ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg);
6929 if (ret != SCF_SUCCESS) {
6930 warn(gettext("Failed to get restarter property "
6931 "group for instance: %s\n"), inst->sc_name);
6932 switch (ret) {
6933 case SCF_ERROR_DELETED:
6934 err = ENODEV;
6935 break;
6936 case SCF_ERROR_CONNECTION_BROKEN:
6937 warn(gettext("Lost repository connection\n"));
6938 err = ECONNABORTED;
6939 break;
6940 default:
6941 bad_error("scf_service_get_instance", ret);
6942 }
6943
6944 return (err);
6945 }
6946 }
6947
6948 /*
6949 * We don't have to free the property groups or other values that we got
6950 * because we stored them in global variables that are allocated and
6951 * freed by the routines that call into these functions. Unless of
6952 * course the rest of the code here that we are basing this on is
6953 * mistaken.
6954 */
6955 return (0);
6956 }
6957 #endif
6958
6959 /*
6960 * If the service is missing, create it, import its properties, and import the
6961 * instances. Since the service is brand new, it should be empty, and if we
6962 * run into any existing entities (SCF_ERROR_EXISTS), abort.
6963 *
6964 * If the service exists, we want to upgrade its properties and import the
6965 * instances. Upgrade requires a last-import snapshot, though, which are
6966 * children of instances, so first we'll have to go through the instances
6967 * looking for a last-import snapshot. If we don't find one then we'll just
6968 * override-import the service properties (but don't delete existing
6969 * properties: another service might have declared us as a dependent). Before
6970 * we change anything, though, we want to take the previous snapshots. We
6971 * also give lscf_instance_import() a leg up on taking last-import snapshots
6972 * by importing the manifest's service properties into a temporary service.
6973 *
6974 * On success, returns UU_WALK_NEXT. On failure, returns UU_WALK_ERROR and
6975 * sets lcbdata->sc_err to
6976 * ECONNABORTED - repository connection broken
6977 * ENOMEM - out of memory
6978 * ENOSPC - svc.configd is out of resources
6979 * EPERM - couldn't create temporary service (error printed)
6980 * - couldn't import into temp service (error printed)
6981 * - couldn't create service (error printed)
6982 * - couldn't import dependent (error printed)
6983 * - couldn't take snapshot (error printed)
6984 * - couldn't create instance (error printed)
6985 * - couldn't create, modify, or delete pg (error printed)
6986 * - couldn't create, modify, or delete dependent (error printed)
6987 * - couldn't import instance (error printed)
6988 * EROFS - couldn't create temporary service (repository read-only)
6989 * - couldn't import into temporary service (repository read-only)
6990 * - couldn't create service (repository read-only)
6991 * - couldn't import dependent (repository read-only)
6992 * - couldn't create instance (repository read-only)
6993 * - couldn't create, modify, or delete pg or dependent
6994 * - couldn't import instance (repository read-only)
6995 * EACCES - couldn't create temporary service (backend access denied)
6996 * - couldn't import into temporary service (backend access denied)
6997 * - couldn't create service (backend access denied)
6998 * - couldn't import dependent (backend access denied)
6999 * - couldn't create instance (backend access denied)
7000 * - couldn't create, modify, or delete pg or dependent
7001 * - couldn't import instance (backend access denied)
7002 * EINVAL - service name is invalid (error printed)
7003 * - service name is too long (error printed)
7004 * - s has invalid pgroup (error printed)
7005 * - s has invalid dependent (error printed)
7006 * - instance name is invalid (error printed)
7007 * - instance entity_t is invalid (error printed)
7008 * EEXIST - couldn't create temporary service (already exists) (error printed)
7009 * - couldn't import dependent (dependency pg already exists) (printed)
7010 * - dependency collision in dependent service (error printed)
7011 * EBUSY - temporary service deleted (error printed)
7012 * - property group added to temporary service (error printed)
7013 * - new property group changed or was deleted (error printed)
7014 * - service was added unexpectedly (error printed)
7015 * - service was deleted unexpectedly (error printed)
7016 * - property group added to new service (error printed)
7017 * - instance added unexpectedly (error printed)
7018 * - instance deleted unexpectedly (error printed)
7019 * - dependent service deleted unexpectedly (error printed)
7020 * - pg was added, changed, or deleted (error printed)
7021 * - dependent pg changed (error printed)
7022 * - temporary instance added, changed, or deleted (error printed)
7023 * EBADF - a last-import snapshot is corrupt (error printed)
7024 * - the service is corrupt (error printed)
7025 * - a dependent is corrupt (error printed)
7026 * - an instance is corrupt (error printed)
7027 * - an instance has a corrupt last-import snapshot (error printed)
7028 * - dependent target has a corrupt snapshot (error printed)
7029 * -1 - unknown libscf error (error printed)
7030 */
7031 static int
lscf_service_import(void * v,void * pvt)7032 lscf_service_import(void *v, void *pvt)
7033 {
7034 entity_t *s = v;
7035 scf_callback_t cbdata;
7036 scf_callback_t *lcbdata = pvt;
7037 scf_scope_t *scope = lcbdata->sc_parent;
7038 entity_t *inst, linst;
7039 int r;
7040 int fresh = 0;
7041 scf_snaplevel_t *running;
7042 int have_ge = 0;
7043 boolean_t retried = B_FALSE;
7044
7045 const char * const ts_deleted = gettext("Temporary service svc:/%s "
7046 "was deleted unexpectedly.\n");
7047 const char * const ts_pg_added = gettext("Temporary service svc:/%s "
7048 "changed unexpectedly (property group added).\n");
7049 const char * const s_deleted =
7050 gettext("%s was deleted unexpectedly.\n");
7051 const char * const i_deleted =
7052 gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
7053 const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
7054 "is corrupt (missing service snaplevel).\n");
7055 const char * const s_mfile_upd =
7056 gettext("Unable to update the manifest file connection "
7057 "for %s\n");
7058
7059 li_only = 0;
7060 /* Validate the service name */
7061 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7062 switch (scf_error()) {
7063 case SCF_ERROR_CONNECTION_BROKEN:
7064 return (stash_scferror(lcbdata));
7065
7066 case SCF_ERROR_INVALID_ARGUMENT:
7067 warn(gettext("\"%s\" is an invalid service name. "
7068 "Cannot import.\n"), s->sc_name);
7069 return (stash_scferror(lcbdata));
7070
7071 case SCF_ERROR_NOT_FOUND:
7072 break;
7073
7074 case SCF_ERROR_HANDLE_MISMATCH:
7075 case SCF_ERROR_NOT_BOUND:
7076 case SCF_ERROR_NOT_SET:
7077 default:
7078 bad_error("scf_scope_get_service", scf_error());
7079 }
7080 }
7081
7082 /* create temporary service */
7083 /*
7084 * the size of the buffer was reduced to max_scf_name_len to prevent
7085 * hitting bug 6681151. After the bug fix, the size of the buffer
7086 * should be restored to its original value (max_scf_name_len +1)
7087 */
7088 r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
7089 if (r < 0)
7090 bad_error("snprintf", errno);
7091 if (r > max_scf_name_len) {
7092 warn(gettext(
7093 "Service name \"%s\" is too long. Cannot import.\n"),
7094 s->sc_name);
7095 lcbdata->sc_err = EINVAL;
7096 return (UU_WALK_ERROR);
7097 }
7098
7099 retry:
7100 if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
7101 switch (scf_error()) {
7102 case SCF_ERROR_CONNECTION_BROKEN:
7103 case SCF_ERROR_NO_RESOURCES:
7104 case SCF_ERROR_BACKEND_READONLY:
7105 case SCF_ERROR_BACKEND_ACCESS:
7106 return (stash_scferror(lcbdata));
7107
7108 case SCF_ERROR_EXISTS:
7109 if (!retried) {
7110 lscf_delete(imp_tsname, 0);
7111 retried = B_TRUE;
7112 goto retry;
7113 }
7114 warn(gettext(
7115 "Temporary service \"%s\" must be deleted before "
7116 "this manifest can be imported.\n"), imp_tsname);
7117 return (stash_scferror(lcbdata));
7118
7119 case SCF_ERROR_PERMISSION_DENIED:
7120 warn(gettext("Could not create temporary service "
7121 "\"%s\" (permission denied).\n"), imp_tsname);
7122 return (stash_scferror(lcbdata));
7123
7124 case SCF_ERROR_INVALID_ARGUMENT:
7125 case SCF_ERROR_HANDLE_MISMATCH:
7126 case SCF_ERROR_NOT_BOUND:
7127 case SCF_ERROR_NOT_SET:
7128 default:
7129 bad_error("scf_scope_add_service", scf_error());
7130 }
7131 }
7132
7133 r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
7134 if (r < 0)
7135 bad_error("snprintf", errno);
7136
7137 cbdata.sc_handle = lcbdata->sc_handle;
7138 cbdata.sc_parent = imp_tsvc;
7139 cbdata.sc_service = 1;
7140 cbdata.sc_source_fmri = s->sc_fmri;
7141 cbdata.sc_target_fmri = imp_str;
7142 cbdata.sc_flags = 0;
7143
7144 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
7145 UU_DEFAULT) != 0) {
7146 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7147 bad_error("uu_list_walk", uu_error());
7148
7149 lcbdata->sc_err = cbdata.sc_err;
7150 switch (cbdata.sc_err) {
7151 case ECONNABORTED:
7152 goto connaborted;
7153
7154 case ECANCELED:
7155 warn(ts_deleted, imp_tsname);
7156 lcbdata->sc_err = EBUSY;
7157 return (UU_WALK_ERROR);
7158
7159 case EEXIST:
7160 warn(ts_pg_added, imp_tsname);
7161 lcbdata->sc_err = EBUSY;
7162 return (UU_WALK_ERROR);
7163 }
7164
7165 r = UU_WALK_ERROR;
7166 goto deltemp;
7167 }
7168
7169 if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
7170 UU_DEFAULT) != 0) {
7171 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7172 bad_error("uu_list_walk", uu_error());
7173
7174 lcbdata->sc_err = cbdata.sc_err;
7175 switch (cbdata.sc_err) {
7176 case ECONNABORTED:
7177 goto connaborted;
7178
7179 case ECANCELED:
7180 warn(ts_deleted, imp_tsname);
7181 lcbdata->sc_err = EBUSY;
7182 return (UU_WALK_ERROR);
7183
7184 case EEXIST:
7185 warn(ts_pg_added, imp_tsname);
7186 lcbdata->sc_err = EBUSY;
7187 return (UU_WALK_ERROR);
7188 }
7189
7190 r = UU_WALK_ERROR;
7191 goto deltemp;
7192 }
7193
7194 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7195 switch (scf_error()) {
7196 case SCF_ERROR_NOT_FOUND:
7197 break;
7198
7199 case SCF_ERROR_CONNECTION_BROKEN:
7200 goto connaborted;
7201
7202 case SCF_ERROR_INVALID_ARGUMENT:
7203 case SCF_ERROR_HANDLE_MISMATCH:
7204 case SCF_ERROR_NOT_BOUND:
7205 case SCF_ERROR_NOT_SET:
7206 default:
7207 bad_error("scf_scope_get_service", scf_error());
7208 }
7209
7210 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
7211 switch (scf_error()) {
7212 case SCF_ERROR_CONNECTION_BROKEN:
7213 goto connaborted;
7214
7215 case SCF_ERROR_NO_RESOURCES:
7216 case SCF_ERROR_BACKEND_READONLY:
7217 case SCF_ERROR_BACKEND_ACCESS:
7218 r = stash_scferror(lcbdata);
7219 goto deltemp;
7220
7221 case SCF_ERROR_EXISTS:
7222 warn(gettext("Scope \"%s\" changed unexpectedly"
7223 " (service \"%s\" added).\n"),
7224 SCF_SCOPE_LOCAL, s->sc_name);
7225 lcbdata->sc_err = EBUSY;
7226 goto deltemp;
7227
7228 case SCF_ERROR_PERMISSION_DENIED:
7229 warn(gettext("Could not create service \"%s\" "
7230 "(permission denied).\n"), s->sc_name);
7231 goto deltemp;
7232
7233 case SCF_ERROR_INVALID_ARGUMENT:
7234 case SCF_ERROR_HANDLE_MISMATCH:
7235 case SCF_ERROR_NOT_BOUND:
7236 case SCF_ERROR_NOT_SET:
7237 default:
7238 bad_error("scf_scope_add_service", scf_error());
7239 }
7240 }
7241
7242 s->sc_import_state = IMPORT_PROP_BEGUN;
7243
7244 /* import service properties */
7245 cbdata.sc_handle = lcbdata->sc_handle;
7246 cbdata.sc_parent = imp_svc;
7247 cbdata.sc_service = 1;
7248 cbdata.sc_flags = lcbdata->sc_flags;
7249 cbdata.sc_source_fmri = s->sc_fmri;
7250 cbdata.sc_target_fmri = s->sc_fmri;
7251
7252 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7253 &cbdata, UU_DEFAULT) != 0) {
7254 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7255 bad_error("uu_list_walk", uu_error());
7256
7257 lcbdata->sc_err = cbdata.sc_err;
7258 switch (cbdata.sc_err) {
7259 case ECONNABORTED:
7260 goto connaborted;
7261
7262 case ECANCELED:
7263 warn(s_deleted, s->sc_fmri);
7264 lcbdata->sc_err = EBUSY;
7265 return (UU_WALK_ERROR);
7266
7267 case EEXIST:
7268 warn(gettext("%s changed unexpectedly "
7269 "(property group added).\n"), s->sc_fmri);
7270 lcbdata->sc_err = EBUSY;
7271 return (UU_WALK_ERROR);
7272
7273 case EINVAL:
7274 /* caught above */
7275 bad_error("entity_pgroup_import",
7276 cbdata.sc_err);
7277 }
7278
7279 r = UU_WALK_ERROR;
7280 goto deltemp;
7281 }
7282
7283 cbdata.sc_trans = NULL;
7284 cbdata.sc_flags = 0;
7285 if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
7286 &cbdata, UU_DEFAULT) != 0) {
7287 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7288 bad_error("uu_list_walk", uu_error());
7289
7290 lcbdata->sc_err = cbdata.sc_err;
7291 if (cbdata.sc_err == ECONNABORTED)
7292 goto connaborted;
7293 r = UU_WALK_ERROR;
7294 goto deltemp;
7295 }
7296
7297 s->sc_import_state = IMPORT_PROP_DONE;
7298
7299 /*
7300 * This is a new service, so we can't take previous snapshots
7301 * or upgrade service properties.
7302 */
7303 fresh = 1;
7304 goto instances;
7305 }
7306
7307 /* Clear sc_seen for the instances. */
7308 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
7309 (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
7310 bad_error("uu_list_walk", uu_error());
7311
7312 /*
7313 * Take previous snapshots for all instances. Even for ones not
7314 * mentioned in the bundle, since we might change their service
7315 * properties.
7316 */
7317 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7318 switch (scf_error()) {
7319 case SCF_ERROR_CONNECTION_BROKEN:
7320 goto connaborted;
7321
7322 case SCF_ERROR_DELETED:
7323 warn(s_deleted, s->sc_fmri);
7324 lcbdata->sc_err = EBUSY;
7325 r = UU_WALK_ERROR;
7326 goto deltemp;
7327
7328 case SCF_ERROR_HANDLE_MISMATCH:
7329 case SCF_ERROR_NOT_BOUND:
7330 case SCF_ERROR_NOT_SET:
7331 default:
7332 bad_error("scf_iter_service_instances", scf_error());
7333 }
7334 }
7335
7336 for (;;) {
7337 r = scf_iter_next_instance(imp_iter, imp_inst);
7338 if (r == 0)
7339 break;
7340 if (r != 1) {
7341 switch (scf_error()) {
7342 case SCF_ERROR_DELETED:
7343 warn(s_deleted, s->sc_fmri);
7344 lcbdata->sc_err = EBUSY;
7345 r = UU_WALK_ERROR;
7346 goto deltemp;
7347
7348 case SCF_ERROR_CONNECTION_BROKEN:
7349 goto connaborted;
7350
7351 case SCF_ERROR_NOT_BOUND:
7352 case SCF_ERROR_HANDLE_MISMATCH:
7353 case SCF_ERROR_INVALID_ARGUMENT:
7354 case SCF_ERROR_NOT_SET:
7355 default:
7356 bad_error("scf_iter_next_instance",
7357 scf_error());
7358 }
7359 }
7360
7361 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
7362 switch (scf_error()) {
7363 case SCF_ERROR_DELETED:
7364 continue;
7365
7366 case SCF_ERROR_CONNECTION_BROKEN:
7367 goto connaborted;
7368
7369 case SCF_ERROR_NOT_SET:
7370 case SCF_ERROR_NOT_BOUND:
7371 default:
7372 bad_error("scf_instance_get_name", scf_error());
7373 }
7374 }
7375
7376 if (g_verbose)
7377 warn(gettext(
7378 "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
7379 snap_previous, s->sc_name, imp_str);
7380
7381 r = take_snap(imp_inst, snap_previous, imp_snap);
7382 switch (r) {
7383 case 0:
7384 break;
7385
7386 case ECANCELED:
7387 continue;
7388
7389 case ECONNABORTED:
7390 goto connaborted;
7391
7392 case EPERM:
7393 warn(gettext("Could not take \"%s\" snapshot of "
7394 "svc:/%s:%s (permission denied).\n"),
7395 snap_previous, s->sc_name, imp_str);
7396 lcbdata->sc_err = r;
7397 return (UU_WALK_ERROR);
7398
7399 case ENOSPC:
7400 case -1:
7401 lcbdata->sc_err = r;
7402 r = UU_WALK_ERROR;
7403 goto deltemp;
7404
7405 default:
7406 bad_error("take_snap", r);
7407 }
7408
7409 linst.sc_name = imp_str;
7410 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
7411 &linst, NULL, NULL);
7412 if (inst != NULL) {
7413 inst->sc_import_state = IMPORT_PREVIOUS;
7414 inst->sc_seen = 1;
7415 }
7416 }
7417
7418 /*
7419 * Create the new instances and take previous snapshots of
7420 * them. This is not necessary, but it maximizes data preservation.
7421 */
7422 for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
7423 inst != NULL;
7424 inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
7425 inst)) {
7426 if (inst->sc_seen)
7427 continue;
7428
7429 if (scf_service_add_instance(imp_svc, inst->sc_name,
7430 imp_inst) != 0) {
7431 switch (scf_error()) {
7432 case SCF_ERROR_CONNECTION_BROKEN:
7433 goto connaborted;
7434
7435 case SCF_ERROR_BACKEND_READONLY:
7436 case SCF_ERROR_BACKEND_ACCESS:
7437 case SCF_ERROR_NO_RESOURCES:
7438 r = stash_scferror(lcbdata);
7439 goto deltemp;
7440
7441 case SCF_ERROR_EXISTS:
7442 warn(gettext("%s changed unexpectedly "
7443 "(instance \"%s\" added).\n"), s->sc_fmri,
7444 inst->sc_name);
7445 lcbdata->sc_err = EBUSY;
7446 r = UU_WALK_ERROR;
7447 goto deltemp;
7448
7449 case SCF_ERROR_INVALID_ARGUMENT:
7450 warn(gettext("Service \"%s\" has instance with "
7451 "invalid name \"%s\".\n"), s->sc_name,
7452 inst->sc_name);
7453 r = stash_scferror(lcbdata);
7454 goto deltemp;
7455
7456 case SCF_ERROR_PERMISSION_DENIED:
7457 warn(gettext("Could not create instance \"%s\" "
7458 "in %s (permission denied).\n"),
7459 inst->sc_name, s->sc_fmri);
7460 r = stash_scferror(lcbdata);
7461 goto deltemp;
7462
7463 case SCF_ERROR_HANDLE_MISMATCH:
7464 case SCF_ERROR_NOT_BOUND:
7465 case SCF_ERROR_NOT_SET:
7466 default:
7467 bad_error("scf_service_add_instance",
7468 scf_error());
7469 }
7470 }
7471
7472 if (g_verbose)
7473 warn(gettext("Taking \"%s\" snapshot for "
7474 "new service %s.\n"), snap_previous, inst->sc_fmri);
7475 r = take_snap(imp_inst, snap_previous, imp_snap);
7476 switch (r) {
7477 case 0:
7478 break;
7479
7480 case ECANCELED:
7481 warn(i_deleted, s->sc_fmri, inst->sc_name);
7482 lcbdata->sc_err = EBUSY;
7483 r = UU_WALK_ERROR;
7484 goto deltemp;
7485
7486 case ECONNABORTED:
7487 goto connaborted;
7488
7489 case EPERM:
7490 warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
7491 lcbdata->sc_err = r;
7492 r = UU_WALK_ERROR;
7493 goto deltemp;
7494
7495 case ENOSPC:
7496 case -1:
7497 r = UU_WALK_ERROR;
7498 goto deltemp;
7499
7500 default:
7501 bad_error("take_snap", r);
7502 }
7503 }
7504
7505 s->sc_import_state = IMPORT_PREVIOUS;
7506
7507 /*
7508 * Upgrade service properties, if we can find a last-import snapshot.
7509 * Any will do because we don't support different service properties
7510 * in different manifests, so all snaplevels of the service in all of
7511 * the last-import snapshots of the instances should be the same.
7512 */
7513 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7514 switch (scf_error()) {
7515 case SCF_ERROR_CONNECTION_BROKEN:
7516 goto connaborted;
7517
7518 case SCF_ERROR_DELETED:
7519 warn(s_deleted, s->sc_fmri);
7520 lcbdata->sc_err = EBUSY;
7521 r = UU_WALK_ERROR;
7522 goto deltemp;
7523
7524 case SCF_ERROR_HANDLE_MISMATCH:
7525 case SCF_ERROR_NOT_BOUND:
7526 case SCF_ERROR_NOT_SET:
7527 default:
7528 bad_error("scf_iter_service_instances", scf_error());
7529 }
7530 }
7531
7532 for (;;) {
7533 r = scf_iter_next_instance(imp_iter, imp_inst);
7534 if (r == -1) {
7535 switch (scf_error()) {
7536 case SCF_ERROR_DELETED:
7537 warn(s_deleted, s->sc_fmri);
7538 lcbdata->sc_err = EBUSY;
7539 r = UU_WALK_ERROR;
7540 goto deltemp;
7541
7542 case SCF_ERROR_CONNECTION_BROKEN:
7543 goto connaborted;
7544
7545 case SCF_ERROR_NOT_BOUND:
7546 case SCF_ERROR_HANDLE_MISMATCH:
7547 case SCF_ERROR_INVALID_ARGUMENT:
7548 case SCF_ERROR_NOT_SET:
7549 default:
7550 bad_error("scf_iter_next_instance",
7551 scf_error());
7552 }
7553 }
7554
7555 if (r == 0) {
7556 /*
7557 * Didn't find any last-import snapshots. Override-
7558 * import the properties. Unless one of the instances
7559 * has a general/enabled property, in which case we're
7560 * probably running a last-import-capable svccfg for
7561 * the first time, and we should only take the
7562 * last-import snapshot.
7563 */
7564 if (have_ge) {
7565 pgroup_t *mfpg;
7566 scf_callback_t mfcbdata;
7567
7568 li_only = 1;
7569 no_refresh = 1;
7570 /*
7571 * Need to go ahead and import the manifestfiles
7572 * pg if it exists. If the last-import snapshot
7573 * upgrade code is ever removed this code can
7574 * be removed as well.
7575 */
7576 mfpg = internal_pgroup_find(s,
7577 SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
7578
7579 if (mfpg) {
7580 mfcbdata.sc_handle = g_hndl;
7581 mfcbdata.sc_parent = imp_svc;
7582 mfcbdata.sc_service = 1;
7583 mfcbdata.sc_flags = SCI_FORCE;
7584 mfcbdata.sc_source_fmri = s->sc_fmri;
7585 mfcbdata.sc_target_fmri = s->sc_fmri;
7586 if (entity_pgroup_import(mfpg,
7587 &mfcbdata) != UU_WALK_NEXT) {
7588 warn(s_mfile_upd, s->sc_fmri);
7589 r = UU_WALK_ERROR;
7590 goto deltemp;
7591 }
7592 }
7593 break;
7594 }
7595
7596 s->sc_import_state = IMPORT_PROP_BEGUN;
7597
7598 cbdata.sc_handle = g_hndl;
7599 cbdata.sc_parent = imp_svc;
7600 cbdata.sc_service = 1;
7601 cbdata.sc_flags = SCI_FORCE;
7602 cbdata.sc_source_fmri = s->sc_fmri;
7603 cbdata.sc_target_fmri = s->sc_fmri;
7604 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7605 &cbdata, UU_DEFAULT) != 0) {
7606 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7607 bad_error("uu_list_walk", uu_error());
7608 lcbdata->sc_err = cbdata.sc_err;
7609 switch (cbdata.sc_err) {
7610 case ECONNABORTED:
7611 goto connaborted;
7612
7613 case ECANCELED:
7614 warn(s_deleted, s->sc_fmri);
7615 lcbdata->sc_err = EBUSY;
7616 break;
7617
7618 case EINVAL: /* caught above */
7619 case EEXIST:
7620 bad_error("entity_pgroup_import",
7621 cbdata.sc_err);
7622 }
7623
7624 r = UU_WALK_ERROR;
7625 goto deltemp;
7626 }
7627
7628 cbdata.sc_trans = NULL;
7629 cbdata.sc_flags = 0;
7630 if (uu_list_walk(s->sc_dependents,
7631 lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
7632 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7633 bad_error("uu_list_walk", uu_error());
7634 lcbdata->sc_err = cbdata.sc_err;
7635 if (cbdata.sc_err == ECONNABORTED)
7636 goto connaborted;
7637 r = UU_WALK_ERROR;
7638 goto deltemp;
7639 }
7640 break;
7641 }
7642
7643 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
7644 imp_snap) != 0) {
7645 switch (scf_error()) {
7646 case SCF_ERROR_DELETED:
7647 continue;
7648
7649 case SCF_ERROR_NOT_FOUND:
7650 break;
7651
7652 case SCF_ERROR_CONNECTION_BROKEN:
7653 goto connaborted;
7654
7655 case SCF_ERROR_HANDLE_MISMATCH:
7656 case SCF_ERROR_NOT_BOUND:
7657 case SCF_ERROR_INVALID_ARGUMENT:
7658 case SCF_ERROR_NOT_SET:
7659 default:
7660 bad_error("scf_instance_get_snapshot",
7661 scf_error());
7662 }
7663
7664 if (have_ge)
7665 continue;
7666
7667 /*
7668 * Check for a general/enabled property. This is how
7669 * we tell whether to import if there turn out to be
7670 * no last-import snapshots.
7671 */
7672 if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
7673 imp_pg) == 0) {
7674 if (scf_pg_get_property(imp_pg,
7675 SCF_PROPERTY_ENABLED, imp_prop) == 0) {
7676 have_ge = 1;
7677 } else {
7678 switch (scf_error()) {
7679 case SCF_ERROR_DELETED:
7680 case SCF_ERROR_NOT_FOUND:
7681 continue;
7682
7683 case SCF_ERROR_INVALID_ARGUMENT:
7684 case SCF_ERROR_HANDLE_MISMATCH:
7685 case SCF_ERROR_CONNECTION_BROKEN:
7686 case SCF_ERROR_NOT_BOUND:
7687 case SCF_ERROR_NOT_SET:
7688 default:
7689 bad_error("scf_pg_get_property",
7690 scf_error());
7691 }
7692 }
7693 } else {
7694 switch (scf_error()) {
7695 case SCF_ERROR_DELETED:
7696 case SCF_ERROR_NOT_FOUND:
7697 continue;
7698
7699 case SCF_ERROR_CONNECTION_BROKEN:
7700 goto connaborted;
7701
7702 case SCF_ERROR_NOT_BOUND:
7703 case SCF_ERROR_NOT_SET:
7704 case SCF_ERROR_INVALID_ARGUMENT:
7705 case SCF_ERROR_HANDLE_MISMATCH:
7706 default:
7707 bad_error("scf_instance_get_pg",
7708 scf_error());
7709 }
7710 }
7711 continue;
7712 }
7713
7714 /* find service snaplevel */
7715 r = get_snaplevel(imp_snap, 1, imp_snpl);
7716 switch (r) {
7717 case 0:
7718 break;
7719
7720 case ECONNABORTED:
7721 goto connaborted;
7722
7723 case ECANCELED:
7724 continue;
7725
7726 case ENOENT:
7727 if (scf_instance_get_name(imp_inst, imp_str,
7728 imp_str_sz) < 0)
7729 (void) strcpy(imp_str, "?");
7730 warn(badsnap, snap_lastimport, s->sc_name, imp_str);
7731 lcbdata->sc_err = EBADF;
7732 r = UU_WALK_ERROR;
7733 goto deltemp;
7734
7735 default:
7736 bad_error("get_snaplevel", r);
7737 }
7738
7739 if (scf_instance_get_snapshot(imp_inst, snap_running,
7740 imp_rsnap) != 0) {
7741 switch (scf_error()) {
7742 case SCF_ERROR_DELETED:
7743 continue;
7744
7745 case SCF_ERROR_NOT_FOUND:
7746 break;
7747
7748 case SCF_ERROR_CONNECTION_BROKEN:
7749 goto connaborted;
7750
7751 case SCF_ERROR_INVALID_ARGUMENT:
7752 case SCF_ERROR_HANDLE_MISMATCH:
7753 case SCF_ERROR_NOT_BOUND:
7754 case SCF_ERROR_NOT_SET:
7755 default:
7756 bad_error("scf_instance_get_snapshot",
7757 scf_error());
7758 }
7759 running = NULL;
7760 } else {
7761 r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
7762 switch (r) {
7763 case 0:
7764 running = imp_rsnpl;
7765 break;
7766
7767 case ECONNABORTED:
7768 goto connaborted;
7769
7770 case ECANCELED:
7771 continue;
7772
7773 case ENOENT:
7774 if (scf_instance_get_name(imp_inst, imp_str,
7775 imp_str_sz) < 0)
7776 (void) strcpy(imp_str, "?");
7777 warn(badsnap, snap_running, s->sc_name,
7778 imp_str);
7779 lcbdata->sc_err = EBADF;
7780 r = UU_WALK_ERROR;
7781 goto deltemp;
7782
7783 default:
7784 bad_error("get_snaplevel", r);
7785 }
7786 }
7787
7788 if (g_verbose) {
7789 if (scf_instance_get_name(imp_inst, imp_str,
7790 imp_str_sz) < 0)
7791 (void) strcpy(imp_str, "?");
7792 warn(gettext("Upgrading properties of %s according to "
7793 "instance \"%s\".\n"), s->sc_fmri, imp_str);
7794 }
7795
7796 /* upgrade service properties */
7797 r = upgrade_props(imp_svc, running, imp_snpl, s);
7798 if (r == 0)
7799 break;
7800
7801 switch (r) {
7802 case ECONNABORTED:
7803 goto connaborted;
7804
7805 case ECANCELED:
7806 warn(s_deleted, s->sc_fmri);
7807 lcbdata->sc_err = EBUSY;
7808 break;
7809
7810 case ENODEV:
7811 if (scf_instance_get_name(imp_inst, imp_str,
7812 imp_str_sz) < 0)
7813 (void) strcpy(imp_str, "?");
7814 warn(i_deleted, s->sc_fmri, imp_str);
7815 lcbdata->sc_err = EBUSY;
7816 break;
7817
7818 default:
7819 lcbdata->sc_err = r;
7820 }
7821
7822 r = UU_WALK_ERROR;
7823 goto deltemp;
7824 }
7825
7826 s->sc_import_state = IMPORT_PROP_DONE;
7827
7828 instances:
7829 /* import instances */
7830 cbdata.sc_handle = lcbdata->sc_handle;
7831 cbdata.sc_parent = imp_svc;
7832 cbdata.sc_service = 1;
7833 cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7834 cbdata.sc_general = NULL;
7835
7836 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7837 lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7838 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7839 bad_error("uu_list_walk", uu_error());
7840
7841 lcbdata->sc_err = cbdata.sc_err;
7842 if (cbdata.sc_err == ECONNABORTED)
7843 goto connaborted;
7844 r = UU_WALK_ERROR;
7845 goto deltemp;
7846 }
7847
7848 s->sc_import_state = IMPORT_COMPLETE;
7849 r = UU_WALK_NEXT;
7850
7851 deltemp:
7852 /* delete temporary service */
7853 if (scf_service_delete(imp_tsvc) != 0) {
7854 switch (scf_error()) {
7855 case SCF_ERROR_DELETED:
7856 break;
7857
7858 case SCF_ERROR_CONNECTION_BROKEN:
7859 goto connaborted;
7860
7861 case SCF_ERROR_EXISTS:
7862 warn(gettext(
7863 "Could not delete svc:/%s (instances exist).\n"),
7864 imp_tsname);
7865 break;
7866
7867 case SCF_ERROR_NOT_SET:
7868 case SCF_ERROR_NOT_BOUND:
7869 default:
7870 bad_error("scf_service_delete", scf_error());
7871 }
7872 }
7873
7874 return (r);
7875
7876 connaborted:
7877 warn(gettext("Could not delete svc:/%s "
7878 "(repository connection broken).\n"), imp_tsname);
7879 lcbdata->sc_err = ECONNABORTED;
7880 return (UU_WALK_ERROR);
7881 }
7882
7883 static const char *
import_progress(int st)7884 import_progress(int st)
7885 {
7886 switch (st) {
7887 case 0:
7888 return (gettext("not reached."));
7889
7890 case IMPORT_PREVIOUS:
7891 return (gettext("previous snapshot taken."));
7892
7893 case IMPORT_PROP_BEGUN:
7894 return (gettext("some properties imported."));
7895
7896 case IMPORT_PROP_DONE:
7897 return (gettext("properties imported."));
7898
7899 case IMPORT_COMPLETE:
7900 return (gettext("imported."));
7901
7902 case IMPORT_REFRESHED:
7903 return (gettext("refresh requested."));
7904
7905 default:
7906 #ifndef NDEBUG
7907 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7908 __FILE__, __LINE__, st);
7909 #endif
7910 abort();
7911 /* NOTREACHED */
7912 }
7913 }
7914
7915 /*
7916 * Returns
7917 * 0 - success
7918 * - fmri wasn't found (error printed)
7919 * - entity was deleted (error printed)
7920 * - backend denied access (error printed)
7921 * ENOMEM - out of memory (error printed)
7922 * ECONNABORTED - repository connection broken (error printed)
7923 * EPERM - permission denied (error printed)
7924 * -1 - unknown libscf error (error printed)
7925 */
7926 static int
imp_refresh_fmri(const char * fmri,const char * name,const char * d_fmri)7927 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7928 {
7929 scf_error_t serr;
7930 void *ent;
7931 int issvc;
7932 int r;
7933
7934 const char *deleted = gettext("Could not refresh %s (deleted).\n");
7935 const char *dpt_deleted = gettext("Could not refresh %s "
7936 "(dependent \"%s\" of %s) (deleted).\n");
7937
7938 serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7939 switch (serr) {
7940 case SCF_ERROR_NONE:
7941 break;
7942
7943 case SCF_ERROR_NO_MEMORY:
7944 if (name == NULL)
7945 warn(gettext("Could not refresh %s (out of memory).\n"),
7946 fmri);
7947 else
7948 warn(gettext("Could not refresh %s "
7949 "(dependent \"%s\" of %s) (out of memory).\n"),
7950 fmri, name, d_fmri);
7951 return (ENOMEM);
7952
7953 case SCF_ERROR_NOT_FOUND:
7954 if (name == NULL)
7955 warn(deleted, fmri);
7956 else
7957 warn(dpt_deleted, fmri, name, d_fmri);
7958 return (0);
7959
7960 case SCF_ERROR_INVALID_ARGUMENT:
7961 case SCF_ERROR_CONSTRAINT_VIOLATED:
7962 default:
7963 bad_error("fmri_to_entity", serr);
7964 }
7965
7966 r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7967 switch (r) {
7968 case 0:
7969 break;
7970
7971 case ECONNABORTED:
7972 if (name != NULL)
7973 warn(gettext("Could not refresh %s "
7974 "(dependent \"%s\" of %s) "
7975 "(repository connection broken).\n"), fmri, name,
7976 d_fmri);
7977 return (r);
7978
7979 case ECANCELED:
7980 if (name == NULL)
7981 warn(deleted, fmri);
7982 else
7983 warn(dpt_deleted, fmri, name, d_fmri);
7984 return (0);
7985
7986 case EACCES:
7987 if (!g_verbose)
7988 return (0);
7989 if (name == NULL)
7990 warn(gettext("Could not refresh %s "
7991 "(backend access denied).\n"), fmri);
7992 else
7993 warn(gettext("Could not refresh %s "
7994 "(dependent \"%s\" of %s) "
7995 "(backend access denied).\n"), fmri, name, d_fmri);
7996 return (0);
7997
7998 case EPERM:
7999 if (name == NULL)
8000 warn(gettext("Could not refresh %s "
8001 "(permission denied).\n"), fmri);
8002 else
8003 warn(gettext("Could not refresh %s "
8004 "(dependent \"%s\" of %s) "
8005 "(permission denied).\n"), fmri, name, d_fmri);
8006 return (r);
8007
8008 case ENOSPC:
8009 if (name == NULL)
8010 warn(gettext("Could not refresh %s "
8011 "(repository server out of resources).\n"),
8012 fmri);
8013 else
8014 warn(gettext("Could not refresh %s "
8015 "(dependent \"%s\" of %s) "
8016 "(repository server out of resources).\n"),
8017 fmri, name, d_fmri);
8018 return (r);
8019
8020 case -1:
8021 scfwarn();
8022 return (r);
8023
8024 default:
8025 bad_error("refresh_entity", r);
8026 }
8027
8028 if (issvc)
8029 scf_service_destroy(ent);
8030 else
8031 scf_instance_destroy(ent);
8032
8033 return (0);
8034 }
8035
8036 static int
alloc_imp_globals()8037 alloc_imp_globals()
8038 {
8039 int r;
8040
8041 const char * const emsg_nomem = gettext("Out of memory.\n");
8042 const char * const emsg_nores =
8043 gettext("svc.configd is out of resources.\n");
8044
8045 imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
8046 max_scf_name_len : max_scf_fmri_len) + 1;
8047
8048 if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
8049 (imp_svc = scf_service_create(g_hndl)) == NULL ||
8050 (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
8051 (imp_inst = scf_instance_create(g_hndl)) == NULL ||
8052 (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
8053 (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
8054 (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
8055 (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
8056 (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
8057 (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8058 (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
8059 (imp_pg = scf_pg_create(g_hndl)) == NULL ||
8060 (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
8061 (imp_prop = scf_property_create(g_hndl)) == NULL ||
8062 (imp_iter = scf_iter_create(g_hndl)) == NULL ||
8063 (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
8064 (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
8065 (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
8066 (imp_str = malloc(imp_str_sz)) == NULL ||
8067 (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
8068 (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
8069 (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
8070 (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
8071 (ud_inst = scf_instance_create(g_hndl)) == NULL ||
8072 (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8073 (ud_pg = scf_pg_create(g_hndl)) == NULL ||
8074 (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
8075 (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
8076 (ud_prop = scf_property_create(g_hndl)) == NULL ||
8077 (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
8078 (ud_val = scf_value_create(g_hndl)) == NULL ||
8079 (ud_iter = scf_iter_create(g_hndl)) == NULL ||
8080 (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
8081 (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
8082 (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
8083 (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
8084 (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
8085 if (scf_error() == SCF_ERROR_NO_RESOURCES)
8086 warn(emsg_nores);
8087 else
8088 warn(emsg_nomem);
8089
8090 return (-1);
8091 }
8092
8093 r = load_init();
8094 switch (r) {
8095 case 0:
8096 break;
8097
8098 case ENOMEM:
8099 warn(emsg_nomem);
8100 return (-1);
8101
8102 default:
8103 bad_error("load_init", r);
8104 }
8105
8106 return (0);
8107 }
8108
8109 static void
free_imp_globals()8110 free_imp_globals()
8111 {
8112 pgroup_t *old_dpt;
8113 void *cookie;
8114
8115 load_fini();
8116
8117 free(ud_ctarg);
8118 free(ud_oldtarg);
8119 free(ud_name);
8120 ud_ctarg = ud_oldtarg = ud_name = NULL;
8121
8122 scf_transaction_destroy(ud_tx);
8123 ud_tx = NULL;
8124 scf_iter_destroy(ud_iter);
8125 scf_iter_destroy(ud_iter2);
8126 ud_iter = ud_iter2 = NULL;
8127 scf_value_destroy(ud_val);
8128 ud_val = NULL;
8129 scf_property_destroy(ud_prop);
8130 scf_property_destroy(ud_dpt_prop);
8131 ud_prop = ud_dpt_prop = NULL;
8132 scf_pg_destroy(ud_pg);
8133 scf_pg_destroy(ud_cur_depts_pg);
8134 scf_pg_destroy(ud_run_dpts_pg);
8135 ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
8136 scf_snaplevel_destroy(ud_snpl);
8137 ud_snpl = NULL;
8138 scf_instance_destroy(ud_inst);
8139 ud_inst = NULL;
8140
8141 free(imp_str);
8142 free(imp_tsname);
8143 free(imp_fe1);
8144 free(imp_fe2);
8145 imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
8146
8147 cookie = NULL;
8148 while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
8149 NULL) {
8150 free((char *)old_dpt->sc_pgroup_name);
8151 free((char *)old_dpt->sc_pgroup_fmri);
8152 internal_pgroup_free(old_dpt);
8153 }
8154 uu_list_destroy(imp_deleted_dpts);
8155
8156 scf_transaction_destroy(imp_tx);
8157 imp_tx = NULL;
8158 scf_iter_destroy(imp_iter);
8159 scf_iter_destroy(imp_rpg_iter);
8160 scf_iter_destroy(imp_up_iter);
8161 imp_iter = imp_rpg_iter = imp_up_iter = NULL;
8162 scf_property_destroy(imp_prop);
8163 imp_prop = NULL;
8164 scf_pg_destroy(imp_pg);
8165 scf_pg_destroy(imp_pg2);
8166 imp_pg = imp_pg2 = NULL;
8167 scf_snaplevel_destroy(imp_snpl);
8168 scf_snaplevel_destroy(imp_rsnpl);
8169 imp_snpl = imp_rsnpl = NULL;
8170 scf_snapshot_destroy(imp_snap);
8171 scf_snapshot_destroy(imp_lisnap);
8172 scf_snapshot_destroy(imp_tlisnap);
8173 scf_snapshot_destroy(imp_rsnap);
8174 imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
8175 scf_instance_destroy(imp_inst);
8176 scf_instance_destroy(imp_tinst);
8177 imp_inst = imp_tinst = NULL;
8178 scf_service_destroy(imp_svc);
8179 scf_service_destroy(imp_tsvc);
8180 imp_svc = imp_tsvc = NULL;
8181 scf_scope_destroy(imp_scope);
8182 imp_scope = NULL;
8183
8184 load_fini();
8185 }
8186
8187 int
lscf_bundle_import(bundle_t * bndl,const char * filename,uint_t flags)8188 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
8189 {
8190 scf_callback_t cbdata;
8191 int result = 0;
8192 entity_t *svc, *inst;
8193 uu_list_t *insts;
8194 int r;
8195 pgroup_t *old_dpt;
8196 int annotation_set = 0;
8197
8198 const char * const emsg_nomem = gettext("Out of memory.\n");
8199 const char * const emsg_nores =
8200 gettext("svc.configd is out of resources.\n");
8201
8202 lscf_prep_hndl();
8203
8204 if (alloc_imp_globals())
8205 goto out;
8206
8207 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
8208 switch (scf_error()) {
8209 case SCF_ERROR_CONNECTION_BROKEN:
8210 warn(gettext("Repository connection broken.\n"));
8211 repository_teardown();
8212 result = -1;
8213 goto out;
8214
8215 case SCF_ERROR_NOT_FOUND:
8216 case SCF_ERROR_INVALID_ARGUMENT:
8217 case SCF_ERROR_NOT_BOUND:
8218 case SCF_ERROR_HANDLE_MISMATCH:
8219 default:
8220 bad_error("scf_handle_get_scope", scf_error());
8221 }
8222 }
8223
8224 /* Set up the auditing annotation. */
8225 if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
8226 annotation_set = 1;
8227 } else {
8228 switch (scf_error()) {
8229 case SCF_ERROR_CONNECTION_BROKEN:
8230 warn(gettext("Repository connection broken.\n"));
8231 repository_teardown();
8232 result = -1;
8233 goto out;
8234
8235 case SCF_ERROR_INVALID_ARGUMENT:
8236 case SCF_ERROR_NOT_BOUND:
8237 case SCF_ERROR_NO_RESOURCES:
8238 case SCF_ERROR_INTERNAL:
8239 bad_error("_scf_set_annotation", scf_error());
8240 /* NOTREACHED */
8241
8242 default:
8243 /*
8244 * Do not terminate import because of inability to
8245 * generate annotation audit event.
8246 */
8247 warn(gettext("_scf_set_annotation() unexpectedly "
8248 "failed with return code of %d\n"), scf_error());
8249 break;
8250 }
8251 }
8252
8253 /*
8254 * Clear the sc_import_state's of all services & instances so we can
8255 * report how far we got if we fail.
8256 */
8257 for (svc = uu_list_first(bndl->sc_bundle_services);
8258 svc != NULL;
8259 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8260 svc->sc_import_state = 0;
8261
8262 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
8263 clear_int, (void *)offsetof(entity_t, sc_import_state),
8264 UU_DEFAULT) != 0)
8265 bad_error("uu_list_walk", uu_error());
8266 }
8267
8268 cbdata.sc_handle = g_hndl;
8269 cbdata.sc_parent = imp_scope;
8270 cbdata.sc_flags = flags;
8271 cbdata.sc_general = NULL;
8272
8273 if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
8274 &cbdata, UU_DEFAULT) == 0) {
8275 char *eptr;
8276 /* Success. Refresh everything. */
8277
8278 if (flags & SCI_NOREFRESH || no_refresh) {
8279 no_refresh = 0;
8280 result = 0;
8281 goto out;
8282 }
8283
8284 for (svc = uu_list_first(bndl->sc_bundle_services);
8285 svc != NULL;
8286 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8287 pgroup_t *dpt;
8288
8289 insts = svc->sc_u.sc_service.sc_service_instances;
8290
8291 for (inst = uu_list_first(insts);
8292 inst != NULL;
8293 inst = uu_list_next(insts, inst)) {
8294 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
8295 switch (r) {
8296 case 0:
8297 break;
8298
8299 case ENOMEM:
8300 case ECONNABORTED:
8301 case EPERM:
8302 case -1:
8303 goto progress;
8304
8305 default:
8306 bad_error("imp_refresh_fmri", r);
8307 }
8308
8309 inst->sc_import_state = IMPORT_REFRESHED;
8310
8311 for (dpt = uu_list_first(inst->sc_dependents);
8312 dpt != NULL;
8313 dpt = uu_list_next(inst->sc_dependents,
8314 dpt))
8315 if (imp_refresh_fmri(
8316 dpt->sc_pgroup_fmri,
8317 dpt->sc_pgroup_name,
8318 inst->sc_fmri) != 0)
8319 goto progress;
8320 }
8321
8322 for (dpt = uu_list_first(svc->sc_dependents);
8323 dpt != NULL;
8324 dpt = uu_list_next(svc->sc_dependents, dpt))
8325 if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
8326 dpt->sc_pgroup_name, svc->sc_fmri) != 0)
8327 goto progress;
8328 }
8329
8330 for (old_dpt = uu_list_first(imp_deleted_dpts);
8331 old_dpt != NULL;
8332 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
8333 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8334 old_dpt->sc_pgroup_name,
8335 old_dpt->sc_parent->sc_fmri) != 0)
8336 goto progress;
8337
8338 result = 0;
8339
8340 /*
8341 * This snippet of code assumes that we are running svccfg as we
8342 * normally do -- witih svc.startd running. Of course, that is
8343 * not actually the case all the time because we also use a
8344 * varient of svc.configd and svccfg which are only meant to
8345 * run during the build process. During this time we have no
8346 * svc.startd, so this check would hang the build process.
8347 *
8348 * However, we've also given other consolidations, a bit of a
8349 * means to tie themselves into a knot. They're not properly
8350 * using the native build equivalents, but they've been getting
8351 * away with it anyways. Therefore, if we've found that
8352 * SVCCFG_REPOSITORY is set indicating that a separate configd
8353 * should be spun up, then we have to assume it's not using a
8354 * startd and we should not do this check.
8355 */
8356 #ifndef NATIVE_BUILD
8357 /*
8358 * Verify that the restarter group is preset
8359 */
8360 eptr = getenv("SVCCFG_REPOSITORY");
8361 for (svc = uu_list_first(bndl->sc_bundle_services);
8362 svc != NULL && eptr == NULL;
8363 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8364
8365 insts = svc->sc_u.sc_service.sc_service_instances;
8366
8367 for (inst = uu_list_first(insts);
8368 inst != NULL;
8369 inst = uu_list_next(insts, inst)) {
8370 if (lscf_instance_verify(imp_scope, svc,
8371 inst) != 0)
8372 goto progress;
8373 }
8374 }
8375 #endif
8376 goto out;
8377
8378 }
8379
8380 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8381 bad_error("uu_list_walk", uu_error());
8382
8383 printerr:
8384 /* If the error hasn't been printed yet, do so here. */
8385 switch (cbdata.sc_err) {
8386 case ECONNABORTED:
8387 warn(gettext("Repository connection broken.\n"));
8388 break;
8389
8390 case ENOMEM:
8391 warn(emsg_nomem);
8392 break;
8393
8394 case ENOSPC:
8395 warn(emsg_nores);
8396 break;
8397
8398 case EROFS:
8399 warn(gettext("Repository is read-only.\n"));
8400 break;
8401
8402 case EACCES:
8403 warn(gettext("Repository backend denied access.\n"));
8404 break;
8405
8406 case EPERM:
8407 case EINVAL:
8408 case EEXIST:
8409 case EBUSY:
8410 case EBADF:
8411 case -1:
8412 break;
8413
8414 default:
8415 bad_error("lscf_service_import", cbdata.sc_err);
8416 }
8417
8418 progress:
8419 warn(gettext("Import of %s failed. Progress:\n"), filename);
8420
8421 for (svc = uu_list_first(bndl->sc_bundle_services);
8422 svc != NULL;
8423 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8424 insts = svc->sc_u.sc_service.sc_service_instances;
8425
8426 warn(gettext(" Service \"%s\": %s\n"), svc->sc_name,
8427 import_progress(svc->sc_import_state));
8428
8429 for (inst = uu_list_first(insts);
8430 inst != NULL;
8431 inst = uu_list_next(insts, inst))
8432 warn(gettext(" Instance \"%s\": %s\n"),
8433 inst->sc_name,
8434 import_progress(inst->sc_import_state));
8435 }
8436
8437 if (cbdata.sc_err == ECONNABORTED)
8438 repository_teardown();
8439
8440
8441 result = -1;
8442
8443 out:
8444 if (annotation_set != 0) {
8445 /* Turn off annotation. It is no longer needed. */
8446 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8447 }
8448
8449 free_imp_globals();
8450
8451 return (result);
8452 }
8453
8454 /*
8455 * _lscf_import_err() summarize the error handling returned by
8456 * lscf_import_{instance | service}_pgs
8457 * Return values are:
8458 * IMPORT_NEXT
8459 * IMPORT_OUT
8460 * IMPORT_BAD
8461 */
8462
8463 #define IMPORT_BAD -1
8464 #define IMPORT_NEXT 0
8465 #define IMPORT_OUT 1
8466
8467 static int
_lscf_import_err(int err,const char * fmri)8468 _lscf_import_err(int err, const char *fmri)
8469 {
8470 switch (err) {
8471 case 0:
8472 if (g_verbose)
8473 warn(gettext("%s updated.\n"), fmri);
8474 return (IMPORT_NEXT);
8475
8476 case ECONNABORTED:
8477 warn(gettext("Could not update %s "
8478 "(repository connection broken).\n"), fmri);
8479 return (IMPORT_OUT);
8480
8481 case ENOMEM:
8482 warn(gettext("Could not update %s (out of memory).\n"), fmri);
8483 return (IMPORT_OUT);
8484
8485 case ENOSPC:
8486 warn(gettext("Could not update %s "
8487 "(repository server out of resources).\n"), fmri);
8488 return (IMPORT_OUT);
8489
8490 case ECANCELED:
8491 warn(gettext(
8492 "Could not update %s (deleted).\n"), fmri);
8493 return (IMPORT_NEXT);
8494
8495 case EPERM:
8496 case EINVAL:
8497 case EBUSY:
8498 return (IMPORT_NEXT);
8499
8500 case EROFS:
8501 warn(gettext("Could not update %s (repository read-only).\n"),
8502 fmri);
8503 return (IMPORT_OUT);
8504
8505 case EACCES:
8506 warn(gettext("Could not update %s "
8507 "(backend access denied).\n"), fmri);
8508 return (IMPORT_NEXT);
8509
8510 case EEXIST:
8511 default:
8512 return (IMPORT_BAD);
8513 }
8514
8515 /*NOTREACHED*/
8516 }
8517
8518 /*
8519 * The global imp_svc and imp_inst should be set by the caller in the
8520 * check to make sure the service and instance exist that the apply is
8521 * working on.
8522 */
8523 static int
lscf_dependent_apply(void * dpg,void * e)8524 lscf_dependent_apply(void *dpg, void *e)
8525 {
8526 scf_callback_t cb;
8527 pgroup_t *dpt_pgroup = dpg;
8528 pgroup_t *deldpt;
8529 entity_t *ent = e;
8530 int tissvc;
8531 void *sc_ent, *tent;
8532 scf_error_t serr;
8533 int r;
8534
8535 const char * const dependents = "dependents";
8536 const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT);
8537
8538 if (issvc)
8539 sc_ent = imp_svc;
8540 else
8541 sc_ent = imp_inst;
8542
8543 if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg,
8544 imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 ||
8545 scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name,
8546 imp_prop) != 0) {
8547 switch (scf_error()) {
8548 case SCF_ERROR_NOT_FOUND:
8549 case SCF_ERROR_DELETED:
8550 break;
8551
8552 case SCF_ERROR_CONNECTION_BROKEN:
8553 case SCF_ERROR_NOT_SET:
8554 case SCF_ERROR_INVALID_ARGUMENT:
8555 case SCF_ERROR_HANDLE_MISMATCH:
8556 case SCF_ERROR_NOT_BOUND:
8557 default:
8558 bad_error("entity_get_pg", scf_error());
8559 }
8560 } else {
8561 /*
8562 * Found the dependents/<wip dep> so check to
8563 * see if the service is different. If so
8564 * store the service for later refresh, and
8565 * delete the wip dependency from the service
8566 */
8567 if (scf_property_get_value(imp_prop, ud_val) != 0) {
8568 switch (scf_error()) {
8569 case SCF_ERROR_DELETED:
8570 break;
8571
8572 case SCF_ERROR_CONNECTION_BROKEN:
8573 case SCF_ERROR_NOT_SET:
8574 case SCF_ERROR_INVALID_ARGUMENT:
8575 case SCF_ERROR_HANDLE_MISMATCH:
8576 case SCF_ERROR_NOT_BOUND:
8577 default:
8578 bad_error("scf_property_get_value",
8579 scf_error());
8580 }
8581 }
8582
8583 if (scf_value_get_as_string(ud_val, ud_oldtarg,
8584 max_scf_value_len + 1) < 0)
8585 bad_error("scf_value_get_as_string", scf_error());
8586
8587 r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
8588 switch (r) {
8589 case 1:
8590 break;
8591 case 0:
8592 if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent,
8593 &tissvc)) != SCF_ERROR_NONE) {
8594 if (serr == SCF_ERROR_NOT_FOUND) {
8595 break;
8596 } else {
8597 bad_error("fmri_to_entity", serr);
8598 }
8599 }
8600
8601 if (entity_get_pg(tent, tissvc,
8602 dpt_pgroup->sc_pgroup_name, imp_pg) != 0) {
8603 serr = scf_error();
8604 if (serr == SCF_ERROR_NOT_FOUND ||
8605 serr == SCF_ERROR_DELETED) {
8606 break;
8607 } else {
8608 bad_error("entity_get_pg", scf_error());
8609 }
8610 }
8611
8612 if (scf_pg_delete(imp_pg) != 0) {
8613 serr = scf_error();
8614 if (serr == SCF_ERROR_NOT_FOUND ||
8615 serr == SCF_ERROR_DELETED) {
8616 break;
8617 } else {
8618 bad_error("scf_pg_delete", scf_error());
8619 }
8620 }
8621
8622 deldpt = internal_pgroup_new();
8623 if (deldpt == NULL)
8624 return (ENOMEM);
8625 deldpt->sc_pgroup_name =
8626 strdup(dpt_pgroup->sc_pgroup_name);
8627 deldpt->sc_pgroup_fmri = strdup(ud_oldtarg);
8628 if (deldpt->sc_pgroup_name == NULL ||
8629 deldpt->sc_pgroup_fmri == NULL)
8630 return (ENOMEM);
8631 deldpt->sc_parent = (entity_t *)ent;
8632 if (uu_list_insert_after(imp_deleted_dpts, NULL,
8633 deldpt) != 0)
8634 uu_die(gettext("libuutil error: %s\n"),
8635 uu_strerror(uu_error()));
8636
8637 break;
8638 default:
8639 bad_error("fmri_equal", r);
8640 }
8641 }
8642
8643 cb.sc_handle = g_hndl;
8644 cb.sc_parent = ent;
8645 cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT;
8646 cb.sc_source_fmri = ent->sc_fmri;
8647 cb.sc_target_fmri = ent->sc_fmri;
8648 cb.sc_trans = NULL;
8649 cb.sc_flags = SCI_FORCE;
8650
8651 if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT)
8652 return (UU_WALK_ERROR);
8653
8654 r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL);
8655 switch (r) {
8656 case 0:
8657 break;
8658
8659 case ENOMEM:
8660 case ECONNABORTED:
8661 case EPERM:
8662 case -1:
8663 warn(gettext("Unable to refresh \"%s\"\n"),
8664 dpt_pgroup->sc_pgroup_fmri);
8665 return (UU_WALK_ERROR);
8666
8667 default:
8668 bad_error("imp_refresh_fmri", r);
8669 }
8670
8671 return (UU_WALK_NEXT);
8672 }
8673
8674 /*
8675 * Returns
8676 * 0 - success
8677 * -1 - lscf_import_instance_pgs() failed.
8678 */
8679 int
lscf_bundle_apply(bundle_t * bndl,const char * file)8680 lscf_bundle_apply(bundle_t *bndl, const char *file)
8681 {
8682 pgroup_t *old_dpt;
8683 entity_t *svc, *inst;
8684 int annotation_set = 0;
8685 int ret = 0;
8686 int r = 0;
8687
8688 lscf_prep_hndl();
8689
8690 if ((ret = alloc_imp_globals()))
8691 goto out;
8692
8693 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0)
8694 scfdie();
8695
8696 /*
8697 * Set the strings to be used for the security audit annotation
8698 * event.
8699 */
8700 if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
8701 annotation_set = 1;
8702 } else {
8703 switch (scf_error()) {
8704 case SCF_ERROR_CONNECTION_BROKEN:
8705 warn(gettext("Repository connection broken.\n"));
8706 goto out;
8707
8708 case SCF_ERROR_INVALID_ARGUMENT:
8709 case SCF_ERROR_NOT_BOUND:
8710 case SCF_ERROR_NO_RESOURCES:
8711 case SCF_ERROR_INTERNAL:
8712 bad_error("_scf_set_annotation", scf_error());
8713 /* NOTREACHED */
8714
8715 default:
8716 /*
8717 * Do not abort apply operation because of
8718 * inability to create annotation audit event.
8719 */
8720 warn(gettext("_scf_set_annotation() unexpectedly "
8721 "failed with return code of %d\n"), scf_error());
8722 break;
8723 }
8724 }
8725
8726 for (svc = uu_list_first(bndl->sc_bundle_services);
8727 svc != NULL;
8728 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8729 int refresh = 0;
8730
8731 if (scf_scope_get_service(imp_scope, svc->sc_name,
8732 imp_svc) != 0) {
8733 switch (scf_error()) {
8734 case SCF_ERROR_NOT_FOUND:
8735 if (g_verbose)
8736 warn(gettext("Ignoring nonexistent "
8737 "service %s.\n"), svc->sc_name);
8738 continue;
8739
8740 default:
8741 scfdie();
8742 }
8743 }
8744
8745 /*
8746 * If there were missing types in the profile, then need to
8747 * attempt to find the types.
8748 */
8749 if (svc->sc_miss_type) {
8750 if (uu_list_numnodes(svc->sc_pgroups) &&
8751 uu_list_walk(svc->sc_pgroups, find_current_pg_type,
8752 svc, UU_DEFAULT) != 0) {
8753 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8754 bad_error("uu_list_walk", uu_error());
8755
8756 ret = -1;
8757 continue;
8758 }
8759
8760 for (inst = uu_list_first(
8761 svc->sc_u.sc_service.sc_service_instances);
8762 inst != NULL;
8763 inst = uu_list_next(
8764 svc->sc_u.sc_service.sc_service_instances, inst)) {
8765 /*
8766 * If the instance doesn't exist just
8767 * skip to the next instance and let the
8768 * import note the missing instance.
8769 */
8770 if (scf_service_get_instance(imp_svc,
8771 inst->sc_name, imp_inst) != 0)
8772 continue;
8773
8774 if (uu_list_walk(inst->sc_pgroups,
8775 find_current_pg_type, inst,
8776 UU_DEFAULT) != 0) {
8777 if (uu_error() !=
8778 UU_ERROR_CALLBACK_FAILED)
8779 bad_error("uu_list_walk",
8780 uu_error());
8781
8782 ret = -1;
8783 inst->sc_miss_type = B_TRUE;
8784 }
8785 }
8786 }
8787
8788 /*
8789 * if we have pgs in the profile, we need to refresh ALL
8790 * instances of the service
8791 */
8792 if (uu_list_numnodes(svc->sc_pgroups) != 0) {
8793 refresh = 1;
8794 r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc,
8795 SCI_FORCE | SCI_KEEP);
8796 switch (_lscf_import_err(r, svc->sc_fmri)) {
8797 case IMPORT_NEXT:
8798 break;
8799
8800 case IMPORT_OUT:
8801 goto out;
8802
8803 case IMPORT_BAD:
8804 default:
8805 bad_error("lscf_import_service_pgs", r);
8806 }
8807 }
8808
8809 if (uu_list_numnodes(svc->sc_dependents) != 0) {
8810 uu_list_walk(svc->sc_dependents,
8811 lscf_dependent_apply, svc, UU_DEFAULT);
8812 }
8813
8814 for (inst = uu_list_first(
8815 svc->sc_u.sc_service.sc_service_instances);
8816 inst != NULL;
8817 inst = uu_list_next(
8818 svc->sc_u.sc_service.sc_service_instances, inst)) {
8819 /*
8820 * This instance still has missing types
8821 * so skip it.
8822 */
8823 if (inst->sc_miss_type) {
8824 if (g_verbose)
8825 warn(gettext("Ignoring instance "
8826 "%s:%s with missing types\n"),
8827 inst->sc_parent->sc_name,
8828 inst->sc_name);
8829
8830 continue;
8831 }
8832
8833 if (scf_service_get_instance(imp_svc, inst->sc_name,
8834 imp_inst) != 0) {
8835 switch (scf_error()) {
8836 case SCF_ERROR_NOT_FOUND:
8837 if (g_verbose)
8838 warn(gettext("Ignoring "
8839 "nonexistant instance "
8840 "%s:%s.\n"),
8841 inst->sc_parent->sc_name,
8842 inst->sc_name);
8843 continue;
8844
8845 default:
8846 scfdie();
8847 }
8848 }
8849
8850 /*
8851 * If the instance does not have a general/enabled
8852 * property and no last-import snapshot then the
8853 * instance is not a fully installed instance and
8854 * should not have a profile applied to it.
8855 *
8856 * This could happen if a service/instance declares
8857 * a dependent on behalf of another service/instance.
8858 *
8859 */
8860 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
8861 imp_snap) != 0) {
8862 if (scf_instance_get_pg(imp_inst,
8863 SCF_PG_GENERAL, imp_pg) != 0 ||
8864 scf_pg_get_property(imp_pg,
8865 SCF_PROPERTY_ENABLED, imp_prop) != 0) {
8866 if (g_verbose)
8867 warn(gettext("Ignoreing "
8868 "partial instance "
8869 "%s:%s.\n"),
8870 inst->sc_parent->sc_name,
8871 inst->sc_name);
8872 continue;
8873 }
8874 }
8875
8876 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri,
8877 inst, SCI_FORCE | SCI_KEEP);
8878 switch (_lscf_import_err(r, inst->sc_fmri)) {
8879 case IMPORT_NEXT:
8880 break;
8881
8882 case IMPORT_OUT:
8883 goto out;
8884
8885 case IMPORT_BAD:
8886 default:
8887 bad_error("lscf_import_instance_pgs", r);
8888 }
8889
8890 if (uu_list_numnodes(inst->sc_dependents) != 0) {
8891 uu_list_walk(inst->sc_dependents,
8892 lscf_dependent_apply, inst, UU_DEFAULT);
8893 }
8894
8895 /* refresh only if there is no pgs in the service */
8896 if (refresh == 0)
8897 (void) refresh_entity(0, imp_inst,
8898 inst->sc_fmri, NULL, NULL, NULL);
8899 }
8900
8901 if (refresh == 1) {
8902 char *name_buf = safe_malloc(max_scf_name_len + 1);
8903
8904 (void) refresh_entity(1, imp_svc, svc->sc_name,
8905 imp_inst, imp_iter, name_buf);
8906 free(name_buf);
8907 }
8908
8909 for (old_dpt = uu_list_first(imp_deleted_dpts);
8910 old_dpt != NULL;
8911 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) {
8912 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8913 old_dpt->sc_pgroup_name,
8914 old_dpt->sc_parent->sc_fmri) != 0) {
8915 warn(gettext("Unable to refresh \"%s\"\n"),
8916 old_dpt->sc_pgroup_fmri);
8917 }
8918 }
8919 }
8920
8921 out:
8922 if (annotation_set) {
8923 /* Remove security audit annotation strings. */
8924 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8925 }
8926
8927 free_imp_globals();
8928 return (ret);
8929 }
8930
8931
8932 /*
8933 * Export. These functions create and output an XML tree of a service
8934 * description from the repository. This is largely the inverse of
8935 * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
8936 *
8937 * - We must include any properties which are not represented specifically by
8938 * a service manifest, e.g., properties created by an admin post-import. To
8939 * do so we'll iterate through all properties and deal with each
8940 * apropriately.
8941 *
8942 * - Children of services and instances must must be in the order set by the
8943 * DTD, but we iterate over the properties in undefined order. The elements
8944 * are not easily (or efficiently) sortable by name. Since there's a fixed
8945 * number of classes of them, however, we'll keep the classes separate and
8946 * assemble them in order.
8947 */
8948
8949 /*
8950 * Convenience function to handle xmlSetProp errors (and type casting).
8951 */
8952 static void
safe_setprop(xmlNodePtr n,const char * name,const char * val)8953 safe_setprop(xmlNodePtr n, const char *name, const char *val)
8954 {
8955 if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
8956 uu_die(gettext("Could not set XML property.\n"));
8957 }
8958
8959 /*
8960 * Convenience function to set an XML attribute to the single value of an
8961 * astring property. If the value happens to be the default, don't set the
8962 * attribute. "dval" should be the default value supplied by the DTD, or
8963 * NULL for no default.
8964 */
8965 static int
set_attr_from_prop_default(scf_property_t * prop,xmlNodePtr n,const char * name,const char * dval)8966 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
8967 const char *name, const char *dval)
8968 {
8969 scf_value_t *val;
8970 ssize_t len;
8971 char *str;
8972
8973 val = scf_value_create(g_hndl);
8974 if (val == NULL)
8975 scfdie();
8976
8977 if (prop_get_val(prop, val) != 0) {
8978 scf_value_destroy(val);
8979 return (-1);
8980 }
8981
8982 len = scf_value_get_as_string(val, NULL, 0);
8983 if (len < 0)
8984 scfdie();
8985
8986 str = safe_malloc(len + 1);
8987
8988 if (scf_value_get_as_string(val, str, len + 1) < 0)
8989 scfdie();
8990
8991 scf_value_destroy(val);
8992
8993 if (dval == NULL || strcmp(str, dval) != 0)
8994 safe_setprop(n, name, str);
8995
8996 free(str);
8997
8998 return (0);
8999 }
9000
9001 /*
9002 * As above, but the attribute is always set.
9003 */
9004 static int
set_attr_from_prop(scf_property_t * prop,xmlNodePtr n,const char * name)9005 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
9006 {
9007 return (set_attr_from_prop_default(prop, n, name, NULL));
9008 }
9009
9010 /*
9011 * Dump the given document onto f, with "'s replaced by ''s.
9012 */
9013 static int
write_service_bundle(xmlDocPtr doc,FILE * f)9014 write_service_bundle(xmlDocPtr doc, FILE *f)
9015 {
9016 xmlChar *mem;
9017 int sz, i;
9018
9019 mem = NULL;
9020 xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
9021
9022 if (mem == NULL) {
9023 semerr(gettext("Could not dump XML tree.\n"));
9024 return (-1);
9025 }
9026
9027 /*
9028 * Fortunately libxml produces " instead of ", so we can blindly
9029 * replace all " with '. Cursed libxml2! Why must you #ifdef out the
9030 * ' code?!
9031 */
9032 for (i = 0; i < sz; ++i) {
9033 char c = (char)mem[i];
9034
9035 if (c == '"')
9036 (void) fputc('\'', f);
9037 else if (c == '\'')
9038 (void) fwrite("'", sizeof ("'") - 1, 1, f);
9039 else
9040 (void) fputc(c, f);
9041 }
9042
9043 return (0);
9044 }
9045
9046 /*
9047 * Create the DOM elements in elts necessary to (generically) represent prop
9048 * (i.e., a property or propval element). If the name of the property is
9049 * known, it should be passed as name_arg. Otherwise, pass NULL.
9050 */
9051 static void
export_property(scf_property_t * prop,const char * name_arg,struct pg_elts * elts,int flags)9052 export_property(scf_property_t *prop, const char *name_arg,
9053 struct pg_elts *elts, int flags)
9054 {
9055 const char *type;
9056 scf_error_t err = 0;
9057 xmlNodePtr pnode, lnode;
9058 char *lnname;
9059 int ret;
9060
9061 /* name */
9062 if (name_arg != NULL) {
9063 (void) strcpy(exp_str, name_arg);
9064 } else {
9065 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
9066 scfdie();
9067 }
9068
9069 /* type */
9070 type = prop_to_typestr(prop);
9071 if (type == NULL)
9072 uu_die(gettext("Can't export property %s: unknown type.\n"),
9073 exp_str);
9074
9075 /* If we're exporting values, and there's just one, export it here. */
9076 if (!(flags & SCE_ALL_VALUES))
9077 goto empty;
9078
9079 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
9080 xmlNodePtr n;
9081
9082 /* Single value, so use propval */
9083 n = xmlNewNode(NULL, (xmlChar *)"propval");
9084 if (n == NULL)
9085 uu_die(emsg_create_xml);
9086
9087 safe_setprop(n, name_attr, exp_str);
9088 safe_setprop(n, type_attr, type);
9089
9090 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9091 scfdie();
9092 safe_setprop(n, value_attr, exp_str);
9093
9094 if (elts->propvals == NULL)
9095 elts->propvals = n;
9096 else
9097 (void) xmlAddSibling(elts->propvals, n);
9098
9099 return;
9100 }
9101
9102 err = scf_error();
9103
9104 if (err == SCF_ERROR_PERMISSION_DENIED) {
9105 semerr(emsg_permission_denied);
9106 return;
9107 }
9108
9109 if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
9110 err != SCF_ERROR_NOT_FOUND &&
9111 err != SCF_ERROR_PERMISSION_DENIED)
9112 scfdie();
9113
9114 empty:
9115 /* Multiple (or no) values, so use property */
9116 pnode = xmlNewNode(NULL, (xmlChar *)"property");
9117 if (pnode == NULL)
9118 uu_die(emsg_create_xml);
9119
9120 safe_setprop(pnode, name_attr, exp_str);
9121 safe_setprop(pnode, type_attr, type);
9122
9123 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
9124 lnname = uu_msprintf("%s_list", type);
9125 if (lnname == NULL)
9126 uu_die(gettext("Could not create string"));
9127
9128 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
9129 if (lnode == NULL)
9130 uu_die(emsg_create_xml);
9131
9132 uu_free(lnname);
9133
9134 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
9135 scfdie();
9136
9137 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
9138 1) {
9139 xmlNodePtr vn;
9140
9141 vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
9142 NULL);
9143 if (vn == NULL)
9144 uu_die(emsg_create_xml);
9145
9146 if (scf_value_get_as_string(exp_val, exp_str,
9147 exp_str_sz) < 0)
9148 scfdie();
9149 safe_setprop(vn, value_attr, exp_str);
9150 }
9151 if (ret != 0)
9152 scfdie();
9153 }
9154
9155 if (elts->properties == NULL)
9156 elts->properties = pnode;
9157 else
9158 (void) xmlAddSibling(elts->properties, pnode);
9159 }
9160
9161 /*
9162 * Add a property_group element for this property group to elts.
9163 */
9164 static void
export_pg(scf_propertygroup_t * pg,struct entity_elts * eelts,int flags)9165 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
9166 {
9167 xmlNodePtr n;
9168 struct pg_elts elts;
9169 int ret;
9170 boolean_t read_protected;
9171
9172 n = xmlNewNode(NULL, (xmlChar *)"property_group");
9173
9174 /* name */
9175 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9176 scfdie();
9177 safe_setprop(n, name_attr, exp_str);
9178
9179 /* type */
9180 if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
9181 scfdie();
9182 safe_setprop(n, type_attr, exp_str);
9183
9184 /* properties */
9185 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9186 scfdie();
9187
9188 (void) memset(&elts, 0, sizeof (elts));
9189
9190 /*
9191 * If this property group is not read protected, we always want to
9192 * output all the values. Otherwise, we only output the values if the
9193 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
9194 */
9195 if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
9196 scfdie();
9197
9198 if (!read_protected)
9199 flags |= SCE_ALL_VALUES;
9200
9201 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9202 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9203 scfdie();
9204
9205 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9206 xmlNodePtr m;
9207
9208 m = xmlNewNode(NULL, (xmlChar *)"stability");
9209 if (m == NULL)
9210 uu_die(emsg_create_xml);
9211
9212 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9213 elts.stability = m;
9214 continue;
9215 }
9216
9217 xmlFreeNode(m);
9218 }
9219
9220 export_property(exp_prop, NULL, &elts, flags);
9221 }
9222 if (ret == -1)
9223 scfdie();
9224
9225 (void) xmlAddChild(n, elts.stability);
9226 (void) xmlAddChildList(n, elts.propvals);
9227 (void) xmlAddChildList(n, elts.properties);
9228
9229 if (eelts->property_groups == NULL)
9230 eelts->property_groups = n;
9231 else
9232 (void) xmlAddSibling(eelts->property_groups, n);
9233 }
9234
9235 /*
9236 * Create an XML node representing the dependency described by the given
9237 * property group and put it in eelts. Unless the dependency is not valid, in
9238 * which case create a generic property_group element which represents it and
9239 * put it in eelts.
9240 */
9241 static void
export_dependency(scf_propertygroup_t * pg,struct entity_elts * eelts)9242 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
9243 {
9244 xmlNodePtr n;
9245 int err = 0, ret;
9246 struct pg_elts elts;
9247
9248 n = xmlNewNode(NULL, (xmlChar *)"dependency");
9249 if (n == NULL)
9250 uu_die(emsg_create_xml);
9251
9252 /*
9253 * If the external flag is present, skip this dependency because it
9254 * should have been created by another manifest.
9255 */
9256 if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
9257 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9258 prop_get_val(exp_prop, exp_val) == 0) {
9259 uint8_t b;
9260
9261 if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
9262 scfdie();
9263
9264 if (b)
9265 return;
9266 }
9267 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
9268 scfdie();
9269
9270 /* Get the required attributes. */
9271
9272 /* name */
9273 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9274 scfdie();
9275 safe_setprop(n, name_attr, exp_str);
9276
9277 /* grouping */
9278 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9279 set_attr_from_prop(exp_prop, n, "grouping") != 0)
9280 err = 1;
9281
9282 /* restart_on */
9283 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9284 set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9285 err = 1;
9286
9287 /* type */
9288 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9289 set_attr_from_prop(exp_prop, n, type_attr) != 0)
9290 err = 1;
9291
9292 /*
9293 * entities: Not required, but if we create no children, it will be
9294 * created as empty on import, so fail if it's missing.
9295 */
9296 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9297 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
9298 scf_iter_t *eiter;
9299 int ret2;
9300
9301 eiter = scf_iter_create(g_hndl);
9302 if (eiter == NULL)
9303 scfdie();
9304
9305 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
9306 scfdie();
9307
9308 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
9309 xmlNodePtr ch;
9310
9311 if (scf_value_get_astring(exp_val, exp_str,
9312 exp_str_sz) < 0)
9313 scfdie();
9314
9315 /*
9316 * service_fmri's must be first, so we can add them
9317 * here.
9318 */
9319 ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
9320 NULL);
9321 if (ch == NULL)
9322 uu_die(emsg_create_xml);
9323
9324 safe_setprop(ch, value_attr, exp_str);
9325 }
9326 if (ret2 == -1)
9327 scfdie();
9328
9329 scf_iter_destroy(eiter);
9330 } else
9331 err = 1;
9332
9333 if (err) {
9334 xmlFreeNode(n);
9335
9336 export_pg(pg, eelts, SCE_ALL_VALUES);
9337
9338 return;
9339 }
9340
9341 /* Iterate through the properties & handle each. */
9342 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9343 scfdie();
9344
9345 (void) memset(&elts, 0, sizeof (elts));
9346
9347 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9348 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9349 scfdie();
9350
9351 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9352 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9353 strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9354 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9355 continue;
9356 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9357 xmlNodePtr m;
9358
9359 m = xmlNewNode(NULL, (xmlChar *)"stability");
9360 if (m == NULL)
9361 uu_die(emsg_create_xml);
9362
9363 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9364 elts.stability = m;
9365 continue;
9366 }
9367
9368 xmlFreeNode(m);
9369 }
9370
9371 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9372 }
9373 if (ret == -1)
9374 scfdie();
9375
9376 (void) xmlAddChild(n, elts.stability);
9377 (void) xmlAddChildList(n, elts.propvals);
9378 (void) xmlAddChildList(n, elts.properties);
9379
9380 if (eelts->dependencies == NULL)
9381 eelts->dependencies = n;
9382 else
9383 (void) xmlAddSibling(eelts->dependencies, n);
9384 }
9385
9386 static xmlNodePtr
export_method_environment(scf_propertygroup_t * pg)9387 export_method_environment(scf_propertygroup_t *pg)
9388 {
9389 xmlNodePtr env;
9390 int ret;
9391 int children = 0;
9392
9393 if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
9394 return (NULL);
9395
9396 env = xmlNewNode(NULL, (xmlChar *)"method_environment");
9397 if (env == NULL)
9398 uu_die(emsg_create_xml);
9399
9400 if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
9401 scfdie();
9402
9403 if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
9404 scfdie();
9405
9406 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
9407 xmlNodePtr ev;
9408 char *cp;
9409
9410 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9411 scfdie();
9412
9413 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
9414 warn(gettext("Invalid environment variable \"%s\".\n"),
9415 exp_str);
9416 continue;
9417 } else if (strncmp(exp_str, "SMF_", 4) == 0) {
9418 warn(gettext("Invalid environment variable \"%s\"; "
9419 "\"SMF_\" prefix is reserved.\n"), exp_str);
9420 continue;
9421 }
9422
9423 *cp = '\0';
9424 cp++;
9425
9426 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
9427 if (ev == NULL)
9428 uu_die(emsg_create_xml);
9429
9430 safe_setprop(ev, name_attr, exp_str);
9431 safe_setprop(ev, value_attr, cp);
9432 children++;
9433 }
9434
9435 if (ret != 0)
9436 scfdie();
9437
9438 if (children == 0) {
9439 xmlFreeNode(env);
9440 return (NULL);
9441 }
9442
9443 return (env);
9444 }
9445
9446 /*
9447 * As above, but for a method property group.
9448 */
9449 static void
export_method(scf_propertygroup_t * pg,struct entity_elts * eelts)9450 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
9451 {
9452 xmlNodePtr n, env;
9453 char *str;
9454 int err = 0, nonenv, ret;
9455 uint8_t use_profile;
9456 struct pg_elts elts;
9457 xmlNodePtr ctxt = NULL;
9458
9459 n = xmlNewNode(NULL, (xmlChar *)"exec_method");
9460
9461 /* Get the required attributes. */
9462
9463 /* name */
9464 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9465 scfdie();
9466 safe_setprop(n, name_attr, exp_str);
9467
9468 /* type */
9469 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9470 set_attr_from_prop(exp_prop, n, type_attr) != 0)
9471 err = 1;
9472
9473 /* exec */
9474 if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
9475 set_attr_from_prop(exp_prop, n, "exec") != 0)
9476 err = 1;
9477
9478 /* timeout */
9479 if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
9480 prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
9481 prop_get_val(exp_prop, exp_val) == 0) {
9482 uint64_t c;
9483
9484 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
9485 scfdie();
9486
9487 str = uu_msprintf("%llu", c);
9488 if (str == NULL)
9489 uu_die(gettext("Could not create string"));
9490
9491 safe_setprop(n, "timeout_seconds", str);
9492 free(str);
9493 } else
9494 err = 1;
9495
9496 if (err) {
9497 xmlFreeNode(n);
9498
9499 export_pg(pg, eelts, SCE_ALL_VALUES);
9500
9501 return;
9502 }
9503
9504
9505 /*
9506 * If we're going to have a method_context child, we need to know
9507 * before we iterate through the properties. Since method_context's
9508 * are optional, we don't want to complain about any properties
9509 * missing if none of them are there. Thus we can't use the
9510 * convenience functions.
9511 */
9512 nonenv =
9513 scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
9514 SCF_SUCCESS ||
9515 scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
9516 SCF_SUCCESS ||
9517 scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
9518 SCF_SUCCESS ||
9519 scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
9520 SCF_SUCCESS;
9521
9522 if (nonenv) {
9523 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9524 if (ctxt == NULL)
9525 uu_die(emsg_create_xml);
9526
9527 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
9528 0 &&
9529 set_attr_from_prop_default(exp_prop, ctxt,
9530 "working_directory", ":default") != 0)
9531 err = 1;
9532
9533 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
9534 set_attr_from_prop_default(exp_prop, ctxt, "project",
9535 ":default") != 0)
9536 err = 1;
9537
9538 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
9539 0 &&
9540 set_attr_from_prop_default(exp_prop, ctxt,
9541 "resource_pool", ":default") != 0)
9542 err = 1;
9543 /*
9544 * We only want to complain about profile or credential
9545 * properties if we will use them. To determine that we must
9546 * examine USE_PROFILE.
9547 */
9548 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9549 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9550 prop_get_val(exp_prop, exp_val) == 0) {
9551 if (scf_value_get_boolean(exp_val, &use_profile) !=
9552 SCF_SUCCESS) {
9553 scfdie();
9554 }
9555
9556 if (use_profile) {
9557 xmlNodePtr prof;
9558
9559 prof = xmlNewChild(ctxt, NULL,
9560 (xmlChar *)"method_profile", NULL);
9561 if (prof == NULL)
9562 uu_die(emsg_create_xml);
9563
9564 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
9565 exp_prop) != 0 ||
9566 set_attr_from_prop(exp_prop, prof,
9567 name_attr) != 0)
9568 err = 1;
9569 } else {
9570 xmlNodePtr cred;
9571
9572 cred = xmlNewChild(ctxt, NULL,
9573 (xmlChar *)"method_credential", NULL);
9574 if (cred == NULL)
9575 uu_die(emsg_create_xml);
9576
9577 if (pg_get_prop(pg, SCF_PROPERTY_USER,
9578 exp_prop) != 0 ||
9579 set_attr_from_prop(exp_prop, cred,
9580 "user") != 0) {
9581 err = 1;
9582 }
9583
9584 if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
9585 exp_prop) == 0 &&
9586 set_attr_from_prop_default(exp_prop, cred,
9587 "group", ":default") != 0)
9588 err = 1;
9589
9590 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
9591 exp_prop) == 0 &&
9592 set_attr_from_prop_default(exp_prop, cred,
9593 "supp_groups", ":default") != 0)
9594 err = 1;
9595
9596 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
9597 exp_prop) == 0 &&
9598 set_attr_from_prop_default(exp_prop, cred,
9599 "privileges", ":default") != 0)
9600 err = 1;
9601
9602 if (pg_get_prop(pg,
9603 SCF_PROPERTY_LIMIT_PRIVILEGES,
9604 exp_prop) == 0 &&
9605 set_attr_from_prop_default(exp_prop, cred,
9606 "limit_privileges", ":default") != 0)
9607 err = 1;
9608 }
9609 }
9610 }
9611
9612 if ((env = export_method_environment(pg)) != NULL) {
9613 if (ctxt == NULL) {
9614 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9615 if (ctxt == NULL)
9616 uu_die(emsg_create_xml);
9617 }
9618 (void) xmlAddChild(ctxt, env);
9619 }
9620
9621 if (env != NULL || (nonenv && err == 0))
9622 (void) xmlAddChild(n, ctxt);
9623 else
9624 xmlFreeNode(ctxt);
9625
9626 nonenv = (err == 0);
9627
9628 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9629 scfdie();
9630
9631 (void) memset(&elts, 0, sizeof (elts));
9632
9633 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9634 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9635 scfdie();
9636
9637 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9638 strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
9639 strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
9640 continue;
9641 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9642 xmlNodePtr m;
9643
9644 m = xmlNewNode(NULL, (xmlChar *)"stability");
9645 if (m == NULL)
9646 uu_die(emsg_create_xml);
9647
9648 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9649 elts.stability = m;
9650 continue;
9651 }
9652
9653 xmlFreeNode(m);
9654 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
9655 0 ||
9656 strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
9657 strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
9658 strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9659 if (nonenv)
9660 continue;
9661 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
9662 strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
9663 strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
9664 strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
9665 strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) {
9666 if (nonenv && !use_profile)
9667 continue;
9668 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9669 if (nonenv && use_profile)
9670 continue;
9671 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
9672 if (env != NULL)
9673 continue;
9674 }
9675
9676 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9677 }
9678 if (ret == -1)
9679 scfdie();
9680
9681 (void) xmlAddChild(n, elts.stability);
9682 (void) xmlAddChildList(n, elts.propvals);
9683 (void) xmlAddChildList(n, elts.properties);
9684
9685 if (eelts->exec_methods == NULL)
9686 eelts->exec_methods = n;
9687 else
9688 (void) xmlAddSibling(eelts->exec_methods, n);
9689 }
9690
9691 static void
export_pg_elts(struct pg_elts * elts,const char * name,const char * type,struct entity_elts * eelts)9692 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
9693 struct entity_elts *eelts)
9694 {
9695 xmlNodePtr pgnode;
9696
9697 pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
9698 if (pgnode == NULL)
9699 uu_die(emsg_create_xml);
9700
9701 safe_setprop(pgnode, name_attr, name);
9702 safe_setprop(pgnode, type_attr, type);
9703
9704 (void) xmlAddChildList(pgnode, elts->propvals);
9705 (void) xmlAddChildList(pgnode, elts->properties);
9706
9707 if (eelts->property_groups == NULL)
9708 eelts->property_groups = pgnode;
9709 else
9710 (void) xmlAddSibling(eelts->property_groups, pgnode);
9711 }
9712
9713 /*
9714 * Process the general property group for a service. This is the one with the
9715 * goodies.
9716 */
9717 static void
export_svc_general(scf_propertygroup_t * pg,struct entity_elts * selts)9718 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
9719 {
9720 struct pg_elts elts;
9721 int ret;
9722
9723 /*
9724 * In case there are properties which don't correspond to child
9725 * entities of the service entity, we'll set up a pg_elts structure to
9726 * put them in.
9727 */
9728 (void) memset(&elts, 0, sizeof (elts));
9729
9730 /* Walk the properties, looking for special ones. */
9731 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9732 scfdie();
9733
9734 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9735 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9736 scfdie();
9737
9738 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
9739 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9740 prop_get_val(exp_prop, exp_val) == 0) {
9741 uint8_t b;
9742
9743 if (scf_value_get_boolean(exp_val, &b) !=
9744 SCF_SUCCESS)
9745 scfdie();
9746
9747 if (b) {
9748 selts->single_instance =
9749 xmlNewNode(NULL,
9750 (xmlChar *)"single_instance");
9751 if (selts->single_instance == NULL)
9752 uu_die(emsg_create_xml);
9753 }
9754
9755 continue;
9756 }
9757 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9758 xmlNodePtr rnode, sfnode;
9759
9760 rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9761 if (rnode == NULL)
9762 uu_die(emsg_create_xml);
9763
9764 sfnode = xmlNewChild(rnode, NULL,
9765 (xmlChar *)"service_fmri", NULL);
9766 if (sfnode == NULL)
9767 uu_die(emsg_create_xml);
9768
9769 if (set_attr_from_prop(exp_prop, sfnode,
9770 value_attr) == 0) {
9771 selts->restarter = rnode;
9772 continue;
9773 }
9774
9775 xmlFreeNode(rnode);
9776 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
9777 0) {
9778 xmlNodePtr s;
9779
9780 s = xmlNewNode(NULL, (xmlChar *)"stability");
9781 if (s == NULL)
9782 uu_die(emsg_create_xml);
9783
9784 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9785 selts->stability = s;
9786 continue;
9787 }
9788
9789 xmlFreeNode(s);
9790 }
9791
9792 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9793 }
9794 if (ret == -1)
9795 scfdie();
9796
9797 if (elts.propvals != NULL || elts.properties != NULL)
9798 export_pg_elts(&elts, scf_pg_general, scf_group_framework,
9799 selts);
9800 }
9801
9802 static void
export_method_context(scf_propertygroup_t * pg,struct entity_elts * elts)9803 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
9804 {
9805 xmlNodePtr n, prof, cred, env;
9806 uint8_t use_profile;
9807 int ret, err = 0;
9808
9809 n = xmlNewNode(NULL, (xmlChar *)"method_context");
9810
9811 env = export_method_environment(pg);
9812
9813 /* Need to know whether we'll use a profile or not. */
9814 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9815 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9816 prop_get_val(exp_prop, exp_val) == 0) {
9817 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
9818 scfdie();
9819
9820 if (use_profile)
9821 prof =
9822 xmlNewChild(n, NULL, (xmlChar *)"method_profile",
9823 NULL);
9824 else
9825 cred =
9826 xmlNewChild(n, NULL, (xmlChar *)"method_credential",
9827 NULL);
9828 }
9829
9830 if (env != NULL)
9831 (void) xmlAddChild(n, env);
9832
9833 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9834 scfdie();
9835
9836 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9837 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9838 scfdie();
9839
9840 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
9841 if (set_attr_from_prop(exp_prop, n,
9842 "working_directory") != 0)
9843 err = 1;
9844 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
9845 if (set_attr_from_prop(exp_prop, n, "project") != 0)
9846 err = 1;
9847 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
9848 if (set_attr_from_prop(exp_prop, n,
9849 "resource_pool") != 0)
9850 err = 1;
9851 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9852 /* EMPTY */
9853 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
9854 if (use_profile ||
9855 set_attr_from_prop(exp_prop, cred, "user") != 0)
9856 err = 1;
9857 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
9858 if (use_profile ||
9859 set_attr_from_prop(exp_prop, cred, "group") != 0)
9860 err = 1;
9861 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
9862 if (use_profile || set_attr_from_prop(exp_prop, cred,
9863 "supp_groups") != 0)
9864 err = 1;
9865 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
9866 if (use_profile || set_attr_from_prop(exp_prop, cred,
9867 "privileges") != 0)
9868 err = 1;
9869 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
9870 0) {
9871 if (use_profile || set_attr_from_prop(exp_prop, cred,
9872 "limit_privileges") != 0)
9873 err = 1;
9874 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9875 if (!use_profile || set_attr_from_prop(exp_prop,
9876 prof, name_attr) != 0)
9877 err = 1;
9878 } else {
9879 /* Can't have generic properties in method_context's */
9880 err = 1;
9881 }
9882 }
9883 if (ret == -1)
9884 scfdie();
9885
9886 if (err && env == NULL) {
9887 xmlFreeNode(n);
9888 export_pg(pg, elts, SCE_ALL_VALUES);
9889 return;
9890 }
9891
9892 elts->method_context = n;
9893 }
9894
9895 /*
9896 * Given a dependency property group in the tfmri entity (target fmri), return
9897 * a dependent element which represents it.
9898 */
9899 static xmlNodePtr
export_dependent(scf_propertygroup_t * pg,const char * name,const char * tfmri)9900 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
9901 {
9902 uint8_t b;
9903 xmlNodePtr n, sf;
9904 int err = 0, ret;
9905 struct pg_elts pgelts;
9906
9907 /*
9908 * If external isn't set to true then exporting the service will
9909 * export this as a normal dependency, so we should stop to avoid
9910 * duplication.
9911 */
9912 if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
9913 scf_property_get_value(exp_prop, exp_val) != 0 ||
9914 scf_value_get_boolean(exp_val, &b) != 0 || !b) {
9915 if (g_verbose) {
9916 warn(gettext("Dependent \"%s\" cannot be exported "
9917 "properly because the \"%s\" property of the "
9918 "\"%s\" dependency of %s is not set to true.\n"),
9919 name, scf_property_external, name, tfmri);
9920 }
9921
9922 return (NULL);
9923 }
9924
9925 n = xmlNewNode(NULL, (xmlChar *)"dependent");
9926 if (n == NULL)
9927 uu_die(emsg_create_xml);
9928
9929 safe_setprop(n, name_attr, name);
9930
9931 /* Get the required attributes */
9932 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9933 set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9934 err = 1;
9935
9936 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9937 set_attr_from_prop(exp_prop, n, "grouping") != 0)
9938 err = 1;
9939
9940 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9941 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
9942 prop_get_val(exp_prop, exp_val) == 0) {
9943 /* EMPTY */
9944 } else
9945 err = 1;
9946
9947 if (err) {
9948 xmlFreeNode(n);
9949 return (NULL);
9950 }
9951
9952 sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
9953 if (sf == NULL)
9954 uu_die(emsg_create_xml);
9955
9956 safe_setprop(sf, value_attr, tfmri);
9957
9958 /*
9959 * Now add elements for the other properties.
9960 */
9961 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9962 scfdie();
9963
9964 (void) memset(&pgelts, 0, sizeof (pgelts));
9965
9966 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9967 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9968 scfdie();
9969
9970 if (strcmp(exp_str, scf_property_external) == 0 ||
9971 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9972 strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9973 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9974 continue;
9975 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
9976 if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
9977 prop_get_val(exp_prop, exp_val) == 0) {
9978 char type[sizeof ("service") + 1];
9979
9980 if (scf_value_get_astring(exp_val, type,
9981 sizeof (type)) < 0)
9982 scfdie();
9983
9984 if (strcmp(type, "service") == 0)
9985 continue;
9986 }
9987 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9988 xmlNodePtr s;
9989
9990 s = xmlNewNode(NULL, (xmlChar *)"stability");
9991 if (s == NULL)
9992 uu_die(emsg_create_xml);
9993
9994 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9995 pgelts.stability = s;
9996 continue;
9997 }
9998
9999 xmlFreeNode(s);
10000 }
10001
10002 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10003 }
10004 if (ret == -1)
10005 scfdie();
10006
10007 (void) xmlAddChild(n, pgelts.stability);
10008 (void) xmlAddChildList(n, pgelts.propvals);
10009 (void) xmlAddChildList(n, pgelts.properties);
10010
10011 return (n);
10012 }
10013
10014 static void
export_dependents(scf_propertygroup_t * pg,struct entity_elts * eelts)10015 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
10016 {
10017 scf_propertygroup_t *opg;
10018 scf_iter_t *iter;
10019 char *type, *fmri;
10020 int ret;
10021 struct pg_elts pgelts;
10022 xmlNodePtr n;
10023 scf_error_t serr;
10024
10025 if ((opg = scf_pg_create(g_hndl)) == NULL ||
10026 (iter = scf_iter_create(g_hndl)) == NULL)
10027 scfdie();
10028
10029 /* Can't use exp_prop_iter due to export_dependent(). */
10030 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
10031 scfdie();
10032
10033 type = safe_malloc(max_scf_pg_type_len + 1);
10034
10035 /* Get an extra byte so we can tell if values are too long. */
10036 fmri = safe_malloc(max_scf_fmri_len + 2);
10037
10038 (void) memset(&pgelts, 0, sizeof (pgelts));
10039
10040 while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
10041 void *entity;
10042 int isservice;
10043 scf_type_t ty;
10044
10045 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
10046 scfdie();
10047
10048 if ((ty != SCF_TYPE_ASTRING &&
10049 prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
10050 prop_get_val(exp_prop, exp_val) != 0) {
10051 export_property(exp_prop, NULL, &pgelts,
10052 SCE_ALL_VALUES);
10053 continue;
10054 }
10055
10056 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10057 scfdie();
10058
10059 if (scf_value_get_astring(exp_val, fmri,
10060 max_scf_fmri_len + 2) < 0)
10061 scfdie();
10062
10063 /* Look for a dependency group in the target fmri. */
10064 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
10065 switch (serr) {
10066 case SCF_ERROR_NONE:
10067 break;
10068
10069 case SCF_ERROR_NO_MEMORY:
10070 uu_die(gettext("Out of memory.\n"));
10071 /* NOTREACHED */
10072
10073 case SCF_ERROR_INVALID_ARGUMENT:
10074 if (g_verbose) {
10075 if (scf_property_to_fmri(exp_prop, fmri,
10076 max_scf_fmri_len + 2) < 0)
10077 scfdie();
10078
10079 warn(gettext("The value of %s is not a valid "
10080 "FMRI.\n"), fmri);
10081 }
10082
10083 export_property(exp_prop, exp_str, &pgelts,
10084 SCE_ALL_VALUES);
10085 continue;
10086
10087 case SCF_ERROR_CONSTRAINT_VIOLATED:
10088 if (g_verbose) {
10089 if (scf_property_to_fmri(exp_prop, fmri,
10090 max_scf_fmri_len + 2) < 0)
10091 scfdie();
10092
10093 warn(gettext("The value of %s does not specify "
10094 "a service or an instance.\n"), fmri);
10095 }
10096
10097 export_property(exp_prop, exp_str, &pgelts,
10098 SCE_ALL_VALUES);
10099 continue;
10100
10101 case SCF_ERROR_NOT_FOUND:
10102 if (g_verbose) {
10103 if (scf_property_to_fmri(exp_prop, fmri,
10104 max_scf_fmri_len + 2) < 0)
10105 scfdie();
10106
10107 warn(gettext("The entity specified by %s does "
10108 "not exist.\n"), fmri);
10109 }
10110
10111 export_property(exp_prop, exp_str, &pgelts,
10112 SCE_ALL_VALUES);
10113 continue;
10114
10115 default:
10116 #ifndef NDEBUG
10117 (void) fprintf(stderr, "%s:%d: %s() failed with "
10118 "unexpected error %d.\n", __FILE__, __LINE__,
10119 "fmri_to_entity", serr);
10120 #endif
10121 abort();
10122 }
10123
10124 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
10125 if (scf_error() != SCF_ERROR_NOT_FOUND)
10126 scfdie();
10127
10128 warn(gettext("Entity %s is missing dependency property "
10129 "group %s.\n"), fmri, exp_str);
10130
10131 export_property(exp_prop, NULL, &pgelts,
10132 SCE_ALL_VALUES);
10133 continue;
10134 }
10135
10136 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
10137 scfdie();
10138
10139 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
10140 if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
10141 scfdie();
10142
10143 warn(gettext("Property group %s is not of "
10144 "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
10145
10146 export_property(exp_prop, NULL, &pgelts,
10147 SCE_ALL_VALUES);
10148 continue;
10149 }
10150
10151 n = export_dependent(opg, exp_str, fmri);
10152 if (n == NULL) {
10153 export_property(exp_prop, exp_str, &pgelts,
10154 SCE_ALL_VALUES);
10155 } else {
10156 if (eelts->dependents == NULL)
10157 eelts->dependents = n;
10158 else
10159 (void) xmlAddSibling(eelts->dependents,
10160 n);
10161 }
10162 }
10163 if (ret == -1)
10164 scfdie();
10165
10166 free(fmri);
10167 free(type);
10168
10169 scf_iter_destroy(iter);
10170 scf_pg_destroy(opg);
10171
10172 if (pgelts.propvals != NULL || pgelts.properties != NULL)
10173 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
10174 eelts);
10175 }
10176
10177 static void
make_node(xmlNodePtr * nodep,const char * name)10178 make_node(xmlNodePtr *nodep, const char *name)
10179 {
10180 if (*nodep == NULL) {
10181 *nodep = xmlNewNode(NULL, (xmlChar *)name);
10182 if (*nodep == NULL)
10183 uu_die(emsg_create_xml);
10184 }
10185 }
10186
10187 static xmlNodePtr
export_tm_loctext(scf_propertygroup_t * pg,const char * parname)10188 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
10189 {
10190 int ret;
10191 xmlNodePtr parent = NULL;
10192 xmlNodePtr loctext = NULL;
10193
10194 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10195 scfdie();
10196
10197 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10198 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
10199 prop_get_val(exp_prop, exp_val) != 0)
10200 continue;
10201
10202 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
10203 scfdie();
10204
10205 make_node(&parent, parname);
10206 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
10207 (xmlChar *)exp_str);
10208 if (loctext == NULL)
10209 uu_die(emsg_create_xml);
10210
10211 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10212 scfdie();
10213
10214 safe_setprop(loctext, "xml:lang", exp_str);
10215 }
10216
10217 if (ret == -1)
10218 scfdie();
10219
10220 return (parent);
10221 }
10222
10223 static xmlNodePtr
export_tm_manpage(scf_propertygroup_t * pg)10224 export_tm_manpage(scf_propertygroup_t *pg)
10225 {
10226 xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
10227 if (manpage == NULL)
10228 uu_die(emsg_create_xml);
10229
10230 if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
10231 set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
10232 pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
10233 set_attr_from_prop(exp_prop, manpage, "section") != 0) {
10234 xmlFreeNode(manpage);
10235 return (NULL);
10236 }
10237
10238 if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
10239 (void) set_attr_from_prop_default(exp_prop,
10240 manpage, "manpath", ":default");
10241
10242 return (manpage);
10243 }
10244
10245 static xmlNodePtr
export_tm_doc_link(scf_propertygroup_t * pg)10246 export_tm_doc_link(scf_propertygroup_t *pg)
10247 {
10248 xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
10249 if (doc_link == NULL)
10250 uu_die(emsg_create_xml);
10251
10252 if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
10253 set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
10254 pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
10255 set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
10256 xmlFreeNode(doc_link);
10257 return (NULL);
10258 }
10259 return (doc_link);
10260 }
10261
10262 /*
10263 * Process template information for a service or instances.
10264 */
10265 static void
export_template(scf_propertygroup_t * pg,struct entity_elts * elts,struct template_elts * telts)10266 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
10267 struct template_elts *telts)
10268 {
10269 size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
10270 size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
10271 xmlNodePtr child = NULL;
10272
10273 if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
10274 scfdie();
10275
10276 if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
10277 telts->common_name = export_tm_loctext(pg, "common_name");
10278 if (telts->common_name == NULL)
10279 export_pg(pg, elts, SCE_ALL_VALUES);
10280 return;
10281 } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
10282 telts->description = export_tm_loctext(pg, "description");
10283 if (telts->description == NULL)
10284 export_pg(pg, elts, SCE_ALL_VALUES);
10285 return;
10286 }
10287
10288 if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
10289 child = export_tm_manpage(pg);
10290 } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
10291 child = export_tm_doc_link(pg);
10292 }
10293
10294 if (child != NULL) {
10295 make_node(&telts->documentation, "documentation");
10296 (void) xmlAddChild(telts->documentation, child);
10297 } else {
10298 export_pg(pg, elts, SCE_ALL_VALUES);
10299 }
10300 }
10301
10302 /*
10303 * Process parameter and paramval elements
10304 */
10305 static void
export_parameter(scf_property_t * prop,const char * name,struct params_elts * elts)10306 export_parameter(scf_property_t *prop, const char *name,
10307 struct params_elts *elts)
10308 {
10309 xmlNodePtr param;
10310 scf_error_t err = 0;
10311 int ret;
10312
10313 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
10314 if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL)
10315 uu_die(emsg_create_xml);
10316
10317 safe_setprop(param, name_attr, name);
10318
10319 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
10320 scfdie();
10321 safe_setprop(param, value_attr, exp_str);
10322
10323 if (elts->paramval == NULL)
10324 elts->paramval = param;
10325 else
10326 (void) xmlAddSibling(elts->paramval, param);
10327
10328 return;
10329 }
10330
10331 err = scf_error();
10332
10333 if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
10334 err != SCF_ERROR_NOT_FOUND)
10335 scfdie();
10336
10337 if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL)
10338 uu_die(emsg_create_xml);
10339
10340 safe_setprop(param, name_attr, name);
10341
10342 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
10343 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
10344 scfdie();
10345
10346 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
10347 1) {
10348 xmlNodePtr vn;
10349
10350 if ((vn = xmlNewChild(param, NULL,
10351 (xmlChar *)"value_node", NULL)) == NULL)
10352 uu_die(emsg_create_xml);
10353
10354 if (scf_value_get_as_string(exp_val, exp_str,
10355 exp_str_sz) < 0)
10356 scfdie();
10357
10358 safe_setprop(vn, value_attr, exp_str);
10359 }
10360 if (ret != 0)
10361 scfdie();
10362 }
10363
10364 if (elts->parameter == NULL)
10365 elts->parameter = param;
10366 else
10367 (void) xmlAddSibling(elts->parameter, param);
10368 }
10369
10370 /*
10371 * Process notification parameters for a service or instance
10372 */
10373 static void
export_notify_params(scf_propertygroup_t * pg,struct entity_elts * elts)10374 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts)
10375 {
10376 xmlNodePtr n, event, *type;
10377 struct params_elts *eelts;
10378 int ret, err, i;
10379
10380 n = xmlNewNode(NULL, (xmlChar *)"notification_parameters");
10381 event = xmlNewNode(NULL, (xmlChar *)"event");
10382 if (n == NULL || event == NULL)
10383 uu_die(emsg_create_xml);
10384
10385 /* event value */
10386 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
10387 scfdie();
10388 safe_setprop(event, value_attr, exp_str);
10389
10390 (void) xmlAddChild(n, event);
10391
10392 if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL ||
10393 (eelts = calloc(URI_SCHEME_NUM,
10394 sizeof (struct params_elts))) == NULL)
10395 uu_die(gettext("Out of memory.\n"));
10396
10397 err = 0;
10398
10399 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10400 scfdie();
10401
10402 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10403 char *t, *p;
10404
10405 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10406 scfdie();
10407
10408 if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) {
10409 /*
10410 * this is not a well formed notification parameters
10411 * element, we should export as regular pg
10412 */
10413 err = 1;
10414 break;
10415 }
10416
10417 if ((i = check_uri_protocol(t)) < 0) {
10418 err = 1;
10419 break;
10420 }
10421
10422 if (type[i] == NULL) {
10423 if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) ==
10424 NULL)
10425 uu_die(emsg_create_xml);
10426
10427 safe_setprop(type[i], name_attr, t);
10428 }
10429 if (strcmp(p, active_attr) == 0) {
10430 if (set_attr_from_prop(exp_prop, type[i],
10431 active_attr) != 0) {
10432 err = 1;
10433 break;
10434 }
10435 continue;
10436 }
10437 /*
10438 * We export the parameter
10439 */
10440 export_parameter(exp_prop, p, &eelts[i]);
10441 }
10442
10443 if (ret == -1)
10444 scfdie();
10445
10446 if (err == 1) {
10447 for (i = 0; i < URI_SCHEME_NUM; ++i)
10448 xmlFree(type[i]);
10449 free(type);
10450
10451 export_pg(pg, elts, SCE_ALL_VALUES);
10452
10453 return;
10454 } else {
10455 for (i = 0; i < URI_SCHEME_NUM; ++i)
10456 if (type[i] != NULL) {
10457 (void) xmlAddChildList(type[i],
10458 eelts[i].paramval);
10459 (void) xmlAddChildList(type[i],
10460 eelts[i].parameter);
10461 (void) xmlAddSibling(event, type[i]);
10462 }
10463 }
10464 free(type);
10465
10466 if (elts->notify_params == NULL)
10467 elts->notify_params = n;
10468 else
10469 (void) xmlAddSibling(elts->notify_params, n);
10470 }
10471
10472 /*
10473 * Process the general property group for an instance.
10474 */
10475 static void
export_inst_general(scf_propertygroup_t * pg,xmlNodePtr inode,struct entity_elts * elts)10476 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
10477 struct entity_elts *elts)
10478 {
10479 uint8_t enabled;
10480 struct pg_elts pgelts;
10481 int ret;
10482
10483 /* enabled */
10484 if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
10485 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
10486 prop_get_val(exp_prop, exp_val) == 0) {
10487 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
10488 scfdie();
10489 } else {
10490 enabled = 0;
10491 }
10492
10493 safe_setprop(inode, enabled_attr, enabled ? true : false);
10494
10495 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10496 scfdie();
10497
10498 (void) memset(&pgelts, 0, sizeof (pgelts));
10499
10500 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10501 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10502 scfdie();
10503
10504 if (strcmp(exp_str, scf_property_enabled) == 0) {
10505 continue;
10506 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
10507 xmlNodePtr rnode, sfnode;
10508
10509 rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10510 if (rnode == NULL)
10511 uu_die(emsg_create_xml);
10512
10513 sfnode = xmlNewChild(rnode, NULL,
10514 (xmlChar *)"service_fmri", NULL);
10515 if (sfnode == NULL)
10516 uu_die(emsg_create_xml);
10517
10518 if (set_attr_from_prop(exp_prop, sfnode,
10519 value_attr) == 0) {
10520 elts->restarter = rnode;
10521 continue;
10522 }
10523
10524 xmlFreeNode(rnode);
10525 }
10526
10527 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10528 }
10529 if (ret == -1)
10530 scfdie();
10531
10532 if (pgelts.propvals != NULL || pgelts.properties != NULL)
10533 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10534 elts);
10535 }
10536
10537 /*
10538 * Put an instance element for the given instance into selts.
10539 */
10540 static void
export_instance(scf_instance_t * inst,struct entity_elts * selts,int flags)10541 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10542 {
10543 xmlNodePtr n;
10544 boolean_t isdefault;
10545 struct entity_elts elts;
10546 struct template_elts template_elts;
10547 int ret;
10548
10549 n = xmlNewNode(NULL, (xmlChar *)"instance");
10550 if (n == NULL)
10551 uu_die(emsg_create_xml);
10552
10553 /* name */
10554 if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10555 scfdie();
10556 safe_setprop(n, name_attr, exp_str);
10557 isdefault = strcmp(exp_str, "default") == 0;
10558
10559 /* check existance of general pg (since general/enabled is required) */
10560 if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
10561 if (scf_error() != SCF_ERROR_NOT_FOUND)
10562 scfdie();
10563
10564 if (g_verbose) {
10565 if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10566 scfdie();
10567
10568 warn(gettext("Instance %s has no general property "
10569 "group; it will be marked disabled.\n"), exp_str);
10570 }
10571
10572 safe_setprop(n, enabled_attr, false);
10573 } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
10574 strcmp(exp_str, scf_group_framework) != 0) {
10575 if (g_verbose) {
10576 if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10577 scfdie();
10578
10579 warn(gettext("Property group %s is not of type "
10580 "framework; the instance will be marked "
10581 "disabled.\n"), exp_str);
10582 }
10583
10584 safe_setprop(n, enabled_attr, false);
10585 }
10586
10587 /* property groups */
10588 if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
10589 scfdie();
10590
10591 (void) memset(&elts, 0, sizeof (elts));
10592 (void) memset(&template_elts, 0, sizeof (template_elts));
10593
10594 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10595 uint32_t pgflags;
10596
10597 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10598 scfdie();
10599
10600 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10601 continue;
10602
10603 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10604 scfdie();
10605
10606 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10607 export_dependency(exp_pg, &elts);
10608 continue;
10609 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10610 export_method(exp_pg, &elts);
10611 continue;
10612 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10613 if (scf_pg_get_name(exp_pg, exp_str,
10614 max_scf_name_len + 1) < 0)
10615 scfdie();
10616
10617 if (strcmp(exp_str, scf_pg_general) == 0) {
10618 export_inst_general(exp_pg, n, &elts);
10619 continue;
10620 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10621 0) {
10622 export_method_context(exp_pg, &elts);
10623 continue;
10624 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10625 export_dependents(exp_pg, &elts);
10626 continue;
10627 }
10628 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10629 export_template(exp_pg, &elts, &template_elts);
10630 continue;
10631 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10632 export_notify_params(exp_pg, &elts);
10633 continue;
10634 }
10635
10636 /* Ordinary pg. */
10637 export_pg(exp_pg, &elts, flags);
10638 }
10639 if (ret == -1)
10640 scfdie();
10641
10642 if (template_elts.common_name != NULL) {
10643 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10644 (void) xmlAddChild(elts.template, template_elts.common_name);
10645 (void) xmlAddChild(elts.template, template_elts.description);
10646 (void) xmlAddChild(elts.template, template_elts.documentation);
10647 } else {
10648 xmlFreeNode(template_elts.description);
10649 xmlFreeNode(template_elts.documentation);
10650 }
10651
10652 if (isdefault && elts.restarter == NULL &&
10653 elts.dependencies == NULL && elts.method_context == NULL &&
10654 elts.exec_methods == NULL && elts.notify_params == NULL &&
10655 elts.property_groups == NULL && elts.template == NULL) {
10656 xmlChar *eval;
10657
10658 /* This is a default instance */
10659 eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10660
10661 xmlFreeNode(n);
10662
10663 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10664 if (n == NULL)
10665 uu_die(emsg_create_xml);
10666
10667 safe_setprop(n, enabled_attr, (char *)eval);
10668 xmlFree(eval);
10669
10670 selts->create_default_instance = n;
10671 } else {
10672 /* Assemble the children in order. */
10673 (void) xmlAddChild(n, elts.restarter);
10674 (void) xmlAddChildList(n, elts.dependencies);
10675 (void) xmlAddChildList(n, elts.dependents);
10676 (void) xmlAddChild(n, elts.method_context);
10677 (void) xmlAddChildList(n, elts.exec_methods);
10678 (void) xmlAddChildList(n, elts.notify_params);
10679 (void) xmlAddChildList(n, elts.property_groups);
10680 (void) xmlAddChild(n, elts.template);
10681
10682 if (selts->instances == NULL)
10683 selts->instances = n;
10684 else
10685 (void) xmlAddSibling(selts->instances, n);
10686 }
10687 }
10688
10689 /*
10690 * Return a service element for the given service.
10691 */
10692 static xmlNodePtr
export_service(scf_service_t * svc,int flags)10693 export_service(scf_service_t *svc, int flags)
10694 {
10695 xmlNodePtr snode;
10696 struct entity_elts elts;
10697 struct template_elts template_elts;
10698 int ret;
10699
10700 snode = xmlNewNode(NULL, (xmlChar *)"service");
10701 if (snode == NULL)
10702 uu_die(emsg_create_xml);
10703
10704 /* Get & set name attribute */
10705 if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
10706 scfdie();
10707 safe_setprop(snode, name_attr, exp_str);
10708
10709 safe_setprop(snode, type_attr, "service");
10710 safe_setprop(snode, "version", "0");
10711
10712 /* Acquire child elements. */
10713 if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
10714 scfdie();
10715
10716 (void) memset(&elts, 0, sizeof (elts));
10717 (void) memset(&template_elts, 0, sizeof (template_elts));
10718
10719 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10720 uint32_t pgflags;
10721
10722 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10723 scfdie();
10724
10725 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10726 continue;
10727
10728 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10729 scfdie();
10730
10731 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10732 export_dependency(exp_pg, &elts);
10733 continue;
10734 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10735 export_method(exp_pg, &elts);
10736 continue;
10737 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10738 if (scf_pg_get_name(exp_pg, exp_str,
10739 max_scf_name_len + 1) < 0)
10740 scfdie();
10741
10742 if (strcmp(exp_str, scf_pg_general) == 0) {
10743 export_svc_general(exp_pg, &elts);
10744 continue;
10745 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10746 0) {
10747 export_method_context(exp_pg, &elts);
10748 continue;
10749 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10750 export_dependents(exp_pg, &elts);
10751 continue;
10752 } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10753 continue;
10754 }
10755 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10756 export_template(exp_pg, &elts, &template_elts);
10757 continue;
10758 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10759 export_notify_params(exp_pg, &elts);
10760 continue;
10761 }
10762
10763 export_pg(exp_pg, &elts, flags);
10764 }
10765 if (ret == -1)
10766 scfdie();
10767
10768 if (template_elts.common_name != NULL) {
10769 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10770 (void) xmlAddChild(elts.template, template_elts.common_name);
10771 (void) xmlAddChild(elts.template, template_elts.description);
10772 (void) xmlAddChild(elts.template, template_elts.documentation);
10773 } else {
10774 xmlFreeNode(template_elts.description);
10775 xmlFreeNode(template_elts.documentation);
10776 }
10777
10778 /* Iterate instances */
10779 if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
10780 scfdie();
10781
10782 while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10783 export_instance(exp_inst, &elts, flags);
10784 if (ret == -1)
10785 scfdie();
10786
10787 /* Now add all of the accumulated elements in order. */
10788 (void) xmlAddChild(snode, elts.create_default_instance);
10789 (void) xmlAddChild(snode, elts.single_instance);
10790 (void) xmlAddChild(snode, elts.restarter);
10791 (void) xmlAddChildList(snode, elts.dependencies);
10792 (void) xmlAddChildList(snode, elts.dependents);
10793 (void) xmlAddChild(snode, elts.method_context);
10794 (void) xmlAddChildList(snode, elts.exec_methods);
10795 (void) xmlAddChildList(snode, elts.notify_params);
10796 (void) xmlAddChildList(snode, elts.property_groups);
10797 (void) xmlAddChildList(snode, elts.instances);
10798 (void) xmlAddChild(snode, elts.stability);
10799 (void) xmlAddChild(snode, elts.template);
10800
10801 return (snode);
10802 }
10803
10804 static int
export_callback(void * data,scf_walkinfo_t * wip)10805 export_callback(void *data, scf_walkinfo_t *wip)
10806 {
10807 FILE *f;
10808 xmlDocPtr doc;
10809 xmlNodePtr sb;
10810 int result;
10811 struct export_args *argsp = (struct export_args *)data;
10812
10813 if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
10814 (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10815 (exp_prop = scf_property_create(g_hndl)) == NULL ||
10816 (exp_val = scf_value_create(g_hndl)) == NULL ||
10817 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10818 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10819 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10820 (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10821 scfdie();
10822
10823 exp_str_sz = max_scf_len + 1;
10824 exp_str = safe_malloc(exp_str_sz);
10825
10826 if (argsp->filename != NULL) {
10827 errno = 0;
10828 f = fopen(argsp->filename, "wb");
10829 if (f == NULL) {
10830 if (errno == 0)
10831 uu_die(gettext("Could not open \"%s\": no free "
10832 "stdio streams.\n"), argsp->filename);
10833 else
10834 uu_die(gettext("Could not open \"%s\""),
10835 argsp->filename);
10836 }
10837 } else
10838 f = stdout;
10839
10840 doc = xmlNewDoc((xmlChar *)"1.0");
10841 if (doc == NULL)
10842 uu_die(gettext("Could not create XML document.\n"));
10843
10844 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10845 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10846 uu_die(emsg_create_xml);
10847
10848 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10849 if (sb == NULL)
10850 uu_die(emsg_create_xml);
10851 safe_setprop(sb, type_attr, "manifest");
10852 safe_setprop(sb, name_attr, "export");
10853 (void) xmlAddSibling(doc->children, sb);
10854
10855 (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
10856
10857 result = write_service_bundle(doc, f);
10858
10859 free(exp_str);
10860 scf_iter_destroy(exp_val_iter);
10861 scf_iter_destroy(exp_prop_iter);
10862 scf_iter_destroy(exp_pg_iter);
10863 scf_iter_destroy(exp_inst_iter);
10864 scf_value_destroy(exp_val);
10865 scf_property_destroy(exp_prop);
10866 scf_pg_destroy(exp_pg);
10867 scf_instance_destroy(exp_inst);
10868
10869 xmlFreeDoc(doc);
10870
10871 if (f != stdout)
10872 (void) fclose(f);
10873
10874 return (result);
10875 }
10876
10877 /*
10878 * Get the service named by fmri, build an XML tree which represents it, and
10879 * dump it into filename (or stdout if filename is NULL).
10880 */
10881 int
lscf_service_export(char * fmri,const char * filename,int flags)10882 lscf_service_export(char *fmri, const char *filename, int flags)
10883 {
10884 struct export_args args;
10885 char *fmridup;
10886 const char *scope, *svc, *inst;
10887 size_t cblen = 3 * max_scf_name_len;
10888 char *canonbuf = alloca(cblen);
10889 int ret, err;
10890
10891 lscf_prep_hndl();
10892
10893 bzero(&args, sizeof (args));
10894 args.filename = filename;
10895 args.flags = flags;
10896
10897 /*
10898 * If some poor user has passed an exact instance FMRI, of the sort
10899 * one might cut and paste from svcs(1) or an error message, warn
10900 * and chop off the instance instead of failing.
10901 */
10902 fmridup = alloca(strlen(fmri) + 1);
10903 (void) strcpy(fmridup, fmri);
10904 if (strncmp(fmridup, SCF_FMRI_SVC_PREFIX,
10905 sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 &&
10906 scf_parse_svc_fmri(fmridup, &scope, &svc, &inst, NULL, NULL) == 0 &&
10907 inst != NULL) {
10908 (void) strlcpy(canonbuf, "svc:/", cblen);
10909 if (strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
10910 (void) strlcat(canonbuf, "/", cblen);
10911 (void) strlcat(canonbuf, scope, cblen);
10912 }
10913 (void) strlcat(canonbuf, svc, cblen);
10914 fmri = canonbuf;
10915
10916 warn(gettext("Only services may be exported; ignoring "
10917 "instance portion of argument.\n"));
10918 }
10919
10920 err = 0;
10921 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10922 SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10923 &args, &err, semerr)) != 0) {
10924 if (ret != -1)
10925 semerr(gettext("Failed to walk instances: %s\n"),
10926 scf_strerror(ret));
10927 return (-1);
10928 }
10929
10930 /*
10931 * Error message has already been printed.
10932 */
10933 if (err != 0)
10934 return (-1);
10935
10936 return (0);
10937 }
10938
10939
10940 /*
10941 * Archive
10942 */
10943
10944 static xmlNodePtr
make_archive(int flags)10945 make_archive(int flags)
10946 {
10947 xmlNodePtr sb;
10948 scf_scope_t *scope;
10949 scf_service_t *svc;
10950 scf_iter_t *iter;
10951 int r;
10952
10953 if ((scope = scf_scope_create(g_hndl)) == NULL ||
10954 (svc = scf_service_create(g_hndl)) == NULL ||
10955 (iter = scf_iter_create(g_hndl)) == NULL ||
10956 (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10957 (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10958 (exp_prop = scf_property_create(g_hndl)) == NULL ||
10959 (exp_val = scf_value_create(g_hndl)) == NULL ||
10960 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10961 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10962 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10963 (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10964 scfdie();
10965
10966 exp_str_sz = max_scf_len + 1;
10967 exp_str = safe_malloc(exp_str_sz);
10968
10969 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10970 if (sb == NULL)
10971 uu_die(emsg_create_xml);
10972 safe_setprop(sb, type_attr, "archive");
10973 safe_setprop(sb, name_attr, "none");
10974
10975 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
10976 scfdie();
10977 if (scf_iter_scope_services(iter, scope) != 0)
10978 scfdie();
10979
10980 for (;;) {
10981 r = scf_iter_next_service(iter, svc);
10982 if (r == 0)
10983 break;
10984 if (r != 1)
10985 scfdie();
10986
10987 if (scf_service_get_name(svc, exp_str,
10988 max_scf_name_len + 1) < 0)
10989 scfdie();
10990
10991 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
10992 continue;
10993
10994 (void) xmlAddChild(sb, export_service(svc, flags));
10995 }
10996
10997 free(exp_str);
10998
10999 scf_iter_destroy(exp_val_iter);
11000 scf_iter_destroy(exp_prop_iter);
11001 scf_iter_destroy(exp_pg_iter);
11002 scf_iter_destroy(exp_inst_iter);
11003 scf_value_destroy(exp_val);
11004 scf_property_destroy(exp_prop);
11005 scf_pg_destroy(exp_pg);
11006 scf_instance_destroy(exp_inst);
11007 scf_iter_destroy(iter);
11008 scf_service_destroy(svc);
11009 scf_scope_destroy(scope);
11010
11011 return (sb);
11012 }
11013
11014 int
lscf_archive(const char * filename,int flags)11015 lscf_archive(const char *filename, int flags)
11016 {
11017 FILE *f;
11018 xmlDocPtr doc;
11019 int result;
11020
11021 lscf_prep_hndl();
11022
11023 if (filename != NULL) {
11024 errno = 0;
11025 f = fopen(filename, "wb");
11026 if (f == NULL) {
11027 if (errno == 0)
11028 uu_die(gettext("Could not open \"%s\": no free "
11029 "stdio streams.\n"), filename);
11030 else
11031 uu_die(gettext("Could not open \"%s\""),
11032 filename);
11033 }
11034 } else
11035 f = stdout;
11036
11037 doc = xmlNewDoc((xmlChar *)"1.0");
11038 if (doc == NULL)
11039 uu_die(gettext("Could not create XML document.\n"));
11040
11041 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11042 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11043 uu_die(emsg_create_xml);
11044
11045 (void) xmlAddSibling(doc->children, make_archive(flags));
11046
11047 result = write_service_bundle(doc, f);
11048
11049 xmlFreeDoc(doc);
11050
11051 if (f != stdout)
11052 (void) fclose(f);
11053
11054 return (result);
11055 }
11056
11057
11058 /*
11059 * "Extract" a profile.
11060 */
11061 int
lscf_profile_extract(const char * filename)11062 lscf_profile_extract(const char *filename)
11063 {
11064 FILE *f;
11065 xmlDocPtr doc;
11066 xmlNodePtr sb, snode, inode;
11067 scf_scope_t *scope;
11068 scf_service_t *svc;
11069 scf_instance_t *inst;
11070 scf_propertygroup_t *pg;
11071 scf_property_t *prop;
11072 scf_value_t *val;
11073 scf_iter_t *siter, *iiter;
11074 int r, s;
11075 char *namebuf;
11076 uint8_t b;
11077 int result;
11078
11079 lscf_prep_hndl();
11080
11081 if (filename != NULL) {
11082 errno = 0;
11083 f = fopen(filename, "wb");
11084 if (f == NULL) {
11085 if (errno == 0)
11086 uu_die(gettext("Could not open \"%s\": no "
11087 "free stdio streams.\n"), filename);
11088 else
11089 uu_die(gettext("Could not open \"%s\""),
11090 filename);
11091 }
11092 } else
11093 f = stdout;
11094
11095 doc = xmlNewDoc((xmlChar *)"1.0");
11096 if (doc == NULL)
11097 uu_die(gettext("Could not create XML document.\n"));
11098
11099 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11100 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11101 uu_die(emsg_create_xml);
11102
11103 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
11104 if (sb == NULL)
11105 uu_die(emsg_create_xml);
11106 safe_setprop(sb, type_attr, "profile");
11107 safe_setprop(sb, name_attr, "extract");
11108 (void) xmlAddSibling(doc->children, sb);
11109
11110 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11111 (svc = scf_service_create(g_hndl)) == NULL ||
11112 (inst = scf_instance_create(g_hndl)) == NULL ||
11113 (pg = scf_pg_create(g_hndl)) == NULL ||
11114 (prop = scf_property_create(g_hndl)) == NULL ||
11115 (val = scf_value_create(g_hndl)) == NULL ||
11116 (siter = scf_iter_create(g_hndl)) == NULL ||
11117 (iiter = scf_iter_create(g_hndl)) == NULL)
11118 scfdie();
11119
11120 if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
11121 scfdie();
11122
11123 if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
11124 scfdie();
11125
11126 namebuf = safe_malloc(max_scf_name_len + 1);
11127
11128 while ((r = scf_iter_next_service(siter, svc)) == 1) {
11129 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
11130 scfdie();
11131
11132 snode = xmlNewNode(NULL, (xmlChar *)"service");
11133 if (snode == NULL)
11134 uu_die(emsg_create_xml);
11135
11136 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
11137 0)
11138 scfdie();
11139
11140 safe_setprop(snode, name_attr, namebuf);
11141
11142 safe_setprop(snode, type_attr, "service");
11143 safe_setprop(snode, "version", "0");
11144
11145 while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
11146 if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
11147 SCF_SUCCESS) {
11148 if (scf_error() != SCF_ERROR_NOT_FOUND)
11149 scfdie();
11150
11151 if (g_verbose) {
11152 ssize_t len;
11153 char *fmri;
11154
11155 len =
11156 scf_instance_to_fmri(inst, NULL, 0);
11157 if (len < 0)
11158 scfdie();
11159
11160 fmri = safe_malloc(len + 1);
11161
11162 if (scf_instance_to_fmri(inst, fmri,
11163 len + 1) < 0)
11164 scfdie();
11165
11166 warn("Instance %s has no \"%s\" "
11167 "property group.\n", fmri,
11168 scf_pg_general);
11169
11170 free(fmri);
11171 }
11172
11173 continue;
11174 }
11175
11176 if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
11177 prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
11178 prop_get_val(prop, val) != 0)
11179 continue;
11180
11181 inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
11182 NULL);
11183 if (inode == NULL)
11184 uu_die(emsg_create_xml);
11185
11186 if (scf_instance_get_name(inst, namebuf,
11187 max_scf_name_len + 1) < 0)
11188 scfdie();
11189
11190 safe_setprop(inode, name_attr, namebuf);
11191
11192 if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
11193 scfdie();
11194
11195 safe_setprop(inode, enabled_attr, b ? true : false);
11196 }
11197 if (s < 0)
11198 scfdie();
11199
11200 if (snode->children != NULL)
11201 (void) xmlAddChild(sb, snode);
11202 else
11203 xmlFreeNode(snode);
11204 }
11205 if (r < 0)
11206 scfdie();
11207
11208 free(namebuf);
11209
11210 result = write_service_bundle(doc, f);
11211
11212 xmlFreeDoc(doc);
11213
11214 if (f != stdout)
11215 (void) fclose(f);
11216
11217 return (result);
11218 }
11219
11220
11221 /*
11222 * Entity manipulation commands
11223 */
11224
11225 /*
11226 * Entity selection. If no entity is selected, then the current scope is in
11227 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected,
11228 * only cur_inst is NULL, and when an instance is selected, none are NULL.
11229 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
11230 * cur_inst will be non-NULL.
11231 */
11232
11233 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
11234 static int
select_inst(const char * name)11235 select_inst(const char *name)
11236 {
11237 scf_instance_t *inst;
11238 scf_error_t err;
11239
11240 assert(cur_svc != NULL);
11241
11242 inst = scf_instance_create(g_hndl);
11243 if (inst == NULL)
11244 scfdie();
11245
11246 if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
11247 cur_inst = inst;
11248 return (0);
11249 }
11250
11251 err = scf_error();
11252 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11253 scfdie();
11254
11255 scf_instance_destroy(inst);
11256 return (1);
11257 }
11258
11259 /* Returns as above. */
11260 static int
select_svc(const char * name)11261 select_svc(const char *name)
11262 {
11263 scf_service_t *svc;
11264 scf_error_t err;
11265
11266 assert(cur_scope != NULL);
11267
11268 svc = scf_service_create(g_hndl);
11269 if (svc == NULL)
11270 scfdie();
11271
11272 if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
11273 cur_svc = svc;
11274 return (0);
11275 }
11276
11277 err = scf_error();
11278 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11279 scfdie();
11280
11281 scf_service_destroy(svc);
11282 return (1);
11283 }
11284
11285 /* ARGSUSED */
11286 static int
select_callback(void * unused,scf_walkinfo_t * wip)11287 select_callback(void *unused, scf_walkinfo_t *wip)
11288 {
11289 scf_instance_t *inst;
11290 scf_service_t *svc;
11291 scf_scope_t *scope;
11292
11293 if (wip->inst != NULL) {
11294 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11295 (svc = scf_service_create(g_hndl)) == NULL ||
11296 (inst = scf_instance_create(g_hndl)) == NULL)
11297 scfdie();
11298
11299 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11300 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11301 scfdie();
11302 } else {
11303 assert(wip->svc != NULL);
11304
11305 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11306 (svc = scf_service_create(g_hndl)) == NULL)
11307 scfdie();
11308
11309 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11310 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11311 scfdie();
11312
11313 inst = NULL;
11314 }
11315
11316 /* Clear out the current selection */
11317 assert(cur_scope != NULL);
11318 scf_scope_destroy(cur_scope);
11319 scf_service_destroy(cur_svc);
11320 scf_instance_destroy(cur_inst);
11321
11322 cur_scope = scope;
11323 cur_svc = svc;
11324 cur_inst = inst;
11325
11326 return (0);
11327 }
11328
11329 static int
validate_callback(void * fmri_p,scf_walkinfo_t * wip)11330 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
11331 {
11332 char **fmri = fmri_p;
11333
11334 *fmri = strdup(wip->fmri);
11335 if (*fmri == NULL)
11336 uu_die(gettext("Out of memory.\n"));
11337
11338 return (0);
11339 }
11340
11341 /*
11342 * validate [fmri]
11343 * Perform the validation of an FMRI instance.
11344 */
11345 void
lscf_validate_fmri(const char * fmri)11346 lscf_validate_fmri(const char *fmri)
11347 {
11348 int ret = 0;
11349 size_t inst_sz;
11350 char *inst_fmri = NULL;
11351 scf_tmpl_errors_t *errs = NULL;
11352 char *snapbuf = NULL;
11353
11354 lscf_prep_hndl();
11355
11356 if (fmri == NULL) {
11357 inst_sz = max_scf_fmri_len + 1;
11358 inst_fmri = safe_malloc(inst_sz);
11359
11360 if (cur_snap != NULL) {
11361 snapbuf = safe_malloc(max_scf_name_len + 1);
11362 if (scf_snapshot_get_name(cur_snap, snapbuf,
11363 max_scf_name_len + 1) < 0)
11364 scfdie();
11365 }
11366 if (cur_inst == NULL) {
11367 semerr(gettext("No instance selected\n"));
11368 goto cleanup;
11369 } else if (scf_instance_to_fmri(cur_inst, inst_fmri,
11370 inst_sz) >= inst_sz) {
11371 /* sanity check. Should never get here */
11372 uu_die(gettext("Unexpected error! file %s, line %d\n"),
11373 __FILE__, __LINE__);
11374 }
11375 } else {
11376 scf_error_t scf_err;
11377 int err = 0;
11378
11379 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
11380 validate_callback, &inst_fmri, &err, semerr)) != 0) {
11381 uu_warn("Failed to walk instances: %s\n",
11382 scf_strerror(scf_err));
11383 goto cleanup;
11384 }
11385 if (err != 0) {
11386 /* error message displayed by scf_walk_fmri */
11387 goto cleanup;
11388 }
11389 }
11390
11391 ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
11392 SCF_TMPL_VALIDATE_FLAG_CURRENT);
11393 if (ret == -1) {
11394 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
11395 warn(gettext("Template data for %s is invalid. "
11396 "Consider reverting to a previous snapshot or "
11397 "restoring original configuration.\n"), inst_fmri);
11398 } else {
11399 uu_warn("%s: %s\n",
11400 gettext("Error validating the instance"),
11401 scf_strerror(scf_error()));
11402 }
11403 } else if (ret == 1 && errs != NULL) {
11404 scf_tmpl_error_t *err = NULL;
11405 char *msg;
11406 size_t len = 256; /* initial error buffer size */
11407 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
11408 SCF_TMPL_STRERROR_HUMAN : 0;
11409
11410 msg = safe_malloc(len);
11411
11412 while ((err = scf_tmpl_next_error(errs)) != NULL) {
11413 int ret;
11414
11415 if ((ret = scf_tmpl_strerror(err, msg, len,
11416 flag)) >= len) {
11417 len = ret + 1;
11418 msg = realloc(msg, len);
11419 if (msg == NULL)
11420 uu_die(gettext(
11421 "Out of memory.\n"));
11422 (void) scf_tmpl_strerror(err, msg, len,
11423 flag);
11424 }
11425 (void) fprintf(stderr, "%s\n", msg);
11426 }
11427 if (msg != NULL)
11428 free(msg);
11429 }
11430 if (errs != NULL)
11431 scf_tmpl_errors_destroy(errs);
11432
11433 cleanup:
11434 free(inst_fmri);
11435 free(snapbuf);
11436 }
11437
11438 static void
lscf_validate_file(const char * filename)11439 lscf_validate_file(const char *filename)
11440 {
11441 tmpl_errors_t *errs;
11442
11443 bundle_t *b = internal_bundle_new();
11444 if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
11445 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
11446 tmpl_errors_print(stderr, errs, "");
11447 semerr(gettext("Validation failed.\n"));
11448 }
11449 tmpl_errors_destroy(errs);
11450 }
11451 (void) internal_bundle_free(b);
11452 }
11453
11454 /*
11455 * validate [fmri|file]
11456 */
11457 void
lscf_validate(const char * arg)11458 lscf_validate(const char *arg)
11459 {
11460 const char *str;
11461
11462 if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
11463 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
11464 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
11465 lscf_validate_file(str);
11466 } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
11467 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
11468 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
11469 lscf_validate_fmri(str);
11470 } else if (access(arg, R_OK | F_OK) == 0) {
11471 lscf_validate_file(arg);
11472 } else {
11473 lscf_validate_fmri(arg);
11474 }
11475 }
11476
11477 void
lscf_select(const char * fmri)11478 lscf_select(const char *fmri)
11479 {
11480 int ret, err;
11481
11482 lscf_prep_hndl();
11483
11484 if (cur_snap != NULL) {
11485 struct snaplevel *elt;
11486 char *buf;
11487
11488 /* Error unless name is that of the next level. */
11489 elt = uu_list_next(cur_levels, cur_elt);
11490 if (elt == NULL) {
11491 semerr(gettext("No children.\n"));
11492 return;
11493 }
11494
11495 buf = safe_malloc(max_scf_name_len + 1);
11496
11497 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11498 max_scf_name_len + 1) < 0)
11499 scfdie();
11500
11501 if (strcmp(buf, fmri) != 0) {
11502 semerr(gettext("No such child.\n"));
11503 free(buf);
11504 return;
11505 }
11506
11507 free(buf);
11508
11509 cur_elt = elt;
11510 cur_level = elt->sl;
11511 return;
11512 }
11513
11514 /*
11515 * Special case for 'svc:', which takes the user to the scope level.
11516 */
11517 if (strcmp(fmri, "svc:") == 0) {
11518 scf_instance_destroy(cur_inst);
11519 scf_service_destroy(cur_svc);
11520 cur_inst = NULL;
11521 cur_svc = NULL;
11522 return;
11523 }
11524
11525 /*
11526 * Special case for ':properties'. This appears as part of 'list' but
11527 * can't be selected. Give a more helpful error message in this case.
11528 */
11529 if (strcmp(fmri, ":properties") == 0) {
11530 semerr(gettext(":properties is not an entity. Try 'listprop' "
11531 "to list properties.\n"));
11532 return;
11533 }
11534
11535 /*
11536 * First try the argument as relative to the current selection.
11537 */
11538 if (cur_inst != NULL) {
11539 /* EMPTY */;
11540 } else if (cur_svc != NULL) {
11541 if (select_inst(fmri) != 1)
11542 return;
11543 } else {
11544 if (select_svc(fmri) != 1)
11545 return;
11546 }
11547
11548 err = 0;
11549 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11550 select_callback, NULL, &err, semerr)) != 0) {
11551 semerr(gettext("Failed to walk instances: %s\n"),
11552 scf_strerror(ret));
11553 }
11554 }
11555
11556 void
lscf_unselect(void)11557 lscf_unselect(void)
11558 {
11559 lscf_prep_hndl();
11560
11561 if (cur_snap != NULL) {
11562 struct snaplevel *elt;
11563
11564 elt = uu_list_prev(cur_levels, cur_elt);
11565 if (elt == NULL) {
11566 semerr(gettext("No parent levels.\n"));
11567 } else {
11568 cur_elt = elt;
11569 cur_level = elt->sl;
11570 }
11571 } else if (cur_inst != NULL) {
11572 scf_instance_destroy(cur_inst);
11573 cur_inst = NULL;
11574 } else if (cur_svc != NULL) {
11575 scf_service_destroy(cur_svc);
11576 cur_svc = NULL;
11577 } else {
11578 semerr(gettext("Cannot unselect at scope level.\n"));
11579 }
11580 }
11581
11582 /*
11583 * Return the FMRI of the current selection, for the prompt.
11584 */
11585 void
lscf_get_selection_str(char * buf,size_t bufsz)11586 lscf_get_selection_str(char *buf, size_t bufsz)
11587 {
11588 char *cp;
11589 ssize_t fmrilen, szret;
11590 boolean_t deleted = B_FALSE;
11591
11592 if (g_hndl == NULL) {
11593 (void) strlcpy(buf, "svc:", bufsz);
11594 return;
11595 }
11596
11597 if (cur_level != NULL) {
11598 assert(cur_snap != NULL);
11599
11600 /* [ snapshot ] FMRI [: instance ] */
11601 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11602 + 2 + max_scf_name_len + 1 + 1);
11603
11604 buf[0] = '[';
11605
11606 szret = scf_snapshot_get_name(cur_snap, buf + 1,
11607 max_scf_name_len + 1);
11608 if (szret < 0) {
11609 if (scf_error() != SCF_ERROR_DELETED)
11610 scfdie();
11611
11612 goto snap_deleted;
11613 }
11614
11615 (void) strcat(buf, "]svc:/");
11616
11617 cp = strchr(buf, '\0');
11618
11619 szret = scf_snaplevel_get_service_name(cur_level, cp,
11620 max_scf_name_len + 1);
11621 if (szret < 0) {
11622 if (scf_error() != SCF_ERROR_DELETED)
11623 scfdie();
11624
11625 goto snap_deleted;
11626 }
11627
11628 cp = strchr(cp, '\0');
11629
11630 if (snaplevel_is_instance(cur_level)) {
11631 *cp++ = ':';
11632
11633 if (scf_snaplevel_get_instance_name(cur_level, cp,
11634 max_scf_name_len + 1) < 0) {
11635 if (scf_error() != SCF_ERROR_DELETED)
11636 scfdie();
11637
11638 goto snap_deleted;
11639 }
11640 } else {
11641 *cp++ = '[';
11642 *cp++ = ':';
11643
11644 if (scf_instance_get_name(cur_inst, cp,
11645 max_scf_name_len + 1) < 0) {
11646 if (scf_error() != SCF_ERROR_DELETED)
11647 scfdie();
11648
11649 goto snap_deleted;
11650 }
11651
11652 (void) strcat(buf, "]");
11653 }
11654
11655 return;
11656
11657 snap_deleted:
11658 deleted = B_TRUE;
11659 free(buf);
11660 unselect_cursnap();
11661 }
11662
11663 assert(cur_snap == NULL);
11664
11665 if (cur_inst != NULL) {
11666 assert(cur_svc != NULL);
11667 assert(cur_scope != NULL);
11668
11669 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11670 if (fmrilen >= 0) {
11671 assert(fmrilen < bufsz);
11672 if (deleted)
11673 warn(emsg_deleted);
11674 return;
11675 }
11676
11677 if (scf_error() != SCF_ERROR_DELETED)
11678 scfdie();
11679
11680 deleted = B_TRUE;
11681
11682 scf_instance_destroy(cur_inst);
11683 cur_inst = NULL;
11684 }
11685
11686 if (cur_svc != NULL) {
11687 assert(cur_scope != NULL);
11688
11689 szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11690 if (szret >= 0) {
11691 assert(szret < bufsz);
11692 if (deleted)
11693 warn(emsg_deleted);
11694 return;
11695 }
11696
11697 if (scf_error() != SCF_ERROR_DELETED)
11698 scfdie();
11699
11700 deleted = B_TRUE;
11701 scf_service_destroy(cur_svc);
11702 cur_svc = NULL;
11703 }
11704
11705 assert(cur_scope != NULL);
11706 fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11707
11708 if (fmrilen < 0)
11709 scfdie();
11710
11711 assert(fmrilen < bufsz);
11712 if (deleted)
11713 warn(emsg_deleted);
11714 }
11715
11716 /*
11717 * Entity listing. Entities and colon namespaces (e.g., :properties and
11718 * :statistics) are listed for the current selection.
11719 */
11720 void
lscf_list(const char * pattern)11721 lscf_list(const char *pattern)
11722 {
11723 scf_iter_t *iter;
11724 char *buf;
11725 int ret;
11726
11727 lscf_prep_hndl();
11728
11729 if (cur_level != NULL) {
11730 struct snaplevel *elt;
11731
11732 (void) fputs(COLON_NAMESPACES, stdout);
11733
11734 elt = uu_list_next(cur_levels, cur_elt);
11735 if (elt == NULL)
11736 return;
11737
11738 /*
11739 * For now, we know that the next level is an instance. But
11740 * if we ever have multiple scopes, this could be complicated.
11741 */
11742 buf = safe_malloc(max_scf_name_len + 1);
11743 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11744 max_scf_name_len + 1) >= 0) {
11745 (void) puts(buf);
11746 } else {
11747 if (scf_error() != SCF_ERROR_DELETED)
11748 scfdie();
11749 }
11750
11751 free(buf);
11752
11753 return;
11754 }
11755
11756 if (cur_inst != NULL) {
11757 (void) fputs(COLON_NAMESPACES, stdout);
11758 return;
11759 }
11760
11761 iter = scf_iter_create(g_hndl);
11762 if (iter == NULL)
11763 scfdie();
11764
11765 buf = safe_malloc(max_scf_name_len + 1);
11766
11767 if (cur_svc != NULL) {
11768 /* List the instances in this service. */
11769 scf_instance_t *inst;
11770
11771 inst = scf_instance_create(g_hndl);
11772 if (inst == NULL)
11773 scfdie();
11774
11775 if (scf_iter_service_instances(iter, cur_svc) == 0) {
11776 safe_printf(COLON_NAMESPACES);
11777
11778 for (;;) {
11779 ret = scf_iter_next_instance(iter, inst);
11780 if (ret == 0)
11781 break;
11782 if (ret != 1) {
11783 if (scf_error() != SCF_ERROR_DELETED)
11784 scfdie();
11785
11786 break;
11787 }
11788
11789 if (scf_instance_get_name(inst, buf,
11790 max_scf_name_len + 1) >= 0) {
11791 if (pattern == NULL ||
11792 fnmatch(pattern, buf, 0) == 0)
11793 (void) puts(buf);
11794 } else {
11795 if (scf_error() != SCF_ERROR_DELETED)
11796 scfdie();
11797 }
11798 }
11799 } else {
11800 if (scf_error() != SCF_ERROR_DELETED)
11801 scfdie();
11802 }
11803
11804 scf_instance_destroy(inst);
11805 } else {
11806 /* List the services in this scope. */
11807 scf_service_t *svc;
11808
11809 assert(cur_scope != NULL);
11810
11811 svc = scf_service_create(g_hndl);
11812 if (svc == NULL)
11813 scfdie();
11814
11815 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11816 scfdie();
11817
11818 for (;;) {
11819 ret = scf_iter_next_service(iter, svc);
11820 if (ret == 0)
11821 break;
11822 if (ret != 1)
11823 scfdie();
11824
11825 if (scf_service_get_name(svc, buf,
11826 max_scf_name_len + 1) >= 0) {
11827 if (pattern == NULL ||
11828 fnmatch(pattern, buf, 0) == 0)
11829 safe_printf("%s\n", buf);
11830 } else {
11831 if (scf_error() != SCF_ERROR_DELETED)
11832 scfdie();
11833 }
11834 }
11835
11836 scf_service_destroy(svc);
11837 }
11838
11839 free(buf);
11840 scf_iter_destroy(iter);
11841 }
11842
11843 /*
11844 * Entity addition. Creates an empty entity in the current selection.
11845 */
11846 void
lscf_add(const char * name)11847 lscf_add(const char *name)
11848 {
11849 lscf_prep_hndl();
11850
11851 if (cur_snap != NULL) {
11852 semerr(emsg_cant_modify_snapshots);
11853 } else if (cur_inst != NULL) {
11854 semerr(gettext("Cannot add entities to an instance.\n"));
11855 } else if (cur_svc != NULL) {
11856
11857 if (scf_service_add_instance(cur_svc, name, NULL) !=
11858 SCF_SUCCESS) {
11859 switch (scf_error()) {
11860 case SCF_ERROR_INVALID_ARGUMENT:
11861 semerr(gettext("Invalid name.\n"));
11862 break;
11863
11864 case SCF_ERROR_EXISTS:
11865 semerr(gettext("Instance already exists.\n"));
11866 break;
11867
11868 case SCF_ERROR_PERMISSION_DENIED:
11869 semerr(emsg_permission_denied);
11870 break;
11871
11872 default:
11873 scfdie();
11874 }
11875 }
11876 } else {
11877 assert(cur_scope != NULL);
11878
11879 if (scf_scope_add_service(cur_scope, name, NULL) !=
11880 SCF_SUCCESS) {
11881 switch (scf_error()) {
11882 case SCF_ERROR_INVALID_ARGUMENT:
11883 semerr(gettext("Invalid name.\n"));
11884 break;
11885
11886 case SCF_ERROR_EXISTS:
11887 semerr(gettext("Service already exists.\n"));
11888 break;
11889
11890 case SCF_ERROR_PERMISSION_DENIED:
11891 semerr(emsg_permission_denied);
11892 break;
11893
11894 case SCF_ERROR_BACKEND_READONLY:
11895 semerr(emsg_read_only);
11896 break;
11897
11898 default:
11899 scfdie();
11900 }
11901 }
11902 }
11903 }
11904
11905 /* return 1 if the entity has no persistent pgs, else return 0 */
11906 static int
entity_has_no_pgs(void * ent,int isservice)11907 entity_has_no_pgs(void *ent, int isservice)
11908 {
11909 scf_iter_t *iter = NULL;
11910 scf_propertygroup_t *pg = NULL;
11911 uint32_t flags;
11912 int err;
11913 int ret = 1;
11914
11915 if ((iter = scf_iter_create(g_hndl)) == NULL ||
11916 (pg = scf_pg_create(g_hndl)) == NULL)
11917 scfdie();
11918
11919 if (isservice) {
11920 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11921 scfdie();
11922 } else {
11923 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11924 scfdie();
11925 }
11926
11927 while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11928 if (scf_pg_get_flags(pg, &flags) != 0)
11929 scfdie();
11930
11931 /* skip nonpersistent pgs */
11932 if (flags & SCF_PG_FLAG_NONPERSISTENT)
11933 continue;
11934
11935 ret = 0;
11936 break;
11937 }
11938
11939 if (err == -1)
11940 scfdie();
11941
11942 scf_pg_destroy(pg);
11943 scf_iter_destroy(iter);
11944
11945 return (ret);
11946 }
11947
11948 /* return 1 if the service has no instances, else return 0 */
11949 static int
svc_has_no_insts(scf_service_t * svc)11950 svc_has_no_insts(scf_service_t *svc)
11951 {
11952 scf_instance_t *inst;
11953 scf_iter_t *iter;
11954 int r;
11955 int ret = 1;
11956
11957 if ((inst = scf_instance_create(g_hndl)) == NULL ||
11958 (iter = scf_iter_create(g_hndl)) == NULL)
11959 scfdie();
11960
11961 if (scf_iter_service_instances(iter, svc) != 0)
11962 scfdie();
11963
11964 r = scf_iter_next_instance(iter, inst);
11965 if (r == 1) {
11966 ret = 0;
11967 } else if (r == 0) {
11968 ret = 1;
11969 } else if (r == -1) {
11970 scfdie();
11971 } else {
11972 bad_error("scf_iter_next_instance", r);
11973 }
11974
11975 scf_iter_destroy(iter);
11976 scf_instance_destroy(inst);
11977
11978 return (ret);
11979 }
11980
11981 /*
11982 * Entity deletion.
11983 */
11984
11985 /*
11986 * Delete the property group <fmri>/:properties/<name>. Returns
11987 * SCF_ERROR_NONE on success (or if the entity is not found),
11988 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
11989 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
11990 * denied.
11991 */
11992 static scf_error_t
delete_dependency_pg(const char * fmri,const char * name)11993 delete_dependency_pg(const char *fmri, const char *name)
11994 {
11995 void *entity = NULL;
11996 int isservice;
11997 scf_propertygroup_t *pg = NULL;
11998 scf_error_t result;
11999 char *pgty;
12000 scf_service_t *svc = NULL;
12001 scf_instance_t *inst = NULL;
12002 scf_iter_t *iter = NULL;
12003 char *name_buf = NULL;
12004
12005 result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
12006 switch (result) {
12007 case SCF_ERROR_NONE:
12008 break;
12009
12010 case SCF_ERROR_NO_MEMORY:
12011 uu_die(gettext("Out of memory.\n"));
12012 /* NOTREACHED */
12013
12014 case SCF_ERROR_INVALID_ARGUMENT:
12015 case SCF_ERROR_CONSTRAINT_VIOLATED:
12016 return (SCF_ERROR_INVALID_ARGUMENT);
12017
12018 case SCF_ERROR_NOT_FOUND:
12019 result = SCF_ERROR_NONE;
12020 goto out;
12021
12022 default:
12023 bad_error("fmri_to_entity", result);
12024 }
12025
12026 pg = scf_pg_create(g_hndl);
12027 if (pg == NULL)
12028 scfdie();
12029
12030 if (entity_get_pg(entity, isservice, name, pg) != 0) {
12031 if (scf_error() != SCF_ERROR_NOT_FOUND)
12032 scfdie();
12033
12034 result = SCF_ERROR_NONE;
12035 goto out;
12036 }
12037
12038 pgty = safe_malloc(max_scf_pg_type_len + 1);
12039
12040 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12041 scfdie();
12042
12043 if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
12044 result = SCF_ERROR_TYPE_MISMATCH;
12045 free(pgty);
12046 goto out;
12047 }
12048
12049 free(pgty);
12050
12051 if (scf_pg_delete(pg) != 0) {
12052 result = scf_error();
12053 if (result != SCF_ERROR_PERMISSION_DENIED)
12054 scfdie();
12055 goto out;
12056 }
12057
12058 /*
12059 * We have to handle the case where we've just deleted the last
12060 * property group of a "dummy" entity (instance or service).
12061 * A "dummy" entity is an entity only present to hold an
12062 * external dependency.
12063 * So, in the case we deleted the last property group then we
12064 * can also delete the entity. If the entity is an instance then
12065 * we must verify if this was the last instance for the service
12066 * and if it is, we can also delete the service if it doesn't
12067 * have any property group either.
12068 */
12069
12070 result = SCF_ERROR_NONE;
12071
12072 if (isservice) {
12073 svc = (scf_service_t *)entity;
12074
12075 if ((inst = scf_instance_create(g_hndl)) == NULL ||
12076 (iter = scf_iter_create(g_hndl)) == NULL)
12077 scfdie();
12078
12079 name_buf = safe_malloc(max_scf_name_len + 1);
12080 } else {
12081 inst = (scf_instance_t *)entity;
12082 }
12083
12084 /*
12085 * If the entity is an instance and we've just deleted its last
12086 * property group then we should delete it.
12087 */
12088 if (!isservice && entity_has_no_pgs(entity, isservice)) {
12089 /* find the service before deleting the inst. - needed later */
12090 if ((svc = scf_service_create(g_hndl)) == NULL)
12091 scfdie();
12092
12093 if (scf_instance_get_parent(inst, svc) != 0)
12094 scfdie();
12095
12096 /* delete the instance */
12097 if (scf_instance_delete(inst) != 0) {
12098 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12099 scfdie();
12100
12101 result = SCF_ERROR_PERMISSION_DENIED;
12102 goto out;
12103 }
12104 /* no need to refresh the instance */
12105 inst = NULL;
12106 }
12107
12108 /*
12109 * If the service has no more instances and pgs or we just deleted the
12110 * last instance and the service doesn't have anymore propery groups
12111 * then the service should be deleted.
12112 */
12113 if (svc != NULL &&
12114 svc_has_no_insts(svc) &&
12115 entity_has_no_pgs((void *)svc, 1)) {
12116 if (scf_service_delete(svc) == 0) {
12117 if (isservice) {
12118 /* no need to refresh the service */
12119 svc = NULL;
12120 }
12121
12122 goto out;
12123 }
12124
12125 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12126 scfdie();
12127
12128 result = SCF_ERROR_PERMISSION_DENIED;
12129 }
12130
12131 /* if the entity has not been deleted, refresh it */
12132 if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
12133 (void) refresh_entity(isservice, entity, fmri, inst, iter,
12134 name_buf);
12135 }
12136
12137 out:
12138 if (isservice && (inst != NULL && iter != NULL)) {
12139 free(name_buf);
12140 scf_iter_destroy(iter);
12141 scf_instance_destroy(inst);
12142 }
12143
12144 if (!isservice && svc != NULL) {
12145 scf_service_destroy(svc);
12146 }
12147
12148 scf_pg_destroy(pg);
12149 if (entity != NULL)
12150 entity_destroy(entity, isservice);
12151
12152 return (result);
12153 }
12154
12155 static int
delete_dependents(scf_propertygroup_t * pg)12156 delete_dependents(scf_propertygroup_t *pg)
12157 {
12158 char *pgty, *name, *fmri;
12159 scf_property_t *prop;
12160 scf_value_t *val;
12161 scf_iter_t *iter;
12162 int r;
12163 scf_error_t err;
12164
12165 /* Verify that the pg has the correct type. */
12166 pgty = safe_malloc(max_scf_pg_type_len + 1);
12167 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12168 scfdie();
12169
12170 if (strcmp(pgty, scf_group_framework) != 0) {
12171 if (g_verbose) {
12172 fmri = safe_malloc(max_scf_fmri_len + 1);
12173 if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
12174 scfdie();
12175
12176 warn(gettext("Property group %s is not of expected "
12177 "type %s.\n"), fmri, scf_group_framework);
12178
12179 free(fmri);
12180 }
12181
12182 free(pgty);
12183 return (-1);
12184 }
12185
12186 free(pgty);
12187
12188 /* map delete_dependency_pg onto the properties. */
12189 if ((prop = scf_property_create(g_hndl)) == NULL ||
12190 (val = scf_value_create(g_hndl)) == NULL ||
12191 (iter = scf_iter_create(g_hndl)) == NULL)
12192 scfdie();
12193
12194 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
12195 scfdie();
12196
12197 name = safe_malloc(max_scf_name_len + 1);
12198 fmri = safe_malloc(max_scf_fmri_len + 2);
12199
12200 while ((r = scf_iter_next_property(iter, prop)) == 1) {
12201 scf_type_t ty;
12202
12203 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
12204 scfdie();
12205
12206 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
12207 scfdie();
12208
12209 if ((ty != SCF_TYPE_ASTRING &&
12210 prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
12211 prop_get_val(prop, val) != 0)
12212 continue;
12213
12214 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
12215 scfdie();
12216
12217 err = delete_dependency_pg(fmri, name);
12218 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
12219 if (scf_property_to_fmri(prop, fmri,
12220 max_scf_fmri_len + 2) < 0)
12221 scfdie();
12222
12223 warn(gettext("Value of %s is not a valid FMRI.\n"),
12224 fmri);
12225 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
12226 warn(gettext("Property group \"%s\" of entity \"%s\" "
12227 "does not have dependency type.\n"), name, fmri);
12228 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
12229 warn(gettext("Could not delete property group \"%s\" "
12230 "of entity \"%s\" (permission denied).\n"), name,
12231 fmri);
12232 }
12233 }
12234 if (r == -1)
12235 scfdie();
12236
12237 scf_value_destroy(val);
12238 scf_property_destroy(prop);
12239
12240 return (0);
12241 }
12242
12243 /*
12244 * Returns 1 if the instance may be running, and 0 otherwise.
12245 */
12246 static int
inst_is_running(scf_instance_t * inst)12247 inst_is_running(scf_instance_t *inst)
12248 {
12249 scf_propertygroup_t *pg;
12250 scf_property_t *prop;
12251 scf_value_t *val;
12252 char buf[MAX_SCF_STATE_STRING_SZ];
12253 int ret = 0;
12254 ssize_t szret;
12255
12256 if ((pg = scf_pg_create(g_hndl)) == NULL ||
12257 (prop = scf_property_create(g_hndl)) == NULL ||
12258 (val = scf_value_create(g_hndl)) == NULL)
12259 scfdie();
12260
12261 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
12262 if (scf_error() != SCF_ERROR_NOT_FOUND)
12263 scfdie();
12264 goto out;
12265 }
12266
12267 if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
12268 prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
12269 prop_get_val(prop, val) != 0)
12270 goto out;
12271
12272 szret = scf_value_get_astring(val, buf, sizeof (buf));
12273 assert(szret >= 0);
12274
12275 ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
12276 strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
12277
12278 out:
12279 scf_value_destroy(val);
12280 scf_property_destroy(prop);
12281 scf_pg_destroy(pg);
12282 return (ret);
12283 }
12284
12285 static uint8_t
pg_is_external_dependency(scf_propertygroup_t * pg)12286 pg_is_external_dependency(scf_propertygroup_t *pg)
12287 {
12288 char *type;
12289 scf_value_t *val;
12290 scf_property_t *prop;
12291 uint8_t b = B_FALSE;
12292
12293 type = safe_malloc(max_scf_pg_type_len + 1);
12294
12295 if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
12296 scfdie();
12297
12298 if ((prop = scf_property_create(g_hndl)) == NULL ||
12299 (val = scf_value_create(g_hndl)) == NULL)
12300 scfdie();
12301
12302 if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
12303 if (pg_get_prop(pg, scf_property_external, prop) == 0) {
12304 if (scf_property_get_value(prop, val) != 0)
12305 scfdie();
12306 if (scf_value_get_boolean(val, &b) != 0)
12307 scfdie();
12308 }
12309 }
12310
12311 free(type);
12312 (void) scf_value_destroy(val);
12313 (void) scf_property_destroy(prop);
12314
12315 return (b);
12316 }
12317
12318 #define DELETE_FAILURE -1
12319 #define DELETE_SUCCESS_NOEXTDEPS 0
12320 #define DELETE_SUCCESS_EXTDEPS 1
12321
12322 /*
12323 * lscf_instance_delete() deletes an instance. Before calling
12324 * scf_instance_delete(), though, we make sure the instance isn't
12325 * running and delete dependencies in other entities which the instance
12326 * declared as "dependents". If there are dependencies which were
12327 * created for other entities, then instead of deleting the instance we
12328 * make it "empty" by deleting all other property groups and all
12329 * snapshots.
12330 *
12331 * lscf_instance_delete() verifies that there is no external dependency pgs
12332 * before suppressing the instance. If there is, then we must not remove them
12333 * now in case the instance is re-created otherwise the dependencies would be
12334 * lost. The external dependency pgs will be removed if the dependencies are
12335 * removed.
12336 *
12337 * Returns:
12338 * DELETE_FAILURE on failure
12339 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12340 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12341 */
12342 static int
lscf_instance_delete(scf_instance_t * inst,int force)12343 lscf_instance_delete(scf_instance_t *inst, int force)
12344 {
12345 scf_propertygroup_t *pg;
12346 scf_snapshot_t *snap;
12347 scf_iter_t *iter;
12348 int err;
12349 int external = 0;
12350
12351 /* If we're not forcing and the instance is running, refuse. */
12352 if (!force && inst_is_running(inst)) {
12353 char *fmri;
12354
12355 fmri = safe_malloc(max_scf_fmri_len + 1);
12356
12357 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
12358 scfdie();
12359
12360 semerr(gettext("Instance %s may be running. "
12361 "Use delete -f if it is not.\n"), fmri);
12362
12363 free(fmri);
12364 return (DELETE_FAILURE);
12365 }
12366
12367 pg = scf_pg_create(g_hndl);
12368 if (pg == NULL)
12369 scfdie();
12370
12371 if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
12372 (void) delete_dependents(pg);
12373 else if (scf_error() != SCF_ERROR_NOT_FOUND)
12374 scfdie();
12375
12376 scf_pg_destroy(pg);
12377
12378 /*
12379 * If the instance has some external dependencies then we must
12380 * keep them in case the instance is reimported otherwise the
12381 * dependencies would be lost on reimport.
12382 */
12383 if ((iter = scf_iter_create(g_hndl)) == NULL ||
12384 (pg = scf_pg_create(g_hndl)) == NULL)
12385 scfdie();
12386
12387 if (scf_iter_instance_pgs(iter, inst) < 0)
12388 scfdie();
12389
12390 while ((err = scf_iter_next_pg(iter, pg)) == 1) {
12391 if (pg_is_external_dependency(pg)) {
12392 external = 1;
12393 continue;
12394 }
12395
12396 if (scf_pg_delete(pg) != 0) {
12397 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12398 scfdie();
12399 else {
12400 semerr(emsg_permission_denied);
12401
12402 (void) scf_iter_destroy(iter);
12403 (void) scf_pg_destroy(pg);
12404 return (DELETE_FAILURE);
12405 }
12406 }
12407 }
12408
12409 if (err == -1)
12410 scfdie();
12411
12412 (void) scf_iter_destroy(iter);
12413 (void) scf_pg_destroy(pg);
12414
12415 if (external) {
12416 /*
12417 * All the pgs have been deleted for the instance except
12418 * the ones holding the external dependencies.
12419 * For the job to be complete, we must also delete the
12420 * snapshots associated with the instance.
12421 */
12422 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
12423 NULL)
12424 scfdie();
12425 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
12426 scfdie();
12427
12428 if (scf_iter_instance_snapshots(iter, inst) == -1)
12429 scfdie();
12430
12431 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
12432 if (_scf_snapshot_delete(snap) != 0) {
12433 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12434 scfdie();
12435
12436 semerr(emsg_permission_denied);
12437
12438 (void) scf_iter_destroy(iter);
12439 (void) scf_snapshot_destroy(snap);
12440 return (DELETE_FAILURE);
12441 }
12442 }
12443
12444 if (err == -1)
12445 scfdie();
12446
12447 (void) scf_iter_destroy(iter);
12448 (void) scf_snapshot_destroy(snap);
12449 return (DELETE_SUCCESS_EXTDEPS);
12450 }
12451
12452 if (scf_instance_delete(inst) != 0) {
12453 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12454 scfdie();
12455
12456 semerr(emsg_permission_denied);
12457
12458 return (DELETE_FAILURE);
12459 }
12460
12461 return (DELETE_SUCCESS_NOEXTDEPS);
12462 }
12463
12464 /*
12465 * lscf_service_delete() deletes a service. Before calling
12466 * scf_service_delete(), though, we call lscf_instance_delete() for
12467 * each of the instances and delete dependencies in other entities
12468 * which were created as "dependents" of this service. If there are
12469 * dependencies which were created for other entities, then we delete
12470 * all other property groups in the service and leave it as "empty".
12471 *
12472 * lscf_service_delete() verifies that there is no external dependency
12473 * pgs at the instance & service level before suppressing the service.
12474 * If there is, then we must not remove them now in case the service
12475 * is re-imported otherwise the dependencies would be lost. The external
12476 * dependency pgs will be removed if the dependencies are removed.
12477 *
12478 * Returns:
12479 * DELETE_FAILURE on failure
12480 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12481 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12482 */
12483 static int
lscf_service_delete(scf_service_t * svc,int force)12484 lscf_service_delete(scf_service_t *svc, int force)
12485 {
12486 int r;
12487 scf_instance_t *inst;
12488 scf_propertygroup_t *pg;
12489 scf_iter_t *iter;
12490 int ret;
12491 int external = 0;
12492
12493 if ((inst = scf_instance_create(g_hndl)) == NULL ||
12494 (pg = scf_pg_create(g_hndl)) == NULL ||
12495 (iter = scf_iter_create(g_hndl)) == NULL)
12496 scfdie();
12497
12498 if (scf_iter_service_instances(iter, svc) != 0)
12499 scfdie();
12500
12501 for (r = scf_iter_next_instance(iter, inst);
12502 r == 1;
12503 r = scf_iter_next_instance(iter, inst)) {
12504
12505 ret = lscf_instance_delete(inst, force);
12506 if (ret == DELETE_FAILURE) {
12507 scf_iter_destroy(iter);
12508 scf_pg_destroy(pg);
12509 scf_instance_destroy(inst);
12510 return (DELETE_FAILURE);
12511 }
12512
12513 /*
12514 * Record the fact that there is some external dependencies
12515 * at the instance level.
12516 */
12517 if (ret == DELETE_SUCCESS_EXTDEPS)
12518 external |= 1;
12519 }
12520
12521 if (r != 0)
12522 scfdie();
12523
12524 /* Delete dependency property groups in dependent services. */
12525 if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12526 (void) delete_dependents(pg);
12527 else if (scf_error() != SCF_ERROR_NOT_FOUND)
12528 scfdie();
12529
12530 scf_iter_destroy(iter);
12531 scf_pg_destroy(pg);
12532 scf_instance_destroy(inst);
12533
12534 /*
12535 * If the service has some external dependencies then we don't
12536 * want to remove them in case the service is re-imported.
12537 */
12538 if ((pg = scf_pg_create(g_hndl)) == NULL ||
12539 (iter = scf_iter_create(g_hndl)) == NULL)
12540 scfdie();
12541
12542 if (scf_iter_service_pgs(iter, svc) < 0)
12543 scfdie();
12544
12545 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12546 if (pg_is_external_dependency(pg)) {
12547 external |= 2;
12548 continue;
12549 }
12550
12551 if (scf_pg_delete(pg) != 0) {
12552 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12553 scfdie();
12554 else {
12555 semerr(emsg_permission_denied);
12556
12557 (void) scf_iter_destroy(iter);
12558 (void) scf_pg_destroy(pg);
12559 return (DELETE_FAILURE);
12560 }
12561 }
12562 }
12563
12564 if (r == -1)
12565 scfdie();
12566
12567 (void) scf_iter_destroy(iter);
12568 (void) scf_pg_destroy(pg);
12569
12570 if (external != 0)
12571 return (DELETE_SUCCESS_EXTDEPS);
12572
12573 if (scf_service_delete(svc) == 0)
12574 return (DELETE_SUCCESS_NOEXTDEPS);
12575
12576 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12577 scfdie();
12578
12579 semerr(emsg_permission_denied);
12580 return (DELETE_FAILURE);
12581 }
12582
12583 static int
delete_callback(void * data,scf_walkinfo_t * wip)12584 delete_callback(void *data, scf_walkinfo_t *wip)
12585 {
12586 int force = (int)data;
12587
12588 if (wip->inst != NULL)
12589 (void) lscf_instance_delete(wip->inst, force);
12590 else
12591 (void) lscf_service_delete(wip->svc, force);
12592
12593 return (0);
12594 }
12595
12596 void
lscf_delete(const char * fmri,int force)12597 lscf_delete(const char *fmri, int force)
12598 {
12599 scf_service_t *svc;
12600 scf_instance_t *inst;
12601 int ret;
12602
12603 lscf_prep_hndl();
12604
12605 if (cur_snap != NULL) {
12606 if (!snaplevel_is_instance(cur_level)) {
12607 char *buf;
12608
12609 buf = safe_malloc(max_scf_name_len + 1);
12610 if (scf_instance_get_name(cur_inst, buf,
12611 max_scf_name_len + 1) >= 0) {
12612 if (strcmp(buf, fmri) == 0) {
12613 semerr(emsg_cant_modify_snapshots);
12614 free(buf);
12615 return;
12616 }
12617 } else if (scf_error() != SCF_ERROR_DELETED) {
12618 scfdie();
12619 }
12620 free(buf);
12621 }
12622 } else if (cur_inst != NULL) {
12623 /* EMPTY */;
12624 } else if (cur_svc != NULL) {
12625 inst = scf_instance_create(g_hndl);
12626 if (inst == NULL)
12627 scfdie();
12628
12629 if (scf_service_get_instance(cur_svc, fmri, inst) ==
12630 SCF_SUCCESS) {
12631 (void) lscf_instance_delete(inst, force);
12632 scf_instance_destroy(inst);
12633 return;
12634 }
12635
12636 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12637 scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12638 scfdie();
12639
12640 scf_instance_destroy(inst);
12641 } else {
12642 assert(cur_scope != NULL);
12643
12644 svc = scf_service_create(g_hndl);
12645 if (svc == NULL)
12646 scfdie();
12647
12648 if (scf_scope_get_service(cur_scope, fmri, svc) ==
12649 SCF_SUCCESS) {
12650 (void) lscf_service_delete(svc, force);
12651 scf_service_destroy(svc);
12652 return;
12653 }
12654
12655 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12656 scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12657 scfdie();
12658
12659 scf_service_destroy(svc);
12660 }
12661
12662 /*
12663 * Match FMRI to entity.
12664 */
12665 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12666 delete_callback, (void *)force, NULL, semerr)) != 0) {
12667 semerr(gettext("Failed to walk instances: %s\n"),
12668 scf_strerror(ret));
12669 }
12670 }
12671
12672
12673
12674 /*
12675 * :properties commands. These all end with "pg" or "prop" and generally
12676 * operate on the currently selected entity.
12677 */
12678
12679 /*
12680 * Property listing. List the property groups, properties, their types and
12681 * their values for the currently selected entity.
12682 */
12683 static void
list_pg_info(const scf_propertygroup_t * pg,const char * name,size_t namewidth)12684 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12685 {
12686 char *buf;
12687 uint32_t flags;
12688
12689 buf = safe_malloc(max_scf_pg_type_len + 1);
12690
12691 if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12692 scfdie();
12693
12694 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12695 scfdie();
12696
12697 safe_printf("%-*s %s", namewidth, name, buf);
12698
12699 if (flags & SCF_PG_FLAG_NONPERSISTENT)
12700 safe_printf("\tNONPERSISTENT");
12701
12702 safe_printf("\n");
12703
12704 free(buf);
12705 }
12706
12707 static boolean_t
prop_has_multiple_values(const scf_property_t * prop,scf_value_t * val)12708 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12709 {
12710 if (scf_property_get_value(prop, val) == 0) {
12711 return (B_FALSE);
12712 } else {
12713 switch (scf_error()) {
12714 case SCF_ERROR_NOT_FOUND:
12715 return (B_FALSE);
12716 case SCF_ERROR_PERMISSION_DENIED:
12717 case SCF_ERROR_CONSTRAINT_VIOLATED:
12718 return (B_TRUE);
12719 default:
12720 scfdie();
12721 /*NOTREACHED*/
12722 }
12723 }
12724 }
12725
12726 static void
list_prop_info(const scf_property_t * prop,const char * name,size_t len)12727 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12728 {
12729 scf_iter_t *iter;
12730 scf_value_t *val;
12731 const char *type;
12732 int multiple_strings = 0;
12733 int ret;
12734
12735 if ((iter = scf_iter_create(g_hndl)) == NULL ||
12736 (val = scf_value_create(g_hndl)) == NULL)
12737 scfdie();
12738
12739 type = prop_to_typestr(prop);
12740 assert(type != NULL);
12741
12742 safe_printf("%-*s %-7s ", len, name, type);
12743
12744 if (prop_has_multiple_values(prop, val) &&
12745 (scf_value_type(val) == SCF_TYPE_ASTRING ||
12746 scf_value_type(val) == SCF_TYPE_USTRING))
12747 multiple_strings = 1;
12748
12749 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12750 scfdie();
12751
12752 while ((ret = scf_iter_next_value(iter, val)) == 1) {
12753 char *buf;
12754 ssize_t vlen, szret;
12755
12756 vlen = scf_value_get_as_string(val, NULL, 0);
12757 if (vlen < 0)
12758 scfdie();
12759
12760 buf = safe_malloc(vlen + 1);
12761
12762 szret = scf_value_get_as_string(val, buf, vlen + 1);
12763 if (szret < 0)
12764 scfdie();
12765 assert(szret <= vlen);
12766
12767 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12768 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12769 safe_printf(" \"");
12770 (void) quote_and_print(buf, stdout, 0);
12771 (void) putchar('"');
12772 if (ferror(stdout)) {
12773 (void) putchar('\n');
12774 uu_die(gettext("Error writing to stdout.\n"));
12775 }
12776 } else {
12777 safe_printf(" %s", buf);
12778 }
12779
12780 free(buf);
12781 }
12782 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12783 scfdie();
12784
12785 if (putchar('\n') != '\n')
12786 uu_die(gettext("Could not output newline"));
12787 }
12788
12789 /*
12790 * Outputs template property group info for the describe subcommand.
12791 * If 'templates' == 2, verbose output is printed in the format expected
12792 * for describe -v, which includes all templates fields. If pg is
12793 * not NULL, we're describing the template data, not an existing property
12794 * group, and formatting should be appropriate for describe -t.
12795 */
12796 static void
list_pg_tmpl(scf_pg_tmpl_t * pgt,scf_propertygroup_t * pg,int templates)12797 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12798 {
12799 char *buf;
12800 uint8_t required;
12801 scf_property_t *stability_prop;
12802 scf_value_t *stability_val;
12803
12804 if (templates == 0)
12805 return;
12806
12807 if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12808 (stability_val = scf_value_create(g_hndl)) == NULL)
12809 scfdie();
12810
12811 if (templates == 2 && pg != NULL) {
12812 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12813 stability_prop) == 0) {
12814 if (prop_check_type(stability_prop,
12815 SCF_TYPE_ASTRING) == 0 &&
12816 prop_get_val(stability_prop, stability_val) == 0) {
12817 char *stability;
12818
12819 stability = safe_malloc(max_scf_value_len + 1);
12820
12821 if (scf_value_get_astring(stability_val,
12822 stability, max_scf_value_len + 1) == -1 &&
12823 scf_error() != SCF_ERROR_NOT_FOUND)
12824 scfdie();
12825
12826 safe_printf("%s%s: %s\n", TMPL_INDENT,
12827 gettext("stability"), stability);
12828
12829 free(stability);
12830 }
12831 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
12832 scfdie();
12833 }
12834
12835 scf_property_destroy(stability_prop);
12836 scf_value_destroy(stability_val);
12837
12838 if (pgt == NULL)
12839 return;
12840
12841 if (pg == NULL || templates == 2) {
12842 /* print type info only if scf_tmpl_pg_name succeeds */
12843 if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12844 if (pg != NULL)
12845 safe_printf("%s", TMPL_INDENT);
12846 safe_printf("%s: ", gettext("name"));
12847 safe_printf("%s\n", buf);
12848 free(buf);
12849 }
12850
12851 /* print type info only if scf_tmpl_pg_type succeeds */
12852 if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12853 if (pg != NULL)
12854 safe_printf("%s", TMPL_INDENT);
12855 safe_printf("%s: ", gettext("type"));
12856 safe_printf("%s\n", buf);
12857 free(buf);
12858 }
12859 }
12860
12861 if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12862 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12863 required ? "true" : "false");
12864
12865 if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12866 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12867 buf);
12868 free(buf);
12869 }
12870
12871 if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12872 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12873 buf);
12874 free(buf);
12875 }
12876
12877 if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12878 if (templates == 2)
12879 safe_printf("%s%s: %s\n", TMPL_INDENT,
12880 gettext("description"), buf);
12881 else
12882 safe_printf("%s%s\n", TMPL_INDENT, buf);
12883 free(buf);
12884 }
12885
12886 }
12887
12888 /*
12889 * With as_value set to true, indent as appropriate for the value level.
12890 * If false, indent to appropriate level for inclusion in constraint
12891 * or choice printout.
12892 */
12893 static void
print_template_value_details(scf_prop_tmpl_t * prt,const char * val_buf,int as_value)12894 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12895 int as_value)
12896 {
12897 char *buf;
12898
12899 if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12900 if (as_value == 0)
12901 safe_printf("%s", TMPL_CHOICE_INDENT);
12902 else
12903 safe_printf("%s", TMPL_INDENT);
12904 safe_printf("%s: %s\n", gettext("value common name"), buf);
12905 free(buf);
12906 }
12907
12908 if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12909 if (as_value == 0)
12910 safe_printf("%s", TMPL_CHOICE_INDENT);
12911 else
12912 safe_printf("%s", TMPL_INDENT);
12913 safe_printf("%s: %s\n", gettext("value description"), buf);
12914 free(buf);
12915 }
12916 }
12917
12918 static void
print_template_value(scf_prop_tmpl_t * prt,const char * val_buf)12919 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12920 {
12921 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12922 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12923 safe_printf("%s\n", val_buf);
12924
12925 print_template_value_details(prt, val_buf, 1);
12926 }
12927
12928 static void
print_template_constraints(scf_prop_tmpl_t * prt,int verbose)12929 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12930 {
12931 int i, printed = 0;
12932 scf_values_t values;
12933 scf_count_ranges_t c_ranges;
12934 scf_int_ranges_t i_ranges;
12935
12936 printed = 0;
12937 i = 0;
12938 if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12939 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12940 gettext("value constraints"));
12941 printed++;
12942 for (i = 0; i < values.value_count; ++i) {
12943 safe_printf("%s%s: %s\n", TMPL_INDENT,
12944 gettext("value name"), values.values_as_strings[i]);
12945 if (verbose == 1)
12946 print_template_value_details(prt,
12947 values.values_as_strings[i], 0);
12948 }
12949
12950 scf_values_destroy(&values);
12951 }
12952
12953 if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12954 if (printed++ == 0)
12955 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12956 gettext("value constraints"));
12957 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12958 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12959 gettext("range"), c_ranges.scr_min[i],
12960 c_ranges.scr_max[i]);
12961 }
12962 scf_count_ranges_destroy(&c_ranges);
12963 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12964 scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
12965 if (printed++ == 0)
12966 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12967 gettext("value constraints"));
12968 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12969 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12970 gettext("range"), i_ranges.sir_min[i],
12971 i_ranges.sir_max[i]);
12972 }
12973 scf_int_ranges_destroy(&i_ranges);
12974 }
12975 }
12976
12977 static void
print_template_choices(scf_prop_tmpl_t * prt,int verbose)12978 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
12979 {
12980 int i = 0, printed = 0;
12981 scf_values_t values;
12982 scf_count_ranges_t c_ranges;
12983 scf_int_ranges_t i_ranges;
12984
12985 printed = 0;
12986 if (scf_tmpl_value_name_choices(prt, &values) == 0) {
12987 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12988 gettext("value constraints"));
12989 printed++;
12990 for (i = 0; i < values.value_count; i++) {
12991 safe_printf("%s%s: %s\n", TMPL_INDENT,
12992 gettext("value name"), values.values_as_strings[i]);
12993 if (verbose == 1)
12994 print_template_value_details(prt,
12995 values.values_as_strings[i], 0);
12996 }
12997
12998 scf_values_destroy(&values);
12999 }
13000
13001 if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
13002 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
13003 if (printed++ == 0)
13004 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13005 gettext("value choices"));
13006 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
13007 gettext("range"), c_ranges.scr_min[i],
13008 c_ranges.scr_max[i]);
13009 }
13010 scf_count_ranges_destroy(&c_ranges);
13011 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
13012 scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
13013 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
13014 if (printed++ == 0)
13015 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13016 gettext("value choices"));
13017 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
13018 gettext("range"), i_ranges.sir_min[i],
13019 i_ranges.sir_max[i]);
13020 }
13021 scf_int_ranges_destroy(&i_ranges);
13022 }
13023 }
13024
13025 static void
list_values_by_template(scf_prop_tmpl_t * prt)13026 list_values_by_template(scf_prop_tmpl_t *prt)
13027 {
13028 print_template_constraints(prt, 1);
13029 print_template_choices(prt, 1);
13030 }
13031
13032 static void
list_values_tmpl(scf_prop_tmpl_t * prt,scf_property_t * prop)13033 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
13034 {
13035 char *val_buf;
13036 scf_iter_t *iter;
13037 scf_value_t *val;
13038 int ret;
13039
13040 if ((iter = scf_iter_create(g_hndl)) == NULL ||
13041 (val = scf_value_create(g_hndl)) == NULL)
13042 scfdie();
13043
13044 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
13045 scfdie();
13046
13047 val_buf = safe_malloc(max_scf_value_len + 1);
13048
13049 while ((ret = scf_iter_next_value(iter, val)) == 1) {
13050 if (scf_value_get_as_string(val, val_buf,
13051 max_scf_value_len + 1) < 0)
13052 scfdie();
13053
13054 print_template_value(prt, val_buf);
13055 }
13056 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
13057 scfdie();
13058 free(val_buf);
13059
13060 print_template_constraints(prt, 0);
13061 print_template_choices(prt, 0);
13062
13063 }
13064
13065 /*
13066 * Outputs property info for the describe subcommand
13067 * Verbose output if templates == 2, -v option of svccfg describe
13068 * Displays template data if prop is not NULL, -t option of svccfg describe
13069 */
13070 static void
list_prop_tmpl(scf_prop_tmpl_t * prt,scf_property_t * prop,int templates)13071 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
13072 {
13073 char *buf;
13074 uint8_t u_buf;
13075 int i;
13076 uint64_t min, max;
13077 scf_values_t values;
13078
13079 if (prt == NULL || templates == 0)
13080 return;
13081
13082 if (prop == NULL) {
13083 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
13084 if (scf_tmpl_prop_name(prt, &buf) > 0) {
13085 safe_printf("%s\n", buf);
13086 free(buf);
13087 } else
13088 safe_printf("(%s)\n", gettext("any"));
13089 }
13090
13091 if (prop == NULL || templates == 2) {
13092 if (prop != NULL)
13093 safe_printf("%s", TMPL_INDENT);
13094 else
13095 safe_printf("%s", TMPL_VALUE_INDENT);
13096 safe_printf("%s: ", gettext("type"));
13097 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
13098 safe_printf("%s\n", buf);
13099 free(buf);
13100 } else
13101 safe_printf("(%s)\n", gettext("any"));
13102 }
13103
13104 if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
13105 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
13106 u_buf ? "true" : "false");
13107
13108 if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
13109 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
13110 buf);
13111 free(buf);
13112 }
13113
13114 if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
13115 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
13116 buf);
13117 free(buf);
13118 }
13119
13120 if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
13121 safe_printf("%s%s\n", TMPL_INDENT, buf);
13122 free(buf);
13123 }
13124
13125 if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
13126 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
13127 scf_tmpl_visibility_to_string(u_buf));
13128
13129 if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
13130 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13131 gettext("minimum number of values"), min);
13132 if (max == ULLONG_MAX) {
13133 safe_printf("%s%s: %s\n", TMPL_INDENT,
13134 gettext("maximum number of values"),
13135 gettext("unlimited"));
13136 } else {
13137 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13138 gettext("maximum number of values"), max);
13139 }
13140 }
13141
13142 if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
13143 for (i = 0; i < values.value_count; i++) {
13144 if (i == 0) {
13145 safe_printf("%s%s:", TMPL_INDENT,
13146 gettext("internal separators"));
13147 }
13148 safe_printf(" \"%s\"", values.values_as_strings[i]);
13149 }
13150 safe_printf("\n");
13151 }
13152
13153 if (templates != 2)
13154 return;
13155
13156 if (prop != NULL)
13157 list_values_tmpl(prt, prop);
13158 else
13159 list_values_by_template(prt);
13160 }
13161
13162 static char *
read_astring(scf_propertygroup_t * pg,const char * prop_name)13163 read_astring(scf_propertygroup_t *pg, const char *prop_name)
13164 {
13165 char *rv;
13166
13167 rv = _scf_read_single_astring_from_pg(pg, prop_name);
13168 if (rv == NULL) {
13169 switch (scf_error()) {
13170 case SCF_ERROR_NOT_FOUND:
13171 break;
13172 default:
13173 scfdie();
13174 }
13175 }
13176 return (rv);
13177 }
13178
13179 static void
display_documentation(scf_iter_t * iter,scf_propertygroup_t * pg)13180 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
13181 {
13182 size_t doc_len;
13183 size_t man_len;
13184 char *pg_name;
13185 char *text = NULL;
13186 int rv;
13187
13188 doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
13189 man_len = strlen(SCF_PG_TM_MAN_PREFIX);
13190 pg_name = safe_malloc(max_scf_name_len + 1);
13191 while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
13192 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
13193 scfdie();
13194 }
13195 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
13196 /* Display doc_link and and uri */
13197 safe_printf("%s%s:\n", TMPL_INDENT,
13198 gettext("doc_link"));
13199 text = read_astring(pg, SCF_PROPERTY_TM_NAME);
13200 if (text != NULL) {
13201 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13202 TMPL_INDENT, gettext("name"), text);
13203 uu_free(text);
13204 }
13205 text = read_astring(pg, SCF_PROPERTY_TM_URI);
13206 if (text != NULL) {
13207 safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
13208 gettext("uri"), text);
13209 uu_free(text);
13210 }
13211 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
13212 man_len) == 0) {
13213 /* Display manpage title, section and path */
13214 safe_printf("%s%s:\n", TMPL_INDENT,
13215 gettext("manpage"));
13216 text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
13217 if (text != NULL) {
13218 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13219 TMPL_INDENT, gettext("title"), text);
13220 uu_free(text);
13221 }
13222 text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
13223 if (text != NULL) {
13224 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13225 TMPL_INDENT, gettext("section"), text);
13226 uu_free(text);
13227 }
13228 text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
13229 if (text != NULL) {
13230 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13231 TMPL_INDENT, gettext("manpath"), text);
13232 uu_free(text);
13233 }
13234 }
13235 }
13236 if (rv == -1)
13237 scfdie();
13238
13239 done:
13240 free(pg_name);
13241 }
13242
13243 static void
list_entity_tmpl(int templates)13244 list_entity_tmpl(int templates)
13245 {
13246 char *common_name = NULL;
13247 char *description = NULL;
13248 char *locale = NULL;
13249 scf_iter_t *iter;
13250 scf_propertygroup_t *pg;
13251 scf_property_t *prop;
13252 int r;
13253 scf_value_t *val;
13254
13255 if ((pg = scf_pg_create(g_hndl)) == NULL ||
13256 (prop = scf_property_create(g_hndl)) == NULL ||
13257 (val = scf_value_create(g_hndl)) == NULL ||
13258 (iter = scf_iter_create(g_hndl)) == NULL)
13259 scfdie();
13260
13261 locale = setlocale(LC_MESSAGES, NULL);
13262
13263 if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
13264 common_name = safe_malloc(max_scf_value_len + 1);
13265
13266 /* Try both the current locale and the "C" locale. */
13267 if (scf_pg_get_property(pg, locale, prop) == 0 ||
13268 (scf_error() == SCF_ERROR_NOT_FOUND &&
13269 scf_pg_get_property(pg, "C", prop) == 0)) {
13270 if (prop_get_val(prop, val) == 0 &&
13271 scf_value_get_ustring(val, common_name,
13272 max_scf_value_len + 1) != -1) {
13273 safe_printf("%s%s: %s\n", TMPL_INDENT,
13274 gettext("common name"), common_name);
13275 }
13276 }
13277 }
13278
13279 /*
13280 * Do description, manpages, and doc links if templates == 2.
13281 */
13282 if (templates == 2) {
13283 /* Get the description. */
13284 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
13285 description = safe_malloc(max_scf_value_len + 1);
13286
13287 /* Try both the current locale and the "C" locale. */
13288 if (scf_pg_get_property(pg, locale, prop) == 0 ||
13289 (scf_error() == SCF_ERROR_NOT_FOUND &&
13290 scf_pg_get_property(pg, "C", prop) == 0)) {
13291 if (prop_get_val(prop, val) == 0 &&
13292 scf_value_get_ustring(val, description,
13293 max_scf_value_len + 1) != -1) {
13294 safe_printf("%s%s: %s\n", TMPL_INDENT,
13295 gettext("description"),
13296 description);
13297 }
13298 }
13299 }
13300
13301 /* Process doc_link & manpage elements. */
13302 if (cur_level != NULL) {
13303 r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
13304 SCF_GROUP_TEMPLATE);
13305 } else if (cur_inst != NULL) {
13306 r = scf_iter_instance_pgs_typed(iter, cur_inst,
13307 SCF_GROUP_TEMPLATE);
13308 } else {
13309 r = scf_iter_service_pgs_typed(iter, cur_svc,
13310 SCF_GROUP_TEMPLATE);
13311 }
13312 if (r == 0) {
13313 display_documentation(iter, pg);
13314 }
13315 }
13316
13317 free(common_name);
13318 free(description);
13319 scf_pg_destroy(pg);
13320 scf_property_destroy(prop);
13321 scf_value_destroy(val);
13322 scf_iter_destroy(iter);
13323 }
13324
13325 static void
listtmpl(const char * pattern,int templates)13326 listtmpl(const char *pattern, int templates)
13327 {
13328 scf_pg_tmpl_t *pgt;
13329 scf_prop_tmpl_t *prt;
13330 char *snapbuf = NULL;
13331 char *fmribuf;
13332 char *pg_name = NULL, *prop_name = NULL;
13333 ssize_t prop_name_size;
13334 char *qual_prop_name;
13335 char *search_name;
13336 int listed = 0;
13337
13338 if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13339 (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
13340 scfdie();
13341
13342 fmribuf = safe_malloc(max_scf_name_len + 1);
13343 qual_prop_name = safe_malloc(max_scf_name_len + 1);
13344
13345 if (cur_snap != NULL) {
13346 snapbuf = safe_malloc(max_scf_name_len + 1);
13347 if (scf_snapshot_get_name(cur_snap, snapbuf,
13348 max_scf_name_len + 1) < 0)
13349 scfdie();
13350 }
13351
13352 if (cur_inst != NULL) {
13353 if (scf_instance_to_fmri(cur_inst, fmribuf,
13354 max_scf_name_len + 1) < 0)
13355 scfdie();
13356 } else if (cur_svc != NULL) {
13357 if (scf_service_to_fmri(cur_svc, fmribuf,
13358 max_scf_name_len + 1) < 0)
13359 scfdie();
13360 } else
13361 abort();
13362
13363 /* If pattern is specified, we want to list only those items. */
13364 while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) {
13365 listed = 0;
13366 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
13367 fnmatch(pattern, pg_name, 0) == 0)) {
13368 list_pg_tmpl(pgt, NULL, templates);
13369 listed++;
13370 }
13371
13372 scf_tmpl_prop_reset(prt);
13373
13374 while (scf_tmpl_iter_props(pgt, prt, 0) == 0) {
13375 search_name = NULL;
13376 prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
13377 if ((prop_name_size > 0) && (pg_name != NULL)) {
13378 if (snprintf(qual_prop_name,
13379 max_scf_name_len + 1, "%s/%s",
13380 pg_name, prop_name) >=
13381 max_scf_name_len + 1) {
13382 prop_name_size = -1;
13383 } else {
13384 search_name = qual_prop_name;
13385 }
13386 }
13387 if (listed > 0 || pattern == NULL ||
13388 (prop_name_size > 0 &&
13389 fnmatch(pattern, search_name,
13390 FNM_PATHNAME) == 0))
13391 list_prop_tmpl(prt, NULL, templates);
13392 if (prop_name != NULL) {
13393 free(prop_name);
13394 prop_name = NULL;
13395 }
13396 }
13397 if (pg_name != NULL) {
13398 free(pg_name);
13399 pg_name = NULL;
13400 }
13401 }
13402
13403 scf_tmpl_prop_destroy(prt);
13404 scf_tmpl_pg_destroy(pgt);
13405 free(snapbuf);
13406 free(fmribuf);
13407 free(qual_prop_name);
13408 }
13409
13410 static void
listprop(const char * pattern,int only_pgs,int templates)13411 listprop(const char *pattern, int only_pgs, int templates)
13412 {
13413 scf_propertygroup_t *pg;
13414 scf_property_t *prop;
13415 scf_iter_t *iter, *piter;
13416 char *pgnbuf, *prnbuf, *ppnbuf;
13417 scf_pg_tmpl_t *pgt, *pgtp;
13418 scf_prop_tmpl_t *prt;
13419
13420 void **objects;
13421 char **names;
13422 void **tmpls;
13423 int allocd, i;
13424
13425 int ret;
13426 ssize_t pgnlen, prnlen, szret;
13427 size_t max_len = 0;
13428
13429 if (cur_svc == NULL && cur_inst == NULL) {
13430 semerr(emsg_entity_not_selected);
13431 return;
13432 }
13433
13434 if ((pg = scf_pg_create(g_hndl)) == NULL ||
13435 (prop = scf_property_create(g_hndl)) == NULL ||
13436 (iter = scf_iter_create(g_hndl)) == NULL ||
13437 (piter = scf_iter_create(g_hndl)) == NULL ||
13438 (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13439 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
13440 scfdie();
13441
13442 prnbuf = safe_malloc(max_scf_name_len + 1);
13443
13444 if (cur_level != NULL)
13445 ret = scf_iter_snaplevel_pgs(iter, cur_level);
13446 else if (cur_inst != NULL)
13447 ret = scf_iter_instance_pgs(iter, cur_inst);
13448 else
13449 ret = scf_iter_service_pgs(iter, cur_svc);
13450 if (ret != 0) {
13451 return;
13452 }
13453
13454 /*
13455 * We want to only list items which match pattern, and we want the
13456 * second column to line up, so during the first pass we'll save
13457 * matching items, their names, and their templates in objects,
13458 * names, and tmpls, computing the maximum name length as we go,
13459 * and then we'll print them out.
13460 *
13461 * Note: We always keep an extra slot available so the array can be
13462 * NULL-terminated.
13463 */
13464 i = 0;
13465 allocd = 1;
13466 objects = safe_malloc(sizeof (*objects));
13467 names = safe_malloc(sizeof (*names));
13468 tmpls = safe_malloc(sizeof (*tmpls));
13469
13470 while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13471 int new_pg = 0;
13472 int print_props = 0;
13473 pgtp = NULL;
13474
13475 pgnlen = scf_pg_get_name(pg, NULL, 0);
13476 if (pgnlen < 0)
13477 scfdie();
13478
13479 pgnbuf = safe_malloc(pgnlen + 1);
13480
13481 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
13482 if (szret < 0)
13483 scfdie();
13484 assert(szret <= pgnlen);
13485
13486 if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) {
13487 if (scf_error() != SCF_ERROR_NOT_FOUND)
13488 scfdie();
13489 pgtp = NULL;
13490 } else {
13491 pgtp = pgt;
13492 }
13493
13494 if (pattern == NULL ||
13495 fnmatch(pattern, pgnbuf, 0) == 0) {
13496 if (i+1 >= allocd) {
13497 allocd *= 2;
13498 objects = realloc(objects,
13499 sizeof (*objects) * allocd);
13500 names =
13501 realloc(names, sizeof (*names) * allocd);
13502 tmpls = realloc(tmpls,
13503 sizeof (*tmpls) * allocd);
13504 if (objects == NULL || names == NULL ||
13505 tmpls == NULL)
13506 uu_die(gettext("Out of memory"));
13507 }
13508 objects[i] = pg;
13509 names[i] = pgnbuf;
13510
13511 if (pgtp == NULL)
13512 tmpls[i] = NULL;
13513 else
13514 tmpls[i] = pgt;
13515
13516 ++i;
13517
13518 if (pgnlen > max_len)
13519 max_len = pgnlen;
13520
13521 new_pg = 1;
13522 print_props = 1;
13523 }
13524
13525 if (only_pgs) {
13526 if (new_pg) {
13527 pg = scf_pg_create(g_hndl);
13528 if (pg == NULL)
13529 scfdie();
13530 pgt = scf_tmpl_pg_create(g_hndl);
13531 if (pgt == NULL)
13532 scfdie();
13533 } else
13534 free(pgnbuf);
13535
13536 continue;
13537 }
13538
13539 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13540 scfdie();
13541
13542 while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13543 prnlen = scf_property_get_name(prop, prnbuf,
13544 max_scf_name_len + 1);
13545 if (prnlen < 0)
13546 scfdie();
13547
13548 /* Will prepend the property group name and a slash. */
13549 prnlen += pgnlen + 1;
13550
13551 ppnbuf = safe_malloc(prnlen + 1);
13552
13553 if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13554 prnbuf) < 0)
13555 uu_die("snprintf");
13556
13557 if (pattern == NULL || print_props == 1 ||
13558 fnmatch(pattern, ppnbuf, 0) == 0) {
13559 if (i+1 >= allocd) {
13560 allocd *= 2;
13561 objects = realloc(objects,
13562 sizeof (*objects) * allocd);
13563 names = realloc(names,
13564 sizeof (*names) * allocd);
13565 tmpls = realloc(tmpls,
13566 sizeof (*tmpls) * allocd);
13567 if (objects == NULL || names == NULL ||
13568 tmpls == NULL)
13569 uu_die(gettext(
13570 "Out of memory"));
13571 }
13572
13573 objects[i] = prop;
13574 names[i] = ppnbuf;
13575
13576 if (pgtp != NULL) {
13577 if (scf_tmpl_get_by_prop(pgt, prnbuf,
13578 prt, 0) < 0) {
13579 if (scf_error() !=
13580 SCF_ERROR_NOT_FOUND)
13581 scfdie();
13582 tmpls[i] = NULL;
13583 } else {
13584 tmpls[i] = prt;
13585 }
13586 } else {
13587 tmpls[i] = NULL;
13588 }
13589
13590 ++i;
13591
13592 if (prnlen > max_len)
13593 max_len = prnlen;
13594
13595 prop = scf_property_create(g_hndl);
13596 prt = scf_tmpl_prop_create(g_hndl);
13597 } else {
13598 free(ppnbuf);
13599 }
13600 }
13601
13602 if (new_pg) {
13603 pg = scf_pg_create(g_hndl);
13604 if (pg == NULL)
13605 scfdie();
13606 pgt = scf_tmpl_pg_create(g_hndl);
13607 if (pgt == NULL)
13608 scfdie();
13609 } else
13610 free(pgnbuf);
13611 }
13612 if (ret != 0)
13613 scfdie();
13614
13615 objects[i] = NULL;
13616
13617 scf_pg_destroy(pg);
13618 scf_tmpl_pg_destroy(pgt);
13619 scf_property_destroy(prop);
13620 scf_tmpl_prop_destroy(prt);
13621
13622 for (i = 0; objects[i] != NULL; ++i) {
13623 if (strchr(names[i], '/') == NULL) {
13624 /* property group */
13625 pg = (scf_propertygroup_t *)objects[i];
13626 pgt = (scf_pg_tmpl_t *)tmpls[i];
13627 list_pg_info(pg, names[i], max_len);
13628 list_pg_tmpl(pgt, pg, templates);
13629 free(names[i]);
13630 scf_pg_destroy(pg);
13631 if (pgt != NULL)
13632 scf_tmpl_pg_destroy(pgt);
13633 } else {
13634 /* property */
13635 prop = (scf_property_t *)objects[i];
13636 prt = (scf_prop_tmpl_t *)tmpls[i];
13637 list_prop_info(prop, names[i], max_len);
13638 list_prop_tmpl(prt, prop, templates);
13639 free(names[i]);
13640 scf_property_destroy(prop);
13641 if (prt != NULL)
13642 scf_tmpl_prop_destroy(prt);
13643 }
13644 }
13645
13646 free(names);
13647 free(objects);
13648 free(tmpls);
13649 }
13650
13651 void
lscf_listpg(const char * pattern)13652 lscf_listpg(const char *pattern)
13653 {
13654 lscf_prep_hndl();
13655
13656 listprop(pattern, 1, 0);
13657 }
13658
13659 /*
13660 * Property group and property creation, setting, and deletion. setprop (and
13661 * its alias, addprop) can either create a property group of a given type, or
13662 * it can create or set a property to a given type and list of values.
13663 */
13664 void
lscf_addpg(const char * name,const char * type,const char * flags)13665 lscf_addpg(const char *name, const char *type, const char *flags)
13666 {
13667 scf_propertygroup_t *pg;
13668 int ret;
13669 uint32_t flgs = 0;
13670 const char *cp;
13671
13672
13673 lscf_prep_hndl();
13674
13675 if (cur_snap != NULL) {
13676 semerr(emsg_cant_modify_snapshots);
13677 return;
13678 }
13679
13680 if (cur_inst == NULL && cur_svc == NULL) {
13681 semerr(emsg_entity_not_selected);
13682 return;
13683 }
13684
13685 if (flags != NULL) {
13686 for (cp = flags; *cp != '\0'; ++cp) {
13687 switch (*cp) {
13688 case 'P':
13689 flgs |= SCF_PG_FLAG_NONPERSISTENT;
13690 break;
13691
13692 case 'p':
13693 flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13694 break;
13695
13696 default:
13697 semerr(gettext("Invalid property group flag "
13698 "%c."), *cp);
13699 return;
13700 }
13701 }
13702 }
13703
13704 pg = scf_pg_create(g_hndl);
13705 if (pg == NULL)
13706 scfdie();
13707
13708 if (cur_inst != NULL)
13709 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13710 else
13711 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13712
13713 if (ret != SCF_SUCCESS) {
13714 switch (scf_error()) {
13715 case SCF_ERROR_INVALID_ARGUMENT:
13716 semerr(gettext("Name, type, or flags are invalid.\n"));
13717 break;
13718
13719 case SCF_ERROR_EXISTS:
13720 semerr(gettext("Property group already exists.\n"));
13721 break;
13722
13723 case SCF_ERROR_PERMISSION_DENIED:
13724 semerr(emsg_permission_denied);
13725 break;
13726
13727 case SCF_ERROR_BACKEND_ACCESS:
13728 semerr(gettext("Backend refused access.\n"));
13729 break;
13730
13731 default:
13732 scfdie();
13733 }
13734 }
13735
13736 scf_pg_destroy(pg);
13737
13738 private_refresh();
13739 }
13740
13741 void
lscf_delpg(char * name)13742 lscf_delpg(char *name)
13743 {
13744 lscf_prep_hndl();
13745
13746 if (cur_snap != NULL) {
13747 semerr(emsg_cant_modify_snapshots);
13748 return;
13749 }
13750
13751 if (cur_inst == NULL && cur_svc == NULL) {
13752 semerr(emsg_entity_not_selected);
13753 return;
13754 }
13755
13756 if (strchr(name, '/') != NULL) {
13757 semerr(emsg_invalid_pg_name, name);
13758 return;
13759 }
13760
13761 lscf_delprop(name);
13762 }
13763
13764 /*
13765 * scf_delhash() is used to remove the property group related to the
13766 * hash entry for a specific manifest in the repository. pgname will be
13767 * constructed from the location of the manifest file. If deathrow isn't 0,
13768 * manifest file doesn't need to exist (manifest string will be used as
13769 * an absolute path).
13770 */
13771 void
lscf_delhash(char * manifest,int deathrow)13772 lscf_delhash(char *manifest, int deathrow)
13773 {
13774 char *pgname;
13775
13776 if (cur_snap != NULL ||
13777 cur_inst != NULL || cur_svc != NULL) {
13778 warn(gettext("error, an entity is selected\n"));
13779 return;
13780 }
13781
13782 /* select smf/manifest */
13783 lscf_select(HASH_SVC);
13784 /*
13785 * Translate the manifest file name to property name. In the deathrow
13786 * case, the manifest file does not need to exist.
13787 */
13788 pgname = mhash_filename_to_propname(manifest,
13789 deathrow ? B_TRUE : B_FALSE);
13790 if (pgname == NULL) {
13791 warn(gettext("cannot resolve pathname for %s\n"), manifest);
13792 return;
13793 }
13794 /* delete the hash property name */
13795 lscf_delpg(pgname);
13796 }
13797
13798 void
lscf_listprop(const char * pattern)13799 lscf_listprop(const char *pattern)
13800 {
13801 lscf_prep_hndl();
13802
13803 listprop(pattern, 0, 0);
13804 }
13805
13806 int
lscf_setprop(const char * pgname,const char * type,const char * value,const uu_list_t * values)13807 lscf_setprop(const char *pgname, const char *type, const char *value,
13808 const uu_list_t *values)
13809 {
13810 scf_type_t ty, current_ty;
13811 scf_service_t *svc;
13812 scf_propertygroup_t *pg, *parent_pg;
13813 scf_property_t *prop, *parent_prop;
13814 scf_pg_tmpl_t *pgt;
13815 scf_prop_tmpl_t *prt;
13816 int ret, result = 0;
13817 scf_transaction_t *tx;
13818 scf_transaction_entry_t *e;
13819 scf_value_t *v;
13820 uu_list_walk_t *walk;
13821 string_list_t *sp;
13822 char *propname;
13823 int req_quotes = 0;
13824
13825 lscf_prep_hndl();
13826
13827 if ((e = scf_entry_create(g_hndl)) == NULL ||
13828 (svc = scf_service_create(g_hndl)) == NULL ||
13829 (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13830 (pg = scf_pg_create(g_hndl)) == NULL ||
13831 (parent_prop = scf_property_create(g_hndl)) == NULL ||
13832 (prop = scf_property_create(g_hndl)) == NULL ||
13833 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13834 (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13835 (tx = scf_transaction_create(g_hndl)) == NULL)
13836 scfdie();
13837
13838 if (cur_snap != NULL) {
13839 semerr(emsg_cant_modify_snapshots);
13840 goto fail;
13841 }
13842
13843 if (cur_inst == NULL && cur_svc == NULL) {
13844 semerr(emsg_entity_not_selected);
13845 goto fail;
13846 }
13847
13848 propname = strchr(pgname, '/');
13849 if (propname == NULL) {
13850 semerr(gettext("Property names must contain a `/'.\n"));
13851 goto fail;
13852 }
13853
13854 *propname = '\0';
13855 ++propname;
13856
13857 if (type != NULL) {
13858 ty = string_to_type(type);
13859 if (ty == SCF_TYPE_INVALID) {
13860 semerr(gettext("Unknown type \"%s\".\n"), type);
13861 goto fail;
13862 }
13863 }
13864
13865 if (cur_inst != NULL)
13866 ret = scf_instance_get_pg(cur_inst, pgname, pg);
13867 else
13868 ret = scf_service_get_pg(cur_svc, pgname, pg);
13869 if (ret != SCF_SUCCESS) {
13870 switch (scf_error()) {
13871 case SCF_ERROR_NOT_FOUND:
13872 semerr(emsg_no_such_pg, pgname);
13873 goto fail;
13874
13875 case SCF_ERROR_INVALID_ARGUMENT:
13876 semerr(emsg_invalid_pg_name, pgname);
13877 goto fail;
13878
13879 default:
13880 scfdie();
13881 break;
13882 }
13883 }
13884
13885 do {
13886 if (scf_pg_update(pg) == -1)
13887 scfdie();
13888 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13889 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13890 scfdie();
13891
13892 semerr(emsg_permission_denied);
13893 goto fail;
13894 }
13895
13896 ret = scf_pg_get_property(pg, propname, prop);
13897 if (ret == SCF_SUCCESS) {
13898 if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS)
13899 scfdie();
13900
13901 if (type == NULL)
13902 ty = current_ty;
13903 if (scf_transaction_property_change_type(tx, e,
13904 propname, ty) == -1)
13905 scfdie();
13906
13907 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13908 /* Infer the type, if possible. */
13909 if (type == NULL) {
13910 /*
13911 * First check if we're an instance and the
13912 * property is set on the service.
13913 */
13914 if (cur_inst != NULL &&
13915 scf_instance_get_parent(cur_inst,
13916 svc) == 0 &&
13917 scf_service_get_pg(cur_svc, pgname,
13918 parent_pg) == 0 &&
13919 scf_pg_get_property(parent_pg, propname,
13920 parent_prop) == 0 &&
13921 scf_property_type(parent_prop,
13922 ¤t_ty) == 0) {
13923 ty = current_ty;
13924
13925 /* Then check for a type set in a template. */
13926 } else if (scf_tmpl_get_by_pg(pg, pgt,
13927 0) == 0 &&
13928 scf_tmpl_get_by_prop(pgt, propname, prt,
13929 0) == 0 &&
13930 scf_tmpl_prop_type(prt, ¤t_ty) == 0) {
13931 ty = current_ty;
13932
13933 /* If type can't be inferred, fail. */
13934 } else {
13935 semerr(gettext("Type required for new "
13936 "properties.\n"));
13937 goto fail;
13938 }
13939 }
13940 if (scf_transaction_property_new(tx, e, propname,
13941 ty) == -1)
13942 scfdie();
13943 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13944 semerr(emsg_invalid_prop_name, propname);
13945 goto fail;
13946 } else {
13947 scfdie();
13948 }
13949
13950 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13951 req_quotes = 1;
13952
13953 if (value != NULL) {
13954 v = string_to_value(value, ty, 0);
13955
13956 if (v == NULL)
13957 goto fail;
13958
13959 ret = scf_entry_add_value(e, v);
13960 assert(ret == SCF_SUCCESS);
13961 } else {
13962 assert(values != NULL);
13963
13964 walk = uu_list_walk_start((uu_list_t *)values,
13965 UU_DEFAULT);
13966 if (walk == NULL)
13967 uu_die(gettext("Could not walk list"));
13968
13969 for (sp = uu_list_walk_next(walk); sp != NULL;
13970 sp = uu_list_walk_next(walk)) {
13971 v = string_to_value(sp->str, ty, req_quotes);
13972
13973 if (v == NULL) {
13974 scf_entry_destroy_children(e);
13975 goto fail;
13976 }
13977
13978 ret = scf_entry_add_value(e, v);
13979 assert(ret == SCF_SUCCESS);
13980 }
13981 uu_list_walk_end(walk);
13982 }
13983 result = scf_transaction_commit(tx);
13984
13985 scf_transaction_reset(tx);
13986 scf_entry_destroy_children(e);
13987 } while (result == 0);
13988
13989 if (result < 0) {
13990 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13991 scfdie();
13992
13993 semerr(emsg_permission_denied);
13994 goto fail;
13995 }
13996
13997 ret = 0;
13998
13999 private_refresh();
14000
14001 goto cleanup;
14002
14003 fail:
14004 ret = -1;
14005
14006 cleanup:
14007 scf_transaction_destroy(tx);
14008 scf_entry_destroy(e);
14009 scf_service_destroy(svc);
14010 scf_pg_destroy(parent_pg);
14011 scf_pg_destroy(pg);
14012 scf_property_destroy(parent_prop);
14013 scf_property_destroy(prop);
14014 scf_tmpl_pg_destroy(pgt);
14015 scf_tmpl_prop_destroy(prt);
14016
14017 return (ret);
14018 }
14019
14020 void
lscf_delprop(char * pgn)14021 lscf_delprop(char *pgn)
14022 {
14023 char *slash, *pn;
14024 scf_propertygroup_t *pg;
14025 scf_transaction_t *tx;
14026 scf_transaction_entry_t *e;
14027 int ret;
14028
14029
14030 lscf_prep_hndl();
14031
14032 if (cur_snap != NULL) {
14033 semerr(emsg_cant_modify_snapshots);
14034 return;
14035 }
14036
14037 if (cur_inst == NULL && cur_svc == NULL) {
14038 semerr(emsg_entity_not_selected);
14039 return;
14040 }
14041
14042 pg = scf_pg_create(g_hndl);
14043 if (pg == NULL)
14044 scfdie();
14045
14046 slash = strchr(pgn, '/');
14047 if (slash == NULL) {
14048 pn = NULL;
14049 } else {
14050 *slash = '\0';
14051 pn = slash + 1;
14052 }
14053
14054 if (cur_inst != NULL)
14055 ret = scf_instance_get_pg(cur_inst, pgn, pg);
14056 else
14057 ret = scf_service_get_pg(cur_svc, pgn, pg);
14058 if (ret != SCF_SUCCESS) {
14059 switch (scf_error()) {
14060 case SCF_ERROR_NOT_FOUND:
14061 semerr(emsg_no_such_pg, pgn);
14062 break;
14063
14064 case SCF_ERROR_INVALID_ARGUMENT:
14065 semerr(emsg_invalid_pg_name, pgn);
14066 break;
14067
14068 default:
14069 scfdie();
14070 }
14071
14072 scf_pg_destroy(pg);
14073
14074 return;
14075 }
14076
14077 if (pn == NULL) {
14078 /* Try to delete the property group. */
14079 if (scf_pg_delete(pg) != SCF_SUCCESS) {
14080 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14081 scfdie();
14082
14083 semerr(emsg_permission_denied);
14084 } else {
14085 private_refresh();
14086 }
14087
14088 scf_pg_destroy(pg);
14089 return;
14090 }
14091
14092 e = scf_entry_create(g_hndl);
14093 tx = scf_transaction_create(g_hndl);
14094
14095 do {
14096 if (scf_pg_update(pg) == -1)
14097 scfdie();
14098 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
14099 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14100 scfdie();
14101
14102 semerr(emsg_permission_denied);
14103 break;
14104 }
14105
14106 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
14107 if (scf_error() == SCF_ERROR_NOT_FOUND) {
14108 semerr(gettext("No such property %s/%s.\n"),
14109 pgn, pn);
14110 break;
14111 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14112 semerr(emsg_invalid_prop_name, pn);
14113 break;
14114 } else {
14115 scfdie();
14116 }
14117 }
14118
14119 ret = scf_transaction_commit(tx);
14120
14121 if (ret == 0)
14122 scf_transaction_reset(tx);
14123 } while (ret == 0);
14124
14125 if (ret < 0) {
14126 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14127 scfdie();
14128
14129 semerr(emsg_permission_denied);
14130 } else {
14131 private_refresh();
14132 }
14133
14134 scf_transaction_destroy(tx);
14135 scf_entry_destroy(e);
14136 scf_pg_destroy(pg);
14137 }
14138
14139 /*
14140 * Property editing.
14141 */
14142
14143 static int
write_edit_script(FILE * strm)14144 write_edit_script(FILE *strm)
14145 {
14146 char *fmribuf;
14147 ssize_t fmrilen;
14148
14149 scf_propertygroup_t *pg;
14150 scf_property_t *prop;
14151 scf_value_t *val;
14152 scf_type_t ty;
14153 int ret, result = 0;
14154 scf_iter_t *iter, *piter, *viter;
14155 char *buf, *tybuf, *pname;
14156 const char *emsg_write_error;
14157
14158
14159 emsg_write_error = gettext("Error writing temoprary file: %s.\n");
14160
14161
14162 /* select fmri */
14163 if (cur_inst != NULL) {
14164 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
14165 if (fmrilen < 0)
14166 scfdie();
14167 fmribuf = safe_malloc(fmrilen + 1);
14168 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
14169 scfdie();
14170 } else {
14171 assert(cur_svc != NULL);
14172 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
14173 if (fmrilen < 0)
14174 scfdie();
14175 fmribuf = safe_malloc(fmrilen + 1);
14176 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
14177 scfdie();
14178 }
14179
14180 if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
14181 warn(emsg_write_error, strerror(errno));
14182 free(fmribuf);
14183 return (-1);
14184 }
14185
14186 free(fmribuf);
14187
14188
14189 if ((pg = scf_pg_create(g_hndl)) == NULL ||
14190 (prop = scf_property_create(g_hndl)) == NULL ||
14191 (val = scf_value_create(g_hndl)) == NULL ||
14192 (iter = scf_iter_create(g_hndl)) == NULL ||
14193 (piter = scf_iter_create(g_hndl)) == NULL ||
14194 (viter = scf_iter_create(g_hndl)) == NULL)
14195 scfdie();
14196
14197 buf = safe_malloc(max_scf_name_len + 1);
14198 tybuf = safe_malloc(max_scf_pg_type_len + 1);
14199 pname = safe_malloc(max_scf_name_len + 1);
14200
14201 if (cur_inst != NULL)
14202 ret = scf_iter_instance_pgs(iter, cur_inst);
14203 else
14204 ret = scf_iter_service_pgs(iter, cur_svc);
14205 if (ret != SCF_SUCCESS)
14206 scfdie();
14207
14208 while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
14209 int ret2;
14210
14211 /*
14212 * # delprop pg
14213 * # addpg pg type
14214 */
14215 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
14216 scfdie();
14217
14218 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
14219 scfdie();
14220
14221 if (fprintf(strm, "# Property group \"%s\"\n"
14222 "# delprop %s\n"
14223 "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
14224 warn(emsg_write_error, strerror(errno));
14225 result = -1;
14226 goto out;
14227 }
14228
14229 /* # setprop pg/prop = (values) */
14230
14231 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
14232 scfdie();
14233
14234 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
14235 int first = 1;
14236 int ret3;
14237 int multiple;
14238 int is_str;
14239 scf_type_t bty;
14240
14241 if (scf_property_get_name(prop, pname,
14242 max_scf_name_len + 1) < 0)
14243 scfdie();
14244
14245 if (scf_property_type(prop, &ty) != 0)
14246 scfdie();
14247
14248 multiple = prop_has_multiple_values(prop, val);
14249
14250 if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
14251 pname, scf_type_to_string(ty), multiple ? "(" : "")
14252 < 0) {
14253 warn(emsg_write_error, strerror(errno));
14254 result = -1;
14255 goto out;
14256 }
14257
14258 (void) scf_type_base_type(ty, &bty);
14259 is_str = (bty == SCF_TYPE_ASTRING);
14260
14261 if (scf_iter_property_values(viter, prop) !=
14262 SCF_SUCCESS)
14263 scfdie();
14264
14265 while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
14266 char *buf;
14267 ssize_t buflen;
14268
14269 buflen = scf_value_get_as_string(val, NULL, 0);
14270 if (buflen < 0)
14271 scfdie();
14272
14273 buf = safe_malloc(buflen + 1);
14274
14275 if (scf_value_get_as_string(val, buf,
14276 buflen + 1) < 0)
14277 scfdie();
14278
14279 if (first)
14280 first = 0;
14281 else {
14282 if (putc(' ', strm) != ' ') {
14283 warn(emsg_write_error,
14284 strerror(errno));
14285 result = -1;
14286 goto out;
14287 }
14288 }
14289
14290 if ((is_str && multiple) ||
14291 strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
14292 (void) putc('"', strm);
14293 (void) quote_and_print(buf, strm, 1);
14294 (void) putc('"', strm);
14295
14296 if (ferror(strm)) {
14297 warn(emsg_write_error,
14298 strerror(errno));
14299 result = -1;
14300 goto out;
14301 }
14302 } else {
14303 if (fprintf(strm, "%s", buf) < 0) {
14304 warn(emsg_write_error,
14305 strerror(errno));
14306 result = -1;
14307 goto out;
14308 }
14309 }
14310
14311 free(buf);
14312 }
14313 if (ret3 < 0 &&
14314 scf_error() != SCF_ERROR_PERMISSION_DENIED)
14315 scfdie();
14316
14317 /* Write closing paren if mult-value property */
14318 if ((multiple && putc(')', strm) == EOF) ||
14319
14320 /* Write final newline */
14321 fputc('\n', strm) == EOF) {
14322 warn(emsg_write_error, strerror(errno));
14323 result = -1;
14324 goto out;
14325 }
14326 }
14327 if (ret2 < 0)
14328 scfdie();
14329
14330 if (fputc('\n', strm) == EOF) {
14331 warn(emsg_write_error, strerror(errno));
14332 result = -1;
14333 goto out;
14334 }
14335 }
14336 if (ret < 0)
14337 scfdie();
14338
14339 out:
14340 free(pname);
14341 free(tybuf);
14342 free(buf);
14343 scf_iter_destroy(viter);
14344 scf_iter_destroy(piter);
14345 scf_iter_destroy(iter);
14346 scf_value_destroy(val);
14347 scf_property_destroy(prop);
14348 scf_pg_destroy(pg);
14349
14350 if (result == 0) {
14351 if (fflush(strm) != 0) {
14352 warn(emsg_write_error, strerror(errno));
14353 return (-1);
14354 }
14355 }
14356
14357 return (result);
14358 }
14359
14360 int
lscf_editprop()14361 lscf_editprop()
14362 {
14363 char *buf, *editor;
14364 size_t bufsz;
14365 int tmpfd;
14366 char tempname[] = TEMP_FILE_PATTERN;
14367
14368 lscf_prep_hndl();
14369
14370 if (cur_snap != NULL) {
14371 semerr(emsg_cant_modify_snapshots);
14372 return (-1);
14373 }
14374
14375 if (cur_svc == NULL && cur_inst == NULL) {
14376 semerr(emsg_entity_not_selected);
14377 return (-1);
14378 }
14379
14380 tmpfd = mkstemp(tempname);
14381 if (tmpfd == -1) {
14382 semerr(gettext("Could not create temporary file.\n"));
14383 return (-1);
14384 }
14385
14386 (void) strcpy(tempfilename, tempname);
14387
14388 tempfile = fdopen(tmpfd, "r+");
14389 if (tempfile == NULL) {
14390 warn(gettext("Could not create temporary file.\n"));
14391 if (close(tmpfd) == -1)
14392 warn(gettext("Could not close temporary file: %s.\n"),
14393 strerror(errno));
14394
14395 remove_tempfile();
14396
14397 return (-1);
14398 }
14399
14400 if (write_edit_script(tempfile) == -1) {
14401 remove_tempfile();
14402 return (-1);
14403 }
14404
14405 editor = getenv("EDITOR");
14406 if (editor == NULL)
14407 editor = "vi";
14408
14409 bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
14410 buf = safe_malloc(bufsz);
14411
14412 if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
14413 uu_die(gettext("Error creating editor command"));
14414
14415 if (system(buf) == -1) {
14416 semerr(gettext("Could not launch editor %s: %s\n"), editor,
14417 strerror(errno));
14418 free(buf);
14419 remove_tempfile();
14420 return (-1);
14421 }
14422
14423 free(buf);
14424
14425 (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
14426
14427 remove_tempfile();
14428
14429 return (0);
14430 }
14431
14432 static void
add_string(uu_list_t * strlist,const char * str)14433 add_string(uu_list_t *strlist, const char *str)
14434 {
14435 string_list_t *elem;
14436 elem = safe_malloc(sizeof (*elem));
14437 uu_list_node_init(elem, &elem->node, string_pool);
14438 elem->str = safe_strdup(str);
14439 if (uu_list_append(strlist, elem) != 0)
14440 uu_die(gettext("libuutil error: %s\n"),
14441 uu_strerror(uu_error()));
14442 }
14443
14444 static int
remove_string(uu_list_t * strlist,const char * str)14445 remove_string(uu_list_t *strlist, const char *str)
14446 {
14447 uu_list_walk_t *elems;
14448 string_list_t *sp;
14449
14450 /*
14451 * Find the element that needs to be removed.
14452 */
14453 elems = uu_list_walk_start(strlist, UU_DEFAULT);
14454 while ((sp = uu_list_walk_next(elems)) != NULL) {
14455 if (strcmp(sp->str, str) == 0)
14456 break;
14457 }
14458 uu_list_walk_end(elems);
14459
14460 /*
14461 * Returning 1 here as the value was not found, this
14462 * might not be an error. Leave it to the caller to
14463 * decide.
14464 */
14465 if (sp == NULL) {
14466 return (1);
14467 }
14468
14469 uu_list_remove(strlist, sp);
14470
14471 free(sp->str);
14472 free(sp);
14473
14474 return (0);
14475 }
14476
14477 /*
14478 * Get all property values that don't match the given glob pattern,
14479 * if a pattern is specified.
14480 */
14481 static void
get_prop_values(scf_property_t * prop,uu_list_t * values,const char * pattern)14482 get_prop_values(scf_property_t *prop, uu_list_t *values,
14483 const char *pattern)
14484 {
14485 scf_iter_t *iter;
14486 scf_value_t *val;
14487 int ret;
14488
14489 if ((iter = scf_iter_create(g_hndl)) == NULL ||
14490 (val = scf_value_create(g_hndl)) == NULL)
14491 scfdie();
14492
14493 if (scf_iter_property_values(iter, prop) != 0)
14494 scfdie();
14495
14496 while ((ret = scf_iter_next_value(iter, val)) == 1) {
14497 char *buf;
14498 ssize_t vlen, szret;
14499
14500 vlen = scf_value_get_as_string(val, NULL, 0);
14501 if (vlen < 0)
14502 scfdie();
14503
14504 buf = safe_malloc(vlen + 1);
14505
14506 szret = scf_value_get_as_string(val, buf, vlen + 1);
14507 if (szret < 0)
14508 scfdie();
14509 assert(szret <= vlen);
14510
14511 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14512 add_string(values, buf);
14513
14514 free(buf);
14515 }
14516
14517 if (ret == -1)
14518 scfdie();
14519
14520 scf_value_destroy(val);
14521 scf_iter_destroy(iter);
14522 }
14523
14524 static int
lscf_setpropvalue(const char * pgname,const char * type,const char * arg,int isadd,int isnotfoundok)14525 lscf_setpropvalue(const char *pgname, const char *type,
14526 const char *arg, int isadd, int isnotfoundok)
14527 {
14528 scf_type_t ty;
14529 scf_propertygroup_t *pg;
14530 scf_property_t *prop;
14531 int ret, result = 0;
14532 scf_transaction_t *tx;
14533 scf_transaction_entry_t *e;
14534 scf_value_t *v;
14535 string_list_t *sp;
14536 char *propname;
14537 uu_list_t *values;
14538 uu_list_walk_t *walk;
14539 void *cookie = NULL;
14540 char *pattern = NULL;
14541
14542 lscf_prep_hndl();
14543
14544 if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14545 uu_die(gettext("Could not create property list: %s\n"),
14546 uu_strerror(uu_error()));
14547
14548 if (!isadd)
14549 pattern = safe_strdup(arg);
14550
14551 if ((e = scf_entry_create(g_hndl)) == NULL ||
14552 (pg = scf_pg_create(g_hndl)) == NULL ||
14553 (prop = scf_property_create(g_hndl)) == NULL ||
14554 (tx = scf_transaction_create(g_hndl)) == NULL)
14555 scfdie();
14556
14557 if (cur_snap != NULL) {
14558 semerr(emsg_cant_modify_snapshots);
14559 goto fail;
14560 }
14561
14562 if (cur_inst == NULL && cur_svc == NULL) {
14563 semerr(emsg_entity_not_selected);
14564 goto fail;
14565 }
14566
14567 propname = strchr(pgname, '/');
14568 if (propname == NULL) {
14569 semerr(gettext("Property names must contain a `/'.\n"));
14570 goto fail;
14571 }
14572
14573 *propname = '\0';
14574 ++propname;
14575
14576 if (type != NULL) {
14577 ty = string_to_type(type);
14578 if (ty == SCF_TYPE_INVALID) {
14579 semerr(gettext("Unknown type \"%s\".\n"), type);
14580 goto fail;
14581 }
14582 }
14583
14584 if (cur_inst != NULL)
14585 ret = scf_instance_get_pg(cur_inst, pgname, pg);
14586 else
14587 ret = scf_service_get_pg(cur_svc, pgname, pg);
14588 if (ret != 0) {
14589 switch (scf_error()) {
14590 case SCF_ERROR_NOT_FOUND:
14591 if (isnotfoundok) {
14592 result = 0;
14593 } else {
14594 semerr(emsg_no_such_pg, pgname);
14595 result = -1;
14596 }
14597 goto out;
14598
14599 case SCF_ERROR_INVALID_ARGUMENT:
14600 semerr(emsg_invalid_pg_name, pgname);
14601 goto fail;
14602
14603 default:
14604 scfdie();
14605 }
14606 }
14607
14608 do {
14609 if (scf_pg_update(pg) == -1)
14610 scfdie();
14611 if (scf_transaction_start(tx, pg) != 0) {
14612 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14613 scfdie();
14614
14615 semerr(emsg_permission_denied);
14616 goto fail;
14617 }
14618
14619 ret = scf_pg_get_property(pg, propname, prop);
14620 if (ret == 0) {
14621 scf_type_t ptype;
14622 char *pat = pattern;
14623
14624 if (scf_property_type(prop, &ptype) != 0)
14625 scfdie();
14626
14627 if (isadd) {
14628 if (type != NULL && ptype != ty) {
14629 semerr(gettext("Property \"%s\" is not "
14630 "of type \"%s\".\n"), propname,
14631 type);
14632 goto fail;
14633 }
14634
14635 pat = NULL;
14636 } else {
14637 size_t len = strlen(pat);
14638 if (len > 0 && pat[len - 1] == '\"')
14639 pat[len - 1] = '\0';
14640 if (len > 0 && pat[0] == '\"')
14641 pat++;
14642 }
14643
14644 ty = ptype;
14645
14646 get_prop_values(prop, values, pat);
14647
14648 if (isadd)
14649 add_string(values, arg);
14650
14651 if (scf_transaction_property_change(tx, e,
14652 propname, ty) == -1)
14653 scfdie();
14654 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14655 if (isadd) {
14656 if (type == NULL) {
14657 semerr(gettext("Type required "
14658 "for new properties.\n"));
14659 goto fail;
14660 }
14661
14662 add_string(values, arg);
14663
14664 if (scf_transaction_property_new(tx, e,
14665 propname, ty) == -1)
14666 scfdie();
14667 } else if (isnotfoundok) {
14668 result = 0;
14669 goto out;
14670 } else {
14671 semerr(gettext("No such property %s/%s.\n"),
14672 pgname, propname);
14673 result = -1;
14674 goto out;
14675 }
14676 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14677 semerr(emsg_invalid_prop_name, propname);
14678 goto fail;
14679 } else {
14680 scfdie();
14681 }
14682
14683 walk = uu_list_walk_start(values, UU_DEFAULT);
14684 if (walk == NULL)
14685 uu_die(gettext("Could not walk property list.\n"));
14686
14687 for (sp = uu_list_walk_next(walk); sp != NULL;
14688 sp = uu_list_walk_next(walk)) {
14689 v = string_to_value(sp->str, ty, 0);
14690
14691 if (v == NULL) {
14692 scf_entry_destroy_children(e);
14693 goto fail;
14694 }
14695 ret = scf_entry_add_value(e, v);
14696 assert(ret == 0);
14697 }
14698 uu_list_walk_end(walk);
14699
14700 result = scf_transaction_commit(tx);
14701
14702 scf_transaction_reset(tx);
14703 scf_entry_destroy_children(e);
14704 } while (result == 0);
14705
14706 if (result < 0) {
14707 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14708 scfdie();
14709
14710 semerr(emsg_permission_denied);
14711 goto fail;
14712 }
14713
14714 result = 0;
14715
14716 private_refresh();
14717
14718 out:
14719 scf_transaction_destroy(tx);
14720 scf_entry_destroy(e);
14721 scf_pg_destroy(pg);
14722 scf_property_destroy(prop);
14723 free(pattern);
14724
14725 while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14726 free(sp->str);
14727 free(sp);
14728 }
14729
14730 uu_list_destroy(values);
14731
14732 return (result);
14733
14734 fail:
14735 result = -1;
14736 goto out;
14737 }
14738
14739 int
lscf_addpropvalue(const char * pgname,const char * type,const char * value)14740 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14741 {
14742 return (lscf_setpropvalue(pgname, type, value, 1, 0));
14743 }
14744
14745 int
lscf_delpropvalue(const char * pgname,const char * pattern,int isnotfoundok)14746 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14747 {
14748 return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14749 }
14750
14751 /*
14752 * Look for a standard start method, first in the instance (if any),
14753 * then the service.
14754 */
14755 static const char *
start_method_name(int * in_instance)14756 start_method_name(int *in_instance)
14757 {
14758 scf_propertygroup_t *pg;
14759 char **p;
14760 int ret;
14761 scf_instance_t *inst = cur_inst;
14762
14763 if ((pg = scf_pg_create(g_hndl)) == NULL)
14764 scfdie();
14765
14766 again:
14767 for (p = start_method_names; *p != NULL; p++) {
14768 if (inst != NULL)
14769 ret = scf_instance_get_pg(inst, *p, pg);
14770 else
14771 ret = scf_service_get_pg(cur_svc, *p, pg);
14772
14773 if (ret == 0) {
14774 size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14775 char *buf = safe_malloc(bufsz);
14776
14777 if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14778 free(buf);
14779 continue;
14780 }
14781 if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14782 free(buf);
14783 continue;
14784 }
14785
14786 free(buf);
14787 *in_instance = (inst != NULL);
14788 scf_pg_destroy(pg);
14789 return (*p);
14790 }
14791
14792 if (scf_error() == SCF_ERROR_NOT_FOUND)
14793 continue;
14794
14795 scfdie();
14796 }
14797
14798 if (inst != NULL) {
14799 inst = NULL;
14800 goto again;
14801 }
14802
14803 scf_pg_destroy(pg);
14804 return (NULL);
14805 }
14806
14807 static int
addpg(const char * name,const char * type)14808 addpg(const char *name, const char *type)
14809 {
14810 scf_propertygroup_t *pg;
14811 int ret;
14812
14813 pg = scf_pg_create(g_hndl);
14814 if (pg == NULL)
14815 scfdie();
14816
14817 if (cur_inst != NULL)
14818 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14819 else
14820 ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14821
14822 if (ret != 0) {
14823 switch (scf_error()) {
14824 case SCF_ERROR_EXISTS:
14825 ret = 0;
14826 break;
14827
14828 case SCF_ERROR_PERMISSION_DENIED:
14829 semerr(emsg_permission_denied);
14830 break;
14831
14832 default:
14833 scfdie();
14834 }
14835 }
14836
14837 scf_pg_destroy(pg);
14838 return (ret);
14839 }
14840
14841 int
lscf_setenv(uu_list_t * args,int isunset)14842 lscf_setenv(uu_list_t *args, int isunset)
14843 {
14844 int ret = 0;
14845 size_t i;
14846 int argc;
14847 char **argv = NULL;
14848 string_list_t *slp;
14849 char *pattern;
14850 char *prop;
14851 int do_service = 0;
14852 int do_instance = 0;
14853 const char *method = NULL;
14854 const char *name = NULL;
14855 const char *value = NULL;
14856 scf_instance_t *saved_cur_inst = cur_inst;
14857
14858 lscf_prep_hndl();
14859
14860 argc = uu_list_numnodes(args);
14861 if (argc < 1)
14862 goto usage;
14863
14864 argv = calloc(argc + 1, sizeof (char *));
14865 if (argv == NULL)
14866 uu_die(gettext("Out of memory.\n"));
14867
14868 for (slp = uu_list_first(args), i = 0;
14869 slp != NULL;
14870 slp = uu_list_next(args, slp), ++i)
14871 argv[i] = slp->str;
14872
14873 argv[i] = NULL;
14874
14875 opterr = 0;
14876 optind = 0;
14877 for (;;) {
14878 ret = getopt(argc, argv, "sim:");
14879 if (ret == -1)
14880 break;
14881
14882 switch (ret) {
14883 case 's':
14884 do_service = 1;
14885 cur_inst = NULL;
14886 break;
14887
14888 case 'i':
14889 do_instance = 1;
14890 break;
14891
14892 case 'm':
14893 method = optarg;
14894 break;
14895
14896 case '?':
14897 goto usage;
14898
14899 default:
14900 bad_error("getopt", ret);
14901 }
14902 }
14903
14904 argc -= optind;
14905 if ((do_service && do_instance) ||
14906 (isunset && argc != 1) ||
14907 (!isunset && argc != 2))
14908 goto usage;
14909
14910 name = argv[optind];
14911 if (!isunset)
14912 value = argv[optind + 1];
14913
14914 if (cur_snap != NULL) {
14915 semerr(emsg_cant_modify_snapshots);
14916 ret = -1;
14917 goto out;
14918 }
14919
14920 if (cur_inst == NULL && cur_svc == NULL) {
14921 semerr(emsg_entity_not_selected);
14922 ret = -1;
14923 goto out;
14924 }
14925
14926 if (do_instance && cur_inst == NULL) {
14927 semerr(gettext("No instance is selected.\n"));
14928 ret = -1;
14929 goto out;
14930 }
14931
14932 if (do_service && cur_svc == NULL) {
14933 semerr(gettext("No service is selected.\n"));
14934 ret = -1;
14935 goto out;
14936 }
14937
14938 if (method == NULL) {
14939 if (do_instance || do_service) {
14940 method = "method_context";
14941 if (!isunset) {
14942 ret = addpg("method_context",
14943 SCF_GROUP_FRAMEWORK);
14944 if (ret != 0)
14945 goto out;
14946 }
14947 } else {
14948 int in_instance;
14949 method = start_method_name(&in_instance);
14950 if (method == NULL) {
14951 semerr(gettext(
14952 "Couldn't find start method; please "
14953 "specify a method with '-m'.\n"));
14954 ret = -1;
14955 goto out;
14956 }
14957 if (!in_instance)
14958 cur_inst = NULL;
14959 }
14960 } else {
14961 scf_propertygroup_t *pg;
14962 size_t bufsz;
14963 char *buf;
14964 int ret;
14965
14966 if ((pg = scf_pg_create(g_hndl)) == NULL)
14967 scfdie();
14968
14969 if (cur_inst != NULL)
14970 ret = scf_instance_get_pg(cur_inst, method, pg);
14971 else
14972 ret = scf_service_get_pg(cur_svc, method, pg);
14973
14974 if (ret != 0) {
14975 scf_pg_destroy(pg);
14976 switch (scf_error()) {
14977 case SCF_ERROR_NOT_FOUND:
14978 semerr(gettext("Couldn't find the method "
14979 "\"%s\".\n"), method);
14980 goto out;
14981
14982 case SCF_ERROR_INVALID_ARGUMENT:
14983 semerr(gettext("Invalid method name \"%s\".\n"),
14984 method);
14985 goto out;
14986
14987 default:
14988 scfdie();
14989 }
14990 }
14991
14992 bufsz = strlen(SCF_GROUP_METHOD) + 1;
14993 buf = safe_malloc(bufsz);
14994
14995 if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
14996 strcmp(buf, SCF_GROUP_METHOD) != 0) {
14997 semerr(gettext("Property group \"%s\" is not of type "
14998 "\"method\".\n"), method);
14999 ret = -1;
15000 free(buf);
15001 scf_pg_destroy(pg);
15002 goto out;
15003 }
15004
15005 free(buf);
15006 scf_pg_destroy(pg);
15007 }
15008
15009 prop = uu_msprintf("%s/environment", method);
15010 pattern = uu_msprintf("%s=*", name);
15011
15012 if (prop == NULL || pattern == NULL)
15013 uu_die(gettext("Out of memory.\n"));
15014
15015 ret = lscf_delpropvalue(prop, pattern, !isunset);
15016
15017 if (ret == 0 && !isunset) {
15018 uu_free(pattern);
15019 uu_free(prop);
15020 prop = uu_msprintf("%s/environment", method);
15021 pattern = uu_msprintf("%s=%s", name, value);
15022 if (prop == NULL || pattern == NULL)
15023 uu_die(gettext("Out of memory.\n"));
15024 ret = lscf_addpropvalue(prop, "astring:", pattern);
15025 }
15026 uu_free(pattern);
15027 uu_free(prop);
15028
15029 out:
15030 cur_inst = saved_cur_inst;
15031
15032 free(argv);
15033 return (ret);
15034 usage:
15035 ret = -2;
15036 goto out;
15037 }
15038
15039 /*
15040 * Snapshot commands
15041 */
15042
15043 void
lscf_listsnap()15044 lscf_listsnap()
15045 {
15046 scf_snapshot_t *snap;
15047 scf_iter_t *iter;
15048 char *nb;
15049 int r;
15050
15051 lscf_prep_hndl();
15052
15053 if (cur_inst == NULL) {
15054 semerr(gettext("Instance not selected.\n"));
15055 return;
15056 }
15057
15058 if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15059 (iter = scf_iter_create(g_hndl)) == NULL)
15060 scfdie();
15061
15062 if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
15063 scfdie();
15064
15065 nb = safe_malloc(max_scf_name_len + 1);
15066
15067 while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
15068 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
15069 scfdie();
15070
15071 (void) puts(nb);
15072 }
15073 if (r < 0)
15074 scfdie();
15075
15076 free(nb);
15077 scf_iter_destroy(iter);
15078 scf_snapshot_destroy(snap);
15079 }
15080
15081 void
lscf_selectsnap(const char * name)15082 lscf_selectsnap(const char *name)
15083 {
15084 scf_snapshot_t *snap;
15085 scf_snaplevel_t *level;
15086
15087 lscf_prep_hndl();
15088
15089 if (cur_inst == NULL) {
15090 semerr(gettext("Instance not selected.\n"));
15091 return;
15092 }
15093
15094 if (cur_snap != NULL) {
15095 if (name != NULL) {
15096 char *cur_snap_name;
15097 boolean_t nochange;
15098
15099 cur_snap_name = safe_malloc(max_scf_name_len + 1);
15100
15101 if (scf_snapshot_get_name(cur_snap, cur_snap_name,
15102 max_scf_name_len + 1) < 0)
15103 scfdie();
15104
15105 nochange = strcmp(name, cur_snap_name) == 0;
15106
15107 free(cur_snap_name);
15108
15109 if (nochange)
15110 return;
15111 }
15112
15113 unselect_cursnap();
15114 }
15115
15116 if (name == NULL)
15117 return;
15118
15119 if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15120 (level = scf_snaplevel_create(g_hndl)) == NULL)
15121 scfdie();
15122
15123 if (scf_instance_get_snapshot(cur_inst, name, snap) !=
15124 SCF_SUCCESS) {
15125 switch (scf_error()) {
15126 case SCF_ERROR_INVALID_ARGUMENT:
15127 semerr(gettext("Invalid name \"%s\".\n"), name);
15128 break;
15129
15130 case SCF_ERROR_NOT_FOUND:
15131 semerr(gettext("No such snapshot \"%s\".\n"), name);
15132 break;
15133
15134 default:
15135 scfdie();
15136 }
15137
15138 scf_snaplevel_destroy(level);
15139 scf_snapshot_destroy(snap);
15140 return;
15141 }
15142
15143 /* Load the snaplevels into our list. */
15144 cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
15145 if (cur_levels == NULL)
15146 uu_die(gettext("Could not create list: %s\n"),
15147 uu_strerror(uu_error()));
15148
15149 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15150 if (scf_error() != SCF_ERROR_NOT_FOUND)
15151 scfdie();
15152
15153 semerr(gettext("Snapshot has no snaplevels.\n"));
15154
15155 scf_snaplevel_destroy(level);
15156 scf_snapshot_destroy(snap);
15157 return;
15158 }
15159
15160 cur_snap = snap;
15161
15162 for (;;) {
15163 cur_elt = safe_malloc(sizeof (*cur_elt));
15164 uu_list_node_init(cur_elt, &cur_elt->list_node,
15165 snaplevel_pool);
15166 cur_elt->sl = level;
15167 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
15168 uu_die(gettext("libuutil error: %s\n"),
15169 uu_strerror(uu_error()));
15170
15171 level = scf_snaplevel_create(g_hndl);
15172 if (level == NULL)
15173 scfdie();
15174
15175 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
15176 level) != SCF_SUCCESS) {
15177 if (scf_error() != SCF_ERROR_NOT_FOUND)
15178 scfdie();
15179
15180 scf_snaplevel_destroy(level);
15181 break;
15182 }
15183 }
15184
15185 cur_elt = uu_list_last(cur_levels);
15186 cur_level = cur_elt->sl;
15187 }
15188
15189 /*
15190 * Copies the properties & values in src to dst. Assumes src won't change.
15191 * Returns -1 if permission is denied, -2 if another transaction interrupts,
15192 * and 0 on success.
15193 *
15194 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
15195 * property, if it is copied and has type boolean. (See comment in
15196 * lscf_revert()).
15197 */
15198 static int
pg_copy(const scf_propertygroup_t * src,scf_propertygroup_t * dst,uint8_t enabled)15199 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
15200 uint8_t enabled)
15201 {
15202 scf_transaction_t *tx;
15203 scf_iter_t *iter, *viter;
15204 scf_property_t *prop;
15205 scf_value_t *v;
15206 char *nbuf;
15207 int r;
15208
15209 tx = scf_transaction_create(g_hndl);
15210 if (tx == NULL)
15211 scfdie();
15212
15213 if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
15214 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15215 scfdie();
15216
15217 scf_transaction_destroy(tx);
15218
15219 return (-1);
15220 }
15221
15222 if ((iter = scf_iter_create(g_hndl)) == NULL ||
15223 (prop = scf_property_create(g_hndl)) == NULL ||
15224 (viter = scf_iter_create(g_hndl)) == NULL)
15225 scfdie();
15226
15227 nbuf = safe_malloc(max_scf_name_len + 1);
15228
15229 if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
15230 scfdie();
15231
15232 for (;;) {
15233 scf_transaction_entry_t *e;
15234 scf_type_t ty;
15235
15236 r = scf_iter_next_property(iter, prop);
15237 if (r == -1)
15238 scfdie();
15239 if (r == 0)
15240 break;
15241
15242 e = scf_entry_create(g_hndl);
15243 if (e == NULL)
15244 scfdie();
15245
15246 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
15247 scfdie();
15248
15249 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
15250 scfdie();
15251
15252 if (scf_transaction_property_new(tx, e, nbuf,
15253 ty) != SCF_SUCCESS)
15254 scfdie();
15255
15256 if ((enabled == 0 || enabled == 1) &&
15257 strcmp(nbuf, scf_property_enabled) == 0 &&
15258 ty == SCF_TYPE_BOOLEAN) {
15259 v = scf_value_create(g_hndl);
15260 if (v == NULL)
15261 scfdie();
15262
15263 scf_value_set_boolean(v, enabled);
15264
15265 if (scf_entry_add_value(e, v) != 0)
15266 scfdie();
15267 } else {
15268 if (scf_iter_property_values(viter, prop) != 0)
15269 scfdie();
15270
15271 for (;;) {
15272 v = scf_value_create(g_hndl);
15273 if (v == NULL)
15274 scfdie();
15275
15276 r = scf_iter_next_value(viter, v);
15277 if (r == -1)
15278 scfdie();
15279 if (r == 0) {
15280 scf_value_destroy(v);
15281 break;
15282 }
15283
15284 if (scf_entry_add_value(e, v) != SCF_SUCCESS)
15285 scfdie();
15286 }
15287 }
15288 }
15289
15290 free(nbuf);
15291 scf_iter_destroy(viter);
15292 scf_property_destroy(prop);
15293 scf_iter_destroy(iter);
15294
15295 r = scf_transaction_commit(tx);
15296 if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
15297 scfdie();
15298
15299 scf_transaction_destroy_children(tx);
15300 scf_transaction_destroy(tx);
15301
15302 switch (r) {
15303 case 1: return (0);
15304 case 0: return (-2);
15305 case -1: return (-1);
15306
15307 default:
15308 abort();
15309 }
15310
15311 /* NOTREACHED */
15312 }
15313
15314 void
lscf_revert(const char * snapname)15315 lscf_revert(const char *snapname)
15316 {
15317 scf_snapshot_t *snap, *prev;
15318 scf_snaplevel_t *level, *nlevel;
15319 scf_iter_t *iter;
15320 scf_propertygroup_t *pg, *npg;
15321 scf_property_t *prop;
15322 scf_value_t *val;
15323 char *nbuf, *tbuf;
15324 uint8_t enabled;
15325
15326 lscf_prep_hndl();
15327
15328 if (cur_inst == NULL) {
15329 semerr(gettext("Instance not selected.\n"));
15330 return;
15331 }
15332
15333 if (snapname != NULL) {
15334 snap = scf_snapshot_create(g_hndl);
15335 if (snap == NULL)
15336 scfdie();
15337
15338 if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
15339 SCF_SUCCESS) {
15340 switch (scf_error()) {
15341 case SCF_ERROR_INVALID_ARGUMENT:
15342 semerr(gettext("Invalid snapshot name "
15343 "\"%s\".\n"), snapname);
15344 break;
15345
15346 case SCF_ERROR_NOT_FOUND:
15347 semerr(gettext("No such snapshot.\n"));
15348 break;
15349
15350 default:
15351 scfdie();
15352 }
15353
15354 scf_snapshot_destroy(snap);
15355 return;
15356 }
15357 } else {
15358 if (cur_snap != NULL) {
15359 snap = cur_snap;
15360 } else {
15361 semerr(gettext("No snapshot selected.\n"));
15362 return;
15363 }
15364 }
15365
15366 if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
15367 (level = scf_snaplevel_create(g_hndl)) == NULL ||
15368 (iter = scf_iter_create(g_hndl)) == NULL ||
15369 (pg = scf_pg_create(g_hndl)) == NULL ||
15370 (npg = scf_pg_create(g_hndl)) == NULL ||
15371 (prop = scf_property_create(g_hndl)) == NULL ||
15372 (val = scf_value_create(g_hndl)) == NULL)
15373 scfdie();
15374
15375 nbuf = safe_malloc(max_scf_name_len + 1);
15376 tbuf = safe_malloc(max_scf_pg_type_len + 1);
15377
15378 /* Take the "previous" snapshot before we blow away the properties. */
15379 if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
15380 if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
15381 scfdie();
15382 } else {
15383 if (scf_error() != SCF_ERROR_NOT_FOUND)
15384 scfdie();
15385
15386 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
15387 scfdie();
15388 }
15389
15390 /* Save general/enabled, since we're probably going to replace it. */
15391 enabled = 2;
15392 if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
15393 scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
15394 scf_property_get_value(prop, val) == 0)
15395 (void) scf_value_get_boolean(val, &enabled);
15396
15397 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15398 if (scf_error() != SCF_ERROR_NOT_FOUND)
15399 scfdie();
15400
15401 goto out;
15402 }
15403
15404 for (;;) {
15405 boolean_t isinst;
15406 uint32_t flags;
15407 int r;
15408
15409 /* Clear the properties from the corresponding entity. */
15410 isinst = snaplevel_is_instance(level);
15411
15412 if (!isinst)
15413 r = scf_iter_service_pgs(iter, cur_svc);
15414 else
15415 r = scf_iter_instance_pgs(iter, cur_inst);
15416 if (r != SCF_SUCCESS)
15417 scfdie();
15418
15419 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15420 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15421 scfdie();
15422
15423 /* Skip nonpersistent pgs. */
15424 if (flags & SCF_PG_FLAG_NONPERSISTENT)
15425 continue;
15426
15427 if (scf_pg_delete(pg) != SCF_SUCCESS) {
15428 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15429 scfdie();
15430
15431 semerr(emsg_permission_denied);
15432 goto out;
15433 }
15434 }
15435 if (r == -1)
15436 scfdie();
15437
15438 /* Copy the properties to the corresponding entity. */
15439 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
15440 scfdie();
15441
15442 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15443 if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
15444 scfdie();
15445
15446 if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
15447 0)
15448 scfdie();
15449
15450 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15451 scfdie();
15452
15453 if (!isinst)
15454 r = scf_service_add_pg(cur_svc, nbuf, tbuf,
15455 flags, npg);
15456 else
15457 r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
15458 flags, npg);
15459 if (r != SCF_SUCCESS) {
15460 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15461 scfdie();
15462
15463 semerr(emsg_permission_denied);
15464 goto out;
15465 }
15466
15467 if ((enabled == 0 || enabled == 1) &&
15468 strcmp(nbuf, scf_pg_general) == 0)
15469 r = pg_copy(pg, npg, enabled);
15470 else
15471 r = pg_copy(pg, npg, 2);
15472
15473 switch (r) {
15474 case 0:
15475 break;
15476
15477 case -1:
15478 semerr(emsg_permission_denied);
15479 goto out;
15480
15481 case -2:
15482 semerr(gettext(
15483 "Interrupted by another change.\n"));
15484 goto out;
15485
15486 default:
15487 abort();
15488 }
15489 }
15490 if (r == -1)
15491 scfdie();
15492
15493 /* Get next level. */
15494 nlevel = scf_snaplevel_create(g_hndl);
15495 if (nlevel == NULL)
15496 scfdie();
15497
15498 if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
15499 SCF_SUCCESS) {
15500 if (scf_error() != SCF_ERROR_NOT_FOUND)
15501 scfdie();
15502
15503 scf_snaplevel_destroy(nlevel);
15504 break;
15505 }
15506
15507 scf_snaplevel_destroy(level);
15508 level = nlevel;
15509 }
15510
15511 if (snapname == NULL) {
15512 lscf_selectsnap(NULL);
15513 snap = NULL; /* cur_snap has been destroyed */
15514 }
15515
15516 out:
15517 free(tbuf);
15518 free(nbuf);
15519 scf_value_destroy(val);
15520 scf_property_destroy(prop);
15521 scf_pg_destroy(npg);
15522 scf_pg_destroy(pg);
15523 scf_iter_destroy(iter);
15524 scf_snaplevel_destroy(level);
15525 scf_snapshot_destroy(prev);
15526 if (snap != cur_snap)
15527 scf_snapshot_destroy(snap);
15528 }
15529
15530 void
lscf_refresh(void)15531 lscf_refresh(void)
15532 {
15533 ssize_t fmrilen;
15534 size_t bufsz;
15535 char *fmribuf;
15536 int r;
15537
15538 lscf_prep_hndl();
15539
15540 if (cur_inst == NULL) {
15541 semerr(gettext("Instance not selected.\n"));
15542 return;
15543 }
15544
15545 bufsz = max_scf_fmri_len + 1;
15546 fmribuf = safe_malloc(bufsz);
15547 fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15548 if (fmrilen < 0) {
15549 free(fmribuf);
15550 if (scf_error() != SCF_ERROR_DELETED)
15551 scfdie();
15552 scf_instance_destroy(cur_inst);
15553 cur_inst = NULL;
15554 warn(emsg_deleted);
15555 return;
15556 }
15557 assert(fmrilen < bufsz);
15558
15559 r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15560 switch (r) {
15561 case 0:
15562 break;
15563
15564 case ECONNABORTED:
15565 warn(gettext("Could not refresh %s "
15566 "(repository connection broken).\n"), fmribuf);
15567 break;
15568
15569 case ECANCELED:
15570 warn(emsg_deleted);
15571 break;
15572
15573 case EPERM:
15574 warn(gettext("Could not refresh %s "
15575 "(permission denied).\n"), fmribuf);
15576 break;
15577
15578 case ENOSPC:
15579 warn(gettext("Could not refresh %s "
15580 "(repository server out of resources).\n"),
15581 fmribuf);
15582 break;
15583
15584 case EACCES:
15585 default:
15586 bad_error("refresh_entity", scf_error());
15587 }
15588
15589 free(fmribuf);
15590 }
15591
15592 /*
15593 * describe [-v] [-t] [pg/prop]
15594 */
15595 int
lscf_describe(uu_list_t * args,int hasargs)15596 lscf_describe(uu_list_t *args, int hasargs)
15597 {
15598 int ret = 0;
15599 size_t i;
15600 int argc;
15601 char **argv = NULL;
15602 string_list_t *slp;
15603 int do_verbose = 0;
15604 int do_templates = 0;
15605 char *pattern = NULL;
15606
15607 lscf_prep_hndl();
15608
15609 if (hasargs != 0) {
15610 argc = uu_list_numnodes(args);
15611 if (argc < 1)
15612 goto usage;
15613
15614 argv = calloc(argc + 1, sizeof (char *));
15615 if (argv == NULL)
15616 uu_die(gettext("Out of memory.\n"));
15617
15618 for (slp = uu_list_first(args), i = 0;
15619 slp != NULL;
15620 slp = uu_list_next(args, slp), ++i)
15621 argv[i] = slp->str;
15622
15623 argv[i] = NULL;
15624
15625 /*
15626 * We start optind = 0 because our list of arguments
15627 * starts at argv[0]
15628 */
15629 optind = 0;
15630 opterr = 0;
15631 for (;;) {
15632 ret = getopt(argc, argv, "vt");
15633 if (ret == -1)
15634 break;
15635
15636 switch (ret) {
15637 case 'v':
15638 do_verbose = 1;
15639 break;
15640
15641 case 't':
15642 do_templates = 1;
15643 break;
15644
15645 case '?':
15646 goto usage;
15647
15648 default:
15649 bad_error("getopt", ret);
15650 }
15651 }
15652
15653 pattern = argv[optind];
15654 }
15655
15656 if (cur_inst == NULL && cur_svc == NULL) {
15657 semerr(emsg_entity_not_selected);
15658 ret = -1;
15659 goto out;
15660 }
15661
15662 /*
15663 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15664 * output if their last parameter is set to 2. Less information is
15665 * produced if the parameter is set to 1.
15666 */
15667 if (pattern == NULL) {
15668 if (do_verbose == 1)
15669 list_entity_tmpl(2);
15670 else
15671 list_entity_tmpl(1);
15672 }
15673
15674 if (do_templates == 0) {
15675 if (do_verbose == 1)
15676 listprop(pattern, 0, 2);
15677 else
15678 listprop(pattern, 0, 1);
15679 } else {
15680 if (do_verbose == 1)
15681 listtmpl(pattern, 2);
15682 else
15683 listtmpl(pattern, 1);
15684 }
15685
15686 ret = 0;
15687 out:
15688 if (argv != NULL)
15689 free(argv);
15690 return (ret);
15691 usage:
15692 ret = -2;
15693 goto out;
15694 }
15695
15696 #define PARAM_ACTIVE ((const char *) "active")
15697 #define PARAM_INACTIVE ((const char *) "inactive")
15698 #define PARAM_SMTP_TO ((const char *) "to")
15699
15700 /*
15701 * tokenize()
15702 * Breaks down the string according to the tokens passed.
15703 * Caller is responsible for freeing array of pointers returned.
15704 * Returns NULL on failure
15705 */
15706 char **
tokenize(char * str,const char * sep)15707 tokenize(char *str, const char *sep)
15708 {
15709 char *token, *lasts;
15710 char **buf;
15711 int n = 0; /* number of elements */
15712 int size = 8; /* size of the array (initial) */
15713
15714 buf = safe_malloc(size * sizeof (char *));
15715
15716 for (token = strtok_r(str, sep, &lasts); token != NULL;
15717 token = strtok_r(NULL, sep, &lasts), ++n) {
15718 if (n + 1 >= size) {
15719 size *= 2;
15720 if ((buf = realloc(buf, size * sizeof (char *))) ==
15721 NULL) {
15722 uu_die(gettext("Out of memory"));
15723 }
15724 }
15725 buf[n] = token;
15726 }
15727 /* NULL terminate the pointer array */
15728 buf[n] = NULL;
15729
15730 return (buf);
15731 }
15732
15733 int32_t
check_tokens(char ** p)15734 check_tokens(char **p)
15735 {
15736 int32_t smf = 0;
15737 int32_t fma = 0;
15738
15739 while (*p) {
15740 int32_t t = string_to_tset(*p);
15741
15742 if (t == 0) {
15743 if (is_fma_token(*p) == 0)
15744 return (INVALID_TOKENS);
15745 fma = 1; /* this token is an fma event */
15746 } else {
15747 smf |= t;
15748 }
15749
15750 if (smf != 0 && fma == 1)
15751 return (MIXED_TOKENS);
15752 ++p;
15753 }
15754
15755 if (smf > 0)
15756 return (smf);
15757 else if (fma == 1)
15758 return (FMA_TOKENS);
15759
15760 return (INVALID_TOKENS);
15761 }
15762
15763 static int
get_selection_str(char * fmri,size_t sz)15764 get_selection_str(char *fmri, size_t sz)
15765 {
15766 if (g_hndl == NULL) {
15767 semerr(emsg_entity_not_selected);
15768 return (-1);
15769 } else if (cur_level != NULL) {
15770 semerr(emsg_invalid_for_snapshot);
15771 return (-1);
15772 } else {
15773 lscf_get_selection_str(fmri, sz);
15774 }
15775
15776 return (0);
15777 }
15778
15779 void
lscf_delnotify(const char * set,int global)15780 lscf_delnotify(const char *set, int global)
15781 {
15782 char *str = strdup(set);
15783 char **pgs;
15784 char **p;
15785 int32_t tset;
15786 char *fmri = NULL;
15787
15788 if (str == NULL)
15789 uu_die(gettext("Out of memory.\n"));
15790
15791 pgs = tokenize(str, ",");
15792
15793 if ((tset = check_tokens(pgs)) > 0) {
15794 size_t sz = max_scf_fmri_len + 1;
15795
15796 fmri = safe_malloc(sz);
15797 if (global) {
15798 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15799 } else if (get_selection_str(fmri, sz) != 0) {
15800 goto out;
15801 }
15802
15803 if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri,
15804 tset) != SCF_SUCCESS) {
15805 uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15806 scf_strerror(scf_error()));
15807 }
15808 } else if (tset == FMA_TOKENS) {
15809 if (global) {
15810 semerr(gettext("Can't use option '-g' with FMA event "
15811 "definitions\n"));
15812 goto out;
15813 }
15814
15815 for (p = pgs; *p; ++p) {
15816 if (smf_notify_del_params(de_tag(*p), NULL, 0) !=
15817 SCF_SUCCESS) {
15818 uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
15819 scf_strerror(scf_error()));
15820 goto out;
15821 }
15822 }
15823 } else if (tset == MIXED_TOKENS) {
15824 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15825 goto out;
15826 } else {
15827 uu_die(gettext("Invalid input.\n"));
15828 }
15829
15830 out:
15831 free(fmri);
15832 free(pgs);
15833 free(str);
15834 }
15835
15836 void
lscf_listnotify(const char * set,int global)15837 lscf_listnotify(const char *set, int global)
15838 {
15839 char *str = safe_strdup(set);
15840 char **pgs;
15841 char **p;
15842 int32_t tset;
15843 nvlist_t *nvl;
15844 char *fmri = NULL;
15845
15846 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
15847 uu_die(gettext("Out of memory.\n"));
15848
15849 pgs = tokenize(str, ",");
15850
15851 if ((tset = check_tokens(pgs)) > 0) {
15852 size_t sz = max_scf_fmri_len + 1;
15853
15854 fmri = safe_malloc(sz);
15855 if (global) {
15856 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15857 } else if (get_selection_str(fmri, sz) != 0) {
15858 goto out;
15859 }
15860
15861 if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
15862 SCF_SUCCESS) {
15863 if (scf_error() != SCF_ERROR_NOT_FOUND &&
15864 scf_error() != SCF_ERROR_DELETED)
15865 uu_warn(gettext(
15866 "Failed listnotify: %s\n"),
15867 scf_strerror(scf_error()));
15868 goto out;
15869 }
15870
15871 listnotify_print(nvl, NULL);
15872 } else if (tset == FMA_TOKENS) {
15873 if (global) {
15874 semerr(gettext("Can't use option '-g' with FMA event "
15875 "definitions\n"));
15876 goto out;
15877 }
15878
15879 for (p = pgs; *p; ++p) {
15880 if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
15881 SCF_SUCCESS) {
15882 /*
15883 * if the preferences have just been deleted
15884 * or does not exist, just skip.
15885 */
15886 if (scf_error() == SCF_ERROR_NOT_FOUND ||
15887 scf_error() == SCF_ERROR_DELETED)
15888 continue;
15889 uu_warn(gettext(
15890 "Failed listnotify: %s\n"),
15891 scf_strerror(scf_error()));
15892 goto out;
15893 }
15894 listnotify_print(nvl, re_tag(*p));
15895 }
15896 } else if (tset == MIXED_TOKENS) {
15897 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15898 goto out;
15899 } else {
15900 semerr(gettext("Invalid input.\n"));
15901 }
15902
15903 out:
15904 nvlist_free(nvl);
15905 free(fmri);
15906 free(pgs);
15907 free(str);
15908 }
15909
15910 static char *
strip_quotes_and_blanks(char * s)15911 strip_quotes_and_blanks(char *s)
15912 {
15913 char *start = s;
15914 char *end = strrchr(s, '\"');
15915
15916 if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
15917 start = s + 1;
15918 while (isblank(*start))
15919 start++;
15920 while (isblank(*(end - 1)) && end > start) {
15921 end--;
15922 }
15923 *end = '\0';
15924 }
15925
15926 return (start);
15927 }
15928
15929 static int
set_active(nvlist_t * mech,const char * hier_part)15930 set_active(nvlist_t *mech, const char *hier_part)
15931 {
15932 boolean_t b;
15933
15934 if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
15935 b = B_TRUE;
15936 } else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
15937 b = B_FALSE;
15938 } else {
15939 return (-1);
15940 }
15941
15942 if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
15943 uu_die(gettext("Out of memory.\n"));
15944
15945 return (0);
15946 }
15947
15948 static int
add_snmp_params(nvlist_t * mech,char * hier_part)15949 add_snmp_params(nvlist_t *mech, char *hier_part)
15950 {
15951 return (set_active(mech, hier_part));
15952 }
15953
15954 static int
add_syslog_params(nvlist_t * mech,char * hier_part)15955 add_syslog_params(nvlist_t *mech, char *hier_part)
15956 {
15957 return (set_active(mech, hier_part));
15958 }
15959
15960 /*
15961 * add_mailto_paramas()
15962 * parse the hier_part of mailto URI
15963 * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
15964 * or mailto:{[active]|inactive}
15965 */
15966 static int
add_mailto_params(nvlist_t * mech,char * hier_part)15967 add_mailto_params(nvlist_t *mech, char *hier_part)
15968 {
15969 const char *tok = "?&";
15970 char *p;
15971 char *lasts;
15972 char *param;
15973 char *val;
15974
15975 /*
15976 * If the notification parametes are in the form of
15977 *
15978 * malito:{[active]|inactive}
15979 *
15980 * we set the property accordingly and return.
15981 * Otherwise, we make the notification type active and
15982 * process the hier_part.
15983 */
15984 if (set_active(mech, hier_part) == 0)
15985 return (0);
15986 else if (set_active(mech, PARAM_ACTIVE) != 0)
15987 return (-1);
15988
15989 if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) {
15990 /*
15991 * sanity check: we only get here if hier_part = "", but
15992 * that's handled by set_active
15993 */
15994 uu_die("strtok_r");
15995 }
15996
15997 if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0)
15998 uu_die(gettext("Out of memory.\n"));
15999
16000 while ((p = strtok_r(NULL, tok, &lasts)) != NULL)
16001 if ((param = strtok_r(p, "=", &val)) != NULL)
16002 if (nvlist_add_string(mech, param, val) != 0)
16003 uu_die(gettext("Out of memory.\n"));
16004
16005 return (0);
16006 }
16007
16008 static int
uri_split(char * uri,char ** scheme,char ** hier_part)16009 uri_split(char *uri, char **scheme, char **hier_part)
16010 {
16011 int r = -1;
16012
16013 if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
16014 *hier_part == NULL) {
16015 semerr(gettext("'%s' is not an URI\n"), uri);
16016 return (r);
16017 }
16018
16019 if ((r = check_uri_scheme(*scheme)) < 0) {
16020 semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
16021 return (r);
16022 }
16023
16024 return (r);
16025 }
16026
16027 static int
process_uri(nvlist_t * params,char * uri)16028 process_uri(nvlist_t *params, char *uri)
16029 {
16030 char *scheme;
16031 char *hier_part;
16032 nvlist_t *mech;
16033 int index;
16034 int r;
16035
16036 if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
16037 return (-1);
16038
16039 if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
16040 uu_die(gettext("Out of memory.\n"));
16041
16042 switch (index) {
16043 case 0:
16044 /* error messages displayed by called function */
16045 r = add_mailto_params(mech, hier_part);
16046 break;
16047
16048 case 1:
16049 if ((r = add_snmp_params(mech, hier_part)) != 0)
16050 semerr(gettext("Not valid parameters: '%s'\n"),
16051 hier_part);
16052 break;
16053
16054 case 2:
16055 if ((r = add_syslog_params(mech, hier_part)) != 0)
16056 semerr(gettext("Not valid parameters: '%s'\n"),
16057 hier_part);
16058 break;
16059
16060 default:
16061 r = -1;
16062 }
16063
16064 if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
16065 mech) != 0)
16066 uu_die(gettext("Out of memory.\n"));
16067
16068 nvlist_free(mech);
16069 return (r);
16070 }
16071
16072 static int
set_params(nvlist_t * params,char ** p)16073 set_params(nvlist_t *params, char **p)
16074 {
16075 char *uri;
16076
16077 if (p == NULL)
16078 /* sanity check */
16079 uu_die("set_params");
16080
16081 while (*p) {
16082 uri = strip_quotes_and_blanks(*p);
16083 if (process_uri(params, uri) != 0)
16084 return (-1);
16085
16086 ++p;
16087 }
16088
16089 return (0);
16090 }
16091
16092 static int
setnotify(const char * e,char ** p,int global)16093 setnotify(const char *e, char **p, int global)
16094 {
16095 char *str = safe_strdup(e);
16096 char **events;
16097 int32_t tset;
16098 int r = -1;
16099 nvlist_t *nvl, *params;
16100 char *fmri = NULL;
16101
16102 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
16103 nvlist_alloc(¶ms, NV_UNIQUE_NAME, 0) != 0 ||
16104 nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
16105 SCF_NOTIFY_PARAMS_VERSION) != 0)
16106 uu_die(gettext("Out of memory.\n"));
16107
16108 events = tokenize(str, ",");
16109
16110 if ((tset = check_tokens(events)) > 0) {
16111 /* SMF state transitions parameters */
16112 size_t sz = max_scf_fmri_len + 1;
16113
16114 fmri = safe_malloc(sz);
16115 if (global) {
16116 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
16117 } else if (get_selection_str(fmri, sz) != 0) {
16118 goto out;
16119 }
16120
16121 if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 ||
16122 nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0)
16123 uu_die(gettext("Out of memory.\n"));
16124
16125 if ((r = set_params(params, p)) == 0) {
16126 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS,
16127 params) != 0)
16128 uu_die(gettext("Out of memory.\n"));
16129
16130 if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
16131 nvl) != SCF_SUCCESS) {
16132 r = -1;
16133 uu_warn(gettext(
16134 "Failed smf_notify_set_params(3SCF): %s\n"),
16135 scf_strerror(scf_error()));
16136 }
16137 }
16138 } else if (tset == FMA_TOKENS) {
16139 /* FMA event parameters */
16140 if (global) {
16141 semerr(gettext("Can't use option '-g' with FMA event "
16142 "definitions\n"));
16143 goto out;
16144 }
16145
16146 if ((r = set_params(params, p)) != 0)
16147 goto out;
16148
16149 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
16150 uu_die(gettext("Out of memory.\n"));
16151
16152 while (*events) {
16153 if (smf_notify_set_params(de_tag(*events), nvl) !=
16154 SCF_SUCCESS)
16155 uu_warn(gettext(
16156 "Failed smf_notify_set_params(3SCF) for "
16157 "event %s: %s\n"), *events,
16158 scf_strerror(scf_error()));
16159 events++;
16160 }
16161 } else if (tset == MIXED_TOKENS) {
16162 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
16163 } else {
16164 /* Sanity check */
16165 uu_die(gettext("Invalid input.\n"));
16166 }
16167
16168 out:
16169 nvlist_free(nvl);
16170 nvlist_free(params);
16171 free(fmri);
16172 free(str);
16173
16174 return (r);
16175 }
16176
16177 int
lscf_setnotify(uu_list_t * args)16178 lscf_setnotify(uu_list_t *args)
16179 {
16180 int argc;
16181 char **argv = NULL;
16182 string_list_t *slp;
16183 int global;
16184 char *events;
16185 char **p;
16186 int i;
16187 int ret;
16188
16189 if ((argc = uu_list_numnodes(args)) < 2)
16190 goto usage;
16191
16192 argv = calloc(argc + 1, sizeof (char *));
16193 if (argv == NULL)
16194 uu_die(gettext("Out of memory.\n"));
16195
16196 for (slp = uu_list_first(args), i = 0;
16197 slp != NULL;
16198 slp = uu_list_next(args, slp), ++i)
16199 argv[i] = slp->str;
16200
16201 argv[i] = NULL;
16202
16203 if (strcmp(argv[0], "-g") == 0) {
16204 global = 1;
16205 events = argv[1];
16206 p = argv + 2;
16207 } else {
16208 global = 0;
16209 events = argv[0];
16210 p = argv + 1;
16211 }
16212
16213 ret = setnotify(events, p, global);
16214
16215 out:
16216 free(argv);
16217 return (ret);
16218
16219 usage:
16220 ret = -2;
16221 goto out;
16222 }
16223
16224 /*
16225 * Creates a list of instance name strings associated with a service. If
16226 * wohandcrafted flag is set, get only instances that have a last-import
16227 * snapshot, instances that were imported via svccfg.
16228 */
16229 static uu_list_t *
create_instance_list(scf_service_t * svc,int wohandcrafted)16230 create_instance_list(scf_service_t *svc, int wohandcrafted)
16231 {
16232 scf_snapshot_t *snap = NULL;
16233 scf_instance_t *inst;
16234 scf_iter_t *inst_iter;
16235 uu_list_t *instances;
16236 char *instname;
16237 int r;
16238
16239 inst_iter = scf_iter_create(g_hndl);
16240 inst = scf_instance_create(g_hndl);
16241 if (inst_iter == NULL || inst == NULL) {
16242 uu_warn(gettext("Could not create instance or iterator\n"));
16243 scfdie();
16244 }
16245
16246 if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
16247 return (instances);
16248
16249 if (scf_iter_service_instances(inst_iter, svc) != 0) {
16250 switch (scf_error()) {
16251 case SCF_ERROR_CONNECTION_BROKEN:
16252 case SCF_ERROR_DELETED:
16253 uu_list_destroy(instances);
16254 instances = NULL;
16255 goto out;
16256
16257 case SCF_ERROR_HANDLE_MISMATCH:
16258 case SCF_ERROR_NOT_BOUND:
16259 case SCF_ERROR_NOT_SET:
16260 default:
16261 bad_error("scf_iter_service_instances", scf_error());
16262 }
16263 }
16264
16265 instname = safe_malloc(max_scf_name_len + 1);
16266 while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
16267 if (r == -1) {
16268 (void) uu_warn(gettext("Unable to iterate through "
16269 "instances to create instance list : %s\n"),
16270 scf_strerror(scf_error()));
16271
16272 uu_list_destroy(instances);
16273 instances = NULL;
16274 goto out;
16275 }
16276
16277 /*
16278 * If the instance does not have a last-import snapshot
16279 * then do not add it to the list as it is a hand-crafted
16280 * instance that should not be managed.
16281 */
16282 if (wohandcrafted) {
16283 if (snap == NULL &&
16284 (snap = scf_snapshot_create(g_hndl)) == NULL) {
16285 uu_warn(gettext("Unable to create snapshot "
16286 "entity\n"));
16287 scfdie();
16288 }
16289
16290 if (scf_instance_get_snapshot(inst,
16291 snap_lastimport, snap) != 0) {
16292 switch (scf_error()) {
16293 case SCF_ERROR_NOT_FOUND :
16294 case SCF_ERROR_DELETED:
16295 continue;
16296
16297 case SCF_ERROR_CONNECTION_BROKEN:
16298 uu_list_destroy(instances);
16299 instances = NULL;
16300 goto out;
16301
16302 case SCF_ERROR_HANDLE_MISMATCH:
16303 case SCF_ERROR_NOT_BOUND:
16304 case SCF_ERROR_NOT_SET:
16305 default:
16306 bad_error("scf_iter_service_instances",
16307 scf_error());
16308 }
16309 }
16310 }
16311
16312 if (scf_instance_get_name(inst, instname,
16313 max_scf_name_len + 1) < 0) {
16314 switch (scf_error()) {
16315 case SCF_ERROR_NOT_FOUND :
16316 continue;
16317
16318 case SCF_ERROR_CONNECTION_BROKEN:
16319 case SCF_ERROR_DELETED:
16320 uu_list_destroy(instances);
16321 instances = NULL;
16322 goto out;
16323
16324 case SCF_ERROR_HANDLE_MISMATCH:
16325 case SCF_ERROR_NOT_BOUND:
16326 case SCF_ERROR_NOT_SET:
16327 default:
16328 bad_error("scf_iter_service_instances",
16329 scf_error());
16330 }
16331 }
16332
16333 add_string(instances, instname);
16334 }
16335
16336 out:
16337 if (snap)
16338 scf_snapshot_destroy(snap);
16339
16340 scf_instance_destroy(inst);
16341 scf_iter_destroy(inst_iter);
16342 free(instname);
16343 return (instances);
16344 }
16345
16346 /*
16347 * disable an instance but wait for the instance to
16348 * move out of the running state.
16349 *
16350 * Returns 0 : if the instance did not disable
16351 * Returns non-zero : if the instance disabled.
16352 *
16353 */
16354 static int
disable_instance(scf_instance_t * instance)16355 disable_instance(scf_instance_t *instance)
16356 {
16357 char *fmribuf;
16358 int enabled = 10000;
16359
16360 if (inst_is_running(instance)) {
16361 fmribuf = safe_malloc(max_scf_name_len + 1);
16362 if (scf_instance_to_fmri(instance, fmribuf,
16363 max_scf_name_len + 1) < 0) {
16364 free(fmribuf);
16365 return (0);
16366 }
16367
16368 /*
16369 * If the instance cannot be disabled then return
16370 * failure to disable and let the caller decide
16371 * if that is of importance.
16372 */
16373 if (smf_disable_instance(fmribuf, 0) != 0) {
16374 free(fmribuf);
16375 return (0);
16376 }
16377
16378 while (enabled) {
16379 if (!inst_is_running(instance))
16380 break;
16381
16382 (void) poll(NULL, 0, 5);
16383 enabled = enabled - 5;
16384 }
16385
16386 free(fmribuf);
16387 }
16388
16389 return (enabled);
16390 }
16391
16392 /*
16393 * Function to compare two service_manifest structures.
16394 */
16395 /* ARGSUSED2 */
16396 static int
service_manifest_compare(const void * left,const void * right,void * unused)16397 service_manifest_compare(const void *left, const void *right, void *unused)
16398 {
16399 service_manifest_t *l = (service_manifest_t *)left;
16400 service_manifest_t *r = (service_manifest_t *)right;
16401 int rc;
16402
16403 rc = strcmp(l->servicename, r->servicename);
16404
16405 return (rc);
16406 }
16407
16408 /*
16409 * Look for the provided service in the service to manifest
16410 * tree. If the service exists, and a manifest was provided
16411 * then add the manifest to that service. If the service
16412 * does not exist, then add the service and manifest to the
16413 * list.
16414 *
16415 * If the manifest is NULL, return the element if found. If
16416 * the service is not found return NULL.
16417 */
16418 service_manifest_t *
find_add_svc_mfst(const char * svnbuf,const char * mfst)16419 find_add_svc_mfst(const char *svnbuf, const char *mfst)
16420 {
16421 service_manifest_t elem;
16422 service_manifest_t *fnelem;
16423 uu_avl_index_t marker;
16424
16425 elem.servicename = svnbuf;
16426 fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
16427
16428 if (mfst) {
16429 if (fnelem) {
16430 add_string(fnelem->mfstlist, strdup(mfst));
16431 } else {
16432 fnelem = safe_malloc(sizeof (*fnelem));
16433 fnelem->servicename = safe_strdup(svnbuf);
16434 if ((fnelem->mfstlist =
16435 uu_list_create(string_pool, NULL, 0)) == NULL)
16436 uu_die(gettext("Could not create property "
16437 "list: %s\n"), uu_strerror(uu_error()));
16438
16439 add_string(fnelem->mfstlist, safe_strdup(mfst));
16440
16441 uu_avl_insert(service_manifest_tree, fnelem, marker);
16442 }
16443 }
16444
16445 return (fnelem);
16446 }
16447
16448 /*
16449 * Create the service to manifest avl tree.
16450 *
16451 * Walk each of the manifests currently installed in the supported
16452 * directories, /lib/svc/manifests and /var/svc/manifests. For
16453 * each of the manifests, inventory the services and add them to
16454 * the tree.
16455 *
16456 * Code that calls this function should make sure fileystem/minimal is online,
16457 * /var is available, since this function walks the /var/svc/manifest directory.
16458 */
16459 static void
create_manifest_tree(void)16460 create_manifest_tree(void)
16461 {
16462 manifest_info_t **entry;
16463 manifest_info_t **manifests;
16464 uu_list_walk_t *svcs;
16465 bundle_t *b;
16466 entity_t *mfsvc;
16467 char *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
16468 int c, status;
16469
16470 if (service_manifest_pool)
16471 return;
16472
16473 /*
16474 * Create the list pool for the service manifest list
16475 */
16476 service_manifest_pool = uu_avl_pool_create("service_manifest",
16477 sizeof (service_manifest_t),
16478 offsetof(service_manifest_t, svcmfst_node),
16479 service_manifest_compare, UU_DEFAULT);
16480 if (service_manifest_pool == NULL)
16481 uu_die(gettext("service_manifest pool creation failed: %s\n"),
16482 uu_strerror(uu_error()));
16483
16484 /*
16485 * Create the list
16486 */
16487 service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
16488 UU_DEFAULT);
16489 if (service_manifest_tree == NULL)
16490 uu_die(gettext("service_manifest tree creation failed: %s\n"),
16491 uu_strerror(uu_error()));
16492
16493 /*
16494 * Walk the manifests adding the service(s) from each manifest.
16495 *
16496 * If a service already exists add the manifest to the manifest
16497 * list for that service. This covers the case of a service that
16498 * is supported by multiple manifest files.
16499 */
16500 for (c = 0; dirs[c]; c++) {
16501 status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT);
16502 if (status < 0) {
16503 uu_warn(gettext("file tree walk of %s encountered "
16504 "error %s\n"), dirs[c], strerror(errno));
16505
16506 uu_avl_destroy(service_manifest_tree);
16507 service_manifest_tree = NULL;
16508 return;
16509 }
16510
16511 /*
16512 * If a manifest that was in the list is not found
16513 * then skip and go to the next manifest file.
16514 */
16515 if (manifests != NULL) {
16516 for (entry = manifests; *entry != NULL; entry++) {
16517 b = internal_bundle_new();
16518 if (lxml_get_bundle_file(b, (*entry)->mi_path,
16519 SVCCFG_OP_IMPORT) != 0) {
16520 internal_bundle_free(b);
16521 continue;
16522 }
16523
16524 svcs = uu_list_walk_start(b->sc_bundle_services,
16525 0);
16526 if (svcs == NULL) {
16527 internal_bundle_free(b);
16528 continue;
16529 }
16530
16531 while ((mfsvc = uu_list_walk_next(svcs)) !=
16532 NULL) {
16533 /* Add manifest to service */
16534 (void) find_add_svc_mfst(mfsvc->sc_name,
16535 (*entry)->mi_path);
16536 }
16537
16538 uu_list_walk_end(svcs);
16539 internal_bundle_free(b);
16540 }
16541
16542 free_manifest_array(manifests);
16543 }
16544 }
16545 }
16546
16547 /*
16548 * Check the manifest history file to see
16549 * if the service was ever installed from
16550 * one of the supported directories.
16551 *
16552 * Return Values :
16553 * -1 - if there's error reading manifest history file
16554 * 1 - if the service is not found
16555 * 0 - if the service is found
16556 */
16557 static int
check_mfst_history(const char * svcname)16558 check_mfst_history(const char *svcname)
16559 {
16560 struct stat st;
16561 caddr_t mfsthist_start;
16562 char *svnbuf;
16563 int fd;
16564 int r = 1;
16565
16566 fd = open(MFSTHISTFILE, O_RDONLY);
16567 if (fd == -1) {
16568 uu_warn(gettext("Unable to open the history file\n"));
16569 return (-1);
16570 }
16571
16572 if (fstat(fd, &st) == -1) {
16573 uu_warn(gettext("Unable to stat the history file\n"));
16574 return (-1);
16575 }
16576
16577 mfsthist_start = mmap(0, st.st_size, PROT_READ,
16578 MAP_PRIVATE, fd, 0);
16579
16580 (void) close(fd);
16581 if (mfsthist_start == MAP_FAILED ||
16582 *(mfsthist_start + st.st_size) != '\0') {
16583 (void) munmap(mfsthist_start, st.st_size);
16584 return (-1);
16585 }
16586
16587 /*
16588 * The manifest history file is a space delimited list
16589 * of service and instance to manifest linkage. Adding
16590 * a space to the end of the service name so to get only
16591 * the service that is being searched for.
16592 */
16593 svnbuf = uu_msprintf("%s ", svcname);
16594 if (svnbuf == NULL)
16595 uu_die(gettext("Out of memory"));
16596
16597 if (strstr(mfsthist_start, svnbuf) != NULL)
16598 r = 0;
16599
16600 (void) munmap(mfsthist_start, st.st_size);
16601 uu_free(svnbuf);
16602 return (r);
16603 }
16604
16605 /*
16606 * Take down each of the instances in the service
16607 * and remove them, then delete the service.
16608 */
16609 static void
teardown_service(scf_service_t * svc,const char * svnbuf)16610 teardown_service(scf_service_t *svc, const char *svnbuf)
16611 {
16612 scf_instance_t *instance;
16613 scf_iter_t *iter;
16614 int r;
16615
16616 safe_printf(gettext("Delete service %s as there are no "
16617 "supporting manifests\n"), svnbuf);
16618
16619 instance = scf_instance_create(g_hndl);
16620 iter = scf_iter_create(g_hndl);
16621 if (iter == NULL || instance == NULL) {
16622 uu_warn(gettext("Unable to create supporting entities to "
16623 "teardown the service\n"));
16624 uu_warn(gettext("scf error is : %s\n"),
16625 scf_strerror(scf_error()));
16626 scfdie();
16627 }
16628
16629 if (scf_iter_service_instances(iter, svc) != 0) {
16630 switch (scf_error()) {
16631 case SCF_ERROR_CONNECTION_BROKEN:
16632 case SCF_ERROR_DELETED:
16633 goto out;
16634
16635 case SCF_ERROR_HANDLE_MISMATCH:
16636 case SCF_ERROR_NOT_BOUND:
16637 case SCF_ERROR_NOT_SET:
16638 default:
16639 bad_error("scf_iter_service_instances",
16640 scf_error());
16641 }
16642 }
16643
16644 while ((r = scf_iter_next_instance(iter, instance)) != 0) {
16645 if (r == -1) {
16646 uu_warn(gettext("Error - %s\n"),
16647 scf_strerror(scf_error()));
16648 goto out;
16649 }
16650
16651 (void) disable_instance(instance);
16652 }
16653
16654 /*
16655 * Delete the service... forcing the deletion in case
16656 * any of the instances did not disable.
16657 */
16658 (void) lscf_service_delete(svc, 1);
16659 out:
16660 scf_instance_destroy(instance);
16661 scf_iter_destroy(iter);
16662 }
16663
16664 /*
16665 * Get the list of instances supported by the manifest
16666 * file.
16667 *
16668 * Return 0 if there are no instances.
16669 *
16670 * Return -1 if there are errors attempting to collect instances.
16671 *
16672 * Return the count of instances found if there are no errors.
16673 *
16674 */
16675 static int
check_instance_support(char * mfstfile,const char * svcname,uu_list_t * instances)16676 check_instance_support(char *mfstfile, const char *svcname,
16677 uu_list_t *instances)
16678 {
16679 uu_list_walk_t *svcs, *insts;
16680 uu_list_t *ilist;
16681 bundle_t *b;
16682 entity_t *mfsvc, *mfinst;
16683 const char *svcn;
16684 int rminstcnt = 0;
16685
16686
16687 b = internal_bundle_new();
16688
16689 if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
16690 /*
16691 * Unable to process the manifest file for
16692 * instance support, so just return as
16693 * don't want to remove instances that could
16694 * not be accounted for that might exist here.
16695 */
16696 internal_bundle_free(b);
16697 return (0);
16698 }
16699
16700 svcs = uu_list_walk_start(b->sc_bundle_services, 0);
16701 if (svcs == NULL) {
16702 internal_bundle_free(b);
16703 return (0);
16704 }
16705
16706 svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
16707 (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
16708
16709 while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
16710 if (strcmp(mfsvc->sc_name, svcn) == 0)
16711 break;
16712 }
16713 uu_list_walk_end(svcs);
16714
16715 if (mfsvc == NULL) {
16716 internal_bundle_free(b);
16717 return (-1);
16718 }
16719
16720 ilist = mfsvc->sc_u.sc_service.sc_service_instances;
16721 if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
16722 internal_bundle_free(b);
16723 return (0);
16724 }
16725
16726 while ((mfinst = uu_list_walk_next(insts)) != NULL) {
16727 /*
16728 * Remove the instance from the instances list.
16729 * The unaccounted for instances will be removed
16730 * from the service once all manifests are
16731 * processed.
16732 */
16733 (void) remove_string(instances,
16734 mfinst->sc_name);
16735 rminstcnt++;
16736 }
16737
16738 uu_list_walk_end(insts);
16739 internal_bundle_free(b);
16740
16741 return (rminstcnt);
16742 }
16743
16744 /*
16745 * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16746 * 'false' to indicate there's no manifest file(s) found for the service.
16747 */
16748 static void
svc_add_no_support(scf_service_t * svc)16749 svc_add_no_support(scf_service_t *svc)
16750 {
16751 char *pname;
16752
16753 /* Add no support */
16754 cur_svc = svc;
16755 if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
16756 return;
16757
16758 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
16759 if (pname == NULL)
16760 uu_die(gettext("Out of memory.\n"));
16761
16762 (void) lscf_addpropvalue(pname, "boolean:", "0");
16763
16764 uu_free(pname);
16765 cur_svc = NULL;
16766 }
16767
16768 /*
16769 * This function handles all upgrade scenarios for a service that doesn't have
16770 * SCF_PG_MANIFESTFILES pg. The function creates and populates
16771 * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16772 * manifest(s) mapping. Manifests under supported directories are inventoried
16773 * and a property is added for each file that delivers configuration to the
16774 * service. A service that has no corresponding manifest files (deleted) are
16775 * removed from repository.
16776 *
16777 * Unsupported services:
16778 *
16779 * A service is considered unsupported if there is no corresponding manifest
16780 * in the supported directories for that service and the service isn't in the
16781 * history file list. The history file, MFSTHISTFILE, contains a list of all
16782 * services and instances that were delivered by Solaris before the introduction
16783 * of the SCF_PG_MANIFESTFILES property group. The history file also contains
16784 * the path to the manifest file that defined the service or instance.
16785 *
16786 * Another type of unsupported services is 'handcrafted' services,
16787 * programmatically created services or services created by dependent entries
16788 * in other manifests. A handcrafted service is identified by its lack of any
16789 * instance containing last-import snapshot which is created during svccfg
16790 * import.
16791 *
16792 * This function sets a flag for unsupported services by setting services'
16793 * SCF_PG_MANIFESTFILES/support property to false.
16794 */
16795 static void
upgrade_svc_mfst_connection(scf_service_t * svc,const char * svcname)16796 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
16797 {
16798 service_manifest_t *elem;
16799 uu_list_walk_t *mfwalk;
16800 string_list_t *mfile;
16801 uu_list_t *instances;
16802 const char *sname;
16803 char *pname;
16804 int r;
16805
16806 /*
16807 * Since there's no guarantee manifests under /var are available during
16808 * early import, don't perform any upgrade during early import.
16809 */
16810 if (IGNORE_VAR)
16811 return;
16812
16813 if (service_manifest_tree == NULL) {
16814 create_manifest_tree();
16815 }
16816
16817 /*
16818 * Find service's supporting manifest(s) after
16819 * stripping off the svc:/ prefix that is part
16820 * of the fmri that is not used in the service
16821 * manifest bundle list.
16822 */
16823 sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
16824 strlen(SCF_FMRI_SERVICE_PREFIX);
16825 elem = find_add_svc_mfst(sname, NULL);
16826 if (elem == NULL) {
16827
16828 /*
16829 * A handcrafted service, one that has no instance containing
16830 * last-import snapshot, should get unsupported flag.
16831 */
16832 instances = create_instance_list(svc, 1);
16833 if (instances == NULL) {
16834 uu_warn(gettext("Unable to create instance list %s\n"),
16835 svcname);
16836 return;
16837 }
16838
16839 if (uu_list_numnodes(instances) == 0) {
16840 svc_add_no_support(svc);
16841 return;
16842 }
16843
16844 /*
16845 * If the service is in the history file, and its supporting
16846 * manifests are not found, we can safely delete the service
16847 * because its manifests are removed from the system.
16848 *
16849 * Services not found in the history file are not delivered by
16850 * Solaris and/or delivered outside supported directories, set
16851 * unsupported flag for these services.
16852 */
16853 r = check_mfst_history(svcname);
16854 if (r == -1)
16855 return;
16856
16857 if (r) {
16858 /* Set unsupported flag for service */
16859 svc_add_no_support(svc);
16860 } else {
16861 /* Delete the service */
16862 teardown_service(svc, svcname);
16863 }
16864
16865 return;
16866 }
16867
16868 /*
16869 * Walk through the list of manifests and add them
16870 * to the service.
16871 *
16872 * Create a manifestfiles pg and add the property.
16873 */
16874 mfwalk = uu_list_walk_start(elem->mfstlist, 0);
16875 if (mfwalk == NULL)
16876 return;
16877
16878 cur_svc = svc;
16879 r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
16880 if (r != 0) {
16881 cur_svc = NULL;
16882 return;
16883 }
16884
16885 while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
16886 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16887 mhash_filename_to_propname(mfile->str, 0));
16888 if (pname == NULL)
16889 uu_die(gettext("Out of memory.\n"));
16890
16891 (void) lscf_addpropvalue(pname, "astring:", mfile->str);
16892 uu_free(pname);
16893 }
16894 uu_list_walk_end(mfwalk);
16895
16896 cur_svc = NULL;
16897 }
16898
16899 /*
16900 * Take a service and process the manifest file entires to see if
16901 * there is continued support for the service and instances. If
16902 * not cleanup as appropriate.
16903 *
16904 * If a service does not have a manifest files entry flag it for
16905 * upgrade and return.
16906 *
16907 * For each manifestfiles property check if the manifest file is
16908 * under the supported /lib/svc/manifest or /var/svc/manifest path
16909 * and if not then return immediately as this service is not supported
16910 * by the cleanup mechanism and should be ignored.
16911 *
16912 * For each manifest file that is supported, check to see if the
16913 * file exists. If not then remove the manifest file property
16914 * from the service and the smf/manifest hash table. If the manifest
16915 * file exists then verify that it supports the instances that are
16916 * part of the service.
16917 *
16918 * Once all manifest files have been accounted for remove any instances
16919 * that are no longer supported in the service.
16920 *
16921 * Return values :
16922 * 0 - Successfully processed the service
16923 * non-zero - failed to process the service
16924 *
16925 * On most errors, will just return to wait and get the next service,
16926 * unless in case of unable to create the needed structures which is
16927 * most likely a fatal error that is not going to be recoverable.
16928 */
16929 int
lscf_service_cleanup(void * act,scf_walkinfo_t * wip)16930 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
16931 {
16932 struct mpg_mfile *mpntov;
16933 struct mpg_mfile **mpvarry = NULL;
16934 scf_service_t *svc;
16935 scf_propertygroup_t *mpg;
16936 scf_property_t *mp;
16937 scf_value_t *mv;
16938 scf_iter_t *mi;
16939 scf_instance_t *instance;
16940 uu_list_walk_t *insts;
16941 uu_list_t *instances = NULL;
16942 boolean_t activity = (boolean_t)act;
16943 char *mpnbuf;
16944 char *mpvbuf;
16945 char *pgpropbuf;
16946 int mfstcnt, rminstct, instct, mfstmax;
16947 int index;
16948 int r = 0;
16949
16950 assert(g_hndl != NULL);
16951 assert(wip->svc != NULL);
16952 assert(wip->fmri != NULL);
16953
16954 svc = wip->svc;
16955
16956 mpg = scf_pg_create(g_hndl);
16957 mp = scf_property_create(g_hndl);
16958 mi = scf_iter_create(g_hndl);
16959 mv = scf_value_create(g_hndl);
16960 instance = scf_instance_create(g_hndl);
16961
16962 if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
16963 instance == NULL) {
16964 uu_warn(gettext("Unable to create the supporting entities\n"));
16965 uu_warn(gettext("scf error is : %s\n"),
16966 scf_strerror(scf_error()));
16967 scfdie();
16968 }
16969
16970 /*
16971 * Get the manifestfiles property group to be parsed for
16972 * files existence.
16973 */
16974 if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
16975 switch (scf_error()) {
16976 case SCF_ERROR_NOT_FOUND:
16977 upgrade_svc_mfst_connection(svc, wip->fmri);
16978 break;
16979 case SCF_ERROR_DELETED:
16980 case SCF_ERROR_CONNECTION_BROKEN:
16981 goto out;
16982
16983 case SCF_ERROR_HANDLE_MISMATCH:
16984 case SCF_ERROR_NOT_BOUND:
16985 case SCF_ERROR_NOT_SET:
16986 default:
16987 bad_error("scf_iter_pg_properties",
16988 scf_error());
16989 }
16990
16991 goto out;
16992 }
16993
16994 /*
16995 * Iterate through each of the manifestfiles properties
16996 * to determine what manifestfiles are available.
16997 *
16998 * If a manifest file is supported then increment the
16999 * count and therefore the service is safe.
17000 */
17001 if (scf_iter_pg_properties(mi, mpg) != 0) {
17002 switch (scf_error()) {
17003 case SCF_ERROR_DELETED:
17004 case SCF_ERROR_CONNECTION_BROKEN:
17005 goto out;
17006
17007 case SCF_ERROR_HANDLE_MISMATCH:
17008 case SCF_ERROR_NOT_BOUND:
17009 case SCF_ERROR_NOT_SET:
17010 default:
17011 bad_error("scf_iter_pg_properties",
17012 scf_error());
17013 }
17014 }
17015
17016 mfstcnt = 0;
17017 mfstmax = MFSTFILE_MAX;
17018 mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
17019 while ((r = scf_iter_next_property(mi, mp)) != 0) {
17020 if (r == -1)
17021 bad_error(gettext("Unable to iterate through "
17022 "manifestfiles properties : %s"),
17023 scf_error());
17024
17025 mpntov = safe_malloc(sizeof (struct mpg_mfile));
17026 mpnbuf = safe_malloc(max_scf_name_len + 1);
17027 mpvbuf = safe_malloc(max_scf_value_len + 1);
17028 mpntov->mpg = mpnbuf;
17029 mpntov->mfile = mpvbuf;
17030 mpntov->access = 1;
17031 if (scf_property_get_name(mp, mpnbuf,
17032 max_scf_name_len + 1) < 0) {
17033 uu_warn(gettext("Unable to get manifest file "
17034 "property : %s\n"),
17035 scf_strerror(scf_error()));
17036
17037 switch (scf_error()) {
17038 case SCF_ERROR_DELETED:
17039 case SCF_ERROR_CONNECTION_BROKEN:
17040 r = scferror2errno(scf_error());
17041 goto out_free;
17042
17043 case SCF_ERROR_HANDLE_MISMATCH:
17044 case SCF_ERROR_NOT_BOUND:
17045 case SCF_ERROR_NOT_SET:
17046 default:
17047 bad_error("scf_iter_pg_properties",
17048 scf_error());
17049 }
17050 }
17051
17052 /*
17053 * The support property is a boolean value that indicates
17054 * if the service is supported for manifest file deletion.
17055 * Currently at this time there is no code that sets this
17056 * value to true. So while we could just let this be caught
17057 * by the support check below, in the future this by be set
17058 * to true and require processing. So for that, go ahead
17059 * and check here, and just return if false. Otherwise,
17060 * fall through expecting that other support checks will
17061 * handle the entries.
17062 */
17063 if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
17064 uint8_t support;
17065
17066 if (scf_property_get_value(mp, mv) != 0 ||
17067 scf_value_get_boolean(mv, &support) != 0) {
17068 uu_warn(gettext("Unable to get the manifest "
17069 "support value: %s\n"),
17070 scf_strerror(scf_error()));
17071
17072 switch (scf_error()) {
17073 case SCF_ERROR_DELETED:
17074 case SCF_ERROR_CONNECTION_BROKEN:
17075 r = scferror2errno(scf_error());
17076 goto out_free;
17077
17078 case SCF_ERROR_HANDLE_MISMATCH:
17079 case SCF_ERROR_NOT_BOUND:
17080 case SCF_ERROR_NOT_SET:
17081 default:
17082 bad_error("scf_iter_pg_properties",
17083 scf_error());
17084 }
17085 }
17086
17087 if (support == B_FALSE)
17088 goto out_free;
17089 }
17090
17091 /*
17092 * Anything with a manifest outside of the supported
17093 * directories, immediately bail out because that makes
17094 * this service non-supported. We don't even want
17095 * to do instance processing in this case because the
17096 * instances could be part of the non-supported manifest.
17097 */
17098 if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
17099 /*
17100 * Manifest is not in /lib/svc, so we need to
17101 * consider the /var/svc case.
17102 */
17103 if (strncmp(mpnbuf, VARSVC_PR,
17104 strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
17105 /*
17106 * Either the manifest is not in /var/svc or
17107 * /var is not yet mounted. We ignore the
17108 * manifest either because it is not in a
17109 * standard location or because we cannot
17110 * currently access the manifest.
17111 */
17112 goto out_free;
17113 }
17114 }
17115
17116 /*
17117 * Get the value to of the manifest file for this entry
17118 * for access verification and instance support
17119 * verification if it still exists.
17120 *
17121 * During Early Manifest Import if the manifest is in
17122 * /var/svc then it may not yet be available for checking
17123 * so we must determine if /var/svc is available. If not
17124 * then defer until Late Manifest Import to cleanup.
17125 */
17126 if (scf_property_get_value(mp, mv) != 0) {
17127 uu_warn(gettext("Unable to get the manifest file "
17128 "value: %s\n"),
17129 scf_strerror(scf_error()));
17130
17131 switch (scf_error()) {
17132 case SCF_ERROR_DELETED:
17133 case SCF_ERROR_CONNECTION_BROKEN:
17134 r = scferror2errno(scf_error());
17135 goto out_free;
17136
17137 case SCF_ERROR_HANDLE_MISMATCH:
17138 case SCF_ERROR_NOT_BOUND:
17139 case SCF_ERROR_NOT_SET:
17140 default:
17141 bad_error("scf_property_get_value",
17142 scf_error());
17143 }
17144 }
17145
17146 if (scf_value_get_astring(mv, mpvbuf,
17147 max_scf_value_len + 1) < 0) {
17148 uu_warn(gettext("Unable to get the manifest "
17149 "file : %s\n"),
17150 scf_strerror(scf_error()));
17151
17152 switch (scf_error()) {
17153 case SCF_ERROR_DELETED:
17154 case SCF_ERROR_CONNECTION_BROKEN:
17155 r = scferror2errno(scf_error());
17156 goto out_free;
17157
17158 case SCF_ERROR_HANDLE_MISMATCH:
17159 case SCF_ERROR_NOT_BOUND:
17160 case SCF_ERROR_NOT_SET:
17161 default:
17162 bad_error("scf_value_get_astring",
17163 scf_error());
17164 }
17165 }
17166
17167 mpvarry[mfstcnt] = mpntov;
17168 mfstcnt++;
17169
17170 /*
17171 * Check for the need to reallocate array
17172 */
17173 if (mfstcnt >= (mfstmax - 1)) {
17174 struct mpg_mfile **newmpvarry;
17175
17176 mfstmax = mfstmax * 2;
17177 newmpvarry = realloc(mpvarry,
17178 sizeof (struct mpg_mfile *) * mfstmax);
17179
17180 if (newmpvarry == NULL)
17181 goto out_free;
17182
17183 mpvarry = newmpvarry;
17184 }
17185
17186 mpvarry[mfstcnt] = NULL;
17187 }
17188
17189 for (index = 0; mpvarry[index]; index++) {
17190 mpntov = mpvarry[index];
17191
17192 /*
17193 * Check to see if the manifestfile is accessable, if so hand
17194 * this service and manifestfile off to be processed for
17195 * instance support.
17196 */
17197 mpnbuf = mpntov->mpg;
17198 mpvbuf = mpntov->mfile;
17199 if (access(mpvbuf, F_OK) != 0) {
17200 mpntov->access = 0;
17201 activity++;
17202 mfstcnt--;
17203 /* Remove the entry from the service */
17204 cur_svc = svc;
17205 pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
17206 mpnbuf);
17207 if (pgpropbuf == NULL)
17208 uu_die(gettext("Out of memory.\n"));
17209
17210 lscf_delprop(pgpropbuf);
17211 cur_svc = NULL;
17212
17213 uu_free(pgpropbuf);
17214 }
17215 }
17216
17217 /*
17218 * If mfstcnt is 0, none of the manifests that supported the service
17219 * existed so remove the service.
17220 */
17221 if (mfstcnt == 0) {
17222 teardown_service(svc, wip->fmri);
17223
17224 goto out_free;
17225 }
17226
17227 if (activity) {
17228 int nosvcsupport = 0;
17229
17230 /*
17231 * If the list of service instances is NULL then
17232 * create the list.
17233 */
17234 instances = create_instance_list(svc, 1);
17235 if (instances == NULL) {
17236 uu_warn(gettext("Unable to create instance list %s\n"),
17237 wip->fmri);
17238 goto out_free;
17239 }
17240
17241 rminstct = uu_list_numnodes(instances);
17242 instct = rminstct;
17243
17244 for (index = 0; mpvarry[index]; index++) {
17245 mpntov = mpvarry[index];
17246 if (mpntov->access == 0)
17247 continue;
17248
17249 mpnbuf = mpntov->mpg;
17250 mpvbuf = mpntov->mfile;
17251 r = check_instance_support(mpvbuf, wip->fmri,
17252 instances);
17253 if (r == -1) {
17254 nosvcsupport++;
17255 } else {
17256 rminstct -= r;
17257 }
17258 }
17259
17260 if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
17261 teardown_service(svc, wip->fmri);
17262
17263 goto out_free;
17264 }
17265 }
17266
17267 /*
17268 * If there are instances left on the instance list, then
17269 * we must remove them.
17270 */
17271 if (instances != NULL && uu_list_numnodes(instances)) {
17272 string_list_t *sp;
17273
17274 insts = uu_list_walk_start(instances, 0);
17275 while ((sp = uu_list_walk_next(insts)) != NULL) {
17276 /*
17277 * Remove the instance from the instances list.
17278 */
17279 safe_printf(gettext("Delete instance %s from "
17280 "service %s\n"), sp->str, wip->fmri);
17281 if (scf_service_get_instance(svc, sp->str,
17282 instance) != SCF_SUCCESS) {
17283 (void) uu_warn("scf_error - %s\n",
17284 scf_strerror(scf_error()));
17285
17286 continue;
17287 }
17288
17289 (void) disable_instance(instance);
17290
17291 (void) lscf_instance_delete(instance, 1);
17292 }
17293 scf_instance_destroy(instance);
17294 uu_list_walk_end(insts);
17295 }
17296
17297 out_free:
17298 if (mpvarry) {
17299 struct mpg_mfile *fmpntov;
17300
17301 for (index = 0; mpvarry[index]; index++) {
17302 fmpntov = mpvarry[index];
17303 if (fmpntov->mpg == mpnbuf)
17304 mpnbuf = NULL;
17305 free(fmpntov->mpg);
17306
17307 if (fmpntov->mfile == mpvbuf)
17308 mpvbuf = NULL;
17309 free(fmpntov->mfile);
17310
17311 if (fmpntov == mpntov)
17312 mpntov = NULL;
17313 free(fmpntov);
17314 }
17315 if (mpnbuf)
17316 free(mpnbuf);
17317 if (mpvbuf)
17318 free(mpvbuf);
17319 if (mpntov)
17320 free(mpntov);
17321
17322 free(mpvarry);
17323 }
17324 out:
17325 scf_pg_destroy(mpg);
17326 scf_property_destroy(mp);
17327 scf_iter_destroy(mi);
17328 scf_value_destroy(mv);
17329
17330 return (0);
17331 }
17332
17333 /*
17334 * Take the service and search for the manifestfiles property
17335 * in each of the property groups. If the manifest file
17336 * associated with the property does not exist then remove
17337 * the property group.
17338 */
17339 int
lscf_hash_cleanup()17340 lscf_hash_cleanup()
17341 {
17342 scf_service_t *svc;
17343 scf_scope_t *scope;
17344 scf_propertygroup_t *pg;
17345 scf_property_t *prop;
17346 scf_value_t *val;
17347 scf_iter_t *iter;
17348 char *pgname = NULL;
17349 char *mfile = NULL;
17350 int r;
17351
17352 svc = scf_service_create(g_hndl);
17353 scope = scf_scope_create(g_hndl);
17354 pg = scf_pg_create(g_hndl);
17355 prop = scf_property_create(g_hndl);
17356 val = scf_value_create(g_hndl);
17357 iter = scf_iter_create(g_hndl);
17358 if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
17359 svc == NULL || scope == NULL) {
17360 uu_warn(gettext("Unable to create a property group, or "
17361 "property\n"));
17362 uu_warn("%s\n", pg == NULL ? "pg is NULL" :
17363 "pg is not NULL");
17364 uu_warn("%s\n", prop == NULL ? "prop is NULL" :
17365 "prop is not NULL");
17366 uu_warn("%s\n", val == NULL ? "val is NULL" :
17367 "val is not NULL");
17368 uu_warn("%s\n", iter == NULL ? "iter is NULL" :
17369 "iter is not NULL");
17370 uu_warn("%s\n", svc == NULL ? "svc is NULL" :
17371 "svc is not NULL");
17372 uu_warn("%s\n", scope == NULL ? "scope is NULL" :
17373 "scope is not NULL");
17374 uu_warn(gettext("scf error is : %s\n"),
17375 scf_strerror(scf_error()));
17376 scfdie();
17377 }
17378
17379 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
17380 switch (scf_error()) {
17381 case SCF_ERROR_CONNECTION_BROKEN:
17382 case SCF_ERROR_NOT_FOUND:
17383 goto out;
17384
17385 case SCF_ERROR_HANDLE_MISMATCH:
17386 case SCF_ERROR_NOT_BOUND:
17387 case SCF_ERROR_INVALID_ARGUMENT:
17388 default:
17389 bad_error("scf_handle_get_scope", scf_error());
17390 }
17391 }
17392
17393 if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
17394 uu_warn(gettext("Unable to process the hash service, %s\n"),
17395 HASH_SVC);
17396 goto out;
17397 }
17398
17399 pgname = safe_malloc(max_scf_name_len + 1);
17400 mfile = safe_malloc(max_scf_value_len + 1);
17401
17402 if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
17403 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17404 scf_strerror(scf_error()));
17405 goto out;
17406 }
17407
17408 while ((r = scf_iter_next_pg(iter, pg)) != 0) {
17409 if (r == -1)
17410 goto out;
17411
17412 if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
17413 switch (scf_error()) {
17414 case SCF_ERROR_DELETED:
17415 return (ENODEV);
17416
17417 case SCF_ERROR_CONNECTION_BROKEN:
17418 return (ECONNABORTED);
17419
17420 case SCF_ERROR_NOT_SET:
17421 case SCF_ERROR_NOT_BOUND:
17422 default:
17423 bad_error("scf_pg_get_name", scf_error());
17424 }
17425 }
17426 if (IGNORE_VAR) {
17427 if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
17428 continue;
17429 }
17430
17431 /*
17432 * If unable to get the property continue as this is an
17433 * entry that has no location to check against.
17434 */
17435 if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
17436 continue;
17437 }
17438
17439 if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
17440 uu_warn(gettext("Unable to get value from %s\n"),
17441 pgname);
17442
17443 switch (scf_error()) {
17444 case SCF_ERROR_DELETED:
17445 case SCF_ERROR_CONSTRAINT_VIOLATED:
17446 case SCF_ERROR_NOT_FOUND:
17447 case SCF_ERROR_NOT_SET:
17448 continue;
17449
17450 case SCF_ERROR_CONNECTION_BROKEN:
17451 r = scferror2errno(scf_error());
17452 goto out;
17453
17454 case SCF_ERROR_HANDLE_MISMATCH:
17455 case SCF_ERROR_NOT_BOUND:
17456 default:
17457 bad_error("scf_property_get_value",
17458 scf_error());
17459 }
17460 }
17461
17462 if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
17463 == -1) {
17464 uu_warn(gettext("Unable to get astring from %s : %s\n"),
17465 pgname, scf_strerror(scf_error()));
17466
17467 switch (scf_error()) {
17468 case SCF_ERROR_NOT_SET:
17469 case SCF_ERROR_TYPE_MISMATCH:
17470 continue;
17471
17472 default:
17473 bad_error("scf_value_get_astring", scf_error());
17474 }
17475 }
17476
17477 if (access(mfile, F_OK) == 0)
17478 continue;
17479
17480 (void) scf_pg_delete(pg);
17481 }
17482
17483 out:
17484 scf_scope_destroy(scope);
17485 scf_service_destroy(svc);
17486 scf_pg_destroy(pg);
17487 scf_property_destroy(prop);
17488 scf_value_destroy(val);
17489 scf_iter_destroy(iter);
17490 free(pgname);
17491 free(mfile);
17492
17493 return (0);
17494 }
17495
17496 #ifndef NATIVE_BUILD
17497 /* ARGSUSED */
CPL_MATCH_FN(complete_select)17498 CPL_MATCH_FN(complete_select)
17499 {
17500 const char *arg0, *arg1, *arg1end;
17501 int word_start, err = 0, r;
17502 size_t len;
17503 char *buf;
17504
17505 lscf_prep_hndl();
17506
17507 arg0 = line + strspn(line, " \t");
17508 assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
17509
17510 arg1 = arg0 + sizeof ("select") - 1;
17511 arg1 += strspn(arg1, " \t");
17512 word_start = arg1 - line;
17513
17514 arg1end = arg1 + strcspn(arg1, " \t");
17515 if (arg1end < line + word_end)
17516 return (0);
17517
17518 len = line + word_end - arg1;
17519
17520 buf = safe_malloc(max_scf_name_len + 1);
17521
17522 if (cur_snap != NULL) {
17523 return (0);
17524 } else if (cur_inst != NULL) {
17525 return (0);
17526 } else if (cur_svc != NULL) {
17527 scf_instance_t *inst;
17528 scf_iter_t *iter;
17529
17530 if ((inst = scf_instance_create(g_hndl)) == NULL ||
17531 (iter = scf_iter_create(g_hndl)) == NULL)
17532 scfdie();
17533
17534 if (scf_iter_service_instances(iter, cur_svc) != 0)
17535 scfdie();
17536
17537 for (;;) {
17538 r = scf_iter_next_instance(iter, inst);
17539 if (r == 0)
17540 break;
17541 if (r != 1)
17542 scfdie();
17543
17544 if (scf_instance_get_name(inst, buf,
17545 max_scf_name_len + 1) < 0)
17546 scfdie();
17547
17548 if (strncmp(buf, arg1, len) == 0) {
17549 err = cpl_add_completion(cpl, line, word_start,
17550 word_end, buf + len, "", " ");
17551 if (err != 0)
17552 break;
17553 }
17554 }
17555
17556 scf_iter_destroy(iter);
17557 scf_instance_destroy(inst);
17558
17559 return (err);
17560 } else {
17561 scf_service_t *svc;
17562 scf_iter_t *iter;
17563
17564 assert(cur_scope != NULL);
17565
17566 if ((svc = scf_service_create(g_hndl)) == NULL ||
17567 (iter = scf_iter_create(g_hndl)) == NULL)
17568 scfdie();
17569
17570 if (scf_iter_scope_services(iter, cur_scope) != 0)
17571 scfdie();
17572
17573 for (;;) {
17574 r = scf_iter_next_service(iter, svc);
17575 if (r == 0)
17576 break;
17577 if (r != 1)
17578 scfdie();
17579
17580 if (scf_service_get_name(svc, buf,
17581 max_scf_name_len + 1) < 0)
17582 scfdie();
17583
17584 if (strncmp(buf, arg1, len) == 0) {
17585 err = cpl_add_completion(cpl, line, word_start,
17586 word_end, buf + len, "", " ");
17587 if (err != 0)
17588 break;
17589 }
17590 }
17591
17592 scf_iter_destroy(iter);
17593 scf_service_destroy(svc);
17594
17595 return (err);
17596 }
17597 }
17598
17599 /* ARGSUSED */
CPL_MATCH_FN(complete_command)17600 CPL_MATCH_FN(complete_command)
17601 {
17602 uint32_t scope = 0;
17603
17604 if (cur_snap != NULL)
17605 scope = CS_SNAP;
17606 else if (cur_inst != NULL)
17607 scope = CS_INST;
17608 else if (cur_svc != NULL)
17609 scope = CS_SVC;
17610 else
17611 scope = CS_SCOPE;
17612
17613 return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
17614 }
17615 #endif /* NATIVE_BUILD */
17616