Print this page
7806 svccfg restore segfaults in upgrade_manifestfiles
Reviewed by: Toomas Soome <tsoome@me.com>
Reviewed by: Jason King <jason.brian.king@gmail.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/svc/svccfg/svccfg_libscf.c
+++ new/usr/src/cmd/svc/svccfg/svccfg_libscf.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 * Copyright 2015 Joyent, Inc.
25 25 * Copyright 2012 Milan Jurik. All rights reserved.
26 + * Copyright 2017 RackTop Systems.
26 27 */
27 28
28 29
29 30 #include <alloca.h>
30 31 #include <assert.h>
31 32 #include <ctype.h>
32 33 #include <door.h>
33 34 #include <errno.h>
34 35 #include <fcntl.h>
35 36 #include <fnmatch.h>
36 37 #include <inttypes.h>
37 38 #include <libintl.h>
38 39 #include <libnvpair.h>
39 40 #include <libscf.h>
40 41 #include <libscf_priv.h>
41 42 #include <libtecla.h>
42 43 #include <libuutil.h>
43 44 #include <limits.h>
44 45 #include <locale.h>
45 46 #include <stdarg.h>
46 47 #include <string.h>
47 48 #include <strings.h>
48 49 #include <time.h>
49 50 #include <unistd.h>
50 51 #include <wait.h>
51 52 #include <poll.h>
52 53
53 54 #include <libxml/tree.h>
54 55
55 56 #include <sys/param.h>
56 57
57 58 #include <sys/stat.h>
58 59 #include <sys/mman.h>
59 60
60 61 #include "svccfg.h"
61 62 #include "notify_params.h"
62 63 #include "manifest_hash.h"
63 64 #include "manifest_find.h"
64 65
65 66 /* The colon namespaces in each entity (each followed by a newline). */
66 67 #define COLON_NAMESPACES ":properties\n"
67 68
68 69 #define TEMP_FILE_PATTERN "/tmp/svccfg-XXXXXX"
69 70
70 71 /* These are characters which the lexer requires to be in double-quotes. */
71 72 #define CHARS_TO_QUOTE " \t\n\\>=\"()"
72 73
73 74 #define HASH_SIZE 16
74 75 #define HASH_PG_TYPE "framework"
75 76 #define HASH_PG_FLAGS 0
76 77 #define HASH_PROP "md5sum"
77 78
78 79 /*
79 80 * Indentation used in the output of the describe subcommand.
80 81 */
81 82 #define TMPL_VALUE_INDENT " "
82 83 #define TMPL_INDENT " "
83 84 #define TMPL_INDENT_2X " "
84 85 #define TMPL_CHOICE_INDENT " "
85 86
86 87 /*
87 88 * Directory locations for manifests
88 89 */
89 90 #define VARSVC_DIR "/var/svc/manifest"
90 91 #define LIBSVC_DIR "/lib/svc/manifest"
91 92 #define VARSVC_PR "var_svc_manifest"
92 93 #define LIBSVC_PR "lib_svc_manifest"
93 94 #define MFSTFILEPR "manifestfile"
94 95
95 96 #define SUPPORTPROP "support"
96 97
97 98 #define MFSTHISTFILE "/lib/svc/share/mfsthistory"
98 99
99 100 #define MFSTFILE_MAX 16
100 101
101 102 /*
102 103 * These are the classes of elements which may appear as children of service
103 104 * or instance elements in XML manifests.
104 105 */
105 106 struct entity_elts {
106 107 xmlNodePtr create_default_instance;
107 108 xmlNodePtr single_instance;
108 109 xmlNodePtr restarter;
109 110 xmlNodePtr dependencies;
110 111 xmlNodePtr dependents;
111 112 xmlNodePtr method_context;
112 113 xmlNodePtr exec_methods;
113 114 xmlNodePtr notify_params;
114 115 xmlNodePtr property_groups;
115 116 xmlNodePtr instances;
116 117 xmlNodePtr stability;
117 118 xmlNodePtr template;
118 119 };
119 120
120 121 /*
121 122 * Likewise for property_group elements.
122 123 */
123 124 struct pg_elts {
124 125 xmlNodePtr stability;
125 126 xmlNodePtr propvals;
126 127 xmlNodePtr properties;
127 128 };
128 129
129 130 /*
130 131 * Likewise for template elements.
131 132 */
132 133 struct template_elts {
133 134 xmlNodePtr common_name;
134 135 xmlNodePtr description;
135 136 xmlNodePtr documentation;
136 137 };
137 138
138 139 /*
139 140 * Likewise for type (for notification parameters) elements.
140 141 */
141 142 struct params_elts {
142 143 xmlNodePtr paramval;
143 144 xmlNodePtr parameter;
144 145 };
145 146
146 147 /*
147 148 * This structure is for snaplevel lists. They are convenient because libscf
148 149 * only allows traversing snaplevels in one direction.
149 150 */
150 151 struct snaplevel {
151 152 uu_list_node_t list_node;
152 153 scf_snaplevel_t *sl;
153 154 };
154 155
155 156 /*
156 157 * This is used for communication between lscf_service_export and
157 158 * export_callback.
158 159 */
159 160 struct export_args {
160 161 const char *filename;
161 162 int flags;
162 163 };
163 164
164 165 /*
165 166 * The service_manifest structure is used by the upgrade process
166 167 * to create a list of service to manifest linkages from the manifests
167 168 * in a set of given directories.
168 169 */
169 170 typedef struct service_manifest {
170 171 const char *servicename;
171 172 uu_list_t *mfstlist;
172 173 size_t mfstlist_sz;
173 174
174 175 uu_avl_node_t svcmfst_node;
175 176 } service_manifest_t;
176 177
177 178 /*
178 179 * Structure to track the manifest file property group
179 180 * and the manifest file associated with that property
180 181 * group. Also, a flag to keep the access once it has
181 182 * been checked.
182 183 */
183 184 struct mpg_mfile {
184 185 char *mpg;
185 186 char *mfile;
186 187 int access;
187 188 };
188 189
189 190 const char * const scf_pg_general = SCF_PG_GENERAL;
190 191 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
191 192 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
192 193 const char * const scf_property_external = "external";
193 194
194 195 const char * const snap_initial = "initial";
195 196 const char * const snap_lastimport = "last-import";
196 197 const char * const snap_previous = "previous";
197 198 const char * const snap_running = "running";
198 199
199 200 scf_handle_t *g_hndl = NULL; /* only valid after lscf_prep_hndl() */
200 201
201 202 ssize_t max_scf_fmri_len;
202 203 ssize_t max_scf_name_len;
203 204 ssize_t max_scf_pg_type_len;
204 205 ssize_t max_scf_value_len;
205 206 static size_t max_scf_len;
206 207
207 208 static scf_scope_t *cur_scope;
208 209 static scf_service_t *cur_svc = NULL;
209 210 static scf_instance_t *cur_inst = NULL;
210 211 static scf_snapshot_t *cur_snap = NULL;
211 212 static scf_snaplevel_t *cur_level = NULL;
212 213
213 214 static uu_list_pool_t *snaplevel_pool;
214 215 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
215 216 static uu_list_t *cur_levels;
216 217 static struct snaplevel *cur_elt; /* cur_elt->sl == cur_level */
217 218
218 219 static FILE *tempfile = NULL;
219 220 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
220 221
221 222 static const char *emsg_entity_not_selected;
222 223 static const char *emsg_permission_denied;
223 224 static const char *emsg_create_xml;
224 225 static const char *emsg_cant_modify_snapshots;
225 226 static const char *emsg_invalid_for_snapshot;
226 227 static const char *emsg_read_only;
227 228 static const char *emsg_deleted;
228 229 static const char *emsg_invalid_pg_name;
229 230 static const char *emsg_invalid_prop_name;
230 231 static const char *emsg_no_such_pg;
231 232 static const char *emsg_fmri_invalid_pg_name;
232 233 static const char *emsg_fmri_invalid_pg_name_type;
233 234 static const char *emsg_pg_added;
234 235 static const char *emsg_pg_changed;
235 236 static const char *emsg_pg_deleted;
236 237 static const char *emsg_pg_mod_perm;
237 238 static const char *emsg_pg_add_perm;
238 239 static const char *emsg_pg_del_perm;
239 240 static const char *emsg_snap_perm;
240 241 static const char *emsg_dpt_dangling;
241 242 static const char *emsg_dpt_no_dep;
242 243
243 244 static int li_only = 0;
244 245 static int no_refresh = 0;
245 246
246 247 /* how long in ns we should wait between checks for a pg */
247 248 static uint64_t pg_timeout = 100 * (NANOSEC / MILLISEC);
248 249
249 250 /* import globals, to minimize allocations */
250 251 static scf_scope_t *imp_scope = NULL;
251 252 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
252 253 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
253 254 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
254 255 static scf_snapshot_t *imp_rsnap = NULL;
255 256 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
256 257 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
257 258 static scf_property_t *imp_prop = NULL;
258 259 static scf_iter_t *imp_iter = NULL;
259 260 static scf_iter_t *imp_rpg_iter = NULL;
260 261 static scf_iter_t *imp_up_iter = NULL;
261 262 static scf_transaction_t *imp_tx = NULL; /* always reset this */
262 263 static char *imp_str = NULL;
263 264 static size_t imp_str_sz;
264 265 static char *imp_tsname = NULL;
265 266 static char *imp_fe1 = NULL; /* for fmri_equal() */
266 267 static char *imp_fe2 = NULL;
267 268 static uu_list_t *imp_deleted_dpts = NULL; /* pgroup_t's to refresh */
268 269
269 270 /* upgrade_dependents() globals */
270 271 static scf_instance_t *ud_inst = NULL;
271 272 static scf_snaplevel_t *ud_snpl = NULL;
272 273 static scf_propertygroup_t *ud_pg = NULL;
273 274 static scf_propertygroup_t *ud_cur_depts_pg = NULL;
274 275 static scf_propertygroup_t *ud_run_dpts_pg = NULL;
275 276 static int ud_run_dpts_pg_set = 0;
276 277 static scf_property_t *ud_prop = NULL;
277 278 static scf_property_t *ud_dpt_prop = NULL;
278 279 static scf_value_t *ud_val = NULL;
279 280 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
280 281 static scf_transaction_t *ud_tx = NULL;
281 282 static char *ud_ctarg = NULL;
282 283 static char *ud_oldtarg = NULL;
283 284 static char *ud_name = NULL;
284 285
285 286 /* export globals */
286 287 static scf_instance_t *exp_inst;
287 288 static scf_propertygroup_t *exp_pg;
288 289 static scf_property_t *exp_prop;
289 290 static scf_value_t *exp_val;
290 291 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
291 292 static char *exp_str;
292 293 static size_t exp_str_sz;
293 294
294 295 /* cleanup globals */
295 296 static uu_avl_pool_t *service_manifest_pool = NULL;
296 297 static uu_avl_t *service_manifest_tree = NULL;
297 298
298 299 static void scfdie_lineno(int lineno) __NORETURN;
299 300
300 301 static char *start_method_names[] = {
301 302 "start",
302 303 "inetd_start",
303 304 NULL
304 305 };
305 306
306 307 static struct uri_scheme {
307 308 const char *scheme;
308 309 const char *protocol;
309 310 } uri_scheme[] = {
310 311 { "mailto", "smtp" },
311 312 { "snmp", "snmp" },
312 313 { "syslog", "syslog" },
313 314 { NULL, NULL }
314 315 };
315 316 #define URI_SCHEME_NUM ((sizeof (uri_scheme) / \
316 317 sizeof (struct uri_scheme)) - 1)
317 318
318 319 static int
319 320 check_uri_scheme(const char *scheme)
320 321 {
321 322 int i;
322 323
323 324 for (i = 0; uri_scheme[i].scheme != NULL; ++i) {
324 325 if (strcmp(scheme, uri_scheme[i].scheme) == 0)
325 326 return (i);
326 327 }
327 328
328 329 return (-1);
329 330 }
330 331
331 332 static int
332 333 check_uri_protocol(const char *p)
333 334 {
334 335 int i;
335 336
336 337 for (i = 0; uri_scheme[i].protocol != NULL; ++i) {
337 338 if (strcmp(p, uri_scheme[i].protocol) == 0)
338 339 return (i);
339 340 }
340 341
341 342 return (-1);
342 343 }
343 344
344 345 /*
345 346 * For unexpected libscf errors.
346 347 */
347 348 #ifdef NDEBUG
348 349
349 350 static void scfdie(void) __NORETURN;
350 351
351 352 static void
352 353 scfdie(void)
353 354 {
354 355 scf_error_t err = scf_error();
355 356
356 357 if (err == SCF_ERROR_CONNECTION_BROKEN)
357 358 uu_die(gettext("Repository connection broken. Exiting.\n"));
358 359
359 360 uu_die(gettext("Unexpected fatal libscf error: %s. Exiting.\n"),
360 361 scf_strerror(err));
361 362 }
362 363
363 364 #else
364 365
365 366 #define scfdie() scfdie_lineno(__LINE__)
366 367
367 368 static void
368 369 scfdie_lineno(int lineno)
369 370 {
370 371 scf_error_t err = scf_error();
371 372
372 373 if (err == SCF_ERROR_CONNECTION_BROKEN)
373 374 uu_die(gettext("Repository connection broken. Exiting.\n"));
374 375
375 376 uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
376 377 ": %s.\n"), lineno, scf_strerror(err));
377 378 }
378 379
379 380 #endif
380 381
381 382 static void
382 383 scfwarn(void)
383 384 {
384 385 warn(gettext("Unexpected libscf error: %s.\n"),
385 386 scf_strerror(scf_error()));
386 387 }
387 388
388 389 /*
389 390 * Clear a field of a structure.
390 391 */
391 392 static int
392 393 clear_int(void *a, void *b)
393 394 {
394 395 /* LINTED */
395 396 *(int *)((char *)a + (size_t)b) = 0;
396 397
397 398 return (UU_WALK_NEXT);
398 399 }
399 400
400 401 static int
401 402 scferror2errno(scf_error_t err)
402 403 {
403 404 switch (err) {
404 405 case SCF_ERROR_BACKEND_ACCESS:
405 406 return (EACCES);
406 407
407 408 case SCF_ERROR_BACKEND_READONLY:
408 409 return (EROFS);
409 410
410 411 case SCF_ERROR_CONNECTION_BROKEN:
411 412 return (ECONNABORTED);
412 413
413 414 case SCF_ERROR_CONSTRAINT_VIOLATED:
414 415 case SCF_ERROR_INVALID_ARGUMENT:
415 416 return (EINVAL);
416 417
417 418 case SCF_ERROR_DELETED:
418 419 return (ECANCELED);
419 420
420 421 case SCF_ERROR_EXISTS:
421 422 return (EEXIST);
422 423
423 424 case SCF_ERROR_NO_MEMORY:
424 425 return (ENOMEM);
425 426
426 427 case SCF_ERROR_NO_RESOURCES:
427 428 return (ENOSPC);
428 429
429 430 case SCF_ERROR_NOT_FOUND:
430 431 return (ENOENT);
431 432
432 433 case SCF_ERROR_PERMISSION_DENIED:
433 434 return (EPERM);
434 435
435 436 default:
436 437 #ifndef NDEBUG
437 438 (void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
438 439 __FILE__, __LINE__, err);
439 440 #else
440 441 (void) fprintf(stderr, "Unknown libscf error %d.\n", err);
441 442 #endif
442 443 abort();
443 444 /* NOTREACHED */
444 445 }
445 446 }
446 447
447 448 static int
448 449 entity_get_pg(void *ent, int issvc, const char *name,
449 450 scf_propertygroup_t *pg)
450 451 {
451 452 if (issvc)
452 453 return (scf_service_get_pg(ent, name, pg));
453 454 else
454 455 return (scf_instance_get_pg(ent, name, pg));
455 456 }
456 457
457 458 static void
458 459 entity_destroy(void *ent, int issvc)
459 460 {
460 461 if (issvc)
461 462 scf_service_destroy(ent);
462 463 else
463 464 scf_instance_destroy(ent);
464 465 }
465 466
466 467 static int
467 468 get_pg(const char *pg_name, scf_propertygroup_t *pg)
468 469 {
469 470 int ret;
470 471
471 472 if (cur_level != NULL)
472 473 ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
473 474 else if (cur_inst != NULL)
474 475 ret = scf_instance_get_pg(cur_inst, pg_name, pg);
475 476 else
476 477 ret = scf_service_get_pg(cur_svc, pg_name, pg);
477 478
478 479 return (ret);
479 480 }
480 481
481 482 /*
482 483 * Find a snaplevel in a snapshot. If get_svc is true, find the service
483 484 * snaplevel. Otherwise find the instance snaplevel.
484 485 *
485 486 * Returns
486 487 * 0 - success
487 488 * ECONNABORTED - repository connection broken
488 489 * ECANCELED - instance containing snap was deleted
489 490 * ENOENT - snap has no snaplevels
490 491 * - requested snaplevel not found
491 492 */
492 493 static int
493 494 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
494 495 {
495 496 if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
496 497 switch (scf_error()) {
497 498 case SCF_ERROR_CONNECTION_BROKEN:
498 499 case SCF_ERROR_DELETED:
499 500 case SCF_ERROR_NOT_FOUND:
500 501 return (scferror2errno(scf_error()));
501 502
502 503 case SCF_ERROR_HANDLE_MISMATCH:
503 504 case SCF_ERROR_NOT_BOUND:
504 505 case SCF_ERROR_NOT_SET:
505 506 default:
506 507 bad_error("scf_snapshot_get_base_snaplevel",
507 508 scf_error());
508 509 }
509 510 }
510 511
511 512 for (;;) {
512 513 ssize_t ssz;
513 514
514 515 ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
515 516 if (ssz >= 0) {
516 517 if (!get_svc)
517 518 return (0);
518 519 } else {
519 520 switch (scf_error()) {
520 521 case SCF_ERROR_CONSTRAINT_VIOLATED:
521 522 if (get_svc)
522 523 return (0);
523 524 break;
524 525
525 526 case SCF_ERROR_DELETED:
526 527 case SCF_ERROR_CONNECTION_BROKEN:
527 528 return (scferror2errno(scf_error()));
528 529
529 530 case SCF_ERROR_NOT_SET:
530 531 case SCF_ERROR_NOT_BOUND:
531 532 default:
532 533 bad_error("scf_snaplevel_get_instance_name",
533 534 scf_error());
534 535 }
535 536 }
536 537
537 538 if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
538 539 switch (scf_error()) {
539 540 case SCF_ERROR_NOT_FOUND:
540 541 case SCF_ERROR_CONNECTION_BROKEN:
541 542 case SCF_ERROR_DELETED:
542 543 return (scferror2errno(scf_error()));
543 544
544 545 case SCF_ERROR_HANDLE_MISMATCH:
545 546 case SCF_ERROR_NOT_BOUND:
546 547 case SCF_ERROR_NOT_SET:
547 548 case SCF_ERROR_INVALID_ARGUMENT:
548 549 default:
549 550 bad_error("scf_snaplevel_get_next_snaplevel",
550 551 scf_error());
551 552 }
552 553 }
553 554 }
554 555 }
555 556
556 557 /*
557 558 * If issvc is 0, take ent to be a pointer to an scf_instance_t. If it has
558 559 * a running snapshot, and that snapshot has an instance snaplevel, set pg to
559 560 * the property group named name in it. If it doesn't have a running
560 561 * snapshot, set pg to the instance's current property group named name.
561 562 *
562 563 * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
563 564 * its instances. If one has a running snapshot with a service snaplevel, set
564 565 * pg to the property group named name in it. If no such snaplevel could be
565 566 * found, set pg to the service's current property group named name.
566 567 *
567 568 * iter, inst, snap, and snpl are required scratch objects.
568 569 *
569 570 * Returns
570 571 * 0 - success
571 572 * ECONNABORTED - repository connection broken
572 573 * ECANCELED - ent was deleted
573 574 * ENOENT - no such property group
574 575 * EINVAL - name is an invalid property group name
575 576 * EBADF - found running snapshot is missing a snaplevel
576 577 */
577 578 static int
578 579 entity_get_running_pg(void *ent, int issvc, const char *name,
579 580 scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
580 581 scf_snapshot_t *snap, scf_snaplevel_t *snpl)
581 582 {
582 583 int r;
583 584
584 585 if (issvc) {
585 586 /* Search for an instance with a running snapshot. */
586 587 if (scf_iter_service_instances(iter, ent) != 0) {
587 588 switch (scf_error()) {
588 589 case SCF_ERROR_DELETED:
589 590 case SCF_ERROR_CONNECTION_BROKEN:
590 591 return (scferror2errno(scf_error()));
591 592
592 593 case SCF_ERROR_NOT_SET:
593 594 case SCF_ERROR_NOT_BOUND:
594 595 case SCF_ERROR_HANDLE_MISMATCH:
595 596 default:
596 597 bad_error("scf_iter_service_instances",
597 598 scf_error());
598 599 }
599 600 }
600 601
601 602 for (;;) {
602 603 r = scf_iter_next_instance(iter, inst);
603 604 if (r == 0) {
604 605 if (scf_service_get_pg(ent, name, pg) == 0)
605 606 return (0);
606 607
607 608 switch (scf_error()) {
608 609 case SCF_ERROR_DELETED:
609 610 case SCF_ERROR_NOT_FOUND:
610 611 case SCF_ERROR_INVALID_ARGUMENT:
611 612 case SCF_ERROR_CONNECTION_BROKEN:
612 613 return (scferror2errno(scf_error()));
613 614
614 615 case SCF_ERROR_NOT_BOUND:
615 616 case SCF_ERROR_HANDLE_MISMATCH:
616 617 case SCF_ERROR_NOT_SET:
617 618 default:
618 619 bad_error("scf_service_get_pg",
619 620 scf_error());
620 621 }
621 622 }
622 623 if (r != 1) {
623 624 switch (scf_error()) {
624 625 case SCF_ERROR_DELETED:
625 626 case SCF_ERROR_CONNECTION_BROKEN:
626 627 return (scferror2errno(scf_error()));
627 628
628 629 case SCF_ERROR_INVALID_ARGUMENT:
629 630 case SCF_ERROR_NOT_SET:
630 631 case SCF_ERROR_NOT_BOUND:
631 632 case SCF_ERROR_HANDLE_MISMATCH:
632 633 default:
633 634 bad_error("scf_iter_next_instance",
634 635 scf_error());
635 636 }
636 637 }
637 638
638 639 if (scf_instance_get_snapshot(inst, snap_running,
639 640 snap) == 0)
640 641 break;
641 642
642 643 switch (scf_error()) {
643 644 case SCF_ERROR_NOT_FOUND:
644 645 case SCF_ERROR_DELETED:
645 646 continue;
646 647
647 648 case SCF_ERROR_CONNECTION_BROKEN:
648 649 return (ECONNABORTED);
649 650
650 651 case SCF_ERROR_HANDLE_MISMATCH:
651 652 case SCF_ERROR_INVALID_ARGUMENT:
652 653 case SCF_ERROR_NOT_SET:
653 654 case SCF_ERROR_NOT_BOUND:
654 655 default:
655 656 bad_error("scf_instance_get_snapshot",
656 657 scf_error());
657 658 }
658 659 }
659 660 } else {
660 661 if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
661 662 switch (scf_error()) {
662 663 case SCF_ERROR_NOT_FOUND:
663 664 break;
664 665
665 666 case SCF_ERROR_DELETED:
666 667 case SCF_ERROR_CONNECTION_BROKEN:
667 668 return (scferror2errno(scf_error()));
668 669
669 670 case SCF_ERROR_NOT_BOUND:
670 671 case SCF_ERROR_HANDLE_MISMATCH:
671 672 case SCF_ERROR_INVALID_ARGUMENT:
672 673 case SCF_ERROR_NOT_SET:
673 674 default:
674 675 bad_error("scf_instance_get_snapshot",
675 676 scf_error());
676 677 }
677 678
678 679 if (scf_instance_get_pg(ent, name, pg) == 0)
679 680 return (0);
680 681
681 682 switch (scf_error()) {
682 683 case SCF_ERROR_DELETED:
683 684 case SCF_ERROR_NOT_FOUND:
684 685 case SCF_ERROR_INVALID_ARGUMENT:
685 686 case SCF_ERROR_CONNECTION_BROKEN:
686 687 return (scferror2errno(scf_error()));
687 688
688 689 case SCF_ERROR_NOT_BOUND:
689 690 case SCF_ERROR_HANDLE_MISMATCH:
690 691 case SCF_ERROR_NOT_SET:
691 692 default:
692 693 bad_error("scf_instance_get_pg", scf_error());
693 694 }
694 695 }
695 696 }
696 697
697 698 r = get_snaplevel(snap, issvc, snpl);
698 699 switch (r) {
699 700 case 0:
700 701 break;
701 702
702 703 case ECONNABORTED:
703 704 case ECANCELED:
704 705 return (r);
705 706
706 707 case ENOENT:
707 708 return (EBADF);
708 709
709 710 default:
710 711 bad_error("get_snaplevel", r);
711 712 }
712 713
713 714 if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
714 715 return (0);
715 716
716 717 switch (scf_error()) {
717 718 case SCF_ERROR_DELETED:
718 719 case SCF_ERROR_INVALID_ARGUMENT:
719 720 case SCF_ERROR_CONNECTION_BROKEN:
720 721 case SCF_ERROR_NOT_FOUND:
721 722 return (scferror2errno(scf_error()));
722 723
723 724 case SCF_ERROR_NOT_BOUND:
724 725 case SCF_ERROR_HANDLE_MISMATCH:
725 726 case SCF_ERROR_NOT_SET:
726 727 default:
727 728 bad_error("scf_snaplevel_get_pg", scf_error());
728 729 /* NOTREACHED */
729 730 }
730 731 }
731 732
732 733 /*
733 734 * To be registered with atexit().
734 735 */
735 736 static void
736 737 remove_tempfile(void)
737 738 {
738 739 int ret;
739 740
740 741 if (tempfile != NULL) {
741 742 if (fclose(tempfile) == EOF)
742 743 (void) warn(gettext("Could not close temporary file"));
743 744 tempfile = NULL;
744 745 }
745 746
746 747 if (tempfilename[0] != '\0') {
747 748 do {
748 749 ret = remove(tempfilename);
749 750 } while (ret == -1 && errno == EINTR);
750 751 if (ret == -1)
751 752 warn(gettext("Could not remove temporary file"));
752 753 tempfilename[0] = '\0';
753 754 }
754 755 }
755 756
756 757 /*
757 758 * Launch private svc.configd(1M) for manipulating alternate repositories.
758 759 */
759 760 static void
760 761 start_private_repository(engine_state_t *est)
761 762 {
762 763 int fd, stat;
763 764 struct door_info info;
764 765 pid_t pid;
765 766
766 767 /*
767 768 * 1. Create a temporary file for the door.
768 769 */
769 770 if (est->sc_repo_doorname != NULL)
770 771 free((void *)est->sc_repo_doorname);
771 772
772 773 est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
773 774 if (est->sc_repo_doorname == NULL)
774 775 uu_die(gettext("Could not acquire temporary filename"));
775 776
776 777 fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
777 778 if (fd < 0)
778 779 uu_die(gettext("Could not create temporary file for "
779 780 "repository server"));
780 781
781 782 (void) close(fd);
782 783
783 784 /*
784 785 * 2. Launch a configd with that door, using the specified
785 786 * repository.
786 787 */
787 788 if ((est->sc_repo_pid = fork()) == 0) {
788 789 (void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
789 790 "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
790 791 NULL);
791 792 uu_die(gettext("Could not execute %s"), est->sc_repo_server);
792 793 } else if (est->sc_repo_pid == -1)
793 794 uu_die(gettext("Attempt to fork failed"));
794 795
795 796 do {
796 797 pid = waitpid(est->sc_repo_pid, &stat, 0);
797 798 } while (pid == -1 && errno == EINTR);
798 799
799 800 if (pid == -1)
800 801 uu_die(gettext("Could not waitpid() for repository server"));
801 802
802 803 if (!WIFEXITED(stat)) {
803 804 uu_die(gettext("Repository server failed (status %d).\n"),
804 805 stat);
805 806 } else if (WEXITSTATUS(stat) != 0) {
806 807 uu_die(gettext("Repository server failed (exit %d).\n"),
807 808 WEXITSTATUS(stat));
808 809 }
809 810
810 811 /*
811 812 * See if it was successful by checking if the door is a door.
812 813 */
813 814
814 815 fd = open(est->sc_repo_doorname, O_RDWR);
815 816 if (fd < 0)
816 817 uu_die(gettext("Could not open door \"%s\""),
817 818 est->sc_repo_doorname);
818 819
819 820 if (door_info(fd, &info) < 0)
820 821 uu_die(gettext("Unexpected door_info() error"));
821 822
822 823 if (close(fd) == -1)
823 824 warn(gettext("Could not close repository door"),
824 825 strerror(errno));
825 826
826 827 est->sc_repo_pid = info.di_target;
827 828 }
828 829
829 830 void
830 831 lscf_cleanup(void)
831 832 {
832 833 /*
833 834 * In the case where we've launched a private svc.configd(1M)
834 835 * instance, we must terminate our child and remove the temporary
835 836 * rendezvous point.
836 837 */
837 838 if (est->sc_repo_pid > 0) {
838 839 (void) kill(est->sc_repo_pid, SIGTERM);
839 840 (void) waitpid(est->sc_repo_pid, NULL, 0);
840 841 (void) unlink(est->sc_repo_doorname);
841 842
842 843 est->sc_repo_pid = 0;
843 844 }
844 845 }
845 846
846 847 void
847 848 unselect_cursnap(void)
848 849 {
849 850 void *cookie;
850 851
851 852 cur_level = NULL;
852 853
853 854 cookie = NULL;
854 855 while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
855 856 scf_snaplevel_destroy(cur_elt->sl);
856 857 free(cur_elt);
857 858 }
858 859
859 860 scf_snapshot_destroy(cur_snap);
860 861 cur_snap = NULL;
861 862 }
862 863
863 864 void
864 865 lscf_prep_hndl(void)
865 866 {
866 867 if (g_hndl != NULL)
867 868 return;
868 869
869 870 g_hndl = scf_handle_create(SCF_VERSION);
870 871 if (g_hndl == NULL)
871 872 scfdie();
872 873
873 874 if (est->sc_repo_filename != NULL)
874 875 start_private_repository(est);
875 876
876 877 if (est->sc_repo_doorname != NULL) {
877 878 scf_value_t *repo_value;
878 879 int ret;
879 880
880 881 repo_value = scf_value_create(g_hndl);
881 882 if (repo_value == NULL)
882 883 scfdie();
883 884
884 885 ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
885 886 assert(ret == SCF_SUCCESS);
886 887
887 888 if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
888 889 SCF_SUCCESS)
889 890 scfdie();
890 891
891 892 scf_value_destroy(repo_value);
892 893 }
893 894
894 895 if (scf_handle_bind(g_hndl) != 0)
895 896 uu_die(gettext("Could not connect to repository server: %s.\n"),
896 897 scf_strerror(scf_error()));
897 898
898 899 cur_scope = scf_scope_create(g_hndl);
899 900 if (cur_scope == NULL)
900 901 scfdie();
901 902
902 903 if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
903 904 scfdie();
904 905 }
905 906
906 907 static void
907 908 repository_teardown(void)
908 909 {
909 910 if (g_hndl != NULL) {
910 911 if (cur_snap != NULL)
911 912 unselect_cursnap();
912 913 scf_instance_destroy(cur_inst);
913 914 scf_service_destroy(cur_svc);
914 915 scf_scope_destroy(cur_scope);
915 916 scf_handle_destroy(g_hndl);
916 917 cur_inst = NULL;
917 918 cur_svc = NULL;
918 919 cur_scope = NULL;
919 920 g_hndl = NULL;
920 921 lscf_cleanup();
921 922 }
922 923 }
923 924
924 925 void
925 926 lscf_set_repository(const char *repfile, int force)
926 927 {
927 928 repository_teardown();
928 929
929 930 if (est->sc_repo_filename != NULL) {
930 931 free((void *)est->sc_repo_filename);
931 932 est->sc_repo_filename = NULL;
932 933 }
933 934
934 935 if ((force == 0) && (access(repfile, R_OK) != 0)) {
935 936 /*
936 937 * Repository file does not exist
937 938 * or has no read permission.
938 939 */
939 940 warn(gettext("Cannot access \"%s\": %s\n"),
940 941 repfile, strerror(errno));
941 942 } else {
942 943 est->sc_repo_filename = safe_strdup(repfile);
943 944 }
944 945
945 946 lscf_prep_hndl();
946 947 }
947 948
948 949 void
949 950 lscf_init()
950 951 {
951 952 if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
952 953 (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
953 954 (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
954 955 0 ||
955 956 (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
956 957 scfdie();
957 958
958 959 max_scf_len = max_scf_fmri_len;
959 960 if (max_scf_name_len > max_scf_len)
960 961 max_scf_len = max_scf_name_len;
961 962 if (max_scf_pg_type_len > max_scf_len)
962 963 max_scf_len = max_scf_pg_type_len;
963 964 /*
964 965 * When a value of type opaque is represented as a string, the
965 966 * string contains 2 characters for every byte of data. That is
966 967 * because the string contains the hex representation of the opaque
967 968 * value.
968 969 */
969 970 if (2 * max_scf_value_len > max_scf_len)
970 971 max_scf_len = 2 * max_scf_value_len;
971 972
972 973 if (atexit(remove_tempfile) != 0)
973 974 uu_die(gettext("Could not register atexit() function"));
974 975
975 976 emsg_entity_not_selected = gettext("An entity is not selected.\n");
976 977 emsg_permission_denied = gettext("Permission denied.\n");
977 978 emsg_create_xml = gettext("Could not create XML node.\n");
978 979 emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
979 980 emsg_invalid_for_snapshot =
980 981 gettext("Invalid operation on a snapshot.\n");
981 982 emsg_read_only = gettext("Backend read-only.\n");
982 983 emsg_deleted = gettext("Current selection has been deleted.\n");
983 984 emsg_invalid_pg_name =
984 985 gettext("Invalid property group name \"%s\".\n");
985 986 emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
986 987 emsg_no_such_pg = gettext("No such property group \"%s\".\n");
987 988 emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
988 989 "with invalid name \"%s\".\n");
989 990 emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
990 991 "group with invalid name \"%s\" or type \"%s\".\n");
991 992 emsg_pg_added = gettext("%s changed unexpectedly "
992 993 "(property group \"%s\" added).\n");
993 994 emsg_pg_changed = gettext("%s changed unexpectedly "
994 995 "(property group \"%s\" changed).\n");
995 996 emsg_pg_deleted = gettext("%s changed unexpectedly "
996 997 "(property group \"%s\" or an ancestor was deleted).\n");
997 998 emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
998 999 "in %s (permission denied).\n");
999 1000 emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
1000 1001 "in %s (permission denied).\n");
1001 1002 emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
1002 1003 "in %s (permission denied).\n");
1003 1004 emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
1004 1005 "(permission denied).\n");
1005 1006 emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
1006 1007 "new dependent \"%s\" because it already exists). Warning: The "
1007 1008 "current dependent's target (%s) does not exist.\n");
1008 1009 emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
1009 1010 "dependent \"%s\" because it already exists). Warning: The "
1010 1011 "current dependent's target (%s) does not have a dependency named "
1011 1012 "\"%s\" as expected.\n");
1012 1013
1013 1014 string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
1014 1015 offsetof(string_list_t, node), NULL, 0);
1015 1016 snaplevel_pool = uu_list_pool_create("snaplevels",
1016 1017 sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
1017 1018 NULL, 0);
1018 1019 }
1019 1020
1020 1021
1021 1022 static const char *
1022 1023 prop_to_typestr(const scf_property_t *prop)
1023 1024 {
1024 1025 scf_type_t ty;
1025 1026
1026 1027 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
1027 1028 scfdie();
1028 1029
1029 1030 return (scf_type_to_string(ty));
1030 1031 }
1031 1032
1032 1033 static scf_type_t
1033 1034 string_to_type(const char *type)
1034 1035 {
1035 1036 size_t len = strlen(type);
1036 1037 char *buf;
1037 1038
1038 1039 if (len == 0 || type[len - 1] != ':')
1039 1040 return (SCF_TYPE_INVALID);
1040 1041
1041 1042 buf = (char *)alloca(len + 1);
1042 1043 (void) strlcpy(buf, type, len + 1);
1043 1044 buf[len - 1] = 0;
1044 1045
1045 1046 return (scf_string_to_type(buf));
1046 1047 }
1047 1048
1048 1049 static scf_value_t *
1049 1050 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
1050 1051 {
1051 1052 scf_value_t *v;
1052 1053 char *dup, *nstr;
1053 1054 size_t len;
1054 1055
1055 1056 v = scf_value_create(g_hndl);
1056 1057 if (v == NULL)
1057 1058 scfdie();
1058 1059
1059 1060 len = strlen(str);
1060 1061 if (require_quotes &&
1061 1062 (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
1062 1063 semerr(gettext("Multiple string values or string values "
1063 1064 "with spaces must be quoted with '\"'.\n"));
1064 1065 scf_value_destroy(v);
1065 1066 return (NULL);
1066 1067 }
1067 1068
1068 1069 nstr = dup = safe_strdup(str);
1069 1070 if (dup[0] == '\"') {
1070 1071 /*
1071 1072 * Strip out the first and the last quote.
1072 1073 */
1073 1074 dup[len - 1] = '\0';
1074 1075 nstr = dup + 1;
1075 1076 }
1076 1077
1077 1078 if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
1078 1079 assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1079 1080 semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1080 1081 scf_type_to_string(ty), nstr);
1081 1082 scf_value_destroy(v);
1082 1083 v = NULL;
1083 1084 }
1084 1085 free(dup);
1085 1086 return (v);
1086 1087 }
1087 1088
1088 1089 /*
1089 1090 * Print str to strm, quoting double-quotes and backslashes with backslashes.
1090 1091 * Optionally append a comment prefix ('#') to newlines ('\n').
1091 1092 */
1092 1093 static int
1093 1094 quote_and_print(const char *str, FILE *strm, int commentnl)
1094 1095 {
1095 1096 const char *cp;
1096 1097
1097 1098 for (cp = str; *cp != '\0'; ++cp) {
1098 1099 if (*cp == '"' || *cp == '\\')
1099 1100 (void) putc('\\', strm);
1100 1101
1101 1102 (void) putc(*cp, strm);
1102 1103
1103 1104 if (commentnl && *cp == '\n') {
1104 1105 (void) putc('#', strm);
1105 1106 }
1106 1107 }
1107 1108
1108 1109 return (ferror(strm));
1109 1110 }
1110 1111
1111 1112 /*
1112 1113 * These wrappers around lowlevel functions provide consistent error checking
1113 1114 * and warnings.
1114 1115 */
1115 1116 static int
1116 1117 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1117 1118 {
1118 1119 if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1119 1120 return (0);
1120 1121
1121 1122 if (scf_error() != SCF_ERROR_NOT_FOUND)
1122 1123 scfdie();
1123 1124
1124 1125 if (g_verbose) {
1125 1126 ssize_t len;
1126 1127 char *fmri;
1127 1128
1128 1129 len = scf_pg_to_fmri(pg, NULL, 0);
1129 1130 if (len < 0)
1130 1131 scfdie();
1131 1132
1132 1133 fmri = safe_malloc(len + 1);
1133 1134
1134 1135 if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1135 1136 scfdie();
1136 1137
1137 1138 warn(gettext("Expected property %s of property group %s is "
1138 1139 "missing.\n"), propname, fmri);
1139 1140
1140 1141 free(fmri);
1141 1142 }
1142 1143
1143 1144 return (-1);
1144 1145 }
1145 1146
1146 1147 static int
1147 1148 prop_check_type(scf_property_t *prop, scf_type_t ty)
1148 1149 {
1149 1150 scf_type_t pty;
1150 1151
1151 1152 if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1152 1153 scfdie();
1153 1154
1154 1155 if (ty == pty)
1155 1156 return (0);
1156 1157
1157 1158 if (g_verbose) {
1158 1159 ssize_t len;
1159 1160 char *fmri;
1160 1161 const char *tystr;
1161 1162
1162 1163 len = scf_property_to_fmri(prop, NULL, 0);
1163 1164 if (len < 0)
1164 1165 scfdie();
1165 1166
1166 1167 fmri = safe_malloc(len + 1);
1167 1168
1168 1169 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1169 1170 scfdie();
1170 1171
1171 1172 tystr = scf_type_to_string(ty);
1172 1173 if (tystr == NULL)
1173 1174 tystr = "?";
1174 1175
1175 1176 warn(gettext("Property %s is not of expected type %s.\n"),
1176 1177 fmri, tystr);
1177 1178
1178 1179 free(fmri);
1179 1180 }
1180 1181
1181 1182 return (-1);
1182 1183 }
1183 1184
1184 1185 static int
1185 1186 prop_get_val(scf_property_t *prop, scf_value_t *val)
1186 1187 {
1187 1188 scf_error_t err;
1188 1189
1189 1190 if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1190 1191 return (0);
1191 1192
1192 1193 err = scf_error();
1193 1194
1194 1195 if (err != SCF_ERROR_NOT_FOUND &&
1195 1196 err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1196 1197 err != SCF_ERROR_PERMISSION_DENIED)
1197 1198 scfdie();
1198 1199
1199 1200 if (g_verbose) {
1200 1201 ssize_t len;
1201 1202 char *fmri, *emsg;
1202 1203
1203 1204 len = scf_property_to_fmri(prop, NULL, 0);
1204 1205 if (len < 0)
1205 1206 scfdie();
1206 1207
1207 1208 fmri = safe_malloc(len + 1);
1208 1209
1209 1210 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1210 1211 scfdie();
1211 1212
1212 1213 if (err == SCF_ERROR_NOT_FOUND)
1213 1214 emsg = gettext("Property %s has no values; expected "
1214 1215 "one.\n");
1215 1216 else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1216 1217 emsg = gettext("Property %s has multiple values; "
1217 1218 "expected one.\n");
1218 1219 else
1219 1220 emsg = gettext("No permission to read property %s.\n");
1220 1221
1221 1222 warn(emsg, fmri);
1222 1223
1223 1224 free(fmri);
1224 1225 }
1225 1226
1226 1227 return (-1);
1227 1228 }
1228 1229
1229 1230
1230 1231 static boolean_t
1231 1232 snaplevel_is_instance(const scf_snaplevel_t *level)
1232 1233 {
1233 1234 if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1234 1235 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1235 1236 scfdie();
1236 1237 return (0);
1237 1238 } else {
1238 1239 return (1);
1239 1240 }
1240 1241 }
1241 1242
1242 1243 /*
1243 1244 * Decode FMRI into a service or instance, and put the result in *ep. If
1244 1245 * memory cannot be allocated, return SCF_ERROR_NO_MEMORY. If the FMRI is
1245 1246 * invalid, return SCF_ERROR_INVALID_ARGUMENT. If the FMRI does not specify
1246 1247 * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED. If the entity cannot be
1247 1248 * found, return SCF_ERROR_NOT_FOUND. Otherwise return SCF_ERROR_NONE, point
1248 1249 * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1249 1250 * whether *ep is a service.
1250 1251 */
1251 1252 static scf_error_t
1252 1253 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1253 1254 {
1254 1255 char *fmri_copy;
1255 1256 const char *sstr, *istr, *pgstr;
1256 1257 scf_service_t *svc;
1257 1258 scf_instance_t *inst;
1258 1259
1259 1260 fmri_copy = strdup(fmri);
1260 1261 if (fmri_copy == NULL)
1261 1262 return (SCF_ERROR_NO_MEMORY);
1262 1263
1263 1264 if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1264 1265 SCF_SUCCESS) {
1265 1266 free(fmri_copy);
1266 1267 return (SCF_ERROR_INVALID_ARGUMENT);
1267 1268 }
1268 1269
1269 1270 free(fmri_copy);
1270 1271
1271 1272 if (sstr == NULL || pgstr != NULL)
1272 1273 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1273 1274
1274 1275 if (istr == NULL) {
1275 1276 svc = scf_service_create(h);
1276 1277 if (svc == NULL)
1277 1278 return (SCF_ERROR_NO_MEMORY);
1278 1279
1279 1280 if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1280 1281 SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1281 1282 if (scf_error() != SCF_ERROR_NOT_FOUND)
1282 1283 scfdie();
1283 1284
1284 1285 return (SCF_ERROR_NOT_FOUND);
1285 1286 }
1286 1287
1287 1288 *ep = svc;
1288 1289 *isservice = 1;
1289 1290 } else {
1290 1291 inst = scf_instance_create(h);
1291 1292 if (inst == NULL)
1292 1293 return (SCF_ERROR_NO_MEMORY);
1293 1294
1294 1295 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1295 1296 NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1296 1297 if (scf_error() != SCF_ERROR_NOT_FOUND)
1297 1298 scfdie();
1298 1299
1299 1300 return (SCF_ERROR_NOT_FOUND);
1300 1301 }
1301 1302
1302 1303 *ep = inst;
1303 1304 *isservice = 0;
1304 1305 }
1305 1306
1306 1307 return (SCF_ERROR_NONE);
1307 1308 }
1308 1309
1309 1310 /*
1310 1311 * Create the entity named by fmri. Place a pointer to its libscf handle in
1311 1312 * *ep, and set or clear *isservicep if it is a service or an instance.
1312 1313 * Returns
1313 1314 * SCF_ERROR_NONE - success
1314 1315 * SCF_ERROR_NO_MEMORY - scf_*_create() failed
1315 1316 * SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1316 1317 * SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1317 1318 * SCF_ERROR_NOT_FOUND - no such scope
1318 1319 * SCF_ERROR_PERMISSION_DENIED
1319 1320 * SCF_ERROR_BACKEND_READONLY
1320 1321 * SCF_ERROR_BACKEND_ACCESS
1321 1322 */
1322 1323 static scf_error_t
1323 1324 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1324 1325 {
1325 1326 char *fmri_copy;
1326 1327 const char *scstr, *sstr, *istr, *pgstr;
1327 1328 scf_scope_t *scope = NULL;
1328 1329 scf_service_t *svc = NULL;
1329 1330 scf_instance_t *inst = NULL;
1330 1331 scf_error_t scfe;
1331 1332
1332 1333 fmri_copy = safe_strdup(fmri);
1333 1334
1334 1335 if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1335 1336 0) {
1336 1337 free(fmri_copy);
1337 1338 return (SCF_ERROR_INVALID_ARGUMENT);
1338 1339 }
1339 1340
1340 1341 if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1341 1342 free(fmri_copy);
1342 1343 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1343 1344 }
1344 1345
1345 1346 *ep = NULL;
1346 1347
1347 1348 if ((scope = scf_scope_create(h)) == NULL ||
1348 1349 (svc = scf_service_create(h)) == NULL ||
1349 1350 (inst = scf_instance_create(h)) == NULL) {
1350 1351 scfe = SCF_ERROR_NO_MEMORY;
1351 1352 goto out;
1352 1353 }
1353 1354
1354 1355 get_scope:
1355 1356 if (scf_handle_get_scope(h, scstr, scope) != 0) {
1356 1357 switch (scf_error()) {
1357 1358 case SCF_ERROR_CONNECTION_BROKEN:
1358 1359 scfdie();
1359 1360 /* NOTREACHED */
1360 1361
1361 1362 case SCF_ERROR_NOT_FOUND:
1362 1363 scfe = SCF_ERROR_NOT_FOUND;
1363 1364 goto out;
1364 1365
1365 1366 case SCF_ERROR_HANDLE_MISMATCH:
1366 1367 case SCF_ERROR_NOT_BOUND:
1367 1368 case SCF_ERROR_INVALID_ARGUMENT:
1368 1369 default:
1369 1370 bad_error("scf_handle_get_scope", scf_error());
1370 1371 }
1371 1372 }
1372 1373
1373 1374 get_svc:
1374 1375 if (scf_scope_get_service(scope, sstr, svc) != 0) {
1375 1376 switch (scf_error()) {
1376 1377 case SCF_ERROR_CONNECTION_BROKEN:
1377 1378 scfdie();
1378 1379 /* NOTREACHED */
1379 1380
1380 1381 case SCF_ERROR_DELETED:
1381 1382 goto get_scope;
1382 1383
1383 1384 case SCF_ERROR_NOT_FOUND:
1384 1385 break;
1385 1386
1386 1387 case SCF_ERROR_HANDLE_MISMATCH:
1387 1388 case SCF_ERROR_INVALID_ARGUMENT:
1388 1389 case SCF_ERROR_NOT_BOUND:
1389 1390 case SCF_ERROR_NOT_SET:
1390 1391 default:
1391 1392 bad_error("scf_scope_get_service", scf_error());
1392 1393 }
1393 1394
1394 1395 if (scf_scope_add_service(scope, sstr, svc) != 0) {
1395 1396 switch (scf_error()) {
1396 1397 case SCF_ERROR_CONNECTION_BROKEN:
1397 1398 scfdie();
1398 1399 /* NOTREACHED */
1399 1400
1400 1401 case SCF_ERROR_DELETED:
1401 1402 goto get_scope;
1402 1403
1403 1404 case SCF_ERROR_PERMISSION_DENIED:
1404 1405 case SCF_ERROR_BACKEND_READONLY:
1405 1406 case SCF_ERROR_BACKEND_ACCESS:
1406 1407 scfe = scf_error();
1407 1408 goto out;
1408 1409
1409 1410 case SCF_ERROR_HANDLE_MISMATCH:
1410 1411 case SCF_ERROR_INVALID_ARGUMENT:
1411 1412 case SCF_ERROR_NOT_BOUND:
1412 1413 case SCF_ERROR_NOT_SET:
1413 1414 default:
1414 1415 bad_error("scf_scope_get_service", scf_error());
1415 1416 }
1416 1417 }
1417 1418 }
1418 1419
1419 1420 if (istr == NULL) {
1420 1421 scfe = SCF_ERROR_NONE;
1421 1422 *ep = svc;
1422 1423 *isservicep = 1;
1423 1424 goto out;
1424 1425 }
1425 1426
1426 1427 get_inst:
1427 1428 if (scf_service_get_instance(svc, istr, inst) != 0) {
1428 1429 switch (scf_error()) {
1429 1430 case SCF_ERROR_CONNECTION_BROKEN:
1430 1431 scfdie();
1431 1432 /* NOTREACHED */
1432 1433
1433 1434 case SCF_ERROR_DELETED:
1434 1435 goto get_svc;
1435 1436
1436 1437 case SCF_ERROR_NOT_FOUND:
1437 1438 break;
1438 1439
1439 1440 case SCF_ERROR_HANDLE_MISMATCH:
1440 1441 case SCF_ERROR_INVALID_ARGUMENT:
1441 1442 case SCF_ERROR_NOT_BOUND:
1442 1443 case SCF_ERROR_NOT_SET:
1443 1444 default:
1444 1445 bad_error("scf_service_get_instance", scf_error());
1445 1446 }
1446 1447
1447 1448 if (scf_service_add_instance(svc, istr, inst) != 0) {
1448 1449 switch (scf_error()) {
1449 1450 case SCF_ERROR_CONNECTION_BROKEN:
1450 1451 scfdie();
1451 1452 /* NOTREACHED */
1452 1453
1453 1454 case SCF_ERROR_DELETED:
1454 1455 goto get_svc;
1455 1456
1456 1457 case SCF_ERROR_PERMISSION_DENIED:
1457 1458 case SCF_ERROR_BACKEND_READONLY:
1458 1459 case SCF_ERROR_BACKEND_ACCESS:
1459 1460 scfe = scf_error();
1460 1461 goto out;
1461 1462
1462 1463 case SCF_ERROR_HANDLE_MISMATCH:
1463 1464 case SCF_ERROR_INVALID_ARGUMENT:
1464 1465 case SCF_ERROR_NOT_BOUND:
1465 1466 case SCF_ERROR_NOT_SET:
1466 1467 default:
1467 1468 bad_error("scf_service_add_instance",
1468 1469 scf_error());
1469 1470 }
1470 1471 }
1471 1472 }
1472 1473
1473 1474 scfe = SCF_ERROR_NONE;
1474 1475 *ep = inst;
1475 1476 *isservicep = 0;
1476 1477
1477 1478 out:
1478 1479 if (*ep != inst)
1479 1480 scf_instance_destroy(inst);
1480 1481 if (*ep != svc)
1481 1482 scf_service_destroy(svc);
1482 1483 scf_scope_destroy(scope);
1483 1484 free(fmri_copy);
1484 1485 return (scfe);
1485 1486 }
1486 1487
1487 1488 /*
1488 1489 * Create or update a snapshot of inst. snap is a required scratch object.
1489 1490 *
1490 1491 * Returns
1491 1492 * 0 - success
1492 1493 * ECONNABORTED - repository connection broken
1493 1494 * EPERM - permission denied
1494 1495 * ENOSPC - configd is out of resources
1495 1496 * ECANCELED - inst was deleted
1496 1497 * -1 - unknown libscf error (message printed)
1497 1498 */
1498 1499 static int
1499 1500 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1500 1501 {
1501 1502 again:
1502 1503 if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1503 1504 if (_scf_snapshot_take_attach(inst, snap) != 0) {
1504 1505 switch (scf_error()) {
1505 1506 case SCF_ERROR_CONNECTION_BROKEN:
1506 1507 case SCF_ERROR_PERMISSION_DENIED:
1507 1508 case SCF_ERROR_NO_RESOURCES:
1508 1509 return (scferror2errno(scf_error()));
1509 1510
1510 1511 case SCF_ERROR_NOT_SET:
1511 1512 case SCF_ERROR_INVALID_ARGUMENT:
1512 1513 default:
1513 1514 bad_error("_scf_snapshot_take_attach",
1514 1515 scf_error());
1515 1516 }
1516 1517 }
1517 1518 } else {
1518 1519 switch (scf_error()) {
1519 1520 case SCF_ERROR_NOT_FOUND:
1520 1521 break;
1521 1522
1522 1523 case SCF_ERROR_DELETED:
1523 1524 case SCF_ERROR_CONNECTION_BROKEN:
1524 1525 return (scferror2errno(scf_error()));
1525 1526
1526 1527 case SCF_ERROR_HANDLE_MISMATCH:
1527 1528 case SCF_ERROR_NOT_BOUND:
1528 1529 case SCF_ERROR_INVALID_ARGUMENT:
1529 1530 case SCF_ERROR_NOT_SET:
1530 1531 default:
1531 1532 bad_error("scf_instance_get_snapshot", scf_error());
1532 1533 }
1533 1534
1534 1535 if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1535 1536 switch (scf_error()) {
1536 1537 case SCF_ERROR_EXISTS:
1537 1538 goto again;
1538 1539
1539 1540 case SCF_ERROR_CONNECTION_BROKEN:
1540 1541 case SCF_ERROR_NO_RESOURCES:
1541 1542 case SCF_ERROR_PERMISSION_DENIED:
1542 1543 return (scferror2errno(scf_error()));
1543 1544
1544 1545 default:
1545 1546 scfwarn();
1546 1547 return (-1);
1547 1548
1548 1549 case SCF_ERROR_NOT_SET:
1549 1550 case SCF_ERROR_INTERNAL:
1550 1551 case SCF_ERROR_INVALID_ARGUMENT:
1551 1552 case SCF_ERROR_HANDLE_MISMATCH:
1552 1553 bad_error("_scf_snapshot_take_new",
1553 1554 scf_error());
1554 1555 }
1555 1556 }
1556 1557 }
1557 1558
1558 1559 return (0);
1559 1560 }
1560 1561
1561 1562 static int
1562 1563 refresh_running_snapshot(void *entity)
1563 1564 {
1564 1565 scf_snapshot_t *snap;
1565 1566 int r;
1566 1567
1567 1568 if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1568 1569 scfdie();
1569 1570 r = take_snap(entity, snap_running, snap);
1570 1571 scf_snapshot_destroy(snap);
1571 1572
1572 1573 return (r);
1573 1574 }
1574 1575
1575 1576 /*
1576 1577 * Refresh entity. If isservice is zero, take entity to be an scf_instance_t *.
1577 1578 * Otherwise take entity to be an scf_service_t * and refresh all of its child
1578 1579 * instances. fmri is used for messages. inst, iter, and name_buf are used
1579 1580 * for scratch space. Returns
1580 1581 * 0 - success
1581 1582 * ECONNABORTED - repository connection broken
1582 1583 * ECANCELED - entity was deleted
1583 1584 * EACCES - backend denied access
1584 1585 * EPERM - permission denied
1585 1586 * ENOSPC - repository server out of resources
1586 1587 * -1 - _smf_refresh_instance_i() failed. scf_error() should be set.
1587 1588 */
1588 1589 static int
1589 1590 refresh_entity(int isservice, void *entity, const char *fmri,
1590 1591 scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1591 1592 {
1592 1593 scf_error_t scfe;
1593 1594 int r;
1594 1595
1595 1596 if (!isservice) {
1596 1597 /*
1597 1598 * Let restarter handles refreshing and making new running
1598 1599 * snapshot only if operating on a live repository and not
1599 1600 * running in early import.
1600 1601 */
1601 1602 if (est->sc_repo_filename == NULL &&
1602 1603 est->sc_repo_doorname == NULL &&
1603 1604 est->sc_in_emi == 0) {
1604 1605 if (_smf_refresh_instance_i(entity) == 0) {
1605 1606 if (g_verbose)
1606 1607 warn(gettext("Refreshed %s.\n"), fmri);
1607 1608 return (0);
1608 1609 }
1609 1610
1610 1611 switch (scf_error()) {
1611 1612 case SCF_ERROR_BACKEND_ACCESS:
1612 1613 return (EACCES);
1613 1614
1614 1615 case SCF_ERROR_PERMISSION_DENIED:
1615 1616 return (EPERM);
1616 1617
1617 1618 default:
1618 1619 return (-1);
1619 1620 }
1620 1621 } else {
1621 1622 r = refresh_running_snapshot(entity);
1622 1623 switch (r) {
1623 1624 case 0:
1624 1625 break;
1625 1626
1626 1627 case ECONNABORTED:
1627 1628 case ECANCELED:
1628 1629 case EPERM:
1629 1630 case ENOSPC:
1630 1631 break;
1631 1632
1632 1633 default:
1633 1634 bad_error("refresh_running_snapshot",
1634 1635 scf_error());
1635 1636 }
1636 1637
1637 1638 return (r);
1638 1639 }
1639 1640 }
1640 1641
1641 1642 if (scf_iter_service_instances(iter, entity) != 0) {
1642 1643 switch (scf_error()) {
1643 1644 case SCF_ERROR_CONNECTION_BROKEN:
1644 1645 return (ECONNABORTED);
1645 1646
1646 1647 case SCF_ERROR_DELETED:
1647 1648 return (ECANCELED);
1648 1649
1649 1650 case SCF_ERROR_HANDLE_MISMATCH:
1650 1651 case SCF_ERROR_NOT_BOUND:
1651 1652 case SCF_ERROR_NOT_SET:
1652 1653 default:
1653 1654 bad_error("scf_iter_service_instances", scf_error());
1654 1655 }
1655 1656 }
1656 1657
1657 1658 for (;;) {
1658 1659 r = scf_iter_next_instance(iter, inst);
1659 1660 if (r == 0)
1660 1661 break;
1661 1662 if (r != 1) {
1662 1663 switch (scf_error()) {
1663 1664 case SCF_ERROR_CONNECTION_BROKEN:
1664 1665 return (ECONNABORTED);
1665 1666
1666 1667 case SCF_ERROR_DELETED:
1667 1668 return (ECANCELED);
1668 1669
1669 1670 case SCF_ERROR_HANDLE_MISMATCH:
1670 1671 case SCF_ERROR_NOT_BOUND:
1671 1672 case SCF_ERROR_NOT_SET:
1672 1673 case SCF_ERROR_INVALID_ARGUMENT:
1673 1674 default:
1674 1675 bad_error("scf_iter_next_instance",
1675 1676 scf_error());
1676 1677 }
1677 1678 }
1678 1679
1679 1680 /*
1680 1681 * Similarly, just take a new running snapshot if operating on
1681 1682 * a non-live repository or running during early import.
1682 1683 */
1683 1684 if (est->sc_repo_filename != NULL ||
1684 1685 est->sc_repo_doorname != NULL ||
1685 1686 est->sc_in_emi == 1) {
1686 1687 r = refresh_running_snapshot(inst);
1687 1688 switch (r) {
1688 1689 case 0:
1689 1690 continue;
1690 1691
1691 1692 case ECONNABORTED:
1692 1693 case ECANCELED:
1693 1694 case EPERM:
1694 1695 case ENOSPC:
1695 1696 break;
1696 1697 default:
1697 1698 bad_error("refresh_running_snapshot",
1698 1699 scf_error());
1699 1700 }
1700 1701
1701 1702 return (r);
1702 1703
1703 1704 }
1704 1705
1705 1706 if (_smf_refresh_instance_i(inst) == 0) {
1706 1707 if (g_verbose) {
1707 1708 if (scf_instance_get_name(inst, name_buf,
1708 1709 max_scf_name_len + 1) < 0)
1709 1710 (void) strcpy(name_buf, "?");
1710 1711
1711 1712 warn(gettext("Refreshed %s:%s.\n"),
1712 1713 fmri, name_buf);
1713 1714 }
1714 1715 } else {
1715 1716 if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1716 1717 g_verbose) {
1717 1718 scfe = scf_error();
1718 1719
1719 1720 if (scf_instance_to_fmri(inst, name_buf,
1720 1721 max_scf_name_len + 1) < 0)
1721 1722 (void) strcpy(name_buf, "?");
1722 1723
1723 1724 warn(gettext(
1724 1725 "Refresh of %s:%s failed: %s.\n"), fmri,
1725 1726 name_buf, scf_strerror(scfe));
1726 1727 }
1727 1728 }
1728 1729 }
1729 1730
1730 1731 return (0);
1731 1732 }
1732 1733
1733 1734 static void
1734 1735 private_refresh(void)
1735 1736 {
1736 1737 scf_instance_t *pinst = NULL;
1737 1738 scf_iter_t *piter = NULL;
1738 1739 ssize_t fmrilen;
1739 1740 size_t bufsz;
1740 1741 char *fmribuf;
1741 1742 void *ent;
1742 1743 int issvc;
1743 1744 int r;
1744 1745
1745 1746 if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1746 1747 return;
1747 1748
1748 1749 assert(cur_svc != NULL);
1749 1750
1750 1751 bufsz = max_scf_fmri_len + 1;
1751 1752 fmribuf = safe_malloc(bufsz);
1752 1753 if (cur_inst) {
1753 1754 issvc = 0;
1754 1755 ent = cur_inst;
1755 1756 fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1756 1757 } else {
1757 1758 issvc = 1;
1758 1759 ent = cur_svc;
1759 1760 fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1760 1761 if ((pinst = scf_instance_create(g_hndl)) == NULL)
1761 1762 scfdie();
1762 1763
1763 1764 if ((piter = scf_iter_create(g_hndl)) == NULL)
1764 1765 scfdie();
1765 1766 }
1766 1767 if (fmrilen < 0) {
1767 1768 free(fmribuf);
1768 1769 if (scf_error() != SCF_ERROR_DELETED)
1769 1770 scfdie();
1770 1771
1771 1772 warn(emsg_deleted);
1772 1773 return;
1773 1774 }
1774 1775 assert(fmrilen < bufsz);
1775 1776
1776 1777 r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1777 1778 switch (r) {
1778 1779 case 0:
1779 1780 break;
1780 1781
1781 1782 case ECONNABORTED:
1782 1783 warn(gettext("Could not refresh %s "
1783 1784 "(repository connection broken).\n"), fmribuf);
1784 1785 break;
1785 1786
1786 1787 case ECANCELED:
1787 1788 warn(emsg_deleted);
1788 1789 break;
1789 1790
1790 1791 case EPERM:
1791 1792 warn(gettext("Could not refresh %s "
1792 1793 "(permission denied).\n"), fmribuf);
1793 1794 break;
1794 1795
1795 1796 case ENOSPC:
1796 1797 warn(gettext("Could not refresh %s "
1797 1798 "(repository server out of resources).\n"),
1798 1799 fmribuf);
1799 1800 break;
1800 1801
1801 1802 case EACCES:
1802 1803 default:
1803 1804 bad_error("refresh_entity", scf_error());
1804 1805 }
1805 1806
1806 1807 if (issvc) {
1807 1808 scf_instance_destroy(pinst);
1808 1809 scf_iter_destroy(piter);
1809 1810 }
1810 1811
1811 1812 free(fmribuf);
1812 1813 }
1813 1814
1814 1815
1815 1816 static int
1816 1817 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1817 1818 {
1818 1819 cbp->sc_err = scferror2errno(err);
1819 1820 return (UU_WALK_ERROR);
1820 1821 }
1821 1822
1822 1823 static int
1823 1824 stash_scferror(scf_callback_t *cbp)
1824 1825 {
1825 1826 return (stash_scferror_err(cbp, scf_error()));
1826 1827 }
1827 1828
1828 1829 static int select_inst(const char *);
1829 1830 static int select_svc(const char *);
1830 1831
1831 1832 /*
1832 1833 * Take a property that does not have a type and check to see if a type
1833 1834 * exists or can be gleened from the current data. Set the type.
1834 1835 *
1835 1836 * Check the current level (instance) and then check the higher level
1836 1837 * (service). This could be the case for adding a new property to
1837 1838 * the instance that's going to "override" a service level property.
1838 1839 *
1839 1840 * For a property :
1840 1841 * 1. Take the type from an existing property
1841 1842 * 2. Take the type from a template entry
1842 1843 *
1843 1844 * If the type can not be found, then leave the type as is, and let the import
1844 1845 * report the problem of the missing type.
1845 1846 */
1846 1847 static int
1847 1848 find_current_prop_type(void *p, void *g)
1848 1849 {
1849 1850 property_t *prop = p;
1850 1851 scf_callback_t *lcb = g;
1851 1852 pgroup_t *pg = NULL;
1852 1853
1853 1854 const char *fmri = NULL;
1854 1855 char *lfmri = NULL;
1855 1856 char *cur_selection = NULL;
1856 1857
1857 1858 scf_propertygroup_t *sc_pg = NULL;
1858 1859 scf_property_t *sc_prop = NULL;
1859 1860 scf_pg_tmpl_t *t_pg = NULL;
1860 1861 scf_prop_tmpl_t *t_prop = NULL;
1861 1862 scf_type_t prop_type;
1862 1863
1863 1864 value_t *vp;
1864 1865 int issvc = lcb->sc_service;
1865 1866 int r = UU_WALK_ERROR;
1866 1867
1867 1868 if (prop->sc_value_type != SCF_TYPE_INVALID)
1868 1869 return (UU_WALK_NEXT);
1869 1870
1870 1871 t_prop = scf_tmpl_prop_create(g_hndl);
1871 1872 sc_prop = scf_property_create(g_hndl);
1872 1873 if (sc_prop == NULL || t_prop == NULL) {
1873 1874 warn(gettext("Unable to create the property to attempt and "
1874 1875 "find a missing type.\n"));
1875 1876
1876 1877 scf_property_destroy(sc_prop);
1877 1878 scf_tmpl_prop_destroy(t_prop);
1878 1879
1879 1880 return (UU_WALK_ERROR);
1880 1881 }
1881 1882
1882 1883 if (lcb->sc_flags == 1) {
1883 1884 pg = lcb->sc_parent;
1884 1885 issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT);
1885 1886 fmri = pg->sc_parent->sc_fmri;
1886 1887 retry_pg:
1887 1888 if (cur_svc && cur_selection == NULL) {
1888 1889 cur_selection = safe_malloc(max_scf_fmri_len + 1);
1889 1890 lscf_get_selection_str(cur_selection,
1890 1891 max_scf_fmri_len + 1);
1891 1892
1892 1893 if (strcmp(cur_selection, fmri) != 0) {
1893 1894 lscf_select(fmri);
1894 1895 } else {
1895 1896 free(cur_selection);
1896 1897 cur_selection = NULL;
1897 1898 }
1898 1899 } else {
1899 1900 lscf_select(fmri);
1900 1901 }
1901 1902
1902 1903 if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) {
1903 1904 warn(gettext("Unable to create property group to "
1904 1905 "find a missing property type.\n"));
1905 1906
1906 1907 goto out;
1907 1908 }
1908 1909
1909 1910 if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) {
1910 1911 /*
1911 1912 * If this is the sc_pg from the parent
1912 1913 * let the caller clean up the sc_pg,
1913 1914 * and just throw it away in this case.
1914 1915 */
1915 1916 if (sc_pg != lcb->sc_parent)
1916 1917 scf_pg_destroy(sc_pg);
1917 1918
1918 1919 sc_pg = NULL;
1919 1920 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1920 1921 warn(gettext("Unable to create template "
1921 1922 "property group to find a property "
1922 1923 "type.\n"));
1923 1924
1924 1925 goto out;
1925 1926 }
1926 1927
1927 1928 if (scf_tmpl_get_by_pg_name(fmri, NULL,
1928 1929 pg->sc_pgroup_name, NULL, t_pg,
1929 1930 SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) {
1930 1931 /*
1931 1932 * if instance get service and jump back
1932 1933 */
1933 1934 scf_tmpl_pg_destroy(t_pg);
1934 1935 t_pg = NULL;
1935 1936 if (issvc == 0) {
1936 1937 entity_t *e = pg->sc_parent->sc_parent;
1937 1938
1938 1939 fmri = e->sc_fmri;
1939 1940 issvc = 1;
1940 1941 goto retry_pg;
1941 1942 } else {
1942 1943 goto out;
1943 1944 }
1944 1945 }
1945 1946 }
1946 1947 } else {
1947 1948 sc_pg = lcb->sc_parent;
1948 1949 }
1949 1950
1950 1951 /*
1951 1952 * Attempt to get the type from an existing property. If the property
1952 1953 * cannot be found then attempt to get the type from a template entry
1953 1954 * for the property.
1954 1955 *
1955 1956 * Finally, if at the instance level look at the service level.
1956 1957 */
1957 1958 if (sc_pg != NULL &&
1958 1959 pg_get_prop(sc_pg, prop->sc_property_name,
1959 1960 sc_prop) == SCF_SUCCESS &&
1960 1961 scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) {
1961 1962 prop->sc_value_type = prop_type;
1962 1963
1963 1964 /*
1964 1965 * Found a type, update the value types and validate
1965 1966 * the actual value against this type.
1966 1967 */
1967 1968 for (vp = uu_list_first(prop->sc_property_values);
1968 1969 vp != NULL;
1969 1970 vp = uu_list_next(prop->sc_property_values, vp)) {
1970 1971 vp->sc_type = prop->sc_value_type;
1971 1972 lxml_store_value(vp, 0, NULL);
1972 1973 }
1973 1974
1974 1975 r = UU_WALK_NEXT;
1975 1976 goto out;
1976 1977 }
1977 1978
1978 1979 /*
1979 1980 * If we get here with t_pg set to NULL then we had to have
1980 1981 * gotten an sc_pg but that sc_pg did not have the property
1981 1982 * we are looking for. So if the t_pg is not null look up
1982 1983 * the template entry for the property.
1983 1984 *
1984 1985 * If the t_pg is null then need to attempt to get a matching
1985 1986 * template entry for the sc_pg, and see if there is a property
1986 1987 * entry for that template entry.
1987 1988 */
1988 1989 do_tmpl :
1989 1990 if (t_pg != NULL &&
1990 1991 scf_tmpl_get_by_prop(t_pg, prop->sc_property_name,
1991 1992 t_prop, 0) == SCF_SUCCESS) {
1992 1993 if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) {
1993 1994 prop->sc_value_type = prop_type;
1994 1995
1995 1996 /*
1996 1997 * Found a type, update the value types and validate
1997 1998 * the actual value against this type.
1998 1999 */
1999 2000 for (vp = uu_list_first(prop->sc_property_values);
2000 2001 vp != NULL;
2001 2002 vp = uu_list_next(prop->sc_property_values, vp)) {
2002 2003 vp->sc_type = prop->sc_value_type;
2003 2004 lxml_store_value(vp, 0, NULL);
2004 2005 }
2005 2006
2006 2007 r = UU_WALK_NEXT;
2007 2008 goto out;
2008 2009 }
2009 2010 } else {
2010 2011 if (t_pg == NULL && sc_pg) {
2011 2012 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
2012 2013 warn(gettext("Unable to create template "
2013 2014 "property group to find a property "
2014 2015 "type.\n"));
2015 2016
2016 2017 goto out;
2017 2018 }
2018 2019
2019 2020 if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
2020 2021 scf_tmpl_pg_destroy(t_pg);
2021 2022 t_pg = NULL;
2022 2023 } else {
2023 2024 goto do_tmpl;
2024 2025 }
2025 2026 }
2026 2027 }
2027 2028
2028 2029 if (issvc == 0) {
2029 2030 scf_instance_t *i;
2030 2031 scf_service_t *s;
2031 2032
2032 2033 issvc = 1;
2033 2034 if (lcb->sc_flags == 1) {
2034 2035 entity_t *e = pg->sc_parent->sc_parent;
2035 2036
2036 2037 fmri = e->sc_fmri;
2037 2038 goto retry_pg;
2038 2039 }
2039 2040
2040 2041 /*
2041 2042 * because lcb->sc_flags was not set then this means
2042 2043 * the pg was not used and can be used here.
2043 2044 */
2044 2045 if ((pg = internal_pgroup_new()) == NULL) {
2045 2046 warn(gettext("Could not create internal property group "
2046 2047 "to find a missing type."));
2047 2048
2048 2049 goto out;
2049 2050 }
2050 2051
2051 2052 pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1);
2052 2053 if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name,
2053 2054 max_scf_name_len + 1) < 0)
2054 2055 goto out;
2055 2056
2056 2057 i = scf_instance_create(g_hndl);
2057 2058 s = scf_service_create(g_hndl);
2058 2059 if (i == NULL || s == NULL ||
2059 2060 scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) {
2060 2061 warn(gettext("Could not get a service for the instance "
2061 2062 "to find a missing type."));
2062 2063
2063 2064 goto out;
2064 2065 }
2065 2066
2066 2067 /*
2067 2068 * Check to see truly at the instance level.
2068 2069 */
2069 2070 lfmri = safe_malloc(max_scf_fmri_len + 1);
2070 2071 if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
2071 2072 scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0)
2072 2073 goto out;
2073 2074 else
2074 2075 fmri = (const char *)lfmri;
2075 2076
2076 2077 goto retry_pg;
2077 2078 }
2078 2079
2079 2080 out :
2080 2081 if (sc_pg != lcb->sc_parent) {
2081 2082 scf_pg_destroy(sc_pg);
2082 2083 }
2083 2084
2084 2085 /*
2085 2086 * If this is true then the pg was allocated
2086 2087 * here, and the name was set so need to free
2087 2088 * the name and the pg.
2088 2089 */
2089 2090 if (pg != NULL && pg != lcb->sc_parent) {
2090 2091 free((char *)pg->sc_pgroup_name);
2091 2092 internal_pgroup_free(pg);
2092 2093 }
2093 2094
2094 2095 if (cur_selection) {
2095 2096 lscf_select(cur_selection);
2096 2097 free(cur_selection);
2097 2098 }
2098 2099
2099 2100 scf_tmpl_pg_destroy(t_pg);
2100 2101 scf_tmpl_prop_destroy(t_prop);
2101 2102 scf_property_destroy(sc_prop);
2102 2103
2103 2104 if (r != UU_WALK_NEXT)
2104 2105 warn(gettext("Could not find property type for \"%s\" "
2105 2106 "from \"%s\"\n"), prop->sc_property_name,
2106 2107 fmri != NULL ? fmri : lcb->sc_source_fmri);
2107 2108
2108 2109 free(lfmri);
2109 2110
2110 2111 return (r);
2111 2112 }
2112 2113
2113 2114 /*
2114 2115 * Take a property group that does not have a type and check to see if a type
2115 2116 * exists or can be gleened from the current data. Set the type.
2116 2117 *
2117 2118 * Check the current level (instance) and then check the higher level
2118 2119 * (service). This could be the case for adding a new property to
2119 2120 * the instance that's going to "override" a service level property.
2120 2121 *
2121 2122 * For a property group
2122 2123 * 1. Take the type from an existing property group
2123 2124 * 2. Take the type from a template entry
2124 2125 *
2125 2126 * If the type can not be found, then leave the type as is, and let the import
2126 2127 * report the problem of the missing type.
2127 2128 */
2128 2129 static int
2129 2130 find_current_pg_type(void *p, void *sori)
2130 2131 {
2131 2132 entity_t *si = sori;
2132 2133 pgroup_t *pg = p;
2133 2134
2134 2135 const char *ofmri, *fmri;
2135 2136 char *cur_selection = NULL;
2136 2137 char *pg_type = NULL;
2137 2138
2138 2139 scf_propertygroup_t *sc_pg = NULL;
2139 2140 scf_pg_tmpl_t *t_pg = NULL;
2140 2141
2141 2142 int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2142 2143 int r = UU_WALK_ERROR;
2143 2144
2144 2145 ofmri = fmri = si->sc_fmri;
2145 2146 if (pg->sc_pgroup_type != NULL) {
2146 2147 r = UU_WALK_NEXT;
2147 2148
2148 2149 goto out;
2149 2150 }
2150 2151
2151 2152 sc_pg = scf_pg_create(g_hndl);
2152 2153 if (sc_pg == NULL) {
2153 2154 warn(gettext("Unable to create property group to attempt "
2154 2155 "and find a missing type.\n"));
2155 2156
2156 2157 return (UU_WALK_ERROR);
2157 2158 }
2158 2159
2159 2160 /*
2160 2161 * Using get_pg() requires that the cur_svc/cur_inst be
2161 2162 * via lscf_select. Need to preserve the current selection
2162 2163 * if going to use lscf_select() to set up the cur_svc/cur_inst
2163 2164 */
2164 2165 if (cur_svc) {
2165 2166 cur_selection = safe_malloc(max_scf_fmri_len + 1);
2166 2167 lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1);
2167 2168 }
2168 2169
2169 2170 /*
2170 2171 * If the property group exists get the type, and set
2171 2172 * the pgroup_t type of that type.
2172 2173 *
2173 2174 * If not the check for a template pg_pattern entry
2174 2175 * and take the type from that.
2175 2176 */
2176 2177 retry_svc:
2177 2178 lscf_select(fmri);
2178 2179
2179 2180 if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) {
2180 2181 pg_type = safe_malloc(max_scf_pg_type_len + 1);
2181 2182 if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type,
2182 2183 max_scf_pg_type_len + 1) != -1) {
2183 2184 pg->sc_pgroup_type = pg_type;
2184 2185
2185 2186 r = UU_WALK_NEXT;
2186 2187 goto out;
2187 2188 } else {
2188 2189 free(pg_type);
2189 2190 }
2190 2191 } else {
2191 2192 if ((t_pg == NULL) &&
2192 2193 (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
2193 2194 goto out;
2194 2195
2195 2196 if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name,
2196 2197 NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS &&
2197 2198 scf_tmpl_pg_type(t_pg, &pg_type) != -1) {
2198 2199 pg->sc_pgroup_type = pg_type;
2199 2200
2200 2201 r = UU_WALK_NEXT;
2201 2202 goto out;
2202 2203 }
2203 2204 }
2204 2205
2205 2206 /*
2206 2207 * If type is not found at the instance level then attempt to
2207 2208 * find the type at the service level.
2208 2209 */
2209 2210 if (!issvc) {
2210 2211 si = si->sc_parent;
2211 2212 fmri = si->sc_fmri;
2212 2213 issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2213 2214 goto retry_svc;
2214 2215 }
2215 2216
2216 2217 out :
2217 2218 if (cur_selection) {
2218 2219 lscf_select(cur_selection);
2219 2220 free(cur_selection);
2220 2221 }
2221 2222
2222 2223 /*
2223 2224 * Now walk the properties of the property group to make sure that
2224 2225 * all properties have the correct type and values are valid for
2225 2226 * those types.
2226 2227 */
2227 2228 if (r == UU_WALK_NEXT) {
2228 2229 scf_callback_t cb;
2229 2230
2230 2231 cb.sc_service = issvc;
2231 2232 cb.sc_source_fmri = ofmri;
2232 2233 if (sc_pg != NULL) {
2233 2234 cb.sc_parent = sc_pg;
2234 2235 cb.sc_flags = 0;
2235 2236 } else {
2236 2237 cb.sc_parent = pg;
2237 2238 cb.sc_flags = 1;
2238 2239 }
2239 2240
2240 2241 if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type,
2241 2242 &cb, UU_DEFAULT) != 0) {
2242 2243 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2243 2244 bad_error("uu_list_walk", uu_error());
2244 2245
2245 2246 r = UU_WALK_ERROR;
2246 2247 }
2247 2248 } else {
2248 2249 warn(gettext("Could not find property group type for "
2249 2250 "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri);
2250 2251 }
2251 2252
2252 2253 scf_tmpl_pg_destroy(t_pg);
2253 2254 scf_pg_destroy(sc_pg);
2254 2255
2255 2256 return (r);
2256 2257 }
2257 2258
2258 2259 /*
2259 2260 * Import. These functions import a bundle into the repository.
2260 2261 */
2261 2262
2262 2263 /*
2263 2264 * Add a transaction entry to lcbdata->sc_trans for this property_t. Uses
2264 2265 * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata. On success,
2265 2266 * returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
2266 2267 * lcbdata->sc_err to
2267 2268 * ENOMEM - out of memory
2268 2269 * ECONNABORTED - repository connection broken
2269 2270 * ECANCELED - sc_trans's property group was deleted
2270 2271 * EINVAL - p's name is invalid (error printed)
2271 2272 * - p has an invalid value (error printed)
2272 2273 */
2273 2274 static int
2274 2275 lscf_property_import(void *v, void *pvt)
2275 2276 {
2276 2277 property_t *p = v;
2277 2278 scf_callback_t *lcbdata = pvt;
2278 2279 value_t *vp;
2279 2280 scf_transaction_t *trans = lcbdata->sc_trans;
2280 2281 scf_transaction_entry_t *entr;
2281 2282 scf_value_t *val;
2282 2283 scf_type_t tp;
2283 2284
2284 2285 if ((lcbdata->sc_flags & SCI_NOENABLED ||
2285 2286 lcbdata->sc_flags & SCI_DELAYENABLE) &&
2286 2287 strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
2287 2288 lcbdata->sc_enable = p;
2288 2289 return (UU_WALK_NEXT);
2289 2290 }
2290 2291
2291 2292 entr = scf_entry_create(lcbdata->sc_handle);
2292 2293 if (entr == NULL) {
2293 2294 switch (scf_error()) {
2294 2295 case SCF_ERROR_NO_MEMORY:
2295 2296 return (stash_scferror(lcbdata));
2296 2297
2297 2298 case SCF_ERROR_INVALID_ARGUMENT:
2298 2299 default:
2299 2300 bad_error("scf_entry_create", scf_error());
2300 2301 }
2301 2302 }
2302 2303
2303 2304 tp = p->sc_value_type;
2304 2305
2305 2306 if (scf_transaction_property_new(trans, entr,
2306 2307 p->sc_property_name, tp) != 0) {
2307 2308 switch (scf_error()) {
2308 2309 case SCF_ERROR_INVALID_ARGUMENT:
2309 2310 semerr(emsg_invalid_prop_name, p->sc_property_name);
2310 2311 scf_entry_destroy(entr);
2311 2312 return (stash_scferror(lcbdata));
2312 2313
2313 2314 case SCF_ERROR_EXISTS:
2314 2315 break;
2315 2316
2316 2317 case SCF_ERROR_DELETED:
2317 2318 case SCF_ERROR_CONNECTION_BROKEN:
2318 2319 scf_entry_destroy(entr);
2319 2320 return (stash_scferror(lcbdata));
2320 2321
2321 2322 case SCF_ERROR_NOT_BOUND:
2322 2323 case SCF_ERROR_HANDLE_MISMATCH:
2323 2324 case SCF_ERROR_NOT_SET:
2324 2325 default:
2325 2326 bad_error("scf_transaction_property_new", scf_error());
2326 2327 }
2327 2328
2328 2329 if (scf_transaction_property_change_type(trans, entr,
2329 2330 p->sc_property_name, tp) != 0) {
2330 2331 switch (scf_error()) {
2331 2332 case SCF_ERROR_DELETED:
2332 2333 case SCF_ERROR_CONNECTION_BROKEN:
2333 2334 scf_entry_destroy(entr);
2334 2335 return (stash_scferror(lcbdata));
2335 2336
2336 2337 case SCF_ERROR_INVALID_ARGUMENT:
2337 2338 semerr(emsg_invalid_prop_name,
2338 2339 p->sc_property_name);
2339 2340 scf_entry_destroy(entr);
2340 2341 return (stash_scferror(lcbdata));
2341 2342
2342 2343 case SCF_ERROR_NOT_FOUND:
2343 2344 case SCF_ERROR_NOT_SET:
2344 2345 case SCF_ERROR_HANDLE_MISMATCH:
2345 2346 case SCF_ERROR_NOT_BOUND:
2346 2347 default:
2347 2348 bad_error(
2348 2349 "scf_transaction_property_change_type",
2349 2350 scf_error());
2350 2351 }
2351 2352 }
2352 2353 }
2353 2354
2354 2355 for (vp = uu_list_first(p->sc_property_values);
2355 2356 vp != NULL;
2356 2357 vp = uu_list_next(p->sc_property_values, vp)) {
2357 2358 val = scf_value_create(g_hndl);
2358 2359 if (val == NULL) {
2359 2360 switch (scf_error()) {
2360 2361 case SCF_ERROR_NO_MEMORY:
2361 2362 return (stash_scferror(lcbdata));
2362 2363
2363 2364 case SCF_ERROR_INVALID_ARGUMENT:
2364 2365 default:
2365 2366 bad_error("scf_value_create", scf_error());
2366 2367 }
2367 2368 }
2368 2369
2369 2370 switch (tp) {
2370 2371 case SCF_TYPE_BOOLEAN:
2371 2372 scf_value_set_boolean(val, vp->sc_u.sc_count);
2372 2373 break;
2373 2374 case SCF_TYPE_COUNT:
2374 2375 scf_value_set_count(val, vp->sc_u.sc_count);
2375 2376 break;
2376 2377 case SCF_TYPE_INTEGER:
2377 2378 scf_value_set_integer(val, vp->sc_u.sc_integer);
2378 2379 break;
2379 2380 default:
2380 2381 assert(vp->sc_u.sc_string != NULL);
2381 2382 if (scf_value_set_from_string(val, tp,
2382 2383 vp->sc_u.sc_string) != 0) {
2383 2384 if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
2384 2385 bad_error("scf_value_set_from_string",
2385 2386 scf_error());
2386 2387
2387 2388 warn(gettext("Value \"%s\" is not a valid "
2388 2389 "%s.\n"), vp->sc_u.sc_string,
2389 2390 scf_type_to_string(tp));
2390 2391 scf_value_destroy(val);
2391 2392 return (stash_scferror(lcbdata));
2392 2393 }
2393 2394 break;
2394 2395 }
2395 2396
2396 2397 if (scf_entry_add_value(entr, val) != 0)
2397 2398 bad_error("scf_entry_add_value", scf_error());
2398 2399 }
2399 2400
2400 2401 return (UU_WALK_NEXT);
2401 2402 }
2402 2403
2403 2404 /*
2404 2405 * Import a pgroup_t into the repository. Uses sc_handle, sc_parent,
2405 2406 * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2406 2407 * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2407 2408 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
2408 2409 * lcbdata->sc_err to
2409 2410 * ECONNABORTED - repository connection broken
2410 2411 * ENOMEM - out of memory
2411 2412 * ENOSPC - svc.configd is out of resources
2412 2413 * ECANCELED - sc_parent was deleted
2413 2414 * EPERM - could not create property group (permission denied) (error printed)
2414 2415 * - could not modify property group (permission denied) (error printed)
2415 2416 * - could not delete property group (permission denied) (error printed)
2416 2417 * EROFS - could not create property group (repository is read-only)
2417 2418 * - could not delete property group (repository is read-only)
2418 2419 * EACCES - could not create property group (backend access denied)
2419 2420 * - could not delete property group (backend access denied)
2420 2421 * EEXIST - could not create property group (already exists)
2421 2422 * EINVAL - invalid property group name (error printed)
2422 2423 * - invalid property name (error printed)
2423 2424 * - invalid value (error printed)
2424 2425 * EBUSY - new property group deleted (error printed)
2425 2426 * - new property group changed (error printed)
2426 2427 * - property group added (error printed)
2427 2428 * - property group deleted (error printed)
2428 2429 */
2429 2430 static int
2430 2431 entity_pgroup_import(void *v, void *pvt)
2431 2432 {
2432 2433 pgroup_t *p = v;
2433 2434 scf_callback_t cbdata;
2434 2435 scf_callback_t *lcbdata = pvt;
2435 2436 void *ent = lcbdata->sc_parent;
2436 2437 int issvc = lcbdata->sc_service;
2437 2438 int r;
2438 2439
2439 2440 const char * const pg_changed = gettext("%s changed unexpectedly "
2440 2441 "(new property group \"%s\" changed).\n");
2441 2442
2442 2443 /* Never import deleted property groups. */
2443 2444 if (p->sc_pgroup_delete) {
2444 2445 if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY &&
2445 2446 entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) {
2446 2447 goto delete_pg;
2447 2448 }
2448 2449 return (UU_WALK_NEXT);
2449 2450 }
2450 2451
2451 2452 if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
2452 2453 strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
2453 2454 lcbdata->sc_general = p;
2454 2455 return (UU_WALK_NEXT);
2455 2456 }
2456 2457
2457 2458 add_pg:
2458 2459 if (issvc)
2459 2460 r = scf_service_add_pg(ent, p->sc_pgroup_name,
2460 2461 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2461 2462 else
2462 2463 r = scf_instance_add_pg(ent, p->sc_pgroup_name,
2463 2464 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2464 2465 if (r != 0) {
2465 2466 switch (scf_error()) {
2466 2467 case SCF_ERROR_DELETED:
2467 2468 case SCF_ERROR_CONNECTION_BROKEN:
2468 2469 case SCF_ERROR_BACKEND_READONLY:
2469 2470 case SCF_ERROR_BACKEND_ACCESS:
2470 2471 case SCF_ERROR_NO_RESOURCES:
2471 2472 return (stash_scferror(lcbdata));
2472 2473
2473 2474 case SCF_ERROR_EXISTS:
2474 2475 if (lcbdata->sc_flags & SCI_FORCE)
2475 2476 break;
2476 2477 return (stash_scferror(lcbdata));
2477 2478
2478 2479 case SCF_ERROR_INVALID_ARGUMENT:
2479 2480 warn(emsg_fmri_invalid_pg_name_type,
2480 2481 lcbdata->sc_source_fmri,
2481 2482 p->sc_pgroup_name, p->sc_pgroup_type);
2482 2483 return (stash_scferror(lcbdata));
2483 2484
2484 2485 case SCF_ERROR_PERMISSION_DENIED:
2485 2486 warn(emsg_pg_add_perm, p->sc_pgroup_name,
2486 2487 lcbdata->sc_target_fmri);
2487 2488 return (stash_scferror(lcbdata));
2488 2489
2489 2490 case SCF_ERROR_NOT_BOUND:
2490 2491 case SCF_ERROR_HANDLE_MISMATCH:
2491 2492 case SCF_ERROR_NOT_SET:
2492 2493 default:
2493 2494 bad_error("scf_service_add_pg", scf_error());
2494 2495 }
2495 2496
2496 2497 if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2497 2498 switch (scf_error()) {
2498 2499 case SCF_ERROR_CONNECTION_BROKEN:
2499 2500 case SCF_ERROR_DELETED:
2500 2501 return (stash_scferror(lcbdata));
2501 2502
2502 2503 case SCF_ERROR_INVALID_ARGUMENT:
2503 2504 warn(emsg_fmri_invalid_pg_name,
2504 2505 lcbdata->sc_source_fmri,
2505 2506 p->sc_pgroup_name);
2506 2507 return (stash_scferror(lcbdata));
2507 2508
2508 2509 case SCF_ERROR_NOT_FOUND:
2509 2510 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2510 2511 p->sc_pgroup_name);
2511 2512 lcbdata->sc_err = EBUSY;
2512 2513 return (UU_WALK_ERROR);
2513 2514
2514 2515 case SCF_ERROR_NOT_BOUND:
2515 2516 case SCF_ERROR_HANDLE_MISMATCH:
2516 2517 case SCF_ERROR_NOT_SET:
2517 2518 default:
2518 2519 bad_error("entity_get_pg", scf_error());
2519 2520 }
2520 2521 }
2521 2522
2522 2523 if (lcbdata->sc_flags & SCI_KEEP)
2523 2524 goto props;
2524 2525
2525 2526 delete_pg:
2526 2527 if (scf_pg_delete(imp_pg) != 0) {
2527 2528 switch (scf_error()) {
2528 2529 case SCF_ERROR_DELETED:
2529 2530 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2530 2531 p->sc_pgroup_name);
2531 2532 lcbdata->sc_err = EBUSY;
2532 2533 return (UU_WALK_ERROR);
2533 2534
2534 2535 case SCF_ERROR_PERMISSION_DENIED:
2535 2536 warn(emsg_pg_del_perm, p->sc_pgroup_name,
2536 2537 lcbdata->sc_target_fmri);
2537 2538 return (stash_scferror(lcbdata));
2538 2539
2539 2540 case SCF_ERROR_BACKEND_READONLY:
2540 2541 case SCF_ERROR_BACKEND_ACCESS:
2541 2542 case SCF_ERROR_CONNECTION_BROKEN:
2542 2543 return (stash_scferror(lcbdata));
2543 2544
2544 2545 case SCF_ERROR_NOT_SET:
2545 2546 default:
2546 2547 bad_error("scf_pg_delete", scf_error());
2547 2548 }
2548 2549 }
2549 2550
2550 2551 if (p->sc_pgroup_delete)
2551 2552 return (UU_WALK_NEXT);
2552 2553
2553 2554 goto add_pg;
2554 2555 }
2555 2556
2556 2557 props:
2557 2558
2558 2559 /*
2559 2560 * Add properties to property group, if any.
2560 2561 */
2561 2562 cbdata.sc_handle = lcbdata->sc_handle;
2562 2563 cbdata.sc_parent = imp_pg;
2563 2564 cbdata.sc_flags = lcbdata->sc_flags;
2564 2565 cbdata.sc_trans = imp_tx;
2565 2566 cbdata.sc_enable = NULL;
2566 2567
2567 2568 if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2568 2569 switch (scf_error()) {
2569 2570 case SCF_ERROR_BACKEND_ACCESS:
2570 2571 case SCF_ERROR_BACKEND_READONLY:
2571 2572 case SCF_ERROR_CONNECTION_BROKEN:
2572 2573 return (stash_scferror(lcbdata));
2573 2574
2574 2575 case SCF_ERROR_DELETED:
2575 2576 warn(pg_changed, lcbdata->sc_target_fmri,
2576 2577 p->sc_pgroup_name);
2577 2578 lcbdata->sc_err = EBUSY;
2578 2579 return (UU_WALK_ERROR);
2579 2580
2580 2581 case SCF_ERROR_PERMISSION_DENIED:
2581 2582 warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2582 2583 lcbdata->sc_target_fmri);
2583 2584 return (stash_scferror(lcbdata));
2584 2585
2585 2586 case SCF_ERROR_NOT_BOUND:
2586 2587 case SCF_ERROR_NOT_SET:
2587 2588 case SCF_ERROR_IN_USE:
2588 2589 case SCF_ERROR_HANDLE_MISMATCH:
2589 2590 default:
2590 2591 bad_error("scf_transaction_start", scf_error());
2591 2592 }
2592 2593 }
2593 2594
2594 2595 if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2595 2596 UU_DEFAULT) != 0) {
2596 2597 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2597 2598 bad_error("uu_list_walk", uu_error());
2598 2599 scf_transaction_reset(imp_tx);
2599 2600
2600 2601 lcbdata->sc_err = cbdata.sc_err;
2601 2602 if (cbdata.sc_err == ECANCELED) {
2602 2603 warn(pg_changed, lcbdata->sc_target_fmri,
2603 2604 p->sc_pgroup_name);
2604 2605 lcbdata->sc_err = EBUSY;
2605 2606 }
2606 2607 return (UU_WALK_ERROR);
2607 2608 }
2608 2609
2609 2610 if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2610 2611 cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2611 2612
2612 2613 /*
2613 2614 * take the snapshot running snapshot then
2614 2615 * import the stored general/enable property
2615 2616 */
2616 2617 r = take_snap(ent, snap_running, imp_rsnap);
2617 2618 switch (r) {
2618 2619 case 0:
2619 2620 break;
2620 2621
2621 2622 case ECONNABORTED:
2622 2623 warn(gettext("Could not take %s snapshot on import "
2623 2624 "(repository connection broken).\n"),
2624 2625 snap_running);
2625 2626 lcbdata->sc_err = r;
2626 2627 return (UU_WALK_ERROR);
2627 2628 case ECANCELED:
2628 2629 warn(emsg_deleted);
2629 2630 lcbdata->sc_err = r;
2630 2631 return (UU_WALK_ERROR);
2631 2632
2632 2633 case EPERM:
2633 2634 warn(gettext("Could not take %s snapshot "
2634 2635 "(permission denied).\n"), snap_running);
2635 2636 lcbdata->sc_err = r;
2636 2637 return (UU_WALK_ERROR);
2637 2638
2638 2639 case ENOSPC:
2639 2640 warn(gettext("Could not take %s snapshot"
2640 2641 "(repository server out of resources).\n"),
2641 2642 snap_running);
2642 2643 lcbdata->sc_err = r;
2643 2644 return (UU_WALK_ERROR);
2644 2645
2645 2646 default:
2646 2647 bad_error("take_snap", r);
2647 2648 }
2648 2649
2649 2650 r = lscf_property_import(cbdata.sc_enable, &cbdata);
2650 2651 if (r != UU_WALK_NEXT) {
2651 2652 if (r != UU_WALK_ERROR)
2652 2653 bad_error("lscf_property_import", r);
2653 2654 return (EINVAL);
2654 2655 }
2655 2656 }
2656 2657
2657 2658 r = scf_transaction_commit(imp_tx);
2658 2659 switch (r) {
2659 2660 case 1:
2660 2661 r = UU_WALK_NEXT;
2661 2662 break;
2662 2663
2663 2664 case 0:
2664 2665 warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2665 2666 lcbdata->sc_err = EBUSY;
2666 2667 r = UU_WALK_ERROR;
2667 2668 break;
2668 2669
2669 2670 case -1:
2670 2671 switch (scf_error()) {
2671 2672 case SCF_ERROR_BACKEND_READONLY:
2672 2673 case SCF_ERROR_BACKEND_ACCESS:
2673 2674 case SCF_ERROR_CONNECTION_BROKEN:
2674 2675 case SCF_ERROR_NO_RESOURCES:
2675 2676 r = stash_scferror(lcbdata);
2676 2677 break;
2677 2678
2678 2679 case SCF_ERROR_DELETED:
2679 2680 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2680 2681 p->sc_pgroup_name);
2681 2682 lcbdata->sc_err = EBUSY;
2682 2683 r = UU_WALK_ERROR;
2683 2684 break;
2684 2685
2685 2686 case SCF_ERROR_PERMISSION_DENIED:
2686 2687 warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2687 2688 lcbdata->sc_target_fmri);
2688 2689 r = stash_scferror(lcbdata);
2689 2690 break;
2690 2691
2691 2692 case SCF_ERROR_NOT_SET:
2692 2693 case SCF_ERROR_INVALID_ARGUMENT:
2693 2694 case SCF_ERROR_NOT_BOUND:
2694 2695 default:
2695 2696 bad_error("scf_transaction_commit", scf_error());
2696 2697 }
2697 2698 break;
2698 2699
2699 2700 default:
2700 2701 bad_error("scf_transaction_commit", r);
2701 2702 }
2702 2703
2703 2704 scf_transaction_destroy_children(imp_tx);
2704 2705
2705 2706 return (r);
2706 2707 }
2707 2708
2708 2709 /*
2709 2710 * Returns
2710 2711 * 0 - success
2711 2712 * ECONNABORTED - repository connection broken
2712 2713 * ENOMEM - out of memory
2713 2714 * ENOSPC - svc.configd is out of resources
2714 2715 * ECANCELED - inst was deleted
2715 2716 * EPERM - could not create property group (permission denied) (error printed)
2716 2717 * - could not modify property group (permission denied) (error printed)
2717 2718 * EROFS - could not create property group (repository is read-only)
2718 2719 * EACCES - could not create property group (backend access denied)
2719 2720 * EEXIST - could not create property group (already exists)
2720 2721 * EINVAL - invalid property group name (error printed)
2721 2722 * - invalid property name (error printed)
2722 2723 * - invalid value (error printed)
2723 2724 * EBUSY - new property group changed (error printed)
2724 2725 */
2725 2726 static int
2726 2727 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2727 2728 const entity_t *isvc, int flags)
2728 2729 {
2729 2730 scf_callback_t cbdata;
2730 2731
2731 2732 cbdata.sc_handle = scf_service_handle(svc);
2732 2733 cbdata.sc_parent = svc;
2733 2734 cbdata.sc_service = 1;
2734 2735 cbdata.sc_general = 0;
2735 2736 cbdata.sc_enable = 0;
2736 2737 cbdata.sc_flags = flags;
2737 2738 cbdata.sc_source_fmri = isvc->sc_fmri;
2738 2739 cbdata.sc_target_fmri = target_fmri;
2739 2740
2740 2741 /*
2741 2742 * If the op is set, then add the flag to the callback
2742 2743 * flags for later use.
2743 2744 */
2744 2745 if (isvc->sc_op != SVCCFG_OP_NONE) {
2745 2746 switch (isvc->sc_op) {
2746 2747 case SVCCFG_OP_IMPORT :
2747 2748 cbdata.sc_flags |= SCI_OP_IMPORT;
2748 2749 break;
2749 2750 case SVCCFG_OP_APPLY :
2750 2751 cbdata.sc_flags |= SCI_OP_APPLY;
2751 2752 break;
2752 2753 case SVCCFG_OP_RESTORE :
2753 2754 cbdata.sc_flags |= SCI_OP_RESTORE;
2754 2755 break;
2755 2756 default :
2756 2757 uu_die(gettext("lscf_import_service_pgs : "
2757 2758 "Unknown op stored in the service entity\n"));
2758 2759
2759 2760 }
2760 2761 }
2761 2762
2762 2763 if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2763 2764 UU_DEFAULT) != 0) {
2764 2765 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2765 2766 bad_error("uu_list_walk", uu_error());
2766 2767
2767 2768 return (cbdata.sc_err);
2768 2769 }
2769 2770
2770 2771 return (0);
2771 2772 }
2772 2773
2773 2774 /*
2774 2775 * Returns
2775 2776 * 0 - success
2776 2777 * ECONNABORTED - repository connection broken
2777 2778 * ENOMEM - out of memory
2778 2779 * ENOSPC - svc.configd is out of resources
2779 2780 * ECANCELED - inst was deleted
2780 2781 * EPERM - could not create property group (permission denied) (error printed)
2781 2782 * - could not modify property group (permission denied) (error printed)
2782 2783 * EROFS - could not create property group (repository is read-only)
2783 2784 * EACCES - could not create property group (backend access denied)
2784 2785 * EEXIST - could not create property group (already exists)
2785 2786 * EINVAL - invalid property group name (error printed)
2786 2787 * - invalid property name (error printed)
2787 2788 * - invalid value (error printed)
2788 2789 * EBUSY - new property group changed (error printed)
2789 2790 */
2790 2791 static int
2791 2792 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2792 2793 const entity_t *iinst, int flags)
2793 2794 {
2794 2795 scf_callback_t cbdata;
2795 2796
2796 2797 cbdata.sc_handle = scf_instance_handle(inst);
2797 2798 cbdata.sc_parent = inst;
2798 2799 cbdata.sc_service = 0;
2799 2800 cbdata.sc_general = NULL;
2800 2801 cbdata.sc_enable = NULL;
2801 2802 cbdata.sc_flags = flags;
2802 2803 cbdata.sc_source_fmri = iinst->sc_fmri;
2803 2804 cbdata.sc_target_fmri = target_fmri;
2804 2805
2805 2806 /*
2806 2807 * If the op is set, then add the flag to the callback
2807 2808 * flags for later use.
2808 2809 */
2809 2810 if (iinst->sc_op != SVCCFG_OP_NONE) {
2810 2811 switch (iinst->sc_op) {
2811 2812 case SVCCFG_OP_IMPORT :
2812 2813 cbdata.sc_flags |= SCI_OP_IMPORT;
2813 2814 break;
2814 2815 case SVCCFG_OP_APPLY :
2815 2816 cbdata.sc_flags |= SCI_OP_APPLY;
2816 2817 break;
2817 2818 case SVCCFG_OP_RESTORE :
2818 2819 cbdata.sc_flags |= SCI_OP_RESTORE;
2819 2820 break;
2820 2821 default :
2821 2822 uu_die(gettext("lscf_import_instance_pgs : "
2822 2823 "Unknown op stored in the instance entity\n"));
2823 2824 }
2824 2825 }
2825 2826
2826 2827 if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2827 2828 UU_DEFAULT) != 0) {
2828 2829 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2829 2830 bad_error("uu_list_walk", uu_error());
2830 2831
2831 2832 return (cbdata.sc_err);
2832 2833 }
2833 2834
2834 2835 if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2835 2836 cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2836 2837 /*
2837 2838 * If importing with the SCI_NOENABLED flag then
2838 2839 * skip the delay, but if not then add the delay
2839 2840 * of the enable property.
2840 2841 */
2841 2842 if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2842 2843 cbdata.sc_flags |= SCI_DELAYENABLE;
2843 2844 }
2844 2845
2845 2846 if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2846 2847 != UU_WALK_NEXT)
2847 2848 return (cbdata.sc_err);
2848 2849 }
2849 2850
2850 2851 return (0);
2851 2852 }
2852 2853
2853 2854 /*
2854 2855 * Report the reasons why we can't upgrade pg2 to pg1.
2855 2856 */
2856 2857 static void
2857 2858 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2858 2859 int new)
2859 2860 {
2860 2861 property_t *p1, *p2;
2861 2862
2862 2863 assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2863 2864
2864 2865 if (!pg_attrs_equal(pg1, pg2, fmri, new))
2865 2866 return;
2866 2867
2867 2868 for (p1 = uu_list_first(pg1->sc_pgroup_props);
2868 2869 p1 != NULL;
2869 2870 p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2870 2871 p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2871 2872 if (p2 != NULL) {
2872 2873 (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2873 2874 new);
2874 2875 continue;
2875 2876 }
2876 2877
2877 2878 if (new)
2878 2879 warn(gettext("Conflict upgrading %s (new property "
2879 2880 "group \"%s\" is missing property \"%s\").\n"),
2880 2881 fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2881 2882 else
2882 2883 warn(gettext("Conflict upgrading %s (property "
2883 2884 "\"%s/%s\" is missing).\n"), fmri,
2884 2885 pg1->sc_pgroup_name, p1->sc_property_name);
2885 2886 }
2886 2887
2887 2888 /*
2888 2889 * Since pg1 should be from the manifest, any properties in pg2 which
2889 2890 * aren't in pg1 shouldn't be reported as conflicts.
2890 2891 */
2891 2892 }
2892 2893
2893 2894 /*
2894 2895 * Add transaction entries to tx which will upgrade cur's pg according to old
2895 2896 * & new.
2896 2897 *
2897 2898 * Returns
2898 2899 * 0 - success
2899 2900 * EINVAL - new has a property with an invalid name or value (message emitted)
2900 2901 * ENOMEM - out of memory
2901 2902 */
2902 2903 static int
2903 2904 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2904 2905 pgroup_t *cur, int speak, const char *fmri)
2905 2906 {
2906 2907 property_t *p, *new_p, *cur_p;
2907 2908 scf_transaction_entry_t *e;
2908 2909 int r;
2909 2910 int is_general;
2910 2911 int is_protected;
2911 2912
2912 2913 if (uu_list_walk(new->sc_pgroup_props, clear_int,
2913 2914 (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2914 2915 bad_error("uu_list_walk", uu_error());
2915 2916
2916 2917 is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2917 2918
2918 2919 for (p = uu_list_first(old->sc_pgroup_props);
2919 2920 p != NULL;
2920 2921 p = uu_list_next(old->sc_pgroup_props, p)) {
2921 2922 /* p is a property in the old property group. */
2922 2923
2923 2924 /* Protect live properties. */
2924 2925 is_protected = 0;
2925 2926 if (is_general) {
2926 2927 if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2927 2928 0 ||
2928 2929 strcmp(p->sc_property_name,
2929 2930 SCF_PROPERTY_RESTARTER) == 0)
2930 2931 is_protected = 1;
2931 2932 }
2932 2933
2933 2934 /* Look for the same property in the new properties. */
2934 2935 new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2935 2936 if (new_p != NULL) {
2936 2937 new_p->sc_seen = 1;
2937 2938
2938 2939 /*
2939 2940 * If the new property is the same as the old, don't do
2940 2941 * anything (leave any user customizations).
2941 2942 */
2942 2943 if (prop_equal(p, new_p, NULL, NULL, 0))
2943 2944 continue;
2944 2945
2945 2946 if (new_p->sc_property_override)
2946 2947 goto upgrade;
2947 2948 }
2948 2949
2949 2950 cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2950 2951 if (cur_p == NULL) {
2951 2952 /*
2952 2953 * p has been deleted from the repository. If we were
2953 2954 * going to delete it anyway, do nothing. Otherwise
2954 2955 * report a conflict.
2955 2956 */
2956 2957 if (new_p == NULL)
2957 2958 continue;
2958 2959
2959 2960 if (is_protected)
2960 2961 continue;
2961 2962
2962 2963 warn(gettext("Conflict upgrading %s "
2963 2964 "(property \"%s/%s\" is missing).\n"), fmri,
2964 2965 old->sc_pgroup_name, p->sc_property_name);
2965 2966 continue;
2966 2967 }
2967 2968
2968 2969 if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2969 2970 /*
2970 2971 * Conflict. Don't warn if the property is already the
2971 2972 * way we want it, though.
2972 2973 */
2973 2974 if (is_protected)
2974 2975 continue;
2975 2976
2976 2977 if (new_p == NULL)
2977 2978 (void) prop_equal(p, cur_p, fmri,
2978 2979 old->sc_pgroup_name, 0);
2979 2980 else
2980 2981 (void) prop_equal(cur_p, new_p, fmri,
2981 2982 old->sc_pgroup_name, 0);
2982 2983 continue;
2983 2984 }
2984 2985
2985 2986 if (is_protected) {
2986 2987 if (speak)
2987 2988 warn(gettext("%s: Refusing to upgrade "
2988 2989 "\"%s/%s\" (live property).\n"), fmri,
2989 2990 old->sc_pgroup_name, p->sc_property_name);
2990 2991 continue;
2991 2992 }
2992 2993
2993 2994 upgrade:
2994 2995 /* p hasn't been customized in the repository. Upgrade it. */
2995 2996 if (new_p == NULL) {
2996 2997 /* p was deleted. Delete from cur if unchanged. */
2997 2998 if (speak)
2998 2999 warn(gettext(
2999 3000 "%s: Deleting property \"%s/%s\".\n"),
3000 3001 fmri, old->sc_pgroup_name,
3001 3002 p->sc_property_name);
3002 3003
3003 3004 e = scf_entry_create(g_hndl);
3004 3005 if (e == NULL)
3005 3006 return (ENOMEM);
3006 3007
3007 3008 if (scf_transaction_property_delete(tx, e,
3008 3009 p->sc_property_name) != 0) {
3009 3010 switch (scf_error()) {
3010 3011 case SCF_ERROR_DELETED:
3011 3012 scf_entry_destroy(e);
3012 3013 return (ECANCELED);
3013 3014
3014 3015 case SCF_ERROR_CONNECTION_BROKEN:
3015 3016 scf_entry_destroy(e);
3016 3017 return (ECONNABORTED);
3017 3018
3018 3019 case SCF_ERROR_NOT_FOUND:
3019 3020 /*
3020 3021 * This can happen if cur is from the
3021 3022 * running snapshot (and it differs
3022 3023 * from the live properties).
3023 3024 */
3024 3025 scf_entry_destroy(e);
3025 3026 break;
3026 3027
3027 3028 case SCF_ERROR_HANDLE_MISMATCH:
3028 3029 case SCF_ERROR_NOT_BOUND:
3029 3030 case SCF_ERROR_NOT_SET:
3030 3031 case SCF_ERROR_INVALID_ARGUMENT:
3031 3032 default:
3032 3033 bad_error(
3033 3034 "scf_transaction_property_delete",
3034 3035 scf_error());
3035 3036 }
3036 3037 }
3037 3038 } else {
3038 3039 scf_callback_t ctx;
3039 3040
3040 3041 if (speak)
3041 3042 warn(gettext(
3042 3043 "%s: Upgrading property \"%s/%s\".\n"),
3043 3044 fmri, old->sc_pgroup_name,
3044 3045 p->sc_property_name);
3045 3046
3046 3047 ctx.sc_handle = g_hndl;
3047 3048 ctx.sc_trans = tx;
3048 3049 ctx.sc_flags = 0;
3049 3050
3050 3051 r = lscf_property_import(new_p, &ctx);
3051 3052 if (r != UU_WALK_NEXT) {
3052 3053 if (r != UU_WALK_ERROR)
3053 3054 bad_error("lscf_property_import", r);
3054 3055 return (EINVAL);
3055 3056 }
3056 3057 }
3057 3058 }
3058 3059
3059 3060 /* Go over the properties which were added. */
3060 3061 for (new_p = uu_list_first(new->sc_pgroup_props);
3061 3062 new_p != NULL;
3062 3063 new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
3063 3064 if (new_p->sc_seen)
3064 3065 continue;
3065 3066
3066 3067 /* This is a new property. */
3067 3068 cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
3068 3069 if (cur_p == NULL) {
3069 3070 scf_callback_t ctx;
3070 3071
3071 3072 ctx.sc_handle = g_hndl;
3072 3073 ctx.sc_trans = tx;
3073 3074 ctx.sc_flags = 0;
3074 3075
3075 3076 r = lscf_property_import(new_p, &ctx);
3076 3077 if (r != UU_WALK_NEXT) {
3077 3078 if (r != UU_WALK_ERROR)
3078 3079 bad_error("lscf_property_import", r);
3079 3080 return (EINVAL);
3080 3081 }
3081 3082 continue;
3082 3083 }
3083 3084
3084 3085 /*
3085 3086 * Report a conflict if the new property differs from the
3086 3087 * current one. Unless it's general/enabled, since that's
3087 3088 * never in the last-import snapshot.
3088 3089 */
3089 3090 if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
3090 3091 0 &&
3091 3092 strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
3092 3093 continue;
3093 3094
3094 3095 (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
3095 3096 }
3096 3097
3097 3098 return (0);
3098 3099 }
3099 3100
3100 3101 /*
3101 3102 * Upgrade pg according to old & new.
3102 3103 *
3103 3104 * Returns
3104 3105 * 0 - success
3105 3106 * ECONNABORTED - repository connection broken
3106 3107 * ENOMEM - out of memory
3107 3108 * ENOSPC - svc.configd is out of resources
3108 3109 * ECANCELED - pg was deleted
3109 3110 * EPERM - couldn't modify pg (permission denied)
3110 3111 * EROFS - couldn't modify pg (backend read-only)
3111 3112 * EACCES - couldn't modify pg (backend access denied)
3112 3113 * EINVAL - new has a property with invalid name or value (error printed)
3113 3114 * EBUSY - pg changed unexpectedly
3114 3115 */
3115 3116 static int
3116 3117 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
3117 3118 pgroup_t *new, int speak, const char *fmri)
3118 3119 {
3119 3120 int r;
3120 3121
3121 3122 if (scf_transaction_start(imp_tx, pg) != 0) {
3122 3123 switch (scf_error()) {
3123 3124 case SCF_ERROR_CONNECTION_BROKEN:
3124 3125 case SCF_ERROR_DELETED:
3125 3126 case SCF_ERROR_PERMISSION_DENIED:
3126 3127 case SCF_ERROR_BACKEND_READONLY:
3127 3128 case SCF_ERROR_BACKEND_ACCESS:
3128 3129 return (scferror2errno(scf_error()));
3129 3130
3130 3131 case SCF_ERROR_HANDLE_MISMATCH:
3131 3132 case SCF_ERROR_IN_USE:
3132 3133 case SCF_ERROR_NOT_BOUND:
3133 3134 case SCF_ERROR_NOT_SET:
3134 3135 default:
3135 3136 bad_error("scf_transaction_start", scf_error());
3136 3137 }
3137 3138 }
3138 3139
3139 3140 r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
3140 3141 switch (r) {
3141 3142 case 0:
3142 3143 break;
3143 3144
3144 3145 case EINVAL:
3145 3146 case ENOMEM:
3146 3147 scf_transaction_destroy_children(imp_tx);
3147 3148 return (r);
3148 3149
3149 3150 default:
3150 3151 bad_error("add_upgrade_entries", r);
3151 3152 }
3152 3153
3153 3154 r = scf_transaction_commit(imp_tx);
3154 3155
3155 3156 scf_transaction_destroy_children(imp_tx);
3156 3157
3157 3158 switch (r) {
3158 3159 case 1:
3159 3160 break;
3160 3161
3161 3162 case 0:
3162 3163 return (EBUSY);
3163 3164
3164 3165 case -1:
3165 3166 switch (scf_error()) {
3166 3167 case SCF_ERROR_CONNECTION_BROKEN:
3167 3168 case SCF_ERROR_NO_RESOURCES:
3168 3169 case SCF_ERROR_PERMISSION_DENIED:
3169 3170 case SCF_ERROR_BACKEND_READONLY:
3170 3171 case SCF_ERROR_BACKEND_ACCESS:
3171 3172 case SCF_ERROR_DELETED:
3172 3173 return (scferror2errno(scf_error()));
3173 3174
3174 3175 case SCF_ERROR_NOT_BOUND:
3175 3176 case SCF_ERROR_INVALID_ARGUMENT:
3176 3177 case SCF_ERROR_NOT_SET:
3177 3178 default:
3178 3179 bad_error("scf_transaction_commit", scf_error());
3179 3180 }
3180 3181
3181 3182 default:
3182 3183 bad_error("scf_transaction_commit", r);
3183 3184 }
3184 3185
3185 3186 return (0);
3186 3187 }
3187 3188
3188 3189 /*
3189 3190 * Compares two entity FMRIs. Returns
3190 3191 *
3191 3192 * 1 - equal
3192 3193 * 0 - not equal
3193 3194 * -1 - f1 is invalid or not an entity
3194 3195 * -2 - f2 is invalid or not an entity
3195 3196 */
3196 3197 static int
3197 3198 fmri_equal(const char *f1, const char *f2)
3198 3199 {
3199 3200 int r;
3200 3201 const char *s1, *i1, *pg1;
3201 3202 const char *s2, *i2, *pg2;
3202 3203
3203 3204 if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3204 3205 return (-1);
3205 3206 if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
3206 3207 return (-1);
3207 3208
3208 3209 if (s1 == NULL || pg1 != NULL)
3209 3210 return (-1);
3210 3211
3211 3212 if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3212 3213 return (-2);
3213 3214 if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
3214 3215 return (-2);
3215 3216
3216 3217 if (s2 == NULL || pg2 != NULL)
3217 3218 return (-2);
3218 3219
3219 3220 r = strcmp(s1, s2);
3220 3221 if (r != 0)
3221 3222 return (0);
3222 3223
3223 3224 if (i1 == NULL && i2 == NULL)
3224 3225 return (1);
3225 3226
3226 3227 if (i1 == NULL || i2 == NULL)
3227 3228 return (0);
3228 3229
3229 3230 return (strcmp(i1, i2) == 0);
3230 3231 }
3231 3232
3232 3233 /*
3233 3234 * Import a dependent by creating a dependency property group in the dependent
3234 3235 * entity. If lcbdata->sc_trans is set, assume it's been started on the
3235 3236 * dependents pg, and add an entry to create a new property for this
3236 3237 * dependent. Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3237 3238 *
3238 3239 * On success, returns UU_WALK_NEXT. On error, returns UU_WALK_ERROR and sets
3239 3240 * lcbdata->sc_err to
3240 3241 * ECONNABORTED - repository connection broken
3241 3242 * ENOMEM - out of memory
3242 3243 * ENOSPC - configd is out of resources
3243 3244 * EINVAL - target is invalid (error printed)
3244 3245 * - target is not an entity (error printed)
3245 3246 * - dependent has invalid name (error printed)
3246 3247 * - invalid property name (error printed)
3247 3248 * - invalid value (error printed)
3248 3249 * - scope of target does not exist (error printed)
3249 3250 * EPERM - couldn't create target (permission denied) (error printed)
3250 3251 * - couldn't create dependency pg (permission denied) (error printed)
3251 3252 * - couldn't modify dependency pg (permission denied) (error printed)
3252 3253 * EROFS - couldn't create target (repository read-only)
3253 3254 * - couldn't create dependency pg (repository read-only)
3254 3255 * EACCES - couldn't create target (backend access denied)
3255 3256 * - couldn't create dependency pg (backend access denied)
3256 3257 * ECANCELED - sc_trans's pg was deleted
3257 3258 * EALREADY - property for dependent already exists in sc_trans's pg
3258 3259 * EEXIST - dependency pg already exists in target (error printed)
3259 3260 * EBUSY - target deleted (error printed)
3260 3261 * - property group changed during import (error printed)
3261 3262 */
3262 3263 static int
3263 3264 lscf_dependent_import(void *a1, void *pvt)
3264 3265 {
3265 3266 pgroup_t *pgrp = a1;
3266 3267 scf_callback_t *lcbdata = pvt;
3267 3268
3268 3269 int isservice;
3269 3270 int ret;
3270 3271 scf_transaction_entry_t *e;
3271 3272 scf_value_t *val;
3272 3273 scf_callback_t dependent_cbdata;
3273 3274 scf_error_t scfe;
3274 3275
3275 3276 /*
3276 3277 * Decode the FMRI into dependent_cbdata->sc_parent. Do it here so if
3277 3278 * it's invalid, we fail before modifying the repository.
3278 3279 */
3279 3280 scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3280 3281 &dependent_cbdata.sc_parent, &isservice);
3281 3282 switch (scfe) {
3282 3283 case SCF_ERROR_NONE:
3283 3284 break;
3284 3285
3285 3286 case SCF_ERROR_NO_MEMORY:
3286 3287 return (stash_scferror_err(lcbdata, scfe));
3287 3288
3288 3289 case SCF_ERROR_INVALID_ARGUMENT:
3289 3290 semerr(gettext("The FMRI for the \"%s\" dependent is "
3290 3291 "invalid.\n"), pgrp->sc_pgroup_name);
3291 3292 return (stash_scferror_err(lcbdata, scfe));
3292 3293
3293 3294 case SCF_ERROR_CONSTRAINT_VIOLATED:
3294 3295 semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3295 3296 "specifies neither a service nor an instance.\n"),
3296 3297 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3297 3298 return (stash_scferror_err(lcbdata, scfe));
3298 3299
3299 3300 case SCF_ERROR_NOT_FOUND:
3300 3301 scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3301 3302 &dependent_cbdata.sc_parent, &isservice);
3302 3303 switch (scfe) {
3303 3304 case SCF_ERROR_NONE:
3304 3305 break;
3305 3306
3306 3307 case SCF_ERROR_NO_MEMORY:
3307 3308 case SCF_ERROR_BACKEND_READONLY:
3308 3309 case SCF_ERROR_BACKEND_ACCESS:
3309 3310 return (stash_scferror_err(lcbdata, scfe));
3310 3311
3311 3312 case SCF_ERROR_NOT_FOUND:
3312 3313 semerr(gettext("The scope in FMRI \"%s\" for the "
3313 3314 "\"%s\" dependent does not exist.\n"),
3314 3315 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3315 3316 lcbdata->sc_err = EINVAL;
3316 3317 return (UU_WALK_ERROR);
3317 3318
3318 3319 case SCF_ERROR_PERMISSION_DENIED:
3319 3320 warn(gettext(
3320 3321 "Could not create %s (permission denied).\n"),
3321 3322 pgrp->sc_pgroup_fmri);
3322 3323 return (stash_scferror_err(lcbdata, scfe));
3323 3324
3324 3325 case SCF_ERROR_INVALID_ARGUMENT:
3325 3326 case SCF_ERROR_CONSTRAINT_VIOLATED:
3326 3327 default:
3327 3328 bad_error("create_entity", scfe);
3328 3329 }
3329 3330 break;
3330 3331
3331 3332 default:
3332 3333 bad_error("fmri_to_entity", scfe);
3333 3334 }
3334 3335
3335 3336 if (lcbdata->sc_trans != NULL) {
3336 3337 e = scf_entry_create(lcbdata->sc_handle);
3337 3338 if (e == NULL) {
3338 3339 if (scf_error() != SCF_ERROR_NO_MEMORY)
3339 3340 bad_error("scf_entry_create", scf_error());
3340 3341
3341 3342 entity_destroy(dependent_cbdata.sc_parent, isservice);
3342 3343 return (stash_scferror(lcbdata));
3343 3344 }
3344 3345
3345 3346 if (scf_transaction_property_new(lcbdata->sc_trans, e,
3346 3347 pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
3347 3348 switch (scf_error()) {
3348 3349 case SCF_ERROR_INVALID_ARGUMENT:
3349 3350 warn(gettext("Dependent of %s has invalid name "
3350 3351 "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
3351 3352 pgrp->sc_pgroup_name);
3352 3353 /* FALLTHROUGH */
3353 3354
3354 3355 case SCF_ERROR_DELETED:
3355 3356 case SCF_ERROR_CONNECTION_BROKEN:
3356 3357 scf_entry_destroy(e);
3357 3358 entity_destroy(dependent_cbdata.sc_parent,
3358 3359 isservice);
3359 3360 return (stash_scferror(lcbdata));
3360 3361
3361 3362 case SCF_ERROR_EXISTS:
3362 3363 scf_entry_destroy(e);
3363 3364 entity_destroy(dependent_cbdata.sc_parent,
3364 3365 isservice);
3365 3366 lcbdata->sc_err = EALREADY;
3366 3367 return (UU_WALK_ERROR);
3367 3368
3368 3369 case SCF_ERROR_NOT_BOUND:
3369 3370 case SCF_ERROR_HANDLE_MISMATCH:
3370 3371 case SCF_ERROR_NOT_SET:
3371 3372 default:
3372 3373 bad_error("scf_transaction_property_new",
3373 3374 scf_error());
3374 3375 }
3375 3376 }
3376 3377
3377 3378 val = scf_value_create(lcbdata->sc_handle);
3378 3379 if (val == NULL) {
3379 3380 if (scf_error() != SCF_ERROR_NO_MEMORY)
3380 3381 bad_error("scf_value_create", scf_error());
3381 3382
3382 3383 entity_destroy(dependent_cbdata.sc_parent, isservice);
3383 3384 return (stash_scferror(lcbdata));
3384 3385 }
3385 3386
3386 3387 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
3387 3388 pgrp->sc_pgroup_fmri) != 0)
3388 3389 /* invalid should have been caught above */
3389 3390 bad_error("scf_value_set_from_string", scf_error());
3390 3391
3391 3392 if (scf_entry_add_value(e, val) != 0)
3392 3393 bad_error("scf_entry_add_value", scf_error());
3393 3394 }
3394 3395
3395 3396 /* Add the property group to the target entity. */
3396 3397
3397 3398 dependent_cbdata.sc_handle = lcbdata->sc_handle;
3398 3399 dependent_cbdata.sc_flags = lcbdata->sc_flags;
3399 3400 dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
3400 3401 dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
3401 3402
3402 3403 ret = entity_pgroup_import(pgrp, &dependent_cbdata);
3403 3404
3404 3405 entity_destroy(dependent_cbdata.sc_parent, isservice);
3405 3406
3406 3407 if (ret == UU_WALK_NEXT)
3407 3408 return (ret);
3408 3409
3409 3410 if (ret != UU_WALK_ERROR)
3410 3411 bad_error("entity_pgroup_import", ret);
3411 3412
3412 3413 switch (dependent_cbdata.sc_err) {
3413 3414 case ECANCELED:
3414 3415 warn(gettext("%s deleted unexpectedly.\n"),
3415 3416 pgrp->sc_pgroup_fmri);
3416 3417 lcbdata->sc_err = EBUSY;
3417 3418 break;
3418 3419
3419 3420 case EEXIST:
3420 3421 warn(gettext("Could not create \"%s\" dependency in %s "
3421 3422 "(already exists).\n"), pgrp->sc_pgroup_name,
3422 3423 pgrp->sc_pgroup_fmri);
3423 3424 /* FALLTHROUGH */
3424 3425
3425 3426 default:
3426 3427 lcbdata->sc_err = dependent_cbdata.sc_err;
3427 3428 }
3428 3429
3429 3430 return (UU_WALK_ERROR);
3430 3431 }
3431 3432
3432 3433 static int upgrade_dependent(const scf_property_t *, const entity_t *,
3433 3434 const scf_snaplevel_t *, scf_transaction_t *);
3434 3435 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
3435 3436 const pgroup_t *);
3436 3437
3437 3438 /*
3438 3439 * Upgrade uncustomized dependents of ent to those specified in ient. Read
3439 3440 * the current dependent targets from running (the snaplevel of a running
3440 3441 * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3441 3442 * scf_instance_t * according to ient, otherwise). Draw the ancestral
3442 3443 * dependent targets and dependency properties from li_dpts_pg (the
3443 3444 * "dependents" property group in snpl) and snpl (the snaplevel which
3444 3445 * corresponds to ent in a last-import snapshot). If li_dpts_pg is NULL, then
3445 3446 * snpl doesn't have a "dependents" property group, and any dependents in ient
3446 3447 * are new.
3447 3448 *
3448 3449 * Returns
3449 3450 * 0 - success
3450 3451 * ECONNABORTED - repository connection broken
3451 3452 * ENOMEM - out of memory
3452 3453 * ENOSPC - configd is out of resources
3453 3454 * ECANCELED - ent was deleted
3454 3455 * ENODEV - the entity containing li_dpts_pg was deleted
3455 3456 * EPERM - could not modify dependents pg (permission denied) (error printed)
3456 3457 * - couldn't upgrade dependent (permission denied) (error printed)
3457 3458 * - couldn't create dependent (permission denied) (error printed)
3458 3459 * EROFS - could not modify dependents pg (repository read-only)
3459 3460 * - couldn't upgrade dependent (repository read-only)
3460 3461 * - couldn't create dependent (repository read-only)
3461 3462 * EACCES - could not modify dependents pg (backend access denied)
3462 3463 * - could not upgrade dependent (backend access denied)
3463 3464 * - could not create dependent (backend access denied)
3464 3465 * EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3465 3466 * - dependent target deleted (error printed)
3466 3467 * - dependent pg changed (error printed)
3467 3468 * EINVAL - new dependent is invalid (error printed)
3468 3469 * EBADF - snpl is corrupt (error printed)
3469 3470 * - snpl has corrupt pg (error printed)
3470 3471 * - dependency pg in target is corrupt (error printed)
3471 3472 * - target has corrupt snapshot (error printed)
3472 3473 * EEXIST - dependency pg already existed in target service (error printed)
3473 3474 */
3474 3475 static int
3475 3476 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
3476 3477 const scf_snaplevel_t *snpl, const entity_t *ient,
3477 3478 const scf_snaplevel_t *running, void *ent)
3478 3479 {
3479 3480 pgroup_t *new_dpt_pgroup;
3480 3481 scf_callback_t cbdata;
3481 3482 int r, unseen, tx_started = 0;
3482 3483 int have_cur_depts;
3483 3484
3484 3485 const char * const dependents = "dependents";
3485 3486
3486 3487 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3487 3488
3488 3489 if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
3489 3490 /* Nothing to do. */
3490 3491 return (0);
3491 3492
3492 3493 /* Fetch the current version of the "dependents" property group. */
3493 3494 have_cur_depts = 1;
3494 3495 if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
3495 3496 switch (scf_error()) {
3496 3497 case SCF_ERROR_NOT_FOUND:
3497 3498 break;
3498 3499
3499 3500 case SCF_ERROR_DELETED:
3500 3501 case SCF_ERROR_CONNECTION_BROKEN:
3501 3502 return (scferror2errno(scf_error()));
3502 3503
3503 3504 case SCF_ERROR_NOT_SET:
3504 3505 case SCF_ERROR_INVALID_ARGUMENT:
3505 3506 case SCF_ERROR_HANDLE_MISMATCH:
3506 3507 case SCF_ERROR_NOT_BOUND:
3507 3508 default:
3508 3509 bad_error("entity_get_pg", scf_error());
3509 3510 }
3510 3511
3511 3512 have_cur_depts = 0;
3512 3513 }
3513 3514
3514 3515 /* Fetch the running version of the "dependents" property group. */
3515 3516 ud_run_dpts_pg_set = 0;
3516 3517 if (running != NULL)
3517 3518 r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
3518 3519 else
3519 3520 r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
3520 3521 if (r == 0) {
3521 3522 ud_run_dpts_pg_set = 1;
3522 3523 } else {
3523 3524 switch (scf_error()) {
3524 3525 case SCF_ERROR_NOT_FOUND:
3525 3526 break;
3526 3527
3527 3528 case SCF_ERROR_DELETED:
3528 3529 case SCF_ERROR_CONNECTION_BROKEN:
3529 3530 return (scferror2errno(scf_error()));
3530 3531
3531 3532 case SCF_ERROR_NOT_SET:
3532 3533 case SCF_ERROR_INVALID_ARGUMENT:
3533 3534 case SCF_ERROR_HANDLE_MISMATCH:
3534 3535 case SCF_ERROR_NOT_BOUND:
3535 3536 default:
3536 3537 bad_error(running ? "scf_snaplevel_get_pg" :
3537 3538 "entity_get_pg", scf_error());
3538 3539 }
3539 3540 }
3540 3541
3541 3542 /*
3542 3543 * Clear the seen fields of the dependents, so we can tell which ones
3543 3544 * are new.
3544 3545 */
3545 3546 if (uu_list_walk(ient->sc_dependents, clear_int,
3546 3547 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3547 3548 bad_error("uu_list_walk", uu_error());
3548 3549
3549 3550 if (li_dpts_pg != NULL) {
3550 3551 /*
3551 3552 * Each property in li_dpts_pg represents a dependent tag in
3552 3553 * the old manifest. For each, call upgrade_dependent(),
3553 3554 * which will change ud_cur_depts_pg or dependencies in other
3554 3555 * services as appropriate. Note (a) that changes to
3555 3556 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3556 3557 * made en masse, and (b) it's ok if the entity doesn't have
3557 3558 * a current version of the "dependents" property group,
3558 3559 * because we'll just consider all dependents as customized
3559 3560 * (by being deleted).
3560 3561 */
3561 3562
3562 3563 if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3563 3564 switch (scf_error()) {
3564 3565 case SCF_ERROR_DELETED:
3565 3566 return (ENODEV);
3566 3567
3567 3568 case SCF_ERROR_CONNECTION_BROKEN:
3568 3569 return (ECONNABORTED);
3569 3570
3570 3571 case SCF_ERROR_HANDLE_MISMATCH:
3571 3572 case SCF_ERROR_NOT_BOUND:
3572 3573 case SCF_ERROR_NOT_SET:
3573 3574 default:
3574 3575 bad_error("scf_iter_pg_properties",
3575 3576 scf_error());
3576 3577 }
3577 3578 }
3578 3579
3579 3580 if (have_cur_depts &&
3580 3581 scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3581 3582 switch (scf_error()) {
3582 3583 case SCF_ERROR_BACKEND_ACCESS:
3583 3584 case SCF_ERROR_BACKEND_READONLY:
3584 3585 case SCF_ERROR_CONNECTION_BROKEN:
3585 3586 return (scferror2errno(scf_error()));
3586 3587
3587 3588 case SCF_ERROR_DELETED:
3588 3589 warn(emsg_pg_deleted, ient->sc_fmri,
3589 3590 dependents);
3590 3591 return (EBUSY);
3591 3592
3592 3593 case SCF_ERROR_PERMISSION_DENIED:
3593 3594 warn(emsg_pg_mod_perm, dependents,
3594 3595 ient->sc_fmri);
3595 3596 return (scferror2errno(scf_error()));
3596 3597
3597 3598 case SCF_ERROR_HANDLE_MISMATCH:
3598 3599 case SCF_ERROR_IN_USE:
3599 3600 case SCF_ERROR_NOT_BOUND:
3600 3601 case SCF_ERROR_NOT_SET:
3601 3602 default:
3602 3603 bad_error("scf_transaction_start", scf_error());
3603 3604 }
3604 3605 }
3605 3606 tx_started = have_cur_depts;
3606 3607
3607 3608 for (;;) {
3608 3609 r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3609 3610 if (r == 0)
3610 3611 break;
3611 3612 if (r == 1) {
3612 3613 r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3613 3614 tx_started ? ud_tx : NULL);
3614 3615 switch (r) {
3615 3616 case 0:
3616 3617 continue;
3617 3618
3618 3619 case ECONNABORTED:
3619 3620 case ENOMEM:
3620 3621 case ENOSPC:
3621 3622 case EBADF:
3622 3623 case EBUSY:
3623 3624 case EINVAL:
3624 3625 case EPERM:
3625 3626 case EROFS:
3626 3627 case EACCES:
3627 3628 case EEXIST:
3628 3629 break;
3629 3630
3630 3631 case ECANCELED:
3631 3632 r = ENODEV;
3632 3633 break;
3633 3634
3634 3635 default:
3635 3636 bad_error("upgrade_dependent", r);
3636 3637 }
3637 3638
3638 3639 if (tx_started)
3639 3640 scf_transaction_destroy_children(ud_tx);
3640 3641 return (r);
3641 3642 }
3642 3643 if (r != -1)
3643 3644 bad_error("scf_iter_next_property", r);
3644 3645
3645 3646 switch (scf_error()) {
3646 3647 case SCF_ERROR_DELETED:
3647 3648 r = ENODEV;
3648 3649 break;
3649 3650
3650 3651 case SCF_ERROR_CONNECTION_BROKEN:
3651 3652 r = ECONNABORTED;
3652 3653 break;
3653 3654
3654 3655 case SCF_ERROR_NOT_SET:
3655 3656 case SCF_ERROR_INVALID_ARGUMENT:
3656 3657 case SCF_ERROR_NOT_BOUND:
3657 3658 case SCF_ERROR_HANDLE_MISMATCH:
3658 3659 default:
3659 3660 bad_error("scf_iter_next_property",
3660 3661 scf_error());
3661 3662 }
3662 3663
3663 3664 if (tx_started)
3664 3665 scf_transaction_destroy_children(ud_tx);
3665 3666 return (r);
3666 3667 }
3667 3668 }
3668 3669
3669 3670 /* import unseen dependents */
3670 3671 unseen = 0;
3671 3672 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3672 3673 new_dpt_pgroup != NULL;
3673 3674 new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3674 3675 new_dpt_pgroup)) {
3675 3676 if (!new_dpt_pgroup->sc_pgroup_seen) {
3676 3677 unseen = 1;
3677 3678 break;
3678 3679 }
3679 3680 }
3680 3681
3681 3682 /* If there are none, exit early. */
3682 3683 if (unseen == 0)
3683 3684 goto commit;
3684 3685
3685 3686 /* Set up for lscf_dependent_import() */
3686 3687 cbdata.sc_handle = g_hndl;
3687 3688 cbdata.sc_parent = ent;
3688 3689 cbdata.sc_service = issvc;
3689 3690 cbdata.sc_flags = 0;
3690 3691
3691 3692 if (!have_cur_depts) {
3692 3693 /*
3693 3694 * We have new dependents to import, so we need a "dependents"
3694 3695 * property group.
3695 3696 */
3696 3697 if (issvc)
3697 3698 r = scf_service_add_pg(ent, dependents,
3698 3699 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3699 3700 else
3700 3701 r = scf_instance_add_pg(ent, dependents,
3701 3702 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3702 3703 if (r != 0) {
3703 3704 switch (scf_error()) {
3704 3705 case SCF_ERROR_DELETED:
3705 3706 case SCF_ERROR_CONNECTION_BROKEN:
3706 3707 case SCF_ERROR_BACKEND_READONLY:
3707 3708 case SCF_ERROR_BACKEND_ACCESS:
3708 3709 case SCF_ERROR_NO_RESOURCES:
3709 3710 return (scferror2errno(scf_error()));
3710 3711
3711 3712 case SCF_ERROR_EXISTS:
3712 3713 warn(emsg_pg_added, ient->sc_fmri, dependents);
3713 3714 return (EBUSY);
3714 3715
3715 3716 case SCF_ERROR_PERMISSION_DENIED:
3716 3717 warn(emsg_pg_add_perm, dependents,
3717 3718 ient->sc_fmri);
3718 3719 return (scferror2errno(scf_error()));
3719 3720
3720 3721 case SCF_ERROR_NOT_BOUND:
3721 3722 case SCF_ERROR_HANDLE_MISMATCH:
3722 3723 case SCF_ERROR_INVALID_ARGUMENT:
3723 3724 case SCF_ERROR_NOT_SET:
3724 3725 default:
3725 3726 bad_error("scf_service_add_pg", scf_error());
3726 3727 }
3727 3728 }
3728 3729 }
3729 3730
3730 3731 cbdata.sc_trans = ud_tx;
3731 3732
3732 3733 if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3733 3734 switch (scf_error()) {
3734 3735 case SCF_ERROR_CONNECTION_BROKEN:
3735 3736 case SCF_ERROR_BACKEND_ACCESS:
3736 3737 case SCF_ERROR_BACKEND_READONLY:
3737 3738 return (scferror2errno(scf_error()));
3738 3739
3739 3740 case SCF_ERROR_DELETED:
3740 3741 warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3741 3742 return (EBUSY);
3742 3743
3743 3744 case SCF_ERROR_PERMISSION_DENIED:
3744 3745 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3745 3746 return (scferror2errno(scf_error()));
3746 3747
3747 3748 case SCF_ERROR_HANDLE_MISMATCH:
3748 3749 case SCF_ERROR_IN_USE:
3749 3750 case SCF_ERROR_NOT_BOUND:
3750 3751 case SCF_ERROR_NOT_SET:
3751 3752 default:
3752 3753 bad_error("scf_transaction_start", scf_error());
3753 3754 }
3754 3755 }
3755 3756 tx_started = 1;
3756 3757
3757 3758 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3758 3759 new_dpt_pgroup != NULL;
3759 3760 new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3760 3761 new_dpt_pgroup)) {
3761 3762 if (new_dpt_pgroup->sc_pgroup_seen)
3762 3763 continue;
3763 3764
3764 3765 if (ud_run_dpts_pg_set) {
3765 3766 /*
3766 3767 * If the dependent is already there, then we have
3767 3768 * a conflict.
3768 3769 */
3769 3770 if (scf_pg_get_property(ud_run_dpts_pg,
3770 3771 new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3771 3772 r = handle_dependent_conflict(ient, ud_prop,
3772 3773 new_dpt_pgroup);
3773 3774 switch (r) {
3774 3775 case 0:
3775 3776 continue;
3776 3777
3777 3778 case ECONNABORTED:
3778 3779 case ENOMEM:
3779 3780 case EBUSY:
3780 3781 case EBADF:
3781 3782 case EINVAL:
3782 3783 scf_transaction_destroy_children(ud_tx);
3783 3784 return (r);
3784 3785
3785 3786 default:
3786 3787 bad_error("handle_dependent_conflict",
3787 3788 r);
3788 3789 }
3789 3790 } else {
3790 3791 switch (scf_error()) {
3791 3792 case SCF_ERROR_NOT_FOUND:
3792 3793 break;
3793 3794
3794 3795 case SCF_ERROR_INVALID_ARGUMENT:
3795 3796 warn(emsg_fmri_invalid_pg_name,
3796 3797 ient->sc_fmri,
3797 3798 new_dpt_pgroup->sc_pgroup_name);
3798 3799 scf_transaction_destroy_children(ud_tx);
3799 3800 return (EINVAL);
3800 3801
3801 3802 case SCF_ERROR_DELETED:
3802 3803 warn(emsg_pg_deleted, ient->sc_fmri,
3803 3804 new_dpt_pgroup->sc_pgroup_name);
3804 3805 scf_transaction_destroy_children(ud_tx);
3805 3806 return (EBUSY);
3806 3807
3807 3808 case SCF_ERROR_CONNECTION_BROKEN:
3808 3809 scf_transaction_destroy_children(ud_tx);
3809 3810 return (ECONNABORTED);
3810 3811
3811 3812 case SCF_ERROR_NOT_BOUND:
3812 3813 case SCF_ERROR_HANDLE_MISMATCH:
3813 3814 case SCF_ERROR_NOT_SET:
3814 3815 default:
3815 3816 bad_error("scf_pg_get_property",
3816 3817 scf_error());
3817 3818 }
3818 3819 }
3819 3820 }
3820 3821
3821 3822 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3822 3823 if (r != UU_WALK_NEXT) {
3823 3824 if (r != UU_WALK_ERROR)
3824 3825 bad_error("lscf_dependent_import", r);
3825 3826
3826 3827 if (cbdata.sc_err == EALREADY) {
3827 3828 /* Collisions were handled preemptively. */
3828 3829 bad_error("lscf_dependent_import",
3829 3830 cbdata.sc_err);
3830 3831 }
3831 3832
3832 3833 scf_transaction_destroy_children(ud_tx);
3833 3834 return (cbdata.sc_err);
3834 3835 }
3835 3836 }
3836 3837
3837 3838 commit:
3838 3839 if (!tx_started)
3839 3840 return (0);
3840 3841
3841 3842 r = scf_transaction_commit(ud_tx);
3842 3843
3843 3844 scf_transaction_destroy_children(ud_tx);
3844 3845
3845 3846 switch (r) {
3846 3847 case 1:
3847 3848 return (0);
3848 3849
3849 3850 case 0:
3850 3851 warn(emsg_pg_changed, ient->sc_fmri, dependents);
3851 3852 return (EBUSY);
3852 3853
3853 3854 case -1:
3854 3855 break;
3855 3856
3856 3857 default:
3857 3858 bad_error("scf_transaction_commit", r);
3858 3859 }
3859 3860
3860 3861 switch (scf_error()) {
3861 3862 case SCF_ERROR_CONNECTION_BROKEN:
3862 3863 case SCF_ERROR_BACKEND_READONLY:
3863 3864 case SCF_ERROR_BACKEND_ACCESS:
3864 3865 case SCF_ERROR_NO_RESOURCES:
3865 3866 return (scferror2errno(scf_error()));
3866 3867
3867 3868 case SCF_ERROR_DELETED:
3868 3869 warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3869 3870 return (EBUSY);
3870 3871
3871 3872 case SCF_ERROR_PERMISSION_DENIED:
3872 3873 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3873 3874 return (scferror2errno(scf_error()));
3874 3875
3875 3876 case SCF_ERROR_NOT_BOUND:
3876 3877 case SCF_ERROR_INVALID_ARGUMENT:
3877 3878 case SCF_ERROR_NOT_SET:
3878 3879 default:
3879 3880 bad_error("scf_transaction_destroy", scf_error());
3880 3881 /* NOTREACHED */
3881 3882 }
3882 3883 }
3883 3884
3884 3885 /*
3885 3886 * Used to add the manifests to the list of currently supported manifests.
3886 3887 * We can modify the existing manifest list removing entries if the files
3887 3888 * don't exist.
↓ open down ↓ |
3852 lines elided |
↑ open up ↑ |
3888 3889 *
3889 3890 * Get the old list and the new file name
3890 3891 * If the new file name is in the list return
3891 3892 * If not then add the file to the list.
3892 3893 * As we process the list check to see if the files in the old list exist
3893 3894 * if not then remove the file from the list.
3894 3895 * Commit the list of manifest file names.
3895 3896 *
3896 3897 */
3897 3898 static int
3898 -upgrade_manifestfiles(pgroup_t *pg, const entity_t *ient,
3899 +upgrade_manifestfiles(pgroup_t *pg, entity_t *ient,
3899 3900 const scf_snaplevel_t *running, void *ent)
3900 3901 {
3901 3902 scf_propertygroup_t *ud_mfsts_pg = NULL;
3902 3903 scf_property_t *ud_prop = NULL;
3903 3904 scf_iter_t *ud_prop_iter;
3904 3905 scf_value_t *fname_value;
3905 3906 scf_callback_t cbdata;
3906 3907 pgroup_t *mfst_pgroup;
3907 3908 property_t *mfst_prop;
3908 3909 property_t *old_prop;
3909 3910 char *pname;
3910 3911 char *fval;
3911 3912 char *old_pname;
3912 3913 char *old_fval;
3913 3914 int no_upgrade_pg;
3914 3915 int mfst_seen;
3915 3916 int r;
3916 3917
3917 3918 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3918 3919
3919 3920 /*
3920 3921 * This should always be the service base on the code
3921 3922 * path, and the fact that the manifests pg is a service
3922 3923 * level property group only.
3923 3924 */
3924 3925 ud_mfsts_pg = scf_pg_create(g_hndl);
3925 3926 ud_prop = scf_property_create(g_hndl);
3926 3927 ud_prop_iter = scf_iter_create(g_hndl);
3927 3928 fname_value = scf_value_create(g_hndl);
3928 3929
3929 3930 /* Fetch the "manifests" property group */
3930 3931 no_upgrade_pg = 0;
3931 3932 r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3932 3933 ud_mfsts_pg);
3933 3934 if (r != 0) {
3934 3935 switch (scf_error()) {
3935 3936 case SCF_ERROR_NOT_FOUND:
3936 3937 no_upgrade_pg = 1;
3937 3938 break;
3938 3939
3939 3940 case SCF_ERROR_DELETED:
3940 3941 case SCF_ERROR_CONNECTION_BROKEN:
3941 3942 return (scferror2errno(scf_error()));
3942 3943
3943 3944 case SCF_ERROR_NOT_SET:
3944 3945 case SCF_ERROR_INVALID_ARGUMENT:
3945 3946 case SCF_ERROR_HANDLE_MISMATCH:
3946 3947 case SCF_ERROR_NOT_BOUND:
3947 3948 default:
3948 3949 bad_error(running ? "scf_snaplevel_get_pg" :
3949 3950 "entity_get_pg", scf_error());
3950 3951 }
3951 3952 }
3952 3953
3953 3954 if (no_upgrade_pg) {
3954 3955 cbdata.sc_handle = g_hndl;
3955 3956 cbdata.sc_parent = ent;
3956 3957 cbdata.sc_service = issvc;
3957 3958 cbdata.sc_flags = SCI_FORCE;
↓ open down ↓ |
49 lines elided |
↑ open up ↑ |
3958 3959 cbdata.sc_source_fmri = ient->sc_fmri;
3959 3960 cbdata.sc_target_fmri = ient->sc_fmri;
3960 3961
3961 3962 if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3962 3963 return (cbdata.sc_err);
3963 3964
3964 3965 return (0);
3965 3966 }
3966 3967
3967 3968 /* 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 - }
3969 + mfst_pgroup = internal_pgroup_find_or_create(ient,
3970 + SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
3971 + assert(mfst_pgroup != NULL);
3975 3972
3976 3973 if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3977 3974 SCF_SUCCESS)
3978 3975 return (-1);
3979 3976
3980 3977 if ((pname = malloc(MAXPATHLEN)) == NULL)
3981 3978 return (ENOMEM);
3982 3979 if ((fval = malloc(MAXPATHLEN)) == NULL) {
3983 3980 free(pname);
3984 3981 return (ENOMEM);
3985 3982 }
3986 3983
3987 3984 while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
3988 3985 mfst_seen = 0;
3989 3986 if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
3990 3987 continue;
3991 3988
3992 3989 for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
3993 3990 mfst_prop != NULL;
3994 3991 mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
3995 3992 mfst_prop)) {
3996 3993 if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
3997 3994 mfst_seen = 1;
3998 3995 }
3999 3996 }
4000 3997
4001 3998 /*
4002 3999 * If the manifest is not seen then add it to the new mfst
4003 4000 * property list to get proccessed into the repo.
4004 4001 */
4005 4002 if (mfst_seen == 0) {
4006 4003 /*
4007 4004 * If we cannot get the value then there is no
4008 4005 * reason to attempt to attach the value to
4009 4006 * the property group
4010 4007 */
4011 4008 if (prop_get_val(ud_prop, fname_value) == 0 &&
4012 4009 scf_value_get_astring(fname_value, fval,
4013 4010 MAXPATHLEN) != -1) {
4014 4011 old_pname = safe_strdup(pname);
4015 4012 old_fval = safe_strdup(fval);
4016 4013 old_prop = internal_property_create(old_pname,
4017 4014 SCF_TYPE_ASTRING, 1, old_fval);
4018 4015
4019 4016 /*
4020 4017 * Already checked to see if the property exists
4021 4018 * in the group, and it does not.
4022 4019 */
4023 4020 (void) internal_attach_property(mfst_pgroup,
4024 4021 old_prop);
4025 4022 }
4026 4023 }
4027 4024 }
4028 4025 free(pname);
4029 4026 free(fval);
4030 4027
4031 4028 cbdata.sc_handle = g_hndl;
4032 4029 cbdata.sc_parent = ent;
4033 4030 cbdata.sc_service = issvc;
4034 4031 cbdata.sc_flags = SCI_FORCE;
4035 4032 cbdata.sc_source_fmri = ient->sc_fmri;
4036 4033 cbdata.sc_target_fmri = ient->sc_fmri;
4037 4034
4038 4035 if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
4039 4036 return (cbdata.sc_err);
4040 4037
4041 4038 return (r);
4042 4039 }
4043 4040
4044 4041 /*
4045 4042 * prop is taken to be a property in the "dependents" property group of snpl,
4046 4043 * which is taken to be the snaplevel of a last-import snapshot corresponding
4047 4044 * to ient. If prop is a valid dependents property, upgrade the dependent it
4048 4045 * represents according to the repository & ient. If ud_run_dpts_pg_set is
4049 4046 * true, then ud_run_dpts_pg is taken to be the "dependents" property group
4050 4047 * of the entity ient represents (possibly in the running snapshot). If it
4051 4048 * needs to be changed, an entry will be added to tx, if not NULL.
4052 4049 *
4053 4050 * Returns
4054 4051 * 0 - success
4055 4052 * ECONNABORTED - repository connection broken
4056 4053 * ENOMEM - out of memory
4057 4054 * ENOSPC - configd was out of resources
4058 4055 * ECANCELED - snpl's entity was deleted
4059 4056 * EINVAL - dependent target is invalid (error printed)
4060 4057 * - dependent is invalid (error printed)
4061 4058 * EBADF - snpl is corrupt (error printed)
4062 4059 * - snpl has corrupt pg (error printed)
4063 4060 * - dependency pg in target is corrupt (error printed)
4064 4061 * - running snapshot in dependent is missing snaplevel (error printed)
4065 4062 * EPERM - couldn't delete dependency pg (permission denied) (error printed)
4066 4063 * - couldn't create dependent (permission denied) (error printed)
4067 4064 * - couldn't modify dependent pg (permission denied) (error printed)
4068 4065 * EROFS - couldn't delete dependency pg (repository read-only)
4069 4066 * - couldn't create dependent (repository read-only)
4070 4067 * EACCES - couldn't delete dependency pg (backend access denied)
4071 4068 * - couldn't create dependent (backend access denied)
4072 4069 * EBUSY - ud_run_dpts_pg was deleted (error printed)
4073 4070 * - tx's pg was deleted (error printed)
4074 4071 * - dependent pg was changed or deleted (error printed)
4075 4072 * EEXIST - dependency pg already exists in new target (error printed)
4076 4073 */
4077 4074 static int
4078 4075 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
4079 4076 const scf_snaplevel_t *snpl, scf_transaction_t *tx)
4080 4077 {
4081 4078 pgroup_t pgrp;
4082 4079 scf_type_t ty;
4083 4080 pgroup_t *new_dpt_pgroup;
4084 4081 pgroup_t *old_dpt_pgroup = NULL;
4085 4082 pgroup_t *current_pg;
4086 4083 pgroup_t *dpt;
4087 4084 scf_callback_t cbdata;
4088 4085 int tissvc;
4089 4086 void *target_ent;
4090 4087 scf_error_t serr;
4091 4088 int r;
4092 4089 scf_transaction_entry_t *ent;
4093 4090
4094 4091 const char * const cf_inval = gettext("Conflict upgrading %s "
4095 4092 "(dependent \"%s\" has invalid dependents property).\n");
4096 4093 const char * const cf_missing = gettext("Conflict upgrading %s "
4097 4094 "(dependent \"%s\" is missing).\n");
4098 4095 const char * const cf_newdpg = gettext("Conflict upgrading %s "
4099 4096 "(dependent \"%s\" has new dependency property group).\n");
4100 4097 const char * const cf_newtarg = gettext("Conflict upgrading %s "
4101 4098 "(dependent \"%s\" has new target).\n");
4102 4099 const char * const li_corrupt =
4103 4100 gettext("%s: \"last-import\" snapshot is corrupt.\n");
4104 4101 const char * const upgrading =
4105 4102 gettext("%s: Upgrading dependent \"%s\".\n");
4106 4103 const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
4107 4104 "corrupt (missing snaplevel).\n");
4108 4105
4109 4106 if (scf_property_type(prop, &ty) != 0) {
4110 4107 switch (scf_error()) {
4111 4108 case SCF_ERROR_DELETED:
4112 4109 case SCF_ERROR_CONNECTION_BROKEN:
4113 4110 return (scferror2errno(scf_error()));
4114 4111
4115 4112 case SCF_ERROR_NOT_BOUND:
4116 4113 case SCF_ERROR_NOT_SET:
4117 4114 default:
4118 4115 bad_error("scf_property_type", scf_error());
4119 4116 }
4120 4117 }
4121 4118
4122 4119 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4123 4120 warn(li_corrupt, ient->sc_fmri);
4124 4121 return (EBADF);
4125 4122 }
4126 4123
4127 4124 /*
4128 4125 * prop represents a dependent in the old manifest. It is named after
4129 4126 * the dependent.
4130 4127 */
4131 4128 if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
4132 4129 switch (scf_error()) {
4133 4130 case SCF_ERROR_DELETED:
4134 4131 case SCF_ERROR_CONNECTION_BROKEN:
4135 4132 return (scferror2errno(scf_error()));
4136 4133
4137 4134 case SCF_ERROR_NOT_BOUND:
4138 4135 case SCF_ERROR_NOT_SET:
4139 4136 default:
4140 4137 bad_error("scf_property_get_name", scf_error());
4141 4138 }
4142 4139 }
4143 4140
4144 4141 /* See if it's in the new manifest. */
4145 4142 pgrp.sc_pgroup_name = ud_name;
4146 4143 new_dpt_pgroup =
4147 4144 uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
4148 4145
4149 4146 /* If it's not, delete it... if it hasn't been customized. */
4150 4147 if (new_dpt_pgroup == NULL) {
4151 4148 if (!ud_run_dpts_pg_set)
4152 4149 return (0);
4153 4150
4154 4151 if (scf_property_get_value(prop, ud_val) != 0) {
4155 4152 switch (scf_error()) {
4156 4153 case SCF_ERROR_NOT_FOUND:
4157 4154 case SCF_ERROR_CONSTRAINT_VIOLATED:
4158 4155 warn(li_corrupt, ient->sc_fmri);
4159 4156 return (EBADF);
4160 4157
4161 4158 case SCF_ERROR_DELETED:
4162 4159 case SCF_ERROR_CONNECTION_BROKEN:
4163 4160 return (scferror2errno(scf_error()));
4164 4161
4165 4162 case SCF_ERROR_HANDLE_MISMATCH:
4166 4163 case SCF_ERROR_NOT_BOUND:
4167 4164 case SCF_ERROR_NOT_SET:
4168 4165 case SCF_ERROR_PERMISSION_DENIED:
4169 4166 default:
4170 4167 bad_error("scf_property_get_value",
4171 4168 scf_error());
4172 4169 }
4173 4170 }
4174 4171
4175 4172 if (scf_value_get_as_string(ud_val, ud_oldtarg,
4176 4173 max_scf_value_len + 1) < 0)
4177 4174 bad_error("scf_value_get_as_string", scf_error());
4178 4175
4179 4176 if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
4180 4177 0) {
4181 4178 switch (scf_error()) {
4182 4179 case SCF_ERROR_NOT_FOUND:
4183 4180 return (0);
4184 4181
4185 4182 case SCF_ERROR_CONNECTION_BROKEN:
4186 4183 return (scferror2errno(scf_error()));
4187 4184
4188 4185 case SCF_ERROR_DELETED:
4189 4186 warn(emsg_pg_deleted, ient->sc_fmri,
4190 4187 "dependents");
4191 4188 return (EBUSY);
4192 4189
4193 4190 case SCF_ERROR_INVALID_ARGUMENT:
4194 4191 case SCF_ERROR_NOT_BOUND:
4195 4192 case SCF_ERROR_HANDLE_MISMATCH:
4196 4193 case SCF_ERROR_NOT_SET:
4197 4194 default:
4198 4195 bad_error("scf_pg_get_property", scf_error());
4199 4196 }
4200 4197 }
4201 4198 if (scf_property_get_value(ud_prop, ud_val) != 0) {
4202 4199 switch (scf_error()) {
4203 4200 case SCF_ERROR_NOT_FOUND:
4204 4201 case SCF_ERROR_CONSTRAINT_VIOLATED:
4205 4202 warn(cf_inval, ient->sc_fmri, ud_name);
4206 4203 return (0);
4207 4204
4208 4205 case SCF_ERROR_DELETED:
4209 4206 case SCF_ERROR_CONNECTION_BROKEN:
4210 4207 return (scferror2errno(scf_error()));
4211 4208
4212 4209 case SCF_ERROR_HANDLE_MISMATCH:
4213 4210 case SCF_ERROR_NOT_BOUND:
4214 4211 case SCF_ERROR_NOT_SET:
4215 4212 case SCF_ERROR_PERMISSION_DENIED:
4216 4213 default:
4217 4214 bad_error("scf_property_get_value",
4218 4215 scf_error());
4219 4216 }
4220 4217 }
4221 4218
4222 4219 ty = scf_value_type(ud_val);
4223 4220 assert(ty != SCF_TYPE_INVALID);
4224 4221 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4225 4222 warn(cf_inval, ient->sc_fmri, ud_name);
4226 4223 return (0);
4227 4224 }
4228 4225
4229 4226 if (scf_value_get_as_string(ud_val, ud_ctarg,
4230 4227 max_scf_value_len + 1) < 0)
4231 4228 bad_error("scf_value_get_as_string", scf_error());
4232 4229
4233 4230 r = fmri_equal(ud_ctarg, ud_oldtarg);
4234 4231 switch (r) {
4235 4232 case 1:
4236 4233 break;
4237 4234
4238 4235 case 0:
4239 4236 case -1: /* warn? */
4240 4237 warn(cf_newtarg, ient->sc_fmri, ud_name);
4241 4238 return (0);
4242 4239
4243 4240 case -2:
4244 4241 warn(li_corrupt, ient->sc_fmri);
4245 4242 return (EBADF);
4246 4243
4247 4244 default:
4248 4245 bad_error("fmri_equal", r);
4249 4246 }
4250 4247
4251 4248 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4252 4249 switch (scf_error()) {
4253 4250 case SCF_ERROR_NOT_FOUND:
4254 4251 warn(li_corrupt, ient->sc_fmri);
4255 4252 return (EBADF);
4256 4253
4257 4254 case SCF_ERROR_DELETED:
4258 4255 case SCF_ERROR_CONNECTION_BROKEN:
4259 4256 return (scferror2errno(scf_error()));
4260 4257
4261 4258 case SCF_ERROR_NOT_BOUND:
4262 4259 case SCF_ERROR_HANDLE_MISMATCH:
4263 4260 case SCF_ERROR_INVALID_ARGUMENT:
4264 4261 case SCF_ERROR_NOT_SET:
4265 4262 default:
4266 4263 bad_error("scf_snaplevel_get_pg", scf_error());
4267 4264 }
4268 4265 }
4269 4266
4270 4267 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4271 4268 snap_lastimport);
4272 4269 switch (r) {
4273 4270 case 0:
4274 4271 break;
4275 4272
4276 4273 case ECANCELED:
4277 4274 case ECONNABORTED:
4278 4275 case ENOMEM:
4279 4276 case EBADF:
4280 4277 return (r);
4281 4278
4282 4279 case EACCES:
4283 4280 default:
4284 4281 bad_error("load_pg", r);
4285 4282 }
4286 4283
4287 4284 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4288 4285 switch (serr) {
4289 4286 case SCF_ERROR_NONE:
4290 4287 break;
4291 4288
4292 4289 case SCF_ERROR_NO_MEMORY:
4293 4290 internal_pgroup_free(old_dpt_pgroup);
4294 4291 return (ENOMEM);
4295 4292
4296 4293 case SCF_ERROR_NOT_FOUND:
4297 4294 internal_pgroup_free(old_dpt_pgroup);
4298 4295 goto delprop;
4299 4296
4300 4297 case SCF_ERROR_CONSTRAINT_VIOLATED: /* caught above */
4301 4298 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
4302 4299 default:
4303 4300 bad_error("fmri_to_entity", serr);
4304 4301 }
4305 4302
4306 4303 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4307 4304 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4308 4305 switch (r) {
4309 4306 case 0:
4310 4307 break;
4311 4308
4312 4309 case ECONNABORTED:
4313 4310 internal_pgroup_free(old_dpt_pgroup);
4314 4311 return (r);
4315 4312
4316 4313 case ECANCELED:
4317 4314 case ENOENT:
4318 4315 internal_pgroup_free(old_dpt_pgroup);
4319 4316 goto delprop;
4320 4317
4321 4318 case EBADF:
4322 4319 warn(r_no_lvl, ud_ctarg);
4323 4320 internal_pgroup_free(old_dpt_pgroup);
4324 4321 return (r);
4325 4322
4326 4323 case EINVAL:
4327 4324 default:
4328 4325 bad_error("entity_get_running_pg", r);
4329 4326 }
4330 4327
4331 4328 /* load it */
4332 4329 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4333 4330 switch (r) {
4334 4331 case 0:
4335 4332 break;
4336 4333
4337 4334 case ECANCELED:
4338 4335 internal_pgroup_free(old_dpt_pgroup);
4339 4336 goto delprop;
4340 4337
4341 4338 case ECONNABORTED:
4342 4339 case ENOMEM:
4343 4340 case EBADF:
4344 4341 internal_pgroup_free(old_dpt_pgroup);
4345 4342 return (r);
4346 4343
4347 4344 case EACCES:
4348 4345 default:
4349 4346 bad_error("load_pg", r);
4350 4347 }
4351 4348
4352 4349 /* compare property groups */
4353 4350 if (!pg_equal(old_dpt_pgroup, current_pg)) {
4354 4351 warn(cf_newdpg, ient->sc_fmri, ud_name);
4355 4352 internal_pgroup_free(old_dpt_pgroup);
4356 4353 internal_pgroup_free(current_pg);
4357 4354 return (0);
4358 4355 }
4359 4356
4360 4357 internal_pgroup_free(old_dpt_pgroup);
4361 4358 internal_pgroup_free(current_pg);
4362 4359
4363 4360 if (g_verbose)
4364 4361 warn(gettext("%s: Deleting dependent \"%s\".\n"),
4365 4362 ient->sc_fmri, ud_name);
4366 4363
4367 4364 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4368 4365 switch (scf_error()) {
4369 4366 case SCF_ERROR_NOT_FOUND:
4370 4367 case SCF_ERROR_DELETED:
4371 4368 internal_pgroup_free(old_dpt_pgroup);
4372 4369 goto delprop;
4373 4370
4374 4371 case SCF_ERROR_CONNECTION_BROKEN:
4375 4372 internal_pgroup_free(old_dpt_pgroup);
4376 4373 return (ECONNABORTED);
4377 4374
4378 4375 case SCF_ERROR_NOT_SET:
4379 4376 case SCF_ERROR_INVALID_ARGUMENT:
4380 4377 case SCF_ERROR_HANDLE_MISMATCH:
4381 4378 case SCF_ERROR_NOT_BOUND:
4382 4379 default:
4383 4380 bad_error("entity_get_pg", scf_error());
4384 4381 }
4385 4382 }
4386 4383
4387 4384 if (scf_pg_delete(ud_pg) != 0) {
4388 4385 switch (scf_error()) {
4389 4386 case SCF_ERROR_DELETED:
4390 4387 break;
4391 4388
4392 4389 case SCF_ERROR_CONNECTION_BROKEN:
4393 4390 case SCF_ERROR_BACKEND_READONLY:
4394 4391 case SCF_ERROR_BACKEND_ACCESS:
4395 4392 return (scferror2errno(scf_error()));
4396 4393
4397 4394 case SCF_ERROR_PERMISSION_DENIED:
4398 4395 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4399 4396 return (scferror2errno(scf_error()));
4400 4397
4401 4398 case SCF_ERROR_NOT_SET:
4402 4399 default:
4403 4400 bad_error("scf_pg_delete", scf_error());
4404 4401 }
4405 4402 }
4406 4403
4407 4404 /*
4408 4405 * This service was changed, so it must be refreshed. But
4409 4406 * since it's not mentioned in the new manifest, we have to
4410 4407 * record its FMRI here for use later. We record the name
4411 4408 * & the entity (via sc_parent) in case we need to print error
4412 4409 * messages during the refresh.
4413 4410 */
4414 4411 dpt = internal_pgroup_new();
4415 4412 if (dpt == NULL)
4416 4413 return (ENOMEM);
4417 4414 dpt->sc_pgroup_name = strdup(ud_name);
4418 4415 dpt->sc_pgroup_fmri = strdup(ud_ctarg);
4419 4416 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4420 4417 return (ENOMEM);
4421 4418 dpt->sc_parent = (entity_t *)ient;
4422 4419 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4423 4420 uu_die(gettext("libuutil error: %s\n"),
4424 4421 uu_strerror(uu_error()));
4425 4422
4426 4423 delprop:
4427 4424 if (tx == NULL)
4428 4425 return (0);
4429 4426
4430 4427 ent = scf_entry_create(g_hndl);
4431 4428 if (ent == NULL)
4432 4429 return (ENOMEM);
4433 4430
4434 4431 if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
4435 4432 scf_entry_destroy(ent);
4436 4433 switch (scf_error()) {
4437 4434 case SCF_ERROR_DELETED:
4438 4435 warn(emsg_pg_deleted, ient->sc_fmri,
4439 4436 "dependents");
4440 4437 return (EBUSY);
4441 4438
4442 4439 case SCF_ERROR_CONNECTION_BROKEN:
4443 4440 return (scferror2errno(scf_error()));
4444 4441
4445 4442 case SCF_ERROR_NOT_FOUND:
4446 4443 break;
4447 4444
4448 4445 case SCF_ERROR_HANDLE_MISMATCH:
4449 4446 case SCF_ERROR_NOT_BOUND:
4450 4447 case SCF_ERROR_INVALID_ARGUMENT:
4451 4448 case SCF_ERROR_NOT_SET:
4452 4449 default:
4453 4450 bad_error("scf_transaction_property_delete",
4454 4451 scf_error());
4455 4452 }
4456 4453 }
4457 4454
4458 4455 return (0);
4459 4456 }
4460 4457
4461 4458 new_dpt_pgroup->sc_pgroup_seen = 1;
4462 4459
4463 4460 /*
4464 4461 * Decide whether the dependent has changed in the manifest.
4465 4462 */
4466 4463 /* Compare the target. */
4467 4464 if (scf_property_get_value(prop, ud_val) != 0) {
4468 4465 switch (scf_error()) {
4469 4466 case SCF_ERROR_NOT_FOUND:
4470 4467 case SCF_ERROR_CONSTRAINT_VIOLATED:
4471 4468 warn(li_corrupt, ient->sc_fmri);
4472 4469 return (EBADF);
4473 4470
4474 4471 case SCF_ERROR_DELETED:
4475 4472 case SCF_ERROR_CONNECTION_BROKEN:
4476 4473 return (scferror2errno(scf_error()));
4477 4474
4478 4475 case SCF_ERROR_HANDLE_MISMATCH:
4479 4476 case SCF_ERROR_NOT_BOUND:
4480 4477 case SCF_ERROR_NOT_SET:
4481 4478 case SCF_ERROR_PERMISSION_DENIED:
4482 4479 default:
4483 4480 bad_error("scf_property_get_value", scf_error());
4484 4481 }
4485 4482 }
4486 4483
4487 4484 if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
4488 4485 0)
4489 4486 bad_error("scf_value_get_as_string", scf_error());
4490 4487
4491 4488 /*
4492 4489 * If the fmri's are not equal then the old fmri will need to
4493 4490 * be refreshed to ensure that the changes are properly updated
4494 4491 * in that service.
4495 4492 */
4496 4493 r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
4497 4494 switch (r) {
4498 4495 case 0:
4499 4496 dpt = internal_pgroup_new();
4500 4497 if (dpt == NULL)
4501 4498 return (ENOMEM);
4502 4499 dpt->sc_pgroup_name = strdup(ud_name);
4503 4500 dpt->sc_pgroup_fmri = strdup(ud_oldtarg);
4504 4501 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4505 4502 return (ENOMEM);
4506 4503 dpt->sc_parent = (entity_t *)ient;
4507 4504 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4508 4505 uu_die(gettext("libuutil error: %s\n"),
4509 4506 uu_strerror(uu_error()));
4510 4507 break;
4511 4508
4512 4509 case 1:
4513 4510 /* Compare the dependency pgs. */
4514 4511 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4515 4512 switch (scf_error()) {
4516 4513 case SCF_ERROR_NOT_FOUND:
4517 4514 warn(li_corrupt, ient->sc_fmri);
4518 4515 return (EBADF);
4519 4516
4520 4517 case SCF_ERROR_DELETED:
4521 4518 case SCF_ERROR_CONNECTION_BROKEN:
4522 4519 return (scferror2errno(scf_error()));
4523 4520
4524 4521 case SCF_ERROR_NOT_BOUND:
4525 4522 case SCF_ERROR_HANDLE_MISMATCH:
4526 4523 case SCF_ERROR_INVALID_ARGUMENT:
4527 4524 case SCF_ERROR_NOT_SET:
4528 4525 default:
4529 4526 bad_error("scf_snaplevel_get_pg", scf_error());
4530 4527 }
4531 4528 }
4532 4529
4533 4530 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4534 4531 snap_lastimport);
4535 4532 switch (r) {
4536 4533 case 0:
4537 4534 break;
4538 4535
4539 4536 case ECANCELED:
4540 4537 case ECONNABORTED:
4541 4538 case ENOMEM:
4542 4539 case EBADF:
4543 4540 return (r);
4544 4541
4545 4542 case EACCES:
4546 4543 default:
4547 4544 bad_error("load_pg", r);
4548 4545 }
4549 4546
4550 4547 if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4551 4548 /* no change, leave customizations */
4552 4549 internal_pgroup_free(old_dpt_pgroup);
4553 4550 return (0);
4554 4551 }
4555 4552 break;
4556 4553
4557 4554 case -1:
4558 4555 warn(li_corrupt, ient->sc_fmri);
4559 4556 return (EBADF);
4560 4557
4561 4558 case -2:
4562 4559 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4563 4560 ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4564 4561 return (EINVAL);
4565 4562
4566 4563 default:
4567 4564 bad_error("fmri_equal", r);
4568 4565 }
4569 4566
4570 4567 /*
4571 4568 * The dependent has changed in the manifest. Upgrade the current
4572 4569 * properties if they haven't been customized.
4573 4570 */
4574 4571
4575 4572 /*
4576 4573 * If new_dpt_pgroup->sc_override, then act as though the property
4577 4574 * group hasn't been customized.
4578 4575 */
4579 4576 if (new_dpt_pgroup->sc_pgroup_override) {
4580 4577 (void) strcpy(ud_ctarg, ud_oldtarg);
4581 4578 goto nocust;
4582 4579 }
4583 4580
4584 4581 if (!ud_run_dpts_pg_set) {
4585 4582 warn(cf_missing, ient->sc_fmri, ud_name);
4586 4583 r = 0;
4587 4584 goto out;
4588 4585 } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4589 4586 switch (scf_error()) {
4590 4587 case SCF_ERROR_NOT_FOUND:
4591 4588 warn(cf_missing, ient->sc_fmri, ud_name);
4592 4589 r = 0;
4593 4590 goto out;
4594 4591
4595 4592 case SCF_ERROR_CONNECTION_BROKEN:
4596 4593 r = scferror2errno(scf_error());
4597 4594 goto out;
4598 4595
4599 4596 case SCF_ERROR_DELETED:
4600 4597 warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4601 4598 r = EBUSY;
4602 4599 goto out;
4603 4600
4604 4601 case SCF_ERROR_INVALID_ARGUMENT:
4605 4602 case SCF_ERROR_NOT_BOUND:
4606 4603 case SCF_ERROR_HANDLE_MISMATCH:
4607 4604 case SCF_ERROR_NOT_SET:
4608 4605 default:
4609 4606 bad_error("scf_pg_get_property", scf_error());
4610 4607 }
4611 4608 }
4612 4609
4613 4610 if (scf_property_get_value(ud_prop, ud_val) != 0) {
4614 4611 switch (scf_error()) {
4615 4612 case SCF_ERROR_NOT_FOUND:
4616 4613 case SCF_ERROR_CONSTRAINT_VIOLATED:
4617 4614 warn(cf_inval, ient->sc_fmri, ud_name);
4618 4615 r = 0;
4619 4616 goto out;
4620 4617
4621 4618 case SCF_ERROR_DELETED:
4622 4619 case SCF_ERROR_CONNECTION_BROKEN:
4623 4620 r = scferror2errno(scf_error());
4624 4621 goto out;
4625 4622
4626 4623 case SCF_ERROR_HANDLE_MISMATCH:
4627 4624 case SCF_ERROR_NOT_BOUND:
4628 4625 case SCF_ERROR_NOT_SET:
4629 4626 case SCF_ERROR_PERMISSION_DENIED:
4630 4627 default:
4631 4628 bad_error("scf_property_get_value", scf_error());
4632 4629 }
4633 4630 }
4634 4631
4635 4632 ty = scf_value_type(ud_val);
4636 4633 assert(ty != SCF_TYPE_INVALID);
4637 4634 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4638 4635 warn(cf_inval, ient->sc_fmri, ud_name);
4639 4636 r = 0;
4640 4637 goto out;
4641 4638 }
4642 4639 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4643 4640 0)
4644 4641 bad_error("scf_value_get_as_string", scf_error());
4645 4642
4646 4643 r = fmri_equal(ud_ctarg, ud_oldtarg);
4647 4644 if (r == -1) {
4648 4645 warn(cf_inval, ient->sc_fmri, ud_name);
4649 4646 r = 0;
4650 4647 goto out;
4651 4648 } else if (r == -2) {
4652 4649 warn(li_corrupt, ient->sc_fmri);
4653 4650 r = EBADF;
4654 4651 goto out;
4655 4652 } else if (r == 0) {
4656 4653 /*
4657 4654 * Target has been changed. Only abort now if it's been
4658 4655 * changed to something other than what's in the manifest.
4659 4656 */
4660 4657 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4661 4658 if (r == -1) {
4662 4659 warn(cf_inval, ient->sc_fmri, ud_name);
4663 4660 r = 0;
4664 4661 goto out;
4665 4662 } else if (r == 0) {
4666 4663 warn(cf_newtarg, ient->sc_fmri, ud_name);
4667 4664 r = 0;
4668 4665 goto out;
4669 4666 } else if (r != 1) {
4670 4667 /* invalid sc_pgroup_fmri caught above */
4671 4668 bad_error("fmri_equal", r);
4672 4669 }
4673 4670
4674 4671 /*
4675 4672 * Fetch the current dependency pg. If it's what the manifest
4676 4673 * says, then no problem.
4677 4674 */
4678 4675 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4679 4676 switch (serr) {
4680 4677 case SCF_ERROR_NONE:
4681 4678 break;
4682 4679
4683 4680 case SCF_ERROR_NOT_FOUND:
4684 4681 warn(cf_missing, ient->sc_fmri, ud_name);
4685 4682 r = 0;
4686 4683 goto out;
4687 4684
4688 4685 case SCF_ERROR_NO_MEMORY:
4689 4686 r = ENOMEM;
4690 4687 goto out;
4691 4688
4692 4689 case SCF_ERROR_CONSTRAINT_VIOLATED:
4693 4690 case SCF_ERROR_INVALID_ARGUMENT:
4694 4691 default:
4695 4692 bad_error("fmri_to_entity", serr);
4696 4693 }
4697 4694
4698 4695 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4699 4696 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4700 4697 switch (r) {
4701 4698 case 0:
4702 4699 break;
4703 4700
4704 4701 case ECONNABORTED:
4705 4702 goto out;
4706 4703
4707 4704 case ECANCELED:
4708 4705 case ENOENT:
4709 4706 warn(cf_missing, ient->sc_fmri, ud_name);
4710 4707 r = 0;
4711 4708 goto out;
4712 4709
4713 4710 case EBADF:
4714 4711 warn(r_no_lvl, ud_ctarg);
4715 4712 goto out;
4716 4713
4717 4714 case EINVAL:
4718 4715 default:
4719 4716 bad_error("entity_get_running_pg", r);
4720 4717 }
4721 4718
4722 4719 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4723 4720 switch (r) {
4724 4721 case 0:
4725 4722 break;
4726 4723
4727 4724 case ECANCELED:
4728 4725 warn(cf_missing, ient->sc_fmri, ud_name);
4729 4726 r = 0;
4730 4727 goto out;
4731 4728
4732 4729 case ECONNABORTED:
4733 4730 case ENOMEM:
4734 4731 case EBADF:
4735 4732 goto out;
4736 4733
4737 4734 case EACCES:
4738 4735 default:
4739 4736 bad_error("load_pg", r);
4740 4737 }
4741 4738
4742 4739 if (!pg_equal(current_pg, new_dpt_pgroup))
4743 4740 warn(cf_newdpg, ient->sc_fmri, ud_name);
4744 4741 internal_pgroup_free(current_pg);
4745 4742 r = 0;
4746 4743 goto out;
4747 4744 } else if (r != 1) {
4748 4745 bad_error("fmri_equal", r);
4749 4746 }
4750 4747
4751 4748 nocust:
4752 4749 /*
4753 4750 * Target has not been customized. Check the dependency property
4754 4751 * group.
4755 4752 */
4756 4753
4757 4754 if (old_dpt_pgroup == NULL) {
4758 4755 if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4759 4756 ud_pg) != 0) {
4760 4757 switch (scf_error()) {
4761 4758 case SCF_ERROR_NOT_FOUND:
4762 4759 warn(li_corrupt, ient->sc_fmri);
4763 4760 return (EBADF);
4764 4761
4765 4762 case SCF_ERROR_DELETED:
4766 4763 case SCF_ERROR_CONNECTION_BROKEN:
4767 4764 return (scferror2errno(scf_error()));
4768 4765
4769 4766 case SCF_ERROR_NOT_BOUND:
4770 4767 case SCF_ERROR_HANDLE_MISMATCH:
4771 4768 case SCF_ERROR_INVALID_ARGUMENT:
4772 4769 case SCF_ERROR_NOT_SET:
4773 4770 default:
4774 4771 bad_error("scf_snaplevel_get_pg", scf_error());
4775 4772 }
4776 4773 }
4777 4774
4778 4775 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4779 4776 snap_lastimport);
4780 4777 switch (r) {
4781 4778 case 0:
4782 4779 break;
4783 4780
4784 4781 case ECANCELED:
4785 4782 case ECONNABORTED:
4786 4783 case ENOMEM:
4787 4784 case EBADF:
4788 4785 return (r);
4789 4786
4790 4787 case EACCES:
4791 4788 default:
4792 4789 bad_error("load_pg", r);
4793 4790 }
4794 4791 }
4795 4792 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4796 4793 switch (serr) {
4797 4794 case SCF_ERROR_NONE:
4798 4795 break;
4799 4796
4800 4797 case SCF_ERROR_NOT_FOUND:
4801 4798 warn(cf_missing, ient->sc_fmri, ud_name);
4802 4799 r = 0;
4803 4800 goto out;
4804 4801
4805 4802 case SCF_ERROR_NO_MEMORY:
4806 4803 r = ENOMEM;
4807 4804 goto out;
4808 4805
4809 4806 case SCF_ERROR_CONSTRAINT_VIOLATED:
4810 4807 case SCF_ERROR_INVALID_ARGUMENT:
4811 4808 default:
4812 4809 bad_error("fmri_to_entity", serr);
4813 4810 }
4814 4811
4815 4812 r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4816 4813 ud_iter2, ud_inst, imp_snap, ud_snpl);
4817 4814 switch (r) {
4818 4815 case 0:
4819 4816 break;
4820 4817
4821 4818 case ECONNABORTED:
4822 4819 goto out;
4823 4820
4824 4821 case ECANCELED:
4825 4822 case ENOENT:
4826 4823 warn(cf_missing, ient->sc_fmri, ud_name);
4827 4824 r = 0;
4828 4825 goto out;
4829 4826
4830 4827 case EBADF:
4831 4828 warn(r_no_lvl, ud_ctarg);
4832 4829 goto out;
4833 4830
4834 4831 case EINVAL:
4835 4832 default:
4836 4833 bad_error("entity_get_running_pg", r);
4837 4834 }
4838 4835
4839 4836 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4840 4837 switch (r) {
4841 4838 case 0:
4842 4839 break;
4843 4840
4844 4841 case ECANCELED:
4845 4842 warn(cf_missing, ient->sc_fmri, ud_name);
4846 4843 goto out;
4847 4844
4848 4845 case ECONNABORTED:
4849 4846 case ENOMEM:
4850 4847 case EBADF:
4851 4848 goto out;
4852 4849
4853 4850 case EACCES:
4854 4851 default:
4855 4852 bad_error("load_pg", r);
4856 4853 }
4857 4854
4858 4855 if (!pg_equal(current_pg, old_dpt_pgroup)) {
4859 4856 if (!pg_equal(current_pg, new_dpt_pgroup))
4860 4857 warn(cf_newdpg, ient->sc_fmri, ud_name);
4861 4858 internal_pgroup_free(current_pg);
4862 4859 r = 0;
4863 4860 goto out;
4864 4861 }
4865 4862
4866 4863 /* Uncustomized. Upgrade. */
4867 4864
4868 4865 r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4869 4866 switch (r) {
4870 4867 case 1:
4871 4868 if (pg_equal(current_pg, new_dpt_pgroup)) {
4872 4869 /* Already upgraded. */
4873 4870 internal_pgroup_free(current_pg);
4874 4871 r = 0;
4875 4872 goto out;
4876 4873 }
4877 4874
4878 4875 internal_pgroup_free(current_pg);
4879 4876
4880 4877 /* upgrade current_pg */
4881 4878 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4882 4879 switch (scf_error()) {
4883 4880 case SCF_ERROR_CONNECTION_BROKEN:
4884 4881 r = scferror2errno(scf_error());
4885 4882 goto out;
4886 4883
4887 4884 case SCF_ERROR_DELETED:
4888 4885 warn(cf_missing, ient->sc_fmri, ud_name);
4889 4886 r = 0;
4890 4887 goto out;
4891 4888
4892 4889 case SCF_ERROR_NOT_FOUND:
4893 4890 break;
4894 4891
4895 4892 case SCF_ERROR_INVALID_ARGUMENT:
4896 4893 case SCF_ERROR_NOT_BOUND:
4897 4894 case SCF_ERROR_NOT_SET:
4898 4895 case SCF_ERROR_HANDLE_MISMATCH:
4899 4896 default:
4900 4897 bad_error("entity_get_pg", scf_error());
4901 4898 }
4902 4899
4903 4900 if (tissvc)
4904 4901 r = scf_service_add_pg(target_ent, ud_name,
4905 4902 SCF_GROUP_DEPENDENCY, 0, ud_pg);
4906 4903 else
4907 4904 r = scf_instance_add_pg(target_ent, ud_name,
4908 4905 SCF_GROUP_DEPENDENCY, 0, ud_pg);
4909 4906 if (r != 0) {
4910 4907 switch (scf_error()) {
4911 4908 case SCF_ERROR_CONNECTION_BROKEN:
4912 4909 case SCF_ERROR_NO_RESOURCES:
4913 4910 case SCF_ERROR_BACKEND_READONLY:
4914 4911 case SCF_ERROR_BACKEND_ACCESS:
4915 4912 r = scferror2errno(scf_error());
4916 4913 goto out;
4917 4914
4918 4915 case SCF_ERROR_DELETED:
4919 4916 warn(cf_missing, ient->sc_fmri,
4920 4917 ud_name);
4921 4918 r = 0;
4922 4919 goto out;
4923 4920
4924 4921 case SCF_ERROR_PERMISSION_DENIED:
4925 4922 warn(emsg_pg_deleted, ud_ctarg,
4926 4923 ud_name);
4927 4924 r = EPERM;
4928 4925 goto out;
4929 4926
4930 4927 case SCF_ERROR_EXISTS:
4931 4928 warn(emsg_pg_added, ud_ctarg, ud_name);
4932 4929 r = EBUSY;
4933 4930 goto out;
4934 4931
4935 4932 case SCF_ERROR_NOT_BOUND:
4936 4933 case SCF_ERROR_HANDLE_MISMATCH:
4937 4934 case SCF_ERROR_INVALID_ARGUMENT:
4938 4935 case SCF_ERROR_NOT_SET:
4939 4936 default:
4940 4937 bad_error("entity_add_pg", scf_error());
4941 4938 }
4942 4939 }
4943 4940 }
4944 4941
4945 4942 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4946 4943 switch (r) {
4947 4944 case 0:
4948 4945 break;
4949 4946
4950 4947 case ECANCELED:
4951 4948 warn(cf_missing, ient->sc_fmri, ud_name);
4952 4949 goto out;
4953 4950
4954 4951 case ECONNABORTED:
4955 4952 case ENOMEM:
4956 4953 case EBADF:
4957 4954 goto out;
4958 4955
4959 4956 case EACCES:
4960 4957 default:
4961 4958 bad_error("load_pg", r);
4962 4959 }
4963 4960
4964 4961 if (g_verbose)
4965 4962 warn(upgrading, ient->sc_fmri, ud_name);
4966 4963
4967 4964 r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4968 4965 new_dpt_pgroup, 0, ient->sc_fmri);
4969 4966 switch (r) {
4970 4967 case 0:
4971 4968 break;
4972 4969
4973 4970 case ECANCELED:
4974 4971 warn(emsg_pg_deleted, ud_ctarg, ud_name);
4975 4972 r = EBUSY;
4976 4973 goto out;
4977 4974
4978 4975 case EPERM:
4979 4976 warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4980 4977 goto out;
4981 4978
4982 4979 case EBUSY:
4983 4980 warn(emsg_pg_changed, ud_ctarg, ud_name);
4984 4981 goto out;
4985 4982
4986 4983 case ECONNABORTED:
4987 4984 case ENOMEM:
4988 4985 case ENOSPC:
4989 4986 case EROFS:
4990 4987 case EACCES:
4991 4988 case EINVAL:
4992 4989 goto out;
4993 4990
4994 4991 default:
4995 4992 bad_error("upgrade_pg", r);
4996 4993 }
4997 4994 break;
4998 4995
4999 4996 case 0: {
5000 4997 scf_transaction_entry_t *ent;
5001 4998 scf_value_t *val;
5002 4999
5003 5000 internal_pgroup_free(current_pg);
5004 5001
5005 5002 /* delete old pg */
5006 5003 if (g_verbose)
5007 5004 warn(upgrading, ient->sc_fmri, ud_name);
5008 5005
5009 5006 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
5010 5007 switch (scf_error()) {
5011 5008 case SCF_ERROR_CONNECTION_BROKEN:
5012 5009 r = scferror2errno(scf_error());
5013 5010 goto out;
5014 5011
5015 5012 case SCF_ERROR_DELETED:
5016 5013 warn(cf_missing, ient->sc_fmri, ud_name);
5017 5014 r = 0;
5018 5015 goto out;
5019 5016
5020 5017 case SCF_ERROR_NOT_FOUND:
5021 5018 break;
5022 5019
5023 5020 case SCF_ERROR_INVALID_ARGUMENT:
5024 5021 case SCF_ERROR_NOT_BOUND:
5025 5022 case SCF_ERROR_NOT_SET:
5026 5023 case SCF_ERROR_HANDLE_MISMATCH:
5027 5024 default:
5028 5025 bad_error("entity_get_pg", scf_error());
5029 5026 }
5030 5027 } else if (scf_pg_delete(ud_pg) != 0) {
5031 5028 switch (scf_error()) {
5032 5029 case SCF_ERROR_DELETED:
5033 5030 break;
5034 5031
5035 5032 case SCF_ERROR_CONNECTION_BROKEN:
5036 5033 case SCF_ERROR_BACKEND_READONLY:
5037 5034 case SCF_ERROR_BACKEND_ACCESS:
5038 5035 r = scferror2errno(scf_error());
5039 5036 goto out;
5040 5037
5041 5038 case SCF_ERROR_PERMISSION_DENIED:
5042 5039 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
5043 5040 r = scferror2errno(scf_error());
5044 5041 goto out;
5045 5042
5046 5043 case SCF_ERROR_NOT_SET:
5047 5044 default:
5048 5045 bad_error("scf_pg_delete", scf_error());
5049 5046 }
5050 5047 }
5051 5048
5052 5049 /* import new one */
5053 5050 cbdata.sc_handle = g_hndl;
5054 5051 cbdata.sc_trans = NULL; /* handled below */
5055 5052 cbdata.sc_flags = 0;
5056 5053
5057 5054 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
5058 5055 if (r != UU_WALK_NEXT) {
5059 5056 if (r != UU_WALK_ERROR)
5060 5057 bad_error("lscf_dependent_import", r);
5061 5058
5062 5059 r = cbdata.sc_err;
5063 5060 goto out;
5064 5061 }
5065 5062
5066 5063 if (tx == NULL)
5067 5064 break;
5068 5065
5069 5066 if ((ent = scf_entry_create(g_hndl)) == NULL ||
5070 5067 (val = scf_value_create(g_hndl)) == NULL) {
5071 5068 if (scf_error() == SCF_ERROR_NO_MEMORY)
5072 5069 return (ENOMEM);
5073 5070
5074 5071 bad_error("scf_entry_create", scf_error());
5075 5072 }
5076 5073
5077 5074 if (scf_transaction_property_change_type(tx, ent, ud_name,
5078 5075 SCF_TYPE_FMRI) != 0) {
5079 5076 switch (scf_error()) {
5080 5077 case SCF_ERROR_CONNECTION_BROKEN:
5081 5078 r = scferror2errno(scf_error());
5082 5079 goto out;
5083 5080
5084 5081 case SCF_ERROR_DELETED:
5085 5082 warn(emsg_pg_deleted, ient->sc_fmri,
5086 5083 "dependents");
5087 5084 r = EBUSY;
5088 5085 goto out;
5089 5086
5090 5087 case SCF_ERROR_NOT_FOUND:
5091 5088 break;
5092 5089
5093 5090 case SCF_ERROR_NOT_BOUND:
5094 5091 case SCF_ERROR_HANDLE_MISMATCH:
5095 5092 case SCF_ERROR_INVALID_ARGUMENT:
5096 5093 case SCF_ERROR_NOT_SET:
5097 5094 default:
5098 5095 bad_error("scf_transaction_property_"
5099 5096 "change_type", scf_error());
5100 5097 }
5101 5098
5102 5099 if (scf_transaction_property_new(tx, ent, ud_name,
5103 5100 SCF_TYPE_FMRI) != 0) {
5104 5101 switch (scf_error()) {
5105 5102 case SCF_ERROR_CONNECTION_BROKEN:
5106 5103 r = scferror2errno(scf_error());
5107 5104 goto out;
5108 5105
5109 5106 case SCF_ERROR_DELETED:
5110 5107 warn(emsg_pg_deleted, ient->sc_fmri,
5111 5108 "dependents");
5112 5109 r = EBUSY;
5113 5110 goto out;
5114 5111
5115 5112 case SCF_ERROR_EXISTS:
5116 5113 warn(emsg_pg_changed, ient->sc_fmri,
5117 5114 "dependents");
5118 5115 r = EBUSY;
5119 5116 goto out;
5120 5117
5121 5118 case SCF_ERROR_INVALID_ARGUMENT:
5122 5119 case SCF_ERROR_HANDLE_MISMATCH:
5123 5120 case SCF_ERROR_NOT_BOUND:
5124 5121 case SCF_ERROR_NOT_SET:
5125 5122 default:
5126 5123 bad_error("scf_transaction_property_"
5127 5124 "new", scf_error());
5128 5125 }
5129 5126 }
5130 5127 }
5131 5128
5132 5129 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
5133 5130 new_dpt_pgroup->sc_pgroup_fmri) != 0)
5134 5131 /* invalid sc_pgroup_fmri caught above */
5135 5132 bad_error("scf_value_set_from_string",
5136 5133 scf_error());
5137 5134
5138 5135 if (scf_entry_add_value(ent, val) != 0)
5139 5136 bad_error("scf_entry_add_value", scf_error());
5140 5137 break;
5141 5138 }
5142 5139
5143 5140 case -2:
5144 5141 warn(li_corrupt, ient->sc_fmri);
5145 5142 internal_pgroup_free(current_pg);
5146 5143 r = EBADF;
5147 5144 goto out;
5148 5145
5149 5146 case -1:
5150 5147 default:
5151 5148 /* invalid sc_pgroup_fmri caught above */
5152 5149 bad_error("fmri_equal", r);
5153 5150 }
5154 5151
5155 5152 r = 0;
5156 5153
5157 5154 out:
5158 5155 if (old_dpt_pgroup != NULL)
5159 5156 internal_pgroup_free(old_dpt_pgroup);
5160 5157
5161 5158 return (r);
5162 5159 }
5163 5160
5164 5161 /*
5165 5162 * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
5166 5163 * would import it, except it seems to exist in the service anyway. Compare
5167 5164 * the existent dependent with the one we would import, and report any
5168 5165 * differences (if there are none, be silent). prop is the property which
5169 5166 * represents the existent dependent (in the dependents property group) in the
5170 5167 * entity corresponding to ient.
5171 5168 *
5172 5169 * Returns
5173 5170 * 0 - success (Sort of. At least, we can continue importing.)
5174 5171 * ECONNABORTED - repository connection broken
5175 5172 * EBUSY - ancestor of prop was deleted (error printed)
5176 5173 * ENOMEM - out of memory
5177 5174 * EBADF - corrupt property group (error printed)
5178 5175 * EINVAL - new_dpt_pgroup has invalid target (error printed)
5179 5176 */
5180 5177 static int
5181 5178 handle_dependent_conflict(const entity_t * const ient,
5182 5179 const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
5183 5180 {
5184 5181 int r;
5185 5182 scf_type_t ty;
5186 5183 scf_error_t scfe;
5187 5184 void *tptr;
5188 5185 int tissvc;
5189 5186 pgroup_t *pgroup;
5190 5187
5191 5188 if (scf_property_get_value(prop, ud_val) != 0) {
5192 5189 switch (scf_error()) {
5193 5190 case SCF_ERROR_CONNECTION_BROKEN:
5194 5191 return (scferror2errno(scf_error()));
5195 5192
5196 5193 case SCF_ERROR_DELETED:
5197 5194 warn(emsg_pg_deleted, ient->sc_fmri,
5198 5195 new_dpt_pgroup->sc_pgroup_name);
5199 5196 return (EBUSY);
5200 5197
5201 5198 case SCF_ERROR_CONSTRAINT_VIOLATED:
5202 5199 case SCF_ERROR_NOT_FOUND:
5203 5200 warn(gettext("Conflict upgrading %s (not importing "
5204 5201 "dependent \"%s\" because it already exists.) "
5205 5202 "Warning: The \"%s/%2$s\" property has more or "
5206 5203 "fewer than one value)).\n"), ient->sc_fmri,
5207 5204 new_dpt_pgroup->sc_pgroup_name, "dependents");
5208 5205 return (0);
5209 5206
5210 5207 case SCF_ERROR_HANDLE_MISMATCH:
5211 5208 case SCF_ERROR_NOT_BOUND:
5212 5209 case SCF_ERROR_NOT_SET:
5213 5210 case SCF_ERROR_PERMISSION_DENIED:
5214 5211 default:
5215 5212 bad_error("scf_property_get_value",
5216 5213 scf_error());
5217 5214 }
5218 5215 }
5219 5216
5220 5217 ty = scf_value_type(ud_val);
5221 5218 assert(ty != SCF_TYPE_INVALID);
5222 5219 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
5223 5220 warn(gettext("Conflict upgrading %s (not importing dependent "
5224 5221 "\"%s\" because it already exists). Warning: The "
5225 5222 "\"%s/%s\" property has unexpected type \"%s\")).\n"),
5226 5223 ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
5227 5224 scf_type_to_string(ty), "dependents");
5228 5225 return (0);
5229 5226 }
5230 5227
5231 5228 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
5232 5229 0)
5233 5230 bad_error("scf_value_get_as_string", scf_error());
5234 5231
5235 5232 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
5236 5233 switch (r) {
5237 5234 case 0:
5238 5235 warn(gettext("Conflict upgrading %s (not importing dependent "
5239 5236 "\"%s\" (target \"%s\") because it already exists with "
5240 5237 "target \"%s\").\n"), ient->sc_fmri,
5241 5238 new_dpt_pgroup->sc_pgroup_name,
5242 5239 new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
5243 5240 return (0);
5244 5241
5245 5242 case 1:
5246 5243 break;
5247 5244
5248 5245 case -1:
5249 5246 warn(gettext("Conflict upgrading %s (not importing dependent "
5250 5247 "\"%s\" because it already exists). Warning: The current "
5251 5248 "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
5252 5249 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5253 5250 return (0);
5254 5251
5255 5252 case -2:
5256 5253 warn(gettext("Dependent \"%s\" of %s has invalid target "
5257 5254 "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
5258 5255 new_dpt_pgroup->sc_pgroup_fmri);
5259 5256 return (EINVAL);
5260 5257
5261 5258 default:
5262 5259 bad_error("fmri_equal", r);
5263 5260 }
5264 5261
5265 5262 /* compare dependency pgs in target */
5266 5263 scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
5267 5264 switch (scfe) {
5268 5265 case SCF_ERROR_NONE:
5269 5266 break;
5270 5267
5271 5268 case SCF_ERROR_NO_MEMORY:
5272 5269 return (ENOMEM);
5273 5270
5274 5271 case SCF_ERROR_NOT_FOUND:
5275 5272 warn(emsg_dpt_dangling, ient->sc_fmri,
5276 5273 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5277 5274 return (0);
5278 5275
5279 5276 case SCF_ERROR_CONSTRAINT_VIOLATED:
5280 5277 case SCF_ERROR_INVALID_ARGUMENT:
5281 5278 default:
5282 5279 bad_error("fmri_to_entity", scfe);
5283 5280 }
5284 5281
5285 5282 r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
5286 5283 ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
5287 5284 switch (r) {
5288 5285 case 0:
5289 5286 break;
5290 5287
5291 5288 case ECONNABORTED:
5292 5289 return (r);
5293 5290
5294 5291 case ECANCELED:
5295 5292 warn(emsg_dpt_dangling, ient->sc_fmri,
5296 5293 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5297 5294 return (0);
5298 5295
5299 5296 case EBADF:
5300 5297 if (tissvc)
5301 5298 warn(gettext("%s has an instance with a \"%s\" "
5302 5299 "snapshot which is missing a snaplevel.\n"),
5303 5300 ud_ctarg, "running");
5304 5301 else
5305 5302 warn(gettext("%s has a \"%s\" snapshot which is "
5306 5303 "missing a snaplevel.\n"), ud_ctarg, "running");
5307 5304 /* FALLTHROUGH */
5308 5305
5309 5306 case ENOENT:
5310 5307 warn(emsg_dpt_no_dep, ient->sc_fmri,
5311 5308 new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5312 5309 new_dpt_pgroup->sc_pgroup_name);
5313 5310 return (0);
5314 5311
5315 5312 case EINVAL:
5316 5313 default:
5317 5314 bad_error("entity_get_running_pg", r);
5318 5315 }
5319 5316
5320 5317 pgroup = internal_pgroup_new();
5321 5318 if (pgroup == NULL)
5322 5319 return (ENOMEM);
5323 5320
5324 5321 r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
5325 5322 switch (r) {
5326 5323 case 0:
5327 5324 break;
5328 5325
5329 5326 case ECONNABORTED:
5330 5327 case EBADF:
5331 5328 case ENOMEM:
5332 5329 internal_pgroup_free(pgroup);
5333 5330 return (r);
5334 5331
5335 5332 case ECANCELED:
5336 5333 warn(emsg_dpt_no_dep, ient->sc_fmri,
5337 5334 new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5338 5335 new_dpt_pgroup->sc_pgroup_name);
5339 5336 internal_pgroup_free(pgroup);
5340 5337 return (0);
5341 5338
5342 5339 case EACCES:
5343 5340 default:
5344 5341 bad_error("load_pg", r);
5345 5342 }
5346 5343
5347 5344 /* report differences */
5348 5345 report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
5349 5346 internal_pgroup_free(pgroup);
5350 5347 return (0);
5351 5348 }
5352 5349
5353 5350 /*
5354 5351 * lipg is a property group in the last-import snapshot of ent, which is an
5355 5352 * scf_service_t or an scf_instance_t (according to ient). If lipg is not in
5356 5353 * ient's pgroups, delete it from ent if it hasn't been customized. If it is
5357 5354 * in ents's property groups, compare and upgrade ent appropriately.
5358 5355 *
5359 5356 * Returns
5360 5357 * 0 - success
5361 5358 * ECONNABORTED - repository connection broken
5362 5359 * ENOMEM - out of memory
5363 5360 * ENOSPC - configd is out of resources
5364 5361 * EINVAL - ient has invalid dependent (error printed)
5365 5362 * - ient has invalid pgroup_t (error printed)
5366 5363 * ECANCELED - ent has been deleted
5367 5364 * ENODEV - entity containing lipg has been deleted
5368 5365 * - entity containing running has been deleted
5369 5366 * EPERM - could not delete pg (permission denied) (error printed)
5370 5367 * - couldn't upgrade dependents (permission denied) (error printed)
5371 5368 * - couldn't import pg (permission denied) (error printed)
5372 5369 * - couldn't upgrade pg (permission denied) (error printed)
5373 5370 * EROFS - could not delete pg (repository read-only)
5374 5371 * - couldn't upgrade dependents (repository read-only)
5375 5372 * - couldn't import pg (repository read-only)
5376 5373 * - couldn't upgrade pg (repository read-only)
5377 5374 * EACCES - could not delete pg (backend access denied)
5378 5375 * - couldn't upgrade dependents (backend access denied)
5379 5376 * - couldn't import pg (backend access denied)
5380 5377 * - couldn't upgrade pg (backend access denied)
5381 5378 * - couldn't read property (backend access denied)
5382 5379 * EBUSY - property group was added (error printed)
5383 5380 * - property group was deleted (error printed)
5384 5381 * - property group changed (error printed)
5385 5382 * - "dependents" pg was added, changed, or deleted (error printed)
5386 5383 * - dependent target deleted (error printed)
5387 5384 * - dependent pg changed (error printed)
5388 5385 * EBADF - imp_snpl is corrupt (error printed)
5389 5386 * - ent has bad pg (error printed)
5390 5387 * EEXIST - dependent collision in target service (error printed)
5391 5388 */
5392 5389 static int
5393 5390 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
5394 5391 const scf_snaplevel_t *running)
5395 5392 {
5396 5393 int r;
5397 5394 pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
5398 5395 scf_callback_t cbdata;
5399 5396
5400 5397 const char * const cf_pg_missing =
5401 5398 gettext("Conflict upgrading %s (property group %s is missing)\n");
5402 5399 const char * const deleting =
5403 5400 gettext("%s: Deleting property group \"%s\".\n");
5404 5401
5405 5402 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5406 5403
5407 5404 /* Skip dependent property groups. */
5408 5405 if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
5409 5406 switch (scf_error()) {
5410 5407 case SCF_ERROR_DELETED:
5411 5408 return (ENODEV);
5412 5409
5413 5410 case SCF_ERROR_CONNECTION_BROKEN:
5414 5411 return (ECONNABORTED);
5415 5412
5416 5413 case SCF_ERROR_NOT_SET:
5417 5414 case SCF_ERROR_NOT_BOUND:
5418 5415 default:
5419 5416 bad_error("scf_pg_get_type", scf_error());
5420 5417 }
5421 5418 }
5422 5419
5423 5420 if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
5424 5421 if (scf_pg_get_property(lipg, "external", NULL) == 0)
5425 5422 return (0);
5426 5423
5427 5424 switch (scf_error()) {
5428 5425 case SCF_ERROR_NOT_FOUND:
5429 5426 break;
5430 5427
5431 5428 case SCF_ERROR_CONNECTION_BROKEN:
5432 5429 return (ECONNABORTED);
5433 5430
5434 5431 case SCF_ERROR_DELETED:
5435 5432 return (ENODEV);
5436 5433
5437 5434 case SCF_ERROR_INVALID_ARGUMENT:
5438 5435 case SCF_ERROR_NOT_BOUND:
5439 5436 case SCF_ERROR_HANDLE_MISMATCH:
5440 5437 case SCF_ERROR_NOT_SET:
5441 5438 default:
5442 5439 bad_error("scf_pg_get_property", scf_error());
5443 5440 }
5444 5441 }
5445 5442
5446 5443 /* lookup pg in new properties */
5447 5444 if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
5448 5445 switch (scf_error()) {
5449 5446 case SCF_ERROR_DELETED:
5450 5447 return (ENODEV);
5451 5448
5452 5449 case SCF_ERROR_CONNECTION_BROKEN:
5453 5450 return (ECONNABORTED);
5454 5451
5455 5452 case SCF_ERROR_NOT_SET:
5456 5453 case SCF_ERROR_NOT_BOUND:
5457 5454 default:
5458 5455 bad_error("scf_pg_get_name", scf_error());
5459 5456 }
5460 5457 }
5461 5458
5462 5459 pgrp.sc_pgroup_name = imp_str;
5463 5460 mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
5464 5461
5465 5462 if (mpg != NULL)
5466 5463 mpg->sc_pgroup_seen = 1;
5467 5464
5468 5465 /* Special handling for dependents */
5469 5466 if (strcmp(imp_str, "dependents") == 0)
5470 5467 return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
5471 5468
5472 5469 if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
5473 5470 return (upgrade_manifestfiles(NULL, ient, running, ent));
5474 5471
5475 5472 if (mpg == NULL || mpg->sc_pgroup_delete) {
5476 5473 /* property group was deleted from manifest */
5477 5474 if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5478 5475 switch (scf_error()) {
5479 5476 case SCF_ERROR_NOT_FOUND:
5480 5477 return (0);
5481 5478
5482 5479 case SCF_ERROR_DELETED:
5483 5480 case SCF_ERROR_CONNECTION_BROKEN:
5484 5481 return (scferror2errno(scf_error()));
5485 5482
5486 5483 case SCF_ERROR_INVALID_ARGUMENT:
5487 5484 case SCF_ERROR_HANDLE_MISMATCH:
5488 5485 case SCF_ERROR_NOT_BOUND:
5489 5486 case SCF_ERROR_NOT_SET:
5490 5487 default:
5491 5488 bad_error("entity_get_pg", scf_error());
5492 5489 }
5493 5490 }
5494 5491
5495 5492 if (mpg != NULL && mpg->sc_pgroup_delete) {
5496 5493 if (g_verbose)
5497 5494 warn(deleting, ient->sc_fmri, imp_str);
5498 5495 if (scf_pg_delete(imp_pg2) == 0)
5499 5496 return (0);
5500 5497
5501 5498 switch (scf_error()) {
5502 5499 case SCF_ERROR_DELETED:
5503 5500 return (0);
5504 5501
5505 5502 case SCF_ERROR_CONNECTION_BROKEN:
5506 5503 case SCF_ERROR_BACKEND_READONLY:
5507 5504 case SCF_ERROR_BACKEND_ACCESS:
5508 5505 return (scferror2errno(scf_error()));
5509 5506
5510 5507 case SCF_ERROR_PERMISSION_DENIED:
5511 5508 warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
5512 5509 return (scferror2errno(scf_error()));
5513 5510
5514 5511 case SCF_ERROR_NOT_SET:
5515 5512 default:
5516 5513 bad_error("scf_pg_delete", scf_error());
5517 5514 }
5518 5515 }
5519 5516
5520 5517 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5521 5518 switch (r) {
5522 5519 case 0:
5523 5520 break;
5524 5521
5525 5522 case ECANCELED:
5526 5523 return (ENODEV);
5527 5524
5528 5525 case ECONNABORTED:
5529 5526 case ENOMEM:
5530 5527 case EBADF:
5531 5528 case EACCES:
5532 5529 return (r);
5533 5530
5534 5531 default:
5535 5532 bad_error("load_pg", r);
5536 5533 }
5537 5534
5538 5535 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5539 5536 switch (r) {
5540 5537 case 0:
5541 5538 break;
5542 5539
5543 5540 case ECANCELED:
5544 5541 case ECONNABORTED:
5545 5542 case ENOMEM:
5546 5543 case EBADF:
5547 5544 case EACCES:
5548 5545 internal_pgroup_free(lipg_i);
5549 5546 return (r);
5550 5547
5551 5548 default:
5552 5549 bad_error("load_pg", r);
5553 5550 }
5554 5551
5555 5552 if (pg_equal(lipg_i, curpg_i)) {
5556 5553 if (g_verbose)
5557 5554 warn(deleting, ient->sc_fmri, imp_str);
5558 5555 if (scf_pg_delete(imp_pg2) != 0) {
5559 5556 switch (scf_error()) {
5560 5557 case SCF_ERROR_DELETED:
5561 5558 break;
5562 5559
5563 5560 case SCF_ERROR_CONNECTION_BROKEN:
5564 5561 internal_pgroup_free(lipg_i);
5565 5562 internal_pgroup_free(curpg_i);
5566 5563 return (ECONNABORTED);
5567 5564
5568 5565 case SCF_ERROR_NOT_SET:
5569 5566 case SCF_ERROR_NOT_BOUND:
5570 5567 default:
5571 5568 bad_error("scf_pg_delete", scf_error());
5572 5569 }
5573 5570 }
5574 5571 } else {
5575 5572 report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5576 5573 }
5577 5574
5578 5575 internal_pgroup_free(lipg_i);
5579 5576 internal_pgroup_free(curpg_i);
5580 5577
5581 5578 return (0);
5582 5579 }
5583 5580
5584 5581 /*
5585 5582 * Only dependent pgs can have override set, and we skipped those
5586 5583 * above.
5587 5584 */
5588 5585 assert(!mpg->sc_pgroup_override);
5589 5586
5590 5587 /* compare */
5591 5588 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5592 5589 switch (r) {
5593 5590 case 0:
5594 5591 break;
5595 5592
5596 5593 case ECANCELED:
5597 5594 return (ENODEV);
5598 5595
5599 5596 case ECONNABORTED:
5600 5597 case EBADF:
5601 5598 case ENOMEM:
5602 5599 case EACCES:
5603 5600 return (r);
5604 5601
5605 5602 default:
5606 5603 bad_error("load_pg", r);
5607 5604 }
5608 5605
5609 5606 if (pg_equal(mpg, lipg_i)) {
5610 5607 /* The manifest pg has not changed. Move on. */
5611 5608 r = 0;
5612 5609 goto out;
5613 5610 }
5614 5611
5615 5612 /* upgrade current properties according to lipg & mpg */
5616 5613 if (running != NULL)
5617 5614 r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5618 5615 else
5619 5616 r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5620 5617 if (r != 0) {
5621 5618 switch (scf_error()) {
5622 5619 case SCF_ERROR_CONNECTION_BROKEN:
5623 5620 r = scferror2errno(scf_error());
5624 5621 goto out;
5625 5622
5626 5623 case SCF_ERROR_DELETED:
5627 5624 if (running != NULL)
5628 5625 r = ENODEV;
5629 5626 else
5630 5627 r = ECANCELED;
5631 5628 goto out;
5632 5629
5633 5630 case SCF_ERROR_NOT_FOUND:
5634 5631 break;
5635 5632
5636 5633 case SCF_ERROR_INVALID_ARGUMENT:
5637 5634 case SCF_ERROR_HANDLE_MISMATCH:
5638 5635 case SCF_ERROR_NOT_BOUND:
5639 5636 case SCF_ERROR_NOT_SET:
5640 5637 default:
5641 5638 bad_error("entity_get_pg", scf_error());
5642 5639 }
5643 5640
5644 5641 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5645 5642
5646 5643 r = 0;
5647 5644 goto out;
5648 5645 }
5649 5646
5650 5647 r = load_pg_attrs(imp_pg2, &curpg_i);
5651 5648 switch (r) {
5652 5649 case 0:
5653 5650 break;
5654 5651
5655 5652 case ECANCELED:
5656 5653 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5657 5654 r = 0;
5658 5655 goto out;
5659 5656
5660 5657 case ECONNABORTED:
5661 5658 case ENOMEM:
5662 5659 goto out;
5663 5660
5664 5661 default:
5665 5662 bad_error("load_pg_attrs", r);
5666 5663 }
5667 5664
5668 5665 if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5669 5666 (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5670 5667 internal_pgroup_free(curpg_i);
5671 5668 r = 0;
5672 5669 goto out;
5673 5670 }
5674 5671
5675 5672 internal_pgroup_free(curpg_i);
5676 5673
5677 5674 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5678 5675 switch (r) {
5679 5676 case 0:
5680 5677 break;
5681 5678
5682 5679 case ECANCELED:
5683 5680 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5684 5681 r = 0;
5685 5682 goto out;
5686 5683
5687 5684 case ECONNABORTED:
5688 5685 case EBADF:
5689 5686 case ENOMEM:
5690 5687 case EACCES:
5691 5688 goto out;
5692 5689
5693 5690 default:
5694 5691 bad_error("load_pg", r);
5695 5692 }
5696 5693
5697 5694 if (pg_equal(lipg_i, curpg_i) &&
5698 5695 !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5699 5696 int do_delete = 1;
5700 5697
5701 5698 if (g_verbose)
5702 5699 warn(gettext("%s: Upgrading property group \"%s\".\n"),
5703 5700 ient->sc_fmri, mpg->sc_pgroup_name);
5704 5701
5705 5702 internal_pgroup_free(curpg_i);
5706 5703
5707 5704 if (running != NULL &&
5708 5705 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5709 5706 switch (scf_error()) {
5710 5707 case SCF_ERROR_DELETED:
5711 5708 r = ECANCELED;
5712 5709 goto out;
5713 5710
5714 5711 case SCF_ERROR_NOT_FOUND:
5715 5712 do_delete = 0;
5716 5713 break;
5717 5714
5718 5715 case SCF_ERROR_CONNECTION_BROKEN:
5719 5716 r = scferror2errno(scf_error());
5720 5717 goto out;
5721 5718
5722 5719 case SCF_ERROR_HANDLE_MISMATCH:
5723 5720 case SCF_ERROR_INVALID_ARGUMENT:
5724 5721 case SCF_ERROR_NOT_SET:
5725 5722 case SCF_ERROR_NOT_BOUND:
5726 5723 default:
5727 5724 bad_error("entity_get_pg", scf_error());
5728 5725 }
5729 5726 }
5730 5727
5731 5728 if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5732 5729 switch (scf_error()) {
5733 5730 case SCF_ERROR_DELETED:
5734 5731 break;
5735 5732
5736 5733 case SCF_ERROR_CONNECTION_BROKEN:
5737 5734 case SCF_ERROR_BACKEND_READONLY:
5738 5735 case SCF_ERROR_BACKEND_ACCESS:
5739 5736 r = scferror2errno(scf_error());
5740 5737 goto out;
5741 5738
5742 5739 case SCF_ERROR_PERMISSION_DENIED:
5743 5740 warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5744 5741 ient->sc_fmri);
5745 5742 r = scferror2errno(scf_error());
5746 5743 goto out;
5747 5744
5748 5745 case SCF_ERROR_NOT_SET:
5749 5746 case SCF_ERROR_NOT_BOUND:
5750 5747 default:
5751 5748 bad_error("scf_pg_delete", scf_error());
5752 5749 }
5753 5750 }
5754 5751
5755 5752 cbdata.sc_handle = g_hndl;
5756 5753 cbdata.sc_parent = ent;
5757 5754 cbdata.sc_service = issvc;
5758 5755 cbdata.sc_flags = 0;
5759 5756 cbdata.sc_source_fmri = ient->sc_fmri;
5760 5757 cbdata.sc_target_fmri = ient->sc_fmri;
5761 5758
5762 5759 r = entity_pgroup_import(mpg, &cbdata);
5763 5760 switch (r) {
5764 5761 case UU_WALK_NEXT:
5765 5762 r = 0;
5766 5763 goto out;
5767 5764
5768 5765 case UU_WALK_ERROR:
5769 5766 if (cbdata.sc_err == EEXIST) {
5770 5767 warn(emsg_pg_added, ient->sc_fmri,
5771 5768 mpg->sc_pgroup_name);
5772 5769 r = EBUSY;
5773 5770 } else {
5774 5771 r = cbdata.sc_err;
5775 5772 }
5776 5773 goto out;
5777 5774
5778 5775 default:
5779 5776 bad_error("entity_pgroup_import", r);
5780 5777 }
5781 5778 }
5782 5779
5783 5780 if (running != NULL &&
5784 5781 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5785 5782 switch (scf_error()) {
5786 5783 case SCF_ERROR_CONNECTION_BROKEN:
5787 5784 case SCF_ERROR_DELETED:
5788 5785 r = scferror2errno(scf_error());
5789 5786 goto out;
5790 5787
5791 5788 case SCF_ERROR_NOT_FOUND:
5792 5789 break;
5793 5790
5794 5791 case SCF_ERROR_HANDLE_MISMATCH:
5795 5792 case SCF_ERROR_INVALID_ARGUMENT:
5796 5793 case SCF_ERROR_NOT_SET:
5797 5794 case SCF_ERROR_NOT_BOUND:
5798 5795 default:
5799 5796 bad_error("entity_get_pg", scf_error());
5800 5797 }
5801 5798
5802 5799 cbdata.sc_handle = g_hndl;
5803 5800 cbdata.sc_parent = ent;
5804 5801 cbdata.sc_service = issvc;
5805 5802 cbdata.sc_flags = SCI_FORCE;
5806 5803 cbdata.sc_source_fmri = ient->sc_fmri;
5807 5804 cbdata.sc_target_fmri = ient->sc_fmri;
5808 5805
5809 5806 r = entity_pgroup_import(mpg, &cbdata);
5810 5807 switch (r) {
5811 5808 case UU_WALK_NEXT:
5812 5809 r = 0;
5813 5810 goto out;
5814 5811
5815 5812 case UU_WALK_ERROR:
5816 5813 if (cbdata.sc_err == EEXIST) {
5817 5814 warn(emsg_pg_added, ient->sc_fmri,
5818 5815 mpg->sc_pgroup_name);
5819 5816 r = EBUSY;
5820 5817 } else {
5821 5818 r = cbdata.sc_err;
5822 5819 }
5823 5820 goto out;
5824 5821
5825 5822 default:
5826 5823 bad_error("entity_pgroup_import", r);
5827 5824 }
5828 5825 }
5829 5826
5830 5827 r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5831 5828 internal_pgroup_free(curpg_i);
5832 5829 switch (r) {
5833 5830 case 0:
5834 5831 ient->sc_import_state = IMPORT_PROP_BEGUN;
5835 5832 break;
5836 5833
5837 5834 case ECANCELED:
5838 5835 warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5839 5836 r = EBUSY;
5840 5837 break;
5841 5838
5842 5839 case EPERM:
5843 5840 warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5844 5841 break;
5845 5842
5846 5843 case EBUSY:
5847 5844 warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5848 5845 break;
5849 5846
5850 5847 case ECONNABORTED:
5851 5848 case ENOMEM:
5852 5849 case ENOSPC:
5853 5850 case EROFS:
5854 5851 case EACCES:
5855 5852 case EINVAL:
5856 5853 break;
5857 5854
5858 5855 default:
5859 5856 bad_error("upgrade_pg", r);
5860 5857 }
5861 5858
5862 5859 out:
5863 5860 internal_pgroup_free(lipg_i);
5864 5861 return (r);
5865 5862 }
5866 5863
5867 5864 /*
5868 5865 * Upgrade the properties of ent according to snpl & ient.
5869 5866 *
5870 5867 * Returns
5871 5868 * 0 - success
5872 5869 * ECONNABORTED - repository connection broken
5873 5870 * ENOMEM - out of memory
5874 5871 * ENOSPC - configd is out of resources
5875 5872 * ECANCELED - ent was deleted
5876 5873 * ENODEV - entity containing snpl was deleted
5877 5874 * - entity containing running was deleted
5878 5875 * EBADF - imp_snpl is corrupt (error printed)
5879 5876 * - ent has corrupt pg (error printed)
5880 5877 * - dependent has corrupt pg (error printed)
5881 5878 * - dependent target has a corrupt snapshot (error printed)
5882 5879 * EBUSY - pg was added, changed, or deleted (error printed)
5883 5880 * - dependent target was deleted (error printed)
5884 5881 * - dependent pg changed (error printed)
5885 5882 * EINVAL - invalid property group name (error printed)
5886 5883 * - invalid property name (error printed)
5887 5884 * - invalid value (error printed)
5888 5885 * - ient has invalid pgroup or dependent (error printed)
5889 5886 * EPERM - could not create property group (permission denied) (error printed)
5890 5887 * - could not modify property group (permission denied) (error printed)
5891 5888 * - couldn't delete, upgrade, or import pg or dependent (error printed)
5892 5889 * EROFS - could not create property group (repository read-only)
5893 5890 * - couldn't delete, upgrade, or import pg or dependent
5894 5891 * EACCES - could not create property group (backend access denied)
5895 5892 * - couldn't delete, upgrade, or import pg or dependent
5896 5893 * EEXIST - dependent collision in target service (error printed)
5897 5894 */
5898 5895 static int
5899 5896 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5900 5897 entity_t *ient)
5901 5898 {
5902 5899 pgroup_t *pg, *rpg;
5903 5900 int r;
5904 5901 uu_list_t *pgs = ient->sc_pgroups;
5905 5902
5906 5903 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5907 5904
5908 5905 /* clear sc_sceen for pgs */
5909 5906 if (uu_list_walk(pgs, clear_int,
5910 5907 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5911 5908 bad_error("uu_list_walk", uu_error());
5912 5909
5913 5910 if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5914 5911 switch (scf_error()) {
5915 5912 case SCF_ERROR_DELETED:
5916 5913 return (ENODEV);
5917 5914
5918 5915 case SCF_ERROR_CONNECTION_BROKEN:
5919 5916 return (ECONNABORTED);
5920 5917
5921 5918 case SCF_ERROR_NOT_SET:
5922 5919 case SCF_ERROR_NOT_BOUND:
5923 5920 case SCF_ERROR_HANDLE_MISMATCH:
5924 5921 default:
5925 5922 bad_error("scf_iter_snaplevel_pgs", scf_error());
5926 5923 }
5927 5924 }
5928 5925
5929 5926 for (;;) {
5930 5927 r = scf_iter_next_pg(imp_up_iter, imp_pg);
5931 5928 if (r == 0)
5932 5929 break;
5933 5930 if (r == 1) {
5934 5931 r = process_old_pg(imp_pg, ient, ent, running);
5935 5932 switch (r) {
5936 5933 case 0:
5937 5934 break;
5938 5935
5939 5936 case ECONNABORTED:
5940 5937 case ENOMEM:
5941 5938 case ENOSPC:
5942 5939 case ECANCELED:
5943 5940 case ENODEV:
5944 5941 case EPERM:
5945 5942 case EROFS:
5946 5943 case EACCES:
5947 5944 case EBADF:
5948 5945 case EBUSY:
5949 5946 case EINVAL:
5950 5947 case EEXIST:
5951 5948 return (r);
5952 5949
5953 5950 default:
5954 5951 bad_error("process_old_pg", r);
5955 5952 }
5956 5953 continue;
5957 5954 }
5958 5955 if (r != -1)
5959 5956 bad_error("scf_iter_next_pg", r);
5960 5957
5961 5958 switch (scf_error()) {
5962 5959 case SCF_ERROR_DELETED:
5963 5960 return (ENODEV);
5964 5961
5965 5962 case SCF_ERROR_CONNECTION_BROKEN:
5966 5963 return (ECONNABORTED);
5967 5964
5968 5965 case SCF_ERROR_HANDLE_MISMATCH:
5969 5966 case SCF_ERROR_NOT_BOUND:
5970 5967 case SCF_ERROR_NOT_SET:
5971 5968 case SCF_ERROR_INVALID_ARGUMENT:
5972 5969 default:
5973 5970 bad_error("scf_iter_next_pg", scf_error());
5974 5971 }
5975 5972 }
5976 5973
5977 5974 for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5978 5975 if (pg->sc_pgroup_seen)
5979 5976 continue;
5980 5977
5981 5978 /* pg is new */
5982 5979
5983 5980 if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5984 5981 r = upgrade_dependents(NULL, imp_snpl, ient, running,
5985 5982 ent);
5986 5983 switch (r) {
5987 5984 case 0:
5988 5985 break;
5989 5986
5990 5987 case ECONNABORTED:
5991 5988 case ENOMEM:
5992 5989 case ENOSPC:
5993 5990 case ECANCELED:
5994 5991 case ENODEV:
5995 5992 case EBADF:
5996 5993 case EBUSY:
5997 5994 case EINVAL:
5998 5995 case EPERM:
5999 5996 case EROFS:
6000 5997 case EACCES:
6001 5998 case EEXIST:
6002 5999 return (r);
6003 6000
6004 6001 default:
6005 6002 bad_error("upgrade_dependents", r);
6006 6003 }
6007 6004 continue;
6008 6005 }
6009 6006
6010 6007 if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
6011 6008 r = upgrade_manifestfiles(pg, ient, running, ent);
6012 6009 switch (r) {
6013 6010 case 0:
6014 6011 break;
6015 6012
6016 6013 case ECONNABORTED:
6017 6014 case ENOMEM:
6018 6015 case ENOSPC:
6019 6016 case ECANCELED:
6020 6017 case ENODEV:
6021 6018 case EBADF:
6022 6019 case EBUSY:
6023 6020 case EINVAL:
6024 6021 case EPERM:
6025 6022 case EROFS:
6026 6023 case EACCES:
6027 6024 case EEXIST:
6028 6025 return (r);
6029 6026
6030 6027 default:
6031 6028 bad_error("upgrade_manifestfiles", r);
6032 6029 }
6033 6030 continue;
6034 6031 }
6035 6032
6036 6033 if (running != NULL) {
6037 6034 r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
6038 6035 imp_pg);
6039 6036 } else {
6040 6037 r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
6041 6038 imp_pg);
6042 6039 }
6043 6040 if (r != 0) {
6044 6041 scf_callback_t cbdata;
6045 6042
6046 6043 switch (scf_error()) {
6047 6044 case SCF_ERROR_NOT_FOUND:
6048 6045 break;
6049 6046
6050 6047 case SCF_ERROR_CONNECTION_BROKEN:
6051 6048 return (scferror2errno(scf_error()));
6052 6049
6053 6050 case SCF_ERROR_DELETED:
6054 6051 if (running != NULL)
6055 6052 return (ENODEV);
6056 6053 else
6057 6054 return (scferror2errno(scf_error()));
6058 6055
6059 6056 case SCF_ERROR_INVALID_ARGUMENT:
6060 6057 warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
6061 6058 pg->sc_pgroup_name);
6062 6059 return (EINVAL);
6063 6060
6064 6061 case SCF_ERROR_NOT_SET:
6065 6062 case SCF_ERROR_HANDLE_MISMATCH:
6066 6063 case SCF_ERROR_NOT_BOUND:
6067 6064 default:
6068 6065 bad_error("entity_get_pg", scf_error());
6069 6066 }
6070 6067
6071 6068 /* User doesn't have pg, so import it. */
6072 6069
6073 6070 cbdata.sc_handle = g_hndl;
6074 6071 cbdata.sc_parent = ent;
6075 6072 cbdata.sc_service = issvc;
6076 6073 cbdata.sc_flags = SCI_FORCE;
6077 6074 cbdata.sc_source_fmri = ient->sc_fmri;
6078 6075 cbdata.sc_target_fmri = ient->sc_fmri;
6079 6076
6080 6077 r = entity_pgroup_import(pg, &cbdata);
6081 6078 switch (r) {
6082 6079 case UU_WALK_NEXT:
6083 6080 ient->sc_import_state = IMPORT_PROP_BEGUN;
6084 6081 continue;
6085 6082
6086 6083 case UU_WALK_ERROR:
6087 6084 if (cbdata.sc_err == EEXIST) {
6088 6085 warn(emsg_pg_added, ient->sc_fmri,
6089 6086 pg->sc_pgroup_name);
6090 6087 return (EBUSY);
6091 6088 }
6092 6089 return (cbdata.sc_err);
6093 6090
6094 6091 default:
6095 6092 bad_error("entity_pgroup_import", r);
6096 6093 }
6097 6094 }
6098 6095
6099 6096 /* report differences between pg & current */
6100 6097 r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
6101 6098 switch (r) {
6102 6099 case 0:
6103 6100 break;
6104 6101
6105 6102 case ECANCELED:
6106 6103 warn(emsg_pg_deleted, ient->sc_fmri,
6107 6104 pg->sc_pgroup_name);
6108 6105 return (EBUSY);
6109 6106
6110 6107 case ECONNABORTED:
6111 6108 case EBADF:
6112 6109 case ENOMEM:
6113 6110 case EACCES:
6114 6111 return (r);
6115 6112
6116 6113 default:
6117 6114 bad_error("load_pg", r);
6118 6115 }
6119 6116 report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
6120 6117 internal_pgroup_free(rpg);
6121 6118 rpg = NULL;
6122 6119 }
6123 6120
6124 6121 return (0);
6125 6122 }
6126 6123
6127 6124 /*
6128 6125 * Import an instance. If it doesn't exist, create it. If it has
6129 6126 * a last-import snapshot, upgrade its properties. Finish by updating its
6130 6127 * last-import snapshot. If it doesn't have a last-import snapshot then it
6131 6128 * could have been created for a dependent tag in another manifest. Import the
6132 6129 * new properties. If there's a conflict, don't override, like now?
6133 6130 *
6134 6131 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
6135 6132 * lcbdata->sc_err to
6136 6133 * ECONNABORTED - repository connection broken
6137 6134 * ENOMEM - out of memory
6138 6135 * ENOSPC - svc.configd is out of resources
6139 6136 * EEXIST - dependency collision in dependent service (error printed)
6140 6137 * EPERM - couldn't create temporary instance (permission denied)
6141 6138 * - couldn't import into temporary instance (permission denied)
6142 6139 * - couldn't take snapshot (permission denied)
6143 6140 * - couldn't upgrade properties (permission denied)
6144 6141 * - couldn't import properties (permission denied)
6145 6142 * - couldn't import dependents (permission denied)
6146 6143 * EROFS - couldn't create temporary instance (repository read-only)
6147 6144 * - couldn't import into temporary instance (repository read-only)
6148 6145 * - couldn't upgrade properties (repository read-only)
6149 6146 * - couldn't import properties (repository read-only)
6150 6147 * - couldn't import dependents (repository read-only)
6151 6148 * EACCES - couldn't create temporary instance (backend access denied)
6152 6149 * - couldn't import into temporary instance (backend access denied)
6153 6150 * - couldn't upgrade properties (backend access denied)
6154 6151 * - couldn't import properties (backend access denied)
6155 6152 * - couldn't import dependents (backend access denied)
6156 6153 * EINVAL - invalid instance name (error printed)
6157 6154 * - invalid pgroup_t's (error printed)
6158 6155 * - invalid dependents (error printed)
6159 6156 * EBUSY - temporary service deleted (error printed)
6160 6157 * - temporary instance deleted (error printed)
6161 6158 * - temporary instance changed (error printed)
6162 6159 * - temporary instance already exists (error printed)
6163 6160 * - instance deleted (error printed)
6164 6161 * EBADF - instance has corrupt last-import snapshot (error printed)
6165 6162 * - instance is corrupt (error printed)
6166 6163 * - dependent has corrupt pg (error printed)
6167 6164 * - dependent target has a corrupt snapshot (error printed)
6168 6165 * -1 - unknown libscf error (error printed)
6169 6166 */
6170 6167 static int
6171 6168 lscf_instance_import(void *v, void *pvt)
6172 6169 {
6173 6170 entity_t *inst = v;
6174 6171 scf_callback_t ctx;
6175 6172 scf_callback_t *lcbdata = pvt;
6176 6173 scf_service_t *rsvc = lcbdata->sc_parent;
6177 6174 int r;
6178 6175 scf_snaplevel_t *running;
6179 6176 int flags = lcbdata->sc_flags;
6180 6177
6181 6178 const char * const emsg_tdel =
6182 6179 gettext("Temporary instance svc:/%s:%s was deleted.\n");
6183 6180 const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
6184 6181 "changed unexpectedly.\n");
6185 6182 const char * const emsg_del = gettext("%s changed unexpectedly "
6186 6183 "(instance \"%s\" was deleted.)\n");
6187 6184 const char * const emsg_badsnap = gettext(
6188 6185 "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
6189 6186
6190 6187 /*
6191 6188 * prepare last-import snapshot:
6192 6189 * create temporary instance (service was precreated)
6193 6190 * populate with properties from bundle
6194 6191 * take snapshot
6195 6192 */
6196 6193 if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
6197 6194 switch (scf_error()) {
6198 6195 case SCF_ERROR_CONNECTION_BROKEN:
6199 6196 case SCF_ERROR_NO_RESOURCES:
6200 6197 case SCF_ERROR_BACKEND_READONLY:
6201 6198 case SCF_ERROR_BACKEND_ACCESS:
6202 6199 return (stash_scferror(lcbdata));
6203 6200
6204 6201 case SCF_ERROR_EXISTS:
6205 6202 warn(gettext("Temporary service svc:/%s "
6206 6203 "changed unexpectedly (instance \"%s\" added).\n"),
6207 6204 imp_tsname, inst->sc_name);
6208 6205 lcbdata->sc_err = EBUSY;
6209 6206 return (UU_WALK_ERROR);
6210 6207
6211 6208 case SCF_ERROR_DELETED:
6212 6209 warn(gettext("Temporary service svc:/%s "
6213 6210 "was deleted unexpectedly.\n"), imp_tsname);
6214 6211 lcbdata->sc_err = EBUSY;
6215 6212 return (UU_WALK_ERROR);
6216 6213
6217 6214 case SCF_ERROR_INVALID_ARGUMENT:
6218 6215 warn(gettext("Invalid instance name \"%s\".\n"),
6219 6216 inst->sc_name);
6220 6217 return (stash_scferror(lcbdata));
6221 6218
6222 6219 case SCF_ERROR_PERMISSION_DENIED:
6223 6220 warn(gettext("Could not create temporary instance "
6224 6221 "\"%s\" in svc:/%s (permission denied).\n"),
6225 6222 inst->sc_name, imp_tsname);
6226 6223 return (stash_scferror(lcbdata));
6227 6224
6228 6225 case SCF_ERROR_HANDLE_MISMATCH:
6229 6226 case SCF_ERROR_NOT_BOUND:
6230 6227 case SCF_ERROR_NOT_SET:
6231 6228 default:
6232 6229 bad_error("scf_service_add_instance", scf_error());
6233 6230 }
6234 6231 }
6235 6232
6236 6233 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6237 6234 inst->sc_name);
6238 6235 if (r < 0)
6239 6236 bad_error("snprintf", errno);
6240 6237
6241 6238 r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
6242 6239 lcbdata->sc_flags | SCI_NOENABLED);
6243 6240 switch (r) {
6244 6241 case 0:
6245 6242 break;
6246 6243
6247 6244 case ECANCELED:
6248 6245 warn(emsg_tdel, imp_tsname, inst->sc_name);
6249 6246 lcbdata->sc_err = EBUSY;
6250 6247 r = UU_WALK_ERROR;
6251 6248 goto deltemp;
6252 6249
6253 6250 case EEXIST:
6254 6251 warn(emsg_tchg, imp_tsname, inst->sc_name);
6255 6252 lcbdata->sc_err = EBUSY;
6256 6253 r = UU_WALK_ERROR;
6257 6254 goto deltemp;
6258 6255
6259 6256 case ECONNABORTED:
6260 6257 goto connaborted;
6261 6258
6262 6259 case ENOMEM:
6263 6260 case ENOSPC:
6264 6261 case EPERM:
6265 6262 case EROFS:
6266 6263 case EACCES:
6267 6264 case EINVAL:
6268 6265 case EBUSY:
6269 6266 lcbdata->sc_err = r;
6270 6267 r = UU_WALK_ERROR;
6271 6268 goto deltemp;
6272 6269
6273 6270 default:
6274 6271 bad_error("lscf_import_instance_pgs", r);
6275 6272 }
6276 6273
6277 6274 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6278 6275 inst->sc_name);
6279 6276 if (r < 0)
6280 6277 bad_error("snprintf", errno);
6281 6278
6282 6279 ctx.sc_handle = lcbdata->sc_handle;
6283 6280 ctx.sc_parent = imp_tinst;
6284 6281 ctx.sc_service = 0;
6285 6282 ctx.sc_source_fmri = inst->sc_fmri;
6286 6283 ctx.sc_target_fmri = imp_str;
6287 6284 if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
6288 6285 UU_DEFAULT) != 0) {
6289 6286 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6290 6287 bad_error("uu_list_walk", uu_error());
6291 6288
6292 6289 switch (ctx.sc_err) {
6293 6290 case ECONNABORTED:
6294 6291 goto connaborted;
6295 6292
6296 6293 case ECANCELED:
6297 6294 warn(emsg_tdel, imp_tsname, inst->sc_name);
6298 6295 lcbdata->sc_err = EBUSY;
6299 6296 break;
6300 6297
6301 6298 case EEXIST:
6302 6299 warn(emsg_tchg, imp_tsname, inst->sc_name);
6303 6300 lcbdata->sc_err = EBUSY;
6304 6301 break;
6305 6302
6306 6303 default:
6307 6304 lcbdata->sc_err = ctx.sc_err;
6308 6305 }
6309 6306 r = UU_WALK_ERROR;
6310 6307 goto deltemp;
6311 6308 }
6312 6309
6313 6310 if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
6314 6311 inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
6315 6312 switch (scf_error()) {
6316 6313 case SCF_ERROR_CONNECTION_BROKEN:
6317 6314 goto connaborted;
6318 6315
6319 6316 case SCF_ERROR_NO_RESOURCES:
6320 6317 r = stash_scferror(lcbdata);
6321 6318 goto deltemp;
6322 6319
6323 6320 case SCF_ERROR_EXISTS:
6324 6321 warn(emsg_tchg, imp_tsname, inst->sc_name);
6325 6322 lcbdata->sc_err = EBUSY;
6326 6323 r = UU_WALK_ERROR;
6327 6324 goto deltemp;
6328 6325
6329 6326 case SCF_ERROR_PERMISSION_DENIED:
6330 6327 warn(gettext("Could not take \"%s\" snapshot of %s "
6331 6328 "(permission denied).\n"), snap_lastimport,
6332 6329 imp_str);
6333 6330 r = stash_scferror(lcbdata);
6334 6331 goto deltemp;
6335 6332
6336 6333 default:
6337 6334 scfwarn();
6338 6335 lcbdata->sc_err = -1;
6339 6336 r = UU_WALK_ERROR;
6340 6337 goto deltemp;
6341 6338
6342 6339 case SCF_ERROR_HANDLE_MISMATCH:
6343 6340 case SCF_ERROR_INVALID_ARGUMENT:
6344 6341 case SCF_ERROR_NOT_SET:
6345 6342 bad_error("_scf_snapshot_take_new_named", scf_error());
6346 6343 }
6347 6344 }
6348 6345
6349 6346 if (lcbdata->sc_flags & SCI_FRESH)
6350 6347 goto fresh;
6351 6348
6352 6349 if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
6353 6350 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6354 6351 imp_lisnap) != 0) {
6355 6352 switch (scf_error()) {
6356 6353 case SCF_ERROR_DELETED:
6357 6354 warn(emsg_del, inst->sc_parent->sc_fmri,
6358 6355 inst->sc_name);
6359 6356 lcbdata->sc_err = EBUSY;
6360 6357 r = UU_WALK_ERROR;
6361 6358 goto deltemp;
6362 6359
6363 6360 case SCF_ERROR_NOT_FOUND:
6364 6361 flags |= SCI_FORCE;
6365 6362 goto nosnap;
6366 6363
6367 6364 case SCF_ERROR_CONNECTION_BROKEN:
6368 6365 goto connaborted;
6369 6366
6370 6367 case SCF_ERROR_INVALID_ARGUMENT:
6371 6368 case SCF_ERROR_HANDLE_MISMATCH:
6372 6369 case SCF_ERROR_NOT_BOUND:
6373 6370 case SCF_ERROR_NOT_SET:
6374 6371 default:
6375 6372 bad_error("scf_instance_get_snapshot",
6376 6373 scf_error());
6377 6374 }
6378 6375 }
6379 6376
6380 6377 /* upgrade */
6381 6378
6382 6379 /*
6383 6380 * compare new properties with last-import properties
6384 6381 * upgrade current properties
6385 6382 */
6386 6383 /* clear sc_sceen for pgs */
6387 6384 if (uu_list_walk(inst->sc_pgroups, clear_int,
6388 6385 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
6389 6386 0)
6390 6387 bad_error("uu_list_walk", uu_error());
6391 6388
6392 6389 r = get_snaplevel(imp_lisnap, 0, imp_snpl);
6393 6390 switch (r) {
6394 6391 case 0:
6395 6392 break;
6396 6393
6397 6394 case ECONNABORTED:
6398 6395 goto connaborted;
6399 6396
6400 6397 case ECANCELED:
6401 6398 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6402 6399 lcbdata->sc_err = EBUSY;
6403 6400 r = UU_WALK_ERROR;
6404 6401 goto deltemp;
6405 6402
6406 6403 case ENOENT:
6407 6404 warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
6408 6405 lcbdata->sc_err = EBADF;
6409 6406 r = UU_WALK_ERROR;
6410 6407 goto deltemp;
6411 6408
6412 6409 default:
6413 6410 bad_error("get_snaplevel", r);
6414 6411 }
6415 6412
6416 6413 if (scf_instance_get_snapshot(imp_inst, snap_running,
6417 6414 imp_rsnap) != 0) {
6418 6415 switch (scf_error()) {
6419 6416 case SCF_ERROR_DELETED:
6420 6417 warn(emsg_del, inst->sc_parent->sc_fmri,
6421 6418 inst->sc_name);
6422 6419 lcbdata->sc_err = EBUSY;
6423 6420 r = UU_WALK_ERROR;
6424 6421 goto deltemp;
6425 6422
6426 6423 case SCF_ERROR_NOT_FOUND:
6427 6424 break;
6428 6425
6429 6426 case SCF_ERROR_CONNECTION_BROKEN:
6430 6427 goto connaborted;
6431 6428
6432 6429 case SCF_ERROR_INVALID_ARGUMENT:
6433 6430 case SCF_ERROR_HANDLE_MISMATCH:
6434 6431 case SCF_ERROR_NOT_BOUND:
6435 6432 case SCF_ERROR_NOT_SET:
6436 6433 default:
6437 6434 bad_error("scf_instance_get_snapshot",
6438 6435 scf_error());
6439 6436 }
6440 6437
6441 6438 running = NULL;
6442 6439 } else {
6443 6440 r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
6444 6441 switch (r) {
6445 6442 case 0:
6446 6443 running = imp_rsnpl;
6447 6444 break;
6448 6445
6449 6446 case ECONNABORTED:
6450 6447 goto connaborted;
6451 6448
6452 6449 case ECANCELED:
6453 6450 warn(emsg_del, inst->sc_parent->sc_fmri,
6454 6451 inst->sc_name);
6455 6452 lcbdata->sc_err = EBUSY;
6456 6453 r = UU_WALK_ERROR;
6457 6454 goto deltemp;
6458 6455
6459 6456 case ENOENT:
6460 6457 warn(emsg_badsnap, snap_running, inst->sc_fmri);
6461 6458 lcbdata->sc_err = EBADF;
6462 6459 r = UU_WALK_ERROR;
6463 6460 goto deltemp;
6464 6461
6465 6462 default:
6466 6463 bad_error("get_snaplevel", r);
6467 6464 }
6468 6465 }
6469 6466
6470 6467 r = upgrade_props(imp_inst, running, imp_snpl, inst);
6471 6468 switch (r) {
6472 6469 case 0:
6473 6470 break;
6474 6471
6475 6472 case ECANCELED:
6476 6473 case ENODEV:
6477 6474 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6478 6475 lcbdata->sc_err = EBUSY;
6479 6476 r = UU_WALK_ERROR;
6480 6477 goto deltemp;
6481 6478
6482 6479 case ECONNABORTED:
6483 6480 goto connaborted;
6484 6481
6485 6482 case ENOMEM:
6486 6483 case ENOSPC:
6487 6484 case EBADF:
6488 6485 case EBUSY:
6489 6486 case EINVAL:
6490 6487 case EPERM:
6491 6488 case EROFS:
6492 6489 case EACCES:
6493 6490 case EEXIST:
6494 6491 lcbdata->sc_err = r;
6495 6492 r = UU_WALK_ERROR;
6496 6493 goto deltemp;
6497 6494
6498 6495 default:
6499 6496 bad_error("upgrade_props", r);
6500 6497 }
6501 6498
6502 6499 inst->sc_import_state = IMPORT_PROP_DONE;
6503 6500 } else {
6504 6501 switch (scf_error()) {
6505 6502 case SCF_ERROR_CONNECTION_BROKEN:
6506 6503 goto connaborted;
6507 6504
6508 6505 case SCF_ERROR_NOT_FOUND:
6509 6506 break;
6510 6507
6511 6508 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
6512 6509 case SCF_ERROR_HANDLE_MISMATCH:
6513 6510 case SCF_ERROR_NOT_BOUND:
6514 6511 case SCF_ERROR_NOT_SET:
6515 6512 default:
6516 6513 bad_error("scf_service_get_instance", scf_error());
6517 6514 }
6518 6515
6519 6516 fresh:
6520 6517 /* create instance */
6521 6518 if (scf_service_add_instance(rsvc, inst->sc_name,
6522 6519 imp_inst) != 0) {
6523 6520 switch (scf_error()) {
6524 6521 case SCF_ERROR_CONNECTION_BROKEN:
6525 6522 goto connaborted;
6526 6523
6527 6524 case SCF_ERROR_NO_RESOURCES:
6528 6525 case SCF_ERROR_BACKEND_READONLY:
6529 6526 case SCF_ERROR_BACKEND_ACCESS:
6530 6527 r = stash_scferror(lcbdata);
6531 6528 goto deltemp;
6532 6529
6533 6530 case SCF_ERROR_EXISTS:
6534 6531 warn(gettext("%s changed unexpectedly "
6535 6532 "(instance \"%s\" added).\n"),
6536 6533 inst->sc_parent->sc_fmri, inst->sc_name);
6537 6534 lcbdata->sc_err = EBUSY;
6538 6535 r = UU_WALK_ERROR;
6539 6536 goto deltemp;
6540 6537
6541 6538 case SCF_ERROR_PERMISSION_DENIED:
6542 6539 warn(gettext("Could not create \"%s\" instance "
6543 6540 "in %s (permission denied).\n"),
6544 6541 inst->sc_name, inst->sc_parent->sc_fmri);
6545 6542 r = stash_scferror(lcbdata);
6546 6543 goto deltemp;
6547 6544
6548 6545 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
6549 6546 case SCF_ERROR_HANDLE_MISMATCH:
6550 6547 case SCF_ERROR_NOT_BOUND:
6551 6548 case SCF_ERROR_NOT_SET:
6552 6549 default:
6553 6550 bad_error("scf_service_add_instance",
6554 6551 scf_error());
6555 6552 }
6556 6553 }
6557 6554
6558 6555 nosnap:
6559 6556 /*
6560 6557 * Create a last-import snapshot to serve as an attachment
6561 6558 * point for the real one from the temporary instance. Since
6562 6559 * the contents is irrelevant, take it now, while the instance
6563 6560 * is empty, to minimize svc.configd's work.
6564 6561 */
6565 6562 if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6566 6563 imp_lisnap) != 0) {
6567 6564 switch (scf_error()) {
6568 6565 case SCF_ERROR_CONNECTION_BROKEN:
6569 6566 goto connaborted;
6570 6567
6571 6568 case SCF_ERROR_NO_RESOURCES:
6572 6569 r = stash_scferror(lcbdata);
6573 6570 goto deltemp;
6574 6571
6575 6572 case SCF_ERROR_EXISTS:
6576 6573 warn(gettext("%s changed unexpectedly "
6577 6574 "(snapshot \"%s\" added).\n"),
6578 6575 inst->sc_fmri, snap_lastimport);
6579 6576 lcbdata->sc_err = EBUSY;
6580 6577 r = UU_WALK_ERROR;
6581 6578 goto deltemp;
6582 6579
6583 6580 case SCF_ERROR_PERMISSION_DENIED:
6584 6581 warn(gettext("Could not take \"%s\" snapshot "
6585 6582 "of %s (permission denied).\n"),
6586 6583 snap_lastimport, inst->sc_fmri);
6587 6584 r = stash_scferror(lcbdata);
6588 6585 goto deltemp;
6589 6586
6590 6587 default:
6591 6588 scfwarn();
6592 6589 lcbdata->sc_err = -1;
6593 6590 r = UU_WALK_ERROR;
6594 6591 goto deltemp;
6595 6592
6596 6593 case SCF_ERROR_NOT_SET:
6597 6594 case SCF_ERROR_INTERNAL:
6598 6595 case SCF_ERROR_INVALID_ARGUMENT:
6599 6596 case SCF_ERROR_HANDLE_MISMATCH:
6600 6597 bad_error("_scf_snapshot_take_new",
6601 6598 scf_error());
6602 6599 }
6603 6600 }
6604 6601
6605 6602 if (li_only)
6606 6603 goto lionly;
6607 6604
6608 6605 inst->sc_import_state = IMPORT_PROP_BEGUN;
6609 6606
6610 6607 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6611 6608 flags);
6612 6609 switch (r) {
6613 6610 case 0:
6614 6611 break;
6615 6612
6616 6613 case ECONNABORTED:
6617 6614 goto connaborted;
6618 6615
6619 6616 case ECANCELED:
6620 6617 warn(gettext("%s changed unexpectedly "
6621 6618 "(instance \"%s\" deleted).\n"),
6622 6619 inst->sc_parent->sc_fmri, inst->sc_name);
6623 6620 lcbdata->sc_err = EBUSY;
6624 6621 r = UU_WALK_ERROR;
6625 6622 goto deltemp;
6626 6623
6627 6624 case EEXIST:
6628 6625 warn(gettext("%s changed unexpectedly "
6629 6626 "(property group added).\n"), inst->sc_fmri);
6630 6627 lcbdata->sc_err = EBUSY;
6631 6628 r = UU_WALK_ERROR;
6632 6629 goto deltemp;
6633 6630
6634 6631 default:
6635 6632 lcbdata->sc_err = r;
6636 6633 r = UU_WALK_ERROR;
6637 6634 goto deltemp;
6638 6635
6639 6636 case EINVAL: /* caught above */
6640 6637 bad_error("lscf_import_instance_pgs", r);
6641 6638 }
6642 6639
6643 6640 ctx.sc_parent = imp_inst;
6644 6641 ctx.sc_service = 0;
6645 6642 ctx.sc_trans = NULL;
6646 6643 ctx.sc_flags = 0;
6647 6644 if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6648 6645 &ctx, UU_DEFAULT) != 0) {
6649 6646 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6650 6647 bad_error("uu_list_walk", uu_error());
6651 6648
6652 6649 if (ctx.sc_err == ECONNABORTED)
6653 6650 goto connaborted;
6654 6651 lcbdata->sc_err = ctx.sc_err;
6655 6652 r = UU_WALK_ERROR;
6656 6653 goto deltemp;
6657 6654 }
6658 6655
6659 6656 inst->sc_import_state = IMPORT_PROP_DONE;
6660 6657
6661 6658 if (g_verbose)
6662 6659 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6663 6660 snap_initial, inst->sc_fmri);
6664 6661 r = take_snap(imp_inst, snap_initial, imp_snap);
6665 6662 switch (r) {
6666 6663 case 0:
6667 6664 break;
6668 6665
6669 6666 case ECONNABORTED:
6670 6667 goto connaborted;
6671 6668
6672 6669 case ENOSPC:
6673 6670 case -1:
6674 6671 lcbdata->sc_err = r;
6675 6672 r = UU_WALK_ERROR;
6676 6673 goto deltemp;
6677 6674
6678 6675 case ECANCELED:
6679 6676 warn(gettext("%s changed unexpectedly "
6680 6677 "(instance %s deleted).\n"),
6681 6678 inst->sc_parent->sc_fmri, inst->sc_name);
6682 6679 lcbdata->sc_err = r;
6683 6680 r = UU_WALK_ERROR;
6684 6681 goto deltemp;
6685 6682
6686 6683 case EPERM:
6687 6684 warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6688 6685 lcbdata->sc_err = r;
6689 6686 r = UU_WALK_ERROR;
6690 6687 goto deltemp;
6691 6688
6692 6689 default:
6693 6690 bad_error("take_snap", r);
6694 6691 }
6695 6692 }
6696 6693
6697 6694 lionly:
6698 6695 if (lcbdata->sc_flags & SCI_NOSNAP)
6699 6696 goto deltemp;
6700 6697
6701 6698 /* transfer snapshot from temporary instance */
6702 6699 if (g_verbose)
6703 6700 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6704 6701 snap_lastimport, inst->sc_fmri);
6705 6702 if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6706 6703 switch (scf_error()) {
6707 6704 case SCF_ERROR_CONNECTION_BROKEN:
6708 6705 goto connaborted;
6709 6706
6710 6707 case SCF_ERROR_NO_RESOURCES:
6711 6708 r = stash_scferror(lcbdata);
6712 6709 goto deltemp;
6713 6710
6714 6711 case SCF_ERROR_PERMISSION_DENIED:
6715 6712 warn(gettext("Could not take \"%s\" snapshot for %s "
6716 6713 "(permission denied).\n"), snap_lastimport,
6717 6714 inst->sc_fmri);
6718 6715 r = stash_scferror(lcbdata);
6719 6716 goto deltemp;
6720 6717
6721 6718 case SCF_ERROR_NOT_SET:
6722 6719 case SCF_ERROR_HANDLE_MISMATCH:
6723 6720 default:
6724 6721 bad_error("_scf_snapshot_attach", scf_error());
6725 6722 }
6726 6723 }
6727 6724
6728 6725 inst->sc_import_state = IMPORT_COMPLETE;
6729 6726
6730 6727 r = UU_WALK_NEXT;
6731 6728
6732 6729 deltemp:
6733 6730 /* delete temporary instance */
6734 6731 if (scf_instance_delete(imp_tinst) != 0) {
6735 6732 switch (scf_error()) {
6736 6733 case SCF_ERROR_DELETED:
6737 6734 break;
6738 6735
6739 6736 case SCF_ERROR_CONNECTION_BROKEN:
6740 6737 goto connaborted;
6741 6738
6742 6739 case SCF_ERROR_NOT_SET:
6743 6740 case SCF_ERROR_NOT_BOUND:
6744 6741 default:
6745 6742 bad_error("scf_instance_delete", scf_error());
6746 6743 }
6747 6744 }
6748 6745
6749 6746 return (r);
6750 6747
6751 6748 connaborted:
6752 6749 warn(gettext("Could not delete svc:/%s:%s "
6753 6750 "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6754 6751 lcbdata->sc_err = ECONNABORTED;
6755 6752 return (UU_WALK_ERROR);
6756 6753 }
6757 6754
6758 6755 /*
6759 6756 * When an instance is imported we end up telling configd about it. Once we tell
6760 6757 * configd about these changes, startd eventually notices. If this is a new
6761 6758 * instance, the manifest may not specify the SCF_PG_RESTARTER (restarter)
6762 6759 * property group. However, many of the other tools expect that this property
6763 6760 * group exists and has certain values.
6764 6761 *
6765 6762 * These values are added asynchronously by startd. We should not return from
6766 6763 * this routine until we can verify that the property group we need is there.
6767 6764 *
6768 6765 * Before we go ahead and verify this, we have to ask ourselves an important
6769 6766 * question: Is the early manifest service currently running? Because if it is
6770 6767 * running and it has invoked us, then the service will never get a restarter
6771 6768 * property because svc.startd is blocked on EMI finishing before it lets itself
6772 6769 * fully connect to svc.configd. Of course, this means that this race condition
6773 6770 * is in fact impossible to 100% eliminate.
6774 6771 *
6775 6772 * svc.startd makes sure that EMI only runs once and has succeeded by checking
6776 6773 * the state of the EMI instance. If it is online it bails out and makes sure
6777 6774 * that it doesn't run again. In this case, we're going to do something similar,
6778 6775 * only if the state is online, then we're going to actually verify. EMI always
6779 6776 * has to be present, but it can be explicitly disabled to reduce the amount of
6780 6777 * damage it can cause. If EMI has been disabled then we no longer have to worry
6781 6778 * about the implicit race condition and can go ahead and check things. If EMI
6782 6779 * is in some state that isn't online or disabled and isn't runinng, then we
6783 6780 * assume that things are rather bad and we're not going to get in your way,
6784 6781 * even if the rest of SMF does.
6785 6782 *
6786 6783 * Returns 0 on success or returns an errno.
6787 6784 */
6788 6785 #ifndef NATIVE_BUILD
6789 6786 static int
6790 6787 lscf_instance_verify(scf_scope_t *scope, entity_t *svc, entity_t *inst)
6791 6788 {
6792 6789 int ret, err;
6793 6790 struct timespec ts;
6794 6791 char *emi_state;
6795 6792
6796 6793 /*
6797 6794 * smf_get_state does not distinguish between its different failure
6798 6795 * modes: memory allocation failures, SMF internal failures, and a lack
6799 6796 * of EMI entirely because it's been removed. In these cases, we're
6800 6797 * going to be conservative and opt to say that if we don't know, better
6801 6798 * to not block import or falsely warn to the user.
6802 6799 */
6803 6800 if ((emi_state = smf_get_state(SCF_INSTANCE_EMI)) == NULL) {
6804 6801 return (0);
6805 6802 }
6806 6803
6807 6804 /*
6808 6805 * As per the block comment for this function check the state of EMI
6809 6806 */
6810 6807 if (strcmp(emi_state, SCF_STATE_STRING_ONLINE) != 0 &&
6811 6808 strcmp(emi_state, SCF_STATE_STRING_DISABLED) != 0) {
6812 6809 warn(gettext("Not validating instance %s:%s because EMI's "
6813 6810 "state is %s\n"), svc->sc_name, inst->sc_name, emi_state);
6814 6811 free(emi_state);
6815 6812 return (0);
6816 6813 }
6817 6814
6818 6815 free(emi_state);
6819 6816
6820 6817 /*
6821 6818 * First we have to get the property.
6822 6819 */
6823 6820 if ((ret = scf_scope_get_service(scope, svc->sc_name, imp_svc)) != 0) {
6824 6821 ret = scf_error();
6825 6822 warn(gettext("Failed to look up service: %s\n"), svc->sc_name);
6826 6823 return (ret);
6827 6824 }
6828 6825
6829 6826 /*
6830 6827 * We should always be able to get the instance. It should already
6831 6828 * exist because we just created it or got it. There probably is a
6832 6829 * slim chance that someone may have come in and deleted it though from
6833 6830 * under us.
6834 6831 */
6835 6832 if ((ret = scf_service_get_instance(imp_svc, inst->sc_name, imp_inst))
6836 6833 != 0) {
6837 6834 ret = scf_error();
6838 6835 warn(gettext("Failed to verify instance: %s\n"), inst->sc_name);
6839 6836 switch (ret) {
6840 6837 case SCF_ERROR_DELETED:
6841 6838 err = ENODEV;
6842 6839 break;
6843 6840 case SCF_ERROR_CONNECTION_BROKEN:
6844 6841 warn(gettext("Lost repository connection\n"));
6845 6842 err = ECONNABORTED;
6846 6843 break;
6847 6844 case SCF_ERROR_NOT_FOUND:
6848 6845 warn(gettext("Instance \"%s\" disappeared out from "
6849 6846 "under us.\n"), inst->sc_name);
6850 6847 err = ENOENT;
6851 6848 break;
6852 6849 default:
6853 6850 bad_error("scf_service_get_instance", ret);
6854 6851 }
6855 6852
6856 6853 return (err);
6857 6854 }
6858 6855
6859 6856 /*
6860 6857 * An astute observer may want to use _scf_wait_pg which would notify us
6861 6858 * of a property group change, unfortunately that does not work if the
6862 6859 * property group in question does not exist. So instead we have to
6863 6860 * manually poll and ask smf the best way to get to it.
6864 6861 */
6865 6862 while ((ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg))
6866 6863 != SCF_SUCCESS) {
6867 6864 ret = scf_error();
6868 6865 if (ret != SCF_ERROR_NOT_FOUND) {
6869 6866 warn(gettext("Failed to get restarter property "
6870 6867 "group for instance: %s\n"), inst->sc_name);
6871 6868 switch (ret) {
6872 6869 case SCF_ERROR_DELETED:
6873 6870 err = ENODEV;
6874 6871 break;
6875 6872 case SCF_ERROR_CONNECTION_BROKEN:
6876 6873 warn(gettext("Lost repository connection\n"));
6877 6874 err = ECONNABORTED;
6878 6875 break;
6879 6876 default:
6880 6877 bad_error("scf_service_get_instance", ret);
6881 6878 }
6882 6879
6883 6880 return (err);
6884 6881 }
6885 6882
6886 6883 ts.tv_sec = pg_timeout / NANOSEC;
6887 6884 ts.tv_nsec = pg_timeout % NANOSEC;
6888 6885
6889 6886 (void) nanosleep(&ts, NULL);
6890 6887 }
6891 6888
6892 6889 /*
6893 6890 * svcadm also expects that the SCF_PROPERTY_STATE property is present.
6894 6891 * So in addition to the property group being present, we need to wait
6895 6892 * for the property to be there in some form.
6896 6893 *
6897 6894 * Note that a property group is a frozen snapshot in time. To properly
6898 6895 * get beyond this, you have to refresh the property group each time.
6899 6896 */
6900 6897 while ((ret = scf_pg_get_property(imp_pg, SCF_PROPERTY_STATE,
6901 6898 imp_prop)) != 0) {
6902 6899
6903 6900 ret = scf_error();
6904 6901 if (ret != SCF_ERROR_NOT_FOUND) {
6905 6902 warn(gettext("Failed to get property %s from the "
6906 6903 "restarter property group of instance %s\n"),
6907 6904 SCF_PROPERTY_STATE, inst->sc_name);
6908 6905 switch (ret) {
6909 6906 case SCF_ERROR_CONNECTION_BROKEN:
6910 6907 warn(gettext("Lost repository connection\n"));
6911 6908 err = ECONNABORTED;
6912 6909 break;
6913 6910 case SCF_ERROR_DELETED:
6914 6911 err = ENODEV;
6915 6912 break;
6916 6913 default:
6917 6914 bad_error("scf_pg_get_property", ret);
6918 6915 }
6919 6916
6920 6917 return (err);
6921 6918 }
6922 6919
6923 6920 ts.tv_sec = pg_timeout / NANOSEC;
6924 6921 ts.tv_nsec = pg_timeout % NANOSEC;
6925 6922
6926 6923 (void) nanosleep(&ts, NULL);
6927 6924
6928 6925 ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg);
6929 6926 if (ret != SCF_SUCCESS) {
6930 6927 warn(gettext("Failed to get restarter property "
6931 6928 "group for instance: %s\n"), inst->sc_name);
6932 6929 switch (ret) {
6933 6930 case SCF_ERROR_DELETED:
6934 6931 err = ENODEV;
6935 6932 break;
6936 6933 case SCF_ERROR_CONNECTION_BROKEN:
6937 6934 warn(gettext("Lost repository connection\n"));
6938 6935 err = ECONNABORTED;
6939 6936 break;
6940 6937 default:
6941 6938 bad_error("scf_service_get_instance", ret);
6942 6939 }
6943 6940
6944 6941 return (err);
6945 6942 }
6946 6943 }
6947 6944
6948 6945 /*
6949 6946 * We don't have to free the property groups or other values that we got
6950 6947 * because we stored them in global variables that are allocated and
6951 6948 * freed by the routines that call into these functions. Unless of
6952 6949 * course the rest of the code here that we are basing this on is
6953 6950 * mistaken.
6954 6951 */
6955 6952 return (0);
6956 6953 }
6957 6954 #endif
6958 6955
6959 6956 /*
6960 6957 * If the service is missing, create it, import its properties, and import the
6961 6958 * instances. Since the service is brand new, it should be empty, and if we
6962 6959 * run into any existing entities (SCF_ERROR_EXISTS), abort.
6963 6960 *
6964 6961 * If the service exists, we want to upgrade its properties and import the
6965 6962 * instances. Upgrade requires a last-import snapshot, though, which are
6966 6963 * children of instances, so first we'll have to go through the instances
6967 6964 * looking for a last-import snapshot. If we don't find one then we'll just
6968 6965 * override-import the service properties (but don't delete existing
6969 6966 * properties: another service might have declared us as a dependent). Before
6970 6967 * we change anything, though, we want to take the previous snapshots. We
6971 6968 * also give lscf_instance_import() a leg up on taking last-import snapshots
6972 6969 * by importing the manifest's service properties into a temporary service.
6973 6970 *
6974 6971 * On success, returns UU_WALK_NEXT. On failure, returns UU_WALK_ERROR and
6975 6972 * sets lcbdata->sc_err to
6976 6973 * ECONNABORTED - repository connection broken
6977 6974 * ENOMEM - out of memory
6978 6975 * ENOSPC - svc.configd is out of resources
6979 6976 * EPERM - couldn't create temporary service (error printed)
6980 6977 * - couldn't import into temp service (error printed)
6981 6978 * - couldn't create service (error printed)
6982 6979 * - couldn't import dependent (error printed)
6983 6980 * - couldn't take snapshot (error printed)
6984 6981 * - couldn't create instance (error printed)
6985 6982 * - couldn't create, modify, or delete pg (error printed)
6986 6983 * - couldn't create, modify, or delete dependent (error printed)
6987 6984 * - couldn't import instance (error printed)
6988 6985 * EROFS - couldn't create temporary service (repository read-only)
6989 6986 * - couldn't import into temporary service (repository read-only)
6990 6987 * - couldn't create service (repository read-only)
6991 6988 * - couldn't import dependent (repository read-only)
6992 6989 * - couldn't create instance (repository read-only)
6993 6990 * - couldn't create, modify, or delete pg or dependent
6994 6991 * - couldn't import instance (repository read-only)
6995 6992 * EACCES - couldn't create temporary service (backend access denied)
6996 6993 * - couldn't import into temporary service (backend access denied)
6997 6994 * - couldn't create service (backend access denied)
6998 6995 * - couldn't import dependent (backend access denied)
6999 6996 * - couldn't create instance (backend access denied)
7000 6997 * - couldn't create, modify, or delete pg or dependent
7001 6998 * - couldn't import instance (backend access denied)
7002 6999 * EINVAL - service name is invalid (error printed)
7003 7000 * - service name is too long (error printed)
7004 7001 * - s has invalid pgroup (error printed)
7005 7002 * - s has invalid dependent (error printed)
7006 7003 * - instance name is invalid (error printed)
7007 7004 * - instance entity_t is invalid (error printed)
7008 7005 * EEXIST - couldn't create temporary service (already exists) (error printed)
7009 7006 * - couldn't import dependent (dependency pg already exists) (printed)
7010 7007 * - dependency collision in dependent service (error printed)
7011 7008 * EBUSY - temporary service deleted (error printed)
7012 7009 * - property group added to temporary service (error printed)
7013 7010 * - new property group changed or was deleted (error printed)
7014 7011 * - service was added unexpectedly (error printed)
7015 7012 * - service was deleted unexpectedly (error printed)
7016 7013 * - property group added to new service (error printed)
7017 7014 * - instance added unexpectedly (error printed)
7018 7015 * - instance deleted unexpectedly (error printed)
7019 7016 * - dependent service deleted unexpectedly (error printed)
7020 7017 * - pg was added, changed, or deleted (error printed)
7021 7018 * - dependent pg changed (error printed)
7022 7019 * - temporary instance added, changed, or deleted (error printed)
7023 7020 * EBADF - a last-import snapshot is corrupt (error printed)
7024 7021 * - the service is corrupt (error printed)
7025 7022 * - a dependent is corrupt (error printed)
7026 7023 * - an instance is corrupt (error printed)
7027 7024 * - an instance has a corrupt last-import snapshot (error printed)
7028 7025 * - dependent target has a corrupt snapshot (error printed)
7029 7026 * -1 - unknown libscf error (error printed)
7030 7027 */
7031 7028 static int
7032 7029 lscf_service_import(void *v, void *pvt)
7033 7030 {
7034 7031 entity_t *s = v;
7035 7032 scf_callback_t cbdata;
7036 7033 scf_callback_t *lcbdata = pvt;
7037 7034 scf_scope_t *scope = lcbdata->sc_parent;
7038 7035 entity_t *inst, linst;
7039 7036 int r;
7040 7037 int fresh = 0;
7041 7038 scf_snaplevel_t *running;
7042 7039 int have_ge = 0;
7043 7040 boolean_t retried = B_FALSE;
7044 7041
7045 7042 const char * const ts_deleted = gettext("Temporary service svc:/%s "
7046 7043 "was deleted unexpectedly.\n");
7047 7044 const char * const ts_pg_added = gettext("Temporary service svc:/%s "
7048 7045 "changed unexpectedly (property group added).\n");
7049 7046 const char * const s_deleted =
7050 7047 gettext("%s was deleted unexpectedly.\n");
7051 7048 const char * const i_deleted =
7052 7049 gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
7053 7050 const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
7054 7051 "is corrupt (missing service snaplevel).\n");
7055 7052 const char * const s_mfile_upd =
7056 7053 gettext("Unable to update the manifest file connection "
7057 7054 "for %s\n");
7058 7055
7059 7056 li_only = 0;
7060 7057 /* Validate the service name */
7061 7058 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7062 7059 switch (scf_error()) {
7063 7060 case SCF_ERROR_CONNECTION_BROKEN:
7064 7061 return (stash_scferror(lcbdata));
7065 7062
7066 7063 case SCF_ERROR_INVALID_ARGUMENT:
7067 7064 warn(gettext("\"%s\" is an invalid service name. "
7068 7065 "Cannot import.\n"), s->sc_name);
7069 7066 return (stash_scferror(lcbdata));
7070 7067
7071 7068 case SCF_ERROR_NOT_FOUND:
7072 7069 break;
7073 7070
7074 7071 case SCF_ERROR_HANDLE_MISMATCH:
7075 7072 case SCF_ERROR_NOT_BOUND:
7076 7073 case SCF_ERROR_NOT_SET:
7077 7074 default:
7078 7075 bad_error("scf_scope_get_service", scf_error());
7079 7076 }
7080 7077 }
7081 7078
7082 7079 /* create temporary service */
7083 7080 /*
7084 7081 * the size of the buffer was reduced to max_scf_name_len to prevent
7085 7082 * hitting bug 6681151. After the bug fix, the size of the buffer
7086 7083 * should be restored to its original value (max_scf_name_len +1)
7087 7084 */
7088 7085 r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
7089 7086 if (r < 0)
7090 7087 bad_error("snprintf", errno);
7091 7088 if (r > max_scf_name_len) {
7092 7089 warn(gettext(
7093 7090 "Service name \"%s\" is too long. Cannot import.\n"),
7094 7091 s->sc_name);
7095 7092 lcbdata->sc_err = EINVAL;
7096 7093 return (UU_WALK_ERROR);
7097 7094 }
7098 7095
7099 7096 retry:
7100 7097 if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
7101 7098 switch (scf_error()) {
7102 7099 case SCF_ERROR_CONNECTION_BROKEN:
7103 7100 case SCF_ERROR_NO_RESOURCES:
7104 7101 case SCF_ERROR_BACKEND_READONLY:
7105 7102 case SCF_ERROR_BACKEND_ACCESS:
7106 7103 return (stash_scferror(lcbdata));
7107 7104
7108 7105 case SCF_ERROR_EXISTS:
7109 7106 if (!retried) {
7110 7107 lscf_delete(imp_tsname, 0);
7111 7108 retried = B_TRUE;
7112 7109 goto retry;
7113 7110 }
7114 7111 warn(gettext(
7115 7112 "Temporary service \"%s\" must be deleted before "
7116 7113 "this manifest can be imported.\n"), imp_tsname);
7117 7114 return (stash_scferror(lcbdata));
7118 7115
7119 7116 case SCF_ERROR_PERMISSION_DENIED:
7120 7117 warn(gettext("Could not create temporary service "
7121 7118 "\"%s\" (permission denied).\n"), imp_tsname);
7122 7119 return (stash_scferror(lcbdata));
7123 7120
7124 7121 case SCF_ERROR_INVALID_ARGUMENT:
7125 7122 case SCF_ERROR_HANDLE_MISMATCH:
7126 7123 case SCF_ERROR_NOT_BOUND:
7127 7124 case SCF_ERROR_NOT_SET:
7128 7125 default:
7129 7126 bad_error("scf_scope_add_service", scf_error());
7130 7127 }
7131 7128 }
7132 7129
7133 7130 r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
7134 7131 if (r < 0)
7135 7132 bad_error("snprintf", errno);
7136 7133
7137 7134 cbdata.sc_handle = lcbdata->sc_handle;
7138 7135 cbdata.sc_parent = imp_tsvc;
7139 7136 cbdata.sc_service = 1;
7140 7137 cbdata.sc_source_fmri = s->sc_fmri;
7141 7138 cbdata.sc_target_fmri = imp_str;
7142 7139 cbdata.sc_flags = 0;
7143 7140
7144 7141 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
7145 7142 UU_DEFAULT) != 0) {
7146 7143 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7147 7144 bad_error("uu_list_walk", uu_error());
7148 7145
7149 7146 lcbdata->sc_err = cbdata.sc_err;
7150 7147 switch (cbdata.sc_err) {
7151 7148 case ECONNABORTED:
7152 7149 goto connaborted;
7153 7150
7154 7151 case ECANCELED:
7155 7152 warn(ts_deleted, imp_tsname);
7156 7153 lcbdata->sc_err = EBUSY;
7157 7154 return (UU_WALK_ERROR);
7158 7155
7159 7156 case EEXIST:
7160 7157 warn(ts_pg_added, imp_tsname);
7161 7158 lcbdata->sc_err = EBUSY;
7162 7159 return (UU_WALK_ERROR);
7163 7160 }
7164 7161
7165 7162 r = UU_WALK_ERROR;
7166 7163 goto deltemp;
7167 7164 }
7168 7165
7169 7166 if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
7170 7167 UU_DEFAULT) != 0) {
7171 7168 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7172 7169 bad_error("uu_list_walk", uu_error());
7173 7170
7174 7171 lcbdata->sc_err = cbdata.sc_err;
7175 7172 switch (cbdata.sc_err) {
7176 7173 case ECONNABORTED:
7177 7174 goto connaborted;
7178 7175
7179 7176 case ECANCELED:
7180 7177 warn(ts_deleted, imp_tsname);
7181 7178 lcbdata->sc_err = EBUSY;
7182 7179 return (UU_WALK_ERROR);
7183 7180
7184 7181 case EEXIST:
7185 7182 warn(ts_pg_added, imp_tsname);
7186 7183 lcbdata->sc_err = EBUSY;
7187 7184 return (UU_WALK_ERROR);
7188 7185 }
7189 7186
7190 7187 r = UU_WALK_ERROR;
7191 7188 goto deltemp;
7192 7189 }
7193 7190
7194 7191 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7195 7192 switch (scf_error()) {
7196 7193 case SCF_ERROR_NOT_FOUND:
7197 7194 break;
7198 7195
7199 7196 case SCF_ERROR_CONNECTION_BROKEN:
7200 7197 goto connaborted;
7201 7198
7202 7199 case SCF_ERROR_INVALID_ARGUMENT:
7203 7200 case SCF_ERROR_HANDLE_MISMATCH:
7204 7201 case SCF_ERROR_NOT_BOUND:
7205 7202 case SCF_ERROR_NOT_SET:
7206 7203 default:
7207 7204 bad_error("scf_scope_get_service", scf_error());
7208 7205 }
7209 7206
7210 7207 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
7211 7208 switch (scf_error()) {
7212 7209 case SCF_ERROR_CONNECTION_BROKEN:
7213 7210 goto connaborted;
7214 7211
7215 7212 case SCF_ERROR_NO_RESOURCES:
7216 7213 case SCF_ERROR_BACKEND_READONLY:
7217 7214 case SCF_ERROR_BACKEND_ACCESS:
7218 7215 r = stash_scferror(lcbdata);
7219 7216 goto deltemp;
7220 7217
7221 7218 case SCF_ERROR_EXISTS:
7222 7219 warn(gettext("Scope \"%s\" changed unexpectedly"
7223 7220 " (service \"%s\" added).\n"),
7224 7221 SCF_SCOPE_LOCAL, s->sc_name);
7225 7222 lcbdata->sc_err = EBUSY;
7226 7223 goto deltemp;
7227 7224
7228 7225 case SCF_ERROR_PERMISSION_DENIED:
7229 7226 warn(gettext("Could not create service \"%s\" "
7230 7227 "(permission denied).\n"), s->sc_name);
7231 7228 goto deltemp;
7232 7229
7233 7230 case SCF_ERROR_INVALID_ARGUMENT:
7234 7231 case SCF_ERROR_HANDLE_MISMATCH:
7235 7232 case SCF_ERROR_NOT_BOUND:
7236 7233 case SCF_ERROR_NOT_SET:
7237 7234 default:
7238 7235 bad_error("scf_scope_add_service", scf_error());
7239 7236 }
7240 7237 }
7241 7238
7242 7239 s->sc_import_state = IMPORT_PROP_BEGUN;
7243 7240
7244 7241 /* import service properties */
7245 7242 cbdata.sc_handle = lcbdata->sc_handle;
7246 7243 cbdata.sc_parent = imp_svc;
7247 7244 cbdata.sc_service = 1;
7248 7245 cbdata.sc_flags = lcbdata->sc_flags;
7249 7246 cbdata.sc_source_fmri = s->sc_fmri;
7250 7247 cbdata.sc_target_fmri = s->sc_fmri;
7251 7248
7252 7249 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7253 7250 &cbdata, UU_DEFAULT) != 0) {
7254 7251 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7255 7252 bad_error("uu_list_walk", uu_error());
7256 7253
7257 7254 lcbdata->sc_err = cbdata.sc_err;
7258 7255 switch (cbdata.sc_err) {
7259 7256 case ECONNABORTED:
7260 7257 goto connaborted;
7261 7258
7262 7259 case ECANCELED:
7263 7260 warn(s_deleted, s->sc_fmri);
7264 7261 lcbdata->sc_err = EBUSY;
7265 7262 return (UU_WALK_ERROR);
7266 7263
7267 7264 case EEXIST:
7268 7265 warn(gettext("%s changed unexpectedly "
7269 7266 "(property group added).\n"), s->sc_fmri);
7270 7267 lcbdata->sc_err = EBUSY;
7271 7268 return (UU_WALK_ERROR);
7272 7269
7273 7270 case EINVAL:
7274 7271 /* caught above */
7275 7272 bad_error("entity_pgroup_import",
7276 7273 cbdata.sc_err);
7277 7274 }
7278 7275
7279 7276 r = UU_WALK_ERROR;
7280 7277 goto deltemp;
7281 7278 }
7282 7279
7283 7280 cbdata.sc_trans = NULL;
7284 7281 cbdata.sc_flags = 0;
7285 7282 if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
7286 7283 &cbdata, UU_DEFAULT) != 0) {
7287 7284 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7288 7285 bad_error("uu_list_walk", uu_error());
7289 7286
7290 7287 lcbdata->sc_err = cbdata.sc_err;
7291 7288 if (cbdata.sc_err == ECONNABORTED)
7292 7289 goto connaborted;
7293 7290 r = UU_WALK_ERROR;
7294 7291 goto deltemp;
7295 7292 }
7296 7293
7297 7294 s->sc_import_state = IMPORT_PROP_DONE;
7298 7295
7299 7296 /*
7300 7297 * This is a new service, so we can't take previous snapshots
7301 7298 * or upgrade service properties.
7302 7299 */
7303 7300 fresh = 1;
7304 7301 goto instances;
7305 7302 }
7306 7303
7307 7304 /* Clear sc_seen for the instances. */
7308 7305 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
7309 7306 (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
7310 7307 bad_error("uu_list_walk", uu_error());
7311 7308
7312 7309 /*
7313 7310 * Take previous snapshots for all instances. Even for ones not
7314 7311 * mentioned in the bundle, since we might change their service
7315 7312 * properties.
7316 7313 */
7317 7314 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7318 7315 switch (scf_error()) {
7319 7316 case SCF_ERROR_CONNECTION_BROKEN:
7320 7317 goto connaborted;
7321 7318
7322 7319 case SCF_ERROR_DELETED:
7323 7320 warn(s_deleted, s->sc_fmri);
7324 7321 lcbdata->sc_err = EBUSY;
7325 7322 r = UU_WALK_ERROR;
7326 7323 goto deltemp;
7327 7324
7328 7325 case SCF_ERROR_HANDLE_MISMATCH:
7329 7326 case SCF_ERROR_NOT_BOUND:
7330 7327 case SCF_ERROR_NOT_SET:
7331 7328 default:
7332 7329 bad_error("scf_iter_service_instances", scf_error());
7333 7330 }
7334 7331 }
7335 7332
7336 7333 for (;;) {
7337 7334 r = scf_iter_next_instance(imp_iter, imp_inst);
7338 7335 if (r == 0)
7339 7336 break;
7340 7337 if (r != 1) {
7341 7338 switch (scf_error()) {
7342 7339 case SCF_ERROR_DELETED:
7343 7340 warn(s_deleted, s->sc_fmri);
7344 7341 lcbdata->sc_err = EBUSY;
7345 7342 r = UU_WALK_ERROR;
7346 7343 goto deltemp;
7347 7344
7348 7345 case SCF_ERROR_CONNECTION_BROKEN:
7349 7346 goto connaborted;
7350 7347
7351 7348 case SCF_ERROR_NOT_BOUND:
7352 7349 case SCF_ERROR_HANDLE_MISMATCH:
7353 7350 case SCF_ERROR_INVALID_ARGUMENT:
7354 7351 case SCF_ERROR_NOT_SET:
7355 7352 default:
7356 7353 bad_error("scf_iter_next_instance",
7357 7354 scf_error());
7358 7355 }
7359 7356 }
7360 7357
7361 7358 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
7362 7359 switch (scf_error()) {
7363 7360 case SCF_ERROR_DELETED:
7364 7361 continue;
7365 7362
7366 7363 case SCF_ERROR_CONNECTION_BROKEN:
7367 7364 goto connaborted;
7368 7365
7369 7366 case SCF_ERROR_NOT_SET:
7370 7367 case SCF_ERROR_NOT_BOUND:
7371 7368 default:
7372 7369 bad_error("scf_instance_get_name", scf_error());
7373 7370 }
7374 7371 }
7375 7372
7376 7373 if (g_verbose)
7377 7374 warn(gettext(
7378 7375 "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
7379 7376 snap_previous, s->sc_name, imp_str);
7380 7377
7381 7378 r = take_snap(imp_inst, snap_previous, imp_snap);
7382 7379 switch (r) {
7383 7380 case 0:
7384 7381 break;
7385 7382
7386 7383 case ECANCELED:
7387 7384 continue;
7388 7385
7389 7386 case ECONNABORTED:
7390 7387 goto connaborted;
7391 7388
7392 7389 case EPERM:
7393 7390 warn(gettext("Could not take \"%s\" snapshot of "
7394 7391 "svc:/%s:%s (permission denied).\n"),
7395 7392 snap_previous, s->sc_name, imp_str);
7396 7393 lcbdata->sc_err = r;
7397 7394 return (UU_WALK_ERROR);
7398 7395
7399 7396 case ENOSPC:
7400 7397 case -1:
7401 7398 lcbdata->sc_err = r;
7402 7399 r = UU_WALK_ERROR;
7403 7400 goto deltemp;
7404 7401
7405 7402 default:
7406 7403 bad_error("take_snap", r);
7407 7404 }
7408 7405
7409 7406 linst.sc_name = imp_str;
7410 7407 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
7411 7408 &linst, NULL, NULL);
7412 7409 if (inst != NULL) {
7413 7410 inst->sc_import_state = IMPORT_PREVIOUS;
7414 7411 inst->sc_seen = 1;
7415 7412 }
7416 7413 }
7417 7414
7418 7415 /*
7419 7416 * Create the new instances and take previous snapshots of
7420 7417 * them. This is not necessary, but it maximizes data preservation.
7421 7418 */
7422 7419 for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
7423 7420 inst != NULL;
7424 7421 inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
7425 7422 inst)) {
7426 7423 if (inst->sc_seen)
7427 7424 continue;
7428 7425
7429 7426 if (scf_service_add_instance(imp_svc, inst->sc_name,
7430 7427 imp_inst) != 0) {
7431 7428 switch (scf_error()) {
7432 7429 case SCF_ERROR_CONNECTION_BROKEN:
7433 7430 goto connaborted;
7434 7431
7435 7432 case SCF_ERROR_BACKEND_READONLY:
7436 7433 case SCF_ERROR_BACKEND_ACCESS:
7437 7434 case SCF_ERROR_NO_RESOURCES:
7438 7435 r = stash_scferror(lcbdata);
7439 7436 goto deltemp;
7440 7437
7441 7438 case SCF_ERROR_EXISTS:
7442 7439 warn(gettext("%s changed unexpectedly "
7443 7440 "(instance \"%s\" added).\n"), s->sc_fmri,
7444 7441 inst->sc_name);
7445 7442 lcbdata->sc_err = EBUSY;
7446 7443 r = UU_WALK_ERROR;
7447 7444 goto deltemp;
7448 7445
7449 7446 case SCF_ERROR_INVALID_ARGUMENT:
7450 7447 warn(gettext("Service \"%s\" has instance with "
7451 7448 "invalid name \"%s\".\n"), s->sc_name,
7452 7449 inst->sc_name);
7453 7450 r = stash_scferror(lcbdata);
7454 7451 goto deltemp;
7455 7452
7456 7453 case SCF_ERROR_PERMISSION_DENIED:
7457 7454 warn(gettext("Could not create instance \"%s\" "
7458 7455 "in %s (permission denied).\n"),
7459 7456 inst->sc_name, s->sc_fmri);
7460 7457 r = stash_scferror(lcbdata);
7461 7458 goto deltemp;
7462 7459
7463 7460 case SCF_ERROR_HANDLE_MISMATCH:
7464 7461 case SCF_ERROR_NOT_BOUND:
7465 7462 case SCF_ERROR_NOT_SET:
7466 7463 default:
7467 7464 bad_error("scf_service_add_instance",
7468 7465 scf_error());
7469 7466 }
7470 7467 }
7471 7468
7472 7469 if (g_verbose)
7473 7470 warn(gettext("Taking \"%s\" snapshot for "
7474 7471 "new service %s.\n"), snap_previous, inst->sc_fmri);
7475 7472 r = take_snap(imp_inst, snap_previous, imp_snap);
7476 7473 switch (r) {
7477 7474 case 0:
7478 7475 break;
7479 7476
7480 7477 case ECANCELED:
7481 7478 warn(i_deleted, s->sc_fmri, inst->sc_name);
7482 7479 lcbdata->sc_err = EBUSY;
7483 7480 r = UU_WALK_ERROR;
7484 7481 goto deltemp;
7485 7482
7486 7483 case ECONNABORTED:
7487 7484 goto connaborted;
7488 7485
7489 7486 case EPERM:
7490 7487 warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
7491 7488 lcbdata->sc_err = r;
7492 7489 r = UU_WALK_ERROR;
7493 7490 goto deltemp;
7494 7491
7495 7492 case ENOSPC:
7496 7493 case -1:
7497 7494 r = UU_WALK_ERROR;
7498 7495 goto deltemp;
7499 7496
7500 7497 default:
7501 7498 bad_error("take_snap", r);
7502 7499 }
7503 7500 }
7504 7501
7505 7502 s->sc_import_state = IMPORT_PREVIOUS;
7506 7503
7507 7504 /*
7508 7505 * Upgrade service properties, if we can find a last-import snapshot.
7509 7506 * Any will do because we don't support different service properties
7510 7507 * in different manifests, so all snaplevels of the service in all of
7511 7508 * the last-import snapshots of the instances should be the same.
7512 7509 */
7513 7510 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7514 7511 switch (scf_error()) {
7515 7512 case SCF_ERROR_CONNECTION_BROKEN:
7516 7513 goto connaborted;
7517 7514
7518 7515 case SCF_ERROR_DELETED:
7519 7516 warn(s_deleted, s->sc_fmri);
7520 7517 lcbdata->sc_err = EBUSY;
7521 7518 r = UU_WALK_ERROR;
7522 7519 goto deltemp;
7523 7520
7524 7521 case SCF_ERROR_HANDLE_MISMATCH:
7525 7522 case SCF_ERROR_NOT_BOUND:
7526 7523 case SCF_ERROR_NOT_SET:
7527 7524 default:
7528 7525 bad_error("scf_iter_service_instances", scf_error());
7529 7526 }
7530 7527 }
7531 7528
7532 7529 for (;;) {
7533 7530 r = scf_iter_next_instance(imp_iter, imp_inst);
7534 7531 if (r == -1) {
7535 7532 switch (scf_error()) {
7536 7533 case SCF_ERROR_DELETED:
7537 7534 warn(s_deleted, s->sc_fmri);
7538 7535 lcbdata->sc_err = EBUSY;
7539 7536 r = UU_WALK_ERROR;
7540 7537 goto deltemp;
7541 7538
7542 7539 case SCF_ERROR_CONNECTION_BROKEN:
7543 7540 goto connaborted;
7544 7541
7545 7542 case SCF_ERROR_NOT_BOUND:
7546 7543 case SCF_ERROR_HANDLE_MISMATCH:
7547 7544 case SCF_ERROR_INVALID_ARGUMENT:
7548 7545 case SCF_ERROR_NOT_SET:
7549 7546 default:
7550 7547 bad_error("scf_iter_next_instance",
7551 7548 scf_error());
7552 7549 }
7553 7550 }
7554 7551
7555 7552 if (r == 0) {
7556 7553 /*
7557 7554 * Didn't find any last-import snapshots. Override-
7558 7555 * import the properties. Unless one of the instances
7559 7556 * has a general/enabled property, in which case we're
7560 7557 * probably running a last-import-capable svccfg for
7561 7558 * the first time, and we should only take the
7562 7559 * last-import snapshot.
7563 7560 */
7564 7561 if (have_ge) {
7565 7562 pgroup_t *mfpg;
7566 7563 scf_callback_t mfcbdata;
7567 7564
7568 7565 li_only = 1;
7569 7566 no_refresh = 1;
7570 7567 /*
7571 7568 * Need to go ahead and import the manifestfiles
7572 7569 * pg if it exists. If the last-import snapshot
7573 7570 * upgrade code is ever removed this code can
7574 7571 * be removed as well.
7575 7572 */
7576 7573 mfpg = internal_pgroup_find(s,
7577 7574 SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
7578 7575
7579 7576 if (mfpg) {
7580 7577 mfcbdata.sc_handle = g_hndl;
7581 7578 mfcbdata.sc_parent = imp_svc;
7582 7579 mfcbdata.sc_service = 1;
7583 7580 mfcbdata.sc_flags = SCI_FORCE;
7584 7581 mfcbdata.sc_source_fmri = s->sc_fmri;
7585 7582 mfcbdata.sc_target_fmri = s->sc_fmri;
7586 7583 if (entity_pgroup_import(mfpg,
7587 7584 &mfcbdata) != UU_WALK_NEXT) {
7588 7585 warn(s_mfile_upd, s->sc_fmri);
7589 7586 r = UU_WALK_ERROR;
7590 7587 goto deltemp;
7591 7588 }
7592 7589 }
7593 7590 break;
7594 7591 }
7595 7592
7596 7593 s->sc_import_state = IMPORT_PROP_BEGUN;
7597 7594
7598 7595 cbdata.sc_handle = g_hndl;
7599 7596 cbdata.sc_parent = imp_svc;
7600 7597 cbdata.sc_service = 1;
7601 7598 cbdata.sc_flags = SCI_FORCE;
7602 7599 cbdata.sc_source_fmri = s->sc_fmri;
7603 7600 cbdata.sc_target_fmri = s->sc_fmri;
7604 7601 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7605 7602 &cbdata, UU_DEFAULT) != 0) {
7606 7603 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7607 7604 bad_error("uu_list_walk", uu_error());
7608 7605 lcbdata->sc_err = cbdata.sc_err;
7609 7606 switch (cbdata.sc_err) {
7610 7607 case ECONNABORTED:
7611 7608 goto connaborted;
7612 7609
7613 7610 case ECANCELED:
7614 7611 warn(s_deleted, s->sc_fmri);
7615 7612 lcbdata->sc_err = EBUSY;
7616 7613 break;
7617 7614
7618 7615 case EINVAL: /* caught above */
7619 7616 case EEXIST:
7620 7617 bad_error("entity_pgroup_import",
7621 7618 cbdata.sc_err);
7622 7619 }
7623 7620
7624 7621 r = UU_WALK_ERROR;
7625 7622 goto deltemp;
7626 7623 }
7627 7624
7628 7625 cbdata.sc_trans = NULL;
7629 7626 cbdata.sc_flags = 0;
7630 7627 if (uu_list_walk(s->sc_dependents,
7631 7628 lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
7632 7629 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7633 7630 bad_error("uu_list_walk", uu_error());
7634 7631 lcbdata->sc_err = cbdata.sc_err;
7635 7632 if (cbdata.sc_err == ECONNABORTED)
7636 7633 goto connaborted;
7637 7634 r = UU_WALK_ERROR;
7638 7635 goto deltemp;
7639 7636 }
7640 7637 break;
7641 7638 }
7642 7639
7643 7640 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
7644 7641 imp_snap) != 0) {
7645 7642 switch (scf_error()) {
7646 7643 case SCF_ERROR_DELETED:
7647 7644 continue;
7648 7645
7649 7646 case SCF_ERROR_NOT_FOUND:
7650 7647 break;
7651 7648
7652 7649 case SCF_ERROR_CONNECTION_BROKEN:
7653 7650 goto connaborted;
7654 7651
7655 7652 case SCF_ERROR_HANDLE_MISMATCH:
7656 7653 case SCF_ERROR_NOT_BOUND:
7657 7654 case SCF_ERROR_INVALID_ARGUMENT:
7658 7655 case SCF_ERROR_NOT_SET:
7659 7656 default:
7660 7657 bad_error("scf_instance_get_snapshot",
7661 7658 scf_error());
7662 7659 }
7663 7660
7664 7661 if (have_ge)
7665 7662 continue;
7666 7663
7667 7664 /*
7668 7665 * Check for a general/enabled property. This is how
7669 7666 * we tell whether to import if there turn out to be
7670 7667 * no last-import snapshots.
7671 7668 */
7672 7669 if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
7673 7670 imp_pg) == 0) {
7674 7671 if (scf_pg_get_property(imp_pg,
7675 7672 SCF_PROPERTY_ENABLED, imp_prop) == 0) {
7676 7673 have_ge = 1;
7677 7674 } else {
7678 7675 switch (scf_error()) {
7679 7676 case SCF_ERROR_DELETED:
7680 7677 case SCF_ERROR_NOT_FOUND:
7681 7678 continue;
7682 7679
7683 7680 case SCF_ERROR_INVALID_ARGUMENT:
7684 7681 case SCF_ERROR_HANDLE_MISMATCH:
7685 7682 case SCF_ERROR_CONNECTION_BROKEN:
7686 7683 case SCF_ERROR_NOT_BOUND:
7687 7684 case SCF_ERROR_NOT_SET:
7688 7685 default:
7689 7686 bad_error("scf_pg_get_property",
7690 7687 scf_error());
7691 7688 }
7692 7689 }
7693 7690 } else {
7694 7691 switch (scf_error()) {
7695 7692 case SCF_ERROR_DELETED:
7696 7693 case SCF_ERROR_NOT_FOUND:
7697 7694 continue;
7698 7695
7699 7696 case SCF_ERROR_CONNECTION_BROKEN:
7700 7697 goto connaborted;
7701 7698
7702 7699 case SCF_ERROR_NOT_BOUND:
7703 7700 case SCF_ERROR_NOT_SET:
7704 7701 case SCF_ERROR_INVALID_ARGUMENT:
7705 7702 case SCF_ERROR_HANDLE_MISMATCH:
7706 7703 default:
7707 7704 bad_error("scf_instance_get_pg",
7708 7705 scf_error());
7709 7706 }
7710 7707 }
7711 7708 continue;
7712 7709 }
7713 7710
7714 7711 /* find service snaplevel */
7715 7712 r = get_snaplevel(imp_snap, 1, imp_snpl);
7716 7713 switch (r) {
7717 7714 case 0:
7718 7715 break;
7719 7716
7720 7717 case ECONNABORTED:
7721 7718 goto connaborted;
7722 7719
7723 7720 case ECANCELED:
7724 7721 continue;
7725 7722
7726 7723 case ENOENT:
7727 7724 if (scf_instance_get_name(imp_inst, imp_str,
7728 7725 imp_str_sz) < 0)
7729 7726 (void) strcpy(imp_str, "?");
7730 7727 warn(badsnap, snap_lastimport, s->sc_name, imp_str);
7731 7728 lcbdata->sc_err = EBADF;
7732 7729 r = UU_WALK_ERROR;
7733 7730 goto deltemp;
7734 7731
7735 7732 default:
7736 7733 bad_error("get_snaplevel", r);
7737 7734 }
7738 7735
7739 7736 if (scf_instance_get_snapshot(imp_inst, snap_running,
7740 7737 imp_rsnap) != 0) {
7741 7738 switch (scf_error()) {
7742 7739 case SCF_ERROR_DELETED:
7743 7740 continue;
7744 7741
7745 7742 case SCF_ERROR_NOT_FOUND:
7746 7743 break;
7747 7744
7748 7745 case SCF_ERROR_CONNECTION_BROKEN:
7749 7746 goto connaborted;
7750 7747
7751 7748 case SCF_ERROR_INVALID_ARGUMENT:
7752 7749 case SCF_ERROR_HANDLE_MISMATCH:
7753 7750 case SCF_ERROR_NOT_BOUND:
7754 7751 case SCF_ERROR_NOT_SET:
7755 7752 default:
7756 7753 bad_error("scf_instance_get_snapshot",
7757 7754 scf_error());
7758 7755 }
7759 7756 running = NULL;
7760 7757 } else {
7761 7758 r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
7762 7759 switch (r) {
7763 7760 case 0:
7764 7761 running = imp_rsnpl;
7765 7762 break;
7766 7763
7767 7764 case ECONNABORTED:
7768 7765 goto connaborted;
7769 7766
7770 7767 case ECANCELED:
7771 7768 continue;
7772 7769
7773 7770 case ENOENT:
7774 7771 if (scf_instance_get_name(imp_inst, imp_str,
7775 7772 imp_str_sz) < 0)
7776 7773 (void) strcpy(imp_str, "?");
7777 7774 warn(badsnap, snap_running, s->sc_name,
7778 7775 imp_str);
7779 7776 lcbdata->sc_err = EBADF;
7780 7777 r = UU_WALK_ERROR;
7781 7778 goto deltemp;
7782 7779
7783 7780 default:
7784 7781 bad_error("get_snaplevel", r);
7785 7782 }
7786 7783 }
7787 7784
7788 7785 if (g_verbose) {
7789 7786 if (scf_instance_get_name(imp_inst, imp_str,
7790 7787 imp_str_sz) < 0)
7791 7788 (void) strcpy(imp_str, "?");
7792 7789 warn(gettext("Upgrading properties of %s according to "
7793 7790 "instance \"%s\".\n"), s->sc_fmri, imp_str);
7794 7791 }
7795 7792
7796 7793 /* upgrade service properties */
7797 7794 r = upgrade_props(imp_svc, running, imp_snpl, s);
7798 7795 if (r == 0)
7799 7796 break;
7800 7797
7801 7798 switch (r) {
7802 7799 case ECONNABORTED:
7803 7800 goto connaborted;
7804 7801
7805 7802 case ECANCELED:
7806 7803 warn(s_deleted, s->sc_fmri);
7807 7804 lcbdata->sc_err = EBUSY;
7808 7805 break;
7809 7806
7810 7807 case ENODEV:
7811 7808 if (scf_instance_get_name(imp_inst, imp_str,
7812 7809 imp_str_sz) < 0)
7813 7810 (void) strcpy(imp_str, "?");
7814 7811 warn(i_deleted, s->sc_fmri, imp_str);
7815 7812 lcbdata->sc_err = EBUSY;
7816 7813 break;
7817 7814
7818 7815 default:
7819 7816 lcbdata->sc_err = r;
7820 7817 }
7821 7818
7822 7819 r = UU_WALK_ERROR;
7823 7820 goto deltemp;
7824 7821 }
7825 7822
7826 7823 s->sc_import_state = IMPORT_PROP_DONE;
7827 7824
7828 7825 instances:
7829 7826 /* import instances */
7830 7827 cbdata.sc_handle = lcbdata->sc_handle;
7831 7828 cbdata.sc_parent = imp_svc;
7832 7829 cbdata.sc_service = 1;
7833 7830 cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7834 7831 cbdata.sc_general = NULL;
7835 7832
7836 7833 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7837 7834 lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7838 7835 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7839 7836 bad_error("uu_list_walk", uu_error());
7840 7837
7841 7838 lcbdata->sc_err = cbdata.sc_err;
7842 7839 if (cbdata.sc_err == ECONNABORTED)
7843 7840 goto connaborted;
7844 7841 r = UU_WALK_ERROR;
7845 7842 goto deltemp;
7846 7843 }
7847 7844
7848 7845 s->sc_import_state = IMPORT_COMPLETE;
7849 7846 r = UU_WALK_NEXT;
7850 7847
7851 7848 deltemp:
7852 7849 /* delete temporary service */
7853 7850 if (scf_service_delete(imp_tsvc) != 0) {
7854 7851 switch (scf_error()) {
7855 7852 case SCF_ERROR_DELETED:
7856 7853 break;
7857 7854
7858 7855 case SCF_ERROR_CONNECTION_BROKEN:
7859 7856 goto connaborted;
7860 7857
7861 7858 case SCF_ERROR_EXISTS:
7862 7859 warn(gettext(
7863 7860 "Could not delete svc:/%s (instances exist).\n"),
7864 7861 imp_tsname);
7865 7862 break;
7866 7863
7867 7864 case SCF_ERROR_NOT_SET:
7868 7865 case SCF_ERROR_NOT_BOUND:
7869 7866 default:
7870 7867 bad_error("scf_service_delete", scf_error());
7871 7868 }
7872 7869 }
7873 7870
7874 7871 return (r);
7875 7872
7876 7873 connaborted:
7877 7874 warn(gettext("Could not delete svc:/%s "
7878 7875 "(repository connection broken).\n"), imp_tsname);
7879 7876 lcbdata->sc_err = ECONNABORTED;
7880 7877 return (UU_WALK_ERROR);
7881 7878 }
7882 7879
7883 7880 static const char *
7884 7881 import_progress(int st)
7885 7882 {
7886 7883 switch (st) {
7887 7884 case 0:
7888 7885 return (gettext("not reached."));
7889 7886
7890 7887 case IMPORT_PREVIOUS:
7891 7888 return (gettext("previous snapshot taken."));
7892 7889
7893 7890 case IMPORT_PROP_BEGUN:
7894 7891 return (gettext("some properties imported."));
7895 7892
7896 7893 case IMPORT_PROP_DONE:
7897 7894 return (gettext("properties imported."));
7898 7895
7899 7896 case IMPORT_COMPLETE:
7900 7897 return (gettext("imported."));
7901 7898
7902 7899 case IMPORT_REFRESHED:
7903 7900 return (gettext("refresh requested."));
7904 7901
7905 7902 default:
7906 7903 #ifndef NDEBUG
7907 7904 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7908 7905 __FILE__, __LINE__, st);
7909 7906 #endif
7910 7907 abort();
7911 7908 /* NOTREACHED */
7912 7909 }
7913 7910 }
7914 7911
7915 7912 /*
7916 7913 * Returns
7917 7914 * 0 - success
7918 7915 * - fmri wasn't found (error printed)
7919 7916 * - entity was deleted (error printed)
7920 7917 * - backend denied access (error printed)
7921 7918 * ENOMEM - out of memory (error printed)
7922 7919 * ECONNABORTED - repository connection broken (error printed)
7923 7920 * EPERM - permission denied (error printed)
7924 7921 * -1 - unknown libscf error (error printed)
7925 7922 */
7926 7923 static int
7927 7924 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7928 7925 {
7929 7926 scf_error_t serr;
7930 7927 void *ent;
7931 7928 int issvc;
7932 7929 int r;
7933 7930
7934 7931 const char *deleted = gettext("Could not refresh %s (deleted).\n");
7935 7932 const char *dpt_deleted = gettext("Could not refresh %s "
7936 7933 "(dependent \"%s\" of %s) (deleted).\n");
7937 7934
7938 7935 serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7939 7936 switch (serr) {
7940 7937 case SCF_ERROR_NONE:
7941 7938 break;
7942 7939
7943 7940 case SCF_ERROR_NO_MEMORY:
7944 7941 if (name == NULL)
7945 7942 warn(gettext("Could not refresh %s (out of memory).\n"),
7946 7943 fmri);
7947 7944 else
7948 7945 warn(gettext("Could not refresh %s "
7949 7946 "(dependent \"%s\" of %s) (out of memory).\n"),
7950 7947 fmri, name, d_fmri);
7951 7948 return (ENOMEM);
7952 7949
7953 7950 case SCF_ERROR_NOT_FOUND:
7954 7951 if (name == NULL)
7955 7952 warn(deleted, fmri);
7956 7953 else
7957 7954 warn(dpt_deleted, fmri, name, d_fmri);
7958 7955 return (0);
7959 7956
7960 7957 case SCF_ERROR_INVALID_ARGUMENT:
7961 7958 case SCF_ERROR_CONSTRAINT_VIOLATED:
7962 7959 default:
7963 7960 bad_error("fmri_to_entity", serr);
7964 7961 }
7965 7962
7966 7963 r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7967 7964 switch (r) {
7968 7965 case 0:
7969 7966 break;
7970 7967
7971 7968 case ECONNABORTED:
7972 7969 if (name != NULL)
7973 7970 warn(gettext("Could not refresh %s "
7974 7971 "(dependent \"%s\" of %s) "
7975 7972 "(repository connection broken).\n"), fmri, name,
7976 7973 d_fmri);
7977 7974 return (r);
7978 7975
7979 7976 case ECANCELED:
7980 7977 if (name == NULL)
7981 7978 warn(deleted, fmri);
7982 7979 else
7983 7980 warn(dpt_deleted, fmri, name, d_fmri);
7984 7981 return (0);
7985 7982
7986 7983 case EACCES:
7987 7984 if (!g_verbose)
7988 7985 return (0);
7989 7986 if (name == NULL)
7990 7987 warn(gettext("Could not refresh %s "
7991 7988 "(backend access denied).\n"), fmri);
7992 7989 else
7993 7990 warn(gettext("Could not refresh %s "
7994 7991 "(dependent \"%s\" of %s) "
7995 7992 "(backend access denied).\n"), fmri, name, d_fmri);
7996 7993 return (0);
7997 7994
7998 7995 case EPERM:
7999 7996 if (name == NULL)
8000 7997 warn(gettext("Could not refresh %s "
8001 7998 "(permission denied).\n"), fmri);
8002 7999 else
8003 8000 warn(gettext("Could not refresh %s "
8004 8001 "(dependent \"%s\" of %s) "
8005 8002 "(permission denied).\n"), fmri, name, d_fmri);
8006 8003 return (r);
8007 8004
8008 8005 case ENOSPC:
8009 8006 if (name == NULL)
8010 8007 warn(gettext("Could not refresh %s "
8011 8008 "(repository server out of resources).\n"),
8012 8009 fmri);
8013 8010 else
8014 8011 warn(gettext("Could not refresh %s "
8015 8012 "(dependent \"%s\" of %s) "
8016 8013 "(repository server out of resources).\n"),
8017 8014 fmri, name, d_fmri);
8018 8015 return (r);
8019 8016
8020 8017 case -1:
8021 8018 scfwarn();
8022 8019 return (r);
8023 8020
8024 8021 default:
8025 8022 bad_error("refresh_entity", r);
8026 8023 }
8027 8024
8028 8025 if (issvc)
8029 8026 scf_service_destroy(ent);
8030 8027 else
8031 8028 scf_instance_destroy(ent);
8032 8029
8033 8030 return (0);
8034 8031 }
8035 8032
8036 8033 static int
8037 8034 alloc_imp_globals()
8038 8035 {
8039 8036 int r;
8040 8037
8041 8038 const char * const emsg_nomem = gettext("Out of memory.\n");
8042 8039 const char * const emsg_nores =
8043 8040 gettext("svc.configd is out of resources.\n");
8044 8041
8045 8042 imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
8046 8043 max_scf_name_len : max_scf_fmri_len) + 1;
8047 8044
8048 8045 if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
8049 8046 (imp_svc = scf_service_create(g_hndl)) == NULL ||
8050 8047 (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
8051 8048 (imp_inst = scf_instance_create(g_hndl)) == NULL ||
8052 8049 (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
8053 8050 (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
8054 8051 (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
8055 8052 (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
8056 8053 (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
8057 8054 (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8058 8055 (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
8059 8056 (imp_pg = scf_pg_create(g_hndl)) == NULL ||
8060 8057 (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
8061 8058 (imp_prop = scf_property_create(g_hndl)) == NULL ||
8062 8059 (imp_iter = scf_iter_create(g_hndl)) == NULL ||
8063 8060 (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
8064 8061 (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
8065 8062 (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
8066 8063 (imp_str = malloc(imp_str_sz)) == NULL ||
8067 8064 (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
8068 8065 (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
8069 8066 (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
8070 8067 (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
8071 8068 (ud_inst = scf_instance_create(g_hndl)) == NULL ||
8072 8069 (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8073 8070 (ud_pg = scf_pg_create(g_hndl)) == NULL ||
8074 8071 (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
8075 8072 (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
8076 8073 (ud_prop = scf_property_create(g_hndl)) == NULL ||
8077 8074 (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
8078 8075 (ud_val = scf_value_create(g_hndl)) == NULL ||
8079 8076 (ud_iter = scf_iter_create(g_hndl)) == NULL ||
8080 8077 (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
8081 8078 (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
8082 8079 (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
8083 8080 (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
8084 8081 (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
8085 8082 if (scf_error() == SCF_ERROR_NO_RESOURCES)
8086 8083 warn(emsg_nores);
8087 8084 else
8088 8085 warn(emsg_nomem);
8089 8086
8090 8087 return (-1);
8091 8088 }
8092 8089
8093 8090 r = load_init();
8094 8091 switch (r) {
8095 8092 case 0:
8096 8093 break;
8097 8094
8098 8095 case ENOMEM:
8099 8096 warn(emsg_nomem);
8100 8097 return (-1);
8101 8098
8102 8099 default:
8103 8100 bad_error("load_init", r);
8104 8101 }
8105 8102
8106 8103 return (0);
8107 8104 }
8108 8105
8109 8106 static void
8110 8107 free_imp_globals()
8111 8108 {
8112 8109 pgroup_t *old_dpt;
8113 8110 void *cookie;
8114 8111
8115 8112 load_fini();
8116 8113
8117 8114 free(ud_ctarg);
8118 8115 free(ud_oldtarg);
8119 8116 free(ud_name);
8120 8117 ud_ctarg = ud_oldtarg = ud_name = NULL;
8121 8118
8122 8119 scf_transaction_destroy(ud_tx);
8123 8120 ud_tx = NULL;
8124 8121 scf_iter_destroy(ud_iter);
8125 8122 scf_iter_destroy(ud_iter2);
8126 8123 ud_iter = ud_iter2 = NULL;
8127 8124 scf_value_destroy(ud_val);
8128 8125 ud_val = NULL;
8129 8126 scf_property_destroy(ud_prop);
8130 8127 scf_property_destroy(ud_dpt_prop);
8131 8128 ud_prop = ud_dpt_prop = NULL;
8132 8129 scf_pg_destroy(ud_pg);
8133 8130 scf_pg_destroy(ud_cur_depts_pg);
8134 8131 scf_pg_destroy(ud_run_dpts_pg);
8135 8132 ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
8136 8133 scf_snaplevel_destroy(ud_snpl);
8137 8134 ud_snpl = NULL;
8138 8135 scf_instance_destroy(ud_inst);
8139 8136 ud_inst = NULL;
8140 8137
8141 8138 free(imp_str);
8142 8139 free(imp_tsname);
8143 8140 free(imp_fe1);
8144 8141 free(imp_fe2);
8145 8142 imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
8146 8143
8147 8144 cookie = NULL;
8148 8145 while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
8149 8146 NULL) {
8150 8147 free((char *)old_dpt->sc_pgroup_name);
8151 8148 free((char *)old_dpt->sc_pgroup_fmri);
8152 8149 internal_pgroup_free(old_dpt);
8153 8150 }
8154 8151 uu_list_destroy(imp_deleted_dpts);
8155 8152
8156 8153 scf_transaction_destroy(imp_tx);
8157 8154 imp_tx = NULL;
8158 8155 scf_iter_destroy(imp_iter);
8159 8156 scf_iter_destroy(imp_rpg_iter);
8160 8157 scf_iter_destroy(imp_up_iter);
8161 8158 imp_iter = imp_rpg_iter = imp_up_iter = NULL;
8162 8159 scf_property_destroy(imp_prop);
8163 8160 imp_prop = NULL;
8164 8161 scf_pg_destroy(imp_pg);
8165 8162 scf_pg_destroy(imp_pg2);
8166 8163 imp_pg = imp_pg2 = NULL;
8167 8164 scf_snaplevel_destroy(imp_snpl);
8168 8165 scf_snaplevel_destroy(imp_rsnpl);
8169 8166 imp_snpl = imp_rsnpl = NULL;
8170 8167 scf_snapshot_destroy(imp_snap);
8171 8168 scf_snapshot_destroy(imp_lisnap);
8172 8169 scf_snapshot_destroy(imp_tlisnap);
8173 8170 scf_snapshot_destroy(imp_rsnap);
8174 8171 imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
8175 8172 scf_instance_destroy(imp_inst);
8176 8173 scf_instance_destroy(imp_tinst);
8177 8174 imp_inst = imp_tinst = NULL;
8178 8175 scf_service_destroy(imp_svc);
8179 8176 scf_service_destroy(imp_tsvc);
8180 8177 imp_svc = imp_tsvc = NULL;
8181 8178 scf_scope_destroy(imp_scope);
8182 8179 imp_scope = NULL;
8183 8180
8184 8181 load_fini();
8185 8182 }
8186 8183
8187 8184 int
8188 8185 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
8189 8186 {
8190 8187 scf_callback_t cbdata;
8191 8188 int result = 0;
8192 8189 entity_t *svc, *inst;
8193 8190 uu_list_t *insts;
8194 8191 int r;
8195 8192 pgroup_t *old_dpt;
8196 8193 int annotation_set = 0;
8197 8194
8198 8195 const char * const emsg_nomem = gettext("Out of memory.\n");
8199 8196 const char * const emsg_nores =
8200 8197 gettext("svc.configd is out of resources.\n");
8201 8198
8202 8199 lscf_prep_hndl();
8203 8200
8204 8201 if (alloc_imp_globals())
8205 8202 goto out;
8206 8203
8207 8204 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
8208 8205 switch (scf_error()) {
8209 8206 case SCF_ERROR_CONNECTION_BROKEN:
8210 8207 warn(gettext("Repository connection broken.\n"));
8211 8208 repository_teardown();
8212 8209 result = -1;
8213 8210 goto out;
8214 8211
8215 8212 case SCF_ERROR_NOT_FOUND:
8216 8213 case SCF_ERROR_INVALID_ARGUMENT:
8217 8214 case SCF_ERROR_NOT_BOUND:
8218 8215 case SCF_ERROR_HANDLE_MISMATCH:
8219 8216 default:
8220 8217 bad_error("scf_handle_get_scope", scf_error());
8221 8218 }
8222 8219 }
8223 8220
8224 8221 /* Set up the auditing annotation. */
8225 8222 if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
8226 8223 annotation_set = 1;
8227 8224 } else {
8228 8225 switch (scf_error()) {
8229 8226 case SCF_ERROR_CONNECTION_BROKEN:
8230 8227 warn(gettext("Repository connection broken.\n"));
8231 8228 repository_teardown();
8232 8229 result = -1;
8233 8230 goto out;
8234 8231
8235 8232 case SCF_ERROR_INVALID_ARGUMENT:
8236 8233 case SCF_ERROR_NOT_BOUND:
8237 8234 case SCF_ERROR_NO_RESOURCES:
8238 8235 case SCF_ERROR_INTERNAL:
8239 8236 bad_error("_scf_set_annotation", scf_error());
8240 8237 /* NOTREACHED */
8241 8238
8242 8239 default:
8243 8240 /*
8244 8241 * Do not terminate import because of inability to
8245 8242 * generate annotation audit event.
8246 8243 */
8247 8244 warn(gettext("_scf_set_annotation() unexpectedly "
8248 8245 "failed with return code of %d\n"), scf_error());
8249 8246 break;
8250 8247 }
8251 8248 }
8252 8249
8253 8250 /*
8254 8251 * Clear the sc_import_state's of all services & instances so we can
8255 8252 * report how far we got if we fail.
8256 8253 */
8257 8254 for (svc = uu_list_first(bndl->sc_bundle_services);
8258 8255 svc != NULL;
8259 8256 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8260 8257 svc->sc_import_state = 0;
8261 8258
8262 8259 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
8263 8260 clear_int, (void *)offsetof(entity_t, sc_import_state),
8264 8261 UU_DEFAULT) != 0)
8265 8262 bad_error("uu_list_walk", uu_error());
8266 8263 }
8267 8264
8268 8265 cbdata.sc_handle = g_hndl;
8269 8266 cbdata.sc_parent = imp_scope;
8270 8267 cbdata.sc_flags = flags;
8271 8268 cbdata.sc_general = NULL;
8272 8269
8273 8270 if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
8274 8271 &cbdata, UU_DEFAULT) == 0) {
8275 8272 char *eptr;
8276 8273 /* Success. Refresh everything. */
8277 8274
8278 8275 if (flags & SCI_NOREFRESH || no_refresh) {
8279 8276 no_refresh = 0;
8280 8277 result = 0;
8281 8278 goto out;
8282 8279 }
8283 8280
8284 8281 for (svc = uu_list_first(bndl->sc_bundle_services);
8285 8282 svc != NULL;
8286 8283 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8287 8284 pgroup_t *dpt;
8288 8285
8289 8286 insts = svc->sc_u.sc_service.sc_service_instances;
8290 8287
8291 8288 for (inst = uu_list_first(insts);
8292 8289 inst != NULL;
8293 8290 inst = uu_list_next(insts, inst)) {
8294 8291 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
8295 8292 switch (r) {
8296 8293 case 0:
8297 8294 break;
8298 8295
8299 8296 case ENOMEM:
8300 8297 case ECONNABORTED:
8301 8298 case EPERM:
8302 8299 case -1:
8303 8300 goto progress;
8304 8301
8305 8302 default:
8306 8303 bad_error("imp_refresh_fmri", r);
8307 8304 }
8308 8305
8309 8306 inst->sc_import_state = IMPORT_REFRESHED;
8310 8307
8311 8308 for (dpt = uu_list_first(inst->sc_dependents);
8312 8309 dpt != NULL;
8313 8310 dpt = uu_list_next(inst->sc_dependents,
8314 8311 dpt))
8315 8312 if (imp_refresh_fmri(
8316 8313 dpt->sc_pgroup_fmri,
8317 8314 dpt->sc_pgroup_name,
8318 8315 inst->sc_fmri) != 0)
8319 8316 goto progress;
8320 8317 }
8321 8318
8322 8319 for (dpt = uu_list_first(svc->sc_dependents);
8323 8320 dpt != NULL;
8324 8321 dpt = uu_list_next(svc->sc_dependents, dpt))
8325 8322 if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
8326 8323 dpt->sc_pgroup_name, svc->sc_fmri) != 0)
8327 8324 goto progress;
8328 8325 }
8329 8326
8330 8327 for (old_dpt = uu_list_first(imp_deleted_dpts);
8331 8328 old_dpt != NULL;
8332 8329 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
8333 8330 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8334 8331 old_dpt->sc_pgroup_name,
8335 8332 old_dpt->sc_parent->sc_fmri) != 0)
8336 8333 goto progress;
8337 8334
8338 8335 result = 0;
8339 8336
8340 8337 /*
8341 8338 * This snippet of code assumes that we are running svccfg as we
8342 8339 * normally do -- witih svc.startd running. Of course, that is
8343 8340 * not actually the case all the time because we also use a
8344 8341 * varient of svc.configd and svccfg which are only meant to
8345 8342 * run during the build process. During this time we have no
8346 8343 * svc.startd, so this check would hang the build process.
8347 8344 *
8348 8345 * However, we've also given other consolidations, a bit of a
8349 8346 * means to tie themselves into a knot. They're not properly
8350 8347 * using the native build equivalents, but they've been getting
8351 8348 * away with it anyways. Therefore, if we've found that
8352 8349 * SVCCFG_REPOSITORY is set indicating that a separate configd
8353 8350 * should be spun up, then we have to assume it's not using a
8354 8351 * startd and we should not do this check.
8355 8352 */
8356 8353 #ifndef NATIVE_BUILD
8357 8354 /*
8358 8355 * Verify that the restarter group is preset
8359 8356 */
8360 8357 eptr = getenv("SVCCFG_REPOSITORY");
8361 8358 for (svc = uu_list_first(bndl->sc_bundle_services);
8362 8359 svc != NULL && eptr == NULL;
8363 8360 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8364 8361
8365 8362 insts = svc->sc_u.sc_service.sc_service_instances;
8366 8363
8367 8364 for (inst = uu_list_first(insts);
8368 8365 inst != NULL;
8369 8366 inst = uu_list_next(insts, inst)) {
8370 8367 if (lscf_instance_verify(imp_scope, svc,
8371 8368 inst) != 0)
8372 8369 goto progress;
8373 8370 }
8374 8371 }
8375 8372 #endif
8376 8373 goto out;
8377 8374
8378 8375 }
8379 8376
8380 8377 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8381 8378 bad_error("uu_list_walk", uu_error());
8382 8379
8383 8380 printerr:
8384 8381 /* If the error hasn't been printed yet, do so here. */
8385 8382 switch (cbdata.sc_err) {
8386 8383 case ECONNABORTED:
8387 8384 warn(gettext("Repository connection broken.\n"));
8388 8385 break;
8389 8386
8390 8387 case ENOMEM:
8391 8388 warn(emsg_nomem);
8392 8389 break;
8393 8390
8394 8391 case ENOSPC:
8395 8392 warn(emsg_nores);
8396 8393 break;
8397 8394
8398 8395 case EROFS:
8399 8396 warn(gettext("Repository is read-only.\n"));
8400 8397 break;
8401 8398
8402 8399 case EACCES:
8403 8400 warn(gettext("Repository backend denied access.\n"));
8404 8401 break;
8405 8402
8406 8403 case EPERM:
8407 8404 case EINVAL:
8408 8405 case EEXIST:
8409 8406 case EBUSY:
8410 8407 case EBADF:
8411 8408 case -1:
8412 8409 break;
8413 8410
8414 8411 default:
8415 8412 bad_error("lscf_service_import", cbdata.sc_err);
8416 8413 }
8417 8414
8418 8415 progress:
8419 8416 warn(gettext("Import of %s failed. Progress:\n"), filename);
8420 8417
8421 8418 for (svc = uu_list_first(bndl->sc_bundle_services);
8422 8419 svc != NULL;
8423 8420 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8424 8421 insts = svc->sc_u.sc_service.sc_service_instances;
8425 8422
8426 8423 warn(gettext(" Service \"%s\": %s\n"), svc->sc_name,
8427 8424 import_progress(svc->sc_import_state));
8428 8425
8429 8426 for (inst = uu_list_first(insts);
8430 8427 inst != NULL;
8431 8428 inst = uu_list_next(insts, inst))
8432 8429 warn(gettext(" Instance \"%s\": %s\n"),
8433 8430 inst->sc_name,
8434 8431 import_progress(inst->sc_import_state));
8435 8432 }
8436 8433
8437 8434 if (cbdata.sc_err == ECONNABORTED)
8438 8435 repository_teardown();
8439 8436
8440 8437
8441 8438 result = -1;
8442 8439
8443 8440 out:
8444 8441 if (annotation_set != 0) {
8445 8442 /* Turn off annotation. It is no longer needed. */
8446 8443 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8447 8444 }
8448 8445
8449 8446 free_imp_globals();
8450 8447
8451 8448 return (result);
8452 8449 }
8453 8450
8454 8451 /*
8455 8452 * _lscf_import_err() summarize the error handling returned by
8456 8453 * lscf_import_{instance | service}_pgs
8457 8454 * Return values are:
8458 8455 * IMPORT_NEXT
8459 8456 * IMPORT_OUT
8460 8457 * IMPORT_BAD
8461 8458 */
8462 8459
8463 8460 #define IMPORT_BAD -1
8464 8461 #define IMPORT_NEXT 0
8465 8462 #define IMPORT_OUT 1
8466 8463
8467 8464 static int
8468 8465 _lscf_import_err(int err, const char *fmri)
8469 8466 {
8470 8467 switch (err) {
8471 8468 case 0:
8472 8469 if (g_verbose)
8473 8470 warn(gettext("%s updated.\n"), fmri);
8474 8471 return (IMPORT_NEXT);
8475 8472
8476 8473 case ECONNABORTED:
8477 8474 warn(gettext("Could not update %s "
8478 8475 "(repository connection broken).\n"), fmri);
8479 8476 return (IMPORT_OUT);
8480 8477
8481 8478 case ENOMEM:
8482 8479 warn(gettext("Could not update %s (out of memory).\n"), fmri);
8483 8480 return (IMPORT_OUT);
8484 8481
8485 8482 case ENOSPC:
8486 8483 warn(gettext("Could not update %s "
8487 8484 "(repository server out of resources).\n"), fmri);
8488 8485 return (IMPORT_OUT);
8489 8486
8490 8487 case ECANCELED:
8491 8488 warn(gettext(
8492 8489 "Could not update %s (deleted).\n"), fmri);
8493 8490 return (IMPORT_NEXT);
8494 8491
8495 8492 case EPERM:
8496 8493 case EINVAL:
8497 8494 case EBUSY:
8498 8495 return (IMPORT_NEXT);
8499 8496
8500 8497 case EROFS:
8501 8498 warn(gettext("Could not update %s (repository read-only).\n"),
8502 8499 fmri);
8503 8500 return (IMPORT_OUT);
8504 8501
8505 8502 case EACCES:
8506 8503 warn(gettext("Could not update %s "
8507 8504 "(backend access denied).\n"), fmri);
8508 8505 return (IMPORT_NEXT);
8509 8506
8510 8507 case EEXIST:
8511 8508 default:
8512 8509 return (IMPORT_BAD);
8513 8510 }
8514 8511
8515 8512 /*NOTREACHED*/
8516 8513 }
8517 8514
8518 8515 /*
8519 8516 * The global imp_svc and imp_inst should be set by the caller in the
8520 8517 * check to make sure the service and instance exist that the apply is
8521 8518 * working on.
8522 8519 */
8523 8520 static int
8524 8521 lscf_dependent_apply(void *dpg, void *e)
8525 8522 {
8526 8523 scf_callback_t cb;
8527 8524 pgroup_t *dpt_pgroup = dpg;
8528 8525 pgroup_t *deldpt;
8529 8526 entity_t *ent = e;
8530 8527 int tissvc;
8531 8528 void *sc_ent, *tent;
8532 8529 scf_error_t serr;
8533 8530 int r;
8534 8531
8535 8532 const char * const dependents = "dependents";
8536 8533 const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT);
8537 8534
8538 8535 if (issvc)
8539 8536 sc_ent = imp_svc;
8540 8537 else
8541 8538 sc_ent = imp_inst;
8542 8539
8543 8540 if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg,
8544 8541 imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 ||
8545 8542 scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name,
8546 8543 imp_prop) != 0) {
8547 8544 switch (scf_error()) {
8548 8545 case SCF_ERROR_NOT_FOUND:
8549 8546 case SCF_ERROR_DELETED:
8550 8547 break;
8551 8548
8552 8549 case SCF_ERROR_CONNECTION_BROKEN:
8553 8550 case SCF_ERROR_NOT_SET:
8554 8551 case SCF_ERROR_INVALID_ARGUMENT:
8555 8552 case SCF_ERROR_HANDLE_MISMATCH:
8556 8553 case SCF_ERROR_NOT_BOUND:
8557 8554 default:
8558 8555 bad_error("entity_get_pg", scf_error());
8559 8556 }
8560 8557 } else {
8561 8558 /*
8562 8559 * Found the dependents/<wip dep> so check to
8563 8560 * see if the service is different. If so
8564 8561 * store the service for later refresh, and
8565 8562 * delete the wip dependency from the service
8566 8563 */
8567 8564 if (scf_property_get_value(imp_prop, ud_val) != 0) {
8568 8565 switch (scf_error()) {
8569 8566 case SCF_ERROR_DELETED:
8570 8567 break;
8571 8568
8572 8569 case SCF_ERROR_CONNECTION_BROKEN:
8573 8570 case SCF_ERROR_NOT_SET:
8574 8571 case SCF_ERROR_INVALID_ARGUMENT:
8575 8572 case SCF_ERROR_HANDLE_MISMATCH:
8576 8573 case SCF_ERROR_NOT_BOUND:
8577 8574 default:
8578 8575 bad_error("scf_property_get_value",
8579 8576 scf_error());
8580 8577 }
8581 8578 }
8582 8579
8583 8580 if (scf_value_get_as_string(ud_val, ud_oldtarg,
8584 8581 max_scf_value_len + 1) < 0)
8585 8582 bad_error("scf_value_get_as_string", scf_error());
8586 8583
8587 8584 r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
8588 8585 switch (r) {
8589 8586 case 1:
8590 8587 break;
8591 8588 case 0:
8592 8589 if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent,
8593 8590 &tissvc)) != SCF_ERROR_NONE) {
8594 8591 if (serr == SCF_ERROR_NOT_FOUND) {
8595 8592 break;
8596 8593 } else {
8597 8594 bad_error("fmri_to_entity", serr);
8598 8595 }
8599 8596 }
8600 8597
8601 8598 if (entity_get_pg(tent, tissvc,
8602 8599 dpt_pgroup->sc_pgroup_name, imp_pg) != 0) {
8603 8600 serr = scf_error();
8604 8601 if (serr == SCF_ERROR_NOT_FOUND ||
8605 8602 serr == SCF_ERROR_DELETED) {
8606 8603 break;
8607 8604 } else {
8608 8605 bad_error("entity_get_pg", scf_error());
8609 8606 }
8610 8607 }
8611 8608
8612 8609 if (scf_pg_delete(imp_pg) != 0) {
8613 8610 serr = scf_error();
8614 8611 if (serr == SCF_ERROR_NOT_FOUND ||
8615 8612 serr == SCF_ERROR_DELETED) {
8616 8613 break;
8617 8614 } else {
8618 8615 bad_error("scf_pg_delete", scf_error());
8619 8616 }
8620 8617 }
8621 8618
8622 8619 deldpt = internal_pgroup_new();
8623 8620 if (deldpt == NULL)
8624 8621 return (ENOMEM);
8625 8622 deldpt->sc_pgroup_name =
8626 8623 strdup(dpt_pgroup->sc_pgroup_name);
8627 8624 deldpt->sc_pgroup_fmri = strdup(ud_oldtarg);
8628 8625 if (deldpt->sc_pgroup_name == NULL ||
8629 8626 deldpt->sc_pgroup_fmri == NULL)
8630 8627 return (ENOMEM);
8631 8628 deldpt->sc_parent = (entity_t *)ent;
8632 8629 if (uu_list_insert_after(imp_deleted_dpts, NULL,
8633 8630 deldpt) != 0)
8634 8631 uu_die(gettext("libuutil error: %s\n"),
8635 8632 uu_strerror(uu_error()));
8636 8633
8637 8634 break;
8638 8635 default:
8639 8636 bad_error("fmri_equal", r);
8640 8637 }
8641 8638 }
8642 8639
8643 8640 cb.sc_handle = g_hndl;
8644 8641 cb.sc_parent = ent;
8645 8642 cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT;
8646 8643 cb.sc_source_fmri = ent->sc_fmri;
8647 8644 cb.sc_target_fmri = ent->sc_fmri;
8648 8645 cb.sc_trans = NULL;
8649 8646 cb.sc_flags = SCI_FORCE;
8650 8647
8651 8648 if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT)
8652 8649 return (UU_WALK_ERROR);
8653 8650
8654 8651 r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL);
8655 8652 switch (r) {
8656 8653 case 0:
8657 8654 break;
8658 8655
8659 8656 case ENOMEM:
8660 8657 case ECONNABORTED:
8661 8658 case EPERM:
8662 8659 case -1:
8663 8660 warn(gettext("Unable to refresh \"%s\"\n"),
8664 8661 dpt_pgroup->sc_pgroup_fmri);
8665 8662 return (UU_WALK_ERROR);
8666 8663
8667 8664 default:
8668 8665 bad_error("imp_refresh_fmri", r);
8669 8666 }
8670 8667
8671 8668 return (UU_WALK_NEXT);
8672 8669 }
8673 8670
8674 8671 /*
8675 8672 * Returns
8676 8673 * 0 - success
8677 8674 * -1 - lscf_import_instance_pgs() failed.
8678 8675 */
8679 8676 int
8680 8677 lscf_bundle_apply(bundle_t *bndl, const char *file)
8681 8678 {
8682 8679 pgroup_t *old_dpt;
8683 8680 entity_t *svc, *inst;
8684 8681 int annotation_set = 0;
8685 8682 int ret = 0;
8686 8683 int r = 0;
8687 8684
8688 8685 lscf_prep_hndl();
8689 8686
8690 8687 if ((ret = alloc_imp_globals()))
8691 8688 goto out;
8692 8689
8693 8690 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0)
8694 8691 scfdie();
8695 8692
8696 8693 /*
8697 8694 * Set the strings to be used for the security audit annotation
8698 8695 * event.
8699 8696 */
8700 8697 if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
8701 8698 annotation_set = 1;
8702 8699 } else {
8703 8700 switch (scf_error()) {
8704 8701 case SCF_ERROR_CONNECTION_BROKEN:
8705 8702 warn(gettext("Repository connection broken.\n"));
8706 8703 goto out;
8707 8704
8708 8705 case SCF_ERROR_INVALID_ARGUMENT:
8709 8706 case SCF_ERROR_NOT_BOUND:
8710 8707 case SCF_ERROR_NO_RESOURCES:
8711 8708 case SCF_ERROR_INTERNAL:
8712 8709 bad_error("_scf_set_annotation", scf_error());
8713 8710 /* NOTREACHED */
8714 8711
8715 8712 default:
8716 8713 /*
8717 8714 * Do not abort apply operation because of
8718 8715 * inability to create annotation audit event.
8719 8716 */
8720 8717 warn(gettext("_scf_set_annotation() unexpectedly "
8721 8718 "failed with return code of %d\n"), scf_error());
8722 8719 break;
8723 8720 }
8724 8721 }
8725 8722
8726 8723 for (svc = uu_list_first(bndl->sc_bundle_services);
8727 8724 svc != NULL;
8728 8725 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8729 8726 int refresh = 0;
8730 8727
8731 8728 if (scf_scope_get_service(imp_scope, svc->sc_name,
8732 8729 imp_svc) != 0) {
8733 8730 switch (scf_error()) {
8734 8731 case SCF_ERROR_NOT_FOUND:
8735 8732 if (g_verbose)
8736 8733 warn(gettext("Ignoring nonexistent "
8737 8734 "service %s.\n"), svc->sc_name);
8738 8735 continue;
8739 8736
8740 8737 default:
8741 8738 scfdie();
8742 8739 }
8743 8740 }
8744 8741
8745 8742 /*
8746 8743 * If there were missing types in the profile, then need to
8747 8744 * attempt to find the types.
8748 8745 */
8749 8746 if (svc->sc_miss_type) {
8750 8747 if (uu_list_numnodes(svc->sc_pgroups) &&
8751 8748 uu_list_walk(svc->sc_pgroups, find_current_pg_type,
8752 8749 svc, UU_DEFAULT) != 0) {
8753 8750 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8754 8751 bad_error("uu_list_walk", uu_error());
8755 8752
8756 8753 ret = -1;
8757 8754 continue;
8758 8755 }
8759 8756
8760 8757 for (inst = uu_list_first(
8761 8758 svc->sc_u.sc_service.sc_service_instances);
8762 8759 inst != NULL;
8763 8760 inst = uu_list_next(
8764 8761 svc->sc_u.sc_service.sc_service_instances, inst)) {
8765 8762 /*
8766 8763 * If the instance doesn't exist just
8767 8764 * skip to the next instance and let the
8768 8765 * import note the missing instance.
8769 8766 */
8770 8767 if (scf_service_get_instance(imp_svc,
8771 8768 inst->sc_name, imp_inst) != 0)
8772 8769 continue;
8773 8770
8774 8771 if (uu_list_walk(inst->sc_pgroups,
8775 8772 find_current_pg_type, inst,
8776 8773 UU_DEFAULT) != 0) {
8777 8774 if (uu_error() !=
8778 8775 UU_ERROR_CALLBACK_FAILED)
8779 8776 bad_error("uu_list_walk",
8780 8777 uu_error());
8781 8778
8782 8779 ret = -1;
8783 8780 inst->sc_miss_type = B_TRUE;
8784 8781 }
8785 8782 }
8786 8783 }
8787 8784
8788 8785 /*
8789 8786 * if we have pgs in the profile, we need to refresh ALL
8790 8787 * instances of the service
8791 8788 */
8792 8789 if (uu_list_numnodes(svc->sc_pgroups) != 0) {
8793 8790 refresh = 1;
8794 8791 r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc,
8795 8792 SCI_FORCE | SCI_KEEP);
8796 8793 switch (_lscf_import_err(r, svc->sc_fmri)) {
8797 8794 case IMPORT_NEXT:
8798 8795 break;
8799 8796
8800 8797 case IMPORT_OUT:
8801 8798 goto out;
8802 8799
8803 8800 case IMPORT_BAD:
8804 8801 default:
8805 8802 bad_error("lscf_import_service_pgs", r);
8806 8803 }
8807 8804 }
8808 8805
8809 8806 if (uu_list_numnodes(svc->sc_dependents) != 0) {
8810 8807 uu_list_walk(svc->sc_dependents,
8811 8808 lscf_dependent_apply, svc, UU_DEFAULT);
8812 8809 }
8813 8810
8814 8811 for (inst = uu_list_first(
8815 8812 svc->sc_u.sc_service.sc_service_instances);
8816 8813 inst != NULL;
8817 8814 inst = uu_list_next(
8818 8815 svc->sc_u.sc_service.sc_service_instances, inst)) {
8819 8816 /*
8820 8817 * This instance still has missing types
8821 8818 * so skip it.
8822 8819 */
8823 8820 if (inst->sc_miss_type) {
8824 8821 if (g_verbose)
8825 8822 warn(gettext("Ignoring instance "
8826 8823 "%s:%s with missing types\n"),
8827 8824 inst->sc_parent->sc_name,
8828 8825 inst->sc_name);
8829 8826
8830 8827 continue;
8831 8828 }
8832 8829
8833 8830 if (scf_service_get_instance(imp_svc, inst->sc_name,
8834 8831 imp_inst) != 0) {
8835 8832 switch (scf_error()) {
8836 8833 case SCF_ERROR_NOT_FOUND:
8837 8834 if (g_verbose)
8838 8835 warn(gettext("Ignoring "
8839 8836 "nonexistant instance "
8840 8837 "%s:%s.\n"),
8841 8838 inst->sc_parent->sc_name,
8842 8839 inst->sc_name);
8843 8840 continue;
8844 8841
8845 8842 default:
8846 8843 scfdie();
8847 8844 }
8848 8845 }
8849 8846
8850 8847 /*
8851 8848 * If the instance does not have a general/enabled
8852 8849 * property and no last-import snapshot then the
8853 8850 * instance is not a fully installed instance and
8854 8851 * should not have a profile applied to it.
8855 8852 *
8856 8853 * This could happen if a service/instance declares
8857 8854 * a dependent on behalf of another service/instance.
8858 8855 *
8859 8856 */
8860 8857 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
8861 8858 imp_snap) != 0) {
8862 8859 if (scf_instance_get_pg(imp_inst,
8863 8860 SCF_PG_GENERAL, imp_pg) != 0 ||
8864 8861 scf_pg_get_property(imp_pg,
8865 8862 SCF_PROPERTY_ENABLED, imp_prop) != 0) {
8866 8863 if (g_verbose)
8867 8864 warn(gettext("Ignoreing "
8868 8865 "partial instance "
8869 8866 "%s:%s.\n"),
8870 8867 inst->sc_parent->sc_name,
8871 8868 inst->sc_name);
8872 8869 continue;
8873 8870 }
8874 8871 }
8875 8872
8876 8873 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri,
8877 8874 inst, SCI_FORCE | SCI_KEEP);
8878 8875 switch (_lscf_import_err(r, inst->sc_fmri)) {
8879 8876 case IMPORT_NEXT:
8880 8877 break;
8881 8878
8882 8879 case IMPORT_OUT:
8883 8880 goto out;
8884 8881
8885 8882 case IMPORT_BAD:
8886 8883 default:
8887 8884 bad_error("lscf_import_instance_pgs", r);
8888 8885 }
8889 8886
8890 8887 if (uu_list_numnodes(inst->sc_dependents) != 0) {
8891 8888 uu_list_walk(inst->sc_dependents,
8892 8889 lscf_dependent_apply, inst, UU_DEFAULT);
8893 8890 }
8894 8891
8895 8892 /* refresh only if there is no pgs in the service */
8896 8893 if (refresh == 0)
8897 8894 (void) refresh_entity(0, imp_inst,
8898 8895 inst->sc_fmri, NULL, NULL, NULL);
8899 8896 }
8900 8897
8901 8898 if (refresh == 1) {
8902 8899 char *name_buf = safe_malloc(max_scf_name_len + 1);
8903 8900
8904 8901 (void) refresh_entity(1, imp_svc, svc->sc_name,
8905 8902 imp_inst, imp_iter, name_buf);
8906 8903 free(name_buf);
8907 8904 }
8908 8905
8909 8906 for (old_dpt = uu_list_first(imp_deleted_dpts);
8910 8907 old_dpt != NULL;
8911 8908 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) {
8912 8909 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8913 8910 old_dpt->sc_pgroup_name,
8914 8911 old_dpt->sc_parent->sc_fmri) != 0) {
8915 8912 warn(gettext("Unable to refresh \"%s\"\n"),
8916 8913 old_dpt->sc_pgroup_fmri);
8917 8914 }
8918 8915 }
8919 8916 }
8920 8917
8921 8918 out:
8922 8919 if (annotation_set) {
8923 8920 /* Remove security audit annotation strings. */
8924 8921 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8925 8922 }
8926 8923
8927 8924 free_imp_globals();
8928 8925 return (ret);
8929 8926 }
8930 8927
8931 8928
8932 8929 /*
8933 8930 * Export. These functions create and output an XML tree of a service
8934 8931 * description from the repository. This is largely the inverse of
8935 8932 * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
8936 8933 *
8937 8934 * - We must include any properties which are not represented specifically by
8938 8935 * a service manifest, e.g., properties created by an admin post-import. To
8939 8936 * do so we'll iterate through all properties and deal with each
8940 8937 * apropriately.
8941 8938 *
8942 8939 * - Children of services and instances must must be in the order set by the
8943 8940 * DTD, but we iterate over the properties in undefined order. The elements
8944 8941 * are not easily (or efficiently) sortable by name. Since there's a fixed
8945 8942 * number of classes of them, however, we'll keep the classes separate and
8946 8943 * assemble them in order.
8947 8944 */
8948 8945
8949 8946 /*
8950 8947 * Convenience function to handle xmlSetProp errors (and type casting).
8951 8948 */
8952 8949 static void
8953 8950 safe_setprop(xmlNodePtr n, const char *name, const char *val)
8954 8951 {
8955 8952 if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
8956 8953 uu_die(gettext("Could not set XML property.\n"));
8957 8954 }
8958 8955
8959 8956 /*
8960 8957 * Convenience function to set an XML attribute to the single value of an
8961 8958 * astring property. If the value happens to be the default, don't set the
8962 8959 * attribute. "dval" should be the default value supplied by the DTD, or
8963 8960 * NULL for no default.
8964 8961 */
8965 8962 static int
8966 8963 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
8967 8964 const char *name, const char *dval)
8968 8965 {
8969 8966 scf_value_t *val;
8970 8967 ssize_t len;
8971 8968 char *str;
8972 8969
8973 8970 val = scf_value_create(g_hndl);
8974 8971 if (val == NULL)
8975 8972 scfdie();
8976 8973
8977 8974 if (prop_get_val(prop, val) != 0) {
8978 8975 scf_value_destroy(val);
8979 8976 return (-1);
8980 8977 }
8981 8978
8982 8979 len = scf_value_get_as_string(val, NULL, 0);
8983 8980 if (len < 0)
8984 8981 scfdie();
8985 8982
8986 8983 str = safe_malloc(len + 1);
8987 8984
8988 8985 if (scf_value_get_as_string(val, str, len + 1) < 0)
8989 8986 scfdie();
8990 8987
8991 8988 scf_value_destroy(val);
8992 8989
8993 8990 if (dval == NULL || strcmp(str, dval) != 0)
8994 8991 safe_setprop(n, name, str);
8995 8992
8996 8993 free(str);
8997 8994
8998 8995 return (0);
8999 8996 }
9000 8997
9001 8998 /*
9002 8999 * As above, but the attribute is always set.
9003 9000 */
9004 9001 static int
9005 9002 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
9006 9003 {
9007 9004 return (set_attr_from_prop_default(prop, n, name, NULL));
9008 9005 }
9009 9006
9010 9007 /*
9011 9008 * Dump the given document onto f, with "'s replaced by ''s.
9012 9009 */
9013 9010 static int
9014 9011 write_service_bundle(xmlDocPtr doc, FILE *f)
9015 9012 {
9016 9013 xmlChar *mem;
9017 9014 int sz, i;
9018 9015
9019 9016 mem = NULL;
9020 9017 xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
9021 9018
9022 9019 if (mem == NULL) {
9023 9020 semerr(gettext("Could not dump XML tree.\n"));
9024 9021 return (-1);
9025 9022 }
9026 9023
9027 9024 /*
9028 9025 * Fortunately libxml produces " instead of ", so we can blindly
9029 9026 * replace all " with '. Cursed libxml2! Why must you #ifdef out the
9030 9027 * ' code?!
9031 9028 */
9032 9029 for (i = 0; i < sz; ++i) {
9033 9030 char c = (char)mem[i];
9034 9031
9035 9032 if (c == '"')
9036 9033 (void) fputc('\'', f);
9037 9034 else if (c == '\'')
9038 9035 (void) fwrite("'", sizeof ("'") - 1, 1, f);
9039 9036 else
9040 9037 (void) fputc(c, f);
9041 9038 }
9042 9039
9043 9040 return (0);
9044 9041 }
9045 9042
9046 9043 /*
9047 9044 * Create the DOM elements in elts necessary to (generically) represent prop
9048 9045 * (i.e., a property or propval element). If the name of the property is
9049 9046 * known, it should be passed as name_arg. Otherwise, pass NULL.
9050 9047 */
9051 9048 static void
9052 9049 export_property(scf_property_t *prop, const char *name_arg,
9053 9050 struct pg_elts *elts, int flags)
9054 9051 {
9055 9052 const char *type;
9056 9053 scf_error_t err = 0;
9057 9054 xmlNodePtr pnode, lnode;
9058 9055 char *lnname;
9059 9056 int ret;
9060 9057
9061 9058 /* name */
9062 9059 if (name_arg != NULL) {
9063 9060 (void) strcpy(exp_str, name_arg);
9064 9061 } else {
9065 9062 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
9066 9063 scfdie();
9067 9064 }
9068 9065
9069 9066 /* type */
9070 9067 type = prop_to_typestr(prop);
9071 9068 if (type == NULL)
9072 9069 uu_die(gettext("Can't export property %s: unknown type.\n"),
9073 9070 exp_str);
9074 9071
9075 9072 /* If we're exporting values, and there's just one, export it here. */
9076 9073 if (!(flags & SCE_ALL_VALUES))
9077 9074 goto empty;
9078 9075
9079 9076 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
9080 9077 xmlNodePtr n;
9081 9078
9082 9079 /* Single value, so use propval */
9083 9080 n = xmlNewNode(NULL, (xmlChar *)"propval");
9084 9081 if (n == NULL)
9085 9082 uu_die(emsg_create_xml);
9086 9083
9087 9084 safe_setprop(n, name_attr, exp_str);
9088 9085 safe_setprop(n, type_attr, type);
9089 9086
9090 9087 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9091 9088 scfdie();
9092 9089 safe_setprop(n, value_attr, exp_str);
9093 9090
9094 9091 if (elts->propvals == NULL)
9095 9092 elts->propvals = n;
9096 9093 else
9097 9094 (void) xmlAddSibling(elts->propvals, n);
9098 9095
9099 9096 return;
9100 9097 }
9101 9098
9102 9099 err = scf_error();
9103 9100
9104 9101 if (err == SCF_ERROR_PERMISSION_DENIED) {
9105 9102 semerr(emsg_permission_denied);
9106 9103 return;
9107 9104 }
9108 9105
9109 9106 if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
9110 9107 err != SCF_ERROR_NOT_FOUND &&
9111 9108 err != SCF_ERROR_PERMISSION_DENIED)
9112 9109 scfdie();
9113 9110
9114 9111 empty:
9115 9112 /* Multiple (or no) values, so use property */
9116 9113 pnode = xmlNewNode(NULL, (xmlChar *)"property");
9117 9114 if (pnode == NULL)
9118 9115 uu_die(emsg_create_xml);
9119 9116
9120 9117 safe_setprop(pnode, name_attr, exp_str);
9121 9118 safe_setprop(pnode, type_attr, type);
9122 9119
9123 9120 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
9124 9121 lnname = uu_msprintf("%s_list", type);
9125 9122 if (lnname == NULL)
9126 9123 uu_die(gettext("Could not create string"));
9127 9124
9128 9125 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
9129 9126 if (lnode == NULL)
9130 9127 uu_die(emsg_create_xml);
9131 9128
9132 9129 uu_free(lnname);
9133 9130
9134 9131 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
9135 9132 scfdie();
9136 9133
9137 9134 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
9138 9135 1) {
9139 9136 xmlNodePtr vn;
9140 9137
9141 9138 vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
9142 9139 NULL);
9143 9140 if (vn == NULL)
9144 9141 uu_die(emsg_create_xml);
9145 9142
9146 9143 if (scf_value_get_as_string(exp_val, exp_str,
9147 9144 exp_str_sz) < 0)
9148 9145 scfdie();
9149 9146 safe_setprop(vn, value_attr, exp_str);
9150 9147 }
9151 9148 if (ret != 0)
9152 9149 scfdie();
9153 9150 }
9154 9151
9155 9152 if (elts->properties == NULL)
9156 9153 elts->properties = pnode;
9157 9154 else
9158 9155 (void) xmlAddSibling(elts->properties, pnode);
9159 9156 }
9160 9157
9161 9158 /*
9162 9159 * Add a property_group element for this property group to elts.
9163 9160 */
9164 9161 static void
9165 9162 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
9166 9163 {
9167 9164 xmlNodePtr n;
9168 9165 struct pg_elts elts;
9169 9166 int ret;
9170 9167 boolean_t read_protected;
9171 9168
9172 9169 n = xmlNewNode(NULL, (xmlChar *)"property_group");
9173 9170
9174 9171 /* name */
9175 9172 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9176 9173 scfdie();
9177 9174 safe_setprop(n, name_attr, exp_str);
9178 9175
9179 9176 /* type */
9180 9177 if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
9181 9178 scfdie();
9182 9179 safe_setprop(n, type_attr, exp_str);
9183 9180
9184 9181 /* properties */
9185 9182 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9186 9183 scfdie();
9187 9184
9188 9185 (void) memset(&elts, 0, sizeof (elts));
9189 9186
9190 9187 /*
9191 9188 * If this property group is not read protected, we always want to
9192 9189 * output all the values. Otherwise, we only output the values if the
9193 9190 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
9194 9191 */
9195 9192 if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
9196 9193 scfdie();
9197 9194
9198 9195 if (!read_protected)
9199 9196 flags |= SCE_ALL_VALUES;
9200 9197
9201 9198 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9202 9199 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9203 9200 scfdie();
9204 9201
9205 9202 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9206 9203 xmlNodePtr m;
9207 9204
9208 9205 m = xmlNewNode(NULL, (xmlChar *)"stability");
9209 9206 if (m == NULL)
9210 9207 uu_die(emsg_create_xml);
9211 9208
9212 9209 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9213 9210 elts.stability = m;
9214 9211 continue;
9215 9212 }
9216 9213
9217 9214 xmlFreeNode(m);
9218 9215 }
9219 9216
9220 9217 export_property(exp_prop, NULL, &elts, flags);
9221 9218 }
9222 9219 if (ret == -1)
9223 9220 scfdie();
9224 9221
9225 9222 (void) xmlAddChild(n, elts.stability);
9226 9223 (void) xmlAddChildList(n, elts.propvals);
9227 9224 (void) xmlAddChildList(n, elts.properties);
9228 9225
9229 9226 if (eelts->property_groups == NULL)
9230 9227 eelts->property_groups = n;
9231 9228 else
9232 9229 (void) xmlAddSibling(eelts->property_groups, n);
9233 9230 }
9234 9231
9235 9232 /*
9236 9233 * Create an XML node representing the dependency described by the given
9237 9234 * property group and put it in eelts. Unless the dependency is not valid, in
9238 9235 * which case create a generic property_group element which represents it and
9239 9236 * put it in eelts.
9240 9237 */
9241 9238 static void
9242 9239 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
9243 9240 {
9244 9241 xmlNodePtr n;
9245 9242 int err = 0, ret;
9246 9243 struct pg_elts elts;
9247 9244
9248 9245 n = xmlNewNode(NULL, (xmlChar *)"dependency");
9249 9246 if (n == NULL)
9250 9247 uu_die(emsg_create_xml);
9251 9248
9252 9249 /*
9253 9250 * If the external flag is present, skip this dependency because it
9254 9251 * should have been created by another manifest.
9255 9252 */
9256 9253 if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
9257 9254 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9258 9255 prop_get_val(exp_prop, exp_val) == 0) {
9259 9256 uint8_t b;
9260 9257
9261 9258 if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
9262 9259 scfdie();
9263 9260
9264 9261 if (b)
9265 9262 return;
9266 9263 }
9267 9264 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
9268 9265 scfdie();
9269 9266
9270 9267 /* Get the required attributes. */
9271 9268
9272 9269 /* name */
9273 9270 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9274 9271 scfdie();
9275 9272 safe_setprop(n, name_attr, exp_str);
9276 9273
9277 9274 /* grouping */
9278 9275 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9279 9276 set_attr_from_prop(exp_prop, n, "grouping") != 0)
9280 9277 err = 1;
9281 9278
9282 9279 /* restart_on */
9283 9280 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9284 9281 set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9285 9282 err = 1;
9286 9283
9287 9284 /* type */
9288 9285 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9289 9286 set_attr_from_prop(exp_prop, n, type_attr) != 0)
9290 9287 err = 1;
9291 9288
9292 9289 /*
9293 9290 * entities: Not required, but if we create no children, it will be
9294 9291 * created as empty on import, so fail if it's missing.
9295 9292 */
9296 9293 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9297 9294 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
9298 9295 scf_iter_t *eiter;
9299 9296 int ret2;
9300 9297
9301 9298 eiter = scf_iter_create(g_hndl);
9302 9299 if (eiter == NULL)
9303 9300 scfdie();
9304 9301
9305 9302 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
9306 9303 scfdie();
9307 9304
9308 9305 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
9309 9306 xmlNodePtr ch;
9310 9307
9311 9308 if (scf_value_get_astring(exp_val, exp_str,
9312 9309 exp_str_sz) < 0)
9313 9310 scfdie();
9314 9311
9315 9312 /*
9316 9313 * service_fmri's must be first, so we can add them
9317 9314 * here.
9318 9315 */
9319 9316 ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
9320 9317 NULL);
9321 9318 if (ch == NULL)
9322 9319 uu_die(emsg_create_xml);
9323 9320
9324 9321 safe_setprop(ch, value_attr, exp_str);
9325 9322 }
9326 9323 if (ret2 == -1)
9327 9324 scfdie();
9328 9325
9329 9326 scf_iter_destroy(eiter);
9330 9327 } else
9331 9328 err = 1;
9332 9329
9333 9330 if (err) {
9334 9331 xmlFreeNode(n);
9335 9332
9336 9333 export_pg(pg, eelts, SCE_ALL_VALUES);
9337 9334
9338 9335 return;
9339 9336 }
9340 9337
9341 9338 /* Iterate through the properties & handle each. */
9342 9339 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9343 9340 scfdie();
9344 9341
9345 9342 (void) memset(&elts, 0, sizeof (elts));
9346 9343
9347 9344 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9348 9345 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9349 9346 scfdie();
9350 9347
9351 9348 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9352 9349 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9353 9350 strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9354 9351 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9355 9352 continue;
9356 9353 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9357 9354 xmlNodePtr m;
9358 9355
9359 9356 m = xmlNewNode(NULL, (xmlChar *)"stability");
9360 9357 if (m == NULL)
9361 9358 uu_die(emsg_create_xml);
9362 9359
9363 9360 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9364 9361 elts.stability = m;
9365 9362 continue;
9366 9363 }
9367 9364
9368 9365 xmlFreeNode(m);
9369 9366 }
9370 9367
9371 9368 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9372 9369 }
9373 9370 if (ret == -1)
9374 9371 scfdie();
9375 9372
9376 9373 (void) xmlAddChild(n, elts.stability);
9377 9374 (void) xmlAddChildList(n, elts.propvals);
9378 9375 (void) xmlAddChildList(n, elts.properties);
9379 9376
9380 9377 if (eelts->dependencies == NULL)
9381 9378 eelts->dependencies = n;
9382 9379 else
9383 9380 (void) xmlAddSibling(eelts->dependencies, n);
9384 9381 }
9385 9382
9386 9383 static xmlNodePtr
9387 9384 export_method_environment(scf_propertygroup_t *pg)
9388 9385 {
9389 9386 xmlNodePtr env;
9390 9387 int ret;
9391 9388 int children = 0;
9392 9389
9393 9390 if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
9394 9391 return (NULL);
9395 9392
9396 9393 env = xmlNewNode(NULL, (xmlChar *)"method_environment");
9397 9394 if (env == NULL)
9398 9395 uu_die(emsg_create_xml);
9399 9396
9400 9397 if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
9401 9398 scfdie();
9402 9399
9403 9400 if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
9404 9401 scfdie();
9405 9402
9406 9403 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
9407 9404 xmlNodePtr ev;
9408 9405 char *cp;
9409 9406
9410 9407 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9411 9408 scfdie();
9412 9409
9413 9410 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
9414 9411 warn(gettext("Invalid environment variable \"%s\".\n"),
9415 9412 exp_str);
9416 9413 continue;
9417 9414 } else if (strncmp(exp_str, "SMF_", 4) == 0) {
9418 9415 warn(gettext("Invalid environment variable \"%s\"; "
9419 9416 "\"SMF_\" prefix is reserved.\n"), exp_str);
9420 9417 continue;
9421 9418 }
9422 9419
9423 9420 *cp = '\0';
9424 9421 cp++;
9425 9422
9426 9423 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
9427 9424 if (ev == NULL)
9428 9425 uu_die(emsg_create_xml);
9429 9426
9430 9427 safe_setprop(ev, name_attr, exp_str);
9431 9428 safe_setprop(ev, value_attr, cp);
9432 9429 children++;
9433 9430 }
9434 9431
9435 9432 if (ret != 0)
9436 9433 scfdie();
9437 9434
9438 9435 if (children == 0) {
9439 9436 xmlFreeNode(env);
9440 9437 return (NULL);
9441 9438 }
9442 9439
9443 9440 return (env);
9444 9441 }
9445 9442
9446 9443 /*
9447 9444 * As above, but for a method property group.
9448 9445 */
9449 9446 static void
9450 9447 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
9451 9448 {
9452 9449 xmlNodePtr n, env;
9453 9450 char *str;
9454 9451 int err = 0, nonenv, ret;
9455 9452 uint8_t use_profile;
9456 9453 struct pg_elts elts;
9457 9454 xmlNodePtr ctxt = NULL;
9458 9455
9459 9456 n = xmlNewNode(NULL, (xmlChar *)"exec_method");
9460 9457
9461 9458 /* Get the required attributes. */
9462 9459
9463 9460 /* name */
9464 9461 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9465 9462 scfdie();
9466 9463 safe_setprop(n, name_attr, exp_str);
9467 9464
9468 9465 /* type */
9469 9466 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9470 9467 set_attr_from_prop(exp_prop, n, type_attr) != 0)
9471 9468 err = 1;
9472 9469
9473 9470 /* exec */
9474 9471 if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
9475 9472 set_attr_from_prop(exp_prop, n, "exec") != 0)
9476 9473 err = 1;
9477 9474
9478 9475 /* timeout */
9479 9476 if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
9480 9477 prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
9481 9478 prop_get_val(exp_prop, exp_val) == 0) {
9482 9479 uint64_t c;
9483 9480
9484 9481 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
9485 9482 scfdie();
9486 9483
9487 9484 str = uu_msprintf("%llu", c);
9488 9485 if (str == NULL)
9489 9486 uu_die(gettext("Could not create string"));
9490 9487
9491 9488 safe_setprop(n, "timeout_seconds", str);
9492 9489 free(str);
9493 9490 } else
9494 9491 err = 1;
9495 9492
9496 9493 if (err) {
9497 9494 xmlFreeNode(n);
9498 9495
9499 9496 export_pg(pg, eelts, SCE_ALL_VALUES);
9500 9497
9501 9498 return;
9502 9499 }
9503 9500
9504 9501
9505 9502 /*
9506 9503 * If we're going to have a method_context child, we need to know
9507 9504 * before we iterate through the properties. Since method_context's
9508 9505 * are optional, we don't want to complain about any properties
9509 9506 * missing if none of them are there. Thus we can't use the
9510 9507 * convenience functions.
9511 9508 */
9512 9509 nonenv =
9513 9510 scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
9514 9511 SCF_SUCCESS ||
9515 9512 scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
9516 9513 SCF_SUCCESS ||
9517 9514 scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
9518 9515 SCF_SUCCESS ||
9519 9516 scf_pg_get_property(pg, SCF_PROPERTY_SECFLAGS, NULL) ==
9520 9517 SCF_SUCCESS ||
9521 9518 scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
9522 9519 SCF_SUCCESS;
9523 9520
9524 9521 if (nonenv) {
9525 9522 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9526 9523 if (ctxt == NULL)
9527 9524 uu_die(emsg_create_xml);
9528 9525
9529 9526 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
9530 9527 0 &&
9531 9528 set_attr_from_prop_default(exp_prop, ctxt,
9532 9529 "working_directory", ":default") != 0)
9533 9530 err = 1;
9534 9531
9535 9532 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
9536 9533 set_attr_from_prop_default(exp_prop, ctxt, "project",
9537 9534 ":default") != 0)
9538 9535 err = 1;
9539 9536
9540 9537 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
9541 9538 0 &&
9542 9539 set_attr_from_prop_default(exp_prop, ctxt,
9543 9540 "resource_pool", ":default") != 0)
9544 9541 err = 1;
9545 9542
9546 9543 if (pg_get_prop(pg, SCF_PROPERTY_SECFLAGS, exp_prop) == 0 &&
9547 9544 set_attr_from_prop_default(exp_prop, ctxt,
9548 9545 "security_flags", ":default") != 0)
9549 9546 err = 1;
9550 9547
9551 9548 /*
9552 9549 * We only want to complain about profile or credential
9553 9550 * properties if we will use them. To determine that we must
9554 9551 * examine USE_PROFILE.
9555 9552 */
9556 9553 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9557 9554 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9558 9555 prop_get_val(exp_prop, exp_val) == 0) {
9559 9556 if (scf_value_get_boolean(exp_val, &use_profile) !=
9560 9557 SCF_SUCCESS) {
9561 9558 scfdie();
9562 9559 }
9563 9560
9564 9561 if (use_profile) {
9565 9562 xmlNodePtr prof;
9566 9563
9567 9564 prof = xmlNewChild(ctxt, NULL,
9568 9565 (xmlChar *)"method_profile", NULL);
9569 9566 if (prof == NULL)
9570 9567 uu_die(emsg_create_xml);
9571 9568
9572 9569 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
9573 9570 exp_prop) != 0 ||
9574 9571 set_attr_from_prop(exp_prop, prof,
9575 9572 name_attr) != 0)
9576 9573 err = 1;
9577 9574 } else {
9578 9575 xmlNodePtr cred;
9579 9576
9580 9577 cred = xmlNewChild(ctxt, NULL,
9581 9578 (xmlChar *)"method_credential", NULL);
9582 9579 if (cred == NULL)
9583 9580 uu_die(emsg_create_xml);
9584 9581
9585 9582 if (pg_get_prop(pg, SCF_PROPERTY_USER,
9586 9583 exp_prop) != 0 ||
9587 9584 set_attr_from_prop(exp_prop, cred,
9588 9585 "user") != 0) {
9589 9586 err = 1;
9590 9587 }
9591 9588
9592 9589 if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
9593 9590 exp_prop) == 0 &&
9594 9591 set_attr_from_prop_default(exp_prop, cred,
9595 9592 "group", ":default") != 0)
9596 9593 err = 1;
9597 9594
9598 9595 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
9599 9596 exp_prop) == 0 &&
9600 9597 set_attr_from_prop_default(exp_prop, cred,
9601 9598 "supp_groups", ":default") != 0)
9602 9599 err = 1;
9603 9600
9604 9601 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
9605 9602 exp_prop) == 0 &&
9606 9603 set_attr_from_prop_default(exp_prop, cred,
9607 9604 "privileges", ":default") != 0)
9608 9605 err = 1;
9609 9606
9610 9607 if (pg_get_prop(pg,
9611 9608 SCF_PROPERTY_LIMIT_PRIVILEGES,
9612 9609 exp_prop) == 0 &&
9613 9610 set_attr_from_prop_default(exp_prop, cred,
9614 9611 "limit_privileges", ":default") != 0)
9615 9612 err = 1;
9616 9613 }
9617 9614 }
9618 9615 }
9619 9616
9620 9617 if ((env = export_method_environment(pg)) != NULL) {
9621 9618 if (ctxt == NULL) {
9622 9619 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9623 9620 if (ctxt == NULL)
9624 9621 uu_die(emsg_create_xml);
9625 9622 }
9626 9623 (void) xmlAddChild(ctxt, env);
9627 9624 }
9628 9625
9629 9626 if (env != NULL || (nonenv && err == 0))
9630 9627 (void) xmlAddChild(n, ctxt);
9631 9628 else
9632 9629 xmlFreeNode(ctxt);
9633 9630
9634 9631 nonenv = (err == 0);
9635 9632
9636 9633 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9637 9634 scfdie();
9638 9635
9639 9636 (void) memset(&elts, 0, sizeof (elts));
9640 9637
9641 9638 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9642 9639 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9643 9640 scfdie();
9644 9641
9645 9642 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9646 9643 strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
9647 9644 strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
9648 9645 continue;
9649 9646 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9650 9647 xmlNodePtr m;
9651 9648
9652 9649 m = xmlNewNode(NULL, (xmlChar *)"stability");
9653 9650 if (m == NULL)
9654 9651 uu_die(emsg_create_xml);
9655 9652
9656 9653 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9657 9654 elts.stability = m;
9658 9655 continue;
9659 9656 }
9660 9657
9661 9658 xmlFreeNode(m);
9662 9659 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
9663 9660 0 ||
9664 9661 strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
9665 9662 strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
9666 9663 strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9667 9664 if (nonenv)
9668 9665 continue;
9669 9666 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
9670 9667 strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
9671 9668 strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
9672 9669 strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
9673 9670 strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0 ||
9674 9671 strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9675 9672 if (nonenv && !use_profile)
9676 9673 continue;
9677 9674 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9678 9675 if (nonenv && use_profile)
9679 9676 continue;
9680 9677 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
9681 9678 if (env != NULL)
9682 9679 continue;
9683 9680 }
9684 9681
9685 9682 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9686 9683 }
9687 9684 if (ret == -1)
9688 9685 scfdie();
9689 9686
9690 9687 (void) xmlAddChild(n, elts.stability);
9691 9688 (void) xmlAddChildList(n, elts.propvals);
9692 9689 (void) xmlAddChildList(n, elts.properties);
9693 9690
9694 9691 if (eelts->exec_methods == NULL)
9695 9692 eelts->exec_methods = n;
9696 9693 else
9697 9694 (void) xmlAddSibling(eelts->exec_methods, n);
9698 9695 }
9699 9696
9700 9697 static void
9701 9698 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
9702 9699 struct entity_elts *eelts)
9703 9700 {
9704 9701 xmlNodePtr pgnode;
9705 9702
9706 9703 pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
9707 9704 if (pgnode == NULL)
9708 9705 uu_die(emsg_create_xml);
9709 9706
9710 9707 safe_setprop(pgnode, name_attr, name);
9711 9708 safe_setprop(pgnode, type_attr, type);
9712 9709
9713 9710 (void) xmlAddChildList(pgnode, elts->propvals);
9714 9711 (void) xmlAddChildList(pgnode, elts->properties);
9715 9712
9716 9713 if (eelts->property_groups == NULL)
9717 9714 eelts->property_groups = pgnode;
9718 9715 else
9719 9716 (void) xmlAddSibling(eelts->property_groups, pgnode);
9720 9717 }
9721 9718
9722 9719 /*
9723 9720 * Process the general property group for a service. This is the one with the
9724 9721 * goodies.
9725 9722 */
9726 9723 static void
9727 9724 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
9728 9725 {
9729 9726 struct pg_elts elts;
9730 9727 int ret;
9731 9728
9732 9729 /*
9733 9730 * In case there are properties which don't correspond to child
9734 9731 * entities of the service entity, we'll set up a pg_elts structure to
9735 9732 * put them in.
9736 9733 */
9737 9734 (void) memset(&elts, 0, sizeof (elts));
9738 9735
9739 9736 /* Walk the properties, looking for special ones. */
9740 9737 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9741 9738 scfdie();
9742 9739
9743 9740 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9744 9741 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9745 9742 scfdie();
9746 9743
9747 9744 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
9748 9745 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9749 9746 prop_get_val(exp_prop, exp_val) == 0) {
9750 9747 uint8_t b;
9751 9748
9752 9749 if (scf_value_get_boolean(exp_val, &b) !=
9753 9750 SCF_SUCCESS)
9754 9751 scfdie();
9755 9752
9756 9753 if (b) {
9757 9754 selts->single_instance =
9758 9755 xmlNewNode(NULL,
9759 9756 (xmlChar *)"single_instance");
9760 9757 if (selts->single_instance == NULL)
9761 9758 uu_die(emsg_create_xml);
9762 9759 }
9763 9760
9764 9761 continue;
9765 9762 }
9766 9763 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9767 9764 xmlNodePtr rnode, sfnode;
9768 9765
9769 9766 rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9770 9767 if (rnode == NULL)
9771 9768 uu_die(emsg_create_xml);
9772 9769
9773 9770 sfnode = xmlNewChild(rnode, NULL,
9774 9771 (xmlChar *)"service_fmri", NULL);
9775 9772 if (sfnode == NULL)
9776 9773 uu_die(emsg_create_xml);
9777 9774
9778 9775 if (set_attr_from_prop(exp_prop, sfnode,
9779 9776 value_attr) == 0) {
9780 9777 selts->restarter = rnode;
9781 9778 continue;
9782 9779 }
9783 9780
9784 9781 xmlFreeNode(rnode);
9785 9782 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
9786 9783 0) {
9787 9784 xmlNodePtr s;
9788 9785
9789 9786 s = xmlNewNode(NULL, (xmlChar *)"stability");
9790 9787 if (s == NULL)
9791 9788 uu_die(emsg_create_xml);
9792 9789
9793 9790 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9794 9791 selts->stability = s;
9795 9792 continue;
9796 9793 }
9797 9794
9798 9795 xmlFreeNode(s);
9799 9796 }
9800 9797
9801 9798 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9802 9799 }
9803 9800 if (ret == -1)
9804 9801 scfdie();
9805 9802
9806 9803 if (elts.propvals != NULL || elts.properties != NULL)
9807 9804 export_pg_elts(&elts, scf_pg_general, scf_group_framework,
9808 9805 selts);
9809 9806 }
9810 9807
9811 9808 static void
9812 9809 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
9813 9810 {
9814 9811 xmlNodePtr n, prof, cred, env;
9815 9812 uint8_t use_profile;
9816 9813 int ret, err = 0;
9817 9814
9818 9815 n = xmlNewNode(NULL, (xmlChar *)"method_context");
9819 9816
9820 9817 env = export_method_environment(pg);
9821 9818
9822 9819 /* Need to know whether we'll use a profile or not. */
9823 9820 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9824 9821 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9825 9822 prop_get_val(exp_prop, exp_val) == 0) {
9826 9823 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
9827 9824 scfdie();
9828 9825
9829 9826 if (use_profile)
9830 9827 prof =
9831 9828 xmlNewChild(n, NULL, (xmlChar *)"method_profile",
9832 9829 NULL);
9833 9830 else
9834 9831 cred =
9835 9832 xmlNewChild(n, NULL, (xmlChar *)"method_credential",
9836 9833 NULL);
9837 9834 }
9838 9835
9839 9836 if (env != NULL)
9840 9837 (void) xmlAddChild(n, env);
9841 9838
9842 9839 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9843 9840 scfdie();
9844 9841
9845 9842 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9846 9843 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9847 9844 scfdie();
9848 9845
9849 9846 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
9850 9847 if (set_attr_from_prop(exp_prop, n,
9851 9848 "working_directory") != 0)
9852 9849 err = 1;
9853 9850 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
9854 9851 if (set_attr_from_prop(exp_prop, n, "project") != 0)
9855 9852 err = 1;
9856 9853 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
9857 9854 if (set_attr_from_prop(exp_prop, n,
9858 9855 "resource_pool") != 0)
9859 9856 err = 1;
9860 9857 } else if (strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9861 9858 if (set_attr_from_prop(exp_prop, n,
9862 9859 "security_flags") != 0)
9863 9860 err = 1;
9864 9861 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9865 9862 /* EMPTY */
9866 9863 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
9867 9864 if (use_profile ||
9868 9865 set_attr_from_prop(exp_prop, cred, "user") != 0)
9869 9866 err = 1;
9870 9867 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
9871 9868 if (use_profile ||
9872 9869 set_attr_from_prop(exp_prop, cred, "group") != 0)
9873 9870 err = 1;
9874 9871 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
9875 9872 if (use_profile || set_attr_from_prop(exp_prop, cred,
9876 9873 "supp_groups") != 0)
9877 9874 err = 1;
9878 9875 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
9879 9876 if (use_profile || set_attr_from_prop(exp_prop, cred,
9880 9877 "privileges") != 0)
9881 9878 err = 1;
9882 9879 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
9883 9880 0) {
9884 9881 if (use_profile || set_attr_from_prop(exp_prop, cred,
9885 9882 "limit_privileges") != 0)
9886 9883 err = 1;
9887 9884 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9888 9885 if (!use_profile || set_attr_from_prop(exp_prop,
9889 9886 prof, name_attr) != 0)
9890 9887 err = 1;
9891 9888 } else {
9892 9889 /* Can't have generic properties in method_context's */
9893 9890 err = 1;
9894 9891 }
9895 9892 }
9896 9893 if (ret == -1)
9897 9894 scfdie();
9898 9895
9899 9896 if (err && env == NULL) {
9900 9897 xmlFreeNode(n);
9901 9898 export_pg(pg, elts, SCE_ALL_VALUES);
9902 9899 return;
9903 9900 }
9904 9901
9905 9902 elts->method_context = n;
9906 9903 }
9907 9904
9908 9905 /*
9909 9906 * Given a dependency property group in the tfmri entity (target fmri), return
9910 9907 * a dependent element which represents it.
9911 9908 */
9912 9909 static xmlNodePtr
9913 9910 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
9914 9911 {
9915 9912 uint8_t b;
9916 9913 xmlNodePtr n, sf;
9917 9914 int err = 0, ret;
9918 9915 struct pg_elts pgelts;
9919 9916
9920 9917 /*
9921 9918 * If external isn't set to true then exporting the service will
9922 9919 * export this as a normal dependency, so we should stop to avoid
9923 9920 * duplication.
9924 9921 */
9925 9922 if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
9926 9923 scf_property_get_value(exp_prop, exp_val) != 0 ||
9927 9924 scf_value_get_boolean(exp_val, &b) != 0 || !b) {
9928 9925 if (g_verbose) {
9929 9926 warn(gettext("Dependent \"%s\" cannot be exported "
9930 9927 "properly because the \"%s\" property of the "
9931 9928 "\"%s\" dependency of %s is not set to true.\n"),
9932 9929 name, scf_property_external, name, tfmri);
9933 9930 }
9934 9931
9935 9932 return (NULL);
9936 9933 }
9937 9934
9938 9935 n = xmlNewNode(NULL, (xmlChar *)"dependent");
9939 9936 if (n == NULL)
9940 9937 uu_die(emsg_create_xml);
9941 9938
9942 9939 safe_setprop(n, name_attr, name);
9943 9940
9944 9941 /* Get the required attributes */
9945 9942 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9946 9943 set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9947 9944 err = 1;
9948 9945
9949 9946 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9950 9947 set_attr_from_prop(exp_prop, n, "grouping") != 0)
9951 9948 err = 1;
9952 9949
9953 9950 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9954 9951 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
9955 9952 prop_get_val(exp_prop, exp_val) == 0) {
9956 9953 /* EMPTY */
9957 9954 } else
9958 9955 err = 1;
9959 9956
9960 9957 if (err) {
9961 9958 xmlFreeNode(n);
9962 9959 return (NULL);
9963 9960 }
9964 9961
9965 9962 sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
9966 9963 if (sf == NULL)
9967 9964 uu_die(emsg_create_xml);
9968 9965
9969 9966 safe_setprop(sf, value_attr, tfmri);
9970 9967
9971 9968 /*
9972 9969 * Now add elements for the other properties.
9973 9970 */
9974 9971 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9975 9972 scfdie();
9976 9973
9977 9974 (void) memset(&pgelts, 0, sizeof (pgelts));
9978 9975
9979 9976 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9980 9977 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9981 9978 scfdie();
9982 9979
9983 9980 if (strcmp(exp_str, scf_property_external) == 0 ||
9984 9981 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9985 9982 strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9986 9983 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9987 9984 continue;
9988 9985 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
9989 9986 if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
9990 9987 prop_get_val(exp_prop, exp_val) == 0) {
9991 9988 char type[sizeof ("service") + 1];
9992 9989
9993 9990 if (scf_value_get_astring(exp_val, type,
9994 9991 sizeof (type)) < 0)
9995 9992 scfdie();
9996 9993
9997 9994 if (strcmp(type, "service") == 0)
9998 9995 continue;
9999 9996 }
10000 9997 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
10001 9998 xmlNodePtr s;
10002 9999
10003 10000 s = xmlNewNode(NULL, (xmlChar *)"stability");
10004 10001 if (s == NULL)
10005 10002 uu_die(emsg_create_xml);
10006 10003
10007 10004 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
10008 10005 pgelts.stability = s;
10009 10006 continue;
10010 10007 }
10011 10008
10012 10009 xmlFreeNode(s);
10013 10010 }
10014 10011
10015 10012 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10016 10013 }
10017 10014 if (ret == -1)
10018 10015 scfdie();
10019 10016
10020 10017 (void) xmlAddChild(n, pgelts.stability);
10021 10018 (void) xmlAddChildList(n, pgelts.propvals);
10022 10019 (void) xmlAddChildList(n, pgelts.properties);
10023 10020
10024 10021 return (n);
10025 10022 }
10026 10023
10027 10024 static void
10028 10025 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
10029 10026 {
10030 10027 scf_propertygroup_t *opg;
10031 10028 scf_iter_t *iter;
10032 10029 char *type, *fmri;
10033 10030 int ret;
10034 10031 struct pg_elts pgelts;
10035 10032 xmlNodePtr n;
10036 10033 scf_error_t serr;
10037 10034
10038 10035 if ((opg = scf_pg_create(g_hndl)) == NULL ||
10039 10036 (iter = scf_iter_create(g_hndl)) == NULL)
10040 10037 scfdie();
10041 10038
10042 10039 /* Can't use exp_prop_iter due to export_dependent(). */
10043 10040 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
10044 10041 scfdie();
10045 10042
10046 10043 type = safe_malloc(max_scf_pg_type_len + 1);
10047 10044
10048 10045 /* Get an extra byte so we can tell if values are too long. */
10049 10046 fmri = safe_malloc(max_scf_fmri_len + 2);
10050 10047
10051 10048 (void) memset(&pgelts, 0, sizeof (pgelts));
10052 10049
10053 10050 while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
10054 10051 void *entity;
10055 10052 int isservice;
10056 10053 scf_type_t ty;
10057 10054
10058 10055 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
10059 10056 scfdie();
10060 10057
10061 10058 if ((ty != SCF_TYPE_ASTRING &&
10062 10059 prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
10063 10060 prop_get_val(exp_prop, exp_val) != 0) {
10064 10061 export_property(exp_prop, NULL, &pgelts,
10065 10062 SCE_ALL_VALUES);
10066 10063 continue;
10067 10064 }
10068 10065
10069 10066 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10070 10067 scfdie();
10071 10068
10072 10069 if (scf_value_get_astring(exp_val, fmri,
10073 10070 max_scf_fmri_len + 2) < 0)
10074 10071 scfdie();
10075 10072
10076 10073 /* Look for a dependency group in the target fmri. */
10077 10074 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
10078 10075 switch (serr) {
10079 10076 case SCF_ERROR_NONE:
10080 10077 break;
10081 10078
10082 10079 case SCF_ERROR_NO_MEMORY:
10083 10080 uu_die(gettext("Out of memory.\n"));
10084 10081 /* NOTREACHED */
10085 10082
10086 10083 case SCF_ERROR_INVALID_ARGUMENT:
10087 10084 if (g_verbose) {
10088 10085 if (scf_property_to_fmri(exp_prop, fmri,
10089 10086 max_scf_fmri_len + 2) < 0)
10090 10087 scfdie();
10091 10088
10092 10089 warn(gettext("The value of %s is not a valid "
10093 10090 "FMRI.\n"), fmri);
10094 10091 }
10095 10092
10096 10093 export_property(exp_prop, exp_str, &pgelts,
10097 10094 SCE_ALL_VALUES);
10098 10095 continue;
10099 10096
10100 10097 case SCF_ERROR_CONSTRAINT_VIOLATED:
10101 10098 if (g_verbose) {
10102 10099 if (scf_property_to_fmri(exp_prop, fmri,
10103 10100 max_scf_fmri_len + 2) < 0)
10104 10101 scfdie();
10105 10102
10106 10103 warn(gettext("The value of %s does not specify "
10107 10104 "a service or an instance.\n"), fmri);
10108 10105 }
10109 10106
10110 10107 export_property(exp_prop, exp_str, &pgelts,
10111 10108 SCE_ALL_VALUES);
10112 10109 continue;
10113 10110
10114 10111 case SCF_ERROR_NOT_FOUND:
10115 10112 if (g_verbose) {
10116 10113 if (scf_property_to_fmri(exp_prop, fmri,
10117 10114 max_scf_fmri_len + 2) < 0)
10118 10115 scfdie();
10119 10116
10120 10117 warn(gettext("The entity specified by %s does "
10121 10118 "not exist.\n"), fmri);
10122 10119 }
10123 10120
10124 10121 export_property(exp_prop, exp_str, &pgelts,
10125 10122 SCE_ALL_VALUES);
10126 10123 continue;
10127 10124
10128 10125 default:
10129 10126 #ifndef NDEBUG
10130 10127 (void) fprintf(stderr, "%s:%d: %s() failed with "
10131 10128 "unexpected error %d.\n", __FILE__, __LINE__,
10132 10129 "fmri_to_entity", serr);
10133 10130 #endif
10134 10131 abort();
10135 10132 }
10136 10133
10137 10134 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
10138 10135 if (scf_error() != SCF_ERROR_NOT_FOUND)
10139 10136 scfdie();
10140 10137
10141 10138 warn(gettext("Entity %s is missing dependency property "
10142 10139 "group %s.\n"), fmri, exp_str);
10143 10140
10144 10141 export_property(exp_prop, NULL, &pgelts,
10145 10142 SCE_ALL_VALUES);
10146 10143 continue;
10147 10144 }
10148 10145
10149 10146 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
10150 10147 scfdie();
10151 10148
10152 10149 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
10153 10150 if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
10154 10151 scfdie();
10155 10152
10156 10153 warn(gettext("Property group %s is not of "
10157 10154 "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
10158 10155
10159 10156 export_property(exp_prop, NULL, &pgelts,
10160 10157 SCE_ALL_VALUES);
10161 10158 continue;
10162 10159 }
10163 10160
10164 10161 n = export_dependent(opg, exp_str, fmri);
10165 10162 if (n == NULL) {
10166 10163 export_property(exp_prop, exp_str, &pgelts,
10167 10164 SCE_ALL_VALUES);
10168 10165 } else {
10169 10166 if (eelts->dependents == NULL)
10170 10167 eelts->dependents = n;
10171 10168 else
10172 10169 (void) xmlAddSibling(eelts->dependents,
10173 10170 n);
10174 10171 }
10175 10172 }
10176 10173 if (ret == -1)
10177 10174 scfdie();
10178 10175
10179 10176 free(fmri);
10180 10177 free(type);
10181 10178
10182 10179 scf_iter_destroy(iter);
10183 10180 scf_pg_destroy(opg);
10184 10181
10185 10182 if (pgelts.propvals != NULL || pgelts.properties != NULL)
10186 10183 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
10187 10184 eelts);
10188 10185 }
10189 10186
10190 10187 static void
10191 10188 make_node(xmlNodePtr *nodep, const char *name)
10192 10189 {
10193 10190 if (*nodep == NULL) {
10194 10191 *nodep = xmlNewNode(NULL, (xmlChar *)name);
10195 10192 if (*nodep == NULL)
10196 10193 uu_die(emsg_create_xml);
10197 10194 }
10198 10195 }
10199 10196
10200 10197 static xmlNodePtr
10201 10198 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
10202 10199 {
10203 10200 int ret;
10204 10201 xmlNodePtr parent = NULL;
10205 10202 xmlNodePtr loctext = NULL;
10206 10203
10207 10204 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10208 10205 scfdie();
10209 10206
10210 10207 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10211 10208 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
10212 10209 prop_get_val(exp_prop, exp_val) != 0)
10213 10210 continue;
10214 10211
10215 10212 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
10216 10213 scfdie();
10217 10214
10218 10215 make_node(&parent, parname);
10219 10216 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
10220 10217 (xmlChar *)exp_str);
10221 10218 if (loctext == NULL)
10222 10219 uu_die(emsg_create_xml);
10223 10220
10224 10221 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10225 10222 scfdie();
10226 10223
10227 10224 safe_setprop(loctext, "xml:lang", exp_str);
10228 10225 }
10229 10226
10230 10227 if (ret == -1)
10231 10228 scfdie();
10232 10229
10233 10230 return (parent);
10234 10231 }
10235 10232
10236 10233 static xmlNodePtr
10237 10234 export_tm_manpage(scf_propertygroup_t *pg)
10238 10235 {
10239 10236 xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
10240 10237 if (manpage == NULL)
10241 10238 uu_die(emsg_create_xml);
10242 10239
10243 10240 if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
10244 10241 set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
10245 10242 pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
10246 10243 set_attr_from_prop(exp_prop, manpage, "section") != 0) {
10247 10244 xmlFreeNode(manpage);
10248 10245 return (NULL);
10249 10246 }
10250 10247
10251 10248 if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
10252 10249 (void) set_attr_from_prop_default(exp_prop,
10253 10250 manpage, "manpath", ":default");
10254 10251
10255 10252 return (manpage);
10256 10253 }
10257 10254
10258 10255 static xmlNodePtr
10259 10256 export_tm_doc_link(scf_propertygroup_t *pg)
10260 10257 {
10261 10258 xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
10262 10259 if (doc_link == NULL)
10263 10260 uu_die(emsg_create_xml);
10264 10261
10265 10262 if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
10266 10263 set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
10267 10264 pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
10268 10265 set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
10269 10266 xmlFreeNode(doc_link);
10270 10267 return (NULL);
10271 10268 }
10272 10269 return (doc_link);
10273 10270 }
10274 10271
10275 10272 /*
10276 10273 * Process template information for a service or instances.
10277 10274 */
10278 10275 static void
10279 10276 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
10280 10277 struct template_elts *telts)
10281 10278 {
10282 10279 size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
10283 10280 size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
10284 10281 xmlNodePtr child = NULL;
10285 10282
10286 10283 if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
10287 10284 scfdie();
10288 10285
10289 10286 if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
10290 10287 telts->common_name = export_tm_loctext(pg, "common_name");
10291 10288 if (telts->common_name == NULL)
10292 10289 export_pg(pg, elts, SCE_ALL_VALUES);
10293 10290 return;
10294 10291 } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
10295 10292 telts->description = export_tm_loctext(pg, "description");
10296 10293 if (telts->description == NULL)
10297 10294 export_pg(pg, elts, SCE_ALL_VALUES);
10298 10295 return;
10299 10296 }
10300 10297
10301 10298 if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
10302 10299 child = export_tm_manpage(pg);
10303 10300 } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
10304 10301 child = export_tm_doc_link(pg);
10305 10302 }
10306 10303
10307 10304 if (child != NULL) {
10308 10305 make_node(&telts->documentation, "documentation");
10309 10306 (void) xmlAddChild(telts->documentation, child);
10310 10307 } else {
10311 10308 export_pg(pg, elts, SCE_ALL_VALUES);
10312 10309 }
10313 10310 }
10314 10311
10315 10312 /*
10316 10313 * Process parameter and paramval elements
10317 10314 */
10318 10315 static void
10319 10316 export_parameter(scf_property_t *prop, const char *name,
10320 10317 struct params_elts *elts)
10321 10318 {
10322 10319 xmlNodePtr param;
10323 10320 scf_error_t err = 0;
10324 10321 int ret;
10325 10322
10326 10323 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
10327 10324 if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL)
10328 10325 uu_die(emsg_create_xml);
10329 10326
10330 10327 safe_setprop(param, name_attr, name);
10331 10328
10332 10329 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
10333 10330 scfdie();
10334 10331 safe_setprop(param, value_attr, exp_str);
10335 10332
10336 10333 if (elts->paramval == NULL)
10337 10334 elts->paramval = param;
10338 10335 else
10339 10336 (void) xmlAddSibling(elts->paramval, param);
10340 10337
10341 10338 return;
10342 10339 }
10343 10340
10344 10341 err = scf_error();
10345 10342
10346 10343 if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
10347 10344 err != SCF_ERROR_NOT_FOUND)
10348 10345 scfdie();
10349 10346
10350 10347 if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL)
10351 10348 uu_die(emsg_create_xml);
10352 10349
10353 10350 safe_setprop(param, name_attr, name);
10354 10351
10355 10352 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
10356 10353 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
10357 10354 scfdie();
10358 10355
10359 10356 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
10360 10357 1) {
10361 10358 xmlNodePtr vn;
10362 10359
10363 10360 if ((vn = xmlNewChild(param, NULL,
10364 10361 (xmlChar *)"value_node", NULL)) == NULL)
10365 10362 uu_die(emsg_create_xml);
10366 10363
10367 10364 if (scf_value_get_as_string(exp_val, exp_str,
10368 10365 exp_str_sz) < 0)
10369 10366 scfdie();
10370 10367
10371 10368 safe_setprop(vn, value_attr, exp_str);
10372 10369 }
10373 10370 if (ret != 0)
10374 10371 scfdie();
10375 10372 }
10376 10373
10377 10374 if (elts->parameter == NULL)
10378 10375 elts->parameter = param;
10379 10376 else
10380 10377 (void) xmlAddSibling(elts->parameter, param);
10381 10378 }
10382 10379
10383 10380 /*
10384 10381 * Process notification parameters for a service or instance
10385 10382 */
10386 10383 static void
10387 10384 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts)
10388 10385 {
10389 10386 xmlNodePtr n, event, *type;
10390 10387 struct params_elts *eelts;
10391 10388 int ret, err, i;
10392 10389
10393 10390 n = xmlNewNode(NULL, (xmlChar *)"notification_parameters");
10394 10391 event = xmlNewNode(NULL, (xmlChar *)"event");
10395 10392 if (n == NULL || event == NULL)
10396 10393 uu_die(emsg_create_xml);
10397 10394
10398 10395 /* event value */
10399 10396 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
10400 10397 scfdie();
10401 10398 safe_setprop(event, value_attr, exp_str);
10402 10399
10403 10400 (void) xmlAddChild(n, event);
10404 10401
10405 10402 if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL ||
10406 10403 (eelts = calloc(URI_SCHEME_NUM,
10407 10404 sizeof (struct params_elts))) == NULL)
10408 10405 uu_die(gettext("Out of memory.\n"));
10409 10406
10410 10407 err = 0;
10411 10408
10412 10409 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10413 10410 scfdie();
10414 10411
10415 10412 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10416 10413 char *t, *p;
10417 10414
10418 10415 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10419 10416 scfdie();
10420 10417
10421 10418 if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) {
10422 10419 /*
10423 10420 * this is not a well formed notification parameters
10424 10421 * element, we should export as regular pg
10425 10422 */
10426 10423 err = 1;
10427 10424 break;
10428 10425 }
10429 10426
10430 10427 if ((i = check_uri_protocol(t)) < 0) {
10431 10428 err = 1;
10432 10429 break;
10433 10430 }
10434 10431
10435 10432 if (type[i] == NULL) {
10436 10433 if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) ==
10437 10434 NULL)
10438 10435 uu_die(emsg_create_xml);
10439 10436
10440 10437 safe_setprop(type[i], name_attr, t);
10441 10438 }
10442 10439 if (strcmp(p, active_attr) == 0) {
10443 10440 if (set_attr_from_prop(exp_prop, type[i],
10444 10441 active_attr) != 0) {
10445 10442 err = 1;
10446 10443 break;
10447 10444 }
10448 10445 continue;
10449 10446 }
10450 10447 /*
10451 10448 * We export the parameter
10452 10449 */
10453 10450 export_parameter(exp_prop, p, &eelts[i]);
10454 10451 }
10455 10452
10456 10453 if (ret == -1)
10457 10454 scfdie();
10458 10455
10459 10456 if (err == 1) {
10460 10457 for (i = 0; i < URI_SCHEME_NUM; ++i)
10461 10458 xmlFree(type[i]);
10462 10459 free(type);
10463 10460
10464 10461 export_pg(pg, elts, SCE_ALL_VALUES);
10465 10462
10466 10463 return;
10467 10464 } else {
10468 10465 for (i = 0; i < URI_SCHEME_NUM; ++i)
10469 10466 if (type[i] != NULL) {
10470 10467 (void) xmlAddChildList(type[i],
10471 10468 eelts[i].paramval);
10472 10469 (void) xmlAddChildList(type[i],
10473 10470 eelts[i].parameter);
10474 10471 (void) xmlAddSibling(event, type[i]);
10475 10472 }
10476 10473 }
10477 10474 free(type);
10478 10475
10479 10476 if (elts->notify_params == NULL)
10480 10477 elts->notify_params = n;
10481 10478 else
10482 10479 (void) xmlAddSibling(elts->notify_params, n);
10483 10480 }
10484 10481
10485 10482 /*
10486 10483 * Process the general property group for an instance.
10487 10484 */
10488 10485 static void
10489 10486 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
10490 10487 struct entity_elts *elts)
10491 10488 {
10492 10489 uint8_t enabled;
10493 10490 struct pg_elts pgelts;
10494 10491 int ret;
10495 10492
10496 10493 /* enabled */
10497 10494 if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
10498 10495 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
10499 10496 prop_get_val(exp_prop, exp_val) == 0) {
10500 10497 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
10501 10498 scfdie();
10502 10499 } else {
10503 10500 enabled = 0;
10504 10501 }
10505 10502
10506 10503 safe_setprop(inode, enabled_attr, enabled ? true : false);
10507 10504
10508 10505 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10509 10506 scfdie();
10510 10507
10511 10508 (void) memset(&pgelts, 0, sizeof (pgelts));
10512 10509
10513 10510 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10514 10511 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10515 10512 scfdie();
10516 10513
10517 10514 if (strcmp(exp_str, scf_property_enabled) == 0) {
10518 10515 continue;
10519 10516 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
10520 10517 xmlNodePtr rnode, sfnode;
10521 10518
10522 10519 rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10523 10520 if (rnode == NULL)
10524 10521 uu_die(emsg_create_xml);
10525 10522
10526 10523 sfnode = xmlNewChild(rnode, NULL,
10527 10524 (xmlChar *)"service_fmri", NULL);
10528 10525 if (sfnode == NULL)
10529 10526 uu_die(emsg_create_xml);
10530 10527
10531 10528 if (set_attr_from_prop(exp_prop, sfnode,
10532 10529 value_attr) == 0) {
10533 10530 elts->restarter = rnode;
10534 10531 continue;
10535 10532 }
10536 10533
10537 10534 xmlFreeNode(rnode);
10538 10535 }
10539 10536
10540 10537 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10541 10538 }
10542 10539 if (ret == -1)
10543 10540 scfdie();
10544 10541
10545 10542 if (pgelts.propvals != NULL || pgelts.properties != NULL)
10546 10543 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10547 10544 elts);
10548 10545 }
10549 10546
10550 10547 /*
10551 10548 * Put an instance element for the given instance into selts.
10552 10549 */
10553 10550 static void
10554 10551 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10555 10552 {
10556 10553 xmlNodePtr n;
10557 10554 boolean_t isdefault;
10558 10555 struct entity_elts elts;
10559 10556 struct template_elts template_elts;
10560 10557 int ret;
10561 10558
10562 10559 n = xmlNewNode(NULL, (xmlChar *)"instance");
10563 10560 if (n == NULL)
10564 10561 uu_die(emsg_create_xml);
10565 10562
10566 10563 /* name */
10567 10564 if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10568 10565 scfdie();
10569 10566 safe_setprop(n, name_attr, exp_str);
10570 10567 isdefault = strcmp(exp_str, "default") == 0;
10571 10568
10572 10569 /* check existance of general pg (since general/enabled is required) */
10573 10570 if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
10574 10571 if (scf_error() != SCF_ERROR_NOT_FOUND)
10575 10572 scfdie();
10576 10573
10577 10574 if (g_verbose) {
10578 10575 if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10579 10576 scfdie();
10580 10577
10581 10578 warn(gettext("Instance %s has no general property "
10582 10579 "group; it will be marked disabled.\n"), exp_str);
10583 10580 }
10584 10581
10585 10582 safe_setprop(n, enabled_attr, false);
10586 10583 } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
10587 10584 strcmp(exp_str, scf_group_framework) != 0) {
10588 10585 if (g_verbose) {
10589 10586 if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10590 10587 scfdie();
10591 10588
10592 10589 warn(gettext("Property group %s is not of type "
10593 10590 "framework; the instance will be marked "
10594 10591 "disabled.\n"), exp_str);
10595 10592 }
10596 10593
10597 10594 safe_setprop(n, enabled_attr, false);
10598 10595 }
10599 10596
10600 10597 /* property groups */
10601 10598 if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
10602 10599 scfdie();
10603 10600
10604 10601 (void) memset(&elts, 0, sizeof (elts));
10605 10602 (void) memset(&template_elts, 0, sizeof (template_elts));
10606 10603
10607 10604 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10608 10605 uint32_t pgflags;
10609 10606
10610 10607 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10611 10608 scfdie();
10612 10609
10613 10610 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10614 10611 continue;
10615 10612
10616 10613 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10617 10614 scfdie();
10618 10615
10619 10616 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10620 10617 export_dependency(exp_pg, &elts);
10621 10618 continue;
10622 10619 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10623 10620 export_method(exp_pg, &elts);
10624 10621 continue;
10625 10622 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10626 10623 if (scf_pg_get_name(exp_pg, exp_str,
10627 10624 max_scf_name_len + 1) < 0)
10628 10625 scfdie();
10629 10626
10630 10627 if (strcmp(exp_str, scf_pg_general) == 0) {
10631 10628 export_inst_general(exp_pg, n, &elts);
10632 10629 continue;
10633 10630 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10634 10631 0) {
10635 10632 export_method_context(exp_pg, &elts);
10636 10633 continue;
10637 10634 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10638 10635 export_dependents(exp_pg, &elts);
10639 10636 continue;
10640 10637 }
10641 10638 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10642 10639 export_template(exp_pg, &elts, &template_elts);
10643 10640 continue;
10644 10641 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10645 10642 export_notify_params(exp_pg, &elts);
10646 10643 continue;
10647 10644 }
10648 10645
10649 10646 /* Ordinary pg. */
10650 10647 export_pg(exp_pg, &elts, flags);
10651 10648 }
10652 10649 if (ret == -1)
10653 10650 scfdie();
10654 10651
10655 10652 if (template_elts.common_name != NULL) {
10656 10653 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10657 10654 (void) xmlAddChild(elts.template, template_elts.common_name);
10658 10655 (void) xmlAddChild(elts.template, template_elts.description);
10659 10656 (void) xmlAddChild(elts.template, template_elts.documentation);
10660 10657 } else {
10661 10658 xmlFreeNode(template_elts.description);
10662 10659 xmlFreeNode(template_elts.documentation);
10663 10660 }
10664 10661
10665 10662 if (isdefault && elts.restarter == NULL &&
10666 10663 elts.dependencies == NULL && elts.method_context == NULL &&
10667 10664 elts.exec_methods == NULL && elts.notify_params == NULL &&
10668 10665 elts.property_groups == NULL && elts.template == NULL) {
10669 10666 xmlChar *eval;
10670 10667
10671 10668 /* This is a default instance */
10672 10669 eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10673 10670
10674 10671 xmlFreeNode(n);
10675 10672
10676 10673 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10677 10674 if (n == NULL)
10678 10675 uu_die(emsg_create_xml);
10679 10676
10680 10677 safe_setprop(n, enabled_attr, (char *)eval);
10681 10678 xmlFree(eval);
10682 10679
10683 10680 selts->create_default_instance = n;
10684 10681 } else {
10685 10682 /* Assemble the children in order. */
10686 10683 (void) xmlAddChild(n, elts.restarter);
10687 10684 (void) xmlAddChildList(n, elts.dependencies);
10688 10685 (void) xmlAddChildList(n, elts.dependents);
10689 10686 (void) xmlAddChild(n, elts.method_context);
10690 10687 (void) xmlAddChildList(n, elts.exec_methods);
10691 10688 (void) xmlAddChildList(n, elts.notify_params);
10692 10689 (void) xmlAddChildList(n, elts.property_groups);
10693 10690 (void) xmlAddChild(n, elts.template);
10694 10691
10695 10692 if (selts->instances == NULL)
10696 10693 selts->instances = n;
10697 10694 else
10698 10695 (void) xmlAddSibling(selts->instances, n);
10699 10696 }
10700 10697 }
10701 10698
10702 10699 /*
10703 10700 * Return a service element for the given service.
10704 10701 */
10705 10702 static xmlNodePtr
10706 10703 export_service(scf_service_t *svc, int flags)
10707 10704 {
10708 10705 xmlNodePtr snode;
10709 10706 struct entity_elts elts;
10710 10707 struct template_elts template_elts;
10711 10708 int ret;
10712 10709
10713 10710 snode = xmlNewNode(NULL, (xmlChar *)"service");
10714 10711 if (snode == NULL)
10715 10712 uu_die(emsg_create_xml);
10716 10713
10717 10714 /* Get & set name attribute */
10718 10715 if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
10719 10716 scfdie();
10720 10717 safe_setprop(snode, name_attr, exp_str);
10721 10718
10722 10719 safe_setprop(snode, type_attr, "service");
10723 10720 safe_setprop(snode, "version", "0");
10724 10721
10725 10722 /* Acquire child elements. */
10726 10723 if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
10727 10724 scfdie();
10728 10725
10729 10726 (void) memset(&elts, 0, sizeof (elts));
10730 10727 (void) memset(&template_elts, 0, sizeof (template_elts));
10731 10728
10732 10729 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10733 10730 uint32_t pgflags;
10734 10731
10735 10732 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10736 10733 scfdie();
10737 10734
10738 10735 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10739 10736 continue;
10740 10737
10741 10738 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10742 10739 scfdie();
10743 10740
10744 10741 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10745 10742 export_dependency(exp_pg, &elts);
10746 10743 continue;
10747 10744 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10748 10745 export_method(exp_pg, &elts);
10749 10746 continue;
10750 10747 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10751 10748 if (scf_pg_get_name(exp_pg, exp_str,
10752 10749 max_scf_name_len + 1) < 0)
10753 10750 scfdie();
10754 10751
10755 10752 if (strcmp(exp_str, scf_pg_general) == 0) {
10756 10753 export_svc_general(exp_pg, &elts);
10757 10754 continue;
10758 10755 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10759 10756 0) {
10760 10757 export_method_context(exp_pg, &elts);
10761 10758 continue;
10762 10759 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10763 10760 export_dependents(exp_pg, &elts);
10764 10761 continue;
10765 10762 } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10766 10763 continue;
10767 10764 }
10768 10765 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10769 10766 export_template(exp_pg, &elts, &template_elts);
10770 10767 continue;
10771 10768 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10772 10769 export_notify_params(exp_pg, &elts);
10773 10770 continue;
10774 10771 }
10775 10772
10776 10773 export_pg(exp_pg, &elts, flags);
10777 10774 }
10778 10775 if (ret == -1)
10779 10776 scfdie();
10780 10777
10781 10778 if (template_elts.common_name != NULL) {
10782 10779 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10783 10780 (void) xmlAddChild(elts.template, template_elts.common_name);
10784 10781 (void) xmlAddChild(elts.template, template_elts.description);
10785 10782 (void) xmlAddChild(elts.template, template_elts.documentation);
10786 10783 } else {
10787 10784 xmlFreeNode(template_elts.description);
10788 10785 xmlFreeNode(template_elts.documentation);
10789 10786 }
10790 10787
10791 10788 /* Iterate instances */
10792 10789 if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
10793 10790 scfdie();
10794 10791
10795 10792 while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10796 10793 export_instance(exp_inst, &elts, flags);
10797 10794 if (ret == -1)
10798 10795 scfdie();
10799 10796
10800 10797 /* Now add all of the accumulated elements in order. */
10801 10798 (void) xmlAddChild(snode, elts.create_default_instance);
10802 10799 (void) xmlAddChild(snode, elts.single_instance);
10803 10800 (void) xmlAddChild(snode, elts.restarter);
10804 10801 (void) xmlAddChildList(snode, elts.dependencies);
10805 10802 (void) xmlAddChildList(snode, elts.dependents);
10806 10803 (void) xmlAddChild(snode, elts.method_context);
10807 10804 (void) xmlAddChildList(snode, elts.exec_methods);
10808 10805 (void) xmlAddChildList(snode, elts.notify_params);
10809 10806 (void) xmlAddChildList(snode, elts.property_groups);
10810 10807 (void) xmlAddChildList(snode, elts.instances);
10811 10808 (void) xmlAddChild(snode, elts.stability);
10812 10809 (void) xmlAddChild(snode, elts.template);
10813 10810
10814 10811 return (snode);
10815 10812 }
10816 10813
10817 10814 static int
10818 10815 export_callback(void *data, scf_walkinfo_t *wip)
10819 10816 {
10820 10817 FILE *f;
10821 10818 xmlDocPtr doc;
10822 10819 xmlNodePtr sb;
10823 10820 int result;
10824 10821 struct export_args *argsp = (struct export_args *)data;
10825 10822
10826 10823 if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
10827 10824 (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10828 10825 (exp_prop = scf_property_create(g_hndl)) == NULL ||
10829 10826 (exp_val = scf_value_create(g_hndl)) == NULL ||
10830 10827 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10831 10828 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10832 10829 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10833 10830 (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10834 10831 scfdie();
10835 10832
10836 10833 exp_str_sz = max_scf_len + 1;
10837 10834 exp_str = safe_malloc(exp_str_sz);
10838 10835
10839 10836 if (argsp->filename != NULL) {
10840 10837 errno = 0;
10841 10838 f = fopen(argsp->filename, "wb");
10842 10839 if (f == NULL) {
10843 10840 if (errno == 0)
10844 10841 uu_die(gettext("Could not open \"%s\": no free "
10845 10842 "stdio streams.\n"), argsp->filename);
10846 10843 else
10847 10844 uu_die(gettext("Could not open \"%s\""),
10848 10845 argsp->filename);
10849 10846 }
10850 10847 } else
10851 10848 f = stdout;
10852 10849
10853 10850 doc = xmlNewDoc((xmlChar *)"1.0");
10854 10851 if (doc == NULL)
10855 10852 uu_die(gettext("Could not create XML document.\n"));
10856 10853
10857 10854 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10858 10855 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10859 10856 uu_die(emsg_create_xml);
10860 10857
10861 10858 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10862 10859 if (sb == NULL)
10863 10860 uu_die(emsg_create_xml);
10864 10861 safe_setprop(sb, type_attr, "manifest");
10865 10862 safe_setprop(sb, name_attr, "export");
10866 10863 (void) xmlAddSibling(doc->children, sb);
10867 10864
10868 10865 (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
10869 10866
10870 10867 result = write_service_bundle(doc, f);
10871 10868
10872 10869 free(exp_str);
10873 10870 scf_iter_destroy(exp_val_iter);
10874 10871 scf_iter_destroy(exp_prop_iter);
10875 10872 scf_iter_destroy(exp_pg_iter);
10876 10873 scf_iter_destroy(exp_inst_iter);
10877 10874 scf_value_destroy(exp_val);
10878 10875 scf_property_destroy(exp_prop);
10879 10876 scf_pg_destroy(exp_pg);
10880 10877 scf_instance_destroy(exp_inst);
10881 10878
10882 10879 xmlFreeDoc(doc);
10883 10880
10884 10881 if (f != stdout)
10885 10882 (void) fclose(f);
10886 10883
10887 10884 return (result);
10888 10885 }
10889 10886
10890 10887 /*
10891 10888 * Get the service named by fmri, build an XML tree which represents it, and
10892 10889 * dump it into filename (or stdout if filename is NULL).
10893 10890 */
10894 10891 int
10895 10892 lscf_service_export(char *fmri, const char *filename, int flags)
10896 10893 {
10897 10894 struct export_args args;
10898 10895 char *fmridup;
10899 10896 const char *scope, *svc, *inst;
10900 10897 size_t cblen = 3 * max_scf_name_len;
10901 10898 char *canonbuf = alloca(cblen);
10902 10899 int ret, err;
10903 10900
10904 10901 lscf_prep_hndl();
10905 10902
10906 10903 bzero(&args, sizeof (args));
10907 10904 args.filename = filename;
10908 10905 args.flags = flags;
10909 10906
10910 10907 /*
10911 10908 * If some poor user has passed an exact instance FMRI, of the sort
10912 10909 * one might cut and paste from svcs(1) or an error message, warn
10913 10910 * and chop off the instance instead of failing.
10914 10911 */
10915 10912 fmridup = alloca(strlen(fmri) + 1);
10916 10913 (void) strcpy(fmridup, fmri);
10917 10914 if (strncmp(fmridup, SCF_FMRI_SVC_PREFIX,
10918 10915 sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 &&
10919 10916 scf_parse_svc_fmri(fmridup, &scope, &svc, &inst, NULL, NULL) == 0 &&
10920 10917 inst != NULL) {
10921 10918 (void) strlcpy(canonbuf, "svc:/", cblen);
10922 10919 if (strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
10923 10920 (void) strlcat(canonbuf, "/", cblen);
10924 10921 (void) strlcat(canonbuf, scope, cblen);
10925 10922 }
10926 10923 (void) strlcat(canonbuf, svc, cblen);
10927 10924 fmri = canonbuf;
10928 10925
10929 10926 warn(gettext("Only services may be exported; ignoring "
10930 10927 "instance portion of argument.\n"));
10931 10928 }
10932 10929
10933 10930 err = 0;
10934 10931 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10935 10932 SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10936 10933 &args, &err, semerr)) != 0) {
10937 10934 if (ret != -1)
10938 10935 semerr(gettext("Failed to walk instances: %s\n"),
10939 10936 scf_strerror(ret));
10940 10937 return (-1);
10941 10938 }
10942 10939
10943 10940 /*
10944 10941 * Error message has already been printed.
10945 10942 */
10946 10943 if (err != 0)
10947 10944 return (-1);
10948 10945
10949 10946 return (0);
10950 10947 }
10951 10948
10952 10949
10953 10950 /*
10954 10951 * Archive
10955 10952 */
10956 10953
10957 10954 static xmlNodePtr
10958 10955 make_archive(int flags)
10959 10956 {
10960 10957 xmlNodePtr sb;
10961 10958 scf_scope_t *scope;
10962 10959 scf_service_t *svc;
10963 10960 scf_iter_t *iter;
10964 10961 int r;
10965 10962
10966 10963 if ((scope = scf_scope_create(g_hndl)) == NULL ||
10967 10964 (svc = scf_service_create(g_hndl)) == NULL ||
10968 10965 (iter = scf_iter_create(g_hndl)) == NULL ||
10969 10966 (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10970 10967 (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10971 10968 (exp_prop = scf_property_create(g_hndl)) == NULL ||
10972 10969 (exp_val = scf_value_create(g_hndl)) == NULL ||
10973 10970 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10974 10971 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10975 10972 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10976 10973 (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10977 10974 scfdie();
10978 10975
10979 10976 exp_str_sz = max_scf_len + 1;
10980 10977 exp_str = safe_malloc(exp_str_sz);
10981 10978
10982 10979 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10983 10980 if (sb == NULL)
10984 10981 uu_die(emsg_create_xml);
10985 10982 safe_setprop(sb, type_attr, "archive");
10986 10983 safe_setprop(sb, name_attr, "none");
10987 10984
10988 10985 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
10989 10986 scfdie();
10990 10987 if (scf_iter_scope_services(iter, scope) != 0)
10991 10988 scfdie();
10992 10989
10993 10990 for (;;) {
10994 10991 r = scf_iter_next_service(iter, svc);
10995 10992 if (r == 0)
10996 10993 break;
10997 10994 if (r != 1)
10998 10995 scfdie();
10999 10996
11000 10997 if (scf_service_get_name(svc, exp_str,
11001 10998 max_scf_name_len + 1) < 0)
11002 10999 scfdie();
11003 11000
11004 11001 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
11005 11002 continue;
11006 11003
11007 11004 (void) xmlAddChild(sb, export_service(svc, flags));
11008 11005 }
11009 11006
11010 11007 free(exp_str);
11011 11008
11012 11009 scf_iter_destroy(exp_val_iter);
11013 11010 scf_iter_destroy(exp_prop_iter);
11014 11011 scf_iter_destroy(exp_pg_iter);
11015 11012 scf_iter_destroy(exp_inst_iter);
11016 11013 scf_value_destroy(exp_val);
11017 11014 scf_property_destroy(exp_prop);
11018 11015 scf_pg_destroy(exp_pg);
11019 11016 scf_instance_destroy(exp_inst);
11020 11017 scf_iter_destroy(iter);
11021 11018 scf_service_destroy(svc);
11022 11019 scf_scope_destroy(scope);
11023 11020
11024 11021 return (sb);
11025 11022 }
11026 11023
11027 11024 int
11028 11025 lscf_archive(const char *filename, int flags)
11029 11026 {
11030 11027 FILE *f;
11031 11028 xmlDocPtr doc;
11032 11029 int result;
11033 11030
11034 11031 lscf_prep_hndl();
11035 11032
11036 11033 if (filename != NULL) {
11037 11034 errno = 0;
11038 11035 f = fopen(filename, "wb");
11039 11036 if (f == NULL) {
11040 11037 if (errno == 0)
11041 11038 uu_die(gettext("Could not open \"%s\": no free "
11042 11039 "stdio streams.\n"), filename);
11043 11040 else
11044 11041 uu_die(gettext("Could not open \"%s\""),
11045 11042 filename);
11046 11043 }
11047 11044 } else
11048 11045 f = stdout;
11049 11046
11050 11047 doc = xmlNewDoc((xmlChar *)"1.0");
11051 11048 if (doc == NULL)
11052 11049 uu_die(gettext("Could not create XML document.\n"));
11053 11050
11054 11051 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11055 11052 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11056 11053 uu_die(emsg_create_xml);
11057 11054
11058 11055 (void) xmlAddSibling(doc->children, make_archive(flags));
11059 11056
11060 11057 result = write_service_bundle(doc, f);
11061 11058
11062 11059 xmlFreeDoc(doc);
11063 11060
11064 11061 if (f != stdout)
11065 11062 (void) fclose(f);
11066 11063
11067 11064 return (result);
11068 11065 }
11069 11066
11070 11067
11071 11068 /*
11072 11069 * "Extract" a profile.
11073 11070 */
11074 11071 int
11075 11072 lscf_profile_extract(const char *filename)
11076 11073 {
11077 11074 FILE *f;
11078 11075 xmlDocPtr doc;
11079 11076 xmlNodePtr sb, snode, inode;
11080 11077 scf_scope_t *scope;
11081 11078 scf_service_t *svc;
11082 11079 scf_instance_t *inst;
11083 11080 scf_propertygroup_t *pg;
11084 11081 scf_property_t *prop;
11085 11082 scf_value_t *val;
11086 11083 scf_iter_t *siter, *iiter;
11087 11084 int r, s;
11088 11085 char *namebuf;
11089 11086 uint8_t b;
11090 11087 int result;
11091 11088
11092 11089 lscf_prep_hndl();
11093 11090
11094 11091 if (filename != NULL) {
11095 11092 errno = 0;
11096 11093 f = fopen(filename, "wb");
11097 11094 if (f == NULL) {
11098 11095 if (errno == 0)
11099 11096 uu_die(gettext("Could not open \"%s\": no "
11100 11097 "free stdio streams.\n"), filename);
11101 11098 else
11102 11099 uu_die(gettext("Could not open \"%s\""),
11103 11100 filename);
11104 11101 }
11105 11102 } else
11106 11103 f = stdout;
11107 11104
11108 11105 doc = xmlNewDoc((xmlChar *)"1.0");
11109 11106 if (doc == NULL)
11110 11107 uu_die(gettext("Could not create XML document.\n"));
11111 11108
11112 11109 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11113 11110 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11114 11111 uu_die(emsg_create_xml);
11115 11112
11116 11113 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
11117 11114 if (sb == NULL)
11118 11115 uu_die(emsg_create_xml);
11119 11116 safe_setprop(sb, type_attr, "profile");
11120 11117 safe_setprop(sb, name_attr, "extract");
11121 11118 (void) xmlAddSibling(doc->children, sb);
11122 11119
11123 11120 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11124 11121 (svc = scf_service_create(g_hndl)) == NULL ||
11125 11122 (inst = scf_instance_create(g_hndl)) == NULL ||
11126 11123 (pg = scf_pg_create(g_hndl)) == NULL ||
11127 11124 (prop = scf_property_create(g_hndl)) == NULL ||
11128 11125 (val = scf_value_create(g_hndl)) == NULL ||
11129 11126 (siter = scf_iter_create(g_hndl)) == NULL ||
11130 11127 (iiter = scf_iter_create(g_hndl)) == NULL)
11131 11128 scfdie();
11132 11129
11133 11130 if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
11134 11131 scfdie();
11135 11132
11136 11133 if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
11137 11134 scfdie();
11138 11135
11139 11136 namebuf = safe_malloc(max_scf_name_len + 1);
11140 11137
11141 11138 while ((r = scf_iter_next_service(siter, svc)) == 1) {
11142 11139 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
11143 11140 scfdie();
11144 11141
11145 11142 snode = xmlNewNode(NULL, (xmlChar *)"service");
11146 11143 if (snode == NULL)
11147 11144 uu_die(emsg_create_xml);
11148 11145
11149 11146 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
11150 11147 0)
11151 11148 scfdie();
11152 11149
11153 11150 safe_setprop(snode, name_attr, namebuf);
11154 11151
11155 11152 safe_setprop(snode, type_attr, "service");
11156 11153 safe_setprop(snode, "version", "0");
11157 11154
11158 11155 while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
11159 11156 if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
11160 11157 SCF_SUCCESS) {
11161 11158 if (scf_error() != SCF_ERROR_NOT_FOUND)
11162 11159 scfdie();
11163 11160
11164 11161 if (g_verbose) {
11165 11162 ssize_t len;
11166 11163 char *fmri;
11167 11164
11168 11165 len =
11169 11166 scf_instance_to_fmri(inst, NULL, 0);
11170 11167 if (len < 0)
11171 11168 scfdie();
11172 11169
11173 11170 fmri = safe_malloc(len + 1);
11174 11171
11175 11172 if (scf_instance_to_fmri(inst, fmri,
11176 11173 len + 1) < 0)
11177 11174 scfdie();
11178 11175
11179 11176 warn("Instance %s has no \"%s\" "
11180 11177 "property group.\n", fmri,
11181 11178 scf_pg_general);
11182 11179
11183 11180 free(fmri);
11184 11181 }
11185 11182
11186 11183 continue;
11187 11184 }
11188 11185
11189 11186 if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
11190 11187 prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
11191 11188 prop_get_val(prop, val) != 0)
11192 11189 continue;
11193 11190
11194 11191 inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
11195 11192 NULL);
11196 11193 if (inode == NULL)
11197 11194 uu_die(emsg_create_xml);
11198 11195
11199 11196 if (scf_instance_get_name(inst, namebuf,
11200 11197 max_scf_name_len + 1) < 0)
11201 11198 scfdie();
11202 11199
11203 11200 safe_setprop(inode, name_attr, namebuf);
11204 11201
11205 11202 if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
11206 11203 scfdie();
11207 11204
11208 11205 safe_setprop(inode, enabled_attr, b ? true : false);
11209 11206 }
11210 11207 if (s < 0)
11211 11208 scfdie();
11212 11209
11213 11210 if (snode->children != NULL)
11214 11211 (void) xmlAddChild(sb, snode);
11215 11212 else
11216 11213 xmlFreeNode(snode);
11217 11214 }
11218 11215 if (r < 0)
11219 11216 scfdie();
11220 11217
11221 11218 free(namebuf);
11222 11219
11223 11220 result = write_service_bundle(doc, f);
11224 11221
11225 11222 xmlFreeDoc(doc);
11226 11223
11227 11224 if (f != stdout)
11228 11225 (void) fclose(f);
11229 11226
11230 11227 return (result);
11231 11228 }
11232 11229
11233 11230
11234 11231 /*
11235 11232 * Entity manipulation commands
11236 11233 */
11237 11234
11238 11235 /*
11239 11236 * Entity selection. If no entity is selected, then the current scope is in
11240 11237 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected,
11241 11238 * only cur_inst is NULL, and when an instance is selected, none are NULL.
11242 11239 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
11243 11240 * cur_inst will be non-NULL.
11244 11241 */
11245 11242
11246 11243 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
11247 11244 static int
11248 11245 select_inst(const char *name)
11249 11246 {
11250 11247 scf_instance_t *inst;
11251 11248 scf_error_t err;
11252 11249
11253 11250 assert(cur_svc != NULL);
11254 11251
11255 11252 inst = scf_instance_create(g_hndl);
11256 11253 if (inst == NULL)
11257 11254 scfdie();
11258 11255
11259 11256 if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
11260 11257 cur_inst = inst;
11261 11258 return (0);
11262 11259 }
11263 11260
11264 11261 err = scf_error();
11265 11262 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11266 11263 scfdie();
11267 11264
11268 11265 scf_instance_destroy(inst);
11269 11266 return (1);
11270 11267 }
11271 11268
11272 11269 /* Returns as above. */
11273 11270 static int
11274 11271 select_svc(const char *name)
11275 11272 {
11276 11273 scf_service_t *svc;
11277 11274 scf_error_t err;
11278 11275
11279 11276 assert(cur_scope != NULL);
11280 11277
11281 11278 svc = scf_service_create(g_hndl);
11282 11279 if (svc == NULL)
11283 11280 scfdie();
11284 11281
11285 11282 if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
11286 11283 cur_svc = svc;
11287 11284 return (0);
11288 11285 }
11289 11286
11290 11287 err = scf_error();
11291 11288 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11292 11289 scfdie();
11293 11290
11294 11291 scf_service_destroy(svc);
11295 11292 return (1);
11296 11293 }
11297 11294
11298 11295 /* ARGSUSED */
11299 11296 static int
11300 11297 select_callback(void *unused, scf_walkinfo_t *wip)
11301 11298 {
11302 11299 scf_instance_t *inst;
11303 11300 scf_service_t *svc;
11304 11301 scf_scope_t *scope;
11305 11302
11306 11303 if (wip->inst != NULL) {
11307 11304 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11308 11305 (svc = scf_service_create(g_hndl)) == NULL ||
11309 11306 (inst = scf_instance_create(g_hndl)) == NULL)
11310 11307 scfdie();
11311 11308
11312 11309 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11313 11310 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11314 11311 scfdie();
11315 11312 } else {
11316 11313 assert(wip->svc != NULL);
11317 11314
11318 11315 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11319 11316 (svc = scf_service_create(g_hndl)) == NULL)
11320 11317 scfdie();
11321 11318
11322 11319 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11323 11320 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11324 11321 scfdie();
11325 11322
11326 11323 inst = NULL;
11327 11324 }
11328 11325
11329 11326 /* Clear out the current selection */
11330 11327 assert(cur_scope != NULL);
11331 11328 scf_scope_destroy(cur_scope);
11332 11329 scf_service_destroy(cur_svc);
11333 11330 scf_instance_destroy(cur_inst);
11334 11331
11335 11332 cur_scope = scope;
11336 11333 cur_svc = svc;
11337 11334 cur_inst = inst;
11338 11335
11339 11336 return (0);
11340 11337 }
11341 11338
11342 11339 static int
11343 11340 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
11344 11341 {
11345 11342 char **fmri = fmri_p;
11346 11343
11347 11344 *fmri = strdup(wip->fmri);
11348 11345 if (*fmri == NULL)
11349 11346 uu_die(gettext("Out of memory.\n"));
11350 11347
11351 11348 return (0);
11352 11349 }
11353 11350
11354 11351 /*
11355 11352 * validate [fmri]
11356 11353 * Perform the validation of an FMRI instance.
11357 11354 */
11358 11355 void
11359 11356 lscf_validate_fmri(const char *fmri)
11360 11357 {
11361 11358 int ret = 0;
11362 11359 size_t inst_sz;
11363 11360 char *inst_fmri = NULL;
11364 11361 scf_tmpl_errors_t *errs = NULL;
11365 11362 char *snapbuf = NULL;
11366 11363
11367 11364 lscf_prep_hndl();
11368 11365
11369 11366 if (fmri == NULL) {
11370 11367 inst_sz = max_scf_fmri_len + 1;
11371 11368 inst_fmri = safe_malloc(inst_sz);
11372 11369
11373 11370 if (cur_snap != NULL) {
11374 11371 snapbuf = safe_malloc(max_scf_name_len + 1);
11375 11372 if (scf_snapshot_get_name(cur_snap, snapbuf,
11376 11373 max_scf_name_len + 1) < 0)
11377 11374 scfdie();
11378 11375 }
11379 11376 if (cur_inst == NULL) {
11380 11377 semerr(gettext("No instance selected\n"));
11381 11378 goto cleanup;
11382 11379 } else if (scf_instance_to_fmri(cur_inst, inst_fmri,
11383 11380 inst_sz) >= inst_sz) {
11384 11381 /* sanity check. Should never get here */
11385 11382 uu_die(gettext("Unexpected error! file %s, line %d\n"),
11386 11383 __FILE__, __LINE__);
11387 11384 }
11388 11385 } else {
11389 11386 scf_error_t scf_err;
11390 11387 int err = 0;
11391 11388
11392 11389 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
11393 11390 validate_callback, &inst_fmri, &err, semerr)) != 0) {
11394 11391 uu_warn("Failed to walk instances: %s\n",
11395 11392 scf_strerror(scf_err));
11396 11393 goto cleanup;
11397 11394 }
11398 11395 if (err != 0) {
11399 11396 /* error message displayed by scf_walk_fmri */
11400 11397 goto cleanup;
11401 11398 }
11402 11399 }
11403 11400
11404 11401 ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
11405 11402 SCF_TMPL_VALIDATE_FLAG_CURRENT);
11406 11403 if (ret == -1) {
11407 11404 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
11408 11405 warn(gettext("Template data for %s is invalid. "
11409 11406 "Consider reverting to a previous snapshot or "
11410 11407 "restoring original configuration.\n"), inst_fmri);
11411 11408 } else {
11412 11409 uu_warn("%s: %s\n",
11413 11410 gettext("Error validating the instance"),
11414 11411 scf_strerror(scf_error()));
11415 11412 }
11416 11413 } else if (ret == 1 && errs != NULL) {
11417 11414 scf_tmpl_error_t *err = NULL;
11418 11415 char *msg;
11419 11416 size_t len = 256; /* initial error buffer size */
11420 11417 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
11421 11418 SCF_TMPL_STRERROR_HUMAN : 0;
11422 11419
11423 11420 msg = safe_malloc(len);
11424 11421
11425 11422 while ((err = scf_tmpl_next_error(errs)) != NULL) {
11426 11423 int ret;
11427 11424
11428 11425 if ((ret = scf_tmpl_strerror(err, msg, len,
11429 11426 flag)) >= len) {
11430 11427 len = ret + 1;
11431 11428 msg = realloc(msg, len);
11432 11429 if (msg == NULL)
11433 11430 uu_die(gettext(
11434 11431 "Out of memory.\n"));
11435 11432 (void) scf_tmpl_strerror(err, msg, len,
11436 11433 flag);
11437 11434 }
11438 11435 (void) fprintf(stderr, "%s\n", msg);
11439 11436 }
11440 11437 if (msg != NULL)
11441 11438 free(msg);
11442 11439 }
11443 11440 if (errs != NULL)
11444 11441 scf_tmpl_errors_destroy(errs);
11445 11442
11446 11443 cleanup:
11447 11444 free(inst_fmri);
11448 11445 free(snapbuf);
11449 11446 }
11450 11447
11451 11448 static void
11452 11449 lscf_validate_file(const char *filename)
11453 11450 {
11454 11451 tmpl_errors_t *errs;
11455 11452
11456 11453 bundle_t *b = internal_bundle_new();
11457 11454 if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
11458 11455 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
11459 11456 tmpl_errors_print(stderr, errs, "");
11460 11457 semerr(gettext("Validation failed.\n"));
11461 11458 }
11462 11459 tmpl_errors_destroy(errs);
11463 11460 }
11464 11461 (void) internal_bundle_free(b);
11465 11462 }
11466 11463
11467 11464 /*
11468 11465 * validate [fmri|file]
11469 11466 */
11470 11467 void
11471 11468 lscf_validate(const char *arg)
11472 11469 {
11473 11470 const char *str;
11474 11471
11475 11472 if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
11476 11473 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
11477 11474 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
11478 11475 lscf_validate_file(str);
11479 11476 } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
11480 11477 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
11481 11478 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
11482 11479 lscf_validate_fmri(str);
11483 11480 } else if (access(arg, R_OK | F_OK) == 0) {
11484 11481 lscf_validate_file(arg);
11485 11482 } else {
11486 11483 lscf_validate_fmri(arg);
11487 11484 }
11488 11485 }
11489 11486
11490 11487 void
11491 11488 lscf_select(const char *fmri)
11492 11489 {
11493 11490 int ret, err;
11494 11491
11495 11492 lscf_prep_hndl();
11496 11493
11497 11494 if (cur_snap != NULL) {
11498 11495 struct snaplevel *elt;
11499 11496 char *buf;
11500 11497
11501 11498 /* Error unless name is that of the next level. */
11502 11499 elt = uu_list_next(cur_levels, cur_elt);
11503 11500 if (elt == NULL) {
11504 11501 semerr(gettext("No children.\n"));
11505 11502 return;
11506 11503 }
11507 11504
11508 11505 buf = safe_malloc(max_scf_name_len + 1);
11509 11506
11510 11507 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11511 11508 max_scf_name_len + 1) < 0)
11512 11509 scfdie();
11513 11510
11514 11511 if (strcmp(buf, fmri) != 0) {
11515 11512 semerr(gettext("No such child.\n"));
11516 11513 free(buf);
11517 11514 return;
11518 11515 }
11519 11516
11520 11517 free(buf);
11521 11518
11522 11519 cur_elt = elt;
11523 11520 cur_level = elt->sl;
11524 11521 return;
11525 11522 }
11526 11523
11527 11524 /*
11528 11525 * Special case for 'svc:', which takes the user to the scope level.
11529 11526 */
11530 11527 if (strcmp(fmri, "svc:") == 0) {
11531 11528 scf_instance_destroy(cur_inst);
11532 11529 scf_service_destroy(cur_svc);
11533 11530 cur_inst = NULL;
11534 11531 cur_svc = NULL;
11535 11532 return;
11536 11533 }
11537 11534
11538 11535 /*
11539 11536 * Special case for ':properties'. This appears as part of 'list' but
11540 11537 * can't be selected. Give a more helpful error message in this case.
11541 11538 */
11542 11539 if (strcmp(fmri, ":properties") == 0) {
11543 11540 semerr(gettext(":properties is not an entity. Try 'listprop' "
11544 11541 "to list properties.\n"));
11545 11542 return;
11546 11543 }
11547 11544
11548 11545 /*
11549 11546 * First try the argument as relative to the current selection.
11550 11547 */
11551 11548 if (cur_inst != NULL) {
11552 11549 /* EMPTY */;
11553 11550 } else if (cur_svc != NULL) {
11554 11551 if (select_inst(fmri) != 1)
11555 11552 return;
11556 11553 } else {
11557 11554 if (select_svc(fmri) != 1)
11558 11555 return;
11559 11556 }
11560 11557
11561 11558 err = 0;
11562 11559 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11563 11560 select_callback, NULL, &err, semerr)) != 0) {
11564 11561 semerr(gettext("Failed to walk instances: %s\n"),
11565 11562 scf_strerror(ret));
11566 11563 }
11567 11564 }
11568 11565
11569 11566 void
11570 11567 lscf_unselect(void)
11571 11568 {
11572 11569 lscf_prep_hndl();
11573 11570
11574 11571 if (cur_snap != NULL) {
11575 11572 struct snaplevel *elt;
11576 11573
11577 11574 elt = uu_list_prev(cur_levels, cur_elt);
11578 11575 if (elt == NULL) {
11579 11576 semerr(gettext("No parent levels.\n"));
11580 11577 } else {
11581 11578 cur_elt = elt;
11582 11579 cur_level = elt->sl;
11583 11580 }
11584 11581 } else if (cur_inst != NULL) {
11585 11582 scf_instance_destroy(cur_inst);
11586 11583 cur_inst = NULL;
11587 11584 } else if (cur_svc != NULL) {
11588 11585 scf_service_destroy(cur_svc);
11589 11586 cur_svc = NULL;
11590 11587 } else {
11591 11588 semerr(gettext("Cannot unselect at scope level.\n"));
11592 11589 }
11593 11590 }
11594 11591
11595 11592 /*
11596 11593 * Return the FMRI of the current selection, for the prompt.
11597 11594 */
11598 11595 void
11599 11596 lscf_get_selection_str(char *buf, size_t bufsz)
11600 11597 {
11601 11598 char *cp;
11602 11599 ssize_t fmrilen, szret;
11603 11600 boolean_t deleted = B_FALSE;
11604 11601
11605 11602 if (g_hndl == NULL) {
11606 11603 (void) strlcpy(buf, "svc:", bufsz);
11607 11604 return;
11608 11605 }
11609 11606
11610 11607 if (cur_level != NULL) {
11611 11608 assert(cur_snap != NULL);
11612 11609
11613 11610 /* [ snapshot ] FMRI [: instance ] */
11614 11611 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11615 11612 + 2 + max_scf_name_len + 1 + 1);
11616 11613
11617 11614 buf[0] = '[';
11618 11615
11619 11616 szret = scf_snapshot_get_name(cur_snap, buf + 1,
11620 11617 max_scf_name_len + 1);
11621 11618 if (szret < 0) {
11622 11619 if (scf_error() != SCF_ERROR_DELETED)
11623 11620 scfdie();
11624 11621
11625 11622 goto snap_deleted;
11626 11623 }
11627 11624
11628 11625 (void) strcat(buf, "]svc:/");
11629 11626
11630 11627 cp = strchr(buf, '\0');
11631 11628
11632 11629 szret = scf_snaplevel_get_service_name(cur_level, cp,
11633 11630 max_scf_name_len + 1);
11634 11631 if (szret < 0) {
11635 11632 if (scf_error() != SCF_ERROR_DELETED)
11636 11633 scfdie();
11637 11634
11638 11635 goto snap_deleted;
11639 11636 }
11640 11637
11641 11638 cp = strchr(cp, '\0');
11642 11639
11643 11640 if (snaplevel_is_instance(cur_level)) {
11644 11641 *cp++ = ':';
11645 11642
11646 11643 if (scf_snaplevel_get_instance_name(cur_level, cp,
11647 11644 max_scf_name_len + 1) < 0) {
11648 11645 if (scf_error() != SCF_ERROR_DELETED)
11649 11646 scfdie();
11650 11647
11651 11648 goto snap_deleted;
11652 11649 }
11653 11650 } else {
11654 11651 *cp++ = '[';
11655 11652 *cp++ = ':';
11656 11653
11657 11654 if (scf_instance_get_name(cur_inst, cp,
11658 11655 max_scf_name_len + 1) < 0) {
11659 11656 if (scf_error() != SCF_ERROR_DELETED)
11660 11657 scfdie();
11661 11658
11662 11659 goto snap_deleted;
11663 11660 }
11664 11661
11665 11662 (void) strcat(buf, "]");
11666 11663 }
11667 11664
11668 11665 return;
11669 11666
11670 11667 snap_deleted:
11671 11668 deleted = B_TRUE;
11672 11669 free(buf);
11673 11670 unselect_cursnap();
11674 11671 }
11675 11672
11676 11673 assert(cur_snap == NULL);
11677 11674
11678 11675 if (cur_inst != NULL) {
11679 11676 assert(cur_svc != NULL);
11680 11677 assert(cur_scope != NULL);
11681 11678
11682 11679 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11683 11680 if (fmrilen >= 0) {
11684 11681 assert(fmrilen < bufsz);
11685 11682 if (deleted)
11686 11683 warn(emsg_deleted);
11687 11684 return;
11688 11685 }
11689 11686
11690 11687 if (scf_error() != SCF_ERROR_DELETED)
11691 11688 scfdie();
11692 11689
11693 11690 deleted = B_TRUE;
11694 11691
11695 11692 scf_instance_destroy(cur_inst);
11696 11693 cur_inst = NULL;
11697 11694 }
11698 11695
11699 11696 if (cur_svc != NULL) {
11700 11697 assert(cur_scope != NULL);
11701 11698
11702 11699 szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11703 11700 if (szret >= 0) {
11704 11701 assert(szret < bufsz);
11705 11702 if (deleted)
11706 11703 warn(emsg_deleted);
11707 11704 return;
11708 11705 }
11709 11706
11710 11707 if (scf_error() != SCF_ERROR_DELETED)
11711 11708 scfdie();
11712 11709
11713 11710 deleted = B_TRUE;
11714 11711 scf_service_destroy(cur_svc);
11715 11712 cur_svc = NULL;
11716 11713 }
11717 11714
11718 11715 assert(cur_scope != NULL);
11719 11716 fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11720 11717
11721 11718 if (fmrilen < 0)
11722 11719 scfdie();
11723 11720
11724 11721 assert(fmrilen < bufsz);
11725 11722 if (deleted)
11726 11723 warn(emsg_deleted);
11727 11724 }
11728 11725
11729 11726 /*
11730 11727 * Entity listing. Entities and colon namespaces (e.g., :properties and
11731 11728 * :statistics) are listed for the current selection.
11732 11729 */
11733 11730 void
11734 11731 lscf_list(const char *pattern)
11735 11732 {
11736 11733 scf_iter_t *iter;
11737 11734 char *buf;
11738 11735 int ret;
11739 11736
11740 11737 lscf_prep_hndl();
11741 11738
11742 11739 if (cur_level != NULL) {
11743 11740 struct snaplevel *elt;
11744 11741
11745 11742 (void) fputs(COLON_NAMESPACES, stdout);
11746 11743
11747 11744 elt = uu_list_next(cur_levels, cur_elt);
11748 11745 if (elt == NULL)
11749 11746 return;
11750 11747
11751 11748 /*
11752 11749 * For now, we know that the next level is an instance. But
11753 11750 * if we ever have multiple scopes, this could be complicated.
11754 11751 */
11755 11752 buf = safe_malloc(max_scf_name_len + 1);
11756 11753 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11757 11754 max_scf_name_len + 1) >= 0) {
11758 11755 (void) puts(buf);
11759 11756 } else {
11760 11757 if (scf_error() != SCF_ERROR_DELETED)
11761 11758 scfdie();
11762 11759 }
11763 11760
11764 11761 free(buf);
11765 11762
11766 11763 return;
11767 11764 }
11768 11765
11769 11766 if (cur_inst != NULL) {
11770 11767 (void) fputs(COLON_NAMESPACES, stdout);
11771 11768 return;
11772 11769 }
11773 11770
11774 11771 iter = scf_iter_create(g_hndl);
11775 11772 if (iter == NULL)
11776 11773 scfdie();
11777 11774
11778 11775 buf = safe_malloc(max_scf_name_len + 1);
11779 11776
11780 11777 if (cur_svc != NULL) {
11781 11778 /* List the instances in this service. */
11782 11779 scf_instance_t *inst;
11783 11780
11784 11781 inst = scf_instance_create(g_hndl);
11785 11782 if (inst == NULL)
11786 11783 scfdie();
11787 11784
11788 11785 if (scf_iter_service_instances(iter, cur_svc) == 0) {
11789 11786 safe_printf(COLON_NAMESPACES);
11790 11787
11791 11788 for (;;) {
11792 11789 ret = scf_iter_next_instance(iter, inst);
11793 11790 if (ret == 0)
11794 11791 break;
11795 11792 if (ret != 1) {
11796 11793 if (scf_error() != SCF_ERROR_DELETED)
11797 11794 scfdie();
11798 11795
11799 11796 break;
11800 11797 }
11801 11798
11802 11799 if (scf_instance_get_name(inst, buf,
11803 11800 max_scf_name_len + 1) >= 0) {
11804 11801 if (pattern == NULL ||
11805 11802 fnmatch(pattern, buf, 0) == 0)
11806 11803 (void) puts(buf);
11807 11804 } else {
11808 11805 if (scf_error() != SCF_ERROR_DELETED)
11809 11806 scfdie();
11810 11807 }
11811 11808 }
11812 11809 } else {
11813 11810 if (scf_error() != SCF_ERROR_DELETED)
11814 11811 scfdie();
11815 11812 }
11816 11813
11817 11814 scf_instance_destroy(inst);
11818 11815 } else {
11819 11816 /* List the services in this scope. */
11820 11817 scf_service_t *svc;
11821 11818
11822 11819 assert(cur_scope != NULL);
11823 11820
11824 11821 svc = scf_service_create(g_hndl);
11825 11822 if (svc == NULL)
11826 11823 scfdie();
11827 11824
11828 11825 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11829 11826 scfdie();
11830 11827
11831 11828 for (;;) {
11832 11829 ret = scf_iter_next_service(iter, svc);
11833 11830 if (ret == 0)
11834 11831 break;
11835 11832 if (ret != 1)
11836 11833 scfdie();
11837 11834
11838 11835 if (scf_service_get_name(svc, buf,
11839 11836 max_scf_name_len + 1) >= 0) {
11840 11837 if (pattern == NULL ||
11841 11838 fnmatch(pattern, buf, 0) == 0)
11842 11839 safe_printf("%s\n", buf);
11843 11840 } else {
11844 11841 if (scf_error() != SCF_ERROR_DELETED)
11845 11842 scfdie();
11846 11843 }
11847 11844 }
11848 11845
11849 11846 scf_service_destroy(svc);
11850 11847 }
11851 11848
11852 11849 free(buf);
11853 11850 scf_iter_destroy(iter);
11854 11851 }
11855 11852
11856 11853 /*
11857 11854 * Entity addition. Creates an empty entity in the current selection.
11858 11855 */
11859 11856 void
11860 11857 lscf_add(const char *name)
11861 11858 {
11862 11859 lscf_prep_hndl();
11863 11860
11864 11861 if (cur_snap != NULL) {
11865 11862 semerr(emsg_cant_modify_snapshots);
11866 11863 } else if (cur_inst != NULL) {
11867 11864 semerr(gettext("Cannot add entities to an instance.\n"));
11868 11865 } else if (cur_svc != NULL) {
11869 11866
11870 11867 if (scf_service_add_instance(cur_svc, name, NULL) !=
11871 11868 SCF_SUCCESS) {
11872 11869 switch (scf_error()) {
11873 11870 case SCF_ERROR_INVALID_ARGUMENT:
11874 11871 semerr(gettext("Invalid name.\n"));
11875 11872 break;
11876 11873
11877 11874 case SCF_ERROR_EXISTS:
11878 11875 semerr(gettext("Instance already exists.\n"));
11879 11876 break;
11880 11877
11881 11878 case SCF_ERROR_PERMISSION_DENIED:
11882 11879 semerr(emsg_permission_denied);
11883 11880 break;
11884 11881
11885 11882 default:
11886 11883 scfdie();
11887 11884 }
11888 11885 }
11889 11886 } else {
11890 11887 assert(cur_scope != NULL);
11891 11888
11892 11889 if (scf_scope_add_service(cur_scope, name, NULL) !=
11893 11890 SCF_SUCCESS) {
11894 11891 switch (scf_error()) {
11895 11892 case SCF_ERROR_INVALID_ARGUMENT:
11896 11893 semerr(gettext("Invalid name.\n"));
11897 11894 break;
11898 11895
11899 11896 case SCF_ERROR_EXISTS:
11900 11897 semerr(gettext("Service already exists.\n"));
11901 11898 break;
11902 11899
11903 11900 case SCF_ERROR_PERMISSION_DENIED:
11904 11901 semerr(emsg_permission_denied);
11905 11902 break;
11906 11903
11907 11904 case SCF_ERROR_BACKEND_READONLY:
11908 11905 semerr(emsg_read_only);
11909 11906 break;
11910 11907
11911 11908 default:
11912 11909 scfdie();
11913 11910 }
11914 11911 }
11915 11912 }
11916 11913 }
11917 11914
11918 11915 /* return 1 if the entity has no persistent pgs, else return 0 */
11919 11916 static int
11920 11917 entity_has_no_pgs(void *ent, int isservice)
11921 11918 {
11922 11919 scf_iter_t *iter = NULL;
11923 11920 scf_propertygroup_t *pg = NULL;
11924 11921 uint32_t flags;
11925 11922 int err;
11926 11923 int ret = 1;
11927 11924
11928 11925 if ((iter = scf_iter_create(g_hndl)) == NULL ||
11929 11926 (pg = scf_pg_create(g_hndl)) == NULL)
11930 11927 scfdie();
11931 11928
11932 11929 if (isservice) {
11933 11930 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11934 11931 scfdie();
11935 11932 } else {
11936 11933 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11937 11934 scfdie();
11938 11935 }
11939 11936
11940 11937 while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11941 11938 if (scf_pg_get_flags(pg, &flags) != 0)
11942 11939 scfdie();
11943 11940
11944 11941 /* skip nonpersistent pgs */
11945 11942 if (flags & SCF_PG_FLAG_NONPERSISTENT)
11946 11943 continue;
11947 11944
11948 11945 ret = 0;
11949 11946 break;
11950 11947 }
11951 11948
11952 11949 if (err == -1)
11953 11950 scfdie();
11954 11951
11955 11952 scf_pg_destroy(pg);
11956 11953 scf_iter_destroy(iter);
11957 11954
11958 11955 return (ret);
11959 11956 }
11960 11957
11961 11958 /* return 1 if the service has no instances, else return 0 */
11962 11959 static int
11963 11960 svc_has_no_insts(scf_service_t *svc)
11964 11961 {
11965 11962 scf_instance_t *inst;
11966 11963 scf_iter_t *iter;
11967 11964 int r;
11968 11965 int ret = 1;
11969 11966
11970 11967 if ((inst = scf_instance_create(g_hndl)) == NULL ||
11971 11968 (iter = scf_iter_create(g_hndl)) == NULL)
11972 11969 scfdie();
11973 11970
11974 11971 if (scf_iter_service_instances(iter, svc) != 0)
11975 11972 scfdie();
11976 11973
11977 11974 r = scf_iter_next_instance(iter, inst);
11978 11975 if (r == 1) {
11979 11976 ret = 0;
11980 11977 } else if (r == 0) {
11981 11978 ret = 1;
11982 11979 } else if (r == -1) {
11983 11980 scfdie();
11984 11981 } else {
11985 11982 bad_error("scf_iter_next_instance", r);
11986 11983 }
11987 11984
11988 11985 scf_iter_destroy(iter);
11989 11986 scf_instance_destroy(inst);
11990 11987
11991 11988 return (ret);
11992 11989 }
11993 11990
11994 11991 /*
11995 11992 * Entity deletion.
11996 11993 */
11997 11994
11998 11995 /*
11999 11996 * Delete the property group <fmri>/:properties/<name>. Returns
12000 11997 * SCF_ERROR_NONE on success (or if the entity is not found),
12001 11998 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
12002 11999 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
12003 12000 * denied.
12004 12001 */
12005 12002 static scf_error_t
12006 12003 delete_dependency_pg(const char *fmri, const char *name)
12007 12004 {
12008 12005 void *entity = NULL;
12009 12006 int isservice;
12010 12007 scf_propertygroup_t *pg = NULL;
12011 12008 scf_error_t result;
12012 12009 char *pgty;
12013 12010 scf_service_t *svc = NULL;
12014 12011 scf_instance_t *inst = NULL;
12015 12012 scf_iter_t *iter = NULL;
12016 12013 char *name_buf = NULL;
12017 12014
12018 12015 result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
12019 12016 switch (result) {
12020 12017 case SCF_ERROR_NONE:
12021 12018 break;
12022 12019
12023 12020 case SCF_ERROR_NO_MEMORY:
12024 12021 uu_die(gettext("Out of memory.\n"));
12025 12022 /* NOTREACHED */
12026 12023
12027 12024 case SCF_ERROR_INVALID_ARGUMENT:
12028 12025 case SCF_ERROR_CONSTRAINT_VIOLATED:
12029 12026 return (SCF_ERROR_INVALID_ARGUMENT);
12030 12027
12031 12028 case SCF_ERROR_NOT_FOUND:
12032 12029 result = SCF_ERROR_NONE;
12033 12030 goto out;
12034 12031
12035 12032 default:
12036 12033 bad_error("fmri_to_entity", result);
12037 12034 }
12038 12035
12039 12036 pg = scf_pg_create(g_hndl);
12040 12037 if (pg == NULL)
12041 12038 scfdie();
12042 12039
12043 12040 if (entity_get_pg(entity, isservice, name, pg) != 0) {
12044 12041 if (scf_error() != SCF_ERROR_NOT_FOUND)
12045 12042 scfdie();
12046 12043
12047 12044 result = SCF_ERROR_NONE;
12048 12045 goto out;
12049 12046 }
12050 12047
12051 12048 pgty = safe_malloc(max_scf_pg_type_len + 1);
12052 12049
12053 12050 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12054 12051 scfdie();
12055 12052
12056 12053 if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
12057 12054 result = SCF_ERROR_TYPE_MISMATCH;
12058 12055 free(pgty);
12059 12056 goto out;
12060 12057 }
12061 12058
12062 12059 free(pgty);
12063 12060
12064 12061 if (scf_pg_delete(pg) != 0) {
12065 12062 result = scf_error();
12066 12063 if (result != SCF_ERROR_PERMISSION_DENIED)
12067 12064 scfdie();
12068 12065 goto out;
12069 12066 }
12070 12067
12071 12068 /*
12072 12069 * We have to handle the case where we've just deleted the last
12073 12070 * property group of a "dummy" entity (instance or service).
12074 12071 * A "dummy" entity is an entity only present to hold an
12075 12072 * external dependency.
12076 12073 * So, in the case we deleted the last property group then we
12077 12074 * can also delete the entity. If the entity is an instance then
12078 12075 * we must verify if this was the last instance for the service
12079 12076 * and if it is, we can also delete the service if it doesn't
12080 12077 * have any property group either.
12081 12078 */
12082 12079
12083 12080 result = SCF_ERROR_NONE;
12084 12081
12085 12082 if (isservice) {
12086 12083 svc = (scf_service_t *)entity;
12087 12084
12088 12085 if ((inst = scf_instance_create(g_hndl)) == NULL ||
12089 12086 (iter = scf_iter_create(g_hndl)) == NULL)
12090 12087 scfdie();
12091 12088
12092 12089 name_buf = safe_malloc(max_scf_name_len + 1);
12093 12090 } else {
12094 12091 inst = (scf_instance_t *)entity;
12095 12092 }
12096 12093
12097 12094 /*
12098 12095 * If the entity is an instance and we've just deleted its last
12099 12096 * property group then we should delete it.
12100 12097 */
12101 12098 if (!isservice && entity_has_no_pgs(entity, isservice)) {
12102 12099 /* find the service before deleting the inst. - needed later */
12103 12100 if ((svc = scf_service_create(g_hndl)) == NULL)
12104 12101 scfdie();
12105 12102
12106 12103 if (scf_instance_get_parent(inst, svc) != 0)
12107 12104 scfdie();
12108 12105
12109 12106 /* delete the instance */
12110 12107 if (scf_instance_delete(inst) != 0) {
12111 12108 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12112 12109 scfdie();
12113 12110
12114 12111 result = SCF_ERROR_PERMISSION_DENIED;
12115 12112 goto out;
12116 12113 }
12117 12114 /* no need to refresh the instance */
12118 12115 inst = NULL;
12119 12116 }
12120 12117
12121 12118 /*
12122 12119 * If the service has no more instances and pgs or we just deleted the
12123 12120 * last instance and the service doesn't have anymore propery groups
12124 12121 * then the service should be deleted.
12125 12122 */
12126 12123 if (svc != NULL &&
12127 12124 svc_has_no_insts(svc) &&
12128 12125 entity_has_no_pgs((void *)svc, 1)) {
12129 12126 if (scf_service_delete(svc) == 0) {
12130 12127 if (isservice) {
12131 12128 /* no need to refresh the service */
12132 12129 svc = NULL;
12133 12130 }
12134 12131
12135 12132 goto out;
12136 12133 }
12137 12134
12138 12135 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12139 12136 scfdie();
12140 12137
12141 12138 result = SCF_ERROR_PERMISSION_DENIED;
12142 12139 }
12143 12140
12144 12141 /* if the entity has not been deleted, refresh it */
12145 12142 if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
12146 12143 (void) refresh_entity(isservice, entity, fmri, inst, iter,
12147 12144 name_buf);
12148 12145 }
12149 12146
12150 12147 out:
12151 12148 if (isservice && (inst != NULL && iter != NULL)) {
12152 12149 free(name_buf);
12153 12150 scf_iter_destroy(iter);
12154 12151 scf_instance_destroy(inst);
12155 12152 }
12156 12153
12157 12154 if (!isservice && svc != NULL) {
12158 12155 scf_service_destroy(svc);
12159 12156 }
12160 12157
12161 12158 scf_pg_destroy(pg);
12162 12159 if (entity != NULL)
12163 12160 entity_destroy(entity, isservice);
12164 12161
12165 12162 return (result);
12166 12163 }
12167 12164
12168 12165 static int
12169 12166 delete_dependents(scf_propertygroup_t *pg)
12170 12167 {
12171 12168 char *pgty, *name, *fmri;
12172 12169 scf_property_t *prop;
12173 12170 scf_value_t *val;
12174 12171 scf_iter_t *iter;
12175 12172 int r;
12176 12173 scf_error_t err;
12177 12174
12178 12175 /* Verify that the pg has the correct type. */
12179 12176 pgty = safe_malloc(max_scf_pg_type_len + 1);
12180 12177 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12181 12178 scfdie();
12182 12179
12183 12180 if (strcmp(pgty, scf_group_framework) != 0) {
12184 12181 if (g_verbose) {
12185 12182 fmri = safe_malloc(max_scf_fmri_len + 1);
12186 12183 if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
12187 12184 scfdie();
12188 12185
12189 12186 warn(gettext("Property group %s is not of expected "
12190 12187 "type %s.\n"), fmri, scf_group_framework);
12191 12188
12192 12189 free(fmri);
12193 12190 }
12194 12191
12195 12192 free(pgty);
12196 12193 return (-1);
12197 12194 }
12198 12195
12199 12196 free(pgty);
12200 12197
12201 12198 /* map delete_dependency_pg onto the properties. */
12202 12199 if ((prop = scf_property_create(g_hndl)) == NULL ||
12203 12200 (val = scf_value_create(g_hndl)) == NULL ||
12204 12201 (iter = scf_iter_create(g_hndl)) == NULL)
12205 12202 scfdie();
12206 12203
12207 12204 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
12208 12205 scfdie();
12209 12206
12210 12207 name = safe_malloc(max_scf_name_len + 1);
12211 12208 fmri = safe_malloc(max_scf_fmri_len + 2);
12212 12209
12213 12210 while ((r = scf_iter_next_property(iter, prop)) == 1) {
12214 12211 scf_type_t ty;
12215 12212
12216 12213 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
12217 12214 scfdie();
12218 12215
12219 12216 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
12220 12217 scfdie();
12221 12218
12222 12219 if ((ty != SCF_TYPE_ASTRING &&
12223 12220 prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
12224 12221 prop_get_val(prop, val) != 0)
12225 12222 continue;
12226 12223
12227 12224 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
12228 12225 scfdie();
12229 12226
12230 12227 err = delete_dependency_pg(fmri, name);
12231 12228 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
12232 12229 if (scf_property_to_fmri(prop, fmri,
12233 12230 max_scf_fmri_len + 2) < 0)
12234 12231 scfdie();
12235 12232
12236 12233 warn(gettext("Value of %s is not a valid FMRI.\n"),
12237 12234 fmri);
12238 12235 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
12239 12236 warn(gettext("Property group \"%s\" of entity \"%s\" "
12240 12237 "does not have dependency type.\n"), name, fmri);
12241 12238 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
12242 12239 warn(gettext("Could not delete property group \"%s\" "
12243 12240 "of entity \"%s\" (permission denied).\n"), name,
12244 12241 fmri);
12245 12242 }
12246 12243 }
12247 12244 if (r == -1)
12248 12245 scfdie();
12249 12246
12250 12247 scf_value_destroy(val);
12251 12248 scf_property_destroy(prop);
12252 12249
12253 12250 return (0);
12254 12251 }
12255 12252
12256 12253 /*
12257 12254 * Returns 1 if the instance may be running, and 0 otherwise.
12258 12255 */
12259 12256 static int
12260 12257 inst_is_running(scf_instance_t *inst)
12261 12258 {
12262 12259 scf_propertygroup_t *pg;
12263 12260 scf_property_t *prop;
12264 12261 scf_value_t *val;
12265 12262 char buf[MAX_SCF_STATE_STRING_SZ];
12266 12263 int ret = 0;
12267 12264 ssize_t szret;
12268 12265
12269 12266 if ((pg = scf_pg_create(g_hndl)) == NULL ||
12270 12267 (prop = scf_property_create(g_hndl)) == NULL ||
12271 12268 (val = scf_value_create(g_hndl)) == NULL)
12272 12269 scfdie();
12273 12270
12274 12271 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
12275 12272 if (scf_error() != SCF_ERROR_NOT_FOUND)
12276 12273 scfdie();
12277 12274 goto out;
12278 12275 }
12279 12276
12280 12277 if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
12281 12278 prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
12282 12279 prop_get_val(prop, val) != 0)
12283 12280 goto out;
12284 12281
12285 12282 szret = scf_value_get_astring(val, buf, sizeof (buf));
12286 12283 assert(szret >= 0);
12287 12284
12288 12285 ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
12289 12286 strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
12290 12287
12291 12288 out:
12292 12289 scf_value_destroy(val);
12293 12290 scf_property_destroy(prop);
12294 12291 scf_pg_destroy(pg);
12295 12292 return (ret);
12296 12293 }
12297 12294
12298 12295 static uint8_t
12299 12296 pg_is_external_dependency(scf_propertygroup_t *pg)
12300 12297 {
12301 12298 char *type;
12302 12299 scf_value_t *val;
12303 12300 scf_property_t *prop;
12304 12301 uint8_t b = B_FALSE;
12305 12302
12306 12303 type = safe_malloc(max_scf_pg_type_len + 1);
12307 12304
12308 12305 if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
12309 12306 scfdie();
12310 12307
12311 12308 if ((prop = scf_property_create(g_hndl)) == NULL ||
12312 12309 (val = scf_value_create(g_hndl)) == NULL)
12313 12310 scfdie();
12314 12311
12315 12312 if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
12316 12313 if (pg_get_prop(pg, scf_property_external, prop) == 0) {
12317 12314 if (scf_property_get_value(prop, val) != 0)
12318 12315 scfdie();
12319 12316 if (scf_value_get_boolean(val, &b) != 0)
12320 12317 scfdie();
12321 12318 }
12322 12319 }
12323 12320
12324 12321 free(type);
12325 12322 (void) scf_value_destroy(val);
12326 12323 (void) scf_property_destroy(prop);
12327 12324
12328 12325 return (b);
12329 12326 }
12330 12327
12331 12328 #define DELETE_FAILURE -1
12332 12329 #define DELETE_SUCCESS_NOEXTDEPS 0
12333 12330 #define DELETE_SUCCESS_EXTDEPS 1
12334 12331
12335 12332 /*
12336 12333 * lscf_instance_delete() deletes an instance. Before calling
12337 12334 * scf_instance_delete(), though, we make sure the instance isn't
12338 12335 * running and delete dependencies in other entities which the instance
12339 12336 * declared as "dependents". If there are dependencies which were
12340 12337 * created for other entities, then instead of deleting the instance we
12341 12338 * make it "empty" by deleting all other property groups and all
12342 12339 * snapshots.
12343 12340 *
12344 12341 * lscf_instance_delete() verifies that there is no external dependency pgs
12345 12342 * before suppressing the instance. If there is, then we must not remove them
12346 12343 * now in case the instance is re-created otherwise the dependencies would be
12347 12344 * lost. The external dependency pgs will be removed if the dependencies are
12348 12345 * removed.
12349 12346 *
12350 12347 * Returns:
12351 12348 * DELETE_FAILURE on failure
12352 12349 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12353 12350 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12354 12351 */
12355 12352 static int
12356 12353 lscf_instance_delete(scf_instance_t *inst, int force)
12357 12354 {
12358 12355 scf_propertygroup_t *pg;
12359 12356 scf_snapshot_t *snap;
12360 12357 scf_iter_t *iter;
12361 12358 int err;
12362 12359 int external = 0;
12363 12360
12364 12361 /* If we're not forcing and the instance is running, refuse. */
12365 12362 if (!force && inst_is_running(inst)) {
12366 12363 char *fmri;
12367 12364
12368 12365 fmri = safe_malloc(max_scf_fmri_len + 1);
12369 12366
12370 12367 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
12371 12368 scfdie();
12372 12369
12373 12370 semerr(gettext("Instance %s may be running. "
12374 12371 "Use delete -f if it is not.\n"), fmri);
12375 12372
12376 12373 free(fmri);
12377 12374 return (DELETE_FAILURE);
12378 12375 }
12379 12376
12380 12377 pg = scf_pg_create(g_hndl);
12381 12378 if (pg == NULL)
12382 12379 scfdie();
12383 12380
12384 12381 if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
12385 12382 (void) delete_dependents(pg);
12386 12383 else if (scf_error() != SCF_ERROR_NOT_FOUND)
12387 12384 scfdie();
12388 12385
12389 12386 scf_pg_destroy(pg);
12390 12387
12391 12388 /*
12392 12389 * If the instance has some external dependencies then we must
12393 12390 * keep them in case the instance is reimported otherwise the
12394 12391 * dependencies would be lost on reimport.
12395 12392 */
12396 12393 if ((iter = scf_iter_create(g_hndl)) == NULL ||
12397 12394 (pg = scf_pg_create(g_hndl)) == NULL)
12398 12395 scfdie();
12399 12396
12400 12397 if (scf_iter_instance_pgs(iter, inst) < 0)
12401 12398 scfdie();
12402 12399
12403 12400 while ((err = scf_iter_next_pg(iter, pg)) == 1) {
12404 12401 if (pg_is_external_dependency(pg)) {
12405 12402 external = 1;
12406 12403 continue;
12407 12404 }
12408 12405
12409 12406 if (scf_pg_delete(pg) != 0) {
12410 12407 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12411 12408 scfdie();
12412 12409 else {
12413 12410 semerr(emsg_permission_denied);
12414 12411
12415 12412 (void) scf_iter_destroy(iter);
12416 12413 (void) scf_pg_destroy(pg);
12417 12414 return (DELETE_FAILURE);
12418 12415 }
12419 12416 }
12420 12417 }
12421 12418
12422 12419 if (err == -1)
12423 12420 scfdie();
12424 12421
12425 12422 (void) scf_iter_destroy(iter);
12426 12423 (void) scf_pg_destroy(pg);
12427 12424
12428 12425 if (external) {
12429 12426 /*
12430 12427 * All the pgs have been deleted for the instance except
12431 12428 * the ones holding the external dependencies.
12432 12429 * For the job to be complete, we must also delete the
12433 12430 * snapshots associated with the instance.
12434 12431 */
12435 12432 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
12436 12433 NULL)
12437 12434 scfdie();
12438 12435 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
12439 12436 scfdie();
12440 12437
12441 12438 if (scf_iter_instance_snapshots(iter, inst) == -1)
12442 12439 scfdie();
12443 12440
12444 12441 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
12445 12442 if (_scf_snapshot_delete(snap) != 0) {
12446 12443 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12447 12444 scfdie();
12448 12445
12449 12446 semerr(emsg_permission_denied);
12450 12447
12451 12448 (void) scf_iter_destroy(iter);
12452 12449 (void) scf_snapshot_destroy(snap);
12453 12450 return (DELETE_FAILURE);
12454 12451 }
12455 12452 }
12456 12453
12457 12454 if (err == -1)
12458 12455 scfdie();
12459 12456
12460 12457 (void) scf_iter_destroy(iter);
12461 12458 (void) scf_snapshot_destroy(snap);
12462 12459 return (DELETE_SUCCESS_EXTDEPS);
12463 12460 }
12464 12461
12465 12462 if (scf_instance_delete(inst) != 0) {
12466 12463 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12467 12464 scfdie();
12468 12465
12469 12466 semerr(emsg_permission_denied);
12470 12467
12471 12468 return (DELETE_FAILURE);
12472 12469 }
12473 12470
12474 12471 return (DELETE_SUCCESS_NOEXTDEPS);
12475 12472 }
12476 12473
12477 12474 /*
12478 12475 * lscf_service_delete() deletes a service. Before calling
12479 12476 * scf_service_delete(), though, we call lscf_instance_delete() for
12480 12477 * each of the instances and delete dependencies in other entities
12481 12478 * which were created as "dependents" of this service. If there are
12482 12479 * dependencies which were created for other entities, then we delete
12483 12480 * all other property groups in the service and leave it as "empty".
12484 12481 *
12485 12482 * lscf_service_delete() verifies that there is no external dependency
12486 12483 * pgs at the instance & service level before suppressing the service.
12487 12484 * If there is, then we must not remove them now in case the service
12488 12485 * is re-imported otherwise the dependencies would be lost. The external
12489 12486 * dependency pgs will be removed if the dependencies are removed.
12490 12487 *
12491 12488 * Returns:
12492 12489 * DELETE_FAILURE on failure
12493 12490 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12494 12491 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12495 12492 */
12496 12493 static int
12497 12494 lscf_service_delete(scf_service_t *svc, int force)
12498 12495 {
12499 12496 int r;
12500 12497 scf_instance_t *inst;
12501 12498 scf_propertygroup_t *pg;
12502 12499 scf_iter_t *iter;
12503 12500 int ret;
12504 12501 int external = 0;
12505 12502
12506 12503 if ((inst = scf_instance_create(g_hndl)) == NULL ||
12507 12504 (pg = scf_pg_create(g_hndl)) == NULL ||
12508 12505 (iter = scf_iter_create(g_hndl)) == NULL)
12509 12506 scfdie();
12510 12507
12511 12508 if (scf_iter_service_instances(iter, svc) != 0)
12512 12509 scfdie();
12513 12510
12514 12511 for (r = scf_iter_next_instance(iter, inst);
12515 12512 r == 1;
12516 12513 r = scf_iter_next_instance(iter, inst)) {
12517 12514
12518 12515 ret = lscf_instance_delete(inst, force);
12519 12516 if (ret == DELETE_FAILURE) {
12520 12517 scf_iter_destroy(iter);
12521 12518 scf_pg_destroy(pg);
12522 12519 scf_instance_destroy(inst);
12523 12520 return (DELETE_FAILURE);
12524 12521 }
12525 12522
12526 12523 /*
12527 12524 * Record the fact that there is some external dependencies
12528 12525 * at the instance level.
12529 12526 */
12530 12527 if (ret == DELETE_SUCCESS_EXTDEPS)
12531 12528 external |= 1;
12532 12529 }
12533 12530
12534 12531 if (r != 0)
12535 12532 scfdie();
12536 12533
12537 12534 /* Delete dependency property groups in dependent services. */
12538 12535 if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12539 12536 (void) delete_dependents(pg);
12540 12537 else if (scf_error() != SCF_ERROR_NOT_FOUND)
12541 12538 scfdie();
12542 12539
12543 12540 scf_iter_destroy(iter);
12544 12541 scf_pg_destroy(pg);
12545 12542 scf_instance_destroy(inst);
12546 12543
12547 12544 /*
12548 12545 * If the service has some external dependencies then we don't
12549 12546 * want to remove them in case the service is re-imported.
12550 12547 */
12551 12548 if ((pg = scf_pg_create(g_hndl)) == NULL ||
12552 12549 (iter = scf_iter_create(g_hndl)) == NULL)
12553 12550 scfdie();
12554 12551
12555 12552 if (scf_iter_service_pgs(iter, svc) < 0)
12556 12553 scfdie();
12557 12554
12558 12555 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12559 12556 if (pg_is_external_dependency(pg)) {
12560 12557 external |= 2;
12561 12558 continue;
12562 12559 }
12563 12560
12564 12561 if (scf_pg_delete(pg) != 0) {
12565 12562 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12566 12563 scfdie();
12567 12564 else {
12568 12565 semerr(emsg_permission_denied);
12569 12566
12570 12567 (void) scf_iter_destroy(iter);
12571 12568 (void) scf_pg_destroy(pg);
12572 12569 return (DELETE_FAILURE);
12573 12570 }
12574 12571 }
12575 12572 }
12576 12573
12577 12574 if (r == -1)
12578 12575 scfdie();
12579 12576
12580 12577 (void) scf_iter_destroy(iter);
12581 12578 (void) scf_pg_destroy(pg);
12582 12579
12583 12580 if (external != 0)
12584 12581 return (DELETE_SUCCESS_EXTDEPS);
12585 12582
12586 12583 if (scf_service_delete(svc) == 0)
12587 12584 return (DELETE_SUCCESS_NOEXTDEPS);
12588 12585
12589 12586 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12590 12587 scfdie();
12591 12588
12592 12589 semerr(emsg_permission_denied);
12593 12590 return (DELETE_FAILURE);
12594 12591 }
12595 12592
12596 12593 static int
12597 12594 delete_callback(void *data, scf_walkinfo_t *wip)
12598 12595 {
12599 12596 int force = (int)data;
12600 12597
12601 12598 if (wip->inst != NULL)
12602 12599 (void) lscf_instance_delete(wip->inst, force);
12603 12600 else
12604 12601 (void) lscf_service_delete(wip->svc, force);
12605 12602
12606 12603 return (0);
12607 12604 }
12608 12605
12609 12606 void
12610 12607 lscf_delete(const char *fmri, int force)
12611 12608 {
12612 12609 scf_service_t *svc;
12613 12610 scf_instance_t *inst;
12614 12611 int ret;
12615 12612
12616 12613 lscf_prep_hndl();
12617 12614
12618 12615 if (cur_snap != NULL) {
12619 12616 if (!snaplevel_is_instance(cur_level)) {
12620 12617 char *buf;
12621 12618
12622 12619 buf = safe_malloc(max_scf_name_len + 1);
12623 12620 if (scf_instance_get_name(cur_inst, buf,
12624 12621 max_scf_name_len + 1) >= 0) {
12625 12622 if (strcmp(buf, fmri) == 0) {
12626 12623 semerr(emsg_cant_modify_snapshots);
12627 12624 free(buf);
12628 12625 return;
12629 12626 }
12630 12627 } else if (scf_error() != SCF_ERROR_DELETED) {
12631 12628 scfdie();
12632 12629 }
12633 12630 free(buf);
12634 12631 }
12635 12632 } else if (cur_inst != NULL) {
12636 12633 /* EMPTY */;
12637 12634 } else if (cur_svc != NULL) {
12638 12635 inst = scf_instance_create(g_hndl);
12639 12636 if (inst == NULL)
12640 12637 scfdie();
12641 12638
12642 12639 if (scf_service_get_instance(cur_svc, fmri, inst) ==
12643 12640 SCF_SUCCESS) {
12644 12641 (void) lscf_instance_delete(inst, force);
12645 12642 scf_instance_destroy(inst);
12646 12643 return;
12647 12644 }
12648 12645
12649 12646 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12650 12647 scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12651 12648 scfdie();
12652 12649
12653 12650 scf_instance_destroy(inst);
12654 12651 } else {
12655 12652 assert(cur_scope != NULL);
12656 12653
12657 12654 svc = scf_service_create(g_hndl);
12658 12655 if (svc == NULL)
12659 12656 scfdie();
12660 12657
12661 12658 if (scf_scope_get_service(cur_scope, fmri, svc) ==
12662 12659 SCF_SUCCESS) {
12663 12660 (void) lscf_service_delete(svc, force);
12664 12661 scf_service_destroy(svc);
12665 12662 return;
12666 12663 }
12667 12664
12668 12665 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12669 12666 scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12670 12667 scfdie();
12671 12668
12672 12669 scf_service_destroy(svc);
12673 12670 }
12674 12671
12675 12672 /*
12676 12673 * Match FMRI to entity.
12677 12674 */
12678 12675 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12679 12676 delete_callback, (void *)force, NULL, semerr)) != 0) {
12680 12677 semerr(gettext("Failed to walk instances: %s\n"),
12681 12678 scf_strerror(ret));
12682 12679 }
12683 12680 }
12684 12681
12685 12682
12686 12683
12687 12684 /*
12688 12685 * :properties commands. These all end with "pg" or "prop" and generally
12689 12686 * operate on the currently selected entity.
12690 12687 */
12691 12688
12692 12689 /*
12693 12690 * Property listing. List the property groups, properties, their types and
12694 12691 * their values for the currently selected entity.
12695 12692 */
12696 12693 static void
12697 12694 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12698 12695 {
12699 12696 char *buf;
12700 12697 uint32_t flags;
12701 12698
12702 12699 buf = safe_malloc(max_scf_pg_type_len + 1);
12703 12700
12704 12701 if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12705 12702 scfdie();
12706 12703
12707 12704 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12708 12705 scfdie();
12709 12706
12710 12707 safe_printf("%-*s %s", namewidth, name, buf);
12711 12708
12712 12709 if (flags & SCF_PG_FLAG_NONPERSISTENT)
12713 12710 safe_printf("\tNONPERSISTENT");
12714 12711
12715 12712 safe_printf("\n");
12716 12713
12717 12714 free(buf);
12718 12715 }
12719 12716
12720 12717 static boolean_t
12721 12718 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12722 12719 {
12723 12720 if (scf_property_get_value(prop, val) == 0) {
12724 12721 return (B_FALSE);
12725 12722 } else {
12726 12723 switch (scf_error()) {
12727 12724 case SCF_ERROR_NOT_FOUND:
12728 12725 return (B_FALSE);
12729 12726 case SCF_ERROR_PERMISSION_DENIED:
12730 12727 case SCF_ERROR_CONSTRAINT_VIOLATED:
12731 12728 return (B_TRUE);
12732 12729 default:
12733 12730 scfdie();
12734 12731 /*NOTREACHED*/
12735 12732 }
12736 12733 }
12737 12734 }
12738 12735
12739 12736 static void
12740 12737 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12741 12738 {
12742 12739 scf_iter_t *iter;
12743 12740 scf_value_t *val;
12744 12741 const char *type;
12745 12742 int multiple_strings = 0;
12746 12743 int ret;
12747 12744
12748 12745 if ((iter = scf_iter_create(g_hndl)) == NULL ||
12749 12746 (val = scf_value_create(g_hndl)) == NULL)
12750 12747 scfdie();
12751 12748
12752 12749 type = prop_to_typestr(prop);
12753 12750 assert(type != NULL);
12754 12751
12755 12752 safe_printf("%-*s %-7s ", len, name, type);
12756 12753
12757 12754 if (prop_has_multiple_values(prop, val) &&
12758 12755 (scf_value_type(val) == SCF_TYPE_ASTRING ||
12759 12756 scf_value_type(val) == SCF_TYPE_USTRING))
12760 12757 multiple_strings = 1;
12761 12758
12762 12759 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12763 12760 scfdie();
12764 12761
12765 12762 while ((ret = scf_iter_next_value(iter, val)) == 1) {
12766 12763 char *buf;
12767 12764 ssize_t vlen, szret;
12768 12765
12769 12766 vlen = scf_value_get_as_string(val, NULL, 0);
12770 12767 if (vlen < 0)
12771 12768 scfdie();
12772 12769
12773 12770 buf = safe_malloc(vlen + 1);
12774 12771
12775 12772 szret = scf_value_get_as_string(val, buf, vlen + 1);
12776 12773 if (szret < 0)
12777 12774 scfdie();
12778 12775 assert(szret <= vlen);
12779 12776
12780 12777 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12781 12778 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12782 12779 safe_printf(" \"");
12783 12780 (void) quote_and_print(buf, stdout, 0);
12784 12781 (void) putchar('"');
12785 12782 if (ferror(stdout)) {
12786 12783 (void) putchar('\n');
12787 12784 uu_die(gettext("Error writing to stdout.\n"));
12788 12785 }
12789 12786 } else {
12790 12787 safe_printf(" %s", buf);
12791 12788 }
12792 12789
12793 12790 free(buf);
12794 12791 }
12795 12792 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12796 12793 scfdie();
12797 12794
12798 12795 if (putchar('\n') != '\n')
12799 12796 uu_die(gettext("Could not output newline"));
12800 12797 }
12801 12798
12802 12799 /*
12803 12800 * Outputs template property group info for the describe subcommand.
12804 12801 * If 'templates' == 2, verbose output is printed in the format expected
12805 12802 * for describe -v, which includes all templates fields. If pg is
12806 12803 * not NULL, we're describing the template data, not an existing property
12807 12804 * group, and formatting should be appropriate for describe -t.
12808 12805 */
12809 12806 static void
12810 12807 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12811 12808 {
12812 12809 char *buf;
12813 12810 uint8_t required;
12814 12811 scf_property_t *stability_prop;
12815 12812 scf_value_t *stability_val;
12816 12813
12817 12814 if (templates == 0)
12818 12815 return;
12819 12816
12820 12817 if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12821 12818 (stability_val = scf_value_create(g_hndl)) == NULL)
12822 12819 scfdie();
12823 12820
12824 12821 if (templates == 2 && pg != NULL) {
12825 12822 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12826 12823 stability_prop) == 0) {
12827 12824 if (prop_check_type(stability_prop,
12828 12825 SCF_TYPE_ASTRING) == 0 &&
12829 12826 prop_get_val(stability_prop, stability_val) == 0) {
12830 12827 char *stability;
12831 12828
12832 12829 stability = safe_malloc(max_scf_value_len + 1);
12833 12830
12834 12831 if (scf_value_get_astring(stability_val,
12835 12832 stability, max_scf_value_len + 1) == -1 &&
12836 12833 scf_error() != SCF_ERROR_NOT_FOUND)
12837 12834 scfdie();
12838 12835
12839 12836 safe_printf("%s%s: %s\n", TMPL_INDENT,
12840 12837 gettext("stability"), stability);
12841 12838
12842 12839 free(stability);
12843 12840 }
12844 12841 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
12845 12842 scfdie();
12846 12843 }
12847 12844
12848 12845 scf_property_destroy(stability_prop);
12849 12846 scf_value_destroy(stability_val);
12850 12847
12851 12848 if (pgt == NULL)
12852 12849 return;
12853 12850
12854 12851 if (pg == NULL || templates == 2) {
12855 12852 /* print type info only if scf_tmpl_pg_name succeeds */
12856 12853 if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12857 12854 if (pg != NULL)
12858 12855 safe_printf("%s", TMPL_INDENT);
12859 12856 safe_printf("%s: ", gettext("name"));
12860 12857 safe_printf("%s\n", buf);
12861 12858 free(buf);
12862 12859 }
12863 12860
12864 12861 /* print type info only if scf_tmpl_pg_type succeeds */
12865 12862 if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12866 12863 if (pg != NULL)
12867 12864 safe_printf("%s", TMPL_INDENT);
12868 12865 safe_printf("%s: ", gettext("type"));
12869 12866 safe_printf("%s\n", buf);
12870 12867 free(buf);
12871 12868 }
12872 12869 }
12873 12870
12874 12871 if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12875 12872 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12876 12873 required ? "true" : "false");
12877 12874
12878 12875 if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12879 12876 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12880 12877 buf);
12881 12878 free(buf);
12882 12879 }
12883 12880
12884 12881 if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12885 12882 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12886 12883 buf);
12887 12884 free(buf);
12888 12885 }
12889 12886
12890 12887 if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12891 12888 if (templates == 2)
12892 12889 safe_printf("%s%s: %s\n", TMPL_INDENT,
12893 12890 gettext("description"), buf);
12894 12891 else
12895 12892 safe_printf("%s%s\n", TMPL_INDENT, buf);
12896 12893 free(buf);
12897 12894 }
12898 12895
12899 12896 }
12900 12897
12901 12898 /*
12902 12899 * With as_value set to true, indent as appropriate for the value level.
12903 12900 * If false, indent to appropriate level for inclusion in constraint
12904 12901 * or choice printout.
12905 12902 */
12906 12903 static void
12907 12904 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12908 12905 int as_value)
12909 12906 {
12910 12907 char *buf;
12911 12908
12912 12909 if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12913 12910 if (as_value == 0)
12914 12911 safe_printf("%s", TMPL_CHOICE_INDENT);
12915 12912 else
12916 12913 safe_printf("%s", TMPL_INDENT);
12917 12914 safe_printf("%s: %s\n", gettext("value common name"), buf);
12918 12915 free(buf);
12919 12916 }
12920 12917
12921 12918 if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12922 12919 if (as_value == 0)
12923 12920 safe_printf("%s", TMPL_CHOICE_INDENT);
12924 12921 else
12925 12922 safe_printf("%s", TMPL_INDENT);
12926 12923 safe_printf("%s: %s\n", gettext("value description"), buf);
12927 12924 free(buf);
12928 12925 }
12929 12926 }
12930 12927
12931 12928 static void
12932 12929 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12933 12930 {
12934 12931 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12935 12932 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12936 12933 safe_printf("%s\n", val_buf);
12937 12934
12938 12935 print_template_value_details(prt, val_buf, 1);
12939 12936 }
12940 12937
12941 12938 static void
12942 12939 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12943 12940 {
12944 12941 int i, printed = 0;
12945 12942 scf_values_t values;
12946 12943 scf_count_ranges_t c_ranges;
12947 12944 scf_int_ranges_t i_ranges;
12948 12945
12949 12946 printed = 0;
12950 12947 i = 0;
12951 12948 if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12952 12949 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12953 12950 gettext("value constraints"));
12954 12951 printed++;
12955 12952 for (i = 0; i < values.value_count; ++i) {
12956 12953 safe_printf("%s%s: %s\n", TMPL_INDENT,
12957 12954 gettext("value name"), values.values_as_strings[i]);
12958 12955 if (verbose == 1)
12959 12956 print_template_value_details(prt,
12960 12957 values.values_as_strings[i], 0);
12961 12958 }
12962 12959
12963 12960 scf_values_destroy(&values);
12964 12961 }
12965 12962
12966 12963 if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12967 12964 if (printed++ == 0)
12968 12965 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12969 12966 gettext("value constraints"));
12970 12967 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12971 12968 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12972 12969 gettext("range"), c_ranges.scr_min[i],
12973 12970 c_ranges.scr_max[i]);
12974 12971 }
12975 12972 scf_count_ranges_destroy(&c_ranges);
12976 12973 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12977 12974 scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
12978 12975 if (printed++ == 0)
12979 12976 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12980 12977 gettext("value constraints"));
12981 12978 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12982 12979 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12983 12980 gettext("range"), i_ranges.sir_min[i],
12984 12981 i_ranges.sir_max[i]);
12985 12982 }
12986 12983 scf_int_ranges_destroy(&i_ranges);
12987 12984 }
12988 12985 }
12989 12986
12990 12987 static void
12991 12988 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
12992 12989 {
12993 12990 int i = 0, printed = 0;
12994 12991 scf_values_t values;
12995 12992 scf_count_ranges_t c_ranges;
12996 12993 scf_int_ranges_t i_ranges;
12997 12994
12998 12995 printed = 0;
12999 12996 if (scf_tmpl_value_name_choices(prt, &values) == 0) {
13000 12997 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13001 12998 gettext("value constraints"));
13002 12999 printed++;
13003 13000 for (i = 0; i < values.value_count; i++) {
13004 13001 safe_printf("%s%s: %s\n", TMPL_INDENT,
13005 13002 gettext("value name"), values.values_as_strings[i]);
13006 13003 if (verbose == 1)
13007 13004 print_template_value_details(prt,
13008 13005 values.values_as_strings[i], 0);
13009 13006 }
13010 13007
13011 13008 scf_values_destroy(&values);
13012 13009 }
13013 13010
13014 13011 if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
13015 13012 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
13016 13013 if (printed++ == 0)
13017 13014 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13018 13015 gettext("value choices"));
13019 13016 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
13020 13017 gettext("range"), c_ranges.scr_min[i],
13021 13018 c_ranges.scr_max[i]);
13022 13019 }
13023 13020 scf_count_ranges_destroy(&c_ranges);
13024 13021 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
13025 13022 scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
13026 13023 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
13027 13024 if (printed++ == 0)
13028 13025 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13029 13026 gettext("value choices"));
13030 13027 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
13031 13028 gettext("range"), i_ranges.sir_min[i],
13032 13029 i_ranges.sir_max[i]);
13033 13030 }
13034 13031 scf_int_ranges_destroy(&i_ranges);
13035 13032 }
13036 13033 }
13037 13034
13038 13035 static void
13039 13036 list_values_by_template(scf_prop_tmpl_t *prt)
13040 13037 {
13041 13038 print_template_constraints(prt, 1);
13042 13039 print_template_choices(prt, 1);
13043 13040 }
13044 13041
13045 13042 static void
13046 13043 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
13047 13044 {
13048 13045 char *val_buf;
13049 13046 scf_iter_t *iter;
13050 13047 scf_value_t *val;
13051 13048 int ret;
13052 13049
13053 13050 if ((iter = scf_iter_create(g_hndl)) == NULL ||
13054 13051 (val = scf_value_create(g_hndl)) == NULL)
13055 13052 scfdie();
13056 13053
13057 13054 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
13058 13055 scfdie();
13059 13056
13060 13057 val_buf = safe_malloc(max_scf_value_len + 1);
13061 13058
13062 13059 while ((ret = scf_iter_next_value(iter, val)) == 1) {
13063 13060 if (scf_value_get_as_string(val, val_buf,
13064 13061 max_scf_value_len + 1) < 0)
13065 13062 scfdie();
13066 13063
13067 13064 print_template_value(prt, val_buf);
13068 13065 }
13069 13066 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
13070 13067 scfdie();
13071 13068 free(val_buf);
13072 13069
13073 13070 print_template_constraints(prt, 0);
13074 13071 print_template_choices(prt, 0);
13075 13072
13076 13073 }
13077 13074
13078 13075 /*
13079 13076 * Outputs property info for the describe subcommand
13080 13077 * Verbose output if templates == 2, -v option of svccfg describe
13081 13078 * Displays template data if prop is not NULL, -t option of svccfg describe
13082 13079 */
13083 13080 static void
13084 13081 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
13085 13082 {
13086 13083 char *buf;
13087 13084 uint8_t u_buf;
13088 13085 int i;
13089 13086 uint64_t min, max;
13090 13087 scf_values_t values;
13091 13088
13092 13089 if (prt == NULL || templates == 0)
13093 13090 return;
13094 13091
13095 13092 if (prop == NULL) {
13096 13093 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
13097 13094 if (scf_tmpl_prop_name(prt, &buf) > 0) {
13098 13095 safe_printf("%s\n", buf);
13099 13096 free(buf);
13100 13097 } else
13101 13098 safe_printf("(%s)\n", gettext("any"));
13102 13099 }
13103 13100
13104 13101 if (prop == NULL || templates == 2) {
13105 13102 if (prop != NULL)
13106 13103 safe_printf("%s", TMPL_INDENT);
13107 13104 else
13108 13105 safe_printf("%s", TMPL_VALUE_INDENT);
13109 13106 safe_printf("%s: ", gettext("type"));
13110 13107 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
13111 13108 safe_printf("%s\n", buf);
13112 13109 free(buf);
13113 13110 } else
13114 13111 safe_printf("(%s)\n", gettext("any"));
13115 13112 }
13116 13113
13117 13114 if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
13118 13115 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
13119 13116 u_buf ? "true" : "false");
13120 13117
13121 13118 if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
13122 13119 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
13123 13120 buf);
13124 13121 free(buf);
13125 13122 }
13126 13123
13127 13124 if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
13128 13125 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
13129 13126 buf);
13130 13127 free(buf);
13131 13128 }
13132 13129
13133 13130 if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
13134 13131 safe_printf("%s%s\n", TMPL_INDENT, buf);
13135 13132 free(buf);
13136 13133 }
13137 13134
13138 13135 if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
13139 13136 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
13140 13137 scf_tmpl_visibility_to_string(u_buf));
13141 13138
13142 13139 if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
13143 13140 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13144 13141 gettext("minimum number of values"), min);
13145 13142 if (max == ULLONG_MAX) {
13146 13143 safe_printf("%s%s: %s\n", TMPL_INDENT,
13147 13144 gettext("maximum number of values"),
13148 13145 gettext("unlimited"));
13149 13146 } else {
13150 13147 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13151 13148 gettext("maximum number of values"), max);
13152 13149 }
13153 13150 }
13154 13151
13155 13152 if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
13156 13153 for (i = 0; i < values.value_count; i++) {
13157 13154 if (i == 0) {
13158 13155 safe_printf("%s%s:", TMPL_INDENT,
13159 13156 gettext("internal separators"));
13160 13157 }
13161 13158 safe_printf(" \"%s\"", values.values_as_strings[i]);
13162 13159 }
13163 13160 safe_printf("\n");
13164 13161 }
13165 13162
13166 13163 if (templates != 2)
13167 13164 return;
13168 13165
13169 13166 if (prop != NULL)
13170 13167 list_values_tmpl(prt, prop);
13171 13168 else
13172 13169 list_values_by_template(prt);
13173 13170 }
13174 13171
13175 13172 static char *
13176 13173 read_astring(scf_propertygroup_t *pg, const char *prop_name)
13177 13174 {
13178 13175 char *rv;
13179 13176
13180 13177 rv = _scf_read_single_astring_from_pg(pg, prop_name);
13181 13178 if (rv == NULL) {
13182 13179 switch (scf_error()) {
13183 13180 case SCF_ERROR_NOT_FOUND:
13184 13181 break;
13185 13182 default:
13186 13183 scfdie();
13187 13184 }
13188 13185 }
13189 13186 return (rv);
13190 13187 }
13191 13188
13192 13189 static void
13193 13190 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
13194 13191 {
13195 13192 size_t doc_len;
13196 13193 size_t man_len;
13197 13194 char *pg_name;
13198 13195 char *text = NULL;
13199 13196 int rv;
13200 13197
13201 13198 doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
13202 13199 man_len = strlen(SCF_PG_TM_MAN_PREFIX);
13203 13200 pg_name = safe_malloc(max_scf_name_len + 1);
13204 13201 while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
13205 13202 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
13206 13203 scfdie();
13207 13204 }
13208 13205 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
13209 13206 /* Display doc_link and and uri */
13210 13207 safe_printf("%s%s:\n", TMPL_INDENT,
13211 13208 gettext("doc_link"));
13212 13209 text = read_astring(pg, SCF_PROPERTY_TM_NAME);
13213 13210 if (text != NULL) {
13214 13211 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13215 13212 TMPL_INDENT, gettext("name"), text);
13216 13213 uu_free(text);
13217 13214 }
13218 13215 text = read_astring(pg, SCF_PROPERTY_TM_URI);
13219 13216 if (text != NULL) {
13220 13217 safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
13221 13218 gettext("uri"), text);
13222 13219 uu_free(text);
13223 13220 }
13224 13221 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
13225 13222 man_len) == 0) {
13226 13223 /* Display manpage title, section and path */
13227 13224 safe_printf("%s%s:\n", TMPL_INDENT,
13228 13225 gettext("manpage"));
13229 13226 text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
13230 13227 if (text != NULL) {
13231 13228 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13232 13229 TMPL_INDENT, gettext("title"), text);
13233 13230 uu_free(text);
13234 13231 }
13235 13232 text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
13236 13233 if (text != NULL) {
13237 13234 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13238 13235 TMPL_INDENT, gettext("section"), text);
13239 13236 uu_free(text);
13240 13237 }
13241 13238 text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
13242 13239 if (text != NULL) {
13243 13240 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13244 13241 TMPL_INDENT, gettext("manpath"), text);
13245 13242 uu_free(text);
13246 13243 }
13247 13244 }
13248 13245 }
13249 13246 if (rv == -1)
13250 13247 scfdie();
13251 13248
13252 13249 done:
13253 13250 free(pg_name);
13254 13251 }
13255 13252
13256 13253 static void
13257 13254 list_entity_tmpl(int templates)
13258 13255 {
13259 13256 char *common_name = NULL;
13260 13257 char *description = NULL;
13261 13258 char *locale = NULL;
13262 13259 scf_iter_t *iter;
13263 13260 scf_propertygroup_t *pg;
13264 13261 scf_property_t *prop;
13265 13262 int r;
13266 13263 scf_value_t *val;
13267 13264
13268 13265 if ((pg = scf_pg_create(g_hndl)) == NULL ||
13269 13266 (prop = scf_property_create(g_hndl)) == NULL ||
13270 13267 (val = scf_value_create(g_hndl)) == NULL ||
13271 13268 (iter = scf_iter_create(g_hndl)) == NULL)
13272 13269 scfdie();
13273 13270
13274 13271 locale = setlocale(LC_MESSAGES, NULL);
13275 13272
13276 13273 if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
13277 13274 common_name = safe_malloc(max_scf_value_len + 1);
13278 13275
13279 13276 /* Try both the current locale and the "C" locale. */
13280 13277 if (scf_pg_get_property(pg, locale, prop) == 0 ||
13281 13278 (scf_error() == SCF_ERROR_NOT_FOUND &&
13282 13279 scf_pg_get_property(pg, "C", prop) == 0)) {
13283 13280 if (prop_get_val(prop, val) == 0 &&
13284 13281 scf_value_get_ustring(val, common_name,
13285 13282 max_scf_value_len + 1) != -1) {
13286 13283 safe_printf("%s%s: %s\n", TMPL_INDENT,
13287 13284 gettext("common name"), common_name);
13288 13285 }
13289 13286 }
13290 13287 }
13291 13288
13292 13289 /*
13293 13290 * Do description, manpages, and doc links if templates == 2.
13294 13291 */
13295 13292 if (templates == 2) {
13296 13293 /* Get the description. */
13297 13294 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
13298 13295 description = safe_malloc(max_scf_value_len + 1);
13299 13296
13300 13297 /* Try both the current locale and the "C" locale. */
13301 13298 if (scf_pg_get_property(pg, locale, prop) == 0 ||
13302 13299 (scf_error() == SCF_ERROR_NOT_FOUND &&
13303 13300 scf_pg_get_property(pg, "C", prop) == 0)) {
13304 13301 if (prop_get_val(prop, val) == 0 &&
13305 13302 scf_value_get_ustring(val, description,
13306 13303 max_scf_value_len + 1) != -1) {
13307 13304 safe_printf("%s%s: %s\n", TMPL_INDENT,
13308 13305 gettext("description"),
13309 13306 description);
13310 13307 }
13311 13308 }
13312 13309 }
13313 13310
13314 13311 /* Process doc_link & manpage elements. */
13315 13312 if (cur_level != NULL) {
13316 13313 r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
13317 13314 SCF_GROUP_TEMPLATE);
13318 13315 } else if (cur_inst != NULL) {
13319 13316 r = scf_iter_instance_pgs_typed(iter, cur_inst,
13320 13317 SCF_GROUP_TEMPLATE);
13321 13318 } else {
13322 13319 r = scf_iter_service_pgs_typed(iter, cur_svc,
13323 13320 SCF_GROUP_TEMPLATE);
13324 13321 }
13325 13322 if (r == 0) {
13326 13323 display_documentation(iter, pg);
13327 13324 }
13328 13325 }
13329 13326
13330 13327 free(common_name);
13331 13328 free(description);
13332 13329 scf_pg_destroy(pg);
13333 13330 scf_property_destroy(prop);
13334 13331 scf_value_destroy(val);
13335 13332 scf_iter_destroy(iter);
13336 13333 }
13337 13334
13338 13335 static void
13339 13336 listtmpl(const char *pattern, int templates)
13340 13337 {
13341 13338 scf_pg_tmpl_t *pgt;
13342 13339 scf_prop_tmpl_t *prt;
13343 13340 char *snapbuf = NULL;
13344 13341 char *fmribuf;
13345 13342 char *pg_name = NULL, *prop_name = NULL;
13346 13343 ssize_t prop_name_size;
13347 13344 char *qual_prop_name;
13348 13345 char *search_name;
13349 13346 int listed = 0;
13350 13347
13351 13348 if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13352 13349 (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
13353 13350 scfdie();
13354 13351
13355 13352 fmribuf = safe_malloc(max_scf_name_len + 1);
13356 13353 qual_prop_name = safe_malloc(max_scf_name_len + 1);
13357 13354
13358 13355 if (cur_snap != NULL) {
13359 13356 snapbuf = safe_malloc(max_scf_name_len + 1);
13360 13357 if (scf_snapshot_get_name(cur_snap, snapbuf,
13361 13358 max_scf_name_len + 1) < 0)
13362 13359 scfdie();
13363 13360 }
13364 13361
13365 13362 if (cur_inst != NULL) {
13366 13363 if (scf_instance_to_fmri(cur_inst, fmribuf,
13367 13364 max_scf_name_len + 1) < 0)
13368 13365 scfdie();
13369 13366 } else if (cur_svc != NULL) {
13370 13367 if (scf_service_to_fmri(cur_svc, fmribuf,
13371 13368 max_scf_name_len + 1) < 0)
13372 13369 scfdie();
13373 13370 } else
13374 13371 abort();
13375 13372
13376 13373 /* If pattern is specified, we want to list only those items. */
13377 13374 while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) {
13378 13375 listed = 0;
13379 13376 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
13380 13377 fnmatch(pattern, pg_name, 0) == 0)) {
13381 13378 list_pg_tmpl(pgt, NULL, templates);
13382 13379 listed++;
13383 13380 }
13384 13381
13385 13382 scf_tmpl_prop_reset(prt);
13386 13383
13387 13384 while (scf_tmpl_iter_props(pgt, prt, 0) == 0) {
13388 13385 search_name = NULL;
13389 13386 prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
13390 13387 if ((prop_name_size > 0) && (pg_name != NULL)) {
13391 13388 if (snprintf(qual_prop_name,
13392 13389 max_scf_name_len + 1, "%s/%s",
13393 13390 pg_name, prop_name) >=
13394 13391 max_scf_name_len + 1) {
13395 13392 prop_name_size = -1;
13396 13393 } else {
13397 13394 search_name = qual_prop_name;
13398 13395 }
13399 13396 }
13400 13397 if (listed > 0 || pattern == NULL ||
13401 13398 (prop_name_size > 0 &&
13402 13399 fnmatch(pattern, search_name,
13403 13400 FNM_PATHNAME) == 0))
13404 13401 list_prop_tmpl(prt, NULL, templates);
13405 13402 if (prop_name != NULL) {
13406 13403 free(prop_name);
13407 13404 prop_name = NULL;
13408 13405 }
13409 13406 }
13410 13407 if (pg_name != NULL) {
13411 13408 free(pg_name);
13412 13409 pg_name = NULL;
13413 13410 }
13414 13411 }
13415 13412
13416 13413 scf_tmpl_prop_destroy(prt);
13417 13414 scf_tmpl_pg_destroy(pgt);
13418 13415 free(snapbuf);
13419 13416 free(fmribuf);
13420 13417 free(qual_prop_name);
13421 13418 }
13422 13419
13423 13420 static void
13424 13421 listprop(const char *pattern, int only_pgs, int templates)
13425 13422 {
13426 13423 scf_propertygroup_t *pg;
13427 13424 scf_property_t *prop;
13428 13425 scf_iter_t *iter, *piter;
13429 13426 char *pgnbuf, *prnbuf, *ppnbuf;
13430 13427 scf_pg_tmpl_t *pgt, *pgtp;
13431 13428 scf_prop_tmpl_t *prt;
13432 13429
13433 13430 void **objects;
13434 13431 char **names;
13435 13432 void **tmpls;
13436 13433 int allocd, i;
13437 13434
13438 13435 int ret;
13439 13436 ssize_t pgnlen, prnlen, szret;
13440 13437 size_t max_len = 0;
13441 13438
13442 13439 if (cur_svc == NULL && cur_inst == NULL) {
13443 13440 semerr(emsg_entity_not_selected);
13444 13441 return;
13445 13442 }
13446 13443
13447 13444 if ((pg = scf_pg_create(g_hndl)) == NULL ||
13448 13445 (prop = scf_property_create(g_hndl)) == NULL ||
13449 13446 (iter = scf_iter_create(g_hndl)) == NULL ||
13450 13447 (piter = scf_iter_create(g_hndl)) == NULL ||
13451 13448 (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13452 13449 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
13453 13450 scfdie();
13454 13451
13455 13452 prnbuf = safe_malloc(max_scf_name_len + 1);
13456 13453
13457 13454 if (cur_level != NULL)
13458 13455 ret = scf_iter_snaplevel_pgs(iter, cur_level);
13459 13456 else if (cur_inst != NULL)
13460 13457 ret = scf_iter_instance_pgs(iter, cur_inst);
13461 13458 else
13462 13459 ret = scf_iter_service_pgs(iter, cur_svc);
13463 13460 if (ret != 0) {
13464 13461 return;
13465 13462 }
13466 13463
13467 13464 /*
13468 13465 * We want to only list items which match pattern, and we want the
13469 13466 * second column to line up, so during the first pass we'll save
13470 13467 * matching items, their names, and their templates in objects,
13471 13468 * names, and tmpls, computing the maximum name length as we go,
13472 13469 * and then we'll print them out.
13473 13470 *
13474 13471 * Note: We always keep an extra slot available so the array can be
13475 13472 * NULL-terminated.
13476 13473 */
13477 13474 i = 0;
13478 13475 allocd = 1;
13479 13476 objects = safe_malloc(sizeof (*objects));
13480 13477 names = safe_malloc(sizeof (*names));
13481 13478 tmpls = safe_malloc(sizeof (*tmpls));
13482 13479
13483 13480 while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13484 13481 int new_pg = 0;
13485 13482 int print_props = 0;
13486 13483 pgtp = NULL;
13487 13484
13488 13485 pgnlen = scf_pg_get_name(pg, NULL, 0);
13489 13486 if (pgnlen < 0)
13490 13487 scfdie();
13491 13488
13492 13489 pgnbuf = safe_malloc(pgnlen + 1);
13493 13490
13494 13491 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
13495 13492 if (szret < 0)
13496 13493 scfdie();
13497 13494 assert(szret <= pgnlen);
13498 13495
13499 13496 if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) {
13500 13497 if (scf_error() != SCF_ERROR_NOT_FOUND)
13501 13498 scfdie();
13502 13499 pgtp = NULL;
13503 13500 } else {
13504 13501 pgtp = pgt;
13505 13502 }
13506 13503
13507 13504 if (pattern == NULL ||
13508 13505 fnmatch(pattern, pgnbuf, 0) == 0) {
13509 13506 if (i+1 >= allocd) {
13510 13507 allocd *= 2;
13511 13508 objects = realloc(objects,
13512 13509 sizeof (*objects) * allocd);
13513 13510 names =
13514 13511 realloc(names, sizeof (*names) * allocd);
13515 13512 tmpls = realloc(tmpls,
13516 13513 sizeof (*tmpls) * allocd);
13517 13514 if (objects == NULL || names == NULL ||
13518 13515 tmpls == NULL)
13519 13516 uu_die(gettext("Out of memory"));
13520 13517 }
13521 13518 objects[i] = pg;
13522 13519 names[i] = pgnbuf;
13523 13520
13524 13521 if (pgtp == NULL)
13525 13522 tmpls[i] = NULL;
13526 13523 else
13527 13524 tmpls[i] = pgt;
13528 13525
13529 13526 ++i;
13530 13527
13531 13528 if (pgnlen > max_len)
13532 13529 max_len = pgnlen;
13533 13530
13534 13531 new_pg = 1;
13535 13532 print_props = 1;
13536 13533 }
13537 13534
13538 13535 if (only_pgs) {
13539 13536 if (new_pg) {
13540 13537 pg = scf_pg_create(g_hndl);
13541 13538 if (pg == NULL)
13542 13539 scfdie();
13543 13540 pgt = scf_tmpl_pg_create(g_hndl);
13544 13541 if (pgt == NULL)
13545 13542 scfdie();
13546 13543 } else
13547 13544 free(pgnbuf);
13548 13545
13549 13546 continue;
13550 13547 }
13551 13548
13552 13549 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13553 13550 scfdie();
13554 13551
13555 13552 while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13556 13553 prnlen = scf_property_get_name(prop, prnbuf,
13557 13554 max_scf_name_len + 1);
13558 13555 if (prnlen < 0)
13559 13556 scfdie();
13560 13557
13561 13558 /* Will prepend the property group name and a slash. */
13562 13559 prnlen += pgnlen + 1;
13563 13560
13564 13561 ppnbuf = safe_malloc(prnlen + 1);
13565 13562
13566 13563 if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13567 13564 prnbuf) < 0)
13568 13565 uu_die("snprintf");
13569 13566
13570 13567 if (pattern == NULL || print_props == 1 ||
13571 13568 fnmatch(pattern, ppnbuf, 0) == 0) {
13572 13569 if (i+1 >= allocd) {
13573 13570 allocd *= 2;
13574 13571 objects = realloc(objects,
13575 13572 sizeof (*objects) * allocd);
13576 13573 names = realloc(names,
13577 13574 sizeof (*names) * allocd);
13578 13575 tmpls = realloc(tmpls,
13579 13576 sizeof (*tmpls) * allocd);
13580 13577 if (objects == NULL || names == NULL ||
13581 13578 tmpls == NULL)
13582 13579 uu_die(gettext(
13583 13580 "Out of memory"));
13584 13581 }
13585 13582
13586 13583 objects[i] = prop;
13587 13584 names[i] = ppnbuf;
13588 13585
13589 13586 if (pgtp != NULL) {
13590 13587 if (scf_tmpl_get_by_prop(pgt, prnbuf,
13591 13588 prt, 0) < 0) {
13592 13589 if (scf_error() !=
13593 13590 SCF_ERROR_NOT_FOUND)
13594 13591 scfdie();
13595 13592 tmpls[i] = NULL;
13596 13593 } else {
13597 13594 tmpls[i] = prt;
13598 13595 }
13599 13596 } else {
13600 13597 tmpls[i] = NULL;
13601 13598 }
13602 13599
13603 13600 ++i;
13604 13601
13605 13602 if (prnlen > max_len)
13606 13603 max_len = prnlen;
13607 13604
13608 13605 prop = scf_property_create(g_hndl);
13609 13606 prt = scf_tmpl_prop_create(g_hndl);
13610 13607 } else {
13611 13608 free(ppnbuf);
13612 13609 }
13613 13610 }
13614 13611
13615 13612 if (new_pg) {
13616 13613 pg = scf_pg_create(g_hndl);
13617 13614 if (pg == NULL)
13618 13615 scfdie();
13619 13616 pgt = scf_tmpl_pg_create(g_hndl);
13620 13617 if (pgt == NULL)
13621 13618 scfdie();
13622 13619 } else
13623 13620 free(pgnbuf);
13624 13621 }
13625 13622 if (ret != 0)
13626 13623 scfdie();
13627 13624
13628 13625 objects[i] = NULL;
13629 13626
13630 13627 scf_pg_destroy(pg);
13631 13628 scf_tmpl_pg_destroy(pgt);
13632 13629 scf_property_destroy(prop);
13633 13630 scf_tmpl_prop_destroy(prt);
13634 13631
13635 13632 for (i = 0; objects[i] != NULL; ++i) {
13636 13633 if (strchr(names[i], '/') == NULL) {
13637 13634 /* property group */
13638 13635 pg = (scf_propertygroup_t *)objects[i];
13639 13636 pgt = (scf_pg_tmpl_t *)tmpls[i];
13640 13637 list_pg_info(pg, names[i], max_len);
13641 13638 list_pg_tmpl(pgt, pg, templates);
13642 13639 free(names[i]);
13643 13640 scf_pg_destroy(pg);
13644 13641 if (pgt != NULL)
13645 13642 scf_tmpl_pg_destroy(pgt);
13646 13643 } else {
13647 13644 /* property */
13648 13645 prop = (scf_property_t *)objects[i];
13649 13646 prt = (scf_prop_tmpl_t *)tmpls[i];
13650 13647 list_prop_info(prop, names[i], max_len);
13651 13648 list_prop_tmpl(prt, prop, templates);
13652 13649 free(names[i]);
13653 13650 scf_property_destroy(prop);
13654 13651 if (prt != NULL)
13655 13652 scf_tmpl_prop_destroy(prt);
13656 13653 }
13657 13654 }
13658 13655
13659 13656 free(names);
13660 13657 free(objects);
13661 13658 free(tmpls);
13662 13659 }
13663 13660
13664 13661 void
13665 13662 lscf_listpg(const char *pattern)
13666 13663 {
13667 13664 lscf_prep_hndl();
13668 13665
13669 13666 listprop(pattern, 1, 0);
13670 13667 }
13671 13668
13672 13669 /*
13673 13670 * Property group and property creation, setting, and deletion. setprop (and
13674 13671 * its alias, addprop) can either create a property group of a given type, or
13675 13672 * it can create or set a property to a given type and list of values.
13676 13673 */
13677 13674 void
13678 13675 lscf_addpg(const char *name, const char *type, const char *flags)
13679 13676 {
13680 13677 scf_propertygroup_t *pg;
13681 13678 int ret;
13682 13679 uint32_t flgs = 0;
13683 13680 const char *cp;
13684 13681
13685 13682
13686 13683 lscf_prep_hndl();
13687 13684
13688 13685 if (cur_snap != NULL) {
13689 13686 semerr(emsg_cant_modify_snapshots);
13690 13687 return;
13691 13688 }
13692 13689
13693 13690 if (cur_inst == NULL && cur_svc == NULL) {
13694 13691 semerr(emsg_entity_not_selected);
13695 13692 return;
13696 13693 }
13697 13694
13698 13695 if (flags != NULL) {
13699 13696 for (cp = flags; *cp != '\0'; ++cp) {
13700 13697 switch (*cp) {
13701 13698 case 'P':
13702 13699 flgs |= SCF_PG_FLAG_NONPERSISTENT;
13703 13700 break;
13704 13701
13705 13702 case 'p':
13706 13703 flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13707 13704 break;
13708 13705
13709 13706 default:
13710 13707 semerr(gettext("Invalid property group flag "
13711 13708 "%c."), *cp);
13712 13709 return;
13713 13710 }
13714 13711 }
13715 13712 }
13716 13713
13717 13714 pg = scf_pg_create(g_hndl);
13718 13715 if (pg == NULL)
13719 13716 scfdie();
13720 13717
13721 13718 if (cur_inst != NULL)
13722 13719 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13723 13720 else
13724 13721 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13725 13722
13726 13723 if (ret != SCF_SUCCESS) {
13727 13724 switch (scf_error()) {
13728 13725 case SCF_ERROR_INVALID_ARGUMENT:
13729 13726 semerr(gettext("Name, type, or flags are invalid.\n"));
13730 13727 break;
13731 13728
13732 13729 case SCF_ERROR_EXISTS:
13733 13730 semerr(gettext("Property group already exists.\n"));
13734 13731 break;
13735 13732
13736 13733 case SCF_ERROR_PERMISSION_DENIED:
13737 13734 semerr(emsg_permission_denied);
13738 13735 break;
13739 13736
13740 13737 case SCF_ERROR_BACKEND_ACCESS:
13741 13738 semerr(gettext("Backend refused access.\n"));
13742 13739 break;
13743 13740
13744 13741 default:
13745 13742 scfdie();
13746 13743 }
13747 13744 }
13748 13745
13749 13746 scf_pg_destroy(pg);
13750 13747
13751 13748 private_refresh();
13752 13749 }
13753 13750
13754 13751 void
13755 13752 lscf_delpg(char *name)
13756 13753 {
13757 13754 lscf_prep_hndl();
13758 13755
13759 13756 if (cur_snap != NULL) {
13760 13757 semerr(emsg_cant_modify_snapshots);
13761 13758 return;
13762 13759 }
13763 13760
13764 13761 if (cur_inst == NULL && cur_svc == NULL) {
13765 13762 semerr(emsg_entity_not_selected);
13766 13763 return;
13767 13764 }
13768 13765
13769 13766 if (strchr(name, '/') != NULL) {
13770 13767 semerr(emsg_invalid_pg_name, name);
13771 13768 return;
13772 13769 }
13773 13770
13774 13771 lscf_delprop(name);
13775 13772 }
13776 13773
13777 13774 /*
13778 13775 * scf_delhash() is used to remove the property group related to the
13779 13776 * hash entry for a specific manifest in the repository. pgname will be
13780 13777 * constructed from the location of the manifest file. If deathrow isn't 0,
13781 13778 * manifest file doesn't need to exist (manifest string will be used as
13782 13779 * an absolute path).
13783 13780 */
13784 13781 void
13785 13782 lscf_delhash(char *manifest, int deathrow)
13786 13783 {
13787 13784 char *pgname;
13788 13785
13789 13786 if (cur_snap != NULL ||
13790 13787 cur_inst != NULL || cur_svc != NULL) {
13791 13788 warn(gettext("error, an entity is selected\n"));
13792 13789 return;
13793 13790 }
13794 13791
13795 13792 /* select smf/manifest */
13796 13793 lscf_select(HASH_SVC);
13797 13794 /*
13798 13795 * Translate the manifest file name to property name. In the deathrow
13799 13796 * case, the manifest file does not need to exist.
13800 13797 */
13801 13798 pgname = mhash_filename_to_propname(manifest,
13802 13799 deathrow ? B_TRUE : B_FALSE);
13803 13800 if (pgname == NULL) {
13804 13801 warn(gettext("cannot resolve pathname for %s\n"), manifest);
13805 13802 return;
13806 13803 }
13807 13804 /* delete the hash property name */
13808 13805 lscf_delpg(pgname);
13809 13806 }
13810 13807
13811 13808 void
13812 13809 lscf_listprop(const char *pattern)
13813 13810 {
13814 13811 lscf_prep_hndl();
13815 13812
13816 13813 listprop(pattern, 0, 0);
13817 13814 }
13818 13815
13819 13816 int
13820 13817 lscf_setprop(const char *pgname, const char *type, const char *value,
13821 13818 const uu_list_t *values)
13822 13819 {
13823 13820 scf_type_t ty, current_ty;
13824 13821 scf_service_t *svc;
13825 13822 scf_propertygroup_t *pg, *parent_pg;
13826 13823 scf_property_t *prop, *parent_prop;
13827 13824 scf_pg_tmpl_t *pgt;
13828 13825 scf_prop_tmpl_t *prt;
13829 13826 int ret, result = 0;
13830 13827 scf_transaction_t *tx;
13831 13828 scf_transaction_entry_t *e;
13832 13829 scf_value_t *v;
13833 13830 uu_list_walk_t *walk;
13834 13831 string_list_t *sp;
13835 13832 char *propname;
13836 13833 int req_quotes = 0;
13837 13834
13838 13835 lscf_prep_hndl();
13839 13836
13840 13837 if ((e = scf_entry_create(g_hndl)) == NULL ||
13841 13838 (svc = scf_service_create(g_hndl)) == NULL ||
13842 13839 (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13843 13840 (pg = scf_pg_create(g_hndl)) == NULL ||
13844 13841 (parent_prop = scf_property_create(g_hndl)) == NULL ||
13845 13842 (prop = scf_property_create(g_hndl)) == NULL ||
13846 13843 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13847 13844 (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13848 13845 (tx = scf_transaction_create(g_hndl)) == NULL)
13849 13846 scfdie();
13850 13847
13851 13848 if (cur_snap != NULL) {
13852 13849 semerr(emsg_cant_modify_snapshots);
13853 13850 goto fail;
13854 13851 }
13855 13852
13856 13853 if (cur_inst == NULL && cur_svc == NULL) {
13857 13854 semerr(emsg_entity_not_selected);
13858 13855 goto fail;
13859 13856 }
13860 13857
13861 13858 propname = strchr(pgname, '/');
13862 13859 if (propname == NULL) {
13863 13860 semerr(gettext("Property names must contain a `/'.\n"));
13864 13861 goto fail;
13865 13862 }
13866 13863
13867 13864 *propname = '\0';
13868 13865 ++propname;
13869 13866
13870 13867 if (type != NULL) {
13871 13868 ty = string_to_type(type);
13872 13869 if (ty == SCF_TYPE_INVALID) {
13873 13870 semerr(gettext("Unknown type \"%s\".\n"), type);
13874 13871 goto fail;
13875 13872 }
13876 13873 }
13877 13874
13878 13875 if (cur_inst != NULL)
13879 13876 ret = scf_instance_get_pg(cur_inst, pgname, pg);
13880 13877 else
13881 13878 ret = scf_service_get_pg(cur_svc, pgname, pg);
13882 13879 if (ret != SCF_SUCCESS) {
13883 13880 switch (scf_error()) {
13884 13881 case SCF_ERROR_NOT_FOUND:
13885 13882 semerr(emsg_no_such_pg, pgname);
13886 13883 goto fail;
13887 13884
13888 13885 case SCF_ERROR_INVALID_ARGUMENT:
13889 13886 semerr(emsg_invalid_pg_name, pgname);
13890 13887 goto fail;
13891 13888
13892 13889 default:
13893 13890 scfdie();
13894 13891 break;
13895 13892 }
13896 13893 }
13897 13894
13898 13895 do {
13899 13896 if (scf_pg_update(pg) == -1)
13900 13897 scfdie();
13901 13898 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13902 13899 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13903 13900 scfdie();
13904 13901
13905 13902 semerr(emsg_permission_denied);
13906 13903 goto fail;
13907 13904 }
13908 13905
13909 13906 ret = scf_pg_get_property(pg, propname, prop);
13910 13907 if (ret == SCF_SUCCESS) {
13911 13908 if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS)
13912 13909 scfdie();
13913 13910
13914 13911 if (type == NULL)
13915 13912 ty = current_ty;
13916 13913 if (scf_transaction_property_change_type(tx, e,
13917 13914 propname, ty) == -1)
13918 13915 scfdie();
13919 13916
13920 13917 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13921 13918 /* Infer the type, if possible. */
13922 13919 if (type == NULL) {
13923 13920 /*
13924 13921 * First check if we're an instance and the
13925 13922 * property is set on the service.
13926 13923 */
13927 13924 if (cur_inst != NULL &&
13928 13925 scf_instance_get_parent(cur_inst,
13929 13926 svc) == 0 &&
13930 13927 scf_service_get_pg(cur_svc, pgname,
13931 13928 parent_pg) == 0 &&
13932 13929 scf_pg_get_property(parent_pg, propname,
13933 13930 parent_prop) == 0 &&
13934 13931 scf_property_type(parent_prop,
13935 13932 ¤t_ty) == 0) {
13936 13933 ty = current_ty;
13937 13934
13938 13935 /* Then check for a type set in a template. */
13939 13936 } else if (scf_tmpl_get_by_pg(pg, pgt,
13940 13937 0) == 0 &&
13941 13938 scf_tmpl_get_by_prop(pgt, propname, prt,
13942 13939 0) == 0 &&
13943 13940 scf_tmpl_prop_type(prt, ¤t_ty) == 0) {
13944 13941 ty = current_ty;
13945 13942
13946 13943 /* If type can't be inferred, fail. */
13947 13944 } else {
13948 13945 semerr(gettext("Type required for new "
13949 13946 "properties.\n"));
13950 13947 goto fail;
13951 13948 }
13952 13949 }
13953 13950 if (scf_transaction_property_new(tx, e, propname,
13954 13951 ty) == -1)
13955 13952 scfdie();
13956 13953 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13957 13954 semerr(emsg_invalid_prop_name, propname);
13958 13955 goto fail;
13959 13956 } else {
13960 13957 scfdie();
13961 13958 }
13962 13959
13963 13960 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13964 13961 req_quotes = 1;
13965 13962
13966 13963 if (value != NULL) {
13967 13964 v = string_to_value(value, ty, 0);
13968 13965
13969 13966 if (v == NULL)
13970 13967 goto fail;
13971 13968
13972 13969 ret = scf_entry_add_value(e, v);
13973 13970 assert(ret == SCF_SUCCESS);
13974 13971 } else {
13975 13972 assert(values != NULL);
13976 13973
13977 13974 walk = uu_list_walk_start((uu_list_t *)values,
13978 13975 UU_DEFAULT);
13979 13976 if (walk == NULL)
13980 13977 uu_die(gettext("Could not walk list"));
13981 13978
13982 13979 for (sp = uu_list_walk_next(walk); sp != NULL;
13983 13980 sp = uu_list_walk_next(walk)) {
13984 13981 v = string_to_value(sp->str, ty, req_quotes);
13985 13982
13986 13983 if (v == NULL) {
13987 13984 scf_entry_destroy_children(e);
13988 13985 goto fail;
13989 13986 }
13990 13987
13991 13988 ret = scf_entry_add_value(e, v);
13992 13989 assert(ret == SCF_SUCCESS);
13993 13990 }
13994 13991 uu_list_walk_end(walk);
13995 13992 }
13996 13993 result = scf_transaction_commit(tx);
13997 13994
13998 13995 scf_transaction_reset(tx);
13999 13996 scf_entry_destroy_children(e);
14000 13997 } while (result == 0);
14001 13998
14002 13999 if (result < 0) {
14003 14000 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14004 14001 scfdie();
14005 14002
14006 14003 semerr(emsg_permission_denied);
14007 14004 goto fail;
14008 14005 }
14009 14006
14010 14007 ret = 0;
14011 14008
14012 14009 private_refresh();
14013 14010
14014 14011 goto cleanup;
14015 14012
14016 14013 fail:
14017 14014 ret = -1;
14018 14015
14019 14016 cleanup:
14020 14017 scf_transaction_destroy(tx);
14021 14018 scf_entry_destroy(e);
14022 14019 scf_service_destroy(svc);
14023 14020 scf_pg_destroy(parent_pg);
14024 14021 scf_pg_destroy(pg);
14025 14022 scf_property_destroy(parent_prop);
14026 14023 scf_property_destroy(prop);
14027 14024 scf_tmpl_pg_destroy(pgt);
14028 14025 scf_tmpl_prop_destroy(prt);
14029 14026
14030 14027 return (ret);
14031 14028 }
14032 14029
14033 14030 void
14034 14031 lscf_delprop(char *pgn)
14035 14032 {
14036 14033 char *slash, *pn;
14037 14034 scf_propertygroup_t *pg;
14038 14035 scf_transaction_t *tx;
14039 14036 scf_transaction_entry_t *e;
14040 14037 int ret;
14041 14038
14042 14039
14043 14040 lscf_prep_hndl();
14044 14041
14045 14042 if (cur_snap != NULL) {
14046 14043 semerr(emsg_cant_modify_snapshots);
14047 14044 return;
14048 14045 }
14049 14046
14050 14047 if (cur_inst == NULL && cur_svc == NULL) {
14051 14048 semerr(emsg_entity_not_selected);
14052 14049 return;
14053 14050 }
14054 14051
14055 14052 pg = scf_pg_create(g_hndl);
14056 14053 if (pg == NULL)
14057 14054 scfdie();
14058 14055
14059 14056 slash = strchr(pgn, '/');
14060 14057 if (slash == NULL) {
14061 14058 pn = NULL;
14062 14059 } else {
14063 14060 *slash = '\0';
14064 14061 pn = slash + 1;
14065 14062 }
14066 14063
14067 14064 if (cur_inst != NULL)
14068 14065 ret = scf_instance_get_pg(cur_inst, pgn, pg);
14069 14066 else
14070 14067 ret = scf_service_get_pg(cur_svc, pgn, pg);
14071 14068 if (ret != SCF_SUCCESS) {
14072 14069 switch (scf_error()) {
14073 14070 case SCF_ERROR_NOT_FOUND:
14074 14071 semerr(emsg_no_such_pg, pgn);
14075 14072 break;
14076 14073
14077 14074 case SCF_ERROR_INVALID_ARGUMENT:
14078 14075 semerr(emsg_invalid_pg_name, pgn);
14079 14076 break;
14080 14077
14081 14078 default:
14082 14079 scfdie();
14083 14080 }
14084 14081
14085 14082 scf_pg_destroy(pg);
14086 14083
14087 14084 return;
14088 14085 }
14089 14086
14090 14087 if (pn == NULL) {
14091 14088 /* Try to delete the property group. */
14092 14089 if (scf_pg_delete(pg) != SCF_SUCCESS) {
14093 14090 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14094 14091 scfdie();
14095 14092
14096 14093 semerr(emsg_permission_denied);
14097 14094 } else {
14098 14095 private_refresh();
14099 14096 }
14100 14097
14101 14098 scf_pg_destroy(pg);
14102 14099 return;
14103 14100 }
14104 14101
14105 14102 e = scf_entry_create(g_hndl);
14106 14103 tx = scf_transaction_create(g_hndl);
14107 14104
14108 14105 do {
14109 14106 if (scf_pg_update(pg) == -1)
14110 14107 scfdie();
14111 14108 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
14112 14109 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14113 14110 scfdie();
14114 14111
14115 14112 semerr(emsg_permission_denied);
14116 14113 break;
14117 14114 }
14118 14115
14119 14116 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
14120 14117 if (scf_error() == SCF_ERROR_NOT_FOUND) {
14121 14118 semerr(gettext("No such property %s/%s.\n"),
14122 14119 pgn, pn);
14123 14120 break;
14124 14121 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14125 14122 semerr(emsg_invalid_prop_name, pn);
14126 14123 break;
14127 14124 } else {
14128 14125 scfdie();
14129 14126 }
14130 14127 }
14131 14128
14132 14129 ret = scf_transaction_commit(tx);
14133 14130
14134 14131 if (ret == 0)
14135 14132 scf_transaction_reset(tx);
14136 14133 } while (ret == 0);
14137 14134
14138 14135 if (ret < 0) {
14139 14136 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14140 14137 scfdie();
14141 14138
14142 14139 semerr(emsg_permission_denied);
14143 14140 } else {
14144 14141 private_refresh();
14145 14142 }
14146 14143
14147 14144 scf_transaction_destroy(tx);
14148 14145 scf_entry_destroy(e);
14149 14146 scf_pg_destroy(pg);
14150 14147 }
14151 14148
14152 14149 /*
14153 14150 * Property editing.
14154 14151 */
14155 14152
14156 14153 static int
14157 14154 write_edit_script(FILE *strm)
14158 14155 {
14159 14156 char *fmribuf;
14160 14157 ssize_t fmrilen;
14161 14158
14162 14159 scf_propertygroup_t *pg;
14163 14160 scf_property_t *prop;
14164 14161 scf_value_t *val;
14165 14162 scf_type_t ty;
14166 14163 int ret, result = 0;
14167 14164 scf_iter_t *iter, *piter, *viter;
14168 14165 char *buf, *tybuf, *pname;
14169 14166 const char *emsg_write_error;
14170 14167
14171 14168
14172 14169 emsg_write_error = gettext("Error writing temoprary file: %s.\n");
14173 14170
14174 14171
14175 14172 /* select fmri */
14176 14173 if (cur_inst != NULL) {
14177 14174 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
14178 14175 if (fmrilen < 0)
14179 14176 scfdie();
14180 14177 fmribuf = safe_malloc(fmrilen + 1);
14181 14178 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
14182 14179 scfdie();
14183 14180 } else {
14184 14181 assert(cur_svc != NULL);
14185 14182 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
14186 14183 if (fmrilen < 0)
14187 14184 scfdie();
14188 14185 fmribuf = safe_malloc(fmrilen + 1);
14189 14186 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
14190 14187 scfdie();
14191 14188 }
14192 14189
14193 14190 if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
14194 14191 warn(emsg_write_error, strerror(errno));
14195 14192 free(fmribuf);
14196 14193 return (-1);
14197 14194 }
14198 14195
14199 14196 free(fmribuf);
14200 14197
14201 14198
14202 14199 if ((pg = scf_pg_create(g_hndl)) == NULL ||
14203 14200 (prop = scf_property_create(g_hndl)) == NULL ||
14204 14201 (val = scf_value_create(g_hndl)) == NULL ||
14205 14202 (iter = scf_iter_create(g_hndl)) == NULL ||
14206 14203 (piter = scf_iter_create(g_hndl)) == NULL ||
14207 14204 (viter = scf_iter_create(g_hndl)) == NULL)
14208 14205 scfdie();
14209 14206
14210 14207 buf = safe_malloc(max_scf_name_len + 1);
14211 14208 tybuf = safe_malloc(max_scf_pg_type_len + 1);
14212 14209 pname = safe_malloc(max_scf_name_len + 1);
14213 14210
14214 14211 if (cur_inst != NULL)
14215 14212 ret = scf_iter_instance_pgs(iter, cur_inst);
14216 14213 else
14217 14214 ret = scf_iter_service_pgs(iter, cur_svc);
14218 14215 if (ret != SCF_SUCCESS)
14219 14216 scfdie();
14220 14217
14221 14218 while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
14222 14219 int ret2;
14223 14220
14224 14221 /*
14225 14222 * # delprop pg
14226 14223 * # addpg pg type
14227 14224 */
14228 14225 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
14229 14226 scfdie();
14230 14227
14231 14228 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
14232 14229 scfdie();
14233 14230
14234 14231 if (fprintf(strm, "# Property group \"%s\"\n"
14235 14232 "# delprop %s\n"
14236 14233 "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
14237 14234 warn(emsg_write_error, strerror(errno));
14238 14235 result = -1;
14239 14236 goto out;
14240 14237 }
14241 14238
14242 14239 /* # setprop pg/prop = (values) */
14243 14240
14244 14241 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
14245 14242 scfdie();
14246 14243
14247 14244 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
14248 14245 int first = 1;
14249 14246 int ret3;
14250 14247 int multiple;
14251 14248 int is_str;
14252 14249 scf_type_t bty;
14253 14250
14254 14251 if (scf_property_get_name(prop, pname,
14255 14252 max_scf_name_len + 1) < 0)
14256 14253 scfdie();
14257 14254
14258 14255 if (scf_property_type(prop, &ty) != 0)
14259 14256 scfdie();
14260 14257
14261 14258 multiple = prop_has_multiple_values(prop, val);
14262 14259
14263 14260 if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
14264 14261 pname, scf_type_to_string(ty), multiple ? "(" : "")
14265 14262 < 0) {
14266 14263 warn(emsg_write_error, strerror(errno));
14267 14264 result = -1;
14268 14265 goto out;
14269 14266 }
14270 14267
14271 14268 (void) scf_type_base_type(ty, &bty);
14272 14269 is_str = (bty == SCF_TYPE_ASTRING);
14273 14270
14274 14271 if (scf_iter_property_values(viter, prop) !=
14275 14272 SCF_SUCCESS)
14276 14273 scfdie();
14277 14274
14278 14275 while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
14279 14276 char *buf;
14280 14277 ssize_t buflen;
14281 14278
14282 14279 buflen = scf_value_get_as_string(val, NULL, 0);
14283 14280 if (buflen < 0)
14284 14281 scfdie();
14285 14282
14286 14283 buf = safe_malloc(buflen + 1);
14287 14284
14288 14285 if (scf_value_get_as_string(val, buf,
14289 14286 buflen + 1) < 0)
14290 14287 scfdie();
14291 14288
14292 14289 if (first)
14293 14290 first = 0;
14294 14291 else {
14295 14292 if (putc(' ', strm) != ' ') {
14296 14293 warn(emsg_write_error,
14297 14294 strerror(errno));
14298 14295 result = -1;
14299 14296 goto out;
14300 14297 }
14301 14298 }
14302 14299
14303 14300 if ((is_str && multiple) ||
14304 14301 strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
14305 14302 (void) putc('"', strm);
14306 14303 (void) quote_and_print(buf, strm, 1);
14307 14304 (void) putc('"', strm);
14308 14305
14309 14306 if (ferror(strm)) {
14310 14307 warn(emsg_write_error,
14311 14308 strerror(errno));
14312 14309 result = -1;
14313 14310 goto out;
14314 14311 }
14315 14312 } else {
14316 14313 if (fprintf(strm, "%s", buf) < 0) {
14317 14314 warn(emsg_write_error,
14318 14315 strerror(errno));
14319 14316 result = -1;
14320 14317 goto out;
14321 14318 }
14322 14319 }
14323 14320
14324 14321 free(buf);
14325 14322 }
14326 14323 if (ret3 < 0 &&
14327 14324 scf_error() != SCF_ERROR_PERMISSION_DENIED)
14328 14325 scfdie();
14329 14326
14330 14327 /* Write closing paren if mult-value property */
14331 14328 if ((multiple && putc(')', strm) == EOF) ||
14332 14329
14333 14330 /* Write final newline */
14334 14331 fputc('\n', strm) == EOF) {
14335 14332 warn(emsg_write_error, strerror(errno));
14336 14333 result = -1;
14337 14334 goto out;
14338 14335 }
14339 14336 }
14340 14337 if (ret2 < 0)
14341 14338 scfdie();
14342 14339
14343 14340 if (fputc('\n', strm) == EOF) {
14344 14341 warn(emsg_write_error, strerror(errno));
14345 14342 result = -1;
14346 14343 goto out;
14347 14344 }
14348 14345 }
14349 14346 if (ret < 0)
14350 14347 scfdie();
14351 14348
14352 14349 out:
14353 14350 free(pname);
14354 14351 free(tybuf);
14355 14352 free(buf);
14356 14353 scf_iter_destroy(viter);
14357 14354 scf_iter_destroy(piter);
14358 14355 scf_iter_destroy(iter);
14359 14356 scf_value_destroy(val);
14360 14357 scf_property_destroy(prop);
14361 14358 scf_pg_destroy(pg);
14362 14359
14363 14360 if (result == 0) {
14364 14361 if (fflush(strm) != 0) {
14365 14362 warn(emsg_write_error, strerror(errno));
14366 14363 return (-1);
14367 14364 }
14368 14365 }
14369 14366
14370 14367 return (result);
14371 14368 }
14372 14369
14373 14370 int
14374 14371 lscf_editprop()
14375 14372 {
14376 14373 char *buf, *editor;
14377 14374 size_t bufsz;
14378 14375 int tmpfd;
14379 14376 char tempname[] = TEMP_FILE_PATTERN;
14380 14377
14381 14378 lscf_prep_hndl();
14382 14379
14383 14380 if (cur_snap != NULL) {
14384 14381 semerr(emsg_cant_modify_snapshots);
14385 14382 return (-1);
14386 14383 }
14387 14384
14388 14385 if (cur_svc == NULL && cur_inst == NULL) {
14389 14386 semerr(emsg_entity_not_selected);
14390 14387 return (-1);
14391 14388 }
14392 14389
14393 14390 tmpfd = mkstemp(tempname);
14394 14391 if (tmpfd == -1) {
14395 14392 semerr(gettext("Could not create temporary file.\n"));
14396 14393 return (-1);
14397 14394 }
14398 14395
14399 14396 (void) strcpy(tempfilename, tempname);
14400 14397
14401 14398 tempfile = fdopen(tmpfd, "r+");
14402 14399 if (tempfile == NULL) {
14403 14400 warn(gettext("Could not create temporary file.\n"));
14404 14401 if (close(tmpfd) == -1)
14405 14402 warn(gettext("Could not close temporary file: %s.\n"),
14406 14403 strerror(errno));
14407 14404
14408 14405 remove_tempfile();
14409 14406
14410 14407 return (-1);
14411 14408 }
14412 14409
14413 14410 if (write_edit_script(tempfile) == -1) {
14414 14411 remove_tempfile();
14415 14412 return (-1);
14416 14413 }
14417 14414
14418 14415 editor = getenv("EDITOR");
14419 14416 if (editor == NULL)
14420 14417 editor = "vi";
14421 14418
14422 14419 bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
14423 14420 buf = safe_malloc(bufsz);
14424 14421
14425 14422 if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
14426 14423 uu_die(gettext("Error creating editor command"));
14427 14424
14428 14425 if (system(buf) == -1) {
14429 14426 semerr(gettext("Could not launch editor %s: %s\n"), editor,
14430 14427 strerror(errno));
14431 14428 free(buf);
14432 14429 remove_tempfile();
14433 14430 return (-1);
14434 14431 }
14435 14432
14436 14433 free(buf);
14437 14434
14438 14435 (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
14439 14436
14440 14437 remove_tempfile();
14441 14438
14442 14439 return (0);
14443 14440 }
14444 14441
14445 14442 static void
14446 14443 add_string(uu_list_t *strlist, const char *str)
14447 14444 {
14448 14445 string_list_t *elem;
14449 14446 elem = safe_malloc(sizeof (*elem));
14450 14447 uu_list_node_init(elem, &elem->node, string_pool);
14451 14448 elem->str = safe_strdup(str);
14452 14449 if (uu_list_append(strlist, elem) != 0)
14453 14450 uu_die(gettext("libuutil error: %s\n"),
14454 14451 uu_strerror(uu_error()));
14455 14452 }
14456 14453
14457 14454 static int
14458 14455 remove_string(uu_list_t *strlist, const char *str)
14459 14456 {
14460 14457 uu_list_walk_t *elems;
14461 14458 string_list_t *sp;
14462 14459
14463 14460 /*
14464 14461 * Find the element that needs to be removed.
14465 14462 */
14466 14463 elems = uu_list_walk_start(strlist, UU_DEFAULT);
14467 14464 while ((sp = uu_list_walk_next(elems)) != NULL) {
14468 14465 if (strcmp(sp->str, str) == 0)
14469 14466 break;
14470 14467 }
14471 14468 uu_list_walk_end(elems);
14472 14469
14473 14470 /*
14474 14471 * Returning 1 here as the value was not found, this
14475 14472 * might not be an error. Leave it to the caller to
14476 14473 * decide.
14477 14474 */
14478 14475 if (sp == NULL) {
14479 14476 return (1);
14480 14477 }
14481 14478
14482 14479 uu_list_remove(strlist, sp);
14483 14480
14484 14481 free(sp->str);
14485 14482 free(sp);
14486 14483
14487 14484 return (0);
14488 14485 }
14489 14486
14490 14487 /*
14491 14488 * Get all property values that don't match the given glob pattern,
14492 14489 * if a pattern is specified.
14493 14490 */
14494 14491 static void
14495 14492 get_prop_values(scf_property_t *prop, uu_list_t *values,
14496 14493 const char *pattern)
14497 14494 {
14498 14495 scf_iter_t *iter;
14499 14496 scf_value_t *val;
14500 14497 int ret;
14501 14498
14502 14499 if ((iter = scf_iter_create(g_hndl)) == NULL ||
14503 14500 (val = scf_value_create(g_hndl)) == NULL)
14504 14501 scfdie();
14505 14502
14506 14503 if (scf_iter_property_values(iter, prop) != 0)
14507 14504 scfdie();
14508 14505
14509 14506 while ((ret = scf_iter_next_value(iter, val)) == 1) {
14510 14507 char *buf;
14511 14508 ssize_t vlen, szret;
14512 14509
14513 14510 vlen = scf_value_get_as_string(val, NULL, 0);
14514 14511 if (vlen < 0)
14515 14512 scfdie();
14516 14513
14517 14514 buf = safe_malloc(vlen + 1);
14518 14515
14519 14516 szret = scf_value_get_as_string(val, buf, vlen + 1);
14520 14517 if (szret < 0)
14521 14518 scfdie();
14522 14519 assert(szret <= vlen);
14523 14520
14524 14521 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14525 14522 add_string(values, buf);
14526 14523
14527 14524 free(buf);
14528 14525 }
14529 14526
14530 14527 if (ret == -1)
14531 14528 scfdie();
14532 14529
14533 14530 scf_value_destroy(val);
14534 14531 scf_iter_destroy(iter);
14535 14532 }
14536 14533
14537 14534 static int
14538 14535 lscf_setpropvalue(const char *pgname, const char *type,
14539 14536 const char *arg, int isadd, int isnotfoundok)
14540 14537 {
14541 14538 scf_type_t ty;
14542 14539 scf_propertygroup_t *pg;
14543 14540 scf_property_t *prop;
14544 14541 int ret, result = 0;
14545 14542 scf_transaction_t *tx;
14546 14543 scf_transaction_entry_t *e;
14547 14544 scf_value_t *v;
14548 14545 string_list_t *sp;
14549 14546 char *propname;
14550 14547 uu_list_t *values;
14551 14548 uu_list_walk_t *walk;
14552 14549 void *cookie = NULL;
14553 14550 char *pattern = NULL;
14554 14551
14555 14552 lscf_prep_hndl();
14556 14553
14557 14554 if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14558 14555 uu_die(gettext("Could not create property list: %s\n"),
14559 14556 uu_strerror(uu_error()));
14560 14557
14561 14558 if (!isadd)
14562 14559 pattern = safe_strdup(arg);
14563 14560
14564 14561 if ((e = scf_entry_create(g_hndl)) == NULL ||
14565 14562 (pg = scf_pg_create(g_hndl)) == NULL ||
14566 14563 (prop = scf_property_create(g_hndl)) == NULL ||
14567 14564 (tx = scf_transaction_create(g_hndl)) == NULL)
14568 14565 scfdie();
14569 14566
14570 14567 if (cur_snap != NULL) {
14571 14568 semerr(emsg_cant_modify_snapshots);
14572 14569 goto fail;
14573 14570 }
14574 14571
14575 14572 if (cur_inst == NULL && cur_svc == NULL) {
14576 14573 semerr(emsg_entity_not_selected);
14577 14574 goto fail;
14578 14575 }
14579 14576
14580 14577 propname = strchr(pgname, '/');
14581 14578 if (propname == NULL) {
14582 14579 semerr(gettext("Property names must contain a `/'.\n"));
14583 14580 goto fail;
14584 14581 }
14585 14582
14586 14583 *propname = '\0';
14587 14584 ++propname;
14588 14585
14589 14586 if (type != NULL) {
14590 14587 ty = string_to_type(type);
14591 14588 if (ty == SCF_TYPE_INVALID) {
14592 14589 semerr(gettext("Unknown type \"%s\".\n"), type);
14593 14590 goto fail;
14594 14591 }
14595 14592 }
14596 14593
14597 14594 if (cur_inst != NULL)
14598 14595 ret = scf_instance_get_pg(cur_inst, pgname, pg);
14599 14596 else
14600 14597 ret = scf_service_get_pg(cur_svc, pgname, pg);
14601 14598 if (ret != 0) {
14602 14599 switch (scf_error()) {
14603 14600 case SCF_ERROR_NOT_FOUND:
14604 14601 if (isnotfoundok) {
14605 14602 result = 0;
14606 14603 } else {
14607 14604 semerr(emsg_no_such_pg, pgname);
14608 14605 result = -1;
14609 14606 }
14610 14607 goto out;
14611 14608
14612 14609 case SCF_ERROR_INVALID_ARGUMENT:
14613 14610 semerr(emsg_invalid_pg_name, pgname);
14614 14611 goto fail;
14615 14612
14616 14613 default:
14617 14614 scfdie();
14618 14615 }
14619 14616 }
14620 14617
14621 14618 do {
14622 14619 if (scf_pg_update(pg) == -1)
14623 14620 scfdie();
14624 14621 if (scf_transaction_start(tx, pg) != 0) {
14625 14622 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14626 14623 scfdie();
14627 14624
14628 14625 semerr(emsg_permission_denied);
14629 14626 goto fail;
14630 14627 }
14631 14628
14632 14629 ret = scf_pg_get_property(pg, propname, prop);
14633 14630 if (ret == 0) {
14634 14631 scf_type_t ptype;
14635 14632 char *pat = pattern;
14636 14633
14637 14634 if (scf_property_type(prop, &ptype) != 0)
14638 14635 scfdie();
14639 14636
14640 14637 if (isadd) {
14641 14638 if (type != NULL && ptype != ty) {
14642 14639 semerr(gettext("Property \"%s\" is not "
14643 14640 "of type \"%s\".\n"), propname,
14644 14641 type);
14645 14642 goto fail;
14646 14643 }
14647 14644
14648 14645 pat = NULL;
14649 14646 } else {
14650 14647 size_t len = strlen(pat);
14651 14648 if (len > 0 && pat[len - 1] == '\"')
14652 14649 pat[len - 1] = '\0';
14653 14650 if (len > 0 && pat[0] == '\"')
14654 14651 pat++;
14655 14652 }
14656 14653
14657 14654 ty = ptype;
14658 14655
14659 14656 get_prop_values(prop, values, pat);
14660 14657
14661 14658 if (isadd)
14662 14659 add_string(values, arg);
14663 14660
14664 14661 if (scf_transaction_property_change(tx, e,
14665 14662 propname, ty) == -1)
14666 14663 scfdie();
14667 14664 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14668 14665 if (isadd) {
14669 14666 if (type == NULL) {
14670 14667 semerr(gettext("Type required "
14671 14668 "for new properties.\n"));
14672 14669 goto fail;
14673 14670 }
14674 14671
14675 14672 add_string(values, arg);
14676 14673
14677 14674 if (scf_transaction_property_new(tx, e,
14678 14675 propname, ty) == -1)
14679 14676 scfdie();
14680 14677 } else if (isnotfoundok) {
14681 14678 result = 0;
14682 14679 goto out;
14683 14680 } else {
14684 14681 semerr(gettext("No such property %s/%s.\n"),
14685 14682 pgname, propname);
14686 14683 result = -1;
14687 14684 goto out;
14688 14685 }
14689 14686 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14690 14687 semerr(emsg_invalid_prop_name, propname);
14691 14688 goto fail;
14692 14689 } else {
14693 14690 scfdie();
14694 14691 }
14695 14692
14696 14693 walk = uu_list_walk_start(values, UU_DEFAULT);
14697 14694 if (walk == NULL)
14698 14695 uu_die(gettext("Could not walk property list.\n"));
14699 14696
14700 14697 for (sp = uu_list_walk_next(walk); sp != NULL;
14701 14698 sp = uu_list_walk_next(walk)) {
14702 14699 v = string_to_value(sp->str, ty, 0);
14703 14700
14704 14701 if (v == NULL) {
14705 14702 scf_entry_destroy_children(e);
14706 14703 goto fail;
14707 14704 }
14708 14705 ret = scf_entry_add_value(e, v);
14709 14706 assert(ret == 0);
14710 14707 }
14711 14708 uu_list_walk_end(walk);
14712 14709
14713 14710 result = scf_transaction_commit(tx);
14714 14711
14715 14712 scf_transaction_reset(tx);
14716 14713 scf_entry_destroy_children(e);
14717 14714 } while (result == 0);
14718 14715
14719 14716 if (result < 0) {
14720 14717 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14721 14718 scfdie();
14722 14719
14723 14720 semerr(emsg_permission_denied);
14724 14721 goto fail;
14725 14722 }
14726 14723
14727 14724 result = 0;
14728 14725
14729 14726 private_refresh();
14730 14727
14731 14728 out:
14732 14729 scf_transaction_destroy(tx);
14733 14730 scf_entry_destroy(e);
14734 14731 scf_pg_destroy(pg);
14735 14732 scf_property_destroy(prop);
14736 14733 free(pattern);
14737 14734
14738 14735 while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14739 14736 free(sp->str);
14740 14737 free(sp);
14741 14738 }
14742 14739
14743 14740 uu_list_destroy(values);
14744 14741
14745 14742 return (result);
14746 14743
14747 14744 fail:
14748 14745 result = -1;
14749 14746 goto out;
14750 14747 }
14751 14748
14752 14749 int
14753 14750 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14754 14751 {
14755 14752 return (lscf_setpropvalue(pgname, type, value, 1, 0));
14756 14753 }
14757 14754
14758 14755 int
14759 14756 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14760 14757 {
14761 14758 return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14762 14759 }
14763 14760
14764 14761 /*
14765 14762 * Look for a standard start method, first in the instance (if any),
14766 14763 * then the service.
14767 14764 */
14768 14765 static const char *
14769 14766 start_method_name(int *in_instance)
14770 14767 {
14771 14768 scf_propertygroup_t *pg;
14772 14769 char **p;
14773 14770 int ret;
14774 14771 scf_instance_t *inst = cur_inst;
14775 14772
14776 14773 if ((pg = scf_pg_create(g_hndl)) == NULL)
14777 14774 scfdie();
14778 14775
14779 14776 again:
14780 14777 for (p = start_method_names; *p != NULL; p++) {
14781 14778 if (inst != NULL)
14782 14779 ret = scf_instance_get_pg(inst, *p, pg);
14783 14780 else
14784 14781 ret = scf_service_get_pg(cur_svc, *p, pg);
14785 14782
14786 14783 if (ret == 0) {
14787 14784 size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14788 14785 char *buf = safe_malloc(bufsz);
14789 14786
14790 14787 if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14791 14788 free(buf);
14792 14789 continue;
14793 14790 }
14794 14791 if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14795 14792 free(buf);
14796 14793 continue;
14797 14794 }
14798 14795
14799 14796 free(buf);
14800 14797 *in_instance = (inst != NULL);
14801 14798 scf_pg_destroy(pg);
14802 14799 return (*p);
14803 14800 }
14804 14801
14805 14802 if (scf_error() == SCF_ERROR_NOT_FOUND)
14806 14803 continue;
14807 14804
14808 14805 scfdie();
14809 14806 }
14810 14807
14811 14808 if (inst != NULL) {
14812 14809 inst = NULL;
14813 14810 goto again;
14814 14811 }
14815 14812
14816 14813 scf_pg_destroy(pg);
14817 14814 return (NULL);
14818 14815 }
14819 14816
14820 14817 static int
14821 14818 addpg(const char *name, const char *type)
14822 14819 {
14823 14820 scf_propertygroup_t *pg;
14824 14821 int ret;
14825 14822
14826 14823 pg = scf_pg_create(g_hndl);
14827 14824 if (pg == NULL)
14828 14825 scfdie();
14829 14826
14830 14827 if (cur_inst != NULL)
14831 14828 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14832 14829 else
14833 14830 ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14834 14831
14835 14832 if (ret != 0) {
14836 14833 switch (scf_error()) {
14837 14834 case SCF_ERROR_EXISTS:
14838 14835 ret = 0;
14839 14836 break;
14840 14837
14841 14838 case SCF_ERROR_PERMISSION_DENIED:
14842 14839 semerr(emsg_permission_denied);
14843 14840 break;
14844 14841
14845 14842 default:
14846 14843 scfdie();
14847 14844 }
14848 14845 }
14849 14846
14850 14847 scf_pg_destroy(pg);
14851 14848 return (ret);
14852 14849 }
14853 14850
14854 14851 int
14855 14852 lscf_setenv(uu_list_t *args, int isunset)
14856 14853 {
14857 14854 int ret = 0;
14858 14855 size_t i;
14859 14856 int argc;
14860 14857 char **argv = NULL;
14861 14858 string_list_t *slp;
14862 14859 char *pattern;
14863 14860 char *prop;
14864 14861 int do_service = 0;
14865 14862 int do_instance = 0;
14866 14863 const char *method = NULL;
14867 14864 const char *name = NULL;
14868 14865 const char *value = NULL;
14869 14866 scf_instance_t *saved_cur_inst = cur_inst;
14870 14867
14871 14868 lscf_prep_hndl();
14872 14869
14873 14870 argc = uu_list_numnodes(args);
14874 14871 if (argc < 1)
14875 14872 goto usage;
14876 14873
14877 14874 argv = calloc(argc + 1, sizeof (char *));
14878 14875 if (argv == NULL)
14879 14876 uu_die(gettext("Out of memory.\n"));
14880 14877
14881 14878 for (slp = uu_list_first(args), i = 0;
14882 14879 slp != NULL;
14883 14880 slp = uu_list_next(args, slp), ++i)
14884 14881 argv[i] = slp->str;
14885 14882
14886 14883 argv[i] = NULL;
14887 14884
14888 14885 opterr = 0;
14889 14886 optind = 0;
14890 14887 for (;;) {
14891 14888 ret = getopt(argc, argv, "sim:");
14892 14889 if (ret == -1)
14893 14890 break;
14894 14891
14895 14892 switch (ret) {
14896 14893 case 's':
14897 14894 do_service = 1;
14898 14895 cur_inst = NULL;
14899 14896 break;
14900 14897
14901 14898 case 'i':
14902 14899 do_instance = 1;
14903 14900 break;
14904 14901
14905 14902 case 'm':
14906 14903 method = optarg;
14907 14904 break;
14908 14905
14909 14906 case '?':
14910 14907 goto usage;
14911 14908
14912 14909 default:
14913 14910 bad_error("getopt", ret);
14914 14911 }
14915 14912 }
14916 14913
14917 14914 argc -= optind;
14918 14915 if ((do_service && do_instance) ||
14919 14916 (isunset && argc != 1) ||
14920 14917 (!isunset && argc != 2))
14921 14918 goto usage;
14922 14919
14923 14920 name = argv[optind];
14924 14921 if (!isunset)
14925 14922 value = argv[optind + 1];
14926 14923
14927 14924 if (cur_snap != NULL) {
14928 14925 semerr(emsg_cant_modify_snapshots);
14929 14926 ret = -1;
14930 14927 goto out;
14931 14928 }
14932 14929
14933 14930 if (cur_inst == NULL && cur_svc == NULL) {
14934 14931 semerr(emsg_entity_not_selected);
14935 14932 ret = -1;
14936 14933 goto out;
14937 14934 }
14938 14935
14939 14936 if (do_instance && cur_inst == NULL) {
14940 14937 semerr(gettext("No instance is selected.\n"));
14941 14938 ret = -1;
14942 14939 goto out;
14943 14940 }
14944 14941
14945 14942 if (do_service && cur_svc == NULL) {
14946 14943 semerr(gettext("No service is selected.\n"));
14947 14944 ret = -1;
14948 14945 goto out;
14949 14946 }
14950 14947
14951 14948 if (method == NULL) {
14952 14949 if (do_instance || do_service) {
14953 14950 method = "method_context";
14954 14951 if (!isunset) {
14955 14952 ret = addpg("method_context",
14956 14953 SCF_GROUP_FRAMEWORK);
14957 14954 if (ret != 0)
14958 14955 goto out;
14959 14956 }
14960 14957 } else {
14961 14958 int in_instance;
14962 14959 method = start_method_name(&in_instance);
14963 14960 if (method == NULL) {
14964 14961 semerr(gettext(
14965 14962 "Couldn't find start method; please "
14966 14963 "specify a method with '-m'.\n"));
14967 14964 ret = -1;
14968 14965 goto out;
14969 14966 }
14970 14967 if (!in_instance)
14971 14968 cur_inst = NULL;
14972 14969 }
14973 14970 } else {
14974 14971 scf_propertygroup_t *pg;
14975 14972 size_t bufsz;
14976 14973 char *buf;
14977 14974 int ret;
14978 14975
14979 14976 if ((pg = scf_pg_create(g_hndl)) == NULL)
14980 14977 scfdie();
14981 14978
14982 14979 if (cur_inst != NULL)
14983 14980 ret = scf_instance_get_pg(cur_inst, method, pg);
14984 14981 else
14985 14982 ret = scf_service_get_pg(cur_svc, method, pg);
14986 14983
14987 14984 if (ret != 0) {
14988 14985 scf_pg_destroy(pg);
14989 14986 switch (scf_error()) {
14990 14987 case SCF_ERROR_NOT_FOUND:
14991 14988 semerr(gettext("Couldn't find the method "
14992 14989 "\"%s\".\n"), method);
14993 14990 goto out;
14994 14991
14995 14992 case SCF_ERROR_INVALID_ARGUMENT:
14996 14993 semerr(gettext("Invalid method name \"%s\".\n"),
14997 14994 method);
14998 14995 goto out;
14999 14996
15000 14997 default:
15001 14998 scfdie();
15002 14999 }
15003 15000 }
15004 15001
15005 15002 bufsz = strlen(SCF_GROUP_METHOD) + 1;
15006 15003 buf = safe_malloc(bufsz);
15007 15004
15008 15005 if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
15009 15006 strcmp(buf, SCF_GROUP_METHOD) != 0) {
15010 15007 semerr(gettext("Property group \"%s\" is not of type "
15011 15008 "\"method\".\n"), method);
15012 15009 ret = -1;
15013 15010 free(buf);
15014 15011 scf_pg_destroy(pg);
15015 15012 goto out;
15016 15013 }
15017 15014
15018 15015 free(buf);
15019 15016 scf_pg_destroy(pg);
15020 15017 }
15021 15018
15022 15019 prop = uu_msprintf("%s/environment", method);
15023 15020 pattern = uu_msprintf("%s=*", name);
15024 15021
15025 15022 if (prop == NULL || pattern == NULL)
15026 15023 uu_die(gettext("Out of memory.\n"));
15027 15024
15028 15025 ret = lscf_delpropvalue(prop, pattern, !isunset);
15029 15026
15030 15027 if (ret == 0 && !isunset) {
15031 15028 uu_free(pattern);
15032 15029 uu_free(prop);
15033 15030 prop = uu_msprintf("%s/environment", method);
15034 15031 pattern = uu_msprintf("%s=%s", name, value);
15035 15032 if (prop == NULL || pattern == NULL)
15036 15033 uu_die(gettext("Out of memory.\n"));
15037 15034 ret = lscf_addpropvalue(prop, "astring:", pattern);
15038 15035 }
15039 15036 uu_free(pattern);
15040 15037 uu_free(prop);
15041 15038
15042 15039 out:
15043 15040 cur_inst = saved_cur_inst;
15044 15041
15045 15042 free(argv);
15046 15043 return (ret);
15047 15044 usage:
15048 15045 ret = -2;
15049 15046 goto out;
15050 15047 }
15051 15048
15052 15049 /*
15053 15050 * Snapshot commands
15054 15051 */
15055 15052
15056 15053 void
15057 15054 lscf_listsnap()
15058 15055 {
15059 15056 scf_snapshot_t *snap;
15060 15057 scf_iter_t *iter;
15061 15058 char *nb;
15062 15059 int r;
15063 15060
15064 15061 lscf_prep_hndl();
15065 15062
15066 15063 if (cur_inst == NULL) {
15067 15064 semerr(gettext("Instance not selected.\n"));
15068 15065 return;
15069 15066 }
15070 15067
15071 15068 if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15072 15069 (iter = scf_iter_create(g_hndl)) == NULL)
15073 15070 scfdie();
15074 15071
15075 15072 if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
15076 15073 scfdie();
15077 15074
15078 15075 nb = safe_malloc(max_scf_name_len + 1);
15079 15076
15080 15077 while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
15081 15078 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
15082 15079 scfdie();
15083 15080
15084 15081 (void) puts(nb);
15085 15082 }
15086 15083 if (r < 0)
15087 15084 scfdie();
15088 15085
15089 15086 free(nb);
15090 15087 scf_iter_destroy(iter);
15091 15088 scf_snapshot_destroy(snap);
15092 15089 }
15093 15090
15094 15091 void
15095 15092 lscf_selectsnap(const char *name)
15096 15093 {
15097 15094 scf_snapshot_t *snap;
15098 15095 scf_snaplevel_t *level;
15099 15096
15100 15097 lscf_prep_hndl();
15101 15098
15102 15099 if (cur_inst == NULL) {
15103 15100 semerr(gettext("Instance not selected.\n"));
15104 15101 return;
15105 15102 }
15106 15103
15107 15104 if (cur_snap != NULL) {
15108 15105 if (name != NULL) {
15109 15106 char *cur_snap_name;
15110 15107 boolean_t nochange;
15111 15108
15112 15109 cur_snap_name = safe_malloc(max_scf_name_len + 1);
15113 15110
15114 15111 if (scf_snapshot_get_name(cur_snap, cur_snap_name,
15115 15112 max_scf_name_len + 1) < 0)
15116 15113 scfdie();
15117 15114
15118 15115 nochange = strcmp(name, cur_snap_name) == 0;
15119 15116
15120 15117 free(cur_snap_name);
15121 15118
15122 15119 if (nochange)
15123 15120 return;
15124 15121 }
15125 15122
15126 15123 unselect_cursnap();
15127 15124 }
15128 15125
15129 15126 if (name == NULL)
15130 15127 return;
15131 15128
15132 15129 if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15133 15130 (level = scf_snaplevel_create(g_hndl)) == NULL)
15134 15131 scfdie();
15135 15132
15136 15133 if (scf_instance_get_snapshot(cur_inst, name, snap) !=
15137 15134 SCF_SUCCESS) {
15138 15135 switch (scf_error()) {
15139 15136 case SCF_ERROR_INVALID_ARGUMENT:
15140 15137 semerr(gettext("Invalid name \"%s\".\n"), name);
15141 15138 break;
15142 15139
15143 15140 case SCF_ERROR_NOT_FOUND:
15144 15141 semerr(gettext("No such snapshot \"%s\".\n"), name);
15145 15142 break;
15146 15143
15147 15144 default:
15148 15145 scfdie();
15149 15146 }
15150 15147
15151 15148 scf_snaplevel_destroy(level);
15152 15149 scf_snapshot_destroy(snap);
15153 15150 return;
15154 15151 }
15155 15152
15156 15153 /* Load the snaplevels into our list. */
15157 15154 cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
15158 15155 if (cur_levels == NULL)
15159 15156 uu_die(gettext("Could not create list: %s\n"),
15160 15157 uu_strerror(uu_error()));
15161 15158
15162 15159 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15163 15160 if (scf_error() != SCF_ERROR_NOT_FOUND)
15164 15161 scfdie();
15165 15162
15166 15163 semerr(gettext("Snapshot has no snaplevels.\n"));
15167 15164
15168 15165 scf_snaplevel_destroy(level);
15169 15166 scf_snapshot_destroy(snap);
15170 15167 return;
15171 15168 }
15172 15169
15173 15170 cur_snap = snap;
15174 15171
15175 15172 for (;;) {
15176 15173 cur_elt = safe_malloc(sizeof (*cur_elt));
15177 15174 uu_list_node_init(cur_elt, &cur_elt->list_node,
15178 15175 snaplevel_pool);
15179 15176 cur_elt->sl = level;
15180 15177 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
15181 15178 uu_die(gettext("libuutil error: %s\n"),
15182 15179 uu_strerror(uu_error()));
15183 15180
15184 15181 level = scf_snaplevel_create(g_hndl);
15185 15182 if (level == NULL)
15186 15183 scfdie();
15187 15184
15188 15185 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
15189 15186 level) != SCF_SUCCESS) {
15190 15187 if (scf_error() != SCF_ERROR_NOT_FOUND)
15191 15188 scfdie();
15192 15189
15193 15190 scf_snaplevel_destroy(level);
15194 15191 break;
15195 15192 }
15196 15193 }
15197 15194
15198 15195 cur_elt = uu_list_last(cur_levels);
15199 15196 cur_level = cur_elt->sl;
15200 15197 }
15201 15198
15202 15199 /*
15203 15200 * Copies the properties & values in src to dst. Assumes src won't change.
15204 15201 * Returns -1 if permission is denied, -2 if another transaction interrupts,
15205 15202 * and 0 on success.
15206 15203 *
15207 15204 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
15208 15205 * property, if it is copied and has type boolean. (See comment in
15209 15206 * lscf_revert()).
15210 15207 */
15211 15208 static int
15212 15209 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
15213 15210 uint8_t enabled)
15214 15211 {
15215 15212 scf_transaction_t *tx;
15216 15213 scf_iter_t *iter, *viter;
15217 15214 scf_property_t *prop;
15218 15215 scf_value_t *v;
15219 15216 char *nbuf;
15220 15217 int r;
15221 15218
15222 15219 tx = scf_transaction_create(g_hndl);
15223 15220 if (tx == NULL)
15224 15221 scfdie();
15225 15222
15226 15223 if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
15227 15224 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15228 15225 scfdie();
15229 15226
15230 15227 scf_transaction_destroy(tx);
15231 15228
15232 15229 return (-1);
15233 15230 }
15234 15231
15235 15232 if ((iter = scf_iter_create(g_hndl)) == NULL ||
15236 15233 (prop = scf_property_create(g_hndl)) == NULL ||
15237 15234 (viter = scf_iter_create(g_hndl)) == NULL)
15238 15235 scfdie();
15239 15236
15240 15237 nbuf = safe_malloc(max_scf_name_len + 1);
15241 15238
15242 15239 if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
15243 15240 scfdie();
15244 15241
15245 15242 for (;;) {
15246 15243 scf_transaction_entry_t *e;
15247 15244 scf_type_t ty;
15248 15245
15249 15246 r = scf_iter_next_property(iter, prop);
15250 15247 if (r == -1)
15251 15248 scfdie();
15252 15249 if (r == 0)
15253 15250 break;
15254 15251
15255 15252 e = scf_entry_create(g_hndl);
15256 15253 if (e == NULL)
15257 15254 scfdie();
15258 15255
15259 15256 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
15260 15257 scfdie();
15261 15258
15262 15259 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
15263 15260 scfdie();
15264 15261
15265 15262 if (scf_transaction_property_new(tx, e, nbuf,
15266 15263 ty) != SCF_SUCCESS)
15267 15264 scfdie();
15268 15265
15269 15266 if ((enabled == 0 || enabled == 1) &&
15270 15267 strcmp(nbuf, scf_property_enabled) == 0 &&
15271 15268 ty == SCF_TYPE_BOOLEAN) {
15272 15269 v = scf_value_create(g_hndl);
15273 15270 if (v == NULL)
15274 15271 scfdie();
15275 15272
15276 15273 scf_value_set_boolean(v, enabled);
15277 15274
15278 15275 if (scf_entry_add_value(e, v) != 0)
15279 15276 scfdie();
15280 15277 } else {
15281 15278 if (scf_iter_property_values(viter, prop) != 0)
15282 15279 scfdie();
15283 15280
15284 15281 for (;;) {
15285 15282 v = scf_value_create(g_hndl);
15286 15283 if (v == NULL)
15287 15284 scfdie();
15288 15285
15289 15286 r = scf_iter_next_value(viter, v);
15290 15287 if (r == -1)
15291 15288 scfdie();
15292 15289 if (r == 0) {
15293 15290 scf_value_destroy(v);
15294 15291 break;
15295 15292 }
15296 15293
15297 15294 if (scf_entry_add_value(e, v) != SCF_SUCCESS)
15298 15295 scfdie();
15299 15296 }
15300 15297 }
15301 15298 }
15302 15299
15303 15300 free(nbuf);
15304 15301 scf_iter_destroy(viter);
15305 15302 scf_property_destroy(prop);
15306 15303 scf_iter_destroy(iter);
15307 15304
15308 15305 r = scf_transaction_commit(tx);
15309 15306 if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
15310 15307 scfdie();
15311 15308
15312 15309 scf_transaction_destroy_children(tx);
15313 15310 scf_transaction_destroy(tx);
15314 15311
15315 15312 switch (r) {
15316 15313 case 1: return (0);
15317 15314 case 0: return (-2);
15318 15315 case -1: return (-1);
15319 15316
15320 15317 default:
15321 15318 abort();
15322 15319 }
15323 15320
15324 15321 /* NOTREACHED */
15325 15322 }
15326 15323
15327 15324 void
15328 15325 lscf_revert(const char *snapname)
15329 15326 {
15330 15327 scf_snapshot_t *snap, *prev;
15331 15328 scf_snaplevel_t *level, *nlevel;
15332 15329 scf_iter_t *iter;
15333 15330 scf_propertygroup_t *pg, *npg;
15334 15331 scf_property_t *prop;
15335 15332 scf_value_t *val;
15336 15333 char *nbuf, *tbuf;
15337 15334 uint8_t enabled;
15338 15335
15339 15336 lscf_prep_hndl();
15340 15337
15341 15338 if (cur_inst == NULL) {
15342 15339 semerr(gettext("Instance not selected.\n"));
15343 15340 return;
15344 15341 }
15345 15342
15346 15343 if (snapname != NULL) {
15347 15344 snap = scf_snapshot_create(g_hndl);
15348 15345 if (snap == NULL)
15349 15346 scfdie();
15350 15347
15351 15348 if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
15352 15349 SCF_SUCCESS) {
15353 15350 switch (scf_error()) {
15354 15351 case SCF_ERROR_INVALID_ARGUMENT:
15355 15352 semerr(gettext("Invalid snapshot name "
15356 15353 "\"%s\".\n"), snapname);
15357 15354 break;
15358 15355
15359 15356 case SCF_ERROR_NOT_FOUND:
15360 15357 semerr(gettext("No such snapshot.\n"));
15361 15358 break;
15362 15359
15363 15360 default:
15364 15361 scfdie();
15365 15362 }
15366 15363
15367 15364 scf_snapshot_destroy(snap);
15368 15365 return;
15369 15366 }
15370 15367 } else {
15371 15368 if (cur_snap != NULL) {
15372 15369 snap = cur_snap;
15373 15370 } else {
15374 15371 semerr(gettext("No snapshot selected.\n"));
15375 15372 return;
15376 15373 }
15377 15374 }
15378 15375
15379 15376 if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
15380 15377 (level = scf_snaplevel_create(g_hndl)) == NULL ||
15381 15378 (iter = scf_iter_create(g_hndl)) == NULL ||
15382 15379 (pg = scf_pg_create(g_hndl)) == NULL ||
15383 15380 (npg = scf_pg_create(g_hndl)) == NULL ||
15384 15381 (prop = scf_property_create(g_hndl)) == NULL ||
15385 15382 (val = scf_value_create(g_hndl)) == NULL)
15386 15383 scfdie();
15387 15384
15388 15385 nbuf = safe_malloc(max_scf_name_len + 1);
15389 15386 tbuf = safe_malloc(max_scf_pg_type_len + 1);
15390 15387
15391 15388 /* Take the "previous" snapshot before we blow away the properties. */
15392 15389 if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
15393 15390 if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
15394 15391 scfdie();
15395 15392 } else {
15396 15393 if (scf_error() != SCF_ERROR_NOT_FOUND)
15397 15394 scfdie();
15398 15395
15399 15396 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
15400 15397 scfdie();
15401 15398 }
15402 15399
15403 15400 /* Save general/enabled, since we're probably going to replace it. */
15404 15401 enabled = 2;
15405 15402 if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
15406 15403 scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
15407 15404 scf_property_get_value(prop, val) == 0)
15408 15405 (void) scf_value_get_boolean(val, &enabled);
15409 15406
15410 15407 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15411 15408 if (scf_error() != SCF_ERROR_NOT_FOUND)
15412 15409 scfdie();
15413 15410
15414 15411 goto out;
15415 15412 }
15416 15413
15417 15414 for (;;) {
15418 15415 boolean_t isinst;
15419 15416 uint32_t flags;
15420 15417 int r;
15421 15418
15422 15419 /* Clear the properties from the corresponding entity. */
15423 15420 isinst = snaplevel_is_instance(level);
15424 15421
15425 15422 if (!isinst)
15426 15423 r = scf_iter_service_pgs(iter, cur_svc);
15427 15424 else
15428 15425 r = scf_iter_instance_pgs(iter, cur_inst);
15429 15426 if (r != SCF_SUCCESS)
15430 15427 scfdie();
15431 15428
15432 15429 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15433 15430 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15434 15431 scfdie();
15435 15432
15436 15433 /* Skip nonpersistent pgs. */
15437 15434 if (flags & SCF_PG_FLAG_NONPERSISTENT)
15438 15435 continue;
15439 15436
15440 15437 if (scf_pg_delete(pg) != SCF_SUCCESS) {
15441 15438 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15442 15439 scfdie();
15443 15440
15444 15441 semerr(emsg_permission_denied);
15445 15442 goto out;
15446 15443 }
15447 15444 }
15448 15445 if (r == -1)
15449 15446 scfdie();
15450 15447
15451 15448 /* Copy the properties to the corresponding entity. */
15452 15449 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
15453 15450 scfdie();
15454 15451
15455 15452 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15456 15453 if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
15457 15454 scfdie();
15458 15455
15459 15456 if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
15460 15457 0)
15461 15458 scfdie();
15462 15459
15463 15460 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15464 15461 scfdie();
15465 15462
15466 15463 if (!isinst)
15467 15464 r = scf_service_add_pg(cur_svc, nbuf, tbuf,
15468 15465 flags, npg);
15469 15466 else
15470 15467 r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
15471 15468 flags, npg);
15472 15469 if (r != SCF_SUCCESS) {
15473 15470 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15474 15471 scfdie();
15475 15472
15476 15473 semerr(emsg_permission_denied);
15477 15474 goto out;
15478 15475 }
15479 15476
15480 15477 if ((enabled == 0 || enabled == 1) &&
15481 15478 strcmp(nbuf, scf_pg_general) == 0)
15482 15479 r = pg_copy(pg, npg, enabled);
15483 15480 else
15484 15481 r = pg_copy(pg, npg, 2);
15485 15482
15486 15483 switch (r) {
15487 15484 case 0:
15488 15485 break;
15489 15486
15490 15487 case -1:
15491 15488 semerr(emsg_permission_denied);
15492 15489 goto out;
15493 15490
15494 15491 case -2:
15495 15492 semerr(gettext(
15496 15493 "Interrupted by another change.\n"));
15497 15494 goto out;
15498 15495
15499 15496 default:
15500 15497 abort();
15501 15498 }
15502 15499 }
15503 15500 if (r == -1)
15504 15501 scfdie();
15505 15502
15506 15503 /* Get next level. */
15507 15504 nlevel = scf_snaplevel_create(g_hndl);
15508 15505 if (nlevel == NULL)
15509 15506 scfdie();
15510 15507
15511 15508 if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
15512 15509 SCF_SUCCESS) {
15513 15510 if (scf_error() != SCF_ERROR_NOT_FOUND)
15514 15511 scfdie();
15515 15512
15516 15513 scf_snaplevel_destroy(nlevel);
15517 15514 break;
15518 15515 }
15519 15516
15520 15517 scf_snaplevel_destroy(level);
15521 15518 level = nlevel;
15522 15519 }
15523 15520
15524 15521 if (snapname == NULL) {
15525 15522 lscf_selectsnap(NULL);
15526 15523 snap = NULL; /* cur_snap has been destroyed */
15527 15524 }
15528 15525
15529 15526 out:
15530 15527 free(tbuf);
15531 15528 free(nbuf);
15532 15529 scf_value_destroy(val);
15533 15530 scf_property_destroy(prop);
15534 15531 scf_pg_destroy(npg);
15535 15532 scf_pg_destroy(pg);
15536 15533 scf_iter_destroy(iter);
15537 15534 scf_snaplevel_destroy(level);
15538 15535 scf_snapshot_destroy(prev);
15539 15536 if (snap != cur_snap)
15540 15537 scf_snapshot_destroy(snap);
15541 15538 }
15542 15539
15543 15540 void
15544 15541 lscf_refresh(void)
15545 15542 {
15546 15543 ssize_t fmrilen;
15547 15544 size_t bufsz;
15548 15545 char *fmribuf;
15549 15546 int r;
15550 15547
15551 15548 lscf_prep_hndl();
15552 15549
15553 15550 if (cur_inst == NULL) {
15554 15551 semerr(gettext("Instance not selected.\n"));
15555 15552 return;
15556 15553 }
15557 15554
15558 15555 bufsz = max_scf_fmri_len + 1;
15559 15556 fmribuf = safe_malloc(bufsz);
15560 15557 fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15561 15558 if (fmrilen < 0) {
15562 15559 free(fmribuf);
15563 15560 if (scf_error() != SCF_ERROR_DELETED)
15564 15561 scfdie();
15565 15562 scf_instance_destroy(cur_inst);
15566 15563 cur_inst = NULL;
15567 15564 warn(emsg_deleted);
15568 15565 return;
15569 15566 }
15570 15567 assert(fmrilen < bufsz);
15571 15568
15572 15569 r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15573 15570 switch (r) {
15574 15571 case 0:
15575 15572 break;
15576 15573
15577 15574 case ECONNABORTED:
15578 15575 warn(gettext("Could not refresh %s "
15579 15576 "(repository connection broken).\n"), fmribuf);
15580 15577 break;
15581 15578
15582 15579 case ECANCELED:
15583 15580 warn(emsg_deleted);
15584 15581 break;
15585 15582
15586 15583 case EPERM:
15587 15584 warn(gettext("Could not refresh %s "
15588 15585 "(permission denied).\n"), fmribuf);
15589 15586 break;
15590 15587
15591 15588 case ENOSPC:
15592 15589 warn(gettext("Could not refresh %s "
15593 15590 "(repository server out of resources).\n"),
15594 15591 fmribuf);
15595 15592 break;
15596 15593
15597 15594 case EACCES:
15598 15595 default:
15599 15596 bad_error("refresh_entity", scf_error());
15600 15597 }
15601 15598
15602 15599 free(fmribuf);
15603 15600 }
15604 15601
15605 15602 /*
15606 15603 * describe [-v] [-t] [pg/prop]
15607 15604 */
15608 15605 int
15609 15606 lscf_describe(uu_list_t *args, int hasargs)
15610 15607 {
15611 15608 int ret = 0;
15612 15609 size_t i;
15613 15610 int argc;
15614 15611 char **argv = NULL;
15615 15612 string_list_t *slp;
15616 15613 int do_verbose = 0;
15617 15614 int do_templates = 0;
15618 15615 char *pattern = NULL;
15619 15616
15620 15617 lscf_prep_hndl();
15621 15618
15622 15619 if (hasargs != 0) {
15623 15620 argc = uu_list_numnodes(args);
15624 15621 if (argc < 1)
15625 15622 goto usage;
15626 15623
15627 15624 argv = calloc(argc + 1, sizeof (char *));
15628 15625 if (argv == NULL)
15629 15626 uu_die(gettext("Out of memory.\n"));
15630 15627
15631 15628 for (slp = uu_list_first(args), i = 0;
15632 15629 slp != NULL;
15633 15630 slp = uu_list_next(args, slp), ++i)
15634 15631 argv[i] = slp->str;
15635 15632
15636 15633 argv[i] = NULL;
15637 15634
15638 15635 /*
15639 15636 * We start optind = 0 because our list of arguments
15640 15637 * starts at argv[0]
15641 15638 */
15642 15639 optind = 0;
15643 15640 opterr = 0;
15644 15641 for (;;) {
15645 15642 ret = getopt(argc, argv, "vt");
15646 15643 if (ret == -1)
15647 15644 break;
15648 15645
15649 15646 switch (ret) {
15650 15647 case 'v':
15651 15648 do_verbose = 1;
15652 15649 break;
15653 15650
15654 15651 case 't':
15655 15652 do_templates = 1;
15656 15653 break;
15657 15654
15658 15655 case '?':
15659 15656 goto usage;
15660 15657
15661 15658 default:
15662 15659 bad_error("getopt", ret);
15663 15660 }
15664 15661 }
15665 15662
15666 15663 pattern = argv[optind];
15667 15664 }
15668 15665
15669 15666 if (cur_inst == NULL && cur_svc == NULL) {
15670 15667 semerr(emsg_entity_not_selected);
15671 15668 ret = -1;
15672 15669 goto out;
15673 15670 }
15674 15671
15675 15672 /*
15676 15673 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15677 15674 * output if their last parameter is set to 2. Less information is
15678 15675 * produced if the parameter is set to 1.
15679 15676 */
15680 15677 if (pattern == NULL) {
15681 15678 if (do_verbose == 1)
15682 15679 list_entity_tmpl(2);
15683 15680 else
15684 15681 list_entity_tmpl(1);
15685 15682 }
15686 15683
15687 15684 if (do_templates == 0) {
15688 15685 if (do_verbose == 1)
15689 15686 listprop(pattern, 0, 2);
15690 15687 else
15691 15688 listprop(pattern, 0, 1);
15692 15689 } else {
15693 15690 if (do_verbose == 1)
15694 15691 listtmpl(pattern, 2);
15695 15692 else
15696 15693 listtmpl(pattern, 1);
15697 15694 }
15698 15695
15699 15696 ret = 0;
15700 15697 out:
15701 15698 if (argv != NULL)
15702 15699 free(argv);
15703 15700 return (ret);
15704 15701 usage:
15705 15702 ret = -2;
15706 15703 goto out;
15707 15704 }
15708 15705
15709 15706 #define PARAM_ACTIVE ((const char *) "active")
15710 15707 #define PARAM_INACTIVE ((const char *) "inactive")
15711 15708 #define PARAM_SMTP_TO ((const char *) "to")
15712 15709
15713 15710 /*
15714 15711 * tokenize()
15715 15712 * Breaks down the string according to the tokens passed.
15716 15713 * Caller is responsible for freeing array of pointers returned.
15717 15714 * Returns NULL on failure
15718 15715 */
15719 15716 char **
15720 15717 tokenize(char *str, const char *sep)
15721 15718 {
15722 15719 char *token, *lasts;
15723 15720 char **buf;
15724 15721 int n = 0; /* number of elements */
15725 15722 int size = 8; /* size of the array (initial) */
15726 15723
15727 15724 buf = safe_malloc(size * sizeof (char *));
15728 15725
15729 15726 for (token = strtok_r(str, sep, &lasts); token != NULL;
15730 15727 token = strtok_r(NULL, sep, &lasts), ++n) {
15731 15728 if (n + 1 >= size) {
15732 15729 size *= 2;
15733 15730 if ((buf = realloc(buf, size * sizeof (char *))) ==
15734 15731 NULL) {
15735 15732 uu_die(gettext("Out of memory"));
15736 15733 }
15737 15734 }
15738 15735 buf[n] = token;
15739 15736 }
15740 15737 /* NULL terminate the pointer array */
15741 15738 buf[n] = NULL;
15742 15739
15743 15740 return (buf);
15744 15741 }
15745 15742
15746 15743 int32_t
15747 15744 check_tokens(char **p)
15748 15745 {
15749 15746 int32_t smf = 0;
15750 15747 int32_t fma = 0;
15751 15748
15752 15749 while (*p) {
15753 15750 int32_t t = string_to_tset(*p);
15754 15751
15755 15752 if (t == 0) {
15756 15753 if (is_fma_token(*p) == 0)
15757 15754 return (INVALID_TOKENS);
15758 15755 fma = 1; /* this token is an fma event */
15759 15756 } else {
15760 15757 smf |= t;
15761 15758 }
15762 15759
15763 15760 if (smf != 0 && fma == 1)
15764 15761 return (MIXED_TOKENS);
15765 15762 ++p;
15766 15763 }
15767 15764
15768 15765 if (smf > 0)
15769 15766 return (smf);
15770 15767 else if (fma == 1)
15771 15768 return (FMA_TOKENS);
15772 15769
15773 15770 return (INVALID_TOKENS);
15774 15771 }
15775 15772
15776 15773 static int
15777 15774 get_selection_str(char *fmri, size_t sz)
15778 15775 {
15779 15776 if (g_hndl == NULL) {
15780 15777 semerr(emsg_entity_not_selected);
15781 15778 return (-1);
15782 15779 } else if (cur_level != NULL) {
15783 15780 semerr(emsg_invalid_for_snapshot);
15784 15781 return (-1);
15785 15782 } else {
15786 15783 lscf_get_selection_str(fmri, sz);
15787 15784 }
15788 15785
15789 15786 return (0);
15790 15787 }
15791 15788
15792 15789 void
15793 15790 lscf_delnotify(const char *set, int global)
15794 15791 {
15795 15792 char *str = strdup(set);
15796 15793 char **pgs;
15797 15794 char **p;
15798 15795 int32_t tset;
15799 15796 char *fmri = NULL;
15800 15797
15801 15798 if (str == NULL)
15802 15799 uu_die(gettext("Out of memory.\n"));
15803 15800
15804 15801 pgs = tokenize(str, ",");
15805 15802
15806 15803 if ((tset = check_tokens(pgs)) > 0) {
15807 15804 size_t sz = max_scf_fmri_len + 1;
15808 15805
15809 15806 fmri = safe_malloc(sz);
15810 15807 if (global) {
15811 15808 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15812 15809 } else if (get_selection_str(fmri, sz) != 0) {
15813 15810 goto out;
15814 15811 }
15815 15812
15816 15813 if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri,
15817 15814 tset) != SCF_SUCCESS) {
15818 15815 uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15819 15816 scf_strerror(scf_error()));
15820 15817 }
15821 15818 } else if (tset == FMA_TOKENS) {
15822 15819 if (global) {
15823 15820 semerr(gettext("Can't use option '-g' with FMA event "
15824 15821 "definitions\n"));
15825 15822 goto out;
15826 15823 }
15827 15824
15828 15825 for (p = pgs; *p; ++p) {
15829 15826 if (smf_notify_del_params(de_tag(*p), NULL, 0) !=
15830 15827 SCF_SUCCESS) {
15831 15828 uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
15832 15829 scf_strerror(scf_error()));
15833 15830 goto out;
15834 15831 }
15835 15832 }
15836 15833 } else if (tset == MIXED_TOKENS) {
15837 15834 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15838 15835 goto out;
15839 15836 } else {
15840 15837 uu_die(gettext("Invalid input.\n"));
15841 15838 }
15842 15839
15843 15840 out:
15844 15841 free(fmri);
15845 15842 free(pgs);
15846 15843 free(str);
15847 15844 }
15848 15845
15849 15846 void
15850 15847 lscf_listnotify(const char *set, int global)
15851 15848 {
15852 15849 char *str = safe_strdup(set);
15853 15850 char **pgs;
15854 15851 char **p;
15855 15852 int32_t tset;
15856 15853 nvlist_t *nvl;
15857 15854 char *fmri = NULL;
15858 15855
15859 15856 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
15860 15857 uu_die(gettext("Out of memory.\n"));
15861 15858
15862 15859 pgs = tokenize(str, ",");
15863 15860
15864 15861 if ((tset = check_tokens(pgs)) > 0) {
15865 15862 size_t sz = max_scf_fmri_len + 1;
15866 15863
15867 15864 fmri = safe_malloc(sz);
15868 15865 if (global) {
15869 15866 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15870 15867 } else if (get_selection_str(fmri, sz) != 0) {
15871 15868 goto out;
15872 15869 }
15873 15870
15874 15871 if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
15875 15872 SCF_SUCCESS) {
15876 15873 if (scf_error() != SCF_ERROR_NOT_FOUND &&
15877 15874 scf_error() != SCF_ERROR_DELETED)
15878 15875 uu_warn(gettext(
15879 15876 "Failed listnotify: %s\n"),
15880 15877 scf_strerror(scf_error()));
15881 15878 goto out;
15882 15879 }
15883 15880
15884 15881 listnotify_print(nvl, NULL);
15885 15882 } else if (tset == FMA_TOKENS) {
15886 15883 if (global) {
15887 15884 semerr(gettext("Can't use option '-g' with FMA event "
15888 15885 "definitions\n"));
15889 15886 goto out;
15890 15887 }
15891 15888
15892 15889 for (p = pgs; *p; ++p) {
15893 15890 if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
15894 15891 SCF_SUCCESS) {
15895 15892 /*
15896 15893 * if the preferences have just been deleted
15897 15894 * or does not exist, just skip.
15898 15895 */
15899 15896 if (scf_error() == SCF_ERROR_NOT_FOUND ||
15900 15897 scf_error() == SCF_ERROR_DELETED)
15901 15898 continue;
15902 15899 uu_warn(gettext(
15903 15900 "Failed listnotify: %s\n"),
15904 15901 scf_strerror(scf_error()));
15905 15902 goto out;
15906 15903 }
15907 15904 listnotify_print(nvl, re_tag(*p));
15908 15905 }
15909 15906 } else if (tset == MIXED_TOKENS) {
15910 15907 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15911 15908 goto out;
15912 15909 } else {
15913 15910 semerr(gettext("Invalid input.\n"));
15914 15911 }
15915 15912
15916 15913 out:
15917 15914 nvlist_free(nvl);
15918 15915 free(fmri);
15919 15916 free(pgs);
15920 15917 free(str);
15921 15918 }
15922 15919
15923 15920 static char *
15924 15921 strip_quotes_and_blanks(char *s)
15925 15922 {
15926 15923 char *start = s;
15927 15924 char *end = strrchr(s, '\"');
15928 15925
15929 15926 if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
15930 15927 start = s + 1;
15931 15928 while (isblank(*start))
15932 15929 start++;
15933 15930 while (isblank(*(end - 1)) && end > start) {
15934 15931 end--;
15935 15932 }
15936 15933 *end = '\0';
15937 15934 }
15938 15935
15939 15936 return (start);
15940 15937 }
15941 15938
15942 15939 static int
15943 15940 set_active(nvlist_t *mech, const char *hier_part)
15944 15941 {
15945 15942 boolean_t b;
15946 15943
15947 15944 if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
15948 15945 b = B_TRUE;
15949 15946 } else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
15950 15947 b = B_FALSE;
15951 15948 } else {
15952 15949 return (-1);
15953 15950 }
15954 15951
15955 15952 if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
15956 15953 uu_die(gettext("Out of memory.\n"));
15957 15954
15958 15955 return (0);
15959 15956 }
15960 15957
15961 15958 static int
15962 15959 add_snmp_params(nvlist_t *mech, char *hier_part)
15963 15960 {
15964 15961 return (set_active(mech, hier_part));
15965 15962 }
15966 15963
15967 15964 static int
15968 15965 add_syslog_params(nvlist_t *mech, char *hier_part)
15969 15966 {
15970 15967 return (set_active(mech, hier_part));
15971 15968 }
15972 15969
15973 15970 /*
15974 15971 * add_mailto_paramas()
15975 15972 * parse the hier_part of mailto URI
15976 15973 * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
15977 15974 * or mailto:{[active]|inactive}
15978 15975 */
15979 15976 static int
15980 15977 add_mailto_params(nvlist_t *mech, char *hier_part)
15981 15978 {
15982 15979 const char *tok = "?&";
15983 15980 char *p;
15984 15981 char *lasts;
15985 15982 char *param;
15986 15983 char *val;
15987 15984
15988 15985 /*
15989 15986 * If the notification parametes are in the form of
15990 15987 *
15991 15988 * malito:{[active]|inactive}
15992 15989 *
15993 15990 * we set the property accordingly and return.
15994 15991 * Otherwise, we make the notification type active and
15995 15992 * process the hier_part.
15996 15993 */
15997 15994 if (set_active(mech, hier_part) == 0)
15998 15995 return (0);
15999 15996 else if (set_active(mech, PARAM_ACTIVE) != 0)
16000 15997 return (-1);
16001 15998
16002 15999 if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) {
16003 16000 /*
16004 16001 * sanity check: we only get here if hier_part = "", but
16005 16002 * that's handled by set_active
16006 16003 */
16007 16004 uu_die("strtok_r");
16008 16005 }
16009 16006
16010 16007 if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0)
16011 16008 uu_die(gettext("Out of memory.\n"));
16012 16009
16013 16010 while ((p = strtok_r(NULL, tok, &lasts)) != NULL)
16014 16011 if ((param = strtok_r(p, "=", &val)) != NULL)
16015 16012 if (nvlist_add_string(mech, param, val) != 0)
16016 16013 uu_die(gettext("Out of memory.\n"));
16017 16014
16018 16015 return (0);
16019 16016 }
16020 16017
16021 16018 static int
16022 16019 uri_split(char *uri, char **scheme, char **hier_part)
16023 16020 {
16024 16021 int r = -1;
16025 16022
16026 16023 if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
16027 16024 *hier_part == NULL) {
16028 16025 semerr(gettext("'%s' is not an URI\n"), uri);
16029 16026 return (r);
16030 16027 }
16031 16028
16032 16029 if ((r = check_uri_scheme(*scheme)) < 0) {
16033 16030 semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
16034 16031 return (r);
16035 16032 }
16036 16033
16037 16034 return (r);
16038 16035 }
16039 16036
16040 16037 static int
16041 16038 process_uri(nvlist_t *params, char *uri)
16042 16039 {
16043 16040 char *scheme;
16044 16041 char *hier_part;
16045 16042 nvlist_t *mech;
16046 16043 int index;
16047 16044 int r;
16048 16045
16049 16046 if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
16050 16047 return (-1);
16051 16048
16052 16049 if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
16053 16050 uu_die(gettext("Out of memory.\n"));
16054 16051
16055 16052 switch (index) {
16056 16053 case 0:
16057 16054 /* error messages displayed by called function */
16058 16055 r = add_mailto_params(mech, hier_part);
16059 16056 break;
16060 16057
16061 16058 case 1:
16062 16059 if ((r = add_snmp_params(mech, hier_part)) != 0)
16063 16060 semerr(gettext("Not valid parameters: '%s'\n"),
16064 16061 hier_part);
16065 16062 break;
16066 16063
16067 16064 case 2:
16068 16065 if ((r = add_syslog_params(mech, hier_part)) != 0)
16069 16066 semerr(gettext("Not valid parameters: '%s'\n"),
16070 16067 hier_part);
16071 16068 break;
16072 16069
16073 16070 default:
16074 16071 r = -1;
16075 16072 }
16076 16073
16077 16074 if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
16078 16075 mech) != 0)
16079 16076 uu_die(gettext("Out of memory.\n"));
16080 16077
16081 16078 nvlist_free(mech);
16082 16079 return (r);
16083 16080 }
16084 16081
16085 16082 static int
16086 16083 set_params(nvlist_t *params, char **p)
16087 16084 {
16088 16085 char *uri;
16089 16086
16090 16087 if (p == NULL)
16091 16088 /* sanity check */
16092 16089 uu_die("set_params");
16093 16090
16094 16091 while (*p) {
16095 16092 uri = strip_quotes_and_blanks(*p);
16096 16093 if (process_uri(params, uri) != 0)
16097 16094 return (-1);
16098 16095
16099 16096 ++p;
16100 16097 }
16101 16098
16102 16099 return (0);
16103 16100 }
16104 16101
16105 16102 static int
16106 16103 setnotify(const char *e, char **p, int global)
16107 16104 {
16108 16105 char *str = safe_strdup(e);
16109 16106 char **events;
16110 16107 int32_t tset;
16111 16108 int r = -1;
16112 16109 nvlist_t *nvl, *params;
16113 16110 char *fmri = NULL;
16114 16111
16115 16112 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
16116 16113 nvlist_alloc(¶ms, NV_UNIQUE_NAME, 0) != 0 ||
16117 16114 nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
16118 16115 SCF_NOTIFY_PARAMS_VERSION) != 0)
16119 16116 uu_die(gettext("Out of memory.\n"));
16120 16117
16121 16118 events = tokenize(str, ",");
16122 16119
16123 16120 if ((tset = check_tokens(events)) > 0) {
16124 16121 /* SMF state transitions parameters */
16125 16122 size_t sz = max_scf_fmri_len + 1;
16126 16123
16127 16124 fmri = safe_malloc(sz);
16128 16125 if (global) {
16129 16126 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
16130 16127 } else if (get_selection_str(fmri, sz) != 0) {
16131 16128 goto out;
16132 16129 }
16133 16130
16134 16131 if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 ||
16135 16132 nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0)
16136 16133 uu_die(gettext("Out of memory.\n"));
16137 16134
16138 16135 if ((r = set_params(params, p)) == 0) {
16139 16136 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS,
16140 16137 params) != 0)
16141 16138 uu_die(gettext("Out of memory.\n"));
16142 16139
16143 16140 if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
16144 16141 nvl) != SCF_SUCCESS) {
16145 16142 r = -1;
16146 16143 uu_warn(gettext(
16147 16144 "Failed smf_notify_set_params(3SCF): %s\n"),
16148 16145 scf_strerror(scf_error()));
16149 16146 }
16150 16147 }
16151 16148 } else if (tset == FMA_TOKENS) {
16152 16149 /* FMA event parameters */
16153 16150 if (global) {
16154 16151 semerr(gettext("Can't use option '-g' with FMA event "
16155 16152 "definitions\n"));
16156 16153 goto out;
16157 16154 }
16158 16155
16159 16156 if ((r = set_params(params, p)) != 0)
16160 16157 goto out;
16161 16158
16162 16159 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
16163 16160 uu_die(gettext("Out of memory.\n"));
16164 16161
16165 16162 while (*events) {
16166 16163 if (smf_notify_set_params(de_tag(*events), nvl) !=
16167 16164 SCF_SUCCESS)
16168 16165 uu_warn(gettext(
16169 16166 "Failed smf_notify_set_params(3SCF) for "
16170 16167 "event %s: %s\n"), *events,
16171 16168 scf_strerror(scf_error()));
16172 16169 events++;
16173 16170 }
16174 16171 } else if (tset == MIXED_TOKENS) {
16175 16172 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
16176 16173 } else {
16177 16174 /* Sanity check */
16178 16175 uu_die(gettext("Invalid input.\n"));
16179 16176 }
16180 16177
16181 16178 out:
16182 16179 nvlist_free(nvl);
16183 16180 nvlist_free(params);
16184 16181 free(fmri);
16185 16182 free(str);
16186 16183
16187 16184 return (r);
16188 16185 }
16189 16186
16190 16187 int
16191 16188 lscf_setnotify(uu_list_t *args)
16192 16189 {
16193 16190 int argc;
16194 16191 char **argv = NULL;
16195 16192 string_list_t *slp;
16196 16193 int global;
16197 16194 char *events;
16198 16195 char **p;
16199 16196 int i;
16200 16197 int ret;
16201 16198
16202 16199 if ((argc = uu_list_numnodes(args)) < 2)
16203 16200 goto usage;
16204 16201
16205 16202 argv = calloc(argc + 1, sizeof (char *));
16206 16203 if (argv == NULL)
16207 16204 uu_die(gettext("Out of memory.\n"));
16208 16205
16209 16206 for (slp = uu_list_first(args), i = 0;
16210 16207 slp != NULL;
16211 16208 slp = uu_list_next(args, slp), ++i)
16212 16209 argv[i] = slp->str;
16213 16210
16214 16211 argv[i] = NULL;
16215 16212
16216 16213 if (strcmp(argv[0], "-g") == 0) {
16217 16214 global = 1;
16218 16215 events = argv[1];
16219 16216 p = argv + 2;
16220 16217 } else {
16221 16218 global = 0;
16222 16219 events = argv[0];
16223 16220 p = argv + 1;
16224 16221 }
16225 16222
16226 16223 ret = setnotify(events, p, global);
16227 16224
16228 16225 out:
16229 16226 free(argv);
16230 16227 return (ret);
16231 16228
16232 16229 usage:
16233 16230 ret = -2;
16234 16231 goto out;
16235 16232 }
16236 16233
16237 16234 /*
16238 16235 * Creates a list of instance name strings associated with a service. If
16239 16236 * wohandcrafted flag is set, get only instances that have a last-import
16240 16237 * snapshot, instances that were imported via svccfg.
16241 16238 */
16242 16239 static uu_list_t *
16243 16240 create_instance_list(scf_service_t *svc, int wohandcrafted)
16244 16241 {
16245 16242 scf_snapshot_t *snap = NULL;
16246 16243 scf_instance_t *inst;
16247 16244 scf_iter_t *inst_iter;
16248 16245 uu_list_t *instances;
16249 16246 char *instname;
16250 16247 int r;
16251 16248
16252 16249 inst_iter = scf_iter_create(g_hndl);
16253 16250 inst = scf_instance_create(g_hndl);
16254 16251 if (inst_iter == NULL || inst == NULL) {
16255 16252 uu_warn(gettext("Could not create instance or iterator\n"));
16256 16253 scfdie();
16257 16254 }
16258 16255
16259 16256 if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
16260 16257 return (instances);
16261 16258
16262 16259 if (scf_iter_service_instances(inst_iter, svc) != 0) {
16263 16260 switch (scf_error()) {
16264 16261 case SCF_ERROR_CONNECTION_BROKEN:
16265 16262 case SCF_ERROR_DELETED:
16266 16263 uu_list_destroy(instances);
16267 16264 instances = NULL;
16268 16265 goto out;
16269 16266
16270 16267 case SCF_ERROR_HANDLE_MISMATCH:
16271 16268 case SCF_ERROR_NOT_BOUND:
16272 16269 case SCF_ERROR_NOT_SET:
16273 16270 default:
16274 16271 bad_error("scf_iter_service_instances", scf_error());
16275 16272 }
16276 16273 }
16277 16274
16278 16275 instname = safe_malloc(max_scf_name_len + 1);
16279 16276 while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
16280 16277 if (r == -1) {
16281 16278 (void) uu_warn(gettext("Unable to iterate through "
16282 16279 "instances to create instance list : %s\n"),
16283 16280 scf_strerror(scf_error()));
16284 16281
16285 16282 uu_list_destroy(instances);
16286 16283 instances = NULL;
16287 16284 goto out;
16288 16285 }
16289 16286
16290 16287 /*
16291 16288 * If the instance does not have a last-import snapshot
16292 16289 * then do not add it to the list as it is a hand-crafted
16293 16290 * instance that should not be managed.
16294 16291 */
16295 16292 if (wohandcrafted) {
16296 16293 if (snap == NULL &&
16297 16294 (snap = scf_snapshot_create(g_hndl)) == NULL) {
16298 16295 uu_warn(gettext("Unable to create snapshot "
16299 16296 "entity\n"));
16300 16297 scfdie();
16301 16298 }
16302 16299
16303 16300 if (scf_instance_get_snapshot(inst,
16304 16301 snap_lastimport, snap) != 0) {
16305 16302 switch (scf_error()) {
16306 16303 case SCF_ERROR_NOT_FOUND :
16307 16304 case SCF_ERROR_DELETED:
16308 16305 continue;
16309 16306
16310 16307 case SCF_ERROR_CONNECTION_BROKEN:
16311 16308 uu_list_destroy(instances);
16312 16309 instances = NULL;
16313 16310 goto out;
16314 16311
16315 16312 case SCF_ERROR_HANDLE_MISMATCH:
16316 16313 case SCF_ERROR_NOT_BOUND:
16317 16314 case SCF_ERROR_NOT_SET:
16318 16315 default:
16319 16316 bad_error("scf_iter_service_instances",
16320 16317 scf_error());
16321 16318 }
16322 16319 }
16323 16320 }
16324 16321
16325 16322 if (scf_instance_get_name(inst, instname,
16326 16323 max_scf_name_len + 1) < 0) {
16327 16324 switch (scf_error()) {
16328 16325 case SCF_ERROR_NOT_FOUND :
16329 16326 continue;
16330 16327
16331 16328 case SCF_ERROR_CONNECTION_BROKEN:
16332 16329 case SCF_ERROR_DELETED:
16333 16330 uu_list_destroy(instances);
16334 16331 instances = NULL;
16335 16332 goto out;
16336 16333
16337 16334 case SCF_ERROR_HANDLE_MISMATCH:
16338 16335 case SCF_ERROR_NOT_BOUND:
16339 16336 case SCF_ERROR_NOT_SET:
16340 16337 default:
16341 16338 bad_error("scf_iter_service_instances",
16342 16339 scf_error());
16343 16340 }
16344 16341 }
16345 16342
16346 16343 add_string(instances, instname);
16347 16344 }
16348 16345
16349 16346 out:
16350 16347 if (snap)
16351 16348 scf_snapshot_destroy(snap);
16352 16349
16353 16350 scf_instance_destroy(inst);
16354 16351 scf_iter_destroy(inst_iter);
16355 16352 free(instname);
16356 16353 return (instances);
16357 16354 }
16358 16355
16359 16356 /*
16360 16357 * disable an instance but wait for the instance to
16361 16358 * move out of the running state.
16362 16359 *
16363 16360 * Returns 0 : if the instance did not disable
16364 16361 * Returns non-zero : if the instance disabled.
16365 16362 *
16366 16363 */
16367 16364 static int
16368 16365 disable_instance(scf_instance_t *instance)
16369 16366 {
16370 16367 char *fmribuf;
16371 16368 int enabled = 10000;
16372 16369
16373 16370 if (inst_is_running(instance)) {
16374 16371 fmribuf = safe_malloc(max_scf_name_len + 1);
16375 16372 if (scf_instance_to_fmri(instance, fmribuf,
16376 16373 max_scf_name_len + 1) < 0) {
16377 16374 free(fmribuf);
16378 16375 return (0);
16379 16376 }
16380 16377
16381 16378 /*
16382 16379 * If the instance cannot be disabled then return
16383 16380 * failure to disable and let the caller decide
16384 16381 * if that is of importance.
16385 16382 */
16386 16383 if (smf_disable_instance(fmribuf, 0) != 0) {
16387 16384 free(fmribuf);
16388 16385 return (0);
16389 16386 }
16390 16387
16391 16388 while (enabled) {
16392 16389 if (!inst_is_running(instance))
16393 16390 break;
16394 16391
16395 16392 (void) poll(NULL, 0, 5);
16396 16393 enabled = enabled - 5;
16397 16394 }
16398 16395
16399 16396 free(fmribuf);
16400 16397 }
16401 16398
16402 16399 return (enabled);
16403 16400 }
16404 16401
16405 16402 /*
16406 16403 * Function to compare two service_manifest structures.
16407 16404 */
16408 16405 /* ARGSUSED2 */
16409 16406 static int
16410 16407 service_manifest_compare(const void *left, const void *right, void *unused)
16411 16408 {
16412 16409 service_manifest_t *l = (service_manifest_t *)left;
16413 16410 service_manifest_t *r = (service_manifest_t *)right;
16414 16411 int rc;
16415 16412
16416 16413 rc = strcmp(l->servicename, r->servicename);
16417 16414
16418 16415 return (rc);
16419 16416 }
16420 16417
16421 16418 /*
16422 16419 * Look for the provided service in the service to manifest
16423 16420 * tree. If the service exists, and a manifest was provided
16424 16421 * then add the manifest to that service. If the service
16425 16422 * does not exist, then add the service and manifest to the
16426 16423 * list.
16427 16424 *
16428 16425 * If the manifest is NULL, return the element if found. If
16429 16426 * the service is not found return NULL.
16430 16427 */
16431 16428 service_manifest_t *
16432 16429 find_add_svc_mfst(const char *svnbuf, const char *mfst)
16433 16430 {
16434 16431 service_manifest_t elem;
16435 16432 service_manifest_t *fnelem;
16436 16433 uu_avl_index_t marker;
16437 16434
16438 16435 elem.servicename = svnbuf;
16439 16436 fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
16440 16437
16441 16438 if (mfst) {
16442 16439 if (fnelem) {
16443 16440 add_string(fnelem->mfstlist, strdup(mfst));
16444 16441 } else {
16445 16442 fnelem = safe_malloc(sizeof (*fnelem));
16446 16443 fnelem->servicename = safe_strdup(svnbuf);
16447 16444 if ((fnelem->mfstlist =
16448 16445 uu_list_create(string_pool, NULL, 0)) == NULL)
16449 16446 uu_die(gettext("Could not create property "
16450 16447 "list: %s\n"), uu_strerror(uu_error()));
16451 16448
16452 16449 add_string(fnelem->mfstlist, safe_strdup(mfst));
16453 16450
16454 16451 uu_avl_insert(service_manifest_tree, fnelem, marker);
16455 16452 }
16456 16453 }
16457 16454
16458 16455 return (fnelem);
16459 16456 }
16460 16457
16461 16458 /*
16462 16459 * Create the service to manifest avl tree.
16463 16460 *
16464 16461 * Walk each of the manifests currently installed in the supported
16465 16462 * directories, /lib/svc/manifests and /var/svc/manifests. For
16466 16463 * each of the manifests, inventory the services and add them to
16467 16464 * the tree.
16468 16465 *
16469 16466 * Code that calls this function should make sure fileystem/minimal is online,
16470 16467 * /var is available, since this function walks the /var/svc/manifest directory.
16471 16468 */
16472 16469 static void
16473 16470 create_manifest_tree(void)
16474 16471 {
16475 16472 manifest_info_t **entry;
16476 16473 manifest_info_t **manifests;
16477 16474 uu_list_walk_t *svcs;
16478 16475 bundle_t *b;
16479 16476 entity_t *mfsvc;
16480 16477 char *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
16481 16478 int c, status;
16482 16479
16483 16480 if (service_manifest_pool)
16484 16481 return;
16485 16482
16486 16483 /*
16487 16484 * Create the list pool for the service manifest list
16488 16485 */
16489 16486 service_manifest_pool = uu_avl_pool_create("service_manifest",
16490 16487 sizeof (service_manifest_t),
16491 16488 offsetof(service_manifest_t, svcmfst_node),
16492 16489 service_manifest_compare, UU_DEFAULT);
16493 16490 if (service_manifest_pool == NULL)
16494 16491 uu_die(gettext("service_manifest pool creation failed: %s\n"),
16495 16492 uu_strerror(uu_error()));
16496 16493
16497 16494 /*
16498 16495 * Create the list
16499 16496 */
16500 16497 service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
16501 16498 UU_DEFAULT);
16502 16499 if (service_manifest_tree == NULL)
16503 16500 uu_die(gettext("service_manifest tree creation failed: %s\n"),
16504 16501 uu_strerror(uu_error()));
16505 16502
16506 16503 /*
16507 16504 * Walk the manifests adding the service(s) from each manifest.
16508 16505 *
16509 16506 * If a service already exists add the manifest to the manifest
16510 16507 * list for that service. This covers the case of a service that
16511 16508 * is supported by multiple manifest files.
16512 16509 */
16513 16510 for (c = 0; dirs[c]; c++) {
16514 16511 status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT);
16515 16512 if (status < 0) {
16516 16513 uu_warn(gettext("file tree walk of %s encountered "
16517 16514 "error %s\n"), dirs[c], strerror(errno));
16518 16515
16519 16516 uu_avl_destroy(service_manifest_tree);
16520 16517 service_manifest_tree = NULL;
16521 16518 return;
16522 16519 }
16523 16520
16524 16521 /*
16525 16522 * If a manifest that was in the list is not found
16526 16523 * then skip and go to the next manifest file.
16527 16524 */
16528 16525 if (manifests != NULL) {
16529 16526 for (entry = manifests; *entry != NULL; entry++) {
16530 16527 b = internal_bundle_new();
16531 16528 if (lxml_get_bundle_file(b, (*entry)->mi_path,
16532 16529 SVCCFG_OP_IMPORT) != 0) {
16533 16530 internal_bundle_free(b);
16534 16531 continue;
16535 16532 }
16536 16533
16537 16534 svcs = uu_list_walk_start(b->sc_bundle_services,
16538 16535 0);
16539 16536 if (svcs == NULL) {
16540 16537 internal_bundle_free(b);
16541 16538 continue;
16542 16539 }
16543 16540
16544 16541 while ((mfsvc = uu_list_walk_next(svcs)) !=
16545 16542 NULL) {
16546 16543 /* Add manifest to service */
16547 16544 (void) find_add_svc_mfst(mfsvc->sc_name,
16548 16545 (*entry)->mi_path);
16549 16546 }
16550 16547
16551 16548 uu_list_walk_end(svcs);
16552 16549 internal_bundle_free(b);
16553 16550 }
16554 16551
16555 16552 free_manifest_array(manifests);
16556 16553 }
16557 16554 }
16558 16555 }
16559 16556
16560 16557 /*
16561 16558 * Check the manifest history file to see
16562 16559 * if the service was ever installed from
16563 16560 * one of the supported directories.
16564 16561 *
16565 16562 * Return Values :
16566 16563 * -1 - if there's error reading manifest history file
16567 16564 * 1 - if the service is not found
16568 16565 * 0 - if the service is found
16569 16566 */
16570 16567 static int
16571 16568 check_mfst_history(const char *svcname)
16572 16569 {
16573 16570 struct stat st;
16574 16571 caddr_t mfsthist_start;
16575 16572 char *svnbuf;
16576 16573 int fd;
16577 16574 int r = 1;
16578 16575
16579 16576 fd = open(MFSTHISTFILE, O_RDONLY);
16580 16577 if (fd == -1) {
16581 16578 uu_warn(gettext("Unable to open the history file\n"));
16582 16579 return (-1);
16583 16580 }
16584 16581
16585 16582 if (fstat(fd, &st) == -1) {
16586 16583 uu_warn(gettext("Unable to stat the history file\n"));
16587 16584 return (-1);
16588 16585 }
16589 16586
16590 16587 mfsthist_start = mmap(0, st.st_size, PROT_READ,
16591 16588 MAP_PRIVATE, fd, 0);
16592 16589
16593 16590 (void) close(fd);
16594 16591 if (mfsthist_start == MAP_FAILED ||
16595 16592 *(mfsthist_start + st.st_size) != '\0') {
16596 16593 (void) munmap(mfsthist_start, st.st_size);
16597 16594 return (-1);
16598 16595 }
16599 16596
16600 16597 /*
16601 16598 * The manifest history file is a space delimited list
16602 16599 * of service and instance to manifest linkage. Adding
16603 16600 * a space to the end of the service name so to get only
16604 16601 * the service that is being searched for.
16605 16602 */
16606 16603 svnbuf = uu_msprintf("%s ", svcname);
16607 16604 if (svnbuf == NULL)
16608 16605 uu_die(gettext("Out of memory"));
16609 16606
16610 16607 if (strstr(mfsthist_start, svnbuf) != NULL)
16611 16608 r = 0;
16612 16609
16613 16610 (void) munmap(mfsthist_start, st.st_size);
16614 16611 uu_free(svnbuf);
16615 16612 return (r);
16616 16613 }
16617 16614
16618 16615 /*
16619 16616 * Take down each of the instances in the service
16620 16617 * and remove them, then delete the service.
16621 16618 */
16622 16619 static void
16623 16620 teardown_service(scf_service_t *svc, const char *svnbuf)
16624 16621 {
16625 16622 scf_instance_t *instance;
16626 16623 scf_iter_t *iter;
16627 16624 int r;
16628 16625
16629 16626 safe_printf(gettext("Delete service %s as there are no "
16630 16627 "supporting manifests\n"), svnbuf);
16631 16628
16632 16629 instance = scf_instance_create(g_hndl);
16633 16630 iter = scf_iter_create(g_hndl);
16634 16631 if (iter == NULL || instance == NULL) {
16635 16632 uu_warn(gettext("Unable to create supporting entities to "
16636 16633 "teardown the service\n"));
16637 16634 uu_warn(gettext("scf error is : %s\n"),
16638 16635 scf_strerror(scf_error()));
16639 16636 scfdie();
16640 16637 }
16641 16638
16642 16639 if (scf_iter_service_instances(iter, svc) != 0) {
16643 16640 switch (scf_error()) {
16644 16641 case SCF_ERROR_CONNECTION_BROKEN:
16645 16642 case SCF_ERROR_DELETED:
16646 16643 goto out;
16647 16644
16648 16645 case SCF_ERROR_HANDLE_MISMATCH:
16649 16646 case SCF_ERROR_NOT_BOUND:
16650 16647 case SCF_ERROR_NOT_SET:
16651 16648 default:
16652 16649 bad_error("scf_iter_service_instances",
16653 16650 scf_error());
16654 16651 }
16655 16652 }
16656 16653
16657 16654 while ((r = scf_iter_next_instance(iter, instance)) != 0) {
16658 16655 if (r == -1) {
16659 16656 uu_warn(gettext("Error - %s\n"),
16660 16657 scf_strerror(scf_error()));
16661 16658 goto out;
16662 16659 }
16663 16660
16664 16661 (void) disable_instance(instance);
16665 16662 }
16666 16663
16667 16664 /*
16668 16665 * Delete the service... forcing the deletion in case
16669 16666 * any of the instances did not disable.
16670 16667 */
16671 16668 (void) lscf_service_delete(svc, 1);
16672 16669 out:
16673 16670 scf_instance_destroy(instance);
16674 16671 scf_iter_destroy(iter);
16675 16672 }
16676 16673
16677 16674 /*
16678 16675 * Get the list of instances supported by the manifest
16679 16676 * file.
16680 16677 *
16681 16678 * Return 0 if there are no instances.
16682 16679 *
16683 16680 * Return -1 if there are errors attempting to collect instances.
16684 16681 *
16685 16682 * Return the count of instances found if there are no errors.
16686 16683 *
16687 16684 */
16688 16685 static int
16689 16686 check_instance_support(char *mfstfile, const char *svcname,
16690 16687 uu_list_t *instances)
16691 16688 {
16692 16689 uu_list_walk_t *svcs, *insts;
16693 16690 uu_list_t *ilist;
16694 16691 bundle_t *b;
16695 16692 entity_t *mfsvc, *mfinst;
16696 16693 const char *svcn;
16697 16694 int rminstcnt = 0;
16698 16695
16699 16696
16700 16697 b = internal_bundle_new();
16701 16698
16702 16699 if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
16703 16700 /*
16704 16701 * Unable to process the manifest file for
16705 16702 * instance support, so just return as
16706 16703 * don't want to remove instances that could
16707 16704 * not be accounted for that might exist here.
16708 16705 */
16709 16706 internal_bundle_free(b);
16710 16707 return (0);
16711 16708 }
16712 16709
16713 16710 svcs = uu_list_walk_start(b->sc_bundle_services, 0);
16714 16711 if (svcs == NULL) {
16715 16712 internal_bundle_free(b);
16716 16713 return (0);
16717 16714 }
16718 16715
16719 16716 svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
16720 16717 (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
16721 16718
16722 16719 while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
16723 16720 if (strcmp(mfsvc->sc_name, svcn) == 0)
16724 16721 break;
16725 16722 }
16726 16723 uu_list_walk_end(svcs);
16727 16724
16728 16725 if (mfsvc == NULL) {
16729 16726 internal_bundle_free(b);
16730 16727 return (-1);
16731 16728 }
16732 16729
16733 16730 ilist = mfsvc->sc_u.sc_service.sc_service_instances;
16734 16731 if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
16735 16732 internal_bundle_free(b);
16736 16733 return (0);
16737 16734 }
16738 16735
16739 16736 while ((mfinst = uu_list_walk_next(insts)) != NULL) {
16740 16737 /*
16741 16738 * Remove the instance from the instances list.
16742 16739 * The unaccounted for instances will be removed
16743 16740 * from the service once all manifests are
16744 16741 * processed.
16745 16742 */
16746 16743 (void) remove_string(instances,
16747 16744 mfinst->sc_name);
16748 16745 rminstcnt++;
16749 16746 }
16750 16747
16751 16748 uu_list_walk_end(insts);
16752 16749 internal_bundle_free(b);
16753 16750
16754 16751 return (rminstcnt);
16755 16752 }
16756 16753
16757 16754 /*
16758 16755 * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16759 16756 * 'false' to indicate there's no manifest file(s) found for the service.
16760 16757 */
16761 16758 static void
16762 16759 svc_add_no_support(scf_service_t *svc)
16763 16760 {
16764 16761 char *pname;
16765 16762
16766 16763 /* Add no support */
16767 16764 cur_svc = svc;
16768 16765 if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
16769 16766 return;
16770 16767
16771 16768 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
16772 16769 if (pname == NULL)
16773 16770 uu_die(gettext("Out of memory.\n"));
16774 16771
16775 16772 (void) lscf_addpropvalue(pname, "boolean:", "0");
16776 16773
16777 16774 uu_free(pname);
16778 16775 cur_svc = NULL;
16779 16776 }
16780 16777
16781 16778 /*
16782 16779 * This function handles all upgrade scenarios for a service that doesn't have
16783 16780 * SCF_PG_MANIFESTFILES pg. The function creates and populates
16784 16781 * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16785 16782 * manifest(s) mapping. Manifests under supported directories are inventoried
16786 16783 * and a property is added for each file that delivers configuration to the
16787 16784 * service. A service that has no corresponding manifest files (deleted) are
16788 16785 * removed from repository.
16789 16786 *
16790 16787 * Unsupported services:
16791 16788 *
16792 16789 * A service is considered unsupported if there is no corresponding manifest
16793 16790 * in the supported directories for that service and the service isn't in the
16794 16791 * history file list. The history file, MFSTHISTFILE, contains a list of all
16795 16792 * services and instances that were delivered by Solaris before the introduction
16796 16793 * of the SCF_PG_MANIFESTFILES property group. The history file also contains
16797 16794 * the path to the manifest file that defined the service or instance.
16798 16795 *
16799 16796 * Another type of unsupported services is 'handcrafted' services,
16800 16797 * programmatically created services or services created by dependent entries
16801 16798 * in other manifests. A handcrafted service is identified by its lack of any
16802 16799 * instance containing last-import snapshot which is created during svccfg
16803 16800 * import.
16804 16801 *
16805 16802 * This function sets a flag for unsupported services by setting services'
16806 16803 * SCF_PG_MANIFESTFILES/support property to false.
16807 16804 */
16808 16805 static void
16809 16806 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
16810 16807 {
16811 16808 service_manifest_t *elem;
16812 16809 uu_list_walk_t *mfwalk;
16813 16810 string_list_t *mfile;
16814 16811 uu_list_t *instances;
16815 16812 const char *sname;
16816 16813 char *pname;
16817 16814 int r;
16818 16815
16819 16816 /*
16820 16817 * Since there's no guarantee manifests under /var are available during
16821 16818 * early import, don't perform any upgrade during early import.
16822 16819 */
16823 16820 if (IGNORE_VAR)
16824 16821 return;
16825 16822
16826 16823 if (service_manifest_tree == NULL) {
16827 16824 create_manifest_tree();
16828 16825 }
16829 16826
16830 16827 /*
16831 16828 * Find service's supporting manifest(s) after
16832 16829 * stripping off the svc:/ prefix that is part
16833 16830 * of the fmri that is not used in the service
16834 16831 * manifest bundle list.
16835 16832 */
16836 16833 sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
16837 16834 strlen(SCF_FMRI_SERVICE_PREFIX);
16838 16835 elem = find_add_svc_mfst(sname, NULL);
16839 16836 if (elem == NULL) {
16840 16837
16841 16838 /*
16842 16839 * A handcrafted service, one that has no instance containing
16843 16840 * last-import snapshot, should get unsupported flag.
16844 16841 */
16845 16842 instances = create_instance_list(svc, 1);
16846 16843 if (instances == NULL) {
16847 16844 uu_warn(gettext("Unable to create instance list %s\n"),
16848 16845 svcname);
16849 16846 return;
16850 16847 }
16851 16848
16852 16849 if (uu_list_numnodes(instances) == 0) {
16853 16850 svc_add_no_support(svc);
16854 16851 return;
16855 16852 }
16856 16853
16857 16854 /*
16858 16855 * If the service is in the history file, and its supporting
16859 16856 * manifests are not found, we can safely delete the service
16860 16857 * because its manifests are removed from the system.
16861 16858 *
16862 16859 * Services not found in the history file are not delivered by
16863 16860 * Solaris and/or delivered outside supported directories, set
16864 16861 * unsupported flag for these services.
16865 16862 */
16866 16863 r = check_mfst_history(svcname);
16867 16864 if (r == -1)
16868 16865 return;
16869 16866
16870 16867 if (r) {
16871 16868 /* Set unsupported flag for service */
16872 16869 svc_add_no_support(svc);
16873 16870 } else {
16874 16871 /* Delete the service */
16875 16872 teardown_service(svc, svcname);
16876 16873 }
16877 16874
16878 16875 return;
16879 16876 }
16880 16877
16881 16878 /*
16882 16879 * Walk through the list of manifests and add them
16883 16880 * to the service.
16884 16881 *
16885 16882 * Create a manifestfiles pg and add the property.
16886 16883 */
16887 16884 mfwalk = uu_list_walk_start(elem->mfstlist, 0);
16888 16885 if (mfwalk == NULL)
16889 16886 return;
16890 16887
16891 16888 cur_svc = svc;
16892 16889 r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
16893 16890 if (r != 0) {
16894 16891 cur_svc = NULL;
16895 16892 return;
16896 16893 }
16897 16894
16898 16895 while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
16899 16896 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16900 16897 mhash_filename_to_propname(mfile->str, 0));
16901 16898 if (pname == NULL)
16902 16899 uu_die(gettext("Out of memory.\n"));
16903 16900
16904 16901 (void) lscf_addpropvalue(pname, "astring:", mfile->str);
16905 16902 uu_free(pname);
16906 16903 }
16907 16904 uu_list_walk_end(mfwalk);
16908 16905
16909 16906 cur_svc = NULL;
16910 16907 }
16911 16908
16912 16909 /*
16913 16910 * Take a service and process the manifest file entires to see if
16914 16911 * there is continued support for the service and instances. If
16915 16912 * not cleanup as appropriate.
16916 16913 *
16917 16914 * If a service does not have a manifest files entry flag it for
16918 16915 * upgrade and return.
16919 16916 *
16920 16917 * For each manifestfiles property check if the manifest file is
16921 16918 * under the supported /lib/svc/manifest or /var/svc/manifest path
16922 16919 * and if not then return immediately as this service is not supported
16923 16920 * by the cleanup mechanism and should be ignored.
16924 16921 *
16925 16922 * For each manifest file that is supported, check to see if the
16926 16923 * file exists. If not then remove the manifest file property
16927 16924 * from the service and the smf/manifest hash table. If the manifest
16928 16925 * file exists then verify that it supports the instances that are
16929 16926 * part of the service.
16930 16927 *
16931 16928 * Once all manifest files have been accounted for remove any instances
16932 16929 * that are no longer supported in the service.
16933 16930 *
16934 16931 * Return values :
16935 16932 * 0 - Successfully processed the service
16936 16933 * non-zero - failed to process the service
16937 16934 *
16938 16935 * On most errors, will just return to wait and get the next service,
16939 16936 * unless in case of unable to create the needed structures which is
16940 16937 * most likely a fatal error that is not going to be recoverable.
16941 16938 */
16942 16939 int
16943 16940 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
16944 16941 {
16945 16942 struct mpg_mfile *mpntov;
16946 16943 struct mpg_mfile **mpvarry = NULL;
16947 16944 scf_service_t *svc;
16948 16945 scf_propertygroup_t *mpg;
16949 16946 scf_property_t *mp;
16950 16947 scf_value_t *mv;
16951 16948 scf_iter_t *mi;
16952 16949 scf_instance_t *instance;
16953 16950 uu_list_walk_t *insts;
16954 16951 uu_list_t *instances = NULL;
16955 16952 boolean_t activity = (boolean_t)act;
16956 16953 char *mpnbuf;
16957 16954 char *mpvbuf;
16958 16955 char *pgpropbuf;
16959 16956 int mfstcnt, rminstct, instct, mfstmax;
16960 16957 int index;
16961 16958 int r = 0;
16962 16959
16963 16960 assert(g_hndl != NULL);
16964 16961 assert(wip->svc != NULL);
16965 16962 assert(wip->fmri != NULL);
16966 16963
16967 16964 svc = wip->svc;
16968 16965
16969 16966 mpg = scf_pg_create(g_hndl);
16970 16967 mp = scf_property_create(g_hndl);
16971 16968 mi = scf_iter_create(g_hndl);
16972 16969 mv = scf_value_create(g_hndl);
16973 16970 instance = scf_instance_create(g_hndl);
16974 16971
16975 16972 if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
16976 16973 instance == NULL) {
16977 16974 uu_warn(gettext("Unable to create the supporting entities\n"));
16978 16975 uu_warn(gettext("scf error is : %s\n"),
16979 16976 scf_strerror(scf_error()));
16980 16977 scfdie();
16981 16978 }
16982 16979
16983 16980 /*
16984 16981 * Get the manifestfiles property group to be parsed for
16985 16982 * files existence.
16986 16983 */
16987 16984 if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
16988 16985 switch (scf_error()) {
16989 16986 case SCF_ERROR_NOT_FOUND:
16990 16987 upgrade_svc_mfst_connection(svc, wip->fmri);
16991 16988 break;
16992 16989 case SCF_ERROR_DELETED:
16993 16990 case SCF_ERROR_CONNECTION_BROKEN:
16994 16991 goto out;
16995 16992
16996 16993 case SCF_ERROR_HANDLE_MISMATCH:
16997 16994 case SCF_ERROR_NOT_BOUND:
16998 16995 case SCF_ERROR_NOT_SET:
16999 16996 default:
17000 16997 bad_error("scf_iter_pg_properties",
17001 16998 scf_error());
17002 16999 }
17003 17000
17004 17001 goto out;
17005 17002 }
17006 17003
17007 17004 /*
17008 17005 * Iterate through each of the manifestfiles properties
17009 17006 * to determine what manifestfiles are available.
17010 17007 *
17011 17008 * If a manifest file is supported then increment the
17012 17009 * count and therefore the service is safe.
17013 17010 */
17014 17011 if (scf_iter_pg_properties(mi, mpg) != 0) {
17015 17012 switch (scf_error()) {
17016 17013 case SCF_ERROR_DELETED:
17017 17014 case SCF_ERROR_CONNECTION_BROKEN:
17018 17015 goto out;
17019 17016
17020 17017 case SCF_ERROR_HANDLE_MISMATCH:
17021 17018 case SCF_ERROR_NOT_BOUND:
17022 17019 case SCF_ERROR_NOT_SET:
17023 17020 default:
17024 17021 bad_error("scf_iter_pg_properties",
17025 17022 scf_error());
17026 17023 }
17027 17024 }
17028 17025
17029 17026 mfstcnt = 0;
17030 17027 mfstmax = MFSTFILE_MAX;
17031 17028 mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
17032 17029 while ((r = scf_iter_next_property(mi, mp)) != 0) {
17033 17030 if (r == -1)
17034 17031 bad_error(gettext("Unable to iterate through "
17035 17032 "manifestfiles properties : %s"),
17036 17033 scf_error());
17037 17034
17038 17035 mpntov = safe_malloc(sizeof (struct mpg_mfile));
17039 17036 mpnbuf = safe_malloc(max_scf_name_len + 1);
17040 17037 mpvbuf = safe_malloc(max_scf_value_len + 1);
17041 17038 mpntov->mpg = mpnbuf;
17042 17039 mpntov->mfile = mpvbuf;
17043 17040 mpntov->access = 1;
17044 17041 if (scf_property_get_name(mp, mpnbuf,
17045 17042 max_scf_name_len + 1) < 0) {
17046 17043 uu_warn(gettext("Unable to get manifest file "
17047 17044 "property : %s\n"),
17048 17045 scf_strerror(scf_error()));
17049 17046
17050 17047 switch (scf_error()) {
17051 17048 case SCF_ERROR_DELETED:
17052 17049 case SCF_ERROR_CONNECTION_BROKEN:
17053 17050 r = scferror2errno(scf_error());
17054 17051 goto out_free;
17055 17052
17056 17053 case SCF_ERROR_HANDLE_MISMATCH:
17057 17054 case SCF_ERROR_NOT_BOUND:
17058 17055 case SCF_ERROR_NOT_SET:
17059 17056 default:
17060 17057 bad_error("scf_iter_pg_properties",
17061 17058 scf_error());
17062 17059 }
17063 17060 }
17064 17061
17065 17062 /*
17066 17063 * The support property is a boolean value that indicates
17067 17064 * if the service is supported for manifest file deletion.
17068 17065 * Currently at this time there is no code that sets this
17069 17066 * value to true. So while we could just let this be caught
17070 17067 * by the support check below, in the future this by be set
17071 17068 * to true and require processing. So for that, go ahead
17072 17069 * and check here, and just return if false. Otherwise,
17073 17070 * fall through expecting that other support checks will
17074 17071 * handle the entries.
17075 17072 */
17076 17073 if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
17077 17074 uint8_t support;
17078 17075
17079 17076 if (scf_property_get_value(mp, mv) != 0 ||
17080 17077 scf_value_get_boolean(mv, &support) != 0) {
17081 17078 uu_warn(gettext("Unable to get the manifest "
17082 17079 "support value: %s\n"),
17083 17080 scf_strerror(scf_error()));
17084 17081
17085 17082 switch (scf_error()) {
17086 17083 case SCF_ERROR_DELETED:
17087 17084 case SCF_ERROR_CONNECTION_BROKEN:
17088 17085 r = scferror2errno(scf_error());
17089 17086 goto out_free;
17090 17087
17091 17088 case SCF_ERROR_HANDLE_MISMATCH:
17092 17089 case SCF_ERROR_NOT_BOUND:
17093 17090 case SCF_ERROR_NOT_SET:
17094 17091 default:
17095 17092 bad_error("scf_iter_pg_properties",
17096 17093 scf_error());
17097 17094 }
17098 17095 }
17099 17096
17100 17097 if (support == B_FALSE)
17101 17098 goto out_free;
17102 17099 }
17103 17100
17104 17101 /*
17105 17102 * Anything with a manifest outside of the supported
17106 17103 * directories, immediately bail out because that makes
17107 17104 * this service non-supported. We don't even want
17108 17105 * to do instance processing in this case because the
17109 17106 * instances could be part of the non-supported manifest.
17110 17107 */
17111 17108 if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
17112 17109 /*
17113 17110 * Manifest is not in /lib/svc, so we need to
17114 17111 * consider the /var/svc case.
17115 17112 */
17116 17113 if (strncmp(mpnbuf, VARSVC_PR,
17117 17114 strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
17118 17115 /*
17119 17116 * Either the manifest is not in /var/svc or
17120 17117 * /var is not yet mounted. We ignore the
17121 17118 * manifest either because it is not in a
17122 17119 * standard location or because we cannot
17123 17120 * currently access the manifest.
17124 17121 */
17125 17122 goto out_free;
17126 17123 }
17127 17124 }
17128 17125
17129 17126 /*
17130 17127 * Get the value to of the manifest file for this entry
17131 17128 * for access verification and instance support
17132 17129 * verification if it still exists.
17133 17130 *
17134 17131 * During Early Manifest Import if the manifest is in
17135 17132 * /var/svc then it may not yet be available for checking
17136 17133 * so we must determine if /var/svc is available. If not
17137 17134 * then defer until Late Manifest Import to cleanup.
17138 17135 */
17139 17136 if (scf_property_get_value(mp, mv) != 0) {
17140 17137 uu_warn(gettext("Unable to get the manifest file "
17141 17138 "value: %s\n"),
17142 17139 scf_strerror(scf_error()));
17143 17140
17144 17141 switch (scf_error()) {
17145 17142 case SCF_ERROR_DELETED:
17146 17143 case SCF_ERROR_CONNECTION_BROKEN:
17147 17144 r = scferror2errno(scf_error());
17148 17145 goto out_free;
17149 17146
17150 17147 case SCF_ERROR_HANDLE_MISMATCH:
17151 17148 case SCF_ERROR_NOT_BOUND:
17152 17149 case SCF_ERROR_NOT_SET:
17153 17150 default:
17154 17151 bad_error("scf_property_get_value",
17155 17152 scf_error());
17156 17153 }
17157 17154 }
17158 17155
17159 17156 if (scf_value_get_astring(mv, mpvbuf,
17160 17157 max_scf_value_len + 1) < 0) {
17161 17158 uu_warn(gettext("Unable to get the manifest "
17162 17159 "file : %s\n"),
17163 17160 scf_strerror(scf_error()));
17164 17161
17165 17162 switch (scf_error()) {
17166 17163 case SCF_ERROR_DELETED:
17167 17164 case SCF_ERROR_CONNECTION_BROKEN:
17168 17165 r = scferror2errno(scf_error());
17169 17166 goto out_free;
17170 17167
17171 17168 case SCF_ERROR_HANDLE_MISMATCH:
17172 17169 case SCF_ERROR_NOT_BOUND:
17173 17170 case SCF_ERROR_NOT_SET:
17174 17171 default:
17175 17172 bad_error("scf_value_get_astring",
17176 17173 scf_error());
17177 17174 }
17178 17175 }
17179 17176
17180 17177 mpvarry[mfstcnt] = mpntov;
17181 17178 mfstcnt++;
17182 17179
17183 17180 /*
17184 17181 * Check for the need to reallocate array
17185 17182 */
17186 17183 if (mfstcnt >= (mfstmax - 1)) {
17187 17184 struct mpg_mfile **newmpvarry;
17188 17185
17189 17186 mfstmax = mfstmax * 2;
17190 17187 newmpvarry = realloc(mpvarry,
17191 17188 sizeof (struct mpg_mfile *) * mfstmax);
17192 17189
17193 17190 if (newmpvarry == NULL)
17194 17191 goto out_free;
17195 17192
17196 17193 mpvarry = newmpvarry;
17197 17194 }
17198 17195
17199 17196 mpvarry[mfstcnt] = NULL;
17200 17197 }
17201 17198
17202 17199 for (index = 0; mpvarry[index]; index++) {
17203 17200 mpntov = mpvarry[index];
17204 17201
17205 17202 /*
17206 17203 * Check to see if the manifestfile is accessable, if so hand
17207 17204 * this service and manifestfile off to be processed for
17208 17205 * instance support.
17209 17206 */
17210 17207 mpnbuf = mpntov->mpg;
17211 17208 mpvbuf = mpntov->mfile;
17212 17209 if (access(mpvbuf, F_OK) != 0) {
17213 17210 mpntov->access = 0;
17214 17211 activity++;
17215 17212 mfstcnt--;
17216 17213 /* Remove the entry from the service */
17217 17214 cur_svc = svc;
17218 17215 pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
17219 17216 mpnbuf);
17220 17217 if (pgpropbuf == NULL)
17221 17218 uu_die(gettext("Out of memory.\n"));
17222 17219
17223 17220 lscf_delprop(pgpropbuf);
17224 17221 cur_svc = NULL;
17225 17222
17226 17223 uu_free(pgpropbuf);
17227 17224 }
17228 17225 }
17229 17226
17230 17227 /*
17231 17228 * If mfstcnt is 0, none of the manifests that supported the service
17232 17229 * existed so remove the service.
17233 17230 */
17234 17231 if (mfstcnt == 0) {
17235 17232 teardown_service(svc, wip->fmri);
17236 17233
17237 17234 goto out_free;
17238 17235 }
17239 17236
17240 17237 if (activity) {
17241 17238 int nosvcsupport = 0;
17242 17239
17243 17240 /*
17244 17241 * If the list of service instances is NULL then
17245 17242 * create the list.
17246 17243 */
17247 17244 instances = create_instance_list(svc, 1);
17248 17245 if (instances == NULL) {
17249 17246 uu_warn(gettext("Unable to create instance list %s\n"),
17250 17247 wip->fmri);
17251 17248 goto out_free;
17252 17249 }
17253 17250
17254 17251 rminstct = uu_list_numnodes(instances);
17255 17252 instct = rminstct;
17256 17253
17257 17254 for (index = 0; mpvarry[index]; index++) {
17258 17255 mpntov = mpvarry[index];
17259 17256 if (mpntov->access == 0)
17260 17257 continue;
17261 17258
17262 17259 mpnbuf = mpntov->mpg;
17263 17260 mpvbuf = mpntov->mfile;
17264 17261 r = check_instance_support(mpvbuf, wip->fmri,
17265 17262 instances);
17266 17263 if (r == -1) {
17267 17264 nosvcsupport++;
17268 17265 } else {
17269 17266 rminstct -= r;
17270 17267 }
17271 17268 }
17272 17269
17273 17270 if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
17274 17271 teardown_service(svc, wip->fmri);
17275 17272
17276 17273 goto out_free;
17277 17274 }
17278 17275 }
17279 17276
17280 17277 /*
17281 17278 * If there are instances left on the instance list, then
17282 17279 * we must remove them.
17283 17280 */
17284 17281 if (instances != NULL && uu_list_numnodes(instances)) {
17285 17282 string_list_t *sp;
17286 17283
17287 17284 insts = uu_list_walk_start(instances, 0);
17288 17285 while ((sp = uu_list_walk_next(insts)) != NULL) {
17289 17286 /*
17290 17287 * Remove the instance from the instances list.
17291 17288 */
17292 17289 safe_printf(gettext("Delete instance %s from "
17293 17290 "service %s\n"), sp->str, wip->fmri);
17294 17291 if (scf_service_get_instance(svc, sp->str,
17295 17292 instance) != SCF_SUCCESS) {
17296 17293 (void) uu_warn("scf_error - %s\n",
17297 17294 scf_strerror(scf_error()));
17298 17295
17299 17296 continue;
17300 17297 }
17301 17298
17302 17299 (void) disable_instance(instance);
17303 17300
17304 17301 (void) lscf_instance_delete(instance, 1);
17305 17302 }
17306 17303 scf_instance_destroy(instance);
17307 17304 uu_list_walk_end(insts);
17308 17305 }
17309 17306
17310 17307 out_free:
17311 17308 if (mpvarry) {
17312 17309 struct mpg_mfile *fmpntov;
17313 17310
17314 17311 for (index = 0; mpvarry[index]; index++) {
17315 17312 fmpntov = mpvarry[index];
17316 17313 if (fmpntov->mpg == mpnbuf)
17317 17314 mpnbuf = NULL;
17318 17315 free(fmpntov->mpg);
17319 17316
17320 17317 if (fmpntov->mfile == mpvbuf)
17321 17318 mpvbuf = NULL;
17322 17319 free(fmpntov->mfile);
17323 17320
17324 17321 if (fmpntov == mpntov)
17325 17322 mpntov = NULL;
17326 17323 free(fmpntov);
17327 17324 }
17328 17325 if (mpnbuf)
17329 17326 free(mpnbuf);
17330 17327 if (mpvbuf)
17331 17328 free(mpvbuf);
17332 17329 if (mpntov)
17333 17330 free(mpntov);
17334 17331
17335 17332 free(mpvarry);
17336 17333 }
17337 17334 out:
17338 17335 scf_pg_destroy(mpg);
17339 17336 scf_property_destroy(mp);
17340 17337 scf_iter_destroy(mi);
17341 17338 scf_value_destroy(mv);
17342 17339
17343 17340 return (0);
17344 17341 }
17345 17342
17346 17343 /*
17347 17344 * Take the service and search for the manifestfiles property
17348 17345 * in each of the property groups. If the manifest file
17349 17346 * associated with the property does not exist then remove
17350 17347 * the property group.
17351 17348 */
17352 17349 int
17353 17350 lscf_hash_cleanup()
17354 17351 {
17355 17352 scf_service_t *svc;
17356 17353 scf_scope_t *scope;
17357 17354 scf_propertygroup_t *pg;
17358 17355 scf_property_t *prop;
17359 17356 scf_value_t *val;
17360 17357 scf_iter_t *iter;
17361 17358 char *pgname = NULL;
17362 17359 char *mfile = NULL;
17363 17360 int r;
17364 17361
17365 17362 svc = scf_service_create(g_hndl);
17366 17363 scope = scf_scope_create(g_hndl);
17367 17364 pg = scf_pg_create(g_hndl);
17368 17365 prop = scf_property_create(g_hndl);
17369 17366 val = scf_value_create(g_hndl);
17370 17367 iter = scf_iter_create(g_hndl);
17371 17368 if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
17372 17369 svc == NULL || scope == NULL) {
17373 17370 uu_warn(gettext("Unable to create a property group, or "
17374 17371 "property\n"));
17375 17372 uu_warn("%s\n", pg == NULL ? "pg is NULL" :
17376 17373 "pg is not NULL");
17377 17374 uu_warn("%s\n", prop == NULL ? "prop is NULL" :
17378 17375 "prop is not NULL");
17379 17376 uu_warn("%s\n", val == NULL ? "val is NULL" :
17380 17377 "val is not NULL");
17381 17378 uu_warn("%s\n", iter == NULL ? "iter is NULL" :
17382 17379 "iter is not NULL");
17383 17380 uu_warn("%s\n", svc == NULL ? "svc is NULL" :
17384 17381 "svc is not NULL");
17385 17382 uu_warn("%s\n", scope == NULL ? "scope is NULL" :
17386 17383 "scope is not NULL");
17387 17384 uu_warn(gettext("scf error is : %s\n"),
17388 17385 scf_strerror(scf_error()));
17389 17386 scfdie();
17390 17387 }
17391 17388
17392 17389 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
17393 17390 switch (scf_error()) {
17394 17391 case SCF_ERROR_CONNECTION_BROKEN:
17395 17392 case SCF_ERROR_NOT_FOUND:
17396 17393 goto out;
17397 17394
17398 17395 case SCF_ERROR_HANDLE_MISMATCH:
17399 17396 case SCF_ERROR_NOT_BOUND:
17400 17397 case SCF_ERROR_INVALID_ARGUMENT:
17401 17398 default:
17402 17399 bad_error("scf_handle_get_scope", scf_error());
17403 17400 }
17404 17401 }
17405 17402
17406 17403 if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
17407 17404 uu_warn(gettext("Unable to process the hash service, %s\n"),
17408 17405 HASH_SVC);
17409 17406 goto out;
17410 17407 }
17411 17408
17412 17409 pgname = safe_malloc(max_scf_name_len + 1);
17413 17410 mfile = safe_malloc(max_scf_value_len + 1);
17414 17411
17415 17412 if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
17416 17413 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17417 17414 scf_strerror(scf_error()));
17418 17415 goto out;
17419 17416 }
17420 17417
17421 17418 while ((r = scf_iter_next_pg(iter, pg)) != 0) {
17422 17419 if (r == -1)
17423 17420 goto out;
17424 17421
17425 17422 if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
17426 17423 switch (scf_error()) {
17427 17424 case SCF_ERROR_DELETED:
17428 17425 return (ENODEV);
17429 17426
17430 17427 case SCF_ERROR_CONNECTION_BROKEN:
17431 17428 return (ECONNABORTED);
17432 17429
17433 17430 case SCF_ERROR_NOT_SET:
17434 17431 case SCF_ERROR_NOT_BOUND:
17435 17432 default:
17436 17433 bad_error("scf_pg_get_name", scf_error());
17437 17434 }
17438 17435 }
17439 17436 if (IGNORE_VAR) {
17440 17437 if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
17441 17438 continue;
17442 17439 }
17443 17440
17444 17441 /*
17445 17442 * If unable to get the property continue as this is an
17446 17443 * entry that has no location to check against.
17447 17444 */
17448 17445 if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
17449 17446 continue;
17450 17447 }
17451 17448
17452 17449 if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
17453 17450 uu_warn(gettext("Unable to get value from %s\n"),
17454 17451 pgname);
17455 17452
17456 17453 switch (scf_error()) {
17457 17454 case SCF_ERROR_DELETED:
17458 17455 case SCF_ERROR_CONSTRAINT_VIOLATED:
17459 17456 case SCF_ERROR_NOT_FOUND:
17460 17457 case SCF_ERROR_NOT_SET:
17461 17458 continue;
17462 17459
17463 17460 case SCF_ERROR_CONNECTION_BROKEN:
17464 17461 r = scferror2errno(scf_error());
17465 17462 goto out;
17466 17463
17467 17464 case SCF_ERROR_HANDLE_MISMATCH:
17468 17465 case SCF_ERROR_NOT_BOUND:
17469 17466 default:
17470 17467 bad_error("scf_property_get_value",
17471 17468 scf_error());
17472 17469 }
17473 17470 }
17474 17471
17475 17472 if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
17476 17473 == -1) {
17477 17474 uu_warn(gettext("Unable to get astring from %s : %s\n"),
17478 17475 pgname, scf_strerror(scf_error()));
17479 17476
17480 17477 switch (scf_error()) {
17481 17478 case SCF_ERROR_NOT_SET:
17482 17479 case SCF_ERROR_TYPE_MISMATCH:
17483 17480 continue;
17484 17481
17485 17482 default:
17486 17483 bad_error("scf_value_get_astring", scf_error());
17487 17484 }
17488 17485 }
17489 17486
17490 17487 if (access(mfile, F_OK) == 0)
17491 17488 continue;
17492 17489
17493 17490 (void) scf_pg_delete(pg);
17494 17491 }
17495 17492
17496 17493 out:
17497 17494 scf_scope_destroy(scope);
17498 17495 scf_service_destroy(svc);
17499 17496 scf_pg_destroy(pg);
17500 17497 scf_property_destroy(prop);
17501 17498 scf_value_destroy(val);
17502 17499 scf_iter_destroy(iter);
17503 17500 free(pgname);
17504 17501 free(mfile);
17505 17502
17506 17503 return (0);
17507 17504 }
17508 17505
17509 17506 #ifndef NATIVE_BUILD
17510 17507 /* ARGSUSED */
17511 17508 CPL_MATCH_FN(complete_select)
17512 17509 {
17513 17510 const char *arg0, *arg1, *arg1end;
17514 17511 int word_start, err = 0, r;
17515 17512 size_t len;
17516 17513 char *buf;
17517 17514
17518 17515 lscf_prep_hndl();
17519 17516
17520 17517 arg0 = line + strspn(line, " \t");
17521 17518 assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
17522 17519
17523 17520 arg1 = arg0 + sizeof ("select") - 1;
17524 17521 arg1 += strspn(arg1, " \t");
17525 17522 word_start = arg1 - line;
17526 17523
17527 17524 arg1end = arg1 + strcspn(arg1, " \t");
17528 17525 if (arg1end < line + word_end)
17529 17526 return (0);
17530 17527
17531 17528 len = line + word_end - arg1;
17532 17529
17533 17530 buf = safe_malloc(max_scf_name_len + 1);
17534 17531
17535 17532 if (cur_snap != NULL) {
17536 17533 return (0);
17537 17534 } else if (cur_inst != NULL) {
17538 17535 return (0);
17539 17536 } else if (cur_svc != NULL) {
17540 17537 scf_instance_t *inst;
17541 17538 scf_iter_t *iter;
17542 17539
17543 17540 if ((inst = scf_instance_create(g_hndl)) == NULL ||
17544 17541 (iter = scf_iter_create(g_hndl)) == NULL)
17545 17542 scfdie();
17546 17543
17547 17544 if (scf_iter_service_instances(iter, cur_svc) != 0)
17548 17545 scfdie();
17549 17546
17550 17547 for (;;) {
17551 17548 r = scf_iter_next_instance(iter, inst);
17552 17549 if (r == 0)
17553 17550 break;
17554 17551 if (r != 1)
17555 17552 scfdie();
17556 17553
17557 17554 if (scf_instance_get_name(inst, buf,
17558 17555 max_scf_name_len + 1) < 0)
17559 17556 scfdie();
17560 17557
17561 17558 if (strncmp(buf, arg1, len) == 0) {
17562 17559 err = cpl_add_completion(cpl, line, word_start,
17563 17560 word_end, buf + len, "", " ");
17564 17561 if (err != 0)
17565 17562 break;
17566 17563 }
17567 17564 }
17568 17565
17569 17566 scf_iter_destroy(iter);
17570 17567 scf_instance_destroy(inst);
17571 17568
17572 17569 return (err);
17573 17570 } else {
17574 17571 scf_service_t *svc;
17575 17572 scf_iter_t *iter;
17576 17573
17577 17574 assert(cur_scope != NULL);
17578 17575
17579 17576 if ((svc = scf_service_create(g_hndl)) == NULL ||
17580 17577 (iter = scf_iter_create(g_hndl)) == NULL)
17581 17578 scfdie();
17582 17579
17583 17580 if (scf_iter_scope_services(iter, cur_scope) != 0)
17584 17581 scfdie();
17585 17582
17586 17583 for (;;) {
17587 17584 r = scf_iter_next_service(iter, svc);
17588 17585 if (r == 0)
17589 17586 break;
17590 17587 if (r != 1)
17591 17588 scfdie();
17592 17589
17593 17590 if (scf_service_get_name(svc, buf,
17594 17591 max_scf_name_len + 1) < 0)
17595 17592 scfdie();
17596 17593
17597 17594 if (strncmp(buf, arg1, len) == 0) {
17598 17595 err = cpl_add_completion(cpl, line, word_start,
17599 17596 word_end, buf + len, "", " ");
17600 17597 if (err != 0)
17601 17598 break;
17602 17599 }
17603 17600 }
17604 17601
17605 17602 scf_iter_destroy(iter);
17606 17603 scf_service_destroy(svc);
17607 17604
17608 17605 return (err);
17609 17606 }
17610 17607 }
17611 17608
17612 17609 /* ARGSUSED */
17613 17610 CPL_MATCH_FN(complete_command)
17614 17611 {
17615 17612 uint32_t scope = 0;
17616 17613
17617 17614 if (cur_snap != NULL)
17618 17615 scope = CS_SNAP;
17619 17616 else if (cur_inst != NULL)
17620 17617 scope = CS_INST;
17621 17618 else if (cur_svc != NULL)
17622 17619 scope = CS_SVC;
17623 17620 else
17624 17621 scope = CS_SCOPE;
17625 17622
17626 17623 return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
17627 17624 }
17628 17625 #endif /* NATIVE_BUILD */
↓ open down ↓ |
13644 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX