Print this page
7852 svccfg archive should drop SCF_NOTIFY_PG_POSTFIX
Reviewed by: Dan McDonald <danmcd@omniti.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 2015 Joyent, Inc.
25 25 * Copyright 2012 Milan Jurik. All rights reserved.
26 26 * Copyright 2017 RackTop Systems.
27 27 */
28 28
29 29
30 30 #include <alloca.h>
31 31 #include <assert.h>
32 32 #include <ctype.h>
33 33 #include <door.h>
34 34 #include <errno.h>
35 35 #include <fcntl.h>
36 36 #include <fnmatch.h>
37 37 #include <inttypes.h>
38 38 #include <libintl.h>
39 39 #include <libnvpair.h>
40 40 #include <libscf.h>
41 41 #include <libscf_priv.h>
42 42 #include <libtecla.h>
43 43 #include <libuutil.h>
44 44 #include <limits.h>
45 45 #include <locale.h>
46 46 #include <stdarg.h>
47 47 #include <string.h>
48 48 #include <strings.h>
49 49 #include <time.h>
50 50 #include <unistd.h>
51 51 #include <wait.h>
52 52 #include <poll.h>
53 53
54 54 #include <libxml/tree.h>
55 55
56 56 #include <sys/param.h>
57 57
58 58 #include <sys/stat.h>
59 59 #include <sys/mman.h>
60 60
61 61 #include "svccfg.h"
62 62 #include "notify_params.h"
63 63 #include "manifest_hash.h"
64 64 #include "manifest_find.h"
65 65
66 66 /* The colon namespaces in each entity (each followed by a newline). */
67 67 #define COLON_NAMESPACES ":properties\n"
68 68
69 69 #define TEMP_FILE_PATTERN "/tmp/svccfg-XXXXXX"
70 70
71 71 /* These are characters which the lexer requires to be in double-quotes. */
72 72 #define CHARS_TO_QUOTE " \t\n\\>=\"()"
73 73
74 74 #define HASH_SIZE 16
75 75 #define HASH_PG_TYPE "framework"
76 76 #define HASH_PG_FLAGS 0
77 77 #define HASH_PROP "md5sum"
78 78
79 79 /*
80 80 * Indentation used in the output of the describe subcommand.
81 81 */
82 82 #define TMPL_VALUE_INDENT " "
83 83 #define TMPL_INDENT " "
84 84 #define TMPL_INDENT_2X " "
85 85 #define TMPL_CHOICE_INDENT " "
86 86
87 87 /*
88 88 * Directory locations for manifests
89 89 */
90 90 #define VARSVC_DIR "/var/svc/manifest"
91 91 #define LIBSVC_DIR "/lib/svc/manifest"
92 92 #define VARSVC_PR "var_svc_manifest"
93 93 #define LIBSVC_PR "lib_svc_manifest"
94 94 #define MFSTFILEPR "manifestfile"
95 95
96 96 #define SUPPORTPROP "support"
97 97
98 98 #define MFSTHISTFILE "/lib/svc/share/mfsthistory"
99 99
100 100 #define MFSTFILE_MAX 16
101 101
102 102 /*
103 103 * These are the classes of elements which may appear as children of service
104 104 * or instance elements in XML manifests.
105 105 */
106 106 struct entity_elts {
107 107 xmlNodePtr create_default_instance;
108 108 xmlNodePtr single_instance;
109 109 xmlNodePtr restarter;
110 110 xmlNodePtr dependencies;
111 111 xmlNodePtr dependents;
112 112 xmlNodePtr method_context;
113 113 xmlNodePtr exec_methods;
114 114 xmlNodePtr notify_params;
115 115 xmlNodePtr property_groups;
116 116 xmlNodePtr instances;
117 117 xmlNodePtr stability;
118 118 xmlNodePtr template;
119 119 };
120 120
121 121 /*
122 122 * Likewise for property_group elements.
123 123 */
124 124 struct pg_elts {
125 125 xmlNodePtr stability;
126 126 xmlNodePtr propvals;
127 127 xmlNodePtr properties;
128 128 };
129 129
130 130 /*
131 131 * Likewise for template elements.
132 132 */
133 133 struct template_elts {
134 134 xmlNodePtr common_name;
135 135 xmlNodePtr description;
136 136 xmlNodePtr documentation;
137 137 };
138 138
139 139 /*
140 140 * Likewise for type (for notification parameters) elements.
141 141 */
142 142 struct params_elts {
143 143 xmlNodePtr paramval;
144 144 xmlNodePtr parameter;
145 145 };
146 146
147 147 /*
148 148 * This structure is for snaplevel lists. They are convenient because libscf
149 149 * only allows traversing snaplevels in one direction.
150 150 */
151 151 struct snaplevel {
152 152 uu_list_node_t list_node;
153 153 scf_snaplevel_t *sl;
154 154 };
155 155
156 156 /*
157 157 * This is used for communication between lscf_service_export and
158 158 * export_callback.
159 159 */
160 160 struct export_args {
161 161 const char *filename;
162 162 int flags;
163 163 };
164 164
165 165 /*
166 166 * The service_manifest structure is used by the upgrade process
167 167 * to create a list of service to manifest linkages from the manifests
168 168 * in a set of given directories.
169 169 */
170 170 typedef struct service_manifest {
171 171 const char *servicename;
172 172 uu_list_t *mfstlist;
173 173 size_t mfstlist_sz;
174 174
175 175 uu_avl_node_t svcmfst_node;
176 176 } service_manifest_t;
177 177
178 178 /*
179 179 * Structure to track the manifest file property group
180 180 * and the manifest file associated with that property
181 181 * group. Also, a flag to keep the access once it has
182 182 * been checked.
183 183 */
184 184 struct mpg_mfile {
185 185 char *mpg;
186 186 char *mfile;
187 187 int access;
188 188 };
189 189
190 190 const char * const scf_pg_general = SCF_PG_GENERAL;
191 191 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
192 192 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
193 193 const char * const scf_property_external = "external";
194 194
195 195 const char * const snap_initial = "initial";
196 196 const char * const snap_lastimport = "last-import";
197 197 const char * const snap_previous = "previous";
198 198 const char * const snap_running = "running";
199 199
200 200 scf_handle_t *g_hndl = NULL; /* only valid after lscf_prep_hndl() */
201 201
202 202 ssize_t max_scf_fmri_len;
203 203 ssize_t max_scf_name_len;
204 204 ssize_t max_scf_pg_type_len;
205 205 ssize_t max_scf_value_len;
206 206 static size_t max_scf_len;
207 207
208 208 static scf_scope_t *cur_scope;
209 209 static scf_service_t *cur_svc = NULL;
210 210 static scf_instance_t *cur_inst = NULL;
211 211 static scf_snapshot_t *cur_snap = NULL;
212 212 static scf_snaplevel_t *cur_level = NULL;
213 213
214 214 static uu_list_pool_t *snaplevel_pool;
215 215 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
216 216 static uu_list_t *cur_levels;
217 217 static struct snaplevel *cur_elt; /* cur_elt->sl == cur_level */
218 218
219 219 static FILE *tempfile = NULL;
220 220 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
221 221
222 222 static const char *emsg_entity_not_selected;
223 223 static const char *emsg_permission_denied;
224 224 static const char *emsg_create_xml;
225 225 static const char *emsg_cant_modify_snapshots;
226 226 static const char *emsg_invalid_for_snapshot;
227 227 static const char *emsg_read_only;
228 228 static const char *emsg_deleted;
229 229 static const char *emsg_invalid_pg_name;
230 230 static const char *emsg_invalid_prop_name;
231 231 static const char *emsg_no_such_pg;
232 232 static const char *emsg_fmri_invalid_pg_name;
233 233 static const char *emsg_fmri_invalid_pg_name_type;
234 234 static const char *emsg_pg_added;
235 235 static const char *emsg_pg_changed;
236 236 static const char *emsg_pg_deleted;
237 237 static const char *emsg_pg_mod_perm;
238 238 static const char *emsg_pg_add_perm;
239 239 static const char *emsg_pg_del_perm;
240 240 static const char *emsg_snap_perm;
241 241 static const char *emsg_dpt_dangling;
242 242 static const char *emsg_dpt_no_dep;
243 243
244 244 static int li_only = 0;
245 245 static int no_refresh = 0;
246 246
247 247 /* how long in ns we should wait between checks for a pg */
248 248 static uint64_t pg_timeout = 100 * (NANOSEC / MILLISEC);
249 249
250 250 /* import globals, to minimize allocations */
251 251 static scf_scope_t *imp_scope = NULL;
252 252 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
253 253 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
254 254 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
255 255 static scf_snapshot_t *imp_rsnap = NULL;
256 256 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
257 257 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
258 258 static scf_property_t *imp_prop = NULL;
259 259 static scf_iter_t *imp_iter = NULL;
260 260 static scf_iter_t *imp_rpg_iter = NULL;
261 261 static scf_iter_t *imp_up_iter = NULL;
262 262 static scf_transaction_t *imp_tx = NULL; /* always reset this */
263 263 static char *imp_str = NULL;
264 264 static size_t imp_str_sz;
265 265 static char *imp_tsname = NULL;
266 266 static char *imp_fe1 = NULL; /* for fmri_equal() */
267 267 static char *imp_fe2 = NULL;
268 268 static uu_list_t *imp_deleted_dpts = NULL; /* pgroup_t's to refresh */
269 269
270 270 /* upgrade_dependents() globals */
271 271 static scf_instance_t *ud_inst = NULL;
272 272 static scf_snaplevel_t *ud_snpl = NULL;
273 273 static scf_propertygroup_t *ud_pg = NULL;
274 274 static scf_propertygroup_t *ud_cur_depts_pg = NULL;
275 275 static scf_propertygroup_t *ud_run_dpts_pg = NULL;
276 276 static int ud_run_dpts_pg_set = 0;
277 277 static scf_property_t *ud_prop = NULL;
278 278 static scf_property_t *ud_dpt_prop = NULL;
279 279 static scf_value_t *ud_val = NULL;
280 280 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
281 281 static scf_transaction_t *ud_tx = NULL;
282 282 static char *ud_ctarg = NULL;
283 283 static char *ud_oldtarg = NULL;
284 284 static char *ud_name = NULL;
285 285
286 286 /* export globals */
287 287 static scf_instance_t *exp_inst;
288 288 static scf_propertygroup_t *exp_pg;
289 289 static scf_property_t *exp_prop;
290 290 static scf_value_t *exp_val;
291 291 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
292 292 static char *exp_str;
293 293 static size_t exp_str_sz;
294 294
295 295 /* cleanup globals */
296 296 static uu_avl_pool_t *service_manifest_pool = NULL;
297 297 static uu_avl_t *service_manifest_tree = NULL;
298 298
299 299 static void scfdie_lineno(int lineno) __NORETURN;
300 300
301 301 static char *start_method_names[] = {
302 302 "start",
303 303 "inetd_start",
304 304 NULL
305 305 };
306 306
307 307 static struct uri_scheme {
308 308 const char *scheme;
309 309 const char *protocol;
310 310 } uri_scheme[] = {
311 311 { "mailto", "smtp" },
312 312 { "snmp", "snmp" },
313 313 { "syslog", "syslog" },
314 314 { NULL, NULL }
315 315 };
316 316 #define URI_SCHEME_NUM ((sizeof (uri_scheme) / \
317 317 sizeof (struct uri_scheme)) - 1)
318 318
319 319 static int
320 320 check_uri_scheme(const char *scheme)
321 321 {
322 322 int i;
323 323
324 324 for (i = 0; uri_scheme[i].scheme != NULL; ++i) {
325 325 if (strcmp(scheme, uri_scheme[i].scheme) == 0)
326 326 return (i);
327 327 }
328 328
329 329 return (-1);
330 330 }
331 331
332 332 static int
333 333 check_uri_protocol(const char *p)
334 334 {
335 335 int i;
336 336
337 337 for (i = 0; uri_scheme[i].protocol != NULL; ++i) {
338 338 if (strcmp(p, uri_scheme[i].protocol) == 0)
339 339 return (i);
340 340 }
341 341
342 342 return (-1);
343 343 }
344 344
345 345 /*
346 346 * For unexpected libscf errors.
347 347 */
348 348 #ifdef NDEBUG
349 349
350 350 static void scfdie(void) __NORETURN;
351 351
352 352 static void
353 353 scfdie(void)
354 354 {
355 355 scf_error_t err = scf_error();
356 356
357 357 if (err == SCF_ERROR_CONNECTION_BROKEN)
358 358 uu_die(gettext("Repository connection broken. Exiting.\n"));
359 359
360 360 uu_die(gettext("Unexpected fatal libscf error: %s. Exiting.\n"),
361 361 scf_strerror(err));
362 362 }
363 363
364 364 #else
365 365
366 366 #define scfdie() scfdie_lineno(__LINE__)
367 367
368 368 static void
369 369 scfdie_lineno(int lineno)
370 370 {
371 371 scf_error_t err = scf_error();
372 372
373 373 if (err == SCF_ERROR_CONNECTION_BROKEN)
374 374 uu_die(gettext("Repository connection broken. Exiting.\n"));
375 375
376 376 uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
377 377 ": %s.\n"), lineno, scf_strerror(err));
378 378 }
379 379
380 380 #endif
381 381
382 382 static void
383 383 scfwarn(void)
384 384 {
385 385 warn(gettext("Unexpected libscf error: %s.\n"),
386 386 scf_strerror(scf_error()));
387 387 }
388 388
389 389 /*
390 390 * Clear a field of a structure.
391 391 */
392 392 static int
393 393 clear_int(void *a, void *b)
394 394 {
395 395 /* LINTED */
396 396 *(int *)((char *)a + (size_t)b) = 0;
397 397
398 398 return (UU_WALK_NEXT);
399 399 }
400 400
401 401 static int
402 402 scferror2errno(scf_error_t err)
403 403 {
404 404 switch (err) {
405 405 case SCF_ERROR_BACKEND_ACCESS:
406 406 return (EACCES);
407 407
408 408 case SCF_ERROR_BACKEND_READONLY:
409 409 return (EROFS);
410 410
411 411 case SCF_ERROR_CONNECTION_BROKEN:
412 412 return (ECONNABORTED);
413 413
414 414 case SCF_ERROR_CONSTRAINT_VIOLATED:
415 415 case SCF_ERROR_INVALID_ARGUMENT:
416 416 return (EINVAL);
417 417
418 418 case SCF_ERROR_DELETED:
419 419 return (ECANCELED);
420 420
421 421 case SCF_ERROR_EXISTS:
422 422 return (EEXIST);
423 423
424 424 case SCF_ERROR_NO_MEMORY:
425 425 return (ENOMEM);
426 426
427 427 case SCF_ERROR_NO_RESOURCES:
428 428 return (ENOSPC);
429 429
430 430 case SCF_ERROR_NOT_FOUND:
431 431 return (ENOENT);
432 432
433 433 case SCF_ERROR_PERMISSION_DENIED:
434 434 return (EPERM);
435 435
436 436 default:
437 437 #ifndef NDEBUG
438 438 (void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
439 439 __FILE__, __LINE__, err);
440 440 #else
441 441 (void) fprintf(stderr, "Unknown libscf error %d.\n", err);
442 442 #endif
443 443 abort();
444 444 /* NOTREACHED */
445 445 }
446 446 }
447 447
448 448 static int
449 449 entity_get_pg(void *ent, int issvc, const char *name,
450 450 scf_propertygroup_t *pg)
451 451 {
452 452 if (issvc)
453 453 return (scf_service_get_pg(ent, name, pg));
454 454 else
455 455 return (scf_instance_get_pg(ent, name, pg));
456 456 }
457 457
458 458 static void
459 459 entity_destroy(void *ent, int issvc)
460 460 {
461 461 if (issvc)
462 462 scf_service_destroy(ent);
463 463 else
464 464 scf_instance_destroy(ent);
465 465 }
466 466
467 467 static int
468 468 get_pg(const char *pg_name, scf_propertygroup_t *pg)
469 469 {
470 470 int ret;
471 471
472 472 if (cur_level != NULL)
473 473 ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
474 474 else if (cur_inst != NULL)
475 475 ret = scf_instance_get_pg(cur_inst, pg_name, pg);
476 476 else
477 477 ret = scf_service_get_pg(cur_svc, pg_name, pg);
478 478
479 479 return (ret);
480 480 }
481 481
482 482 /*
483 483 * Find a snaplevel in a snapshot. If get_svc is true, find the service
484 484 * snaplevel. Otherwise find the instance snaplevel.
485 485 *
486 486 * Returns
487 487 * 0 - success
488 488 * ECONNABORTED - repository connection broken
489 489 * ECANCELED - instance containing snap was deleted
490 490 * ENOENT - snap has no snaplevels
491 491 * - requested snaplevel not found
492 492 */
493 493 static int
494 494 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
495 495 {
496 496 if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
497 497 switch (scf_error()) {
498 498 case SCF_ERROR_CONNECTION_BROKEN:
499 499 case SCF_ERROR_DELETED:
500 500 case SCF_ERROR_NOT_FOUND:
501 501 return (scferror2errno(scf_error()));
502 502
503 503 case SCF_ERROR_HANDLE_MISMATCH:
504 504 case SCF_ERROR_NOT_BOUND:
505 505 case SCF_ERROR_NOT_SET:
506 506 default:
507 507 bad_error("scf_snapshot_get_base_snaplevel",
508 508 scf_error());
509 509 }
510 510 }
511 511
512 512 for (;;) {
513 513 ssize_t ssz;
514 514
515 515 ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
516 516 if (ssz >= 0) {
517 517 if (!get_svc)
518 518 return (0);
519 519 } else {
520 520 switch (scf_error()) {
521 521 case SCF_ERROR_CONSTRAINT_VIOLATED:
522 522 if (get_svc)
523 523 return (0);
524 524 break;
525 525
526 526 case SCF_ERROR_DELETED:
527 527 case SCF_ERROR_CONNECTION_BROKEN:
528 528 return (scferror2errno(scf_error()));
529 529
530 530 case SCF_ERROR_NOT_SET:
531 531 case SCF_ERROR_NOT_BOUND:
532 532 default:
533 533 bad_error("scf_snaplevel_get_instance_name",
534 534 scf_error());
535 535 }
536 536 }
537 537
538 538 if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
539 539 switch (scf_error()) {
540 540 case SCF_ERROR_NOT_FOUND:
541 541 case SCF_ERROR_CONNECTION_BROKEN:
542 542 case SCF_ERROR_DELETED:
543 543 return (scferror2errno(scf_error()));
544 544
545 545 case SCF_ERROR_HANDLE_MISMATCH:
546 546 case SCF_ERROR_NOT_BOUND:
547 547 case SCF_ERROR_NOT_SET:
548 548 case SCF_ERROR_INVALID_ARGUMENT:
549 549 default:
550 550 bad_error("scf_snaplevel_get_next_snaplevel",
551 551 scf_error());
552 552 }
553 553 }
554 554 }
555 555 }
556 556
557 557 /*
558 558 * If issvc is 0, take ent to be a pointer to an scf_instance_t. If it has
559 559 * a running snapshot, and that snapshot has an instance snaplevel, set pg to
560 560 * the property group named name in it. If it doesn't have a running
561 561 * snapshot, set pg to the instance's current property group named name.
562 562 *
563 563 * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
564 564 * its instances. If one has a running snapshot with a service snaplevel, set
565 565 * pg to the property group named name in it. If no such snaplevel could be
566 566 * found, set pg to the service's current property group named name.
567 567 *
568 568 * iter, inst, snap, and snpl are required scratch objects.
569 569 *
570 570 * Returns
571 571 * 0 - success
572 572 * ECONNABORTED - repository connection broken
573 573 * ECANCELED - ent was deleted
574 574 * ENOENT - no such property group
575 575 * EINVAL - name is an invalid property group name
576 576 * EBADF - found running snapshot is missing a snaplevel
577 577 */
578 578 static int
579 579 entity_get_running_pg(void *ent, int issvc, const char *name,
580 580 scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
581 581 scf_snapshot_t *snap, scf_snaplevel_t *snpl)
582 582 {
583 583 int r;
584 584
585 585 if (issvc) {
586 586 /* Search for an instance with a running snapshot. */
587 587 if (scf_iter_service_instances(iter, ent) != 0) {
588 588 switch (scf_error()) {
589 589 case SCF_ERROR_DELETED:
590 590 case SCF_ERROR_CONNECTION_BROKEN:
591 591 return (scferror2errno(scf_error()));
592 592
593 593 case SCF_ERROR_NOT_SET:
594 594 case SCF_ERROR_NOT_BOUND:
595 595 case SCF_ERROR_HANDLE_MISMATCH:
596 596 default:
597 597 bad_error("scf_iter_service_instances",
598 598 scf_error());
599 599 }
600 600 }
601 601
602 602 for (;;) {
603 603 r = scf_iter_next_instance(iter, inst);
604 604 if (r == 0) {
605 605 if (scf_service_get_pg(ent, name, pg) == 0)
606 606 return (0);
607 607
608 608 switch (scf_error()) {
609 609 case SCF_ERROR_DELETED:
610 610 case SCF_ERROR_NOT_FOUND:
611 611 case SCF_ERROR_INVALID_ARGUMENT:
612 612 case SCF_ERROR_CONNECTION_BROKEN:
613 613 return (scferror2errno(scf_error()));
614 614
615 615 case SCF_ERROR_NOT_BOUND:
616 616 case SCF_ERROR_HANDLE_MISMATCH:
617 617 case SCF_ERROR_NOT_SET:
618 618 default:
619 619 bad_error("scf_service_get_pg",
620 620 scf_error());
621 621 }
622 622 }
623 623 if (r != 1) {
624 624 switch (scf_error()) {
625 625 case SCF_ERROR_DELETED:
626 626 case SCF_ERROR_CONNECTION_BROKEN:
627 627 return (scferror2errno(scf_error()));
628 628
629 629 case SCF_ERROR_INVALID_ARGUMENT:
630 630 case SCF_ERROR_NOT_SET:
631 631 case SCF_ERROR_NOT_BOUND:
632 632 case SCF_ERROR_HANDLE_MISMATCH:
633 633 default:
634 634 bad_error("scf_iter_next_instance",
635 635 scf_error());
636 636 }
637 637 }
638 638
639 639 if (scf_instance_get_snapshot(inst, snap_running,
640 640 snap) == 0)
641 641 break;
642 642
643 643 switch (scf_error()) {
644 644 case SCF_ERROR_NOT_FOUND:
645 645 case SCF_ERROR_DELETED:
646 646 continue;
647 647
648 648 case SCF_ERROR_CONNECTION_BROKEN:
649 649 return (ECONNABORTED);
650 650
651 651 case SCF_ERROR_HANDLE_MISMATCH:
652 652 case SCF_ERROR_INVALID_ARGUMENT:
653 653 case SCF_ERROR_NOT_SET:
654 654 case SCF_ERROR_NOT_BOUND:
655 655 default:
656 656 bad_error("scf_instance_get_snapshot",
657 657 scf_error());
658 658 }
659 659 }
660 660 } else {
661 661 if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
662 662 switch (scf_error()) {
663 663 case SCF_ERROR_NOT_FOUND:
664 664 break;
665 665
666 666 case SCF_ERROR_DELETED:
667 667 case SCF_ERROR_CONNECTION_BROKEN:
668 668 return (scferror2errno(scf_error()));
669 669
670 670 case SCF_ERROR_NOT_BOUND:
671 671 case SCF_ERROR_HANDLE_MISMATCH:
672 672 case SCF_ERROR_INVALID_ARGUMENT:
673 673 case SCF_ERROR_NOT_SET:
674 674 default:
675 675 bad_error("scf_instance_get_snapshot",
676 676 scf_error());
677 677 }
678 678
679 679 if (scf_instance_get_pg(ent, name, pg) == 0)
680 680 return (0);
681 681
682 682 switch (scf_error()) {
683 683 case SCF_ERROR_DELETED:
684 684 case SCF_ERROR_NOT_FOUND:
685 685 case SCF_ERROR_INVALID_ARGUMENT:
686 686 case SCF_ERROR_CONNECTION_BROKEN:
687 687 return (scferror2errno(scf_error()));
688 688
689 689 case SCF_ERROR_NOT_BOUND:
690 690 case SCF_ERROR_HANDLE_MISMATCH:
691 691 case SCF_ERROR_NOT_SET:
692 692 default:
693 693 bad_error("scf_instance_get_pg", scf_error());
694 694 }
695 695 }
696 696 }
697 697
698 698 r = get_snaplevel(snap, issvc, snpl);
699 699 switch (r) {
700 700 case 0:
701 701 break;
702 702
703 703 case ECONNABORTED:
704 704 case ECANCELED:
705 705 return (r);
706 706
707 707 case ENOENT:
708 708 return (EBADF);
709 709
710 710 default:
711 711 bad_error("get_snaplevel", r);
712 712 }
713 713
714 714 if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
715 715 return (0);
716 716
717 717 switch (scf_error()) {
718 718 case SCF_ERROR_DELETED:
719 719 case SCF_ERROR_INVALID_ARGUMENT:
720 720 case SCF_ERROR_CONNECTION_BROKEN:
721 721 case SCF_ERROR_NOT_FOUND:
722 722 return (scferror2errno(scf_error()));
723 723
724 724 case SCF_ERROR_NOT_BOUND:
725 725 case SCF_ERROR_HANDLE_MISMATCH:
726 726 case SCF_ERROR_NOT_SET:
727 727 default:
728 728 bad_error("scf_snaplevel_get_pg", scf_error());
729 729 /* NOTREACHED */
730 730 }
731 731 }
732 732
733 733 /*
734 734 * To be registered with atexit().
735 735 */
736 736 static void
737 737 remove_tempfile(void)
738 738 {
739 739 int ret;
740 740
741 741 if (tempfile != NULL) {
742 742 if (fclose(tempfile) == EOF)
743 743 (void) warn(gettext("Could not close temporary file"));
744 744 tempfile = NULL;
745 745 }
746 746
747 747 if (tempfilename[0] != '\0') {
748 748 do {
749 749 ret = remove(tempfilename);
750 750 } while (ret == -1 && errno == EINTR);
751 751 if (ret == -1)
752 752 warn(gettext("Could not remove temporary file"));
753 753 tempfilename[0] = '\0';
754 754 }
755 755 }
756 756
757 757 /*
758 758 * Launch private svc.configd(1M) for manipulating alternate repositories.
759 759 */
760 760 static void
761 761 start_private_repository(engine_state_t *est)
762 762 {
763 763 int fd, stat;
764 764 struct door_info info;
765 765 pid_t pid;
766 766
767 767 /*
768 768 * 1. Create a temporary file for the door.
769 769 */
770 770 if (est->sc_repo_doorname != NULL)
771 771 free((void *)est->sc_repo_doorname);
772 772
773 773 est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
774 774 if (est->sc_repo_doorname == NULL)
775 775 uu_die(gettext("Could not acquire temporary filename"));
776 776
777 777 fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
778 778 if (fd < 0)
779 779 uu_die(gettext("Could not create temporary file for "
780 780 "repository server"));
781 781
782 782 (void) close(fd);
783 783
784 784 /*
785 785 * 2. Launch a configd with that door, using the specified
786 786 * repository.
787 787 */
788 788 if ((est->sc_repo_pid = fork()) == 0) {
789 789 (void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
790 790 "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
791 791 NULL);
792 792 uu_die(gettext("Could not execute %s"), est->sc_repo_server);
793 793 } else if (est->sc_repo_pid == -1)
794 794 uu_die(gettext("Attempt to fork failed"));
795 795
796 796 do {
797 797 pid = waitpid(est->sc_repo_pid, &stat, 0);
798 798 } while (pid == -1 && errno == EINTR);
799 799
800 800 if (pid == -1)
801 801 uu_die(gettext("Could not waitpid() for repository server"));
802 802
803 803 if (!WIFEXITED(stat)) {
804 804 uu_die(gettext("Repository server failed (status %d).\n"),
805 805 stat);
806 806 } else if (WEXITSTATUS(stat) != 0) {
807 807 uu_die(gettext("Repository server failed (exit %d).\n"),
808 808 WEXITSTATUS(stat));
809 809 }
810 810
811 811 /*
812 812 * See if it was successful by checking if the door is a door.
813 813 */
814 814
815 815 fd = open(est->sc_repo_doorname, O_RDWR);
816 816 if (fd < 0)
817 817 uu_die(gettext("Could not open door \"%s\""),
818 818 est->sc_repo_doorname);
819 819
820 820 if (door_info(fd, &info) < 0)
821 821 uu_die(gettext("Unexpected door_info() error"));
822 822
823 823 if (close(fd) == -1)
824 824 warn(gettext("Could not close repository door"),
825 825 strerror(errno));
826 826
827 827 est->sc_repo_pid = info.di_target;
828 828 }
829 829
830 830 void
831 831 lscf_cleanup(void)
832 832 {
833 833 /*
834 834 * In the case where we've launched a private svc.configd(1M)
835 835 * instance, we must terminate our child and remove the temporary
836 836 * rendezvous point.
837 837 */
838 838 if (est->sc_repo_pid > 0) {
839 839 (void) kill(est->sc_repo_pid, SIGTERM);
840 840 (void) waitpid(est->sc_repo_pid, NULL, 0);
841 841 (void) unlink(est->sc_repo_doorname);
842 842
843 843 est->sc_repo_pid = 0;
844 844 }
845 845 }
846 846
847 847 void
848 848 unselect_cursnap(void)
849 849 {
850 850 void *cookie;
851 851
852 852 cur_level = NULL;
853 853
854 854 cookie = NULL;
855 855 while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
856 856 scf_snaplevel_destroy(cur_elt->sl);
857 857 free(cur_elt);
858 858 }
859 859
860 860 scf_snapshot_destroy(cur_snap);
861 861 cur_snap = NULL;
862 862 }
863 863
864 864 void
865 865 lscf_prep_hndl(void)
866 866 {
867 867 if (g_hndl != NULL)
868 868 return;
869 869
870 870 g_hndl = scf_handle_create(SCF_VERSION);
871 871 if (g_hndl == NULL)
872 872 scfdie();
873 873
874 874 if (est->sc_repo_filename != NULL)
875 875 start_private_repository(est);
876 876
877 877 if (est->sc_repo_doorname != NULL) {
878 878 scf_value_t *repo_value;
879 879 int ret;
880 880
881 881 repo_value = scf_value_create(g_hndl);
882 882 if (repo_value == NULL)
883 883 scfdie();
884 884
885 885 ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
886 886 assert(ret == SCF_SUCCESS);
887 887
888 888 if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
889 889 SCF_SUCCESS)
890 890 scfdie();
891 891
892 892 scf_value_destroy(repo_value);
893 893 }
894 894
895 895 if (scf_handle_bind(g_hndl) != 0)
896 896 uu_die(gettext("Could not connect to repository server: %s.\n"),
897 897 scf_strerror(scf_error()));
898 898
899 899 cur_scope = scf_scope_create(g_hndl);
900 900 if (cur_scope == NULL)
901 901 scfdie();
902 902
903 903 if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
904 904 scfdie();
905 905 }
906 906
907 907 static void
908 908 repository_teardown(void)
909 909 {
910 910 if (g_hndl != NULL) {
911 911 if (cur_snap != NULL)
912 912 unselect_cursnap();
913 913 scf_instance_destroy(cur_inst);
914 914 scf_service_destroy(cur_svc);
915 915 scf_scope_destroy(cur_scope);
916 916 scf_handle_destroy(g_hndl);
917 917 cur_inst = NULL;
918 918 cur_svc = NULL;
919 919 cur_scope = NULL;
920 920 g_hndl = NULL;
921 921 lscf_cleanup();
922 922 }
923 923 }
924 924
925 925 void
926 926 lscf_set_repository(const char *repfile, int force)
927 927 {
928 928 repository_teardown();
929 929
930 930 if (est->sc_repo_filename != NULL) {
931 931 free((void *)est->sc_repo_filename);
932 932 est->sc_repo_filename = NULL;
933 933 }
934 934
935 935 if ((force == 0) && (access(repfile, R_OK) != 0)) {
936 936 /*
937 937 * Repository file does not exist
938 938 * or has no read permission.
939 939 */
940 940 warn(gettext("Cannot access \"%s\": %s\n"),
941 941 repfile, strerror(errno));
942 942 } else {
943 943 est->sc_repo_filename = safe_strdup(repfile);
944 944 }
945 945
946 946 lscf_prep_hndl();
947 947 }
948 948
949 949 void
950 950 lscf_init()
951 951 {
952 952 if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
953 953 (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
954 954 (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
955 955 0 ||
956 956 (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
957 957 scfdie();
958 958
959 959 max_scf_len = max_scf_fmri_len;
960 960 if (max_scf_name_len > max_scf_len)
961 961 max_scf_len = max_scf_name_len;
962 962 if (max_scf_pg_type_len > max_scf_len)
963 963 max_scf_len = max_scf_pg_type_len;
964 964 /*
965 965 * When a value of type opaque is represented as a string, the
966 966 * string contains 2 characters for every byte of data. That is
967 967 * because the string contains the hex representation of the opaque
968 968 * value.
969 969 */
970 970 if (2 * max_scf_value_len > max_scf_len)
971 971 max_scf_len = 2 * max_scf_value_len;
972 972
973 973 if (atexit(remove_tempfile) != 0)
974 974 uu_die(gettext("Could not register atexit() function"));
975 975
976 976 emsg_entity_not_selected = gettext("An entity is not selected.\n");
977 977 emsg_permission_denied = gettext("Permission denied.\n");
978 978 emsg_create_xml = gettext("Could not create XML node.\n");
979 979 emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
980 980 emsg_invalid_for_snapshot =
981 981 gettext("Invalid operation on a snapshot.\n");
982 982 emsg_read_only = gettext("Backend read-only.\n");
983 983 emsg_deleted = gettext("Current selection has been deleted.\n");
984 984 emsg_invalid_pg_name =
985 985 gettext("Invalid property group name \"%s\".\n");
986 986 emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
987 987 emsg_no_such_pg = gettext("No such property group \"%s\".\n");
988 988 emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
989 989 "with invalid name \"%s\".\n");
990 990 emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
991 991 "group with invalid name \"%s\" or type \"%s\".\n");
992 992 emsg_pg_added = gettext("%s changed unexpectedly "
993 993 "(property group \"%s\" added).\n");
994 994 emsg_pg_changed = gettext("%s changed unexpectedly "
995 995 "(property group \"%s\" changed).\n");
996 996 emsg_pg_deleted = gettext("%s changed unexpectedly "
997 997 "(property group \"%s\" or an ancestor was deleted).\n");
998 998 emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
999 999 "in %s (permission denied).\n");
1000 1000 emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
1001 1001 "in %s (permission denied).\n");
1002 1002 emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
1003 1003 "in %s (permission denied).\n");
1004 1004 emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
1005 1005 "(permission denied).\n");
1006 1006 emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
1007 1007 "new dependent \"%s\" because it already exists). Warning: The "
1008 1008 "current dependent's target (%s) does not exist.\n");
1009 1009 emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
1010 1010 "dependent \"%s\" because it already exists). Warning: The "
1011 1011 "current dependent's target (%s) does not have a dependency named "
1012 1012 "\"%s\" as expected.\n");
1013 1013
1014 1014 string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
1015 1015 offsetof(string_list_t, node), NULL, 0);
1016 1016 snaplevel_pool = uu_list_pool_create("snaplevels",
1017 1017 sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
1018 1018 NULL, 0);
1019 1019 }
1020 1020
1021 1021
1022 1022 static const char *
1023 1023 prop_to_typestr(const scf_property_t *prop)
1024 1024 {
1025 1025 scf_type_t ty;
1026 1026
1027 1027 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
1028 1028 scfdie();
1029 1029
1030 1030 return (scf_type_to_string(ty));
1031 1031 }
1032 1032
1033 1033 static scf_type_t
1034 1034 string_to_type(const char *type)
1035 1035 {
1036 1036 size_t len = strlen(type);
1037 1037 char *buf;
1038 1038
1039 1039 if (len == 0 || type[len - 1] != ':')
1040 1040 return (SCF_TYPE_INVALID);
1041 1041
1042 1042 buf = (char *)alloca(len + 1);
1043 1043 (void) strlcpy(buf, type, len + 1);
1044 1044 buf[len - 1] = 0;
1045 1045
1046 1046 return (scf_string_to_type(buf));
1047 1047 }
1048 1048
1049 1049 static scf_value_t *
1050 1050 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
1051 1051 {
1052 1052 scf_value_t *v;
1053 1053 char *dup, *nstr;
1054 1054 size_t len;
1055 1055
1056 1056 v = scf_value_create(g_hndl);
1057 1057 if (v == NULL)
1058 1058 scfdie();
1059 1059
1060 1060 len = strlen(str);
1061 1061 if (require_quotes &&
1062 1062 (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
1063 1063 semerr(gettext("Multiple string values or string values "
1064 1064 "with spaces must be quoted with '\"'.\n"));
1065 1065 scf_value_destroy(v);
1066 1066 return (NULL);
1067 1067 }
1068 1068
1069 1069 nstr = dup = safe_strdup(str);
1070 1070 if (dup[0] == '\"') {
1071 1071 /*
1072 1072 * Strip out the first and the last quote.
1073 1073 */
1074 1074 dup[len - 1] = '\0';
1075 1075 nstr = dup + 1;
1076 1076 }
1077 1077
1078 1078 if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
1079 1079 assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1080 1080 semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1081 1081 scf_type_to_string(ty), nstr);
1082 1082 scf_value_destroy(v);
1083 1083 v = NULL;
1084 1084 }
1085 1085 free(dup);
1086 1086 return (v);
1087 1087 }
1088 1088
1089 1089 /*
1090 1090 * Print str to strm, quoting double-quotes and backslashes with backslashes.
1091 1091 * Optionally append a comment prefix ('#') to newlines ('\n').
1092 1092 */
1093 1093 static int
1094 1094 quote_and_print(const char *str, FILE *strm, int commentnl)
1095 1095 {
1096 1096 const char *cp;
1097 1097
1098 1098 for (cp = str; *cp != '\0'; ++cp) {
1099 1099 if (*cp == '"' || *cp == '\\')
1100 1100 (void) putc('\\', strm);
1101 1101
1102 1102 (void) putc(*cp, strm);
1103 1103
1104 1104 if (commentnl && *cp == '\n') {
1105 1105 (void) putc('#', strm);
1106 1106 }
1107 1107 }
1108 1108
1109 1109 return (ferror(strm));
1110 1110 }
1111 1111
1112 1112 /*
1113 1113 * These wrappers around lowlevel functions provide consistent error checking
1114 1114 * and warnings.
1115 1115 */
1116 1116 static int
1117 1117 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1118 1118 {
1119 1119 if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1120 1120 return (0);
1121 1121
1122 1122 if (scf_error() != SCF_ERROR_NOT_FOUND)
1123 1123 scfdie();
1124 1124
1125 1125 if (g_verbose) {
1126 1126 ssize_t len;
1127 1127 char *fmri;
1128 1128
1129 1129 len = scf_pg_to_fmri(pg, NULL, 0);
1130 1130 if (len < 0)
1131 1131 scfdie();
1132 1132
1133 1133 fmri = safe_malloc(len + 1);
1134 1134
1135 1135 if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1136 1136 scfdie();
1137 1137
1138 1138 warn(gettext("Expected property %s of property group %s is "
1139 1139 "missing.\n"), propname, fmri);
1140 1140
1141 1141 free(fmri);
1142 1142 }
1143 1143
1144 1144 return (-1);
1145 1145 }
1146 1146
1147 1147 static int
1148 1148 prop_check_type(scf_property_t *prop, scf_type_t ty)
1149 1149 {
1150 1150 scf_type_t pty;
1151 1151
1152 1152 if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1153 1153 scfdie();
1154 1154
1155 1155 if (ty == pty)
1156 1156 return (0);
1157 1157
1158 1158 if (g_verbose) {
1159 1159 ssize_t len;
1160 1160 char *fmri;
1161 1161 const char *tystr;
1162 1162
1163 1163 len = scf_property_to_fmri(prop, NULL, 0);
1164 1164 if (len < 0)
1165 1165 scfdie();
1166 1166
1167 1167 fmri = safe_malloc(len + 1);
1168 1168
1169 1169 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1170 1170 scfdie();
1171 1171
1172 1172 tystr = scf_type_to_string(ty);
1173 1173 if (tystr == NULL)
1174 1174 tystr = "?";
1175 1175
1176 1176 warn(gettext("Property %s is not of expected type %s.\n"),
1177 1177 fmri, tystr);
1178 1178
1179 1179 free(fmri);
1180 1180 }
1181 1181
1182 1182 return (-1);
1183 1183 }
1184 1184
1185 1185 static int
1186 1186 prop_get_val(scf_property_t *prop, scf_value_t *val)
1187 1187 {
1188 1188 scf_error_t err;
1189 1189
1190 1190 if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1191 1191 return (0);
1192 1192
1193 1193 err = scf_error();
1194 1194
1195 1195 if (err != SCF_ERROR_NOT_FOUND &&
1196 1196 err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1197 1197 err != SCF_ERROR_PERMISSION_DENIED)
1198 1198 scfdie();
1199 1199
1200 1200 if (g_verbose) {
1201 1201 ssize_t len;
1202 1202 char *fmri, *emsg;
1203 1203
1204 1204 len = scf_property_to_fmri(prop, NULL, 0);
1205 1205 if (len < 0)
1206 1206 scfdie();
1207 1207
1208 1208 fmri = safe_malloc(len + 1);
1209 1209
1210 1210 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1211 1211 scfdie();
1212 1212
1213 1213 if (err == SCF_ERROR_NOT_FOUND)
1214 1214 emsg = gettext("Property %s has no values; expected "
1215 1215 "one.\n");
1216 1216 else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1217 1217 emsg = gettext("Property %s has multiple values; "
1218 1218 "expected one.\n");
1219 1219 else
1220 1220 emsg = gettext("No permission to read property %s.\n");
1221 1221
1222 1222 warn(emsg, fmri);
1223 1223
1224 1224 free(fmri);
1225 1225 }
1226 1226
1227 1227 return (-1);
1228 1228 }
1229 1229
1230 1230
1231 1231 static boolean_t
1232 1232 snaplevel_is_instance(const scf_snaplevel_t *level)
1233 1233 {
1234 1234 if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1235 1235 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1236 1236 scfdie();
1237 1237 return (0);
1238 1238 } else {
1239 1239 return (1);
1240 1240 }
1241 1241 }
1242 1242
1243 1243 /*
1244 1244 * Decode FMRI into a service or instance, and put the result in *ep. If
1245 1245 * memory cannot be allocated, return SCF_ERROR_NO_MEMORY. If the FMRI is
1246 1246 * invalid, return SCF_ERROR_INVALID_ARGUMENT. If the FMRI does not specify
1247 1247 * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED. If the entity cannot be
1248 1248 * found, return SCF_ERROR_NOT_FOUND. Otherwise return SCF_ERROR_NONE, point
1249 1249 * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1250 1250 * whether *ep is a service.
1251 1251 */
1252 1252 static scf_error_t
1253 1253 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1254 1254 {
1255 1255 char *fmri_copy;
1256 1256 const char *sstr, *istr, *pgstr;
1257 1257 scf_service_t *svc;
1258 1258 scf_instance_t *inst;
1259 1259
1260 1260 fmri_copy = strdup(fmri);
1261 1261 if (fmri_copy == NULL)
1262 1262 return (SCF_ERROR_NO_MEMORY);
1263 1263
1264 1264 if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1265 1265 SCF_SUCCESS) {
1266 1266 free(fmri_copy);
1267 1267 return (SCF_ERROR_INVALID_ARGUMENT);
1268 1268 }
1269 1269
1270 1270 free(fmri_copy);
1271 1271
1272 1272 if (sstr == NULL || pgstr != NULL)
1273 1273 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1274 1274
1275 1275 if (istr == NULL) {
1276 1276 svc = scf_service_create(h);
1277 1277 if (svc == NULL)
1278 1278 return (SCF_ERROR_NO_MEMORY);
1279 1279
1280 1280 if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1281 1281 SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1282 1282 if (scf_error() != SCF_ERROR_NOT_FOUND)
1283 1283 scfdie();
1284 1284
1285 1285 return (SCF_ERROR_NOT_FOUND);
1286 1286 }
1287 1287
1288 1288 *ep = svc;
1289 1289 *isservice = 1;
1290 1290 } else {
1291 1291 inst = scf_instance_create(h);
1292 1292 if (inst == NULL)
1293 1293 return (SCF_ERROR_NO_MEMORY);
1294 1294
1295 1295 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1296 1296 NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1297 1297 if (scf_error() != SCF_ERROR_NOT_FOUND)
1298 1298 scfdie();
1299 1299
1300 1300 return (SCF_ERROR_NOT_FOUND);
1301 1301 }
1302 1302
1303 1303 *ep = inst;
1304 1304 *isservice = 0;
1305 1305 }
1306 1306
1307 1307 return (SCF_ERROR_NONE);
1308 1308 }
1309 1309
1310 1310 /*
1311 1311 * Create the entity named by fmri. Place a pointer to its libscf handle in
1312 1312 * *ep, and set or clear *isservicep if it is a service or an instance.
1313 1313 * Returns
1314 1314 * SCF_ERROR_NONE - success
1315 1315 * SCF_ERROR_NO_MEMORY - scf_*_create() failed
1316 1316 * SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1317 1317 * SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1318 1318 * SCF_ERROR_NOT_FOUND - no such scope
1319 1319 * SCF_ERROR_PERMISSION_DENIED
1320 1320 * SCF_ERROR_BACKEND_READONLY
1321 1321 * SCF_ERROR_BACKEND_ACCESS
1322 1322 */
1323 1323 static scf_error_t
1324 1324 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1325 1325 {
1326 1326 char *fmri_copy;
1327 1327 const char *scstr, *sstr, *istr, *pgstr;
1328 1328 scf_scope_t *scope = NULL;
1329 1329 scf_service_t *svc = NULL;
1330 1330 scf_instance_t *inst = NULL;
1331 1331 scf_error_t scfe;
1332 1332
1333 1333 fmri_copy = safe_strdup(fmri);
1334 1334
1335 1335 if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1336 1336 0) {
1337 1337 free(fmri_copy);
1338 1338 return (SCF_ERROR_INVALID_ARGUMENT);
1339 1339 }
1340 1340
1341 1341 if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1342 1342 free(fmri_copy);
1343 1343 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1344 1344 }
1345 1345
1346 1346 *ep = NULL;
1347 1347
1348 1348 if ((scope = scf_scope_create(h)) == NULL ||
1349 1349 (svc = scf_service_create(h)) == NULL ||
1350 1350 (inst = scf_instance_create(h)) == NULL) {
1351 1351 scfe = SCF_ERROR_NO_MEMORY;
1352 1352 goto out;
1353 1353 }
1354 1354
1355 1355 get_scope:
1356 1356 if (scf_handle_get_scope(h, scstr, scope) != 0) {
1357 1357 switch (scf_error()) {
1358 1358 case SCF_ERROR_CONNECTION_BROKEN:
1359 1359 scfdie();
1360 1360 /* NOTREACHED */
1361 1361
1362 1362 case SCF_ERROR_NOT_FOUND:
1363 1363 scfe = SCF_ERROR_NOT_FOUND;
1364 1364 goto out;
1365 1365
1366 1366 case SCF_ERROR_HANDLE_MISMATCH:
1367 1367 case SCF_ERROR_NOT_BOUND:
1368 1368 case SCF_ERROR_INVALID_ARGUMENT:
1369 1369 default:
1370 1370 bad_error("scf_handle_get_scope", scf_error());
1371 1371 }
1372 1372 }
1373 1373
1374 1374 get_svc:
1375 1375 if (scf_scope_get_service(scope, sstr, svc) != 0) {
1376 1376 switch (scf_error()) {
1377 1377 case SCF_ERROR_CONNECTION_BROKEN:
1378 1378 scfdie();
1379 1379 /* NOTREACHED */
1380 1380
1381 1381 case SCF_ERROR_DELETED:
1382 1382 goto get_scope;
1383 1383
1384 1384 case SCF_ERROR_NOT_FOUND:
1385 1385 break;
1386 1386
1387 1387 case SCF_ERROR_HANDLE_MISMATCH:
1388 1388 case SCF_ERROR_INVALID_ARGUMENT:
1389 1389 case SCF_ERROR_NOT_BOUND:
1390 1390 case SCF_ERROR_NOT_SET:
1391 1391 default:
1392 1392 bad_error("scf_scope_get_service", scf_error());
1393 1393 }
1394 1394
1395 1395 if (scf_scope_add_service(scope, sstr, svc) != 0) {
1396 1396 switch (scf_error()) {
1397 1397 case SCF_ERROR_CONNECTION_BROKEN:
1398 1398 scfdie();
1399 1399 /* NOTREACHED */
1400 1400
1401 1401 case SCF_ERROR_DELETED:
1402 1402 goto get_scope;
1403 1403
1404 1404 case SCF_ERROR_PERMISSION_DENIED:
1405 1405 case SCF_ERROR_BACKEND_READONLY:
1406 1406 case SCF_ERROR_BACKEND_ACCESS:
1407 1407 scfe = scf_error();
1408 1408 goto out;
1409 1409
1410 1410 case SCF_ERROR_HANDLE_MISMATCH:
1411 1411 case SCF_ERROR_INVALID_ARGUMENT:
1412 1412 case SCF_ERROR_NOT_BOUND:
1413 1413 case SCF_ERROR_NOT_SET:
1414 1414 default:
1415 1415 bad_error("scf_scope_get_service", scf_error());
1416 1416 }
1417 1417 }
1418 1418 }
1419 1419
1420 1420 if (istr == NULL) {
1421 1421 scfe = SCF_ERROR_NONE;
1422 1422 *ep = svc;
1423 1423 *isservicep = 1;
1424 1424 goto out;
1425 1425 }
1426 1426
1427 1427 get_inst:
1428 1428 if (scf_service_get_instance(svc, istr, inst) != 0) {
1429 1429 switch (scf_error()) {
1430 1430 case SCF_ERROR_CONNECTION_BROKEN:
1431 1431 scfdie();
1432 1432 /* NOTREACHED */
1433 1433
1434 1434 case SCF_ERROR_DELETED:
1435 1435 goto get_svc;
1436 1436
1437 1437 case SCF_ERROR_NOT_FOUND:
1438 1438 break;
1439 1439
1440 1440 case SCF_ERROR_HANDLE_MISMATCH:
1441 1441 case SCF_ERROR_INVALID_ARGUMENT:
1442 1442 case SCF_ERROR_NOT_BOUND:
1443 1443 case SCF_ERROR_NOT_SET:
1444 1444 default:
1445 1445 bad_error("scf_service_get_instance", scf_error());
1446 1446 }
1447 1447
1448 1448 if (scf_service_add_instance(svc, istr, inst) != 0) {
1449 1449 switch (scf_error()) {
1450 1450 case SCF_ERROR_CONNECTION_BROKEN:
1451 1451 scfdie();
1452 1452 /* NOTREACHED */
1453 1453
1454 1454 case SCF_ERROR_DELETED:
1455 1455 goto get_svc;
1456 1456
1457 1457 case SCF_ERROR_PERMISSION_DENIED:
1458 1458 case SCF_ERROR_BACKEND_READONLY:
1459 1459 case SCF_ERROR_BACKEND_ACCESS:
1460 1460 scfe = scf_error();
1461 1461 goto out;
1462 1462
1463 1463 case SCF_ERROR_HANDLE_MISMATCH:
1464 1464 case SCF_ERROR_INVALID_ARGUMENT:
1465 1465 case SCF_ERROR_NOT_BOUND:
1466 1466 case SCF_ERROR_NOT_SET:
1467 1467 default:
1468 1468 bad_error("scf_service_add_instance",
1469 1469 scf_error());
1470 1470 }
1471 1471 }
1472 1472 }
1473 1473
1474 1474 scfe = SCF_ERROR_NONE;
1475 1475 *ep = inst;
1476 1476 *isservicep = 0;
1477 1477
1478 1478 out:
1479 1479 if (*ep != inst)
1480 1480 scf_instance_destroy(inst);
1481 1481 if (*ep != svc)
1482 1482 scf_service_destroy(svc);
1483 1483 scf_scope_destroy(scope);
1484 1484 free(fmri_copy);
1485 1485 return (scfe);
1486 1486 }
1487 1487
1488 1488 /*
1489 1489 * Create or update a snapshot of inst. snap is a required scratch object.
1490 1490 *
1491 1491 * Returns
1492 1492 * 0 - success
1493 1493 * ECONNABORTED - repository connection broken
1494 1494 * EPERM - permission denied
1495 1495 * ENOSPC - configd is out of resources
1496 1496 * ECANCELED - inst was deleted
1497 1497 * -1 - unknown libscf error (message printed)
1498 1498 */
1499 1499 static int
1500 1500 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1501 1501 {
1502 1502 again:
1503 1503 if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1504 1504 if (_scf_snapshot_take_attach(inst, snap) != 0) {
1505 1505 switch (scf_error()) {
1506 1506 case SCF_ERROR_CONNECTION_BROKEN:
1507 1507 case SCF_ERROR_PERMISSION_DENIED:
1508 1508 case SCF_ERROR_NO_RESOURCES:
1509 1509 return (scferror2errno(scf_error()));
1510 1510
1511 1511 case SCF_ERROR_NOT_SET:
1512 1512 case SCF_ERROR_INVALID_ARGUMENT:
1513 1513 default:
1514 1514 bad_error("_scf_snapshot_take_attach",
1515 1515 scf_error());
1516 1516 }
1517 1517 }
1518 1518 } else {
1519 1519 switch (scf_error()) {
1520 1520 case SCF_ERROR_NOT_FOUND:
1521 1521 break;
1522 1522
1523 1523 case SCF_ERROR_DELETED:
1524 1524 case SCF_ERROR_CONNECTION_BROKEN:
1525 1525 return (scferror2errno(scf_error()));
1526 1526
1527 1527 case SCF_ERROR_HANDLE_MISMATCH:
1528 1528 case SCF_ERROR_NOT_BOUND:
1529 1529 case SCF_ERROR_INVALID_ARGUMENT:
1530 1530 case SCF_ERROR_NOT_SET:
1531 1531 default:
1532 1532 bad_error("scf_instance_get_snapshot", scf_error());
1533 1533 }
1534 1534
1535 1535 if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1536 1536 switch (scf_error()) {
1537 1537 case SCF_ERROR_EXISTS:
1538 1538 goto again;
1539 1539
1540 1540 case SCF_ERROR_CONNECTION_BROKEN:
1541 1541 case SCF_ERROR_NO_RESOURCES:
1542 1542 case SCF_ERROR_PERMISSION_DENIED:
1543 1543 return (scferror2errno(scf_error()));
1544 1544
1545 1545 default:
1546 1546 scfwarn();
1547 1547 return (-1);
1548 1548
1549 1549 case SCF_ERROR_NOT_SET:
1550 1550 case SCF_ERROR_INTERNAL:
1551 1551 case SCF_ERROR_INVALID_ARGUMENT:
1552 1552 case SCF_ERROR_HANDLE_MISMATCH:
1553 1553 bad_error("_scf_snapshot_take_new",
1554 1554 scf_error());
1555 1555 }
1556 1556 }
1557 1557 }
1558 1558
1559 1559 return (0);
1560 1560 }
1561 1561
1562 1562 static int
1563 1563 refresh_running_snapshot(void *entity)
1564 1564 {
1565 1565 scf_snapshot_t *snap;
1566 1566 int r;
1567 1567
1568 1568 if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1569 1569 scfdie();
1570 1570 r = take_snap(entity, snap_running, snap);
1571 1571 scf_snapshot_destroy(snap);
1572 1572
1573 1573 return (r);
1574 1574 }
1575 1575
1576 1576 /*
1577 1577 * Refresh entity. If isservice is zero, take entity to be an scf_instance_t *.
1578 1578 * Otherwise take entity to be an scf_service_t * and refresh all of its child
1579 1579 * instances. fmri is used for messages. inst, iter, and name_buf are used
1580 1580 * for scratch space. Returns
1581 1581 * 0 - success
1582 1582 * ECONNABORTED - repository connection broken
1583 1583 * ECANCELED - entity was deleted
1584 1584 * EACCES - backend denied access
1585 1585 * EPERM - permission denied
1586 1586 * ENOSPC - repository server out of resources
1587 1587 * -1 - _smf_refresh_instance_i() failed. scf_error() should be set.
1588 1588 */
1589 1589 static int
1590 1590 refresh_entity(int isservice, void *entity, const char *fmri,
1591 1591 scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1592 1592 {
1593 1593 scf_error_t scfe;
1594 1594 int r;
1595 1595
1596 1596 if (!isservice) {
1597 1597 /*
1598 1598 * Let restarter handles refreshing and making new running
1599 1599 * snapshot only if operating on a live repository and not
1600 1600 * running in early import.
1601 1601 */
1602 1602 if (est->sc_repo_filename == NULL &&
1603 1603 est->sc_repo_doorname == NULL &&
1604 1604 est->sc_in_emi == 0) {
1605 1605 if (_smf_refresh_instance_i(entity) == 0) {
1606 1606 if (g_verbose)
1607 1607 warn(gettext("Refreshed %s.\n"), fmri);
1608 1608 return (0);
1609 1609 }
1610 1610
1611 1611 switch (scf_error()) {
1612 1612 case SCF_ERROR_BACKEND_ACCESS:
1613 1613 return (EACCES);
1614 1614
1615 1615 case SCF_ERROR_PERMISSION_DENIED:
1616 1616 return (EPERM);
1617 1617
1618 1618 default:
1619 1619 return (-1);
1620 1620 }
1621 1621 } else {
1622 1622 r = refresh_running_snapshot(entity);
1623 1623 switch (r) {
1624 1624 case 0:
1625 1625 break;
1626 1626
1627 1627 case ECONNABORTED:
1628 1628 case ECANCELED:
1629 1629 case EPERM:
1630 1630 case ENOSPC:
1631 1631 break;
1632 1632
1633 1633 default:
1634 1634 bad_error("refresh_running_snapshot",
1635 1635 scf_error());
1636 1636 }
1637 1637
1638 1638 return (r);
1639 1639 }
1640 1640 }
1641 1641
1642 1642 if (scf_iter_service_instances(iter, entity) != 0) {
1643 1643 switch (scf_error()) {
1644 1644 case SCF_ERROR_CONNECTION_BROKEN:
1645 1645 return (ECONNABORTED);
1646 1646
1647 1647 case SCF_ERROR_DELETED:
1648 1648 return (ECANCELED);
1649 1649
1650 1650 case SCF_ERROR_HANDLE_MISMATCH:
1651 1651 case SCF_ERROR_NOT_BOUND:
1652 1652 case SCF_ERROR_NOT_SET:
1653 1653 default:
1654 1654 bad_error("scf_iter_service_instances", scf_error());
1655 1655 }
1656 1656 }
1657 1657
1658 1658 for (;;) {
1659 1659 r = scf_iter_next_instance(iter, inst);
1660 1660 if (r == 0)
1661 1661 break;
1662 1662 if (r != 1) {
1663 1663 switch (scf_error()) {
1664 1664 case SCF_ERROR_CONNECTION_BROKEN:
1665 1665 return (ECONNABORTED);
1666 1666
1667 1667 case SCF_ERROR_DELETED:
1668 1668 return (ECANCELED);
1669 1669
1670 1670 case SCF_ERROR_HANDLE_MISMATCH:
1671 1671 case SCF_ERROR_NOT_BOUND:
1672 1672 case SCF_ERROR_NOT_SET:
1673 1673 case SCF_ERROR_INVALID_ARGUMENT:
1674 1674 default:
1675 1675 bad_error("scf_iter_next_instance",
1676 1676 scf_error());
1677 1677 }
1678 1678 }
1679 1679
1680 1680 /*
1681 1681 * Similarly, just take a new running snapshot if operating on
1682 1682 * a non-live repository or running during early import.
1683 1683 */
1684 1684 if (est->sc_repo_filename != NULL ||
1685 1685 est->sc_repo_doorname != NULL ||
1686 1686 est->sc_in_emi == 1) {
1687 1687 r = refresh_running_snapshot(inst);
1688 1688 switch (r) {
1689 1689 case 0:
1690 1690 continue;
1691 1691
1692 1692 case ECONNABORTED:
1693 1693 case ECANCELED:
1694 1694 case EPERM:
1695 1695 case ENOSPC:
1696 1696 break;
1697 1697 default:
1698 1698 bad_error("refresh_running_snapshot",
1699 1699 scf_error());
1700 1700 }
1701 1701
1702 1702 return (r);
1703 1703
1704 1704 }
1705 1705
1706 1706 if (_smf_refresh_instance_i(inst) == 0) {
1707 1707 if (g_verbose) {
1708 1708 if (scf_instance_get_name(inst, name_buf,
1709 1709 max_scf_name_len + 1) < 0)
1710 1710 (void) strcpy(name_buf, "?");
1711 1711
1712 1712 warn(gettext("Refreshed %s:%s.\n"),
1713 1713 fmri, name_buf);
1714 1714 }
1715 1715 } else {
1716 1716 if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1717 1717 g_verbose) {
1718 1718 scfe = scf_error();
1719 1719
1720 1720 if (scf_instance_to_fmri(inst, name_buf,
1721 1721 max_scf_name_len + 1) < 0)
1722 1722 (void) strcpy(name_buf, "?");
1723 1723
1724 1724 warn(gettext(
1725 1725 "Refresh of %s:%s failed: %s.\n"), fmri,
1726 1726 name_buf, scf_strerror(scfe));
1727 1727 }
1728 1728 }
1729 1729 }
1730 1730
1731 1731 return (0);
1732 1732 }
1733 1733
1734 1734 static void
1735 1735 private_refresh(void)
1736 1736 {
1737 1737 scf_instance_t *pinst = NULL;
1738 1738 scf_iter_t *piter = NULL;
1739 1739 ssize_t fmrilen;
1740 1740 size_t bufsz;
1741 1741 char *fmribuf;
1742 1742 void *ent;
1743 1743 int issvc;
1744 1744 int r;
1745 1745
1746 1746 if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1747 1747 return;
1748 1748
1749 1749 assert(cur_svc != NULL);
1750 1750
1751 1751 bufsz = max_scf_fmri_len + 1;
1752 1752 fmribuf = safe_malloc(bufsz);
1753 1753 if (cur_inst) {
1754 1754 issvc = 0;
1755 1755 ent = cur_inst;
1756 1756 fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1757 1757 } else {
1758 1758 issvc = 1;
1759 1759 ent = cur_svc;
1760 1760 fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1761 1761 if ((pinst = scf_instance_create(g_hndl)) == NULL)
1762 1762 scfdie();
1763 1763
1764 1764 if ((piter = scf_iter_create(g_hndl)) == NULL)
1765 1765 scfdie();
1766 1766 }
1767 1767 if (fmrilen < 0) {
1768 1768 free(fmribuf);
1769 1769 if (scf_error() != SCF_ERROR_DELETED)
1770 1770 scfdie();
1771 1771
1772 1772 warn(emsg_deleted);
1773 1773 return;
1774 1774 }
1775 1775 assert(fmrilen < bufsz);
1776 1776
1777 1777 r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1778 1778 switch (r) {
1779 1779 case 0:
1780 1780 break;
1781 1781
1782 1782 case ECONNABORTED:
1783 1783 warn(gettext("Could not refresh %s "
1784 1784 "(repository connection broken).\n"), fmribuf);
1785 1785 break;
1786 1786
1787 1787 case ECANCELED:
1788 1788 warn(emsg_deleted);
1789 1789 break;
1790 1790
1791 1791 case EPERM:
1792 1792 warn(gettext("Could not refresh %s "
1793 1793 "(permission denied).\n"), fmribuf);
1794 1794 break;
1795 1795
1796 1796 case ENOSPC:
1797 1797 warn(gettext("Could not refresh %s "
1798 1798 "(repository server out of resources).\n"),
1799 1799 fmribuf);
1800 1800 break;
1801 1801
1802 1802 case EACCES:
1803 1803 default:
1804 1804 bad_error("refresh_entity", scf_error());
1805 1805 }
1806 1806
1807 1807 if (issvc) {
1808 1808 scf_instance_destroy(pinst);
1809 1809 scf_iter_destroy(piter);
1810 1810 }
1811 1811
1812 1812 free(fmribuf);
1813 1813 }
1814 1814
1815 1815
1816 1816 static int
1817 1817 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1818 1818 {
1819 1819 cbp->sc_err = scferror2errno(err);
1820 1820 return (UU_WALK_ERROR);
1821 1821 }
1822 1822
1823 1823 static int
1824 1824 stash_scferror(scf_callback_t *cbp)
1825 1825 {
1826 1826 return (stash_scferror_err(cbp, scf_error()));
1827 1827 }
1828 1828
1829 1829 static int select_inst(const char *);
1830 1830 static int select_svc(const char *);
1831 1831
1832 1832 /*
1833 1833 * Take a property that does not have a type and check to see if a type
1834 1834 * exists or can be gleened from the current data. Set the type.
1835 1835 *
1836 1836 * Check the current level (instance) and then check the higher level
1837 1837 * (service). This could be the case for adding a new property to
1838 1838 * the instance that's going to "override" a service level property.
1839 1839 *
1840 1840 * For a property :
1841 1841 * 1. Take the type from an existing property
1842 1842 * 2. Take the type from a template entry
1843 1843 *
1844 1844 * If the type can not be found, then leave the type as is, and let the import
1845 1845 * report the problem of the missing type.
1846 1846 */
1847 1847 static int
1848 1848 find_current_prop_type(void *p, void *g)
1849 1849 {
1850 1850 property_t *prop = p;
1851 1851 scf_callback_t *lcb = g;
1852 1852 pgroup_t *pg = NULL;
1853 1853
1854 1854 const char *fmri = NULL;
1855 1855 char *lfmri = NULL;
1856 1856 char *cur_selection = NULL;
1857 1857
1858 1858 scf_propertygroup_t *sc_pg = NULL;
1859 1859 scf_property_t *sc_prop = NULL;
1860 1860 scf_pg_tmpl_t *t_pg = NULL;
1861 1861 scf_prop_tmpl_t *t_prop = NULL;
1862 1862 scf_type_t prop_type;
1863 1863
1864 1864 value_t *vp;
1865 1865 int issvc = lcb->sc_service;
1866 1866 int r = UU_WALK_ERROR;
1867 1867
1868 1868 if (prop->sc_value_type != SCF_TYPE_INVALID)
1869 1869 return (UU_WALK_NEXT);
1870 1870
1871 1871 t_prop = scf_tmpl_prop_create(g_hndl);
1872 1872 sc_prop = scf_property_create(g_hndl);
1873 1873 if (sc_prop == NULL || t_prop == NULL) {
1874 1874 warn(gettext("Unable to create the property to attempt and "
1875 1875 "find a missing type.\n"));
1876 1876
1877 1877 scf_property_destroy(sc_prop);
1878 1878 scf_tmpl_prop_destroy(t_prop);
1879 1879
1880 1880 return (UU_WALK_ERROR);
1881 1881 }
1882 1882
1883 1883 if (lcb->sc_flags == 1) {
1884 1884 pg = lcb->sc_parent;
1885 1885 issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT);
1886 1886 fmri = pg->sc_parent->sc_fmri;
1887 1887 retry_pg:
1888 1888 if (cur_svc && cur_selection == NULL) {
1889 1889 cur_selection = safe_malloc(max_scf_fmri_len + 1);
1890 1890 lscf_get_selection_str(cur_selection,
1891 1891 max_scf_fmri_len + 1);
1892 1892
1893 1893 if (strcmp(cur_selection, fmri) != 0) {
1894 1894 lscf_select(fmri);
1895 1895 } else {
1896 1896 free(cur_selection);
1897 1897 cur_selection = NULL;
1898 1898 }
1899 1899 } else {
1900 1900 lscf_select(fmri);
1901 1901 }
1902 1902
1903 1903 if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) {
1904 1904 warn(gettext("Unable to create property group to "
1905 1905 "find a missing property type.\n"));
1906 1906
1907 1907 goto out;
1908 1908 }
1909 1909
1910 1910 if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) {
1911 1911 /*
1912 1912 * If this is the sc_pg from the parent
1913 1913 * let the caller clean up the sc_pg,
1914 1914 * and just throw it away in this case.
1915 1915 */
1916 1916 if (sc_pg != lcb->sc_parent)
1917 1917 scf_pg_destroy(sc_pg);
1918 1918
1919 1919 sc_pg = NULL;
1920 1920 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1921 1921 warn(gettext("Unable to create template "
1922 1922 "property group to find a property "
1923 1923 "type.\n"));
1924 1924
1925 1925 goto out;
1926 1926 }
1927 1927
1928 1928 if (scf_tmpl_get_by_pg_name(fmri, NULL,
1929 1929 pg->sc_pgroup_name, NULL, t_pg,
1930 1930 SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) {
1931 1931 /*
1932 1932 * if instance get service and jump back
1933 1933 */
1934 1934 scf_tmpl_pg_destroy(t_pg);
1935 1935 t_pg = NULL;
1936 1936 if (issvc == 0) {
1937 1937 entity_t *e = pg->sc_parent->sc_parent;
1938 1938
1939 1939 fmri = e->sc_fmri;
1940 1940 issvc = 1;
1941 1941 goto retry_pg;
1942 1942 } else {
1943 1943 goto out;
1944 1944 }
1945 1945 }
1946 1946 }
1947 1947 } else {
1948 1948 sc_pg = lcb->sc_parent;
1949 1949 }
1950 1950
1951 1951 /*
1952 1952 * Attempt to get the type from an existing property. If the property
1953 1953 * cannot be found then attempt to get the type from a template entry
1954 1954 * for the property.
1955 1955 *
1956 1956 * Finally, if at the instance level look at the service level.
1957 1957 */
1958 1958 if (sc_pg != NULL &&
1959 1959 pg_get_prop(sc_pg, prop->sc_property_name,
1960 1960 sc_prop) == SCF_SUCCESS &&
1961 1961 scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) {
1962 1962 prop->sc_value_type = prop_type;
1963 1963
1964 1964 /*
1965 1965 * Found a type, update the value types and validate
1966 1966 * the actual value against this type.
1967 1967 */
1968 1968 for (vp = uu_list_first(prop->sc_property_values);
1969 1969 vp != NULL;
1970 1970 vp = uu_list_next(prop->sc_property_values, vp)) {
1971 1971 vp->sc_type = prop->sc_value_type;
1972 1972 lxml_store_value(vp, 0, NULL);
1973 1973 }
1974 1974
1975 1975 r = UU_WALK_NEXT;
1976 1976 goto out;
1977 1977 }
1978 1978
1979 1979 /*
1980 1980 * If we get here with t_pg set to NULL then we had to have
1981 1981 * gotten an sc_pg but that sc_pg did not have the property
1982 1982 * we are looking for. So if the t_pg is not null look up
1983 1983 * the template entry for the property.
1984 1984 *
1985 1985 * If the t_pg is null then need to attempt to get a matching
1986 1986 * template entry for the sc_pg, and see if there is a property
1987 1987 * entry for that template entry.
1988 1988 */
1989 1989 do_tmpl :
1990 1990 if (t_pg != NULL &&
1991 1991 scf_tmpl_get_by_prop(t_pg, prop->sc_property_name,
1992 1992 t_prop, 0) == SCF_SUCCESS) {
1993 1993 if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) {
1994 1994 prop->sc_value_type = prop_type;
1995 1995
1996 1996 /*
1997 1997 * Found a type, update the value types and validate
1998 1998 * the actual value against this type.
1999 1999 */
2000 2000 for (vp = uu_list_first(prop->sc_property_values);
2001 2001 vp != NULL;
2002 2002 vp = uu_list_next(prop->sc_property_values, vp)) {
2003 2003 vp->sc_type = prop->sc_value_type;
2004 2004 lxml_store_value(vp, 0, NULL);
2005 2005 }
2006 2006
2007 2007 r = UU_WALK_NEXT;
2008 2008 goto out;
2009 2009 }
2010 2010 } else {
2011 2011 if (t_pg == NULL && sc_pg) {
2012 2012 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
2013 2013 warn(gettext("Unable to create template "
2014 2014 "property group to find a property "
2015 2015 "type.\n"));
2016 2016
2017 2017 goto out;
2018 2018 }
2019 2019
2020 2020 if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
2021 2021 scf_tmpl_pg_destroy(t_pg);
2022 2022 t_pg = NULL;
2023 2023 } else {
2024 2024 goto do_tmpl;
2025 2025 }
2026 2026 }
2027 2027 }
2028 2028
2029 2029 if (issvc == 0) {
2030 2030 scf_instance_t *i;
2031 2031 scf_service_t *s;
2032 2032
2033 2033 issvc = 1;
2034 2034 if (lcb->sc_flags == 1) {
2035 2035 entity_t *e = pg->sc_parent->sc_parent;
2036 2036
2037 2037 fmri = e->sc_fmri;
2038 2038 goto retry_pg;
2039 2039 }
2040 2040
2041 2041 /*
2042 2042 * because lcb->sc_flags was not set then this means
2043 2043 * the pg was not used and can be used here.
2044 2044 */
2045 2045 if ((pg = internal_pgroup_new()) == NULL) {
2046 2046 warn(gettext("Could not create internal property group "
2047 2047 "to find a missing type."));
2048 2048
2049 2049 goto out;
2050 2050 }
2051 2051
2052 2052 pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1);
2053 2053 if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name,
2054 2054 max_scf_name_len + 1) < 0)
2055 2055 goto out;
2056 2056
2057 2057 i = scf_instance_create(g_hndl);
2058 2058 s = scf_service_create(g_hndl);
2059 2059 if (i == NULL || s == NULL ||
2060 2060 scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) {
2061 2061 warn(gettext("Could not get a service for the instance "
2062 2062 "to find a missing type."));
2063 2063
2064 2064 goto out;
2065 2065 }
2066 2066
2067 2067 /*
2068 2068 * Check to see truly at the instance level.
2069 2069 */
2070 2070 lfmri = safe_malloc(max_scf_fmri_len + 1);
2071 2071 if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
2072 2072 scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0)
2073 2073 goto out;
2074 2074 else
2075 2075 fmri = (const char *)lfmri;
2076 2076
2077 2077 goto retry_pg;
2078 2078 }
2079 2079
2080 2080 out :
2081 2081 if (sc_pg != lcb->sc_parent) {
2082 2082 scf_pg_destroy(sc_pg);
2083 2083 }
2084 2084
2085 2085 /*
2086 2086 * If this is true then the pg was allocated
2087 2087 * here, and the name was set so need to free
2088 2088 * the name and the pg.
2089 2089 */
2090 2090 if (pg != NULL && pg != lcb->sc_parent) {
2091 2091 free((char *)pg->sc_pgroup_name);
2092 2092 internal_pgroup_free(pg);
2093 2093 }
2094 2094
2095 2095 if (cur_selection) {
2096 2096 lscf_select(cur_selection);
2097 2097 free(cur_selection);
2098 2098 }
2099 2099
2100 2100 scf_tmpl_pg_destroy(t_pg);
2101 2101 scf_tmpl_prop_destroy(t_prop);
2102 2102 scf_property_destroy(sc_prop);
2103 2103
2104 2104 if (r != UU_WALK_NEXT)
2105 2105 warn(gettext("Could not find property type for \"%s\" "
2106 2106 "from \"%s\"\n"), prop->sc_property_name,
2107 2107 fmri != NULL ? fmri : lcb->sc_source_fmri);
2108 2108
2109 2109 free(lfmri);
2110 2110
2111 2111 return (r);
2112 2112 }
2113 2113
2114 2114 /*
2115 2115 * Take a property group that does not have a type and check to see if a type
2116 2116 * exists or can be gleened from the current data. Set the type.
2117 2117 *
2118 2118 * Check the current level (instance) and then check the higher level
2119 2119 * (service). This could be the case for adding a new property to
2120 2120 * the instance that's going to "override" a service level property.
2121 2121 *
2122 2122 * For a property group
2123 2123 * 1. Take the type from an existing property group
2124 2124 * 2. Take the type from a template entry
2125 2125 *
2126 2126 * If the type can not be found, then leave the type as is, and let the import
2127 2127 * report the problem of the missing type.
2128 2128 */
2129 2129 static int
2130 2130 find_current_pg_type(void *p, void *sori)
2131 2131 {
2132 2132 entity_t *si = sori;
2133 2133 pgroup_t *pg = p;
2134 2134
2135 2135 const char *ofmri, *fmri;
2136 2136 char *cur_selection = NULL;
2137 2137 char *pg_type = NULL;
2138 2138
2139 2139 scf_propertygroup_t *sc_pg = NULL;
2140 2140 scf_pg_tmpl_t *t_pg = NULL;
2141 2141
2142 2142 int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2143 2143 int r = UU_WALK_ERROR;
2144 2144
2145 2145 ofmri = fmri = si->sc_fmri;
2146 2146 if (pg->sc_pgroup_type != NULL) {
2147 2147 r = UU_WALK_NEXT;
2148 2148
2149 2149 goto out;
2150 2150 }
2151 2151
2152 2152 sc_pg = scf_pg_create(g_hndl);
2153 2153 if (sc_pg == NULL) {
2154 2154 warn(gettext("Unable to create property group to attempt "
2155 2155 "and find a missing type.\n"));
2156 2156
2157 2157 return (UU_WALK_ERROR);
2158 2158 }
2159 2159
2160 2160 /*
2161 2161 * Using get_pg() requires that the cur_svc/cur_inst be
2162 2162 * via lscf_select. Need to preserve the current selection
2163 2163 * if going to use lscf_select() to set up the cur_svc/cur_inst
2164 2164 */
2165 2165 if (cur_svc) {
2166 2166 cur_selection = safe_malloc(max_scf_fmri_len + 1);
2167 2167 lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1);
2168 2168 }
2169 2169
2170 2170 /*
2171 2171 * If the property group exists get the type, and set
2172 2172 * the pgroup_t type of that type.
2173 2173 *
2174 2174 * If not the check for a template pg_pattern entry
2175 2175 * and take the type from that.
2176 2176 */
2177 2177 retry_svc:
2178 2178 lscf_select(fmri);
2179 2179
2180 2180 if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) {
2181 2181 pg_type = safe_malloc(max_scf_pg_type_len + 1);
2182 2182 if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type,
2183 2183 max_scf_pg_type_len + 1) != -1) {
2184 2184 pg->sc_pgroup_type = pg_type;
2185 2185
2186 2186 r = UU_WALK_NEXT;
2187 2187 goto out;
2188 2188 } else {
2189 2189 free(pg_type);
2190 2190 }
2191 2191 } else {
2192 2192 if ((t_pg == NULL) &&
2193 2193 (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
2194 2194 goto out;
2195 2195
2196 2196 if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name,
2197 2197 NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS &&
2198 2198 scf_tmpl_pg_type(t_pg, &pg_type) != -1) {
2199 2199 pg->sc_pgroup_type = pg_type;
2200 2200
2201 2201 r = UU_WALK_NEXT;
2202 2202 goto out;
2203 2203 }
2204 2204 }
2205 2205
2206 2206 /*
2207 2207 * If type is not found at the instance level then attempt to
2208 2208 * find the type at the service level.
2209 2209 */
2210 2210 if (!issvc) {
2211 2211 si = si->sc_parent;
2212 2212 fmri = si->sc_fmri;
2213 2213 issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2214 2214 goto retry_svc;
2215 2215 }
2216 2216
2217 2217 out :
2218 2218 if (cur_selection) {
2219 2219 lscf_select(cur_selection);
2220 2220 free(cur_selection);
2221 2221 }
2222 2222
2223 2223 /*
2224 2224 * Now walk the properties of the property group to make sure that
2225 2225 * all properties have the correct type and values are valid for
2226 2226 * those types.
2227 2227 */
2228 2228 if (r == UU_WALK_NEXT) {
2229 2229 scf_callback_t cb;
2230 2230
2231 2231 cb.sc_service = issvc;
2232 2232 cb.sc_source_fmri = ofmri;
2233 2233 if (sc_pg != NULL) {
2234 2234 cb.sc_parent = sc_pg;
2235 2235 cb.sc_flags = 0;
2236 2236 } else {
2237 2237 cb.sc_parent = pg;
2238 2238 cb.sc_flags = 1;
2239 2239 }
2240 2240
2241 2241 if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type,
2242 2242 &cb, UU_DEFAULT) != 0) {
2243 2243 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2244 2244 bad_error("uu_list_walk", uu_error());
2245 2245
2246 2246 r = UU_WALK_ERROR;
2247 2247 }
2248 2248 } else {
2249 2249 warn(gettext("Could not find property group type for "
2250 2250 "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri);
2251 2251 }
2252 2252
2253 2253 scf_tmpl_pg_destroy(t_pg);
2254 2254 scf_pg_destroy(sc_pg);
2255 2255
2256 2256 return (r);
2257 2257 }
2258 2258
2259 2259 /*
2260 2260 * Import. These functions import a bundle into the repository.
2261 2261 */
2262 2262
2263 2263 /*
2264 2264 * Add a transaction entry to lcbdata->sc_trans for this property_t. Uses
2265 2265 * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata. On success,
2266 2266 * returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
2267 2267 * lcbdata->sc_err to
2268 2268 * ENOMEM - out of memory
2269 2269 * ECONNABORTED - repository connection broken
2270 2270 * ECANCELED - sc_trans's property group was deleted
2271 2271 * EINVAL - p's name is invalid (error printed)
2272 2272 * - p has an invalid value (error printed)
2273 2273 */
2274 2274 static int
2275 2275 lscf_property_import(void *v, void *pvt)
2276 2276 {
2277 2277 property_t *p = v;
2278 2278 scf_callback_t *lcbdata = pvt;
2279 2279 value_t *vp;
2280 2280 scf_transaction_t *trans = lcbdata->sc_trans;
2281 2281 scf_transaction_entry_t *entr;
2282 2282 scf_value_t *val;
2283 2283 scf_type_t tp;
2284 2284
2285 2285 if ((lcbdata->sc_flags & SCI_NOENABLED ||
2286 2286 lcbdata->sc_flags & SCI_DELAYENABLE) &&
2287 2287 strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
2288 2288 lcbdata->sc_enable = p;
2289 2289 return (UU_WALK_NEXT);
2290 2290 }
2291 2291
2292 2292 entr = scf_entry_create(lcbdata->sc_handle);
2293 2293 if (entr == NULL) {
2294 2294 switch (scf_error()) {
2295 2295 case SCF_ERROR_NO_MEMORY:
2296 2296 return (stash_scferror(lcbdata));
2297 2297
2298 2298 case SCF_ERROR_INVALID_ARGUMENT:
2299 2299 default:
2300 2300 bad_error("scf_entry_create", scf_error());
2301 2301 }
2302 2302 }
2303 2303
2304 2304 tp = p->sc_value_type;
2305 2305
2306 2306 if (scf_transaction_property_new(trans, entr,
2307 2307 p->sc_property_name, tp) != 0) {
2308 2308 switch (scf_error()) {
2309 2309 case SCF_ERROR_INVALID_ARGUMENT:
2310 2310 semerr(emsg_invalid_prop_name, p->sc_property_name);
2311 2311 scf_entry_destroy(entr);
2312 2312 return (stash_scferror(lcbdata));
2313 2313
2314 2314 case SCF_ERROR_EXISTS:
2315 2315 break;
2316 2316
2317 2317 case SCF_ERROR_DELETED:
2318 2318 case SCF_ERROR_CONNECTION_BROKEN:
2319 2319 scf_entry_destroy(entr);
2320 2320 return (stash_scferror(lcbdata));
2321 2321
2322 2322 case SCF_ERROR_NOT_BOUND:
2323 2323 case SCF_ERROR_HANDLE_MISMATCH:
2324 2324 case SCF_ERROR_NOT_SET:
2325 2325 default:
2326 2326 bad_error("scf_transaction_property_new", scf_error());
2327 2327 }
2328 2328
2329 2329 if (scf_transaction_property_change_type(trans, entr,
2330 2330 p->sc_property_name, tp) != 0) {
2331 2331 switch (scf_error()) {
2332 2332 case SCF_ERROR_DELETED:
2333 2333 case SCF_ERROR_CONNECTION_BROKEN:
2334 2334 scf_entry_destroy(entr);
2335 2335 return (stash_scferror(lcbdata));
2336 2336
2337 2337 case SCF_ERROR_INVALID_ARGUMENT:
2338 2338 semerr(emsg_invalid_prop_name,
2339 2339 p->sc_property_name);
2340 2340 scf_entry_destroy(entr);
2341 2341 return (stash_scferror(lcbdata));
2342 2342
2343 2343 case SCF_ERROR_NOT_FOUND:
2344 2344 case SCF_ERROR_NOT_SET:
2345 2345 case SCF_ERROR_HANDLE_MISMATCH:
2346 2346 case SCF_ERROR_NOT_BOUND:
2347 2347 default:
2348 2348 bad_error(
2349 2349 "scf_transaction_property_change_type",
2350 2350 scf_error());
2351 2351 }
2352 2352 }
2353 2353 }
2354 2354
2355 2355 for (vp = uu_list_first(p->sc_property_values);
2356 2356 vp != NULL;
2357 2357 vp = uu_list_next(p->sc_property_values, vp)) {
2358 2358 val = scf_value_create(g_hndl);
2359 2359 if (val == NULL) {
2360 2360 switch (scf_error()) {
2361 2361 case SCF_ERROR_NO_MEMORY:
2362 2362 return (stash_scferror(lcbdata));
2363 2363
2364 2364 case SCF_ERROR_INVALID_ARGUMENT:
2365 2365 default:
2366 2366 bad_error("scf_value_create", scf_error());
2367 2367 }
2368 2368 }
2369 2369
2370 2370 switch (tp) {
2371 2371 case SCF_TYPE_BOOLEAN:
2372 2372 scf_value_set_boolean(val, vp->sc_u.sc_count);
2373 2373 break;
2374 2374 case SCF_TYPE_COUNT:
2375 2375 scf_value_set_count(val, vp->sc_u.sc_count);
2376 2376 break;
2377 2377 case SCF_TYPE_INTEGER:
2378 2378 scf_value_set_integer(val, vp->sc_u.sc_integer);
2379 2379 break;
2380 2380 default:
2381 2381 assert(vp->sc_u.sc_string != NULL);
2382 2382 if (scf_value_set_from_string(val, tp,
2383 2383 vp->sc_u.sc_string) != 0) {
2384 2384 if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
2385 2385 bad_error("scf_value_set_from_string",
2386 2386 scf_error());
2387 2387
2388 2388 warn(gettext("Value \"%s\" is not a valid "
2389 2389 "%s.\n"), vp->sc_u.sc_string,
2390 2390 scf_type_to_string(tp));
2391 2391 scf_value_destroy(val);
2392 2392 return (stash_scferror(lcbdata));
2393 2393 }
2394 2394 break;
2395 2395 }
2396 2396
2397 2397 if (scf_entry_add_value(entr, val) != 0)
2398 2398 bad_error("scf_entry_add_value", scf_error());
2399 2399 }
2400 2400
2401 2401 return (UU_WALK_NEXT);
2402 2402 }
2403 2403
2404 2404 /*
2405 2405 * Import a pgroup_t into the repository. Uses sc_handle, sc_parent,
2406 2406 * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2407 2407 * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2408 2408 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
2409 2409 * lcbdata->sc_err to
2410 2410 * ECONNABORTED - repository connection broken
2411 2411 * ENOMEM - out of memory
2412 2412 * ENOSPC - svc.configd is out of resources
2413 2413 * ECANCELED - sc_parent was deleted
2414 2414 * EPERM - could not create property group (permission denied) (error printed)
2415 2415 * - could not modify property group (permission denied) (error printed)
2416 2416 * - could not delete property group (permission denied) (error printed)
2417 2417 * EROFS - could not create property group (repository is read-only)
2418 2418 * - could not delete property group (repository is read-only)
2419 2419 * EACCES - could not create property group (backend access denied)
2420 2420 * - could not delete property group (backend access denied)
2421 2421 * EEXIST - could not create property group (already exists)
2422 2422 * EINVAL - invalid property group name (error printed)
2423 2423 * - invalid property name (error printed)
2424 2424 * - invalid value (error printed)
2425 2425 * EBUSY - new property group deleted (error printed)
2426 2426 * - new property group changed (error printed)
2427 2427 * - property group added (error printed)
2428 2428 * - property group deleted (error printed)
2429 2429 */
2430 2430 static int
2431 2431 entity_pgroup_import(void *v, void *pvt)
2432 2432 {
2433 2433 pgroup_t *p = v;
2434 2434 scf_callback_t cbdata;
2435 2435 scf_callback_t *lcbdata = pvt;
2436 2436 void *ent = lcbdata->sc_parent;
2437 2437 int issvc = lcbdata->sc_service;
2438 2438 int r;
2439 2439
2440 2440 const char * const pg_changed = gettext("%s changed unexpectedly "
2441 2441 "(new property group \"%s\" changed).\n");
2442 2442
2443 2443 /* Never import deleted property groups. */
2444 2444 if (p->sc_pgroup_delete) {
2445 2445 if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY &&
2446 2446 entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) {
2447 2447 goto delete_pg;
2448 2448 }
2449 2449 return (UU_WALK_NEXT);
2450 2450 }
2451 2451
2452 2452 if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
2453 2453 strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
2454 2454 lcbdata->sc_general = p;
2455 2455 return (UU_WALK_NEXT);
2456 2456 }
2457 2457
2458 2458 add_pg:
2459 2459 if (issvc)
2460 2460 r = scf_service_add_pg(ent, p->sc_pgroup_name,
2461 2461 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2462 2462 else
2463 2463 r = scf_instance_add_pg(ent, p->sc_pgroup_name,
2464 2464 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2465 2465 if (r != 0) {
2466 2466 switch (scf_error()) {
2467 2467 case SCF_ERROR_DELETED:
2468 2468 case SCF_ERROR_CONNECTION_BROKEN:
2469 2469 case SCF_ERROR_BACKEND_READONLY:
2470 2470 case SCF_ERROR_BACKEND_ACCESS:
2471 2471 case SCF_ERROR_NO_RESOURCES:
2472 2472 return (stash_scferror(lcbdata));
2473 2473
2474 2474 case SCF_ERROR_EXISTS:
2475 2475 if (lcbdata->sc_flags & SCI_FORCE)
2476 2476 break;
2477 2477 return (stash_scferror(lcbdata));
2478 2478
2479 2479 case SCF_ERROR_INVALID_ARGUMENT:
2480 2480 warn(emsg_fmri_invalid_pg_name_type,
2481 2481 lcbdata->sc_source_fmri,
2482 2482 p->sc_pgroup_name, p->sc_pgroup_type);
2483 2483 return (stash_scferror(lcbdata));
2484 2484
2485 2485 case SCF_ERROR_PERMISSION_DENIED:
2486 2486 warn(emsg_pg_add_perm, p->sc_pgroup_name,
2487 2487 lcbdata->sc_target_fmri);
2488 2488 return (stash_scferror(lcbdata));
2489 2489
2490 2490 case SCF_ERROR_NOT_BOUND:
2491 2491 case SCF_ERROR_HANDLE_MISMATCH:
2492 2492 case SCF_ERROR_NOT_SET:
2493 2493 default:
2494 2494 bad_error("scf_service_add_pg", scf_error());
2495 2495 }
2496 2496
2497 2497 if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2498 2498 switch (scf_error()) {
2499 2499 case SCF_ERROR_CONNECTION_BROKEN:
2500 2500 case SCF_ERROR_DELETED:
2501 2501 return (stash_scferror(lcbdata));
2502 2502
2503 2503 case SCF_ERROR_INVALID_ARGUMENT:
2504 2504 warn(emsg_fmri_invalid_pg_name,
2505 2505 lcbdata->sc_source_fmri,
2506 2506 p->sc_pgroup_name);
2507 2507 return (stash_scferror(lcbdata));
2508 2508
2509 2509 case SCF_ERROR_NOT_FOUND:
2510 2510 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2511 2511 p->sc_pgroup_name);
2512 2512 lcbdata->sc_err = EBUSY;
2513 2513 return (UU_WALK_ERROR);
2514 2514
2515 2515 case SCF_ERROR_NOT_BOUND:
2516 2516 case SCF_ERROR_HANDLE_MISMATCH:
2517 2517 case SCF_ERROR_NOT_SET:
2518 2518 default:
2519 2519 bad_error("entity_get_pg", scf_error());
2520 2520 }
2521 2521 }
2522 2522
2523 2523 if (lcbdata->sc_flags & SCI_KEEP)
2524 2524 goto props;
2525 2525
2526 2526 delete_pg:
2527 2527 if (scf_pg_delete(imp_pg) != 0) {
2528 2528 switch (scf_error()) {
2529 2529 case SCF_ERROR_DELETED:
2530 2530 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2531 2531 p->sc_pgroup_name);
2532 2532 lcbdata->sc_err = EBUSY;
2533 2533 return (UU_WALK_ERROR);
2534 2534
2535 2535 case SCF_ERROR_PERMISSION_DENIED:
2536 2536 warn(emsg_pg_del_perm, p->sc_pgroup_name,
2537 2537 lcbdata->sc_target_fmri);
2538 2538 return (stash_scferror(lcbdata));
2539 2539
2540 2540 case SCF_ERROR_BACKEND_READONLY:
2541 2541 case SCF_ERROR_BACKEND_ACCESS:
2542 2542 case SCF_ERROR_CONNECTION_BROKEN:
2543 2543 return (stash_scferror(lcbdata));
2544 2544
2545 2545 case SCF_ERROR_NOT_SET:
2546 2546 default:
2547 2547 bad_error("scf_pg_delete", scf_error());
2548 2548 }
2549 2549 }
2550 2550
2551 2551 if (p->sc_pgroup_delete)
2552 2552 return (UU_WALK_NEXT);
2553 2553
2554 2554 goto add_pg;
2555 2555 }
2556 2556
2557 2557 props:
2558 2558
2559 2559 /*
2560 2560 * Add properties to property group, if any.
2561 2561 */
2562 2562 cbdata.sc_handle = lcbdata->sc_handle;
2563 2563 cbdata.sc_parent = imp_pg;
2564 2564 cbdata.sc_flags = lcbdata->sc_flags;
2565 2565 cbdata.sc_trans = imp_tx;
2566 2566 cbdata.sc_enable = NULL;
2567 2567
2568 2568 if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2569 2569 switch (scf_error()) {
2570 2570 case SCF_ERROR_BACKEND_ACCESS:
2571 2571 case SCF_ERROR_BACKEND_READONLY:
2572 2572 case SCF_ERROR_CONNECTION_BROKEN:
2573 2573 return (stash_scferror(lcbdata));
2574 2574
2575 2575 case SCF_ERROR_DELETED:
2576 2576 warn(pg_changed, lcbdata->sc_target_fmri,
2577 2577 p->sc_pgroup_name);
2578 2578 lcbdata->sc_err = EBUSY;
2579 2579 return (UU_WALK_ERROR);
2580 2580
2581 2581 case SCF_ERROR_PERMISSION_DENIED:
2582 2582 warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2583 2583 lcbdata->sc_target_fmri);
2584 2584 return (stash_scferror(lcbdata));
2585 2585
2586 2586 case SCF_ERROR_NOT_BOUND:
2587 2587 case SCF_ERROR_NOT_SET:
2588 2588 case SCF_ERROR_IN_USE:
2589 2589 case SCF_ERROR_HANDLE_MISMATCH:
2590 2590 default:
2591 2591 bad_error("scf_transaction_start", scf_error());
2592 2592 }
2593 2593 }
2594 2594
2595 2595 if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2596 2596 UU_DEFAULT) != 0) {
2597 2597 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2598 2598 bad_error("uu_list_walk", uu_error());
2599 2599 scf_transaction_reset(imp_tx);
2600 2600
2601 2601 lcbdata->sc_err = cbdata.sc_err;
2602 2602 if (cbdata.sc_err == ECANCELED) {
2603 2603 warn(pg_changed, lcbdata->sc_target_fmri,
2604 2604 p->sc_pgroup_name);
2605 2605 lcbdata->sc_err = EBUSY;
2606 2606 }
2607 2607 return (UU_WALK_ERROR);
2608 2608 }
2609 2609
2610 2610 if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2611 2611 cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2612 2612
2613 2613 /*
2614 2614 * take the snapshot running snapshot then
2615 2615 * import the stored general/enable property
2616 2616 */
2617 2617 r = take_snap(ent, snap_running, imp_rsnap);
2618 2618 switch (r) {
2619 2619 case 0:
2620 2620 break;
2621 2621
2622 2622 case ECONNABORTED:
2623 2623 warn(gettext("Could not take %s snapshot on import "
2624 2624 "(repository connection broken).\n"),
2625 2625 snap_running);
2626 2626 lcbdata->sc_err = r;
2627 2627 return (UU_WALK_ERROR);
2628 2628 case ECANCELED:
2629 2629 warn(emsg_deleted);
2630 2630 lcbdata->sc_err = r;
2631 2631 return (UU_WALK_ERROR);
2632 2632
2633 2633 case EPERM:
2634 2634 warn(gettext("Could not take %s snapshot "
2635 2635 "(permission denied).\n"), snap_running);
2636 2636 lcbdata->sc_err = r;
2637 2637 return (UU_WALK_ERROR);
2638 2638
2639 2639 case ENOSPC:
2640 2640 warn(gettext("Could not take %s snapshot"
2641 2641 "(repository server out of resources).\n"),
2642 2642 snap_running);
2643 2643 lcbdata->sc_err = r;
2644 2644 return (UU_WALK_ERROR);
2645 2645
2646 2646 default:
2647 2647 bad_error("take_snap", r);
2648 2648 }
2649 2649
2650 2650 r = lscf_property_import(cbdata.sc_enable, &cbdata);
2651 2651 if (r != UU_WALK_NEXT) {
2652 2652 if (r != UU_WALK_ERROR)
2653 2653 bad_error("lscf_property_import", r);
2654 2654 return (EINVAL);
2655 2655 }
2656 2656 }
2657 2657
2658 2658 r = scf_transaction_commit(imp_tx);
2659 2659 switch (r) {
2660 2660 case 1:
2661 2661 r = UU_WALK_NEXT;
2662 2662 break;
2663 2663
2664 2664 case 0:
2665 2665 warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2666 2666 lcbdata->sc_err = EBUSY;
2667 2667 r = UU_WALK_ERROR;
2668 2668 break;
2669 2669
2670 2670 case -1:
2671 2671 switch (scf_error()) {
2672 2672 case SCF_ERROR_BACKEND_READONLY:
2673 2673 case SCF_ERROR_BACKEND_ACCESS:
2674 2674 case SCF_ERROR_CONNECTION_BROKEN:
2675 2675 case SCF_ERROR_NO_RESOURCES:
2676 2676 r = stash_scferror(lcbdata);
2677 2677 break;
2678 2678
2679 2679 case SCF_ERROR_DELETED:
2680 2680 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2681 2681 p->sc_pgroup_name);
2682 2682 lcbdata->sc_err = EBUSY;
2683 2683 r = UU_WALK_ERROR;
2684 2684 break;
2685 2685
2686 2686 case SCF_ERROR_PERMISSION_DENIED:
2687 2687 warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2688 2688 lcbdata->sc_target_fmri);
2689 2689 r = stash_scferror(lcbdata);
2690 2690 break;
2691 2691
2692 2692 case SCF_ERROR_NOT_SET:
2693 2693 case SCF_ERROR_INVALID_ARGUMENT:
2694 2694 case SCF_ERROR_NOT_BOUND:
2695 2695 default:
2696 2696 bad_error("scf_transaction_commit", scf_error());
2697 2697 }
2698 2698 break;
2699 2699
2700 2700 default:
2701 2701 bad_error("scf_transaction_commit", r);
2702 2702 }
2703 2703
2704 2704 scf_transaction_destroy_children(imp_tx);
2705 2705
2706 2706 return (r);
2707 2707 }
2708 2708
2709 2709 /*
2710 2710 * Returns
2711 2711 * 0 - success
2712 2712 * ECONNABORTED - repository connection broken
2713 2713 * ENOMEM - out of memory
2714 2714 * ENOSPC - svc.configd is out of resources
2715 2715 * ECANCELED - inst was deleted
2716 2716 * EPERM - could not create property group (permission denied) (error printed)
2717 2717 * - could not modify property group (permission denied) (error printed)
2718 2718 * EROFS - could not create property group (repository is read-only)
2719 2719 * EACCES - could not create property group (backend access denied)
2720 2720 * EEXIST - could not create property group (already exists)
2721 2721 * EINVAL - invalid property group name (error printed)
2722 2722 * - invalid property name (error printed)
2723 2723 * - invalid value (error printed)
2724 2724 * EBUSY - new property group changed (error printed)
2725 2725 */
2726 2726 static int
2727 2727 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2728 2728 const entity_t *isvc, int flags)
2729 2729 {
2730 2730 scf_callback_t cbdata;
2731 2731
2732 2732 cbdata.sc_handle = scf_service_handle(svc);
2733 2733 cbdata.sc_parent = svc;
2734 2734 cbdata.sc_service = 1;
2735 2735 cbdata.sc_general = 0;
2736 2736 cbdata.sc_enable = 0;
2737 2737 cbdata.sc_flags = flags;
2738 2738 cbdata.sc_source_fmri = isvc->sc_fmri;
2739 2739 cbdata.sc_target_fmri = target_fmri;
2740 2740
2741 2741 /*
2742 2742 * If the op is set, then add the flag to the callback
2743 2743 * flags for later use.
2744 2744 */
2745 2745 if (isvc->sc_op != SVCCFG_OP_NONE) {
2746 2746 switch (isvc->sc_op) {
2747 2747 case SVCCFG_OP_IMPORT :
2748 2748 cbdata.sc_flags |= SCI_OP_IMPORT;
2749 2749 break;
2750 2750 case SVCCFG_OP_APPLY :
2751 2751 cbdata.sc_flags |= SCI_OP_APPLY;
2752 2752 break;
2753 2753 case SVCCFG_OP_RESTORE :
2754 2754 cbdata.sc_flags |= SCI_OP_RESTORE;
2755 2755 break;
2756 2756 default :
2757 2757 uu_die(gettext("lscf_import_service_pgs : "
2758 2758 "Unknown op stored in the service entity\n"));
2759 2759
2760 2760 }
2761 2761 }
2762 2762
2763 2763 if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2764 2764 UU_DEFAULT) != 0) {
2765 2765 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2766 2766 bad_error("uu_list_walk", uu_error());
2767 2767
2768 2768 return (cbdata.sc_err);
2769 2769 }
2770 2770
2771 2771 return (0);
2772 2772 }
2773 2773
2774 2774 /*
2775 2775 * Returns
2776 2776 * 0 - success
2777 2777 * ECONNABORTED - repository connection broken
2778 2778 * ENOMEM - out of memory
2779 2779 * ENOSPC - svc.configd is out of resources
2780 2780 * ECANCELED - inst was deleted
2781 2781 * EPERM - could not create property group (permission denied) (error printed)
2782 2782 * - could not modify property group (permission denied) (error printed)
2783 2783 * EROFS - could not create property group (repository is read-only)
2784 2784 * EACCES - could not create property group (backend access denied)
2785 2785 * EEXIST - could not create property group (already exists)
2786 2786 * EINVAL - invalid property group name (error printed)
2787 2787 * - invalid property name (error printed)
2788 2788 * - invalid value (error printed)
2789 2789 * EBUSY - new property group changed (error printed)
2790 2790 */
2791 2791 static int
2792 2792 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2793 2793 const entity_t *iinst, int flags)
2794 2794 {
2795 2795 scf_callback_t cbdata;
2796 2796
2797 2797 cbdata.sc_handle = scf_instance_handle(inst);
2798 2798 cbdata.sc_parent = inst;
2799 2799 cbdata.sc_service = 0;
2800 2800 cbdata.sc_general = NULL;
2801 2801 cbdata.sc_enable = NULL;
2802 2802 cbdata.sc_flags = flags;
2803 2803 cbdata.sc_source_fmri = iinst->sc_fmri;
2804 2804 cbdata.sc_target_fmri = target_fmri;
2805 2805
2806 2806 /*
2807 2807 * If the op is set, then add the flag to the callback
2808 2808 * flags for later use.
2809 2809 */
2810 2810 if (iinst->sc_op != SVCCFG_OP_NONE) {
2811 2811 switch (iinst->sc_op) {
2812 2812 case SVCCFG_OP_IMPORT :
2813 2813 cbdata.sc_flags |= SCI_OP_IMPORT;
2814 2814 break;
2815 2815 case SVCCFG_OP_APPLY :
2816 2816 cbdata.sc_flags |= SCI_OP_APPLY;
2817 2817 break;
2818 2818 case SVCCFG_OP_RESTORE :
2819 2819 cbdata.sc_flags |= SCI_OP_RESTORE;
2820 2820 break;
2821 2821 default :
2822 2822 uu_die(gettext("lscf_import_instance_pgs : "
2823 2823 "Unknown op stored in the instance entity\n"));
2824 2824 }
2825 2825 }
2826 2826
2827 2827 if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2828 2828 UU_DEFAULT) != 0) {
2829 2829 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2830 2830 bad_error("uu_list_walk", uu_error());
2831 2831
2832 2832 return (cbdata.sc_err);
2833 2833 }
2834 2834
2835 2835 if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2836 2836 cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2837 2837 /*
2838 2838 * If importing with the SCI_NOENABLED flag then
2839 2839 * skip the delay, but if not then add the delay
2840 2840 * of the enable property.
2841 2841 */
2842 2842 if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2843 2843 cbdata.sc_flags |= SCI_DELAYENABLE;
2844 2844 }
2845 2845
2846 2846 if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2847 2847 != UU_WALK_NEXT)
2848 2848 return (cbdata.sc_err);
2849 2849 }
2850 2850
2851 2851 return (0);
2852 2852 }
2853 2853
2854 2854 /*
2855 2855 * Report the reasons why we can't upgrade pg2 to pg1.
2856 2856 */
2857 2857 static void
2858 2858 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2859 2859 int new)
2860 2860 {
2861 2861 property_t *p1, *p2;
2862 2862
2863 2863 assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2864 2864
2865 2865 if (!pg_attrs_equal(pg1, pg2, fmri, new))
2866 2866 return;
2867 2867
2868 2868 for (p1 = uu_list_first(pg1->sc_pgroup_props);
2869 2869 p1 != NULL;
2870 2870 p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2871 2871 p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2872 2872 if (p2 != NULL) {
2873 2873 (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2874 2874 new);
2875 2875 continue;
2876 2876 }
2877 2877
2878 2878 if (new)
2879 2879 warn(gettext("Conflict upgrading %s (new property "
2880 2880 "group \"%s\" is missing property \"%s\").\n"),
2881 2881 fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2882 2882 else
2883 2883 warn(gettext("Conflict upgrading %s (property "
2884 2884 "\"%s/%s\" is missing).\n"), fmri,
2885 2885 pg1->sc_pgroup_name, p1->sc_property_name);
2886 2886 }
2887 2887
2888 2888 /*
2889 2889 * Since pg1 should be from the manifest, any properties in pg2 which
2890 2890 * aren't in pg1 shouldn't be reported as conflicts.
2891 2891 */
2892 2892 }
2893 2893
2894 2894 /*
2895 2895 * Add transaction entries to tx which will upgrade cur's pg according to old
2896 2896 * & new.
2897 2897 *
2898 2898 * Returns
2899 2899 * 0 - success
2900 2900 * EINVAL - new has a property with an invalid name or value (message emitted)
2901 2901 * ENOMEM - out of memory
2902 2902 */
2903 2903 static int
2904 2904 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2905 2905 pgroup_t *cur, int speak, const char *fmri)
2906 2906 {
2907 2907 property_t *p, *new_p, *cur_p;
2908 2908 scf_transaction_entry_t *e;
2909 2909 int r;
2910 2910 int is_general;
2911 2911 int is_protected;
2912 2912
2913 2913 if (uu_list_walk(new->sc_pgroup_props, clear_int,
2914 2914 (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2915 2915 bad_error("uu_list_walk", uu_error());
2916 2916
2917 2917 is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2918 2918
2919 2919 for (p = uu_list_first(old->sc_pgroup_props);
2920 2920 p != NULL;
2921 2921 p = uu_list_next(old->sc_pgroup_props, p)) {
2922 2922 /* p is a property in the old property group. */
2923 2923
2924 2924 /* Protect live properties. */
2925 2925 is_protected = 0;
2926 2926 if (is_general) {
2927 2927 if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2928 2928 0 ||
2929 2929 strcmp(p->sc_property_name,
2930 2930 SCF_PROPERTY_RESTARTER) == 0)
2931 2931 is_protected = 1;
2932 2932 }
2933 2933
2934 2934 /* Look for the same property in the new properties. */
2935 2935 new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2936 2936 if (new_p != NULL) {
2937 2937 new_p->sc_seen = 1;
2938 2938
2939 2939 /*
2940 2940 * If the new property is the same as the old, don't do
2941 2941 * anything (leave any user customizations).
2942 2942 */
2943 2943 if (prop_equal(p, new_p, NULL, NULL, 0))
2944 2944 continue;
2945 2945
2946 2946 if (new_p->sc_property_override)
2947 2947 goto upgrade;
2948 2948 }
2949 2949
2950 2950 cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2951 2951 if (cur_p == NULL) {
2952 2952 /*
2953 2953 * p has been deleted from the repository. If we were
2954 2954 * going to delete it anyway, do nothing. Otherwise
2955 2955 * report a conflict.
2956 2956 */
2957 2957 if (new_p == NULL)
2958 2958 continue;
2959 2959
2960 2960 if (is_protected)
2961 2961 continue;
2962 2962
2963 2963 warn(gettext("Conflict upgrading %s "
2964 2964 "(property \"%s/%s\" is missing).\n"), fmri,
2965 2965 old->sc_pgroup_name, p->sc_property_name);
2966 2966 continue;
2967 2967 }
2968 2968
2969 2969 if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2970 2970 /*
2971 2971 * Conflict. Don't warn if the property is already the
2972 2972 * way we want it, though.
2973 2973 */
2974 2974 if (is_protected)
2975 2975 continue;
2976 2976
2977 2977 if (new_p == NULL)
2978 2978 (void) prop_equal(p, cur_p, fmri,
2979 2979 old->sc_pgroup_name, 0);
2980 2980 else
2981 2981 (void) prop_equal(cur_p, new_p, fmri,
2982 2982 old->sc_pgroup_name, 0);
2983 2983 continue;
2984 2984 }
2985 2985
2986 2986 if (is_protected) {
2987 2987 if (speak)
2988 2988 warn(gettext("%s: Refusing to upgrade "
2989 2989 "\"%s/%s\" (live property).\n"), fmri,
2990 2990 old->sc_pgroup_name, p->sc_property_name);
2991 2991 continue;
2992 2992 }
2993 2993
2994 2994 upgrade:
2995 2995 /* p hasn't been customized in the repository. Upgrade it. */
2996 2996 if (new_p == NULL) {
2997 2997 /* p was deleted. Delete from cur if unchanged. */
2998 2998 if (speak)
2999 2999 warn(gettext(
3000 3000 "%s: Deleting property \"%s/%s\".\n"),
3001 3001 fmri, old->sc_pgroup_name,
3002 3002 p->sc_property_name);
3003 3003
3004 3004 e = scf_entry_create(g_hndl);
3005 3005 if (e == NULL)
3006 3006 return (ENOMEM);
3007 3007
3008 3008 if (scf_transaction_property_delete(tx, e,
3009 3009 p->sc_property_name) != 0) {
3010 3010 switch (scf_error()) {
3011 3011 case SCF_ERROR_DELETED:
3012 3012 scf_entry_destroy(e);
3013 3013 return (ECANCELED);
3014 3014
3015 3015 case SCF_ERROR_CONNECTION_BROKEN:
3016 3016 scf_entry_destroy(e);
3017 3017 return (ECONNABORTED);
3018 3018
3019 3019 case SCF_ERROR_NOT_FOUND:
3020 3020 /*
3021 3021 * This can happen if cur is from the
3022 3022 * running snapshot (and it differs
3023 3023 * from the live properties).
3024 3024 */
3025 3025 scf_entry_destroy(e);
3026 3026 break;
3027 3027
3028 3028 case SCF_ERROR_HANDLE_MISMATCH:
3029 3029 case SCF_ERROR_NOT_BOUND:
3030 3030 case SCF_ERROR_NOT_SET:
3031 3031 case SCF_ERROR_INVALID_ARGUMENT:
3032 3032 default:
3033 3033 bad_error(
3034 3034 "scf_transaction_property_delete",
3035 3035 scf_error());
3036 3036 }
3037 3037 }
3038 3038 } else {
3039 3039 scf_callback_t ctx;
3040 3040
3041 3041 if (speak)
3042 3042 warn(gettext(
3043 3043 "%s: Upgrading property \"%s/%s\".\n"),
3044 3044 fmri, old->sc_pgroup_name,
3045 3045 p->sc_property_name);
3046 3046
3047 3047 ctx.sc_handle = g_hndl;
3048 3048 ctx.sc_trans = tx;
3049 3049 ctx.sc_flags = 0;
3050 3050
3051 3051 r = lscf_property_import(new_p, &ctx);
3052 3052 if (r != UU_WALK_NEXT) {
3053 3053 if (r != UU_WALK_ERROR)
3054 3054 bad_error("lscf_property_import", r);
3055 3055 return (EINVAL);
3056 3056 }
3057 3057 }
3058 3058 }
3059 3059
3060 3060 /* Go over the properties which were added. */
3061 3061 for (new_p = uu_list_first(new->sc_pgroup_props);
3062 3062 new_p != NULL;
3063 3063 new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
3064 3064 if (new_p->sc_seen)
3065 3065 continue;
3066 3066
3067 3067 /* This is a new property. */
3068 3068 cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
3069 3069 if (cur_p == NULL) {
3070 3070 scf_callback_t ctx;
3071 3071
3072 3072 ctx.sc_handle = g_hndl;
3073 3073 ctx.sc_trans = tx;
3074 3074 ctx.sc_flags = 0;
3075 3075
3076 3076 r = lscf_property_import(new_p, &ctx);
3077 3077 if (r != UU_WALK_NEXT) {
3078 3078 if (r != UU_WALK_ERROR)
3079 3079 bad_error("lscf_property_import", r);
3080 3080 return (EINVAL);
3081 3081 }
3082 3082 continue;
3083 3083 }
3084 3084
3085 3085 /*
3086 3086 * Report a conflict if the new property differs from the
3087 3087 * current one. Unless it's general/enabled, since that's
3088 3088 * never in the last-import snapshot.
3089 3089 */
3090 3090 if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
3091 3091 0 &&
3092 3092 strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
3093 3093 continue;
3094 3094
3095 3095 (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
3096 3096 }
3097 3097
3098 3098 return (0);
3099 3099 }
3100 3100
3101 3101 /*
3102 3102 * Upgrade pg according to old & new.
3103 3103 *
3104 3104 * Returns
3105 3105 * 0 - success
3106 3106 * ECONNABORTED - repository connection broken
3107 3107 * ENOMEM - out of memory
3108 3108 * ENOSPC - svc.configd is out of resources
3109 3109 * ECANCELED - pg was deleted
3110 3110 * EPERM - couldn't modify pg (permission denied)
3111 3111 * EROFS - couldn't modify pg (backend read-only)
3112 3112 * EACCES - couldn't modify pg (backend access denied)
3113 3113 * EINVAL - new has a property with invalid name or value (error printed)
3114 3114 * EBUSY - pg changed unexpectedly
3115 3115 */
3116 3116 static int
3117 3117 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
3118 3118 pgroup_t *new, int speak, const char *fmri)
3119 3119 {
3120 3120 int r;
3121 3121
3122 3122 if (scf_transaction_start(imp_tx, pg) != 0) {
3123 3123 switch (scf_error()) {
3124 3124 case SCF_ERROR_CONNECTION_BROKEN:
3125 3125 case SCF_ERROR_DELETED:
3126 3126 case SCF_ERROR_PERMISSION_DENIED:
3127 3127 case SCF_ERROR_BACKEND_READONLY:
3128 3128 case SCF_ERROR_BACKEND_ACCESS:
3129 3129 return (scferror2errno(scf_error()));
3130 3130
3131 3131 case SCF_ERROR_HANDLE_MISMATCH:
3132 3132 case SCF_ERROR_IN_USE:
3133 3133 case SCF_ERROR_NOT_BOUND:
3134 3134 case SCF_ERROR_NOT_SET:
3135 3135 default:
3136 3136 bad_error("scf_transaction_start", scf_error());
3137 3137 }
3138 3138 }
3139 3139
3140 3140 r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
3141 3141 switch (r) {
3142 3142 case 0:
3143 3143 break;
3144 3144
3145 3145 case EINVAL:
3146 3146 case ENOMEM:
3147 3147 scf_transaction_destroy_children(imp_tx);
3148 3148 return (r);
3149 3149
3150 3150 default:
3151 3151 bad_error("add_upgrade_entries", r);
3152 3152 }
3153 3153
3154 3154 r = scf_transaction_commit(imp_tx);
3155 3155
3156 3156 scf_transaction_destroy_children(imp_tx);
3157 3157
3158 3158 switch (r) {
3159 3159 case 1:
3160 3160 break;
3161 3161
3162 3162 case 0:
3163 3163 return (EBUSY);
3164 3164
3165 3165 case -1:
3166 3166 switch (scf_error()) {
3167 3167 case SCF_ERROR_CONNECTION_BROKEN:
3168 3168 case SCF_ERROR_NO_RESOURCES:
3169 3169 case SCF_ERROR_PERMISSION_DENIED:
3170 3170 case SCF_ERROR_BACKEND_READONLY:
3171 3171 case SCF_ERROR_BACKEND_ACCESS:
3172 3172 case SCF_ERROR_DELETED:
3173 3173 return (scferror2errno(scf_error()));
3174 3174
3175 3175 case SCF_ERROR_NOT_BOUND:
3176 3176 case SCF_ERROR_INVALID_ARGUMENT:
3177 3177 case SCF_ERROR_NOT_SET:
3178 3178 default:
3179 3179 bad_error("scf_transaction_commit", scf_error());
3180 3180 }
3181 3181
3182 3182 default:
3183 3183 bad_error("scf_transaction_commit", r);
3184 3184 }
3185 3185
3186 3186 return (0);
3187 3187 }
3188 3188
3189 3189 /*
3190 3190 * Compares two entity FMRIs. Returns
3191 3191 *
3192 3192 * 1 - equal
3193 3193 * 0 - not equal
3194 3194 * -1 - f1 is invalid or not an entity
3195 3195 * -2 - f2 is invalid or not an entity
3196 3196 */
3197 3197 static int
3198 3198 fmri_equal(const char *f1, const char *f2)
3199 3199 {
3200 3200 int r;
3201 3201 const char *s1, *i1, *pg1;
3202 3202 const char *s2, *i2, *pg2;
3203 3203
3204 3204 if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3205 3205 return (-1);
3206 3206 if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
3207 3207 return (-1);
3208 3208
3209 3209 if (s1 == NULL || pg1 != NULL)
3210 3210 return (-1);
3211 3211
3212 3212 if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3213 3213 return (-2);
3214 3214 if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
3215 3215 return (-2);
3216 3216
3217 3217 if (s2 == NULL || pg2 != NULL)
3218 3218 return (-2);
3219 3219
3220 3220 r = strcmp(s1, s2);
3221 3221 if (r != 0)
3222 3222 return (0);
3223 3223
3224 3224 if (i1 == NULL && i2 == NULL)
3225 3225 return (1);
3226 3226
3227 3227 if (i1 == NULL || i2 == NULL)
3228 3228 return (0);
3229 3229
3230 3230 return (strcmp(i1, i2) == 0);
3231 3231 }
3232 3232
3233 3233 /*
3234 3234 * Import a dependent by creating a dependency property group in the dependent
3235 3235 * entity. If lcbdata->sc_trans is set, assume it's been started on the
3236 3236 * dependents pg, and add an entry to create a new property for this
3237 3237 * dependent. Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3238 3238 *
3239 3239 * On success, returns UU_WALK_NEXT. On error, returns UU_WALK_ERROR and sets
3240 3240 * lcbdata->sc_err to
3241 3241 * ECONNABORTED - repository connection broken
3242 3242 * ENOMEM - out of memory
3243 3243 * ENOSPC - configd is out of resources
3244 3244 * EINVAL - target is invalid (error printed)
3245 3245 * - target is not an entity (error printed)
3246 3246 * - dependent has invalid name (error printed)
3247 3247 * - invalid property name (error printed)
3248 3248 * - invalid value (error printed)
3249 3249 * - scope of target does not exist (error printed)
3250 3250 * EPERM - couldn't create target (permission denied) (error printed)
3251 3251 * - couldn't create dependency pg (permission denied) (error printed)
3252 3252 * - couldn't modify dependency pg (permission denied) (error printed)
3253 3253 * EROFS - couldn't create target (repository read-only)
3254 3254 * - couldn't create dependency pg (repository read-only)
3255 3255 * EACCES - couldn't create target (backend access denied)
3256 3256 * - couldn't create dependency pg (backend access denied)
3257 3257 * ECANCELED - sc_trans's pg was deleted
3258 3258 * EALREADY - property for dependent already exists in sc_trans's pg
3259 3259 * EEXIST - dependency pg already exists in target (error printed)
3260 3260 * EBUSY - target deleted (error printed)
3261 3261 * - property group changed during import (error printed)
3262 3262 */
3263 3263 static int
3264 3264 lscf_dependent_import(void *a1, void *pvt)
3265 3265 {
3266 3266 pgroup_t *pgrp = a1;
3267 3267 scf_callback_t *lcbdata = pvt;
3268 3268
3269 3269 int isservice;
3270 3270 int ret;
3271 3271 scf_transaction_entry_t *e;
3272 3272 scf_value_t *val;
3273 3273 scf_callback_t dependent_cbdata;
3274 3274 scf_error_t scfe;
3275 3275
3276 3276 /*
3277 3277 * Decode the FMRI into dependent_cbdata->sc_parent. Do it here so if
3278 3278 * it's invalid, we fail before modifying the repository.
3279 3279 */
3280 3280 scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3281 3281 &dependent_cbdata.sc_parent, &isservice);
3282 3282 switch (scfe) {
3283 3283 case SCF_ERROR_NONE:
3284 3284 break;
3285 3285
3286 3286 case SCF_ERROR_NO_MEMORY:
3287 3287 return (stash_scferror_err(lcbdata, scfe));
3288 3288
3289 3289 case SCF_ERROR_INVALID_ARGUMENT:
3290 3290 semerr(gettext("The FMRI for the \"%s\" dependent is "
3291 3291 "invalid.\n"), pgrp->sc_pgroup_name);
3292 3292 return (stash_scferror_err(lcbdata, scfe));
3293 3293
3294 3294 case SCF_ERROR_CONSTRAINT_VIOLATED:
3295 3295 semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3296 3296 "specifies neither a service nor an instance.\n"),
3297 3297 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3298 3298 return (stash_scferror_err(lcbdata, scfe));
3299 3299
3300 3300 case SCF_ERROR_NOT_FOUND:
3301 3301 scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3302 3302 &dependent_cbdata.sc_parent, &isservice);
3303 3303 switch (scfe) {
3304 3304 case SCF_ERROR_NONE:
3305 3305 break;
3306 3306
3307 3307 case SCF_ERROR_NO_MEMORY:
3308 3308 case SCF_ERROR_BACKEND_READONLY:
3309 3309 case SCF_ERROR_BACKEND_ACCESS:
3310 3310 return (stash_scferror_err(lcbdata, scfe));
3311 3311
3312 3312 case SCF_ERROR_NOT_FOUND:
3313 3313 semerr(gettext("The scope in FMRI \"%s\" for the "
3314 3314 "\"%s\" dependent does not exist.\n"),
3315 3315 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3316 3316 lcbdata->sc_err = EINVAL;
3317 3317 return (UU_WALK_ERROR);
3318 3318
3319 3319 case SCF_ERROR_PERMISSION_DENIED:
3320 3320 warn(gettext(
3321 3321 "Could not create %s (permission denied).\n"),
3322 3322 pgrp->sc_pgroup_fmri);
3323 3323 return (stash_scferror_err(lcbdata, scfe));
3324 3324
3325 3325 case SCF_ERROR_INVALID_ARGUMENT:
3326 3326 case SCF_ERROR_CONSTRAINT_VIOLATED:
3327 3327 default:
3328 3328 bad_error("create_entity", scfe);
3329 3329 }
3330 3330 break;
3331 3331
3332 3332 default:
3333 3333 bad_error("fmri_to_entity", scfe);
3334 3334 }
3335 3335
3336 3336 if (lcbdata->sc_trans != NULL) {
3337 3337 e = scf_entry_create(lcbdata->sc_handle);
3338 3338 if (e == NULL) {
3339 3339 if (scf_error() != SCF_ERROR_NO_MEMORY)
3340 3340 bad_error("scf_entry_create", scf_error());
3341 3341
3342 3342 entity_destroy(dependent_cbdata.sc_parent, isservice);
3343 3343 return (stash_scferror(lcbdata));
3344 3344 }
3345 3345
3346 3346 if (scf_transaction_property_new(lcbdata->sc_trans, e,
3347 3347 pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
3348 3348 switch (scf_error()) {
3349 3349 case SCF_ERROR_INVALID_ARGUMENT:
3350 3350 warn(gettext("Dependent of %s has invalid name "
3351 3351 "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
3352 3352 pgrp->sc_pgroup_name);
3353 3353 /* FALLTHROUGH */
3354 3354
3355 3355 case SCF_ERROR_DELETED:
3356 3356 case SCF_ERROR_CONNECTION_BROKEN:
3357 3357 scf_entry_destroy(e);
3358 3358 entity_destroy(dependent_cbdata.sc_parent,
3359 3359 isservice);
3360 3360 return (stash_scferror(lcbdata));
3361 3361
3362 3362 case SCF_ERROR_EXISTS:
3363 3363 scf_entry_destroy(e);
3364 3364 entity_destroy(dependent_cbdata.sc_parent,
3365 3365 isservice);
3366 3366 lcbdata->sc_err = EALREADY;
3367 3367 return (UU_WALK_ERROR);
3368 3368
3369 3369 case SCF_ERROR_NOT_BOUND:
3370 3370 case SCF_ERROR_HANDLE_MISMATCH:
3371 3371 case SCF_ERROR_NOT_SET:
3372 3372 default:
3373 3373 bad_error("scf_transaction_property_new",
3374 3374 scf_error());
3375 3375 }
3376 3376 }
3377 3377
3378 3378 val = scf_value_create(lcbdata->sc_handle);
3379 3379 if (val == NULL) {
3380 3380 if (scf_error() != SCF_ERROR_NO_MEMORY)
3381 3381 bad_error("scf_value_create", scf_error());
3382 3382
3383 3383 entity_destroy(dependent_cbdata.sc_parent, isservice);
3384 3384 return (stash_scferror(lcbdata));
3385 3385 }
3386 3386
3387 3387 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
3388 3388 pgrp->sc_pgroup_fmri) != 0)
3389 3389 /* invalid should have been caught above */
3390 3390 bad_error("scf_value_set_from_string", scf_error());
3391 3391
3392 3392 if (scf_entry_add_value(e, val) != 0)
3393 3393 bad_error("scf_entry_add_value", scf_error());
3394 3394 }
3395 3395
3396 3396 /* Add the property group to the target entity. */
3397 3397
3398 3398 dependent_cbdata.sc_handle = lcbdata->sc_handle;
3399 3399 dependent_cbdata.sc_flags = lcbdata->sc_flags;
3400 3400 dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
3401 3401 dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
3402 3402
3403 3403 ret = entity_pgroup_import(pgrp, &dependent_cbdata);
3404 3404
3405 3405 entity_destroy(dependent_cbdata.sc_parent, isservice);
3406 3406
3407 3407 if (ret == UU_WALK_NEXT)
3408 3408 return (ret);
3409 3409
3410 3410 if (ret != UU_WALK_ERROR)
3411 3411 bad_error("entity_pgroup_import", ret);
3412 3412
3413 3413 switch (dependent_cbdata.sc_err) {
3414 3414 case ECANCELED:
3415 3415 warn(gettext("%s deleted unexpectedly.\n"),
3416 3416 pgrp->sc_pgroup_fmri);
3417 3417 lcbdata->sc_err = EBUSY;
3418 3418 break;
3419 3419
3420 3420 case EEXIST:
3421 3421 warn(gettext("Could not create \"%s\" dependency in %s "
3422 3422 "(already exists).\n"), pgrp->sc_pgroup_name,
3423 3423 pgrp->sc_pgroup_fmri);
3424 3424 /* FALLTHROUGH */
3425 3425
3426 3426 default:
3427 3427 lcbdata->sc_err = dependent_cbdata.sc_err;
3428 3428 }
3429 3429
3430 3430 return (UU_WALK_ERROR);
3431 3431 }
3432 3432
3433 3433 static int upgrade_dependent(const scf_property_t *, const entity_t *,
3434 3434 const scf_snaplevel_t *, scf_transaction_t *);
3435 3435 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
3436 3436 const pgroup_t *);
3437 3437
3438 3438 /*
3439 3439 * Upgrade uncustomized dependents of ent to those specified in ient. Read
3440 3440 * the current dependent targets from running (the snaplevel of a running
3441 3441 * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3442 3442 * scf_instance_t * according to ient, otherwise). Draw the ancestral
3443 3443 * dependent targets and dependency properties from li_dpts_pg (the
3444 3444 * "dependents" property group in snpl) and snpl (the snaplevel which
3445 3445 * corresponds to ent in a last-import snapshot). If li_dpts_pg is NULL, then
3446 3446 * snpl doesn't have a "dependents" property group, and any dependents in ient
3447 3447 * are new.
3448 3448 *
3449 3449 * Returns
3450 3450 * 0 - success
3451 3451 * ECONNABORTED - repository connection broken
3452 3452 * ENOMEM - out of memory
3453 3453 * ENOSPC - configd is out of resources
3454 3454 * ECANCELED - ent was deleted
3455 3455 * ENODEV - the entity containing li_dpts_pg was deleted
3456 3456 * EPERM - could not modify dependents pg (permission denied) (error printed)
3457 3457 * - couldn't upgrade dependent (permission denied) (error printed)
3458 3458 * - couldn't create dependent (permission denied) (error printed)
3459 3459 * EROFS - could not modify dependents pg (repository read-only)
3460 3460 * - couldn't upgrade dependent (repository read-only)
3461 3461 * - couldn't create dependent (repository read-only)
3462 3462 * EACCES - could not modify dependents pg (backend access denied)
3463 3463 * - could not upgrade dependent (backend access denied)
3464 3464 * - could not create dependent (backend access denied)
3465 3465 * EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3466 3466 * - dependent target deleted (error printed)
3467 3467 * - dependent pg changed (error printed)
3468 3468 * EINVAL - new dependent is invalid (error printed)
3469 3469 * EBADF - snpl is corrupt (error printed)
3470 3470 * - snpl has corrupt pg (error printed)
3471 3471 * - dependency pg in target is corrupt (error printed)
3472 3472 * - target has corrupt snapshot (error printed)
3473 3473 * EEXIST - dependency pg already existed in target service (error printed)
3474 3474 */
3475 3475 static int
3476 3476 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
3477 3477 const scf_snaplevel_t *snpl, const entity_t *ient,
3478 3478 const scf_snaplevel_t *running, void *ent)
3479 3479 {
3480 3480 pgroup_t *new_dpt_pgroup;
3481 3481 scf_callback_t cbdata;
3482 3482 int r, unseen, tx_started = 0;
3483 3483 int have_cur_depts;
3484 3484
3485 3485 const char * const dependents = "dependents";
3486 3486
3487 3487 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3488 3488
3489 3489 if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
3490 3490 /* Nothing to do. */
3491 3491 return (0);
3492 3492
3493 3493 /* Fetch the current version of the "dependents" property group. */
3494 3494 have_cur_depts = 1;
3495 3495 if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
3496 3496 switch (scf_error()) {
3497 3497 case SCF_ERROR_NOT_FOUND:
3498 3498 break;
3499 3499
3500 3500 case SCF_ERROR_DELETED:
3501 3501 case SCF_ERROR_CONNECTION_BROKEN:
3502 3502 return (scferror2errno(scf_error()));
3503 3503
3504 3504 case SCF_ERROR_NOT_SET:
3505 3505 case SCF_ERROR_INVALID_ARGUMENT:
3506 3506 case SCF_ERROR_HANDLE_MISMATCH:
3507 3507 case SCF_ERROR_NOT_BOUND:
3508 3508 default:
3509 3509 bad_error("entity_get_pg", scf_error());
3510 3510 }
3511 3511
3512 3512 have_cur_depts = 0;
3513 3513 }
3514 3514
3515 3515 /* Fetch the running version of the "dependents" property group. */
3516 3516 ud_run_dpts_pg_set = 0;
3517 3517 if (running != NULL)
3518 3518 r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
3519 3519 else
3520 3520 r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
3521 3521 if (r == 0) {
3522 3522 ud_run_dpts_pg_set = 1;
3523 3523 } else {
3524 3524 switch (scf_error()) {
3525 3525 case SCF_ERROR_NOT_FOUND:
3526 3526 break;
3527 3527
3528 3528 case SCF_ERROR_DELETED:
3529 3529 case SCF_ERROR_CONNECTION_BROKEN:
3530 3530 return (scferror2errno(scf_error()));
3531 3531
3532 3532 case SCF_ERROR_NOT_SET:
3533 3533 case SCF_ERROR_INVALID_ARGUMENT:
3534 3534 case SCF_ERROR_HANDLE_MISMATCH:
3535 3535 case SCF_ERROR_NOT_BOUND:
3536 3536 default:
3537 3537 bad_error(running ? "scf_snaplevel_get_pg" :
3538 3538 "entity_get_pg", scf_error());
3539 3539 }
3540 3540 }
3541 3541
3542 3542 /*
3543 3543 * Clear the seen fields of the dependents, so we can tell which ones
3544 3544 * are new.
3545 3545 */
3546 3546 if (uu_list_walk(ient->sc_dependents, clear_int,
3547 3547 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3548 3548 bad_error("uu_list_walk", uu_error());
3549 3549
3550 3550 if (li_dpts_pg != NULL) {
3551 3551 /*
3552 3552 * Each property in li_dpts_pg represents a dependent tag in
3553 3553 * the old manifest. For each, call upgrade_dependent(),
3554 3554 * which will change ud_cur_depts_pg or dependencies in other
3555 3555 * services as appropriate. Note (a) that changes to
3556 3556 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3557 3557 * made en masse, and (b) it's ok if the entity doesn't have
3558 3558 * a current version of the "dependents" property group,
3559 3559 * because we'll just consider all dependents as customized
3560 3560 * (by being deleted).
3561 3561 */
3562 3562
3563 3563 if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3564 3564 switch (scf_error()) {
3565 3565 case SCF_ERROR_DELETED:
3566 3566 return (ENODEV);
3567 3567
3568 3568 case SCF_ERROR_CONNECTION_BROKEN:
3569 3569 return (ECONNABORTED);
3570 3570
3571 3571 case SCF_ERROR_HANDLE_MISMATCH:
3572 3572 case SCF_ERROR_NOT_BOUND:
3573 3573 case SCF_ERROR_NOT_SET:
3574 3574 default:
3575 3575 bad_error("scf_iter_pg_properties",
3576 3576 scf_error());
3577 3577 }
3578 3578 }
3579 3579
3580 3580 if (have_cur_depts &&
3581 3581 scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3582 3582 switch (scf_error()) {
3583 3583 case SCF_ERROR_BACKEND_ACCESS:
3584 3584 case SCF_ERROR_BACKEND_READONLY:
3585 3585 case SCF_ERROR_CONNECTION_BROKEN:
3586 3586 return (scferror2errno(scf_error()));
3587 3587
3588 3588 case SCF_ERROR_DELETED:
3589 3589 warn(emsg_pg_deleted, ient->sc_fmri,
3590 3590 dependents);
3591 3591 return (EBUSY);
3592 3592
3593 3593 case SCF_ERROR_PERMISSION_DENIED:
3594 3594 warn(emsg_pg_mod_perm, dependents,
3595 3595 ient->sc_fmri);
3596 3596 return (scferror2errno(scf_error()));
3597 3597
3598 3598 case SCF_ERROR_HANDLE_MISMATCH:
3599 3599 case SCF_ERROR_IN_USE:
3600 3600 case SCF_ERROR_NOT_BOUND:
3601 3601 case SCF_ERROR_NOT_SET:
3602 3602 default:
3603 3603 bad_error("scf_transaction_start", scf_error());
3604 3604 }
3605 3605 }
3606 3606 tx_started = have_cur_depts;
3607 3607
3608 3608 for (;;) {
3609 3609 r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3610 3610 if (r == 0)
3611 3611 break;
3612 3612 if (r == 1) {
3613 3613 r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3614 3614 tx_started ? ud_tx : NULL);
3615 3615 switch (r) {
3616 3616 case 0:
3617 3617 continue;
3618 3618
3619 3619 case ECONNABORTED:
3620 3620 case ENOMEM:
3621 3621 case ENOSPC:
3622 3622 case EBADF:
3623 3623 case EBUSY:
3624 3624 case EINVAL:
3625 3625 case EPERM:
3626 3626 case EROFS:
3627 3627 case EACCES:
3628 3628 case EEXIST:
3629 3629 break;
3630 3630
3631 3631 case ECANCELED:
3632 3632 r = ENODEV;
3633 3633 break;
3634 3634
3635 3635 default:
3636 3636 bad_error("upgrade_dependent", r);
3637 3637 }
3638 3638
3639 3639 if (tx_started)
3640 3640 scf_transaction_destroy_children(ud_tx);
3641 3641 return (r);
3642 3642 }
3643 3643 if (r != -1)
3644 3644 bad_error("scf_iter_next_property", r);
3645 3645
3646 3646 switch (scf_error()) {
3647 3647 case SCF_ERROR_DELETED:
3648 3648 r = ENODEV;
3649 3649 break;
3650 3650
3651 3651 case SCF_ERROR_CONNECTION_BROKEN:
3652 3652 r = ECONNABORTED;
3653 3653 break;
3654 3654
3655 3655 case SCF_ERROR_NOT_SET:
3656 3656 case SCF_ERROR_INVALID_ARGUMENT:
3657 3657 case SCF_ERROR_NOT_BOUND:
3658 3658 case SCF_ERROR_HANDLE_MISMATCH:
3659 3659 default:
3660 3660 bad_error("scf_iter_next_property",
3661 3661 scf_error());
3662 3662 }
3663 3663
3664 3664 if (tx_started)
3665 3665 scf_transaction_destroy_children(ud_tx);
3666 3666 return (r);
3667 3667 }
3668 3668 }
3669 3669
3670 3670 /* import unseen dependents */
3671 3671 unseen = 0;
3672 3672 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3673 3673 new_dpt_pgroup != NULL;
3674 3674 new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3675 3675 new_dpt_pgroup)) {
3676 3676 if (!new_dpt_pgroup->sc_pgroup_seen) {
3677 3677 unseen = 1;
3678 3678 break;
3679 3679 }
3680 3680 }
3681 3681
3682 3682 /* If there are none, exit early. */
3683 3683 if (unseen == 0)
3684 3684 goto commit;
3685 3685
3686 3686 /* Set up for lscf_dependent_import() */
3687 3687 cbdata.sc_handle = g_hndl;
3688 3688 cbdata.sc_parent = ent;
3689 3689 cbdata.sc_service = issvc;
3690 3690 cbdata.sc_flags = 0;
3691 3691
3692 3692 if (!have_cur_depts) {
3693 3693 /*
3694 3694 * We have new dependents to import, so we need a "dependents"
3695 3695 * property group.
3696 3696 */
3697 3697 if (issvc)
3698 3698 r = scf_service_add_pg(ent, dependents,
3699 3699 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3700 3700 else
3701 3701 r = scf_instance_add_pg(ent, dependents,
3702 3702 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3703 3703 if (r != 0) {
3704 3704 switch (scf_error()) {
3705 3705 case SCF_ERROR_DELETED:
3706 3706 case SCF_ERROR_CONNECTION_BROKEN:
3707 3707 case SCF_ERROR_BACKEND_READONLY:
3708 3708 case SCF_ERROR_BACKEND_ACCESS:
3709 3709 case SCF_ERROR_NO_RESOURCES:
3710 3710 return (scferror2errno(scf_error()));
3711 3711
3712 3712 case SCF_ERROR_EXISTS:
3713 3713 warn(emsg_pg_added, ient->sc_fmri, dependents);
3714 3714 return (EBUSY);
3715 3715
3716 3716 case SCF_ERROR_PERMISSION_DENIED:
3717 3717 warn(emsg_pg_add_perm, dependents,
3718 3718 ient->sc_fmri);
3719 3719 return (scferror2errno(scf_error()));
3720 3720
3721 3721 case SCF_ERROR_NOT_BOUND:
3722 3722 case SCF_ERROR_HANDLE_MISMATCH:
3723 3723 case SCF_ERROR_INVALID_ARGUMENT:
3724 3724 case SCF_ERROR_NOT_SET:
3725 3725 default:
3726 3726 bad_error("scf_service_add_pg", scf_error());
3727 3727 }
3728 3728 }
3729 3729 }
3730 3730
3731 3731 cbdata.sc_trans = ud_tx;
3732 3732
3733 3733 if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3734 3734 switch (scf_error()) {
3735 3735 case SCF_ERROR_CONNECTION_BROKEN:
3736 3736 case SCF_ERROR_BACKEND_ACCESS:
3737 3737 case SCF_ERROR_BACKEND_READONLY:
3738 3738 return (scferror2errno(scf_error()));
3739 3739
3740 3740 case SCF_ERROR_DELETED:
3741 3741 warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3742 3742 return (EBUSY);
3743 3743
3744 3744 case SCF_ERROR_PERMISSION_DENIED:
3745 3745 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3746 3746 return (scferror2errno(scf_error()));
3747 3747
3748 3748 case SCF_ERROR_HANDLE_MISMATCH:
3749 3749 case SCF_ERROR_IN_USE:
3750 3750 case SCF_ERROR_NOT_BOUND:
3751 3751 case SCF_ERROR_NOT_SET:
3752 3752 default:
3753 3753 bad_error("scf_transaction_start", scf_error());
3754 3754 }
3755 3755 }
3756 3756 tx_started = 1;
3757 3757
3758 3758 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3759 3759 new_dpt_pgroup != NULL;
3760 3760 new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3761 3761 new_dpt_pgroup)) {
3762 3762 if (new_dpt_pgroup->sc_pgroup_seen)
3763 3763 continue;
3764 3764
3765 3765 if (ud_run_dpts_pg_set) {
3766 3766 /*
3767 3767 * If the dependent is already there, then we have
3768 3768 * a conflict.
3769 3769 */
3770 3770 if (scf_pg_get_property(ud_run_dpts_pg,
3771 3771 new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3772 3772 r = handle_dependent_conflict(ient, ud_prop,
3773 3773 new_dpt_pgroup);
3774 3774 switch (r) {
3775 3775 case 0:
3776 3776 continue;
3777 3777
3778 3778 case ECONNABORTED:
3779 3779 case ENOMEM:
3780 3780 case EBUSY:
3781 3781 case EBADF:
3782 3782 case EINVAL:
3783 3783 scf_transaction_destroy_children(ud_tx);
3784 3784 return (r);
3785 3785
3786 3786 default:
3787 3787 bad_error("handle_dependent_conflict",
3788 3788 r);
3789 3789 }
3790 3790 } else {
3791 3791 switch (scf_error()) {
3792 3792 case SCF_ERROR_NOT_FOUND:
3793 3793 break;
3794 3794
3795 3795 case SCF_ERROR_INVALID_ARGUMENT:
3796 3796 warn(emsg_fmri_invalid_pg_name,
3797 3797 ient->sc_fmri,
3798 3798 new_dpt_pgroup->sc_pgroup_name);
3799 3799 scf_transaction_destroy_children(ud_tx);
3800 3800 return (EINVAL);
3801 3801
3802 3802 case SCF_ERROR_DELETED:
3803 3803 warn(emsg_pg_deleted, ient->sc_fmri,
3804 3804 new_dpt_pgroup->sc_pgroup_name);
3805 3805 scf_transaction_destroy_children(ud_tx);
3806 3806 return (EBUSY);
3807 3807
3808 3808 case SCF_ERROR_CONNECTION_BROKEN:
3809 3809 scf_transaction_destroy_children(ud_tx);
3810 3810 return (ECONNABORTED);
3811 3811
3812 3812 case SCF_ERROR_NOT_BOUND:
3813 3813 case SCF_ERROR_HANDLE_MISMATCH:
3814 3814 case SCF_ERROR_NOT_SET:
3815 3815 default:
3816 3816 bad_error("scf_pg_get_property",
3817 3817 scf_error());
3818 3818 }
3819 3819 }
3820 3820 }
3821 3821
3822 3822 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3823 3823 if (r != UU_WALK_NEXT) {
3824 3824 if (r != UU_WALK_ERROR)
3825 3825 bad_error("lscf_dependent_import", r);
3826 3826
3827 3827 if (cbdata.sc_err == EALREADY) {
3828 3828 /* Collisions were handled preemptively. */
3829 3829 bad_error("lscf_dependent_import",
3830 3830 cbdata.sc_err);
3831 3831 }
3832 3832
3833 3833 scf_transaction_destroy_children(ud_tx);
3834 3834 return (cbdata.sc_err);
3835 3835 }
3836 3836 }
3837 3837
3838 3838 commit:
3839 3839 if (!tx_started)
3840 3840 return (0);
3841 3841
3842 3842 r = scf_transaction_commit(ud_tx);
3843 3843
3844 3844 scf_transaction_destroy_children(ud_tx);
3845 3845
3846 3846 switch (r) {
3847 3847 case 1:
3848 3848 return (0);
3849 3849
3850 3850 case 0:
3851 3851 warn(emsg_pg_changed, ient->sc_fmri, dependents);
3852 3852 return (EBUSY);
3853 3853
3854 3854 case -1:
3855 3855 break;
3856 3856
3857 3857 default:
3858 3858 bad_error("scf_transaction_commit", r);
3859 3859 }
3860 3860
3861 3861 switch (scf_error()) {
3862 3862 case SCF_ERROR_CONNECTION_BROKEN:
3863 3863 case SCF_ERROR_BACKEND_READONLY:
3864 3864 case SCF_ERROR_BACKEND_ACCESS:
3865 3865 case SCF_ERROR_NO_RESOURCES:
3866 3866 return (scferror2errno(scf_error()));
3867 3867
3868 3868 case SCF_ERROR_DELETED:
3869 3869 warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3870 3870 return (EBUSY);
3871 3871
3872 3872 case SCF_ERROR_PERMISSION_DENIED:
3873 3873 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3874 3874 return (scferror2errno(scf_error()));
3875 3875
3876 3876 case SCF_ERROR_NOT_BOUND:
3877 3877 case SCF_ERROR_INVALID_ARGUMENT:
3878 3878 case SCF_ERROR_NOT_SET:
3879 3879 default:
3880 3880 bad_error("scf_transaction_destroy", scf_error());
3881 3881 /* NOTREACHED */
3882 3882 }
3883 3883 }
3884 3884
3885 3885 /*
3886 3886 * Used to add the manifests to the list of currently supported manifests.
3887 3887 * We can modify the existing manifest list removing entries if the files
3888 3888 * don't exist.
3889 3889 *
3890 3890 * Get the old list and the new file name
3891 3891 * If the new file name is in the list return
3892 3892 * If not then add the file to the list.
3893 3893 * As we process the list check to see if the files in the old list exist
3894 3894 * if not then remove the file from the list.
3895 3895 * Commit the list of manifest file names.
3896 3896 *
3897 3897 */
3898 3898 static int
3899 3899 upgrade_manifestfiles(pgroup_t *pg, entity_t *ient,
3900 3900 const scf_snaplevel_t *running, void *ent)
3901 3901 {
3902 3902 scf_propertygroup_t *ud_mfsts_pg = NULL;
3903 3903 scf_property_t *ud_prop = NULL;
3904 3904 scf_iter_t *ud_prop_iter;
3905 3905 scf_value_t *fname_value;
3906 3906 scf_callback_t cbdata;
3907 3907 pgroup_t *mfst_pgroup;
3908 3908 property_t *mfst_prop;
3909 3909 property_t *old_prop;
3910 3910 char *pname;
3911 3911 char *fval;
3912 3912 char *old_pname;
3913 3913 char *old_fval;
3914 3914 int no_upgrade_pg;
3915 3915 int mfst_seen;
3916 3916 int r;
3917 3917
3918 3918 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3919 3919
3920 3920 /*
3921 3921 * This should always be the service base on the code
3922 3922 * path, and the fact that the manifests pg is a service
3923 3923 * level property group only.
3924 3924 */
3925 3925 ud_mfsts_pg = scf_pg_create(g_hndl);
3926 3926 ud_prop = scf_property_create(g_hndl);
3927 3927 ud_prop_iter = scf_iter_create(g_hndl);
3928 3928 fname_value = scf_value_create(g_hndl);
3929 3929
3930 3930 /* Fetch the "manifests" property group */
3931 3931 no_upgrade_pg = 0;
3932 3932 r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3933 3933 ud_mfsts_pg);
3934 3934 if (r != 0) {
3935 3935 switch (scf_error()) {
3936 3936 case SCF_ERROR_NOT_FOUND:
3937 3937 no_upgrade_pg = 1;
3938 3938 break;
3939 3939
3940 3940 case SCF_ERROR_DELETED:
3941 3941 case SCF_ERROR_CONNECTION_BROKEN:
3942 3942 return (scferror2errno(scf_error()));
3943 3943
3944 3944 case SCF_ERROR_NOT_SET:
3945 3945 case SCF_ERROR_INVALID_ARGUMENT:
3946 3946 case SCF_ERROR_HANDLE_MISMATCH:
3947 3947 case SCF_ERROR_NOT_BOUND:
3948 3948 default:
3949 3949 bad_error(running ? "scf_snaplevel_get_pg" :
3950 3950 "entity_get_pg", scf_error());
3951 3951 }
3952 3952 }
3953 3953
3954 3954 if (no_upgrade_pg) {
3955 3955 cbdata.sc_handle = g_hndl;
3956 3956 cbdata.sc_parent = ent;
3957 3957 cbdata.sc_service = issvc;
3958 3958 cbdata.sc_flags = SCI_FORCE;
3959 3959 cbdata.sc_source_fmri = ient->sc_fmri;
3960 3960 cbdata.sc_target_fmri = ient->sc_fmri;
3961 3961
3962 3962 if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3963 3963 return (cbdata.sc_err);
3964 3964
3965 3965 return (0);
3966 3966 }
3967 3967
3968 3968 /* Fetch the new manifests property group */
3969 3969 mfst_pgroup = internal_pgroup_find_or_create(ient,
3970 3970 SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
3971 3971 assert(mfst_pgroup != NULL);
3972 3972
3973 3973 if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3974 3974 SCF_SUCCESS)
3975 3975 return (-1);
3976 3976
3977 3977 if ((pname = malloc(MAXPATHLEN)) == NULL)
3978 3978 return (ENOMEM);
3979 3979 if ((fval = malloc(MAXPATHLEN)) == NULL) {
3980 3980 free(pname);
3981 3981 return (ENOMEM);
3982 3982 }
3983 3983
3984 3984 while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
3985 3985 mfst_seen = 0;
3986 3986 if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
3987 3987 continue;
3988 3988
3989 3989 for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
3990 3990 mfst_prop != NULL;
3991 3991 mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
3992 3992 mfst_prop)) {
3993 3993 if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
3994 3994 mfst_seen = 1;
3995 3995 }
3996 3996 }
3997 3997
3998 3998 /*
3999 3999 * If the manifest is not seen then add it to the new mfst
4000 4000 * property list to get proccessed into the repo.
4001 4001 */
4002 4002 if (mfst_seen == 0) {
4003 4003 /*
4004 4004 * If we cannot get the value then there is no
4005 4005 * reason to attempt to attach the value to
4006 4006 * the property group
4007 4007 */
4008 4008 if (prop_get_val(ud_prop, fname_value) == 0 &&
4009 4009 scf_value_get_astring(fname_value, fval,
4010 4010 MAXPATHLEN) != -1) {
4011 4011 old_pname = safe_strdup(pname);
4012 4012 old_fval = safe_strdup(fval);
4013 4013 old_prop = internal_property_create(old_pname,
4014 4014 SCF_TYPE_ASTRING, 1, old_fval);
4015 4015
4016 4016 /*
4017 4017 * Already checked to see if the property exists
4018 4018 * in the group, and it does not.
4019 4019 */
4020 4020 (void) internal_attach_property(mfst_pgroup,
4021 4021 old_prop);
4022 4022 }
4023 4023 }
4024 4024 }
4025 4025 free(pname);
4026 4026 free(fval);
4027 4027
4028 4028 cbdata.sc_handle = g_hndl;
4029 4029 cbdata.sc_parent = ent;
4030 4030 cbdata.sc_service = issvc;
4031 4031 cbdata.sc_flags = SCI_FORCE;
4032 4032 cbdata.sc_source_fmri = ient->sc_fmri;
4033 4033 cbdata.sc_target_fmri = ient->sc_fmri;
4034 4034
4035 4035 if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
4036 4036 return (cbdata.sc_err);
4037 4037
4038 4038 return (r);
4039 4039 }
4040 4040
4041 4041 /*
4042 4042 * prop is taken to be a property in the "dependents" property group of snpl,
4043 4043 * which is taken to be the snaplevel of a last-import snapshot corresponding
4044 4044 * to ient. If prop is a valid dependents property, upgrade the dependent it
4045 4045 * represents according to the repository & ient. If ud_run_dpts_pg_set is
4046 4046 * true, then ud_run_dpts_pg is taken to be the "dependents" property group
4047 4047 * of the entity ient represents (possibly in the running snapshot). If it
4048 4048 * needs to be changed, an entry will be added to tx, if not NULL.
4049 4049 *
4050 4050 * Returns
4051 4051 * 0 - success
4052 4052 * ECONNABORTED - repository connection broken
4053 4053 * ENOMEM - out of memory
4054 4054 * ENOSPC - configd was out of resources
4055 4055 * ECANCELED - snpl's entity was deleted
4056 4056 * EINVAL - dependent target is invalid (error printed)
4057 4057 * - dependent is invalid (error printed)
4058 4058 * EBADF - snpl is corrupt (error printed)
4059 4059 * - snpl has corrupt pg (error printed)
4060 4060 * - dependency pg in target is corrupt (error printed)
4061 4061 * - running snapshot in dependent is missing snaplevel (error printed)
4062 4062 * EPERM - couldn't delete dependency pg (permission denied) (error printed)
4063 4063 * - couldn't create dependent (permission denied) (error printed)
4064 4064 * - couldn't modify dependent pg (permission denied) (error printed)
4065 4065 * EROFS - couldn't delete dependency pg (repository read-only)
4066 4066 * - couldn't create dependent (repository read-only)
4067 4067 * EACCES - couldn't delete dependency pg (backend access denied)
4068 4068 * - couldn't create dependent (backend access denied)
4069 4069 * EBUSY - ud_run_dpts_pg was deleted (error printed)
4070 4070 * - tx's pg was deleted (error printed)
4071 4071 * - dependent pg was changed or deleted (error printed)
4072 4072 * EEXIST - dependency pg already exists in new target (error printed)
4073 4073 */
4074 4074 static int
4075 4075 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
4076 4076 const scf_snaplevel_t *snpl, scf_transaction_t *tx)
4077 4077 {
4078 4078 pgroup_t pgrp;
4079 4079 scf_type_t ty;
4080 4080 pgroup_t *new_dpt_pgroup;
4081 4081 pgroup_t *old_dpt_pgroup = NULL;
4082 4082 pgroup_t *current_pg;
4083 4083 pgroup_t *dpt;
4084 4084 scf_callback_t cbdata;
4085 4085 int tissvc;
4086 4086 void *target_ent;
4087 4087 scf_error_t serr;
4088 4088 int r;
4089 4089 scf_transaction_entry_t *ent;
4090 4090
4091 4091 const char * const cf_inval = gettext("Conflict upgrading %s "
4092 4092 "(dependent \"%s\" has invalid dependents property).\n");
4093 4093 const char * const cf_missing = gettext("Conflict upgrading %s "
4094 4094 "(dependent \"%s\" is missing).\n");
4095 4095 const char * const cf_newdpg = gettext("Conflict upgrading %s "
4096 4096 "(dependent \"%s\" has new dependency property group).\n");
4097 4097 const char * const cf_newtarg = gettext("Conflict upgrading %s "
4098 4098 "(dependent \"%s\" has new target).\n");
4099 4099 const char * const li_corrupt =
4100 4100 gettext("%s: \"last-import\" snapshot is corrupt.\n");
4101 4101 const char * const upgrading =
4102 4102 gettext("%s: Upgrading dependent \"%s\".\n");
4103 4103 const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
4104 4104 "corrupt (missing snaplevel).\n");
4105 4105
4106 4106 if (scf_property_type(prop, &ty) != 0) {
4107 4107 switch (scf_error()) {
4108 4108 case SCF_ERROR_DELETED:
4109 4109 case SCF_ERROR_CONNECTION_BROKEN:
4110 4110 return (scferror2errno(scf_error()));
4111 4111
4112 4112 case SCF_ERROR_NOT_BOUND:
4113 4113 case SCF_ERROR_NOT_SET:
4114 4114 default:
4115 4115 bad_error("scf_property_type", scf_error());
4116 4116 }
4117 4117 }
4118 4118
4119 4119 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4120 4120 warn(li_corrupt, ient->sc_fmri);
4121 4121 return (EBADF);
4122 4122 }
4123 4123
4124 4124 /*
4125 4125 * prop represents a dependent in the old manifest. It is named after
4126 4126 * the dependent.
4127 4127 */
4128 4128 if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
4129 4129 switch (scf_error()) {
4130 4130 case SCF_ERROR_DELETED:
4131 4131 case SCF_ERROR_CONNECTION_BROKEN:
4132 4132 return (scferror2errno(scf_error()));
4133 4133
4134 4134 case SCF_ERROR_NOT_BOUND:
4135 4135 case SCF_ERROR_NOT_SET:
4136 4136 default:
4137 4137 bad_error("scf_property_get_name", scf_error());
4138 4138 }
4139 4139 }
4140 4140
4141 4141 /* See if it's in the new manifest. */
4142 4142 pgrp.sc_pgroup_name = ud_name;
4143 4143 new_dpt_pgroup =
4144 4144 uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
4145 4145
4146 4146 /* If it's not, delete it... if it hasn't been customized. */
4147 4147 if (new_dpt_pgroup == NULL) {
4148 4148 if (!ud_run_dpts_pg_set)
4149 4149 return (0);
4150 4150
4151 4151 if (scf_property_get_value(prop, ud_val) != 0) {
4152 4152 switch (scf_error()) {
4153 4153 case SCF_ERROR_NOT_FOUND:
4154 4154 case SCF_ERROR_CONSTRAINT_VIOLATED:
4155 4155 warn(li_corrupt, ient->sc_fmri);
4156 4156 return (EBADF);
4157 4157
4158 4158 case SCF_ERROR_DELETED:
4159 4159 case SCF_ERROR_CONNECTION_BROKEN:
4160 4160 return (scferror2errno(scf_error()));
4161 4161
4162 4162 case SCF_ERROR_HANDLE_MISMATCH:
4163 4163 case SCF_ERROR_NOT_BOUND:
4164 4164 case SCF_ERROR_NOT_SET:
4165 4165 case SCF_ERROR_PERMISSION_DENIED:
4166 4166 default:
4167 4167 bad_error("scf_property_get_value",
4168 4168 scf_error());
4169 4169 }
4170 4170 }
4171 4171
4172 4172 if (scf_value_get_as_string(ud_val, ud_oldtarg,
4173 4173 max_scf_value_len + 1) < 0)
4174 4174 bad_error("scf_value_get_as_string", scf_error());
4175 4175
4176 4176 if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
4177 4177 0) {
4178 4178 switch (scf_error()) {
4179 4179 case SCF_ERROR_NOT_FOUND:
4180 4180 return (0);
4181 4181
4182 4182 case SCF_ERROR_CONNECTION_BROKEN:
4183 4183 return (scferror2errno(scf_error()));
4184 4184
4185 4185 case SCF_ERROR_DELETED:
4186 4186 warn(emsg_pg_deleted, ient->sc_fmri,
4187 4187 "dependents");
4188 4188 return (EBUSY);
4189 4189
4190 4190 case SCF_ERROR_INVALID_ARGUMENT:
4191 4191 case SCF_ERROR_NOT_BOUND:
4192 4192 case SCF_ERROR_HANDLE_MISMATCH:
4193 4193 case SCF_ERROR_NOT_SET:
4194 4194 default:
4195 4195 bad_error("scf_pg_get_property", scf_error());
4196 4196 }
4197 4197 }
4198 4198 if (scf_property_get_value(ud_prop, ud_val) != 0) {
4199 4199 switch (scf_error()) {
4200 4200 case SCF_ERROR_NOT_FOUND:
4201 4201 case SCF_ERROR_CONSTRAINT_VIOLATED:
4202 4202 warn(cf_inval, ient->sc_fmri, ud_name);
4203 4203 return (0);
4204 4204
4205 4205 case SCF_ERROR_DELETED:
4206 4206 case SCF_ERROR_CONNECTION_BROKEN:
4207 4207 return (scferror2errno(scf_error()));
4208 4208
4209 4209 case SCF_ERROR_HANDLE_MISMATCH:
4210 4210 case SCF_ERROR_NOT_BOUND:
4211 4211 case SCF_ERROR_NOT_SET:
4212 4212 case SCF_ERROR_PERMISSION_DENIED:
4213 4213 default:
4214 4214 bad_error("scf_property_get_value",
4215 4215 scf_error());
4216 4216 }
4217 4217 }
4218 4218
4219 4219 ty = scf_value_type(ud_val);
4220 4220 assert(ty != SCF_TYPE_INVALID);
4221 4221 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4222 4222 warn(cf_inval, ient->sc_fmri, ud_name);
4223 4223 return (0);
4224 4224 }
4225 4225
4226 4226 if (scf_value_get_as_string(ud_val, ud_ctarg,
4227 4227 max_scf_value_len + 1) < 0)
4228 4228 bad_error("scf_value_get_as_string", scf_error());
4229 4229
4230 4230 r = fmri_equal(ud_ctarg, ud_oldtarg);
4231 4231 switch (r) {
4232 4232 case 1:
4233 4233 break;
4234 4234
4235 4235 case 0:
4236 4236 case -1: /* warn? */
4237 4237 warn(cf_newtarg, ient->sc_fmri, ud_name);
4238 4238 return (0);
4239 4239
4240 4240 case -2:
4241 4241 warn(li_corrupt, ient->sc_fmri);
4242 4242 return (EBADF);
4243 4243
4244 4244 default:
4245 4245 bad_error("fmri_equal", r);
4246 4246 }
4247 4247
4248 4248 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4249 4249 switch (scf_error()) {
4250 4250 case SCF_ERROR_NOT_FOUND:
4251 4251 warn(li_corrupt, ient->sc_fmri);
4252 4252 return (EBADF);
4253 4253
4254 4254 case SCF_ERROR_DELETED:
4255 4255 case SCF_ERROR_CONNECTION_BROKEN:
4256 4256 return (scferror2errno(scf_error()));
4257 4257
4258 4258 case SCF_ERROR_NOT_BOUND:
4259 4259 case SCF_ERROR_HANDLE_MISMATCH:
4260 4260 case SCF_ERROR_INVALID_ARGUMENT:
4261 4261 case SCF_ERROR_NOT_SET:
4262 4262 default:
4263 4263 bad_error("scf_snaplevel_get_pg", scf_error());
4264 4264 }
4265 4265 }
4266 4266
4267 4267 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4268 4268 snap_lastimport);
4269 4269 switch (r) {
4270 4270 case 0:
4271 4271 break;
4272 4272
4273 4273 case ECANCELED:
4274 4274 case ECONNABORTED:
4275 4275 case ENOMEM:
4276 4276 case EBADF:
4277 4277 return (r);
4278 4278
4279 4279 case EACCES:
4280 4280 default:
4281 4281 bad_error("load_pg", r);
4282 4282 }
4283 4283
4284 4284 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4285 4285 switch (serr) {
4286 4286 case SCF_ERROR_NONE:
4287 4287 break;
4288 4288
4289 4289 case SCF_ERROR_NO_MEMORY:
4290 4290 internal_pgroup_free(old_dpt_pgroup);
4291 4291 return (ENOMEM);
4292 4292
4293 4293 case SCF_ERROR_NOT_FOUND:
4294 4294 internal_pgroup_free(old_dpt_pgroup);
4295 4295 goto delprop;
4296 4296
4297 4297 case SCF_ERROR_CONSTRAINT_VIOLATED: /* caught above */
4298 4298 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
4299 4299 default:
4300 4300 bad_error("fmri_to_entity", serr);
4301 4301 }
4302 4302
4303 4303 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4304 4304 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4305 4305 switch (r) {
4306 4306 case 0:
4307 4307 break;
4308 4308
4309 4309 case ECONNABORTED:
4310 4310 internal_pgroup_free(old_dpt_pgroup);
4311 4311 return (r);
4312 4312
4313 4313 case ECANCELED:
4314 4314 case ENOENT:
4315 4315 internal_pgroup_free(old_dpt_pgroup);
4316 4316 goto delprop;
4317 4317
4318 4318 case EBADF:
4319 4319 warn(r_no_lvl, ud_ctarg);
4320 4320 internal_pgroup_free(old_dpt_pgroup);
4321 4321 return (r);
4322 4322
4323 4323 case EINVAL:
4324 4324 default:
4325 4325 bad_error("entity_get_running_pg", r);
4326 4326 }
4327 4327
4328 4328 /* load it */
4329 4329 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4330 4330 switch (r) {
4331 4331 case 0:
4332 4332 break;
4333 4333
4334 4334 case ECANCELED:
4335 4335 internal_pgroup_free(old_dpt_pgroup);
4336 4336 goto delprop;
4337 4337
4338 4338 case ECONNABORTED:
4339 4339 case ENOMEM:
4340 4340 case EBADF:
4341 4341 internal_pgroup_free(old_dpt_pgroup);
4342 4342 return (r);
4343 4343
4344 4344 case EACCES:
4345 4345 default:
4346 4346 bad_error("load_pg", r);
4347 4347 }
4348 4348
4349 4349 /* compare property groups */
4350 4350 if (!pg_equal(old_dpt_pgroup, current_pg)) {
4351 4351 warn(cf_newdpg, ient->sc_fmri, ud_name);
4352 4352 internal_pgroup_free(old_dpt_pgroup);
4353 4353 internal_pgroup_free(current_pg);
4354 4354 return (0);
4355 4355 }
4356 4356
4357 4357 internal_pgroup_free(old_dpt_pgroup);
4358 4358 internal_pgroup_free(current_pg);
4359 4359
4360 4360 if (g_verbose)
4361 4361 warn(gettext("%s: Deleting dependent \"%s\".\n"),
4362 4362 ient->sc_fmri, ud_name);
4363 4363
4364 4364 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4365 4365 switch (scf_error()) {
4366 4366 case SCF_ERROR_NOT_FOUND:
4367 4367 case SCF_ERROR_DELETED:
4368 4368 internal_pgroup_free(old_dpt_pgroup);
4369 4369 goto delprop;
4370 4370
4371 4371 case SCF_ERROR_CONNECTION_BROKEN:
4372 4372 internal_pgroup_free(old_dpt_pgroup);
4373 4373 return (ECONNABORTED);
4374 4374
4375 4375 case SCF_ERROR_NOT_SET:
4376 4376 case SCF_ERROR_INVALID_ARGUMENT:
4377 4377 case SCF_ERROR_HANDLE_MISMATCH:
4378 4378 case SCF_ERROR_NOT_BOUND:
4379 4379 default:
4380 4380 bad_error("entity_get_pg", scf_error());
4381 4381 }
4382 4382 }
4383 4383
4384 4384 if (scf_pg_delete(ud_pg) != 0) {
4385 4385 switch (scf_error()) {
4386 4386 case SCF_ERROR_DELETED:
4387 4387 break;
4388 4388
4389 4389 case SCF_ERROR_CONNECTION_BROKEN:
4390 4390 case SCF_ERROR_BACKEND_READONLY:
4391 4391 case SCF_ERROR_BACKEND_ACCESS:
4392 4392 return (scferror2errno(scf_error()));
4393 4393
4394 4394 case SCF_ERROR_PERMISSION_DENIED:
4395 4395 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4396 4396 return (scferror2errno(scf_error()));
4397 4397
4398 4398 case SCF_ERROR_NOT_SET:
4399 4399 default:
4400 4400 bad_error("scf_pg_delete", scf_error());
4401 4401 }
4402 4402 }
4403 4403
4404 4404 /*
4405 4405 * This service was changed, so it must be refreshed. But
4406 4406 * since it's not mentioned in the new manifest, we have to
4407 4407 * record its FMRI here for use later. We record the name
4408 4408 * & the entity (via sc_parent) in case we need to print error
4409 4409 * messages during the refresh.
4410 4410 */
4411 4411 dpt = internal_pgroup_new();
4412 4412 if (dpt == NULL)
4413 4413 return (ENOMEM);
4414 4414 dpt->sc_pgroup_name = strdup(ud_name);
4415 4415 dpt->sc_pgroup_fmri = strdup(ud_ctarg);
4416 4416 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4417 4417 return (ENOMEM);
4418 4418 dpt->sc_parent = (entity_t *)ient;
4419 4419 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4420 4420 uu_die(gettext("libuutil error: %s\n"),
4421 4421 uu_strerror(uu_error()));
4422 4422
4423 4423 delprop:
4424 4424 if (tx == NULL)
4425 4425 return (0);
4426 4426
4427 4427 ent = scf_entry_create(g_hndl);
4428 4428 if (ent == NULL)
4429 4429 return (ENOMEM);
4430 4430
4431 4431 if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
4432 4432 scf_entry_destroy(ent);
4433 4433 switch (scf_error()) {
4434 4434 case SCF_ERROR_DELETED:
4435 4435 warn(emsg_pg_deleted, ient->sc_fmri,
4436 4436 "dependents");
4437 4437 return (EBUSY);
4438 4438
4439 4439 case SCF_ERROR_CONNECTION_BROKEN:
4440 4440 return (scferror2errno(scf_error()));
4441 4441
4442 4442 case SCF_ERROR_NOT_FOUND:
4443 4443 break;
4444 4444
4445 4445 case SCF_ERROR_HANDLE_MISMATCH:
4446 4446 case SCF_ERROR_NOT_BOUND:
4447 4447 case SCF_ERROR_INVALID_ARGUMENT:
4448 4448 case SCF_ERROR_NOT_SET:
4449 4449 default:
4450 4450 bad_error("scf_transaction_property_delete",
4451 4451 scf_error());
4452 4452 }
4453 4453 }
4454 4454
4455 4455 return (0);
4456 4456 }
4457 4457
4458 4458 new_dpt_pgroup->sc_pgroup_seen = 1;
4459 4459
4460 4460 /*
4461 4461 * Decide whether the dependent has changed in the manifest.
4462 4462 */
4463 4463 /* Compare the target. */
4464 4464 if (scf_property_get_value(prop, ud_val) != 0) {
4465 4465 switch (scf_error()) {
4466 4466 case SCF_ERROR_NOT_FOUND:
4467 4467 case SCF_ERROR_CONSTRAINT_VIOLATED:
4468 4468 warn(li_corrupt, ient->sc_fmri);
4469 4469 return (EBADF);
4470 4470
4471 4471 case SCF_ERROR_DELETED:
4472 4472 case SCF_ERROR_CONNECTION_BROKEN:
4473 4473 return (scferror2errno(scf_error()));
4474 4474
4475 4475 case SCF_ERROR_HANDLE_MISMATCH:
4476 4476 case SCF_ERROR_NOT_BOUND:
4477 4477 case SCF_ERROR_NOT_SET:
4478 4478 case SCF_ERROR_PERMISSION_DENIED:
4479 4479 default:
4480 4480 bad_error("scf_property_get_value", scf_error());
4481 4481 }
4482 4482 }
4483 4483
4484 4484 if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
4485 4485 0)
4486 4486 bad_error("scf_value_get_as_string", scf_error());
4487 4487
4488 4488 /*
4489 4489 * If the fmri's are not equal then the old fmri will need to
4490 4490 * be refreshed to ensure that the changes are properly updated
4491 4491 * in that service.
4492 4492 */
4493 4493 r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
4494 4494 switch (r) {
4495 4495 case 0:
4496 4496 dpt = internal_pgroup_new();
4497 4497 if (dpt == NULL)
4498 4498 return (ENOMEM);
4499 4499 dpt->sc_pgroup_name = strdup(ud_name);
4500 4500 dpt->sc_pgroup_fmri = strdup(ud_oldtarg);
4501 4501 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4502 4502 return (ENOMEM);
4503 4503 dpt->sc_parent = (entity_t *)ient;
4504 4504 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4505 4505 uu_die(gettext("libuutil error: %s\n"),
4506 4506 uu_strerror(uu_error()));
4507 4507 break;
4508 4508
4509 4509 case 1:
4510 4510 /* Compare the dependency pgs. */
4511 4511 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4512 4512 switch (scf_error()) {
4513 4513 case SCF_ERROR_NOT_FOUND:
4514 4514 warn(li_corrupt, ient->sc_fmri);
4515 4515 return (EBADF);
4516 4516
4517 4517 case SCF_ERROR_DELETED:
4518 4518 case SCF_ERROR_CONNECTION_BROKEN:
4519 4519 return (scferror2errno(scf_error()));
4520 4520
4521 4521 case SCF_ERROR_NOT_BOUND:
4522 4522 case SCF_ERROR_HANDLE_MISMATCH:
4523 4523 case SCF_ERROR_INVALID_ARGUMENT:
4524 4524 case SCF_ERROR_NOT_SET:
4525 4525 default:
4526 4526 bad_error("scf_snaplevel_get_pg", scf_error());
4527 4527 }
4528 4528 }
4529 4529
4530 4530 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4531 4531 snap_lastimport);
4532 4532 switch (r) {
4533 4533 case 0:
4534 4534 break;
4535 4535
4536 4536 case ECANCELED:
4537 4537 case ECONNABORTED:
4538 4538 case ENOMEM:
4539 4539 case EBADF:
4540 4540 return (r);
4541 4541
4542 4542 case EACCES:
4543 4543 default:
4544 4544 bad_error("load_pg", r);
4545 4545 }
4546 4546
4547 4547 if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4548 4548 /* no change, leave customizations */
4549 4549 internal_pgroup_free(old_dpt_pgroup);
4550 4550 return (0);
4551 4551 }
4552 4552 break;
4553 4553
4554 4554 case -1:
4555 4555 warn(li_corrupt, ient->sc_fmri);
4556 4556 return (EBADF);
4557 4557
4558 4558 case -2:
4559 4559 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4560 4560 ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4561 4561 return (EINVAL);
4562 4562
4563 4563 default:
4564 4564 bad_error("fmri_equal", r);
4565 4565 }
4566 4566
4567 4567 /*
4568 4568 * The dependent has changed in the manifest. Upgrade the current
4569 4569 * properties if they haven't been customized.
4570 4570 */
4571 4571
4572 4572 /*
4573 4573 * If new_dpt_pgroup->sc_override, then act as though the property
4574 4574 * group hasn't been customized.
4575 4575 */
4576 4576 if (new_dpt_pgroup->sc_pgroup_override) {
4577 4577 (void) strcpy(ud_ctarg, ud_oldtarg);
4578 4578 goto nocust;
4579 4579 }
4580 4580
4581 4581 if (!ud_run_dpts_pg_set) {
4582 4582 warn(cf_missing, ient->sc_fmri, ud_name);
4583 4583 r = 0;
4584 4584 goto out;
4585 4585 } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4586 4586 switch (scf_error()) {
4587 4587 case SCF_ERROR_NOT_FOUND:
4588 4588 warn(cf_missing, ient->sc_fmri, ud_name);
4589 4589 r = 0;
4590 4590 goto out;
4591 4591
4592 4592 case SCF_ERROR_CONNECTION_BROKEN:
4593 4593 r = scferror2errno(scf_error());
4594 4594 goto out;
4595 4595
4596 4596 case SCF_ERROR_DELETED:
4597 4597 warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4598 4598 r = EBUSY;
4599 4599 goto out;
4600 4600
4601 4601 case SCF_ERROR_INVALID_ARGUMENT:
4602 4602 case SCF_ERROR_NOT_BOUND:
4603 4603 case SCF_ERROR_HANDLE_MISMATCH:
4604 4604 case SCF_ERROR_NOT_SET:
4605 4605 default:
4606 4606 bad_error("scf_pg_get_property", scf_error());
4607 4607 }
4608 4608 }
4609 4609
4610 4610 if (scf_property_get_value(ud_prop, ud_val) != 0) {
4611 4611 switch (scf_error()) {
4612 4612 case SCF_ERROR_NOT_FOUND:
4613 4613 case SCF_ERROR_CONSTRAINT_VIOLATED:
4614 4614 warn(cf_inval, ient->sc_fmri, ud_name);
4615 4615 r = 0;
4616 4616 goto out;
4617 4617
4618 4618 case SCF_ERROR_DELETED:
4619 4619 case SCF_ERROR_CONNECTION_BROKEN:
4620 4620 r = scferror2errno(scf_error());
4621 4621 goto out;
4622 4622
4623 4623 case SCF_ERROR_HANDLE_MISMATCH:
4624 4624 case SCF_ERROR_NOT_BOUND:
4625 4625 case SCF_ERROR_NOT_SET:
4626 4626 case SCF_ERROR_PERMISSION_DENIED:
4627 4627 default:
4628 4628 bad_error("scf_property_get_value", scf_error());
4629 4629 }
4630 4630 }
4631 4631
4632 4632 ty = scf_value_type(ud_val);
4633 4633 assert(ty != SCF_TYPE_INVALID);
4634 4634 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4635 4635 warn(cf_inval, ient->sc_fmri, ud_name);
4636 4636 r = 0;
4637 4637 goto out;
4638 4638 }
4639 4639 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4640 4640 0)
4641 4641 bad_error("scf_value_get_as_string", scf_error());
4642 4642
4643 4643 r = fmri_equal(ud_ctarg, ud_oldtarg);
4644 4644 if (r == -1) {
4645 4645 warn(cf_inval, ient->sc_fmri, ud_name);
4646 4646 r = 0;
4647 4647 goto out;
4648 4648 } else if (r == -2) {
4649 4649 warn(li_corrupt, ient->sc_fmri);
4650 4650 r = EBADF;
4651 4651 goto out;
4652 4652 } else if (r == 0) {
4653 4653 /*
4654 4654 * Target has been changed. Only abort now if it's been
4655 4655 * changed to something other than what's in the manifest.
4656 4656 */
4657 4657 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4658 4658 if (r == -1) {
4659 4659 warn(cf_inval, ient->sc_fmri, ud_name);
4660 4660 r = 0;
4661 4661 goto out;
4662 4662 } else if (r == 0) {
4663 4663 warn(cf_newtarg, ient->sc_fmri, ud_name);
4664 4664 r = 0;
4665 4665 goto out;
4666 4666 } else if (r != 1) {
4667 4667 /* invalid sc_pgroup_fmri caught above */
4668 4668 bad_error("fmri_equal", r);
4669 4669 }
4670 4670
4671 4671 /*
4672 4672 * Fetch the current dependency pg. If it's what the manifest
4673 4673 * says, then no problem.
4674 4674 */
4675 4675 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4676 4676 switch (serr) {
4677 4677 case SCF_ERROR_NONE:
4678 4678 break;
4679 4679
4680 4680 case SCF_ERROR_NOT_FOUND:
4681 4681 warn(cf_missing, ient->sc_fmri, ud_name);
4682 4682 r = 0;
4683 4683 goto out;
4684 4684
4685 4685 case SCF_ERROR_NO_MEMORY:
4686 4686 r = ENOMEM;
4687 4687 goto out;
4688 4688
4689 4689 case SCF_ERROR_CONSTRAINT_VIOLATED:
4690 4690 case SCF_ERROR_INVALID_ARGUMENT:
4691 4691 default:
4692 4692 bad_error("fmri_to_entity", serr);
4693 4693 }
4694 4694
4695 4695 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4696 4696 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4697 4697 switch (r) {
4698 4698 case 0:
4699 4699 break;
4700 4700
4701 4701 case ECONNABORTED:
4702 4702 goto out;
4703 4703
4704 4704 case ECANCELED:
4705 4705 case ENOENT:
4706 4706 warn(cf_missing, ient->sc_fmri, ud_name);
4707 4707 r = 0;
4708 4708 goto out;
4709 4709
4710 4710 case EBADF:
4711 4711 warn(r_no_lvl, ud_ctarg);
4712 4712 goto out;
4713 4713
4714 4714 case EINVAL:
4715 4715 default:
4716 4716 bad_error("entity_get_running_pg", r);
4717 4717 }
4718 4718
4719 4719 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4720 4720 switch (r) {
4721 4721 case 0:
4722 4722 break;
4723 4723
4724 4724 case ECANCELED:
4725 4725 warn(cf_missing, ient->sc_fmri, ud_name);
4726 4726 r = 0;
4727 4727 goto out;
4728 4728
4729 4729 case ECONNABORTED:
4730 4730 case ENOMEM:
4731 4731 case EBADF:
4732 4732 goto out;
4733 4733
4734 4734 case EACCES:
4735 4735 default:
4736 4736 bad_error("load_pg", r);
4737 4737 }
4738 4738
4739 4739 if (!pg_equal(current_pg, new_dpt_pgroup))
4740 4740 warn(cf_newdpg, ient->sc_fmri, ud_name);
4741 4741 internal_pgroup_free(current_pg);
4742 4742 r = 0;
4743 4743 goto out;
4744 4744 } else if (r != 1) {
4745 4745 bad_error("fmri_equal", r);
4746 4746 }
4747 4747
4748 4748 nocust:
4749 4749 /*
4750 4750 * Target has not been customized. Check the dependency property
4751 4751 * group.
4752 4752 */
4753 4753
4754 4754 if (old_dpt_pgroup == NULL) {
4755 4755 if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4756 4756 ud_pg) != 0) {
4757 4757 switch (scf_error()) {
4758 4758 case SCF_ERROR_NOT_FOUND:
4759 4759 warn(li_corrupt, ient->sc_fmri);
4760 4760 return (EBADF);
4761 4761
4762 4762 case SCF_ERROR_DELETED:
4763 4763 case SCF_ERROR_CONNECTION_BROKEN:
4764 4764 return (scferror2errno(scf_error()));
4765 4765
4766 4766 case SCF_ERROR_NOT_BOUND:
4767 4767 case SCF_ERROR_HANDLE_MISMATCH:
4768 4768 case SCF_ERROR_INVALID_ARGUMENT:
4769 4769 case SCF_ERROR_NOT_SET:
4770 4770 default:
4771 4771 bad_error("scf_snaplevel_get_pg", scf_error());
4772 4772 }
4773 4773 }
4774 4774
4775 4775 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4776 4776 snap_lastimport);
4777 4777 switch (r) {
4778 4778 case 0:
4779 4779 break;
4780 4780
4781 4781 case ECANCELED:
4782 4782 case ECONNABORTED:
4783 4783 case ENOMEM:
4784 4784 case EBADF:
4785 4785 return (r);
4786 4786
4787 4787 case EACCES:
4788 4788 default:
4789 4789 bad_error("load_pg", r);
4790 4790 }
4791 4791 }
4792 4792 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4793 4793 switch (serr) {
4794 4794 case SCF_ERROR_NONE:
4795 4795 break;
4796 4796
4797 4797 case SCF_ERROR_NOT_FOUND:
4798 4798 warn(cf_missing, ient->sc_fmri, ud_name);
4799 4799 r = 0;
4800 4800 goto out;
4801 4801
4802 4802 case SCF_ERROR_NO_MEMORY:
4803 4803 r = ENOMEM;
4804 4804 goto out;
4805 4805
4806 4806 case SCF_ERROR_CONSTRAINT_VIOLATED:
4807 4807 case SCF_ERROR_INVALID_ARGUMENT:
4808 4808 default:
4809 4809 bad_error("fmri_to_entity", serr);
4810 4810 }
4811 4811
4812 4812 r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4813 4813 ud_iter2, ud_inst, imp_snap, ud_snpl);
4814 4814 switch (r) {
4815 4815 case 0:
4816 4816 break;
4817 4817
4818 4818 case ECONNABORTED:
4819 4819 goto out;
4820 4820
4821 4821 case ECANCELED:
4822 4822 case ENOENT:
4823 4823 warn(cf_missing, ient->sc_fmri, ud_name);
4824 4824 r = 0;
4825 4825 goto out;
4826 4826
4827 4827 case EBADF:
4828 4828 warn(r_no_lvl, ud_ctarg);
4829 4829 goto out;
4830 4830
4831 4831 case EINVAL:
4832 4832 default:
4833 4833 bad_error("entity_get_running_pg", r);
4834 4834 }
4835 4835
4836 4836 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4837 4837 switch (r) {
4838 4838 case 0:
4839 4839 break;
4840 4840
4841 4841 case ECANCELED:
4842 4842 warn(cf_missing, ient->sc_fmri, ud_name);
4843 4843 goto out;
4844 4844
4845 4845 case ECONNABORTED:
4846 4846 case ENOMEM:
4847 4847 case EBADF:
4848 4848 goto out;
4849 4849
4850 4850 case EACCES:
4851 4851 default:
4852 4852 bad_error("load_pg", r);
4853 4853 }
4854 4854
4855 4855 if (!pg_equal(current_pg, old_dpt_pgroup)) {
4856 4856 if (!pg_equal(current_pg, new_dpt_pgroup))
4857 4857 warn(cf_newdpg, ient->sc_fmri, ud_name);
4858 4858 internal_pgroup_free(current_pg);
4859 4859 r = 0;
4860 4860 goto out;
4861 4861 }
4862 4862
4863 4863 /* Uncustomized. Upgrade. */
4864 4864
4865 4865 r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4866 4866 switch (r) {
4867 4867 case 1:
4868 4868 if (pg_equal(current_pg, new_dpt_pgroup)) {
4869 4869 /* Already upgraded. */
4870 4870 internal_pgroup_free(current_pg);
4871 4871 r = 0;
4872 4872 goto out;
4873 4873 }
4874 4874
4875 4875 internal_pgroup_free(current_pg);
4876 4876
4877 4877 /* upgrade current_pg */
4878 4878 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4879 4879 switch (scf_error()) {
4880 4880 case SCF_ERROR_CONNECTION_BROKEN:
4881 4881 r = scferror2errno(scf_error());
4882 4882 goto out;
4883 4883
4884 4884 case SCF_ERROR_DELETED:
4885 4885 warn(cf_missing, ient->sc_fmri, ud_name);
4886 4886 r = 0;
4887 4887 goto out;
4888 4888
4889 4889 case SCF_ERROR_NOT_FOUND:
4890 4890 break;
4891 4891
4892 4892 case SCF_ERROR_INVALID_ARGUMENT:
4893 4893 case SCF_ERROR_NOT_BOUND:
4894 4894 case SCF_ERROR_NOT_SET:
4895 4895 case SCF_ERROR_HANDLE_MISMATCH:
4896 4896 default:
4897 4897 bad_error("entity_get_pg", scf_error());
4898 4898 }
4899 4899
4900 4900 if (tissvc)
4901 4901 r = scf_service_add_pg(target_ent, ud_name,
4902 4902 SCF_GROUP_DEPENDENCY, 0, ud_pg);
4903 4903 else
4904 4904 r = scf_instance_add_pg(target_ent, ud_name,
4905 4905 SCF_GROUP_DEPENDENCY, 0, ud_pg);
4906 4906 if (r != 0) {
4907 4907 switch (scf_error()) {
4908 4908 case SCF_ERROR_CONNECTION_BROKEN:
4909 4909 case SCF_ERROR_NO_RESOURCES:
4910 4910 case SCF_ERROR_BACKEND_READONLY:
4911 4911 case SCF_ERROR_BACKEND_ACCESS:
4912 4912 r = scferror2errno(scf_error());
4913 4913 goto out;
4914 4914
4915 4915 case SCF_ERROR_DELETED:
4916 4916 warn(cf_missing, ient->sc_fmri,
4917 4917 ud_name);
4918 4918 r = 0;
4919 4919 goto out;
4920 4920
4921 4921 case SCF_ERROR_PERMISSION_DENIED:
4922 4922 warn(emsg_pg_deleted, ud_ctarg,
4923 4923 ud_name);
4924 4924 r = EPERM;
4925 4925 goto out;
4926 4926
4927 4927 case SCF_ERROR_EXISTS:
4928 4928 warn(emsg_pg_added, ud_ctarg, ud_name);
4929 4929 r = EBUSY;
4930 4930 goto out;
4931 4931
4932 4932 case SCF_ERROR_NOT_BOUND:
4933 4933 case SCF_ERROR_HANDLE_MISMATCH:
4934 4934 case SCF_ERROR_INVALID_ARGUMENT:
4935 4935 case SCF_ERROR_NOT_SET:
4936 4936 default:
4937 4937 bad_error("entity_add_pg", scf_error());
4938 4938 }
4939 4939 }
4940 4940 }
4941 4941
4942 4942 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
4943 4943 switch (r) {
4944 4944 case 0:
4945 4945 break;
4946 4946
4947 4947 case ECANCELED:
4948 4948 warn(cf_missing, ient->sc_fmri, ud_name);
4949 4949 goto out;
4950 4950
4951 4951 case ECONNABORTED:
4952 4952 case ENOMEM:
4953 4953 case EBADF:
4954 4954 goto out;
4955 4955
4956 4956 case EACCES:
4957 4957 default:
4958 4958 bad_error("load_pg", r);
4959 4959 }
4960 4960
4961 4961 if (g_verbose)
4962 4962 warn(upgrading, ient->sc_fmri, ud_name);
4963 4963
4964 4964 r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4965 4965 new_dpt_pgroup, 0, ient->sc_fmri);
4966 4966 switch (r) {
4967 4967 case 0:
4968 4968 break;
4969 4969
4970 4970 case ECANCELED:
4971 4971 warn(emsg_pg_deleted, ud_ctarg, ud_name);
4972 4972 r = EBUSY;
4973 4973 goto out;
4974 4974
4975 4975 case EPERM:
4976 4976 warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4977 4977 goto out;
4978 4978
4979 4979 case EBUSY:
4980 4980 warn(emsg_pg_changed, ud_ctarg, ud_name);
4981 4981 goto out;
4982 4982
4983 4983 case ECONNABORTED:
4984 4984 case ENOMEM:
4985 4985 case ENOSPC:
4986 4986 case EROFS:
4987 4987 case EACCES:
4988 4988 case EINVAL:
4989 4989 goto out;
4990 4990
4991 4991 default:
4992 4992 bad_error("upgrade_pg", r);
4993 4993 }
4994 4994 break;
4995 4995
4996 4996 case 0: {
4997 4997 scf_transaction_entry_t *ent;
4998 4998 scf_value_t *val;
4999 4999
5000 5000 internal_pgroup_free(current_pg);
5001 5001
5002 5002 /* delete old pg */
5003 5003 if (g_verbose)
5004 5004 warn(upgrading, ient->sc_fmri, ud_name);
5005 5005
5006 5006 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
5007 5007 switch (scf_error()) {
5008 5008 case SCF_ERROR_CONNECTION_BROKEN:
5009 5009 r = scferror2errno(scf_error());
5010 5010 goto out;
5011 5011
5012 5012 case SCF_ERROR_DELETED:
5013 5013 warn(cf_missing, ient->sc_fmri, ud_name);
5014 5014 r = 0;
5015 5015 goto out;
5016 5016
5017 5017 case SCF_ERROR_NOT_FOUND:
5018 5018 break;
5019 5019
5020 5020 case SCF_ERROR_INVALID_ARGUMENT:
5021 5021 case SCF_ERROR_NOT_BOUND:
5022 5022 case SCF_ERROR_NOT_SET:
5023 5023 case SCF_ERROR_HANDLE_MISMATCH:
5024 5024 default:
5025 5025 bad_error("entity_get_pg", scf_error());
5026 5026 }
5027 5027 } else if (scf_pg_delete(ud_pg) != 0) {
5028 5028 switch (scf_error()) {
5029 5029 case SCF_ERROR_DELETED:
5030 5030 break;
5031 5031
5032 5032 case SCF_ERROR_CONNECTION_BROKEN:
5033 5033 case SCF_ERROR_BACKEND_READONLY:
5034 5034 case SCF_ERROR_BACKEND_ACCESS:
5035 5035 r = scferror2errno(scf_error());
5036 5036 goto out;
5037 5037
5038 5038 case SCF_ERROR_PERMISSION_DENIED:
5039 5039 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
5040 5040 r = scferror2errno(scf_error());
5041 5041 goto out;
5042 5042
5043 5043 case SCF_ERROR_NOT_SET:
5044 5044 default:
5045 5045 bad_error("scf_pg_delete", scf_error());
5046 5046 }
5047 5047 }
5048 5048
5049 5049 /* import new one */
5050 5050 cbdata.sc_handle = g_hndl;
5051 5051 cbdata.sc_trans = NULL; /* handled below */
5052 5052 cbdata.sc_flags = 0;
5053 5053
5054 5054 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
5055 5055 if (r != UU_WALK_NEXT) {
5056 5056 if (r != UU_WALK_ERROR)
5057 5057 bad_error("lscf_dependent_import", r);
5058 5058
5059 5059 r = cbdata.sc_err;
5060 5060 goto out;
5061 5061 }
5062 5062
5063 5063 if (tx == NULL)
5064 5064 break;
5065 5065
5066 5066 if ((ent = scf_entry_create(g_hndl)) == NULL ||
5067 5067 (val = scf_value_create(g_hndl)) == NULL) {
5068 5068 if (scf_error() == SCF_ERROR_NO_MEMORY)
5069 5069 return (ENOMEM);
5070 5070
5071 5071 bad_error("scf_entry_create", scf_error());
5072 5072 }
5073 5073
5074 5074 if (scf_transaction_property_change_type(tx, ent, ud_name,
5075 5075 SCF_TYPE_FMRI) != 0) {
5076 5076 switch (scf_error()) {
5077 5077 case SCF_ERROR_CONNECTION_BROKEN:
5078 5078 r = scferror2errno(scf_error());
5079 5079 goto out;
5080 5080
5081 5081 case SCF_ERROR_DELETED:
5082 5082 warn(emsg_pg_deleted, ient->sc_fmri,
5083 5083 "dependents");
5084 5084 r = EBUSY;
5085 5085 goto out;
5086 5086
5087 5087 case SCF_ERROR_NOT_FOUND:
5088 5088 break;
5089 5089
5090 5090 case SCF_ERROR_NOT_BOUND:
5091 5091 case SCF_ERROR_HANDLE_MISMATCH:
5092 5092 case SCF_ERROR_INVALID_ARGUMENT:
5093 5093 case SCF_ERROR_NOT_SET:
5094 5094 default:
5095 5095 bad_error("scf_transaction_property_"
5096 5096 "change_type", scf_error());
5097 5097 }
5098 5098
5099 5099 if (scf_transaction_property_new(tx, ent, ud_name,
5100 5100 SCF_TYPE_FMRI) != 0) {
5101 5101 switch (scf_error()) {
5102 5102 case SCF_ERROR_CONNECTION_BROKEN:
5103 5103 r = scferror2errno(scf_error());
5104 5104 goto out;
5105 5105
5106 5106 case SCF_ERROR_DELETED:
5107 5107 warn(emsg_pg_deleted, ient->sc_fmri,
5108 5108 "dependents");
5109 5109 r = EBUSY;
5110 5110 goto out;
5111 5111
5112 5112 case SCF_ERROR_EXISTS:
5113 5113 warn(emsg_pg_changed, ient->sc_fmri,
5114 5114 "dependents");
5115 5115 r = EBUSY;
5116 5116 goto out;
5117 5117
5118 5118 case SCF_ERROR_INVALID_ARGUMENT:
5119 5119 case SCF_ERROR_HANDLE_MISMATCH:
5120 5120 case SCF_ERROR_NOT_BOUND:
5121 5121 case SCF_ERROR_NOT_SET:
5122 5122 default:
5123 5123 bad_error("scf_transaction_property_"
5124 5124 "new", scf_error());
5125 5125 }
5126 5126 }
5127 5127 }
5128 5128
5129 5129 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
5130 5130 new_dpt_pgroup->sc_pgroup_fmri) != 0)
5131 5131 /* invalid sc_pgroup_fmri caught above */
5132 5132 bad_error("scf_value_set_from_string",
5133 5133 scf_error());
5134 5134
5135 5135 if (scf_entry_add_value(ent, val) != 0)
5136 5136 bad_error("scf_entry_add_value", scf_error());
5137 5137 break;
5138 5138 }
5139 5139
5140 5140 case -2:
5141 5141 warn(li_corrupt, ient->sc_fmri);
5142 5142 internal_pgroup_free(current_pg);
5143 5143 r = EBADF;
5144 5144 goto out;
5145 5145
5146 5146 case -1:
5147 5147 default:
5148 5148 /* invalid sc_pgroup_fmri caught above */
5149 5149 bad_error("fmri_equal", r);
5150 5150 }
5151 5151
5152 5152 r = 0;
5153 5153
5154 5154 out:
5155 5155 if (old_dpt_pgroup != NULL)
5156 5156 internal_pgroup_free(old_dpt_pgroup);
5157 5157
5158 5158 return (r);
5159 5159 }
5160 5160
5161 5161 /*
5162 5162 * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
5163 5163 * would import it, except it seems to exist in the service anyway. Compare
5164 5164 * the existent dependent with the one we would import, and report any
5165 5165 * differences (if there are none, be silent). prop is the property which
5166 5166 * represents the existent dependent (in the dependents property group) in the
5167 5167 * entity corresponding to ient.
5168 5168 *
5169 5169 * Returns
5170 5170 * 0 - success (Sort of. At least, we can continue importing.)
5171 5171 * ECONNABORTED - repository connection broken
5172 5172 * EBUSY - ancestor of prop was deleted (error printed)
5173 5173 * ENOMEM - out of memory
5174 5174 * EBADF - corrupt property group (error printed)
5175 5175 * EINVAL - new_dpt_pgroup has invalid target (error printed)
5176 5176 */
5177 5177 static int
5178 5178 handle_dependent_conflict(const entity_t * const ient,
5179 5179 const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
5180 5180 {
5181 5181 int r;
5182 5182 scf_type_t ty;
5183 5183 scf_error_t scfe;
5184 5184 void *tptr;
5185 5185 int tissvc;
5186 5186 pgroup_t *pgroup;
5187 5187
5188 5188 if (scf_property_get_value(prop, ud_val) != 0) {
5189 5189 switch (scf_error()) {
5190 5190 case SCF_ERROR_CONNECTION_BROKEN:
5191 5191 return (scferror2errno(scf_error()));
5192 5192
5193 5193 case SCF_ERROR_DELETED:
5194 5194 warn(emsg_pg_deleted, ient->sc_fmri,
5195 5195 new_dpt_pgroup->sc_pgroup_name);
5196 5196 return (EBUSY);
5197 5197
5198 5198 case SCF_ERROR_CONSTRAINT_VIOLATED:
5199 5199 case SCF_ERROR_NOT_FOUND:
5200 5200 warn(gettext("Conflict upgrading %s (not importing "
5201 5201 "dependent \"%s\" because it already exists.) "
5202 5202 "Warning: The \"%s/%2$s\" property has more or "
5203 5203 "fewer than one value)).\n"), ient->sc_fmri,
5204 5204 new_dpt_pgroup->sc_pgroup_name, "dependents");
5205 5205 return (0);
5206 5206
5207 5207 case SCF_ERROR_HANDLE_MISMATCH:
5208 5208 case SCF_ERROR_NOT_BOUND:
5209 5209 case SCF_ERROR_NOT_SET:
5210 5210 case SCF_ERROR_PERMISSION_DENIED:
5211 5211 default:
5212 5212 bad_error("scf_property_get_value",
5213 5213 scf_error());
5214 5214 }
5215 5215 }
5216 5216
5217 5217 ty = scf_value_type(ud_val);
5218 5218 assert(ty != SCF_TYPE_INVALID);
5219 5219 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
5220 5220 warn(gettext("Conflict upgrading %s (not importing dependent "
5221 5221 "\"%s\" because it already exists). Warning: The "
5222 5222 "\"%s/%s\" property has unexpected type \"%s\")).\n"),
5223 5223 ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
5224 5224 scf_type_to_string(ty), "dependents");
5225 5225 return (0);
5226 5226 }
5227 5227
5228 5228 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
5229 5229 0)
5230 5230 bad_error("scf_value_get_as_string", scf_error());
5231 5231
5232 5232 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
5233 5233 switch (r) {
5234 5234 case 0:
5235 5235 warn(gettext("Conflict upgrading %s (not importing dependent "
5236 5236 "\"%s\" (target \"%s\") because it already exists with "
5237 5237 "target \"%s\").\n"), ient->sc_fmri,
5238 5238 new_dpt_pgroup->sc_pgroup_name,
5239 5239 new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
5240 5240 return (0);
5241 5241
5242 5242 case 1:
5243 5243 break;
5244 5244
5245 5245 case -1:
5246 5246 warn(gettext("Conflict upgrading %s (not importing dependent "
5247 5247 "\"%s\" because it already exists). Warning: The current "
5248 5248 "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
5249 5249 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5250 5250 return (0);
5251 5251
5252 5252 case -2:
5253 5253 warn(gettext("Dependent \"%s\" of %s has invalid target "
5254 5254 "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
5255 5255 new_dpt_pgroup->sc_pgroup_fmri);
5256 5256 return (EINVAL);
5257 5257
5258 5258 default:
5259 5259 bad_error("fmri_equal", r);
5260 5260 }
5261 5261
5262 5262 /* compare dependency pgs in target */
5263 5263 scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
5264 5264 switch (scfe) {
5265 5265 case SCF_ERROR_NONE:
5266 5266 break;
5267 5267
5268 5268 case SCF_ERROR_NO_MEMORY:
5269 5269 return (ENOMEM);
5270 5270
5271 5271 case SCF_ERROR_NOT_FOUND:
5272 5272 warn(emsg_dpt_dangling, ient->sc_fmri,
5273 5273 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5274 5274 return (0);
5275 5275
5276 5276 case SCF_ERROR_CONSTRAINT_VIOLATED:
5277 5277 case SCF_ERROR_INVALID_ARGUMENT:
5278 5278 default:
5279 5279 bad_error("fmri_to_entity", scfe);
5280 5280 }
5281 5281
5282 5282 r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
5283 5283 ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
5284 5284 switch (r) {
5285 5285 case 0:
5286 5286 break;
5287 5287
5288 5288 case ECONNABORTED:
5289 5289 return (r);
5290 5290
5291 5291 case ECANCELED:
5292 5292 warn(emsg_dpt_dangling, ient->sc_fmri,
5293 5293 new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5294 5294 return (0);
5295 5295
5296 5296 case EBADF:
5297 5297 if (tissvc)
5298 5298 warn(gettext("%s has an instance with a \"%s\" "
5299 5299 "snapshot which is missing a snaplevel.\n"),
5300 5300 ud_ctarg, "running");
5301 5301 else
5302 5302 warn(gettext("%s has a \"%s\" snapshot which is "
5303 5303 "missing a snaplevel.\n"), ud_ctarg, "running");
5304 5304 /* FALLTHROUGH */
5305 5305
5306 5306 case ENOENT:
5307 5307 warn(emsg_dpt_no_dep, ient->sc_fmri,
5308 5308 new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5309 5309 new_dpt_pgroup->sc_pgroup_name);
5310 5310 return (0);
5311 5311
5312 5312 case EINVAL:
5313 5313 default:
5314 5314 bad_error("entity_get_running_pg", r);
5315 5315 }
5316 5316
5317 5317 pgroup = internal_pgroup_new();
5318 5318 if (pgroup == NULL)
5319 5319 return (ENOMEM);
5320 5320
5321 5321 r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
5322 5322 switch (r) {
5323 5323 case 0:
5324 5324 break;
5325 5325
5326 5326 case ECONNABORTED:
5327 5327 case EBADF:
5328 5328 case ENOMEM:
5329 5329 internal_pgroup_free(pgroup);
5330 5330 return (r);
5331 5331
5332 5332 case ECANCELED:
5333 5333 warn(emsg_dpt_no_dep, ient->sc_fmri,
5334 5334 new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5335 5335 new_dpt_pgroup->sc_pgroup_name);
5336 5336 internal_pgroup_free(pgroup);
5337 5337 return (0);
5338 5338
5339 5339 case EACCES:
5340 5340 default:
5341 5341 bad_error("load_pg", r);
5342 5342 }
5343 5343
5344 5344 /* report differences */
5345 5345 report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
5346 5346 internal_pgroup_free(pgroup);
5347 5347 return (0);
5348 5348 }
5349 5349
5350 5350 /*
5351 5351 * lipg is a property group in the last-import snapshot of ent, which is an
5352 5352 * scf_service_t or an scf_instance_t (according to ient). If lipg is not in
5353 5353 * ient's pgroups, delete it from ent if it hasn't been customized. If it is
5354 5354 * in ents's property groups, compare and upgrade ent appropriately.
5355 5355 *
5356 5356 * Returns
5357 5357 * 0 - success
5358 5358 * ECONNABORTED - repository connection broken
5359 5359 * ENOMEM - out of memory
5360 5360 * ENOSPC - configd is out of resources
5361 5361 * EINVAL - ient has invalid dependent (error printed)
5362 5362 * - ient has invalid pgroup_t (error printed)
5363 5363 * ECANCELED - ent has been deleted
5364 5364 * ENODEV - entity containing lipg has been deleted
5365 5365 * - entity containing running has been deleted
5366 5366 * EPERM - could not delete pg (permission denied) (error printed)
5367 5367 * - couldn't upgrade dependents (permission denied) (error printed)
5368 5368 * - couldn't import pg (permission denied) (error printed)
5369 5369 * - couldn't upgrade pg (permission denied) (error printed)
5370 5370 * EROFS - could not delete pg (repository read-only)
5371 5371 * - couldn't upgrade dependents (repository read-only)
5372 5372 * - couldn't import pg (repository read-only)
5373 5373 * - couldn't upgrade pg (repository read-only)
5374 5374 * EACCES - could not delete pg (backend access denied)
5375 5375 * - couldn't upgrade dependents (backend access denied)
5376 5376 * - couldn't import pg (backend access denied)
5377 5377 * - couldn't upgrade pg (backend access denied)
5378 5378 * - couldn't read property (backend access denied)
5379 5379 * EBUSY - property group was added (error printed)
5380 5380 * - property group was deleted (error printed)
5381 5381 * - property group changed (error printed)
5382 5382 * - "dependents" pg was added, changed, or deleted (error printed)
5383 5383 * - dependent target deleted (error printed)
5384 5384 * - dependent pg changed (error printed)
5385 5385 * EBADF - imp_snpl is corrupt (error printed)
5386 5386 * - ent has bad pg (error printed)
5387 5387 * EEXIST - dependent collision in target service (error printed)
5388 5388 */
5389 5389 static int
5390 5390 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
5391 5391 const scf_snaplevel_t *running)
5392 5392 {
5393 5393 int r;
5394 5394 pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
5395 5395 scf_callback_t cbdata;
5396 5396
5397 5397 const char * const cf_pg_missing =
5398 5398 gettext("Conflict upgrading %s (property group %s is missing)\n");
5399 5399 const char * const deleting =
5400 5400 gettext("%s: Deleting property group \"%s\".\n");
5401 5401
5402 5402 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5403 5403
5404 5404 /* Skip dependent property groups. */
5405 5405 if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
5406 5406 switch (scf_error()) {
5407 5407 case SCF_ERROR_DELETED:
5408 5408 return (ENODEV);
5409 5409
5410 5410 case SCF_ERROR_CONNECTION_BROKEN:
5411 5411 return (ECONNABORTED);
5412 5412
5413 5413 case SCF_ERROR_NOT_SET:
5414 5414 case SCF_ERROR_NOT_BOUND:
5415 5415 default:
5416 5416 bad_error("scf_pg_get_type", scf_error());
5417 5417 }
5418 5418 }
5419 5419
5420 5420 if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
5421 5421 if (scf_pg_get_property(lipg, "external", NULL) == 0)
5422 5422 return (0);
5423 5423
5424 5424 switch (scf_error()) {
5425 5425 case SCF_ERROR_NOT_FOUND:
5426 5426 break;
5427 5427
5428 5428 case SCF_ERROR_CONNECTION_BROKEN:
5429 5429 return (ECONNABORTED);
5430 5430
5431 5431 case SCF_ERROR_DELETED:
5432 5432 return (ENODEV);
5433 5433
5434 5434 case SCF_ERROR_INVALID_ARGUMENT:
5435 5435 case SCF_ERROR_NOT_BOUND:
5436 5436 case SCF_ERROR_HANDLE_MISMATCH:
5437 5437 case SCF_ERROR_NOT_SET:
5438 5438 default:
5439 5439 bad_error("scf_pg_get_property", scf_error());
5440 5440 }
5441 5441 }
5442 5442
5443 5443 /* lookup pg in new properties */
5444 5444 if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
5445 5445 switch (scf_error()) {
5446 5446 case SCF_ERROR_DELETED:
5447 5447 return (ENODEV);
5448 5448
5449 5449 case SCF_ERROR_CONNECTION_BROKEN:
5450 5450 return (ECONNABORTED);
5451 5451
5452 5452 case SCF_ERROR_NOT_SET:
5453 5453 case SCF_ERROR_NOT_BOUND:
5454 5454 default:
5455 5455 bad_error("scf_pg_get_name", scf_error());
5456 5456 }
5457 5457 }
5458 5458
5459 5459 pgrp.sc_pgroup_name = imp_str;
5460 5460 mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
5461 5461
5462 5462 if (mpg != NULL)
5463 5463 mpg->sc_pgroup_seen = 1;
5464 5464
5465 5465 /* Special handling for dependents */
5466 5466 if (strcmp(imp_str, "dependents") == 0)
5467 5467 return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
5468 5468
5469 5469 if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
5470 5470 return (upgrade_manifestfiles(NULL, ient, running, ent));
5471 5471
5472 5472 if (mpg == NULL || mpg->sc_pgroup_delete) {
5473 5473 /* property group was deleted from manifest */
5474 5474 if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5475 5475 switch (scf_error()) {
5476 5476 case SCF_ERROR_NOT_FOUND:
5477 5477 return (0);
5478 5478
5479 5479 case SCF_ERROR_DELETED:
5480 5480 case SCF_ERROR_CONNECTION_BROKEN:
5481 5481 return (scferror2errno(scf_error()));
5482 5482
5483 5483 case SCF_ERROR_INVALID_ARGUMENT:
5484 5484 case SCF_ERROR_HANDLE_MISMATCH:
5485 5485 case SCF_ERROR_NOT_BOUND:
5486 5486 case SCF_ERROR_NOT_SET:
5487 5487 default:
5488 5488 bad_error("entity_get_pg", scf_error());
5489 5489 }
5490 5490 }
5491 5491
5492 5492 if (mpg != NULL && mpg->sc_pgroup_delete) {
5493 5493 if (g_verbose)
5494 5494 warn(deleting, ient->sc_fmri, imp_str);
5495 5495 if (scf_pg_delete(imp_pg2) == 0)
5496 5496 return (0);
5497 5497
5498 5498 switch (scf_error()) {
5499 5499 case SCF_ERROR_DELETED:
5500 5500 return (0);
5501 5501
5502 5502 case SCF_ERROR_CONNECTION_BROKEN:
5503 5503 case SCF_ERROR_BACKEND_READONLY:
5504 5504 case SCF_ERROR_BACKEND_ACCESS:
5505 5505 return (scferror2errno(scf_error()));
5506 5506
5507 5507 case SCF_ERROR_PERMISSION_DENIED:
5508 5508 warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
5509 5509 return (scferror2errno(scf_error()));
5510 5510
5511 5511 case SCF_ERROR_NOT_SET:
5512 5512 default:
5513 5513 bad_error("scf_pg_delete", scf_error());
5514 5514 }
5515 5515 }
5516 5516
5517 5517 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5518 5518 switch (r) {
5519 5519 case 0:
5520 5520 break;
5521 5521
5522 5522 case ECANCELED:
5523 5523 return (ENODEV);
5524 5524
5525 5525 case ECONNABORTED:
5526 5526 case ENOMEM:
5527 5527 case EBADF:
5528 5528 case EACCES:
5529 5529 return (r);
5530 5530
5531 5531 default:
5532 5532 bad_error("load_pg", r);
5533 5533 }
5534 5534
5535 5535 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5536 5536 switch (r) {
5537 5537 case 0:
5538 5538 break;
5539 5539
5540 5540 case ECANCELED:
5541 5541 case ECONNABORTED:
5542 5542 case ENOMEM:
5543 5543 case EBADF:
5544 5544 case EACCES:
5545 5545 internal_pgroup_free(lipg_i);
5546 5546 return (r);
5547 5547
5548 5548 default:
5549 5549 bad_error("load_pg", r);
5550 5550 }
5551 5551
5552 5552 if (pg_equal(lipg_i, curpg_i)) {
5553 5553 if (g_verbose)
5554 5554 warn(deleting, ient->sc_fmri, imp_str);
5555 5555 if (scf_pg_delete(imp_pg2) != 0) {
5556 5556 switch (scf_error()) {
5557 5557 case SCF_ERROR_DELETED:
5558 5558 break;
5559 5559
5560 5560 case SCF_ERROR_CONNECTION_BROKEN:
5561 5561 internal_pgroup_free(lipg_i);
5562 5562 internal_pgroup_free(curpg_i);
5563 5563 return (ECONNABORTED);
5564 5564
5565 5565 case SCF_ERROR_NOT_SET:
5566 5566 case SCF_ERROR_NOT_BOUND:
5567 5567 default:
5568 5568 bad_error("scf_pg_delete", scf_error());
5569 5569 }
5570 5570 }
5571 5571 } else {
5572 5572 report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5573 5573 }
5574 5574
5575 5575 internal_pgroup_free(lipg_i);
5576 5576 internal_pgroup_free(curpg_i);
5577 5577
5578 5578 return (0);
5579 5579 }
5580 5580
5581 5581 /*
5582 5582 * Only dependent pgs can have override set, and we skipped those
5583 5583 * above.
5584 5584 */
5585 5585 assert(!mpg->sc_pgroup_override);
5586 5586
5587 5587 /* compare */
5588 5588 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5589 5589 switch (r) {
5590 5590 case 0:
5591 5591 break;
5592 5592
5593 5593 case ECANCELED:
5594 5594 return (ENODEV);
5595 5595
5596 5596 case ECONNABORTED:
5597 5597 case EBADF:
5598 5598 case ENOMEM:
5599 5599 case EACCES:
5600 5600 return (r);
5601 5601
5602 5602 default:
5603 5603 bad_error("load_pg", r);
5604 5604 }
5605 5605
5606 5606 if (pg_equal(mpg, lipg_i)) {
5607 5607 /* The manifest pg has not changed. Move on. */
5608 5608 r = 0;
5609 5609 goto out;
5610 5610 }
5611 5611
5612 5612 /* upgrade current properties according to lipg & mpg */
5613 5613 if (running != NULL)
5614 5614 r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5615 5615 else
5616 5616 r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5617 5617 if (r != 0) {
5618 5618 switch (scf_error()) {
5619 5619 case SCF_ERROR_CONNECTION_BROKEN:
5620 5620 r = scferror2errno(scf_error());
5621 5621 goto out;
5622 5622
5623 5623 case SCF_ERROR_DELETED:
5624 5624 if (running != NULL)
5625 5625 r = ENODEV;
5626 5626 else
5627 5627 r = ECANCELED;
5628 5628 goto out;
5629 5629
5630 5630 case SCF_ERROR_NOT_FOUND:
5631 5631 break;
5632 5632
5633 5633 case SCF_ERROR_INVALID_ARGUMENT:
5634 5634 case SCF_ERROR_HANDLE_MISMATCH:
5635 5635 case SCF_ERROR_NOT_BOUND:
5636 5636 case SCF_ERROR_NOT_SET:
5637 5637 default:
5638 5638 bad_error("entity_get_pg", scf_error());
5639 5639 }
5640 5640
5641 5641 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5642 5642
5643 5643 r = 0;
5644 5644 goto out;
5645 5645 }
5646 5646
5647 5647 r = load_pg_attrs(imp_pg2, &curpg_i);
5648 5648 switch (r) {
5649 5649 case 0:
5650 5650 break;
5651 5651
5652 5652 case ECANCELED:
5653 5653 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5654 5654 r = 0;
5655 5655 goto out;
5656 5656
5657 5657 case ECONNABORTED:
5658 5658 case ENOMEM:
5659 5659 goto out;
5660 5660
5661 5661 default:
5662 5662 bad_error("load_pg_attrs", r);
5663 5663 }
5664 5664
5665 5665 if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5666 5666 (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5667 5667 internal_pgroup_free(curpg_i);
5668 5668 r = 0;
5669 5669 goto out;
5670 5670 }
5671 5671
5672 5672 internal_pgroup_free(curpg_i);
5673 5673
5674 5674 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5675 5675 switch (r) {
5676 5676 case 0:
5677 5677 break;
5678 5678
5679 5679 case ECANCELED:
5680 5680 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5681 5681 r = 0;
5682 5682 goto out;
5683 5683
5684 5684 case ECONNABORTED:
5685 5685 case EBADF:
5686 5686 case ENOMEM:
5687 5687 case EACCES:
5688 5688 goto out;
5689 5689
5690 5690 default:
5691 5691 bad_error("load_pg", r);
5692 5692 }
5693 5693
5694 5694 if (pg_equal(lipg_i, curpg_i) &&
5695 5695 !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5696 5696 int do_delete = 1;
5697 5697
5698 5698 if (g_verbose)
5699 5699 warn(gettext("%s: Upgrading property group \"%s\".\n"),
5700 5700 ient->sc_fmri, mpg->sc_pgroup_name);
5701 5701
5702 5702 internal_pgroup_free(curpg_i);
5703 5703
5704 5704 if (running != NULL &&
5705 5705 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5706 5706 switch (scf_error()) {
5707 5707 case SCF_ERROR_DELETED:
5708 5708 r = ECANCELED;
5709 5709 goto out;
5710 5710
5711 5711 case SCF_ERROR_NOT_FOUND:
5712 5712 do_delete = 0;
5713 5713 break;
5714 5714
5715 5715 case SCF_ERROR_CONNECTION_BROKEN:
5716 5716 r = scferror2errno(scf_error());
5717 5717 goto out;
5718 5718
5719 5719 case SCF_ERROR_HANDLE_MISMATCH:
5720 5720 case SCF_ERROR_INVALID_ARGUMENT:
5721 5721 case SCF_ERROR_NOT_SET:
5722 5722 case SCF_ERROR_NOT_BOUND:
5723 5723 default:
5724 5724 bad_error("entity_get_pg", scf_error());
5725 5725 }
5726 5726 }
5727 5727
5728 5728 if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5729 5729 switch (scf_error()) {
5730 5730 case SCF_ERROR_DELETED:
5731 5731 break;
5732 5732
5733 5733 case SCF_ERROR_CONNECTION_BROKEN:
5734 5734 case SCF_ERROR_BACKEND_READONLY:
5735 5735 case SCF_ERROR_BACKEND_ACCESS:
5736 5736 r = scferror2errno(scf_error());
5737 5737 goto out;
5738 5738
5739 5739 case SCF_ERROR_PERMISSION_DENIED:
5740 5740 warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5741 5741 ient->sc_fmri);
5742 5742 r = scferror2errno(scf_error());
5743 5743 goto out;
5744 5744
5745 5745 case SCF_ERROR_NOT_SET:
5746 5746 case SCF_ERROR_NOT_BOUND:
5747 5747 default:
5748 5748 bad_error("scf_pg_delete", scf_error());
5749 5749 }
5750 5750 }
5751 5751
5752 5752 cbdata.sc_handle = g_hndl;
5753 5753 cbdata.sc_parent = ent;
5754 5754 cbdata.sc_service = issvc;
5755 5755 cbdata.sc_flags = 0;
5756 5756 cbdata.sc_source_fmri = ient->sc_fmri;
5757 5757 cbdata.sc_target_fmri = ient->sc_fmri;
5758 5758
5759 5759 r = entity_pgroup_import(mpg, &cbdata);
5760 5760 switch (r) {
5761 5761 case UU_WALK_NEXT:
5762 5762 r = 0;
5763 5763 goto out;
5764 5764
5765 5765 case UU_WALK_ERROR:
5766 5766 if (cbdata.sc_err == EEXIST) {
5767 5767 warn(emsg_pg_added, ient->sc_fmri,
5768 5768 mpg->sc_pgroup_name);
5769 5769 r = EBUSY;
5770 5770 } else {
5771 5771 r = cbdata.sc_err;
5772 5772 }
5773 5773 goto out;
5774 5774
5775 5775 default:
5776 5776 bad_error("entity_pgroup_import", r);
5777 5777 }
5778 5778 }
5779 5779
5780 5780 if (running != NULL &&
5781 5781 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5782 5782 switch (scf_error()) {
5783 5783 case SCF_ERROR_CONNECTION_BROKEN:
5784 5784 case SCF_ERROR_DELETED:
5785 5785 r = scferror2errno(scf_error());
5786 5786 goto out;
5787 5787
5788 5788 case SCF_ERROR_NOT_FOUND:
5789 5789 break;
5790 5790
5791 5791 case SCF_ERROR_HANDLE_MISMATCH:
5792 5792 case SCF_ERROR_INVALID_ARGUMENT:
5793 5793 case SCF_ERROR_NOT_SET:
5794 5794 case SCF_ERROR_NOT_BOUND:
5795 5795 default:
5796 5796 bad_error("entity_get_pg", scf_error());
5797 5797 }
5798 5798
5799 5799 cbdata.sc_handle = g_hndl;
5800 5800 cbdata.sc_parent = ent;
5801 5801 cbdata.sc_service = issvc;
5802 5802 cbdata.sc_flags = SCI_FORCE;
5803 5803 cbdata.sc_source_fmri = ient->sc_fmri;
5804 5804 cbdata.sc_target_fmri = ient->sc_fmri;
5805 5805
5806 5806 r = entity_pgroup_import(mpg, &cbdata);
5807 5807 switch (r) {
5808 5808 case UU_WALK_NEXT:
5809 5809 r = 0;
5810 5810 goto out;
5811 5811
5812 5812 case UU_WALK_ERROR:
5813 5813 if (cbdata.sc_err == EEXIST) {
5814 5814 warn(emsg_pg_added, ient->sc_fmri,
5815 5815 mpg->sc_pgroup_name);
5816 5816 r = EBUSY;
5817 5817 } else {
5818 5818 r = cbdata.sc_err;
5819 5819 }
5820 5820 goto out;
5821 5821
5822 5822 default:
5823 5823 bad_error("entity_pgroup_import", r);
5824 5824 }
5825 5825 }
5826 5826
5827 5827 r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5828 5828 internal_pgroup_free(curpg_i);
5829 5829 switch (r) {
5830 5830 case 0:
5831 5831 ient->sc_import_state = IMPORT_PROP_BEGUN;
5832 5832 break;
5833 5833
5834 5834 case ECANCELED:
5835 5835 warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5836 5836 r = EBUSY;
5837 5837 break;
5838 5838
5839 5839 case EPERM:
5840 5840 warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5841 5841 break;
5842 5842
5843 5843 case EBUSY:
5844 5844 warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5845 5845 break;
5846 5846
5847 5847 case ECONNABORTED:
5848 5848 case ENOMEM:
5849 5849 case ENOSPC:
5850 5850 case EROFS:
5851 5851 case EACCES:
5852 5852 case EINVAL:
5853 5853 break;
5854 5854
5855 5855 default:
5856 5856 bad_error("upgrade_pg", r);
5857 5857 }
5858 5858
5859 5859 out:
5860 5860 internal_pgroup_free(lipg_i);
5861 5861 return (r);
5862 5862 }
5863 5863
5864 5864 /*
5865 5865 * Upgrade the properties of ent according to snpl & ient.
5866 5866 *
5867 5867 * Returns
5868 5868 * 0 - success
5869 5869 * ECONNABORTED - repository connection broken
5870 5870 * ENOMEM - out of memory
5871 5871 * ENOSPC - configd is out of resources
5872 5872 * ECANCELED - ent was deleted
5873 5873 * ENODEV - entity containing snpl was deleted
5874 5874 * - entity containing running was deleted
5875 5875 * EBADF - imp_snpl is corrupt (error printed)
5876 5876 * - ent has corrupt pg (error printed)
5877 5877 * - dependent has corrupt pg (error printed)
5878 5878 * - dependent target has a corrupt snapshot (error printed)
5879 5879 * EBUSY - pg was added, changed, or deleted (error printed)
5880 5880 * - dependent target was deleted (error printed)
5881 5881 * - dependent pg changed (error printed)
5882 5882 * EINVAL - invalid property group name (error printed)
5883 5883 * - invalid property name (error printed)
5884 5884 * - invalid value (error printed)
5885 5885 * - ient has invalid pgroup or dependent (error printed)
5886 5886 * EPERM - could not create property group (permission denied) (error printed)
5887 5887 * - could not modify property group (permission denied) (error printed)
5888 5888 * - couldn't delete, upgrade, or import pg or dependent (error printed)
5889 5889 * EROFS - could not create property group (repository read-only)
5890 5890 * - couldn't delete, upgrade, or import pg or dependent
5891 5891 * EACCES - could not create property group (backend access denied)
5892 5892 * - couldn't delete, upgrade, or import pg or dependent
5893 5893 * EEXIST - dependent collision in target service (error printed)
5894 5894 */
5895 5895 static int
5896 5896 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5897 5897 entity_t *ient)
5898 5898 {
5899 5899 pgroup_t *pg, *rpg;
5900 5900 int r;
5901 5901 uu_list_t *pgs = ient->sc_pgroups;
5902 5902
5903 5903 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5904 5904
5905 5905 /* clear sc_sceen for pgs */
5906 5906 if (uu_list_walk(pgs, clear_int,
5907 5907 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5908 5908 bad_error("uu_list_walk", uu_error());
5909 5909
5910 5910 if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5911 5911 switch (scf_error()) {
5912 5912 case SCF_ERROR_DELETED:
5913 5913 return (ENODEV);
5914 5914
5915 5915 case SCF_ERROR_CONNECTION_BROKEN:
5916 5916 return (ECONNABORTED);
5917 5917
5918 5918 case SCF_ERROR_NOT_SET:
5919 5919 case SCF_ERROR_NOT_BOUND:
5920 5920 case SCF_ERROR_HANDLE_MISMATCH:
5921 5921 default:
5922 5922 bad_error("scf_iter_snaplevel_pgs", scf_error());
5923 5923 }
5924 5924 }
5925 5925
5926 5926 for (;;) {
5927 5927 r = scf_iter_next_pg(imp_up_iter, imp_pg);
5928 5928 if (r == 0)
5929 5929 break;
5930 5930 if (r == 1) {
5931 5931 r = process_old_pg(imp_pg, ient, ent, running);
5932 5932 switch (r) {
5933 5933 case 0:
5934 5934 break;
5935 5935
5936 5936 case ECONNABORTED:
5937 5937 case ENOMEM:
5938 5938 case ENOSPC:
5939 5939 case ECANCELED:
5940 5940 case ENODEV:
5941 5941 case EPERM:
5942 5942 case EROFS:
5943 5943 case EACCES:
5944 5944 case EBADF:
5945 5945 case EBUSY:
5946 5946 case EINVAL:
5947 5947 case EEXIST:
5948 5948 return (r);
5949 5949
5950 5950 default:
5951 5951 bad_error("process_old_pg", r);
5952 5952 }
5953 5953 continue;
5954 5954 }
5955 5955 if (r != -1)
5956 5956 bad_error("scf_iter_next_pg", r);
5957 5957
5958 5958 switch (scf_error()) {
5959 5959 case SCF_ERROR_DELETED:
5960 5960 return (ENODEV);
5961 5961
5962 5962 case SCF_ERROR_CONNECTION_BROKEN:
5963 5963 return (ECONNABORTED);
5964 5964
5965 5965 case SCF_ERROR_HANDLE_MISMATCH:
5966 5966 case SCF_ERROR_NOT_BOUND:
5967 5967 case SCF_ERROR_NOT_SET:
5968 5968 case SCF_ERROR_INVALID_ARGUMENT:
5969 5969 default:
5970 5970 bad_error("scf_iter_next_pg", scf_error());
5971 5971 }
5972 5972 }
5973 5973
5974 5974 for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5975 5975 if (pg->sc_pgroup_seen)
5976 5976 continue;
5977 5977
5978 5978 /* pg is new */
5979 5979
5980 5980 if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5981 5981 r = upgrade_dependents(NULL, imp_snpl, ient, running,
5982 5982 ent);
5983 5983 switch (r) {
5984 5984 case 0:
5985 5985 break;
5986 5986
5987 5987 case ECONNABORTED:
5988 5988 case ENOMEM:
5989 5989 case ENOSPC:
5990 5990 case ECANCELED:
5991 5991 case ENODEV:
5992 5992 case EBADF:
5993 5993 case EBUSY:
5994 5994 case EINVAL:
5995 5995 case EPERM:
5996 5996 case EROFS:
5997 5997 case EACCES:
5998 5998 case EEXIST:
5999 5999 return (r);
6000 6000
6001 6001 default:
6002 6002 bad_error("upgrade_dependents", r);
6003 6003 }
6004 6004 continue;
6005 6005 }
6006 6006
6007 6007 if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
6008 6008 r = upgrade_manifestfiles(pg, ient, running, ent);
6009 6009 switch (r) {
6010 6010 case 0:
6011 6011 break;
6012 6012
6013 6013 case ECONNABORTED:
6014 6014 case ENOMEM:
6015 6015 case ENOSPC:
6016 6016 case ECANCELED:
6017 6017 case ENODEV:
6018 6018 case EBADF:
6019 6019 case EBUSY:
6020 6020 case EINVAL:
6021 6021 case EPERM:
6022 6022 case EROFS:
6023 6023 case EACCES:
6024 6024 case EEXIST:
6025 6025 return (r);
6026 6026
6027 6027 default:
6028 6028 bad_error("upgrade_manifestfiles", r);
6029 6029 }
6030 6030 continue;
6031 6031 }
6032 6032
6033 6033 if (running != NULL) {
6034 6034 r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
6035 6035 imp_pg);
6036 6036 } else {
6037 6037 r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
6038 6038 imp_pg);
6039 6039 }
6040 6040 if (r != 0) {
6041 6041 scf_callback_t cbdata;
6042 6042
6043 6043 switch (scf_error()) {
6044 6044 case SCF_ERROR_NOT_FOUND:
6045 6045 break;
6046 6046
6047 6047 case SCF_ERROR_CONNECTION_BROKEN:
6048 6048 return (scferror2errno(scf_error()));
6049 6049
6050 6050 case SCF_ERROR_DELETED:
6051 6051 if (running != NULL)
6052 6052 return (ENODEV);
6053 6053 else
6054 6054 return (scferror2errno(scf_error()));
6055 6055
6056 6056 case SCF_ERROR_INVALID_ARGUMENT:
6057 6057 warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
6058 6058 pg->sc_pgroup_name);
6059 6059 return (EINVAL);
6060 6060
6061 6061 case SCF_ERROR_NOT_SET:
6062 6062 case SCF_ERROR_HANDLE_MISMATCH:
6063 6063 case SCF_ERROR_NOT_BOUND:
6064 6064 default:
6065 6065 bad_error("entity_get_pg", scf_error());
6066 6066 }
6067 6067
6068 6068 /* User doesn't have pg, so import it. */
6069 6069
6070 6070 cbdata.sc_handle = g_hndl;
6071 6071 cbdata.sc_parent = ent;
6072 6072 cbdata.sc_service = issvc;
6073 6073 cbdata.sc_flags = SCI_FORCE;
6074 6074 cbdata.sc_source_fmri = ient->sc_fmri;
6075 6075 cbdata.sc_target_fmri = ient->sc_fmri;
6076 6076
6077 6077 r = entity_pgroup_import(pg, &cbdata);
6078 6078 switch (r) {
6079 6079 case UU_WALK_NEXT:
6080 6080 ient->sc_import_state = IMPORT_PROP_BEGUN;
6081 6081 continue;
6082 6082
6083 6083 case UU_WALK_ERROR:
6084 6084 if (cbdata.sc_err == EEXIST) {
6085 6085 warn(emsg_pg_added, ient->sc_fmri,
6086 6086 pg->sc_pgroup_name);
6087 6087 return (EBUSY);
6088 6088 }
6089 6089 return (cbdata.sc_err);
6090 6090
6091 6091 default:
6092 6092 bad_error("entity_pgroup_import", r);
6093 6093 }
6094 6094 }
6095 6095
6096 6096 /* report differences between pg & current */
6097 6097 r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
6098 6098 switch (r) {
6099 6099 case 0:
6100 6100 break;
6101 6101
6102 6102 case ECANCELED:
6103 6103 warn(emsg_pg_deleted, ient->sc_fmri,
6104 6104 pg->sc_pgroup_name);
6105 6105 return (EBUSY);
6106 6106
6107 6107 case ECONNABORTED:
6108 6108 case EBADF:
6109 6109 case ENOMEM:
6110 6110 case EACCES:
6111 6111 return (r);
6112 6112
6113 6113 default:
6114 6114 bad_error("load_pg", r);
6115 6115 }
6116 6116 report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
6117 6117 internal_pgroup_free(rpg);
6118 6118 rpg = NULL;
6119 6119 }
6120 6120
6121 6121 return (0);
6122 6122 }
6123 6123
6124 6124 /*
6125 6125 * Import an instance. If it doesn't exist, create it. If it has
6126 6126 * a last-import snapshot, upgrade its properties. Finish by updating its
6127 6127 * last-import snapshot. If it doesn't have a last-import snapshot then it
6128 6128 * could have been created for a dependent tag in another manifest. Import the
6129 6129 * new properties. If there's a conflict, don't override, like now?
6130 6130 *
6131 6131 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
6132 6132 * lcbdata->sc_err to
6133 6133 * ECONNABORTED - repository connection broken
6134 6134 * ENOMEM - out of memory
6135 6135 * ENOSPC - svc.configd is out of resources
6136 6136 * EEXIST - dependency collision in dependent service (error printed)
6137 6137 * EPERM - couldn't create temporary instance (permission denied)
6138 6138 * - couldn't import into temporary instance (permission denied)
6139 6139 * - couldn't take snapshot (permission denied)
6140 6140 * - couldn't upgrade properties (permission denied)
6141 6141 * - couldn't import properties (permission denied)
6142 6142 * - couldn't import dependents (permission denied)
6143 6143 * EROFS - couldn't create temporary instance (repository read-only)
6144 6144 * - couldn't import into temporary instance (repository read-only)
6145 6145 * - couldn't upgrade properties (repository read-only)
6146 6146 * - couldn't import properties (repository read-only)
6147 6147 * - couldn't import dependents (repository read-only)
6148 6148 * EACCES - couldn't create temporary instance (backend access denied)
6149 6149 * - couldn't import into temporary instance (backend access denied)
6150 6150 * - couldn't upgrade properties (backend access denied)
6151 6151 * - couldn't import properties (backend access denied)
6152 6152 * - couldn't import dependents (backend access denied)
6153 6153 * EINVAL - invalid instance name (error printed)
6154 6154 * - invalid pgroup_t's (error printed)
6155 6155 * - invalid dependents (error printed)
6156 6156 * EBUSY - temporary service deleted (error printed)
6157 6157 * - temporary instance deleted (error printed)
6158 6158 * - temporary instance changed (error printed)
6159 6159 * - temporary instance already exists (error printed)
6160 6160 * - instance deleted (error printed)
6161 6161 * EBADF - instance has corrupt last-import snapshot (error printed)
6162 6162 * - instance is corrupt (error printed)
6163 6163 * - dependent has corrupt pg (error printed)
6164 6164 * - dependent target has a corrupt snapshot (error printed)
6165 6165 * -1 - unknown libscf error (error printed)
6166 6166 */
6167 6167 static int
6168 6168 lscf_instance_import(void *v, void *pvt)
6169 6169 {
6170 6170 entity_t *inst = v;
6171 6171 scf_callback_t ctx;
6172 6172 scf_callback_t *lcbdata = pvt;
6173 6173 scf_service_t *rsvc = lcbdata->sc_parent;
6174 6174 int r;
6175 6175 scf_snaplevel_t *running;
6176 6176 int flags = lcbdata->sc_flags;
6177 6177
6178 6178 const char * const emsg_tdel =
6179 6179 gettext("Temporary instance svc:/%s:%s was deleted.\n");
6180 6180 const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
6181 6181 "changed unexpectedly.\n");
6182 6182 const char * const emsg_del = gettext("%s changed unexpectedly "
6183 6183 "(instance \"%s\" was deleted.)\n");
6184 6184 const char * const emsg_badsnap = gettext(
6185 6185 "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
6186 6186
6187 6187 /*
6188 6188 * prepare last-import snapshot:
6189 6189 * create temporary instance (service was precreated)
6190 6190 * populate with properties from bundle
6191 6191 * take snapshot
6192 6192 */
6193 6193 if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
6194 6194 switch (scf_error()) {
6195 6195 case SCF_ERROR_CONNECTION_BROKEN:
6196 6196 case SCF_ERROR_NO_RESOURCES:
6197 6197 case SCF_ERROR_BACKEND_READONLY:
6198 6198 case SCF_ERROR_BACKEND_ACCESS:
6199 6199 return (stash_scferror(lcbdata));
6200 6200
6201 6201 case SCF_ERROR_EXISTS:
6202 6202 warn(gettext("Temporary service svc:/%s "
6203 6203 "changed unexpectedly (instance \"%s\" added).\n"),
6204 6204 imp_tsname, inst->sc_name);
6205 6205 lcbdata->sc_err = EBUSY;
6206 6206 return (UU_WALK_ERROR);
6207 6207
6208 6208 case SCF_ERROR_DELETED:
6209 6209 warn(gettext("Temporary service svc:/%s "
6210 6210 "was deleted unexpectedly.\n"), imp_tsname);
6211 6211 lcbdata->sc_err = EBUSY;
6212 6212 return (UU_WALK_ERROR);
6213 6213
6214 6214 case SCF_ERROR_INVALID_ARGUMENT:
6215 6215 warn(gettext("Invalid instance name \"%s\".\n"),
6216 6216 inst->sc_name);
6217 6217 return (stash_scferror(lcbdata));
6218 6218
6219 6219 case SCF_ERROR_PERMISSION_DENIED:
6220 6220 warn(gettext("Could not create temporary instance "
6221 6221 "\"%s\" in svc:/%s (permission denied).\n"),
6222 6222 inst->sc_name, imp_tsname);
6223 6223 return (stash_scferror(lcbdata));
6224 6224
6225 6225 case SCF_ERROR_HANDLE_MISMATCH:
6226 6226 case SCF_ERROR_NOT_BOUND:
6227 6227 case SCF_ERROR_NOT_SET:
6228 6228 default:
6229 6229 bad_error("scf_service_add_instance", scf_error());
6230 6230 }
6231 6231 }
6232 6232
6233 6233 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6234 6234 inst->sc_name);
6235 6235 if (r < 0)
6236 6236 bad_error("snprintf", errno);
6237 6237
6238 6238 r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
6239 6239 lcbdata->sc_flags | SCI_NOENABLED);
6240 6240 switch (r) {
6241 6241 case 0:
6242 6242 break;
6243 6243
6244 6244 case ECANCELED:
6245 6245 warn(emsg_tdel, imp_tsname, inst->sc_name);
6246 6246 lcbdata->sc_err = EBUSY;
6247 6247 r = UU_WALK_ERROR;
6248 6248 goto deltemp;
6249 6249
6250 6250 case EEXIST:
6251 6251 warn(emsg_tchg, imp_tsname, inst->sc_name);
6252 6252 lcbdata->sc_err = EBUSY;
6253 6253 r = UU_WALK_ERROR;
6254 6254 goto deltemp;
6255 6255
6256 6256 case ECONNABORTED:
6257 6257 goto connaborted;
6258 6258
6259 6259 case ENOMEM:
6260 6260 case ENOSPC:
6261 6261 case EPERM:
6262 6262 case EROFS:
6263 6263 case EACCES:
6264 6264 case EINVAL:
6265 6265 case EBUSY:
6266 6266 lcbdata->sc_err = r;
6267 6267 r = UU_WALK_ERROR;
6268 6268 goto deltemp;
6269 6269
6270 6270 default:
6271 6271 bad_error("lscf_import_instance_pgs", r);
6272 6272 }
6273 6273
6274 6274 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6275 6275 inst->sc_name);
6276 6276 if (r < 0)
6277 6277 bad_error("snprintf", errno);
6278 6278
6279 6279 ctx.sc_handle = lcbdata->sc_handle;
6280 6280 ctx.sc_parent = imp_tinst;
6281 6281 ctx.sc_service = 0;
6282 6282 ctx.sc_source_fmri = inst->sc_fmri;
6283 6283 ctx.sc_target_fmri = imp_str;
6284 6284 if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
6285 6285 UU_DEFAULT) != 0) {
6286 6286 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6287 6287 bad_error("uu_list_walk", uu_error());
6288 6288
6289 6289 switch (ctx.sc_err) {
6290 6290 case ECONNABORTED:
6291 6291 goto connaborted;
6292 6292
6293 6293 case ECANCELED:
6294 6294 warn(emsg_tdel, imp_tsname, inst->sc_name);
6295 6295 lcbdata->sc_err = EBUSY;
6296 6296 break;
6297 6297
6298 6298 case EEXIST:
6299 6299 warn(emsg_tchg, imp_tsname, inst->sc_name);
6300 6300 lcbdata->sc_err = EBUSY;
6301 6301 break;
6302 6302
6303 6303 default:
6304 6304 lcbdata->sc_err = ctx.sc_err;
6305 6305 }
6306 6306 r = UU_WALK_ERROR;
6307 6307 goto deltemp;
6308 6308 }
6309 6309
6310 6310 if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
6311 6311 inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
6312 6312 switch (scf_error()) {
6313 6313 case SCF_ERROR_CONNECTION_BROKEN:
6314 6314 goto connaborted;
6315 6315
6316 6316 case SCF_ERROR_NO_RESOURCES:
6317 6317 r = stash_scferror(lcbdata);
6318 6318 goto deltemp;
6319 6319
6320 6320 case SCF_ERROR_EXISTS:
6321 6321 warn(emsg_tchg, imp_tsname, inst->sc_name);
6322 6322 lcbdata->sc_err = EBUSY;
6323 6323 r = UU_WALK_ERROR;
6324 6324 goto deltemp;
6325 6325
6326 6326 case SCF_ERROR_PERMISSION_DENIED:
6327 6327 warn(gettext("Could not take \"%s\" snapshot of %s "
6328 6328 "(permission denied).\n"), snap_lastimport,
6329 6329 imp_str);
6330 6330 r = stash_scferror(lcbdata);
6331 6331 goto deltemp;
6332 6332
6333 6333 default:
6334 6334 scfwarn();
6335 6335 lcbdata->sc_err = -1;
6336 6336 r = UU_WALK_ERROR;
6337 6337 goto deltemp;
6338 6338
6339 6339 case SCF_ERROR_HANDLE_MISMATCH:
6340 6340 case SCF_ERROR_INVALID_ARGUMENT:
6341 6341 case SCF_ERROR_NOT_SET:
6342 6342 bad_error("_scf_snapshot_take_new_named", scf_error());
6343 6343 }
6344 6344 }
6345 6345
6346 6346 if (lcbdata->sc_flags & SCI_FRESH)
6347 6347 goto fresh;
6348 6348
6349 6349 if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
6350 6350 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6351 6351 imp_lisnap) != 0) {
6352 6352 switch (scf_error()) {
6353 6353 case SCF_ERROR_DELETED:
6354 6354 warn(emsg_del, inst->sc_parent->sc_fmri,
6355 6355 inst->sc_name);
6356 6356 lcbdata->sc_err = EBUSY;
6357 6357 r = UU_WALK_ERROR;
6358 6358 goto deltemp;
6359 6359
6360 6360 case SCF_ERROR_NOT_FOUND:
6361 6361 flags |= SCI_FORCE;
6362 6362 goto nosnap;
6363 6363
6364 6364 case SCF_ERROR_CONNECTION_BROKEN:
6365 6365 goto connaborted;
6366 6366
6367 6367 case SCF_ERROR_INVALID_ARGUMENT:
6368 6368 case SCF_ERROR_HANDLE_MISMATCH:
6369 6369 case SCF_ERROR_NOT_BOUND:
6370 6370 case SCF_ERROR_NOT_SET:
6371 6371 default:
6372 6372 bad_error("scf_instance_get_snapshot",
6373 6373 scf_error());
6374 6374 }
6375 6375 }
6376 6376
6377 6377 /* upgrade */
6378 6378
6379 6379 /*
6380 6380 * compare new properties with last-import properties
6381 6381 * upgrade current properties
6382 6382 */
6383 6383 /* clear sc_sceen for pgs */
6384 6384 if (uu_list_walk(inst->sc_pgroups, clear_int,
6385 6385 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
6386 6386 0)
6387 6387 bad_error("uu_list_walk", uu_error());
6388 6388
6389 6389 r = get_snaplevel(imp_lisnap, 0, imp_snpl);
6390 6390 switch (r) {
6391 6391 case 0:
6392 6392 break;
6393 6393
6394 6394 case ECONNABORTED:
6395 6395 goto connaborted;
6396 6396
6397 6397 case ECANCELED:
6398 6398 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6399 6399 lcbdata->sc_err = EBUSY;
6400 6400 r = UU_WALK_ERROR;
6401 6401 goto deltemp;
6402 6402
6403 6403 case ENOENT:
6404 6404 warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
6405 6405 lcbdata->sc_err = EBADF;
6406 6406 r = UU_WALK_ERROR;
6407 6407 goto deltemp;
6408 6408
6409 6409 default:
6410 6410 bad_error("get_snaplevel", r);
6411 6411 }
6412 6412
6413 6413 if (scf_instance_get_snapshot(imp_inst, snap_running,
6414 6414 imp_rsnap) != 0) {
6415 6415 switch (scf_error()) {
6416 6416 case SCF_ERROR_DELETED:
6417 6417 warn(emsg_del, inst->sc_parent->sc_fmri,
6418 6418 inst->sc_name);
6419 6419 lcbdata->sc_err = EBUSY;
6420 6420 r = UU_WALK_ERROR;
6421 6421 goto deltemp;
6422 6422
6423 6423 case SCF_ERROR_NOT_FOUND:
6424 6424 break;
6425 6425
6426 6426 case SCF_ERROR_CONNECTION_BROKEN:
6427 6427 goto connaborted;
6428 6428
6429 6429 case SCF_ERROR_INVALID_ARGUMENT:
6430 6430 case SCF_ERROR_HANDLE_MISMATCH:
6431 6431 case SCF_ERROR_NOT_BOUND:
6432 6432 case SCF_ERROR_NOT_SET:
6433 6433 default:
6434 6434 bad_error("scf_instance_get_snapshot",
6435 6435 scf_error());
6436 6436 }
6437 6437
6438 6438 running = NULL;
6439 6439 } else {
6440 6440 r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
6441 6441 switch (r) {
6442 6442 case 0:
6443 6443 running = imp_rsnpl;
6444 6444 break;
6445 6445
6446 6446 case ECONNABORTED:
6447 6447 goto connaborted;
6448 6448
6449 6449 case ECANCELED:
6450 6450 warn(emsg_del, inst->sc_parent->sc_fmri,
6451 6451 inst->sc_name);
6452 6452 lcbdata->sc_err = EBUSY;
6453 6453 r = UU_WALK_ERROR;
6454 6454 goto deltemp;
6455 6455
6456 6456 case ENOENT:
6457 6457 warn(emsg_badsnap, snap_running, inst->sc_fmri);
6458 6458 lcbdata->sc_err = EBADF;
6459 6459 r = UU_WALK_ERROR;
6460 6460 goto deltemp;
6461 6461
6462 6462 default:
6463 6463 bad_error("get_snaplevel", r);
6464 6464 }
6465 6465 }
6466 6466
6467 6467 r = upgrade_props(imp_inst, running, imp_snpl, inst);
6468 6468 switch (r) {
6469 6469 case 0:
6470 6470 break;
6471 6471
6472 6472 case ECANCELED:
6473 6473 case ENODEV:
6474 6474 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6475 6475 lcbdata->sc_err = EBUSY;
6476 6476 r = UU_WALK_ERROR;
6477 6477 goto deltemp;
6478 6478
6479 6479 case ECONNABORTED:
6480 6480 goto connaborted;
6481 6481
6482 6482 case ENOMEM:
6483 6483 case ENOSPC:
6484 6484 case EBADF:
6485 6485 case EBUSY:
6486 6486 case EINVAL:
6487 6487 case EPERM:
6488 6488 case EROFS:
6489 6489 case EACCES:
6490 6490 case EEXIST:
6491 6491 lcbdata->sc_err = r;
6492 6492 r = UU_WALK_ERROR;
6493 6493 goto deltemp;
6494 6494
6495 6495 default:
6496 6496 bad_error("upgrade_props", r);
6497 6497 }
6498 6498
6499 6499 inst->sc_import_state = IMPORT_PROP_DONE;
6500 6500 } else {
6501 6501 switch (scf_error()) {
6502 6502 case SCF_ERROR_CONNECTION_BROKEN:
6503 6503 goto connaborted;
6504 6504
6505 6505 case SCF_ERROR_NOT_FOUND:
6506 6506 break;
6507 6507
6508 6508 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
6509 6509 case SCF_ERROR_HANDLE_MISMATCH:
6510 6510 case SCF_ERROR_NOT_BOUND:
6511 6511 case SCF_ERROR_NOT_SET:
6512 6512 default:
6513 6513 bad_error("scf_service_get_instance", scf_error());
6514 6514 }
6515 6515
6516 6516 fresh:
6517 6517 /* create instance */
6518 6518 if (scf_service_add_instance(rsvc, inst->sc_name,
6519 6519 imp_inst) != 0) {
6520 6520 switch (scf_error()) {
6521 6521 case SCF_ERROR_CONNECTION_BROKEN:
6522 6522 goto connaborted;
6523 6523
6524 6524 case SCF_ERROR_NO_RESOURCES:
6525 6525 case SCF_ERROR_BACKEND_READONLY:
6526 6526 case SCF_ERROR_BACKEND_ACCESS:
6527 6527 r = stash_scferror(lcbdata);
6528 6528 goto deltemp;
6529 6529
6530 6530 case SCF_ERROR_EXISTS:
6531 6531 warn(gettext("%s changed unexpectedly "
6532 6532 "(instance \"%s\" added).\n"),
6533 6533 inst->sc_parent->sc_fmri, inst->sc_name);
6534 6534 lcbdata->sc_err = EBUSY;
6535 6535 r = UU_WALK_ERROR;
6536 6536 goto deltemp;
6537 6537
6538 6538 case SCF_ERROR_PERMISSION_DENIED:
6539 6539 warn(gettext("Could not create \"%s\" instance "
6540 6540 "in %s (permission denied).\n"),
6541 6541 inst->sc_name, inst->sc_parent->sc_fmri);
6542 6542 r = stash_scferror(lcbdata);
6543 6543 goto deltemp;
6544 6544
6545 6545 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
6546 6546 case SCF_ERROR_HANDLE_MISMATCH:
6547 6547 case SCF_ERROR_NOT_BOUND:
6548 6548 case SCF_ERROR_NOT_SET:
6549 6549 default:
6550 6550 bad_error("scf_service_add_instance",
6551 6551 scf_error());
6552 6552 }
6553 6553 }
6554 6554
6555 6555 nosnap:
6556 6556 /*
6557 6557 * Create a last-import snapshot to serve as an attachment
6558 6558 * point for the real one from the temporary instance. Since
6559 6559 * the contents is irrelevant, take it now, while the instance
6560 6560 * is empty, to minimize svc.configd's work.
6561 6561 */
6562 6562 if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6563 6563 imp_lisnap) != 0) {
6564 6564 switch (scf_error()) {
6565 6565 case SCF_ERROR_CONNECTION_BROKEN:
6566 6566 goto connaborted;
6567 6567
6568 6568 case SCF_ERROR_NO_RESOURCES:
6569 6569 r = stash_scferror(lcbdata);
6570 6570 goto deltemp;
6571 6571
6572 6572 case SCF_ERROR_EXISTS:
6573 6573 warn(gettext("%s changed unexpectedly "
6574 6574 "(snapshot \"%s\" added).\n"),
6575 6575 inst->sc_fmri, snap_lastimport);
6576 6576 lcbdata->sc_err = EBUSY;
6577 6577 r = UU_WALK_ERROR;
6578 6578 goto deltemp;
6579 6579
6580 6580 case SCF_ERROR_PERMISSION_DENIED:
6581 6581 warn(gettext("Could not take \"%s\" snapshot "
6582 6582 "of %s (permission denied).\n"),
6583 6583 snap_lastimport, inst->sc_fmri);
6584 6584 r = stash_scferror(lcbdata);
6585 6585 goto deltemp;
6586 6586
6587 6587 default:
6588 6588 scfwarn();
6589 6589 lcbdata->sc_err = -1;
6590 6590 r = UU_WALK_ERROR;
6591 6591 goto deltemp;
6592 6592
6593 6593 case SCF_ERROR_NOT_SET:
6594 6594 case SCF_ERROR_INTERNAL:
6595 6595 case SCF_ERROR_INVALID_ARGUMENT:
6596 6596 case SCF_ERROR_HANDLE_MISMATCH:
6597 6597 bad_error("_scf_snapshot_take_new",
6598 6598 scf_error());
6599 6599 }
6600 6600 }
6601 6601
6602 6602 if (li_only)
6603 6603 goto lionly;
6604 6604
6605 6605 inst->sc_import_state = IMPORT_PROP_BEGUN;
6606 6606
6607 6607 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6608 6608 flags);
6609 6609 switch (r) {
6610 6610 case 0:
6611 6611 break;
6612 6612
6613 6613 case ECONNABORTED:
6614 6614 goto connaborted;
6615 6615
6616 6616 case ECANCELED:
6617 6617 warn(gettext("%s changed unexpectedly "
6618 6618 "(instance \"%s\" deleted).\n"),
6619 6619 inst->sc_parent->sc_fmri, inst->sc_name);
6620 6620 lcbdata->sc_err = EBUSY;
6621 6621 r = UU_WALK_ERROR;
6622 6622 goto deltemp;
6623 6623
6624 6624 case EEXIST:
6625 6625 warn(gettext("%s changed unexpectedly "
6626 6626 "(property group added).\n"), inst->sc_fmri);
6627 6627 lcbdata->sc_err = EBUSY;
6628 6628 r = UU_WALK_ERROR;
6629 6629 goto deltemp;
6630 6630
6631 6631 default:
6632 6632 lcbdata->sc_err = r;
6633 6633 r = UU_WALK_ERROR;
6634 6634 goto deltemp;
6635 6635
6636 6636 case EINVAL: /* caught above */
6637 6637 bad_error("lscf_import_instance_pgs", r);
6638 6638 }
6639 6639
6640 6640 ctx.sc_parent = imp_inst;
6641 6641 ctx.sc_service = 0;
6642 6642 ctx.sc_trans = NULL;
6643 6643 ctx.sc_flags = 0;
6644 6644 if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6645 6645 &ctx, UU_DEFAULT) != 0) {
6646 6646 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6647 6647 bad_error("uu_list_walk", uu_error());
6648 6648
6649 6649 if (ctx.sc_err == ECONNABORTED)
6650 6650 goto connaborted;
6651 6651 lcbdata->sc_err = ctx.sc_err;
6652 6652 r = UU_WALK_ERROR;
6653 6653 goto deltemp;
6654 6654 }
6655 6655
6656 6656 inst->sc_import_state = IMPORT_PROP_DONE;
6657 6657
6658 6658 if (g_verbose)
6659 6659 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6660 6660 snap_initial, inst->sc_fmri);
6661 6661 r = take_snap(imp_inst, snap_initial, imp_snap);
6662 6662 switch (r) {
6663 6663 case 0:
6664 6664 break;
6665 6665
6666 6666 case ECONNABORTED:
6667 6667 goto connaborted;
6668 6668
6669 6669 case ENOSPC:
6670 6670 case -1:
6671 6671 lcbdata->sc_err = r;
6672 6672 r = UU_WALK_ERROR;
6673 6673 goto deltemp;
6674 6674
6675 6675 case ECANCELED:
6676 6676 warn(gettext("%s changed unexpectedly "
6677 6677 "(instance %s deleted).\n"),
6678 6678 inst->sc_parent->sc_fmri, inst->sc_name);
6679 6679 lcbdata->sc_err = r;
6680 6680 r = UU_WALK_ERROR;
6681 6681 goto deltemp;
6682 6682
6683 6683 case EPERM:
6684 6684 warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6685 6685 lcbdata->sc_err = r;
6686 6686 r = UU_WALK_ERROR;
6687 6687 goto deltemp;
6688 6688
6689 6689 default:
6690 6690 bad_error("take_snap", r);
6691 6691 }
6692 6692 }
6693 6693
6694 6694 lionly:
6695 6695 if (lcbdata->sc_flags & SCI_NOSNAP)
6696 6696 goto deltemp;
6697 6697
6698 6698 /* transfer snapshot from temporary instance */
6699 6699 if (g_verbose)
6700 6700 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6701 6701 snap_lastimport, inst->sc_fmri);
6702 6702 if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6703 6703 switch (scf_error()) {
6704 6704 case SCF_ERROR_CONNECTION_BROKEN:
6705 6705 goto connaborted;
6706 6706
6707 6707 case SCF_ERROR_NO_RESOURCES:
6708 6708 r = stash_scferror(lcbdata);
6709 6709 goto deltemp;
6710 6710
6711 6711 case SCF_ERROR_PERMISSION_DENIED:
6712 6712 warn(gettext("Could not take \"%s\" snapshot for %s "
6713 6713 "(permission denied).\n"), snap_lastimport,
6714 6714 inst->sc_fmri);
6715 6715 r = stash_scferror(lcbdata);
6716 6716 goto deltemp;
6717 6717
6718 6718 case SCF_ERROR_NOT_SET:
6719 6719 case SCF_ERROR_HANDLE_MISMATCH:
6720 6720 default:
6721 6721 bad_error("_scf_snapshot_attach", scf_error());
6722 6722 }
6723 6723 }
6724 6724
6725 6725 inst->sc_import_state = IMPORT_COMPLETE;
6726 6726
6727 6727 r = UU_WALK_NEXT;
6728 6728
6729 6729 deltemp:
6730 6730 /* delete temporary instance */
6731 6731 if (scf_instance_delete(imp_tinst) != 0) {
6732 6732 switch (scf_error()) {
6733 6733 case SCF_ERROR_DELETED:
6734 6734 break;
6735 6735
6736 6736 case SCF_ERROR_CONNECTION_BROKEN:
6737 6737 goto connaborted;
6738 6738
6739 6739 case SCF_ERROR_NOT_SET:
6740 6740 case SCF_ERROR_NOT_BOUND:
6741 6741 default:
6742 6742 bad_error("scf_instance_delete", scf_error());
6743 6743 }
6744 6744 }
6745 6745
6746 6746 return (r);
6747 6747
6748 6748 connaborted:
6749 6749 warn(gettext("Could not delete svc:/%s:%s "
6750 6750 "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6751 6751 lcbdata->sc_err = ECONNABORTED;
6752 6752 return (UU_WALK_ERROR);
6753 6753 }
6754 6754
6755 6755 /*
6756 6756 * When an instance is imported we end up telling configd about it. Once we tell
6757 6757 * configd about these changes, startd eventually notices. If this is a new
6758 6758 * instance, the manifest may not specify the SCF_PG_RESTARTER (restarter)
6759 6759 * property group. However, many of the other tools expect that this property
6760 6760 * group exists and has certain values.
6761 6761 *
6762 6762 * These values are added asynchronously by startd. We should not return from
6763 6763 * this routine until we can verify that the property group we need is there.
6764 6764 *
6765 6765 * Before we go ahead and verify this, we have to ask ourselves an important
6766 6766 * question: Is the early manifest service currently running? Because if it is
6767 6767 * running and it has invoked us, then the service will never get a restarter
6768 6768 * property because svc.startd is blocked on EMI finishing before it lets itself
6769 6769 * fully connect to svc.configd. Of course, this means that this race condition
6770 6770 * is in fact impossible to 100% eliminate.
6771 6771 *
6772 6772 * svc.startd makes sure that EMI only runs once and has succeeded by checking
6773 6773 * the state of the EMI instance. If it is online it bails out and makes sure
6774 6774 * that it doesn't run again. In this case, we're going to do something similar,
6775 6775 * only if the state is online, then we're going to actually verify. EMI always
6776 6776 * has to be present, but it can be explicitly disabled to reduce the amount of
6777 6777 * damage it can cause. If EMI has been disabled then we no longer have to worry
6778 6778 * about the implicit race condition and can go ahead and check things. If EMI
6779 6779 * is in some state that isn't online or disabled and isn't runinng, then we
6780 6780 * assume that things are rather bad and we're not going to get in your way,
6781 6781 * even if the rest of SMF does.
6782 6782 *
6783 6783 * Returns 0 on success or returns an errno.
6784 6784 */
6785 6785 #ifndef NATIVE_BUILD
6786 6786 static int
6787 6787 lscf_instance_verify(scf_scope_t *scope, entity_t *svc, entity_t *inst)
6788 6788 {
6789 6789 int ret, err;
6790 6790 struct timespec ts;
6791 6791 char *emi_state;
6792 6792
6793 6793 /*
6794 6794 * smf_get_state does not distinguish between its different failure
6795 6795 * modes: memory allocation failures, SMF internal failures, and a lack
6796 6796 * of EMI entirely because it's been removed. In these cases, we're
6797 6797 * going to be conservative and opt to say that if we don't know, better
6798 6798 * to not block import or falsely warn to the user.
6799 6799 */
6800 6800 if ((emi_state = smf_get_state(SCF_INSTANCE_EMI)) == NULL) {
6801 6801 return (0);
6802 6802 }
6803 6803
6804 6804 /*
6805 6805 * As per the block comment for this function check the state of EMI
6806 6806 */
6807 6807 if (strcmp(emi_state, SCF_STATE_STRING_ONLINE) != 0 &&
6808 6808 strcmp(emi_state, SCF_STATE_STRING_DISABLED) != 0) {
6809 6809 warn(gettext("Not validating instance %s:%s because EMI's "
6810 6810 "state is %s\n"), svc->sc_name, inst->sc_name, emi_state);
6811 6811 free(emi_state);
6812 6812 return (0);
6813 6813 }
6814 6814
6815 6815 free(emi_state);
6816 6816
6817 6817 /*
6818 6818 * First we have to get the property.
6819 6819 */
6820 6820 if ((ret = scf_scope_get_service(scope, svc->sc_name, imp_svc)) != 0) {
6821 6821 ret = scf_error();
6822 6822 warn(gettext("Failed to look up service: %s\n"), svc->sc_name);
6823 6823 return (ret);
6824 6824 }
6825 6825
6826 6826 /*
6827 6827 * We should always be able to get the instance. It should already
6828 6828 * exist because we just created it or got it. There probably is a
6829 6829 * slim chance that someone may have come in and deleted it though from
6830 6830 * under us.
6831 6831 */
6832 6832 if ((ret = scf_service_get_instance(imp_svc, inst->sc_name, imp_inst))
6833 6833 != 0) {
6834 6834 ret = scf_error();
6835 6835 warn(gettext("Failed to verify instance: %s\n"), inst->sc_name);
6836 6836 switch (ret) {
6837 6837 case SCF_ERROR_DELETED:
6838 6838 err = ENODEV;
6839 6839 break;
6840 6840 case SCF_ERROR_CONNECTION_BROKEN:
6841 6841 warn(gettext("Lost repository connection\n"));
6842 6842 err = ECONNABORTED;
6843 6843 break;
6844 6844 case SCF_ERROR_NOT_FOUND:
6845 6845 warn(gettext("Instance \"%s\" disappeared out from "
6846 6846 "under us.\n"), inst->sc_name);
6847 6847 err = ENOENT;
6848 6848 break;
6849 6849 default:
6850 6850 bad_error("scf_service_get_instance", ret);
6851 6851 }
6852 6852
6853 6853 return (err);
6854 6854 }
6855 6855
6856 6856 /*
6857 6857 * An astute observer may want to use _scf_wait_pg which would notify us
6858 6858 * of a property group change, unfortunately that does not work if the
6859 6859 * property group in question does not exist. So instead we have to
6860 6860 * manually poll and ask smf the best way to get to it.
6861 6861 */
6862 6862 while ((ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg))
6863 6863 != SCF_SUCCESS) {
6864 6864 ret = scf_error();
6865 6865 if (ret != SCF_ERROR_NOT_FOUND) {
6866 6866 warn(gettext("Failed to get restarter property "
6867 6867 "group for instance: %s\n"), inst->sc_name);
6868 6868 switch (ret) {
6869 6869 case SCF_ERROR_DELETED:
6870 6870 err = ENODEV;
6871 6871 break;
6872 6872 case SCF_ERROR_CONNECTION_BROKEN:
6873 6873 warn(gettext("Lost repository connection\n"));
6874 6874 err = ECONNABORTED;
6875 6875 break;
6876 6876 default:
6877 6877 bad_error("scf_service_get_instance", ret);
6878 6878 }
6879 6879
6880 6880 return (err);
6881 6881 }
6882 6882
6883 6883 ts.tv_sec = pg_timeout / NANOSEC;
6884 6884 ts.tv_nsec = pg_timeout % NANOSEC;
6885 6885
6886 6886 (void) nanosleep(&ts, NULL);
6887 6887 }
6888 6888
6889 6889 /*
6890 6890 * svcadm also expects that the SCF_PROPERTY_STATE property is present.
6891 6891 * So in addition to the property group being present, we need to wait
6892 6892 * for the property to be there in some form.
6893 6893 *
6894 6894 * Note that a property group is a frozen snapshot in time. To properly
6895 6895 * get beyond this, you have to refresh the property group each time.
6896 6896 */
6897 6897 while ((ret = scf_pg_get_property(imp_pg, SCF_PROPERTY_STATE,
6898 6898 imp_prop)) != 0) {
6899 6899
6900 6900 ret = scf_error();
6901 6901 if (ret != SCF_ERROR_NOT_FOUND) {
6902 6902 warn(gettext("Failed to get property %s from the "
6903 6903 "restarter property group of instance %s\n"),
6904 6904 SCF_PROPERTY_STATE, inst->sc_name);
6905 6905 switch (ret) {
6906 6906 case SCF_ERROR_CONNECTION_BROKEN:
6907 6907 warn(gettext("Lost repository connection\n"));
6908 6908 err = ECONNABORTED;
6909 6909 break;
6910 6910 case SCF_ERROR_DELETED:
6911 6911 err = ENODEV;
6912 6912 break;
6913 6913 default:
6914 6914 bad_error("scf_pg_get_property", ret);
6915 6915 }
6916 6916
6917 6917 return (err);
6918 6918 }
6919 6919
6920 6920 ts.tv_sec = pg_timeout / NANOSEC;
6921 6921 ts.tv_nsec = pg_timeout % NANOSEC;
6922 6922
6923 6923 (void) nanosleep(&ts, NULL);
6924 6924
6925 6925 ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg);
6926 6926 if (ret != SCF_SUCCESS) {
6927 6927 warn(gettext("Failed to get restarter property "
6928 6928 "group for instance: %s\n"), inst->sc_name);
6929 6929 switch (ret) {
6930 6930 case SCF_ERROR_DELETED:
6931 6931 err = ENODEV;
6932 6932 break;
6933 6933 case SCF_ERROR_CONNECTION_BROKEN:
6934 6934 warn(gettext("Lost repository connection\n"));
6935 6935 err = ECONNABORTED;
6936 6936 break;
6937 6937 default:
6938 6938 bad_error("scf_service_get_instance", ret);
6939 6939 }
6940 6940
6941 6941 return (err);
6942 6942 }
6943 6943 }
6944 6944
6945 6945 /*
6946 6946 * We don't have to free the property groups or other values that we got
6947 6947 * because we stored them in global variables that are allocated and
6948 6948 * freed by the routines that call into these functions. Unless of
6949 6949 * course the rest of the code here that we are basing this on is
6950 6950 * mistaken.
6951 6951 */
6952 6952 return (0);
6953 6953 }
6954 6954 #endif
6955 6955
6956 6956 /*
6957 6957 * If the service is missing, create it, import its properties, and import the
6958 6958 * instances. Since the service is brand new, it should be empty, and if we
6959 6959 * run into any existing entities (SCF_ERROR_EXISTS), abort.
6960 6960 *
6961 6961 * If the service exists, we want to upgrade its properties and import the
6962 6962 * instances. Upgrade requires a last-import snapshot, though, which are
6963 6963 * children of instances, so first we'll have to go through the instances
6964 6964 * looking for a last-import snapshot. If we don't find one then we'll just
6965 6965 * override-import the service properties (but don't delete existing
6966 6966 * properties: another service might have declared us as a dependent). Before
6967 6967 * we change anything, though, we want to take the previous snapshots. We
6968 6968 * also give lscf_instance_import() a leg up on taking last-import snapshots
6969 6969 * by importing the manifest's service properties into a temporary service.
6970 6970 *
6971 6971 * On success, returns UU_WALK_NEXT. On failure, returns UU_WALK_ERROR and
6972 6972 * sets lcbdata->sc_err to
6973 6973 * ECONNABORTED - repository connection broken
6974 6974 * ENOMEM - out of memory
6975 6975 * ENOSPC - svc.configd is out of resources
6976 6976 * EPERM - couldn't create temporary service (error printed)
6977 6977 * - couldn't import into temp service (error printed)
6978 6978 * - couldn't create service (error printed)
6979 6979 * - couldn't import dependent (error printed)
6980 6980 * - couldn't take snapshot (error printed)
6981 6981 * - couldn't create instance (error printed)
6982 6982 * - couldn't create, modify, or delete pg (error printed)
6983 6983 * - couldn't create, modify, or delete dependent (error printed)
6984 6984 * - couldn't import instance (error printed)
6985 6985 * EROFS - couldn't create temporary service (repository read-only)
6986 6986 * - couldn't import into temporary service (repository read-only)
6987 6987 * - couldn't create service (repository read-only)
6988 6988 * - couldn't import dependent (repository read-only)
6989 6989 * - couldn't create instance (repository read-only)
6990 6990 * - couldn't create, modify, or delete pg or dependent
6991 6991 * - couldn't import instance (repository read-only)
6992 6992 * EACCES - couldn't create temporary service (backend access denied)
6993 6993 * - couldn't import into temporary service (backend access denied)
6994 6994 * - couldn't create service (backend access denied)
6995 6995 * - couldn't import dependent (backend access denied)
6996 6996 * - couldn't create instance (backend access denied)
6997 6997 * - couldn't create, modify, or delete pg or dependent
6998 6998 * - couldn't import instance (backend access denied)
6999 6999 * EINVAL - service name is invalid (error printed)
7000 7000 * - service name is too long (error printed)
7001 7001 * - s has invalid pgroup (error printed)
7002 7002 * - s has invalid dependent (error printed)
7003 7003 * - instance name is invalid (error printed)
7004 7004 * - instance entity_t is invalid (error printed)
7005 7005 * EEXIST - couldn't create temporary service (already exists) (error printed)
7006 7006 * - couldn't import dependent (dependency pg already exists) (printed)
7007 7007 * - dependency collision in dependent service (error printed)
7008 7008 * EBUSY - temporary service deleted (error printed)
7009 7009 * - property group added to temporary service (error printed)
7010 7010 * - new property group changed or was deleted (error printed)
7011 7011 * - service was added unexpectedly (error printed)
7012 7012 * - service was deleted unexpectedly (error printed)
7013 7013 * - property group added to new service (error printed)
7014 7014 * - instance added unexpectedly (error printed)
7015 7015 * - instance deleted unexpectedly (error printed)
7016 7016 * - dependent service deleted unexpectedly (error printed)
7017 7017 * - pg was added, changed, or deleted (error printed)
7018 7018 * - dependent pg changed (error printed)
7019 7019 * - temporary instance added, changed, or deleted (error printed)
7020 7020 * EBADF - a last-import snapshot is corrupt (error printed)
7021 7021 * - the service is corrupt (error printed)
7022 7022 * - a dependent is corrupt (error printed)
7023 7023 * - an instance is corrupt (error printed)
7024 7024 * - an instance has a corrupt last-import snapshot (error printed)
7025 7025 * - dependent target has a corrupt snapshot (error printed)
7026 7026 * -1 - unknown libscf error (error printed)
7027 7027 */
7028 7028 static int
7029 7029 lscf_service_import(void *v, void *pvt)
7030 7030 {
7031 7031 entity_t *s = v;
7032 7032 scf_callback_t cbdata;
7033 7033 scf_callback_t *lcbdata = pvt;
7034 7034 scf_scope_t *scope = lcbdata->sc_parent;
7035 7035 entity_t *inst, linst;
7036 7036 int r;
7037 7037 int fresh = 0;
7038 7038 scf_snaplevel_t *running;
7039 7039 int have_ge = 0;
7040 7040 boolean_t retried = B_FALSE;
7041 7041
7042 7042 const char * const ts_deleted = gettext("Temporary service svc:/%s "
7043 7043 "was deleted unexpectedly.\n");
7044 7044 const char * const ts_pg_added = gettext("Temporary service svc:/%s "
7045 7045 "changed unexpectedly (property group added).\n");
7046 7046 const char * const s_deleted =
7047 7047 gettext("%s was deleted unexpectedly.\n");
7048 7048 const char * const i_deleted =
7049 7049 gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
7050 7050 const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
7051 7051 "is corrupt (missing service snaplevel).\n");
7052 7052 const char * const s_mfile_upd =
7053 7053 gettext("Unable to update the manifest file connection "
7054 7054 "for %s\n");
7055 7055
7056 7056 li_only = 0;
7057 7057 /* Validate the service name */
7058 7058 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7059 7059 switch (scf_error()) {
7060 7060 case SCF_ERROR_CONNECTION_BROKEN:
7061 7061 return (stash_scferror(lcbdata));
7062 7062
7063 7063 case SCF_ERROR_INVALID_ARGUMENT:
7064 7064 warn(gettext("\"%s\" is an invalid service name. "
7065 7065 "Cannot import.\n"), s->sc_name);
7066 7066 return (stash_scferror(lcbdata));
7067 7067
7068 7068 case SCF_ERROR_NOT_FOUND:
7069 7069 break;
7070 7070
7071 7071 case SCF_ERROR_HANDLE_MISMATCH:
7072 7072 case SCF_ERROR_NOT_BOUND:
7073 7073 case SCF_ERROR_NOT_SET:
7074 7074 default:
7075 7075 bad_error("scf_scope_get_service", scf_error());
7076 7076 }
7077 7077 }
7078 7078
7079 7079 /* create temporary service */
7080 7080 /*
7081 7081 * the size of the buffer was reduced to max_scf_name_len to prevent
7082 7082 * hitting bug 6681151. After the bug fix, the size of the buffer
7083 7083 * should be restored to its original value (max_scf_name_len +1)
7084 7084 */
7085 7085 r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
7086 7086 if (r < 0)
7087 7087 bad_error("snprintf", errno);
7088 7088 if (r > max_scf_name_len) {
7089 7089 warn(gettext(
7090 7090 "Service name \"%s\" is too long. Cannot import.\n"),
7091 7091 s->sc_name);
7092 7092 lcbdata->sc_err = EINVAL;
7093 7093 return (UU_WALK_ERROR);
7094 7094 }
7095 7095
7096 7096 retry:
7097 7097 if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
7098 7098 switch (scf_error()) {
7099 7099 case SCF_ERROR_CONNECTION_BROKEN:
7100 7100 case SCF_ERROR_NO_RESOURCES:
7101 7101 case SCF_ERROR_BACKEND_READONLY:
7102 7102 case SCF_ERROR_BACKEND_ACCESS:
7103 7103 return (stash_scferror(lcbdata));
7104 7104
7105 7105 case SCF_ERROR_EXISTS:
7106 7106 if (!retried) {
7107 7107 lscf_delete(imp_tsname, 0);
7108 7108 retried = B_TRUE;
7109 7109 goto retry;
7110 7110 }
7111 7111 warn(gettext(
7112 7112 "Temporary service \"%s\" must be deleted before "
7113 7113 "this manifest can be imported.\n"), imp_tsname);
7114 7114 return (stash_scferror(lcbdata));
7115 7115
7116 7116 case SCF_ERROR_PERMISSION_DENIED:
7117 7117 warn(gettext("Could not create temporary service "
7118 7118 "\"%s\" (permission denied).\n"), imp_tsname);
7119 7119 return (stash_scferror(lcbdata));
7120 7120
7121 7121 case SCF_ERROR_INVALID_ARGUMENT:
7122 7122 case SCF_ERROR_HANDLE_MISMATCH:
7123 7123 case SCF_ERROR_NOT_BOUND:
7124 7124 case SCF_ERROR_NOT_SET:
7125 7125 default:
7126 7126 bad_error("scf_scope_add_service", scf_error());
7127 7127 }
7128 7128 }
7129 7129
7130 7130 r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
7131 7131 if (r < 0)
7132 7132 bad_error("snprintf", errno);
7133 7133
7134 7134 cbdata.sc_handle = lcbdata->sc_handle;
7135 7135 cbdata.sc_parent = imp_tsvc;
7136 7136 cbdata.sc_service = 1;
7137 7137 cbdata.sc_source_fmri = s->sc_fmri;
7138 7138 cbdata.sc_target_fmri = imp_str;
7139 7139 cbdata.sc_flags = 0;
7140 7140
7141 7141 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
7142 7142 UU_DEFAULT) != 0) {
7143 7143 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7144 7144 bad_error("uu_list_walk", uu_error());
7145 7145
7146 7146 lcbdata->sc_err = cbdata.sc_err;
7147 7147 switch (cbdata.sc_err) {
7148 7148 case ECONNABORTED:
7149 7149 goto connaborted;
7150 7150
7151 7151 case ECANCELED:
7152 7152 warn(ts_deleted, imp_tsname);
7153 7153 lcbdata->sc_err = EBUSY;
7154 7154 return (UU_WALK_ERROR);
7155 7155
7156 7156 case EEXIST:
7157 7157 warn(ts_pg_added, imp_tsname);
7158 7158 lcbdata->sc_err = EBUSY;
7159 7159 return (UU_WALK_ERROR);
7160 7160 }
7161 7161
7162 7162 r = UU_WALK_ERROR;
7163 7163 goto deltemp;
7164 7164 }
7165 7165
7166 7166 if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
7167 7167 UU_DEFAULT) != 0) {
7168 7168 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7169 7169 bad_error("uu_list_walk", uu_error());
7170 7170
7171 7171 lcbdata->sc_err = cbdata.sc_err;
7172 7172 switch (cbdata.sc_err) {
7173 7173 case ECONNABORTED:
7174 7174 goto connaborted;
7175 7175
7176 7176 case ECANCELED:
7177 7177 warn(ts_deleted, imp_tsname);
7178 7178 lcbdata->sc_err = EBUSY;
7179 7179 return (UU_WALK_ERROR);
7180 7180
7181 7181 case EEXIST:
7182 7182 warn(ts_pg_added, imp_tsname);
7183 7183 lcbdata->sc_err = EBUSY;
7184 7184 return (UU_WALK_ERROR);
7185 7185 }
7186 7186
7187 7187 r = UU_WALK_ERROR;
7188 7188 goto deltemp;
7189 7189 }
7190 7190
7191 7191 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7192 7192 switch (scf_error()) {
7193 7193 case SCF_ERROR_NOT_FOUND:
7194 7194 break;
7195 7195
7196 7196 case SCF_ERROR_CONNECTION_BROKEN:
7197 7197 goto connaborted;
7198 7198
7199 7199 case SCF_ERROR_INVALID_ARGUMENT:
7200 7200 case SCF_ERROR_HANDLE_MISMATCH:
7201 7201 case SCF_ERROR_NOT_BOUND:
7202 7202 case SCF_ERROR_NOT_SET:
7203 7203 default:
7204 7204 bad_error("scf_scope_get_service", scf_error());
7205 7205 }
7206 7206
7207 7207 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
7208 7208 switch (scf_error()) {
7209 7209 case SCF_ERROR_CONNECTION_BROKEN:
7210 7210 goto connaborted;
7211 7211
7212 7212 case SCF_ERROR_NO_RESOURCES:
7213 7213 case SCF_ERROR_BACKEND_READONLY:
7214 7214 case SCF_ERROR_BACKEND_ACCESS:
7215 7215 r = stash_scferror(lcbdata);
7216 7216 goto deltemp;
7217 7217
7218 7218 case SCF_ERROR_EXISTS:
7219 7219 warn(gettext("Scope \"%s\" changed unexpectedly"
7220 7220 " (service \"%s\" added).\n"),
7221 7221 SCF_SCOPE_LOCAL, s->sc_name);
7222 7222 lcbdata->sc_err = EBUSY;
7223 7223 goto deltemp;
7224 7224
7225 7225 case SCF_ERROR_PERMISSION_DENIED:
7226 7226 warn(gettext("Could not create service \"%s\" "
7227 7227 "(permission denied).\n"), s->sc_name);
7228 7228 goto deltemp;
7229 7229
7230 7230 case SCF_ERROR_INVALID_ARGUMENT:
7231 7231 case SCF_ERROR_HANDLE_MISMATCH:
7232 7232 case SCF_ERROR_NOT_BOUND:
7233 7233 case SCF_ERROR_NOT_SET:
7234 7234 default:
7235 7235 bad_error("scf_scope_add_service", scf_error());
7236 7236 }
7237 7237 }
7238 7238
7239 7239 s->sc_import_state = IMPORT_PROP_BEGUN;
7240 7240
7241 7241 /* import service properties */
7242 7242 cbdata.sc_handle = lcbdata->sc_handle;
7243 7243 cbdata.sc_parent = imp_svc;
7244 7244 cbdata.sc_service = 1;
7245 7245 cbdata.sc_flags = lcbdata->sc_flags;
7246 7246 cbdata.sc_source_fmri = s->sc_fmri;
7247 7247 cbdata.sc_target_fmri = s->sc_fmri;
7248 7248
7249 7249 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7250 7250 &cbdata, UU_DEFAULT) != 0) {
7251 7251 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7252 7252 bad_error("uu_list_walk", uu_error());
7253 7253
7254 7254 lcbdata->sc_err = cbdata.sc_err;
7255 7255 switch (cbdata.sc_err) {
7256 7256 case ECONNABORTED:
7257 7257 goto connaborted;
7258 7258
7259 7259 case ECANCELED:
7260 7260 warn(s_deleted, s->sc_fmri);
7261 7261 lcbdata->sc_err = EBUSY;
7262 7262 return (UU_WALK_ERROR);
7263 7263
7264 7264 case EEXIST:
7265 7265 warn(gettext("%s changed unexpectedly "
7266 7266 "(property group added).\n"), s->sc_fmri);
7267 7267 lcbdata->sc_err = EBUSY;
7268 7268 return (UU_WALK_ERROR);
7269 7269
7270 7270 case EINVAL:
7271 7271 /* caught above */
7272 7272 bad_error("entity_pgroup_import",
7273 7273 cbdata.sc_err);
7274 7274 }
7275 7275
7276 7276 r = UU_WALK_ERROR;
7277 7277 goto deltemp;
7278 7278 }
7279 7279
7280 7280 cbdata.sc_trans = NULL;
7281 7281 cbdata.sc_flags = 0;
7282 7282 if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
7283 7283 &cbdata, UU_DEFAULT) != 0) {
7284 7284 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7285 7285 bad_error("uu_list_walk", uu_error());
7286 7286
7287 7287 lcbdata->sc_err = cbdata.sc_err;
7288 7288 if (cbdata.sc_err == ECONNABORTED)
7289 7289 goto connaborted;
7290 7290 r = UU_WALK_ERROR;
7291 7291 goto deltemp;
7292 7292 }
7293 7293
7294 7294 s->sc_import_state = IMPORT_PROP_DONE;
7295 7295
7296 7296 /*
7297 7297 * This is a new service, so we can't take previous snapshots
7298 7298 * or upgrade service properties.
7299 7299 */
7300 7300 fresh = 1;
7301 7301 goto instances;
7302 7302 }
7303 7303
7304 7304 /* Clear sc_seen for the instances. */
7305 7305 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
7306 7306 (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
7307 7307 bad_error("uu_list_walk", uu_error());
7308 7308
7309 7309 /*
7310 7310 * Take previous snapshots for all instances. Even for ones not
7311 7311 * mentioned in the bundle, since we might change their service
7312 7312 * properties.
7313 7313 */
7314 7314 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7315 7315 switch (scf_error()) {
7316 7316 case SCF_ERROR_CONNECTION_BROKEN:
7317 7317 goto connaborted;
7318 7318
7319 7319 case SCF_ERROR_DELETED:
7320 7320 warn(s_deleted, s->sc_fmri);
7321 7321 lcbdata->sc_err = EBUSY;
7322 7322 r = UU_WALK_ERROR;
7323 7323 goto deltemp;
7324 7324
7325 7325 case SCF_ERROR_HANDLE_MISMATCH:
7326 7326 case SCF_ERROR_NOT_BOUND:
7327 7327 case SCF_ERROR_NOT_SET:
7328 7328 default:
7329 7329 bad_error("scf_iter_service_instances", scf_error());
7330 7330 }
7331 7331 }
7332 7332
7333 7333 for (;;) {
7334 7334 r = scf_iter_next_instance(imp_iter, imp_inst);
7335 7335 if (r == 0)
7336 7336 break;
7337 7337 if (r != 1) {
7338 7338 switch (scf_error()) {
7339 7339 case SCF_ERROR_DELETED:
7340 7340 warn(s_deleted, s->sc_fmri);
7341 7341 lcbdata->sc_err = EBUSY;
7342 7342 r = UU_WALK_ERROR;
7343 7343 goto deltemp;
7344 7344
7345 7345 case SCF_ERROR_CONNECTION_BROKEN:
7346 7346 goto connaborted;
7347 7347
7348 7348 case SCF_ERROR_NOT_BOUND:
7349 7349 case SCF_ERROR_HANDLE_MISMATCH:
7350 7350 case SCF_ERROR_INVALID_ARGUMENT:
7351 7351 case SCF_ERROR_NOT_SET:
7352 7352 default:
7353 7353 bad_error("scf_iter_next_instance",
7354 7354 scf_error());
7355 7355 }
7356 7356 }
7357 7357
7358 7358 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
7359 7359 switch (scf_error()) {
7360 7360 case SCF_ERROR_DELETED:
7361 7361 continue;
7362 7362
7363 7363 case SCF_ERROR_CONNECTION_BROKEN:
7364 7364 goto connaborted;
7365 7365
7366 7366 case SCF_ERROR_NOT_SET:
7367 7367 case SCF_ERROR_NOT_BOUND:
7368 7368 default:
7369 7369 bad_error("scf_instance_get_name", scf_error());
7370 7370 }
7371 7371 }
7372 7372
7373 7373 if (g_verbose)
7374 7374 warn(gettext(
7375 7375 "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
7376 7376 snap_previous, s->sc_name, imp_str);
7377 7377
7378 7378 r = take_snap(imp_inst, snap_previous, imp_snap);
7379 7379 switch (r) {
7380 7380 case 0:
7381 7381 break;
7382 7382
7383 7383 case ECANCELED:
7384 7384 continue;
7385 7385
7386 7386 case ECONNABORTED:
7387 7387 goto connaborted;
7388 7388
7389 7389 case EPERM:
7390 7390 warn(gettext("Could not take \"%s\" snapshot of "
7391 7391 "svc:/%s:%s (permission denied).\n"),
7392 7392 snap_previous, s->sc_name, imp_str);
7393 7393 lcbdata->sc_err = r;
7394 7394 return (UU_WALK_ERROR);
7395 7395
7396 7396 case ENOSPC:
7397 7397 case -1:
7398 7398 lcbdata->sc_err = r;
7399 7399 r = UU_WALK_ERROR;
7400 7400 goto deltemp;
7401 7401
7402 7402 default:
7403 7403 bad_error("take_snap", r);
7404 7404 }
7405 7405
7406 7406 linst.sc_name = imp_str;
7407 7407 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
7408 7408 &linst, NULL, NULL);
7409 7409 if (inst != NULL) {
7410 7410 inst->sc_import_state = IMPORT_PREVIOUS;
7411 7411 inst->sc_seen = 1;
7412 7412 }
7413 7413 }
7414 7414
7415 7415 /*
7416 7416 * Create the new instances and take previous snapshots of
7417 7417 * them. This is not necessary, but it maximizes data preservation.
7418 7418 */
7419 7419 for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
7420 7420 inst != NULL;
7421 7421 inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
7422 7422 inst)) {
7423 7423 if (inst->sc_seen)
7424 7424 continue;
7425 7425
7426 7426 if (scf_service_add_instance(imp_svc, inst->sc_name,
7427 7427 imp_inst) != 0) {
7428 7428 switch (scf_error()) {
7429 7429 case SCF_ERROR_CONNECTION_BROKEN:
7430 7430 goto connaborted;
7431 7431
7432 7432 case SCF_ERROR_BACKEND_READONLY:
7433 7433 case SCF_ERROR_BACKEND_ACCESS:
7434 7434 case SCF_ERROR_NO_RESOURCES:
7435 7435 r = stash_scferror(lcbdata);
7436 7436 goto deltemp;
7437 7437
7438 7438 case SCF_ERROR_EXISTS:
7439 7439 warn(gettext("%s changed unexpectedly "
7440 7440 "(instance \"%s\" added).\n"), s->sc_fmri,
7441 7441 inst->sc_name);
7442 7442 lcbdata->sc_err = EBUSY;
7443 7443 r = UU_WALK_ERROR;
7444 7444 goto deltemp;
7445 7445
7446 7446 case SCF_ERROR_INVALID_ARGUMENT:
7447 7447 warn(gettext("Service \"%s\" has instance with "
7448 7448 "invalid name \"%s\".\n"), s->sc_name,
7449 7449 inst->sc_name);
7450 7450 r = stash_scferror(lcbdata);
7451 7451 goto deltemp;
7452 7452
7453 7453 case SCF_ERROR_PERMISSION_DENIED:
7454 7454 warn(gettext("Could not create instance \"%s\" "
7455 7455 "in %s (permission denied).\n"),
7456 7456 inst->sc_name, s->sc_fmri);
7457 7457 r = stash_scferror(lcbdata);
7458 7458 goto deltemp;
7459 7459
7460 7460 case SCF_ERROR_HANDLE_MISMATCH:
7461 7461 case SCF_ERROR_NOT_BOUND:
7462 7462 case SCF_ERROR_NOT_SET:
7463 7463 default:
7464 7464 bad_error("scf_service_add_instance",
7465 7465 scf_error());
7466 7466 }
7467 7467 }
7468 7468
7469 7469 if (g_verbose)
7470 7470 warn(gettext("Taking \"%s\" snapshot for "
7471 7471 "new service %s.\n"), snap_previous, inst->sc_fmri);
7472 7472 r = take_snap(imp_inst, snap_previous, imp_snap);
7473 7473 switch (r) {
7474 7474 case 0:
7475 7475 break;
7476 7476
7477 7477 case ECANCELED:
7478 7478 warn(i_deleted, s->sc_fmri, inst->sc_name);
7479 7479 lcbdata->sc_err = EBUSY;
7480 7480 r = UU_WALK_ERROR;
7481 7481 goto deltemp;
7482 7482
7483 7483 case ECONNABORTED:
7484 7484 goto connaborted;
7485 7485
7486 7486 case EPERM:
7487 7487 warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
7488 7488 lcbdata->sc_err = r;
7489 7489 r = UU_WALK_ERROR;
7490 7490 goto deltemp;
7491 7491
7492 7492 case ENOSPC:
7493 7493 case -1:
7494 7494 r = UU_WALK_ERROR;
7495 7495 goto deltemp;
7496 7496
7497 7497 default:
7498 7498 bad_error("take_snap", r);
7499 7499 }
7500 7500 }
7501 7501
7502 7502 s->sc_import_state = IMPORT_PREVIOUS;
7503 7503
7504 7504 /*
7505 7505 * Upgrade service properties, if we can find a last-import snapshot.
7506 7506 * Any will do because we don't support different service properties
7507 7507 * in different manifests, so all snaplevels of the service in all of
7508 7508 * the last-import snapshots of the instances should be the same.
7509 7509 */
7510 7510 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7511 7511 switch (scf_error()) {
7512 7512 case SCF_ERROR_CONNECTION_BROKEN:
7513 7513 goto connaborted;
7514 7514
7515 7515 case SCF_ERROR_DELETED:
7516 7516 warn(s_deleted, s->sc_fmri);
7517 7517 lcbdata->sc_err = EBUSY;
7518 7518 r = UU_WALK_ERROR;
7519 7519 goto deltemp;
7520 7520
7521 7521 case SCF_ERROR_HANDLE_MISMATCH:
7522 7522 case SCF_ERROR_NOT_BOUND:
7523 7523 case SCF_ERROR_NOT_SET:
7524 7524 default:
7525 7525 bad_error("scf_iter_service_instances", scf_error());
7526 7526 }
7527 7527 }
7528 7528
7529 7529 for (;;) {
7530 7530 r = scf_iter_next_instance(imp_iter, imp_inst);
7531 7531 if (r == -1) {
7532 7532 switch (scf_error()) {
7533 7533 case SCF_ERROR_DELETED:
7534 7534 warn(s_deleted, s->sc_fmri);
7535 7535 lcbdata->sc_err = EBUSY;
7536 7536 r = UU_WALK_ERROR;
7537 7537 goto deltemp;
7538 7538
7539 7539 case SCF_ERROR_CONNECTION_BROKEN:
7540 7540 goto connaborted;
7541 7541
7542 7542 case SCF_ERROR_NOT_BOUND:
7543 7543 case SCF_ERROR_HANDLE_MISMATCH:
7544 7544 case SCF_ERROR_INVALID_ARGUMENT:
7545 7545 case SCF_ERROR_NOT_SET:
7546 7546 default:
7547 7547 bad_error("scf_iter_next_instance",
7548 7548 scf_error());
7549 7549 }
7550 7550 }
7551 7551
7552 7552 if (r == 0) {
7553 7553 /*
7554 7554 * Didn't find any last-import snapshots. Override-
7555 7555 * import the properties. Unless one of the instances
7556 7556 * has a general/enabled property, in which case we're
7557 7557 * probably running a last-import-capable svccfg for
7558 7558 * the first time, and we should only take the
7559 7559 * last-import snapshot.
7560 7560 */
7561 7561 if (have_ge) {
7562 7562 pgroup_t *mfpg;
7563 7563 scf_callback_t mfcbdata;
7564 7564
7565 7565 li_only = 1;
7566 7566 no_refresh = 1;
7567 7567 /*
7568 7568 * Need to go ahead and import the manifestfiles
7569 7569 * pg if it exists. If the last-import snapshot
7570 7570 * upgrade code is ever removed this code can
7571 7571 * be removed as well.
7572 7572 */
7573 7573 mfpg = internal_pgroup_find(s,
7574 7574 SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
7575 7575
7576 7576 if (mfpg) {
7577 7577 mfcbdata.sc_handle = g_hndl;
7578 7578 mfcbdata.sc_parent = imp_svc;
7579 7579 mfcbdata.sc_service = 1;
7580 7580 mfcbdata.sc_flags = SCI_FORCE;
7581 7581 mfcbdata.sc_source_fmri = s->sc_fmri;
7582 7582 mfcbdata.sc_target_fmri = s->sc_fmri;
7583 7583 if (entity_pgroup_import(mfpg,
7584 7584 &mfcbdata) != UU_WALK_NEXT) {
7585 7585 warn(s_mfile_upd, s->sc_fmri);
7586 7586 r = UU_WALK_ERROR;
7587 7587 goto deltemp;
7588 7588 }
7589 7589 }
7590 7590 break;
7591 7591 }
7592 7592
7593 7593 s->sc_import_state = IMPORT_PROP_BEGUN;
7594 7594
7595 7595 cbdata.sc_handle = g_hndl;
7596 7596 cbdata.sc_parent = imp_svc;
7597 7597 cbdata.sc_service = 1;
7598 7598 cbdata.sc_flags = SCI_FORCE;
7599 7599 cbdata.sc_source_fmri = s->sc_fmri;
7600 7600 cbdata.sc_target_fmri = s->sc_fmri;
7601 7601 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7602 7602 &cbdata, UU_DEFAULT) != 0) {
7603 7603 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7604 7604 bad_error("uu_list_walk", uu_error());
7605 7605 lcbdata->sc_err = cbdata.sc_err;
7606 7606 switch (cbdata.sc_err) {
7607 7607 case ECONNABORTED:
7608 7608 goto connaborted;
7609 7609
7610 7610 case ECANCELED:
7611 7611 warn(s_deleted, s->sc_fmri);
7612 7612 lcbdata->sc_err = EBUSY;
7613 7613 break;
7614 7614
7615 7615 case EINVAL: /* caught above */
7616 7616 case EEXIST:
7617 7617 bad_error("entity_pgroup_import",
7618 7618 cbdata.sc_err);
7619 7619 }
7620 7620
7621 7621 r = UU_WALK_ERROR;
7622 7622 goto deltemp;
7623 7623 }
7624 7624
7625 7625 cbdata.sc_trans = NULL;
7626 7626 cbdata.sc_flags = 0;
7627 7627 if (uu_list_walk(s->sc_dependents,
7628 7628 lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
7629 7629 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7630 7630 bad_error("uu_list_walk", uu_error());
7631 7631 lcbdata->sc_err = cbdata.sc_err;
7632 7632 if (cbdata.sc_err == ECONNABORTED)
7633 7633 goto connaborted;
7634 7634 r = UU_WALK_ERROR;
7635 7635 goto deltemp;
7636 7636 }
7637 7637 break;
7638 7638 }
7639 7639
7640 7640 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
7641 7641 imp_snap) != 0) {
7642 7642 switch (scf_error()) {
7643 7643 case SCF_ERROR_DELETED:
7644 7644 continue;
7645 7645
7646 7646 case SCF_ERROR_NOT_FOUND:
7647 7647 break;
7648 7648
7649 7649 case SCF_ERROR_CONNECTION_BROKEN:
7650 7650 goto connaborted;
7651 7651
7652 7652 case SCF_ERROR_HANDLE_MISMATCH:
7653 7653 case SCF_ERROR_NOT_BOUND:
7654 7654 case SCF_ERROR_INVALID_ARGUMENT:
7655 7655 case SCF_ERROR_NOT_SET:
7656 7656 default:
7657 7657 bad_error("scf_instance_get_snapshot",
7658 7658 scf_error());
7659 7659 }
7660 7660
7661 7661 if (have_ge)
7662 7662 continue;
7663 7663
7664 7664 /*
7665 7665 * Check for a general/enabled property. This is how
7666 7666 * we tell whether to import if there turn out to be
7667 7667 * no last-import snapshots.
7668 7668 */
7669 7669 if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
7670 7670 imp_pg) == 0) {
7671 7671 if (scf_pg_get_property(imp_pg,
7672 7672 SCF_PROPERTY_ENABLED, imp_prop) == 0) {
7673 7673 have_ge = 1;
7674 7674 } else {
7675 7675 switch (scf_error()) {
7676 7676 case SCF_ERROR_DELETED:
7677 7677 case SCF_ERROR_NOT_FOUND:
7678 7678 continue;
7679 7679
7680 7680 case SCF_ERROR_INVALID_ARGUMENT:
7681 7681 case SCF_ERROR_HANDLE_MISMATCH:
7682 7682 case SCF_ERROR_CONNECTION_BROKEN:
7683 7683 case SCF_ERROR_NOT_BOUND:
7684 7684 case SCF_ERROR_NOT_SET:
7685 7685 default:
7686 7686 bad_error("scf_pg_get_property",
7687 7687 scf_error());
7688 7688 }
7689 7689 }
7690 7690 } else {
7691 7691 switch (scf_error()) {
7692 7692 case SCF_ERROR_DELETED:
7693 7693 case SCF_ERROR_NOT_FOUND:
7694 7694 continue;
7695 7695
7696 7696 case SCF_ERROR_CONNECTION_BROKEN:
7697 7697 goto connaborted;
7698 7698
7699 7699 case SCF_ERROR_NOT_BOUND:
7700 7700 case SCF_ERROR_NOT_SET:
7701 7701 case SCF_ERROR_INVALID_ARGUMENT:
7702 7702 case SCF_ERROR_HANDLE_MISMATCH:
7703 7703 default:
7704 7704 bad_error("scf_instance_get_pg",
7705 7705 scf_error());
7706 7706 }
7707 7707 }
7708 7708 continue;
7709 7709 }
7710 7710
7711 7711 /* find service snaplevel */
7712 7712 r = get_snaplevel(imp_snap, 1, imp_snpl);
7713 7713 switch (r) {
7714 7714 case 0:
7715 7715 break;
7716 7716
7717 7717 case ECONNABORTED:
7718 7718 goto connaborted;
7719 7719
7720 7720 case ECANCELED:
7721 7721 continue;
7722 7722
7723 7723 case ENOENT:
7724 7724 if (scf_instance_get_name(imp_inst, imp_str,
7725 7725 imp_str_sz) < 0)
7726 7726 (void) strcpy(imp_str, "?");
7727 7727 warn(badsnap, snap_lastimport, s->sc_name, imp_str);
7728 7728 lcbdata->sc_err = EBADF;
7729 7729 r = UU_WALK_ERROR;
7730 7730 goto deltemp;
7731 7731
7732 7732 default:
7733 7733 bad_error("get_snaplevel", r);
7734 7734 }
7735 7735
7736 7736 if (scf_instance_get_snapshot(imp_inst, snap_running,
7737 7737 imp_rsnap) != 0) {
7738 7738 switch (scf_error()) {
7739 7739 case SCF_ERROR_DELETED:
7740 7740 continue;
7741 7741
7742 7742 case SCF_ERROR_NOT_FOUND:
7743 7743 break;
7744 7744
7745 7745 case SCF_ERROR_CONNECTION_BROKEN:
7746 7746 goto connaborted;
7747 7747
7748 7748 case SCF_ERROR_INVALID_ARGUMENT:
7749 7749 case SCF_ERROR_HANDLE_MISMATCH:
7750 7750 case SCF_ERROR_NOT_BOUND:
7751 7751 case SCF_ERROR_NOT_SET:
7752 7752 default:
7753 7753 bad_error("scf_instance_get_snapshot",
7754 7754 scf_error());
7755 7755 }
7756 7756 running = NULL;
7757 7757 } else {
7758 7758 r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
7759 7759 switch (r) {
7760 7760 case 0:
7761 7761 running = imp_rsnpl;
7762 7762 break;
7763 7763
7764 7764 case ECONNABORTED:
7765 7765 goto connaborted;
7766 7766
7767 7767 case ECANCELED:
7768 7768 continue;
7769 7769
7770 7770 case ENOENT:
7771 7771 if (scf_instance_get_name(imp_inst, imp_str,
7772 7772 imp_str_sz) < 0)
7773 7773 (void) strcpy(imp_str, "?");
7774 7774 warn(badsnap, snap_running, s->sc_name,
7775 7775 imp_str);
7776 7776 lcbdata->sc_err = EBADF;
7777 7777 r = UU_WALK_ERROR;
7778 7778 goto deltemp;
7779 7779
7780 7780 default:
7781 7781 bad_error("get_snaplevel", r);
7782 7782 }
7783 7783 }
7784 7784
7785 7785 if (g_verbose) {
7786 7786 if (scf_instance_get_name(imp_inst, imp_str,
7787 7787 imp_str_sz) < 0)
7788 7788 (void) strcpy(imp_str, "?");
7789 7789 warn(gettext("Upgrading properties of %s according to "
7790 7790 "instance \"%s\".\n"), s->sc_fmri, imp_str);
7791 7791 }
7792 7792
7793 7793 /* upgrade service properties */
7794 7794 r = upgrade_props(imp_svc, running, imp_snpl, s);
7795 7795 if (r == 0)
7796 7796 break;
7797 7797
7798 7798 switch (r) {
7799 7799 case ECONNABORTED:
7800 7800 goto connaborted;
7801 7801
7802 7802 case ECANCELED:
7803 7803 warn(s_deleted, s->sc_fmri);
7804 7804 lcbdata->sc_err = EBUSY;
7805 7805 break;
7806 7806
7807 7807 case ENODEV:
7808 7808 if (scf_instance_get_name(imp_inst, imp_str,
7809 7809 imp_str_sz) < 0)
7810 7810 (void) strcpy(imp_str, "?");
7811 7811 warn(i_deleted, s->sc_fmri, imp_str);
7812 7812 lcbdata->sc_err = EBUSY;
7813 7813 break;
7814 7814
7815 7815 default:
7816 7816 lcbdata->sc_err = r;
7817 7817 }
7818 7818
7819 7819 r = UU_WALK_ERROR;
7820 7820 goto deltemp;
7821 7821 }
7822 7822
7823 7823 s->sc_import_state = IMPORT_PROP_DONE;
7824 7824
7825 7825 instances:
7826 7826 /* import instances */
7827 7827 cbdata.sc_handle = lcbdata->sc_handle;
7828 7828 cbdata.sc_parent = imp_svc;
7829 7829 cbdata.sc_service = 1;
7830 7830 cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7831 7831 cbdata.sc_general = NULL;
7832 7832
7833 7833 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7834 7834 lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7835 7835 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7836 7836 bad_error("uu_list_walk", uu_error());
7837 7837
7838 7838 lcbdata->sc_err = cbdata.sc_err;
7839 7839 if (cbdata.sc_err == ECONNABORTED)
7840 7840 goto connaborted;
7841 7841 r = UU_WALK_ERROR;
7842 7842 goto deltemp;
7843 7843 }
7844 7844
7845 7845 s->sc_import_state = IMPORT_COMPLETE;
7846 7846 r = UU_WALK_NEXT;
7847 7847
7848 7848 deltemp:
7849 7849 /* delete temporary service */
7850 7850 if (scf_service_delete(imp_tsvc) != 0) {
7851 7851 switch (scf_error()) {
7852 7852 case SCF_ERROR_DELETED:
7853 7853 break;
7854 7854
7855 7855 case SCF_ERROR_CONNECTION_BROKEN:
7856 7856 goto connaborted;
7857 7857
7858 7858 case SCF_ERROR_EXISTS:
7859 7859 warn(gettext(
7860 7860 "Could not delete svc:/%s (instances exist).\n"),
7861 7861 imp_tsname);
7862 7862 break;
7863 7863
7864 7864 case SCF_ERROR_NOT_SET:
7865 7865 case SCF_ERROR_NOT_BOUND:
7866 7866 default:
7867 7867 bad_error("scf_service_delete", scf_error());
7868 7868 }
7869 7869 }
7870 7870
7871 7871 return (r);
7872 7872
7873 7873 connaborted:
7874 7874 warn(gettext("Could not delete svc:/%s "
7875 7875 "(repository connection broken).\n"), imp_tsname);
7876 7876 lcbdata->sc_err = ECONNABORTED;
7877 7877 return (UU_WALK_ERROR);
7878 7878 }
7879 7879
7880 7880 static const char *
7881 7881 import_progress(int st)
7882 7882 {
7883 7883 switch (st) {
7884 7884 case 0:
7885 7885 return (gettext("not reached."));
7886 7886
7887 7887 case IMPORT_PREVIOUS:
7888 7888 return (gettext("previous snapshot taken."));
7889 7889
7890 7890 case IMPORT_PROP_BEGUN:
7891 7891 return (gettext("some properties imported."));
7892 7892
7893 7893 case IMPORT_PROP_DONE:
7894 7894 return (gettext("properties imported."));
7895 7895
7896 7896 case IMPORT_COMPLETE:
7897 7897 return (gettext("imported."));
7898 7898
7899 7899 case IMPORT_REFRESHED:
7900 7900 return (gettext("refresh requested."));
7901 7901
7902 7902 default:
7903 7903 #ifndef NDEBUG
7904 7904 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7905 7905 __FILE__, __LINE__, st);
7906 7906 #endif
7907 7907 abort();
7908 7908 /* NOTREACHED */
7909 7909 }
7910 7910 }
7911 7911
7912 7912 /*
7913 7913 * Returns
7914 7914 * 0 - success
7915 7915 * - fmri wasn't found (error printed)
7916 7916 * - entity was deleted (error printed)
7917 7917 * - backend denied access (error printed)
7918 7918 * ENOMEM - out of memory (error printed)
7919 7919 * ECONNABORTED - repository connection broken (error printed)
7920 7920 * EPERM - permission denied (error printed)
7921 7921 * -1 - unknown libscf error (error printed)
7922 7922 */
7923 7923 static int
7924 7924 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7925 7925 {
7926 7926 scf_error_t serr;
7927 7927 void *ent;
7928 7928 int issvc;
7929 7929 int r;
7930 7930
7931 7931 const char *deleted = gettext("Could not refresh %s (deleted).\n");
7932 7932 const char *dpt_deleted = gettext("Could not refresh %s "
7933 7933 "(dependent \"%s\" of %s) (deleted).\n");
7934 7934
7935 7935 serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7936 7936 switch (serr) {
7937 7937 case SCF_ERROR_NONE:
7938 7938 break;
7939 7939
7940 7940 case SCF_ERROR_NO_MEMORY:
7941 7941 if (name == NULL)
7942 7942 warn(gettext("Could not refresh %s (out of memory).\n"),
7943 7943 fmri);
7944 7944 else
7945 7945 warn(gettext("Could not refresh %s "
7946 7946 "(dependent \"%s\" of %s) (out of memory).\n"),
7947 7947 fmri, name, d_fmri);
7948 7948 return (ENOMEM);
7949 7949
7950 7950 case SCF_ERROR_NOT_FOUND:
7951 7951 if (name == NULL)
7952 7952 warn(deleted, fmri);
7953 7953 else
7954 7954 warn(dpt_deleted, fmri, name, d_fmri);
7955 7955 return (0);
7956 7956
7957 7957 case SCF_ERROR_INVALID_ARGUMENT:
7958 7958 case SCF_ERROR_CONSTRAINT_VIOLATED:
7959 7959 default:
7960 7960 bad_error("fmri_to_entity", serr);
7961 7961 }
7962 7962
7963 7963 r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7964 7964 switch (r) {
7965 7965 case 0:
7966 7966 break;
7967 7967
7968 7968 case ECONNABORTED:
7969 7969 if (name != NULL)
7970 7970 warn(gettext("Could not refresh %s "
7971 7971 "(dependent \"%s\" of %s) "
7972 7972 "(repository connection broken).\n"), fmri, name,
7973 7973 d_fmri);
7974 7974 return (r);
7975 7975
7976 7976 case ECANCELED:
7977 7977 if (name == NULL)
7978 7978 warn(deleted, fmri);
7979 7979 else
7980 7980 warn(dpt_deleted, fmri, name, d_fmri);
7981 7981 return (0);
7982 7982
7983 7983 case EACCES:
7984 7984 if (!g_verbose)
7985 7985 return (0);
7986 7986 if (name == NULL)
7987 7987 warn(gettext("Could not refresh %s "
7988 7988 "(backend access denied).\n"), fmri);
7989 7989 else
7990 7990 warn(gettext("Could not refresh %s "
7991 7991 "(dependent \"%s\" of %s) "
7992 7992 "(backend access denied).\n"), fmri, name, d_fmri);
7993 7993 return (0);
7994 7994
7995 7995 case EPERM:
7996 7996 if (name == NULL)
7997 7997 warn(gettext("Could not refresh %s "
7998 7998 "(permission denied).\n"), fmri);
7999 7999 else
8000 8000 warn(gettext("Could not refresh %s "
8001 8001 "(dependent \"%s\" of %s) "
8002 8002 "(permission denied).\n"), fmri, name, d_fmri);
8003 8003 return (r);
8004 8004
8005 8005 case ENOSPC:
8006 8006 if (name == NULL)
8007 8007 warn(gettext("Could not refresh %s "
8008 8008 "(repository server out of resources).\n"),
8009 8009 fmri);
8010 8010 else
8011 8011 warn(gettext("Could not refresh %s "
8012 8012 "(dependent \"%s\" of %s) "
8013 8013 "(repository server out of resources).\n"),
8014 8014 fmri, name, d_fmri);
8015 8015 return (r);
8016 8016
8017 8017 case -1:
8018 8018 scfwarn();
8019 8019 return (r);
8020 8020
8021 8021 default:
8022 8022 bad_error("refresh_entity", r);
8023 8023 }
8024 8024
8025 8025 if (issvc)
8026 8026 scf_service_destroy(ent);
8027 8027 else
8028 8028 scf_instance_destroy(ent);
8029 8029
8030 8030 return (0);
8031 8031 }
8032 8032
8033 8033 static int
8034 8034 alloc_imp_globals()
8035 8035 {
8036 8036 int r;
8037 8037
8038 8038 const char * const emsg_nomem = gettext("Out of memory.\n");
8039 8039 const char * const emsg_nores =
8040 8040 gettext("svc.configd is out of resources.\n");
8041 8041
8042 8042 imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
8043 8043 max_scf_name_len : max_scf_fmri_len) + 1;
8044 8044
8045 8045 if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
8046 8046 (imp_svc = scf_service_create(g_hndl)) == NULL ||
8047 8047 (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
8048 8048 (imp_inst = scf_instance_create(g_hndl)) == NULL ||
8049 8049 (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
8050 8050 (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
8051 8051 (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
8052 8052 (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
8053 8053 (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
8054 8054 (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8055 8055 (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
8056 8056 (imp_pg = scf_pg_create(g_hndl)) == NULL ||
8057 8057 (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
8058 8058 (imp_prop = scf_property_create(g_hndl)) == NULL ||
8059 8059 (imp_iter = scf_iter_create(g_hndl)) == NULL ||
8060 8060 (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
8061 8061 (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
8062 8062 (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
8063 8063 (imp_str = malloc(imp_str_sz)) == NULL ||
8064 8064 (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
8065 8065 (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
8066 8066 (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
8067 8067 (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
8068 8068 (ud_inst = scf_instance_create(g_hndl)) == NULL ||
8069 8069 (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8070 8070 (ud_pg = scf_pg_create(g_hndl)) == NULL ||
8071 8071 (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
8072 8072 (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
8073 8073 (ud_prop = scf_property_create(g_hndl)) == NULL ||
8074 8074 (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
8075 8075 (ud_val = scf_value_create(g_hndl)) == NULL ||
8076 8076 (ud_iter = scf_iter_create(g_hndl)) == NULL ||
8077 8077 (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
8078 8078 (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
8079 8079 (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
8080 8080 (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
8081 8081 (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
8082 8082 if (scf_error() == SCF_ERROR_NO_RESOURCES)
8083 8083 warn(emsg_nores);
8084 8084 else
8085 8085 warn(emsg_nomem);
8086 8086
8087 8087 return (-1);
8088 8088 }
8089 8089
8090 8090 r = load_init();
8091 8091 switch (r) {
8092 8092 case 0:
8093 8093 break;
8094 8094
8095 8095 case ENOMEM:
8096 8096 warn(emsg_nomem);
8097 8097 return (-1);
8098 8098
8099 8099 default:
8100 8100 bad_error("load_init", r);
8101 8101 }
8102 8102
8103 8103 return (0);
8104 8104 }
8105 8105
8106 8106 static void
8107 8107 free_imp_globals()
8108 8108 {
8109 8109 pgroup_t *old_dpt;
8110 8110 void *cookie;
8111 8111
8112 8112 load_fini();
8113 8113
8114 8114 free(ud_ctarg);
8115 8115 free(ud_oldtarg);
8116 8116 free(ud_name);
8117 8117 ud_ctarg = ud_oldtarg = ud_name = NULL;
8118 8118
8119 8119 scf_transaction_destroy(ud_tx);
8120 8120 ud_tx = NULL;
8121 8121 scf_iter_destroy(ud_iter);
8122 8122 scf_iter_destroy(ud_iter2);
8123 8123 ud_iter = ud_iter2 = NULL;
8124 8124 scf_value_destroy(ud_val);
8125 8125 ud_val = NULL;
8126 8126 scf_property_destroy(ud_prop);
8127 8127 scf_property_destroy(ud_dpt_prop);
8128 8128 ud_prop = ud_dpt_prop = NULL;
8129 8129 scf_pg_destroy(ud_pg);
8130 8130 scf_pg_destroy(ud_cur_depts_pg);
8131 8131 scf_pg_destroy(ud_run_dpts_pg);
8132 8132 ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
8133 8133 scf_snaplevel_destroy(ud_snpl);
8134 8134 ud_snpl = NULL;
8135 8135 scf_instance_destroy(ud_inst);
8136 8136 ud_inst = NULL;
8137 8137
8138 8138 free(imp_str);
8139 8139 free(imp_tsname);
8140 8140 free(imp_fe1);
8141 8141 free(imp_fe2);
8142 8142 imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
8143 8143
8144 8144 cookie = NULL;
8145 8145 while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
8146 8146 NULL) {
8147 8147 free((char *)old_dpt->sc_pgroup_name);
8148 8148 free((char *)old_dpt->sc_pgroup_fmri);
8149 8149 internal_pgroup_free(old_dpt);
8150 8150 }
8151 8151 uu_list_destroy(imp_deleted_dpts);
8152 8152
8153 8153 scf_transaction_destroy(imp_tx);
8154 8154 imp_tx = NULL;
8155 8155 scf_iter_destroy(imp_iter);
8156 8156 scf_iter_destroy(imp_rpg_iter);
8157 8157 scf_iter_destroy(imp_up_iter);
8158 8158 imp_iter = imp_rpg_iter = imp_up_iter = NULL;
8159 8159 scf_property_destroy(imp_prop);
8160 8160 imp_prop = NULL;
8161 8161 scf_pg_destroy(imp_pg);
8162 8162 scf_pg_destroy(imp_pg2);
8163 8163 imp_pg = imp_pg2 = NULL;
8164 8164 scf_snaplevel_destroy(imp_snpl);
8165 8165 scf_snaplevel_destroy(imp_rsnpl);
8166 8166 imp_snpl = imp_rsnpl = NULL;
8167 8167 scf_snapshot_destroy(imp_snap);
8168 8168 scf_snapshot_destroy(imp_lisnap);
8169 8169 scf_snapshot_destroy(imp_tlisnap);
8170 8170 scf_snapshot_destroy(imp_rsnap);
8171 8171 imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
8172 8172 scf_instance_destroy(imp_inst);
8173 8173 scf_instance_destroy(imp_tinst);
8174 8174 imp_inst = imp_tinst = NULL;
8175 8175 scf_service_destroy(imp_svc);
8176 8176 scf_service_destroy(imp_tsvc);
8177 8177 imp_svc = imp_tsvc = NULL;
8178 8178 scf_scope_destroy(imp_scope);
8179 8179 imp_scope = NULL;
8180 8180
8181 8181 load_fini();
8182 8182 }
8183 8183
8184 8184 int
8185 8185 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
8186 8186 {
8187 8187 scf_callback_t cbdata;
8188 8188 int result = 0;
8189 8189 entity_t *svc, *inst;
8190 8190 uu_list_t *insts;
8191 8191 int r;
8192 8192 pgroup_t *old_dpt;
8193 8193 int annotation_set = 0;
8194 8194
8195 8195 const char * const emsg_nomem = gettext("Out of memory.\n");
8196 8196 const char * const emsg_nores =
8197 8197 gettext("svc.configd is out of resources.\n");
8198 8198
8199 8199 lscf_prep_hndl();
8200 8200
8201 8201 if (alloc_imp_globals())
8202 8202 goto out;
8203 8203
8204 8204 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
8205 8205 switch (scf_error()) {
8206 8206 case SCF_ERROR_CONNECTION_BROKEN:
8207 8207 warn(gettext("Repository connection broken.\n"));
8208 8208 repository_teardown();
8209 8209 result = -1;
8210 8210 goto out;
8211 8211
8212 8212 case SCF_ERROR_NOT_FOUND:
8213 8213 case SCF_ERROR_INVALID_ARGUMENT:
8214 8214 case SCF_ERROR_NOT_BOUND:
8215 8215 case SCF_ERROR_HANDLE_MISMATCH:
8216 8216 default:
8217 8217 bad_error("scf_handle_get_scope", scf_error());
8218 8218 }
8219 8219 }
8220 8220
8221 8221 /* Set up the auditing annotation. */
8222 8222 if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
8223 8223 annotation_set = 1;
8224 8224 } else {
8225 8225 switch (scf_error()) {
8226 8226 case SCF_ERROR_CONNECTION_BROKEN:
8227 8227 warn(gettext("Repository connection broken.\n"));
8228 8228 repository_teardown();
8229 8229 result = -1;
8230 8230 goto out;
8231 8231
8232 8232 case SCF_ERROR_INVALID_ARGUMENT:
8233 8233 case SCF_ERROR_NOT_BOUND:
8234 8234 case SCF_ERROR_NO_RESOURCES:
8235 8235 case SCF_ERROR_INTERNAL:
8236 8236 bad_error("_scf_set_annotation", scf_error());
8237 8237 /* NOTREACHED */
8238 8238
8239 8239 default:
8240 8240 /*
8241 8241 * Do not terminate import because of inability to
8242 8242 * generate annotation audit event.
8243 8243 */
8244 8244 warn(gettext("_scf_set_annotation() unexpectedly "
8245 8245 "failed with return code of %d\n"), scf_error());
8246 8246 break;
8247 8247 }
8248 8248 }
8249 8249
8250 8250 /*
8251 8251 * Clear the sc_import_state's of all services & instances so we can
8252 8252 * report how far we got if we fail.
8253 8253 */
8254 8254 for (svc = uu_list_first(bndl->sc_bundle_services);
8255 8255 svc != NULL;
8256 8256 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8257 8257 svc->sc_import_state = 0;
8258 8258
8259 8259 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
8260 8260 clear_int, (void *)offsetof(entity_t, sc_import_state),
8261 8261 UU_DEFAULT) != 0)
8262 8262 bad_error("uu_list_walk", uu_error());
8263 8263 }
8264 8264
8265 8265 cbdata.sc_handle = g_hndl;
8266 8266 cbdata.sc_parent = imp_scope;
8267 8267 cbdata.sc_flags = flags;
8268 8268 cbdata.sc_general = NULL;
8269 8269
8270 8270 if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
8271 8271 &cbdata, UU_DEFAULT) == 0) {
8272 8272 char *eptr;
8273 8273 /* Success. Refresh everything. */
8274 8274
8275 8275 if (flags & SCI_NOREFRESH || no_refresh) {
8276 8276 no_refresh = 0;
8277 8277 result = 0;
8278 8278 goto out;
8279 8279 }
8280 8280
8281 8281 for (svc = uu_list_first(bndl->sc_bundle_services);
8282 8282 svc != NULL;
8283 8283 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8284 8284 pgroup_t *dpt;
8285 8285
8286 8286 insts = svc->sc_u.sc_service.sc_service_instances;
8287 8287
8288 8288 for (inst = uu_list_first(insts);
8289 8289 inst != NULL;
8290 8290 inst = uu_list_next(insts, inst)) {
8291 8291 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
8292 8292 switch (r) {
8293 8293 case 0:
8294 8294 break;
8295 8295
8296 8296 case ENOMEM:
8297 8297 case ECONNABORTED:
8298 8298 case EPERM:
8299 8299 case -1:
8300 8300 goto progress;
8301 8301
8302 8302 default:
8303 8303 bad_error("imp_refresh_fmri", r);
8304 8304 }
8305 8305
8306 8306 inst->sc_import_state = IMPORT_REFRESHED;
8307 8307
8308 8308 for (dpt = uu_list_first(inst->sc_dependents);
8309 8309 dpt != NULL;
8310 8310 dpt = uu_list_next(inst->sc_dependents,
8311 8311 dpt))
8312 8312 if (imp_refresh_fmri(
8313 8313 dpt->sc_pgroup_fmri,
8314 8314 dpt->sc_pgroup_name,
8315 8315 inst->sc_fmri) != 0)
8316 8316 goto progress;
8317 8317 }
8318 8318
8319 8319 for (dpt = uu_list_first(svc->sc_dependents);
8320 8320 dpt != NULL;
8321 8321 dpt = uu_list_next(svc->sc_dependents, dpt))
8322 8322 if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
8323 8323 dpt->sc_pgroup_name, svc->sc_fmri) != 0)
8324 8324 goto progress;
8325 8325 }
8326 8326
8327 8327 for (old_dpt = uu_list_first(imp_deleted_dpts);
8328 8328 old_dpt != NULL;
8329 8329 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
8330 8330 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8331 8331 old_dpt->sc_pgroup_name,
8332 8332 old_dpt->sc_parent->sc_fmri) != 0)
8333 8333 goto progress;
8334 8334
8335 8335 result = 0;
8336 8336
8337 8337 /*
8338 8338 * This snippet of code assumes that we are running svccfg as we
8339 8339 * normally do -- witih svc.startd running. Of course, that is
8340 8340 * not actually the case all the time because we also use a
8341 8341 * varient of svc.configd and svccfg which are only meant to
8342 8342 * run during the build process. During this time we have no
8343 8343 * svc.startd, so this check would hang the build process.
8344 8344 *
8345 8345 * However, we've also given other consolidations, a bit of a
8346 8346 * means to tie themselves into a knot. They're not properly
8347 8347 * using the native build equivalents, but they've been getting
8348 8348 * away with it anyways. Therefore, if we've found that
8349 8349 * SVCCFG_REPOSITORY is set indicating that a separate configd
8350 8350 * should be spun up, then we have to assume it's not using a
8351 8351 * startd and we should not do this check.
8352 8352 */
8353 8353 #ifndef NATIVE_BUILD
8354 8354 /*
8355 8355 * Verify that the restarter group is preset
8356 8356 */
8357 8357 eptr = getenv("SVCCFG_REPOSITORY");
8358 8358 for (svc = uu_list_first(bndl->sc_bundle_services);
8359 8359 svc != NULL && eptr == NULL;
8360 8360 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8361 8361
8362 8362 insts = svc->sc_u.sc_service.sc_service_instances;
8363 8363
8364 8364 for (inst = uu_list_first(insts);
8365 8365 inst != NULL;
8366 8366 inst = uu_list_next(insts, inst)) {
8367 8367 if (lscf_instance_verify(imp_scope, svc,
8368 8368 inst) != 0)
8369 8369 goto progress;
8370 8370 }
8371 8371 }
8372 8372 #endif
8373 8373 goto out;
8374 8374
8375 8375 }
8376 8376
8377 8377 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8378 8378 bad_error("uu_list_walk", uu_error());
8379 8379
8380 8380 printerr:
8381 8381 /* If the error hasn't been printed yet, do so here. */
8382 8382 switch (cbdata.sc_err) {
8383 8383 case ECONNABORTED:
8384 8384 warn(gettext("Repository connection broken.\n"));
8385 8385 break;
8386 8386
8387 8387 case ENOMEM:
8388 8388 warn(emsg_nomem);
8389 8389 break;
8390 8390
8391 8391 case ENOSPC:
8392 8392 warn(emsg_nores);
8393 8393 break;
8394 8394
8395 8395 case EROFS:
8396 8396 warn(gettext("Repository is read-only.\n"));
8397 8397 break;
8398 8398
8399 8399 case EACCES:
8400 8400 warn(gettext("Repository backend denied access.\n"));
8401 8401 break;
8402 8402
8403 8403 case EPERM:
8404 8404 case EINVAL:
8405 8405 case EEXIST:
8406 8406 case EBUSY:
8407 8407 case EBADF:
8408 8408 case -1:
8409 8409 break;
8410 8410
8411 8411 default:
8412 8412 bad_error("lscf_service_import", cbdata.sc_err);
8413 8413 }
8414 8414
8415 8415 progress:
8416 8416 warn(gettext("Import of %s failed. Progress:\n"), filename);
8417 8417
8418 8418 for (svc = uu_list_first(bndl->sc_bundle_services);
8419 8419 svc != NULL;
8420 8420 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8421 8421 insts = svc->sc_u.sc_service.sc_service_instances;
8422 8422
8423 8423 warn(gettext(" Service \"%s\": %s\n"), svc->sc_name,
8424 8424 import_progress(svc->sc_import_state));
8425 8425
8426 8426 for (inst = uu_list_first(insts);
8427 8427 inst != NULL;
8428 8428 inst = uu_list_next(insts, inst))
8429 8429 warn(gettext(" Instance \"%s\": %s\n"),
8430 8430 inst->sc_name,
8431 8431 import_progress(inst->sc_import_state));
8432 8432 }
8433 8433
8434 8434 if (cbdata.sc_err == ECONNABORTED)
8435 8435 repository_teardown();
8436 8436
8437 8437
8438 8438 result = -1;
8439 8439
8440 8440 out:
8441 8441 if (annotation_set != 0) {
8442 8442 /* Turn off annotation. It is no longer needed. */
8443 8443 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8444 8444 }
8445 8445
8446 8446 free_imp_globals();
8447 8447
8448 8448 return (result);
8449 8449 }
8450 8450
8451 8451 /*
8452 8452 * _lscf_import_err() summarize the error handling returned by
8453 8453 * lscf_import_{instance | service}_pgs
8454 8454 * Return values are:
8455 8455 * IMPORT_NEXT
8456 8456 * IMPORT_OUT
8457 8457 * IMPORT_BAD
8458 8458 */
8459 8459
8460 8460 #define IMPORT_BAD -1
8461 8461 #define IMPORT_NEXT 0
8462 8462 #define IMPORT_OUT 1
8463 8463
8464 8464 static int
8465 8465 _lscf_import_err(int err, const char *fmri)
8466 8466 {
8467 8467 switch (err) {
8468 8468 case 0:
8469 8469 if (g_verbose)
8470 8470 warn(gettext("%s updated.\n"), fmri);
8471 8471 return (IMPORT_NEXT);
8472 8472
8473 8473 case ECONNABORTED:
8474 8474 warn(gettext("Could not update %s "
8475 8475 "(repository connection broken).\n"), fmri);
8476 8476 return (IMPORT_OUT);
8477 8477
8478 8478 case ENOMEM:
8479 8479 warn(gettext("Could not update %s (out of memory).\n"), fmri);
8480 8480 return (IMPORT_OUT);
8481 8481
8482 8482 case ENOSPC:
8483 8483 warn(gettext("Could not update %s "
8484 8484 "(repository server out of resources).\n"), fmri);
8485 8485 return (IMPORT_OUT);
8486 8486
8487 8487 case ECANCELED:
8488 8488 warn(gettext(
8489 8489 "Could not update %s (deleted).\n"), fmri);
8490 8490 return (IMPORT_NEXT);
8491 8491
8492 8492 case EPERM:
8493 8493 case EINVAL:
8494 8494 case EBUSY:
8495 8495 return (IMPORT_NEXT);
8496 8496
8497 8497 case EROFS:
8498 8498 warn(gettext("Could not update %s (repository read-only).\n"),
8499 8499 fmri);
8500 8500 return (IMPORT_OUT);
8501 8501
8502 8502 case EACCES:
8503 8503 warn(gettext("Could not update %s "
8504 8504 "(backend access denied).\n"), fmri);
8505 8505 return (IMPORT_NEXT);
8506 8506
8507 8507 case EEXIST:
8508 8508 default:
8509 8509 return (IMPORT_BAD);
8510 8510 }
8511 8511
8512 8512 /*NOTREACHED*/
8513 8513 }
8514 8514
8515 8515 /*
8516 8516 * The global imp_svc and imp_inst should be set by the caller in the
8517 8517 * check to make sure the service and instance exist that the apply is
8518 8518 * working on.
8519 8519 */
8520 8520 static int
8521 8521 lscf_dependent_apply(void *dpg, void *e)
8522 8522 {
8523 8523 scf_callback_t cb;
8524 8524 pgroup_t *dpt_pgroup = dpg;
8525 8525 pgroup_t *deldpt;
8526 8526 entity_t *ent = e;
8527 8527 int tissvc;
8528 8528 void *sc_ent, *tent;
8529 8529 scf_error_t serr;
8530 8530 int r;
8531 8531
8532 8532 const char * const dependents = "dependents";
8533 8533 const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT);
8534 8534
8535 8535 if (issvc)
8536 8536 sc_ent = imp_svc;
8537 8537 else
8538 8538 sc_ent = imp_inst;
8539 8539
8540 8540 if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg,
8541 8541 imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 ||
8542 8542 scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name,
8543 8543 imp_prop) != 0) {
8544 8544 switch (scf_error()) {
8545 8545 case SCF_ERROR_NOT_FOUND:
8546 8546 case SCF_ERROR_DELETED:
8547 8547 break;
8548 8548
8549 8549 case SCF_ERROR_CONNECTION_BROKEN:
8550 8550 case SCF_ERROR_NOT_SET:
8551 8551 case SCF_ERROR_INVALID_ARGUMENT:
8552 8552 case SCF_ERROR_HANDLE_MISMATCH:
8553 8553 case SCF_ERROR_NOT_BOUND:
8554 8554 default:
8555 8555 bad_error("entity_get_pg", scf_error());
8556 8556 }
8557 8557 } else {
8558 8558 /*
8559 8559 * Found the dependents/<wip dep> so check to
8560 8560 * see if the service is different. If so
8561 8561 * store the service for later refresh, and
8562 8562 * delete the wip dependency from the service
8563 8563 */
8564 8564 if (scf_property_get_value(imp_prop, ud_val) != 0) {
8565 8565 switch (scf_error()) {
8566 8566 case SCF_ERROR_DELETED:
8567 8567 break;
8568 8568
8569 8569 case SCF_ERROR_CONNECTION_BROKEN:
8570 8570 case SCF_ERROR_NOT_SET:
8571 8571 case SCF_ERROR_INVALID_ARGUMENT:
8572 8572 case SCF_ERROR_HANDLE_MISMATCH:
8573 8573 case SCF_ERROR_NOT_BOUND:
8574 8574 default:
8575 8575 bad_error("scf_property_get_value",
8576 8576 scf_error());
8577 8577 }
8578 8578 }
8579 8579
8580 8580 if (scf_value_get_as_string(ud_val, ud_oldtarg,
8581 8581 max_scf_value_len + 1) < 0)
8582 8582 bad_error("scf_value_get_as_string", scf_error());
8583 8583
8584 8584 r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
8585 8585 switch (r) {
8586 8586 case 1:
8587 8587 break;
8588 8588 case 0:
8589 8589 if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent,
8590 8590 &tissvc)) != SCF_ERROR_NONE) {
8591 8591 if (serr == SCF_ERROR_NOT_FOUND) {
8592 8592 break;
8593 8593 } else {
8594 8594 bad_error("fmri_to_entity", serr);
8595 8595 }
8596 8596 }
8597 8597
8598 8598 if (entity_get_pg(tent, tissvc,
8599 8599 dpt_pgroup->sc_pgroup_name, imp_pg) != 0) {
8600 8600 serr = scf_error();
8601 8601 if (serr == SCF_ERROR_NOT_FOUND ||
8602 8602 serr == SCF_ERROR_DELETED) {
8603 8603 break;
8604 8604 } else {
8605 8605 bad_error("entity_get_pg", scf_error());
8606 8606 }
8607 8607 }
8608 8608
8609 8609 if (scf_pg_delete(imp_pg) != 0) {
8610 8610 serr = scf_error();
8611 8611 if (serr == SCF_ERROR_NOT_FOUND ||
8612 8612 serr == SCF_ERROR_DELETED) {
8613 8613 break;
8614 8614 } else {
8615 8615 bad_error("scf_pg_delete", scf_error());
8616 8616 }
8617 8617 }
8618 8618
8619 8619 deldpt = internal_pgroup_new();
8620 8620 if (deldpt == NULL)
8621 8621 return (ENOMEM);
8622 8622 deldpt->sc_pgroup_name =
8623 8623 strdup(dpt_pgroup->sc_pgroup_name);
8624 8624 deldpt->sc_pgroup_fmri = strdup(ud_oldtarg);
8625 8625 if (deldpt->sc_pgroup_name == NULL ||
8626 8626 deldpt->sc_pgroup_fmri == NULL)
8627 8627 return (ENOMEM);
8628 8628 deldpt->sc_parent = (entity_t *)ent;
8629 8629 if (uu_list_insert_after(imp_deleted_dpts, NULL,
8630 8630 deldpt) != 0)
8631 8631 uu_die(gettext("libuutil error: %s\n"),
8632 8632 uu_strerror(uu_error()));
8633 8633
8634 8634 break;
8635 8635 default:
8636 8636 bad_error("fmri_equal", r);
8637 8637 }
8638 8638 }
8639 8639
8640 8640 cb.sc_handle = g_hndl;
8641 8641 cb.sc_parent = ent;
8642 8642 cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT;
8643 8643 cb.sc_source_fmri = ent->sc_fmri;
8644 8644 cb.sc_target_fmri = ent->sc_fmri;
8645 8645 cb.sc_trans = NULL;
8646 8646 cb.sc_flags = SCI_FORCE;
8647 8647
8648 8648 if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT)
8649 8649 return (UU_WALK_ERROR);
8650 8650
8651 8651 r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL);
8652 8652 switch (r) {
8653 8653 case 0:
8654 8654 break;
8655 8655
8656 8656 case ENOMEM:
8657 8657 case ECONNABORTED:
8658 8658 case EPERM:
8659 8659 case -1:
8660 8660 warn(gettext("Unable to refresh \"%s\"\n"),
8661 8661 dpt_pgroup->sc_pgroup_fmri);
8662 8662 return (UU_WALK_ERROR);
8663 8663
8664 8664 default:
8665 8665 bad_error("imp_refresh_fmri", r);
8666 8666 }
8667 8667
8668 8668 return (UU_WALK_NEXT);
8669 8669 }
8670 8670
8671 8671 /*
8672 8672 * Returns
8673 8673 * 0 - success
8674 8674 * -1 - lscf_import_instance_pgs() failed.
8675 8675 */
8676 8676 int
8677 8677 lscf_bundle_apply(bundle_t *bndl, const char *file)
8678 8678 {
8679 8679 pgroup_t *old_dpt;
8680 8680 entity_t *svc, *inst;
8681 8681 int annotation_set = 0;
8682 8682 int ret = 0;
8683 8683 int r = 0;
8684 8684
8685 8685 lscf_prep_hndl();
8686 8686
8687 8687 if ((ret = alloc_imp_globals()))
8688 8688 goto out;
8689 8689
8690 8690 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0)
8691 8691 scfdie();
8692 8692
8693 8693 /*
8694 8694 * Set the strings to be used for the security audit annotation
8695 8695 * event.
8696 8696 */
8697 8697 if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
8698 8698 annotation_set = 1;
8699 8699 } else {
8700 8700 switch (scf_error()) {
8701 8701 case SCF_ERROR_CONNECTION_BROKEN:
8702 8702 warn(gettext("Repository connection broken.\n"));
8703 8703 goto out;
8704 8704
8705 8705 case SCF_ERROR_INVALID_ARGUMENT:
8706 8706 case SCF_ERROR_NOT_BOUND:
8707 8707 case SCF_ERROR_NO_RESOURCES:
8708 8708 case SCF_ERROR_INTERNAL:
8709 8709 bad_error("_scf_set_annotation", scf_error());
8710 8710 /* NOTREACHED */
8711 8711
8712 8712 default:
8713 8713 /*
8714 8714 * Do not abort apply operation because of
8715 8715 * inability to create annotation audit event.
8716 8716 */
8717 8717 warn(gettext("_scf_set_annotation() unexpectedly "
8718 8718 "failed with return code of %d\n"), scf_error());
8719 8719 break;
8720 8720 }
8721 8721 }
8722 8722
8723 8723 for (svc = uu_list_first(bndl->sc_bundle_services);
8724 8724 svc != NULL;
8725 8725 svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8726 8726 int refresh = 0;
8727 8727
8728 8728 if (scf_scope_get_service(imp_scope, svc->sc_name,
8729 8729 imp_svc) != 0) {
8730 8730 switch (scf_error()) {
8731 8731 case SCF_ERROR_NOT_FOUND:
8732 8732 if (g_verbose)
8733 8733 warn(gettext("Ignoring nonexistent "
8734 8734 "service %s.\n"), svc->sc_name);
8735 8735 continue;
8736 8736
8737 8737 default:
8738 8738 scfdie();
8739 8739 }
8740 8740 }
8741 8741
8742 8742 /*
8743 8743 * If there were missing types in the profile, then need to
8744 8744 * attempt to find the types.
8745 8745 */
8746 8746 if (svc->sc_miss_type) {
8747 8747 if (uu_list_numnodes(svc->sc_pgroups) &&
8748 8748 uu_list_walk(svc->sc_pgroups, find_current_pg_type,
8749 8749 svc, UU_DEFAULT) != 0) {
8750 8750 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8751 8751 bad_error("uu_list_walk", uu_error());
8752 8752
8753 8753 ret = -1;
8754 8754 continue;
8755 8755 }
8756 8756
8757 8757 for (inst = uu_list_first(
8758 8758 svc->sc_u.sc_service.sc_service_instances);
8759 8759 inst != NULL;
8760 8760 inst = uu_list_next(
8761 8761 svc->sc_u.sc_service.sc_service_instances, inst)) {
8762 8762 /*
8763 8763 * If the instance doesn't exist just
8764 8764 * skip to the next instance and let the
8765 8765 * import note the missing instance.
8766 8766 */
8767 8767 if (scf_service_get_instance(imp_svc,
8768 8768 inst->sc_name, imp_inst) != 0)
8769 8769 continue;
8770 8770
8771 8771 if (uu_list_walk(inst->sc_pgroups,
8772 8772 find_current_pg_type, inst,
8773 8773 UU_DEFAULT) != 0) {
8774 8774 if (uu_error() !=
8775 8775 UU_ERROR_CALLBACK_FAILED)
8776 8776 bad_error("uu_list_walk",
8777 8777 uu_error());
8778 8778
8779 8779 ret = -1;
8780 8780 inst->sc_miss_type = B_TRUE;
8781 8781 }
8782 8782 }
8783 8783 }
8784 8784
8785 8785 /*
8786 8786 * if we have pgs in the profile, we need to refresh ALL
8787 8787 * instances of the service
8788 8788 */
8789 8789 if (uu_list_numnodes(svc->sc_pgroups) != 0) {
8790 8790 refresh = 1;
8791 8791 r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc,
8792 8792 SCI_FORCE | SCI_KEEP);
8793 8793 switch (_lscf_import_err(r, svc->sc_fmri)) {
8794 8794 case IMPORT_NEXT:
8795 8795 break;
8796 8796
8797 8797 case IMPORT_OUT:
8798 8798 goto out;
8799 8799
8800 8800 case IMPORT_BAD:
8801 8801 default:
8802 8802 bad_error("lscf_import_service_pgs", r);
8803 8803 }
8804 8804 }
8805 8805
8806 8806 if (uu_list_numnodes(svc->sc_dependents) != 0) {
8807 8807 uu_list_walk(svc->sc_dependents,
8808 8808 lscf_dependent_apply, svc, UU_DEFAULT);
8809 8809 }
8810 8810
8811 8811 for (inst = uu_list_first(
8812 8812 svc->sc_u.sc_service.sc_service_instances);
8813 8813 inst != NULL;
8814 8814 inst = uu_list_next(
8815 8815 svc->sc_u.sc_service.sc_service_instances, inst)) {
8816 8816 /*
8817 8817 * This instance still has missing types
8818 8818 * so skip it.
8819 8819 */
8820 8820 if (inst->sc_miss_type) {
8821 8821 if (g_verbose)
8822 8822 warn(gettext("Ignoring instance "
8823 8823 "%s:%s with missing types\n"),
8824 8824 inst->sc_parent->sc_name,
8825 8825 inst->sc_name);
8826 8826
8827 8827 continue;
8828 8828 }
8829 8829
8830 8830 if (scf_service_get_instance(imp_svc, inst->sc_name,
8831 8831 imp_inst) != 0) {
8832 8832 switch (scf_error()) {
8833 8833 case SCF_ERROR_NOT_FOUND:
8834 8834 if (g_verbose)
8835 8835 warn(gettext("Ignoring "
8836 8836 "nonexistant instance "
8837 8837 "%s:%s.\n"),
8838 8838 inst->sc_parent->sc_name,
8839 8839 inst->sc_name);
8840 8840 continue;
8841 8841
8842 8842 default:
8843 8843 scfdie();
8844 8844 }
8845 8845 }
8846 8846
8847 8847 /*
8848 8848 * If the instance does not have a general/enabled
8849 8849 * property and no last-import snapshot then the
8850 8850 * instance is not a fully installed instance and
8851 8851 * should not have a profile applied to it.
8852 8852 *
8853 8853 * This could happen if a service/instance declares
8854 8854 * a dependent on behalf of another service/instance.
8855 8855 *
8856 8856 */
8857 8857 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
8858 8858 imp_snap) != 0) {
8859 8859 if (scf_instance_get_pg(imp_inst,
8860 8860 SCF_PG_GENERAL, imp_pg) != 0 ||
8861 8861 scf_pg_get_property(imp_pg,
8862 8862 SCF_PROPERTY_ENABLED, imp_prop) != 0) {
8863 8863 if (g_verbose)
8864 8864 warn(gettext("Ignoreing "
8865 8865 "partial instance "
8866 8866 "%s:%s.\n"),
8867 8867 inst->sc_parent->sc_name,
8868 8868 inst->sc_name);
8869 8869 continue;
8870 8870 }
8871 8871 }
8872 8872
8873 8873 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri,
8874 8874 inst, SCI_FORCE | SCI_KEEP);
8875 8875 switch (_lscf_import_err(r, inst->sc_fmri)) {
8876 8876 case IMPORT_NEXT:
8877 8877 break;
8878 8878
8879 8879 case IMPORT_OUT:
8880 8880 goto out;
8881 8881
8882 8882 case IMPORT_BAD:
8883 8883 default:
8884 8884 bad_error("lscf_import_instance_pgs", r);
8885 8885 }
8886 8886
8887 8887 if (uu_list_numnodes(inst->sc_dependents) != 0) {
8888 8888 uu_list_walk(inst->sc_dependents,
8889 8889 lscf_dependent_apply, inst, UU_DEFAULT);
8890 8890 }
8891 8891
8892 8892 /* refresh only if there is no pgs in the service */
8893 8893 if (refresh == 0)
8894 8894 (void) refresh_entity(0, imp_inst,
8895 8895 inst->sc_fmri, NULL, NULL, NULL);
8896 8896 }
8897 8897
8898 8898 if (refresh == 1) {
8899 8899 char *name_buf = safe_malloc(max_scf_name_len + 1);
8900 8900
8901 8901 (void) refresh_entity(1, imp_svc, svc->sc_name,
8902 8902 imp_inst, imp_iter, name_buf);
8903 8903 free(name_buf);
8904 8904 }
8905 8905
8906 8906 for (old_dpt = uu_list_first(imp_deleted_dpts);
8907 8907 old_dpt != NULL;
8908 8908 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) {
8909 8909 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8910 8910 old_dpt->sc_pgroup_name,
8911 8911 old_dpt->sc_parent->sc_fmri) != 0) {
8912 8912 warn(gettext("Unable to refresh \"%s\"\n"),
8913 8913 old_dpt->sc_pgroup_fmri);
8914 8914 }
8915 8915 }
8916 8916 }
8917 8917
8918 8918 out:
8919 8919 if (annotation_set) {
8920 8920 /* Remove security audit annotation strings. */
8921 8921 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8922 8922 }
8923 8923
8924 8924 free_imp_globals();
8925 8925 return (ret);
8926 8926 }
8927 8927
8928 8928
8929 8929 /*
8930 8930 * Export. These functions create and output an XML tree of a service
8931 8931 * description from the repository. This is largely the inverse of
8932 8932 * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
8933 8933 *
8934 8934 * - We must include any properties which are not represented specifically by
8935 8935 * a service manifest, e.g., properties created by an admin post-import. To
8936 8936 * do so we'll iterate through all properties and deal with each
8937 8937 * apropriately.
8938 8938 *
8939 8939 * - Children of services and instances must must be in the order set by the
8940 8940 * DTD, but we iterate over the properties in undefined order. The elements
8941 8941 * are not easily (or efficiently) sortable by name. Since there's a fixed
8942 8942 * number of classes of them, however, we'll keep the classes separate and
8943 8943 * assemble them in order.
8944 8944 */
8945 8945
8946 8946 /*
8947 8947 * Convenience function to handle xmlSetProp errors (and type casting).
8948 8948 */
8949 8949 static void
8950 8950 safe_setprop(xmlNodePtr n, const char *name, const char *val)
8951 8951 {
8952 8952 if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
8953 8953 uu_die(gettext("Could not set XML property.\n"));
8954 8954 }
8955 8955
8956 8956 /*
8957 8957 * Convenience function to set an XML attribute to the single value of an
8958 8958 * astring property. If the value happens to be the default, don't set the
8959 8959 * attribute. "dval" should be the default value supplied by the DTD, or
8960 8960 * NULL for no default.
8961 8961 */
8962 8962 static int
8963 8963 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
8964 8964 const char *name, const char *dval)
8965 8965 {
8966 8966 scf_value_t *val;
8967 8967 ssize_t len;
8968 8968 char *str;
8969 8969
8970 8970 val = scf_value_create(g_hndl);
8971 8971 if (val == NULL)
8972 8972 scfdie();
8973 8973
8974 8974 if (prop_get_val(prop, val) != 0) {
8975 8975 scf_value_destroy(val);
8976 8976 return (-1);
8977 8977 }
8978 8978
8979 8979 len = scf_value_get_as_string(val, NULL, 0);
8980 8980 if (len < 0)
8981 8981 scfdie();
8982 8982
8983 8983 str = safe_malloc(len + 1);
8984 8984
8985 8985 if (scf_value_get_as_string(val, str, len + 1) < 0)
8986 8986 scfdie();
8987 8987
8988 8988 scf_value_destroy(val);
8989 8989
8990 8990 if (dval == NULL || strcmp(str, dval) != 0)
8991 8991 safe_setprop(n, name, str);
8992 8992
8993 8993 free(str);
8994 8994
8995 8995 return (0);
8996 8996 }
8997 8997
8998 8998 /*
8999 8999 * As above, but the attribute is always set.
9000 9000 */
9001 9001 static int
9002 9002 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
9003 9003 {
9004 9004 return (set_attr_from_prop_default(prop, n, name, NULL));
9005 9005 }
9006 9006
9007 9007 /*
9008 9008 * Dump the given document onto f, with "'s replaced by ''s.
9009 9009 */
9010 9010 static int
9011 9011 write_service_bundle(xmlDocPtr doc, FILE *f)
9012 9012 {
9013 9013 xmlChar *mem;
9014 9014 int sz, i;
9015 9015
9016 9016 mem = NULL;
9017 9017 xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
9018 9018
9019 9019 if (mem == NULL) {
9020 9020 semerr(gettext("Could not dump XML tree.\n"));
9021 9021 return (-1);
9022 9022 }
9023 9023
9024 9024 /*
9025 9025 * Fortunately libxml produces " instead of ", so we can blindly
9026 9026 * replace all " with '. Cursed libxml2! Why must you #ifdef out the
9027 9027 * ' code?!
9028 9028 */
9029 9029 for (i = 0; i < sz; ++i) {
9030 9030 char c = (char)mem[i];
9031 9031
9032 9032 if (c == '"')
9033 9033 (void) fputc('\'', f);
9034 9034 else if (c == '\'')
9035 9035 (void) fwrite("'", sizeof ("'") - 1, 1, f);
9036 9036 else
9037 9037 (void) fputc(c, f);
9038 9038 }
9039 9039
9040 9040 return (0);
9041 9041 }
9042 9042
9043 9043 /*
9044 9044 * Create the DOM elements in elts necessary to (generically) represent prop
9045 9045 * (i.e., a property or propval element). If the name of the property is
9046 9046 * known, it should be passed as name_arg. Otherwise, pass NULL.
9047 9047 */
9048 9048 static void
9049 9049 export_property(scf_property_t *prop, const char *name_arg,
9050 9050 struct pg_elts *elts, int flags)
9051 9051 {
9052 9052 const char *type;
9053 9053 scf_error_t err = 0;
9054 9054 xmlNodePtr pnode, lnode;
9055 9055 char *lnname;
9056 9056 int ret;
9057 9057
9058 9058 /* name */
9059 9059 if (name_arg != NULL) {
9060 9060 (void) strcpy(exp_str, name_arg);
9061 9061 } else {
9062 9062 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
9063 9063 scfdie();
9064 9064 }
9065 9065
9066 9066 /* type */
9067 9067 type = prop_to_typestr(prop);
9068 9068 if (type == NULL)
9069 9069 uu_die(gettext("Can't export property %s: unknown type.\n"),
9070 9070 exp_str);
9071 9071
9072 9072 /* If we're exporting values, and there's just one, export it here. */
9073 9073 if (!(flags & SCE_ALL_VALUES))
9074 9074 goto empty;
9075 9075
9076 9076 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
9077 9077 xmlNodePtr n;
9078 9078
9079 9079 /* Single value, so use propval */
9080 9080 n = xmlNewNode(NULL, (xmlChar *)"propval");
9081 9081 if (n == NULL)
9082 9082 uu_die(emsg_create_xml);
9083 9083
9084 9084 safe_setprop(n, name_attr, exp_str);
9085 9085 safe_setprop(n, type_attr, type);
9086 9086
9087 9087 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9088 9088 scfdie();
9089 9089 safe_setprop(n, value_attr, exp_str);
9090 9090
9091 9091 if (elts->propvals == NULL)
9092 9092 elts->propvals = n;
9093 9093 else
9094 9094 (void) xmlAddSibling(elts->propvals, n);
9095 9095
9096 9096 return;
9097 9097 }
9098 9098
9099 9099 err = scf_error();
9100 9100
9101 9101 if (err == SCF_ERROR_PERMISSION_DENIED) {
9102 9102 semerr(emsg_permission_denied);
9103 9103 return;
9104 9104 }
9105 9105
9106 9106 if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
9107 9107 err != SCF_ERROR_NOT_FOUND &&
9108 9108 err != SCF_ERROR_PERMISSION_DENIED)
9109 9109 scfdie();
9110 9110
9111 9111 empty:
9112 9112 /* Multiple (or no) values, so use property */
9113 9113 pnode = xmlNewNode(NULL, (xmlChar *)"property");
9114 9114 if (pnode == NULL)
9115 9115 uu_die(emsg_create_xml);
9116 9116
9117 9117 safe_setprop(pnode, name_attr, exp_str);
9118 9118 safe_setprop(pnode, type_attr, type);
9119 9119
9120 9120 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
9121 9121 lnname = uu_msprintf("%s_list", type);
9122 9122 if (lnname == NULL)
9123 9123 uu_die(gettext("Could not create string"));
9124 9124
9125 9125 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
9126 9126 if (lnode == NULL)
9127 9127 uu_die(emsg_create_xml);
9128 9128
9129 9129 uu_free(lnname);
9130 9130
9131 9131 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
9132 9132 scfdie();
9133 9133
9134 9134 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
9135 9135 1) {
9136 9136 xmlNodePtr vn;
9137 9137
9138 9138 vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
9139 9139 NULL);
9140 9140 if (vn == NULL)
9141 9141 uu_die(emsg_create_xml);
9142 9142
9143 9143 if (scf_value_get_as_string(exp_val, exp_str,
9144 9144 exp_str_sz) < 0)
9145 9145 scfdie();
9146 9146 safe_setprop(vn, value_attr, exp_str);
9147 9147 }
9148 9148 if (ret != 0)
9149 9149 scfdie();
9150 9150 }
9151 9151
9152 9152 if (elts->properties == NULL)
9153 9153 elts->properties = pnode;
9154 9154 else
9155 9155 (void) xmlAddSibling(elts->properties, pnode);
9156 9156 }
9157 9157
9158 9158 /*
9159 9159 * Add a property_group element for this property group to elts.
9160 9160 */
9161 9161 static void
9162 9162 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
9163 9163 {
9164 9164 xmlNodePtr n;
9165 9165 struct pg_elts elts;
9166 9166 int ret;
9167 9167 boolean_t read_protected;
9168 9168
9169 9169 n = xmlNewNode(NULL, (xmlChar *)"property_group");
9170 9170
9171 9171 /* name */
9172 9172 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9173 9173 scfdie();
9174 9174 safe_setprop(n, name_attr, exp_str);
9175 9175
9176 9176 /* type */
9177 9177 if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
9178 9178 scfdie();
9179 9179 safe_setprop(n, type_attr, exp_str);
9180 9180
9181 9181 /* properties */
9182 9182 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9183 9183 scfdie();
9184 9184
9185 9185 (void) memset(&elts, 0, sizeof (elts));
9186 9186
9187 9187 /*
9188 9188 * If this property group is not read protected, we always want to
9189 9189 * output all the values. Otherwise, we only output the values if the
9190 9190 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
9191 9191 */
9192 9192 if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
9193 9193 scfdie();
9194 9194
9195 9195 if (!read_protected)
9196 9196 flags |= SCE_ALL_VALUES;
9197 9197
9198 9198 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9199 9199 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9200 9200 scfdie();
9201 9201
9202 9202 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9203 9203 xmlNodePtr m;
9204 9204
9205 9205 m = xmlNewNode(NULL, (xmlChar *)"stability");
9206 9206 if (m == NULL)
9207 9207 uu_die(emsg_create_xml);
9208 9208
9209 9209 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9210 9210 elts.stability = m;
9211 9211 continue;
9212 9212 }
9213 9213
9214 9214 xmlFreeNode(m);
9215 9215 }
9216 9216
9217 9217 export_property(exp_prop, NULL, &elts, flags);
9218 9218 }
9219 9219 if (ret == -1)
9220 9220 scfdie();
9221 9221
9222 9222 (void) xmlAddChild(n, elts.stability);
9223 9223 (void) xmlAddChildList(n, elts.propvals);
9224 9224 (void) xmlAddChildList(n, elts.properties);
9225 9225
9226 9226 if (eelts->property_groups == NULL)
9227 9227 eelts->property_groups = n;
9228 9228 else
9229 9229 (void) xmlAddSibling(eelts->property_groups, n);
9230 9230 }
9231 9231
9232 9232 /*
9233 9233 * Create an XML node representing the dependency described by the given
9234 9234 * property group and put it in eelts. Unless the dependency is not valid, in
9235 9235 * which case create a generic property_group element which represents it and
9236 9236 * put it in eelts.
9237 9237 */
9238 9238 static void
9239 9239 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
9240 9240 {
9241 9241 xmlNodePtr n;
9242 9242 int err = 0, ret;
9243 9243 struct pg_elts elts;
9244 9244
9245 9245 n = xmlNewNode(NULL, (xmlChar *)"dependency");
9246 9246 if (n == NULL)
9247 9247 uu_die(emsg_create_xml);
9248 9248
9249 9249 /*
9250 9250 * If the external flag is present, skip this dependency because it
9251 9251 * should have been created by another manifest.
9252 9252 */
9253 9253 if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
9254 9254 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9255 9255 prop_get_val(exp_prop, exp_val) == 0) {
9256 9256 uint8_t b;
9257 9257
9258 9258 if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
9259 9259 scfdie();
9260 9260
9261 9261 if (b)
9262 9262 return;
9263 9263 }
9264 9264 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
9265 9265 scfdie();
9266 9266
9267 9267 /* Get the required attributes. */
9268 9268
9269 9269 /* name */
9270 9270 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9271 9271 scfdie();
9272 9272 safe_setprop(n, name_attr, exp_str);
9273 9273
9274 9274 /* grouping */
9275 9275 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9276 9276 set_attr_from_prop(exp_prop, n, "grouping") != 0)
9277 9277 err = 1;
9278 9278
9279 9279 /* restart_on */
9280 9280 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9281 9281 set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9282 9282 err = 1;
9283 9283
9284 9284 /* type */
9285 9285 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9286 9286 set_attr_from_prop(exp_prop, n, type_attr) != 0)
9287 9287 err = 1;
9288 9288
9289 9289 /*
9290 9290 * entities: Not required, but if we create no children, it will be
9291 9291 * created as empty on import, so fail if it's missing.
9292 9292 */
9293 9293 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9294 9294 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
9295 9295 scf_iter_t *eiter;
9296 9296 int ret2;
9297 9297
9298 9298 eiter = scf_iter_create(g_hndl);
9299 9299 if (eiter == NULL)
9300 9300 scfdie();
9301 9301
9302 9302 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
9303 9303 scfdie();
9304 9304
9305 9305 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
9306 9306 xmlNodePtr ch;
9307 9307
9308 9308 if (scf_value_get_astring(exp_val, exp_str,
9309 9309 exp_str_sz) < 0)
9310 9310 scfdie();
9311 9311
9312 9312 /*
9313 9313 * service_fmri's must be first, so we can add them
9314 9314 * here.
9315 9315 */
9316 9316 ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
9317 9317 NULL);
9318 9318 if (ch == NULL)
9319 9319 uu_die(emsg_create_xml);
9320 9320
9321 9321 safe_setprop(ch, value_attr, exp_str);
9322 9322 }
9323 9323 if (ret2 == -1)
9324 9324 scfdie();
9325 9325
9326 9326 scf_iter_destroy(eiter);
9327 9327 } else
9328 9328 err = 1;
9329 9329
9330 9330 if (err) {
9331 9331 xmlFreeNode(n);
9332 9332
9333 9333 export_pg(pg, eelts, SCE_ALL_VALUES);
9334 9334
9335 9335 return;
9336 9336 }
9337 9337
9338 9338 /* Iterate through the properties & handle each. */
9339 9339 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9340 9340 scfdie();
9341 9341
9342 9342 (void) memset(&elts, 0, sizeof (elts));
9343 9343
9344 9344 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9345 9345 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9346 9346 scfdie();
9347 9347
9348 9348 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9349 9349 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9350 9350 strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9351 9351 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9352 9352 continue;
9353 9353 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9354 9354 xmlNodePtr m;
9355 9355
9356 9356 m = xmlNewNode(NULL, (xmlChar *)"stability");
9357 9357 if (m == NULL)
9358 9358 uu_die(emsg_create_xml);
9359 9359
9360 9360 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9361 9361 elts.stability = m;
9362 9362 continue;
9363 9363 }
9364 9364
9365 9365 xmlFreeNode(m);
9366 9366 }
9367 9367
9368 9368 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9369 9369 }
9370 9370 if (ret == -1)
9371 9371 scfdie();
9372 9372
9373 9373 (void) xmlAddChild(n, elts.stability);
9374 9374 (void) xmlAddChildList(n, elts.propvals);
9375 9375 (void) xmlAddChildList(n, elts.properties);
9376 9376
9377 9377 if (eelts->dependencies == NULL)
9378 9378 eelts->dependencies = n;
9379 9379 else
9380 9380 (void) xmlAddSibling(eelts->dependencies, n);
9381 9381 }
9382 9382
9383 9383 static xmlNodePtr
9384 9384 export_method_environment(scf_propertygroup_t *pg)
9385 9385 {
9386 9386 xmlNodePtr env;
9387 9387 int ret;
9388 9388 int children = 0;
9389 9389
9390 9390 if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
9391 9391 return (NULL);
9392 9392
9393 9393 env = xmlNewNode(NULL, (xmlChar *)"method_environment");
9394 9394 if (env == NULL)
9395 9395 uu_die(emsg_create_xml);
9396 9396
9397 9397 if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
9398 9398 scfdie();
9399 9399
9400 9400 if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
9401 9401 scfdie();
9402 9402
9403 9403 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
9404 9404 xmlNodePtr ev;
9405 9405 char *cp;
9406 9406
9407 9407 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9408 9408 scfdie();
9409 9409
9410 9410 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
9411 9411 warn(gettext("Invalid environment variable \"%s\".\n"),
9412 9412 exp_str);
9413 9413 continue;
9414 9414 } else if (strncmp(exp_str, "SMF_", 4) == 0) {
9415 9415 warn(gettext("Invalid environment variable \"%s\"; "
9416 9416 "\"SMF_\" prefix is reserved.\n"), exp_str);
9417 9417 continue;
9418 9418 }
9419 9419
9420 9420 *cp = '\0';
9421 9421 cp++;
9422 9422
9423 9423 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
9424 9424 if (ev == NULL)
9425 9425 uu_die(emsg_create_xml);
9426 9426
9427 9427 safe_setprop(ev, name_attr, exp_str);
9428 9428 safe_setprop(ev, value_attr, cp);
9429 9429 children++;
9430 9430 }
9431 9431
9432 9432 if (ret != 0)
9433 9433 scfdie();
9434 9434
9435 9435 if (children == 0) {
9436 9436 xmlFreeNode(env);
9437 9437 return (NULL);
9438 9438 }
9439 9439
9440 9440 return (env);
9441 9441 }
9442 9442
9443 9443 /*
9444 9444 * As above, but for a method property group.
9445 9445 */
9446 9446 static void
9447 9447 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
9448 9448 {
9449 9449 xmlNodePtr n, env;
9450 9450 char *str;
9451 9451 int err = 0, nonenv, ret;
9452 9452 uint8_t use_profile;
9453 9453 struct pg_elts elts;
9454 9454 xmlNodePtr ctxt = NULL;
9455 9455
9456 9456 n = xmlNewNode(NULL, (xmlChar *)"exec_method");
9457 9457
9458 9458 /* Get the required attributes. */
9459 9459
9460 9460 /* name */
9461 9461 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9462 9462 scfdie();
9463 9463 safe_setprop(n, name_attr, exp_str);
9464 9464
9465 9465 /* type */
9466 9466 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9467 9467 set_attr_from_prop(exp_prop, n, type_attr) != 0)
9468 9468 err = 1;
9469 9469
9470 9470 /* exec */
9471 9471 if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
9472 9472 set_attr_from_prop(exp_prop, n, "exec") != 0)
9473 9473 err = 1;
9474 9474
9475 9475 /* timeout */
9476 9476 if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
9477 9477 prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
9478 9478 prop_get_val(exp_prop, exp_val) == 0) {
9479 9479 uint64_t c;
9480 9480
9481 9481 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
9482 9482 scfdie();
9483 9483
9484 9484 str = uu_msprintf("%llu", c);
9485 9485 if (str == NULL)
9486 9486 uu_die(gettext("Could not create string"));
9487 9487
9488 9488 safe_setprop(n, "timeout_seconds", str);
9489 9489 free(str);
9490 9490 } else
9491 9491 err = 1;
9492 9492
9493 9493 if (err) {
9494 9494 xmlFreeNode(n);
9495 9495
9496 9496 export_pg(pg, eelts, SCE_ALL_VALUES);
9497 9497
9498 9498 return;
9499 9499 }
9500 9500
9501 9501
9502 9502 /*
9503 9503 * If we're going to have a method_context child, we need to know
9504 9504 * before we iterate through the properties. Since method_context's
9505 9505 * are optional, we don't want to complain about any properties
9506 9506 * missing if none of them are there. Thus we can't use the
9507 9507 * convenience functions.
9508 9508 */
9509 9509 nonenv =
9510 9510 scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
9511 9511 SCF_SUCCESS ||
9512 9512 scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
9513 9513 SCF_SUCCESS ||
9514 9514 scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
9515 9515 SCF_SUCCESS ||
9516 9516 scf_pg_get_property(pg, SCF_PROPERTY_SECFLAGS, NULL) ==
9517 9517 SCF_SUCCESS ||
9518 9518 scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
9519 9519 SCF_SUCCESS;
9520 9520
9521 9521 if (nonenv) {
9522 9522 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9523 9523 if (ctxt == NULL)
9524 9524 uu_die(emsg_create_xml);
9525 9525
9526 9526 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
9527 9527 0 &&
9528 9528 set_attr_from_prop_default(exp_prop, ctxt,
9529 9529 "working_directory", ":default") != 0)
9530 9530 err = 1;
9531 9531
9532 9532 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
9533 9533 set_attr_from_prop_default(exp_prop, ctxt, "project",
9534 9534 ":default") != 0)
9535 9535 err = 1;
9536 9536
9537 9537 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
9538 9538 0 &&
9539 9539 set_attr_from_prop_default(exp_prop, ctxt,
9540 9540 "resource_pool", ":default") != 0)
9541 9541 err = 1;
9542 9542
9543 9543 if (pg_get_prop(pg, SCF_PROPERTY_SECFLAGS, exp_prop) == 0 &&
9544 9544 set_attr_from_prop_default(exp_prop, ctxt,
9545 9545 "security_flags", ":default") != 0)
9546 9546 err = 1;
9547 9547
9548 9548 /*
9549 9549 * We only want to complain about profile or credential
9550 9550 * properties if we will use them. To determine that we must
9551 9551 * examine USE_PROFILE.
9552 9552 */
9553 9553 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9554 9554 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9555 9555 prop_get_val(exp_prop, exp_val) == 0) {
9556 9556 if (scf_value_get_boolean(exp_val, &use_profile) !=
9557 9557 SCF_SUCCESS) {
9558 9558 scfdie();
9559 9559 }
9560 9560
9561 9561 if (use_profile) {
9562 9562 xmlNodePtr prof;
9563 9563
9564 9564 prof = xmlNewChild(ctxt, NULL,
9565 9565 (xmlChar *)"method_profile", NULL);
9566 9566 if (prof == NULL)
9567 9567 uu_die(emsg_create_xml);
9568 9568
9569 9569 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
9570 9570 exp_prop) != 0 ||
9571 9571 set_attr_from_prop(exp_prop, prof,
9572 9572 name_attr) != 0)
9573 9573 err = 1;
9574 9574 } else {
9575 9575 xmlNodePtr cred;
9576 9576
9577 9577 cred = xmlNewChild(ctxt, NULL,
9578 9578 (xmlChar *)"method_credential", NULL);
9579 9579 if (cred == NULL)
9580 9580 uu_die(emsg_create_xml);
9581 9581
9582 9582 if (pg_get_prop(pg, SCF_PROPERTY_USER,
9583 9583 exp_prop) != 0 ||
9584 9584 set_attr_from_prop(exp_prop, cred,
9585 9585 "user") != 0) {
9586 9586 err = 1;
9587 9587 }
9588 9588
9589 9589 if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
9590 9590 exp_prop) == 0 &&
9591 9591 set_attr_from_prop_default(exp_prop, cred,
9592 9592 "group", ":default") != 0)
9593 9593 err = 1;
9594 9594
9595 9595 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
9596 9596 exp_prop) == 0 &&
9597 9597 set_attr_from_prop_default(exp_prop, cred,
9598 9598 "supp_groups", ":default") != 0)
9599 9599 err = 1;
9600 9600
9601 9601 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
9602 9602 exp_prop) == 0 &&
9603 9603 set_attr_from_prop_default(exp_prop, cred,
9604 9604 "privileges", ":default") != 0)
9605 9605 err = 1;
9606 9606
9607 9607 if (pg_get_prop(pg,
9608 9608 SCF_PROPERTY_LIMIT_PRIVILEGES,
9609 9609 exp_prop) == 0 &&
9610 9610 set_attr_from_prop_default(exp_prop, cred,
9611 9611 "limit_privileges", ":default") != 0)
9612 9612 err = 1;
9613 9613 }
9614 9614 }
9615 9615 }
9616 9616
9617 9617 if ((env = export_method_environment(pg)) != NULL) {
9618 9618 if (ctxt == NULL) {
9619 9619 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9620 9620 if (ctxt == NULL)
9621 9621 uu_die(emsg_create_xml);
9622 9622 }
9623 9623 (void) xmlAddChild(ctxt, env);
9624 9624 }
9625 9625
9626 9626 if (env != NULL || (nonenv && err == 0))
9627 9627 (void) xmlAddChild(n, ctxt);
9628 9628 else
9629 9629 xmlFreeNode(ctxt);
9630 9630
9631 9631 nonenv = (err == 0);
9632 9632
9633 9633 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9634 9634 scfdie();
9635 9635
9636 9636 (void) memset(&elts, 0, sizeof (elts));
9637 9637
9638 9638 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9639 9639 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9640 9640 scfdie();
9641 9641
9642 9642 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9643 9643 strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
9644 9644 strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
9645 9645 continue;
9646 9646 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9647 9647 xmlNodePtr m;
9648 9648
9649 9649 m = xmlNewNode(NULL, (xmlChar *)"stability");
9650 9650 if (m == NULL)
9651 9651 uu_die(emsg_create_xml);
9652 9652
9653 9653 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9654 9654 elts.stability = m;
9655 9655 continue;
9656 9656 }
9657 9657
9658 9658 xmlFreeNode(m);
9659 9659 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
9660 9660 0 ||
9661 9661 strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
9662 9662 strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
9663 9663 strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9664 9664 if (nonenv)
9665 9665 continue;
9666 9666 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
9667 9667 strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
9668 9668 strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
9669 9669 strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
9670 9670 strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0 ||
9671 9671 strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9672 9672 if (nonenv && !use_profile)
9673 9673 continue;
9674 9674 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9675 9675 if (nonenv && use_profile)
9676 9676 continue;
9677 9677 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
9678 9678 if (env != NULL)
9679 9679 continue;
9680 9680 }
9681 9681
9682 9682 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9683 9683 }
9684 9684 if (ret == -1)
9685 9685 scfdie();
9686 9686
9687 9687 (void) xmlAddChild(n, elts.stability);
9688 9688 (void) xmlAddChildList(n, elts.propvals);
9689 9689 (void) xmlAddChildList(n, elts.properties);
9690 9690
9691 9691 if (eelts->exec_methods == NULL)
9692 9692 eelts->exec_methods = n;
9693 9693 else
9694 9694 (void) xmlAddSibling(eelts->exec_methods, n);
9695 9695 }
9696 9696
9697 9697 static void
9698 9698 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
9699 9699 struct entity_elts *eelts)
9700 9700 {
9701 9701 xmlNodePtr pgnode;
9702 9702
9703 9703 pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
9704 9704 if (pgnode == NULL)
9705 9705 uu_die(emsg_create_xml);
9706 9706
9707 9707 safe_setprop(pgnode, name_attr, name);
9708 9708 safe_setprop(pgnode, type_attr, type);
9709 9709
9710 9710 (void) xmlAddChildList(pgnode, elts->propvals);
9711 9711 (void) xmlAddChildList(pgnode, elts->properties);
9712 9712
9713 9713 if (eelts->property_groups == NULL)
9714 9714 eelts->property_groups = pgnode;
9715 9715 else
9716 9716 (void) xmlAddSibling(eelts->property_groups, pgnode);
9717 9717 }
9718 9718
9719 9719 /*
9720 9720 * Process the general property group for a service. This is the one with the
9721 9721 * goodies.
9722 9722 */
9723 9723 static void
9724 9724 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
9725 9725 {
9726 9726 struct pg_elts elts;
9727 9727 int ret;
9728 9728
9729 9729 /*
9730 9730 * In case there are properties which don't correspond to child
9731 9731 * entities of the service entity, we'll set up a pg_elts structure to
9732 9732 * put them in.
9733 9733 */
9734 9734 (void) memset(&elts, 0, sizeof (elts));
9735 9735
9736 9736 /* Walk the properties, looking for special ones. */
9737 9737 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9738 9738 scfdie();
9739 9739
9740 9740 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9741 9741 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9742 9742 scfdie();
9743 9743
9744 9744 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
9745 9745 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9746 9746 prop_get_val(exp_prop, exp_val) == 0) {
9747 9747 uint8_t b;
9748 9748
9749 9749 if (scf_value_get_boolean(exp_val, &b) !=
9750 9750 SCF_SUCCESS)
9751 9751 scfdie();
9752 9752
9753 9753 if (b) {
9754 9754 selts->single_instance =
9755 9755 xmlNewNode(NULL,
9756 9756 (xmlChar *)"single_instance");
9757 9757 if (selts->single_instance == NULL)
9758 9758 uu_die(emsg_create_xml);
9759 9759 }
9760 9760
9761 9761 continue;
9762 9762 }
9763 9763 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9764 9764 xmlNodePtr rnode, sfnode;
9765 9765
9766 9766 rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9767 9767 if (rnode == NULL)
9768 9768 uu_die(emsg_create_xml);
9769 9769
9770 9770 sfnode = xmlNewChild(rnode, NULL,
9771 9771 (xmlChar *)"service_fmri", NULL);
9772 9772 if (sfnode == NULL)
9773 9773 uu_die(emsg_create_xml);
9774 9774
9775 9775 if (set_attr_from_prop(exp_prop, sfnode,
9776 9776 value_attr) == 0) {
9777 9777 selts->restarter = rnode;
9778 9778 continue;
9779 9779 }
9780 9780
9781 9781 xmlFreeNode(rnode);
9782 9782 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
9783 9783 0) {
9784 9784 xmlNodePtr s;
9785 9785
9786 9786 s = xmlNewNode(NULL, (xmlChar *)"stability");
9787 9787 if (s == NULL)
9788 9788 uu_die(emsg_create_xml);
9789 9789
9790 9790 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9791 9791 selts->stability = s;
9792 9792 continue;
9793 9793 }
9794 9794
9795 9795 xmlFreeNode(s);
9796 9796 }
9797 9797
9798 9798 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9799 9799 }
9800 9800 if (ret == -1)
9801 9801 scfdie();
9802 9802
9803 9803 if (elts.propvals != NULL || elts.properties != NULL)
9804 9804 export_pg_elts(&elts, scf_pg_general, scf_group_framework,
9805 9805 selts);
9806 9806 }
9807 9807
9808 9808 static void
9809 9809 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
9810 9810 {
9811 9811 xmlNodePtr n, prof, cred, env;
9812 9812 uint8_t use_profile;
9813 9813 int ret, err = 0;
9814 9814
9815 9815 n = xmlNewNode(NULL, (xmlChar *)"method_context");
9816 9816
9817 9817 env = export_method_environment(pg);
9818 9818
9819 9819 /* Need to know whether we'll use a profile or not. */
9820 9820 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9821 9821 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9822 9822 prop_get_val(exp_prop, exp_val) == 0) {
9823 9823 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
9824 9824 scfdie();
9825 9825
9826 9826 if (use_profile)
9827 9827 prof =
9828 9828 xmlNewChild(n, NULL, (xmlChar *)"method_profile",
9829 9829 NULL);
9830 9830 else
9831 9831 cred =
9832 9832 xmlNewChild(n, NULL, (xmlChar *)"method_credential",
9833 9833 NULL);
9834 9834 }
9835 9835
9836 9836 if (env != NULL)
9837 9837 (void) xmlAddChild(n, env);
9838 9838
9839 9839 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9840 9840 scfdie();
9841 9841
9842 9842 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9843 9843 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9844 9844 scfdie();
9845 9845
9846 9846 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
9847 9847 if (set_attr_from_prop(exp_prop, n,
9848 9848 "working_directory") != 0)
9849 9849 err = 1;
9850 9850 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
9851 9851 if (set_attr_from_prop(exp_prop, n, "project") != 0)
9852 9852 err = 1;
9853 9853 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
9854 9854 if (set_attr_from_prop(exp_prop, n,
9855 9855 "resource_pool") != 0)
9856 9856 err = 1;
9857 9857 } else if (strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9858 9858 if (set_attr_from_prop(exp_prop, n,
9859 9859 "security_flags") != 0)
9860 9860 err = 1;
9861 9861 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9862 9862 /* EMPTY */
9863 9863 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
9864 9864 if (use_profile ||
9865 9865 set_attr_from_prop(exp_prop, cred, "user") != 0)
9866 9866 err = 1;
9867 9867 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
9868 9868 if (use_profile ||
9869 9869 set_attr_from_prop(exp_prop, cred, "group") != 0)
9870 9870 err = 1;
9871 9871 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
9872 9872 if (use_profile || set_attr_from_prop(exp_prop, cred,
9873 9873 "supp_groups") != 0)
9874 9874 err = 1;
9875 9875 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
9876 9876 if (use_profile || set_attr_from_prop(exp_prop, cred,
9877 9877 "privileges") != 0)
9878 9878 err = 1;
9879 9879 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
9880 9880 0) {
9881 9881 if (use_profile || set_attr_from_prop(exp_prop, cred,
9882 9882 "limit_privileges") != 0)
9883 9883 err = 1;
9884 9884 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9885 9885 if (!use_profile || set_attr_from_prop(exp_prop,
9886 9886 prof, name_attr) != 0)
9887 9887 err = 1;
9888 9888 } else {
9889 9889 /* Can't have generic properties in method_context's */
9890 9890 err = 1;
9891 9891 }
9892 9892 }
9893 9893 if (ret == -1)
9894 9894 scfdie();
9895 9895
9896 9896 if (err && env == NULL) {
9897 9897 xmlFreeNode(n);
9898 9898 export_pg(pg, elts, SCE_ALL_VALUES);
9899 9899 return;
9900 9900 }
9901 9901
9902 9902 elts->method_context = n;
9903 9903 }
9904 9904
9905 9905 /*
9906 9906 * Given a dependency property group in the tfmri entity (target fmri), return
9907 9907 * a dependent element which represents it.
9908 9908 */
9909 9909 static xmlNodePtr
9910 9910 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
9911 9911 {
9912 9912 uint8_t b;
9913 9913 xmlNodePtr n, sf;
9914 9914 int err = 0, ret;
9915 9915 struct pg_elts pgelts;
9916 9916
9917 9917 /*
9918 9918 * If external isn't set to true then exporting the service will
9919 9919 * export this as a normal dependency, so we should stop to avoid
9920 9920 * duplication.
9921 9921 */
9922 9922 if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
9923 9923 scf_property_get_value(exp_prop, exp_val) != 0 ||
9924 9924 scf_value_get_boolean(exp_val, &b) != 0 || !b) {
9925 9925 if (g_verbose) {
9926 9926 warn(gettext("Dependent \"%s\" cannot be exported "
9927 9927 "properly because the \"%s\" property of the "
9928 9928 "\"%s\" dependency of %s is not set to true.\n"),
9929 9929 name, scf_property_external, name, tfmri);
9930 9930 }
9931 9931
9932 9932 return (NULL);
9933 9933 }
9934 9934
9935 9935 n = xmlNewNode(NULL, (xmlChar *)"dependent");
9936 9936 if (n == NULL)
9937 9937 uu_die(emsg_create_xml);
9938 9938
9939 9939 safe_setprop(n, name_attr, name);
9940 9940
9941 9941 /* Get the required attributes */
9942 9942 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9943 9943 set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9944 9944 err = 1;
9945 9945
9946 9946 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9947 9947 set_attr_from_prop(exp_prop, n, "grouping") != 0)
9948 9948 err = 1;
9949 9949
9950 9950 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9951 9951 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
9952 9952 prop_get_val(exp_prop, exp_val) == 0) {
9953 9953 /* EMPTY */
9954 9954 } else
9955 9955 err = 1;
9956 9956
9957 9957 if (err) {
9958 9958 xmlFreeNode(n);
9959 9959 return (NULL);
9960 9960 }
9961 9961
9962 9962 sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
9963 9963 if (sf == NULL)
9964 9964 uu_die(emsg_create_xml);
9965 9965
9966 9966 safe_setprop(sf, value_attr, tfmri);
9967 9967
9968 9968 /*
9969 9969 * Now add elements for the other properties.
9970 9970 */
9971 9971 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9972 9972 scfdie();
9973 9973
9974 9974 (void) memset(&pgelts, 0, sizeof (pgelts));
9975 9975
9976 9976 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9977 9977 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9978 9978 scfdie();
9979 9979
9980 9980 if (strcmp(exp_str, scf_property_external) == 0 ||
9981 9981 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9982 9982 strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9983 9983 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9984 9984 continue;
9985 9985 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
9986 9986 if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
9987 9987 prop_get_val(exp_prop, exp_val) == 0) {
9988 9988 char type[sizeof ("service") + 1];
9989 9989
9990 9990 if (scf_value_get_astring(exp_val, type,
9991 9991 sizeof (type)) < 0)
9992 9992 scfdie();
9993 9993
9994 9994 if (strcmp(type, "service") == 0)
9995 9995 continue;
9996 9996 }
9997 9997 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9998 9998 xmlNodePtr s;
9999 9999
10000 10000 s = xmlNewNode(NULL, (xmlChar *)"stability");
10001 10001 if (s == NULL)
10002 10002 uu_die(emsg_create_xml);
10003 10003
10004 10004 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
10005 10005 pgelts.stability = s;
10006 10006 continue;
10007 10007 }
10008 10008
10009 10009 xmlFreeNode(s);
10010 10010 }
10011 10011
10012 10012 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10013 10013 }
10014 10014 if (ret == -1)
10015 10015 scfdie();
10016 10016
10017 10017 (void) xmlAddChild(n, pgelts.stability);
10018 10018 (void) xmlAddChildList(n, pgelts.propvals);
10019 10019 (void) xmlAddChildList(n, pgelts.properties);
10020 10020
10021 10021 return (n);
10022 10022 }
10023 10023
10024 10024 static void
10025 10025 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
10026 10026 {
10027 10027 scf_propertygroup_t *opg;
10028 10028 scf_iter_t *iter;
10029 10029 char *type, *fmri;
10030 10030 int ret;
10031 10031 struct pg_elts pgelts;
10032 10032 xmlNodePtr n;
10033 10033 scf_error_t serr;
10034 10034
10035 10035 if ((opg = scf_pg_create(g_hndl)) == NULL ||
10036 10036 (iter = scf_iter_create(g_hndl)) == NULL)
10037 10037 scfdie();
10038 10038
10039 10039 /* Can't use exp_prop_iter due to export_dependent(). */
10040 10040 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
10041 10041 scfdie();
10042 10042
10043 10043 type = safe_malloc(max_scf_pg_type_len + 1);
10044 10044
10045 10045 /* Get an extra byte so we can tell if values are too long. */
10046 10046 fmri = safe_malloc(max_scf_fmri_len + 2);
10047 10047
10048 10048 (void) memset(&pgelts, 0, sizeof (pgelts));
10049 10049
10050 10050 while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
10051 10051 void *entity;
10052 10052 int isservice;
10053 10053 scf_type_t ty;
10054 10054
10055 10055 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
10056 10056 scfdie();
10057 10057
10058 10058 if ((ty != SCF_TYPE_ASTRING &&
10059 10059 prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
10060 10060 prop_get_val(exp_prop, exp_val) != 0) {
10061 10061 export_property(exp_prop, NULL, &pgelts,
10062 10062 SCE_ALL_VALUES);
10063 10063 continue;
10064 10064 }
10065 10065
10066 10066 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10067 10067 scfdie();
10068 10068
10069 10069 if (scf_value_get_astring(exp_val, fmri,
10070 10070 max_scf_fmri_len + 2) < 0)
10071 10071 scfdie();
10072 10072
10073 10073 /* Look for a dependency group in the target fmri. */
10074 10074 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
10075 10075 switch (serr) {
10076 10076 case SCF_ERROR_NONE:
10077 10077 break;
10078 10078
10079 10079 case SCF_ERROR_NO_MEMORY:
10080 10080 uu_die(gettext("Out of memory.\n"));
10081 10081 /* NOTREACHED */
10082 10082
10083 10083 case SCF_ERROR_INVALID_ARGUMENT:
10084 10084 if (g_verbose) {
10085 10085 if (scf_property_to_fmri(exp_prop, fmri,
10086 10086 max_scf_fmri_len + 2) < 0)
10087 10087 scfdie();
10088 10088
10089 10089 warn(gettext("The value of %s is not a valid "
10090 10090 "FMRI.\n"), fmri);
10091 10091 }
10092 10092
10093 10093 export_property(exp_prop, exp_str, &pgelts,
10094 10094 SCE_ALL_VALUES);
10095 10095 continue;
10096 10096
10097 10097 case SCF_ERROR_CONSTRAINT_VIOLATED:
10098 10098 if (g_verbose) {
10099 10099 if (scf_property_to_fmri(exp_prop, fmri,
10100 10100 max_scf_fmri_len + 2) < 0)
10101 10101 scfdie();
10102 10102
10103 10103 warn(gettext("The value of %s does not specify "
10104 10104 "a service or an instance.\n"), fmri);
10105 10105 }
10106 10106
10107 10107 export_property(exp_prop, exp_str, &pgelts,
10108 10108 SCE_ALL_VALUES);
10109 10109 continue;
10110 10110
10111 10111 case SCF_ERROR_NOT_FOUND:
10112 10112 if (g_verbose) {
10113 10113 if (scf_property_to_fmri(exp_prop, fmri,
10114 10114 max_scf_fmri_len + 2) < 0)
10115 10115 scfdie();
10116 10116
10117 10117 warn(gettext("The entity specified by %s does "
10118 10118 "not exist.\n"), fmri);
10119 10119 }
10120 10120
10121 10121 export_property(exp_prop, exp_str, &pgelts,
10122 10122 SCE_ALL_VALUES);
10123 10123 continue;
10124 10124
10125 10125 default:
10126 10126 #ifndef NDEBUG
10127 10127 (void) fprintf(stderr, "%s:%d: %s() failed with "
10128 10128 "unexpected error %d.\n", __FILE__, __LINE__,
10129 10129 "fmri_to_entity", serr);
10130 10130 #endif
10131 10131 abort();
10132 10132 }
10133 10133
10134 10134 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
10135 10135 if (scf_error() != SCF_ERROR_NOT_FOUND)
10136 10136 scfdie();
10137 10137
10138 10138 warn(gettext("Entity %s is missing dependency property "
10139 10139 "group %s.\n"), fmri, exp_str);
10140 10140
10141 10141 export_property(exp_prop, NULL, &pgelts,
10142 10142 SCE_ALL_VALUES);
10143 10143 continue;
10144 10144 }
10145 10145
10146 10146 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
10147 10147 scfdie();
10148 10148
10149 10149 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
10150 10150 if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
10151 10151 scfdie();
10152 10152
10153 10153 warn(gettext("Property group %s is not of "
10154 10154 "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
10155 10155
10156 10156 export_property(exp_prop, NULL, &pgelts,
10157 10157 SCE_ALL_VALUES);
10158 10158 continue;
10159 10159 }
10160 10160
10161 10161 n = export_dependent(opg, exp_str, fmri);
10162 10162 if (n == NULL) {
10163 10163 export_property(exp_prop, exp_str, &pgelts,
10164 10164 SCE_ALL_VALUES);
10165 10165 } else {
10166 10166 if (eelts->dependents == NULL)
10167 10167 eelts->dependents = n;
10168 10168 else
10169 10169 (void) xmlAddSibling(eelts->dependents,
10170 10170 n);
10171 10171 }
10172 10172 }
10173 10173 if (ret == -1)
10174 10174 scfdie();
10175 10175
10176 10176 free(fmri);
10177 10177 free(type);
10178 10178
10179 10179 scf_iter_destroy(iter);
10180 10180 scf_pg_destroy(opg);
10181 10181
10182 10182 if (pgelts.propvals != NULL || pgelts.properties != NULL)
10183 10183 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
10184 10184 eelts);
10185 10185 }
10186 10186
10187 10187 static void
10188 10188 make_node(xmlNodePtr *nodep, const char *name)
10189 10189 {
10190 10190 if (*nodep == NULL) {
10191 10191 *nodep = xmlNewNode(NULL, (xmlChar *)name);
10192 10192 if (*nodep == NULL)
10193 10193 uu_die(emsg_create_xml);
10194 10194 }
10195 10195 }
10196 10196
10197 10197 static xmlNodePtr
10198 10198 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
10199 10199 {
10200 10200 int ret;
10201 10201 xmlNodePtr parent = NULL;
10202 10202 xmlNodePtr loctext = NULL;
10203 10203
10204 10204 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10205 10205 scfdie();
10206 10206
10207 10207 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10208 10208 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
10209 10209 prop_get_val(exp_prop, exp_val) != 0)
10210 10210 continue;
10211 10211
10212 10212 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
10213 10213 scfdie();
10214 10214
10215 10215 make_node(&parent, parname);
10216 10216 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
10217 10217 (xmlChar *)exp_str);
10218 10218 if (loctext == NULL)
10219 10219 uu_die(emsg_create_xml);
10220 10220
10221 10221 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10222 10222 scfdie();
10223 10223
10224 10224 safe_setprop(loctext, "xml:lang", exp_str);
10225 10225 }
10226 10226
10227 10227 if (ret == -1)
10228 10228 scfdie();
10229 10229
10230 10230 return (parent);
10231 10231 }
10232 10232
10233 10233 static xmlNodePtr
10234 10234 export_tm_manpage(scf_propertygroup_t *pg)
10235 10235 {
10236 10236 xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
10237 10237 if (manpage == NULL)
10238 10238 uu_die(emsg_create_xml);
10239 10239
10240 10240 if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
10241 10241 set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
10242 10242 pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
10243 10243 set_attr_from_prop(exp_prop, manpage, "section") != 0) {
10244 10244 xmlFreeNode(manpage);
10245 10245 return (NULL);
10246 10246 }
10247 10247
10248 10248 if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
10249 10249 (void) set_attr_from_prop_default(exp_prop,
10250 10250 manpage, "manpath", ":default");
10251 10251
10252 10252 return (manpage);
10253 10253 }
10254 10254
10255 10255 static xmlNodePtr
10256 10256 export_tm_doc_link(scf_propertygroup_t *pg)
10257 10257 {
10258 10258 xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
10259 10259 if (doc_link == NULL)
10260 10260 uu_die(emsg_create_xml);
10261 10261
10262 10262 if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
10263 10263 set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
10264 10264 pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
10265 10265 set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
10266 10266 xmlFreeNode(doc_link);
10267 10267 return (NULL);
10268 10268 }
10269 10269 return (doc_link);
10270 10270 }
10271 10271
10272 10272 /*
10273 10273 * Process template information for a service or instances.
10274 10274 */
10275 10275 static void
10276 10276 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
10277 10277 struct template_elts *telts)
10278 10278 {
10279 10279 size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
10280 10280 size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
10281 10281 xmlNodePtr child = NULL;
10282 10282
10283 10283 if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
10284 10284 scfdie();
10285 10285
10286 10286 if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
10287 10287 telts->common_name = export_tm_loctext(pg, "common_name");
10288 10288 if (telts->common_name == NULL)
10289 10289 export_pg(pg, elts, SCE_ALL_VALUES);
10290 10290 return;
10291 10291 } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
10292 10292 telts->description = export_tm_loctext(pg, "description");
10293 10293 if (telts->description == NULL)
10294 10294 export_pg(pg, elts, SCE_ALL_VALUES);
10295 10295 return;
10296 10296 }
10297 10297
10298 10298 if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
10299 10299 child = export_tm_manpage(pg);
10300 10300 } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
10301 10301 child = export_tm_doc_link(pg);
10302 10302 }
10303 10303
10304 10304 if (child != NULL) {
10305 10305 make_node(&telts->documentation, "documentation");
10306 10306 (void) xmlAddChild(telts->documentation, child);
10307 10307 } else {
10308 10308 export_pg(pg, elts, SCE_ALL_VALUES);
10309 10309 }
10310 10310 }
10311 10311
10312 10312 /*
10313 10313 * Process parameter and paramval elements
10314 10314 */
10315 10315 static void
10316 10316 export_parameter(scf_property_t *prop, const char *name,
10317 10317 struct params_elts *elts)
10318 10318 {
10319 10319 xmlNodePtr param;
10320 10320 scf_error_t err = 0;
10321 10321 int ret;
10322 10322
10323 10323 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
10324 10324 if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL)
10325 10325 uu_die(emsg_create_xml);
10326 10326
10327 10327 safe_setprop(param, name_attr, name);
10328 10328
10329 10329 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
10330 10330 scfdie();
10331 10331 safe_setprop(param, value_attr, exp_str);
10332 10332
10333 10333 if (elts->paramval == NULL)
10334 10334 elts->paramval = param;
10335 10335 else
10336 10336 (void) xmlAddSibling(elts->paramval, param);
10337 10337
10338 10338 return;
10339 10339 }
10340 10340
10341 10341 err = scf_error();
10342 10342
10343 10343 if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
10344 10344 err != SCF_ERROR_NOT_FOUND)
10345 10345 scfdie();
10346 10346
10347 10347 if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL)
10348 10348 uu_die(emsg_create_xml);
10349 10349
10350 10350 safe_setprop(param, name_attr, name);
10351 10351
10352 10352 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
10353 10353 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
10354 10354 scfdie();
10355 10355
10356 10356 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
10357 10357 1) {
10358 10358 xmlNodePtr vn;
10359 10359
10360 10360 if ((vn = xmlNewChild(param, NULL,
10361 10361 (xmlChar *)"value_node", NULL)) == NULL)
10362 10362 uu_die(emsg_create_xml);
10363 10363
10364 10364 if (scf_value_get_as_string(exp_val, exp_str,
10365 10365 exp_str_sz) < 0)
10366 10366 scfdie();
10367 10367
10368 10368 safe_setprop(vn, value_attr, exp_str);
10369 10369 }
10370 10370 if (ret != 0)
10371 10371 scfdie();
10372 10372 }
10373 10373
10374 10374 if (elts->parameter == NULL)
10375 10375 elts->parameter = param;
10376 10376 else
10377 10377 (void) xmlAddSibling(elts->parameter, param);
10378 10378 }
↓ open down ↓ |
10378 lines elided |
↑ open up ↑ |
10379 10379
10380 10380 /*
10381 10381 * Process notification parameters for a service or instance
10382 10382 */
10383 10383 static void
10384 10384 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts)
10385 10385 {
10386 10386 xmlNodePtr n, event, *type;
10387 10387 struct params_elts *eelts;
10388 10388 int ret, err, i;
10389 + char *s;
10389 10390
10390 10391 n = xmlNewNode(NULL, (xmlChar *)"notification_parameters");
10391 10392 event = xmlNewNode(NULL, (xmlChar *)"event");
10392 10393 if (n == NULL || event == NULL)
10393 10394 uu_die(emsg_create_xml);
10394 10395
10395 10396 /* event value */
10396 10397 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
10397 10398 scfdie();
10399 + /* trim SCF_NOTIFY_PG_POSTFIX appended to name on import */
10400 + if ((s = strchr(exp_str, ',')) != NULL)
10401 + *s = '\0';
10398 10402 safe_setprop(event, value_attr, exp_str);
10399 10403
10400 10404 (void) xmlAddChild(n, event);
10401 10405
10402 10406 if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL ||
10403 10407 (eelts = calloc(URI_SCHEME_NUM,
10404 10408 sizeof (struct params_elts))) == NULL)
10405 10409 uu_die(gettext("Out of memory.\n"));
10406 10410
10407 10411 err = 0;
10408 10412
10409 10413 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10410 10414 scfdie();
10411 10415
10412 10416 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10413 10417 char *t, *p;
10414 10418
10415 10419 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10416 10420 scfdie();
10417 10421
10418 10422 if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) {
10419 10423 /*
10420 10424 * this is not a well formed notification parameters
10421 10425 * element, we should export as regular pg
10422 10426 */
10423 10427 err = 1;
10424 10428 break;
10425 10429 }
10426 10430
10427 10431 if ((i = check_uri_protocol(t)) < 0) {
10428 10432 err = 1;
10429 10433 break;
10430 10434 }
10431 10435
10432 10436 if (type[i] == NULL) {
10433 10437 if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) ==
10434 10438 NULL)
10435 10439 uu_die(emsg_create_xml);
10436 10440
10437 10441 safe_setprop(type[i], name_attr, t);
10438 10442 }
10439 10443 if (strcmp(p, active_attr) == 0) {
10440 10444 if (set_attr_from_prop(exp_prop, type[i],
10441 10445 active_attr) != 0) {
10442 10446 err = 1;
10443 10447 break;
10444 10448 }
10445 10449 continue;
10446 10450 }
10447 10451 /*
10448 10452 * We export the parameter
10449 10453 */
10450 10454 export_parameter(exp_prop, p, &eelts[i]);
10451 10455 }
10452 10456
10453 10457 if (ret == -1)
10454 10458 scfdie();
10455 10459
10456 10460 if (err == 1) {
10457 10461 for (i = 0; i < URI_SCHEME_NUM; ++i)
10458 10462 xmlFree(type[i]);
10459 10463 free(type);
10460 10464
10461 10465 export_pg(pg, elts, SCE_ALL_VALUES);
10462 10466
10463 10467 return;
10464 10468 } else {
10465 10469 for (i = 0; i < URI_SCHEME_NUM; ++i)
10466 10470 if (type[i] != NULL) {
10467 10471 (void) xmlAddChildList(type[i],
10468 10472 eelts[i].paramval);
10469 10473 (void) xmlAddChildList(type[i],
10470 10474 eelts[i].parameter);
10471 10475 (void) xmlAddSibling(event, type[i]);
10472 10476 }
10473 10477 }
10474 10478 free(type);
10475 10479
10476 10480 if (elts->notify_params == NULL)
10477 10481 elts->notify_params = n;
10478 10482 else
10479 10483 (void) xmlAddSibling(elts->notify_params, n);
10480 10484 }
10481 10485
10482 10486 /*
10483 10487 * Process the general property group for an instance.
10484 10488 */
10485 10489 static void
10486 10490 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
10487 10491 struct entity_elts *elts)
10488 10492 {
10489 10493 uint8_t enabled;
10490 10494 struct pg_elts pgelts;
10491 10495 int ret;
10492 10496
10493 10497 /* enabled */
10494 10498 if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
10495 10499 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
10496 10500 prop_get_val(exp_prop, exp_val) == 0) {
10497 10501 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
10498 10502 scfdie();
10499 10503 } else {
10500 10504 enabled = 0;
10501 10505 }
10502 10506
10503 10507 safe_setprop(inode, enabled_attr, enabled ? true : false);
10504 10508
10505 10509 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10506 10510 scfdie();
10507 10511
10508 10512 (void) memset(&pgelts, 0, sizeof (pgelts));
10509 10513
10510 10514 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10511 10515 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10512 10516 scfdie();
10513 10517
10514 10518 if (strcmp(exp_str, scf_property_enabled) == 0) {
10515 10519 continue;
10516 10520 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
10517 10521 xmlNodePtr rnode, sfnode;
10518 10522
10519 10523 rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10520 10524 if (rnode == NULL)
10521 10525 uu_die(emsg_create_xml);
10522 10526
10523 10527 sfnode = xmlNewChild(rnode, NULL,
10524 10528 (xmlChar *)"service_fmri", NULL);
10525 10529 if (sfnode == NULL)
10526 10530 uu_die(emsg_create_xml);
10527 10531
10528 10532 if (set_attr_from_prop(exp_prop, sfnode,
10529 10533 value_attr) == 0) {
10530 10534 elts->restarter = rnode;
10531 10535 continue;
10532 10536 }
10533 10537
10534 10538 xmlFreeNode(rnode);
10535 10539 }
10536 10540
10537 10541 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10538 10542 }
10539 10543 if (ret == -1)
10540 10544 scfdie();
10541 10545
10542 10546 if (pgelts.propvals != NULL || pgelts.properties != NULL)
10543 10547 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10544 10548 elts);
10545 10549 }
10546 10550
10547 10551 /*
10548 10552 * Put an instance element for the given instance into selts.
10549 10553 */
10550 10554 static void
10551 10555 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10552 10556 {
10553 10557 xmlNodePtr n;
10554 10558 boolean_t isdefault;
10555 10559 struct entity_elts elts;
10556 10560 struct template_elts template_elts;
10557 10561 int ret;
10558 10562
10559 10563 n = xmlNewNode(NULL, (xmlChar *)"instance");
10560 10564 if (n == NULL)
10561 10565 uu_die(emsg_create_xml);
10562 10566
10563 10567 /* name */
10564 10568 if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10565 10569 scfdie();
10566 10570 safe_setprop(n, name_attr, exp_str);
10567 10571 isdefault = strcmp(exp_str, "default") == 0;
10568 10572
10569 10573 /* check existance of general pg (since general/enabled is required) */
10570 10574 if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
10571 10575 if (scf_error() != SCF_ERROR_NOT_FOUND)
10572 10576 scfdie();
10573 10577
10574 10578 if (g_verbose) {
10575 10579 if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10576 10580 scfdie();
10577 10581
10578 10582 warn(gettext("Instance %s has no general property "
10579 10583 "group; it will be marked disabled.\n"), exp_str);
10580 10584 }
10581 10585
10582 10586 safe_setprop(n, enabled_attr, false);
10583 10587 } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
10584 10588 strcmp(exp_str, scf_group_framework) != 0) {
10585 10589 if (g_verbose) {
10586 10590 if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10587 10591 scfdie();
10588 10592
10589 10593 warn(gettext("Property group %s is not of type "
10590 10594 "framework; the instance will be marked "
10591 10595 "disabled.\n"), exp_str);
10592 10596 }
10593 10597
10594 10598 safe_setprop(n, enabled_attr, false);
10595 10599 }
10596 10600
10597 10601 /* property groups */
10598 10602 if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
10599 10603 scfdie();
10600 10604
10601 10605 (void) memset(&elts, 0, sizeof (elts));
10602 10606 (void) memset(&template_elts, 0, sizeof (template_elts));
10603 10607
10604 10608 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10605 10609 uint32_t pgflags;
10606 10610
10607 10611 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10608 10612 scfdie();
10609 10613
10610 10614 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10611 10615 continue;
10612 10616
10613 10617 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10614 10618 scfdie();
10615 10619
10616 10620 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10617 10621 export_dependency(exp_pg, &elts);
10618 10622 continue;
10619 10623 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10620 10624 export_method(exp_pg, &elts);
10621 10625 continue;
10622 10626 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10623 10627 if (scf_pg_get_name(exp_pg, exp_str,
10624 10628 max_scf_name_len + 1) < 0)
10625 10629 scfdie();
10626 10630
10627 10631 if (strcmp(exp_str, scf_pg_general) == 0) {
10628 10632 export_inst_general(exp_pg, n, &elts);
10629 10633 continue;
10630 10634 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10631 10635 0) {
10632 10636 export_method_context(exp_pg, &elts);
10633 10637 continue;
10634 10638 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10635 10639 export_dependents(exp_pg, &elts);
10636 10640 continue;
10637 10641 }
10638 10642 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10639 10643 export_template(exp_pg, &elts, &template_elts);
10640 10644 continue;
10641 10645 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10642 10646 export_notify_params(exp_pg, &elts);
10643 10647 continue;
10644 10648 }
10645 10649
10646 10650 /* Ordinary pg. */
10647 10651 export_pg(exp_pg, &elts, flags);
10648 10652 }
10649 10653 if (ret == -1)
10650 10654 scfdie();
10651 10655
10652 10656 if (template_elts.common_name != NULL) {
10653 10657 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10654 10658 (void) xmlAddChild(elts.template, template_elts.common_name);
10655 10659 (void) xmlAddChild(elts.template, template_elts.description);
10656 10660 (void) xmlAddChild(elts.template, template_elts.documentation);
10657 10661 } else {
10658 10662 xmlFreeNode(template_elts.description);
10659 10663 xmlFreeNode(template_elts.documentation);
10660 10664 }
10661 10665
10662 10666 if (isdefault && elts.restarter == NULL &&
10663 10667 elts.dependencies == NULL && elts.method_context == NULL &&
10664 10668 elts.exec_methods == NULL && elts.notify_params == NULL &&
10665 10669 elts.property_groups == NULL && elts.template == NULL) {
10666 10670 xmlChar *eval;
10667 10671
10668 10672 /* This is a default instance */
10669 10673 eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10670 10674
10671 10675 xmlFreeNode(n);
10672 10676
10673 10677 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10674 10678 if (n == NULL)
10675 10679 uu_die(emsg_create_xml);
10676 10680
10677 10681 safe_setprop(n, enabled_attr, (char *)eval);
10678 10682 xmlFree(eval);
10679 10683
10680 10684 selts->create_default_instance = n;
10681 10685 } else {
10682 10686 /* Assemble the children in order. */
10683 10687 (void) xmlAddChild(n, elts.restarter);
10684 10688 (void) xmlAddChildList(n, elts.dependencies);
10685 10689 (void) xmlAddChildList(n, elts.dependents);
10686 10690 (void) xmlAddChild(n, elts.method_context);
10687 10691 (void) xmlAddChildList(n, elts.exec_methods);
10688 10692 (void) xmlAddChildList(n, elts.notify_params);
10689 10693 (void) xmlAddChildList(n, elts.property_groups);
10690 10694 (void) xmlAddChild(n, elts.template);
10691 10695
10692 10696 if (selts->instances == NULL)
10693 10697 selts->instances = n;
10694 10698 else
10695 10699 (void) xmlAddSibling(selts->instances, n);
10696 10700 }
10697 10701 }
10698 10702
10699 10703 /*
10700 10704 * Return a service element for the given service.
10701 10705 */
10702 10706 static xmlNodePtr
10703 10707 export_service(scf_service_t *svc, int flags)
10704 10708 {
10705 10709 xmlNodePtr snode;
10706 10710 struct entity_elts elts;
10707 10711 struct template_elts template_elts;
10708 10712 int ret;
10709 10713
10710 10714 snode = xmlNewNode(NULL, (xmlChar *)"service");
10711 10715 if (snode == NULL)
10712 10716 uu_die(emsg_create_xml);
10713 10717
10714 10718 /* Get & set name attribute */
10715 10719 if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
10716 10720 scfdie();
10717 10721 safe_setprop(snode, name_attr, exp_str);
10718 10722
10719 10723 safe_setprop(snode, type_attr, "service");
10720 10724 safe_setprop(snode, "version", "0");
10721 10725
10722 10726 /* Acquire child elements. */
10723 10727 if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
10724 10728 scfdie();
10725 10729
10726 10730 (void) memset(&elts, 0, sizeof (elts));
10727 10731 (void) memset(&template_elts, 0, sizeof (template_elts));
10728 10732
10729 10733 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10730 10734 uint32_t pgflags;
10731 10735
10732 10736 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10733 10737 scfdie();
10734 10738
10735 10739 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10736 10740 continue;
10737 10741
10738 10742 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10739 10743 scfdie();
10740 10744
10741 10745 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10742 10746 export_dependency(exp_pg, &elts);
10743 10747 continue;
10744 10748 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10745 10749 export_method(exp_pg, &elts);
10746 10750 continue;
10747 10751 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10748 10752 if (scf_pg_get_name(exp_pg, exp_str,
10749 10753 max_scf_name_len + 1) < 0)
10750 10754 scfdie();
10751 10755
10752 10756 if (strcmp(exp_str, scf_pg_general) == 0) {
10753 10757 export_svc_general(exp_pg, &elts);
10754 10758 continue;
10755 10759 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10756 10760 0) {
10757 10761 export_method_context(exp_pg, &elts);
10758 10762 continue;
10759 10763 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10760 10764 export_dependents(exp_pg, &elts);
10761 10765 continue;
10762 10766 } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10763 10767 continue;
10764 10768 }
10765 10769 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10766 10770 export_template(exp_pg, &elts, &template_elts);
10767 10771 continue;
10768 10772 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10769 10773 export_notify_params(exp_pg, &elts);
10770 10774 continue;
10771 10775 }
10772 10776
10773 10777 export_pg(exp_pg, &elts, flags);
10774 10778 }
10775 10779 if (ret == -1)
10776 10780 scfdie();
10777 10781
10778 10782 if (template_elts.common_name != NULL) {
10779 10783 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10780 10784 (void) xmlAddChild(elts.template, template_elts.common_name);
10781 10785 (void) xmlAddChild(elts.template, template_elts.description);
10782 10786 (void) xmlAddChild(elts.template, template_elts.documentation);
10783 10787 } else {
10784 10788 xmlFreeNode(template_elts.description);
10785 10789 xmlFreeNode(template_elts.documentation);
10786 10790 }
10787 10791
10788 10792 /* Iterate instances */
10789 10793 if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
10790 10794 scfdie();
10791 10795
10792 10796 while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10793 10797 export_instance(exp_inst, &elts, flags);
10794 10798 if (ret == -1)
10795 10799 scfdie();
10796 10800
10797 10801 /* Now add all of the accumulated elements in order. */
10798 10802 (void) xmlAddChild(snode, elts.create_default_instance);
10799 10803 (void) xmlAddChild(snode, elts.single_instance);
10800 10804 (void) xmlAddChild(snode, elts.restarter);
10801 10805 (void) xmlAddChildList(snode, elts.dependencies);
10802 10806 (void) xmlAddChildList(snode, elts.dependents);
10803 10807 (void) xmlAddChild(snode, elts.method_context);
10804 10808 (void) xmlAddChildList(snode, elts.exec_methods);
10805 10809 (void) xmlAddChildList(snode, elts.notify_params);
10806 10810 (void) xmlAddChildList(snode, elts.property_groups);
10807 10811 (void) xmlAddChildList(snode, elts.instances);
10808 10812 (void) xmlAddChild(snode, elts.stability);
10809 10813 (void) xmlAddChild(snode, elts.template);
10810 10814
10811 10815 return (snode);
10812 10816 }
10813 10817
10814 10818 static int
10815 10819 export_callback(void *data, scf_walkinfo_t *wip)
10816 10820 {
10817 10821 FILE *f;
10818 10822 xmlDocPtr doc;
10819 10823 xmlNodePtr sb;
10820 10824 int result;
10821 10825 struct export_args *argsp = (struct export_args *)data;
10822 10826
10823 10827 if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
10824 10828 (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10825 10829 (exp_prop = scf_property_create(g_hndl)) == NULL ||
10826 10830 (exp_val = scf_value_create(g_hndl)) == NULL ||
10827 10831 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10828 10832 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10829 10833 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10830 10834 (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10831 10835 scfdie();
10832 10836
10833 10837 exp_str_sz = max_scf_len + 1;
10834 10838 exp_str = safe_malloc(exp_str_sz);
10835 10839
10836 10840 if (argsp->filename != NULL) {
10837 10841 errno = 0;
10838 10842 f = fopen(argsp->filename, "wb");
10839 10843 if (f == NULL) {
10840 10844 if (errno == 0)
10841 10845 uu_die(gettext("Could not open \"%s\": no free "
10842 10846 "stdio streams.\n"), argsp->filename);
10843 10847 else
10844 10848 uu_die(gettext("Could not open \"%s\""),
10845 10849 argsp->filename);
10846 10850 }
10847 10851 } else
10848 10852 f = stdout;
10849 10853
10850 10854 doc = xmlNewDoc((xmlChar *)"1.0");
10851 10855 if (doc == NULL)
10852 10856 uu_die(gettext("Could not create XML document.\n"));
10853 10857
10854 10858 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10855 10859 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10856 10860 uu_die(emsg_create_xml);
10857 10861
10858 10862 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10859 10863 if (sb == NULL)
10860 10864 uu_die(emsg_create_xml);
10861 10865 safe_setprop(sb, type_attr, "manifest");
10862 10866 safe_setprop(sb, name_attr, "export");
10863 10867 (void) xmlAddSibling(doc->children, sb);
10864 10868
10865 10869 (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
10866 10870
10867 10871 result = write_service_bundle(doc, f);
10868 10872
10869 10873 free(exp_str);
10870 10874 scf_iter_destroy(exp_val_iter);
10871 10875 scf_iter_destroy(exp_prop_iter);
10872 10876 scf_iter_destroy(exp_pg_iter);
10873 10877 scf_iter_destroy(exp_inst_iter);
10874 10878 scf_value_destroy(exp_val);
10875 10879 scf_property_destroy(exp_prop);
10876 10880 scf_pg_destroy(exp_pg);
10877 10881 scf_instance_destroy(exp_inst);
10878 10882
10879 10883 xmlFreeDoc(doc);
10880 10884
10881 10885 if (f != stdout)
10882 10886 (void) fclose(f);
10883 10887
10884 10888 return (result);
10885 10889 }
10886 10890
10887 10891 /*
10888 10892 * Get the service named by fmri, build an XML tree which represents it, and
10889 10893 * dump it into filename (or stdout if filename is NULL).
10890 10894 */
10891 10895 int
10892 10896 lscf_service_export(char *fmri, const char *filename, int flags)
10893 10897 {
10894 10898 struct export_args args;
10895 10899 char *fmridup;
10896 10900 const char *scope, *svc, *inst;
10897 10901 size_t cblen = 3 * max_scf_name_len;
10898 10902 char *canonbuf = alloca(cblen);
10899 10903 int ret, err;
10900 10904
10901 10905 lscf_prep_hndl();
10902 10906
10903 10907 bzero(&args, sizeof (args));
10904 10908 args.filename = filename;
10905 10909 args.flags = flags;
10906 10910
10907 10911 /*
10908 10912 * If some poor user has passed an exact instance FMRI, of the sort
10909 10913 * one might cut and paste from svcs(1) or an error message, warn
10910 10914 * and chop off the instance instead of failing.
10911 10915 */
10912 10916 fmridup = alloca(strlen(fmri) + 1);
10913 10917 (void) strcpy(fmridup, fmri);
10914 10918 if (strncmp(fmridup, SCF_FMRI_SVC_PREFIX,
10915 10919 sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 &&
10916 10920 scf_parse_svc_fmri(fmridup, &scope, &svc, &inst, NULL, NULL) == 0 &&
10917 10921 inst != NULL) {
10918 10922 (void) strlcpy(canonbuf, "svc:/", cblen);
10919 10923 if (strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
10920 10924 (void) strlcat(canonbuf, "/", cblen);
10921 10925 (void) strlcat(canonbuf, scope, cblen);
10922 10926 }
10923 10927 (void) strlcat(canonbuf, svc, cblen);
10924 10928 fmri = canonbuf;
10925 10929
10926 10930 warn(gettext("Only services may be exported; ignoring "
10927 10931 "instance portion of argument.\n"));
10928 10932 }
10929 10933
10930 10934 err = 0;
10931 10935 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10932 10936 SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10933 10937 &args, &err, semerr)) != 0) {
10934 10938 if (ret != -1)
10935 10939 semerr(gettext("Failed to walk instances: %s\n"),
10936 10940 scf_strerror(ret));
10937 10941 return (-1);
10938 10942 }
10939 10943
10940 10944 /*
10941 10945 * Error message has already been printed.
10942 10946 */
10943 10947 if (err != 0)
10944 10948 return (-1);
10945 10949
10946 10950 return (0);
10947 10951 }
10948 10952
10949 10953
10950 10954 /*
10951 10955 * Archive
10952 10956 */
10953 10957
10954 10958 static xmlNodePtr
10955 10959 make_archive(int flags)
10956 10960 {
10957 10961 xmlNodePtr sb;
10958 10962 scf_scope_t *scope;
10959 10963 scf_service_t *svc;
10960 10964 scf_iter_t *iter;
10961 10965 int r;
10962 10966
10963 10967 if ((scope = scf_scope_create(g_hndl)) == NULL ||
10964 10968 (svc = scf_service_create(g_hndl)) == NULL ||
10965 10969 (iter = scf_iter_create(g_hndl)) == NULL ||
10966 10970 (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10967 10971 (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10968 10972 (exp_prop = scf_property_create(g_hndl)) == NULL ||
10969 10973 (exp_val = scf_value_create(g_hndl)) == NULL ||
10970 10974 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10971 10975 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10972 10976 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10973 10977 (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10974 10978 scfdie();
10975 10979
10976 10980 exp_str_sz = max_scf_len + 1;
10977 10981 exp_str = safe_malloc(exp_str_sz);
10978 10982
10979 10983 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10980 10984 if (sb == NULL)
10981 10985 uu_die(emsg_create_xml);
10982 10986 safe_setprop(sb, type_attr, "archive");
10983 10987 safe_setprop(sb, name_attr, "none");
10984 10988
10985 10989 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
10986 10990 scfdie();
10987 10991 if (scf_iter_scope_services(iter, scope) != 0)
10988 10992 scfdie();
10989 10993
10990 10994 for (;;) {
10991 10995 r = scf_iter_next_service(iter, svc);
10992 10996 if (r == 0)
10993 10997 break;
10994 10998 if (r != 1)
10995 10999 scfdie();
10996 11000
10997 11001 if (scf_service_get_name(svc, exp_str,
10998 11002 max_scf_name_len + 1) < 0)
10999 11003 scfdie();
11000 11004
11001 11005 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
11002 11006 continue;
11003 11007
11004 11008 (void) xmlAddChild(sb, export_service(svc, flags));
11005 11009 }
11006 11010
11007 11011 free(exp_str);
11008 11012
11009 11013 scf_iter_destroy(exp_val_iter);
11010 11014 scf_iter_destroy(exp_prop_iter);
11011 11015 scf_iter_destroy(exp_pg_iter);
11012 11016 scf_iter_destroy(exp_inst_iter);
11013 11017 scf_value_destroy(exp_val);
11014 11018 scf_property_destroy(exp_prop);
11015 11019 scf_pg_destroy(exp_pg);
11016 11020 scf_instance_destroy(exp_inst);
11017 11021 scf_iter_destroy(iter);
11018 11022 scf_service_destroy(svc);
11019 11023 scf_scope_destroy(scope);
11020 11024
11021 11025 return (sb);
11022 11026 }
11023 11027
11024 11028 int
11025 11029 lscf_archive(const char *filename, int flags)
11026 11030 {
11027 11031 FILE *f;
11028 11032 xmlDocPtr doc;
11029 11033 int result;
11030 11034
11031 11035 lscf_prep_hndl();
11032 11036
11033 11037 if (filename != NULL) {
11034 11038 errno = 0;
11035 11039 f = fopen(filename, "wb");
11036 11040 if (f == NULL) {
11037 11041 if (errno == 0)
11038 11042 uu_die(gettext("Could not open \"%s\": no free "
11039 11043 "stdio streams.\n"), filename);
11040 11044 else
11041 11045 uu_die(gettext("Could not open \"%s\""),
11042 11046 filename);
11043 11047 }
11044 11048 } else
11045 11049 f = stdout;
11046 11050
11047 11051 doc = xmlNewDoc((xmlChar *)"1.0");
11048 11052 if (doc == NULL)
11049 11053 uu_die(gettext("Could not create XML document.\n"));
11050 11054
11051 11055 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11052 11056 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11053 11057 uu_die(emsg_create_xml);
11054 11058
11055 11059 (void) xmlAddSibling(doc->children, make_archive(flags));
11056 11060
11057 11061 result = write_service_bundle(doc, f);
11058 11062
11059 11063 xmlFreeDoc(doc);
11060 11064
11061 11065 if (f != stdout)
11062 11066 (void) fclose(f);
11063 11067
11064 11068 return (result);
11065 11069 }
11066 11070
11067 11071
11068 11072 /*
11069 11073 * "Extract" a profile.
11070 11074 */
11071 11075 int
11072 11076 lscf_profile_extract(const char *filename)
11073 11077 {
11074 11078 FILE *f;
11075 11079 xmlDocPtr doc;
11076 11080 xmlNodePtr sb, snode, inode;
11077 11081 scf_scope_t *scope;
11078 11082 scf_service_t *svc;
11079 11083 scf_instance_t *inst;
11080 11084 scf_propertygroup_t *pg;
11081 11085 scf_property_t *prop;
11082 11086 scf_value_t *val;
11083 11087 scf_iter_t *siter, *iiter;
11084 11088 int r, s;
11085 11089 char *namebuf;
11086 11090 uint8_t b;
11087 11091 int result;
11088 11092
11089 11093 lscf_prep_hndl();
11090 11094
11091 11095 if (filename != NULL) {
11092 11096 errno = 0;
11093 11097 f = fopen(filename, "wb");
11094 11098 if (f == NULL) {
11095 11099 if (errno == 0)
11096 11100 uu_die(gettext("Could not open \"%s\": no "
11097 11101 "free stdio streams.\n"), filename);
11098 11102 else
11099 11103 uu_die(gettext("Could not open \"%s\""),
11100 11104 filename);
11101 11105 }
11102 11106 } else
11103 11107 f = stdout;
11104 11108
11105 11109 doc = xmlNewDoc((xmlChar *)"1.0");
11106 11110 if (doc == NULL)
11107 11111 uu_die(gettext("Could not create XML document.\n"));
11108 11112
11109 11113 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11110 11114 (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11111 11115 uu_die(emsg_create_xml);
11112 11116
11113 11117 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
11114 11118 if (sb == NULL)
11115 11119 uu_die(emsg_create_xml);
11116 11120 safe_setprop(sb, type_attr, "profile");
11117 11121 safe_setprop(sb, name_attr, "extract");
11118 11122 (void) xmlAddSibling(doc->children, sb);
11119 11123
11120 11124 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11121 11125 (svc = scf_service_create(g_hndl)) == NULL ||
11122 11126 (inst = scf_instance_create(g_hndl)) == NULL ||
11123 11127 (pg = scf_pg_create(g_hndl)) == NULL ||
11124 11128 (prop = scf_property_create(g_hndl)) == NULL ||
11125 11129 (val = scf_value_create(g_hndl)) == NULL ||
11126 11130 (siter = scf_iter_create(g_hndl)) == NULL ||
11127 11131 (iiter = scf_iter_create(g_hndl)) == NULL)
11128 11132 scfdie();
11129 11133
11130 11134 if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
11131 11135 scfdie();
11132 11136
11133 11137 if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
11134 11138 scfdie();
11135 11139
11136 11140 namebuf = safe_malloc(max_scf_name_len + 1);
11137 11141
11138 11142 while ((r = scf_iter_next_service(siter, svc)) == 1) {
11139 11143 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
11140 11144 scfdie();
11141 11145
11142 11146 snode = xmlNewNode(NULL, (xmlChar *)"service");
11143 11147 if (snode == NULL)
11144 11148 uu_die(emsg_create_xml);
11145 11149
11146 11150 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
11147 11151 0)
11148 11152 scfdie();
11149 11153
11150 11154 safe_setprop(snode, name_attr, namebuf);
11151 11155
11152 11156 safe_setprop(snode, type_attr, "service");
11153 11157 safe_setprop(snode, "version", "0");
11154 11158
11155 11159 while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
11156 11160 if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
11157 11161 SCF_SUCCESS) {
11158 11162 if (scf_error() != SCF_ERROR_NOT_FOUND)
11159 11163 scfdie();
11160 11164
11161 11165 if (g_verbose) {
11162 11166 ssize_t len;
11163 11167 char *fmri;
11164 11168
11165 11169 len =
11166 11170 scf_instance_to_fmri(inst, NULL, 0);
11167 11171 if (len < 0)
11168 11172 scfdie();
11169 11173
11170 11174 fmri = safe_malloc(len + 1);
11171 11175
11172 11176 if (scf_instance_to_fmri(inst, fmri,
11173 11177 len + 1) < 0)
11174 11178 scfdie();
11175 11179
11176 11180 warn("Instance %s has no \"%s\" "
11177 11181 "property group.\n", fmri,
11178 11182 scf_pg_general);
11179 11183
11180 11184 free(fmri);
11181 11185 }
11182 11186
11183 11187 continue;
11184 11188 }
11185 11189
11186 11190 if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
11187 11191 prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
11188 11192 prop_get_val(prop, val) != 0)
11189 11193 continue;
11190 11194
11191 11195 inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
11192 11196 NULL);
11193 11197 if (inode == NULL)
11194 11198 uu_die(emsg_create_xml);
11195 11199
11196 11200 if (scf_instance_get_name(inst, namebuf,
11197 11201 max_scf_name_len + 1) < 0)
11198 11202 scfdie();
11199 11203
11200 11204 safe_setprop(inode, name_attr, namebuf);
11201 11205
11202 11206 if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
11203 11207 scfdie();
11204 11208
11205 11209 safe_setprop(inode, enabled_attr, b ? true : false);
11206 11210 }
11207 11211 if (s < 0)
11208 11212 scfdie();
11209 11213
11210 11214 if (snode->children != NULL)
11211 11215 (void) xmlAddChild(sb, snode);
11212 11216 else
11213 11217 xmlFreeNode(snode);
11214 11218 }
11215 11219 if (r < 0)
11216 11220 scfdie();
11217 11221
11218 11222 free(namebuf);
11219 11223
11220 11224 result = write_service_bundle(doc, f);
11221 11225
11222 11226 xmlFreeDoc(doc);
11223 11227
11224 11228 if (f != stdout)
11225 11229 (void) fclose(f);
11226 11230
11227 11231 return (result);
11228 11232 }
11229 11233
11230 11234
11231 11235 /*
11232 11236 * Entity manipulation commands
11233 11237 */
11234 11238
11235 11239 /*
11236 11240 * Entity selection. If no entity is selected, then the current scope is in
11237 11241 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected,
11238 11242 * only cur_inst is NULL, and when an instance is selected, none are NULL.
11239 11243 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
11240 11244 * cur_inst will be non-NULL.
11241 11245 */
11242 11246
11243 11247 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
11244 11248 static int
11245 11249 select_inst(const char *name)
11246 11250 {
11247 11251 scf_instance_t *inst;
11248 11252 scf_error_t err;
11249 11253
11250 11254 assert(cur_svc != NULL);
11251 11255
11252 11256 inst = scf_instance_create(g_hndl);
11253 11257 if (inst == NULL)
11254 11258 scfdie();
11255 11259
11256 11260 if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
11257 11261 cur_inst = inst;
11258 11262 return (0);
11259 11263 }
11260 11264
11261 11265 err = scf_error();
11262 11266 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11263 11267 scfdie();
11264 11268
11265 11269 scf_instance_destroy(inst);
11266 11270 return (1);
11267 11271 }
11268 11272
11269 11273 /* Returns as above. */
11270 11274 static int
11271 11275 select_svc(const char *name)
11272 11276 {
11273 11277 scf_service_t *svc;
11274 11278 scf_error_t err;
11275 11279
11276 11280 assert(cur_scope != NULL);
11277 11281
11278 11282 svc = scf_service_create(g_hndl);
11279 11283 if (svc == NULL)
11280 11284 scfdie();
11281 11285
11282 11286 if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
11283 11287 cur_svc = svc;
11284 11288 return (0);
11285 11289 }
11286 11290
11287 11291 err = scf_error();
11288 11292 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11289 11293 scfdie();
11290 11294
11291 11295 scf_service_destroy(svc);
11292 11296 return (1);
11293 11297 }
11294 11298
11295 11299 /* ARGSUSED */
11296 11300 static int
11297 11301 select_callback(void *unused, scf_walkinfo_t *wip)
11298 11302 {
11299 11303 scf_instance_t *inst;
11300 11304 scf_service_t *svc;
11301 11305 scf_scope_t *scope;
11302 11306
11303 11307 if (wip->inst != NULL) {
11304 11308 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11305 11309 (svc = scf_service_create(g_hndl)) == NULL ||
11306 11310 (inst = scf_instance_create(g_hndl)) == NULL)
11307 11311 scfdie();
11308 11312
11309 11313 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11310 11314 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11311 11315 scfdie();
11312 11316 } else {
11313 11317 assert(wip->svc != NULL);
11314 11318
11315 11319 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11316 11320 (svc = scf_service_create(g_hndl)) == NULL)
11317 11321 scfdie();
11318 11322
11319 11323 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11320 11324 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11321 11325 scfdie();
11322 11326
11323 11327 inst = NULL;
11324 11328 }
11325 11329
11326 11330 /* Clear out the current selection */
11327 11331 assert(cur_scope != NULL);
11328 11332 scf_scope_destroy(cur_scope);
11329 11333 scf_service_destroy(cur_svc);
11330 11334 scf_instance_destroy(cur_inst);
11331 11335
11332 11336 cur_scope = scope;
11333 11337 cur_svc = svc;
11334 11338 cur_inst = inst;
11335 11339
11336 11340 return (0);
11337 11341 }
11338 11342
11339 11343 static int
11340 11344 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
11341 11345 {
11342 11346 char **fmri = fmri_p;
11343 11347
11344 11348 *fmri = strdup(wip->fmri);
11345 11349 if (*fmri == NULL)
11346 11350 uu_die(gettext("Out of memory.\n"));
11347 11351
11348 11352 return (0);
11349 11353 }
11350 11354
11351 11355 /*
11352 11356 * validate [fmri]
11353 11357 * Perform the validation of an FMRI instance.
11354 11358 */
11355 11359 void
11356 11360 lscf_validate_fmri(const char *fmri)
11357 11361 {
11358 11362 int ret = 0;
11359 11363 size_t inst_sz;
11360 11364 char *inst_fmri = NULL;
11361 11365 scf_tmpl_errors_t *errs = NULL;
11362 11366 char *snapbuf = NULL;
11363 11367
11364 11368 lscf_prep_hndl();
11365 11369
11366 11370 if (fmri == NULL) {
11367 11371 inst_sz = max_scf_fmri_len + 1;
11368 11372 inst_fmri = safe_malloc(inst_sz);
11369 11373
11370 11374 if (cur_snap != NULL) {
11371 11375 snapbuf = safe_malloc(max_scf_name_len + 1);
11372 11376 if (scf_snapshot_get_name(cur_snap, snapbuf,
11373 11377 max_scf_name_len + 1) < 0)
11374 11378 scfdie();
11375 11379 }
11376 11380 if (cur_inst == NULL) {
11377 11381 semerr(gettext("No instance selected\n"));
11378 11382 goto cleanup;
11379 11383 } else if (scf_instance_to_fmri(cur_inst, inst_fmri,
11380 11384 inst_sz) >= inst_sz) {
11381 11385 /* sanity check. Should never get here */
11382 11386 uu_die(gettext("Unexpected error! file %s, line %d\n"),
11383 11387 __FILE__, __LINE__);
11384 11388 }
11385 11389 } else {
11386 11390 scf_error_t scf_err;
11387 11391 int err = 0;
11388 11392
11389 11393 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
11390 11394 validate_callback, &inst_fmri, &err, semerr)) != 0) {
11391 11395 uu_warn("Failed to walk instances: %s\n",
11392 11396 scf_strerror(scf_err));
11393 11397 goto cleanup;
11394 11398 }
11395 11399 if (err != 0) {
11396 11400 /* error message displayed by scf_walk_fmri */
11397 11401 goto cleanup;
11398 11402 }
11399 11403 }
11400 11404
11401 11405 ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
11402 11406 SCF_TMPL_VALIDATE_FLAG_CURRENT);
11403 11407 if (ret == -1) {
11404 11408 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
11405 11409 warn(gettext("Template data for %s is invalid. "
11406 11410 "Consider reverting to a previous snapshot or "
11407 11411 "restoring original configuration.\n"), inst_fmri);
11408 11412 } else {
11409 11413 uu_warn("%s: %s\n",
11410 11414 gettext("Error validating the instance"),
11411 11415 scf_strerror(scf_error()));
11412 11416 }
11413 11417 } else if (ret == 1 && errs != NULL) {
11414 11418 scf_tmpl_error_t *err = NULL;
11415 11419 char *msg;
11416 11420 size_t len = 256; /* initial error buffer size */
11417 11421 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
11418 11422 SCF_TMPL_STRERROR_HUMAN : 0;
11419 11423
11420 11424 msg = safe_malloc(len);
11421 11425
11422 11426 while ((err = scf_tmpl_next_error(errs)) != NULL) {
11423 11427 int ret;
11424 11428
11425 11429 if ((ret = scf_tmpl_strerror(err, msg, len,
11426 11430 flag)) >= len) {
11427 11431 len = ret + 1;
11428 11432 msg = realloc(msg, len);
11429 11433 if (msg == NULL)
11430 11434 uu_die(gettext(
11431 11435 "Out of memory.\n"));
11432 11436 (void) scf_tmpl_strerror(err, msg, len,
11433 11437 flag);
11434 11438 }
11435 11439 (void) fprintf(stderr, "%s\n", msg);
11436 11440 }
11437 11441 if (msg != NULL)
11438 11442 free(msg);
11439 11443 }
11440 11444 if (errs != NULL)
11441 11445 scf_tmpl_errors_destroy(errs);
11442 11446
11443 11447 cleanup:
11444 11448 free(inst_fmri);
11445 11449 free(snapbuf);
11446 11450 }
11447 11451
11448 11452 static void
11449 11453 lscf_validate_file(const char *filename)
11450 11454 {
11451 11455 tmpl_errors_t *errs;
11452 11456
11453 11457 bundle_t *b = internal_bundle_new();
11454 11458 if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
11455 11459 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
11456 11460 tmpl_errors_print(stderr, errs, "");
11457 11461 semerr(gettext("Validation failed.\n"));
11458 11462 }
11459 11463 tmpl_errors_destroy(errs);
11460 11464 }
11461 11465 (void) internal_bundle_free(b);
11462 11466 }
11463 11467
11464 11468 /*
11465 11469 * validate [fmri|file]
11466 11470 */
11467 11471 void
11468 11472 lscf_validate(const char *arg)
11469 11473 {
11470 11474 const char *str;
11471 11475
11472 11476 if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
11473 11477 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
11474 11478 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
11475 11479 lscf_validate_file(str);
11476 11480 } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
11477 11481 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
11478 11482 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
11479 11483 lscf_validate_fmri(str);
11480 11484 } else if (access(arg, R_OK | F_OK) == 0) {
11481 11485 lscf_validate_file(arg);
11482 11486 } else {
11483 11487 lscf_validate_fmri(arg);
11484 11488 }
11485 11489 }
11486 11490
11487 11491 void
11488 11492 lscf_select(const char *fmri)
11489 11493 {
11490 11494 int ret, err;
11491 11495
11492 11496 lscf_prep_hndl();
11493 11497
11494 11498 if (cur_snap != NULL) {
11495 11499 struct snaplevel *elt;
11496 11500 char *buf;
11497 11501
11498 11502 /* Error unless name is that of the next level. */
11499 11503 elt = uu_list_next(cur_levels, cur_elt);
11500 11504 if (elt == NULL) {
11501 11505 semerr(gettext("No children.\n"));
11502 11506 return;
11503 11507 }
11504 11508
11505 11509 buf = safe_malloc(max_scf_name_len + 1);
11506 11510
11507 11511 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11508 11512 max_scf_name_len + 1) < 0)
11509 11513 scfdie();
11510 11514
11511 11515 if (strcmp(buf, fmri) != 0) {
11512 11516 semerr(gettext("No such child.\n"));
11513 11517 free(buf);
11514 11518 return;
11515 11519 }
11516 11520
11517 11521 free(buf);
11518 11522
11519 11523 cur_elt = elt;
11520 11524 cur_level = elt->sl;
11521 11525 return;
11522 11526 }
11523 11527
11524 11528 /*
11525 11529 * Special case for 'svc:', which takes the user to the scope level.
11526 11530 */
11527 11531 if (strcmp(fmri, "svc:") == 0) {
11528 11532 scf_instance_destroy(cur_inst);
11529 11533 scf_service_destroy(cur_svc);
11530 11534 cur_inst = NULL;
11531 11535 cur_svc = NULL;
11532 11536 return;
11533 11537 }
11534 11538
11535 11539 /*
11536 11540 * Special case for ':properties'. This appears as part of 'list' but
11537 11541 * can't be selected. Give a more helpful error message in this case.
11538 11542 */
11539 11543 if (strcmp(fmri, ":properties") == 0) {
11540 11544 semerr(gettext(":properties is not an entity. Try 'listprop' "
11541 11545 "to list properties.\n"));
11542 11546 return;
11543 11547 }
11544 11548
11545 11549 /*
11546 11550 * First try the argument as relative to the current selection.
11547 11551 */
11548 11552 if (cur_inst != NULL) {
11549 11553 /* EMPTY */;
11550 11554 } else if (cur_svc != NULL) {
11551 11555 if (select_inst(fmri) != 1)
11552 11556 return;
11553 11557 } else {
11554 11558 if (select_svc(fmri) != 1)
11555 11559 return;
11556 11560 }
11557 11561
11558 11562 err = 0;
11559 11563 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11560 11564 select_callback, NULL, &err, semerr)) != 0) {
11561 11565 semerr(gettext("Failed to walk instances: %s\n"),
11562 11566 scf_strerror(ret));
11563 11567 }
11564 11568 }
11565 11569
11566 11570 void
11567 11571 lscf_unselect(void)
11568 11572 {
11569 11573 lscf_prep_hndl();
11570 11574
11571 11575 if (cur_snap != NULL) {
11572 11576 struct snaplevel *elt;
11573 11577
11574 11578 elt = uu_list_prev(cur_levels, cur_elt);
11575 11579 if (elt == NULL) {
11576 11580 semerr(gettext("No parent levels.\n"));
11577 11581 } else {
11578 11582 cur_elt = elt;
11579 11583 cur_level = elt->sl;
11580 11584 }
11581 11585 } else if (cur_inst != NULL) {
11582 11586 scf_instance_destroy(cur_inst);
11583 11587 cur_inst = NULL;
11584 11588 } else if (cur_svc != NULL) {
11585 11589 scf_service_destroy(cur_svc);
11586 11590 cur_svc = NULL;
11587 11591 } else {
11588 11592 semerr(gettext("Cannot unselect at scope level.\n"));
11589 11593 }
11590 11594 }
11591 11595
11592 11596 /*
11593 11597 * Return the FMRI of the current selection, for the prompt.
11594 11598 */
11595 11599 void
11596 11600 lscf_get_selection_str(char *buf, size_t bufsz)
11597 11601 {
11598 11602 char *cp;
11599 11603 ssize_t fmrilen, szret;
11600 11604 boolean_t deleted = B_FALSE;
11601 11605
11602 11606 if (g_hndl == NULL) {
11603 11607 (void) strlcpy(buf, "svc:", bufsz);
11604 11608 return;
11605 11609 }
11606 11610
11607 11611 if (cur_level != NULL) {
11608 11612 assert(cur_snap != NULL);
11609 11613
11610 11614 /* [ snapshot ] FMRI [: instance ] */
11611 11615 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11612 11616 + 2 + max_scf_name_len + 1 + 1);
11613 11617
11614 11618 buf[0] = '[';
11615 11619
11616 11620 szret = scf_snapshot_get_name(cur_snap, buf + 1,
11617 11621 max_scf_name_len + 1);
11618 11622 if (szret < 0) {
11619 11623 if (scf_error() != SCF_ERROR_DELETED)
11620 11624 scfdie();
11621 11625
11622 11626 goto snap_deleted;
11623 11627 }
11624 11628
11625 11629 (void) strcat(buf, "]svc:/");
11626 11630
11627 11631 cp = strchr(buf, '\0');
11628 11632
11629 11633 szret = scf_snaplevel_get_service_name(cur_level, cp,
11630 11634 max_scf_name_len + 1);
11631 11635 if (szret < 0) {
11632 11636 if (scf_error() != SCF_ERROR_DELETED)
11633 11637 scfdie();
11634 11638
11635 11639 goto snap_deleted;
11636 11640 }
11637 11641
11638 11642 cp = strchr(cp, '\0');
11639 11643
11640 11644 if (snaplevel_is_instance(cur_level)) {
11641 11645 *cp++ = ':';
11642 11646
11643 11647 if (scf_snaplevel_get_instance_name(cur_level, cp,
11644 11648 max_scf_name_len + 1) < 0) {
11645 11649 if (scf_error() != SCF_ERROR_DELETED)
11646 11650 scfdie();
11647 11651
11648 11652 goto snap_deleted;
11649 11653 }
11650 11654 } else {
11651 11655 *cp++ = '[';
11652 11656 *cp++ = ':';
11653 11657
11654 11658 if (scf_instance_get_name(cur_inst, cp,
11655 11659 max_scf_name_len + 1) < 0) {
11656 11660 if (scf_error() != SCF_ERROR_DELETED)
11657 11661 scfdie();
11658 11662
11659 11663 goto snap_deleted;
11660 11664 }
11661 11665
11662 11666 (void) strcat(buf, "]");
11663 11667 }
11664 11668
11665 11669 return;
11666 11670
11667 11671 snap_deleted:
11668 11672 deleted = B_TRUE;
11669 11673 free(buf);
11670 11674 unselect_cursnap();
11671 11675 }
11672 11676
11673 11677 assert(cur_snap == NULL);
11674 11678
11675 11679 if (cur_inst != NULL) {
11676 11680 assert(cur_svc != NULL);
11677 11681 assert(cur_scope != NULL);
11678 11682
11679 11683 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11680 11684 if (fmrilen >= 0) {
11681 11685 assert(fmrilen < bufsz);
11682 11686 if (deleted)
11683 11687 warn(emsg_deleted);
11684 11688 return;
11685 11689 }
11686 11690
11687 11691 if (scf_error() != SCF_ERROR_DELETED)
11688 11692 scfdie();
11689 11693
11690 11694 deleted = B_TRUE;
11691 11695
11692 11696 scf_instance_destroy(cur_inst);
11693 11697 cur_inst = NULL;
11694 11698 }
11695 11699
11696 11700 if (cur_svc != NULL) {
11697 11701 assert(cur_scope != NULL);
11698 11702
11699 11703 szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11700 11704 if (szret >= 0) {
11701 11705 assert(szret < bufsz);
11702 11706 if (deleted)
11703 11707 warn(emsg_deleted);
11704 11708 return;
11705 11709 }
11706 11710
11707 11711 if (scf_error() != SCF_ERROR_DELETED)
11708 11712 scfdie();
11709 11713
11710 11714 deleted = B_TRUE;
11711 11715 scf_service_destroy(cur_svc);
11712 11716 cur_svc = NULL;
11713 11717 }
11714 11718
11715 11719 assert(cur_scope != NULL);
11716 11720 fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11717 11721
11718 11722 if (fmrilen < 0)
11719 11723 scfdie();
11720 11724
11721 11725 assert(fmrilen < bufsz);
11722 11726 if (deleted)
11723 11727 warn(emsg_deleted);
11724 11728 }
11725 11729
11726 11730 /*
11727 11731 * Entity listing. Entities and colon namespaces (e.g., :properties and
11728 11732 * :statistics) are listed for the current selection.
11729 11733 */
11730 11734 void
11731 11735 lscf_list(const char *pattern)
11732 11736 {
11733 11737 scf_iter_t *iter;
11734 11738 char *buf;
11735 11739 int ret;
11736 11740
11737 11741 lscf_prep_hndl();
11738 11742
11739 11743 if (cur_level != NULL) {
11740 11744 struct snaplevel *elt;
11741 11745
11742 11746 (void) fputs(COLON_NAMESPACES, stdout);
11743 11747
11744 11748 elt = uu_list_next(cur_levels, cur_elt);
11745 11749 if (elt == NULL)
11746 11750 return;
11747 11751
11748 11752 /*
11749 11753 * For now, we know that the next level is an instance. But
11750 11754 * if we ever have multiple scopes, this could be complicated.
11751 11755 */
11752 11756 buf = safe_malloc(max_scf_name_len + 1);
11753 11757 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11754 11758 max_scf_name_len + 1) >= 0) {
11755 11759 (void) puts(buf);
11756 11760 } else {
11757 11761 if (scf_error() != SCF_ERROR_DELETED)
11758 11762 scfdie();
11759 11763 }
11760 11764
11761 11765 free(buf);
11762 11766
11763 11767 return;
11764 11768 }
11765 11769
11766 11770 if (cur_inst != NULL) {
11767 11771 (void) fputs(COLON_NAMESPACES, stdout);
11768 11772 return;
11769 11773 }
11770 11774
11771 11775 iter = scf_iter_create(g_hndl);
11772 11776 if (iter == NULL)
11773 11777 scfdie();
11774 11778
11775 11779 buf = safe_malloc(max_scf_name_len + 1);
11776 11780
11777 11781 if (cur_svc != NULL) {
11778 11782 /* List the instances in this service. */
11779 11783 scf_instance_t *inst;
11780 11784
11781 11785 inst = scf_instance_create(g_hndl);
11782 11786 if (inst == NULL)
11783 11787 scfdie();
11784 11788
11785 11789 if (scf_iter_service_instances(iter, cur_svc) == 0) {
11786 11790 safe_printf(COLON_NAMESPACES);
11787 11791
11788 11792 for (;;) {
11789 11793 ret = scf_iter_next_instance(iter, inst);
11790 11794 if (ret == 0)
11791 11795 break;
11792 11796 if (ret != 1) {
11793 11797 if (scf_error() != SCF_ERROR_DELETED)
11794 11798 scfdie();
11795 11799
11796 11800 break;
11797 11801 }
11798 11802
11799 11803 if (scf_instance_get_name(inst, buf,
11800 11804 max_scf_name_len + 1) >= 0) {
11801 11805 if (pattern == NULL ||
11802 11806 fnmatch(pattern, buf, 0) == 0)
11803 11807 (void) puts(buf);
11804 11808 } else {
11805 11809 if (scf_error() != SCF_ERROR_DELETED)
11806 11810 scfdie();
11807 11811 }
11808 11812 }
11809 11813 } else {
11810 11814 if (scf_error() != SCF_ERROR_DELETED)
11811 11815 scfdie();
11812 11816 }
11813 11817
11814 11818 scf_instance_destroy(inst);
11815 11819 } else {
11816 11820 /* List the services in this scope. */
11817 11821 scf_service_t *svc;
11818 11822
11819 11823 assert(cur_scope != NULL);
11820 11824
11821 11825 svc = scf_service_create(g_hndl);
11822 11826 if (svc == NULL)
11823 11827 scfdie();
11824 11828
11825 11829 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11826 11830 scfdie();
11827 11831
11828 11832 for (;;) {
11829 11833 ret = scf_iter_next_service(iter, svc);
11830 11834 if (ret == 0)
11831 11835 break;
11832 11836 if (ret != 1)
11833 11837 scfdie();
11834 11838
11835 11839 if (scf_service_get_name(svc, buf,
11836 11840 max_scf_name_len + 1) >= 0) {
11837 11841 if (pattern == NULL ||
11838 11842 fnmatch(pattern, buf, 0) == 0)
11839 11843 safe_printf("%s\n", buf);
11840 11844 } else {
11841 11845 if (scf_error() != SCF_ERROR_DELETED)
11842 11846 scfdie();
11843 11847 }
11844 11848 }
11845 11849
11846 11850 scf_service_destroy(svc);
11847 11851 }
11848 11852
11849 11853 free(buf);
11850 11854 scf_iter_destroy(iter);
11851 11855 }
11852 11856
11853 11857 /*
11854 11858 * Entity addition. Creates an empty entity in the current selection.
11855 11859 */
11856 11860 void
11857 11861 lscf_add(const char *name)
11858 11862 {
11859 11863 lscf_prep_hndl();
11860 11864
11861 11865 if (cur_snap != NULL) {
11862 11866 semerr(emsg_cant_modify_snapshots);
11863 11867 } else if (cur_inst != NULL) {
11864 11868 semerr(gettext("Cannot add entities to an instance.\n"));
11865 11869 } else if (cur_svc != NULL) {
11866 11870
11867 11871 if (scf_service_add_instance(cur_svc, name, NULL) !=
11868 11872 SCF_SUCCESS) {
11869 11873 switch (scf_error()) {
11870 11874 case SCF_ERROR_INVALID_ARGUMENT:
11871 11875 semerr(gettext("Invalid name.\n"));
11872 11876 break;
11873 11877
11874 11878 case SCF_ERROR_EXISTS:
11875 11879 semerr(gettext("Instance already exists.\n"));
11876 11880 break;
11877 11881
11878 11882 case SCF_ERROR_PERMISSION_DENIED:
11879 11883 semerr(emsg_permission_denied);
11880 11884 break;
11881 11885
11882 11886 default:
11883 11887 scfdie();
11884 11888 }
11885 11889 }
11886 11890 } else {
11887 11891 assert(cur_scope != NULL);
11888 11892
11889 11893 if (scf_scope_add_service(cur_scope, name, NULL) !=
11890 11894 SCF_SUCCESS) {
11891 11895 switch (scf_error()) {
11892 11896 case SCF_ERROR_INVALID_ARGUMENT:
11893 11897 semerr(gettext("Invalid name.\n"));
11894 11898 break;
11895 11899
11896 11900 case SCF_ERROR_EXISTS:
11897 11901 semerr(gettext("Service already exists.\n"));
11898 11902 break;
11899 11903
11900 11904 case SCF_ERROR_PERMISSION_DENIED:
11901 11905 semerr(emsg_permission_denied);
11902 11906 break;
11903 11907
11904 11908 case SCF_ERROR_BACKEND_READONLY:
11905 11909 semerr(emsg_read_only);
11906 11910 break;
11907 11911
11908 11912 default:
11909 11913 scfdie();
11910 11914 }
11911 11915 }
11912 11916 }
11913 11917 }
11914 11918
11915 11919 /* return 1 if the entity has no persistent pgs, else return 0 */
11916 11920 static int
11917 11921 entity_has_no_pgs(void *ent, int isservice)
11918 11922 {
11919 11923 scf_iter_t *iter = NULL;
11920 11924 scf_propertygroup_t *pg = NULL;
11921 11925 uint32_t flags;
11922 11926 int err;
11923 11927 int ret = 1;
11924 11928
11925 11929 if ((iter = scf_iter_create(g_hndl)) == NULL ||
11926 11930 (pg = scf_pg_create(g_hndl)) == NULL)
11927 11931 scfdie();
11928 11932
11929 11933 if (isservice) {
11930 11934 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11931 11935 scfdie();
11932 11936 } else {
11933 11937 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11934 11938 scfdie();
11935 11939 }
11936 11940
11937 11941 while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11938 11942 if (scf_pg_get_flags(pg, &flags) != 0)
11939 11943 scfdie();
11940 11944
11941 11945 /* skip nonpersistent pgs */
11942 11946 if (flags & SCF_PG_FLAG_NONPERSISTENT)
11943 11947 continue;
11944 11948
11945 11949 ret = 0;
11946 11950 break;
11947 11951 }
11948 11952
11949 11953 if (err == -1)
11950 11954 scfdie();
11951 11955
11952 11956 scf_pg_destroy(pg);
11953 11957 scf_iter_destroy(iter);
11954 11958
11955 11959 return (ret);
11956 11960 }
11957 11961
11958 11962 /* return 1 if the service has no instances, else return 0 */
11959 11963 static int
11960 11964 svc_has_no_insts(scf_service_t *svc)
11961 11965 {
11962 11966 scf_instance_t *inst;
11963 11967 scf_iter_t *iter;
11964 11968 int r;
11965 11969 int ret = 1;
11966 11970
11967 11971 if ((inst = scf_instance_create(g_hndl)) == NULL ||
11968 11972 (iter = scf_iter_create(g_hndl)) == NULL)
11969 11973 scfdie();
11970 11974
11971 11975 if (scf_iter_service_instances(iter, svc) != 0)
11972 11976 scfdie();
11973 11977
11974 11978 r = scf_iter_next_instance(iter, inst);
11975 11979 if (r == 1) {
11976 11980 ret = 0;
11977 11981 } else if (r == 0) {
11978 11982 ret = 1;
11979 11983 } else if (r == -1) {
11980 11984 scfdie();
11981 11985 } else {
11982 11986 bad_error("scf_iter_next_instance", r);
11983 11987 }
11984 11988
11985 11989 scf_iter_destroy(iter);
11986 11990 scf_instance_destroy(inst);
11987 11991
11988 11992 return (ret);
11989 11993 }
11990 11994
11991 11995 /*
11992 11996 * Entity deletion.
11993 11997 */
11994 11998
11995 11999 /*
11996 12000 * Delete the property group <fmri>/:properties/<name>. Returns
11997 12001 * SCF_ERROR_NONE on success (or if the entity is not found),
11998 12002 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
11999 12003 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
12000 12004 * denied.
12001 12005 */
12002 12006 static scf_error_t
12003 12007 delete_dependency_pg(const char *fmri, const char *name)
12004 12008 {
12005 12009 void *entity = NULL;
12006 12010 int isservice;
12007 12011 scf_propertygroup_t *pg = NULL;
12008 12012 scf_error_t result;
12009 12013 char *pgty;
12010 12014 scf_service_t *svc = NULL;
12011 12015 scf_instance_t *inst = NULL;
12012 12016 scf_iter_t *iter = NULL;
12013 12017 char *name_buf = NULL;
12014 12018
12015 12019 result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
12016 12020 switch (result) {
12017 12021 case SCF_ERROR_NONE:
12018 12022 break;
12019 12023
12020 12024 case SCF_ERROR_NO_MEMORY:
12021 12025 uu_die(gettext("Out of memory.\n"));
12022 12026 /* NOTREACHED */
12023 12027
12024 12028 case SCF_ERROR_INVALID_ARGUMENT:
12025 12029 case SCF_ERROR_CONSTRAINT_VIOLATED:
12026 12030 return (SCF_ERROR_INVALID_ARGUMENT);
12027 12031
12028 12032 case SCF_ERROR_NOT_FOUND:
12029 12033 result = SCF_ERROR_NONE;
12030 12034 goto out;
12031 12035
12032 12036 default:
12033 12037 bad_error("fmri_to_entity", result);
12034 12038 }
12035 12039
12036 12040 pg = scf_pg_create(g_hndl);
12037 12041 if (pg == NULL)
12038 12042 scfdie();
12039 12043
12040 12044 if (entity_get_pg(entity, isservice, name, pg) != 0) {
12041 12045 if (scf_error() != SCF_ERROR_NOT_FOUND)
12042 12046 scfdie();
12043 12047
12044 12048 result = SCF_ERROR_NONE;
12045 12049 goto out;
12046 12050 }
12047 12051
12048 12052 pgty = safe_malloc(max_scf_pg_type_len + 1);
12049 12053
12050 12054 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12051 12055 scfdie();
12052 12056
12053 12057 if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
12054 12058 result = SCF_ERROR_TYPE_MISMATCH;
12055 12059 free(pgty);
12056 12060 goto out;
12057 12061 }
12058 12062
12059 12063 free(pgty);
12060 12064
12061 12065 if (scf_pg_delete(pg) != 0) {
12062 12066 result = scf_error();
12063 12067 if (result != SCF_ERROR_PERMISSION_DENIED)
12064 12068 scfdie();
12065 12069 goto out;
12066 12070 }
12067 12071
12068 12072 /*
12069 12073 * We have to handle the case where we've just deleted the last
12070 12074 * property group of a "dummy" entity (instance or service).
12071 12075 * A "dummy" entity is an entity only present to hold an
12072 12076 * external dependency.
12073 12077 * So, in the case we deleted the last property group then we
12074 12078 * can also delete the entity. If the entity is an instance then
12075 12079 * we must verify if this was the last instance for the service
12076 12080 * and if it is, we can also delete the service if it doesn't
12077 12081 * have any property group either.
12078 12082 */
12079 12083
12080 12084 result = SCF_ERROR_NONE;
12081 12085
12082 12086 if (isservice) {
12083 12087 svc = (scf_service_t *)entity;
12084 12088
12085 12089 if ((inst = scf_instance_create(g_hndl)) == NULL ||
12086 12090 (iter = scf_iter_create(g_hndl)) == NULL)
12087 12091 scfdie();
12088 12092
12089 12093 name_buf = safe_malloc(max_scf_name_len + 1);
12090 12094 } else {
12091 12095 inst = (scf_instance_t *)entity;
12092 12096 }
12093 12097
12094 12098 /*
12095 12099 * If the entity is an instance and we've just deleted its last
12096 12100 * property group then we should delete it.
12097 12101 */
12098 12102 if (!isservice && entity_has_no_pgs(entity, isservice)) {
12099 12103 /* find the service before deleting the inst. - needed later */
12100 12104 if ((svc = scf_service_create(g_hndl)) == NULL)
12101 12105 scfdie();
12102 12106
12103 12107 if (scf_instance_get_parent(inst, svc) != 0)
12104 12108 scfdie();
12105 12109
12106 12110 /* delete the instance */
12107 12111 if (scf_instance_delete(inst) != 0) {
12108 12112 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12109 12113 scfdie();
12110 12114
12111 12115 result = SCF_ERROR_PERMISSION_DENIED;
12112 12116 goto out;
12113 12117 }
12114 12118 /* no need to refresh the instance */
12115 12119 inst = NULL;
12116 12120 }
12117 12121
12118 12122 /*
12119 12123 * If the service has no more instances and pgs or we just deleted the
12120 12124 * last instance and the service doesn't have anymore propery groups
12121 12125 * then the service should be deleted.
12122 12126 */
12123 12127 if (svc != NULL &&
12124 12128 svc_has_no_insts(svc) &&
12125 12129 entity_has_no_pgs((void *)svc, 1)) {
12126 12130 if (scf_service_delete(svc) == 0) {
12127 12131 if (isservice) {
12128 12132 /* no need to refresh the service */
12129 12133 svc = NULL;
12130 12134 }
12131 12135
12132 12136 goto out;
12133 12137 }
12134 12138
12135 12139 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12136 12140 scfdie();
12137 12141
12138 12142 result = SCF_ERROR_PERMISSION_DENIED;
12139 12143 }
12140 12144
12141 12145 /* if the entity has not been deleted, refresh it */
12142 12146 if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
12143 12147 (void) refresh_entity(isservice, entity, fmri, inst, iter,
12144 12148 name_buf);
12145 12149 }
12146 12150
12147 12151 out:
12148 12152 if (isservice && (inst != NULL && iter != NULL)) {
12149 12153 free(name_buf);
12150 12154 scf_iter_destroy(iter);
12151 12155 scf_instance_destroy(inst);
12152 12156 }
12153 12157
12154 12158 if (!isservice && svc != NULL) {
12155 12159 scf_service_destroy(svc);
12156 12160 }
12157 12161
12158 12162 scf_pg_destroy(pg);
12159 12163 if (entity != NULL)
12160 12164 entity_destroy(entity, isservice);
12161 12165
12162 12166 return (result);
12163 12167 }
12164 12168
12165 12169 static int
12166 12170 delete_dependents(scf_propertygroup_t *pg)
12167 12171 {
12168 12172 char *pgty, *name, *fmri;
12169 12173 scf_property_t *prop;
12170 12174 scf_value_t *val;
12171 12175 scf_iter_t *iter;
12172 12176 int r;
12173 12177 scf_error_t err;
12174 12178
12175 12179 /* Verify that the pg has the correct type. */
12176 12180 pgty = safe_malloc(max_scf_pg_type_len + 1);
12177 12181 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12178 12182 scfdie();
12179 12183
12180 12184 if (strcmp(pgty, scf_group_framework) != 0) {
12181 12185 if (g_verbose) {
12182 12186 fmri = safe_malloc(max_scf_fmri_len + 1);
12183 12187 if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
12184 12188 scfdie();
12185 12189
12186 12190 warn(gettext("Property group %s is not of expected "
12187 12191 "type %s.\n"), fmri, scf_group_framework);
12188 12192
12189 12193 free(fmri);
12190 12194 }
12191 12195
12192 12196 free(pgty);
12193 12197 return (-1);
12194 12198 }
12195 12199
12196 12200 free(pgty);
12197 12201
12198 12202 /* map delete_dependency_pg onto the properties. */
12199 12203 if ((prop = scf_property_create(g_hndl)) == NULL ||
12200 12204 (val = scf_value_create(g_hndl)) == NULL ||
12201 12205 (iter = scf_iter_create(g_hndl)) == NULL)
12202 12206 scfdie();
12203 12207
12204 12208 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
12205 12209 scfdie();
12206 12210
12207 12211 name = safe_malloc(max_scf_name_len + 1);
12208 12212 fmri = safe_malloc(max_scf_fmri_len + 2);
12209 12213
12210 12214 while ((r = scf_iter_next_property(iter, prop)) == 1) {
12211 12215 scf_type_t ty;
12212 12216
12213 12217 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
12214 12218 scfdie();
12215 12219
12216 12220 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
12217 12221 scfdie();
12218 12222
12219 12223 if ((ty != SCF_TYPE_ASTRING &&
12220 12224 prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
12221 12225 prop_get_val(prop, val) != 0)
12222 12226 continue;
12223 12227
12224 12228 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
12225 12229 scfdie();
12226 12230
12227 12231 err = delete_dependency_pg(fmri, name);
12228 12232 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
12229 12233 if (scf_property_to_fmri(prop, fmri,
12230 12234 max_scf_fmri_len + 2) < 0)
12231 12235 scfdie();
12232 12236
12233 12237 warn(gettext("Value of %s is not a valid FMRI.\n"),
12234 12238 fmri);
12235 12239 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
12236 12240 warn(gettext("Property group \"%s\" of entity \"%s\" "
12237 12241 "does not have dependency type.\n"), name, fmri);
12238 12242 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
12239 12243 warn(gettext("Could not delete property group \"%s\" "
12240 12244 "of entity \"%s\" (permission denied).\n"), name,
12241 12245 fmri);
12242 12246 }
12243 12247 }
12244 12248 if (r == -1)
12245 12249 scfdie();
12246 12250
12247 12251 scf_value_destroy(val);
12248 12252 scf_property_destroy(prop);
12249 12253
12250 12254 return (0);
12251 12255 }
12252 12256
12253 12257 /*
12254 12258 * Returns 1 if the instance may be running, and 0 otherwise.
12255 12259 */
12256 12260 static int
12257 12261 inst_is_running(scf_instance_t *inst)
12258 12262 {
12259 12263 scf_propertygroup_t *pg;
12260 12264 scf_property_t *prop;
12261 12265 scf_value_t *val;
12262 12266 char buf[MAX_SCF_STATE_STRING_SZ];
12263 12267 int ret = 0;
12264 12268 ssize_t szret;
12265 12269
12266 12270 if ((pg = scf_pg_create(g_hndl)) == NULL ||
12267 12271 (prop = scf_property_create(g_hndl)) == NULL ||
12268 12272 (val = scf_value_create(g_hndl)) == NULL)
12269 12273 scfdie();
12270 12274
12271 12275 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
12272 12276 if (scf_error() != SCF_ERROR_NOT_FOUND)
12273 12277 scfdie();
12274 12278 goto out;
12275 12279 }
12276 12280
12277 12281 if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
12278 12282 prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
12279 12283 prop_get_val(prop, val) != 0)
12280 12284 goto out;
12281 12285
12282 12286 szret = scf_value_get_astring(val, buf, sizeof (buf));
12283 12287 assert(szret >= 0);
12284 12288
12285 12289 ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
12286 12290 strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
12287 12291
12288 12292 out:
12289 12293 scf_value_destroy(val);
12290 12294 scf_property_destroy(prop);
12291 12295 scf_pg_destroy(pg);
12292 12296 return (ret);
12293 12297 }
12294 12298
12295 12299 static uint8_t
12296 12300 pg_is_external_dependency(scf_propertygroup_t *pg)
12297 12301 {
12298 12302 char *type;
12299 12303 scf_value_t *val;
12300 12304 scf_property_t *prop;
12301 12305 uint8_t b = B_FALSE;
12302 12306
12303 12307 type = safe_malloc(max_scf_pg_type_len + 1);
12304 12308
12305 12309 if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
12306 12310 scfdie();
12307 12311
12308 12312 if ((prop = scf_property_create(g_hndl)) == NULL ||
12309 12313 (val = scf_value_create(g_hndl)) == NULL)
12310 12314 scfdie();
12311 12315
12312 12316 if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
12313 12317 if (pg_get_prop(pg, scf_property_external, prop) == 0) {
12314 12318 if (scf_property_get_value(prop, val) != 0)
12315 12319 scfdie();
12316 12320 if (scf_value_get_boolean(val, &b) != 0)
12317 12321 scfdie();
12318 12322 }
12319 12323 }
12320 12324
12321 12325 free(type);
12322 12326 (void) scf_value_destroy(val);
12323 12327 (void) scf_property_destroy(prop);
12324 12328
12325 12329 return (b);
12326 12330 }
12327 12331
12328 12332 #define DELETE_FAILURE -1
12329 12333 #define DELETE_SUCCESS_NOEXTDEPS 0
12330 12334 #define DELETE_SUCCESS_EXTDEPS 1
12331 12335
12332 12336 /*
12333 12337 * lscf_instance_delete() deletes an instance. Before calling
12334 12338 * scf_instance_delete(), though, we make sure the instance isn't
12335 12339 * running and delete dependencies in other entities which the instance
12336 12340 * declared as "dependents". If there are dependencies which were
12337 12341 * created for other entities, then instead of deleting the instance we
12338 12342 * make it "empty" by deleting all other property groups and all
12339 12343 * snapshots.
12340 12344 *
12341 12345 * lscf_instance_delete() verifies that there is no external dependency pgs
12342 12346 * before suppressing the instance. If there is, then we must not remove them
12343 12347 * now in case the instance is re-created otherwise the dependencies would be
12344 12348 * lost. The external dependency pgs will be removed if the dependencies are
12345 12349 * removed.
12346 12350 *
12347 12351 * Returns:
12348 12352 * DELETE_FAILURE on failure
12349 12353 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12350 12354 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12351 12355 */
12352 12356 static int
12353 12357 lscf_instance_delete(scf_instance_t *inst, int force)
12354 12358 {
12355 12359 scf_propertygroup_t *pg;
12356 12360 scf_snapshot_t *snap;
12357 12361 scf_iter_t *iter;
12358 12362 int err;
12359 12363 int external = 0;
12360 12364
12361 12365 /* If we're not forcing and the instance is running, refuse. */
12362 12366 if (!force && inst_is_running(inst)) {
12363 12367 char *fmri;
12364 12368
12365 12369 fmri = safe_malloc(max_scf_fmri_len + 1);
12366 12370
12367 12371 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
12368 12372 scfdie();
12369 12373
12370 12374 semerr(gettext("Instance %s may be running. "
12371 12375 "Use delete -f if it is not.\n"), fmri);
12372 12376
12373 12377 free(fmri);
12374 12378 return (DELETE_FAILURE);
12375 12379 }
12376 12380
12377 12381 pg = scf_pg_create(g_hndl);
12378 12382 if (pg == NULL)
12379 12383 scfdie();
12380 12384
12381 12385 if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
12382 12386 (void) delete_dependents(pg);
12383 12387 else if (scf_error() != SCF_ERROR_NOT_FOUND)
12384 12388 scfdie();
12385 12389
12386 12390 scf_pg_destroy(pg);
12387 12391
12388 12392 /*
12389 12393 * If the instance has some external dependencies then we must
12390 12394 * keep them in case the instance is reimported otherwise the
12391 12395 * dependencies would be lost on reimport.
12392 12396 */
12393 12397 if ((iter = scf_iter_create(g_hndl)) == NULL ||
12394 12398 (pg = scf_pg_create(g_hndl)) == NULL)
12395 12399 scfdie();
12396 12400
12397 12401 if (scf_iter_instance_pgs(iter, inst) < 0)
12398 12402 scfdie();
12399 12403
12400 12404 while ((err = scf_iter_next_pg(iter, pg)) == 1) {
12401 12405 if (pg_is_external_dependency(pg)) {
12402 12406 external = 1;
12403 12407 continue;
12404 12408 }
12405 12409
12406 12410 if (scf_pg_delete(pg) != 0) {
12407 12411 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12408 12412 scfdie();
12409 12413 else {
12410 12414 semerr(emsg_permission_denied);
12411 12415
12412 12416 (void) scf_iter_destroy(iter);
12413 12417 (void) scf_pg_destroy(pg);
12414 12418 return (DELETE_FAILURE);
12415 12419 }
12416 12420 }
12417 12421 }
12418 12422
12419 12423 if (err == -1)
12420 12424 scfdie();
12421 12425
12422 12426 (void) scf_iter_destroy(iter);
12423 12427 (void) scf_pg_destroy(pg);
12424 12428
12425 12429 if (external) {
12426 12430 /*
12427 12431 * All the pgs have been deleted for the instance except
12428 12432 * the ones holding the external dependencies.
12429 12433 * For the job to be complete, we must also delete the
12430 12434 * snapshots associated with the instance.
12431 12435 */
12432 12436 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
12433 12437 NULL)
12434 12438 scfdie();
12435 12439 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
12436 12440 scfdie();
12437 12441
12438 12442 if (scf_iter_instance_snapshots(iter, inst) == -1)
12439 12443 scfdie();
12440 12444
12441 12445 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
12442 12446 if (_scf_snapshot_delete(snap) != 0) {
12443 12447 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12444 12448 scfdie();
12445 12449
12446 12450 semerr(emsg_permission_denied);
12447 12451
12448 12452 (void) scf_iter_destroy(iter);
12449 12453 (void) scf_snapshot_destroy(snap);
12450 12454 return (DELETE_FAILURE);
12451 12455 }
12452 12456 }
12453 12457
12454 12458 if (err == -1)
12455 12459 scfdie();
12456 12460
12457 12461 (void) scf_iter_destroy(iter);
12458 12462 (void) scf_snapshot_destroy(snap);
12459 12463 return (DELETE_SUCCESS_EXTDEPS);
12460 12464 }
12461 12465
12462 12466 if (scf_instance_delete(inst) != 0) {
12463 12467 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12464 12468 scfdie();
12465 12469
12466 12470 semerr(emsg_permission_denied);
12467 12471
12468 12472 return (DELETE_FAILURE);
12469 12473 }
12470 12474
12471 12475 return (DELETE_SUCCESS_NOEXTDEPS);
12472 12476 }
12473 12477
12474 12478 /*
12475 12479 * lscf_service_delete() deletes a service. Before calling
12476 12480 * scf_service_delete(), though, we call lscf_instance_delete() for
12477 12481 * each of the instances and delete dependencies in other entities
12478 12482 * which were created as "dependents" of this service. If there are
12479 12483 * dependencies which were created for other entities, then we delete
12480 12484 * all other property groups in the service and leave it as "empty".
12481 12485 *
12482 12486 * lscf_service_delete() verifies that there is no external dependency
12483 12487 * pgs at the instance & service level before suppressing the service.
12484 12488 * If there is, then we must not remove them now in case the service
12485 12489 * is re-imported otherwise the dependencies would be lost. The external
12486 12490 * dependency pgs will be removed if the dependencies are removed.
12487 12491 *
12488 12492 * Returns:
12489 12493 * DELETE_FAILURE on failure
12490 12494 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
12491 12495 * DELETE_SUCCESS_EXTDEPS on success - external dependencies
12492 12496 */
12493 12497 static int
12494 12498 lscf_service_delete(scf_service_t *svc, int force)
12495 12499 {
12496 12500 int r;
12497 12501 scf_instance_t *inst;
12498 12502 scf_propertygroup_t *pg;
12499 12503 scf_iter_t *iter;
12500 12504 int ret;
12501 12505 int external = 0;
12502 12506
12503 12507 if ((inst = scf_instance_create(g_hndl)) == NULL ||
12504 12508 (pg = scf_pg_create(g_hndl)) == NULL ||
12505 12509 (iter = scf_iter_create(g_hndl)) == NULL)
12506 12510 scfdie();
12507 12511
12508 12512 if (scf_iter_service_instances(iter, svc) != 0)
12509 12513 scfdie();
12510 12514
12511 12515 for (r = scf_iter_next_instance(iter, inst);
12512 12516 r == 1;
12513 12517 r = scf_iter_next_instance(iter, inst)) {
12514 12518
12515 12519 ret = lscf_instance_delete(inst, force);
12516 12520 if (ret == DELETE_FAILURE) {
12517 12521 scf_iter_destroy(iter);
12518 12522 scf_pg_destroy(pg);
12519 12523 scf_instance_destroy(inst);
12520 12524 return (DELETE_FAILURE);
12521 12525 }
12522 12526
12523 12527 /*
12524 12528 * Record the fact that there is some external dependencies
12525 12529 * at the instance level.
12526 12530 */
12527 12531 if (ret == DELETE_SUCCESS_EXTDEPS)
12528 12532 external |= 1;
12529 12533 }
12530 12534
12531 12535 if (r != 0)
12532 12536 scfdie();
12533 12537
12534 12538 /* Delete dependency property groups in dependent services. */
12535 12539 if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12536 12540 (void) delete_dependents(pg);
12537 12541 else if (scf_error() != SCF_ERROR_NOT_FOUND)
12538 12542 scfdie();
12539 12543
12540 12544 scf_iter_destroy(iter);
12541 12545 scf_pg_destroy(pg);
12542 12546 scf_instance_destroy(inst);
12543 12547
12544 12548 /*
12545 12549 * If the service has some external dependencies then we don't
12546 12550 * want to remove them in case the service is re-imported.
12547 12551 */
12548 12552 if ((pg = scf_pg_create(g_hndl)) == NULL ||
12549 12553 (iter = scf_iter_create(g_hndl)) == NULL)
12550 12554 scfdie();
12551 12555
12552 12556 if (scf_iter_service_pgs(iter, svc) < 0)
12553 12557 scfdie();
12554 12558
12555 12559 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12556 12560 if (pg_is_external_dependency(pg)) {
12557 12561 external |= 2;
12558 12562 continue;
12559 12563 }
12560 12564
12561 12565 if (scf_pg_delete(pg) != 0) {
12562 12566 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12563 12567 scfdie();
12564 12568 else {
12565 12569 semerr(emsg_permission_denied);
12566 12570
12567 12571 (void) scf_iter_destroy(iter);
12568 12572 (void) scf_pg_destroy(pg);
12569 12573 return (DELETE_FAILURE);
12570 12574 }
12571 12575 }
12572 12576 }
12573 12577
12574 12578 if (r == -1)
12575 12579 scfdie();
12576 12580
12577 12581 (void) scf_iter_destroy(iter);
12578 12582 (void) scf_pg_destroy(pg);
12579 12583
12580 12584 if (external != 0)
12581 12585 return (DELETE_SUCCESS_EXTDEPS);
12582 12586
12583 12587 if (scf_service_delete(svc) == 0)
12584 12588 return (DELETE_SUCCESS_NOEXTDEPS);
12585 12589
12586 12590 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12587 12591 scfdie();
12588 12592
12589 12593 semerr(emsg_permission_denied);
12590 12594 return (DELETE_FAILURE);
12591 12595 }
12592 12596
12593 12597 static int
12594 12598 delete_callback(void *data, scf_walkinfo_t *wip)
12595 12599 {
12596 12600 int force = (int)data;
12597 12601
12598 12602 if (wip->inst != NULL)
12599 12603 (void) lscf_instance_delete(wip->inst, force);
12600 12604 else
12601 12605 (void) lscf_service_delete(wip->svc, force);
12602 12606
12603 12607 return (0);
12604 12608 }
12605 12609
12606 12610 void
12607 12611 lscf_delete(const char *fmri, int force)
12608 12612 {
12609 12613 scf_service_t *svc;
12610 12614 scf_instance_t *inst;
12611 12615 int ret;
12612 12616
12613 12617 lscf_prep_hndl();
12614 12618
12615 12619 if (cur_snap != NULL) {
12616 12620 if (!snaplevel_is_instance(cur_level)) {
12617 12621 char *buf;
12618 12622
12619 12623 buf = safe_malloc(max_scf_name_len + 1);
12620 12624 if (scf_instance_get_name(cur_inst, buf,
12621 12625 max_scf_name_len + 1) >= 0) {
12622 12626 if (strcmp(buf, fmri) == 0) {
12623 12627 semerr(emsg_cant_modify_snapshots);
12624 12628 free(buf);
12625 12629 return;
12626 12630 }
12627 12631 } else if (scf_error() != SCF_ERROR_DELETED) {
12628 12632 scfdie();
12629 12633 }
12630 12634 free(buf);
12631 12635 }
12632 12636 } else if (cur_inst != NULL) {
12633 12637 /* EMPTY */;
12634 12638 } else if (cur_svc != NULL) {
12635 12639 inst = scf_instance_create(g_hndl);
12636 12640 if (inst == NULL)
12637 12641 scfdie();
12638 12642
12639 12643 if (scf_service_get_instance(cur_svc, fmri, inst) ==
12640 12644 SCF_SUCCESS) {
12641 12645 (void) lscf_instance_delete(inst, force);
12642 12646 scf_instance_destroy(inst);
12643 12647 return;
12644 12648 }
12645 12649
12646 12650 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12647 12651 scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12648 12652 scfdie();
12649 12653
12650 12654 scf_instance_destroy(inst);
12651 12655 } else {
12652 12656 assert(cur_scope != NULL);
12653 12657
12654 12658 svc = scf_service_create(g_hndl);
12655 12659 if (svc == NULL)
12656 12660 scfdie();
12657 12661
12658 12662 if (scf_scope_get_service(cur_scope, fmri, svc) ==
12659 12663 SCF_SUCCESS) {
12660 12664 (void) lscf_service_delete(svc, force);
12661 12665 scf_service_destroy(svc);
12662 12666 return;
12663 12667 }
12664 12668
12665 12669 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12666 12670 scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12667 12671 scfdie();
12668 12672
12669 12673 scf_service_destroy(svc);
12670 12674 }
12671 12675
12672 12676 /*
12673 12677 * Match FMRI to entity.
12674 12678 */
12675 12679 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12676 12680 delete_callback, (void *)force, NULL, semerr)) != 0) {
12677 12681 semerr(gettext("Failed to walk instances: %s\n"),
12678 12682 scf_strerror(ret));
12679 12683 }
12680 12684 }
12681 12685
12682 12686
12683 12687
12684 12688 /*
12685 12689 * :properties commands. These all end with "pg" or "prop" and generally
12686 12690 * operate on the currently selected entity.
12687 12691 */
12688 12692
12689 12693 /*
12690 12694 * Property listing. List the property groups, properties, their types and
12691 12695 * their values for the currently selected entity.
12692 12696 */
12693 12697 static void
12694 12698 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12695 12699 {
12696 12700 char *buf;
12697 12701 uint32_t flags;
12698 12702
12699 12703 buf = safe_malloc(max_scf_pg_type_len + 1);
12700 12704
12701 12705 if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12702 12706 scfdie();
12703 12707
12704 12708 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12705 12709 scfdie();
12706 12710
12707 12711 safe_printf("%-*s %s", namewidth, name, buf);
12708 12712
12709 12713 if (flags & SCF_PG_FLAG_NONPERSISTENT)
12710 12714 safe_printf("\tNONPERSISTENT");
12711 12715
12712 12716 safe_printf("\n");
12713 12717
12714 12718 free(buf);
12715 12719 }
12716 12720
12717 12721 static boolean_t
12718 12722 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12719 12723 {
12720 12724 if (scf_property_get_value(prop, val) == 0) {
12721 12725 return (B_FALSE);
12722 12726 } else {
12723 12727 switch (scf_error()) {
12724 12728 case SCF_ERROR_NOT_FOUND:
12725 12729 return (B_FALSE);
12726 12730 case SCF_ERROR_PERMISSION_DENIED:
12727 12731 case SCF_ERROR_CONSTRAINT_VIOLATED:
12728 12732 return (B_TRUE);
12729 12733 default:
12730 12734 scfdie();
12731 12735 /*NOTREACHED*/
12732 12736 }
12733 12737 }
12734 12738 }
12735 12739
12736 12740 static void
12737 12741 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12738 12742 {
12739 12743 scf_iter_t *iter;
12740 12744 scf_value_t *val;
12741 12745 const char *type;
12742 12746 int multiple_strings = 0;
12743 12747 int ret;
12744 12748
12745 12749 if ((iter = scf_iter_create(g_hndl)) == NULL ||
12746 12750 (val = scf_value_create(g_hndl)) == NULL)
12747 12751 scfdie();
12748 12752
12749 12753 type = prop_to_typestr(prop);
12750 12754 assert(type != NULL);
12751 12755
12752 12756 safe_printf("%-*s %-7s ", len, name, type);
12753 12757
12754 12758 if (prop_has_multiple_values(prop, val) &&
12755 12759 (scf_value_type(val) == SCF_TYPE_ASTRING ||
12756 12760 scf_value_type(val) == SCF_TYPE_USTRING))
12757 12761 multiple_strings = 1;
12758 12762
12759 12763 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12760 12764 scfdie();
12761 12765
12762 12766 while ((ret = scf_iter_next_value(iter, val)) == 1) {
12763 12767 char *buf;
12764 12768 ssize_t vlen, szret;
12765 12769
12766 12770 vlen = scf_value_get_as_string(val, NULL, 0);
12767 12771 if (vlen < 0)
12768 12772 scfdie();
12769 12773
12770 12774 buf = safe_malloc(vlen + 1);
12771 12775
12772 12776 szret = scf_value_get_as_string(val, buf, vlen + 1);
12773 12777 if (szret < 0)
12774 12778 scfdie();
12775 12779 assert(szret <= vlen);
12776 12780
12777 12781 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12778 12782 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12779 12783 safe_printf(" \"");
12780 12784 (void) quote_and_print(buf, stdout, 0);
12781 12785 (void) putchar('"');
12782 12786 if (ferror(stdout)) {
12783 12787 (void) putchar('\n');
12784 12788 uu_die(gettext("Error writing to stdout.\n"));
12785 12789 }
12786 12790 } else {
12787 12791 safe_printf(" %s", buf);
12788 12792 }
12789 12793
12790 12794 free(buf);
12791 12795 }
12792 12796 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12793 12797 scfdie();
12794 12798
12795 12799 if (putchar('\n') != '\n')
12796 12800 uu_die(gettext("Could not output newline"));
12797 12801 }
12798 12802
12799 12803 /*
12800 12804 * Outputs template property group info for the describe subcommand.
12801 12805 * If 'templates' == 2, verbose output is printed in the format expected
12802 12806 * for describe -v, which includes all templates fields. If pg is
12803 12807 * not NULL, we're describing the template data, not an existing property
12804 12808 * group, and formatting should be appropriate for describe -t.
12805 12809 */
12806 12810 static void
12807 12811 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12808 12812 {
12809 12813 char *buf;
12810 12814 uint8_t required;
12811 12815 scf_property_t *stability_prop;
12812 12816 scf_value_t *stability_val;
12813 12817
12814 12818 if (templates == 0)
12815 12819 return;
12816 12820
12817 12821 if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12818 12822 (stability_val = scf_value_create(g_hndl)) == NULL)
12819 12823 scfdie();
12820 12824
12821 12825 if (templates == 2 && pg != NULL) {
12822 12826 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12823 12827 stability_prop) == 0) {
12824 12828 if (prop_check_type(stability_prop,
12825 12829 SCF_TYPE_ASTRING) == 0 &&
12826 12830 prop_get_val(stability_prop, stability_val) == 0) {
12827 12831 char *stability;
12828 12832
12829 12833 stability = safe_malloc(max_scf_value_len + 1);
12830 12834
12831 12835 if (scf_value_get_astring(stability_val,
12832 12836 stability, max_scf_value_len + 1) == -1 &&
12833 12837 scf_error() != SCF_ERROR_NOT_FOUND)
12834 12838 scfdie();
12835 12839
12836 12840 safe_printf("%s%s: %s\n", TMPL_INDENT,
12837 12841 gettext("stability"), stability);
12838 12842
12839 12843 free(stability);
12840 12844 }
12841 12845 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
12842 12846 scfdie();
12843 12847 }
12844 12848
12845 12849 scf_property_destroy(stability_prop);
12846 12850 scf_value_destroy(stability_val);
12847 12851
12848 12852 if (pgt == NULL)
12849 12853 return;
12850 12854
12851 12855 if (pg == NULL || templates == 2) {
12852 12856 /* print type info only if scf_tmpl_pg_name succeeds */
12853 12857 if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12854 12858 if (pg != NULL)
12855 12859 safe_printf("%s", TMPL_INDENT);
12856 12860 safe_printf("%s: ", gettext("name"));
12857 12861 safe_printf("%s\n", buf);
12858 12862 free(buf);
12859 12863 }
12860 12864
12861 12865 /* print type info only if scf_tmpl_pg_type succeeds */
12862 12866 if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12863 12867 if (pg != NULL)
12864 12868 safe_printf("%s", TMPL_INDENT);
12865 12869 safe_printf("%s: ", gettext("type"));
12866 12870 safe_printf("%s\n", buf);
12867 12871 free(buf);
12868 12872 }
12869 12873 }
12870 12874
12871 12875 if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12872 12876 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12873 12877 required ? "true" : "false");
12874 12878
12875 12879 if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12876 12880 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12877 12881 buf);
12878 12882 free(buf);
12879 12883 }
12880 12884
12881 12885 if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12882 12886 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12883 12887 buf);
12884 12888 free(buf);
12885 12889 }
12886 12890
12887 12891 if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12888 12892 if (templates == 2)
12889 12893 safe_printf("%s%s: %s\n", TMPL_INDENT,
12890 12894 gettext("description"), buf);
12891 12895 else
12892 12896 safe_printf("%s%s\n", TMPL_INDENT, buf);
12893 12897 free(buf);
12894 12898 }
12895 12899
12896 12900 }
12897 12901
12898 12902 /*
12899 12903 * With as_value set to true, indent as appropriate for the value level.
12900 12904 * If false, indent to appropriate level for inclusion in constraint
12901 12905 * or choice printout.
12902 12906 */
12903 12907 static void
12904 12908 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12905 12909 int as_value)
12906 12910 {
12907 12911 char *buf;
12908 12912
12909 12913 if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12910 12914 if (as_value == 0)
12911 12915 safe_printf("%s", TMPL_CHOICE_INDENT);
12912 12916 else
12913 12917 safe_printf("%s", TMPL_INDENT);
12914 12918 safe_printf("%s: %s\n", gettext("value common name"), buf);
12915 12919 free(buf);
12916 12920 }
12917 12921
12918 12922 if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12919 12923 if (as_value == 0)
12920 12924 safe_printf("%s", TMPL_CHOICE_INDENT);
12921 12925 else
12922 12926 safe_printf("%s", TMPL_INDENT);
12923 12927 safe_printf("%s: %s\n", gettext("value description"), buf);
12924 12928 free(buf);
12925 12929 }
12926 12930 }
12927 12931
12928 12932 static void
12929 12933 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12930 12934 {
12931 12935 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12932 12936 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12933 12937 safe_printf("%s\n", val_buf);
12934 12938
12935 12939 print_template_value_details(prt, val_buf, 1);
12936 12940 }
12937 12941
12938 12942 static void
12939 12943 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12940 12944 {
12941 12945 int i, printed = 0;
12942 12946 scf_values_t values;
12943 12947 scf_count_ranges_t c_ranges;
12944 12948 scf_int_ranges_t i_ranges;
12945 12949
12946 12950 printed = 0;
12947 12951 i = 0;
12948 12952 if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12949 12953 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12950 12954 gettext("value constraints"));
12951 12955 printed++;
12952 12956 for (i = 0; i < values.value_count; ++i) {
12953 12957 safe_printf("%s%s: %s\n", TMPL_INDENT,
12954 12958 gettext("value name"), values.values_as_strings[i]);
12955 12959 if (verbose == 1)
12956 12960 print_template_value_details(prt,
12957 12961 values.values_as_strings[i], 0);
12958 12962 }
12959 12963
12960 12964 scf_values_destroy(&values);
12961 12965 }
12962 12966
12963 12967 if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12964 12968 if (printed++ == 0)
12965 12969 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12966 12970 gettext("value constraints"));
12967 12971 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12968 12972 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12969 12973 gettext("range"), c_ranges.scr_min[i],
12970 12974 c_ranges.scr_max[i]);
12971 12975 }
12972 12976 scf_count_ranges_destroy(&c_ranges);
12973 12977 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12974 12978 scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
12975 12979 if (printed++ == 0)
12976 12980 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12977 12981 gettext("value constraints"));
12978 12982 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12979 12983 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12980 12984 gettext("range"), i_ranges.sir_min[i],
12981 12985 i_ranges.sir_max[i]);
12982 12986 }
12983 12987 scf_int_ranges_destroy(&i_ranges);
12984 12988 }
12985 12989 }
12986 12990
12987 12991 static void
12988 12992 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
12989 12993 {
12990 12994 int i = 0, printed = 0;
12991 12995 scf_values_t values;
12992 12996 scf_count_ranges_t c_ranges;
12993 12997 scf_int_ranges_t i_ranges;
12994 12998
12995 12999 printed = 0;
12996 13000 if (scf_tmpl_value_name_choices(prt, &values) == 0) {
12997 13001 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12998 13002 gettext("value constraints"));
12999 13003 printed++;
13000 13004 for (i = 0; i < values.value_count; i++) {
13001 13005 safe_printf("%s%s: %s\n", TMPL_INDENT,
13002 13006 gettext("value name"), values.values_as_strings[i]);
13003 13007 if (verbose == 1)
13004 13008 print_template_value_details(prt,
13005 13009 values.values_as_strings[i], 0);
13006 13010 }
13007 13011
13008 13012 scf_values_destroy(&values);
13009 13013 }
13010 13014
13011 13015 if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
13012 13016 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
13013 13017 if (printed++ == 0)
13014 13018 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13015 13019 gettext("value choices"));
13016 13020 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
13017 13021 gettext("range"), c_ranges.scr_min[i],
13018 13022 c_ranges.scr_max[i]);
13019 13023 }
13020 13024 scf_count_ranges_destroy(&c_ranges);
13021 13025 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
13022 13026 scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
13023 13027 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
13024 13028 if (printed++ == 0)
13025 13029 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13026 13030 gettext("value choices"));
13027 13031 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
13028 13032 gettext("range"), i_ranges.sir_min[i],
13029 13033 i_ranges.sir_max[i]);
13030 13034 }
13031 13035 scf_int_ranges_destroy(&i_ranges);
13032 13036 }
13033 13037 }
13034 13038
13035 13039 static void
13036 13040 list_values_by_template(scf_prop_tmpl_t *prt)
13037 13041 {
13038 13042 print_template_constraints(prt, 1);
13039 13043 print_template_choices(prt, 1);
13040 13044 }
13041 13045
13042 13046 static void
13043 13047 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
13044 13048 {
13045 13049 char *val_buf;
13046 13050 scf_iter_t *iter;
13047 13051 scf_value_t *val;
13048 13052 int ret;
13049 13053
13050 13054 if ((iter = scf_iter_create(g_hndl)) == NULL ||
13051 13055 (val = scf_value_create(g_hndl)) == NULL)
13052 13056 scfdie();
13053 13057
13054 13058 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
13055 13059 scfdie();
13056 13060
13057 13061 val_buf = safe_malloc(max_scf_value_len + 1);
13058 13062
13059 13063 while ((ret = scf_iter_next_value(iter, val)) == 1) {
13060 13064 if (scf_value_get_as_string(val, val_buf,
13061 13065 max_scf_value_len + 1) < 0)
13062 13066 scfdie();
13063 13067
13064 13068 print_template_value(prt, val_buf);
13065 13069 }
13066 13070 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
13067 13071 scfdie();
13068 13072 free(val_buf);
13069 13073
13070 13074 print_template_constraints(prt, 0);
13071 13075 print_template_choices(prt, 0);
13072 13076
13073 13077 }
13074 13078
13075 13079 /*
13076 13080 * Outputs property info for the describe subcommand
13077 13081 * Verbose output if templates == 2, -v option of svccfg describe
13078 13082 * Displays template data if prop is not NULL, -t option of svccfg describe
13079 13083 */
13080 13084 static void
13081 13085 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
13082 13086 {
13083 13087 char *buf;
13084 13088 uint8_t u_buf;
13085 13089 int i;
13086 13090 uint64_t min, max;
13087 13091 scf_values_t values;
13088 13092
13089 13093 if (prt == NULL || templates == 0)
13090 13094 return;
13091 13095
13092 13096 if (prop == NULL) {
13093 13097 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
13094 13098 if (scf_tmpl_prop_name(prt, &buf) > 0) {
13095 13099 safe_printf("%s\n", buf);
13096 13100 free(buf);
13097 13101 } else
13098 13102 safe_printf("(%s)\n", gettext("any"));
13099 13103 }
13100 13104
13101 13105 if (prop == NULL || templates == 2) {
13102 13106 if (prop != NULL)
13103 13107 safe_printf("%s", TMPL_INDENT);
13104 13108 else
13105 13109 safe_printf("%s", TMPL_VALUE_INDENT);
13106 13110 safe_printf("%s: ", gettext("type"));
13107 13111 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
13108 13112 safe_printf("%s\n", buf);
13109 13113 free(buf);
13110 13114 } else
13111 13115 safe_printf("(%s)\n", gettext("any"));
13112 13116 }
13113 13117
13114 13118 if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
13115 13119 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
13116 13120 u_buf ? "true" : "false");
13117 13121
13118 13122 if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
13119 13123 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
13120 13124 buf);
13121 13125 free(buf);
13122 13126 }
13123 13127
13124 13128 if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
13125 13129 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
13126 13130 buf);
13127 13131 free(buf);
13128 13132 }
13129 13133
13130 13134 if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
13131 13135 safe_printf("%s%s\n", TMPL_INDENT, buf);
13132 13136 free(buf);
13133 13137 }
13134 13138
13135 13139 if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
13136 13140 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
13137 13141 scf_tmpl_visibility_to_string(u_buf));
13138 13142
13139 13143 if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
13140 13144 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13141 13145 gettext("minimum number of values"), min);
13142 13146 if (max == ULLONG_MAX) {
13143 13147 safe_printf("%s%s: %s\n", TMPL_INDENT,
13144 13148 gettext("maximum number of values"),
13145 13149 gettext("unlimited"));
13146 13150 } else {
13147 13151 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13148 13152 gettext("maximum number of values"), max);
13149 13153 }
13150 13154 }
13151 13155
13152 13156 if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
13153 13157 for (i = 0; i < values.value_count; i++) {
13154 13158 if (i == 0) {
13155 13159 safe_printf("%s%s:", TMPL_INDENT,
13156 13160 gettext("internal separators"));
13157 13161 }
13158 13162 safe_printf(" \"%s\"", values.values_as_strings[i]);
13159 13163 }
13160 13164 safe_printf("\n");
13161 13165 }
13162 13166
13163 13167 if (templates != 2)
13164 13168 return;
13165 13169
13166 13170 if (prop != NULL)
13167 13171 list_values_tmpl(prt, prop);
13168 13172 else
13169 13173 list_values_by_template(prt);
13170 13174 }
13171 13175
13172 13176 static char *
13173 13177 read_astring(scf_propertygroup_t *pg, const char *prop_name)
13174 13178 {
13175 13179 char *rv;
13176 13180
13177 13181 rv = _scf_read_single_astring_from_pg(pg, prop_name);
13178 13182 if (rv == NULL) {
13179 13183 switch (scf_error()) {
13180 13184 case SCF_ERROR_NOT_FOUND:
13181 13185 break;
13182 13186 default:
13183 13187 scfdie();
13184 13188 }
13185 13189 }
13186 13190 return (rv);
13187 13191 }
13188 13192
13189 13193 static void
13190 13194 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
13191 13195 {
13192 13196 size_t doc_len;
13193 13197 size_t man_len;
13194 13198 char *pg_name;
13195 13199 char *text = NULL;
13196 13200 int rv;
13197 13201
13198 13202 doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
13199 13203 man_len = strlen(SCF_PG_TM_MAN_PREFIX);
13200 13204 pg_name = safe_malloc(max_scf_name_len + 1);
13201 13205 while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
13202 13206 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
13203 13207 scfdie();
13204 13208 }
13205 13209 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
13206 13210 /* Display doc_link and and uri */
13207 13211 safe_printf("%s%s:\n", TMPL_INDENT,
13208 13212 gettext("doc_link"));
13209 13213 text = read_astring(pg, SCF_PROPERTY_TM_NAME);
13210 13214 if (text != NULL) {
13211 13215 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13212 13216 TMPL_INDENT, gettext("name"), text);
13213 13217 uu_free(text);
13214 13218 }
13215 13219 text = read_astring(pg, SCF_PROPERTY_TM_URI);
13216 13220 if (text != NULL) {
13217 13221 safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
13218 13222 gettext("uri"), text);
13219 13223 uu_free(text);
13220 13224 }
13221 13225 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
13222 13226 man_len) == 0) {
13223 13227 /* Display manpage title, section and path */
13224 13228 safe_printf("%s%s:\n", TMPL_INDENT,
13225 13229 gettext("manpage"));
13226 13230 text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
13227 13231 if (text != NULL) {
13228 13232 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13229 13233 TMPL_INDENT, gettext("title"), text);
13230 13234 uu_free(text);
13231 13235 }
13232 13236 text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
13233 13237 if (text != NULL) {
13234 13238 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13235 13239 TMPL_INDENT, gettext("section"), text);
13236 13240 uu_free(text);
13237 13241 }
13238 13242 text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
13239 13243 if (text != NULL) {
13240 13244 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13241 13245 TMPL_INDENT, gettext("manpath"), text);
13242 13246 uu_free(text);
13243 13247 }
13244 13248 }
13245 13249 }
13246 13250 if (rv == -1)
13247 13251 scfdie();
13248 13252
13249 13253 done:
13250 13254 free(pg_name);
13251 13255 }
13252 13256
13253 13257 static void
13254 13258 list_entity_tmpl(int templates)
13255 13259 {
13256 13260 char *common_name = NULL;
13257 13261 char *description = NULL;
13258 13262 char *locale = NULL;
13259 13263 scf_iter_t *iter;
13260 13264 scf_propertygroup_t *pg;
13261 13265 scf_property_t *prop;
13262 13266 int r;
13263 13267 scf_value_t *val;
13264 13268
13265 13269 if ((pg = scf_pg_create(g_hndl)) == NULL ||
13266 13270 (prop = scf_property_create(g_hndl)) == NULL ||
13267 13271 (val = scf_value_create(g_hndl)) == NULL ||
13268 13272 (iter = scf_iter_create(g_hndl)) == NULL)
13269 13273 scfdie();
13270 13274
13271 13275 locale = setlocale(LC_MESSAGES, NULL);
13272 13276
13273 13277 if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
13274 13278 common_name = safe_malloc(max_scf_value_len + 1);
13275 13279
13276 13280 /* Try both the current locale and the "C" locale. */
13277 13281 if (scf_pg_get_property(pg, locale, prop) == 0 ||
13278 13282 (scf_error() == SCF_ERROR_NOT_FOUND &&
13279 13283 scf_pg_get_property(pg, "C", prop) == 0)) {
13280 13284 if (prop_get_val(prop, val) == 0 &&
13281 13285 scf_value_get_ustring(val, common_name,
13282 13286 max_scf_value_len + 1) != -1) {
13283 13287 safe_printf("%s%s: %s\n", TMPL_INDENT,
13284 13288 gettext("common name"), common_name);
13285 13289 }
13286 13290 }
13287 13291 }
13288 13292
13289 13293 /*
13290 13294 * Do description, manpages, and doc links if templates == 2.
13291 13295 */
13292 13296 if (templates == 2) {
13293 13297 /* Get the description. */
13294 13298 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
13295 13299 description = safe_malloc(max_scf_value_len + 1);
13296 13300
13297 13301 /* Try both the current locale and the "C" locale. */
13298 13302 if (scf_pg_get_property(pg, locale, prop) == 0 ||
13299 13303 (scf_error() == SCF_ERROR_NOT_FOUND &&
13300 13304 scf_pg_get_property(pg, "C", prop) == 0)) {
13301 13305 if (prop_get_val(prop, val) == 0 &&
13302 13306 scf_value_get_ustring(val, description,
13303 13307 max_scf_value_len + 1) != -1) {
13304 13308 safe_printf("%s%s: %s\n", TMPL_INDENT,
13305 13309 gettext("description"),
13306 13310 description);
13307 13311 }
13308 13312 }
13309 13313 }
13310 13314
13311 13315 /* Process doc_link & manpage elements. */
13312 13316 if (cur_level != NULL) {
13313 13317 r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
13314 13318 SCF_GROUP_TEMPLATE);
13315 13319 } else if (cur_inst != NULL) {
13316 13320 r = scf_iter_instance_pgs_typed(iter, cur_inst,
13317 13321 SCF_GROUP_TEMPLATE);
13318 13322 } else {
13319 13323 r = scf_iter_service_pgs_typed(iter, cur_svc,
13320 13324 SCF_GROUP_TEMPLATE);
13321 13325 }
13322 13326 if (r == 0) {
13323 13327 display_documentation(iter, pg);
13324 13328 }
13325 13329 }
13326 13330
13327 13331 free(common_name);
13328 13332 free(description);
13329 13333 scf_pg_destroy(pg);
13330 13334 scf_property_destroy(prop);
13331 13335 scf_value_destroy(val);
13332 13336 scf_iter_destroy(iter);
13333 13337 }
13334 13338
13335 13339 static void
13336 13340 listtmpl(const char *pattern, int templates)
13337 13341 {
13338 13342 scf_pg_tmpl_t *pgt;
13339 13343 scf_prop_tmpl_t *prt;
13340 13344 char *snapbuf = NULL;
13341 13345 char *fmribuf;
13342 13346 char *pg_name = NULL, *prop_name = NULL;
13343 13347 ssize_t prop_name_size;
13344 13348 char *qual_prop_name;
13345 13349 char *search_name;
13346 13350 int listed = 0;
13347 13351
13348 13352 if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13349 13353 (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
13350 13354 scfdie();
13351 13355
13352 13356 fmribuf = safe_malloc(max_scf_name_len + 1);
13353 13357 qual_prop_name = safe_malloc(max_scf_name_len + 1);
13354 13358
13355 13359 if (cur_snap != NULL) {
13356 13360 snapbuf = safe_malloc(max_scf_name_len + 1);
13357 13361 if (scf_snapshot_get_name(cur_snap, snapbuf,
13358 13362 max_scf_name_len + 1) < 0)
13359 13363 scfdie();
13360 13364 }
13361 13365
13362 13366 if (cur_inst != NULL) {
13363 13367 if (scf_instance_to_fmri(cur_inst, fmribuf,
13364 13368 max_scf_name_len + 1) < 0)
13365 13369 scfdie();
13366 13370 } else if (cur_svc != NULL) {
13367 13371 if (scf_service_to_fmri(cur_svc, fmribuf,
13368 13372 max_scf_name_len + 1) < 0)
13369 13373 scfdie();
13370 13374 } else
13371 13375 abort();
13372 13376
13373 13377 /* If pattern is specified, we want to list only those items. */
13374 13378 while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) {
13375 13379 listed = 0;
13376 13380 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
13377 13381 fnmatch(pattern, pg_name, 0) == 0)) {
13378 13382 list_pg_tmpl(pgt, NULL, templates);
13379 13383 listed++;
13380 13384 }
13381 13385
13382 13386 scf_tmpl_prop_reset(prt);
13383 13387
13384 13388 while (scf_tmpl_iter_props(pgt, prt, 0) == 0) {
13385 13389 search_name = NULL;
13386 13390 prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
13387 13391 if ((prop_name_size > 0) && (pg_name != NULL)) {
13388 13392 if (snprintf(qual_prop_name,
13389 13393 max_scf_name_len + 1, "%s/%s",
13390 13394 pg_name, prop_name) >=
13391 13395 max_scf_name_len + 1) {
13392 13396 prop_name_size = -1;
13393 13397 } else {
13394 13398 search_name = qual_prop_name;
13395 13399 }
13396 13400 }
13397 13401 if (listed > 0 || pattern == NULL ||
13398 13402 (prop_name_size > 0 &&
13399 13403 fnmatch(pattern, search_name,
13400 13404 FNM_PATHNAME) == 0))
13401 13405 list_prop_tmpl(prt, NULL, templates);
13402 13406 if (prop_name != NULL) {
13403 13407 free(prop_name);
13404 13408 prop_name = NULL;
13405 13409 }
13406 13410 }
13407 13411 if (pg_name != NULL) {
13408 13412 free(pg_name);
13409 13413 pg_name = NULL;
13410 13414 }
13411 13415 }
13412 13416
13413 13417 scf_tmpl_prop_destroy(prt);
13414 13418 scf_tmpl_pg_destroy(pgt);
13415 13419 free(snapbuf);
13416 13420 free(fmribuf);
13417 13421 free(qual_prop_name);
13418 13422 }
13419 13423
13420 13424 static void
13421 13425 listprop(const char *pattern, int only_pgs, int templates)
13422 13426 {
13423 13427 scf_propertygroup_t *pg;
13424 13428 scf_property_t *prop;
13425 13429 scf_iter_t *iter, *piter;
13426 13430 char *pgnbuf, *prnbuf, *ppnbuf;
13427 13431 scf_pg_tmpl_t *pgt, *pgtp;
13428 13432 scf_prop_tmpl_t *prt;
13429 13433
13430 13434 void **objects;
13431 13435 char **names;
13432 13436 void **tmpls;
13433 13437 int allocd, i;
13434 13438
13435 13439 int ret;
13436 13440 ssize_t pgnlen, prnlen, szret;
13437 13441 size_t max_len = 0;
13438 13442
13439 13443 if (cur_svc == NULL && cur_inst == NULL) {
13440 13444 semerr(emsg_entity_not_selected);
13441 13445 return;
13442 13446 }
13443 13447
13444 13448 if ((pg = scf_pg_create(g_hndl)) == NULL ||
13445 13449 (prop = scf_property_create(g_hndl)) == NULL ||
13446 13450 (iter = scf_iter_create(g_hndl)) == NULL ||
13447 13451 (piter = scf_iter_create(g_hndl)) == NULL ||
13448 13452 (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13449 13453 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
13450 13454 scfdie();
13451 13455
13452 13456 prnbuf = safe_malloc(max_scf_name_len + 1);
13453 13457
13454 13458 if (cur_level != NULL)
13455 13459 ret = scf_iter_snaplevel_pgs(iter, cur_level);
13456 13460 else if (cur_inst != NULL)
13457 13461 ret = scf_iter_instance_pgs(iter, cur_inst);
13458 13462 else
13459 13463 ret = scf_iter_service_pgs(iter, cur_svc);
13460 13464 if (ret != 0) {
13461 13465 return;
13462 13466 }
13463 13467
13464 13468 /*
13465 13469 * We want to only list items which match pattern, and we want the
13466 13470 * second column to line up, so during the first pass we'll save
13467 13471 * matching items, their names, and their templates in objects,
13468 13472 * names, and tmpls, computing the maximum name length as we go,
13469 13473 * and then we'll print them out.
13470 13474 *
13471 13475 * Note: We always keep an extra slot available so the array can be
13472 13476 * NULL-terminated.
13473 13477 */
13474 13478 i = 0;
13475 13479 allocd = 1;
13476 13480 objects = safe_malloc(sizeof (*objects));
13477 13481 names = safe_malloc(sizeof (*names));
13478 13482 tmpls = safe_malloc(sizeof (*tmpls));
13479 13483
13480 13484 while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13481 13485 int new_pg = 0;
13482 13486 int print_props = 0;
13483 13487 pgtp = NULL;
13484 13488
13485 13489 pgnlen = scf_pg_get_name(pg, NULL, 0);
13486 13490 if (pgnlen < 0)
13487 13491 scfdie();
13488 13492
13489 13493 pgnbuf = safe_malloc(pgnlen + 1);
13490 13494
13491 13495 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
13492 13496 if (szret < 0)
13493 13497 scfdie();
13494 13498 assert(szret <= pgnlen);
13495 13499
13496 13500 if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) {
13497 13501 if (scf_error() != SCF_ERROR_NOT_FOUND)
13498 13502 scfdie();
13499 13503 pgtp = NULL;
13500 13504 } else {
13501 13505 pgtp = pgt;
13502 13506 }
13503 13507
13504 13508 if (pattern == NULL ||
13505 13509 fnmatch(pattern, pgnbuf, 0) == 0) {
13506 13510 if (i+1 >= allocd) {
13507 13511 allocd *= 2;
13508 13512 objects = realloc(objects,
13509 13513 sizeof (*objects) * allocd);
13510 13514 names =
13511 13515 realloc(names, sizeof (*names) * allocd);
13512 13516 tmpls = realloc(tmpls,
13513 13517 sizeof (*tmpls) * allocd);
13514 13518 if (objects == NULL || names == NULL ||
13515 13519 tmpls == NULL)
13516 13520 uu_die(gettext("Out of memory"));
13517 13521 }
13518 13522 objects[i] = pg;
13519 13523 names[i] = pgnbuf;
13520 13524
13521 13525 if (pgtp == NULL)
13522 13526 tmpls[i] = NULL;
13523 13527 else
13524 13528 tmpls[i] = pgt;
13525 13529
13526 13530 ++i;
13527 13531
13528 13532 if (pgnlen > max_len)
13529 13533 max_len = pgnlen;
13530 13534
13531 13535 new_pg = 1;
13532 13536 print_props = 1;
13533 13537 }
13534 13538
13535 13539 if (only_pgs) {
13536 13540 if (new_pg) {
13537 13541 pg = scf_pg_create(g_hndl);
13538 13542 if (pg == NULL)
13539 13543 scfdie();
13540 13544 pgt = scf_tmpl_pg_create(g_hndl);
13541 13545 if (pgt == NULL)
13542 13546 scfdie();
13543 13547 } else
13544 13548 free(pgnbuf);
13545 13549
13546 13550 continue;
13547 13551 }
13548 13552
13549 13553 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13550 13554 scfdie();
13551 13555
13552 13556 while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13553 13557 prnlen = scf_property_get_name(prop, prnbuf,
13554 13558 max_scf_name_len + 1);
13555 13559 if (prnlen < 0)
13556 13560 scfdie();
13557 13561
13558 13562 /* Will prepend the property group name and a slash. */
13559 13563 prnlen += pgnlen + 1;
13560 13564
13561 13565 ppnbuf = safe_malloc(prnlen + 1);
13562 13566
13563 13567 if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13564 13568 prnbuf) < 0)
13565 13569 uu_die("snprintf");
13566 13570
13567 13571 if (pattern == NULL || print_props == 1 ||
13568 13572 fnmatch(pattern, ppnbuf, 0) == 0) {
13569 13573 if (i+1 >= allocd) {
13570 13574 allocd *= 2;
13571 13575 objects = realloc(objects,
13572 13576 sizeof (*objects) * allocd);
13573 13577 names = realloc(names,
13574 13578 sizeof (*names) * allocd);
13575 13579 tmpls = realloc(tmpls,
13576 13580 sizeof (*tmpls) * allocd);
13577 13581 if (objects == NULL || names == NULL ||
13578 13582 tmpls == NULL)
13579 13583 uu_die(gettext(
13580 13584 "Out of memory"));
13581 13585 }
13582 13586
13583 13587 objects[i] = prop;
13584 13588 names[i] = ppnbuf;
13585 13589
13586 13590 if (pgtp != NULL) {
13587 13591 if (scf_tmpl_get_by_prop(pgt, prnbuf,
13588 13592 prt, 0) < 0) {
13589 13593 if (scf_error() !=
13590 13594 SCF_ERROR_NOT_FOUND)
13591 13595 scfdie();
13592 13596 tmpls[i] = NULL;
13593 13597 } else {
13594 13598 tmpls[i] = prt;
13595 13599 }
13596 13600 } else {
13597 13601 tmpls[i] = NULL;
13598 13602 }
13599 13603
13600 13604 ++i;
13601 13605
13602 13606 if (prnlen > max_len)
13603 13607 max_len = prnlen;
13604 13608
13605 13609 prop = scf_property_create(g_hndl);
13606 13610 prt = scf_tmpl_prop_create(g_hndl);
13607 13611 } else {
13608 13612 free(ppnbuf);
13609 13613 }
13610 13614 }
13611 13615
13612 13616 if (new_pg) {
13613 13617 pg = scf_pg_create(g_hndl);
13614 13618 if (pg == NULL)
13615 13619 scfdie();
13616 13620 pgt = scf_tmpl_pg_create(g_hndl);
13617 13621 if (pgt == NULL)
13618 13622 scfdie();
13619 13623 } else
13620 13624 free(pgnbuf);
13621 13625 }
13622 13626 if (ret != 0)
13623 13627 scfdie();
13624 13628
13625 13629 objects[i] = NULL;
13626 13630
13627 13631 scf_pg_destroy(pg);
13628 13632 scf_tmpl_pg_destroy(pgt);
13629 13633 scf_property_destroy(prop);
13630 13634 scf_tmpl_prop_destroy(prt);
13631 13635
13632 13636 for (i = 0; objects[i] != NULL; ++i) {
13633 13637 if (strchr(names[i], '/') == NULL) {
13634 13638 /* property group */
13635 13639 pg = (scf_propertygroup_t *)objects[i];
13636 13640 pgt = (scf_pg_tmpl_t *)tmpls[i];
13637 13641 list_pg_info(pg, names[i], max_len);
13638 13642 list_pg_tmpl(pgt, pg, templates);
13639 13643 free(names[i]);
13640 13644 scf_pg_destroy(pg);
13641 13645 if (pgt != NULL)
13642 13646 scf_tmpl_pg_destroy(pgt);
13643 13647 } else {
13644 13648 /* property */
13645 13649 prop = (scf_property_t *)objects[i];
13646 13650 prt = (scf_prop_tmpl_t *)tmpls[i];
13647 13651 list_prop_info(prop, names[i], max_len);
13648 13652 list_prop_tmpl(prt, prop, templates);
13649 13653 free(names[i]);
13650 13654 scf_property_destroy(prop);
13651 13655 if (prt != NULL)
13652 13656 scf_tmpl_prop_destroy(prt);
13653 13657 }
13654 13658 }
13655 13659
13656 13660 free(names);
13657 13661 free(objects);
13658 13662 free(tmpls);
13659 13663 }
13660 13664
13661 13665 void
13662 13666 lscf_listpg(const char *pattern)
13663 13667 {
13664 13668 lscf_prep_hndl();
13665 13669
13666 13670 listprop(pattern, 1, 0);
13667 13671 }
13668 13672
13669 13673 /*
13670 13674 * Property group and property creation, setting, and deletion. setprop (and
13671 13675 * its alias, addprop) can either create a property group of a given type, or
13672 13676 * it can create or set a property to a given type and list of values.
13673 13677 */
13674 13678 void
13675 13679 lscf_addpg(const char *name, const char *type, const char *flags)
13676 13680 {
13677 13681 scf_propertygroup_t *pg;
13678 13682 int ret;
13679 13683 uint32_t flgs = 0;
13680 13684 const char *cp;
13681 13685
13682 13686
13683 13687 lscf_prep_hndl();
13684 13688
13685 13689 if (cur_snap != NULL) {
13686 13690 semerr(emsg_cant_modify_snapshots);
13687 13691 return;
13688 13692 }
13689 13693
13690 13694 if (cur_inst == NULL && cur_svc == NULL) {
13691 13695 semerr(emsg_entity_not_selected);
13692 13696 return;
13693 13697 }
13694 13698
13695 13699 if (flags != NULL) {
13696 13700 for (cp = flags; *cp != '\0'; ++cp) {
13697 13701 switch (*cp) {
13698 13702 case 'P':
13699 13703 flgs |= SCF_PG_FLAG_NONPERSISTENT;
13700 13704 break;
13701 13705
13702 13706 case 'p':
13703 13707 flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13704 13708 break;
13705 13709
13706 13710 default:
13707 13711 semerr(gettext("Invalid property group flag "
13708 13712 "%c."), *cp);
13709 13713 return;
13710 13714 }
13711 13715 }
13712 13716 }
13713 13717
13714 13718 pg = scf_pg_create(g_hndl);
13715 13719 if (pg == NULL)
13716 13720 scfdie();
13717 13721
13718 13722 if (cur_inst != NULL)
13719 13723 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13720 13724 else
13721 13725 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13722 13726
13723 13727 if (ret != SCF_SUCCESS) {
13724 13728 switch (scf_error()) {
13725 13729 case SCF_ERROR_INVALID_ARGUMENT:
13726 13730 semerr(gettext("Name, type, or flags are invalid.\n"));
13727 13731 break;
13728 13732
13729 13733 case SCF_ERROR_EXISTS:
13730 13734 semerr(gettext("Property group already exists.\n"));
13731 13735 break;
13732 13736
13733 13737 case SCF_ERROR_PERMISSION_DENIED:
13734 13738 semerr(emsg_permission_denied);
13735 13739 break;
13736 13740
13737 13741 case SCF_ERROR_BACKEND_ACCESS:
13738 13742 semerr(gettext("Backend refused access.\n"));
13739 13743 break;
13740 13744
13741 13745 default:
13742 13746 scfdie();
13743 13747 }
13744 13748 }
13745 13749
13746 13750 scf_pg_destroy(pg);
13747 13751
13748 13752 private_refresh();
13749 13753 }
13750 13754
13751 13755 void
13752 13756 lscf_delpg(char *name)
13753 13757 {
13754 13758 lscf_prep_hndl();
13755 13759
13756 13760 if (cur_snap != NULL) {
13757 13761 semerr(emsg_cant_modify_snapshots);
13758 13762 return;
13759 13763 }
13760 13764
13761 13765 if (cur_inst == NULL && cur_svc == NULL) {
13762 13766 semerr(emsg_entity_not_selected);
13763 13767 return;
13764 13768 }
13765 13769
13766 13770 if (strchr(name, '/') != NULL) {
13767 13771 semerr(emsg_invalid_pg_name, name);
13768 13772 return;
13769 13773 }
13770 13774
13771 13775 lscf_delprop(name);
13772 13776 }
13773 13777
13774 13778 /*
13775 13779 * scf_delhash() is used to remove the property group related to the
13776 13780 * hash entry for a specific manifest in the repository. pgname will be
13777 13781 * constructed from the location of the manifest file. If deathrow isn't 0,
13778 13782 * manifest file doesn't need to exist (manifest string will be used as
13779 13783 * an absolute path).
13780 13784 */
13781 13785 void
13782 13786 lscf_delhash(char *manifest, int deathrow)
13783 13787 {
13784 13788 char *pgname;
13785 13789
13786 13790 if (cur_snap != NULL ||
13787 13791 cur_inst != NULL || cur_svc != NULL) {
13788 13792 warn(gettext("error, an entity is selected\n"));
13789 13793 return;
13790 13794 }
13791 13795
13792 13796 /* select smf/manifest */
13793 13797 lscf_select(HASH_SVC);
13794 13798 /*
13795 13799 * Translate the manifest file name to property name. In the deathrow
13796 13800 * case, the manifest file does not need to exist.
13797 13801 */
13798 13802 pgname = mhash_filename_to_propname(manifest,
13799 13803 deathrow ? B_TRUE : B_FALSE);
13800 13804 if (pgname == NULL) {
13801 13805 warn(gettext("cannot resolve pathname for %s\n"), manifest);
13802 13806 return;
13803 13807 }
13804 13808 /* delete the hash property name */
13805 13809 lscf_delpg(pgname);
13806 13810 }
13807 13811
13808 13812 void
13809 13813 lscf_listprop(const char *pattern)
13810 13814 {
13811 13815 lscf_prep_hndl();
13812 13816
13813 13817 listprop(pattern, 0, 0);
13814 13818 }
13815 13819
13816 13820 int
13817 13821 lscf_setprop(const char *pgname, const char *type, const char *value,
13818 13822 const uu_list_t *values)
13819 13823 {
13820 13824 scf_type_t ty, current_ty;
13821 13825 scf_service_t *svc;
13822 13826 scf_propertygroup_t *pg, *parent_pg;
13823 13827 scf_property_t *prop, *parent_prop;
13824 13828 scf_pg_tmpl_t *pgt;
13825 13829 scf_prop_tmpl_t *prt;
13826 13830 int ret, result = 0;
13827 13831 scf_transaction_t *tx;
13828 13832 scf_transaction_entry_t *e;
13829 13833 scf_value_t *v;
13830 13834 uu_list_walk_t *walk;
13831 13835 string_list_t *sp;
13832 13836 char *propname;
13833 13837 int req_quotes = 0;
13834 13838
13835 13839 lscf_prep_hndl();
13836 13840
13837 13841 if ((e = scf_entry_create(g_hndl)) == NULL ||
13838 13842 (svc = scf_service_create(g_hndl)) == NULL ||
13839 13843 (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13840 13844 (pg = scf_pg_create(g_hndl)) == NULL ||
13841 13845 (parent_prop = scf_property_create(g_hndl)) == NULL ||
13842 13846 (prop = scf_property_create(g_hndl)) == NULL ||
13843 13847 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13844 13848 (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13845 13849 (tx = scf_transaction_create(g_hndl)) == NULL)
13846 13850 scfdie();
13847 13851
13848 13852 if (cur_snap != NULL) {
13849 13853 semerr(emsg_cant_modify_snapshots);
13850 13854 goto fail;
13851 13855 }
13852 13856
13853 13857 if (cur_inst == NULL && cur_svc == NULL) {
13854 13858 semerr(emsg_entity_not_selected);
13855 13859 goto fail;
13856 13860 }
13857 13861
13858 13862 propname = strchr(pgname, '/');
13859 13863 if (propname == NULL) {
13860 13864 semerr(gettext("Property names must contain a `/'.\n"));
13861 13865 goto fail;
13862 13866 }
13863 13867
13864 13868 *propname = '\0';
13865 13869 ++propname;
13866 13870
13867 13871 if (type != NULL) {
13868 13872 ty = string_to_type(type);
13869 13873 if (ty == SCF_TYPE_INVALID) {
13870 13874 semerr(gettext("Unknown type \"%s\".\n"), type);
13871 13875 goto fail;
13872 13876 }
13873 13877 }
13874 13878
13875 13879 if (cur_inst != NULL)
13876 13880 ret = scf_instance_get_pg(cur_inst, pgname, pg);
13877 13881 else
13878 13882 ret = scf_service_get_pg(cur_svc, pgname, pg);
13879 13883 if (ret != SCF_SUCCESS) {
13880 13884 switch (scf_error()) {
13881 13885 case SCF_ERROR_NOT_FOUND:
13882 13886 semerr(emsg_no_such_pg, pgname);
13883 13887 goto fail;
13884 13888
13885 13889 case SCF_ERROR_INVALID_ARGUMENT:
13886 13890 semerr(emsg_invalid_pg_name, pgname);
13887 13891 goto fail;
13888 13892
13889 13893 default:
13890 13894 scfdie();
13891 13895 break;
13892 13896 }
13893 13897 }
13894 13898
13895 13899 do {
13896 13900 if (scf_pg_update(pg) == -1)
13897 13901 scfdie();
13898 13902 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13899 13903 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13900 13904 scfdie();
13901 13905
13902 13906 semerr(emsg_permission_denied);
13903 13907 goto fail;
13904 13908 }
13905 13909
13906 13910 ret = scf_pg_get_property(pg, propname, prop);
13907 13911 if (ret == SCF_SUCCESS) {
13908 13912 if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS)
13909 13913 scfdie();
13910 13914
13911 13915 if (type == NULL)
13912 13916 ty = current_ty;
13913 13917 if (scf_transaction_property_change_type(tx, e,
13914 13918 propname, ty) == -1)
13915 13919 scfdie();
13916 13920
13917 13921 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13918 13922 /* Infer the type, if possible. */
13919 13923 if (type == NULL) {
13920 13924 /*
13921 13925 * First check if we're an instance and the
13922 13926 * property is set on the service.
13923 13927 */
13924 13928 if (cur_inst != NULL &&
13925 13929 scf_instance_get_parent(cur_inst,
13926 13930 svc) == 0 &&
13927 13931 scf_service_get_pg(cur_svc, pgname,
13928 13932 parent_pg) == 0 &&
13929 13933 scf_pg_get_property(parent_pg, propname,
13930 13934 parent_prop) == 0 &&
13931 13935 scf_property_type(parent_prop,
13932 13936 ¤t_ty) == 0) {
13933 13937 ty = current_ty;
13934 13938
13935 13939 /* Then check for a type set in a template. */
13936 13940 } else if (scf_tmpl_get_by_pg(pg, pgt,
13937 13941 0) == 0 &&
13938 13942 scf_tmpl_get_by_prop(pgt, propname, prt,
13939 13943 0) == 0 &&
13940 13944 scf_tmpl_prop_type(prt, ¤t_ty) == 0) {
13941 13945 ty = current_ty;
13942 13946
13943 13947 /* If type can't be inferred, fail. */
13944 13948 } else {
13945 13949 semerr(gettext("Type required for new "
13946 13950 "properties.\n"));
13947 13951 goto fail;
13948 13952 }
13949 13953 }
13950 13954 if (scf_transaction_property_new(tx, e, propname,
13951 13955 ty) == -1)
13952 13956 scfdie();
13953 13957 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13954 13958 semerr(emsg_invalid_prop_name, propname);
13955 13959 goto fail;
13956 13960 } else {
13957 13961 scfdie();
13958 13962 }
13959 13963
13960 13964 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13961 13965 req_quotes = 1;
13962 13966
13963 13967 if (value != NULL) {
13964 13968 v = string_to_value(value, ty, 0);
13965 13969
13966 13970 if (v == NULL)
13967 13971 goto fail;
13968 13972
13969 13973 ret = scf_entry_add_value(e, v);
13970 13974 assert(ret == SCF_SUCCESS);
13971 13975 } else {
13972 13976 assert(values != NULL);
13973 13977
13974 13978 walk = uu_list_walk_start((uu_list_t *)values,
13975 13979 UU_DEFAULT);
13976 13980 if (walk == NULL)
13977 13981 uu_die(gettext("Could not walk list"));
13978 13982
13979 13983 for (sp = uu_list_walk_next(walk); sp != NULL;
13980 13984 sp = uu_list_walk_next(walk)) {
13981 13985 v = string_to_value(sp->str, ty, req_quotes);
13982 13986
13983 13987 if (v == NULL) {
13984 13988 scf_entry_destroy_children(e);
13985 13989 goto fail;
13986 13990 }
13987 13991
13988 13992 ret = scf_entry_add_value(e, v);
13989 13993 assert(ret == SCF_SUCCESS);
13990 13994 }
13991 13995 uu_list_walk_end(walk);
13992 13996 }
13993 13997 result = scf_transaction_commit(tx);
13994 13998
13995 13999 scf_transaction_reset(tx);
13996 14000 scf_entry_destroy_children(e);
13997 14001 } while (result == 0);
13998 14002
13999 14003 if (result < 0) {
14000 14004 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14001 14005 scfdie();
14002 14006
14003 14007 semerr(emsg_permission_denied);
14004 14008 goto fail;
14005 14009 }
14006 14010
14007 14011 ret = 0;
14008 14012
14009 14013 private_refresh();
14010 14014
14011 14015 goto cleanup;
14012 14016
14013 14017 fail:
14014 14018 ret = -1;
14015 14019
14016 14020 cleanup:
14017 14021 scf_transaction_destroy(tx);
14018 14022 scf_entry_destroy(e);
14019 14023 scf_service_destroy(svc);
14020 14024 scf_pg_destroy(parent_pg);
14021 14025 scf_pg_destroy(pg);
14022 14026 scf_property_destroy(parent_prop);
14023 14027 scf_property_destroy(prop);
14024 14028 scf_tmpl_pg_destroy(pgt);
14025 14029 scf_tmpl_prop_destroy(prt);
14026 14030
14027 14031 return (ret);
14028 14032 }
14029 14033
14030 14034 void
14031 14035 lscf_delprop(char *pgn)
14032 14036 {
14033 14037 char *slash, *pn;
14034 14038 scf_propertygroup_t *pg;
14035 14039 scf_transaction_t *tx;
14036 14040 scf_transaction_entry_t *e;
14037 14041 int ret;
14038 14042
14039 14043
14040 14044 lscf_prep_hndl();
14041 14045
14042 14046 if (cur_snap != NULL) {
14043 14047 semerr(emsg_cant_modify_snapshots);
14044 14048 return;
14045 14049 }
14046 14050
14047 14051 if (cur_inst == NULL && cur_svc == NULL) {
14048 14052 semerr(emsg_entity_not_selected);
14049 14053 return;
14050 14054 }
14051 14055
14052 14056 pg = scf_pg_create(g_hndl);
14053 14057 if (pg == NULL)
14054 14058 scfdie();
14055 14059
14056 14060 slash = strchr(pgn, '/');
14057 14061 if (slash == NULL) {
14058 14062 pn = NULL;
14059 14063 } else {
14060 14064 *slash = '\0';
14061 14065 pn = slash + 1;
14062 14066 }
14063 14067
14064 14068 if (cur_inst != NULL)
14065 14069 ret = scf_instance_get_pg(cur_inst, pgn, pg);
14066 14070 else
14067 14071 ret = scf_service_get_pg(cur_svc, pgn, pg);
14068 14072 if (ret != SCF_SUCCESS) {
14069 14073 switch (scf_error()) {
14070 14074 case SCF_ERROR_NOT_FOUND:
14071 14075 semerr(emsg_no_such_pg, pgn);
14072 14076 break;
14073 14077
14074 14078 case SCF_ERROR_INVALID_ARGUMENT:
14075 14079 semerr(emsg_invalid_pg_name, pgn);
14076 14080 break;
14077 14081
14078 14082 default:
14079 14083 scfdie();
14080 14084 }
14081 14085
14082 14086 scf_pg_destroy(pg);
14083 14087
14084 14088 return;
14085 14089 }
14086 14090
14087 14091 if (pn == NULL) {
14088 14092 /* Try to delete the property group. */
14089 14093 if (scf_pg_delete(pg) != SCF_SUCCESS) {
14090 14094 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14091 14095 scfdie();
14092 14096
14093 14097 semerr(emsg_permission_denied);
14094 14098 } else {
14095 14099 private_refresh();
14096 14100 }
14097 14101
14098 14102 scf_pg_destroy(pg);
14099 14103 return;
14100 14104 }
14101 14105
14102 14106 e = scf_entry_create(g_hndl);
14103 14107 tx = scf_transaction_create(g_hndl);
14104 14108
14105 14109 do {
14106 14110 if (scf_pg_update(pg) == -1)
14107 14111 scfdie();
14108 14112 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
14109 14113 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14110 14114 scfdie();
14111 14115
14112 14116 semerr(emsg_permission_denied);
14113 14117 break;
14114 14118 }
14115 14119
14116 14120 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
14117 14121 if (scf_error() == SCF_ERROR_NOT_FOUND) {
14118 14122 semerr(gettext("No such property %s/%s.\n"),
14119 14123 pgn, pn);
14120 14124 break;
14121 14125 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14122 14126 semerr(emsg_invalid_prop_name, pn);
14123 14127 break;
14124 14128 } else {
14125 14129 scfdie();
14126 14130 }
14127 14131 }
14128 14132
14129 14133 ret = scf_transaction_commit(tx);
14130 14134
14131 14135 if (ret == 0)
14132 14136 scf_transaction_reset(tx);
14133 14137 } while (ret == 0);
14134 14138
14135 14139 if (ret < 0) {
14136 14140 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14137 14141 scfdie();
14138 14142
14139 14143 semerr(emsg_permission_denied);
14140 14144 } else {
14141 14145 private_refresh();
14142 14146 }
14143 14147
14144 14148 scf_transaction_destroy(tx);
14145 14149 scf_entry_destroy(e);
14146 14150 scf_pg_destroy(pg);
14147 14151 }
14148 14152
14149 14153 /*
14150 14154 * Property editing.
14151 14155 */
14152 14156
14153 14157 static int
14154 14158 write_edit_script(FILE *strm)
14155 14159 {
14156 14160 char *fmribuf;
14157 14161 ssize_t fmrilen;
14158 14162
14159 14163 scf_propertygroup_t *pg;
14160 14164 scf_property_t *prop;
14161 14165 scf_value_t *val;
14162 14166 scf_type_t ty;
14163 14167 int ret, result = 0;
14164 14168 scf_iter_t *iter, *piter, *viter;
14165 14169 char *buf, *tybuf, *pname;
14166 14170 const char *emsg_write_error;
14167 14171
14168 14172
14169 14173 emsg_write_error = gettext("Error writing temoprary file: %s.\n");
14170 14174
14171 14175
14172 14176 /* select fmri */
14173 14177 if (cur_inst != NULL) {
14174 14178 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
14175 14179 if (fmrilen < 0)
14176 14180 scfdie();
14177 14181 fmribuf = safe_malloc(fmrilen + 1);
14178 14182 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
14179 14183 scfdie();
14180 14184 } else {
14181 14185 assert(cur_svc != NULL);
14182 14186 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
14183 14187 if (fmrilen < 0)
14184 14188 scfdie();
14185 14189 fmribuf = safe_malloc(fmrilen + 1);
14186 14190 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
14187 14191 scfdie();
14188 14192 }
14189 14193
14190 14194 if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
14191 14195 warn(emsg_write_error, strerror(errno));
14192 14196 free(fmribuf);
14193 14197 return (-1);
14194 14198 }
14195 14199
14196 14200 free(fmribuf);
14197 14201
14198 14202
14199 14203 if ((pg = scf_pg_create(g_hndl)) == NULL ||
14200 14204 (prop = scf_property_create(g_hndl)) == NULL ||
14201 14205 (val = scf_value_create(g_hndl)) == NULL ||
14202 14206 (iter = scf_iter_create(g_hndl)) == NULL ||
14203 14207 (piter = scf_iter_create(g_hndl)) == NULL ||
14204 14208 (viter = scf_iter_create(g_hndl)) == NULL)
14205 14209 scfdie();
14206 14210
14207 14211 buf = safe_malloc(max_scf_name_len + 1);
14208 14212 tybuf = safe_malloc(max_scf_pg_type_len + 1);
14209 14213 pname = safe_malloc(max_scf_name_len + 1);
14210 14214
14211 14215 if (cur_inst != NULL)
14212 14216 ret = scf_iter_instance_pgs(iter, cur_inst);
14213 14217 else
14214 14218 ret = scf_iter_service_pgs(iter, cur_svc);
14215 14219 if (ret != SCF_SUCCESS)
14216 14220 scfdie();
14217 14221
14218 14222 while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
14219 14223 int ret2;
14220 14224
14221 14225 /*
14222 14226 * # delprop pg
14223 14227 * # addpg pg type
14224 14228 */
14225 14229 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
14226 14230 scfdie();
14227 14231
14228 14232 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
14229 14233 scfdie();
14230 14234
14231 14235 if (fprintf(strm, "# Property group \"%s\"\n"
14232 14236 "# delprop %s\n"
14233 14237 "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
14234 14238 warn(emsg_write_error, strerror(errno));
14235 14239 result = -1;
14236 14240 goto out;
14237 14241 }
14238 14242
14239 14243 /* # setprop pg/prop = (values) */
14240 14244
14241 14245 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
14242 14246 scfdie();
14243 14247
14244 14248 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
14245 14249 int first = 1;
14246 14250 int ret3;
14247 14251 int multiple;
14248 14252 int is_str;
14249 14253 scf_type_t bty;
14250 14254
14251 14255 if (scf_property_get_name(prop, pname,
14252 14256 max_scf_name_len + 1) < 0)
14253 14257 scfdie();
14254 14258
14255 14259 if (scf_property_type(prop, &ty) != 0)
14256 14260 scfdie();
14257 14261
14258 14262 multiple = prop_has_multiple_values(prop, val);
14259 14263
14260 14264 if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
14261 14265 pname, scf_type_to_string(ty), multiple ? "(" : "")
14262 14266 < 0) {
14263 14267 warn(emsg_write_error, strerror(errno));
14264 14268 result = -1;
14265 14269 goto out;
14266 14270 }
14267 14271
14268 14272 (void) scf_type_base_type(ty, &bty);
14269 14273 is_str = (bty == SCF_TYPE_ASTRING);
14270 14274
14271 14275 if (scf_iter_property_values(viter, prop) !=
14272 14276 SCF_SUCCESS)
14273 14277 scfdie();
14274 14278
14275 14279 while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
14276 14280 char *buf;
14277 14281 ssize_t buflen;
14278 14282
14279 14283 buflen = scf_value_get_as_string(val, NULL, 0);
14280 14284 if (buflen < 0)
14281 14285 scfdie();
14282 14286
14283 14287 buf = safe_malloc(buflen + 1);
14284 14288
14285 14289 if (scf_value_get_as_string(val, buf,
14286 14290 buflen + 1) < 0)
14287 14291 scfdie();
14288 14292
14289 14293 if (first)
14290 14294 first = 0;
14291 14295 else {
14292 14296 if (putc(' ', strm) != ' ') {
14293 14297 warn(emsg_write_error,
14294 14298 strerror(errno));
14295 14299 result = -1;
14296 14300 goto out;
14297 14301 }
14298 14302 }
14299 14303
14300 14304 if ((is_str && multiple) ||
14301 14305 strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
14302 14306 (void) putc('"', strm);
14303 14307 (void) quote_and_print(buf, strm, 1);
14304 14308 (void) putc('"', strm);
14305 14309
14306 14310 if (ferror(strm)) {
14307 14311 warn(emsg_write_error,
14308 14312 strerror(errno));
14309 14313 result = -1;
14310 14314 goto out;
14311 14315 }
14312 14316 } else {
14313 14317 if (fprintf(strm, "%s", buf) < 0) {
14314 14318 warn(emsg_write_error,
14315 14319 strerror(errno));
14316 14320 result = -1;
14317 14321 goto out;
14318 14322 }
14319 14323 }
14320 14324
14321 14325 free(buf);
14322 14326 }
14323 14327 if (ret3 < 0 &&
14324 14328 scf_error() != SCF_ERROR_PERMISSION_DENIED)
14325 14329 scfdie();
14326 14330
14327 14331 /* Write closing paren if mult-value property */
14328 14332 if ((multiple && putc(')', strm) == EOF) ||
14329 14333
14330 14334 /* Write final newline */
14331 14335 fputc('\n', strm) == EOF) {
14332 14336 warn(emsg_write_error, strerror(errno));
14333 14337 result = -1;
14334 14338 goto out;
14335 14339 }
14336 14340 }
14337 14341 if (ret2 < 0)
14338 14342 scfdie();
14339 14343
14340 14344 if (fputc('\n', strm) == EOF) {
14341 14345 warn(emsg_write_error, strerror(errno));
14342 14346 result = -1;
14343 14347 goto out;
14344 14348 }
14345 14349 }
14346 14350 if (ret < 0)
14347 14351 scfdie();
14348 14352
14349 14353 out:
14350 14354 free(pname);
14351 14355 free(tybuf);
14352 14356 free(buf);
14353 14357 scf_iter_destroy(viter);
14354 14358 scf_iter_destroy(piter);
14355 14359 scf_iter_destroy(iter);
14356 14360 scf_value_destroy(val);
14357 14361 scf_property_destroy(prop);
14358 14362 scf_pg_destroy(pg);
14359 14363
14360 14364 if (result == 0) {
14361 14365 if (fflush(strm) != 0) {
14362 14366 warn(emsg_write_error, strerror(errno));
14363 14367 return (-1);
14364 14368 }
14365 14369 }
14366 14370
14367 14371 return (result);
14368 14372 }
14369 14373
14370 14374 int
14371 14375 lscf_editprop()
14372 14376 {
14373 14377 char *buf, *editor;
14374 14378 size_t bufsz;
14375 14379 int tmpfd;
14376 14380 char tempname[] = TEMP_FILE_PATTERN;
14377 14381
14378 14382 lscf_prep_hndl();
14379 14383
14380 14384 if (cur_snap != NULL) {
14381 14385 semerr(emsg_cant_modify_snapshots);
14382 14386 return (-1);
14383 14387 }
14384 14388
14385 14389 if (cur_svc == NULL && cur_inst == NULL) {
14386 14390 semerr(emsg_entity_not_selected);
14387 14391 return (-1);
14388 14392 }
14389 14393
14390 14394 tmpfd = mkstemp(tempname);
14391 14395 if (tmpfd == -1) {
14392 14396 semerr(gettext("Could not create temporary file.\n"));
14393 14397 return (-1);
14394 14398 }
14395 14399
14396 14400 (void) strcpy(tempfilename, tempname);
14397 14401
14398 14402 tempfile = fdopen(tmpfd, "r+");
14399 14403 if (tempfile == NULL) {
14400 14404 warn(gettext("Could not create temporary file.\n"));
14401 14405 if (close(tmpfd) == -1)
14402 14406 warn(gettext("Could not close temporary file: %s.\n"),
14403 14407 strerror(errno));
14404 14408
14405 14409 remove_tempfile();
14406 14410
14407 14411 return (-1);
14408 14412 }
14409 14413
14410 14414 if (write_edit_script(tempfile) == -1) {
14411 14415 remove_tempfile();
14412 14416 return (-1);
14413 14417 }
14414 14418
14415 14419 editor = getenv("EDITOR");
14416 14420 if (editor == NULL)
14417 14421 editor = "vi";
14418 14422
14419 14423 bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
14420 14424 buf = safe_malloc(bufsz);
14421 14425
14422 14426 if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
14423 14427 uu_die(gettext("Error creating editor command"));
14424 14428
14425 14429 if (system(buf) == -1) {
14426 14430 semerr(gettext("Could not launch editor %s: %s\n"), editor,
14427 14431 strerror(errno));
14428 14432 free(buf);
14429 14433 remove_tempfile();
14430 14434 return (-1);
14431 14435 }
14432 14436
14433 14437 free(buf);
14434 14438
14435 14439 (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
14436 14440
14437 14441 remove_tempfile();
14438 14442
14439 14443 return (0);
14440 14444 }
14441 14445
14442 14446 static void
14443 14447 add_string(uu_list_t *strlist, const char *str)
14444 14448 {
14445 14449 string_list_t *elem;
14446 14450 elem = safe_malloc(sizeof (*elem));
14447 14451 uu_list_node_init(elem, &elem->node, string_pool);
14448 14452 elem->str = safe_strdup(str);
14449 14453 if (uu_list_append(strlist, elem) != 0)
14450 14454 uu_die(gettext("libuutil error: %s\n"),
14451 14455 uu_strerror(uu_error()));
14452 14456 }
14453 14457
14454 14458 static int
14455 14459 remove_string(uu_list_t *strlist, const char *str)
14456 14460 {
14457 14461 uu_list_walk_t *elems;
14458 14462 string_list_t *sp;
14459 14463
14460 14464 /*
14461 14465 * Find the element that needs to be removed.
14462 14466 */
14463 14467 elems = uu_list_walk_start(strlist, UU_DEFAULT);
14464 14468 while ((sp = uu_list_walk_next(elems)) != NULL) {
14465 14469 if (strcmp(sp->str, str) == 0)
14466 14470 break;
14467 14471 }
14468 14472 uu_list_walk_end(elems);
14469 14473
14470 14474 /*
14471 14475 * Returning 1 here as the value was not found, this
14472 14476 * might not be an error. Leave it to the caller to
14473 14477 * decide.
14474 14478 */
14475 14479 if (sp == NULL) {
14476 14480 return (1);
14477 14481 }
14478 14482
14479 14483 uu_list_remove(strlist, sp);
14480 14484
14481 14485 free(sp->str);
14482 14486 free(sp);
14483 14487
14484 14488 return (0);
14485 14489 }
14486 14490
14487 14491 /*
14488 14492 * Get all property values that don't match the given glob pattern,
14489 14493 * if a pattern is specified.
14490 14494 */
14491 14495 static void
14492 14496 get_prop_values(scf_property_t *prop, uu_list_t *values,
14493 14497 const char *pattern)
14494 14498 {
14495 14499 scf_iter_t *iter;
14496 14500 scf_value_t *val;
14497 14501 int ret;
14498 14502
14499 14503 if ((iter = scf_iter_create(g_hndl)) == NULL ||
14500 14504 (val = scf_value_create(g_hndl)) == NULL)
14501 14505 scfdie();
14502 14506
14503 14507 if (scf_iter_property_values(iter, prop) != 0)
14504 14508 scfdie();
14505 14509
14506 14510 while ((ret = scf_iter_next_value(iter, val)) == 1) {
14507 14511 char *buf;
14508 14512 ssize_t vlen, szret;
14509 14513
14510 14514 vlen = scf_value_get_as_string(val, NULL, 0);
14511 14515 if (vlen < 0)
14512 14516 scfdie();
14513 14517
14514 14518 buf = safe_malloc(vlen + 1);
14515 14519
14516 14520 szret = scf_value_get_as_string(val, buf, vlen + 1);
14517 14521 if (szret < 0)
14518 14522 scfdie();
14519 14523 assert(szret <= vlen);
14520 14524
14521 14525 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14522 14526 add_string(values, buf);
14523 14527
14524 14528 free(buf);
14525 14529 }
14526 14530
14527 14531 if (ret == -1)
14528 14532 scfdie();
14529 14533
14530 14534 scf_value_destroy(val);
14531 14535 scf_iter_destroy(iter);
14532 14536 }
14533 14537
14534 14538 static int
14535 14539 lscf_setpropvalue(const char *pgname, const char *type,
14536 14540 const char *arg, int isadd, int isnotfoundok)
14537 14541 {
14538 14542 scf_type_t ty;
14539 14543 scf_propertygroup_t *pg;
14540 14544 scf_property_t *prop;
14541 14545 int ret, result = 0;
14542 14546 scf_transaction_t *tx;
14543 14547 scf_transaction_entry_t *e;
14544 14548 scf_value_t *v;
14545 14549 string_list_t *sp;
14546 14550 char *propname;
14547 14551 uu_list_t *values;
14548 14552 uu_list_walk_t *walk;
14549 14553 void *cookie = NULL;
14550 14554 char *pattern = NULL;
14551 14555
14552 14556 lscf_prep_hndl();
14553 14557
14554 14558 if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14555 14559 uu_die(gettext("Could not create property list: %s\n"),
14556 14560 uu_strerror(uu_error()));
14557 14561
14558 14562 if (!isadd)
14559 14563 pattern = safe_strdup(arg);
14560 14564
14561 14565 if ((e = scf_entry_create(g_hndl)) == NULL ||
14562 14566 (pg = scf_pg_create(g_hndl)) == NULL ||
14563 14567 (prop = scf_property_create(g_hndl)) == NULL ||
14564 14568 (tx = scf_transaction_create(g_hndl)) == NULL)
14565 14569 scfdie();
14566 14570
14567 14571 if (cur_snap != NULL) {
14568 14572 semerr(emsg_cant_modify_snapshots);
14569 14573 goto fail;
14570 14574 }
14571 14575
14572 14576 if (cur_inst == NULL && cur_svc == NULL) {
14573 14577 semerr(emsg_entity_not_selected);
14574 14578 goto fail;
14575 14579 }
14576 14580
14577 14581 propname = strchr(pgname, '/');
14578 14582 if (propname == NULL) {
14579 14583 semerr(gettext("Property names must contain a `/'.\n"));
14580 14584 goto fail;
14581 14585 }
14582 14586
14583 14587 *propname = '\0';
14584 14588 ++propname;
14585 14589
14586 14590 if (type != NULL) {
14587 14591 ty = string_to_type(type);
14588 14592 if (ty == SCF_TYPE_INVALID) {
14589 14593 semerr(gettext("Unknown type \"%s\".\n"), type);
14590 14594 goto fail;
14591 14595 }
14592 14596 }
14593 14597
14594 14598 if (cur_inst != NULL)
14595 14599 ret = scf_instance_get_pg(cur_inst, pgname, pg);
14596 14600 else
14597 14601 ret = scf_service_get_pg(cur_svc, pgname, pg);
14598 14602 if (ret != 0) {
14599 14603 switch (scf_error()) {
14600 14604 case SCF_ERROR_NOT_FOUND:
14601 14605 if (isnotfoundok) {
14602 14606 result = 0;
14603 14607 } else {
14604 14608 semerr(emsg_no_such_pg, pgname);
14605 14609 result = -1;
14606 14610 }
14607 14611 goto out;
14608 14612
14609 14613 case SCF_ERROR_INVALID_ARGUMENT:
14610 14614 semerr(emsg_invalid_pg_name, pgname);
14611 14615 goto fail;
14612 14616
14613 14617 default:
14614 14618 scfdie();
14615 14619 }
14616 14620 }
14617 14621
14618 14622 do {
14619 14623 if (scf_pg_update(pg) == -1)
14620 14624 scfdie();
14621 14625 if (scf_transaction_start(tx, pg) != 0) {
14622 14626 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14623 14627 scfdie();
14624 14628
14625 14629 semerr(emsg_permission_denied);
14626 14630 goto fail;
14627 14631 }
14628 14632
14629 14633 ret = scf_pg_get_property(pg, propname, prop);
14630 14634 if (ret == 0) {
14631 14635 scf_type_t ptype;
14632 14636 char *pat = pattern;
14633 14637
14634 14638 if (scf_property_type(prop, &ptype) != 0)
14635 14639 scfdie();
14636 14640
14637 14641 if (isadd) {
14638 14642 if (type != NULL && ptype != ty) {
14639 14643 semerr(gettext("Property \"%s\" is not "
14640 14644 "of type \"%s\".\n"), propname,
14641 14645 type);
14642 14646 goto fail;
14643 14647 }
14644 14648
14645 14649 pat = NULL;
14646 14650 } else {
14647 14651 size_t len = strlen(pat);
14648 14652 if (len > 0 && pat[len - 1] == '\"')
14649 14653 pat[len - 1] = '\0';
14650 14654 if (len > 0 && pat[0] == '\"')
14651 14655 pat++;
14652 14656 }
14653 14657
14654 14658 ty = ptype;
14655 14659
14656 14660 get_prop_values(prop, values, pat);
14657 14661
14658 14662 if (isadd)
14659 14663 add_string(values, arg);
14660 14664
14661 14665 if (scf_transaction_property_change(tx, e,
14662 14666 propname, ty) == -1)
14663 14667 scfdie();
14664 14668 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14665 14669 if (isadd) {
14666 14670 if (type == NULL) {
14667 14671 semerr(gettext("Type required "
14668 14672 "for new properties.\n"));
14669 14673 goto fail;
14670 14674 }
14671 14675
14672 14676 add_string(values, arg);
14673 14677
14674 14678 if (scf_transaction_property_new(tx, e,
14675 14679 propname, ty) == -1)
14676 14680 scfdie();
14677 14681 } else if (isnotfoundok) {
14678 14682 result = 0;
14679 14683 goto out;
14680 14684 } else {
14681 14685 semerr(gettext("No such property %s/%s.\n"),
14682 14686 pgname, propname);
14683 14687 result = -1;
14684 14688 goto out;
14685 14689 }
14686 14690 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14687 14691 semerr(emsg_invalid_prop_name, propname);
14688 14692 goto fail;
14689 14693 } else {
14690 14694 scfdie();
14691 14695 }
14692 14696
14693 14697 walk = uu_list_walk_start(values, UU_DEFAULT);
14694 14698 if (walk == NULL)
14695 14699 uu_die(gettext("Could not walk property list.\n"));
14696 14700
14697 14701 for (sp = uu_list_walk_next(walk); sp != NULL;
14698 14702 sp = uu_list_walk_next(walk)) {
14699 14703 v = string_to_value(sp->str, ty, 0);
14700 14704
14701 14705 if (v == NULL) {
14702 14706 scf_entry_destroy_children(e);
14703 14707 goto fail;
14704 14708 }
14705 14709 ret = scf_entry_add_value(e, v);
14706 14710 assert(ret == 0);
14707 14711 }
14708 14712 uu_list_walk_end(walk);
14709 14713
14710 14714 result = scf_transaction_commit(tx);
14711 14715
14712 14716 scf_transaction_reset(tx);
14713 14717 scf_entry_destroy_children(e);
14714 14718 } while (result == 0);
14715 14719
14716 14720 if (result < 0) {
14717 14721 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14718 14722 scfdie();
14719 14723
14720 14724 semerr(emsg_permission_denied);
14721 14725 goto fail;
14722 14726 }
14723 14727
14724 14728 result = 0;
14725 14729
14726 14730 private_refresh();
14727 14731
14728 14732 out:
14729 14733 scf_transaction_destroy(tx);
14730 14734 scf_entry_destroy(e);
14731 14735 scf_pg_destroy(pg);
14732 14736 scf_property_destroy(prop);
14733 14737 free(pattern);
14734 14738
14735 14739 while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14736 14740 free(sp->str);
14737 14741 free(sp);
14738 14742 }
14739 14743
14740 14744 uu_list_destroy(values);
14741 14745
14742 14746 return (result);
14743 14747
14744 14748 fail:
14745 14749 result = -1;
14746 14750 goto out;
14747 14751 }
14748 14752
14749 14753 int
14750 14754 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14751 14755 {
14752 14756 return (lscf_setpropvalue(pgname, type, value, 1, 0));
14753 14757 }
14754 14758
14755 14759 int
14756 14760 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14757 14761 {
14758 14762 return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14759 14763 }
14760 14764
14761 14765 /*
14762 14766 * Look for a standard start method, first in the instance (if any),
14763 14767 * then the service.
14764 14768 */
14765 14769 static const char *
14766 14770 start_method_name(int *in_instance)
14767 14771 {
14768 14772 scf_propertygroup_t *pg;
14769 14773 char **p;
14770 14774 int ret;
14771 14775 scf_instance_t *inst = cur_inst;
14772 14776
14773 14777 if ((pg = scf_pg_create(g_hndl)) == NULL)
14774 14778 scfdie();
14775 14779
14776 14780 again:
14777 14781 for (p = start_method_names; *p != NULL; p++) {
14778 14782 if (inst != NULL)
14779 14783 ret = scf_instance_get_pg(inst, *p, pg);
14780 14784 else
14781 14785 ret = scf_service_get_pg(cur_svc, *p, pg);
14782 14786
14783 14787 if (ret == 0) {
14784 14788 size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14785 14789 char *buf = safe_malloc(bufsz);
14786 14790
14787 14791 if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14788 14792 free(buf);
14789 14793 continue;
14790 14794 }
14791 14795 if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14792 14796 free(buf);
14793 14797 continue;
14794 14798 }
14795 14799
14796 14800 free(buf);
14797 14801 *in_instance = (inst != NULL);
14798 14802 scf_pg_destroy(pg);
14799 14803 return (*p);
14800 14804 }
14801 14805
14802 14806 if (scf_error() == SCF_ERROR_NOT_FOUND)
14803 14807 continue;
14804 14808
14805 14809 scfdie();
14806 14810 }
14807 14811
14808 14812 if (inst != NULL) {
14809 14813 inst = NULL;
14810 14814 goto again;
14811 14815 }
14812 14816
14813 14817 scf_pg_destroy(pg);
14814 14818 return (NULL);
14815 14819 }
14816 14820
14817 14821 static int
14818 14822 addpg(const char *name, const char *type)
14819 14823 {
14820 14824 scf_propertygroup_t *pg;
14821 14825 int ret;
14822 14826
14823 14827 pg = scf_pg_create(g_hndl);
14824 14828 if (pg == NULL)
14825 14829 scfdie();
14826 14830
14827 14831 if (cur_inst != NULL)
14828 14832 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14829 14833 else
14830 14834 ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14831 14835
14832 14836 if (ret != 0) {
14833 14837 switch (scf_error()) {
14834 14838 case SCF_ERROR_EXISTS:
14835 14839 ret = 0;
14836 14840 break;
14837 14841
14838 14842 case SCF_ERROR_PERMISSION_DENIED:
14839 14843 semerr(emsg_permission_denied);
14840 14844 break;
14841 14845
14842 14846 default:
14843 14847 scfdie();
14844 14848 }
14845 14849 }
14846 14850
14847 14851 scf_pg_destroy(pg);
14848 14852 return (ret);
14849 14853 }
14850 14854
14851 14855 int
14852 14856 lscf_setenv(uu_list_t *args, int isunset)
14853 14857 {
14854 14858 int ret = 0;
14855 14859 size_t i;
14856 14860 int argc;
14857 14861 char **argv = NULL;
14858 14862 string_list_t *slp;
14859 14863 char *pattern;
14860 14864 char *prop;
14861 14865 int do_service = 0;
14862 14866 int do_instance = 0;
14863 14867 const char *method = NULL;
14864 14868 const char *name = NULL;
14865 14869 const char *value = NULL;
14866 14870 scf_instance_t *saved_cur_inst = cur_inst;
14867 14871
14868 14872 lscf_prep_hndl();
14869 14873
14870 14874 argc = uu_list_numnodes(args);
14871 14875 if (argc < 1)
14872 14876 goto usage;
14873 14877
14874 14878 argv = calloc(argc + 1, sizeof (char *));
14875 14879 if (argv == NULL)
14876 14880 uu_die(gettext("Out of memory.\n"));
14877 14881
14878 14882 for (slp = uu_list_first(args), i = 0;
14879 14883 slp != NULL;
14880 14884 slp = uu_list_next(args, slp), ++i)
14881 14885 argv[i] = slp->str;
14882 14886
14883 14887 argv[i] = NULL;
14884 14888
14885 14889 opterr = 0;
14886 14890 optind = 0;
14887 14891 for (;;) {
14888 14892 ret = getopt(argc, argv, "sim:");
14889 14893 if (ret == -1)
14890 14894 break;
14891 14895
14892 14896 switch (ret) {
14893 14897 case 's':
14894 14898 do_service = 1;
14895 14899 cur_inst = NULL;
14896 14900 break;
14897 14901
14898 14902 case 'i':
14899 14903 do_instance = 1;
14900 14904 break;
14901 14905
14902 14906 case 'm':
14903 14907 method = optarg;
14904 14908 break;
14905 14909
14906 14910 case '?':
14907 14911 goto usage;
14908 14912
14909 14913 default:
14910 14914 bad_error("getopt", ret);
14911 14915 }
14912 14916 }
14913 14917
14914 14918 argc -= optind;
14915 14919 if ((do_service && do_instance) ||
14916 14920 (isunset && argc != 1) ||
14917 14921 (!isunset && argc != 2))
14918 14922 goto usage;
14919 14923
14920 14924 name = argv[optind];
14921 14925 if (!isunset)
14922 14926 value = argv[optind + 1];
14923 14927
14924 14928 if (cur_snap != NULL) {
14925 14929 semerr(emsg_cant_modify_snapshots);
14926 14930 ret = -1;
14927 14931 goto out;
14928 14932 }
14929 14933
14930 14934 if (cur_inst == NULL && cur_svc == NULL) {
14931 14935 semerr(emsg_entity_not_selected);
14932 14936 ret = -1;
14933 14937 goto out;
14934 14938 }
14935 14939
14936 14940 if (do_instance && cur_inst == NULL) {
14937 14941 semerr(gettext("No instance is selected.\n"));
14938 14942 ret = -1;
14939 14943 goto out;
14940 14944 }
14941 14945
14942 14946 if (do_service && cur_svc == NULL) {
14943 14947 semerr(gettext("No service is selected.\n"));
14944 14948 ret = -1;
14945 14949 goto out;
14946 14950 }
14947 14951
14948 14952 if (method == NULL) {
14949 14953 if (do_instance || do_service) {
14950 14954 method = "method_context";
14951 14955 if (!isunset) {
14952 14956 ret = addpg("method_context",
14953 14957 SCF_GROUP_FRAMEWORK);
14954 14958 if (ret != 0)
14955 14959 goto out;
14956 14960 }
14957 14961 } else {
14958 14962 int in_instance;
14959 14963 method = start_method_name(&in_instance);
14960 14964 if (method == NULL) {
14961 14965 semerr(gettext(
14962 14966 "Couldn't find start method; please "
14963 14967 "specify a method with '-m'.\n"));
14964 14968 ret = -1;
14965 14969 goto out;
14966 14970 }
14967 14971 if (!in_instance)
14968 14972 cur_inst = NULL;
14969 14973 }
14970 14974 } else {
14971 14975 scf_propertygroup_t *pg;
14972 14976 size_t bufsz;
14973 14977 char *buf;
14974 14978 int ret;
14975 14979
14976 14980 if ((pg = scf_pg_create(g_hndl)) == NULL)
14977 14981 scfdie();
14978 14982
14979 14983 if (cur_inst != NULL)
14980 14984 ret = scf_instance_get_pg(cur_inst, method, pg);
14981 14985 else
14982 14986 ret = scf_service_get_pg(cur_svc, method, pg);
14983 14987
14984 14988 if (ret != 0) {
14985 14989 scf_pg_destroy(pg);
14986 14990 switch (scf_error()) {
14987 14991 case SCF_ERROR_NOT_FOUND:
14988 14992 semerr(gettext("Couldn't find the method "
14989 14993 "\"%s\".\n"), method);
14990 14994 goto out;
14991 14995
14992 14996 case SCF_ERROR_INVALID_ARGUMENT:
14993 14997 semerr(gettext("Invalid method name \"%s\".\n"),
14994 14998 method);
14995 14999 goto out;
14996 15000
14997 15001 default:
14998 15002 scfdie();
14999 15003 }
15000 15004 }
15001 15005
15002 15006 bufsz = strlen(SCF_GROUP_METHOD) + 1;
15003 15007 buf = safe_malloc(bufsz);
15004 15008
15005 15009 if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
15006 15010 strcmp(buf, SCF_GROUP_METHOD) != 0) {
15007 15011 semerr(gettext("Property group \"%s\" is not of type "
15008 15012 "\"method\".\n"), method);
15009 15013 ret = -1;
15010 15014 free(buf);
15011 15015 scf_pg_destroy(pg);
15012 15016 goto out;
15013 15017 }
15014 15018
15015 15019 free(buf);
15016 15020 scf_pg_destroy(pg);
15017 15021 }
15018 15022
15019 15023 prop = uu_msprintf("%s/environment", method);
15020 15024 pattern = uu_msprintf("%s=*", name);
15021 15025
15022 15026 if (prop == NULL || pattern == NULL)
15023 15027 uu_die(gettext("Out of memory.\n"));
15024 15028
15025 15029 ret = lscf_delpropvalue(prop, pattern, !isunset);
15026 15030
15027 15031 if (ret == 0 && !isunset) {
15028 15032 uu_free(pattern);
15029 15033 uu_free(prop);
15030 15034 prop = uu_msprintf("%s/environment", method);
15031 15035 pattern = uu_msprintf("%s=%s", name, value);
15032 15036 if (prop == NULL || pattern == NULL)
15033 15037 uu_die(gettext("Out of memory.\n"));
15034 15038 ret = lscf_addpropvalue(prop, "astring:", pattern);
15035 15039 }
15036 15040 uu_free(pattern);
15037 15041 uu_free(prop);
15038 15042
15039 15043 out:
15040 15044 cur_inst = saved_cur_inst;
15041 15045
15042 15046 free(argv);
15043 15047 return (ret);
15044 15048 usage:
15045 15049 ret = -2;
15046 15050 goto out;
15047 15051 }
15048 15052
15049 15053 /*
15050 15054 * Snapshot commands
15051 15055 */
15052 15056
15053 15057 void
15054 15058 lscf_listsnap()
15055 15059 {
15056 15060 scf_snapshot_t *snap;
15057 15061 scf_iter_t *iter;
15058 15062 char *nb;
15059 15063 int r;
15060 15064
15061 15065 lscf_prep_hndl();
15062 15066
15063 15067 if (cur_inst == NULL) {
15064 15068 semerr(gettext("Instance not selected.\n"));
15065 15069 return;
15066 15070 }
15067 15071
15068 15072 if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15069 15073 (iter = scf_iter_create(g_hndl)) == NULL)
15070 15074 scfdie();
15071 15075
15072 15076 if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
15073 15077 scfdie();
15074 15078
15075 15079 nb = safe_malloc(max_scf_name_len + 1);
15076 15080
15077 15081 while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
15078 15082 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
15079 15083 scfdie();
15080 15084
15081 15085 (void) puts(nb);
15082 15086 }
15083 15087 if (r < 0)
15084 15088 scfdie();
15085 15089
15086 15090 free(nb);
15087 15091 scf_iter_destroy(iter);
15088 15092 scf_snapshot_destroy(snap);
15089 15093 }
15090 15094
15091 15095 void
15092 15096 lscf_selectsnap(const char *name)
15093 15097 {
15094 15098 scf_snapshot_t *snap;
15095 15099 scf_snaplevel_t *level;
15096 15100
15097 15101 lscf_prep_hndl();
15098 15102
15099 15103 if (cur_inst == NULL) {
15100 15104 semerr(gettext("Instance not selected.\n"));
15101 15105 return;
15102 15106 }
15103 15107
15104 15108 if (cur_snap != NULL) {
15105 15109 if (name != NULL) {
15106 15110 char *cur_snap_name;
15107 15111 boolean_t nochange;
15108 15112
15109 15113 cur_snap_name = safe_malloc(max_scf_name_len + 1);
15110 15114
15111 15115 if (scf_snapshot_get_name(cur_snap, cur_snap_name,
15112 15116 max_scf_name_len + 1) < 0)
15113 15117 scfdie();
15114 15118
15115 15119 nochange = strcmp(name, cur_snap_name) == 0;
15116 15120
15117 15121 free(cur_snap_name);
15118 15122
15119 15123 if (nochange)
15120 15124 return;
15121 15125 }
15122 15126
15123 15127 unselect_cursnap();
15124 15128 }
15125 15129
15126 15130 if (name == NULL)
15127 15131 return;
15128 15132
15129 15133 if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15130 15134 (level = scf_snaplevel_create(g_hndl)) == NULL)
15131 15135 scfdie();
15132 15136
15133 15137 if (scf_instance_get_snapshot(cur_inst, name, snap) !=
15134 15138 SCF_SUCCESS) {
15135 15139 switch (scf_error()) {
15136 15140 case SCF_ERROR_INVALID_ARGUMENT:
15137 15141 semerr(gettext("Invalid name \"%s\".\n"), name);
15138 15142 break;
15139 15143
15140 15144 case SCF_ERROR_NOT_FOUND:
15141 15145 semerr(gettext("No such snapshot \"%s\".\n"), name);
15142 15146 break;
15143 15147
15144 15148 default:
15145 15149 scfdie();
15146 15150 }
15147 15151
15148 15152 scf_snaplevel_destroy(level);
15149 15153 scf_snapshot_destroy(snap);
15150 15154 return;
15151 15155 }
15152 15156
15153 15157 /* Load the snaplevels into our list. */
15154 15158 cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
15155 15159 if (cur_levels == NULL)
15156 15160 uu_die(gettext("Could not create list: %s\n"),
15157 15161 uu_strerror(uu_error()));
15158 15162
15159 15163 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15160 15164 if (scf_error() != SCF_ERROR_NOT_FOUND)
15161 15165 scfdie();
15162 15166
15163 15167 semerr(gettext("Snapshot has no snaplevels.\n"));
15164 15168
15165 15169 scf_snaplevel_destroy(level);
15166 15170 scf_snapshot_destroy(snap);
15167 15171 return;
15168 15172 }
15169 15173
15170 15174 cur_snap = snap;
15171 15175
15172 15176 for (;;) {
15173 15177 cur_elt = safe_malloc(sizeof (*cur_elt));
15174 15178 uu_list_node_init(cur_elt, &cur_elt->list_node,
15175 15179 snaplevel_pool);
15176 15180 cur_elt->sl = level;
15177 15181 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
15178 15182 uu_die(gettext("libuutil error: %s\n"),
15179 15183 uu_strerror(uu_error()));
15180 15184
15181 15185 level = scf_snaplevel_create(g_hndl);
15182 15186 if (level == NULL)
15183 15187 scfdie();
15184 15188
15185 15189 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
15186 15190 level) != SCF_SUCCESS) {
15187 15191 if (scf_error() != SCF_ERROR_NOT_FOUND)
15188 15192 scfdie();
15189 15193
15190 15194 scf_snaplevel_destroy(level);
15191 15195 break;
15192 15196 }
15193 15197 }
15194 15198
15195 15199 cur_elt = uu_list_last(cur_levels);
15196 15200 cur_level = cur_elt->sl;
15197 15201 }
15198 15202
15199 15203 /*
15200 15204 * Copies the properties & values in src to dst. Assumes src won't change.
15201 15205 * Returns -1 if permission is denied, -2 if another transaction interrupts,
15202 15206 * and 0 on success.
15203 15207 *
15204 15208 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
15205 15209 * property, if it is copied and has type boolean. (See comment in
15206 15210 * lscf_revert()).
15207 15211 */
15208 15212 static int
15209 15213 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
15210 15214 uint8_t enabled)
15211 15215 {
15212 15216 scf_transaction_t *tx;
15213 15217 scf_iter_t *iter, *viter;
15214 15218 scf_property_t *prop;
15215 15219 scf_value_t *v;
15216 15220 char *nbuf;
15217 15221 int r;
15218 15222
15219 15223 tx = scf_transaction_create(g_hndl);
15220 15224 if (tx == NULL)
15221 15225 scfdie();
15222 15226
15223 15227 if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
15224 15228 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15225 15229 scfdie();
15226 15230
15227 15231 scf_transaction_destroy(tx);
15228 15232
15229 15233 return (-1);
15230 15234 }
15231 15235
15232 15236 if ((iter = scf_iter_create(g_hndl)) == NULL ||
15233 15237 (prop = scf_property_create(g_hndl)) == NULL ||
15234 15238 (viter = scf_iter_create(g_hndl)) == NULL)
15235 15239 scfdie();
15236 15240
15237 15241 nbuf = safe_malloc(max_scf_name_len + 1);
15238 15242
15239 15243 if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
15240 15244 scfdie();
15241 15245
15242 15246 for (;;) {
15243 15247 scf_transaction_entry_t *e;
15244 15248 scf_type_t ty;
15245 15249
15246 15250 r = scf_iter_next_property(iter, prop);
15247 15251 if (r == -1)
15248 15252 scfdie();
15249 15253 if (r == 0)
15250 15254 break;
15251 15255
15252 15256 e = scf_entry_create(g_hndl);
15253 15257 if (e == NULL)
15254 15258 scfdie();
15255 15259
15256 15260 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
15257 15261 scfdie();
15258 15262
15259 15263 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
15260 15264 scfdie();
15261 15265
15262 15266 if (scf_transaction_property_new(tx, e, nbuf,
15263 15267 ty) != SCF_SUCCESS)
15264 15268 scfdie();
15265 15269
15266 15270 if ((enabled == 0 || enabled == 1) &&
15267 15271 strcmp(nbuf, scf_property_enabled) == 0 &&
15268 15272 ty == SCF_TYPE_BOOLEAN) {
15269 15273 v = scf_value_create(g_hndl);
15270 15274 if (v == NULL)
15271 15275 scfdie();
15272 15276
15273 15277 scf_value_set_boolean(v, enabled);
15274 15278
15275 15279 if (scf_entry_add_value(e, v) != 0)
15276 15280 scfdie();
15277 15281 } else {
15278 15282 if (scf_iter_property_values(viter, prop) != 0)
15279 15283 scfdie();
15280 15284
15281 15285 for (;;) {
15282 15286 v = scf_value_create(g_hndl);
15283 15287 if (v == NULL)
15284 15288 scfdie();
15285 15289
15286 15290 r = scf_iter_next_value(viter, v);
15287 15291 if (r == -1)
15288 15292 scfdie();
15289 15293 if (r == 0) {
15290 15294 scf_value_destroy(v);
15291 15295 break;
15292 15296 }
15293 15297
15294 15298 if (scf_entry_add_value(e, v) != SCF_SUCCESS)
15295 15299 scfdie();
15296 15300 }
15297 15301 }
15298 15302 }
15299 15303
15300 15304 free(nbuf);
15301 15305 scf_iter_destroy(viter);
15302 15306 scf_property_destroy(prop);
15303 15307 scf_iter_destroy(iter);
15304 15308
15305 15309 r = scf_transaction_commit(tx);
15306 15310 if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
15307 15311 scfdie();
15308 15312
15309 15313 scf_transaction_destroy_children(tx);
15310 15314 scf_transaction_destroy(tx);
15311 15315
15312 15316 switch (r) {
15313 15317 case 1: return (0);
15314 15318 case 0: return (-2);
15315 15319 case -1: return (-1);
15316 15320
15317 15321 default:
15318 15322 abort();
15319 15323 }
15320 15324
15321 15325 /* NOTREACHED */
15322 15326 }
15323 15327
15324 15328 void
15325 15329 lscf_revert(const char *snapname)
15326 15330 {
15327 15331 scf_snapshot_t *snap, *prev;
15328 15332 scf_snaplevel_t *level, *nlevel;
15329 15333 scf_iter_t *iter;
15330 15334 scf_propertygroup_t *pg, *npg;
15331 15335 scf_property_t *prop;
15332 15336 scf_value_t *val;
15333 15337 char *nbuf, *tbuf;
15334 15338 uint8_t enabled;
15335 15339
15336 15340 lscf_prep_hndl();
15337 15341
15338 15342 if (cur_inst == NULL) {
15339 15343 semerr(gettext("Instance not selected.\n"));
15340 15344 return;
15341 15345 }
15342 15346
15343 15347 if (snapname != NULL) {
15344 15348 snap = scf_snapshot_create(g_hndl);
15345 15349 if (snap == NULL)
15346 15350 scfdie();
15347 15351
15348 15352 if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
15349 15353 SCF_SUCCESS) {
15350 15354 switch (scf_error()) {
15351 15355 case SCF_ERROR_INVALID_ARGUMENT:
15352 15356 semerr(gettext("Invalid snapshot name "
15353 15357 "\"%s\".\n"), snapname);
15354 15358 break;
15355 15359
15356 15360 case SCF_ERROR_NOT_FOUND:
15357 15361 semerr(gettext("No such snapshot.\n"));
15358 15362 break;
15359 15363
15360 15364 default:
15361 15365 scfdie();
15362 15366 }
15363 15367
15364 15368 scf_snapshot_destroy(snap);
15365 15369 return;
15366 15370 }
15367 15371 } else {
15368 15372 if (cur_snap != NULL) {
15369 15373 snap = cur_snap;
15370 15374 } else {
15371 15375 semerr(gettext("No snapshot selected.\n"));
15372 15376 return;
15373 15377 }
15374 15378 }
15375 15379
15376 15380 if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
15377 15381 (level = scf_snaplevel_create(g_hndl)) == NULL ||
15378 15382 (iter = scf_iter_create(g_hndl)) == NULL ||
15379 15383 (pg = scf_pg_create(g_hndl)) == NULL ||
15380 15384 (npg = scf_pg_create(g_hndl)) == NULL ||
15381 15385 (prop = scf_property_create(g_hndl)) == NULL ||
15382 15386 (val = scf_value_create(g_hndl)) == NULL)
15383 15387 scfdie();
15384 15388
15385 15389 nbuf = safe_malloc(max_scf_name_len + 1);
15386 15390 tbuf = safe_malloc(max_scf_pg_type_len + 1);
15387 15391
15388 15392 /* Take the "previous" snapshot before we blow away the properties. */
15389 15393 if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
15390 15394 if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
15391 15395 scfdie();
15392 15396 } else {
15393 15397 if (scf_error() != SCF_ERROR_NOT_FOUND)
15394 15398 scfdie();
15395 15399
15396 15400 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
15397 15401 scfdie();
15398 15402 }
15399 15403
15400 15404 /* Save general/enabled, since we're probably going to replace it. */
15401 15405 enabled = 2;
15402 15406 if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
15403 15407 scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
15404 15408 scf_property_get_value(prop, val) == 0)
15405 15409 (void) scf_value_get_boolean(val, &enabled);
15406 15410
15407 15411 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15408 15412 if (scf_error() != SCF_ERROR_NOT_FOUND)
15409 15413 scfdie();
15410 15414
15411 15415 goto out;
15412 15416 }
15413 15417
15414 15418 for (;;) {
15415 15419 boolean_t isinst;
15416 15420 uint32_t flags;
15417 15421 int r;
15418 15422
15419 15423 /* Clear the properties from the corresponding entity. */
15420 15424 isinst = snaplevel_is_instance(level);
15421 15425
15422 15426 if (!isinst)
15423 15427 r = scf_iter_service_pgs(iter, cur_svc);
15424 15428 else
15425 15429 r = scf_iter_instance_pgs(iter, cur_inst);
15426 15430 if (r != SCF_SUCCESS)
15427 15431 scfdie();
15428 15432
15429 15433 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15430 15434 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15431 15435 scfdie();
15432 15436
15433 15437 /* Skip nonpersistent pgs. */
15434 15438 if (flags & SCF_PG_FLAG_NONPERSISTENT)
15435 15439 continue;
15436 15440
15437 15441 if (scf_pg_delete(pg) != SCF_SUCCESS) {
15438 15442 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15439 15443 scfdie();
15440 15444
15441 15445 semerr(emsg_permission_denied);
15442 15446 goto out;
15443 15447 }
15444 15448 }
15445 15449 if (r == -1)
15446 15450 scfdie();
15447 15451
15448 15452 /* Copy the properties to the corresponding entity. */
15449 15453 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
15450 15454 scfdie();
15451 15455
15452 15456 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15453 15457 if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
15454 15458 scfdie();
15455 15459
15456 15460 if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
15457 15461 0)
15458 15462 scfdie();
15459 15463
15460 15464 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15461 15465 scfdie();
15462 15466
15463 15467 if (!isinst)
15464 15468 r = scf_service_add_pg(cur_svc, nbuf, tbuf,
15465 15469 flags, npg);
15466 15470 else
15467 15471 r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
15468 15472 flags, npg);
15469 15473 if (r != SCF_SUCCESS) {
15470 15474 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15471 15475 scfdie();
15472 15476
15473 15477 semerr(emsg_permission_denied);
15474 15478 goto out;
15475 15479 }
15476 15480
15477 15481 if ((enabled == 0 || enabled == 1) &&
15478 15482 strcmp(nbuf, scf_pg_general) == 0)
15479 15483 r = pg_copy(pg, npg, enabled);
15480 15484 else
15481 15485 r = pg_copy(pg, npg, 2);
15482 15486
15483 15487 switch (r) {
15484 15488 case 0:
15485 15489 break;
15486 15490
15487 15491 case -1:
15488 15492 semerr(emsg_permission_denied);
15489 15493 goto out;
15490 15494
15491 15495 case -2:
15492 15496 semerr(gettext(
15493 15497 "Interrupted by another change.\n"));
15494 15498 goto out;
15495 15499
15496 15500 default:
15497 15501 abort();
15498 15502 }
15499 15503 }
15500 15504 if (r == -1)
15501 15505 scfdie();
15502 15506
15503 15507 /* Get next level. */
15504 15508 nlevel = scf_snaplevel_create(g_hndl);
15505 15509 if (nlevel == NULL)
15506 15510 scfdie();
15507 15511
15508 15512 if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
15509 15513 SCF_SUCCESS) {
15510 15514 if (scf_error() != SCF_ERROR_NOT_FOUND)
15511 15515 scfdie();
15512 15516
15513 15517 scf_snaplevel_destroy(nlevel);
15514 15518 break;
15515 15519 }
15516 15520
15517 15521 scf_snaplevel_destroy(level);
15518 15522 level = nlevel;
15519 15523 }
15520 15524
15521 15525 if (snapname == NULL) {
15522 15526 lscf_selectsnap(NULL);
15523 15527 snap = NULL; /* cur_snap has been destroyed */
15524 15528 }
15525 15529
15526 15530 out:
15527 15531 free(tbuf);
15528 15532 free(nbuf);
15529 15533 scf_value_destroy(val);
15530 15534 scf_property_destroy(prop);
15531 15535 scf_pg_destroy(npg);
15532 15536 scf_pg_destroy(pg);
15533 15537 scf_iter_destroy(iter);
15534 15538 scf_snaplevel_destroy(level);
15535 15539 scf_snapshot_destroy(prev);
15536 15540 if (snap != cur_snap)
15537 15541 scf_snapshot_destroy(snap);
15538 15542 }
15539 15543
15540 15544 void
15541 15545 lscf_refresh(void)
15542 15546 {
15543 15547 ssize_t fmrilen;
15544 15548 size_t bufsz;
15545 15549 char *fmribuf;
15546 15550 int r;
15547 15551
15548 15552 lscf_prep_hndl();
15549 15553
15550 15554 if (cur_inst == NULL) {
15551 15555 semerr(gettext("Instance not selected.\n"));
15552 15556 return;
15553 15557 }
15554 15558
15555 15559 bufsz = max_scf_fmri_len + 1;
15556 15560 fmribuf = safe_malloc(bufsz);
15557 15561 fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15558 15562 if (fmrilen < 0) {
15559 15563 free(fmribuf);
15560 15564 if (scf_error() != SCF_ERROR_DELETED)
15561 15565 scfdie();
15562 15566 scf_instance_destroy(cur_inst);
15563 15567 cur_inst = NULL;
15564 15568 warn(emsg_deleted);
15565 15569 return;
15566 15570 }
15567 15571 assert(fmrilen < bufsz);
15568 15572
15569 15573 r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15570 15574 switch (r) {
15571 15575 case 0:
15572 15576 break;
15573 15577
15574 15578 case ECONNABORTED:
15575 15579 warn(gettext("Could not refresh %s "
15576 15580 "(repository connection broken).\n"), fmribuf);
15577 15581 break;
15578 15582
15579 15583 case ECANCELED:
15580 15584 warn(emsg_deleted);
15581 15585 break;
15582 15586
15583 15587 case EPERM:
15584 15588 warn(gettext("Could not refresh %s "
15585 15589 "(permission denied).\n"), fmribuf);
15586 15590 break;
15587 15591
15588 15592 case ENOSPC:
15589 15593 warn(gettext("Could not refresh %s "
15590 15594 "(repository server out of resources).\n"),
15591 15595 fmribuf);
15592 15596 break;
15593 15597
15594 15598 case EACCES:
15595 15599 default:
15596 15600 bad_error("refresh_entity", scf_error());
15597 15601 }
15598 15602
15599 15603 free(fmribuf);
15600 15604 }
15601 15605
15602 15606 /*
15603 15607 * describe [-v] [-t] [pg/prop]
15604 15608 */
15605 15609 int
15606 15610 lscf_describe(uu_list_t *args, int hasargs)
15607 15611 {
15608 15612 int ret = 0;
15609 15613 size_t i;
15610 15614 int argc;
15611 15615 char **argv = NULL;
15612 15616 string_list_t *slp;
15613 15617 int do_verbose = 0;
15614 15618 int do_templates = 0;
15615 15619 char *pattern = NULL;
15616 15620
15617 15621 lscf_prep_hndl();
15618 15622
15619 15623 if (hasargs != 0) {
15620 15624 argc = uu_list_numnodes(args);
15621 15625 if (argc < 1)
15622 15626 goto usage;
15623 15627
15624 15628 argv = calloc(argc + 1, sizeof (char *));
15625 15629 if (argv == NULL)
15626 15630 uu_die(gettext("Out of memory.\n"));
15627 15631
15628 15632 for (slp = uu_list_first(args), i = 0;
15629 15633 slp != NULL;
15630 15634 slp = uu_list_next(args, slp), ++i)
15631 15635 argv[i] = slp->str;
15632 15636
15633 15637 argv[i] = NULL;
15634 15638
15635 15639 /*
15636 15640 * We start optind = 0 because our list of arguments
15637 15641 * starts at argv[0]
15638 15642 */
15639 15643 optind = 0;
15640 15644 opterr = 0;
15641 15645 for (;;) {
15642 15646 ret = getopt(argc, argv, "vt");
15643 15647 if (ret == -1)
15644 15648 break;
15645 15649
15646 15650 switch (ret) {
15647 15651 case 'v':
15648 15652 do_verbose = 1;
15649 15653 break;
15650 15654
15651 15655 case 't':
15652 15656 do_templates = 1;
15653 15657 break;
15654 15658
15655 15659 case '?':
15656 15660 goto usage;
15657 15661
15658 15662 default:
15659 15663 bad_error("getopt", ret);
15660 15664 }
15661 15665 }
15662 15666
15663 15667 pattern = argv[optind];
15664 15668 }
15665 15669
15666 15670 if (cur_inst == NULL && cur_svc == NULL) {
15667 15671 semerr(emsg_entity_not_selected);
15668 15672 ret = -1;
15669 15673 goto out;
15670 15674 }
15671 15675
15672 15676 /*
15673 15677 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15674 15678 * output if their last parameter is set to 2. Less information is
15675 15679 * produced if the parameter is set to 1.
15676 15680 */
15677 15681 if (pattern == NULL) {
15678 15682 if (do_verbose == 1)
15679 15683 list_entity_tmpl(2);
15680 15684 else
15681 15685 list_entity_tmpl(1);
15682 15686 }
15683 15687
15684 15688 if (do_templates == 0) {
15685 15689 if (do_verbose == 1)
15686 15690 listprop(pattern, 0, 2);
15687 15691 else
15688 15692 listprop(pattern, 0, 1);
15689 15693 } else {
15690 15694 if (do_verbose == 1)
15691 15695 listtmpl(pattern, 2);
15692 15696 else
15693 15697 listtmpl(pattern, 1);
15694 15698 }
15695 15699
15696 15700 ret = 0;
15697 15701 out:
15698 15702 if (argv != NULL)
15699 15703 free(argv);
15700 15704 return (ret);
15701 15705 usage:
15702 15706 ret = -2;
15703 15707 goto out;
15704 15708 }
15705 15709
15706 15710 #define PARAM_ACTIVE ((const char *) "active")
15707 15711 #define PARAM_INACTIVE ((const char *) "inactive")
15708 15712 #define PARAM_SMTP_TO ((const char *) "to")
15709 15713
15710 15714 /*
15711 15715 * tokenize()
15712 15716 * Breaks down the string according to the tokens passed.
15713 15717 * Caller is responsible for freeing array of pointers returned.
15714 15718 * Returns NULL on failure
15715 15719 */
15716 15720 char **
15717 15721 tokenize(char *str, const char *sep)
15718 15722 {
15719 15723 char *token, *lasts;
15720 15724 char **buf;
15721 15725 int n = 0; /* number of elements */
15722 15726 int size = 8; /* size of the array (initial) */
15723 15727
15724 15728 buf = safe_malloc(size * sizeof (char *));
15725 15729
15726 15730 for (token = strtok_r(str, sep, &lasts); token != NULL;
15727 15731 token = strtok_r(NULL, sep, &lasts), ++n) {
15728 15732 if (n + 1 >= size) {
15729 15733 size *= 2;
15730 15734 if ((buf = realloc(buf, size * sizeof (char *))) ==
15731 15735 NULL) {
15732 15736 uu_die(gettext("Out of memory"));
15733 15737 }
15734 15738 }
15735 15739 buf[n] = token;
15736 15740 }
15737 15741 /* NULL terminate the pointer array */
15738 15742 buf[n] = NULL;
15739 15743
15740 15744 return (buf);
15741 15745 }
15742 15746
15743 15747 int32_t
15744 15748 check_tokens(char **p)
15745 15749 {
15746 15750 int32_t smf = 0;
15747 15751 int32_t fma = 0;
15748 15752
15749 15753 while (*p) {
15750 15754 int32_t t = string_to_tset(*p);
15751 15755
15752 15756 if (t == 0) {
15753 15757 if (is_fma_token(*p) == 0)
15754 15758 return (INVALID_TOKENS);
15755 15759 fma = 1; /* this token is an fma event */
15756 15760 } else {
15757 15761 smf |= t;
15758 15762 }
15759 15763
15760 15764 if (smf != 0 && fma == 1)
15761 15765 return (MIXED_TOKENS);
15762 15766 ++p;
15763 15767 }
15764 15768
15765 15769 if (smf > 0)
15766 15770 return (smf);
15767 15771 else if (fma == 1)
15768 15772 return (FMA_TOKENS);
15769 15773
15770 15774 return (INVALID_TOKENS);
15771 15775 }
15772 15776
15773 15777 static int
15774 15778 get_selection_str(char *fmri, size_t sz)
15775 15779 {
15776 15780 if (g_hndl == NULL) {
15777 15781 semerr(emsg_entity_not_selected);
15778 15782 return (-1);
15779 15783 } else if (cur_level != NULL) {
15780 15784 semerr(emsg_invalid_for_snapshot);
15781 15785 return (-1);
15782 15786 } else {
15783 15787 lscf_get_selection_str(fmri, sz);
15784 15788 }
15785 15789
15786 15790 return (0);
15787 15791 }
15788 15792
15789 15793 void
15790 15794 lscf_delnotify(const char *set, int global)
15791 15795 {
15792 15796 char *str = strdup(set);
15793 15797 char **pgs;
15794 15798 char **p;
15795 15799 int32_t tset;
15796 15800 char *fmri = NULL;
15797 15801
15798 15802 if (str == NULL)
15799 15803 uu_die(gettext("Out of memory.\n"));
15800 15804
15801 15805 pgs = tokenize(str, ",");
15802 15806
15803 15807 if ((tset = check_tokens(pgs)) > 0) {
15804 15808 size_t sz = max_scf_fmri_len + 1;
15805 15809
15806 15810 fmri = safe_malloc(sz);
15807 15811 if (global) {
15808 15812 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15809 15813 } else if (get_selection_str(fmri, sz) != 0) {
15810 15814 goto out;
15811 15815 }
15812 15816
15813 15817 if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri,
15814 15818 tset) != SCF_SUCCESS) {
15815 15819 uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15816 15820 scf_strerror(scf_error()));
15817 15821 }
15818 15822 } else if (tset == FMA_TOKENS) {
15819 15823 if (global) {
15820 15824 semerr(gettext("Can't use option '-g' with FMA event "
15821 15825 "definitions\n"));
15822 15826 goto out;
15823 15827 }
15824 15828
15825 15829 for (p = pgs; *p; ++p) {
15826 15830 if (smf_notify_del_params(de_tag(*p), NULL, 0) !=
15827 15831 SCF_SUCCESS) {
15828 15832 uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
15829 15833 scf_strerror(scf_error()));
15830 15834 goto out;
15831 15835 }
15832 15836 }
15833 15837 } else if (tset == MIXED_TOKENS) {
15834 15838 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15835 15839 goto out;
15836 15840 } else {
15837 15841 uu_die(gettext("Invalid input.\n"));
15838 15842 }
15839 15843
15840 15844 out:
15841 15845 free(fmri);
15842 15846 free(pgs);
15843 15847 free(str);
15844 15848 }
15845 15849
15846 15850 void
15847 15851 lscf_listnotify(const char *set, int global)
15848 15852 {
15849 15853 char *str = safe_strdup(set);
15850 15854 char **pgs;
15851 15855 char **p;
15852 15856 int32_t tset;
15853 15857 nvlist_t *nvl;
15854 15858 char *fmri = NULL;
15855 15859
15856 15860 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
15857 15861 uu_die(gettext("Out of memory.\n"));
15858 15862
15859 15863 pgs = tokenize(str, ",");
15860 15864
15861 15865 if ((tset = check_tokens(pgs)) > 0) {
15862 15866 size_t sz = max_scf_fmri_len + 1;
15863 15867
15864 15868 fmri = safe_malloc(sz);
15865 15869 if (global) {
15866 15870 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15867 15871 } else if (get_selection_str(fmri, sz) != 0) {
15868 15872 goto out;
15869 15873 }
15870 15874
15871 15875 if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
15872 15876 SCF_SUCCESS) {
15873 15877 if (scf_error() != SCF_ERROR_NOT_FOUND &&
15874 15878 scf_error() != SCF_ERROR_DELETED)
15875 15879 uu_warn(gettext(
15876 15880 "Failed listnotify: %s\n"),
15877 15881 scf_strerror(scf_error()));
15878 15882 goto out;
15879 15883 }
15880 15884
15881 15885 listnotify_print(nvl, NULL);
15882 15886 } else if (tset == FMA_TOKENS) {
15883 15887 if (global) {
15884 15888 semerr(gettext("Can't use option '-g' with FMA event "
15885 15889 "definitions\n"));
15886 15890 goto out;
15887 15891 }
15888 15892
15889 15893 for (p = pgs; *p; ++p) {
15890 15894 if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
15891 15895 SCF_SUCCESS) {
15892 15896 /*
15893 15897 * if the preferences have just been deleted
15894 15898 * or does not exist, just skip.
15895 15899 */
15896 15900 if (scf_error() == SCF_ERROR_NOT_FOUND ||
15897 15901 scf_error() == SCF_ERROR_DELETED)
15898 15902 continue;
15899 15903 uu_warn(gettext(
15900 15904 "Failed listnotify: %s\n"),
15901 15905 scf_strerror(scf_error()));
15902 15906 goto out;
15903 15907 }
15904 15908 listnotify_print(nvl, re_tag(*p));
15905 15909 }
15906 15910 } else if (tset == MIXED_TOKENS) {
15907 15911 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15908 15912 goto out;
15909 15913 } else {
15910 15914 semerr(gettext("Invalid input.\n"));
15911 15915 }
15912 15916
15913 15917 out:
15914 15918 nvlist_free(nvl);
15915 15919 free(fmri);
15916 15920 free(pgs);
15917 15921 free(str);
15918 15922 }
15919 15923
15920 15924 static char *
15921 15925 strip_quotes_and_blanks(char *s)
15922 15926 {
15923 15927 char *start = s;
15924 15928 char *end = strrchr(s, '\"');
15925 15929
15926 15930 if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
15927 15931 start = s + 1;
15928 15932 while (isblank(*start))
15929 15933 start++;
15930 15934 while (isblank(*(end - 1)) && end > start) {
15931 15935 end--;
15932 15936 }
15933 15937 *end = '\0';
15934 15938 }
15935 15939
15936 15940 return (start);
15937 15941 }
15938 15942
15939 15943 static int
15940 15944 set_active(nvlist_t *mech, const char *hier_part)
15941 15945 {
15942 15946 boolean_t b;
15943 15947
15944 15948 if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
15945 15949 b = B_TRUE;
15946 15950 } else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
15947 15951 b = B_FALSE;
15948 15952 } else {
15949 15953 return (-1);
15950 15954 }
15951 15955
15952 15956 if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
15953 15957 uu_die(gettext("Out of memory.\n"));
15954 15958
15955 15959 return (0);
15956 15960 }
15957 15961
15958 15962 static int
15959 15963 add_snmp_params(nvlist_t *mech, char *hier_part)
15960 15964 {
15961 15965 return (set_active(mech, hier_part));
15962 15966 }
15963 15967
15964 15968 static int
15965 15969 add_syslog_params(nvlist_t *mech, char *hier_part)
15966 15970 {
15967 15971 return (set_active(mech, hier_part));
15968 15972 }
15969 15973
15970 15974 /*
15971 15975 * add_mailto_paramas()
15972 15976 * parse the hier_part of mailto URI
15973 15977 * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
15974 15978 * or mailto:{[active]|inactive}
15975 15979 */
15976 15980 static int
15977 15981 add_mailto_params(nvlist_t *mech, char *hier_part)
15978 15982 {
15979 15983 const char *tok = "?&";
15980 15984 char *p;
15981 15985 char *lasts;
15982 15986 char *param;
15983 15987 char *val;
15984 15988
15985 15989 /*
15986 15990 * If the notification parametes are in the form of
15987 15991 *
15988 15992 * malito:{[active]|inactive}
15989 15993 *
15990 15994 * we set the property accordingly and return.
15991 15995 * Otherwise, we make the notification type active and
15992 15996 * process the hier_part.
15993 15997 */
15994 15998 if (set_active(mech, hier_part) == 0)
15995 15999 return (0);
15996 16000 else if (set_active(mech, PARAM_ACTIVE) != 0)
15997 16001 return (-1);
15998 16002
15999 16003 if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) {
16000 16004 /*
16001 16005 * sanity check: we only get here if hier_part = "", but
16002 16006 * that's handled by set_active
16003 16007 */
16004 16008 uu_die("strtok_r");
16005 16009 }
16006 16010
16007 16011 if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0)
16008 16012 uu_die(gettext("Out of memory.\n"));
16009 16013
16010 16014 while ((p = strtok_r(NULL, tok, &lasts)) != NULL)
16011 16015 if ((param = strtok_r(p, "=", &val)) != NULL)
16012 16016 if (nvlist_add_string(mech, param, val) != 0)
16013 16017 uu_die(gettext("Out of memory.\n"));
16014 16018
16015 16019 return (0);
16016 16020 }
16017 16021
16018 16022 static int
16019 16023 uri_split(char *uri, char **scheme, char **hier_part)
16020 16024 {
16021 16025 int r = -1;
16022 16026
16023 16027 if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
16024 16028 *hier_part == NULL) {
16025 16029 semerr(gettext("'%s' is not an URI\n"), uri);
16026 16030 return (r);
16027 16031 }
16028 16032
16029 16033 if ((r = check_uri_scheme(*scheme)) < 0) {
16030 16034 semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
16031 16035 return (r);
16032 16036 }
16033 16037
16034 16038 return (r);
16035 16039 }
16036 16040
16037 16041 static int
16038 16042 process_uri(nvlist_t *params, char *uri)
16039 16043 {
16040 16044 char *scheme;
16041 16045 char *hier_part;
16042 16046 nvlist_t *mech;
16043 16047 int index;
16044 16048 int r;
16045 16049
16046 16050 if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
16047 16051 return (-1);
16048 16052
16049 16053 if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
16050 16054 uu_die(gettext("Out of memory.\n"));
16051 16055
16052 16056 switch (index) {
16053 16057 case 0:
16054 16058 /* error messages displayed by called function */
16055 16059 r = add_mailto_params(mech, hier_part);
16056 16060 break;
16057 16061
16058 16062 case 1:
16059 16063 if ((r = add_snmp_params(mech, hier_part)) != 0)
16060 16064 semerr(gettext("Not valid parameters: '%s'\n"),
16061 16065 hier_part);
16062 16066 break;
16063 16067
16064 16068 case 2:
16065 16069 if ((r = add_syslog_params(mech, hier_part)) != 0)
16066 16070 semerr(gettext("Not valid parameters: '%s'\n"),
16067 16071 hier_part);
16068 16072 break;
16069 16073
16070 16074 default:
16071 16075 r = -1;
16072 16076 }
16073 16077
16074 16078 if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
16075 16079 mech) != 0)
16076 16080 uu_die(gettext("Out of memory.\n"));
16077 16081
16078 16082 nvlist_free(mech);
16079 16083 return (r);
16080 16084 }
16081 16085
16082 16086 static int
16083 16087 set_params(nvlist_t *params, char **p)
16084 16088 {
16085 16089 char *uri;
16086 16090
16087 16091 if (p == NULL)
16088 16092 /* sanity check */
16089 16093 uu_die("set_params");
16090 16094
16091 16095 while (*p) {
16092 16096 uri = strip_quotes_and_blanks(*p);
16093 16097 if (process_uri(params, uri) != 0)
16094 16098 return (-1);
16095 16099
16096 16100 ++p;
16097 16101 }
16098 16102
16099 16103 return (0);
16100 16104 }
16101 16105
16102 16106 static int
16103 16107 setnotify(const char *e, char **p, int global)
16104 16108 {
16105 16109 char *str = safe_strdup(e);
16106 16110 char **events;
16107 16111 int32_t tset;
16108 16112 int r = -1;
16109 16113 nvlist_t *nvl, *params;
16110 16114 char *fmri = NULL;
16111 16115
16112 16116 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
16113 16117 nvlist_alloc(¶ms, NV_UNIQUE_NAME, 0) != 0 ||
16114 16118 nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
16115 16119 SCF_NOTIFY_PARAMS_VERSION) != 0)
16116 16120 uu_die(gettext("Out of memory.\n"));
16117 16121
16118 16122 events = tokenize(str, ",");
16119 16123
16120 16124 if ((tset = check_tokens(events)) > 0) {
16121 16125 /* SMF state transitions parameters */
16122 16126 size_t sz = max_scf_fmri_len + 1;
16123 16127
16124 16128 fmri = safe_malloc(sz);
16125 16129 if (global) {
16126 16130 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
16127 16131 } else if (get_selection_str(fmri, sz) != 0) {
16128 16132 goto out;
16129 16133 }
16130 16134
16131 16135 if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 ||
16132 16136 nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0)
16133 16137 uu_die(gettext("Out of memory.\n"));
16134 16138
16135 16139 if ((r = set_params(params, p)) == 0) {
16136 16140 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS,
16137 16141 params) != 0)
16138 16142 uu_die(gettext("Out of memory.\n"));
16139 16143
16140 16144 if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
16141 16145 nvl) != SCF_SUCCESS) {
16142 16146 r = -1;
16143 16147 uu_warn(gettext(
16144 16148 "Failed smf_notify_set_params(3SCF): %s\n"),
16145 16149 scf_strerror(scf_error()));
16146 16150 }
16147 16151 }
16148 16152 } else if (tset == FMA_TOKENS) {
16149 16153 /* FMA event parameters */
16150 16154 if (global) {
16151 16155 semerr(gettext("Can't use option '-g' with FMA event "
16152 16156 "definitions\n"));
16153 16157 goto out;
16154 16158 }
16155 16159
16156 16160 if ((r = set_params(params, p)) != 0)
16157 16161 goto out;
16158 16162
16159 16163 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
16160 16164 uu_die(gettext("Out of memory.\n"));
16161 16165
16162 16166 while (*events) {
16163 16167 if (smf_notify_set_params(de_tag(*events), nvl) !=
16164 16168 SCF_SUCCESS)
16165 16169 uu_warn(gettext(
16166 16170 "Failed smf_notify_set_params(3SCF) for "
16167 16171 "event %s: %s\n"), *events,
16168 16172 scf_strerror(scf_error()));
16169 16173 events++;
16170 16174 }
16171 16175 } else if (tset == MIXED_TOKENS) {
16172 16176 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
16173 16177 } else {
16174 16178 /* Sanity check */
16175 16179 uu_die(gettext("Invalid input.\n"));
16176 16180 }
16177 16181
16178 16182 out:
16179 16183 nvlist_free(nvl);
16180 16184 nvlist_free(params);
16181 16185 free(fmri);
16182 16186 free(str);
16183 16187
16184 16188 return (r);
16185 16189 }
16186 16190
16187 16191 int
16188 16192 lscf_setnotify(uu_list_t *args)
16189 16193 {
16190 16194 int argc;
16191 16195 char **argv = NULL;
16192 16196 string_list_t *slp;
16193 16197 int global;
16194 16198 char *events;
16195 16199 char **p;
16196 16200 int i;
16197 16201 int ret;
16198 16202
16199 16203 if ((argc = uu_list_numnodes(args)) < 2)
16200 16204 goto usage;
16201 16205
16202 16206 argv = calloc(argc + 1, sizeof (char *));
16203 16207 if (argv == NULL)
16204 16208 uu_die(gettext("Out of memory.\n"));
16205 16209
16206 16210 for (slp = uu_list_first(args), i = 0;
16207 16211 slp != NULL;
16208 16212 slp = uu_list_next(args, slp), ++i)
16209 16213 argv[i] = slp->str;
16210 16214
16211 16215 argv[i] = NULL;
16212 16216
16213 16217 if (strcmp(argv[0], "-g") == 0) {
16214 16218 global = 1;
16215 16219 events = argv[1];
16216 16220 p = argv + 2;
16217 16221 } else {
16218 16222 global = 0;
16219 16223 events = argv[0];
16220 16224 p = argv + 1;
16221 16225 }
16222 16226
16223 16227 ret = setnotify(events, p, global);
16224 16228
16225 16229 out:
16226 16230 free(argv);
16227 16231 return (ret);
16228 16232
16229 16233 usage:
16230 16234 ret = -2;
16231 16235 goto out;
16232 16236 }
16233 16237
16234 16238 /*
16235 16239 * Creates a list of instance name strings associated with a service. If
16236 16240 * wohandcrafted flag is set, get only instances that have a last-import
16237 16241 * snapshot, instances that were imported via svccfg.
16238 16242 */
16239 16243 static uu_list_t *
16240 16244 create_instance_list(scf_service_t *svc, int wohandcrafted)
16241 16245 {
16242 16246 scf_snapshot_t *snap = NULL;
16243 16247 scf_instance_t *inst;
16244 16248 scf_iter_t *inst_iter;
16245 16249 uu_list_t *instances;
16246 16250 char *instname;
16247 16251 int r;
16248 16252
16249 16253 inst_iter = scf_iter_create(g_hndl);
16250 16254 inst = scf_instance_create(g_hndl);
16251 16255 if (inst_iter == NULL || inst == NULL) {
16252 16256 uu_warn(gettext("Could not create instance or iterator\n"));
16253 16257 scfdie();
16254 16258 }
16255 16259
16256 16260 if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
16257 16261 return (instances);
16258 16262
16259 16263 if (scf_iter_service_instances(inst_iter, svc) != 0) {
16260 16264 switch (scf_error()) {
16261 16265 case SCF_ERROR_CONNECTION_BROKEN:
16262 16266 case SCF_ERROR_DELETED:
16263 16267 uu_list_destroy(instances);
16264 16268 instances = NULL;
16265 16269 goto out;
16266 16270
16267 16271 case SCF_ERROR_HANDLE_MISMATCH:
16268 16272 case SCF_ERROR_NOT_BOUND:
16269 16273 case SCF_ERROR_NOT_SET:
16270 16274 default:
16271 16275 bad_error("scf_iter_service_instances", scf_error());
16272 16276 }
16273 16277 }
16274 16278
16275 16279 instname = safe_malloc(max_scf_name_len + 1);
16276 16280 while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
16277 16281 if (r == -1) {
16278 16282 (void) uu_warn(gettext("Unable to iterate through "
16279 16283 "instances to create instance list : %s\n"),
16280 16284 scf_strerror(scf_error()));
16281 16285
16282 16286 uu_list_destroy(instances);
16283 16287 instances = NULL;
16284 16288 goto out;
16285 16289 }
16286 16290
16287 16291 /*
16288 16292 * If the instance does not have a last-import snapshot
16289 16293 * then do not add it to the list as it is a hand-crafted
16290 16294 * instance that should not be managed.
16291 16295 */
16292 16296 if (wohandcrafted) {
16293 16297 if (snap == NULL &&
16294 16298 (snap = scf_snapshot_create(g_hndl)) == NULL) {
16295 16299 uu_warn(gettext("Unable to create snapshot "
16296 16300 "entity\n"));
16297 16301 scfdie();
16298 16302 }
16299 16303
16300 16304 if (scf_instance_get_snapshot(inst,
16301 16305 snap_lastimport, snap) != 0) {
16302 16306 switch (scf_error()) {
16303 16307 case SCF_ERROR_NOT_FOUND :
16304 16308 case SCF_ERROR_DELETED:
16305 16309 continue;
16306 16310
16307 16311 case SCF_ERROR_CONNECTION_BROKEN:
16308 16312 uu_list_destroy(instances);
16309 16313 instances = NULL;
16310 16314 goto out;
16311 16315
16312 16316 case SCF_ERROR_HANDLE_MISMATCH:
16313 16317 case SCF_ERROR_NOT_BOUND:
16314 16318 case SCF_ERROR_NOT_SET:
16315 16319 default:
16316 16320 bad_error("scf_iter_service_instances",
16317 16321 scf_error());
16318 16322 }
16319 16323 }
16320 16324 }
16321 16325
16322 16326 if (scf_instance_get_name(inst, instname,
16323 16327 max_scf_name_len + 1) < 0) {
16324 16328 switch (scf_error()) {
16325 16329 case SCF_ERROR_NOT_FOUND :
16326 16330 continue;
16327 16331
16328 16332 case SCF_ERROR_CONNECTION_BROKEN:
16329 16333 case SCF_ERROR_DELETED:
16330 16334 uu_list_destroy(instances);
16331 16335 instances = NULL;
16332 16336 goto out;
16333 16337
16334 16338 case SCF_ERROR_HANDLE_MISMATCH:
16335 16339 case SCF_ERROR_NOT_BOUND:
16336 16340 case SCF_ERROR_NOT_SET:
16337 16341 default:
16338 16342 bad_error("scf_iter_service_instances",
16339 16343 scf_error());
16340 16344 }
16341 16345 }
16342 16346
16343 16347 add_string(instances, instname);
16344 16348 }
16345 16349
16346 16350 out:
16347 16351 if (snap)
16348 16352 scf_snapshot_destroy(snap);
16349 16353
16350 16354 scf_instance_destroy(inst);
16351 16355 scf_iter_destroy(inst_iter);
16352 16356 free(instname);
16353 16357 return (instances);
16354 16358 }
16355 16359
16356 16360 /*
16357 16361 * disable an instance but wait for the instance to
16358 16362 * move out of the running state.
16359 16363 *
16360 16364 * Returns 0 : if the instance did not disable
16361 16365 * Returns non-zero : if the instance disabled.
16362 16366 *
16363 16367 */
16364 16368 static int
16365 16369 disable_instance(scf_instance_t *instance)
16366 16370 {
16367 16371 char *fmribuf;
16368 16372 int enabled = 10000;
16369 16373
16370 16374 if (inst_is_running(instance)) {
16371 16375 fmribuf = safe_malloc(max_scf_name_len + 1);
16372 16376 if (scf_instance_to_fmri(instance, fmribuf,
16373 16377 max_scf_name_len + 1) < 0) {
16374 16378 free(fmribuf);
16375 16379 return (0);
16376 16380 }
16377 16381
16378 16382 /*
16379 16383 * If the instance cannot be disabled then return
16380 16384 * failure to disable and let the caller decide
16381 16385 * if that is of importance.
16382 16386 */
16383 16387 if (smf_disable_instance(fmribuf, 0) != 0) {
16384 16388 free(fmribuf);
16385 16389 return (0);
16386 16390 }
16387 16391
16388 16392 while (enabled) {
16389 16393 if (!inst_is_running(instance))
16390 16394 break;
16391 16395
16392 16396 (void) poll(NULL, 0, 5);
16393 16397 enabled = enabled - 5;
16394 16398 }
16395 16399
16396 16400 free(fmribuf);
16397 16401 }
16398 16402
16399 16403 return (enabled);
16400 16404 }
16401 16405
16402 16406 /*
16403 16407 * Function to compare two service_manifest structures.
16404 16408 */
16405 16409 /* ARGSUSED2 */
16406 16410 static int
16407 16411 service_manifest_compare(const void *left, const void *right, void *unused)
16408 16412 {
16409 16413 service_manifest_t *l = (service_manifest_t *)left;
16410 16414 service_manifest_t *r = (service_manifest_t *)right;
16411 16415 int rc;
16412 16416
16413 16417 rc = strcmp(l->servicename, r->servicename);
16414 16418
16415 16419 return (rc);
16416 16420 }
16417 16421
16418 16422 /*
16419 16423 * Look for the provided service in the service to manifest
16420 16424 * tree. If the service exists, and a manifest was provided
16421 16425 * then add the manifest to that service. If the service
16422 16426 * does not exist, then add the service and manifest to the
16423 16427 * list.
16424 16428 *
16425 16429 * If the manifest is NULL, return the element if found. If
16426 16430 * the service is not found return NULL.
16427 16431 */
16428 16432 service_manifest_t *
16429 16433 find_add_svc_mfst(const char *svnbuf, const char *mfst)
16430 16434 {
16431 16435 service_manifest_t elem;
16432 16436 service_manifest_t *fnelem;
16433 16437 uu_avl_index_t marker;
16434 16438
16435 16439 elem.servicename = svnbuf;
16436 16440 fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
16437 16441
16438 16442 if (mfst) {
16439 16443 if (fnelem) {
16440 16444 add_string(fnelem->mfstlist, strdup(mfst));
16441 16445 } else {
16442 16446 fnelem = safe_malloc(sizeof (*fnelem));
16443 16447 fnelem->servicename = safe_strdup(svnbuf);
16444 16448 if ((fnelem->mfstlist =
16445 16449 uu_list_create(string_pool, NULL, 0)) == NULL)
16446 16450 uu_die(gettext("Could not create property "
16447 16451 "list: %s\n"), uu_strerror(uu_error()));
16448 16452
16449 16453 add_string(fnelem->mfstlist, safe_strdup(mfst));
16450 16454
16451 16455 uu_avl_insert(service_manifest_tree, fnelem, marker);
16452 16456 }
16453 16457 }
16454 16458
16455 16459 return (fnelem);
16456 16460 }
16457 16461
16458 16462 /*
16459 16463 * Create the service to manifest avl tree.
16460 16464 *
16461 16465 * Walk each of the manifests currently installed in the supported
16462 16466 * directories, /lib/svc/manifests and /var/svc/manifests. For
16463 16467 * each of the manifests, inventory the services and add them to
16464 16468 * the tree.
16465 16469 *
16466 16470 * Code that calls this function should make sure fileystem/minimal is online,
16467 16471 * /var is available, since this function walks the /var/svc/manifest directory.
16468 16472 */
16469 16473 static void
16470 16474 create_manifest_tree(void)
16471 16475 {
16472 16476 manifest_info_t **entry;
16473 16477 manifest_info_t **manifests;
16474 16478 uu_list_walk_t *svcs;
16475 16479 bundle_t *b;
16476 16480 entity_t *mfsvc;
16477 16481 char *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
16478 16482 int c, status;
16479 16483
16480 16484 if (service_manifest_pool)
16481 16485 return;
16482 16486
16483 16487 /*
16484 16488 * Create the list pool for the service manifest list
16485 16489 */
16486 16490 service_manifest_pool = uu_avl_pool_create("service_manifest",
16487 16491 sizeof (service_manifest_t),
16488 16492 offsetof(service_manifest_t, svcmfst_node),
16489 16493 service_manifest_compare, UU_DEFAULT);
16490 16494 if (service_manifest_pool == NULL)
16491 16495 uu_die(gettext("service_manifest pool creation failed: %s\n"),
16492 16496 uu_strerror(uu_error()));
16493 16497
16494 16498 /*
16495 16499 * Create the list
16496 16500 */
16497 16501 service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
16498 16502 UU_DEFAULT);
16499 16503 if (service_manifest_tree == NULL)
16500 16504 uu_die(gettext("service_manifest tree creation failed: %s\n"),
16501 16505 uu_strerror(uu_error()));
16502 16506
16503 16507 /*
16504 16508 * Walk the manifests adding the service(s) from each manifest.
16505 16509 *
16506 16510 * If a service already exists add the manifest to the manifest
16507 16511 * list for that service. This covers the case of a service that
16508 16512 * is supported by multiple manifest files.
16509 16513 */
16510 16514 for (c = 0; dirs[c]; c++) {
16511 16515 status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT);
16512 16516 if (status < 0) {
16513 16517 uu_warn(gettext("file tree walk of %s encountered "
16514 16518 "error %s\n"), dirs[c], strerror(errno));
16515 16519
16516 16520 uu_avl_destroy(service_manifest_tree);
16517 16521 service_manifest_tree = NULL;
16518 16522 return;
16519 16523 }
16520 16524
16521 16525 /*
16522 16526 * If a manifest that was in the list is not found
16523 16527 * then skip and go to the next manifest file.
16524 16528 */
16525 16529 if (manifests != NULL) {
16526 16530 for (entry = manifests; *entry != NULL; entry++) {
16527 16531 b = internal_bundle_new();
16528 16532 if (lxml_get_bundle_file(b, (*entry)->mi_path,
16529 16533 SVCCFG_OP_IMPORT) != 0) {
16530 16534 internal_bundle_free(b);
16531 16535 continue;
16532 16536 }
16533 16537
16534 16538 svcs = uu_list_walk_start(b->sc_bundle_services,
16535 16539 0);
16536 16540 if (svcs == NULL) {
16537 16541 internal_bundle_free(b);
16538 16542 continue;
16539 16543 }
16540 16544
16541 16545 while ((mfsvc = uu_list_walk_next(svcs)) !=
16542 16546 NULL) {
16543 16547 /* Add manifest to service */
16544 16548 (void) find_add_svc_mfst(mfsvc->sc_name,
16545 16549 (*entry)->mi_path);
16546 16550 }
16547 16551
16548 16552 uu_list_walk_end(svcs);
16549 16553 internal_bundle_free(b);
16550 16554 }
16551 16555
16552 16556 free_manifest_array(manifests);
16553 16557 }
16554 16558 }
16555 16559 }
16556 16560
16557 16561 /*
16558 16562 * Check the manifest history file to see
16559 16563 * if the service was ever installed from
16560 16564 * one of the supported directories.
16561 16565 *
16562 16566 * Return Values :
16563 16567 * -1 - if there's error reading manifest history file
16564 16568 * 1 - if the service is not found
16565 16569 * 0 - if the service is found
16566 16570 */
16567 16571 static int
16568 16572 check_mfst_history(const char *svcname)
16569 16573 {
16570 16574 struct stat st;
16571 16575 caddr_t mfsthist_start;
16572 16576 char *svnbuf;
16573 16577 int fd;
16574 16578 int r = 1;
16575 16579
16576 16580 fd = open(MFSTHISTFILE, O_RDONLY);
16577 16581 if (fd == -1) {
16578 16582 uu_warn(gettext("Unable to open the history file\n"));
16579 16583 return (-1);
16580 16584 }
16581 16585
16582 16586 if (fstat(fd, &st) == -1) {
16583 16587 uu_warn(gettext("Unable to stat the history file\n"));
16584 16588 return (-1);
16585 16589 }
16586 16590
16587 16591 mfsthist_start = mmap(0, st.st_size, PROT_READ,
16588 16592 MAP_PRIVATE, fd, 0);
16589 16593
16590 16594 (void) close(fd);
16591 16595 if (mfsthist_start == MAP_FAILED ||
16592 16596 *(mfsthist_start + st.st_size) != '\0') {
16593 16597 (void) munmap(mfsthist_start, st.st_size);
16594 16598 return (-1);
16595 16599 }
16596 16600
16597 16601 /*
16598 16602 * The manifest history file is a space delimited list
16599 16603 * of service and instance to manifest linkage. Adding
16600 16604 * a space to the end of the service name so to get only
16601 16605 * the service that is being searched for.
16602 16606 */
16603 16607 svnbuf = uu_msprintf("%s ", svcname);
16604 16608 if (svnbuf == NULL)
16605 16609 uu_die(gettext("Out of memory"));
16606 16610
16607 16611 if (strstr(mfsthist_start, svnbuf) != NULL)
16608 16612 r = 0;
16609 16613
16610 16614 (void) munmap(mfsthist_start, st.st_size);
16611 16615 uu_free(svnbuf);
16612 16616 return (r);
16613 16617 }
16614 16618
16615 16619 /*
16616 16620 * Take down each of the instances in the service
16617 16621 * and remove them, then delete the service.
16618 16622 */
16619 16623 static void
16620 16624 teardown_service(scf_service_t *svc, const char *svnbuf)
16621 16625 {
16622 16626 scf_instance_t *instance;
16623 16627 scf_iter_t *iter;
16624 16628 int r;
16625 16629
16626 16630 safe_printf(gettext("Delete service %s as there are no "
16627 16631 "supporting manifests\n"), svnbuf);
16628 16632
16629 16633 instance = scf_instance_create(g_hndl);
16630 16634 iter = scf_iter_create(g_hndl);
16631 16635 if (iter == NULL || instance == NULL) {
16632 16636 uu_warn(gettext("Unable to create supporting entities to "
16633 16637 "teardown the service\n"));
16634 16638 uu_warn(gettext("scf error is : %s\n"),
16635 16639 scf_strerror(scf_error()));
16636 16640 scfdie();
16637 16641 }
16638 16642
16639 16643 if (scf_iter_service_instances(iter, svc) != 0) {
16640 16644 switch (scf_error()) {
16641 16645 case SCF_ERROR_CONNECTION_BROKEN:
16642 16646 case SCF_ERROR_DELETED:
16643 16647 goto out;
16644 16648
16645 16649 case SCF_ERROR_HANDLE_MISMATCH:
16646 16650 case SCF_ERROR_NOT_BOUND:
16647 16651 case SCF_ERROR_NOT_SET:
16648 16652 default:
16649 16653 bad_error("scf_iter_service_instances",
16650 16654 scf_error());
16651 16655 }
16652 16656 }
16653 16657
16654 16658 while ((r = scf_iter_next_instance(iter, instance)) != 0) {
16655 16659 if (r == -1) {
16656 16660 uu_warn(gettext("Error - %s\n"),
16657 16661 scf_strerror(scf_error()));
16658 16662 goto out;
16659 16663 }
16660 16664
16661 16665 (void) disable_instance(instance);
16662 16666 }
16663 16667
16664 16668 /*
16665 16669 * Delete the service... forcing the deletion in case
16666 16670 * any of the instances did not disable.
16667 16671 */
16668 16672 (void) lscf_service_delete(svc, 1);
16669 16673 out:
16670 16674 scf_instance_destroy(instance);
16671 16675 scf_iter_destroy(iter);
16672 16676 }
16673 16677
16674 16678 /*
16675 16679 * Get the list of instances supported by the manifest
16676 16680 * file.
16677 16681 *
16678 16682 * Return 0 if there are no instances.
16679 16683 *
16680 16684 * Return -1 if there are errors attempting to collect instances.
16681 16685 *
16682 16686 * Return the count of instances found if there are no errors.
16683 16687 *
16684 16688 */
16685 16689 static int
16686 16690 check_instance_support(char *mfstfile, const char *svcname,
16687 16691 uu_list_t *instances)
16688 16692 {
16689 16693 uu_list_walk_t *svcs, *insts;
16690 16694 uu_list_t *ilist;
16691 16695 bundle_t *b;
16692 16696 entity_t *mfsvc, *mfinst;
16693 16697 const char *svcn;
16694 16698 int rminstcnt = 0;
16695 16699
16696 16700
16697 16701 b = internal_bundle_new();
16698 16702
16699 16703 if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
16700 16704 /*
16701 16705 * Unable to process the manifest file for
16702 16706 * instance support, so just return as
16703 16707 * don't want to remove instances that could
16704 16708 * not be accounted for that might exist here.
16705 16709 */
16706 16710 internal_bundle_free(b);
16707 16711 return (0);
16708 16712 }
16709 16713
16710 16714 svcs = uu_list_walk_start(b->sc_bundle_services, 0);
16711 16715 if (svcs == NULL) {
16712 16716 internal_bundle_free(b);
16713 16717 return (0);
16714 16718 }
16715 16719
16716 16720 svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
16717 16721 (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
16718 16722
16719 16723 while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
16720 16724 if (strcmp(mfsvc->sc_name, svcn) == 0)
16721 16725 break;
16722 16726 }
16723 16727 uu_list_walk_end(svcs);
16724 16728
16725 16729 if (mfsvc == NULL) {
16726 16730 internal_bundle_free(b);
16727 16731 return (-1);
16728 16732 }
16729 16733
16730 16734 ilist = mfsvc->sc_u.sc_service.sc_service_instances;
16731 16735 if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
16732 16736 internal_bundle_free(b);
16733 16737 return (0);
16734 16738 }
16735 16739
16736 16740 while ((mfinst = uu_list_walk_next(insts)) != NULL) {
16737 16741 /*
16738 16742 * Remove the instance from the instances list.
16739 16743 * The unaccounted for instances will be removed
16740 16744 * from the service once all manifests are
16741 16745 * processed.
16742 16746 */
16743 16747 (void) remove_string(instances,
16744 16748 mfinst->sc_name);
16745 16749 rminstcnt++;
16746 16750 }
16747 16751
16748 16752 uu_list_walk_end(insts);
16749 16753 internal_bundle_free(b);
16750 16754
16751 16755 return (rminstcnt);
16752 16756 }
16753 16757
16754 16758 /*
16755 16759 * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16756 16760 * 'false' to indicate there's no manifest file(s) found for the service.
16757 16761 */
16758 16762 static void
16759 16763 svc_add_no_support(scf_service_t *svc)
16760 16764 {
16761 16765 char *pname;
16762 16766
16763 16767 /* Add no support */
16764 16768 cur_svc = svc;
16765 16769 if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
16766 16770 return;
16767 16771
16768 16772 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
16769 16773 if (pname == NULL)
16770 16774 uu_die(gettext("Out of memory.\n"));
16771 16775
16772 16776 (void) lscf_addpropvalue(pname, "boolean:", "0");
16773 16777
16774 16778 uu_free(pname);
16775 16779 cur_svc = NULL;
16776 16780 }
16777 16781
16778 16782 /*
16779 16783 * This function handles all upgrade scenarios for a service that doesn't have
16780 16784 * SCF_PG_MANIFESTFILES pg. The function creates and populates
16781 16785 * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16782 16786 * manifest(s) mapping. Manifests under supported directories are inventoried
16783 16787 * and a property is added for each file that delivers configuration to the
16784 16788 * service. A service that has no corresponding manifest files (deleted) are
16785 16789 * removed from repository.
16786 16790 *
16787 16791 * Unsupported services:
16788 16792 *
16789 16793 * A service is considered unsupported if there is no corresponding manifest
16790 16794 * in the supported directories for that service and the service isn't in the
16791 16795 * history file list. The history file, MFSTHISTFILE, contains a list of all
16792 16796 * services and instances that were delivered by Solaris before the introduction
16793 16797 * of the SCF_PG_MANIFESTFILES property group. The history file also contains
16794 16798 * the path to the manifest file that defined the service or instance.
16795 16799 *
16796 16800 * Another type of unsupported services is 'handcrafted' services,
16797 16801 * programmatically created services or services created by dependent entries
16798 16802 * in other manifests. A handcrafted service is identified by its lack of any
16799 16803 * instance containing last-import snapshot which is created during svccfg
16800 16804 * import.
16801 16805 *
16802 16806 * This function sets a flag for unsupported services by setting services'
16803 16807 * SCF_PG_MANIFESTFILES/support property to false.
16804 16808 */
16805 16809 static void
16806 16810 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
16807 16811 {
16808 16812 service_manifest_t *elem;
16809 16813 uu_list_walk_t *mfwalk;
16810 16814 string_list_t *mfile;
16811 16815 uu_list_t *instances;
16812 16816 const char *sname;
16813 16817 char *pname;
16814 16818 int r;
16815 16819
16816 16820 /*
16817 16821 * Since there's no guarantee manifests under /var are available during
16818 16822 * early import, don't perform any upgrade during early import.
16819 16823 */
16820 16824 if (IGNORE_VAR)
16821 16825 return;
16822 16826
16823 16827 if (service_manifest_tree == NULL) {
16824 16828 create_manifest_tree();
16825 16829 }
16826 16830
16827 16831 /*
16828 16832 * Find service's supporting manifest(s) after
16829 16833 * stripping off the svc:/ prefix that is part
16830 16834 * of the fmri that is not used in the service
16831 16835 * manifest bundle list.
16832 16836 */
16833 16837 sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
16834 16838 strlen(SCF_FMRI_SERVICE_PREFIX);
16835 16839 elem = find_add_svc_mfst(sname, NULL);
16836 16840 if (elem == NULL) {
16837 16841
16838 16842 /*
16839 16843 * A handcrafted service, one that has no instance containing
16840 16844 * last-import snapshot, should get unsupported flag.
16841 16845 */
16842 16846 instances = create_instance_list(svc, 1);
16843 16847 if (instances == NULL) {
16844 16848 uu_warn(gettext("Unable to create instance list %s\n"),
16845 16849 svcname);
16846 16850 return;
16847 16851 }
16848 16852
16849 16853 if (uu_list_numnodes(instances) == 0) {
16850 16854 svc_add_no_support(svc);
16851 16855 return;
16852 16856 }
16853 16857
16854 16858 /*
16855 16859 * If the service is in the history file, and its supporting
16856 16860 * manifests are not found, we can safely delete the service
16857 16861 * because its manifests are removed from the system.
16858 16862 *
16859 16863 * Services not found in the history file are not delivered by
16860 16864 * Solaris and/or delivered outside supported directories, set
16861 16865 * unsupported flag for these services.
16862 16866 */
16863 16867 r = check_mfst_history(svcname);
16864 16868 if (r == -1)
16865 16869 return;
16866 16870
16867 16871 if (r) {
16868 16872 /* Set unsupported flag for service */
16869 16873 svc_add_no_support(svc);
16870 16874 } else {
16871 16875 /* Delete the service */
16872 16876 teardown_service(svc, svcname);
16873 16877 }
16874 16878
16875 16879 return;
16876 16880 }
16877 16881
16878 16882 /*
16879 16883 * Walk through the list of manifests and add them
16880 16884 * to the service.
16881 16885 *
16882 16886 * Create a manifestfiles pg and add the property.
16883 16887 */
16884 16888 mfwalk = uu_list_walk_start(elem->mfstlist, 0);
16885 16889 if (mfwalk == NULL)
16886 16890 return;
16887 16891
16888 16892 cur_svc = svc;
16889 16893 r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
16890 16894 if (r != 0) {
16891 16895 cur_svc = NULL;
16892 16896 return;
16893 16897 }
16894 16898
16895 16899 while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
16896 16900 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16897 16901 mhash_filename_to_propname(mfile->str, 0));
16898 16902 if (pname == NULL)
16899 16903 uu_die(gettext("Out of memory.\n"));
16900 16904
16901 16905 (void) lscf_addpropvalue(pname, "astring:", mfile->str);
16902 16906 uu_free(pname);
16903 16907 }
16904 16908 uu_list_walk_end(mfwalk);
16905 16909
16906 16910 cur_svc = NULL;
16907 16911 }
16908 16912
16909 16913 /*
16910 16914 * Take a service and process the manifest file entires to see if
16911 16915 * there is continued support for the service and instances. If
16912 16916 * not cleanup as appropriate.
16913 16917 *
16914 16918 * If a service does not have a manifest files entry flag it for
16915 16919 * upgrade and return.
16916 16920 *
16917 16921 * For each manifestfiles property check if the manifest file is
16918 16922 * under the supported /lib/svc/manifest or /var/svc/manifest path
16919 16923 * and if not then return immediately as this service is not supported
16920 16924 * by the cleanup mechanism and should be ignored.
16921 16925 *
16922 16926 * For each manifest file that is supported, check to see if the
16923 16927 * file exists. If not then remove the manifest file property
16924 16928 * from the service and the smf/manifest hash table. If the manifest
16925 16929 * file exists then verify that it supports the instances that are
16926 16930 * part of the service.
16927 16931 *
16928 16932 * Once all manifest files have been accounted for remove any instances
16929 16933 * that are no longer supported in the service.
16930 16934 *
16931 16935 * Return values :
16932 16936 * 0 - Successfully processed the service
16933 16937 * non-zero - failed to process the service
16934 16938 *
16935 16939 * On most errors, will just return to wait and get the next service,
16936 16940 * unless in case of unable to create the needed structures which is
16937 16941 * most likely a fatal error that is not going to be recoverable.
16938 16942 */
16939 16943 int
16940 16944 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
16941 16945 {
16942 16946 struct mpg_mfile *mpntov;
16943 16947 struct mpg_mfile **mpvarry = NULL;
16944 16948 scf_service_t *svc;
16945 16949 scf_propertygroup_t *mpg;
16946 16950 scf_property_t *mp;
16947 16951 scf_value_t *mv;
16948 16952 scf_iter_t *mi;
16949 16953 scf_instance_t *instance;
16950 16954 uu_list_walk_t *insts;
16951 16955 uu_list_t *instances = NULL;
16952 16956 boolean_t activity = (boolean_t)act;
16953 16957 char *mpnbuf;
16954 16958 char *mpvbuf;
16955 16959 char *pgpropbuf;
16956 16960 int mfstcnt, rminstct, instct, mfstmax;
16957 16961 int index;
16958 16962 int r = 0;
16959 16963
16960 16964 assert(g_hndl != NULL);
16961 16965 assert(wip->svc != NULL);
16962 16966 assert(wip->fmri != NULL);
16963 16967
16964 16968 svc = wip->svc;
16965 16969
16966 16970 mpg = scf_pg_create(g_hndl);
16967 16971 mp = scf_property_create(g_hndl);
16968 16972 mi = scf_iter_create(g_hndl);
16969 16973 mv = scf_value_create(g_hndl);
16970 16974 instance = scf_instance_create(g_hndl);
16971 16975
16972 16976 if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
16973 16977 instance == NULL) {
16974 16978 uu_warn(gettext("Unable to create the supporting entities\n"));
16975 16979 uu_warn(gettext("scf error is : %s\n"),
16976 16980 scf_strerror(scf_error()));
16977 16981 scfdie();
16978 16982 }
16979 16983
16980 16984 /*
16981 16985 * Get the manifestfiles property group to be parsed for
16982 16986 * files existence.
16983 16987 */
16984 16988 if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
16985 16989 switch (scf_error()) {
16986 16990 case SCF_ERROR_NOT_FOUND:
16987 16991 upgrade_svc_mfst_connection(svc, wip->fmri);
16988 16992 break;
16989 16993 case SCF_ERROR_DELETED:
16990 16994 case SCF_ERROR_CONNECTION_BROKEN:
16991 16995 goto out;
16992 16996
16993 16997 case SCF_ERROR_HANDLE_MISMATCH:
16994 16998 case SCF_ERROR_NOT_BOUND:
16995 16999 case SCF_ERROR_NOT_SET:
16996 17000 default:
16997 17001 bad_error("scf_iter_pg_properties",
16998 17002 scf_error());
16999 17003 }
17000 17004
17001 17005 goto out;
17002 17006 }
17003 17007
17004 17008 /*
17005 17009 * Iterate through each of the manifestfiles properties
17006 17010 * to determine what manifestfiles are available.
17007 17011 *
17008 17012 * If a manifest file is supported then increment the
17009 17013 * count and therefore the service is safe.
17010 17014 */
17011 17015 if (scf_iter_pg_properties(mi, mpg) != 0) {
17012 17016 switch (scf_error()) {
17013 17017 case SCF_ERROR_DELETED:
17014 17018 case SCF_ERROR_CONNECTION_BROKEN:
17015 17019 goto out;
17016 17020
17017 17021 case SCF_ERROR_HANDLE_MISMATCH:
17018 17022 case SCF_ERROR_NOT_BOUND:
17019 17023 case SCF_ERROR_NOT_SET:
17020 17024 default:
17021 17025 bad_error("scf_iter_pg_properties",
17022 17026 scf_error());
17023 17027 }
17024 17028 }
17025 17029
17026 17030 mfstcnt = 0;
17027 17031 mfstmax = MFSTFILE_MAX;
17028 17032 mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
17029 17033 while ((r = scf_iter_next_property(mi, mp)) != 0) {
17030 17034 if (r == -1)
17031 17035 bad_error(gettext("Unable to iterate through "
17032 17036 "manifestfiles properties : %s"),
17033 17037 scf_error());
17034 17038
17035 17039 mpntov = safe_malloc(sizeof (struct mpg_mfile));
17036 17040 mpnbuf = safe_malloc(max_scf_name_len + 1);
17037 17041 mpvbuf = safe_malloc(max_scf_value_len + 1);
17038 17042 mpntov->mpg = mpnbuf;
17039 17043 mpntov->mfile = mpvbuf;
17040 17044 mpntov->access = 1;
17041 17045 if (scf_property_get_name(mp, mpnbuf,
17042 17046 max_scf_name_len + 1) < 0) {
17043 17047 uu_warn(gettext("Unable to get manifest file "
17044 17048 "property : %s\n"),
17045 17049 scf_strerror(scf_error()));
17046 17050
17047 17051 switch (scf_error()) {
17048 17052 case SCF_ERROR_DELETED:
17049 17053 case SCF_ERROR_CONNECTION_BROKEN:
17050 17054 r = scferror2errno(scf_error());
17051 17055 goto out_free;
17052 17056
17053 17057 case SCF_ERROR_HANDLE_MISMATCH:
17054 17058 case SCF_ERROR_NOT_BOUND:
17055 17059 case SCF_ERROR_NOT_SET:
17056 17060 default:
17057 17061 bad_error("scf_iter_pg_properties",
17058 17062 scf_error());
17059 17063 }
17060 17064 }
17061 17065
17062 17066 /*
17063 17067 * The support property is a boolean value that indicates
17064 17068 * if the service is supported for manifest file deletion.
17065 17069 * Currently at this time there is no code that sets this
17066 17070 * value to true. So while we could just let this be caught
17067 17071 * by the support check below, in the future this by be set
17068 17072 * to true and require processing. So for that, go ahead
17069 17073 * and check here, and just return if false. Otherwise,
17070 17074 * fall through expecting that other support checks will
17071 17075 * handle the entries.
17072 17076 */
17073 17077 if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
17074 17078 uint8_t support;
17075 17079
17076 17080 if (scf_property_get_value(mp, mv) != 0 ||
17077 17081 scf_value_get_boolean(mv, &support) != 0) {
17078 17082 uu_warn(gettext("Unable to get the manifest "
17079 17083 "support value: %s\n"),
17080 17084 scf_strerror(scf_error()));
17081 17085
17082 17086 switch (scf_error()) {
17083 17087 case SCF_ERROR_DELETED:
17084 17088 case SCF_ERROR_CONNECTION_BROKEN:
17085 17089 r = scferror2errno(scf_error());
17086 17090 goto out_free;
17087 17091
17088 17092 case SCF_ERROR_HANDLE_MISMATCH:
17089 17093 case SCF_ERROR_NOT_BOUND:
17090 17094 case SCF_ERROR_NOT_SET:
17091 17095 default:
17092 17096 bad_error("scf_iter_pg_properties",
17093 17097 scf_error());
17094 17098 }
17095 17099 }
17096 17100
17097 17101 if (support == B_FALSE)
17098 17102 goto out_free;
17099 17103 }
17100 17104
17101 17105 /*
17102 17106 * Anything with a manifest outside of the supported
17103 17107 * directories, immediately bail out because that makes
17104 17108 * this service non-supported. We don't even want
17105 17109 * to do instance processing in this case because the
17106 17110 * instances could be part of the non-supported manifest.
17107 17111 */
17108 17112 if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
17109 17113 /*
17110 17114 * Manifest is not in /lib/svc, so we need to
17111 17115 * consider the /var/svc case.
17112 17116 */
17113 17117 if (strncmp(mpnbuf, VARSVC_PR,
17114 17118 strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
17115 17119 /*
17116 17120 * Either the manifest is not in /var/svc or
17117 17121 * /var is not yet mounted. We ignore the
17118 17122 * manifest either because it is not in a
17119 17123 * standard location or because we cannot
17120 17124 * currently access the manifest.
17121 17125 */
17122 17126 goto out_free;
17123 17127 }
17124 17128 }
17125 17129
17126 17130 /*
17127 17131 * Get the value to of the manifest file for this entry
17128 17132 * for access verification and instance support
17129 17133 * verification if it still exists.
17130 17134 *
17131 17135 * During Early Manifest Import if the manifest is in
17132 17136 * /var/svc then it may not yet be available for checking
17133 17137 * so we must determine if /var/svc is available. If not
17134 17138 * then defer until Late Manifest Import to cleanup.
17135 17139 */
17136 17140 if (scf_property_get_value(mp, mv) != 0) {
17137 17141 uu_warn(gettext("Unable to get the manifest file "
17138 17142 "value: %s\n"),
17139 17143 scf_strerror(scf_error()));
17140 17144
17141 17145 switch (scf_error()) {
17142 17146 case SCF_ERROR_DELETED:
17143 17147 case SCF_ERROR_CONNECTION_BROKEN:
17144 17148 r = scferror2errno(scf_error());
17145 17149 goto out_free;
17146 17150
17147 17151 case SCF_ERROR_HANDLE_MISMATCH:
17148 17152 case SCF_ERROR_NOT_BOUND:
17149 17153 case SCF_ERROR_NOT_SET:
17150 17154 default:
17151 17155 bad_error("scf_property_get_value",
17152 17156 scf_error());
17153 17157 }
17154 17158 }
17155 17159
17156 17160 if (scf_value_get_astring(mv, mpvbuf,
17157 17161 max_scf_value_len + 1) < 0) {
17158 17162 uu_warn(gettext("Unable to get the manifest "
17159 17163 "file : %s\n"),
17160 17164 scf_strerror(scf_error()));
17161 17165
17162 17166 switch (scf_error()) {
17163 17167 case SCF_ERROR_DELETED:
17164 17168 case SCF_ERROR_CONNECTION_BROKEN:
17165 17169 r = scferror2errno(scf_error());
17166 17170 goto out_free;
17167 17171
17168 17172 case SCF_ERROR_HANDLE_MISMATCH:
17169 17173 case SCF_ERROR_NOT_BOUND:
17170 17174 case SCF_ERROR_NOT_SET:
17171 17175 default:
17172 17176 bad_error("scf_value_get_astring",
17173 17177 scf_error());
17174 17178 }
17175 17179 }
17176 17180
17177 17181 mpvarry[mfstcnt] = mpntov;
17178 17182 mfstcnt++;
17179 17183
17180 17184 /*
17181 17185 * Check for the need to reallocate array
17182 17186 */
17183 17187 if (mfstcnt >= (mfstmax - 1)) {
17184 17188 struct mpg_mfile **newmpvarry;
17185 17189
17186 17190 mfstmax = mfstmax * 2;
17187 17191 newmpvarry = realloc(mpvarry,
17188 17192 sizeof (struct mpg_mfile *) * mfstmax);
17189 17193
17190 17194 if (newmpvarry == NULL)
17191 17195 goto out_free;
17192 17196
17193 17197 mpvarry = newmpvarry;
17194 17198 }
17195 17199
17196 17200 mpvarry[mfstcnt] = NULL;
17197 17201 }
17198 17202
17199 17203 for (index = 0; mpvarry[index]; index++) {
17200 17204 mpntov = mpvarry[index];
17201 17205
17202 17206 /*
17203 17207 * Check to see if the manifestfile is accessable, if so hand
17204 17208 * this service and manifestfile off to be processed for
17205 17209 * instance support.
17206 17210 */
17207 17211 mpnbuf = mpntov->mpg;
17208 17212 mpvbuf = mpntov->mfile;
17209 17213 if (access(mpvbuf, F_OK) != 0) {
17210 17214 mpntov->access = 0;
17211 17215 activity++;
17212 17216 mfstcnt--;
17213 17217 /* Remove the entry from the service */
17214 17218 cur_svc = svc;
17215 17219 pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
17216 17220 mpnbuf);
17217 17221 if (pgpropbuf == NULL)
17218 17222 uu_die(gettext("Out of memory.\n"));
17219 17223
17220 17224 lscf_delprop(pgpropbuf);
17221 17225 cur_svc = NULL;
17222 17226
17223 17227 uu_free(pgpropbuf);
17224 17228 }
17225 17229 }
17226 17230
17227 17231 /*
17228 17232 * If mfstcnt is 0, none of the manifests that supported the service
17229 17233 * existed so remove the service.
17230 17234 */
17231 17235 if (mfstcnt == 0) {
17232 17236 teardown_service(svc, wip->fmri);
17233 17237
17234 17238 goto out_free;
17235 17239 }
17236 17240
17237 17241 if (activity) {
17238 17242 int nosvcsupport = 0;
17239 17243
17240 17244 /*
17241 17245 * If the list of service instances is NULL then
17242 17246 * create the list.
17243 17247 */
17244 17248 instances = create_instance_list(svc, 1);
17245 17249 if (instances == NULL) {
17246 17250 uu_warn(gettext("Unable to create instance list %s\n"),
17247 17251 wip->fmri);
17248 17252 goto out_free;
17249 17253 }
17250 17254
17251 17255 rminstct = uu_list_numnodes(instances);
17252 17256 instct = rminstct;
17253 17257
17254 17258 for (index = 0; mpvarry[index]; index++) {
17255 17259 mpntov = mpvarry[index];
17256 17260 if (mpntov->access == 0)
17257 17261 continue;
17258 17262
17259 17263 mpnbuf = mpntov->mpg;
17260 17264 mpvbuf = mpntov->mfile;
17261 17265 r = check_instance_support(mpvbuf, wip->fmri,
17262 17266 instances);
17263 17267 if (r == -1) {
17264 17268 nosvcsupport++;
17265 17269 } else {
17266 17270 rminstct -= r;
17267 17271 }
17268 17272 }
17269 17273
17270 17274 if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
17271 17275 teardown_service(svc, wip->fmri);
17272 17276
17273 17277 goto out_free;
17274 17278 }
17275 17279 }
17276 17280
17277 17281 /*
17278 17282 * If there are instances left on the instance list, then
17279 17283 * we must remove them.
17280 17284 */
17281 17285 if (instances != NULL && uu_list_numnodes(instances)) {
17282 17286 string_list_t *sp;
17283 17287
17284 17288 insts = uu_list_walk_start(instances, 0);
17285 17289 while ((sp = uu_list_walk_next(insts)) != NULL) {
17286 17290 /*
17287 17291 * Remove the instance from the instances list.
17288 17292 */
17289 17293 safe_printf(gettext("Delete instance %s from "
17290 17294 "service %s\n"), sp->str, wip->fmri);
17291 17295 if (scf_service_get_instance(svc, sp->str,
17292 17296 instance) != SCF_SUCCESS) {
17293 17297 (void) uu_warn("scf_error - %s\n",
17294 17298 scf_strerror(scf_error()));
17295 17299
17296 17300 continue;
17297 17301 }
17298 17302
17299 17303 (void) disable_instance(instance);
17300 17304
17301 17305 (void) lscf_instance_delete(instance, 1);
17302 17306 }
17303 17307 scf_instance_destroy(instance);
17304 17308 uu_list_walk_end(insts);
17305 17309 }
17306 17310
17307 17311 out_free:
17308 17312 if (mpvarry) {
17309 17313 struct mpg_mfile *fmpntov;
17310 17314
17311 17315 for (index = 0; mpvarry[index]; index++) {
17312 17316 fmpntov = mpvarry[index];
17313 17317 if (fmpntov->mpg == mpnbuf)
17314 17318 mpnbuf = NULL;
17315 17319 free(fmpntov->mpg);
17316 17320
17317 17321 if (fmpntov->mfile == mpvbuf)
17318 17322 mpvbuf = NULL;
17319 17323 free(fmpntov->mfile);
17320 17324
17321 17325 if (fmpntov == mpntov)
17322 17326 mpntov = NULL;
17323 17327 free(fmpntov);
17324 17328 }
17325 17329 if (mpnbuf)
17326 17330 free(mpnbuf);
17327 17331 if (mpvbuf)
17328 17332 free(mpvbuf);
17329 17333 if (mpntov)
17330 17334 free(mpntov);
17331 17335
17332 17336 free(mpvarry);
17333 17337 }
17334 17338 out:
17335 17339 scf_pg_destroy(mpg);
17336 17340 scf_property_destroy(mp);
17337 17341 scf_iter_destroy(mi);
17338 17342 scf_value_destroy(mv);
17339 17343
17340 17344 return (0);
17341 17345 }
17342 17346
17343 17347 /*
17344 17348 * Take the service and search for the manifestfiles property
17345 17349 * in each of the property groups. If the manifest file
17346 17350 * associated with the property does not exist then remove
17347 17351 * the property group.
17348 17352 */
17349 17353 int
17350 17354 lscf_hash_cleanup()
17351 17355 {
17352 17356 scf_service_t *svc;
17353 17357 scf_scope_t *scope;
17354 17358 scf_propertygroup_t *pg;
17355 17359 scf_property_t *prop;
17356 17360 scf_value_t *val;
17357 17361 scf_iter_t *iter;
17358 17362 char *pgname = NULL;
17359 17363 char *mfile = NULL;
17360 17364 int r;
17361 17365
17362 17366 svc = scf_service_create(g_hndl);
17363 17367 scope = scf_scope_create(g_hndl);
17364 17368 pg = scf_pg_create(g_hndl);
17365 17369 prop = scf_property_create(g_hndl);
17366 17370 val = scf_value_create(g_hndl);
17367 17371 iter = scf_iter_create(g_hndl);
17368 17372 if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
17369 17373 svc == NULL || scope == NULL) {
17370 17374 uu_warn(gettext("Unable to create a property group, or "
17371 17375 "property\n"));
17372 17376 uu_warn("%s\n", pg == NULL ? "pg is NULL" :
17373 17377 "pg is not NULL");
17374 17378 uu_warn("%s\n", prop == NULL ? "prop is NULL" :
17375 17379 "prop is not NULL");
17376 17380 uu_warn("%s\n", val == NULL ? "val is NULL" :
17377 17381 "val is not NULL");
17378 17382 uu_warn("%s\n", iter == NULL ? "iter is NULL" :
17379 17383 "iter is not NULL");
17380 17384 uu_warn("%s\n", svc == NULL ? "svc is NULL" :
17381 17385 "svc is not NULL");
17382 17386 uu_warn("%s\n", scope == NULL ? "scope is NULL" :
17383 17387 "scope is not NULL");
17384 17388 uu_warn(gettext("scf error is : %s\n"),
17385 17389 scf_strerror(scf_error()));
17386 17390 scfdie();
17387 17391 }
17388 17392
17389 17393 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
17390 17394 switch (scf_error()) {
17391 17395 case SCF_ERROR_CONNECTION_BROKEN:
17392 17396 case SCF_ERROR_NOT_FOUND:
17393 17397 goto out;
17394 17398
17395 17399 case SCF_ERROR_HANDLE_MISMATCH:
17396 17400 case SCF_ERROR_NOT_BOUND:
17397 17401 case SCF_ERROR_INVALID_ARGUMENT:
17398 17402 default:
17399 17403 bad_error("scf_handle_get_scope", scf_error());
17400 17404 }
17401 17405 }
17402 17406
17403 17407 if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
17404 17408 uu_warn(gettext("Unable to process the hash service, %s\n"),
17405 17409 HASH_SVC);
17406 17410 goto out;
17407 17411 }
17408 17412
17409 17413 pgname = safe_malloc(max_scf_name_len + 1);
17410 17414 mfile = safe_malloc(max_scf_value_len + 1);
17411 17415
17412 17416 if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
17413 17417 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17414 17418 scf_strerror(scf_error()));
17415 17419 goto out;
17416 17420 }
17417 17421
17418 17422 while ((r = scf_iter_next_pg(iter, pg)) != 0) {
17419 17423 if (r == -1)
17420 17424 goto out;
17421 17425
17422 17426 if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
17423 17427 switch (scf_error()) {
17424 17428 case SCF_ERROR_DELETED:
17425 17429 return (ENODEV);
17426 17430
17427 17431 case SCF_ERROR_CONNECTION_BROKEN:
17428 17432 return (ECONNABORTED);
17429 17433
17430 17434 case SCF_ERROR_NOT_SET:
17431 17435 case SCF_ERROR_NOT_BOUND:
17432 17436 default:
17433 17437 bad_error("scf_pg_get_name", scf_error());
17434 17438 }
17435 17439 }
17436 17440 if (IGNORE_VAR) {
17437 17441 if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
17438 17442 continue;
17439 17443 }
17440 17444
17441 17445 /*
17442 17446 * If unable to get the property continue as this is an
17443 17447 * entry that has no location to check against.
17444 17448 */
17445 17449 if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
17446 17450 continue;
17447 17451 }
17448 17452
17449 17453 if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
17450 17454 uu_warn(gettext("Unable to get value from %s\n"),
17451 17455 pgname);
17452 17456
17453 17457 switch (scf_error()) {
17454 17458 case SCF_ERROR_DELETED:
17455 17459 case SCF_ERROR_CONSTRAINT_VIOLATED:
17456 17460 case SCF_ERROR_NOT_FOUND:
17457 17461 case SCF_ERROR_NOT_SET:
17458 17462 continue;
17459 17463
17460 17464 case SCF_ERROR_CONNECTION_BROKEN:
17461 17465 r = scferror2errno(scf_error());
17462 17466 goto out;
17463 17467
17464 17468 case SCF_ERROR_HANDLE_MISMATCH:
17465 17469 case SCF_ERROR_NOT_BOUND:
17466 17470 default:
17467 17471 bad_error("scf_property_get_value",
17468 17472 scf_error());
17469 17473 }
17470 17474 }
17471 17475
17472 17476 if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
17473 17477 == -1) {
17474 17478 uu_warn(gettext("Unable to get astring from %s : %s\n"),
17475 17479 pgname, scf_strerror(scf_error()));
17476 17480
17477 17481 switch (scf_error()) {
17478 17482 case SCF_ERROR_NOT_SET:
17479 17483 case SCF_ERROR_TYPE_MISMATCH:
17480 17484 continue;
17481 17485
17482 17486 default:
17483 17487 bad_error("scf_value_get_astring", scf_error());
17484 17488 }
17485 17489 }
17486 17490
17487 17491 if (access(mfile, F_OK) == 0)
17488 17492 continue;
17489 17493
17490 17494 (void) scf_pg_delete(pg);
17491 17495 }
17492 17496
17493 17497 out:
17494 17498 scf_scope_destroy(scope);
17495 17499 scf_service_destroy(svc);
17496 17500 scf_pg_destroy(pg);
17497 17501 scf_property_destroy(prop);
17498 17502 scf_value_destroy(val);
17499 17503 scf_iter_destroy(iter);
17500 17504 free(pgname);
17501 17505 free(mfile);
17502 17506
17503 17507 return (0);
17504 17508 }
17505 17509
17506 17510 #ifndef NATIVE_BUILD
17507 17511 /* ARGSUSED */
17508 17512 CPL_MATCH_FN(complete_select)
17509 17513 {
17510 17514 const char *arg0, *arg1, *arg1end;
17511 17515 int word_start, err = 0, r;
17512 17516 size_t len;
17513 17517 char *buf;
17514 17518
17515 17519 lscf_prep_hndl();
17516 17520
17517 17521 arg0 = line + strspn(line, " \t");
17518 17522 assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
17519 17523
17520 17524 arg1 = arg0 + sizeof ("select") - 1;
17521 17525 arg1 += strspn(arg1, " \t");
17522 17526 word_start = arg1 - line;
17523 17527
17524 17528 arg1end = arg1 + strcspn(arg1, " \t");
17525 17529 if (arg1end < line + word_end)
17526 17530 return (0);
17527 17531
17528 17532 len = line + word_end - arg1;
17529 17533
17530 17534 buf = safe_malloc(max_scf_name_len + 1);
17531 17535
17532 17536 if (cur_snap != NULL) {
17533 17537 return (0);
17534 17538 } else if (cur_inst != NULL) {
17535 17539 return (0);
17536 17540 } else if (cur_svc != NULL) {
17537 17541 scf_instance_t *inst;
17538 17542 scf_iter_t *iter;
17539 17543
17540 17544 if ((inst = scf_instance_create(g_hndl)) == NULL ||
17541 17545 (iter = scf_iter_create(g_hndl)) == NULL)
17542 17546 scfdie();
17543 17547
17544 17548 if (scf_iter_service_instances(iter, cur_svc) != 0)
17545 17549 scfdie();
17546 17550
17547 17551 for (;;) {
17548 17552 r = scf_iter_next_instance(iter, inst);
17549 17553 if (r == 0)
17550 17554 break;
17551 17555 if (r != 1)
17552 17556 scfdie();
17553 17557
17554 17558 if (scf_instance_get_name(inst, buf,
17555 17559 max_scf_name_len + 1) < 0)
17556 17560 scfdie();
17557 17561
17558 17562 if (strncmp(buf, arg1, len) == 0) {
17559 17563 err = cpl_add_completion(cpl, line, word_start,
17560 17564 word_end, buf + len, "", " ");
17561 17565 if (err != 0)
17562 17566 break;
17563 17567 }
17564 17568 }
17565 17569
17566 17570 scf_iter_destroy(iter);
17567 17571 scf_instance_destroy(inst);
17568 17572
17569 17573 return (err);
17570 17574 } else {
17571 17575 scf_service_t *svc;
17572 17576 scf_iter_t *iter;
17573 17577
17574 17578 assert(cur_scope != NULL);
17575 17579
17576 17580 if ((svc = scf_service_create(g_hndl)) == NULL ||
17577 17581 (iter = scf_iter_create(g_hndl)) == NULL)
17578 17582 scfdie();
17579 17583
17580 17584 if (scf_iter_scope_services(iter, cur_scope) != 0)
17581 17585 scfdie();
17582 17586
17583 17587 for (;;) {
17584 17588 r = scf_iter_next_service(iter, svc);
17585 17589 if (r == 0)
17586 17590 break;
17587 17591 if (r != 1)
17588 17592 scfdie();
17589 17593
17590 17594 if (scf_service_get_name(svc, buf,
17591 17595 max_scf_name_len + 1) < 0)
17592 17596 scfdie();
17593 17597
17594 17598 if (strncmp(buf, arg1, len) == 0) {
17595 17599 err = cpl_add_completion(cpl, line, word_start,
17596 17600 word_end, buf + len, "", " ");
17597 17601 if (err != 0)
17598 17602 break;
17599 17603 }
17600 17604 }
17601 17605
17602 17606 scf_iter_destroy(iter);
17603 17607 scf_service_destroy(svc);
17604 17608
17605 17609 return (err);
17606 17610 }
17607 17611 }
17608 17612
17609 17613 /* ARGSUSED */
17610 17614 CPL_MATCH_FN(complete_command)
17611 17615 {
17612 17616 uint32_t scope = 0;
17613 17617
17614 17618 if (cur_snap != NULL)
17615 17619 scope = CS_SNAP;
17616 17620 else if (cur_inst != NULL)
17617 17621 scope = CS_INST;
17618 17622 else if (cur_svc != NULL)
17619 17623 scope = CS_SVC;
17620 17624 else
17621 17625 scope = CS_SCOPE;
17622 17626
17623 17627 return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
17624 17628 }
17625 17629 #endif /* NATIVE_BUILD */
↓ open down ↓ |
7218 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX