Print this page
3315 svccfg export -a drops values in PG "general"
Reviewed by: Eric Schrock <eric.schrock@delphix.com>
Reviewed by: Dan McDonald <danmcd@nexenta.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
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 2012 Milan Jurik. All rights reserved.
25 25 */
26 26
27 27
28 28 #include <alloca.h>
29 29 #include <assert.h>
30 30 #include <ctype.h>
31 31 #include <door.h>
32 32 #include <errno.h>
33 33 #include <fcntl.h>
34 34 #include <fnmatch.h>
35 35 #include <inttypes.h>
36 36 #include <libintl.h>
37 37 #include <libnvpair.h>
38 38 #include <libscf.h>
39 39 #include <libscf_priv.h>
40 40 #include <libtecla.h>
41 41 #include <libuutil.h>
42 42 #include <limits.h>
43 43 #include <locale.h>
44 44 #include <stdarg.h>
45 45 #include <string.h>
46 46 #include <strings.h>
47 47 #include <unistd.h>
48 48 #include <wait.h>
49 49 #include <poll.h>
50 50
51 51 #include <libxml/tree.h>
52 52
53 53 #include <sys/param.h>
54 54
55 55 #include <sys/stat.h>
56 56 #include <sys/mman.h>
57 57
58 58 #include "svccfg.h"
59 59 #include "notify_params.h"
60 60 #include "manifest_hash.h"
61 61 #include "manifest_find.h"
62 62
63 63 /* The colon namespaces in each entity (each followed by a newline). */
64 64 #define COLON_NAMESPACES ":properties\n"
65 65
66 66 #define TEMP_FILE_PATTERN "/tmp/svccfg-XXXXXX"
67 67
68 68 /* These are characters which the lexer requires to be in double-quotes. */
69 69 #define CHARS_TO_QUOTE " \t\n\\>=\"()"
70 70
71 71 #define HASH_SIZE 16
72 72 #define HASH_PG_TYPE "framework"
73 73 #define HASH_PG_FLAGS 0
74 74 #define HASH_PROP "md5sum"
75 75
76 76 /*
77 77 * Indentation used in the output of the describe subcommand.
78 78 */
79 79 #define TMPL_VALUE_INDENT " "
80 80 #define TMPL_INDENT " "
81 81 #define TMPL_INDENT_2X " "
82 82 #define TMPL_CHOICE_INDENT " "
83 83
84 84 /*
85 85 * Directory locations for manifests
86 86 */
87 87 #define VARSVC_DIR "/var/svc/manifest"
88 88 #define LIBSVC_DIR "/lib/svc/manifest"
89 89 #define VARSVC_PR "var_svc_manifest"
90 90 #define LIBSVC_PR "lib_svc_manifest"
91 91 #define MFSTFILEPR "manifestfile"
92 92
93 93 #define SUPPORTPROP "support"
94 94
95 95 #define MFSTHISTFILE "/lib/svc/share/mfsthistory"
96 96
97 97 #define MFSTFILE_MAX 16
98 98
99 99 /*
100 100 * These are the classes of elements which may appear as children of service
101 101 * or instance elements in XML manifests.
102 102 */
103 103 struct entity_elts {
104 104 xmlNodePtr create_default_instance;
105 105 xmlNodePtr single_instance;
106 106 xmlNodePtr restarter;
107 107 xmlNodePtr dependencies;
108 108 xmlNodePtr dependents;
109 109 xmlNodePtr method_context;
110 110 xmlNodePtr exec_methods;
111 111 xmlNodePtr notify_params;
112 112 xmlNodePtr property_groups;
113 113 xmlNodePtr instances;
114 114 xmlNodePtr stability;
115 115 xmlNodePtr template;
116 116 };
117 117
118 118 /*
119 119 * Likewise for property_group elements.
120 120 */
121 121 struct pg_elts {
122 122 xmlNodePtr stability;
123 123 xmlNodePtr propvals;
124 124 xmlNodePtr properties;
125 125 };
126 126
127 127 /*
128 128 * Likewise for template elements.
129 129 */
130 130 struct template_elts {
131 131 xmlNodePtr common_name;
132 132 xmlNodePtr description;
133 133 xmlNodePtr documentation;
134 134 };
135 135
136 136 /*
137 137 * Likewise for type (for notification parameters) elements.
138 138 */
139 139 struct params_elts {
140 140 xmlNodePtr paramval;
141 141 xmlNodePtr parameter;
142 142 };
143 143
144 144 /*
145 145 * This structure is for snaplevel lists. They are convenient because libscf
146 146 * only allows traversing snaplevels in one direction.
147 147 */
148 148 struct snaplevel {
149 149 uu_list_node_t list_node;
150 150 scf_snaplevel_t *sl;
151 151 };
152 152
153 153 /*
154 154 * This is used for communication between lscf_service_export and
155 155 * export_callback.
156 156 */
157 157 struct export_args {
158 158 const char *filename;
159 159 int flags;
160 160 };
161 161
162 162 /*
163 163 * The service_manifest structure is used by the upgrade process
164 164 * to create a list of service to manifest linkages from the manifests
165 165 * in a set of given directories.
166 166 */
167 167 typedef struct service_manifest {
168 168 const char *servicename;
169 169 uu_list_t *mfstlist;
170 170 size_t mfstlist_sz;
171 171
172 172 uu_avl_node_t svcmfst_node;
173 173 } service_manifest_t;
174 174
175 175 /*
176 176 * Structure to track the manifest file property group
177 177 * and the manifest file associated with that property
178 178 * group. Also, a flag to keep the access once it has
179 179 * been checked.
180 180 */
181 181 struct mpg_mfile {
182 182 char *mpg;
183 183 char *mfile;
184 184 int access;
185 185 };
186 186
187 187 const char * const scf_pg_general = SCF_PG_GENERAL;
188 188 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
189 189 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
190 190 const char * const scf_property_external = "external";
191 191
192 192 const char * const snap_initial = "initial";
193 193 const char * const snap_lastimport = "last-import";
194 194 const char * const snap_previous = "previous";
195 195 const char * const snap_running = "running";
196 196
197 197 scf_handle_t *g_hndl = NULL; /* only valid after lscf_prep_hndl() */
198 198
199 199 ssize_t max_scf_fmri_len;
200 200 ssize_t max_scf_name_len;
201 201 ssize_t max_scf_pg_type_len;
202 202 ssize_t max_scf_value_len;
203 203 static size_t max_scf_len;
204 204
205 205 static scf_scope_t *cur_scope;
206 206 static scf_service_t *cur_svc = NULL;
207 207 static scf_instance_t *cur_inst = NULL;
208 208 static scf_snapshot_t *cur_snap = NULL;
209 209 static scf_snaplevel_t *cur_level = NULL;
210 210
211 211 static uu_list_pool_t *snaplevel_pool;
212 212 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
213 213 static uu_list_t *cur_levels;
214 214 static struct snaplevel *cur_elt; /* cur_elt->sl == cur_level */
215 215
216 216 static FILE *tempfile = NULL;
217 217 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
218 218
219 219 static const char *emsg_entity_not_selected;
220 220 static const char *emsg_permission_denied;
221 221 static const char *emsg_create_xml;
222 222 static const char *emsg_cant_modify_snapshots;
223 223 static const char *emsg_invalid_for_snapshot;
224 224 static const char *emsg_read_only;
225 225 static const char *emsg_deleted;
226 226 static const char *emsg_invalid_pg_name;
227 227 static const char *emsg_invalid_prop_name;
228 228 static const char *emsg_no_such_pg;
229 229 static const char *emsg_fmri_invalid_pg_name;
230 230 static const char *emsg_fmri_invalid_pg_name_type;
231 231 static const char *emsg_pg_added;
232 232 static const char *emsg_pg_changed;
233 233 static const char *emsg_pg_deleted;
234 234 static const char *emsg_pg_mod_perm;
235 235 static const char *emsg_pg_add_perm;
236 236 static const char *emsg_pg_del_perm;
237 237 static const char *emsg_snap_perm;
238 238 static const char *emsg_dpt_dangling;
239 239 static const char *emsg_dpt_no_dep;
240 240
241 241 static int li_only = 0;
242 242 static int no_refresh = 0;
243 243
244 244 /* import globals, to minimize allocations */
245 245 static scf_scope_t *imp_scope = NULL;
246 246 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
247 247 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
248 248 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
249 249 static scf_snapshot_t *imp_rsnap = NULL;
250 250 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
251 251 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
252 252 static scf_property_t *imp_prop = NULL;
253 253 static scf_iter_t *imp_iter = NULL;
254 254 static scf_iter_t *imp_rpg_iter = NULL;
255 255 static scf_iter_t *imp_up_iter = NULL;
256 256 static scf_transaction_t *imp_tx = NULL; /* always reset this */
257 257 static char *imp_str = NULL;
258 258 static size_t imp_str_sz;
259 259 static char *imp_tsname = NULL;
260 260 static char *imp_fe1 = NULL; /* for fmri_equal() */
261 261 static char *imp_fe2 = NULL;
262 262 static uu_list_t *imp_deleted_dpts = NULL; /* pgroup_t's to refresh */
263 263
264 264 /* upgrade_dependents() globals */
265 265 static scf_instance_t *ud_inst = NULL;
266 266 static scf_snaplevel_t *ud_snpl = NULL;
267 267 static scf_propertygroup_t *ud_pg = NULL;
268 268 static scf_propertygroup_t *ud_cur_depts_pg = NULL;
269 269 static scf_propertygroup_t *ud_run_dpts_pg = NULL;
270 270 static int ud_run_dpts_pg_set = 0;
271 271 static scf_property_t *ud_prop = NULL;
272 272 static scf_property_t *ud_dpt_prop = NULL;
273 273 static scf_value_t *ud_val = NULL;
274 274 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
275 275 static scf_transaction_t *ud_tx = NULL;
276 276 static char *ud_ctarg = NULL;
277 277 static char *ud_oldtarg = NULL;
278 278 static char *ud_name = NULL;
279 279
280 280 /* export globals */
281 281 static scf_instance_t *exp_inst;
282 282 static scf_propertygroup_t *exp_pg;
283 283 static scf_property_t *exp_prop;
284 284 static scf_value_t *exp_val;
285 285 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
286 286 static char *exp_str;
287 287 static size_t exp_str_sz;
288 288
289 289 /* cleanup globals */
290 290 static uu_avl_pool_t *service_manifest_pool = NULL;
291 291 static uu_avl_t *service_manifest_tree = NULL;
292 292
293 293 static void scfdie_lineno(int lineno) __NORETURN;
294 294
295 295 static char *start_method_names[] = {
296 296 "start",
297 297 "inetd_start",
298 298 NULL
299 299 };
300 300
301 301 static struct uri_scheme {
302 302 const char *scheme;
303 303 const char *protocol;
304 304 } uri_scheme[] = {
305 305 { "mailto", "smtp" },
306 306 { "snmp", "snmp" },
307 307 { "syslog", "syslog" },
308 308 { NULL, NULL }
309 309 };
310 310 #define URI_SCHEME_NUM ((sizeof (uri_scheme) / \
311 311 sizeof (struct uri_scheme)) - 1)
312 312
313 313 static int
314 314 check_uri_scheme(const char *scheme)
315 315 {
316 316 int i;
317 317
318 318 for (i = 0; uri_scheme[i].scheme != NULL; ++i) {
319 319 if (strcmp(scheme, uri_scheme[i].scheme) == 0)
320 320 return (i);
321 321 }
322 322
323 323 return (-1);
324 324 }
325 325
326 326 static int
327 327 check_uri_protocol(const char *p)
328 328 {
329 329 int i;
330 330
331 331 for (i = 0; uri_scheme[i].protocol != NULL; ++i) {
332 332 if (strcmp(p, uri_scheme[i].protocol) == 0)
333 333 return (i);
334 334 }
335 335
336 336 return (-1);
337 337 }
338 338
339 339 /*
340 340 * For unexpected libscf errors.
341 341 */
342 342 #ifdef NDEBUG
343 343
344 344 static void scfdie(void) __NORETURN;
345 345
346 346 static void
347 347 scfdie(void)
348 348 {
349 349 scf_error_t err = scf_error();
350 350
351 351 if (err == SCF_ERROR_CONNECTION_BROKEN)
352 352 uu_die(gettext("Repository connection broken. Exiting.\n"));
353 353
354 354 uu_die(gettext("Unexpected fatal libscf error: %s. Exiting.\n"),
355 355 scf_strerror(err));
356 356 }
357 357
358 358 #else
359 359
360 360 #define scfdie() scfdie_lineno(__LINE__)
361 361
362 362 static void
363 363 scfdie_lineno(int lineno)
364 364 {
365 365 scf_error_t err = scf_error();
366 366
367 367 if (err == SCF_ERROR_CONNECTION_BROKEN)
368 368 uu_die(gettext("Repository connection broken. Exiting.\n"));
369 369
370 370 uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
371 371 ": %s.\n"), lineno, scf_strerror(err));
372 372 }
373 373
374 374 #endif
375 375
376 376 static void
377 377 scfwarn(void)
378 378 {
379 379 warn(gettext("Unexpected libscf error: %s.\n"),
380 380 scf_strerror(scf_error()));
381 381 }
382 382
383 383 /*
384 384 * Clear a field of a structure.
385 385 */
386 386 static int
387 387 clear_int(void *a, void *b)
388 388 {
389 389 /* LINTED */
390 390 *(int *)((char *)a + (size_t)b) = 0;
391 391
392 392 return (UU_WALK_NEXT);
393 393 }
394 394
395 395 static int
396 396 scferror2errno(scf_error_t err)
397 397 {
398 398 switch (err) {
399 399 case SCF_ERROR_BACKEND_ACCESS:
400 400 return (EACCES);
401 401
402 402 case SCF_ERROR_BACKEND_READONLY:
403 403 return (EROFS);
404 404
405 405 case SCF_ERROR_CONNECTION_BROKEN:
406 406 return (ECONNABORTED);
407 407
408 408 case SCF_ERROR_CONSTRAINT_VIOLATED:
409 409 case SCF_ERROR_INVALID_ARGUMENT:
410 410 return (EINVAL);
411 411
412 412 case SCF_ERROR_DELETED:
413 413 return (ECANCELED);
414 414
415 415 case SCF_ERROR_EXISTS:
416 416 return (EEXIST);
417 417
418 418 case SCF_ERROR_NO_MEMORY:
419 419 return (ENOMEM);
420 420
421 421 case SCF_ERROR_NO_RESOURCES:
422 422 return (ENOSPC);
423 423
424 424 case SCF_ERROR_NOT_FOUND:
425 425 return (ENOENT);
426 426
427 427 case SCF_ERROR_PERMISSION_DENIED:
428 428 return (EPERM);
429 429
430 430 default:
431 431 #ifndef NDEBUG
432 432 (void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
433 433 __FILE__, __LINE__, err);
434 434 #else
435 435 (void) fprintf(stderr, "Unknown libscf error %d.\n", err);
436 436 #endif
437 437 abort();
438 438 /* NOTREACHED */
439 439 }
440 440 }
441 441
442 442 static int
443 443 entity_get_pg(void *ent, int issvc, const char *name,
444 444 scf_propertygroup_t *pg)
445 445 {
446 446 if (issvc)
447 447 return (scf_service_get_pg(ent, name, pg));
448 448 else
449 449 return (scf_instance_get_pg(ent, name, pg));
450 450 }
451 451
452 452 static void
453 453 entity_destroy(void *ent, int issvc)
454 454 {
455 455 if (issvc)
456 456 scf_service_destroy(ent);
457 457 else
458 458 scf_instance_destroy(ent);
459 459 }
460 460
461 461 static int
462 462 get_pg(const char *pg_name, scf_propertygroup_t *pg)
463 463 {
464 464 int ret;
465 465
466 466 if (cur_level != NULL)
467 467 ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
468 468 else if (cur_inst != NULL)
469 469 ret = scf_instance_get_pg(cur_inst, pg_name, pg);
470 470 else
471 471 ret = scf_service_get_pg(cur_svc, pg_name, pg);
472 472
473 473 return (ret);
474 474 }
475 475
476 476 /*
477 477 * Find a snaplevel in a snapshot. If get_svc is true, find the service
478 478 * snaplevel. Otherwise find the instance snaplevel.
479 479 *
480 480 * Returns
481 481 * 0 - success
482 482 * ECONNABORTED - repository connection broken
483 483 * ECANCELED - instance containing snap was deleted
484 484 * ENOENT - snap has no snaplevels
485 485 * - requested snaplevel not found
486 486 */
487 487 static int
488 488 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
489 489 {
490 490 if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
491 491 switch (scf_error()) {
492 492 case SCF_ERROR_CONNECTION_BROKEN:
493 493 case SCF_ERROR_DELETED:
494 494 case SCF_ERROR_NOT_FOUND:
495 495 return (scferror2errno(scf_error()));
496 496
497 497 case SCF_ERROR_HANDLE_MISMATCH:
498 498 case SCF_ERROR_NOT_BOUND:
499 499 case SCF_ERROR_NOT_SET:
500 500 default:
501 501 bad_error("scf_snapshot_get_base_snaplevel",
502 502 scf_error());
503 503 }
504 504 }
505 505
506 506 for (;;) {
507 507 ssize_t ssz;
508 508
509 509 ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
510 510 if (ssz >= 0) {
511 511 if (!get_svc)
512 512 return (0);
513 513 } else {
514 514 switch (scf_error()) {
515 515 case SCF_ERROR_CONSTRAINT_VIOLATED:
516 516 if (get_svc)
517 517 return (0);
518 518 break;
519 519
520 520 case SCF_ERROR_DELETED:
521 521 case SCF_ERROR_CONNECTION_BROKEN:
522 522 return (scferror2errno(scf_error()));
523 523
524 524 case SCF_ERROR_NOT_SET:
525 525 case SCF_ERROR_NOT_BOUND:
526 526 default:
527 527 bad_error("scf_snaplevel_get_instance_name",
528 528 scf_error());
529 529 }
530 530 }
531 531
532 532 if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
533 533 switch (scf_error()) {
534 534 case SCF_ERROR_NOT_FOUND:
535 535 case SCF_ERROR_CONNECTION_BROKEN:
536 536 case SCF_ERROR_DELETED:
537 537 return (scferror2errno(scf_error()));
538 538
539 539 case SCF_ERROR_HANDLE_MISMATCH:
540 540 case SCF_ERROR_NOT_BOUND:
541 541 case SCF_ERROR_NOT_SET:
542 542 case SCF_ERROR_INVALID_ARGUMENT:
543 543 default:
544 544 bad_error("scf_snaplevel_get_next_snaplevel",
545 545 scf_error());
546 546 }
547 547 }
548 548 }
549 549 }
550 550
551 551 /*
552 552 * If issvc is 0, take ent to be a pointer to an scf_instance_t. If it has
553 553 * a running snapshot, and that snapshot has an instance snaplevel, set pg to
554 554 * the property group named name in it. If it doesn't have a running
555 555 * snapshot, set pg to the instance's current property group named name.
556 556 *
557 557 * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
558 558 * its instances. If one has a running snapshot with a service snaplevel, set
559 559 * pg to the property group named name in it. If no such snaplevel could be
560 560 * found, set pg to the service's current property group named name.
561 561 *
562 562 * iter, inst, snap, and snpl are required scratch objects.
563 563 *
564 564 * Returns
565 565 * 0 - success
566 566 * ECONNABORTED - repository connection broken
567 567 * ECANCELED - ent was deleted
568 568 * ENOENT - no such property group
569 569 * EINVAL - name is an invalid property group name
570 570 * EBADF - found running snapshot is missing a snaplevel
571 571 */
572 572 static int
573 573 entity_get_running_pg(void *ent, int issvc, const char *name,
574 574 scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
575 575 scf_snapshot_t *snap, scf_snaplevel_t *snpl)
576 576 {
577 577 int r;
578 578
579 579 if (issvc) {
580 580 /* Search for an instance with a running snapshot. */
581 581 if (scf_iter_service_instances(iter, ent) != 0) {
582 582 switch (scf_error()) {
583 583 case SCF_ERROR_DELETED:
584 584 case SCF_ERROR_CONNECTION_BROKEN:
585 585 return (scferror2errno(scf_error()));
586 586
587 587 case SCF_ERROR_NOT_SET:
588 588 case SCF_ERROR_NOT_BOUND:
589 589 case SCF_ERROR_HANDLE_MISMATCH:
590 590 default:
591 591 bad_error("scf_iter_service_instances",
592 592 scf_error());
593 593 }
594 594 }
595 595
596 596 for (;;) {
597 597 r = scf_iter_next_instance(iter, inst);
598 598 if (r == 0) {
599 599 if (scf_service_get_pg(ent, name, pg) == 0)
600 600 return (0);
601 601
602 602 switch (scf_error()) {
603 603 case SCF_ERROR_DELETED:
604 604 case SCF_ERROR_NOT_FOUND:
605 605 case SCF_ERROR_INVALID_ARGUMENT:
606 606 case SCF_ERROR_CONNECTION_BROKEN:
607 607 return (scferror2errno(scf_error()));
608 608
609 609 case SCF_ERROR_NOT_BOUND:
610 610 case SCF_ERROR_HANDLE_MISMATCH:
611 611 case SCF_ERROR_NOT_SET:
612 612 default:
613 613 bad_error("scf_service_get_pg",
614 614 scf_error());
615 615 }
616 616 }
617 617 if (r != 1) {
618 618 switch (scf_error()) {
619 619 case SCF_ERROR_DELETED:
620 620 case SCF_ERROR_CONNECTION_BROKEN:
621 621 return (scferror2errno(scf_error()));
622 622
623 623 case SCF_ERROR_INVALID_ARGUMENT:
624 624 case SCF_ERROR_NOT_SET:
625 625 case SCF_ERROR_NOT_BOUND:
626 626 case SCF_ERROR_HANDLE_MISMATCH:
627 627 default:
628 628 bad_error("scf_iter_next_instance",
629 629 scf_error());
630 630 }
631 631 }
632 632
633 633 if (scf_instance_get_snapshot(inst, snap_running,
634 634 snap) == 0)
635 635 break;
636 636
637 637 switch (scf_error()) {
638 638 case SCF_ERROR_NOT_FOUND:
639 639 case SCF_ERROR_DELETED:
640 640 continue;
641 641
642 642 case SCF_ERROR_CONNECTION_BROKEN:
643 643 return (ECONNABORTED);
644 644
645 645 case SCF_ERROR_HANDLE_MISMATCH:
646 646 case SCF_ERROR_INVALID_ARGUMENT:
647 647 case SCF_ERROR_NOT_SET:
648 648 case SCF_ERROR_NOT_BOUND:
649 649 default:
650 650 bad_error("scf_instance_get_snapshot",
651 651 scf_error());
652 652 }
653 653 }
654 654 } else {
655 655 if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
656 656 switch (scf_error()) {
657 657 case SCF_ERROR_NOT_FOUND:
658 658 break;
659 659
660 660 case SCF_ERROR_DELETED:
661 661 case SCF_ERROR_CONNECTION_BROKEN:
662 662 return (scferror2errno(scf_error()));
663 663
664 664 case SCF_ERROR_NOT_BOUND:
665 665 case SCF_ERROR_HANDLE_MISMATCH:
666 666 case SCF_ERROR_INVALID_ARGUMENT:
667 667 case SCF_ERROR_NOT_SET:
668 668 default:
669 669 bad_error("scf_instance_get_snapshot",
670 670 scf_error());
671 671 }
672 672
673 673 if (scf_instance_get_pg(ent, name, pg) == 0)
674 674 return (0);
675 675
676 676 switch (scf_error()) {
677 677 case SCF_ERROR_DELETED:
678 678 case SCF_ERROR_NOT_FOUND:
679 679 case SCF_ERROR_INVALID_ARGUMENT:
680 680 case SCF_ERROR_CONNECTION_BROKEN:
681 681 return (scferror2errno(scf_error()));
682 682
683 683 case SCF_ERROR_NOT_BOUND:
684 684 case SCF_ERROR_HANDLE_MISMATCH:
685 685 case SCF_ERROR_NOT_SET:
686 686 default:
687 687 bad_error("scf_instance_get_pg", scf_error());
688 688 }
689 689 }
690 690 }
691 691
692 692 r = get_snaplevel(snap, issvc, snpl);
693 693 switch (r) {
694 694 case 0:
695 695 break;
696 696
697 697 case ECONNABORTED:
698 698 case ECANCELED:
699 699 return (r);
700 700
701 701 case ENOENT:
702 702 return (EBADF);
703 703
704 704 default:
705 705 bad_error("get_snaplevel", r);
706 706 }
707 707
708 708 if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
709 709 return (0);
710 710
711 711 switch (scf_error()) {
712 712 case SCF_ERROR_DELETED:
713 713 case SCF_ERROR_INVALID_ARGUMENT:
714 714 case SCF_ERROR_CONNECTION_BROKEN:
715 715 case SCF_ERROR_NOT_FOUND:
716 716 return (scferror2errno(scf_error()));
717 717
718 718 case SCF_ERROR_NOT_BOUND:
719 719 case SCF_ERROR_HANDLE_MISMATCH:
720 720 case SCF_ERROR_NOT_SET:
721 721 default:
722 722 bad_error("scf_snaplevel_get_pg", scf_error());
723 723 /* NOTREACHED */
724 724 }
725 725 }
726 726
727 727 /*
728 728 * To be registered with atexit().
729 729 */
730 730 static void
731 731 remove_tempfile(void)
732 732 {
733 733 int ret;
734 734
735 735 if (tempfile != NULL) {
736 736 if (fclose(tempfile) == EOF)
737 737 (void) warn(gettext("Could not close temporary file"));
738 738 tempfile = NULL;
739 739 }
740 740
741 741 if (tempfilename[0] != '\0') {
742 742 do {
743 743 ret = remove(tempfilename);
744 744 } while (ret == -1 && errno == EINTR);
745 745 if (ret == -1)
746 746 warn(gettext("Could not remove temporary file"));
747 747 tempfilename[0] = '\0';
748 748 }
749 749 }
750 750
751 751 /*
752 752 * Launch private svc.configd(1M) for manipulating alternate repositories.
753 753 */
754 754 static void
755 755 start_private_repository(engine_state_t *est)
756 756 {
757 757 int fd, stat;
758 758 struct door_info info;
759 759 pid_t pid;
760 760
761 761 /*
762 762 * 1. Create a temporary file for the door.
763 763 */
764 764 if (est->sc_repo_doorname != NULL)
765 765 free((void *)est->sc_repo_doorname);
766 766
767 767 est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
768 768 if (est->sc_repo_doorname == NULL)
769 769 uu_die(gettext("Could not acquire temporary filename"));
770 770
771 771 fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
772 772 if (fd < 0)
773 773 uu_die(gettext("Could not create temporary file for "
774 774 "repository server"));
775 775
776 776 (void) close(fd);
777 777
778 778 /*
779 779 * 2. Launch a configd with that door, using the specified
780 780 * repository.
781 781 */
782 782 if ((est->sc_repo_pid = fork()) == 0) {
783 783 (void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
784 784 "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
785 785 NULL);
786 786 uu_die(gettext("Could not execute %s"), est->sc_repo_server);
787 787 } else if (est->sc_repo_pid == -1)
788 788 uu_die(gettext("Attempt to fork failed"));
789 789
790 790 do {
791 791 pid = waitpid(est->sc_repo_pid, &stat, 0);
792 792 } while (pid == -1 && errno == EINTR);
793 793
794 794 if (pid == -1)
795 795 uu_die(gettext("Could not waitpid() for repository server"));
796 796
797 797 if (!WIFEXITED(stat)) {
798 798 uu_die(gettext("Repository server failed (status %d).\n"),
799 799 stat);
800 800 } else if (WEXITSTATUS(stat) != 0) {
801 801 uu_die(gettext("Repository server failed (exit %d).\n"),
802 802 WEXITSTATUS(stat));
803 803 }
804 804
805 805 /*
806 806 * See if it was successful by checking if the door is a door.
807 807 */
808 808
809 809 fd = open(est->sc_repo_doorname, O_RDWR);
810 810 if (fd < 0)
811 811 uu_die(gettext("Could not open door \"%s\""),
812 812 est->sc_repo_doorname);
813 813
814 814 if (door_info(fd, &info) < 0)
815 815 uu_die(gettext("Unexpected door_info() error"));
816 816
817 817 if (close(fd) == -1)
818 818 warn(gettext("Could not close repository door"),
819 819 strerror(errno));
820 820
821 821 est->sc_repo_pid = info.di_target;
822 822 }
823 823
824 824 void
825 825 lscf_cleanup(void)
826 826 {
827 827 /*
828 828 * In the case where we've launched a private svc.configd(1M)
829 829 * instance, we must terminate our child and remove the temporary
830 830 * rendezvous point.
831 831 */
832 832 if (est->sc_repo_pid > 0) {
833 833 (void) kill(est->sc_repo_pid, SIGTERM);
834 834 (void) waitpid(est->sc_repo_pid, NULL, 0);
835 835 (void) unlink(est->sc_repo_doorname);
836 836
837 837 est->sc_repo_pid = 0;
838 838 }
839 839 }
840 840
841 841 void
842 842 unselect_cursnap(void)
843 843 {
844 844 void *cookie;
845 845
846 846 cur_level = NULL;
847 847
848 848 cookie = NULL;
849 849 while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
850 850 scf_snaplevel_destroy(cur_elt->sl);
851 851 free(cur_elt);
852 852 }
853 853
854 854 scf_snapshot_destroy(cur_snap);
855 855 cur_snap = NULL;
856 856 }
857 857
858 858 void
859 859 lscf_prep_hndl(void)
860 860 {
861 861 if (g_hndl != NULL)
862 862 return;
863 863
864 864 g_hndl = scf_handle_create(SCF_VERSION);
865 865 if (g_hndl == NULL)
866 866 scfdie();
867 867
868 868 if (est->sc_repo_filename != NULL)
869 869 start_private_repository(est);
870 870
871 871 if (est->sc_repo_doorname != NULL) {
872 872 scf_value_t *repo_value;
873 873 int ret;
874 874
875 875 repo_value = scf_value_create(g_hndl);
876 876 if (repo_value == NULL)
877 877 scfdie();
878 878
879 879 ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
880 880 assert(ret == SCF_SUCCESS);
881 881
882 882 if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
883 883 SCF_SUCCESS)
884 884 scfdie();
885 885
886 886 scf_value_destroy(repo_value);
887 887 }
888 888
889 889 if (scf_handle_bind(g_hndl) != 0)
890 890 uu_die(gettext("Could not connect to repository server: %s.\n"),
891 891 scf_strerror(scf_error()));
892 892
893 893 cur_scope = scf_scope_create(g_hndl);
894 894 if (cur_scope == NULL)
895 895 scfdie();
896 896
897 897 if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
898 898 scfdie();
899 899 }
900 900
901 901 static void
902 902 repository_teardown(void)
903 903 {
904 904 if (g_hndl != NULL) {
905 905 if (cur_snap != NULL)
906 906 unselect_cursnap();
907 907 scf_instance_destroy(cur_inst);
908 908 scf_service_destroy(cur_svc);
909 909 scf_scope_destroy(cur_scope);
910 910 scf_handle_destroy(g_hndl);
911 911 cur_inst = NULL;
912 912 cur_svc = NULL;
913 913 cur_scope = NULL;
914 914 g_hndl = NULL;
915 915 lscf_cleanup();
916 916 }
917 917 }
918 918
919 919 void
920 920 lscf_set_repository(const char *repfile, int force)
921 921 {
922 922 repository_teardown();
923 923
924 924 if (est->sc_repo_filename != NULL) {
925 925 free((void *)est->sc_repo_filename);
926 926 est->sc_repo_filename = NULL;
927 927 }
928 928
929 929 if ((force == 0) && (access(repfile, R_OK) != 0)) {
930 930 /*
931 931 * Repository file does not exist
932 932 * or has no read permission.
933 933 */
934 934 warn(gettext("Cannot access \"%s\": %s\n"),
935 935 repfile, strerror(errno));
936 936 } else {
937 937 est->sc_repo_filename = safe_strdup(repfile);
938 938 }
939 939
940 940 lscf_prep_hndl();
941 941 }
942 942
943 943 void
944 944 lscf_init()
945 945 {
946 946 if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
947 947 (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
948 948 (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
949 949 0 ||
950 950 (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
951 951 scfdie();
952 952
953 953 max_scf_len = max_scf_fmri_len;
954 954 if (max_scf_name_len > max_scf_len)
955 955 max_scf_len = max_scf_name_len;
956 956 if (max_scf_pg_type_len > max_scf_len)
957 957 max_scf_len = max_scf_pg_type_len;
958 958 /*
959 959 * When a value of type opaque is represented as a string, the
960 960 * string contains 2 characters for every byte of data. That is
961 961 * because the string contains the hex representation of the opaque
962 962 * value.
963 963 */
964 964 if (2 * max_scf_value_len > max_scf_len)
965 965 max_scf_len = 2 * max_scf_value_len;
966 966
967 967 if (atexit(remove_tempfile) != 0)
968 968 uu_die(gettext("Could not register atexit() function"));
969 969
970 970 emsg_entity_not_selected = gettext("An entity is not selected.\n");
971 971 emsg_permission_denied = gettext("Permission denied.\n");
972 972 emsg_create_xml = gettext("Could not create XML node.\n");
973 973 emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
974 974 emsg_invalid_for_snapshot =
975 975 gettext("Invalid operation on a snapshot.\n");
976 976 emsg_read_only = gettext("Backend read-only.\n");
977 977 emsg_deleted = gettext("Current selection has been deleted.\n");
978 978 emsg_invalid_pg_name =
979 979 gettext("Invalid property group name \"%s\".\n");
980 980 emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
981 981 emsg_no_such_pg = gettext("No such property group \"%s\".\n");
982 982 emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
983 983 "with invalid name \"%s\".\n");
984 984 emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
985 985 "group with invalid name \"%s\" or type \"%s\".\n");
986 986 emsg_pg_added = gettext("%s changed unexpectedly "
987 987 "(property group \"%s\" added).\n");
988 988 emsg_pg_changed = gettext("%s changed unexpectedly "
989 989 "(property group \"%s\" changed).\n");
990 990 emsg_pg_deleted = gettext("%s changed unexpectedly "
991 991 "(property group \"%s\" or an ancestor was deleted).\n");
992 992 emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
993 993 "in %s (permission denied).\n");
994 994 emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
995 995 "in %s (permission denied).\n");
996 996 emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
997 997 "in %s (permission denied).\n");
998 998 emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
999 999 "(permission denied).\n");
1000 1000 emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
1001 1001 "new dependent \"%s\" because it already exists). Warning: The "
1002 1002 "current dependent's target (%s) does not exist.\n");
1003 1003 emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
1004 1004 "dependent \"%s\" because it already exists). Warning: The "
1005 1005 "current dependent's target (%s) does not have a dependency named "
1006 1006 "\"%s\" as expected.\n");
1007 1007
1008 1008 string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
1009 1009 offsetof(string_list_t, node), NULL, 0);
1010 1010 snaplevel_pool = uu_list_pool_create("snaplevels",
1011 1011 sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
1012 1012 NULL, 0);
1013 1013 }
1014 1014
1015 1015
1016 1016 static const char *
1017 1017 prop_to_typestr(const scf_property_t *prop)
1018 1018 {
1019 1019 scf_type_t ty;
1020 1020
1021 1021 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
1022 1022 scfdie();
1023 1023
1024 1024 return (scf_type_to_string(ty));
1025 1025 }
1026 1026
1027 1027 static scf_type_t
1028 1028 string_to_type(const char *type)
1029 1029 {
1030 1030 size_t len = strlen(type);
1031 1031 char *buf;
1032 1032
1033 1033 if (len == 0 || type[len - 1] != ':')
1034 1034 return (SCF_TYPE_INVALID);
1035 1035
1036 1036 buf = (char *)alloca(len + 1);
1037 1037 (void) strlcpy(buf, type, len + 1);
1038 1038 buf[len - 1] = 0;
1039 1039
1040 1040 return (scf_string_to_type(buf));
1041 1041 }
1042 1042
1043 1043 static scf_value_t *
1044 1044 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
1045 1045 {
1046 1046 scf_value_t *v;
1047 1047 char *dup, *nstr;
1048 1048 size_t len;
1049 1049
1050 1050 v = scf_value_create(g_hndl);
1051 1051 if (v == NULL)
1052 1052 scfdie();
1053 1053
1054 1054 len = strlen(str);
1055 1055 if (require_quotes &&
1056 1056 (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
1057 1057 semerr(gettext("Multiple string values or string values "
1058 1058 "with spaces must be quoted with '\"'.\n"));
1059 1059 scf_value_destroy(v);
1060 1060 return (NULL);
1061 1061 }
1062 1062
1063 1063 nstr = dup = safe_strdup(str);
1064 1064 if (dup[0] == '\"') {
1065 1065 /*
1066 1066 * Strip out the first and the last quote.
1067 1067 */
1068 1068 dup[len - 1] = '\0';
1069 1069 nstr = dup + 1;
1070 1070 }
1071 1071
1072 1072 if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
1073 1073 assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1074 1074 semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1075 1075 scf_type_to_string(ty), nstr);
1076 1076 scf_value_destroy(v);
1077 1077 v = NULL;
1078 1078 }
1079 1079 free(dup);
1080 1080 return (v);
1081 1081 }
1082 1082
1083 1083 /*
1084 1084 * Print str to strm, quoting double-quotes and backslashes with backslashes.
1085 1085 * Optionally append a comment prefix ('#') to newlines ('\n').
1086 1086 */
1087 1087 static int
1088 1088 quote_and_print(const char *str, FILE *strm, int commentnl)
1089 1089 {
1090 1090 const char *cp;
1091 1091
1092 1092 for (cp = str; *cp != '\0'; ++cp) {
1093 1093 if (*cp == '"' || *cp == '\\')
1094 1094 (void) putc('\\', strm);
1095 1095
1096 1096 (void) putc(*cp, strm);
1097 1097
1098 1098 if (commentnl && *cp == '\n') {
1099 1099 (void) putc('#', strm);
1100 1100 }
1101 1101 }
1102 1102
1103 1103 return (ferror(strm));
1104 1104 }
1105 1105
1106 1106 /*
1107 1107 * These wrappers around lowlevel functions provide consistent error checking
1108 1108 * and warnings.
1109 1109 */
1110 1110 static int
1111 1111 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1112 1112 {
1113 1113 if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1114 1114 return (0);
1115 1115
1116 1116 if (scf_error() != SCF_ERROR_NOT_FOUND)
1117 1117 scfdie();
1118 1118
1119 1119 if (g_verbose) {
1120 1120 ssize_t len;
1121 1121 char *fmri;
1122 1122
1123 1123 len = scf_pg_to_fmri(pg, NULL, 0);
1124 1124 if (len < 0)
1125 1125 scfdie();
1126 1126
1127 1127 fmri = safe_malloc(len + 1);
1128 1128
1129 1129 if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1130 1130 scfdie();
1131 1131
1132 1132 warn(gettext("Expected property %s of property group %s is "
1133 1133 "missing.\n"), propname, fmri);
1134 1134
1135 1135 free(fmri);
1136 1136 }
1137 1137
1138 1138 return (-1);
1139 1139 }
1140 1140
1141 1141 static int
1142 1142 prop_check_type(scf_property_t *prop, scf_type_t ty)
1143 1143 {
1144 1144 scf_type_t pty;
1145 1145
1146 1146 if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1147 1147 scfdie();
1148 1148
1149 1149 if (ty == pty)
1150 1150 return (0);
1151 1151
1152 1152 if (g_verbose) {
1153 1153 ssize_t len;
1154 1154 char *fmri;
1155 1155 const char *tystr;
1156 1156
1157 1157 len = scf_property_to_fmri(prop, NULL, 0);
1158 1158 if (len < 0)
1159 1159 scfdie();
1160 1160
1161 1161 fmri = safe_malloc(len + 1);
1162 1162
1163 1163 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1164 1164 scfdie();
1165 1165
1166 1166 tystr = scf_type_to_string(ty);
1167 1167 if (tystr == NULL)
1168 1168 tystr = "?";
1169 1169
1170 1170 warn(gettext("Property %s is not of expected type %s.\n"),
1171 1171 fmri, tystr);
1172 1172
1173 1173 free(fmri);
1174 1174 }
1175 1175
1176 1176 return (-1);
1177 1177 }
1178 1178
1179 1179 static int
1180 1180 prop_get_val(scf_property_t *prop, scf_value_t *val)
1181 1181 {
1182 1182 scf_error_t err;
1183 1183
1184 1184 if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1185 1185 return (0);
1186 1186
1187 1187 err = scf_error();
1188 1188
1189 1189 if (err != SCF_ERROR_NOT_FOUND &&
1190 1190 err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1191 1191 err != SCF_ERROR_PERMISSION_DENIED)
1192 1192 scfdie();
1193 1193
1194 1194 if (g_verbose) {
1195 1195 ssize_t len;
1196 1196 char *fmri, *emsg;
1197 1197
1198 1198 len = scf_property_to_fmri(prop, NULL, 0);
1199 1199 if (len < 0)
1200 1200 scfdie();
1201 1201
1202 1202 fmri = safe_malloc(len + 1);
1203 1203
1204 1204 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1205 1205 scfdie();
1206 1206
1207 1207 if (err == SCF_ERROR_NOT_FOUND)
1208 1208 emsg = gettext("Property %s has no values; expected "
1209 1209 "one.\n");
1210 1210 else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1211 1211 emsg = gettext("Property %s has multiple values; "
1212 1212 "expected one.\n");
1213 1213 else
1214 1214 emsg = gettext("No permission to read property %s.\n");
1215 1215
1216 1216 warn(emsg, fmri);
1217 1217
1218 1218 free(fmri);
1219 1219 }
1220 1220
1221 1221 return (-1);
1222 1222 }
1223 1223
1224 1224
1225 1225 static boolean_t
1226 1226 snaplevel_is_instance(const scf_snaplevel_t *level)
1227 1227 {
1228 1228 if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1229 1229 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1230 1230 scfdie();
1231 1231 return (0);
1232 1232 } else {
1233 1233 return (1);
1234 1234 }
1235 1235 }
1236 1236
1237 1237 /*
1238 1238 * Decode FMRI into a service or instance, and put the result in *ep. If
1239 1239 * memory cannot be allocated, return SCF_ERROR_NO_MEMORY. If the FMRI is
1240 1240 * invalid, return SCF_ERROR_INVALID_ARGUMENT. If the FMRI does not specify
1241 1241 * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED. If the entity cannot be
1242 1242 * found, return SCF_ERROR_NOT_FOUND. Otherwise return SCF_ERROR_NONE, point
1243 1243 * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1244 1244 * whether *ep is a service.
1245 1245 */
1246 1246 static scf_error_t
1247 1247 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1248 1248 {
1249 1249 char *fmri_copy;
1250 1250 const char *sstr, *istr, *pgstr;
1251 1251 scf_service_t *svc;
1252 1252 scf_instance_t *inst;
1253 1253
1254 1254 fmri_copy = strdup(fmri);
1255 1255 if (fmri_copy == NULL)
1256 1256 return (SCF_ERROR_NO_MEMORY);
1257 1257
1258 1258 if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1259 1259 SCF_SUCCESS) {
1260 1260 free(fmri_copy);
1261 1261 return (SCF_ERROR_INVALID_ARGUMENT);
1262 1262 }
1263 1263
1264 1264 free(fmri_copy);
1265 1265
1266 1266 if (sstr == NULL || pgstr != NULL)
1267 1267 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1268 1268
1269 1269 if (istr == NULL) {
1270 1270 svc = scf_service_create(h);
1271 1271 if (svc == NULL)
1272 1272 return (SCF_ERROR_NO_MEMORY);
1273 1273
1274 1274 if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1275 1275 SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1276 1276 if (scf_error() != SCF_ERROR_NOT_FOUND)
1277 1277 scfdie();
1278 1278
1279 1279 return (SCF_ERROR_NOT_FOUND);
1280 1280 }
1281 1281
1282 1282 *ep = svc;
1283 1283 *isservice = 1;
1284 1284 } else {
1285 1285 inst = scf_instance_create(h);
1286 1286 if (inst == NULL)
1287 1287 return (SCF_ERROR_NO_MEMORY);
1288 1288
1289 1289 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1290 1290 NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1291 1291 if (scf_error() != SCF_ERROR_NOT_FOUND)
1292 1292 scfdie();
1293 1293
1294 1294 return (SCF_ERROR_NOT_FOUND);
1295 1295 }
1296 1296
1297 1297 *ep = inst;
1298 1298 *isservice = 0;
1299 1299 }
1300 1300
1301 1301 return (SCF_ERROR_NONE);
1302 1302 }
1303 1303
1304 1304 /*
1305 1305 * Create the entity named by fmri. Place a pointer to its libscf handle in
1306 1306 * *ep, and set or clear *isservicep if it is a service or an instance.
1307 1307 * Returns
1308 1308 * SCF_ERROR_NONE - success
1309 1309 * SCF_ERROR_NO_MEMORY - scf_*_create() failed
1310 1310 * SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1311 1311 * SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1312 1312 * SCF_ERROR_NOT_FOUND - no such scope
1313 1313 * SCF_ERROR_PERMISSION_DENIED
1314 1314 * SCF_ERROR_BACKEND_READONLY
1315 1315 * SCF_ERROR_BACKEND_ACCESS
1316 1316 */
1317 1317 static scf_error_t
1318 1318 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1319 1319 {
1320 1320 char *fmri_copy;
1321 1321 const char *scstr, *sstr, *istr, *pgstr;
1322 1322 scf_scope_t *scope = NULL;
1323 1323 scf_service_t *svc = NULL;
1324 1324 scf_instance_t *inst = NULL;
1325 1325 scf_error_t scfe;
1326 1326
1327 1327 fmri_copy = safe_strdup(fmri);
1328 1328
1329 1329 if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1330 1330 0) {
1331 1331 free(fmri_copy);
1332 1332 return (SCF_ERROR_INVALID_ARGUMENT);
1333 1333 }
1334 1334
1335 1335 if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1336 1336 free(fmri_copy);
1337 1337 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1338 1338 }
1339 1339
1340 1340 *ep = NULL;
1341 1341
1342 1342 if ((scope = scf_scope_create(h)) == NULL ||
1343 1343 (svc = scf_service_create(h)) == NULL ||
1344 1344 (inst = scf_instance_create(h)) == NULL) {
1345 1345 scfe = SCF_ERROR_NO_MEMORY;
1346 1346 goto out;
1347 1347 }
1348 1348
1349 1349 get_scope:
1350 1350 if (scf_handle_get_scope(h, scstr, scope) != 0) {
1351 1351 switch (scf_error()) {
1352 1352 case SCF_ERROR_CONNECTION_BROKEN:
1353 1353 scfdie();
1354 1354 /* NOTREACHED */
1355 1355
1356 1356 case SCF_ERROR_NOT_FOUND:
1357 1357 scfe = SCF_ERROR_NOT_FOUND;
1358 1358 goto out;
1359 1359
1360 1360 case SCF_ERROR_HANDLE_MISMATCH:
1361 1361 case SCF_ERROR_NOT_BOUND:
1362 1362 case SCF_ERROR_INVALID_ARGUMENT:
1363 1363 default:
1364 1364 bad_error("scf_handle_get_scope", scf_error());
1365 1365 }
1366 1366 }
1367 1367
1368 1368 get_svc:
1369 1369 if (scf_scope_get_service(scope, sstr, svc) != 0) {
1370 1370 switch (scf_error()) {
1371 1371 case SCF_ERROR_CONNECTION_BROKEN:
1372 1372 scfdie();
1373 1373 /* NOTREACHED */
1374 1374
1375 1375 case SCF_ERROR_DELETED:
1376 1376 goto get_scope;
1377 1377
1378 1378 case SCF_ERROR_NOT_FOUND:
1379 1379 break;
1380 1380
1381 1381 case SCF_ERROR_HANDLE_MISMATCH:
1382 1382 case SCF_ERROR_INVALID_ARGUMENT:
1383 1383 case SCF_ERROR_NOT_BOUND:
1384 1384 case SCF_ERROR_NOT_SET:
1385 1385 default:
1386 1386 bad_error("scf_scope_get_service", scf_error());
1387 1387 }
1388 1388
1389 1389 if (scf_scope_add_service(scope, sstr, svc) != 0) {
1390 1390 switch (scf_error()) {
1391 1391 case SCF_ERROR_CONNECTION_BROKEN:
1392 1392 scfdie();
1393 1393 /* NOTREACHED */
1394 1394
1395 1395 case SCF_ERROR_DELETED:
1396 1396 goto get_scope;
1397 1397
1398 1398 case SCF_ERROR_PERMISSION_DENIED:
1399 1399 case SCF_ERROR_BACKEND_READONLY:
1400 1400 case SCF_ERROR_BACKEND_ACCESS:
1401 1401 scfe = scf_error();
1402 1402 goto out;
1403 1403
1404 1404 case SCF_ERROR_HANDLE_MISMATCH:
1405 1405 case SCF_ERROR_INVALID_ARGUMENT:
1406 1406 case SCF_ERROR_NOT_BOUND:
1407 1407 case SCF_ERROR_NOT_SET:
1408 1408 default:
1409 1409 bad_error("scf_scope_get_service", scf_error());
1410 1410 }
1411 1411 }
1412 1412 }
1413 1413
1414 1414 if (istr == NULL) {
1415 1415 scfe = SCF_ERROR_NONE;
1416 1416 *ep = svc;
1417 1417 *isservicep = 1;
1418 1418 goto out;
1419 1419 }
1420 1420
1421 1421 get_inst:
1422 1422 if (scf_service_get_instance(svc, istr, inst) != 0) {
1423 1423 switch (scf_error()) {
1424 1424 case SCF_ERROR_CONNECTION_BROKEN:
1425 1425 scfdie();
1426 1426 /* NOTREACHED */
1427 1427
1428 1428 case SCF_ERROR_DELETED:
1429 1429 goto get_svc;
1430 1430
1431 1431 case SCF_ERROR_NOT_FOUND:
1432 1432 break;
1433 1433
1434 1434 case SCF_ERROR_HANDLE_MISMATCH:
1435 1435 case SCF_ERROR_INVALID_ARGUMENT:
1436 1436 case SCF_ERROR_NOT_BOUND:
1437 1437 case SCF_ERROR_NOT_SET:
1438 1438 default:
1439 1439 bad_error("scf_service_get_instance", scf_error());
1440 1440 }
1441 1441
1442 1442 if (scf_service_add_instance(svc, istr, inst) != 0) {
1443 1443 switch (scf_error()) {
1444 1444 case SCF_ERROR_CONNECTION_BROKEN:
1445 1445 scfdie();
1446 1446 /* NOTREACHED */
1447 1447
1448 1448 case SCF_ERROR_DELETED:
1449 1449 goto get_svc;
1450 1450
1451 1451 case SCF_ERROR_PERMISSION_DENIED:
1452 1452 case SCF_ERROR_BACKEND_READONLY:
1453 1453 case SCF_ERROR_BACKEND_ACCESS:
1454 1454 scfe = scf_error();
1455 1455 goto out;
1456 1456
1457 1457 case SCF_ERROR_HANDLE_MISMATCH:
1458 1458 case SCF_ERROR_INVALID_ARGUMENT:
1459 1459 case SCF_ERROR_NOT_BOUND:
1460 1460 case SCF_ERROR_NOT_SET:
1461 1461 default:
1462 1462 bad_error("scf_service_add_instance",
1463 1463 scf_error());
1464 1464 }
1465 1465 }
1466 1466 }
1467 1467
1468 1468 scfe = SCF_ERROR_NONE;
1469 1469 *ep = inst;
1470 1470 *isservicep = 0;
1471 1471
1472 1472 out:
1473 1473 if (*ep != inst)
1474 1474 scf_instance_destroy(inst);
1475 1475 if (*ep != svc)
1476 1476 scf_service_destroy(svc);
1477 1477 scf_scope_destroy(scope);
1478 1478 free(fmri_copy);
1479 1479 return (scfe);
1480 1480 }
1481 1481
1482 1482 /*
1483 1483 * Create or update a snapshot of inst. snap is a required scratch object.
1484 1484 *
1485 1485 * Returns
1486 1486 * 0 - success
1487 1487 * ECONNABORTED - repository connection broken
1488 1488 * EPERM - permission denied
1489 1489 * ENOSPC - configd is out of resources
1490 1490 * ECANCELED - inst was deleted
1491 1491 * -1 - unknown libscf error (message printed)
1492 1492 */
1493 1493 static int
1494 1494 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1495 1495 {
1496 1496 again:
1497 1497 if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1498 1498 if (_scf_snapshot_take_attach(inst, snap) != 0) {
1499 1499 switch (scf_error()) {
1500 1500 case SCF_ERROR_CONNECTION_BROKEN:
1501 1501 case SCF_ERROR_PERMISSION_DENIED:
1502 1502 case SCF_ERROR_NO_RESOURCES:
1503 1503 return (scferror2errno(scf_error()));
1504 1504
1505 1505 case SCF_ERROR_NOT_SET:
1506 1506 case SCF_ERROR_INVALID_ARGUMENT:
1507 1507 default:
1508 1508 bad_error("_scf_snapshot_take_attach",
1509 1509 scf_error());
1510 1510 }
1511 1511 }
1512 1512 } else {
1513 1513 switch (scf_error()) {
1514 1514 case SCF_ERROR_NOT_FOUND:
1515 1515 break;
1516 1516
1517 1517 case SCF_ERROR_DELETED:
1518 1518 case SCF_ERROR_CONNECTION_BROKEN:
1519 1519 return (scferror2errno(scf_error()));
1520 1520
1521 1521 case SCF_ERROR_HANDLE_MISMATCH:
1522 1522 case SCF_ERROR_NOT_BOUND:
1523 1523 case SCF_ERROR_INVALID_ARGUMENT:
1524 1524 case SCF_ERROR_NOT_SET:
1525 1525 default:
1526 1526 bad_error("scf_instance_get_snapshot", scf_error());
1527 1527 }
1528 1528
1529 1529 if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1530 1530 switch (scf_error()) {
1531 1531 case SCF_ERROR_EXISTS:
1532 1532 goto again;
1533 1533
1534 1534 case SCF_ERROR_CONNECTION_BROKEN:
1535 1535 case SCF_ERROR_NO_RESOURCES:
1536 1536 case SCF_ERROR_PERMISSION_DENIED:
1537 1537 return (scferror2errno(scf_error()));
1538 1538
1539 1539 default:
1540 1540 scfwarn();
1541 1541 return (-1);
1542 1542
1543 1543 case SCF_ERROR_NOT_SET:
1544 1544 case SCF_ERROR_INTERNAL:
1545 1545 case SCF_ERROR_INVALID_ARGUMENT:
1546 1546 case SCF_ERROR_HANDLE_MISMATCH:
1547 1547 bad_error("_scf_snapshot_take_new",
1548 1548 scf_error());
1549 1549 }
1550 1550 }
1551 1551 }
1552 1552
1553 1553 return (0);
1554 1554 }
1555 1555
1556 1556 static int
1557 1557 refresh_running_snapshot(void *entity)
1558 1558 {
1559 1559 scf_snapshot_t *snap;
1560 1560 int r;
1561 1561
1562 1562 if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1563 1563 scfdie();
1564 1564 r = take_snap(entity, snap_running, snap);
1565 1565 scf_snapshot_destroy(snap);
1566 1566
1567 1567 return (r);
1568 1568 }
1569 1569
1570 1570 /*
1571 1571 * Refresh entity. If isservice is zero, take entity to be an scf_instance_t *.
1572 1572 * Otherwise take entity to be an scf_service_t * and refresh all of its child
1573 1573 * instances. fmri is used for messages. inst, iter, and name_buf are used
1574 1574 * for scratch space. Returns
1575 1575 * 0 - success
1576 1576 * ECONNABORTED - repository connection broken
1577 1577 * ECANCELED - entity was deleted
1578 1578 * EACCES - backend denied access
1579 1579 * EPERM - permission denied
1580 1580 * ENOSPC - repository server out of resources
1581 1581 * -1 - _smf_refresh_instance_i() failed. scf_error() should be set.
1582 1582 */
1583 1583 static int
1584 1584 refresh_entity(int isservice, void *entity, const char *fmri,
1585 1585 scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1586 1586 {
1587 1587 scf_error_t scfe;
1588 1588 int r;
1589 1589
1590 1590 if (!isservice) {
1591 1591 /*
1592 1592 * Let restarter handles refreshing and making new running
1593 1593 * snapshot only if operating on a live repository and not
1594 1594 * running in early import.
1595 1595 */
1596 1596 if (est->sc_repo_filename == NULL &&
1597 1597 est->sc_repo_doorname == NULL &&
1598 1598 est->sc_in_emi == 0) {
1599 1599 if (_smf_refresh_instance_i(entity) == 0) {
1600 1600 if (g_verbose)
1601 1601 warn(gettext("Refreshed %s.\n"), fmri);
1602 1602 return (0);
1603 1603 }
1604 1604
1605 1605 switch (scf_error()) {
1606 1606 case SCF_ERROR_BACKEND_ACCESS:
1607 1607 return (EACCES);
1608 1608
1609 1609 case SCF_ERROR_PERMISSION_DENIED:
1610 1610 return (EPERM);
1611 1611
1612 1612 default:
1613 1613 return (-1);
1614 1614 }
1615 1615 } else {
1616 1616 r = refresh_running_snapshot(entity);
1617 1617 switch (r) {
1618 1618 case 0:
1619 1619 break;
1620 1620
1621 1621 case ECONNABORTED:
1622 1622 case ECANCELED:
1623 1623 case EPERM:
1624 1624 case ENOSPC:
1625 1625 break;
1626 1626
1627 1627 default:
1628 1628 bad_error("refresh_running_snapshot",
1629 1629 scf_error());
1630 1630 }
1631 1631
1632 1632 return (r);
1633 1633 }
1634 1634 }
1635 1635
1636 1636 if (scf_iter_service_instances(iter, entity) != 0) {
1637 1637 switch (scf_error()) {
1638 1638 case SCF_ERROR_CONNECTION_BROKEN:
1639 1639 return (ECONNABORTED);
1640 1640
1641 1641 case SCF_ERROR_DELETED:
1642 1642 return (ECANCELED);
1643 1643
1644 1644 case SCF_ERROR_HANDLE_MISMATCH:
1645 1645 case SCF_ERROR_NOT_BOUND:
1646 1646 case SCF_ERROR_NOT_SET:
1647 1647 default:
1648 1648 bad_error("scf_iter_service_instances", scf_error());
1649 1649 }
1650 1650 }
1651 1651
1652 1652 for (;;) {
1653 1653 r = scf_iter_next_instance(iter, inst);
1654 1654 if (r == 0)
1655 1655 break;
1656 1656 if (r != 1) {
1657 1657 switch (scf_error()) {
1658 1658 case SCF_ERROR_CONNECTION_BROKEN:
1659 1659 return (ECONNABORTED);
1660 1660
1661 1661 case SCF_ERROR_DELETED:
1662 1662 return (ECANCELED);
1663 1663
1664 1664 case SCF_ERROR_HANDLE_MISMATCH:
1665 1665 case SCF_ERROR_NOT_BOUND:
1666 1666 case SCF_ERROR_NOT_SET:
1667 1667 case SCF_ERROR_INVALID_ARGUMENT:
1668 1668 default:
1669 1669 bad_error("scf_iter_next_instance",
1670 1670 scf_error());
1671 1671 }
1672 1672 }
1673 1673
1674 1674 /*
1675 1675 * Similarly, just take a new running snapshot if operating on
1676 1676 * a non-live repository or running during early import.
1677 1677 */
1678 1678 if (est->sc_repo_filename != NULL ||
1679 1679 est->sc_repo_doorname != NULL ||
1680 1680 est->sc_in_emi == 1) {
1681 1681 r = refresh_running_snapshot(inst);
1682 1682 switch (r) {
1683 1683 case 0:
1684 1684 continue;
1685 1685
1686 1686 case ECONNABORTED:
1687 1687 case ECANCELED:
1688 1688 case EPERM:
1689 1689 case ENOSPC:
1690 1690 break;
1691 1691 default:
1692 1692 bad_error("refresh_running_snapshot",
1693 1693 scf_error());
1694 1694 }
1695 1695
1696 1696 return (r);
1697 1697
1698 1698 }
1699 1699
1700 1700 if (_smf_refresh_instance_i(inst) == 0) {
1701 1701 if (g_verbose) {
1702 1702 if (scf_instance_get_name(inst, name_buf,
1703 1703 max_scf_name_len + 1) < 0)
1704 1704 (void) strcpy(name_buf, "?");
1705 1705
1706 1706 warn(gettext("Refreshed %s:%s.\n"),
1707 1707 fmri, name_buf);
1708 1708 }
1709 1709 } else {
1710 1710 if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1711 1711 g_verbose) {
1712 1712 scfe = scf_error();
1713 1713
1714 1714 if (scf_instance_to_fmri(inst, name_buf,
1715 1715 max_scf_name_len + 1) < 0)
1716 1716 (void) strcpy(name_buf, "?");
1717 1717
1718 1718 warn(gettext(
1719 1719 "Refresh of %s:%s failed: %s.\n"), fmri,
1720 1720 name_buf, scf_strerror(scfe));
1721 1721 }
1722 1722 }
1723 1723 }
1724 1724
1725 1725 return (0);
1726 1726 }
1727 1727
1728 1728 static void
1729 1729 private_refresh(void)
1730 1730 {
1731 1731 scf_instance_t *pinst = NULL;
1732 1732 scf_iter_t *piter = NULL;
1733 1733 ssize_t fmrilen;
1734 1734 size_t bufsz;
1735 1735 char *fmribuf;
1736 1736 void *ent;
1737 1737 int issvc;
1738 1738 int r;
1739 1739
1740 1740 if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1741 1741 return;
1742 1742
1743 1743 assert(cur_svc != NULL);
1744 1744
1745 1745 bufsz = max_scf_fmri_len + 1;
1746 1746 fmribuf = safe_malloc(bufsz);
1747 1747 if (cur_inst) {
1748 1748 issvc = 0;
1749 1749 ent = cur_inst;
1750 1750 fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1751 1751 } else {
1752 1752 issvc = 1;
1753 1753 ent = cur_svc;
1754 1754 fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1755 1755 if ((pinst = scf_instance_create(g_hndl)) == NULL)
1756 1756 scfdie();
1757 1757
1758 1758 if ((piter = scf_iter_create(g_hndl)) == NULL)
1759 1759 scfdie();
1760 1760 }
1761 1761 if (fmrilen < 0) {
1762 1762 free(fmribuf);
1763 1763 if (scf_error() != SCF_ERROR_DELETED)
1764 1764 scfdie();
1765 1765
1766 1766 warn(emsg_deleted);
1767 1767 return;
1768 1768 }
1769 1769 assert(fmrilen < bufsz);
1770 1770
1771 1771 r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1772 1772 switch (r) {
1773 1773 case 0:
1774 1774 break;
1775 1775
1776 1776 case ECONNABORTED:
1777 1777 warn(gettext("Could not refresh %s "
1778 1778 "(repository connection broken).\n"), fmribuf);
1779 1779 break;
1780 1780
1781 1781 case ECANCELED:
1782 1782 warn(emsg_deleted);
1783 1783 break;
1784 1784
1785 1785 case EPERM:
1786 1786 warn(gettext("Could not refresh %s "
1787 1787 "(permission denied).\n"), fmribuf);
1788 1788 break;
1789 1789
1790 1790 case ENOSPC:
1791 1791 warn(gettext("Could not refresh %s "
1792 1792 "(repository server out of resources).\n"),
1793 1793 fmribuf);
1794 1794 break;
1795 1795
1796 1796 case EACCES:
1797 1797 default:
1798 1798 bad_error("refresh_entity", scf_error());
1799 1799 }
1800 1800
1801 1801 if (issvc) {
1802 1802 scf_instance_destroy(pinst);
1803 1803 scf_iter_destroy(piter);
1804 1804 }
1805 1805
1806 1806 free(fmribuf);
1807 1807 }
1808 1808
1809 1809
1810 1810 static int
1811 1811 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1812 1812 {
1813 1813 cbp->sc_err = scferror2errno(err);
1814 1814 return (UU_WALK_ERROR);
1815 1815 }
1816 1816
1817 1817 static int
1818 1818 stash_scferror(scf_callback_t *cbp)
1819 1819 {
1820 1820 return (stash_scferror_err(cbp, scf_error()));
1821 1821 }
1822 1822
1823 1823 static int select_inst(const char *);
1824 1824 static int select_svc(const char *);
1825 1825
1826 1826 /*
1827 1827 * Take a property that does not have a type and check to see if a type
1828 1828 * exists or can be gleened from the current data. Set the type.
1829 1829 *
1830 1830 * Check the current level (instance) and then check the higher level
1831 1831 * (service). This could be the case for adding a new property to
1832 1832 * the instance that's going to "override" a service level property.
1833 1833 *
1834 1834 * For a property :
1835 1835 * 1. Take the type from an existing property
1836 1836 * 2. Take the type from a template entry
1837 1837 *
1838 1838 * If the type can not be found, then leave the type as is, and let the import
1839 1839 * report the problem of the missing type.
1840 1840 */
1841 1841 static int
1842 1842 find_current_prop_type(void *p, void *g)
1843 1843 {
1844 1844 property_t *prop = p;
1845 1845 scf_callback_t *lcb = g;
1846 1846 pgroup_t *pg = NULL;
1847 1847
1848 1848 const char *fmri = NULL;
1849 1849 char *lfmri = NULL;
1850 1850 char *cur_selection = NULL;
1851 1851
1852 1852 scf_propertygroup_t *sc_pg = NULL;
1853 1853 scf_property_t *sc_prop = NULL;
1854 1854 scf_pg_tmpl_t *t_pg = NULL;
1855 1855 scf_prop_tmpl_t *t_prop = NULL;
1856 1856 scf_type_t prop_type;
1857 1857
1858 1858 value_t *vp;
1859 1859 int issvc = lcb->sc_service;
1860 1860 int r = UU_WALK_ERROR;
1861 1861
1862 1862 if (prop->sc_value_type != SCF_TYPE_INVALID)
1863 1863 return (UU_WALK_NEXT);
1864 1864
1865 1865 t_prop = scf_tmpl_prop_create(g_hndl);
1866 1866 sc_prop = scf_property_create(g_hndl);
1867 1867 if (sc_prop == NULL || t_prop == NULL) {
1868 1868 warn(gettext("Unable to create the property to attempt and "
1869 1869 "find a missing type.\n"));
1870 1870
1871 1871 scf_property_destroy(sc_prop);
1872 1872 scf_tmpl_prop_destroy(t_prop);
1873 1873
1874 1874 return (UU_WALK_ERROR);
1875 1875 }
1876 1876
1877 1877 if (lcb->sc_flags == 1) {
1878 1878 pg = lcb->sc_parent;
1879 1879 issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT);
1880 1880 fmri = pg->sc_parent->sc_fmri;
1881 1881 retry_pg:
1882 1882 if (cur_svc && cur_selection == NULL) {
1883 1883 cur_selection = safe_malloc(max_scf_fmri_len + 1);
1884 1884 lscf_get_selection_str(cur_selection,
1885 1885 max_scf_fmri_len + 1);
1886 1886
1887 1887 if (strcmp(cur_selection, fmri) != 0) {
1888 1888 lscf_select(fmri);
1889 1889 } else {
1890 1890 free(cur_selection);
1891 1891 cur_selection = NULL;
1892 1892 }
1893 1893 } else {
1894 1894 lscf_select(fmri);
1895 1895 }
1896 1896
1897 1897 if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) {
1898 1898 warn(gettext("Unable to create property group to "
1899 1899 "find a missing property type.\n"));
1900 1900
1901 1901 goto out;
1902 1902 }
1903 1903
1904 1904 if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) {
1905 1905 /*
1906 1906 * If this is the sc_pg from the parent
1907 1907 * let the caller clean up the sc_pg,
1908 1908 * and just throw it away in this case.
1909 1909 */
1910 1910 if (sc_pg != lcb->sc_parent)
1911 1911 scf_pg_destroy(sc_pg);
1912 1912
1913 1913 sc_pg = NULL;
1914 1914 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1915 1915 warn(gettext("Unable to create template "
1916 1916 "property group to find a property "
1917 1917 "type.\n"));
1918 1918
1919 1919 goto out;
1920 1920 }
1921 1921
1922 1922 if (scf_tmpl_get_by_pg_name(fmri, NULL,
1923 1923 pg->sc_pgroup_name, NULL, t_pg,
1924 1924 SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) {
1925 1925 /*
1926 1926 * if instance get service and jump back
1927 1927 */
1928 1928 scf_tmpl_pg_destroy(t_pg);
1929 1929 t_pg = NULL;
1930 1930 if (issvc == 0) {
1931 1931 entity_t *e = pg->sc_parent->sc_parent;
1932 1932
1933 1933 fmri = e->sc_fmri;
1934 1934 issvc = 1;
1935 1935 goto retry_pg;
1936 1936 } else {
1937 1937 goto out;
1938 1938 }
1939 1939 }
1940 1940 }
1941 1941 } else {
1942 1942 sc_pg = lcb->sc_parent;
1943 1943 }
1944 1944
1945 1945 /*
1946 1946 * Attempt to get the type from an existing property. If the property
1947 1947 * cannot be found then attempt to get the type from a template entry
1948 1948 * for the property.
1949 1949 *
1950 1950 * Finally, if at the instance level look at the service level.
1951 1951 */
1952 1952 if (sc_pg != NULL &&
1953 1953 pg_get_prop(sc_pg, prop->sc_property_name,
1954 1954 sc_prop) == SCF_SUCCESS &&
1955 1955 scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) {
1956 1956 prop->sc_value_type = prop_type;
1957 1957
1958 1958 /*
1959 1959 * Found a type, update the value types and validate
1960 1960 * the actual value against this type.
1961 1961 */
1962 1962 for (vp = uu_list_first(prop->sc_property_values);
1963 1963 vp != NULL;
1964 1964 vp = uu_list_next(prop->sc_property_values, vp)) {
1965 1965 vp->sc_type = prop->sc_value_type;
1966 1966 lxml_store_value(vp, 0, NULL);
1967 1967 }
1968 1968
1969 1969 r = UU_WALK_NEXT;
1970 1970 goto out;
1971 1971 }
1972 1972
1973 1973 /*
1974 1974 * If we get here with t_pg set to NULL then we had to have
1975 1975 * gotten an sc_pg but that sc_pg did not have the property
1976 1976 * we are looking for. So if the t_pg is not null look up
1977 1977 * the template entry for the property.
1978 1978 *
1979 1979 * If the t_pg is null then need to attempt to get a matching
1980 1980 * template entry for the sc_pg, and see if there is a property
1981 1981 * entry for that template entry.
1982 1982 */
1983 1983 do_tmpl :
1984 1984 if (t_pg != NULL &&
1985 1985 scf_tmpl_get_by_prop(t_pg, prop->sc_property_name,
1986 1986 t_prop, 0) == SCF_SUCCESS) {
1987 1987 if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) {
1988 1988 prop->sc_value_type = prop_type;
1989 1989
1990 1990 /*
1991 1991 * Found a type, update the value types and validate
1992 1992 * the actual value against this type.
1993 1993 */
1994 1994 for (vp = uu_list_first(prop->sc_property_values);
1995 1995 vp != NULL;
1996 1996 vp = uu_list_next(prop->sc_property_values, vp)) {
1997 1997 vp->sc_type = prop->sc_value_type;
1998 1998 lxml_store_value(vp, 0, NULL);
1999 1999 }
2000 2000
2001 2001 r = UU_WALK_NEXT;
2002 2002 goto out;
2003 2003 }
2004 2004 } else {
2005 2005 if (t_pg == NULL && sc_pg) {
2006 2006 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
2007 2007 warn(gettext("Unable to create template "
2008 2008 "property group to find a property "
2009 2009 "type.\n"));
2010 2010
2011 2011 goto out;
2012 2012 }
2013 2013
2014 2014 if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
2015 2015 scf_tmpl_pg_destroy(t_pg);
2016 2016 t_pg = NULL;
2017 2017 } else {
2018 2018 goto do_tmpl;
2019 2019 }
2020 2020 }
2021 2021 }
2022 2022
2023 2023 if (issvc == 0) {
2024 2024 scf_instance_t *i;
2025 2025 scf_service_t *s;
2026 2026
2027 2027 issvc = 1;
2028 2028 if (lcb->sc_flags == 1) {
2029 2029 entity_t *e = pg->sc_parent->sc_parent;
2030 2030
2031 2031 fmri = e->sc_fmri;
2032 2032 goto retry_pg;
2033 2033 }
2034 2034
2035 2035 /*
2036 2036 * because lcb->sc_flags was not set then this means
2037 2037 * the pg was not used and can be used here.
2038 2038 */
2039 2039 if ((pg = internal_pgroup_new()) == NULL) {
2040 2040 warn(gettext("Could not create internal property group "
2041 2041 "to find a missing type."));
2042 2042
2043 2043 goto out;
2044 2044 }
2045 2045
2046 2046 pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1);
2047 2047 if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name,
2048 2048 max_scf_name_len + 1) < 0)
2049 2049 goto out;
2050 2050
2051 2051 i = scf_instance_create(g_hndl);
2052 2052 s = scf_service_create(g_hndl);
2053 2053 if (i == NULL || s == NULL ||
2054 2054 scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) {
2055 2055 warn(gettext("Could not get a service for the instance "
2056 2056 "to find a missing type."));
2057 2057
2058 2058 goto out;
2059 2059 }
2060 2060
2061 2061 /*
2062 2062 * Check to see truly at the instance level.
2063 2063 */
2064 2064 lfmri = safe_malloc(max_scf_fmri_len + 1);
2065 2065 if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
2066 2066 scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0)
2067 2067 goto out;
2068 2068 else
2069 2069 fmri = (const char *)lfmri;
2070 2070
2071 2071 goto retry_pg;
2072 2072 }
2073 2073
2074 2074 out :
2075 2075 if (sc_pg != lcb->sc_parent) {
2076 2076 scf_pg_destroy(sc_pg);
2077 2077 }
2078 2078
2079 2079 /*
2080 2080 * If this is true then the pg was allocated
2081 2081 * here, and the name was set so need to free
2082 2082 * the name and the pg.
2083 2083 */
2084 2084 if (pg != NULL && pg != lcb->sc_parent) {
2085 2085 free((char *)pg->sc_pgroup_name);
2086 2086 internal_pgroup_free(pg);
2087 2087 }
2088 2088
2089 2089 if (cur_selection) {
2090 2090 lscf_select(cur_selection);
2091 2091 free(cur_selection);
2092 2092 }
2093 2093
2094 2094 scf_tmpl_pg_destroy(t_pg);
2095 2095 scf_tmpl_prop_destroy(t_prop);
2096 2096 scf_property_destroy(sc_prop);
2097 2097
2098 2098 if (r != UU_WALK_NEXT)
2099 2099 warn(gettext("Could not find property type for \"%s\" "
2100 2100 "from \"%s\"\n"), prop->sc_property_name,
2101 2101 fmri != NULL ? fmri : lcb->sc_source_fmri);
2102 2102
2103 2103 free(lfmri);
2104 2104
2105 2105 return (r);
2106 2106 }
2107 2107
2108 2108 /*
2109 2109 * Take a property group that does not have a type and check to see if a type
2110 2110 * exists or can be gleened from the current data. Set the type.
2111 2111 *
2112 2112 * Check the current level (instance) and then check the higher level
2113 2113 * (service). This could be the case for adding a new property to
2114 2114 * the instance that's going to "override" a service level property.
2115 2115 *
2116 2116 * For a property group
2117 2117 * 1. Take the type from an existing property group
2118 2118 * 2. Take the type from a template entry
2119 2119 *
2120 2120 * If the type can not be found, then leave the type as is, and let the import
2121 2121 * report the problem of the missing type.
2122 2122 */
2123 2123 static int
2124 2124 find_current_pg_type(void *p, void *sori)
2125 2125 {
2126 2126 entity_t *si = sori;
2127 2127 pgroup_t *pg = p;
2128 2128
2129 2129 const char *ofmri, *fmri;
2130 2130 char *cur_selection = NULL;
2131 2131 char *pg_type = NULL;
2132 2132
2133 2133 scf_propertygroup_t *sc_pg = NULL;
2134 2134 scf_pg_tmpl_t *t_pg = NULL;
2135 2135
2136 2136 int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2137 2137 int r = UU_WALK_ERROR;
2138 2138
2139 2139 ofmri = fmri = si->sc_fmri;
2140 2140 if (pg->sc_pgroup_type != NULL) {
2141 2141 r = UU_WALK_NEXT;
2142 2142
2143 2143 goto out;
2144 2144 }
2145 2145
2146 2146 sc_pg = scf_pg_create(g_hndl);
2147 2147 if (sc_pg == NULL) {
2148 2148 warn(gettext("Unable to create property group to attempt "
2149 2149 "and find a missing type.\n"));
2150 2150
2151 2151 return (UU_WALK_ERROR);
2152 2152 }
2153 2153
2154 2154 /*
2155 2155 * Using get_pg() requires that the cur_svc/cur_inst be
2156 2156 * via lscf_select. Need to preserve the current selection
2157 2157 * if going to use lscf_select() to set up the cur_svc/cur_inst
2158 2158 */
2159 2159 if (cur_svc) {
2160 2160 cur_selection = safe_malloc(max_scf_fmri_len + 1);
2161 2161 lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1);
2162 2162 }
2163 2163
2164 2164 /*
2165 2165 * If the property group exists get the type, and set
2166 2166 * the pgroup_t type of that type.
2167 2167 *
2168 2168 * If not the check for a template pg_pattern entry
2169 2169 * and take the type from that.
2170 2170 */
2171 2171 retry_svc:
2172 2172 lscf_select(fmri);
2173 2173
2174 2174 if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) {
2175 2175 pg_type = safe_malloc(max_scf_pg_type_len + 1);
2176 2176 if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type,
2177 2177 max_scf_pg_type_len + 1) != -1) {
2178 2178 pg->sc_pgroup_type = pg_type;
2179 2179
2180 2180 r = UU_WALK_NEXT;
2181 2181 goto out;
2182 2182 } else {
2183 2183 free(pg_type);
2184 2184 }
2185 2185 } else {
2186 2186 if ((t_pg == NULL) &&
2187 2187 (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
2188 2188 goto out;
2189 2189
2190 2190 if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name,
2191 2191 NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS &&
2192 2192 scf_tmpl_pg_type(t_pg, &pg_type) != -1) {
2193 2193 pg->sc_pgroup_type = pg_type;
2194 2194
2195 2195 r = UU_WALK_NEXT;
2196 2196 goto out;
2197 2197 }
2198 2198 }
2199 2199
2200 2200 /*
2201 2201 * If type is not found at the instance level then attempt to
2202 2202 * find the type at the service level.
2203 2203 */
2204 2204 if (!issvc) {
2205 2205 si = si->sc_parent;
2206 2206 fmri = si->sc_fmri;
2207 2207 issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2208 2208 goto retry_svc;
2209 2209 }
2210 2210
2211 2211 out :
2212 2212 if (cur_selection) {
2213 2213 lscf_select(cur_selection);
2214 2214 free(cur_selection);
2215 2215 }
2216 2216
2217 2217 /*
2218 2218 * Now walk the properties of the property group to make sure that
2219 2219 * all properties have the correct type and values are valid for
2220 2220 * those types.
2221 2221 */
2222 2222 if (r == UU_WALK_NEXT) {
2223 2223 scf_callback_t cb;
2224 2224
2225 2225 cb.sc_service = issvc;
2226 2226 cb.sc_source_fmri = ofmri;
2227 2227 if (sc_pg != NULL) {
2228 2228 cb.sc_parent = sc_pg;
2229 2229 cb.sc_flags = 0;
2230 2230 } else {
2231 2231 cb.sc_parent = pg;
2232 2232 cb.sc_flags = 1;
2233 2233 }
2234 2234
2235 2235 if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type,
2236 2236 &cb, UU_DEFAULT) != 0) {
2237 2237 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2238 2238 bad_error("uu_list_walk", uu_error());
2239 2239
2240 2240 r = UU_WALK_ERROR;
2241 2241 }
2242 2242 } else {
2243 2243 warn(gettext("Could not find property group type for "
2244 2244 "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri);
2245 2245 }
2246 2246
2247 2247 scf_tmpl_pg_destroy(t_pg);
2248 2248 scf_pg_destroy(sc_pg);
2249 2249
2250 2250 return (r);
2251 2251 }
2252 2252
2253 2253 /*
2254 2254 * Import. These functions import a bundle into the repository.
2255 2255 */
2256 2256
2257 2257 /*
2258 2258 * Add a transaction entry to lcbdata->sc_trans for this property_t. Uses
2259 2259 * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata. On success,
2260 2260 * returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
2261 2261 * lcbdata->sc_err to
2262 2262 * ENOMEM - out of memory
2263 2263 * ECONNABORTED - repository connection broken
2264 2264 * ECANCELED - sc_trans's property group was deleted
2265 2265 * EINVAL - p's name is invalid (error printed)
2266 2266 * - p has an invalid value (error printed)
2267 2267 */
2268 2268 static int
2269 2269 lscf_property_import(void *v, void *pvt)
2270 2270 {
2271 2271 property_t *p = v;
2272 2272 scf_callback_t *lcbdata = pvt;
2273 2273 value_t *vp;
2274 2274 scf_transaction_t *trans = lcbdata->sc_trans;
2275 2275 scf_transaction_entry_t *entr;
2276 2276 scf_value_t *val;
2277 2277 scf_type_t tp;
2278 2278
2279 2279 if ((lcbdata->sc_flags & SCI_NOENABLED ||
2280 2280 lcbdata->sc_flags & SCI_DELAYENABLE) &&
2281 2281 strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
2282 2282 lcbdata->sc_enable = p;
2283 2283 return (UU_WALK_NEXT);
2284 2284 }
2285 2285
2286 2286 entr = scf_entry_create(lcbdata->sc_handle);
2287 2287 if (entr == NULL) {
2288 2288 switch (scf_error()) {
2289 2289 case SCF_ERROR_NO_MEMORY:
2290 2290 return (stash_scferror(lcbdata));
2291 2291
2292 2292 case SCF_ERROR_INVALID_ARGUMENT:
2293 2293 default:
2294 2294 bad_error("scf_entry_create", scf_error());
2295 2295 }
2296 2296 }
2297 2297
2298 2298 tp = p->sc_value_type;
2299 2299
2300 2300 if (scf_transaction_property_new(trans, entr,
2301 2301 p->sc_property_name, tp) != 0) {
2302 2302 switch (scf_error()) {
2303 2303 case SCF_ERROR_INVALID_ARGUMENT:
2304 2304 semerr(emsg_invalid_prop_name, p->sc_property_name);
2305 2305 scf_entry_destroy(entr);
2306 2306 return (stash_scferror(lcbdata));
2307 2307
2308 2308 case SCF_ERROR_EXISTS:
2309 2309 break;
2310 2310
2311 2311 case SCF_ERROR_DELETED:
2312 2312 case SCF_ERROR_CONNECTION_BROKEN:
2313 2313 scf_entry_destroy(entr);
2314 2314 return (stash_scferror(lcbdata));
2315 2315
2316 2316 case SCF_ERROR_NOT_BOUND:
2317 2317 case SCF_ERROR_HANDLE_MISMATCH:
2318 2318 case SCF_ERROR_NOT_SET:
2319 2319 default:
2320 2320 bad_error("scf_transaction_property_new", scf_error());
2321 2321 }
2322 2322
2323 2323 if (scf_transaction_property_change_type(trans, entr,
2324 2324 p->sc_property_name, tp) != 0) {
2325 2325 switch (scf_error()) {
2326 2326 case SCF_ERROR_DELETED:
2327 2327 case SCF_ERROR_CONNECTION_BROKEN:
2328 2328 scf_entry_destroy(entr);
2329 2329 return (stash_scferror(lcbdata));
2330 2330
2331 2331 case SCF_ERROR_INVALID_ARGUMENT:
2332 2332 semerr(emsg_invalid_prop_name,
2333 2333 p->sc_property_name);
2334 2334 scf_entry_destroy(entr);
2335 2335 return (stash_scferror(lcbdata));
2336 2336
2337 2337 case SCF_ERROR_NOT_FOUND:
2338 2338 case SCF_ERROR_NOT_SET:
2339 2339 case SCF_ERROR_HANDLE_MISMATCH:
2340 2340 case SCF_ERROR_NOT_BOUND:
2341 2341 default:
2342 2342 bad_error(
2343 2343 "scf_transaction_property_change_type",
2344 2344 scf_error());
2345 2345 }
2346 2346 }
2347 2347 }
2348 2348
2349 2349 for (vp = uu_list_first(p->sc_property_values);
2350 2350 vp != NULL;
2351 2351 vp = uu_list_next(p->sc_property_values, vp)) {
2352 2352 val = scf_value_create(g_hndl);
2353 2353 if (val == NULL) {
2354 2354 switch (scf_error()) {
2355 2355 case SCF_ERROR_NO_MEMORY:
2356 2356 return (stash_scferror(lcbdata));
2357 2357
2358 2358 case SCF_ERROR_INVALID_ARGUMENT:
2359 2359 default:
2360 2360 bad_error("scf_value_create", scf_error());
2361 2361 }
2362 2362 }
2363 2363
2364 2364 switch (tp) {
2365 2365 case SCF_TYPE_BOOLEAN:
2366 2366 scf_value_set_boolean(val, vp->sc_u.sc_count);
2367 2367 break;
2368 2368 case SCF_TYPE_COUNT:
2369 2369 scf_value_set_count(val, vp->sc_u.sc_count);
2370 2370 break;
2371 2371 case SCF_TYPE_INTEGER:
2372 2372 scf_value_set_integer(val, vp->sc_u.sc_integer);
2373 2373 break;
2374 2374 default:
2375 2375 assert(vp->sc_u.sc_string != NULL);
2376 2376 if (scf_value_set_from_string(val, tp,
2377 2377 vp->sc_u.sc_string) != 0) {
2378 2378 if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
2379 2379 bad_error("scf_value_set_from_string",
2380 2380 scf_error());
2381 2381
2382 2382 warn(gettext("Value \"%s\" is not a valid "
2383 2383 "%s.\n"), vp->sc_u.sc_string,
2384 2384 scf_type_to_string(tp));
2385 2385 scf_value_destroy(val);
2386 2386 return (stash_scferror(lcbdata));
2387 2387 }
2388 2388 break;
2389 2389 }
2390 2390
2391 2391 if (scf_entry_add_value(entr, val) != 0)
2392 2392 bad_error("scf_entry_add_value", scf_error());
2393 2393 }
2394 2394
2395 2395 return (UU_WALK_NEXT);
2396 2396 }
2397 2397
2398 2398 /*
2399 2399 * Import a pgroup_t into the repository. Uses sc_handle, sc_parent,
2400 2400 * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2401 2401 * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2402 2402 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
2403 2403 * lcbdata->sc_err to
2404 2404 * ECONNABORTED - repository connection broken
2405 2405 * ENOMEM - out of memory
2406 2406 * ENOSPC - svc.configd is out of resources
2407 2407 * ECANCELED - sc_parent was deleted
2408 2408 * EPERM - could not create property group (permission denied) (error printed)
2409 2409 * - could not modify property group (permission denied) (error printed)
2410 2410 * - could not delete property group (permission denied) (error printed)
2411 2411 * EROFS - could not create property group (repository is read-only)
2412 2412 * - could not delete property group (repository is read-only)
2413 2413 * EACCES - could not create property group (backend access denied)
2414 2414 * - could not delete property group (backend access denied)
2415 2415 * EEXIST - could not create property group (already exists)
2416 2416 * EINVAL - invalid property group name (error printed)
2417 2417 * - invalid property name (error printed)
2418 2418 * - invalid value (error printed)
2419 2419 * EBUSY - new property group deleted (error printed)
2420 2420 * - new property group changed (error printed)
2421 2421 * - property group added (error printed)
2422 2422 * - property group deleted (error printed)
2423 2423 */
2424 2424 static int
2425 2425 entity_pgroup_import(void *v, void *pvt)
2426 2426 {
2427 2427 pgroup_t *p = v;
2428 2428 scf_callback_t cbdata;
2429 2429 scf_callback_t *lcbdata = pvt;
2430 2430 void *ent = lcbdata->sc_parent;
2431 2431 int issvc = lcbdata->sc_service;
2432 2432 int r;
2433 2433
2434 2434 const char * const pg_changed = gettext("%s changed unexpectedly "
2435 2435 "(new property group \"%s\" changed).\n");
2436 2436
2437 2437 /* Never import deleted property groups. */
2438 2438 if (p->sc_pgroup_delete) {
2439 2439 if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY &&
2440 2440 entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) {
2441 2441 goto delete_pg;
2442 2442 }
2443 2443 return (UU_WALK_NEXT);
2444 2444 }
2445 2445
2446 2446 if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
2447 2447 strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
2448 2448 lcbdata->sc_general = p;
2449 2449 return (UU_WALK_NEXT);
2450 2450 }
2451 2451
2452 2452 add_pg:
2453 2453 if (issvc)
2454 2454 r = scf_service_add_pg(ent, p->sc_pgroup_name,
2455 2455 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2456 2456 else
2457 2457 r = scf_instance_add_pg(ent, p->sc_pgroup_name,
2458 2458 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2459 2459 if (r != 0) {
2460 2460 switch (scf_error()) {
2461 2461 case SCF_ERROR_DELETED:
2462 2462 case SCF_ERROR_CONNECTION_BROKEN:
2463 2463 case SCF_ERROR_BACKEND_READONLY:
2464 2464 case SCF_ERROR_BACKEND_ACCESS:
2465 2465 case SCF_ERROR_NO_RESOURCES:
2466 2466 return (stash_scferror(lcbdata));
2467 2467
2468 2468 case SCF_ERROR_EXISTS:
2469 2469 if (lcbdata->sc_flags & SCI_FORCE)
2470 2470 break;
2471 2471 return (stash_scferror(lcbdata));
2472 2472
2473 2473 case SCF_ERROR_INVALID_ARGUMENT:
2474 2474 warn(emsg_fmri_invalid_pg_name_type,
2475 2475 lcbdata->sc_source_fmri,
2476 2476 p->sc_pgroup_name, p->sc_pgroup_type);
2477 2477 return (stash_scferror(lcbdata));
2478 2478
2479 2479 case SCF_ERROR_PERMISSION_DENIED:
2480 2480 warn(emsg_pg_add_perm, p->sc_pgroup_name,
2481 2481 lcbdata->sc_target_fmri);
2482 2482 return (stash_scferror(lcbdata));
2483 2483
2484 2484 case SCF_ERROR_NOT_BOUND:
2485 2485 case SCF_ERROR_HANDLE_MISMATCH:
2486 2486 case SCF_ERROR_NOT_SET:
2487 2487 default:
2488 2488 bad_error("scf_service_add_pg", scf_error());
2489 2489 }
2490 2490
2491 2491 if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2492 2492 switch (scf_error()) {
2493 2493 case SCF_ERROR_CONNECTION_BROKEN:
2494 2494 case SCF_ERROR_DELETED:
2495 2495 return (stash_scferror(lcbdata));
2496 2496
2497 2497 case SCF_ERROR_INVALID_ARGUMENT:
2498 2498 warn(emsg_fmri_invalid_pg_name,
2499 2499 lcbdata->sc_source_fmri,
2500 2500 p->sc_pgroup_name);
2501 2501 return (stash_scferror(lcbdata));
2502 2502
2503 2503 case SCF_ERROR_NOT_FOUND:
2504 2504 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2505 2505 p->sc_pgroup_name);
2506 2506 lcbdata->sc_err = EBUSY;
2507 2507 return (UU_WALK_ERROR);
2508 2508
2509 2509 case SCF_ERROR_NOT_BOUND:
2510 2510 case SCF_ERROR_HANDLE_MISMATCH:
2511 2511 case SCF_ERROR_NOT_SET:
2512 2512 default:
2513 2513 bad_error("entity_get_pg", scf_error());
2514 2514 }
2515 2515 }
2516 2516
2517 2517 if (lcbdata->sc_flags & SCI_KEEP)
2518 2518 goto props;
2519 2519
2520 2520 delete_pg:
2521 2521 if (scf_pg_delete(imp_pg) != 0) {
2522 2522 switch (scf_error()) {
2523 2523 case SCF_ERROR_DELETED:
2524 2524 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2525 2525 p->sc_pgroup_name);
2526 2526 lcbdata->sc_err = EBUSY;
2527 2527 return (UU_WALK_ERROR);
2528 2528
2529 2529 case SCF_ERROR_PERMISSION_DENIED:
2530 2530 warn(emsg_pg_del_perm, p->sc_pgroup_name,
2531 2531 lcbdata->sc_target_fmri);
2532 2532 return (stash_scferror(lcbdata));
2533 2533
2534 2534 case SCF_ERROR_BACKEND_READONLY:
2535 2535 case SCF_ERROR_BACKEND_ACCESS:
2536 2536 case SCF_ERROR_CONNECTION_BROKEN:
2537 2537 return (stash_scferror(lcbdata));
2538 2538
2539 2539 case SCF_ERROR_NOT_SET:
2540 2540 default:
2541 2541 bad_error("scf_pg_delete", scf_error());
2542 2542 }
2543 2543 }
2544 2544
2545 2545 if (p->sc_pgroup_delete)
2546 2546 return (UU_WALK_NEXT);
2547 2547
2548 2548 goto add_pg;
2549 2549 }
2550 2550
2551 2551 props:
2552 2552
2553 2553 /*
2554 2554 * Add properties to property group, if any.
2555 2555 */
2556 2556 cbdata.sc_handle = lcbdata->sc_handle;
2557 2557 cbdata.sc_parent = imp_pg;
2558 2558 cbdata.sc_flags = lcbdata->sc_flags;
2559 2559 cbdata.sc_trans = imp_tx;
2560 2560 cbdata.sc_enable = NULL;
2561 2561
2562 2562 if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2563 2563 switch (scf_error()) {
2564 2564 case SCF_ERROR_BACKEND_ACCESS:
2565 2565 case SCF_ERROR_BACKEND_READONLY:
2566 2566 case SCF_ERROR_CONNECTION_BROKEN:
2567 2567 return (stash_scferror(lcbdata));
2568 2568
2569 2569 case SCF_ERROR_DELETED:
2570 2570 warn(pg_changed, lcbdata->sc_target_fmri,
2571 2571 p->sc_pgroup_name);
2572 2572 lcbdata->sc_err = EBUSY;
2573 2573 return (UU_WALK_ERROR);
2574 2574
2575 2575 case SCF_ERROR_PERMISSION_DENIED:
2576 2576 warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2577 2577 lcbdata->sc_target_fmri);
2578 2578 return (stash_scferror(lcbdata));
2579 2579
2580 2580 case SCF_ERROR_NOT_BOUND:
2581 2581 case SCF_ERROR_NOT_SET:
2582 2582 case SCF_ERROR_IN_USE:
2583 2583 case SCF_ERROR_HANDLE_MISMATCH:
2584 2584 default:
2585 2585 bad_error("scf_transaction_start", scf_error());
2586 2586 }
2587 2587 }
2588 2588
2589 2589 if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2590 2590 UU_DEFAULT) != 0) {
2591 2591 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2592 2592 bad_error("uu_list_walk", uu_error());
2593 2593 scf_transaction_reset(imp_tx);
2594 2594
2595 2595 lcbdata->sc_err = cbdata.sc_err;
2596 2596 if (cbdata.sc_err == ECANCELED) {
2597 2597 warn(pg_changed, lcbdata->sc_target_fmri,
2598 2598 p->sc_pgroup_name);
2599 2599 lcbdata->sc_err = EBUSY;
2600 2600 }
2601 2601 return (UU_WALK_ERROR);
2602 2602 }
2603 2603
2604 2604 if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2605 2605 cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2606 2606
2607 2607 /*
2608 2608 * take the snapshot running snapshot then
2609 2609 * import the stored general/enable property
2610 2610 */
2611 2611 r = take_snap(ent, snap_running, imp_rsnap);
2612 2612 switch (r) {
2613 2613 case 0:
2614 2614 break;
2615 2615
2616 2616 case ECONNABORTED:
2617 2617 warn(gettext("Could not take %s snapshot on import "
2618 2618 "(repository connection broken).\n"),
2619 2619 snap_running);
2620 2620 lcbdata->sc_err = r;
2621 2621 return (UU_WALK_ERROR);
2622 2622 case ECANCELED:
2623 2623 warn(emsg_deleted);
2624 2624 lcbdata->sc_err = r;
2625 2625 return (UU_WALK_ERROR);
2626 2626
2627 2627 case EPERM:
2628 2628 warn(gettext("Could not take %s snapshot "
2629 2629 "(permission denied).\n"), snap_running);
2630 2630 lcbdata->sc_err = r;
2631 2631 return (UU_WALK_ERROR);
2632 2632
2633 2633 case ENOSPC:
2634 2634 warn(gettext("Could not take %s snapshot"
2635 2635 "(repository server out of resources).\n"),
2636 2636 snap_running);
2637 2637 lcbdata->sc_err = r;
2638 2638 return (UU_WALK_ERROR);
2639 2639
2640 2640 default:
2641 2641 bad_error("take_snap", r);
2642 2642 }
2643 2643
2644 2644 r = lscf_property_import(cbdata.sc_enable, &cbdata);
2645 2645 if (r != UU_WALK_NEXT) {
2646 2646 if (r != UU_WALK_ERROR)
2647 2647 bad_error("lscf_property_import", r);
2648 2648 return (EINVAL);
2649 2649 }
2650 2650 }
2651 2651
2652 2652 r = scf_transaction_commit(imp_tx);
2653 2653 switch (r) {
2654 2654 case 1:
2655 2655 r = UU_WALK_NEXT;
2656 2656 break;
2657 2657
2658 2658 case 0:
2659 2659 warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2660 2660 lcbdata->sc_err = EBUSY;
2661 2661 r = UU_WALK_ERROR;
2662 2662 break;
2663 2663
2664 2664 case -1:
2665 2665 switch (scf_error()) {
2666 2666 case SCF_ERROR_BACKEND_READONLY:
2667 2667 case SCF_ERROR_BACKEND_ACCESS:
2668 2668 case SCF_ERROR_CONNECTION_BROKEN:
2669 2669 case SCF_ERROR_NO_RESOURCES:
2670 2670 r = stash_scferror(lcbdata);
2671 2671 break;
2672 2672
2673 2673 case SCF_ERROR_DELETED:
2674 2674 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2675 2675 p->sc_pgroup_name);
2676 2676 lcbdata->sc_err = EBUSY;
2677 2677 r = UU_WALK_ERROR;
2678 2678 break;
2679 2679
2680 2680 case SCF_ERROR_PERMISSION_DENIED:
2681 2681 warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2682 2682 lcbdata->sc_target_fmri);
2683 2683 r = stash_scferror(lcbdata);
2684 2684 break;
2685 2685
2686 2686 case SCF_ERROR_NOT_SET:
2687 2687 case SCF_ERROR_INVALID_ARGUMENT:
2688 2688 case SCF_ERROR_NOT_BOUND:
2689 2689 default:
2690 2690 bad_error("scf_transaction_commit", scf_error());
2691 2691 }
2692 2692 break;
2693 2693
2694 2694 default:
2695 2695 bad_error("scf_transaction_commit", r);
2696 2696 }
2697 2697
2698 2698 scf_transaction_destroy_children(imp_tx);
2699 2699
2700 2700 return (r);
2701 2701 }
2702 2702
2703 2703 /*
2704 2704 * Returns
2705 2705 * 0 - success
2706 2706 * ECONNABORTED - repository connection broken
2707 2707 * ENOMEM - out of memory
2708 2708 * ENOSPC - svc.configd is out of resources
2709 2709 * ECANCELED - inst was deleted
2710 2710 * EPERM - could not create property group (permission denied) (error printed)
2711 2711 * - could not modify property group (permission denied) (error printed)
2712 2712 * EROFS - could not create property group (repository is read-only)
2713 2713 * EACCES - could not create property group (backend access denied)
2714 2714 * EEXIST - could not create property group (already exists)
2715 2715 * EINVAL - invalid property group name (error printed)
2716 2716 * - invalid property name (error printed)
2717 2717 * - invalid value (error printed)
2718 2718 * EBUSY - new property group changed (error printed)
2719 2719 */
2720 2720 static int
2721 2721 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2722 2722 const entity_t *isvc, int flags)
2723 2723 {
2724 2724 scf_callback_t cbdata;
2725 2725
2726 2726 cbdata.sc_handle = scf_service_handle(svc);
2727 2727 cbdata.sc_parent = svc;
2728 2728 cbdata.sc_service = 1;
2729 2729 cbdata.sc_general = 0;
2730 2730 cbdata.sc_enable = 0;
2731 2731 cbdata.sc_flags = flags;
2732 2732 cbdata.sc_source_fmri = isvc->sc_fmri;
2733 2733 cbdata.sc_target_fmri = target_fmri;
2734 2734
2735 2735 /*
2736 2736 * If the op is set, then add the flag to the callback
2737 2737 * flags for later use.
2738 2738 */
2739 2739 if (isvc->sc_op != SVCCFG_OP_NONE) {
2740 2740 switch (isvc->sc_op) {
2741 2741 case SVCCFG_OP_IMPORT :
2742 2742 cbdata.sc_flags |= SCI_OP_IMPORT;
2743 2743 break;
2744 2744 case SVCCFG_OP_APPLY :
2745 2745 cbdata.sc_flags |= SCI_OP_APPLY;
2746 2746 break;
2747 2747 case SVCCFG_OP_RESTORE :
2748 2748 cbdata.sc_flags |= SCI_OP_RESTORE;
2749 2749 break;
2750 2750 default :
2751 2751 uu_die(gettext("lscf_import_service_pgs : "
2752 2752 "Unknown op stored in the service entity\n"));
2753 2753
2754 2754 }
2755 2755 }
2756 2756
2757 2757 if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2758 2758 UU_DEFAULT) != 0) {
2759 2759 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2760 2760 bad_error("uu_list_walk", uu_error());
2761 2761
2762 2762 return (cbdata.sc_err);
2763 2763 }
2764 2764
2765 2765 return (0);
2766 2766 }
2767 2767
2768 2768 /*
2769 2769 * Returns
2770 2770 * 0 - success
2771 2771 * ECONNABORTED - repository connection broken
2772 2772 * ENOMEM - out of memory
2773 2773 * ENOSPC - svc.configd is out of resources
2774 2774 * ECANCELED - inst was deleted
2775 2775 * EPERM - could not create property group (permission denied) (error printed)
2776 2776 * - could not modify property group (permission denied) (error printed)
2777 2777 * EROFS - could not create property group (repository is read-only)
2778 2778 * EACCES - could not create property group (backend access denied)
2779 2779 * EEXIST - could not create property group (already exists)
2780 2780 * EINVAL - invalid property group name (error printed)
2781 2781 * - invalid property name (error printed)
2782 2782 * - invalid value (error printed)
2783 2783 * EBUSY - new property group changed (error printed)
2784 2784 */
2785 2785 static int
2786 2786 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2787 2787 const entity_t *iinst, int flags)
2788 2788 {
2789 2789 scf_callback_t cbdata;
2790 2790
2791 2791 cbdata.sc_handle = scf_instance_handle(inst);
2792 2792 cbdata.sc_parent = inst;
2793 2793 cbdata.sc_service = 0;
2794 2794 cbdata.sc_general = NULL;
2795 2795 cbdata.sc_enable = NULL;
2796 2796 cbdata.sc_flags = flags;
2797 2797 cbdata.sc_source_fmri = iinst->sc_fmri;
2798 2798 cbdata.sc_target_fmri = target_fmri;
2799 2799
2800 2800 /*
2801 2801 * If the op is set, then add the flag to the callback
2802 2802 * flags for later use.
2803 2803 */
2804 2804 if (iinst->sc_op != SVCCFG_OP_NONE) {
2805 2805 switch (iinst->sc_op) {
2806 2806 case SVCCFG_OP_IMPORT :
2807 2807 cbdata.sc_flags |= SCI_OP_IMPORT;
2808 2808 break;
2809 2809 case SVCCFG_OP_APPLY :
2810 2810 cbdata.sc_flags |= SCI_OP_APPLY;
2811 2811 break;
2812 2812 case SVCCFG_OP_RESTORE :
2813 2813 cbdata.sc_flags |= SCI_OP_RESTORE;
2814 2814 break;
2815 2815 default :
2816 2816 uu_die(gettext("lscf_import_instance_pgs : "
2817 2817 "Unknown op stored in the instance entity\n"));
2818 2818 }
2819 2819 }
2820 2820
2821 2821 if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2822 2822 UU_DEFAULT) != 0) {
2823 2823 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2824 2824 bad_error("uu_list_walk", uu_error());
2825 2825
2826 2826 return (cbdata.sc_err);
2827 2827 }
2828 2828
2829 2829 if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2830 2830 cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2831 2831 /*
2832 2832 * If importing with the SCI_NOENABLED flag then
2833 2833 * skip the delay, but if not then add the delay
2834 2834 * of the enable property.
2835 2835 */
2836 2836 if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2837 2837 cbdata.sc_flags |= SCI_DELAYENABLE;
2838 2838 }
2839 2839
2840 2840 if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2841 2841 != UU_WALK_NEXT)
2842 2842 return (cbdata.sc_err);
2843 2843 }
2844 2844
2845 2845 return (0);
2846 2846 }
2847 2847
2848 2848 /*
2849 2849 * Report the reasons why we can't upgrade pg2 to pg1.
2850 2850 */
2851 2851 static void
2852 2852 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2853 2853 int new)
2854 2854 {
2855 2855 property_t *p1, *p2;
2856 2856
2857 2857 assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2858 2858
2859 2859 if (!pg_attrs_equal(pg1, pg2, fmri, new))
2860 2860 return;
2861 2861
2862 2862 for (p1 = uu_list_first(pg1->sc_pgroup_props);
2863 2863 p1 != NULL;
2864 2864 p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2865 2865 p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2866 2866 if (p2 != NULL) {
2867 2867 (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2868 2868 new);
2869 2869 continue;
2870 2870 }
2871 2871
2872 2872 if (new)
2873 2873 warn(gettext("Conflict upgrading %s (new property "
2874 2874 "group \"%s\" is missing property \"%s\").\n"),
2875 2875 fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2876 2876 else
2877 2877 warn(gettext("Conflict upgrading %s (property "
2878 2878 "\"%s/%s\" is missing).\n"), fmri,
2879 2879 pg1->sc_pgroup_name, p1->sc_property_name);
2880 2880 }
2881 2881
2882 2882 /*
2883 2883 * Since pg1 should be from the manifest, any properties in pg2 which
2884 2884 * aren't in pg1 shouldn't be reported as conflicts.
2885 2885 */
2886 2886 }
2887 2887
2888 2888 /*
2889 2889 * Add transaction entries to tx which will upgrade cur's pg according to old
2890 2890 * & new.
2891 2891 *
2892 2892 * Returns
2893 2893 * 0 - success
2894 2894 * EINVAL - new has a property with an invalid name or value (message emitted)
2895 2895 * ENOMEM - out of memory
2896 2896 */
2897 2897 static int
2898 2898 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2899 2899 pgroup_t *cur, int speak, const char *fmri)
2900 2900 {
2901 2901 property_t *p, *new_p, *cur_p;
2902 2902 scf_transaction_entry_t *e;
2903 2903 int r;
2904 2904 int is_general;
2905 2905 int is_protected;
2906 2906
2907 2907 if (uu_list_walk(new->sc_pgroup_props, clear_int,
2908 2908 (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2909 2909 bad_error("uu_list_walk", uu_error());
2910 2910
2911 2911 is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2912 2912
2913 2913 for (p = uu_list_first(old->sc_pgroup_props);
2914 2914 p != NULL;
2915 2915 p = uu_list_next(old->sc_pgroup_props, p)) {
2916 2916 /* p is a property in the old property group. */
2917 2917
2918 2918 /* Protect live properties. */
2919 2919 is_protected = 0;
2920 2920 if (is_general) {
2921 2921 if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2922 2922 0 ||
2923 2923 strcmp(p->sc_property_name,
2924 2924 SCF_PROPERTY_RESTARTER) == 0)
2925 2925 is_protected = 1;
2926 2926 }
2927 2927
2928 2928 /* Look for the same property in the new properties. */
2929 2929 new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2930 2930 if (new_p != NULL) {
2931 2931 new_p->sc_seen = 1;
2932 2932
2933 2933 /*
2934 2934 * If the new property is the same as the old, don't do
2935 2935 * anything (leave any user customizations).
2936 2936 */
2937 2937 if (prop_equal(p, new_p, NULL, NULL, 0))
2938 2938 continue;
2939 2939
2940 2940 if (new_p->sc_property_override)
2941 2941 goto upgrade;
2942 2942 }
2943 2943
2944 2944 cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2945 2945 if (cur_p == NULL) {
2946 2946 /*
2947 2947 * p has been deleted from the repository. If we were
2948 2948 * going to delete it anyway, do nothing. Otherwise
2949 2949 * report a conflict.
2950 2950 */
2951 2951 if (new_p == NULL)
2952 2952 continue;
2953 2953
2954 2954 if (is_protected)
2955 2955 continue;
2956 2956
2957 2957 warn(gettext("Conflict upgrading %s "
2958 2958 "(property \"%s/%s\" is missing).\n"), fmri,
2959 2959 old->sc_pgroup_name, p->sc_property_name);
2960 2960 continue;
2961 2961 }
2962 2962
2963 2963 if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2964 2964 /*
2965 2965 * Conflict. Don't warn if the property is already the
2966 2966 * way we want it, though.
2967 2967 */
2968 2968 if (is_protected)
2969 2969 continue;
2970 2970
2971 2971 if (new_p == NULL)
2972 2972 (void) prop_equal(p, cur_p, fmri,
2973 2973 old->sc_pgroup_name, 0);
2974 2974 else
2975 2975 (void) prop_equal(cur_p, new_p, fmri,
2976 2976 old->sc_pgroup_name, 0);
2977 2977 continue;
2978 2978 }
2979 2979
2980 2980 if (is_protected) {
2981 2981 if (speak)
2982 2982 warn(gettext("%s: Refusing to upgrade "
2983 2983 "\"%s/%s\" (live property).\n"), fmri,
2984 2984 old->sc_pgroup_name, p->sc_property_name);
2985 2985 continue;
2986 2986 }
2987 2987
2988 2988 upgrade:
2989 2989 /* p hasn't been customized in the repository. Upgrade it. */
2990 2990 if (new_p == NULL) {
2991 2991 /* p was deleted. Delete from cur if unchanged. */
2992 2992 if (speak)
2993 2993 warn(gettext(
2994 2994 "%s: Deleting property \"%s/%s\".\n"),
2995 2995 fmri, old->sc_pgroup_name,
2996 2996 p->sc_property_name);
2997 2997
2998 2998 e = scf_entry_create(g_hndl);
2999 2999 if (e == NULL)
3000 3000 return (ENOMEM);
3001 3001
3002 3002 if (scf_transaction_property_delete(tx, e,
3003 3003 p->sc_property_name) != 0) {
3004 3004 switch (scf_error()) {
3005 3005 case SCF_ERROR_DELETED:
3006 3006 scf_entry_destroy(e);
3007 3007 return (ECANCELED);
3008 3008
3009 3009 case SCF_ERROR_CONNECTION_BROKEN:
3010 3010 scf_entry_destroy(e);
3011 3011 return (ECONNABORTED);
3012 3012
3013 3013 case SCF_ERROR_NOT_FOUND:
3014 3014 /*
3015 3015 * This can happen if cur is from the
3016 3016 * running snapshot (and it differs
3017 3017 * from the live properties).
3018 3018 */
3019 3019 scf_entry_destroy(e);
3020 3020 break;
3021 3021
3022 3022 case SCF_ERROR_HANDLE_MISMATCH:
3023 3023 case SCF_ERROR_NOT_BOUND:
3024 3024 case SCF_ERROR_NOT_SET:
3025 3025 case SCF_ERROR_INVALID_ARGUMENT:
3026 3026 default:
3027 3027 bad_error(
3028 3028 "scf_transaction_property_delete",
3029 3029 scf_error());
3030 3030 }
3031 3031 }
3032 3032 } else {
3033 3033 scf_callback_t ctx;
3034 3034
3035 3035 if (speak)
3036 3036 warn(gettext(
3037 3037 "%s: Upgrading property \"%s/%s\".\n"),
3038 3038 fmri, old->sc_pgroup_name,
3039 3039 p->sc_property_name);
3040 3040
3041 3041 ctx.sc_handle = g_hndl;
3042 3042 ctx.sc_trans = tx;
3043 3043 ctx.sc_flags = 0;
3044 3044
3045 3045 r = lscf_property_import(new_p, &ctx);
3046 3046 if (r != UU_WALK_NEXT) {
3047 3047 if (r != UU_WALK_ERROR)
3048 3048 bad_error("lscf_property_import", r);
3049 3049 return (EINVAL);
3050 3050 }
3051 3051 }
3052 3052 }
3053 3053
3054 3054 /* Go over the properties which were added. */
3055 3055 for (new_p = uu_list_first(new->sc_pgroup_props);
3056 3056 new_p != NULL;
3057 3057 new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
3058 3058 if (new_p->sc_seen)
3059 3059 continue;
3060 3060
3061 3061 /* This is a new property. */
3062 3062 cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
3063 3063 if (cur_p == NULL) {
3064 3064 scf_callback_t ctx;
3065 3065
3066 3066 ctx.sc_handle = g_hndl;
3067 3067 ctx.sc_trans = tx;
3068 3068 ctx.sc_flags = 0;
3069 3069
3070 3070 r = lscf_property_import(new_p, &ctx);
3071 3071 if (r != UU_WALK_NEXT) {
3072 3072 if (r != UU_WALK_ERROR)
3073 3073 bad_error("lscf_property_import", r);
3074 3074 return (EINVAL);
3075 3075 }
3076 3076 continue;
3077 3077 }
3078 3078
3079 3079 /*
3080 3080 * Report a conflict if the new property differs from the
3081 3081 * current one. Unless it's general/enabled, since that's
3082 3082 * never in the last-import snapshot.
3083 3083 */
3084 3084 if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
3085 3085 0 &&
3086 3086 strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
3087 3087 continue;
3088 3088
3089 3089 (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
3090 3090 }
3091 3091
3092 3092 return (0);
3093 3093 }
3094 3094
3095 3095 /*
3096 3096 * Upgrade pg according to old & new.
3097 3097 *
3098 3098 * Returns
3099 3099 * 0 - success
3100 3100 * ECONNABORTED - repository connection broken
3101 3101 * ENOMEM - out of memory
3102 3102 * ENOSPC - svc.configd is out of resources
3103 3103 * ECANCELED - pg was deleted
3104 3104 * EPERM - couldn't modify pg (permission denied)
3105 3105 * EROFS - couldn't modify pg (backend read-only)
3106 3106 * EACCES - couldn't modify pg (backend access denied)
3107 3107 * EINVAL - new has a property with invalid name or value (error printed)
3108 3108 * EBUSY - pg changed unexpectedly
3109 3109 */
3110 3110 static int
3111 3111 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
3112 3112 pgroup_t *new, int speak, const char *fmri)
3113 3113 {
3114 3114 int r;
3115 3115
3116 3116 if (scf_transaction_start(imp_tx, pg) != 0) {
3117 3117 switch (scf_error()) {
3118 3118 case SCF_ERROR_CONNECTION_BROKEN:
3119 3119 case SCF_ERROR_DELETED:
3120 3120 case SCF_ERROR_PERMISSION_DENIED:
3121 3121 case SCF_ERROR_BACKEND_READONLY:
3122 3122 case SCF_ERROR_BACKEND_ACCESS:
3123 3123 return (scferror2errno(scf_error()));
3124 3124
3125 3125 case SCF_ERROR_HANDLE_MISMATCH:
3126 3126 case SCF_ERROR_IN_USE:
3127 3127 case SCF_ERROR_NOT_BOUND:
3128 3128 case SCF_ERROR_NOT_SET:
3129 3129 default:
3130 3130 bad_error("scf_transaction_start", scf_error());
3131 3131 }
3132 3132 }
3133 3133
3134 3134 r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
3135 3135 switch (r) {
3136 3136 case 0:
3137 3137 break;
3138 3138
3139 3139 case EINVAL:
3140 3140 case ENOMEM:
3141 3141 scf_transaction_destroy_children(imp_tx);
3142 3142 return (r);
3143 3143
3144 3144 default:
3145 3145 bad_error("add_upgrade_entries", r);
3146 3146 }
3147 3147
3148 3148 r = scf_transaction_commit(imp_tx);
3149 3149
3150 3150 scf_transaction_destroy_children(imp_tx);
3151 3151
3152 3152 switch (r) {
3153 3153 case 1:
3154 3154 break;
3155 3155
3156 3156 case 0:
3157 3157 return (EBUSY);
3158 3158
3159 3159 case -1:
3160 3160 switch (scf_error()) {
3161 3161 case SCF_ERROR_CONNECTION_BROKEN:
3162 3162 case SCF_ERROR_NO_RESOURCES:
3163 3163 case SCF_ERROR_PERMISSION_DENIED:
3164 3164 case SCF_ERROR_BACKEND_READONLY:
3165 3165 case SCF_ERROR_BACKEND_ACCESS:
3166 3166 case SCF_ERROR_DELETED:
3167 3167 return (scferror2errno(scf_error()));
3168 3168
3169 3169 case SCF_ERROR_NOT_BOUND:
3170 3170 case SCF_ERROR_INVALID_ARGUMENT:
3171 3171 case SCF_ERROR_NOT_SET:
3172 3172 default:
3173 3173 bad_error("scf_transaction_commit", scf_error());
3174 3174 }
3175 3175
3176 3176 default:
3177 3177 bad_error("scf_transaction_commit", r);
3178 3178 }
3179 3179
3180 3180 return (0);
3181 3181 }
3182 3182
3183 3183 /*
3184 3184 * Compares two entity FMRIs. Returns
3185 3185 *
3186 3186 * 1 - equal
3187 3187 * 0 - not equal
3188 3188 * -1 - f1 is invalid or not an entity
3189 3189 * -2 - f2 is invalid or not an entity
3190 3190 */
3191 3191 static int
3192 3192 fmri_equal(const char *f1, const char *f2)
3193 3193 {
3194 3194 int r;
3195 3195 const char *s1, *i1, *pg1;
3196 3196 const char *s2, *i2, *pg2;
3197 3197
3198 3198 if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3199 3199 return (-1);
3200 3200 if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
3201 3201 return (-1);
3202 3202
3203 3203 if (s1 == NULL || pg1 != NULL)
3204 3204 return (-1);
3205 3205
3206 3206 if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3207 3207 return (-2);
3208 3208 if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
3209 3209 return (-2);
3210 3210
3211 3211 if (s2 == NULL || pg2 != NULL)
3212 3212 return (-2);
3213 3213
3214 3214 r = strcmp(s1, s2);
3215 3215 if (r != 0)
3216 3216 return (0);
3217 3217
3218 3218 if (i1 == NULL && i2 == NULL)
3219 3219 return (1);
3220 3220
3221 3221 if (i1 == NULL || i2 == NULL)
3222 3222 return (0);
3223 3223
3224 3224 return (strcmp(i1, i2) == 0);
3225 3225 }
3226 3226
3227 3227 /*
3228 3228 * Import a dependent by creating a dependency property group in the dependent
3229 3229 * entity. If lcbdata->sc_trans is set, assume it's been started on the
3230 3230 * dependents pg, and add an entry to create a new property for this
3231 3231 * dependent. Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3232 3232 *
3233 3233 * On success, returns UU_WALK_NEXT. On error, returns UU_WALK_ERROR and sets
3234 3234 * lcbdata->sc_err to
3235 3235 * ECONNABORTED - repository connection broken
3236 3236 * ENOMEM - out of memory
3237 3237 * ENOSPC - configd is out of resources
3238 3238 * EINVAL - target is invalid (error printed)
3239 3239 * - target is not an entity (error printed)
3240 3240 * - dependent has invalid name (error printed)
3241 3241 * - invalid property name (error printed)
3242 3242 * - invalid value (error printed)
3243 3243 * - scope of target does not exist (error printed)
3244 3244 * EPERM - couldn't create target (permission denied) (error printed)
3245 3245 * - couldn't create dependency pg (permission denied) (error printed)
3246 3246 * - couldn't modify dependency pg (permission denied) (error printed)
3247 3247 * EROFS - couldn't create target (repository read-only)
3248 3248 * - couldn't create dependency pg (repository read-only)
3249 3249 * EACCES - couldn't create target (backend access denied)
3250 3250 * - couldn't create dependency pg (backend access denied)
3251 3251 * ECANCELED - sc_trans's pg was deleted
3252 3252 * EALREADY - property for dependent already exists in sc_trans's pg
3253 3253 * EEXIST - dependency pg already exists in target (error printed)
3254 3254 * EBUSY - target deleted (error printed)
3255 3255 * - property group changed during import (error printed)
3256 3256 */
3257 3257 static int
3258 3258 lscf_dependent_import(void *a1, void *pvt)
3259 3259 {
3260 3260 pgroup_t *pgrp = a1;
3261 3261 scf_callback_t *lcbdata = pvt;
3262 3262
3263 3263 int isservice;
3264 3264 int ret;
3265 3265 scf_transaction_entry_t *e;
3266 3266 scf_value_t *val;
3267 3267 scf_callback_t dependent_cbdata;
3268 3268 scf_error_t scfe;
3269 3269
3270 3270 /*
3271 3271 * Decode the FMRI into dependent_cbdata->sc_parent. Do it here so if
3272 3272 * it's invalid, we fail before modifying the repository.
3273 3273 */
3274 3274 scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3275 3275 &dependent_cbdata.sc_parent, &isservice);
3276 3276 switch (scfe) {
3277 3277 case SCF_ERROR_NONE:
3278 3278 break;
3279 3279
3280 3280 case SCF_ERROR_NO_MEMORY:
3281 3281 return (stash_scferror_err(lcbdata, scfe));
3282 3282
3283 3283 case SCF_ERROR_INVALID_ARGUMENT:
3284 3284 semerr(gettext("The FMRI for the \"%s\" dependent is "
3285 3285 "invalid.\n"), pgrp->sc_pgroup_name);
3286 3286 return (stash_scferror_err(lcbdata, scfe));
3287 3287
3288 3288 case SCF_ERROR_CONSTRAINT_VIOLATED:
3289 3289 semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3290 3290 "specifies neither a service nor an instance.\n"),
3291 3291 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3292 3292 return (stash_scferror_err(lcbdata, scfe));
3293 3293
3294 3294 case SCF_ERROR_NOT_FOUND:
3295 3295 scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3296 3296 &dependent_cbdata.sc_parent, &isservice);
3297 3297 switch (scfe) {
3298 3298 case SCF_ERROR_NONE:
3299 3299 break;
3300 3300
3301 3301 case SCF_ERROR_NO_MEMORY:
3302 3302 case SCF_ERROR_BACKEND_READONLY:
3303 3303 case SCF_ERROR_BACKEND_ACCESS:
3304 3304 return (stash_scferror_err(lcbdata, scfe));
3305 3305
3306 3306 case SCF_ERROR_NOT_FOUND:
3307 3307 semerr(gettext("The scope in FMRI \"%s\" for the "
3308 3308 "\"%s\" dependent does not exist.\n"),
3309 3309 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3310 3310 lcbdata->sc_err = EINVAL;
3311 3311 return (UU_WALK_ERROR);
3312 3312
3313 3313 case SCF_ERROR_PERMISSION_DENIED:
3314 3314 warn(gettext(
3315 3315 "Could not create %s (permission denied).\n"),
3316 3316 pgrp->sc_pgroup_fmri);
3317 3317 return (stash_scferror_err(lcbdata, scfe));
3318 3318
3319 3319 case SCF_ERROR_INVALID_ARGUMENT:
3320 3320 case SCF_ERROR_CONSTRAINT_VIOLATED:
3321 3321 default:
3322 3322 bad_error("create_entity", scfe);
3323 3323 }
3324 3324 break;
3325 3325
3326 3326 default:
3327 3327 bad_error("fmri_to_entity", scfe);
3328 3328 }
3329 3329
3330 3330 if (lcbdata->sc_trans != NULL) {
3331 3331 e = scf_entry_create(lcbdata->sc_handle);
3332 3332 if (e == NULL) {
3333 3333 if (scf_error() != SCF_ERROR_NO_MEMORY)
3334 3334 bad_error("scf_entry_create", scf_error());
3335 3335
3336 3336 entity_destroy(dependent_cbdata.sc_parent, isservice);
3337 3337 return (stash_scferror(lcbdata));
3338 3338 }
3339 3339
3340 3340 if (scf_transaction_property_new(lcbdata->sc_trans, e,
3341 3341 pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
3342 3342 switch (scf_error()) {
3343 3343 case SCF_ERROR_INVALID_ARGUMENT:
3344 3344 warn(gettext("Dependent of %s has invalid name "
3345 3345 "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
3346 3346 pgrp->sc_pgroup_name);
3347 3347 /* FALLTHROUGH */
3348 3348
3349 3349 case SCF_ERROR_DELETED:
3350 3350 case SCF_ERROR_CONNECTION_BROKEN:
3351 3351 scf_entry_destroy(e);
3352 3352 entity_destroy(dependent_cbdata.sc_parent,
3353 3353 isservice);
3354 3354 return (stash_scferror(lcbdata));
3355 3355
3356 3356 case SCF_ERROR_EXISTS:
3357 3357 scf_entry_destroy(e);
3358 3358 entity_destroy(dependent_cbdata.sc_parent,
3359 3359 isservice);
3360 3360 lcbdata->sc_err = EALREADY;
3361 3361 return (UU_WALK_ERROR);
3362 3362
3363 3363 case SCF_ERROR_NOT_BOUND:
3364 3364 case SCF_ERROR_HANDLE_MISMATCH:
3365 3365 case SCF_ERROR_NOT_SET:
3366 3366 default:
3367 3367 bad_error("scf_transaction_property_new",
3368 3368 scf_error());
3369 3369 }
3370 3370 }
3371 3371
3372 3372 val = scf_value_create(lcbdata->sc_handle);
3373 3373 if (val == NULL) {
3374 3374 if (scf_error() != SCF_ERROR_NO_MEMORY)
3375 3375 bad_error("scf_value_create", scf_error());
3376 3376
3377 3377 entity_destroy(dependent_cbdata.sc_parent, isservice);
3378 3378 return (stash_scferror(lcbdata));
3379 3379 }
3380 3380
3381 3381 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
3382 3382 pgrp->sc_pgroup_fmri) != 0)
3383 3383 /* invalid should have been caught above */
3384 3384 bad_error("scf_value_set_from_string", scf_error());
3385 3385
3386 3386 if (scf_entry_add_value(e, val) != 0)
3387 3387 bad_error("scf_entry_add_value", scf_error());
3388 3388 }
3389 3389
3390 3390 /* Add the property group to the target entity. */
3391 3391
3392 3392 dependent_cbdata.sc_handle = lcbdata->sc_handle;
3393 3393 dependent_cbdata.sc_flags = lcbdata->sc_flags;
3394 3394 dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
3395 3395 dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
3396 3396
3397 3397 ret = entity_pgroup_import(pgrp, &dependent_cbdata);
3398 3398
3399 3399 entity_destroy(dependent_cbdata.sc_parent, isservice);
3400 3400
3401 3401 if (ret == UU_WALK_NEXT)
3402 3402 return (ret);
3403 3403
3404 3404 if (ret != UU_WALK_ERROR)
3405 3405 bad_error("entity_pgroup_import", ret);
3406 3406
3407 3407 switch (dependent_cbdata.sc_err) {
3408 3408 case ECANCELED:
3409 3409 warn(gettext("%s deleted unexpectedly.\n"),
3410 3410 pgrp->sc_pgroup_fmri);
3411 3411 lcbdata->sc_err = EBUSY;
3412 3412 break;
3413 3413
3414 3414 case EEXIST:
3415 3415 warn(gettext("Could not create \"%s\" dependency in %s "
3416 3416 "(already exists).\n"), pgrp->sc_pgroup_name,
3417 3417 pgrp->sc_pgroup_fmri);
3418 3418 /* FALLTHROUGH */
3419 3419
3420 3420 default:
3421 3421 lcbdata->sc_err = dependent_cbdata.sc_err;
3422 3422 }
3423 3423
3424 3424 return (UU_WALK_ERROR);
3425 3425 }
3426 3426
3427 3427 static int upgrade_dependent(const scf_property_t *, const entity_t *,
3428 3428 const scf_snaplevel_t *, scf_transaction_t *);
3429 3429 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
3430 3430 const pgroup_t *);
3431 3431
3432 3432 /*
3433 3433 * Upgrade uncustomized dependents of ent to those specified in ient. Read
3434 3434 * the current dependent targets from running (the snaplevel of a running
3435 3435 * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3436 3436 * scf_instance_t * according to ient, otherwise). Draw the ancestral
3437 3437 * dependent targets and dependency properties from li_dpts_pg (the
3438 3438 * "dependents" property group in snpl) and snpl (the snaplevel which
3439 3439 * corresponds to ent in a last-import snapshot). If li_dpts_pg is NULL, then
3440 3440 * snpl doesn't have a "dependents" property group, and any dependents in ient
3441 3441 * are new.
3442 3442 *
3443 3443 * Returns
3444 3444 * 0 - success
3445 3445 * ECONNABORTED - repository connection broken
3446 3446 * ENOMEM - out of memory
3447 3447 * ENOSPC - configd is out of resources
3448 3448 * ECANCELED - ent was deleted
3449 3449 * ENODEV - the entity containing li_dpts_pg was deleted
3450 3450 * EPERM - could not modify dependents pg (permission denied) (error printed)
3451 3451 * - couldn't upgrade dependent (permission denied) (error printed)
3452 3452 * - couldn't create dependent (permission denied) (error printed)
3453 3453 * EROFS - could not modify dependents pg (repository read-only)
3454 3454 * - couldn't upgrade dependent (repository read-only)
3455 3455 * - couldn't create dependent (repository read-only)
3456 3456 * EACCES - could not modify dependents pg (backend access denied)
3457 3457 * - could not upgrade dependent (backend access denied)
3458 3458 * - could not create dependent (backend access denied)
3459 3459 * EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3460 3460 * - dependent target deleted (error printed)
3461 3461 * - dependent pg changed (error printed)
3462 3462 * EINVAL - new dependent is invalid (error printed)
3463 3463 * EBADF - snpl is corrupt (error printed)
3464 3464 * - snpl has corrupt pg (error printed)
3465 3465 * - dependency pg in target is corrupt (error printed)
3466 3466 * - target has corrupt snapshot (error printed)
3467 3467 * EEXIST - dependency pg already existed in target service (error printed)
3468 3468 */
3469 3469 static int
3470 3470 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
3471 3471 const scf_snaplevel_t *snpl, const entity_t *ient,
3472 3472 const scf_snaplevel_t *running, void *ent)
3473 3473 {
3474 3474 pgroup_t *new_dpt_pgroup;
3475 3475 scf_callback_t cbdata;
3476 3476 int r, unseen, tx_started = 0;
3477 3477 int have_cur_depts;
3478 3478
3479 3479 const char * const dependents = "dependents";
3480 3480
3481 3481 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3482 3482
3483 3483 if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
3484 3484 /* Nothing to do. */
3485 3485 return (0);
3486 3486
3487 3487 /* Fetch the current version of the "dependents" property group. */
3488 3488 have_cur_depts = 1;
3489 3489 if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
3490 3490 switch (scf_error()) {
3491 3491 case SCF_ERROR_NOT_FOUND:
3492 3492 break;
3493 3493
3494 3494 case SCF_ERROR_DELETED:
3495 3495 case SCF_ERROR_CONNECTION_BROKEN:
3496 3496 return (scferror2errno(scf_error()));
3497 3497
3498 3498 case SCF_ERROR_NOT_SET:
3499 3499 case SCF_ERROR_INVALID_ARGUMENT:
3500 3500 case SCF_ERROR_HANDLE_MISMATCH:
3501 3501 case SCF_ERROR_NOT_BOUND:
3502 3502 default:
3503 3503 bad_error("entity_get_pg", scf_error());
3504 3504 }
3505 3505
3506 3506 have_cur_depts = 0;
3507 3507 }
3508 3508
3509 3509 /* Fetch the running version of the "dependents" property group. */
3510 3510 ud_run_dpts_pg_set = 0;
3511 3511 if (running != NULL)
3512 3512 r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
3513 3513 else
3514 3514 r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
3515 3515 if (r == 0) {
3516 3516 ud_run_dpts_pg_set = 1;
3517 3517 } else {
3518 3518 switch (scf_error()) {
3519 3519 case SCF_ERROR_NOT_FOUND:
3520 3520 break;
3521 3521
3522 3522 case SCF_ERROR_DELETED:
3523 3523 case SCF_ERROR_CONNECTION_BROKEN:
3524 3524 return (scferror2errno(scf_error()));
3525 3525
3526 3526 case SCF_ERROR_NOT_SET:
3527 3527 case SCF_ERROR_INVALID_ARGUMENT:
3528 3528 case SCF_ERROR_HANDLE_MISMATCH:
3529 3529 case SCF_ERROR_NOT_BOUND:
3530 3530 default:
3531 3531 bad_error(running ? "scf_snaplevel_get_pg" :
3532 3532 "entity_get_pg", scf_error());
3533 3533 }
3534 3534 }
3535 3535
3536 3536 /*
3537 3537 * Clear the seen fields of the dependents, so we can tell which ones
3538 3538 * are new.
3539 3539 */
3540 3540 if (uu_list_walk(ient->sc_dependents, clear_int,
3541 3541 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3542 3542 bad_error("uu_list_walk", uu_error());
3543 3543
3544 3544 if (li_dpts_pg != NULL) {
3545 3545 /*
3546 3546 * Each property in li_dpts_pg represents a dependent tag in
3547 3547 * the old manifest. For each, call upgrade_dependent(),
3548 3548 * which will change ud_cur_depts_pg or dependencies in other
3549 3549 * services as appropriate. Note (a) that changes to
3550 3550 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3551 3551 * made en masse, and (b) it's ok if the entity doesn't have
3552 3552 * a current version of the "dependents" property group,
3553 3553 * because we'll just consider all dependents as customized
3554 3554 * (by being deleted).
3555 3555 */
3556 3556
3557 3557 if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3558 3558 switch (scf_error()) {
3559 3559 case SCF_ERROR_DELETED:
3560 3560 return (ENODEV);
3561 3561
3562 3562 case SCF_ERROR_CONNECTION_BROKEN:
3563 3563 return (ECONNABORTED);
3564 3564
3565 3565 case SCF_ERROR_HANDLE_MISMATCH:
3566 3566 case SCF_ERROR_NOT_BOUND:
3567 3567 case SCF_ERROR_NOT_SET:
3568 3568 default:
3569 3569 bad_error("scf_iter_pg_properties",
3570 3570 scf_error());
3571 3571 }
3572 3572 }
3573 3573
3574 3574 if (have_cur_depts &&
3575 3575 scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3576 3576 switch (scf_error()) {
3577 3577 case SCF_ERROR_BACKEND_ACCESS:
3578 3578 case SCF_ERROR_BACKEND_READONLY:
3579 3579 case SCF_ERROR_CONNECTION_BROKEN:
3580 3580 return (scferror2errno(scf_error()));
3581 3581
3582 3582 case SCF_ERROR_DELETED:
3583 3583 warn(emsg_pg_deleted, ient->sc_fmri,
3584 3584 dependents);
3585 3585 return (EBUSY);
3586 3586
3587 3587 case SCF_ERROR_PERMISSION_DENIED:
3588 3588 warn(emsg_pg_mod_perm, dependents,
3589 3589 ient->sc_fmri);
3590 3590 return (scferror2errno(scf_error()));
3591 3591
3592 3592 case SCF_ERROR_HANDLE_MISMATCH:
3593 3593 case SCF_ERROR_IN_USE:
3594 3594 case SCF_ERROR_NOT_BOUND:
3595 3595 case SCF_ERROR_NOT_SET:
3596 3596 default:
3597 3597 bad_error("scf_transaction_start", scf_error());
3598 3598 }
3599 3599 }
3600 3600 tx_started = have_cur_depts;
3601 3601
3602 3602 for (;;) {
3603 3603 r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3604 3604 if (r == 0)
3605 3605 break;
3606 3606 if (r == 1) {
3607 3607 r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3608 3608 tx_started ? ud_tx : NULL);
3609 3609 switch (r) {
3610 3610 case 0:
3611 3611 continue;
3612 3612
3613 3613 case ECONNABORTED:
3614 3614 case ENOMEM:
3615 3615 case ENOSPC:
3616 3616 case EBADF:
3617 3617 case EBUSY:
3618 3618 case EINVAL:
3619 3619 case EPERM:
3620 3620 case EROFS:
3621 3621 case EACCES:
3622 3622 case EEXIST:
3623 3623 break;
3624 3624
3625 3625 case ECANCELED:
3626 3626 r = ENODEV;
3627 3627 break;
3628 3628
3629 3629 default:
3630 3630 bad_error("upgrade_dependent", r);
3631 3631 }
3632 3632
3633 3633 if (tx_started)
3634 3634 scf_transaction_destroy_children(ud_tx);
3635 3635 return (r);
3636 3636 }
3637 3637 if (r != -1)
3638 3638 bad_error("scf_iter_next_property", r);
3639 3639
3640 3640 switch (scf_error()) {
3641 3641 case SCF_ERROR_DELETED:
3642 3642 r = ENODEV;
3643 3643 break;
3644 3644
3645 3645 case SCF_ERROR_CONNECTION_BROKEN:
3646 3646 r = ECONNABORTED;
3647 3647 break;
3648 3648
3649 3649 case SCF_ERROR_NOT_SET:
3650 3650 case SCF_ERROR_INVALID_ARGUMENT:
3651 3651 case SCF_ERROR_NOT_BOUND:
3652 3652 case SCF_ERROR_HANDLE_MISMATCH:
3653 3653 default:
3654 3654 bad_error("scf_iter_next_property",
3655 3655 scf_error());
3656 3656 }
3657 3657
3658 3658 if (tx_started)
3659 3659 scf_transaction_destroy_children(ud_tx);
3660 3660 return (r);
3661 3661 }
3662 3662 }
3663 3663
3664 3664 /* import unseen dependents */
3665 3665 unseen = 0;
3666 3666 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3667 3667 new_dpt_pgroup != NULL;
3668 3668 new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3669 3669 new_dpt_pgroup)) {
3670 3670 if (!new_dpt_pgroup->sc_pgroup_seen) {
3671 3671 unseen = 1;
3672 3672 break;
3673 3673 }
3674 3674 }
3675 3675
3676 3676 /* If there are none, exit early. */
3677 3677 if (unseen == 0)
3678 3678 goto commit;
3679 3679
3680 3680 /* Set up for lscf_dependent_import() */
3681 3681 cbdata.sc_handle = g_hndl;
3682 3682 cbdata.sc_parent = ent;
3683 3683 cbdata.sc_service = issvc;
3684 3684 cbdata.sc_flags = 0;
3685 3685
3686 3686 if (!have_cur_depts) {
3687 3687 /*
3688 3688 * We have new dependents to import, so we need a "dependents"
3689 3689 * property group.
3690 3690 */
3691 3691 if (issvc)
3692 3692 r = scf_service_add_pg(ent, dependents,
3693 3693 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3694 3694 else
3695 3695 r = scf_instance_add_pg(ent, dependents,
3696 3696 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3697 3697 if (r != 0) {
3698 3698 switch (scf_error()) {
3699 3699 case SCF_ERROR_DELETED:
3700 3700 case SCF_ERROR_CONNECTION_BROKEN:
3701 3701 case SCF_ERROR_BACKEND_READONLY:
3702 3702 case SCF_ERROR_BACKEND_ACCESS:
3703 3703 case SCF_ERROR_NO_RESOURCES:
3704 3704 return (scferror2errno(scf_error()));
3705 3705
3706 3706 case SCF_ERROR_EXISTS:
3707 3707 warn(emsg_pg_added, ient->sc_fmri, dependents);
3708 3708 return (EBUSY);
3709 3709
3710 3710 case SCF_ERROR_PERMISSION_DENIED:
3711 3711 warn(emsg_pg_add_perm, dependents,
3712 3712 ient->sc_fmri);
3713 3713 return (scferror2errno(scf_error()));
3714 3714
3715 3715 case SCF_ERROR_NOT_BOUND:
3716 3716 case SCF_ERROR_HANDLE_MISMATCH:
3717 3717 case SCF_ERROR_INVALID_ARGUMENT:
3718 3718 case SCF_ERROR_NOT_SET:
3719 3719 default:
3720 3720 bad_error("scf_service_add_pg", scf_error());
3721 3721 }
3722 3722 }
3723 3723 }
3724 3724
3725 3725 cbdata.sc_trans = ud_tx;
3726 3726
3727 3727 if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3728 3728 switch (scf_error()) {
3729 3729 case SCF_ERROR_CONNECTION_BROKEN:
3730 3730 case SCF_ERROR_BACKEND_ACCESS:
3731 3731 case SCF_ERROR_BACKEND_READONLY:
3732 3732 return (scferror2errno(scf_error()));
3733 3733
3734 3734 case SCF_ERROR_DELETED:
3735 3735 warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3736 3736 return (EBUSY);
3737 3737
3738 3738 case SCF_ERROR_PERMISSION_DENIED:
3739 3739 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3740 3740 return (scferror2errno(scf_error()));
3741 3741
3742 3742 case SCF_ERROR_HANDLE_MISMATCH:
3743 3743 case SCF_ERROR_IN_USE:
3744 3744 case SCF_ERROR_NOT_BOUND:
3745 3745 case SCF_ERROR_NOT_SET:
3746 3746 default:
3747 3747 bad_error("scf_transaction_start", scf_error());
3748 3748 }
3749 3749 }
3750 3750 tx_started = 1;
3751 3751
3752 3752 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3753 3753 new_dpt_pgroup != NULL;
3754 3754 new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3755 3755 new_dpt_pgroup)) {
3756 3756 if (new_dpt_pgroup->sc_pgroup_seen)
3757 3757 continue;
3758 3758
3759 3759 if (ud_run_dpts_pg_set) {
3760 3760 /*
3761 3761 * If the dependent is already there, then we have
3762 3762 * a conflict.
3763 3763 */
3764 3764 if (scf_pg_get_property(ud_run_dpts_pg,
3765 3765 new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3766 3766 r = handle_dependent_conflict(ient, ud_prop,
3767 3767 new_dpt_pgroup);
3768 3768 switch (r) {
3769 3769 case 0:
3770 3770 continue;
3771 3771
3772 3772 case ECONNABORTED:
3773 3773 case ENOMEM:
3774 3774 case EBUSY:
3775 3775 case EBADF:
3776 3776 case EINVAL:
3777 3777 scf_transaction_destroy_children(ud_tx);
3778 3778 return (r);
3779 3779
3780 3780 default:
3781 3781 bad_error("handle_dependent_conflict",
3782 3782 r);
3783 3783 }
3784 3784 } else {
3785 3785 switch (scf_error()) {
3786 3786 case SCF_ERROR_NOT_FOUND:
3787 3787 break;
3788 3788
3789 3789 case SCF_ERROR_INVALID_ARGUMENT:
3790 3790 warn(emsg_fmri_invalid_pg_name,
3791 3791 ient->sc_fmri,
3792 3792 new_dpt_pgroup->sc_pgroup_name);
3793 3793 scf_transaction_destroy_children(ud_tx);
3794 3794 return (EINVAL);
3795 3795
3796 3796 case SCF_ERROR_DELETED:
3797 3797 warn(emsg_pg_deleted, ient->sc_fmri,
3798 3798 new_dpt_pgroup->sc_pgroup_name);
3799 3799 scf_transaction_destroy_children(ud_tx);
3800 3800 return (EBUSY);
3801 3801
3802 3802 case SCF_ERROR_CONNECTION_BROKEN:
3803 3803 scf_transaction_destroy_children(ud_tx);
3804 3804 return (ECONNABORTED);
3805 3805
3806 3806 case SCF_ERROR_NOT_BOUND:
3807 3807 case SCF_ERROR_HANDLE_MISMATCH:
3808 3808 case SCF_ERROR_NOT_SET:
3809 3809 default:
3810 3810 bad_error("scf_pg_get_property",
3811 3811 scf_error());
3812 3812 }
3813 3813 }
3814 3814 }
3815 3815
3816 3816 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3817 3817 if (r != UU_WALK_NEXT) {
3818 3818 if (r != UU_WALK_ERROR)
3819 3819 bad_error("lscf_dependent_import", r);
3820 3820
3821 3821 if (cbdata.sc_err == EALREADY) {
3822 3822 /* Collisions were handled preemptively. */
3823 3823 bad_error("lscf_dependent_import",
3824 3824 cbdata.sc_err);
3825 3825 }
3826 3826
3827 3827 scf_transaction_destroy_children(ud_tx);
3828 3828 return (cbdata.sc_err);
3829 3829 }
3830 3830 }
3831 3831
3832 3832 commit:
3833 3833 if (!tx_started)
3834 3834 return (0);
3835 3835
3836 3836 r = scf_transaction_commit(ud_tx);
3837 3837
3838 3838 scf_transaction_destroy_children(ud_tx);
3839 3839
3840 3840 switch (r) {
3841 3841 case 1:
3842 3842 return (0);
3843 3843
3844 3844 case 0:
3845 3845 warn(emsg_pg_changed, ient->sc_fmri, dependents);
3846 3846 return (EBUSY);
3847 3847
3848 3848 case -1:
3849 3849 break;
3850 3850
3851 3851 default:
3852 3852 bad_error("scf_transaction_commit", r);
3853 3853 }
3854 3854
3855 3855 switch (scf_error()) {
3856 3856 case SCF_ERROR_CONNECTION_BROKEN:
3857 3857 case SCF_ERROR_BACKEND_READONLY:
3858 3858 case SCF_ERROR_BACKEND_ACCESS:
3859 3859 case SCF_ERROR_NO_RESOURCES:
3860 3860 return (scferror2errno(scf_error()));
3861 3861
3862 3862 case SCF_ERROR_DELETED:
3863 3863 warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3864 3864 return (EBUSY);
3865 3865
3866 3866 case SCF_ERROR_PERMISSION_DENIED:
3867 3867 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3868 3868 return (scferror2errno(scf_error()));
3869 3869
3870 3870 case SCF_ERROR_NOT_BOUND:
3871 3871 case SCF_ERROR_INVALID_ARGUMENT:
3872 3872 case SCF_ERROR_NOT_SET:
3873 3873 default:
3874 3874 bad_error("scf_transaction_destroy", scf_error());
3875 3875 /* NOTREACHED */
3876 3876 }
3877 3877 }
3878 3878
3879 3879 /*
3880 3880 * Used to add the manifests to the list of currently supported manifests.
3881 3881 * We can modify the existing manifest list removing entries if the files
3882 3882 * don't exist.
3883 3883 *
3884 3884 * Get the old list and the new file name
3885 3885 * If the new file name is in the list return
3886 3886 * If not then add the file to the list.
3887 3887 * As we process the list check to see if the files in the old list exist
3888 3888 * if not then remove the file from the list.
3889 3889 * Commit the list of manifest file names.
3890 3890 *
3891 3891 */
3892 3892 static int
3893 3893 upgrade_manifestfiles(pgroup_t *pg, const entity_t *ient,
3894 3894 const scf_snaplevel_t *running, void *ent)
3895 3895 {
3896 3896 scf_propertygroup_t *ud_mfsts_pg = NULL;
3897 3897 scf_property_t *ud_prop = NULL;
3898 3898 scf_iter_t *ud_prop_iter;
3899 3899 scf_value_t *fname_value;
3900 3900 scf_callback_t cbdata;
3901 3901 pgroup_t *mfst_pgroup;
3902 3902 property_t *mfst_prop;
3903 3903 property_t *old_prop;
3904 3904 char *pname;
3905 3905 char *fval;
3906 3906 char *old_pname;
3907 3907 char *old_fval;
3908 3908 int no_upgrade_pg;
3909 3909 int mfst_seen;
3910 3910 int r;
3911 3911
3912 3912 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3913 3913
3914 3914 /*
3915 3915 * This should always be the service base on the code
3916 3916 * path, and the fact that the manifests pg is a service
3917 3917 * level property group only.
3918 3918 */
3919 3919 ud_mfsts_pg = scf_pg_create(g_hndl);
3920 3920 ud_prop = scf_property_create(g_hndl);
3921 3921 ud_prop_iter = scf_iter_create(g_hndl);
3922 3922 fname_value = scf_value_create(g_hndl);
3923 3923
3924 3924 /* Fetch the "manifests" property group */
3925 3925 no_upgrade_pg = 0;
3926 3926 r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3927 3927 ud_mfsts_pg);
3928 3928 if (r != 0) {
3929 3929 switch (scf_error()) {
3930 3930 case SCF_ERROR_NOT_FOUND:
3931 3931 no_upgrade_pg = 1;
3932 3932 break;
3933 3933
3934 3934 case SCF_ERROR_DELETED:
3935 3935 case SCF_ERROR_CONNECTION_BROKEN:
3936 3936 return (scferror2errno(scf_error()));
3937 3937
3938 3938 case SCF_ERROR_NOT_SET:
3939 3939 case SCF_ERROR_INVALID_ARGUMENT:
3940 3940 case SCF_ERROR_HANDLE_MISMATCH:
3941 3941 case SCF_ERROR_NOT_BOUND:
3942 3942 default:
3943 3943 bad_error(running ? "scf_snaplevel_get_pg" :
3944 3944 "entity_get_pg", scf_error());
3945 3945 }
3946 3946 }
3947 3947
3948 3948 if (no_upgrade_pg) {
3949 3949 cbdata.sc_handle = g_hndl;
3950 3950 cbdata.sc_parent = ent;
3951 3951 cbdata.sc_service = issvc;
3952 3952 cbdata.sc_flags = SCI_FORCE;
3953 3953 cbdata.sc_source_fmri = ient->sc_fmri;
3954 3954 cbdata.sc_target_fmri = ient->sc_fmri;
3955 3955
3956 3956 if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3957 3957 return (cbdata.sc_err);
3958 3958
3959 3959 return (0);
3960 3960 }
3961 3961
3962 3962 /* Fetch the new manifests property group */
3963 3963 for (mfst_pgroup = uu_list_first(ient->sc_pgroups);
3964 3964 mfst_pgroup != NULL;
3965 3965 mfst_pgroup = uu_list_next(ient->sc_pgroups, mfst_pgroup)) {
3966 3966 if (strcmp(mfst_pgroup->sc_pgroup_name,
3967 3967 SCF_PG_MANIFESTFILES) == 0)
3968 3968 break;
3969 3969 }
3970 3970
3971 3971 if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3972 3972 SCF_SUCCESS)
3973 3973 return (-1);
3974 3974
3975 3975 if ((pname = malloc(MAXPATHLEN)) == NULL)
3976 3976 return (ENOMEM);
3977 3977 if ((fval = malloc(MAXPATHLEN)) == NULL) {
3978 3978 free(pname);
3979 3979 return (ENOMEM);
3980 3980 }
3981 3981
3982 3982 while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
3983 3983 mfst_seen = 0;
3984 3984 if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
3985 3985 continue;
3986 3986
3987 3987 for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
3988 3988 mfst_prop != NULL;
3989 3989 mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
3990 3990 mfst_prop)) {
3991 3991 if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
3992 3992 mfst_seen = 1;
3993 3993 }
3994 3994 }
3995 3995
3996 3996 /*
3997 3997 * If the manifest is not seen then add it to the new mfst
3998 3998 * property list to get proccessed into the repo.
3999 3999 */
4000 4000 if (mfst_seen == 0) {
4001 4001 /*
4002 4002 * If we cannot get the value then there is no
4003 4003 * reason to attempt to attach the value to
4004 4004 * the property group
4005 4005 */
4006 4006 if (prop_get_val(ud_prop, fname_value) == 0 &&
4007 4007 scf_value_get_astring(fname_value, fval,
4008 4008 MAXPATHLEN) != -1) {
4009 4009 old_pname = safe_strdup(pname);
4010 4010 old_fval = safe_strdup(fval);
4011 4011 old_prop = internal_property_create(old_pname,
4012 4012 SCF_TYPE_ASTRING, 1, old_fval);
4013 4013
4014 4014 /*
4015 4015 * Already checked to see if the property exists
4016 4016 * in the group, and it does not.
4017 4017 */
4018 4018 (void) internal_attach_property(mfst_pgroup,
4019 4019 old_prop);
4020 4020 }
4021 4021 }
4022 4022 }
4023 4023 free(pname);
4024 4024 free(fval);
4025 4025
4026 4026 cbdata.sc_handle = g_hndl;
4027 4027 cbdata.sc_parent = ent;
4028 4028 cbdata.sc_service = issvc;
4029 4029 cbdata.sc_flags = SCI_FORCE;
4030 4030 cbdata.sc_source_fmri = ient->sc_fmri;
4031 4031 cbdata.sc_target_fmri = ient->sc_fmri;
4032 4032
4033 4033 if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
4034 4034 return (cbdata.sc_err);
4035 4035
4036 4036 return (r);
4037 4037 }
4038 4038
4039 4039 /*
4040 4040 * prop is taken to be a property in the "dependents" property group of snpl,
4041 4041 * which is taken to be the snaplevel of a last-import snapshot corresponding
4042 4042 * to ient. If prop is a valid dependents property, upgrade the dependent it
4043 4043 * represents according to the repository & ient. If ud_run_dpts_pg_set is
4044 4044 * true, then ud_run_dpts_pg is taken to be the "dependents" property group
4045 4045 * of the entity ient represents (possibly in the running snapshot). If it
4046 4046 * needs to be changed, an entry will be added to tx, if not NULL.
4047 4047 *
4048 4048 * Returns
4049 4049 * 0 - success
4050 4050 * ECONNABORTED - repository connection broken
4051 4051 * ENOMEM - out of memory
4052 4052 * ENOSPC - configd was out of resources
4053 4053 * ECANCELED - snpl's entity was deleted
4054 4054 * EINVAL - dependent target is invalid (error printed)
4055 4055 * - dependent is invalid (error printed)
4056 4056 * EBADF - snpl is corrupt (error printed)
4057 4057 * - snpl has corrupt pg (error printed)
4058 4058 * - dependency pg in target is corrupt (error printed)
4059 4059 * - running snapshot in dependent is missing snaplevel (error printed)
4060 4060 * EPERM - couldn't delete dependency pg (permission denied) (error printed)
4061 4061 * - couldn't create dependent (permission denied) (error printed)
4062 4062 * - couldn't modify dependent pg (permission denied) (error printed)
4063 4063 * EROFS - couldn't delete dependency pg (repository read-only)
4064 4064 * - couldn't create dependent (repository read-only)
4065 4065 * EACCES - couldn't delete dependency pg (backend access denied)
4066 4066 * - couldn't create dependent (backend access denied)
4067 4067 * EBUSY - ud_run_dpts_pg was deleted (error printed)
4068 4068 * - tx's pg was deleted (error printed)
4069 4069 * - dependent pg was changed or deleted (error printed)
4070 4070 * EEXIST - dependency pg already exists in new target (error printed)
4071 4071 */
4072 4072 static int
4073 4073 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
4074 4074 const scf_snaplevel_t *snpl, scf_transaction_t *tx)
4075 4075 {
4076 4076 pgroup_t pgrp;
4077 4077 scf_type_t ty;
4078 4078 pgroup_t *new_dpt_pgroup;
4079 4079 pgroup_t *old_dpt_pgroup = NULL;
4080 4080 pgroup_t *current_pg;
4081 4081 pgroup_t *dpt;
4082 4082 scf_callback_t cbdata;
4083 4083 int tissvc;
4084 4084 void *target_ent;
4085 4085 scf_error_t serr;
4086 4086 int r;
4087 4087 scf_transaction_entry_t *ent;
4088 4088
4089 4089 const char * const cf_inval = gettext("Conflict upgrading %s "
4090 4090 "(dependent \"%s\" has invalid dependents property).\n");
4091 4091 const char * const cf_missing = gettext("Conflict upgrading %s "
4092 4092 "(dependent \"%s\" is missing).\n");
4093 4093 const char * const cf_newdpg = gettext("Conflict upgrading %s "
4094 4094 "(dependent \"%s\" has new dependency property group).\n");
4095 4095 const char * const cf_newtarg = gettext("Conflict upgrading %s "
4096 4096 "(dependent \"%s\" has new target).\n");
4097 4097 const char * const li_corrupt =
4098 4098 gettext("%s: \"last-import\" snapshot is corrupt.\n");
4099 4099 const char * const upgrading =
4100 4100 gettext("%s: Upgrading dependent \"%s\".\n");
4101 4101 const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
4102 4102 "corrupt (missing snaplevel).\n");
4103 4103
4104 4104 if (scf_property_type(prop, &ty) != 0) {
4105 4105 switch (scf_error()) {
4106 4106 case SCF_ERROR_DELETED:
4107 4107 case SCF_ERROR_CONNECTION_BROKEN:
4108 4108 return (scferror2errno(scf_error()));
4109 4109
4110 4110 case SCF_ERROR_NOT_BOUND:
4111 4111 case SCF_ERROR_NOT_SET:
4112 4112 default:
4113 4113 bad_error("scf_property_type", scf_error());
4114 4114 }
4115 4115 }
4116 4116
4117 4117 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4118 4118 warn(li_corrupt, ient->sc_fmri);
4119 4119 return (EBADF);
4120 4120 }
4121 4121
4122 4122 /*
4123 4123 * prop represents a dependent in the old manifest. It is named after
4124 4124 * the dependent.
4125 4125 */
4126 4126 if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
4127 4127 switch (scf_error()) {
4128 4128 case SCF_ERROR_DELETED:
4129 4129 case SCF_ERROR_CONNECTION_BROKEN:
4130 4130 return (scferror2errno(scf_error()));
4131 4131
4132 4132 case SCF_ERROR_NOT_BOUND:
4133 4133 case SCF_ERROR_NOT_SET:
4134 4134 default:
4135 4135 bad_error("scf_property_get_name", scf_error());
4136 4136 }
4137 4137 }
4138 4138
4139 4139 /* See if it's in the new manifest. */
4140 4140 pgrp.sc_pgroup_name = ud_name;
4141 4141 new_dpt_pgroup =
4142 4142 uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
4143 4143
4144 4144 /* If it's not, delete it... if it hasn't been customized. */
4145 4145 if (new_dpt_pgroup == NULL) {
4146 4146 if (!ud_run_dpts_pg_set)
4147 4147 return (0);
4148 4148
4149 4149 if (scf_property_get_value(prop, ud_val) != 0) {
4150 4150 switch (scf_error()) {
4151 4151 case SCF_ERROR_NOT_FOUND:
4152 4152 case SCF_ERROR_CONSTRAINT_VIOLATED:
4153 4153 warn(li_corrupt, ient->sc_fmri);
4154 4154 return (EBADF);
4155 4155
4156 4156 case SCF_ERROR_DELETED:
4157 4157 case SCF_ERROR_CONNECTION_BROKEN:
4158 4158 return (scferror2errno(scf_error()));
4159 4159
4160 4160 case SCF_ERROR_HANDLE_MISMATCH:
4161 4161 case SCF_ERROR_NOT_BOUND:
4162 4162 case SCF_ERROR_NOT_SET:
4163 4163 case SCF_ERROR_PERMISSION_DENIED:
4164 4164 default:
4165 4165 bad_error("scf_property_get_value",
4166 4166 scf_error());
4167 4167 }
4168 4168 }
4169 4169
4170 4170 if (scf_value_get_as_string(ud_val, ud_oldtarg,
4171 4171 max_scf_value_len + 1) < 0)
4172 4172 bad_error("scf_value_get_as_string", scf_error());
4173 4173
4174 4174 if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
4175 4175 0) {
4176 4176 switch (scf_error()) {
4177 4177 case SCF_ERROR_NOT_FOUND:
4178 4178 return (0);
4179 4179
4180 4180 case SCF_ERROR_CONNECTION_BROKEN:
4181 4181 return (scferror2errno(scf_error()));
4182 4182
4183 4183 case SCF_ERROR_DELETED:
4184 4184 warn(emsg_pg_deleted, ient->sc_fmri,
4185 4185 "dependents");
4186 4186 return (EBUSY);
4187 4187
4188 4188 case SCF_ERROR_INVALID_ARGUMENT:
4189 4189 case SCF_ERROR_NOT_BOUND:
4190 4190 case SCF_ERROR_HANDLE_MISMATCH:
4191 4191 case SCF_ERROR_NOT_SET:
4192 4192 default:
4193 4193 bad_error("scf_pg_get_property", scf_error());
4194 4194 }
4195 4195 }
4196 4196 if (scf_property_get_value(ud_prop, ud_val) != 0) {
4197 4197 switch (scf_error()) {
4198 4198 case SCF_ERROR_NOT_FOUND:
4199 4199 case SCF_ERROR_CONSTRAINT_VIOLATED:
4200 4200 warn(cf_inval, ient->sc_fmri, ud_name);
4201 4201 return (0);
4202 4202
4203 4203 case SCF_ERROR_DELETED:
4204 4204 case SCF_ERROR_CONNECTION_BROKEN:
4205 4205 return (scferror2errno(scf_error()));
4206 4206
4207 4207 case SCF_ERROR_HANDLE_MISMATCH:
4208 4208 case SCF_ERROR_NOT_BOUND:
4209 4209 case SCF_ERROR_NOT_SET:
4210 4210 case SCF_ERROR_PERMISSION_DENIED:
4211 4211 default:
4212 4212 bad_error("scf_property_get_value",
4213 4213 scf_error());
4214 4214 }
4215 4215 }
4216 4216
4217 4217 ty = scf_value_type(ud_val);
4218 4218 assert(ty != SCF_TYPE_INVALID);
4219 4219 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4220 4220 warn(cf_inval, ient->sc_fmri, ud_name);
4221 4221 return (0);
4222 4222 }
4223 4223
4224 4224 if (scf_value_get_as_string(ud_val, ud_ctarg,
4225 4225 max_scf_value_len + 1) < 0)
4226 4226 bad_error("scf_value_get_as_string", scf_error());
4227 4227
4228 4228 r = fmri_equal(ud_ctarg, ud_oldtarg);
4229 4229 switch (r) {
4230 4230 case 1:
4231 4231 break;
4232 4232
4233 4233 case 0:
4234 4234 case -1: /* warn? */
4235 4235 warn(cf_newtarg, ient->sc_fmri, ud_name);
4236 4236 return (0);
4237 4237
4238 4238 case -2:
4239 4239 warn(li_corrupt, ient->sc_fmri);
4240 4240 return (EBADF);
4241 4241
4242 4242 default:
4243 4243 bad_error("fmri_equal", r);
4244 4244 }
4245 4245
4246 4246 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4247 4247 switch (scf_error()) {
4248 4248 case SCF_ERROR_NOT_FOUND:
4249 4249 warn(li_corrupt, ient->sc_fmri);
4250 4250 return (EBADF);
4251 4251
4252 4252 case SCF_ERROR_DELETED:
4253 4253 case SCF_ERROR_CONNECTION_BROKEN:
4254 4254 return (scferror2errno(scf_error()));
4255 4255
4256 4256 case SCF_ERROR_NOT_BOUND:
4257 4257 case SCF_ERROR_HANDLE_MISMATCH:
4258 4258 case SCF_ERROR_INVALID_ARGUMENT:
4259 4259 case SCF_ERROR_NOT_SET:
4260 4260 default:
4261 4261 bad_error("scf_snaplevel_get_pg", scf_error());
4262 4262 }
4263 4263 }
4264 4264
4265 4265 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4266 4266 snap_lastimport);
4267 4267 switch (r) {
4268 4268 case 0:
4269 4269 break;
4270 4270
4271 4271 case ECANCELED:
4272 4272 case ECONNABORTED:
4273 4273 case ENOMEM:
4274 4274 case EBADF:
4275 4275 return (r);
4276 4276
4277 4277 case EACCES:
4278 4278 default:
4279 4279 bad_error("load_pg", r);
4280 4280 }
4281 4281
4282 4282 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4283 4283 switch (serr) {
4284 4284 case SCF_ERROR_NONE:
4285 4285 break;
4286 4286
4287 4287 case SCF_ERROR_NO_MEMORY:
4288 4288 internal_pgroup_free(old_dpt_pgroup);
4289 4289 return (ENOMEM);
4290 4290
4291 4291 case SCF_ERROR_NOT_FOUND:
4292 4292 internal_pgroup_free(old_dpt_pgroup);
4293 4293 goto delprop;
4294 4294
4295 4295 case SCF_ERROR_CONSTRAINT_VIOLATED: /* caught above */
4296 4296 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
4297 4297 default:
4298 4298 bad_error("fmri_to_entity", serr);
4299 4299 }
4300 4300
4301 4301 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4302 4302 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4303 4303 switch (r) {
4304 4304 case 0:
4305 4305 break;
4306 4306
4307 4307 case ECONNABORTED:
4308 4308 internal_pgroup_free(old_dpt_pgroup);
4309 4309 return (r);
4310 4310
4311 4311 case ECANCELED:
4312 4312 case ENOENT:
4313 4313 internal_pgroup_free(old_dpt_pgroup);
4314 4314 goto delprop;
4315 4315
4316 4316 case EBADF:
4317 4317 warn(r_no_lvl, ud_ctarg);
4318 4318 internal_pgroup_free(old_dpt_pgroup);
4319 4319 return (r);
4320 4320
4321 4321 case EINVAL:
4322 4322 default:
4323 4323 bad_error("entity_get_running_pg", r);
4324 4324 }
4325 4325
4326 4326 /* load it */
4327 4327 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4328 4328 switch (r) {
4329 4329 case 0:
4330 4330 break;
4331 4331
4332 4332 case ECANCELED:
4333 4333 internal_pgroup_free(old_dpt_pgroup);
4334 4334 goto delprop;
4335 4335
4336 4336 case ECONNABORTED:
4337 4337 case ENOMEM:
4338 4338 case EBADF:
4339 4339 internal_pgroup_free(old_dpt_pgroup);
4340 4340 return (r);
4341 4341
4342 4342 case EACCES:
4343 4343 default:
4344 4344 bad_error("load_pg", r);
4345 4345 }
4346 4346
4347 4347 /* compare property groups */
4348 4348 if (!pg_equal(old_dpt_pgroup, current_pg)) {
4349 4349 warn(cf_newdpg, ient->sc_fmri, ud_name);
4350 4350 internal_pgroup_free(old_dpt_pgroup);
4351 4351 internal_pgroup_free(current_pg);
4352 4352 return (0);
4353 4353 }
4354 4354
4355 4355 internal_pgroup_free(old_dpt_pgroup);
4356 4356 internal_pgroup_free(current_pg);
4357 4357
4358 4358 if (g_verbose)
4359 4359 warn(gettext("%s: Deleting dependent \"%s\".\n"),
4360 4360 ient->sc_fmri, ud_name);
4361 4361
4362 4362 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4363 4363 switch (scf_error()) {
4364 4364 case SCF_ERROR_NOT_FOUND:
4365 4365 case SCF_ERROR_DELETED:
4366 4366 internal_pgroup_free(old_dpt_pgroup);
4367 4367 goto delprop;
4368 4368
4369 4369 case SCF_ERROR_CONNECTION_BROKEN:
4370 4370 internal_pgroup_free(old_dpt_pgroup);
4371 4371 return (ECONNABORTED);
4372 4372
4373 4373 case SCF_ERROR_NOT_SET:
4374 4374 case SCF_ERROR_INVALID_ARGUMENT:
4375 4375 case SCF_ERROR_HANDLE_MISMATCH:
4376 4376 case SCF_ERROR_NOT_BOUND:
4377 4377 default:
4378 4378 bad_error("entity_get_pg", scf_error());
4379 4379 }
4380 4380 }
4381 4381
4382 4382 if (scf_pg_delete(ud_pg) != 0) {
4383 4383 switch (scf_error()) {
4384 4384 case SCF_ERROR_DELETED:
4385 4385 break;
4386 4386
4387 4387 case SCF_ERROR_CONNECTION_BROKEN:
4388 4388 case SCF_ERROR_BACKEND_READONLY:
4389 4389 case SCF_ERROR_BACKEND_ACCESS:
4390 4390 return (scferror2errno(scf_error()));
4391 4391
4392 4392 case SCF_ERROR_PERMISSION_DENIED:
4393 4393 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4394 4394 return (scferror2errno(scf_error()));
4395 4395
4396 4396 case SCF_ERROR_NOT_SET:
4397 4397 default:
4398 4398 bad_error("scf_pg_delete", scf_error());
4399 4399 }
4400 4400 }
4401 4401
4402 4402 /*
4403 4403 * This service was changed, so it must be refreshed. But
4404 4404 * since it's not mentioned in the new manifest, we have to
4405 4405 * record its FMRI here for use later. We record the name
4406 4406 * & the entity (via sc_parent) in case we need to print error
4407 4407 * messages during the refresh.
4408 4408 */
4409 4409 dpt = internal_pgroup_new();
4410 4410 if (dpt == NULL)
4411 4411 return (ENOMEM);
4412 4412 dpt->sc_pgroup_name = strdup(ud_name);
4413 4413 dpt->sc_pgroup_fmri = strdup(ud_ctarg);
4414 4414 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4415 4415 return (ENOMEM);
4416 4416 dpt->sc_parent = (entity_t *)ient;
4417 4417 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4418 4418 uu_die(gettext("libuutil error: %s\n"),
4419 4419 uu_strerror(uu_error()));
4420 4420
4421 4421 delprop:
4422 4422 if (tx == NULL)
4423 4423 return (0);
4424 4424
4425 4425 ent = scf_entry_create(g_hndl);
4426 4426 if (ent == NULL)
4427 4427 return (ENOMEM);
4428 4428
4429 4429 if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
4430 4430 scf_entry_destroy(ent);
4431 4431 switch (scf_error()) {
4432 4432 case SCF_ERROR_DELETED:
4433 4433 warn(emsg_pg_deleted, ient->sc_fmri,
4434 4434 "dependents");
4435 4435 return (EBUSY);
4436 4436
4437 4437 case SCF_ERROR_CONNECTION_BROKEN:
4438 4438 return (scferror2errno(scf_error()));
4439 4439
4440 4440 case SCF_ERROR_NOT_FOUND:
4441 4441 break;
4442 4442
4443 4443 case SCF_ERROR_HANDLE_MISMATCH:
4444 4444 case SCF_ERROR_NOT_BOUND:
4445 4445 case SCF_ERROR_INVALID_ARGUMENT:
4446 4446 case SCF_ERROR_NOT_SET:
4447 4447 default:
4448 4448 bad_error("scf_transaction_property_delete",
4449 4449 scf_error());
4450 4450 }
4451 4451 }
4452 4452
4453 4453 return (0);
4454 4454 }
4455 4455
4456 4456 new_dpt_pgroup->sc_pgroup_seen = 1;
4457 4457
4458 4458 /*
4459 4459 * Decide whether the dependent has changed in the manifest.
4460 4460 */
4461 4461 /* Compare the target. */
4462 4462 if (scf_property_get_value(prop, ud_val) != 0) {
4463 4463 switch (scf_error()) {
4464 4464 case SCF_ERROR_NOT_FOUND:
4465 4465 case SCF_ERROR_CONSTRAINT_VIOLATED:
4466 4466 warn(li_corrupt, ient->sc_fmri);
4467 4467 return (EBADF);
4468 4468
4469 4469 case SCF_ERROR_DELETED:
4470 4470 case SCF_ERROR_CONNECTION_BROKEN:
4471 4471 return (scferror2errno(scf_error()));
4472 4472
4473 4473 case SCF_ERROR_HANDLE_MISMATCH:
4474 4474 case SCF_ERROR_NOT_BOUND:
4475 4475 case SCF_ERROR_NOT_SET:
4476 4476 case SCF_ERROR_PERMISSION_DENIED:
4477 4477 default:
4478 4478 bad_error("scf_property_get_value", scf_error());
4479 4479 }
4480 4480 }
4481 4481
4482 4482 if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
4483 4483 0)
4484 4484 bad_error("scf_value_get_as_string", scf_error());
4485 4485
4486 4486 /*
4487 4487 * If the fmri's are not equal then the old fmri will need to
4488 4488 * be refreshed to ensure that the changes are properly updated
4489 4489 * in that service.
4490 4490 */
4491 4491 r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
4492 4492 switch (r) {
4493 4493 case 0:
4494 4494 dpt = internal_pgroup_new();
4495 4495 if (dpt == NULL)
4496 4496 return (ENOMEM);
4497 4497 dpt->sc_pgroup_name = strdup(ud_name);
4498 4498 dpt->sc_pgroup_fmri = strdup(ud_oldtarg);
4499 4499 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4500 4500 return (ENOMEM);
4501 4501 dpt->sc_parent = (entity_t *)ient;
4502 4502 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4503 4503 uu_die(gettext("libuutil error: %s\n"),
4504 4504 uu_strerror(uu_error()));
4505 4505 break;
4506 4506
4507 4507 case 1:
4508 4508 /* Compare the dependency pgs. */
4509 4509 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4510 4510 switch (scf_error()) {
4511 4511 case SCF_ERROR_NOT_FOUND:
4512 4512 warn(li_corrupt, ient->sc_fmri);
4513 4513 return (EBADF);
4514 4514
4515 4515 case SCF_ERROR_DELETED:
4516 4516 case SCF_ERROR_CONNECTION_BROKEN:
4517 4517 return (scferror2errno(scf_error()));
4518 4518
4519 4519 case SCF_ERROR_NOT_BOUND:
4520 4520 case SCF_ERROR_HANDLE_MISMATCH:
4521 4521 case SCF_ERROR_INVALID_ARGUMENT:
4522 4522 case SCF_ERROR_NOT_SET:
4523 4523 default:
4524 4524 bad_error("scf_snaplevel_get_pg", scf_error());
4525 4525 }
4526 4526 }
4527 4527
4528 4528 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4529 4529 snap_lastimport);
4530 4530 switch (r) {
4531 4531 case 0:
4532 4532 break;
4533 4533
4534 4534 case ECANCELED:
4535 4535 case ECONNABORTED:
4536 4536 case ENOMEM:
4537 4537 case EBADF:
4538 4538 return (r);
4539 4539
4540 4540 case EACCES:
4541 4541 default:
4542 4542 bad_error("load_pg", r);
4543 4543 }
4544 4544
4545 4545 if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4546 4546 /* no change, leave customizations */
4547 4547 internal_pgroup_free(old_dpt_pgroup);
4548 4548 return (0);
4549 4549 }
4550 4550 break;
4551 4551
4552 4552 case -1:
4553 4553 warn(li_corrupt, ient->sc_fmri);
4554 4554 return (EBADF);
4555 4555
4556 4556 case -2:
4557 4557 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4558 4558 ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4559 4559 return (EINVAL);
4560 4560
4561 4561 default:
4562 4562 bad_error("fmri_equal", r);
4563 4563 }
4564 4564
4565 4565 /*
4566 4566 * The dependent has changed in the manifest. Upgrade the current
4567 4567 * properties if they haven't been customized.
4568 4568 */
4569 4569
4570 4570 /*
4571 4571 * If new_dpt_pgroup->sc_override, then act as though the property
4572 4572 * group hasn't been customized.
4573 4573 */
4574 4574 if (new_dpt_pgroup->sc_pgroup_override) {
4575 4575 (void) strcpy(ud_ctarg, ud_oldtarg);
4576 4576 goto nocust;
4577 4577 }
4578 4578
4579 4579 if (!ud_run_dpts_pg_set) {
4580 4580 warn(cf_missing, ient->sc_fmri, ud_name);
4581 4581 r = 0;
4582 4582 goto out;
4583 4583 } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4584 4584 switch (scf_error()) {
4585 4585 case SCF_ERROR_NOT_FOUND:
4586 4586 warn(cf_missing, ient->sc_fmri, ud_name);
4587 4587 r = 0;
4588 4588 goto out;
4589 4589
4590 4590 case SCF_ERROR_CONNECTION_BROKEN:
4591 4591 r = scferror2errno(scf_error());
4592 4592 goto out;
4593 4593
4594 4594 case SCF_ERROR_DELETED:
4595 4595 warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4596 4596 r = EBUSY;
4597 4597 goto out;
4598 4598
4599 4599 case SCF_ERROR_INVALID_ARGUMENT:
4600 4600 case SCF_ERROR_NOT_BOUND:
4601 4601 case SCF_ERROR_HANDLE_MISMATCH:
4602 4602 case SCF_ERROR_NOT_SET:
4603 4603 default:
4604 4604 bad_error("scf_pg_get_property", scf_error());
4605 4605 }
4606 4606 }
4607 4607
4608 4608 if (scf_property_get_value(ud_prop, ud_val) != 0) {
4609 4609 switch (scf_error()) {
4610 4610 case SCF_ERROR_NOT_FOUND:
4611 4611 case SCF_ERROR_CONSTRAINT_VIOLATED:
4612 4612 warn(cf_inval, ient->sc_fmri, ud_name);
4613 4613 r = 0;
4614 4614 goto out;
4615 4615
4616 4616 case SCF_ERROR_DELETED:
4617 4617 case SCF_ERROR_CONNECTION_BROKEN:
4618 4618 r = scferror2errno(scf_error());
4619 4619 goto out;
4620 4620
4621 4621 case SCF_ERROR_HANDLE_MISMATCH:
4622 4622 case SCF_ERROR_NOT_BOUND:
4623 4623 case SCF_ERROR_NOT_SET:
4624 4624 case SCF_ERROR_PERMISSION_DENIED:
4625 4625 default:
4626 4626 bad_error("scf_property_get_value", scf_error());
4627 4627 }
4628 4628 }
4629 4629
4630 4630 ty = scf_value_type(ud_val);
4631 4631 assert(ty != SCF_TYPE_INVALID);
4632 4632 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4633 4633 warn(cf_inval, ient->sc_fmri, ud_name);
4634 4634 r = 0;
4635 4635 goto out;
4636 4636 }
4637 4637 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4638 4638 0)
4639 4639 bad_error("scf_value_get_as_string", scf_error());
4640 4640
4641 4641 r = fmri_equal(ud_ctarg, ud_oldtarg);
4642 4642 if (r == -1) {
4643 4643 warn(cf_inval, ient->sc_fmri, ud_name);
4644 4644 r = 0;
4645 4645 goto out;
4646 4646 } else if (r == -2) {
4647 4647 warn(li_corrupt, ient->sc_fmri);
4648 4648 r = EBADF;
4649 4649 goto out;
4650 4650 } else if (r == 0) {
4651 4651 /*
4652 4652 * Target has been changed. Only abort now if it's been
4653 4653 * changed to something other than what's in the manifest.
4654 4654 */
4655 4655 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4656 4656 if (r == -1) {
4657 4657 warn(cf_inval, ient->sc_fmri, ud_name);
4658 4658 r = 0;
4659 4659 goto out;
4660 4660 } else if (r == 0) {
4661 4661 warn(cf_newtarg, ient->sc_fmri, ud_name);
4662 4662 r = 0;
4663 4663 goto out;
4664 4664 } else if (r != 1) {
4665 4665 /* invalid sc_pgroup_fmri caught above */
4666 4666 bad_error("fmri_equal", r);
4667 4667 }
4668 4668
4669 4669 /*
4670 4670 * Fetch the current dependency pg. If it's what the manifest
4671 4671 * says, then no problem.
4672 4672 */
4673 4673 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4674 4674 switch (serr) {
4675 4675 case SCF_ERROR_NONE:
4676 4676 break;
4677 4677
4678 4678 case SCF_ERROR_NOT_FOUND:
4679 4679 warn(cf_missing, ient->sc_fmri, ud_name);
4680 4680 r = 0;
4681 4681 goto out;
4682 4682
4683 4683 case SCF_ERROR_NO_MEMORY:
4684 4684 r = ENOMEM;
4685 4685 goto out;
4686 4686
4687 4687 case SCF_ERROR_CONSTRAINT_VIOLATED:
4688 4688 case SCF_ERROR_INVALID_ARGUMENT:
4689 4689 default:
4690 4690 bad_error("fmri_to_entity", serr);
4691 4691 }
4692 4692
4693 4693 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4694 4694 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4695 4695 switch (r) {
4696 4696 case 0:
4697 4697 break;
4698 4698
4699 4699 case ECONNABORTED:
4700 4700 goto out;
4701 4701
4702 4702 case ECANCELED:
4703 4703 case ENOENT:
4704 4704 warn(cf_missing, ient->sc_fmri, ud_name);
4705 4705 r = 0;
4706 4706 goto out;
4707 4707
4708 4708 case EBADF:
4709 4709 warn(r_no_lvl, ud_ctarg);
4710 4710 goto out;
4711 4711
4712 4712 case EINVAL:
4713 4713 default:
4714 4714 bad_error("entity_get_running_pg", r);
4715 4715 }
4716 4716
4717 4717 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4718 4718 switch (r) {
4719 4719 case 0:
4720 4720 break;
4721 4721
4722 4722 case ECANCELED:
4723 4723 warn(cf_missing, ient->sc_fmri, ud_name);
4724 4724 r = 0;
4725 4725 goto out;
4726 4726
4727 4727 case ECONNABORTED:
4728 4728 case ENOMEM:
4729 4729 case EBADF:
4730 4730 goto out;
4731 4731
4732 4732 case EACCES:
4733 4733 default:
4734 4734 bad_error("load_pg", r);
4735 4735 }
4736 4736
4737 4737 if (!pg_equal(current_pg, new_dpt_pgroup))
4738 4738 warn(cf_newdpg, ient->sc_fmri, ud_name);
4739 4739 internal_pgroup_free(current_pg);
4740 4740 r = 0;
4741 4741 goto out;
4742 4742 } else if (r != 1) {
4743 4743 bad_error("fmri_equal", r);
4744 4744 }
4745 4745
4746 4746 nocust:
4747 4747 /*
4748 4748 * Target has not been customized. Check the dependency property
4749 4749 * group.
4750 4750 */
4751 4751
4752 4752 if (old_dpt_pgroup == NULL) {
4753 4753 if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4754 4754 ud_pg) != 0) {
4755 4755 switch (scf_error()) {
4756 4756 case SCF_ERROR_NOT_FOUND:
4757 4757 warn(li_corrupt, ient->sc_fmri);
4758 4758 return (EBADF);
4759 4759
4760 4760 case SCF_ERROR_DELETED:
4761 4761 case SCF_ERROR_CONNECTION_BROKEN:
4762 4762 return (scferror2errno(scf_error()));
4763 4763
4764 4764 case SCF_ERROR_NOT_BOUND:
4765 4765 case SCF_ERROR_HANDLE_MISMATCH:
4766 4766 case SCF_ERROR_INVALID_ARGUMENT:
4767 4767 case SCF_ERROR_NOT_SET:
4768 4768 default:
4769 4769 bad_error("scf_snaplevel_get_pg", scf_error());
4770 4770 }
4771 4771 }
4772 4772
4773 4773 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4774 4774 snap_lastimport);
4775 4775 switch (r) {
4776 4776 case 0:
4777 4777 break;
4778 4778
4779 4779 case ECANCELED:
4780 4780 case ECONNABORTED:
4781 4781 case ENOMEM:
4782 4782 case EBADF:
4783 4783 return (r);
4784 4784
4785 4785 case EACCES:
4786 4786 default:
4787 4787 bad_error("load_pg", r);
4788 4788 }
4789 4789 }
4790 4790 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4791 4791 switch (serr) {
4792 4792 case SCF_ERROR_NONE:
4793 4793 break;
4794 4794
4795 4795 case SCF_ERROR_NOT_FOUND:
4796 4796 warn(cf_missing, ient->sc_fmri, ud_name);
4797 4797 r = 0;
4798 4798 goto out;
4799 4799
4800 4800 case SCF_ERROR_NO_MEMORY:
4801 4801 r = ENOMEM;
4802 4802 goto out;
4803 4803
4804 4804 case SCF_ERROR_CONSTRAINT_VIOLATED:
4805 4805 case SCF_ERROR_INVALID_ARGUMENT:
4806 4806 default:
4807 4807 bad_error("fmri_to_entity", serr);
4808 4808 }
4809 4809
4810 4810 r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4811 4811 ud_iter2, ud_inst, imp_snap, ud_snpl);
4812 4812 switch (r) {
4813 4813 case 0:
4814 4814 break;
4815 4815
4816 4816 case ECONNABORTED:
4817 4817 goto out;
4818 4818
4819 4819 case ECANCELED:
4820 4820 case ENOENT:
4821 4821 warn(cf_missing, ient->sc_fmri, ud_name);
4822 4822 r = 0;
4823 4823 goto out;
4824 4824
4825 4825 case EBADF:
4826 4826 warn(r_no_lvl, ud_ctarg);
4827 4827 goto out;
4828 4828
4829 4829 case EINVAL:
4830 4830 default:
4831 4831 bad_error("entity_get_running_pg", r);
4832 4832 }
4833 4833
4834 4834 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4835 4835 switch (r) {
4836 4836 case 0:
4837 4837 break;
4838 4838
4839 4839 case ECANCELED:
4840 4840 warn(cf_missing, ient->sc_fmri, ud_name);
4841 4841 goto out;
4842 4842
4843 4843 case ECONNABORTED:
4844 4844 case ENOMEM:
4845 4845 case EBADF:
4846 4846 goto out;
4847 4847
4848 4848 case EACCES:
4849 4849 default:
4850 4850 bad_error("load_pg", r);
4851 4851 }
4852 4852
4853 4853 if (!pg_equal(current_pg, old_dpt_pgroup)) {
4854 4854 if (!pg_equal(current_pg, new_dpt_pgroup))
4855 4855 warn(cf_newdpg, ient->sc_fmri, ud_name);
4856 4856 internal_pgroup_free(current_pg);
4857 4857 r = 0;
4858 4858 goto out;
4859 4859 }
4860 4860
4861 4861 /* Uncustomized. Upgrade. */
4862 4862
4863 4863 r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4864 4864 switch (r) {
4865 4865 case 1:
4866 4866 if (pg_equal(current_pg, new_dpt_pgroup)) {
4867 4867 /* Already upgraded. */
4868 4868 internal_pgroup_free(current_pg);
4869 4869 r = 0;
4870 4870 goto out;
4871 4871 }
4872 4872
4873 4873 internal_pgroup_free(current_pg);
4874 4874
4875 4875 /* upgrade current_pg */
4876 4876 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4877 4877 switch (scf_error()) {
4878 4878 case SCF_ERROR_CONNECTION_BROKEN:
4879 4879 r = scferror2errno(scf_error());
4880 4880 goto out;
4881 4881
4882 4882 case SCF_ERROR_DELETED:
4883 4883 warn(cf_missing, ient->sc_fmri, ud_name);
4884 4884 r = 0;
4885 4885 goto out;
4886 4886
4887 4887 case SCF_ERROR_NOT_FOUND:
4888 4888 break;
4889 4889
4890 4890 case SCF_ERROR_INVALID_ARGUMENT:
4891 4891 case SCF_ERROR_NOT_BOUND:
4892 4892 case SCF_ERROR_NOT_SET:
4893 4893 case SCF_ERROR_HANDLE_MISMATCH:
4894 4894 default:
4895 4895 bad_error("entity_get_pg", scf_error());
4896 4896 }
4897 4897
4898 4898 if (tissvc)
4899 4899 r = scf_service_add_pg(target_ent, ud_name,
4900 4900 SCF_GROUP_DEPENDENCY, 0, ud_pg);
4901 4901 else
4902 4902 r = scf_instance_add_pg(target_ent, ud_name,
4903 4903 SCF_GROUP_DEPENDENCY, 0, ud_pg);
4904 4904 if (r != 0) {
4905 4905 switch (scf_error()) {
4906 4906 case SCF_ERROR_CONNECTION_BROKEN:
4907 4907 case SCF_ERROR_NO_RESOURCES:
4908 4908 case SCF_ERROR_BACKEND_READONLY:
4909 4909 case SCF_ERROR_BACKEND_ACCESS:
4910 4910 r = scferror2errno(scf_error());
4911 4911 goto out;
4912 4912
4913 4913 case SCF_ERROR_DELETED:
4914 4914 warn(cf_missing, ient->sc_fmri,
4915 4915 ud_name);
4916 4916 r = 0;
4917 4917 goto out;
4918 4918
4919 4919 case SCF_ERROR_PERMISSION_DENIED:
4920 4920 warn(emsg_pg_deleted, ud_ctarg,
4921 4921 ud_name);
4922 4922 r = EPERM;
4923 4923 goto out;
4924 4924
4925 4925 case SCF_ERROR_EXISTS:
4926 4926 warn(emsg_pg_added, ud_ctarg, ud_name);
4927 4927 r = EBUSY;
4928 4928 goto out;
4929 4929
4930 4930 case SCF_ERROR_NOT_BOUND:
4931 4931 case SCF_ERROR_HANDLE_MISMATCH:
4932 4932 case SCF_ERROR_INVALID_ARGUMENT:
4933 4933 case SCF_ERROR_NOT_SET:
4934 4934 default:
4935 4935 bad_error("entity_add_pg", scf_error());
4936 4936 }
4937 4937 }
4938 4938 }
4939 4939
4940 4940 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4941 4941 switch (r) {
4942 4942 case 0:
4943 4943 break;
4944 4944
4945 4945 case ECANCELED:
4946 4946 warn(cf_missing, ient->sc_fmri, ud_name);
4947 4947 goto out;
4948 4948
4949 4949 case ECONNABORTED:
4950 4950 case ENOMEM:
4951 4951 case EBADF:
4952 4952 goto out;
4953 4953
4954 4954 case EACCES:
4955 4955 default:
4956 4956 bad_error("load_pg", r);
4957 4957 }
4958 4958
4959 4959 if (g_verbose)
4960 4960 warn(upgrading, ient->sc_fmri, ud_name);
4961 4961
4962 4962 r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4963 4963 new_dpt_pgroup, 0, ient->sc_fmri);
4964 4964 switch (r) {
4965 4965 case 0:
4966 4966 break;
4967 4967
4968 4968 case ECANCELED:
4969 4969 warn(emsg_pg_deleted, ud_ctarg, ud_name);
4970 4970 r = EBUSY;
4971 4971 goto out;
4972 4972
4973 4973 case EPERM:
4974 4974 warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4975 4975 goto out;
4976 4976
4977 4977 case EBUSY:
4978 4978 warn(emsg_pg_changed, ud_ctarg, ud_name);
4979 4979 goto out;
4980 4980
4981 4981 case ECONNABORTED:
4982 4982 case ENOMEM:
4983 4983 case ENOSPC:
4984 4984 case EROFS:
4985 4985 case EACCES:
4986 4986 case EINVAL:
4987 4987 goto out;
4988 4988
4989 4989 default:
4990 4990 bad_error("upgrade_pg", r);
4991 4991 }
4992 4992 break;
4993 4993
4994 4994 case 0: {
4995 4995 scf_transaction_entry_t *ent;
4996 4996 scf_value_t *val;
4997 4997
4998 4998 internal_pgroup_free(current_pg);
4999 4999
5000 5000 /* delete old pg */
5001 5001 if (g_verbose)
5002 5002 warn(upgrading, ient->sc_fmri, ud_name);
5003 5003
5004 5004 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
5005 5005 switch (scf_error()) {
5006 5006 case SCF_ERROR_CONNECTION_BROKEN:
5007 5007 r = scferror2errno(scf_error());
5008 5008 goto out;
5009 5009
5010 5010 case SCF_ERROR_DELETED:
5011 5011 warn(cf_missing, ient->sc_fmri, ud_name);
5012 5012 r = 0;
5013 5013 goto out;
5014 5014
5015 5015 case SCF_ERROR_NOT_FOUND:
5016 5016 break;
5017 5017
5018 5018 case SCF_ERROR_INVALID_ARGUMENT:
5019 5019 case SCF_ERROR_NOT_BOUND:
5020 5020 case SCF_ERROR_NOT_SET:
5021 5021 case SCF_ERROR_HANDLE_MISMATCH:
5022 5022 default:
5023 5023 bad_error("entity_get_pg", scf_error());
5024 5024 }
5025 5025 } else if (scf_pg_delete(ud_pg) != 0) {
5026 5026 switch (scf_error()) {
5027 5027 case SCF_ERROR_DELETED:
5028 5028 break;
5029 5029
5030 5030 case SCF_ERROR_CONNECTION_BROKEN:
5031 5031 case SCF_ERROR_BACKEND_READONLY:
5032 5032 case SCF_ERROR_BACKEND_ACCESS:
5033 5033 r = scferror2errno(scf_error());
5034 5034 goto out;
5035 5035
5036 5036 case SCF_ERROR_PERMISSION_DENIED:
5037 5037 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
5038 5038 r = scferror2errno(scf_error());
5039 5039 goto out;
5040 5040
5041 5041 case SCF_ERROR_NOT_SET:
5042 5042 default:
5043 5043 bad_error("scf_pg_delete", scf_error());
5044 5044 }
5045 5045 }
5046 5046
5047 5047 /* import new one */
5048 5048 cbdata.sc_handle = g_hndl;
5049 5049 cbdata.sc_trans = NULL; /* handled below */
5050 5050 cbdata.sc_flags = 0;
5051 5051
5052 5052 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
5053 5053 if (r != UU_WALK_NEXT) {
5054 5054 if (r != UU_WALK_ERROR)
5055 5055 bad_error("lscf_dependent_import", r);
5056 5056
5057 5057 r = cbdata.sc_err;
5058 5058 goto out;
5059 5059 }
5060 5060
5061 5061 if (tx == NULL)
5062 5062 break;
5063 5063
5064 5064 if ((ent = scf_entry_create(g_hndl)) == NULL ||
5065 5065 (val = scf_value_create(g_hndl)) == NULL) {
5066 5066 if (scf_error() == SCF_ERROR_NO_MEMORY)
5067 5067 return (ENOMEM);
5068 5068
5069 5069 bad_error("scf_entry_create", scf_error());
5070 5070 }
5071 5071
5072 5072 if (scf_transaction_property_change_type(tx, ent, ud_name,
5073 5073 SCF_TYPE_FMRI) != 0) {
5074 5074 switch (scf_error()) {
5075 5075 case SCF_ERROR_CONNECTION_BROKEN:
5076 5076 r = scferror2errno(scf_error());
5077 5077 goto out;
5078 5078
5079 5079 case SCF_ERROR_DELETED:
5080 5080 warn(emsg_pg_deleted, ient->sc_fmri,
5081 5081 "dependents");
5082 5082 r = EBUSY;
5083 5083 goto out;
5084 5084
5085 5085 case SCF_ERROR_NOT_FOUND:
5086 5086 break;
5087 5087
5088 5088 case SCF_ERROR_NOT_BOUND:
5089 5089 case SCF_ERROR_HANDLE_MISMATCH:
5090 5090 case SCF_ERROR_INVALID_ARGUMENT:
5091 5091 case SCF_ERROR_NOT_SET:
5092 5092 default:
5093 5093 bad_error("scf_transaction_property_"
5094 5094 "change_type", scf_error());
5095 5095 }
5096 5096
5097 5097 if (scf_transaction_property_new(tx, ent, ud_name,
5098 5098 SCF_TYPE_FMRI) != 0) {
5099 5099 switch (scf_error()) {
5100 5100 case SCF_ERROR_CONNECTION_BROKEN:
5101 5101 r = scferror2errno(scf_error());
5102 5102 goto out;
5103 5103
5104 5104 case SCF_ERROR_DELETED:
5105 5105 warn(emsg_pg_deleted, ient->sc_fmri,
5106 5106 "dependents");
5107 5107 r = EBUSY;
5108 5108 goto out;
5109 5109
5110 5110 case SCF_ERROR_EXISTS:
5111 5111 warn(emsg_pg_changed, ient->sc_fmri,
5112 5112 "dependents");
5113 5113 r = EBUSY;
5114 5114 goto out;
5115 5115
5116 5116 case SCF_ERROR_INVALID_ARGUMENT:
5117 5117 case SCF_ERROR_HANDLE_MISMATCH:
5118 5118 case SCF_ERROR_NOT_BOUND:
5119 5119 case SCF_ERROR_NOT_SET:
5120 5120 default:
5121 5121 bad_error("scf_transaction_property_"
5122 5122 "new", scf_error());
5123 5123 }
5124 5124 }
5125 5125 }
5126 5126
5127 5127 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
5128 5128 new_dpt_pgroup->sc_pgroup_fmri) != 0)
5129 5129 /* invalid sc_pgroup_fmri caught above */
5130 5130 bad_error("scf_value_set_from_string",
5131 5131 scf_error());
5132 5132
5133 5133 if (scf_entry_add_value(ent, val) != 0)
5134 5134 bad_error("scf_entry_add_value", scf_error());
5135 5135 break;
5136 5136 }
5137 5137
5138 5138 case -2:
5139 5139 warn(li_corrupt, ient->sc_fmri);
5140 5140 internal_pgroup_free(current_pg);
5141 5141 r = EBADF;
5142 5142 goto out;
5143 5143
5144 5144 case -1:
5145 5145 default:
5146 5146 /* invalid sc_pgroup_fmri caught above */
5147 5147 bad_error("fmri_equal", r);
5148 5148 }
5149 5149
5150 5150 r = 0;
5151 5151
5152 5152 out:
5153 5153 if (old_dpt_pgroup != NULL)
5154 5154 internal_pgroup_free(old_dpt_pgroup);
5155 5155
5156 5156 return (r);
5157 5157 }
5158 5158
5159 5159 /*
5160 5160 * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
5161 5161 * would import it, except it seems to exist in the service anyway. Compare
5162 5162 * the existent dependent with the one we would import, and report any
5163 5163 * differences (if there are none, be silent). prop is the property which
5164 5164 * represents the existent dependent (in the dependents property group) in the
5165 5165 * entity corresponding to ient.
5166 5166 *
5167 5167 * Returns
5168 5168 * 0 - success (Sort of. At least, we can continue importing.)
5169 5169 * ECONNABORTED - repository connection broken
5170 5170 * EBUSY - ancestor of prop was deleted (error printed)
5171 5171 * ENOMEM - out of memory
5172 5172 * EBADF - corrupt property group (error printed)
5173 5173 * EINVAL - new_dpt_pgroup has invalid target (error printed)
5174 5174 */
5175 5175 static int
5176 5176 handle_dependent_conflict(const entity_t * const ient,
5177 5177 const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
5178 5178 {
5179 5179 int r;
5180 5180 scf_type_t ty;
5181 5181 scf_error_t scfe;
5182 5182 void *tptr;
5183 5183 int tissvc;
5184 5184 pgroup_t *pgroup;
5185 5185
5186 5186 if (scf_property_get_value(prop, ud_val) != 0) {
5187 5187 switch (scf_error()) {
5188 5188 case SCF_ERROR_CONNECTION_BROKEN:
5189 5189 return (scferror2errno(scf_error()));
5190 5190
5191 5191 case SCF_ERROR_DELETED:
5192 5192 warn(emsg_pg_deleted, ient->sc_fmri,
5193 5193 new_dpt_pgroup->sc_pgroup_name);
5194 5194 return (EBUSY);
5195 5195
5196 5196 case SCF_ERROR_CONSTRAINT_VIOLATED:
5197 5197 case SCF_ERROR_NOT_FOUND:
5198 5198 warn(gettext("Conflict upgrading %s (not importing "
5199 5199 "dependent \"%s\" because it already exists.) "
5200 5200 "Warning: The \"%s/%2$s\" property has more or "
5201 5201 "fewer than one value)).\n"), ient->sc_fmri,
5202 5202 new_dpt_pgroup->sc_pgroup_name, "dependents");
5203 5203 return (0);
5204 5204
5205 5205 case SCF_ERROR_HANDLE_MISMATCH:
5206 5206 case SCF_ERROR_NOT_BOUND:
5207 5207 case SCF_ERROR_NOT_SET:
5208 5208 case SCF_ERROR_PERMISSION_DENIED:
5209 5209 default:
5210 5210 bad_error("scf_property_get_value",
5211 5211 scf_error());
5212 5212 }
5213 5213 }
5214 5214
5215 5215 ty = scf_value_type(ud_val);
5216 5216 assert(ty != SCF_TYPE_INVALID);
5217 5217 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
5218 5218 warn(gettext("Conflict upgrading %s (not importing dependent "
5219 5219 "\"%s\" because it already exists). Warning: The "
5220 5220 "\"%s/%s\" property has unexpected type \"%s\")).\n"),
5221 5221 ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
5222 5222 scf_type_to_string(ty), "dependents");
5223 5223 return (0);
5224 5224 }
5225 5225
5226 5226 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
5227 5227 0)
5228 5228 bad_error("scf_value_get_as_string", scf_error());
5229 5229
5230 5230 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
5231 5231 switch (r) {
5232 5232 case 0:
5233 5233 warn(gettext("Conflict upgrading %s (not importing dependent "
5234 5234 "\"%s\" (target \"%s\") because it already exists with "
5235 5235 "target \"%s\").\n"), ient->sc_fmri,
5236 5236 new_dpt_pgroup->sc_pgroup_name,
5237 5237 new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
5238 5238 return (0);
5239 5239
5240 5240 case 1:
5241 5241 break;
5242 5242
5243 5243 case -1:
5244 5244 warn(gettext("Conflict upgrading %s (not importing dependent "
5245 5245 "\"%s\" because it already exists). Warning: The current "
5246 5246 "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
5247 5247 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5248 5248 return (0);
5249 5249
5250 5250 case -2:
5251 5251 warn(gettext("Dependent \"%s\" of %s has invalid target "
5252 5252 "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
5253 5253 new_dpt_pgroup->sc_pgroup_fmri);
5254 5254 return (EINVAL);
5255 5255
5256 5256 default:
5257 5257 bad_error("fmri_equal", r);
5258 5258 }
5259 5259
5260 5260 /* compare dependency pgs in target */
5261 5261 scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
5262 5262 switch (scfe) {
5263 5263 case SCF_ERROR_NONE:
5264 5264 break;
5265 5265
5266 5266 case SCF_ERROR_NO_MEMORY:
5267 5267 return (ENOMEM);
5268 5268
5269 5269 case SCF_ERROR_NOT_FOUND:
5270 5270 warn(emsg_dpt_dangling, ient->sc_fmri,
5271 5271 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5272 5272 return (0);
5273 5273
5274 5274 case SCF_ERROR_CONSTRAINT_VIOLATED:
5275 5275 case SCF_ERROR_INVALID_ARGUMENT:
5276 5276 default:
5277 5277 bad_error("fmri_to_entity", scfe);
5278 5278 }
5279 5279
5280 5280 r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
5281 5281 ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
5282 5282 switch (r) {
5283 5283 case 0:
5284 5284 break;
5285 5285
5286 5286 case ECONNABORTED:
5287 5287 return (r);
5288 5288
5289 5289 case ECANCELED:
5290 5290 warn(emsg_dpt_dangling, ient->sc_fmri,
5291 5291 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5292 5292 return (0);
5293 5293
5294 5294 case EBADF:
5295 5295 if (tissvc)
5296 5296 warn(gettext("%s has an instance with a \"%s\" "
5297 5297 "snapshot which is missing a snaplevel.\n"),
5298 5298 ud_ctarg, "running");
5299 5299 else
5300 5300 warn(gettext("%s has a \"%s\" snapshot which is "
5301 5301 "missing a snaplevel.\n"), ud_ctarg, "running");
5302 5302 /* FALLTHROUGH */
5303 5303
5304 5304 case ENOENT:
5305 5305 warn(emsg_dpt_no_dep, ient->sc_fmri,
5306 5306 new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5307 5307 new_dpt_pgroup->sc_pgroup_name);
5308 5308 return (0);
5309 5309
5310 5310 case EINVAL:
5311 5311 default:
5312 5312 bad_error("entity_get_running_pg", r);
5313 5313 }
5314 5314
5315 5315 pgroup = internal_pgroup_new();
5316 5316 if (pgroup == NULL)
5317 5317 return (ENOMEM);
5318 5318
5319 5319 r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
5320 5320 switch (r) {
5321 5321 case 0:
5322 5322 break;
5323 5323
5324 5324 case ECONNABORTED:
5325 5325 case EBADF:
5326 5326 case ENOMEM:
5327 5327 internal_pgroup_free(pgroup);
5328 5328 return (r);
5329 5329
5330 5330 case ECANCELED:
5331 5331 warn(emsg_dpt_no_dep, ient->sc_fmri,
5332 5332 new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5333 5333 new_dpt_pgroup->sc_pgroup_name);
5334 5334 internal_pgroup_free(pgroup);
5335 5335 return (0);
5336 5336
5337 5337 case EACCES:
5338 5338 default:
5339 5339 bad_error("load_pg", r);
5340 5340 }
5341 5341
5342 5342 /* report differences */
5343 5343 report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
5344 5344 internal_pgroup_free(pgroup);
5345 5345 return (0);
5346 5346 }
5347 5347
5348 5348 /*
5349 5349 * lipg is a property group in the last-import snapshot of ent, which is an
5350 5350 * scf_service_t or an scf_instance_t (according to ient). If lipg is not in
5351 5351 * ient's pgroups, delete it from ent if it hasn't been customized. If it is
5352 5352 * in ents's property groups, compare and upgrade ent appropriately.
5353 5353 *
5354 5354 * Returns
5355 5355 * 0 - success
5356 5356 * ECONNABORTED - repository connection broken
5357 5357 * ENOMEM - out of memory
5358 5358 * ENOSPC - configd is out of resources
5359 5359 * EINVAL - ient has invalid dependent (error printed)
5360 5360 * - ient has invalid pgroup_t (error printed)
5361 5361 * ECANCELED - ent has been deleted
5362 5362 * ENODEV - entity containing lipg has been deleted
5363 5363 * - entity containing running has been deleted
5364 5364 * EPERM - could not delete pg (permission denied) (error printed)
5365 5365 * - couldn't upgrade dependents (permission denied) (error printed)
5366 5366 * - couldn't import pg (permission denied) (error printed)
5367 5367 * - couldn't upgrade pg (permission denied) (error printed)
5368 5368 * EROFS - could not delete pg (repository read-only)
5369 5369 * - couldn't upgrade dependents (repository read-only)
5370 5370 * - couldn't import pg (repository read-only)
5371 5371 * - couldn't upgrade pg (repository read-only)
5372 5372 * EACCES - could not delete pg (backend access denied)
5373 5373 * - couldn't upgrade dependents (backend access denied)
5374 5374 * - couldn't import pg (backend access denied)
5375 5375 * - couldn't upgrade pg (backend access denied)
5376 5376 * - couldn't read property (backend access denied)
5377 5377 * EBUSY - property group was added (error printed)
5378 5378 * - property group was deleted (error printed)
5379 5379 * - property group changed (error printed)
5380 5380 * - "dependents" pg was added, changed, or deleted (error printed)
5381 5381 * - dependent target deleted (error printed)
5382 5382 * - dependent pg changed (error printed)
5383 5383 * EBADF - imp_snpl is corrupt (error printed)
5384 5384 * - ent has bad pg (error printed)
5385 5385 * EEXIST - dependent collision in target service (error printed)
5386 5386 */
5387 5387 static int
5388 5388 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
5389 5389 const scf_snaplevel_t *running)
5390 5390 {
5391 5391 int r;
5392 5392 pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
5393 5393 scf_callback_t cbdata;
5394 5394
5395 5395 const char * const cf_pg_missing =
5396 5396 gettext("Conflict upgrading %s (property group %s is missing)\n");
5397 5397 const char * const deleting =
5398 5398 gettext("%s: Deleting property group \"%s\".\n");
5399 5399
5400 5400 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5401 5401
5402 5402 /* Skip dependent property groups. */
5403 5403 if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
5404 5404 switch (scf_error()) {
5405 5405 case SCF_ERROR_DELETED:
5406 5406 return (ENODEV);
5407 5407
5408 5408 case SCF_ERROR_CONNECTION_BROKEN:
5409 5409 return (ECONNABORTED);
5410 5410
5411 5411 case SCF_ERROR_NOT_SET:
5412 5412 case SCF_ERROR_NOT_BOUND:
5413 5413 default:
5414 5414 bad_error("scf_pg_get_type", scf_error());
5415 5415 }
5416 5416 }
5417 5417
5418 5418 if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
5419 5419 if (scf_pg_get_property(lipg, "external", NULL) == 0)
5420 5420 return (0);
5421 5421
5422 5422 switch (scf_error()) {
5423 5423 case SCF_ERROR_NOT_FOUND:
5424 5424 break;
5425 5425
5426 5426 case SCF_ERROR_CONNECTION_BROKEN:
5427 5427 return (ECONNABORTED);
5428 5428
5429 5429 case SCF_ERROR_DELETED:
5430 5430 return (ENODEV);
5431 5431
5432 5432 case SCF_ERROR_INVALID_ARGUMENT:
5433 5433 case SCF_ERROR_NOT_BOUND:
5434 5434 case SCF_ERROR_HANDLE_MISMATCH:
5435 5435 case SCF_ERROR_NOT_SET:
5436 5436 default:
5437 5437 bad_error("scf_pg_get_property", scf_error());
5438 5438 }
5439 5439 }
5440 5440
5441 5441 /* lookup pg in new properties */
5442 5442 if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
5443 5443 switch (scf_error()) {
5444 5444 case SCF_ERROR_DELETED:
5445 5445 return (ENODEV);
5446 5446
5447 5447 case SCF_ERROR_CONNECTION_BROKEN:
5448 5448 return (ECONNABORTED);
5449 5449
5450 5450 case SCF_ERROR_NOT_SET:
5451 5451 case SCF_ERROR_NOT_BOUND:
5452 5452 default:
5453 5453 bad_error("scf_pg_get_name", scf_error());
5454 5454 }
5455 5455 }
5456 5456
5457 5457 pgrp.sc_pgroup_name = imp_str;
5458 5458 mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
5459 5459
5460 5460 if (mpg != NULL)
5461 5461 mpg->sc_pgroup_seen = 1;
5462 5462
5463 5463 /* Special handling for dependents */
5464 5464 if (strcmp(imp_str, "dependents") == 0)
5465 5465 return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
5466 5466
5467 5467 if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
5468 5468 return (upgrade_manifestfiles(NULL, ient, running, ent));
5469 5469
5470 5470 if (mpg == NULL || mpg->sc_pgroup_delete) {
5471 5471 /* property group was deleted from manifest */
5472 5472 if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5473 5473 switch (scf_error()) {
5474 5474 case SCF_ERROR_NOT_FOUND:
5475 5475 return (0);
5476 5476
5477 5477 case SCF_ERROR_DELETED:
5478 5478 case SCF_ERROR_CONNECTION_BROKEN:
5479 5479 return (scferror2errno(scf_error()));
5480 5480
5481 5481 case SCF_ERROR_INVALID_ARGUMENT:
5482 5482 case SCF_ERROR_HANDLE_MISMATCH:
5483 5483 case SCF_ERROR_NOT_BOUND:
5484 5484 case SCF_ERROR_NOT_SET:
5485 5485 default:
5486 5486 bad_error("entity_get_pg", scf_error());
5487 5487 }
5488 5488 }
5489 5489
5490 5490 if (mpg != NULL && mpg->sc_pgroup_delete) {
5491 5491 if (g_verbose)
5492 5492 warn(deleting, ient->sc_fmri, imp_str);
5493 5493 if (scf_pg_delete(imp_pg2) == 0)
5494 5494 return (0);
5495 5495
5496 5496 switch (scf_error()) {
5497 5497 case SCF_ERROR_DELETED:
5498 5498 return (0);
5499 5499
5500 5500 case SCF_ERROR_CONNECTION_BROKEN:
5501 5501 case SCF_ERROR_BACKEND_READONLY:
5502 5502 case SCF_ERROR_BACKEND_ACCESS:
5503 5503 return (scferror2errno(scf_error()));
5504 5504
5505 5505 case SCF_ERROR_PERMISSION_DENIED:
5506 5506 warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
5507 5507 return (scferror2errno(scf_error()));
5508 5508
5509 5509 case SCF_ERROR_NOT_SET:
5510 5510 default:
5511 5511 bad_error("scf_pg_delete", scf_error());
5512 5512 }
5513 5513 }
5514 5514
5515 5515 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5516 5516 switch (r) {
5517 5517 case 0:
5518 5518 break;
5519 5519
5520 5520 case ECANCELED:
5521 5521 return (ENODEV);
5522 5522
5523 5523 case ECONNABORTED:
5524 5524 case ENOMEM:
5525 5525 case EBADF:
5526 5526 case EACCES:
5527 5527 return (r);
5528 5528
5529 5529 default:
5530 5530 bad_error("load_pg", r);
5531 5531 }
5532 5532
5533 5533 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5534 5534 switch (r) {
5535 5535 case 0:
5536 5536 break;
5537 5537
5538 5538 case ECANCELED:
5539 5539 case ECONNABORTED:
5540 5540 case ENOMEM:
5541 5541 case EBADF:
5542 5542 case EACCES:
5543 5543 internal_pgroup_free(lipg_i);
5544 5544 return (r);
5545 5545
5546 5546 default:
5547 5547 bad_error("load_pg", r);
5548 5548 }
5549 5549
5550 5550 if (pg_equal(lipg_i, curpg_i)) {
5551 5551 if (g_verbose)
5552 5552 warn(deleting, ient->sc_fmri, imp_str);
5553 5553 if (scf_pg_delete(imp_pg2) != 0) {
5554 5554 switch (scf_error()) {
5555 5555 case SCF_ERROR_DELETED:
5556 5556 break;
5557 5557
5558 5558 case SCF_ERROR_CONNECTION_BROKEN:
5559 5559 internal_pgroup_free(lipg_i);
5560 5560 internal_pgroup_free(curpg_i);
5561 5561 return (ECONNABORTED);
5562 5562
5563 5563 case SCF_ERROR_NOT_SET:
5564 5564 case SCF_ERROR_NOT_BOUND:
5565 5565 default:
5566 5566 bad_error("scf_pg_delete", scf_error());
5567 5567 }
5568 5568 }
5569 5569 } else {
5570 5570 report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5571 5571 }
5572 5572
5573 5573 internal_pgroup_free(lipg_i);
5574 5574 internal_pgroup_free(curpg_i);
5575 5575
5576 5576 return (0);
5577 5577 }
5578 5578
5579 5579 /*
5580 5580 * Only dependent pgs can have override set, and we skipped those
5581 5581 * above.
5582 5582 */
5583 5583 assert(!mpg->sc_pgroup_override);
5584 5584
5585 5585 /* compare */
5586 5586 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5587 5587 switch (r) {
5588 5588 case 0:
5589 5589 break;
5590 5590
5591 5591 case ECANCELED:
5592 5592 return (ENODEV);
5593 5593
5594 5594 case ECONNABORTED:
5595 5595 case EBADF:
5596 5596 case ENOMEM:
5597 5597 case EACCES:
5598 5598 return (r);
5599 5599
5600 5600 default:
5601 5601 bad_error("load_pg", r);
5602 5602 }
5603 5603
5604 5604 if (pg_equal(mpg, lipg_i)) {
5605 5605 /* The manifest pg has not changed. Move on. */
5606 5606 r = 0;
5607 5607 goto out;
5608 5608 }
5609 5609
5610 5610 /* upgrade current properties according to lipg & mpg */
5611 5611 if (running != NULL)
5612 5612 r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5613 5613 else
5614 5614 r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5615 5615 if (r != 0) {
5616 5616 switch (scf_error()) {
5617 5617 case SCF_ERROR_CONNECTION_BROKEN:
5618 5618 r = scferror2errno(scf_error());
5619 5619 goto out;
5620 5620
5621 5621 case SCF_ERROR_DELETED:
5622 5622 if (running != NULL)
5623 5623 r = ENODEV;
5624 5624 else
5625 5625 r = ECANCELED;
5626 5626 goto out;
5627 5627
5628 5628 case SCF_ERROR_NOT_FOUND:
5629 5629 break;
5630 5630
5631 5631 case SCF_ERROR_INVALID_ARGUMENT:
5632 5632 case SCF_ERROR_HANDLE_MISMATCH:
5633 5633 case SCF_ERROR_NOT_BOUND:
5634 5634 case SCF_ERROR_NOT_SET:
5635 5635 default:
5636 5636 bad_error("entity_get_pg", scf_error());
5637 5637 }
5638 5638
5639 5639 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5640 5640
5641 5641 r = 0;
5642 5642 goto out;
5643 5643 }
5644 5644
5645 5645 r = load_pg_attrs(imp_pg2, &curpg_i);
5646 5646 switch (r) {
5647 5647 case 0:
5648 5648 break;
5649 5649
5650 5650 case ECANCELED:
5651 5651 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5652 5652 r = 0;
5653 5653 goto out;
5654 5654
5655 5655 case ECONNABORTED:
5656 5656 case ENOMEM:
5657 5657 goto out;
5658 5658
5659 5659 default:
5660 5660 bad_error("load_pg_attrs", r);
5661 5661 }
5662 5662
5663 5663 if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5664 5664 (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5665 5665 internal_pgroup_free(curpg_i);
5666 5666 r = 0;
5667 5667 goto out;
5668 5668 }
5669 5669
5670 5670 internal_pgroup_free(curpg_i);
5671 5671
5672 5672 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5673 5673 switch (r) {
5674 5674 case 0:
5675 5675 break;
5676 5676
5677 5677 case ECANCELED:
5678 5678 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5679 5679 r = 0;
5680 5680 goto out;
5681 5681
5682 5682 case ECONNABORTED:
5683 5683 case EBADF:
5684 5684 case ENOMEM:
5685 5685 case EACCES:
5686 5686 goto out;
5687 5687
5688 5688 default:
5689 5689 bad_error("load_pg", r);
5690 5690 }
5691 5691
5692 5692 if (pg_equal(lipg_i, curpg_i) &&
5693 5693 !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5694 5694 int do_delete = 1;
5695 5695
5696 5696 if (g_verbose)
5697 5697 warn(gettext("%s: Upgrading property group \"%s\".\n"),
5698 5698 ient->sc_fmri, mpg->sc_pgroup_name);
5699 5699
5700 5700 internal_pgroup_free(curpg_i);
5701 5701
5702 5702 if (running != NULL &&
5703 5703 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5704 5704 switch (scf_error()) {
5705 5705 case SCF_ERROR_DELETED:
5706 5706 r = ECANCELED;
5707 5707 goto out;
5708 5708
5709 5709 case SCF_ERROR_NOT_FOUND:
5710 5710 do_delete = 0;
5711 5711 break;
5712 5712
5713 5713 case SCF_ERROR_CONNECTION_BROKEN:
5714 5714 r = scferror2errno(scf_error());
5715 5715 goto out;
5716 5716
5717 5717 case SCF_ERROR_HANDLE_MISMATCH:
5718 5718 case SCF_ERROR_INVALID_ARGUMENT:
5719 5719 case SCF_ERROR_NOT_SET:
5720 5720 case SCF_ERROR_NOT_BOUND:
5721 5721 default:
5722 5722 bad_error("entity_get_pg", scf_error());
5723 5723 }
5724 5724 }
5725 5725
5726 5726 if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5727 5727 switch (scf_error()) {
5728 5728 case SCF_ERROR_DELETED:
5729 5729 break;
5730 5730
5731 5731 case SCF_ERROR_CONNECTION_BROKEN:
5732 5732 case SCF_ERROR_BACKEND_READONLY:
5733 5733 case SCF_ERROR_BACKEND_ACCESS:
5734 5734 r = scferror2errno(scf_error());
5735 5735 goto out;
5736 5736
5737 5737 case SCF_ERROR_PERMISSION_DENIED:
5738 5738 warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5739 5739 ient->sc_fmri);
5740 5740 r = scferror2errno(scf_error());
5741 5741 goto out;
5742 5742
5743 5743 case SCF_ERROR_NOT_SET:
5744 5744 case SCF_ERROR_NOT_BOUND:
5745 5745 default:
5746 5746 bad_error("scf_pg_delete", scf_error());
5747 5747 }
5748 5748 }
5749 5749
5750 5750 cbdata.sc_handle = g_hndl;
5751 5751 cbdata.sc_parent = ent;
5752 5752 cbdata.sc_service = issvc;
5753 5753 cbdata.sc_flags = 0;
5754 5754 cbdata.sc_source_fmri = ient->sc_fmri;
5755 5755 cbdata.sc_target_fmri = ient->sc_fmri;
5756 5756
5757 5757 r = entity_pgroup_import(mpg, &cbdata);
5758 5758 switch (r) {
5759 5759 case UU_WALK_NEXT:
5760 5760 r = 0;
5761 5761 goto out;
5762 5762
5763 5763 case UU_WALK_ERROR:
5764 5764 if (cbdata.sc_err == EEXIST) {
5765 5765 warn(emsg_pg_added, ient->sc_fmri,
5766 5766 mpg->sc_pgroup_name);
5767 5767 r = EBUSY;
5768 5768 } else {
5769 5769 r = cbdata.sc_err;
5770 5770 }
5771 5771 goto out;
5772 5772
5773 5773 default:
5774 5774 bad_error("entity_pgroup_import", r);
5775 5775 }
5776 5776 }
5777 5777
5778 5778 if (running != NULL &&
5779 5779 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5780 5780 switch (scf_error()) {
5781 5781 case SCF_ERROR_CONNECTION_BROKEN:
5782 5782 case SCF_ERROR_DELETED:
5783 5783 r = scferror2errno(scf_error());
5784 5784 goto out;
5785 5785
5786 5786 case SCF_ERROR_NOT_FOUND:
5787 5787 break;
5788 5788
5789 5789 case SCF_ERROR_HANDLE_MISMATCH:
5790 5790 case SCF_ERROR_INVALID_ARGUMENT:
5791 5791 case SCF_ERROR_NOT_SET:
5792 5792 case SCF_ERROR_NOT_BOUND:
5793 5793 default:
5794 5794 bad_error("entity_get_pg", scf_error());
5795 5795 }
5796 5796
5797 5797 cbdata.sc_handle = g_hndl;
5798 5798 cbdata.sc_parent = ent;
5799 5799 cbdata.sc_service = issvc;
5800 5800 cbdata.sc_flags = SCI_FORCE;
5801 5801 cbdata.sc_source_fmri = ient->sc_fmri;
5802 5802 cbdata.sc_target_fmri = ient->sc_fmri;
5803 5803
5804 5804 r = entity_pgroup_import(mpg, &cbdata);
5805 5805 switch (r) {
5806 5806 case UU_WALK_NEXT:
5807 5807 r = 0;
5808 5808 goto out;
5809 5809
5810 5810 case UU_WALK_ERROR:
5811 5811 if (cbdata.sc_err == EEXIST) {
5812 5812 warn(emsg_pg_added, ient->sc_fmri,
5813 5813 mpg->sc_pgroup_name);
5814 5814 r = EBUSY;
5815 5815 } else {
5816 5816 r = cbdata.sc_err;
5817 5817 }
5818 5818 goto out;
5819 5819
5820 5820 default:
5821 5821 bad_error("entity_pgroup_import", r);
5822 5822 }
5823 5823 }
5824 5824
5825 5825 r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5826 5826 internal_pgroup_free(curpg_i);
5827 5827 switch (r) {
5828 5828 case 0:
5829 5829 ient->sc_import_state = IMPORT_PROP_BEGUN;
5830 5830 break;
5831 5831
5832 5832 case ECANCELED:
5833 5833 warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5834 5834 r = EBUSY;
5835 5835 break;
5836 5836
5837 5837 case EPERM:
5838 5838 warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5839 5839 break;
5840 5840
5841 5841 case EBUSY:
5842 5842 warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5843 5843 break;
5844 5844
5845 5845 case ECONNABORTED:
5846 5846 case ENOMEM:
5847 5847 case ENOSPC:
5848 5848 case EROFS:
5849 5849 case EACCES:
5850 5850 case EINVAL:
5851 5851 break;
5852 5852
5853 5853 default:
5854 5854 bad_error("upgrade_pg", r);
5855 5855 }
5856 5856
5857 5857 out:
5858 5858 internal_pgroup_free(lipg_i);
5859 5859 return (r);
5860 5860 }
5861 5861
5862 5862 /*
5863 5863 * Upgrade the properties of ent according to snpl & ient.
5864 5864 *
5865 5865 * Returns
5866 5866 * 0 - success
5867 5867 * ECONNABORTED - repository connection broken
5868 5868 * ENOMEM - out of memory
5869 5869 * ENOSPC - configd is out of resources
5870 5870 * ECANCELED - ent was deleted
5871 5871 * ENODEV - entity containing snpl was deleted
5872 5872 * - entity containing running was deleted
5873 5873 * EBADF - imp_snpl is corrupt (error printed)
5874 5874 * - ent has corrupt pg (error printed)
5875 5875 * - dependent has corrupt pg (error printed)
5876 5876 * - dependent target has a corrupt snapshot (error printed)
5877 5877 * EBUSY - pg was added, changed, or deleted (error printed)
5878 5878 * - dependent target was deleted (error printed)
5879 5879 * - dependent pg changed (error printed)
5880 5880 * EINVAL - invalid property group name (error printed)
5881 5881 * - invalid property name (error printed)
5882 5882 * - invalid value (error printed)
5883 5883 * - ient has invalid pgroup or dependent (error printed)
5884 5884 * EPERM - could not create property group (permission denied) (error printed)
5885 5885 * - could not modify property group (permission denied) (error printed)
5886 5886 * - couldn't delete, upgrade, or import pg or dependent (error printed)
5887 5887 * EROFS - could not create property group (repository read-only)
5888 5888 * - couldn't delete, upgrade, or import pg or dependent
5889 5889 * EACCES - could not create property group (backend access denied)
5890 5890 * - couldn't delete, upgrade, or import pg or dependent
5891 5891 * EEXIST - dependent collision in target service (error printed)
5892 5892 */
5893 5893 static int
5894 5894 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5895 5895 entity_t *ient)
5896 5896 {
5897 5897 pgroup_t *pg, *rpg;
5898 5898 int r;
5899 5899 uu_list_t *pgs = ient->sc_pgroups;
5900 5900
5901 5901 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5902 5902
5903 5903 /* clear sc_sceen for pgs */
5904 5904 if (uu_list_walk(pgs, clear_int,
5905 5905 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5906 5906 bad_error("uu_list_walk", uu_error());
5907 5907
5908 5908 if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5909 5909 switch (scf_error()) {
5910 5910 case SCF_ERROR_DELETED:
5911 5911 return (ENODEV);
5912 5912
5913 5913 case SCF_ERROR_CONNECTION_BROKEN:
5914 5914 return (ECONNABORTED);
5915 5915
5916 5916 case SCF_ERROR_NOT_SET:
5917 5917 case SCF_ERROR_NOT_BOUND:
5918 5918 case SCF_ERROR_HANDLE_MISMATCH:
5919 5919 default:
5920 5920 bad_error("scf_iter_snaplevel_pgs", scf_error());
5921 5921 }
5922 5922 }
5923 5923
5924 5924 for (;;) {
5925 5925 r = scf_iter_next_pg(imp_up_iter, imp_pg);
5926 5926 if (r == 0)
5927 5927 break;
5928 5928 if (r == 1) {
5929 5929 r = process_old_pg(imp_pg, ient, ent, running);
5930 5930 switch (r) {
5931 5931 case 0:
5932 5932 break;
5933 5933
5934 5934 case ECONNABORTED:
5935 5935 case ENOMEM:
5936 5936 case ENOSPC:
5937 5937 case ECANCELED:
5938 5938 case ENODEV:
5939 5939 case EPERM:
5940 5940 case EROFS:
5941 5941 case EACCES:
5942 5942 case EBADF:
5943 5943 case EBUSY:
5944 5944 case EINVAL:
5945 5945 case EEXIST:
5946 5946 return (r);
5947 5947
5948 5948 default:
5949 5949 bad_error("process_old_pg", r);
5950 5950 }
5951 5951 continue;
5952 5952 }
5953 5953 if (r != -1)
5954 5954 bad_error("scf_iter_next_pg", r);
5955 5955
5956 5956 switch (scf_error()) {
5957 5957 case SCF_ERROR_DELETED:
5958 5958 return (ENODEV);
5959 5959
5960 5960 case SCF_ERROR_CONNECTION_BROKEN:
5961 5961 return (ECONNABORTED);
5962 5962
5963 5963 case SCF_ERROR_HANDLE_MISMATCH:
5964 5964 case SCF_ERROR_NOT_BOUND:
5965 5965 case SCF_ERROR_NOT_SET:
5966 5966 case SCF_ERROR_INVALID_ARGUMENT:
5967 5967 default:
5968 5968 bad_error("scf_iter_next_pg", scf_error());
5969 5969 }
5970 5970 }
5971 5971
5972 5972 for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5973 5973 if (pg->sc_pgroup_seen)
5974 5974 continue;
5975 5975
5976 5976 /* pg is new */
5977 5977
5978 5978 if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5979 5979 r = upgrade_dependents(NULL, imp_snpl, ient, running,
5980 5980 ent);
5981 5981 switch (r) {
5982 5982 case 0:
5983 5983 break;
5984 5984
5985 5985 case ECONNABORTED:
5986 5986 case ENOMEM:
5987 5987 case ENOSPC:
5988 5988 case ECANCELED:
5989 5989 case ENODEV:
5990 5990 case EBADF:
5991 5991 case EBUSY:
5992 5992 case EINVAL:
5993 5993 case EPERM:
5994 5994 case EROFS:
5995 5995 case EACCES:
5996 5996 case EEXIST:
5997 5997 return (r);
5998 5998
5999 5999 default:
6000 6000 bad_error("upgrade_dependents", r);
6001 6001 }
6002 6002 continue;
6003 6003 }
6004 6004
6005 6005 if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
6006 6006 r = upgrade_manifestfiles(pg, ient, running, ent);
6007 6007 switch (r) {
6008 6008 case 0:
6009 6009 break;
6010 6010
6011 6011 case ECONNABORTED:
6012 6012 case ENOMEM:
6013 6013 case ENOSPC:
6014 6014 case ECANCELED:
6015 6015 case ENODEV:
6016 6016 case EBADF:
6017 6017 case EBUSY:
6018 6018 case EINVAL:
6019 6019 case EPERM:
6020 6020 case EROFS:
6021 6021 case EACCES:
6022 6022 case EEXIST:
6023 6023 return (r);
6024 6024
6025 6025 default:
6026 6026 bad_error("upgrade_manifestfiles", r);
6027 6027 }
6028 6028 continue;
6029 6029 }
6030 6030
6031 6031 if (running != NULL) {
6032 6032 r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
6033 6033 imp_pg);
6034 6034 } else {
6035 6035 r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
6036 6036 imp_pg);
6037 6037 }
6038 6038 if (r != 0) {
6039 6039 scf_callback_t cbdata;
6040 6040
6041 6041 switch (scf_error()) {
6042 6042 case SCF_ERROR_NOT_FOUND:
6043 6043 break;
6044 6044
6045 6045 case SCF_ERROR_CONNECTION_BROKEN:
6046 6046 return (scferror2errno(scf_error()));
6047 6047
6048 6048 case SCF_ERROR_DELETED:
6049 6049 if (running != NULL)
6050 6050 return (ENODEV);
6051 6051 else
6052 6052 return (scferror2errno(scf_error()));
6053 6053
6054 6054 case SCF_ERROR_INVALID_ARGUMENT:
6055 6055 warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
6056 6056 pg->sc_pgroup_name);
6057 6057 return (EINVAL);
6058 6058
6059 6059 case SCF_ERROR_NOT_SET:
6060 6060 case SCF_ERROR_HANDLE_MISMATCH:
6061 6061 case SCF_ERROR_NOT_BOUND:
6062 6062 default:
6063 6063 bad_error("entity_get_pg", scf_error());
6064 6064 }
6065 6065
6066 6066 /* User doesn't have pg, so import it. */
6067 6067
6068 6068 cbdata.sc_handle = g_hndl;
6069 6069 cbdata.sc_parent = ent;
6070 6070 cbdata.sc_service = issvc;
6071 6071 cbdata.sc_flags = SCI_FORCE;
6072 6072 cbdata.sc_source_fmri = ient->sc_fmri;
6073 6073 cbdata.sc_target_fmri = ient->sc_fmri;
6074 6074
6075 6075 r = entity_pgroup_import(pg, &cbdata);
6076 6076 switch (r) {
6077 6077 case UU_WALK_NEXT:
6078 6078 ient->sc_import_state = IMPORT_PROP_BEGUN;
6079 6079 continue;
6080 6080
6081 6081 case UU_WALK_ERROR:
6082 6082 if (cbdata.sc_err == EEXIST) {
6083 6083 warn(emsg_pg_added, ient->sc_fmri,
6084 6084 pg->sc_pgroup_name);
6085 6085 return (EBUSY);
6086 6086 }
6087 6087 return (cbdata.sc_err);
6088 6088
6089 6089 default:
6090 6090 bad_error("entity_pgroup_import", r);
6091 6091 }
6092 6092 }
6093 6093
6094 6094 /* report differences between pg & current */
6095 6095 r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
6096 6096 switch (r) {
6097 6097 case 0:
6098 6098 break;
6099 6099
6100 6100 case ECANCELED:
6101 6101 warn(emsg_pg_deleted, ient->sc_fmri,
6102 6102 pg->sc_pgroup_name);
6103 6103 return (EBUSY);
6104 6104
6105 6105 case ECONNABORTED:
6106 6106 case EBADF:
6107 6107 case ENOMEM:
6108 6108 case EACCES:
6109 6109 return (r);
6110 6110
6111 6111 default:
6112 6112 bad_error("load_pg", r);
6113 6113 }
6114 6114 report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
6115 6115 internal_pgroup_free(rpg);
6116 6116 rpg = NULL;
6117 6117 }
6118 6118
6119 6119 return (0);
6120 6120 }
6121 6121
6122 6122 /*
6123 6123 * Import an instance. If it doesn't exist, create it. If it has
6124 6124 * a last-import snapshot, upgrade its properties. Finish by updating its
6125 6125 * last-import snapshot. If it doesn't have a last-import snapshot then it
6126 6126 * could have been created for a dependent tag in another manifest. Import the
6127 6127 * new properties. If there's a conflict, don't override, like now?
6128 6128 *
6129 6129 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
6130 6130 * lcbdata->sc_err to
6131 6131 * ECONNABORTED - repository connection broken
6132 6132 * ENOMEM - out of memory
6133 6133 * ENOSPC - svc.configd is out of resources
6134 6134 * EEXIST - dependency collision in dependent service (error printed)
6135 6135 * EPERM - couldn't create temporary instance (permission denied)
6136 6136 * - couldn't import into temporary instance (permission denied)
6137 6137 * - couldn't take snapshot (permission denied)
6138 6138 * - couldn't upgrade properties (permission denied)
6139 6139 * - couldn't import properties (permission denied)
6140 6140 * - couldn't import dependents (permission denied)
6141 6141 * EROFS - couldn't create temporary instance (repository read-only)
6142 6142 * - couldn't import into temporary instance (repository read-only)
6143 6143 * - couldn't upgrade properties (repository read-only)
6144 6144 * - couldn't import properties (repository read-only)
6145 6145 * - couldn't import dependents (repository read-only)
6146 6146 * EACCES - couldn't create temporary instance (backend access denied)
6147 6147 * - couldn't import into temporary instance (backend access denied)
6148 6148 * - couldn't upgrade properties (backend access denied)
6149 6149 * - couldn't import properties (backend access denied)
6150 6150 * - couldn't import dependents (backend access denied)
6151 6151 * EINVAL - invalid instance name (error printed)
6152 6152 * - invalid pgroup_t's (error printed)
6153 6153 * - invalid dependents (error printed)
6154 6154 * EBUSY - temporary service deleted (error printed)
6155 6155 * - temporary instance deleted (error printed)
6156 6156 * - temporary instance changed (error printed)
6157 6157 * - temporary instance already exists (error printed)
6158 6158 * - instance deleted (error printed)
6159 6159 * EBADF - instance has corrupt last-import snapshot (error printed)
6160 6160 * - instance is corrupt (error printed)
6161 6161 * - dependent has corrupt pg (error printed)
6162 6162 * - dependent target has a corrupt snapshot (error printed)
6163 6163 * -1 - unknown libscf error (error printed)
6164 6164 */
6165 6165 static int
6166 6166 lscf_instance_import(void *v, void *pvt)
6167 6167 {
6168 6168 entity_t *inst = v;
6169 6169 scf_callback_t ctx;
6170 6170 scf_callback_t *lcbdata = pvt;
6171 6171 scf_service_t *rsvc = lcbdata->sc_parent;
6172 6172 int r;
6173 6173 scf_snaplevel_t *running;
6174 6174 int flags = lcbdata->sc_flags;
6175 6175
6176 6176 const char * const emsg_tdel =
6177 6177 gettext("Temporary instance svc:/%s:%s was deleted.\n");
6178 6178 const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
6179 6179 "changed unexpectedly.\n");
6180 6180 const char * const emsg_del = gettext("%s changed unexpectedly "
6181 6181 "(instance \"%s\" was deleted.)\n");
6182 6182 const char * const emsg_badsnap = gettext(
6183 6183 "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
6184 6184
6185 6185 /*
6186 6186 * prepare last-import snapshot:
6187 6187 * create temporary instance (service was precreated)
6188 6188 * populate with properties from bundle
6189 6189 * take snapshot
6190 6190 */
6191 6191 if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
6192 6192 switch (scf_error()) {
6193 6193 case SCF_ERROR_CONNECTION_BROKEN:
6194 6194 case SCF_ERROR_NO_RESOURCES:
6195 6195 case SCF_ERROR_BACKEND_READONLY:
6196 6196 case SCF_ERROR_BACKEND_ACCESS:
6197 6197 return (stash_scferror(lcbdata));
6198 6198
6199 6199 case SCF_ERROR_EXISTS:
6200 6200 warn(gettext("Temporary service svc:/%s "
6201 6201 "changed unexpectedly (instance \"%s\" added).\n"),
6202 6202 imp_tsname, inst->sc_name);
6203 6203 lcbdata->sc_err = EBUSY;
6204 6204 return (UU_WALK_ERROR);
6205 6205
6206 6206 case SCF_ERROR_DELETED:
6207 6207 warn(gettext("Temporary service svc:/%s "
6208 6208 "was deleted unexpectedly.\n"), imp_tsname);
6209 6209 lcbdata->sc_err = EBUSY;
6210 6210 return (UU_WALK_ERROR);
6211 6211
6212 6212 case SCF_ERROR_INVALID_ARGUMENT:
6213 6213 warn(gettext("Invalid instance name \"%s\".\n"),
6214 6214 inst->sc_name);
6215 6215 return (stash_scferror(lcbdata));
6216 6216
6217 6217 case SCF_ERROR_PERMISSION_DENIED:
6218 6218 warn(gettext("Could not create temporary instance "
6219 6219 "\"%s\" in svc:/%s (permission denied).\n"),
6220 6220 inst->sc_name, imp_tsname);
6221 6221 return (stash_scferror(lcbdata));
6222 6222
6223 6223 case SCF_ERROR_HANDLE_MISMATCH:
6224 6224 case SCF_ERROR_NOT_BOUND:
6225 6225 case SCF_ERROR_NOT_SET:
6226 6226 default:
6227 6227 bad_error("scf_service_add_instance", scf_error());
6228 6228 }
6229 6229 }
6230 6230
6231 6231 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6232 6232 inst->sc_name);
6233 6233 if (r < 0)
6234 6234 bad_error("snprintf", errno);
6235 6235
6236 6236 r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
6237 6237 lcbdata->sc_flags | SCI_NOENABLED);
6238 6238 switch (r) {
6239 6239 case 0:
6240 6240 break;
6241 6241
6242 6242 case ECANCELED:
6243 6243 warn(emsg_tdel, imp_tsname, inst->sc_name);
6244 6244 lcbdata->sc_err = EBUSY;
6245 6245 r = UU_WALK_ERROR;
6246 6246 goto deltemp;
6247 6247
6248 6248 case EEXIST:
6249 6249 warn(emsg_tchg, imp_tsname, inst->sc_name);
6250 6250 lcbdata->sc_err = EBUSY;
6251 6251 r = UU_WALK_ERROR;
6252 6252 goto deltemp;
6253 6253
6254 6254 case ECONNABORTED:
6255 6255 goto connaborted;
6256 6256
6257 6257 case ENOMEM:
6258 6258 case ENOSPC:
6259 6259 case EPERM:
6260 6260 case EROFS:
6261 6261 case EACCES:
6262 6262 case EINVAL:
6263 6263 case EBUSY:
6264 6264 lcbdata->sc_err = r;
6265 6265 r = UU_WALK_ERROR;
6266 6266 goto deltemp;
6267 6267
6268 6268 default:
6269 6269 bad_error("lscf_import_instance_pgs", r);
6270 6270 }
6271 6271
6272 6272 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6273 6273 inst->sc_name);
6274 6274 if (r < 0)
6275 6275 bad_error("snprintf", errno);
6276 6276
6277 6277 ctx.sc_handle = lcbdata->sc_handle;
6278 6278 ctx.sc_parent = imp_tinst;
6279 6279 ctx.sc_service = 0;
6280 6280 ctx.sc_source_fmri = inst->sc_fmri;
6281 6281 ctx.sc_target_fmri = imp_str;
6282 6282 if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
6283 6283 UU_DEFAULT) != 0) {
6284 6284 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6285 6285 bad_error("uu_list_walk", uu_error());
6286 6286
6287 6287 switch (ctx.sc_err) {
6288 6288 case ECONNABORTED:
6289 6289 goto connaborted;
6290 6290
6291 6291 case ECANCELED:
6292 6292 warn(emsg_tdel, imp_tsname, inst->sc_name);
6293 6293 lcbdata->sc_err = EBUSY;
6294 6294 break;
6295 6295
6296 6296 case EEXIST:
6297 6297 warn(emsg_tchg, imp_tsname, inst->sc_name);
6298 6298 lcbdata->sc_err = EBUSY;
6299 6299 break;
6300 6300
6301 6301 default:
6302 6302 lcbdata->sc_err = ctx.sc_err;
6303 6303 }
6304 6304 r = UU_WALK_ERROR;
6305 6305 goto deltemp;
6306 6306 }
6307 6307
6308 6308 if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
6309 6309 inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
6310 6310 switch (scf_error()) {
6311 6311 case SCF_ERROR_CONNECTION_BROKEN:
6312 6312 goto connaborted;
6313 6313
6314 6314 case SCF_ERROR_NO_RESOURCES:
6315 6315 r = stash_scferror(lcbdata);
6316 6316 goto deltemp;
6317 6317
6318 6318 case SCF_ERROR_EXISTS:
6319 6319 warn(emsg_tchg, imp_tsname, inst->sc_name);
6320 6320 lcbdata->sc_err = EBUSY;
6321 6321 r = UU_WALK_ERROR;
6322 6322 goto deltemp;
6323 6323
6324 6324 case SCF_ERROR_PERMISSION_DENIED:
6325 6325 warn(gettext("Could not take \"%s\" snapshot of %s "
6326 6326 "(permission denied).\n"), snap_lastimport,
6327 6327 imp_str);
6328 6328 r = stash_scferror(lcbdata);
6329 6329 goto deltemp;
6330 6330
6331 6331 default:
6332 6332 scfwarn();
6333 6333 lcbdata->sc_err = -1;
6334 6334 r = UU_WALK_ERROR;
6335 6335 goto deltemp;
6336 6336
6337 6337 case SCF_ERROR_HANDLE_MISMATCH:
6338 6338 case SCF_ERROR_INVALID_ARGUMENT:
6339 6339 case SCF_ERROR_NOT_SET:
6340 6340 bad_error("_scf_snapshot_take_new_named", scf_error());
6341 6341 }
6342 6342 }
6343 6343
6344 6344 if (lcbdata->sc_flags & SCI_FRESH)
6345 6345 goto fresh;
6346 6346
6347 6347 if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
6348 6348 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6349 6349 imp_lisnap) != 0) {
6350 6350 switch (scf_error()) {
6351 6351 case SCF_ERROR_DELETED:
6352 6352 warn(emsg_del, inst->sc_parent->sc_fmri,
6353 6353 inst->sc_name);
6354 6354 lcbdata->sc_err = EBUSY;
6355 6355 r = UU_WALK_ERROR;
6356 6356 goto deltemp;
6357 6357
6358 6358 case SCF_ERROR_NOT_FOUND:
6359 6359 flags |= SCI_FORCE;
6360 6360 goto nosnap;
6361 6361
6362 6362 case SCF_ERROR_CONNECTION_BROKEN:
6363 6363 goto connaborted;
6364 6364
6365 6365 case SCF_ERROR_INVALID_ARGUMENT:
6366 6366 case SCF_ERROR_HANDLE_MISMATCH:
6367 6367 case SCF_ERROR_NOT_BOUND:
6368 6368 case SCF_ERROR_NOT_SET:
6369 6369 default:
6370 6370 bad_error("scf_instance_get_snapshot",
6371 6371 scf_error());
6372 6372 }
6373 6373 }
6374 6374
6375 6375 /* upgrade */
6376 6376
6377 6377 /*
6378 6378 * compare new properties with last-import properties
6379 6379 * upgrade current properties
6380 6380 */
6381 6381 /* clear sc_sceen for pgs */
6382 6382 if (uu_list_walk(inst->sc_pgroups, clear_int,
6383 6383 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
6384 6384 0)
6385 6385 bad_error("uu_list_walk", uu_error());
6386 6386
6387 6387 r = get_snaplevel(imp_lisnap, 0, imp_snpl);
6388 6388 switch (r) {
6389 6389 case 0:
6390 6390 break;
6391 6391
6392 6392 case ECONNABORTED:
6393 6393 goto connaborted;
6394 6394
6395 6395 case ECANCELED:
6396 6396 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6397 6397 lcbdata->sc_err = EBUSY;
6398 6398 r = UU_WALK_ERROR;
6399 6399 goto deltemp;
6400 6400
6401 6401 case ENOENT:
6402 6402 warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
6403 6403 lcbdata->sc_err = EBADF;
6404 6404 r = UU_WALK_ERROR;
6405 6405 goto deltemp;
6406 6406
6407 6407 default:
6408 6408 bad_error("get_snaplevel", r);
6409 6409 }
6410 6410
6411 6411 if (scf_instance_get_snapshot(imp_inst, snap_running,
6412 6412 imp_rsnap) != 0) {
6413 6413 switch (scf_error()) {
6414 6414 case SCF_ERROR_DELETED:
6415 6415 warn(emsg_del, inst->sc_parent->sc_fmri,
6416 6416 inst->sc_name);
6417 6417 lcbdata->sc_err = EBUSY;
6418 6418 r = UU_WALK_ERROR;
6419 6419 goto deltemp;
6420 6420
6421 6421 case SCF_ERROR_NOT_FOUND:
6422 6422 break;
6423 6423
6424 6424 case SCF_ERROR_CONNECTION_BROKEN:
6425 6425 goto connaborted;
6426 6426
6427 6427 case SCF_ERROR_INVALID_ARGUMENT:
6428 6428 case SCF_ERROR_HANDLE_MISMATCH:
6429 6429 case SCF_ERROR_NOT_BOUND:
6430 6430 case SCF_ERROR_NOT_SET:
6431 6431 default:
6432 6432 bad_error("scf_instance_get_snapshot",
6433 6433 scf_error());
6434 6434 }
6435 6435
6436 6436 running = NULL;
6437 6437 } else {
6438 6438 r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
6439 6439 switch (r) {
6440 6440 case 0:
6441 6441 running = imp_rsnpl;
6442 6442 break;
6443 6443
6444 6444 case ECONNABORTED:
6445 6445 goto connaborted;
6446 6446
6447 6447 case ECANCELED:
6448 6448 warn(emsg_del, inst->sc_parent->sc_fmri,
6449 6449 inst->sc_name);
6450 6450 lcbdata->sc_err = EBUSY;
6451 6451 r = UU_WALK_ERROR;
6452 6452 goto deltemp;
6453 6453
6454 6454 case ENOENT:
6455 6455 warn(emsg_badsnap, snap_running, inst->sc_fmri);
6456 6456 lcbdata->sc_err = EBADF;
6457 6457 r = UU_WALK_ERROR;
6458 6458 goto deltemp;
6459 6459
6460 6460 default:
6461 6461 bad_error("get_snaplevel", r);
6462 6462 }
6463 6463 }
6464 6464
6465 6465 r = upgrade_props(imp_inst, running, imp_snpl, inst);
6466 6466 switch (r) {
6467 6467 case 0:
6468 6468 break;
6469 6469
6470 6470 case ECANCELED:
6471 6471 case ENODEV:
6472 6472 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6473 6473 lcbdata->sc_err = EBUSY;
6474 6474 r = UU_WALK_ERROR;
6475 6475 goto deltemp;
6476 6476
6477 6477 case ECONNABORTED:
6478 6478 goto connaborted;
6479 6479
6480 6480 case ENOMEM:
6481 6481 case ENOSPC:
6482 6482 case EBADF:
6483 6483 case EBUSY:
6484 6484 case EINVAL:
6485 6485 case EPERM:
6486 6486 case EROFS:
6487 6487 case EACCES:
6488 6488 case EEXIST:
6489 6489 lcbdata->sc_err = r;
6490 6490 r = UU_WALK_ERROR;
6491 6491 goto deltemp;
6492 6492
6493 6493 default:
6494 6494 bad_error("upgrade_props", r);
6495 6495 }
6496 6496
6497 6497 inst->sc_import_state = IMPORT_PROP_DONE;
6498 6498 } else {
6499 6499 switch (scf_error()) {
6500 6500 case SCF_ERROR_CONNECTION_BROKEN:
6501 6501 goto connaborted;
6502 6502
6503 6503 case SCF_ERROR_NOT_FOUND:
6504 6504 break;
6505 6505
6506 6506 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
6507 6507 case SCF_ERROR_HANDLE_MISMATCH:
6508 6508 case SCF_ERROR_NOT_BOUND:
6509 6509 case SCF_ERROR_NOT_SET:
6510 6510 default:
6511 6511 bad_error("scf_service_get_instance", scf_error());
6512 6512 }
6513 6513
6514 6514 fresh:
6515 6515 /* create instance */
6516 6516 if (scf_service_add_instance(rsvc, inst->sc_name,
6517 6517 imp_inst) != 0) {
6518 6518 switch (scf_error()) {
6519 6519 case SCF_ERROR_CONNECTION_BROKEN:
6520 6520 goto connaborted;
6521 6521
6522 6522 case SCF_ERROR_NO_RESOURCES:
6523 6523 case SCF_ERROR_BACKEND_READONLY:
6524 6524 case SCF_ERROR_BACKEND_ACCESS:
6525 6525 r = stash_scferror(lcbdata);
6526 6526 goto deltemp;
6527 6527
6528 6528 case SCF_ERROR_EXISTS:
6529 6529 warn(gettext("%s changed unexpectedly "
6530 6530 "(instance \"%s\" added).\n"),
6531 6531 inst->sc_parent->sc_fmri, inst->sc_name);
6532 6532 lcbdata->sc_err = EBUSY;
6533 6533 r = UU_WALK_ERROR;
6534 6534 goto deltemp;
6535 6535
6536 6536 case SCF_ERROR_PERMISSION_DENIED:
6537 6537 warn(gettext("Could not create \"%s\" instance "
6538 6538 "in %s (permission denied).\n"),
6539 6539 inst->sc_name, inst->sc_parent->sc_fmri);
6540 6540 r = stash_scferror(lcbdata);
6541 6541 goto deltemp;
6542 6542
6543 6543 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
6544 6544 case SCF_ERROR_HANDLE_MISMATCH:
6545 6545 case SCF_ERROR_NOT_BOUND:
6546 6546 case SCF_ERROR_NOT_SET:
6547 6547 default:
6548 6548 bad_error("scf_service_add_instance",
6549 6549 scf_error());
6550 6550 }
6551 6551 }
6552 6552
6553 6553 nosnap:
6554 6554 /*
6555 6555 * Create a last-import snapshot to serve as an attachment
6556 6556 * point for the real one from the temporary instance. Since
6557 6557 * the contents is irrelevant, take it now, while the instance
6558 6558 * is empty, to minimize svc.configd's work.
6559 6559 */
6560 6560 if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6561 6561 imp_lisnap) != 0) {
6562 6562 switch (scf_error()) {
6563 6563 case SCF_ERROR_CONNECTION_BROKEN:
6564 6564 goto connaborted;
6565 6565
6566 6566 case SCF_ERROR_NO_RESOURCES:
6567 6567 r = stash_scferror(lcbdata);
6568 6568 goto deltemp;
6569 6569
6570 6570 case SCF_ERROR_EXISTS:
6571 6571 warn(gettext("%s changed unexpectedly "
6572 6572 "(snapshot \"%s\" added).\n"),
6573 6573 inst->sc_fmri, snap_lastimport);
6574 6574 lcbdata->sc_err = EBUSY;
6575 6575 r = UU_WALK_ERROR;
6576 6576 goto deltemp;
6577 6577
6578 6578 case SCF_ERROR_PERMISSION_DENIED:
6579 6579 warn(gettext("Could not take \"%s\" snapshot "
6580 6580 "of %s (permission denied).\n"),
6581 6581 snap_lastimport, inst->sc_fmri);
6582 6582 r = stash_scferror(lcbdata);
6583 6583 goto deltemp;
6584 6584
6585 6585 default:
6586 6586 scfwarn();
6587 6587 lcbdata->sc_err = -1;
6588 6588 r = UU_WALK_ERROR;
6589 6589 goto deltemp;
6590 6590
6591 6591 case SCF_ERROR_NOT_SET:
6592 6592 case SCF_ERROR_INTERNAL:
6593 6593 case SCF_ERROR_INVALID_ARGUMENT:
6594 6594 case SCF_ERROR_HANDLE_MISMATCH:
6595 6595 bad_error("_scf_snapshot_take_new",
6596 6596 scf_error());
6597 6597 }
6598 6598 }
6599 6599
6600 6600 if (li_only)
6601 6601 goto lionly;
6602 6602
6603 6603 inst->sc_import_state = IMPORT_PROP_BEGUN;
6604 6604
6605 6605 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6606 6606 flags);
6607 6607 switch (r) {
6608 6608 case 0:
6609 6609 break;
6610 6610
6611 6611 case ECONNABORTED:
6612 6612 goto connaborted;
6613 6613
6614 6614 case ECANCELED:
6615 6615 warn(gettext("%s changed unexpectedly "
6616 6616 "(instance \"%s\" deleted).\n"),
6617 6617 inst->sc_parent->sc_fmri, inst->sc_name);
6618 6618 lcbdata->sc_err = EBUSY;
6619 6619 r = UU_WALK_ERROR;
6620 6620 goto deltemp;
6621 6621
6622 6622 case EEXIST:
6623 6623 warn(gettext("%s changed unexpectedly "
6624 6624 "(property group added).\n"), inst->sc_fmri);
6625 6625 lcbdata->sc_err = EBUSY;
6626 6626 r = UU_WALK_ERROR;
6627 6627 goto deltemp;
6628 6628
6629 6629 default:
6630 6630 lcbdata->sc_err = r;
6631 6631 r = UU_WALK_ERROR;
6632 6632 goto deltemp;
6633 6633
6634 6634 case EINVAL: /* caught above */
6635 6635 bad_error("lscf_import_instance_pgs", r);
6636 6636 }
6637 6637
6638 6638 ctx.sc_parent = imp_inst;
6639 6639 ctx.sc_service = 0;
6640 6640 ctx.sc_trans = NULL;
6641 6641 ctx.sc_flags = 0;
6642 6642 if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6643 6643 &ctx, UU_DEFAULT) != 0) {
6644 6644 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6645 6645 bad_error("uu_list_walk", uu_error());
6646 6646
6647 6647 if (ctx.sc_err == ECONNABORTED)
6648 6648 goto connaborted;
6649 6649 lcbdata->sc_err = ctx.sc_err;
6650 6650 r = UU_WALK_ERROR;
6651 6651 goto deltemp;
6652 6652 }
6653 6653
6654 6654 inst->sc_import_state = IMPORT_PROP_DONE;
6655 6655
6656 6656 if (g_verbose)
6657 6657 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6658 6658 snap_initial, inst->sc_fmri);
6659 6659 r = take_snap(imp_inst, snap_initial, imp_snap);
6660 6660 switch (r) {
6661 6661 case 0:
6662 6662 break;
6663 6663
6664 6664 case ECONNABORTED:
6665 6665 goto connaborted;
6666 6666
6667 6667 case ENOSPC:
6668 6668 case -1:
6669 6669 lcbdata->sc_err = r;
6670 6670 r = UU_WALK_ERROR;
6671 6671 goto deltemp;
6672 6672
6673 6673 case ECANCELED:
6674 6674 warn(gettext("%s changed unexpectedly "
6675 6675 "(instance %s deleted).\n"),
6676 6676 inst->sc_parent->sc_fmri, inst->sc_name);
6677 6677 lcbdata->sc_err = r;
6678 6678 r = UU_WALK_ERROR;
6679 6679 goto deltemp;
6680 6680
6681 6681 case EPERM:
6682 6682 warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6683 6683 lcbdata->sc_err = r;
6684 6684 r = UU_WALK_ERROR;
6685 6685 goto deltemp;
6686 6686
6687 6687 default:
6688 6688 bad_error("take_snap", r);
6689 6689 }
6690 6690 }
6691 6691
6692 6692 lionly:
6693 6693 if (lcbdata->sc_flags & SCI_NOSNAP)
6694 6694 goto deltemp;
6695 6695
6696 6696 /* transfer snapshot from temporary instance */
6697 6697 if (g_verbose)
6698 6698 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6699 6699 snap_lastimport, inst->sc_fmri);
6700 6700 if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6701 6701 switch (scf_error()) {
6702 6702 case SCF_ERROR_CONNECTION_BROKEN:
6703 6703 goto connaborted;
6704 6704
6705 6705 case SCF_ERROR_NO_RESOURCES:
6706 6706 r = stash_scferror(lcbdata);
6707 6707 goto deltemp;
6708 6708
6709 6709 case SCF_ERROR_PERMISSION_DENIED:
6710 6710 warn(gettext("Could not take \"%s\" snapshot for %s "
6711 6711 "(permission denied).\n"), snap_lastimport,
6712 6712 inst->sc_fmri);
6713 6713 r = stash_scferror(lcbdata);
6714 6714 goto deltemp;
6715 6715
6716 6716 case SCF_ERROR_NOT_SET:
6717 6717 case SCF_ERROR_HANDLE_MISMATCH:
6718 6718 default:
6719 6719 bad_error("_scf_snapshot_attach", scf_error());
6720 6720 }
6721 6721 }
6722 6722
6723 6723 inst->sc_import_state = IMPORT_COMPLETE;
6724 6724
6725 6725 r = UU_WALK_NEXT;
6726 6726
6727 6727 deltemp:
6728 6728 /* delete temporary instance */
6729 6729 if (scf_instance_delete(imp_tinst) != 0) {
6730 6730 switch (scf_error()) {
6731 6731 case SCF_ERROR_DELETED:
6732 6732 break;
6733 6733
6734 6734 case SCF_ERROR_CONNECTION_BROKEN:
6735 6735 goto connaborted;
6736 6736
6737 6737 case SCF_ERROR_NOT_SET:
6738 6738 case SCF_ERROR_NOT_BOUND:
6739 6739 default:
6740 6740 bad_error("scf_instance_delete", scf_error());
6741 6741 }
6742 6742 }
6743 6743
6744 6744 return (r);
6745 6745
6746 6746 connaborted:
6747 6747 warn(gettext("Could not delete svc:/%s:%s "
6748 6748 "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6749 6749 lcbdata->sc_err = ECONNABORTED;
6750 6750 return (UU_WALK_ERROR);
6751 6751 }
6752 6752
6753 6753 /*
6754 6754 * If the service is missing, create it, import its properties, and import the
6755 6755 * instances. Since the service is brand new, it should be empty, and if we
6756 6756 * run into any existing entities (SCF_ERROR_EXISTS), abort.
6757 6757 *
6758 6758 * If the service exists, we want to upgrade its properties and import the
6759 6759 * instances. Upgrade requires a last-import snapshot, though, which are
6760 6760 * children of instances, so first we'll have to go through the instances
6761 6761 * looking for a last-import snapshot. If we don't find one then we'll just
6762 6762 * override-import the service properties (but don't delete existing
6763 6763 * properties: another service might have declared us as a dependent). Before
6764 6764 * we change anything, though, we want to take the previous snapshots. We
6765 6765 * also give lscf_instance_import() a leg up on taking last-import snapshots
6766 6766 * by importing the manifest's service properties into a temporary service.
6767 6767 *
6768 6768 * On success, returns UU_WALK_NEXT. On failure, returns UU_WALK_ERROR and
6769 6769 * sets lcbdata->sc_err to
6770 6770 * ECONNABORTED - repository connection broken
6771 6771 * ENOMEM - out of memory
6772 6772 * ENOSPC - svc.configd is out of resources
6773 6773 * EPERM - couldn't create temporary service (error printed)
6774 6774 * - couldn't import into temp service (error printed)
6775 6775 * - couldn't create service (error printed)
6776 6776 * - couldn't import dependent (error printed)
6777 6777 * - couldn't take snapshot (error printed)
6778 6778 * - couldn't create instance (error printed)
6779 6779 * - couldn't create, modify, or delete pg (error printed)
6780 6780 * - couldn't create, modify, or delete dependent (error printed)
6781 6781 * - couldn't import instance (error printed)
6782 6782 * EROFS - couldn't create temporary service (repository read-only)
6783 6783 * - couldn't import into temporary service (repository read-only)
6784 6784 * - couldn't create service (repository read-only)
6785 6785 * - couldn't import dependent (repository read-only)
6786 6786 * - couldn't create instance (repository read-only)
6787 6787 * - couldn't create, modify, or delete pg or dependent
6788 6788 * - couldn't import instance (repository read-only)
6789 6789 * EACCES - couldn't create temporary service (backend access denied)
6790 6790 * - couldn't import into temporary service (backend access denied)
6791 6791 * - couldn't create service (backend access denied)
6792 6792 * - couldn't import dependent (backend access denied)
6793 6793 * - couldn't create instance (backend access denied)
6794 6794 * - couldn't create, modify, or delete pg or dependent
6795 6795 * - couldn't import instance (backend access denied)
6796 6796 * EINVAL - service name is invalid (error printed)
6797 6797 * - service name is too long (error printed)
6798 6798 * - s has invalid pgroup (error printed)
6799 6799 * - s has invalid dependent (error printed)
6800 6800 * - instance name is invalid (error printed)
6801 6801 * - instance entity_t is invalid (error printed)
6802 6802 * EEXIST - couldn't create temporary service (already exists) (error printed)
6803 6803 * - couldn't import dependent (dependency pg already exists) (printed)
6804 6804 * - dependency collision in dependent service (error printed)
6805 6805 * EBUSY - temporary service deleted (error printed)
6806 6806 * - property group added to temporary service (error printed)
6807 6807 * - new property group changed or was deleted (error printed)
6808 6808 * - service was added unexpectedly (error printed)
6809 6809 * - service was deleted unexpectedly (error printed)
6810 6810 * - property group added to new service (error printed)
6811 6811 * - instance added unexpectedly (error printed)
6812 6812 * - instance deleted unexpectedly (error printed)
6813 6813 * - dependent service deleted unexpectedly (error printed)
6814 6814 * - pg was added, changed, or deleted (error printed)
6815 6815 * - dependent pg changed (error printed)
6816 6816 * - temporary instance added, changed, or deleted (error printed)
6817 6817 * EBADF - a last-import snapshot is corrupt (error printed)
6818 6818 * - the service is corrupt (error printed)
6819 6819 * - a dependent is corrupt (error printed)
6820 6820 * - an instance is corrupt (error printed)
6821 6821 * - an instance has a corrupt last-import snapshot (error printed)
6822 6822 * - dependent target has a corrupt snapshot (error printed)
6823 6823 * -1 - unknown libscf error (error printed)
6824 6824 */
6825 6825 static int
6826 6826 lscf_service_import(void *v, void *pvt)
6827 6827 {
6828 6828 entity_t *s = v;
6829 6829 scf_callback_t cbdata;
6830 6830 scf_callback_t *lcbdata = pvt;
6831 6831 scf_scope_t *scope = lcbdata->sc_parent;
6832 6832 entity_t *inst, linst;
6833 6833 int r;
6834 6834 int fresh = 0;
6835 6835 scf_snaplevel_t *running;
6836 6836 int have_ge = 0;
6837 6837
6838 6838 const char * const ts_deleted = gettext("Temporary service svc:/%s "
6839 6839 "was deleted unexpectedly.\n");
6840 6840 const char * const ts_pg_added = gettext("Temporary service svc:/%s "
6841 6841 "changed unexpectedly (property group added).\n");
6842 6842 const char * const s_deleted =
6843 6843 gettext("%s was deleted unexpectedly.\n");
6844 6844 const char * const i_deleted =
6845 6845 gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
6846 6846 const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
6847 6847 "is corrupt (missing service snaplevel).\n");
6848 6848 const char * const s_mfile_upd =
6849 6849 gettext("Unable to update the manifest file connection "
6850 6850 "for %s\n");
6851 6851
6852 6852 li_only = 0;
6853 6853 /* Validate the service name */
6854 6854 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
6855 6855 switch (scf_error()) {
6856 6856 case SCF_ERROR_CONNECTION_BROKEN:
6857 6857 return (stash_scferror(lcbdata));
6858 6858
6859 6859 case SCF_ERROR_INVALID_ARGUMENT:
6860 6860 warn(gettext("\"%s\" is an invalid service name. "
6861 6861 "Cannot import.\n"), s->sc_name);
6862 6862 return (stash_scferror(lcbdata));
6863 6863
6864 6864 case SCF_ERROR_NOT_FOUND:
6865 6865 break;
6866 6866
6867 6867 case SCF_ERROR_HANDLE_MISMATCH:
6868 6868 case SCF_ERROR_NOT_BOUND:
6869 6869 case SCF_ERROR_NOT_SET:
6870 6870 default:
6871 6871 bad_error("scf_scope_get_service", scf_error());
6872 6872 }
6873 6873 }
6874 6874
6875 6875 /* create temporary service */
6876 6876 /*
6877 6877 * the size of the buffer was reduced to max_scf_name_len to prevent
6878 6878 * hitting bug 6681151. After the bug fix, the size of the buffer
6879 6879 * should be restored to its original value (max_scf_name_len +1)
6880 6880 */
6881 6881 r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
6882 6882 if (r < 0)
6883 6883 bad_error("snprintf", errno);
6884 6884 if (r > max_scf_name_len) {
6885 6885 warn(gettext(
6886 6886 "Service name \"%s\" is too long. Cannot import.\n"),
6887 6887 s->sc_name);
6888 6888 lcbdata->sc_err = EINVAL;
6889 6889 return (UU_WALK_ERROR);
6890 6890 }
6891 6891
6892 6892 if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
6893 6893 switch (scf_error()) {
6894 6894 case SCF_ERROR_CONNECTION_BROKEN:
6895 6895 case SCF_ERROR_NO_RESOURCES:
6896 6896 case SCF_ERROR_BACKEND_READONLY:
6897 6897 case SCF_ERROR_BACKEND_ACCESS:
6898 6898 return (stash_scferror(lcbdata));
6899 6899
6900 6900 case SCF_ERROR_EXISTS:
6901 6901 warn(gettext(
6902 6902 "Temporary service \"%s\" must be deleted before "
6903 6903 "this manifest can be imported.\n"), imp_tsname);
6904 6904 return (stash_scferror(lcbdata));
6905 6905
6906 6906 case SCF_ERROR_PERMISSION_DENIED:
6907 6907 warn(gettext("Could not create temporary service "
6908 6908 "\"%s\" (permission denied).\n"), imp_tsname);
6909 6909 return (stash_scferror(lcbdata));
6910 6910
6911 6911 case SCF_ERROR_INVALID_ARGUMENT:
6912 6912 case SCF_ERROR_HANDLE_MISMATCH:
6913 6913 case SCF_ERROR_NOT_BOUND:
6914 6914 case SCF_ERROR_NOT_SET:
6915 6915 default:
6916 6916 bad_error("scf_scope_add_service", scf_error());
6917 6917 }
6918 6918 }
6919 6919
6920 6920 r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
6921 6921 if (r < 0)
6922 6922 bad_error("snprintf", errno);
6923 6923
6924 6924 cbdata.sc_handle = lcbdata->sc_handle;
6925 6925 cbdata.sc_parent = imp_tsvc;
6926 6926 cbdata.sc_service = 1;
6927 6927 cbdata.sc_source_fmri = s->sc_fmri;
6928 6928 cbdata.sc_target_fmri = imp_str;
6929 6929 cbdata.sc_flags = 0;
6930 6930
6931 6931 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
6932 6932 UU_DEFAULT) != 0) {
6933 6933 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6934 6934 bad_error("uu_list_walk", uu_error());
6935 6935
6936 6936 lcbdata->sc_err = cbdata.sc_err;
6937 6937 switch (cbdata.sc_err) {
6938 6938 case ECONNABORTED:
6939 6939 goto connaborted;
6940 6940
6941 6941 case ECANCELED:
6942 6942 warn(ts_deleted, imp_tsname);
6943 6943 lcbdata->sc_err = EBUSY;
6944 6944 return (UU_WALK_ERROR);
6945 6945
6946 6946 case EEXIST:
6947 6947 warn(ts_pg_added, imp_tsname);
6948 6948 lcbdata->sc_err = EBUSY;
6949 6949 return (UU_WALK_ERROR);
6950 6950 }
6951 6951
6952 6952 r = UU_WALK_ERROR;
6953 6953 goto deltemp;
6954 6954 }
6955 6955
6956 6956 if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
6957 6957 UU_DEFAULT) != 0) {
6958 6958 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6959 6959 bad_error("uu_list_walk", uu_error());
6960 6960
6961 6961 lcbdata->sc_err = cbdata.sc_err;
6962 6962 switch (cbdata.sc_err) {
6963 6963 case ECONNABORTED:
6964 6964 goto connaborted;
6965 6965
6966 6966 case ECANCELED:
6967 6967 warn(ts_deleted, imp_tsname);
6968 6968 lcbdata->sc_err = EBUSY;
6969 6969 return (UU_WALK_ERROR);
6970 6970
6971 6971 case EEXIST:
6972 6972 warn(ts_pg_added, imp_tsname);
6973 6973 lcbdata->sc_err = EBUSY;
6974 6974 return (UU_WALK_ERROR);
6975 6975 }
6976 6976
6977 6977 r = UU_WALK_ERROR;
6978 6978 goto deltemp;
6979 6979 }
6980 6980
6981 6981 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
6982 6982 switch (scf_error()) {
6983 6983 case SCF_ERROR_NOT_FOUND:
6984 6984 break;
6985 6985
6986 6986 case SCF_ERROR_CONNECTION_BROKEN:
6987 6987 goto connaborted;
6988 6988
6989 6989 case SCF_ERROR_INVALID_ARGUMENT:
6990 6990 case SCF_ERROR_HANDLE_MISMATCH:
6991 6991 case SCF_ERROR_NOT_BOUND:
6992 6992 case SCF_ERROR_NOT_SET:
6993 6993 default:
6994 6994 bad_error("scf_scope_get_service", scf_error());
6995 6995 }
6996 6996
6997 6997 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
6998 6998 switch (scf_error()) {
6999 6999 case SCF_ERROR_CONNECTION_BROKEN:
7000 7000 goto connaborted;
7001 7001
7002 7002 case SCF_ERROR_NO_RESOURCES:
7003 7003 case SCF_ERROR_BACKEND_READONLY:
7004 7004 case SCF_ERROR_BACKEND_ACCESS:
7005 7005 r = stash_scferror(lcbdata);
7006 7006 goto deltemp;
7007 7007
7008 7008 case SCF_ERROR_EXISTS:
7009 7009 warn(gettext("Scope \"%s\" changed unexpectedly"
7010 7010 " (service \"%s\" added).\n"),
7011 7011 SCF_SCOPE_LOCAL, s->sc_name);
7012 7012 lcbdata->sc_err = EBUSY;
7013 7013 goto deltemp;
7014 7014
7015 7015 case SCF_ERROR_PERMISSION_DENIED:
7016 7016 warn(gettext("Could not create service \"%s\" "
7017 7017 "(permission denied).\n"), s->sc_name);
7018 7018 goto deltemp;
7019 7019
7020 7020 case SCF_ERROR_INVALID_ARGUMENT:
7021 7021 case SCF_ERROR_HANDLE_MISMATCH:
7022 7022 case SCF_ERROR_NOT_BOUND:
7023 7023 case SCF_ERROR_NOT_SET:
7024 7024 default:
7025 7025 bad_error("scf_scope_add_service", scf_error());
7026 7026 }
7027 7027 }
7028 7028
7029 7029 s->sc_import_state = IMPORT_PROP_BEGUN;
7030 7030
7031 7031 /* import service properties */
7032 7032 cbdata.sc_handle = lcbdata->sc_handle;
7033 7033 cbdata.sc_parent = imp_svc;
7034 7034 cbdata.sc_service = 1;
7035 7035 cbdata.sc_flags = lcbdata->sc_flags;
7036 7036 cbdata.sc_source_fmri = s->sc_fmri;
7037 7037 cbdata.sc_target_fmri = s->sc_fmri;
7038 7038
7039 7039 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7040 7040 &cbdata, UU_DEFAULT) != 0) {
7041 7041 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7042 7042 bad_error("uu_list_walk", uu_error());
7043 7043
7044 7044 lcbdata->sc_err = cbdata.sc_err;
7045 7045 switch (cbdata.sc_err) {
7046 7046 case ECONNABORTED:
7047 7047 goto connaborted;
7048 7048
7049 7049 case ECANCELED:
7050 7050 warn(s_deleted, s->sc_fmri);
7051 7051 lcbdata->sc_err = EBUSY;
7052 7052 return (UU_WALK_ERROR);
7053 7053
7054 7054 case EEXIST:
7055 7055 warn(gettext("%s changed unexpectedly "
7056 7056 "(property group added).\n"), s->sc_fmri);
7057 7057 lcbdata->sc_err = EBUSY;
7058 7058 return (UU_WALK_ERROR);
7059 7059
7060 7060 case EINVAL:
7061 7061 /* caught above */
7062 7062 bad_error("entity_pgroup_import",
7063 7063 cbdata.sc_err);
7064 7064 }
7065 7065
7066 7066 r = UU_WALK_ERROR;
7067 7067 goto deltemp;
7068 7068 }
7069 7069
7070 7070 cbdata.sc_trans = NULL;
7071 7071 cbdata.sc_flags = 0;
7072 7072 if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
7073 7073 &cbdata, UU_DEFAULT) != 0) {
7074 7074 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7075 7075 bad_error("uu_list_walk", uu_error());
7076 7076
7077 7077 lcbdata->sc_err = cbdata.sc_err;
7078 7078 if (cbdata.sc_err == ECONNABORTED)
7079 7079 goto connaborted;
7080 7080 r = UU_WALK_ERROR;
7081 7081 goto deltemp;
7082 7082 }
7083 7083
7084 7084 s->sc_import_state = IMPORT_PROP_DONE;
7085 7085
7086 7086 /*
7087 7087 * This is a new service, so we can't take previous snapshots
7088 7088 * or upgrade service properties.
7089 7089 */
7090 7090 fresh = 1;
7091 7091 goto instances;
7092 7092 }
7093 7093
7094 7094 /* Clear sc_seen for the instances. */
7095 7095 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
7096 7096 (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
7097 7097 bad_error("uu_list_walk", uu_error());
7098 7098
7099 7099 /*
7100 7100 * Take previous snapshots for all instances. Even for ones not
7101 7101 * mentioned in the bundle, since we might change their service
7102 7102 * properties.
7103 7103 */
7104 7104 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7105 7105 switch (scf_error()) {
7106 7106 case SCF_ERROR_CONNECTION_BROKEN:
7107 7107 goto connaborted;
7108 7108
7109 7109 case SCF_ERROR_DELETED:
7110 7110 warn(s_deleted, s->sc_fmri);
7111 7111 lcbdata->sc_err = EBUSY;
7112 7112 r = UU_WALK_ERROR;
7113 7113 goto deltemp;
7114 7114
7115 7115 case SCF_ERROR_HANDLE_MISMATCH:
7116 7116 case SCF_ERROR_NOT_BOUND:
7117 7117 case SCF_ERROR_NOT_SET:
7118 7118 default:
7119 7119 bad_error("scf_iter_service_instances", scf_error());
7120 7120 }
7121 7121 }
7122 7122
7123 7123 for (;;) {
7124 7124 r = scf_iter_next_instance(imp_iter, imp_inst);
7125 7125 if (r == 0)
7126 7126 break;
7127 7127 if (r != 1) {
7128 7128 switch (scf_error()) {
7129 7129 case SCF_ERROR_DELETED:
7130 7130 warn(s_deleted, s->sc_fmri);
7131 7131 lcbdata->sc_err = EBUSY;
7132 7132 r = UU_WALK_ERROR;
7133 7133 goto deltemp;
7134 7134
7135 7135 case SCF_ERROR_CONNECTION_BROKEN:
7136 7136 goto connaborted;
7137 7137
7138 7138 case SCF_ERROR_NOT_BOUND:
7139 7139 case SCF_ERROR_HANDLE_MISMATCH:
7140 7140 case SCF_ERROR_INVALID_ARGUMENT:
7141 7141 case SCF_ERROR_NOT_SET:
7142 7142 default:
7143 7143 bad_error("scf_iter_next_instance",
7144 7144 scf_error());
7145 7145 }
7146 7146 }
7147 7147
7148 7148 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
7149 7149 switch (scf_error()) {
7150 7150 case SCF_ERROR_DELETED:
7151 7151 continue;
7152 7152
7153 7153 case SCF_ERROR_CONNECTION_BROKEN:
7154 7154 goto connaborted;
7155 7155
7156 7156 case SCF_ERROR_NOT_SET:
7157 7157 case SCF_ERROR_NOT_BOUND:
7158 7158 default:
7159 7159 bad_error("scf_instance_get_name", scf_error());
7160 7160 }
7161 7161 }
7162 7162
7163 7163 if (g_verbose)
7164 7164 warn(gettext(
7165 7165 "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
7166 7166 snap_previous, s->sc_name, imp_str);
7167 7167
7168 7168 r = take_snap(imp_inst, snap_previous, imp_snap);
7169 7169 switch (r) {
7170 7170 case 0:
7171 7171 break;
7172 7172
7173 7173 case ECANCELED:
7174 7174 continue;
7175 7175
7176 7176 case ECONNABORTED:
7177 7177 goto connaborted;
7178 7178
7179 7179 case EPERM:
7180 7180 warn(gettext("Could not take \"%s\" snapshot of "
7181 7181 "svc:/%s:%s (permission denied).\n"),
7182 7182 snap_previous, s->sc_name, imp_str);
7183 7183 lcbdata->sc_err = r;
7184 7184 return (UU_WALK_ERROR);
7185 7185
7186 7186 case ENOSPC:
7187 7187 case -1:
7188 7188 lcbdata->sc_err = r;
7189 7189 r = UU_WALK_ERROR;
7190 7190 goto deltemp;
7191 7191
7192 7192 default:
7193 7193 bad_error("take_snap", r);
7194 7194 }
7195 7195
7196 7196 linst.sc_name = imp_str;
7197 7197 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
7198 7198 &linst, NULL, NULL);
7199 7199 if (inst != NULL) {
7200 7200 inst->sc_import_state = IMPORT_PREVIOUS;
7201 7201 inst->sc_seen = 1;
7202 7202 }
7203 7203 }
7204 7204
7205 7205 /*
7206 7206 * Create the new instances and take previous snapshots of
7207 7207 * them. This is not necessary, but it maximizes data preservation.
7208 7208 */
7209 7209 for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
7210 7210 inst != NULL;
7211 7211 inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
7212 7212 inst)) {
7213 7213 if (inst->sc_seen)
7214 7214 continue;
7215 7215
7216 7216 if (scf_service_add_instance(imp_svc, inst->sc_name,
7217 7217 imp_inst) != 0) {
7218 7218 switch (scf_error()) {
7219 7219 case SCF_ERROR_CONNECTION_BROKEN:
7220 7220 goto connaborted;
7221 7221
7222 7222 case SCF_ERROR_BACKEND_READONLY:
7223 7223 case SCF_ERROR_BACKEND_ACCESS:
7224 7224 case SCF_ERROR_NO_RESOURCES:
7225 7225 r = stash_scferror(lcbdata);
7226 7226 goto deltemp;
7227 7227
7228 7228 case SCF_ERROR_EXISTS:
7229 7229 warn(gettext("%s changed unexpectedly "
7230 7230 "(instance \"%s\" added).\n"), s->sc_fmri,
7231 7231 inst->sc_name);
7232 7232 lcbdata->sc_err = EBUSY;
7233 7233 r = UU_WALK_ERROR;
7234 7234 goto deltemp;
7235 7235
7236 7236 case SCF_ERROR_INVALID_ARGUMENT:
7237 7237 warn(gettext("Service \"%s\" has instance with "
7238 7238 "invalid name \"%s\".\n"), s->sc_name,
7239 7239 inst->sc_name);
7240 7240 r = stash_scferror(lcbdata);
7241 7241 goto deltemp;
7242 7242
7243 7243 case SCF_ERROR_PERMISSION_DENIED:
7244 7244 warn(gettext("Could not create instance \"%s\" "
7245 7245 "in %s (permission denied).\n"),
7246 7246 inst->sc_name, s->sc_fmri);
7247 7247 r = stash_scferror(lcbdata);
7248 7248 goto deltemp;
7249 7249
7250 7250 case SCF_ERROR_HANDLE_MISMATCH:
7251 7251 case SCF_ERROR_NOT_BOUND:
7252 7252 case SCF_ERROR_NOT_SET:
7253 7253 default:
7254 7254 bad_error("scf_service_add_instance",
7255 7255 scf_error());
7256 7256 }
7257 7257 }
7258 7258
7259 7259 if (g_verbose)
7260 7260 warn(gettext("Taking \"%s\" snapshot for "
7261 7261 "new service %s.\n"), snap_previous, inst->sc_fmri);
7262 7262 r = take_snap(imp_inst, snap_previous, imp_snap);
7263 7263 switch (r) {
7264 7264 case 0:
7265 7265 break;
7266 7266
7267 7267 case ECANCELED:
7268 7268 warn(i_deleted, s->sc_fmri, inst->sc_name);
7269 7269 lcbdata->sc_err = EBUSY;
7270 7270 r = UU_WALK_ERROR;
7271 7271 goto deltemp;
7272 7272
7273 7273 case ECONNABORTED:
7274 7274 goto connaborted;
7275 7275
7276 7276 case EPERM:
7277 7277 warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
7278 7278 lcbdata->sc_err = r;
7279 7279 r = UU_WALK_ERROR;
7280 7280 goto deltemp;
7281 7281
7282 7282 case ENOSPC:
7283 7283 case -1:
7284 7284 r = UU_WALK_ERROR;
7285 7285 goto deltemp;
7286 7286
7287 7287 default:
7288 7288 bad_error("take_snap", r);
7289 7289 }
7290 7290 }
7291 7291
7292 7292 s->sc_import_state = IMPORT_PREVIOUS;
7293 7293
7294 7294 /*
7295 7295 * Upgrade service properties, if we can find a last-import snapshot.
7296 7296 * Any will do because we don't support different service properties
7297 7297 * in different manifests, so all snaplevels of the service in all of
7298 7298 * the last-import snapshots of the instances should be the same.
7299 7299 */
7300 7300 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7301 7301 switch (scf_error()) {
7302 7302 case SCF_ERROR_CONNECTION_BROKEN:
7303 7303 goto connaborted;
7304 7304
7305 7305 case SCF_ERROR_DELETED:
7306 7306 warn(s_deleted, s->sc_fmri);
7307 7307 lcbdata->sc_err = EBUSY;
7308 7308 r = UU_WALK_ERROR;
7309 7309 goto deltemp;
7310 7310
7311 7311 case SCF_ERROR_HANDLE_MISMATCH:
7312 7312 case SCF_ERROR_NOT_BOUND:
7313 7313 case SCF_ERROR_NOT_SET:
7314 7314 default:
7315 7315 bad_error("scf_iter_service_instances", scf_error());
7316 7316 }
7317 7317 }
7318 7318
7319 7319 for (;;) {
7320 7320 r = scf_iter_next_instance(imp_iter, imp_inst);
7321 7321 if (r == -1) {
7322 7322 switch (scf_error()) {
7323 7323 case SCF_ERROR_DELETED:
7324 7324 warn(s_deleted, s->sc_fmri);
7325 7325 lcbdata->sc_err = EBUSY;
7326 7326 r = UU_WALK_ERROR;
7327 7327 goto deltemp;
7328 7328
7329 7329 case SCF_ERROR_CONNECTION_BROKEN:
7330 7330 goto connaborted;
7331 7331
7332 7332 case SCF_ERROR_NOT_BOUND:
7333 7333 case SCF_ERROR_HANDLE_MISMATCH:
7334 7334 case SCF_ERROR_INVALID_ARGUMENT:
7335 7335 case SCF_ERROR_NOT_SET:
7336 7336 default:
7337 7337 bad_error("scf_iter_next_instance",
7338 7338 scf_error());
7339 7339 }
7340 7340 }
7341 7341
7342 7342 if (r == 0) {
7343 7343 /*
7344 7344 * Didn't find any last-import snapshots. Override-
7345 7345 * import the properties. Unless one of the instances
7346 7346 * has a general/enabled property, in which case we're
7347 7347 * probably running a last-import-capable svccfg for
7348 7348 * the first time, and we should only take the
7349 7349 * last-import snapshot.
7350 7350 */
7351 7351 if (have_ge) {
7352 7352 pgroup_t *mfpg;
7353 7353 scf_callback_t mfcbdata;
7354 7354
7355 7355 li_only = 1;
7356 7356 no_refresh = 1;
7357 7357 /*
7358 7358 * Need to go ahead and import the manifestfiles
7359 7359 * pg if it exists. If the last-import snapshot
7360 7360 * upgrade code is ever removed this code can
7361 7361 * be removed as well.
7362 7362 */
7363 7363 mfpg = internal_pgroup_find(s,
7364 7364 SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
7365 7365
7366 7366 if (mfpg) {
7367 7367 mfcbdata.sc_handle = g_hndl;
7368 7368 mfcbdata.sc_parent = imp_svc;
7369 7369 mfcbdata.sc_service = 1;
7370 7370 mfcbdata.sc_flags = SCI_FORCE;
7371 7371 mfcbdata.sc_source_fmri = s->sc_fmri;
7372 7372 mfcbdata.sc_target_fmri = s->sc_fmri;
7373 7373 if (entity_pgroup_import(mfpg,
7374 7374 &mfcbdata) != UU_WALK_NEXT) {
7375 7375 warn(s_mfile_upd, s->sc_fmri);
7376 7376 r = UU_WALK_ERROR;
7377 7377 goto deltemp;
7378 7378 }
7379 7379 }
7380 7380 break;
7381 7381 }
7382 7382
7383 7383 s->sc_import_state = IMPORT_PROP_BEGUN;
7384 7384
7385 7385 cbdata.sc_handle = g_hndl;
7386 7386 cbdata.sc_parent = imp_svc;
7387 7387 cbdata.sc_service = 1;
7388 7388 cbdata.sc_flags = SCI_FORCE;
7389 7389 cbdata.sc_source_fmri = s->sc_fmri;
7390 7390 cbdata.sc_target_fmri = s->sc_fmri;
7391 7391 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7392 7392 &cbdata, UU_DEFAULT) != 0) {
7393 7393 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7394 7394 bad_error("uu_list_walk", uu_error());
7395 7395 lcbdata->sc_err = cbdata.sc_err;
7396 7396 switch (cbdata.sc_err) {
7397 7397 case ECONNABORTED:
7398 7398 goto connaborted;
7399 7399
7400 7400 case ECANCELED:
7401 7401 warn(s_deleted, s->sc_fmri);
7402 7402 lcbdata->sc_err = EBUSY;
7403 7403 break;
7404 7404
7405 7405 case EINVAL: /* caught above */
7406 7406 case EEXIST:
7407 7407 bad_error("entity_pgroup_import",
7408 7408 cbdata.sc_err);
7409 7409 }
7410 7410
7411 7411 r = UU_WALK_ERROR;
7412 7412 goto deltemp;
7413 7413 }
7414 7414
7415 7415 cbdata.sc_trans = NULL;
7416 7416 cbdata.sc_flags = 0;
7417 7417 if (uu_list_walk(s->sc_dependents,
7418 7418 lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
7419 7419 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7420 7420 bad_error("uu_list_walk", uu_error());
7421 7421 lcbdata->sc_err = cbdata.sc_err;
7422 7422 if (cbdata.sc_err == ECONNABORTED)
7423 7423 goto connaborted;
7424 7424 r = UU_WALK_ERROR;
7425 7425 goto deltemp;
7426 7426 }
7427 7427 break;
7428 7428 }
7429 7429
7430 7430 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
7431 7431 imp_snap) != 0) {
7432 7432 switch (scf_error()) {
7433 7433 case SCF_ERROR_DELETED:
7434 7434 continue;
7435 7435
7436 7436 case SCF_ERROR_NOT_FOUND:
7437 7437 break;
7438 7438
7439 7439 case SCF_ERROR_CONNECTION_BROKEN:
7440 7440 goto connaborted;
7441 7441
7442 7442 case SCF_ERROR_HANDLE_MISMATCH:
7443 7443 case SCF_ERROR_NOT_BOUND:
7444 7444 case SCF_ERROR_INVALID_ARGUMENT:
7445 7445 case SCF_ERROR_NOT_SET:
7446 7446 default:
7447 7447 bad_error("scf_instance_get_snapshot",
7448 7448 scf_error());
7449 7449 }
7450 7450
7451 7451 if (have_ge)
7452 7452 continue;
7453 7453
7454 7454 /*
7455 7455 * Check for a general/enabled property. This is how
7456 7456 * we tell whether to import if there turn out to be
7457 7457 * no last-import snapshots.
7458 7458 */
7459 7459 if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
7460 7460 imp_pg) == 0) {
7461 7461 if (scf_pg_get_property(imp_pg,
7462 7462 SCF_PROPERTY_ENABLED, imp_prop) == 0) {
7463 7463 have_ge = 1;
7464 7464 } else {
7465 7465 switch (scf_error()) {
7466 7466 case SCF_ERROR_DELETED:
7467 7467 case SCF_ERROR_NOT_FOUND:
7468 7468 continue;
7469 7469
7470 7470 case SCF_ERROR_INVALID_ARGUMENT:
7471 7471 case SCF_ERROR_HANDLE_MISMATCH:
7472 7472 case SCF_ERROR_CONNECTION_BROKEN:
7473 7473 case SCF_ERROR_NOT_BOUND:
7474 7474 case SCF_ERROR_NOT_SET:
7475 7475 default:
7476 7476 bad_error("scf_pg_get_property",
7477 7477 scf_error());
7478 7478 }
7479 7479 }
7480 7480 } else {
7481 7481 switch (scf_error()) {
7482 7482 case SCF_ERROR_DELETED:
7483 7483 case SCF_ERROR_NOT_FOUND:
7484 7484 continue;
7485 7485
7486 7486 case SCF_ERROR_CONNECTION_BROKEN:
7487 7487 goto connaborted;
7488 7488
7489 7489 case SCF_ERROR_NOT_BOUND:
7490 7490 case SCF_ERROR_NOT_SET:
7491 7491 case SCF_ERROR_INVALID_ARGUMENT:
7492 7492 case SCF_ERROR_HANDLE_MISMATCH:
7493 7493 default:
7494 7494 bad_error("scf_instance_get_pg",
7495 7495 scf_error());
7496 7496 }
7497 7497 }
7498 7498 continue;
7499 7499 }
7500 7500
7501 7501 /* find service snaplevel */
7502 7502 r = get_snaplevel(imp_snap, 1, imp_snpl);
7503 7503 switch (r) {
7504 7504 case 0:
7505 7505 break;
7506 7506
7507 7507 case ECONNABORTED:
7508 7508 goto connaborted;
7509 7509
7510 7510 case ECANCELED:
7511 7511 continue;
7512 7512
7513 7513 case ENOENT:
7514 7514 if (scf_instance_get_name(imp_inst, imp_str,
7515 7515 imp_str_sz) < 0)
7516 7516 (void) strcpy(imp_str, "?");
7517 7517 warn(badsnap, snap_lastimport, s->sc_name, imp_str);
7518 7518 lcbdata->sc_err = EBADF;
7519 7519 r = UU_WALK_ERROR;
7520 7520 goto deltemp;
7521 7521
7522 7522 default:
7523 7523 bad_error("get_snaplevel", r);
7524 7524 }
7525 7525
7526 7526 if (scf_instance_get_snapshot(imp_inst, snap_running,
7527 7527 imp_rsnap) != 0) {
7528 7528 switch (scf_error()) {
7529 7529 case SCF_ERROR_DELETED:
7530 7530 continue;
7531 7531
7532 7532 case SCF_ERROR_NOT_FOUND:
7533 7533 break;
7534 7534
7535 7535 case SCF_ERROR_CONNECTION_BROKEN:
7536 7536 goto connaborted;
7537 7537
7538 7538 case SCF_ERROR_INVALID_ARGUMENT:
7539 7539 case SCF_ERROR_HANDLE_MISMATCH:
7540 7540 case SCF_ERROR_NOT_BOUND:
7541 7541 case SCF_ERROR_NOT_SET:
7542 7542 default:
7543 7543 bad_error("scf_instance_get_snapshot",
7544 7544 scf_error());
7545 7545 }
7546 7546 running = NULL;
7547 7547 } else {
7548 7548 r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
7549 7549 switch (r) {
7550 7550 case 0:
7551 7551 running = imp_rsnpl;
7552 7552 break;
7553 7553
7554 7554 case ECONNABORTED:
7555 7555 goto connaborted;
7556 7556
7557 7557 case ECANCELED:
7558 7558 continue;
7559 7559
7560 7560 case ENOENT:
7561 7561 if (scf_instance_get_name(imp_inst, imp_str,
7562 7562 imp_str_sz) < 0)
7563 7563 (void) strcpy(imp_str, "?");
7564 7564 warn(badsnap, snap_running, s->sc_name,
7565 7565 imp_str);
7566 7566 lcbdata->sc_err = EBADF;
7567 7567 r = UU_WALK_ERROR;
7568 7568 goto deltemp;
7569 7569
7570 7570 default:
7571 7571 bad_error("get_snaplevel", r);
7572 7572 }
7573 7573 }
7574 7574
7575 7575 if (g_verbose) {
7576 7576 if (scf_instance_get_name(imp_inst, imp_str,
7577 7577 imp_str_sz) < 0)
7578 7578 (void) strcpy(imp_str, "?");
7579 7579 warn(gettext("Upgrading properties of %s according to "
7580 7580 "instance \"%s\".\n"), s->sc_fmri, imp_str);
7581 7581 }
7582 7582
7583 7583 /* upgrade service properties */
7584 7584 r = upgrade_props(imp_svc, running, imp_snpl, s);
7585 7585 if (r == 0)
7586 7586 break;
7587 7587
7588 7588 switch (r) {
7589 7589 case ECONNABORTED:
7590 7590 goto connaborted;
7591 7591
7592 7592 case ECANCELED:
7593 7593 warn(s_deleted, s->sc_fmri);
7594 7594 lcbdata->sc_err = EBUSY;
7595 7595 break;
7596 7596
7597 7597 case ENODEV:
7598 7598 if (scf_instance_get_name(imp_inst, imp_str,
7599 7599 imp_str_sz) < 0)
7600 7600 (void) strcpy(imp_str, "?");
7601 7601 warn(i_deleted, s->sc_fmri, imp_str);
7602 7602 lcbdata->sc_err = EBUSY;
7603 7603 break;
7604 7604
7605 7605 default:
7606 7606 lcbdata->sc_err = r;
7607 7607 }
7608 7608
7609 7609 r = UU_WALK_ERROR;
7610 7610 goto deltemp;
7611 7611 }
7612 7612
7613 7613 s->sc_import_state = IMPORT_PROP_DONE;
7614 7614
7615 7615 instances:
7616 7616 /* import instances */
7617 7617 cbdata.sc_handle = lcbdata->sc_handle;
7618 7618 cbdata.sc_parent = imp_svc;
7619 7619 cbdata.sc_service = 1;
7620 7620 cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7621 7621 cbdata.sc_general = NULL;
7622 7622
7623 7623 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7624 7624 lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7625 7625 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7626 7626 bad_error("uu_list_walk", uu_error());
7627 7627
7628 7628 lcbdata->sc_err = cbdata.sc_err;
7629 7629 if (cbdata.sc_err == ECONNABORTED)
7630 7630 goto connaborted;
7631 7631 r = UU_WALK_ERROR;
7632 7632 goto deltemp;
7633 7633 }
7634 7634
7635 7635 s->sc_import_state = IMPORT_COMPLETE;
7636 7636 r = UU_WALK_NEXT;
7637 7637
7638 7638 deltemp:
7639 7639 /* delete temporary service */
7640 7640 if (scf_service_delete(imp_tsvc) != 0) {
7641 7641 switch (scf_error()) {
7642 7642 case SCF_ERROR_DELETED:
7643 7643 break;
7644 7644
7645 7645 case SCF_ERROR_CONNECTION_BROKEN:
7646 7646 goto connaborted;
7647 7647
7648 7648 case SCF_ERROR_EXISTS:
7649 7649 warn(gettext(
7650 7650 "Could not delete svc:/%s (instances exist).\n"),
7651 7651 imp_tsname);
7652 7652 break;
7653 7653
7654 7654 case SCF_ERROR_NOT_SET:
7655 7655 case SCF_ERROR_NOT_BOUND:
7656 7656 default:
7657 7657 bad_error("scf_service_delete", scf_error());
7658 7658 }
7659 7659 }
7660 7660
7661 7661 return (r);
7662 7662
7663 7663 connaborted:
7664 7664 warn(gettext("Could not delete svc:/%s "
7665 7665 "(repository connection broken).\n"), imp_tsname);
7666 7666 lcbdata->sc_err = ECONNABORTED;
7667 7667 return (UU_WALK_ERROR);
7668 7668 }
7669 7669
7670 7670 static const char *
7671 7671 import_progress(int st)
7672 7672 {
7673 7673 switch (st) {
7674 7674 case 0:
7675 7675 return (gettext("not reached."));
7676 7676
7677 7677 case IMPORT_PREVIOUS:
7678 7678 return (gettext("previous snapshot taken."));
7679 7679
7680 7680 case IMPORT_PROP_BEGUN:
7681 7681 return (gettext("some properties imported."));
7682 7682
7683 7683 case IMPORT_PROP_DONE:
7684 7684 return (gettext("properties imported."));
7685 7685
7686 7686 case IMPORT_COMPLETE:
7687 7687 return (gettext("imported."));
7688 7688
7689 7689 case IMPORT_REFRESHED:
7690 7690 return (gettext("refresh requested."));
7691 7691
7692 7692 default:
7693 7693 #ifndef NDEBUG
7694 7694 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7695 7695 __FILE__, __LINE__, st);
7696 7696 #endif
7697 7697 abort();
7698 7698 /* NOTREACHED */
7699 7699 }
7700 7700 }
7701 7701
7702 7702 /*
7703 7703 * Returns
7704 7704 * 0 - success
7705 7705 * - fmri wasn't found (error printed)
7706 7706 * - entity was deleted (error printed)
7707 7707 * - backend denied access (error printed)
7708 7708 * ENOMEM - out of memory (error printed)
7709 7709 * ECONNABORTED - repository connection broken (error printed)
7710 7710 * EPERM - permission denied (error printed)
7711 7711 * -1 - unknown libscf error (error printed)
7712 7712 */
7713 7713 static int
7714 7714 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7715 7715 {
7716 7716 scf_error_t serr;
7717 7717 void *ent;
7718 7718 int issvc;
7719 7719 int r;
7720 7720
7721 7721 const char *deleted = gettext("Could not refresh %s (deleted).\n");
7722 7722 const char *dpt_deleted = gettext("Could not refresh %s "
7723 7723 "(dependent \"%s\" of %s) (deleted).\n");
7724 7724
7725 7725 serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7726 7726 switch (serr) {
7727 7727 case SCF_ERROR_NONE:
7728 7728 break;
7729 7729
7730 7730 case SCF_ERROR_NO_MEMORY:
7731 7731 if (name == NULL)
7732 7732 warn(gettext("Could not refresh %s (out of memory).\n"),
7733 7733 fmri);
7734 7734 else
7735 7735 warn(gettext("Could not refresh %s "
7736 7736 "(dependent \"%s\" of %s) (out of memory).\n"),
7737 7737 fmri, name, d_fmri);
7738 7738 return (ENOMEM);
7739 7739
7740 7740 case SCF_ERROR_NOT_FOUND:
7741 7741 if (name == NULL)
7742 7742 warn(deleted, fmri);
7743 7743 else
7744 7744 warn(dpt_deleted, fmri, name, d_fmri);
7745 7745 return (0);
7746 7746
7747 7747 case SCF_ERROR_INVALID_ARGUMENT:
7748 7748 case SCF_ERROR_CONSTRAINT_VIOLATED:
7749 7749 default:
7750 7750 bad_error("fmri_to_entity", serr);
7751 7751 }
7752 7752
7753 7753 r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7754 7754 switch (r) {
7755 7755 case 0:
7756 7756 break;
7757 7757
7758 7758 case ECONNABORTED:
7759 7759 if (name != NULL)
7760 7760 warn(gettext("Could not refresh %s "
7761 7761 "(dependent \"%s\" of %s) "
7762 7762 "(repository connection broken).\n"), fmri, name,
7763 7763 d_fmri);
7764 7764 return (r);
7765 7765
7766 7766 case ECANCELED:
7767 7767 if (name == NULL)
7768 7768 warn(deleted, fmri);
7769 7769 else
7770 7770 warn(dpt_deleted, fmri, name, d_fmri);
7771 7771 return (0);
7772 7772
7773 7773 case EACCES:
7774 7774 if (!g_verbose)
7775 7775 return (0);
7776 7776 if (name == NULL)
7777 7777 warn(gettext("Could not refresh %s "
7778 7778 "(backend access denied).\n"), fmri);
7779 7779 else
7780 7780 warn(gettext("Could not refresh %s "
7781 7781 "(dependent \"%s\" of %s) "
7782 7782 "(backend access denied).\n"), fmri, name, d_fmri);
7783 7783 return (0);
7784 7784
7785 7785 case EPERM:
7786 7786 if (name == NULL)
7787 7787 warn(gettext("Could not refresh %s "
7788 7788 "(permission denied).\n"), fmri);
7789 7789 else
7790 7790 warn(gettext("Could not refresh %s "
7791 7791 "(dependent \"%s\" of %s) "
7792 7792 "(permission denied).\n"), fmri, name, d_fmri);
7793 7793 return (r);
7794 7794
7795 7795 case ENOSPC:
7796 7796 if (name == NULL)
7797 7797 warn(gettext("Could not refresh %s "
7798 7798 "(repository server out of resources).\n"),
7799 7799 fmri);
7800 7800 else
7801 7801 warn(gettext("Could not refresh %s "
7802 7802 "(dependent \"%s\" of %s) "
7803 7803 "(repository server out of resources).\n"),
7804 7804 fmri, name, d_fmri);
7805 7805 return (r);
7806 7806
7807 7807 case -1:
7808 7808 scfwarn();
7809 7809 return (r);
7810 7810
7811 7811 default:
7812 7812 bad_error("refresh_entity", r);
7813 7813 }
7814 7814
7815 7815 if (issvc)
7816 7816 scf_service_destroy(ent);
7817 7817 else
7818 7818 scf_instance_destroy(ent);
7819 7819
7820 7820 return (0);
7821 7821 }
7822 7822
7823 7823 static int
7824 7824 alloc_imp_globals()
7825 7825 {
7826 7826 int r;
7827 7827
7828 7828 const char * const emsg_nomem = gettext("Out of memory.\n");
7829 7829 const char * const emsg_nores =
7830 7830 gettext("svc.configd is out of resources.\n");
7831 7831
7832 7832 imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
7833 7833 max_scf_name_len : max_scf_fmri_len) + 1;
7834 7834
7835 7835 if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
7836 7836 (imp_svc = scf_service_create(g_hndl)) == NULL ||
7837 7837 (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
7838 7838 (imp_inst = scf_instance_create(g_hndl)) == NULL ||
7839 7839 (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
7840 7840 (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
7841 7841 (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
7842 7842 (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
7843 7843 (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
7844 7844 (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
7845 7845 (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
7846 7846 (imp_pg = scf_pg_create(g_hndl)) == NULL ||
7847 7847 (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
7848 7848 (imp_prop = scf_property_create(g_hndl)) == NULL ||
7849 7849 (imp_iter = scf_iter_create(g_hndl)) == NULL ||
7850 7850 (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
7851 7851 (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
7852 7852 (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
7853 7853 (imp_str = malloc(imp_str_sz)) == NULL ||
7854 7854 (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
7855 7855 (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
7856 7856 (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
7857 7857 (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
7858 7858 (ud_inst = scf_instance_create(g_hndl)) == NULL ||
7859 7859 (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
7860 7860 (ud_pg = scf_pg_create(g_hndl)) == NULL ||
7861 7861 (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
7862 7862 (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
7863 7863 (ud_prop = scf_property_create(g_hndl)) == NULL ||
7864 7864 (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
7865 7865 (ud_val = scf_value_create(g_hndl)) == NULL ||
7866 7866 (ud_iter = scf_iter_create(g_hndl)) == NULL ||
7867 7867 (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
7868 7868 (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
7869 7869 (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
7870 7870 (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
7871 7871 (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
7872 7872 if (scf_error() == SCF_ERROR_NO_RESOURCES)
7873 7873 warn(emsg_nores);
7874 7874 else
7875 7875 warn(emsg_nomem);
7876 7876
7877 7877 return (-1);
7878 7878 }
7879 7879
7880 7880 r = load_init();
7881 7881 switch (r) {
7882 7882 case 0:
7883 7883 break;
7884 7884
7885 7885 case ENOMEM:
7886 7886 warn(emsg_nomem);
7887 7887 return (-1);
7888 7888
7889 7889 default:
7890 7890 bad_error("load_init", r);
7891 7891 }
7892 7892
7893 7893 return (0);
7894 7894 }
7895 7895
7896 7896 static void
7897 7897 free_imp_globals()
7898 7898 {
7899 7899 pgroup_t *old_dpt;
7900 7900 void *cookie;
7901 7901
7902 7902 load_fini();
7903 7903
7904 7904 free(ud_ctarg);
7905 7905 free(ud_oldtarg);
7906 7906 free(ud_name);
7907 7907 ud_ctarg = ud_oldtarg = ud_name = NULL;
7908 7908
7909 7909 scf_transaction_destroy(ud_tx);
7910 7910 ud_tx = NULL;
7911 7911 scf_iter_destroy(ud_iter);
7912 7912 scf_iter_destroy(ud_iter2);
7913 7913 ud_iter = ud_iter2 = NULL;
7914 7914 scf_value_destroy(ud_val);
7915 7915 ud_val = NULL;
7916 7916 scf_property_destroy(ud_prop);
7917 7917 scf_property_destroy(ud_dpt_prop);
7918 7918 ud_prop = ud_dpt_prop = NULL;
7919 7919 scf_pg_destroy(ud_pg);
7920 7920 scf_pg_destroy(ud_cur_depts_pg);
7921 7921 scf_pg_destroy(ud_run_dpts_pg);
7922 7922 ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
7923 7923 scf_snaplevel_destroy(ud_snpl);
7924 7924 ud_snpl = NULL;
7925 7925 scf_instance_destroy(ud_inst);
7926 7926 ud_inst = NULL;
7927 7927
7928 7928 free(imp_str);
7929 7929 free(imp_tsname);
7930 7930 free(imp_fe1);
7931 7931 free(imp_fe2);
7932 7932 imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
7933 7933
7934 7934 cookie = NULL;
7935 7935 while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
7936 7936 NULL) {
7937 7937 free((char *)old_dpt->sc_pgroup_name);
7938 7938 free((char *)old_dpt->sc_pgroup_fmri);
7939 7939 internal_pgroup_free(old_dpt);
7940 7940 }
7941 7941 uu_list_destroy(imp_deleted_dpts);
7942 7942
7943 7943 scf_transaction_destroy(imp_tx);
7944 7944 imp_tx = NULL;
7945 7945 scf_iter_destroy(imp_iter);
7946 7946 scf_iter_destroy(imp_rpg_iter);
7947 7947 scf_iter_destroy(imp_up_iter);
7948 7948 imp_iter = imp_rpg_iter = imp_up_iter = NULL;
7949 7949 scf_property_destroy(imp_prop);
7950 7950 imp_prop = NULL;
7951 7951 scf_pg_destroy(imp_pg);
7952 7952 scf_pg_destroy(imp_pg2);
7953 7953 imp_pg = imp_pg2 = NULL;
7954 7954 scf_snaplevel_destroy(imp_snpl);
7955 7955 scf_snaplevel_destroy(imp_rsnpl);
7956 7956 imp_snpl = imp_rsnpl = NULL;
7957 7957 scf_snapshot_destroy(imp_snap);
7958 7958 scf_snapshot_destroy(imp_lisnap);
7959 7959 scf_snapshot_destroy(imp_tlisnap);
7960 7960 scf_snapshot_destroy(imp_rsnap);
7961 7961 imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
7962 7962 scf_instance_destroy(imp_inst);
7963 7963 scf_instance_destroy(imp_tinst);
7964 7964 imp_inst = imp_tinst = NULL;
7965 7965 scf_service_destroy(imp_svc);
7966 7966 scf_service_destroy(imp_tsvc);
7967 7967 imp_svc = imp_tsvc = NULL;
7968 7968 scf_scope_destroy(imp_scope);
7969 7969 imp_scope = NULL;
7970 7970
7971 7971 load_fini();
7972 7972 }
7973 7973
7974 7974 int
7975 7975 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
7976 7976 {
7977 7977 scf_callback_t cbdata;
7978 7978 int result = 0;
7979 7979 entity_t *svc, *inst;
7980 7980 uu_list_t *insts;
7981 7981 int r;
7982 7982 pgroup_t *old_dpt;
7983 7983 int annotation_set = 0;
7984 7984
7985 7985 const char * const emsg_nomem = gettext("Out of memory.\n");
7986 7986 const char * const emsg_nores =
7987 7987 gettext("svc.configd is out of resources.\n");
7988 7988
7989 7989 lscf_prep_hndl();
7990 7990
7991 7991 if (alloc_imp_globals())
7992 7992 goto out;
7993 7993
7994 7994 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
7995 7995 switch (scf_error()) {
7996 7996 case SCF_ERROR_CONNECTION_BROKEN:
7997 7997 warn(gettext("Repository connection broken.\n"));
7998 7998 repository_teardown();
7999 7999 result = -1;
8000 8000 goto out;
8001 8001
8002 8002 case SCF_ERROR_NOT_FOUND:
8003 8003 case SCF_ERROR_INVALID_ARGUMENT:
8004 8004 case SCF_ERROR_NOT_BOUND:
8005 8005 case SCF_ERROR_HANDLE_MISMATCH:
8006 8006 default:
8007 8007 bad_error("scf_handle_get_scope", scf_error());
8008 8008 }
8009 8009 }
8010 8010
8011 8011 /* Set up the auditing annotation. */
8012 8012 if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
8013 8013 annotation_set = 1;
8014 8014 } else {
8015 8015 switch (scf_error()) {
8016 8016 case SCF_ERROR_CONNECTION_BROKEN:
8017 8017 warn(gettext("Repository connection broken.\n"));
8018 8018 repository_teardown();
8019 8019 result = -1;
8020 8020 goto out;
8021 8021
8022 8022 case SCF_ERROR_INVALID_ARGUMENT:
8023 8023 case SCF_ERROR_NOT_BOUND:
8024 8024 case SCF_ERROR_NO_RESOURCES:
8025 8025 case SCF_ERROR_INTERNAL:
8026 8026 bad_error("_scf_set_annotation", scf_error());
8027 8027 /* NOTREACHED */
8028 8028
8029 8029 default:
8030 8030 /*
8031 8031 * Do not terminate import because of inability to
8032 8032 * generate annotation audit event.
8033 8033 */
8034 8034 warn(gettext("_scf_set_annotation() unexpectedly "
8035 8035 "failed with return code of %d\n"), scf_error());
8036 8036 break;
8037 8037 }
8038 8038 }
8039 8039
8040 8040 /*
8041 8041 * Clear the sc_import_state's of all services & instances so we can
8042 8042 * report how far we got if we fail.
8043 8043 */
8044 8044 for (svc = uu_list_first(bndl->sc_bundle_services);
8045 8045 svc != NULL;
8046 8046 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8047 8047 svc->sc_import_state = 0;
8048 8048
8049 8049 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
8050 8050 clear_int, (void *)offsetof(entity_t, sc_import_state),
8051 8051 UU_DEFAULT) != 0)
8052 8052 bad_error("uu_list_walk", uu_error());
8053 8053 }
8054 8054
8055 8055 cbdata.sc_handle = g_hndl;
8056 8056 cbdata.sc_parent = imp_scope;
8057 8057 cbdata.sc_flags = flags;
8058 8058 cbdata.sc_general = NULL;
8059 8059
8060 8060 if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
8061 8061 &cbdata, UU_DEFAULT) == 0) {
8062 8062 /* Success. Refresh everything. */
8063 8063
8064 8064 if (flags & SCI_NOREFRESH || no_refresh) {
8065 8065 no_refresh = 0;
8066 8066 result = 0;
8067 8067 goto out;
8068 8068 }
8069 8069
8070 8070 for (svc = uu_list_first(bndl->sc_bundle_services);
8071 8071 svc != NULL;
8072 8072 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8073 8073 pgroup_t *dpt;
8074 8074
8075 8075 insts = svc->sc_u.sc_service.sc_service_instances;
8076 8076
8077 8077 for (inst = uu_list_first(insts);
8078 8078 inst != NULL;
8079 8079 inst = uu_list_next(insts, inst)) {
8080 8080 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
8081 8081 switch (r) {
8082 8082 case 0:
8083 8083 break;
8084 8084
8085 8085 case ENOMEM:
8086 8086 case ECONNABORTED:
8087 8087 case EPERM:
8088 8088 case -1:
8089 8089 goto progress;
8090 8090
8091 8091 default:
8092 8092 bad_error("imp_refresh_fmri", r);
8093 8093 }
8094 8094
8095 8095 inst->sc_import_state = IMPORT_REFRESHED;
8096 8096
8097 8097 for (dpt = uu_list_first(inst->sc_dependents);
8098 8098 dpt != NULL;
8099 8099 dpt = uu_list_next(inst->sc_dependents,
8100 8100 dpt))
8101 8101 if (imp_refresh_fmri(
8102 8102 dpt->sc_pgroup_fmri,
8103 8103 dpt->sc_pgroup_name,
8104 8104 inst->sc_fmri) != 0)
8105 8105 goto progress;
8106 8106 }
8107 8107
8108 8108 for (dpt = uu_list_first(svc->sc_dependents);
8109 8109 dpt != NULL;
8110 8110 dpt = uu_list_next(svc->sc_dependents, dpt))
8111 8111 if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
8112 8112 dpt->sc_pgroup_name, svc->sc_fmri) != 0)
8113 8113 goto progress;
8114 8114 }
8115 8115
8116 8116 for (old_dpt = uu_list_first(imp_deleted_dpts);
8117 8117 old_dpt != NULL;
8118 8118 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
8119 8119 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8120 8120 old_dpt->sc_pgroup_name,
8121 8121 old_dpt->sc_parent->sc_fmri) != 0)
8122 8122 goto progress;
8123 8123
8124 8124 result = 0;
8125 8125 goto out;
8126 8126 }
8127 8127
8128 8128 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8129 8129 bad_error("uu_list_walk", uu_error());
8130 8130
8131 8131 printerr:
8132 8132 /* If the error hasn't been printed yet, do so here. */
8133 8133 switch (cbdata.sc_err) {
8134 8134 case ECONNABORTED:
8135 8135 warn(gettext("Repository connection broken.\n"));
8136 8136 break;
8137 8137
8138 8138 case ENOMEM:
8139 8139 warn(emsg_nomem);
8140 8140 break;
8141 8141
8142 8142 case ENOSPC:
8143 8143 warn(emsg_nores);
8144 8144 break;
8145 8145
8146 8146 case EROFS:
8147 8147 warn(gettext("Repository is read-only.\n"));
8148 8148 break;
8149 8149
8150 8150 case EACCES:
8151 8151 warn(gettext("Repository backend denied access.\n"));
8152 8152 break;
8153 8153
8154 8154 case EPERM:
8155 8155 case EINVAL:
8156 8156 case EEXIST:
8157 8157 case EBUSY:
8158 8158 case EBADF:
8159 8159 case -1:
8160 8160 break;
8161 8161
8162 8162 default:
8163 8163 bad_error("lscf_service_import", cbdata.sc_err);
8164 8164 }
8165 8165
8166 8166 progress:
8167 8167 warn(gettext("Import of %s failed. Progress:\n"), filename);
8168 8168
8169 8169 for (svc = uu_list_first(bndl->sc_bundle_services);
8170 8170 svc != NULL;
8171 8171 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8172 8172 insts = svc->sc_u.sc_service.sc_service_instances;
8173 8173
8174 8174 warn(gettext(" Service \"%s\": %s\n"), svc->sc_name,
8175 8175 import_progress(svc->sc_import_state));
8176 8176
8177 8177 for (inst = uu_list_first(insts);
8178 8178 inst != NULL;
8179 8179 inst = uu_list_next(insts, inst))
8180 8180 warn(gettext(" Instance \"%s\": %s\n"),
8181 8181 inst->sc_name,
8182 8182 import_progress(inst->sc_import_state));
8183 8183 }
8184 8184
8185 8185 if (cbdata.sc_err == ECONNABORTED)
8186 8186 repository_teardown();
8187 8187
8188 8188
8189 8189 result = -1;
8190 8190
8191 8191 out:
8192 8192 if (annotation_set != 0) {
8193 8193 /* Turn off annotation. It is no longer needed. */
8194 8194 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8195 8195 }
8196 8196
8197 8197 free_imp_globals();
8198 8198
8199 8199 return (result);
8200 8200 }
8201 8201
8202 8202 /*
8203 8203 * _lscf_import_err() summarize the error handling returned by
8204 8204 * lscf_import_{instance | service}_pgs
8205 8205 * Return values are:
8206 8206 * IMPORT_NEXT
8207 8207 * IMPORT_OUT
8208 8208 * IMPORT_BAD
8209 8209 */
8210 8210
8211 8211 #define IMPORT_BAD -1
8212 8212 #define IMPORT_NEXT 0
8213 8213 #define IMPORT_OUT 1
8214 8214
8215 8215 static int
8216 8216 _lscf_import_err(int err, const char *fmri)
8217 8217 {
8218 8218 switch (err) {
8219 8219 case 0:
8220 8220 if (g_verbose)
8221 8221 warn(gettext("%s updated.\n"), fmri);
8222 8222 return (IMPORT_NEXT);
8223 8223
8224 8224 case ECONNABORTED:
8225 8225 warn(gettext("Could not update %s "
8226 8226 "(repository connection broken).\n"), fmri);
8227 8227 return (IMPORT_OUT);
8228 8228
8229 8229 case ENOMEM:
8230 8230 warn(gettext("Could not update %s (out of memory).\n"), fmri);
8231 8231 return (IMPORT_OUT);
8232 8232
8233 8233 case ENOSPC:
8234 8234 warn(gettext("Could not update %s "
8235 8235 "(repository server out of resources).\n"), fmri);
8236 8236 return (IMPORT_OUT);
8237 8237
8238 8238 case ECANCELED:
8239 8239 warn(gettext(
8240 8240 "Could not update %s (deleted).\n"), fmri);
8241 8241 return (IMPORT_NEXT);
8242 8242
8243 8243 case EPERM:
8244 8244 case EINVAL:
8245 8245 case EBUSY:
8246 8246 return (IMPORT_NEXT);
8247 8247
8248 8248 case EROFS:
8249 8249 warn(gettext("Could not update %s (repository read-only).\n"),
8250 8250 fmri);
8251 8251 return (IMPORT_OUT);
8252 8252
8253 8253 case EACCES:
8254 8254 warn(gettext("Could not update %s "
8255 8255 "(backend access denied).\n"), fmri);
8256 8256 return (IMPORT_NEXT);
8257 8257
8258 8258 case EEXIST:
8259 8259 default:
8260 8260 return (IMPORT_BAD);
8261 8261 }
8262 8262
8263 8263 /*NOTREACHED*/
8264 8264 }
8265 8265
8266 8266 /*
8267 8267 * The global imp_svc and imp_inst should be set by the caller in the
8268 8268 * check to make sure the service and instance exist that the apply is
8269 8269 * working on.
8270 8270 */
8271 8271 static int
8272 8272 lscf_dependent_apply(void *dpg, void *e)
8273 8273 {
8274 8274 scf_callback_t cb;
8275 8275 pgroup_t *dpt_pgroup = dpg;
8276 8276 pgroup_t *deldpt;
8277 8277 entity_t *ent = e;
8278 8278 int tissvc;
8279 8279 void *sc_ent, *tent;
8280 8280 scf_error_t serr;
8281 8281 int r;
8282 8282
8283 8283 const char * const dependents = "dependents";
8284 8284 const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT);
8285 8285
8286 8286 if (issvc)
8287 8287 sc_ent = imp_svc;
8288 8288 else
8289 8289 sc_ent = imp_inst;
8290 8290
8291 8291 if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg,
8292 8292 imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 ||
8293 8293 scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name,
8294 8294 imp_prop) != 0) {
8295 8295 switch (scf_error()) {
8296 8296 case SCF_ERROR_NOT_FOUND:
8297 8297 case SCF_ERROR_DELETED:
8298 8298 break;
8299 8299
8300 8300 case SCF_ERROR_CONNECTION_BROKEN:
8301 8301 case SCF_ERROR_NOT_SET:
8302 8302 case SCF_ERROR_INVALID_ARGUMENT:
8303 8303 case SCF_ERROR_HANDLE_MISMATCH:
8304 8304 case SCF_ERROR_NOT_BOUND:
8305 8305 default:
8306 8306 bad_error("entity_get_pg", scf_error());
8307 8307 }
8308 8308 } else {
8309 8309 /*
8310 8310 * Found the dependents/<wip dep> so check to
8311 8311 * see if the service is different. If so
8312 8312 * store the service for later refresh, and
8313 8313 * delete the wip dependency from the service
8314 8314 */
8315 8315 if (scf_property_get_value(imp_prop, ud_val) != 0) {
8316 8316 switch (scf_error()) {
8317 8317 case SCF_ERROR_DELETED:
8318 8318 break;
8319 8319
8320 8320 case SCF_ERROR_CONNECTION_BROKEN:
8321 8321 case SCF_ERROR_NOT_SET:
8322 8322 case SCF_ERROR_INVALID_ARGUMENT:
8323 8323 case SCF_ERROR_HANDLE_MISMATCH:
8324 8324 case SCF_ERROR_NOT_BOUND:
8325 8325 default:
8326 8326 bad_error("scf_property_get_value",
8327 8327 scf_error());
8328 8328 }
8329 8329 }
8330 8330
8331 8331 if (scf_value_get_as_string(ud_val, ud_oldtarg,
8332 8332 max_scf_value_len + 1) < 0)
8333 8333 bad_error("scf_value_get_as_string", scf_error());
8334 8334
8335 8335 r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
8336 8336 switch (r) {
8337 8337 case 1:
8338 8338 break;
8339 8339 case 0:
8340 8340 if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent,
8341 8341 &tissvc)) != SCF_ERROR_NONE) {
8342 8342 if (serr == SCF_ERROR_NOT_FOUND) {
8343 8343 break;
8344 8344 } else {
8345 8345 bad_error("fmri_to_entity", serr);
8346 8346 }
8347 8347 }
8348 8348
8349 8349 if (entity_get_pg(tent, tissvc,
8350 8350 dpt_pgroup->sc_pgroup_name, imp_pg) != 0) {
8351 8351 serr = scf_error();
8352 8352 if (serr == SCF_ERROR_NOT_FOUND ||
8353 8353 serr == SCF_ERROR_DELETED) {
8354 8354 break;
8355 8355 } else {
8356 8356 bad_error("entity_get_pg", scf_error());
8357 8357 }
8358 8358 }
8359 8359
8360 8360 if (scf_pg_delete(imp_pg) != 0) {
8361 8361 serr = scf_error();
8362 8362 if (serr == SCF_ERROR_NOT_FOUND ||
8363 8363 serr == SCF_ERROR_DELETED) {
8364 8364 break;
8365 8365 } else {
8366 8366 bad_error("scf_pg_delete", scf_error());
8367 8367 }
8368 8368 }
8369 8369
8370 8370 deldpt = internal_pgroup_new();
8371 8371 if (deldpt == NULL)
8372 8372 return (ENOMEM);
8373 8373 deldpt->sc_pgroup_name =
8374 8374 strdup(dpt_pgroup->sc_pgroup_name);
8375 8375 deldpt->sc_pgroup_fmri = strdup(ud_oldtarg);
8376 8376 if (deldpt->sc_pgroup_name == NULL ||
8377 8377 deldpt->sc_pgroup_fmri == NULL)
8378 8378 return (ENOMEM);
8379 8379 deldpt->sc_parent = (entity_t *)ent;
8380 8380 if (uu_list_insert_after(imp_deleted_dpts, NULL,
8381 8381 deldpt) != 0)
8382 8382 uu_die(gettext("libuutil error: %s\n"),
8383 8383 uu_strerror(uu_error()));
8384 8384
8385 8385 break;
8386 8386 default:
8387 8387 bad_error("fmri_equal", r);
8388 8388 }
8389 8389 }
8390 8390
8391 8391 cb.sc_handle = g_hndl;
8392 8392 cb.sc_parent = ent;
8393 8393 cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT;
8394 8394 cb.sc_source_fmri = ent->sc_fmri;
8395 8395 cb.sc_target_fmri = ent->sc_fmri;
8396 8396 cb.sc_trans = NULL;
8397 8397 cb.sc_flags = SCI_FORCE;
8398 8398
8399 8399 if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT)
8400 8400 return (UU_WALK_ERROR);
8401 8401
8402 8402 r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL);
8403 8403 switch (r) {
8404 8404 case 0:
8405 8405 break;
8406 8406
8407 8407 case ENOMEM:
8408 8408 case ECONNABORTED:
8409 8409 case EPERM:
8410 8410 case -1:
8411 8411 warn(gettext("Unable to refresh \"%s\"\n"),
8412 8412 dpt_pgroup->sc_pgroup_fmri);
8413 8413 return (UU_WALK_ERROR);
8414 8414
8415 8415 default:
8416 8416 bad_error("imp_refresh_fmri", r);
8417 8417 }
8418 8418
8419 8419 return (UU_WALK_NEXT);
8420 8420 }
8421 8421
8422 8422 /*
8423 8423 * Returns
8424 8424 * 0 - success
8425 8425 * -1 - lscf_import_instance_pgs() failed.
8426 8426 */
8427 8427 int
8428 8428 lscf_bundle_apply(bundle_t *bndl, const char *file)
8429 8429 {
8430 8430 pgroup_t *old_dpt;
8431 8431 entity_t *svc, *inst;
8432 8432 int annotation_set = 0;
8433 8433 int ret = 0;
8434 8434 int r = 0;
8435 8435
8436 8436 lscf_prep_hndl();
8437 8437
8438 8438 if ((ret = alloc_imp_globals()))
8439 8439 goto out;
8440 8440
8441 8441 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0)
8442 8442 scfdie();
8443 8443
8444 8444 /*
8445 8445 * Set the strings to be used for the security audit annotation
8446 8446 * event.
8447 8447 */
8448 8448 if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
8449 8449 annotation_set = 1;
8450 8450 } else {
8451 8451 switch (scf_error()) {
8452 8452 case SCF_ERROR_CONNECTION_BROKEN:
8453 8453 warn(gettext("Repository connection broken.\n"));
8454 8454 goto out;
8455 8455
8456 8456 case SCF_ERROR_INVALID_ARGUMENT:
8457 8457 case SCF_ERROR_NOT_BOUND:
8458 8458 case SCF_ERROR_NO_RESOURCES:
8459 8459 case SCF_ERROR_INTERNAL:
8460 8460 bad_error("_scf_set_annotation", scf_error());
8461 8461 /* NOTREACHED */
8462 8462
8463 8463 default:
8464 8464 /*
8465 8465 * Do not abort apply operation because of
8466 8466 * inability to create annotation audit event.
8467 8467 */
8468 8468 warn(gettext("_scf_set_annotation() unexpectedly "
8469 8469 "failed with return code of %d\n"), scf_error());
8470 8470 break;
8471 8471 }
8472 8472 }
8473 8473
8474 8474 for (svc = uu_list_first(bndl->sc_bundle_services);
8475 8475 svc != NULL;
8476 8476 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8477 8477 int refresh = 0;
8478 8478
8479 8479 if (scf_scope_get_service(imp_scope, svc->sc_name,
8480 8480 imp_svc) != 0) {
8481 8481 switch (scf_error()) {
8482 8482 case SCF_ERROR_NOT_FOUND:
8483 8483 if (g_verbose)
8484 8484 warn(gettext("Ignoring nonexistent "
8485 8485 "service %s.\n"), svc->sc_name);
8486 8486 continue;
8487 8487
8488 8488 default:
8489 8489 scfdie();
8490 8490 }
8491 8491 }
8492 8492
8493 8493 /*
8494 8494 * If there were missing types in the profile, then need to
8495 8495 * attempt to find the types.
8496 8496 */
8497 8497 if (svc->sc_miss_type) {
8498 8498 if (uu_list_numnodes(svc->sc_pgroups) &&
8499 8499 uu_list_walk(svc->sc_pgroups, find_current_pg_type,
8500 8500 svc, UU_DEFAULT) != 0) {
8501 8501 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8502 8502 bad_error("uu_list_walk", uu_error());
8503 8503
8504 8504 ret = -1;
8505 8505 continue;
8506 8506 }
8507 8507
8508 8508 for (inst = uu_list_first(
8509 8509 svc->sc_u.sc_service.sc_service_instances);
8510 8510 inst != NULL;
8511 8511 inst = uu_list_next(
8512 8512 svc->sc_u.sc_service.sc_service_instances, inst)) {
8513 8513 /*
8514 8514 * If the instance doesn't exist just
8515 8515 * skip to the next instance and let the
8516 8516 * import note the missing instance.
8517 8517 */
8518 8518 if (scf_service_get_instance(imp_svc,
8519 8519 inst->sc_name, imp_inst) != 0)
8520 8520 continue;
8521 8521
8522 8522 if (uu_list_walk(inst->sc_pgroups,
8523 8523 find_current_pg_type, inst,
8524 8524 UU_DEFAULT) != 0) {
8525 8525 if (uu_error() !=
8526 8526 UU_ERROR_CALLBACK_FAILED)
8527 8527 bad_error("uu_list_walk",
8528 8528 uu_error());
8529 8529
8530 8530 ret = -1;
8531 8531 inst->sc_miss_type = B_TRUE;
8532 8532 }
8533 8533 }
8534 8534 }
8535 8535
8536 8536 /*
8537 8537 * if we have pgs in the profile, we need to refresh ALL
8538 8538 * instances of the service
8539 8539 */
8540 8540 if (uu_list_numnodes(svc->sc_pgroups) != 0) {
8541 8541 refresh = 1;
8542 8542 r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc,
8543 8543 SCI_FORCE | SCI_KEEP);
8544 8544 switch (_lscf_import_err(r, svc->sc_fmri)) {
8545 8545 case IMPORT_NEXT:
8546 8546 break;
8547 8547
8548 8548 case IMPORT_OUT:
8549 8549 goto out;
8550 8550
8551 8551 case IMPORT_BAD:
8552 8552 default:
8553 8553 bad_error("lscf_import_service_pgs", r);
8554 8554 }
8555 8555 }
8556 8556
8557 8557 if (uu_list_numnodes(svc->sc_dependents) != 0) {
8558 8558 uu_list_walk(svc->sc_dependents,
8559 8559 lscf_dependent_apply, svc, UU_DEFAULT);
8560 8560 }
8561 8561
8562 8562 for (inst = uu_list_first(
8563 8563 svc->sc_u.sc_service.sc_service_instances);
8564 8564 inst != NULL;
8565 8565 inst = uu_list_next(
8566 8566 svc->sc_u.sc_service.sc_service_instances, inst)) {
8567 8567 /*
8568 8568 * This instance still has missing types
8569 8569 * so skip it.
8570 8570 */
8571 8571 if (inst->sc_miss_type) {
8572 8572 if (g_verbose)
8573 8573 warn(gettext("Ignoring instance "
8574 8574 "%s:%s with missing types\n"),
8575 8575 inst->sc_parent->sc_name,
8576 8576 inst->sc_name);
8577 8577
8578 8578 continue;
8579 8579 }
8580 8580
8581 8581 if (scf_service_get_instance(imp_svc, inst->sc_name,
8582 8582 imp_inst) != 0) {
8583 8583 switch (scf_error()) {
8584 8584 case SCF_ERROR_NOT_FOUND:
8585 8585 if (g_verbose)
8586 8586 warn(gettext("Ignoring "
8587 8587 "nonexistant instance "
8588 8588 "%s:%s.\n"),
8589 8589 inst->sc_parent->sc_name,
8590 8590 inst->sc_name);
8591 8591 continue;
8592 8592
8593 8593 default:
8594 8594 scfdie();
8595 8595 }
8596 8596 }
8597 8597
8598 8598 /*
8599 8599 * If the instance does not have a general/enabled
8600 8600 * property and no last-import snapshot then the
8601 8601 * instance is not a fully installed instance and
8602 8602 * should not have a profile applied to it.
8603 8603 *
8604 8604 * This could happen if a service/instance declares
8605 8605 * a dependent on behalf of another service/instance.
8606 8606 *
8607 8607 */
8608 8608 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
8609 8609 imp_snap) != 0) {
8610 8610 if (scf_instance_get_pg(imp_inst,
8611 8611 SCF_PG_GENERAL, imp_pg) != 0 ||
8612 8612 scf_pg_get_property(imp_pg,
8613 8613 SCF_PROPERTY_ENABLED, imp_prop) != 0) {
8614 8614 if (g_verbose)
8615 8615 warn(gettext("Ignoreing "
8616 8616 "partial instance "
8617 8617 "%s:%s.\n"),
8618 8618 inst->sc_parent->sc_name,
8619 8619 inst->sc_name);
8620 8620 continue;
8621 8621 }
8622 8622 }
8623 8623
8624 8624 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri,
8625 8625 inst, SCI_FORCE | SCI_KEEP);
8626 8626 switch (_lscf_import_err(r, inst->sc_fmri)) {
8627 8627 case IMPORT_NEXT:
8628 8628 break;
8629 8629
8630 8630 case IMPORT_OUT:
8631 8631 goto out;
8632 8632
8633 8633 case IMPORT_BAD:
8634 8634 default:
8635 8635 bad_error("lscf_import_instance_pgs", r);
8636 8636 }
8637 8637
8638 8638 if (uu_list_numnodes(inst->sc_dependents) != 0) {
8639 8639 uu_list_walk(inst->sc_dependents,
8640 8640 lscf_dependent_apply, inst, UU_DEFAULT);
8641 8641 }
8642 8642
8643 8643 /* refresh only if there is no pgs in the service */
8644 8644 if (refresh == 0)
8645 8645 (void) refresh_entity(0, imp_inst,
8646 8646 inst->sc_fmri, NULL, NULL, NULL);
8647 8647 }
8648 8648
8649 8649 if (refresh == 1) {
8650 8650 char *name_buf = safe_malloc(max_scf_name_len + 1);
8651 8651
8652 8652 (void) refresh_entity(1, imp_svc, svc->sc_name,
8653 8653 imp_inst, imp_iter, name_buf);
8654 8654 free(name_buf);
8655 8655 }
8656 8656
8657 8657 for (old_dpt = uu_list_first(imp_deleted_dpts);
8658 8658 old_dpt != NULL;
8659 8659 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) {
8660 8660 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8661 8661 old_dpt->sc_pgroup_name,
8662 8662 old_dpt->sc_parent->sc_fmri) != 0) {
8663 8663 warn(gettext("Unable to refresh \"%s\"\n"),
8664 8664 old_dpt->sc_pgroup_fmri);
8665 8665 }
8666 8666 }
8667 8667 }
8668 8668
8669 8669 out:
8670 8670 if (annotation_set) {
8671 8671 /* Remove security audit annotation strings. */
8672 8672 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8673 8673 }
8674 8674
8675 8675 free_imp_globals();
8676 8676 return (ret);
8677 8677 }
8678 8678
8679 8679
8680 8680 /*
8681 8681 * Export. These functions create and output an XML tree of a service
8682 8682 * description from the repository. This is largely the inverse of
8683 8683 * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
8684 8684 *
8685 8685 * - We must include any properties which are not represented specifically by
8686 8686 * a service manifest, e.g., properties created by an admin post-import. To
8687 8687 * do so we'll iterate through all properties and deal with each
8688 8688 * apropriately.
8689 8689 *
8690 8690 * - Children of services and instances must must be in the order set by the
8691 8691 * DTD, but we iterate over the properties in undefined order. The elements
8692 8692 * are not easily (or efficiently) sortable by name. Since there's a fixed
8693 8693 * number of classes of them, however, we'll keep the classes separate and
8694 8694 * assemble them in order.
8695 8695 */
8696 8696
8697 8697 /*
8698 8698 * Convenience function to handle xmlSetProp errors (and type casting).
8699 8699 */
8700 8700 static void
8701 8701 safe_setprop(xmlNodePtr n, const char *name, const char *val)
8702 8702 {
8703 8703 if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
8704 8704 uu_die(gettext("Could not set XML property.\n"));
8705 8705 }
8706 8706
8707 8707 /*
8708 8708 * Convenience function to set an XML attribute to the single value of an
8709 8709 * astring property. If the value happens to be the default, don't set the
8710 8710 * attribute. "dval" should be the default value supplied by the DTD, or
8711 8711 * NULL for no default.
8712 8712 */
8713 8713 static int
8714 8714 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
8715 8715 const char *name, const char *dval)
8716 8716 {
8717 8717 scf_value_t *val;
8718 8718 ssize_t len;
8719 8719 char *str;
8720 8720
8721 8721 val = scf_value_create(g_hndl);
8722 8722 if (val == NULL)
8723 8723 scfdie();
8724 8724
8725 8725 if (prop_get_val(prop, val) != 0) {
8726 8726 scf_value_destroy(val);
8727 8727 return (-1);
8728 8728 }
8729 8729
8730 8730 len = scf_value_get_as_string(val, NULL, 0);
8731 8731 if (len < 0)
8732 8732 scfdie();
8733 8733
8734 8734 str = safe_malloc(len + 1);
8735 8735
8736 8736 if (scf_value_get_as_string(val, str, len + 1) < 0)
8737 8737 scfdie();
8738 8738
8739 8739 scf_value_destroy(val);
8740 8740
8741 8741 if (dval == NULL || strcmp(str, dval) != 0)
8742 8742 safe_setprop(n, name, str);
8743 8743
8744 8744 free(str);
8745 8745
8746 8746 return (0);
8747 8747 }
8748 8748
8749 8749 /*
8750 8750 * As above, but the attribute is always set.
8751 8751 */
8752 8752 static int
8753 8753 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
8754 8754 {
8755 8755 return (set_attr_from_prop_default(prop, n, name, NULL));
8756 8756 }
8757 8757
8758 8758 /*
8759 8759 * Dump the given document onto f, with "'s replaced by ''s.
8760 8760 */
8761 8761 static int
8762 8762 write_service_bundle(xmlDocPtr doc, FILE *f)
8763 8763 {
8764 8764 xmlChar *mem;
8765 8765 int sz, i;
8766 8766
8767 8767 mem = NULL;
8768 8768 xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
8769 8769
8770 8770 if (mem == NULL) {
8771 8771 semerr(gettext("Could not dump XML tree.\n"));
8772 8772 return (-1);
8773 8773 }
8774 8774
8775 8775 /*
8776 8776 * Fortunately libxml produces " instead of ", so we can blindly
8777 8777 * replace all " with '. Cursed libxml2! Why must you #ifdef out the
8778 8778 * ' code?!
8779 8779 */
8780 8780 for (i = 0; i < sz; ++i) {
8781 8781 char c = (char)mem[i];
8782 8782
8783 8783 if (c == '"')
8784 8784 (void) fputc('\'', f);
8785 8785 else if (c == '\'')
8786 8786 (void) fwrite("'", sizeof ("'") - 1, 1, f);
8787 8787 else
8788 8788 (void) fputc(c, f);
8789 8789 }
8790 8790
8791 8791 return (0);
8792 8792 }
8793 8793
8794 8794 /*
8795 8795 * Create the DOM elements in elts necessary to (generically) represent prop
8796 8796 * (i.e., a property or propval element). If the name of the property is
8797 8797 * known, it should be passed as name_arg. Otherwise, pass NULL.
8798 8798 */
8799 8799 static void
8800 8800 export_property(scf_property_t *prop, const char *name_arg,
8801 8801 struct pg_elts *elts, int flags)
8802 8802 {
8803 8803 const char *type;
8804 8804 scf_error_t err = 0;
8805 8805 xmlNodePtr pnode, lnode;
8806 8806 char *lnname;
8807 8807 int ret;
8808 8808
8809 8809 /* name */
8810 8810 if (name_arg != NULL) {
8811 8811 (void) strcpy(exp_str, name_arg);
8812 8812 } else {
8813 8813 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
8814 8814 scfdie();
8815 8815 }
8816 8816
8817 8817 /* type */
8818 8818 type = prop_to_typestr(prop);
8819 8819 if (type == NULL)
8820 8820 uu_die(gettext("Can't export property %s: unknown type.\n"),
8821 8821 exp_str);
8822 8822
8823 8823 /* If we're exporting values, and there's just one, export it here. */
8824 8824 if (!(flags & SCE_ALL_VALUES))
8825 8825 goto empty;
8826 8826
8827 8827 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
8828 8828 xmlNodePtr n;
8829 8829
8830 8830 /* Single value, so use propval */
8831 8831 n = xmlNewNode(NULL, (xmlChar *)"propval");
8832 8832 if (n == NULL)
8833 8833 uu_die(emsg_create_xml);
8834 8834
8835 8835 safe_setprop(n, name_attr, exp_str);
8836 8836 safe_setprop(n, type_attr, type);
8837 8837
8838 8838 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
8839 8839 scfdie();
8840 8840 safe_setprop(n, value_attr, exp_str);
8841 8841
8842 8842 if (elts->propvals == NULL)
8843 8843 elts->propvals = n;
8844 8844 else
8845 8845 (void) xmlAddSibling(elts->propvals, n);
8846 8846
8847 8847 return;
8848 8848 }
8849 8849
8850 8850 err = scf_error();
8851 8851
8852 8852 if (err == SCF_ERROR_PERMISSION_DENIED) {
8853 8853 semerr(emsg_permission_denied);
8854 8854 return;
8855 8855 }
8856 8856
8857 8857 if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
8858 8858 err != SCF_ERROR_NOT_FOUND &&
8859 8859 err != SCF_ERROR_PERMISSION_DENIED)
8860 8860 scfdie();
8861 8861
8862 8862 empty:
8863 8863 /* Multiple (or no) values, so use property */
8864 8864 pnode = xmlNewNode(NULL, (xmlChar *)"property");
8865 8865 if (pnode == NULL)
8866 8866 uu_die(emsg_create_xml);
8867 8867
8868 8868 safe_setprop(pnode, name_attr, exp_str);
8869 8869 safe_setprop(pnode, type_attr, type);
8870 8870
8871 8871 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
8872 8872 lnname = uu_msprintf("%s_list", type);
8873 8873 if (lnname == NULL)
8874 8874 uu_die(gettext("Could not create string"));
8875 8875
8876 8876 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
8877 8877 if (lnode == NULL)
8878 8878 uu_die(emsg_create_xml);
8879 8879
8880 8880 uu_free(lnname);
8881 8881
8882 8882 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
8883 8883 scfdie();
8884 8884
8885 8885 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
8886 8886 1) {
8887 8887 xmlNodePtr vn;
8888 8888
8889 8889 vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
8890 8890 NULL);
8891 8891 if (vn == NULL)
8892 8892 uu_die(emsg_create_xml);
8893 8893
8894 8894 if (scf_value_get_as_string(exp_val, exp_str,
8895 8895 exp_str_sz) < 0)
8896 8896 scfdie();
8897 8897 safe_setprop(vn, value_attr, exp_str);
8898 8898 }
8899 8899 if (ret != 0)
8900 8900 scfdie();
8901 8901 }
8902 8902
8903 8903 if (elts->properties == NULL)
8904 8904 elts->properties = pnode;
8905 8905 else
8906 8906 (void) xmlAddSibling(elts->properties, pnode);
8907 8907 }
8908 8908
8909 8909 /*
8910 8910 * Add a property_group element for this property group to elts.
8911 8911 */
8912 8912 static void
8913 8913 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
8914 8914 {
8915 8915 xmlNodePtr n;
8916 8916 struct pg_elts elts;
8917 8917 int ret;
8918 8918 boolean_t read_protected;
8919 8919
8920 8920 n = xmlNewNode(NULL, (xmlChar *)"property_group");
8921 8921
8922 8922 /* name */
8923 8923 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
8924 8924 scfdie();
8925 8925 safe_setprop(n, name_attr, exp_str);
8926 8926
8927 8927 /* type */
8928 8928 if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
8929 8929 scfdie();
8930 8930 safe_setprop(n, type_attr, exp_str);
8931 8931
8932 8932 /* properties */
8933 8933 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8934 8934 scfdie();
8935 8935
8936 8936 (void) memset(&elts, 0, sizeof (elts));
8937 8937
8938 8938 /*
8939 8939 * If this property group is not read protected, we always want to
8940 8940 * output all the values. Otherwise, we only output the values if the
8941 8941 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
8942 8942 */
8943 8943 if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
8944 8944 scfdie();
8945 8945
8946 8946 if (!read_protected)
8947 8947 flags |= SCE_ALL_VALUES;
8948 8948
8949 8949 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8950 8950 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8951 8951 scfdie();
8952 8952
8953 8953 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8954 8954 xmlNodePtr m;
8955 8955
8956 8956 m = xmlNewNode(NULL, (xmlChar *)"stability");
8957 8957 if (m == NULL)
8958 8958 uu_die(emsg_create_xml);
8959 8959
8960 8960 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
8961 8961 elts.stability = m;
8962 8962 continue;
8963 8963 }
8964 8964
8965 8965 xmlFreeNode(m);
8966 8966 }
8967 8967
8968 8968 export_property(exp_prop, NULL, &elts, flags);
8969 8969 }
8970 8970 if (ret == -1)
8971 8971 scfdie();
8972 8972
8973 8973 (void) xmlAddChild(n, elts.stability);
8974 8974 (void) xmlAddChildList(n, elts.propvals);
8975 8975 (void) xmlAddChildList(n, elts.properties);
8976 8976
8977 8977 if (eelts->property_groups == NULL)
8978 8978 eelts->property_groups = n;
8979 8979 else
8980 8980 (void) xmlAddSibling(eelts->property_groups, n);
8981 8981 }
8982 8982
8983 8983 /*
8984 8984 * Create an XML node representing the dependency described by the given
8985 8985 * property group and put it in eelts. Unless the dependency is not valid, in
8986 8986 * which case create a generic property_group element which represents it and
8987 8987 * put it in eelts.
8988 8988 */
8989 8989 static void
8990 8990 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
8991 8991 {
8992 8992 xmlNodePtr n;
8993 8993 int err = 0, ret;
8994 8994 struct pg_elts elts;
8995 8995
8996 8996 n = xmlNewNode(NULL, (xmlChar *)"dependency");
8997 8997 if (n == NULL)
8998 8998 uu_die(emsg_create_xml);
8999 8999
9000 9000 /*
9001 9001 * If the external flag is present, skip this dependency because it
9002 9002 * should have been created by another manifest.
9003 9003 */
9004 9004 if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
9005 9005 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9006 9006 prop_get_val(exp_prop, exp_val) == 0) {
9007 9007 uint8_t b;
9008 9008
9009 9009 if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
9010 9010 scfdie();
9011 9011
9012 9012 if (b)
9013 9013 return;
9014 9014 }
9015 9015 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
9016 9016 scfdie();
9017 9017
9018 9018 /* Get the required attributes. */
9019 9019
9020 9020 /* name */
9021 9021 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9022 9022 scfdie();
9023 9023 safe_setprop(n, name_attr, exp_str);
9024 9024
9025 9025 /* grouping */
9026 9026 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9027 9027 set_attr_from_prop(exp_prop, n, "grouping") != 0)
9028 9028 err = 1;
9029 9029
9030 9030 /* restart_on */
9031 9031 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9032 9032 set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9033 9033 err = 1;
9034 9034
9035 9035 /* type */
9036 9036 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9037 9037 set_attr_from_prop(exp_prop, n, type_attr) != 0)
9038 9038 err = 1;
9039 9039
9040 9040 /*
9041 9041 * entities: Not required, but if we create no children, it will be
9042 9042 * created as empty on import, so fail if it's missing.
9043 9043 */
9044 9044 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9045 9045 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
9046 9046 scf_iter_t *eiter;
9047 9047 int ret2;
9048 9048
9049 9049 eiter = scf_iter_create(g_hndl);
9050 9050 if (eiter == NULL)
9051 9051 scfdie();
9052 9052
9053 9053 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
9054 9054 scfdie();
9055 9055
9056 9056 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
9057 9057 xmlNodePtr ch;
9058 9058
9059 9059 if (scf_value_get_astring(exp_val, exp_str,
9060 9060 exp_str_sz) < 0)
9061 9061 scfdie();
9062 9062
9063 9063 /*
9064 9064 * service_fmri's must be first, so we can add them
9065 9065 * here.
9066 9066 */
9067 9067 ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
9068 9068 NULL);
9069 9069 if (ch == NULL)
9070 9070 uu_die(emsg_create_xml);
9071 9071
9072 9072 safe_setprop(ch, value_attr, exp_str);
9073 9073 }
↓ open down ↓ |
9073 lines elided |
↑ open up ↑ |
9074 9074 if (ret2 == -1)
9075 9075 scfdie();
9076 9076
9077 9077 scf_iter_destroy(eiter);
9078 9078 } else
9079 9079 err = 1;
9080 9080
9081 9081 if (err) {
9082 9082 xmlFreeNode(n);
9083 9083
9084 - export_pg(pg, eelts, 0);
9084 + export_pg(pg, eelts, SCE_ALL_VALUES);
9085 9085
9086 9086 return;
9087 9087 }
9088 9088
9089 9089 /* Iterate through the properties & handle each. */
9090 9090 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9091 9091 scfdie();
9092 9092
9093 9093 (void) memset(&elts, 0, sizeof (elts));
9094 9094
9095 9095 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9096 9096 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9097 9097 scfdie();
9098 9098
9099 9099 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9100 9100 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9101 9101 strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9102 9102 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9103 9103 continue;
9104 9104 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9105 9105 xmlNodePtr m;
9106 9106
9107 9107 m = xmlNewNode(NULL, (xmlChar *)"stability");
9108 9108 if (m == NULL)
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
9109 9109 uu_die(emsg_create_xml);
9110 9110
9111 9111 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9112 9112 elts.stability = m;
9113 9113 continue;
9114 9114 }
9115 9115
9116 9116 xmlFreeNode(m);
9117 9117 }
9118 9118
9119 - export_property(exp_prop, exp_str, &elts, 0);
9119 + export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9120 9120 }
9121 9121 if (ret == -1)
9122 9122 scfdie();
9123 9123
9124 9124 (void) xmlAddChild(n, elts.stability);
9125 9125 (void) xmlAddChildList(n, elts.propvals);
9126 9126 (void) xmlAddChildList(n, elts.properties);
9127 9127
9128 9128 if (eelts->dependencies == NULL)
9129 9129 eelts->dependencies = n;
9130 9130 else
9131 9131 (void) xmlAddSibling(eelts->dependencies, n);
9132 9132 }
9133 9133
9134 9134 static xmlNodePtr
9135 9135 export_method_environment(scf_propertygroup_t *pg)
9136 9136 {
9137 9137 xmlNodePtr env;
9138 9138 int ret;
9139 9139 int children = 0;
9140 9140
9141 9141 if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
9142 9142 return (NULL);
9143 9143
9144 9144 env = xmlNewNode(NULL, (xmlChar *)"method_environment");
9145 9145 if (env == NULL)
9146 9146 uu_die(emsg_create_xml);
9147 9147
9148 9148 if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
9149 9149 scfdie();
9150 9150
9151 9151 if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
9152 9152 scfdie();
9153 9153
9154 9154 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
9155 9155 xmlNodePtr ev;
9156 9156 char *cp;
9157 9157
9158 9158 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9159 9159 scfdie();
9160 9160
9161 9161 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
9162 9162 warn(gettext("Invalid environment variable \"%s\".\n"),
9163 9163 exp_str);
9164 9164 continue;
9165 9165 } else if (strncmp(exp_str, "SMF_", 4) == 0) {
9166 9166 warn(gettext("Invalid environment variable \"%s\"; "
9167 9167 "\"SMF_\" prefix is reserved.\n"), exp_str);
9168 9168 continue;
9169 9169 }
9170 9170
9171 9171 *cp = '\0';
9172 9172 cp++;
9173 9173
9174 9174 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
9175 9175 if (ev == NULL)
9176 9176 uu_die(emsg_create_xml);
9177 9177
9178 9178 safe_setprop(ev, name_attr, exp_str);
9179 9179 safe_setprop(ev, value_attr, cp);
9180 9180 children++;
9181 9181 }
9182 9182
9183 9183 if (ret != 0)
9184 9184 scfdie();
9185 9185
9186 9186 if (children == 0) {
9187 9187 xmlFreeNode(env);
9188 9188 return (NULL);
9189 9189 }
9190 9190
9191 9191 return (env);
9192 9192 }
9193 9193
9194 9194 /*
9195 9195 * As above, but for a method property group.
9196 9196 */
9197 9197 static void
9198 9198 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
9199 9199 {
9200 9200 xmlNodePtr n, env;
9201 9201 char *str;
9202 9202 int err = 0, nonenv, ret;
9203 9203 uint8_t use_profile;
9204 9204 struct pg_elts elts;
9205 9205 xmlNodePtr ctxt = NULL;
9206 9206
9207 9207 n = xmlNewNode(NULL, (xmlChar *)"exec_method");
9208 9208
9209 9209 /* Get the required attributes. */
9210 9210
9211 9211 /* name */
9212 9212 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9213 9213 scfdie();
9214 9214 safe_setprop(n, name_attr, exp_str);
9215 9215
9216 9216 /* type */
9217 9217 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9218 9218 set_attr_from_prop(exp_prop, n, type_attr) != 0)
9219 9219 err = 1;
9220 9220
9221 9221 /* exec */
9222 9222 if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
9223 9223 set_attr_from_prop(exp_prop, n, "exec") != 0)
9224 9224 err = 1;
9225 9225
9226 9226 /* timeout */
9227 9227 if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
9228 9228 prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
9229 9229 prop_get_val(exp_prop, exp_val) == 0) {
9230 9230 uint64_t c;
9231 9231
9232 9232 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
9233 9233 scfdie();
9234 9234
9235 9235 str = uu_msprintf("%llu", c);
9236 9236 if (str == NULL)
↓ open down ↓ |
107 lines elided |
↑ open up ↑ |
9237 9237 uu_die(gettext("Could not create string"));
9238 9238
9239 9239 safe_setprop(n, "timeout_seconds", str);
9240 9240 free(str);
9241 9241 } else
9242 9242 err = 1;
9243 9243
9244 9244 if (err) {
9245 9245 xmlFreeNode(n);
9246 9246
9247 - export_pg(pg, eelts, 0);
9247 + export_pg(pg, eelts, SCE_ALL_VALUES);
9248 9248
9249 9249 return;
9250 9250 }
9251 9251
9252 9252
9253 9253 /*
9254 9254 * If we're going to have a method_context child, we need to know
9255 9255 * before we iterate through the properties. Since method_context's
9256 9256 * are optional, we don't want to complain about any properties
9257 9257 * missing if none of them are there. Thus we can't use the
9258 9258 * convenience functions.
9259 9259 */
9260 9260 nonenv =
9261 9261 scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
9262 9262 SCF_SUCCESS ||
9263 9263 scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
9264 9264 SCF_SUCCESS ||
9265 9265 scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
9266 9266 SCF_SUCCESS ||
9267 9267 scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
9268 9268 SCF_SUCCESS;
9269 9269
9270 9270 if (nonenv) {
9271 9271 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9272 9272 if (ctxt == NULL)
9273 9273 uu_die(emsg_create_xml);
9274 9274
9275 9275 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
9276 9276 0 &&
9277 9277 set_attr_from_prop_default(exp_prop, ctxt,
9278 9278 "working_directory", ":default") != 0)
9279 9279 err = 1;
9280 9280
9281 9281 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
9282 9282 set_attr_from_prop_default(exp_prop, ctxt, "project",
9283 9283 ":default") != 0)
9284 9284 err = 1;
9285 9285
9286 9286 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
9287 9287 0 &&
9288 9288 set_attr_from_prop_default(exp_prop, ctxt,
9289 9289 "resource_pool", ":default") != 0)
9290 9290 err = 1;
9291 9291 /*
9292 9292 * We only want to complain about profile or credential
9293 9293 * properties if we will use them. To determine that we must
9294 9294 * examine USE_PROFILE.
9295 9295 */
9296 9296 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9297 9297 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9298 9298 prop_get_val(exp_prop, exp_val) == 0) {
9299 9299 if (scf_value_get_boolean(exp_val, &use_profile) !=
9300 9300 SCF_SUCCESS) {
9301 9301 scfdie();
9302 9302 }
9303 9303
9304 9304 if (use_profile) {
9305 9305 xmlNodePtr prof;
9306 9306
9307 9307 prof = xmlNewChild(ctxt, NULL,
9308 9308 (xmlChar *)"method_profile", NULL);
9309 9309 if (prof == NULL)
9310 9310 uu_die(emsg_create_xml);
9311 9311
9312 9312 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
9313 9313 exp_prop) != 0 ||
9314 9314 set_attr_from_prop(exp_prop, prof,
9315 9315 name_attr) != 0)
9316 9316 err = 1;
9317 9317 } else {
9318 9318 xmlNodePtr cred;
9319 9319
9320 9320 cred = xmlNewChild(ctxt, NULL,
9321 9321 (xmlChar *)"method_credential", NULL);
9322 9322 if (cred == NULL)
9323 9323 uu_die(emsg_create_xml);
9324 9324
9325 9325 if (pg_get_prop(pg, SCF_PROPERTY_USER,
9326 9326 exp_prop) != 0 ||
9327 9327 set_attr_from_prop(exp_prop, cred,
9328 9328 "user") != 0) {
9329 9329 err = 1;
9330 9330 }
9331 9331
9332 9332 if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
9333 9333 exp_prop) == 0 &&
9334 9334 set_attr_from_prop_default(exp_prop, cred,
9335 9335 "group", ":default") != 0)
9336 9336 err = 1;
9337 9337
9338 9338 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
9339 9339 exp_prop) == 0 &&
9340 9340 set_attr_from_prop_default(exp_prop, cred,
9341 9341 "supp_groups", ":default") != 0)
9342 9342 err = 1;
9343 9343
9344 9344 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
9345 9345 exp_prop) == 0 &&
9346 9346 set_attr_from_prop_default(exp_prop, cred,
9347 9347 "privileges", ":default") != 0)
9348 9348 err = 1;
9349 9349
9350 9350 if (pg_get_prop(pg,
9351 9351 SCF_PROPERTY_LIMIT_PRIVILEGES,
9352 9352 exp_prop) == 0 &&
9353 9353 set_attr_from_prop_default(exp_prop, cred,
9354 9354 "limit_privileges", ":default") != 0)
9355 9355 err = 1;
9356 9356 }
9357 9357 }
9358 9358 }
9359 9359
9360 9360 if ((env = export_method_environment(pg)) != NULL) {
9361 9361 if (ctxt == NULL) {
9362 9362 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9363 9363 if (ctxt == NULL)
9364 9364 uu_die(emsg_create_xml);
9365 9365 }
9366 9366 (void) xmlAddChild(ctxt, env);
9367 9367 }
9368 9368
9369 9369 if (env != NULL || (nonenv && err == 0))
9370 9370 (void) xmlAddChild(n, ctxt);
9371 9371 else
9372 9372 xmlFreeNode(ctxt);
9373 9373
9374 9374 nonenv = (err == 0);
9375 9375
9376 9376 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9377 9377 scfdie();
9378 9378
9379 9379 (void) memset(&elts, 0, sizeof (elts));
9380 9380
9381 9381 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9382 9382 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9383 9383 scfdie();
9384 9384
9385 9385 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9386 9386 strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
9387 9387 strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
9388 9388 continue;
9389 9389 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9390 9390 xmlNodePtr m;
9391 9391
9392 9392 m = xmlNewNode(NULL, (xmlChar *)"stability");
9393 9393 if (m == NULL)
9394 9394 uu_die(emsg_create_xml);
9395 9395
9396 9396 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9397 9397 elts.stability = m;
9398 9398 continue;
9399 9399 }
9400 9400
9401 9401 xmlFreeNode(m);
9402 9402 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
9403 9403 0 ||
9404 9404 strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
9405 9405 strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
9406 9406 strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9407 9407 if (nonenv)
9408 9408 continue;
9409 9409 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
9410 9410 strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
9411 9411 strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
9412 9412 strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
9413 9413 strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) {
↓ open down ↓ |
156 lines elided |
↑ open up ↑ |
9414 9414 if (nonenv && !use_profile)
9415 9415 continue;
9416 9416 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9417 9417 if (nonenv && use_profile)
9418 9418 continue;
9419 9419 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
9420 9420 if (env != NULL)
9421 9421 continue;
9422 9422 }
9423 9423
9424 - export_property(exp_prop, exp_str, &elts, 0);
9424 + export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9425 9425 }
9426 9426 if (ret == -1)
9427 9427 scfdie();
9428 9428
9429 9429 (void) xmlAddChild(n, elts.stability);
9430 9430 (void) xmlAddChildList(n, elts.propvals);
9431 9431 (void) xmlAddChildList(n, elts.properties);
9432 9432
9433 9433 if (eelts->exec_methods == NULL)
9434 9434 eelts->exec_methods = n;
9435 9435 else
9436 9436 (void) xmlAddSibling(eelts->exec_methods, n);
9437 9437 }
9438 9438
9439 9439 static void
9440 9440 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
9441 9441 struct entity_elts *eelts)
9442 9442 {
9443 9443 xmlNodePtr pgnode;
9444 9444
9445 9445 pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
9446 9446 if (pgnode == NULL)
9447 9447 uu_die(emsg_create_xml);
9448 9448
9449 9449 safe_setprop(pgnode, name_attr, name);
9450 9450 safe_setprop(pgnode, type_attr, type);
9451 9451
9452 9452 (void) xmlAddChildList(pgnode, elts->propvals);
9453 9453 (void) xmlAddChildList(pgnode, elts->properties);
9454 9454
9455 9455 if (eelts->property_groups == NULL)
9456 9456 eelts->property_groups = pgnode;
9457 9457 else
9458 9458 (void) xmlAddSibling(eelts->property_groups, pgnode);
9459 9459 }
9460 9460
9461 9461 /*
9462 9462 * Process the general property group for a service. This is the one with the
9463 9463 * goodies.
9464 9464 */
9465 9465 static void
9466 9466 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
9467 9467 {
9468 9468 struct pg_elts elts;
9469 9469 int ret;
9470 9470
9471 9471 /*
9472 9472 * In case there are properties which don't correspond to child
9473 9473 * entities of the service entity, we'll set up a pg_elts structure to
9474 9474 * put them in.
9475 9475 */
9476 9476 (void) memset(&elts, 0, sizeof (elts));
9477 9477
9478 9478 /* Walk the properties, looking for special ones. */
9479 9479 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9480 9480 scfdie();
9481 9481
9482 9482 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9483 9483 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9484 9484 scfdie();
9485 9485
9486 9486 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
9487 9487 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9488 9488 prop_get_val(exp_prop, exp_val) == 0) {
9489 9489 uint8_t b;
9490 9490
9491 9491 if (scf_value_get_boolean(exp_val, &b) !=
9492 9492 SCF_SUCCESS)
9493 9493 scfdie();
9494 9494
9495 9495 if (b) {
9496 9496 selts->single_instance =
9497 9497 xmlNewNode(NULL,
9498 9498 (xmlChar *)"single_instance");
9499 9499 if (selts->single_instance == NULL)
9500 9500 uu_die(emsg_create_xml);
9501 9501 }
9502 9502
9503 9503 continue;
9504 9504 }
9505 9505 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9506 9506 xmlNodePtr rnode, sfnode;
9507 9507
9508 9508 rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9509 9509 if (rnode == NULL)
9510 9510 uu_die(emsg_create_xml);
9511 9511
9512 9512 sfnode = xmlNewChild(rnode, NULL,
9513 9513 (xmlChar *)"service_fmri", NULL);
9514 9514 if (sfnode == NULL)
9515 9515 uu_die(emsg_create_xml);
9516 9516
9517 9517 if (set_attr_from_prop(exp_prop, sfnode,
9518 9518 value_attr) == 0) {
9519 9519 selts->restarter = rnode;
9520 9520 continue;
9521 9521 }
9522 9522
9523 9523 xmlFreeNode(rnode);
9524 9524 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
9525 9525 0) {
9526 9526 xmlNodePtr s;
9527 9527
9528 9528 s = xmlNewNode(NULL, (xmlChar *)"stability");
9529 9529 if (s == NULL)
↓ open down ↓ |
95 lines elided |
↑ open up ↑ |
9530 9530 uu_die(emsg_create_xml);
9531 9531
9532 9532 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9533 9533 selts->stability = s;
9534 9534 continue;
9535 9535 }
9536 9536
9537 9537 xmlFreeNode(s);
9538 9538 }
9539 9539
9540 - export_property(exp_prop, exp_str, &elts, 0);
9540 + export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9541 9541 }
9542 9542 if (ret == -1)
9543 9543 scfdie();
9544 9544
9545 9545 if (elts.propvals != NULL || elts.properties != NULL)
9546 9546 export_pg_elts(&elts, scf_pg_general, scf_group_framework,
9547 9547 selts);
9548 9548 }
9549 9549
9550 9550 static void
9551 9551 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
9552 9552 {
9553 9553 xmlNodePtr n, prof, cred, env;
9554 9554 uint8_t use_profile;
9555 9555 int ret, err = 0;
9556 9556
9557 9557 n = xmlNewNode(NULL, (xmlChar *)"method_context");
9558 9558
9559 9559 env = export_method_environment(pg);
9560 9560
9561 9561 /* Need to know whether we'll use a profile or not. */
9562 9562 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9563 9563 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9564 9564 prop_get_val(exp_prop, exp_val) == 0) {
9565 9565 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
9566 9566 scfdie();
9567 9567
9568 9568 if (use_profile)
9569 9569 prof =
9570 9570 xmlNewChild(n, NULL, (xmlChar *)"method_profile",
9571 9571 NULL);
9572 9572 else
9573 9573 cred =
9574 9574 xmlNewChild(n, NULL, (xmlChar *)"method_credential",
9575 9575 NULL);
9576 9576 }
9577 9577
9578 9578 if (env != NULL)
9579 9579 (void) xmlAddChild(n, env);
9580 9580
9581 9581 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9582 9582 scfdie();
9583 9583
9584 9584 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9585 9585 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9586 9586 scfdie();
9587 9587
9588 9588 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
9589 9589 if (set_attr_from_prop(exp_prop, n,
9590 9590 "working_directory") != 0)
9591 9591 err = 1;
9592 9592 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
9593 9593 if (set_attr_from_prop(exp_prop, n, "project") != 0)
9594 9594 err = 1;
9595 9595 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
9596 9596 if (set_attr_from_prop(exp_prop, n,
9597 9597 "resource_pool") != 0)
9598 9598 err = 1;
9599 9599 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9600 9600 /* EMPTY */
9601 9601 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
9602 9602 if (use_profile ||
9603 9603 set_attr_from_prop(exp_prop, cred, "user") != 0)
9604 9604 err = 1;
9605 9605 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
9606 9606 if (use_profile ||
9607 9607 set_attr_from_prop(exp_prop, cred, "group") != 0)
9608 9608 err = 1;
9609 9609 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
9610 9610 if (use_profile || set_attr_from_prop(exp_prop, cred,
9611 9611 "supp_groups") != 0)
9612 9612 err = 1;
9613 9613 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
9614 9614 if (use_profile || set_attr_from_prop(exp_prop, cred,
9615 9615 "privileges") != 0)
9616 9616 err = 1;
9617 9617 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
9618 9618 0) {
9619 9619 if (use_profile || set_attr_from_prop(exp_prop, cred,
9620 9620 "limit_privileges") != 0)
9621 9621 err = 1;
9622 9622 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9623 9623 if (!use_profile || set_attr_from_prop(exp_prop,
9624 9624 prof, name_attr) != 0)
9625 9625 err = 1;
↓ open down ↓ |
75 lines elided |
↑ open up ↑ |
9626 9626 } else {
9627 9627 /* Can't have generic properties in method_context's */
9628 9628 err = 1;
9629 9629 }
9630 9630 }
9631 9631 if (ret == -1)
9632 9632 scfdie();
9633 9633
9634 9634 if (err && env == NULL) {
9635 9635 xmlFreeNode(n);
9636 - export_pg(pg, elts, 0);
9636 + export_pg(pg, elts, SCE_ALL_VALUES);
9637 9637 return;
9638 9638 }
9639 9639
9640 9640 elts->method_context = n;
9641 9641 }
9642 9642
9643 9643 /*
9644 9644 * Given a dependency property group in the tfmri entity (target fmri), return
9645 9645 * a dependent element which represents it.
9646 9646 */
9647 9647 static xmlNodePtr
9648 9648 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
9649 9649 {
9650 9650 uint8_t b;
9651 9651 xmlNodePtr n, sf;
9652 9652 int err = 0, ret;
9653 9653 struct pg_elts pgelts;
9654 9654
9655 9655 /*
9656 9656 * If external isn't set to true then exporting the service will
9657 9657 * export this as a normal dependency, so we should stop to avoid
9658 9658 * duplication.
9659 9659 */
9660 9660 if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
9661 9661 scf_property_get_value(exp_prop, exp_val) != 0 ||
9662 9662 scf_value_get_boolean(exp_val, &b) != 0 || !b) {
9663 9663 if (g_verbose) {
9664 9664 warn(gettext("Dependent \"%s\" cannot be exported "
9665 9665 "properly because the \"%s\" property of the "
9666 9666 "\"%s\" dependency of %s is not set to true.\n"),
9667 9667 name, scf_property_external, name, tfmri);
9668 9668 }
9669 9669
9670 9670 return (NULL);
9671 9671 }
9672 9672
9673 9673 n = xmlNewNode(NULL, (xmlChar *)"dependent");
9674 9674 if (n == NULL)
9675 9675 uu_die(emsg_create_xml);
9676 9676
9677 9677 safe_setprop(n, name_attr, name);
9678 9678
9679 9679 /* Get the required attributes */
9680 9680 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9681 9681 set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9682 9682 err = 1;
9683 9683
9684 9684 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9685 9685 set_attr_from_prop(exp_prop, n, "grouping") != 0)
9686 9686 err = 1;
9687 9687
9688 9688 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9689 9689 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
9690 9690 prop_get_val(exp_prop, exp_val) == 0) {
9691 9691 /* EMPTY */
9692 9692 } else
9693 9693 err = 1;
9694 9694
9695 9695 if (err) {
9696 9696 xmlFreeNode(n);
9697 9697 return (NULL);
9698 9698 }
9699 9699
9700 9700 sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
9701 9701 if (sf == NULL)
9702 9702 uu_die(emsg_create_xml);
9703 9703
9704 9704 safe_setprop(sf, value_attr, tfmri);
9705 9705
9706 9706 /*
9707 9707 * Now add elements for the other properties.
9708 9708 */
9709 9709 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9710 9710 scfdie();
9711 9711
9712 9712 (void) memset(&pgelts, 0, sizeof (pgelts));
9713 9713
9714 9714 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9715 9715 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9716 9716 scfdie();
9717 9717
9718 9718 if (strcmp(exp_str, scf_property_external) == 0 ||
9719 9719 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9720 9720 strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9721 9721 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9722 9722 continue;
9723 9723 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
9724 9724 if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
9725 9725 prop_get_val(exp_prop, exp_val) == 0) {
9726 9726 char type[sizeof ("service") + 1];
9727 9727
9728 9728 if (scf_value_get_astring(exp_val, type,
9729 9729 sizeof (type)) < 0)
9730 9730 scfdie();
9731 9731
9732 9732 if (strcmp(type, "service") == 0)
9733 9733 continue;
9734 9734 }
9735 9735 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9736 9736 xmlNodePtr s;
9737 9737
9738 9738 s = xmlNewNode(NULL, (xmlChar *)"stability");
9739 9739 if (s == NULL)
↓ open down ↓ |
93 lines elided |
↑ open up ↑ |
9740 9740 uu_die(emsg_create_xml);
9741 9741
9742 9742 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9743 9743 pgelts.stability = s;
9744 9744 continue;
9745 9745 }
9746 9746
9747 9747 xmlFreeNode(s);
9748 9748 }
9749 9749
9750 - export_property(exp_prop, exp_str, &pgelts, 0);
9750 + export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
9751 9751 }
9752 9752 if (ret == -1)
9753 9753 scfdie();
9754 9754
9755 9755 (void) xmlAddChild(n, pgelts.stability);
9756 9756 (void) xmlAddChildList(n, pgelts.propvals);
9757 9757 (void) xmlAddChildList(n, pgelts.properties);
9758 9758
9759 9759 return (n);
9760 9760 }
9761 9761
9762 9762 static void
9763 9763 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
9764 9764 {
9765 9765 scf_propertygroup_t *opg;
9766 9766 scf_iter_t *iter;
9767 9767 char *type, *fmri;
9768 9768 int ret;
9769 9769 struct pg_elts pgelts;
9770 9770 xmlNodePtr n;
9771 9771 scf_error_t serr;
9772 9772
9773 9773 if ((opg = scf_pg_create(g_hndl)) == NULL ||
9774 9774 (iter = scf_iter_create(g_hndl)) == NULL)
9775 9775 scfdie();
9776 9776
9777 9777 /* Can't use exp_prop_iter due to export_dependent(). */
9778 9778 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
9779 9779 scfdie();
9780 9780
9781 9781 type = safe_malloc(max_scf_pg_type_len + 1);
9782 9782
9783 9783 /* Get an extra byte so we can tell if values are too long. */
9784 9784 fmri = safe_malloc(max_scf_fmri_len + 2);
9785 9785
9786 9786 (void) memset(&pgelts, 0, sizeof (pgelts));
9787 9787
9788 9788 while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
↓ open down ↓ |
28 lines elided |
↑ open up ↑ |
9789 9789 void *entity;
9790 9790 int isservice;
9791 9791 scf_type_t ty;
9792 9792
9793 9793 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
9794 9794 scfdie();
9795 9795
9796 9796 if ((ty != SCF_TYPE_ASTRING &&
9797 9797 prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
9798 9798 prop_get_val(exp_prop, exp_val) != 0) {
9799 - export_property(exp_prop, NULL, &pgelts, 0);
9799 + export_property(exp_prop, NULL, &pgelts,
9800 + SCE_ALL_VALUES);
9800 9801 continue;
9801 9802 }
9802 9803
9803 9804 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9804 9805 scfdie();
9805 9806
9806 9807 if (scf_value_get_astring(exp_val, fmri,
9807 9808 max_scf_fmri_len + 2) < 0)
9808 9809 scfdie();
9809 9810
9810 9811 /* Look for a dependency group in the target fmri. */
9811 9812 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
9812 9813 switch (serr) {
9813 9814 case SCF_ERROR_NONE:
9814 9815 break;
9815 9816
9816 9817 case SCF_ERROR_NO_MEMORY:
9817 9818 uu_die(gettext("Out of memory.\n"));
9818 9819 /* NOTREACHED */
9819 9820
↓ open down ↓ |
10 lines elided |
↑ open up ↑ |
9820 9821 case SCF_ERROR_INVALID_ARGUMENT:
9821 9822 if (g_verbose) {
9822 9823 if (scf_property_to_fmri(exp_prop, fmri,
9823 9824 max_scf_fmri_len + 2) < 0)
9824 9825 scfdie();
9825 9826
9826 9827 warn(gettext("The value of %s is not a valid "
9827 9828 "FMRI.\n"), fmri);
9828 9829 }
9829 9830
9830 - export_property(exp_prop, exp_str, &pgelts, 0);
9831 + export_property(exp_prop, exp_str, &pgelts,
9832 + SCE_ALL_VALUES);
9831 9833 continue;
9832 9834
9833 9835 case SCF_ERROR_CONSTRAINT_VIOLATED:
9834 9836 if (g_verbose) {
9835 9837 if (scf_property_to_fmri(exp_prop, fmri,
9836 9838 max_scf_fmri_len + 2) < 0)
9837 9839 scfdie();
9838 9840
9839 9841 warn(gettext("The value of %s does not specify "
9840 9842 "a service or an instance.\n"), fmri);
9841 9843 }
9842 9844
9843 - export_property(exp_prop, exp_str, &pgelts, 0);
9845 + export_property(exp_prop, exp_str, &pgelts,
9846 + SCE_ALL_VALUES);
9844 9847 continue;
9845 9848
9846 9849 case SCF_ERROR_NOT_FOUND:
9847 9850 if (g_verbose) {
9848 9851 if (scf_property_to_fmri(exp_prop, fmri,
9849 9852 max_scf_fmri_len + 2) < 0)
9850 9853 scfdie();
9851 9854
9852 9855 warn(gettext("The entity specified by %s does "
9853 9856 "not exist.\n"), fmri);
9854 9857 }
9855 9858
9856 - export_property(exp_prop, exp_str, &pgelts, 0);
9859 + export_property(exp_prop, exp_str, &pgelts,
9860 + SCE_ALL_VALUES);
9857 9861 continue;
9858 9862
9859 9863 default:
9860 9864 #ifndef NDEBUG
9861 9865 (void) fprintf(stderr, "%s:%d: %s() failed with "
9862 9866 "unexpected error %d.\n", __FILE__, __LINE__,
9863 9867 "fmri_to_entity", serr);
9864 9868 #endif
9865 9869 abort();
9866 9870 }
9867 9871
9868 9872 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
9869 9873 if (scf_error() != SCF_ERROR_NOT_FOUND)
9870 9874 scfdie();
9871 9875
9872 9876 warn(gettext("Entity %s is missing dependency property "
9873 9877 "group %s.\n"), fmri, exp_str);
9874 9878
9875 - export_property(exp_prop, NULL, &pgelts, 0);
9879 + export_property(exp_prop, NULL, &pgelts,
9880 + SCE_ALL_VALUES);
9876 9881 continue;
9877 9882 }
9878 9883
9879 9884 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
9880 9885 scfdie();
9881 9886
9882 9887 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
9883 9888 if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
9884 9889 scfdie();
9885 9890
9886 9891 warn(gettext("Property group %s is not of "
9887 9892 "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
9888 9893
9889 - export_property(exp_prop, NULL, &pgelts, 0);
9894 + export_property(exp_prop, NULL, &pgelts,
9895 + SCE_ALL_VALUES);
9890 9896 continue;
9891 9897 }
9892 9898
9893 9899 n = export_dependent(opg, exp_str, fmri);
9894 - if (n == NULL)
9895 - export_property(exp_prop, exp_str, &pgelts, 0);
9896 - else {
9900 + if (n == NULL) {
9901 + export_property(exp_prop, exp_str, &pgelts,
9902 + SCE_ALL_VALUES);
9903 + } else {
9897 9904 if (eelts->dependents == NULL)
9898 9905 eelts->dependents = n;
9899 9906 else
9900 9907 (void) xmlAddSibling(eelts->dependents,
9901 9908 n);
9902 9909 }
9903 9910 }
9904 9911 if (ret == -1)
9905 9912 scfdie();
9906 9913
9907 9914 free(fmri);
9908 9915 free(type);
9909 9916
9910 9917 scf_iter_destroy(iter);
9911 9918 scf_pg_destroy(opg);
9912 9919
9913 9920 if (pgelts.propvals != NULL || pgelts.properties != NULL)
9914 9921 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
9915 9922 eelts);
9916 9923 }
9917 9924
9918 9925 static void
9919 9926 make_node(xmlNodePtr *nodep, const char *name)
9920 9927 {
9921 9928 if (*nodep == NULL) {
9922 9929 *nodep = xmlNewNode(NULL, (xmlChar *)name);
9923 9930 if (*nodep == NULL)
9924 9931 uu_die(emsg_create_xml);
9925 9932 }
9926 9933 }
9927 9934
9928 9935 static xmlNodePtr
9929 9936 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
9930 9937 {
9931 9938 int ret;
9932 9939 xmlNodePtr parent = NULL;
9933 9940 xmlNodePtr loctext = NULL;
9934 9941
9935 9942 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9936 9943 scfdie();
9937 9944
9938 9945 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9939 9946 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
9940 9947 prop_get_val(exp_prop, exp_val) != 0)
9941 9948 continue;
9942 9949
9943 9950 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
9944 9951 scfdie();
9945 9952
9946 9953 make_node(&parent, parname);
9947 9954 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
9948 9955 (xmlChar *)exp_str);
9949 9956 if (loctext == NULL)
9950 9957 uu_die(emsg_create_xml);
9951 9958
9952 9959 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9953 9960 scfdie();
9954 9961
9955 9962 safe_setprop(loctext, "xml:lang", exp_str);
9956 9963 }
9957 9964
9958 9965 if (ret == -1)
9959 9966 scfdie();
9960 9967
9961 9968 return (parent);
9962 9969 }
9963 9970
9964 9971 static xmlNodePtr
9965 9972 export_tm_manpage(scf_propertygroup_t *pg)
9966 9973 {
9967 9974 xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
9968 9975 if (manpage == NULL)
9969 9976 uu_die(emsg_create_xml);
9970 9977
9971 9978 if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
9972 9979 set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
9973 9980 pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
9974 9981 set_attr_from_prop(exp_prop, manpage, "section") != 0) {
9975 9982 xmlFreeNode(manpage);
9976 9983 return (NULL);
9977 9984 }
9978 9985
9979 9986 if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
9980 9987 (void) set_attr_from_prop_default(exp_prop,
9981 9988 manpage, "manpath", ":default");
9982 9989
9983 9990 return (manpage);
9984 9991 }
9985 9992
9986 9993 static xmlNodePtr
9987 9994 export_tm_doc_link(scf_propertygroup_t *pg)
9988 9995 {
9989 9996 xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
9990 9997 if (doc_link == NULL)
9991 9998 uu_die(emsg_create_xml);
9992 9999
9993 10000 if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
9994 10001 set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
9995 10002 pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
9996 10003 set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
9997 10004 xmlFreeNode(doc_link);
9998 10005 return (NULL);
9999 10006 }
10000 10007 return (doc_link);
10001 10008 }
10002 10009
10003 10010 /*
10004 10011 * Process template information for a service or instances.
10005 10012 */
10006 10013 static void
10007 10014 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
10008 10015 struct template_elts *telts)
10009 10016 {
↓ open down ↓ |
103 lines elided |
↑ open up ↑ |
10010 10017 size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
10011 10018 size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
10012 10019 xmlNodePtr child = NULL;
10013 10020
10014 10021 if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
10015 10022 scfdie();
10016 10023
10017 10024 if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
10018 10025 telts->common_name = export_tm_loctext(pg, "common_name");
10019 10026 if (telts->common_name == NULL)
10020 - export_pg(pg, elts, 0);
10027 + export_pg(pg, elts, SCE_ALL_VALUES);
10021 10028 return;
10022 10029 } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
10023 10030 telts->description = export_tm_loctext(pg, "description");
10024 10031 if (telts->description == NULL)
10025 - export_pg(pg, elts, 0);
10032 + export_pg(pg, elts, SCE_ALL_VALUES);
10026 10033 return;
10027 10034 }
10028 10035
10029 10036 if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
10030 10037 child = export_tm_manpage(pg);
10031 10038 } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
10032 10039 child = export_tm_doc_link(pg);
10033 10040 }
10034 10041
10035 10042 if (child != NULL) {
10036 10043 make_node(&telts->documentation, "documentation");
10037 10044 (void) xmlAddChild(telts->documentation, child);
10038 10045 } else {
10039 - export_pg(pg, elts, 0);
10046 + export_pg(pg, elts, SCE_ALL_VALUES);
10040 10047 }
10041 10048 }
10042 10049
10043 10050 /*
10044 10051 * Process parameter and paramval elements
10045 10052 */
10046 10053 static void
10047 10054 export_parameter(scf_property_t *prop, const char *name,
10048 10055 struct params_elts *elts)
10049 10056 {
10050 10057 xmlNodePtr param;
10051 10058 scf_error_t err = 0;
10052 10059 int ret;
10053 10060
10054 10061 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
10055 10062 if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL)
10056 10063 uu_die(emsg_create_xml);
10057 10064
10058 10065 safe_setprop(param, name_attr, name);
10059 10066
10060 10067 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
10061 10068 scfdie();
10062 10069 safe_setprop(param, value_attr, exp_str);
10063 10070
10064 10071 if (elts->paramval == NULL)
10065 10072 elts->paramval = param;
10066 10073 else
10067 10074 (void) xmlAddSibling(elts->paramval, param);
10068 10075
10069 10076 return;
10070 10077 }
10071 10078
10072 10079 err = scf_error();
10073 10080
10074 10081 if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
10075 10082 err != SCF_ERROR_NOT_FOUND)
10076 10083 scfdie();
10077 10084
10078 10085 if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL)
10079 10086 uu_die(emsg_create_xml);
10080 10087
10081 10088 safe_setprop(param, name_attr, name);
10082 10089
10083 10090 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
10084 10091 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
10085 10092 scfdie();
10086 10093
10087 10094 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
10088 10095 1) {
10089 10096 xmlNodePtr vn;
10090 10097
10091 10098 if ((vn = xmlNewChild(param, NULL,
10092 10099 (xmlChar *)"value_node", NULL)) == NULL)
10093 10100 uu_die(emsg_create_xml);
10094 10101
10095 10102 if (scf_value_get_as_string(exp_val, exp_str,
10096 10103 exp_str_sz) < 0)
10097 10104 scfdie();
10098 10105
10099 10106 safe_setprop(vn, value_attr, exp_str);
10100 10107 }
10101 10108 if (ret != 0)
10102 10109 scfdie();
10103 10110 }
10104 10111
10105 10112 if (elts->parameter == NULL)
10106 10113 elts->parameter = param;
10107 10114 else
10108 10115 (void) xmlAddSibling(elts->parameter, param);
10109 10116 }
10110 10117
10111 10118 /*
10112 10119 * Process notification parameters for a service or instance
10113 10120 */
10114 10121 static void
10115 10122 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts)
10116 10123 {
10117 10124 xmlNodePtr n, event, *type;
10118 10125 struct params_elts *eelts;
10119 10126 int ret, err, i;
10120 10127
10121 10128 n = xmlNewNode(NULL, (xmlChar *)"notification_parameters");
10122 10129 event = xmlNewNode(NULL, (xmlChar *)"event");
10123 10130 if (n == NULL || event == NULL)
10124 10131 uu_die(emsg_create_xml);
10125 10132
10126 10133 /* event value */
10127 10134 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
10128 10135 scfdie();
10129 10136 safe_setprop(event, value_attr, exp_str);
10130 10137
10131 10138 (void) xmlAddChild(n, event);
10132 10139
10133 10140 if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL ||
10134 10141 (eelts = calloc(URI_SCHEME_NUM,
10135 10142 sizeof (struct params_elts))) == NULL)
10136 10143 uu_die(gettext("Out of memory.\n"));
10137 10144
10138 10145 err = 0;
10139 10146
10140 10147 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10141 10148 scfdie();
10142 10149
10143 10150 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10144 10151 char *t, *p;
10145 10152
10146 10153 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10147 10154 scfdie();
10148 10155
10149 10156 if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) {
10150 10157 /*
10151 10158 * this is not a well formed notification parameters
10152 10159 * element, we should export as regular pg
10153 10160 */
10154 10161 err = 1;
10155 10162 break;
10156 10163 }
10157 10164
10158 10165 if ((i = check_uri_protocol(t)) < 0) {
10159 10166 err = 1;
10160 10167 break;
10161 10168 }
10162 10169
10163 10170 if (type[i] == NULL) {
10164 10171 if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) ==
10165 10172 NULL)
10166 10173 uu_die(emsg_create_xml);
10167 10174
10168 10175 safe_setprop(type[i], name_attr, t);
10169 10176 }
10170 10177 if (strcmp(p, active_attr) == 0) {
10171 10178 if (set_attr_from_prop(exp_prop, type[i],
10172 10179 active_attr) != 0) {
10173 10180 err = 1;
10174 10181 break;
10175 10182 }
10176 10183 continue;
10177 10184 }
10178 10185 /*
10179 10186 * We export the parameter
10180 10187 */
10181 10188 export_parameter(exp_prop, p, &eelts[i]);
↓ open down ↓ |
132 lines elided |
↑ open up ↑ |
10182 10189 }
10183 10190
10184 10191 if (ret == -1)
10185 10192 scfdie();
10186 10193
10187 10194 if (err == 1) {
10188 10195 for (i = 0; i < URI_SCHEME_NUM; ++i)
10189 10196 xmlFree(type[i]);
10190 10197 free(type);
10191 10198
10192 - export_pg(pg, elts, 0);
10199 + export_pg(pg, elts, SCE_ALL_VALUES);
10193 10200
10194 10201 return;
10195 10202 } else {
10196 10203 for (i = 0; i < URI_SCHEME_NUM; ++i)
10197 10204 if (type[i] != NULL) {
10198 10205 (void) xmlAddChildList(type[i],
10199 10206 eelts[i].paramval);
10200 10207 (void) xmlAddChildList(type[i],
10201 10208 eelts[i].parameter);
10202 10209 (void) xmlAddSibling(event, type[i]);
10203 10210 }
10204 10211 }
10205 10212 free(type);
10206 10213
10207 10214 if (elts->notify_params == NULL)
10208 10215 elts->notify_params = n;
10209 10216 else
10210 10217 (void) xmlAddSibling(elts->notify_params, n);
10211 10218 }
10212 10219
10213 10220 /*
10214 10221 * Process the general property group for an instance.
10215 10222 */
10216 10223 static void
10217 10224 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
10218 10225 struct entity_elts *elts)
10219 10226 {
10220 10227 uint8_t enabled;
10221 10228 struct pg_elts pgelts;
10222 10229 int ret;
10223 10230
10224 10231 /* enabled */
10225 10232 if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
10226 10233 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
10227 10234 prop_get_val(exp_prop, exp_val) == 0) {
10228 10235 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
10229 10236 scfdie();
10230 10237 } else {
10231 10238 enabled = 0;
10232 10239 }
10233 10240
10234 10241 safe_setprop(inode, enabled_attr, enabled ? true : false);
10235 10242
10236 10243 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10237 10244 scfdie();
10238 10245
10239 10246 (void) memset(&pgelts, 0, sizeof (pgelts));
10240 10247
10241 10248 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10242 10249 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10243 10250 scfdie();
10244 10251
10245 10252 if (strcmp(exp_str, scf_property_enabled) == 0) {
10246 10253 continue;
10247 10254 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
10248 10255 xmlNodePtr rnode, sfnode;
10249 10256
10250 10257 rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10251 10258 if (rnode == NULL)
10252 10259 uu_die(emsg_create_xml);
10253 10260
10254 10261 sfnode = xmlNewChild(rnode, NULL,
10255 10262 (xmlChar *)"service_fmri", NULL);
10256 10263 if (sfnode == NULL)
10257 10264 uu_die(emsg_create_xml);
↓ open down ↓ |
55 lines elided |
↑ open up ↑ |
10258 10265
10259 10266 if (set_attr_from_prop(exp_prop, sfnode,
10260 10267 value_attr) == 0) {
10261 10268 elts->restarter = rnode;
10262 10269 continue;
10263 10270 }
10264 10271
10265 10272 xmlFreeNode(rnode);
10266 10273 }
10267 10274
10268 - export_property(exp_prop, exp_str, &pgelts, 0);
10275 + export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10269 10276 }
10270 10277 if (ret == -1)
10271 10278 scfdie();
10272 10279
10273 10280 if (pgelts.propvals != NULL || pgelts.properties != NULL)
10274 10281 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10275 10282 elts);
10276 10283 }
10277 10284
10278 10285 /*
10279 10286 * Put an instance element for the given instance into selts.
10280 10287 */
10281 10288 static void
10282 10289 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10283 10290 {
10284 10291 xmlNodePtr n;
10285 10292 boolean_t isdefault;
10286 10293 struct entity_elts elts;
10287 10294 struct template_elts template_elts;
10288 10295 int ret;
10289 10296
10290 10297 n = xmlNewNode(NULL, (xmlChar *)"instance");
10291 10298 if (n == NULL)
10292 10299 uu_die(emsg_create_xml);
10293 10300
10294 10301 /* name */
10295 10302 if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10296 10303 scfdie();
10297 10304 safe_setprop(n, name_attr, exp_str);
10298 10305 isdefault = strcmp(exp_str, "default") == 0;
10299 10306
10300 10307 /* check existance of general pg (since general/enabled is required) */
10301 10308 if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
10302 10309 if (scf_error() != SCF_ERROR_NOT_FOUND)
10303 10310 scfdie();
10304 10311
10305 10312 if (g_verbose) {
10306 10313 if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10307 10314 scfdie();
10308 10315
10309 10316 warn(gettext("Instance %s has no general property "
10310 10317 "group; it will be marked disabled.\n"), exp_str);
10311 10318 }
10312 10319
10313 10320 safe_setprop(n, enabled_attr, false);
10314 10321 } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
10315 10322 strcmp(exp_str, scf_group_framework) != 0) {
10316 10323 if (g_verbose) {
10317 10324 if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10318 10325 scfdie();
10319 10326
10320 10327 warn(gettext("Property group %s is not of type "
10321 10328 "framework; the instance will be marked "
10322 10329 "disabled.\n"), exp_str);
10323 10330 }
10324 10331
10325 10332 safe_setprop(n, enabled_attr, false);
10326 10333 }
10327 10334
10328 10335 /* property groups */
10329 10336 if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
10330 10337 scfdie();
10331 10338
10332 10339 (void) memset(&elts, 0, sizeof (elts));
10333 10340 (void) memset(&template_elts, 0, sizeof (template_elts));
10334 10341
10335 10342 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10336 10343 uint32_t pgflags;
10337 10344
10338 10345 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10339 10346 scfdie();
10340 10347
10341 10348 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10342 10349 continue;
10343 10350
10344 10351 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10345 10352 scfdie();
10346 10353
10347 10354 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10348 10355 export_dependency(exp_pg, &elts);
10349 10356 continue;
10350 10357 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10351 10358 export_method(exp_pg, &elts);
10352 10359 continue;
10353 10360 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10354 10361 if (scf_pg_get_name(exp_pg, exp_str,
10355 10362 max_scf_name_len + 1) < 0)
10356 10363 scfdie();
10357 10364
10358 10365 if (strcmp(exp_str, scf_pg_general) == 0) {
10359 10366 export_inst_general(exp_pg, n, &elts);
10360 10367 continue;
10361 10368 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10362 10369 0) {
10363 10370 export_method_context(exp_pg, &elts);
10364 10371 continue;
10365 10372 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10366 10373 export_dependents(exp_pg, &elts);
10367 10374 continue;
10368 10375 }
10369 10376 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10370 10377 export_template(exp_pg, &elts, &template_elts);
10371 10378 continue;
10372 10379 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10373 10380 export_notify_params(exp_pg, &elts);
10374 10381 continue;
10375 10382 }
10376 10383
10377 10384 /* Ordinary pg. */
10378 10385 export_pg(exp_pg, &elts, flags);
10379 10386 }
10380 10387 if (ret == -1)
10381 10388 scfdie();
10382 10389
10383 10390 if (template_elts.common_name != NULL) {
10384 10391 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10385 10392 (void) xmlAddChild(elts.template, template_elts.common_name);
10386 10393 (void) xmlAddChild(elts.template, template_elts.description);
10387 10394 (void) xmlAddChild(elts.template, template_elts.documentation);
10388 10395 } else {
10389 10396 xmlFreeNode(template_elts.description);
10390 10397 xmlFreeNode(template_elts.documentation);
10391 10398 }
10392 10399
10393 10400 if (isdefault && elts.restarter == NULL &&
10394 10401 elts.dependencies == NULL && elts.method_context == NULL &&
10395 10402 elts.exec_methods == NULL && elts.notify_params == NULL &&
10396 10403 elts.property_groups == NULL && elts.template == NULL) {
10397 10404 xmlChar *eval;
10398 10405
10399 10406 /* This is a default instance */
10400 10407 eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10401 10408
10402 10409 xmlFreeNode(n);
10403 10410
10404 10411 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10405 10412 if (n == NULL)
10406 10413 uu_die(emsg_create_xml);
10407 10414
10408 10415 safe_setprop(n, enabled_attr, (char *)eval);
10409 10416 xmlFree(eval);
10410 10417
10411 10418 selts->create_default_instance = n;
10412 10419 } else {
10413 10420 /* Assemble the children in order. */
10414 10421 (void) xmlAddChild(n, elts.restarter);
10415 10422 (void) xmlAddChildList(n, elts.dependencies);
10416 10423 (void) xmlAddChildList(n, elts.dependents);
10417 10424 (void) xmlAddChild(n, elts.method_context);
10418 10425 (void) xmlAddChildList(n, elts.exec_methods);
10419 10426 (void) xmlAddChildList(n, elts.notify_params);
10420 10427 (void) xmlAddChildList(n, elts.property_groups);
10421 10428 (void) xmlAddChild(n, elts.template);
10422 10429
10423 10430 if (selts->instances == NULL)
10424 10431 selts->instances = n;
10425 10432 else
10426 10433 (void) xmlAddSibling(selts->instances, n);
10427 10434 }
10428 10435 }
10429 10436
10430 10437 /*
10431 10438 * Return a service element for the given service.
10432 10439 */
10433 10440 static xmlNodePtr
10434 10441 export_service(scf_service_t *svc, int flags)
10435 10442 {
10436 10443 xmlNodePtr snode;
10437 10444 struct entity_elts elts;
10438 10445 struct template_elts template_elts;
10439 10446 int ret;
10440 10447
10441 10448 snode = xmlNewNode(NULL, (xmlChar *)"service");
10442 10449 if (snode == NULL)
10443 10450 uu_die(emsg_create_xml);
10444 10451
10445 10452 /* Get & set name attribute */
10446 10453 if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
10447 10454 scfdie();
10448 10455 safe_setprop(snode, name_attr, exp_str);
10449 10456
10450 10457 safe_setprop(snode, type_attr, "service");
10451 10458 safe_setprop(snode, "version", "0");
10452 10459
10453 10460 /* Acquire child elements. */
10454 10461 if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
10455 10462 scfdie();
10456 10463
10457 10464 (void) memset(&elts, 0, sizeof (elts));
10458 10465 (void) memset(&template_elts, 0, sizeof (template_elts));
10459 10466
10460 10467 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10461 10468 uint32_t pgflags;
10462 10469
10463 10470 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10464 10471 scfdie();
10465 10472
10466 10473 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10467 10474 continue;
10468 10475
10469 10476 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10470 10477 scfdie();
10471 10478
10472 10479 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10473 10480 export_dependency(exp_pg, &elts);
10474 10481 continue;
10475 10482 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10476 10483 export_method(exp_pg, &elts);
10477 10484 continue;
10478 10485 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10479 10486 if (scf_pg_get_name(exp_pg, exp_str,
10480 10487 max_scf_name_len + 1) < 0)
10481 10488 scfdie();
10482 10489
10483 10490 if (strcmp(exp_str, scf_pg_general) == 0) {
10484 10491 export_svc_general(exp_pg, &elts);
10485 10492 continue;
10486 10493 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10487 10494 0) {
10488 10495 export_method_context(exp_pg, &elts);
10489 10496 continue;
10490 10497 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10491 10498 export_dependents(exp_pg, &elts);
10492 10499 continue;
10493 10500 } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10494 10501 continue;
10495 10502 }
10496 10503 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10497 10504 export_template(exp_pg, &elts, &template_elts);
10498 10505 continue;
10499 10506 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10500 10507 export_notify_params(exp_pg, &elts);
10501 10508 continue;
10502 10509 }
10503 10510
10504 10511 export_pg(exp_pg, &elts, flags);
10505 10512 }
10506 10513 if (ret == -1)
10507 10514 scfdie();
10508 10515
10509 10516 if (template_elts.common_name != NULL) {
10510 10517 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10511 10518 (void) xmlAddChild(elts.template, template_elts.common_name);
10512 10519 (void) xmlAddChild(elts.template, template_elts.description);
10513 10520 (void) xmlAddChild(elts.template, template_elts.documentation);
10514 10521 } else {
10515 10522 xmlFreeNode(template_elts.description);
10516 10523 xmlFreeNode(template_elts.documentation);
10517 10524 }
10518 10525
10519 10526 /* Iterate instances */
10520 10527 if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
10521 10528 scfdie();
10522 10529
10523 10530 while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10524 10531 export_instance(exp_inst, &elts, flags);
10525 10532 if (ret == -1)
10526 10533 scfdie();
10527 10534
10528 10535 /* Now add all of the accumulated elements in order. */
10529 10536 (void) xmlAddChild(snode, elts.create_default_instance);
10530 10537 (void) xmlAddChild(snode, elts.single_instance);
10531 10538 (void) xmlAddChild(snode, elts.restarter);
10532 10539 (void) xmlAddChildList(snode, elts.dependencies);
10533 10540 (void) xmlAddChildList(snode, elts.dependents);
10534 10541 (void) xmlAddChild(snode, elts.method_context);
10535 10542 (void) xmlAddChildList(snode, elts.exec_methods);
10536 10543 (void) xmlAddChildList(snode, elts.notify_params);
10537 10544 (void) xmlAddChildList(snode, elts.property_groups);
10538 10545 (void) xmlAddChildList(snode, elts.instances);
10539 10546 (void) xmlAddChild(snode, elts.stability);
10540 10547 (void) xmlAddChild(snode, elts.template);
10541 10548
10542 10549 return (snode);
10543 10550 }
10544 10551
10545 10552 static int
10546 10553 export_callback(void *data, scf_walkinfo_t *wip)
10547 10554 {
10548 10555 FILE *f;
10549 10556 xmlDocPtr doc;
10550 10557 xmlNodePtr sb;
10551 10558 int result;
10552 10559 struct export_args *argsp = (struct export_args *)data;
10553 10560
10554 10561 if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
10555 10562 (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10556 10563 (exp_prop = scf_property_create(g_hndl)) == NULL ||
10557 10564 (exp_val = scf_value_create(g_hndl)) == NULL ||
10558 10565 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10559 10566 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10560 10567 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10561 10568 (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10562 10569 scfdie();
10563 10570
10564 10571 exp_str_sz = max_scf_len + 1;
10565 10572 exp_str = safe_malloc(exp_str_sz);
10566 10573
10567 10574 if (argsp->filename != NULL) {
10568 10575 errno = 0;
10569 10576 f = fopen(argsp->filename, "wb");
10570 10577 if (f == NULL) {
10571 10578 if (errno == 0)
10572 10579 uu_die(gettext("Could not open \"%s\": no free "
10573 10580 "stdio streams.\n"), argsp->filename);
10574 10581 else
10575 10582 uu_die(gettext("Could not open \"%s\""),
10576 10583 argsp->filename);
10577 10584 }
10578 10585 } else
10579 10586 f = stdout;
10580 10587
10581 10588 doc = xmlNewDoc((xmlChar *)"1.0");
10582 10589 if (doc == NULL)
10583 10590 uu_die(gettext("Could not create XML document.\n"));
10584 10591
10585 10592 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10586 10593 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10587 10594 uu_die(emsg_create_xml);
10588 10595
10589 10596 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10590 10597 if (sb == NULL)
10591 10598 uu_die(emsg_create_xml);
10592 10599 safe_setprop(sb, type_attr, "manifest");
10593 10600 safe_setprop(sb, name_attr, "export");
10594 10601 (void) xmlAddSibling(doc->children, sb);
10595 10602
10596 10603 (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
10597 10604
10598 10605 result = write_service_bundle(doc, f);
10599 10606
10600 10607 free(exp_str);
10601 10608 scf_iter_destroy(exp_val_iter);
10602 10609 scf_iter_destroy(exp_prop_iter);
10603 10610 scf_iter_destroy(exp_pg_iter);
10604 10611 scf_iter_destroy(exp_inst_iter);
10605 10612 scf_value_destroy(exp_val);
10606 10613 scf_property_destroy(exp_prop);
10607 10614 scf_pg_destroy(exp_pg);
10608 10615 scf_instance_destroy(exp_inst);
10609 10616
10610 10617 xmlFreeDoc(doc);
10611 10618
10612 10619 if (f != stdout)
10613 10620 (void) fclose(f);
10614 10621
10615 10622 return (result);
10616 10623 }
10617 10624
10618 10625 /*
10619 10626 * Get the service named by fmri, build an XML tree which represents it, and
10620 10627 * dump it into filename (or stdout if filename is NULL).
10621 10628 */
10622 10629 int
10623 10630 lscf_service_export(char *fmri, const char *filename, int flags)
10624 10631 {
10625 10632 struct export_args args;
10626 10633 int ret, err;
10627 10634
10628 10635 lscf_prep_hndl();
10629 10636
10630 10637 bzero(&args, sizeof (args));
10631 10638 args.filename = filename;
10632 10639 args.flags = flags;
10633 10640
10634 10641 err = 0;
10635 10642 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10636 10643 SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10637 10644 &args, &err, semerr)) != 0) {
10638 10645 if (ret != -1)
10639 10646 semerr(gettext("Failed to walk instances: %s\n"),
10640 10647 scf_strerror(ret));
10641 10648 return (-1);
10642 10649 }
10643 10650
10644 10651 /*
10645 10652 * Error message has already been printed.
10646 10653 */
10647 10654 if (err != 0)
10648 10655 return (-1);
10649 10656
10650 10657 return (0);
10651 10658 }
10652 10659
10653 10660
10654 10661 /*
10655 10662 * Archive
10656 10663 */
10657 10664
10658 10665 static xmlNodePtr
10659 10666 make_archive(int flags)
10660 10667 {
10661 10668 xmlNodePtr sb;
10662 10669 scf_scope_t *scope;
10663 10670 scf_service_t *svc;
10664 10671 scf_iter_t *iter;
10665 10672 int r;
10666 10673
10667 10674 if ((scope = scf_scope_create(g_hndl)) == NULL ||
10668 10675 (svc = scf_service_create(g_hndl)) == NULL ||
10669 10676 (iter = scf_iter_create(g_hndl)) == NULL ||
10670 10677 (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10671 10678 (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10672 10679 (exp_prop = scf_property_create(g_hndl)) == NULL ||
10673 10680 (exp_val = scf_value_create(g_hndl)) == NULL ||
10674 10681 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10675 10682 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10676 10683 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10677 10684 (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10678 10685 scfdie();
10679 10686
10680 10687 exp_str_sz = max_scf_len + 1;
10681 10688 exp_str = safe_malloc(exp_str_sz);
10682 10689
10683 10690 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10684 10691 if (sb == NULL)
10685 10692 uu_die(emsg_create_xml);
10686 10693 safe_setprop(sb, type_attr, "archive");
10687 10694 safe_setprop(sb, name_attr, "none");
10688 10695
10689 10696 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
10690 10697 scfdie();
10691 10698 if (scf_iter_scope_services(iter, scope) != 0)
10692 10699 scfdie();
10693 10700
10694 10701 for (;;) {
10695 10702 r = scf_iter_next_service(iter, svc);
10696 10703 if (r == 0)
10697 10704 break;
10698 10705 if (r != 1)
10699 10706 scfdie();
10700 10707
10701 10708 if (scf_service_get_name(svc, exp_str,
10702 10709 max_scf_name_len + 1) < 0)
10703 10710 scfdie();
10704 10711
10705 10712 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
10706 10713 continue;
10707 10714
10708 10715 (void) xmlAddChild(sb, export_service(svc, flags));
10709 10716 }
10710 10717
10711 10718 free(exp_str);
10712 10719
10713 10720 scf_iter_destroy(exp_val_iter);
10714 10721 scf_iter_destroy(exp_prop_iter);
10715 10722 scf_iter_destroy(exp_pg_iter);
10716 10723 scf_iter_destroy(exp_inst_iter);
10717 10724 scf_value_destroy(exp_val);
10718 10725 scf_property_destroy(exp_prop);
10719 10726 scf_pg_destroy(exp_pg);
10720 10727 scf_instance_destroy(exp_inst);
10721 10728 scf_iter_destroy(iter);
10722 10729 scf_service_destroy(svc);
10723 10730 scf_scope_destroy(scope);
10724 10731
10725 10732 return (sb);
10726 10733 }
10727 10734
10728 10735 int
10729 10736 lscf_archive(const char *filename, int flags)
10730 10737 {
10731 10738 FILE *f;
10732 10739 xmlDocPtr doc;
10733 10740 int result;
10734 10741
10735 10742 lscf_prep_hndl();
10736 10743
10737 10744 if (filename != NULL) {
10738 10745 errno = 0;
10739 10746 f = fopen(filename, "wb");
10740 10747 if (f == NULL) {
10741 10748 if (errno == 0)
10742 10749 uu_die(gettext("Could not open \"%s\": no free "
10743 10750 "stdio streams.\n"), filename);
10744 10751 else
10745 10752 uu_die(gettext("Could not open \"%s\""),
10746 10753 filename);
10747 10754 }
10748 10755 } else
10749 10756 f = stdout;
10750 10757
10751 10758 doc = xmlNewDoc((xmlChar *)"1.0");
10752 10759 if (doc == NULL)
10753 10760 uu_die(gettext("Could not create XML document.\n"));
10754 10761
10755 10762 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10756 10763 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10757 10764 uu_die(emsg_create_xml);
10758 10765
10759 10766 (void) xmlAddSibling(doc->children, make_archive(flags));
10760 10767
10761 10768 result = write_service_bundle(doc, f);
10762 10769
10763 10770 xmlFreeDoc(doc);
10764 10771
10765 10772 if (f != stdout)
10766 10773 (void) fclose(f);
10767 10774
10768 10775 return (result);
10769 10776 }
10770 10777
10771 10778
10772 10779 /*
10773 10780 * "Extract" a profile.
10774 10781 */
10775 10782 int
10776 10783 lscf_profile_extract(const char *filename)
10777 10784 {
10778 10785 FILE *f;
10779 10786 xmlDocPtr doc;
10780 10787 xmlNodePtr sb, snode, inode;
10781 10788 scf_scope_t *scope;
10782 10789 scf_service_t *svc;
10783 10790 scf_instance_t *inst;
10784 10791 scf_propertygroup_t *pg;
10785 10792 scf_property_t *prop;
10786 10793 scf_value_t *val;
10787 10794 scf_iter_t *siter, *iiter;
10788 10795 int r, s;
10789 10796 char *namebuf;
10790 10797 uint8_t b;
10791 10798 int result;
10792 10799
10793 10800 lscf_prep_hndl();
10794 10801
10795 10802 if (filename != NULL) {
10796 10803 errno = 0;
10797 10804 f = fopen(filename, "wb");
10798 10805 if (f == NULL) {
10799 10806 if (errno == 0)
10800 10807 uu_die(gettext("Could not open \"%s\": no "
10801 10808 "free stdio streams.\n"), filename);
10802 10809 else
10803 10810 uu_die(gettext("Could not open \"%s\""),
10804 10811 filename);
10805 10812 }
10806 10813 } else
10807 10814 f = stdout;
10808 10815
10809 10816 doc = xmlNewDoc((xmlChar *)"1.0");
10810 10817 if (doc == NULL)
10811 10818 uu_die(gettext("Could not create XML document.\n"));
10812 10819
10813 10820 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10814 10821 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10815 10822 uu_die(emsg_create_xml);
10816 10823
10817 10824 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10818 10825 if (sb == NULL)
10819 10826 uu_die(emsg_create_xml);
10820 10827 safe_setprop(sb, type_attr, "profile");
10821 10828 safe_setprop(sb, name_attr, "extract");
10822 10829 (void) xmlAddSibling(doc->children, sb);
10823 10830
10824 10831 if ((scope = scf_scope_create(g_hndl)) == NULL ||
10825 10832 (svc = scf_service_create(g_hndl)) == NULL ||
10826 10833 (inst = scf_instance_create(g_hndl)) == NULL ||
10827 10834 (pg = scf_pg_create(g_hndl)) == NULL ||
10828 10835 (prop = scf_property_create(g_hndl)) == NULL ||
10829 10836 (val = scf_value_create(g_hndl)) == NULL ||
10830 10837 (siter = scf_iter_create(g_hndl)) == NULL ||
10831 10838 (iiter = scf_iter_create(g_hndl)) == NULL)
10832 10839 scfdie();
10833 10840
10834 10841 if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
10835 10842 scfdie();
10836 10843
10837 10844 if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
10838 10845 scfdie();
10839 10846
10840 10847 namebuf = safe_malloc(max_scf_name_len + 1);
10841 10848
10842 10849 while ((r = scf_iter_next_service(siter, svc)) == 1) {
10843 10850 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
10844 10851 scfdie();
10845 10852
10846 10853 snode = xmlNewNode(NULL, (xmlChar *)"service");
10847 10854 if (snode == NULL)
10848 10855 uu_die(emsg_create_xml);
10849 10856
10850 10857 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
10851 10858 0)
10852 10859 scfdie();
10853 10860
10854 10861 safe_setprop(snode, name_attr, namebuf);
10855 10862
10856 10863 safe_setprop(snode, type_attr, "service");
10857 10864 safe_setprop(snode, "version", "0");
10858 10865
10859 10866 while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
10860 10867 if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
10861 10868 SCF_SUCCESS) {
10862 10869 if (scf_error() != SCF_ERROR_NOT_FOUND)
10863 10870 scfdie();
10864 10871
10865 10872 if (g_verbose) {
10866 10873 ssize_t len;
10867 10874 char *fmri;
10868 10875
10869 10876 len =
10870 10877 scf_instance_to_fmri(inst, NULL, 0);
10871 10878 if (len < 0)
10872 10879 scfdie();
10873 10880
10874 10881 fmri = safe_malloc(len + 1);
10875 10882
10876 10883 if (scf_instance_to_fmri(inst, fmri,
10877 10884 len + 1) < 0)
10878 10885 scfdie();
10879 10886
10880 10887 warn("Instance %s has no \"%s\" "
10881 10888 "property group.\n", fmri,
10882 10889 scf_pg_general);
10883 10890
10884 10891 free(fmri);
10885 10892 }
10886 10893
10887 10894 continue;
10888 10895 }
10889 10896
10890 10897 if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
10891 10898 prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
10892 10899 prop_get_val(prop, val) != 0)
10893 10900 continue;
10894 10901
10895 10902 inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
10896 10903 NULL);
10897 10904 if (inode == NULL)
10898 10905 uu_die(emsg_create_xml);
10899 10906
10900 10907 if (scf_instance_get_name(inst, namebuf,
10901 10908 max_scf_name_len + 1) < 0)
10902 10909 scfdie();
10903 10910
10904 10911 safe_setprop(inode, name_attr, namebuf);
10905 10912
10906 10913 if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
10907 10914 scfdie();
10908 10915
10909 10916 safe_setprop(inode, enabled_attr, b ? true : false);
10910 10917 }
10911 10918 if (s < 0)
10912 10919 scfdie();
10913 10920
10914 10921 if (snode->children != NULL)
10915 10922 (void) xmlAddChild(sb, snode);
10916 10923 else
10917 10924 xmlFreeNode(snode);
10918 10925 }
10919 10926 if (r < 0)
10920 10927 scfdie();
10921 10928
10922 10929 free(namebuf);
10923 10930
10924 10931 result = write_service_bundle(doc, f);
10925 10932
10926 10933 xmlFreeDoc(doc);
10927 10934
10928 10935 if (f != stdout)
10929 10936 (void) fclose(f);
10930 10937
10931 10938 return (result);
10932 10939 }
10933 10940
10934 10941
10935 10942 /*
10936 10943 * Entity manipulation commands
10937 10944 */
10938 10945
10939 10946 /*
10940 10947 * Entity selection. If no entity is selected, then the current scope is in
10941 10948 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected,
10942 10949 * only cur_inst is NULL, and when an instance is selected, none are NULL.
10943 10950 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
10944 10951 * cur_inst will be non-NULL.
10945 10952 */
10946 10953
10947 10954 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
10948 10955 static int
10949 10956 select_inst(const char *name)
10950 10957 {
10951 10958 scf_instance_t *inst;
10952 10959 scf_error_t err;
10953 10960
10954 10961 assert(cur_svc != NULL);
10955 10962
10956 10963 inst = scf_instance_create(g_hndl);
10957 10964 if (inst == NULL)
10958 10965 scfdie();
10959 10966
10960 10967 if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
10961 10968 cur_inst = inst;
10962 10969 return (0);
10963 10970 }
10964 10971
10965 10972 err = scf_error();
10966 10973 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
10967 10974 scfdie();
10968 10975
10969 10976 scf_instance_destroy(inst);
10970 10977 return (1);
10971 10978 }
10972 10979
10973 10980 /* Returns as above. */
10974 10981 static int
10975 10982 select_svc(const char *name)
10976 10983 {
10977 10984 scf_service_t *svc;
10978 10985 scf_error_t err;
10979 10986
10980 10987 assert(cur_scope != NULL);
10981 10988
10982 10989 svc = scf_service_create(g_hndl);
10983 10990 if (svc == NULL)
10984 10991 scfdie();
10985 10992
10986 10993 if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
10987 10994 cur_svc = svc;
10988 10995 return (0);
10989 10996 }
10990 10997
10991 10998 err = scf_error();
10992 10999 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
10993 11000 scfdie();
10994 11001
10995 11002 scf_service_destroy(svc);
10996 11003 return (1);
10997 11004 }
10998 11005
10999 11006 /* ARGSUSED */
11000 11007 static int
11001 11008 select_callback(void *unused, scf_walkinfo_t *wip)
11002 11009 {
11003 11010 scf_instance_t *inst;
11004 11011 scf_service_t *svc;
11005 11012 scf_scope_t *scope;
11006 11013
11007 11014 if (wip->inst != NULL) {
11008 11015 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11009 11016 (svc = scf_service_create(g_hndl)) == NULL ||
11010 11017 (inst = scf_instance_create(g_hndl)) == NULL)
11011 11018 scfdie();
11012 11019
11013 11020 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11014 11021 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11015 11022 scfdie();
11016 11023 } else {
11017 11024 assert(wip->svc != NULL);
11018 11025
11019 11026 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11020 11027 (svc = scf_service_create(g_hndl)) == NULL)
11021 11028 scfdie();
11022 11029
11023 11030 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11024 11031 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11025 11032 scfdie();
11026 11033
11027 11034 inst = NULL;
11028 11035 }
11029 11036
11030 11037 /* Clear out the current selection */
11031 11038 assert(cur_scope != NULL);
11032 11039 scf_scope_destroy(cur_scope);
11033 11040 scf_service_destroy(cur_svc);
11034 11041 scf_instance_destroy(cur_inst);
11035 11042
11036 11043 cur_scope = scope;
11037 11044 cur_svc = svc;
11038 11045 cur_inst = inst;
11039 11046
11040 11047 return (0);
11041 11048 }
11042 11049
11043 11050 static int
11044 11051 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
11045 11052 {
11046 11053 char **fmri = fmri_p;
11047 11054
11048 11055 *fmri = strdup(wip->fmri);
11049 11056 if (*fmri == NULL)
11050 11057 uu_die(gettext("Out of memory.\n"));
11051 11058
11052 11059 return (0);
11053 11060 }
11054 11061
11055 11062 /*
11056 11063 * validate [fmri]
11057 11064 * Perform the validation of an FMRI instance.
11058 11065 */
11059 11066 void
11060 11067 lscf_validate_fmri(const char *fmri)
11061 11068 {
11062 11069 int ret = 0;
11063 11070 size_t inst_sz;
11064 11071 char *inst_fmri = NULL;
11065 11072 scf_tmpl_errors_t *errs = NULL;
11066 11073 char *snapbuf = NULL;
11067 11074
11068 11075 lscf_prep_hndl();
11069 11076
11070 11077 if (fmri == NULL) {
11071 11078 inst_sz = max_scf_fmri_len + 1;
11072 11079 inst_fmri = safe_malloc(inst_sz);
11073 11080
11074 11081 if (cur_snap != NULL) {
11075 11082 snapbuf = safe_malloc(max_scf_name_len + 1);
11076 11083 if (scf_snapshot_get_name(cur_snap, snapbuf,
11077 11084 max_scf_name_len + 1) < 0)
11078 11085 scfdie();
11079 11086 }
11080 11087 if (cur_inst == NULL) {
11081 11088 semerr(gettext("No instance selected\n"));
11082 11089 goto cleanup;
11083 11090 } else if (scf_instance_to_fmri(cur_inst, inst_fmri,
11084 11091 inst_sz) >= inst_sz) {
11085 11092 /* sanity check. Should never get here */
11086 11093 uu_die(gettext("Unexpected error! file %s, line %d\n"),
11087 11094 __FILE__, __LINE__);
11088 11095 }
11089 11096 } else {
11090 11097 scf_error_t scf_err;
11091 11098 int err = 0;
11092 11099
11093 11100 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
11094 11101 validate_callback, &inst_fmri, &err, semerr)) != 0) {
11095 11102 uu_warn("Failed to walk instances: %s\n",
11096 11103 scf_strerror(scf_err));
11097 11104 goto cleanup;
11098 11105 }
11099 11106 if (err != 0) {
11100 11107 /* error message displayed by scf_walk_fmri */
11101 11108 goto cleanup;
11102 11109 }
11103 11110 }
11104 11111
11105 11112 ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
11106 11113 SCF_TMPL_VALIDATE_FLAG_CURRENT);
11107 11114 if (ret == -1) {
11108 11115 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
11109 11116 warn(gettext("Template data for %s is invalid. "
11110 11117 "Consider reverting to a previous snapshot or "
11111 11118 "restoring original configuration.\n"), inst_fmri);
11112 11119 } else {
11113 11120 uu_warn("%s: %s\n",
11114 11121 gettext("Error validating the instance"),
11115 11122 scf_strerror(scf_error()));
11116 11123 }
11117 11124 } else if (ret == 1 && errs != NULL) {
11118 11125 scf_tmpl_error_t *err = NULL;
11119 11126 char *msg;
11120 11127 size_t len = 256; /* initial error buffer size */
11121 11128 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
11122 11129 SCF_TMPL_STRERROR_HUMAN : 0;
11123 11130
11124 11131 msg = safe_malloc(len);
11125 11132
11126 11133 while ((err = scf_tmpl_next_error(errs)) != NULL) {
11127 11134 int ret;
11128 11135
11129 11136 if ((ret = scf_tmpl_strerror(err, msg, len,
11130 11137 flag)) >= len) {
11131 11138 len = ret + 1;
11132 11139 msg = realloc(msg, len);
11133 11140 if (msg == NULL)
11134 11141 uu_die(gettext(
11135 11142 "Out of memory.\n"));
11136 11143 (void) scf_tmpl_strerror(err, msg, len,
11137 11144 flag);
11138 11145 }
11139 11146 (void) fprintf(stderr, "%s\n", msg);
11140 11147 }
11141 11148 if (msg != NULL)
11142 11149 free(msg);
11143 11150 }
11144 11151 if (errs != NULL)
11145 11152 scf_tmpl_errors_destroy(errs);
11146 11153
11147 11154 cleanup:
11148 11155 free(inst_fmri);
11149 11156 free(snapbuf);
11150 11157 }
11151 11158
11152 11159 static void
11153 11160 lscf_validate_file(const char *filename)
11154 11161 {
11155 11162 tmpl_errors_t *errs;
11156 11163
11157 11164 bundle_t *b = internal_bundle_new();
11158 11165 if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
11159 11166 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
11160 11167 tmpl_errors_print(stderr, errs, "");
11161 11168 semerr(gettext("Validation failed.\n"));
11162 11169 }
11163 11170 tmpl_errors_destroy(errs);
11164 11171 }
11165 11172 (void) internal_bundle_free(b);
11166 11173 }
11167 11174
11168 11175 /*
11169 11176 * validate [fmri|file]
11170 11177 */
11171 11178 void
11172 11179 lscf_validate(const char *arg)
11173 11180 {
11174 11181 const char *str;
11175 11182
11176 11183 if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
11177 11184 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
11178 11185 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
11179 11186 lscf_validate_file(str);
11180 11187 } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
11181 11188 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
11182 11189 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
11183 11190 lscf_validate_fmri(str);
11184 11191 } else if (access(arg, R_OK | F_OK) == 0) {
11185 11192 lscf_validate_file(arg);
11186 11193 } else {
11187 11194 lscf_validate_fmri(arg);
11188 11195 }
11189 11196 }
11190 11197
11191 11198 void
11192 11199 lscf_select(const char *fmri)
11193 11200 {
11194 11201 int ret, err;
11195 11202
11196 11203 lscf_prep_hndl();
11197 11204
11198 11205 if (cur_snap != NULL) {
11199 11206 struct snaplevel *elt;
11200 11207 char *buf;
11201 11208
11202 11209 /* Error unless name is that of the next level. */
11203 11210 elt = uu_list_next(cur_levels, cur_elt);
11204 11211 if (elt == NULL) {
11205 11212 semerr(gettext("No children.\n"));
11206 11213 return;
11207 11214 }
11208 11215
11209 11216 buf = safe_malloc(max_scf_name_len + 1);
11210 11217
11211 11218 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11212 11219 max_scf_name_len + 1) < 0)
11213 11220 scfdie();
11214 11221
11215 11222 if (strcmp(buf, fmri) != 0) {
11216 11223 semerr(gettext("No such child.\n"));
11217 11224 free(buf);
11218 11225 return;
11219 11226 }
11220 11227
11221 11228 free(buf);
11222 11229
11223 11230 cur_elt = elt;
11224 11231 cur_level = elt->sl;
11225 11232 return;
11226 11233 }
11227 11234
11228 11235 /*
11229 11236 * Special case for 'svc:', which takes the user to the scope level.
11230 11237 */
11231 11238 if (strcmp(fmri, "svc:") == 0) {
11232 11239 scf_instance_destroy(cur_inst);
11233 11240 scf_service_destroy(cur_svc);
11234 11241 cur_inst = NULL;
11235 11242 cur_svc = NULL;
11236 11243 return;
11237 11244 }
11238 11245
11239 11246 /*
11240 11247 * Special case for ':properties'. This appears as part of 'list' but
11241 11248 * can't be selected. Give a more helpful error message in this case.
11242 11249 */
11243 11250 if (strcmp(fmri, ":properties") == 0) {
11244 11251 semerr(gettext(":properties is not an entity. Try 'listprop' "
11245 11252 "to list properties.\n"));
11246 11253 return;
11247 11254 }
11248 11255
11249 11256 /*
11250 11257 * First try the argument as relative to the current selection.
11251 11258 */
11252 11259 if (cur_inst != NULL) {
11253 11260 /* EMPTY */;
11254 11261 } else if (cur_svc != NULL) {
11255 11262 if (select_inst(fmri) != 1)
11256 11263 return;
11257 11264 } else {
11258 11265 if (select_svc(fmri) != 1)
11259 11266 return;
11260 11267 }
11261 11268
11262 11269 err = 0;
11263 11270 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11264 11271 select_callback, NULL, &err, semerr)) != 0) {
11265 11272 semerr(gettext("Failed to walk instances: %s\n"),
11266 11273 scf_strerror(ret));
11267 11274 }
11268 11275 }
11269 11276
11270 11277 void
11271 11278 lscf_unselect(void)
11272 11279 {
11273 11280 lscf_prep_hndl();
11274 11281
11275 11282 if (cur_snap != NULL) {
11276 11283 struct snaplevel *elt;
11277 11284
11278 11285 elt = uu_list_prev(cur_levels, cur_elt);
11279 11286 if (elt == NULL) {
11280 11287 semerr(gettext("No parent levels.\n"));
11281 11288 } else {
11282 11289 cur_elt = elt;
11283 11290 cur_level = elt->sl;
11284 11291 }
11285 11292 } else if (cur_inst != NULL) {
11286 11293 scf_instance_destroy(cur_inst);
11287 11294 cur_inst = NULL;
11288 11295 } else if (cur_svc != NULL) {
11289 11296 scf_service_destroy(cur_svc);
11290 11297 cur_svc = NULL;
11291 11298 } else {
11292 11299 semerr(gettext("Cannot unselect at scope level.\n"));
11293 11300 }
11294 11301 }
11295 11302
11296 11303 /*
11297 11304 * Return the FMRI of the current selection, for the prompt.
11298 11305 */
11299 11306 void
11300 11307 lscf_get_selection_str(char *buf, size_t bufsz)
11301 11308 {
11302 11309 char *cp;
11303 11310 ssize_t fmrilen, szret;
11304 11311 boolean_t deleted = B_FALSE;
11305 11312
11306 11313 if (g_hndl == NULL) {
11307 11314 (void) strlcpy(buf, "svc:", bufsz);
11308 11315 return;
11309 11316 }
11310 11317
11311 11318 if (cur_level != NULL) {
11312 11319 assert(cur_snap != NULL);
11313 11320
11314 11321 /* [ snapshot ] FMRI [: instance ] */
11315 11322 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11316 11323 + 2 + max_scf_name_len + 1 + 1);
11317 11324
11318 11325 buf[0] = '[';
11319 11326
11320 11327 szret = scf_snapshot_get_name(cur_snap, buf + 1,
11321 11328 max_scf_name_len + 1);
11322 11329 if (szret < 0) {
11323 11330 if (scf_error() != SCF_ERROR_DELETED)
11324 11331 scfdie();
11325 11332
11326 11333 goto snap_deleted;
11327 11334 }
11328 11335
11329 11336 (void) strcat(buf, "]svc:/");
11330 11337
11331 11338 cp = strchr(buf, '\0');
11332 11339
11333 11340 szret = scf_snaplevel_get_service_name(cur_level, cp,
11334 11341 max_scf_name_len + 1);
11335 11342 if (szret < 0) {
11336 11343 if (scf_error() != SCF_ERROR_DELETED)
11337 11344 scfdie();
11338 11345
11339 11346 goto snap_deleted;
11340 11347 }
11341 11348
11342 11349 cp = strchr(cp, '\0');
11343 11350
11344 11351 if (snaplevel_is_instance(cur_level)) {
11345 11352 *cp++ = ':';
11346 11353
11347 11354 if (scf_snaplevel_get_instance_name(cur_level, cp,
11348 11355 max_scf_name_len + 1) < 0) {
11349 11356 if (scf_error() != SCF_ERROR_DELETED)
11350 11357 scfdie();
11351 11358
11352 11359 goto snap_deleted;
11353 11360 }
11354 11361 } else {
11355 11362 *cp++ = '[';
11356 11363 *cp++ = ':';
11357 11364
11358 11365 if (scf_instance_get_name(cur_inst, cp,
11359 11366 max_scf_name_len + 1) < 0) {
11360 11367 if (scf_error() != SCF_ERROR_DELETED)
11361 11368 scfdie();
11362 11369
11363 11370 goto snap_deleted;
11364 11371 }
11365 11372
11366 11373 (void) strcat(buf, "]");
11367 11374 }
11368 11375
11369 11376 return;
11370 11377
11371 11378 snap_deleted:
11372 11379 deleted = B_TRUE;
11373 11380 free(buf);
11374 11381 unselect_cursnap();
11375 11382 }
11376 11383
11377 11384 assert(cur_snap == NULL);
11378 11385
11379 11386 if (cur_inst != NULL) {
11380 11387 assert(cur_svc != NULL);
11381 11388 assert(cur_scope != NULL);
11382 11389
11383 11390 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11384 11391 if (fmrilen >= 0) {
11385 11392 assert(fmrilen < bufsz);
11386 11393 if (deleted)
11387 11394 warn(emsg_deleted);
11388 11395 return;
11389 11396 }
11390 11397
11391 11398 if (scf_error() != SCF_ERROR_DELETED)
11392 11399 scfdie();
11393 11400
11394 11401 deleted = B_TRUE;
11395 11402
11396 11403 scf_instance_destroy(cur_inst);
11397 11404 cur_inst = NULL;
11398 11405 }
11399 11406
11400 11407 if (cur_svc != NULL) {
11401 11408 assert(cur_scope != NULL);
11402 11409
11403 11410 szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11404 11411 if (szret >= 0) {
11405 11412 assert(szret < bufsz);
11406 11413 if (deleted)
11407 11414 warn(emsg_deleted);
11408 11415 return;
11409 11416 }
11410 11417
11411 11418 if (scf_error() != SCF_ERROR_DELETED)
11412 11419 scfdie();
11413 11420
11414 11421 deleted = B_TRUE;
11415 11422 scf_service_destroy(cur_svc);
11416 11423 cur_svc = NULL;
11417 11424 }
11418 11425
11419 11426 assert(cur_scope != NULL);
11420 11427 fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11421 11428
11422 11429 if (fmrilen < 0)
11423 11430 scfdie();
11424 11431
11425 11432 assert(fmrilen < bufsz);
11426 11433 if (deleted)
11427 11434 warn(emsg_deleted);
11428 11435 }
11429 11436
11430 11437 /*
11431 11438 * Entity listing. Entities and colon namespaces (e.g., :properties and
11432 11439 * :statistics) are listed for the current selection.
11433 11440 */
11434 11441 void
11435 11442 lscf_list(const char *pattern)
11436 11443 {
11437 11444 scf_iter_t *iter;
11438 11445 char *buf;
11439 11446 int ret;
11440 11447
11441 11448 lscf_prep_hndl();
11442 11449
11443 11450 if (cur_level != NULL) {
11444 11451 struct snaplevel *elt;
11445 11452
11446 11453 (void) fputs(COLON_NAMESPACES, stdout);
11447 11454
11448 11455 elt = uu_list_next(cur_levels, cur_elt);
11449 11456 if (elt == NULL)
11450 11457 return;
11451 11458
11452 11459 /*
11453 11460 * For now, we know that the next level is an instance. But
11454 11461 * if we ever have multiple scopes, this could be complicated.
11455 11462 */
11456 11463 buf = safe_malloc(max_scf_name_len + 1);
11457 11464 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11458 11465 max_scf_name_len + 1) >= 0) {
11459 11466 (void) puts(buf);
11460 11467 } else {
11461 11468 if (scf_error() != SCF_ERROR_DELETED)
11462 11469 scfdie();
11463 11470 }
11464 11471
11465 11472 free(buf);
11466 11473
11467 11474 return;
11468 11475 }
11469 11476
11470 11477 if (cur_inst != NULL) {
11471 11478 (void) fputs(COLON_NAMESPACES, stdout);
11472 11479 return;
11473 11480 }
11474 11481
11475 11482 iter = scf_iter_create(g_hndl);
11476 11483 if (iter == NULL)
11477 11484 scfdie();
11478 11485
11479 11486 buf = safe_malloc(max_scf_name_len + 1);
11480 11487
11481 11488 if (cur_svc != NULL) {
11482 11489 /* List the instances in this service. */
11483 11490 scf_instance_t *inst;
11484 11491
11485 11492 inst = scf_instance_create(g_hndl);
11486 11493 if (inst == NULL)
11487 11494 scfdie();
11488 11495
11489 11496 if (scf_iter_service_instances(iter, cur_svc) == 0) {
11490 11497 safe_printf(COLON_NAMESPACES);
11491 11498
11492 11499 for (;;) {
11493 11500 ret = scf_iter_next_instance(iter, inst);
11494 11501 if (ret == 0)
11495 11502 break;
11496 11503 if (ret != 1) {
11497 11504 if (scf_error() != SCF_ERROR_DELETED)
11498 11505 scfdie();
11499 11506
11500 11507 break;
11501 11508 }
11502 11509
11503 11510 if (scf_instance_get_name(inst, buf,
11504 11511 max_scf_name_len + 1) >= 0) {
11505 11512 if (pattern == NULL ||
11506 11513 fnmatch(pattern, buf, 0) == 0)
11507 11514 (void) puts(buf);
11508 11515 } else {
11509 11516 if (scf_error() != SCF_ERROR_DELETED)
11510 11517 scfdie();
11511 11518 }
11512 11519 }
11513 11520 } else {
11514 11521 if (scf_error() != SCF_ERROR_DELETED)
11515 11522 scfdie();
11516 11523 }
11517 11524
11518 11525 scf_instance_destroy(inst);
11519 11526 } else {
11520 11527 /* List the services in this scope. */
11521 11528 scf_service_t *svc;
11522 11529
11523 11530 assert(cur_scope != NULL);
11524 11531
11525 11532 svc = scf_service_create(g_hndl);
11526 11533 if (svc == NULL)
11527 11534 scfdie();
11528 11535
11529 11536 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11530 11537 scfdie();
11531 11538
11532 11539 for (;;) {
11533 11540 ret = scf_iter_next_service(iter, svc);
11534 11541 if (ret == 0)
11535 11542 break;
11536 11543 if (ret != 1)
11537 11544 scfdie();
11538 11545
11539 11546 if (scf_service_get_name(svc, buf,
11540 11547 max_scf_name_len + 1) >= 0) {
11541 11548 if (pattern == NULL ||
11542 11549 fnmatch(pattern, buf, 0) == 0)
11543 11550 safe_printf("%s\n", buf);
11544 11551 } else {
11545 11552 if (scf_error() != SCF_ERROR_DELETED)
11546 11553 scfdie();
11547 11554 }
11548 11555 }
11549 11556
11550 11557 scf_service_destroy(svc);
11551 11558 }
11552 11559
11553 11560 free(buf);
11554 11561 scf_iter_destroy(iter);
11555 11562 }
11556 11563
11557 11564 /*
11558 11565 * Entity addition. Creates an empty entity in the current selection.
11559 11566 */
11560 11567 void
11561 11568 lscf_add(const char *name)
11562 11569 {
11563 11570 lscf_prep_hndl();
11564 11571
11565 11572 if (cur_snap != NULL) {
11566 11573 semerr(emsg_cant_modify_snapshots);
11567 11574 } else if (cur_inst != NULL) {
11568 11575 semerr(gettext("Cannot add entities to an instance.\n"));
11569 11576 } else if (cur_svc != NULL) {
11570 11577
11571 11578 if (scf_service_add_instance(cur_svc, name, NULL) !=
11572 11579 SCF_SUCCESS) {
11573 11580 switch (scf_error()) {
11574 11581 case SCF_ERROR_INVALID_ARGUMENT:
11575 11582 semerr(gettext("Invalid name.\n"));
11576 11583 break;
11577 11584
11578 11585 case SCF_ERROR_EXISTS:
11579 11586 semerr(gettext("Instance already exists.\n"));
11580 11587 break;
11581 11588
11582 11589 case SCF_ERROR_PERMISSION_DENIED:
11583 11590 semerr(emsg_permission_denied);
11584 11591 break;
11585 11592
11586 11593 default:
11587 11594 scfdie();
11588 11595 }
11589 11596 }
11590 11597 } else {
11591 11598 assert(cur_scope != NULL);
11592 11599
11593 11600 if (scf_scope_add_service(cur_scope, name, NULL) !=
11594 11601 SCF_SUCCESS) {
11595 11602 switch (scf_error()) {
11596 11603 case SCF_ERROR_INVALID_ARGUMENT:
11597 11604 semerr(gettext("Invalid name.\n"));
11598 11605 break;
11599 11606
11600 11607 case SCF_ERROR_EXISTS:
11601 11608 semerr(gettext("Service already exists.\n"));
11602 11609 break;
11603 11610
11604 11611 case SCF_ERROR_PERMISSION_DENIED:
11605 11612 semerr(emsg_permission_denied);
11606 11613 break;
11607 11614
11608 11615 case SCF_ERROR_BACKEND_READONLY:
11609 11616 semerr(emsg_read_only);
11610 11617 break;
11611 11618
11612 11619 default:
11613 11620 scfdie();
11614 11621 }
11615 11622 }
11616 11623 }
11617 11624 }
11618 11625
11619 11626 /* return 1 if the entity has no persistent pgs, else return 0 */
11620 11627 static int
11621 11628 entity_has_no_pgs(void *ent, int isservice)
11622 11629 {
11623 11630 scf_iter_t *iter = NULL;
11624 11631 scf_propertygroup_t *pg = NULL;
11625 11632 uint32_t flags;
11626 11633 int err;
11627 11634 int ret = 1;
11628 11635
11629 11636 if ((iter = scf_iter_create(g_hndl)) == NULL ||
11630 11637 (pg = scf_pg_create(g_hndl)) == NULL)
11631 11638 scfdie();
11632 11639
11633 11640 if (isservice) {
11634 11641 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11635 11642 scfdie();
11636 11643 } else {
11637 11644 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11638 11645 scfdie();
11639 11646 }
11640 11647
11641 11648 while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11642 11649 if (scf_pg_get_flags(pg, &flags) != 0)
11643 11650 scfdie();
11644 11651
11645 11652 /* skip nonpersistent pgs */
11646 11653 if (flags & SCF_PG_FLAG_NONPERSISTENT)
11647 11654 continue;
11648 11655
11649 11656 ret = 0;
11650 11657 break;
11651 11658 }
11652 11659
11653 11660 if (err == -1)
11654 11661 scfdie();
11655 11662
11656 11663 scf_pg_destroy(pg);
11657 11664 scf_iter_destroy(iter);
11658 11665
11659 11666 return (ret);
11660 11667 }
11661 11668
11662 11669 /* return 1 if the service has no instances, else return 0 */
11663 11670 static int
11664 11671 svc_has_no_insts(scf_service_t *svc)
11665 11672 {
11666 11673 scf_instance_t *inst;
11667 11674 scf_iter_t *iter;
11668 11675 int r;
11669 11676 int ret = 1;
11670 11677
11671 11678 if ((inst = scf_instance_create(g_hndl)) == NULL ||
11672 11679 (iter = scf_iter_create(g_hndl)) == NULL)
11673 11680 scfdie();
11674 11681
11675 11682 if (scf_iter_service_instances(iter, svc) != 0)
11676 11683 scfdie();
11677 11684
11678 11685 r = scf_iter_next_instance(iter, inst);
11679 11686 if (r == 1) {
11680 11687 ret = 0;
11681 11688 } else if (r == 0) {
11682 11689 ret = 1;
11683 11690 } else if (r == -1) {
11684 11691 scfdie();
11685 11692 } else {
11686 11693 bad_error("scf_iter_next_instance", r);
11687 11694 }
11688 11695
11689 11696 scf_iter_destroy(iter);
11690 11697 scf_instance_destroy(inst);
11691 11698
11692 11699 return (ret);
11693 11700 }
11694 11701
11695 11702 /*
11696 11703 * Entity deletion.
11697 11704 */
11698 11705
11699 11706 /*
11700 11707 * Delete the property group <fmri>/:properties/<name>. Returns
11701 11708 * SCF_ERROR_NONE on success (or if the entity is not found),
11702 11709 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
11703 11710 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
11704 11711 * denied.
11705 11712 */
11706 11713 static scf_error_t
11707 11714 delete_dependency_pg(const char *fmri, const char *name)
11708 11715 {
11709 11716 void *entity = NULL;
11710 11717 int isservice;
11711 11718 scf_propertygroup_t *pg = NULL;
11712 11719 scf_error_t result;
11713 11720 char *pgty;
11714 11721 scf_service_t *svc = NULL;
11715 11722 scf_instance_t *inst = NULL;
11716 11723 scf_iter_t *iter = NULL;
11717 11724 char *name_buf = NULL;
11718 11725
11719 11726 result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
11720 11727 switch (result) {
11721 11728 case SCF_ERROR_NONE:
11722 11729 break;
11723 11730
11724 11731 case SCF_ERROR_NO_MEMORY:
11725 11732 uu_die(gettext("Out of memory.\n"));
11726 11733 /* NOTREACHED */
11727 11734
11728 11735 case SCF_ERROR_INVALID_ARGUMENT:
11729 11736 case SCF_ERROR_CONSTRAINT_VIOLATED:
11730 11737 return (SCF_ERROR_INVALID_ARGUMENT);
11731 11738
11732 11739 case SCF_ERROR_NOT_FOUND:
11733 11740 result = SCF_ERROR_NONE;
11734 11741 goto out;
11735 11742
11736 11743 default:
11737 11744 bad_error("fmri_to_entity", result);
11738 11745 }
11739 11746
11740 11747 pg = scf_pg_create(g_hndl);
11741 11748 if (pg == NULL)
11742 11749 scfdie();
11743 11750
11744 11751 if (entity_get_pg(entity, isservice, name, pg) != 0) {
11745 11752 if (scf_error() != SCF_ERROR_NOT_FOUND)
11746 11753 scfdie();
11747 11754
11748 11755 result = SCF_ERROR_NONE;
11749 11756 goto out;
11750 11757 }
11751 11758
11752 11759 pgty = safe_malloc(max_scf_pg_type_len + 1);
11753 11760
11754 11761 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
11755 11762 scfdie();
11756 11763
11757 11764 if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
11758 11765 result = SCF_ERROR_TYPE_MISMATCH;
11759 11766 free(pgty);
11760 11767 goto out;
11761 11768 }
11762 11769
11763 11770 free(pgty);
11764 11771
11765 11772 if (scf_pg_delete(pg) != 0) {
11766 11773 result = scf_error();
11767 11774 if (result != SCF_ERROR_PERMISSION_DENIED)
11768 11775 scfdie();
11769 11776 goto out;
11770 11777 }
11771 11778
11772 11779 /*
11773 11780 * We have to handle the case where we've just deleted the last
11774 11781 * property group of a "dummy" entity (instance or service).
11775 11782 * A "dummy" entity is an entity only present to hold an
11776 11783 * external dependency.
11777 11784 * So, in the case we deleted the last property group then we
11778 11785 * can also delete the entity. If the entity is an instance then
11779 11786 * we must verify if this was the last instance for the service
11780 11787 * and if it is, we can also delete the service if it doesn't
11781 11788 * have any property group either.
11782 11789 */
11783 11790
11784 11791 result = SCF_ERROR_NONE;
11785 11792
11786 11793 if (isservice) {
11787 11794 svc = (scf_service_t *)entity;
11788 11795
11789 11796 if ((inst = scf_instance_create(g_hndl)) == NULL ||
11790 11797 (iter = scf_iter_create(g_hndl)) == NULL)
11791 11798 scfdie();
11792 11799
11793 11800 name_buf = safe_malloc(max_scf_name_len + 1);
11794 11801 } else {
11795 11802 inst = (scf_instance_t *)entity;
11796 11803 }
11797 11804
11798 11805 /*
11799 11806 * If the entity is an instance and we've just deleted its last
11800 11807 * property group then we should delete it.
11801 11808 */
11802 11809 if (!isservice && entity_has_no_pgs(entity, isservice)) {
11803 11810 /* find the service before deleting the inst. - needed later */
11804 11811 if ((svc = scf_service_create(g_hndl)) == NULL)
11805 11812 scfdie();
11806 11813
11807 11814 if (scf_instance_get_parent(inst, svc) != 0)
11808 11815 scfdie();
11809 11816
11810 11817 /* delete the instance */
11811 11818 if (scf_instance_delete(inst) != 0) {
11812 11819 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11813 11820 scfdie();
11814 11821
11815 11822 result = SCF_ERROR_PERMISSION_DENIED;
11816 11823 goto out;
11817 11824 }
11818 11825 /* no need to refresh the instance */
11819 11826 inst = NULL;
11820 11827 }
11821 11828
11822 11829 /*
11823 11830 * If the service has no more instances and pgs or we just deleted the
11824 11831 * last instance and the service doesn't have anymore propery groups
11825 11832 * then the service should be deleted.
11826 11833 */
11827 11834 if (svc != NULL &&
11828 11835 svc_has_no_insts(svc) &&
11829 11836 entity_has_no_pgs((void *)svc, 1)) {
11830 11837 if (scf_service_delete(svc) == 0) {
11831 11838 if (isservice) {
11832 11839 /* no need to refresh the service */
11833 11840 svc = NULL;
11834 11841 }
11835 11842
11836 11843 goto out;
11837 11844 }
11838 11845
11839 11846 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11840 11847 scfdie();
11841 11848
11842 11849 result = SCF_ERROR_PERMISSION_DENIED;
11843 11850 }
11844 11851
11845 11852 /* if the entity has not been deleted, refresh it */
11846 11853 if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
11847 11854 (void) refresh_entity(isservice, entity, fmri, inst, iter,
11848 11855 name_buf);
11849 11856 }
11850 11857
11851 11858 out:
11852 11859 if (isservice && (inst != NULL && iter != NULL)) {
11853 11860 free(name_buf);
11854 11861 scf_iter_destroy(iter);
11855 11862 scf_instance_destroy(inst);
11856 11863 }
11857 11864
11858 11865 if (!isservice && svc != NULL) {
11859 11866 scf_service_destroy(svc);
11860 11867 }
11861 11868
11862 11869 scf_pg_destroy(pg);
11863 11870 if (entity != NULL)
11864 11871 entity_destroy(entity, isservice);
11865 11872
11866 11873 return (result);
11867 11874 }
11868 11875
11869 11876 static int
11870 11877 delete_dependents(scf_propertygroup_t *pg)
11871 11878 {
11872 11879 char *pgty, *name, *fmri;
11873 11880 scf_property_t *prop;
11874 11881 scf_value_t *val;
11875 11882 scf_iter_t *iter;
11876 11883 int r;
11877 11884 scf_error_t err;
11878 11885
11879 11886 /* Verify that the pg has the correct type. */
11880 11887 pgty = safe_malloc(max_scf_pg_type_len + 1);
11881 11888 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
11882 11889 scfdie();
11883 11890
11884 11891 if (strcmp(pgty, scf_group_framework) != 0) {
11885 11892 if (g_verbose) {
11886 11893 fmri = safe_malloc(max_scf_fmri_len + 1);
11887 11894 if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
11888 11895 scfdie();
11889 11896
11890 11897 warn(gettext("Property group %s is not of expected "
11891 11898 "type %s.\n"), fmri, scf_group_framework);
11892 11899
11893 11900 free(fmri);
11894 11901 }
11895 11902
11896 11903 free(pgty);
11897 11904 return (-1);
11898 11905 }
11899 11906
11900 11907 free(pgty);
11901 11908
11902 11909 /* map delete_dependency_pg onto the properties. */
11903 11910 if ((prop = scf_property_create(g_hndl)) == NULL ||
11904 11911 (val = scf_value_create(g_hndl)) == NULL ||
11905 11912 (iter = scf_iter_create(g_hndl)) == NULL)
11906 11913 scfdie();
11907 11914
11908 11915 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
11909 11916 scfdie();
11910 11917
11911 11918 name = safe_malloc(max_scf_name_len + 1);
11912 11919 fmri = safe_malloc(max_scf_fmri_len + 2);
11913 11920
11914 11921 while ((r = scf_iter_next_property(iter, prop)) == 1) {
11915 11922 scf_type_t ty;
11916 11923
11917 11924 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
11918 11925 scfdie();
11919 11926
11920 11927 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
11921 11928 scfdie();
11922 11929
11923 11930 if ((ty != SCF_TYPE_ASTRING &&
11924 11931 prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
11925 11932 prop_get_val(prop, val) != 0)
11926 11933 continue;
11927 11934
11928 11935 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
11929 11936 scfdie();
11930 11937
11931 11938 err = delete_dependency_pg(fmri, name);
11932 11939 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
11933 11940 if (scf_property_to_fmri(prop, fmri,
11934 11941 max_scf_fmri_len + 2) < 0)
11935 11942 scfdie();
11936 11943
11937 11944 warn(gettext("Value of %s is not a valid FMRI.\n"),
11938 11945 fmri);
11939 11946 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
11940 11947 warn(gettext("Property group \"%s\" of entity \"%s\" "
11941 11948 "does not have dependency type.\n"), name, fmri);
11942 11949 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
11943 11950 warn(gettext("Could not delete property group \"%s\" "
11944 11951 "of entity \"%s\" (permission denied).\n"), name,
11945 11952 fmri);
11946 11953 }
11947 11954 }
11948 11955 if (r == -1)
11949 11956 scfdie();
11950 11957
11951 11958 scf_value_destroy(val);
11952 11959 scf_property_destroy(prop);
11953 11960
11954 11961 return (0);
11955 11962 }
11956 11963
11957 11964 /*
11958 11965 * Returns 1 if the instance may be running, and 0 otherwise.
11959 11966 */
11960 11967 static int
11961 11968 inst_is_running(scf_instance_t *inst)
11962 11969 {
11963 11970 scf_propertygroup_t *pg;
11964 11971 scf_property_t *prop;
11965 11972 scf_value_t *val;
11966 11973 char buf[MAX_SCF_STATE_STRING_SZ];
11967 11974 int ret = 0;
11968 11975 ssize_t szret;
11969 11976
11970 11977 if ((pg = scf_pg_create(g_hndl)) == NULL ||
11971 11978 (prop = scf_property_create(g_hndl)) == NULL ||
11972 11979 (val = scf_value_create(g_hndl)) == NULL)
11973 11980 scfdie();
11974 11981
11975 11982 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
11976 11983 if (scf_error() != SCF_ERROR_NOT_FOUND)
11977 11984 scfdie();
11978 11985 goto out;
11979 11986 }
11980 11987
11981 11988 if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
11982 11989 prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
11983 11990 prop_get_val(prop, val) != 0)
11984 11991 goto out;
11985 11992
11986 11993 szret = scf_value_get_astring(val, buf, sizeof (buf));
11987 11994 assert(szret >= 0);
11988 11995
11989 11996 ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
11990 11997 strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
11991 11998
11992 11999 out:
11993 12000 scf_value_destroy(val);
11994 12001 scf_property_destroy(prop);
11995 12002 scf_pg_destroy(pg);
11996 12003 return (ret);
11997 12004 }
11998 12005
11999 12006 static uint8_t
12000 12007 pg_is_external_dependency(scf_propertygroup_t *pg)
12001 12008 {
12002 12009 char *type;
12003 12010 scf_value_t *val;
12004 12011 scf_property_t *prop;
12005 12012 uint8_t b = B_FALSE;
12006 12013
12007 12014 type = safe_malloc(max_scf_pg_type_len + 1);
12008 12015
12009 12016 if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
12010 12017 scfdie();
12011 12018
12012 12019 if ((prop = scf_property_create(g_hndl)) == NULL ||
12013 12020 (val = scf_value_create(g_hndl)) == NULL)
12014 12021 scfdie();
12015 12022
12016 12023 if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
12017 12024 if (pg_get_prop(pg, scf_property_external, prop) == 0) {
12018 12025 if (scf_property_get_value(prop, val) != 0)
12019 12026 scfdie();
12020 12027 if (scf_value_get_boolean(val, &b) != 0)
12021 12028 scfdie();
12022 12029 }
12023 12030 }
12024 12031
12025 12032 free(type);
12026 12033 (void) scf_value_destroy(val);
12027 12034 (void) scf_property_destroy(prop);
12028 12035
12029 12036 return (b);
12030 12037 }
12031 12038
12032 12039 #define DELETE_FAILURE -1
12033 12040 #define DELETE_SUCCESS_NOEXTDEPS 0
12034 12041 #define DELETE_SUCCESS_EXTDEPS 1
12035 12042
12036 12043 /*
12037 12044 * lscf_instance_delete() deletes an instance. Before calling
12038 12045 * scf_instance_delete(), though, we make sure the instance isn't
12039 12046 * running and delete dependencies in other entities which the instance
12040 12047 * declared as "dependents". If there are dependencies which were
12041 12048 * created for other entities, then instead of deleting the instance we
12042 12049 * make it "empty" by deleting all other property groups and all
12043 12050 * snapshots.
12044 12051 *
12045 12052 * lscf_instance_delete() verifies that there is no external dependency pgs
12046 12053 * before suppressing the instance. If there is, then we must not remove them
12047 12054 * now in case the instance is re-created otherwise the dependencies would be
12048 12055 * lost. The external dependency pgs will be removed if the dependencies are
12049 12056 * removed.
12050 12057 *
12051 12058 * Returns:
12052 12059 * DELETE_FAILURE on failure
12053 12060 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12054 12061 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12055 12062 */
12056 12063 static int
12057 12064 lscf_instance_delete(scf_instance_t *inst, int force)
12058 12065 {
12059 12066 scf_propertygroup_t *pg;
12060 12067 scf_snapshot_t *snap;
12061 12068 scf_iter_t *iter;
12062 12069 int err;
12063 12070 int external = 0;
12064 12071
12065 12072 /* If we're not forcing and the instance is running, refuse. */
12066 12073 if (!force && inst_is_running(inst)) {
12067 12074 char *fmri;
12068 12075
12069 12076 fmri = safe_malloc(max_scf_fmri_len + 1);
12070 12077
12071 12078 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
12072 12079 scfdie();
12073 12080
12074 12081 semerr(gettext("Instance %s may be running. "
12075 12082 "Use delete -f if it is not.\n"), fmri);
12076 12083
12077 12084 free(fmri);
12078 12085 return (DELETE_FAILURE);
12079 12086 }
12080 12087
12081 12088 pg = scf_pg_create(g_hndl);
12082 12089 if (pg == NULL)
12083 12090 scfdie();
12084 12091
12085 12092 if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
12086 12093 (void) delete_dependents(pg);
12087 12094 else if (scf_error() != SCF_ERROR_NOT_FOUND)
12088 12095 scfdie();
12089 12096
12090 12097 scf_pg_destroy(pg);
12091 12098
12092 12099 /*
12093 12100 * If the instance has some external dependencies then we must
12094 12101 * keep them in case the instance is reimported otherwise the
12095 12102 * dependencies would be lost on reimport.
12096 12103 */
12097 12104 if ((iter = scf_iter_create(g_hndl)) == NULL ||
12098 12105 (pg = scf_pg_create(g_hndl)) == NULL)
12099 12106 scfdie();
12100 12107
12101 12108 if (scf_iter_instance_pgs(iter, inst) < 0)
12102 12109 scfdie();
12103 12110
12104 12111 while ((err = scf_iter_next_pg(iter, pg)) == 1) {
12105 12112 if (pg_is_external_dependency(pg)) {
12106 12113 external = 1;
12107 12114 continue;
12108 12115 }
12109 12116
12110 12117 if (scf_pg_delete(pg) != 0) {
12111 12118 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12112 12119 scfdie();
12113 12120 else {
12114 12121 semerr(emsg_permission_denied);
12115 12122
12116 12123 (void) scf_iter_destroy(iter);
12117 12124 (void) scf_pg_destroy(pg);
12118 12125 return (DELETE_FAILURE);
12119 12126 }
12120 12127 }
12121 12128 }
12122 12129
12123 12130 if (err == -1)
12124 12131 scfdie();
12125 12132
12126 12133 (void) scf_iter_destroy(iter);
12127 12134 (void) scf_pg_destroy(pg);
12128 12135
12129 12136 if (external) {
12130 12137 /*
12131 12138 * All the pgs have been deleted for the instance except
12132 12139 * the ones holding the external dependencies.
12133 12140 * For the job to be complete, we must also delete the
12134 12141 * snapshots associated with the instance.
12135 12142 */
12136 12143 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
12137 12144 NULL)
12138 12145 scfdie();
12139 12146 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
12140 12147 scfdie();
12141 12148
12142 12149 if (scf_iter_instance_snapshots(iter, inst) == -1)
12143 12150 scfdie();
12144 12151
12145 12152 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
12146 12153 if (_scf_snapshot_delete(snap) != 0) {
12147 12154 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12148 12155 scfdie();
12149 12156
12150 12157 semerr(emsg_permission_denied);
12151 12158
12152 12159 (void) scf_iter_destroy(iter);
12153 12160 (void) scf_snapshot_destroy(snap);
12154 12161 return (DELETE_FAILURE);
12155 12162 }
12156 12163 }
12157 12164
12158 12165 if (err == -1)
12159 12166 scfdie();
12160 12167
12161 12168 (void) scf_iter_destroy(iter);
12162 12169 (void) scf_snapshot_destroy(snap);
12163 12170 return (DELETE_SUCCESS_EXTDEPS);
12164 12171 }
12165 12172
12166 12173 if (scf_instance_delete(inst) != 0) {
12167 12174 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12168 12175 scfdie();
12169 12176
12170 12177 semerr(emsg_permission_denied);
12171 12178
12172 12179 return (DELETE_FAILURE);
12173 12180 }
12174 12181
12175 12182 return (DELETE_SUCCESS_NOEXTDEPS);
12176 12183 }
12177 12184
12178 12185 /*
12179 12186 * lscf_service_delete() deletes a service. Before calling
12180 12187 * scf_service_delete(), though, we call lscf_instance_delete() for
12181 12188 * each of the instances and delete dependencies in other entities
12182 12189 * which were created as "dependents" of this service. If there are
12183 12190 * dependencies which were created for other entities, then we delete
12184 12191 * all other property groups in the service and leave it as "empty".
12185 12192 *
12186 12193 * lscf_service_delete() verifies that there is no external dependency
12187 12194 * pgs at the instance & service level before suppressing the service.
12188 12195 * If there is, then we must not remove them now in case the service
12189 12196 * is re-imported otherwise the dependencies would be lost. The external
12190 12197 * dependency pgs will be removed if the dependencies are removed.
12191 12198 *
12192 12199 * Returns:
12193 12200 * DELETE_FAILURE on failure
12194 12201 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12195 12202 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12196 12203 */
12197 12204 static int
12198 12205 lscf_service_delete(scf_service_t *svc, int force)
12199 12206 {
12200 12207 int r;
12201 12208 scf_instance_t *inst;
12202 12209 scf_propertygroup_t *pg;
12203 12210 scf_iter_t *iter;
12204 12211 int ret;
12205 12212 int external = 0;
12206 12213
12207 12214 if ((inst = scf_instance_create(g_hndl)) == NULL ||
12208 12215 (pg = scf_pg_create(g_hndl)) == NULL ||
12209 12216 (iter = scf_iter_create(g_hndl)) == NULL)
12210 12217 scfdie();
12211 12218
12212 12219 if (scf_iter_service_instances(iter, svc) != 0)
12213 12220 scfdie();
12214 12221
12215 12222 for (r = scf_iter_next_instance(iter, inst);
12216 12223 r == 1;
12217 12224 r = scf_iter_next_instance(iter, inst)) {
12218 12225
12219 12226 ret = lscf_instance_delete(inst, force);
12220 12227 if (ret == DELETE_FAILURE) {
12221 12228 scf_iter_destroy(iter);
12222 12229 scf_pg_destroy(pg);
12223 12230 scf_instance_destroy(inst);
12224 12231 return (DELETE_FAILURE);
12225 12232 }
12226 12233
12227 12234 /*
12228 12235 * Record the fact that there is some external dependencies
12229 12236 * at the instance level.
12230 12237 */
12231 12238 if (ret == DELETE_SUCCESS_EXTDEPS)
12232 12239 external |= 1;
12233 12240 }
12234 12241
12235 12242 if (r != 0)
12236 12243 scfdie();
12237 12244
12238 12245 /* Delete dependency property groups in dependent services. */
12239 12246 if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12240 12247 (void) delete_dependents(pg);
12241 12248 else if (scf_error() != SCF_ERROR_NOT_FOUND)
12242 12249 scfdie();
12243 12250
12244 12251 scf_iter_destroy(iter);
12245 12252 scf_pg_destroy(pg);
12246 12253 scf_instance_destroy(inst);
12247 12254
12248 12255 /*
12249 12256 * If the service has some external dependencies then we don't
12250 12257 * want to remove them in case the service is re-imported.
12251 12258 */
12252 12259 if ((pg = scf_pg_create(g_hndl)) == NULL ||
12253 12260 (iter = scf_iter_create(g_hndl)) == NULL)
12254 12261 scfdie();
12255 12262
12256 12263 if (scf_iter_service_pgs(iter, svc) < 0)
12257 12264 scfdie();
12258 12265
12259 12266 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12260 12267 if (pg_is_external_dependency(pg)) {
12261 12268 external |= 2;
12262 12269 continue;
12263 12270 }
12264 12271
12265 12272 if (scf_pg_delete(pg) != 0) {
12266 12273 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12267 12274 scfdie();
12268 12275 else {
12269 12276 semerr(emsg_permission_denied);
12270 12277
12271 12278 (void) scf_iter_destroy(iter);
12272 12279 (void) scf_pg_destroy(pg);
12273 12280 return (DELETE_FAILURE);
12274 12281 }
12275 12282 }
12276 12283 }
12277 12284
12278 12285 if (r == -1)
12279 12286 scfdie();
12280 12287
12281 12288 (void) scf_iter_destroy(iter);
12282 12289 (void) scf_pg_destroy(pg);
12283 12290
12284 12291 if (external != 0)
12285 12292 return (DELETE_SUCCESS_EXTDEPS);
12286 12293
12287 12294 if (scf_service_delete(svc) == 0)
12288 12295 return (DELETE_SUCCESS_NOEXTDEPS);
12289 12296
12290 12297 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12291 12298 scfdie();
12292 12299
12293 12300 semerr(emsg_permission_denied);
12294 12301 return (DELETE_FAILURE);
12295 12302 }
12296 12303
12297 12304 static int
12298 12305 delete_callback(void *data, scf_walkinfo_t *wip)
12299 12306 {
12300 12307 int force = (int)data;
12301 12308
12302 12309 if (wip->inst != NULL)
12303 12310 (void) lscf_instance_delete(wip->inst, force);
12304 12311 else
12305 12312 (void) lscf_service_delete(wip->svc, force);
12306 12313
12307 12314 return (0);
12308 12315 }
12309 12316
12310 12317 void
12311 12318 lscf_delete(const char *fmri, int force)
12312 12319 {
12313 12320 scf_service_t *svc;
12314 12321 scf_instance_t *inst;
12315 12322 int ret;
12316 12323
12317 12324 lscf_prep_hndl();
12318 12325
12319 12326 if (cur_snap != NULL) {
12320 12327 if (!snaplevel_is_instance(cur_level)) {
12321 12328 char *buf;
12322 12329
12323 12330 buf = safe_malloc(max_scf_name_len + 1);
12324 12331 if (scf_instance_get_name(cur_inst, buf,
12325 12332 max_scf_name_len + 1) >= 0) {
12326 12333 if (strcmp(buf, fmri) == 0) {
12327 12334 semerr(emsg_cant_modify_snapshots);
12328 12335 free(buf);
12329 12336 return;
12330 12337 }
12331 12338 } else if (scf_error() != SCF_ERROR_DELETED) {
12332 12339 scfdie();
12333 12340 }
12334 12341 free(buf);
12335 12342 }
12336 12343 } else if (cur_inst != NULL) {
12337 12344 /* EMPTY */;
12338 12345 } else if (cur_svc != NULL) {
12339 12346 inst = scf_instance_create(g_hndl);
12340 12347 if (inst == NULL)
12341 12348 scfdie();
12342 12349
12343 12350 if (scf_service_get_instance(cur_svc, fmri, inst) ==
12344 12351 SCF_SUCCESS) {
12345 12352 (void) lscf_instance_delete(inst, force);
12346 12353 scf_instance_destroy(inst);
12347 12354 return;
12348 12355 }
12349 12356
12350 12357 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12351 12358 scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12352 12359 scfdie();
12353 12360
12354 12361 scf_instance_destroy(inst);
12355 12362 } else {
12356 12363 assert(cur_scope != NULL);
12357 12364
12358 12365 svc = scf_service_create(g_hndl);
12359 12366 if (svc == NULL)
12360 12367 scfdie();
12361 12368
12362 12369 if (scf_scope_get_service(cur_scope, fmri, svc) ==
12363 12370 SCF_SUCCESS) {
12364 12371 (void) lscf_service_delete(svc, force);
12365 12372 scf_service_destroy(svc);
12366 12373 return;
12367 12374 }
12368 12375
12369 12376 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12370 12377 scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12371 12378 scfdie();
12372 12379
12373 12380 scf_service_destroy(svc);
12374 12381 }
12375 12382
12376 12383 /*
12377 12384 * Match FMRI to entity.
12378 12385 */
12379 12386 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12380 12387 delete_callback, (void *)force, NULL, semerr)) != 0) {
12381 12388 semerr(gettext("Failed to walk instances: %s\n"),
12382 12389 scf_strerror(ret));
12383 12390 }
12384 12391 }
12385 12392
12386 12393
12387 12394
12388 12395 /*
12389 12396 * :properties commands. These all end with "pg" or "prop" and generally
12390 12397 * operate on the currently selected entity.
12391 12398 */
12392 12399
12393 12400 /*
12394 12401 * Property listing. List the property groups, properties, their types and
12395 12402 * their values for the currently selected entity.
12396 12403 */
12397 12404 static void
12398 12405 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12399 12406 {
12400 12407 char *buf;
12401 12408 uint32_t flags;
12402 12409
12403 12410 buf = safe_malloc(max_scf_pg_type_len + 1);
12404 12411
12405 12412 if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12406 12413 scfdie();
12407 12414
12408 12415 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12409 12416 scfdie();
12410 12417
12411 12418 safe_printf("%-*s %s", namewidth, name, buf);
12412 12419
12413 12420 if (flags & SCF_PG_FLAG_NONPERSISTENT)
12414 12421 safe_printf("\tNONPERSISTENT");
12415 12422
12416 12423 safe_printf("\n");
12417 12424
12418 12425 free(buf);
12419 12426 }
12420 12427
12421 12428 static boolean_t
12422 12429 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12423 12430 {
12424 12431 if (scf_property_get_value(prop, val) == 0) {
12425 12432 return (B_FALSE);
12426 12433 } else {
12427 12434 switch (scf_error()) {
12428 12435 case SCF_ERROR_NOT_FOUND:
12429 12436 return (B_FALSE);
12430 12437 case SCF_ERROR_PERMISSION_DENIED:
12431 12438 case SCF_ERROR_CONSTRAINT_VIOLATED:
12432 12439 return (B_TRUE);
12433 12440 default:
12434 12441 scfdie();
12435 12442 /*NOTREACHED*/
12436 12443 }
12437 12444 }
12438 12445 }
12439 12446
12440 12447 static void
12441 12448 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12442 12449 {
12443 12450 scf_iter_t *iter;
12444 12451 scf_value_t *val;
12445 12452 const char *type;
12446 12453 int multiple_strings = 0;
12447 12454 int ret;
12448 12455
12449 12456 if ((iter = scf_iter_create(g_hndl)) == NULL ||
12450 12457 (val = scf_value_create(g_hndl)) == NULL)
12451 12458 scfdie();
12452 12459
12453 12460 type = prop_to_typestr(prop);
12454 12461 assert(type != NULL);
12455 12462
12456 12463 safe_printf("%-*s %-7s ", len, name, type);
12457 12464
12458 12465 if (prop_has_multiple_values(prop, val) &&
12459 12466 (scf_value_type(val) == SCF_TYPE_ASTRING ||
12460 12467 scf_value_type(val) == SCF_TYPE_USTRING))
12461 12468 multiple_strings = 1;
12462 12469
12463 12470 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12464 12471 scfdie();
12465 12472
12466 12473 while ((ret = scf_iter_next_value(iter, val)) == 1) {
12467 12474 char *buf;
12468 12475 ssize_t vlen, szret;
12469 12476
12470 12477 vlen = scf_value_get_as_string(val, NULL, 0);
12471 12478 if (vlen < 0)
12472 12479 scfdie();
12473 12480
12474 12481 buf = safe_malloc(vlen + 1);
12475 12482
12476 12483 szret = scf_value_get_as_string(val, buf, vlen + 1);
12477 12484 if (szret < 0)
12478 12485 scfdie();
12479 12486 assert(szret <= vlen);
12480 12487
12481 12488 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12482 12489 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12483 12490 safe_printf(" \"");
12484 12491 (void) quote_and_print(buf, stdout, 0);
12485 12492 (void) putchar('"');
12486 12493 if (ferror(stdout)) {
12487 12494 (void) putchar('\n');
12488 12495 uu_die(gettext("Error writing to stdout.\n"));
12489 12496 }
12490 12497 } else {
12491 12498 safe_printf(" %s", buf);
12492 12499 }
12493 12500
12494 12501 free(buf);
12495 12502 }
12496 12503 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12497 12504 scfdie();
12498 12505
12499 12506 if (putchar('\n') != '\n')
12500 12507 uu_die(gettext("Could not output newline"));
12501 12508 }
12502 12509
12503 12510 /*
12504 12511 * Outputs template property group info for the describe subcommand.
12505 12512 * If 'templates' == 2, verbose output is printed in the format expected
12506 12513 * for describe -v, which includes all templates fields. If pg is
12507 12514 * not NULL, we're describing the template data, not an existing property
12508 12515 * group, and formatting should be appropriate for describe -t.
12509 12516 */
12510 12517 static void
12511 12518 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12512 12519 {
12513 12520 char *buf;
12514 12521 uint8_t required;
12515 12522 scf_property_t *stability_prop;
12516 12523 scf_value_t *stability_val;
12517 12524
12518 12525 if (templates == 0)
12519 12526 return;
12520 12527
12521 12528 if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12522 12529 (stability_val = scf_value_create(g_hndl)) == NULL)
12523 12530 scfdie();
12524 12531
12525 12532 if (templates == 2 && pg != NULL) {
12526 12533 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12527 12534 stability_prop) == 0) {
12528 12535 if (prop_check_type(stability_prop,
12529 12536 SCF_TYPE_ASTRING) == 0 &&
12530 12537 prop_get_val(stability_prop, stability_val) == 0) {
12531 12538 char *stability;
12532 12539
12533 12540 stability = safe_malloc(max_scf_value_len + 1);
12534 12541
12535 12542 if (scf_value_get_astring(stability_val,
12536 12543 stability, max_scf_value_len + 1) == -1 &&
12537 12544 scf_error() != SCF_ERROR_NOT_FOUND)
12538 12545 scfdie();
12539 12546
12540 12547 safe_printf("%s%s: %s\n", TMPL_INDENT,
12541 12548 gettext("stability"), stability);
12542 12549
12543 12550 free(stability);
12544 12551 }
12545 12552 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
12546 12553 scfdie();
12547 12554 }
12548 12555
12549 12556 scf_property_destroy(stability_prop);
12550 12557 scf_value_destroy(stability_val);
12551 12558
12552 12559 if (pgt == NULL)
12553 12560 return;
12554 12561
12555 12562 if (pg == NULL || templates == 2) {
12556 12563 /* print type info only if scf_tmpl_pg_name succeeds */
12557 12564 if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12558 12565 if (pg != NULL)
12559 12566 safe_printf("%s", TMPL_INDENT);
12560 12567 safe_printf("%s: ", gettext("name"));
12561 12568 safe_printf("%s\n", buf);
12562 12569 free(buf);
12563 12570 }
12564 12571
12565 12572 /* print type info only if scf_tmpl_pg_type succeeds */
12566 12573 if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12567 12574 if (pg != NULL)
12568 12575 safe_printf("%s", TMPL_INDENT);
12569 12576 safe_printf("%s: ", gettext("type"));
12570 12577 safe_printf("%s\n", buf);
12571 12578 free(buf);
12572 12579 }
12573 12580 }
12574 12581
12575 12582 if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12576 12583 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12577 12584 required ? "true" : "false");
12578 12585
12579 12586 if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12580 12587 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12581 12588 buf);
12582 12589 free(buf);
12583 12590 }
12584 12591
12585 12592 if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12586 12593 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12587 12594 buf);
12588 12595 free(buf);
12589 12596 }
12590 12597
12591 12598 if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12592 12599 if (templates == 2)
12593 12600 safe_printf("%s%s: %s\n", TMPL_INDENT,
12594 12601 gettext("description"), buf);
12595 12602 else
12596 12603 safe_printf("%s%s\n", TMPL_INDENT, buf);
12597 12604 free(buf);
12598 12605 }
12599 12606
12600 12607 }
12601 12608
12602 12609 /*
12603 12610 * With as_value set to true, indent as appropriate for the value level.
12604 12611 * If false, indent to appropriate level for inclusion in constraint
12605 12612 * or choice printout.
12606 12613 */
12607 12614 static void
12608 12615 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12609 12616 int as_value)
12610 12617 {
12611 12618 char *buf;
12612 12619
12613 12620 if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12614 12621 if (as_value == 0)
12615 12622 safe_printf("%s", TMPL_CHOICE_INDENT);
12616 12623 else
12617 12624 safe_printf("%s", TMPL_INDENT);
12618 12625 safe_printf("%s: %s\n", gettext("value common name"), buf);
12619 12626 free(buf);
12620 12627 }
12621 12628
12622 12629 if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12623 12630 if (as_value == 0)
12624 12631 safe_printf("%s", TMPL_CHOICE_INDENT);
12625 12632 else
12626 12633 safe_printf("%s", TMPL_INDENT);
12627 12634 safe_printf("%s: %s\n", gettext("value description"), buf);
12628 12635 free(buf);
12629 12636 }
12630 12637 }
12631 12638
12632 12639 static void
12633 12640 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12634 12641 {
12635 12642 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12636 12643 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12637 12644 safe_printf("%s\n", val_buf);
12638 12645
12639 12646 print_template_value_details(prt, val_buf, 1);
12640 12647 }
12641 12648
12642 12649 static void
12643 12650 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12644 12651 {
12645 12652 int i, printed = 0;
12646 12653 scf_values_t values;
12647 12654 scf_count_ranges_t c_ranges;
12648 12655 scf_int_ranges_t i_ranges;
12649 12656
12650 12657 printed = 0;
12651 12658 i = 0;
12652 12659 if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12653 12660 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12654 12661 gettext("value constraints"));
12655 12662 printed++;
12656 12663 for (i = 0; i < values.value_count; ++i) {
12657 12664 safe_printf("%s%s: %s\n", TMPL_INDENT,
12658 12665 gettext("value name"), values.values_as_strings[i]);
12659 12666 if (verbose == 1)
12660 12667 print_template_value_details(prt,
12661 12668 values.values_as_strings[i], 0);
12662 12669 }
12663 12670
12664 12671 scf_values_destroy(&values);
12665 12672 }
12666 12673
12667 12674 if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12668 12675 if (printed++ == 0)
12669 12676 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12670 12677 gettext("value constraints"));
12671 12678 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12672 12679 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12673 12680 gettext("range"), c_ranges.scr_min[i],
12674 12681 c_ranges.scr_max[i]);
12675 12682 }
12676 12683 scf_count_ranges_destroy(&c_ranges);
12677 12684 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12678 12685 scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
12679 12686 if (printed++ == 0)
12680 12687 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12681 12688 gettext("value constraints"));
12682 12689 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12683 12690 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12684 12691 gettext("range"), i_ranges.sir_min[i],
12685 12692 i_ranges.sir_max[i]);
12686 12693 }
12687 12694 scf_int_ranges_destroy(&i_ranges);
12688 12695 }
12689 12696 }
12690 12697
12691 12698 static void
12692 12699 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
12693 12700 {
12694 12701 int i = 0, printed = 0;
12695 12702 scf_values_t values;
12696 12703 scf_count_ranges_t c_ranges;
12697 12704 scf_int_ranges_t i_ranges;
12698 12705
12699 12706 printed = 0;
12700 12707 if (scf_tmpl_value_name_choices(prt, &values) == 0) {
12701 12708 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12702 12709 gettext("value constraints"));
12703 12710 printed++;
12704 12711 for (i = 0; i < values.value_count; i++) {
12705 12712 safe_printf("%s%s: %s\n", TMPL_INDENT,
12706 12713 gettext("value name"), values.values_as_strings[i]);
12707 12714 if (verbose == 1)
12708 12715 print_template_value_details(prt,
12709 12716 values.values_as_strings[i], 0);
12710 12717 }
12711 12718
12712 12719 scf_values_destroy(&values);
12713 12720 }
12714 12721
12715 12722 if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
12716 12723 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12717 12724 if (printed++ == 0)
12718 12725 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12719 12726 gettext("value choices"));
12720 12727 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12721 12728 gettext("range"), c_ranges.scr_min[i],
12722 12729 c_ranges.scr_max[i]);
12723 12730 }
12724 12731 scf_count_ranges_destroy(&c_ranges);
12725 12732 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12726 12733 scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
12727 12734 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12728 12735 if (printed++ == 0)
12729 12736 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12730 12737 gettext("value choices"));
12731 12738 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12732 12739 gettext("range"), i_ranges.sir_min[i],
12733 12740 i_ranges.sir_max[i]);
12734 12741 }
12735 12742 scf_int_ranges_destroy(&i_ranges);
12736 12743 }
12737 12744 }
12738 12745
12739 12746 static void
12740 12747 list_values_by_template(scf_prop_tmpl_t *prt)
12741 12748 {
12742 12749 print_template_constraints(prt, 1);
12743 12750 print_template_choices(prt, 1);
12744 12751 }
12745 12752
12746 12753 static void
12747 12754 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
12748 12755 {
12749 12756 char *val_buf;
12750 12757 scf_iter_t *iter;
12751 12758 scf_value_t *val;
12752 12759 int ret;
12753 12760
12754 12761 if ((iter = scf_iter_create(g_hndl)) == NULL ||
12755 12762 (val = scf_value_create(g_hndl)) == NULL)
12756 12763 scfdie();
12757 12764
12758 12765 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12759 12766 scfdie();
12760 12767
12761 12768 val_buf = safe_malloc(max_scf_value_len + 1);
12762 12769
12763 12770 while ((ret = scf_iter_next_value(iter, val)) == 1) {
12764 12771 if (scf_value_get_as_string(val, val_buf,
12765 12772 max_scf_value_len + 1) < 0)
12766 12773 scfdie();
12767 12774
12768 12775 print_template_value(prt, val_buf);
12769 12776 }
12770 12777 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12771 12778 scfdie();
12772 12779 free(val_buf);
12773 12780
12774 12781 print_template_constraints(prt, 0);
12775 12782 print_template_choices(prt, 0);
12776 12783
12777 12784 }
12778 12785
12779 12786 /*
12780 12787 * Outputs property info for the describe subcommand
12781 12788 * Verbose output if templates == 2, -v option of svccfg describe
12782 12789 * Displays template data if prop is not NULL, -t option of svccfg describe
12783 12790 */
12784 12791 static void
12785 12792 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
12786 12793 {
12787 12794 char *buf;
12788 12795 uint8_t u_buf;
12789 12796 int i;
12790 12797 uint64_t min, max;
12791 12798 scf_values_t values;
12792 12799
12793 12800 if (prt == NULL || templates == 0)
12794 12801 return;
12795 12802
12796 12803 if (prop == NULL) {
12797 12804 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
12798 12805 if (scf_tmpl_prop_name(prt, &buf) > 0) {
12799 12806 safe_printf("%s\n", buf);
12800 12807 free(buf);
12801 12808 } else
12802 12809 safe_printf("(%s)\n", gettext("any"));
12803 12810 }
12804 12811
12805 12812 if (prop == NULL || templates == 2) {
12806 12813 if (prop != NULL)
12807 12814 safe_printf("%s", TMPL_INDENT);
12808 12815 else
12809 12816 safe_printf("%s", TMPL_VALUE_INDENT);
12810 12817 safe_printf("%s: ", gettext("type"));
12811 12818 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
12812 12819 safe_printf("%s\n", buf);
12813 12820 free(buf);
12814 12821 } else
12815 12822 safe_printf("(%s)\n", gettext("any"));
12816 12823 }
12817 12824
12818 12825 if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
12819 12826 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12820 12827 u_buf ? "true" : "false");
12821 12828
12822 12829 if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
12823 12830 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12824 12831 buf);
12825 12832 free(buf);
12826 12833 }
12827 12834
12828 12835 if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
12829 12836 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
12830 12837 buf);
12831 12838 free(buf);
12832 12839 }
12833 12840
12834 12841 if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
12835 12842 safe_printf("%s%s\n", TMPL_INDENT, buf);
12836 12843 free(buf);
12837 12844 }
12838 12845
12839 12846 if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
12840 12847 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
12841 12848 scf_tmpl_visibility_to_string(u_buf));
12842 12849
12843 12850 if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
12844 12851 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
12845 12852 gettext("minimum number of values"), min);
12846 12853 if (max == ULLONG_MAX) {
12847 12854 safe_printf("%s%s: %s\n", TMPL_INDENT,
12848 12855 gettext("maximum number of values"),
12849 12856 gettext("unlimited"));
12850 12857 } else {
12851 12858 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
12852 12859 gettext("maximum number of values"), max);
12853 12860 }
12854 12861 }
12855 12862
12856 12863 if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
12857 12864 for (i = 0; i < values.value_count; i++) {
12858 12865 if (i == 0) {
12859 12866 safe_printf("%s%s:", TMPL_INDENT,
12860 12867 gettext("internal separators"));
12861 12868 }
12862 12869 safe_printf(" \"%s\"", values.values_as_strings[i]);
12863 12870 }
12864 12871 safe_printf("\n");
12865 12872 }
12866 12873
12867 12874 if (templates != 2)
12868 12875 return;
12869 12876
12870 12877 if (prop != NULL)
12871 12878 list_values_tmpl(prt, prop);
12872 12879 else
12873 12880 list_values_by_template(prt);
12874 12881 }
12875 12882
12876 12883 static char *
12877 12884 read_astring(scf_propertygroup_t *pg, const char *prop_name)
12878 12885 {
12879 12886 char *rv;
12880 12887
12881 12888 rv = _scf_read_single_astring_from_pg(pg, prop_name);
12882 12889 if (rv == NULL) {
12883 12890 switch (scf_error()) {
12884 12891 case SCF_ERROR_NOT_FOUND:
12885 12892 break;
12886 12893 default:
12887 12894 scfdie();
12888 12895 }
12889 12896 }
12890 12897 return (rv);
12891 12898 }
12892 12899
12893 12900 static void
12894 12901 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
12895 12902 {
12896 12903 size_t doc_len;
12897 12904 size_t man_len;
12898 12905 char *pg_name;
12899 12906 char *text = NULL;
12900 12907 int rv;
12901 12908
12902 12909 doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
12903 12910 man_len = strlen(SCF_PG_TM_MAN_PREFIX);
12904 12911 pg_name = safe_malloc(max_scf_name_len + 1);
12905 12912 while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
12906 12913 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
12907 12914 scfdie();
12908 12915 }
12909 12916 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
12910 12917 /* Display doc_link and and uri */
12911 12918 safe_printf("%s%s:\n", TMPL_INDENT,
12912 12919 gettext("doc_link"));
12913 12920 text = read_astring(pg, SCF_PROPERTY_TM_NAME);
12914 12921 if (text != NULL) {
12915 12922 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12916 12923 TMPL_INDENT, gettext("name"), text);
12917 12924 uu_free(text);
12918 12925 }
12919 12926 text = read_astring(pg, SCF_PROPERTY_TM_URI);
12920 12927 if (text != NULL) {
12921 12928 safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
12922 12929 gettext("uri"), text);
12923 12930 uu_free(text);
12924 12931 }
12925 12932 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
12926 12933 man_len) == 0) {
12927 12934 /* Display manpage title, section and path */
12928 12935 safe_printf("%s%s:\n", TMPL_INDENT,
12929 12936 gettext("manpage"));
12930 12937 text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
12931 12938 if (text != NULL) {
12932 12939 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12933 12940 TMPL_INDENT, gettext("title"), text);
12934 12941 uu_free(text);
12935 12942 }
12936 12943 text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
12937 12944 if (text != NULL) {
12938 12945 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12939 12946 TMPL_INDENT, gettext("section"), text);
12940 12947 uu_free(text);
12941 12948 }
12942 12949 text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
12943 12950 if (text != NULL) {
12944 12951 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12945 12952 TMPL_INDENT, gettext("manpath"), text);
12946 12953 uu_free(text);
12947 12954 }
12948 12955 }
12949 12956 }
12950 12957 if (rv == -1)
12951 12958 scfdie();
12952 12959
12953 12960 done:
12954 12961 free(pg_name);
12955 12962 }
12956 12963
12957 12964 static void
12958 12965 list_entity_tmpl(int templates)
12959 12966 {
12960 12967 char *common_name = NULL;
12961 12968 char *description = NULL;
12962 12969 char *locale = NULL;
12963 12970 scf_iter_t *iter;
12964 12971 scf_propertygroup_t *pg;
12965 12972 scf_property_t *prop;
12966 12973 int r;
12967 12974 scf_value_t *val;
12968 12975
12969 12976 if ((pg = scf_pg_create(g_hndl)) == NULL ||
12970 12977 (prop = scf_property_create(g_hndl)) == NULL ||
12971 12978 (val = scf_value_create(g_hndl)) == NULL ||
12972 12979 (iter = scf_iter_create(g_hndl)) == NULL)
12973 12980 scfdie();
12974 12981
12975 12982 locale = setlocale(LC_MESSAGES, NULL);
12976 12983
12977 12984 if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
12978 12985 common_name = safe_malloc(max_scf_value_len + 1);
12979 12986
12980 12987 /* Try both the current locale and the "C" locale. */
12981 12988 if (scf_pg_get_property(pg, locale, prop) == 0 ||
12982 12989 (scf_error() == SCF_ERROR_NOT_FOUND &&
12983 12990 scf_pg_get_property(pg, "C", prop) == 0)) {
12984 12991 if (prop_get_val(prop, val) == 0 &&
12985 12992 scf_value_get_ustring(val, common_name,
12986 12993 max_scf_value_len + 1) != -1) {
12987 12994 safe_printf("%s%s: %s\n", TMPL_INDENT,
12988 12995 gettext("common name"), common_name);
12989 12996 }
12990 12997 }
12991 12998 }
12992 12999
12993 13000 /*
12994 13001 * Do description, manpages, and doc links if templates == 2.
12995 13002 */
12996 13003 if (templates == 2) {
12997 13004 /* Get the description. */
12998 13005 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
12999 13006 description = safe_malloc(max_scf_value_len + 1);
13000 13007
13001 13008 /* Try both the current locale and the "C" locale. */
13002 13009 if (scf_pg_get_property(pg, locale, prop) == 0 ||
13003 13010 (scf_error() == SCF_ERROR_NOT_FOUND &&
13004 13011 scf_pg_get_property(pg, "C", prop) == 0)) {
13005 13012 if (prop_get_val(prop, val) == 0 &&
13006 13013 scf_value_get_ustring(val, description,
13007 13014 max_scf_value_len + 1) != -1) {
13008 13015 safe_printf("%s%s: %s\n", TMPL_INDENT,
13009 13016 gettext("description"),
13010 13017 description);
13011 13018 }
13012 13019 }
13013 13020 }
13014 13021
13015 13022 /* Process doc_link & manpage elements. */
13016 13023 if (cur_level != NULL) {
13017 13024 r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
13018 13025 SCF_GROUP_TEMPLATE);
13019 13026 } else if (cur_inst != NULL) {
13020 13027 r = scf_iter_instance_pgs_typed(iter, cur_inst,
13021 13028 SCF_GROUP_TEMPLATE);
13022 13029 } else {
13023 13030 r = scf_iter_service_pgs_typed(iter, cur_svc,
13024 13031 SCF_GROUP_TEMPLATE);
13025 13032 }
13026 13033 if (r == 0) {
13027 13034 display_documentation(iter, pg);
13028 13035 }
13029 13036 }
13030 13037
13031 13038 free(common_name);
13032 13039 free(description);
13033 13040 scf_pg_destroy(pg);
13034 13041 scf_property_destroy(prop);
13035 13042 scf_value_destroy(val);
13036 13043 scf_iter_destroy(iter);
13037 13044 }
13038 13045
13039 13046 static void
13040 13047 listtmpl(const char *pattern, int templates)
13041 13048 {
13042 13049 scf_pg_tmpl_t *pgt;
13043 13050 scf_prop_tmpl_t *prt;
13044 13051 char *snapbuf = NULL;
13045 13052 char *fmribuf;
13046 13053 char *pg_name = NULL, *prop_name = NULL;
13047 13054 ssize_t prop_name_size;
13048 13055 char *qual_prop_name;
13049 13056 char *search_name;
13050 13057 int listed = 0;
13051 13058
13052 13059 if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13053 13060 (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
13054 13061 scfdie();
13055 13062
13056 13063 fmribuf = safe_malloc(max_scf_name_len + 1);
13057 13064 qual_prop_name = safe_malloc(max_scf_name_len + 1);
13058 13065
13059 13066 if (cur_snap != NULL) {
13060 13067 snapbuf = safe_malloc(max_scf_name_len + 1);
13061 13068 if (scf_snapshot_get_name(cur_snap, snapbuf,
13062 13069 max_scf_name_len + 1) < 0)
13063 13070 scfdie();
13064 13071 }
13065 13072
13066 13073 if (cur_inst != NULL) {
13067 13074 if (scf_instance_to_fmri(cur_inst, fmribuf,
13068 13075 max_scf_name_len + 1) < 0)
13069 13076 scfdie();
13070 13077 } else if (cur_svc != NULL) {
13071 13078 if (scf_service_to_fmri(cur_svc, fmribuf,
13072 13079 max_scf_name_len + 1) < 0)
13073 13080 scfdie();
13074 13081 } else
13075 13082 abort();
13076 13083
13077 13084 /* If pattern is specified, we want to list only those items. */
13078 13085 while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) {
13079 13086 listed = 0;
13080 13087 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
13081 13088 fnmatch(pattern, pg_name, 0) == 0)) {
13082 13089 list_pg_tmpl(pgt, NULL, templates);
13083 13090 listed++;
13084 13091 }
13085 13092
13086 13093 scf_tmpl_prop_reset(prt);
13087 13094
13088 13095 while (scf_tmpl_iter_props(pgt, prt, 0) == 0) {
13089 13096 search_name = NULL;
13090 13097 prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
13091 13098 if ((prop_name_size > 0) && (pg_name != NULL)) {
13092 13099 if (snprintf(qual_prop_name,
13093 13100 max_scf_name_len + 1, "%s/%s",
13094 13101 pg_name, prop_name) >=
13095 13102 max_scf_name_len + 1) {
13096 13103 prop_name_size = -1;
13097 13104 } else {
13098 13105 search_name = qual_prop_name;
13099 13106 }
13100 13107 }
13101 13108 if (listed > 0 || pattern == NULL ||
13102 13109 (prop_name_size > 0 &&
13103 13110 fnmatch(pattern, search_name,
13104 13111 FNM_PATHNAME) == 0))
13105 13112 list_prop_tmpl(prt, NULL, templates);
13106 13113 if (prop_name != NULL) {
13107 13114 free(prop_name);
13108 13115 prop_name = NULL;
13109 13116 }
13110 13117 }
13111 13118 if (pg_name != NULL) {
13112 13119 free(pg_name);
13113 13120 pg_name = NULL;
13114 13121 }
13115 13122 }
13116 13123
13117 13124 scf_tmpl_prop_destroy(prt);
13118 13125 scf_tmpl_pg_destroy(pgt);
13119 13126 free(snapbuf);
13120 13127 free(fmribuf);
13121 13128 free(qual_prop_name);
13122 13129 }
13123 13130
13124 13131 static void
13125 13132 listprop(const char *pattern, int only_pgs, int templates)
13126 13133 {
13127 13134 scf_propertygroup_t *pg;
13128 13135 scf_property_t *prop;
13129 13136 scf_iter_t *iter, *piter;
13130 13137 char *pgnbuf, *prnbuf, *ppnbuf;
13131 13138 scf_pg_tmpl_t *pgt, *pgtp;
13132 13139 scf_prop_tmpl_t *prt;
13133 13140
13134 13141 void **objects;
13135 13142 char **names;
13136 13143 void **tmpls;
13137 13144 int allocd, i;
13138 13145
13139 13146 int ret;
13140 13147 ssize_t pgnlen, prnlen, szret;
13141 13148 size_t max_len = 0;
13142 13149
13143 13150 if (cur_svc == NULL && cur_inst == NULL) {
13144 13151 semerr(emsg_entity_not_selected);
13145 13152 return;
13146 13153 }
13147 13154
13148 13155 if ((pg = scf_pg_create(g_hndl)) == NULL ||
13149 13156 (prop = scf_property_create(g_hndl)) == NULL ||
13150 13157 (iter = scf_iter_create(g_hndl)) == NULL ||
13151 13158 (piter = scf_iter_create(g_hndl)) == NULL ||
13152 13159 (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13153 13160 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
13154 13161 scfdie();
13155 13162
13156 13163 prnbuf = safe_malloc(max_scf_name_len + 1);
13157 13164
13158 13165 if (cur_level != NULL)
13159 13166 ret = scf_iter_snaplevel_pgs(iter, cur_level);
13160 13167 else if (cur_inst != NULL)
13161 13168 ret = scf_iter_instance_pgs(iter, cur_inst);
13162 13169 else
13163 13170 ret = scf_iter_service_pgs(iter, cur_svc);
13164 13171 if (ret != 0) {
13165 13172 return;
13166 13173 }
13167 13174
13168 13175 /*
13169 13176 * We want to only list items which match pattern, and we want the
13170 13177 * second column to line up, so during the first pass we'll save
13171 13178 * matching items, their names, and their templates in objects,
13172 13179 * names, and tmpls, computing the maximum name length as we go,
13173 13180 * and then we'll print them out.
13174 13181 *
13175 13182 * Note: We always keep an extra slot available so the array can be
13176 13183 * NULL-terminated.
13177 13184 */
13178 13185 i = 0;
13179 13186 allocd = 1;
13180 13187 objects = safe_malloc(sizeof (*objects));
13181 13188 names = safe_malloc(sizeof (*names));
13182 13189 tmpls = safe_malloc(sizeof (*tmpls));
13183 13190
13184 13191 while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13185 13192 int new_pg = 0;
13186 13193 int print_props = 0;
13187 13194 pgtp = NULL;
13188 13195
13189 13196 pgnlen = scf_pg_get_name(pg, NULL, 0);
13190 13197 if (pgnlen < 0)
13191 13198 scfdie();
13192 13199
13193 13200 pgnbuf = safe_malloc(pgnlen + 1);
13194 13201
13195 13202 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
13196 13203 if (szret < 0)
13197 13204 scfdie();
13198 13205 assert(szret <= pgnlen);
13199 13206
13200 13207 if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) {
13201 13208 if (scf_error() != SCF_ERROR_NOT_FOUND)
13202 13209 scfdie();
13203 13210 pgtp = NULL;
13204 13211 } else {
13205 13212 pgtp = pgt;
13206 13213 }
13207 13214
13208 13215 if (pattern == NULL ||
13209 13216 fnmatch(pattern, pgnbuf, 0) == 0) {
13210 13217 if (i+1 >= allocd) {
13211 13218 allocd *= 2;
13212 13219 objects = realloc(objects,
13213 13220 sizeof (*objects) * allocd);
13214 13221 names =
13215 13222 realloc(names, sizeof (*names) * allocd);
13216 13223 tmpls = realloc(tmpls,
13217 13224 sizeof (*tmpls) * allocd);
13218 13225 if (objects == NULL || names == NULL ||
13219 13226 tmpls == NULL)
13220 13227 uu_die(gettext("Out of memory"));
13221 13228 }
13222 13229 objects[i] = pg;
13223 13230 names[i] = pgnbuf;
13224 13231
13225 13232 if (pgtp == NULL)
13226 13233 tmpls[i] = NULL;
13227 13234 else
13228 13235 tmpls[i] = pgt;
13229 13236
13230 13237 ++i;
13231 13238
13232 13239 if (pgnlen > max_len)
13233 13240 max_len = pgnlen;
13234 13241
13235 13242 new_pg = 1;
13236 13243 print_props = 1;
13237 13244 }
13238 13245
13239 13246 if (only_pgs) {
13240 13247 if (new_pg) {
13241 13248 pg = scf_pg_create(g_hndl);
13242 13249 if (pg == NULL)
13243 13250 scfdie();
13244 13251 pgt = scf_tmpl_pg_create(g_hndl);
13245 13252 if (pgt == NULL)
13246 13253 scfdie();
13247 13254 } else
13248 13255 free(pgnbuf);
13249 13256
13250 13257 continue;
13251 13258 }
13252 13259
13253 13260 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13254 13261 scfdie();
13255 13262
13256 13263 while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13257 13264 prnlen = scf_property_get_name(prop, prnbuf,
13258 13265 max_scf_name_len + 1);
13259 13266 if (prnlen < 0)
13260 13267 scfdie();
13261 13268
13262 13269 /* Will prepend the property group name and a slash. */
13263 13270 prnlen += pgnlen + 1;
13264 13271
13265 13272 ppnbuf = safe_malloc(prnlen + 1);
13266 13273
13267 13274 if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13268 13275 prnbuf) < 0)
13269 13276 uu_die("snprintf");
13270 13277
13271 13278 if (pattern == NULL || print_props == 1 ||
13272 13279 fnmatch(pattern, ppnbuf, 0) == 0) {
13273 13280 if (i+1 >= allocd) {
13274 13281 allocd *= 2;
13275 13282 objects = realloc(objects,
13276 13283 sizeof (*objects) * allocd);
13277 13284 names = realloc(names,
13278 13285 sizeof (*names) * allocd);
13279 13286 tmpls = realloc(tmpls,
13280 13287 sizeof (*tmpls) * allocd);
13281 13288 if (objects == NULL || names == NULL ||
13282 13289 tmpls == NULL)
13283 13290 uu_die(gettext(
13284 13291 "Out of memory"));
13285 13292 }
13286 13293
13287 13294 objects[i] = prop;
13288 13295 names[i] = ppnbuf;
13289 13296
13290 13297 if (pgtp != NULL) {
13291 13298 if (scf_tmpl_get_by_prop(pgt, prnbuf,
13292 13299 prt, 0) < 0) {
13293 13300 if (scf_error() !=
13294 13301 SCF_ERROR_NOT_FOUND)
13295 13302 scfdie();
13296 13303 tmpls[i] = NULL;
13297 13304 } else {
13298 13305 tmpls[i] = prt;
13299 13306 }
13300 13307 } else {
13301 13308 tmpls[i] = NULL;
13302 13309 }
13303 13310
13304 13311 ++i;
13305 13312
13306 13313 if (prnlen > max_len)
13307 13314 max_len = prnlen;
13308 13315
13309 13316 prop = scf_property_create(g_hndl);
13310 13317 prt = scf_tmpl_prop_create(g_hndl);
13311 13318 } else {
13312 13319 free(ppnbuf);
13313 13320 }
13314 13321 }
13315 13322
13316 13323 if (new_pg) {
13317 13324 pg = scf_pg_create(g_hndl);
13318 13325 if (pg == NULL)
13319 13326 scfdie();
13320 13327 pgt = scf_tmpl_pg_create(g_hndl);
13321 13328 if (pgt == NULL)
13322 13329 scfdie();
13323 13330 } else
13324 13331 free(pgnbuf);
13325 13332 }
13326 13333 if (ret != 0)
13327 13334 scfdie();
13328 13335
13329 13336 objects[i] = NULL;
13330 13337
13331 13338 scf_pg_destroy(pg);
13332 13339 scf_tmpl_pg_destroy(pgt);
13333 13340 scf_property_destroy(prop);
13334 13341 scf_tmpl_prop_destroy(prt);
13335 13342
13336 13343 for (i = 0; objects[i] != NULL; ++i) {
13337 13344 if (strchr(names[i], '/') == NULL) {
13338 13345 /* property group */
13339 13346 pg = (scf_propertygroup_t *)objects[i];
13340 13347 pgt = (scf_pg_tmpl_t *)tmpls[i];
13341 13348 list_pg_info(pg, names[i], max_len);
13342 13349 list_pg_tmpl(pgt, pg, templates);
13343 13350 free(names[i]);
13344 13351 scf_pg_destroy(pg);
13345 13352 if (pgt != NULL)
13346 13353 scf_tmpl_pg_destroy(pgt);
13347 13354 } else {
13348 13355 /* property */
13349 13356 prop = (scf_property_t *)objects[i];
13350 13357 prt = (scf_prop_tmpl_t *)tmpls[i];
13351 13358 list_prop_info(prop, names[i], max_len);
13352 13359 list_prop_tmpl(prt, prop, templates);
13353 13360 free(names[i]);
13354 13361 scf_property_destroy(prop);
13355 13362 if (prt != NULL)
13356 13363 scf_tmpl_prop_destroy(prt);
13357 13364 }
13358 13365 }
13359 13366
13360 13367 free(names);
13361 13368 free(objects);
13362 13369 free(tmpls);
13363 13370 }
13364 13371
13365 13372 void
13366 13373 lscf_listpg(const char *pattern)
13367 13374 {
13368 13375 lscf_prep_hndl();
13369 13376
13370 13377 listprop(pattern, 1, 0);
13371 13378 }
13372 13379
13373 13380 /*
13374 13381 * Property group and property creation, setting, and deletion. setprop (and
13375 13382 * its alias, addprop) can either create a property group of a given type, or
13376 13383 * it can create or set a property to a given type and list of values.
13377 13384 */
13378 13385 void
13379 13386 lscf_addpg(const char *name, const char *type, const char *flags)
13380 13387 {
13381 13388 scf_propertygroup_t *pg;
13382 13389 int ret;
13383 13390 uint32_t flgs = 0;
13384 13391 const char *cp;
13385 13392
13386 13393
13387 13394 lscf_prep_hndl();
13388 13395
13389 13396 if (cur_snap != NULL) {
13390 13397 semerr(emsg_cant_modify_snapshots);
13391 13398 return;
13392 13399 }
13393 13400
13394 13401 if (cur_inst == NULL && cur_svc == NULL) {
13395 13402 semerr(emsg_entity_not_selected);
13396 13403 return;
13397 13404 }
13398 13405
13399 13406 if (flags != NULL) {
13400 13407 for (cp = flags; *cp != '\0'; ++cp) {
13401 13408 switch (*cp) {
13402 13409 case 'P':
13403 13410 flgs |= SCF_PG_FLAG_NONPERSISTENT;
13404 13411 break;
13405 13412
13406 13413 case 'p':
13407 13414 flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13408 13415 break;
13409 13416
13410 13417 default:
13411 13418 semerr(gettext("Invalid property group flag "
13412 13419 "%c."), *cp);
13413 13420 return;
13414 13421 }
13415 13422 }
13416 13423 }
13417 13424
13418 13425 pg = scf_pg_create(g_hndl);
13419 13426 if (pg == NULL)
13420 13427 scfdie();
13421 13428
13422 13429 if (cur_inst != NULL)
13423 13430 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13424 13431 else
13425 13432 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13426 13433
13427 13434 if (ret != SCF_SUCCESS) {
13428 13435 switch (scf_error()) {
13429 13436 case SCF_ERROR_INVALID_ARGUMENT:
13430 13437 semerr(gettext("Name, type, or flags are invalid.\n"));
13431 13438 break;
13432 13439
13433 13440 case SCF_ERROR_EXISTS:
13434 13441 semerr(gettext("Property group already exists.\n"));
13435 13442 break;
13436 13443
13437 13444 case SCF_ERROR_PERMISSION_DENIED:
13438 13445 semerr(emsg_permission_denied);
13439 13446 break;
13440 13447
13441 13448 case SCF_ERROR_BACKEND_ACCESS:
13442 13449 semerr(gettext("Backend refused access.\n"));
13443 13450 break;
13444 13451
13445 13452 default:
13446 13453 scfdie();
13447 13454 }
13448 13455 }
13449 13456
13450 13457 scf_pg_destroy(pg);
13451 13458
13452 13459 private_refresh();
13453 13460 }
13454 13461
13455 13462 void
13456 13463 lscf_delpg(char *name)
13457 13464 {
13458 13465 lscf_prep_hndl();
13459 13466
13460 13467 if (cur_snap != NULL) {
13461 13468 semerr(emsg_cant_modify_snapshots);
13462 13469 return;
13463 13470 }
13464 13471
13465 13472 if (cur_inst == NULL && cur_svc == NULL) {
13466 13473 semerr(emsg_entity_not_selected);
13467 13474 return;
13468 13475 }
13469 13476
13470 13477 if (strchr(name, '/') != NULL) {
13471 13478 semerr(emsg_invalid_pg_name, name);
13472 13479 return;
13473 13480 }
13474 13481
13475 13482 lscf_delprop(name);
13476 13483 }
13477 13484
13478 13485 /*
13479 13486 * scf_delhash() is used to remove the property group related to the
13480 13487 * hash entry for a specific manifest in the repository. pgname will be
13481 13488 * constructed from the location of the manifest file. If deathrow isn't 0,
13482 13489 * manifest file doesn't need to exist (manifest string will be used as
13483 13490 * an absolute path).
13484 13491 */
13485 13492 void
13486 13493 lscf_delhash(char *manifest, int deathrow)
13487 13494 {
13488 13495 char *pgname;
13489 13496
13490 13497 if (cur_snap != NULL ||
13491 13498 cur_inst != NULL || cur_svc != NULL) {
13492 13499 warn(gettext("error, an entity is selected\n"));
13493 13500 return;
13494 13501 }
13495 13502
13496 13503 /* select smf/manifest */
13497 13504 lscf_select(HASH_SVC);
13498 13505 /*
13499 13506 * Translate the manifest file name to property name. In the deathrow
13500 13507 * case, the manifest file does not need to exist.
13501 13508 */
13502 13509 pgname = mhash_filename_to_propname(manifest,
13503 13510 deathrow ? B_TRUE : B_FALSE);
13504 13511 if (pgname == NULL) {
13505 13512 warn(gettext("cannot resolve pathname for %s\n"), manifest);
13506 13513 return;
13507 13514 }
13508 13515 /* delete the hash property name */
13509 13516 lscf_delpg(pgname);
13510 13517 }
13511 13518
13512 13519 void
13513 13520 lscf_listprop(const char *pattern)
13514 13521 {
13515 13522 lscf_prep_hndl();
13516 13523
13517 13524 listprop(pattern, 0, 0);
13518 13525 }
13519 13526
13520 13527 int
13521 13528 lscf_setprop(const char *pgname, const char *type, const char *value,
13522 13529 const uu_list_t *values)
13523 13530 {
13524 13531 scf_type_t ty, current_ty;
13525 13532 scf_service_t *svc;
13526 13533 scf_propertygroup_t *pg, *parent_pg;
13527 13534 scf_property_t *prop, *parent_prop;
13528 13535 scf_pg_tmpl_t *pgt;
13529 13536 scf_prop_tmpl_t *prt;
13530 13537 int ret, result = 0;
13531 13538 scf_transaction_t *tx;
13532 13539 scf_transaction_entry_t *e;
13533 13540 scf_value_t *v;
13534 13541 uu_list_walk_t *walk;
13535 13542 string_list_t *sp;
13536 13543 char *propname;
13537 13544 int req_quotes = 0;
13538 13545
13539 13546 lscf_prep_hndl();
13540 13547
13541 13548 if ((e = scf_entry_create(g_hndl)) == NULL ||
13542 13549 (svc = scf_service_create(g_hndl)) == NULL ||
13543 13550 (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13544 13551 (pg = scf_pg_create(g_hndl)) == NULL ||
13545 13552 (parent_prop = scf_property_create(g_hndl)) == NULL ||
13546 13553 (prop = scf_property_create(g_hndl)) == NULL ||
13547 13554 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13548 13555 (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13549 13556 (tx = scf_transaction_create(g_hndl)) == NULL)
13550 13557 scfdie();
13551 13558
13552 13559 if (cur_snap != NULL) {
13553 13560 semerr(emsg_cant_modify_snapshots);
13554 13561 goto fail;
13555 13562 }
13556 13563
13557 13564 if (cur_inst == NULL && cur_svc == NULL) {
13558 13565 semerr(emsg_entity_not_selected);
13559 13566 goto fail;
13560 13567 }
13561 13568
13562 13569 propname = strchr(pgname, '/');
13563 13570 if (propname == NULL) {
13564 13571 semerr(gettext("Property names must contain a `/'.\n"));
13565 13572 goto fail;
13566 13573 }
13567 13574
13568 13575 *propname = '\0';
13569 13576 ++propname;
13570 13577
13571 13578 if (type != NULL) {
13572 13579 ty = string_to_type(type);
13573 13580 if (ty == SCF_TYPE_INVALID) {
13574 13581 semerr(gettext("Unknown type \"%s\".\n"), type);
13575 13582 goto fail;
13576 13583 }
13577 13584 }
13578 13585
13579 13586 if (cur_inst != NULL)
13580 13587 ret = scf_instance_get_pg(cur_inst, pgname, pg);
13581 13588 else
13582 13589 ret = scf_service_get_pg(cur_svc, pgname, pg);
13583 13590 if (ret != SCF_SUCCESS) {
13584 13591 switch (scf_error()) {
13585 13592 case SCF_ERROR_NOT_FOUND:
13586 13593 semerr(emsg_no_such_pg, pgname);
13587 13594 goto fail;
13588 13595
13589 13596 case SCF_ERROR_INVALID_ARGUMENT:
13590 13597 semerr(emsg_invalid_pg_name, pgname);
13591 13598 goto fail;
13592 13599
13593 13600 default:
13594 13601 scfdie();
13595 13602 break;
13596 13603 }
13597 13604 }
13598 13605
13599 13606 do {
13600 13607 if (scf_pg_update(pg) == -1)
13601 13608 scfdie();
13602 13609 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13603 13610 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13604 13611 scfdie();
13605 13612
13606 13613 semerr(emsg_permission_denied);
13607 13614 goto fail;
13608 13615 }
13609 13616
13610 13617 ret = scf_pg_get_property(pg, propname, prop);
13611 13618 if (ret == SCF_SUCCESS) {
13612 13619 if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS)
13613 13620 scfdie();
13614 13621
13615 13622 if (type == NULL)
13616 13623 ty = current_ty;
13617 13624 if (scf_transaction_property_change_type(tx, e,
13618 13625 propname, ty) == -1)
13619 13626 scfdie();
13620 13627
13621 13628 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13622 13629 /* Infer the type, if possible. */
13623 13630 if (type == NULL) {
13624 13631 /*
13625 13632 * First check if we're an instance and the
13626 13633 * property is set on the service.
13627 13634 */
13628 13635 if (cur_inst != NULL &&
13629 13636 scf_instance_get_parent(cur_inst,
13630 13637 svc) == 0 &&
13631 13638 scf_service_get_pg(cur_svc, pgname,
13632 13639 parent_pg) == 0 &&
13633 13640 scf_pg_get_property(parent_pg, propname,
13634 13641 parent_prop) == 0 &&
13635 13642 scf_property_type(parent_prop,
13636 13643 ¤t_ty) == 0) {
13637 13644 ty = current_ty;
13638 13645
13639 13646 /* Then check for a type set in a template. */
13640 13647 } else if (scf_tmpl_get_by_pg(pg, pgt,
13641 13648 0) == 0 &&
13642 13649 scf_tmpl_get_by_prop(pgt, propname, prt,
13643 13650 0) == 0 &&
13644 13651 scf_tmpl_prop_type(prt, ¤t_ty) == 0) {
13645 13652 ty = current_ty;
13646 13653
13647 13654 /* If type can't be inferred, fail. */
13648 13655 } else {
13649 13656 semerr(gettext("Type required for new "
13650 13657 "properties.\n"));
13651 13658 goto fail;
13652 13659 }
13653 13660 }
13654 13661 if (scf_transaction_property_new(tx, e, propname,
13655 13662 ty) == -1)
13656 13663 scfdie();
13657 13664 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13658 13665 semerr(emsg_invalid_prop_name, propname);
13659 13666 goto fail;
13660 13667 } else {
13661 13668 scfdie();
13662 13669 }
13663 13670
13664 13671 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13665 13672 req_quotes = 1;
13666 13673
13667 13674 if (value != NULL) {
13668 13675 v = string_to_value(value, ty, 0);
13669 13676
13670 13677 if (v == NULL)
13671 13678 goto fail;
13672 13679
13673 13680 ret = scf_entry_add_value(e, v);
13674 13681 assert(ret == SCF_SUCCESS);
13675 13682 } else {
13676 13683 assert(values != NULL);
13677 13684
13678 13685 walk = uu_list_walk_start((uu_list_t *)values,
13679 13686 UU_DEFAULT);
13680 13687 if (walk == NULL)
13681 13688 uu_die(gettext("Could not walk list"));
13682 13689
13683 13690 for (sp = uu_list_walk_next(walk); sp != NULL;
13684 13691 sp = uu_list_walk_next(walk)) {
13685 13692 v = string_to_value(sp->str, ty, req_quotes);
13686 13693
13687 13694 if (v == NULL) {
13688 13695 scf_entry_destroy_children(e);
13689 13696 goto fail;
13690 13697 }
13691 13698
13692 13699 ret = scf_entry_add_value(e, v);
13693 13700 assert(ret == SCF_SUCCESS);
13694 13701 }
13695 13702 uu_list_walk_end(walk);
13696 13703 }
13697 13704 result = scf_transaction_commit(tx);
13698 13705
13699 13706 scf_transaction_reset(tx);
13700 13707 scf_entry_destroy_children(e);
13701 13708 } while (result == 0);
13702 13709
13703 13710 if (result < 0) {
13704 13711 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13705 13712 scfdie();
13706 13713
13707 13714 semerr(emsg_permission_denied);
13708 13715 goto fail;
13709 13716 }
13710 13717
13711 13718 ret = 0;
13712 13719
13713 13720 private_refresh();
13714 13721
13715 13722 goto cleanup;
13716 13723
13717 13724 fail:
13718 13725 ret = -1;
13719 13726
13720 13727 cleanup:
13721 13728 scf_transaction_destroy(tx);
13722 13729 scf_entry_destroy(e);
13723 13730 scf_service_destroy(svc);
13724 13731 scf_pg_destroy(parent_pg);
13725 13732 scf_pg_destroy(pg);
13726 13733 scf_property_destroy(parent_prop);
13727 13734 scf_property_destroy(prop);
13728 13735 scf_tmpl_pg_destroy(pgt);
13729 13736 scf_tmpl_prop_destroy(prt);
13730 13737
13731 13738 return (ret);
13732 13739 }
13733 13740
13734 13741 void
13735 13742 lscf_delprop(char *pgn)
13736 13743 {
13737 13744 char *slash, *pn;
13738 13745 scf_propertygroup_t *pg;
13739 13746 scf_transaction_t *tx;
13740 13747 scf_transaction_entry_t *e;
13741 13748 int ret;
13742 13749
13743 13750
13744 13751 lscf_prep_hndl();
13745 13752
13746 13753 if (cur_snap != NULL) {
13747 13754 semerr(emsg_cant_modify_snapshots);
13748 13755 return;
13749 13756 }
13750 13757
13751 13758 if (cur_inst == NULL && cur_svc == NULL) {
13752 13759 semerr(emsg_entity_not_selected);
13753 13760 return;
13754 13761 }
13755 13762
13756 13763 pg = scf_pg_create(g_hndl);
13757 13764 if (pg == NULL)
13758 13765 scfdie();
13759 13766
13760 13767 slash = strchr(pgn, '/');
13761 13768 if (slash == NULL) {
13762 13769 pn = NULL;
13763 13770 } else {
13764 13771 *slash = '\0';
13765 13772 pn = slash + 1;
13766 13773 }
13767 13774
13768 13775 if (cur_inst != NULL)
13769 13776 ret = scf_instance_get_pg(cur_inst, pgn, pg);
13770 13777 else
13771 13778 ret = scf_service_get_pg(cur_svc, pgn, pg);
13772 13779 if (ret != SCF_SUCCESS) {
13773 13780 switch (scf_error()) {
13774 13781 case SCF_ERROR_NOT_FOUND:
13775 13782 semerr(emsg_no_such_pg, pgn);
13776 13783 break;
13777 13784
13778 13785 case SCF_ERROR_INVALID_ARGUMENT:
13779 13786 semerr(emsg_invalid_pg_name, pgn);
13780 13787 break;
13781 13788
13782 13789 default:
13783 13790 scfdie();
13784 13791 }
13785 13792
13786 13793 scf_pg_destroy(pg);
13787 13794
13788 13795 return;
13789 13796 }
13790 13797
13791 13798 if (pn == NULL) {
13792 13799 /* Try to delete the property group. */
13793 13800 if (scf_pg_delete(pg) != SCF_SUCCESS) {
13794 13801 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13795 13802 scfdie();
13796 13803
13797 13804 semerr(emsg_permission_denied);
13798 13805 } else {
13799 13806 private_refresh();
13800 13807 }
13801 13808
13802 13809 scf_pg_destroy(pg);
13803 13810 return;
13804 13811 }
13805 13812
13806 13813 e = scf_entry_create(g_hndl);
13807 13814 tx = scf_transaction_create(g_hndl);
13808 13815
13809 13816 do {
13810 13817 if (scf_pg_update(pg) == -1)
13811 13818 scfdie();
13812 13819 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13813 13820 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13814 13821 scfdie();
13815 13822
13816 13823 semerr(emsg_permission_denied);
13817 13824 break;
13818 13825 }
13819 13826
13820 13827 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
13821 13828 if (scf_error() == SCF_ERROR_NOT_FOUND) {
13822 13829 semerr(gettext("No such property %s/%s.\n"),
13823 13830 pgn, pn);
13824 13831 break;
13825 13832 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13826 13833 semerr(emsg_invalid_prop_name, pn);
13827 13834 break;
13828 13835 } else {
13829 13836 scfdie();
13830 13837 }
13831 13838 }
13832 13839
13833 13840 ret = scf_transaction_commit(tx);
13834 13841
13835 13842 if (ret == 0)
13836 13843 scf_transaction_reset(tx);
13837 13844 } while (ret == 0);
13838 13845
13839 13846 if (ret < 0) {
13840 13847 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13841 13848 scfdie();
13842 13849
13843 13850 semerr(emsg_permission_denied);
13844 13851 } else {
13845 13852 private_refresh();
13846 13853 }
13847 13854
13848 13855 scf_transaction_destroy(tx);
13849 13856 scf_entry_destroy(e);
13850 13857 scf_pg_destroy(pg);
13851 13858 }
13852 13859
13853 13860 /*
13854 13861 * Property editing.
13855 13862 */
13856 13863
13857 13864 static int
13858 13865 write_edit_script(FILE *strm)
13859 13866 {
13860 13867 char *fmribuf;
13861 13868 ssize_t fmrilen;
13862 13869
13863 13870 scf_propertygroup_t *pg;
13864 13871 scf_property_t *prop;
13865 13872 scf_value_t *val;
13866 13873 scf_type_t ty;
13867 13874 int ret, result = 0;
13868 13875 scf_iter_t *iter, *piter, *viter;
13869 13876 char *buf, *tybuf, *pname;
13870 13877 const char *emsg_write_error;
13871 13878
13872 13879
13873 13880 emsg_write_error = gettext("Error writing temoprary file: %s.\n");
13874 13881
13875 13882
13876 13883 /* select fmri */
13877 13884 if (cur_inst != NULL) {
13878 13885 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
13879 13886 if (fmrilen < 0)
13880 13887 scfdie();
13881 13888 fmribuf = safe_malloc(fmrilen + 1);
13882 13889 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
13883 13890 scfdie();
13884 13891 } else {
13885 13892 assert(cur_svc != NULL);
13886 13893 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
13887 13894 if (fmrilen < 0)
13888 13895 scfdie();
13889 13896 fmribuf = safe_malloc(fmrilen + 1);
13890 13897 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
13891 13898 scfdie();
13892 13899 }
13893 13900
13894 13901 if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
13895 13902 warn(emsg_write_error, strerror(errno));
13896 13903 free(fmribuf);
13897 13904 return (-1);
13898 13905 }
13899 13906
13900 13907 free(fmribuf);
13901 13908
13902 13909
13903 13910 if ((pg = scf_pg_create(g_hndl)) == NULL ||
13904 13911 (prop = scf_property_create(g_hndl)) == NULL ||
13905 13912 (val = scf_value_create(g_hndl)) == NULL ||
13906 13913 (iter = scf_iter_create(g_hndl)) == NULL ||
13907 13914 (piter = scf_iter_create(g_hndl)) == NULL ||
13908 13915 (viter = scf_iter_create(g_hndl)) == NULL)
13909 13916 scfdie();
13910 13917
13911 13918 buf = safe_malloc(max_scf_name_len + 1);
13912 13919 tybuf = safe_malloc(max_scf_pg_type_len + 1);
13913 13920 pname = safe_malloc(max_scf_name_len + 1);
13914 13921
13915 13922 if (cur_inst != NULL)
13916 13923 ret = scf_iter_instance_pgs(iter, cur_inst);
13917 13924 else
13918 13925 ret = scf_iter_service_pgs(iter, cur_svc);
13919 13926 if (ret != SCF_SUCCESS)
13920 13927 scfdie();
13921 13928
13922 13929 while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13923 13930 int ret2;
13924 13931
13925 13932 /*
13926 13933 * # delprop pg
13927 13934 * # addpg pg type
13928 13935 */
13929 13936 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
13930 13937 scfdie();
13931 13938
13932 13939 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
13933 13940 scfdie();
13934 13941
13935 13942 if (fprintf(strm, "# Property group \"%s\"\n"
13936 13943 "# delprop %s\n"
13937 13944 "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
13938 13945 warn(emsg_write_error, strerror(errno));
13939 13946 result = -1;
13940 13947 goto out;
13941 13948 }
13942 13949
13943 13950 /* # setprop pg/prop = (values) */
13944 13951
13945 13952 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13946 13953 scfdie();
13947 13954
13948 13955 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
13949 13956 int first = 1;
13950 13957 int ret3;
13951 13958 int multiple;
13952 13959 int is_str;
13953 13960 scf_type_t bty;
13954 13961
13955 13962 if (scf_property_get_name(prop, pname,
13956 13963 max_scf_name_len + 1) < 0)
13957 13964 scfdie();
13958 13965
13959 13966 if (scf_property_type(prop, &ty) != 0)
13960 13967 scfdie();
13961 13968
13962 13969 multiple = prop_has_multiple_values(prop, val);
13963 13970
13964 13971 if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
13965 13972 pname, scf_type_to_string(ty), multiple ? "(" : "")
13966 13973 < 0) {
13967 13974 warn(emsg_write_error, strerror(errno));
13968 13975 result = -1;
13969 13976 goto out;
13970 13977 }
13971 13978
13972 13979 (void) scf_type_base_type(ty, &bty);
13973 13980 is_str = (bty == SCF_TYPE_ASTRING);
13974 13981
13975 13982 if (scf_iter_property_values(viter, prop) !=
13976 13983 SCF_SUCCESS)
13977 13984 scfdie();
13978 13985
13979 13986 while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
13980 13987 char *buf;
13981 13988 ssize_t buflen;
13982 13989
13983 13990 buflen = scf_value_get_as_string(val, NULL, 0);
13984 13991 if (buflen < 0)
13985 13992 scfdie();
13986 13993
13987 13994 buf = safe_malloc(buflen + 1);
13988 13995
13989 13996 if (scf_value_get_as_string(val, buf,
13990 13997 buflen + 1) < 0)
13991 13998 scfdie();
13992 13999
13993 14000 if (first)
13994 14001 first = 0;
13995 14002 else {
13996 14003 if (putc(' ', strm) != ' ') {
13997 14004 warn(emsg_write_error,
13998 14005 strerror(errno));
13999 14006 result = -1;
14000 14007 goto out;
14001 14008 }
14002 14009 }
14003 14010
14004 14011 if ((is_str && multiple) ||
14005 14012 strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
14006 14013 (void) putc('"', strm);
14007 14014 (void) quote_and_print(buf, strm, 1);
14008 14015 (void) putc('"', strm);
14009 14016
14010 14017 if (ferror(strm)) {
14011 14018 warn(emsg_write_error,
14012 14019 strerror(errno));
14013 14020 result = -1;
14014 14021 goto out;
14015 14022 }
14016 14023 } else {
14017 14024 if (fprintf(strm, "%s", buf) < 0) {
14018 14025 warn(emsg_write_error,
14019 14026 strerror(errno));
14020 14027 result = -1;
14021 14028 goto out;
14022 14029 }
14023 14030 }
14024 14031
14025 14032 free(buf);
14026 14033 }
14027 14034 if (ret3 < 0 &&
14028 14035 scf_error() != SCF_ERROR_PERMISSION_DENIED)
14029 14036 scfdie();
14030 14037
14031 14038 /* Write closing paren if mult-value property */
14032 14039 if ((multiple && putc(')', strm) == EOF) ||
14033 14040
14034 14041 /* Write final newline */
14035 14042 fputc('\n', strm) == EOF) {
14036 14043 warn(emsg_write_error, strerror(errno));
14037 14044 result = -1;
14038 14045 goto out;
14039 14046 }
14040 14047 }
14041 14048 if (ret2 < 0)
14042 14049 scfdie();
14043 14050
14044 14051 if (fputc('\n', strm) == EOF) {
14045 14052 warn(emsg_write_error, strerror(errno));
14046 14053 result = -1;
14047 14054 goto out;
14048 14055 }
14049 14056 }
14050 14057 if (ret < 0)
14051 14058 scfdie();
14052 14059
14053 14060 out:
14054 14061 free(pname);
14055 14062 free(tybuf);
14056 14063 free(buf);
14057 14064 scf_iter_destroy(viter);
14058 14065 scf_iter_destroy(piter);
14059 14066 scf_iter_destroy(iter);
14060 14067 scf_value_destroy(val);
14061 14068 scf_property_destroy(prop);
14062 14069 scf_pg_destroy(pg);
14063 14070
14064 14071 if (result == 0) {
14065 14072 if (fflush(strm) != 0) {
14066 14073 warn(emsg_write_error, strerror(errno));
14067 14074 return (-1);
14068 14075 }
14069 14076 }
14070 14077
14071 14078 return (result);
14072 14079 }
14073 14080
14074 14081 int
14075 14082 lscf_editprop()
14076 14083 {
14077 14084 char *buf, *editor;
14078 14085 size_t bufsz;
14079 14086 int tmpfd;
14080 14087 char tempname[] = TEMP_FILE_PATTERN;
14081 14088
14082 14089 lscf_prep_hndl();
14083 14090
14084 14091 if (cur_snap != NULL) {
14085 14092 semerr(emsg_cant_modify_snapshots);
14086 14093 return (-1);
14087 14094 }
14088 14095
14089 14096 if (cur_svc == NULL && cur_inst == NULL) {
14090 14097 semerr(emsg_entity_not_selected);
14091 14098 return (-1);
14092 14099 }
14093 14100
14094 14101 tmpfd = mkstemp(tempname);
14095 14102 if (tmpfd == -1) {
14096 14103 semerr(gettext("Could not create temporary file.\n"));
14097 14104 return (-1);
14098 14105 }
14099 14106
14100 14107 (void) strcpy(tempfilename, tempname);
14101 14108
14102 14109 tempfile = fdopen(tmpfd, "r+");
14103 14110 if (tempfile == NULL) {
14104 14111 warn(gettext("Could not create temporary file.\n"));
14105 14112 if (close(tmpfd) == -1)
14106 14113 warn(gettext("Could not close temporary file: %s.\n"),
14107 14114 strerror(errno));
14108 14115
14109 14116 remove_tempfile();
14110 14117
14111 14118 return (-1);
14112 14119 }
14113 14120
14114 14121 if (write_edit_script(tempfile) == -1) {
14115 14122 remove_tempfile();
14116 14123 return (-1);
14117 14124 }
14118 14125
14119 14126 editor = getenv("EDITOR");
14120 14127 if (editor == NULL)
14121 14128 editor = "vi";
14122 14129
14123 14130 bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
14124 14131 buf = safe_malloc(bufsz);
14125 14132
14126 14133 if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
14127 14134 uu_die(gettext("Error creating editor command"));
14128 14135
14129 14136 if (system(buf) == -1) {
14130 14137 semerr(gettext("Could not launch editor %s: %s\n"), editor,
14131 14138 strerror(errno));
14132 14139 free(buf);
14133 14140 remove_tempfile();
14134 14141 return (-1);
14135 14142 }
14136 14143
14137 14144 free(buf);
14138 14145
14139 14146 (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
14140 14147
14141 14148 remove_tempfile();
14142 14149
14143 14150 return (0);
14144 14151 }
14145 14152
14146 14153 static void
14147 14154 add_string(uu_list_t *strlist, const char *str)
14148 14155 {
14149 14156 string_list_t *elem;
14150 14157 elem = safe_malloc(sizeof (*elem));
14151 14158 uu_list_node_init(elem, &elem->node, string_pool);
14152 14159 elem->str = safe_strdup(str);
14153 14160 if (uu_list_append(strlist, elem) != 0)
14154 14161 uu_die(gettext("libuutil error: %s\n"),
14155 14162 uu_strerror(uu_error()));
14156 14163 }
14157 14164
14158 14165 static int
14159 14166 remove_string(uu_list_t *strlist, const char *str)
14160 14167 {
14161 14168 uu_list_walk_t *elems;
14162 14169 string_list_t *sp;
14163 14170
14164 14171 /*
14165 14172 * Find the element that needs to be removed.
14166 14173 */
14167 14174 elems = uu_list_walk_start(strlist, UU_DEFAULT);
14168 14175 while ((sp = uu_list_walk_next(elems)) != NULL) {
14169 14176 if (strcmp(sp->str, str) == 0)
14170 14177 break;
14171 14178 }
14172 14179 uu_list_walk_end(elems);
14173 14180
14174 14181 /*
14175 14182 * Returning 1 here as the value was not found, this
14176 14183 * might not be an error. Leave it to the caller to
14177 14184 * decide.
14178 14185 */
14179 14186 if (sp == NULL) {
14180 14187 return (1);
14181 14188 }
14182 14189
14183 14190 uu_list_remove(strlist, sp);
14184 14191
14185 14192 free(sp->str);
14186 14193 free(sp);
14187 14194
14188 14195 return (0);
14189 14196 }
14190 14197
14191 14198 /*
14192 14199 * Get all property values that don't match the given glob pattern,
14193 14200 * if a pattern is specified.
14194 14201 */
14195 14202 static void
14196 14203 get_prop_values(scf_property_t *prop, uu_list_t *values,
14197 14204 const char *pattern)
14198 14205 {
14199 14206 scf_iter_t *iter;
14200 14207 scf_value_t *val;
14201 14208 int ret;
14202 14209
14203 14210 if ((iter = scf_iter_create(g_hndl)) == NULL ||
14204 14211 (val = scf_value_create(g_hndl)) == NULL)
14205 14212 scfdie();
14206 14213
14207 14214 if (scf_iter_property_values(iter, prop) != 0)
14208 14215 scfdie();
14209 14216
14210 14217 while ((ret = scf_iter_next_value(iter, val)) == 1) {
14211 14218 char *buf;
14212 14219 ssize_t vlen, szret;
14213 14220
14214 14221 vlen = scf_value_get_as_string(val, NULL, 0);
14215 14222 if (vlen < 0)
14216 14223 scfdie();
14217 14224
14218 14225 buf = safe_malloc(vlen + 1);
14219 14226
14220 14227 szret = scf_value_get_as_string(val, buf, vlen + 1);
14221 14228 if (szret < 0)
14222 14229 scfdie();
14223 14230 assert(szret <= vlen);
14224 14231
14225 14232 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14226 14233 add_string(values, buf);
14227 14234
14228 14235 free(buf);
14229 14236 }
14230 14237
14231 14238 if (ret == -1)
14232 14239 scfdie();
14233 14240
14234 14241 scf_value_destroy(val);
14235 14242 scf_iter_destroy(iter);
14236 14243 }
14237 14244
14238 14245 static int
14239 14246 lscf_setpropvalue(const char *pgname, const char *type,
14240 14247 const char *arg, int isadd, int isnotfoundok)
14241 14248 {
14242 14249 scf_type_t ty;
14243 14250 scf_propertygroup_t *pg;
14244 14251 scf_property_t *prop;
14245 14252 int ret, result = 0;
14246 14253 scf_transaction_t *tx;
14247 14254 scf_transaction_entry_t *e;
14248 14255 scf_value_t *v;
14249 14256 string_list_t *sp;
14250 14257 char *propname;
14251 14258 uu_list_t *values;
14252 14259 uu_list_walk_t *walk;
14253 14260 void *cookie = NULL;
14254 14261 char *pattern = NULL;
14255 14262
14256 14263 lscf_prep_hndl();
14257 14264
14258 14265 if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14259 14266 uu_die(gettext("Could not create property list: %s\n"),
14260 14267 uu_strerror(uu_error()));
14261 14268
14262 14269 if (!isadd)
14263 14270 pattern = safe_strdup(arg);
14264 14271
14265 14272 if ((e = scf_entry_create(g_hndl)) == NULL ||
14266 14273 (pg = scf_pg_create(g_hndl)) == NULL ||
14267 14274 (prop = scf_property_create(g_hndl)) == NULL ||
14268 14275 (tx = scf_transaction_create(g_hndl)) == NULL)
14269 14276 scfdie();
14270 14277
14271 14278 if (cur_snap != NULL) {
14272 14279 semerr(emsg_cant_modify_snapshots);
14273 14280 goto fail;
14274 14281 }
14275 14282
14276 14283 if (cur_inst == NULL && cur_svc == NULL) {
14277 14284 semerr(emsg_entity_not_selected);
14278 14285 goto fail;
14279 14286 }
14280 14287
14281 14288 propname = strchr(pgname, '/');
14282 14289 if (propname == NULL) {
14283 14290 semerr(gettext("Property names must contain a `/'.\n"));
14284 14291 goto fail;
14285 14292 }
14286 14293
14287 14294 *propname = '\0';
14288 14295 ++propname;
14289 14296
14290 14297 if (type != NULL) {
14291 14298 ty = string_to_type(type);
14292 14299 if (ty == SCF_TYPE_INVALID) {
14293 14300 semerr(gettext("Unknown type \"%s\".\n"), type);
14294 14301 goto fail;
14295 14302 }
14296 14303 }
14297 14304
14298 14305 if (cur_inst != NULL)
14299 14306 ret = scf_instance_get_pg(cur_inst, pgname, pg);
14300 14307 else
14301 14308 ret = scf_service_get_pg(cur_svc, pgname, pg);
14302 14309 if (ret != 0) {
14303 14310 switch (scf_error()) {
14304 14311 case SCF_ERROR_NOT_FOUND:
14305 14312 if (isnotfoundok) {
14306 14313 result = 0;
14307 14314 } else {
14308 14315 semerr(emsg_no_such_pg, pgname);
14309 14316 result = -1;
14310 14317 }
14311 14318 goto out;
14312 14319
14313 14320 case SCF_ERROR_INVALID_ARGUMENT:
14314 14321 semerr(emsg_invalid_pg_name, pgname);
14315 14322 goto fail;
14316 14323
14317 14324 default:
14318 14325 scfdie();
14319 14326 }
14320 14327 }
14321 14328
14322 14329 do {
14323 14330 if (scf_pg_update(pg) == -1)
14324 14331 scfdie();
14325 14332 if (scf_transaction_start(tx, pg) != 0) {
14326 14333 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14327 14334 scfdie();
14328 14335
14329 14336 semerr(emsg_permission_denied);
14330 14337 goto fail;
14331 14338 }
14332 14339
14333 14340 ret = scf_pg_get_property(pg, propname, prop);
14334 14341 if (ret == 0) {
14335 14342 scf_type_t ptype;
14336 14343 char *pat = pattern;
14337 14344
14338 14345 if (scf_property_type(prop, &ptype) != 0)
14339 14346 scfdie();
14340 14347
14341 14348 if (isadd) {
14342 14349 if (type != NULL && ptype != ty) {
14343 14350 semerr(gettext("Property \"%s\" is not "
14344 14351 "of type \"%s\".\n"), propname,
14345 14352 type);
14346 14353 goto fail;
14347 14354 }
14348 14355
14349 14356 pat = NULL;
14350 14357 } else {
14351 14358 size_t len = strlen(pat);
14352 14359 if (len > 0 && pat[len - 1] == '\"')
14353 14360 pat[len - 1] = '\0';
14354 14361 if (len > 0 && pat[0] == '\"')
14355 14362 pat++;
14356 14363 }
14357 14364
14358 14365 ty = ptype;
14359 14366
14360 14367 get_prop_values(prop, values, pat);
14361 14368
14362 14369 if (isadd)
14363 14370 add_string(values, arg);
14364 14371
14365 14372 if (scf_transaction_property_change(tx, e,
14366 14373 propname, ty) == -1)
14367 14374 scfdie();
14368 14375 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14369 14376 if (isadd) {
14370 14377 if (type == NULL) {
14371 14378 semerr(gettext("Type required "
14372 14379 "for new properties.\n"));
14373 14380 goto fail;
14374 14381 }
14375 14382
14376 14383 add_string(values, arg);
14377 14384
14378 14385 if (scf_transaction_property_new(tx, e,
14379 14386 propname, ty) == -1)
14380 14387 scfdie();
14381 14388 } else if (isnotfoundok) {
14382 14389 result = 0;
14383 14390 goto out;
14384 14391 } else {
14385 14392 semerr(gettext("No such property %s/%s.\n"),
14386 14393 pgname, propname);
14387 14394 result = -1;
14388 14395 goto out;
14389 14396 }
14390 14397 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14391 14398 semerr(emsg_invalid_prop_name, propname);
14392 14399 goto fail;
14393 14400 } else {
14394 14401 scfdie();
14395 14402 }
14396 14403
14397 14404 walk = uu_list_walk_start(values, UU_DEFAULT);
14398 14405 if (walk == NULL)
14399 14406 uu_die(gettext("Could not walk property list.\n"));
14400 14407
14401 14408 for (sp = uu_list_walk_next(walk); sp != NULL;
14402 14409 sp = uu_list_walk_next(walk)) {
14403 14410 v = string_to_value(sp->str, ty, 0);
14404 14411
14405 14412 if (v == NULL) {
14406 14413 scf_entry_destroy_children(e);
14407 14414 goto fail;
14408 14415 }
14409 14416 ret = scf_entry_add_value(e, v);
14410 14417 assert(ret == 0);
14411 14418 }
14412 14419 uu_list_walk_end(walk);
14413 14420
14414 14421 result = scf_transaction_commit(tx);
14415 14422
14416 14423 scf_transaction_reset(tx);
14417 14424 scf_entry_destroy_children(e);
14418 14425 } while (result == 0);
14419 14426
14420 14427 if (result < 0) {
14421 14428 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14422 14429 scfdie();
14423 14430
14424 14431 semerr(emsg_permission_denied);
14425 14432 goto fail;
14426 14433 }
14427 14434
14428 14435 result = 0;
14429 14436
14430 14437 private_refresh();
14431 14438
14432 14439 out:
14433 14440 scf_transaction_destroy(tx);
14434 14441 scf_entry_destroy(e);
14435 14442 scf_pg_destroy(pg);
14436 14443 scf_property_destroy(prop);
14437 14444 free(pattern);
14438 14445
14439 14446 while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14440 14447 free(sp->str);
14441 14448 free(sp);
14442 14449 }
14443 14450
14444 14451 uu_list_destroy(values);
14445 14452
14446 14453 return (result);
14447 14454
14448 14455 fail:
14449 14456 result = -1;
14450 14457 goto out;
14451 14458 }
14452 14459
14453 14460 int
14454 14461 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14455 14462 {
14456 14463 return (lscf_setpropvalue(pgname, type, value, 1, 0));
14457 14464 }
14458 14465
14459 14466 int
14460 14467 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14461 14468 {
14462 14469 return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14463 14470 }
14464 14471
14465 14472 /*
14466 14473 * Look for a standard start method, first in the instance (if any),
14467 14474 * then the service.
14468 14475 */
14469 14476 static const char *
14470 14477 start_method_name(int *in_instance)
14471 14478 {
14472 14479 scf_propertygroup_t *pg;
14473 14480 char **p;
14474 14481 int ret;
14475 14482 scf_instance_t *inst = cur_inst;
14476 14483
14477 14484 if ((pg = scf_pg_create(g_hndl)) == NULL)
14478 14485 scfdie();
14479 14486
14480 14487 again:
14481 14488 for (p = start_method_names; *p != NULL; p++) {
14482 14489 if (inst != NULL)
14483 14490 ret = scf_instance_get_pg(inst, *p, pg);
14484 14491 else
14485 14492 ret = scf_service_get_pg(cur_svc, *p, pg);
14486 14493
14487 14494 if (ret == 0) {
14488 14495 size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14489 14496 char *buf = safe_malloc(bufsz);
14490 14497
14491 14498 if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14492 14499 free(buf);
14493 14500 continue;
14494 14501 }
14495 14502 if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14496 14503 free(buf);
14497 14504 continue;
14498 14505 }
14499 14506
14500 14507 free(buf);
14501 14508 *in_instance = (inst != NULL);
14502 14509 scf_pg_destroy(pg);
14503 14510 return (*p);
14504 14511 }
14505 14512
14506 14513 if (scf_error() == SCF_ERROR_NOT_FOUND)
14507 14514 continue;
14508 14515
14509 14516 scfdie();
14510 14517 }
14511 14518
14512 14519 if (inst != NULL) {
14513 14520 inst = NULL;
14514 14521 goto again;
14515 14522 }
14516 14523
14517 14524 scf_pg_destroy(pg);
14518 14525 return (NULL);
14519 14526 }
14520 14527
14521 14528 static int
14522 14529 addpg(const char *name, const char *type)
14523 14530 {
14524 14531 scf_propertygroup_t *pg;
14525 14532 int ret;
14526 14533
14527 14534 pg = scf_pg_create(g_hndl);
14528 14535 if (pg == NULL)
14529 14536 scfdie();
14530 14537
14531 14538 if (cur_inst != NULL)
14532 14539 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14533 14540 else
14534 14541 ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14535 14542
14536 14543 if (ret != 0) {
14537 14544 switch (scf_error()) {
14538 14545 case SCF_ERROR_EXISTS:
14539 14546 ret = 0;
14540 14547 break;
14541 14548
14542 14549 case SCF_ERROR_PERMISSION_DENIED:
14543 14550 semerr(emsg_permission_denied);
14544 14551 break;
14545 14552
14546 14553 default:
14547 14554 scfdie();
14548 14555 }
14549 14556 }
14550 14557
14551 14558 scf_pg_destroy(pg);
14552 14559 return (ret);
14553 14560 }
14554 14561
14555 14562 int
14556 14563 lscf_setenv(uu_list_t *args, int isunset)
14557 14564 {
14558 14565 int ret = 0;
14559 14566 size_t i;
14560 14567 int argc;
14561 14568 char **argv = NULL;
14562 14569 string_list_t *slp;
14563 14570 char *pattern;
14564 14571 char *prop;
14565 14572 int do_service = 0;
14566 14573 int do_instance = 0;
14567 14574 const char *method = NULL;
14568 14575 const char *name = NULL;
14569 14576 const char *value = NULL;
14570 14577 scf_instance_t *saved_cur_inst = cur_inst;
14571 14578
14572 14579 lscf_prep_hndl();
14573 14580
14574 14581 argc = uu_list_numnodes(args);
14575 14582 if (argc < 1)
14576 14583 goto usage;
14577 14584
14578 14585 argv = calloc(argc + 1, sizeof (char *));
14579 14586 if (argv == NULL)
14580 14587 uu_die(gettext("Out of memory.\n"));
14581 14588
14582 14589 for (slp = uu_list_first(args), i = 0;
14583 14590 slp != NULL;
14584 14591 slp = uu_list_next(args, slp), ++i)
14585 14592 argv[i] = slp->str;
14586 14593
14587 14594 argv[i] = NULL;
14588 14595
14589 14596 opterr = 0;
14590 14597 optind = 0;
14591 14598 for (;;) {
14592 14599 ret = getopt(argc, argv, "sim:");
14593 14600 if (ret == -1)
14594 14601 break;
14595 14602
14596 14603 switch (ret) {
14597 14604 case 's':
14598 14605 do_service = 1;
14599 14606 cur_inst = NULL;
14600 14607 break;
14601 14608
14602 14609 case 'i':
14603 14610 do_instance = 1;
14604 14611 break;
14605 14612
14606 14613 case 'm':
14607 14614 method = optarg;
14608 14615 break;
14609 14616
14610 14617 case '?':
14611 14618 goto usage;
14612 14619
14613 14620 default:
14614 14621 bad_error("getopt", ret);
14615 14622 }
14616 14623 }
14617 14624
14618 14625 argc -= optind;
14619 14626 if ((do_service && do_instance) ||
14620 14627 (isunset && argc != 1) ||
14621 14628 (!isunset && argc != 2))
14622 14629 goto usage;
14623 14630
14624 14631 name = argv[optind];
14625 14632 if (!isunset)
14626 14633 value = argv[optind + 1];
14627 14634
14628 14635 if (cur_snap != NULL) {
14629 14636 semerr(emsg_cant_modify_snapshots);
14630 14637 ret = -1;
14631 14638 goto out;
14632 14639 }
14633 14640
14634 14641 if (cur_inst == NULL && cur_svc == NULL) {
14635 14642 semerr(emsg_entity_not_selected);
14636 14643 ret = -1;
14637 14644 goto out;
14638 14645 }
14639 14646
14640 14647 if (do_instance && cur_inst == NULL) {
14641 14648 semerr(gettext("No instance is selected.\n"));
14642 14649 ret = -1;
14643 14650 goto out;
14644 14651 }
14645 14652
14646 14653 if (do_service && cur_svc == NULL) {
14647 14654 semerr(gettext("No service is selected.\n"));
14648 14655 ret = -1;
14649 14656 goto out;
14650 14657 }
14651 14658
14652 14659 if (method == NULL) {
14653 14660 if (do_instance || do_service) {
14654 14661 method = "method_context";
14655 14662 if (!isunset) {
14656 14663 ret = addpg("method_context",
14657 14664 SCF_GROUP_FRAMEWORK);
14658 14665 if (ret != 0)
14659 14666 goto out;
14660 14667 }
14661 14668 } else {
14662 14669 int in_instance;
14663 14670 method = start_method_name(&in_instance);
14664 14671 if (method == NULL) {
14665 14672 semerr(gettext(
14666 14673 "Couldn't find start method; please "
14667 14674 "specify a method with '-m'.\n"));
14668 14675 ret = -1;
14669 14676 goto out;
14670 14677 }
14671 14678 if (!in_instance)
14672 14679 cur_inst = NULL;
14673 14680 }
14674 14681 } else {
14675 14682 scf_propertygroup_t *pg;
14676 14683 size_t bufsz;
14677 14684 char *buf;
14678 14685 int ret;
14679 14686
14680 14687 if ((pg = scf_pg_create(g_hndl)) == NULL)
14681 14688 scfdie();
14682 14689
14683 14690 if (cur_inst != NULL)
14684 14691 ret = scf_instance_get_pg(cur_inst, method, pg);
14685 14692 else
14686 14693 ret = scf_service_get_pg(cur_svc, method, pg);
14687 14694
14688 14695 if (ret != 0) {
14689 14696 scf_pg_destroy(pg);
14690 14697 switch (scf_error()) {
14691 14698 case SCF_ERROR_NOT_FOUND:
14692 14699 semerr(gettext("Couldn't find the method "
14693 14700 "\"%s\".\n"), method);
14694 14701 goto out;
14695 14702
14696 14703 case SCF_ERROR_INVALID_ARGUMENT:
14697 14704 semerr(gettext("Invalid method name \"%s\".\n"),
14698 14705 method);
14699 14706 goto out;
14700 14707
14701 14708 default:
14702 14709 scfdie();
14703 14710 }
14704 14711 }
14705 14712
14706 14713 bufsz = strlen(SCF_GROUP_METHOD) + 1;
14707 14714 buf = safe_malloc(bufsz);
14708 14715
14709 14716 if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
14710 14717 strcmp(buf, SCF_GROUP_METHOD) != 0) {
14711 14718 semerr(gettext("Property group \"%s\" is not of type "
14712 14719 "\"method\".\n"), method);
14713 14720 ret = -1;
14714 14721 free(buf);
14715 14722 scf_pg_destroy(pg);
14716 14723 goto out;
14717 14724 }
14718 14725
14719 14726 free(buf);
14720 14727 scf_pg_destroy(pg);
14721 14728 }
14722 14729
14723 14730 prop = uu_msprintf("%s/environment", method);
14724 14731 pattern = uu_msprintf("%s=*", name);
14725 14732
14726 14733 if (prop == NULL || pattern == NULL)
14727 14734 uu_die(gettext("Out of memory.\n"));
14728 14735
14729 14736 ret = lscf_delpropvalue(prop, pattern, !isunset);
14730 14737
14731 14738 if (ret == 0 && !isunset) {
14732 14739 uu_free(pattern);
14733 14740 uu_free(prop);
14734 14741 prop = uu_msprintf("%s/environment", method);
14735 14742 pattern = uu_msprintf("%s=%s", name, value);
14736 14743 if (prop == NULL || pattern == NULL)
14737 14744 uu_die(gettext("Out of memory.\n"));
14738 14745 ret = lscf_addpropvalue(prop, "astring:", pattern);
14739 14746 }
14740 14747 uu_free(pattern);
14741 14748 uu_free(prop);
14742 14749
14743 14750 out:
14744 14751 cur_inst = saved_cur_inst;
14745 14752
14746 14753 free(argv);
14747 14754 return (ret);
14748 14755 usage:
14749 14756 ret = -2;
14750 14757 goto out;
14751 14758 }
14752 14759
14753 14760 /*
14754 14761 * Snapshot commands
14755 14762 */
14756 14763
14757 14764 void
14758 14765 lscf_listsnap()
14759 14766 {
14760 14767 scf_snapshot_t *snap;
14761 14768 scf_iter_t *iter;
14762 14769 char *nb;
14763 14770 int r;
14764 14771
14765 14772 lscf_prep_hndl();
14766 14773
14767 14774 if (cur_inst == NULL) {
14768 14775 semerr(gettext("Instance not selected.\n"));
14769 14776 return;
14770 14777 }
14771 14778
14772 14779 if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
14773 14780 (iter = scf_iter_create(g_hndl)) == NULL)
14774 14781 scfdie();
14775 14782
14776 14783 if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
14777 14784 scfdie();
14778 14785
14779 14786 nb = safe_malloc(max_scf_name_len + 1);
14780 14787
14781 14788 while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
14782 14789 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
14783 14790 scfdie();
14784 14791
14785 14792 (void) puts(nb);
14786 14793 }
14787 14794 if (r < 0)
14788 14795 scfdie();
14789 14796
14790 14797 free(nb);
14791 14798 scf_iter_destroy(iter);
14792 14799 scf_snapshot_destroy(snap);
14793 14800 }
14794 14801
14795 14802 void
14796 14803 lscf_selectsnap(const char *name)
14797 14804 {
14798 14805 scf_snapshot_t *snap;
14799 14806 scf_snaplevel_t *level;
14800 14807
14801 14808 lscf_prep_hndl();
14802 14809
14803 14810 if (cur_inst == NULL) {
14804 14811 semerr(gettext("Instance not selected.\n"));
14805 14812 return;
14806 14813 }
14807 14814
14808 14815 if (cur_snap != NULL) {
14809 14816 if (name != NULL) {
14810 14817 char *cur_snap_name;
14811 14818 boolean_t nochange;
14812 14819
14813 14820 cur_snap_name = safe_malloc(max_scf_name_len + 1);
14814 14821
14815 14822 if (scf_snapshot_get_name(cur_snap, cur_snap_name,
14816 14823 max_scf_name_len + 1) < 0)
14817 14824 scfdie();
14818 14825
14819 14826 nochange = strcmp(name, cur_snap_name) == 0;
14820 14827
14821 14828 free(cur_snap_name);
14822 14829
14823 14830 if (nochange)
14824 14831 return;
14825 14832 }
14826 14833
14827 14834 unselect_cursnap();
14828 14835 }
14829 14836
14830 14837 if (name == NULL)
14831 14838 return;
14832 14839
14833 14840 if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
14834 14841 (level = scf_snaplevel_create(g_hndl)) == NULL)
14835 14842 scfdie();
14836 14843
14837 14844 if (scf_instance_get_snapshot(cur_inst, name, snap) !=
14838 14845 SCF_SUCCESS) {
14839 14846 switch (scf_error()) {
14840 14847 case SCF_ERROR_INVALID_ARGUMENT:
14841 14848 semerr(gettext("Invalid name \"%s\".\n"), name);
14842 14849 break;
14843 14850
14844 14851 case SCF_ERROR_NOT_FOUND:
14845 14852 semerr(gettext("No such snapshot \"%s\".\n"), name);
14846 14853 break;
14847 14854
14848 14855 default:
14849 14856 scfdie();
14850 14857 }
14851 14858
14852 14859 scf_snaplevel_destroy(level);
14853 14860 scf_snapshot_destroy(snap);
14854 14861 return;
14855 14862 }
14856 14863
14857 14864 /* Load the snaplevels into our list. */
14858 14865 cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
14859 14866 if (cur_levels == NULL)
14860 14867 uu_die(gettext("Could not create list: %s\n"),
14861 14868 uu_strerror(uu_error()));
14862 14869
14863 14870 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
14864 14871 if (scf_error() != SCF_ERROR_NOT_FOUND)
14865 14872 scfdie();
14866 14873
14867 14874 semerr(gettext("Snapshot has no snaplevels.\n"));
14868 14875
14869 14876 scf_snaplevel_destroy(level);
14870 14877 scf_snapshot_destroy(snap);
14871 14878 return;
14872 14879 }
14873 14880
14874 14881 cur_snap = snap;
14875 14882
14876 14883 for (;;) {
14877 14884 cur_elt = safe_malloc(sizeof (*cur_elt));
14878 14885 uu_list_node_init(cur_elt, &cur_elt->list_node,
14879 14886 snaplevel_pool);
14880 14887 cur_elt->sl = level;
14881 14888 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
14882 14889 uu_die(gettext("libuutil error: %s\n"),
14883 14890 uu_strerror(uu_error()));
14884 14891
14885 14892 level = scf_snaplevel_create(g_hndl);
14886 14893 if (level == NULL)
14887 14894 scfdie();
14888 14895
14889 14896 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
14890 14897 level) != SCF_SUCCESS) {
14891 14898 if (scf_error() != SCF_ERROR_NOT_FOUND)
14892 14899 scfdie();
14893 14900
14894 14901 scf_snaplevel_destroy(level);
14895 14902 break;
14896 14903 }
14897 14904 }
14898 14905
14899 14906 cur_elt = uu_list_last(cur_levels);
14900 14907 cur_level = cur_elt->sl;
14901 14908 }
14902 14909
14903 14910 /*
14904 14911 * Copies the properties & values in src to dst. Assumes src won't change.
14905 14912 * Returns -1 if permission is denied, -2 if another transaction interrupts,
14906 14913 * and 0 on success.
14907 14914 *
14908 14915 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
14909 14916 * property, if it is copied and has type boolean. (See comment in
14910 14917 * lscf_revert()).
14911 14918 */
14912 14919 static int
14913 14920 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
14914 14921 uint8_t enabled)
14915 14922 {
14916 14923 scf_transaction_t *tx;
14917 14924 scf_iter_t *iter, *viter;
14918 14925 scf_property_t *prop;
14919 14926 scf_value_t *v;
14920 14927 char *nbuf;
14921 14928 int r;
14922 14929
14923 14930 tx = scf_transaction_create(g_hndl);
14924 14931 if (tx == NULL)
14925 14932 scfdie();
14926 14933
14927 14934 if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
14928 14935 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14929 14936 scfdie();
14930 14937
14931 14938 scf_transaction_destroy(tx);
14932 14939
14933 14940 return (-1);
14934 14941 }
14935 14942
14936 14943 if ((iter = scf_iter_create(g_hndl)) == NULL ||
14937 14944 (prop = scf_property_create(g_hndl)) == NULL ||
14938 14945 (viter = scf_iter_create(g_hndl)) == NULL)
14939 14946 scfdie();
14940 14947
14941 14948 nbuf = safe_malloc(max_scf_name_len + 1);
14942 14949
14943 14950 if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
14944 14951 scfdie();
14945 14952
14946 14953 for (;;) {
14947 14954 scf_transaction_entry_t *e;
14948 14955 scf_type_t ty;
14949 14956
14950 14957 r = scf_iter_next_property(iter, prop);
14951 14958 if (r == -1)
14952 14959 scfdie();
14953 14960 if (r == 0)
14954 14961 break;
14955 14962
14956 14963 e = scf_entry_create(g_hndl);
14957 14964 if (e == NULL)
14958 14965 scfdie();
14959 14966
14960 14967 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
14961 14968 scfdie();
14962 14969
14963 14970 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
14964 14971 scfdie();
14965 14972
14966 14973 if (scf_transaction_property_new(tx, e, nbuf,
14967 14974 ty) != SCF_SUCCESS)
14968 14975 scfdie();
14969 14976
14970 14977 if ((enabled == 0 || enabled == 1) &&
14971 14978 strcmp(nbuf, scf_property_enabled) == 0 &&
14972 14979 ty == SCF_TYPE_BOOLEAN) {
14973 14980 v = scf_value_create(g_hndl);
14974 14981 if (v == NULL)
14975 14982 scfdie();
14976 14983
14977 14984 scf_value_set_boolean(v, enabled);
14978 14985
14979 14986 if (scf_entry_add_value(e, v) != 0)
14980 14987 scfdie();
14981 14988 } else {
14982 14989 if (scf_iter_property_values(viter, prop) != 0)
14983 14990 scfdie();
14984 14991
14985 14992 for (;;) {
14986 14993 v = scf_value_create(g_hndl);
14987 14994 if (v == NULL)
14988 14995 scfdie();
14989 14996
14990 14997 r = scf_iter_next_value(viter, v);
14991 14998 if (r == -1)
14992 14999 scfdie();
14993 15000 if (r == 0) {
14994 15001 scf_value_destroy(v);
14995 15002 break;
14996 15003 }
14997 15004
14998 15005 if (scf_entry_add_value(e, v) != SCF_SUCCESS)
14999 15006 scfdie();
15000 15007 }
15001 15008 }
15002 15009 }
15003 15010
15004 15011 free(nbuf);
15005 15012 scf_iter_destroy(viter);
15006 15013 scf_property_destroy(prop);
15007 15014 scf_iter_destroy(iter);
15008 15015
15009 15016 r = scf_transaction_commit(tx);
15010 15017 if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
15011 15018 scfdie();
15012 15019
15013 15020 scf_transaction_destroy_children(tx);
15014 15021 scf_transaction_destroy(tx);
15015 15022
15016 15023 switch (r) {
15017 15024 case 1: return (0);
15018 15025 case 0: return (-2);
15019 15026 case -1: return (-1);
15020 15027
15021 15028 default:
15022 15029 abort();
15023 15030 }
15024 15031
15025 15032 /* NOTREACHED */
15026 15033 }
15027 15034
15028 15035 void
15029 15036 lscf_revert(const char *snapname)
15030 15037 {
15031 15038 scf_snapshot_t *snap, *prev;
15032 15039 scf_snaplevel_t *level, *nlevel;
15033 15040 scf_iter_t *iter;
15034 15041 scf_propertygroup_t *pg, *npg;
15035 15042 scf_property_t *prop;
15036 15043 scf_value_t *val;
15037 15044 char *nbuf, *tbuf;
15038 15045 uint8_t enabled;
15039 15046
15040 15047 lscf_prep_hndl();
15041 15048
15042 15049 if (cur_inst == NULL) {
15043 15050 semerr(gettext("Instance not selected.\n"));
15044 15051 return;
15045 15052 }
15046 15053
15047 15054 if (snapname != NULL) {
15048 15055 snap = scf_snapshot_create(g_hndl);
15049 15056 if (snap == NULL)
15050 15057 scfdie();
15051 15058
15052 15059 if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
15053 15060 SCF_SUCCESS) {
15054 15061 switch (scf_error()) {
15055 15062 case SCF_ERROR_INVALID_ARGUMENT:
15056 15063 semerr(gettext("Invalid snapshot name "
15057 15064 "\"%s\".\n"), snapname);
15058 15065 break;
15059 15066
15060 15067 case SCF_ERROR_NOT_FOUND:
15061 15068 semerr(gettext("No such snapshot.\n"));
15062 15069 break;
15063 15070
15064 15071 default:
15065 15072 scfdie();
15066 15073 }
15067 15074
15068 15075 scf_snapshot_destroy(snap);
15069 15076 return;
15070 15077 }
15071 15078 } else {
15072 15079 if (cur_snap != NULL) {
15073 15080 snap = cur_snap;
15074 15081 } else {
15075 15082 semerr(gettext("No snapshot selected.\n"));
15076 15083 return;
15077 15084 }
15078 15085 }
15079 15086
15080 15087 if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
15081 15088 (level = scf_snaplevel_create(g_hndl)) == NULL ||
15082 15089 (iter = scf_iter_create(g_hndl)) == NULL ||
15083 15090 (pg = scf_pg_create(g_hndl)) == NULL ||
15084 15091 (npg = scf_pg_create(g_hndl)) == NULL ||
15085 15092 (prop = scf_property_create(g_hndl)) == NULL ||
15086 15093 (val = scf_value_create(g_hndl)) == NULL)
15087 15094 scfdie();
15088 15095
15089 15096 nbuf = safe_malloc(max_scf_name_len + 1);
15090 15097 tbuf = safe_malloc(max_scf_pg_type_len + 1);
15091 15098
15092 15099 /* Take the "previous" snapshot before we blow away the properties. */
15093 15100 if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
15094 15101 if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
15095 15102 scfdie();
15096 15103 } else {
15097 15104 if (scf_error() != SCF_ERROR_NOT_FOUND)
15098 15105 scfdie();
15099 15106
15100 15107 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
15101 15108 scfdie();
15102 15109 }
15103 15110
15104 15111 /* Save general/enabled, since we're probably going to replace it. */
15105 15112 enabled = 2;
15106 15113 if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
15107 15114 scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
15108 15115 scf_property_get_value(prop, val) == 0)
15109 15116 (void) scf_value_get_boolean(val, &enabled);
15110 15117
15111 15118 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15112 15119 if (scf_error() != SCF_ERROR_NOT_FOUND)
15113 15120 scfdie();
15114 15121
15115 15122 goto out;
15116 15123 }
15117 15124
15118 15125 for (;;) {
15119 15126 boolean_t isinst;
15120 15127 uint32_t flags;
15121 15128 int r;
15122 15129
15123 15130 /* Clear the properties from the corresponding entity. */
15124 15131 isinst = snaplevel_is_instance(level);
15125 15132
15126 15133 if (!isinst)
15127 15134 r = scf_iter_service_pgs(iter, cur_svc);
15128 15135 else
15129 15136 r = scf_iter_instance_pgs(iter, cur_inst);
15130 15137 if (r != SCF_SUCCESS)
15131 15138 scfdie();
15132 15139
15133 15140 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15134 15141 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15135 15142 scfdie();
15136 15143
15137 15144 /* Skip nonpersistent pgs. */
15138 15145 if (flags & SCF_PG_FLAG_NONPERSISTENT)
15139 15146 continue;
15140 15147
15141 15148 if (scf_pg_delete(pg) != SCF_SUCCESS) {
15142 15149 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15143 15150 scfdie();
15144 15151
15145 15152 semerr(emsg_permission_denied);
15146 15153 goto out;
15147 15154 }
15148 15155 }
15149 15156 if (r == -1)
15150 15157 scfdie();
15151 15158
15152 15159 /* Copy the properties to the corresponding entity. */
15153 15160 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
15154 15161 scfdie();
15155 15162
15156 15163 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15157 15164 if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
15158 15165 scfdie();
15159 15166
15160 15167 if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
15161 15168 0)
15162 15169 scfdie();
15163 15170
15164 15171 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15165 15172 scfdie();
15166 15173
15167 15174 if (!isinst)
15168 15175 r = scf_service_add_pg(cur_svc, nbuf, tbuf,
15169 15176 flags, npg);
15170 15177 else
15171 15178 r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
15172 15179 flags, npg);
15173 15180 if (r != SCF_SUCCESS) {
15174 15181 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15175 15182 scfdie();
15176 15183
15177 15184 semerr(emsg_permission_denied);
15178 15185 goto out;
15179 15186 }
15180 15187
15181 15188 if ((enabled == 0 || enabled == 1) &&
15182 15189 strcmp(nbuf, scf_pg_general) == 0)
15183 15190 r = pg_copy(pg, npg, enabled);
15184 15191 else
15185 15192 r = pg_copy(pg, npg, 2);
15186 15193
15187 15194 switch (r) {
15188 15195 case 0:
15189 15196 break;
15190 15197
15191 15198 case -1:
15192 15199 semerr(emsg_permission_denied);
15193 15200 goto out;
15194 15201
15195 15202 case -2:
15196 15203 semerr(gettext(
15197 15204 "Interrupted by another change.\n"));
15198 15205 goto out;
15199 15206
15200 15207 default:
15201 15208 abort();
15202 15209 }
15203 15210 }
15204 15211 if (r == -1)
15205 15212 scfdie();
15206 15213
15207 15214 /* Get next level. */
15208 15215 nlevel = scf_snaplevel_create(g_hndl);
15209 15216 if (nlevel == NULL)
15210 15217 scfdie();
15211 15218
15212 15219 if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
15213 15220 SCF_SUCCESS) {
15214 15221 if (scf_error() != SCF_ERROR_NOT_FOUND)
15215 15222 scfdie();
15216 15223
15217 15224 scf_snaplevel_destroy(nlevel);
15218 15225 break;
15219 15226 }
15220 15227
15221 15228 scf_snaplevel_destroy(level);
15222 15229 level = nlevel;
15223 15230 }
15224 15231
15225 15232 if (snapname == NULL) {
15226 15233 lscf_selectsnap(NULL);
15227 15234 snap = NULL; /* cur_snap has been destroyed */
15228 15235 }
15229 15236
15230 15237 out:
15231 15238 free(tbuf);
15232 15239 free(nbuf);
15233 15240 scf_value_destroy(val);
15234 15241 scf_property_destroy(prop);
15235 15242 scf_pg_destroy(npg);
15236 15243 scf_pg_destroy(pg);
15237 15244 scf_iter_destroy(iter);
15238 15245 scf_snaplevel_destroy(level);
15239 15246 scf_snapshot_destroy(prev);
15240 15247 if (snap != cur_snap)
15241 15248 scf_snapshot_destroy(snap);
15242 15249 }
15243 15250
15244 15251 void
15245 15252 lscf_refresh(void)
15246 15253 {
15247 15254 ssize_t fmrilen;
15248 15255 size_t bufsz;
15249 15256 char *fmribuf;
15250 15257 int r;
15251 15258
15252 15259 lscf_prep_hndl();
15253 15260
15254 15261 if (cur_inst == NULL) {
15255 15262 semerr(gettext("Instance not selected.\n"));
15256 15263 return;
15257 15264 }
15258 15265
15259 15266 bufsz = max_scf_fmri_len + 1;
15260 15267 fmribuf = safe_malloc(bufsz);
15261 15268 fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15262 15269 if (fmrilen < 0) {
15263 15270 free(fmribuf);
15264 15271 if (scf_error() != SCF_ERROR_DELETED)
15265 15272 scfdie();
15266 15273 scf_instance_destroy(cur_inst);
15267 15274 cur_inst = NULL;
15268 15275 warn(emsg_deleted);
15269 15276 return;
15270 15277 }
15271 15278 assert(fmrilen < bufsz);
15272 15279
15273 15280 r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15274 15281 switch (r) {
15275 15282 case 0:
15276 15283 break;
15277 15284
15278 15285 case ECONNABORTED:
15279 15286 warn(gettext("Could not refresh %s "
15280 15287 "(repository connection broken).\n"), fmribuf);
15281 15288 break;
15282 15289
15283 15290 case ECANCELED:
15284 15291 warn(emsg_deleted);
15285 15292 break;
15286 15293
15287 15294 case EPERM:
15288 15295 warn(gettext("Could not refresh %s "
15289 15296 "(permission denied).\n"), fmribuf);
15290 15297 break;
15291 15298
15292 15299 case ENOSPC:
15293 15300 warn(gettext("Could not refresh %s "
15294 15301 "(repository server out of resources).\n"),
15295 15302 fmribuf);
15296 15303 break;
15297 15304
15298 15305 case EACCES:
15299 15306 default:
15300 15307 bad_error("refresh_entity", scf_error());
15301 15308 }
15302 15309
15303 15310 free(fmribuf);
15304 15311 }
15305 15312
15306 15313 /*
15307 15314 * describe [-v] [-t] [pg/prop]
15308 15315 */
15309 15316 int
15310 15317 lscf_describe(uu_list_t *args, int hasargs)
15311 15318 {
15312 15319 int ret = 0;
15313 15320 size_t i;
15314 15321 int argc;
15315 15322 char **argv = NULL;
15316 15323 string_list_t *slp;
15317 15324 int do_verbose = 0;
15318 15325 int do_templates = 0;
15319 15326 char *pattern = NULL;
15320 15327
15321 15328 lscf_prep_hndl();
15322 15329
15323 15330 if (hasargs != 0) {
15324 15331 argc = uu_list_numnodes(args);
15325 15332 if (argc < 1)
15326 15333 goto usage;
15327 15334
15328 15335 argv = calloc(argc + 1, sizeof (char *));
15329 15336 if (argv == NULL)
15330 15337 uu_die(gettext("Out of memory.\n"));
15331 15338
15332 15339 for (slp = uu_list_first(args), i = 0;
15333 15340 slp != NULL;
15334 15341 slp = uu_list_next(args, slp), ++i)
15335 15342 argv[i] = slp->str;
15336 15343
15337 15344 argv[i] = NULL;
15338 15345
15339 15346 /*
15340 15347 * We start optind = 0 because our list of arguments
15341 15348 * starts at argv[0]
15342 15349 */
15343 15350 optind = 0;
15344 15351 opterr = 0;
15345 15352 for (;;) {
15346 15353 ret = getopt(argc, argv, "vt");
15347 15354 if (ret == -1)
15348 15355 break;
15349 15356
15350 15357 switch (ret) {
15351 15358 case 'v':
15352 15359 do_verbose = 1;
15353 15360 break;
15354 15361
15355 15362 case 't':
15356 15363 do_templates = 1;
15357 15364 break;
15358 15365
15359 15366 case '?':
15360 15367 goto usage;
15361 15368
15362 15369 default:
15363 15370 bad_error("getopt", ret);
15364 15371 }
15365 15372 }
15366 15373
15367 15374 pattern = argv[optind];
15368 15375 }
15369 15376
15370 15377 if (cur_inst == NULL && cur_svc == NULL) {
15371 15378 semerr(emsg_entity_not_selected);
15372 15379 ret = -1;
15373 15380 goto out;
15374 15381 }
15375 15382
15376 15383 /*
15377 15384 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15378 15385 * output if their last parameter is set to 2. Less information is
15379 15386 * produced if the parameter is set to 1.
15380 15387 */
15381 15388 if (pattern == NULL) {
15382 15389 if (do_verbose == 1)
15383 15390 list_entity_tmpl(2);
15384 15391 else
15385 15392 list_entity_tmpl(1);
15386 15393 }
15387 15394
15388 15395 if (do_templates == 0) {
15389 15396 if (do_verbose == 1)
15390 15397 listprop(pattern, 0, 2);
15391 15398 else
15392 15399 listprop(pattern, 0, 1);
15393 15400 } else {
15394 15401 if (do_verbose == 1)
15395 15402 listtmpl(pattern, 2);
15396 15403 else
15397 15404 listtmpl(pattern, 1);
15398 15405 }
15399 15406
15400 15407 ret = 0;
15401 15408 out:
15402 15409 if (argv != NULL)
15403 15410 free(argv);
15404 15411 return (ret);
15405 15412 usage:
15406 15413 ret = -2;
15407 15414 goto out;
15408 15415 }
15409 15416
15410 15417 #define PARAM_ACTIVE ((const char *) "active")
15411 15418 #define PARAM_INACTIVE ((const char *) "inactive")
15412 15419 #define PARAM_SMTP_TO ((const char *) "to")
15413 15420
15414 15421 /*
15415 15422 * tokenize()
15416 15423 * Breaks down the string according to the tokens passed.
15417 15424 * Caller is responsible for freeing array of pointers returned.
15418 15425 * Returns NULL on failure
15419 15426 */
15420 15427 char **
15421 15428 tokenize(char *str, const char *sep)
15422 15429 {
15423 15430 char *token, *lasts;
15424 15431 char **buf;
15425 15432 int n = 0; /* number of elements */
15426 15433 int size = 8; /* size of the array (initial) */
15427 15434
15428 15435 buf = safe_malloc(size * sizeof (char *));
15429 15436
15430 15437 for (token = strtok_r(str, sep, &lasts); token != NULL;
15431 15438 token = strtok_r(NULL, sep, &lasts), ++n) {
15432 15439 if (n + 1 >= size) {
15433 15440 size *= 2;
15434 15441 if ((buf = realloc(buf, size * sizeof (char *))) ==
15435 15442 NULL) {
15436 15443 uu_die(gettext("Out of memory"));
15437 15444 }
15438 15445 }
15439 15446 buf[n] = token;
15440 15447 }
15441 15448 /* NULL terminate the pointer array */
15442 15449 buf[n] = NULL;
15443 15450
15444 15451 return (buf);
15445 15452 }
15446 15453
15447 15454 int32_t
15448 15455 check_tokens(char **p)
15449 15456 {
15450 15457 int32_t smf = 0;
15451 15458 int32_t fma = 0;
15452 15459
15453 15460 while (*p) {
15454 15461 int32_t t = string_to_tset(*p);
15455 15462
15456 15463 if (t == 0) {
15457 15464 if (is_fma_token(*p) == 0)
15458 15465 return (INVALID_TOKENS);
15459 15466 fma = 1; /* this token is an fma event */
15460 15467 } else {
15461 15468 smf |= t;
15462 15469 }
15463 15470
15464 15471 if (smf != 0 && fma == 1)
15465 15472 return (MIXED_TOKENS);
15466 15473 ++p;
15467 15474 }
15468 15475
15469 15476 if (smf > 0)
15470 15477 return (smf);
15471 15478 else if (fma == 1)
15472 15479 return (FMA_TOKENS);
15473 15480
15474 15481 return (INVALID_TOKENS);
15475 15482 }
15476 15483
15477 15484 static int
15478 15485 get_selection_str(char *fmri, size_t sz)
15479 15486 {
15480 15487 if (g_hndl == NULL) {
15481 15488 semerr(emsg_entity_not_selected);
15482 15489 return (-1);
15483 15490 } else if (cur_level != NULL) {
15484 15491 semerr(emsg_invalid_for_snapshot);
15485 15492 return (-1);
15486 15493 } else {
15487 15494 lscf_get_selection_str(fmri, sz);
15488 15495 }
15489 15496
15490 15497 return (0);
15491 15498 }
15492 15499
15493 15500 void
15494 15501 lscf_delnotify(const char *set, int global)
15495 15502 {
15496 15503 char *str = strdup(set);
15497 15504 char **pgs;
15498 15505 char **p;
15499 15506 int32_t tset;
15500 15507 char *fmri = NULL;
15501 15508
15502 15509 if (str == NULL)
15503 15510 uu_die(gettext("Out of memory.\n"));
15504 15511
15505 15512 pgs = tokenize(str, ",");
15506 15513
15507 15514 if ((tset = check_tokens(pgs)) > 0) {
15508 15515 size_t sz = max_scf_fmri_len + 1;
15509 15516
15510 15517 fmri = safe_malloc(sz);
15511 15518 if (global) {
15512 15519 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15513 15520 } else if (get_selection_str(fmri, sz) != 0) {
15514 15521 goto out;
15515 15522 }
15516 15523
15517 15524 if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri,
15518 15525 tset) != SCF_SUCCESS) {
15519 15526 uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15520 15527 scf_strerror(scf_error()));
15521 15528 }
15522 15529 } else if (tset == FMA_TOKENS) {
15523 15530 if (global) {
15524 15531 semerr(gettext("Can't use option '-g' with FMA event "
15525 15532 "definitions\n"));
15526 15533 goto out;
15527 15534 }
15528 15535
15529 15536 for (p = pgs; *p; ++p) {
15530 15537 if (smf_notify_del_params(de_tag(*p), NULL, 0) !=
15531 15538 SCF_SUCCESS) {
15532 15539 uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
15533 15540 scf_strerror(scf_error()));
15534 15541 goto out;
15535 15542 }
15536 15543 }
15537 15544 } else if (tset == MIXED_TOKENS) {
15538 15545 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15539 15546 goto out;
15540 15547 } else {
15541 15548 uu_die(gettext("Invalid input.\n"));
15542 15549 }
15543 15550
15544 15551 out:
15545 15552 free(fmri);
15546 15553 free(pgs);
15547 15554 free(str);
15548 15555 }
15549 15556
15550 15557 void
15551 15558 lscf_listnotify(const char *set, int global)
15552 15559 {
15553 15560 char *str = safe_strdup(set);
15554 15561 char **pgs;
15555 15562 char **p;
15556 15563 int32_t tset;
15557 15564 nvlist_t *nvl;
15558 15565 char *fmri = NULL;
15559 15566
15560 15567 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
15561 15568 uu_die(gettext("Out of memory.\n"));
15562 15569
15563 15570 pgs = tokenize(str, ",");
15564 15571
15565 15572 if ((tset = check_tokens(pgs)) > 0) {
15566 15573 size_t sz = max_scf_fmri_len + 1;
15567 15574
15568 15575 fmri = safe_malloc(sz);
15569 15576 if (global) {
15570 15577 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15571 15578 } else if (get_selection_str(fmri, sz) != 0) {
15572 15579 goto out;
15573 15580 }
15574 15581
15575 15582 if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
15576 15583 SCF_SUCCESS) {
15577 15584 if (scf_error() != SCF_ERROR_NOT_FOUND &&
15578 15585 scf_error() != SCF_ERROR_DELETED)
15579 15586 uu_warn(gettext(
15580 15587 "Failed listnotify: %s\n"),
15581 15588 scf_strerror(scf_error()));
15582 15589 goto out;
15583 15590 }
15584 15591
15585 15592 listnotify_print(nvl, NULL);
15586 15593 } else if (tset == FMA_TOKENS) {
15587 15594 if (global) {
15588 15595 semerr(gettext("Can't use option '-g' with FMA event "
15589 15596 "definitions\n"));
15590 15597 goto out;
15591 15598 }
15592 15599
15593 15600 for (p = pgs; *p; ++p) {
15594 15601 if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
15595 15602 SCF_SUCCESS) {
15596 15603 /*
15597 15604 * if the preferences have just been deleted
15598 15605 * or does not exist, just skip.
15599 15606 */
15600 15607 if (scf_error() == SCF_ERROR_NOT_FOUND ||
15601 15608 scf_error() == SCF_ERROR_DELETED)
15602 15609 continue;
15603 15610 uu_warn(gettext(
15604 15611 "Failed listnotify: %s\n"),
15605 15612 scf_strerror(scf_error()));
15606 15613 goto out;
15607 15614 }
15608 15615 listnotify_print(nvl, re_tag(*p));
15609 15616 }
15610 15617 } else if (tset == MIXED_TOKENS) {
15611 15618 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15612 15619 goto out;
15613 15620 } else {
15614 15621 semerr(gettext("Invalid input.\n"));
15615 15622 }
15616 15623
15617 15624 out:
15618 15625 nvlist_free(nvl);
15619 15626 free(fmri);
15620 15627 free(pgs);
15621 15628 free(str);
15622 15629 }
15623 15630
15624 15631 static char *
15625 15632 strip_quotes_and_blanks(char *s)
15626 15633 {
15627 15634 char *start = s;
15628 15635 char *end = strrchr(s, '\"');
15629 15636
15630 15637 if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
15631 15638 start = s + 1;
15632 15639 while (isblank(*start))
15633 15640 start++;
15634 15641 while (isblank(*(end - 1)) && end > start) {
15635 15642 end--;
15636 15643 }
15637 15644 *end = '\0';
15638 15645 }
15639 15646
15640 15647 return (start);
15641 15648 }
15642 15649
15643 15650 static int
15644 15651 set_active(nvlist_t *mech, const char *hier_part)
15645 15652 {
15646 15653 boolean_t b;
15647 15654
15648 15655 if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
15649 15656 b = B_TRUE;
15650 15657 } else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
15651 15658 b = B_FALSE;
15652 15659 } else {
15653 15660 return (-1);
15654 15661 }
15655 15662
15656 15663 if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
15657 15664 uu_die(gettext("Out of memory.\n"));
15658 15665
15659 15666 return (0);
15660 15667 }
15661 15668
15662 15669 static int
15663 15670 add_snmp_params(nvlist_t *mech, char *hier_part)
15664 15671 {
15665 15672 return (set_active(mech, hier_part));
15666 15673 }
15667 15674
15668 15675 static int
15669 15676 add_syslog_params(nvlist_t *mech, char *hier_part)
15670 15677 {
15671 15678 return (set_active(mech, hier_part));
15672 15679 }
15673 15680
15674 15681 /*
15675 15682 * add_mailto_paramas()
15676 15683 * parse the hier_part of mailto URI
15677 15684 * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
15678 15685 * or mailto:{[active]|inactive}
15679 15686 */
15680 15687 static int
15681 15688 add_mailto_params(nvlist_t *mech, char *hier_part)
15682 15689 {
15683 15690 const char *tok = "?&";
15684 15691 char *p;
15685 15692 char *lasts;
15686 15693 char *param;
15687 15694 char *val;
15688 15695
15689 15696 /*
15690 15697 * If the notification parametes are in the form of
15691 15698 *
15692 15699 * malito:{[active]|inactive}
15693 15700 *
15694 15701 * we set the property accordingly and return.
15695 15702 * Otherwise, we make the notification type active and
15696 15703 * process the hier_part.
15697 15704 */
15698 15705 if (set_active(mech, hier_part) == 0)
15699 15706 return (0);
15700 15707 else if (set_active(mech, PARAM_ACTIVE) != 0)
15701 15708 return (-1);
15702 15709
15703 15710 if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) {
15704 15711 /*
15705 15712 * sanity check: we only get here if hier_part = "", but
15706 15713 * that's handled by set_active
15707 15714 */
15708 15715 uu_die("strtok_r");
15709 15716 }
15710 15717
15711 15718 if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0)
15712 15719 uu_die(gettext("Out of memory.\n"));
15713 15720
15714 15721 while ((p = strtok_r(NULL, tok, &lasts)) != NULL)
15715 15722 if ((param = strtok_r(p, "=", &val)) != NULL)
15716 15723 if (nvlist_add_string(mech, param, val) != 0)
15717 15724 uu_die(gettext("Out of memory.\n"));
15718 15725
15719 15726 return (0);
15720 15727 }
15721 15728
15722 15729 static int
15723 15730 uri_split(char *uri, char **scheme, char **hier_part)
15724 15731 {
15725 15732 int r = -1;
15726 15733
15727 15734 if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
15728 15735 *hier_part == NULL) {
15729 15736 semerr(gettext("'%s' is not an URI\n"), uri);
15730 15737 return (r);
15731 15738 }
15732 15739
15733 15740 if ((r = check_uri_scheme(*scheme)) < 0) {
15734 15741 semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
15735 15742 return (r);
15736 15743 }
15737 15744
15738 15745 return (r);
15739 15746 }
15740 15747
15741 15748 static int
15742 15749 process_uri(nvlist_t *params, char *uri)
15743 15750 {
15744 15751 char *scheme;
15745 15752 char *hier_part;
15746 15753 nvlist_t *mech;
15747 15754 int index;
15748 15755 int r;
15749 15756
15750 15757 if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
15751 15758 return (-1);
15752 15759
15753 15760 if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
15754 15761 uu_die(gettext("Out of memory.\n"));
15755 15762
15756 15763 switch (index) {
15757 15764 case 0:
15758 15765 /* error messages displayed by called function */
15759 15766 r = add_mailto_params(mech, hier_part);
15760 15767 break;
15761 15768
15762 15769 case 1:
15763 15770 if ((r = add_snmp_params(mech, hier_part)) != 0)
15764 15771 semerr(gettext("Not valid parameters: '%s'\n"),
15765 15772 hier_part);
15766 15773 break;
15767 15774
15768 15775 case 2:
15769 15776 if ((r = add_syslog_params(mech, hier_part)) != 0)
15770 15777 semerr(gettext("Not valid parameters: '%s'\n"),
15771 15778 hier_part);
15772 15779 break;
15773 15780
15774 15781 default:
15775 15782 r = -1;
15776 15783 }
15777 15784
15778 15785 if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
15779 15786 mech) != 0)
15780 15787 uu_die(gettext("Out of memory.\n"));
15781 15788
15782 15789 nvlist_free(mech);
15783 15790 return (r);
15784 15791 }
15785 15792
15786 15793 static int
15787 15794 set_params(nvlist_t *params, char **p)
15788 15795 {
15789 15796 char *uri;
15790 15797
15791 15798 if (p == NULL)
15792 15799 /* sanity check */
15793 15800 uu_die("set_params");
15794 15801
15795 15802 while (*p) {
15796 15803 uri = strip_quotes_and_blanks(*p);
15797 15804 if (process_uri(params, uri) != 0)
15798 15805 return (-1);
15799 15806
15800 15807 ++p;
15801 15808 }
15802 15809
15803 15810 return (0);
15804 15811 }
15805 15812
15806 15813 static int
15807 15814 setnotify(const char *e, char **p, int global)
15808 15815 {
15809 15816 char *str = safe_strdup(e);
15810 15817 char **events;
15811 15818 int32_t tset;
15812 15819 int r = -1;
15813 15820 nvlist_t *nvl, *params;
15814 15821 char *fmri = NULL;
15815 15822
15816 15823 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
15817 15824 nvlist_alloc(¶ms, NV_UNIQUE_NAME, 0) != 0 ||
15818 15825 nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
15819 15826 SCF_NOTIFY_PARAMS_VERSION) != 0)
15820 15827 uu_die(gettext("Out of memory.\n"));
15821 15828
15822 15829 events = tokenize(str, ",");
15823 15830
15824 15831 if ((tset = check_tokens(events)) > 0) {
15825 15832 /* SMF state transitions parameters */
15826 15833 size_t sz = max_scf_fmri_len + 1;
15827 15834
15828 15835 fmri = safe_malloc(sz);
15829 15836 if (global) {
15830 15837 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15831 15838 } else if (get_selection_str(fmri, sz) != 0) {
15832 15839 goto out;
15833 15840 }
15834 15841
15835 15842 if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 ||
15836 15843 nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0)
15837 15844 uu_die(gettext("Out of memory.\n"));
15838 15845
15839 15846 if ((r = set_params(params, p)) == 0) {
15840 15847 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS,
15841 15848 params) != 0)
15842 15849 uu_die(gettext("Out of memory.\n"));
15843 15850
15844 15851 if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
15845 15852 nvl) != SCF_SUCCESS) {
15846 15853 r = -1;
15847 15854 uu_warn(gettext(
15848 15855 "Failed smf_notify_set_params(3SCF): %s\n"),
15849 15856 scf_strerror(scf_error()));
15850 15857 }
15851 15858 }
15852 15859 } else if (tset == FMA_TOKENS) {
15853 15860 /* FMA event parameters */
15854 15861 if (global) {
15855 15862 semerr(gettext("Can't use option '-g' with FMA event "
15856 15863 "definitions\n"));
15857 15864 goto out;
15858 15865 }
15859 15866
15860 15867 if ((r = set_params(params, p)) != 0)
15861 15868 goto out;
15862 15869
15863 15870 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
15864 15871 uu_die(gettext("Out of memory.\n"));
15865 15872
15866 15873 while (*events) {
15867 15874 if (smf_notify_set_params(de_tag(*events), nvl) !=
15868 15875 SCF_SUCCESS)
15869 15876 uu_warn(gettext(
15870 15877 "Failed smf_notify_set_params(3SCF) for "
15871 15878 "event %s: %s\n"), *events,
15872 15879 scf_strerror(scf_error()));
15873 15880 events++;
15874 15881 }
15875 15882 } else if (tset == MIXED_TOKENS) {
15876 15883 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15877 15884 } else {
15878 15885 /* Sanity check */
15879 15886 uu_die(gettext("Invalid input.\n"));
15880 15887 }
15881 15888
15882 15889 out:
15883 15890 nvlist_free(nvl);
15884 15891 nvlist_free(params);
15885 15892 free(fmri);
15886 15893 free(str);
15887 15894
15888 15895 return (r);
15889 15896 }
15890 15897
15891 15898 int
15892 15899 lscf_setnotify(uu_list_t *args)
15893 15900 {
15894 15901 int argc;
15895 15902 char **argv = NULL;
15896 15903 string_list_t *slp;
15897 15904 int global;
15898 15905 char *events;
15899 15906 char **p;
15900 15907 int i;
15901 15908 int ret;
15902 15909
15903 15910 if ((argc = uu_list_numnodes(args)) < 2)
15904 15911 goto usage;
15905 15912
15906 15913 argv = calloc(argc + 1, sizeof (char *));
15907 15914 if (argv == NULL)
15908 15915 uu_die(gettext("Out of memory.\n"));
15909 15916
15910 15917 for (slp = uu_list_first(args), i = 0;
15911 15918 slp != NULL;
15912 15919 slp = uu_list_next(args, slp), ++i)
15913 15920 argv[i] = slp->str;
15914 15921
15915 15922 argv[i] = NULL;
15916 15923
15917 15924 if (strcmp(argv[0], "-g") == 0) {
15918 15925 global = 1;
15919 15926 events = argv[1];
15920 15927 p = argv + 2;
15921 15928 } else {
15922 15929 global = 0;
15923 15930 events = argv[0];
15924 15931 p = argv + 1;
15925 15932 }
15926 15933
15927 15934 ret = setnotify(events, p, global);
15928 15935
15929 15936 out:
15930 15937 free(argv);
15931 15938 return (ret);
15932 15939
15933 15940 usage:
15934 15941 ret = -2;
15935 15942 goto out;
15936 15943 }
15937 15944
15938 15945 /*
15939 15946 * Creates a list of instance name strings associated with a service. If
15940 15947 * wohandcrafted flag is set, get only instances that have a last-import
15941 15948 * snapshot, instances that were imported via svccfg.
15942 15949 */
15943 15950 static uu_list_t *
15944 15951 create_instance_list(scf_service_t *svc, int wohandcrafted)
15945 15952 {
15946 15953 scf_snapshot_t *snap = NULL;
15947 15954 scf_instance_t *inst;
15948 15955 scf_iter_t *inst_iter;
15949 15956 uu_list_t *instances;
15950 15957 char *instname;
15951 15958 int r;
15952 15959
15953 15960 inst_iter = scf_iter_create(g_hndl);
15954 15961 inst = scf_instance_create(g_hndl);
15955 15962 if (inst_iter == NULL || inst == NULL) {
15956 15963 uu_warn(gettext("Could not create instance or iterator\n"));
15957 15964 scfdie();
15958 15965 }
15959 15966
15960 15967 if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
15961 15968 return (instances);
15962 15969
15963 15970 if (scf_iter_service_instances(inst_iter, svc) != 0) {
15964 15971 switch (scf_error()) {
15965 15972 case SCF_ERROR_CONNECTION_BROKEN:
15966 15973 case SCF_ERROR_DELETED:
15967 15974 uu_list_destroy(instances);
15968 15975 instances = NULL;
15969 15976 goto out;
15970 15977
15971 15978 case SCF_ERROR_HANDLE_MISMATCH:
15972 15979 case SCF_ERROR_NOT_BOUND:
15973 15980 case SCF_ERROR_NOT_SET:
15974 15981 default:
15975 15982 bad_error("scf_iter_service_instances", scf_error());
15976 15983 }
15977 15984 }
15978 15985
15979 15986 instname = safe_malloc(max_scf_name_len + 1);
15980 15987 while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
15981 15988 if (r == -1) {
15982 15989 (void) uu_warn(gettext("Unable to iterate through "
15983 15990 "instances to create instance list : %s\n"),
15984 15991 scf_strerror(scf_error()));
15985 15992
15986 15993 uu_list_destroy(instances);
15987 15994 instances = NULL;
15988 15995 goto out;
15989 15996 }
15990 15997
15991 15998 /*
15992 15999 * If the instance does not have a last-import snapshot
15993 16000 * then do not add it to the list as it is a hand-crafted
15994 16001 * instance that should not be managed.
15995 16002 */
15996 16003 if (wohandcrafted) {
15997 16004 if (snap == NULL &&
15998 16005 (snap = scf_snapshot_create(g_hndl)) == NULL) {
15999 16006 uu_warn(gettext("Unable to create snapshot "
16000 16007 "entity\n"));
16001 16008 scfdie();
16002 16009 }
16003 16010
16004 16011 if (scf_instance_get_snapshot(inst,
16005 16012 snap_lastimport, snap) != 0) {
16006 16013 switch (scf_error()) {
16007 16014 case SCF_ERROR_NOT_FOUND :
16008 16015 case SCF_ERROR_DELETED:
16009 16016 continue;
16010 16017
16011 16018 case SCF_ERROR_CONNECTION_BROKEN:
16012 16019 uu_list_destroy(instances);
16013 16020 instances = NULL;
16014 16021 goto out;
16015 16022
16016 16023 case SCF_ERROR_HANDLE_MISMATCH:
16017 16024 case SCF_ERROR_NOT_BOUND:
16018 16025 case SCF_ERROR_NOT_SET:
16019 16026 default:
16020 16027 bad_error("scf_iter_service_instances",
16021 16028 scf_error());
16022 16029 }
16023 16030 }
16024 16031 }
16025 16032
16026 16033 if (scf_instance_get_name(inst, instname,
16027 16034 max_scf_name_len + 1) < 0) {
16028 16035 switch (scf_error()) {
16029 16036 case SCF_ERROR_NOT_FOUND :
16030 16037 continue;
16031 16038
16032 16039 case SCF_ERROR_CONNECTION_BROKEN:
16033 16040 case SCF_ERROR_DELETED:
16034 16041 uu_list_destroy(instances);
16035 16042 instances = NULL;
16036 16043 goto out;
16037 16044
16038 16045 case SCF_ERROR_HANDLE_MISMATCH:
16039 16046 case SCF_ERROR_NOT_BOUND:
16040 16047 case SCF_ERROR_NOT_SET:
16041 16048 default:
16042 16049 bad_error("scf_iter_service_instances",
16043 16050 scf_error());
16044 16051 }
16045 16052 }
16046 16053
16047 16054 add_string(instances, instname);
16048 16055 }
16049 16056
16050 16057 out:
16051 16058 if (snap)
16052 16059 scf_snapshot_destroy(snap);
16053 16060
16054 16061 scf_instance_destroy(inst);
16055 16062 scf_iter_destroy(inst_iter);
16056 16063 free(instname);
16057 16064 return (instances);
16058 16065 }
16059 16066
16060 16067 /*
16061 16068 * disable an instance but wait for the instance to
16062 16069 * move out of the running state.
16063 16070 *
16064 16071 * Returns 0 : if the instance did not disable
16065 16072 * Returns non-zero : if the instance disabled.
16066 16073 *
16067 16074 */
16068 16075 static int
16069 16076 disable_instance(scf_instance_t *instance)
16070 16077 {
16071 16078 char *fmribuf;
16072 16079 int enabled = 10000;
16073 16080
16074 16081 if (inst_is_running(instance)) {
16075 16082 fmribuf = safe_malloc(max_scf_name_len + 1);
16076 16083 if (scf_instance_to_fmri(instance, fmribuf,
16077 16084 max_scf_name_len + 1) < 0) {
16078 16085 free(fmribuf);
16079 16086 return (0);
16080 16087 }
16081 16088
16082 16089 /*
16083 16090 * If the instance cannot be disabled then return
16084 16091 * failure to disable and let the caller decide
16085 16092 * if that is of importance.
16086 16093 */
16087 16094 if (smf_disable_instance(fmribuf, 0) != 0) {
16088 16095 free(fmribuf);
16089 16096 return (0);
16090 16097 }
16091 16098
16092 16099 while (enabled) {
16093 16100 if (!inst_is_running(instance))
16094 16101 break;
16095 16102
16096 16103 (void) poll(NULL, 0, 5);
16097 16104 enabled = enabled - 5;
16098 16105 }
16099 16106
16100 16107 free(fmribuf);
16101 16108 }
16102 16109
16103 16110 return (enabled);
16104 16111 }
16105 16112
16106 16113 /*
16107 16114 * Function to compare two service_manifest structures.
16108 16115 */
16109 16116 /* ARGSUSED2 */
16110 16117 static int
16111 16118 service_manifest_compare(const void *left, const void *right, void *unused)
16112 16119 {
16113 16120 service_manifest_t *l = (service_manifest_t *)left;
16114 16121 service_manifest_t *r = (service_manifest_t *)right;
16115 16122 int rc;
16116 16123
16117 16124 rc = strcmp(l->servicename, r->servicename);
16118 16125
16119 16126 return (rc);
16120 16127 }
16121 16128
16122 16129 /*
16123 16130 * Look for the provided service in the service to manifest
16124 16131 * tree. If the service exists, and a manifest was provided
16125 16132 * then add the manifest to that service. If the service
16126 16133 * does not exist, then add the service and manifest to the
16127 16134 * list.
16128 16135 *
16129 16136 * If the manifest is NULL, return the element if found. If
16130 16137 * the service is not found return NULL.
16131 16138 */
16132 16139 service_manifest_t *
16133 16140 find_add_svc_mfst(const char *svnbuf, const char *mfst)
16134 16141 {
16135 16142 service_manifest_t elem;
16136 16143 service_manifest_t *fnelem;
16137 16144 uu_avl_index_t marker;
16138 16145
16139 16146 elem.servicename = svnbuf;
16140 16147 fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
16141 16148
16142 16149 if (mfst) {
16143 16150 if (fnelem) {
16144 16151 add_string(fnelem->mfstlist, strdup(mfst));
16145 16152 } else {
16146 16153 fnelem = safe_malloc(sizeof (*fnelem));
16147 16154 fnelem->servicename = safe_strdup(svnbuf);
16148 16155 if ((fnelem->mfstlist =
16149 16156 uu_list_create(string_pool, NULL, 0)) == NULL)
16150 16157 uu_die(gettext("Could not create property "
16151 16158 "list: %s\n"), uu_strerror(uu_error()));
16152 16159
16153 16160 add_string(fnelem->mfstlist, safe_strdup(mfst));
16154 16161
16155 16162 uu_avl_insert(service_manifest_tree, fnelem, marker);
16156 16163 }
16157 16164 }
16158 16165
16159 16166 return (fnelem);
16160 16167 }
16161 16168
16162 16169 /*
16163 16170 * Create the service to manifest avl tree.
16164 16171 *
16165 16172 * Walk each of the manifests currently installed in the supported
16166 16173 * directories, /lib/svc/manifests and /var/svc/manifests. For
16167 16174 * each of the manifests, inventory the services and add them to
16168 16175 * the tree.
16169 16176 *
16170 16177 * Code that calls this function should make sure fileystem/minimal is online,
16171 16178 * /var is available, since this function walks the /var/svc/manifest directory.
16172 16179 */
16173 16180 static void
16174 16181 create_manifest_tree(void)
16175 16182 {
16176 16183 manifest_info_t **entry;
16177 16184 manifest_info_t **manifests;
16178 16185 uu_list_walk_t *svcs;
16179 16186 bundle_t *b;
16180 16187 entity_t *mfsvc;
16181 16188 char *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
16182 16189 int c, status;
16183 16190
16184 16191 if (service_manifest_pool)
16185 16192 return;
16186 16193
16187 16194 /*
16188 16195 * Create the list pool for the service manifest list
16189 16196 */
16190 16197 service_manifest_pool = uu_avl_pool_create("service_manifest",
16191 16198 sizeof (service_manifest_t),
16192 16199 offsetof(service_manifest_t, svcmfst_node),
16193 16200 service_manifest_compare, UU_DEFAULT);
16194 16201 if (service_manifest_pool == NULL)
16195 16202 uu_die(gettext("service_manifest pool creation failed: %s\n"),
16196 16203 uu_strerror(uu_error()));
16197 16204
16198 16205 /*
16199 16206 * Create the list
16200 16207 */
16201 16208 service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
16202 16209 UU_DEFAULT);
16203 16210 if (service_manifest_tree == NULL)
16204 16211 uu_die(gettext("service_manifest tree creation failed: %s\n"),
16205 16212 uu_strerror(uu_error()));
16206 16213
16207 16214 /*
16208 16215 * Walk the manifests adding the service(s) from each manifest.
16209 16216 *
16210 16217 * If a service already exists add the manifest to the manifest
16211 16218 * list for that service. This covers the case of a service that
16212 16219 * is supported by multiple manifest files.
16213 16220 */
16214 16221 for (c = 0; dirs[c]; c++) {
16215 16222 status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT);
16216 16223 if (status < 0) {
16217 16224 uu_warn(gettext("file tree walk of %s encountered "
16218 16225 "error %s\n"), dirs[c], strerror(errno));
16219 16226
16220 16227 uu_avl_destroy(service_manifest_tree);
16221 16228 service_manifest_tree = NULL;
16222 16229 return;
16223 16230 }
16224 16231
16225 16232 /*
16226 16233 * If a manifest that was in the list is not found
16227 16234 * then skip and go to the next manifest file.
16228 16235 */
16229 16236 if (manifests != NULL) {
16230 16237 for (entry = manifests; *entry != NULL; entry++) {
16231 16238 b = internal_bundle_new();
16232 16239 if (lxml_get_bundle_file(b, (*entry)->mi_path,
16233 16240 SVCCFG_OP_IMPORT) != 0) {
16234 16241 internal_bundle_free(b);
16235 16242 continue;
16236 16243 }
16237 16244
16238 16245 svcs = uu_list_walk_start(b->sc_bundle_services,
16239 16246 0);
16240 16247 if (svcs == NULL) {
16241 16248 internal_bundle_free(b);
16242 16249 continue;
16243 16250 }
16244 16251
16245 16252 while ((mfsvc = uu_list_walk_next(svcs)) !=
16246 16253 NULL) {
16247 16254 /* Add manifest to service */
16248 16255 (void) find_add_svc_mfst(mfsvc->sc_name,
16249 16256 (*entry)->mi_path);
16250 16257 }
16251 16258
16252 16259 uu_list_walk_end(svcs);
16253 16260 internal_bundle_free(b);
16254 16261 }
16255 16262
16256 16263 free_manifest_array(manifests);
16257 16264 }
16258 16265 }
16259 16266 }
16260 16267
16261 16268 /*
16262 16269 * Check the manifest history file to see
16263 16270 * if the service was ever installed from
16264 16271 * one of the supported directories.
16265 16272 *
16266 16273 * Return Values :
16267 16274 * -1 - if there's error reading manifest history file
16268 16275 * 1 - if the service is not found
16269 16276 * 0 - if the service is found
16270 16277 */
16271 16278 static int
16272 16279 check_mfst_history(const char *svcname)
16273 16280 {
16274 16281 struct stat st;
16275 16282 caddr_t mfsthist_start;
16276 16283 char *svnbuf;
16277 16284 int fd;
16278 16285 int r = 1;
16279 16286
16280 16287 fd = open(MFSTHISTFILE, O_RDONLY);
16281 16288 if (fd == -1) {
16282 16289 uu_warn(gettext("Unable to open the history file\n"));
16283 16290 return (-1);
16284 16291 }
16285 16292
16286 16293 if (fstat(fd, &st) == -1) {
16287 16294 uu_warn(gettext("Unable to stat the history file\n"));
16288 16295 return (-1);
16289 16296 }
16290 16297
16291 16298 mfsthist_start = mmap(0, st.st_size, PROT_READ,
16292 16299 MAP_PRIVATE, fd, 0);
16293 16300
16294 16301 (void) close(fd);
16295 16302 if (mfsthist_start == MAP_FAILED ||
16296 16303 *(mfsthist_start + st.st_size) != '\0') {
16297 16304 (void) munmap(mfsthist_start, st.st_size);
16298 16305 return (-1);
16299 16306 }
16300 16307
16301 16308 /*
16302 16309 * The manifest history file is a space delimited list
16303 16310 * of service and instance to manifest linkage. Adding
16304 16311 * a space to the end of the service name so to get only
16305 16312 * the service that is being searched for.
16306 16313 */
16307 16314 svnbuf = uu_msprintf("%s ", svcname);
16308 16315 if (svnbuf == NULL)
16309 16316 uu_die(gettext("Out of memory"));
16310 16317
16311 16318 if (strstr(mfsthist_start, svnbuf) != NULL)
16312 16319 r = 0;
16313 16320
16314 16321 (void) munmap(mfsthist_start, st.st_size);
16315 16322 uu_free(svnbuf);
16316 16323 return (r);
16317 16324 }
16318 16325
16319 16326 /*
16320 16327 * Take down each of the instances in the service
16321 16328 * and remove them, then delete the service.
16322 16329 */
16323 16330 static void
16324 16331 teardown_service(scf_service_t *svc, const char *svnbuf)
16325 16332 {
16326 16333 scf_instance_t *instance;
16327 16334 scf_iter_t *iter;
16328 16335 int r;
16329 16336
16330 16337 safe_printf(gettext("Delete service %s as there are no "
16331 16338 "supporting manifests\n"), svnbuf);
16332 16339
16333 16340 instance = scf_instance_create(g_hndl);
16334 16341 iter = scf_iter_create(g_hndl);
16335 16342 if (iter == NULL || instance == NULL) {
16336 16343 uu_warn(gettext("Unable to create supporting entities to "
16337 16344 "teardown the service\n"));
16338 16345 uu_warn(gettext("scf error is : %s\n"),
16339 16346 scf_strerror(scf_error()));
16340 16347 scfdie();
16341 16348 }
16342 16349
16343 16350 if (scf_iter_service_instances(iter, svc) != 0) {
16344 16351 switch (scf_error()) {
16345 16352 case SCF_ERROR_CONNECTION_BROKEN:
16346 16353 case SCF_ERROR_DELETED:
16347 16354 goto out;
16348 16355
16349 16356 case SCF_ERROR_HANDLE_MISMATCH:
16350 16357 case SCF_ERROR_NOT_BOUND:
16351 16358 case SCF_ERROR_NOT_SET:
16352 16359 default:
16353 16360 bad_error("scf_iter_service_instances",
16354 16361 scf_error());
16355 16362 }
16356 16363 }
16357 16364
16358 16365 while ((r = scf_iter_next_instance(iter, instance)) != 0) {
16359 16366 if (r == -1) {
16360 16367 uu_warn(gettext("Error - %s\n"),
16361 16368 scf_strerror(scf_error()));
16362 16369 goto out;
16363 16370 }
16364 16371
16365 16372 (void) disable_instance(instance);
16366 16373 }
16367 16374
16368 16375 /*
16369 16376 * Delete the service... forcing the deletion in case
16370 16377 * any of the instances did not disable.
16371 16378 */
16372 16379 (void) lscf_service_delete(svc, 1);
16373 16380 out:
16374 16381 scf_instance_destroy(instance);
16375 16382 scf_iter_destroy(iter);
16376 16383 }
16377 16384
16378 16385 /*
16379 16386 * Get the list of instances supported by the manifest
16380 16387 * file.
16381 16388 *
16382 16389 * Return 0 if there are no instances.
16383 16390 *
16384 16391 * Return -1 if there are errors attempting to collect instances.
16385 16392 *
16386 16393 * Return the count of instances found if there are no errors.
16387 16394 *
16388 16395 */
16389 16396 static int
16390 16397 check_instance_support(char *mfstfile, const char *svcname,
16391 16398 uu_list_t *instances)
16392 16399 {
16393 16400 uu_list_walk_t *svcs, *insts;
16394 16401 uu_list_t *ilist;
16395 16402 bundle_t *b;
16396 16403 entity_t *mfsvc, *mfinst;
16397 16404 const char *svcn;
16398 16405 int rminstcnt = 0;
16399 16406
16400 16407
16401 16408 b = internal_bundle_new();
16402 16409
16403 16410 if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
16404 16411 /*
16405 16412 * Unable to process the manifest file for
16406 16413 * instance support, so just return as
16407 16414 * don't want to remove instances that could
16408 16415 * not be accounted for that might exist here.
16409 16416 */
16410 16417 internal_bundle_free(b);
16411 16418 return (0);
16412 16419 }
16413 16420
16414 16421 svcs = uu_list_walk_start(b->sc_bundle_services, 0);
16415 16422 if (svcs == NULL) {
16416 16423 internal_bundle_free(b);
16417 16424 return (0);
16418 16425 }
16419 16426
16420 16427 svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
16421 16428 (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
16422 16429
16423 16430 while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
16424 16431 if (strcmp(mfsvc->sc_name, svcn) == 0)
16425 16432 break;
16426 16433 }
16427 16434 uu_list_walk_end(svcs);
16428 16435
16429 16436 if (mfsvc == NULL) {
16430 16437 internal_bundle_free(b);
16431 16438 return (-1);
16432 16439 }
16433 16440
16434 16441 ilist = mfsvc->sc_u.sc_service.sc_service_instances;
16435 16442 if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
16436 16443 internal_bundle_free(b);
16437 16444 return (0);
16438 16445 }
16439 16446
16440 16447 while ((mfinst = uu_list_walk_next(insts)) != NULL) {
16441 16448 /*
16442 16449 * Remove the instance from the instances list.
16443 16450 * The unaccounted for instances will be removed
16444 16451 * from the service once all manifests are
16445 16452 * processed.
16446 16453 */
16447 16454 (void) remove_string(instances,
16448 16455 mfinst->sc_name);
16449 16456 rminstcnt++;
16450 16457 }
16451 16458
16452 16459 uu_list_walk_end(insts);
16453 16460 internal_bundle_free(b);
16454 16461
16455 16462 return (rminstcnt);
16456 16463 }
16457 16464
16458 16465 /*
16459 16466 * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16460 16467 * 'false' to indicate there's no manifest file(s) found for the service.
16461 16468 */
16462 16469 static void
16463 16470 svc_add_no_support(scf_service_t *svc)
16464 16471 {
16465 16472 char *pname;
16466 16473
16467 16474 /* Add no support */
16468 16475 cur_svc = svc;
16469 16476 if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
16470 16477 return;
16471 16478
16472 16479 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
16473 16480 if (pname == NULL)
16474 16481 uu_die(gettext("Out of memory.\n"));
16475 16482
16476 16483 (void) lscf_addpropvalue(pname, "boolean:", "0");
16477 16484
16478 16485 uu_free(pname);
16479 16486 cur_svc = NULL;
16480 16487 }
16481 16488
16482 16489 /*
16483 16490 * This function handles all upgrade scenarios for a service that doesn't have
16484 16491 * SCF_PG_MANIFESTFILES pg. The function creates and populates
16485 16492 * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16486 16493 * manifest(s) mapping. Manifests under supported directories are inventoried
16487 16494 * and a property is added for each file that delivers configuration to the
16488 16495 * service. A service that has no corresponding manifest files (deleted) are
16489 16496 * removed from repository.
16490 16497 *
16491 16498 * Unsupported services:
16492 16499 *
16493 16500 * A service is considered unsupported if there is no corresponding manifest
16494 16501 * in the supported directories for that service and the service isn't in the
16495 16502 * history file list. The history file, MFSTHISTFILE, contains a list of all
16496 16503 * services and instances that were delivered by Solaris before the introduction
16497 16504 * of the SCF_PG_MANIFESTFILES property group. The history file also contains
16498 16505 * the path to the manifest file that defined the service or instance.
16499 16506 *
16500 16507 * Another type of unsupported services is 'handcrafted' services,
16501 16508 * programmatically created services or services created by dependent entries
16502 16509 * in other manifests. A handcrafted service is identified by its lack of any
16503 16510 * instance containing last-import snapshot which is created during svccfg
16504 16511 * import.
16505 16512 *
16506 16513 * This function sets a flag for unsupported services by setting services'
16507 16514 * SCF_PG_MANIFESTFILES/support property to false.
16508 16515 */
16509 16516 static void
16510 16517 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
16511 16518 {
16512 16519 service_manifest_t *elem;
16513 16520 uu_list_walk_t *mfwalk;
16514 16521 string_list_t *mfile;
16515 16522 uu_list_t *instances;
16516 16523 const char *sname;
16517 16524 char *pname;
16518 16525 int r;
16519 16526
16520 16527 /*
16521 16528 * Since there's no guarantee manifests under /var are available during
16522 16529 * early import, don't perform any upgrade during early import.
16523 16530 */
16524 16531 if (IGNORE_VAR)
16525 16532 return;
16526 16533
16527 16534 if (service_manifest_tree == NULL) {
16528 16535 create_manifest_tree();
16529 16536 }
16530 16537
16531 16538 /*
16532 16539 * Find service's supporting manifest(s) after
16533 16540 * stripping off the svc:/ prefix that is part
16534 16541 * of the fmri that is not used in the service
16535 16542 * manifest bundle list.
16536 16543 */
16537 16544 sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
16538 16545 strlen(SCF_FMRI_SERVICE_PREFIX);
16539 16546 elem = find_add_svc_mfst(sname, NULL);
16540 16547 if (elem == NULL) {
16541 16548
16542 16549 /*
16543 16550 * A handcrafted service, one that has no instance containing
16544 16551 * last-import snapshot, should get unsupported flag.
16545 16552 */
16546 16553 instances = create_instance_list(svc, 1);
16547 16554 if (instances == NULL) {
16548 16555 uu_warn(gettext("Unable to create instance list %s\n"),
16549 16556 svcname);
16550 16557 return;
16551 16558 }
16552 16559
16553 16560 if (uu_list_numnodes(instances) == 0) {
16554 16561 svc_add_no_support(svc);
16555 16562 return;
16556 16563 }
16557 16564
16558 16565 /*
16559 16566 * If the service is in the history file, and its supporting
16560 16567 * manifests are not found, we can safely delete the service
16561 16568 * because its manifests are removed from the system.
16562 16569 *
16563 16570 * Services not found in the history file are not delivered by
16564 16571 * Solaris and/or delivered outside supported directories, set
16565 16572 * unsupported flag for these services.
16566 16573 */
16567 16574 r = check_mfst_history(svcname);
16568 16575 if (r == -1)
16569 16576 return;
16570 16577
16571 16578 if (r) {
16572 16579 /* Set unsupported flag for service */
16573 16580 svc_add_no_support(svc);
16574 16581 } else {
16575 16582 /* Delete the service */
16576 16583 teardown_service(svc, svcname);
16577 16584 }
16578 16585
16579 16586 return;
16580 16587 }
16581 16588
16582 16589 /*
16583 16590 * Walk through the list of manifests and add them
16584 16591 * to the service.
16585 16592 *
16586 16593 * Create a manifestfiles pg and add the property.
16587 16594 */
16588 16595 mfwalk = uu_list_walk_start(elem->mfstlist, 0);
16589 16596 if (mfwalk == NULL)
16590 16597 return;
16591 16598
16592 16599 cur_svc = svc;
16593 16600 r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
16594 16601 if (r != 0) {
16595 16602 cur_svc = NULL;
16596 16603 return;
16597 16604 }
16598 16605
16599 16606 while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
16600 16607 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16601 16608 mhash_filename_to_propname(mfile->str, 0));
16602 16609 if (pname == NULL)
16603 16610 uu_die(gettext("Out of memory.\n"));
16604 16611
16605 16612 (void) lscf_addpropvalue(pname, "astring:", mfile->str);
16606 16613 uu_free(pname);
16607 16614 }
16608 16615 uu_list_walk_end(mfwalk);
16609 16616
16610 16617 cur_svc = NULL;
16611 16618 }
16612 16619
16613 16620 /*
16614 16621 * Take a service and process the manifest file entires to see if
16615 16622 * there is continued support for the service and instances. If
16616 16623 * not cleanup as appropriate.
16617 16624 *
16618 16625 * If a service does not have a manifest files entry flag it for
16619 16626 * upgrade and return.
16620 16627 *
16621 16628 * For each manifestfiles property check if the manifest file is
16622 16629 * under the supported /lib/svc/manifest or /var/svc/manifest path
16623 16630 * and if not then return immediately as this service is not supported
16624 16631 * by the cleanup mechanism and should be ignored.
16625 16632 *
16626 16633 * For each manifest file that is supported, check to see if the
16627 16634 * file exists. If not then remove the manifest file property
16628 16635 * from the service and the smf/manifest hash table. If the manifest
16629 16636 * file exists then verify that it supports the instances that are
16630 16637 * part of the service.
16631 16638 *
16632 16639 * Once all manifest files have been accounted for remove any instances
16633 16640 * that are no longer supported in the service.
16634 16641 *
16635 16642 * Return values :
16636 16643 * 0 - Successfully processed the service
16637 16644 * non-zero - failed to process the service
16638 16645 *
16639 16646 * On most errors, will just return to wait and get the next service,
16640 16647 * unless in case of unable to create the needed structures which is
16641 16648 * most likely a fatal error that is not going to be recoverable.
16642 16649 */
16643 16650 int
16644 16651 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
16645 16652 {
16646 16653 struct mpg_mfile *mpntov;
16647 16654 struct mpg_mfile **mpvarry = NULL;
16648 16655 scf_service_t *svc;
16649 16656 scf_propertygroup_t *mpg;
16650 16657 scf_property_t *mp;
16651 16658 scf_value_t *mv;
16652 16659 scf_iter_t *mi;
16653 16660 scf_instance_t *instance;
16654 16661 uu_list_walk_t *insts;
16655 16662 uu_list_t *instances = NULL;
16656 16663 boolean_t activity = (boolean_t)act;
16657 16664 char *mpnbuf;
16658 16665 char *mpvbuf;
16659 16666 char *pgpropbuf;
16660 16667 int mfstcnt, rminstct, instct, mfstmax;
16661 16668 int index;
16662 16669 int r = 0;
16663 16670
16664 16671 assert(g_hndl != NULL);
16665 16672 assert(wip->svc != NULL);
16666 16673 assert(wip->fmri != NULL);
16667 16674
16668 16675 svc = wip->svc;
16669 16676
16670 16677 mpg = scf_pg_create(g_hndl);
16671 16678 mp = scf_property_create(g_hndl);
16672 16679 mi = scf_iter_create(g_hndl);
16673 16680 mv = scf_value_create(g_hndl);
16674 16681 instance = scf_instance_create(g_hndl);
16675 16682
16676 16683 if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
16677 16684 instance == NULL) {
16678 16685 uu_warn(gettext("Unable to create the supporting entities\n"));
16679 16686 uu_warn(gettext("scf error is : %s\n"),
16680 16687 scf_strerror(scf_error()));
16681 16688 scfdie();
16682 16689 }
16683 16690
16684 16691 /*
16685 16692 * Get the manifestfiles property group to be parsed for
16686 16693 * files existence.
16687 16694 */
16688 16695 if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
16689 16696 switch (scf_error()) {
16690 16697 case SCF_ERROR_NOT_FOUND:
16691 16698 upgrade_svc_mfst_connection(svc, wip->fmri);
16692 16699 break;
16693 16700 case SCF_ERROR_DELETED:
16694 16701 case SCF_ERROR_CONNECTION_BROKEN:
16695 16702 goto out;
16696 16703
16697 16704 case SCF_ERROR_HANDLE_MISMATCH:
16698 16705 case SCF_ERROR_NOT_BOUND:
16699 16706 case SCF_ERROR_NOT_SET:
16700 16707 default:
16701 16708 bad_error("scf_iter_pg_properties",
16702 16709 scf_error());
16703 16710 }
16704 16711
16705 16712 goto out;
16706 16713 }
16707 16714
16708 16715 /*
16709 16716 * Iterate through each of the manifestfiles properties
16710 16717 * to determine what manifestfiles are available.
16711 16718 *
16712 16719 * If a manifest file is supported then increment the
16713 16720 * count and therefore the service is safe.
16714 16721 */
16715 16722 if (scf_iter_pg_properties(mi, mpg) != 0) {
16716 16723 switch (scf_error()) {
16717 16724 case SCF_ERROR_DELETED:
16718 16725 case SCF_ERROR_CONNECTION_BROKEN:
16719 16726 goto out;
16720 16727
16721 16728 case SCF_ERROR_HANDLE_MISMATCH:
16722 16729 case SCF_ERROR_NOT_BOUND:
16723 16730 case SCF_ERROR_NOT_SET:
16724 16731 default:
16725 16732 bad_error("scf_iter_pg_properties",
16726 16733 scf_error());
16727 16734 }
16728 16735 }
16729 16736
16730 16737 mfstcnt = 0;
16731 16738 mfstmax = MFSTFILE_MAX;
16732 16739 mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
16733 16740 while ((r = scf_iter_next_property(mi, mp)) != 0) {
16734 16741 if (r == -1)
16735 16742 bad_error(gettext("Unable to iterate through "
16736 16743 "manifestfiles properties : %s"),
16737 16744 scf_error());
16738 16745
16739 16746 mpntov = safe_malloc(sizeof (struct mpg_mfile));
16740 16747 mpnbuf = safe_malloc(max_scf_name_len + 1);
16741 16748 mpvbuf = safe_malloc(max_scf_value_len + 1);
16742 16749 mpntov->mpg = mpnbuf;
16743 16750 mpntov->mfile = mpvbuf;
16744 16751 mpntov->access = 1;
16745 16752 if (scf_property_get_name(mp, mpnbuf,
16746 16753 max_scf_name_len + 1) < 0) {
16747 16754 uu_warn(gettext("Unable to get manifest file "
16748 16755 "property : %s\n"),
16749 16756 scf_strerror(scf_error()));
16750 16757
16751 16758 switch (scf_error()) {
16752 16759 case SCF_ERROR_DELETED:
16753 16760 case SCF_ERROR_CONNECTION_BROKEN:
16754 16761 r = scferror2errno(scf_error());
16755 16762 goto out_free;
16756 16763
16757 16764 case SCF_ERROR_HANDLE_MISMATCH:
16758 16765 case SCF_ERROR_NOT_BOUND:
16759 16766 case SCF_ERROR_NOT_SET:
16760 16767 default:
16761 16768 bad_error("scf_iter_pg_properties",
16762 16769 scf_error());
16763 16770 }
16764 16771 }
16765 16772
16766 16773 /*
16767 16774 * The support property is a boolean value that indicates
16768 16775 * if the service is supported for manifest file deletion.
16769 16776 * Currently at this time there is no code that sets this
16770 16777 * value to true. So while we could just let this be caught
16771 16778 * by the support check below, in the future this by be set
16772 16779 * to true and require processing. So for that, go ahead
16773 16780 * and check here, and just return if false. Otherwise,
16774 16781 * fall through expecting that other support checks will
16775 16782 * handle the entries.
16776 16783 */
16777 16784 if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
16778 16785 uint8_t support;
16779 16786
16780 16787 if (scf_property_get_value(mp, mv) != 0 ||
16781 16788 scf_value_get_boolean(mv, &support) != 0) {
16782 16789 uu_warn(gettext("Unable to get the manifest "
16783 16790 "support value: %s\n"),
16784 16791 scf_strerror(scf_error()));
16785 16792
16786 16793 switch (scf_error()) {
16787 16794 case SCF_ERROR_DELETED:
16788 16795 case SCF_ERROR_CONNECTION_BROKEN:
16789 16796 r = scferror2errno(scf_error());
16790 16797 goto out_free;
16791 16798
16792 16799 case SCF_ERROR_HANDLE_MISMATCH:
16793 16800 case SCF_ERROR_NOT_BOUND:
16794 16801 case SCF_ERROR_NOT_SET:
16795 16802 default:
16796 16803 bad_error("scf_iter_pg_properties",
16797 16804 scf_error());
16798 16805 }
16799 16806 }
16800 16807
16801 16808 if (support == B_FALSE)
16802 16809 goto out_free;
16803 16810 }
16804 16811
16805 16812 /*
16806 16813 * Anything with a manifest outside of the supported
16807 16814 * directories, immediately bail out because that makes
16808 16815 * this service non-supported. We don't even want
16809 16816 * to do instance processing in this case because the
16810 16817 * instances could be part of the non-supported manifest.
16811 16818 */
16812 16819 if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
16813 16820 /*
16814 16821 * Manifest is not in /lib/svc, so we need to
16815 16822 * consider the /var/svc case.
16816 16823 */
16817 16824 if (strncmp(mpnbuf, VARSVC_PR,
16818 16825 strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
16819 16826 /*
16820 16827 * Either the manifest is not in /var/svc or
16821 16828 * /var is not yet mounted. We ignore the
16822 16829 * manifest either because it is not in a
16823 16830 * standard location or because we cannot
16824 16831 * currently access the manifest.
16825 16832 */
16826 16833 goto out_free;
16827 16834 }
16828 16835 }
16829 16836
16830 16837 /*
16831 16838 * Get the value to of the manifest file for this entry
16832 16839 * for access verification and instance support
16833 16840 * verification if it still exists.
16834 16841 *
16835 16842 * During Early Manifest Import if the manifest is in
16836 16843 * /var/svc then it may not yet be available for checking
16837 16844 * so we must determine if /var/svc is available. If not
16838 16845 * then defer until Late Manifest Import to cleanup.
16839 16846 */
16840 16847 if (scf_property_get_value(mp, mv) != 0) {
16841 16848 uu_warn(gettext("Unable to get the manifest file "
16842 16849 "value: %s\n"),
16843 16850 scf_strerror(scf_error()));
16844 16851
16845 16852 switch (scf_error()) {
16846 16853 case SCF_ERROR_DELETED:
16847 16854 case SCF_ERROR_CONNECTION_BROKEN:
16848 16855 r = scferror2errno(scf_error());
16849 16856 goto out_free;
16850 16857
16851 16858 case SCF_ERROR_HANDLE_MISMATCH:
16852 16859 case SCF_ERROR_NOT_BOUND:
16853 16860 case SCF_ERROR_NOT_SET:
16854 16861 default:
16855 16862 bad_error("scf_property_get_value",
16856 16863 scf_error());
16857 16864 }
16858 16865 }
16859 16866
16860 16867 if (scf_value_get_astring(mv, mpvbuf,
16861 16868 max_scf_value_len + 1) < 0) {
16862 16869 uu_warn(gettext("Unable to get the manifest "
16863 16870 "file : %s\n"),
16864 16871 scf_strerror(scf_error()));
16865 16872
16866 16873 switch (scf_error()) {
16867 16874 case SCF_ERROR_DELETED:
16868 16875 case SCF_ERROR_CONNECTION_BROKEN:
16869 16876 r = scferror2errno(scf_error());
16870 16877 goto out_free;
16871 16878
16872 16879 case SCF_ERROR_HANDLE_MISMATCH:
16873 16880 case SCF_ERROR_NOT_BOUND:
16874 16881 case SCF_ERROR_NOT_SET:
16875 16882 default:
16876 16883 bad_error("scf_value_get_astring",
16877 16884 scf_error());
16878 16885 }
16879 16886 }
16880 16887
16881 16888 mpvarry[mfstcnt] = mpntov;
16882 16889 mfstcnt++;
16883 16890
16884 16891 /*
16885 16892 * Check for the need to reallocate array
16886 16893 */
16887 16894 if (mfstcnt >= (mfstmax - 1)) {
16888 16895 struct mpg_mfile **newmpvarry;
16889 16896
16890 16897 mfstmax = mfstmax * 2;
16891 16898 newmpvarry = realloc(mpvarry,
16892 16899 sizeof (struct mpg_mfile *) * mfstmax);
16893 16900
16894 16901 if (newmpvarry == NULL)
16895 16902 goto out_free;
16896 16903
16897 16904 mpvarry = newmpvarry;
16898 16905 }
16899 16906
16900 16907 mpvarry[mfstcnt] = NULL;
16901 16908 }
16902 16909
16903 16910 for (index = 0; mpvarry[index]; index++) {
16904 16911 mpntov = mpvarry[index];
16905 16912
16906 16913 /*
16907 16914 * Check to see if the manifestfile is accessable, if so hand
16908 16915 * this service and manifestfile off to be processed for
16909 16916 * instance support.
16910 16917 */
16911 16918 mpnbuf = mpntov->mpg;
16912 16919 mpvbuf = mpntov->mfile;
16913 16920 if (access(mpvbuf, F_OK) != 0) {
16914 16921 mpntov->access = 0;
16915 16922 activity++;
16916 16923 mfstcnt--;
16917 16924 /* Remove the entry from the service */
16918 16925 cur_svc = svc;
16919 16926 pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16920 16927 mpnbuf);
16921 16928 if (pgpropbuf == NULL)
16922 16929 uu_die(gettext("Out of memory.\n"));
16923 16930
16924 16931 lscf_delprop(pgpropbuf);
16925 16932 cur_svc = NULL;
16926 16933
16927 16934 uu_free(pgpropbuf);
16928 16935 }
16929 16936 }
16930 16937
16931 16938 /*
16932 16939 * If mfstcnt is 0, none of the manifests that supported the service
16933 16940 * existed so remove the service.
16934 16941 */
16935 16942 if (mfstcnt == 0) {
16936 16943 teardown_service(svc, wip->fmri);
16937 16944
16938 16945 goto out_free;
16939 16946 }
16940 16947
16941 16948 if (activity) {
16942 16949 int nosvcsupport = 0;
16943 16950
16944 16951 /*
16945 16952 * If the list of service instances is NULL then
16946 16953 * create the list.
16947 16954 */
16948 16955 instances = create_instance_list(svc, 1);
16949 16956 if (instances == NULL) {
16950 16957 uu_warn(gettext("Unable to create instance list %s\n"),
16951 16958 wip->fmri);
16952 16959 goto out_free;
16953 16960 }
16954 16961
16955 16962 rminstct = uu_list_numnodes(instances);
16956 16963 instct = rminstct;
16957 16964
16958 16965 for (index = 0; mpvarry[index]; index++) {
16959 16966 mpntov = mpvarry[index];
16960 16967 if (mpntov->access == 0)
16961 16968 continue;
16962 16969
16963 16970 mpnbuf = mpntov->mpg;
16964 16971 mpvbuf = mpntov->mfile;
16965 16972 r = check_instance_support(mpvbuf, wip->fmri,
16966 16973 instances);
16967 16974 if (r == -1) {
16968 16975 nosvcsupport++;
16969 16976 } else {
16970 16977 rminstct -= r;
16971 16978 }
16972 16979 }
16973 16980
16974 16981 if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
16975 16982 teardown_service(svc, wip->fmri);
16976 16983
16977 16984 goto out_free;
16978 16985 }
16979 16986 }
16980 16987
16981 16988 /*
16982 16989 * If there are instances left on the instance list, then
16983 16990 * we must remove them.
16984 16991 */
16985 16992 if (instances != NULL && uu_list_numnodes(instances)) {
16986 16993 string_list_t *sp;
16987 16994
16988 16995 insts = uu_list_walk_start(instances, 0);
16989 16996 while ((sp = uu_list_walk_next(insts)) != NULL) {
16990 16997 /*
16991 16998 * Remove the instance from the instances list.
16992 16999 */
16993 17000 safe_printf(gettext("Delete instance %s from "
16994 17001 "service %s\n"), sp->str, wip->fmri);
16995 17002 if (scf_service_get_instance(svc, sp->str,
16996 17003 instance) != SCF_SUCCESS) {
16997 17004 (void) uu_warn("scf_error - %s\n",
16998 17005 scf_strerror(scf_error()));
16999 17006
17000 17007 continue;
17001 17008 }
17002 17009
17003 17010 (void) disable_instance(instance);
17004 17011
17005 17012 (void) lscf_instance_delete(instance, 1);
17006 17013 }
17007 17014 scf_instance_destroy(instance);
17008 17015 uu_list_walk_end(insts);
17009 17016 }
17010 17017
17011 17018 out_free:
17012 17019 if (mpvarry) {
17013 17020 struct mpg_mfile *fmpntov;
17014 17021
17015 17022 for (index = 0; mpvarry[index]; index++) {
17016 17023 fmpntov = mpvarry[index];
17017 17024 if (fmpntov->mpg == mpnbuf)
17018 17025 mpnbuf = NULL;
17019 17026 free(fmpntov->mpg);
17020 17027
17021 17028 if (fmpntov->mfile == mpvbuf)
17022 17029 mpvbuf = NULL;
17023 17030 free(fmpntov->mfile);
17024 17031
17025 17032 if (fmpntov == mpntov)
17026 17033 mpntov = NULL;
17027 17034 free(fmpntov);
17028 17035 }
17029 17036 if (mpnbuf)
17030 17037 free(mpnbuf);
17031 17038 if (mpvbuf)
17032 17039 free(mpvbuf);
17033 17040 if (mpntov)
17034 17041 free(mpntov);
17035 17042
17036 17043 free(mpvarry);
17037 17044 }
17038 17045 out:
17039 17046 scf_pg_destroy(mpg);
17040 17047 scf_property_destroy(mp);
17041 17048 scf_iter_destroy(mi);
17042 17049 scf_value_destroy(mv);
17043 17050
17044 17051 return (0);
17045 17052 }
17046 17053
17047 17054 /*
17048 17055 * Take the service and search for the manifestfiles property
17049 17056 * in each of the property groups. If the manifest file
17050 17057 * associated with the property does not exist then remove
17051 17058 * the property group.
17052 17059 */
17053 17060 int
17054 17061 lscf_hash_cleanup()
17055 17062 {
17056 17063 scf_service_t *svc;
17057 17064 scf_scope_t *scope;
17058 17065 scf_propertygroup_t *pg;
17059 17066 scf_property_t *prop;
17060 17067 scf_value_t *val;
17061 17068 scf_iter_t *iter;
17062 17069 char *pgname = NULL;
17063 17070 char *mfile = NULL;
17064 17071 int r;
17065 17072
17066 17073 svc = scf_service_create(g_hndl);
17067 17074 scope = scf_scope_create(g_hndl);
17068 17075 pg = scf_pg_create(g_hndl);
17069 17076 prop = scf_property_create(g_hndl);
17070 17077 val = scf_value_create(g_hndl);
17071 17078 iter = scf_iter_create(g_hndl);
17072 17079 if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
17073 17080 svc == NULL || scope == NULL) {
17074 17081 uu_warn(gettext("Unable to create a property group, or "
17075 17082 "property\n"));
17076 17083 uu_warn("%s\n", pg == NULL ? "pg is NULL" :
17077 17084 "pg is not NULL");
17078 17085 uu_warn("%s\n", prop == NULL ? "prop is NULL" :
17079 17086 "prop is not NULL");
17080 17087 uu_warn("%s\n", val == NULL ? "val is NULL" :
17081 17088 "val is not NULL");
17082 17089 uu_warn("%s\n", iter == NULL ? "iter is NULL" :
17083 17090 "iter is not NULL");
17084 17091 uu_warn("%s\n", svc == NULL ? "svc is NULL" :
17085 17092 "svc is not NULL");
17086 17093 uu_warn("%s\n", scope == NULL ? "scope is NULL" :
17087 17094 "scope is not NULL");
17088 17095 uu_warn(gettext("scf error is : %s\n"),
17089 17096 scf_strerror(scf_error()));
17090 17097 scfdie();
17091 17098 }
17092 17099
17093 17100 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
17094 17101 switch (scf_error()) {
17095 17102 case SCF_ERROR_CONNECTION_BROKEN:
17096 17103 case SCF_ERROR_NOT_FOUND:
17097 17104 goto out;
17098 17105
17099 17106 case SCF_ERROR_HANDLE_MISMATCH:
17100 17107 case SCF_ERROR_NOT_BOUND:
17101 17108 case SCF_ERROR_INVALID_ARGUMENT:
17102 17109 default:
17103 17110 bad_error("scf_handle_get_scope", scf_error());
17104 17111 }
17105 17112 }
17106 17113
17107 17114 if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
17108 17115 uu_warn(gettext("Unable to process the hash service, %s\n"),
17109 17116 HASH_SVC);
17110 17117 goto out;
17111 17118 }
17112 17119
17113 17120 pgname = safe_malloc(max_scf_name_len + 1);
17114 17121 mfile = safe_malloc(max_scf_value_len + 1);
17115 17122
17116 17123 if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
17117 17124 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17118 17125 scf_strerror(scf_error()));
17119 17126 goto out;
17120 17127 }
17121 17128
17122 17129 while ((r = scf_iter_next_pg(iter, pg)) != 0) {
17123 17130 if (r == -1)
17124 17131 goto out;
17125 17132
17126 17133 if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
17127 17134 switch (scf_error()) {
17128 17135 case SCF_ERROR_DELETED:
17129 17136 return (ENODEV);
17130 17137
17131 17138 case SCF_ERROR_CONNECTION_BROKEN:
17132 17139 return (ECONNABORTED);
17133 17140
17134 17141 case SCF_ERROR_NOT_SET:
17135 17142 case SCF_ERROR_NOT_BOUND:
17136 17143 default:
17137 17144 bad_error("scf_pg_get_name", scf_error());
17138 17145 }
17139 17146 }
17140 17147 if (IGNORE_VAR) {
17141 17148 if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
17142 17149 continue;
17143 17150 }
17144 17151
17145 17152 /*
17146 17153 * If unable to get the property continue as this is an
17147 17154 * entry that has no location to check against.
17148 17155 */
17149 17156 if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
17150 17157 continue;
17151 17158 }
17152 17159
17153 17160 if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
17154 17161 uu_warn(gettext("Unable to get value from %s\n"),
17155 17162 pgname);
17156 17163
17157 17164 switch (scf_error()) {
17158 17165 case SCF_ERROR_DELETED:
17159 17166 case SCF_ERROR_CONSTRAINT_VIOLATED:
17160 17167 case SCF_ERROR_NOT_FOUND:
17161 17168 case SCF_ERROR_NOT_SET:
17162 17169 continue;
17163 17170
17164 17171 case SCF_ERROR_CONNECTION_BROKEN:
17165 17172 r = scferror2errno(scf_error());
17166 17173 goto out;
17167 17174
17168 17175 case SCF_ERROR_HANDLE_MISMATCH:
17169 17176 case SCF_ERROR_NOT_BOUND:
17170 17177 default:
17171 17178 bad_error("scf_property_get_value",
17172 17179 scf_error());
17173 17180 }
17174 17181 }
17175 17182
17176 17183 if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
17177 17184 == -1) {
17178 17185 uu_warn(gettext("Unable to get astring from %s : %s\n"),
17179 17186 pgname, scf_strerror(scf_error()));
17180 17187
17181 17188 switch (scf_error()) {
17182 17189 case SCF_ERROR_NOT_SET:
17183 17190 case SCF_ERROR_TYPE_MISMATCH:
17184 17191 continue;
17185 17192
17186 17193 default:
17187 17194 bad_error("scf_value_get_astring", scf_error());
17188 17195 }
17189 17196 }
17190 17197
17191 17198 if (access(mfile, F_OK) == 0)
17192 17199 continue;
17193 17200
17194 17201 (void) scf_pg_delete(pg);
17195 17202 }
17196 17203
17197 17204 out:
17198 17205 scf_scope_destroy(scope);
17199 17206 scf_service_destroy(svc);
17200 17207 scf_pg_destroy(pg);
17201 17208 scf_property_destroy(prop);
17202 17209 scf_value_destroy(val);
17203 17210 scf_iter_destroy(iter);
17204 17211 free(pgname);
17205 17212 free(mfile);
17206 17213
17207 17214 return (0);
17208 17215 }
17209 17216
17210 17217 #ifndef NATIVE_BUILD
17211 17218 /* ARGSUSED */
17212 17219 CPL_MATCH_FN(complete_select)
17213 17220 {
17214 17221 const char *arg0, *arg1, *arg1end;
17215 17222 int word_start, err = 0, r;
17216 17223 size_t len;
17217 17224 char *buf;
17218 17225
17219 17226 lscf_prep_hndl();
17220 17227
17221 17228 arg0 = line + strspn(line, " \t");
17222 17229 assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
17223 17230
17224 17231 arg1 = arg0 + sizeof ("select") - 1;
17225 17232 arg1 += strspn(arg1, " \t");
17226 17233 word_start = arg1 - line;
17227 17234
17228 17235 arg1end = arg1 + strcspn(arg1, " \t");
17229 17236 if (arg1end < line + word_end)
17230 17237 return (0);
17231 17238
17232 17239 len = line + word_end - arg1;
17233 17240
17234 17241 buf = safe_malloc(max_scf_name_len + 1);
17235 17242
17236 17243 if (cur_snap != NULL) {
17237 17244 return (0);
17238 17245 } else if (cur_inst != NULL) {
17239 17246 return (0);
17240 17247 } else if (cur_svc != NULL) {
17241 17248 scf_instance_t *inst;
17242 17249 scf_iter_t *iter;
17243 17250
17244 17251 if ((inst = scf_instance_create(g_hndl)) == NULL ||
17245 17252 (iter = scf_iter_create(g_hndl)) == NULL)
17246 17253 scfdie();
17247 17254
17248 17255 if (scf_iter_service_instances(iter, cur_svc) != 0)
17249 17256 scfdie();
17250 17257
17251 17258 for (;;) {
17252 17259 r = scf_iter_next_instance(iter, inst);
17253 17260 if (r == 0)
17254 17261 break;
17255 17262 if (r != 1)
17256 17263 scfdie();
17257 17264
17258 17265 if (scf_instance_get_name(inst, buf,
17259 17266 max_scf_name_len + 1) < 0)
17260 17267 scfdie();
17261 17268
17262 17269 if (strncmp(buf, arg1, len) == 0) {
17263 17270 err = cpl_add_completion(cpl, line, word_start,
17264 17271 word_end, buf + len, "", " ");
17265 17272 if (err != 0)
17266 17273 break;
17267 17274 }
17268 17275 }
17269 17276
17270 17277 scf_iter_destroy(iter);
17271 17278 scf_instance_destroy(inst);
17272 17279
17273 17280 return (err);
17274 17281 } else {
17275 17282 scf_service_t *svc;
17276 17283 scf_iter_t *iter;
17277 17284
17278 17285 assert(cur_scope != NULL);
17279 17286
17280 17287 if ((svc = scf_service_create(g_hndl)) == NULL ||
17281 17288 (iter = scf_iter_create(g_hndl)) == NULL)
17282 17289 scfdie();
17283 17290
17284 17291 if (scf_iter_scope_services(iter, cur_scope) != 0)
17285 17292 scfdie();
17286 17293
17287 17294 for (;;) {
17288 17295 r = scf_iter_next_service(iter, svc);
17289 17296 if (r == 0)
17290 17297 break;
17291 17298 if (r != 1)
17292 17299 scfdie();
17293 17300
17294 17301 if (scf_service_get_name(svc, buf,
17295 17302 max_scf_name_len + 1) < 0)
17296 17303 scfdie();
17297 17304
17298 17305 if (strncmp(buf, arg1, len) == 0) {
17299 17306 err = cpl_add_completion(cpl, line, word_start,
17300 17307 word_end, buf + len, "", " ");
17301 17308 if (err != 0)
17302 17309 break;
17303 17310 }
17304 17311 }
17305 17312
17306 17313 scf_iter_destroy(iter);
17307 17314 scf_service_destroy(svc);
17308 17315
17309 17316 return (err);
17310 17317 }
17311 17318 }
17312 17319
17313 17320 /* ARGSUSED */
17314 17321 CPL_MATCH_FN(complete_command)
17315 17322 {
17316 17323 uint32_t scope = 0;
17317 17324
17318 17325 if (cur_snap != NULL)
17319 17326 scope = CS_SNAP;
17320 17327 else if (cur_inst != NULL)
17321 17328 scope = CS_INST;
17322 17329 else if (cur_svc != NULL)
17323 17330 scope = CS_SVC;
17324 17331 else
17325 17332 scope = CS_SCOPE;
17326 17333
17327 17334 return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
17328 17335 }
17329 17336 #endif /* NATIVE_BUILD */
↓ open down ↓ |
7051 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX